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