formatting fix for init_flag
[nobug.git] / src / nobug_env.c
blob7a9766d082ae4eb7025958d653e685b14e0eacd2
1 /*
2 This file is part of the NoBug debugging library.
4 Copyright (C)
5 2007, 2008, 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 int flags = 0;
206 switch (target)
208 case NOBUG_TARGET_RINGBUFFER:
209 while (*env == '(' && given >= 0)
211 /* (file=name) */
212 if ((s = nobug_env_parse_string_option (&env, "file", name)))
214 given |= s;
215 continue;
218 /* (size=N) */
219 if ((s = nobug_env_parse_size_option (&env, "size", &size)))
221 given |= s;
222 continue;
225 /* (append) (temp) (keep) */
226 if ((s = nobug_env_parse_flag_option (&env, "append",
227 &flags, NOBUG_RINGBUFFER_APPEND)))
229 given |= s;
230 continue;
232 if ((s = nobug_env_parse_flag_option (&env, "temp",
233 &flags, NOBUG_RINGBUFFER_TEMP)))
235 given |= s;
236 continue;
238 if ((s = nobug_env_parse_flag_option (&env, "keep",
239 &flags, NOBUG_RINGBUFFER_KEEP)))
241 given |= s;
242 continue;
244 if (nobug_env_parse_drop_option (&env))
245 return -1;
247 if (given < 0)
248 return -1;
249 if (given)
251 /* create new ringbuffer for flag */
252 if (flag->ringbuffer_target != &nobug_default_ringbuffer)
253 nobug_ringbuffer_delete (flag->ringbuffer_target);
254 flag->ringbuffer_target = nobug_ringbuffer_new (size, name, flags);
256 break;
257 case NOBUG_TARGET_CONSOLE:
258 while (*env == '(' && given >= 0)
260 /* (fd=N) */
261 if ((s = nobug_env_parse_int_option (&env, "fd", &fd)))
263 given |= s;
264 continue;
266 if (nobug_env_parse_drop_option (&env))
267 return -1;
269 if (given < 0)
270 return -1;
271 if (given)
273 // open fd for console
274 if (!write (fd, NULL, 0) && flag->console_target == stderr)
275 flag->console_target = fdopen (fd, "w");
277 break;
278 case NOBUG_TARGET_FILE:
279 while (*env == '(' && given >= 0)
281 /* (name=name) */
282 if ((s = nobug_env_parse_string_option (&env, "name", name)))
284 given |= s;
285 continue;
288 /* (append) */
289 if ((s = nobug_env_parse_flag_option (&env, "append",
290 &flags, NOBUG_RINGBUFFER_APPEND)))
292 given |= s;
293 continue;
295 if (nobug_env_parse_drop_option (&env))
296 return -1;
298 if (given < 0)
299 return -1;
300 if (given)
302 FILE* new = fopen (name, flags?"a":"w");
303 if (new)
305 if (flag->file_target)
306 fclose (flag->file_target);
307 flag->file_target = new;
310 break;
311 case NOBUG_TARGET_SYSLOG:
312 while (*env == '(' && given >= 0)
314 /* (facility=name) unimplemented */
315 //given |= nobug_env_parse_string_option (&env, "facility", .. );
317 /* (ident=string) */
318 if ((s = nobug_env_parse_string_option (&env, "ident", name)))
320 given |= s;
321 continue;
324 /* (cons) (pid) */
325 if ((s = nobug_env_parse_flag_option (&env, "cons",
326 &flags, LOG_CONS)))
328 given |= s;
329 continue;
331 if ((s = nobug_env_parse_flag_option (&env, "pid",
332 &flags, LOG_PID)))
334 given |= s;
335 continue;
337 if ((s = nobug_env_parse_flag_option (&env, "perror",
338 &flags, LOG_PERROR)))
340 given |= s;
341 continue;
343 if (nobug_env_parse_drop_option (&env))
344 return -1;
346 if (given < 0)
347 return -1;
348 if (given)
350 closelog ();
351 openlog (*name?strdup (name): NULL, flags, LOG_USER);
353 break;
354 case NOBUG_TARGET_APPLICATION:
355 // TODO
356 break;
358 ret = flag->limits[target] = nobug_limits[limit].value;
362 else
364 /* flag:LIMIT with no @target */
365 ret = flag->limits[default_target] = nobug_limits[limit].value;
369 else
371 /* flag with no :LIMIT */
372 ret = flag->limits[default_target] = default_limit;
375 env = strchr(env, ',');
376 if (env)
377 ++env;
379 while (env);
380 return ret;
385 nobug_env_init_flag (struct nobug_flag* flag, int default_target, int default_limit, const struct nobug_context context)
387 int i;
388 nobug_init(context);
390 if (flag->initialized)
391 return 1;
392 flag->initialized = 1;
394 /* set some defaults */
395 flag->ringbuffer_target = &nobug_default_ringbuffer;
396 flag->console_target = stderr;
397 flag->file_target = nobug_default_file;
399 if (flag->parent)
401 nobug_env_init_flag (flag->parent, default_target, default_limit, context);
403 for (i = NOBUG_TARGET_CONSOLE; i <= NOBUG_TARGET_APPLICATION; ++i)
405 flag->limits[i] = flag->parent->limits[i];
407 flag->ringbuffer_target = flag->parent->ringbuffer_target;
408 flag->console_target = flag->parent->console_target;
409 flag->file_target = flag->parent->file_target;
412 /* parse $NOBUG_LOG */
413 int ret = nobug_env_parse_flag (getenv("NOBUG_LOG"), flag, default_target, default_limit, context);
415 /* ensure that the ringbuffer is the most verbose */
416 int max;
418 for (max = i = NOBUG_TARGET_CONSOLE; i <= NOBUG_TARGET_APPLICATION; ++i)
420 max = max > flag->limits[i] ? max : flag->limits[i];
423 flag->limits[NOBUG_TARGET_RINGBUFFER] = max > flag->limits[NOBUG_TARGET_RINGBUFFER]
424 ? max : flag->limits[NOBUG_TARGET_RINGBUFFER];
426 return ret;