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