xref: /freebsd/lib/libc/gen/fmtcheck.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
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 
36 /*	$NetBSD: fmtcheck.c,v 1.2 2000/11/01 01:17:20 briggs Exp $	*/
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
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_LONG,
51 	FMTCHECK_QUAD,
52 	FMTCHECK_PTRDIFFT,
53 	FMTCHECK_SIZET,
54 	FMTCHECK_SHORTPOINTER,
55 	FMTCHECK_INTPOINTER,
56 	FMTCHECK_LONGPOINTER,
57 	FMTCHECK_QUADPOINTER,
58 	FMTCHECK_PTRDIFFTPOINTER,
59 	FMTCHECK_SIZETPOINTER,
60 	FMTCHECK_DOUBLE,
61 	FMTCHECK_LONGDOUBLE,
62 	FMTCHECK_STRING,
63 	FMTCHECK_WIDTH,
64 	FMTCHECK_PRECISION,
65 	FMTCHECK_DONE,
66 	FMTCHECK_UNKNOWN
67 };
68 typedef enum __e_fmtcheck_types EFT;
69 
70 #define RETURN(pf,f,r) do { \
71 			*(pf) = (f); \
72 			return r; \
73 		       } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
74 
75 static EFT
76 get_next_format_from_precision(const char **pf)
77 {
78 	int		sh, lg, quad, longdouble, ptrdifft, sizet;
79 	const char	*f;
80 
81 	sh = lg = quad = longdouble = ptrdifft = sizet = 0;
82 
83 	f = *pf;
84 	switch (*f) {
85 	case 'h':
86 		f++;
87 		sh = 1;
88 		break;
89 	case 'l':
90 		f++;
91 		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
92 		if (*f == 'l') {
93 			f++;
94 			quad = 1;
95 		} else {
96 			lg = 1;
97 		}
98 		break;
99 	case 'q':
100 		f++;
101 		quad = 1;
102 		break;
103 	case 't':
104 		f++;
105 		ptrdifft = 1;
106 		break;
107 	case 'z':
108 		f++;
109 		sizet = 1;
110 		break;
111 	case 'L':
112 		f++;
113 		longdouble = 1;
114 		break;
115 	default:
116 		break;
117 	}
118 	if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
119 	if (strchr("diouxX", *f)) {
120 		if (longdouble)
121 			RETURN(pf,f,FMTCHECK_UNKNOWN);
122 		if (lg)
123 			RETURN(pf,f,FMTCHECK_LONG);
124 		if (quad)
125 			RETURN(pf,f,FMTCHECK_QUAD);
126 		if (ptrdifft)
127 			RETURN(pf,f,FMTCHECK_PTRDIFFT);
128 		if (sizet)
129 			RETURN(pf,f,FMTCHECK_SIZET);
130 		RETURN(pf,f,FMTCHECK_INT);
131 	}
132 	if (*f == 'n') {
133 		if (longdouble)
134 			RETURN(pf,f,FMTCHECK_UNKNOWN);
135 		if (sh)
136 			RETURN(pf,f,FMTCHECK_SHORTPOINTER);
137 		if (lg)
138 			RETURN(pf,f,FMTCHECK_LONGPOINTER);
139 		if (quad)
140 			RETURN(pf,f,FMTCHECK_QUADPOINTER);
141 		if (ptrdifft)
142 			RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
143 		if (sizet)
144 			RETURN(pf,f,FMTCHECK_SIZETPOINTER);
145 		RETURN(pf,f,FMTCHECK_INTPOINTER);
146 	}
147 	if (strchr("DOU", *f)) {
148 		if (sh + lg + quad + longdouble + ptrdifft + sizet)
149 			RETURN(pf,f,FMTCHECK_UNKNOWN);
150 		RETURN(pf,f,FMTCHECK_LONG);
151 	}
152 	if (strchr("aAeEfFgG", *f)) {
153 		if (longdouble)
154 			RETURN(pf,f,FMTCHECK_LONGDOUBLE);
155 		if (sh + lg + quad + ptrdifft + sizet)
156 			RETURN(pf,f,FMTCHECK_UNKNOWN);
157 		RETURN(pf,f,FMTCHECK_DOUBLE);
158 	}
159 	if (*f == 'c') {
160 		if (sh + lg + quad + longdouble + ptrdifft + sizet)
161 			RETURN(pf,f,FMTCHECK_UNKNOWN);
162 		RETURN(pf,f,FMTCHECK_INT);
163 	}
164 	if (*f == 's') {
165 		if (sh + lg + quad + longdouble + ptrdifft + sizet)
166 			RETURN(pf,f,FMTCHECK_UNKNOWN);
167 		RETURN(pf,f,FMTCHECK_STRING);
168 	}
169 	if (*f == 'p') {
170 		if (sh + lg + quad + longdouble + ptrdifft + sizet)
171 			RETURN(pf,f,FMTCHECK_UNKNOWN);
172 		RETURN(pf,f,FMTCHECK_LONG);
173 	}
174 	RETURN(pf,f,FMTCHECK_UNKNOWN);
175 	/*NOTREACHED*/
176 }
177 
178 static EFT
179 get_next_format_from_width(const char **pf)
180 {
181 	const char	*f;
182 
183 	f = *pf;
184 	if (*f == '.') {
185 		f++;
186 		if (*f == '*') {
187 			RETURN(pf,f,FMTCHECK_PRECISION);
188 		}
189 		/* eat any precision (empty is allowed) */
190 		while (isdigit(*f)) f++;
191 		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
192 	}
193 	RETURN(pf,f,get_next_format_from_precision(pf));
194 	/*NOTREACHED*/
195 }
196 
197 static EFT
198 get_next_format(const char **pf, EFT eft)
199 {
200 	int		infmt;
201 	const char	*f;
202 
203 	if (eft == FMTCHECK_WIDTH) {
204 		(*pf)++;
205 		return get_next_format_from_width(pf);
206 	} else if (eft == FMTCHECK_PRECISION) {
207 		(*pf)++;
208 		return get_next_format_from_precision(pf);
209 	}
210 
211 	f = *pf;
212 	infmt = 0;
213 	while (!infmt) {
214 		f = strchr(f, '%');
215 		if (f == NULL)
216 			RETURN(pf,f,FMTCHECK_DONE);
217 		f++;
218 		if (!*f)
219 			RETURN(pf,f,FMTCHECK_UNKNOWN);
220 		if (*f != '%')
221 			infmt = 1;
222 		else
223 			f++;
224 	}
225 
226 	/* Eat any of the flags */
227 	while (*f && (strchr("#0- +", *f)))
228 		f++;
229 
230 	if (*f == '*') {
231 		RETURN(pf,f,FMTCHECK_WIDTH);
232 	}
233 	/* eat any width */
234 	while (isdigit(*f)) f++;
235 	if (!*f) {
236 		RETURN(pf,f,FMTCHECK_UNKNOWN);
237 	}
238 
239 	RETURN(pf,f,get_next_format_from_width(pf));
240 	/*NOTREACHED*/
241 }
242 
243 __const char *
244 __fmtcheck(const char *f1, const char *f2)
245 {
246 	const char	*f1p, *f2p;
247 	EFT		f1t, f2t;
248 
249 	if (!f1) return f2;
250 
251 	f1p = f1;
252 	f1t = FMTCHECK_START;
253 	f2p = f2;
254 	f2t = FMTCHECK_START;
255 	while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
256 		if (f1t == FMTCHECK_UNKNOWN)
257 			return f2;
258 		f2t = get_next_format(&f2p, f2t);
259 		if (f1t != f2t)
260 			return f2;
261 	}
262 	return f1;
263 }
264