]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/debug.c
Merge changes from CUPS 1.5svn-r9105.
[thirdparty/cups.git] / cups / debug.c
CommitLineData
ae71f5de
MS
1/*
2 * "$Id$"
3 *
71e16022 4 * Debugging functions for CUPS.
ae71f5de 5 *
71e16022 6 * Copyright 2008-2010 by Apple Inc.
ae71f5de
MS
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
11 * which should have been included with this file. If this file is
12 * file is missing or damaged, see the license at "http://www.cups.org/".
13 *
14 * This file is subject to the Apple OS-Developed Software exception.
15 *
16 * Contents:
17 *
1ff0402e 18 * debug_vsnprintf() - Format a string into a fixed size buffer.
ae71f5de
MS
19 * _cups_debug_printf() - Write a formatted line to the log.
20 * _cups_debug_puts() - Write a single line to the log.
21 */
22
23/*
24 * Include necessary headers...
25 */
26
71e16022 27#include "cups-private.h"
6d2f911b 28#include "thread-private.h"
536bc2c6
MS
29#ifdef WIN32
30# include <io.h>
31#else
32# include <sys/time.h>
33# include <unistd.h>
34#endif /* WIN32 */
ae71f5de 35#include <fcntl.h>
536bc2c6
MS
36#ifndef WIN32
37# include <regex.h>
38#endif /* WIN32 */
ae71f5de
MS
39
40
4509bb49
MS
41/*
42 * Globals...
43 */
44
45int _cups_debug_fd = -1;
46 /* Debug log file descriptor */
f11a948a
MS
47int _cups_debug_level = 1;
48 /* Log level (0 to 9) */
4509bb49
MS
49
50
ae71f5de 51#ifdef DEBUG
4509bb49
MS
52/*
53 * Local globals...
54 */
55
536bc2c6 56# ifndef WIN32
e07d4801
MS
57static regex_t *debug_filter = NULL;
58 /* Filter expression for messages */
536bc2c6 59# endif /* !WIN32 */
f11a948a 60static int debug_init = 0; /* Did we initialize debugging? */
6d2f911b 61static _cups_mutex_t debug_mutex = _CUPS_MUTEX_INITIALIZER;
4509bb49 62 /* Mutex to control initialization */
4509bb49
MS
63
64
ae71f5de
MS
65/*
66 * 'debug_vsnprintf()' - Format a string into a fixed size buffer.
67 */
68
f8b3a85b 69static int /* O - Number of bytes formatted */
ae71f5de
MS
70debug_vsnprintf(char *buffer, /* O - Output buffer */
71 size_t bufsize, /* O - Size of output buffer */
72 const char *format, /* I - printf-style format string */
73 va_list ap) /* I - Pointer to additional arguments */
74{
75 char *bufptr, /* Pointer to position in buffer */
76 *bufend, /* Pointer to end of buffer */
ae71f5de
MS
77 size, /* Size character (h, l, L) */
78 type; /* Format type character */
79 int width, /* Width of field */
80 prec; /* Number of characters of precision */
81 char tformat[100], /* Temporary format string for sprintf() */
82 *tptr, /* Pointer into temporary format */
83 temp[1024]; /* Buffer for formatted numbers */
84 char *s; /* Pointer to string */
85 int bytes; /* Total number of bytes needed */
86
87
1f0275e3
MS
88 if (!buffer || bufsize < 2 || !format)
89 return (-1);
90
ae71f5de
MS
91 /*
92 * Loop through the format string, formatting as needed...
93 */
94
95 bufptr = buffer;
96 bufend = buffer + bufsize - 1;
97 bytes = 0;
98
99 while (*format)
100 {
101 if (*format == '%')
102 {
103 tptr = tformat;
104 *tptr++ = *format++;
105
106 if (*format == '%')
107 {
1f0275e3
MS
108 if (bufptr < bufend)
109 *bufptr++ = *format;
ae71f5de
MS
110 bytes ++;
111 format ++;
112 continue;
113 }
114 else if (strchr(" -+#\'", *format))
1f0275e3 115 *tptr++ = *format++;
ae71f5de
MS
116
117 if (*format == '*')
118 {
119 /*
120 * Get width from argument...
121 */
122
123 format ++;
124 width = va_arg(ap, int);
125
126 snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
127 tptr += strlen(tptr);
128 }
129 else
130 {
131 width = 0;
132
133 while (isdigit(*format & 255))
134 {
135 if (tptr < (tformat + sizeof(tformat) - 1))
136 *tptr++ = *format;
137
138 width = width * 10 + *format++ - '0';
139 }
140 }
141
142 if (*format == '.')
143 {
144 if (tptr < (tformat + sizeof(tformat) - 1))
145 *tptr++ = *format;
146
147 format ++;
148
149 if (*format == '*')
150 {
151 /*
152 * Get precision from argument...
153 */
154
155 format ++;
156 prec = va_arg(ap, int);
157
158 snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
159 tptr += strlen(tptr);
160 }
161 else
162 {
163 prec = 0;
164
165 while (isdigit(*format & 255))
166 {
167 if (tptr < (tformat + sizeof(tformat) - 1))
168 *tptr++ = *format;
169
170 prec = prec * 10 + *format++ - '0';
171 }
172 }
173 }
ae71f5de
MS
174
175 if (*format == 'l' && format[1] == 'l')
176 {
177 size = 'L';
178
179 if (tptr < (tformat + sizeof(tformat) - 2))
180 {
181 *tptr++ = 'l';
182 *tptr++ = 'l';
183 }
184
185 format += 2;
186 }
187 else if (*format == 'h' || *format == 'l' || *format == 'L')
188 {
189 if (tptr < (tformat + sizeof(tformat) - 1))
190 *tptr++ = *format;
191
192 size = *format++;
193 }
1f0275e3
MS
194 else
195 size = 0;
ae71f5de
MS
196
197 if (!*format)
198 break;
199
200 if (tptr < (tformat + sizeof(tformat) - 1))
201 *tptr++ = *format;
202
203 type = *format++;
204 *tptr = '\0';
205
206 switch (type)
207 {
208 case 'E' : /* Floating point formats */
209 case 'G' :
210 case 'e' :
211 case 'f' :
212 case 'g' :
213 if ((width + 2) > sizeof(temp))
214 break;
215
216 sprintf(temp, tformat, va_arg(ap, double));
217
218 bytes += (int)strlen(temp);
219
220 if (bufptr)
221 {
222 if ((bufptr + strlen(temp)) > bufend)
223 {
224 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
225 bufptr = bufend;
226 }
227 else
228 {
229 strcpy(bufptr, temp);
230 bufptr += strlen(temp);
231 }
232 }
233 break;
234
235 case 'B' : /* Integer formats */
236 case 'X' :
237 case 'b' :
238 case 'd' :
239 case 'i' :
240 case 'o' :
241 case 'u' :
242 case 'x' :
243 if ((width + 2) > sizeof(temp))
244 break;
245
6d2f911b 246# ifdef HAVE_LONG_LONG
ae71f5de
MS
247 if (size == 'L')
248 sprintf(temp, tformat, va_arg(ap, long long));
249 else
6d2f911b 250# endif /* HAVE_LONG_LONG */
ae71f5de
MS
251 if (size == 'l')
252 sprintf(temp, tformat, va_arg(ap, long));
253 else
254 sprintf(temp, tformat, va_arg(ap, int));
255
256 bytes += (int)strlen(temp);
257
258 if (bufptr)
259 {
260 if ((bufptr + strlen(temp)) > bufend)
261 {
262 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
263 bufptr = bufend;
264 }
265 else
266 {
267 strcpy(bufptr, temp);
268 bufptr += strlen(temp);
269 }
270 }
271 break;
272
273 case 'p' : /* Pointer value */
274 if ((width + 2) > sizeof(temp))
275 break;
276
277 sprintf(temp, tformat, va_arg(ap, void *));
278
279 bytes += (int)strlen(temp);
280
281 if (bufptr)
282 {
283 if ((bufptr + strlen(temp)) > bufend)
284 {
285 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
286 bufptr = bufend;
287 }
288 else
289 {
290 strcpy(bufptr, temp);
291 bufptr += strlen(temp);
292 }
293 }
294 break;
295
296 case 'c' : /* Character or character array */
297 bytes += width;
298
299 if (bufptr)
300 {
301 if (width <= 1)
302 *bufptr++ = va_arg(ap, int);
303 else
304 {
305 if ((bufptr + width) > bufend)
306 width = (int)(bufend - bufptr);
307
308 memcpy(bufptr, va_arg(ap, char *), (size_t)width);
309 bufptr += width;
310 }
311 }
312 break;
313
314 case 's' : /* String */
315 if ((s = va_arg(ap, char *)) == NULL)
316 s = "(null)";
317
318 /*
319 * Copy the C string, replacing control chars and \ with
320 * C character escapes...
321 */
322
323 for (bufend --; *s && bufptr < bufend; s ++)
324 {
325 if (*s == '\n')
326 {
327 *bufptr++ = '\\';
328 *bufptr++ = 'n';
329 }
330 else if (*s == '\r')
331 {
332 *bufptr++ = '\\';
333 *bufptr++ = 'r';
334 }
335 else if (*s == '\t')
336 {
337 *bufptr++ = '\\';
338 *bufptr++ = 't';
339 }
340 else if (*s == '\\')
341 {
342 *bufptr++ = '\\';
343 *bufptr++ = '\\';
344 }
345 else if (*s == '\'')
346 {
347 *bufptr++ = '\\';
348 *bufptr++ = '\'';
349 }
350 else if (*s == '\"')
351 {
352 *bufptr++ = '\\';
353 *bufptr++ = '\"';
354 }
355 else if ((*s & 255) < ' ')
356 {
357 *bufptr++ = '\\';
358 *bufptr++ = '0';
359 *bufptr++ = '0' + *s / 8;
360 *bufptr++ = '0' + (*s & 7);
361 }
362 else
363 *bufptr++ = *s;
364 }
365
366 bufend ++;
367 break;
368
369 case 'n' : /* Output number of chars so far */
370 *(va_arg(ap, int *)) = bytes;
371 break;
372 }
373 }
374 else
375 {
376 bytes ++;
377
1f0275e3 378 if (bufptr < bufend)
ae71f5de
MS
379 *bufptr++ = *format;
380
381 format ++;
382 }
383 }
384
385 /*
386 * Nul-terminate the string and return the number of characters needed.
387 */
388
389 *bufptr = '\0';
390
391 return (bytes);
392}
393
394
395/*
396 * '_cups_debug_printf()' - Write a formatted line to the log.
397 */
398
399void
400_cups_debug_printf(const char *format, /* I - Printf-style format string */
401 ...) /* I - Additional arguments as needed */
402{
403 va_list ap; /* Pointer to arguments */
404 struct timeval curtime; /* Current time */
405 char buffer[2048]; /* Output buffer */
406 size_t bytes; /* Number of bytes in buffer */
e07d4801
MS
407 int level; /* Log level in message */
408 const char *cups_debug_filter,
409 /* CUPS_DEBUG_FILTER environment variable */
410 *cups_debug_level,
411 /* CUPS_DEBUG_LEVEL environment variable */
412 *cups_debug_log;/* CUPS_DEBUG_LOG environment variable */
6d2f911b 413
ae71f5de
MS
414
415 /*
416 * See if we need to do any logging...
417 */
418
4509bb49 419 if (!debug_init)
ae71f5de 420 {
4509bb49
MS
421 /*
422 * Get a lock on the debug initializer, then re-check in case another
423 * thread already did it...
424 */
ae71f5de 425
6d2f911b 426 _cupsMutexLock(&debug_mutex);
4509bb49
MS
427
428 if (!debug_init)
dd1abb6b 429 {
4509bb49
MS
430 if ((cups_debug_log = getenv("CUPS_DEBUG_LOG")) == NULL)
431 _cups_debug_fd = -1;
432 else if (!strcmp(cups_debug_log, "-"))
433 _cups_debug_fd = 2;
434 else
435 {
436 snprintf(buffer, sizeof(buffer), cups_debug_log, getpid());
f11a948a
MS
437
438 if (buffer[0] == '+')
439 _cups_debug_fd = open(buffer + 1, O_WRONLY | O_APPEND | O_CREAT, 0644);
440 else
441 _cups_debug_fd = open(buffer, O_WRONLY | O_TRUNC | O_CREAT, 0644);
4509bb49 442 }
e07d4801
MS
443
444 if ((cups_debug_level = getenv("CUPS_DEBUG_LEVEL")) != NULL)
f11a948a 445 _cups_debug_level = atoi(cups_debug_level);
e07d4801
MS
446
447 if ((cups_debug_filter = getenv("CUPS_DEBUG_FILTER")) != NULL)
448 {
449 if ((debug_filter = (regex_t *)calloc(1, sizeof(regex_t))) == NULL)
450 fputs("Unable to allocate memory for CUPS_DEBUG_FILTER - results not "
451 "filtered!\n", stderr);
452 else if (regcomp(debug_filter, cups_debug_filter, REG_EXTENDED))
453 {
454 fputs("Bad regular expression in CUPS_DEBUG_FILTER - results not "
455 "filtered!\n", stderr);
456 free(debug_filter);
457 debug_filter = NULL;
458 }
459 }
f11a948a
MS
460
461 debug_init = 1;
dd1abb6b 462 }
4509bb49 463
6d2f911b 464 _cupsMutexUnlock(&debug_mutex);
ae71f5de
MS
465 }
466
4509bb49 467 if (_cups_debug_fd < 0)
ae71f5de
MS
468 return;
469
e07d4801
MS
470 /*
471 * Filter as needed...
472 */
473
474 if (isdigit(format[0]))
475 level = *format++ - '0';
476 else
477 level = 0;
478
f11a948a 479 if (level > _cups_debug_level)
e07d4801
MS
480 return;
481
482 if (debug_filter)
483 {
484 int result; /* Filter result */
485
6d2f911b 486 _cupsMutexLock(&debug_mutex);
e07d4801 487 result = regexec(debug_filter, format, 0, NULL, 0);
6d2f911b 488 _cupsMutexUnlock(&debug_mutex);
e07d4801
MS
489
490 if (result)
491 return;
492 }
493
ae71f5de
MS
494 /*
495 * Format the message...
496 */
497
498 gettimeofday(&curtime, NULL);
499 snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d.%03d ",
500 (int)((curtime.tv_sec / 3600) % 24),
501 (int)((curtime.tv_sec / 60) % 60),
502 (int)(curtime.tv_sec % 60), (int)(curtime.tv_usec / 1000));
503
504 va_start(ap, format);
505 debug_vsnprintf(buffer + 13, sizeof(buffer) - 14, format, ap);
506 va_end(ap);
507
508 bytes = strlen(buffer);
509 if (buffer[bytes - 1] != '\n')
510 {
511 buffer[bytes] = '\n';
512 bytes ++;
513 buffer[bytes] = '\0';
514 }
515
516 /*
517 * Write it out...
518 */
519
4509bb49 520 write(_cups_debug_fd, buffer, bytes);
ae71f5de
MS
521}
522
523
524/*
525 * '_cups_debug_puts()' - Write a single line to the log.
526 */
527
528void
529_cups_debug_puts(const char *s) /* I - String to output */
530{
e07d4801
MS
531 char format[4]; /* C%s */
532
533 format[0] = *s++;
534 format[1] = '%';
535 format[2] = 's';
536 format[3] = '\0';
537
538 _cups_debug_printf(format, s);
ae71f5de 539}
ae71f5de
MS
540#endif /* DEBUG */
541
542
543/*
544 * End of "$Id$".
545 */