MFC:
[dragonfly.git] / lib / libc / gen / fmtcheck.c
blob2140f2438b187708fb59b504df30da059e9ff0eb
1 /* $FreeBSD: src/lib/libc/gen/fmtcheck.c,v 1.1.2.1 2001/07/05 07:43:42 kris Exp $ */
2 /* $DragonFly: src/lib/libc/gen/fmtcheck.c,v 1.3 2003/08/22 19:31:21 asmodai Exp $ */
3 /* $NetBSD: fmtcheck.c,v 1.2 2000/11/01 01:17:20 briggs Exp $ */
5 /*-
6 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * All rights reserved.
9 * This code was contributed to The NetBSD Foundation by Allen Briggs.
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 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
39 * $FreeBSD: src/lib/libc/gen/fmtcheck.c,v 1.1.2.1 2001/07/05 07:43:42 kris Exp $
42 #include <sys/cdefs.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <ctype.h>
49 #ifdef __weak_alias
50 __weak_alias(fmtcheck,__fmtcheck)
51 #endif
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
71 typedef enum __e_fmtcheck_types EFT;
73 #define RETURN(pf,f,r) do { \
74 *(pf) = (f); \
75 return r; \
76 } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
78 static EFT
79 get_next_format_from_precision(const char **pf)
81 int sh, lg, quad, longdouble;
82 const char *f;
84 sh = lg = quad = longdouble = 0;
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;
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;
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);
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);
134 if (strchr("DOU", *f)) {
135 if (sh + lg + quad + longdouble)
136 RETURN(pf,f,FMTCHECK_UNKNOWN);
137 RETURN(pf,f,FMTCHECK_LONG);
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);
146 if (*f == 'c') {
147 if (sh + lg + quad + longdouble)
148 RETURN(pf,f,FMTCHECK_UNKNOWN);
149 RETURN(pf,f,FMTCHECK_INT);
151 if (*f == 's') {
152 if (sh + lg + quad + longdouble)
153 RETURN(pf,f,FMTCHECK_UNKNOWN);
154 RETURN(pf,f,FMTCHECK_STRING);
156 if (*f == 'p') {
157 if (sh + lg + quad + longdouble)
158 RETURN(pf,f,FMTCHECK_UNKNOWN);
159 RETURN(pf,f,FMTCHECK_LONG);
161 RETURN(pf,f,FMTCHECK_UNKNOWN);
162 /*NOTREACHED*/
165 static EFT
166 get_next_format_from_width(const char **pf)
168 const char *f;
170 f = *pf;
171 if (*f == '.') {
172 f++;
173 if (*f == '*') {
174 RETURN(pf,f,FMTCHECK_PRECISION);
176 /* eat any precision (empty is allowed) */
177 while (isdigit(*f)) f++;
178 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
180 RETURN(pf,f,get_next_format_from_precision(pf));
181 /*NOTREACHED*/
184 static EFT
185 get_next_format(const char **pf, EFT eft)
187 int infmt;
188 const char *f;
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);
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++;
213 /* Eat any of the flags */
214 while (*f && (strchr("#0- +", *f)))
215 f++;
217 if (*f == '*') {
218 RETURN(pf,f,FMTCHECK_WIDTH);
220 /* eat any width */
221 while (isdigit(*f)) f++;
222 if (!*f) {
223 RETURN(pf,f,FMTCHECK_UNKNOWN);
226 RETURN(pf,f,get_next_format_from_width(pf));
227 /*NOTREACHED*/
230 const char *
231 fmtcheck(const char *f1, const char *f2)
233 const char *f1p, *f2p;
234 EFT f1t, f2t;
236 if (!f1) return f2;
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;
249 return f1;