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.
21 * _cups_debug_set() - Enable or disable debug logging.
25 * Include necessary headers...
28 #include "cups-private.h"
29 #include "thread-private.h"
31 # include <sys/timeb.h>
34 # define getpid (int)GetCurrentProcessId
35 static int /* O - 0 on success, -1 on failure */
36 gettimeofday(struct timeval
*tv
, /* I - Timeval struct */
37 void *tz
) /* I - Timezone */
39 struct _timeb timebuffer
; /* Time buffer struct */
41 tv
->tv_sec
= (long)timebuffer
.time
;
42 tv
->tv_usec
= timebuffer
.millitm
* 1000;
46 # include <sys/time.h>
57 int _cups_debug_fd
= -1;
58 /* Debug log file descriptor */
59 int _cups_debug_level
= 1;
60 /* Log level (0 to 9) */
68 static regex_t
*debug_filter
= NULL
;
69 /* Filter expression for messages */
70 static int debug_init
= 0; /* Did we initialize debugging? */
71 static _cups_mutex_t debug_mutex
= _CUPS_MUTEX_INITIALIZER
;
72 /* Mutex to control initialization */
76 * 'debug_vsnprintf()' - Format a string into a fixed size buffer.
79 static int /* O - Number of bytes formatted */
80 debug_vsnprintf(char *buffer
, /* O - Output buffer */
81 size_t bufsize
, /* O - Size of output buffer */
82 const char *format
, /* I - printf-style format string */
83 va_list ap
) /* I - Pointer to additional arguments */
85 char *bufptr
, /* Pointer to position in buffer */
86 *bufend
, /* Pointer to end of buffer */
87 size
, /* Size character (h, l, L) */
88 type
; /* Format type character */
89 int width
, /* Width of field */
90 prec
; /* Number of characters of precision */
91 char tformat
[100], /* Temporary format string for sprintf() */
92 *tptr
, /* Pointer into temporary format */
93 temp
[1024]; /* Buffer for formatted numbers */
94 char *s
; /* Pointer to string */
95 int bytes
; /* Total number of bytes needed */
98 if (!buffer
|| bufsize
< 2 || !format
)
102 * Loop through the format string, formatting as needed...
106 bufend
= buffer
+ bufsize
- 1;
124 else if (strchr(" -+#\'", *format
))
130 * Get width from argument...
134 width
= va_arg(ap
, int);
136 snprintf(tptr
, sizeof(tformat
) - (tptr
- tformat
), "%d", width
);
137 tptr
+= strlen(tptr
);
143 while (isdigit(*format
& 255))
145 if (tptr
< (tformat
+ sizeof(tformat
) - 1))
148 width
= width
* 10 + *format
++ - '0';
154 if (tptr
< (tformat
+ sizeof(tformat
) - 1))
162 * Get precision from argument...
166 prec
= va_arg(ap
, int);
168 snprintf(tptr
, sizeof(tformat
) - (tptr
- tformat
), "%d", prec
);
169 tptr
+= strlen(tptr
);
175 while (isdigit(*format
& 255))
177 if (tptr
< (tformat
+ sizeof(tformat
) - 1))
180 prec
= prec
* 10 + *format
++ - '0';
185 if (*format
== 'l' && format
[1] == 'l')
189 if (tptr
< (tformat
+ sizeof(tformat
) - 2))
197 else if (*format
== 'h' || *format
== 'l' || *format
== 'L')
199 if (tptr
< (tformat
+ sizeof(tformat
) - 1))
210 if (tptr
< (tformat
+ sizeof(tformat
) - 1))
218 case 'E' : /* Floating point formats */
223 if ((width
+ 2) > sizeof(temp
))
226 sprintf(temp
, tformat
, va_arg(ap
, double));
228 bytes
+= (int)strlen(temp
);
232 if ((bufptr
+ strlen(temp
)) > bufend
)
234 strncpy(bufptr
, temp
, (size_t)(bufend
- bufptr
));
239 strcpy(bufptr
, temp
);
240 bufptr
+= strlen(temp
);
245 case 'B' : /* Integer formats */
253 if ((width
+ 2) > sizeof(temp
))
256 # ifdef HAVE_LONG_LONG
258 sprintf(temp
, tformat
, va_arg(ap
, long long));
260 # endif /* HAVE_LONG_LONG */
262 sprintf(temp
, tformat
, va_arg(ap
, long));
264 sprintf(temp
, tformat
, va_arg(ap
, int));
266 bytes
+= (int)strlen(temp
);
270 if ((bufptr
+ strlen(temp
)) > bufend
)
272 strncpy(bufptr
, temp
, (size_t)(bufend
- bufptr
));
277 strcpy(bufptr
, temp
);
278 bufptr
+= strlen(temp
);
283 case 'p' : /* Pointer value */
284 if ((width
+ 2) > sizeof(temp
))
287 sprintf(temp
, tformat
, va_arg(ap
, void *));
289 bytes
+= (int)strlen(temp
);
293 if ((bufptr
+ strlen(temp
)) > bufend
)
295 strncpy(bufptr
, temp
, (size_t)(bufend
- bufptr
));
300 strcpy(bufptr
, temp
);
301 bufptr
+= strlen(temp
);
306 case 'c' : /* Character or character array */
312 *bufptr
++ = va_arg(ap
, int);
315 if ((bufptr
+ width
) > bufend
)
316 width
= (int)(bufend
- bufptr
);
318 memcpy(bufptr
, va_arg(ap
, char *), (size_t)width
);
324 case 's' : /* String */
325 if ((s
= va_arg(ap
, char *)) == NULL
)
329 * Copy the C string, replacing control chars and \ with
330 * C character escapes...
333 for (bufend
--; *s
&& bufptr
< bufend
; s
++)
365 else if ((*s
& 255) < ' ')
369 *bufptr
++ = '0' + *s
/ 8;
370 *bufptr
++ = '0' + (*s
& 7);
379 case 'n' : /* Output number of chars so far */
380 *(va_arg(ap
, int *)) = bytes
;
396 * Nul-terminate the string and return the number of characters needed.
406 * '_cups_debug_printf()' - Write a formatted line to the log.
410 _cups_debug_printf(const char *format
, /* I - Printf-style format string */
411 ...) /* I - Additional arguments as needed */
413 va_list ap
; /* Pointer to arguments */
414 struct timeval curtime
; /* Current time */
415 char buffer
[2048]; /* Output buffer */
416 size_t bytes
; /* Number of bytes in buffer */
417 int level
; /* Log level in message */
421 * See if we need to do any logging...
425 _cups_debug_set(getenv("CUPS_DEBUG_LOG"), getenv("CUPS_DEBUG_LEVEL"),
426 getenv("CUPS_DEBUG_FILTER"), 0);
428 if (_cups_debug_fd
< 0)
432 * Filter as needed...
435 if (isdigit(format
[0]))
436 level
= *format
++ - '0';
440 if (level
> _cups_debug_level
)
445 int result
; /* Filter result */
447 _cupsMutexLock(&debug_mutex
);
448 result
= regexec(debug_filter
, format
, 0, NULL
, 0);
449 _cupsMutexUnlock(&debug_mutex
);
456 * Format the message...
459 gettimeofday(&curtime
, NULL
);
460 snprintf(buffer
, sizeof(buffer
), "%02d:%02d:%02d.%03d ",
461 (int)((curtime
.tv_sec
/ 3600) % 24),
462 (int)((curtime
.tv_sec
/ 60) % 60),
463 (int)(curtime
.tv_sec
% 60), (int)(curtime
.tv_usec
/ 1000));
465 va_start(ap
, format
);
466 debug_vsnprintf(buffer
+ 13, sizeof(buffer
) - 14, format
, ap
);
469 bytes
= strlen(buffer
);
470 if (buffer
[bytes
- 1] != '\n')
472 buffer
[bytes
] = '\n';
474 buffer
[bytes
] = '\0';
481 write(_cups_debug_fd
, buffer
, bytes
);
486 * '_cups_debug_puts()' - Write a single line to the log.
490 _cups_debug_puts(const char *s
) /* I - String to output */
492 char format
[4]; /* C%s */
500 _cups_debug_printf(format
, s
);
505 * '_cups_debug_set()' - Enable or disable debug logging.
509 _cups_debug_set(const char *logfile
, /* I - Log file or NULL */
510 const char *level
, /* I - Log level or NULL */
511 const char *filter
, /* I - Filter string or NULL */
512 int force
) /* I - Force initialization */
514 _cupsMutexLock(&debug_mutex
);
516 if (!debug_init
|| force
)
519 * Restore debug settings to defaults...
522 if (_cups_debug_fd
!= -1)
524 close(_cups_debug_fd
);
530 regfree((regex_t
*)debug_filter
);
534 _cups_debug_level
= 1;
537 * Open logs, set log levels, etc.
542 else if (!strcmp(logfile
, "-"))
546 char buffer
[1024]; /* Filename buffer */
548 snprintf(buffer
, sizeof(buffer
), logfile
, getpid());
550 if (buffer
[0] == '+')
551 _cups_debug_fd
= open(buffer
+ 1, O_WRONLY
| O_APPEND
| O_CREAT
, 0644);
553 _cups_debug_fd
= open(buffer
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0644);
557 _cups_debug_level
= atoi(level
);
561 if ((debug_filter
= (regex_t
*)calloc(1, sizeof(regex_t
))) == NULL
)
562 fputs("Unable to allocate memory for CUPS_DEBUG_FILTER - results not "
563 "filtered!\n", stderr
);
564 else if (regcomp(debug_filter
, filter
, REG_EXTENDED
))
566 fputs("Bad regular expression in CUPS_DEBUG_FILTER - results not "
567 "filtered!\n", stderr
);
576 _cupsMutexUnlock(&debug_mutex
);