source: branches/uq/src/core/RpLibrary.cc @ 5679

Last change on this file since 5679 was 5679, checked in by ldelgass, 7 years ago

Full merge 1.3 branch to uq branch to sync. Fixed partial subdirectory merge
by removing mergeinfo from lang/python/Rappture directory.

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