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