1eb4bd20cSXin LI /* $NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp $ */
2eb4bd20cSXin LI
33d090549SKris Kennaway /*-
4*b61a5730SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
5d915a14eSPedro F. Giffuni *
63d090549SKris Kennaway * Copyright (c) 2000 The NetBSD Foundation, Inc.
73d090549SKris Kennaway * All rights reserved.
83d090549SKris Kennaway *
93d090549SKris Kennaway * This code was contributed to The NetBSD Foundation by Allen Briggs.
103d090549SKris Kennaway *
113d090549SKris Kennaway * Redistribution and use in source and binary forms, with or without
123d090549SKris Kennaway * modification, are permitted provided that the following conditions
133d090549SKris Kennaway * are met:
143d090549SKris Kennaway * 1. Redistributions of source code must retain the above copyright
153d090549SKris Kennaway * notice, this list of conditions and the following disclaimer.
163d090549SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright
173d090549SKris Kennaway * notice, this list of conditions and the following disclaimer in the
183d090549SKris Kennaway * documentation and/or other materials provided with the distribution.
193d090549SKris Kennaway *
203d090549SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
213d090549SKris Kennaway * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
223d090549SKris Kennaway * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
233d090549SKris Kennaway * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
243d090549SKris Kennaway * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
253d090549SKris Kennaway * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
263d090549SKris Kennaway * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
273d090549SKris Kennaway * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
283d090549SKris Kennaway * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
293d090549SKris Kennaway * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
303d090549SKris Kennaway * POSSIBILITY OF SUCH DAMAGE.
313d090549SKris Kennaway */
323d090549SKris Kennaway
333d090549SKris Kennaway #include <stdio.h>
343d090549SKris Kennaway #include <string.h>
353d090549SKris Kennaway #include <ctype.h>
363d090549SKris Kennaway
3753154da0SDaniel Eischen __weak_reference(__fmtcheck, fmtcheck);
38d5bf9eb5SCraig Rodrigues const char * __fmtcheck(const char *, const char *);
393d090549SKris Kennaway
403d090549SKris Kennaway enum __e_fmtcheck_types {
413d090549SKris Kennaway FMTCHECK_START,
423d090549SKris Kennaway FMTCHECK_SHORT,
433d090549SKris Kennaway FMTCHECK_INT,
44cc4c35b9SDavid Schultz FMTCHECK_WINTT,
453d090549SKris Kennaway FMTCHECK_LONG,
463d090549SKris Kennaway FMTCHECK_QUAD,
47cc4c35b9SDavid Schultz FMTCHECK_INTMAXT,
48ec045e41SDavid Schultz FMTCHECK_PTRDIFFT,
49ec045e41SDavid Schultz FMTCHECK_SIZET,
50cc4c35b9SDavid Schultz FMTCHECK_CHARPOINTER,
513d090549SKris Kennaway FMTCHECK_SHORTPOINTER,
523d090549SKris Kennaway FMTCHECK_INTPOINTER,
533d090549SKris Kennaway FMTCHECK_LONGPOINTER,
543d090549SKris Kennaway FMTCHECK_QUADPOINTER,
55cc4c35b9SDavid Schultz FMTCHECK_INTMAXTPOINTER,
56ec045e41SDavid Schultz FMTCHECK_PTRDIFFTPOINTER,
57ec045e41SDavid Schultz FMTCHECK_SIZETPOINTER,
5838d17374SDavid Schultz #ifndef NO_FLOATING_POINT
593d090549SKris Kennaway FMTCHECK_DOUBLE,
603d090549SKris Kennaway FMTCHECK_LONGDOUBLE,
6138d17374SDavid Schultz #endif
623d090549SKris Kennaway FMTCHECK_STRING,
63cc4c35b9SDavid Schultz FMTCHECK_WSTRING,
643d090549SKris Kennaway FMTCHECK_WIDTH,
653d090549SKris Kennaway FMTCHECK_PRECISION,
663d090549SKris Kennaway FMTCHECK_DONE,
673d090549SKris Kennaway FMTCHECK_UNKNOWN
683d090549SKris Kennaway };
693d090549SKris Kennaway typedef enum __e_fmtcheck_types EFT;
703d090549SKris Kennaway
71cc4c35b9SDavid Schultz enum e_modifier {
72cc4c35b9SDavid Schultz MOD_NONE,
73cc4c35b9SDavid Schultz MOD_CHAR,
74cc4c35b9SDavid Schultz MOD_SHORT,
75cc4c35b9SDavid Schultz MOD_LONG,
76cc4c35b9SDavid Schultz MOD_QUAD,
77cc4c35b9SDavid Schultz MOD_INTMAXT,
78cc4c35b9SDavid Schultz MOD_LONGDOUBLE,
79cc4c35b9SDavid Schultz MOD_PTRDIFFT,
80cc4c35b9SDavid Schultz MOD_SIZET,
81cc4c35b9SDavid Schultz };
82cc4c35b9SDavid Schultz
833d090549SKris Kennaway #define RETURN(pf,f,r) do { \
843d090549SKris Kennaway *(pf) = (f); \
853d090549SKris Kennaway return r; \
863d090549SKris Kennaway } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
873d090549SKris Kennaway
883d090549SKris Kennaway static EFT
get_next_format_from_precision(const char ** pf)893d090549SKris Kennaway get_next_format_from_precision(const char **pf)
903d090549SKris Kennaway {
91cc4c35b9SDavid Schultz enum e_modifier modifier;
923d090549SKris Kennaway const char *f;
933d090549SKris Kennaway
943d090549SKris Kennaway f = *pf;
953d090549SKris Kennaway switch (*f) {
963d090549SKris Kennaway case 'h':
973d090549SKris Kennaway f++;
98cc4c35b9SDavid Schultz if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
99cc4c35b9SDavid Schultz if (*f == 'h') {
100cc4c35b9SDavid Schultz f++;
101cc4c35b9SDavid Schultz modifier = MOD_CHAR;
102cc4c35b9SDavid Schultz } else {
103cc4c35b9SDavid Schultz modifier = MOD_SHORT;
104cc4c35b9SDavid Schultz }
105cc4c35b9SDavid Schultz break;
106cc4c35b9SDavid Schultz case 'j':
107cc4c35b9SDavid Schultz f++;
108cc4c35b9SDavid Schultz modifier = MOD_INTMAXT;
1093d090549SKris Kennaway break;
1103d090549SKris Kennaway case 'l':
1113d090549SKris Kennaway f++;
1123d090549SKris Kennaway if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
1133d090549SKris Kennaway if (*f == 'l') {
1143d090549SKris Kennaway f++;
115cc4c35b9SDavid Schultz modifier = MOD_QUAD;
1163d090549SKris Kennaway } else {
117cc4c35b9SDavid Schultz modifier = MOD_LONG;
1183d090549SKris Kennaway }
1193d090549SKris Kennaway break;
1203d090549SKris Kennaway case 'q':
1213d090549SKris Kennaway f++;
122cc4c35b9SDavid Schultz modifier = MOD_QUAD;
1233d090549SKris Kennaway break;
124ec045e41SDavid Schultz case 't':
125ec045e41SDavid Schultz f++;
126cc4c35b9SDavid Schultz modifier = MOD_PTRDIFFT;
127ec045e41SDavid Schultz break;
128ec045e41SDavid Schultz case 'z':
129ec045e41SDavid Schultz f++;
130cc4c35b9SDavid Schultz modifier = MOD_SIZET;
131ec045e41SDavid Schultz break;
1323d090549SKris Kennaway case 'L':
1333d090549SKris Kennaway f++;
134cc4c35b9SDavid Schultz modifier = MOD_LONGDOUBLE;
1353d090549SKris Kennaway break;
1363d090549SKris Kennaway default:
137cc4c35b9SDavid Schultz modifier = MOD_NONE;
1383d090549SKris Kennaway break;
1393d090549SKris Kennaway }
1403d090549SKris Kennaway if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
1413d090549SKris Kennaway if (strchr("diouxX", *f)) {
142cc4c35b9SDavid Schultz switch (modifier) {
143cc4c35b9SDavid Schultz case MOD_LONG:
1443d090549SKris Kennaway RETURN(pf,f,FMTCHECK_LONG);
145cc4c35b9SDavid Schultz case MOD_QUAD:
1463d090549SKris Kennaway RETURN(pf,f,FMTCHECK_QUAD);
147cc4c35b9SDavid Schultz case MOD_INTMAXT:
148cc4c35b9SDavid Schultz RETURN(pf,f,FMTCHECK_INTMAXT);
149cc4c35b9SDavid Schultz case MOD_PTRDIFFT:
150ec045e41SDavid Schultz RETURN(pf,f,FMTCHECK_PTRDIFFT);
151cc4c35b9SDavid Schultz case MOD_SIZET:
152ec045e41SDavid Schultz RETURN(pf,f,FMTCHECK_SIZET);
153cc4c35b9SDavid Schultz case MOD_CHAR:
154cc4c35b9SDavid Schultz case MOD_SHORT:
155cc4c35b9SDavid Schultz case MOD_NONE:
1563d090549SKris Kennaway RETURN(pf,f,FMTCHECK_INT);
157cc4c35b9SDavid Schultz default:
158cc4c35b9SDavid Schultz RETURN(pf,f,FMTCHECK_UNKNOWN);
159cc4c35b9SDavid Schultz }
1603d090549SKris Kennaway }
1613d090549SKris Kennaway if (*f == 'n') {
162cc4c35b9SDavid Schultz switch (modifier) {
163cc4c35b9SDavid Schultz case MOD_CHAR:
164cc4c35b9SDavid Schultz RETURN(pf,f,FMTCHECK_CHARPOINTER);
165cc4c35b9SDavid Schultz case MOD_SHORT:
1663d090549SKris Kennaway RETURN(pf,f,FMTCHECK_SHORTPOINTER);
167cc4c35b9SDavid Schultz case MOD_LONG:
1683d090549SKris Kennaway RETURN(pf,f,FMTCHECK_LONGPOINTER);
169cc4c35b9SDavid Schultz case MOD_QUAD:
1703d090549SKris Kennaway RETURN(pf,f,FMTCHECK_QUADPOINTER);
171cc4c35b9SDavid Schultz case MOD_INTMAXT:
172cc4c35b9SDavid Schultz RETURN(pf,f,FMTCHECK_INTMAXTPOINTER);
173cc4c35b9SDavid Schultz case MOD_PTRDIFFT:
174ec045e41SDavid Schultz RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
175cc4c35b9SDavid Schultz case MOD_SIZET:
176ec045e41SDavid Schultz RETURN(pf,f,FMTCHECK_SIZETPOINTER);
177cc4c35b9SDavid Schultz case MOD_NONE:
1783d090549SKris Kennaway RETURN(pf,f,FMTCHECK_INTPOINTER);
179cc4c35b9SDavid Schultz default:
180cc4c35b9SDavid Schultz RETURN(pf,f,FMTCHECK_UNKNOWN);
181cc4c35b9SDavid Schultz }
1823d090549SKris Kennaway }
1833d090549SKris Kennaway if (strchr("DOU", *f)) {
184cc4c35b9SDavid Schultz if (modifier != MOD_NONE)
1853d090549SKris Kennaway RETURN(pf,f,FMTCHECK_UNKNOWN);
1863d090549SKris Kennaway RETURN(pf,f,FMTCHECK_LONG);
1873d090549SKris Kennaway }
18838d17374SDavid Schultz #ifndef NO_FLOATING_POINT
189ec045e41SDavid Schultz if (strchr("aAeEfFgG", *f)) {
190cc4c35b9SDavid Schultz switch (modifier) {
191cc4c35b9SDavid Schultz case MOD_LONGDOUBLE:
1923d090549SKris Kennaway RETURN(pf,f,FMTCHECK_LONGDOUBLE);
193cc4c35b9SDavid Schultz case MOD_LONG:
194cc4c35b9SDavid Schultz case MOD_NONE:
1953d090549SKris Kennaway RETURN(pf,f,FMTCHECK_DOUBLE);
196cc4c35b9SDavid Schultz default:
197cc4c35b9SDavid Schultz RETURN(pf,f,FMTCHECK_UNKNOWN);
198cc4c35b9SDavid Schultz }
1993d090549SKris Kennaway }
20038d17374SDavid Schultz #endif
2013d090549SKris Kennaway if (*f == 'c') {
202cc4c35b9SDavid Schultz switch (modifier) {
203cc4c35b9SDavid Schultz case MOD_LONG:
204cc4c35b9SDavid Schultz RETURN(pf,f,FMTCHECK_WINTT);
205cc4c35b9SDavid Schultz case MOD_NONE:
2063d090549SKris Kennaway RETURN(pf,f,FMTCHECK_INT);
207cc4c35b9SDavid Schultz default:
208cc4c35b9SDavid Schultz RETURN(pf,f,FMTCHECK_UNKNOWN);
209cc4c35b9SDavid Schultz }
210cc4c35b9SDavid Schultz }
211cc4c35b9SDavid Schultz if (*f == 'C') {
212cc4c35b9SDavid Schultz if (modifier != MOD_NONE)
213cc4c35b9SDavid Schultz RETURN(pf,f,FMTCHECK_UNKNOWN);
214cc4c35b9SDavid Schultz RETURN(pf,f,FMTCHECK_WINTT);
2153d090549SKris Kennaway }
2163d090549SKris Kennaway if (*f == 's') {
217cc4c35b9SDavid Schultz switch (modifier) {
218cc4c35b9SDavid Schultz case MOD_LONG:
219cc4c35b9SDavid Schultz RETURN(pf,f,FMTCHECK_WSTRING);
220cc4c35b9SDavid Schultz case MOD_NONE:
2213d090549SKris Kennaway RETURN(pf,f,FMTCHECK_STRING);
222cc4c35b9SDavid Schultz default:
223cc4c35b9SDavid Schultz RETURN(pf,f,FMTCHECK_UNKNOWN);
224cc4c35b9SDavid Schultz }
225cc4c35b9SDavid Schultz }
226cc4c35b9SDavid Schultz if (*f == 'S') {
227cc4c35b9SDavid Schultz if (modifier != MOD_NONE)
228cc4c35b9SDavid Schultz RETURN(pf,f,FMTCHECK_UNKNOWN);
229cc4c35b9SDavid Schultz RETURN(pf,f,FMTCHECK_WSTRING);
2303d090549SKris Kennaway }
2313d090549SKris Kennaway if (*f == 'p') {
232cc4c35b9SDavid Schultz if (modifier != MOD_NONE)
2333d090549SKris Kennaway RETURN(pf,f,FMTCHECK_UNKNOWN);
2343d090549SKris Kennaway RETURN(pf,f,FMTCHECK_LONG);
2353d090549SKris Kennaway }
2363d090549SKris Kennaway RETURN(pf,f,FMTCHECK_UNKNOWN);
2373d090549SKris Kennaway /*NOTREACHED*/
2383d090549SKris Kennaway }
2393d090549SKris Kennaway
2403d090549SKris Kennaway static EFT
get_next_format_from_width(const char ** pf)2413d090549SKris Kennaway get_next_format_from_width(const char **pf)
2423d090549SKris Kennaway {
2433d090549SKris Kennaway const char *f;
2443d090549SKris Kennaway
2453d090549SKris Kennaway f = *pf;
2463d090549SKris Kennaway if (*f == '.') {
2473d090549SKris Kennaway f++;
2483d090549SKris Kennaway if (*f == '*') {
2493d090549SKris Kennaway RETURN(pf,f,FMTCHECK_PRECISION);
2503d090549SKris Kennaway }
2513d090549SKris Kennaway /* eat any precision (empty is allowed) */
2523d090549SKris Kennaway while (isdigit(*f)) f++;
2533d090549SKris Kennaway if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
2543d090549SKris Kennaway }
2553d090549SKris Kennaway RETURN(pf,f,get_next_format_from_precision(pf));
2563d090549SKris Kennaway /*NOTREACHED*/
2573d090549SKris Kennaway }
2583d090549SKris Kennaway
2593d090549SKris Kennaway static EFT
get_next_format(const char ** pf,EFT eft)2603d090549SKris Kennaway get_next_format(const char **pf, EFT eft)
2613d090549SKris Kennaway {
2623d090549SKris Kennaway int infmt;
2633d090549SKris Kennaway const char *f;
2643d090549SKris Kennaway
2653d090549SKris Kennaway if (eft == FMTCHECK_WIDTH) {
2663d090549SKris Kennaway (*pf)++;
2673d090549SKris Kennaway return get_next_format_from_width(pf);
2683d090549SKris Kennaway } else if (eft == FMTCHECK_PRECISION) {
2693d090549SKris Kennaway (*pf)++;
2703d090549SKris Kennaway return get_next_format_from_precision(pf);
2713d090549SKris Kennaway }
2723d090549SKris Kennaway
2733d090549SKris Kennaway f = *pf;
2743d090549SKris Kennaway infmt = 0;
2753d090549SKris Kennaway while (!infmt) {
2763d090549SKris Kennaway f = strchr(f, '%');
2773d090549SKris Kennaway if (f == NULL)
2783d090549SKris Kennaway RETURN(pf,f,FMTCHECK_DONE);
2793d090549SKris Kennaway f++;
2803d090549SKris Kennaway if (!*f)
2813d090549SKris Kennaway RETURN(pf,f,FMTCHECK_UNKNOWN);
2823d090549SKris Kennaway if (*f != '%')
2833d090549SKris Kennaway infmt = 1;
2843d090549SKris Kennaway else
2853d090549SKris Kennaway f++;
2863d090549SKris Kennaway }
2873d090549SKris Kennaway
2883d090549SKris Kennaway /* Eat any of the flags */
2893edb8f41SDavid Schultz while (*f && (strchr("#'0- +", *f)))
2903d090549SKris Kennaway f++;
2913d090549SKris Kennaway
2923d090549SKris Kennaway if (*f == '*') {
2933d090549SKris Kennaway RETURN(pf,f,FMTCHECK_WIDTH);
2943d090549SKris Kennaway }
2953d090549SKris Kennaway /* eat any width */
2963d090549SKris Kennaway while (isdigit(*f)) f++;
2973d090549SKris Kennaway if (!*f) {
2983d090549SKris Kennaway RETURN(pf,f,FMTCHECK_UNKNOWN);
2993d090549SKris Kennaway }
3003d090549SKris Kennaway
3013d090549SKris Kennaway RETURN(pf,f,get_next_format_from_width(pf));
3023d090549SKris Kennaway /*NOTREACHED*/
3033d090549SKris Kennaway }
3043d090549SKris Kennaway
305eb4bd20cSXin LI const char *
__fmtcheck(const char * f1,const char * f2)30653154da0SDaniel Eischen __fmtcheck(const char *f1, const char *f2)
3073d090549SKris Kennaway {
3083d090549SKris Kennaway const char *f1p, *f2p;
3093d090549SKris Kennaway EFT f1t, f2t;
3103d090549SKris Kennaway
3113d090549SKris Kennaway if (!f1) return f2;
3123d090549SKris Kennaway
3133d090549SKris Kennaway f1p = f1;
3143d090549SKris Kennaway f1t = FMTCHECK_START;
3153d090549SKris Kennaway f2p = f2;
3163d090549SKris Kennaway f2t = FMTCHECK_START;
3173d090549SKris Kennaway while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
3183d090549SKris Kennaway if (f1t == FMTCHECK_UNKNOWN)
3193d090549SKris Kennaway return f2;
3203d090549SKris Kennaway f2t = get_next_format(&f2p, f2t);
3213d090549SKris Kennaway if (f1t != f2t)
3223d090549SKris Kennaway return f2;
3233d090549SKris Kennaway }
3243d090549SKris Kennaway return f1;
3253d090549SKris Kennaway }
326