1 /***************************************************************************
2 keyset.c - Methods for KeySet manipulation
4 begin : Sun Oct 02 2005
5 copyright : (C) 2005 by Avi Alkalay
7 ***************************************************************************/
9 /***************************************************************************
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the BSD License (revised). *
14 ***************************************************************************/
18 * @defgroup keyset KeySet :: Class Methods
19 * @brief Methods to manipulate KeySets.
21 * A KeySet is a unsorted set of keys.
23 * Terminate with ksNew(0) or ksNew(20, ..., KS_END)
24 * This is because there is a list of Key* required and
25 * KS_END has the length of (Key*).
27 * It can be implemented in various ways like a linked list or with a
28 * dynamically allocated array.
30 * With ksNew() you can create a new KeySet.
32 * You can add keys with ksAppendKey() in the keyset. ksGetSize() tells you
33 * the current size of the keyset.
35 * With ksRewind() and ksNext() you can navigate through the keyset. Don't
36 * expect any particular order, but it is assured that you will get every
39 * KeySets have an @link ksCurrent() internal cursor @endlink. This is used
40 * for ksLookup() and kdbSet().
42 * KeySet has a fundamental meaning inside elektra. It makes it possible
43 * to get and store many keys at once inside the database. In addition to
44 * that the class can be used as high level datastructure in applications.
45 * With ksLookupByName() it is possible to fetch easily specific keys
46 * out of the list of keys.
48 * You can easily create and iterate keys:
52 // create a new keyset with 3 keys
53 // with a hint that about 20 keys will be inside
54 KeySet *myConfig = ksNew(20,
55 keyNew ("user/name1", 0),
56 keyNew ("user/name2", 0),
57 keyNew ("user/name3", 0),
59 // append a key in the keyset
60 ksAppendKey(myConfig, keyNew("user/name4", 0));
64 while ((current=ksNext(myConfig))!=0) {
65 printf("Key name is %s.\n", keyName (current));
67 ksDel (myConfig); // delete keyset and all keys appended
77 #if DEBUG && HAVE_STDIO_H
93 #include "kdbbackend.h"
98 * Allocate, initialize and return a new KeySet object.
100 * Objects created with ksNew() must be destroyed with ksDel().
102 * You can use a various long list of parameters to preload the keyset
103 * with a list of keys. Either your first and only parameter is 0 or
104 * your last parameter must be KEY_END.
108 KeySet *keys = ksNew(0);
112 * goes ok, the alloc size will be 16, defined in kdbprivate.h.
113 * The alloc size will be doubled whenever size reaches alloc size,
114 * so it also performs out large keysets.
116 * But if you have any clue how large your keyset may be you should
117 * read the next statements.
119 * If you want a keyset with length 15 (because you know of your
120 * application that you normally need about 12 up to 14 keys), use:
122 KeySet * keys = ksNew (15, KS_END);
127 * If you start having 3 keys, and your application needs approximately
128 * 200-500 keys, you can use:
130 KeySet * config = ksNew (500,
131 keyNew ("user/sw/app/fixedConfiguration/key1", KEY_SWITCH_VALUE, "value1", 0),
132 keyNew ("user/sw/app/fixedConfiguration/key2", KEY_SWITCH_VALUE, "value2", 0),
133 keyNew ("user/sw/app/fixedConfiguration/key3", KEY_SWITCH_VALUE, "value3", 0),
134 KS_END); // don't forget the KS_END at the end!
138 * Alloc size is 500, the size of the keyset will be 3 after ksNew.
139 * This means the keyset will reallocate when appending more than
142 * The main benefit of taking a list of variant length parameters is to be able
143 * to have one C-Statement for any possible KeySet.
145 * Due to ABI compatibility, the @p KeySet structure is only declared in kdb.h,
146 * and not defined. So you can only declare @p pointers to @p KeySets in your
148 * See http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html#AEN135
150 * @see ksDel() to free the keyset afterwards
151 * @see ksDup() to duplicate an existing keyset
152 * @param alloc gives a hint for the size how many Keys may be stored initially
153 * @return a ready to use KeySet object
154 * @return 0 on memory error
156 KeySet *ksNew(size_t alloc, ...) {
160 if (alloc) va_start(va, alloc);
161 ks = ksVNew (alloc, va);
162 if (alloc) va_end (va);
167 KeySet *ksVNew (size_t alloc, va_list va)
172 keyset= (KeySet *)kdbiMalloc(sizeof(KeySet));
175 /*errno = KDB_ERR_NOMEM;*/
180 if (alloc < KEYSET_SIZE) keyset->alloc=KEYSET_SIZE;
181 else keyset->alloc=alloc;
183 keyset->array = kdbiMalloc (sizeof(struct _Key *) * keyset->alloc);
187 /*errno = KDB_ERR_NOMEM;*/
190 keyset->array[0] = 0;
194 key = (struct _Key *) va_arg (va, struct _Key *);
196 ksAppendKey(keyset, key);
197 key = (struct _Key *) va_arg (va, struct _Key *);
206 * Return a duplicate of a keyset.
208 * Objects created with ksDup() must be destroyed with ksDel().
210 * Memory will be allocated as needed for dynamic properties,
211 * so you need to ksDel() the returned pointer.
213 * A flat copy is made, so the keys will not be duplicated,
214 * but there reference counter is updated, so both keysets
217 * @param source has to be an initializised source KeySet
218 * @return a flat copy of source on success
219 * @return 0 on NULL pointer
220 * @see ksNew(), ksDel()
221 * @see keyDup() for key duplication
223 KeySet *ksDup (const KeySet * source)
227 if (!source) return 0;
229 keyset = ksNew(source->alloc,KS_END);
230 ksAppend (keyset, source);
239 * Most often you may want a duplicate of a keyset, see
240 * ksDup() or append keys, see ksAppend().
241 * But in some situations you need to copy a
242 * keyset to a existing keyset, for that this function
245 * You can also use it to clear a keyset when you pass
246 * a NULL pointer as @p source.
248 * Note that all keys in @p dest will be deleted. Afterwards
249 * the content of the source will be added to the destination
250 * and the ksCurrent() is set properly in @p dest.
252 * A flat copy is made, so the keys will not be duplicated,
253 * but there reference counter is updated, so both keysets
254 * need to be ksDel().
259 KeySet *c = ksNew (20, ..., KS_END);
261 ksCopy (ks, c); // pass the keyset to the caller
264 } // caller needs to ksDel (ks)
267 * @param source has to be an initialized source KeySet or NULL
268 * @param dest has to be an initialized KeySet where to write the keys
269 * @return 1 on success
270 * @return 0 if dest was cleared successfully (source is NULL)
271 * @return -1 on NULL pointer
272 * @see ksNew(), ksDel(), ksDup()
273 * @see keyCopy() for copying keys
275 int ksCopy (KeySet *dest, const KeySet *source)
277 if (!dest) return -1;
279 if (!source) return 0;
281 ksAppend (dest, source);
282 ksSetCursor (dest, ksGetCursor (source));
290 * A destructor for KeySet objects.
292 * Cleans all internal dynamic attributes, decrement all reference pointers
293 * to all keys and then keyDel() all contained Keys,
294 * and free()s the release the KeySet object memory (that was previously
295 * allocated by ksNew()).
297 * @param ks the keyset object to work with
298 * @return 0 when the keyset was freed
299 * @return -1 on null pointer
302 int ksDel(KeySet *ks)
315 * KeySet object cleaner.
317 * Will keyDel() all contained keys, reset internal pointers and counters.
319 * After this call you can use the empty keyset again.
321 * @param ks the keyset object to work with
322 * @see ksAppendKey() for details on how keys are inserted in KeySets
323 * @return 0 on sucess
324 * @return -1 on failure
326 int ksClear(KeySet *ks)
331 { /* go back to standard size KEYSET_SIZE */
332 if (kdbiRealloc ((void**) &ks->array, sizeof(struct _Key *) * KEYSET_SIZE) == -1)
334 /*errno = KDB_ERR_NOMEM;*/
335 kdbiFree (ks->array);
341 if ((ks->array = kdbiMalloc (sizeof(struct _Key *) * KEYSET_SIZE)) == 0)
343 /*errno = KDB_ERR_NOMEM;*/
348 ks->alloc = KEYSET_SIZE;
357 * Returns if keyset needs sort.
359 * It is very inefficient to resort the keyset every time when a
360 * key or a keyset is appended, so only a flag will be set to
361 * show that the keyset is not sorted any more.
363 * Before operations where the code depends on a sorted keyset,
364 * namely in kdbGet(), kdbSet() and ksLookup(), this simple code
368 if (ksNeedSort(ks)) ksSort(ks);
371 * @warning ksNeedSort() does not track every change which actually
372 * affects sorting: changing of names with keySetName() and
373 * marking keys remove with keyRemove() won't be recognized.
374 * But any ks* Method will leave the KeySet sorted or
377 * So if your code might rename keys or flag them to remove,
378 * make sure that you use
384 * somewhere afterwards before using ksLookup(). Otherwise the
385 * renamed key won't be found.
387 * kdbSet() will have no problems with that issue, because it
388 * duplicates its keysets using ksDup().
390 * @param ks the keyset object to work with
391 * @see ksAppendKey(), ksAppend() and ksSort()
392 * @return 1 if sort is needed
393 * 0 if the keyset is sorted
395 int ksNeedSort (const KeySet *ks)
397 return (ks->flags & KS_FLAG_DIRTY) == KS_FLAG_DIRTY;
401 /* Used as a callback by the qsort() function */
402 static int keyCompareWithRemove(const void *p1, const void *p2) {
403 Key *key1=*(Key **)p1;
404 Key *key2=*(Key **)p2;
405 const char *name1 = keyName(key1);
406 const char *name2 = keyName(key2);
407 int ret = strcmp(name1, name2);
409 /* one key remove, sort in order of KEY_FLAG_REMOVE */
410 if (keyNeedRemove(key1) && !keyNeedRemove(key2)) return -1;
411 else if (!keyNeedRemove(key1) && keyNeedRemove(key2)) return 1;
414 if (keyNeedRemove(key1) && keyNeedRemove(key2))
415 { /* both keys remove, sort reverse */
416 if (ret < 0) return 1;
417 else if (ret > 0) return -1;
419 } else { /* sort by owner */
422 const char *owner1 = keyOwner(key1);
423 const char *owner2 = keyOwner(key2);
424 return strcmp(owner1, owner2);
432 * Sorts a KeySet alphabetically by Key name.
434 * You need ksSort() only in few cases directly.
436 * @section sortlookup Don't need to sort before using ksLookup
438 * You don't need it if you just just kdbGet() and subsequent
441 KeySet *ks = ksNew(0);
443 // ksPop(), ksAppend() and ksAppendKey() allowed here
444 ksLookup(ks, s, 0); // you dont need to sort ks
447 * This is because the KeySet tracks if it needs to be sorted
448 * and ksLookup() will sort when needed.
450 * @section sortiterate Sort when iterating
452 * Before you iterate over a keyset you have to sort it, if
453 * you need it in a sorted way.
455 * To achieve that you can pass option_t::KDB_O_SORT to kdbGet()
456 * and kdbSet(). Then you will receive a already sorted keyset
457 * over which you can iterate.
459 KeySet *ks = ksNew(0);
460 kdbGet(h, ks, k, KDB_O_SORT);
461 // no changes to keyset allowed
463 // now you can iterate over a sorted keyset
466 * Its of course also possible to use ksLookup() once, because it
467 * will sort the keyset too.
469 * @section sortkey Sort when changing key
471 * @warning You should not use keySetName() or keyRemove() when a
472 * key belongs to a keyset. When you are doing this, you always need to @p manually
473 * sort @p all keysets where the key was before using ksLookup() (otherwise ksLookup()
474 * won't find that keys), kdbGet() or kdbSet() methods.
476 * When you change a key's name or its remove status the order
477 * which was previously correctly is then wrong. The keyset
478 * does not recognize this, so the programmer has to take care
479 * that ksSort() is called before any operation which needs
480 * a sorted keyset (which are all ksLookup(), all kdbGet()
481 * and all kdbSet() functions).
483 * @note You can remember that easily that all functions which get options
484 * require one of the following:
485 * - that you did not manipulate a keys name or a remove status
486 * - that you pass KDB_O_SORT when you know that you manipulated at least one key
487 * - that you ksSort() yourself after manipulating keys
489 * @section dirty Dirty KeySet
491 * When you use ksAppend(), ksAppendKey(), ksPop() the keyset is dirty
492 * afterwards, which means that it needs to be sorted. This is done
493 * automatically using a ksLookup() method and in ksGet() or ksSet()
494 * (All methods which accept options).
496 * It won't be done if you just iterate over the keyset, so you might
497 * use a ksLookup() or ksSort() first. ksLookup() will be more efficient
498 * in that case, because it will only sort when needed. Don't pass
499 * KDB_O_NOALL (it will deactivate the sorting feature),
500 * see ksLookup() for more information.
502 * @param ks KeySet to be sorted
503 * @see kdbGet(), kdbSet(), ksLookup() for some functions which may
504 * need sorting before they are called. (All functions which take
505 * options as arguments)
506 * @see keySetName(), keySetBaseName(), keyAddBaseName() and keyRemove()
507 * for all methods which change the sorting state where the keyset
508 * can't track the change.
509 * @see ksAppend(), ksAppendKey(), ksPop() for all methods which make
512 void ksSort(KeySet *ks)
516 ks->flags = ~KS_FLAG_DIRTY & ks->flags;
517 if (! ks->size) return;
519 qsort(ks->array,ks->size,sizeof(Key *),keyCompareWithRemove);
526 * Return the number of keys that @p ks contains.
528 * @param ks the keyset object to work with
529 * @return the number of keys that @p ks contains.
530 * @return -1 on NULL pointer
531 * @see ksNew(0), ksDel()
533 ssize_t ksGetSize(const KeySet *ks)
542 /*******************************************
543 * Filling up KeySets *
544 *******************************************/
547 * Appends a Key to the end of @p ks.
549 * A pointer to the key will
550 * be stored, and not a private copy. So a future ksDel() on
551 * @p ks may keyDel() the @p toAppend object, see keyGetRef().
553 * The reference counter of the key will be incremented, and
554 * thus toAppend is not const.
556 * The KeySet internal cursor is not moved.
558 * Makes the keyset dirty, see ksSort().
560 * @return the size of the KeySet after insertion
561 * @return -1 on NULL pointers
562 * @param ks KeySet that will receive the key
563 * @param toAppend Key that will be appended to ks
564 * @see ksInsert(), ksInsertKeys(), ksAppend(), keyNew(), ksDel()
568 ssize_t ksAppendKey(KeySet *ks, Key *toAppend)
571 if (!toAppend) return -1;
573 ks->flags |= KS_FLAG_DIRTY;
575 if (keyNeedRemove (toAppend)) ++ ks->rsize;
576 if (ks->size >= ks->alloc) ksResize (ks, ks->alloc * 2);
577 keyIncRef (toAppend);
578 ks->array[ks->size-1] = toAppend;
579 ks->array[ks->size] = 0;
586 * Append all @p toAppend contained keys to the end of the @p ks.
588 * @p toAppend KeySet will be left unchanged.
590 * Makes the keyset dirty, see ksSort().
592 * @return the size of the KeySet after transfer
593 * @return -1 on NULL pointers
594 * @param ks the KeySet that will receive the keys
595 * @param toAppend the KeySet that provides the keys that will be transfered
596 * @see ksAppendKey(), ksInsert(), ksInsertKeys()
599 ssize_t ksAppend(KeySet *ks, const KeySet *toAppend)
606 if (!toAppend) return -1;
611 if (toAppend->size <= 0) return ks->size;
612 ks->flags |= KS_FLAG_DIRTY;
613 ks->size += toAppend->size;
614 ks->rsize += toAppend->rsize;
615 while (ks->size >= toAlloc) toAlloc *= 2;
616 ksResize (ks, toAlloc);
617 for (i=0; i<toAppend->size; i++) keyIncRef(toAppend->array[i]);
618 memcpy (ks->array + oldSize, toAppend->array, toAppend->size * sizeof (Key *));
619 ks->array[ks->size] = 0;
627 * Remove and return the last key of @p ks.
629 * The reference counter will be decremented by one.
631 * The KeySets cursor will not be effected if it did not
632 * point to the popped key.
634 * @note You need to keyDel() the key afterwards, if
635 * you don't append it to another keyset. It has the
636 * same semantics like a key allocated with keyNew()
643 k1=keyNew(0); // ref counter 0
644 ksAppendKey(ks1, k1); // ref counter 1
645 ksAppendKey(ks2, k1); // ref counter 2
647 k1=ksPop (ks1); // ref counter 1
648 k1=ksPop (ks2); // ref counter 0, like after keyNew()
650 ksAppendKey(ks1, k1); // ref counter 1
652 ksDel (ks1); // key is deleted too
656 * @return the last key of @p ks
657 * @return NULL if @p ks is empty or on NULL pointer
658 * @param ks KeySet to work with
659 * @see ksAppendKey(), ksAppend()
660 * @see commandList() for an example
663 Key *ksPop(KeySet *ks)
669 if (ks->size <= 0) return 0;
671 if (ks->size+1 < ks->alloc/2) ksResize (ks, ks->alloc / 2);
672 ret = ks->array[ks->size];
673 ks->array[ks->size] = 0;
681 /*******************************************
682 * KeySet browsing methods *
683 *******************************************/
688 * Rewinds the KeySet internal cursor.
690 * Use it to set the cursor to the beginning of the KeySet.
691 * ksCurrent() will then always return NULL afterwards. So
692 * you want to ksNext() first.
696 while ((key = keyNext (ks))!=0) {}
699 * @param ks the keyset object to work with
700 * @return 0 on success
701 * @return -1 on NULL pointer
702 * @see ksNext(), ksCurrent()
704 int ksRewind(KeySet *ks)
715 * Returns the next Key in a KeySet.
717 * KeySets have an internal cursor that can be reset with ksRewind(). Every
718 * time ksNext() is called the cursor is incremented and the new current Key
721 * You'll get a NULL pointer if the key after the end of the KeySet was reached.
722 * It will set the cursor to the beginning of
723 * the KeySet and the next time the first key is returned.
725 * The @p ks internal cursor will be changed, so it is not const.
727 * @note You must not delete or change the key, use ksPop() if you want to delete it.
729 * @param ks the keyset object to work with
730 * @return the new current Key
731 * @return 0 when the end is reached
732 * @return 0 on NULL pointer
733 * @see ksRewind(), ksCurrent()
735 Key *ksNext(KeySet *ks)
739 if (ks->size == 0) return 0;
740 if (ks->current >= ks->size)
745 if (ks->cursor) ks->current++;
746 return ks->cursor = ks->array[ks->current];
753 * Return the current Key.
755 * The pointer is NULL if you reached the end or after
758 * @note You must not delete the key or change the key,
759 * use ksPop() if you want to delete it.
761 * @param ks the keyset object to work with
762 * @return pointer to the Key pointed by @p ks's cursor
763 * @return 0 on NULL pointer
764 * @see ksNext(), ksRewind()
765 * @see kdbMonitorKeys() for a usage example
767 Key *ksCurrent(const KeySet *ks)
778 * Return the first key in the KeySet.
780 * The KeySets cursor will not be effected.
782 * If ksCurrent()==ksHead() you know you are
785 * @param ks the keyset object to work with
786 * @return the first Key of a keyset
787 * @return 0 on NULL pointer or empty keyset
788 * @see ksTail() for the last key
789 * @see ksRewind(), ksCurrent() and ksNext() for iterating over the keyset
791 Key *ksHead(const KeySet *ks)
795 if (ks->size > 0) return ks->array[0];
804 * Return the last key in the KeySet.
806 * The KeySets cursor will not be effected.
808 * If ksCurrent()==ksTail() you know you
809 * are on the last key. ksNext() will return
810 * a NULL pointer afterwards.
812 * @param ks the keyset object to work with
813 * @return the last Key of a keyset
814 * @return 0 on NULL pointer or empty keyset
815 * @see ksHead() for the first key
816 * @see ksRewind(), ksCurrent() and ksNext() for iterating over the keyset
818 Key *ksTail(const KeySet *ks)
822 if (ks->size > 0) return ks->array[ks->size-1];
829 * Get the KeySet internal cursor.
831 * Use it to get the cursor of the actual position.
833 * @warning Cursors are getting invalid when the key
834 * was ksPop()ed or ksLookup() with KDB_O_POP was
837 * @section readahead Read ahead
839 * With the cursors it is possible to read ahead
845 while ((key = keyNext (ks))!=0)
848 jump = ksGetCursor(ks);
851 keyNext (ks); // now browse on
852 // use ksCurrent(ks) to check the keys
855 // jump back to the position marked before
856 ksSetCursor(ks, jump);
860 * @section restore Restoring state
862 * It can also be used to restore the state of a
863 * keyset in a function
868 cursor_t state = ksGetCursor(ks);
872 // now bring the keyset to the state before
873 ksSetCursor (ks, state);
877 * It is of course possible to make the KeySet const
878 * and cast its const away to set the cursor.
879 * Another way to achieve
880 * the same is to ksDup() the keyset, but it is
883 * An invalid cursor will be returned directly after
884 * ksRewind(). When you set an invalid cursor ksCurrent()
885 * is 0 and ksNext() == ksHead().
887 * @note Only use a cursor for the same keyset which it was
890 * @param ks the keyset object to work with
891 * @return a valid cursor on success
892 * @return an invalid cursor on NULL pointer or after ksRewind()
893 * @see ksNext(), ksSetCursor()
895 cursor_t ksGetCursor(const KeySet *ks)
897 if (!ks) return (cursor_t) -1;
899 if (ks->cursor == 0) return (cursor_t) -1;
900 else return (cursor_t) ks->current;
907 * Set the KeySet internal cursor.
909 * Use it to set the cursor to a stored position.
910 * ksCurrent() will then be the position which you got with.
912 * @warning Cursors may get invalid when the key
913 * was ksPop()ed or ksLookup() was used together
919 // key now in any position here
920 cursor = ksGetCursor (ks);
921 while ((key = keyNext (ks))!=0) {}
922 ksSetCursor (ks, cursor); // reset state
923 ksCurrent(ks); // in same position as before
926 * An invalid cursor will set the keyset to its beginning like
927 * ksRewind(). When you set an invalid cursor ksCurrent()
928 * is 0 and ksNext() == ksHead().
930 * @param cursor the cursor to use
931 * @param ks the keyset object to work with
932 * @return 0 when the keyset is ksRewind()ed
933 * @return 1 otherwise
934 * @return -1 on NULL pointer
935 * @see ksNext(), ksGetCursor()
937 int ksSetCursor(KeySet *ks, cursor_t cursor)
941 if ((cursor_t) -1 == cursor)
946 ks->current= (size_t)cursor;
947 ks->cursor=ks->array[ks->current];
955 * Returns the previous Key in a KeySet.
957 * KeySets have an internal cursor that can be reset with ksRewind(). Every
958 * time ksPrev() is called the cursor is decremented and the new current Key
961 * You'll get a NULL pointer if the key before begin of the KeySet was reached.
963 * Don't delete the key, use ksPop() if you want to delete it.
965 * @return the new current Key
966 * @see ksRewind(), ksCurrent()
969 static Key *ksPrev(KeySet *ks)
971 if (ks->size == 0) return 0;
972 if (ks->current <= 0)
978 return ks->cursor = ks->array[ks->current];
984 /*******************************************
985 * Looking up Keys inside KeySets *
986 *******************************************/
988 static int keyCompareByName(const void *p1, const void *p2) {
989 Key *key1=*(Key **)p1;
990 Key *key2=*(Key **)p2;
991 const char *name1 = keyName(key1);
992 const char *name2 = keyName(key2);
994 return strcmp(name1, name2);
997 static int keyCompareByNameCase(const void *p1, const void *p2) {
998 Key *key1=*(Key **)p1;
999 Key *key2=*(Key **)p2;
1000 const char *name1 = keyName(key1);
1001 const char *name2 = keyName(key2);
1003 return kdbiStrCaseCmp(name1, name2);
1006 static int keyCompareByNameOwner(const void *p1, const void *p2) {
1007 Key *key1=*(Key **)p1;
1008 Key *key2=*(Key **)p2;
1009 const char *name1 = keyName(key1);
1010 const char *name2 = keyName(key2);
1011 int result = strcmp(name1, name2);
1015 const char *owner1 = keyOwner(key1);
1016 const char *owner2 = keyOwner(key2);
1017 return strcmp(owner1, owner2);
1023 static int keyCompareByNameOwnerCase(const void *p1, const void *p2) {
1024 Key *key1=*(Key **)p1;
1025 Key *key2=*(Key **)p2;
1026 const char *name1 = keyName(key1);
1027 const char *name2 = keyName(key2);
1028 int result = kdbiStrCaseCmp(name1, name2);
1032 const char *owner1 = keyOwner(key1);
1033 const char *owner2 = keyOwner(key2);
1034 return kdbiStrCaseCmp(owner1, owner2);
1041 * Look for a Key contained in @p ks that matches the name of the @p key.
1043 * @section Introduction
1045 * @p ksLookup() is designed to let you work with
1046 * entirely pre-loaded KeySets, so instead of kdbGetKey(), key by key, the
1047 * idea is to fully kdbGet() for your application root key and
1048 * process it all at once with @p ksLookup().
1050 * This function is very efficient by using binary search. Together with
1051 * kdbGet() which can you load the whole configuration with only
1052 * some communication to backends you can write very effective but short
1053 * code for configuration.
1057 * If found, @p ks internal cursor will be positioned in the matched key
1058 * (also accessible by ksCurrent()), and a pointer to the Key is returned.
1059 * If not found, @p ks internal cursor will not move, and a NULL pointer is
1062 * Cascading is done if the first character is a /. This leads to ignoring
1063 * the prefix like system/ and user/.
1065 if (kdbGet(handle, "user/myapp", myConfig, 0 ) == -1)
1066 ErrorHandler ("Could not get Keys");
1068 if (kdbGet(handle, "system/myapp", myConfig, 0 ) == -1)
1069 ErrorHandler ("Could not get Keys");
1071 if ((myKey = ksLookup(myConfig, key, 0)) == NULL)
1072 ErrorHandler ("Could not Lookup Key");
1075 * This is the way multi user Programs should get there configuration and
1076 * search after the values. It is guaranteed that more namespaces can be
1077 * added easily and that all values can be set by admin and user.
1079 * @subsection KDB_O_NOALL
1081 * When KDB_O_NOALL is set the keyset will be only searched from ksCurrent()
1082 * to ksTail(). You need to ksRewind() the keyset yourself. ksCurrent() is
1083 * always set properly after searching a key, so you can go on searching
1084 * another key after the found key.
1086 * When KDB_O_NOALL is not set the cursor will stay untouched and all keys
1087 * are considered. A much more efficient binary search will be used then.
1089 * So if you change keys, e.g. rename (keySetName()) or remove (keyRemove()) them
1090 * make sure to sort the keyset with ksSort(). When the keyset is dirty,
1091 * see ksNeedSort() it will be sorted automatically when needed.
1093 * @subsection KDB_O_POP
1095 * When KDB_O_POP is set the key which was found will be ksPop()ed. ksCurrent()
1096 * will not be changed, only iff ksCurrent() is the searched key, then the keyset
1097 * will be ksRewind()ed.
1099 * @note Note that keyRemove() keys won't be found after the first time the keyset
1100 * is resorted. Lookup automatically sorts the keyset, if needed, but it
1101 * can't find it out when only keys are changed, not the keyset.
1103 * @note Like in ksPop() the popped key always needs to be keyDel() afterwards, even
1104 * if it is appended to another keyset.
1106 * @warning All cursors on the keyset will be invalid
1107 * iff you use KDB_O_POP, so don't use this if you rely on a cursor, see ksGetCursor().
1109 * @note Never use ksLookup() with KDB_O_POP and ksAppendKey() or ksAppend() together in a loop.
1110 * Otherwise ksLookup() will need to resort the keyset every iteration and spend 99.96% of the
1111 * time in ksSort() (benchmarked with above 500k iterations).
1113 * You can solve this problem by using KDB_O_NOALL, risking you have to iterate n^2 instead of n.
1115 * The more elegant way is to separate the keyset you use for ksLookup() and ksAppendKey():
1117 int f(KeySet *iterator, KeySet *lookup)
1119 KeySet *append = ksNew (ksGetSize(lookup), KS_END);
1124 while (current=ksNext(iterator))
1126 key = ksLookup (lookup, current, KDB_O_POP);
1128 ksAppendKey(append, key); // now append it to append, not lookup!
1129 keyDel (key); // make sure to ALWAYS delete poped keys.
1131 ksAppend(lookup, append);
1132 // now lookup needs to be sorted only once, append never
1137 * @param ks where to look for
1138 * @param key the key object you are looking for
1139 * @param options some @p KDB_O_* option bits:
1140 * - @p KDB_O_NOCASE @n
1141 * Lookup ignoring case.
1142 * - @p KDB_O_WITHOWNER @n
1143 * Also consider correct owner.
1144 * - @p KDB_O_NOALL @n
1145 * Only search from ksCurrent() to end of keyset, see above text.
1147 * Pop the key which was found.
1148 * - @p KDB_O_SORT @n
1149 * Force sorting before searching, see ksSort().
1150 * Together with KDB_O_NOALL the search will start from beginning.
1151 * @return pointer to the Key found, 0 otherwise
1152 * @return 0 on NULL pointers
1153 * @see ksLookupByName() to search by a name given by a string
1154 * @see ksCurrent(), ksRewind(), ksNext() for iterating over a keyset
1155 * @see ksSort() to understand how keyset sort themself
1157 Key *ksLookup(KeySet *ks, Key * key, option_t options)
1161 cursor_t cursor = 0;
1167 cursor = ksGetCursor (ks);
1169 if (options & KDB_O_SORT)
1174 else if (!(options & KDB_O_NOALL) && ks->flags & KS_FLAG_DIRTY) ksSort(ks);
1178 if (options & KDB_O_NOALL)
1180 while ((current=ksNext(ks)) != 0) {
1181 if ((options & KDB_O_WITHOWNER) && (options & KDB_O_NOCASE))
1183 if (!keyCompareByNameOwnerCase(&key, ¤t)) break;
1185 else if (options & KDB_O_WITHOWNER)
1187 if (!keyCompareByNameOwner(&key, ¤t)) break;
1189 else if (options & KDB_O_NOCASE)
1191 if (!keyCompareByNameCase(&key, ¤t)) break;
1193 else if (!keyCompareByName(&key, ¤t)) break;
1195 if (options & KDB_O_DEL) keyDel (key);
1196 if (current == 0) ksSetCursor (ks, cursor);
1199 if ((options & KDB_O_WITHOWNER) && (options & KDB_O_NOCASE))
1200 found = (Key **) bsearch (&key, ks->array+jump, ks->size-jump,
1201 sizeof (Key *), keyCompareByNameOwnerCase);
1202 else if (options & KDB_O_WITHOWNER)
1203 found = (Key **) bsearch (&key, ks->array+jump, ks->size-jump,
1204 sizeof (Key *), keyCompareByNameOwner);
1205 else if (options & KDB_O_NOCASE)
1206 found = (Key **) bsearch (&key, ks->array+jump, ks->size-jump,
1207 sizeof (Key *), keyCompareByNameCase);
1209 found = (Key **) bsearch (&key, ks->array+jump, ks->size-jump,
1210 sizeof (Key *), keyCompareByName);
1211 if (options & KDB_O_DEL) keyDel (key);
1214 if (options & KDB_O_POP)
1217 /* Move the array over the place where key was found */
1218 memmove (found, found+1, ks->size*sizeof(Key *)-(found-ks->array)-sizeof(Key *));
1219 *(ks->array+ks->size-1) = k;
1220 if (found < ks->array+ks->current)
1224 else if (found == ks->array+ks->current)
1230 cursor = found-ks->array;
1231 ksSetCursor(ks, cursor);
1235 /*Reset Cursor to old position*/
1236 ksSetCursor(ks, cursor);
1243 * Look for a Key contained in @p ks that matches @p name.
1245 * @p ksLookupByName() is designed to let you work with
1246 * entirely pre-loaded KeySets, so instead of kdbGetKey(), key by key, the
1247 * idea is to fully kdbGetByName() for your application root key and
1248 * process it all at once with @p ksLookupByName().
1250 * This function is very efficient by using binary search. Together with
1251 * kdbGetByName() which can you load the whole configuration with only
1252 * some communication to backends you can write very effective but short
1253 * code for configuration.
1255 * If found, @p ks internal cursor will be positioned in the matched key
1256 * (also accessible by ksCurrent()), and a pointer to the Key is returned.
1257 * If not found, @p ks internal cursor will not move, and a NULL pointer is
1260 * @section cascading Cascading
1262 * Cascading is done if the first character is a /. This leads to ignoring
1263 * the prefix like system/ and user/.
1265 if (kdbGetByName(handle, "/sw/myapp/current", myConfig, 0 ) == -1)
1266 ErrorHandler ("Could not get Keys");
1268 if ((myKey = ksLookupByName (myConfig, "/myapp/current/key", 0)) == NULL)
1269 ErrorHandler ("Could not Lookup Key");
1272 * This is the way multi user Programs should get there configuration and
1273 * search after the values. It is guaranteed that more namespaces can be
1274 * added easily and that all values can be set by admin and user.
1276 * @section fullsearch Full Search
1278 * When KDB_O_NOALL is set the keyset will be only searched from ksCurrent()
1279 * to ksTail(). You need to ksRewind() the keyset yourself. ksCurrent() is
1280 * always set properly after searching a key, so you can go on searching
1281 * another key after the found key.
1283 * When KDB_O_NOALL is not set the cursor will stay untouched and all keys
1284 * are considered. A much more efficient binary search will be used then.
1286 * @param ks where to look for
1287 * @param name key name you are looking for
1288 * @param options some @p KDB_O_* option bits:
1289 * - @p KDB_O_NOCASE @n
1290 * Lookup ignoring case.
1291 * - @p KDB_O_WITHOWNER @n
1292 * Also consider correct owner.
1293 * - @p KDB_O_NOALL @n
1294 * Only search from ksCurrent() to end of keyset, see above text.
1296 * Pop the key which was found.
1297 * - @p KDB_O_SORT @n
1298 * Force sorting before searching, see ksSort().
1299 * Together with KDB_O_NOALL the search will start from beginning.
1301 * Currently no options supported.
1302 * @return pointer to the Key found, 0 otherwise
1303 * @return 0 on NULL pointers
1304 * @see keyCompare() for very powerfull Key lookups in KeySets
1305 * @see ksCurrent(), ksRewind(), ksNext()
1307 Key *ksLookupByName(KeySet *ks, const char *name, option_t options)
1314 if (!name) return 0;
1316 if (! ks->size) return 0;
1320 /* Will be freed by second key */
1321 newname = kdbiMalloc (strlen (name) + sizeof ("system") + 1);
1324 /*errno = KDB_ERR_NOMEM;*/
1327 strncpy (newname+4, "db",2);
1328 strcpy (newname+6, name);
1329 key = keyNew (newname+4, KEY_END);
1330 found = ksLookup(ks, key, options);
1335 strncpy (newname+2, "file",4);
1336 key = keyNew (newname+2, KEY_END);
1337 found = ksLookup(ks, key, options);
1343 strncpy (newname, "memory",6);
1344 key = keyNew (newname, KEY_END);
1345 found = ksLookup(ks, key, options);
1352 key = keyNew (name, KEY_END);
1354 found = ksLookup(ks, key, options);
1362 * Lookup for a Key contained in @p ks KeySet that matches @p value,
1363 * starting from ks' ksNext() position.
1365 * If found, @p ks internal cursor will be positioned in the matched key
1366 * (also accessible by ksCurrent()), and a pointer to the Key is returned.
1367 * If not found, @p ks internal cursor won't move, and a NULL pointer is
1370 * This method skips binary keys.
1375 while (key=ksLookupByString(ks,"my value",0)) {
1376 // show all keys which value="my value"
1377 keyToStream(key,stdout,0);
1381 * @param ks where to look for
1382 * @param value the value which owner key you want to find
1383 * @param options some @p KDB_O_* option bits. Currently supported:
1384 * - @p KDB_O_NOALL @n
1385 * Only search from ksCurrent() to end of keyset, see ksLookup().
1386 * - @p KDB_O_SORT @n
1387 * Force sorting before searching, see ksSort().
1388 * Together with KDB_O_NOALL the search will start from beginning.
1389 * - @p KDB_O_NOCASE @n
1390 * Lookup ignoring case.
1391 * @return the Key found, 0 otherwise
1392 * @see ksLookupByBinary()
1393 * @see keyCompare() for very powerfull Key lookups in KeySets
1394 * @see ksCurrent(), ksRewind(), ksNext()
1396 Key *ksLookupByString(KeySet *ks, const char *value, option_t options)
1403 if (options & KDB_O_SORT)
1408 else if (!(options & KDB_O_NOALL) && ks->flags & KS_FLAG_DIRTY) ksSort(ks);
1410 if (!(options & KDB_O_NOALL))
1413 init=ksGetCursor(ks);
1416 if (!value) return 0;
1418 while ((current=ksNext(ks)) != 0)
1420 if (!keyIsString(current)) continue;
1422 /*fprintf (stderr, "Compare %s with %s\n", keyValue(current), value);*/
1424 if ((options & KDB_O_NOCASE) &&
1425 !kdbiStrCaseCmp(keyValue(current),value)) break;
1426 else if (!strcmp(keyValue(current),value)) break;
1429 /* reached end of KeySet */
1430 if (!(options & KDB_O_NOALL))
1432 ksSetCursor (ks, init);
1441 * Lookup for a Key contained in @p ks KeySet that matches the binary @p value,
1442 * starting from ks' ksNext() position.
1444 * If found, @p ks internal cursor will be positioned in the matched key.
1445 * That means it is also accessible by ksCurrent(). A pointer to the Key
1446 * is returned. If not found, @p ks internal cursor won't move, and a
1447 * NULL pointer is returned.
1449 * This method skips string keys.
1451 * @param ks where to look for
1452 * @param value the value which owner key you want to find
1453 * @param size the size of @p value
1454 * @param options some @p KDB_O_* option bits:
1455 * - @p KDB_O_NOALL @n
1456 * Only search from ksCurrent() to end of keyset, see above text.
1457 * - @p KDB_O_SORT @n
1458 * Force sorting before searching, see ksSort().
1459 * Together with KDB_O_NOALL the search will start from beginning.
1460 * @return the Key found, NULL otherwise
1461 * @return 0 on NULL pointer
1462 * @see ksLookupByString()
1463 * @see keyCompare() for very powerfull Key lookups in KeySets
1464 * @see ksCurrent(), ksRewind(), ksNext()
1466 Key *ksLookupByBinary(KeySet *ks, const void *value, size_t size,
1474 if (options & KDB_O_SORT)
1479 else if (!(options & KDB_O_NOALL) && ks->flags & KS_FLAG_DIRTY) ksSort(ks);
1481 if (!(options & KDB_O_NOALL))
1484 init=ksGetCursor(ks);
1487 while ((current=ksNext(ks)))
1489 if (!keyIsBinary(current)) continue;
1491 if (size != current->dataSize) continue;
1495 if (!current->data) break;
1499 if (current->data &&
1500 !memcmp(current->data,value,size)) break;
1503 /* reached end of KeySet */
1504 if (!(options & KDB_O_NOALL))
1506 ksSetCursor (ks, init);
1514 /*******************************************
1515 * Other operations *
1516 *******************************************/
1522 * Calculates the common parent to all keys in @p ks.
1524 * This is a c-helper function, you need not implement it in bindings.
1526 * Given the @p ks KeySet, calculates the parent name for all the keys.
1527 * So if @p ks contains this keys:
1530 * system/sw/xorg/Monitors/Monitor1/vrefresh
1531 * system/sw/xorg/Monitors/Monitor1/hrefresh
1532 * system/sw/xorg/Devices/Device1/driver
1533 * system/sw/xorg/Devices/Device1/mode
1536 * The common parent is @p system/sw/xorg .
1538 * On the other hand, if we have this KeySet:
1542 * system/other/thing
1546 * No common parent is possible, so @p returnedCommonParent will contain nothing.
1548 * This method will work correctly only on @link ksSort() sorted KeySets @endlink.
1550 * @param working the Keyset to work with
1551 * @param returnedCommonParent a pre-allocated buffer that will receive the
1552 * common parent, if found
1553 * @param maxSize size of the pre-allocated @p returnedCommonParent buffer
1554 * @return size in bytes of the parent name, or 0 if there is no common parent,
1555 * or -1 to indicate an error, then @p errno must be checked.
1557 ssize_t ksGetCommonParentName(const KeySet *working,char *returnedCommonParent, size_t maxSize) {
1558 size_t parentSize=0;
1563 init = ksGetCursor (working);
1564 ks = (KeySet *) working;
1566 if (ks->size < 1) return 0;
1569 current = ksNext(ks);
1570 if (keyGetNameSize(current) > maxSize) {
1571 /*errno=KDB_ERR_TRUNC;*/
1572 returnedCommonParent[0]=0;
1576 strcpy(returnedCommonParent,keyName(current));
1577 parentSize=kdbiStrLen(returnedCommonParent);
1579 while (*returnedCommonParent) {
1581 while ((current = ksNext(ks)) != 0) {
1582 /* Test if a key doesn't match */
1583 if (memcmp(returnedCommonParent,keyName(current),parentSize-1)) break;
1586 /* some key failed to be a child */
1587 /* parent will be the parent of current parent... */
1590 if ((delim=strrchr(returnedCommonParent,PATH_SEPARATOR))) {
1592 parentSize=kdbiStrLen(returnedCommonParent);
1594 *returnedCommonParent=0;
1596 break; /* Better don't make comparision with parentSize-1 now */
1599 /* All keys matched (current==0) */
1600 /* We have our common parent to return in commonParent */
1601 ksSetCursor (ks, init );
1605 ksSetCursor (ks, init );
1606 return parentSize; /* if reached, will be zero */
1611 /*********************************************************************
1612 * Data constructors (protected) *
1613 *********************************************************************/
1619 * For internal useage only.
1621 * Don't use that function to be portable. You can give an hint
1622 * how large the keyset should be in ksNew().
1624 * Subsequent is the description of the implementation with array.
1625 * ksResize() enlarge or shrink the internal array to wished
1628 * If you resize it to n, you can be sure to fill in n-1 elements,
1629 * the n-th element will do an automatic resize to n*2. So give
1630 * some spare to avoid wasteful duplication.
1632 * @param ks the keyset which should be resized
1633 * @param alloc the size to which the array will be resized
1634 * @return 1 on success
1635 * @return 0 on nothing done because keyset would be too small.
1636 * @return -1 if alloc is smaller then current size of keyset.
1637 * @return -1 on memory error
1639 int ksResize (KeySet *ks, size_t alloc)
1641 if (alloc == ks->alloc) return 1;
1642 if (alloc < ks->size) return 0;
1643 if (alloc < KEYSET_SIZE)
1645 if (ks->alloc != KEYSET_SIZE) alloc = KEYSET_SIZE;
1649 if (ks->array == NULL)
1650 { /* Not allocated up to now */
1653 ks->array = kdbiMalloc (sizeof(struct _Key *) * ks->alloc);
1656 /*errno = KDB_ERR_NOMEM;*/
1661 #if DEBUG && VERBOSE
1662 printf ("Resize from %d to %d\n",(int) ks->alloc,(int) alloc);
1667 if (kdbiRealloc((void**) &ks->array, sizeof(struct _Key *) * ks->alloc) == -1)
1670 fprintf (stderr, "Reallocation error\n");
1672 kdbiFree (ks->array);
1674 /*errno = KDB_ERR_NOMEM;*/
1682 * Returns current allocation size.
1684 * @param ks the keyset object to work with
1685 * @return allocated size*/
1686 size_t ksGetAlloc (const KeySet *ks)
1694 * KeySet object initializer.
1696 * You should always use ksNew() instead of ksInit().
1698 * Every KeySet object that will be used must be initialized first, to setup
1699 * pointers, counters, etc. After use, all ksInit()ialized KeySets must be
1700 * cleaned with ksClear().
1702 * @deprecated Thus you can't get a Keyset without ksNew, this function is useless.
1703 * @see ksNew(), ksClose(), keyInit()
1704 * @return 1 on success
1706 int ksInit(KeySet *ks) {
1708 ks->flags = KS_FLAG_DIRTY;
1721 * KeySet object initializer.
1723 * @deprecated Thus you can't get a Keyset without ksNew, this function is useless.
1724 * @see ksDel(), ksNew(), keyInit()
1725 * @return 1 on success
1727 int ksClose(KeySet *ks)
1732 while ((k = ksNext(ks)) != 0)
1738 if (ks->array) kdbiFree (ks->array);