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

Last change on this file since 2408 was 2408, checked in by dkearney, 11 years ago

adding a getFile function for rappture library and fortran bindings so fortran users no longer need to know the length of a string a user provides them as input, before compile time. they can now just dump the string into a file, and read the file as they are probably already used to doing. also fixed a bug in teh Rappture::Buffer dump function where it would correctly open a file pointer, but failed the check to see if the file pointer was opened.

  • Property svn:keywords set to Date Rev URL
File size: 65.3 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: getFile()
1738/// Get the value at path and write it to the file at fileName
1739/**
1740 * Return the number of bytes written
1741 */
1742
1743size_t
1744RpLibrary::getFile (std::string path, std::string fileName) const
1745{
1746    Rappture::Buffer buf;
1747
1748    buf = getData(path);
1749
1750    if (buf.bad()) {
1751        status.addContext("RpLibrary::getFile()");
1752        return 0;
1753    }
1754
1755    if (!buf.dump(status, fileName.c_str())) {
1756        status.addContext("RpLibrary::getFile()");
1757        return 0;
1758    }
1759
1760    return buf.size();
1761}
1762
1763
1764/**********************************************************************/
1765// METHOD: put()
1766/// Put a string value into the xml.
1767/**
1768 */
1769
1770RpLibrary&
1771RpLibrary::put (std::string path, std::string value, std::string id,
1772                unsigned int append, unsigned int translateFlag)
1773{
1774    Rappture::EntityRef ERTranslator;
1775    scew_element* retNode = NULL;
1776    std::string tmpVal = "";
1777    const char* contents = NULL;
1778    const char* translatedContents = NULL;
1779
1780    status.addContext("RpLibrary::put() - putString");
1781
1782    if (!this->root) {
1783        // library doesn't exist, do nothing;
1784        status.error("invalid library object");
1785        return *this;
1786    }
1787
1788    // check for binary data
1789    // FIXME: I've already appended a NUL-byte of this assuming that
1790    //        it's a ASCII string. This test must come before.
1791    if (Rappture::encoding::isBinary(value.c_str(), value.length())) {
1792        putData(path, value.c_str(), value.length(), append);
1793        return *this;
1794    }
1795
1796    retNode = _find(path, CREATE_PATH);
1797    if (retNode == NULL) {
1798        // node not found, set error
1799        status.error("Error while searching for node: node not found");
1800        return *this;
1801    }
1802
1803    if (translateFlag == RPLIB_TRANSLATE) {
1804        translatedContents = ERTranslator.encode(value.c_str(),0);
1805        if (translatedContents == NULL) {
1806            // entity referene translation failed
1807            if (!status) {
1808                status.error("Error while translating entity references");
1809                return *this;
1810            }
1811        }
1812        else {
1813            value = std::string(translatedContents);
1814            translatedContents = NULL;
1815        }
1816    }
1817    if (append == RPLIB_APPEND) {
1818        contents = scew_element_contents(retNode);
1819        if (contents != NULL) {
1820            tmpVal = std::string(contents);
1821            value = tmpVal + value;
1822        }
1823    }
1824    scew_element_set_contents(retNode,value.c_str());
1825    return *this;
1826}
1827
1828/**********************************************************************/
1829// METHOD: put()
1830/// Put a double value into the xml.
1831/**
1832 */
1833
1834RpLibrary&
1835RpLibrary::put (std::string path, double value, std::string id,
1836                unsigned int append)
1837{
1838    std::stringstream valStr;
1839
1840    if (this->root == NULL) {
1841        // library doesn't exist, do nothing;
1842        status.error("invalid library object");
1843        status.addContext("RpLibrary::put() - putDouble");
1844        return *this;
1845    }
1846
1847    valStr << value;
1848
1849    put(path,valStr.str(),id,append);
1850    return *this;
1851}
1852
1853/**********************************************************************/
1854// METHOD: put()
1855/// Put a RpLibrary* value into the xml. This is used by copy()
1856/**
1857 *  Append flag adds additional nodes, it does not merge same
1858 *  named nodes together
1859 */
1860
1861RpLibrary&
1862RpLibrary::put (    std::string path,
1863                    RpLibrary* value,
1864                    std::string id,
1865                    unsigned int append )
1866{
1867    scew_element *retNode   = NULL;
1868    scew_element *new_elem  = NULL;
1869    scew_element *childNode = NULL;
1870    scew_element *tmpNode   = NULL;
1871    const char *contents    = NULL;
1872    int retVal              = 1;
1873    int deleteTmpNode       = 0;
1874
1875    if (this->root == NULL) {
1876        // library doesn't exist, do nothing;
1877        status.error("invalid library object");
1878        status.addContext("RpLibrary::put()");
1879        return *this;
1880    }
1881
1882    if (value == NULL) {
1883        // you cannot put a null RpLibrary into the tree
1884        // user specified a null value
1885        status.error("user specified NULL value");
1886        status.addContext("RpLibrary::put()");
1887        return *this;
1888    }
1889
1890    if (value->root == NULL) {
1891        // you cannot put a null RpLibrary into the tree
1892        // user specified a null value
1893        status.error("user specified uninitialized RpLibrary object");
1894        status.addContext("RpLibrary::put()");
1895        return *this;
1896    }
1897
1898    tmpNode = value->root;
1899
1900    if (append == RPLIB_OVERWRITE) {
1901        retNode = _find(path,NO_CREATE_PATH);
1902        if (retNode) {
1903            // compare roots to see if they are part of the
1904            // same xml tree, if so, make a tmp copy of the
1905            // tree to be copied before freeing it.
1906            if (_checkPathConflict(retNode,tmpNode)) {
1907                tmpNode = scew_element_copy(tmpNode);
1908                deleteTmpNode = 1;
1909            }
1910            contents = scew_element_contents(tmpNode);
1911            if (contents) {
1912                scew_element_set_contents(retNode, "");
1913            }
1914
1915            while ( (childNode = scew_element_next(retNode,childNode)) ) {
1916                scew_element_free(childNode);
1917            }
1918        }
1919        else {
1920            // path did not exist and was not created
1921            // do nothing
1922        }
1923    }
1924
1925    retNode = _find(path,CREATE_PATH);
1926
1927    if (retNode) {
1928        contents = scew_element_contents(tmpNode);
1929        if (contents) {
1930            scew_element_set_contents(retNode, contents);
1931        }
1932
1933        while ( (childNode = scew_element_next(tmpNode,childNode)) ) {
1934            if ((new_elem = scew_element_copy(childNode))) {
1935                if (scew_element_add_elem(retNode, new_elem)) {
1936                    // maybe we want to count the number of children
1937                    // that we have successfully added?
1938                    retVal = 0;
1939                }
1940                else {
1941                    // adding new element failed
1942                    status.error("error while adding child node");
1943                    status.addContext("RpLibrary::put()");
1944                }
1945            }
1946            else {
1947                // copying new element failed
1948                status.error("error while copying child node");
1949                status.addContext("RpLibrary::put()");
1950            }
1951        }
1952
1953        if (deleteTmpNode == 1) {
1954            scew_element_free(tmpNode);
1955        }
1956    }
1957    else {
1958        // path did not exist and was not created.
1959        status.error("error while creating child node");
1960        status.addContext("RpLibrary::put()");
1961    }
1962
1963    return *this;
1964}
1965
1966
1967/**********************************************************************/
1968// METHOD: putData()
1969/// Put a data from a buffer into the xml.
1970/**
1971 *  Append flag adds additional nodes, it does not merge same
1972 *  named nodes together
1973 */
1974
1975RpLibrary&
1976RpLibrary::putData (std::string path,
1977                    const char* bytes,
1978                    int nbytes,
1979                    unsigned int append  )
1980{
1981    scew_element* retNode = NULL;
1982    const char* contents = NULL;
1983    Rappture::Buffer inData;
1984    unsigned int bytesWritten = 0;
1985    size_t flags = 0;
1986
1987    status.addContext("RpLibrary::putData()");
1988    if (!this->root) {
1989        // library doesn't exist, do nothing;
1990        return *this;
1991    }
1992    retNode = _find(path,CREATE_PATH);
1993
1994    if (retNode == NULL) {
1995        status.addError("can't create node from path \"%s\"", path.c_str());
1996        return *this;
1997    }
1998    if (append == RPLIB_APPEND) {
1999        if ( (contents = scew_element_contents(retNode)) ) {
2000            inData.append(contents);
2001            // base64 decode and un-gzip the data
2002            if (!Rappture::encoding::decode(status, inData, 0)) {
2003                return *this;
2004            }
2005        }
2006    }
2007    if (inData.append(bytes, nbytes) != nbytes) {
2008        status.addError("can't append %d bytes", nbytes);
2009        return *this;
2010    }
2011    // gzip and base64 encode the data
2012    flags = RPENC_Z|RPENC_B64|RPENC_HDR;
2013    if (!Rappture::encoding::encode(status, inData,flags)) {
2014        return *this;
2015    }
2016    bytesWritten = (unsigned int) inData.size();
2017    scew_element_set_contents_binary(retNode,inData.bytes(),&bytesWritten);
2018    return *this;
2019}
2020
2021
2022/**********************************************************************/
2023// METHOD: putFile()
2024/// Put data from a file into the xml.
2025/**
2026 *  Append flag adds additional nodes, it does not merge same
2027 *  named nodes together
2028 */
2029
2030RpLibrary&
2031RpLibrary::putFile(std::string path, std::string fileName,
2032                   unsigned int compress, unsigned int append)
2033{
2034    Rappture::Buffer buf;
2035    Rappture::Buffer fileBuf;
2036
2037    if (!this->root) {
2038        // library doesn't exist, do nothing;
2039        return *this;
2040    }
2041
2042    if (!fileBuf.load(status, fileName.c_str())) {
2043        fprintf(stderr, "error loading file: %s\n", status.remark());
2044        status.addContext("RpLibrary::putFile()");
2045        return *this;
2046    }
2047    if (compress == RPLIB_COMPRESS) {
2048        putData(path, fileBuf.bytes(), fileBuf.size(), append);
2049    } else {
2050        /* Always append a NUL-byte to the end of ASCII strings. */
2051        fileBuf.append("\0", 1);
2052        put(path, fileBuf.bytes(), "", append, RPLIB_TRANSLATE);
2053    }
2054    return *this;
2055}
2056
2057
2058/**********************************************************************/
2059// METHOD: remove()
2060/// Remove the provided path from this RpLibrary
2061/**
2062 */
2063
2064RpLibrary*
2065RpLibrary::remove ( std::string path )
2066{
2067    scew_element* ele = NULL;
2068    int setNULL = 0;
2069    RpLibrary* retLib = NULL;
2070
2071    if (!this->root) {
2072        // library doesn't exist, do nothing;
2073        return NULL;
2074    }
2075
2076    if ( !path.empty() ) {
2077        ele = _find(path,NO_CREATE_PATH);
2078    }
2079    else {
2080        // telling this function to remove "" is essentially destroying
2081        // the object. most functions will fail after a call like this.
2082        ele = this->root;
2083        setNULL++;
2084    }
2085
2086    if (ele) {
2087        scew_element_free(ele);
2088        if (setNULL != 0) {
2089            // this is the case where user specified an empty path.
2090            // the object is useless, and will be deleted.
2091            this->root = NULL;
2092            retLib = NULL;
2093        }
2094        else {
2095            retLib = this;
2096        }
2097    }
2098
2099    return retLib;
2100}
2101
2102/**********************************************************************/
2103// METHOD: xml()
2104/// Return the xml text held in this RpLibrary
2105/**
2106 */
2107
2108std::string
2109RpLibrary::xml () const
2110{
2111    std::stringstream outString;
2112
2113    if (!this->root) {
2114        // library doesn't exist, do nothing;
2115        return std::string("");
2116    }
2117
2118    outString << "<?xml version=\"1.0\"?>\n";
2119    print_element(this->root, 0, outString);
2120
2121    return outString.str();
2122}
2123
2124/**********************************************************************/
2125// METHOD: nodeType()
2126/// Return the type name of this node
2127/**
2128 */
2129
2130std::string
2131RpLibrary::nodeType () const
2132{
2133    if (!this->root) {
2134        // library doesn't exist, do nothing;
2135        return std::string("");
2136    }
2137
2138    return std::string(scew_element_name(root));
2139}
2140
2141/**********************************************************************/
2142// METHOD: nodeId()
2143/// Return the id of this node.
2144/**
2145 */
2146
2147std::string
2148RpLibrary::nodeId () const
2149{
2150    if (!this->root) {
2151        // library doesn't exist, do nothing;
2152        return std::string("");
2153    }
2154
2155    return _node2name(root);
2156}
2157
2158/**********************************************************************/
2159// METHOD: nodeComp()
2160/// Return the component name of this node.
2161/**
2162 */
2163
2164std::string
2165RpLibrary::nodeComp () const
2166{
2167    if (!this->root) {
2168        // library doesn't exist, do nothing;
2169        return std::string("");
2170    }
2171
2172    return _node2comp(root);
2173}
2174
2175/**********************************************************************/
2176// METHOD: nodePath()
2177/// Return the component name of this node's path.
2178/**
2179 */
2180
2181std::string
2182RpLibrary::nodePath () const
2183{
2184    if (!this->root) {
2185        // library doesn't exist, do nothing;
2186        return std::string("");
2187    }
2188
2189    return _node2path(root);
2190}
2191
2192/**********************************************************************/
2193// METHOD: outcome()
2194/// Return the status object of this library object.
2195/**
2196 */
2197
2198Rappture::Outcome&
2199RpLibrary::outcome() const
2200{
2201    return status;
2202}
2203
2204/*
2205 * ----------------------------------------------------------------------
2206 *  METHOD: result
2207 *
2208 *  Clients call this function at the end of their simulation, to
2209 *  pass the simulation result back to the Rappture GUI.  It writes
2210 *  out the given XML object to a runXXX.xml file, and then writes
2211 *  out the name of that file to stdout.
2212 * ======================================================================
2213 *  AUTHOR:  Michael McLennan, Purdue University
2214 *  Copyright (c) 2004-2007
2215 *  Purdue Research Foundation, West Lafayette, IN
2216 * ======================================================================
2217 */
2218void
2219RpLibrary::result(int exitStatus)
2220{
2221    std::stringstream outputFile;
2222    std::fstream file;
2223    std::string xmlText = "";
2224    time_t t = 0;
2225    struct tm* timeinfo = NULL;
2226    std::string timestamp = "";
2227    std::string username = "";
2228    std::string hostname = "";
2229    char *user = NULL;
2230
2231    if (this->root) {
2232#ifdef _POSIX_SOURCE
2233        // if the posix function gettimeofday is available,
2234        // we can get more precision on the time and more
2235        // unique filenames.
2236        struct timeval tv;
2237        gettimeofday(&tv,NULL);
2238        outputFile << "run" << tv.tv_sec << tv.tv_usec << ".xml";
2239#else
2240        outputFile << "run" << (int)time(&t) << ".xml";
2241#endif
2242        file.open(outputFile.str().c_str(),std::ios::out);
2243
2244        put("tool.version.rappture.revision","$LastChangedRevision: 2408 $");
2245        put("tool.version.rappture.modified","$LastChangedDate: 2011-08-25 02:01:44 +0000 (Thu, 25 Aug 2011) $");
2246        if ( "" == get("tool.version.rappture.language") ) {
2247            put("tool.version.rappture.language","c++");
2248        }
2249
2250        // generate a timestamp for the run file
2251        timeinfo = localtime(&t);
2252        timestamp = std::string(ctime(&t));
2253        // erase the 24th character because it is a newline
2254        timestamp.erase(24);
2255        // concatinate the timezone
2256        timestamp.append(" ");
2257#ifdef _WIN32
2258        timestamp.append(_tzname[_daylight]);
2259        // username is left blank for windows because i dont know
2260        // how to retrieve username on win32 environment.
2261        username = "";
2262        hostname = "";
2263#else
2264        timestamp.append(timeinfo->tm_zone);
2265        user = getenv("USER");
2266        if (user != NULL) {
2267            username = std::string(user);
2268        } else {
2269            user = getenv("LOGNAME");
2270            if (user != NULL) {
2271                username = std::string(user);
2272            }
2273        }
2274#endif
2275
2276        // add the timestamp to the run file
2277        put("output.time", timestamp);
2278        put("output.status",exitStatus);
2279        put("output.user",username);
2280        put("output.host",hostname);
2281
2282        if ( file.is_open() ) {
2283            xmlText = xml();
2284            if (!xmlText.empty()) {
2285                file << xmlText;
2286            }
2287            // check to make sure there were no
2288            // errors while writing the run.xml file.
2289            if (   (!file.good())
2290                || ((long)xmlText.length() != ((long)file.tellp()-(long)1))
2291               ) {
2292                 status.error("Error while writing run file");
2293                 status.addContext("RpLibrary::result()");
2294            }
2295            file.close();
2296        }
2297        else {
2298            status.error("Error while opening run file");
2299            status.addContext("RpLibrary::result()");
2300        }
2301        std::cout << "=RAPPTURE-RUN=>" << outputFile.str() << std::endl;
2302    }
2303}
2304
2305/**********************************************************************/
2306// METHOD: print_indent()
2307/// Add indentations to the requested stringstream object.
2308/**
2309 */
2310
2311void
2312RpLibrary::print_indent(    unsigned int indent,
2313                            std::stringstream& outString ) const
2314{
2315
2316    // keep this around incase you want to use tabs instead of spaces
2317    // while ( (indent--) > 0)
2318    // {
2319    //     outString << "\t";
2320    // }
2321
2322    // keep this around incase you want to use spaces instead of tabs
2323    int cnt = indent*INDENT_SIZE;
2324    while ( (cnt--) > 0)
2325    {
2326        outString << " ";
2327    }
2328
2329}
2330
2331/**********************************************************************/
2332// METHOD: print_attributes()
2333/// Print the attribute names and values for the provided xml node
2334/**
2335 */
2336
2337void
2338RpLibrary::print_attributes(    scew_element* element,
2339                                std::stringstream& outString ) const
2340{
2341    scew_attribute* attribute = NULL;
2342
2343    if (element != NULL)
2344    {
2345        if (scew_attribute_count(element) > 0) {
2346            /**
2347             * Iterates through the element's attribute list, printing the
2348             * pair name-value.
2349             */
2350            attribute = NULL;
2351            while((attribute=scew_attribute_next(element, attribute)) != NULL)
2352            {
2353                outString << " " << scew_attribute_name(attribute) << "=\"" <<
2354                       scew_attribute_value(attribute) << "\"";
2355            }
2356        }
2357    }
2358}
2359
2360
2361/**********************************************************************/
2362// METHOD: print_element()
2363/// Print the value of the node and its attributes to a stringstream object
2364/**
2365 */
2366
2367void
2368RpLibrary::print_element(   scew_element* element,
2369                            unsigned int indent,
2370                            std::stringstream& outString    ) const
2371{
2372    scew_element* child = NULL;
2373    XML_Char const* contents = NULL;
2374
2375    if (element == NULL)
2376    {
2377        return;
2378    }
2379
2380    /**
2381     * Prints the starting element tag with its attributes.
2382     */
2383    print_indent(indent, outString);
2384    outString << "<" << scew_element_name(element);
2385    print_attributes(element,outString);
2386    outString << ">";
2387    contents = scew_element_contents(element);
2388    if (contents == NULL)
2389    {
2390        outString << "\n";
2391    }
2392
2393    /**
2394     * Call print_element function again for each child of the
2395     * current element.
2396     */
2397    child = NULL;
2398    while ((child = scew_element_next(element, child)) != NULL)
2399    {
2400        print_element(child, indent + 1, outString);
2401    }
2402
2403    /* Prints element's content. */
2404    if (contents != NULL)
2405    {
2406        outString << contents;
2407    }
2408    else
2409    {
2410        print_indent(indent, outString);
2411    }
2412
2413    /**
2414     * Prints the closing element tag.
2415     */
2416    outString << "</" << scew_element_name(element) << ">\n" ;
2417}
Note: See TracBrowser for help on using the repository browser.