📄 fiolib.c
字号:
** This routine is used by the printf() family of routines to handle the* actual conversion of a format string. The first argument is a format* string, as described in the entry for printf(). The second argument is a* variable argument list <vaList> that was previously established.** As the format string is processed, the result will be passed to the output* routine whose address is passed as the third parameter, <outRoutine>.* This output routine may output the result to a device, or put it in a* buffer. In addition to the buffer and length to output, the fourth* argument, <outarg>, will be passed through as the third parameter to the* output routine. This parameter could be a file descriptor, a buffer * address, or any other value that can be passed in an "int".** The output routine should be declared as follows:* .CS* STATUS outRoutine* (* char *buffer, /@ buffer passed to routine @/* int nchars, /@ length of buffer @/* int outarg /@ arbitrary arg passed to fmt routine @/* )* .CE* The output routine should return OK if successful, or ERROR if unsuccessful.** RETURNS:* The number of characters output, or ERROR if the output routine * returned ERROR.** INTERNAL* Warning, you are about to read one of the ugliest pieces of shit in modern* programming. It comes to us from the "ace developers" of the UCB BSD * group. Please resist the urge to clean up this routine, its integrity* is easily destroyed. Yes it is impossible to change, but it claims ANSI* compliance (so what are you changing?), and at the time of this writing* it appears to actually be so. Ah the sweet mysteries of life...*/int fioFormatV ( FAST const char *fmt, /* format string */ va_list vaList, /* pointer to varargs list */ FUNCPTR outRoutine, /* handler for args as they're formatted */ int outarg /* argument to routine */ ) { FAST int ch; /* character from fmt */ FAST int n; /* handy integer (short term usage) */ FAST char * cp; /* handy char pointer (short term usage) */ int width; /* width from format (%8d), or 0 */ char sign; /* sign prefix (' ', '+', '-', or \0) */ ulong_t ulongVal; /* integer arguments %[diouxX] */ int prec; /* precision from format (%.3d), or -1 */ int oldprec; /* old precision from format (%.3d), or -1 */ int dprec; /* a copy of prec if [diouxX], 0 otherwise */ int fpprec; /* `extra' floating precision in [eEfgG] */ int size; /* size of converted field or string */ int fieldsz; /* field size expanded by sign, etc */ int realsz; /* field size expanded by dprec */ BOOL doLongInt; /* long integer */ BOOL doShortInt; /* short integer */ BOOL doAlt; /* alternate form */ BOOL doLAdjust; /* left adjustment */ BOOL doZeroPad; /* zero (as opposed to blank) pad */ BOOL doHexPrefix; /* add 0x or 0X prefix */ BOOL doSign; /* change sign to '-' */ char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */#if (CPU_FAMILY != AM29XXX) char ox[2]; /* space for 0x hex-prefix */#else char ox[3]; /* space for 0x hex-prefix */#endif /*(CPU_FAMILY != AM29XXX)*/ char * xdigs = NULL; /* digits for [xX] conversion */ int ret = 0; /* return value accumulator */ enum {OCT, DEC, HEX} base; /* base for [diouxX] conversion */ FOREVER /* Scan the format for conversions (`%' character) */ { for (cp = CHAR_FROM_CONST(fmt);((ch=*fmt) != EOS)&&(ch != '%'); fmt++) ; if ((n = fmt - cp) != 0) { if ((*outRoutine) (cp, n, outarg) != OK) return (ERROR); ret += n; } if (ch == EOS) return (ret); /* return total length */ fmt++; /* skip over '%' */ doLongInt = FALSE; /* long integer */ doShortInt = FALSE; /* short integer */ doAlt = FALSE; /* alternate form */ doLAdjust = FALSE; /* left adjustment */ doZeroPad = FALSE; /* zero (as opposed to blank) pad */ doHexPrefix = FALSE; /* add 0x or 0X prefix */ doSign = FALSE; /* change sign to '-' */ dprec = 0; fpprec = 0; width = 0; prec = -1; oldprec = -1; sign = EOS;rflag: ch = *fmt++;reswitch: switch (ch) { case ' ': /* If the space and + flags both appear, the space * flag will be ignored. -- ANSI X3J11 */ if (!sign) sign = ' '; goto rflag; case '#': doAlt = TRUE; goto rflag; case '*': /* A negative field width argument is taken as a * flag followed by a positive field width. * -- ANSI X3J11 * They don't exclude field widths read from args. */ if ((width = va_arg(vaList, int)) >= 0) goto rflag; width = -width; /* FALLTHROUGH */ case '-': doLAdjust = TRUE; goto rflag; case '+': sign = '+'; goto rflag; case '.': if ((ch = *fmt++) == '*') { n = va_arg(vaList, int); prec = (n < 0) ? -1 : n; goto rflag; } n = 0; while (is_digit(ch)) { n = 10 * n + to_digit(ch); ch = *fmt++; } prec = n < 0 ? -1 : n; goto reswitch; case '0': /* Note that 0 is taken as a flag, not as the * beginning of a field width. -- ANSI X3J11 */ doZeroPad = TRUE; goto rflag; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = 0; do { n = 10 * n + to_digit(ch); ch = *fmt++; } while (is_digit(ch)); width = n; goto reswitch; case 'h': doShortInt = TRUE; goto rflag; case 'l': doLongInt = TRUE; goto rflag; case 'c': *(cp = buf) = va_arg(vaList, int); size = 1; sign = EOS; break; case 'D': doLongInt = TRUE; /* FALLTHROUGH */ case 'd': case 'i': ulongVal = SARG(); if ((long)ulongVal < 0) { ulongVal = -ulongVal; sign = '-'; } base = DEC; goto number; case 'n': if (doLongInt) *va_arg(vaList, long *) = ret; else if (doShortInt) *va_arg(vaList, short *) = ret; else *va_arg(vaList, int *) = ret; continue; /* no output */ case 'O': doLongInt = TRUE; /* FALLTHROUGH */ case 'o': ulongVal = UARG(); base = OCT; goto nosign; case 'p': /* The argument shall be a pointer to void. The * value of the pointer is converted to a sequence * of printable characters, in an implementation * defined manner. -- ANSI X3J11 */ ulongVal = (u_long)va_arg(vaList, void *);/* NOSTRICT */ base = HEX; xdigs = "0123456789abcdef"; doHexPrefix = TRUE; ch = 'x'; goto nosign; case 's': if ((cp = va_arg(vaList, char *)) == NULL) cp = "(null)"; if (prec >= 0) { /* can't use strlen; can only look for the * NUL in the first `prec' characters, and * strlen() will go further. */ char *p = (char *)memchr(cp, 0, prec); if (p != NULL) { size = p - cp; if (size > prec) size = prec; } else size = prec; } else size = strlen(cp); sign = EOS; break; case 'U': doLongInt = TRUE; /* FALLTHROUGH */ case 'u': ulongVal = UARG(); base = DEC; goto nosign; case 'X': xdigs = "0123456789ABCDEF"; goto hex; case 'x': xdigs = "0123456789abcdef";hex: ulongVal = UARG(); base = HEX; /* leading 0x/X only if non-zero */ if (doAlt && (ulongVal != 0)) doHexPrefix = TRUE; /* unsigned conversions */nosign: sign = EOS; /* ... diouXx conversions ... if a precision is * specified, the 0 flag will be ignored. -- ANSI X3J11 */number: if ((dprec = prec) >= 0) doZeroPad = FALSE; /* The result of converting a zero value with an * explicit precision of zero is no characters. * -- ANSI X3J11 */ cp = buf + BUF; if ((ulongVal != 0) || (prec != 0)) { /* unsigned mod is hard, and unsigned mod * by a constant is easier than that by * a variable; hence this switch. */ switch (base) { case OCT: do { *--cp = to_char(ulongVal & 7); ulongVal >>= 3; } while (ulongVal); /* handle octal leading 0 */ if (doAlt && (*cp != '0')) *--cp = '0'; break; case DEC: /* many numbers are 1 digit */ while (ulongVal >= 10) { *--cp = to_char(ulongVal % 10); ulongVal /= 10; } *--cp = to_char(ulongVal); break; case HEX: do { *--cp = xdigs[ulongVal & 15]; ulongVal >>= 4; } while (ulongVal); break; default: cp = "bug in vfprintf: bad base"; size = strlen(cp); goto skipsize; } } size = buf + BUF - cp;skipsize: break; case 'L': /* NOT IMPLEMENTED */ goto rflag; case 'e': case 'E': case 'f': case 'g': case 'G': if (fioFltFormatRtn != NULL) { oldprec = prec; /* in case of strange float */ if (prec > MAXFRACT) /* do realistic precision */ { if (((ch != 'g') && (ch != 'G')) || doAlt) fpprec = prec - MAXFRACT; prec = MAXFRACT; /* they asked for it! */ } else if (prec == -1) prec = 6; /* ANSI default precision */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -