Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/i386/modules/Libc/stdio/printf-pos.c

1/*-
2 * Copyright (c) 1990, 1993
3 *The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Torek.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#if defined(LIBC_SCCS) && !defined(lint)
34static char sccsid[] = "@(#)vfprintf.c8.1 (Berkeley) 6/4/93";
35#endif /* LIBC_SCCS and not lint */
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD: src/lib/libc/stdio/printf-pos.c,v 1.6 2009/03/02 04:07:58 das Exp $");
38
39/*
40 * This is the code responsible for handling positional arguments
41 * (%m$ and %m$.n$) for vfprintf() and vfwprintf().
42 */
43
44#include "namespace.h"
45#include <sys/types.h>
46
47#include <stdarg.h>
48#include <stddef.h>
49#include <stdint.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <strings.h>
54
55#include "un-namespace.h"
56#include "printflocal.h"
57
58/*
59 * Type ids for argument type table.
60 */
61enum typeid {
62T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
63T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
64T_PTRDIFFT, TP_PTRDIFFT, T_SSIZET, T_SIZET, TP_SSIZET,
65T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
66T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
67};
68
69/* An expandable array of types. */
70struct typetable {
71enum typeid *table; /* table of types */
72enum typeid stattable[STATIC_ARG_TBL_SIZE];
73int tablesize;/* current size of type table */
74int tablemax;/* largest used index in table */
75int nextarg;/* 1-based argument index */
76};
77
78static int__grow_type_table(struct typetable *);
79static voidbuild_arg_table (struct typetable *, va_list, union arg **);
80
81/*
82 * Initialize a struct typetable.
83 */
84static inline void
85inittypes(struct typetable *types)
86{
87int n;
88
89types->table = types->stattable;
90types->tablesize = STATIC_ARG_TBL_SIZE;
91types->tablemax = 0;
92types->nextarg = 1;
93for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
94types->table[n] = T_UNUSED;
95}
96
97/*
98 * struct typetable destructor.
99 */
100static inline void
101freetypes(struct typetable *types)
102{
103
104if (types->table != types->stattable)
105free (types->table);
106}
107
108/*
109 * Ensure that there is space to add a new argument type to the type table.
110 * Expand the table if necessary. Returns 0 on success.
111 */
112static inline int
113_ensurespace(struct typetable *types)
114{
115
116if (types->nextarg >= types->tablesize) {
117if (__grow_type_table(types))
118return (-1);
119}
120if (types->nextarg > types->tablemax)
121types->tablemax = types->nextarg;
122return (0);
123}
124
125/*
126 * Add an argument type to the table, expanding if necessary.
127 * Returns 0 on success.
128 */
129static inline int
130addtype(struct typetable *types, enum typeid type)
131{
132
133if (_ensurespace(types))
134return (-1);
135types->table[types->nextarg++] = type;
136return (0);
137}
138
139static inline int
140addsarg(struct typetable *types, int flags)
141{
142
143if (_ensurespace(types))
144return (-1);
145if (flags & INTMAXT)
146types->table[types->nextarg++] = T_INTMAXT;
147else if (flags & SIZET)
148types->table[types->nextarg++] = T_SSIZET;
149else if (flags & PTRDIFFT)
150types->table[types->nextarg++] = T_PTRDIFFT;
151else if (flags & LLONGINT)
152types->table[types->nextarg++] = T_LLONG;
153else if (flags & LONGINT)
154types->table[types->nextarg++] = T_LONG;
155else
156types->table[types->nextarg++] = T_INT;
157return (0);
158}
159
160static inline int
161adduarg(struct typetable *types, int flags)
162{
163
164if (_ensurespace(types))
165return (-1);
166if (flags & INTMAXT)
167types->table[types->nextarg++] = T_UINTMAXT;
168else if (flags & SIZET)
169types->table[types->nextarg++] = T_SIZET;
170else if (flags & PTRDIFFT)
171types->table[types->nextarg++] = T_SIZET;
172else if (flags & LLONGINT)
173types->table[types->nextarg++] = T_U_LLONG;
174else if (flags & LONGINT)
175types->table[types->nextarg++] = T_U_LONG;
176else
177types->table[types->nextarg++] = T_U_INT;
178return (0);
179}
180
181/*
182 * Add * arguments to the type array.
183 */
184static inline int
185addaster(struct typetable *types, char **fmtp)
186{
187char *cp;
188int n2;
189
190n2 = 0;
191cp = *fmtp;
192while (is_digit(*cp)) {
193n2 = 10 * n2 + to_digit(*cp);
194cp++;
195}
196if (*cp == '$') {
197int hold = types->nextarg;
198types->nextarg = n2;
199if (addtype(types, T_INT))
200return (-1);
201types->nextarg = hold;
202*fmtp = ++cp;
203} else {
204if (addtype(types, T_INT))
205return (-1);
206}
207return (0);
208}
209
210static inline int
211addwaster(struct typetable *types, wchar_t **fmtp)
212{
213wchar_t *cp;
214int n2;
215
216n2 = 0;
217cp = *fmtp;
218while (is_digit(*cp)) {
219n2 = 10 * n2 + to_digit(*cp);
220cp++;
221}
222if (*cp == '$') {
223int hold = types->nextarg;
224types->nextarg = n2;
225if (addtype(types, T_INT))
226return (-1);
227types->nextarg = hold;
228*fmtp = ++cp;
229} else {
230if (addtype(types, T_INT))
231return (-1);
232}
233return (0);
234}
235
236/*
237 * Find all arguments when a positional parameter is encountered. Returns a
238 * table, indexed by argument number, of pointers to each arguments. The
239 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
240 * It will be replaces with a malloc-ed one if it overflows.
241 * Returns 0 on success. On failure, returns nonzero and sets errno.
242 */
243int
244__find_arguments (const char *fmt0, va_list ap, union arg **argtable)
245{
246char *fmt;/* format string */
247int ch;/* character from fmt */
248int n;/* handy integer (short term usage) */
249int error;
250int flags;/* flags as above */
251struct typetable types;/* table of types */
252
253fmt = (char *)fmt0;
254inittypes(&types);
255error = 0;
256
257/*
258 * Scan the format for conversions (`%' character).
259 */
260for (;;) {
261while ((ch = *fmt) != '\0' && ch != '%')
262fmt++;
263if (ch == '\0')
264goto done;
265fmt++;/* skip over '%' */
266
267flags = 0;
268
269rflag:ch = *fmt++;
270reswitch:switch (ch) {
271case ' ':
272case '#':
273goto rflag;
274case '*':
275if ((error = addaster(&types, &fmt)))
276goto error;
277goto rflag;
278case '-':
279case '+':
280case '\'':
281goto rflag;
282case '.':
283if ((ch = *fmt++) == '*') {
284if ((error = addaster(&types, &fmt)))
285goto error;
286goto rflag;
287}
288while (is_digit(ch)) {
289ch = *fmt++;
290}
291goto reswitch;
292case '0':
293goto rflag;
294case '1': case '2': case '3': case '4':
295case '5': case '6': case '7': case '8': case '9':
296n = 0;
297do {
298n = 10 * n + to_digit(ch);
299ch = *fmt++;
300} while (is_digit(ch));
301if (ch == '$') {
302types.nextarg = n;
303goto rflag;
304}
305goto reswitch;
306#ifndef NO_FLOATING_POINT
307case 'L':
308flags |= LONGDBL;
309goto rflag;
310#endif
311case 'h':
312if (flags & SHORTINT) {
313flags &= ~SHORTINT;
314flags |= CHARINT;
315} else
316flags |= SHORTINT;
317goto rflag;
318case 'j':
319flags |= INTMAXT;
320goto rflag;
321case 'l':
322if (flags & LONGINT) {
323flags &= ~LONGINT;
324flags |= LLONGINT;
325} else
326flags |= LONGINT;
327goto rflag;
328case 'q':
329flags |= LLONGINT;/* not necessarily */
330goto rflag;
331case 't':
332flags |= PTRDIFFT;
333goto rflag;
334case 'z':
335flags |= SIZET;
336goto rflag;
337case 'C':
338flags |= LONGINT;
339/*FALLTHROUGH*/
340case 'c':
341error = addtype(&types,
342(flags & LONGINT) ? T_WINT : T_INT);
343if (error)
344goto error;
345break;
346case 'D':
347flags |= LONGINT;
348/*FALLTHROUGH*/
349case 'd':
350case 'i':
351if ((error = addsarg(&types, flags)))
352goto error;
353break;
354#ifndef NO_FLOATING_POINT
355case 'a':
356case 'A':
357case 'e':
358case 'E':
359case 'f':
360case 'g':
361case 'G':
362error = addtype(&types,
363 (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
364if (error)
365goto error;
366break;
367#endif /* !NO_FLOATING_POINT */
368case 'n':
369if (flags & INTMAXT)
370error = addtype(&types, TP_INTMAXT);
371else if (flags & PTRDIFFT)
372error = addtype(&types, TP_PTRDIFFT);
373else if (flags & SIZET)
374error = addtype(&types, TP_SSIZET);
375else if (flags & LLONGINT)
376error = addtype(&types, TP_LLONG);
377else if (flags & LONGINT)
378error = addtype(&types, TP_LONG);
379else if (flags & SHORTINT)
380error = addtype(&types, TP_SHORT);
381else if (flags & CHARINT)
382error = addtype(&types, TP_SCHAR);
383else
384error = addtype(&types, TP_INT);
385if (error)
386goto error;
387continue;/* no output */
388case 'O':
389flags |= LONGINT;
390/*FALLTHROUGH*/
391case 'o':
392if ((error = adduarg(&types, flags)))
393goto error;
394break;
395case 'p':
396if ((error = addtype(&types, TP_VOID)))
397goto error;
398break;
399case 'S':
400flags |= LONGINT;
401/*FALLTHROUGH*/
402case 's':
403error = addtype(&types,
404(flags & LONGINT) ? TP_WCHAR : TP_CHAR);
405if (error)
406goto error;
407break;
408case 'U':
409flags |= LONGINT;
410/*FALLTHROUGH*/
411case 'u':
412case 'X':
413case 'x':
414if ((error = adduarg(&types, flags)))
415goto error;
416break;
417default:/* "%?" prints ?, unless ? is NUL */
418if (ch == '\0')
419goto done;
420break;
421}
422}
423done:
424build_arg_table(&types, ap, argtable);
425error:
426freetypes(&types);
427return (error || *argtable == NULL);
428}
429
430/* wchar version of __find_arguments. */
431int
432__find_warguments (const wchar_t *fmt0, va_list ap, union arg **argtable)
433{
434wchar_t *fmt;/* format string */
435wchar_t ch;/* character from fmt */
436int n;/* handy integer (short term usage) */
437int error;
438int flags;/* flags as above */
439struct typetable types;/* table of types */
440
441fmt = (wchar_t *)fmt0;
442inittypes(&types);
443error = 0;
444
445/*
446 * Scan the format for conversions (`%' character).
447 */
448for (;;) {
449while ((ch = *fmt) != '\0' && ch != '%')
450fmt++;
451if (ch == '\0')
452goto done;
453fmt++;/* skip over '%' */
454
455flags = 0;
456
457rflag:ch = *fmt++;
458reswitch:switch (ch) {
459case ' ':
460case '#':
461goto rflag;
462case '*':
463if ((error = addwaster(&types, &fmt)))
464goto error;
465goto rflag;
466case '-':
467case '+':
468case '\'':
469goto rflag;
470case '.':
471if ((ch = *fmt++) == '*') {
472if ((error = addwaster(&types, &fmt)))
473goto error;
474goto rflag;
475}
476while (is_digit(ch)) {
477ch = *fmt++;
478}
479goto reswitch;
480case '0':
481goto rflag;
482case '1': case '2': case '3': case '4':
483case '5': case '6': case '7': case '8': case '9':
484n = 0;
485do {
486n = 10 * n + to_digit(ch);
487ch = *fmt++;
488} while (is_digit(ch));
489if (ch == '$') {
490types.nextarg = n;
491goto rflag;
492}
493goto reswitch;
494#ifndef NO_FLOATING_POINT
495case 'L':
496flags |= LONGDBL;
497goto rflag;
498#endif
499case 'h':
500if (flags & SHORTINT) {
501flags &= ~SHORTINT;
502flags |= CHARINT;
503} else
504flags |= SHORTINT;
505goto rflag;
506case 'j':
507flags |= INTMAXT;
508goto rflag;
509case 'l':
510if (flags & LONGINT) {
511flags &= ~LONGINT;
512flags |= LLONGINT;
513} else
514flags |= LONGINT;
515goto rflag;
516case 'q':
517flags |= LLONGINT;/* not necessarily */
518goto rflag;
519case 't':
520flags |= PTRDIFFT;
521goto rflag;
522case 'z':
523flags |= SIZET;
524goto rflag;
525case 'C':
526flags |= LONGINT;
527/*FALLTHROUGH*/
528case 'c':
529error = addtype(&types,
530(flags & LONGINT) ? T_WINT : T_INT);
531if (error)
532goto error;
533break;
534case 'D':
535flags |= LONGINT;
536/*FALLTHROUGH*/
537case 'd':
538case 'i':
539if ((error = addsarg(&types, flags)))
540goto error;
541break;
542#ifndef NO_FLOATING_POINT
543case 'a':
544case 'A':
545case 'e':
546case 'E':
547case 'f':
548case 'g':
549case 'G':
550error = addtype(&types,
551 (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
552if (error)
553goto error;
554break;
555#endif /* !NO_FLOATING_POINT */
556case 'n':
557if (flags & INTMAXT)
558error = addtype(&types, TP_INTMAXT);
559else if (flags & PTRDIFFT)
560error = addtype(&types, TP_PTRDIFFT);
561else if (flags & SIZET)
562error = addtype(&types, TP_SSIZET);
563else if (flags & LLONGINT)
564error = addtype(&types, TP_LLONG);
565else if (flags & LONGINT)
566error = addtype(&types, TP_LONG);
567else if (flags & SHORTINT)
568error = addtype(&types, TP_SHORT);
569else if (flags & CHARINT)
570error = addtype(&types, TP_SCHAR);
571else
572error = addtype(&types, TP_INT);
573if (error)
574goto error;
575continue;/* no output */
576case 'O':
577flags |= LONGINT;
578/*FALLTHROUGH*/
579case 'o':
580if ((error = adduarg(&types, flags)))
581goto error;
582break;
583case 'p':
584if ((error = addtype(&types, TP_VOID)))
585goto error;
586break;
587case 'S':
588flags |= LONGINT;
589/*FALLTHROUGH*/
590case 's':
591error = addtype(&types,
592 (flags & LONGINT) ? TP_WCHAR : TP_CHAR);
593if (error)
594goto error;
595break;
596case 'U':
597flags |= LONGINT;
598/*FALLTHROUGH*/
599case 'u':
600case 'X':
601case 'x':
602if ((error = adduarg(&types, flags)))
603goto error;
604break;
605default:/* "%?" prints ?, unless ? is NUL */
606if (ch == '\0')
607goto done;
608break;
609}
610}
611done:
612build_arg_table(&types, ap, argtable);
613error:
614freetypes(&types);
615return (error || *argtable == NULL);
616}
617
618/*
619 * Increase the size of the type table. Returns 0 on success.
620 */
621static int
622__grow_type_table(struct typetable *types)
623{
624enum typeid *const oldtable = types->table;
625const int oldsize = types->tablesize;
626enum typeid *newtable;
627int n, newsize = oldsize * 2;
628
629if (newsize < types->nextarg + 1)
630newsize = types->nextarg + 1;
631if (oldsize == STATIC_ARG_TBL_SIZE) {
632if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
633return (-1);
634bcopy(oldtable, newtable, oldsize * sizeof(enum typeid));
635} else {
636newtable = realloc(oldtable, newsize * sizeof(enum typeid));
637if (newtable == NULL)
638return (-1);
639}
640for (n = oldsize; n < newsize; n++)
641newtable[n] = T_UNUSED;
642
643types->table = newtable;
644types->tablesize = newsize;
645
646return (0);
647}
648
649/*
650 * Build the argument table from the completed type table.
651 * On malloc failure, *argtable is set to NULL.
652 */
653static void
654build_arg_table(struct typetable *types, va_list ap, union arg **argtable)
655{
656int n;
657
658if (types->tablemax >= STATIC_ARG_TBL_SIZE) {
659*argtable = (union arg *)
660 malloc (sizeof (union arg) * (types->tablemax + 1));
661if (*argtable == NULL)
662return;
663}
664
665(*argtable) [0].intarg = 0;
666for (n = 1; n <= types->tablemax; n++) {
667switch (types->table[n]) {
668 case T_UNUSED: /* whoops! */
669(*argtable) [n].intarg = va_arg (ap, int);
670break;
671 case TP_SCHAR:
672(*argtable) [n].pschararg = va_arg (ap, signed char *);
673break;
674 case TP_SHORT:
675(*argtable) [n].pshortarg = va_arg (ap, short *);
676break;
677 case T_INT:
678(*argtable) [n].intarg = va_arg (ap, int);
679break;
680 case T_U_INT:
681(*argtable) [n].uintarg = va_arg (ap, unsigned int);
682break;
683 case TP_INT:
684(*argtable) [n].pintarg = va_arg (ap, int *);
685break;
686 case T_LONG:
687(*argtable) [n].longarg = va_arg (ap, long);
688break;
689 case T_U_LONG:
690(*argtable) [n].ulongarg = va_arg (ap, unsigned long);
691break;
692 case TP_LONG:
693(*argtable) [n].plongarg = va_arg (ap, long *);
694break;
695 case T_LLONG:
696(*argtable) [n].longlongarg = va_arg (ap, long long);
697break;
698 case T_U_LLONG:
699(*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
700break;
701 case TP_LLONG:
702(*argtable) [n].plonglongarg = va_arg (ap, long long *);
703break;
704 case T_PTRDIFFT:
705(*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
706break;
707 case TP_PTRDIFFT:
708(*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
709break;
710 case T_SIZET:
711(*argtable) [n].sizearg = va_arg (ap, size_t);
712break;
713 case T_SSIZET:
714(*argtable) [n].sizearg = va_arg (ap, ssize_t);
715break;
716 case TP_SSIZET:
717(*argtable) [n].pssizearg = va_arg (ap, ssize_t *);
718break;
719 case T_INTMAXT:
720(*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
721break;
722 case T_UINTMAXT:
723(*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
724break;
725 case TP_INTMAXT:
726(*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
727break;
728 case T_DOUBLE:
729#ifndef NO_FLOATING_POINT
730(*argtable) [n].doublearg = va_arg (ap, double);
731#endif
732break;
733 case T_LONG_DOUBLE:
734#ifndef NO_FLOATING_POINT
735(*argtable) [n].longdoublearg = va_arg (ap, long double);
736#endif
737break;
738 case TP_CHAR:
739(*argtable) [n].pchararg = va_arg (ap, char *);
740break;
741 case TP_VOID:
742(*argtable) [n].pvoidarg = va_arg (ap, void *);
743break;
744 case T_WINT:
745(*argtable) [n].wintarg = va_arg (ap, wint_t);
746break;
747 case TP_WCHAR:
748(*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
749break;
750}
751}
752}
753

Archive Download this file

Revision: 2182