4 * Debugging functions for CUPS.
6 * Copyright 2008-2010 by Apple Inc.
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/".
14 * This file is subject to the Apple OS-Developed Software exception.
18 * debug_vsnprintf() - Format a string into a fixed size buffer.
19 * _cups_debug_printf() - Write a formatted line to the log.
20 * _cups_debug_puts() - Write a single line to the log.
24 * Include necessary headers...
27 #include "cups-private.h"
31 # include <sys/time.h>
44 int _cups_debug_fd
= -1;
45 /* Debug log file descriptor */
46 int _cups_debug_level
= 1;
47 /* Log level (0 to 9) */
56 static regex_t
*debug_filter
= NULL
;
57 /* Filter expression for messages */
59 static int debug_init
= 0; /* Did we initialize debugging? */
60 # ifdef HAVE_PTHREAD_H
61 static pthread_mutex_t debug_mutex
= PTHREAD_MUTEX_INITIALIZER
;
62 /* Mutex to control initialization */
63 # endif /* HAVE_PTHREAD_H */
67 * 'debug_vsnprintf()' - Format a string into a fixed size buffer.
70 static int /* O - Number of bytes formatted */
71 debug_vsnprintf(char *buffer
, /* O - Output buffer */
72 size_t bufsize
, /* O - Size of output buffer */
73 const char *format
, /* I - printf-style format string */
74 va_list ap
) /* I - Pointer to additional arguments */
76 char *bufptr
, /* Pointer to position in buffer */
77 *bufend
, /* Pointer to end of buffer */
78 size
, /* Size character (h, l, L) */
79 type
; /* Format type character */
80 int width
, /* Width of field */
81 prec
; /* Number of characters of precision */
82 char tformat
[100], /* Temporary format string for sprintf() */
83 *tptr
, /* Pointer into temporary format */
84 temp
[1024]; /* Buffer for formatted numbers */
85 char *s
; /* Pointer to string */
86 int bytes
; /* Total number of bytes needed */
89 if (!buffer
|| bufsize
< 2 || !format
)
93 * Loop through the format string, formatting as needed...
97 bufend
= buffer
+ bufsize
- 1;
115 else if (strchr(" -+#\'", *format
))
121 * Get width from argument...
125 width
= va_arg(ap
, int);
127 snprintf(tptr
, sizeof(tformat
) - (tptr
- tformat
), "%d", width
);
128 tptr
+= strlen(tptr
);
134 while (isdigit(*format
& 255))
136 if (tptr
< (tformat
+ sizeof(tformat
) - 1))
139 width
= width
* 10 + *format
++ - '0';
145 if (tptr
< (tformat
+ sizeof(tformat
) - 1))
153 * Get precision from argument...
157 prec
= va_arg(ap
, int);
159 snprintf(tptr
, sizeof(tformat
) - (tptr
- tformat
), "%d", prec
);
160 tptr
+= strlen(tptr
);
166 while (isdigit(*format
& 255))
168 if (tptr
< (tformat
+ sizeof(tformat
) - 1))
171 prec
= prec
* 10 + *format
++ - '0';
176 if (*format
== 'l' && format
[1] == 'l')
180 if (tptr
< (tformat
+ sizeof(tformat
) - 2))
188 else if (*format
== 'h' || *format
== 'l' || *format
== 'L')
190 if (tptr
< (tformat
+ sizeof(tformat
) - 1))
201 if (tptr
< (tformat
+ sizeof(tformat
) - 1))
209 case 'E' : /* Floating point formats */
214 if ((width
+ 2) > sizeof(temp
))
217 sprintf(temp
, tformat
, va_arg(ap
, double));
219 bytes
+= (int)strlen(temp
);
223 if ((bufptr
+ strlen(temp
)) > bufend
)
225 strncpy(bufptr
, temp
, (size_t)(bufend
- bufptr
));
230 strcpy(bufptr
, temp
);
231 bufptr
+= strlen(temp
);
236 case 'B' : /* Integer formats */
244 if ((width
+ 2) > sizeof(temp
))
247 #ifdef HAVE_LONG_LONG
249 sprintf(temp
, tformat
, va_arg(ap
, long long));
251 #endif /* HAVE_LONG_LONG */
253 sprintf(temp
, tformat
, va_arg(ap
, long));
255 sprintf(temp
, tformat
, va_arg(ap
, int));
257 bytes
+= (int)strlen(temp
);
261 if ((bufptr
+ strlen(temp
)) > bufend
)
263 strncpy(bufptr
, temp
, (size_t)(bufend
- bufptr
));
268 strcpy(bufptr
, temp
);
269 bufptr
+= strlen(temp
);
274 case 'p' : /* Pointer value */
275 if ((width
+ 2) > sizeof(temp
))
278 sprintf(temp
, tformat
, va_arg(ap
, void *));
280 bytes
+= (int)strlen(temp
);
284 if ((bufptr
+ strlen(temp
)) > bufend
)
286 strncpy(bufptr
, temp
, (size_t)(bufend
- bufptr
));
291 strcpy(bufptr
, temp
);
292 bufptr
+= strlen(temp
);
297 case 'c' : /* Character or character array */
303 *bufptr
++ = va_arg(ap
, int);
306 if ((bufptr
+ width
) > bufend
)
307 width
= (int)(bufend
- bufptr
);
309 memcpy(bufptr
, va_arg(ap
, char *), (size_t)width
);
315 case 's' : /* String */
316 if ((s
= va_arg(ap
, char *)) == NULL
)
320 * Copy the C string, replacing control chars and \ with
321 * C character escapes...
324 for (bufend
--; *s
&& bufptr
< bufend
; s
++)
356 else if ((*s
& 255) < ' ')
360 *bufptr
++ = '0' + *s
/ 8;
361 *bufptr
++ = '0' + (*s
& 7);
370 case 'n' : /* Output number of chars so far */
371 *(va_arg(ap
, int *)) = bytes
;
387 * Nul-terminate the string and return the number of characters needed.
397 * '_cups_debug_printf()' - Write a formatted line to the log.
401 _cups_debug_printf(const char *format
, /* I - Printf-style format string */
402 ...) /* I - Additional arguments as needed */
404 va_list ap
; /* Pointer to arguments */
405 struct timeval curtime
; /* Current time */
406 char buffer
[2048]; /* Output buffer */
407 size_t bytes
; /* Number of bytes in buffer */
408 int level
; /* Log level in message */
409 const char *cups_debug_filter
,
410 /* CUPS_DEBUG_FILTER environment variable */
412 /* CUPS_DEBUG_LEVEL environment variable */
413 *cups_debug_log
;/* CUPS_DEBUG_LOG environment variable */
417 * See if we need to do any logging...
423 * Get a lock on the debug initializer, then re-check in case another
424 * thread already did it...
427 pthread_mutex_lock(&debug_mutex
);
431 if ((cups_debug_log
= getenv("CUPS_DEBUG_LOG")) == NULL
)
433 else if (!strcmp(cups_debug_log
, "-"))
437 snprintf(buffer
, sizeof(buffer
), cups_debug_log
, getpid());
439 if (buffer
[0] == '+')
440 _cups_debug_fd
= open(buffer
+ 1, O_WRONLY
| O_APPEND
| O_CREAT
, 0644);
442 _cups_debug_fd
= open(buffer
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0644);
445 if ((cups_debug_level
= getenv("CUPS_DEBUG_LEVEL")) != NULL
)
446 _cups_debug_level
= atoi(cups_debug_level
);
448 if ((cups_debug_filter
= getenv("CUPS_DEBUG_FILTER")) != NULL
)
450 if ((debug_filter
= (regex_t
*)calloc(1, sizeof(regex_t
))) == NULL
)
451 fputs("Unable to allocate memory for CUPS_DEBUG_FILTER - results not "
452 "filtered!\n", stderr
);
453 else if (regcomp(debug_filter
, cups_debug_filter
, REG_EXTENDED
))
455 fputs("Bad regular expression in CUPS_DEBUG_FILTER - results not "
456 "filtered!\n", stderr
);
465 pthread_mutex_unlock(&debug_mutex
);
468 if (_cups_debug_fd
< 0)
472 * Filter as needed...
475 if (isdigit(format
[0]))
476 level
= *format
++ - '0';
480 if (level
> _cups_debug_level
)
485 int result
; /* Filter result */
487 pthread_mutex_lock(&debug_mutex
);
488 result
= regexec(debug_filter
, format
, 0, NULL
, 0);
489 pthread_mutex_unlock(&debug_mutex
);
496 * Format the message...
499 gettimeofday(&curtime
, NULL
);
500 snprintf(buffer
, sizeof(buffer
), "%02d:%02d:%02d.%03d ",
501 (int)((curtime
.tv_sec
/ 3600) % 24),
502 (int)((curtime
.tv_sec
/ 60) % 60),
503 (int)(curtime
.tv_sec
% 60), (int)(curtime
.tv_usec
/ 1000));
505 va_start(ap
, format
);
506 debug_vsnprintf(buffer
+ 13, sizeof(buffer
) - 14, format
, ap
);
509 bytes
= strlen(buffer
);
510 if (buffer
[bytes
- 1] != '\n')
512 buffer
[bytes
] = '\n';
514 buffer
[bytes
] = '\0';
521 write(_cups_debug_fd
, buffer
, bytes
);
526 * '_cups_debug_puts()' - Write a single line to the log.
530 _cups_debug_puts(const char *s
) /* I - String to output */
532 char format
[4]; /* C%s */
539 _cups_debug_printf(format
, s
);
543 #elif defined(__APPLE__)
544 /* Mac OS X needs these stubbed since we reference them in the libcups.exp file */
545 void _cups_debug_printf(const char *format
, ...) {}
546 void _cups_debug_puts(const char *s
) {}