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