1 /* $NetBSD: fmtcheck.c,v 1.1.1.6 2023/08/18 18:36:49 christos Exp $ */
2
3 /* NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp */
4
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 "file.h"
34 #ifndef lint
35 #if 0
36 FILE_RCSID("@(#)$File: fmtcheck.c,v 1.6 2022/09/24 20:30:13 christos Exp $")
37 #else
38 __RCSID("$NetBSD: fmtcheck.c,v 1.1.1.6 2023/08/18 18:36:49 christos Exp $");
39 #endif
40 #endif /* lint */
41
42 #include <stdio.h>
43 #include <string.h>
44 #include <ctype.h>
45
46 enum __e_fmtcheck_types {
47 FMTCHECK_START,
48 FMTCHECK_SHORT,
49 FMTCHECK_INT,
50 FMTCHECK_LONG,
51 FMTCHECK_QUAD,
52 FMTCHECK_SHORTPOINTER,
53 FMTCHECK_INTPOINTER,
54 FMTCHECK_LONGPOINTER,
55 FMTCHECK_QUADPOINTER,
56 FMTCHECK_DOUBLE,
57 FMTCHECK_LONGDOUBLE,
58 FMTCHECK_STRING,
59 FMTCHECK_WIDTH,
60 FMTCHECK_PRECISION,
61 FMTCHECK_DONE,
62 FMTCHECK_UNKNOWN
63 };
64 typedef enum __e_fmtcheck_types EFT;
65
66 #define RETURN(pf,f,r) do { \
67 *(pf) = (f); \
68 return r; \
69 } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
70
71 static EFT
get_next_format_from_precision(const char ** pf)72 get_next_format_from_precision(const char **pf)
73 {
74 int sh, lg, quad, longdouble;
75 const char *f;
76
77 sh = lg = quad = longdouble = 0;
78
79 f = *pf;
80 switch (*f) {
81 case 'h':
82 f++;
83 sh = 1;
84 break;
85 case 'l':
86 f++;
87 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
88 if (*f == 'l') {
89 f++;
90 quad = 1;
91 } else {
92 lg = 1;
93 }
94 break;
95 case 'q':
96 f++;
97 quad = 1;
98 break;
99 case 'L':
100 f++;
101 longdouble = 1;
102 break;
103 #ifdef WIN32
104 case 'I':
105 f++;
106 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
107 if (*f == '3' && f[1] == '2') {
108 f += 2;
109 } else if (*f == '6' && f[1] == '4') {
110 f += 2;
111 quad = 1;
112 }
113 #ifdef _WIN64
114 else {
115 quad = 1;
116 }
117 #endif
118 break;
119 #endif
120 default:
121 break;
122 }
123 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
124 if (strchr("diouxX", *f)) {
125 if (longdouble)
126 RETURN(pf,f,FMTCHECK_UNKNOWN);
127 if (lg)
128 RETURN(pf,f,FMTCHECK_LONG);
129 if (quad)
130 RETURN(pf,f,FMTCHECK_QUAD);
131 RETURN(pf,f,FMTCHECK_INT);
132 }
133 if (*f == 'n') {
134 if (longdouble)
135 RETURN(pf,f,FMTCHECK_UNKNOWN);
136 if (sh)
137 RETURN(pf,f,FMTCHECK_SHORTPOINTER);
138 if (lg)
139 RETURN(pf,f,FMTCHECK_LONGPOINTER);
140 if (quad)
141 RETURN(pf,f,FMTCHECK_QUADPOINTER);
142 RETURN(pf,f,FMTCHECK_INTPOINTER);
143 }
144 if (strchr("DOU", *f)) {
145 if (sh + lg + quad + longdouble)
146 RETURN(pf,f,FMTCHECK_UNKNOWN);
147 RETURN(pf,f,FMTCHECK_LONG);
148 }
149 if (strchr("eEfg", *f)) {
150 if (longdouble)
151 RETURN(pf,f,FMTCHECK_LONGDOUBLE);
152 if (sh + lg + quad)
153 RETURN(pf,f,FMTCHECK_UNKNOWN);
154 RETURN(pf,f,FMTCHECK_DOUBLE);
155 }
156 if (*f == 'c') {
157 if (sh + lg + quad + longdouble)
158 RETURN(pf,f,FMTCHECK_UNKNOWN);
159 RETURN(pf,f,FMTCHECK_INT);
160 }
161 if (*f == 's') {
162 if (sh + lg + quad + longdouble)
163 RETURN(pf,f,FMTCHECK_UNKNOWN);
164 RETURN(pf,f,FMTCHECK_STRING);
165 }
166 if (*f == 'p') {
167 if (sh + lg + quad + longdouble)
168 RETURN(pf,f,FMTCHECK_UNKNOWN);
169 RETURN(pf,f,FMTCHECK_LONG);
170 }
171 RETURN(pf,f,FMTCHECK_UNKNOWN);
172 /*NOTREACHED*/
173 }
174
175 static EFT
get_next_format_from_width(const char ** pf)176 get_next_format_from_width(const char **pf)
177 {
178 const char *f;
179
180 f = *pf;
181 if (*f == '.') {
182 f++;
183 if (*f == '*') {
184 RETURN(pf,f,FMTCHECK_PRECISION);
185 }
186 /* eat any precision (empty is allowed) */
187 while (isdigit((unsigned char)*f)) f++;
188 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
189 }
190 RETURN(pf,f,get_next_format_from_precision(pf));
191 /*NOTREACHED*/
192 }
193
194 static EFT
get_next_format(const char ** pf,EFT eft)195 get_next_format(const char **pf, EFT eft)
196 {
197 int infmt;
198 const char *f;
199
200 if (eft == FMTCHECK_WIDTH) {
201 (*pf)++;
202 return get_next_format_from_width(pf);
203 } else if (eft == FMTCHECK_PRECISION) {
204 (*pf)++;
205 return get_next_format_from_precision(pf);
206 }
207
208 f = *pf;
209 infmt = 0;
210 while (!infmt) {
211 f = strchr(f, '%');
212 if (f == NULL)
213 RETURN(pf,f,FMTCHECK_DONE);
214 f++;
215 if (!*f)
216 RETURN(pf,f,FMTCHECK_UNKNOWN);
217 if (*f != '%')
218 infmt = 1;
219 else
220 f++;
221 }
222
223 /* Eat any of the flags */
224 while (*f && (strchr("#0- +", *f)))
225 f++;
226
227 if (*f == '*') {
228 RETURN(pf,f,FMTCHECK_WIDTH);
229 }
230 /* eat any width */
231 while (isdigit((unsigned char)*f)) f++;
232 if (!*f) {
233 RETURN(pf,f,FMTCHECK_UNKNOWN);
234 }
235
236 RETURN(pf,f,get_next_format_from_width(pf));
237 /*NOTREACHED*/
238 }
239
240 const char *
fmtcheck(const char * f1,const char * f2)241 fmtcheck(const char *f1, const char *f2)
242 {
243 const char *f1p, *f2p;
244 EFT f1t, f2t;
245
246 if (!f1) return f2;
247
248 f1p = f1;
249 f1t = FMTCHECK_START;
250 f2p = f2;
251 f2t = FMTCHECK_START;
252 while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
253 if (f1t == FMTCHECK_UNKNOWN)
254 return f2;
255 f2t = get_next_format(&f2p, f2t);
256 if (f1t != f2t)
257 return f2;
258 }
259 return f1;
260 }
261