123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- /*
- * doprnt.c - print formatted output
- */
- /* $Header$ */
- #include <ctype.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #include "loc_incl.h"
- /* gnum() is used to get the width and precision fields of a format. */
- static const char *
- gnum(register const char *f, int *ip, va_list *app)
- {
- register int i, c;
- if (*f == '*') {
- *ip = va_arg((*app), int);
- f++;
- } else {
- i = 0;
- while ((c = *f - '0') >= 0 && c <= 9) {
- i = i*10 + c;
- f++;
- }
- *ip = i;
- }
- return f;
- }
- #if _EM_WSIZE == _EM_PSIZE
- #define set_pointer(flags) /* nothing */
- #elif _EM_LSIZE == _EM_PSIZE
- #define set_pointer(flags) (flags |= FL_LONG)
- #else
- #error garbage pointer size
- #define set_pointer(flags) /* compilation might continue */
- #endif
- /* print an ordinal number */
- static char *
- o_print(va_list *ap, int flags, char *s, char c, int precision, int is_signed)
- {
- long signed_val;
- unsigned long unsigned_val;
- char *old_s = s;
- int i, base;
- switch (flags & (FL_SHORT | FL_LONG)) {
- case FL_SHORT:
- if (is_signed) {
- signed_val = (short) va_arg(*ap, int);
- } else {
- unsigned_val = (unsigned short) va_arg(*ap, unsigned);
- }
- break;
- case FL_LONG:
- if (is_signed) {
- signed_val = va_arg(*ap, long);
- } else {
- unsigned_val = va_arg(*ap, unsigned long);
- }
- break;
- default:
- if (is_signed) {
- signed_val = va_arg(*ap, int);
- } else {
- unsigned_val = va_arg(*ap, unsigned int);
- }
- break;
- }
- if (is_signed) {
- if (signed_val < 0) {
- *s++ = '-';
- signed_val = -signed_val;
- } else if (flags & FL_SIGN) *s++ = '+';
- else if (flags & FL_SPACE) *s++ = ' ';
- unsigned_val = signed_val;
- }
- if ((flags & FL_ALT) && (c == 'o')) *s++ = '0';
- if (!unsigned_val) {
- if (!precision)
- return s;
- } else if (((flags & FL_ALT) && (c == 'x' || c == 'X'))
- || c == 'p') {
- *s++ = '0';
- *s++ = (c == 'X' ? 'X' : 'x');
- }
- switch (c) {
- case 'b': base = 2; break;
- case 'o': base = 8; break;
- case 'd':
- case 'i':
- case 'u': base = 10; break;
- case 'x':
- case 'X':
- case 'p': base = 16; break;
- }
- s = _i_compute(unsigned_val, base, s, precision - 1);
- if (c == 'X')
- while (old_s != s) {
- *old_s = toupper(*old_s);
- old_s++;
- }
- return s;
- }
- #ifndef NOFLOAT
- static char *
- f_print(va_list *ap, int flags, char *s, char c, int precision)
- {
- register char *old_s = s;
- long double ld_val;
- if (flags & FL_LONGDOUBLE) ld_val = va_arg(*ap, long double);
- else ld_val = (long double) va_arg(*ap, double);
- switch(c) {
- case 'f':
- s = _pfloat(ld_val, s, precision, flags);
- break;
- case 'e':
- case 'E':
- s = _pscien(ld_val, s, precision , flags);
- break;
- case 'g':
- case 'G':
- s = _gcvt(ld_val, precision, s, flags) + strlen(s);
- break;
- }
- if ( c == 'E' || c == 'G') {
- while (*old_s && *old_s != 'e') old_s++;
- if (*old_s == 'e') *old_s = 'E';
- }
- return s;
- }
- #endif /* NOFLOAT */
- int
- _doprnt(register const char *fmt, va_list ap, FILE *stream)
- {
- register char *s;
- unsigned int uint;
- register int j;
- int i, c, width, precision, zfill, flags, between_fill;
- int nrchars=0;
- const char *oldfmt;
- char *s1, buf[1025];
- while (c = *fmt++) {
- if (c != '%') {
- #ifdef CPM
- if (c == '\n') {
- if (putc('\r', stream) == EOF)
- return nrchars ? -nrchars : -1;
- nrchars++;
- }
- #endif
- if (putc(c, stream) == EOF)
- return nrchars ? -nrchars : -1;
- nrchars++;
- continue;
- }
- flags = 0;
- do {
- switch(*fmt) {
- case '-': flags |= FL_LJUST; break;
- case '+': flags |= FL_SIGN; break;
- case ' ': flags |= FL_SPACE; break;
- case '#': flags |= FL_ALT; break;
- case '0': flags |= FL_ZEROFILL; break;
- default: flags |= FL_NOMORE; continue;
- }
- fmt++;
- } while(!(flags & FL_NOMORE));
- oldfmt = fmt;
- fmt = gnum(fmt, &width, &ap);
- if (fmt != oldfmt) flags |= FL_WIDTHSPEC;
- if (*fmt == '.') {
- fmt++; oldfmt = fmt;
- fmt = gnum(fmt, &precision, &ap);
- if (precision >= 0) flags |= FL_PRECSPEC;
- }
- if ((flags & FL_WIDTHSPEC) && width < 0) {
- width = -width;
- flags |= FL_LJUST;
- }
- if (!(flags & FL_WIDTHSPEC)) width = 0;
- if (flags & FL_SIGN) flags &= ~FL_SPACE;
- if (flags & FL_LJUST) flags &= ~FL_ZEROFILL;
- s = s1 = buf;
- switch (*fmt) {
- case 'h': flags |= FL_SHORT; fmt++; break;
- case 'l': flags |= FL_LONG; fmt++; break;
- case 'L': flags |= FL_LONGDOUBLE; fmt++; break;
- }
- switch (c = *fmt++) {
- default:
- #ifdef CPM
- if (c == '\n') {
- if (putc('\r', stream) == EOF)
- return nrchars ? -nrchars : -1;
- nrchars++;
- }
- #endif
- if (putc(c, stream) == EOF)
- return nrchars ? -nrchars : -1;
- nrchars++;
- continue;
- case 'n':
- if (flags & FL_SHORT)
- *va_arg(ap, short *) = (short) nrchars;
- else if (flags & FL_LONG)
- *va_arg(ap, long *) = (long) nrchars;
- else
- *va_arg(ap, int *) = (int) nrchars;
- continue;
- case 's':
- s1 = va_arg(ap, char *);
- if (s1 == NULL)
- s1 = "(null)";
- s = s1;
- while (precision || !(flags & FL_PRECSPEC)) {
- if (*s == '\0')
- break;
- s++;
- precision--;
- }
- break;
- case 'p':
- set_pointer(flags);
- /* fallthrough */
- case 'b':
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- if (!(flags & FL_PRECSPEC)) precision = 1;
- else if (c != 'p') flags &= ~FL_ZEROFILL;
- s = o_print(&ap, flags, s, c, precision, 0);
- break;
- case 'd':
- case 'i':
- flags |= FL_SIGNEDCONV;
- if (!(flags & FL_PRECSPEC)) precision = 1;
- else flags &= ~FL_ZEROFILL;
- s = o_print(&ap, flags, s, c, precision, 1);
- break;
- case 'c':
- uint = va_arg(ap, unsigned int);
- for ( i= sizeof(uint) -1 ; i>=0 ; i-- ) {
- if ( *s = uint%256 ) s++;
- uint/= 256 ;
- }
- break;
- #ifndef NOFLOAT
- case 'G':
- case 'g':
- if ((flags & FL_PRECSPEC) && (precision == 0))
- precision = 1;
- case 'f':
- case 'E':
- case 'e':
- if (!(flags & FL_PRECSPEC))
- precision = 6;
- if (precision >= sizeof(buf))
- precision = sizeof(buf) - 1;
- flags |= FL_SIGNEDCONV;
- s = f_print(&ap, flags, s, c, precision);
- break;
- #endif /* NOFLOAT */
- case 'r':
- ap = va_arg(ap, va_list);
- fmt = va_arg(ap, char *);
- continue;
- }
- zfill = ' ';
- if (flags & FL_ZEROFILL) zfill = '0';
- j = s - s1;
- /* between_fill is true under the following conditions:
- * 1- the fill character is '0'
- * and
- * 2a- the number is of the form 0x... or 0X...
- * or
- * 2b- the number contains a sign or space
- */
- between_fill = 0;
- if ((flags & FL_ZEROFILL)
- && (((c == 'x' || c == 'X') && (flags & FL_ALT))
- || (c == 'p')
- || ((flags & FL_SIGNEDCONV)
- && ( *s1 == '+' || *s1 == '-' || *s1 == ' '))))
- between_fill++;
- if ((i = width - j) > 0)
- if (!(flags & FL_LJUST)) { /* right justify */
- nrchars += i;
- if (between_fill) {
- if (flags & FL_SIGNEDCONV) {
- j--; nrchars++;
- if (putc(*s1++, stream) == EOF)
- return nrchars ? -nrchars : -1;
- } else {
- j -= 2; nrchars += 2;
- if ((putc(*s1++, stream) == EOF)
- || (putc(*s1++, stream) == EOF))
- return nrchars ? -nrchars : -1;
- }
- }
- do {
- if (putc(zfill, stream) == EOF)
- return nrchars ? -nrchars : -1;
- } while (--i);
- }
- nrchars += j;
- while (--j >= 0) {
- if (putc(*s1++, stream) == EOF)
- return nrchars ? -nrchars : -1;
- }
- if (i > 0) nrchars += i;
- while (--i >= 0)
- if (putc(zfill, stream) == EOF)
- return nrchars ? -nrchars : -1;
- }
- return nrchars;
- }
|