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

Last change on this file since 1041 was 1041, checked in by gah, 15 years ago

hide scew from external rappture interface

  • Property svn:keywords set to Date Rev URL
File size: 64.0 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    if (!this->root) {
1523        // library doesn't exist, do nothing;
1524        return retStr;
1525    }
1526
1527    retNode = _find(path,NO_CREATE_PATH);
1528
1529    if (retNode == NULL) {
1530        // need to raise error
1531        return retStr;
1532    }
1533
1534    retCStr = scew_element_contents(retNode);
1535
1536    if (!retCStr) {
1537        return retStr;
1538    }
1539
1540    inData = Rappture::Buffer(retCStr);
1541    status &= Rappture::encoding::decode(inData,0);
1542    status.addContext("RpLibrary::getSting");
1543    // inData.append("\0",1);
1544
1545    if (translateFlag == RPLIB_TRANSLATE) {
1546        translatedContents = ERTranslator.decode(inData.bytes(),inData.size());
1547        if (translatedContents == NULL) {
1548            // translation failed
1549            if (!status) {
1550                status.error("Error while translating entity references");
1551                status.addContext("RpLibrary::getSting");
1552            }
1553        }
1554        else {
1555            // subtract 1 from size because ERTranslator adds extra NULL
1556            retStr = std::string(translatedContents,ERTranslator.size()-1);
1557            translatedContents = NULL;
1558        }
1559    }
1560    else {
1561        retStr = std::string(inData.bytes(),inData.size());
1562    }
1563
1564    inData.clear();
1565
1566    return retStr;
1567}
1568
1569/**********************************************************************/
1570// METHOD: getDouble()
1571/// Return the double value of the object held at location 'path'
1572/**
1573 */
1574
1575double
1576RpLibrary::getDouble (std::string path) const
1577{
1578    std::string retValStr = "";
1579    double retValDbl = 0;
1580
1581    if (!this->root) {
1582        // library doesn't exist, do nothing;
1583        return retValDbl;
1584    }
1585
1586    retValStr = this->getString(path);
1587    status.addContext("RpLibrary::getDouble");
1588    // think about changing this to strtod()
1589    retValDbl = atof(retValStr.c_str());
1590
1591    return retValDbl;
1592}
1593
1594
1595/**********************************************************************/
1596// METHOD: getInt()
1597/// Return the integer value of the object held at location 'path'
1598/**
1599 */
1600
1601int
1602RpLibrary::getInt (std::string path) const
1603{
1604    std::string retValStr = "";
1605    int retValInt = 0;
1606
1607    if (!this->root) {
1608        // library doesn't exist, do nothing;
1609        return retValInt;
1610    }
1611
1612    retValStr = this->getString(path);
1613    status.addContext("RpLibrary::getInt");
1614    // think about changing this to strtod()
1615    retValInt = atoi(retValStr.c_str());
1616
1617    return retValInt;
1618}
1619
1620
1621/**********************************************************************/
1622// METHOD: getBool()
1623/// Return the boolean value of the object held at location 'path'
1624/**
1625 */
1626
1627bool
1628RpLibrary::getBool (std::string path) const
1629{
1630    std::string retValStr = "";
1631    bool retValBool = false;
1632    int retValLen = 0;
1633
1634    if (!this->root) {
1635        // library doesn't exist, do nothing;
1636        return retValBool;
1637    }
1638
1639    retValStr = this->getString(path);
1640    status.addContext("RpLibrary::getBool");
1641    std::transform (retValStr.begin(),retValStr.end(),retValStr.begin(),tolower);
1642    retValLen = retValStr.length();
1643
1644    if ((retValStr.compare(0,retValLen,"1",0,retValLen) == 0  )   ||
1645        (retValStr.compare(0,retValLen,"yes",0,retValLen) == 0 )  ||
1646        (retValStr.compare(0,retValLen,"true",0,retValLen) == 0 ) ||
1647        (retValStr.compare(0,retValLen,"on",0,retValLen) == 0))
1648    {
1649        retValBool = true;
1650    }
1651    else if((retValStr.compare(0,retValLen,"0",0,retValLen) == 0  )    ||
1652            (retValStr.compare(0,retValLen,"no",0,retValLen) == 0 )    ||
1653            (retValStr.compare(0,retValLen,"false",0,retValLen) == 0 ) ||
1654            (retValStr.compare(0,retValLen,"off",0,retValLen) == 0))
1655    {
1656        retValBool = false;
1657    }
1658    else {
1659        // default to false?
1660        retValBool = false;
1661    }
1662
1663    return retValBool;
1664}
1665
1666
1667/**********************************************************************/
1668// METHOD: getData()
1669/// Return a pointer and memory size of the object held at location 'path'
1670/**
1671 */
1672
1673Rappture::Buffer
1674RpLibrary::getData (std::string path) const
1675{
1676    Rappture::EntityRef ERTranslator;
1677    scew_element* retNode = NULL;
1678    const char* retCStr = NULL;
1679    Rappture::Buffer buf;
1680    int translateFlag = RPLIB_TRANSLATE;
1681    const char* translatedContents = NULL;
1682    int len = 0;
1683
1684    if (!this->root) {
1685        // library doesn't exist, do nothing;
1686        return buf;
1687    }
1688
1689    retNode = _find(path,NO_CREATE_PATH);
1690
1691    if (retNode == NULL) {
1692        // need to raise error
1693        status.error("could not find element located at path");
1694        status.addContext("RpLibrary::getData()");
1695        return buf;
1696    }
1697
1698    retCStr = scew_element_contents(retNode);
1699
1700    if (retCStr == NULL) {
1701        // element located at path is empty
1702        return buf;
1703    }
1704
1705    if (translateFlag == RPLIB_TRANSLATE) {
1706        translatedContents = ERTranslator.decode(retCStr,0);
1707        if (translatedContents == NULL) {
1708            // translation failed
1709            if (!status) {
1710                status.error("Error while translating entity references");
1711                status.addContext("RpLibrary::getData()");
1712            }
1713        }
1714        else {
1715            len = strlen(translatedContents);
1716            buf.append(translatedContents,len);
1717            translatedContents = NULL;
1718        }
1719    }
1720    else {
1721        len = strlen(retCStr);
1722        buf.append(retCStr,len);
1723    }
1724
1725    return buf;
1726}
1727
1728
1729/**********************************************************************/
1730// METHOD: put()
1731/// Put a string value into the xml.
1732/**
1733 */
1734
1735RpLibrary&
1736RpLibrary::put (    std::string path,
1737                    std::string value,
1738                    std::string id,
1739                    unsigned int append,
1740                    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    if (!this->root) {
1749        // library doesn't exist, do nothing;
1750        status.error("invalid library object");
1751        status.addContext("RpLibrary::put() - putString");
1752        return *this;
1753    }
1754
1755    // check for binary data
1756    if (Rappture::encoding::isbinary(value.c_str(),value.length()) != 0) {
1757        putData(path,value.c_str(),value.length(),append);
1758        status.addContext("RpLibrary::put() - putString");
1759        return *this;
1760    }
1761
1762    retNode = _find(path,CREATE_PATH);
1763
1764    if (retNode == NULL) {
1765        // node not found, set error
1766        status.error("Error while searching for node: node not found");
1767        status.addContext("RpLibrary::put() - putString");
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            }
1778        }
1779        else {
1780            value = std::string(translatedContents);
1781            translatedContents = NULL;
1782        }
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
1793    scew_element_set_contents(retNode,value.c_str());
1794
1795    status.addContext("RpLibrary::put() - putString");
1796    return *this;
1797}
1798
1799/**********************************************************************/
1800// METHOD: put()
1801/// Put a double value into the xml.
1802/**
1803 */
1804
1805RpLibrary&
1806RpLibrary::put (    std::string path,
1807                    double value,
1808                    std::string id,
1809                    unsigned int append )
1810{
1811    std::stringstream valStr;
1812
1813    if (this->root == NULL) {
1814        // library doesn't exist, do nothing;
1815        status.error("invalid library object");
1816        status.addContext("RpLibrary::put()");
1817        return *this;
1818    }
1819
1820    valStr << value;
1821
1822    put(path,valStr.str(),id,append);
1823    status.addContext("RpLibrary::put() - putDouble");
1824    return *this;
1825}
1826
1827/**********************************************************************/
1828// METHOD: put()
1829/// Put a RpLibrary* value into the xml. This is used by copy()
1830/**
1831 *  Append flag adds additional nodes, it does not merge same
1832 *  named nodes together
1833 */
1834
1835RpLibrary&
1836RpLibrary::put (    std::string path,
1837                    RpLibrary* value,
1838                    std::string id,
1839                    unsigned int append )
1840{
1841    scew_element *retNode   = NULL;
1842    scew_element *new_elem  = NULL;
1843    scew_element *childNode = NULL;
1844    scew_element *tmpNode   = NULL;
1845    const char *contents    = NULL;
1846    int retVal              = 1;
1847    int deleteTmpNode       = 0;
1848
1849    if (this->root == NULL) {
1850        // library doesn't exist, do nothing;
1851        status.error("invalid library object");
1852        status.addContext("RpLibrary::put()");
1853        return *this;
1854    }
1855
1856    if (value == NULL) {
1857        // you cannot put a null RpLibrary into the tree
1858        // user specified a null value
1859        status.error("user specified NULL value");
1860        status.addContext("RpLibrary::put()");
1861        return *this;
1862    }
1863
1864    if (value->root == NULL) {
1865        // you cannot put a null RpLibrary into the tree
1866        // user specified a null value
1867        status.error("user specified uninitialized RpLibrary object");
1868        status.addContext("RpLibrary::put()");
1869        return *this;
1870    }
1871
1872    tmpNode = value->root;
1873
1874    if (append == RPLIB_OVERWRITE) {
1875        retNode = _find(path,NO_CREATE_PATH);
1876        if (retNode) {
1877            // compare roots to see if they are part of the
1878            // same xml tree, if so, make a tmp copy of the
1879            // tree to be copied before freeing it.
1880            if (_checkPathConflict(retNode,tmpNode)) {
1881                tmpNode = scew_element_copy(tmpNode);
1882                deleteTmpNode = 1;
1883            }
1884            contents = scew_element_contents(tmpNode);
1885            if (contents) {
1886                scew_element_set_contents(retNode, "");
1887            }
1888
1889            while ( (childNode = scew_element_next(retNode,childNode)) ) {
1890                scew_element_free(childNode);
1891            }
1892        }
1893        else {
1894            // path did not exist and was not created
1895            // do nothing
1896        }
1897    }
1898
1899    retNode = _find(path,CREATE_PATH);
1900
1901    if (retNode) {
1902        contents = scew_element_contents(tmpNode);
1903        if (contents) {
1904            scew_element_set_contents(retNode, contents);
1905        }
1906
1907        while ( (childNode = scew_element_next(tmpNode,childNode)) ) {
1908            if ((new_elem = scew_element_copy(childNode))) {
1909                if (scew_element_add_elem(retNode, new_elem)) {
1910                    // maybe we want to count the number of children
1911                    // that we have successfully added?
1912                    retVal = 0;
1913                }
1914                else {
1915                    // adding new element failed
1916                    status.error("error while adding child node");
1917                    status.addContext("RpLibrary::put()");
1918                }
1919            }
1920            else {
1921                // copying new element failed
1922                status.error("error while copying child node");
1923                status.addContext("RpLibrary::put()");
1924            }
1925        }
1926
1927        if (deleteTmpNode == 1) {
1928            scew_element_free(tmpNode);
1929        }
1930    }
1931    else {
1932        // path did not exist and was not created.
1933        status.error("error while creating child node");
1934        status.addContext("RpLibrary::put()");
1935    }
1936
1937    return *this;
1938}
1939
1940
1941/**********************************************************************/
1942// METHOD: putData()
1943/// Put a data from a buffer into the xml.
1944/**
1945 *  Append flag adds additional nodes, it does not merge same
1946 *  named nodes together
1947 */
1948
1949RpLibrary&
1950RpLibrary::putData (std::string path,
1951                    const char* bytes,
1952                    int nbytes,
1953                    unsigned int append  )
1954{
1955    scew_element* retNode = NULL;
1956    const char* contents = NULL;
1957    Rappture::Buffer inData;
1958    unsigned int bytesWritten = 0;
1959    int flags = 0;
1960
1961    if (!this->root) {
1962        // library doesn't exist, do nothing;
1963        return *this;
1964    }
1965
1966    retNode = _find(path,CREATE_PATH);
1967
1968    if (retNode) {
1969
1970        if (append == RPLIB_APPEND) {
1971            if ( (contents = scew_element_contents(retNode)) ) {
1972                inData.append(contents);
1973                // base64 decode and un-gzip the data
1974                status &= Rappture::encoding::decode(inData,0);
1975                if (int(status) != 0) {
1976                    status.addContext("RpLibrary::putData()");
1977                    return *this;
1978                }
1979            }
1980        }
1981
1982        inData.append(bytes,nbytes);
1983        // gzip and base64 encode the data
1984        flags = RPENC_Z|RPENC_B64|RPENC_HDR;
1985        status &= Rappture::encoding::encode(inData,flags);
1986
1987        bytesWritten = (unsigned int) inData.size();
1988        scew_element_set_contents_binary(retNode,inData.bytes(),&bytesWritten);
1989    }
1990    else {
1991        // node not found, set error
1992        if (!status) {
1993            status.error("Error while searching for node: node not found");
1994        }
1995    }
1996
1997    status.addContext("RpLibrary::putData()");
1998    return *this;
1999}
2000
2001
2002/**********************************************************************/
2003// METHOD: putFile()
2004/// Put data from a file into the xml.
2005/**
2006 *  Append flag adds additional nodes, it does not merge same
2007 *  named nodes together
2008 */
2009
2010RpLibrary&
2011RpLibrary::putFile (std::string path,
2012                    std::string fileName,
2013                    unsigned int compress,
2014                    unsigned int append  )
2015{
2016    Rappture::Buffer buf;
2017    Rappture::Buffer fileBuf;
2018    Rappture::Outcome err;
2019
2020    if (!this->root) {
2021        // library doesn't exist, do nothing;
2022        return *this;
2023    }
2024
2025    fileBuf.load(fileName.c_str());
2026    if (compress == RPLIB_COMPRESS) {
2027        putData(path,fileBuf.bytes(),fileBuf.size(),append);
2028    }
2029    else {
2030        fileBuf.append("\0",1);
2031        put(path,fileBuf.bytes(),"",append,RPLIB_TRANSLATE);
2032    }
2033    status.addContext("RpLibrary::putFile()");
2034    return *this;
2035}
2036
2037
2038/**********************************************************************/
2039// METHOD: remove()
2040/// Remove the provided path from this RpLibrary
2041/**
2042 */
2043
2044RpLibrary*
2045RpLibrary::remove ( std::string path )
2046{
2047    scew_element* ele = NULL;
2048    int setNULL = 0;
2049    RpLibrary* retLib = NULL;
2050
2051    if (!this->root) {
2052        // library doesn't exist, do nothing;
2053        return NULL;
2054    }
2055
2056    if ( !path.empty() ) {
2057        ele = _find(path,NO_CREATE_PATH);
2058    }
2059    else {
2060        // telling this function to remove "" is essentially destroying
2061        // the object. most functions will fail after a call like this.
2062        ele = this->root;
2063        setNULL++;
2064    }
2065
2066    if (ele) {
2067        scew_element_free(ele);
2068        if (setNULL != 0) {
2069            // this is the case where user specified an empty path.
2070            // the object is useless, and will be deleted.
2071            this->root = NULL;
2072            retLib = NULL;
2073        }
2074        else {
2075            retLib = this;
2076        }
2077    }
2078
2079    return retLib;
2080}
2081
2082/**********************************************************************/
2083// METHOD: xml()
2084/// Return the xml text held in this RpLibrary
2085/**
2086 */
2087
2088std::string
2089RpLibrary::xml () const
2090{
2091    std::stringstream outString;
2092
2093    if (!this->root) {
2094        // library doesn't exist, do nothing;
2095        return std::string("");
2096    }
2097
2098    outString << "<?xml version=\"1.0\"?>\n";
2099    print_element(this->root, 0, outString);
2100
2101    return outString.str();
2102}
2103
2104/**********************************************************************/
2105// METHOD: nodeType()
2106/// Return the type name of this node
2107/**
2108 */
2109
2110std::string
2111RpLibrary::nodeType () const
2112{
2113    if (!this->root) {
2114        // library doesn't exist, do nothing;
2115        return std::string("");
2116    }
2117
2118    return std::string(scew_element_name(root));
2119}
2120
2121/**********************************************************************/
2122// METHOD: nodeId()
2123/// Return the id of this node.
2124/**
2125 */
2126
2127std::string
2128RpLibrary::nodeId () const
2129{
2130    if (!this->root) {
2131        // library doesn't exist, do nothing;
2132        return std::string("");
2133    }
2134
2135    return _node2name(root);
2136}
2137
2138/**********************************************************************/
2139// METHOD: nodeComp()
2140/// Return the component name of this node.
2141/**
2142 */
2143
2144std::string
2145RpLibrary::nodeComp () const
2146{
2147    if (!this->root) {
2148        // library doesn't exist, do nothing;
2149        return std::string("");
2150    }
2151
2152    return _node2comp(root);
2153}
2154
2155/**********************************************************************/
2156// METHOD: nodePath()
2157/// Return the component name of this node's path.
2158/**
2159 */
2160
2161std::string
2162RpLibrary::nodePath () const
2163{
2164    if (!this->root) {
2165        // library doesn't exist, do nothing;
2166        return std::string("");
2167    }
2168
2169    return _node2path(root);
2170}
2171
2172/**********************************************************************/
2173// METHOD: outcome()
2174/// Return the status object of this library object.
2175/**
2176 */
2177
2178Rappture::Outcome&
2179RpLibrary::outcome() const
2180{
2181    return status;
2182}
2183
2184/*
2185 * ----------------------------------------------------------------------
2186 *  METHOD: result
2187 *
2188 *  Clients call this function at the end of their simulation, to
2189 *  pass the simulation result back to the Rappture GUI.  It writes
2190 *  out the given XML object to a runXXX.xml file, and then writes
2191 *  out the name of that file to stdout.
2192 * ======================================================================
2193 *  AUTHOR:  Michael McLennan, Purdue University
2194 *  Copyright (c) 2004-2007
2195 *  Purdue Research Foundation, West Lafayette, IN
2196 * ======================================================================
2197 */
2198void
2199RpLibrary::result(int exitStatus)
2200{
2201    std::stringstream outputFile;
2202    std::fstream file;
2203    std::string xmlText = "";
2204    time_t t = 0;
2205    struct tm* timeinfo = NULL;
2206    std::string timestamp = "";
2207    std::string username = "";
2208    std::string hostname = "";
2209    char *user = NULL;
2210
2211    if (this->root) {
2212        outputFile << "run" << (int)time(&t) << ".xml";
2213        file.open(outputFile.str().c_str(),std::ios::out);
2214
2215        put("tool.version.rappture.revision","$LastChangedRevision: 1041 $");
2216        put("tool.version.rappture.modified","$LastChangedDate: 2008-06-11 00:51:55 +0000 (Wed, 11 Jun 2008) $");
2217        if ( "" == get("tool.version.rappture.language") ) {
2218            put("tool.version.rappture.language","c++");
2219        }
2220
2221        // generate a timestamp for the run file
2222        timeinfo = localtime(&t);
2223        timestamp = std::string(ctime(&t));
2224        // erase the 24th character because it is a newline
2225        timestamp.erase(24);
2226        // concatinate the timezone
2227        timestamp.append(" ");
2228#ifdef _WIN32
2229        timestamp.append(_tzname[_daylight]);
2230        // username is left blank for windows because i dont know
2231        // how to retrieve username on win32 environment.
2232        username = "";
2233        hostname = "";
2234#else
2235        timestamp.append(timeinfo->tm_zone);
2236        user = getenv("USER");
2237        if (user != NULL) {
2238            username = std::string(user);
2239        } else {
2240            user = getenv("LOGNAME");
2241            if (user != NULL) {
2242                username = std::string(user);
2243            }
2244        }
2245#endif
2246
2247        // add the timestamp to the run file
2248        put("output.time", timestamp);
2249        put("output.status",exitStatus);
2250        put("output.user",username);
2251        put("output.host",hostname);
2252
2253        if ( file.is_open() ) {
2254            xmlText = xml();
2255            if (!xmlText.empty()) {
2256                file << xmlText;
2257            }
2258            // check to make sure there were no
2259            // errors while writing the run.xml file.
2260            if (   (!file.good())
2261                || ((long)xmlText.length() != ((long)file.tellp()-(long)1))
2262               ) {
2263                 status.error("Error while writing run file");
2264                 status.addContext("RpLibrary::result()");
2265            }
2266            file.close();
2267        }
2268        else {
2269            status.error("Error while opening run file");
2270            status.addContext("RpLibrary::result()");
2271        }
2272        std::cout << "=RAPPTURE-RUN=>" << outputFile.str() << std::endl;
2273    }
2274}
2275
2276/**********************************************************************/
2277// METHOD: print_indent()
2278/// Add indentations to the requested stringstream object.
2279/**
2280 */
2281
2282void
2283RpLibrary::print_indent(    unsigned int indent,
2284                            std::stringstream& outString ) const
2285{
2286
2287    // keep this around incase you want to use tabs instead of spaces
2288    // while ( (indent--) > 0)
2289    // {
2290    //     outString << "\t";
2291    // }
2292
2293    // keep this around incase you want to use spaces instead of tabs
2294    int cnt = indent*INDENT_SIZE;
2295    while ( (cnt--) > 0)
2296    {
2297        outString << " ";
2298    }
2299
2300}
2301
2302/**********************************************************************/
2303// METHOD: print_attributes()
2304/// Print the attribute names and values for the provided xml node
2305/**
2306 */
2307
2308void
2309RpLibrary::print_attributes(    scew_element* element,
2310                                std::stringstream& outString ) const
2311{
2312    scew_attribute* attribute = NULL;
2313
2314    if (element != NULL)
2315    {
2316        if (scew_attribute_count(element) > 0) {
2317            /**
2318             * Iterates through the element's attribute list, printing the
2319             * pair name-value.
2320             */
2321            attribute = NULL;
2322            while((attribute=scew_attribute_next(element, attribute)) != NULL)
2323            {
2324                outString << " " << scew_attribute_name(attribute) << "=\"" <<
2325                       scew_attribute_value(attribute) << "\"";
2326            }
2327        }
2328    }
2329}
2330
2331
2332/**********************************************************************/
2333// METHOD: print_element()
2334/// Print the value of the node and its attributes to a stringstream object
2335/**
2336 */
2337
2338void
2339RpLibrary::print_element(   scew_element* element,
2340                            unsigned int indent,
2341                            std::stringstream& outString    ) const
2342{
2343    scew_element* child = NULL;
2344    XML_Char const* contents = NULL;
2345
2346    if (element == NULL)
2347    {
2348        return;
2349    }
2350
2351    /**
2352     * Prints the starting element tag with its attributes.
2353     */
2354    print_indent(indent, outString);
2355    outString << "<" << scew_element_name(element);
2356    print_attributes(element,outString);
2357    outString << ">";
2358    contents = scew_element_contents(element);
2359    if (contents == NULL)
2360    {
2361        outString << "\n";
2362    }
2363
2364    /**
2365     * Call print_element function again for each child of the
2366     * current element.
2367     */
2368    child = NULL;
2369    while ((child = scew_element_next(element, child)) != NULL)
2370    {
2371        print_element(child, indent + 1, outString);
2372    }
2373
2374    /* Prints element's content. */
2375    if (contents != NULL)
2376    {
2377        outString << contents;
2378    }
2379    else
2380    {
2381        print_indent(indent, outString);
2382    }
2383
2384    /**
2385     * Prints the closing element tag.
2386     */
2387    outString << "</" << scew_element_name(element) << ">\n" ;
2388}
Note: See TracBrowser for help on using the repository browser.