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