source: trunk/src/objects/RpPath.cc @ 1528

Last change on this file since 1528 was 1528, checked in by dkearney, 15 years ago

updating the objects code and adding some more examples describing how i want developers to use the objects. some of the objects don't work yet, like the tree, anything with an example should work

File size: 13.4 KB
Line 
1/*
2 * ======================================================================
3 *  Rappture::Path
4 *
5 *  AUTHOR:  Derrick Kearney, Purdue University
6 *
7 *  Copyright (c) 2004-2008  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 "RpPath.h"
15
16#include <fstream>
17#include <assert.h>
18
19#ifdef __cplusplus
20    extern "C" {
21#endif // ifdef __cplusplus
22
23#include "RpChainHelper.h"
24#include <cstring>
25
26using namespace Rappture;
27
28/**
29 * Construct an empty Path.
30 */
31Path::Path() :
32    _ifs(0),
33    _pathList(NULL)
34{
35    __pathInit();
36}
37
38
39/**
40 * Construct a Path loaded with initial data.
41 *
42 * @param bytes pointer to bytes being stored.
43 */
44Path::Path(const char* bytes) :
45    _ifs(0),
46    _pathList(NULL)
47{
48    __pathInit();
49    path(bytes);
50}
51
52/**
53 * Copy constructor
54 * @param Path object to copy
55 */
56Path::Path(const Path& b)
57{
58    __pathInit();
59
60    _ifs = b._ifs;
61
62    Rp_ChainCopy (_pathList, b._pathList, Rp_ChainCharCpyFxn);
63}
64
65/**
66 * Assignment operator
67 * @param Path object to copy
68 */
69/*
70Path&
71Path::operator=(const Path& b)
72{
73    b = bSimpleCharBuffer::operator=(b);
74    return *this;
75}
76
77
78Path
79Path::operator+(const Path& b) const
80{
81    Path newBuffer(*this);
82    newBuffer.operator+=(b);
83    return newBuffer;
84}
85
86
87Path&
88Path::operator+=(const Path& b)
89{
90    SimpleCharBuffer::operator+=(b);
91    return *this;
92}
93*/
94
95
96Path::~Path()
97{
98    __pathFree();
99}
100
101
102void
103Path::__pathInit()
104{
105    _ifs = '.';
106    _pathList = Rp_ChainCreate();
107    return;
108}
109
110void
111Path::__pathFree()
112{
113    if (_pathList) {
114        Rp_ChainLink *l = NULL;
115        componentStruct *compVal = NULL;
116        l = Rp_ChainFirstLink(_pathList);
117        while(l) {
118            compVal = (componentStruct *) Rp_ChainGetValue(l);
119            __deleteComponent(compVal);
120            compVal = NULL;;
121            l = Rp_ChainNextLink(l);
122        }
123        Rp_ChainDestroy(_pathList);
124        _pathList = NULL;
125    }
126    b.clear();
127    return;
128}
129
130Path::componentStruct *
131Path::__createComponent(
132    const char *p,
133    int start,
134    int end,
135    int idOpenParen,
136    int idCloseParen)
137{
138    componentStruct *c = new componentStruct();
139    int typeLen = -1;
140    int idLen = -1;
141    char *tmp = NULL;
142
143    c->type = NULL;
144    c->id = NULL;
145
146    if (idOpenParen < idCloseParen) {
147        // user specified an id
148        typeLen = idOpenParen - start;
149        idLen = idCloseParen - idOpenParen - 1;
150    } else {
151        // no id found
152        typeLen = end - start;
153    }
154
155    /*
156        typeLen and idLen are initialized to -1
157        if the user specified a value, the length
158        is set to the length of the specified value.
159        if the user specified a blank string, the
160        length is set to 0 and we still create a char array
161        for the type or id field.
162        we differentiate a blank entry from no entry so we
163        can accept paths like this:
164        input.group(tabs).().current
165        input.group(tabs).()
166        and correctly return the id,type,component, and parent
167        versions of the path. these paths are corner cases that
168        should never be used, but we handle them incase they are.
169        if an id is not specified (no value, not even blank),
170        the id pointer is set to NULL. in the above example paths
171        the type and id of the third component are both blank.
172        for the above example paths, the id field of the first
173        components, the index component, is NULL.
174        i don't think there is a way to get a NULL type right now.
175    */
176
177
178    if (typeLen >= 0) {
179        tmp = new char[typeLen+1];
180        strncpy(tmp,(p+start),typeLen);
181        tmp[typeLen] = '\0';
182        c->type = tmp;
183    }
184
185    if (idLen >= 0) {
186        tmp = new char[idLen+1];
187        strncpy(tmp,(p+idOpenParen+1),idLen);
188        tmp[idLen] = '\0';
189        c->id = tmp;
190    }
191
192    return c;
193}
194
195void
196Path::__deleteComponent(componentStruct *c)
197{
198    if (c) {
199        if (c->type) {
200            delete[] c->type;
201        }
202        if (c->id) {
203            delete[] c->id;
204        }
205        delete c;
206    }
207}
208
209Rp_Chain *
210Path::__parse(const char *p)
211{
212    int start = 0;
213    int end = 0;
214    int idOpenParen = -1;
215    int idCloseParen = -1;
216    componentStruct *c = NULL;
217
218    Rp_Chain *compList = Rp_ChainCreate();
219
220    if (p == NULL) {
221        return 0;
222    }
223
224    while (p[end] != '\0') {
225        if (p[end] == '(') {
226            idOpenParen = end;
227        } else if (p[end] == ')') {
228            idCloseParen = end;
229        } else if (p[end] == _ifs) {
230            c = __createComponent(p,start,end,idOpenParen,idCloseParen);
231            if (c != NULL) {
232                Rp_ChainAppend(compList,c);
233            }
234
235            start = end+1;
236            idOpenParen = -1;
237            idCloseParen = -1;
238        }
239        end++;
240    }
241
242    c = __createComponent(p,start,end,idOpenParen,idCloseParen);
243    if (c != NULL) {
244        Rp_ChainAppend(compList,c);
245    }
246
247    return compList;
248}
249
250void
251Path::__updateBuffer()
252{
253    Rp_ChainLink *l = NULL;
254    size_t len = 0;
255
256    b.clear();
257
258    l = Rp_ChainFirstLink(_pathList);
259    while (l != NULL) {
260
261        if (b.nmemb() != 0) {
262            b.append(&_ifs,1);
263        }
264
265        componentStruct *c = (componentStruct *) Rp_ChainGetValue(l);
266
267        if (c->type != NULL) {
268            len = strlen(c->type);
269            if (len > 0) {
270                b.append(c->type,len);
271            }
272        }
273
274        if (c->id != NULL) {
275            b.append("(",1);
276            len = strlen(c->id);
277            if (len > 0) {
278                b.append(c->id,len);
279            }
280            b.append(")",1);
281        }
282
283        l = Rp_ChainNextLink(l);
284    }
285
286    b.append("\0",1);
287}
288
289const char *
290Path::ifs (const char *el)
291{
292    // ifs cannot be NULL, \0, (, or )
293
294    if ((el != NULL) &&
295        (*el != '\0') &&
296        (*el != '(') &&
297        (*el != ')')) {
298        _ifs = *el;
299        __updateBuffer();
300    }
301
302    return (const char *)&_ifs;
303}
304
305Path&
306Path::add (const char *el)
307{
308    Rp_Chain *addList = NULL;
309
310    addList = __parse(el);
311    Rp_ChainConcat(_pathList,addList);
312
313    __updateBuffer();
314
315    return *this;
316}
317
318Path&
319Path::del ()
320{
321    Rp_ChainLink *l = NULL;
322
323    l = Rp_ChainLastLink(_pathList);
324
325    if (l != NULL) {
326        componentStruct *c = (componentStruct *) Rp_ChainGetValue(l);
327        __deleteComponent(c);
328        c = NULL;
329        Rp_ChainDeleteLink(_pathList,l);
330    }
331
332    __updateBuffer();
333
334    return *this;
335}
336
337const char *
338Path::component(void)
339{
340    Rp_ChainLink *l = NULL;
341    size_t len = 0;
342
343    tmpBuf.clear();
344
345    if (_pathList == NULL) {
346        tmpBuf.append("\0",1);
347        return tmpBuf.bytes();
348    }
349
350    l = Rp_ChainLastLink(_pathList);
351
352    if (l == NULL) {
353        tmpBuf.append("\0",1);
354        return tmpBuf.bytes();
355    }
356
357    componentStruct *c = (componentStruct *) Rp_ChainGetValue(l);
358
359    if (c == NULL) {
360        tmpBuf.append("\0",1);
361        return tmpBuf.bytes();
362    }
363
364    if (c->type != NULL) {
365        len = strlen(c->type);
366        if (len > 0) {
367            tmpBuf.append(c->type,len);
368        }
369    }
370
371    if (c->id != NULL) {
372        tmpBuf.append("(",1);
373        len = strlen(c->id);
374        if (len > 0) {
375            tmpBuf.append(c->id,len);
376        }
377        tmpBuf.append(")",1);
378    }
379
380    tmpBuf.append("\0",1);
381
382    return tmpBuf.bytes();
383}
384
385// if you give more than a component,
386// we only take the last component
387// the whole component (type and id)
388// are used to replace the current component.
389
390void
391Path::component(const char *p)
392{
393    if (p == NULL) {
394        return;
395    }
396
397    Rp_Chain *addList = NULL;
398    Rp_ChainLink *l = NULL;
399
400    addList = __parse(p);
401
402    if (addList == NULL) {
403        // nothing to add
404        return;
405    }
406
407    // get the last component of addList
408    l = Rp_ChainLastLink(addList);
409
410    if (l == NULL) {
411        // nothing to add
412        Rp_ChainDestroy(addList);
413        return;
414    }
415
416    componentStruct *aLcomp = (componentStruct *) Rp_ChainGetValue(l);
417    Rp_ChainDeleteLink(_pathList,l);
418
419    // delete addList
420    l = Rp_ChainFirstLink(addList);
421    while (l != NULL) {
422        componentStruct *c = (componentStruct *) Rp_ChainGetValue(l);
423        delete c;
424        l = Rp_ChainNextLink(l);
425    }
426    Rp_ChainDestroy(addList);
427
428    // remove the last component from the current path
429    l = Rp_ChainLastLink(_pathList);
430
431    if (l != NULL) {
432        componentStruct *last = (componentStruct *) Rp_ChainGetValue(l);
433        delete last;
434        Rp_ChainDeleteLink(_pathList,l);
435    }
436
437    // append the new component onto the current path
438    Rp_ChainAppend(_pathList,aLcomp);
439
440    __updateBuffer();
441
442    return;
443}
444
445const char *
446Path::id()
447{
448    Rp_ChainLink *l = NULL;
449
450    tmpBuf.clear();
451
452    if (_pathList == NULL) {
453        tmpBuf.append("\0",1);
454        return tmpBuf.bytes();
455    }
456
457    l = Rp_ChainLastLink(_pathList);
458
459    if (l == NULL) {
460        tmpBuf.append("\0",1);
461        return tmpBuf.bytes();
462    }
463
464    componentStruct *c = (componentStruct *) Rp_ChainGetValue(l);
465
466    if (c == NULL) {
467        tmpBuf.append("\0",1);
468        return tmpBuf.bytes();
469    }
470
471    if (c->id) {
472        tmpBuf.append(c->id);
473    }
474
475    tmpBuf.append("\0",1);
476
477    return tmpBuf.bytes();
478}
479
480void
481Path::id(const char *p)
482{
483    if (p == NULL) {
484        return;
485    }
486
487    Rp_ChainLink *l = NULL;
488    char *tmp = NULL;
489    size_t len = strlen(p);
490    componentStruct *last = NULL;
491
492    // update the last component from the current path
493    l = Rp_ChainLastLink(_pathList);
494
495    if (l != NULL) {
496        last = (componentStruct *) Rp_ChainGetValue(l);
497        delete[] last->id;
498    } else {
499        // append the new component onto the current path
500        last = new componentStruct;
501        Rp_ChainAppend(_pathList,last);
502        tmp = new char[1];
503        *tmp = '\0';
504        last->type = tmp;
505    }
506
507    // adjust the id field
508    tmp = new char[len+1];
509    strncpy(tmp,p,len+1);
510    last->id = tmp;
511
512    __updateBuffer();
513
514    return;
515}
516
517const char *
518Path::type()
519{
520    Rp_ChainLink *l = NULL;
521
522    tmpBuf.clear();
523
524    if (_pathList == NULL) {
525        tmpBuf.append("\0",1);
526        return tmpBuf.bytes();
527    }
528
529    l = Rp_ChainLastLink(_pathList);
530
531    if (l == NULL) {
532        tmpBuf.append("\0",1);
533        return tmpBuf.bytes();
534    }
535
536    componentStruct *c = (componentStruct *) Rp_ChainGetValue(l);
537
538    if (c == NULL) {
539        tmpBuf.append("\0",1);
540        return tmpBuf.bytes();
541    }
542
543    if (c->type) {
544        tmpBuf.append(c->type);
545    }
546
547    tmpBuf.append("\0",1);
548
549    return tmpBuf.bytes();
550}
551
552void
553Path::type(const char *p)
554{
555    if (p == NULL) {
556        return;
557    }
558
559    Rp_ChainLink *l = NULL;
560    char *tmp = NULL;
561    size_t len = strlen(p);
562    componentStruct *last = NULL;
563
564    // update the last component from the current path
565    l = Rp_ChainLastLink(_pathList);
566
567    if (l != NULL) {
568        last = (componentStruct *) Rp_ChainGetValue(l);
569        delete[] last->type;
570    } else {
571        // append the new component onto the current path
572        last = new componentStruct;
573        Rp_ChainAppend(_pathList,last);
574        last->id = NULL;
575    }
576
577    // adjust the type field
578    tmp = new char[len+1];
579    strncpy(tmp,p,len+1);
580    last->type = tmp;
581
582    __updateBuffer();
583
584    return;
585}
586
587const char *
588Path::parent()
589{
590    Rp_ChainLink *l = NULL;
591    Rp_ChainLink *last = NULL;
592
593    tmpBuf.clear();
594
595    last = Rp_ChainLastLink(_pathList);
596    l = Rp_ChainFirstLink(_pathList);
597    while (l != last) {
598
599        if (tmpBuf.nmemb() != 0) {
600            tmpBuf.append(&_ifs,1);
601        }
602
603        componentStruct *c = (componentStruct *) Rp_ChainGetValue(l);
604
605        if (c->type) {
606            tmpBuf.append(c->type);
607        }
608
609        if (c->id) {
610            tmpBuf.append("(",1);
611            tmpBuf.append(c->id);
612            tmpBuf.append(")",1);
613        }
614
615        // what happens if type and id are both null?
616
617        l = Rp_ChainNextLink(l);
618    }
619
620    tmpBuf.append("\0",1);
621
622    return tmpBuf.bytes();
623}
624
625void
626Path::parent(const char *p)
627{
628// FIXME:
629/*
630    if (p == NULL) {
631        return;
632    }
633
634    Rp_Chain *addList = NULL;
635    Rp_ChainLink *l = NULL;
636
637    addList = __parse(p);
638
639    if (addList == NULL) {
640        // no parent path?
641        return;
642    }
643
644    // get the last component of pathList
645    l = Rp_ChainLastLink(_pathList);
646
647    if (l == NULL) {
648        // nothing to add
649        Rp_ChainDestroy(addList);
650        return;
651    }
652
653    componentStruct *aLcomp = (componentStruct *) Rp_ChainGetValue(l);
654    Rp_ChainDeleteLink(_pathList,l);
655
656    // delete addList
657    l = Rp_ChainFirstLink(addList);
658    while (l != NULL) {
659        componentStruct *c = (componentStruct *) Rp_ChainGetValue(l);
660        delete c;
661        l = Rp_ChainNextLink(l);
662    }
663    Rp_ChainDestroy(addList);
664
665    // update the last component from the current path
666    l = Rp_ChainLastLink(_pathList);
667
668    if (l != NULL) {
669        componentStruct *last = (componentStruct *) Rp_ChainGetValue(l);
670        Rp_ChainDeleteLink(_pathList,l);
671        delete last->type;
672        last->type = aLcomp->type;
673        delete aLcomp->type;
674        delete aLcomp;
675    } else {
676        // append the new component onto the current path
677        delete aLcomp->id;
678        Rp_ChainAppend(_pathList,aLcomp);
679    }
680
681    __updateBuffer();
682
683*/
684    return;
685}
686
687const char *
688Path::path(void)
689{
690    return b.bytes();
691}
692
693void
694Path::path(const char *p)
695{
696    if (p != NULL) {
697        _pathList = __parse(p);
698        __updateBuffer();
699    }
700    return;
701}
702
703#ifdef __cplusplus
704    }
705#endif // ifdef __cplusplus
706
Note: See TracBrowser for help on using the repository browser.