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