2 * Worldvisions Weaver Software:
3 * Copyright (C) 2002 Net Integration Technologies, Inc.
5 * UniConfKeys are paths in the UniConf hierarchy.
11 #include "wvlinklist.h"
14 // The Python headers try to #define ANY as void. If we're building Python
15 // wrappers, get rid of that.
20 * Represents a UniConf key which is a path in a hierarchy structured much
21 * like the traditional Unix filesystem.
23 * - Segments in the path are delimited by slashes.
24 * - The empty string refers to the current level of the tree (eg. root).
25 * - Keys are case insensitive yet preserve case information.
26 * - Paired slashes are converted to single slashes.
27 * - Trailing slashes are discarded.
29 * The following paths are equivalent when canonicalized:
31 * - foo/key (the canonical representation)
32 * - Foo/Key (also canonical but preserves case)
33 * - /foo/key (converted to foo/key)
34 * - foo//key (converted to foo/key)
35 * - foo/key/ (converted to foo/key)
37 * Keys that may contain slashes or nulls should be escaped in some fashion
38 * prior to constructing a UniConfKey object. Simply prefixing slashes with
39 * backslashes is inadequate because UniConfKey does not give any special
40 * meaning to backslash.
44 class Segment
: public WvString
48 WvString(WvString::empty
)
51 Segment(WvStringParm str
) :
52 WvString((!str
)? WvString::empty
: str
)
55 Segment(const Segment
&segment
) :
62 return *this == "*" || *this == "...";
71 SegmentVector(int size
) :
74 vec(new Segment
[_size
])
82 void resize(int size
, int shift
= 0)
88 for (int i
=_used
-1; i
>=0; --i
)
89 vec
[i
+shift
] = vec
[i
];
94 Segment
*old_vec
= vec
;
95 vec
= new Segment
[size
];
98 int limit
= size
-shift
;
103 for (int i
=0; i
<limit
; ++i
)
104 vec
[i
+shift
] = old_vec
[i
];
123 void append(const Segment
&segment
)
125 vec
[_used
++] = segment
;
127 void append(WvStringParm string
)
129 append(Segment(string
));
131 void replace(int index
, const Segment
&segment
)
133 vec
[index
] = segment
;
137 void replace(int index
, WvStringParm string
)
139 replace(index
, Segment(string
));
141 const Segment
&operator [](int index
) const
149 SegmentVector segments
;
152 Store(int size
, int _ref_count
, WvStringParm key
= WvString::null
);
158 static Store EMPTY_store
; /*!< represents "" (root) */
159 static Store ANY_store
; /*!< represents "*" */
160 static Store RECURSIVE_ANY_store
; /*!< represents "..." */
162 UniConfKey(Store
*_store
, int _left
, int _right
) :
172 UniConfKey
&collapse();
175 static UniConfKey EMPTY
; /*!< represents "" (root) */
176 static UniConfKey ANY
; /*!< represents "*" */
177 static UniConfKey RECURSIVE_ANY
; /*!< represents "..." */
179 /** Constructs an empty UniConfKey (the 'root'). */
189 * Constructs a UniConfKey from a string.
191 * See the rules above for information about how the key string
194 * "key" is the key as a string
196 UniConfKey(WvStringParm key
) :
197 store(new Store(4, 1, key
)),
199 right(store
->segments
.used())
204 * Constructs a UniConfKey from a string.
206 * See the rules above for information about how the key string
207 * is canonicalized. This constructor only exists to help out the
208 * C++ compiler with its automatic type conversions.
210 * "key" is the key as a string
212 UniConfKey(const char *key
) :
213 store(new Store(4, 1, WvFastString(key
))),
215 right(store
->segments
.used())
219 /** Constructs a UniConfKey from an int. */
220 UniConfKey(int key
) :
221 store(new Store(1, 1, WvFastString(key
))),
223 right(store
->segments
.used())
228 * Copies a UniConfKey.
229 * "other" is the key to copy
231 UniConfKey(const UniConfKey
&other
) :
240 * Constructs a UniConfKey by concatenating two keys.
241 * "path" is the initial part of the new path
242 * "key" is the tail of the new path
244 UniConfKey(const UniConfKey
&path
, const UniConfKey
&key
);
248 if (--store
->ref_count
== 0)
253 * Appends a path to this path.
254 * "other" is the path
256 void append(const UniConfKey
&other
);
259 * Prepends a path to this path.
260 * "other" is the path
262 void prepend(const UniConfKey
&other
);
265 * Returns true if this path has zero segments (also known as root).
266 * Returns: numsegments() == 0
270 return right
== left
;
273 /** Returns true if the key contains a wildcard. */
276 /** Returns true if the key has a trailing slash. */
277 bool hastrailingslash() const
279 return right
> left
&& !store
->segments
[right
-1];
283 * Returns the number of segments in this path.
285 * The number of segments is equal to the number of slashes
286 * in the path unless the path is "/" (the root), which has
289 * Returns: the number of segments
291 int numsegments() const
297 * Returns the specified segment of the path.
298 * "i" is the segment index
299 * Returns: the segment
301 UniConfKey
segment(int n
) const
303 return range(n
, n
+ 1);
307 * Returns the path formed by the first n segments of this path and
308 * removes them from the key.
311 UniConfKey
pop(int n
= 1);
314 * Returns the path formed by the n first segments of this path.
315 * "n" is the number of segments
318 UniConfKey
first(int n
= 1) const
324 * Returns the path formed by the n last segments of this path.
325 * "n" is the number of segments
328 UniConfKey
last(int n
= 1) const
330 return range(numsegments() - n
, INT_MAX
);
334 * Returns the path formed by removing the first n segments of
336 * "n" is the number of segments
339 UniConfKey
removefirst(int n
= 1) const
341 return range(n
, INT_MAX
);
345 * Returns the path formed by removing the last n segments of
347 * "n" is the number of segments
350 UniConfKey
removelast(int n
= 1) const
352 return range(0, numsegments() - n
);
356 * Returns a range of segments.
357 * "i" is the first segment index, beginning if <= 0
358 * "j" is the last segment index, end if >= numsegments()
359 * Returns: the path, empty if j <= i
361 UniConfKey
range(int i
, int j
) const;
364 * Returns the canonical string representation of the path.
366 * If the UniConfKey was constructed in part or whole from
367 * strings, then the string returned here will have the same
368 * case information as those strings but the arrangement of
369 * slashes may differ. That is, the identity
370 * UniConfKey(string).printable() == string does not hold.
372 * Returns: the path as a string
374 WvString
printable() const;
375 operator WvString() const
376 { return printable(); }
379 * Returns a (const char *) of printable() directly.
381 const char *cstr() const
382 { return printable(); }
385 * Assigns this path to equal another.
386 * "other" is the other path
388 UniConfKey
&operator= (const UniConfKey
&other
)
390 if (--store
->ref_count
== 0)
400 * Compares two paths lexicographically.
401 * Uses case-insensitive matching on the path string to produce
402 * a total ordering of all paths.
403 * "other" is the other path
404 * Returns: 0 if *this == other, < 0 if *this < other, else > 0
406 int compareto(const UniConfKey
&other
) const;
409 * Determines if the key matches a pattern.
410 * Patterns are simply keys that may have path segments consiting
411 * entirely of "*". Optional path segments are indicated by
412 * the segment "..." which matches zero or more segments.
414 * Using wildcards to represent part of a segment is not supported yet.
415 * "pattern" is the pattern
416 * Returns: true if the key matches, false otherwise
418 bool matches(const UniConfKey
&pattern
) const;
422 * Returns true if 'key' is a the same, or a subkey, of this UniConfKey.
424 bool suborsame(const UniConfKey
&key
) const;
425 bool suborsame(const UniConfKey
&key
, UniConfKey
&subkey
) const;
428 * If this UniConfKey is a subkey of 'key', then return the subkey
429 * portion. Behaviour is undefined when this is not the same. Use
430 * suborsame() to check.
432 UniConfKey
subkey(const UniConfKey
&key
) const;
435 * Determines if two paths are equal.
436 * "other" is the other path
437 * Returns: true in that case
439 bool operator== (const UniConfKey
&other
) const
440 { return compareto(other
) == 0; }
443 * Determines if two paths are unequal.
444 * "other" is the other path
445 * Returns: true in that case
447 bool operator!= (const UniConfKey
&other
) const
448 { return compareto(other
) != 0; }
451 * Determines if this path precedes the other lexicographically.
452 * "other" is the other path
453 * Returns: true in that case
455 bool operator< (const UniConfKey
&other
) const
456 { return compareto(other
) < 0; }
460 friend unsigned WvHash(const UniConfKey
&k
);
464 DeclareWvList(UniConfKey
);
466 /** An iterator over the segments of a key. */
467 class UniConfKey::Iter
469 const UniConfKey
&key
;
474 Iter(const UniConfKey
&_key
) : key(_key
)
478 { seg
= -1; max
= key
.numsegments(); }
481 { return seg
>= 0 && seg
< max
; }
484 { seg
++; curseg
= key
.segment(seg
); return cur(); }
486 const UniConfKey
*ptr() const
489 WvIterStuff(const UniConfKey
);
492 #endif // __UNICONFKEY_H