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