1267843Sdelphij/*	$NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp $	*/
2267843Sdelphij
3267843Sdelphij/*-
4267843Sdelphij * Copyright (c) 2000 The NetBSD Foundation, Inc.
5267843Sdelphij * All rights reserved.
6267843Sdelphij *
7267843Sdelphij * This code was contributed to The NetBSD Foundation by Allen Briggs.
8267843Sdelphij *
9267843Sdelphij * Redistribution and use in source and binary forms, with or without
10267843Sdelphij * modification, are permitted provided that the following conditions
11267843Sdelphij * are met:
12267843Sdelphij * 1. Redistributions of source code must retain the above copyright
13267843Sdelphij *    notice, this list of conditions and the following disclaimer.
14267843Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
15267843Sdelphij *    notice, this list of conditions and the following disclaimer in the
16267843Sdelphij *    documentation and/or other materials provided with the distribution.
17267843Sdelphij *
18267843Sdelphij * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19267843Sdelphij * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20267843Sdelphij * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21267843Sdelphij * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22267843Sdelphij * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23267843Sdelphij * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24267843Sdelphij * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25267843Sdelphij * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26267843Sdelphij * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27267843Sdelphij * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28267843Sdelphij * POSSIBILITY OF SUCH DAMAGE.
29267843Sdelphij */
30267843Sdelphij
31267843Sdelphij#include "file.h"
32267843Sdelphij
33267843Sdelphij#include <stdio.h>
34267843Sdelphij#include <string.h>
35267843Sdelphij#include <ctype.h>
36267843Sdelphij
37267843Sdelphijenum __e_fmtcheck_types {
38267843Sdelphij	FMTCHECK_START,
39267843Sdelphij	FMTCHECK_SHORT,
40267843Sdelphij	FMTCHECK_INT,
41267843Sdelphij	FMTCHECK_LONG,
42267843Sdelphij	FMTCHECK_QUAD,
43267843Sdelphij	FMTCHECK_SHORTPOINTER,
44267843Sdelphij	FMTCHECK_INTPOINTER,
45267843Sdelphij	FMTCHECK_LONGPOINTER,
46267843Sdelphij	FMTCHECK_QUADPOINTER,
47267843Sdelphij	FMTCHECK_DOUBLE,
48267843Sdelphij	FMTCHECK_LONGDOUBLE,
49267843Sdelphij	FMTCHECK_STRING,
50267843Sdelphij	FMTCHECK_WIDTH,
51267843Sdelphij	FMTCHECK_PRECISION,
52267843Sdelphij	FMTCHECK_DONE,
53267843Sdelphij	FMTCHECK_UNKNOWN
54267843Sdelphij};
55267843Sdelphijtypedef enum __e_fmtcheck_types EFT;
56267843Sdelphij
57267843Sdelphij#define RETURN(pf,f,r) do { \
58267843Sdelphij			*(pf) = (f); \
59267843Sdelphij			return r; \
60267843Sdelphij		       } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
61267843Sdelphij
62267843Sdelphijstatic EFT
63267843Sdelphijget_next_format_from_precision(const char **pf)
64267843Sdelphij{
65267843Sdelphij	int		sh, lg, quad, longdouble;
66267843Sdelphij	const char	*f;
67267843Sdelphij
68267843Sdelphij	sh = lg = quad = longdouble = 0;
69267843Sdelphij
70267843Sdelphij	f = *pf;
71267843Sdelphij	switch (*f) {
72267843Sdelphij	case 'h':
73267843Sdelphij		f++;
74267843Sdelphij		sh = 1;
75267843Sdelphij		break;
76267843Sdelphij	case 'l':
77267843Sdelphij		f++;
78267843Sdelphij		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
79267843Sdelphij		if (*f == 'l') {
80267843Sdelphij			f++;
81267843Sdelphij			quad = 1;
82267843Sdelphij		} else {
83267843Sdelphij			lg = 1;
84267843Sdelphij		}
85267843Sdelphij		break;
86267843Sdelphij	case 'q':
87267843Sdelphij		f++;
88267843Sdelphij		quad = 1;
89267843Sdelphij		break;
90267843Sdelphij	case 'L':
91267843Sdelphij		f++;
92267843Sdelphij		longdouble = 1;
93267843Sdelphij		break;
94298192Sdelphij#ifdef WIN32
95298192Sdelphij	case 'I':
96298192Sdelphij		f++;
97298192Sdelphij		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
98298192Sdelphij		if (*f == '3' && f[1] == '2') {
99298192Sdelphij			f += 2;
100298192Sdelphij		} else if (*f == '6' && f[1] == '4') {
101298192Sdelphij			f += 2;
102298192Sdelphij			quad = 1;
103298192Sdelphij		}
104298192Sdelphij#ifdef _WIN64
105298192Sdelphij		else {
106298192Sdelphij			quad = 1;
107298192Sdelphij		}
108298192Sdelphij#endif
109298192Sdelphij		break;
110298192Sdelphij#endif
111267843Sdelphij	default:
112267843Sdelphij		break;
113267843Sdelphij	}
114267843Sdelphij	if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
115267843Sdelphij	if (strchr("diouxX", *f)) {
116267843Sdelphij		if (longdouble)
117267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
118267843Sdelphij		if (lg)
119267843Sdelphij			RETURN(pf,f,FMTCHECK_LONG);
120267843Sdelphij		if (quad)
121267843Sdelphij			RETURN(pf,f,FMTCHECK_QUAD);
122267843Sdelphij		RETURN(pf,f,FMTCHECK_INT);
123267843Sdelphij	}
124267843Sdelphij	if (*f == 'n') {
125267843Sdelphij		if (longdouble)
126267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
127267843Sdelphij		if (sh)
128267843Sdelphij			RETURN(pf,f,FMTCHECK_SHORTPOINTER);
129267843Sdelphij		if (lg)
130267843Sdelphij			RETURN(pf,f,FMTCHECK_LONGPOINTER);
131267843Sdelphij		if (quad)
132267843Sdelphij			RETURN(pf,f,FMTCHECK_QUADPOINTER);
133267843Sdelphij		RETURN(pf,f,FMTCHECK_INTPOINTER);
134267843Sdelphij	}
135267843Sdelphij	if (strchr("DOU", *f)) {
136267843Sdelphij		if (sh + lg + quad + longdouble)
137267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
138267843Sdelphij		RETURN(pf,f,FMTCHECK_LONG);
139267843Sdelphij	}
140267843Sdelphij	if (strchr("eEfg", *f)) {
141267843Sdelphij		if (longdouble)
142267843Sdelphij			RETURN(pf,f,FMTCHECK_LONGDOUBLE);
143267843Sdelphij		if (sh + lg + quad)
144267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
145267843Sdelphij		RETURN(pf,f,FMTCHECK_DOUBLE);
146267843Sdelphij	}
147267843Sdelphij	if (*f == 'c') {
148267843Sdelphij		if (sh + lg + quad + longdouble)
149267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
150267843Sdelphij		RETURN(pf,f,FMTCHECK_INT);
151267843Sdelphij	}
152267843Sdelphij	if (*f == 's') {
153267843Sdelphij		if (sh + lg + quad + longdouble)
154267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
155267843Sdelphij		RETURN(pf,f,FMTCHECK_STRING);
156267843Sdelphij	}
157267843Sdelphij	if (*f == 'p') {
158267843Sdelphij		if (sh + lg + quad + longdouble)
159267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
160267843Sdelphij		RETURN(pf,f,FMTCHECK_LONG);
161267843Sdelphij	}
162267843Sdelphij	RETURN(pf,f,FMTCHECK_UNKNOWN);
163267843Sdelphij	/*NOTREACHED*/
164267843Sdelphij}
165267843Sdelphij
166267843Sdelphijstatic EFT
167267843Sdelphijget_next_format_from_width(const char **pf)
168267843Sdelphij{
169267843Sdelphij	const char	*f;
170267843Sdelphij
171267843Sdelphij	f = *pf;
172267843Sdelphij	if (*f == '.') {
173267843Sdelphij		f++;
174267843Sdelphij		if (*f == '*') {
175267843Sdelphij			RETURN(pf,f,FMTCHECK_PRECISION);
176267843Sdelphij		}
177267843Sdelphij		/* eat any precision (empty is allowed) */
178267843Sdelphij		while (isdigit((unsigned char)*f)) f++;
179267843Sdelphij		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
180267843Sdelphij	}
181267843Sdelphij	RETURN(pf,f,get_next_format_from_precision(pf));
182267843Sdelphij	/*NOTREACHED*/
183267843Sdelphij}
184267843Sdelphij
185267843Sdelphijstatic EFT
186267843Sdelphijget_next_format(const char **pf, EFT eft)
187267843Sdelphij{
188267843Sdelphij	int		infmt;
189267843Sdelphij	const char	*f;
190267843Sdelphij
191267843Sdelphij	if (eft == FMTCHECK_WIDTH) {
192267843Sdelphij		(*pf)++;
193267843Sdelphij		return get_next_format_from_width(pf);
194267843Sdelphij	} else if (eft == FMTCHECK_PRECISION) {
195267843Sdelphij		(*pf)++;
196267843Sdelphij		return get_next_format_from_precision(pf);
197267843Sdelphij	}
198267843Sdelphij
199267843Sdelphij	f = *pf;
200267843Sdelphij	infmt = 0;
201267843Sdelphij	while (!infmt) {
202267843Sdelphij		f = strchr(f, '%');
203267843Sdelphij		if (f == NULL)
204267843Sdelphij			RETURN(pf,f,FMTCHECK_DONE);
205267843Sdelphij		f++;
206267843Sdelphij		if (!*f)
207267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
208267843Sdelphij		if (*f != '%')
209267843Sdelphij			infmt = 1;
210267843Sdelphij		else
211267843Sdelphij			f++;
212267843Sdelphij	}
213267843Sdelphij
214267843Sdelphij	/* Eat any of the flags */
215267843Sdelphij	while (*f && (strchr("#0- +", *f)))
216267843Sdelphij		f++;
217267843Sdelphij
218267843Sdelphij	if (*f == '*') {
219267843Sdelphij		RETURN(pf,f,FMTCHECK_WIDTH);
220267843Sdelphij	}
221267843Sdelphij	/* eat any width */
222267843Sdelphij	while (isdigit((unsigned char)*f)) f++;
223267843Sdelphij	if (!*f) {
224267843Sdelphij		RETURN(pf,f,FMTCHECK_UNKNOWN);
225267843Sdelphij	}
226267843Sdelphij
227267843Sdelphij	RETURN(pf,f,get_next_format_from_width(pf));
228267843Sdelphij	/*NOTREACHED*/
229267843Sdelphij}
230267843Sdelphij
231267843Sdelphijconst char *
232267843Sdelphijfmtcheck(const char *f1, const char *f2)
233267843Sdelphij{
234267843Sdelphij	const char	*f1p, *f2p;
235267843Sdelphij	EFT		f1t, f2t;
236267843Sdelphij
237267843Sdelphij	if (!f1) return f2;
238354939Sdelphij
239267843Sdelphij	f1p = f1;
240267843Sdelphij	f1t = FMTCHECK_START;
241267843Sdelphij	f2p = f2;
242267843Sdelphij	f2t = FMTCHECK_START;
243267843Sdelphij	while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
244267843Sdelphij		if (f1t == FMTCHECK_UNKNOWN)
245267843Sdelphij			return f2;
246267843Sdelphij		f2t = get_next_format(&f2p, f2t);
247267843Sdelphij		if (f1t != f2t)
248267843Sdelphij			return f2;
249267843Sdelphij	}
250267843Sdelphij	return f1;
251267843Sdelphij}
252