fmtcheck.c revision 194800
1235070Sjmallett/* $NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp $ */ 2235070Sjmallett 3235070Sjmallett/*- 4235070Sjmallett * Copyright (c) 2000 The NetBSD Foundation, Inc. 5235070Sjmallett * All rights reserved. 6235070Sjmallett * 7235070Sjmallett * This code was contributed to The NetBSD Foundation by Allen Briggs. 8235070Sjmallett * 9235070Sjmallett * Redistribution and use in source and binary forms, with or without 10235070Sjmallett * modification, are permitted provided that the following conditions 11235070Sjmallett * are met: 12235070Sjmallett * 1. Redistributions of source code must retain the above copyright 13235070Sjmallett * notice, this list of conditions and the following disclaimer. 14235070Sjmallett * 2. Redistributions in binary form must reproduce the above copyright 15235070Sjmallett * notice, this list of conditions and the following disclaimer in the 16235070Sjmallett * documentation and/or other materials provided with the distribution. 17235070Sjmallett * 18235070Sjmallett * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19235070Sjmallett * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20235070Sjmallett * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21235070Sjmallett * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22235070Sjmallett * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23235070Sjmallett * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24235070Sjmallett * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25235070Sjmallett * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26235070Sjmallett * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27235070Sjmallett * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28235070Sjmallett * POSSIBILITY OF SUCH DAMAGE. 29235070Sjmallett */ 30235070Sjmallett 31235070Sjmallett#include <sys/cdefs.h> 32235070Sjmallett__FBSDID("$FreeBSD: head/lib/libc/gen/fmtcheck.c 194800 2009-06-23 23:52:12Z delphij $"); 33235070Sjmallett 34235070Sjmallett#include <stdio.h> 35235070Sjmallett#include <string.h> 36235070Sjmallett#include <ctype.h> 37235070Sjmallett 38235070Sjmallett__weak_reference(__fmtcheck, fmtcheck); 39235118Sjmallett 40235070Sjmallettenum __e_fmtcheck_types { 41235070Sjmallett FMTCHECK_START, 42235070Sjmallett FMTCHECK_SHORT, 43235070Sjmallett FMTCHECK_INT, 44235118Sjmallett FMTCHECK_WINTT, 45235070Sjmallett FMTCHECK_LONG, 46255212Sgonzo FMTCHECK_QUAD, 47235070Sjmallett FMTCHECK_INTMAXT, 48235070Sjmallett FMTCHECK_PTRDIFFT, 49235070Sjmallett FMTCHECK_SIZET, 50235070Sjmallett FMTCHECK_CHARPOINTER, 51255212Sgonzo FMTCHECK_SHORTPOINTER, 52255212Sgonzo FMTCHECK_INTPOINTER, 53255212Sgonzo FMTCHECK_LONGPOINTER, 54255212Sgonzo FMTCHECK_QUADPOINTER, 55255212Sgonzo FMTCHECK_INTMAXTPOINTER, 56255212Sgonzo FMTCHECK_PTRDIFFTPOINTER, 57235070Sjmallett FMTCHECK_SIZETPOINTER, 58235070Sjmallett#ifndef NO_FLOATING_POINT 59235070Sjmallett FMTCHECK_DOUBLE, 60235070Sjmallett FMTCHECK_LONGDOUBLE, 61235070Sjmallett#endif 62235070Sjmallett FMTCHECK_STRING, 63 FMTCHECK_WSTRING, 64 FMTCHECK_WIDTH, 65 FMTCHECK_PRECISION, 66 FMTCHECK_DONE, 67 FMTCHECK_UNKNOWN 68}; 69typedef enum __e_fmtcheck_types EFT; 70 71enum 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 88static EFT 89get_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 240static EFT 241get_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 259static EFT 260get_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 305const 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