FreeCalypso > hg > freecalypso-citrine
comparison sprintf/old/doprnt.c @ 0:75a11d740a02
initial import of gsm-fw from freecalypso-sw rev 1033:5ab737ac3ad7
| author | Mychaela Falconia <falcon@freecalypso.org> |
|---|---|
| date | Thu, 09 Jun 2016 00:02:41 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:75a11d740a02 |
|---|---|
| 1 /* the guts of printf - this implementation came from 4.3BSD-Tahoe */ | |
| 2 | |
| 3 #include <sys/types.h> | |
| 4 #include <ctype.h> | |
| 5 #include <stdarg.h> | |
| 6 | |
| 7 #define PUTC(ch) (*(*outptrp)++ = (ch)) | |
| 8 | |
| 9 #define ARG() \ | |
| 10 _ulong = flags&LONGINT ? va_arg(argp, long) : va_arg(argp, int); | |
| 11 | |
| 12 #define BUF 256 | |
| 13 | |
| 14 #define todigit(c) ((c) - '0') | |
| 15 #define tochar(n) ((n) + '0') | |
| 16 | |
| 17 /* have to deal with the negative buffer count kludge */ | |
| 18 #define NEGATIVE_COUNT_KLUDGE | |
| 19 | |
| 20 #define LONGINT 0x01 /* long integer */ | |
| 21 #define LONGDBL 0x02 /* long double; unimplemented */ | |
| 22 #define SHORTINT 0x04 /* short integer */ | |
| 23 #define ALT 0x08 /* alternate form */ | |
| 24 #define LADJUST 0x10 /* left adjustment */ | |
| 25 #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ | |
| 26 #define HEXPREFIX 0x40 /* add 0x or 0X prefix */ | |
| 27 | |
| 28 _doprnt(fmt0, argp, outptrp) | |
| 29 u_char *fmt0; | |
| 30 va_list argp; | |
| 31 char **outptrp; | |
| 32 { | |
| 33 register u_char *fmt; /* format string */ | |
| 34 register int ch; /* character from fmt */ | |
| 35 register int cnt; /* return value accumulator */ | |
| 36 register int n; /* random handy integer */ | |
| 37 register char *t; /* buffer pointer */ | |
| 38 u_long _ulong; /* integer arguments %[diouxX] */ | |
| 39 int base; /* base for [diouxX] conversion */ | |
| 40 int dprec; /* decimal precision in [diouxX] */ | |
| 41 int fieldsz; /* field size expanded by sign, etc */ | |
| 42 int flags; /* flags as above */ | |
| 43 int prec; /* precision from format (%.3d), or -1 */ | |
| 44 int realsz; /* field size expanded by decimal precision */ | |
| 45 int size; /* size of converted field or string */ | |
| 46 int width; /* width from format (%8d), or 0 */ | |
| 47 char sign; /* sign prefix (' ', '+', '-', or \0) */ | |
| 48 char softsign; /* temporary negative sign for floats */ | |
| 49 char *digs; /* digits for [diouxX] conversion */ | |
| 50 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ | |
| 51 | |
| 52 fmt = fmt0; | |
| 53 digs = "0123456789abcdef"; | |
| 54 for (cnt = 0;; ++fmt) { | |
| 55 for (; (ch = *fmt) && ch != '%'; ++cnt, ++fmt) | |
| 56 PUTC(ch); | |
| 57 if (!ch) | |
| 58 return (cnt); | |
| 59 | |
| 60 flags = 0; dprec = 0; width = 0; | |
| 61 prec = -1; | |
| 62 sign = '\0'; | |
| 63 | |
| 64 rflag: switch (*++fmt) { | |
| 65 case ' ': | |
| 66 /* | |
| 67 * ``If the space and + flags both appear, the space | |
| 68 * flag will be ignored.'' | |
| 69 * -- ANSI X3J11 | |
| 70 */ | |
| 71 if (!sign) | |
| 72 sign = ' '; | |
| 73 goto rflag; | |
| 74 case '#': | |
| 75 flags |= ALT; | |
| 76 goto rflag; | |
| 77 case '*': | |
| 78 /* | |
| 79 * ``A negative field width argument is taken as a | |
| 80 * - flag followed by a positive field width.'' | |
| 81 * -- ANSI X3J11 | |
| 82 * They don't exclude field widths read from args. | |
| 83 */ | |
| 84 if ((width = va_arg(argp, int)) >= 0) | |
| 85 goto rflag; | |
| 86 width = -width; | |
| 87 /* FALLTHROUGH */ | |
| 88 case '-': | |
| 89 flags |= LADJUST; | |
| 90 goto rflag; | |
| 91 case '+': | |
| 92 sign = '+'; | |
| 93 goto rflag; | |
| 94 case '.': | |
| 95 if (*++fmt == '*') | |
| 96 n = va_arg(argp, int); | |
| 97 else { | |
| 98 n = 0; | |
| 99 while (isascii(*fmt) && isdigit(*fmt)) | |
| 100 n = 10 * n + todigit(*fmt++); | |
| 101 --fmt; | |
| 102 } | |
| 103 prec = n < 0 ? -1 : n; | |
| 104 goto rflag; | |
| 105 case '0': | |
| 106 /* | |
| 107 * ``Note that 0 is taken as a flag, not as the | |
| 108 * beginning of a field width.'' | |
| 109 * -- ANSI X3J11 | |
| 110 */ | |
| 111 flags |= ZEROPAD; | |
| 112 goto rflag; | |
| 113 case '1': case '2': case '3': case '4': | |
| 114 case '5': case '6': case '7': case '8': case '9': | |
| 115 n = 0; | |
| 116 do { | |
| 117 n = 10 * n + todigit(*fmt); | |
| 118 } while (isascii(*++fmt) && isdigit(*fmt)); | |
| 119 width = n; | |
| 120 --fmt; | |
| 121 goto rflag; | |
| 122 case 'L': | |
| 123 flags |= LONGDBL; | |
| 124 goto rflag; | |
| 125 case 'h': | |
| 126 flags |= SHORTINT; | |
| 127 goto rflag; | |
| 128 case 'l': | |
| 129 flags |= LONGINT; | |
| 130 goto rflag; | |
| 131 case 'c': | |
| 132 *(t = buf) = va_arg(argp, int); | |
| 133 size = 1; | |
| 134 sign = '\0'; | |
| 135 goto pforw; | |
| 136 case 'D': | |
| 137 flags |= LONGINT; | |
| 138 /*FALLTHROUGH*/ | |
| 139 case 'd': | |
| 140 case 'i': | |
| 141 ARG(); | |
| 142 if ((long)_ulong < 0) { | |
| 143 _ulong = -_ulong; | |
| 144 sign = '-'; | |
| 145 } | |
| 146 base = 10; | |
| 147 goto number; | |
| 148 case 'n': | |
| 149 if (flags & LONGINT) | |
| 150 *va_arg(argp, long *) = cnt; | |
| 151 else if (flags & SHORTINT) | |
| 152 *va_arg(argp, short *) = cnt; | |
| 153 else | |
| 154 *va_arg(argp, int *) = cnt; | |
| 155 break; | |
| 156 case 'O': | |
| 157 flags |= LONGINT; | |
| 158 /*FALLTHROUGH*/ | |
| 159 case 'o': | |
| 160 ARG(); | |
| 161 base = 8; | |
| 162 goto nosign; | |
| 163 case 'p': | |
| 164 /* | |
| 165 * ``The argument shall be a pointer to void. The | |
| 166 * value of the pointer is converted to a sequence | |
| 167 * of printable characters, in an implementation- | |
| 168 * defined manner.'' | |
| 169 * -- ANSI X3J11 | |
| 170 */ | |
| 171 /* NOSTRICT */ | |
| 172 _ulong = (u_long)va_arg(argp, void *); | |
| 173 base = 16; | |
| 174 goto nosign; | |
| 175 case 's': | |
| 176 if (!(t = va_arg(argp, char *))) | |
| 177 t = "(null)"; | |
| 178 if (prec >= 0) { | |
| 179 /* | |
| 180 * can't use strlen; can only look for the | |
| 181 * NUL in the first `prec' characters, and | |
| 182 * strlen() will go further. | |
| 183 */ | |
| 184 char *p; | |
| 185 | |
| 186 for (p = t, size = 0; size < prec; p++, size++) | |
| 187 if (*p == '\0') | |
| 188 break; | |
| 189 } else | |
| 190 size = strlen(t); | |
| 191 sign = '\0'; | |
| 192 goto pforw; | |
| 193 case 'U': | |
| 194 flags |= LONGINT; | |
| 195 /*FALLTHROUGH*/ | |
| 196 case 'u': | |
| 197 ARG(); | |
| 198 base = 10; | |
| 199 goto nosign; | |
| 200 case 'X': | |
| 201 digs = "0123456789ABCDEF"; | |
| 202 /* FALLTHROUGH */ | |
| 203 case 'x': | |
| 204 ARG(); | |
| 205 base = 16; | |
| 206 /* leading 0x/X only if non-zero */ | |
| 207 if (flags & ALT && _ulong != 0) | |
| 208 flags |= HEXPREFIX; | |
| 209 | |
| 210 /* unsigned conversions */ | |
| 211 nosign: sign = '\0'; | |
| 212 /* | |
| 213 * ``... diouXx conversions ... if a precision is | |
| 214 * specified, the 0 flag will be ignored.'' | |
| 215 * -- ANSI X3J11 | |
| 216 */ | |
| 217 number: if ((dprec = prec) >= 0) | |
| 218 flags &= ~ZEROPAD; | |
| 219 | |
| 220 /* | |
| 221 * ``The result of converting a zero value with an | |
| 222 * explicit precision of zero is no characters.'' | |
| 223 * -- ANSI X3J11 | |
| 224 */ | |
| 225 t = buf + BUF; | |
| 226 if (_ulong != 0 || prec != 0) { | |
| 227 do { | |
| 228 *--t = digs[_ulong % base]; | |
| 229 _ulong /= base; | |
| 230 } while (_ulong); | |
| 231 digs = "0123456789abcdef"; | |
| 232 if (flags & ALT && base == 8 && *t != '0') | |
| 233 *--t = '0'; /* octal leading 0 */ | |
| 234 } | |
| 235 size = buf + BUF - t; | |
| 236 | |
| 237 pforw: | |
| 238 /* | |
| 239 * All reasonable formats wind up here. At this point, | |
| 240 * `t' points to a string which (if not flags&LADJUST) | |
| 241 * should be padded out to `width' places. If | |
| 242 * flags&ZEROPAD, it should first be prefixed by any | |
| 243 * sign or other prefix; otherwise, it should be blank | |
| 244 * padded before the prefix is emitted. After any | |
| 245 * left-hand padding and prefixing, emit zeroes | |
| 246 * required by a decimal [diouxX] precision, then print | |
| 247 * the string proper, then emit zeroes required by any | |
| 248 * leftover floating precision; finally, if LADJUST, | |
| 249 * pad with blanks. | |
| 250 */ | |
| 251 | |
| 252 /* | |
| 253 * compute actual size, so we know how much to pad | |
| 254 * fieldsz excludes decimal prec; realsz includes it | |
| 255 */ | |
| 256 fieldsz = size; | |
| 257 if (sign) | |
| 258 fieldsz++; | |
| 259 if (flags & HEXPREFIX) | |
| 260 fieldsz += 2; | |
| 261 realsz = dprec > fieldsz ? dprec : fieldsz; | |
| 262 | |
| 263 /* right-adjusting blank padding */ | |
| 264 if ((flags & (LADJUST|ZEROPAD)) == 0 && width) | |
| 265 for (n = realsz; n < width; n++) | |
| 266 PUTC(' '); | |
| 267 /* prefix */ | |
| 268 if (sign) | |
| 269 PUTC(sign); | |
| 270 if (flags & HEXPREFIX) { | |
| 271 PUTC('0'); | |
| 272 PUTC((char)*fmt); | |
| 273 } | |
| 274 /* right-adjusting zero padding */ | |
| 275 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) | |
| 276 for (n = realsz; n < width; n++) | |
| 277 PUTC('0'); | |
| 278 /* leading zeroes from decimal precision */ | |
| 279 for (n = fieldsz; n < dprec; n++) | |
| 280 PUTC('0'); | |
| 281 | |
| 282 for (n = size; --n >= 0; ) | |
| 283 PUTC(*t++); | |
| 284 /* left-adjusting padding (always blank) */ | |
| 285 if (flags & LADJUST) | |
| 286 for (n = realsz; n < width; n++) | |
| 287 PUTC(' '); | |
| 288 /* finally, adjust cnt */ | |
| 289 cnt += width > realsz ? width : realsz; | |
| 290 break; | |
| 291 case '\0': /* "%?" prints ?, unless ? is NULL */ | |
| 292 return (cnt); | |
| 293 default: | |
| 294 PUTC((char)*fmt); | |
| 295 cnt++; | |
| 296 } | |
| 297 } | |
| 298 /* NOTREACHED */ | |
| 299 } |
