Home | History | Annotate | Line # | Download | only in gen
      1 /*	$NetBSD: fmtcheck.c,v 1.16 2017/12/13 06:43:45 rin 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.16 2017/12/13 06:43:45 rin 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_WINTT,
     51 	FMTCHECK_LONG,
     52 	FMTCHECK_QUAD,
     53 	FMTCHECK_INTMAXT,
     54 	FMTCHECK_PTRDIFFT,
     55 	FMTCHECK_SIZET,
     56 	FMTCHECK_POINTER,
     57 	FMTCHECK_CHARPOINTER,
     58 	FMTCHECK_SHORTPOINTER,
     59 	FMTCHECK_INTPOINTER,
     60 	FMTCHECK_LONGPOINTER,
     61 	FMTCHECK_QUADPOINTER,
     62 	FMTCHECK_INTMAXTPOINTER,
     63 	FMTCHECK_PTRDIFFTPOINTER,
     64 	FMTCHECK_SIZETPOINTER,
     65 	FMTCHECK_DOUBLE,
     66 	FMTCHECK_LONGDOUBLE,
     67 	FMTCHECK_STRING,
     68 	FMTCHECK_WSTRING,
     69 	FMTCHECK_WIDTH,
     70 	FMTCHECK_PRECISION,
     71 	FMTCHECK_DONE,
     72 	FMTCHECK_UNKNOWN
     73 };
     74 typedef enum __e_fmtcheck_types EFT;
     75 
     76 enum e_modifier {
     77 	MOD_NONE,
     78 	MOD_CHAR,
     79 	MOD_SHORT,
     80 	MOD_LONG,
     81 	MOD_QUAD,
     82 	MOD_INTMAXT,
     83 	MOD_LONGDOUBLE,
     84 	MOD_PTRDIFFT,
     85 	MOD_SIZET,
     86 };
     87 
     88 #define RETURN(pf,f,r) do { \
     89 			*(pf) = (f); \
     90 			return r; \
     91 		       } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
     92 
     93 static EFT
     94 get_next_format_from_precision(const char **pf)
     95 {
     96 	enum e_modifier	modifier;
     97 	const char	*f;
     98 
     99 	f = *pf;
    100 	switch (*f) {
    101 	case 'h':
    102 		f++;
    103 		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
    104 		if (*f == 'h') {
    105 			f++;
    106 			modifier = MOD_CHAR;
    107 		} else {
    108 			modifier = MOD_SHORT;
    109 		}
    110 		break;
    111 	case 'j':
    112 		f++;
    113 		modifier = MOD_INTMAXT;
    114 		break;
    115 	case 'l':
    116 		f++;
    117 		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
    118 		if (*f == 'l') {
    119 			f++;
    120 			modifier = MOD_QUAD;
    121 		} else {
    122 			modifier = MOD_LONG;
    123 		}
    124 		break;
    125 	case 'q':
    126 		f++;
    127 		modifier = MOD_QUAD;
    128 		break;
    129 	case 't':
    130 		f++;
    131 		modifier = MOD_PTRDIFFT;
    132 		break;
    133 	case 'z':
    134 		f++;
    135 		modifier = MOD_SIZET;
    136 		break;
    137 	case 'L':
    138 		f++;
    139 		modifier = MOD_LONGDOUBLE;
    140 		break;
    141 #ifdef WIN32
    142 	case 'I':
    143 		f++;
    144 		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
    145 		if (*f == '3' && f[1] == '2') {
    146 			f += 2;
    147 			modifier = MOD_NONE;
    148 		} else if (*f == '6' && f[1] == '4') {
    149 			f += 2;
    150 			modifier = MOD_QUAD;
    151 		}
    152 		else {
    153 #ifdef _WIN64
    154 			modifier = MOD_QUAD;
    155 #else
    156 			modifier = MOD_NONE;
    157 #endif
    158 		}
    159 		break;
    160 #endif
    161 	default:
    162 		modifier = MOD_NONE;
    163 		break;
    164 	}
    165 	if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
    166 	if (strchr("diouxX", *f)) {
    167 		switch (modifier) {
    168 		case MOD_LONG:
    169 			RETURN(pf,f,FMTCHECK_LONG);
    170 		case MOD_QUAD:
    171 			RETURN(pf,f,FMTCHECK_QUAD);
    172 		case MOD_INTMAXT:
    173 			RETURN(pf,f,FMTCHECK_INTMAXT);
    174 		case MOD_PTRDIFFT:
    175 			RETURN(pf,f,FMTCHECK_PTRDIFFT);
    176 		case MOD_SIZET:
    177 			RETURN(pf,f,FMTCHECK_SIZET);
    178 		case MOD_CHAR:
    179 		case MOD_SHORT:
    180 		case MOD_NONE:
    181 			RETURN(pf,f,FMTCHECK_INT);
    182 		default:
    183 			RETURN(pf,f,FMTCHECK_UNKNOWN);
    184 		}
    185 	}
    186 	if (*f == 'n') {
    187 		switch (modifier) {
    188 		case MOD_CHAR:
    189 			RETURN(pf,f,FMTCHECK_CHARPOINTER);
    190 		case MOD_SHORT:
    191 			RETURN(pf,f,FMTCHECK_SHORTPOINTER);
    192 		case MOD_LONG:
    193 			RETURN(pf,f,FMTCHECK_LONGPOINTER);
    194 		case MOD_QUAD:
    195 			RETURN(pf,f,FMTCHECK_QUADPOINTER);
    196 		case MOD_INTMAXT:
    197 			RETURN(pf,f,FMTCHECK_INTMAXTPOINTER);
    198 		case MOD_PTRDIFFT:
    199 			RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
    200 		case MOD_SIZET:
    201 			RETURN(pf,f,FMTCHECK_SIZETPOINTER);
    202 		case MOD_NONE:
    203 			RETURN(pf,f,FMTCHECK_INTPOINTER);
    204 		default:
    205 			RETURN(pf,f,FMTCHECK_UNKNOWN);
    206 		}
    207 	}
    208 	if (strchr("DOU", *f)) {
    209 		if (modifier != MOD_NONE)
    210 			RETURN(pf,f,FMTCHECK_UNKNOWN);
    211 		RETURN(pf,f,FMTCHECK_LONG);
    212 	}
    213 	if (strchr("aAeEfFgG", *f)) {
    214 		switch (modifier) {
    215 		case MOD_LONGDOUBLE:
    216 			RETURN(pf,f,FMTCHECK_LONGDOUBLE);
    217 		case MOD_LONG:
    218 		case MOD_NONE:
    219 			RETURN(pf,f,FMTCHECK_DOUBLE);
    220 		default:
    221 			RETURN(pf,f,FMTCHECK_UNKNOWN);
    222 		}
    223 	}
    224 	if (*f == 'c') {
    225 		switch (modifier) {
    226 		case MOD_LONG:
    227 			RETURN(pf,f,FMTCHECK_WINTT);
    228 		case MOD_NONE:
    229 			RETURN(pf,f,FMTCHECK_INT);
    230 		default:
    231 			RETURN(pf,f,FMTCHECK_UNKNOWN);
    232 		}
    233 	}
    234 	if (*f == 'C') {
    235 		if (modifier != MOD_NONE)
    236 			RETURN(pf,f,FMTCHECK_UNKNOWN);
    237 		RETURN(pf,f,FMTCHECK_WINTT);
    238 	}
    239 	if (*f == 's') {
    240 		switch (modifier) {
    241 		case MOD_LONG:
    242 			RETURN(pf,f,FMTCHECK_WSTRING);
    243 		case MOD_NONE:
    244 			RETURN(pf,f,FMTCHECK_STRING);
    245 		default:
    246 			RETURN(pf,f,FMTCHECK_UNKNOWN);
    247 		}
    248 	}
    249 	if (*f == 'S') {
    250 		if (modifier != MOD_NONE)
    251 			RETURN(pf,f,FMTCHECK_UNKNOWN);
    252 		RETURN(pf,f,FMTCHECK_WSTRING);
    253 	}
    254 	if (*f == 'p') {
    255 		if (modifier != MOD_NONE)
    256 			RETURN(pf,f,FMTCHECK_UNKNOWN);
    257 		RETURN(pf,f,FMTCHECK_POINTER);
    258 	}
    259 	RETURN(pf,f,FMTCHECK_UNKNOWN);
    260 	/*NOTREACHED*/
    261 }
    262 
    263 static EFT
    264 get_next_format_from_width(const char **pf)
    265 {
    266 	const char	*f;
    267 
    268 	f = *pf;
    269 	if (*f == '.') {
    270 		f++;
    271 		if (*f == '*') {
    272 			RETURN(pf,f,FMTCHECK_PRECISION);
    273 		}
    274 		/* eat any precision (empty is allowed) */
    275 		while (isdigit((unsigned char)*f)) f++;
    276 		if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
    277 	}
    278 	RETURN(pf,f,get_next_format_from_precision(pf));
    279 	/*NOTREACHED*/
    280 }
    281 
    282 static EFT
    283 get_next_format(const char **pf, EFT eft)
    284 {
    285 	int		infmt;
    286 	const char	*f;
    287 
    288 	if (eft == FMTCHECK_WIDTH) {
    289 		(*pf)++;
    290 		return get_next_format_from_width(pf);
    291 	} else if (eft == FMTCHECK_PRECISION) {
    292 		(*pf)++;
    293 		return get_next_format_from_precision(pf);
    294 	}
    295 
    296 	f = *pf;
    297 	infmt = 0;
    298 	while (!infmt) {
    299 		f = strchr(f, '%');
    300 		if (f == NULL)
    301 			RETURN(pf,f,FMTCHECK_DONE);
    302 		f++;
    303 		if (!*f)
    304 			RETURN(pf,f,FMTCHECK_UNKNOWN);
    305 		if (*f != '%')
    306 			infmt = 1;
    307 		else
    308 			f++;
    309 	}
    310 
    311 	/* Eat any of the flags */
    312 	while (*f && (strchr("#'0- +", *f)))
    313 		f++;
    314 
    315 	if (*f == '*') {
    316 		RETURN(pf,f,FMTCHECK_WIDTH);
    317 	}
    318 	/* eat any width */
    319 	while (isdigit((unsigned char)*f)) f++;
    320 	if (!*f) {
    321 		RETURN(pf,f,FMTCHECK_UNKNOWN);
    322 	}
    323 
    324 	RETURN(pf,f,get_next_format_from_width(pf));
    325 	/*NOTREACHED*/
    326 }
    327 
    328 const char *
    329 fmtcheck(const char *f1, const char *f2)
    330 {
    331 	const char	*f1p, *f2p;
    332 	EFT		f1t, f2t;
    333 
    334 	if (!f1) return f2;
    335 
    336 	f1p = f1;
    337 	f1t = FMTCHECK_START;
    338 	f2p = f2;
    339 	f2t = FMTCHECK_START;
    340 	while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
    341 		if (f1t == FMTCHECK_UNKNOWN)
    342 			return f2;
    343 		f2t = get_next_format(&f2p, f2t);
    344 		if (f1t != f2t)
    345 			return f2;
    346 	}
    347 	return f1;
    348 }
    349