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

Last change on this file since 1707 was 1707, checked in by dkearney, 13 years ago

adding temp fix for how we format filenames. the changes will provide more unique filenames down to near millisecond resolution of time for semi-POSIX compliant systems. I needed this fix in particular for workflow stuff i am playing with.

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