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