]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/debug.c
Merge changes from CUPS 1.4svn-r7715.
[thirdparty/cups.git] / cups / debug.c
1 /*
2 * "$Id$"
3 *
4 * Debugging functions for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2008 by Apple Inc.
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 *
18 * _cups_debug_printf() - Write a formatted line to the log.
19 * _cups_debug_puts() - Write a single line to the log.
20 */
21
22 /*
23 * Include necessary headers...
24 */
25
26 #include "globals.h"
27 #include "debug.h"
28 #include <sys/time.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31
32
33 /*
34 * Globals...
35 */
36
37 int _cups_debug_fd = -1;
38 /* Debug log file descriptor */
39
40
41 #ifdef DEBUG
42 /*
43 * Local globals...
44 */
45
46 static int debug_init = 0; /* Did we initialize debugging? */
47 # ifdef HAVE_PTHREAD_H
48 static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
49 /* Mutex to control initialization */
50 # endif /* HAVE_PTHREAD_H */
51
52
53 /*
54 * 'debug_vsnprintf()' - Format a string into a fixed size buffer.
55 */
56
57 int /* O - Number of bytes formatted */
58 debug_vsnprintf(char *buffer, /* O - Output buffer */
59 size_t bufsize, /* O - Size of output buffer */
60 const char *format, /* I - printf-style format string */
61 va_list ap) /* I - Pointer to additional arguments */
62 {
63 char *bufptr, /* Pointer to position in buffer */
64 *bufend, /* Pointer to end of buffer */
65 size, /* Size character (h, l, L) */
66 type; /* Format type character */
67 int width, /* Width of field */
68 prec; /* Number of characters of precision */
69 char tformat[100], /* Temporary format string for sprintf() */
70 *tptr, /* Pointer into temporary format */
71 temp[1024]; /* Buffer for formatted numbers */
72 char *s; /* Pointer to string */
73 int bytes; /* Total number of bytes needed */
74
75
76 if (!buffer || bufsize < 2 || !format)
77 return (-1);
78
79 /*
80 * Loop through the format string, formatting as needed...
81 */
82
83 bufptr = buffer;
84 bufend = buffer + bufsize - 1;
85 bytes = 0;
86
87 while (*format)
88 {
89 if (*format == '%')
90 {
91 tptr = tformat;
92 *tptr++ = *format++;
93
94 if (*format == '%')
95 {
96 if (bufptr < bufend)
97 *bufptr++ = *format;
98 bytes ++;
99 format ++;
100 continue;
101 }
102 else if (strchr(" -+#\'", *format))
103 *tptr++ = *format++;
104
105 if (*format == '*')
106 {
107 /*
108 * Get width from argument...
109 */
110
111 format ++;
112 width = va_arg(ap, int);
113
114 snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
115 tptr += strlen(tptr);
116 }
117 else
118 {
119 width = 0;
120
121 while (isdigit(*format & 255))
122 {
123 if (tptr < (tformat + sizeof(tformat) - 1))
124 *tptr++ = *format;
125
126 width = width * 10 + *format++ - '0';
127 }
128 }
129
130 if (*format == '.')
131 {
132 if (tptr < (tformat + sizeof(tformat) - 1))
133 *tptr++ = *format;
134
135 format ++;
136
137 if (*format == '*')
138 {
139 /*
140 * Get precision from argument...
141 */
142
143 format ++;
144 prec = va_arg(ap, int);
145
146 snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
147 tptr += strlen(tptr);
148 }
149 else
150 {
151 prec = 0;
152
153 while (isdigit(*format & 255))
154 {
155 if (tptr < (tformat + sizeof(tformat) - 1))
156 *tptr++ = *format;
157
158 prec = prec * 10 + *format++ - '0';
159 }
160 }
161 }
162
163 if (*format == 'l' && format[1] == 'l')
164 {
165 size = 'L';
166
167 if (tptr < (tformat + sizeof(tformat) - 2))
168 {
169 *tptr++ = 'l';
170 *tptr++ = 'l';
171 }
172
173 format += 2;
174 }
175 else if (*format == 'h' || *format == 'l' || *format == 'L')
176 {
177 if (tptr < (tformat + sizeof(tformat) - 1))
178 *tptr++ = *format;
179
180 size = *format++;
181 }
182 else
183 size = 0;
184
185 if (!*format)
186 break;
187
188 if (tptr < (tformat + sizeof(tformat) - 1))
189 *tptr++ = *format;
190
191 type = *format++;
192 *tptr = '\0';
193
194 switch (type)
195 {
196 case 'E' : /* Floating point formats */
197 case 'G' :
198 case 'e' :
199 case 'f' :
200 case 'g' :
201 if ((width + 2) > sizeof(temp))
202 break;
203
204 sprintf(temp, tformat, va_arg(ap, double));
205
206 bytes += (int)strlen(temp);
207
208 if (bufptr)
209 {
210 if ((bufptr + strlen(temp)) > bufend)
211 {
212 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
213 bufptr = bufend;
214 }
215 else
216 {
217 strcpy(bufptr, temp);
218 bufptr += strlen(temp);
219 }
220 }
221 break;
222
223 case 'B' : /* Integer formats */
224 case 'X' :
225 case 'b' :
226 case 'd' :
227 case 'i' :
228 case 'o' :
229 case 'u' :
230 case 'x' :
231 if ((width + 2) > sizeof(temp))
232 break;
233
234 #ifdef HAVE_LONG_LONG
235 if (size == 'L')
236 sprintf(temp, tformat, va_arg(ap, long long));
237 else
238 #endif /* HAVE_LONG_LONG */
239 if (size == 'l')
240 sprintf(temp, tformat, va_arg(ap, long));
241 else
242 sprintf(temp, tformat, va_arg(ap, int));
243
244 bytes += (int)strlen(temp);
245
246 if (bufptr)
247 {
248 if ((bufptr + strlen(temp)) > bufend)
249 {
250 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
251 bufptr = bufend;
252 }
253 else
254 {
255 strcpy(bufptr, temp);
256 bufptr += strlen(temp);
257 }
258 }
259 break;
260
261 case 'p' : /* Pointer value */
262 if ((width + 2) > sizeof(temp))
263 break;
264
265 sprintf(temp, tformat, va_arg(ap, void *));
266
267 bytes += (int)strlen(temp);
268
269 if (bufptr)
270 {
271 if ((bufptr + strlen(temp)) > bufend)
272 {
273 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
274 bufptr = bufend;
275 }
276 else
277 {
278 strcpy(bufptr, temp);
279 bufptr += strlen(temp);
280 }
281 }
282 break;
283
284 case 'c' : /* Character or character array */
285 bytes += width;
286
287 if (bufptr)
288 {
289 if (width <= 1)
290 *bufptr++ = va_arg(ap, int);
291 else
292 {
293 if ((bufptr + width) > bufend)
294 width = (int)(bufend - bufptr);
295
296 memcpy(bufptr, va_arg(ap, char *), (size_t)width);
297 bufptr += width;
298 }
299 }
300 break;
301
302 case 's' : /* String */
303 if ((s = va_arg(ap, char *)) == NULL)
304 s = "(null)";
305
306 /*
307 * Copy the C string, replacing control chars and \ with
308 * C character escapes...
309 */
310
311 for (bufend --; *s && bufptr < bufend; s ++)
312 {
313 if (*s == '\n')
314 {
315 *bufptr++ = '\\';
316 *bufptr++ = 'n';
317 }
318 else if (*s == '\r')
319 {
320 *bufptr++ = '\\';
321 *bufptr++ = 'r';
322 }
323 else if (*s == '\t')
324 {
325 *bufptr++ = '\\';
326 *bufptr++ = 't';
327 }
328 else if (*s == '\\')
329 {
330 *bufptr++ = '\\';
331 *bufptr++ = '\\';
332 }
333 else if (*s == '\'')
334 {
335 *bufptr++ = '\\';
336 *bufptr++ = '\'';
337 }
338 else if (*s == '\"')
339 {
340 *bufptr++ = '\\';
341 *bufptr++ = '\"';
342 }
343 else if ((*s & 255) < ' ')
344 {
345 *bufptr++ = '\\';
346 *bufptr++ = '0';
347 *bufptr++ = '0' + *s / 8;
348 *bufptr++ = '0' + (*s & 7);
349 }
350 else
351 *bufptr++ = *s;
352 }
353
354 bufend ++;
355 break;
356
357 case 'n' : /* Output number of chars so far */
358 *(va_arg(ap, int *)) = bytes;
359 break;
360 }
361 }
362 else
363 {
364 bytes ++;
365
366 if (bufptr < bufend)
367 *bufptr++ = *format;
368
369 format ++;
370 }
371 }
372
373 /*
374 * Nul-terminate the string and return the number of characters needed.
375 */
376
377 *bufptr = '\0';
378
379 return (bytes);
380 }
381
382
383 /*
384 * '_cups_debug_printf()' - Write a formatted line to the log.
385 */
386
387 void
388 _cups_debug_printf(const char *format, /* I - Printf-style format string */
389 ...) /* I - Additional arguments as needed */
390 {
391 va_list ap; /* Pointer to arguments */
392 struct timeval curtime; /* Current time */
393 char buffer[2048]; /* Output buffer */
394 size_t bytes; /* Number of bytes in buffer */
395 const char *cups_debug_log;/* CUPS_DEBUG_LOG environment variable */
396
397
398 /*
399 * See if we need to do any logging...
400 */
401
402 if (!debug_init)
403 {
404 /*
405 * Get a lock on the debug initializer, then re-check in case another
406 * thread already did it...
407 */
408
409 pthread_mutex_lock(&debug_mutex);
410
411 if (!debug_init)
412 {
413 debug_init = 1;
414
415 if ((cups_debug_log = getenv("CUPS_DEBUG_LOG")) == NULL)
416 _cups_debug_fd = -1;
417 else if (!strcmp(cups_debug_log, "-"))
418 _cups_debug_fd = 2;
419 else
420 {
421 snprintf(buffer, sizeof(buffer), cups_debug_log, getpid());
422 _cups_debug_fd = open(buffer, O_WRONLY | O_APPEND | O_CREAT, 0644);
423 }
424 }
425
426 pthread_mutex_unlock(&debug_mutex);
427 }
428
429 if (_cups_debug_fd < 0)
430 return;
431
432 /*
433 * Format the message...
434 */
435
436 gettimeofday(&curtime, NULL);
437 snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d.%03d ",
438 (int)((curtime.tv_sec / 3600) % 24),
439 (int)((curtime.tv_sec / 60) % 60),
440 (int)(curtime.tv_sec % 60), (int)(curtime.tv_usec / 1000));
441
442 va_start(ap, format);
443 debug_vsnprintf(buffer + 13, sizeof(buffer) - 14, format, ap);
444 va_end(ap);
445
446 bytes = strlen(buffer);
447 if (buffer[bytes - 1] != '\n')
448 {
449 buffer[bytes] = '\n';
450 bytes ++;
451 buffer[bytes] = '\0';
452 }
453
454 /*
455 * Write it out...
456 */
457
458 write(_cups_debug_fd, buffer, bytes);
459 }
460
461
462 /*
463 * '_cups_debug_puts()' - Write a single line to the log.
464 */
465
466 void
467 _cups_debug_puts(const char *s) /* I - String to output */
468 {
469 _cups_debug_printf("%s\n", s);
470 }
471
472
473 #elif defined(__APPLE__)
474 /* Mac OS X needs these stubbed since we reference them in the libcups.exp file */
475 void _cups_debug_printf(const char *format, ...) {}
476 void _cups_debug_puts(const char *s) {}
477 #endif /* DEBUG */
478
479
480 /*
481 * End of "$Id$".
482 */