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 * $NetBSD: fmtcheck.c,v 1.2 2000/11/01 01:17:20 briggs Exp $ 36 * $FreeBSD: src/lib/libc/gen/fmtcheck.c,v 1.9 2008/08/02 06:02:42 das Exp $ 37 */ 38 39 #include <stdio.h> 40 #include <string.h> 41 #include <ctype.h> 42 43 const char *__fmtcheck(const char *, const char *); 44 45 enum __e_fmtcheck_types { 46 FMTCHECK_START, 47 FMTCHECK_SHORT, 48 FMTCHECK_INT, 49 FMTCHECK_WINTT, 50 FMTCHECK_LONG, 51 FMTCHECK_QUAD, 52 FMTCHECK_INTMAXT, 53 FMTCHECK_PTRDIFFT, 54 FMTCHECK_SIZET, 55 FMTCHECK_CHARPOINTER, 56 FMTCHECK_SHORTPOINTER, 57 FMTCHECK_INTPOINTER, 58 FMTCHECK_LONGPOINTER, 59 FMTCHECK_QUADPOINTER, 60 FMTCHECK_INTMAXTPOINTER, 61 FMTCHECK_PTRDIFFTPOINTER, 62 FMTCHECK_SIZETPOINTER, 63 #ifndef NO_FLOATING_POINT 64 FMTCHECK_DOUBLE, 65 FMTCHECK_LONGDOUBLE, 66 #endif 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 default: 142 modifier = MOD_NONE; 143 break; 144 } 145 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 146 if (strchr("diouxX", *f)) { 147 switch (modifier) { 148 case MOD_LONG: 149 RETURN(pf,f,FMTCHECK_LONG); 150 case MOD_QUAD: 151 RETURN(pf,f,FMTCHECK_QUAD); 152 case MOD_INTMAXT: 153 RETURN(pf,f,FMTCHECK_INTMAXT); 154 case MOD_PTRDIFFT: 155 RETURN(pf,f,FMTCHECK_PTRDIFFT); 156 case MOD_SIZET: 157 RETURN(pf,f,FMTCHECK_SIZET); 158 case MOD_CHAR: 159 case MOD_SHORT: 160 case MOD_NONE: 161 RETURN(pf,f,FMTCHECK_INT); 162 default: 163 RETURN(pf,f,FMTCHECK_UNKNOWN); 164 } 165 } 166 if (*f == 'n') { 167 switch (modifier) { 168 case MOD_CHAR: 169 RETURN(pf,f,FMTCHECK_CHARPOINTER); 170 case MOD_SHORT: 171 RETURN(pf,f,FMTCHECK_SHORTPOINTER); 172 case MOD_LONG: 173 RETURN(pf,f,FMTCHECK_LONGPOINTER); 174 case MOD_QUAD: 175 RETURN(pf,f,FMTCHECK_QUADPOINTER); 176 case MOD_INTMAXT: 177 RETURN(pf,f,FMTCHECK_INTMAXTPOINTER); 178 case MOD_PTRDIFFT: 179 RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER); 180 case MOD_SIZET: 181 RETURN(pf,f,FMTCHECK_SIZETPOINTER); 182 case MOD_NONE: 183 RETURN(pf,f,FMTCHECK_INTPOINTER); 184 default: 185 RETURN(pf,f,FMTCHECK_UNKNOWN); 186 } 187 } 188 if (strchr("DOU", *f)) { 189 if (modifier != MOD_NONE) 190 RETURN(pf,f,FMTCHECK_UNKNOWN); 191 RETURN(pf,f,FMTCHECK_LONG); 192 } 193 #ifndef NO_FLOATING_POINT 194 if (strchr("aAeEfFgG", *f)) { 195 switch (modifier) { 196 case MOD_LONGDOUBLE: 197 RETURN(pf,f,FMTCHECK_LONGDOUBLE); 198 case MOD_LONG: 199 case MOD_NONE: 200 RETURN(pf,f,FMTCHECK_DOUBLE); 201 default: 202 RETURN(pf,f,FMTCHECK_UNKNOWN); 203 } 204 } 205 #endif 206 if (*f == 'c') { 207 switch (modifier) { 208 case MOD_LONG: 209 RETURN(pf,f,FMTCHECK_WINTT); 210 case MOD_NONE: 211 RETURN(pf,f,FMTCHECK_INT); 212 default: 213 RETURN(pf,f,FMTCHECK_UNKNOWN); 214 } 215 } 216 if (*f == 'C') { 217 if (modifier != MOD_NONE) 218 RETURN(pf,f,FMTCHECK_UNKNOWN); 219 RETURN(pf,f,FMTCHECK_WINTT); 220 } 221 if (*f == 's') { 222 switch (modifier) { 223 case MOD_LONG: 224 RETURN(pf,f,FMTCHECK_WSTRING); 225 case MOD_NONE: 226 RETURN(pf,f,FMTCHECK_STRING); 227 default: 228 RETURN(pf,f,FMTCHECK_UNKNOWN); 229 } 230 } 231 if (*f == 'S') { 232 if (modifier != MOD_NONE) 233 RETURN(pf,f,FMTCHECK_UNKNOWN); 234 RETURN(pf,f,FMTCHECK_WSTRING); 235 } 236 if (*f == 'p') { 237 if (modifier != MOD_NONE) 238 RETURN(pf,f,FMTCHECK_UNKNOWN); 239 RETURN(pf,f,FMTCHECK_LONG); 240 } 241 RETURN(pf,f,FMTCHECK_UNKNOWN); 242 /*NOTREACHED*/ 243 } 244 245 static EFT 246 get_next_format_from_width(const char **pf) 247 { 248 const char *f; 249 250 f = *pf; 251 if (*f == '.') { 252 f++; 253 if (*f == '*') { 254 RETURN(pf,f,FMTCHECK_PRECISION); 255 } 256 /* eat any precision (empty is allowed) */ 257 while (isdigit(*f)) f++; 258 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 259 } 260 RETURN(pf,f,get_next_format_from_precision(pf)); 261 /*NOTREACHED*/ 262 } 263 264 static EFT 265 get_next_format(const char **pf, EFT eft) 266 { 267 int infmt; 268 const char *f; 269 270 if (eft == FMTCHECK_WIDTH) { 271 (*pf)++; 272 return get_next_format_from_width(pf); 273 } else if (eft == FMTCHECK_PRECISION) { 274 (*pf)++; 275 return get_next_format_from_precision(pf); 276 } 277 278 f = *pf; 279 infmt = 0; 280 while (!infmt) { 281 f = strchr(f, '%'); 282 if (f == NULL) 283 RETURN(pf,f,FMTCHECK_DONE); 284 f++; 285 if (!*f) 286 RETURN(pf,f,FMTCHECK_UNKNOWN); 287 if (*f != '%') 288 infmt = 1; 289 else 290 f++; 291 } 292 293 /* Eat any of the flags */ 294 while (*f && (strchr("#'0- +", *f))) 295 f++; 296 297 if (*f == '*') { 298 RETURN(pf,f,FMTCHECK_WIDTH); 299 } 300 /* eat any width */ 301 while (isdigit(*f)) f++; 302 if (!*f) { 303 RETURN(pf,f,FMTCHECK_UNKNOWN); 304 } 305 306 RETURN(pf,f,get_next_format_from_width(pf)); 307 /*NOTREACHED*/ 308 } 309 310 const char * 311 __fmtcheck(const char *f1, const char *f2) 312 { 313 const char *f1p, *f2p; 314 EFT f1t, f2t; 315 316 if (!f1) return f2; 317 318 f1p = f1; 319 f1t = FMTCHECK_START; 320 f2p = f2; 321 f2t = FMTCHECK_START; 322 while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) { 323 if (f1t == FMTCHECK_UNKNOWN) 324 return f2; 325 f2t = get_next_format(&f2p, f2t); 326 if (f1t != f2t) 327 return f2; 328 } 329 return f1; 330 } 331 332 __weak_reference(__fmtcheck, fmtcheck); 333