diff options
Diffstat (limited to 'mig/vprint.c')
-rw-r--r-- | mig/vprint.c | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/mig/vprint.c b/mig/vprint.c new file mode 100644 index 0000000..ea66c59 --- /dev/null +++ b/mig/vprint.c @@ -0,0 +1,433 @@ +/* + * 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 <stdio.h> +#include <stdarg.h> +#include <ctype.h> +#include <limits.h> + +/* + * 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(register 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': + { + register const char *p; + register 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 */ + register 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 |