source: trunk/src/core/RpLibrary.cc @ 185

Last change on this file since 185 was 174, checked in by dkearney, 19 years ago
  1. changed the output of get(...) so that it returns an empty string if the

requested path does not exist but node is available.
ie. lib->get(input.number(max))

  1. changed get to call getString instead of copying the code from getString
File size: 22.4 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  Rappture Library Source
4 *
5 * ======================================================================
6 *  AUTHOR:  Derrick Kearney, Purdue University
7 *  Copyright (c) 2004-2005  Purdue Research Foundation
8 *
9 *  See the file "license.terms" for information on usage and
10 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 * ======================================================================
12 */
13
14#include "RpLibrary.h"
15
16/**********************************************************************/
17// METHOD: _get_attribute()
18/// Return the attribute value matching the provided attribute name.
19/**
20 */
21
22std::string
23RpLibrary::_get_attribute(scew_element* element, std::string attributeName)
24{
25    scew_attribute* attribute = NULL;
26    std::string attrVal;
27    // int attrValSize = 0;
28
29    if (element != NULL)
30    {
31        if (scew_attribute_count(element) > 0) {
32
33            while((attribute=scew_attribute_next(element, attribute)) != NULL)
34            {
35                if (    strcmp( scew_attribute_name(attribute),
36                                attributeName.c_str()) == 0     ){
37                    attrVal = scew_attribute_value(attribute);
38                }
39            }
40        }
41        else {
42            // there are no attributes, count == 0
43        }
44    }
45
46    return attrVal;
47}
48
49/**********************************************************************/
50// METHOD: _path2list()
51/// Convert a path into a list of element names.
52/**
53 */
54
55int
56RpLibrary::_path2list (std::string& path, std::string** list, int listLen)
57{
58    std::string::size_type pos = 0;
59    std::string::size_type start = 0;
60    int index = 0;
61    int retVal = 0;
62
63    // listLen should be the highest index + 1
64    for (   pos = path.find(".",0);
65            (pos != std::string::npos) || (index >= listLen);
66            pos = path.find(".",pos)   )
67    {
68        list[index++] = new std::string(path.substr(start,pos-start));
69        start = ++pos;
70    }
71
72    // add the last path to the list
73    if (index < listLen) {
74        // error checking for path names?
75        // what if you get something like p1.p2. ?
76        list[index] = new std::string(path.substr(start,path.length()-start));
77    }
78
79    retVal = index++;
80
81    // null out the rest of the pointers so we know where to stop free'ing
82    while (index < listLen) {
83        list[index++] = NULL;
84    }
85
86    return retVal;
87}
88
89/**********************************************************************/
90// METHOD: _node2name()
91/// Retrieve the id of a node.
92/**
93 */
94
95std::string
96RpLibrary::_node2name (scew_element* node)
97{
98    // XML_Char const* name = _get_attribute(node,"id");
99    std::string name = _get_attribute(node,"id");
100    std::stringstream retVal;
101    XML_Char const* type = NULL;
102    scew_element* parent = NULL;
103    scew_element** siblings = NULL;
104    unsigned int count = 0;
105    int tmpCount = 0;
106    int index = 0;
107    std::string indexStr;
108
109    type = scew_element_name(node);
110    parent = scew_element_parent(node);
111
112    // if (name == NULL) {
113    if (name.empty()) {
114        siblings = scew_element_list(parent, type, &count);
115        if (count > 0) {
116            tmpCount = count;
117            while ((index < tmpCount) && (siblings[index] != node)) {
118                index++;
119            }
120
121            if (index < tmpCount) {
122
123                if (index > 0) {
124
125                    retVal << type << --index;
126                }
127                else {
128
129                    retVal << type;
130                }
131
132                /*
133                if (retVal == NULL) {
134                    // error with allocating space
135                    return NULL;
136                }
137                */
138            }
139        }
140
141        scew_element_list_free(siblings);
142
143    }
144    else {
145
146        retVal << name;
147    }
148
149    return (retVal.str());
150}
151
152/**********************************************************************/
153// METHOD: _node2comp()
154/// Retrieve the component name of a node
155/**
156 */
157
158std::string
159RpLibrary::_node2comp (scew_element* node)
160{
161    // XML_Char const* name = _get_attribute(node,"id");
162    std::string name = _get_attribute(node,"id");
163    std::stringstream retVal;
164    XML_Char const* type = NULL;
165    scew_element* parent = NULL;
166    scew_element** siblings = NULL;
167    unsigned int count = 0;
168    int tmpCount = 0;
169    int index = 0;
170    std::string indexStr;
171
172    type = scew_element_name(node);
173    parent = scew_element_parent(node);
174
175    // if (name == NULL) {
176    if (name.empty()) {
177        siblings = scew_element_list(parent, type, &count);
178        if (count > 0) {
179            tmpCount = count;
180            while ((index < tmpCount) && (siblings[index] != node)) {
181                index++;
182            }
183
184            if (index < tmpCount) {
185
186                if (index > 0) {
187                    retVal << type << --index;
188                }
189                else {
190                    retVal << type;
191                }
192
193                /*
194                if (retVal == NULL) {
195                    // error with allocating space
196                    return NULL;
197                }
198                */
199            }
200
201        }
202        else {
203            // count == 0 ???
204        }
205        scew_element_list_free(siblings);
206
207    }
208    else {
209        // node has attribute id
210        //
211
212        // retVal = scew_strjoinXX(type,name);
213        retVal << type << "(" << name << ")";
214
215    }
216
217    return (retVal.str());
218}
219
220/**********************************************************************/
221// METHOD: _splitPath()
222/// Split a path (component) name into its tag name, index, and id
223/**
224 */
225
226int
227RpLibrary::_splitPath (std::string& path, std::string& tagName, int* idx, std::string& id )
228{
229    int stop = 0;
230    int start = 0;
231    int index = path.length();
232
233    if (index) {
234        index--;
235    }
236
237    if (!path.empty()) {
238        if (path[index] == ')') {
239            stop = index;
240            while (path[index] != '(') {
241                index--;
242            }
243            start = index+1;
244            // strncpy(id,path+start,stop-start);
245            // id = new std::string(path.substr(start,stop-start));
246            id = path.substr(start,stop-start);
247            index--;
248        }
249        if (isdigit(path[index])) {
250            stop = index;
251            while (isdigit(path[index])) {
252                index--;
253            }
254            // sscanf(path[index+1],"%d",idx);
255            sscanf(path.c_str()+index+1,"%d",idx);
256        }
257        if (isalpha(path[index])) {
258            start = 0;
259            stop = index+1;
260            // tagName = new std::string(path.substr(start,stop-start));
261            tagName = path.substr(start,stop-start);
262            // strncpy(tagName,path+start,stop-start);
263        }
264    }
265    else {
266        tagName = "";
267        *idx = 0;
268        id = "";
269    }
270
271    return 1;
272}
273
274/**********************************************************************/
275// METHOD: _find()
276/// Find or create a node and return it.
277/**
278 */
279
280scew_element*
281RpLibrary::_find(std::string path, int create)
282{
283    // std::string* tagName;
284    // std::string* id;
285    std::string tagName = "";
286    std::string id = "";
287    int index = 0;
288    int listLen = (path.length()/2)+1;
289    std::string* list[listLen];
290    int path_size = 0;
291    int listIdx = 0;
292    unsigned int count = 0;
293    int tmpCount = 0;
294    int lcv = 0;
295    std::string tmpId;
296
297    scew_element* tmpElement = this->root;
298    scew_element* node = NULL;
299    scew_element** eleList = NULL;
300
301
302    if (path.empty()) {
303        //user gave an empty path
304        // return this;
305        return tmpElement;
306    }
307
308    if (!list) {
309        // error calloc'ing space for list
310        return NULL;
311    }
312
313    path_size = _path2list (path,list,listLen);
314
315    while ( (listIdx <= path_size) && (tmpElement != NULL ) ){
316
317        _splitPath(*(list[listIdx]),tagName,&index,id);
318
319        // if (id->empty()) {
320        if (id.empty()) {
321            /*
322            # If the name is like "type2", then look for elements with
323            # the type name and return the one with the given index.
324            # If the name is like "type", then assume the index is 0.
325            */
326
327            // eleList = scew_element_list(tmpElement, tagName->c_str(), &count);
328            eleList = scew_element_list(tmpElement, tagName.c_str(), &count);
329            tmpCount = count;
330            if (index < tmpCount) {
331                node = eleList[index];
332            }
333            else {
334                /* there is no element with the specified index */
335                node = NULL;
336            }
337
338            scew_element_list_free(eleList);
339            eleList = NULL;
340        }
341        else {
342
343            /* what if its like type2(id) ? */
344            /* still unresolved */
345
346            /*
347            # If the name is like "type(id)", then look for elements
348            # that match the type and see if one has the requested name.
349            # if the name is like "(id)", then look for any elements
350            # with the requested name.
351            */
352
353            // eleList = scew_element_list(tmpElement, tagName->c_str(), &count);
354            if (!tagName.empty()) {
355                eleList = scew_element_list(tmpElement, tagName.c_str(), &count);
356            }
357            else {
358                eleList = scew_element_list_all(tmpElement, &count);
359            }
360
361            tmpCount = count;
362            for (lcv = 0; (lcv < tmpCount); lcv++) {
363                tmpId = _get_attribute(eleList[lcv], "id");
364                if (!tmpId.empty()) {
365                    // if (*id == tmpId) {
366                    if (id == tmpId) {
367                        node = eleList[lcv];
368                        break;
369                    }
370                }
371            }
372
373            if (lcv >= tmpCount) {
374                node = NULL;
375            }
376
377            scew_element_list_free(eleList);
378            eleList = NULL;
379
380        }
381
382        if (node == NULL) {
383            if (create == 0) {
384                // break out instead of returning because we still need to
385                // free the list variable
386                // return node;
387                tmpElement = node;
388                break;
389            }
390            else {
391                // create == 1
392                // we should create the rest of the path
393
394                // create the new element
395                // need to figure out how to properly number the new element
396                // node = scew_element_add(tmpElement,tagName->c_str());
397                node = scew_element_add(tmpElement,tagName.c_str());
398                if (! node) {
399                    // a new element was not created
400                }
401
402                // add an attribute and attrValue to the new element
403                // if (id && !id->empty()) {
404                    // scew_element_add_attr_pair(node,"id",id->c_str());
405                if (!id.empty()) {
406                    scew_element_add_attr_pair(node,"id",id.c_str());
407                }
408            }
409        }
410
411
412        // change this so youre not allocating and deallocating so much.
413        // make it static or something.
414        // if (tagName)    { delete (tagName); }
415        // if (id)         { delete (id); }
416        tagName = "";
417        id = "";
418        index = 0;
419        tmpElement = node;
420        listIdx++;
421    }
422
423    // need to free the strings inside of list
424
425    if (list) {
426        for (listIdx = 0; listIdx < listLen; listIdx++) {
427            if (list[listIdx]) {
428                delete(list[listIdx]);
429                list[listIdx] = NULL;
430            }
431        }
432
433        // should we really be freeing list since its on the stack as a fxn variable?
434        // free(list);
435        // list = NULL;
436    }
437
438
439    return tmpElement;
440}
441
442
443/**********************************************************************/
444// METHOD: element()
445/// Search the path of a xml tree and return a RpLibrary node.
446/**
447 */
448
449RpLibrary*
450RpLibrary::element (std::string path)
451{
452    RpLibrary* retLib;
453
454    if (path.empty()) {
455        // an empty path returns the current RpLibrary
456        return this;
457    }
458
459    scew_element* retNode = _find(path,0);
460
461    if (retNode == NULL) {
462        // add error information as to why we are returning NULL
463        return NULL;
464    }
465
466    retLib = new RpLibrary( retNode );
467
468    if (!retLib) {
469        // add error information as to why we are returning NULL
470        /* there was an error mallocing memory for a RpLibrary object */
471        return NULL;
472    }
473
474    return retLib;
475}
476
477/**********************************************************************/
478// METHOD: children()
479/// Return the next child of the node located at 'path'
480//
481// The lookup is reset when you send a NULL rpChilNode.
482//
483/**
484 */
485
486RpLibrary*
487RpLibrary::children (   std::string path,
488                        RpLibrary* rpChildNode,
489                        std::string type,
490                        int* childCount)
491{
492    static std::string old_path = "";
493    static RpLibrary* retLib = NULL;
494    int myChildCount = 0;
495    scew_element* parentNode = NULL;
496    scew_element* childNode = NULL;
497    std::string childName = "";
498
499
500    if (path.empty()) {
501        // an empty path uses the current RpLibrary as parent
502        parentNode = this->root;
503    }
504    else {
505        // check to see if this path is the same as the one set
506        // in the last call to this function.
507        // if so, then we dont need to reset the parentNode
508        //
509        // this check is probably more dependent on rpChildNode
510        // because we want to see if the person want to continue
511        // an old search or start from the beginning of the child list
512        //
513        if ( (path.compare(old_path) == 0) && (rpChildNode != NULL) ) {
514            parentNode = NULL;
515        }
516        // we need to search for a new parentNode
517        else {
518            parentNode = _find(path,0);
519            if (parentNode == NULL) {
520                // node not found
521                // add error code here
522                return NULL;
523            }
524        }
525    }
526
527    old_path = path;
528
529
530    if (rpChildNode) {
531        childNode = rpChildNode->root;
532    }
533
534    if (parentNode) {
535        myChildCount = scew_element_count(parentNode);
536    }
537
538    if (childCount) {
539        *childCount = myChildCount;
540    }
541
542    if ( (childNode = scew_element_next(parentNode,childNode)) ) {
543
544        if (!type.empty()) {
545            childName = scew_element_name(childNode);
546            // we are searching for a specific child name
547            // keep looking till we find a name that matches the type.
548            while (type != childName) {
549                childNode = scew_element_next(parentNode,childNode);
550                childName = scew_element_name(childNode);
551            }
552            if (type == childName) {
553                // found a child with a name that matches type
554                // clean up old memory
555                delete retLib;
556                retLib = new RpLibrary( childNode );
557            }
558            else {
559                // no children with names that match 'type' were found
560                delete retLib;
561                retLib = NULL;
562            }
563        }
564        else {
565            // clean up old memory
566            delete retLib;
567            retLib = new RpLibrary( childNode );
568        }
569    }
570    else {
571        // somthing happened within scew, get error code and display
572        // its probable there are no more child elements left to report
573        // clean up old memory
574        delete retLib;
575        retLib = NULL;
576    }
577
578    return retLib;
579}
580
581/**********************************************************************/
582// METHOD: get()
583/// Return the string value of the object held at location 'path'
584/**
585 */
586
587std::string
588RpLibrary::get (std::string path)
589{
590    return (this->getString(path));
591}
592
593/**********************************************************************/
594// METHOD: getString()
595/// Return the string value of the object held at location 'path'
596/**
597 */
598
599std::string
600RpLibrary::getString (std::string path)
601{
602    scew_element* retNode = _find(path,0);
603    XML_Char const* retCStr = NULL;
604
605    if (retNode == NULL) {
606        // need to raise error
607        return std::string("");
608    }
609
610    retCStr = scew_element_contents(retNode);
611
612    if (!retCStr) {
613        return std::string("");
614    }
615
616    return std::string(retCStr);
617}
618
619/**********************************************************************/
620// METHOD: getDouble()
621/// Return the double value of the object held at location 'path'
622/**
623 */
624
625double
626RpLibrary::getDouble (std::string path)
627{
628    std::string retValStr = "";
629    double retValDbl = 0;
630
631    retValStr = this->getString(path);
632    // think about changing this to strtod()
633    retValDbl = atof(retValStr.c_str());
634
635    // how do we raise error?
636    // currently we depend on getString to raise the error
637    return retValDbl;
638}
639
640
641/**********************************************************************/
642// METHOD: put()
643/// Put a string value into the xml.
644/**
645 */
646
647RpLibrary&
648RpLibrary::put ( std::string path, std::string value, std::string id, int append )
649{
650    scew_element* retNode = NULL;
651    std::string tmpVal = "";
652    const char* contents = NULL;
653
654    if (! path.empty()) {
655        retNode = _find(path,1);
656
657        if (retNode) {
658
659            if (append) {
660                if ( (contents = scew_element_contents(retNode)) ) {
661                    tmpVal = std::string(contents);
662                }
663                value = tmpVal + value;
664            }
665
666            scew_element_set_contents(retNode,value.c_str());
667        }
668    }
669
670    return *this;
671}
672
673/**********************************************************************/
674// METHOD: put()
675/// Put a double value into the xml.
676/**
677 */
678
679RpLibrary&
680RpLibrary::put ( std::string path, double value, std::string id, int append )
681{
682    std::stringstream valStr;
683
684    valStr << value;
685
686    return this->put(path,valStr.str(),id,append);
687}
688
689/*
690RpLibrary&
691RpLibrary::remove ( std::string path )
692{
693    scew_element* ele = _find(path,0);
694    RpLibrary* retLib;
695    if (ele) {
696        retLib = new RpLibrary(ele)
697    }
698
699    return *retLib
700}
701*/
702
703/**********************************************************************/
704// METHOD: xml()
705/// Return the xml text held in this RpLibrary
706/**
707 */
708
709std::string
710RpLibrary::xml ()
711{
712    std::stringstream outString;
713
714    outString << "<?xml version=\"1.0\"?>\n";
715    print_element(this->root, 0, outString);
716
717    return outString.str();
718}
719
720/**********************************************************************/
721// METHOD: nodeType()
722/// Return the type name of this node
723/**
724 */
725
726std::string
727RpLibrary::nodeType ()
728{
729    return std::string(scew_element_name(root));
730}
731
732/**********************************************************************/
733// METHOD: nodeId()
734/// Return the id of this node.
735/**
736 */
737
738std::string
739RpLibrary::nodeId ()
740{
741    return _node2name(root);
742}
743
744/**********************************************************************/
745// METHOD: nodeComp()
746/// Return the component name of this node.
747/**
748 */
749
750std::string
751RpLibrary::nodeComp ()
752{
753    return _node2comp(root);
754}
755
756/*
757 * ----------------------------------------------------------------------
758 *  METHOD: result
759 *
760 *  Clients call this function at the end of their simulation, to
761 *  pass the simulation result back to the Rappture GUI.  It writes
762 *  out the given XML object to a runXXX.xml file, and then writes
763 *  out the name of that file to stdout.
764 * ======================================================================
765 *  AUTHOR:  Michael McLennan, Purdue University
766 *  Copyright (c) 2004-2005
767 *  Purdue Research Foundation, West Lafayette, IN
768 * ======================================================================
769 */
770void
771RpLibrary::result() {
772    std::stringstream outputFile;
773    std::fstream file;
774    std::string xmlText = "";
775    time_t t = 0;
776
777    outputFile << "run" << (int)time(&t) << ".xml";
778    file.open(outputFile.str().c_str(),std::ios::out);
779
780    if ( file.is_open() ) {
781        xmlText = xml();
782        if (!xmlText.empty()) {
783            file << xmlText;
784        }
785    }
786    std::cout << "=RAPPTURE-RUN=>" << outputFile.str() << std::endl;
787}
788
789/**********************************************************************/
790// METHOD: print_indent()
791/// Add indentations to the requested stringstream object.
792/**
793 */
794
795void
796RpLibrary::print_indent(unsigned int indent, std::stringstream& outString)
797{
798
799    // keep this around incase you want to use tabs instead of spaces
800    // while ( (indent--) > 0)
801    // {
802    //     outString << "\t";
803    // }
804
805    // keep this around incase you want to use spaces instead of tabs
806    int cnt = indent*INDENT_SIZE;
807    while ( (cnt--) > 0)
808    {
809        outString << " ";
810    }
811
812}
813
814/**********************************************************************/
815// METHOD: print_attributes()
816/// Print the attribute names and values for the provided xml node
817/**
818 */
819
820void
821RpLibrary::print_attributes(scew_element* element, std::stringstream& outString)
822{
823    scew_attribute* attribute = NULL;
824
825    if (element != NULL)
826    {
827        /**
828         * Iterates through the element's attribute list, printing the
829         * pair name-value.
830         */
831        attribute = NULL;
832        while ((attribute = scew_attribute_next(element, attribute)) != NULL)
833        {
834            outString << " " << scew_attribute_name(attribute) << "=\"" <<
835                   scew_attribute_value(attribute) << "\"";
836        }
837    }
838}
839
840
841/**********************************************************************/
842// METHOD: print_element()
843/// Print the value of the node and its attributes to a stringstream object
844/**
845 */
846
847void
848RpLibrary::print_element(   scew_element* element,
849                            unsigned int indent,
850                            std::stringstream& outString    )
851{
852    scew_element* child = NULL;
853    XML_Char const* contents = NULL;
854
855    if (element == NULL)
856    {
857        return;
858    }
859
860    /**
861     * Prints the starting element tag with its attributes.
862     */
863    print_indent(indent, outString);
864    outString << "<" << scew_element_name(element);
865    print_attributes(element,outString);
866    outString << ">";
867    contents = scew_element_contents(element);
868    if (contents == NULL)
869    {
870        outString << "\n";
871    }
872
873    /**
874     * Call print_element function again for each child of the
875     * current element.
876     */
877    child = NULL;
878    while ((child = scew_element_next(element, child)) != NULL)
879    {
880        print_element(child, indent + 1, outString);
881    }
882
883    /* Prints element's content. */
884    if (contents != NULL)
885    {
886        outString << contents;
887    }
888    else
889    {
890        print_indent(indent, outString);
891    }
892
893    /**
894     * Prints the closing element tag.
895     */
896    outString << "</" << scew_element_name(element) << ">\n" ;
897}
898
Note: See TracBrowser for help on using the repository browser.