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
64
* (extended by -ENOSPC meaning "partial write")
67
/**************************************************************
68
* Partially stolen from OpenSSH's OpenBSD compat directory.
69
* (C) Patrick Powell, Brandon Long, Thomas Roessler,
70
* Michael Elkins, Ben Lindstrom
71
**************************************************************/
77
/* format flags - Bits */
78
#define DP_F_MINUS (1 << 0)
79
#define DP_F_PLUS (1 << 1)
80
#define DP_F_SPACE (1 << 2)
81
#define DP_F_NUM (1 << 3)
82
#define DP_F_ZERO (1 << 4)
83
#define DP_F_UPCASE (1 << 5)
84
#define DP_F_UNSIGNED (1 << 6)
85
#define DP_F_SQUOTE (1 << 7)
86
#define DP_F_DQUOTE (1 << 8)
87
#define DP_F_BACKSL (1 << 9)
88
#define DP_F_ARRAY (1 << 10)
89
#define DP_F_COLON (1 << 11)
91
/* Conversion Flags */
98
typedef void (*OutCh)(void *bp, char c);
102
fmtint(OutCh dopr_outch, void *bp,
103
long value, int base, int min, int max, int flags)
106
unsigned long uvalue;
109
int spadlen = 0; /* amount to space pad */
110
int zpadlen = 0; /* amount to zero pad */
118
if (!(flags & DP_F_UNSIGNED)) {
122
} else if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
124
} else if (flags & DP_F_SPACE) {
129
ctab = (flags & DP_F_UPCASE) ? "0123456789ABCDEF" : "0123456789abcdef";
131
convert[place++] = ctab[uvalue % (unsigned)base];
132
uvalue = uvalue / (unsigned)base;
135
zpadlen = max - place;
136
spadlen = min - (max > place ? max : place) -
137
(signvalue ? 1 : 0) - ((flags & DP_F_NUM) ? 2 : 0);
142
if (flags & DP_F_ZERO) {
143
zpadlen = zpadlen > spadlen ? zpadlen : spadlen;
146
if (flags & DP_F_MINUS)
147
spadlen = -spadlen; /* Left Justifty */
151
while (spadlen > 0) {
158
dopr_outch(bp, signvalue);
161
if (flags & DP_F_NUM) {
168
while (zpadlen > 0) {
175
dopr_outch(bp, convert[--place]);
177
/* Left Justified spaces */
178
while (spadlen < 0) {
190
putstr(OutCh dopr_outch, void *bp, str_t *st)
194
for (pt = 0; pt < st->len; pt++)
195
dopr_outch(bp, st->str[pt]);
198
static str_t _null_parents = { "(null)", 6 };
200
static str_t _null_dparents = { "((null))", 8 };
202
#if defined(PRINT_QUOTES) || defined(PRINT_ARRAYS)
203
static str_t _null_caps = { "NULL", 4 };
207
fmtstr(OutCh dopr_outch, void *bp,
208
const char *value, int flags, int min, int max)
210
int padlen, strln, curcol;
218
if (flags & (DP_F_SQUOTE | DP_F_DQUOTE))
219
putstr(dopr_outch, bp, &_null_caps);
222
putstr(dopr_outch, bp, &_null_parents);
226
for (strln = 0; (unsigned)strln < (unsigned)max && value[strln]; strln++);
227
padlen = min - strln;
230
if (flags & DP_F_MINUS)
231
padlen = -padlen; /* Left Justify */
233
for (; padlen > 0; padlen--)
237
if (flags & DP_F_SQUOTE)
238
dopr_outch(bp, '\'');
239
else if (flags & DP_F_DQUOTE)
241
else if (flags & DP_F_BACKSL)
242
for (lastcol = strln; lastcol && value[lastcol - 1] == ' '; lastcol--);
244
for (curcol = 0; curcol < strln; curcol++) {
247
if (flags & (DP_F_SQUOTE | DP_F_DQUOTE | DP_F_BACKSL)) {
249
case '\r': ch = 'r'; break;
250
case '\n': ch = 'n'; break;
251
case '\t': ch = 't'; break;
252
case '\a': ch = 'a'; break;
253
case '\b': ch = 'b'; break;
254
case '\v': ch = 'v'; break;
255
case '\f': ch = 'f'; break;
258
((unsigned char)ch >= 0x7f && (unsigned char)ch < 0xa0))
260
dopr_outch(bp, '\\');
261
fmtint(dopr_outch, bp, (unsigned char)ch, 8, 3, 3, DP_F_ZERO);
264
if ((ch == '\'' && (flags & DP_F_SQUOTE)) ||
265
(ch == '"' && (flags & DP_F_DQUOTE)) ||
266
(ch == ' ' && (flags & DP_F_BACKSL) &&
267
(!curcol || curcol >= lastcol)) ||
270
dopr_outch(bp, '\\');
276
dopr_outch(bp, '\\');
282
if (flags & DP_F_SQUOTE)
283
dopr_outch(bp, '\'');
284
else if (flags & DP_F_DQUOTE)
287
for (; padlen < 0; padlen++)
292
doPrint(OutCh dopr_outch, void *bp, const char *format, va_list args)
294
const char *strvalue;
296
str_t arpr, arsf, arepr, aresf, aresp, *arp;
300
int radix, min, max, flags, cflags, errn;
307
#define NCHR if (!(ch = *format++)) return
321
flags = cflags = min = 0;
326
case '#': flags |= DP_F_NUM; continue;
327
case '-': flags |= DP_F_MINUS; continue;
328
case '+': flags |= DP_F_PLUS; continue;
329
case ' ': flags |= DP_F_SPACE; continue;
330
case '0': flags |= DP_F_ZERO; continue;
332
case '"': flags |= DP_F_DQUOTE; continue;
333
case '\'': flags |= DP_F_SQUOTE; continue;
334
case '\\': flags |= DP_F_BACKSL; continue;
340
if (isdigit((unsigned char)ch)) {
341
min = 10 * min + (ch - '0');
344
} else if (ch == '*') {
345
min = va_arg(args, int);
354
if (isdigit((unsigned char)ch)) {
355
max = 10 * max + (ch - '0');
357
} else if (ch == '*') {
358
max = va_arg(args, int);
368
arpr.len = arsf.len = arepr.len = aresf.len = 0;
369
aresp.len = 1, aresp.str = " ";
372
if (isdigit((unsigned char)ch)) {
377
if (!isdigit((unsigned char)ch))
383
case ':': flags |= DP_F_COLON; continue;
384
case '*': arlen = va_arg(args, int); continue;
385
case '(': arp = &arpr; goto rar;
386
case ')': arp = &arsf; goto rar;
387
case '<': arp = &arepr; goto rar;
388
case '>': arp = &aresf; goto rar;
389
case '|': arp = &aresp;
397
arp->len = format - arp->str - 1;
400
aresp.len = 1, aresp.str = ",";
403
aresp.len = 0, arpr.len = arepr.len = 1, arsf.len = 2;
404
arpr.str = "{", arepr.str = " ", arsf.str = " }";
433
strvalue = (errn == -ENOSPC) ? "partial write" : strerror(errn);
434
fmtstr(dopr_outch, bp, strvalue, flags, min, max);
437
dopr_outch(bp, va_arg(args, int));
444
strvalue = va_arg(args, char *);
445
fmtstr(dopr_outch, bp, strvalue, flags, min, max);
449
flags |= DP_F_UNSIGNED;
455
flags |= DP_F_UPCASE;
457
flags |= DP_F_UNSIGNED;
461
if (flags & DP_F_ARRAY) {
462
if (!(arptr = va_arg(args, void *))) {
463
putstr(dopr_outch, bp,
464
arpr.len ? &_null_caps : &_null_dparents);
469
case DP_C_STR: while (((char **)arptr)[arlen]) arlen++; break;
470
case DP_C_BYTE: while (((unsigned char *)arptr)[arlen] != (unsigned char)-1) arlen++; break;
471
case DP_C_SHORT: while (((unsigned short int *)arptr)[arlen] != (unsigned short int)-1) arlen++; break;
472
case DP_C_LONG: while (((unsigned long int *)arptr)[arlen] != (unsigned long int)-1) arlen++; break;
473
default: while (((unsigned int *)arptr)[arlen] != (unsigned int)-1) arlen++; break;
476
if (flags & DP_F_COLON) {
477
fmtint(dopr_outch, bp, (long)arlen, 10, 0, -1, DP_F_UNSIGNED);
481
putstr(dopr_outch, bp, &arpr);
482
for (aridx = 0; aridx < (unsigned)arlen; aridx++) {
484
putstr(dopr_outch, bp, &aresp);
485
putstr(dopr_outch, bp, &arepr);
486
if (cflags == DP_C_STR) {
487
strvalue = ((char **)arptr)[aridx];
488
fmtstr(dopr_outch, bp, strvalue, flags, min, max);
490
if (flags & DP_F_UNSIGNED) {
492
case DP_C_BYTE: value = ((unsigned char *)arptr)[aridx]; break;
493
case DP_C_SHORT: value = ((unsigned short int *)arptr)[aridx]; break;
494
case DP_C_LONG: value = ((unsigned long int *)arptr)[aridx]; break;
495
default: value = ((unsigned int *)arptr)[aridx]; break;
499
case DP_C_BYTE: value = ((signed char *)arptr)[aridx]; break;
500
case DP_C_SHORT: value = ((short int *)arptr)[aridx]; break;
501
case DP_C_LONG: value = ((long int *)arptr)[aridx]; break;
502
default: value = ((int *)arptr)[aridx]; break;
505
fmtint(dopr_outch, bp, value, radix, min, max, flags);
507
putstr(dopr_outch, bp, &aresf);
509
putstr(dopr_outch, bp, &arsf);
512
if (cflags == DP_C_STR) {
513
strvalue = va_arg(args, char *);
514
fmtstr(dopr_outch, bp, strvalue, flags, min, max);
517
if (flags & DP_F_UNSIGNED) {
519
case DP_C_LONG: value = va_arg(args, unsigned long int); break;
520
default: value = va_arg(args, unsigned int); break;
524
case DP_C_LONG: value = va_arg(args, long int); break;
525
default: value = va_arg(args, int); break;
528
fmtint(dopr_outch, bp, value, radix, min, max, flags);
535
value = (long)va_arg(args, void *);
536
fmtint(dopr_outch, bp, value, 16, sizeof(long) * 2 + 2,
537
max, flags | DP_F_UNSIGNED | DP_F_ZERO | DP_F_NUM);
543
/* ########## end of printf core implementation ########## */
547
* Logging function for xdm and helper programs.
557
# define InitLog() openlog(LOG_NAME, LOG_PID, LOG_DAEMON)
559
# define InitLog() openlog(prog, LOG_PID, LOG_DAEMON)
561
static int lognums[] = { LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR, LOG_CRIT };
563
# define InitLog() while(0)
566
static const char *lognams[] = { "debug", "info", "warning", "error", "panic" };
573
strftime(dbuf, 20, "%b %e %H:%M:%S", localtime(&tim));
576
#if defined(LOG_DEBUG_MASK) || defined(USE_SYSLOG)
577
STATIC int debugLevel;
580
#define OOMSTR "Out of memory. Expect problems.\n"
589
if (last + 100 > tnow) { /* don't log bursts */
595
if (!(debugLevel & DEBUG_NOSYSLOG))
596
syslog(LOG_CRIT, OOMSTR);
601
char dbuf[24], sbuf[128];
603
el = sprintf(sbuf, "%s "
605
LOG_NAME "[%ld]: " OOMSTR, dbuf,
607
"%s[%ld]: " OOMSTR, dbuf, prog,
616
int clen, blen, type;
621
flush_OCL(OCLBuf *oclbp)
625
if (!(debugLevel & DEBUG_NOSYSLOG))
626
syslog(lognums[oclbp->type], "%.*s", oclbp->clen, oclbp->buf);
630
oclbp->buf[oclbp->clen] = '\n';
631
write(2, oclbp->buf, oclbp->clen + 1);
638
outCh_OCL(void *bp, char c)
640
OCLBuf *oclbp = (OCLBuf *)bp;
647
if (oclbp->clen >= oclbp->blen - 1) {
648
if (oclbp->buf == oclbp->lmbuf) {
653
nlen = oclbp->blen * 3 / 2 + 128;
654
nbuf = Realloc(oclbp->buf, nlen);
660
oclbp->buf = oclbp->lmbuf;
661
oclbp->blen = sizeof(oclbp->lmbuf);
665
if (!oclbp->clen && (debugLevel & DEBUG_NOSYSLOG)) {
671
oclbp->clen = sprintf(oclbp->buf, "%s "
673
LOG_NAME "[%ld] %s: ", dbuf,
675
"%s[%ld] %s: ", dbuf, prog,
677
(long)getpid(), lognams[oclbp->type]);
679
oclbp->buf[oclbp->clen++] = c;
684
logger(int type, const char *fmt, va_list args)
689
oclb.blen = oclb.clen = 0;
691
doPrint(outCh_OCL, &oclb, fmt, args);
692
/* no flush, every message is supposed to be \n-terminated */
693
if (oclb.buf && oclb.buf != oclb.lmbuf)
697
#ifdef LOG_DEBUG_MASK
699
debug(const char *fmt, ...)
701
if (debugLevel & LOG_DEBUG_MASK) {
703
int olderrno = errno;
705
logger(DM_DEBUG, fmt, args);
714
logInfo(const char *fmt, ...)
719
logger(DM_INFO, fmt, args);
726
logWarn(const char *fmt, ...)
731
logger(DM_WARN, fmt, args);
738
logError(const char *fmt, ...)
743
logger(DM_ERR, fmt, args);
748
#ifdef LOG_PANIC_EXIT
750
logPanic(const char *fmt, ...)
755
logger(DM_PANIC, fmt, args);
757
exit(LOG_PANIC_EXIT);
761
#endif /* NO_LOGGER */
767
int clen, blen, tlen;
771
outCh_OCF(void *bp, char c)
773
OCFBuf *ocfbp = (OCFBuf *)bp;
778
if (ocfbp->clen >= ocfbp->blen) {
781
nlen = ocfbp->blen * 3 / 2 + 100;
782
nbuf = Realloc(ocfbp->buf, nlen);
793
ocfbp->buf[ocfbp->clen++] = c;
797
FdPrintf(int fd, const char *fmt, ...)
800
OCFBuf ocfb = { 0, 0, 0, -1 };
803
doPrint(outCh_OCF, &ocfb, fmt, args);
806
debug("FdPrintf %\".*s to %d\n", ocfb.clen, ocfb.buf, fd);
807
(void)write(fd, ocfb.buf, ocfb.clen);
813
#endif /* NEED_FDPRINTF */
819
int clen, blen, tlen;
823
outCh_OCA(void *bp, char c)
825
OCABuf *ocabp = (OCABuf *)bp;
830
if (ocabp->clen >= ocabp->blen) {
833
nlen = ocabp->blen * 3 / 2 + 100;
834
nbuf = Realloc(ocabp->buf, nlen);
845
ocabp->buf[ocabp->clen++] = c;
849
VASPrintf(char **strp, const char *fmt, va_list args)
851
OCABuf ocab = { 0, 0, 0, -1 };
853
doPrint(outCh_OCA, &ocab, fmt, args);
855
*strp = Realloc(ocab.buf, ocab.clen);
862
ASPrintf(char **strp, const char *fmt, ...)
868
len = VASPrintf(strp, fmt, args);
873
#endif /* NEED_ASPRINTF */