source: branches/blt4/src/core/RpLibrary.cc @ 1824

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