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

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