Git init
[pkgs/e/elektra.git] / src / libelektra / keyset.c
1 /***************************************************************************
2                           keyset.c  -  Methods for KeySet manipulation
3                              -------------------
4     begin                : Sun Oct 02 2005
5     copyright            : (C) 2005 by Avi Alkalay
6     email                : avi@unix.sh
7  ***************************************************************************/
8
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the BSD License (revised).                      *
13  *                                                                         *
14  ***************************************************************************/
15
16
17 /**
18  * @defgroup keyset KeySet :: Class Methods
19  * @brief Methods to manipulate KeySets.
20  *
21  * A KeySet is a unsorted set of keys.
22  *
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*).
26  *
27  * It can be implemented in various ways like a linked list or with a
28  * dynamically allocated array.
29  *
30  * With ksNew() you can create a new KeySet.
31  *
32  * You can add keys with ksAppendKey() in the keyset. ksGetSize() tells you
33  * the current size of the keyset.
34  *
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
37  * key of the set.
38  *
39  * KeySets have an @link ksCurrent() internal cursor @endlink. This is used
40  * for ksLookup() and kdbSet().
41  *
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.
47  *
48  * You can easily create and iterate keys:
49  * @code
50 #include <kdb.h>
51
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),
58         KS_END);
59 // append a key in the keyset
60 ksAppendKey(myConfig, keyNew("user/name4", 0));
61
62 Key *current;
63 ksRewind(myConfig);
64 while ((current=ksNext(myConfig))!=0) {
65         printf("Key name is %s.\n", keyName (current));
66 }
67 ksDel (myConfig); // delete keyset and all keys appended
68  * @endcode
69  *
70  * @{
71  */
72
73 #ifdef HAVE_CONFIG_H
74 #include "config.h"
75 #endif
76
77 #if DEBUG && HAVE_STDIO_H
78 #include <stdio.h>
79 #endif
80
81 #ifdef HAVE_STDLIB_H
82 #include <stdlib.h>
83 #endif
84
85 #ifdef HAVE_STDARG_H
86 #include <stdarg.h>
87 #endif
88
89 #ifdef HAVE_STRING_H
90 #include <string.h>
91 #endif
92
93 #include "kdbbackend.h"
94
95
96
97 /**
98  * Allocate, initialize and return a new KeySet object.
99  *
100  * Objects created with ksNew() must be destroyed with ksDel().
101  *
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.
105  *
106  * For most uses
107  * @code
108 KeySet *keys = ksNew(0);
109 // work with it
110 ksDel (keys);
111  * @endcode
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.
115  *
116  * But if you have any clue how large your keyset may be you should
117  * read the next statements.
118  *
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:
121  * @code
122 KeySet * keys = ksNew (15, KS_END);
123 // work with it
124 ksDel (keys);
125  * @endcode
126  *
127  * If you start having 3 keys, and your application needs approximately
128  * 200-500 keys, you can use:
129  * @code
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!
135 // work with it
136 ksDel (config);
137  * @endcode
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
140  * 497 keys.
141  *
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.
144  *
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
147  * program.
148  * See http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html#AEN135
149  *
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
155  */
156 KeySet *ksNew(size_t alloc, ...) {
157         KeySet *ks;
158         va_list va;
159
160         if (alloc) va_start(va, alloc);
161         ks = ksVNew (alloc, va);
162         if (alloc) va_end (va);
163
164         return ks;
165 }
166
167 KeySet *ksVNew (size_t alloc, va_list va)
168 {
169         KeySet *keyset=0;
170         Key *key = 0;
171
172         keyset= (KeySet *)kdbiMalloc(sizeof(KeySet));
173         if (!keyset)
174         {
175                 /*errno = KDB_ERR_NOMEM;*/
176                 return 0;
177         }
178         ksInit(keyset);
179
180         if (alloc < KEYSET_SIZE) keyset->alloc=KEYSET_SIZE;
181         else keyset->alloc=alloc;
182
183         keyset->array = kdbiMalloc (sizeof(struct _Key *) * keyset->alloc);
184         if (!keyset->array)
185         {
186                 kdbiFree(keyset);
187                 /*errno = KDB_ERR_NOMEM;*/
188                 return 0;
189         }
190         keyset->array[0] = 0;
191         
192
193         if (alloc) {
194                 key = (struct _Key *) va_arg (va, struct _Key *);
195                 while (key) {
196                         ksAppendKey(keyset, key);
197                         key = (struct _Key *) va_arg (va, struct _Key *);
198                 }
199
200         }
201
202         return keyset;
203 }
204
205 /**
206  * Return a duplicate of a keyset.
207  *
208  * Objects created with ksDup() must be destroyed with ksDel().
209  *
210  * Memory will be allocated as needed for dynamic properties,
211  * so you need to ksDel() the returned pointer.
212  *
213  * A flat copy is made, so the keys will not be duplicated,
214  * but there reference counter is updated, so both keysets
215  * need ksDel().
216  *
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
222  */
223 KeySet *ksDup (const KeySet * source)
224 {
225         KeySet *keyset=0;
226
227         if (!source) return 0;
228
229         keyset = ksNew(source->alloc,KS_END);
230         ksAppend (keyset, source);
231         return keyset;
232 }
233
234
235
236 /**
237  * Copy a keyset.
238  *
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
243  * exists.
244  *
245  * You can also use it to clear a keyset when you pass
246  * a NULL pointer as @p source.
247  *
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.
251  *
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().
255  *
256  * @code
257 int f (KeySet *ks)
258 {
259         KeySet *c = ksNew (20, ..., KS_END);
260         // c receives keys
261         ksCopy (ks, c); // pass the keyset to the caller
262
263         ksDel (c);
264 }       // caller needs to ksDel (ks)
265  * @endcode
266  *
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
274  */
275 int ksCopy (KeySet *dest, const KeySet *source)
276 {
277         if (!dest) return -1;
278         ksClear (dest);
279         if (!source) return 0;
280
281         ksAppend (dest, source);
282         ksSetCursor (dest, ksGetCursor (source));
283
284         return 1;
285 }
286
287
288
289 /**
290  * A destructor for KeySet objects.
291  *
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()).
296  *
297  * @param ks the keyset object to work with
298  * @return 0 when the keyset was freed
299  * @return -1 on null pointer
300  * @see ksNew()
301  */
302 int ksDel(KeySet *ks)
303 {
304         int rc;
305
306         if (!ks) return -1;
307
308         rc=ksClose(ks);
309         kdbiFree(ks);
310
311         return rc;
312 }
313
314 /*
315  * KeySet object cleaner.
316  *
317  * Will keyDel() all contained keys, reset internal pointers and counters.
318  *
319  * After this call you can use the empty keyset again.
320  *
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
325  */
326 int ksClear(KeySet *ks)
327 {
328         ksClose (ks);
329
330         if (ks->array)
331         {       /* go back to standard size KEYSET_SIZE */
332                 if (kdbiRealloc ((void**) &ks->array, sizeof(struct _Key *) * KEYSET_SIZE) == -1)
333                 {
334                         /*errno = KDB_ERR_NOMEM;*/
335                         kdbiFree (ks->array);
336                         ks->array = 0;
337                         ks->size = 0;
338                         return -1;
339                 }
340         } else {
341                 if ((ks->array = kdbiMalloc (sizeof(struct _Key *) * KEYSET_SIZE)) == 0)
342                 {
343                         /*errno = KDB_ERR_NOMEM;*/
344                         ks->size = 0;
345                         return -1;
346                 }
347         }
348         ks->alloc = KEYSET_SIZE;
349
350
351         return 0;
352 }
353
354
355
356 /*
357  * Returns if keyset needs sort.
358  *
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.
362  *
363  * Before operations where the code depends on a sorted keyset,
364  * namely in kdbGet(), kdbSet() and ksLookup(), this simple code
365  * sorts when needed:
366  *
367  * @code
368 if (ksNeedSort(ks)) ksSort(ks);
369  * @endcode
370  *
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
375  * set the flag.
376  *
377  * So if your code might rename keys or flag them to remove,
378  * make sure that you use
379  *
380  * @code
381 ksSort(ks);
382  * @endcode
383  *
384  * somewhere afterwards before using ksLookup(). Otherwise the
385  * renamed key won't be found.
386  *
387  * kdbSet() will have no problems with that issue, because it
388  * duplicates its keysets using ksDup().
389  *
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
394  */
395 int ksNeedSort (const KeySet *ks)
396 {
397         return (ks->flags & KS_FLAG_DIRTY) == KS_FLAG_DIRTY;
398 }
399
400
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);
408
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;
412
413
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;
418                 else return 0;
419         } else { /* sort by owner */
420                 if (ret == 0)
421                 {
422                         const char *owner1 = keyOwner(key1);
423                         const char *owner2 = keyOwner(key2);
424                         return strcmp(owner1, owner2);
425                 }
426                 else return ret;
427         }
428 }
429
430
431 /**
432  * Sorts a KeySet alphabetically by Key name.
433  *
434  * You need ksSort() only in few cases directly.
435  *
436  * @section sortlookup Don't need to sort before using ksLookup
437  *
438  * You don't need it if you just just kdbGet() and subsequent
439  * ksLookup().
440  * @code
441 KeySet *ks = ksNew(0);
442 kdbGet(h, ks, k, 0);
443 // ksPop(), ksAppend() and ksAppendKey() allowed here
444 ksLookup(ks, s, 0); // you dont need to sort ks
445  * @endcode
446  *
447  * This is because the KeySet tracks if it needs to be sorted
448  * and ksLookup() will sort when needed.
449  *
450  * @section sortiterate Sort when iterating
451  *
452  * Before you iterate over a keyset you have to sort it, if
453  * you need it in a sorted way.
454  *
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.
458  * @code
459 KeySet *ks = ksNew(0);
460 kdbGet(h, ks, k, KDB_O_SORT);
461 // no changes to keyset allowed
462 ksRewind(ks);
463 // now you can iterate over a sorted keyset
464  * @endcode
465  *
466  * Its of course also possible to use ksLookup() once, because it
467  * will sort the keyset too.
468  *
469  * @section sortkey Sort when changing key
470  *
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.
475  *
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).
482  *
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
488  *
489  * @section dirty Dirty KeySet
490  *
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).
495  *
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.
501  *
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
510  *     a keyset dirty.
511  */
512 void ksSort(KeySet *ks)
513 {
514         if (!ks) return;
515
516         ks->flags = ~KS_FLAG_DIRTY & ks->flags;
517         if (! ks->size) return;
518
519         qsort(ks->array,ks->size,sizeof(Key *),keyCompareWithRemove);
520 }
521
522
523
524
525 /**
526  * Return the number of keys that @p ks contains.
527  *
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()
532  */
533 ssize_t ksGetSize(const KeySet *ks)
534 {
535         if (!ks) return -1;
536
537         return ks->size;
538 }
539
540
541
542 /******************************************* 
543  *           Filling up KeySets            *
544  *******************************************/
545
546 /**
547  * Appends a Key to the end of @p ks.
548  *
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().
552  *
553  * The reference counter of the key will be incremented, and
554  * thus toAppend is not const.
555  *
556  * The KeySet internal cursor is not moved.
557  *
558  * Makes the keyset dirty, see ksSort().
559  *
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()
565  * @see keyIncRef()
566  *
567  */
568 ssize_t ksAppendKey(KeySet *ks, Key *toAppend)
569 {
570         if (!ks) return -1;
571         if (!toAppend) return -1;
572
573         ks->flags |= KS_FLAG_DIRTY;
574         ++ ks->size;
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;
580         return ks->size;
581 }
582
583
584
585 /**
586  * Append all @p toAppend contained keys to the end of the @p ks.
587  *
588  * @p toAppend KeySet will be left unchanged.
589  *
590  * Makes the keyset dirty, see ksSort().
591  *
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()
597  * 
598  */
599 ssize_t ksAppend(KeySet *ks, const KeySet *toAppend)
600 {
601         size_t oldSize = 0;
602         int i = 0;
603         int toAlloc = 0;
604
605         if (!ks) return -1;
606         if (!toAppend) return -1;
607
608         oldSize = ks->size;
609         toAlloc = ks->alloc;
610
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;
620         return ks->size;
621 }
622
623
624
625
626 /**
627  * Remove and return the last key of @p ks.
628  *
629  * The reference counter will be decremented by one.
630  *
631  * The KeySets cursor will not be effected if it did not
632  * point to the popped key.
633  *
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()
637  * or keyDup().
638  *
639  *@code
640 ks1=ksNew(0);
641 ks2=ksNew(0);
642
643 k1=keyNew(0); // ref counter 0
644 ksAppendKey(ks1, k1); // ref counter 1
645 ksAppendKey(ks2, k1); // ref counter 2
646
647 k1=ksPop (ks1); // ref counter 1
648 k1=ksPop (ks2); // ref counter 0, like after keyNew()
649
650 ksAppendKey(ks1, k1); // ref counter 1
651
652 ksDel (ks1); // key is deleted too
653 ksDel (ks2);
654  *@endcode
655  *
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
661  *
662  */
663 Key *ksPop(KeySet *ks)
664 {
665         Key *ret=0;
666
667         if (!ks) return 0;
668
669         if (ks->size <= 0) return 0;
670         -- ks->size;
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;
674         keyDecRef(ret);
675
676         return ret;
677 }
678
679
680
681 /*******************************************
682  *           KeySet browsing methods       *
683  *******************************************/
684
685
686
687 /**
688  * Rewinds the KeySet internal cursor.
689  *
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.
693  *
694  * @code
695 ksRewind (ks);
696 while ((key = keyNext (ks))!=0) {}
697  * @endcode
698  *
699  * @param ks the keyset object to work with
700  * @return 0 on success
701  * @return -1 on NULL pointer
702  * @see ksNext(), ksCurrent()
703  */
704 int ksRewind(KeySet *ks)
705 {
706         if (!ks) return -1;
707
708         ks->cursor=0;
709         ks->current=0;
710         return 0;
711 }
712
713
714 /**
715  * Returns the next Key in a KeySet.
716  *
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
719  * is returned.
720  *
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.
724  *
725  * The @p ks internal cursor will be changed, so it is not const.
726  *
727  * @note You must not delete or change the key, use ksPop() if you want to delete it.
728  *
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()
734  */
735 Key *ksNext(KeySet *ks)
736 {
737         if (!ks) return 0;
738
739         if (ks->size == 0) return 0;
740         if (ks->current >= ks->size)
741         {
742                 return 0;
743         }
744
745         if (ks->cursor) ks->current++;
746         return ks->cursor = ks->array[ks->current];
747 }
748
749
750
751
752 /**
753  * Return the current Key.
754  *
755  * The pointer is NULL if you reached the end or after
756  * ksRewind().
757  *
758  * @note You must not delete the key or change the key,
759  *    use ksPop() if you want to delete it.
760  *
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
766  */
767 Key *ksCurrent(const KeySet *ks)
768 {
769         if (!ks) return 0;
770
771         return ks->cursor;
772 }
773
774
775
776
777 /**
778  * Return the first key in the KeySet.
779  *
780  * The KeySets cursor will not be effected.
781  *
782  * If ksCurrent()==ksHead() you know you are
783  * on the first key.
784  *
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
790  */
791 Key *ksHead(const KeySet *ks)
792 {
793         if (!ks) return 0;
794
795         if (ks->size > 0) return ks->array[0];
796         else return 0;
797 }
798
799
800
801
802
803 /**
804  * Return the last key in the KeySet.
805  *
806  * The KeySets cursor will not be effected.
807  *
808  * If ksCurrent()==ksTail() you know you
809  * are on the last key. ksNext() will return
810  * a NULL pointer afterwards.
811  *
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
817  */
818 Key *ksTail(const KeySet *ks)
819 {
820         if (!ks) return 0;
821
822         if (ks->size > 0) return ks->array[ks->size-1];
823         else return 0;
824 }
825
826
827
828 /**
829  * Get the KeySet internal cursor.
830  *
831  * Use it to get the cursor of the actual position.
832  *
833  * @warning Cursors are getting invalid when the key
834  * was ksPop()ed or ksLookup() with KDB_O_POP was
835  * used.
836  *
837  * @section readahead Read ahead
838  *
839  * With the cursors it is possible to read ahead
840  * in a keyset:
841  *
842  * @code
843 cursor_t jump;
844 ksRewind (ks);
845 while ((key = keyNext (ks))!=0)
846 {
847         // now mark this key
848         jump = ksGetCursor(ks);
849
850         //code..
851         keyNext (ks); // now browse on
852         // use ksCurrent(ks) to check the keys
853         //code..
854
855         // jump back to the position marked before
856         ksSetCursor(ks, jump);
857 }
858  * @endcode
859  *
860  * @section restore Restoring state
861  *
862  * It can also be used to restore the state of a
863  * keyset in a function
864  *
865  * @code
866 int f (KeySet *ks)
867 {
868         cursor_t state = ksGetCursor(ks);
869
870         // work with keyset
871
872         // now bring the keyset to the state before
873         ksSetCursor (ks, state);
874 }
875  * @endcode
876  *
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
881  * not as efficient.
882  *
883  * An invalid cursor will be returned directly after
884  * ksRewind(). When you set an invalid cursor ksCurrent()
885  * is 0 and ksNext() == ksHead().
886  *
887  * @note Only use a cursor for the same keyset which it was
888  * made for.
889  *
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()
894  */
895 cursor_t ksGetCursor(const KeySet *ks)
896 {
897         if (!ks) return (cursor_t) -1;
898
899         if (ks->cursor == 0) return (cursor_t) -1;
900         else return (cursor_t) ks->current;
901 }
902
903
904
905
906 /**
907  * Set the KeySet internal cursor.
908  *
909  * Use it to set the cursor to a stored position.
910  * ksCurrent() will then be the position which you got with.
911  *
912  * @warning Cursors may get invalid when the key
913  * was ksPop()ed or ksLookup() was used together
914  * with KDB_O_POP.
915  *
916  * @code
917 cursor_t cursor;
918 ..
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
924  * @endcode
925  *
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().
929  *
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()
936  */
937 int ksSetCursor(KeySet *ks, cursor_t cursor)
938 {
939         if (!ks) return -1;
940
941         if ((cursor_t) -1 == cursor)
942         {
943                 ksRewind (ks);
944                 return 0;
945         }
946         ks->current= (size_t)cursor;
947         ks->cursor=ks->array[ks->current];
948         return 1;
949 }
950
951
952
953
954 /*
955  * Returns the previous Key in a KeySet.
956  *
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
959  * is returned.
960  *
961  * You'll get a NULL pointer if the key before begin of the KeySet was reached.
962  *
963  * Don't delete the key, use ksPop() if you want to delete it.
964  *
965  * @return the new current Key
966  * @see ksRewind(), ksCurrent()
967  *
968  */
969 static Key *ksPrev(KeySet *ks)
970 {
971         if (ks->size == 0) return 0;
972         if (ks->current <= 0)
973         {
974                 ksRewind (ks);
975                 return 0;
976         }
977         ks->current--;
978         return ks->cursor = ks->array[ks->current];
979 }
980
981
982
983
984 /******************************************* 
985  *    Looking up Keys inside KeySets       *
986  *******************************************/
987
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);
993
994         return strcmp(name1, name2);
995 }
996
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);
1002
1003         return kdbiStrCaseCmp(name1, name2);
1004 }
1005
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);
1012
1013         if (result == 0)
1014         {
1015                 const char *owner1 = keyOwner(key1);
1016                 const char *owner2 = keyOwner(key2);
1017                 return strcmp(owner1, owner2);
1018         }
1019         else return result;
1020 }
1021
1022
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);
1029
1030         if (result == 0)
1031         {
1032                 const char *owner1 = keyOwner(key1);
1033                 const char *owner2 = keyOwner(key2);
1034                 return kdbiStrCaseCmp(owner1, owner2);
1035         }
1036         else return result;
1037 }
1038
1039
1040 /**
1041  * Look for a Key contained in @p ks that matches the name of the @p key.
1042  *
1043  * @section Introduction
1044  *
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().
1049  *
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.
1054  *
1055  * @section Usage
1056  *
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
1060  * returned.
1061  *
1062  * Cascading is done if the first character is a /. This leads to ignoring
1063  * the prefix like system/ and user/.
1064  * @code
1065         if (kdbGet(handle, "user/myapp", myConfig, 0 ) == -1)
1066                 ErrorHandler ("Could not get Keys");
1067
1068         if (kdbGet(handle, "system/myapp", myConfig, 0 ) == -1)
1069                 ErrorHandler ("Could not get Keys");
1070
1071         if ((myKey = ksLookup(myConfig, key, 0)) == NULL)
1072                 ErrorHandler ("Could not Lookup Key");
1073  * @endcode
1074  *
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.
1078  *
1079  * @subsection KDB_O_NOALL
1080  *
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.
1085  *
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.
1088  *
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.
1092  *
1093  * @subsection KDB_O_POP
1094  *
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.
1098  *
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.
1102  *
1103  * @note Like in ksPop() the popped key always needs to be keyDel() afterwards, even
1104  * if it is appended to another keyset.
1105  *
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().
1108  *
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).
1112  *
1113  * You can solve this problem by using KDB_O_NOALL, risking you have to iterate n^2 instead of n.
1114  *
1115  * The more elegant way is to separate the keyset you use for ksLookup() and ksAppendKey():
1116  * @code
1117 int f(KeySet *iterator, KeySet *lookup)
1118 {
1119         KeySet *append = ksNew (ksGetSize(lookup), KS_END);
1120         Key *key;
1121         Key *current;
1122
1123         ksRewind(iterator);
1124         while (current=ksNext(iterator))
1125         {
1126                 key = ksLookup (lookup, current, KDB_O_POP);
1127                 // do something...
1128                 ksAppendKey(append, key); // now append it to append, not lookup!
1129                 keyDel (key); // make sure to ALWAYS delete poped keys.
1130         }
1131         ksAppend(lookup, append);
1132         // now lookup needs to be sorted only once, append never
1133         ksDel (append);
1134 }
1135  * @endcode
1136  *
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.
1146  *      - @p KDB_O_POP @n
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
1156  */
1157 Key *ksLookup(KeySet *ks, Key * key, option_t options)
1158 {
1159         Key *current;
1160         Key ** found;
1161         cursor_t cursor = 0;
1162         size_t jump = 0;
1163
1164         if (!ks) return 0;
1165
1166         jump = ks->rsize;
1167         cursor = ksGetCursor (ks);
1168
1169         if (options & KDB_O_SORT)
1170         {
1171                 ksSort (ks);
1172                 ksRewind (ks);
1173         }
1174         else if (!(options & KDB_O_NOALL) && ks->flags & KS_FLAG_DIRTY) ksSort(ks);
1175
1176         if (!key) return 0;
1177
1178         if (options & KDB_O_NOALL)
1179         {
1180                 while ((current=ksNext(ks)) != 0) {
1181                         if ((options & KDB_O_WITHOWNER) && (options & KDB_O_NOCASE))
1182                         {
1183                                 if (!keyCompareByNameOwnerCase(&key, &current)) break;
1184                         }
1185                         else if (options & KDB_O_WITHOWNER)
1186                         {
1187                                 if (!keyCompareByNameOwner(&key, &current)) break;
1188                         }
1189                         else if (options & KDB_O_NOCASE)
1190                         {
1191                                 if (!keyCompareByNameCase(&key, &current)) break;
1192                         }
1193                         else if (!keyCompareByName(&key, &current)) break;
1194                 }
1195                 if (options & KDB_O_DEL) keyDel (key);
1196                 if (current == 0) ksSetCursor (ks, cursor);
1197                 return current;
1198         } else {
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);
1208                 else
1209                         found = (Key **) bsearch (&key, ks->array+jump, ks->size-jump,
1210                                 sizeof (Key *), keyCompareByName);
1211                 if (options & KDB_O_DEL) keyDel (key);
1212                 if (found)
1213                 {
1214                         if (options & KDB_O_POP)
1215                         {
1216                                 Key * k = *found;
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)
1221                                 {
1222                                         ksPrev(ks);
1223                                 }
1224                                 else if (found == ks->array+ks->current)
1225                                 {
1226                                         ksRewind(ks);
1227                                 }
1228                                 return ksPop(ks);
1229                         } else {
1230                                 cursor = found-ks->array;
1231                                 ksSetCursor(ks, cursor);
1232                                 return (*found);
1233                         }
1234                 } else {
1235                         /*Reset Cursor to old position*/
1236                         ksSetCursor(ks, cursor);
1237                         return 0;
1238                 }
1239         }
1240 }
1241
1242 /**
1243  * Look for a Key contained in @p ks that matches @p name.
1244  *
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().
1249  *
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.
1254  *
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
1258  * returned.
1259  *
1260  * @section cascading Cascading
1261  *
1262  * Cascading is done if the first character is a /. This leads to ignoring
1263  * the prefix like system/ and user/.
1264  * @code
1265         if (kdbGetByName(handle, "/sw/myapp/current", myConfig, 0 ) == -1)
1266                 ErrorHandler ("Could not get Keys");
1267
1268         if ((myKey = ksLookupByName (myConfig, "/myapp/current/key", 0)) == NULL)
1269                 ErrorHandler ("Could not Lookup Key");
1270  * @endcode
1271  * 
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.
1275  *
1276  * @section fullsearch Full Search
1277  *
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.
1282  *
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.
1285  * 
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.
1295  *      - @p KDB_O_POP @n
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.
1300  *
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()
1306  */
1307 Key *ksLookupByName(KeySet *ks, const char *name, option_t options)
1308 {
1309         Key * key=0;
1310         Key * found=0;
1311         char * newname=0;
1312
1313         if (!ks) return 0;
1314         if (!name) return 0;
1315
1316         if (! ks->size) return 0;
1317
1318         if (name[0] == '/')
1319         {
1320                 /* Will be freed by second key */
1321                 newname = kdbiMalloc (strlen (name) + sizeof ("system") + 1);
1322                 if (!newname)
1323                 {
1324                         /*errno = KDB_ERR_NOMEM;*/
1325                         return 0;
1326                 }
1327                 strncpy (newname+4, "db",2);
1328                 strcpy  (newname+6, name);
1329                 key = keyNew (newname+4, KEY_END);
1330                 found = ksLookup(ks, key, options);
1331                 keyDel (key);
1332
1333                 if (!found)
1334                 {
1335                         strncpy (newname+2, "file",4);
1336                         key = keyNew (newname+2, KEY_END);
1337                         found = ksLookup(ks, key, options);
1338                         keyDel (key);
1339                 }
1340
1341                 if (!found)
1342                 {
1343                         strncpy (newname, "memory",6);
1344                         key = keyNew (newname, KEY_END);
1345                         found = ksLookup(ks, key, options);
1346                         keyDel (key);
1347                 }
1348
1349                 kdbiFree (newname);
1350                 return found;
1351         } else {
1352                 key = keyNew (name, KEY_END);
1353                 if (!key) return 0;
1354                 found = ksLookup(ks, key, options);
1355                 keyDel (key);
1356                 return found;
1357         }
1358 }
1359
1360
1361 /*
1362  * Lookup for a Key contained in @p ks KeySet that matches @p value,
1363  * starting from ks' ksNext() position.
1364  *
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
1368  * returned.
1369  *
1370  * This method skips binary keys.
1371  *
1372  * @par Example:
1373  * @code
1374 ksRewind(ks);
1375 while (key=ksLookupByString(ks,"my value",0)) {
1376         // show all keys which value="my value"
1377         keyToStream(key,stdout,0);
1378 }
1379  * @endcode
1380  *
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()
1395  */
1396 Key *ksLookupByString(KeySet *ks, const char *value, option_t options)
1397 {
1398         cursor_t init=0;
1399         Key *current=0;
1400
1401         if (!ks) return 0;
1402
1403         if (options & KDB_O_SORT)
1404         {
1405                 ksSort (ks);
1406                 ksRewind (ks);
1407         }
1408         else if (!(options & KDB_O_NOALL) && ks->flags & KS_FLAG_DIRTY) ksSort(ks);
1409
1410         if (!(options & KDB_O_NOALL))
1411         {
1412                 ksRewind (ks);
1413                 init=ksGetCursor(ks);
1414         }
1415
1416         if (!value) return 0;
1417
1418         while ((current=ksNext(ks)) != 0)
1419         {
1420                 if (!keyIsString(current)) continue;
1421
1422                 /*fprintf (stderr, "Compare %s with %s\n", keyValue(current), value);*/
1423
1424                 if ((options & KDB_O_NOCASE) && 
1425                         !kdbiStrCaseCmp(keyValue(current),value)) break;
1426                 else if (!strcmp(keyValue(current),value)) break;
1427         }
1428
1429         /* reached end of KeySet */
1430         if (!(options & KDB_O_NOALL))
1431         {
1432                 ksSetCursor (ks, init);
1433         }
1434
1435         return current;
1436 }
1437
1438
1439
1440 /*
1441  * Lookup for a Key contained in @p ks KeySet that matches the binary @p value,
1442  * starting from ks' ksNext() position.
1443  *
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.
1448  *
1449  * This method skips string keys.
1450  *
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()
1465  */
1466 Key *ksLookupByBinary(KeySet *ks, const void *value, size_t size,
1467                 option_t options)
1468 {
1469         cursor_t init=0;
1470         Key *current=0;
1471
1472         if (!ks) return 0;
1473
1474         if (options & KDB_O_SORT)
1475         {
1476                 ksSort (ks);
1477                 ksRewind (ks);
1478         }
1479         else if (!(options & KDB_O_NOALL) && ks->flags & KS_FLAG_DIRTY) ksSort(ks);
1480
1481         if (!(options & KDB_O_NOALL))
1482         {
1483                 ksRewind (ks);
1484                 init=ksGetCursor(ks);
1485         }
1486
1487         while ((current=ksNext(ks)))
1488         {
1489                 if (!keyIsBinary(current)) continue;
1490
1491                 if (size != current->dataSize) continue;
1492
1493                 if (!value)
1494                 {
1495                         if (!current->data) break;
1496                         else continue;
1497                 }
1498
1499                 if (current->data && 
1500                         !memcmp(current->data,value,size)) break;
1501         }
1502
1503         /* reached end of KeySet */
1504         if (!(options & KDB_O_NOALL))
1505         {
1506                 ksSetCursor (ks, init);
1507         }
1508
1509         return 0;
1510 }
1511
1512
1513
1514 /******************************************* 
1515  *    Other operations                     *
1516  *******************************************/
1517
1518
1519
1520
1521 /*
1522  * Calculates the common parent to all keys in @p ks.
1523  *
1524  * This is a c-helper function, you need not implement it in bindings.
1525  *
1526  * Given the @p ks KeySet, calculates the parent name for all the keys.
1527  * So if @p ks contains this keys:
1528  *
1529  * @code
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
1534  * @endcode
1535  *
1536  * The common parent is @p system/sw/xorg .
1537  *
1538  * On the other hand, if we have this KeySet:
1539  *
1540  * @code
1541  *   system/some/thing
1542  *   system/other/thing
1543  *   user/unique/thing
1544  * @endcode
1545  *
1546  * No common parent is possible, so @p returnedCommonParent will contain nothing.
1547  *
1548  * This method will work correctly only on @link ksSort() sorted KeySets @endlink.
1549  *
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.
1556  */
1557 ssize_t ksGetCommonParentName(const KeySet *working,char *returnedCommonParent, size_t maxSize) {
1558         size_t parentSize=0;
1559         Key *current=0;
1560         cursor_t init;
1561         KeySet *ks;
1562
1563         init = ksGetCursor (working);
1564         ks = (KeySet *) working;
1565
1566         if (ks->size < 1) return 0;
1567
1568         ksRewind(ks);
1569         current = ksNext(ks);
1570         if (keyGetNameSize(current) > maxSize) {
1571                 /*errno=KDB_ERR_TRUNC;*/
1572                 returnedCommonParent[0]=0;
1573                 return -1;
1574         }
1575
1576         strcpy(returnedCommonParent,keyName(current));
1577         parentSize=kdbiStrLen(returnedCommonParent);
1578
1579         while (*returnedCommonParent) {
1580                 ksRewind(ks);
1581                 while ((current = ksNext(ks)) != 0) {
1582                         /* Test if a key doesn't match */
1583                         if (memcmp(returnedCommonParent,keyName(current),parentSize-1)) break;
1584                 }
1585                 if (current) {
1586                         /* some key failed to be a child */
1587                         /* parent will be the parent of current parent... */
1588                         char *delim=0;
1589
1590                         if ((delim=strrchr(returnedCommonParent,PATH_SEPARATOR))) {
1591                                 *delim=0;
1592                                 parentSize=kdbiStrLen(returnedCommonParent);
1593                         } else {
1594                                 *returnedCommonParent=0;
1595                                 parentSize=0;
1596                                 break; /* Better don't make comparision with parentSize-1 now */
1597                         }
1598                 } else {
1599                         /* All keys matched (current==0) */
1600                         /* We have our common parent to return in commonParent */
1601                         ksSetCursor (ks, init );
1602                         return parentSize;
1603                 }
1604         }
1605         ksSetCursor (ks, init );
1606         return parentSize; /* if reached, will be zero */
1607 }
1608
1609
1610
1611 /*********************************************************************
1612  *                Data constructors (protected)                      *
1613  *********************************************************************/
1614
1615
1616 /*
1617  * Resize keyset.
1618  *
1619  * For internal useage only.
1620  *
1621  * Don't use that function to be portable. You can give an hint
1622  * how large the keyset should be in ksNew().
1623  *
1624  * Subsequent is the description of the implementation with array.
1625  * ksResize() enlarge or shrink the internal array to wished
1626  * size alloc.
1627  *
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.
1631  *
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
1638  */
1639 int ksResize (KeySet *ks, size_t alloc)
1640 {
1641         if (alloc == ks->alloc) return 1;
1642         if (alloc < ks->size) return 0;
1643         if (alloc < KEYSET_SIZE)
1644         {
1645                 if (ks->alloc != KEYSET_SIZE) alloc = KEYSET_SIZE;
1646                 else return 0;
1647         }
1648
1649         if (ks->array == NULL)
1650         {       /* Not allocated up to now */
1651                 ks->alloc = alloc;
1652                 ks->size = 0;
1653                 ks->array = kdbiMalloc (sizeof(struct _Key *) * ks->alloc);
1654                 if (!ks->array)
1655                 {
1656                         /*errno = KDB_ERR_NOMEM;*/
1657                         return -1;
1658                 }
1659         }
1660
1661 #if DEBUG && VERBOSE
1662         printf ("Resize from %d to %d\n",(int) ks->alloc,(int) alloc);
1663 #endif
1664         ks->alloc=alloc;
1665
1666
1667         if (kdbiRealloc((void**) &ks->array, sizeof(struct _Key *) * ks->alloc) == -1)
1668         {
1669 #if DEBUG
1670                 fprintf (stderr, "Reallocation error\n");
1671 #endif
1672                 kdbiFree (ks->array);
1673                 ks->array = 0;
1674                 /*errno = KDB_ERR_NOMEM;*/
1675                 return -1;
1676         }
1677
1678         return 1;
1679 }
1680
1681 /*
1682  * Returns current allocation size.
1683  *
1684  * @param ks the keyset object to work with
1685  * @return allocated size*/
1686 size_t ksGetAlloc (const KeySet *ks)
1687 {
1688         return ks->alloc;
1689 }
1690
1691
1692
1693 /*
1694  * KeySet object initializer.
1695  *
1696  * You should always use ksNew() instead of ksInit().
1697  *
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().
1701  * 
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
1705  */
1706 int ksInit(KeySet *ks) {
1707         ks->array = 0;
1708         ks->flags = KS_FLAG_DIRTY;
1709
1710         ks->size=0;
1711         ks->rsize=0;
1712         ks->alloc=0;
1713
1714         ksRewind(ks);
1715
1716         return 1;
1717 }
1718
1719
1720 /*
1721  * KeySet object initializer.
1722  *
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
1726  */
1727 int ksClose(KeySet *ks)
1728 {
1729         Key * k;
1730
1731         ksRewind(ks);
1732         while ((k = ksNext(ks)) != 0)
1733         {
1734                 keyDecRef (k);
1735                 keyDel (k);
1736         }
1737
1738         if (ks->array) kdbiFree (ks->array);
1739         ks->array = 0;
1740         ks->alloc = 0;
1741
1742         ks->size = 0;
1743         ks->rsize= 0;
1744
1745         return 0;
1746 }
1747
1748
1749 /**
1750  * @}
1751  */
1752