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

Last change on this file since 125 was 125, checked in by dkearney, 17 years ago

1) removed "as" string from c++'s element() function because
the function does not have the capacity to return anything
other than RpLibrary? Instances
2) changed get() functions in library module to return strings.
this change was propagated to matlab, octave, c, fortran, c++
bindings.
3) fixed rpFreeLibrary inside of c interface, now function accepts
a pointer to a pointer to RpLibrary? (lib) and sets *lib equal to
null
4) added doxygen target to makefile. (make docs), to get graphics
you need the program named dot (debian: apt-get install graphviz)
otherwise you will get errors for the portion of the proceedure
where it is trying to create the graphics.

File size: 21.7 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 */
482
483RpLibrary*
484RpLibrary::children (   std::string path,
485                        RpLibrary* rpChildNode,
486                        std::string type,
487                        int* childCount)
488{
489    static std::string old_path = "";
490    static RpLibrary* retLib = NULL;
491    int myChildCount = 0;
492    scew_element* parentNode = NULL;
493    scew_element* childNode = NULL;
494    std::string childName = "";
495
496
497    if (path.empty()) {
498        // an empty path uses the current RpLibrary as parent
499        parentNode = this->root;
500    }
501    else {
502        // check to see if this path is the same as the one set
503        // in the last call to this function.
504        // if so, then we dont need to reset the parentNode
505        if ( path.compare(old_path) == 0 ) {
506            parentNode = NULL;
507        }
508        // we need to search for a new parentNode
509        else {
510            parentNode = _find(path,0);
511            if (parentNode == NULL) {
512                // node not found
513                // add error code here
514                return NULL;
515            }
516        }
517    }
518
519    old_path = path;
520
521
522    if (rpChildNode) {
523        childNode = rpChildNode->root;
524    }
525
526    if (parentNode) {
527        myChildCount = scew_element_count(parentNode);
528        std::cout << "myChildCount = " << myChildCount << std::endl;
529    }
530
531    if (childCount) {
532        *childCount = myChildCount;
533    }
534
535    if ( (childNode = scew_element_next(parentNode,childNode)) ) {
536
537        if (!type.empty()) {
538            childName = scew_element_name(childNode);
539            if (type == childName) {
540                // clean up old memory
541                if (retLib) {
542                    delete retLib;
543                }
544                retLib = new RpLibrary( childNode );
545            }
546        }
547        else {
548            // clean up old memory
549            if (retLib) {
550                delete retLib;
551            }
552            retLib = new RpLibrary( childNode );
553        }
554    }
555    else {
556        // somthing happened within scew, get error code and display
557        // its probable there are no more child elements left to report
558        // clean up old memory
559        if (retLib) {
560            delete retLib;
561        }
562        retLib = NULL;
563    }
564
565    return retLib;
566}
567
568/**********************************************************************/
569// METHOD: get()
570/// Return the string value of the object held at location 'path'
571/**
572 */
573
574std::string
575RpLibrary::get (std::string path)
576{
577    scew_element* retNode = _find(path,0);
578
579    if (retNode == NULL) {
580        // need to raise error
581        return "";
582    }
583
584    return std::string(scew_element_contents(retNode));
585}
586
587/**********************************************************************/
588// METHOD: getString()
589/// Return the string value of the object held at location 'path'
590/**
591 */
592
593std::string
594RpLibrary::getString (std::string path)
595{
596    scew_element* retNode = _find(path,0);
597
598    if (retNode == NULL) {
599        // need to raise error
600        return "";
601    }
602
603    return std::string(scew_element_contents(retNode));
604}
605
606/**********************************************************************/
607// METHOD: getDouble()
608/// Return the double value of the object held at location 'path'
609/**
610 */
611
612double
613RpLibrary::getDouble (std::string path)
614{
615    std::string retValStr = "";
616    double retValDbl = 0;
617
618    retValStr = this->getString(path);
619    // think about changing this to strtod()
620    retValDbl = atof(retValStr.c_str());
621
622    // how do we raise error?
623    // currently we depend on getString to raise the error
624    return retValDbl;
625}
626
627
628/**********************************************************************/
629// METHOD: put()
630/// Put a string value into the xml.
631/**
632 */
633
634RpLibrary&
635RpLibrary::put ( std::string path, std::string value, std::string id, int append )
636{
637    scew_element* retNode = NULL;
638    std::string tmpVal = "";
639    const char* contents = NULL;
640
641    if (! path.empty()) {
642        retNode = _find(path,1);
643
644        if (retNode) {
645
646            if (append) {
647                if ( (contents = scew_element_contents(retNode)) ) {
648                    tmpVal = std::string(contents);
649                }
650                value = tmpVal + value;
651            }
652
653            scew_element_set_contents(retNode,value.c_str());
654        }
655    }
656
657    return *this;
658}
659
660/**********************************************************************/
661// METHOD: put()
662/// Put a double value into the xml.
663/**
664 */
665
666RpLibrary&
667RpLibrary::put ( std::string path, double value, std::string id, int append )
668{
669    std::stringstream valStr;
670
671    valStr << value;
672
673    return this->put(path,valStr.str(),id,append);
674}
675
676/*
677RpLibrary&
678RpLibrary::remove ( std::string path )
679{
680    scew_element* ele = _find(path,0);
681    RpLibrary* retLib;
682    if (ele) {
683        retLib = new RpLibrary(ele)
684    }
685
686    return *retLib
687}
688*/
689
690/**********************************************************************/
691// METHOD: xml()
692/// Return the xml text held in this RpLibrary
693/**
694 */
695
696std::string
697RpLibrary::xml ()
698{
699    std::stringstream outString;
700
701    outString << "<?xml version=\"1.0\"?>\n";
702    print_element(this->root, 0, outString);
703
704    return outString.str();
705}
706
707/**********************************************************************/
708// METHOD: nodeType()
709/// Return the type name of this node
710/**
711 */
712
713std::string
714RpLibrary::nodeType ()
715{
716    return std::string(scew_element_name(root));
717}
718
719/**********************************************************************/
720// METHOD: nodeId()
721/// Return the id of this node.
722/**
723 */
724
725std::string
726RpLibrary::nodeId ()
727{
728    return _node2name(root);
729}
730
731/**********************************************************************/
732// METHOD: nodeComp()
733/// Return the component name of this node.
734/**
735 */
736
737std::string
738RpLibrary::nodeComp ()
739{
740    return _node2comp(root);
741}
742
743/*
744 * ----------------------------------------------------------------------
745 *  METHOD: result
746 *
747 *  Clients call this function at the end of their simulation, to
748 *  pass the simulation result back to the Rappture GUI.  It writes
749 *  out the given XML object to a runXXX.xml file, and then writes
750 *  out the name of that file to stdout.
751 * ======================================================================
752 *  AUTHOR:  Michael McLennan, Purdue University
753 *  Copyright (c) 2004-2005
754 *  Purdue Research Foundation, West Lafayette, IN
755 * ======================================================================
756 */
757void
758RpLibrary::result() {
759    std::stringstream outputFile;
760    std::fstream file;
761    std::string xmlText = "";
762    time_t t = 0;
763
764    outputFile << "run" << (int)time(&t) << ".xml";
765    file.open(outputFile.str().c_str(),std::ios::out);
766
767    if ( file.is_open() ) {
768        xmlText = xml();
769        if (!xmlText.empty()) {
770            file << xmlText;
771        }
772    }
773    std::cout << "=RAPPTURE-RUN=>" << outputFile.str() << std::endl;
774}
775
776/**********************************************************************/
777// METHOD: print_indent()
778/// Add indentations to the requested stringstream object.
779/**
780 */
781
782void
783RpLibrary::print_indent(unsigned int indent, std::stringstream& outString)
784{
785
786    // keep this around incase you want to use tabs instead of spaces
787    // while ( (indent--) > 0)
788    // {
789    //     outString << "\t";
790    // }
791
792    // keep this around incase you want to use spaces instead of tabs
793    int cnt = indent*INDENT_SIZE;
794    while ( (cnt--) > 0)
795    {
796        outString << " ";
797    }
798
799}
800
801/**********************************************************************/
802// METHOD: print_attributes()
803/// Print the attribute names and values for the provided xml node
804/**
805 */
806
807void
808RpLibrary::print_attributes(scew_element* element, std::stringstream& outString)
809{
810    scew_attribute* attribute = NULL;
811
812    if (element != NULL)
813    {
814        /**
815         * Iterates through the element's attribute list, printing the
816         * pair name-value.
817         */
818        attribute = NULL;
819        while ((attribute = scew_attribute_next(element, attribute)) != NULL)
820        {
821            outString << " " << scew_attribute_name(attribute) << "=\"" <<
822                   scew_attribute_value(attribute) << "\"";
823        }
824    }
825}
826
827
828/**********************************************************************/
829// METHOD: print_element()
830/// Print the value of the node and its attributes to a stringstream object
831/**
832 */
833
834void
835RpLibrary::print_element(   scew_element* element,
836                            unsigned int indent,
837                            std::stringstream& outString    )
838{
839    scew_element* child = NULL;
840    XML_Char const* contents = NULL;
841
842    if (element == NULL)
843    {
844        return;
845    }
846
847    /**
848     * Prints the starting element tag with its attributes.
849     */
850    print_indent(indent, outString);
851    outString << "<" << scew_element_name(element);
852    print_attributes(element,outString);
853    outString << ">";
854    contents = scew_element_contents(element);
855    if (contents == NULL)
856    {
857        outString << "\n";
858    }
859
860    /**
861     * Call print_element function again for each child of the
862     * current element.
863     */
864    child = NULL;
865    while ((child = scew_element_next(element, child)) != NULL)
866    {
867        print_element(child, indent + 1, outString);
868    }
869
870    /* Prints element's content. */
871    if (contents != NULL)
872    {
873        outString << contents;
874    }
875    else
876    {
877        print_indent(indent, outString);
878    }
879
880    /**
881     * Prints the closing element tag.
882     */
883    outString << "</" << scew_element_name(element) << ">\n" ;
884}
885
Note: See TracBrowser for help on using the repository browser.