1 /* $NetBSD: fmtcheck.c,v 1.10 2016/01/20 15:43:05 christos 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 #if defined(LIBC_SCCS) && !defined(lint) 33 __RCSID("$NetBSD: fmtcheck.c,v 1.10 2016/01/20 15:43:05 christos Exp $"); 34 #endif 35 36 #include "namespace.h" 37 38 #include <stdio.h> 39 #include <string.h> 40 #include <ctype.h> 41 42 #ifdef __weak_alias 43 __weak_alias(fmtcheck,__fmtcheck) 44 #endif 45 46 enum __e_fmtcheck_types { 47 FMTCHECK_START, 48 FMTCHECK_SHORT, 49 FMTCHECK_INT, 50 FMTCHECK_LONG, 51 FMTCHECK_QUAD, 52 FMTCHECK_POINTER, 53 FMTCHECK_SHORTPOINTER, 54 FMTCHECK_INTPOINTER, 55 FMTCHECK_LONGPOINTER, 56 FMTCHECK_QUADPOINTER, 57 FMTCHECK_DOUBLE, 58 FMTCHECK_LONGDOUBLE, 59 FMTCHECK_STRING, 60 FMTCHECK_WIDTH, 61 FMTCHECK_PRECISION, 62 FMTCHECK_DONE, 63 FMTCHECK_UNKNOWN 64 }; 65 typedef enum __e_fmtcheck_types EFT; 66 67 #define RETURN(pf,f,r) do { \ 68 *(pf) = (f); \ 69 return r; \ 70 } /*NOTREACHED*/ /*CONSTCOND*/ while (0) 71 72 static EFT 73 get_next_format_from_precision(const char **pf) 74 { 75 int sh, lg, quad, longdouble; 76 const char *f; 77 78 sh = lg = quad = longdouble = 0; 79 80 f = *pf; 81 switch (*f) { 82 case 'h': 83 f++; 84 sh = 1; 85 break; 86 case 'l': 87 f++; 88 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 89 if (*f == 'l') { 90 f++; 91 quad = 1; 92 } else { 93 lg = 1; 94 } 95 break; 96 case 'q': 97 f++; 98 quad = 1; 99 break; 100 case 'L': 101 f++; 102 longdouble = 1; 103 break; 104 #ifdef WIN32 105 case 'I': 106 f++; 107 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 108 if (*f == '3' && f[1] == '2') { 109 f += 2; 110 } else if (*f == '6' && f[1] == '4') { 111 f += 2; 112 quad = 1; 113 } 114 #ifdef _WIN64 115 else { 116 quad = 1; 117 } 118 #endif 119 break; 120 #endif 121 default: 122 break; 123 } 124 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 125 if (strchr("diouxX", *f)) { 126 if (longdouble) 127 RETURN(pf,f,FMTCHECK_UNKNOWN); 128 if (lg) 129 RETURN(pf,f,FMTCHECK_LONG); 130 if (quad) 131 RETURN(pf,f,FMTCHECK_QUAD); 132 RETURN(pf,f,FMTCHECK_INT); 133 } 134 if (*f == 'n') { 135 if (longdouble) 136 RETURN(pf,f,FMTCHECK_UNKNOWN); 137 if (sh) 138 RETURN(pf,f,FMTCHECK_SHORTPOINTER); 139 if (lg) 140 RETURN(pf,f,FMTCHECK_LONGPOINTER); 141 if (quad) 142 RETURN(pf,f,FMTCHECK_QUADPOINTER); 143 RETURN(pf,f,FMTCHECK_INTPOINTER); 144 } 145 if (strchr("DOU", *f)) { 146 if (sh + lg + quad + longdouble) 147 RETURN(pf,f,FMTCHECK_UNKNOWN); 148 RETURN(pf,f,FMTCHECK_LONG); 149 } 150 if (strchr("eEfg", *f)) { 151 if (longdouble) 152 RETURN(pf,f,FMTCHECK_LONGDOUBLE); 153 if (sh + lg + quad) 154 RETURN(pf,f,FMTCHECK_UNKNOWN); 155 RETURN(pf,f,FMTCHECK_DOUBLE); 156 } 157 if (*f == 'c') { 158 if (sh + lg + quad + longdouble) 159 RETURN(pf,f,FMTCHECK_UNKNOWN); 160 RETURN(pf,f,FMTCHECK_INT); 161 } 162 if (*f == 's') { 163 if (sh + lg + quad + longdouble) 164 RETURN(pf,f,FMTCHECK_UNKNOWN); 165 RETURN(pf,f,FMTCHECK_STRING); 166 } 167 if (*f == 'p') { 168 if (sh + lg + quad + longdouble) 169 RETURN(pf,f,FMTCHECK_UNKNOWN); 170 RETURN(pf,f,FMTCHECK_POINTER); 171 } 172 RETURN(pf,f,FMTCHECK_UNKNOWN); 173 /*NOTREACHED*/ 174 } 175 176 static EFT 177 get_next_format_from_width(const char **pf) 178 { 179 const char *f; 180 181 f = *pf; 182 if (*f == '.') { 183 f++; 184 if (*f == '*') { 185 RETURN(pf,f,FMTCHECK_PRECISION); 186 } 187 /* eat any precision (empty is allowed) */ 188 while (isdigit((unsigned char)*f)) f++; 189 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 190 } 191 RETURN(pf,f,get_next_format_from_precision(pf)); 192 /*NOTREACHED*/ 193 } 194 195 static EFT 196 get_next_format(const char **pf, EFT eft) 197 { 198 int infmt; 199 const char *f; 200 201 if (eft == FMTCHECK_WIDTH) { 202 (*pf)++; 203 return get_next_format_from_width(pf); 204 } else if (eft == FMTCHECK_PRECISION) { 205 (*pf)++; 206 return get_next_format_from_precision(pf); 207 } 208 209 f = *pf; 210 infmt = 0; 211 while (!infmt) { 212 f = strchr(f, '%'); 213 if (f == NULL) 214 RETURN(pf,f,FMTCHECK_DONE); 215 f++; 216 if (!*f) 217 RETURN(pf,f,FMTCHECK_UNKNOWN); 218 if (*f != '%') 219 infmt = 1; 220 else 221 f++; 222 } 223 224 /* Eat any of the flags */ 225 while (*f && (strchr("#0- +", *f))) 226 f++; 227 228 if (*f == '*') { 229 RETURN(pf,f,FMTCHECK_WIDTH); 230 } 231 /* eat any width */ 232 while (isdigit((unsigned char)*f)) f++; 233 if (!*f) { 234 RETURN(pf,f,FMTCHECK_UNKNOWN); 235 } 236 237 RETURN(pf,f,get_next_format_from_width(pf)); 238 /*NOTREACHED*/ 239 } 240 241 const char * 242 fmtcheck(const char *f1, const char *f2) 243 { 244 const char *f1p, *f2p; 245 EFT f1t, f2t; 246 247 if (!f1) return f2; 248 249 f1p = f1; 250 f1t = FMTCHECK_START; 251 f2p = f2; 252 f2t = FMTCHECK_START; 253 while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) { 254 if (f1t == FMTCHECK_UNKNOWN) 255 return f2; 256 f2t = get_next_format(&f2p, f2t); 257 if (f1t != f2t) 258 return f2; 259 } 260 return f1; 261 } 262