fmtcheck.c revision 1.13 1 /* $NetBSD: fmtcheck.c,v 1.13 2017/12/06 12:30:27 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.13 2017/12/06 12:30:27 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_LONG,
51 FMTCHECK_QUAD,
52 FMTCHECK_PTRDIFFT,
53 FMTCHECK_SIZET,
54 FMTCHECK_POINTER,
55 FMTCHECK_SHORTPOINTER,
56 FMTCHECK_INTPOINTER,
57 FMTCHECK_LONGPOINTER,
58 FMTCHECK_QUADPOINTER,
59 FMTCHECK_PTRDIFFTPOINTER,
60 FMTCHECK_SIZETPOINTER,
61 FMTCHECK_DOUBLE,
62 FMTCHECK_LONGDOUBLE,
63 FMTCHECK_STRING,
64 FMTCHECK_WIDTH,
65 FMTCHECK_PRECISION,
66 FMTCHECK_DONE,
67 FMTCHECK_UNKNOWN
68 };
69 typedef enum __e_fmtcheck_types EFT;
70
71 #define RETURN(pf,f,r) do { \
72 *(pf) = (f); \
73 return r; \
74 } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
75
76 static EFT
77 get_next_format_from_precision(const char **pf)
78 {
79 int sh, lg, quad, longdouble, ptrdifft, sizet;
80 const char *f;
81
82 sh = lg = quad = longdouble = ptrdifft = sizet = 0;
83
84 f = *pf;
85 switch (*f) {
86 case 'h':
87 f++;
88 sh = 1;
89 break;
90 case 'l':
91 f++;
92 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
93 if (*f == 'l') {
94 f++;
95 quad = 1;
96 } else {
97 lg = 1;
98 }
99 break;
100 case 'q':
101 f++;
102 quad = 1;
103 break;
104 case 't':
105 f++;
106 ptrdifft = 1;
107 break;
108 case 'z':
109 f++;
110 sizet = 1;
111 break;
112 case 'L':
113 f++;
114 longdouble = 1;
115 break;
116 #ifdef WIN32
117 case 'I':
118 f++;
119 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
120 if (*f == '3' && f[1] == '2') {
121 f += 2;
122 } else if (*f == '6' && f[1] == '4') {
123 f += 2;
124 quad = 1;
125 }
126 #ifdef _WIN64
127 else {
128 quad = 1;
129 }
130 #endif
131 break;
132 #endif
133 default:
134 break;
135 }
136 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
137 if (strchr("diouxX", *f)) {
138 if (longdouble)
139 RETURN(pf,f,FMTCHECK_UNKNOWN);
140 if (lg)
141 RETURN(pf,f,FMTCHECK_LONG);
142 if (quad)
143 RETURN(pf,f,FMTCHECK_QUAD);
144 if (ptrdifft)
145 RETURN(pf,f,FMTCHECK_PTRDIFFT);
146 if (sizet)
147 RETURN(pf,f,FMTCHECK_SIZET);
148 RETURN(pf,f,FMTCHECK_INT);
149 }
150 if (*f == 'n') {
151 if (longdouble)
152 RETURN(pf,f,FMTCHECK_UNKNOWN);
153 if (sh)
154 RETURN(pf,f,FMTCHECK_SHORTPOINTER);
155 if (lg)
156 RETURN(pf,f,FMTCHECK_LONGPOINTER);
157 if (quad)
158 RETURN(pf,f,FMTCHECK_QUADPOINTER);
159 if (ptrdifft)
160 RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
161 if (sizet)
162 RETURN(pf,f,FMTCHECK_SIZETPOINTER);
163 RETURN(pf,f,FMTCHECK_INTPOINTER);
164 }
165 if (strchr("DOU", *f)) {
166 if (sh + lg + quad + longdouble + ptrdifft + sizet)
167 RETURN(pf,f,FMTCHECK_UNKNOWN);
168 RETURN(pf,f,FMTCHECK_LONG);
169 }
170 if (strchr("aAeEfFgG", *f)) {
171 if (longdouble)
172 RETURN(pf,f,FMTCHECK_LONGDOUBLE);
173 if (sh + lg + quad + ptrdifft + sizet)
174 RETURN(pf,f,FMTCHECK_UNKNOWN);
175 RETURN(pf,f,FMTCHECK_DOUBLE);
176 }
177 if (*f == 'c') {
178 if (sh + lg + quad + longdouble + ptrdifft + sizet)
179 RETURN(pf,f,FMTCHECK_UNKNOWN);
180 RETURN(pf,f,FMTCHECK_INT);
181 }
182 if (*f == 's') {
183 if (sh + lg + quad + longdouble + ptrdifft + sizet)
184 RETURN(pf,f,FMTCHECK_UNKNOWN);
185 RETURN(pf,f,FMTCHECK_STRING);
186 }
187 if (*f == 'p') {
188 if (sh + lg + quad + longdouble + ptrdifft + sizet)
189 RETURN(pf,f,FMTCHECK_UNKNOWN);
190 RETURN(pf,f,FMTCHECK_POINTER);
191 }
192 RETURN(pf,f,FMTCHECK_UNKNOWN);
193 /*NOTREACHED*/
194 }
195
196 static EFT
197 get_next_format_from_width(const char **pf)
198 {
199 const char *f;
200
201 f = *pf;
202 if (*f == '.') {
203 f++;
204 if (*f == '*') {
205 RETURN(pf,f,FMTCHECK_PRECISION);
206 }
207 /* eat any precision (empty is allowed) */
208 while (isdigit((unsigned char)*f)) f++;
209 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
210 }
211 RETURN(pf,f,get_next_format_from_precision(pf));
212 /*NOTREACHED*/
213 }
214
215 static EFT
216 get_next_format(const char **pf, EFT eft)
217 {
218 int infmt;
219 const char *f;
220
221 if (eft == FMTCHECK_WIDTH) {
222 (*pf)++;
223 return get_next_format_from_width(pf);
224 } else if (eft == FMTCHECK_PRECISION) {
225 (*pf)++;
226 return get_next_format_from_precision(pf);
227 }
228
229 f = *pf;
230 infmt = 0;
231 while (!infmt) {
232 f = strchr(f, '%');
233 if (f == NULL)
234 RETURN(pf,f,FMTCHECK_DONE);
235 f++;
236 if (!*f)
237 RETURN(pf,f,FMTCHECK_UNKNOWN);
238 if (*f != '%')
239 infmt = 1;
240 else
241 f++;
242 }
243
244 /* Eat any of the flags */
245 while (*f && (strchr("#'0- +", *f)))
246 f++;
247
248 if (*f == '*') {
249 RETURN(pf,f,FMTCHECK_WIDTH);
250 }
251 /* eat any width */
252 while (isdigit((unsigned char)*f)) f++;
253 if (!*f) {
254 RETURN(pf,f,FMTCHECK_UNKNOWN);
255 }
256
257 RETURN(pf,f,get_next_format_from_width(pf));
258 /*NOTREACHED*/
259 }
260
261 const char *
262 fmtcheck(const char *f1, const char *f2)
263 {
264 const char *f1p, *f2p;
265 EFT f1t, f2t;
266
267 if (!f1) return f2;
268
269 f1p = f1;
270 f1t = FMTCHECK_START;
271 f2p = f2;
272 f2t = FMTCHECK_START;
273 while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
274 if (f1t == FMTCHECK_UNKNOWN)
275 return f2;
276 f2t = get_next_format(&f2p, f2t);
277 if (f1t != f2t)
278 return f2;
279 }
280 if (get_next_format(&f2p, f2t) != FMTCHECK_DONE)
281 return f2;
282 else
283 return f1;
284 }
285