diff options
Diffstat (limited to 'kdm/backend/printf.c')
-rw-r--r-- | kdm/backend/printf.c | 872 |
1 files changed, 872 insertions, 0 deletions
diff --git a/kdm/backend/printf.c b/kdm/backend/printf.c new file mode 100644 index 000000000..d7220642b --- /dev/null +++ b/kdm/backend/printf.c @@ -0,0 +1,872 @@ +/* + +Copyright 2001,2002,2004 Oswald Buddenhagen <[email protected]> + +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; +#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, min, max, flags, cflags, errn; +#ifdef PRINT_ARRAYS + int arlen; + 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 */ |