xref: /freebsd-src/lib/libc/gen/fmtcheck.c (revision 559a218c9b257775fb249b67945fe4a05b7a6b9f)
1eb4bd20cSXin LI /*	$NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp $	*/
2eb4bd20cSXin LI 
33d090549SKris Kennaway /*-
4*b61a5730SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
5d915a14eSPedro F. Giffuni  *
63d090549SKris Kennaway  * Copyright (c) 2000 The NetBSD Foundation, Inc.
73d090549SKris Kennaway  * All rights reserved.
83d090549SKris Kennaway  *
93d090549SKris Kennaway  * This code was contributed to The NetBSD Foundation by Allen Briggs.
103d090549SKris Kennaway  *
113d090549SKris Kennaway  * Redistribution and use in source and binary forms, with or without
123d090549SKris Kennaway  * modification, are permitted provided that the following conditions
133d090549SKris Kennaway  * are met:
143d090549SKris Kennaway  * 1. Redistributions of source code must retain the above copyright
153d090549SKris Kennaway  *    notice, this list of conditions and the following disclaimer.
163d090549SKris Kennaway  * 2. Redistributions in binary form must reproduce the above copyright
173d090549SKris Kennaway  *    notice, this list of conditions and the following disclaimer in the
183d090549SKris Kennaway  *    documentation and/or other materials provided with the distribution.
193d090549SKris Kennaway  *
203d090549SKris Kennaway  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
213d090549SKris Kennaway  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
223d090549SKris Kennaway  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
233d090549SKris Kennaway  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
243d090549SKris Kennaway  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
253d090549SKris Kennaway  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
263d090549SKris Kennaway  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
273d090549SKris Kennaway  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
283d090549SKris Kennaway  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
293d090549SKris Kennaway  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
303d090549SKris Kennaway  * POSSIBILITY OF SUCH DAMAGE.
313d090549SKris Kennaway  */
323d090549SKris Kennaway 
333d090549SKris Kennaway #include <stdio.h>
343d090549SKris Kennaway #include <string.h>
353d090549SKris Kennaway #include <ctype.h>
363d090549SKris Kennaway 
3753154da0SDaniel Eischen __weak_reference(__fmtcheck, fmtcheck);
38d5bf9eb5SCraig Rodrigues const char * __fmtcheck(const char *, const char *);
393d090549SKris Kennaway 
403d090549SKris Kennaway enum __e_fmtcheck_types {
413d090549SKris Kennaway 	FMTCHECK_START,
423d090549SKris Kennaway 	FMTCHECK_SHORT,
433d090549SKris Kennaway 	FMTCHECK_INT,
44cc4c35b9SDavid Schultz 	FMTCHECK_WINTT,
453d090549SKris Kennaway 	FMTCHECK_LONG,
463d090549SKris Kennaway 	FMTCHECK_QUAD,
47cc4c35b9SDavid Schultz 	FMTCHECK_INTMAXT,
48ec045e41SDavid Schultz 	FMTCHECK_PTRDIFFT,
49ec045e41SDavid Schultz 	FMTCHECK_SIZET,
50cc4c35b9SDavid Schultz 	FMTCHECK_CHARPOINTER,
513d090549SKris Kennaway 	FMTCHECK_SHORTPOINTER,
523d090549SKris Kennaway 	FMTCHECK_INTPOINTER,
533d090549SKris Kennaway 	FMTCHECK_LONGPOINTER,
543d090549SKris Kennaway 	FMTCHECK_QUADPOINTER,
55cc4c35b9SDavid Schultz 	FMTCHECK_INTMAXTPOINTER,
56ec045e41SDavid Schultz 	FMTCHECK_PTRDIFFTPOINTER,
57ec045e41SDavid Schultz 	FMTCHECK_SIZETPOINTER,
5838d17374SDavid Schultz #ifndef NO_FLOATING_POINT
593d090549SKris Kennaway 	FMTCHECK_DOUBLE,
603d090549SKris Kennaway 	FMTCHECK_LONGDOUBLE,
6138d17374SDavid Schultz #endif
623d090549SKris Kennaway 	FMTCHECK_STRING,
63cc4c35b9SDavid Schultz 	FMTCHECK_WSTRING,
643d090549SKris Kennaway 	FMTCHECK_WIDTH,
653d090549SKris Kennaway 	FMTCHECK_PRECISION,
663d090549SKris Kennaway 	FMTCHECK_DONE,
673d090549SKris Kennaway 	FMTCHECK_UNKNOWN
683d090549SKris Kennaway };
693d090549SKris Kennaway typedef enum __e_fmtcheck_types EFT;
703d090549SKris Kennaway 
71cc4c35b9SDavid Schultz enum e_modifier {
72cc4c35b9SDavid Schultz 	MOD_NONE,
73cc4c35b9SDavid Schultz 	MOD_CHAR,
74cc4c35b9SDavid Schultz 	MOD_SHORT,
75cc4c35b9SDavid Schultz 	MOD_LONG,
76cc4c35b9SDavid Schultz 	MOD_QUAD,
77cc4c35b9SDavid Schultz 	MOD_INTMAXT,
78cc4c35b9SDavid Schultz 	MOD_LONGDOUBLE,
79cc4c35b9SDavid Schultz 	MOD_PTRDIFFT,
80cc4c35b9SDavid Schultz 	MOD_SIZET,
81cc4c35b9SDavid Schultz };
82cc4c35b9SDavid Schultz 
833d090549SKris Kennaway #define RETURN(pf,f,r) do { \
843d090549SKris Kennaway 			*(pf) = (f); \
853d090549SKris Kennaway 			return r; \
863d090549SKris Kennaway 		       } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
873d090549SKris Kennaway 
883d090549SKris Kennaway static EFT
get_next_format_from_precision(const char ** pf)893d090549SKris Kennaway get_next_format_from_precision(const char **pf)
903d090549SKris Kennaway {
91cc4c35b9SDavid Schultz 	enum e_modifier	modifier;
923d090549SKris Kennaway 	const char	*f;
933d090549SKris Kennaway 
943d090549SKris Kennaway 	f = *pf;
953d090549SKris Kennaway 	switch (*f) {
963d090549SKris Kennaway 	case 'h':
973d090549SKris Kennaway 		f++;
98cc4c35b9SDavid Schultz 		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
99cc4c35b9SDavid Schultz 		if (*f == 'h') {
100cc4c35b9SDavid Schultz 			f++;
101cc4c35b9SDavid Schultz 			modifier = MOD_CHAR;
102cc4c35b9SDavid Schultz 		} else {
103cc4c35b9SDavid Schultz 			modifier = MOD_SHORT;
104cc4c35b9SDavid Schultz 		}
105cc4c35b9SDavid Schultz 		break;
106cc4c35b9SDavid Schultz 	case 'j':
107cc4c35b9SDavid Schultz 		f++;
108cc4c35b9SDavid Schultz 		modifier = MOD_INTMAXT;
1093d090549SKris Kennaway 		break;
1103d090549SKris Kennaway 	case 'l':
1113d090549SKris Kennaway 		f++;
1123d090549SKris Kennaway 		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
1133d090549SKris Kennaway 		if (*f == 'l') {
1143d090549SKris Kennaway 			f++;
115cc4c35b9SDavid Schultz 			modifier = MOD_QUAD;
1163d090549SKris Kennaway 		} else {
117cc4c35b9SDavid Schultz 			modifier = MOD_LONG;
1183d090549SKris Kennaway 		}
1193d090549SKris Kennaway 		break;
1203d090549SKris Kennaway 	case 'q':
1213d090549SKris Kennaway 		f++;
122cc4c35b9SDavid Schultz 		modifier = MOD_QUAD;
1233d090549SKris Kennaway 		break;
124ec045e41SDavid Schultz 	case 't':
125ec045e41SDavid Schultz 		f++;
126cc4c35b9SDavid Schultz 		modifier = MOD_PTRDIFFT;
127ec045e41SDavid Schultz 		break;
128ec045e41SDavid Schultz 	case 'z':
129ec045e41SDavid Schultz 		f++;
130cc4c35b9SDavid Schultz 		modifier = MOD_SIZET;
131ec045e41SDavid Schultz 		break;
1323d090549SKris Kennaway 	case 'L':
1333d090549SKris Kennaway 		f++;
134cc4c35b9SDavid Schultz 		modifier = MOD_LONGDOUBLE;
1353d090549SKris Kennaway 		break;
1363d090549SKris Kennaway 	default:
137cc4c35b9SDavid Schultz 		modifier = MOD_NONE;
1383d090549SKris Kennaway 		break;
1393d090549SKris Kennaway 	}
1403d090549SKris Kennaway 	if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
1413d090549SKris Kennaway 	if (strchr("diouxX", *f)) {
142cc4c35b9SDavid Schultz 		switch (modifier) {
143cc4c35b9SDavid Schultz 		case MOD_LONG:
1443d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_LONG);
145cc4c35b9SDavid Schultz 		case MOD_QUAD:
1463d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_QUAD);
147cc4c35b9SDavid Schultz 		case MOD_INTMAXT:
148cc4c35b9SDavid Schultz 			RETURN(pf,f,FMTCHECK_INTMAXT);
149cc4c35b9SDavid Schultz 		case MOD_PTRDIFFT:
150ec045e41SDavid Schultz 			RETURN(pf,f,FMTCHECK_PTRDIFFT);
151cc4c35b9SDavid Schultz 		case MOD_SIZET:
152ec045e41SDavid Schultz 			RETURN(pf,f,FMTCHECK_SIZET);
153cc4c35b9SDavid Schultz 		case MOD_CHAR:
154cc4c35b9SDavid Schultz 		case MOD_SHORT:
155cc4c35b9SDavid Schultz 		case MOD_NONE:
1563d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_INT);
157cc4c35b9SDavid Schultz 		default:
158cc4c35b9SDavid Schultz 			RETURN(pf,f,FMTCHECK_UNKNOWN);
159cc4c35b9SDavid Schultz 		}
1603d090549SKris Kennaway 	}
1613d090549SKris Kennaway 	if (*f == 'n') {
162cc4c35b9SDavid Schultz 		switch (modifier) {
163cc4c35b9SDavid Schultz 		case MOD_CHAR:
164cc4c35b9SDavid Schultz 			RETURN(pf,f,FMTCHECK_CHARPOINTER);
165cc4c35b9SDavid Schultz 		case MOD_SHORT:
1663d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_SHORTPOINTER);
167cc4c35b9SDavid Schultz 		case MOD_LONG:
1683d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_LONGPOINTER);
169cc4c35b9SDavid Schultz 		case MOD_QUAD:
1703d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_QUADPOINTER);
171cc4c35b9SDavid Schultz 		case MOD_INTMAXT:
172cc4c35b9SDavid Schultz 			RETURN(pf,f,FMTCHECK_INTMAXTPOINTER);
173cc4c35b9SDavid Schultz 		case MOD_PTRDIFFT:
174ec045e41SDavid Schultz 			RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
175cc4c35b9SDavid Schultz 		case MOD_SIZET:
176ec045e41SDavid Schultz 			RETURN(pf,f,FMTCHECK_SIZETPOINTER);
177cc4c35b9SDavid Schultz 		case MOD_NONE:
1783d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_INTPOINTER);
179cc4c35b9SDavid Schultz 		default:
180cc4c35b9SDavid Schultz 			RETURN(pf,f,FMTCHECK_UNKNOWN);
181cc4c35b9SDavid Schultz 		}
1823d090549SKris Kennaway 	}
1833d090549SKris Kennaway 	if (strchr("DOU", *f)) {
184cc4c35b9SDavid Schultz 		if (modifier != MOD_NONE)
1853d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_UNKNOWN);
1863d090549SKris Kennaway 		RETURN(pf,f,FMTCHECK_LONG);
1873d090549SKris Kennaway 	}
18838d17374SDavid Schultz #ifndef NO_FLOATING_POINT
189ec045e41SDavid Schultz 	if (strchr("aAeEfFgG", *f)) {
190cc4c35b9SDavid Schultz 		switch (modifier) {
191cc4c35b9SDavid Schultz 		case MOD_LONGDOUBLE:
1923d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_LONGDOUBLE);
193cc4c35b9SDavid Schultz 		case MOD_LONG:
194cc4c35b9SDavid Schultz 		case MOD_NONE:
1953d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_DOUBLE);
196cc4c35b9SDavid Schultz 		default:
197cc4c35b9SDavid Schultz 			RETURN(pf,f,FMTCHECK_UNKNOWN);
198cc4c35b9SDavid Schultz 		}
1993d090549SKris Kennaway 	}
20038d17374SDavid Schultz #endif
2013d090549SKris Kennaway 	if (*f == 'c') {
202cc4c35b9SDavid Schultz 		switch (modifier) {
203cc4c35b9SDavid Schultz 		case MOD_LONG:
204cc4c35b9SDavid Schultz 			RETURN(pf,f,FMTCHECK_WINTT);
205cc4c35b9SDavid Schultz 		case MOD_NONE:
2063d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_INT);
207cc4c35b9SDavid Schultz 		default:
208cc4c35b9SDavid Schultz 			RETURN(pf,f,FMTCHECK_UNKNOWN);
209cc4c35b9SDavid Schultz 		}
210cc4c35b9SDavid Schultz 	}
211cc4c35b9SDavid Schultz 	if (*f == 'C') {
212cc4c35b9SDavid Schultz 		if (modifier != MOD_NONE)
213cc4c35b9SDavid Schultz 			RETURN(pf,f,FMTCHECK_UNKNOWN);
214cc4c35b9SDavid Schultz 		RETURN(pf,f,FMTCHECK_WINTT);
2153d090549SKris Kennaway 	}
2163d090549SKris Kennaway 	if (*f == 's') {
217cc4c35b9SDavid Schultz 		switch (modifier) {
218cc4c35b9SDavid Schultz 		case MOD_LONG:
219cc4c35b9SDavid Schultz 			RETURN(pf,f,FMTCHECK_WSTRING);
220cc4c35b9SDavid Schultz 		case MOD_NONE:
2213d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_STRING);
222cc4c35b9SDavid Schultz 		default:
223cc4c35b9SDavid Schultz 			RETURN(pf,f,FMTCHECK_UNKNOWN);
224cc4c35b9SDavid Schultz 		}
225cc4c35b9SDavid Schultz 	}
226cc4c35b9SDavid Schultz 	if (*f == 'S') {
227cc4c35b9SDavid Schultz 		if (modifier != MOD_NONE)
228cc4c35b9SDavid Schultz 			RETURN(pf,f,FMTCHECK_UNKNOWN);
229cc4c35b9SDavid Schultz 		RETURN(pf,f,FMTCHECK_WSTRING);
2303d090549SKris Kennaway 	}
2313d090549SKris Kennaway 	if (*f == 'p') {
232cc4c35b9SDavid Schultz 		if (modifier != MOD_NONE)
2333d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_UNKNOWN);
2343d090549SKris Kennaway 		RETURN(pf,f,FMTCHECK_LONG);
2353d090549SKris Kennaway 	}
2363d090549SKris Kennaway 	RETURN(pf,f,FMTCHECK_UNKNOWN);
2373d090549SKris Kennaway 	/*NOTREACHED*/
2383d090549SKris Kennaway }
2393d090549SKris Kennaway 
2403d090549SKris Kennaway static EFT
get_next_format_from_width(const char ** pf)2413d090549SKris Kennaway get_next_format_from_width(const char **pf)
2423d090549SKris Kennaway {
2433d090549SKris Kennaway 	const char	*f;
2443d090549SKris Kennaway 
2453d090549SKris Kennaway 	f = *pf;
2463d090549SKris Kennaway 	if (*f == '.') {
2473d090549SKris Kennaway 		f++;
2483d090549SKris Kennaway 		if (*f == '*') {
2493d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_PRECISION);
2503d090549SKris Kennaway 		}
2513d090549SKris Kennaway 		/* eat any precision (empty is allowed) */
2523d090549SKris Kennaway 		while (isdigit(*f)) f++;
2533d090549SKris Kennaway 		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
2543d090549SKris Kennaway 	}
2553d090549SKris Kennaway 	RETURN(pf,f,get_next_format_from_precision(pf));
2563d090549SKris Kennaway 	/*NOTREACHED*/
2573d090549SKris Kennaway }
2583d090549SKris Kennaway 
2593d090549SKris Kennaway static EFT
get_next_format(const char ** pf,EFT eft)2603d090549SKris Kennaway get_next_format(const char **pf, EFT eft)
2613d090549SKris Kennaway {
2623d090549SKris Kennaway 	int		infmt;
2633d090549SKris Kennaway 	const char	*f;
2643d090549SKris Kennaway 
2653d090549SKris Kennaway 	if (eft == FMTCHECK_WIDTH) {
2663d090549SKris Kennaway 		(*pf)++;
2673d090549SKris Kennaway 		return get_next_format_from_width(pf);
2683d090549SKris Kennaway 	} else if (eft == FMTCHECK_PRECISION) {
2693d090549SKris Kennaway 		(*pf)++;
2703d090549SKris Kennaway 		return get_next_format_from_precision(pf);
2713d090549SKris Kennaway 	}
2723d090549SKris Kennaway 
2733d090549SKris Kennaway 	f = *pf;
2743d090549SKris Kennaway 	infmt = 0;
2753d090549SKris Kennaway 	while (!infmt) {
2763d090549SKris Kennaway 		f = strchr(f, '%');
2773d090549SKris Kennaway 		if (f == NULL)
2783d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_DONE);
2793d090549SKris Kennaway 		f++;
2803d090549SKris Kennaway 		if (!*f)
2813d090549SKris Kennaway 			RETURN(pf,f,FMTCHECK_UNKNOWN);
2823d090549SKris Kennaway 		if (*f != '%')
2833d090549SKris Kennaway 			infmt = 1;
2843d090549SKris Kennaway 		else
2853d090549SKris Kennaway 			f++;
2863d090549SKris Kennaway 	}
2873d090549SKris Kennaway 
2883d090549SKris Kennaway 	/* Eat any of the flags */
2893edb8f41SDavid Schultz 	while (*f && (strchr("#'0- +", *f)))
2903d090549SKris Kennaway 		f++;
2913d090549SKris Kennaway 
2923d090549SKris Kennaway 	if (*f == '*') {
2933d090549SKris Kennaway 		RETURN(pf,f,FMTCHECK_WIDTH);
2943d090549SKris Kennaway 	}
2953d090549SKris Kennaway 	/* eat any width */
2963d090549SKris Kennaway 	while (isdigit(*f)) f++;
2973d090549SKris Kennaway 	if (!*f) {
2983d090549SKris Kennaway 		RETURN(pf,f,FMTCHECK_UNKNOWN);
2993d090549SKris Kennaway 	}
3003d090549SKris Kennaway 
3013d090549SKris Kennaway 	RETURN(pf,f,get_next_format_from_width(pf));
3023d090549SKris Kennaway 	/*NOTREACHED*/
3033d090549SKris Kennaway }
3043d090549SKris Kennaway 
305eb4bd20cSXin LI const char *
__fmtcheck(const char * f1,const char * f2)30653154da0SDaniel Eischen __fmtcheck(const char *f1, const char *f2)
3073d090549SKris Kennaway {
3083d090549SKris Kennaway 	const char	*f1p, *f2p;
3093d090549SKris Kennaway 	EFT		f1t, f2t;
3103d090549SKris Kennaway 
3113d090549SKris Kennaway 	if (!f1) return f2;
3123d090549SKris Kennaway 
3133d090549SKris Kennaway 	f1p = f1;
3143d090549SKris Kennaway 	f1t = FMTCHECK_START;
3153d090549SKris Kennaway 	f2p = f2;
3163d090549SKris Kennaway 	f2t = FMTCHECK_START;
3173d090549SKris Kennaway 	while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
3183d090549SKris Kennaway 		if (f1t == FMTCHECK_UNKNOWN)
3193d090549SKris Kennaway 			return f2;
3203d090549SKris Kennaway 		f2t = get_next_format(&f2p, f2t);
3213d090549SKris Kennaway 		if (f1t != f2t)
3223d090549SKris Kennaway 			return f2;
3233d090549SKris Kennaway 	}
3243d090549SKris Kennaway 	return f1;
3253d090549SKris Kennaway }
326