xref: /freebsd/contrib/file/src/fmtcheck.c (revision 57718be8fa0bd5edc11ab9a72e68cc71982939a6)
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 
37 enum __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 };
55 typedef 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 
62 static EFT
63 get_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 	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 
149 static EFT
150 get_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 
168 static EFT
169 get_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 
214 const char *
215 fmtcheck(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