source: branches/1.7/src/core/RpLibrary.cc @ 6708

Last change on this file since 6708 was 6708, checked in by clarksm, 5 years ago

Corrected path filename reversal in RAPPTURE-RUN message.

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