Git init
[pkgs/e/elektra.git] / src / libelektratools / stream.c
1 /***************************************************************************
2                  stream.c  -  Streaming Methods
3                              -------------------
4     begin                : Sat Nov 23 2007
5     copyright            : (C) 2007 by Markus Raab
6     email                : elektra@markus-raab.org
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 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif
19
20 #ifdef HAVE_UNISTD_H
21 #include <unistd.h>
22 #else
23 #error need unistd for getuid and getgid
24 #endif
25
26 #ifdef HAVE_STDIO_H
27 #include <stdio.h>
28 #endif
29
30 #ifdef HAVE_STRING_H
31 #include <string.h>
32 #endif
33
34 #ifdef HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37
38 #ifdef HAVE_TIME_H
39 #include <time.h>
40 #endif
41
42 #include <kdbtools.h>
43 #include <kdbbackend.h>
44
45 #ifdef ELEKTRA_STATIC
46
47 #define ksToStream libelektratools_LTX_ksToStream
48 #define ksOutput libelektratools_LTX_ksOutput
49 #define ksGenerate libelektratools_LTX_ksGenerate
50 #define keyToStream libelektratools_LTX_keyToStream
51 #define keyOutput libelektratools_LTX_keyOutput
52 #define keyGenerate libelektratools_LTX_keyGenerate
53
54 #endif /* ELEKTRA_STATIC */
55
56
57
58 /**
59  * @defgroup stream Streaming
60  * @brief Methods to output, generate and toXML Keys and Keysets.
61  *
62  * Here are some functions that are in a separate library because they
63  * depend on non-basic libraries as libxml. Link against kdbtools library if your
64  * program won't be installed in /bin, or is not essential in early boot
65  * stages.
66  *
67  * It is also possible to have a dynamic linkage, see the
68  * sourcecode from kdb-tool or testing framework how to achieve
69  * that.
70  *
71  * Output prints keys line per line, meaned to be read by humans.
72  * - keyOutput()
73  * - ksOutput()
74  *
75  * Generate prints keys and keysets as C-Structs, meaned to be
76  * read by a C-Compiler.
77  * - keyGenerate()
78  * - ksGenerate()
79  *
80  * toXML prints keys and keysets as XML, meaned to be used
81  * as exchange format.
82  * - keyToStream()
83  * - ksToStream()
84  *
85  * To use them:
86  * @code
87 #include <kdbtools.h>
88  * @endcode
89  *
90  *
91  */
92
93
94
95
96
97
98 /*********************************************
99  *    Textual XML methods                    *
100  *********************************************/
101
102
103 /**
104  * Prints an XML representation of the key.
105  *
106  * String generated is of the form:
107  * @verbatim
108         <key name="system/sw/xorg/Monitor/Monitor0/Name"
109                 type="string" uid="root" gid="root" mode="0660">
110
111                 <value>Samsung TFT panel</value>
112                 <comment>My monitor</comment>
113         </key>@endverbatim
114
115
116
117  * @verbatim
118         <key parent="system/sw/xorg/Monitor/Monitor0" basename="Name"
119                 type="string" uid="root" gid="root" mode="0660">
120
121                 <value>Samsung TFT panel</value>
122                 <comment>My monitor</comment>
123         </key>@endverbatim
124  *
125  * @param key the key object to work with
126  * @param stream where to write output: a file or stdout
127  * @param options Some #option_t ORed:
128  * - @p option_t::KDB_O_NUMBERS \n
129  *   Do not convert UID and GID into user and group names
130  * - @p option_t::KDB_O_CONDENSED \n
131  *   Less human readable, more condensed output
132  * - @p option_t::KDB_O_FULLNAME \n
133  *   The @p user keys are exported with their full names (including
134  *   user domains)
135  *
136  * @see ksToStream()
137  * @return number of bytes written to output
138  * @ingroup stream
139  */
140 ssize_t keyToStream(const Key *key, FILE* stream, option_t options)
141 {
142         return keyToStreamBasename(key,stream,0,0,options);
143 }
144
145
146
147
148
149 /**
150  * Same as keyToStream() but tries to strip @p parentSize bytes from
151  * @p key name if it matches @p parent .
152  *
153  * Taking the example from keyToStream(), if @p parent is
154  * @c "system/sw/xorg", the generated string is of the form:
155  * @verbatim
156         <key basename="Monitor/Monitor0/Name"
157                 type="string" uid="root" gid="root" mode="0660">
158
159                 <value>Samsung TFT panel</value>
160                 <comment>My monitor</comment>
161         </key>@endverbatim
162  *
163  * It usefull to produce more human readable XML output of a key when
164  * it is being represented in a context that defines the parent key name.
165  * For example:
166  *
167  * @verbatim
168         <keyset parent="user/sw">
169                 <key basename="kdbedit"..../>
170                 <key basename="phototools"..../>
171                 <key basename="myapp"..../>
172         </keyset>@endverbatim
173  *
174  * In the bove example, each @p @<key@> entry was generated by a call to 
175  * keyToStreamBasename() having @c "user/sw" as @p parent .
176  * 
177  * This method is used when ksToStream() is called with
178  * KDBOption::KDB_O_HIER option.
179  *
180  * @param key the key object to work with
181  * @param stream the FILE where to send the stream
182  * @param parentSize the maximum size of @p parent that will be used.
183  *        If 0, the entire @p parent will be used.
184  * @param parent the string (or part of it, defined by @p parentSize ) that
185  *        will be used to strip from the key name.
186  * @param options Some #option_t ORed:
187  * - @p option_t::KDB_O_NUMBERS \n
188  *   Do not convert UID and GID into user and group names
189  * - @p option_t::KDB_O_CONDENSED \n
190  *   Less human readable, more condensed output
191  * - @p option_t::KDB_O_FULLNAME \n
192  *   The @p user keys are exported with their full names (including
193  *   user domains)
194  *
195  * @return number of bytes written to output
196  * @ingroup stream
197  */
198 ssize_t keyToStreamBasename(const Key *key, FILE *stream, const char *parent,
199                 const size_t parentSize, option_t options) {
200         ssize_t written=0;
201         char buffer[MAX_PATH_LENGTH];
202
203         uid_t uid = getuid();
204         gid_t gid = getgid();
205
206         /* Write key name */
207         if (parent) {
208                 /* some logic to see if we should print only the relative basename */
209                 int found;
210                 size_t skip=parentSize ? parentSize : kdbiStrLen(parent)-1;
211
212                 found=memcmp(parent,key->key,skip);
213                 if (found == 0) {
214                         while (*(key->key+skip) == PATH_SEPARATOR) ++skip;
215
216                         if (*(key->key+skip) != 0) /* we don't want a null basename */
217                                 written+=fprintf(stream,"<key basename=\"%s\"",
218                                         key->key+skip);
219                 }
220         }
221
222         if (written == 0) { /* no "<key basename=..." was written so far */
223                 if (options & KDB_O_FULLNAME) {
224                         keyGetFullName(key,buffer,sizeof(buffer));
225                         written+=fprintf(stream,"<key name=\"%s\"", buffer);
226                 } else written+=fprintf(stream,"<key name=\"%s\"", key->key);
227         }
228
229
230         if (options & KDB_O_CONDENSED) written+=fprintf(stream," ");
231         else written+=fprintf(stream,"\n       ");
232
233
234
235         /* Key type
236         TODO: xml schema does not output type
237         if (options & KDB_O_NUMBERS) {
238                 written+=fprintf(stream," type=\"%d\"", key->type);
239         } else {
240                 buffer[0]=0;
241
242                 if (key->type & KEY_TYPE_DIR) written+=fprintf(stream, " isdir=\"yes\"");
243                 if (key->type & KEY_TYPE_REMOVE) written+=fprintf(stream, " isremove=\"yes\"");
244                 if (key->type & KEY_TYPE_BINARY) written+=fprintf(stream, " isbinary=\"yes\"");
245         }
246         */
247
248         if (keyGetUID (key) != uid) written+=fprintf(stream," uid=\"%d\"", (int)keyGetUID (key));
249         if (keyGetGID (key) != gid) written+=fprintf(stream," gid=\"%d\"", (int)keyGetGID (key));
250
251 #if defined(S_IRWXU) && defined(S_IRWXG) && defined(S_IRWXO)
252         written+=fprintf(stream," mode=\"0%o\"",
253                 key->mode & (S_IRWXU|S_IRWXG|S_IRWXO));
254 #else
255         written+=fprintf(stream," mode=\"0%o\"",
256                 key->mode);
257 #endif
258
259
260         if (!key->data && !key->comment) { /* no data AND no comment */
261                 written+=fprintf(stream,"/>");
262                 if (!(options & KDB_O_CONDENSED))
263                         written+=fprintf(stream,"\n\n");
264                 
265                 return written; /* end of <key/> */
266         } else {
267                 if (key->data) {
268                         if ((key->dataSize <= 16) && keyIsString (key) && /*TODO: is this for string?*/
269                                         !strchr(key->data,'\n')) {
270
271                                 /* we'll use a "value" attribute instead of a <value> node,
272                                    for readability, so the cut size will be 16, which is
273                                    the maximum size of an IPv4 address */
274
275                                 if (options & KDB_O_CONDENSED) written+=fprintf(stream," ");
276                                 else written+=fprintf(stream,"\n\t");
277                                 
278                                 written+=fprintf(stream,"value=\"%s\"",(char *)key->data);
279                                 
280                                 if (key->comment) written+=fprintf(stream,">\n");
281                                 else {
282                                         written+=fprintf(stream,"/>");
283                                         if (!(options & KDB_O_CONDENSED))
284                                                 written+=fprintf(stream,"\n");
285                                 
286                                         return written;
287                                 }
288                         } else { /* value is bigger than 16 bytes: deserves own <value> */
289                                 written+=fprintf(stream,">");
290                                 if (!(options & KDB_O_CONDENSED)) written+=fprintf(stream,"\n\n     ");
291                                 
292                                 written+=fprintf(stream,"<value>");
293                                 if (keyIsString(key)) { /*TODO: is this for string?*/
294                                         written+=fprintf(stream,"<![CDATA[");
295                                         fflush(stream);
296                                         /* must chop ending \\0 */
297                                         written+=fwrite(key->data,sizeof(char),key->dataSize-1,stream);
298                                         written+=fprintf(stream,"]]>");
299                                 } else {
300                                         /* Binary values */
301                                         char *encoded=malloc(3*key->dataSize);
302                                         size_t encodedSize;
303
304                                         written+=fprintf(stream,"\n");
305                                         encodedSize=kdbbEncode(key->data,key->dataSize,encoded);
306                                         fflush(stream);
307                                         written+=fwrite(encoded,sizeof(char),encodedSize,stream);
308                                         free(encoded);
309                                         written+=fprintf(stream,"\n");
310                                 }
311                                 /* fflush(stream); */
312                                 written+=fprintf(stream,"</value>");
313                         }
314                 } else { /* we have no data */
315                         if (key->comment) {
316                                 written+=fprintf(stream,">");
317                                 if (!(options & KDB_O_CONDENSED))
318                                         written+=fprintf(stream,"\n");
319                         } else {
320                                 written+=fprintf(stream,"/>");
321                                 if (!(options & KDB_O_CONDENSED))
322                                         written+=fprintf(stream,"\n\n");
323                         
324                                 return written;
325                         }
326                 }
327         }
328
329         if (!(options & KDB_O_CONDENSED)) {
330                 written+=fprintf(stream,"\n");
331                 if (key->comment) written+=fprintf(stream,"     ");
332         }
333
334         if (key->comment) {
335                 written+=fprintf(stream,"<comment><![CDATA[%s]]></comment>", key->comment);
336                 if (!(options & KDB_O_CONDENSED))
337                         written+=fprintf(stream,"\n");
338         }
339
340         written+=fprintf(stream,"</key>");
341
342         if (!(options & KDB_O_CONDENSED))
343                 written+=fprintf(stream,"\n\n");
344
345         return written;
346 }
347
348 /**
349  * Writes to @p stream an XML version of the @p ks object.
350  *
351  * String generated is of the form:
352  * @verbatim
353 <keyset>
354 <key name=...>...</key>
355 <key name=...>...</key>
356 <key name=...>...</key>
357
358 </keyset>
359  * @endverbatim
360  *
361  * or if KDB_O_HIER is used, the form will be:
362  * @verbatim
363 <keyset parent="user/smallest/parent/name">
364
365 <key basename=...>...</key>
366 <key name=...>...</key> <!-- a key thats not under this keyset's parent -->
367 <key basename=...>...</key>
368
369 </keyset>
370  * @endverbatim
371  *
372  * KDB_O_HEADER will additionally generate a header like:
373  * @verbatim
374 <?xml version="1.0" encoding="UTF-8"?>
375 <!-- Generated by Elektra API. Total of n keys. -->
376 <keyset xmlns="http://www.libelektra.org"
377         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
378         xsi:schemaLocation="http://www.libelektra.org elektra.xsd">
379  * @endverbatim
380  *
381  * @param ks the KeySet to serialize
382  * @param stream where to write output: a file or stdout
383  * @param options accepted #option_t ORed:
384  * - @p option_t::KDB_O_NUMBERS \n
385  *   Do not convert UID and GID into user and group names.
386  * - @p option_t::KDB_O_FULLNAME \n
387  *   The @c user keys are exported with their full names (including
388  *   user domains)
389  * - @p option_t::KDB_O_CONDENSED \n
390  *   Less human readable, more condensed output.
391  * - @p option_t::KDB_O_XMLHEADERS \n
392  *   Exclude the correct XML headers in the output. If not used, the
393  *   &lt;?xml?&gt; and schema info inside the &lt;keyset&gt; object will not be generated.
394  * - @p option_t::KDB_O_HIER \n
395  *   Will generate a &lt;keyset&gt; node containing a @c parent attribute, and
396  *   &lt;key&gt; nodes with a @c basename relative to that @c parent. The @c parent
397  *   is calculated by taking the smallest key name in the keyset, so it is a
398  *   good idea to have only related keys on the keyset. Otherwise, a valid
399  *   consistent XML document still will be generated with regular absolute
400  *   @c name attribute for the &lt;key&gt; nodes, due to a
401  *   clever keyToStreamBasename() implementation.
402  *
403  * @see keyToStream()
404  * @see commandList() for usage example
405  * @return number of bytes written to output, or -1 if some error occurs
406  * @ingroup stream
407  * @param ks The keyset to output
408  * @param stream the file pointer where to send the stream
409  * @param options see above text
410  */
411 ssize_t ksToStream(const KeySet *ks, FILE* stream, option_t options) {
412         size_t written=0;
413         Key *key=0;
414         char *codeset = "UTF-8";
415         KeySet *cks = ksDup (ks);
416
417         if (ksNeedSort(cks)) ksSort (cks);
418         ksRewind (cks);
419
420         if (options & KDB_O_HEADER) {
421                 written+=fprintf(stream,"<?xml version=\"1.0\" encoding=\"%s\"?>",
422                         codeset);
423                 if (~options & KDB_O_CONDENSED)
424                         written+=fprintf(stream,
425                                         "\n<!-- Generated by Elektra API. Total of %d keys. -->\n",(int)cks->size);
426                 if (~options & KDB_O_CONDENSED)
427                         written+=fprintf(stream,"<keyset xmlns=\"http://www.libelektra.org\"\n"
428                                         "\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
429                                         "\txsi:schemaLocation=\"http://www.libelektra.org elektra.xsd\"\n");
430                 else
431                         written+=fprintf(stream,"<keyset xmlns=\"http://www.libelektra.org\""
432                                         " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
433                                         " xsi:schemaLocation=\"http://www.libelektra.org elektra.xsd\"");
434         } else written+=fprintf(stream,"<keyset");
435
436         if (options & KDB_O_HIER) {
437                 char commonParent[MAX_PATH_LENGTH];
438
439                 ksGetCommonParentName(cks,commonParent,sizeof(commonParent));
440         
441                 if (commonParent[0]) {
442                         written+=fprintf(stream,"        parent=\"%s\">\n",
443                                 commonParent);
444                         ksRewind (cks);
445                         while ((key=ksNext (cks)) != 0)
446                                 written+=keyToStreamBasename(key,stream,commonParent,0,options);
447                 } else {
448                         written+=fprintf(stream,">\n");
449                         ksRewind (cks);
450                         while ((key=ksNext (cks)) != 0)
451                                 written+=keyToStream(key,stream,options);
452                 }
453         } else { /* No KDB_O_HIER*/
454                 written+=fprintf(stream,">\n");
455                 ksRewind (cks);
456                 while ((key=ksNext (cks)) != 0)
457                         written+=keyToStream(key,stream,options);
458         }
459         
460         written+=fprintf(stream,"</keyset>\n");
461         ksDel (cks);
462         return written;
463 }
464
465 /**
466  * Output every information of a single key depending on options.
467  *
468  * The format is not very strict and only intend to be read
469  * by human eyes for debugging purposes. Don't rely on the
470  * format in your applications.
471  *
472  * @param k the key object to work with
473  * @param stream the file pointer where to send the stream
474  * @param options see text above
475  * @see ksOutput()
476  * @return 1 on success
477  * @return -1 on allocation errors
478  * @ingroup stream
479  */
480 int keyOutput (const Key * k, FILE *stream, option_t options)
481 {
482         time_t t;
483         size_t s;
484         char * tmc;
485         char * str;
486
487         size_t c;
488         char * com;
489
490         size_t n;
491         char * nam;
492
493         n = keyGetNameSize (k);
494         if (n>1)
495         {
496                 nam = (char*) malloc (n);
497                 if (nam == NULL) return -1;
498                 keyGetName (k, nam, n);
499
500                 fprintf(stream,"Name[%d]: %s : ", (int)n, nam);
501
502                 free (nam);
503         }
504
505         s = keyGetValueSize (k);
506         if (options & KEY_VALUE && s>1)
507         {
508                 str = (char*) malloc (s);
509                 if (str == NULL) return -1;
510                 if (keyIsBinary(k))
511                 {
512                         /*
513                         char * bin;
514                         bin = (char*) malloc (s*3+1);
515                         keyGetBinary(k, str, s);
516                         kdbbEncode (str, s, bin);
517                         free (bin);
518                         */
519                         keyGetBinary (k, str, s);
520                         fprintf(stream,"Binary[%d]: %s : ", (int)s, str);
521                 } else {
522                         keyGetString (k, str, s);
523                         fprintf(stream,"String[%d]: %s : ", (int)s, str);
524                 }
525
526                 free (str);
527         }
528
529         c = keyGetCommentSize (k);
530         if (options & KEY_COMMENT && c>1)
531         {
532                 com = (char*) malloc (c);
533                 if (com == NULL) return -1;
534                 keyGetComment (k, com, c);
535
536                 fprintf(stream,"Comment[%d]: %s : ", (int)c, com);
537
538                 free (com);
539         }
540
541
542         if (options & KDB_O_SHOWMETA) fprintf(stream," : ");
543         if (options & KEY_TYPE) fprintf(stream,"Type: %d : ", keyGetType (k));
544         if (options & KEY_UID) fprintf(stream,"UID: %d : ", (int)keyGetUID (k));
545         if (options & KEY_GID) fprintf(stream,"GID: %d : ", (int)keyGetGID (k));
546         if (options & KEY_MODE) fprintf(stream,"Mode: %o : ", (int)keyGetMode (k));
547
548         if (options & KEY_ATIME)
549         {
550                 t=keyGetATime(k);
551                 tmc = ctime (& t);
552                 tmc[24] = '\0';
553                 fprintf(stream,"ATime: %s : ", tmc);
554         }
555
556         if (options & KEY_MTIME)
557         {
558                 t=keyGetMTime(k);
559                 tmc = ctime (& t);
560                 tmc[24] = '\0';
561                 fprintf(stream,"MTime: %s : ", tmc);
562         }
563
564         if (options & KEY_CTIME)
565         {
566                 t=keyGetCTime(k);
567                 tmc = ctime (& t);
568                 tmc[24] = '\0';
569                 fprintf(stream,"CTime: %s : ", tmc);
570         }
571
572         if (options & KDB_O_SHOWFLAGS)
573         {
574                 if (!(options & KDB_O_SHOWMETA)) fprintf(stream, " ");
575                 fprintf (stream,"Flags: ");
576                 if (keyIsBinary(k)) fprintf(stream,"b");
577                 if (keyIsString(k)) fprintf(stream,"s");
578                 if (keyIsDir(k)) fprintf(stream,"d");
579                 if (keyIsInactive(k)) fprintf(stream,"i");
580                 if (keyNeedRemove(k)) fprintf(stream,"r");
581                 if (keyNeedSync(k)) fprintf(stream,"s");
582         }
583
584         fprintf(stream,"\n");
585         return 1;
586 }
587
588
589 /**
590  * Output all information of a keyset.
591  *
592  * The format is not very strict and only intend to be read
593  * by human eyes for debugging purposes. Don't rely on the
594  * format in your applications.
595  *
596  * Keys are printed line per line with keyOutput().
597  *
598  * The same options as keyOutput() are taken and passed
599  * to them.
600  *
601  * Additional KDB_O_HEADER will print the number of keys
602  * as first line.
603  *
604  * @param ks the keyset to work with
605  * @param stream the file pointer where to send the stream
606  * @param options
607  * @see keyOutput()
608  * @return 1 on success
609  * @return -1 on allocation errors
610  * @ingroup stream
611  */
612 int ksOutput(const KeySet *ks, FILE *stream, option_t options)
613 {
614         Key     *key;
615         KeySet *cks = ksDup (ks);
616         size_t size = 0;
617
618         if (ksNeedSort(cks)) ksSort (cks);
619         ksRewind (cks);
620
621         if (KDB_O_HEADER & options) {
622                 fprintf(stream,"Output keyset of size %d\n", (int)ksGetSize(cks)); 
623         }
624         while ( (key = ksNext(cks)) != NULL)
625         {
626                 if (options & KDB_O_SHOWINDICES) fprintf(stream, "[%d] ", (int)size);
627                 keyOutput (key,stream,options);
628                 size ++;
629         }
630
631         ksDel (cks);
632         return 1;
633 }
634
635 /**
636  * Generate a C-Style key and stream it.
637  *
638  * This keyset can be used to include as c-code for
639  * applikations using elektra.
640  *
641  * @param key the key object to work with
642  * @param stream the file pointer where to send the stream
643  * @param options KDB_O_SHOWINDICES, KDB_O_IGNORE_COMMENT, KDB_O_SHOWINFO
644  * @return 1 on success
645  * @ingroup stream
646  */
647 int keyGenerate(const Key * key, FILE *stream, option_t options)
648 {
649         size_t s;
650         char * str;
651
652         size_t c;
653         char * com;
654
655         size_t n;
656         char * nam;
657
658         n = keyGetNameSize (key);
659         if (n>1)
660         {
661                 nam = (char*) malloc (n);
662                 if (nam == NULL) return -1;
663                 keyGetName (key, nam, n);
664                 fprintf(stream,"\n\tkeyNew (\"%s\"", nam);
665                 free (nam);
666         }
667
668         if (keyIsDir(key)) fprintf(stream,"\n\t\t, KEY_DIR");
669
670         s = keyGetValueSize (key);
671         if (s>1)
672         {
673                 str = (char*) malloc (s);
674                 if (str == NULL) return -1;
675                 if (keyIsBinary(key)) keyGetBinary(key, str, s);
676                 else keyGetString (key, str, s);
677                 fprintf(stream,"\n\t\t, KEY_VALUE, \"%s\"", str);
678                 free (str);
679         }
680
681         c = keyGetCommentSize (key);
682         if (c>1)
683         {
684                 com = (char*) malloc (c);
685                 if (com == NULL) return -1;
686                 keyGetComment (key, com, c);
687                 fprintf(stream,"\n\t\t, KEY_COMMENT, \"%s\"", com);
688                 free (com);
689         }
690
691         if (keyGetType(key) == KEY_TYPE_BINARY) fprintf(stream,"\n\t\t, KEY_TYPE, KEY_TYPE_BINARY");
692         else if (keyGetType(key) == KEY_TYPE_STRING) fprintf(stream,"\n\t\t, KEY_TYPE, KEY_TYPE_STRING");
693         else fprintf(stream,"\n\t\t, KEY_TYPE, %d", keyGetType(key));
694
695         // if (keyIsInactive(key)) fprintf(stream,"inactive");
696
697         // if (keyIsSystem(key)) fprintf(stream,"system");
698         // if (keyIsUser(key)) fprintf(stream,"user");
699
700         if (keyNeedRemove(key)) fprintf(stream, "\n\t\t, KEY_REMOVE");
701         if (keyNeedStat(key)) fprintf(stream, "\n\t\t, KEY_STAT");
702
703         if (! (keyGetMode(key) == 0664 || (keyGetMode(key) == 0775 && keyIsDir(key))))
704         {
705                 fprintf(stream,"\n\t\t, KEY_MODE, 0%3o", keyGetMode(key));
706         }
707
708         fprintf(stream,"\n\t, KEY_END)");
709
710         if (options == 0) return 1; /* dummy to make icc happy */
711         return 1;
712 }
713
714
715 /**
716  * Generate a C-Style keyset and stream it.
717  *
718  * This keyset can be used to include as c-code for
719  * applikations using elektra.
720  *
721  * The options takes the same options as kdbGet()
722  * and kdbSet().
723  *
724  * @param ks the keyset to work with
725  * @param stream the file pointer where to send the stream
726  * @param options which keys not to output
727  * @return 1 on success
728  * @ingroup stream
729  */
730 int ksGenerate (const KeySet *ks, FILE *stream, option_t options)
731 {
732         Key     *key;
733         size_t  s = 0;
734         KeySet *cks = ksDup (ks);
735
736         if (ksNeedSort(cks)) ksSort (cks);
737         ksRewind (cks);
738
739         fprintf(stream,"ksNew( %d ,", (int)ksGetSize(cks)+10);
740         while ((key=ksNext(cks)) != 0)
741         {
742                 if (options & KDB_O_NODIR) if (key && keyIsDir (key)) continue;
743                 if (options & KDB_O_DIRONLY) if (key && !keyIsDir (key)) continue;
744                 if (options & KDB_O_INACTIVE) if (key && keyIsInactive (key)) continue;
745                 if (options & KDB_O_STATONLY)
746                 {
747                         keySetRaw (key, "", 0);
748                         keySetComment (key, "");
749                 }
750
751                 s++;
752
753                 keyGenerate(key, stream, options);
754                 fprintf(stream,",");
755         }
756         fprintf(stream,"KS_END);\n"); 
757
758         ksDel (cks);
759         return 1;
760 }
761