Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Source for c plugin
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : *
8 : */
9 :
10 : #include "c.h"
11 :
12 : #include <kdberrors.h>
13 : #include <kdbhelper.h>
14 :
15 : #include <ctype.h>
16 : #include <stdio.h>
17 :
18 : static const char * toEscape = "\"'\\?\n\r\t";
19 : static const char * escapes = "\"'\\?nrt";
20 :
21 : static const char * hex = "0123456789abcdef";
22 :
23 1106 : static char * escapeString (char ** str)
24 : {
25 1106 : size_t size = 0;
26 9304 : for (char * cur = *str; *cur != '\0'; ++cur)
27 : {
28 8198 : unsigned char c = *cur;
29 :
30 8198 : if (strchr (toEscape, c) != NULL)
31 : {
32 0 : size += 2;
33 : }
34 8198 : else if (isprint (c))
35 : {
36 8198 : ++size;
37 : }
38 : else
39 : {
40 0 : size += 4;
41 : }
42 : }
43 :
44 1106 : if (size == 0)
45 : {
46 48 : return *str;
47 : }
48 :
49 1058 : char * newStr = elektraMalloc (size + 1);
50 1058 : char * newCur = newStr;
51 9256 : for (char * cur = *str; *cur != '\0'; ++cur)
52 : {
53 8198 : unsigned char c = *cur;
54 8198 : char * e = strchr (toEscape, c);
55 :
56 8198 : if (e != NULL)
57 : {
58 0 : char escaped = escapes[e - toEscape];
59 0 : *newCur = '\\';
60 0 : ++newCur;
61 0 : *newCur = escaped;
62 0 : ++newCur;
63 : }
64 8198 : else if (isprint (c))
65 : {
66 8198 : *newCur = c;
67 8198 : ++newCur;
68 : }
69 : else
70 : {
71 0 : *newCur = '\\';
72 0 : ++newCur;
73 0 : *newCur = 'x';
74 0 : ++newCur;
75 0 : *newCur = hex[c >> 4u];
76 0 : ++newCur;
77 0 : *newCur = hex[c & 0xFu];
78 0 : ++newCur;
79 : }
80 : }
81 1058 : *newCur = '\0';
82 1058 : elektraFree (*str);
83 1058 : *str = newStr;
84 1058 : return newStr;
85 : }
86 :
87 : /**
88 : * Generate a C-Style key and stream it.
89 : *
90 : * This keyset can be used to include as c-code for
91 : * applikations using elektra.
92 : *
93 : * @param key the key object to work with
94 : * @param stream the file pointer where to send the stream
95 : * @param options KDB_O_SHOWINDICES, KDB_O_IGNORE_COMMENT, KDB_O_SHOWINFO
96 : * @retval 1 on success
97 : * @ingroup stream
98 : */
99 210 : int keyGenerate (const Key * key, FILE * stream, option_t options)
100 : {
101 210 : size_t n = keyGetNameSize (key);
102 210 : if (n > 1)
103 : {
104 192 : char * nam = (char *) elektraMalloc (n);
105 192 : if (nam == NULL) return -1;
106 192 : keyGetName (key, nam, n);
107 192 : fprintf (stream, "\tkeyNew (\"%s\"", escapeString (&nam));
108 192 : elektraFree (nam);
109 : }
110 18 : else if (n == 1)
111 : {
112 18 : fprintf (stream, "\tkeyNew(\"\"");
113 : }
114 :
115 210 : size_t s = keyGetValueSize (key);
116 210 : if (s > 1)
117 : {
118 18 : char * str = (char *) elektraMalloc (s);
119 18 : if (str == NULL) return -1;
120 18 : if (keyIsBinary (key))
121 : {
122 0 : keyGetBinary (key, str, s);
123 0 : fprintf (stream, ", KEY_SIZE, \"%zd\"", keyGetValueSize (key));
124 : }
125 : else
126 : {
127 18 : keyGetString (key, str, s);
128 : }
129 18 : fprintf (stream, ", KEY_VALUE, \"%s\"", escapeString (&str));
130 18 : elektraFree (str);
131 : }
132 :
133 : const Key * meta;
134 210 : Key * dup = keyDup (key);
135 210 : keyRewindMeta (dup);
136 868 : while ((meta = keyNextMeta (dup)))
137 : {
138 448 : char * metaNam = elektraStrDup (keyName (meta));
139 448 : char * metaStr = elektraStrDup (keyString (meta));
140 448 : fprintf (stream, ", KEY_META, \"%s\", \"%s\"", escapeString (&metaNam), escapeString (&metaStr));
141 448 : elektraFree (metaNam);
142 448 : elektraFree (metaStr);
143 : }
144 210 : keyDel (dup);
145 :
146 210 : fprintf (stream, ", KEY_END)");
147 :
148 : if (options == 0) return 1; /* dummy to make icc happy */
149 : return 1;
150 : }
151 :
152 :
153 : /**
154 : * Generate a C-Style keyset and stream it.
155 : *
156 : * This keyset can be used to include as c-code for
157 : * applikations using elektra.
158 : *
159 : * The options takes the same options as kdbGet()
160 : * and kdbSet().
161 : *
162 : * @param ks the keyset to work with
163 : * @param stream the file pointer where to send the stream
164 : * @param options which keys not to output
165 : * @retval 1 on success
166 : * @ingroup stream
167 : */
168 54 : int ksGenerate (const KeySet * ks, FILE * stream, option_t options)
169 : {
170 : Key * key;
171 54 : KeySet * cks = ksDup (ks);
172 :
173 54 : ksRewind (cks);
174 :
175 54 : fprintf (stream, "ksNew (%d,\n", (int) ksGetSize (cks));
176 318 : while ((key = ksNext (cks)) != 0)
177 : {
178 210 : if (options & KDB_O_INACTIVE)
179 0 : if (key && keyIsInactive (key)) continue;
180 :
181 210 : keyGenerate (key, stream, options);
182 210 : fprintf (stream, ",\n");
183 : }
184 54 : fprintf (stream, "\tKS_END);\n");
185 :
186 54 : ksDel (cks);
187 54 : return 1;
188 : }
189 :
190 74 : int elektraCGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned ELEKTRA_UNUSED, Key * parentKey ELEKTRA_UNUSED)
191 : {
192 74 : if (!elektraStrCmp (keyName (parentKey), "system/elektra/modules/c"))
193 : {
194 74 : KeySet * contract = ksNew (30, keyNew ("system/elektra/modules/c", KEY_VALUE, "c plugin waits for your orders", KEY_END),
195 : keyNew ("system/elektra/modules/c/exports", KEY_END),
196 : keyNew ("system/elektra/modules/c/exports/get", KEY_FUNC, elektraCGet, KEY_END),
197 : keyNew ("system/elektra/modules/c/exports/set", KEY_FUNC, elektraCSet, KEY_END),
198 : keyNew ("system/elektra/modules/c/exports/checkconf", KEY_FUNC, elektraCCheckConfig, KEY_END),
199 : #include ELEKTRA_README
200 : keyNew ("system/elektra/modules/c/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
201 74 : ksAppend (returned, contract);
202 74 : ksDel (contract);
203 :
204 74 : return 1; // success
205 : }
206 : // get all keys
207 :
208 : return 1; // success
209 : }
210 :
211 54 : int elektraCSet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned ELEKTRA_UNUSED, Key * parentKey ELEKTRA_UNUSED)
212 : {
213 54 : FILE * fp = fopen (keyString (parentKey), "w");
214 :
215 54 : if (!fp)
216 : {
217 0 : ELEKTRA_SET_ERROR_SET (parentKey);
218 : return -1;
219 : }
220 :
221 54 : ksGenerate (returned, fp, 0);
222 :
223 54 : fclose (fp);
224 54 : return 1; // success
225 : }
226 :
227 0 : int elektraCCheckConfig (Key * errorKey ELEKTRA_UNUSED, KeySet * conf ELEKTRA_UNUSED)
228 : {
229 : // validate plugin configuration
230 : // this function is optional
231 :
232 : // the return codes have the following meaning:
233 : // 0: The configuration was OK and has not been changed
234 : // 1: The configuration has been changed and now it is OK
235 : // -1: The configuration was not OK and could not be fixed. An error has to be set to errorKey.
236 0 : return 0;
237 : }
238 :
239 74 : Plugin * ELEKTRA_PLUGIN_EXPORT
240 : {
241 : // clang-format off
242 74 : return elektraPluginExport ("c",
243 : ELEKTRA_PLUGIN_GET, &elektraCGet,
244 : ELEKTRA_PLUGIN_SET, &elektraCSet,
245 : ELEKTRA_PLUGIN_END);
246 : }
247 :
|