3 Copyright 2001,2002,2004 Oswald Buddenhagen <ossi@kde.org>
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of a copyright holder shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from the copyright holder.
30 * xdm - display manager daemon
31 * Author: Keith Packard, MIT X Consortium
33 * printf.c - working horse of error.c
37 * NOTE: this file is meant to be included, not linked,
38 * so it can be used in the helper programs without much voodoo.
41 /* ########## printf core implementation with some extensions ########## */
43 * How to use the extensions:
44 * - put ' or " in the flags field to quote a string with this char and
45 * escape special characters (only available, if PRINT_QUOTES is defined)
46 * - put \\ in the flags field to quote special characters and leading and
47 * trailing spaces (only available, if PRINT_QUOTES is defined)
48 * - arrays (only available, if PRINT_ARRAYS is defined)
49 * - the array modifier [ comes after the maximal field width specifier
50 * - the array length can be specified literally, with the '*' modifier
51 * (in which case an argument is expected) or will be automatically
52 * determined (stop values are -1 for ints and 0 for strings)
53 * - these modifiers expect their argument to be an in-line string quoted
54 * with an arbitrary character:
55 * - (, ) -> array pre-/suf-fix; default ""
56 * - <, > -> element pre-/suf-fix; default ""
57 * - | -> element separator; default " "
58 * - these modifiers expect no argument:
59 * - : -> print '<number of elements>: ' before an array
60 * - , -> short for |','
61 * - { -> short for ('{')' }'<' '|''
62 * - the pointer to the array is the last argument to the format
63 * - the %m conversion from syslog() is supported
66 /**************************************************************
67 * Partially stolen from OpenSSH's OpenBSD compat directory.
68 * (C) Patrick Powell, Brandon Long, Thomas Roessler,
69 * Michael Elkins, Ben Lindstrom
70 **************************************************************/
76 /* format flags - Bits */
77 #define DP_F_MINUS (1 << 0)
78 #define DP_F_PLUS (1 << 1)
79 #define DP_F_SPACE (1 << 2)
80 #define DP_F_NUM (1 << 3)
81 #define DP_F_ZERO (1 << 4)
82 #define DP_F_UPCASE (1 << 5)
83 #define DP_F_UNSIGNED (1 << 6)
84 #define DP_F_SQUOTE (1 << 7)
85 #define DP_F_DQUOTE (1 << 8)
86 #define DP_F_BACKSL (1 << 9)
87 #define DP_F_ARRAY (1 << 10)
88 #define DP_F_COLON (1 << 11)
90 /* Conversion Flags */
97 typedef void (*OutCh
)( void *bp
, char c
);
101 fmtint( OutCh dopr_outch
, void *bp
,
102 long value
, int base
, int min
, int max
, int flags
)
105 unsigned long uvalue
;
108 int spadlen
= 0; /* amount to space pad */
109 int zpadlen
= 0; /* amount to zero pad */
117 if (!(flags
& DP_F_UNSIGNED
)) {
121 } else if (flags
& DP_F_PLUS
) /* Do a sign (+/i) */
123 else if (flags
& DP_F_SPACE
)
127 ctab
= (flags
& DP_F_UPCASE
) ? "0123456789ABCDEF" : "0123456789abcdef";
129 convert
[place
++] = ctab
[uvalue
% (unsigned)base
];
130 uvalue
= uvalue
/ (unsigned)base
;
133 zpadlen
= max
- place
;
134 spadlen
= min
- (max
> place
? max
: place
) -
135 (signvalue
? 1 : 0) - ((flags
& DP_F_NUM
) ? 2 : 0);
140 if (flags
& DP_F_ZERO
) {
141 zpadlen
= zpadlen
> spadlen
? zpadlen
: spadlen
;
144 if (flags
& DP_F_MINUS
)
145 spadlen
= -spadlen
; /* Left Justifty */
149 while (spadlen
> 0) {
150 dopr_outch( bp
, ' ' );
156 dopr_outch( bp
, signvalue
);
159 if (flags
& DP_F_NUM
) {
160 dopr_outch( bp
, '0' );
161 dopr_outch( bp
, 'x' );
166 while (zpadlen
> 0) {
167 dopr_outch( bp
, '0' );
173 dopr_outch( bp
, convert
[--place
] );
175 /* Left Justified spaces */
176 while (spadlen
< 0) {
177 dopr_outch( bp
, ' ' );
188 putstr( OutCh dopr_outch
, void *bp
, str_t
*st
)
192 for (pt
= 0; pt
< st
->len
; pt
++)
193 dopr_outch( bp
, st
->str
[pt
] );
196 static str_t _null_parents
= { "(null)", 6 };
198 static str_t _null_dparents
= { "((null))", 8 };
200 #if defined(PRINT_QUOTES) || defined(PRINT_ARRAYS)
201 static str_t _null_caps
= { "NULL", 4 };
205 fmtstr( OutCh dopr_outch
, void *bp
,
206 const char *value
, int flags
, int min
, int max
)
208 int padlen
, strln
, curcol
;
216 if (flags
& (DP_F_SQUOTE
| DP_F_DQUOTE
))
217 putstr( dopr_outch
, bp
, &_null_caps
);
220 putstr( dopr_outch
, bp
, &_null_parents
);
224 for (strln
= 0; (unsigned)strln
< (unsigned)max
&& value
[strln
]; strln
++);
225 padlen
= min
- strln
;
228 if (flags
& DP_F_MINUS
)
229 padlen
= -padlen
; /* Left Justify */
231 for (; padlen
> 0; padlen
--)
232 dopr_outch( bp
, ' ' );
235 if (flags
& DP_F_SQUOTE
)
236 dopr_outch( bp
, '\'' );
237 else if (flags
& DP_F_DQUOTE
)
238 dopr_outch( bp
, '"');
239 else if (flags
& DP_F_BACKSL
)
240 for (lastcol
= strln
; lastcol
&& value
[lastcol
- 1] == ' '; lastcol
--);
242 for (curcol
= 0; curcol
< strln
; curcol
++) {
245 if (flags
& (DP_F_SQUOTE
| DP_F_DQUOTE
| DP_F_BACKSL
)) {
247 case '\r': ch
= 'r'; break;
248 case '\n': ch
= 'n'; break;
249 case '\t': ch
= 't'; break;
250 case '\a': ch
= 'a'; break;
251 case '\b': ch
= 'b'; break;
252 case '\v': ch
= 'v'; break;
253 case '\f': ch
= 'f'; break;
256 ((unsigned char)ch
>= 0x7f && (unsigned char)ch
< 0xa0))
258 dopr_outch( bp
, '\\' );
259 fmtint( dopr_outch
, bp
, (unsigned char)ch
, 8, 3, 3, DP_F_ZERO
);
262 if ((ch
== '\'' && (flags
& DP_F_SQUOTE
)) ||
263 (ch
== '"' && (flags
& DP_F_DQUOTE
) ) ||
264 (ch
== ' ' && (flags
& DP_F_BACKSL
) &&
265 (!curcol
|| curcol
>= lastcol
)) ||
267 dopr_outch( bp
, '\\' );
268 dopr_outch( bp
, ch
);
272 dopr_outch( bp
, '\\' );
275 dopr_outch( bp
, ch
);
278 if (flags
& DP_F_SQUOTE
)
279 dopr_outch( bp
, '\'' );
280 else if (flags
& DP_F_DQUOTE
)
281 dopr_outch( bp
, '"' );
283 for (; padlen
< 0; padlen
++)
284 dopr_outch( bp
, ' ' );
288 doPrint( OutCh dopr_outch
, void *bp
, const char *format
, va_list args
)
290 const char *strvalue
;
292 str_t arpr
, arsf
, arepr
, aresf
, aresp
, *arp
;
296 int radix
, min
, max
, flags
, cflags
, errn
;
303 #define NCHR if (!(ch = *format++)) return
317 flags
= cflags
= min
= 0;
322 case '#': flags
|= DP_F_NUM
; continue;
323 case '-': flags
|= DP_F_MINUS
; continue;
324 case '+': flags
|= DP_F_PLUS
; continue;
325 case ' ': flags
|= DP_F_SPACE
; continue;
326 case '0': flags
|= DP_F_ZERO
; continue;
328 case '"': flags
|= DP_F_DQUOTE
; continue;
329 case '\'': flags
|= DP_F_SQUOTE
; continue;
330 case '\\': flags
|= DP_F_BACKSL
; continue;
336 if (isdigit( (unsigned char)ch
)) {
337 min
= 10 * min
+ (ch
- '0');
340 } else if (ch
== '*') {
341 min
= va_arg( args
, int );
350 if (isdigit( (unsigned char)ch
)) {
351 max
= 10 * max
+ (ch
- '0');
353 } else if (ch
== '*') {
354 max
= va_arg( args
, int );
364 arpr
.len
= arsf
.len
= arepr
.len
= aresf
.len
= 0;
365 aresp
.len
= 1, aresp
.str
= " ";
368 if (isdigit( (unsigned char)ch
)) {
373 if (!isdigit( (unsigned char)ch
))
379 case ':': flags
|= DP_F_COLON
; continue;
380 case '*': arlen
= va_arg( args
, int ); continue;
381 case '(': arp
= &arpr
; goto rar
;
382 case ')': arp
= &arsf
; goto rar
;
383 case '<': arp
= &arepr
; goto rar
;
384 case '>': arp
= &aresf
; goto rar
;
385 case '|': arp
= &aresp
;
393 arp
->len
= format
- arp
->str
- 1;
396 aresp
.len
= 1, aresp
.str
= ",";
399 aresp
.len
= 0, arpr
.len
= arepr
.len
= 1, arsf
.len
= 2;
400 arpr
.str
= "{", arepr
.str
= " ", arsf
.str
= " }";
426 dopr_outch( bp
, ch
);
429 fmtstr( dopr_outch
, bp
, strerror( errn
), flags
, min
, max
);
432 dopr_outch( bp
, va_arg( args
, int ) );
439 strvalue
= va_arg( args
, char * );
440 fmtstr( dopr_outch
, bp
, strvalue
, flags
, min
, max
);
444 flags
|= DP_F_UNSIGNED
;
450 flags
|= DP_F_UPCASE
;
452 flags
|= DP_F_UNSIGNED
;
456 if (flags
& DP_F_ARRAY
) {
457 if (!(arptr
= va_arg( args
, void * )))
458 putstr( dopr_outch
, bp
,
459 arpr
.len
? &_null_caps
: &_null_dparents
);
464 case DP_C_STR
: while (((char **)arptr
)[arlen
]) arlen
++; break;
465 case DP_C_BYTE
: while (((unsigned char *)arptr
)[arlen
] != (unsigned char)-1) arlen
++; break;
466 case DP_C_SHORT
: while (((unsigned short int *)arptr
)[arlen
] != (unsigned short int)-1) arlen
++; break;
467 case DP_C_LONG
: while (((unsigned long int *)arptr
)[arlen
] != (unsigned long int)-1) arlen
++; break;
468 default: while (((unsigned int *)arptr
)[arlen
] != (unsigned int)-1) arlen
++; break;
471 if (flags
& DP_F_COLON
) {
472 fmtint( dopr_outch
, bp
, (long)arlen
, 10, 0, -1, DP_F_UNSIGNED
);
473 dopr_outch( bp
, ':' );
474 dopr_outch( bp
, ' ' );
476 putstr( dopr_outch
, bp
, &arpr
);
477 for (aridx
= 0; aridx
< (unsigned)arlen
; aridx
++) {
479 putstr( dopr_outch
, bp
, &aresp
);
480 putstr( dopr_outch
, bp
, &arepr
);
481 if (cflags
== DP_C_STR
) {
482 strvalue
= ((char **)arptr
)[aridx
];
483 fmtstr( dopr_outch
, bp
, strvalue
, flags
, min
, max
);
485 if (flags
& DP_F_UNSIGNED
) {
487 case DP_C_BYTE
: value
= ((unsigned char *)arptr
)[aridx
]; break;
488 case DP_C_SHORT
: value
= ((unsigned short int *)arptr
)[aridx
]; break;
489 case DP_C_LONG
: value
= ((unsigned long int *)arptr
)[aridx
]; break;
490 default: value
= ((unsigned int *)arptr
)[aridx
]; break;
494 case DP_C_BYTE
: value
= ((signed char *)arptr
)[aridx
]; break;
495 case DP_C_SHORT
: value
= ((short int *)arptr
)[aridx
]; break;
496 case DP_C_LONG
: value
= ((long int *)arptr
)[aridx
]; break;
497 default: value
= ((int *)arptr
)[aridx
]; break;
500 fmtint( dopr_outch
, bp
, value
, radix
, min
, max
, flags
);
502 putstr( dopr_outch
, bp
, &aresf
);
504 putstr( dopr_outch
, bp
, &arsf
);
507 if (cflags
== DP_C_STR
) {
508 strvalue
= va_arg( args
, char * );
509 fmtstr( dopr_outch
, bp
, strvalue
, flags
, min
, max
);
512 if (flags
& DP_F_UNSIGNED
) {
514 case DP_C_LONG
: value
= va_arg( args
, unsigned long int ); break;
515 default: value
= va_arg( args
, unsigned int ); break;
519 case DP_C_LONG
: value
= va_arg( args
, long int ); break;
520 default: value
= va_arg( args
, int ); break;
523 fmtint( dopr_outch
, bp
, value
, radix
, min
, max
, flags
);
530 value
= (long)va_arg( args
, void * );
531 fmtint( dopr_outch
, bp
, value
, 16, sizeof(long) * 2 + 2,
532 max
, flags
| DP_F_UNSIGNED
| DP_F_ZERO
| DP_F_NUM
);
538 /* ########## end of printf core implementation ########## */
542 * Logging function for xdm and helper programs.
552 # define InitLog() openlog(LOG_NAME, LOG_PID, LOG_DAEMON)
554 # define InitLog() openlog(prog, LOG_PID, LOG_DAEMON)
556 static int lognums
[] = { LOG_DEBUG
, LOG_INFO
, LOG_WARNING
, LOG_ERR
, LOG_CRIT
};
558 # define InitLog() while(0)
561 static const char *lognams
[] = { "debug", "info", "warning", "error", "panic" };
564 logTime( char *dbuf
)
568 strftime( dbuf
, 20, "%b %e %H:%M:%S", localtime( &tim
) );
571 #if defined(LOG_DEBUG_MASK) || defined(USE_SYSLOG)
572 STATIC
int debugLevel
;
575 #define OOMSTR "Out of memory. Expect problems.\n"
584 if (last
+ 100 > tnow
) { /* don't log bursts */
590 if (!(debugLevel
& DEBUG_NOSYSLOG
))
591 syslog( LOG_CRIT
, OOMSTR
);
596 char dbuf
[24], sbuf
[128];
598 el
= sprintf( sbuf
, "%s "
600 LOG_NAME
"[%ld]: " OOMSTR
, dbuf
,
602 "%s[%ld]: " OOMSTR
, dbuf
, prog
,
605 write( 2, sbuf
, el
);
611 int clen
, blen
, type
;
616 flush_OCL( OCLBuf
*oclbp
)
620 if (!(debugLevel
& DEBUG_NOSYSLOG
))
621 syslog( lognums
[oclbp
->type
], "%.*s", oclbp
->clen
, oclbp
->buf
);
625 oclbp
->buf
[oclbp
->clen
] = '\n';
626 write( 2, oclbp
->buf
, oclbp
->clen
+ 1 );
633 outCh_OCL( void *bp
, char c
)
635 OCLBuf
*oclbp
= (OCLBuf
*)bp
;
642 if (oclbp
->clen
>= oclbp
->blen
- 1) {
643 if (oclbp
->buf
== oclbp
->lmbuf
) {
648 nlen
= oclbp
->blen
* 3 / 2 + 128;
649 nbuf
= Realloc( oclbp
->buf
, nlen
);
655 oclbp
->buf
= oclbp
->lmbuf
;
656 oclbp
->blen
= sizeof(oclbp
->lmbuf
);
660 if (!oclbp
->clen
&& (debugLevel
& DEBUG_NOSYSLOG
)) {
666 oclbp
->clen
= sprintf( oclbp
->buf
, "%s "
668 LOG_NAME
"[%ld] %s: ", dbuf
,
670 "%s[%ld] %s: ", dbuf
, prog
,
672 (long)getpid(), lognams
[oclbp
->type
] );
674 oclbp
->buf
[oclbp
->clen
++] = c
;
679 logger( int type
, const char *fmt
, va_list args
)
684 oclb
.blen
= oclb
.clen
= 0;
686 doPrint( outCh_OCL
, &oclb
, fmt
, args
);
687 /* no flush, every message is supposed to be \n-terminated */
688 if (oclb
.buf
&& oclb
.buf
!= oclb
.lmbuf
)
692 #ifdef LOG_DEBUG_MASK
694 debug( const char *fmt
, ... )
696 if (debugLevel
& LOG_DEBUG_MASK
) {
698 int olderrno
= errno
;
699 va_start( args
, fmt
);
700 logger( DM_DEBUG
, fmt
, args
);
709 logInfo( const char *fmt
, ... )
713 va_start( args
, fmt
);
714 logger( DM_INFO
, fmt
, args
);
721 logWarn( const char *fmt
, ... )
725 va_start( args
, fmt
);
726 logger( DM_WARN
, fmt
, args
);
733 logError( const char *fmt
, ... )
737 va_start( args
, fmt
);
738 logger( DM_ERR
, fmt
, args
);
743 #ifdef LOG_PANIC_EXIT
745 logPanic( const char *fmt
, ... )
749 va_start( args
, fmt
);
750 logger( DM_PANIC
, fmt
, args
);
752 exit( LOG_PANIC_EXIT
);
756 #endif /* NO_LOGGER */
762 int clen
, blen
, tlen
;
766 outCh_OCF( void *bp
, char c
)
768 OCFBuf
*ocfbp
= (OCFBuf
*)bp
;
773 if (ocfbp
->clen
>= ocfbp
->blen
) {
776 nlen
= ocfbp
->blen
* 3 / 2 + 100;
777 nbuf
= Realloc( ocfbp
->buf
, nlen
);
788 ocfbp
->buf
[ocfbp
->clen
++] = c
;
792 FdPrintf( int fd
, const char *fmt
, ... )
795 OCFBuf ocfb
= { 0, 0, 0, -1 };
797 va_start( args
, fmt
);
798 doPrint( outCh_OCF
, &ocfb
, fmt
, args
);
801 debug( "FdPrintf %\".*s to %d\n", ocfb
.clen
, ocfb
.buf
, fd
);
802 (void)write( fd
, ocfb
.buf
, ocfb
.clen
);
808 #endif /* NEED_FDPRINTF */
814 int clen
, blen
, tlen
;
818 outCh_OCA( void *bp
, char c
)
820 OCABuf
*ocabp
= (OCABuf
*)bp
;
825 if (ocabp
->clen
>= ocabp
->blen
) {
828 nlen
= ocabp
->blen
* 3 / 2 + 100;
829 nbuf
= Realloc( ocabp
->buf
, nlen
);
840 ocabp
->buf
[ocabp
->clen
++] = c
;
844 VASPrintf( char **strp
, const char *fmt
, va_list args
)
846 OCABuf ocab
= { 0, 0, 0, -1 };
848 doPrint( outCh_OCA
, &ocab
, fmt
, args
);
849 outCh_OCA( &ocab
, 0 );
850 *strp
= Realloc( ocab
.buf
, ocab
.clen
);
857 ASPrintf( char **strp
, const char *fmt
, ... )
862 va_start( args
, fmt
);
863 len
= VASPrintf( strp
, fmt
, args
);
868 #endif /* NEED_ASPRINTF */