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