]>
Commit | Line | Data |
---|---|---|
e9ce8d39 A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
734aad71 A |
5 | * |
6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. | |
7 | * | |
8 | * This file contains Original Code and/or Modifications of Original Code | |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14 | * | |
15 | * The Original Code and all software distributed under the License are | |
16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
e9ce8d39 A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
734aad71 A |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
22 | * | |
e9ce8d39 A |
23 | * @APPLE_LICENSE_HEADER_END@ |
24 | */ | |
25 | /* | |
26 | * Copyright (c) 1990, 1993 | |
27 | * The Regents of the University of California. All rights reserved. | |
28 | * | |
29 | * This code is derived from software contributed to Berkeley by | |
30 | * Chris Torek. | |
31 | * | |
32 | * Redistribution and use in source and binary forms, with or without | |
33 | * modification, are permitted provided that the following conditions | |
34 | * are met: | |
35 | * 1. Redistributions of source code must retain the above copyright | |
36 | * notice, this list of conditions and the following disclaimer. | |
37 | * 2. Redistributions in binary form must reproduce the above copyright | |
38 | * notice, this list of conditions and the following disclaimer in the | |
39 | * documentation and/or other materials provided with the distribution. | |
40 | * 3. All advertising materials mentioning features or use of this software | |
41 | * must display the following acknowledgement: | |
42 | * This product includes software developed by the University of | |
43 | * California, Berkeley and its contributors. | |
44 | * 4. Neither the name of the University nor the names of its contributors | |
45 | * may be used to endorse or promote products derived from this software | |
46 | * without specific prior written permission. | |
47 | * | |
48 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
49 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
50 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
54 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
55 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
58 | * SUCH DAMAGE. | |
59 | */ | |
60 | ||
61 | /* | |
62 | * Actual printf innards. | |
63 | * | |
64 | * This code is large and complicated... | |
65 | */ | |
66 | ||
67 | #include <sys/types.h> | |
68 | ||
69 | #include <limits.h> | |
70 | #include <stdio.h> | |
71 | #include <stdlib.h> | |
72 | #include <string.h> | |
5b2abdfb | 73 | #include <sys/sysctl.h> |
e9ce8d39 A |
74 | |
75 | #if __STDC__ | |
76 | #include <stdarg.h> | |
77 | #else | |
78 | #include <varargs.h> | |
79 | #endif | |
80 | ||
81 | #include "local.h" | |
82 | #include "fvwrite.h" | |
83 | ||
84 | /* Define FLOATING_POINT to get floating point. */ | |
85 | #define FLOATING_POINT | |
5b2abdfb A |
86 | union arg { |
87 | int intarg; | |
88 | unsigned int uintarg; | |
89 | long longarg; | |
90 | unsigned long ulongarg; | |
91 | quad_t quadarg; | |
92 | u_quad_t uquadarg; | |
93 | void *pvoidarg; | |
94 | char *pchararg; | |
95 | short *pshortarg; | |
96 | int *pintarg; | |
97 | long *plongarg; | |
98 | quad_t *pquadarg; | |
99 | #ifdef FLOATING_POINT | |
100 | double doublearg; | |
101 | long double longdoublearg; | |
102 | #endif | |
103 | #ifdef ALTIVEC | |
104 | unsigned char vuchararg[16]; | |
105 | signed char vchararg[16]; | |
106 | unsigned short vushortarg[8]; | |
107 | signed short vshortarg[8]; | |
108 | unsigned int vuintarg[4]; | |
109 | signed int vintarg[4]; | |
110 | float vfloatarg[4]; | |
111 | #endif | |
112 | }; | |
e9ce8d39 A |
113 | |
114 | static int __sprint __P((FILE *, struct __suio *)); | |
115 | static int __sbprintf __P((FILE *, const char *, va_list)); | |
116 | static char * __ultoa __P((u_long, char *, int, int, char *)); | |
117 | static char * __uqtoa __P((u_quad_t, char *, int, int, char *)); | |
5b2abdfb | 118 | static void __find_arguments __P((const char *, va_list, union arg **)); |
e9ce8d39 A |
119 | static void __grow_type_table __P((int, unsigned char **, int *)); |
120 | ||
5b2abdfb A |
121 | /* |
122 | * Get the argument indexed by nextarg. If the argument table is | |
123 | * built, use it to get the argument. If its not, get the next | |
124 | * argument (and arguments must be gotten sequentially). | |
125 | */ | |
126 | #define GETARG(type) \ | |
127 | ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ | |
128 | (nextarg++, va_arg(ap, type))) | |
129 | ||
130 | #ifdef ALTIVEC | |
131 | static void getvec(union arg *dst, const union arg *argtable, int nextarg, va_list ap) | |
132 | { | |
133 | vector unsigned char tmp; | |
134 | ||
135 | tmp = GETARG(vector unsigned char); | |
136 | memcpy( dst, &tmp, 16 ); | |
137 | } | |
138 | ||
139 | #endif | |
140 | ||
e9ce8d39 A |
141 | /* |
142 | * Flush out all the vectors defined by the given uio, | |
143 | * then reset it so that it can be reused. | |
144 | */ | |
145 | static int | |
146 | __sprint(fp, uio) | |
147 | FILE *fp; | |
148 | register struct __suio *uio; | |
149 | { | |
150 | register int err; | |
151 | ||
152 | if (uio->uio_resid == 0) { | |
153 | uio->uio_iovcnt = 0; | |
154 | return (0); | |
155 | } | |
156 | err = __sfvwrite(fp, uio); | |
157 | uio->uio_resid = 0; | |
158 | uio->uio_iovcnt = 0; | |
159 | return (err); | |
160 | } | |
161 | ||
162 | /* | |
163 | * Helper function for `fprintf to unbuffered unix file': creates a | |
164 | * temporary buffer. We only work on write-only files; this avoids | |
165 | * worries about ungetc buffers and so forth. | |
166 | */ | |
167 | static int | |
168 | __sbprintf(fp, fmt, ap) | |
169 | register FILE *fp; | |
170 | const char *fmt; | |
171 | va_list ap; | |
172 | { | |
173 | int ret; | |
174 | FILE fake; | |
175 | unsigned char buf[BUFSIZ]; | |
176 | ||
177 | /* copy the important variables */ | |
178 | fake._flags = fp->_flags & ~__SNBF; | |
179 | fake._file = fp->_file; | |
180 | fake._cookie = fp->_cookie; | |
181 | fake._write = fp->_write; | |
182 | ||
183 | /* set up the buffer */ | |
184 | fake._bf._base = fake._p = buf; | |
185 | fake._bf._size = fake._w = sizeof(buf); | |
186 | fake._lbfsize = 0; /* not actually used, but Just In Case */ | |
187 | ||
188 | /* do the work, then copy any error status */ | |
189 | ret = vfprintf(&fake, fmt, ap); | |
190 | if (ret >= 0 && fflush(&fake)) | |
191 | ret = EOF; | |
192 | if (fake._flags & __SERR) | |
193 | fp->_flags |= __SERR; | |
194 | return (ret); | |
195 | } | |
196 | ||
197 | /* | |
198 | * Macros for converting digits to letters and vice versa | |
199 | */ | |
200 | #define to_digit(c) ((c) - '0') | |
201 | #define is_digit(c) ((unsigned)to_digit(c) <= 9) | |
202 | #define to_char(n) ((n) + '0') | |
203 | ||
204 | /* | |
205 | * Convert an unsigned long to ASCII for printf purposes, returning | |
206 | * a pointer to the first character of the string representation. | |
207 | * Octal numbers can be forced to have a leading zero; hex numbers | |
208 | * use the given digits. | |
209 | */ | |
210 | static char * | |
211 | __ultoa(val, endp, base, octzero, xdigs) | |
212 | register u_long val; | |
213 | char *endp; | |
214 | int base, octzero; | |
215 | char *xdigs; | |
216 | { | |
217 | register char *cp = endp; | |
218 | register long sval; | |
219 | ||
220 | /* | |
221 | * Handle the three cases separately, in the hope of getting | |
222 | * better/faster code. | |
223 | */ | |
224 | switch (base) { | |
225 | case 10: | |
226 | if (val < 10) { /* many numbers are 1 digit */ | |
227 | *--cp = to_char(val); | |
228 | return (cp); | |
229 | } | |
230 | /* | |
231 | * On many machines, unsigned arithmetic is harder than | |
232 | * signed arithmetic, so we do at most one unsigned mod and | |
233 | * divide; this is sufficient to reduce the range of | |
234 | * the incoming value to where signed arithmetic works. | |
235 | */ | |
236 | if (val > LONG_MAX) { | |
237 | *--cp = to_char(val % 10); | |
238 | sval = val / 10; | |
239 | } else | |
240 | sval = val; | |
241 | do { | |
242 | *--cp = to_char(sval % 10); | |
243 | sval /= 10; | |
244 | } while (sval != 0); | |
245 | break; | |
246 | ||
247 | case 8: | |
248 | do { | |
249 | *--cp = to_char(val & 7); | |
250 | val >>= 3; | |
251 | } while (val); | |
252 | if (octzero && *cp != '0') | |
253 | *--cp = '0'; | |
254 | break; | |
255 | ||
256 | case 16: | |
257 | do { | |
258 | *--cp = xdigs[val & 15]; | |
259 | val >>= 4; | |
260 | } while (val); | |
261 | break; | |
262 | ||
263 | default: /* oops */ | |
264 | abort(); | |
265 | } | |
266 | return (cp); | |
267 | } | |
268 | ||
269 | /* Identical to __ultoa, but for quads. */ | |
270 | static char * | |
271 | __uqtoa(val, endp, base, octzero, xdigs) | |
272 | register u_quad_t val; | |
273 | char *endp; | |
274 | int base, octzero; | |
275 | char *xdigs; | |
276 | { | |
277 | register char *cp = endp; | |
278 | register quad_t sval; | |
279 | ||
280 | /* quick test for small values; __ultoa is typically much faster */ | |
281 | /* (perhaps instead we should run until small, then call __ultoa?) */ | |
282 | if (val <= ULONG_MAX) | |
283 | return (__ultoa((u_long)val, endp, base, octzero, xdigs)); | |
284 | switch (base) { | |
285 | case 10: | |
286 | if (val < 10) { | |
287 | *--cp = to_char(val % 10); | |
288 | return (cp); | |
289 | } | |
290 | if (val > QUAD_MAX) { | |
291 | *--cp = to_char(val % 10); | |
292 | sval = val / 10; | |
293 | } else | |
294 | sval = val; | |
295 | do { | |
296 | *--cp = to_char(sval % 10); | |
297 | sval /= 10; | |
298 | } while (sval != 0); | |
299 | break; | |
300 | ||
301 | case 8: | |
302 | do { | |
303 | *--cp = to_char(val & 7); | |
304 | val >>= 3; | |
305 | } while (val); | |
306 | if (octzero && *cp != '0') | |
307 | *--cp = '0'; | |
308 | break; | |
309 | ||
310 | case 16: | |
311 | do { | |
312 | *--cp = xdigs[val & 15]; | |
313 | val >>= 4; | |
314 | } while (val); | |
315 | break; | |
316 | ||
317 | default: | |
318 | abort(); | |
319 | } | |
320 | return (cp); | |
321 | } | |
322 | ||
323 | #ifdef FLOATING_POINT | |
324 | #include <math.h> | |
325 | #include "floatio.h" | |
326 | ||
327 | #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ | |
328 | #define DEFPREC 6 | |
329 | ||
3b2a1fe8 | 330 | static char *cvt __P((double, int, int, char *, int *, int, int *, char **)); |
e9ce8d39 A |
331 | static int exponent __P((char *, int, int)); |
332 | ||
5b2abdfb A |
333 | #if defined(__APPLE__) |
334 | /* | |
335 | * We don't want to be dependent on any libm symbols so use the versions in Libc | |
336 | */ | |
337 | ||
338 | #undef isinf | |
339 | #undef isnan | |
340 | ||
341 | extern int isnan(double); | |
342 | extern int isinf(double); | |
343 | ||
344 | #endif /* __APPLE __ */ | |
345 | ||
e9ce8d39 A |
346 | #else /* no FLOATING_POINT */ |
347 | ||
348 | #define BUF 68 | |
349 | ||
350 | #endif /* FLOATING_POINT */ | |
351 | ||
352 | #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ | |
353 | ||
354 | /* | |
355 | * Flags used during conversion. | |
356 | */ | |
357 | #define ALT 0x001 /* alternate form */ | |
358 | #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ | |
359 | #define LADJUST 0x004 /* left adjustment */ | |
360 | #define LONGDBL 0x008 /* long double */ | |
361 | #define LONGINT 0x010 /* long integer */ | |
362 | #define QUADINT 0x020 /* quad integer */ | |
363 | #define SHORTINT 0x040 /* short integer */ | |
364 | #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ | |
365 | #define FPT 0x100 /* Floating point number */ | |
5b2abdfb | 366 | #define VECTOR 0x200 /* Altivec vector */ |
e9ce8d39 A |
367 | int |
368 | vfprintf(fp, fmt0, ap) | |
369 | FILE *fp; | |
370 | const char *fmt0; | |
371 | va_list ap; | |
372 | { | |
373 | register char *fmt; /* format string */ | |
374 | register int ch; /* character from fmt */ | |
375 | register int n, n2; /* handy integer (short term usage) */ | |
376 | register char *cp; /* handy char pointer (short term usage) */ | |
377 | register struct __siov *iovp;/* for PRINT macro */ | |
378 | register int flags; /* flags as above */ | |
379 | int ret; /* return value accumulator */ | |
380 | int width; /* width from format (%8d), or 0 */ | |
381 | int prec; /* precision from format (%.3d), or -1 */ | |
382 | char sign; /* sign prefix (' ', '+', '-', or \0) */ | |
383 | #ifdef FLOATING_POINT | |
384 | char softsign; /* temporary negative sign for floats */ | |
385 | double _double = 0; /* double precision arguments %[eEfgG] */ | |
386 | int expt; /* integer value of exponent */ | |
387 | int expsize = 0; /* character count for expstr */ | |
388 | int ndig; /* actual number of digits returned by cvt */ | |
389 | char expstr[7]; /* buffer for exponent string */ | |
3b2a1fe8 | 390 | char *dtoaresult; /* buffer allocated by dtoa */ |
5b2abdfb A |
391 | #endif |
392 | #ifdef ALTIVEC | |
393 | union arg vval; /* Vector argument. */ | |
394 | char *pct; /* Pointer to '%' at beginning of specifier. */ | |
395 | char vsep; /* Vector separator character. */ | |
e9ce8d39 A |
396 | #endif |
397 | u_long ulval = 0; /* integer arguments %[diouxX] */ | |
398 | u_quad_t uqval = 0; /* %q integers */ | |
399 | int base; /* base for [diouxX] conversion */ | |
400 | int dprec; /* a copy of prec if [diouxX], 0 otherwise */ | |
401 | int realsz; /* field size expanded by dprec, sign, etc */ | |
402 | int size; /* size of converted field or string */ | |
403 | int prsize; /* max size of printed field */ | |
404 | char *xdigs = NULL; /* digits for [xX] conversion */ | |
405 | #define NIOV 8 | |
406 | struct __suio uio; /* output information: summary */ | |
407 | struct __siov iov[NIOV];/* ... and individual io vectors */ | |
408 | char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ | |
409 | char ox[2]; /* space for 0x hex-prefix */ | |
5b2abdfb A |
410 | union arg *argtable; /* args, built due to positional arg */ |
411 | union arg statargtable [STATIC_ARG_TBL_SIZE]; | |
e9ce8d39 A |
412 | int nextarg; /* 1-based argument index */ |
413 | va_list orgap; /* original argument pointer */ | |
414 | ||
415 | /* | |
416 | * Choose PADSIZE to trade efficiency vs. size. If larger printf | |
417 | * fields occur frequently, increase PADSIZE and make the initialisers | |
418 | * below longer. | |
419 | */ | |
420 | #define PADSIZE 16 /* pad chunk size */ | |
421 | static char blanks[PADSIZE] = | |
422 | {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; | |
423 | static char zeroes[PADSIZE] = | |
424 | {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; | |
425 | ||
426 | /* | |
427 | * BEWARE, these `goto error' on error, and PAD uses `n'. | |
428 | */ | |
429 | #define PRINT(ptr, len) { \ | |
430 | iovp->iov_base = (ptr); \ | |
431 | iovp->iov_len = (len); \ | |
432 | uio.uio_resid += (len); \ | |
433 | iovp++; \ | |
434 | if (++uio.uio_iovcnt >= NIOV) { \ | |
435 | if (__sprint(fp, &uio)) \ | |
436 | goto error; \ | |
437 | iovp = iov; \ | |
438 | } \ | |
439 | } | |
440 | #define PAD(howmany, with) { \ | |
441 | if ((n = (howmany)) > 0) { \ | |
442 | while (n > PADSIZE) { \ | |
443 | PRINT(with, PADSIZE); \ | |
444 | n -= PADSIZE; \ | |
445 | } \ | |
446 | PRINT(with, n); \ | |
447 | } \ | |
448 | } | |
449 | #define FLUSH() { \ | |
450 | if (uio.uio_resid && __sprint(fp, &uio)) \ | |
451 | goto error; \ | |
452 | uio.uio_iovcnt = 0; \ | |
453 | iovp = iov; \ | |
454 | } | |
455 | ||
e9ce8d39 A |
456 | |
457 | /* | |
458 | * To extend shorts properly, we need both signed and unsigned | |
459 | * argument extraction methods. | |
460 | */ | |
461 | #define SARG() \ | |
462 | (flags&LONGINT ? GETARG(long) : \ | |
463 | flags&SHORTINT ? (long)(short)GETARG(int) : \ | |
464 | (long)GETARG(int)) | |
465 | #define UARG() \ | |
466 | (flags&LONGINT ? GETARG(u_long) : \ | |
467 | flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ | |
468 | (u_long)GETARG(u_int)) | |
469 | ||
470 | /* | |
471 | * Get * arguments, including the form *nn$. Preserve the nextarg | |
472 | * that the argument can be gotten once the type is determined. | |
473 | */ | |
474 | #define GETASTER(val) \ | |
475 | n2 = 0; \ | |
476 | cp = fmt; \ | |
477 | while (is_digit(*cp)) { \ | |
478 | n2 = 10 * n2 + to_digit(*cp); \ | |
479 | cp++; \ | |
480 | } \ | |
481 | if (*cp == '$') { \ | |
482 | int hold = nextarg; \ | |
483 | if (argtable == NULL) { \ | |
484 | argtable = statargtable; \ | |
485 | __find_arguments (fmt0, orgap, &argtable); \ | |
486 | } \ | |
487 | nextarg = n2; \ | |
488 | val = GETARG (int); \ | |
489 | nextarg = hold; \ | |
490 | fmt = ++cp; \ | |
491 | } else { \ | |
492 | val = GETARG (int); \ | |
493 | } | |
3b2a1fe8 A |
494 | #ifdef FLOATING_POINT |
495 | dtoaresult = NULL; | |
496 | #endif | |
e9ce8d39 A |
497 | /* FLOCKFILE(fp); */ |
498 | /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ | |
499 | if (cantwrite(fp)) { | |
500 | /* FUNLOCKFILE(fp); */ | |
501 | return (EOF); | |
502 | } | |
503 | ||
504 | /* optimise fprintf(stderr) (and other unbuffered Unix files) */ | |
505 | if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && | |
506 | fp->_file >= 0) { | |
507 | /* FUNLOCKFILE(fp); */ | |
508 | return (__sbprintf(fp, fmt0, ap)); | |
509 | } | |
510 | ||
511 | fmt = (char *)fmt0; | |
512 | argtable = NULL; | |
513 | nextarg = 1; | |
514 | orgap = ap; | |
515 | uio.uio_iov = iovp = iov; | |
516 | uio.uio_resid = 0; | |
517 | uio.uio_iovcnt = 0; | |
518 | ret = 0; | |
519 | ||
520 | /* | |
521 | * Scan the format for conversions (`%' character). | |
522 | */ | |
523 | for (;;) { | |
524 | for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) | |
525 | /* void */; | |
526 | if ((n = fmt - cp) != 0) { | |
527 | if ((unsigned)ret + n > INT_MAX) { | |
528 | ret = EOF; | |
529 | goto error; | |
530 | } | |
531 | PRINT(cp, n); | |
532 | ret += n; | |
533 | } | |
534 | if (ch == '\0') | |
535 | goto done; | |
5b2abdfb A |
536 | #ifdef ALTIVEC |
537 | pct = fmt; | |
538 | #endif | |
e9ce8d39 A |
539 | fmt++; /* skip over '%' */ |
540 | ||
541 | flags = 0; | |
542 | dprec = 0; | |
543 | width = 0; | |
544 | prec = -1; | |
545 | sign = '\0'; | |
5b2abdfb A |
546 | #ifdef ALTIVEC |
547 | vsep = 'X'; /* Illegal value, changed to defaults later. */ | |
548 | #endif | |
e9ce8d39 A |
549 | |
550 | rflag: ch = *fmt++; | |
551 | reswitch: switch (ch) { | |
552 | case ' ': | |
553 | /* | |
554 | * ``If the space and + flags both appear, the space | |
555 | * flag will be ignored.'' | |
556 | * -- ANSI X3J11 | |
557 | */ | |
558 | if (!sign) | |
559 | sign = ' '; | |
560 | goto rflag; | |
561 | case '#': | |
562 | flags |= ALT; | |
563 | goto rflag; | |
5b2abdfb A |
564 | #ifdef ALTIVEC |
565 | case ',': case ';': case ':': case '_': | |
566 | vsep = ch; | |
567 | goto rflag; | |
568 | #endif | |
e9ce8d39 A |
569 | case '*': |
570 | /* | |
571 | * ``A negative field width argument is taken as a | |
572 | * - flag followed by a positive field width.'' | |
573 | * -- ANSI X3J11 | |
574 | * They don't exclude field widths read from args. | |
575 | */ | |
576 | GETASTER (width); | |
577 | if (width >= 0) | |
578 | goto rflag; | |
579 | width = -width; | |
580 | /* FALLTHROUGH */ | |
581 | case '-': | |
582 | flags |= LADJUST; | |
583 | goto rflag; | |
584 | case '+': | |
585 | sign = '+'; | |
586 | goto rflag; | |
587 | case '.': | |
588 | if ((ch = *fmt++) == '*') { | |
589 | GETASTER (n); | |
590 | prec = n < 0 ? -1 : n; | |
591 | goto rflag; | |
592 | } | |
593 | n = 0; | |
594 | while (is_digit(ch)) { | |
595 | n = 10 * n + to_digit(ch); | |
596 | ch = *fmt++; | |
597 | } | |
598 | prec = n < 0 ? -1 : n; | |
599 | goto reswitch; | |
600 | case '0': | |
601 | /* | |
602 | * ``Note that 0 is taken as a flag, not as the | |
603 | * beginning of a field width.'' | |
604 | * -- ANSI X3J11 | |
605 | */ | |
606 | flags |= ZEROPAD; | |
607 | goto rflag; | |
608 | case '1': case '2': case '3': case '4': | |
609 | case '5': case '6': case '7': case '8': case '9': | |
610 | n = 0; | |
611 | do { | |
612 | n = 10 * n + to_digit(ch); | |
613 | ch = *fmt++; | |
614 | } while (is_digit(ch)); | |
615 | if (ch == '$') { | |
616 | nextarg = n; | |
617 | if (argtable == NULL) { | |
618 | argtable = statargtable; | |
619 | __find_arguments (fmt0, orgap, | |
620 | &argtable); | |
621 | } | |
622 | goto rflag; | |
623 | } | |
624 | width = n; | |
625 | goto reswitch; | |
626 | #ifdef FLOATING_POINT | |
627 | case 'L': | |
628 | flags |= LONGDBL; | |
629 | goto rflag; | |
5b2abdfb A |
630 | #endif |
631 | #ifdef ALTIVEC | |
632 | case 'v': | |
633 | flags |= VECTOR; | |
634 | goto rflag; | |
e9ce8d39 A |
635 | #endif |
636 | case 'h': | |
637 | flags |= SHORTINT; | |
638 | goto rflag; | |
639 | case 'l': | |
640 | if (flags & LONGINT) | |
641 | flags |= QUADINT; | |
642 | else | |
643 | flags |= LONGINT; | |
644 | goto rflag; | |
645 | case 'q': | |
646 | flags |= QUADINT; | |
647 | goto rflag; | |
5b2abdfb A |
648 | case 'z': |
649 | if (sizeof(size_t) == sizeof(long)) | |
650 | flags |= LONGINT; | |
651 | if (sizeof(size_t) == sizeof(quad_t)) | |
652 | flags |= QUADINT; | |
653 | goto rflag; | |
e9ce8d39 | 654 | case 'c': |
5b2abdfb A |
655 | #ifdef ALTIVEC |
656 | if (flags & VECTOR) { | |
657 | getvec(&vval, argtable, nextarg, ap); | |
658 | nextarg++; | |
659 | break; | |
660 | } | |
661 | #endif | |
e9ce8d39 A |
662 | *(cp = buf) = GETARG(int); |
663 | size = 1; | |
664 | sign = '\0'; | |
665 | break; | |
666 | case 'D': | |
667 | flags |= LONGINT; | |
668 | /*FALLTHROUGH*/ | |
669 | case 'd': | |
670 | case 'i': | |
5b2abdfb A |
671 | #ifdef ALTIVEC |
672 | if (flags & VECTOR) { | |
673 | getvec(&vval, argtable, nextarg, ap); | |
674 | break; | |
675 | } else | |
676 | #endif | |
e9ce8d39 A |
677 | if (flags & QUADINT) { |
678 | uqval = GETARG(quad_t); | |
679 | if ((quad_t)uqval < 0) { | |
680 | uqval = -uqval; | |
681 | sign = '-'; | |
682 | } | |
683 | } else { | |
684 | ulval = SARG(); | |
685 | if ((long)ulval < 0) { | |
686 | ulval = -ulval; | |
687 | sign = '-'; | |
688 | } | |
689 | } | |
690 | base = 10; | |
691 | goto number; | |
692 | #ifdef FLOATING_POINT | |
693 | case 'e': | |
694 | case 'E': | |
695 | case 'f': | |
5b2abdfb A |
696 | #ifdef ALTIVEC |
697 | if (flags & VECTOR) { | |
698 | flags |= FPT; | |
699 | getvec(&vval, argtable, nextarg, ap); | |
700 | nextarg++; | |
701 | break; | |
702 | } | |
703 | #endif | |
e9ce8d39 A |
704 | goto fp_begin; |
705 | case 'g': | |
706 | case 'G': | |
5b2abdfb A |
707 | #ifdef ALTIVEC |
708 | if (flags & VECTOR) { | |
709 | flags |= FPT; | |
710 | getvec(&vval, argtable, nextarg, ap); | |
711 | nextarg++; | |
712 | break; | |
713 | } | |
714 | #endif | |
e9ce8d39 A |
715 | if (prec == 0) |
716 | prec = 1; | |
717 | fp_begin: if (prec == -1) | |
718 | prec = DEFPREC; | |
719 | if (flags & LONGDBL) | |
720 | /* XXX this loses precision. */ | |
721 | _double = (double)GETARG(long double); | |
722 | else | |
723 | _double = GETARG(double); | |
724 | /* do this before tricky precision changes */ | |
725 | if (isinf(_double)) { | |
726 | if (_double < 0) | |
727 | sign = '-'; | |
728 | cp = "Inf"; | |
729 | size = 3; | |
730 | break; | |
731 | } | |
732 | if (isnan(_double)) { | |
733 | cp = "NaN"; | |
734 | size = 3; | |
735 | break; | |
736 | } | |
737 | flags |= FPT; | |
5b2abdfb A |
738 | if (dtoaresult != NULL) { |
739 | free(dtoaresult); | |
740 | dtoaresult = NULL; | |
741 | } | |
e9ce8d39 | 742 | cp = cvt(_double, prec, flags, &softsign, |
3b2a1fe8 | 743 | &expt, ch, &ndig, &dtoaresult); |
e9ce8d39 A |
744 | if (ch == 'g' || ch == 'G') { |
745 | if (expt <= -4 || expt > prec) | |
746 | ch = (ch == 'g') ? 'e' : 'E'; | |
747 | else | |
748 | ch = 'g'; | |
749 | } | |
750 | if (ch <= 'e') { /* 'e' or 'E' fmt */ | |
751 | --expt; | |
752 | expsize = exponent(expstr, expt, ch); | |
753 | size = expsize + ndig; | |
754 | if (ndig > 1 || flags & ALT) | |
755 | ++size; | |
756 | } else if (ch == 'f') { /* f fmt */ | |
757 | if (expt > 0) { | |
758 | size = expt; | |
759 | if (prec || flags & ALT) | |
760 | size += prec + 1; | |
761 | } else /* "0.X" */ | |
762 | size = prec + 2; | |
763 | } else if (expt >= ndig) { /* fixed g fmt */ | |
764 | size = expt; | |
765 | if (flags & ALT) | |
766 | ++size; | |
767 | } else | |
768 | size = ndig + (expt > 0 ? | |
769 | 1 : 2 - expt); | |
770 | ||
771 | if (softsign) | |
772 | sign = '-'; | |
773 | break; | |
774 | #endif /* FLOATING_POINT */ | |
775 | case 'n': | |
776 | if (flags & QUADINT) | |
777 | *GETARG(quad_t *) = ret; | |
778 | else if (flags & LONGINT) | |
779 | *GETARG(long *) = ret; | |
780 | else if (flags & SHORTINT) | |
781 | *GETARG(short *) = ret; | |
782 | else | |
783 | *GETARG(int *) = ret; | |
784 | continue; /* no output */ | |
785 | case 'O': | |
786 | flags |= LONGINT; | |
787 | /*FALLTHROUGH*/ | |
788 | case 'o': | |
5b2abdfb A |
789 | #ifdef ALTIVEC |
790 | if (flags & VECTOR) { | |
791 | getvec(&vval, argtable, nextarg, ap); | |
792 | nextarg++; | |
793 | break; | |
794 | } else | |
795 | #endif | |
e9ce8d39 A |
796 | if (flags & QUADINT) |
797 | uqval = GETARG(u_quad_t); | |
798 | else | |
799 | ulval = UARG(); | |
800 | base = 8; | |
801 | goto nosign; | |
802 | case 'p': | |
803 | /* | |
804 | * ``The argument shall be a pointer to void. The | |
805 | * value of the pointer is converted to a sequence | |
806 | * of printable characters, in an implementation- | |
807 | * defined manner.'' | |
808 | * -- ANSI X3J11 | |
809 | */ | |
5b2abdfb A |
810 | #ifdef ALTIVEC |
811 | if (flags & VECTOR) { | |
812 | getvec(&vval, argtable, nextarg, ap); | |
813 | nextarg++; | |
814 | break; | |
815 | } | |
816 | #endif | |
e9ce8d39 A |
817 | ulval = (u_long)GETARG(void *); |
818 | base = 16; | |
819 | xdigs = "0123456789abcdef"; | |
820 | flags = (flags & ~QUADINT) | HEXPREFIX; | |
821 | ch = 'x'; | |
822 | goto nosign; | |
823 | case 's': | |
824 | if ((cp = GETARG(char *)) == NULL) | |
825 | cp = "(null)"; | |
826 | if (prec >= 0) { | |
827 | /* | |
828 | * can't use strlen; can only look for the | |
829 | * NUL in the first `prec' characters, and | |
830 | * strlen() will go further. | |
831 | */ | |
832 | char *p = memchr(cp, 0, (size_t)prec); | |
833 | ||
834 | if (p != NULL) { | |
835 | size = p - cp; | |
836 | if (size > prec) | |
837 | size = prec; | |
838 | } else | |
839 | size = prec; | |
840 | } else | |
841 | size = strlen(cp); | |
842 | sign = '\0'; | |
843 | break; | |
844 | case 'U': | |
845 | flags |= LONGINT; | |
846 | /*FALLTHROUGH*/ | |
847 | case 'u': | |
5b2abdfb A |
848 | #ifdef ALTIVEC |
849 | if (flags & VECTOR) { | |
850 | getvec(&vval, argtable, nextarg, ap); | |
851 | nextarg++; | |
852 | break; | |
853 | } else | |
854 | #endif | |
e9ce8d39 A |
855 | if (flags & QUADINT) |
856 | uqval = GETARG(u_quad_t); | |
857 | else | |
858 | ulval = UARG(); | |
859 | base = 10; | |
860 | goto nosign; | |
861 | case 'X': | |
862 | xdigs = "0123456789ABCDEF"; | |
863 | goto hex; | |
864 | case 'x': | |
865 | xdigs = "0123456789abcdef"; | |
5b2abdfb A |
866 | hex: |
867 | #ifdef ALTIVEC | |
868 | if (flags & VECTOR) { | |
869 | getvec(&vval, argtable, nextarg, ap); | |
870 | nextarg++; | |
871 | break; | |
872 | } else | |
873 | #endif | |
874 | if (flags & QUADINT) | |
e9ce8d39 A |
875 | uqval = GETARG(u_quad_t); |
876 | else | |
877 | ulval = UARG(); | |
878 | base = 16; | |
879 | /* leading 0x/X only if non-zero */ | |
880 | if (flags & ALT && | |
881 | (flags & QUADINT ? uqval != 0 : ulval != 0)) | |
882 | flags |= HEXPREFIX; | |
883 | ||
884 | /* unsigned conversions */ | |
885 | nosign: sign = '\0'; | |
886 | /* | |
887 | * ``... diouXx conversions ... if a precision is | |
888 | * specified, the 0 flag will be ignored.'' | |
889 | * -- ANSI X3J11 | |
890 | */ | |
891 | number: if ((dprec = prec) >= 0) | |
892 | flags &= ~ZEROPAD; | |
893 | ||
894 | /* | |
895 | * ``The result of converting a zero value with an | |
896 | * explicit precision of zero is no characters.'' | |
897 | * -- ANSI X3J11 | |
898 | */ | |
899 | cp = buf + BUF; | |
900 | if (flags & QUADINT) { | |
901 | if (uqval != 0 || prec != 0) | |
902 | cp = __uqtoa(uqval, cp, base, | |
903 | flags & ALT, xdigs); | |
904 | } else { | |
905 | if (ulval != 0 || prec != 0) | |
906 | cp = __ultoa(ulval, cp, base, | |
907 | flags & ALT, xdigs); | |
908 | } | |
909 | size = buf + BUF - cp; | |
910 | break; | |
911 | default: /* "%?" prints ?, unless ? is NUL */ | |
912 | if (ch == '\0') | |
913 | goto done; | |
914 | /* pretend it was %c with argument ch */ | |
915 | cp = buf; | |
916 | *cp = ch; | |
917 | size = 1; | |
918 | sign = '\0'; | |
919 | break; | |
920 | } | |
921 | ||
5b2abdfb A |
922 | #ifdef ALTIVEC |
923 | if (flags & VECTOR) { | |
924 | /* | |
925 | * Do the minimum amount of work necessary to construct | |
926 | * a format specifier that can be used to recursively | |
927 | * call vfprintf() for each element in the vector. | |
928 | */ | |
929 | int i, j; /* Counter. */ | |
930 | int vcnt; /* Number of elements in vector. */ | |
931 | char *vfmt; /* Pointer to format specifier. */ | |
932 | char vfmt_buf[32]; /* Static buffer for format spec. */ | |
933 | int vwidth = 0; /* Width specified via '*'. */ | |
934 | int vprec = 0; /* Precision specified via '*'. */ | |
935 | union { /* Element. */ | |
936 | int i; | |
937 | float f; | |
938 | } velm; | |
939 | char *vstr; /* Used for asprintf(). */ | |
940 | int vlen; /* Length returned by asprintf(). */ | |
941 | ||
942 | /* | |
943 | * Set vfmt. If vfmt_buf may not be big enough, | |
944 | * malloc() space, taking care to free it later. | |
945 | */ | |
946 | if (&fmt[-1] - pct < sizeof(vfmt_buf)) | |
947 | vfmt = vfmt_buf; | |
948 | else | |
949 | vfmt = (char *)malloc(&fmt[-1] - pct + 1); | |
950 | ||
951 | /* Set the separator character, if not specified. */ | |
952 | if (vsep == 'X') { | |
953 | if (ch == 'c') | |
954 | vsep = '\0'; | |
955 | else | |
956 | vsep = ' '; | |
957 | } | |
958 | ||
959 | /* Create the format specifier. */ | |
960 | for (i = j = 0; i < &fmt[-1] - pct; i++) { | |
961 | switch (pct[i]) { | |
962 | case ',': case ';': case ':': case '_': | |
963 | case 'v': case 'h': case 'l': | |
964 | /* Ignore. */ | |
965 | break; | |
966 | case '*': | |
967 | if (pct[i - 1] != '.') | |
968 | vwidth = 1; | |
969 | else | |
970 | vprec = 1; | |
971 | /* FALLTHROUGH */ | |
972 | default: | |
973 | vfmt[j++] = pct[i]; | |
974 | } | |
975 | } | |
976 | ||
977 | /* | |
978 | * Determine the number of elements in the vector and | |
979 | * finish up the format specifier. | |
980 | */ | |
981 | if (flags & SHORTINT) { | |
982 | vfmt[j++] = 'h'; | |
983 | vcnt = 8; | |
984 | } else if (flags & LONGINT) { | |
985 | vfmt[j++] = 'l'; | |
986 | vcnt = 4; | |
987 | } else { | |
988 | switch (ch) { | |
989 | case 'e': | |
990 | case 'E': | |
991 | case 'f': | |
992 | case 'g': | |
993 | case 'G': | |
994 | vcnt = 4; | |
995 | break; | |
996 | default: | |
997 | /* | |
998 | * The default case should never | |
999 | * happen. | |
1000 | */ | |
1001 | case 'c': | |
1002 | case 'd': | |
1003 | case 'i': | |
1004 | case 'u': | |
1005 | case 'o': | |
1006 | case 'p': | |
1007 | case 'x': | |
1008 | case 'X': | |
1009 | vcnt = 16; | |
1010 | } | |
1011 | } | |
1012 | vfmt[j++] = ch; | |
1013 | vfmt[j++] = '\0'; | |
1014 | ||
1015 | /* Get a vector element. */ | |
1016 | #define VPRINT(cnt, ind, args...) do { \ | |
1017 | if (flags & FPT) { \ | |
1018 | velm.f = vval.vfloatarg[ind]; \ | |
1019 | vlen = asprintf(&vstr, vfmt , ## args, velm.f); \ | |
1020 | } else { \ | |
1021 | switch (cnt) { \ | |
1022 | default: \ | |
1023 | /* The default case should never happen. */ \ | |
1024 | case 4: \ | |
1025 | velm.i = vval.vintarg[ind]; \ | |
1026 | break; \ | |
1027 | case 8: \ | |
1028 | velm.i = vval.vshortarg[ind]; \ | |
1029 | break; \ | |
1030 | case 16: \ | |
1031 | velm.i = vval.vchararg[ind]; \ | |
1032 | break; \ | |
1033 | } \ | |
1034 | vlen = asprintf(&vstr, vfmt , ## args, velm.i); \ | |
1035 | } \ | |
1036 | ret += vlen; \ | |
1037 | PRINT(vstr, vlen); \ | |
1038 | FLUSH(); \ | |
1039 | free(vstr); \ | |
1040 | } while (0) | |
1041 | ||
1042 | /* Actually print. */ | |
1043 | if (vwidth == 0) { | |
1044 | if (vprec == 0) { | |
1045 | /* First element. */ | |
1046 | VPRINT(vcnt, 0); | |
1047 | for (i = 1; i < vcnt; i++) { | |
1048 | /* Separator. */ | |
1049 | PRINT(&vsep, 1); | |
1050 | ||
1051 | /* Element. */ | |
1052 | VPRINT(vcnt, i); | |
1053 | } | |
1054 | } else { | |
1055 | /* First element. */ | |
1056 | VPRINT(vcnt, 0, prec); | |
1057 | for (i = 1; i < vcnt; i++) { | |
1058 | /* Separator. */ | |
1059 | PRINT(&vsep, 1); | |
1060 | ||
1061 | /* Element. */ | |
1062 | VPRINT(vcnt, i, prec); | |
1063 | } | |
1064 | } | |
1065 | } else { | |
1066 | if (vprec == 0) { | |
1067 | /* First element. */ | |
1068 | VPRINT(vcnt, 0, width); | |
1069 | for (i = 1; i < vcnt; i++) { | |
1070 | /* Separator. */ | |
1071 | PRINT(&vsep, 1); | |
1072 | ||
1073 | /* Element. */ | |
1074 | VPRINT(vcnt, i, width); | |
1075 | } | |
1076 | } else { | |
1077 | /* First element. */ | |
1078 | VPRINT(vcnt, 0, width, prec); | |
1079 | for (i = 1; i < vcnt; i++) { | |
1080 | /* Separator. */ | |
1081 | PRINT(&vsep, 1); | |
1082 | ||
1083 | /* Element. */ | |
1084 | VPRINT(vcnt, i, width, prec); | |
1085 | } | |
1086 | } | |
1087 | } | |
1088 | #undef VPRINT | |
1089 | ||
1090 | if (vfmt != vfmt_buf) | |
1091 | free(vfmt); | |
1092 | ||
1093 | continue; | |
1094 | } | |
1095 | #endif | |
e9ce8d39 A |
1096 | /* |
1097 | * All reasonable formats wind up here. At this point, `cp' | |
1098 | * points to a string which (if not flags&LADJUST) should be | |
1099 | * padded out to `width' places. If flags&ZEROPAD, it should | |
1100 | * first be prefixed by any sign or other prefix; otherwise, | |
1101 | * it should be blank padded before the prefix is emitted. | |
1102 | * After any left-hand padding and prefixing, emit zeroes | |
1103 | * required by a decimal [diouxX] precision, then print the | |
1104 | * string proper, then emit zeroes required by any leftover | |
1105 | * floating precision; finally, if LADJUST, pad with blanks. | |
1106 | * | |
1107 | * Compute actual size, so we know how much to pad. | |
1108 | * size excludes decimal prec; realsz includes it. | |
1109 | */ | |
1110 | realsz = dprec > size ? dprec : size; | |
1111 | if (sign) | |
1112 | realsz++; | |
1113 | else if (flags & HEXPREFIX) | |
1114 | realsz += 2; | |
1115 | ||
1116 | prsize = width > realsz ? width : realsz; | |
1117 | if ((unsigned)ret + prsize > INT_MAX) { | |
1118 | ret = EOF; | |
1119 | goto error; | |
1120 | } | |
1121 | ||
1122 | /* right-adjusting blank padding */ | |
1123 | if ((flags & (LADJUST|ZEROPAD)) == 0) | |
1124 | PAD(width - realsz, blanks); | |
1125 | ||
1126 | /* prefix */ | |
1127 | if (sign) { | |
1128 | PRINT(&sign, 1); | |
1129 | } else if (flags & HEXPREFIX) { | |
1130 | ox[0] = '0'; | |
1131 | ox[1] = ch; | |
1132 | PRINT(ox, 2); | |
1133 | } | |
1134 | ||
1135 | /* right-adjusting zero padding */ | |
1136 | if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) | |
1137 | PAD(width - realsz, zeroes); | |
1138 | ||
1139 | /* leading zeroes from decimal precision */ | |
1140 | PAD(dprec - size, zeroes); | |
1141 | ||
1142 | /* the string or number proper */ | |
1143 | #ifdef FLOATING_POINT | |
1144 | if ((flags & FPT) == 0) { | |
1145 | PRINT(cp, size); | |
1146 | } else { /* glue together f_p fragments */ | |
1147 | if (ch >= 'f') { /* 'f' or 'g' */ | |
1148 | if (_double == 0) { | |
1149 | /* kludge for __dtoa irregularity */ | |
1150 | if (expt >= ndig && | |
1151 | (flags & ALT) == 0) { | |
1152 | PRINT("0", 1); | |
1153 | } else { | |
1154 | PRINT("0.", 2); | |
1155 | PAD(ndig - 1, zeroes); | |
1156 | } | |
1157 | } else if (expt <= 0) { | |
1158 | PRINT("0.", 2); | |
1159 | PAD(-expt, zeroes); | |
1160 | PRINT(cp, ndig); | |
1161 | } else if (expt >= ndig) { | |
1162 | PRINT(cp, ndig); | |
1163 | PAD(expt - ndig, zeroes); | |
1164 | if (flags & ALT) | |
1165 | PRINT(".", 1); | |
1166 | } else { | |
1167 | PRINT(cp, expt); | |
1168 | cp += expt; | |
1169 | PRINT(".", 1); | |
1170 | PRINT(cp, ndig-expt); | |
1171 | } | |
1172 | } else { /* 'e' or 'E' */ | |
1173 | if (ndig > 1 || flags & ALT) { | |
1174 | ox[0] = *cp++; | |
1175 | ox[1] = '.'; | |
1176 | PRINT(ox, 2); | |
1177 | if (_double) { | |
1178 | PRINT(cp, ndig-1); | |
1179 | } else /* 0.[0..] */ | |
1180 | /* __dtoa irregularity */ | |
1181 | PAD(ndig - 1, zeroes); | |
1182 | } else /* XeYYY */ | |
1183 | PRINT(cp, 1); | |
1184 | PRINT(expstr, expsize); | |
1185 | } | |
1186 | } | |
1187 | #else | |
1188 | PRINT(cp, size); | |
1189 | #endif | |
5b2abdfb | 1190 | |
e9ce8d39 A |
1191 | /* left-adjusting padding (always blank) */ |
1192 | if (flags & LADJUST) | |
1193 | PAD(width - realsz, blanks); | |
1194 | ||
1195 | /* finally, adjust ret */ | |
1196 | ret += prsize; | |
1197 | ||
1198 | FLUSH(); /* copy out the I/O vectors */ | |
1199 | } | |
1200 | done: | |
1201 | FLUSH(); | |
1202 | error: | |
3b2a1fe8 A |
1203 | #ifdef FLOATING_POINT |
1204 | if (dtoaresult != NULL) | |
1205 | free(dtoaresult); | |
1206 | #endif | |
e9ce8d39 A |
1207 | if (__sferror(fp)) |
1208 | ret = EOF; | |
1209 | /* FUNLOCKFILE(fp); */ | |
1210 | if ((argtable != NULL) && (argtable != statargtable)) | |
1211 | free (argtable); | |
1212 | return (ret); | |
1213 | /* NOTREACHED */ | |
1214 | } | |
1215 | ||
1216 | /* | |
1217 | * Type ids for argument type table. | |
1218 | */ | |
1219 | #define T_UNUSED 0 | |
1220 | #define T_SHORT 1 | |
1221 | #define T_U_SHORT 2 | |
1222 | #define TP_SHORT 3 | |
1223 | #define T_INT 4 | |
1224 | #define T_U_INT 5 | |
1225 | #define TP_INT 6 | |
1226 | #define T_LONG 7 | |
1227 | #define T_U_LONG 8 | |
1228 | #define TP_LONG 9 | |
1229 | #define T_QUAD 10 | |
1230 | #define T_U_QUAD 11 | |
1231 | #define TP_QUAD 12 | |
1232 | #define T_DOUBLE 13 | |
1233 | #define T_LONG_DOUBLE 14 | |
1234 | #define TP_CHAR 15 | |
1235 | #define TP_VOID 16 | |
5b2abdfb | 1236 | #define T_VECTOR 17 |
e9ce8d39 A |
1237 | |
1238 | /* | |
1239 | * Find all arguments when a positional parameter is encountered. Returns a | |
1240 | * table, indexed by argument number, of pointers to each arguments. The | |
1241 | * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. | |
3b2a1fe8 | 1242 | * It will be replaces with a malloc-ed one if it overflows. |
e9ce8d39 A |
1243 | */ |
1244 | static void | |
1245 | __find_arguments (fmt0, ap, argtable) | |
1246 | const char *fmt0; | |
1247 | va_list ap; | |
5b2abdfb | 1248 | union arg **argtable; |
e9ce8d39 A |
1249 | { |
1250 | register char *fmt; /* format string */ | |
1251 | register int ch; /* character from fmt */ | |
1252 | register int n, n2; /* handy integer (short term usage) */ | |
1253 | register char *cp; /* handy char pointer (short term usage) */ | |
1254 | register int flags; /* flags as above */ | |
1255 | int width; /* width from format (%8d), or 0 */ | |
1256 | unsigned char *typetable; /* table of types */ | |
1257 | unsigned char stattypetable [STATIC_ARG_TBL_SIZE]; | |
1258 | int tablesize; /* current size of type table */ | |
1259 | int tablemax; /* largest used index in table */ | |
1260 | int nextarg; /* 1-based argument index */ | |
1261 | ||
1262 | /* | |
1263 | * Add an argument type to the table, expanding if necessary. | |
1264 | */ | |
1265 | #define ADDTYPE(type) \ | |
1266 | ((nextarg >= tablesize) ? \ | |
1267 | __grow_type_table(nextarg, &typetable, &tablesize) : 0, \ | |
3b2a1fe8 A |
1268 | (nextarg > tablemax) ? tablemax = nextarg : 0, \ |
1269 | typetable[nextarg++] = type) | |
e9ce8d39 A |
1270 | |
1271 | #define ADDSARG() \ | |
1272 | ((flags&LONGINT) ? ADDTYPE(T_LONG) : \ | |
1273 | ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT))) | |
1274 | ||
1275 | #define ADDUARG() \ | |
1276 | ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \ | |
1277 | ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT))) | |
1278 | ||
1279 | /* | |
1280 | * Add * arguments to the type array. | |
1281 | */ | |
1282 | #define ADDASTER() \ | |
1283 | n2 = 0; \ | |
1284 | cp = fmt; \ | |
1285 | while (is_digit(*cp)) { \ | |
1286 | n2 = 10 * n2 + to_digit(*cp); \ | |
1287 | cp++; \ | |
1288 | } \ | |
1289 | if (*cp == '$') { \ | |
1290 | int hold = nextarg; \ | |
1291 | nextarg = n2; \ | |
1292 | ADDTYPE (T_INT); \ | |
1293 | nextarg = hold; \ | |
1294 | fmt = ++cp; \ | |
1295 | } else { \ | |
1296 | ADDTYPE (T_INT); \ | |
1297 | } | |
1298 | fmt = (char *)fmt0; | |
1299 | typetable = stattypetable; | |
1300 | tablesize = STATIC_ARG_TBL_SIZE; | |
1301 | tablemax = 0; | |
1302 | nextarg = 1; | |
1303 | memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); | |
1304 | ||
1305 | /* | |
1306 | * Scan the format for conversions (`%' character). | |
1307 | */ | |
1308 | for (;;) { | |
1309 | for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) | |
1310 | /* void */; | |
1311 | if (ch == '\0') | |
1312 | goto done; | |
1313 | fmt++; /* skip over '%' */ | |
1314 | ||
1315 | flags = 0; | |
1316 | width = 0; | |
1317 | ||
1318 | rflag: ch = *fmt++; | |
1319 | reswitch: switch (ch) { | |
1320 | case ' ': | |
1321 | case '#': | |
1322 | goto rflag; | |
1323 | case '*': | |
1324 | ADDASTER (); | |
1325 | goto rflag; | |
1326 | case '-': | |
1327 | case '+': | |
1328 | goto rflag; | |
1329 | case '.': | |
1330 | if ((ch = *fmt++) == '*') { | |
1331 | ADDASTER (); | |
1332 | goto rflag; | |
1333 | } | |
1334 | while (is_digit(ch)) { | |
1335 | ch = *fmt++; | |
1336 | } | |
1337 | goto reswitch; | |
1338 | case '0': | |
1339 | goto rflag; | |
1340 | case '1': case '2': case '3': case '4': | |
1341 | case '5': case '6': case '7': case '8': case '9': | |
1342 | n = 0; | |
1343 | do { | |
1344 | n = 10 * n + to_digit(ch); | |
1345 | ch = *fmt++; | |
1346 | } while (is_digit(ch)); | |
1347 | if (ch == '$') { | |
1348 | nextarg = n; | |
1349 | goto rflag; | |
1350 | } | |
1351 | width = n; | |
1352 | goto reswitch; | |
1353 | #ifdef FLOATING_POINT | |
1354 | case 'L': | |
1355 | flags |= LONGDBL; | |
1356 | goto rflag; | |
1357 | #endif | |
1358 | case 'h': | |
1359 | flags |= SHORTINT; | |
1360 | goto rflag; | |
1361 | case 'l': | |
1362 | if (flags & LONGINT) | |
1363 | flags |= QUADINT; | |
1364 | else | |
1365 | flags |= LONGINT; | |
1366 | goto rflag; | |
1367 | case 'q': | |
1368 | flags |= QUADINT; | |
1369 | goto rflag; | |
1370 | case 'c': | |
5b2abdfb A |
1371 | #ifdef ALTIVEC |
1372 | if (flags & VECTOR) | |
1373 | ADDTYPE(T_VECTOR); | |
1374 | else | |
1375 | #endif | |
1376 | ADDTYPE(T_INT); | |
e9ce8d39 A |
1377 | break; |
1378 | case 'D': | |
1379 | flags |= LONGINT; | |
1380 | /*FALLTHROUGH*/ | |
1381 | case 'd': | |
1382 | case 'i': | |
5b2abdfb A |
1383 | #ifdef ALTIVEC |
1384 | if (flags & VECTOR) | |
1385 | ADDTYPE(T_VECTOR); | |
1386 | else | |
1387 | #endif | |
e9ce8d39 A |
1388 | if (flags & QUADINT) { |
1389 | ADDTYPE(T_QUAD); | |
1390 | } else { | |
1391 | ADDSARG(); | |
1392 | } | |
1393 | break; | |
1394 | #ifdef FLOATING_POINT | |
1395 | case 'e': | |
1396 | case 'E': | |
1397 | case 'f': | |
1398 | case 'g': | |
1399 | case 'G': | |
5b2abdfb A |
1400 | #ifdef ALTIVEC |
1401 | if (flags & VECTOR) | |
1402 | ADDTYPE(T_VECTOR); | |
1403 | else | |
1404 | #endif | |
e9ce8d39 A |
1405 | if (flags & LONGDBL) |
1406 | ADDTYPE(T_LONG_DOUBLE); | |
1407 | else | |
1408 | ADDTYPE(T_DOUBLE); | |
1409 | break; | |
1410 | #endif /* FLOATING_POINT */ | |
1411 | case 'n': | |
1412 | if (flags & QUADINT) | |
1413 | ADDTYPE(TP_QUAD); | |
1414 | else if (flags & LONGINT) | |
1415 | ADDTYPE(TP_LONG); | |
1416 | else if (flags & SHORTINT) | |
1417 | ADDTYPE(TP_SHORT); | |
1418 | else | |
1419 | ADDTYPE(TP_INT); | |
1420 | continue; /* no output */ | |
1421 | case 'O': | |
1422 | flags |= LONGINT; | |
1423 | /*FALLTHROUGH*/ | |
1424 | case 'o': | |
5b2abdfb A |
1425 | #ifdef ALTIVEC |
1426 | if (flags & VECTOR) | |
1427 | ADDTYPE(T_VECTOR); | |
1428 | else | |
1429 | #endif | |
e9ce8d39 A |
1430 | if (flags & QUADINT) |
1431 | ADDTYPE(T_U_QUAD); | |
1432 | else | |
1433 | ADDUARG(); | |
1434 | break; | |
1435 | case 'p': | |
5b2abdfb A |
1436 | #ifdef ALTIVEC |
1437 | if (flags & VECTOR) | |
1438 | ADDTYPE(T_VECTOR); | |
1439 | else | |
1440 | #endif | |
1441 | ADDTYPE(TP_VOID); | |
e9ce8d39 A |
1442 | break; |
1443 | case 's': | |
1444 | ADDTYPE(TP_CHAR); | |
1445 | break; | |
1446 | case 'U': | |
1447 | flags |= LONGINT; | |
1448 | /*FALLTHROUGH*/ | |
1449 | case 'u': | |
5b2abdfb A |
1450 | #ifdef ALTIVEC |
1451 | if (flags & VECTOR) | |
1452 | ADDTYPE(T_VECTOR); | |
1453 | else | |
1454 | #endif | |
e9ce8d39 A |
1455 | if (flags & QUADINT) |
1456 | ADDTYPE(T_U_QUAD); | |
1457 | else | |
1458 | ADDUARG(); | |
1459 | break; | |
1460 | case 'X': | |
1461 | case 'x': | |
5b2abdfb A |
1462 | #ifdef ALTIVEC |
1463 | if (flags & VECTOR) | |
1464 | ADDTYPE(T_VECTOR); | |
1465 | else | |
1466 | #endif | |
e9ce8d39 A |
1467 | if (flags & QUADINT) |
1468 | ADDTYPE(T_U_QUAD); | |
1469 | else | |
1470 | ADDUARG(); | |
1471 | break; | |
1472 | default: /* "%?" prints ?, unless ? is NUL */ | |
1473 | if (ch == '\0') | |
1474 | goto done; | |
1475 | break; | |
1476 | } | |
1477 | } | |
1478 | done: | |
1479 | /* | |
1480 | * Build the argument table. | |
1481 | */ | |
1482 | if (tablemax >= STATIC_ARG_TBL_SIZE) { | |
5b2abdfb A |
1483 | *argtable = (union arg *) |
1484 | malloc (sizeof (union arg) * (tablemax + 1)); | |
e9ce8d39 A |
1485 | } |
1486 | ||
5b2abdfb | 1487 | (*argtable) [0].intarg = NULL; |
e9ce8d39 A |
1488 | for (n = 1; n <= tablemax; n++) { |
1489 | switch (typetable [n]) { | |
1490 | case T_UNUSED: | |
5b2abdfb | 1491 | (*argtable) [n].intarg = va_arg (ap, int); |
e9ce8d39 A |
1492 | break; |
1493 | case T_SHORT: | |
5b2abdfb | 1494 | (*argtable) [n].intarg = va_arg (ap, int); |
e9ce8d39 A |
1495 | break; |
1496 | case T_U_SHORT: | |
5b2abdfb | 1497 | (*argtable) [n].intarg = va_arg (ap, int); |
e9ce8d39 A |
1498 | break; |
1499 | case TP_SHORT: | |
5b2abdfb | 1500 | (*argtable) [n].pshortarg = va_arg (ap, short *); |
e9ce8d39 A |
1501 | break; |
1502 | case T_INT: | |
5b2abdfb | 1503 | (*argtable) [n].intarg = va_arg (ap, int); |
e9ce8d39 A |
1504 | break; |
1505 | case T_U_INT: | |
5b2abdfb | 1506 | (*argtable) [n].uintarg = va_arg (ap, unsigned int); |
e9ce8d39 A |
1507 | break; |
1508 | case TP_INT: | |
5b2abdfb | 1509 | (*argtable) [n].pintarg = va_arg (ap, int *); |
e9ce8d39 A |
1510 | break; |
1511 | case T_LONG: | |
5b2abdfb | 1512 | (*argtable) [n].longarg = va_arg (ap, long); |
e9ce8d39 A |
1513 | break; |
1514 | case T_U_LONG: | |
5b2abdfb | 1515 | (*argtable) [n].ulongarg = va_arg (ap, unsigned long); |
e9ce8d39 A |
1516 | break; |
1517 | case TP_LONG: | |
5b2abdfb | 1518 | (*argtable) [n].plongarg = va_arg (ap, long *); |
e9ce8d39 A |
1519 | break; |
1520 | case T_QUAD: | |
5b2abdfb | 1521 | (*argtable) [n].quadarg = va_arg (ap, quad_t); |
e9ce8d39 A |
1522 | break; |
1523 | case T_U_QUAD: | |
5b2abdfb | 1524 | (*argtable) [n].uquadarg = va_arg (ap, u_quad_t); |
e9ce8d39 A |
1525 | break; |
1526 | case TP_QUAD: | |
5b2abdfb | 1527 | (*argtable) [n].pquadarg = va_arg (ap, quad_t *); |
e9ce8d39 | 1528 | break; |
5b2abdfb | 1529 | #ifdef FLOATING_POINT |
e9ce8d39 | 1530 | case T_DOUBLE: |
5b2abdfb | 1531 | (*argtable) [n].doublearg = va_arg (ap, double); |
e9ce8d39 A |
1532 | break; |
1533 | case T_LONG_DOUBLE: | |
5b2abdfb | 1534 | (*argtable) [n].longdoublearg = va_arg (ap, long double); |
e9ce8d39 | 1535 | break; |
5b2abdfb A |
1536 | #endif |
1537 | #ifdef ALTIVEC | |
1538 | case T_VECTOR: | |
1539 | { int tmp = 0; | |
1540 | getvec( &((*argtable) [n]), NULL, tmp, ap ); | |
1541 | } | |
1542 | #endif | |
e9ce8d39 | 1543 | case TP_CHAR: |
5b2abdfb | 1544 | (*argtable) [n].pchararg = va_arg (ap, char *); |
e9ce8d39 A |
1545 | break; |
1546 | case TP_VOID: | |
5b2abdfb | 1547 | (*argtable) [n].pvoidarg = va_arg (ap, void *); |
e9ce8d39 A |
1548 | break; |
1549 | } | |
1550 | } | |
1551 | ||
1552 | if ((typetable != NULL) && (typetable != stattypetable)) | |
1553 | free (typetable); | |
1554 | } | |
1555 | ||
1556 | /* | |
1557 | * Increase the size of the type table. | |
1558 | */ | |
1559 | static void | |
1560 | __grow_type_table (nextarg, typetable, tablesize) | |
1561 | int nextarg; | |
1562 | unsigned char **typetable; | |
1563 | int *tablesize; | |
1564 | { | |
3b2a1fe8 A |
1565 | unsigned char *const oldtable = *typetable; |
1566 | const int oldsize = *tablesize; | |
1567 | unsigned char *newtable; | |
1568 | int newsize = oldsize * 2; | |
1569 | ||
1570 | if (newsize < nextarg + 1) | |
1571 | newsize = nextarg + 1; | |
1572 | if (oldsize == STATIC_ARG_TBL_SIZE) { | |
1573 | if ((newtable = malloc (newsize)) == NULL) | |
1574 | abort(); /* XXX handle better */ | |
1575 | bcopy (oldtable, newtable, oldsize); | |
e9ce8d39 | 1576 | } else { |
3b2a1fe8 A |
1577 | if ((newtable = realloc (oldtable, newsize)) == NULL) |
1578 | abort(); /* XXX handle better */ | |
e9ce8d39 | 1579 | } |
3b2a1fe8 | 1580 | memset (&newtable [oldsize], T_UNUSED, (newsize - oldsize)); |
e9ce8d39 | 1581 | |
3b2a1fe8 | 1582 | *typetable = newtable; |
e9ce8d39 A |
1583 | *tablesize = newsize; |
1584 | } | |
1585 | ||
1586 | ||
1587 | #ifdef FLOATING_POINT | |
1588 | ||
3b2a1fe8 | 1589 | extern char *__dtoa __P((double, int, int, int *, int *, char **, char **)); |
e9ce8d39 A |
1590 | |
1591 | static char * | |
3b2a1fe8 | 1592 | cvt(value, ndigits, flags, sign, decpt, ch, length, dtoaresultp) |
e9ce8d39 A |
1593 | double value; |
1594 | int ndigits, flags, *decpt, ch, *length; | |
1595 | char *sign; | |
3b2a1fe8 | 1596 | char **dtoaresultp; |
e9ce8d39 A |
1597 | { |
1598 | int mode, dsgn; | |
1599 | char *digits, *bp, *rve; | |
1600 | ||
1601 | if (ch == 'f') | |
1602 | mode = 3; /* ndigits after the decimal point */ | |
1603 | else { | |
1604 | /* | |
1605 | * To obtain ndigits after the decimal point for the 'e' | |
1606 | * and 'E' formats, round to ndigits + 1 significant | |
1607 | * figures. | |
1608 | */ | |
1609 | if (ch == 'e' || ch == 'E') | |
1610 | ndigits++; | |
1611 | mode = 2; /* ndigits significant digits */ | |
1612 | } | |
1613 | if (value < 0) { | |
1614 | value = -value; | |
1615 | *sign = '-'; | |
1616 | } else | |
1617 | *sign = '\000'; | |
3b2a1fe8 | 1618 | digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve, dtoaresultp); |
e9ce8d39 A |
1619 | if ((ch != 'g' && ch != 'G') || flags & ALT) { |
1620 | /* print trailing zeros */ | |
1621 | bp = digits + ndigits; | |
1622 | if (ch == 'f') { | |
1623 | if (*digits == '0' && value) | |
1624 | *decpt = -ndigits + 1; | |
1625 | bp += *decpt; | |
1626 | } | |
1627 | if (value == 0) /* kludge for __dtoa irregularity */ | |
1628 | rve = bp; | |
1629 | while (rve < bp) | |
1630 | *rve++ = '0'; | |
1631 | } | |
1632 | *length = rve - digits; | |
1633 | return (digits); | |
1634 | } | |
1635 | ||
1636 | static int | |
1637 | exponent(p0, exp, fmtch) | |
1638 | char *p0; | |
1639 | int exp, fmtch; | |
1640 | { | |
1641 | register char *p, *t; | |
1642 | char expbuf[MAXEXP]; | |
1643 | ||
1644 | p = p0; | |
1645 | *p++ = fmtch; | |
1646 | if (exp < 0) { | |
1647 | exp = -exp; | |
1648 | *p++ = '-'; | |
1649 | } | |
1650 | else | |
1651 | *p++ = '+'; | |
1652 | t = expbuf + MAXEXP; | |
1653 | if (exp > 9) { | |
1654 | do { | |
1655 | *--t = to_char(exp % 10); | |
1656 | } while ((exp /= 10) > 9); | |
1657 | *--t = to_char(exp); | |
1658 | for (; t < expbuf + MAXEXP; *p++ = *t++); | |
1659 | } | |
1660 | else { | |
1661 | *p++ = '0'; | |
1662 | *p++ = to_char(exp); | |
1663 | } | |
1664 | return (p - p0); | |
1665 | } | |
1666 | #endif /* FLOATING_POINT */ |