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