1 /* $NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp $ */
2
3 /*-
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * This code was contributed to The NetBSD Foundation by Allen Briggs.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <ctype.h>
36
37 __weak_reference(__fmtcheck, fmtcheck);
38 const char * __fmtcheck(const char *, const char *);
39
40 enum __e_fmtcheck_types {
41 FMTCHECK_START,
42 FMTCHECK_SHORT,
43 FMTCHECK_INT,
44 FMTCHECK_WINTT,
45 FMTCHECK_LONG,
46 FMTCHECK_QUAD,
47 FMTCHECK_INTMAXT,
48 FMTCHECK_PTRDIFFT,
49 FMTCHECK_SIZET,
50 FMTCHECK_CHARPOINTER,
51 FMTCHECK_SHORTPOINTER,
52 FMTCHECK_INTPOINTER,
53 FMTCHECK_LONGPOINTER,
54 FMTCHECK_QUADPOINTER,
55 FMTCHECK_INTMAXTPOINTER,
56 FMTCHECK_PTRDIFFTPOINTER,
57 FMTCHECK_SIZETPOINTER,
58 FMTCHECK_DOUBLE,
59 FMTCHECK_LONGDOUBLE,
60 FMTCHECK_STRING,
61 FMTCHECK_WSTRING,
62 FMTCHECK_WIDTH,
63 FMTCHECK_PRECISION,
64 FMTCHECK_DONE,
65 FMTCHECK_UNKNOWN
66 };
67 typedef enum __e_fmtcheck_types EFT;
68
69 enum e_modifier {
70 MOD_NONE,
71 MOD_CHAR,
72 MOD_SHORT,
73 MOD_LONG,
74 MOD_QUAD,
75 MOD_INTMAXT,
76 MOD_LONGDOUBLE,
77 MOD_PTRDIFFT,
78 MOD_SIZET,
79 };
80
81 #define RETURN(pf,f,r) do { \
82 *(pf) = (f); \
83 return r; \
84 } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
85
86 static EFT
get_next_format_from_precision(const char ** pf)87 get_next_format_from_precision(const char **pf)
88 {
89 enum e_modifier modifier;
90 const char *f;
91
92 f = *pf;
93 switch (*f) {
94 case 'h':
95 f++;
96 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
97 if (*f == 'h') {
98 f++;
99 modifier = MOD_CHAR;
100 } else {
101 modifier = MOD_SHORT;
102 }
103 break;
104 case 'j':
105 f++;
106 modifier = MOD_INTMAXT;
107 break;
108 case 'l':
109 f++;
110 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
111 if (*f == 'l') {
112 f++;
113 modifier = MOD_QUAD;
114 } else {
115 modifier = MOD_LONG;
116 }
117 break;
118 case 'q':
119 f++;
120 modifier = MOD_QUAD;
121 break;
122 case 't':
123 f++;
124 modifier = MOD_PTRDIFFT;
125 break;
126 case 'z':
127 f++;
128 modifier = MOD_SIZET;
129 break;
130 case 'L':
131 f++;
132 modifier = MOD_LONGDOUBLE;
133 break;
134 default:
135 modifier = MOD_NONE;
136 break;
137 }
138 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
139 if (strchr("diouxX", *f)) {
140 switch (modifier) {
141 case MOD_LONG:
142 RETURN(pf,f,FMTCHECK_LONG);
143 case MOD_QUAD:
144 RETURN(pf,f,FMTCHECK_QUAD);
145 case MOD_INTMAXT:
146 RETURN(pf,f,FMTCHECK_INTMAXT);
147 case MOD_PTRDIFFT:
148 RETURN(pf,f,FMTCHECK_PTRDIFFT);
149 case MOD_SIZET:
150 RETURN(pf,f,FMTCHECK_SIZET);
151 case MOD_CHAR:
152 case MOD_SHORT:
153 case MOD_NONE:
154 RETURN(pf,f,FMTCHECK_INT);
155 default:
156 RETURN(pf,f,FMTCHECK_UNKNOWN);
157 }
158 }
159 if (*f == 'n') {
160 switch (modifier) {
161 case MOD_CHAR:
162 RETURN(pf,f,FMTCHECK_CHARPOINTER);
163 case MOD_SHORT:
164 RETURN(pf,f,FMTCHECK_SHORTPOINTER);
165 case MOD_LONG:
166 RETURN(pf,f,FMTCHECK_LONGPOINTER);
167 case MOD_QUAD:
168 RETURN(pf,f,FMTCHECK_QUADPOINTER);
169 case MOD_INTMAXT:
170 RETURN(pf,f,FMTCHECK_INTMAXTPOINTER);
171 case MOD_PTRDIFFT:
172 RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
173 case MOD_SIZET:
174 RETURN(pf,f,FMTCHECK_SIZETPOINTER);
175 case MOD_NONE:
176 RETURN(pf,f,FMTCHECK_INTPOINTER);
177 default:
178 RETURN(pf,f,FMTCHECK_UNKNOWN);
179 }
180 }
181 if (strchr("DOU", *f)) {
182 if (modifier != MOD_NONE)
183 RETURN(pf,f,FMTCHECK_UNKNOWN);
184 RETURN(pf,f,FMTCHECK_LONG);
185 }
186 if (strchr("aAeEfFgG", *f)) {
187 switch (modifier) {
188 case MOD_LONGDOUBLE:
189 RETURN(pf,f,FMTCHECK_LONGDOUBLE);
190 case MOD_LONG:
191 case MOD_NONE:
192 RETURN(pf,f,FMTCHECK_DOUBLE);
193 default:
194 RETURN(pf,f,FMTCHECK_UNKNOWN);
195 }
196 }
197 if (*f == 'c') {
198 switch (modifier) {
199 case MOD_LONG:
200 RETURN(pf,f,FMTCHECK_WINTT);
201 case MOD_NONE:
202 RETURN(pf,f,FMTCHECK_INT);
203 default:
204 RETURN(pf,f,FMTCHECK_UNKNOWN);
205 }
206 }
207 if (*f == 'C') {
208 if (modifier != MOD_NONE)
209 RETURN(pf,f,FMTCHECK_UNKNOWN);
210 RETURN(pf,f,FMTCHECK_WINTT);
211 }
212 if (*f == 's') {
213 switch (modifier) {
214 case MOD_LONG:
215 RETURN(pf,f,FMTCHECK_WSTRING);
216 case MOD_NONE:
217 RETURN(pf,f,FMTCHECK_STRING);
218 default:
219 RETURN(pf,f,FMTCHECK_UNKNOWN);
220 }
221 }
222 if (*f == 'S') {
223 if (modifier != MOD_NONE)
224 RETURN(pf,f,FMTCHECK_UNKNOWN);
225 RETURN(pf,f,FMTCHECK_WSTRING);
226 }
227 if (*f == 'p') {
228 if (modifier != MOD_NONE)
229 RETURN(pf,f,FMTCHECK_UNKNOWN);
230 RETURN(pf,f,FMTCHECK_LONG);
231 }
232 RETURN(pf,f,FMTCHECK_UNKNOWN);
233 /*NOTREACHED*/
234 }
235
236 static EFT
get_next_format_from_width(const char ** pf)237 get_next_format_from_width(const char **pf)
238 {
239 const char *f;
240
241 f = *pf;
242 if (*f == '.') {
243 f++;
244 if (*f == '*') {
245 RETURN(pf,f,FMTCHECK_PRECISION);
246 }
247 /* eat any precision (empty is allowed) */
248 while (isdigit(*f)) f++;
249 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
250 }
251 RETURN(pf,f,get_next_format_from_precision(pf));
252 /*NOTREACHED*/
253 }
254
255 static EFT
get_next_format(const char ** pf,EFT eft)256 get_next_format(const char **pf, EFT eft)
257 {
258 int infmt;
259 const char *f;
260
261 if (eft == FMTCHECK_WIDTH) {
262 (*pf)++;
263 return get_next_format_from_width(pf);
264 } else if (eft == FMTCHECK_PRECISION) {
265 (*pf)++;
266 return get_next_format_from_precision(pf);
267 }
268
269 f = *pf;
270 infmt = 0;
271 while (!infmt) {
272 f = strchr(f, '%');
273 if (f == NULL)
274 RETURN(pf,f,FMTCHECK_DONE);
275 f++;
276 if (!*f)
277 RETURN(pf,f,FMTCHECK_UNKNOWN);
278 if (*f != '%')
279 infmt = 1;
280 else
281 f++;
282 }
283
284 /* Eat any of the flags */
285 while (*f && (strchr("#'0- +", *f)))
286 f++;
287
288 if (*f == '*') {
289 RETURN(pf,f,FMTCHECK_WIDTH);
290 }
291 /* eat any width */
292 while (isdigit(*f)) f++;
293 if (!*f) {
294 RETURN(pf,f,FMTCHECK_UNKNOWN);
295 }
296
297 RETURN(pf,f,get_next_format_from_width(pf));
298 /*NOTREACHED*/
299 }
300
301 const char *
__fmtcheck(const char * f1,const char * f2)302 __fmtcheck(const char *f1, const char *f2)
303 {
304 const char *f1p, *f2p;
305 EFT f1t, f2t;
306
307 if (!f1) return f2;
308
309 f1p = f1;
310 f1t = FMTCHECK_START;
311 f2p = f2;
312 f2t = FMTCHECK_START;
313 while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
314 if (f1t == FMTCHECK_UNKNOWN)
315 return f2;
316 f2t = get_next_format(&f2p, f2t);
317 if (f1t != f2t)
318 return f2;
319 }
320 return f1;
321 }
322