/* * Copyright (c) 1990,1992,1993 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ #ifndef HAVE_VPRINTF /* * ansi varargs versions of printf routines * This are directly included to deal with nonansi libc's. */ #include #include #include #include /* * Forward declaration. */ static void _doprnt_ansi(const char *_fmt, va_list _args, FILE *_stream); int vprintf(const char *fmt, va_list args) { _doprnt_ansi(fmt, args, stdout); return (ferror(stdout) ? EOF : 0); } int vfprintf(FILE *f, const char *fmt, va_list args) { _doprnt_ansi(fmt, args, f); return (ferror(f) ? EOF : 0); } int vsprintf(char *s, const char *fmt, va_list args) { FILE fakebuf; fakebuf._flag = _IOSTRG; /* no _IOWRT: avoid stdio bug */ fakebuf._ptr = s; fakebuf._cnt = 32767; _doprnt_ansi(fmt, args, &fakebuf); putc('\0', &fakebuf); return (strlen(s)); } int vsnprintf(char *s, int n, const char *fmt, va_list args) { FILE fakebuf; fakebuf._flag = _IOSTRG; /* no _IOWRT: avoid stdio bug */ fakebuf._ptr = s; fakebuf._cnt = n-1; _doprnt_ansi(fmt, args, &fakebuf); fakebuf._cnt++; putc('\0', &fakebuf); if (fakebuf._cnt<0) fakebuf._cnt = 0; return (n-fakebuf._cnt-1); } /* * Common code for printf et al. * * The calling routine typically takes a variable number of arguments, * and passes the address of the first one. This implementation * assumes a straightforward, stack implementation, aligned to the * machine's wordsize. Increasing addresses are assumed to point to * successive arguments (left-to-right), as is the case for a machine * with a downward-growing stack with arguments pushed right-to-left. * * To write, for example, fprintf() using this routine, the code * * fprintf(fd, format, args) * FILE *fd; * char *format; * { * _doprnt_ansi(format, &args, fd); * } * * would suffice. (This example does not handle the fprintf's "return * value" correctly, but who looks at the return value of fprintf * anyway?) * * This version implements the following printf features: * * %d decimal conversion * %u unsigned conversion * %x hexadecimal conversion * %X hexadecimal conversion with capital letters * %o octal conversion * %c character * %s string * %m.n field width, precision * %-m.n left adjustment * %0m.n zero-padding * %*.* width and precision taken from arguments * * This version does not implement %f, %e, or %g. It accepts, but * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not * work correctly on machines for which sizeof(long) != sizeof(int). * It does not even parse %D, %O, or %U; you should be using %ld, %o and * %lu if you mean long conversion. * * As mentioned, this version does not return any reasonable value. * * Permission is granted to use, modify, or propagate this code as * long as this notice is incorporated. * * Steve Summit 3/25/87 */ /* * Added for general use: * # prefix for alternate format: * 0x (0X) for hex * leading 0 for octal * + print '+' if positive * blank print ' ' if positive * */ /* * Fixed to handle `l' and `h' prefixes, %% format, and ANSI %p format. * It does not handle the ANSI %n format. * * ANSI NOTE: The formating of %d, %o, %u, %x, and %X are not compliant. * * NOTE: Given that this routine uses stdarg.h, I'm not sure that the * comment above about stack layout is valid. * * Peter Stout, 1/11/93 */ #define Ctod(c) ((c) - '0') #define MAXBUF (sizeof(long int) * 8) /* enough for binary */ typedef int boolean_t; #define FALSE ((boolean_t) 0) #define TRUE ((boolean_t) 1) #define SHORT sizeof(short) #define INT sizeof(int) #define LONG sizeof(long) static void _doprnt_ansi(const char *fmt, va_list args, FILE *stream) { int length; int prec; boolean_t ladjust; char padc; long n; unsigned long u; int plus_sign; int sign_char; boolean_t altfmt; int base; int size; unsigned char char_buf[2]; char_buf[1] = '\0'; while (*fmt != '\0') { if (*fmt != '%') { putc(*fmt++, stream); continue; } fmt++; length = 0; prec = -1; ladjust = FALSE; padc = ' '; plus_sign = 0; sign_char = 0; altfmt = FALSE; while (TRUE) { if (*fmt == '#') { altfmt = TRUE; fmt++; } else if (*fmt == '-') { ladjust = TRUE; fmt++; } else if (*fmt == '+') { plus_sign = '+'; fmt++; } else if (*fmt == ' ') { if (plus_sign == 0) plus_sign = ' '; fmt++; } else break; } if (*fmt == '0') { padc = '0'; fmt++; } if (isdigit(*fmt)) { while(isdigit(*fmt)) length = 10 * length + Ctod(*fmt++); } else if (*fmt == '*') { length = va_arg(args, int); fmt++; if (length < 0) { ladjust = !ladjust; length = -length; } } if (*fmt == '.') { prec = 0; fmt++; if (isdigit(*fmt)) { prec = 0; while(isdigit(*fmt)) prec = 10 * prec + Ctod(*fmt++); } else if (*fmt == '*') { prec = va_arg(args, int); fmt++; } } if (*fmt == 'l' || *fmt == 'h') size = *(fmt++) == 'l' ? LONG : SHORT; else size = INT; switch(*fmt) { case 'c': { const char *p; const char *p2; char_buf[0] = va_arg(args, int); p = char_buf; prec = 1; goto put_string; case 's': if (prec == -1) prec = INT_MAX; p = va_arg(args, char *); if (p == (const char *)0) p = ""; put_string: if (length > 0 && !ladjust) { n = 0; p2 = p; for (; *p != '\0' && n < prec; p++) n++; p = p2; while (n < length) { putc(padc, stream); n++; } } n = 0; while (*p != '\0') { if (++n > prec) break; putc(*p++, stream); } if (n < length && ladjust) { while (n < length) { putc(' ', stream); n++; } } break; } case 'o': base = 8; goto print_unsigned; case 'i': case 'd': base = 10; goto print_signed; case 'u': base = 10; goto print_unsigned; case 'x': case 'X': base = 16; goto print_unsigned; case 'p': base = 16; altfmt = TRUE; u = (unsigned long) va_arg(args, void *); goto print_num; print_signed: if (size == INT) n = va_arg(args, int); else if (size == LONG) n = va_arg(args, long); else n = (short) va_arg(args, int); if (n >= 0) { u = n; sign_char = plus_sign; } else { u = -n; sign_char = '-'; } goto print_num; print_unsigned: if (size == INT) u = va_arg(args, unsigned int); else if (size == LONG) u = va_arg(args, unsigned long); else u = (unsigned short) va_arg(args, unsigned int); goto print_num; print_num: { char buf[MAXBUF]; /* build number here */ char * p = &buf[MAXBUF-1]; static const char digits[] = "0123456789abcdef"; const char *prefix = 0; if (u != 0 && altfmt) { if (base == 8) prefix = "0"; else if (base == 16) prefix = "0x"; } do { *p-- = digits[u % base]; u /= base; } while (u != 0); length -= (&buf[MAXBUF-1] - p); if (sign_char) length--; if (prefix) length -= strlen(prefix); if (padc == ' ' && !ladjust) { /* blank padding goes before prefix */ while (--length >= 0) putc(' ', stream); } if (sign_char) putc(sign_char, stream); if (prefix) while (*prefix) putc(*prefix++, stream); if (padc == '0') { /* zero padding goes after sign and prefix */ while (--length >= 0) putc('0', stream); } while (++p != &buf[MAXBUF]) putc(*p, stream); if (ladjust) { while (--length >= 0) putc(' ', stream); } break; } case '%': putc('%', stream); break; case '\0': fmt--; break; default: putc(*fmt, stream); } fmt++; } } #endif /* !HAVE_VPRINTF */