diff options
Diffstat (limited to 'usr/src/lib/libbc/libc/stdio/common/doprnt.c')
-rw-r--r-- | usr/src/lib/libbc/libc/stdio/common/doprnt.c | 1270 |
1 files changed, 0 insertions, 1270 deletions
diff --git a/usr/src/lib/libbc/libc/stdio/common/doprnt.c b/usr/src/lib/libbc/libc/stdio/common/doprnt.c deleted file mode 100644 index eb5e3438cd..0000000000 --- a/usr/src/lib/libbc/libc/stdio/common/doprnt.c +++ /dev/null @@ -1,1270 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* Copyright (c) 1988 AT&T */ -/* All Rights Reserved */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * _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 <stdarg.h> -#include <values.h> -#include <locale.h> -#include "doprnt.h" -#include "stdiom.h" -#include <string.h> /* strchr, strlen, strspn */ - -#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(); -#endif - -#define emitchar(c) { if (--filecnt < 0) { \ - FILE *iop = file; \ - if (((iop->_flag & (_IOLBF|_IONBF)) == 0 \ - || -filecnt >= iop->_bufsiz)) { \ - iop->_ptr = fileptr; \ - if (iop->_flag & _IOSTRG) \ - return iop->_ptr - iop->_base; \ - else \ - (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; - -void _mkarglst(char *, stva_list, stva_list []); -void _getarg(char *, stva_list *, int); -static char *_check_dol(char *, int *); - -int -_doprnt(char *format, va_list in_args, FILE *file) -{ - char convertbuffer[1024] ; - - /* Current position in format */ - char *cp; - - /* Starting and ending points for value to be printed */ - char *bp; - char *p; - - /* Pointer and count for I/O buffer */ - unsigned char *fileptr; - int filecnt; - - /* Field width and precision */ - int width; - 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 ansi_fzero; /* 0 for ansi-dictated formats */ - bool compat_fzero; /* 0 for backward compatibility */ -#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 */ - unsigned long val; - - /* Work variables */ - int n; - char c; - char radix; - int svswitch = 0; - /* count of output characters */ - 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; - - -/* initialize p an bp (starting and ending points) bugid 1141781 */ - - p = bp = NULL; - - 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); - p = bp; - 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: - { - char *stringp = lowerhex; - bp = buf+MAXDIGS; - stringp = lowerhex; - do { - *--bp = stringp[val%10]; - val /= 10; - } while (val); - } - goto intout; - - case 'X': - { - 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': - { - 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': - { - 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 - ansi_fzero = 0; - compat_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': - ansi_fzero = 1; - compat_fzero = 1; - goto scan; -#endif - } - - /* Scan the field width */ - 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); - } - goto scan; - } - /* - * 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 "ansi_fzero"/"compat_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 - -#if FZERO - /* if both zero-padding and left-justify flags - * are used, ignore zero-padding, per ansi c - */ - if (ansi_fzero & fminus) { - ansi_fzero = 0; - compat_fzero = 0; - } - - /* if zero-padding and precision are specified, - * ignore zero-padding for ansi-dictated formats, - * per ansi c - */ - if (ansi_fzero & (prec != -1)) ansi_fzero = 0; -#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 = " "; - } - /* Set translate table for digits */ - { - 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 */ - } - - /* Calculate padding zero requirement */ - p = buf + MAXDIGS; - - /* Handle the # flag */ - if (fsharp && bp != p) { - switch (fcode) { - case 'x': - prefix = "0x"; - break; - case 'X': - prefix = "0X"; - break; - } - } -#if FZERO - if (ansi_fzero) { - n = width - strlen(prefix); - if (n > prec) - prec = n; - } -#endif - lzero = bp - p + prec; - - /* Handle the # flag for 'o' */ - if (fsharp && bp != p && fcode == 'o' && - lzero < 1) { - lzero = 1; - } - break; -#if FLOAT - -#if defined(__sparc) -#define GETQVAL /* Sun-4 macro to get a quad q from the argument list, passed as a pointer. */ \ - { qval = *(va_arg(args.ap, quadruple*)) ; } -#else -#define GETQVAL /* Sun-3 macro to get a quad q from the argument list, passed as a value. */ \ - { int iq ; unsigned long * pl = (unsigned long *) (&qval) ; for(iq=0;iq<4;iq++) pl[iq] = (unsigned long) va_arg(args.ap, unsigned long) ; } -#endif - - case 'E': - case 'e': - /* - * E-format. The general strategy - * here is fairly easy: we take - * what econvert gives us and re-format it. - */ - - /* Establish default precision */ - if (prec < 0) - prec = 6; - - /* Fetch the value */ - if (Lsize == 0) { /* Double */ - dval = va_arg(args.ap, double); - bp = econvert(dval, prec + 1, &decpt, &sign, convertbuffer); - } else { /* Long Double = quadruple */ - GETQVAL; - bp = qeconvert(&qval, prec + 1, &decpt, &sign, convertbuffer); - } - - /* Determine the prefix */ - if (sign) - prefix = "-"; - else if (fplus) - prefix = "+"; - else if (fblank) - prefix = " "; - if (convertbuffer[0] > '9') - { /* handle infinity, nan */ - bp = &convertbuffer[0]; - for (p = bp+1 ; *p != 0 ; p++) ; - goto ebreak ; - } - { - char *stringp; - /* Place the first digit in the buffer */ - stringp = &buf[0]; - *stringp++ = *bp != '\0'? *bp++: '0'; - - /* Put in a decimal point if needed */ - if (prec != 0 || fsharp) - *stringp++ = decpt_char; - - /* Create the rest of the mantissa */ - rzero = prec; - while (rzero > 0 && *bp!= '\0') { - --rzero; - *stringp++ = *bp++; - } - p = stringp; - } - - bp = &buf[0]; - - /* Create the exponent */ - if (convertbuffer[0] != '0') - n = decpt - 1; - else - n = 0 ; - if (n < 0) - n = -n; - _fourdigitsquick( (short unsigned) n, &(expbuf[2]) ) ; - expbuf[6] = 0 ; - if (n < 100) - /* - * Normally two digit exponent field, - * three or four if required. - */ - { suffix = &(expbuf[4]) ; suffixlength = 4 ; } - else if (n < 1000) - { suffix = &(expbuf[3]) ; suffixlength = 5 ; } - else - { suffix = &(expbuf[2]) ; suffixlength = 6 ; } - /* Put in the exponent sign */ - *--suffix = (decpt > 0 || convertbuffer[0] == '0' )? '+': '-'; - - /* Put in the e; note kludge in 'g' format */ - *--suffix = fcode; -ebreak: -#if FZERO - if (compat_fzero &! fminus) - /* Calculate padding zero requirement */ - lzero = width - (strlen(prefix) - + (p - buf) + rzero + suffixlength); -#endif - break; - - case 'f': - /* - * F-format floating point. This is - * a good deal less simple than E-format. - * The overall strategy will be to call - * fconvert, reformat its result into buf, - * and calculate how many trailing - * zeroes will be required. There will - * never be any leading zeroes needed. - */ - - /* Establish default precision */ - if (prec < 0) - prec = 6; - - if (Lsize == 0) { - dval = va_arg(args.ap, double); - bp = fconvert(dval, prec, &decpt, &sign, convertbuffer); - } else { - GETQVAL ; - bp = qfconvert(&qval, prec, &decpt, &sign, convertbuffer); - } - - /* Determine the prefix */ - if (sign) - prefix = "-"; - else if (fplus) - prefix = "+"; - else if (fblank) - prefix = " "; - if (convertbuffer[0] > '9') - { /* handle infinity, nan */ - bp = &convertbuffer[0]; - for (p = bp+1 ; *p != 0 ; p++) ; - goto fbreak ; - } - { - char *stringp; - /* Initialize buffer pointer */ - stringp = &buf[0]; - - /* Emit the digits before the decimal point */ - n = decpt; - if (n <= 0) - *stringp++ = '0'; - else - do - if (*bp == '\0' ) - *stringp++ = '0'; - else { - *stringp++ = *bp++; - } - while (--n != 0); - - /* Decide whether we need a decimal point */ - if (fsharp || prec > 0) - *stringp++ = decpt_char; - - /* Digits(if any) after the decimal point */ - n = prec; - rzero = prec - n; - while (--n >= 0) { - if (++decpt <= 0 || *bp == '\0') - *stringp++ = '0'; - else { - *stringp++ = *bp++; - } - } -#if FZERO - if (compat_fzero &! fminus) - /* Calculate padding zero requirement */ - lzero = width - (strlen(prefix) - + (stringp - buf) + rzero); -#endif - p = stringp; - } - - bp = &buf[0]; -fbreak: - break; - - case 'G': - case 'g': - /* - * g-format. We play around a bit - * and then jump into e or f, as needed. - */ - - /* Establish default precision */ - if (prec < 0) - prec = 6; - else if (prec == 0) - prec = 1; - - if (Lsize == 0) { - dval = va_arg(args.ap, double); - bp = gconvert(dval, prec, fsharp, convertbuffer); - } else { - GETQVAL; - bp = qgconvert(&qval, prec, fsharp, convertbuffer); - } - bp = convertbuffer ; - if (convertbuffer[0] == '-') { - prefix = "-" ; - bp++; - } - else if (fplus) - prefix = "+"; - else if (fblank) - prefix = " "; - if (isupper(fcode)) - { /* Put in a big E for small minds. */ - for (p = bp ; (*p != NULL) && (*p != 'e') ; p++) ; - if (*p == 'e') *p = 'E' ; - for (; (*p != NULL) ; p++) ; - /* Find end of string. */ - } - else - for (p = bp ; *p != NULL ; p++) ; - /* Find end of string. */ - rzero = 0; -#if FZERO - if (compat_fzero & !fminus) - /* Calculate padding zero requirement */ - lzero = width - (strlen(prefix) - + (p - bp) + rzero); -#endif - break ; - -#endif - case 'c': - buf[0] = va_arg(args.ap, int); - bp = &buf[0]; - p = bp + 1; - break; - - case 's': - bp = va_arg(args.ap, char *); - if (prec < 0) - prec = MAXINT; - /* avoid *(0) */ - if (bp == NULL) - bp = nullstr; - for (n=0; *bp++ != '\0' && n < prec; n++) - ; -#if FZERO - if (compat_fzero &! fminus) - lzero = width - n; -#endif - p = --bp; - bp -= n; - break; - - case '\0': - /* well, what's the punch line? */ - goto out; - - case 'n': - svswitch = 1; - break; - default: - p = bp = &fcode; - p++; - break; - - } - /* Calculate number of padding blanks */ - nblank = width -#if FLOAT - - (rzero < 0? 0: rzero) - - strlen(suffix) -#endif - - (p - bp) - - (lzero < 0? 0: lzero) - - strlen(prefix); - - /* Blanks on left if required */ - if (!fminus) - while (--nblank >= 0) - emitchar(' '); - - /* Prefix, if any */ - while (*prefix != '\0') { - emitchar(*prefix); - prefix++; - } - - /* Zeroes on the left */ - while (--lzero >= 0) - emitchar('0'); - - /* The value itself */ - while (bp < p) { - emitchar(*bp); - bp++; - } -#if FLOAT - /* Zeroes on the right */ - while (--rzero >= 0) - emitchar('0'); - - /* The suffix */ - while (*suffix != '\0') { - emitchar(*suffix); - suffix++; - } -#endif - /* Blanks on the right if required */ - if (fminus) - while (--nblank >= 0) - emitchar(' '); - /* If %n is seen, save count in argument */ - if (svswitch == 1) { - long *svcount; - svcount = va_arg (args.ap, long *); - *svcount = count; - svswitch = 0; - } - } /* else */ - } while ((c = *cp++) != '\0'); /* do */ -out: - file->_ptr = fileptr; - file->_cnt = filecnt; - if (file->_flag & (_IONBF | _IOLBF) && - (file->_flag & _IONBF || - memchr((char *)file->_base, '\n', fileptr - file->_base) != NULL)) - (void) _xflsbuf(file); - return (ferror(file)? EOF: count); -} - -#if defined(__sparc) -/* - * We use "double *" instead of "quadruple *" to skip over the pointer to - * long double on the argument list since a pointer is a pointer after all. - */ -#define SKIPQVAL { \ - (void) va_arg(args.ap, double *); \ -} -#else /* Sun-3 */ -#define SKIPQVAL { \ - int iq; \ - for (iq = 0; iq < 4; iq++) \ - (void) va_arg(args.ap, unsigned long); \ -} -#endif -/* - * This function initializes arglst, to contain the appropriate va_list values - * for the first MAXARGS arguments. - */ -void -_mkarglst(char *fmt, stva_list args, stva_list arglst[]) -{ - static char *digits = "01234567890", *skips = "# +-.0123456789h$"; - - enum types {INT = 1, LONG, CHAR_PTR, DOUBLE, LONG_DOUBLE, VOID_PTR, - LONG_PTR, INT_PTR}; - enum types typelst[MAXARGS], curtype; - int maxnum, n, curargno, flags; - - /* - * Algorithm 1. set all argument types to zero. - * 2. walk through fmt putting arg types in typelst[]. - * 3. walk through args using va_arg(args.ap, typelst[n]) - * and set arglst[] to the appropriate values. - * Assumptions: Cannot use %*$... to specify variable position. - */ - - (void)memset((void *)typelst, 0, sizeof(typelst)); - maxnum = -1; - curargno = 0; - while ((fmt = strchr(fmt, '%')) != 0) - { - fmt++; /* skip % */ - if (fmt[n = strspn(fmt, digits)] == '$') - { - curargno = atoi(fmt) - 1; /* convert to zero base */ - fmt += n + 1; - } - flags = 0; - again:; - fmt += strspn(fmt, skips); - switch (*fmt++) - { - case '%': /*there is no argument! */ - continue; - case 'l': - flags |= 0x1; - goto again; - case 'L': - flags |= 0x8; - goto again; - case '*': /* int argument used for value */ - flags |= 0x2; - curtype = INT; - break; - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - if (flags & 0x8) - curtype = LONG_DOUBLE; - else - curtype = DOUBLE; - break; - case 's': - curtype = CHAR_PTR; - break; - case 'p': - curtype = VOID_PTR; - break; - case 'n': - if (flags & 0x1) - curtype = LONG_PTR; - else - curtype = INT_PTR; - break; - default: - if (flags & 0x1) - curtype = LONG; - else - curtype = INT; - break; - } - if (curargno >= 0 && curargno < MAXARGS) - { - typelst[curargno] = curtype; - if (maxnum < curargno) - maxnum = curargno; - } - curargno++; /* default to next in list */ - if (flags & 0x2) /* took care of *, keep going */ - { - flags ^= 0x2; - goto again; - } - } - for (n = 0 ; n <= maxnum; n++) - { - arglst[n] = args; - if (typelst[n] == 0) - typelst[n] = INT; - - switch (typelst[n]) - { - case INT: - va_arg(args.ap, int); - break; - case LONG: - va_arg(args.ap, long); - break; - case CHAR_PTR: - va_arg(args.ap, char *); - break; - case DOUBLE: - va_arg(args.ap, double); - break; - case LONG_DOUBLE: - SKIPQVAL - break; - case VOID_PTR: - va_arg(args.ap, void *); - break; - case LONG_PTR: - va_arg(args.ap, long *); - break; - case INT_PTR: - va_arg(args.ap, int *); - break; - } - } -} - -/* - * This function is used to find the va_list value for arguments whose - * position is greater than MAXARGS. This function is slow, so hopefully - * MAXARGS will be big enough so that this function need only be called in - * unusual circumstances. - * pargs is assumed to contain the value of arglst[MAXARGS - 1]. - */ -void -_getarg(char *fmt, stva_list *pargs, int argno) -{ - static char *digits = "01234567890", *skips = "# +-.0123456789h$"; - int i, n, curargno, flags; - char *sfmt = fmt; - int found = 1; - - curargno = i = MAXARGS; - while (found) - { - fmt = sfmt; - found = 0; - while ((i != argno) && (fmt = strchr(fmt, '%')) != 0) - { - fmt++; /* skip % */ - if (fmt[n = strspn(fmt, digits)] == '$') - { - curargno = atoi(fmt); - fmt += n + 1; - } - - /* find conversion specifier for next argument */ - if (i != curargno) - { - curargno++; - continue; - } else - found = 1; - flags = 0; - again:; - fmt += strspn(fmt, skips); - switch (*fmt++) - { - case '%': /*there is no argument! */ - continue; - case 'l': - flags |= 0x1; - goto again; - case 'L': - flags |= 0x8; - goto again; - case '*': /* int argument used for value */ - flags |= 0x2; - (void)va_arg((*pargs).ap, int); - break; - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - if (flags & 0x8) { -#define args (*pargs) - SKIPQVAL -#undef args - } - else - (void)va_arg((*pargs).ap, double); - break; - case 's': - (void)va_arg((*pargs).ap, char *); - break; - case 'p': - (void)va_arg((*pargs).ap, void *); - break; - case 'n': - if (flags & 0x1) - (void)va_arg((*pargs).ap, long *); - else - (void)va_arg((*pargs).ap, int *); - break; - default: - if (flags & 0x1) - (void)va_arg((*pargs).ap, long int); - else - (void)va_arg((*pargs).ap, int); - break; - } - i++; - curargno++; /* default to next in list */ - if (flags & 0x2) /* took care of *, keep going */ - { - flags ^= 0x2; - goto again; - } - } - - /* missing specifier for parameter, assume parameter is an int */ - if (!found && i != argno) { - (void)va_arg((*pargs).ap, int); - i++; - curargno++; - found = 1; - } - } -} - - -/* - * parse a string, mini parse - */ -static char * -_check_dol(char *s, int *val) -{ - char *os; /* save old string */ - int tmp_val = 0; - int flag = 0; - - while (isdigit (*s)) { - ++flag; - tmp_val = tmp_val*10 + *s - '0'; - s++; - } - if (flag == 0) - return ((char *)NULL); - if (*s == '$') { - *val = tmp_val; - return(++s); - } - return ((char *)NULL); -} |