1 | /* ================================================================ */
|
---|
2 | /**
|
---|
3 | @file warning.c
|
---|
4 | @brief Pass warning messages to the screen or a usr function as set up.
|
---|
5 |
|
---|
6 | One of the most import parameter for setting up the bevaviour
|
---|
7 | is the warning level:
|
---|
8 |
|
---|
9 | @verbatim
|
---|
10 | ------------------------------------------------------------
|
---|
11 | Warning level: The lowest level of messages to be displayed
|
---|
12 | ------------------------------------------------------------
|
---|
13 | Warning mode:
|
---|
14 | bit 0: display on screen (stderr),
|
---|
15 | bit 1: write to file,
|
---|
16 | bit 2: write with user-defined logging function.
|
---|
17 | bit 3: display origin if supplied.
|
---|
18 | bit 4: open log file for appending.
|
---|
19 | bit 5: call auxilliary function for time/date etc.
|
---|
20 | bit 6: use the auxilliary function output as origin string
|
---|
21 | if no explicit origin was supplied.
|
---|
22 | bit 7: use syslog().
|
---|
23 | ------------------------------------------------------------
|
---|
24 | @endverbatim
|
---|
25 | */
|
---|
26 |
|
---|
27 | #include "initial.h"
|
---|
28 | #define __WARNING_MODULE 1
|
---|
29 | #include "warning.h"
|
---|
30 | #include <errno.h>
|
---|
31 |
|
---|
32 | struct warn_specific_data
|
---|
33 | {
|
---|
34 | /* Warning level: The lowest level of messages to be displayed */
|
---|
35 | int warninglevel;
|
---|
36 | /*
|
---|
37 | * -----------------------------------------------------------
|
---|
38 | * Warning mode:
|
---|
39 | * bit 0: display on screen (stderr),
|
---|
40 | * bit 1: write to file,
|
---|
41 | * bit 2: write with user-defined logging function.
|
---|
42 | * bit 3: display origin if supplied.
|
---|
43 | * bit 4: open log file for appending.
|
---|
44 | * bit 5: call auxilliary function for time/date etc.
|
---|
45 | * bit 6: use the auxilliary function output as origin string
|
---|
46 | * if no explicit origin was supplied.
|
---|
47 | * bit 7: use syslog().
|
---|
48 | * -----------------------------------------------------------
|
---|
49 | */
|
---|
50 | int warningmode;
|
---|
51 | char output_buffer[2048];
|
---|
52 | /** The name of the log file. Used only when opening the file. */
|
---|
53 | const char *logfname;
|
---|
54 | char saved_logfname[256];
|
---|
55 | int buffered;
|
---|
56 | FILE *logfile;
|
---|
57 | void (*log_function) ARGLIST((const char *, const char *, int, int));
|
---|
58 | void (*output_function) ARGLIST((const char *));
|
---|
59 | char *(*aux_function) ARGLIST((void));
|
---|
60 | int recursive;
|
---|
61 | };
|
---|
62 |
|
---|
63 | static struct warn_specific_data warn_defaults =
|
---|
64 | {
|
---|
65 | 0, /* warninglevel */
|
---|
66 | 1+8, /* warningmode */
|
---|
67 | "", /* output_buffer */
|
---|
68 | "warning.log", /* logfname */
|
---|
69 | "", /* saved_logfname */
|
---|
70 | 0, /* buffered */
|
---|
71 | NULL, /* logfile */
|
---|
72 | NULL, /* log_function */
|
---|
73 | NULL, /* output_function */
|
---|
74 | NULL, /* aux_function */
|
---|
75 | 0 /* recursive */
|
---|
76 | };
|
---|
77 |
|
---|
78 | #ifdef _REENTRANT
|
---|
79 |
|
---|
80 | #include <pthread.h>
|
---|
81 |
|
---|
82 | #ifndef PTHREAD_ONCE_INIT
|
---|
83 | #define PTHREAD_ONCE_INIT pthread_once_init
|
---|
84 | #define PTHREAD_MUTEX_INITIALIZER 0
|
---|
85 | #endif
|
---|
86 |
|
---|
87 | /** Global key for thread-specific data. */
|
---|
88 | static pthread_key_t warn_tsd_key;
|
---|
89 | static pthread_once_t warn_key_once = PTHREAD_ONCE_INIT;
|
---|
90 |
|
---|
91 | static int delete_warn_specific(void);
|
---|
92 | static void warn_destructor (void *whatever);
|
---|
93 | static void warn_func_once(void);
|
---|
94 | static int create_warn_specific(void);
|
---|
95 | static void *get_warn_specific(void);
|
---|
96 |
|
---|
97 | static int delete_warn_specific()
|
---|
98 | {
|
---|
99 | void *specific;
|
---|
100 |
|
---|
101 | if ( (specific = pthread_getspecific(warn_tsd_key)) == NULL )
|
---|
102 | return 0;
|
---|
103 | free(specific);
|
---|
104 | if ( pthread_setspecific(warn_tsd_key,NULL) < 0 )
|
---|
105 | return -1;
|
---|
106 | return 0;
|
---|
107 | }
|
---|
108 |
|
---|
109 | static void warn_destructor (void *whatever)
|
---|
110 | {
|
---|
111 | fprintf(stderr,"delete_warn_specific() called\n");
|
---|
112 | delete_warn_specific();
|
---|
113 | }
|
---|
114 |
|
---|
115 | static void warn_func_once()
|
---|
116 | {
|
---|
117 | fprintf(stderr,"Doing one-time thread-specific warning data initialization.\n");
|
---|
118 | #ifdef OS_LYNX
|
---|
119 | pthread_keycreate(&warn_tsd_key,warn_destructor);
|
---|
120 | #else
|
---|
121 | pthread_key_create(&warn_tsd_key,warn_destructor);
|
---|
122 | #endif
|
---|
123 | }
|
---|
124 |
|
---|
125 | static int create_warn_specific()
|
---|
126 | {
|
---|
127 | void *specific;
|
---|
128 | /* Make sure that the key has been set up */
|
---|
129 | if ( pthread_once(&warn_key_once,warn_func_once) != 0 )
|
---|
130 | {
|
---|
131 | fprintf(stderr,"Thread specific one-time initialization failed.\n");
|
---|
132 | return -1;
|
---|
133 | }
|
---|
134 | /* Any prior data ? This would be a memory leak. */
|
---|
135 | if ( (specific = pthread_getspecific(warn_tsd_key)) != NULL )
|
---|
136 | {
|
---|
137 | fprintf(stderr,"Prior thread-specific warning being deleted.\n");
|
---|
138 | free(specific);
|
---|
139 | pthread_setspecific(warn_tsd_key,NULL);
|
---|
140 | }
|
---|
141 |
|
---|
142 | /* New data allocated and initialized with defaults */
|
---|
143 | if ( (specific = calloc(1,sizeof(struct warn_specific_data))) == NULL )
|
---|
144 | return -1;
|
---|
145 | memcpy(specific,&warn_defaults,sizeof(struct warn_specific_data));
|
---|
146 | if ( pthread_setspecific(warn_tsd_key,specific) != 0 )
|
---|
147 | return -1;
|
---|
148 | return 0;
|
---|
149 | }
|
---|
150 |
|
---|
151 | static void *get_warn_specific()
|
---|
152 | {
|
---|
153 | void *specific;
|
---|
154 |
|
---|
155 | if ( (specific = pthread_getspecific(warn_tsd_key)) == NULL )
|
---|
156 | {
|
---|
157 | #if 0
|
---|
158 | fprintf(stderr,"Dynamically creating warning thread-specific data.\n");
|
---|
159 | fprintf(stderr,"Failure to call warn_delete_specific() at thread termination may result in memory leaks.\n");
|
---|
160 | #endif
|
---|
161 | create_warn_specific();
|
---|
162 | specific = pthread_getspecific(warn_tsd_key);
|
---|
163 | }
|
---|
164 |
|
---|
165 | return specific;
|
---|
166 | }
|
---|
167 |
|
---|
168 | #else
|
---|
169 | #define get_warn_specific() (&warn_defaults)
|
---|
170 | #endif
|
---|
171 |
|
---|
172 | /* ------------------------- warn_f_warning ------------------------- */
|
---|
173 | /**
|
---|
174 | * @short Issue a warning to screen or other configured target.
|
---|
175 | *
|
---|
176 | * Issue a warning to screen and/or file if the warning
|
---|
177 | * has a sufficiently large message 'level' (high enough severity).
|
---|
178 | * This function should best be called through the macros
|
---|
179 | * 'Information', 'Warning', and 'Error'.
|
---|
180 | * The name of this function has been changed from 'warning'
|
---|
181 | * to '_warning' to avoid trouble if you call 'warning' instead
|
---|
182 | * of 'Warning'. Now such a typo causes an error in the link step.
|
---|
183 | *
|
---|
184 | * @param msgtext Warning or error text.
|
---|
185 | * @param msgorigin Optional origin (e.g. function name) or NULL.
|
---|
186 | * @param msglevel Level of message importance:
|
---|
187 | * negative: debugging if needed,
|
---|
188 | * 0-9: informative,
|
---|
189 | * 10-19: warning,
|
---|
190 | * 20-29: error.
|
---|
191 | * @param msgno Number of message or 0.
|
---|
192 | *
|
---|
193 | * @return (none)
|
---|
194 | *
|
---|
195 | */
|
---|
196 |
|
---|
197 | void warn_f_warning (const char *msgtext, const char *msgorigin,
|
---|
198 | int msglevel, int msgno)
|
---|
199 | {
|
---|
200 | char enumtext[32];
|
---|
201 | struct warn_specific_data *wt = get_warn_specific();
|
---|
202 |
|
---|
203 | if ( wt == NULL )
|
---|
204 | return;
|
---|
205 |
|
---|
206 | if ( msgtext == (char *) NULL || wt == NULL )
|
---|
207 | return;
|
---|
208 |
|
---|
209 | /* Don't record or print message text if not severe enough. */
|
---|
210 | if ( msglevel < wt->warninglevel )
|
---|
211 | return;
|
---|
212 |
|
---|
213 | /* Make sure that warning() is not executed recursively, */
|
---|
214 | /* for example due to errors in a user-defined log function. */
|
---|
215 | if ( wt->recursive )
|
---|
216 | {
|
---|
217 | fputs("E0003: Recursive call to warning function!\n",stderr);
|
---|
218 | fputs("Text of last call: ",stderr);
|
---|
219 | fputs(msgtext,stderr);
|
---|
220 | fputs("\n",stderr);
|
---|
221 | if ( (wt->warningmode & 0x02) && wt->logfile != (FILE *) NULL )
|
---|
222 | {
|
---|
223 | fputs("E0003: Recursive call to warning function!\n",wt->logfile);
|
---|
224 | fputs("Text of last call: ",wt->logfile);
|
---|
225 | fputs(msgtext,wt->logfile);
|
---|
226 | fputs("\n",wt->logfile);
|
---|
227 | fflush(wt->logfile);
|
---|
228 | }
|
---|
229 | return; /* We could do more sophisticated things here */
|
---|
230 | }
|
---|
231 | wt->recursive++;
|
---|
232 |
|
---|
233 | if ( msgorigin == (char *) NULL && (wt->warningmode & 0x40) &&
|
---|
234 | wt->aux_function != NULL )
|
---|
235 | msgorigin = wt->aux_function();
|
---|
236 |
|
---|
237 | /* Sould the message be printed on the screen (stderr) ? */
|
---|
238 | if ( wt->warningmode & 0x01 )
|
---|
239 | {
|
---|
240 | if ( msgno > 0 )
|
---|
241 | {
|
---|
242 | (void) sprintf(enumtext,"%s%d: ",((msglevel>=20)?"E":"W"),msgno);
|
---|
243 | fputs(enumtext,stderr);
|
---|
244 | }
|
---|
245 | if ( msgorigin != (char *) NULL && ( wt->warningmode & 0x08 ) )
|
---|
246 | {
|
---|
247 | fputs(msgorigin,stderr);
|
---|
248 | fputs(": ",stderr);
|
---|
249 | }
|
---|
250 | if ( (wt->warningmode & 0x20) && wt->aux_function != NULL )
|
---|
251 | fprintf(stderr,"%s: ",wt->aux_function());
|
---|
252 | fputs(msgtext,stderr);
|
---|
253 | fputs("\n",stderr);
|
---|
254 | }
|
---|
255 |
|
---|
256 | /* Should the warning be written to a file ? */
|
---|
257 | if ( wt->warningmode & 0x02 )
|
---|
258 | {
|
---|
259 | if ( wt->logfile == (FILE *) NULL )
|
---|
260 | {
|
---|
261 | if ( wt->logfname == (char *) NULL )
|
---|
262 | {
|
---|
263 | fputs("E0004: No error log file name specified\n",stderr);
|
---|
264 | wt->warningmode &= ~((int)0x02);
|
---|
265 | { wt->recursive--; return; }
|
---|
266 | }
|
---|
267 | if ( (wt->logfile = fopen(wt->logfname,(wt->warningmode&0x10)?"a":"w")) ==
|
---|
268 | (FILE *) NULL )
|
---|
269 | {
|
---|
270 | fputs("E0001: Error opening log file '",stderr);
|
---|
271 | fputs(wt->logfname,stderr);
|
---|
272 | fputs("'.\n",stderr);
|
---|
273 | /* Disable writing to the logfile */
|
---|
274 | wt->warningmode &= ~((int)0x02);
|
---|
275 | { wt->recursive--; return; }
|
---|
276 | }
|
---|
277 | }
|
---|
278 |
|
---|
279 | if ( msgno > 0 )
|
---|
280 | (void) fprintf(wt->logfile,"%s%04d: ",((msglevel>=20)?"E":"W"),msgno);
|
---|
281 | if ( msgorigin != (char *) NULL && ( wt->warningmode & 8 ) )
|
---|
282 | {
|
---|
283 | (void) fputs(msgorigin,wt->logfile);
|
---|
284 | (void) fputs(": ",wt->logfile);
|
---|
285 | }
|
---|
286 | if ( (wt->warningmode & 0x20) && wt->aux_function != NULL )
|
---|
287 | fprintf(wt->logfile,"%s: ",wt->aux_function());
|
---|
288 | (void) fputs(msgtext,wt->logfile);
|
---|
289 | (void) fputs("\n",wt->logfile);
|
---|
290 | fflush(wt->logfile);
|
---|
291 |
|
---|
292 | if ( ferror(wt->logfile) )
|
---|
293 | {
|
---|
294 | clearerr(wt->logfile);
|
---|
295 | fputs("E0002: Error writing to log file '",stderr);
|
---|
296 | fputs(wt->logfname,stderr);
|
---|
297 | fputs("'.\n",stderr);
|
---|
298 | /* Disable writing to the logfile if the disk is full. */
|
---|
299 | if ( errno == ENOSPC )
|
---|
300 | {
|
---|
301 | fputs("E0005: File system is full. Disabling logging now.\n",
|
---|
302 | stderr);
|
---|
303 | wt->warningmode &= ~((int)0x02);
|
---|
304 | }
|
---|
305 | }
|
---|
306 | }
|
---|
307 |
|
---|
308 | if ( wt->log_function != NULL && (wt->warningmode & 0x04) )
|
---|
309 | (*wt->log_function)(msgtext,msgorigin,msglevel,msgno);
|
---|
310 |
|
---|
311 | wt->recursive--;
|
---|
312 | return;
|
---|
313 | }
|
---|
314 |
|
---|
315 | /* ------------------------ set_warning ------------------------- */
|
---|
316 | /**
|
---|
317 | * @short Set a specific warning level and mode.
|
---|
318 | *
|
---|
319 | * @param level Warnings with level below this are ignored.
|
---|
320 | * @param mode To screen, to file, with user function ...
|
---|
321 | *
|
---|
322 | * @return 0 if ok, -1 if level and/or mode could not be set.
|
---|
323 | *
|
---|
324 | */
|
---|
325 |
|
---|
326 | int set_warning (int level, int mode)
|
---|
327 | {
|
---|
328 | struct warn_specific_data *wt = get_warn_specific();
|
---|
329 |
|
---|
330 | if ( wt == NULL )
|
---|
331 | return -1;
|
---|
332 |
|
---|
333 | if ( level != -1 ) /* -1 means: keep the old value */
|
---|
334 | wt->warninglevel = level;
|
---|
335 | if ( mode != -1 )
|
---|
336 | wt->warningmode = mode;
|
---|
337 | return 0; /* So far, always ok */
|
---|
338 | }
|
---|
339 |
|
---|
340 | int set_default_warning (int level, int mode)
|
---|
341 | {
|
---|
342 | struct warn_specific_data *wt = &warn_defaults;
|
---|
343 |
|
---|
344 | if ( wt == NULL )
|
---|
345 | return -1;
|
---|
346 |
|
---|
347 | if ( level != -1 ) /* -1 means: keep the old value */
|
---|
348 | wt->warninglevel = level;
|
---|
349 | if ( mode != -1 )
|
---|
350 | wt->warningmode = mode;
|
---|
351 | return 0; /* So far, always ok */
|
---|
352 | }
|
---|
353 |
|
---|
354 | /* --------------------- warning_status ---------------------- */
|
---|
355 | /**
|
---|
356 | * Inquire status of warning settings.
|
---|
357 | *
|
---|
358 | * @param plevel Pointer to variable for storing current level.
|
---|
359 | * @param pmode Pointer to store the current warning mode.
|
---|
360 | *
|
---|
361 | * @return (none)
|
---|
362 | *
|
---|
363 | */
|
---|
364 |
|
---|
365 | void warning_status (int *plevel, int *pmode)
|
---|
366 | {
|
---|
367 | struct warn_specific_data *wt = get_warn_specific();
|
---|
368 | if ( wt == NULL )
|
---|
369 | return;
|
---|
370 | if ( plevel )
|
---|
371 | *plevel = wt->warninglevel;
|
---|
372 | if ( pmode )
|
---|
373 | *pmode = wt->warningmode;
|
---|
374 | }
|
---|
375 |
|
---|
376 | /* --------------- set_logging_function ------------- */
|
---|
377 | /**
|
---|
378 | * @short Set user-defined function for logging warnings and errors.
|
---|
379 | *
|
---|
380 | * Set a user-defined function as the function to be
|
---|
381 | * used for logging warnings and errors.
|
---|
382 | * To enable usage of this function, bit 2 of the
|
---|
383 | * warning mode must be set and other bits reset, if
|
---|
384 | * logging to screen and/or disk file is no longer wanted.
|
---|
385 | *
|
---|
386 | * @param userfunc Pointer to a function taking two strings
|
---|
387 | * (the message text and the origin text,
|
---|
388 | * which may be NULL) and two integers
|
---|
389 | * (message level and message number).
|
---|
390 | *
|
---|
391 | * @return (none)
|
---|
392 | *
|
---|
393 | */
|
---|
394 |
|
---|
395 | void set_logging_function ( void (*user_function) ARGLIST((
|
---|
396 | const char *, const char *, int, int)) )
|
---|
397 | {
|
---|
398 | struct warn_specific_data *wt = get_warn_specific();
|
---|
399 | if ( wt == NULL )
|
---|
400 | {
|
---|
401 | Warning("Cannot set logging function");
|
---|
402 | return;
|
---|
403 | }
|
---|
404 | wt->log_function = user_function;
|
---|
405 | }
|
---|
406 |
|
---|
407 | void set_default_logging_function ( void (*user_function) ARGLIST((
|
---|
408 | const char *, const char *, int, int)) )
|
---|
409 | {
|
---|
410 | struct warn_specific_data *wt = &warn_defaults;
|
---|
411 | if ( wt == NULL )
|
---|
412 | {
|
---|
413 | Warning("Cannot set logging function");
|
---|
414 | return;
|
---|
415 | }
|
---|
416 | wt->log_function = user_function;
|
---|
417 | }
|
---|
418 |
|
---|
419 | /* --------------------- set_log_file -------------------- */
|
---|
420 | /**
|
---|
421 | * @short Set a new log file name and save it in local storage.
|
---|
422 | *
|
---|
423 | * If there was a log file with a different name opened
|
---|
424 | * previously, close it.
|
---|
425 | *
|
---|
426 | * @param fname New name of log file for warnings
|
---|
427 | *
|
---|
428 | * @return 0 (o.k.), -1 (error)
|
---|
429 | *
|
---|
430 | */
|
---|
431 |
|
---|
432 | int set_log_file (const char *fname)
|
---|
433 | {
|
---|
434 | struct warn_specific_data *wt = get_warn_specific();
|
---|
435 | if ( wt == NULL )
|
---|
436 | return -1;
|
---|
437 | /* No log file? */
|
---|
438 | if ( fname == (char *) NULL )
|
---|
439 | {
|
---|
440 | if ( wt->logfile != (FILE *) NULL )
|
---|
441 | {
|
---|
442 | wt->logfname = (char *) NULL;
|
---|
443 | fclose(wt->logfile);
|
---|
444 | wt->logfile = (FILE *) NULL;
|
---|
445 | }
|
---|
446 | return 0;
|
---|
447 | }
|
---|
448 |
|
---|
449 | /* Is length of name o.k.? */
|
---|
450 | if ( strlen(fname) > sizeof(wt->saved_logfname)-1 )
|
---|
451 | {
|
---|
452 | Warning("Log file name is too long.");
|
---|
453 | return -1;
|
---|
454 | }
|
---|
455 |
|
---|
456 | /* Is this the old log file name again? */
|
---|
457 | if ( wt->logfname != (char *) NULL )
|
---|
458 | if ( strcmp(fname,wt->logfname) == 0 )
|
---|
459 | return 0;
|
---|
460 |
|
---|
461 | /* If there was a different log file before, close it. */
|
---|
462 | if ( wt->logfile != (FILE *) NULL )
|
---|
463 | {
|
---|
464 | fclose(wt->logfile);
|
---|
465 | wt->logfile = (FILE *) NULL;
|
---|
466 | }
|
---|
467 |
|
---|
468 | strcpy(wt->saved_logfname,fname);
|
---|
469 | wt->logfname = wt->saved_logfname;
|
---|
470 |
|
---|
471 | return 0;
|
---|
472 | }
|
---|
473 |
|
---|
474 | /* ---------------------- output_text -------------------- */
|
---|
475 | /**
|
---|
476 | * Print a text string (without appending a newline etc.)
|
---|
477 | * on the screen or send it to a controlling process, depending
|
---|
478 | * on the setting of the output function.
|
---|
479 | *
|
---|
480 | * @param text A text string to be displayed.
|
---|
481 | *
|
---|
482 | * @return (none)
|
---|
483 | *
|
---|
484 | */
|
---|
485 |
|
---|
486 | void warn_f_output_text (const char *text)
|
---|
487 | {
|
---|
488 | int len;
|
---|
489 | struct warn_specific_data *wt = get_warn_specific();
|
---|
490 |
|
---|
491 | if ( wt == NULL )
|
---|
492 | return ;
|
---|
493 |
|
---|
494 | if ( *text == '\0' )
|
---|
495 | return;
|
---|
496 |
|
---|
497 | if ( wt->output_function == NULL )
|
---|
498 | fputs(text,stdout);
|
---|
499 | else
|
---|
500 | {
|
---|
501 | len = strlen(text);
|
---|
502 | if ( wt->buffered + len + 1 >= sizeof(wt->output_buffer) )
|
---|
503 | {
|
---|
504 | if ( wt->buffered )
|
---|
505 | (*wt->output_function)(wt->output_buffer);
|
---|
506 | wt->output_buffer[0] = '\0';
|
---|
507 | wt->buffered = 0;
|
---|
508 | }
|
---|
509 | if ( len + 1 >= sizeof(wt->output_buffer) )
|
---|
510 | {
|
---|
511 | (*wt->output_function)(text);
|
---|
512 | }
|
---|
513 | else if ( len > 0 )
|
---|
514 | {
|
---|
515 | memcpy((wt->output_buffer+wt->buffered),text,(size_t)len);
|
---|
516 | wt->buffered += len;
|
---|
517 | wt->output_buffer[wt->buffered] = '\0';
|
---|
518 | }
|
---|
519 | }
|
---|
520 | }
|
---|
521 |
|
---|
522 | /* ------------------ flush_output ----------------- */
|
---|
523 | /**
|
---|
524 | * @short Flush buffered output.
|
---|
525 | * Output is flushed, no matter if it is standard output
|
---|
526 | * or a special output function;
|
---|
527 | *
|
---|
528 | * @return (none)
|
---|
529 | *
|
---|
530 | */
|
---|
531 |
|
---|
532 | void flush_output ()
|
---|
533 | {
|
---|
534 | struct warn_specific_data *wt = get_warn_specific();
|
---|
535 |
|
---|
536 | if ( wt == NULL )
|
---|
537 | return ;
|
---|
538 |
|
---|
539 | if ( wt->output_function == NULL )
|
---|
540 | fflush(stdout);
|
---|
541 | else if ( wt->buffered )
|
---|
542 | (*wt->output_function)(wt->output_buffer);
|
---|
543 | wt->buffered = 0;
|
---|
544 | }
|
---|
545 |
|
---|
546 | /* --------------- set_output_function ------------- */
|
---|
547 | /**
|
---|
548 | * Set a user-defined function as the function to be used
|
---|
549 | * for normal text output. Such a function may be used to
|
---|
550 | * send output back to a remote control process via network.
|
---|
551 | *
|
---|
552 | * @param userfunc Pointer to a function taking a string
|
---|
553 | * (the text to be displayed) as argument.
|
---|
554 | *
|
---|
555 | * @return (none)
|
---|
556 | *
|
---|
557 | */
|
---|
558 |
|
---|
559 | void set_output_function ( void (*user_function) ARGLIST((const char *)) )
|
---|
560 | {
|
---|
561 | struct warn_specific_data *wt = get_warn_specific();
|
---|
562 |
|
---|
563 | if ( wt == NULL )
|
---|
564 | return ;
|
---|
565 |
|
---|
566 | if ( wt->buffered )
|
---|
567 | flush_output();
|
---|
568 | wt->output_function = user_function;
|
---|
569 | }
|
---|
570 |
|
---|
571 | void set_default_output_function ( void (*user_function) ARGLIST((const char *)) )
|
---|
572 | {
|
---|
573 | struct warn_specific_data *wt = &warn_defaults;
|
---|
574 |
|
---|
575 | if ( wt == NULL )
|
---|
576 | return ;
|
---|
577 |
|
---|
578 | if ( wt->buffered )
|
---|
579 | flush_output();
|
---|
580 | wt->output_function = user_function;
|
---|
581 | }
|
---|
582 |
|
---|
583 | /* --------------------- set_aux_warning_function --------------- */
|
---|
584 | /**
|
---|
585 | * @short Set an auxilliary function for warnings.
|
---|
586 | * This function may be
|
---|
587 | * used to insert time and date or origin etc. at the beginning
|
---|
588 | * of the warning text.
|
---|
589 | *
|
---|
590 | * @param auxfunc -- Pointer to a function taking no argument
|
---|
591 | * and returning a character string.
|
---|
592 | *
|
---|
593 | * @return (none)
|
---|
594 | *
|
---|
595 | */
|
---|
596 |
|
---|
597 | void set_aux_warning_function ( char *(*auxfunc) ARGLIST((void)) )
|
---|
598 | {
|
---|
599 | struct warn_specific_data *wt = get_warn_specific();
|
---|
600 |
|
---|
601 | if ( wt == NULL )
|
---|
602 | return ;
|
---|
603 |
|
---|
604 | wt->aux_function = auxfunc;
|
---|
605 | }
|
---|
606 |
|
---|
607 | void set_default_aux_warning_function ( char *(*auxfunc) ARGLIST((void)) )
|
---|
608 | {
|
---|
609 | struct warn_specific_data *wt = &warn_defaults;
|
---|
610 |
|
---|
611 | if ( wt == NULL )
|
---|
612 | return ;
|
---|
613 |
|
---|
614 | wt->aux_function = auxfunc;
|
---|
615 | }
|
---|