1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*0Sstevel@tonic-gate /* All Rights Reserved */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate /* 31*0Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 32*0Sstevel@tonic-gate * The Regents of the University of California 33*0Sstevel@tonic-gate * All Rights Reserved 34*0Sstevel@tonic-gate * 35*0Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 36*0Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 37*0Sstevel@tonic-gate * contributors. 38*0Sstevel@tonic-gate */ 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate /*LINTLIBRARY*/ 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate /* 45*0Sstevel@tonic-gate * _doprnt: common code for printf, fprintf, sprintf 46*0Sstevel@tonic-gate */ 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate #include "../gen/synonyms.h" 49*0Sstevel@tonic-gate #include <sys/types.h> 50*0Sstevel@tonic-gate #include "file64.h" 51*0Sstevel@tonic-gate #include <stdio.h> 52*0Sstevel@tonic-gate #include <stdlib.h> 53*0Sstevel@tonic-gate #include <ctype.h> 54*0Sstevel@tonic-gate #include <stdarg.h> 55*0Sstevel@tonic-gate #include <values.h> 56*0Sstevel@tonic-gate #include <nan.h> 57*0Sstevel@tonic-gate #include <memory.h> 58*0Sstevel@tonic-gate #include <string.h> 59*0Sstevel@tonic-gate #include "print.h" /* parameters & macros for doprnt */ 60*0Sstevel@tonic-gate #include "stdiom.h" 61*0Sstevel@tonic-gate #include <locale.h> 62*0Sstevel@tonic-gate #include <stddef.h> 63*0Sstevel@tonic-gate #include "_locale.h" 64*0Sstevel@tonic-gate #include "libc.h" 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate #define PUT(p, n) { unsigned char *newbufptr; \ 67*0Sstevel@tonic-gate if ((newbufptr = bufptr + (n)) > bufferend) { \ 68*0Sstevel@tonic-gate _dowrite((p), (n), iop, &bufptr); \ 69*0Sstevel@tonic-gate } else { \ 70*0Sstevel@tonic-gate (void) memcpy(bufptr, (p), (n)); \ 71*0Sstevel@tonic-gate bufptr = newbufptr; \ 72*0Sstevel@tonic-gate } \ 73*0Sstevel@tonic-gate } 74*0Sstevel@tonic-gate #define PAD(s, n) { int nn; \ 75*0Sstevel@tonic-gate for (nn = (n); nn > 20; nn -= 20) \ 76*0Sstevel@tonic-gate _dowrite((s), 20, iop, &bufptr); \ 77*0Sstevel@tonic-gate PUT((s), nn); \ 78*0Sstevel@tonic-gate } 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate #define SNLEN 5 /* Length of string used when printing a NaN */ 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate /* bit positions for flags used in doprnt */ 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate #define LENGTH 1 /* l */ 85*0Sstevel@tonic-gate #define FPLUS 2 /* + */ 86*0Sstevel@tonic-gate #define FMINUS 4 /* - */ 87*0Sstevel@tonic-gate #define FBLANK 8 /* blank */ 88*0Sstevel@tonic-gate #define FSHARP 16 /* # */ 89*0Sstevel@tonic-gate #define PADZERO 32 /* padding zeroes requested via '0' */ 90*0Sstevel@tonic-gate #define DOTSEEN 64 /* dot appeared in format specification */ 91*0Sstevel@tonic-gate #define SUFFIX 128 /* a suffix is to appear in the output */ 92*0Sstevel@tonic-gate #define RZERO 256 /* there will be trailing zeros in output */ 93*0Sstevel@tonic-gate #define LZERO 512 /* there will be leading zeroes in output */ 94*0Sstevel@tonic-gate #define SHORT 1024 /* h */ 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate /* 97*0Sstevel@tonic-gate * Positional Parameter information 98*0Sstevel@tonic-gate */ 99*0Sstevel@tonic-gate #define MAXARGS 30 /* max. number of args for fast positional paramters */ 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate /* 102*0Sstevel@tonic-gate * stva_list is used to subvert C's restriction that a variable with an 103*0Sstevel@tonic-gate * array type can not appear on the left hand side of an assignment operator. 104*0Sstevel@tonic-gate * By putting the array inside a structure, the functionality of assigning to 105*0Sstevel@tonic-gate * the whole array through a simple assignment is achieved.. 106*0Sstevel@tonic-gate */ 107*0Sstevel@tonic-gate typedef struct stva_list { 108*0Sstevel@tonic-gate va_list ap; 109*0Sstevel@tonic-gate } stva_list; 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate static char _blanks[] = " "; 112*0Sstevel@tonic-gate static char _zeroes[] = "00000000000000000000"; 113*0Sstevel@tonic-gate static char uc_digs[] = "0123456789ABCDEF"; 114*0Sstevel@tonic-gate static char lc_digs[] = "0123456789abcdef"; 115*0Sstevel@tonic-gate static char lc_nan[] = "nan0x"; 116*0Sstevel@tonic-gate static char uc_nan[] = "NAN0X"; 117*0Sstevel@tonic-gate static char lc_inf[] = "inf"; 118*0Sstevel@tonic-gate static char uc_inf[] = "INF"; 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate /* 121*0Sstevel@tonic-gate * forward declarations 122*0Sstevel@tonic-gate */ 123*0Sstevel@tonic-gate void _mkarglst(char *, stva_list, stva_list []); 124*0Sstevel@tonic-gate void _getarg(char *, stva_list *, int); 125*0Sstevel@tonic-gate static int _lowdigit(long *); 126*0Sstevel@tonic-gate static void _dowrite(char *, ssize_t, FILE *, unsigned char **); 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate static int 129*0Sstevel@tonic-gate _lowdigit(long *valptr) 130*0Sstevel@tonic-gate { /* This function computes the decimal low-order digit of the number */ 131*0Sstevel@tonic-gate /* pointed to by valptr, and returns this digit after dividing */ 132*0Sstevel@tonic-gate /* *valptr by ten. This function is called ONLY to compute the */ 133*0Sstevel@tonic-gate /* low-order digit of a long whose high-order bit is set. */ 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate int lowbit = (int)(*valptr & 1); 136*0Sstevel@tonic-gate long value = (*valptr >> 1) & ~HIBITL; 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate *valptr = value / 5; 139*0Sstevel@tonic-gate return ((int)(value % 5 * 2 + lowbit + '0')); 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate /* The function _dowrite carries out buffer pointer bookkeeping surrounding */ 143*0Sstevel@tonic-gate /* a call to fwrite. It is called only when the end of the file output */ 144*0Sstevel@tonic-gate /* buffer is approached or in other unusual situations. */ 145*0Sstevel@tonic-gate static void 146*0Sstevel@tonic-gate _dowrite(char *p, ssize_t n, FILE *iop, unsigned char **ptrptr) 147*0Sstevel@tonic-gate { 148*0Sstevel@tonic-gate if (!(iop->_flag & _IOREAD)) { 149*0Sstevel@tonic-gate iop->_cnt -= (*ptrptr - iop->_ptr); 150*0Sstevel@tonic-gate iop->_ptr = *ptrptr; 151*0Sstevel@tonic-gate _bufsync(iop, _bufend(iop)); 152*0Sstevel@tonic-gate (void) fwrite(p, 1, n, iop); 153*0Sstevel@tonic-gate *ptrptr = iop->_ptr; 154*0Sstevel@tonic-gate } else 155*0Sstevel@tonic-gate *ptrptr = (unsigned char *) memcpy(*ptrptr, p, n) + n; 156*0Sstevel@tonic-gate } 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate int 159*0Sstevel@tonic-gate _doprnt(char *format, va_list in_args, FILE *iop) 160*0Sstevel@tonic-gate { 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate /* bufptr is used inside of doprnt instead of iop->_ptr; */ 163*0Sstevel@tonic-gate /* bufferend is a copy of _bufend(iop), if it exists. For */ 164*0Sstevel@tonic-gate /* dummy file descriptors (iop->_flag & _IOREAD), bufferend */ 165*0Sstevel@tonic-gate /* may be meaningless. Dummy file descriptors are used so that */ 166*0Sstevel@tonic-gate /* sprintf and vsprintf may share the _doprnt routine with the */ 167*0Sstevel@tonic-gate /* rest of the printf family. */ 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate unsigned char *bufptr; 170*0Sstevel@tonic-gate unsigned char *bufferend; 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate /* This variable counts output characters. */ 173*0Sstevel@tonic-gate int count = 0; 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate /* Starting and ending points for value to be printed */ 176*0Sstevel@tonic-gate char *bp; 177*0Sstevel@tonic-gate char *p; 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate /* Field width and precision */ 180*0Sstevel@tonic-gate int width, prec; 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate /* Format code */ 183*0Sstevel@tonic-gate int fcode; 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate /* Number of padding zeroes required on the left and right */ 186*0Sstevel@tonic-gate int lzero, rzero; 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate /* Flags - bit positions defined by LENGTH, FPLUS, FMINUS, FBLANK, */ 189*0Sstevel@tonic-gate /* and FSHARP are set if corresponding character is in format */ 190*0Sstevel@tonic-gate /* Bit position defined by PADZERO means extra space in the field */ 191*0Sstevel@tonic-gate /* should be padded with leading zeroes rather than with blanks */ 192*0Sstevel@tonic-gate int flagword; 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate /* Values are developed in this buffer */ 195*0Sstevel@tonic-gate char buf[max(MAXDIGS, 1+max(MAXFCVT+MAXEXP, MAXECVT))]; 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate /* Pointer to sign, "0x", "0X", or empty */ 198*0Sstevel@tonic-gate char *prefix; 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate /* Exponent or empty */ 201*0Sstevel@tonic-gate char *suffix; 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate /* Buffer to create exponent */ 204*0Sstevel@tonic-gate char expbuf[MAXESIZ + 1]; 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate /* Length of prefix and of suffix */ 207*0Sstevel@tonic-gate int prefixlength, suffixlength; 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate /* Combined length of leading zeroes, trailing zeroes, and suffix */ 210*0Sstevel@tonic-gate int otherlength; 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate /* The value being converted, if integer */ 213*0Sstevel@tonic-gate long val; 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate /* The value being converted, if real */ 216*0Sstevel@tonic-gate double dval; 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate /* Output values from fcvt and ecvt */ 219*0Sstevel@tonic-gate int decpt, sign; 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate /* Pointer to a translate table for digits of whatever radix */ 222*0Sstevel@tonic-gate char *tab; 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /* Work variables */ 225*0Sstevel@tonic-gate int k, lradix, mradix; 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate /* Variables used to flag an infinities and nans, resp. */ 228*0Sstevel@tonic-gate /* Nan_flg is used with two purposes: to flag a NaN and */ 229*0Sstevel@tonic-gate /* as the length of the string ``NAN0X'' (``nan0x'') */ 230*0Sstevel@tonic-gate int inf_nan = 0, NaN_flg = 0; 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate /* Pointer to string "NAN0X" or "nan0x" */ 233*0Sstevel@tonic-gate char *SNAN; 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate /* Flag for negative infinity or NaN */ 236*0Sstevel@tonic-gate int neg_in = 0; 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate /* variables for positional parameters */ 239*0Sstevel@tonic-gate char *sformat = format; /* save the beginning of the format */ 240*0Sstevel@tonic-gate int fpos = 1; /* 1 if first positional parameter */ 241*0Sstevel@tonic-gate stva_list args; /* used to step through the argument list */ 242*0Sstevel@tonic-gate stva_list sargs; 243*0Sstevel@tonic-gate /* used to save the start of the argument list */ 244*0Sstevel@tonic-gate stva_list bargs; 245*0Sstevel@tonic-gate /* used to restore args if positional width or precision */ 246*0Sstevel@tonic-gate stva_list arglst[MAXARGS]; 247*0Sstevel@tonic-gate /* 248*0Sstevel@tonic-gate * array giving the appropriate values for va_arg() to 249*0Sstevel@tonic-gate * retrieve the corresponding argument: 250*0Sstevel@tonic-gate * arglst[0] is the first argument, 251*0Sstevel@tonic-gate * arglst[1] is the second argument, etc. 252*0Sstevel@tonic-gate */ 253*0Sstevel@tonic-gate int starflg = 0; /* set to 1 if * format specifier seen */ 254*0Sstevel@tonic-gate /* 255*0Sstevel@tonic-gate * Initialize args and sargs to the start of the argument list. 256*0Sstevel@tonic-gate * Note that ANSI guarantees that the address of the first member of 257*0Sstevel@tonic-gate * a structure will be the same as the address of the structure. 258*0Sstevel@tonic-gate * See equivalent code in libc doprnt.c 259*0Sstevel@tonic-gate */ 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate #if !(defined(__amd64) && defined(__GNUC__)) /* XX64 - fix me */ 262*0Sstevel@tonic-gate va_copy(args.ap, in_args); 263*0Sstevel@tonic-gate #endif 264*0Sstevel@tonic-gate sargs = args; 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate /* if first I/O to the stream get a buffer */ 267*0Sstevel@tonic-gate /* Note that iop->_base should not equal 0 for sprintf and vsprintf */ 268*0Sstevel@tonic-gate if (iop->_base == 0 && _findbuf(iop) == 0) 269*0Sstevel@tonic-gate return (EOF); 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate /* initialize buffer pointer and buffer end pointer */ 272*0Sstevel@tonic-gate bufptr = iop->_ptr; 273*0Sstevel@tonic-gate bufferend = (iop->_flag & _IOREAD) ? 274*0Sstevel@tonic-gate (unsigned char *)((long)bufptr | (-1L & ~HIBITL)) 275*0Sstevel@tonic-gate : _bufend(iop); 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate /* 278*0Sstevel@tonic-gate * The main loop -- this loop goes through one iteration 279*0Sstevel@tonic-gate * for each string of ordinary characters or format specification. 280*0Sstevel@tonic-gate */ 281*0Sstevel@tonic-gate for (;;) { 282*0Sstevel@tonic-gate ptrdiff_t pdiff; 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate if ((fcode = *format) != '\0' && fcode != '%') { 285*0Sstevel@tonic-gate bp = format; 286*0Sstevel@tonic-gate do { 287*0Sstevel@tonic-gate format++; 288*0Sstevel@tonic-gate } while ((fcode = *format) != '\0' && fcode != '%'); 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate pdiff = format - bp; 291*0Sstevel@tonic-gate /* pdiff = no. of non-% chars */ 292*0Sstevel@tonic-gate count += pdiff; 293*0Sstevel@tonic-gate PUT(bp, pdiff); 294*0Sstevel@tonic-gate } 295*0Sstevel@tonic-gate if (fcode == '\0') { /* end of format; return */ 296*0Sstevel@tonic-gate ptrdiff_t d = bufptr - iop->_ptr; 297*0Sstevel@tonic-gate iop->_cnt -= d; 298*0Sstevel@tonic-gate iop->_ptr = bufptr; 299*0Sstevel@tonic-gate if (bufptr + iop->_cnt > bufferend && 300*0Sstevel@tonic-gate !(iop->_flag & _IOREAD)) 301*0Sstevel@tonic-gate _bufsync(iop, bufferend); 302*0Sstevel@tonic-gate /* 303*0Sstevel@tonic-gate * in case of interrupt during last 304*0Sstevel@tonic-gate * several lines 305*0Sstevel@tonic-gate */ 306*0Sstevel@tonic-gate if (iop->_flag & (_IONBF | _IOLBF) && 307*0Sstevel@tonic-gate (iop->_flag & _IONBF || 308*0Sstevel@tonic-gate memchr((char *)(bufptr-count), '\n', count) != 309*0Sstevel@tonic-gate NULL)) 310*0Sstevel@tonic-gate (void) _xflsbuf(iop); 311*0Sstevel@tonic-gate return (ferror(iop) ? EOF : count); 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate /* 315*0Sstevel@tonic-gate * % has been found. 316*0Sstevel@tonic-gate * The following switch is used to parse the format 317*0Sstevel@tonic-gate * specification and to perform the operation specified 318*0Sstevel@tonic-gate * by the format letter. The program repeatedly goes 319*0Sstevel@tonic-gate * back to this switch until the format letter is 320*0Sstevel@tonic-gate * encountered. 321*0Sstevel@tonic-gate */ 322*0Sstevel@tonic-gate width = prefixlength = otherlength = flagword = 323*0Sstevel@tonic-gate suffixlength = 0; 324*0Sstevel@tonic-gate format++; 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate charswitch: 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate switch (fcode = *format++) { 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate case '+': 331*0Sstevel@tonic-gate flagword |= FPLUS; 332*0Sstevel@tonic-gate goto charswitch; 333*0Sstevel@tonic-gate case '-': 334*0Sstevel@tonic-gate flagword |= FMINUS; 335*0Sstevel@tonic-gate flagword &= ~PADZERO; /* ignore 0 flag */ 336*0Sstevel@tonic-gate goto charswitch; 337*0Sstevel@tonic-gate case ' ': 338*0Sstevel@tonic-gate flagword |= FBLANK; 339*0Sstevel@tonic-gate goto charswitch; 340*0Sstevel@tonic-gate case '#': 341*0Sstevel@tonic-gate flagword |= FSHARP; 342*0Sstevel@tonic-gate goto charswitch; 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate /* Scan the field width and precision */ 345*0Sstevel@tonic-gate case '.': 346*0Sstevel@tonic-gate flagword |= DOTSEEN; 347*0Sstevel@tonic-gate prec = 0; 348*0Sstevel@tonic-gate goto charswitch; 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate case '*': 351*0Sstevel@tonic-gate if (isdigit(*format)) { 352*0Sstevel@tonic-gate starflg = 1; 353*0Sstevel@tonic-gate bargs = args; 354*0Sstevel@tonic-gate goto charswitch; 355*0Sstevel@tonic-gate } 356*0Sstevel@tonic-gate if (!(flagword & DOTSEEN)) { 357*0Sstevel@tonic-gate width = va_arg(args.ap, int); 358*0Sstevel@tonic-gate if (width < 0) { 359*0Sstevel@tonic-gate width = -width; 360*0Sstevel@tonic-gate flagword ^= FMINUS; 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate } else { 363*0Sstevel@tonic-gate prec = va_arg(args.ap, int); 364*0Sstevel@tonic-gate if (prec < 0) 365*0Sstevel@tonic-gate prec = 0; 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate goto charswitch; 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate case '$': 370*0Sstevel@tonic-gate { 371*0Sstevel@tonic-gate int position; 372*0Sstevel@tonic-gate stva_list targs; 373*0Sstevel@tonic-gate if (fpos) { 374*0Sstevel@tonic-gate _mkarglst(sformat, sargs, arglst); 375*0Sstevel@tonic-gate fpos = 0; 376*0Sstevel@tonic-gate } 377*0Sstevel@tonic-gate if (flagword & DOTSEEN) { 378*0Sstevel@tonic-gate position = prec; 379*0Sstevel@tonic-gate prec = 0; 380*0Sstevel@tonic-gate } else { 381*0Sstevel@tonic-gate position = width; 382*0Sstevel@tonic-gate width = 0; 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate if (position <= 0) { 385*0Sstevel@tonic-gate /* illegal position */ 386*0Sstevel@tonic-gate format--; 387*0Sstevel@tonic-gate continue; 388*0Sstevel@tonic-gate } 389*0Sstevel@tonic-gate if (position <= MAXARGS) { 390*0Sstevel@tonic-gate targs = arglst[position - 1]; 391*0Sstevel@tonic-gate } else { 392*0Sstevel@tonic-gate targs = arglst[MAXARGS - 1]; 393*0Sstevel@tonic-gate _getarg(sformat, &targs, position); 394*0Sstevel@tonic-gate } 395*0Sstevel@tonic-gate if (!starflg) 396*0Sstevel@tonic-gate args = targs; 397*0Sstevel@tonic-gate else { 398*0Sstevel@tonic-gate starflg = 0; 399*0Sstevel@tonic-gate args = bargs; 400*0Sstevel@tonic-gate if (flagword & DOTSEEN) 401*0Sstevel@tonic-gate prec = va_arg(targs.ap, int); 402*0Sstevel@tonic-gate else 403*0Sstevel@tonic-gate width = va_arg(targs.ap, int); 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate goto charswitch; 406*0Sstevel@tonic-gate } 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate case '0': /* obsolescent spec: leading zero in width */ 409*0Sstevel@tonic-gate /* means pad with leading zeros */ 410*0Sstevel@tonic-gate if (!(flagword & (DOTSEEN | FMINUS))) 411*0Sstevel@tonic-gate flagword |= PADZERO; 412*0Sstevel@tonic-gate /* FALLTHROUGH */ 413*0Sstevel@tonic-gate case '1': 414*0Sstevel@tonic-gate case '2': 415*0Sstevel@tonic-gate case '3': 416*0Sstevel@tonic-gate case '4': 417*0Sstevel@tonic-gate case '5': 418*0Sstevel@tonic-gate case '6': 419*0Sstevel@tonic-gate case '7': 420*0Sstevel@tonic-gate case '8': 421*0Sstevel@tonic-gate case '9': 422*0Sstevel@tonic-gate { int num = fcode - '0'; 423*0Sstevel@tonic-gate while (isdigit(fcode = *format)) { 424*0Sstevel@tonic-gate num = num * 10 + fcode - '0'; 425*0Sstevel@tonic-gate format++; 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate if (flagword & DOTSEEN) 428*0Sstevel@tonic-gate prec = num; 429*0Sstevel@tonic-gate else 430*0Sstevel@tonic-gate width = num; 431*0Sstevel@tonic-gate goto charswitch; 432*0Sstevel@tonic-gate } 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate /* Scan the length modifier */ 435*0Sstevel@tonic-gate case 'l': 436*0Sstevel@tonic-gate flagword |= LENGTH; 437*0Sstevel@tonic-gate goto charswitch; 438*0Sstevel@tonic-gate case 'h': 439*0Sstevel@tonic-gate flagword |= SHORT; 440*0Sstevel@tonic-gate goto charswitch; 441*0Sstevel@tonic-gate case 'L': 442*0Sstevel@tonic-gate goto charswitch; 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate /* 445*0Sstevel@tonic-gate * The character addressed by format must be 446*0Sstevel@tonic-gate * the format letter -- there is nothing 447*0Sstevel@tonic-gate * left for it to be. 448*0Sstevel@tonic-gate * 449*0Sstevel@tonic-gate * The status of the +, -, #, and blank 450*0Sstevel@tonic-gate * flags are reflected in the variable 451*0Sstevel@tonic-gate * "flagword". "width" and "prec" contain 452*0Sstevel@tonic-gate * numbers corresponding to the digit 453*0Sstevel@tonic-gate * strings before and after the decimal 454*0Sstevel@tonic-gate * point, respectively. If there was no 455*0Sstevel@tonic-gate * decimal point, then flagword & DOTSEEN 456*0Sstevel@tonic-gate * is false and the value of prec is meaningless. 457*0Sstevel@tonic-gate * 458*0Sstevel@tonic-gate * The following switch cases set things up 459*0Sstevel@tonic-gate * for printing. What ultimately gets 460*0Sstevel@tonic-gate * printed will be padding blanks, a 461*0Sstevel@tonic-gate * prefix, left padding zeroes, a value, 462*0Sstevel@tonic-gate * right padding zeroes, a suffix, and 463*0Sstevel@tonic-gate * more padding blanks. Padding blanks 464*0Sstevel@tonic-gate * will not appear simultaneously on both 465*0Sstevel@tonic-gate * the left and the right. Each case in 466*0Sstevel@tonic-gate * this switch will compute the value, and 467*0Sstevel@tonic-gate * leave in several variables the informa- 468*0Sstevel@tonic-gate * tion necessary to construct what is to 469*0Sstevel@tonic-gate * be printed. 470*0Sstevel@tonic-gate * 471*0Sstevel@tonic-gate * The prefix is a sign, a blank, "0x", 472*0Sstevel@tonic-gate * "0X", or null, and is addressed by 473*0Sstevel@tonic-gate * "prefix". 474*0Sstevel@tonic-gate * 475*0Sstevel@tonic-gate * The suffix is either null or an 476*0Sstevel@tonic-gate * exponent, and is addressed by "suffix". 477*0Sstevel@tonic-gate * If there is a suffix, the flagword bit 478*0Sstevel@tonic-gate * SUFFIX will be set. 479*0Sstevel@tonic-gate * 480*0Sstevel@tonic-gate * The value to be printed starts at "bp" 481*0Sstevel@tonic-gate * and continues up to and not including 482*0Sstevel@tonic-gate * "p". 483*0Sstevel@tonic-gate * 484*0Sstevel@tonic-gate * "lzero" and "rzero" will contain the 485*0Sstevel@tonic-gate * number of padding zeroes required on 486*0Sstevel@tonic-gate * the left and right, respectively. 487*0Sstevel@tonic-gate * The flagword bits LZERO and RZERO tell 488*0Sstevel@tonic-gate * whether padding zeros are required. 489*0Sstevel@tonic-gate * 490*0Sstevel@tonic-gate * The number of padding blanks, and 491*0Sstevel@tonic-gate * whether they go on the left or the 492*0Sstevel@tonic-gate * right, will be computed on exit from 493*0Sstevel@tonic-gate * the switch. 494*0Sstevel@tonic-gate */ 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate /* 500*0Sstevel@tonic-gate * decimal fixed point representations 501*0Sstevel@tonic-gate * 502*0Sstevel@tonic-gate * HIBITL is 100...000 503*0Sstevel@tonic-gate * binary, and is equal to the maximum 504*0Sstevel@tonic-gate * negative number. 505*0Sstevel@tonic-gate * We assume a 2's complement machine 506*0Sstevel@tonic-gate */ 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate case 'i': 509*0Sstevel@tonic-gate case 'd': 510*0Sstevel@tonic-gate /* Fetch the argument to be printed */ 511*0Sstevel@tonic-gate if (flagword & LENGTH) 512*0Sstevel@tonic-gate val = va_arg(args.ap, long); 513*0Sstevel@tonic-gate else 514*0Sstevel@tonic-gate val = va_arg(args.ap, int); 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate if (flagword & SHORT) 517*0Sstevel@tonic-gate val = (short)val; 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate /* Set buffer pointer to last digit */ 520*0Sstevel@tonic-gate p = bp = buf + MAXDIGS; 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate /* If signed conversion, make sign */ 523*0Sstevel@tonic-gate if (val < 0) { 524*0Sstevel@tonic-gate prefix = "-"; 525*0Sstevel@tonic-gate prefixlength = 1; 526*0Sstevel@tonic-gate /* 527*0Sstevel@tonic-gate * Negate, checking in 528*0Sstevel@tonic-gate * advance for possible 529*0Sstevel@tonic-gate * overflow. 530*0Sstevel@tonic-gate */ 531*0Sstevel@tonic-gate if (val != HIBITL) 532*0Sstevel@tonic-gate val = -val; 533*0Sstevel@tonic-gate else /* number is -HIBITL; convert last */ 534*0Sstevel@tonic-gate /* digit now and get positive number */ 535*0Sstevel@tonic-gate *--bp = _lowdigit(&val); 536*0Sstevel@tonic-gate } else if (flagword & FPLUS) { 537*0Sstevel@tonic-gate prefix = "+"; 538*0Sstevel@tonic-gate prefixlength = 1; 539*0Sstevel@tonic-gate } else if (flagword & FBLANK) { 540*0Sstevel@tonic-gate prefix = " "; 541*0Sstevel@tonic-gate prefixlength = 1; 542*0Sstevel@tonic-gate } 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate decimal: 545*0Sstevel@tonic-gate { long qval = val; 546*0Sstevel@tonic-gate long saveq; 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate if (qval <= 9) { 549*0Sstevel@tonic-gate if (qval != 0 || !(flagword & DOTSEEN)) 550*0Sstevel@tonic-gate *--bp = (char)(qval + '0'); 551*0Sstevel@tonic-gate } else { 552*0Sstevel@tonic-gate do { 553*0Sstevel@tonic-gate saveq = qval; 554*0Sstevel@tonic-gate qval /= 10; 555*0Sstevel@tonic-gate *--bp = (char)(saveq - 556*0Sstevel@tonic-gate qval * 10 + '0'); 557*0Sstevel@tonic-gate } while (qval > 9); 558*0Sstevel@tonic-gate *--bp = (char)(qval + '0'); 559*0Sstevel@tonic-gate pdiff = (ptrdiff_t)saveq; 560*0Sstevel@tonic-gate } 561*0Sstevel@tonic-gate } 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate /* Calculate minimum padding zero requirement */ 564*0Sstevel@tonic-gate if (flagword & DOTSEEN) { 565*0Sstevel@tonic-gate int leadzeroes = prec - (int)(p - bp); 566*0Sstevel@tonic-gate if (leadzeroes > 0) { 567*0Sstevel@tonic-gate otherlength = lzero = leadzeroes; 568*0Sstevel@tonic-gate flagword |= LZERO; 569*0Sstevel@tonic-gate } 570*0Sstevel@tonic-gate } 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate break; 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate case 'u': 575*0Sstevel@tonic-gate /* Fetch the argument to be printed */ 576*0Sstevel@tonic-gate if (flagword & LENGTH) 577*0Sstevel@tonic-gate val = va_arg(args.ap, long); 578*0Sstevel@tonic-gate else 579*0Sstevel@tonic-gate val = va_arg(args.ap, unsigned); 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate if (flagword & SHORT) 582*0Sstevel@tonic-gate val = (unsigned short)val; 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate p = bp = buf + MAXDIGS; 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate if (val & HIBITL) 587*0Sstevel@tonic-gate *--bp = _lowdigit(&val); 588*0Sstevel@tonic-gate 589*0Sstevel@tonic-gate goto decimal; 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate /* 592*0Sstevel@tonic-gate * non-decimal fixed point representations 593*0Sstevel@tonic-gate * for radix equal to a power of two 594*0Sstevel@tonic-gate * 595*0Sstevel@tonic-gate * "mradix" is one less than the radix for the conversion. 596*0Sstevel@tonic-gate * "lradix" is one less than the base 2 log 597*0Sstevel@tonic-gate * of the radix for the conversion. Conversion is unsigned. 598*0Sstevel@tonic-gate * HIBITL is 100...000 599*0Sstevel@tonic-gate * binary, and is equal to the maximum 600*0Sstevel@tonic-gate * negative number. 601*0Sstevel@tonic-gate * We assume a 2's complement machine 602*0Sstevel@tonic-gate */ 603*0Sstevel@tonic-gate 604*0Sstevel@tonic-gate case 'o': 605*0Sstevel@tonic-gate mradix = 7; 606*0Sstevel@tonic-gate lradix = 2; 607*0Sstevel@tonic-gate goto fixed; 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate case 'X': 610*0Sstevel@tonic-gate case 'x': 611*0Sstevel@tonic-gate case 'p': 612*0Sstevel@tonic-gate mradix = 15; 613*0Sstevel@tonic-gate lradix = 3; 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate fixed: 616*0Sstevel@tonic-gate /* Fetch the argument to be printed */ 617*0Sstevel@tonic-gate if (flagword & LENGTH) 618*0Sstevel@tonic-gate val = va_arg(args.ap, long); 619*0Sstevel@tonic-gate else 620*0Sstevel@tonic-gate val = va_arg(args.ap, unsigned); 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate if (flagword & SHORT) 623*0Sstevel@tonic-gate val = (unsigned short)val; 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate /* Set translate table for digits */ 626*0Sstevel@tonic-gate tab = (fcode == 'X') ? uc_digs : lc_digs; 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate /* Entry point when printing a double which is a NaN */ 629*0Sstevel@tonic-gate put_pc: 630*0Sstevel@tonic-gate /* Develop the digits of the value */ 631*0Sstevel@tonic-gate p = bp = buf + MAXDIGS; 632*0Sstevel@tonic-gate { long qval = val; 633*0Sstevel@tonic-gate if (qval == 0) { 634*0Sstevel@tonic-gate if (!(flagword & DOTSEEN)) { 635*0Sstevel@tonic-gate otherlength = lzero = 1; 636*0Sstevel@tonic-gate flagword |= LZERO; 637*0Sstevel@tonic-gate } 638*0Sstevel@tonic-gate } else 639*0Sstevel@tonic-gate do { 640*0Sstevel@tonic-gate *--bp = tab[qval & mradix]; 641*0Sstevel@tonic-gate qval = ((qval >> 1) & ~HIBITL) 642*0Sstevel@tonic-gate >> lradix; 643*0Sstevel@tonic-gate } while (qval != 0); 644*0Sstevel@tonic-gate } 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate /* Calculate minimum padding zero requirement */ 647*0Sstevel@tonic-gate if (flagword & DOTSEEN) { 648*0Sstevel@tonic-gate int leadzeroes = prec - (int)(p - bp); 649*0Sstevel@tonic-gate if (leadzeroes > 0) { 650*0Sstevel@tonic-gate otherlength = lzero = leadzeroes; 651*0Sstevel@tonic-gate flagword |= LZERO; 652*0Sstevel@tonic-gate } 653*0Sstevel@tonic-gate } 654*0Sstevel@tonic-gate 655*0Sstevel@tonic-gate /* Handle the # flag */ 656*0Sstevel@tonic-gate if (flagword & FSHARP && val != 0) 657*0Sstevel@tonic-gate switch (fcode) { 658*0Sstevel@tonic-gate case 'o': 659*0Sstevel@tonic-gate if (!(flagword & LZERO)) { 660*0Sstevel@tonic-gate otherlength = lzero = 1; 661*0Sstevel@tonic-gate flagword |= LZERO; 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate break; 664*0Sstevel@tonic-gate case 'x': 665*0Sstevel@tonic-gate prefix = "0x"; 666*0Sstevel@tonic-gate prefixlength = 2; 667*0Sstevel@tonic-gate break; 668*0Sstevel@tonic-gate case 'X': 669*0Sstevel@tonic-gate prefix = "0X"; 670*0Sstevel@tonic-gate prefixlength = 2; 671*0Sstevel@tonic-gate break; 672*0Sstevel@tonic-gate } 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate break; 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate case 'E': 677*0Sstevel@tonic-gate case 'e': 678*0Sstevel@tonic-gate /* 679*0Sstevel@tonic-gate * E-format. The general strategy 680*0Sstevel@tonic-gate * here is fairly easy: we take 681*0Sstevel@tonic-gate * what ecvt gives us and re-format it. 682*0Sstevel@tonic-gate */ 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate /* Establish default precision */ 685*0Sstevel@tonic-gate if (!(flagword & DOTSEEN)) 686*0Sstevel@tonic-gate prec = 6; 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate /* Fetch the value */ 689*0Sstevel@tonic-gate dval = va_arg(args.ap, double); 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate /* Check for NaNs and Infinities */ 692*0Sstevel@tonic-gate if (IsNANorINF(dval)) { 693*0Sstevel@tonic-gate if (IsINF(dval)) { 694*0Sstevel@tonic-gate if (IsNegNAN(dval)) 695*0Sstevel@tonic-gate neg_in = 1; 696*0Sstevel@tonic-gate inf_nan = 1; 697*0Sstevel@tonic-gate bp = (fcode == 'E')? uc_inf: lc_inf; 698*0Sstevel@tonic-gate p = bp + 3; 699*0Sstevel@tonic-gate break; 700*0Sstevel@tonic-gate } else { 701*0Sstevel@tonic-gate if (IsNegNAN(dval)) 702*0Sstevel@tonic-gate neg_in = 1; 703*0Sstevel@tonic-gate inf_nan = 1; 704*0Sstevel@tonic-gate val = GETNaNPC(dval); 705*0Sstevel@tonic-gate NaN_flg = SNLEN; 706*0Sstevel@tonic-gate mradix = 15; 707*0Sstevel@tonic-gate lradix = 3; 708*0Sstevel@tonic-gate if (fcode == 'E') { 709*0Sstevel@tonic-gate SNAN = uc_nan; 710*0Sstevel@tonic-gate tab = uc_digs; 711*0Sstevel@tonic-gate } else { 712*0Sstevel@tonic-gate SNAN = lc_nan; 713*0Sstevel@tonic-gate tab = lc_digs; 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate goto put_pc; 716*0Sstevel@tonic-gate } 717*0Sstevel@tonic-gate } 718*0Sstevel@tonic-gate /* Develop the mantissa */ 719*0Sstevel@tonic-gate bp = ecvt(dval, min(prec + 1, MAXECVT), &decpt, &sign); 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate /* Determine the prefix */ 722*0Sstevel@tonic-gate e_merge: 723*0Sstevel@tonic-gate if (sign) { 724*0Sstevel@tonic-gate prefix = "-"; 725*0Sstevel@tonic-gate prefixlength = 1; 726*0Sstevel@tonic-gate } else if (flagword & FPLUS) { 727*0Sstevel@tonic-gate prefix = "+"; 728*0Sstevel@tonic-gate prefixlength = 1; 729*0Sstevel@tonic-gate } else if (flagword & FBLANK) { 730*0Sstevel@tonic-gate prefix = " "; 731*0Sstevel@tonic-gate prefixlength = 1; 732*0Sstevel@tonic-gate } 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate /* Place the first digit in the buffer */ 735*0Sstevel@tonic-gate p = &buf[0]; 736*0Sstevel@tonic-gate *p++ = (*bp != '\0') ? *bp++ : '0'; 737*0Sstevel@tonic-gate 738*0Sstevel@tonic-gate /* Put in a decimal point if needed */ 739*0Sstevel@tonic-gate if (prec != 0 || (flagword & FSHARP)) 740*0Sstevel@tonic-gate *p++ = _numeric[0]; 741*0Sstevel@tonic-gate 742*0Sstevel@tonic-gate /* Create the rest of the mantissa */ 743*0Sstevel@tonic-gate { int rz = prec; 744*0Sstevel@tonic-gate for (; rz > 0 && *bp != '\0'; --rz) 745*0Sstevel@tonic-gate *p++ = *bp++; 746*0Sstevel@tonic-gate if (rz > 0) { 747*0Sstevel@tonic-gate otherlength = rzero = rz; 748*0Sstevel@tonic-gate flagword |= RZERO; 749*0Sstevel@tonic-gate } 750*0Sstevel@tonic-gate } 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate bp = &buf[0]; 753*0Sstevel@tonic-gate 754*0Sstevel@tonic-gate /* Create the exponent */ 755*0Sstevel@tonic-gate *(suffix = &expbuf[MAXESIZ]) = '\0'; 756*0Sstevel@tonic-gate if (dval != 0) { 757*0Sstevel@tonic-gate int nn = decpt - 1; 758*0Sstevel@tonic-gate if (nn < 0) 759*0Sstevel@tonic-gate nn = -nn; 760*0Sstevel@tonic-gate for (; nn > 9; nn /= 10) 761*0Sstevel@tonic-gate *--suffix = todigit(nn % 10); 762*0Sstevel@tonic-gate *--suffix = todigit(nn); 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate /* Prepend leading zeroes to the exponent */ 766*0Sstevel@tonic-gate while (suffix > &expbuf[MAXESIZ - 2]) 767*0Sstevel@tonic-gate *--suffix = '0'; 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate /* Put in the exponent sign */ 770*0Sstevel@tonic-gate *--suffix = (decpt > 0 || dval == 0) ? '+' : '-'; 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate /* Put in the e */ 773*0Sstevel@tonic-gate *--suffix = isupper(fcode) ? 'E' : 'e'; 774*0Sstevel@tonic-gate 775*0Sstevel@tonic-gate /* compute size of suffix */ 776*0Sstevel@tonic-gate otherlength += (suffixlength = 777*0Sstevel@tonic-gate (int)(&expbuf[MAXESIZ] - suffix)); 778*0Sstevel@tonic-gate flagword |= SUFFIX; 779*0Sstevel@tonic-gate 780*0Sstevel@tonic-gate break; 781*0Sstevel@tonic-gate 782*0Sstevel@tonic-gate case 'f': 783*0Sstevel@tonic-gate /* 784*0Sstevel@tonic-gate * F-format floating point. This is a 785*0Sstevel@tonic-gate * good deal less simple than E-format. 786*0Sstevel@tonic-gate * The overall strategy will be to call 787*0Sstevel@tonic-gate * fcvt, reformat its result into buf, 788*0Sstevel@tonic-gate * and calculate how many trailing 789*0Sstevel@tonic-gate * zeroes will be required. There will 790*0Sstevel@tonic-gate * never be any leading zeroes needed. 791*0Sstevel@tonic-gate */ 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate /* Establish default precision */ 794*0Sstevel@tonic-gate if (!(flagword & DOTSEEN)) 795*0Sstevel@tonic-gate prec = 6; 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate /* Fetch the value */ 798*0Sstevel@tonic-gate dval = va_arg(args.ap, double); 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate /* Check for NaNs and Infinities */ 801*0Sstevel@tonic-gate if (IsNANorINF(dval)) { 802*0Sstevel@tonic-gate if (IsINF(dval)) { 803*0Sstevel@tonic-gate if (IsNegNAN(dval)) 804*0Sstevel@tonic-gate neg_in = 1; 805*0Sstevel@tonic-gate inf_nan = 1; 806*0Sstevel@tonic-gate bp = lc_inf; 807*0Sstevel@tonic-gate p = bp + 3; 808*0Sstevel@tonic-gate break; 809*0Sstevel@tonic-gate } else { 810*0Sstevel@tonic-gate if (IsNegNAN(dval)) 811*0Sstevel@tonic-gate neg_in = 1; 812*0Sstevel@tonic-gate inf_nan = 1; 813*0Sstevel@tonic-gate val = GETNaNPC(dval); 814*0Sstevel@tonic-gate NaN_flg = SNLEN; 815*0Sstevel@tonic-gate mradix = 15; 816*0Sstevel@tonic-gate lradix = 3; 817*0Sstevel@tonic-gate tab = lc_digs; 818*0Sstevel@tonic-gate SNAN = lc_nan; 819*0Sstevel@tonic-gate goto put_pc; 820*0Sstevel@tonic-gate } 821*0Sstevel@tonic-gate } 822*0Sstevel@tonic-gate /* Do the conversion */ 823*0Sstevel@tonic-gate bp = fcvt(dval, min(prec, MAXFCVT), &decpt, &sign); 824*0Sstevel@tonic-gate 825*0Sstevel@tonic-gate /* Determine the prefix */ 826*0Sstevel@tonic-gate f_merge: 827*0Sstevel@tonic-gate if (sign) { 828*0Sstevel@tonic-gate prefix = "-"; 829*0Sstevel@tonic-gate prefixlength = 1; 830*0Sstevel@tonic-gate } else if (flagword & FPLUS) { 831*0Sstevel@tonic-gate prefix = "+"; 832*0Sstevel@tonic-gate prefixlength = 1; 833*0Sstevel@tonic-gate } else if (flagword & FBLANK) { 834*0Sstevel@tonic-gate prefix = " "; 835*0Sstevel@tonic-gate prefixlength = 1; 836*0Sstevel@tonic-gate } 837*0Sstevel@tonic-gate 838*0Sstevel@tonic-gate /* Initialize buffer pointer */ 839*0Sstevel@tonic-gate p = &buf[0]; 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate { int nn = decpt; 842*0Sstevel@tonic-gate 843*0Sstevel@tonic-gate /* Emit the digits before the decimal point */ 844*0Sstevel@tonic-gate k = 0; 845*0Sstevel@tonic-gate do { 846*0Sstevel@tonic-gate *p++ = (nn <= 0 || *bp == '\0' || 847*0Sstevel@tonic-gate k >= MAXFSIG) ? 848*0Sstevel@tonic-gate '0' : (k++, *bp++); 849*0Sstevel@tonic-gate } while (--nn > 0); 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate /* Decide whether we need a decimal point */ 852*0Sstevel@tonic-gate if ((flagword & FSHARP) || prec > 0) 853*0Sstevel@tonic-gate *p++ = _numeric[0]; 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate /* Digits (if any) after the decimal point */ 856*0Sstevel@tonic-gate nn = min(prec, MAXFCVT); 857*0Sstevel@tonic-gate if (prec > nn) { 858*0Sstevel@tonic-gate flagword |= RZERO; 859*0Sstevel@tonic-gate otherlength = rzero = prec - nn; 860*0Sstevel@tonic-gate } 861*0Sstevel@tonic-gate while (--nn >= 0) 862*0Sstevel@tonic-gate *p++ = (++decpt <= 0 || *bp == '\0' || 863*0Sstevel@tonic-gate k >= MAXFSIG) ? 864*0Sstevel@tonic-gate '0' : (k++, *bp++); 865*0Sstevel@tonic-gate } 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate bp = &buf[0]; 868*0Sstevel@tonic-gate 869*0Sstevel@tonic-gate break; 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gate case 'G': 872*0Sstevel@tonic-gate case 'g': 873*0Sstevel@tonic-gate /* 874*0Sstevel@tonic-gate * g-format. We play around a bit 875*0Sstevel@tonic-gate * and then jump into e or f, as needed. 876*0Sstevel@tonic-gate */ 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate /* Establish default precision */ 879*0Sstevel@tonic-gate if (!(flagword & DOTSEEN)) 880*0Sstevel@tonic-gate prec = 6; 881*0Sstevel@tonic-gate else if (prec == 0) 882*0Sstevel@tonic-gate prec = 1; 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate /* Fetch the value */ 885*0Sstevel@tonic-gate dval = va_arg(args.ap, double); 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate /* Check for NaN and Infinities */ 888*0Sstevel@tonic-gate if (IsNANorINF(dval)) { 889*0Sstevel@tonic-gate if (IsINF(dval)) { 890*0Sstevel@tonic-gate if (IsNegNAN(dval)) 891*0Sstevel@tonic-gate neg_in = 1; 892*0Sstevel@tonic-gate bp = (fcode == 'G') ? uc_inf : lc_inf; 893*0Sstevel@tonic-gate p = bp + 3; 894*0Sstevel@tonic-gate inf_nan = 1; 895*0Sstevel@tonic-gate break; 896*0Sstevel@tonic-gate } else { 897*0Sstevel@tonic-gate if (IsNegNAN(dval)) 898*0Sstevel@tonic-gate neg_in = 1; 899*0Sstevel@tonic-gate inf_nan = 1; 900*0Sstevel@tonic-gate val = GETNaNPC(dval); 901*0Sstevel@tonic-gate NaN_flg = SNLEN; 902*0Sstevel@tonic-gate mradix = 15; 903*0Sstevel@tonic-gate lradix = 3; 904*0Sstevel@tonic-gate if (fcode == 'G') { 905*0Sstevel@tonic-gate SNAN = uc_nan; 906*0Sstevel@tonic-gate tab = uc_digs; 907*0Sstevel@tonic-gate } else { 908*0Sstevel@tonic-gate SNAN = lc_nan; 909*0Sstevel@tonic-gate tab = lc_digs; 910*0Sstevel@tonic-gate } 911*0Sstevel@tonic-gate goto put_pc; 912*0Sstevel@tonic-gate } 913*0Sstevel@tonic-gate } 914*0Sstevel@tonic-gate 915*0Sstevel@tonic-gate /* Do the conversion */ 916*0Sstevel@tonic-gate bp = ecvt(dval, min(prec, MAXECVT), &decpt, &sign); 917*0Sstevel@tonic-gate if (dval == 0) 918*0Sstevel@tonic-gate decpt = 1; 919*0Sstevel@tonic-gate 920*0Sstevel@tonic-gate { int kk = prec; 921*0Sstevel@tonic-gate size_t sz; 922*0Sstevel@tonic-gate 923*0Sstevel@tonic-gate if (!(flagword & FSHARP)) { 924*0Sstevel@tonic-gate sz = strlen(bp); 925*0Sstevel@tonic-gate if (sz < kk) 926*0Sstevel@tonic-gate kk = (int)sz; 927*0Sstevel@tonic-gate while (kk >= 1 && bp[kk-1] == '0') 928*0Sstevel@tonic-gate --kk; 929*0Sstevel@tonic-gate } 930*0Sstevel@tonic-gate 931*0Sstevel@tonic-gate if (decpt < -3 || decpt > prec) { 932*0Sstevel@tonic-gate prec = kk - 1; 933*0Sstevel@tonic-gate goto e_merge; 934*0Sstevel@tonic-gate } 935*0Sstevel@tonic-gate prec = kk - decpt; 936*0Sstevel@tonic-gate goto f_merge; 937*0Sstevel@tonic-gate } 938*0Sstevel@tonic-gate 939*0Sstevel@tonic-gate case '%': 940*0Sstevel@tonic-gate buf[0] = (char)fcode; 941*0Sstevel@tonic-gate goto c_merge; 942*0Sstevel@tonic-gate 943*0Sstevel@tonic-gate case 'c': 944*0Sstevel@tonic-gate buf[0] = va_arg(args.ap, int); 945*0Sstevel@tonic-gate c_merge: 946*0Sstevel@tonic-gate p = (bp = &buf[0]) + 1; 947*0Sstevel@tonic-gate break; 948*0Sstevel@tonic-gate 949*0Sstevel@tonic-gate case 's': 950*0Sstevel@tonic-gate bp = va_arg(args.ap, char *); 951*0Sstevel@tonic-gate if (!(flagword & DOTSEEN)) 952*0Sstevel@tonic-gate p = bp + strlen(bp); 953*0Sstevel@tonic-gate else { /* a strnlen function would be useful here! */ 954*0Sstevel@tonic-gate char *qp = bp; 955*0Sstevel@tonic-gate while (*qp++ != '\0' && --prec >= 0) 956*0Sstevel@tonic-gate ; 957*0Sstevel@tonic-gate p = qp - 1; 958*0Sstevel@tonic-gate } 959*0Sstevel@tonic-gate break; 960*0Sstevel@tonic-gate 961*0Sstevel@tonic-gate case 'n': 962*0Sstevel@tonic-gate { 963*0Sstevel@tonic-gate if (flagword & LENGTH) { 964*0Sstevel@tonic-gate long *svcount; 965*0Sstevel@tonic-gate svcount = va_arg(args.ap, long *); 966*0Sstevel@tonic-gate *svcount = count; 967*0Sstevel@tonic-gate } else if (flagword & SHORT) { 968*0Sstevel@tonic-gate short *svcount; 969*0Sstevel@tonic-gate svcount = va_arg(args.ap, short *); 970*0Sstevel@tonic-gate *svcount = (short)count; 971*0Sstevel@tonic-gate } else { 972*0Sstevel@tonic-gate int *svcount; 973*0Sstevel@tonic-gate svcount = va_arg(args.ap, int *); 974*0Sstevel@tonic-gate *svcount = count; 975*0Sstevel@tonic-gate } 976*0Sstevel@tonic-gate continue; 977*0Sstevel@tonic-gate } 978*0Sstevel@tonic-gate 979*0Sstevel@tonic-gate default: /* this is technically an error; what we do is to */ 980*0Sstevel@tonic-gate /* back up the format pointer to the offending char */ 981*0Sstevel@tonic-gate /* and continue with the format scan */ 982*0Sstevel@tonic-gate format--; 983*0Sstevel@tonic-gate continue; 984*0Sstevel@tonic-gate 985*0Sstevel@tonic-gate } 986*0Sstevel@tonic-gate 987*0Sstevel@tonic-gate if (inf_nan) { 988*0Sstevel@tonic-gate if (neg_in) { 989*0Sstevel@tonic-gate prefix = "-"; 990*0Sstevel@tonic-gate prefixlength = 1; 991*0Sstevel@tonic-gate neg_in = 0; 992*0Sstevel@tonic-gate } else if (flagword & FPLUS) { 993*0Sstevel@tonic-gate prefix = "+"; 994*0Sstevel@tonic-gate prefixlength = 1; 995*0Sstevel@tonic-gate } else if (flagword & FBLANK) { 996*0Sstevel@tonic-gate prefix = " "; 997*0Sstevel@tonic-gate prefixlength = 1; 998*0Sstevel@tonic-gate } 999*0Sstevel@tonic-gate inf_nan = 0; 1000*0Sstevel@tonic-gate } 1001*0Sstevel@tonic-gate 1002*0Sstevel@tonic-gate /* Calculate number of padding blanks */ 1003*0Sstevel@tonic-gate k = (int)(pdiff = p - bp) + prefixlength + otherlength + 1004*0Sstevel@tonic-gate NaN_flg; 1005*0Sstevel@tonic-gate if (width <= k) 1006*0Sstevel@tonic-gate count += k; 1007*0Sstevel@tonic-gate else { 1008*0Sstevel@tonic-gate count += width; 1009*0Sstevel@tonic-gate 1010*0Sstevel@tonic-gate /* Set up for padding zeroes if requested */ 1011*0Sstevel@tonic-gate /* Otherwise emit padding blanks unless output is */ 1012*0Sstevel@tonic-gate /* to be left-justified. */ 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate if (flagword & PADZERO) { 1015*0Sstevel@tonic-gate if (!(flagword & LZERO)) { 1016*0Sstevel@tonic-gate flagword |= LZERO; 1017*0Sstevel@tonic-gate lzero = width - k; 1018*0Sstevel@tonic-gate } 1019*0Sstevel@tonic-gate else 1020*0Sstevel@tonic-gate lzero += width - k; 1021*0Sstevel@tonic-gate k = width; /* cancel padding blanks */ 1022*0Sstevel@tonic-gate } else 1023*0Sstevel@tonic-gate /* Blanks on left if required */ 1024*0Sstevel@tonic-gate if (!(flagword & FMINUS)) 1025*0Sstevel@tonic-gate PAD(_blanks, width - k); 1026*0Sstevel@tonic-gate } 1027*0Sstevel@tonic-gate 1028*0Sstevel@tonic-gate /* Prefix, if any */ 1029*0Sstevel@tonic-gate if (prefixlength != 0) 1030*0Sstevel@tonic-gate PUT(prefix, prefixlength); 1031*0Sstevel@tonic-gate 1032*0Sstevel@tonic-gate /* If value is NaN, put string NaN */ 1033*0Sstevel@tonic-gate if (NaN_flg) { 1034*0Sstevel@tonic-gate PUT(SNAN, SNLEN); 1035*0Sstevel@tonic-gate NaN_flg = 0; 1036*0Sstevel@tonic-gate } 1037*0Sstevel@tonic-gate 1038*0Sstevel@tonic-gate /* Zeroes on the left */ 1039*0Sstevel@tonic-gate if (flagword & LZERO) 1040*0Sstevel@tonic-gate PAD(_zeroes, lzero); 1041*0Sstevel@tonic-gate 1042*0Sstevel@tonic-gate /* The value itself */ 1043*0Sstevel@tonic-gate if (pdiff > 0) 1044*0Sstevel@tonic-gate PUT(bp, pdiff); 1045*0Sstevel@tonic-gate 1046*0Sstevel@tonic-gate if (flagword & (RZERO | SUFFIX | FMINUS)) { 1047*0Sstevel@tonic-gate /* Zeroes on the right */ 1048*0Sstevel@tonic-gate if (flagword & RZERO) 1049*0Sstevel@tonic-gate PAD(_zeroes, rzero); 1050*0Sstevel@tonic-gate 1051*0Sstevel@tonic-gate /* The suffix */ 1052*0Sstevel@tonic-gate if (flagword & SUFFIX) 1053*0Sstevel@tonic-gate PUT(suffix, suffixlength); 1054*0Sstevel@tonic-gate 1055*0Sstevel@tonic-gate /* Blanks on the right if required */ 1056*0Sstevel@tonic-gate if (flagword & FMINUS && width > k) 1057*0Sstevel@tonic-gate PAD(_blanks, width - k); 1058*0Sstevel@tonic-gate } 1059*0Sstevel@tonic-gate } 1060*0Sstevel@tonic-gate } 1061*0Sstevel@tonic-gate 1062*0Sstevel@tonic-gate /* 1063*0Sstevel@tonic-gate * This function initializes arglst, to contain the appropriate va_list values 1064*0Sstevel@tonic-gate * for the first MAXARGS arguments. 1065*0Sstevel@tonic-gate */ 1066*0Sstevel@tonic-gate void 1067*0Sstevel@tonic-gate _mkarglst(char *fmt, stva_list args, stva_list arglst[]) 1068*0Sstevel@tonic-gate { 1069*0Sstevel@tonic-gate static char digits[] = "01234567890", skips[] = "# +-.0123456789hL$"; 1070*0Sstevel@tonic-gate 1071*0Sstevel@tonic-gate enum types {INT = 1, LONG, CHAR_PTR, DOUBLE, LONG_DOUBLE, VOID_PTR, 1072*0Sstevel@tonic-gate LONG_PTR, INT_PTR}; 1073*0Sstevel@tonic-gate enum types typelst[MAXARGS], curtype; 1074*0Sstevel@tonic-gate int maxnum, n, curargno, flags; 1075*0Sstevel@tonic-gate 1076*0Sstevel@tonic-gate /* 1077*0Sstevel@tonic-gate * Algorithm 1. set all argument types to zero. 1078*0Sstevel@tonic-gate * 2. walk through fmt putting arg types in typelst[]. 1079*0Sstevel@tonic-gate * 3. walk through args using va_arg(args.ap, typelst[n]) 1080*0Sstevel@tonic-gate * and set arglst[] to the appropriate values. 1081*0Sstevel@tonic-gate * Assumptions: Cannot use %*$... to specify variable position. 1082*0Sstevel@tonic-gate */ 1083*0Sstevel@tonic-gate 1084*0Sstevel@tonic-gate (void) memset((void *)typelst, 0, sizeof (typelst)); 1085*0Sstevel@tonic-gate maxnum = -1; 1086*0Sstevel@tonic-gate curargno = 0; 1087*0Sstevel@tonic-gate while ((fmt = strchr(fmt, '%')) != 0) { 1088*0Sstevel@tonic-gate size_t sz; 1089*0Sstevel@tonic-gate 1090*0Sstevel@tonic-gate fmt++; /* skip % */ 1091*0Sstevel@tonic-gate if (fmt[sz = strspn(fmt, digits)] == '$') { 1092*0Sstevel@tonic-gate curargno = atoi(fmt) - 1; 1093*0Sstevel@tonic-gate /* convert to zero base */ 1094*0Sstevel@tonic-gate if (curargno < 0) 1095*0Sstevel@tonic-gate continue; 1096*0Sstevel@tonic-gate fmt += sz + 1; 1097*0Sstevel@tonic-gate } 1098*0Sstevel@tonic-gate flags = 0; 1099*0Sstevel@tonic-gate again:; 1100*0Sstevel@tonic-gate fmt += strspn(fmt, skips); 1101*0Sstevel@tonic-gate switch (*fmt++) { 1102*0Sstevel@tonic-gate case '%': /* there is no argument! */ 1103*0Sstevel@tonic-gate continue; 1104*0Sstevel@tonic-gate case 'l': 1105*0Sstevel@tonic-gate flags |= 0x1; 1106*0Sstevel@tonic-gate goto again; 1107*0Sstevel@tonic-gate case '*': /* int argument used for value */ 1108*0Sstevel@tonic-gate /* check if there is a positional parameter */ 1109*0Sstevel@tonic-gate if (isdigit(*fmt)) { 1110*0Sstevel@tonic-gate int targno; 1111*0Sstevel@tonic-gate targno = atoi(fmt) - 1; 1112*0Sstevel@tonic-gate fmt += strspn(fmt, digits); 1113*0Sstevel@tonic-gate if (*fmt == '$') 1114*0Sstevel@tonic-gate fmt++; /* skip '$' */ 1115*0Sstevel@tonic-gate if (targno >= 0 && targno < MAXARGS) { 1116*0Sstevel@tonic-gate typelst[targno] = INT; 1117*0Sstevel@tonic-gate if (maxnum < targno) 1118*0Sstevel@tonic-gate maxnum = targno; 1119*0Sstevel@tonic-gate } 1120*0Sstevel@tonic-gate goto again; 1121*0Sstevel@tonic-gate } 1122*0Sstevel@tonic-gate flags |= 0x2; 1123*0Sstevel@tonic-gate curtype = INT; 1124*0Sstevel@tonic-gate break; 1125*0Sstevel@tonic-gate case 'e': 1126*0Sstevel@tonic-gate case 'E': 1127*0Sstevel@tonic-gate case 'f': 1128*0Sstevel@tonic-gate case 'g': 1129*0Sstevel@tonic-gate case 'G': 1130*0Sstevel@tonic-gate curtype = DOUBLE; 1131*0Sstevel@tonic-gate break; 1132*0Sstevel@tonic-gate case 's': 1133*0Sstevel@tonic-gate curtype = CHAR_PTR; 1134*0Sstevel@tonic-gate break; 1135*0Sstevel@tonic-gate case 'p': 1136*0Sstevel@tonic-gate curtype = VOID_PTR; 1137*0Sstevel@tonic-gate break; 1138*0Sstevel@tonic-gate case 'n': 1139*0Sstevel@tonic-gate if (flags & 0x1) 1140*0Sstevel@tonic-gate curtype = LONG_PTR; 1141*0Sstevel@tonic-gate else 1142*0Sstevel@tonic-gate curtype = INT_PTR; 1143*0Sstevel@tonic-gate break; 1144*0Sstevel@tonic-gate default: 1145*0Sstevel@tonic-gate if (flags & 0x1) 1146*0Sstevel@tonic-gate curtype = LONG; 1147*0Sstevel@tonic-gate else 1148*0Sstevel@tonic-gate curtype = INT; 1149*0Sstevel@tonic-gate break; 1150*0Sstevel@tonic-gate } 1151*0Sstevel@tonic-gate if (curargno >= 0 && curargno < MAXARGS) { 1152*0Sstevel@tonic-gate typelst[curargno] = curtype; 1153*0Sstevel@tonic-gate if (maxnum < curargno) 1154*0Sstevel@tonic-gate maxnum = curargno; 1155*0Sstevel@tonic-gate } 1156*0Sstevel@tonic-gate curargno++; /* default to next in list */ 1157*0Sstevel@tonic-gate if (flags & 0x2) /* took care of *, keep going */ 1158*0Sstevel@tonic-gate { 1159*0Sstevel@tonic-gate flags ^= 0x2; 1160*0Sstevel@tonic-gate goto again; 1161*0Sstevel@tonic-gate } 1162*0Sstevel@tonic-gate } 1163*0Sstevel@tonic-gate for (n = 0; n <= maxnum; n++) { 1164*0Sstevel@tonic-gate arglst[n] = args; 1165*0Sstevel@tonic-gate if (typelst[n] == 0) 1166*0Sstevel@tonic-gate typelst[n] = INT; 1167*0Sstevel@tonic-gate 1168*0Sstevel@tonic-gate switch (typelst[n]) { 1169*0Sstevel@tonic-gate case INT: 1170*0Sstevel@tonic-gate (void) va_arg(args.ap, int); 1171*0Sstevel@tonic-gate break; 1172*0Sstevel@tonic-gate case LONG: 1173*0Sstevel@tonic-gate (void) va_arg(args.ap, long); 1174*0Sstevel@tonic-gate break; 1175*0Sstevel@tonic-gate case CHAR_PTR: 1176*0Sstevel@tonic-gate (void) va_arg(args.ap, char *); 1177*0Sstevel@tonic-gate break; 1178*0Sstevel@tonic-gate case DOUBLE: 1179*0Sstevel@tonic-gate (void) va_arg(args.ap, double); 1180*0Sstevel@tonic-gate break; 1181*0Sstevel@tonic-gate case LONG_DOUBLE: 1182*0Sstevel@tonic-gate (void) va_arg(args.ap, double); 1183*0Sstevel@tonic-gate break; 1184*0Sstevel@tonic-gate case VOID_PTR: 1185*0Sstevel@tonic-gate (void) va_arg(args.ap, void *); 1186*0Sstevel@tonic-gate break; 1187*0Sstevel@tonic-gate case LONG_PTR: 1188*0Sstevel@tonic-gate (void) va_arg(args.ap, long *); 1189*0Sstevel@tonic-gate break; 1190*0Sstevel@tonic-gate case INT_PTR: 1191*0Sstevel@tonic-gate (void) va_arg(args.ap, int *); 1192*0Sstevel@tonic-gate break; 1193*0Sstevel@tonic-gate } 1194*0Sstevel@tonic-gate } 1195*0Sstevel@tonic-gate } 1196*0Sstevel@tonic-gate 1197*0Sstevel@tonic-gate /* 1198*0Sstevel@tonic-gate * This function is used to find the va_list value for arguments whose 1199*0Sstevel@tonic-gate * position is greater than MAXARGS. This function is slow, so hopefully 1200*0Sstevel@tonic-gate * MAXARGS will be big enough so that this function need only be called in 1201*0Sstevel@tonic-gate * unusual circumstances. 1202*0Sstevel@tonic-gate * pargs is assumed to contain the value of arglst[MAXARGS - 1]. 1203*0Sstevel@tonic-gate */ 1204*0Sstevel@tonic-gate void 1205*0Sstevel@tonic-gate _getarg(char *fmt, stva_list *pargs, int argno) 1206*0Sstevel@tonic-gate { 1207*0Sstevel@tonic-gate static char digits[] = "01234567890", skips[] = "# +-.0123456789h$"; 1208*0Sstevel@tonic-gate int i, curargno, flags; 1209*0Sstevel@tonic-gate size_t n; 1210*0Sstevel@tonic-gate char *sfmt = fmt; 1211*0Sstevel@tonic-gate int found = 1; 1212*0Sstevel@tonic-gate 1213*0Sstevel@tonic-gate i = MAXARGS; 1214*0Sstevel@tonic-gate curargno = 1; 1215*0Sstevel@tonic-gate while (found) { 1216*0Sstevel@tonic-gate fmt = sfmt; 1217*0Sstevel@tonic-gate found = 0; 1218*0Sstevel@tonic-gate while ((i != argno) && (fmt = strchr(fmt, '%')) != 0) { 1219*0Sstevel@tonic-gate fmt++; /* skip % */ 1220*0Sstevel@tonic-gate if (fmt[n = strspn(fmt, digits)] == '$') { 1221*0Sstevel@tonic-gate curargno = atoi(fmt); 1222*0Sstevel@tonic-gate if (curargno <= 0) 1223*0Sstevel@tonic-gate continue; 1224*0Sstevel@tonic-gate fmt += n + 1; 1225*0Sstevel@tonic-gate } 1226*0Sstevel@tonic-gate 1227*0Sstevel@tonic-gate /* find conversion specifier for next argument */ 1228*0Sstevel@tonic-gate if (i != curargno) { 1229*0Sstevel@tonic-gate curargno++; 1230*0Sstevel@tonic-gate continue; 1231*0Sstevel@tonic-gate } else 1232*0Sstevel@tonic-gate found = 1; 1233*0Sstevel@tonic-gate flags = 0; 1234*0Sstevel@tonic-gate again:; 1235*0Sstevel@tonic-gate fmt += strspn(fmt, skips); 1236*0Sstevel@tonic-gate switch (*fmt++) { 1237*0Sstevel@tonic-gate case '%': /* there is no argument! */ 1238*0Sstevel@tonic-gate continue; 1239*0Sstevel@tonic-gate case 'l': 1240*0Sstevel@tonic-gate flags |= 0x1; 1241*0Sstevel@tonic-gate goto again; 1242*0Sstevel@tonic-gate case '*': /* int argument used for value */ 1243*0Sstevel@tonic-gate /* 1244*0Sstevel@tonic-gate * check if there is a positional parameter; 1245*0Sstevel@tonic-gate * if so, just skip it; its size will be 1246*0Sstevel@tonic-gate * correctly determined by default 1247*0Sstevel@tonic-gate */ 1248*0Sstevel@tonic-gate if (isdigit(*fmt)) { 1249*0Sstevel@tonic-gate fmt += strspn(fmt, digits); 1250*0Sstevel@tonic-gate if (*fmt == '$') 1251*0Sstevel@tonic-gate fmt++; /* skip '$' */ 1252*0Sstevel@tonic-gate goto again; 1253*0Sstevel@tonic-gate } 1254*0Sstevel@tonic-gate flags |= 0x2; 1255*0Sstevel@tonic-gate (void) va_arg((*pargs).ap, int); 1256*0Sstevel@tonic-gate break; 1257*0Sstevel@tonic-gate case 'e': 1258*0Sstevel@tonic-gate case 'E': 1259*0Sstevel@tonic-gate case 'f': 1260*0Sstevel@tonic-gate case 'g': 1261*0Sstevel@tonic-gate case 'G': 1262*0Sstevel@tonic-gate if (flags & 0x1) 1263*0Sstevel@tonic-gate (void) va_arg((*pargs).ap, double); 1264*0Sstevel@tonic-gate else 1265*0Sstevel@tonic-gate (void) va_arg((*pargs).ap, double); 1266*0Sstevel@tonic-gate break; 1267*0Sstevel@tonic-gate case 's': 1268*0Sstevel@tonic-gate (void) va_arg((*pargs).ap, char *); 1269*0Sstevel@tonic-gate break; 1270*0Sstevel@tonic-gate case 'p': 1271*0Sstevel@tonic-gate (void) va_arg((*pargs).ap, void *); 1272*0Sstevel@tonic-gate break; 1273*0Sstevel@tonic-gate case 'n': 1274*0Sstevel@tonic-gate if (flags & 0x1) 1275*0Sstevel@tonic-gate (void) va_arg((*pargs).ap, long *); 1276*0Sstevel@tonic-gate else 1277*0Sstevel@tonic-gate (void) va_arg((*pargs).ap, int *); 1278*0Sstevel@tonic-gate break; 1279*0Sstevel@tonic-gate default: 1280*0Sstevel@tonic-gate if (flags & 0x1) 1281*0Sstevel@tonic-gate (void) va_arg((*pargs).ap, long int); 1282*0Sstevel@tonic-gate else 1283*0Sstevel@tonic-gate (void) va_arg((*pargs).ap, int); 1284*0Sstevel@tonic-gate break; 1285*0Sstevel@tonic-gate } 1286*0Sstevel@tonic-gate i++; 1287*0Sstevel@tonic-gate curargno++; /* default to next in list */ 1288*0Sstevel@tonic-gate if (flags & 0x2) /* took care of *, keep going */ 1289*0Sstevel@tonic-gate { 1290*0Sstevel@tonic-gate flags ^= 0x2; 1291*0Sstevel@tonic-gate goto again; 1292*0Sstevel@tonic-gate } 1293*0Sstevel@tonic-gate } 1294*0Sstevel@tonic-gate 1295*0Sstevel@tonic-gate /* 1296*0Sstevel@tonic-gate * missing specifier for parameter, assume parameter is an int 1297*0Sstevel@tonic-gate */ 1298*0Sstevel@tonic-gate if (!found && i != argno) { 1299*0Sstevel@tonic-gate (void) va_arg((*pargs).ap, int); 1300*0Sstevel@tonic-gate i++; 1301*0Sstevel@tonic-gate curargno = i; 1302*0Sstevel@tonic-gate found = 1; 1303*0Sstevel@tonic-gate } 1304*0Sstevel@tonic-gate } 1305*0Sstevel@tonic-gate } 1306