source: branches/nanovis2/src/core/RpLibrary.cc @ 3175

Last change on this file since 3175 was 3175, checked in by ldelgass, 12 years ago

sync with trunk

  • Property svn:keywords set to Date Rev URL
File size: 65.4 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  Rappture Library Source
4 *
5 * ======================================================================
6 *  AUTHOR:  Derrick S. Kearney, Purdue University
7 *  Copyright (c) 2004-2007  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 "scew/scew.h"
15#include "scew_extras.h"
16#include "RpLibrary.h"
17#include "RpEntityRef.h"
18#include "RpEncode.h"
19#include <algorithm>
20#include <iostream>
21#include <string>
22#include <sstream>
23#include <fstream>
24#include <stdlib.h>
25#include <errno.h>
26#include <time.h>
27#include <iterator>
28#include <cctype>
29
30#ifdef _POSIX_SOURCE
31    #include <sys/time.h>
32#endif /* _POSIX_SOURCE */
33
34// no arg constructor
35// used when we dont want to read an xml file to populate the xml tree
36// we are building a new xml structure
37RpLibrary::RpLibrary ()
38    :   parser      (NULL),
39        tree        (NULL),
40        root        (NULL),
41        freeTree    (1),
42        freeRoot    (1)
43{
44    tree = scew_tree_create();
45    root = scew_tree_add_root(tree, "run");
46}
47
48RpLibrary::RpLibrary (
49            const std::string filePath
50        )
51    :   parser      (NULL),
52        tree        (NULL),
53        root        (NULL),
54        freeTree    (0),
55        freeRoot    (1)
56{
57    std::stringstream msg;
58
59    if (filePath.length() != 0) {
60        // file path should not be null or empty string unless we are
61        // creating a new xml file
62
63        parser = scew_parser_create();
64
65        // Don't ignore whitespaces!
66        // Things like string inputs may have trailing newlines that
67        // matter to the underlying application.
68        scew_parser_ignore_whitespaces(parser, 0);
69
70        /* Loads an XML file */
71        if (!scew_parser_load_file(parser, filePath.c_str()))
72        {
73            scew_error code = scew_error_code();
74            printf("Unable to load file (error #%d: %s)\n", code,
75                   scew_error_string(code));
76            msg << "Unable to load file (error #" << code
77                << ": " << scew_error_string(code) << ")\n";
78
79            if (code == scew_error_expat)
80            {
81                enum XML_Error expat_code =
82                    scew_error_expat_code(parser);
83                printf("Expat error #%d (line %d, column %d): %s\n",
84                       expat_code,
85                       scew_error_expat_line(parser),
86                       scew_error_expat_column(parser),
87                       scew_error_expat_string(expat_code));
88                msg << "Expat error #" << expat_code << " (line "
89                    << scew_error_expat_line(parser) << ", column "
90                    << scew_error_expat_column(parser) << "): "
91                    << "\n";
92            }
93
94            fflush(stdout);
95            scew_parser_free(parser);
96            parser = NULL;
97
98            // update the status of the call
99            status.error(msg.str().c_str());
100            status.addContext("RpLibrary::RpLibrary()");
101        }
102        else
103        {
104            tree = scew_parser_tree(parser);
105            freeTree = 0;
106            root = scew_tree_root(tree);
107        }
108    }
109    else {
110        // create a new xml (from an empty file)
111        freeTree = 1;
112        tree = scew_tree_create();
113        root = scew_tree_add_root(tree, "run");
114    }
115}
116
117
118// copy constructor
119// for some reason making this a const gives me problems
120// when calling xml()
121// need help looking into this
122// RpLibrary ( const RpLibrary& other )
123RpLibrary::RpLibrary ( const RpLibrary& other )
124    : parser    (NULL),
125      tree      (NULL),
126      root      (NULL),
127      freeTree  (0),
128      freeRoot  (1)
129{
130    std::stringstream msg;
131    std::string buffer;
132    int buffLen;
133
134    // fill in the current RpLibrary's data with other's data
135    parser = scew_parser_create();
136    scew_parser_ignore_whitespaces(parser, 1);
137
138    // Loads the XML from other
139    // the length cannot be 0 because xml() should not be returning
140    // empty strings
141    buffer = other.xml();
142    buffLen = buffer.length();
143
144    if (buffLen > 0) {
145        if (!scew_parser_load_buffer(parser,buffer.c_str(),buffLen))
146        {
147            // there was an error loading the buffer
148            // how do you tell the user, you couldn't make a copy?
149            scew_error code = scew_error_code();
150            printf("Unable to load buffer (error #%d: %s)\n", code,
151                   scew_error_string(code));
152            msg << "Unable to load file (error #" << code
153                << ": " << scew_error_string(code) << ")\n";
154
155            if (code == scew_error_expat)
156            {
157                enum XML_Error expat_code =
158                    scew_error_expat_code(parser);
159                printf("Expat error #%d (line %d, column %d): %s\n",
160                       expat_code,
161                       scew_error_expat_line(parser),
162                       scew_error_expat_column(parser),
163                       scew_error_expat_string(expat_code));
164                msg << "Expat error #" << expat_code << " (line "
165                    << scew_error_expat_line(parser) << ", column "
166                    << scew_error_expat_column(parser) << "): "
167                    << "\n";
168            }
169
170            // return an empty RpLibrary?
171            // return EXIT_FAILURE;
172
173            parser = NULL;
174
175            // update the status of the call
176            status.error(msg.str().c_str());
177            status.addContext("RpLibrary::RpLibrary()");
178        }
179        else {
180
181            // parsing the buffer was successful
182            // populate the new data members.
183
184            tree = scew_parser_tree(parser);
185            freeTree = 0;
186            freeRoot = 1;
187            root = scew_tree_root(tree);
188
189        }
190
191    } // end if (buffer.length() != 0) {
192}// end copy constructor
193
194// copy assignment operator
195// for some reason making this a const gives me problems
196// when calling xml()
197// need help looking into this
198// RpLibrary& operator= (const RpLibrary& other) {
199RpLibrary&
200RpLibrary::operator= (const RpLibrary& other) {
201
202    std::stringstream msg;
203    std::string buffer;
204    int buffLen;
205
206    scew_parser* tmp_parser;
207    scew_tree* tmp_tree;
208    scew_element* tmp_root;
209    int tmp_freeTree;
210    int tmp_freeRoot;
211
212    if (this != &other) {
213
214        tmp_parser   = parser;
215        tmp_tree     = tree;
216        tmp_root     = root;
217        tmp_freeTree = freeTree;
218        tmp_freeRoot = freeRoot;
219
220        // fill in the current RpLibrary's data with other's data
221        parser = scew_parser_create();
222        scew_parser_ignore_whitespaces(parser, 1);
223
224        // Loads the XML from other
225        // the length cannot be 0 because xml()
226        // should not be returning empty strings
227        buffer = other.xml();
228        buffLen = buffer.length();
229
230        if (buffLen > 0) {
231            if (!scew_parser_load_buffer(parser,buffer.c_str(),buffLen))
232            {
233                // there was an error loading the buffer
234                // how do you tell the user, you couldn't make a copy?
235                scew_error code = scew_error_code();
236                printf("Unable to load buffer (error #%d: %s)\n", code,
237                       scew_error_string(code));
238                msg << "Unable to load file (error #" << code
239                    << ": " << scew_error_string(code) << ")\n";
240
241                if (code == scew_error_expat)
242                {
243                    enum XML_Error expat_code =
244                        scew_error_expat_code(parser);
245                    printf("Expat error #%d (line %d, column %d): %s\n",
246                           expat_code,
247                           scew_error_expat_line(parser),
248                           scew_error_expat_column(parser),
249                           scew_error_expat_string(expat_code));
250                    msg << "Expat error #" << expat_code << " (line "
251                        << scew_error_expat_line(parser) << ", column "
252                        << scew_error_expat_column(parser) << "): "
253                        << "\n";
254                }
255
256                // return things back to the way they used to be
257                // or maybe return an empty RpLibrary?
258                // return EXIT_FAILURE;
259
260                // return this object to its previous state.
261                parser = tmp_parser;
262
263                // update the status of the call
264                status.error(msg.str().c_str());
265                status.addContext("RpLibrary::RpLibrary()");
266            }
267            else {
268
269                // parsing the buffer was successful
270                // populate the new data members.
271
272                tree = scew_parser_tree(parser);
273                freeTree = 0;
274                freeRoot = 1;
275                root = scew_tree_root(tree);
276
277                // free the current RpLibrary's data
278                // we do the free so far down so we can see if
279                // parsing the other object's xml fails.
280                // if the parsing fails, we can still return this
281                // object to its previous state.
282                if (tmp_tree && tmp_freeTree) {
283                    scew_tree_free(tmp_tree);
284                    tmp_tree = NULL;
285                }
286                if (tmp_parser) {
287                    scew_parser_free(tmp_parser);
288                    tmp_parser = NULL;
289                }
290                if (tmp_root && tmp_freeRoot) {
291                    tmp_root = NULL;
292                }
293            }
294
295        } // end if (buffer.length() != 0) {
296    } // end if (this != &other)
297
298    return *this;
299} // end operator=
300
301
302// default destructor
303RpLibrary::~RpLibrary ()
304{
305    // clean up dynamic memory
306
307    if (tree && freeTree) {
308        scew_tree_free(tree);
309        tree = NULL;
310    }
311    if (parser) {
312        scew_parser_free(parser);
313        parser = NULL;
314    }
315    if (!freeTree && root && freeRoot) {
316        scew_element_free(root);
317        root = NULL;
318    }
319}
320/**********************************************************************/
321// METHOD: _get_attribute()
322/// Return the attribute value matching the provided attribute name.
323/**
324 */
325
326std::string
327RpLibrary::_get_attribute (
328    scew_element* element,
329    std::string attributeName
330    ) const
331{
332    scew_attribute* attribute = NULL;
333    std::string attrVal;
334
335    if (element != NULL)
336    {
337        if (scew_attribute_count(element) > 0) {
338
339            while((attribute=scew_attribute_next(element, attribute)) != NULL)
340            {
341                if (    strcmp( scew_attribute_name(attribute),
342                                attributeName.c_str()) == 0     ){
343                    attrVal = scew_attribute_value(attribute);
344                }
345            }
346        }
347        else {
348            // there are no attributes, count == 0
349        }
350    }
351
352    return attrVal;
353}
354
355/**********************************************************************/
356// METHOD: _path2list()
357/// Convert a path into a list of element names.
358/**
359 */
360
361int
362RpLibrary::_path2list (
363    std::string& path,
364    std::string** list,
365    int listLen
366    ) const
367{
368    std::string::size_type pos = 0;
369    std::string::size_type start = 0;
370    std::string::size_type end = path.length();
371    int index = 0;
372    int retVal = 0;
373    unsigned int parenDepth = 0;
374
375    for (   pos = 0; (pos < end) && (index < listLen); pos++) {
376        if (path[pos] == '(') {
377            parenDepth++;
378            continue;
379        }
380
381        if (path[pos] == ')') {
382            parenDepth--;
383            continue;
384        }
385
386        if ( (path[pos] == '.') && (parenDepth == 0) ) {
387            list[index] = new std::string(path.substr(start,pos-start));
388            index++;
389            start = pos + 1;
390        }
391    }
392
393    // add the last path to the list
394    // error checking for path names like p1.p2.
395    if ( (start < end) && (pos == end) ) {
396        list[index] = new std::string(path.substr(start,pos-start));
397    }
398    retVal = index;
399    index++;
400
401    // null out the rest of the pointers so we know where to stop free'ing
402    while (index < listLen) {
403        list[index++] = NULL;
404    }
405
406    return retVal;
407}
408
409/**********************************************************************/
410// METHOD: _node2name()
411/// Retrieve the id of a node.
412/**
413 */
414
415std::string
416RpLibrary::_node2name (scew_element* node) const
417{
418    // XML_Char const* name = _get_attribute(node,"id");
419    std::string name = _get_attribute(node,"id");
420    std::stringstream retVal;
421    XML_Char const* type = NULL;
422    scew_element* parent = NULL;
423    scew_element** siblings = NULL;
424    unsigned int count = 0;
425    int tmpCount = 0;
426    int index = 0;
427    std::string indexStr;
428
429    type = scew_element_name(node);
430    parent = scew_element_parent(node);
431
432    if (parent) {
433
434        // if (name == NULL) {
435        if (name.empty()) {
436            siblings = scew_element_list(parent, type, &count);
437            if (count > 0) {
438                tmpCount = count;
439                while ((index < tmpCount) && (siblings[index] != node)) {
440                    index++;
441                }
442
443                if (index < tmpCount) {
444
445                    if (index > 0) {
446
447                        retVal << type << --index;
448                    }
449                    else {
450
451                        retVal << type;
452                    }
453
454                    /*
455                    if (retVal == NULL) {
456                        // error with allocating space
457                        return NULL;
458                    }
459                    */
460                }
461            }
462
463            scew_element_list_free(siblings);
464
465        }
466        else {
467
468            retVal << name;
469        }
470    }
471
472    return (retVal.str());
473}
474
475/**********************************************************************/
476// METHOD: _node2comp()
477/// Retrieve the component name of a node
478/**
479 */
480
481std::string
482RpLibrary::_node2comp (scew_element* node) const
483{
484    // XML_Char const* name = _get_attribute(node,"id");
485    std::string id = _get_attribute(node,"id");
486    std::stringstream retVal;
487    XML_Char const* type = NULL;
488    scew_element* parent = NULL;
489    scew_element** siblings = NULL;
490    unsigned int count = 0;
491    int tmpCount = 0;
492    int index = 0;
493    std::string indexStr;
494
495    type = scew_element_name(node);
496    parent = scew_element_parent(node);
497
498    if (parent) {
499        if (id.empty()) {
500            siblings = scew_element_list(parent, type, &count);
501            if (count > 0) {
502                tmpCount = count;
503                // figure out what the index value should be
504                while ((index < tmpCount) && (siblings[index] != node)) {
505                    index++;
506                }
507
508                if (index < tmpCount) {
509                    if (index > 0) {
510                        // retVal << type << --index;
511                        retVal << type << index;
512                    }
513                    else {
514                        retVal << type;
515                    }
516                }
517
518            }
519            else {
520                // count == 0 ??? this state should never be reached
521            }
522            scew_element_list_free(siblings);
523
524        }
525        else {
526            // node has attribute id
527            retVal << type << "(" << id << ")";
528
529        }
530    }
531
532    return (retVal.str());
533}
534
535/**********************************************************************/
536// METHOD: _node2path()
537/// Retrieve the full path name of a node
538/**
539 */
540
541std::string
542RpLibrary::_node2path (scew_element* node) const
543{
544
545    std::stringstream path;
546    scew_element* snode = node;
547    scew_element* parent = NULL;
548
549    if (snode) {
550        parent = scew_element_parent(snode);
551        path.clear();
552
553        while (snode && parent) {
554
555            if (!path.str().empty()) {
556                path.str(_node2comp(snode) + "." + path.str());
557                // path.str("." + _node2comp(snode) + path.str());
558            }
559            else {
560                path.str(_node2comp(snode));
561                // path.str("." + _node2comp(snode));
562            }
563
564            snode = scew_element_parent(snode);
565            parent = scew_element_parent(snode);
566        }
567    }
568
569    return (path.str());
570}
571
572/**********************************************************************/
573// METHOD: _splitPath()
574/// Split a path (component) name into its tag name, index, and id
575/**
576 */
577
578int
579RpLibrary::_splitPath ( std::string& path,
580                        std::string& tagName,
581                        int* idx,
582                        std::string& id ) const
583{
584    int stop = 0;
585    int start = 0;
586    int index = path.length();
587
588    if (index) {
589        index--;
590    }
591
592    if (!path.empty()) {
593        if (path[index] == ')') {
594            stop = index;
595            while (path[index] != '(') {
596                index--;
597            }
598            start = index+1;
599            // strncpy(id,path+start,stop-start);
600            // id = new std::string(path.substr(start,stop-start));
601            id = path.substr(start,stop-start);
602            index--;
603        }
604        if (isdigit(path[index])) {
605            stop = index;
606            while (isdigit(path[index])) {
607                index--;
608            }
609            // sscanf(path[index+1],"%d",idx);
610            sscanf(path.c_str()+index+1,"%d",idx);
611        }
612        if (isalpha(path[index])) {
613            start = 0;
614            stop = index+1;
615            // tagName = new std::string(path.substr(start,stop-start));
616            tagName = path.substr(start,stop-start);
617            // strncpy(tagName,path+start,stop-start);
618        }
619    }
620    else {
621        tagName = "";
622        *idx = 0;
623        id = "";
624    }
625
626    return 1;
627}
628
629/**********************************************************************/
630// METHOD: _find()
631/// Find or create a node and return it.
632/**
633 */
634
635scew_element*
636RpLibrary::_find(std::string path, int create) const
637{
638    std::string tagName = "";
639    std::string id = "";
640    int index = 0;
641    int listLen = (path.length()/2)+1;
642    std::string** list;
643    int path_size = 0;
644    int listIdx = 0;
645    unsigned int count = 0;
646    int tmpCount = 0;
647    int lcv = 0;
648    std::string tmpId;
649
650    scew_element* tmpElement = this->root;
651    scew_element* node = NULL;
652    scew_element** eleList = NULL;
653
654
655    if (path.empty()) {
656        // user gave an empty path
657        return tmpElement;
658    }
659
660    list = (std::string **) calloc(listLen, sizeof( std::string * ) );
661
662    if (!list) {
663        // error calloc'ing space for list
664        return NULL;
665    }
666
667    path_size = _path2list (path,list,listLen);
668
669    while ( (listIdx <= path_size) && (tmpElement != NULL ) ){
670
671        _splitPath(*(list[listIdx]),tagName,&index,id);
672
673        if (id.empty()) {
674            /*
675            # If the name is like "type2", then look for elements with
676            # the type name and return the one with the given index.
677            # If the name is like "type", then assume the index is 0.
678            */
679
680            eleList = scew_element_list(tmpElement, tagName.c_str(), &count);
681            tmpCount = count;
682            if (index < tmpCount) {
683                node = eleList[index];
684            }
685            else {
686                /* there is no element with the specified index */
687                node = NULL;
688            }
689
690            scew_element_list_free(eleList);
691            eleList = NULL;
692        }
693        else {
694
695            /* what if its like type2(id) ? */
696            /* still unresolved */
697
698            /*
699            # If the name is like "type(id)", then look for elements
700            # that match the type and see if one has the requested name.
701            # if the name is like "(id)", then look for any elements
702            # with the requested name.
703            */
704
705            if (!tagName.empty()) {
706                eleList = scew_element_list(tmpElement, tagName.c_str(), &count);
707            }
708            else {
709                eleList = scew_element_list_all(tmpElement, &count);
710            }
711
712            tmpCount = count;
713            for (lcv = 0; (lcv < tmpCount); lcv++) {
714                tmpId = _get_attribute(eleList[lcv], "id");
715                if (!tmpId.empty()) {
716                    if (id == tmpId) {
717                        node = eleList[lcv];
718                        break;
719                    }
720                }
721            }
722
723            if (lcv >= tmpCount) {
724                node = NULL;
725            }
726
727            scew_element_list_free(eleList);
728            eleList = NULL;
729
730        }
731
732        if (node == NULL) {
733            if (create == NO_CREATE_PATH) {
734                // break out instead of returning because we still need to
735                // free the list variable
736                tmpElement = node;
737                break;
738            }
739            else {
740                // create == CREATE_PATH
741                // we should create the rest of the path
742
743                // create the new element
744                // need to figure out how to properly number the new element
745                node = scew_element_add(tmpElement,tagName.c_str());
746                if (! node) {
747                    // a new element was not created
748                }
749
750                // add an attribute and attrValue to the new element
751                if (!id.empty()) {
752                    scew_element_add_attr_pair(node,"id",id.c_str());
753                }
754            }
755        }
756
757        tagName = "";
758        id = "";
759        index = 0;
760        tmpElement = node;
761        listIdx++;
762    }
763
764    // need to free the strings inside of list
765
766    if (list) {
767        for (listIdx = 0; listIdx < listLen; listIdx++) {
768            if (list[listIdx]) {
769                delete(list[listIdx]);
770                list[listIdx] = NULL;
771            }
772        }
773
774        free(list);
775        list = NULL;
776    }
777
778
779    return tmpElement;
780}
781
782/**********************************************************************/
783// METHOD: _checkPathConflict(scew_element *nodeA,scew_element *nodeB)
784/// check to see if nodeA is in nodeB's path
785/**
786 * This is used by put() function (the RpLibrary flavor). It is
787 * used to check if nodeA can be safely deleted and not effect nodeB
788 */
789
790int
791RpLibrary::_checkPathConflict(scew_element *nodeA, scew_element *nodeB) const
792{
793    scew_element *testNode = NULL;
794
795    if ( (nodeA == NULL) || (nodeB == NULL) ) {
796        return 0;
797    }
798
799    if (nodeA == nodeB) {
800        return 1;
801    }
802
803    testNode = nodeB;
804
805    while ((testNode = scew_element_parent(testNode)) != NULL) {
806        if (testNode == nodeA) {
807            return 1;
808        }
809    }
810
811    return 0;
812}
813
814/**********************************************************************/
815// METHOD: element()
816/// Search the path of a xml tree and return a RpLibrary node.
817/**
818 * It is the user's responsibility to delete the object when
819 * they are finished using it?, else i need to make this static
820 */
821
822RpLibrary*
823RpLibrary::element (std::string path) const
824{
825    RpLibrary* retLib = NULL;
826    scew_element* retNode = NULL;
827
828    if (!this->root) {
829        // library doesn't exist, do nothing;
830        return NULL;
831    }
832
833    /*
834    if (path.empty()) {
835        // an empty path returns the current RpLibrary
836        return this;
837    }
838    */
839
840    if (path.empty()) {
841        // this should be a smart pointer,
842        // if someone deletes the original this->root, this object is void
843        // and will be a memory leak.
844        // retNode = this->root;
845        retLib = new RpLibrary(*this);
846    }
847    else {
848        // get the node located at path
849        retNode = _find(path,NO_CREATE_PATH);
850
851        // if the node exists, create a rappture library object for it.
852        if (retNode) {
853            retLib = new RpLibrary( retNode,this->tree );
854        }
855    }
856
857    return retLib;
858}
859
860/**********************************************************************/
861// METHOD: entities()
862/// Search the path of a xml tree and return a list of its entities.
863/**
864 */
865
866std::list<std::string>
867RpLibrary::entities  (std::string path) const
868{
869    std::list<std::string> queue;
870    std::list<std::string>::iterator iter;
871    std::list<std::string> retList;
872    std::list<std::string> childList;
873    std::list<std::string>::iterator childIter;
874
875    RpLibrary* ele = NULL;
876    std::string pathBack = "";
877
878    RpLibrary* child = NULL;
879    std::string childType = "";
880    std::string childPath = "";
881    std::string paramsPath = "";
882
883    RpLibrary* cchild = NULL;
884    std::string cchildType = "";
885    std::string cchildPath = "";
886
887    queue.push_back(path);
888    iter = queue.begin();
889
890    while( iter != queue.end() ) {
891        ele = this->element(*iter);
892        child = NULL;
893
894        if ((*iter).empty()) {
895            pathBack = "";
896        }
897        else {
898            pathBack = *iter + ".";
899        }
900
901        while ( ele && (child = ele->children("",child)) != NULL ) {
902            childList.push_back(child->nodeComp());
903            delete child;
904        }
905
906        childIter = childList.begin();
907
908        while (childIter != childList.end()) {
909            child = ele->element(*childIter);
910
911            childType = child->nodeType();
912            childPath = child->nodeComp();
913            if ( (childType == "group") || (childType == "phase") ) {
914                // add this path to the queue for paths to search
915                queue.push_back(pathBack+childPath);
916            }
917            else if (childType == "structure") {
918                // add this path to the return list
919                retList.push_back(pathBack+child->nodeComp());
920
921                // check to see if there is a ".current.parameters" node
922                // if so, add them to the queue list for paths to search
923                paramsPath = "current.parameters";
924                if (child->element(paramsPath) != NULL) {
925                    queue.push_back((pathBack+child->nodeComp()+"."+paramsPath));
926                }
927            }
928            else {
929                // add this path to the return list
930                retList.push_back(pathBack+child->nodeComp());
931
932                // look for embedded groups and phases
933                // add them to the queue list for paths to search
934                cchild = NULL;
935                while ( (cchild = child->children("",cchild)) != NULL ) {
936                    cchildType = cchild->nodeType();
937                    cchildPath = cchild->nodePath();
938                    if ( (cchildType == "group") || (cchildType == "phase") ) {
939                        // add this path to the queue for paths to search
940                        queue.push_back(cchildPath);
941                    }
942                    delete cchild;
943                }
944            }
945
946            childList.erase(childIter);
947            childIter = childList.begin();
948            delete child;
949        }
950
951        queue.erase(iter);
952        iter = queue.begin();
953    }
954
955    return retList;
956}
957
958/**********************************************************************/
959// METHOD: diff()
960/// find the differences between two xml trees.
961/**
962 */
963
964std::list<std::string>
965RpLibrary::diff (RpLibrary* otherLib, std::string path) const
966{
967
968    std::list<std::string> thisVal; // two node list of specific entity's value
969    std::list<std::string> otherVal; // two node list of specific entity's value
970
971    std::list<std::string> thisv; // list of this library's entities
972    std::list<std::string>::iterator thisIter;
973
974    std::list<std::string> otherv; // list of other library's entities
975    std::list<std::string>::iterator otherIter;
976
977    std::list<std::string> retList;
978
979    std::string entry = "";
980    std::string thisSpath = "";  // temp string
981    std::string otherSpath = ""; // temp string
982
983    if ( (!this->root) || (!otherLib->root) ) {
984        // library doesn't exist, do nothing;
985        return retList;
986    }
987
988
989    thisv = this->entities(path);
990    otherv = otherLib->entities(path);
991
992    thisIter = thisv.begin();
993
994    while (thisIter != thisv.end() ) {
995        // reset otherIter for a new search.
996        otherIter = otherv.begin();
997        while ( (otherIter != otherv.end()) && (*otherIter != *thisIter) ) {
998            otherIter++;
999        }
1000
1001        //if (!path.empty()) {
1002        //    thisSpath = path + "." + *thisIter;
1003        //}
1004        //else {
1005        //    thisSpath = *thisIter;
1006        //}
1007        thisSpath = *thisIter;
1008
1009        if (otherIter == otherv.end()) {
1010            // we've reached the end of the search
1011            // and did not find anything, mark this as a '-'
1012            thisVal = this->value(thisSpath);
1013            retList.push_back("-");
1014            retList.push_back(thisSpath);
1015            retList.push_back(thisVal.front());
1016            retList.push_back("");
1017        }
1018        else {
1019
1020            //if (!path.empty()) {
1021            //    otherSpath = path + "." + *otherIter;
1022            //}
1023            //else {
1024            //    otherSpath = *otherIter;
1025            //}
1026            otherSpath = *otherIter;
1027
1028            thisVal = this->value(thisSpath);
1029            otherVal = otherLib->value(otherSpath);
1030            if (thisVal.back() != otherVal.back()) {
1031                // add the difference to the return list
1032                retList.push_back("c");
1033                retList.push_back(otherSpath);
1034                retList.push_back(thisVal.front());
1035                retList.push_back(otherVal.front());
1036            }
1037
1038            // remove the last processed value from otherv
1039            otherv.erase(otherIter);
1040        }
1041
1042        // increment thisv's iterator.
1043        thisIter++;
1044    }
1045
1046    // add any left over values in otherv to the return list
1047    otherIter = otherv.begin();
1048    while ( otherIter != otherv.end() ) {
1049
1050        //if (!path.empty()) {
1051        //    otherSpath = path + "." + *otherIter;
1052        //}
1053        //else {
1054        //    otherSpath = *otherIter;
1055        //}
1056        otherSpath = *otherIter;
1057
1058        otherVal = otherLib->value(otherSpath);
1059
1060        retList.push_back("+");
1061        retList.push_back(otherSpath);
1062        retList.push_back("");
1063        retList.push_back(otherVal.front());
1064
1065        otherv.erase(otherIter);
1066        otherIter = otherv.begin();
1067    }
1068
1069    return retList;
1070}
1071
1072/**********************************************************************/
1073// METHOD: value(path)
1074/// Return a 2 element list containing the regular and normalized values.
1075/**
1076 */
1077
1078std::list<std::string>
1079RpLibrary::value (std::string path) const
1080{
1081    std::list<std::string> retArr;
1082
1083    std::string raw = "";
1084    std::string val = "";
1085
1086    RpLibrary* ele = NULL;
1087    RpLibrary* tele = NULL;
1088
1089    int childCount = 0;
1090    std::stringstream valStr;
1091
1092    ele = this->element(path);
1093
1094    if (ele != NULL ) {
1095
1096        if (ele->nodeType() == "structure") {
1097            raw = path;
1098            // try to find a label to represent the structure
1099            val = ele->get("about.label");
1100
1101            if (val == "") {
1102               val = ele->get("current.about.label");
1103            }
1104
1105            if (val == "") {
1106               tele = ele->element("current");
1107               if ( (tele != NULL) && (tele->nodeComp() != "") ) {
1108                   tele->children("components",NULL,"",&childCount);
1109                   valStr << "<structure> with " << childCount  << " components";
1110                   val = valStr.str();
1111               }
1112            }
1113
1114        }
1115        /*
1116        else if (ele->nodeType() == "number") {
1117            raw = "";
1118            retArr[1] = "";
1119            if ( (tele = ele->element("current")) != NULL) {
1120                raw = tele->get();
1121            }
1122            else if ( (tele = ele->element("default")) != NULL) {
1123                raw = tele->get();
1124            }
1125            val = raw
1126            if ( "" != raw) {
1127                // normalize the units
1128                units = ele->get("units");
1129                if ( "" != units) {
1130
1131                }
1132        }
1133        */
1134        else {
1135            raw = "";
1136            if ( (tele = ele->element("current")) != NULL) {
1137                raw = tele->get();
1138            }
1139            else if ( (tele = ele->element("default")) != NULL) {
1140                raw = tele->get();
1141            }
1142            val = raw;
1143        }
1144    }
1145
1146    retArr.push_back(raw);
1147    retArr.push_back(val);
1148
1149    return retArr;
1150}
1151
1152/**********************************************************************/
1153// METHOD: parent()
1154/// Search the path of a xml tree and return its parent.
1155/**
1156 * It is the user's responsibility to delete the object when
1157 * they are finished using it?, else i need to make this static
1158 */
1159
1160RpLibrary*
1161RpLibrary::parent (std::string path) const
1162{
1163    RpLibrary* retLib = NULL;
1164    std::string parentPath = "";
1165    scew_element* ele = NULL;
1166    scew_element* retNode = NULL;
1167
1168    if (!this->root) {
1169        // library doesn't exist, do nothing;
1170        return NULL;
1171    }
1172
1173    if (path.empty()) {
1174        // an empty path returns the parent of the current RpLibrary
1175        ele = this->root;
1176    }
1177    else {
1178        // else find the node representing the provided path
1179        ele = _find(path,NO_CREATE_PATH);
1180    }
1181
1182    if (ele != NULL) {
1183        retNode = scew_element_parent(ele);
1184        if (retNode) {
1185            // allocate a new rappture library object for the node
1186            retLib = new RpLibrary( retNode,this->tree );
1187        }
1188    }
1189    else {
1190        // path was not found by _find
1191    }
1192
1193
1194    return retLib;
1195}
1196
1197/**********************************************************************/
1198// METHOD: copy()
1199/// Copy the value from fromPath to toPath.
1200//  Copy the value from fromObj.fromPath to toPath
1201//  of the current rappture library object. This can copy rappture
1202//  library elements within or between xml trees.
1203/**
1204 */
1205
1206RpLibrary&
1207RpLibrary::copy (   std::string toPath,
1208                    RpLibrary* fromObj,
1209                    std::string fromPath )
1210{
1211    RpLibrary* value = NULL;
1212
1213    if (!this->root) {
1214        // library doesn't exist, do nothing;
1215        // need a good way to raise error, and this is not it.
1216        return *this;
1217    }
1218
1219    if (fromObj == NULL) {
1220        fromObj = this;
1221    }
1222
1223    if ( (fromObj == this) && (toPath == fromPath) ) {
1224        /* cannot copy over myself, causes path to disappear */
1225        return (*this);
1226    }
1227
1228    value = fromObj->element(fromPath);
1229
1230    if ( !value ) {
1231        status.error("fromPath could not be found within fromObj");
1232        status.addContext("RpLibrary::copy");
1233        return *this;
1234    }
1235
1236    this->put(toPath, value);
1237    status.addContext("RpLibrary::copy");
1238    delete value;
1239
1240    return (*this);
1241
1242}
1243
1244/**********************************************************************/
1245// METHOD: children()
1246/// Return the next child of the node located at 'path'
1247//
1248// The lookup is reset when you send a NULL rpChilNode.
1249// User is responsible for deleting returned values
1250//
1251/**
1252 */
1253
1254/*
1255RpLibrary*
1256RpLibrary::children (   std::string path,
1257                        RpLibrary* rpChildNode,
1258                        std::string type,
1259                        int* childCount)
1260{
1261    static std::string old_path = "";
1262    static RpLibrary* retLib = NULL;
1263    int myChildCount = 0;
1264    scew_element* parentNode = NULL;
1265    scew_element* childNode = NULL;
1266    std::string childName = "";
1267
1268    if (!this->root) {
1269        // library doesn't exist, do nothing;
1270        return NULL;
1271    }
1272
1273
1274    if (path.empty()) {
1275        // an empty path uses the current RpLibrary as parent
1276        parentNode = this->root;
1277    }
1278    else {
1279        // check to see if this path is the same as the one set
1280        // in the last call to this function.
1281        // if so, then we dont need to reset the parentNode
1282        //
1283        // this check is probably more dependent on rpChildNode
1284        // because we want to see if the person want to continue
1285        // an old search or start from the beginning of the child list
1286        //
1287        if ( (path.compare(old_path) == 0) && (rpChildNode != NULL) ) {
1288            parentNode = NULL;
1289        }
1290        // we need to search for a new parentNode
1291        else {
1292            parentNode = _find(path,NO_CREATE_PATH);
1293            if (parentNode == NULL) {
1294                // node not found
1295                // add error code here
1296                return NULL;
1297            }
1298        }
1299    }
1300
1301    old_path = path;
1302
1303
1304    if (rpChildNode) {
1305        childNode = rpChildNode->root;
1306    }
1307
1308    if (parentNode) {
1309        myChildCount = scew_element_count(parentNode);
1310    }
1311
1312    if (childCount) {
1313        *childCount = myChildCount;
1314    }
1315
1316    // clean up old memory
1317    delete retLib;
1318
1319    if ( (childNode = scew_element_next(parentNode,childNode)) ) {
1320
1321        if (!type.empty()) {
1322            childName = scew_element_name(childNode);
1323            // we are searching for a specific child name
1324            // keep looking till we find a name that matches the type.
1325            // if the current name does not match out search type,
1326            // grab the next child and check to see if its null
1327            // if its not null, get its name and test for type again
1328            while (  (type != childName)
1329                  && (childNode = scew_element_next(parentNode,childNode)) ) {
1330
1331                childName = scew_element_name(childNode);
1332            }
1333            if (type == childName) {
1334                // found a child with a name that matches type
1335                retLib = new RpLibrary( childNode,this->tree );
1336            }
1337            else {
1338                // no children with names that match 'type' were found
1339                retLib = NULL;
1340            }
1341        }
1342        else {
1343            retLib = new RpLibrary( childNode,this->tree );
1344        }
1345    }
1346    else {
1347        // somthing happened within scew, get error code and display
1348        // its probable there are no more child elements left to report
1349        retLib = NULL;
1350    }
1351
1352    return retLib;
1353}
1354*/
1355
1356RpLibrary*
1357RpLibrary::children (   std::string path,
1358                        RpLibrary* rpChildNode,
1359                        std::string type,
1360                        int* childCount)
1361{
1362    // this is static for efficency reasons
1363    static std::string old_path = "";
1364    // this was static so user never has to delete the retLib.
1365    // should be replaced by a smart pointer
1366    // static RpLibrary* retLib = NULL;
1367    RpLibrary* retLib = NULL;
1368    int myChildCount = 0;
1369    scew_element* parentNode = NULL;
1370    scew_element* childNode = NULL;
1371    std::string childName = "";
1372
1373    if (!this->root) {
1374        // library doesn't exist, do nothing;
1375        return NULL;
1376    }
1377
1378
1379    // check to see if the last call to this function
1380    // was searching for children of the same path.
1381    if ( (path.compare(old_path) == 0) && (rpChildNode != NULL) ) {
1382        parentNode = NULL;
1383    }
1384    else if (path.empty()) {
1385        // searching for children in a new path.
1386        // an empty path uses the current RpLibrary as parent
1387        parentNode = this->root;
1388    }
1389    else {
1390        // searching for children in a new, non-empty, path.
1391        parentNode = _find(path,NO_CREATE_PATH);
1392        if (parentNode == NULL) {
1393            // node not found
1394            // add error code here
1395            return NULL;
1396        }
1397    }
1398
1399    old_path = path;
1400
1401    if (rpChildNode) {
1402        childNode = rpChildNode->root;
1403    }
1404
1405    if (parentNode) {
1406        myChildCount = scew_element_count(parentNode);
1407        if (childCount) {
1408            *childCount = myChildCount;
1409        }
1410    }
1411
1412    // clean up old memory
1413    // delete retLib;
1414
1415    if ( (childNode = scew_element_next(parentNode,childNode)) ) {
1416
1417        if (!type.empty()) {
1418            childName = scew_element_name(childNode);
1419            // we are searching for a specific child name
1420            // keep looking till we find a name that matches the type.
1421            // if the current name does not match out search type,
1422            // grab the next child and check to see if its null
1423            // if its not null, get its name and test for type again
1424            while (  (type != childName)
1425                  && (childNode = scew_element_next(parentNode,childNode)) ) {
1426
1427                childName = scew_element_name(childNode);
1428            }
1429            if (type == childName) {
1430                // found a child with a name that matches type
1431                retLib = new RpLibrary( childNode,this->tree );
1432            }
1433            else {
1434                // no children with names that match 'type' were found
1435                retLib = NULL;
1436            }
1437        }
1438        else {
1439            retLib = new RpLibrary( childNode,this->tree );
1440        }
1441    }
1442    else {
1443        // somthing happened within scew, get error code and display
1444        // its probable there are no more child elements left to report
1445        retLib = NULL;
1446    }
1447
1448    return retLib;
1449}
1450
1451/**********************************************************************/
1452// METHOD: childCount()
1453/// Returns a std::list<RpLibrary*> of all children under 'path'
1454//
1455//
1456/**
1457 */
1458
1459RpLibrary&
1460RpLibrary::childCount(std::string path, int* childCount)
1461{
1462    if (this->root) {
1463        scew_element* parentNode;
1464        int myChildCount = 0;
1465
1466        parentNode = NULL;
1467        if (path.empty()) {
1468            // an empty path uses the current RpLibrary as parent
1469            parentNode = this->root;
1470        }
1471
1472        if (parentNode) {
1473            myChildCount = scew_element_count(parentNode);
1474        }
1475
1476        if (childCount) {
1477            *childCount = myChildCount;
1478        }
1479    }
1480    return *this;
1481}
1482
1483/**********************************************************************/
1484// METHOD: isNull()
1485/// returns whether this RpLibrary is a valid library node
1486//
1487//
1488/**
1489 */
1490
1491bool
1492RpLibrary::isNull () const
1493{
1494    if (this->root) {
1495        return false;
1496    }
1497
1498    return true;
1499}
1500
1501/**********************************************************************/
1502// METHOD: get()
1503/// Return the string value of the object held at location 'path'
1504/**
1505 */
1506
1507std::string
1508RpLibrary::get (std::string path, int translateFlag) const
1509{
1510    return (this->getString(path, translateFlag));
1511}
1512
1513/**********************************************************************/
1514// METHOD: getString()
1515/// Return the string value of the object held at location 'path'
1516/**
1517 */
1518
1519std::string
1520RpLibrary::getString (std::string path, int translateFlag) const
1521{
1522    Rappture::EntityRef ERTranslator;
1523    scew_element* retNode = NULL;
1524    XML_Char const* retCStr = NULL;
1525    const char* translatedContents = NULL;
1526    std::string retStr = "";
1527    Rappture::Buffer inData;
1528
1529    status.addContext("RpLibrary::getString");
1530    if (!this->root) {
1531        // library doesn't exist, do nothing;
1532        return retStr;
1533    }
1534
1535    retNode = _find(path,NO_CREATE_PATH);
1536
1537    if (retNode == NULL) {
1538        // need to raise error
1539        return retStr;
1540    }
1541
1542    retCStr = scew_element_contents(retNode);
1543    if (!retCStr) {
1544        return retStr;
1545    }
1546    inData = Rappture::Buffer(retCStr);
1547
1548    if (Rappture::encoding::headerFlags(inData.bytes(),inData.size()) != 0) {
1549        // data is encoded,
1550        // coming from an rplib, this means it was at least base64 encoded
1551        // there is no reason to do entity translation
1552        // because base64 character set does not include xml entity chars
1553        if (!Rappture::encoding::decode(status, inData, 0)) {
1554            return retStr;
1555        }
1556        retStr = std::string(inData.bytes(),inData.size());
1557    } else {
1558        // check translateFlag to see if we need to translate entity refs
1559        if (translateFlag == RPLIB_TRANSLATE) {
1560            translatedContents = ERTranslator.decode(inData.bytes(),
1561                                                     inData.size());
1562            if (translatedContents == NULL) {
1563                // translation failed
1564                if (!status) {
1565                    status.error("Error while translating entity references");
1566                    return retStr;
1567                }
1568            } else {
1569                // subtract 1 from size because ERTranslator adds extra NULL
1570                retStr = std::string(translatedContents,ERTranslator.size()-1);
1571                translatedContents = NULL;
1572            }
1573        }
1574    }
1575    inData.clear();
1576    return retStr;
1577}
1578
1579/**********************************************************************/
1580// METHOD: getDouble()
1581/// Return the double value of the object held at location 'path'
1582/**
1583 */
1584
1585double
1586RpLibrary::getDouble (std::string path) const
1587{
1588    std::string retValStr = "";
1589    double retValDbl = 0;
1590
1591    if (!this->root) {
1592        // library doesn't exist, do nothing;
1593        return retValDbl;
1594    }
1595
1596    retValStr = this->getString(path);
1597    status.addContext("RpLibrary::getDouble");
1598    // think about changing this to strtod()
1599    retValDbl = atof(retValStr.c_str());
1600
1601    return retValDbl;
1602}
1603
1604
1605/**********************************************************************/
1606// METHOD: getInt()
1607/// Return the integer value of the object held at location 'path'
1608/**
1609 */
1610
1611int
1612RpLibrary::getInt (std::string path) const
1613{
1614    std::string retValStr = "";
1615    int retValInt = 0;
1616
1617    if (!this->root) {
1618        // library doesn't exist, do nothing;
1619        return retValInt;
1620    }
1621
1622    retValStr = this->getString(path);
1623    status.addContext("RpLibrary::getInt");
1624    // think about changing this to strtod()
1625    retValInt = atoi(retValStr.c_str());
1626
1627    return retValInt;
1628}
1629
1630
1631/**********************************************************************/
1632// METHOD: getBool()
1633/// Return the boolean value of the object held at location 'path'
1634/**
1635 */
1636
1637bool
1638RpLibrary::getBool (std::string path) const
1639{
1640    std::string retValStr = "";
1641    bool retValBool = false;
1642    int retValLen = 0;
1643
1644    if (!this->root) {
1645        // library doesn't exist, do nothing;
1646        return retValBool;
1647    }
1648
1649    retValStr = this->getString(path);
1650    status.addContext("RpLibrary::getBool");
1651    std::transform (retValStr.begin(),retValStr.end(),retValStr.begin(),tolower);
1652    retValLen = retValStr.length();
1653
1654    if ((retValStr.compare(0,retValLen,"1",0,retValLen) == 0  )   ||
1655        (retValStr.compare(0,retValLen,"yes",0,retValLen) == 0 )  ||
1656        (retValStr.compare(0,retValLen,"true",0,retValLen) == 0 ) ||
1657        (retValStr.compare(0,retValLen,"on",0,retValLen) == 0))
1658    {
1659        retValBool = true;
1660    }
1661    else if((retValStr.compare(0,retValLen,"0",0,retValLen) == 0  )    ||
1662            (retValStr.compare(0,retValLen,"no",0,retValLen) == 0 )    ||
1663            (retValStr.compare(0,retValLen,"false",0,retValLen) == 0 ) ||
1664            (retValStr.compare(0,retValLen,"off",0,retValLen) == 0))
1665    {
1666        retValBool = false;
1667    }
1668    else {
1669        // default to false?
1670        retValBool = false;
1671    }
1672
1673    return retValBool;
1674}
1675
1676
1677/**********************************************************************/
1678// METHOD: getData()
1679/// Return a pointer and memory size of the object held at location 'path'
1680/**
1681 */
1682
1683Rappture::Buffer
1684RpLibrary::getData (std::string path) const
1685{
1686    Rappture::EntityRef ERTranslator;
1687    scew_element* retNode = NULL;
1688    const char* retCStr = NULL;
1689    Rappture::Buffer buf;
1690    int translateFlag = RPLIB_TRANSLATE;
1691    const char* translatedContents = NULL;
1692    int len = 0;
1693
1694    if (!this->root) {
1695        // library doesn't exist, do nothing;
1696        return buf;
1697    }
1698
1699    retNode = _find(path,NO_CREATE_PATH);
1700
1701    if (retNode == NULL) {
1702        // need to raise error
1703        status.error("could not find element located at path");
1704        status.addContext("RpLibrary::getData()");
1705        return buf;
1706    }
1707
1708    retCStr = scew_element_contents(retNode);
1709
1710    if (retCStr == NULL) {
1711        // element located at path is empty
1712        return buf;
1713    }
1714
1715    if (translateFlag == RPLIB_TRANSLATE) {
1716        translatedContents = ERTranslator.decode(retCStr,0);
1717        if (translatedContents == NULL) {
1718            // translation failed
1719            if (!status) {
1720                status.error("Error while translating entity references");
1721                status.addContext("RpLibrary::getData()");
1722            }
1723        }
1724        else {
1725            len = strlen(translatedContents);
1726            buf.append(translatedContents,len);
1727            translatedContents = NULL;
1728        }
1729    }
1730    else {
1731        len = strlen(retCStr);
1732        buf.append(retCStr,len);
1733    }
1734
1735    return buf;
1736}
1737
1738
1739/**********************************************************************/
1740// METHOD: getFile()
1741/// Get the value at path and write it to the file at fileName
1742/**
1743 * Return the number of bytes written
1744 */
1745
1746size_t
1747RpLibrary::getFile (std::string path, std::string fileName) const
1748{
1749    Rappture::Buffer buf;
1750
1751    buf = getData(path);
1752
1753    if (buf.bad()) {
1754        status.addContext("RpLibrary::getFile()");
1755        return 0;
1756    }
1757
1758    if (!buf.dump(status, fileName.c_str())) {
1759        status.addContext("RpLibrary::getFile()");
1760        return 0;
1761    }
1762
1763    return buf.size();
1764}
1765
1766
1767/**********************************************************************/
1768// METHOD: put()
1769/// Put a string value into the xml.
1770/**
1771 */
1772
1773RpLibrary&
1774RpLibrary::put (std::string path, std::string value, std::string id,
1775                unsigned int append, unsigned int translateFlag)
1776{
1777    Rappture::EntityRef ERTranslator;
1778    scew_element* retNode = NULL;
1779    std::string tmpVal = "";
1780    const char* contents = NULL;
1781    const char* translatedContents = NULL;
1782
1783    status.addContext("RpLibrary::put() - putString");
1784
1785    if (!this->root) {
1786        // library doesn't exist, do nothing;
1787        status.error("invalid library object");
1788        return *this;
1789    }
1790
1791    // check for binary data
1792    // FIXME: I've already appended a NUL-byte of this assuming that
1793    //        it's a ASCII string. This test must come before.
1794    if (Rappture::encoding::isBinary(value.c_str(), value.length())) {
1795        putData(path, value.c_str(), value.length(), append);
1796        return *this;
1797    }
1798
1799    retNode = _find(path, CREATE_PATH);
1800    if (retNode == NULL) {
1801        // node not found, set error
1802        status.error("Error while searching for node: node not found");
1803        return *this;
1804    }
1805
1806    if (translateFlag == RPLIB_TRANSLATE) {
1807        translatedContents = ERTranslator.encode(value.c_str(),0);
1808        if (translatedContents == NULL) {
1809            // entity referene translation failed
1810            if (!status) {
1811                status.error("Error while translating entity references");
1812                return *this;
1813            }
1814        }
1815        else {
1816            value = std::string(translatedContents);
1817            translatedContents = NULL;
1818        }
1819    }
1820    if (append == RPLIB_APPEND) {
1821        contents = scew_element_contents(retNode);
1822        if (contents != NULL) {
1823            tmpVal = std::string(contents);
1824            value = tmpVal + value;
1825        }
1826    }
1827    scew_element_set_contents(retNode,value.c_str());
1828    return *this;
1829}
1830
1831/**********************************************************************/
1832// METHOD: put()
1833/// Put a double value into the xml.
1834/**
1835 */
1836
1837RpLibrary&
1838RpLibrary::put (std::string path, double value, std::string id,
1839                unsigned int append)
1840{
1841    std::stringstream valStr;
1842
1843    if (this->root == NULL) {
1844        // library doesn't exist, do nothing;
1845        status.error("invalid library object");
1846        status.addContext("RpLibrary::put() - putDouble");
1847        return *this;
1848    }
1849
1850    valStr << value;
1851
1852    put(path,valStr.str(),id,append);
1853    return *this;
1854}
1855
1856/**********************************************************************/
1857// METHOD: put()
1858/// Put a RpLibrary* value into the xml. This is used by copy()
1859/**
1860 *  Append flag adds additional nodes, it does not merge same
1861 *  named nodes together
1862 */
1863
1864RpLibrary&
1865RpLibrary::put (    std::string path,
1866                    RpLibrary* value,
1867                    std::string id,
1868                    unsigned int append )
1869{
1870    scew_element *retNode   = NULL;
1871    scew_element *new_elem  = NULL;
1872    scew_element *childNode = NULL;
1873    scew_element *tmpNode   = NULL;
1874    const char *contents    = NULL;
1875    int retVal              = 1;
1876    int deleteTmpNode       = 0;
1877
1878    if (this->root == NULL) {
1879        // library doesn't exist, do nothing;
1880        status.error("invalid library object");
1881        status.addContext("RpLibrary::put()");
1882        return *this;
1883    }
1884
1885    if (value == NULL) {
1886        // you cannot put a null RpLibrary into the tree
1887        // user specified a null value
1888        status.error("user specified NULL value");
1889        status.addContext("RpLibrary::put()");
1890        return *this;
1891    }
1892
1893    if (value->root == NULL) {
1894        // you cannot put a null RpLibrary into the tree
1895        // user specified a null value
1896        status.error("user specified uninitialized RpLibrary object");
1897        status.addContext("RpLibrary::put()");
1898        return *this;
1899    }
1900
1901    tmpNode = value->root;
1902
1903    if (append == RPLIB_OVERWRITE) {
1904        retNode = _find(path,NO_CREATE_PATH);
1905        if (retNode) {
1906            // compare roots to see if they are part of the
1907            // same xml tree, if so, make a tmp copy of the
1908            // tree to be copied before freeing it.
1909            if (_checkPathConflict(retNode,tmpNode)) {
1910                tmpNode = scew_element_copy(tmpNode);
1911                deleteTmpNode = 1;
1912            }
1913            contents = scew_element_contents(tmpNode);
1914            if (contents) {
1915                scew_element_set_contents(retNode, "");
1916            }
1917
1918            while ( (childNode = scew_element_next(retNode,childNode)) ) {
1919                scew_element_free(childNode);
1920            }
1921        }
1922        else {
1923            // path did not exist and was not created
1924            // do nothing
1925        }
1926    }
1927
1928    retNode = _find(path,CREATE_PATH);
1929
1930    if (retNode) {
1931        contents = scew_element_contents(tmpNode);
1932        if (contents) {
1933            scew_element_set_contents(retNode, contents);
1934        }
1935
1936        while ( (childNode = scew_element_next(tmpNode,childNode)) ) {
1937            if ((new_elem = scew_element_copy(childNode))) {
1938                if (scew_element_add_elem(retNode, new_elem)) {
1939                    // maybe we want to count the number of children
1940                    // that we have successfully added?
1941                    retVal = 0;
1942                }
1943                else {
1944                    // adding new element failed
1945                    status.error("error while adding child node");
1946                    status.addContext("RpLibrary::put()");
1947                }
1948            }
1949            else {
1950                // copying new element failed
1951                status.error("error while copying child node");
1952                status.addContext("RpLibrary::put()");
1953            }
1954        }
1955
1956        if (deleteTmpNode == 1) {
1957            scew_element_free(tmpNode);
1958        }
1959    }
1960    else {
1961        // path did not exist and was not created.
1962        status.error("error while creating child node");
1963        status.addContext("RpLibrary::put()");
1964    }
1965
1966    return *this;
1967}
1968
1969
1970/**********************************************************************/
1971// METHOD: putData()
1972/// Put a data from a buffer into the xml.
1973/**
1974 *  Append flag adds additional nodes, it does not merge same
1975 *  named nodes together
1976 */
1977
1978RpLibrary&
1979RpLibrary::putData (std::string path,
1980                    const char* bytes,
1981                    int nbytes,
1982                    unsigned int append  )
1983{
1984    scew_element* retNode = NULL;
1985    const char* contents = NULL;
1986    Rappture::Buffer inData;
1987    unsigned int bytesWritten = 0;
1988    size_t flags = 0;
1989
1990    status.addContext("RpLibrary::putData()");
1991    if (!this->root) {
1992        // library doesn't exist, do nothing;
1993        return *this;
1994    }
1995    retNode = _find(path,CREATE_PATH);
1996
1997    if (retNode == NULL) {
1998        status.addError("can't create node from path \"%s\"", path.c_str());
1999        return *this;
2000    }
2001    if (append == RPLIB_APPEND) {
2002        if ( (contents = scew_element_contents(retNode)) ) {
2003            inData.append(contents);
2004            // base64 decode and un-gzip the data
2005            if (!Rappture::encoding::decode(status, inData, 0)) {
2006                return *this;
2007            }
2008        }
2009    }
2010    if (inData.append(bytes, nbytes) != nbytes) {
2011        status.addError("can't append %d bytes", nbytes);
2012        return *this;
2013    }
2014    // gzip and base64 encode the data
2015    flags = RPENC_Z|RPENC_B64|RPENC_HDR;
2016    if (!Rappture::encoding::encode(status, inData,flags)) {
2017        return *this;
2018    }
2019    bytesWritten = (unsigned int) inData.size();
2020    scew_element_set_contents_binary(retNode,inData.bytes(),&bytesWritten);
2021    return *this;
2022}
2023
2024
2025/**********************************************************************/
2026// METHOD: putFile()
2027/// Put data from a file into the xml.
2028/**
2029 *  Append flag adds additional nodes, it does not merge same
2030 *  named nodes together
2031 */
2032
2033RpLibrary&
2034RpLibrary::putFile(std::string path, std::string fileName,
2035                   unsigned int compress, unsigned int append)
2036{
2037    Rappture::Buffer buf;
2038    Rappture::Buffer fileBuf;
2039
2040    if (!this->root) {
2041        // library doesn't exist, do nothing;
2042        return *this;
2043    }
2044
2045    if (!fileBuf.load(status, fileName.c_str())) {
2046        fprintf(stderr, "error loading file: %s\n", status.remark());
2047        status.addContext("RpLibrary::putFile()");
2048        return *this;
2049    }
2050    if (compress == RPLIB_COMPRESS) {
2051        putData(path, fileBuf.bytes(), fileBuf.size(), append);
2052    } else {
2053        /* Always append a NUL-byte to the end of ASCII strings. */
2054        fileBuf.append("\0", 1);
2055        put(path, fileBuf.bytes(), "", append, RPLIB_TRANSLATE);
2056    }
2057    return *this;
2058}
2059
2060
2061/**********************************************************************/
2062// METHOD: remove()
2063/// Remove the provided path from this RpLibrary
2064/**
2065 */
2066
2067RpLibrary*
2068RpLibrary::remove ( std::string path )
2069{
2070    scew_element* ele = NULL;
2071    int setNULL = 0;
2072    RpLibrary* retLib = NULL;
2073
2074    if (!this->root) {
2075        // library doesn't exist, do nothing;
2076        return NULL;
2077    }
2078
2079    if ( !path.empty() ) {
2080        ele = _find(path,NO_CREATE_PATH);
2081    }
2082    else {
2083        // telling this function to remove "" is essentially destroying
2084        // the object. most functions will fail after a call like this.
2085        ele = this->root;
2086        setNULL++;
2087    }
2088
2089    if (ele) {
2090        scew_element_free(ele);
2091        if (setNULL != 0) {
2092            // this is the case where user specified an empty path.
2093            // the object is useless, and will be deleted.
2094            this->root = NULL;
2095            retLib = NULL;
2096        }
2097        else {
2098            retLib = this;
2099        }
2100    }
2101
2102    return retLib;
2103}
2104
2105/**********************************************************************/
2106// METHOD: xml()
2107/// Return the xml text held in this RpLibrary
2108/**
2109 */
2110
2111std::string
2112RpLibrary::xml () const
2113{
2114    std::stringstream outString;
2115
2116    if (!this->root) {
2117        // library doesn't exist, do nothing;
2118        return std::string("");
2119    }
2120
2121    outString << "<?xml version=\"1.0\"?>\n";
2122    print_element(this->root, 0, outString);
2123
2124    return outString.str();
2125}
2126
2127/**********************************************************************/
2128// METHOD: nodeType()
2129/// Return the type name of this node
2130/**
2131 */
2132
2133std::string
2134RpLibrary::nodeType () const
2135{
2136    if (!this->root) {
2137        // library doesn't exist, do nothing;
2138        return std::string("");
2139    }
2140
2141    return std::string(scew_element_name(root));
2142}
2143
2144/**********************************************************************/
2145// METHOD: nodeId()
2146/// Return the id of this node.
2147/**
2148 */
2149
2150std::string
2151RpLibrary::nodeId () const
2152{
2153    if (!this->root) {
2154        // library doesn't exist, do nothing;
2155        return std::string("");
2156    }
2157
2158    return _node2name(root);
2159}
2160
2161/**********************************************************************/
2162// METHOD: nodeComp()
2163/// Return the component name of this node.
2164/**
2165 */
2166
2167std::string
2168RpLibrary::nodeComp () const
2169{
2170    if (!this->root) {
2171        // library doesn't exist, do nothing;
2172        return std::string("");
2173    }
2174
2175    return _node2comp(root);
2176}
2177
2178/**********************************************************************/
2179// METHOD: nodePath()
2180/// Return the component name of this node's path.
2181/**
2182 */
2183
2184std::string
2185RpLibrary::nodePath () const
2186{
2187    if (!this->root) {
2188        // library doesn't exist, do nothing;
2189        return std::string("");
2190    }
2191
2192    return _node2path(root);
2193}
2194
2195/**********************************************************************/
2196// METHOD: outcome()
2197/// Return the status object of this library object.
2198/**
2199 */
2200
2201Rappture::Outcome&
2202RpLibrary::outcome() const
2203{
2204    return status;
2205}
2206
2207/*
2208 * ----------------------------------------------------------------------
2209 *  METHOD: result
2210 *
2211 *  Clients call this function at the end of their simulation, to
2212 *  pass the simulation result back to the Rappture GUI.  It writes
2213 *  out the given XML object to a runXXX.xml file, and then writes
2214 *  out the name of that file to stdout.
2215 * ======================================================================
2216 *  AUTHOR:  Michael McLennan, Purdue University
2217 *  Copyright (c) 2004-2007
2218 *  Purdue Research Foundation, West Lafayette, IN
2219 * ======================================================================
2220 */
2221void
2222RpLibrary::result(int exitStatus)
2223{
2224    std::stringstream outputFile;
2225    std::fstream file;
2226    std::string xmlText = "";
2227    time_t t = 0;
2228    struct tm* timeinfo = NULL;
2229    std::string timestamp = "";
2230    std::string username = "";
2231    std::string hostname = "";
2232    char *user = NULL;
2233
2234    if (this->root) {
2235#ifdef _POSIX_SOURCE
2236        // if the posix function gettimeofday is available,
2237        // we can get more precision on the time and more
2238        // unique filenames.
2239        struct timeval tv;
2240        gettimeofday(&tv,NULL);
2241        outputFile << "run" << tv.tv_sec << tv.tv_usec << ".xml";
2242#else
2243        outputFile << "run" << (int)time(&t) << ".xml";
2244#endif
2245        file.open(outputFile.str().c_str(),std::ios::out);
2246
2247        put("tool.version.rappture.revision","$LastChangedRevision: 3175 $");
2248        put("tool.version.rappture.modified","$LastChangedDate: 2012-09-20 19:46:32 +0000 (Thu, 20 Sep 2012) $");
2249        if ( "" == get("tool.version.rappture.language") ) {
2250            put("tool.version.rappture.language","c++");
2251        }
2252
2253        // generate a timestamp for the run file
2254        timeinfo = localtime(&t);
2255        timestamp = std::string(ctime(&t));
2256        // erase the 24th character because it is a newline
2257        timestamp.erase(24);
2258        // concatinate the timezone
2259        timestamp.append(" ");
2260#ifdef _WIN32
2261        timestamp.append(_tzname[_daylight]);
2262        // username is left blank for windows because i dont know
2263        // how to retrieve username on win32 environment.
2264        username = "";
2265        hostname = "";
2266#else
2267        timestamp.append(timeinfo->tm_zone);
2268        user = getenv("USER");
2269        if (user != NULL) {
2270            username = std::string(user);
2271        } else {
2272            user = getenv("LOGNAME");
2273            if (user != NULL) {
2274                username = std::string(user);
2275            }
2276        }
2277#endif
2278
2279        // add the timestamp to the run file
2280        put("output.time", timestamp);
2281        put("output.status",exitStatus);
2282        put("output.user",username);
2283        put("output.host",hostname);
2284
2285        if ( file.is_open() ) {
2286            xmlText = xml();
2287            if (!xmlText.empty()) {
2288                file << xmlText;
2289            }
2290            // check to make sure there were no
2291            // errors while writing the run.xml file.
2292            if (   (!file.good())
2293                || ((long)xmlText.length() != ((long)file.tellp()-(long)1))
2294               ) {
2295                 status.error("Error while writing run file");
2296                 status.addContext("RpLibrary::result()");
2297            }
2298            file.close();
2299        }
2300        else {
2301            status.error("Error while opening run file");
2302            status.addContext("RpLibrary::result()");
2303        }
2304        std::cout << "=RAPPTURE-RUN=>" << outputFile.str() << std::endl;
2305    }
2306}
2307
2308/**********************************************************************/
2309// METHOD: print_indent()
2310/// Add indentations to the requested stringstream object.
2311/**
2312 */
2313
2314void
2315RpLibrary::print_indent(    unsigned int indent,
2316                            std::stringstream& outString ) const
2317{
2318
2319    // keep this around incase you want to use tabs instead of spaces
2320    // while ( (indent--) > 0)
2321    // {
2322    //     outString << "\t";
2323    // }
2324
2325    // keep this around incase you want to use spaces instead of tabs
2326    int cnt = indent*INDENT_SIZE;
2327    while ( (cnt--) > 0)
2328    {
2329        outString << " ";
2330    }
2331
2332}
2333
2334/**********************************************************************/
2335// METHOD: print_attributes()
2336/// Print the attribute names and values for the provided xml node
2337/**
2338 */
2339
2340void
2341RpLibrary::print_attributes(    scew_element* element,
2342                                std::stringstream& outString ) const
2343{
2344    scew_attribute* attribute = NULL;
2345
2346    if (element != NULL)
2347    {
2348        if (scew_attribute_count(element) > 0) {
2349            /**
2350             * Iterates through the element's attribute list, printing the
2351             * pair name-value.
2352             */
2353            attribute = NULL;
2354            while((attribute=scew_attribute_next(element, attribute)) != NULL)
2355            {
2356                outString << " " << scew_attribute_name(attribute) << "=\"" <<
2357                       scew_attribute_value(attribute) << "\"";
2358            }
2359        }
2360    }
2361}
2362
2363
2364/**********************************************************************/
2365// METHOD: print_element()
2366/// Print the value of the node and its attributes to a stringstream object
2367/**
2368 */
2369
2370void
2371RpLibrary::print_element(   scew_element* element,
2372                            unsigned int indent,
2373                            std::stringstream& outString    ) const
2374{
2375    scew_element* child = NULL;
2376    XML_Char const* contents = NULL;
2377
2378    if (element == NULL)
2379    {
2380        return;
2381    }
2382
2383    /**
2384     * Prints the starting element tag with its attributes.
2385     */
2386    print_indent(indent, outString);
2387    outString << "<" << scew_element_name(element);
2388    print_attributes(element,outString);
2389    outString << ">";
2390    contents = scew_element_contents(element);
2391    if (contents == NULL)
2392    {
2393        outString << "\n";
2394    }
2395
2396    /**
2397     * Call print_element function again for each child of the
2398     * current element.
2399     */
2400    child = NULL;
2401    while ((child = scew_element_next(element, child)) != NULL)
2402    {
2403        print_element(child, indent + 1, outString);
2404    }
2405
2406    /* Prints element's content. */
2407    if (contents != NULL)
2408    {
2409        outString << contents;
2410    }
2411    else
2412    {
2413        print_indent(indent, outString);
2414    }
2415
2416    /**
2417     * Prints the closing element tag.
2418     */
2419    outString << "</" << scew_element_name(element) << ">\n" ;
2420}
Note: See TracBrowser for help on using the repository browser.