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

Last change on this file since 1040 was 1018, checked in by gah, 16 years ago

Massive changes: New directory/file layout

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