1 /* $NetBSD: fmtcheck.c,v 1.14 2017/12/06 12:32:02 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.14 2017/12/06 12:32:02 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 #ifdef _WIN64 153 else { 154 modifier = MOD_QUAD; 155 } 156 #endif 157 break; 158 #endif 159 default: 160 modifier = MOD_NONE; 161 break; 162 } 163 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 164 if (strchr("diouxX", *f)) { 165 switch (modifier) { 166 case MOD_LONG: 167 RETURN(pf,f,FMTCHECK_LONG); 168 case MOD_QUAD: 169 RETURN(pf,f,FMTCHECK_QUAD); 170 case MOD_INTMAXT: 171 RETURN(pf,f,FMTCHECK_INTMAXT); 172 case MOD_PTRDIFFT: 173 RETURN(pf,f,FMTCHECK_PTRDIFFT); 174 case MOD_SIZET: 175 RETURN(pf,f,FMTCHECK_SIZET); 176 case MOD_CHAR: 177 case MOD_SHORT: 178 case MOD_NONE: 179 RETURN(pf,f,FMTCHECK_INT); 180 default: 181 RETURN(pf,f,FMTCHECK_UNKNOWN); 182 } 183 } 184 if (*f == 'n') { 185 switch (modifier) { 186 case MOD_CHAR: 187 RETURN(pf,f,FMTCHECK_CHARPOINTER); 188 case MOD_SHORT: 189 RETURN(pf,f,FMTCHECK_SHORTPOINTER); 190 case MOD_LONG: 191 RETURN(pf,f,FMTCHECK_LONGPOINTER); 192 case MOD_QUAD: 193 RETURN(pf,f,FMTCHECK_QUADPOINTER); 194 case MOD_INTMAXT: 195 RETURN(pf,f,FMTCHECK_INTMAXTPOINTER); 196 case MOD_PTRDIFFT: 197 RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER); 198 case MOD_SIZET: 199 RETURN(pf,f,FMTCHECK_SIZETPOINTER); 200 case MOD_NONE: 201 RETURN(pf,f,FMTCHECK_INTPOINTER); 202 default: 203 RETURN(pf,f,FMTCHECK_UNKNOWN); 204 } 205 } 206 if (strchr("DOU", *f)) { 207 if (modifier != MOD_NONE) 208 RETURN(pf,f,FMTCHECK_UNKNOWN); 209 RETURN(pf,f,FMTCHECK_LONG); 210 } 211 if (strchr("aAeEfFgG", *f)) { 212 switch (modifier) { 213 case MOD_LONGDOUBLE: 214 RETURN(pf,f,FMTCHECK_LONGDOUBLE); 215 case MOD_LONG: 216 case MOD_NONE: 217 RETURN(pf,f,FMTCHECK_DOUBLE); 218 default: 219 RETURN(pf,f,FMTCHECK_UNKNOWN); 220 } 221 } 222 if (*f == 'c') { 223 switch (modifier) { 224 case MOD_LONG: 225 RETURN(pf,f,FMTCHECK_WINTT); 226 case MOD_NONE: 227 RETURN(pf,f,FMTCHECK_INT); 228 default: 229 RETURN(pf,f,FMTCHECK_UNKNOWN); 230 } 231 } 232 if (*f == 'C') { 233 if (modifier != MOD_NONE) 234 RETURN(pf,f,FMTCHECK_UNKNOWN); 235 RETURN(pf,f,FMTCHECK_WINTT); 236 } 237 if (*f == 's') { 238 switch (modifier) { 239 case MOD_LONG: 240 RETURN(pf,f,FMTCHECK_WSTRING); 241 case MOD_NONE: 242 RETURN(pf,f,FMTCHECK_STRING); 243 default: 244 RETURN(pf,f,FMTCHECK_UNKNOWN); 245 } 246 } 247 if (*f == 'S') { 248 if (modifier != MOD_NONE) 249 RETURN(pf,f,FMTCHECK_UNKNOWN); 250 RETURN(pf,f,FMTCHECK_WSTRING); 251 } 252 if (*f == 'p') { 253 if (modifier != MOD_NONE) 254 RETURN(pf,f,FMTCHECK_UNKNOWN); 255 RETURN(pf,f,FMTCHECK_POINTER); 256 } 257 RETURN(pf,f,FMTCHECK_UNKNOWN); 258 /*NOTREACHED*/ 259 } 260 261 static EFT 262 get_next_format_from_width(const char **pf) 263 { 264 const char *f; 265 266 f = *pf; 267 if (*f == '.') { 268 f++; 269 if (*f == '*') { 270 RETURN(pf,f,FMTCHECK_PRECISION); 271 } 272 /* eat any precision (empty is allowed) */ 273 while (isdigit((unsigned char)*f)) f++; 274 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 275 } 276 RETURN(pf,f,get_next_format_from_precision(pf)); 277 /*NOTREACHED*/ 278 } 279 280 static EFT 281 get_next_format(const char **pf, EFT eft) 282 { 283 int infmt; 284 const char *f; 285 286 if (eft == FMTCHECK_WIDTH) { 287 (*pf)++; 288 return get_next_format_from_width(pf); 289 } else if (eft == FMTCHECK_PRECISION) { 290 (*pf)++; 291 return get_next_format_from_precision(pf); 292 } 293 294 f = *pf; 295 infmt = 0; 296 while (!infmt) { 297 f = strchr(f, '%'); 298 if (f == NULL) 299 RETURN(pf,f,FMTCHECK_DONE); 300 f++; 301 if (!*f) 302 RETURN(pf,f,FMTCHECK_UNKNOWN); 303 if (*f != '%') 304 infmt = 1; 305 else 306 f++; 307 } 308 309 /* Eat any of the flags */ 310 while (*f && (strchr("#'0- +", *f))) 311 f++; 312 313 if (*f == '*') { 314 RETURN(pf,f,FMTCHECK_WIDTH); 315 } 316 /* eat any width */ 317 while (isdigit((unsigned char)*f)) f++; 318 if (!*f) { 319 RETURN(pf,f,FMTCHECK_UNKNOWN); 320 } 321 322 RETURN(pf,f,get_next_format_from_width(pf)); 323 /*NOTREACHED*/ 324 } 325 326 const char * 327 fmtcheck(const char *f1, const char *f2) 328 { 329 const char *f1p, *f2p; 330 EFT f1t, f2t; 331 332 if (!f1) return f2; 333 334 f1p = f1; 335 f1t = FMTCHECK_START; 336 f2p = f2; 337 f2t = FMTCHECK_START; 338 while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) { 339 if (f1t == FMTCHECK_UNKNOWN) 340 return f2; 341 f2t = get_next_format(&f2p, f2t); 342 if (f1t != f2t) 343 return f2; 344 } 345 if (get_next_format(&f2p, f2t) != FMTCHECK_DONE) 346 return f2; 347 else 348 return f1; 349 } 350