fmtcheck.c revision 75578
175578Skris/*	$FreeBSD: head/lib/libc/gen/fmtcheck.c 75578 2001-04-17 07:59:52Z kris $	*/
275578Skris/*	$NetBSD: fmtcheck.c,v 1.2 2000/11/01 01:17:20 briggs Exp $	*/
375578Skris
475578Skris/*-
575578Skris * Copyright (c) 2000 The NetBSD Foundation, Inc.
675578Skris * All rights reserved.
775578Skris *
875578Skris * This code was contributed to The NetBSD Foundation by Allen Briggs.
975578Skris *
1075578Skris * Redistribution and use in source and binary forms, with or without
1175578Skris * modification, are permitted provided that the following conditions
1275578Skris * are met:
1375578Skris * 1. Redistributions of source code must retain the above copyright
1475578Skris *    notice, this list of conditions and the following disclaimer.
1575578Skris * 2. Redistributions in binary form must reproduce the above copyright
1675578Skris *    notice, this list of conditions and the following disclaimer in the
1775578Skris *    documentation and/or other materials provided with the distribution.
1875578Skris * 3. All advertising materials mentioning features or use of this software
1975578Skris *    must display the following acknowledgement:
2075578Skris *        This product includes software developed by the NetBSD
2175578Skris *        Foundation, Inc. and its contributors.
2275578Skris * 4. Neither the name of The NetBSD Foundation nor the names of its
2375578Skris *    contributors may be used to endorse or promote products derived
2475578Skris *    from this software without specific prior written permission.
2575578Skris *
2675578Skris * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2775578Skris * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2875578Skris * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2975578Skris * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
3075578Skris * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3175578Skris * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3275578Skris * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3375578Skris * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3475578Skris * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3575578Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3675578Skris * POSSIBILITY OF SUCH DAMAGE.
3775578Skris */
3875578Skris
3975578Skris#include <sys/cdefs.h>
4075578Skris#ifndef lint
4175578Skrisstatic const char rcsid[] =
4275578Skris  "$FreeBSD: head/lib/libc/gen/fmtcheck.c 75578 2001-04-17 07:59:52Z kris $";
4375578Skris#endif /* not lint */
4475578Skris
4575578Skris#include "namespace.h"
4675578Skris
4775578Skris#include <stdlib.h>
4875578Skris#include <stdio.h>
4975578Skris#include <string.h>
5075578Skris#include <ctype.h>
5175578Skris
5275578Skris#ifdef __weak_alias
5375578Skris__weak_alias(fmtcheck,__fmtcheck)
5475578Skris#endif
5575578Skris
5675578Skrisenum __e_fmtcheck_types {
5775578Skris	FMTCHECK_START,
5875578Skris	FMTCHECK_SHORT,
5975578Skris	FMTCHECK_INT,
6075578Skris	FMTCHECK_LONG,
6175578Skris	FMTCHECK_QUAD,
6275578Skris	FMTCHECK_SHORTPOINTER,
6375578Skris	FMTCHECK_INTPOINTER,
6475578Skris	FMTCHECK_LONGPOINTER,
6575578Skris	FMTCHECK_QUADPOINTER,
6675578Skris	FMTCHECK_DOUBLE,
6775578Skris	FMTCHECK_LONGDOUBLE,
6875578Skris	FMTCHECK_STRING,
6975578Skris	FMTCHECK_WIDTH,
7075578Skris	FMTCHECK_PRECISION,
7175578Skris	FMTCHECK_DONE,
7275578Skris	FMTCHECK_UNKNOWN
7375578Skris};
7475578Skristypedef enum __e_fmtcheck_types EFT;
7575578Skris
7675578Skris#define RETURN(pf,f,r) do { \
7775578Skris			*(pf) = (f); \
7875578Skris			return r; \
7975578Skris		       } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
8075578Skris
8175578Skrisstatic EFT
8275578Skrisget_next_format_from_precision(const char **pf)
8375578Skris{
8475578Skris	int		sh, lg, quad, longdouble;
8575578Skris	const char	*f;
8675578Skris
8775578Skris	sh = lg = quad = longdouble = 0;
8875578Skris
8975578Skris	f = *pf;
9075578Skris	switch (*f) {
9175578Skris	case 'h':
9275578Skris		f++;
9375578Skris		sh = 1;
9475578Skris		break;
9575578Skris	case 'l':
9675578Skris		f++;
9775578Skris		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
9875578Skris		if (*f == 'l') {
9975578Skris			f++;
10075578Skris			quad = 1;
10175578Skris		} else {
10275578Skris			lg = 1;
10375578Skris		}
10475578Skris		break;
10575578Skris	case 'q':
10675578Skris		f++;
10775578Skris		quad = 1;
10875578Skris		break;
10975578Skris	case 'L':
11075578Skris		f++;
11175578Skris		longdouble = 1;
11275578Skris		break;
11375578Skris	default:
11475578Skris		break;
11575578Skris	}
11675578Skris	if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
11775578Skris	if (strchr("diouxX", *f)) {
11875578Skris		if (longdouble)
11975578Skris			RETURN(pf,f,FMTCHECK_UNKNOWN);
12075578Skris		if (lg)
12175578Skris			RETURN(pf,f,FMTCHECK_LONG);
12275578Skris		if (quad)
12375578Skris			RETURN(pf,f,FMTCHECK_QUAD);
12475578Skris		RETURN(pf,f,FMTCHECK_INT);
12575578Skris	}
12675578Skris	if (*f == 'n') {
12775578Skris		if (longdouble)
12875578Skris			RETURN(pf,f,FMTCHECK_UNKNOWN);
12975578Skris		if (sh)
13075578Skris			RETURN(pf,f,FMTCHECK_SHORTPOINTER);
13175578Skris		if (lg)
13275578Skris			RETURN(pf,f,FMTCHECK_LONGPOINTER);
13375578Skris		if (quad)
13475578Skris			RETURN(pf,f,FMTCHECK_QUADPOINTER);
13575578Skris		RETURN(pf,f,FMTCHECK_INTPOINTER);
13675578Skris	}
13775578Skris	if (strchr("DOU", *f)) {
13875578Skris		if (sh + lg + quad + longdouble)
13975578Skris			RETURN(pf,f,FMTCHECK_UNKNOWN);
14075578Skris		RETURN(pf,f,FMTCHECK_LONG);
14175578Skris	}
14275578Skris	if (strchr("eEfg", *f)) {
14375578Skris		if (longdouble)
14475578Skris			RETURN(pf,f,FMTCHECK_LONGDOUBLE);
14575578Skris		if (sh + lg + quad)
14675578Skris			RETURN(pf,f,FMTCHECK_UNKNOWN);
14775578Skris		RETURN(pf,f,FMTCHECK_DOUBLE);
14875578Skris	}
14975578Skris	if (*f == 'c') {
15075578Skris		if (sh + lg + quad + longdouble)
15175578Skris			RETURN(pf,f,FMTCHECK_UNKNOWN);
15275578Skris		RETURN(pf,f,FMTCHECK_INT);
15375578Skris	}
15475578Skris	if (*f == 's') {
15575578Skris		if (sh + lg + quad + longdouble)
15675578Skris			RETURN(pf,f,FMTCHECK_UNKNOWN);
15775578Skris		RETURN(pf,f,FMTCHECK_STRING);
15875578Skris	}
15975578Skris	if (*f == 'p') {
16075578Skris		if (sh + lg + quad + longdouble)
16175578Skris			RETURN(pf,f,FMTCHECK_UNKNOWN);
16275578Skris		RETURN(pf,f,FMTCHECK_LONG);
16375578Skris	}
16475578Skris	RETURN(pf,f,FMTCHECK_UNKNOWN);
16575578Skris	/*NOTREACHED*/
16675578Skris}
16775578Skris
16875578Skrisstatic EFT
16975578Skrisget_next_format_from_width(const char **pf)
17075578Skris{
17175578Skris	const char	*f;
17275578Skris
17375578Skris	f = *pf;
17475578Skris	if (*f == '.') {
17575578Skris		f++;
17675578Skris		if (*f == '*') {
17775578Skris			RETURN(pf,f,FMTCHECK_PRECISION);
17875578Skris		}
17975578Skris		/* eat any precision (empty is allowed) */
18075578Skris		while (isdigit(*f)) f++;
18175578Skris		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
18275578Skris	}
18375578Skris	RETURN(pf,f,get_next_format_from_precision(pf));
18475578Skris	/*NOTREACHED*/
18575578Skris}
18675578Skris
18775578Skrisstatic EFT
18875578Skrisget_next_format(const char **pf, EFT eft)
18975578Skris{
19075578Skris	int		infmt;
19175578Skris	const char	*f;
19275578Skris
19375578Skris	if (eft == FMTCHECK_WIDTH) {
19475578Skris		(*pf)++;
19575578Skris		return get_next_format_from_width(pf);
19675578Skris	} else if (eft == FMTCHECK_PRECISION) {
19775578Skris		(*pf)++;
19875578Skris		return get_next_format_from_precision(pf);
19975578Skris	}
20075578Skris
20175578Skris	f = *pf;
20275578Skris	infmt = 0;
20375578Skris	while (!infmt) {
20475578Skris		f = strchr(f, '%');
20575578Skris		if (f == NULL)
20675578Skris			RETURN(pf,f,FMTCHECK_DONE);
20775578Skris		f++;
20875578Skris		if (!*f)
20975578Skris			RETURN(pf,f,FMTCHECK_UNKNOWN);
21075578Skris		if (*f != '%')
21175578Skris			infmt = 1;
21275578Skris		else
21375578Skris			f++;
21475578Skris	}
21575578Skris
21675578Skris	/* Eat any of the flags */
21775578Skris	while (*f && (strchr("#0- +", *f)))
21875578Skris		f++;
21975578Skris
22075578Skris	if (*f == '*') {
22175578Skris		RETURN(pf,f,FMTCHECK_WIDTH);
22275578Skris	}
22375578Skris	/* eat any width */
22475578Skris	while (isdigit(*f)) f++;
22575578Skris	if (!*f) {
22675578Skris		RETURN(pf,f,FMTCHECK_UNKNOWN);
22775578Skris	}
22875578Skris
22975578Skris	RETURN(pf,f,get_next_format_from_width(pf));
23075578Skris	/*NOTREACHED*/
23175578Skris}
23275578Skris
23375578Skris__const char *
23475578Skrisfmtcheck(const char *f1, const char *f2)
23575578Skris{
23675578Skris	const char	*f1p, *f2p;
23775578Skris	EFT		f1t, f2t;
23875578Skris
23975578Skris	if (!f1) return f2;
24075578Skris
24175578Skris	f1p = f1;
24275578Skris	f1t = FMTCHECK_START;
24375578Skris	f2p = f2;
24475578Skris	f2t = FMTCHECK_START;
24575578Skris	while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
24675578Skris		if (f1t == FMTCHECK_UNKNOWN)
24775578Skris			return f2;
24875578Skris		f2t = get_next_format(&f2p, f2t);
24975578Skris		if (f1t != f2t)
25075578Skris			return f2;
25175578Skris	}
25275578Skris	return f1;
25375578Skris}
254