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