1*fd569112Srin /* $NetBSD: fmtcheck.c,v 1.16 2017/12/13 06:43:45 rin Exp $ */
2d00ebb12Sbriggs
3d00ebb12Sbriggs /*-
4d00ebb12Sbriggs * Copyright (c) 2000 The NetBSD Foundation, Inc.
5d00ebb12Sbriggs * All rights reserved.
6d00ebb12Sbriggs *
7d00ebb12Sbriggs * This code was contributed to The NetBSD Foundation by Allen Briggs.
8d00ebb12Sbriggs *
9d00ebb12Sbriggs * Redistribution and use in source and binary forms, with or without
10d00ebb12Sbriggs * modification, are permitted provided that the following conditions
11d00ebb12Sbriggs * are met:
12d00ebb12Sbriggs * 1. Redistributions of source code must retain the above copyright
13d00ebb12Sbriggs * notice, this list of conditions and the following disclaimer.
14d00ebb12Sbriggs * 2. Redistributions in binary form must reproduce the above copyright
15d00ebb12Sbriggs * notice, this list of conditions and the following disclaimer in the
16d00ebb12Sbriggs * documentation and/or other materials provided with the distribution.
17d00ebb12Sbriggs *
18d00ebb12Sbriggs * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19d00ebb12Sbriggs * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20d00ebb12Sbriggs * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21d00ebb12Sbriggs * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22d00ebb12Sbriggs * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23d00ebb12Sbriggs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24d00ebb12Sbriggs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25d00ebb12Sbriggs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26d00ebb12Sbriggs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27d00ebb12Sbriggs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28d00ebb12Sbriggs * POSSIBILITY OF SUCH DAMAGE.
29d00ebb12Sbriggs */
30d00ebb12Sbriggs
31d00ebb12Sbriggs #include <sys/cdefs.h>
32d00ebb12Sbriggs #if defined(LIBC_SCCS) && !defined(lint)
33*fd569112Srin __RCSID("$NetBSD: fmtcheck.c,v 1.16 2017/12/13 06:43:45 rin Exp $");
34d00ebb12Sbriggs #endif
35d00ebb12Sbriggs
36d00ebb12Sbriggs #include "namespace.h"
37d00ebb12Sbriggs
38f1ac0dd6Smatt #include <stdio.h>
39d00ebb12Sbriggs #include <string.h>
40d00ebb12Sbriggs #include <ctype.h>
41d00ebb12Sbriggs
42d00ebb12Sbriggs #ifdef __weak_alias
43d00ebb12Sbriggs __weak_alias(fmtcheck,__fmtcheck)
44d00ebb12Sbriggs #endif
45d00ebb12Sbriggs
46d00ebb12Sbriggs enum __e_fmtcheck_types {
47d00ebb12Sbriggs FMTCHECK_START,
48d00ebb12Sbriggs FMTCHECK_SHORT,
49d00ebb12Sbriggs FMTCHECK_INT,
50c084bfdfSrin FMTCHECK_WINTT,
51d00ebb12Sbriggs FMTCHECK_LONG,
52d00ebb12Sbriggs FMTCHECK_QUAD,
53c084bfdfSrin FMTCHECK_INTMAXT,
54efd7892aSrin FMTCHECK_PTRDIFFT,
55efd7892aSrin FMTCHECK_SIZET,
56e72cca96Sapb FMTCHECK_POINTER,
57c084bfdfSrin FMTCHECK_CHARPOINTER,
58d00ebb12Sbriggs FMTCHECK_SHORTPOINTER,
59d00ebb12Sbriggs FMTCHECK_INTPOINTER,
60d00ebb12Sbriggs FMTCHECK_LONGPOINTER,
61d00ebb12Sbriggs FMTCHECK_QUADPOINTER,
62c084bfdfSrin FMTCHECK_INTMAXTPOINTER,
63efd7892aSrin FMTCHECK_PTRDIFFTPOINTER,
64efd7892aSrin FMTCHECK_SIZETPOINTER,
65d00ebb12Sbriggs FMTCHECK_DOUBLE,
66d00ebb12Sbriggs FMTCHECK_LONGDOUBLE,
67d00ebb12Sbriggs FMTCHECK_STRING,
68c084bfdfSrin FMTCHECK_WSTRING,
69d00ebb12Sbriggs FMTCHECK_WIDTH,
70d00ebb12Sbriggs FMTCHECK_PRECISION,
71d00ebb12Sbriggs FMTCHECK_DONE,
72d00ebb12Sbriggs FMTCHECK_UNKNOWN
73d00ebb12Sbriggs };
74d00ebb12Sbriggs typedef enum __e_fmtcheck_types EFT;
75d00ebb12Sbriggs
76c084bfdfSrin enum e_modifier {
77c084bfdfSrin MOD_NONE,
78c084bfdfSrin MOD_CHAR,
79c084bfdfSrin MOD_SHORT,
80c084bfdfSrin MOD_LONG,
81c084bfdfSrin MOD_QUAD,
82c084bfdfSrin MOD_INTMAXT,
83c084bfdfSrin MOD_LONGDOUBLE,
84c084bfdfSrin MOD_PTRDIFFT,
85c084bfdfSrin MOD_SIZET,
86c084bfdfSrin };
87c084bfdfSrin
88d00ebb12Sbriggs #define RETURN(pf,f,r) do { \
89d00ebb12Sbriggs *(pf) = (f); \
90d00ebb12Sbriggs return r; \
91d00ebb12Sbriggs } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
92d00ebb12Sbriggs
93d00ebb12Sbriggs static EFT
get_next_format_from_precision(const char ** pf)94d00ebb12Sbriggs get_next_format_from_precision(const char **pf)
95d00ebb12Sbriggs {
96c084bfdfSrin enum e_modifier modifier;
97d00ebb12Sbriggs const char *f;
98d00ebb12Sbriggs
99d00ebb12Sbriggs f = *pf;
100d00ebb12Sbriggs switch (*f) {
101d00ebb12Sbriggs case 'h':
102d00ebb12Sbriggs f++;
103c084bfdfSrin if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
104c084bfdfSrin if (*f == 'h') {
105c084bfdfSrin f++;
106c084bfdfSrin modifier = MOD_CHAR;
107c084bfdfSrin } else {
108c084bfdfSrin modifier = MOD_SHORT;
109c084bfdfSrin }
110c084bfdfSrin break;
111c084bfdfSrin case 'j':
112c084bfdfSrin f++;
113c084bfdfSrin modifier = MOD_INTMAXT;
114d00ebb12Sbriggs break;
115d00ebb12Sbriggs case 'l':
116d00ebb12Sbriggs f++;
117d00ebb12Sbriggs if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
118d00ebb12Sbriggs if (*f == 'l') {
119d00ebb12Sbriggs f++;
120c084bfdfSrin modifier = MOD_QUAD;
121d00ebb12Sbriggs } else {
122c084bfdfSrin modifier = MOD_LONG;
123d00ebb12Sbriggs }
124d00ebb12Sbriggs break;
125d00ebb12Sbriggs case 'q':
126d00ebb12Sbriggs f++;
127c084bfdfSrin modifier = MOD_QUAD;
128d00ebb12Sbriggs break;
129efd7892aSrin case 't':
130efd7892aSrin f++;
131c084bfdfSrin modifier = MOD_PTRDIFFT;
132efd7892aSrin break;
133efd7892aSrin case 'z':
134efd7892aSrin f++;
135c084bfdfSrin modifier = MOD_SIZET;
136efd7892aSrin break;
137d00ebb12Sbriggs case 'L':
138d00ebb12Sbriggs f++;
139c084bfdfSrin modifier = MOD_LONGDOUBLE;
140d00ebb12Sbriggs break;
141801bf996Schristos #ifdef WIN32
142801bf996Schristos case 'I':
143801bf996Schristos f++;
144801bf996Schristos if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
145801bf996Schristos if (*f == '3' && f[1] == '2') {
146801bf996Schristos f += 2;
147c084bfdfSrin modifier = MOD_NONE;
148801bf996Schristos } else if (*f == '6' && f[1] == '4') {
149801bf996Schristos f += 2;
150c084bfdfSrin modifier = MOD_QUAD;
151801bf996Schristos }
152801bf996Schristos else {
153d2b4f0d1Srin #ifdef _WIN64
154c084bfdfSrin modifier = MOD_QUAD;
155d2b4f0d1Srin #else
156d2b4f0d1Srin modifier = MOD_NONE;
157801bf996Schristos #endif
158d2b4f0d1Srin }
159801bf996Schristos break;
160801bf996Schristos #endif
161d00ebb12Sbriggs default:
162c084bfdfSrin modifier = MOD_NONE;
163d00ebb12Sbriggs break;
164d00ebb12Sbriggs }
165d00ebb12Sbriggs if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
166d00ebb12Sbriggs if (strchr("diouxX", *f)) {
167c084bfdfSrin switch (modifier) {
168c084bfdfSrin case MOD_LONG:
169d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_LONG);
170c084bfdfSrin case MOD_QUAD:
171d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_QUAD);
172c084bfdfSrin case MOD_INTMAXT:
173c084bfdfSrin RETURN(pf,f,FMTCHECK_INTMAXT);
174c084bfdfSrin case MOD_PTRDIFFT:
175efd7892aSrin RETURN(pf,f,FMTCHECK_PTRDIFFT);
176c084bfdfSrin case MOD_SIZET:
177efd7892aSrin RETURN(pf,f,FMTCHECK_SIZET);
178c084bfdfSrin case MOD_CHAR:
179c084bfdfSrin case MOD_SHORT:
180c084bfdfSrin case MOD_NONE:
181d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_INT);
182c084bfdfSrin default:
183c084bfdfSrin RETURN(pf,f,FMTCHECK_UNKNOWN);
184c084bfdfSrin }
185d00ebb12Sbriggs }
186d00ebb12Sbriggs if (*f == 'n') {
187c084bfdfSrin switch (modifier) {
188c084bfdfSrin case MOD_CHAR:
189c084bfdfSrin RETURN(pf,f,FMTCHECK_CHARPOINTER);
190c084bfdfSrin case MOD_SHORT:
191d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_SHORTPOINTER);
192c084bfdfSrin case MOD_LONG:
193d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_LONGPOINTER);
194c084bfdfSrin case MOD_QUAD:
195d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_QUADPOINTER);
196c084bfdfSrin case MOD_INTMAXT:
197c084bfdfSrin RETURN(pf,f,FMTCHECK_INTMAXTPOINTER);
198c084bfdfSrin case MOD_PTRDIFFT:
199efd7892aSrin RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
200c084bfdfSrin case MOD_SIZET:
201efd7892aSrin RETURN(pf,f,FMTCHECK_SIZETPOINTER);
202c084bfdfSrin case MOD_NONE:
203d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_INTPOINTER);
204c084bfdfSrin default:
205c084bfdfSrin RETURN(pf,f,FMTCHECK_UNKNOWN);
206c084bfdfSrin }
207d00ebb12Sbriggs }
208d00ebb12Sbriggs if (strchr("DOU", *f)) {
209c084bfdfSrin if (modifier != MOD_NONE)
210d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_UNKNOWN);
211d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_LONG);
212d00ebb12Sbriggs }
213efd7892aSrin if (strchr("aAeEfFgG", *f)) {
214c084bfdfSrin switch (modifier) {
215c084bfdfSrin case MOD_LONGDOUBLE:
216d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_LONGDOUBLE);
217c084bfdfSrin case MOD_LONG:
218c084bfdfSrin case MOD_NONE:
219d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_DOUBLE);
220c084bfdfSrin default:
221c084bfdfSrin RETURN(pf,f,FMTCHECK_UNKNOWN);
222c084bfdfSrin }
223d00ebb12Sbriggs }
224d00ebb12Sbriggs if (*f == 'c') {
225c084bfdfSrin switch (modifier) {
226c084bfdfSrin case MOD_LONG:
227c084bfdfSrin RETURN(pf,f,FMTCHECK_WINTT);
228c084bfdfSrin case MOD_NONE:
229d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_INT);
230c084bfdfSrin default:
231c084bfdfSrin RETURN(pf,f,FMTCHECK_UNKNOWN);
232c084bfdfSrin }
233c084bfdfSrin }
234c084bfdfSrin if (*f == 'C') {
235c084bfdfSrin if (modifier != MOD_NONE)
236c084bfdfSrin RETURN(pf,f,FMTCHECK_UNKNOWN);
237c084bfdfSrin RETURN(pf,f,FMTCHECK_WINTT);
238d00ebb12Sbriggs }
239d00ebb12Sbriggs if (*f == 's') {
240c084bfdfSrin switch (modifier) {
241c084bfdfSrin case MOD_LONG:
242c084bfdfSrin RETURN(pf,f,FMTCHECK_WSTRING);
243c084bfdfSrin case MOD_NONE:
244d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_STRING);
245c084bfdfSrin default:
246c084bfdfSrin RETURN(pf,f,FMTCHECK_UNKNOWN);
247c084bfdfSrin }
248c084bfdfSrin }
249c084bfdfSrin if (*f == 'S') {
250c084bfdfSrin if (modifier != MOD_NONE)
251c084bfdfSrin RETURN(pf,f,FMTCHECK_UNKNOWN);
252c084bfdfSrin RETURN(pf,f,FMTCHECK_WSTRING);
253d00ebb12Sbriggs }
254d00ebb12Sbriggs if (*f == 'p') {
255c084bfdfSrin if (modifier != MOD_NONE)
256d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_UNKNOWN);
257e72cca96Sapb RETURN(pf,f,FMTCHECK_POINTER);
258d00ebb12Sbriggs }
259d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_UNKNOWN);
260d00ebb12Sbriggs /*NOTREACHED*/
261d00ebb12Sbriggs }
262d00ebb12Sbriggs
263d00ebb12Sbriggs static EFT
get_next_format_from_width(const char ** pf)264d00ebb12Sbriggs get_next_format_from_width(const char **pf)
265d00ebb12Sbriggs {
266d00ebb12Sbriggs const char *f;
267d00ebb12Sbriggs
268d00ebb12Sbriggs f = *pf;
269d00ebb12Sbriggs if (*f == '.') {
270d00ebb12Sbriggs f++;
271d00ebb12Sbriggs if (*f == '*') {
272d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_PRECISION);
273d00ebb12Sbriggs }
274d00ebb12Sbriggs /* eat any precision (empty is allowed) */
2751793b7ddSdsl while (isdigit((unsigned char)*f)) f++;
276d00ebb12Sbriggs if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
277d00ebb12Sbriggs }
278d00ebb12Sbriggs RETURN(pf,f,get_next_format_from_precision(pf));
279d00ebb12Sbriggs /*NOTREACHED*/
280d00ebb12Sbriggs }
281d00ebb12Sbriggs
282d00ebb12Sbriggs static EFT
get_next_format(const char ** pf,EFT eft)283d00ebb12Sbriggs get_next_format(const char **pf, EFT eft)
284d00ebb12Sbriggs {
285d00ebb12Sbriggs int infmt;
286d00ebb12Sbriggs const char *f;
287d00ebb12Sbriggs
288d00ebb12Sbriggs if (eft == FMTCHECK_WIDTH) {
289d00ebb12Sbriggs (*pf)++;
290d00ebb12Sbriggs return get_next_format_from_width(pf);
291d00ebb12Sbriggs } else if (eft == FMTCHECK_PRECISION) {
292d00ebb12Sbriggs (*pf)++;
293d00ebb12Sbriggs return get_next_format_from_precision(pf);
294d00ebb12Sbriggs }
295d00ebb12Sbriggs
296d00ebb12Sbriggs f = *pf;
297d00ebb12Sbriggs infmt = 0;
298d00ebb12Sbriggs while (!infmt) {
299d00ebb12Sbriggs f = strchr(f, '%');
300d00ebb12Sbriggs if (f == NULL)
301d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_DONE);
302d00ebb12Sbriggs f++;
303d00ebb12Sbriggs if (!*f)
304d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_UNKNOWN);
305d00ebb12Sbriggs if (*f != '%')
306d00ebb12Sbriggs infmt = 1;
307d00ebb12Sbriggs else
308d00ebb12Sbriggs f++;
309d00ebb12Sbriggs }
310d00ebb12Sbriggs
311d00ebb12Sbriggs /* Eat any of the flags */
31241130f53Srin while (*f && (strchr("#'0- +", *f)))
313d00ebb12Sbriggs f++;
314d00ebb12Sbriggs
315d00ebb12Sbriggs if (*f == '*') {
316d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_WIDTH);
317d00ebb12Sbriggs }
318d00ebb12Sbriggs /* eat any width */
3191793b7ddSdsl while (isdigit((unsigned char)*f)) f++;
320d00ebb12Sbriggs if (!*f) {
321d00ebb12Sbriggs RETURN(pf,f,FMTCHECK_UNKNOWN);
322d00ebb12Sbriggs }
323d00ebb12Sbriggs
324d00ebb12Sbriggs RETURN(pf,f,get_next_format_from_width(pf));
325d00ebb12Sbriggs /*NOTREACHED*/
326d00ebb12Sbriggs }
327d00ebb12Sbriggs
3284e11af46Sperry const char *
fmtcheck(const char * f1,const char * f2)3292c5b1650Sbriggs fmtcheck(const char *f1, const char *f2)
330d00ebb12Sbriggs {
331d00ebb12Sbriggs const char *f1p, *f2p;
332d00ebb12Sbriggs EFT f1t, f2t;
333d00ebb12Sbriggs
334d00ebb12Sbriggs if (!f1) return f2;
335d00ebb12Sbriggs
336d00ebb12Sbriggs f1p = f1;
337d00ebb12Sbriggs f1t = FMTCHECK_START;
338d00ebb12Sbriggs f2p = f2;
339d00ebb12Sbriggs f2t = FMTCHECK_START;
340d00ebb12Sbriggs while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
341d00ebb12Sbriggs if (f1t == FMTCHECK_UNKNOWN)
342d00ebb12Sbriggs return f2;
343d00ebb12Sbriggs f2t = get_next_format(&f2p, f2t);
344d00ebb12Sbriggs if (f1t != f2t)
345d00ebb12Sbriggs return f2;
346d00ebb12Sbriggs }
347d00ebb12Sbriggs return f1;
348d00ebb12Sbriggs }
349