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