Merge branch 'vendor/LIBPCAP'
[dragonfly.git] / lib / libc / gen / fmtcheck.c
1 /*-
2  * Copyright (c) 2000 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This code was contributed to The NetBSD Foundation by Allen Briggs.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *        This product includes software developed by the NetBSD
18  *        Foundation, Inc. and its contributors.
19  * 4. Neither the name of The NetBSD Foundation nor the names of its
20  *    contributors may be used to endorse or promote products derived
21  *    from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * $NetBSD: fmtcheck.c,v 1.2 2000/11/01 01:17:20 briggs Exp $
36  * $FreeBSD: src/lib/libc/gen/fmtcheck.c,v 1.9 2008/08/02 06:02:42 das Exp $
37  * $DragonFly: src/lib/libc/gen/fmtcheck.c,v 1.3 2003/08/22 19:31:21 asmodai Exp $
38  */
39
40 #include <stdio.h>
41 #include <string.h>
42 #include <ctype.h>
43
44 __weak_reference(__fmtcheck, fmtcheck);
45
46 enum __e_fmtcheck_types {
47         FMTCHECK_START,
48         FMTCHECK_SHORT,
49         FMTCHECK_INT,
50         FMTCHECK_WINTT,
51         FMTCHECK_LONG,
52         FMTCHECK_QUAD,
53         FMTCHECK_INTMAXT,
54         FMTCHECK_PTRDIFFT,
55         FMTCHECK_SIZET,
56         FMTCHECK_CHARPOINTER,
57         FMTCHECK_SHORTPOINTER,
58         FMTCHECK_INTPOINTER,
59         FMTCHECK_LONGPOINTER,
60         FMTCHECK_QUADPOINTER,
61         FMTCHECK_INTMAXTPOINTER,
62         FMTCHECK_PTRDIFFTPOINTER,
63         FMTCHECK_SIZETPOINTER,
64 #ifndef NO_FLOATING_POINT
65         FMTCHECK_DOUBLE,
66         FMTCHECK_LONGDOUBLE,
67 #endif
68         FMTCHECK_STRING,
69         FMTCHECK_WSTRING,
70         FMTCHECK_WIDTH,
71         FMTCHECK_PRECISION,
72         FMTCHECK_DONE,
73         FMTCHECK_UNKNOWN
74 };
75 typedef enum __e_fmtcheck_types EFT;
76
77 enum e_modifier {
78         MOD_NONE,
79         MOD_CHAR,
80         MOD_SHORT,
81         MOD_LONG,
82         MOD_QUAD,
83         MOD_INTMAXT,
84         MOD_LONGDOUBLE,
85         MOD_PTRDIFFT,
86         MOD_SIZET,
87 };
88
89 #define RETURN(pf,f,r) do { \
90                         *(pf) = (f); \
91                         return r; \
92                        } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
93
94 static EFT
95 get_next_format_from_precision(const char **pf)
96 {
97         enum e_modifier modifier;
98         const char      *f;
99
100         f = *pf;
101         switch (*f) {
102         case 'h':
103                 f++;
104                 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
105                 if (*f == 'h') {
106                         f++;
107                         modifier = MOD_CHAR;
108                 } else {
109                         modifier = MOD_SHORT;
110                 }
111                 break;
112         case 'j':
113                 f++;
114                 modifier = MOD_INTMAXT;
115                 break;
116         case 'l':
117                 f++;
118                 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
119                 if (*f == 'l') {
120                         f++;
121                         modifier = MOD_QUAD;
122                 } else {
123                         modifier = MOD_LONG;
124                 }
125                 break;
126         case 'q':
127                 f++;
128                 modifier = MOD_QUAD;
129                 break;
130         case 't':
131                 f++;
132                 modifier = MOD_PTRDIFFT;
133                 break;
134         case 'z':
135                 f++;
136                 modifier = MOD_SIZET;
137                 break;
138         case 'L':
139                 f++;
140                 modifier = MOD_LONGDOUBLE;
141                 break;
142         default:
143                 modifier = MOD_NONE;
144                 break;
145         }
146         if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
147         if (strchr("diouxX", *f)) {
148                 switch (modifier) {
149                 case MOD_LONG:
150                         RETURN(pf,f,FMTCHECK_LONG);
151                 case MOD_QUAD:
152                         RETURN(pf,f,FMTCHECK_QUAD);
153                 case MOD_INTMAXT:
154                         RETURN(pf,f,FMTCHECK_INTMAXT);
155                 case MOD_PTRDIFFT:
156                         RETURN(pf,f,FMTCHECK_PTRDIFFT);
157                 case MOD_SIZET:
158                         RETURN(pf,f,FMTCHECK_SIZET);
159                 case MOD_CHAR:
160                 case MOD_SHORT:
161                 case MOD_NONE:
162                         RETURN(pf,f,FMTCHECK_INT);
163                 default:
164                         RETURN(pf,f,FMTCHECK_UNKNOWN);
165                 }
166         }
167         if (*f == 'n') {
168                 switch (modifier) {
169                 case MOD_CHAR:
170                         RETURN(pf,f,FMTCHECK_CHARPOINTER);
171                 case MOD_SHORT:
172                         RETURN(pf,f,FMTCHECK_SHORTPOINTER);
173                 case MOD_LONG:
174                         RETURN(pf,f,FMTCHECK_LONGPOINTER);
175                 case MOD_QUAD:
176                         RETURN(pf,f,FMTCHECK_QUADPOINTER);
177                 case MOD_INTMAXT:
178                         RETURN(pf,f,FMTCHECK_INTMAXTPOINTER);
179                 case MOD_PTRDIFFT:
180                         RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
181                 case MOD_SIZET:
182                         RETURN(pf,f,FMTCHECK_SIZETPOINTER);
183                 case MOD_NONE:
184                         RETURN(pf,f,FMTCHECK_INTPOINTER);
185                 default:
186                         RETURN(pf,f,FMTCHECK_UNKNOWN);
187                 }
188         }
189         if (strchr("DOU", *f)) {
190                 if (modifier != MOD_NONE)
191                         RETURN(pf,f,FMTCHECK_UNKNOWN);
192                 RETURN(pf,f,FMTCHECK_LONG);
193         }
194 #ifndef NO_FLOATING_POINT
195         if (strchr("aAeEfFgG", *f)) {
196                 switch (modifier) {
197                 case MOD_LONGDOUBLE:
198                         RETURN(pf,f,FMTCHECK_LONGDOUBLE);
199                 case MOD_LONG:
200                 case MOD_NONE:
201                         RETURN(pf,f,FMTCHECK_DOUBLE);
202                 default:
203                         RETURN(pf,f,FMTCHECK_UNKNOWN);
204                 }
205         }
206 #endif
207         if (*f == 'c') {
208                 switch (modifier) {
209                 case MOD_LONG:
210                         RETURN(pf,f,FMTCHECK_WINTT);
211                 case MOD_NONE:
212                         RETURN(pf,f,FMTCHECK_INT);
213                 default:
214                         RETURN(pf,f,FMTCHECK_UNKNOWN);
215                 }
216         }
217         if (*f == 'C') {
218                 if (modifier != MOD_NONE)
219                         RETURN(pf,f,FMTCHECK_UNKNOWN);
220                 RETURN(pf,f,FMTCHECK_WINTT);
221         }
222         if (*f == 's') {
223                 switch (modifier) {
224                 case MOD_LONG:
225                         RETURN(pf,f,FMTCHECK_WSTRING);
226                 case MOD_NONE:
227                         RETURN(pf,f,FMTCHECK_STRING);
228                 default:
229                         RETURN(pf,f,FMTCHECK_UNKNOWN);
230                 }
231         }
232         if (*f == 'S') {
233                 if (modifier != MOD_NONE)
234                         RETURN(pf,f,FMTCHECK_UNKNOWN);
235                 RETURN(pf,f,FMTCHECK_WSTRING);
236         }
237         if (*f == 'p') {
238                 if (modifier != MOD_NONE)
239                         RETURN(pf,f,FMTCHECK_UNKNOWN);
240                 RETURN(pf,f,FMTCHECK_LONG);
241         }
242         RETURN(pf,f,FMTCHECK_UNKNOWN);
243         /*NOTREACHED*/
244 }
245
246 static EFT
247 get_next_format_from_width(const char **pf)
248 {
249         const char      *f;
250
251         f = *pf;
252         if (*f == '.') {
253                 f++;
254                 if (*f == '*') {
255                         RETURN(pf,f,FMTCHECK_PRECISION);
256                 }
257                 /* eat any precision (empty is allowed) */
258                 while (isdigit(*f)) f++;
259                 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
260         }
261         RETURN(pf,f,get_next_format_from_precision(pf));
262         /*NOTREACHED*/
263 }
264
265 static EFT
266 get_next_format(const char **pf, EFT eft)
267 {
268         int             infmt;
269         const char      *f;
270
271         if (eft == FMTCHECK_WIDTH) {
272                 (*pf)++;
273                 return get_next_format_from_width(pf);
274         } else if (eft == FMTCHECK_PRECISION) {
275                 (*pf)++;
276                 return get_next_format_from_precision(pf);
277         }
278
279         f = *pf;
280         infmt = 0;
281         while (!infmt) {
282                 f = strchr(f, '%');
283                 if (f == NULL)
284                         RETURN(pf,f,FMTCHECK_DONE);
285                 f++;
286                 if (!*f)
287                         RETURN(pf,f,FMTCHECK_UNKNOWN);
288                 if (*f != '%')
289                         infmt = 1;
290                 else
291                         f++;
292         }
293
294         /* Eat any of the flags */
295         while (*f && (strchr("#'0- +", *f)))
296                 f++;
297
298         if (*f == '*') {
299                 RETURN(pf,f,FMTCHECK_WIDTH);
300         }
301         /* eat any width */
302         while (isdigit(*f)) f++;
303         if (!*f) {
304                 RETURN(pf,f,FMTCHECK_UNKNOWN);
305         }
306
307         RETURN(pf,f,get_next_format_from_width(pf));
308         /*NOTREACHED*/
309 }
310
311 const char *
312 __fmtcheck(const char *f1, const char *f2)
313 {
314         const char      *f1p, *f2p;
315         EFT             f1t, f2t;
316
317         if (!f1) return f2;
318         
319         f1p = f1;
320         f1t = FMTCHECK_START;
321         f2p = f2;
322         f2t = FMTCHECK_START;
323         while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
324                 if (f1t == FMTCHECK_UNKNOWN)
325                         return f2;
326                 f2t = get_next_format(&f2p, f2t);
327                 if (f1t != f2t)
328                         return f2;
329         }
330         return f1;
331 }