fmtcheck.c revision 299236
1193323Sed/*	$NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp $	*/
2193323Sed
3193323Sed/*-
4193323Sed * Copyright (c) 2000 The NetBSD Foundation, Inc.
5193323Sed * All rights reserved.
6193323Sed *
7193323Sed * This code was contributed to The NetBSD Foundation by Allen Briggs.
8193323Sed *
9193323Sed * Redistribution and use in source and binary forms, with or without
10193323Sed * modification, are permitted provided that the following conditions
11193323Sed * are met:
12193323Sed * 1. Redistributions of source code must retain the above copyright
13193323Sed *    notice, this list of conditions and the following disclaimer.
14193323Sed * 2. Redistributions in binary form must reproduce the above copyright
15193323Sed *    notice, this list of conditions and the following disclaimer in the
16218893Sdim *    documentation and/or other materials provided with the distribution.
17193323Sed *
18193323Sed * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19193323Sed * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20193323Sed * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21193323Sed * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22193323Sed * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23193323Sed * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24194612Sed * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25194612Sed * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26193323Sed * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27193323Sed * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28193323Sed * POSSIBILITY OF SUCH DAMAGE.
29193323Sed */
30234353Sdim
31193323Sed#include "file.h"
32234353Sdim
33234353Sdim#include <stdio.h>
34234353Sdim#include <string.h>
35234353Sdim#include <ctype.h>
36234353Sdim
37193323Sedenum __e_fmtcheck_types {
38234353Sdim	FMTCHECK_START,
39193323Sed	FMTCHECK_SHORT,
40193323Sed	FMTCHECK_INT,
41193323Sed	FMTCHECK_LONG,
42193323Sed	FMTCHECK_QUAD,
43193323Sed	FMTCHECK_SHORTPOINTER,
44193323Sed	FMTCHECK_INTPOINTER,
45193323Sed	FMTCHECK_LONGPOINTER,
46194612Sed	FMTCHECK_QUADPOINTER,
47193323Sed	FMTCHECK_DOUBLE,
48193323Sed	FMTCHECK_LONGDOUBLE,
49193323Sed	FMTCHECK_STRING,
50193323Sed	FMTCHECK_WIDTH,
51193323Sed	FMTCHECK_PRECISION,
52193323Sed	FMTCHECK_DONE,
53193323Sed	FMTCHECK_UNKNOWN
54193323Sed};
55193323Sedtypedef enum __e_fmtcheck_types EFT;
56193323Sed
57193323Sed#define RETURN(pf,f,r) do { \
58193323Sed			*(pf) = (f); \
59193323Sed			return r; \
60193323Sed		       } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
61193323Sed
62193323Sedstatic EFT
63193323Sedget_next_format_from_precision(const char **pf)
64193323Sed{
65193323Sed	int		sh, lg, quad, longdouble;
66193323Sed	const char	*f;
67193323Sed
68193323Sed	sh = lg = quad = longdouble = 0;
69193323Sed
70193323Sed	f = *pf;
71193323Sed	switch (*f) {
72193323Sed	case 'h':
73193323Sed		f++;
74193323Sed		sh = 1;
75193323Sed		break;
76193323Sed	case 'l':
77193323Sed		f++;
78193323Sed		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
79193323Sed		if (*f == 'l') {
80194612Sed			f++;
81193323Sed			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	default:
95		break;
96	}
97	if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
98	if (strchr("diouxX", *f)) {
99		if (longdouble)
100			RETURN(pf,f,FMTCHECK_UNKNOWN);
101		if (lg)
102			RETURN(pf,f,FMTCHECK_LONG);
103		if (quad)
104			RETURN(pf,f,FMTCHECK_QUAD);
105		RETURN(pf,f,FMTCHECK_INT);
106	}
107	if (*f == 'n') {
108		if (longdouble)
109			RETURN(pf,f,FMTCHECK_UNKNOWN);
110		if (sh)
111			RETURN(pf,f,FMTCHECK_SHORTPOINTER);
112		if (lg)
113			RETURN(pf,f,FMTCHECK_LONGPOINTER);
114		if (quad)
115			RETURN(pf,f,FMTCHECK_QUADPOINTER);
116		RETURN(pf,f,FMTCHECK_INTPOINTER);
117	}
118	if (strchr("DOU", *f)) {
119		if (sh + lg + quad + longdouble)
120			RETURN(pf,f,FMTCHECK_UNKNOWN);
121		RETURN(pf,f,FMTCHECK_LONG);
122	}
123	if (strchr("eEfg", *f)) {
124		if (longdouble)
125			RETURN(pf,f,FMTCHECK_LONGDOUBLE);
126		if (sh + lg + quad)
127			RETURN(pf,f,FMTCHECK_UNKNOWN);
128		RETURN(pf,f,FMTCHECK_DOUBLE);
129	}
130	if (*f == 'c') {
131		if (sh + lg + quad + longdouble)
132			RETURN(pf,f,FMTCHECK_UNKNOWN);
133		RETURN(pf,f,FMTCHECK_INT);
134	}
135	if (*f == 's') {
136		if (sh + lg + quad + longdouble)
137			RETURN(pf,f,FMTCHECK_UNKNOWN);
138		RETURN(pf,f,FMTCHECK_STRING);
139	}
140	if (*f == 'p') {
141		if (sh + lg + quad + longdouble)
142			RETURN(pf,f,FMTCHECK_UNKNOWN);
143		RETURN(pf,f,FMTCHECK_LONG);
144	}
145	RETURN(pf,f,FMTCHECK_UNKNOWN);
146	/*NOTREACHED*/
147}
148
149static EFT
150get_next_format_from_width(const char **pf)
151{
152	const char	*f;
153
154	f = *pf;
155	if (*f == '.') {
156		f++;
157		if (*f == '*') {
158			RETURN(pf,f,FMTCHECK_PRECISION);
159		}
160		/* eat any precision (empty is allowed) */
161		while (isdigit((unsigned char)*f)) f++;
162		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
163	}
164	RETURN(pf,f,get_next_format_from_precision(pf));
165	/*NOTREACHED*/
166}
167
168static EFT
169get_next_format(const char **pf, EFT eft)
170{
171	int		infmt;
172	const char	*f;
173
174	if (eft == FMTCHECK_WIDTH) {
175		(*pf)++;
176		return get_next_format_from_width(pf);
177	} else if (eft == FMTCHECK_PRECISION) {
178		(*pf)++;
179		return get_next_format_from_precision(pf);
180	}
181
182	f = *pf;
183	infmt = 0;
184	while (!infmt) {
185		f = strchr(f, '%');
186		if (f == NULL)
187			RETURN(pf,f,FMTCHECK_DONE);
188		f++;
189		if (!*f)
190			RETURN(pf,f,FMTCHECK_UNKNOWN);
191		if (*f != '%')
192			infmt = 1;
193		else
194			f++;
195	}
196
197	/* Eat any of the flags */
198	while (*f && (strchr("#0- +", *f)))
199		f++;
200
201	if (*f == '*') {
202		RETURN(pf,f,FMTCHECK_WIDTH);
203	}
204	/* eat any width */
205	while (isdigit((unsigned char)*f)) f++;
206	if (!*f) {
207		RETURN(pf,f,FMTCHECK_UNKNOWN);
208	}
209
210	RETURN(pf,f,get_next_format_from_width(pf));
211	/*NOTREACHED*/
212}
213
214const char *
215fmtcheck(const char *f1, const char *f2)
216{
217	const char	*f1p, *f2p;
218	EFT		f1t, f2t;
219
220	if (!f1) return f2;
221
222	f1p = f1;
223	f1t = FMTCHECK_START;
224	f2p = f2;
225	f2t = FMTCHECK_START;
226	while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
227		if (f1t == FMTCHECK_UNKNOWN)
228			return f2;
229		f2t = get_next_format(&f2p, f2t);
230		if (f1t != f2t)
231			return f2;
232	}
233	return f1;
234}
235