]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/gen/fmtcheck.c
MFV r310796, r310797:
[FreeBSD/FreeBSD.git] / lib / libc / gen / fmtcheck.c
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 <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <ctype.h>
37
38 __weak_reference(__fmtcheck, fmtcheck);
39 const char * __fmtcheck(const char *, const char *);
40
41 enum __e_fmtcheck_types {
42         FMTCHECK_START,
43         FMTCHECK_SHORT,
44         FMTCHECK_INT,
45         FMTCHECK_WINTT,
46         FMTCHECK_LONG,
47         FMTCHECK_QUAD,
48         FMTCHECK_INTMAXT,
49         FMTCHECK_PTRDIFFT,
50         FMTCHECK_SIZET,
51         FMTCHECK_CHARPOINTER,
52         FMTCHECK_SHORTPOINTER,
53         FMTCHECK_INTPOINTER,
54         FMTCHECK_LONGPOINTER,
55         FMTCHECK_QUADPOINTER,
56         FMTCHECK_INTMAXTPOINTER,
57         FMTCHECK_PTRDIFFTPOINTER,
58         FMTCHECK_SIZETPOINTER,
59 #ifndef NO_FLOATING_POINT
60         FMTCHECK_DOUBLE,
61         FMTCHECK_LONGDOUBLE,
62 #endif
63         FMTCHECK_STRING,
64         FMTCHECK_WSTRING,
65         FMTCHECK_WIDTH,
66         FMTCHECK_PRECISION,
67         FMTCHECK_DONE,
68         FMTCHECK_UNKNOWN
69 };
70 typedef enum __e_fmtcheck_types EFT;
71
72 enum e_modifier {
73         MOD_NONE,
74         MOD_CHAR,
75         MOD_SHORT,
76         MOD_LONG,
77         MOD_QUAD,
78         MOD_INTMAXT,
79         MOD_LONGDOUBLE,
80         MOD_PTRDIFFT,
81         MOD_SIZET,
82 };
83
84 #define RETURN(pf,f,r) do { \
85                         *(pf) = (f); \
86                         return r; \
87                        } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
88
89 static EFT
90 get_next_format_from_precision(const char **pf)
91 {
92         enum e_modifier modifier;
93         const char      *f;
94
95         f = *pf;
96         switch (*f) {
97         case 'h':
98                 f++;
99                 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
100                 if (*f == 'h') {
101                         f++;
102                         modifier = MOD_CHAR;
103                 } else {
104                         modifier = MOD_SHORT;
105                 }
106                 break;
107         case 'j':
108                 f++;
109                 modifier = MOD_INTMAXT;
110                 break;
111         case 'l':
112                 f++;
113                 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
114                 if (*f == 'l') {
115                         f++;
116                         modifier = MOD_QUAD;
117                 } else {
118                         modifier = MOD_LONG;
119                 }
120                 break;
121         case 'q':
122                 f++;
123                 modifier = MOD_QUAD;
124                 break;
125         case 't':
126                 f++;
127                 modifier = MOD_PTRDIFFT;
128                 break;
129         case 'z':
130                 f++;
131                 modifier = MOD_SIZET;
132                 break;
133         case 'L':
134                 f++;
135                 modifier = MOD_LONGDOUBLE;
136                 break;
137         default:
138                 modifier = MOD_NONE;
139                 break;
140         }
141         if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
142         if (strchr("diouxX", *f)) {
143                 switch (modifier) {
144                 case MOD_LONG:
145                         RETURN(pf,f,FMTCHECK_LONG);
146                 case MOD_QUAD:
147                         RETURN(pf,f,FMTCHECK_QUAD);
148                 case MOD_INTMAXT:
149                         RETURN(pf,f,FMTCHECK_INTMAXT);
150                 case MOD_PTRDIFFT:
151                         RETURN(pf,f,FMTCHECK_PTRDIFFT);
152                 case MOD_SIZET:
153                         RETURN(pf,f,FMTCHECK_SIZET);
154                 case MOD_CHAR:
155                 case MOD_SHORT:
156                 case MOD_NONE:
157                         RETURN(pf,f,FMTCHECK_INT);
158                 default:
159                         RETURN(pf,f,FMTCHECK_UNKNOWN);
160                 }
161         }
162         if (*f == 'n') {
163                 switch (modifier) {
164                 case MOD_CHAR:
165                         RETURN(pf,f,FMTCHECK_CHARPOINTER);
166                 case MOD_SHORT:
167                         RETURN(pf,f,FMTCHECK_SHORTPOINTER);
168                 case MOD_LONG:
169                         RETURN(pf,f,FMTCHECK_LONGPOINTER);
170                 case MOD_QUAD:
171                         RETURN(pf,f,FMTCHECK_QUADPOINTER);
172                 case MOD_INTMAXT:
173                         RETURN(pf,f,FMTCHECK_INTMAXTPOINTER);
174                 case MOD_PTRDIFFT:
175                         RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
176                 case MOD_SIZET:
177                         RETURN(pf,f,FMTCHECK_SIZETPOINTER);
178                 case MOD_NONE:
179                         RETURN(pf,f,FMTCHECK_INTPOINTER);
180                 default:
181                         RETURN(pf,f,FMTCHECK_UNKNOWN);
182                 }
183         }
184         if (strchr("DOU", *f)) {
185                 if (modifier != MOD_NONE)
186                         RETURN(pf,f,FMTCHECK_UNKNOWN);
187                 RETURN(pf,f,FMTCHECK_LONG);
188         }
189 #ifndef NO_FLOATING_POINT
190         if (strchr("aAeEfFgG", *f)) {
191                 switch (modifier) {
192                 case MOD_LONGDOUBLE:
193                         RETURN(pf,f,FMTCHECK_LONGDOUBLE);
194                 case MOD_LONG:
195                 case MOD_NONE:
196                         RETURN(pf,f,FMTCHECK_DOUBLE);
197                 default:
198                         RETURN(pf,f,FMTCHECK_UNKNOWN);
199                 }
200         }
201 #endif
202         if (*f == 'c') {
203                 switch (modifier) {
204                 case MOD_LONG:
205                         RETURN(pf,f,FMTCHECK_WINTT);
206                 case MOD_NONE:
207                         RETURN(pf,f,FMTCHECK_INT);
208                 default:
209                         RETURN(pf,f,FMTCHECK_UNKNOWN);
210                 }
211         }
212         if (*f == 'C') {
213                 if (modifier != MOD_NONE)
214                         RETURN(pf,f,FMTCHECK_UNKNOWN);
215                 RETURN(pf,f,FMTCHECK_WINTT);
216         }
217         if (*f == 's') {
218                 switch (modifier) {
219                 case MOD_LONG:
220                         RETURN(pf,f,FMTCHECK_WSTRING);
221                 case MOD_NONE:
222                         RETURN(pf,f,FMTCHECK_STRING);
223                 default:
224                         RETURN(pf,f,FMTCHECK_UNKNOWN);
225                 }
226         }
227         if (*f == 'S') {
228                 if (modifier != MOD_NONE)
229                         RETURN(pf,f,FMTCHECK_UNKNOWN);
230                 RETURN(pf,f,FMTCHECK_WSTRING);
231         }
232         if (*f == 'p') {
233                 if (modifier != MOD_NONE)
234                         RETURN(pf,f,FMTCHECK_UNKNOWN);
235                 RETURN(pf,f,FMTCHECK_LONG);
236         }
237         RETURN(pf,f,FMTCHECK_UNKNOWN);
238         /*NOTREACHED*/
239 }
240
241 static EFT
242 get_next_format_from_width(const char **pf)
243 {
244         const char      *f;
245
246         f = *pf;
247         if (*f == '.') {
248                 f++;
249                 if (*f == '*') {
250                         RETURN(pf,f,FMTCHECK_PRECISION);
251                 }
252                 /* eat any precision (empty is allowed) */
253                 while (isdigit(*f)) f++;
254                 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
255         }
256         RETURN(pf,f,get_next_format_from_precision(pf));
257         /*NOTREACHED*/
258 }
259
260 static EFT
261 get_next_format(const char **pf, EFT eft)
262 {
263         int             infmt;
264         const char      *f;
265
266         if (eft == FMTCHECK_WIDTH) {
267                 (*pf)++;
268                 return get_next_format_from_width(pf);
269         } else if (eft == FMTCHECK_PRECISION) {
270                 (*pf)++;
271                 return get_next_format_from_precision(pf);
272         }
273
274         f = *pf;
275         infmt = 0;
276         while (!infmt) {
277                 f = strchr(f, '%');
278                 if (f == NULL)
279                         RETURN(pf,f,FMTCHECK_DONE);
280                 f++;
281                 if (!*f)
282                         RETURN(pf,f,FMTCHECK_UNKNOWN);
283                 if (*f != '%')
284                         infmt = 1;
285                 else
286                         f++;
287         }
288
289         /* Eat any of the flags */
290         while (*f && (strchr("#'0- +", *f)))
291                 f++;
292
293         if (*f == '*') {
294                 RETURN(pf,f,FMTCHECK_WIDTH);
295         }
296         /* eat any width */
297         while (isdigit(*f)) f++;
298         if (!*f) {
299                 RETURN(pf,f,FMTCHECK_UNKNOWN);
300         }
301
302         RETURN(pf,f,get_next_format_from_width(pf));
303         /*NOTREACHED*/
304 }
305
306 const char *
307 __fmtcheck(const char *f1, const char *f2)
308 {
309         const char      *f1p, *f2p;
310         EFT             f1t, f2t;
311
312         if (!f1) return f2;
313         
314         f1p = f1;
315         f1t = FMTCHECK_START;
316         f2p = f2;
317         f2t = FMTCHECK_START;
318         while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
319                 if (f1t == FMTCHECK_UNKNOWN)
320                         return f2;
321                 f2t = get_next_format(&f2p, f2t);
322                 if (f1t != f2t)
323                         return f2;
324         }
325         return f1;
326 }