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