2 * Worldvisions Weaver Software:
3 * Copyright (C) 2002 Net Integration Technologies, Inc.
5 * UniConfKeys are paths in the UniConf hierarchy.
11 #include "wvlinklist.h"
15 // The Python headers try to #define ANY as void. If we're building Python
16 // wrappers, get rid of that.
21 * Represents a UniConf key which is a path in a hierarchy structured much
22 * like the traditional Unix filesystem.
24 * - Segments in the path are delimited by slashes.
25 * - The empty string refers to the current level of the tree (eg. root).
26 * - Keys are case insensitive yet preserve case information.
27 * - Paired slashes are converted to single slashes.
28 * - Trailing slashes are discarded.
30 * The following paths are equivalent when canonicalized:
32 * - foo/key (the canonical representation)
33 * - Foo/Key (also canonical but preserves case)
34 * - /foo/key (converted to foo/key)
35 * - foo//key (converted to foo/key)
36 * - foo/key/ (converted to foo/key)
38 * Keys that may contain slashes or nulls should be escaped in some fashion
39 * prior to constructing a UniConfKey object. Simply prefixing slashes with
40 * backslashes is inadequate because UniConfKey does not give any special
41 * meaning to backslash.
45 class Segment
: public WvString
49 WvString(WvString::empty
)
52 Segment(WvStringParm str
) :
53 WvString((!str
)? WvString::empty
: str
)
56 Segment(const Segment
&segment
) :
63 return *this == "*" || *this == "...";
72 SegmentVector(int size
) :
75 vec(new Segment
[_size
])
83 void resize(int size
, int shift
= 0)
89 for (int i
=_used
-1; i
>=0; --i
)
90 vec
[i
+shift
] = vec
[i
];
95 Segment
*old_vec
= vec
;
96 vec
= new Segment
[size
];
99 int limit
= size
-shift
;
104 for (int i
=0; i
<limit
; ++i
)
105 vec
[i
+shift
] = old_vec
[i
];
124 void append(const Segment
&segment
)
126 vec
[_used
++] = segment
;
128 void append(WvStringParm string
)
130 append(Segment(string
));
132 void replace(int index
, const Segment
&segment
)
134 vec
[index
] = segment
;
138 void replace(int index
, WvStringParm string
)
140 replace(index
, Segment(string
));
142 const Segment
&operator [](int index
) const
150 SegmentVector segments
;
153 Store(int size
, int _ref_count
, WvStringParm key
= WvString::null
);
159 static Store EMPTY_store
; /*!< represents "" (root) */
160 static Store ANY_store
; /*!< represents "*" */
161 static Store RECURSIVE_ANY_store
; /*!< represents "..." */
163 UniConfKey(Store
*_store
, int _left
, int _right
) :
173 UniConfKey
&collapse();
176 static UniConfKey EMPTY
; /*!< represents "" (root) */
177 static UniConfKey ANY
; /*!< represents "*" */
178 static UniConfKey RECURSIVE_ANY
; /*!< represents "..." */
180 /** Constructs an empty UniConfKey (the 'root'). */
190 * Constructs a UniConfKey from a string.
192 * See the rules above for information about how the key string
195 * "key" is the key as a string
197 UniConfKey(WvStringParm key
) :
198 store(new Store(4, 1, key
)),
200 right(store
->segments
.used())
205 * Constructs a UniConfKey from a string.
207 * See the rules above for information about how the key string
208 * is canonicalized. This constructor only exists to help out the
209 * C++ compiler with its automatic type conversions.
211 * "key" is the key as a string
213 UniConfKey(const char *key
) :
214 store(new Store(4, 1, WvFastString(key
))),
216 right(store
->segments
.used())
220 /** Constructs a UniConfKey from an int. */
221 UniConfKey(int key
) :
222 store(new Store(1, 1, WvFastString(key
))),
224 right(store
->segments
.used())
229 * Copies a UniConfKey.
230 * "other" is the key to copy
232 UniConfKey(const UniConfKey
&other
) :
241 * Constructs a UniConfKey by concatenating two keys.
242 * "path" is the initial part of the new path
243 * "key" is the tail of the new path
245 UniConfKey(const UniConfKey
&path
, const UniConfKey
&key
);
249 if (--store
->ref_count
== 0)
254 * Appends a path to this path.
255 * "other" is the path
257 void append(const UniConfKey
&other
);
260 * Prepends a path to this path.
261 * "other" is the path
263 void prepend(const UniConfKey
&other
);
266 * Returns true if this path has zero segments (also known as root).
267 * Returns: numsegments() == 0
271 return right
== left
;
274 /** Returns true if the key contains a wildcard. */
277 /** Returns true if the key has a trailing slash. */
278 bool hastrailingslash() const
280 return right
> left
&& !store
->segments
[right
-1];
284 * Returns the number of segments in this path.
286 * The number of segments is equal to the number of slashes
287 * in the path unless the path is "/" (the root), which has
290 * Returns: the number of segments
292 int numsegments() const
298 * Returns the specified segment of the path.
299 * "i" is the segment index
300 * Returns: the segment
302 UniConfKey
segment(int n
) const
304 return range(n
, n
+ 1);
308 * Returns the path formed by the first n segments of this path and
309 * removes them from the key.
312 UniConfKey
pop(int n
= 1);
315 * Returns the path formed by the n first segments of this path.
316 * "n" is the number of segments
319 UniConfKey
first(int n
= 1) const
325 * Returns the path formed by the n last segments of this path.
326 * "n" is the number of segments
329 UniConfKey
last(int n
= 1) const
331 return range(numsegments() - n
, INT_MAX
);
335 * Returns the path formed by removing the first n segments of
337 * "n" is the number of segments
340 UniConfKey
removefirst(int n
= 1) const
342 return range(n
, INT_MAX
);
346 * Returns the path formed by removing the last n segments of
348 * "n" is the number of segments
351 UniConfKey
removelast(int n
= 1) const
353 return range(0, numsegments() - n
);
357 * Returns a range of segments.
358 * "i" is the first segment index, beginning if <= 0
359 * "j" is the last segment index, end if >= numsegments()
360 * Returns: the path, empty if j <= i
362 UniConfKey
range(int i
, int j
) const;
365 * Returns the canonical string representation of the path.
367 * If the UniConfKey was constructed in part or whole from
368 * strings, then the string returned here will have the same
369 * case information as those strings but the arrangement of
370 * slashes may differ. That is, the identity
371 * UniConfKey(string).printable() == string does not hold.
373 * Returns: the path as a string
375 WvString
printable() const;
376 operator WvString() const
377 { return printable(); }
380 * Returns a (const char *) of printable() directly.
382 const char *cstr() const
383 { return printable(); }
386 * Assigns this path to equal another.
387 * "other" is the other path
389 UniConfKey
&operator= (const UniConfKey
&other
)
391 if (--store
->ref_count
== 0)
401 * Compares two paths lexicographically.
402 * Uses case-insensitive matching on the path string to produce
403 * a total ordering of all paths.
404 * "other" is the other path
405 * Returns: 0 if *this == other, < 0 if *this < other, else > 0
407 int compareto(const UniConfKey
&other
) const;
410 * Determines if the key matches a pattern.
411 * Patterns are simply keys that may have path segments consiting
412 * entirely of "*". Optional path segments are indicated by
413 * the segment "..." which matches zero or more segments.
415 * Using wildcards to represent part of a segment is not supported yet.
416 * "pattern" is the pattern
417 * Returns: true if the key matches, false otherwise
419 bool matches(const UniConfKey
&pattern
) const;
423 * Returns true if 'key' is a the same, or a subkey, of this UniConfKey.
425 bool suborsame(const UniConfKey
&key
) const;
426 bool suborsame(const UniConfKey
&key
, UniConfKey
&subkey
) const;
429 * If this UniConfKey is a subkey of 'key', then return the subkey
430 * portion. Behaviour is undefined when this is not the same. Use
431 * suborsame() to check.
433 UniConfKey
subkey(const UniConfKey
&key
) const;
436 * Determines if two paths are equal.
437 * "other" is the other path
438 * Returns: true in that case
440 bool operator== (const UniConfKey
&other
) const
441 { return compareto(other
) == 0; }
444 * Determines if two paths are unequal.
445 * "other" is the other path
446 * Returns: true in that case
448 bool operator!= (const UniConfKey
&other
) const
449 { return compareto(other
) != 0; }
452 * Determines if this path precedes the other lexicographically.
453 * "other" is the other path
454 * Returns: true in that case
456 bool operator< (const UniConfKey
&other
) const
457 { return compareto(other
) < 0; }
461 friend unsigned WvHash(const UniConfKey
&k
);
465 DeclareWvList(UniConfKey
);
467 /** An iterator over the segments of a key. */
468 class UniConfKey::Iter
470 const UniConfKey
&key
;
475 Iter(const UniConfKey
&_key
) : key(_key
)
479 { seg
= -1; max
= key
.numsegments(); }
482 { return seg
>= 0 && seg
< max
; }
485 { seg
++; curseg
= key
.segment(seg
); return cur(); }
487 const UniConfKey
*ptr() const
490 WvIterStuff(const UniConfKey
);
493 #endif // __UNICONFKEY_H