xref: /minix/lib/libc/gen/fmtcheck.c (revision 0a6a1f1d)
1 /*	$NetBSD: fmtcheck.c,v 1.9 2014/06/14 08:18:24 apb 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 <sys/cdefs.h>
32 #if defined(LIBC_SCCS) && !defined(lint)
33 __RCSID("$NetBSD: fmtcheck.c,v 1.9 2014/06/14 08:18:24 apb Exp $");
34 #endif
35 
36 #include "namespace.h"
37 
38 #include <stdio.h>
39 #include <string.h>
40 #include <ctype.h>
41 
42 #ifdef __weak_alias
43 __weak_alias(fmtcheck,__fmtcheck)
44 #endif
45 
46 enum __e_fmtcheck_types {
47 	FMTCHECK_START,
48 	FMTCHECK_SHORT,
49 	FMTCHECK_INT,
50 	FMTCHECK_LONG,
51 	FMTCHECK_QUAD,
52 	FMTCHECK_POINTER,
53 	FMTCHECK_SHORTPOINTER,
54 	FMTCHECK_INTPOINTER,
55 	FMTCHECK_LONGPOINTER,
56 	FMTCHECK_QUADPOINTER,
57 	FMTCHECK_DOUBLE,
58 	FMTCHECK_LONGDOUBLE,
59 	FMTCHECK_STRING,
60 	FMTCHECK_WIDTH,
61 	FMTCHECK_PRECISION,
62 	FMTCHECK_DONE,
63 	FMTCHECK_UNKNOWN
64 };
65 typedef enum __e_fmtcheck_types EFT;
66 
67 #define RETURN(pf,f,r) do { \
68 			*(pf) = (f); \
69 			return r; \
70 		       } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
71 
72 static EFT
get_next_format_from_precision(const char ** pf)73 get_next_format_from_precision(const char **pf)
74 {
75 	int		sh, lg, quad, longdouble;
76 	const char	*f;
77 
78 	sh = lg = quad = longdouble = 0;
79 
80 	f = *pf;
81 	switch (*f) {
82 	case 'h':
83 		f++;
84 		sh = 1;
85 		break;
86 	case 'l':
87 		f++;
88 		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
89 		if (*f == 'l') {
90 			f++;
91 			quad = 1;
92 		} else {
93 			lg = 1;
94 		}
95 		break;
96 	case 'q':
97 		f++;
98 		quad = 1;
99 		break;
100 	case 'L':
101 		f++;
102 		longdouble = 1;
103 		break;
104 	default:
105 		break;
106 	}
107 	if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
108 	if (strchr("diouxX", *f)) {
109 		if (longdouble)
110 			RETURN(pf,f,FMTCHECK_UNKNOWN);
111 		if (lg)
112 			RETURN(pf,f,FMTCHECK_LONG);
113 		if (quad)
114 			RETURN(pf,f,FMTCHECK_QUAD);
115 		RETURN(pf,f,FMTCHECK_INT);
116 	}
117 	if (*f == 'n') {
118 		if (longdouble)
119 			RETURN(pf,f,FMTCHECK_UNKNOWN);
120 		if (sh)
121 			RETURN(pf,f,FMTCHECK_SHORTPOINTER);
122 		if (lg)
123 			RETURN(pf,f,FMTCHECK_LONGPOINTER);
124 		if (quad)
125 			RETURN(pf,f,FMTCHECK_QUADPOINTER);
126 		RETURN(pf,f,FMTCHECK_INTPOINTER);
127 	}
128 	if (strchr("DOU", *f)) {
129 		if (sh + lg + quad + longdouble)
130 			RETURN(pf,f,FMTCHECK_UNKNOWN);
131 		RETURN(pf,f,FMTCHECK_LONG);
132 	}
133 	if (strchr("eEfg", *f)) {
134 		if (longdouble)
135 			RETURN(pf,f,FMTCHECK_LONGDOUBLE);
136 		if (sh + lg + quad)
137 			RETURN(pf,f,FMTCHECK_UNKNOWN);
138 		RETURN(pf,f,FMTCHECK_DOUBLE);
139 	}
140 	if (*f == 'c') {
141 		if (sh + lg + quad + longdouble)
142 			RETURN(pf,f,FMTCHECK_UNKNOWN);
143 		RETURN(pf,f,FMTCHECK_INT);
144 	}
145 	if (*f == 's') {
146 		if (sh + lg + quad + longdouble)
147 			RETURN(pf,f,FMTCHECK_UNKNOWN);
148 		RETURN(pf,f,FMTCHECK_STRING);
149 	}
150 	if (*f == 'p') {
151 		if (sh + lg + quad + longdouble)
152 			RETURN(pf,f,FMTCHECK_UNKNOWN);
153 		RETURN(pf,f,FMTCHECK_POINTER);
154 	}
155 	RETURN(pf,f,FMTCHECK_UNKNOWN);
156 	/*NOTREACHED*/
157 }
158 
159 static EFT
get_next_format_from_width(const char ** pf)160 get_next_format_from_width(const char **pf)
161 {
162 	const char	*f;
163 
164 	f = *pf;
165 	if (*f == '.') {
166 		f++;
167 		if (*f == '*') {
168 			RETURN(pf,f,FMTCHECK_PRECISION);
169 		}
170 		/* eat any precision (empty is allowed) */
171 		while (isdigit((unsigned char)*f)) f++;
172 		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
173 	}
174 	RETURN(pf,f,get_next_format_from_precision(pf));
175 	/*NOTREACHED*/
176 }
177 
178 static EFT
get_next_format(const char ** pf,EFT eft)179 get_next_format(const char **pf, EFT eft)
180 {
181 	int		infmt;
182 	const char	*f;
183 
184 	if (eft == FMTCHECK_WIDTH) {
185 		(*pf)++;
186 		return get_next_format_from_width(pf);
187 	} else if (eft == FMTCHECK_PRECISION) {
188 		(*pf)++;
189 		return get_next_format_from_precision(pf);
190 	}
191 
192 	f = *pf;
193 	infmt = 0;
194 	while (!infmt) {
195 		f = strchr(f, '%');
196 		if (f == NULL)
197 			RETURN(pf,f,FMTCHECK_DONE);
198 		f++;
199 		if (!*f)
200 			RETURN(pf,f,FMTCHECK_UNKNOWN);
201 		if (*f != '%')
202 			infmt = 1;
203 		else
204 			f++;
205 	}
206 
207 	/* Eat any of the flags */
208 	while (*f && (strchr("#0- +", *f)))
209 		f++;
210 
211 	if (*f == '*') {
212 		RETURN(pf,f,FMTCHECK_WIDTH);
213 	}
214 	/* eat any width */
215 	while (isdigit((unsigned char)*f)) f++;
216 	if (!*f) {
217 		RETURN(pf,f,FMTCHECK_UNKNOWN);
218 	}
219 
220 	RETURN(pf,f,get_next_format_from_width(pf));
221 	/*NOTREACHED*/
222 }
223 
224 const char *
fmtcheck(const char * f1,const char * f2)225 fmtcheck(const char *f1, const char *f2)
226 {
227 	const char	*f1p, *f2p;
228 	EFT		f1t, f2t;
229 
230 	if (!f1) return f2;
231 
232 	f1p = f1;
233 	f1t = FMTCHECK_START;
234 	f2p = f2;
235 	f2t = FMTCHECK_START;
236 	while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
237 		if (f1t == FMTCHECK_UNKNOWN)
238 			return f2;
239 		f2t = get_next_format(&f2p, f2t);
240 		if (f1t != f2t)
241 			return f2;
242 	}
243 	return f1;
244 }
245