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

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

allow the user to create a new empty rappture library object in c++ and python bindings. this is useful when you want to create new xml files.

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