|
|
|
/*
|
|
|
|
|
|
|
|
Copyright 2001,2002,2004 Oswald Buddenhagen <ossi@kde.org>
|
|
|
|
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
|
|
the above copyright notice appear in all copies and that both that
|
|
|
|
copyright notice and this permission notice appear in supporting
|
|
|
|
documentation.
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
|
|
in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
|
|
IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
|
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
|
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
|
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
Except as contained in this notice, the name of a copyright holder shall
|
|
|
|
not be used in advertising or otherwise to promote the sale, use or
|
|
|
|
other dealings in this Software without prior written authorization
|
|
|
|
from the copyright holder.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* xdm - display manager daemon
|
|
|
|
* Author: Keith Packard, MIT X Consortium
|
|
|
|
*
|
|
|
|
* printf.c - working horse of error.c
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NOTE: this file is meant to be included, not linked,
|
|
|
|
* so it can be used in the helper programs without much voodoo.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* ########## printf core implementation with some extensions ########## */
|
|
|
|
/*
|
|
|
|
* How to use the extensions:
|
|
|
|
* - put ' or " in the flags field to quote a string with this char and
|
|
|
|
* escape special characters (only available, if PRINT_QUOTES is defined)
|
|
|
|
* - put \\ in the flags field to quote special characters and leading and
|
|
|
|
* trailing spaces (only available, if PRINT_QUOTES is defined)
|
|
|
|
* - arrays (only available, if PRINT_ARRAYS is defined)
|
|
|
|
* - the array modifier [ comes after the maximal field width specifier
|
|
|
|
* - the array length can be specified literally, with the '*' modifier
|
|
|
|
* (in which case an argument is expected) or will be automatically
|
|
|
|
* determined (stop values are -1 for ints and 0 for strings)
|
|
|
|
* - these modifiers expect their argument to be an in-line string quoted
|
|
|
|
* with an arbitrary character:
|
|
|
|
* - (, ) -> array pre-/suf-fix; default ""
|
|
|
|
* - <, > -> element pre-/suf-fix; default ""
|
|
|
|
* - | -> element separator; default " "
|
|
|
|
* - these modifiers expect no argument:
|
|
|
|
* - : -> print '<number of elements>: ' before an array
|
|
|
|
* - , -> short for |','
|
|
|
|
* - { -> short for ('{')' }'<' '|''
|
|
|
|
* - the pointer to the array is the last argument to the format
|
|
|
|
* - the %m conversion from syslog() is supported
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**************************************************************
|
|
|
|
* Partially stolen from OpenSSH's OpenBSD compat directory.
|
|
|
|
* (C) Patrick Powell, Brandon Long, Thomas Roessler,
|
|
|
|
* Michael Elkins, Ben Lindstrom
|
|
|
|
**************************************************************/
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
/* format flags - Bits */
|
|
|
|
#define DP_F_MINUS (1 << 0)
|
|
|
|
#define DP_F_PLUS (1 << 1)
|
|
|
|
#define DP_F_SPACE (1 << 2)
|
|
|
|
#define DP_F_NUM (1 << 3)
|
|
|
|
#define DP_F_ZERO (1 << 4)
|
|
|
|
#define DP_F_UPCASE (1 << 5)
|
|
|
|
#define DP_F_UNSIGNED (1 << 6)
|
|
|
|
#define DP_F_SQUOTE (1 << 7)
|
|
|
|
#define DP_F_DQUOTE (1 << 8)
|
|
|
|
#define DP_F_BACKSL (1 << 9)
|
|
|
|
#define DP_F_ARRAY (1 << 10)
|
|
|
|
#define DP_F_COLON (1 << 11)
|
|
|
|
|
|
|
|
/* Conversion Flags */
|
|
|
|
#define DP_C_INT 0
|
|
|
|
#define DP_C_BYTE 1
|
|
|
|
#define DP_C_SHORT 2
|
|
|
|
#define DP_C_LONG 3
|
|
|
|
#define DP_C_STR 10
|
|
|
|
|
|
|
|
typedef void (*OutCh)( void *bp, char c );
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
fmtint( OutCh dopr_outch, void *bp,
|
|
|
|
long value, int base, int min, int max, int flags )
|
|
|
|
{
|
|
|
|
const char *ctab;
|
|
|
|
unsigned long uvalue;
|
|
|
|
int signvalue = 0;
|
|
|
|
int place = 0;
|
|
|
|
int spadlen = 0; /* amount to space pad */
|
|
|
|
int zpadlen = 0; /* amount to zero pad */
|
|
|
|
char convert[20];
|
|
|
|
|
|
|
|
if (max < 0)
|
|
|
|
max = 0;
|
|
|
|
|
|
|
|
uvalue = value;
|
|
|
|
|
|
|
|
if (!(flags & DP_F_UNSIGNED)) {
|
|
|
|
if (value < 0) {
|
|
|
|
signvalue = '-';
|
|
|
|
uvalue = -value;
|
|
|
|
} else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
|
|
|
|
signvalue = '+';
|
|
|
|
else if (flags & DP_F_SPACE)
|
|
|
|
signvalue = ' ';
|
|
|
|
}
|
|
|
|
|
|
|
|
ctab = (flags & DP_F_UPCASE) ? "0123456789ABCDEF" : "0123456789abcdef";
|
|
|
|
do {
|
|
|
|
convert[place++] = ctab[uvalue % (unsigned)base];
|
|
|
|
uvalue = uvalue / (unsigned)base;
|
|
|
|
} while (uvalue);
|
|
|
|
|
|
|
|
zpadlen = max - place;
|
|
|
|
spadlen = min - (max > place ? max : place) -
|
|
|
|
(signvalue ? 1 : 0) - ((flags & DP_F_NUM) ? 2 : 0);
|
|
|
|
if (zpadlen < 0)
|
|
|
|
zpadlen = 0;
|
|
|
|
if (spadlen < 0)
|
|
|
|
spadlen = 0;
|
|
|
|
if (flags & DP_F_ZERO) {
|
|
|
|
zpadlen = zpadlen > spadlen ? zpadlen : spadlen;
|
|
|
|
spadlen = 0;
|
|
|
|
}
|
|
|
|
if (flags & DP_F_MINUS)
|
|
|
|
spadlen = -spadlen; /* Left Justifty */
|
|
|
|
|
|
|
|
|
|
|
|
/* Spaces */
|
|
|
|
while (spadlen > 0) {
|
|
|
|
dopr_outch( bp, ' ' );
|
|
|
|
--spadlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sign */
|
|
|
|
if (signvalue)
|
|
|
|
dopr_outch( bp, signvalue );
|
|
|
|
|
|
|
|
/* Prefix */
|
|
|
|
if (flags & DP_F_NUM) {
|
|
|
|
dopr_outch( bp, '0' );
|
|
|
|
dopr_outch( bp, 'x' );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Zeros */
|
|
|
|
if (zpadlen > 0)
|
|
|
|
while (zpadlen > 0) {
|
|
|
|
dopr_outch( bp, '0' );
|
|
|
|
--zpadlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Digits */
|
|
|
|
while (place > 0)
|
|
|
|
dopr_outch( bp, convert[--place] );
|
|
|
|
|
|
|
|
/* Left Justified spaces */
|
|
|
|
while (spadlen < 0) {
|
|
|
|
dopr_outch( bp, ' ' );
|
|
|
|
++spadlen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
const char *str;
|
|
|
|
size_t len;
|
|
|
|
} str_t;
|
|
|
|
|
|
|
|
static void
|
|
|
|
putstr( OutCh dopr_outch, void *bp, str_t *st )
|
|
|
|
{
|
|
|
|
size_t pt;
|
|
|
|
|
|
|
|
for (pt = 0; pt < st->len; pt++)
|
|
|
|
dopr_outch( bp, st->str[pt] );
|
|
|
|
}
|
|
|
|
|
|
|
|
static str_t _null_parents = { "(null)", 6 };
|
|
|
|
#ifdef PRINT_ARRAYS
|
|
|
|
static str_t _null_dparents = { "((null))", 8 };
|
|
|
|
#endif
|
|
|
|
#if defined(PRINT_QUOTES) || defined(PRINT_ARRAYS)
|
|
|
|
static str_t _null_caps = { "NULL", 4 };
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void
|
|
|
|
fmtstr( OutCh dopr_outch, void *bp,
|
|
|
|
const char *value, int flags, int min, int max )
|
|
|
|
{
|
|
|
|
int padlen, strln, curcol;
|
|
|
|
#ifdef PRINT_QUOTES
|
|
|
|
int lastcol = 0;
|
|
|
|
#endif
|
|
|
|
char ch;
|
|
|
|
|
|
|
|
if (!value) {
|
|
|
|
#ifdef PRINT_QUOTES
|
|
|
|
if (flags & (DP_F_SQUOTE | DP_F_DQUOTE))
|
|
|
|
putstr( dopr_outch, bp, &_null_caps );
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
putstr( dopr_outch, bp, &_null_parents );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (strln = 0; (unsigned)strln < (unsigned)max && value[strln]; strln++);
|
|
|
|
padlen = min - strln;
|
|
|
|
if (padlen < 0)
|
|
|
|
padlen = 0;
|
|
|
|
if (flags & DP_F_MINUS)
|
|
|
|
padlen = -padlen; /* Left Justify */
|
|
|
|
|
|
|
|
for (; padlen > 0; padlen--)
|
|
|
|
dopr_outch( bp, ' ' );
|
|
|
|
#ifdef PRINT_QUOTES
|
|
|
|
# if 0 /* gcc's flow analyzer is not the smartest ... */
|
|
|
|
lastcol = 0;
|
|
|
|
# endif
|
|
|
|
if (flags & DP_F_SQUOTE)
|
|
|
|
dopr_outch( bp, '\'' );
|
|
|
|
else if (flags & DP_F_DQUOTE)
|
|
|
|
dopr_outch( bp, '"');
|
|
|
|
else if (flags & DP_F_BACKSL)
|
|
|
|
for (lastcol = strln; lastcol && value[lastcol - 1] == ' '; lastcol--);
|
|
|
|
#endif
|
|
|
|
for (curcol = 0; curcol < strln; curcol++) {
|
|
|
|
ch = value[curcol];
|
|
|
|
#ifdef PRINT_QUOTES
|
|
|
|
if (flags & (DP_F_SQUOTE | DP_F_DQUOTE | DP_F_BACKSL)) {
|
|
|
|
switch (ch) {
|
|
|
|
case '\r': ch = 'r'; break;
|
|
|
|
case '\n': ch = 'n'; break;
|
|
|
|
case '\t': ch = 't'; break;
|
|
|
|
case '\a': ch = 'a'; break;
|
|
|
|
case '\b': ch = 'b'; break;
|
|
|
|
case '\v': ch = 'v'; break;
|
|
|
|
case '\f': ch = 'f'; break;
|
|
|
|
default:
|
|
|
|
if (ch < 32 ||
|
|
|
|
((unsigned char)ch >= 0x7f && (unsigned char)ch < 0xa0))
|
|
|
|
{
|
|
|
|
dopr_outch( bp, '\\' );
|
|
|
|
fmtint( dopr_outch, bp, (unsigned char)ch, 8, 3, 3, DP_F_ZERO );
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
if ((ch == '\'' && (flags & DP_F_SQUOTE)) ||
|
|
|
|
(ch == '"' && (flags & DP_F_DQUOTE) ) ||
|
|
|
|
(ch == ' ' && (flags & DP_F_BACKSL) &&
|
|
|
|
(!curcol || curcol >= lastcol)) ||
|
|
|
|
ch == '\\')
|
|
|
|
dopr_outch( bp, '\\' );
|
|
|
|
dopr_outch( bp, ch );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dopr_outch( bp, '\\' );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
dopr_outch( bp, ch );
|
|
|
|
}
|
|
|
|
#ifdef PRINT_QUOTES
|
|
|
|
if (flags & DP_F_SQUOTE)
|
|
|
|
dopr_outch( bp, '\'' );
|
|
|
|
else if (flags & DP_F_DQUOTE)
|
|
|
|
dopr_outch( bp, '"' );
|
|
|
|
#endif
|
|
|
|
for (; padlen < 0; padlen++)
|
|
|
|
dopr_outch( bp, ' ' );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
DoPr( OutCh dopr_outch, void *bp, const char *format, va_list args )
|
|
|
|
{
|
|
|
|
const char *strvalue;
|
|
|
|
#ifdef PRINT_ARRAYS
|
|
|
|
str_t arpr, arsf, arepr, aresf, aresp, *arp;
|
|
|
|
void *arptr;
|
|
|
|
#endif
|
|
|
|
unsigned long value;
|
|
|
|
int radix = 0, min, max, flags, cflags, errn;
|
|
|
|
#ifdef PRINT_ARRAYS
|
|
|
|
int arlen = 0;
|
|
|
|
unsigned aridx;
|
|
|
|
char sch;
|
|
|
|
#endif
|
|
|
|
char ch;
|
|
|
|
#define NCHR if (!(ch = *format++)) return
|
|
|
|
|
|
|
|
#if 0 /* gcc's flow analyzer is not the smartest ... */
|
|
|
|
# ifdef PRINT_ARRAYS
|
|
|
|
arlen = 0;
|
|
|
|
# endif
|
|
|
|
radix = 0;
|
|
|
|
#endif
|
|
|
|
errn = errno;
|
|
|
|
for (;;) {
|
|
|
|
for (;;) {
|
|
|
|
NCHR;
|
|
|
|
if (ch == '%')
|
|
|
|
break;
|
|
|
|
dopr_outch (bp, ch);
|
|
|
|
}
|
|
|
|
flags = cflags = min = 0;
|
|
|
|
max = -1;
|
|
|
|
for (;;) {
|
|
|
|
NCHR;
|
|
|
|
switch (ch) {
|
|
|
|
case '#': flags |= DP_F_NUM; continue;
|
|
|
|
case '-': flags |= DP_F_MINUS; continue;
|
|
|
|
case '+': flags |= DP_F_PLUS; continue;
|
|
|
|
case ' ': flags |= DP_F_SPACE; continue;
|
|
|
|
case '0': flags |= DP_F_ZERO; continue;
|
|
|
|
#ifdef PRINT_QUOTES
|
|
|
|
case '"': flags |= DP_F_DQUOTE; continue;
|
|
|
|
case '\'': flags |= DP_F_SQUOTE; continue;
|
|
|
|
case '\\': flags |= DP_F_BACKSL; continue;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (;;) {
|
|
|
|
if (isdigit( (unsigned char)ch )) {
|
|
|
|
min = 10 * min + (ch - '0');
|
|
|
|
NCHR;
|
|
|
|
continue;
|
|
|
|
} else if (ch == '*') {
|
|
|
|
min = va_arg( args, int );
|
|
|
|
NCHR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ch == '.') {
|
|
|
|
max = 0;
|
|
|
|
for (;;) {
|
|
|
|
NCHR;
|
|
|
|
if (isdigit( (unsigned char)ch )) {
|
|
|
|
max = 10 * max + (ch - '0');
|
|
|
|
continue;
|
|
|
|
} else if (ch == '*') {
|
|
|
|
max = va_arg( args, int );
|
|
|
|
NCHR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef PRINT_ARRAYS
|
|
|
|
if (ch == '[') {
|
|
|
|
flags |= DP_F_ARRAY;
|
|
|
|
arlen = -1;
|
|
|
|
arpr.len = arsf.len = arepr.len = aresf.len = 0;
|
|
|
|
aresp.len = 1, aresp.str = " ";
|
|
|
|
for (;;) {
|
|
|
|
NCHR;
|
|
|
|
if (isdigit( (unsigned char)ch )) {
|
|
|
|
arlen = 0;
|
|
|
|
for (;;) {
|
|
|
|
arlen += (ch - '0');
|
|
|
|
NCHR;
|
|
|
|
if (!isdigit( (unsigned char)ch ))
|
|
|
|
break;
|
|
|
|
arlen *= 10;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch (ch) {
|
|
|
|
case ':': flags |= DP_F_COLON; continue;
|
|
|
|
case '*': arlen = va_arg( args, int ); continue;
|
|
|
|
case '(': arp = &arpr; goto rar;
|
|
|
|
case ')': arp = &arsf; goto rar;
|
|
|
|
case '<': arp = &arepr; goto rar;
|
|
|
|
case '>': arp = &aresf; goto rar;
|
|
|
|
case '|': arp = &aresp;
|
|
|
|
rar:
|
|
|
|
NCHR;
|
|
|
|
sch = ch;
|
|
|
|
arp->str = format;
|
|
|
|
do {
|
|
|
|
NCHR;
|
|
|
|
} while (ch != sch);
|
|
|
|
arp->len = format - arp->str - 1;
|
|
|
|
continue;
|
|
|
|
case ',':
|
|
|
|
aresp.len = 1, aresp.str = ",";
|
|
|
|
continue;
|
|
|
|
case '{':
|
|
|
|
aresp.len = 0, arpr.len = arepr.len = 1, arsf.len = 2;
|
|
|
|
arpr.str = "{", arepr.str = " ", arsf.str = " }";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
for (;;) {
|
|
|
|
switch (ch) {
|
|
|
|
case 'h':
|
|
|
|
cflags = DP_C_SHORT;
|
|
|
|
NCHR;
|
|
|
|
if (ch == 'h') {
|
|
|
|
cflags = DP_C_BYTE;
|
|
|
|
NCHR;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
case 'l':
|
|
|
|
cflags = DP_C_LONG;
|
|
|
|
NCHR;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (ch) {
|
|
|
|
case '%':
|
|
|
|
dopr_outch( bp, ch );
|
|
|
|
break;
|
|
|
|
case 'm':
|
|
|
|
fmtstr( dopr_outch, bp, strerror( errn ), flags, min, max );
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
dopr_outch( bp, va_arg( args, int ) );
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
#ifdef PRINT_ARRAYS
|
|
|
|
cflags = DP_C_STR;
|
|
|
|
goto printit;
|
|
|
|
#else
|
|
|
|
strvalue = va_arg( args, char * );
|
|
|
|
fmtstr( dopr_outch, bp, strvalue, flags, min, max );
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case 'u':
|
|
|
|
flags |= DP_F_UNSIGNED;
|
|
|
|
case 'd':
|
|
|
|
case 'i':
|
|
|
|
radix = 10;
|
|
|
|
goto printit;
|
|
|
|
case 'X':
|
|
|
|
flags |= DP_F_UPCASE;
|
|
|
|
case 'x':
|
|
|
|
flags |= DP_F_UNSIGNED;
|
|
|
|
radix = 16;
|
|
|
|
printit:
|
|
|
|
#ifdef PRINT_ARRAYS
|
|
|
|
if (flags & DP_F_ARRAY) {
|
|
|
|
if (!(arptr = va_arg( args, void * )))
|
|
|
|
putstr( dopr_outch, bp,
|
|
|
|
arpr.len ? &_null_caps : &_null_dparents );
|
|
|
|
else {
|
|
|
|
if (arlen == -1) {
|
|
|
|
arlen = 0;
|
|
|
|
switch (cflags) {
|
|
|
|
case DP_C_STR: while (((char **)arptr)[arlen]) arlen++; break;
|
|
|
|
case DP_C_BYTE: while (((unsigned char *)arptr)[arlen] != (unsigned char)-1) arlen++; break;
|
|
|
|
case DP_C_SHORT: while (((unsigned short int *)arptr)[arlen] != (unsigned short int)-1) arlen++; break;
|
|
|
|
case DP_C_LONG: while (((unsigned long int *)arptr)[arlen] != (unsigned long int)-1) arlen++; break;
|
|
|
|
default: while (((unsigned int *)arptr)[arlen] != (unsigned int)-1) arlen++; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (flags & DP_F_COLON) {
|
|
|
|
fmtint( dopr_outch, bp, (long)arlen, 10, 0, -1, DP_F_UNSIGNED );
|
|
|
|
dopr_outch( bp, ':' );
|
|
|
|
dopr_outch( bp, ' ' );
|
|
|
|
}
|
|
|
|
putstr( dopr_outch, bp, &arpr );
|
|
|
|
for (aridx = 0; aridx < (unsigned)arlen; aridx++) {
|
|
|
|
if (aridx)
|
|
|
|
putstr( dopr_outch, bp, &aresp );
|
|
|
|
putstr( dopr_outch, bp, &arepr );
|
|
|
|
if (cflags == DP_C_STR) {
|
|
|
|
strvalue = ((char **)arptr)[aridx];
|
|
|
|
fmtstr( dopr_outch, bp, strvalue, flags, min, max );
|
|
|
|
} else {
|
|
|
|
if (flags & DP_F_UNSIGNED) {
|
|
|
|
switch (cflags) {
|
|
|
|
case DP_C_BYTE: value = ((unsigned char *)arptr)[aridx]; break;
|
|
|
|
case DP_C_SHORT: value = ((unsigned short int *)arptr)[aridx]; break;
|
|
|
|
case DP_C_LONG: value = ((unsigned long int *)arptr)[aridx]; break;
|
|
|
|
default: value = ((unsigned int *)arptr)[aridx]; break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (cflags) {
|
|
|
|
case DP_C_BYTE: value = ((signed char *)arptr)[aridx]; break;
|
|
|
|
case DP_C_SHORT: value = ((short int *)arptr)[aridx]; break;
|
|
|
|
case DP_C_LONG: value = ((long int *)arptr)[aridx]; break;
|
|
|
|
default: value = ((int *)arptr)[aridx]; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fmtint( dopr_outch, bp, value, radix, min, max, flags );
|
|
|
|
}
|
|
|
|
putstr( dopr_outch, bp, &aresf );
|
|
|
|
}
|
|
|
|
putstr( dopr_outch, bp, &arsf );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (cflags == DP_C_STR) {
|
|
|
|
strvalue = va_arg( args, char * );
|
|
|
|
fmtstr( dopr_outch, bp, strvalue, flags, min, max );
|
|
|
|
} else {
|
|
|
|
#endif
|
|
|
|
if (flags & DP_F_UNSIGNED) {
|
|
|
|
switch (cflags) {
|
|
|
|
case DP_C_LONG: value = va_arg( args, unsigned long int ); break;
|
|
|
|
default: value = va_arg( args, unsigned int ); break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (cflags) {
|
|
|
|
case DP_C_LONG: value = va_arg( args, long int ); break;
|
|
|
|
default: value = va_arg( args, int ); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fmtint( dopr_outch, bp, value, radix, min, max, flags );
|
|
|
|
#ifdef PRINT_ARRAYS
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
value = (long)va_arg( args, void * );
|
|
|
|
fmtint( dopr_outch, bp, value, 16, sizeof(long) * 2 + 2,
|
|
|
|
max, flags | DP_F_UNSIGNED | DP_F_ZERO | DP_F_NUM );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ########## end of printf core implementation ########## */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Logging function for xdm and helper programs.
|
|
|
|
*/
|
|
|
|
#ifndef NO_LOGGER
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#ifdef USE_SYSLOG
|
|
|
|
# include <syslog.h>
|
|
|
|
# ifdef LOG_NAME
|
|
|
|
# define InitLog() openlog(LOG_NAME, LOG_PID, LOG_DAEMON)
|
|
|
|
# else
|
|
|
|
# define InitLog() openlog(prog, LOG_PID, LOG_DAEMON)
|
|
|
|
# endif
|
|
|
|
static int lognums[] = { LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR, LOG_CRIT };
|
|
|
|
#else
|
|
|
|
# define InitLog() while(0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static const char *lognams[] = { "debug", "info", "warning", "error", "panic" };
|
|
|
|
|
|
|
|
static void
|
|
|
|
logTime( char *dbuf )
|
|
|
|
{
|
|
|
|
time_t tim;
|
|
|
|
(void)time( &tim );
|
|
|
|
strftime( dbuf, 20, "%b %e %H:%M:%S", localtime( &tim ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(LOG_DEBUG_MASK) || defined(USE_SYSLOG)
|
|
|
|
STATIC int debugLevel;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define OOMSTR "Out of memory. Expect problems.\n"
|
|
|
|
|
|
|
|
STATIC void
|
|
|
|
LogOutOfMem( void )
|
|
|
|
{
|
|
|
|
static time_t last;
|
|
|
|
time_t tnow;
|
|
|
|
|
|
|
|
time( &tnow );
|
|
|
|
if (last + 100 > tnow) { /* don't log bursts */
|
|
|
|
last = tnow;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
last = tnow;
|
|
|
|
#ifdef USE_SYSLOG
|
|
|
|
if (!(debugLevel & DEBUG_NOSYSLOG))
|
|
|
|
syslog( LOG_CRIT, OOMSTR );
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
int el;
|
|
|
|
char dbuf[24], sbuf[128];
|
|
|
|
logTime( dbuf );
|
|
|
|
el = sprintf( sbuf, "%s "
|
|
|
|
#ifdef LOG_NAME
|
|
|
|
LOG_NAME "[%ld]: " OOMSTR, dbuf,
|
|
|
|
#else
|
|
|
|
"%s[%ld]: " OOMSTR, dbuf, prog,
|
|
|
|
#endif
|
|
|
|
(long)getpid() );
|
|
|
|
write( 2, sbuf, el );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
char *buf;
|
|
|
|
int clen, blen, type;
|
|
|
|
char lmbuf[128];
|
|
|
|
} OCLBuf;
|
|
|
|
|
|
|
|
static void
|
|
|
|
OutChLFlush( OCLBuf *oclbp )
|
|
|
|
{
|
|
|
|
if (oclbp->clen) {
|
|
|
|
#ifdef USE_SYSLOG
|
|
|
|
if (!(debugLevel & DEBUG_NOSYSLOG))
|
|
|
|
syslog( lognums[oclbp->type], "%.*s", oclbp->clen, oclbp->buf );
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
oclbp->buf[oclbp->clen] = '\n';
|
|
|
|
write( 2, oclbp->buf, oclbp->clen + 1 );
|
|
|
|
}
|
|
|
|
oclbp->clen = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
OutChL( void *bp, char c )
|
|
|
|
{
|
|
|
|
OCLBuf *oclbp = (OCLBuf *)bp;
|
|
|
|
char *nbuf;
|
|
|
|
int nlen;
|
|
|
|
|
|
|
|
if (c == '\n')
|
|
|
|
OutChLFlush( oclbp );
|
|
|
|
else {
|
|
|
|
if (oclbp->clen >= oclbp->blen - 1) {
|
|
|
|
if (oclbp->buf == oclbp->lmbuf) {
|
|
|
|
OutChLFlush( oclbp );
|
|
|
|
oclbp->buf = 0;
|
|
|
|
oclbp->blen = 0;
|
|
|
|
}
|
|
|
|
nlen = oclbp->blen * 3 / 2 + 128;
|
|
|
|
nbuf = Realloc( oclbp->buf, nlen );
|
|
|
|
if (nbuf) {
|
|
|
|
oclbp->buf = nbuf;
|
|
|
|
oclbp->blen = nlen;
|
|
|
|
} else {
|
|
|
|
OutChLFlush( oclbp );
|
|
|
|
oclbp->buf = oclbp->lmbuf;
|
|
|
|
oclbp->blen = sizeof(oclbp->lmbuf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef USE_SYSLOG
|
|
|
|
if (!oclbp->clen && (debugLevel & DEBUG_NOSYSLOG)) {
|
|
|
|
#else
|
|
|
|
if (!oclbp->clen) {
|
|
|
|
#endif
|
|
|
|
char dbuf[24];
|
|
|
|
logTime( dbuf );
|
|
|
|
oclbp->clen = sprintf( oclbp->buf, "%s "
|
|
|
|
#ifdef LOG_NAME
|
|
|
|
LOG_NAME "[%ld] %s: ", dbuf,
|
|
|
|
#else
|
|
|
|
"%s[%ld] %s: ", dbuf, prog,
|
|
|
|
#endif
|
|
|
|
(long)getpid(), lognams[oclbp->type] );
|
|
|
|
}
|
|
|
|
oclbp->buf[oclbp->clen++] = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
Logger( int type, const char *fmt, va_list args )
|
|
|
|
{
|
|
|
|
OCLBuf oclb;
|
|
|
|
|
|
|
|
oclb.buf = 0;
|
|
|
|
oclb.blen = oclb.clen = 0;
|
|
|
|
oclb.type = type;
|
|
|
|
DoPr( OutChL, &oclb, fmt, args );
|
|
|
|
/* no flush, every message is supposed to be \n-terminated */
|
|
|
|
if (oclb.buf && oclb.buf != oclb.lmbuf)
|
|
|
|
free( oclb.buf );
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef LOG_DEBUG_MASK
|
|
|
|
STATIC void
|
|
|
|
Debug( const char *fmt, ... )
|
|
|
|
{
|
|
|
|
if (debugLevel & LOG_DEBUG_MASK) {
|
|
|
|
va_list args;
|
|
|
|
int olderrno = errno;
|
|
|
|
va_start( args, fmt );
|
|
|
|
Logger( DM_DEBUG, fmt, args );
|
|
|
|
va_end( args );
|
|
|
|
errno = olderrno;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef LOG_NO_INFO
|
|
|
|
STATIC void
|
|
|
|
LogInfo( const char *fmt, ... )
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start( args, fmt );
|
|
|
|
Logger( DM_INFO, fmt, args );
|
|
|
|
va_end( args );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef LOG_NO_WARN
|
|
|
|
STATIC void
|
|
|
|
LogWarn( const char *fmt, ... )
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start( args, fmt );
|
|
|
|
Logger( DM_WARN, fmt, args );
|
|
|
|
va_end( args );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef LOG_NO_ERROR
|
|
|
|
STATIC void
|
|
|
|
LogError( const char *fmt, ... )
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start( args, fmt );
|
|
|
|
Logger( DM_ERR, fmt, args );
|
|
|
|
va_end( args );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef LOG_PANIC_EXIT
|
|
|
|
STATIC void
|
|
|
|
LogPanic( const char *fmt, ... )
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start( args, fmt );
|
|
|
|
Logger( DM_PANIC, fmt, args );
|
|
|
|
va_end( args );
|
|
|
|
exit( LOG_PANIC_EXIT );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* NO_LOGGER */
|
|
|
|
|
|
|
|
#ifdef NEED_FDPRINTF
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
char *buf;
|
|
|
|
int clen, blen, tlen;
|
|
|
|
} OCFBuf;
|
|
|
|
|
|
|
|
static void
|
|
|
|
OutCh_OCF( void *bp, char c )
|
|
|
|
{
|
|
|
|
OCFBuf *ocfbp = (OCFBuf *)bp;
|
|
|
|
char *nbuf;
|
|
|
|
int nlen;
|
|
|
|
|
|
|
|
ocfbp->tlen++;
|
|
|
|
if (ocfbp->clen >= ocfbp->blen) {
|
|
|
|
if (ocfbp->blen < 0)
|
|
|
|
return;
|
|
|
|
nlen = ocfbp->blen * 3 / 2 + 100;
|
|
|
|
nbuf = Realloc( ocfbp->buf, nlen );
|
|
|
|
if (!nbuf) {
|
|
|
|
free( ocfbp->buf );
|
|
|
|
ocfbp->blen = -1;
|
|
|
|
ocfbp->buf = 0;
|
|
|
|
ocfbp->clen = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ocfbp->blen = nlen;
|
|
|
|
ocfbp->buf = nbuf;
|
|
|
|
}
|
|
|
|
ocfbp->buf[ocfbp->clen++] = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC int
|
|
|
|
FdPrintf( int fd, const char *fmt, ... )
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
OCFBuf ocfb = { 0, 0, 0, -1 };
|
|
|
|
|
|
|
|
va_start( args, fmt );
|
|
|
|
DoPr( OutCh_OCF, &ocfb, fmt, args );
|
|
|
|
va_end( args );
|
|
|
|
if (ocfb.buf) {
|
|
|
|
Debug( "FdPrintf %\".*s to %d\n", ocfb.clen, ocfb.buf, fd );
|
|
|
|
(void)write( fd, ocfb.buf, ocfb.clen );
|
|
|
|
free( ocfb.buf );
|
|
|
|
}
|
|
|
|
return ocfb.tlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* NEED_FDPRINTF */
|
|
|
|
|
|
|
|
#ifdef NEED_ASPRINTF
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
char *buf;
|
|
|
|
int clen, blen, tlen;
|
|
|
|
} OCABuf;
|
|
|
|
|
|
|
|
static void
|
|
|
|
OutCh_OCA( void *bp, char c )
|
|
|
|
{
|
|
|
|
OCABuf *ocabp = (OCABuf *)bp;
|
|
|
|
char *nbuf;
|
|
|
|
int nlen;
|
|
|
|
|
|
|
|
ocabp->tlen++;
|
|
|
|
if (ocabp->clen >= ocabp->blen) {
|
|
|
|
if (ocabp->blen < 0)
|
|
|
|
return;
|
|
|
|
nlen = ocabp->blen * 3 / 2 + 100;
|
|
|
|
nbuf = Realloc( ocabp->buf, nlen );
|
|
|
|
if (!nbuf) {
|
|
|
|
free( ocabp->buf );
|
|
|
|
ocabp->blen = -1;
|
|
|
|
ocabp->buf = 0;
|
|
|
|
ocabp->clen = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ocabp->blen = nlen;
|
|
|
|
ocabp->buf = nbuf;
|
|
|
|
}
|
|
|
|
ocabp->buf[ocabp->clen++] = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC int
|
|
|
|
VASPrintf( char **strp, const char *fmt, va_list args )
|
|
|
|
{
|
|
|
|
OCABuf ocab = { 0, 0, 0, -1 };
|
|
|
|
|
|
|
|
DoPr( OutCh_OCA, &ocab, fmt, args );
|
|
|
|
OutCh_OCA( &ocab, 0 );
|
|
|
|
*strp = Realloc( ocab.buf, ocab.clen );
|
|
|
|
if (!*strp)
|
|
|
|
*strp = ocab.buf;
|
|
|
|
return ocab.tlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC int
|
|
|
|
ASPrintf( char **strp, const char *fmt, ... )
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
va_start( args, fmt );
|
|
|
|
len = VASPrintf( strp, fmt, args );
|
|
|
|
va_end( args );
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* NEED_ASPRINTF */
|