fmtcheck.c revision 300899
1/*	$NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp $	*/
2
3/*-
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code was contributed to The NetBSD Foundation by Allen Briggs.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "file.h"
32
33#include <stdio.h>
34#include <string.h>
35#include <ctype.h>
36
37enum __e_fmtcheck_types {
38	FMTCHECK_START,
39	FMTCHECK_SHORT,
40	FMTCHECK_INT,
41	FMTCHECK_LONG,
42	FMTCHECK_QUAD,
43	FMTCHECK_SHORTPOINTER,
44	FMTCHECK_INTPOINTER,
45	FMTCHECK_LONGPOINTER,
46	FMTCHECK_QUADPOINTER,
47	FMTCHECK_DOUBLE,
48	FMTCHECK_LONGDOUBLE,
49	FMTCHECK_STRING,
50	FMTCHECK_WIDTH,
51	FMTCHECK_PRECISION,
52	FMTCHECK_DONE,
53	FMTCHECK_UNKNOWN
54};
55typedef enum __e_fmtcheck_types EFT;
56
57#define RETURN(pf,f,r) do { \
58			*(pf) = (f); \
59			return r; \
60		       } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
61
62static EFT
63get_next_format_from_precision(const char **pf)
64{
65	int		sh, lg, quad, longdouble;
66	const char	*f;
67
68	sh = lg = quad = longdouble = 0;
69
70	f = *pf;
71	switch (*f) {
72	case 'h':
73		f++;
74		sh = 1;
75		break;
76	case 'l':
77		f++;
78		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
79		if (*f == 'l') {
80			f++;
81			quad = 1;
82		} else {
83			lg = 1;
84		}
85		break;
86	case 'q':
87		f++;
88		quad = 1;
89		break;
90	case 'L':
91		f++;
92		longdouble = 1;
93		break;
94#ifdef WIN32
95	case 'I':
96		f++;
97		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
98		if (*f == '3' && f[1] == '2') {
99			f += 2;
100		} else if (*f == '6' && f[1] == '4') {
101			f += 2;
102			quad = 1;
103		}
104#ifdef _WIN64
105		else {
106			quad = 1;
107		}
108#endif
109		break;
110#endif
111	default:
112		break;
113	}
114	if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
115	if (strchr("diouxX", *f)) {
116		if (longdouble)
117			RETURN(pf,f,FMTCHECK_UNKNOWN);
118		if (lg)
119			RETURN(pf,f,FMTCHECK_LONG);
120		if (quad)
121			RETURN(pf,f,FMTCHECK_QUAD);
122		RETURN(pf,f,FMTCHECK_INT);
123	}
124	if (*f == 'n') {
125		if (longdouble)
126			RETURN(pf,f,FMTCHECK_UNKNOWN);
127		if (sh)
128			RETURN(pf,f,FMTCHECK_SHORTPOINTER);
129		if (lg)
130			RETURN(pf,f,FMTCHECK_LONGPOINTER);
131		if (quad)
132			RETURN(pf,f,FMTCHECK_QUADPOINTER);
133		RETURN(pf,f,FMTCHECK_INTPOINTER);
134	}
135	if (strchr("DOU", *f)) {
136		if (sh + lg + quad + longdouble)
137			RETURN(pf,f,FMTCHECK_UNKNOWN);
138		RETURN(pf,f,FMTCHECK_LONG);
139	}
140	if (strchr("eEfg", *f)) {
141		if (longdouble)
142			RETURN(pf,f,FMTCHECK_LONGDOUBLE);
143		if (sh + lg + quad)
144			RETURN(pf,f,FMTCHECK_UNKNOWN);
145		RETURN(pf,f,FMTCHECK_DOUBLE);
146	}
147	if (*f == 'c') {
148		if (sh + lg + quad + longdouble)
149			RETURN(pf,f,FMTCHECK_UNKNOWN);
150		RETURN(pf,f,FMTCHECK_INT);
151	}
152	if (*f == 's') {
153		if (sh + lg + quad + longdouble)
154			RETURN(pf,f,FMTCHECK_UNKNOWN);
155		RETURN(pf,f,FMTCHECK_STRING);
156	}
157	if (*f == 'p') {
158		if (sh + lg + quad + longdouble)
159			RETURN(pf,f,FMTCHECK_UNKNOWN);
160		RETURN(pf,f,FMTCHECK_LONG);
161	}
162	RETURN(pf,f,FMTCHECK_UNKNOWN);
163	/*NOTREACHED*/
164}
165
166static EFT
167get_next_format_from_width(const char **pf)
168{
169	const char	*f;
170
171	f = *pf;
172	if (*f == '.') {
173		f++;
174		if (*f == '*') {
175			RETURN(pf,f,FMTCHECK_PRECISION);
176		}
177		/* eat any precision (empty is allowed) */
178		while (isdigit((unsigned char)*f)) f++;
179		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
180	}
181	RETURN(pf,f,get_next_format_from_precision(pf));
182	/*NOTREACHED*/
183}
184
185static EFT
186get_next_format(const char **pf, EFT eft)
187{
188	int		infmt;
189	const char	*f;
190
191	if (eft == FMTCHECK_WIDTH) {
192		(*pf)++;
193		return get_next_format_from_width(pf);
194	} else if (eft == FMTCHECK_PRECISION) {
195		(*pf)++;
196		return get_next_format_from_precision(pf);
197	}
198
199	f = *pf;
200	infmt = 0;
201	while (!infmt) {
202		f = strchr(f, '%');
203		if (f == NULL)
204			RETURN(pf,f,FMTCHECK_DONE);
205		f++;
206		if (!*f)
207			RETURN(pf,f,FMTCHECK_UNKNOWN);
208		if (*f != '%')
209			infmt = 1;
210		else
211			f++;
212	}
213
214	/* Eat any of the flags */
215	while (*f && (strchr("#0- +", *f)))
216		f++;
217
218	if (*f == '*') {
219		RETURN(pf,f,FMTCHECK_WIDTH);
220	}
221	/* eat any width */
222	while (isdigit((unsigned char)*f)) f++;
223	if (!*f) {
224		RETURN(pf,f,FMTCHECK_UNKNOWN);
225	}
226
227	RETURN(pf,f,get_next_format_from_width(pf));
228	/*NOTREACHED*/
229}
230
231const char *
232fmtcheck(const char *f1, const char *f2)
233{
234	const char	*f1p, *f2p;
235	EFT		f1t, f2t;
236
237	if (!f1) return f2;
238
239	f1p = f1;
240	f1t = FMTCHECK_START;
241	f2p = f2;
242	f2t = FMTCHECK_START;
243	while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
244		if (f1t == FMTCHECK_UNKNOWN)
245			return f2;
246		f2t = get_next_format(&f2p, f2t);
247		if (f1t != f2t)
248			return f2;
249	}
250	return f1;
251}
252