fmtcheck.c revision 1.1 1 /* $NetBSD: fmtcheck.c,v 1.1 2000/10/20 18:46:10 briggs 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 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the NetBSD
20 * Foundation, Inc. and its contributors.
21 * 4. Neither the name of The NetBSD Foundation nor the names of its
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include <sys/cdefs.h>
39 #if defined(LIBC_SCCS) && !defined(lint)
40 __RCSID("$NetBSD: fmtcheck.c,v 1.1 2000/10/20 18:46:10 briggs Exp $");
41 #endif
42
43 #include "namespace.h"
44
45 #include <stdlib.h>
46 #include <string.h>
47 #include <ctype.h>
48
49 #ifdef __weak_alias
50 __weak_alias(fmtcheck,__fmtcheck)
51 #endif
52
53 enum __e_fmtcheck_types {
54 FMTCHECK_START,
55 FMTCHECK_SHORT,
56 FMTCHECK_INT,
57 FMTCHECK_LONG,
58 FMTCHECK_QUAD,
59 FMTCHECK_SHORTPOINTER,
60 FMTCHECK_INTPOINTER,
61 FMTCHECK_LONGPOINTER,
62 FMTCHECK_QUADPOINTER,
63 FMTCHECK_DOUBLE,
64 FMTCHECK_LONGDOUBLE,
65 FMTCHECK_STRING,
66 FMTCHECK_WIDTH,
67 FMTCHECK_PRECISION,
68 FMTCHECK_DONE,
69 FMTCHECK_UNKNOWN
70 };
71 typedef enum __e_fmtcheck_types EFT;
72
73 #define RETURN(pf,f,r) do { \
74 *(pf) = (f); \
75 return r; \
76 } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
77
78 static EFT
79 get_next_format_from_precision(const char **pf)
80 {
81 int sh, lg, quad, longdouble;
82 const char *f;
83
84 sh = lg = quad = longdouble = 0;
85
86 f = *pf;
87 switch (*f) {
88 case 'h':
89 f++;
90 sh = 1;
91 break;
92 case 'l':
93 f++;
94 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
95 if (*f == 'l') {
96 f++;
97 quad = 1;
98 } else {
99 lg = 1;
100 }
101 break;
102 case 'q':
103 f++;
104 quad = 1;
105 break;
106 case 'L':
107 f++;
108 longdouble = 1;
109 break;
110 default:
111 break;
112 }
113 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
114 if (strchr("diouxX", *f)) {
115 if (longdouble)
116 RETURN(pf,f,FMTCHECK_UNKNOWN);
117 if (lg)
118 RETURN(pf,f,FMTCHECK_LONG);
119 if (quad)
120 RETURN(pf,f,FMTCHECK_QUAD);
121 RETURN(pf,f,FMTCHECK_INT);
122 }
123 if (*f == 'n') {
124 if (longdouble)
125 RETURN(pf,f,FMTCHECK_UNKNOWN);
126 if (sh)
127 RETURN(pf,f,FMTCHECK_SHORTPOINTER);
128 if (lg)
129 RETURN(pf,f,FMTCHECK_LONGPOINTER);
130 if (quad)
131 RETURN(pf,f,FMTCHECK_QUADPOINTER);
132 RETURN(pf,f,FMTCHECK_INTPOINTER);
133 }
134 if (strchr("DOU", *f)) {
135 if (sh + lg + quad + longdouble)
136 RETURN(pf,f,FMTCHECK_UNKNOWN);
137 RETURN(pf,f,FMTCHECK_LONG);
138 }
139 if (strchr("eEfg", *f)) {
140 if (longdouble)
141 RETURN(pf,f,FMTCHECK_LONGDOUBLE);
142 if (sh + lg + quad)
143 RETURN(pf,f,FMTCHECK_UNKNOWN);
144 RETURN(pf,f,FMTCHECK_DOUBLE);
145 }
146 if (*f == 'c') {
147 if (sh + lg + quad + longdouble)
148 RETURN(pf,f,FMTCHECK_UNKNOWN);
149 RETURN(pf,f,FMTCHECK_INT);
150 }
151 if (*f == 's') {
152 if (sh + lg + quad + longdouble)
153 RETURN(pf,f,FMTCHECK_UNKNOWN);
154 RETURN(pf,f,FMTCHECK_STRING);
155 }
156 if (*f == 'p') {
157 if (sh + lg + quad + longdouble)
158 RETURN(pf,f,FMTCHECK_UNKNOWN);
159 RETURN(pf,f,FMTCHECK_LONG);
160 }
161 RETURN(pf,f,FMTCHECK_UNKNOWN);
162 /*NOTREACHED*/
163 }
164
165 static EFT
166 get_next_format_from_width(const char **pf)
167 {
168 const char *f;
169
170 f = *pf;
171 if (*f == '.') {
172 f++;
173 if (*f == '*') {
174 RETURN(pf,f,FMTCHECK_PRECISION);
175 }
176 /* eat any precision (empty is allowed) */
177 while (isdigit(*f)) f++;
178 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
179 }
180 RETURN(pf,f,get_next_format_from_precision(pf));
181 /*NOTREACHED*/
182 }
183
184 static EFT
185 get_next_format(const char **pf, EFT eft)
186 {
187 int infmt;
188 const char *f;
189
190 if (eft == FMTCHECK_WIDTH) {
191 (*pf)++;
192 return get_next_format_from_width(pf);
193 } else if (eft == FMTCHECK_PRECISION) {
194 (*pf)++;
195 return get_next_format_from_precision(pf);
196 }
197
198 f = *pf;
199 infmt = 0;
200 while (!infmt) {
201 f = strchr(f, '%');
202 if (f == NULL)
203 RETURN(pf,f,FMTCHECK_DONE);
204 f++;
205 if (!*f)
206 RETURN(pf,f,FMTCHECK_UNKNOWN);
207 if (*f != '%')
208 infmt = 1;
209 else
210 f++;
211 }
212
213 /* Eat any of the flags */
214 while (*f && (strchr("#0- +", *f)))
215 f++;
216
217 if (*f == '*') {
218 RETURN(pf,f,FMTCHECK_WIDTH);
219 }
220 /* eat any width */
221 while (isdigit(*f)) f++;
222 if (!*f) {
223 RETURN(pf,f,FMTCHECK_UNKNOWN);
224 }
225
226 RETURN(pf,f,get_next_format_from_width(pf));
227 /*NOTREACHED*/
228 }
229
230 __const char *
231 __fmtcheck(const char *f1, const char *f2)
232 {
233 const char *f1p, *f2p;
234 EFT f1t, f2t;
235
236 if (!f1) return f2;
237
238 f1p = f1;
239 f1t = FMTCHECK_START;
240 f2p = f2;
241 f2t = FMTCHECK_START;
242 while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
243 if (f1t == FMTCHECK_UNKNOWN)
244 return f2;
245 f2t = get_next_format(&f2p, f2t);
246 if (f1t != f2t)
247 return f2;
248 }
249 return f1;
250 }
251