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