1194800Sdelphij/*	$NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp $	*/
2194800Sdelphij
375578Skris/*-
475578Skris * Copyright (c) 2000 The NetBSD Foundation, Inc.
575578Skris * All rights reserved.
675578Skris *
775578Skris * This code was contributed to The NetBSD Foundation by Allen Briggs.
875578Skris *
975578Skris * Redistribution and use in source and binary forms, with or without
1075578Skris * modification, are permitted provided that the following conditions
1175578Skris * are met:
1275578Skris * 1. Redistributions of source code must retain the above copyright
1375578Skris *    notice, this list of conditions and the following disclaimer.
1475578Skris * 2. Redistributions in binary form must reproduce the above copyright
1575578Skris *    notice, this list of conditions and the following disclaimer in the
1675578Skris *    documentation and/or other materials provided with the distribution.
1775578Skris *
1875578Skris * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1975578Skris * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2075578Skris * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2175578Skris * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2275578Skris * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2375578Skris * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2475578Skris * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2575578Skris * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2675578Skris * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2775578Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2875578Skris * POSSIBILITY OF SUCH DAMAGE.
2975578Skris */
3075578Skris
3175578Skris#include <sys/cdefs.h>
3290039Sobrien__FBSDID("$FreeBSD: releng/10.2/lib/libc/gen/fmtcheck.c 194800 2009-06-23 23:52:12Z delphij $");
3375578Skris
3475578Skris#include <stdio.h>
3575578Skris#include <string.h>
3675578Skris#include <ctype.h>
3775578Skris
3898908Sdeischen__weak_reference(__fmtcheck, fmtcheck);
3975578Skris
4075578Skrisenum __e_fmtcheck_types {
4175578Skris	FMTCHECK_START,
4275578Skris	FMTCHECK_SHORT,
4375578Skris	FMTCHECK_INT,
44181154Sdas	FMTCHECK_WINTT,
4575578Skris	FMTCHECK_LONG,
4675578Skris	FMTCHECK_QUAD,
47181154Sdas	FMTCHECK_INTMAXT,
48117014Sdas	FMTCHECK_PTRDIFFT,
49117014Sdas	FMTCHECK_SIZET,
50181154Sdas	FMTCHECK_CHARPOINTER,
5175578Skris	FMTCHECK_SHORTPOINTER,
5275578Skris	FMTCHECK_INTPOINTER,
5375578Skris	FMTCHECK_LONGPOINTER,
5475578Skris	FMTCHECK_QUADPOINTER,
55181154Sdas	FMTCHECK_INTMAXTPOINTER,
56117014Sdas	FMTCHECK_PTRDIFFTPOINTER,
57117014Sdas	FMTCHECK_SIZETPOINTER,
58128818Sdas#ifndef NO_FLOATING_POINT
5975578Skris	FMTCHECK_DOUBLE,
6075578Skris	FMTCHECK_LONGDOUBLE,
61128818Sdas#endif
6275578Skris	FMTCHECK_STRING,
63181154Sdas	FMTCHECK_WSTRING,
6475578Skris	FMTCHECK_WIDTH,
6575578Skris	FMTCHECK_PRECISION,
6675578Skris	FMTCHECK_DONE,
6775578Skris	FMTCHECK_UNKNOWN
6875578Skris};
6975578Skristypedef enum __e_fmtcheck_types EFT;
7075578Skris
71181154Sdasenum e_modifier {
72181154Sdas	MOD_NONE,
73181154Sdas	MOD_CHAR,
74181154Sdas	MOD_SHORT,
75181154Sdas	MOD_LONG,
76181154Sdas	MOD_QUAD,
77181154Sdas	MOD_INTMAXT,
78181154Sdas	MOD_LONGDOUBLE,
79181154Sdas	MOD_PTRDIFFT,
80181154Sdas	MOD_SIZET,
81181154Sdas};
82181154Sdas
8375578Skris#define RETURN(pf,f,r) do { \
8475578Skris			*(pf) = (f); \
8575578Skris			return r; \
8675578Skris		       } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
8775578Skris
8875578Skrisstatic EFT
8975578Skrisget_next_format_from_precision(const char **pf)
9075578Skris{
91181154Sdas	enum e_modifier	modifier;
9275578Skris	const char	*f;
9375578Skris
9475578Skris	f = *pf;
9575578Skris	switch (*f) {
9675578Skris	case 'h':
9775578Skris		f++;
98181154Sdas		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
99181154Sdas		if (*f == 'h') {
100181154Sdas			f++;
101181154Sdas			modifier = MOD_CHAR;
102181154Sdas		} else {
103181154Sdas			modifier = MOD_SHORT;
104181154Sdas		}
10575578Skris		break;
106181154Sdas	case 'j':
107181154Sdas		f++;
108181154Sdas		modifier = MOD_INTMAXT;
109181154Sdas		break;
11075578Skris	case 'l':
11175578Skris		f++;
11275578Skris		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
11375578Skris		if (*f == 'l') {
11475578Skris			f++;
115181154Sdas			modifier = MOD_QUAD;
11675578Skris		} else {
117181154Sdas			modifier = MOD_LONG;
11875578Skris		}
11975578Skris		break;
12075578Skris	case 'q':
12175578Skris		f++;
122181154Sdas		modifier = MOD_QUAD;
12375578Skris		break;
124117014Sdas	case 't':
125117014Sdas		f++;
126181154Sdas		modifier = MOD_PTRDIFFT;
127117014Sdas		break;
128117014Sdas	case 'z':
129117014Sdas		f++;
130181154Sdas		modifier = MOD_SIZET;
131117014Sdas		break;
13275578Skris	case 'L':
13375578Skris		f++;
134181154Sdas		modifier = MOD_LONGDOUBLE;
13575578Skris		break;
13675578Skris	default:
137181154Sdas		modifier = MOD_NONE;
13875578Skris		break;
13975578Skris	}
14075578Skris	if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
14175578Skris	if (strchr("diouxX", *f)) {
142181154Sdas		switch (modifier) {
143181154Sdas		case MOD_LONG:
14475578Skris			RETURN(pf,f,FMTCHECK_LONG);
145181154Sdas		case MOD_QUAD:
14675578Skris			RETURN(pf,f,FMTCHECK_QUAD);
147181154Sdas		case MOD_INTMAXT:
148181154Sdas			RETURN(pf,f,FMTCHECK_INTMAXT);
149181154Sdas		case MOD_PTRDIFFT:
150117014Sdas			RETURN(pf,f,FMTCHECK_PTRDIFFT);
151181154Sdas		case MOD_SIZET:
152117014Sdas			RETURN(pf,f,FMTCHECK_SIZET);
153181154Sdas		case MOD_CHAR:
154181154Sdas		case MOD_SHORT:
155181154Sdas		case MOD_NONE:
156181154Sdas			RETURN(pf,f,FMTCHECK_INT);
157181154Sdas		default:
158181154Sdas			RETURN(pf,f,FMTCHECK_UNKNOWN);
159181154Sdas		}
16075578Skris	}
16175578Skris	if (*f == 'n') {
162181154Sdas		switch (modifier) {
163181154Sdas		case MOD_CHAR:
164181154Sdas			RETURN(pf,f,FMTCHECK_CHARPOINTER);
165181154Sdas		case MOD_SHORT:
16675578Skris			RETURN(pf,f,FMTCHECK_SHORTPOINTER);
167181154Sdas		case MOD_LONG:
16875578Skris			RETURN(pf,f,FMTCHECK_LONGPOINTER);
169181154Sdas		case MOD_QUAD:
17075578Skris			RETURN(pf,f,FMTCHECK_QUADPOINTER);
171181154Sdas		case MOD_INTMAXT:
172181154Sdas			RETURN(pf,f,FMTCHECK_INTMAXTPOINTER);
173181154Sdas		case MOD_PTRDIFFT:
174117014Sdas			RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
175181154Sdas		case MOD_SIZET:
176117014Sdas			RETURN(pf,f,FMTCHECK_SIZETPOINTER);
177181154Sdas		case MOD_NONE:
178181154Sdas			RETURN(pf,f,FMTCHECK_INTPOINTER);
179181154Sdas		default:
180181154Sdas			RETURN(pf,f,FMTCHECK_UNKNOWN);
181181154Sdas		}
18275578Skris	}
18375578Skris	if (strchr("DOU", *f)) {
184181154Sdas		if (modifier != MOD_NONE)
18575578Skris			RETURN(pf,f,FMTCHECK_UNKNOWN);
18675578Skris		RETURN(pf,f,FMTCHECK_LONG);
18775578Skris	}
188128818Sdas#ifndef NO_FLOATING_POINT
189117014Sdas	if (strchr("aAeEfFgG", *f)) {
190181154Sdas		switch (modifier) {
191181154Sdas		case MOD_LONGDOUBLE:
19275578Skris			RETURN(pf,f,FMTCHECK_LONGDOUBLE);
193181154Sdas		case MOD_LONG:
194181154Sdas		case MOD_NONE:
195181154Sdas			RETURN(pf,f,FMTCHECK_DOUBLE);
196181154Sdas		default:
19775578Skris			RETURN(pf,f,FMTCHECK_UNKNOWN);
198181154Sdas		}
19975578Skris	}
200128818Sdas#endif
20175578Skris	if (*f == 'c') {
202181154Sdas		switch (modifier) {
203181154Sdas		case MOD_LONG:
204181154Sdas			RETURN(pf,f,FMTCHECK_WINTT);
205181154Sdas		case MOD_NONE:
206181154Sdas			RETURN(pf,f,FMTCHECK_INT);
207181154Sdas		default:
20875578Skris			RETURN(pf,f,FMTCHECK_UNKNOWN);
209181154Sdas		}
21075578Skris	}
211181154Sdas	if (*f == 'C') {
212181154Sdas		if (modifier != MOD_NONE)
213181154Sdas			RETURN(pf,f,FMTCHECK_UNKNOWN);
214181154Sdas		RETURN(pf,f,FMTCHECK_WINTT);
215181154Sdas	}
21675578Skris	if (*f == 's') {
217181154Sdas		switch (modifier) {
218181154Sdas		case MOD_LONG:
219181154Sdas			RETURN(pf,f,FMTCHECK_WSTRING);
220181154Sdas		case MOD_NONE:
221181154Sdas			RETURN(pf,f,FMTCHECK_STRING);
222181154Sdas		default:
22375578Skris			RETURN(pf,f,FMTCHECK_UNKNOWN);
224181154Sdas		}
22575578Skris	}
226181154Sdas	if (*f == 'S') {
227181154Sdas		if (modifier != MOD_NONE)
228181154Sdas			RETURN(pf,f,FMTCHECK_UNKNOWN);
229181154Sdas		RETURN(pf,f,FMTCHECK_WSTRING);
230181154Sdas	}
23175578Skris	if (*f == 'p') {
232181154Sdas		if (modifier != MOD_NONE)
23375578Skris			RETURN(pf,f,FMTCHECK_UNKNOWN);
23475578Skris		RETURN(pf,f,FMTCHECK_LONG);
23575578Skris	}
23675578Skris	RETURN(pf,f,FMTCHECK_UNKNOWN);
23775578Skris	/*NOTREACHED*/
23875578Skris}
23975578Skris
24075578Skrisstatic EFT
24175578Skrisget_next_format_from_width(const char **pf)
24275578Skris{
24375578Skris	const char	*f;
24475578Skris
24575578Skris	f = *pf;
24675578Skris	if (*f == '.') {
24775578Skris		f++;
24875578Skris		if (*f == '*') {
24975578Skris			RETURN(pf,f,FMTCHECK_PRECISION);
25075578Skris		}
25175578Skris		/* eat any precision (empty is allowed) */
25275578Skris		while (isdigit(*f)) f++;
25375578Skris		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
25475578Skris	}
25575578Skris	RETURN(pf,f,get_next_format_from_precision(pf));
25675578Skris	/*NOTREACHED*/
25775578Skris}
25875578Skris
25975578Skrisstatic EFT
26075578Skrisget_next_format(const char **pf, EFT eft)
26175578Skris{
26275578Skris	int		infmt;
26375578Skris	const char	*f;
26475578Skris
26575578Skris	if (eft == FMTCHECK_WIDTH) {
26675578Skris		(*pf)++;
26775578Skris		return get_next_format_from_width(pf);
26875578Skris	} else if (eft == FMTCHECK_PRECISION) {
26975578Skris		(*pf)++;
27075578Skris		return get_next_format_from_precision(pf);
27175578Skris	}
27275578Skris
27375578Skris	f = *pf;
27475578Skris	infmt = 0;
27575578Skris	while (!infmt) {
27675578Skris		f = strchr(f, '%');
27775578Skris		if (f == NULL)
27875578Skris			RETURN(pf,f,FMTCHECK_DONE);
27975578Skris		f++;
28075578Skris		if (!*f)
28175578Skris			RETURN(pf,f,FMTCHECK_UNKNOWN);
28275578Skris		if (*f != '%')
28375578Skris			infmt = 1;
28475578Skris		else
28575578Skris			f++;
28675578Skris	}
28775578Skris
28875578Skris	/* Eat any of the flags */
289143905Sdas	while (*f && (strchr("#'0- +", *f)))
29075578Skris		f++;
29175578Skris
29275578Skris	if (*f == '*') {
29375578Skris		RETURN(pf,f,FMTCHECK_WIDTH);
29475578Skris	}
29575578Skris	/* eat any width */
29675578Skris	while (isdigit(*f)) f++;
29775578Skris	if (!*f) {
29875578Skris		RETURN(pf,f,FMTCHECK_UNKNOWN);
29975578Skris	}
30075578Skris
30175578Skris	RETURN(pf,f,get_next_format_from_width(pf));
30275578Skris	/*NOTREACHED*/
30375578Skris}
30475578Skris
305194800Sdelphijconst char *
30698908Sdeischen__fmtcheck(const char *f1, const char *f2)
30775578Skris{
30875578Skris	const char	*f1p, *f2p;
30975578Skris	EFT		f1t, f2t;
31075578Skris
31175578Skris	if (!f1) return f2;
31275578Skris
31375578Skris	f1p = f1;
31475578Skris	f1t = FMTCHECK_START;
31575578Skris	f2p = f2;
31675578Skris	f2t = FMTCHECK_START;
31775578Skris	while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
31875578Skris		if (f1t == FMTCHECK_UNKNOWN)
31975578Skris			return f2;
32075578Skris		f2t = get_next_format(&f2p, f2t);
32175578Skris		if (f1t != f2t)
32275578Skris			return f2;
32375578Skris	}
32475578Skris	return f1;
32575578Skris}
326