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

Last change on this file since 788 was 788, checked in by dkearney, 14 years ago

adjustments to entity references encoding to include the length of the string to encode and decode.
this is used for the python bindings, so we can know the length of the string being returned and allow embedded nulls.

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