add a PLANNED_TEST() macro to test.h
[nobug.git] / src / nobug_env.c
blob99c7e7651de6e6e6718004b0e2f68359e817ef59
1 /*
2 This file is part of the NoBug debugging library.
4 Copyright (C)
5 2007, 2008, 2010, Christian Thaeter <ct@pipapo.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, contact Christian Thaeter <ct@pipapo.org>.
20 #define NOBUG_LIBNOBUG_C
21 #include "nobug.h"
23 #include <unistd.h>
26 Env variable parsing
30 Syntax:
32 logdecl_list --> logdecl, any( ',' logdecl_list)
33 logdecl --> flag, opt(limitdecl, any(targetdecl))
34 flag --> "identifier of a flag"
35 limitdecl --> ':', "LIMITNAME"
36 targetdecl --> '@', "targetname", opt(targetopts)
37 targetopts --> '(', "options for target", ')', opt(targetopts)
39 examples:
40 NOBUG_LOG='flag,other' # set the limit of the 'default' target a default limit
41 NOBUG_LOG='flag:DEBUG' # set the limit of the 'default' target to DEBUG
42 NOBUG_LOG='flag:DEBUG@console@syslog' # set console and syslog limits for flag to DEBUG
43 NOBUG_LOG='flag:DEBUG,other:TRACE@ringbuffer'
45 TODO:
46 (options) on targets are not yet implemented
50 const struct
52 const char * name;
53 int value;
54 } nobug_limits[] =
56 { ":EMERG", LOG_EMERG },
57 { ":ALERT", LOG_ALERT },
58 { ":CRIT", LOG_CRIT },
59 { ":ERR", LOG_ERR },
60 { ":ERROR", LOG_ERR },
61 { ":WARNING", LOG_WARNING },
62 { ":WARN", LOG_WARNING },
63 { ":NOTICE", LOG_NOTICE },
64 { ":INFO", LOG_INFO },
65 { ":DEBUG", LOG_DEBUG },
66 { ":TRACE", LOG_DEBUG },
69 const char* nobug_targets[] =
70 {"@ringbuffer", "@console", "@file", "@syslog", "@application"};
73 static int
74 nobug_env_parse_string_option (const char** env, const char* key, char* value)
76 char* end = strchr (*env, ')');
77 if (!end)
78 return -1;
80 if (!strncasecmp (key, *env+1, strlen (key)))
82 char* delim = strchr (*env, '=');
83 if (delim)
85 if (delim > end || end-delim > 256)
86 return -1;
87 strncat (value, delim+1, end-delim-1);
89 *env = end + 1;
90 return 1;
92 return 0;
95 static int
96 nobug_env_parse_size_option (const char** env, const char* key, size_t* value)
98 char* end = strchr (*env, ')');
99 if (!end)
100 return -1;
102 if (!strncasecmp (key, *env+1, strlen (key)))
104 char* delim = strchr (*env, '=');
105 if (!delim || sscanf (delim+1, "%zi", value) != 1)
106 return -1;
107 *env = end + 1;
108 return 1;
110 return 0;
113 static int
114 nobug_env_parse_flag_option (const char** env, const char* key, int* flag, int mask)
117 char* end = strchr (*env, ')');
118 if (!end)
119 return -1;
121 if (!strncasecmp (key, *env+1, strlen (key)))
123 //char* delim = strchr (*env, '='); TODO =yes =no =true =false =1 =0
124 /*|| !delim || delim > end*/
125 *flag ^= mask;
126 *env = end + 1;
127 return 1;
129 return 0;
132 static int
133 nobug_env_parse_int_option (const char** env, const char* key, int* value)
135 char* end = strchr (*env, ')');
136 char* delim = strchr (*env, '=');
137 if (!end || !delim || delim > end)
138 return -1;
140 if (!strncasecmp (key, *env+1, strlen (key)))
142 if (sscanf (delim+1, "%i", value) != 1)
143 return -1;
144 *env = end + 1;
145 return 1;
147 return 0;
150 static int
151 nobug_env_parse_drop_option (const char** env)
153 char* end = strchr (*env, ')');
154 if (!end)
155 return -1;
156 *env = end + 1;
157 return 0;
161 nobug_env_parse_flag (const char* env, struct nobug_flag* flag, int default_target, int default_limit, const struct nobug_context context)
163 int ret = -1;
164 if (!env || !flag->name)
165 return ret;
166 size_t flaglen = strlen (flag->name);
168 if (flag != &nobug_flag_nobug)
169 nobug_log (&nobug_flag_nobug, LOG_NOTICE, "NOBUG", context, " INIT_FLAG: %s", flag->name);
173 if (!strncmp(env, flag->name, flaglen))
175 /* flagname matches */
176 int limit;
177 env += flaglen;
178 if (*env == ':')
179 for (limit = 0; limit<11; ++limit)
181 size_t limitlen = strlen (nobug_limits[limit].name);
182 if (!strncmp(env, nobug_limits[limit].name, limitlen))
184 /* found :LIMIT */
185 int target;
186 env += limitlen;
187 if (*env == '@')
188 while (*env == '@')
190 for (target = 0; target<5; ++target)
192 size_t targetlen = strlen (nobug_targets[target]);
193 if (!strncmp(env, nobug_targets[target], targetlen))
195 /* @target found */
196 env += targetlen;
197 int given = 0;
198 int s = 0;
200 int fd = -1;
201 char name[256];
202 *name = '\0';
203 size_t size = 4096;
204 size_t guard = 4096;
205 int flags = 0;
207 switch (target)
209 case NOBUG_TARGET_RINGBUFFER:
210 while (*env == '(' && given >= 0)
212 /* (file=name) */
213 if ((s = nobug_env_parse_string_option (&env, "file", name)))
215 given |= s;
216 continue;
219 /* (size=N) */
220 if ((s = nobug_env_parse_size_option (&env, "size", &size)))
222 given |= s;
223 continue;
226 /* (guard=N) */
227 if ((s = nobug_env_parse_size_option (&env, "guard", &guard)))
229 given |= s;
230 continue;
233 /* (append) (temp) (keep) */
234 if ((s = nobug_env_parse_flag_option (&env, "append",
235 &flags, NOBUG_RINGBUFFER_APPEND)))
237 given |= s;
238 continue;
240 if ((s = nobug_env_parse_flag_option (&env, "temp",
241 &flags, NOBUG_RINGBUFFER_TEMP)))
243 given |= s;
244 continue;
246 if ((s = nobug_env_parse_flag_option (&env, "keep",
247 &flags, NOBUG_RINGBUFFER_KEEP)))
249 given |= s;
250 continue;
252 if (nobug_env_parse_drop_option (&env))
253 return -1;
255 if (given < 0)
256 return -1;
257 if (given)
259 /* create new ringbuffer for flag */
260 if (flag->ringbuffer_target != &nobug_default_ringbuffer)
261 nobug_ringbuffer_delete (flag->ringbuffer_target);
262 flag->ringbuffer_target = nobug_ringbuffer_new (size, guard, name, flags);
264 break;
265 case NOBUG_TARGET_CONSOLE:
266 while (*env == '(' && given >= 0)
268 /* (fd=N) */
269 if ((s = nobug_env_parse_int_option (&env, "fd", &fd)))
271 given |= s;
272 continue;
274 if (nobug_env_parse_drop_option (&env))
275 return -1;
277 if (given < 0)
278 return -1;
279 if (given)
281 // open fd for console
282 if (!write (fd, NULL, 0) && flag->console_target == stderr)
283 flag->console_target = fdopen (fd, "w");
285 break;
286 case NOBUG_TARGET_FILE:
287 while (*env == '(' && given >= 0)
289 /* (name=name) */
290 if ((s = nobug_env_parse_string_option (&env, "name", name)))
292 given |= s;
293 continue;
296 /* (append) */
297 if ((s = nobug_env_parse_flag_option (&env, "append",
298 &flags, NOBUG_RINGBUFFER_APPEND)))
300 given |= s;
301 continue;
303 if (nobug_env_parse_drop_option (&env))
304 return -1;
306 if (given < 0)
307 return -1;
308 if (given)
310 FILE* new = fopen (name, flags?"a":"w");
311 if (new)
313 if (flag->file_target)
314 fclose (flag->file_target);
315 flag->file_target = new;
318 break;
319 case NOBUG_TARGET_SYSLOG:
320 while (*env == '(' && given >= 0)
322 /* (facility=name) unimplemented */
323 //given |= nobug_env_parse_string_option (&env, "facility", .. );
325 /* (ident=string) */
326 if ((s = nobug_env_parse_string_option (&env, "ident", name)))
328 given |= s;
329 continue;
332 /* (cons) (pid) */
333 if ((s = nobug_env_parse_flag_option (&env, "cons",
334 &flags, LOG_CONS)))
336 given |= s;
337 continue;
339 if ((s = nobug_env_parse_flag_option (&env, "pid",
340 &flags, LOG_PID)))
342 given |= s;
343 continue;
345 if ((s = nobug_env_parse_flag_option (&env, "perror",
346 &flags, LOG_PERROR)))
348 given |= s;
349 continue;
351 if (nobug_env_parse_drop_option (&env))
352 return -1;
354 if (given < 0)
355 return -1;
356 if (given)
358 closelog ();
359 openlog (*name?strdup (name): NULL, flags, LOG_USER);
361 break;
362 case NOBUG_TARGET_APPLICATION:
363 // TODO
364 break;
366 ret = flag->limits[target] = nobug_limits[limit].value;
370 else
372 /* flag:LIMIT with no @target */
373 ret = flag->limits[default_target] = nobug_limits[limit].value;
377 else
379 /* flag with no :LIMIT */
380 ret = flag->limits[default_target] = default_limit;
383 env = strchr(env, ',');
384 if (env)
385 ++env;
387 while (env);
388 return ret;
393 nobug_env_init_flag (struct nobug_flag* flag, int default_target, int default_limit, const struct nobug_context context)
395 int i;
396 nobug_init(context);
398 if (flag->initialized)
399 return 1;
400 flag->initialized = 1;
402 /* set some defaults */
403 flag->ringbuffer_target = &nobug_default_ringbuffer;
404 flag->console_target = stderr;
405 flag->file_target = nobug_default_file;
407 if (flag->parent)
409 nobug_env_init_flag (flag->parent, default_target, default_limit, context);
411 for (i = NOBUG_TARGET_CONSOLE; i <= NOBUG_TARGET_APPLICATION; ++i)
413 flag->limits[i] = flag->parent->limits[i];
415 flag->ringbuffer_target = flag->parent->ringbuffer_target;
416 flag->console_target = flag->parent->console_target;
417 flag->file_target = flag->parent->file_target;
420 /* parse $NOBUG_LOG */
421 int ret = nobug_env_parse_flag (getenv("NOBUG_LOG"), flag, default_target, default_limit, context);
423 /* ensure that the ringbuffer is the most verbose */
424 int max;
426 for (max = i = NOBUG_TARGET_CONSOLE; i <= NOBUG_TARGET_APPLICATION; ++i)
428 max = max > flag->limits[i] ? max : flag->limits[i];
431 flag->limits[NOBUG_TARGET_RINGBUFFER] = max > flag->limits[NOBUG_TARGET_RINGBUFFER]
432 ? max : flag->limits[NOBUG_TARGET_RINGBUFFER];
434 return ret;