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;
94267843Sdelphij	default:
95267843Sdelphij		break;
96267843Sdelphij	}
97267843Sdelphij	if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
98267843Sdelphij	if (strchr("diouxX", *f)) {
99267843Sdelphij		if (longdouble)
100267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
101267843Sdelphij		if (lg)
102267843Sdelphij			RETURN(pf,f,FMTCHECK_LONG);
103267843Sdelphij		if (quad)
104267843Sdelphij			RETURN(pf,f,FMTCHECK_QUAD);
105267843Sdelphij		RETURN(pf,f,FMTCHECK_INT);
106267843Sdelphij	}
107267843Sdelphij	if (*f == 'n') {
108267843Sdelphij		if (longdouble)
109267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
110267843Sdelphij		if (sh)
111267843Sdelphij			RETURN(pf,f,FMTCHECK_SHORTPOINTER);
112267843Sdelphij		if (lg)
113267843Sdelphij			RETURN(pf,f,FMTCHECK_LONGPOINTER);
114267843Sdelphij		if (quad)
115267843Sdelphij			RETURN(pf,f,FMTCHECK_QUADPOINTER);
116267843Sdelphij		RETURN(pf,f,FMTCHECK_INTPOINTER);
117267843Sdelphij	}
118267843Sdelphij	if (strchr("DOU", *f)) {
119267843Sdelphij		if (sh + lg + quad + longdouble)
120267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
121267843Sdelphij		RETURN(pf,f,FMTCHECK_LONG);
122267843Sdelphij	}
123267843Sdelphij	if (strchr("eEfg", *f)) {
124267843Sdelphij		if (longdouble)
125267843Sdelphij			RETURN(pf,f,FMTCHECK_LONGDOUBLE);
126267843Sdelphij		if (sh + lg + quad)
127267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
128267843Sdelphij		RETURN(pf,f,FMTCHECK_DOUBLE);
129267843Sdelphij	}
130267843Sdelphij	if (*f == 'c') {
131267843Sdelphij		if (sh + lg + quad + longdouble)
132267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
133267843Sdelphij		RETURN(pf,f,FMTCHECK_INT);
134267843Sdelphij	}
135267843Sdelphij	if (*f == 's') {
136267843Sdelphij		if (sh + lg + quad + longdouble)
137267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
138267843Sdelphij		RETURN(pf,f,FMTCHECK_STRING);
139267843Sdelphij	}
140267843Sdelphij	if (*f == 'p') {
141267843Sdelphij		if (sh + lg + quad + longdouble)
142267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
143267843Sdelphij		RETURN(pf,f,FMTCHECK_LONG);
144267843Sdelphij	}
145267843Sdelphij	RETURN(pf,f,FMTCHECK_UNKNOWN);
146267843Sdelphij	/*NOTREACHED*/
147267843Sdelphij}
148267843Sdelphij
149267843Sdelphijstatic EFT
150267843Sdelphijget_next_format_from_width(const char **pf)
151267843Sdelphij{
152267843Sdelphij	const char	*f;
153267843Sdelphij
154267843Sdelphij	f = *pf;
155267843Sdelphij	if (*f == '.') {
156267843Sdelphij		f++;
157267843Sdelphij		if (*f == '*') {
158267843Sdelphij			RETURN(pf,f,FMTCHECK_PRECISION);
159267843Sdelphij		}
160267843Sdelphij		/* eat any precision (empty is allowed) */
161267843Sdelphij		while (isdigit((unsigned char)*f)) f++;
162267843Sdelphij		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
163267843Sdelphij	}
164267843Sdelphij	RETURN(pf,f,get_next_format_from_precision(pf));
165267843Sdelphij	/*NOTREACHED*/
166267843Sdelphij}
167267843Sdelphij
168267843Sdelphijstatic EFT
169267843Sdelphijget_next_format(const char **pf, EFT eft)
170267843Sdelphij{
171267843Sdelphij	int		infmt;
172267843Sdelphij	const char	*f;
173267843Sdelphij
174267843Sdelphij	if (eft == FMTCHECK_WIDTH) {
175267843Sdelphij		(*pf)++;
176267843Sdelphij		return get_next_format_from_width(pf);
177267843Sdelphij	} else if (eft == FMTCHECK_PRECISION) {
178267843Sdelphij		(*pf)++;
179267843Sdelphij		return get_next_format_from_precision(pf);
180267843Sdelphij	}
181267843Sdelphij
182267843Sdelphij	f = *pf;
183267843Sdelphij	infmt = 0;
184267843Sdelphij	while (!infmt) {
185267843Sdelphij		f = strchr(f, '%');
186267843Sdelphij		if (f == NULL)
187267843Sdelphij			RETURN(pf,f,FMTCHECK_DONE);
188267843Sdelphij		f++;
189267843Sdelphij		if (!*f)
190267843Sdelphij			RETURN(pf,f,FMTCHECK_UNKNOWN);
191267843Sdelphij		if (*f != '%')
192267843Sdelphij			infmt = 1;
193267843Sdelphij		else
194267843Sdelphij			f++;
195267843Sdelphij	}
196267843Sdelphij
197267843Sdelphij	/* Eat any of the flags */
198267843Sdelphij	while (*f && (strchr("#0- +", *f)))
199267843Sdelphij		f++;
200267843Sdelphij
201267843Sdelphij	if (*f == '*') {
202267843Sdelphij		RETURN(pf,f,FMTCHECK_WIDTH);
203267843Sdelphij	}
204267843Sdelphij	/* eat any width */
205267843Sdelphij	while (isdigit((unsigned char)*f)) f++;
206267843Sdelphij	if (!*f) {
207267843Sdelphij		RETURN(pf,f,FMTCHECK_UNKNOWN);
208267843Sdelphij	}
209267843Sdelphij
210267843Sdelphij	RETURN(pf,f,get_next_format_from_width(pf));
211267843Sdelphij	/*NOTREACHED*/
212267843Sdelphij}
213267843Sdelphij
214267843Sdelphijconst char *
215267843Sdelphijfmtcheck(const char *f1, const char *f2)
216267843Sdelphij{
217267843Sdelphij	const char	*f1p, *f2p;
218267843Sdelphij	EFT		f1t, f2t;
219267843Sdelphij
220267843Sdelphij	if (!f1) return f2;
221267843Sdelphij
222267843Sdelphij	f1p = f1;
223267843Sdelphij	f1t = FMTCHECK_START;
224267843Sdelphij	f2p = f2;
225267843Sdelphij	f2t = FMTCHECK_START;
226267843Sdelphij	while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
227267843Sdelphij		if (f1t == FMTCHECK_UNKNOWN)
228267843Sdelphij			return f2;
229267843Sdelphij		f2t = get_next_format(&f2p, f2t);
230267843Sdelphij		if (f1t != f2t)
231267843Sdelphij			return f2;
232267843Sdelphij	}
233267843Sdelphij	return f1;
234267843Sdelphij}
235