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