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