fmtcheck.c revision 90039
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: head/lib/libc/gen/fmtcheck.c 90039 2002-02-01 00:57:29Z obrien $");
39
40#include "namespace.h"
41
42#include <stdio.h>
43#include <string.h>
44#include <ctype.h>
45
46#ifdef __weak_alias
47__weak_alias(fmtcheck,__fmtcheck)
48#endif
49
50enum __e_fmtcheck_types {
51	FMTCHECK_START,
52	FMTCHECK_SHORT,
53	FMTCHECK_INT,
54	FMTCHECK_LONG,
55	FMTCHECK_QUAD,
56	FMTCHECK_SHORTPOINTER,
57	FMTCHECK_INTPOINTER,
58	FMTCHECK_LONGPOINTER,
59	FMTCHECK_QUADPOINTER,
60	FMTCHECK_DOUBLE,
61	FMTCHECK_LONGDOUBLE,
62	FMTCHECK_STRING,
63	FMTCHECK_WIDTH,
64	FMTCHECK_PRECISION,
65	FMTCHECK_DONE,
66	FMTCHECK_UNKNOWN
67};
68typedef 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
75static EFT
76get_next_format_from_precision(const char **pf)
77{
78	int		sh, lg, quad, longdouble;
79	const char	*f;
80
81	sh = lg = quad = longdouble = 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 'L':
104		f++;
105		longdouble = 1;
106		break;
107	default:
108		break;
109	}
110	if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
111	if (strchr("diouxX", *f)) {
112		if (longdouble)
113			RETURN(pf,f,FMTCHECK_UNKNOWN);
114		if (lg)
115			RETURN(pf,f,FMTCHECK_LONG);
116		if (quad)
117			RETURN(pf,f,FMTCHECK_QUAD);
118		RETURN(pf,f,FMTCHECK_INT);
119	}
120	if (*f == 'n') {
121		if (longdouble)
122			RETURN(pf,f,FMTCHECK_UNKNOWN);
123		if (sh)
124			RETURN(pf,f,FMTCHECK_SHORTPOINTER);
125		if (lg)
126			RETURN(pf,f,FMTCHECK_LONGPOINTER);
127		if (quad)
128			RETURN(pf,f,FMTCHECK_QUADPOINTER);
129		RETURN(pf,f,FMTCHECK_INTPOINTER);
130	}
131	if (strchr("DOU", *f)) {
132		if (sh + lg + quad + longdouble)
133			RETURN(pf,f,FMTCHECK_UNKNOWN);
134		RETURN(pf,f,FMTCHECK_LONG);
135	}
136	if (strchr("eEfg", *f)) {
137		if (longdouble)
138			RETURN(pf,f,FMTCHECK_LONGDOUBLE);
139		if (sh + lg + quad)
140			RETURN(pf,f,FMTCHECK_UNKNOWN);
141		RETURN(pf,f,FMTCHECK_DOUBLE);
142	}
143	if (*f == 'c') {
144		if (sh + lg + quad + longdouble)
145			RETURN(pf,f,FMTCHECK_UNKNOWN);
146		RETURN(pf,f,FMTCHECK_INT);
147	}
148	if (*f == 's') {
149		if (sh + lg + quad + longdouble)
150			RETURN(pf,f,FMTCHECK_UNKNOWN);
151		RETURN(pf,f,FMTCHECK_STRING);
152	}
153	if (*f == 'p') {
154		if (sh + lg + quad + longdouble)
155			RETURN(pf,f,FMTCHECK_UNKNOWN);
156		RETURN(pf,f,FMTCHECK_LONG);
157	}
158	RETURN(pf,f,FMTCHECK_UNKNOWN);
159	/*NOTREACHED*/
160}
161
162static EFT
163get_next_format_from_width(const char **pf)
164{
165	const char	*f;
166
167	f = *pf;
168	if (*f == '.') {
169		f++;
170		if (*f == '*') {
171			RETURN(pf,f,FMTCHECK_PRECISION);
172		}
173		/* eat any precision (empty is allowed) */
174		while (isdigit(*f)) f++;
175		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
176	}
177	RETURN(pf,f,get_next_format_from_precision(pf));
178	/*NOTREACHED*/
179}
180
181static EFT
182get_next_format(const char **pf, EFT eft)
183{
184	int		infmt;
185	const char	*f;
186
187	if (eft == FMTCHECK_WIDTH) {
188		(*pf)++;
189		return get_next_format_from_width(pf);
190	} else if (eft == FMTCHECK_PRECISION) {
191		(*pf)++;
192		return get_next_format_from_precision(pf);
193	}
194
195	f = *pf;
196	infmt = 0;
197	while (!infmt) {
198		f = strchr(f, '%');
199		if (f == NULL)
200			RETURN(pf,f,FMTCHECK_DONE);
201		f++;
202		if (!*f)
203			RETURN(pf,f,FMTCHECK_UNKNOWN);
204		if (*f != '%')
205			infmt = 1;
206		else
207			f++;
208	}
209
210	/* Eat any of the flags */
211	while (*f && (strchr("#0- +", *f)))
212		f++;
213
214	if (*f == '*') {
215		RETURN(pf,f,FMTCHECK_WIDTH);
216	}
217	/* eat any width */
218	while (isdigit(*f)) f++;
219	if (!*f) {
220		RETURN(pf,f,FMTCHECK_UNKNOWN);
221	}
222
223	RETURN(pf,f,get_next_format_from_width(pf));
224	/*NOTREACHED*/
225}
226
227__const char *
228fmtcheck(const char *f1, const char *f2)
229{
230	const char	*f1p, *f2p;
231	EFT		f1t, f2t;
232
233	if (!f1) return f2;
234
235	f1p = f1;
236	f1t = FMTCHECK_START;
237	f2p = f2;
238	f2t = FMTCHECK_START;
239	while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
240		if (f1t == FMTCHECK_UNKNOWN)
241			return f2;
242		f2t = get_next_format(&f2p, f2t);
243		if (f1t != f2t)
244			return f2;
245	}
246	return f1;
247}
248