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