📄 doprnt.c
字号:
#if !defined(lint) && defined(SCCSIDS)static char sccsid[] = "@(#)doprnt.c 1.1 92/07/30 SMI";#endif/* * Copyright (c) 1988 by Sun Microsystems, Inc. *//* * _doprnt: common code for printf, fprintf, sprintf * Floating-point code is included or not, depending * on whether the preprocessor variable FLOAT is 1 or 0. */#define MAXARGS 50#ifndef FLOAT#define FLOAT 1 /* YES! we want floating */#endif#include <stdio.h>#include <ctype.h>#include <varargs.h>#include <values.h>#include <locale.h>#include "doprnt.h"#include "stdiom.h"#define max(a,b) ((a) > (b) ? (a) : (b))#define min(a,b) ((a) < (b) ? (a) : (b))/* If this symbol is nonzero, allow '0' as a flag *//* If this symbol is nonzero, allow '0' as a flag */#define FZERO 1#if FLOAT/* * libc/gen/common functions for floating-point conversion */#include <floatingpoint.h>extern void _fourdigitsquick();#endifvoid _mkarglst();void _getarg();static char *_check_dol();char *strchr();#define emitchar(c) { if (--filecnt < 0) { \ register FILE *iop = file; \ if (((iop->_flag & (_IOLBF|_IONBF)) == 0 \ || -filecnt >= iop->_bufsiz)) { \ iop->_ptr = fileptr; \ (void) _xflsbuf(iop); \ fileptr = iop->_ptr; \ filecnt = iop->_cnt; \ filecnt--; \ } \ } \ *fileptr++ = (unsigned)(c); \ count++; \ }static char *nullstr = "(null)";static char *lowerhex = "0123456789abcdef";static char *upperhex = "0123456789ABCDEF";/* stva_list is used to subvert C's restriction that a variable with an * array type can not appear on the left hand side of an assignment operator. * By putting the array inside a structure, the functionality of assigning to * the whole array through a simple assignment is achieved..*/typedef struct stva_list { va_list ap;} stva_list;_doprnt(format, in_args, file) char *format; va_list in_args; FILE *file;{ char convertbuffer[1024] ; /* Current position in format */ register char *cp; /* Starting and ending points for value to be printed */ register char *bp; char *p; /* Pointer and count for I/O buffer */ register unsigned char *fileptr; register int filecnt; /* Field width and precision */ int width; register int prec; /* Format code */ char fcode; /* Number of padding zeroes required on the left */ int lzero; /* Flags - nonzero if corresponding character appears in format */ bool fplus; /* + */ bool fminus; /* - */ bool fblank; /* blank */ bool fsharp; /* # */#if FZERO bool fzero; /* 0 */#endif bool Lsize; /* Capital L for size = long double = quadruple */ /* Pointer to sign, "0x", "0X", or empty */ char *prefix; /* Scratch */ int nblank;#if FLOAT /* Exponent or empty */ char *suffix; /* Buffer to create exponent */ char expbuf[7]; /* "e+xxxx\0" */ /* Number of padding zeroes required on the right */ int rzero; /* Length of exponent suffix. */ int suffixlength; /* The value being converted, if real or quadruple */ double dval; quadruple qval; /* Output values from fconvert and econvert */ int decpt, sign; /* Values are developed in this buffer */ char buf[1034]; /* Size of convertbuffer, plus some for exponent and sign. */ /* Current locale's decimal point */ char decpt_char = *(localeconv()->decimal_point);#else /* Values are developed in this buffer */ char buf[MAXDIGS];#endif /* The value being converted, if integer */ register unsigned long val; /* Work variables */ register int n; register char c; char radix; int svswitch = 0; /* count of output characters */ register int count; /* variables for positional parameters */ char *sformat = format; /* save the beginning of the format */ int fpos = 1; /* 1 if first positional parameter */ stva_list args, /* used to step through the argument list */ args_width, /* for width */ args_prec, /* for prec */ sargs; /* used to save the start of the argument list */ stva_list arglst[MAXARGS];/* array giving the approriate values * for va_arg() to retrieve the * corresponding argument: * arglst[0] is the first argument * arglst[1] is the second argument, etc. */ int index = 0; /* argument placeolder */ /* Initialize args and sargs to the start of the argument list. * Note that ANSI guarantees that the address of the first member of * a structure will be the same as the address of the structure. */ args_width = args_prec = args = sargs = *(struct stva_list *)&in_args; cp = format; if ((c = *cp++) != '\0') { /* * We know we're going to write something; make sure * we can write and set up buffers, etc.. */ if (_WRTCHK(file)) return(EOF); } else return(0); /* no fault, no error */ count = 0; fileptr = file->_ptr; filecnt = file->_cnt; /* * The main loop -- this loop goes through one iteration * for each ordinary character or format specification. */ do { if (c != '%') { /* Ordinary (non-%) character */ emitchar(c); } else { /* * % has been spotted! * * First, try the 99% cases. * then parse the format specification. * * Note that this code assumes the Sun * Workstation environment (all params * passed as int == long, no interrupts * for fixed point overflow from negating * the most negative number). */ skipit: switch(c = *cp++) { case 'l': case 'h': /* Quickly ignore long & short specifiers */ goto skipit; case 's': bp = va_arg(args.ap, char *); if (bp == NULL) bp = nullstr; while (c = *bp++) emitchar(c); continue; case 'c': c = va_arg(args.ap, int); emitc: emitchar(c); continue; case 'i': case 'd': case 'D': val = va_arg(args.ap, int); if ((long) val < 0) { emitchar('-'); val = -val; } goto udcommon; case 'U': case 'u': val = va_arg(args.ap, unsigned); udcommon: { register char *stringp = lowerhex; bp = buf+MAXDIGS; stringp = lowerhex; do { *--bp = stringp[val%10]; val /= 10; } while (val); } goto intout; case 'X': { register char *stringp = upperhex; val = va_arg(args.ap, unsigned); bp = buf + MAXDIGS; if (val == 0) goto zero; while (val) { *--bp = stringp[val%16]; val /= 16; } } goto intout; case 'x': case 'p': { register char *stringp = lowerhex; val = va_arg(args.ap, unsigned); bp = buf + MAXDIGS; if (val == 0) goto zero; while (val) { *--bp = stringp[val%16]; val /= 16; } } goto intout; case 'O': case 'o': { register char *stringp = lowerhex; val = va_arg(args.ap, unsigned); bp = buf + MAXDIGS; if (val == 0) goto zero; while (val) { *--bp = stringp[val%8]; val /= 8; } } /* Common code to output integers */ intout: p = buf + MAXDIGS; while (bp < p) { c = *bp++; emitchar(c); } continue; zero: c = '0'; goto emitc; default: /* * let AT&T deal with it */ cp-= 2; } Lsize = 0; /* Not long double unless we say so. */ /* Scan the <flags> */ fplus = 0; fminus = 0; fblank = 0; fsharp = 0;#if FZERO fzero = 0;#endif scan: switch (*++cp) { case '+': fplus = 1; goto scan; case '-': fminus = 1; goto scan; case ' ': fblank = 1; goto scan; case '#': fsharp = 1; goto scan;#if FZERO case '0': fzero = 1; goto scan;#endif } /* Scan the field width */found_dol: if (*cp == '*') { char *p; int val; p = _check_dol(cp+1, &val); if (p != (char *)NULL) { /* * argument re-order */ if (fpos) { _mkarglst(sformat, sargs, arglst); fpos = 0; } if (val <= MAXARGS) { args_width = arglst[val - 1]; } else { args_width = arglst[MAXARGS - 1]; _getarg(sformat, &args_width, val); } width = va_arg(args_width.ap, int); if (width < 0) { width = -width; fminus = 1; } cp = p; } else { width = va_arg(args.ap, int); if (width < 0) { width = -width; fminus = 1; } cp++; } } else { index = width = 0; while (isdigit(*cp)) { n = tonumber(*cp++); index = width = width * 10 + n; } } /* Scan the precision */ if (*cp == '.') { /* '*' instead of digits? */ if (*++cp == '*') { char *p; int val; p = _check_dol(cp+1, &val); if (p != (char *)NULL) { /* * argument re-order */ if (fpos) { _mkarglst(sformat, sargs, arglst); fpos = 0; } if (val <= MAXARGS) { args_prec = arglst[val - 1]; } else { args_prec = arglst[MAXARGS - 1]; _getarg(sformat, &args_prec, val); } prec = va_arg(args_prec.ap, int); cp = p; } else { prec = va_arg(args.ap, int); cp++; } } else { prec = 0; while (isdigit(*cp)) { n = tonumber(*cp++); prec = prec * 10 + n; } } } else prec = -1; if (*cp == '$') { if (fpos) { _mkarglst(sformat, sargs, arglst); fpos = 0; } if (index <= MAXARGS) { args = arglst[index - 1]; } else { args = arglst[MAXARGS - 1]; _getarg(sformat, &args, index); } cp++; goto found_dol; } /* * The character addressed by cp must be the * format letter -- there is nothing left for * it to be. * * The status of the +, -, #, blank, and 0 * flags are reflected in the variables * "fplus", "fminus", "fsharp", "fblank", * and "fzero", respectively. * "width" and "prec" contain numbers * corresponding to the digit strings * before and after the decimal point, * respectively. If there was no decimal * point, "prec" is -1. * * The following switch sets things up * for printing. What ultimately gets * printed will be padding blanks, a prefix, * left padding zeroes, a value, right padding * zeroes, a suffix, and more padding * blanks. Padding blanks will not appear * simultaneously on both the left and the * right. Each case in this switch will * compute the value, and leave in several * variables the information necessary to * construct what is to be printed. * * The prefix is a sign, a blank, "0x", "0X", * or null, and is addressed by "prefix". * * The suffix is either null or an exponent, * and is addressed by "suffix". * * The value to be printed starts at "bp" * and continues up to and not including "p". * * "lzero" and "rzero" will contain the number * of padding zeroes required on the left * and right, respectively. If either of * these variables is negative, it will be * treated as if it were zero. * * The number of padding blanks, and whether * they go on the left or the right, will be * computed on exit from the switch. */ lzero = 0; prefix = "";#if FLOAT rzero = 0; suffix = prefix;#endif next: switch (fcode = *cp++) { /* toss the length modifier, if any */ case 'l': case 'h': goto next; case 'L': Lsize = 1; /* Remember long double size. */ goto next; /* * fixed point representations * * "radix" is the radix for the conversion. * Conversion is unsigned unless fcode is 'd'. * We assume a 2's complement machine and * that fixed point overflow (from negating * the largest negative int) is ignored. */ case 'i': case 'D': case 'U': case 'd': case 'u': radix = 10; goto fixed; case 'O': case 'o': radix = 8; goto fixed; case 'X': case 'x': radix = 16; fixed: /* Establish default precision */ if (prec < 0) prec = 1; /* Fetch the argument to be printed */ val = va_arg(args.ap, unsigned); /* If signed conversion, establish sign */ if (fcode == 'd' || fcode == 'D' || fcode == 'i') { if ((long) val < 0) { prefix = "-"; val = -val; } else if (fplus) prefix = "+"; else if (fblank) prefix = " "; }#if FZERO if (fzero) { n = width - strlen(prefix); if (n > prec) prec = n; }#endif /* Set translate table for digits */ { register char *stringp; if (fcode == 'X') stringp = upperhex; else stringp = lowerhex; /* Develop the digits of the value */ bp = buf + MAXDIGS; switch(radix) { case 8: /*octal*/ while (val) { *--bp = stringp[val%8]; val /= 8; } break; case 16:/*hex*/ while (val) { *--bp = stringp[val%16]; val /= 16; } break; default: while (val) { *--bp = stringp[val%10]; val /= 10; } break; } /* switch */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -