1 /* $NetBSD: fmtcheck.c,v 1.1.1.4 2018/10/18 23:54:09 christos Exp $ */ 2 3 /* NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp */ 4 5 /*- 6 * Copyright (c) 2000 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * This code was contributed to The NetBSD Foundation by Allen Briggs. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include "file.h" 34 35 #include <stdio.h> 36 #include <string.h> 37 #include <ctype.h> 38 39 enum __e_fmtcheck_types { 40 FMTCHECK_START, 41 FMTCHECK_SHORT, 42 FMTCHECK_INT, 43 FMTCHECK_LONG, 44 FMTCHECK_QUAD, 45 FMTCHECK_SHORTPOINTER, 46 FMTCHECK_INTPOINTER, 47 FMTCHECK_LONGPOINTER, 48 FMTCHECK_QUADPOINTER, 49 FMTCHECK_DOUBLE, 50 FMTCHECK_LONGDOUBLE, 51 FMTCHECK_STRING, 52 FMTCHECK_WIDTH, 53 FMTCHECK_PRECISION, 54 FMTCHECK_DONE, 55 FMTCHECK_UNKNOWN 56 }; 57 typedef enum __e_fmtcheck_types EFT; 58 59 #define RETURN(pf,f,r) do { \ 60 *(pf) = (f); \ 61 return r; \ 62 } /*NOTREACHED*/ /*CONSTCOND*/ while (0) 63 64 static EFT 65 get_next_format_from_precision(const char **pf) 66 { 67 int sh, lg, quad, longdouble; 68 const char *f; 69 70 sh = lg = quad = longdouble = 0; 71 72 f = *pf; 73 switch (*f) { 74 case 'h': 75 f++; 76 sh = 1; 77 break; 78 case 'l': 79 f++; 80 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 81 if (*f == 'l') { 82 f++; 83 quad = 1; 84 } else { 85 lg = 1; 86 } 87 break; 88 case 'q': 89 f++; 90 quad = 1; 91 break; 92 case 'L': 93 f++; 94 longdouble = 1; 95 break; 96 #ifdef WIN32 97 case 'I': 98 f++; 99 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 100 if (*f == '3' && f[1] == '2') { 101 f += 2; 102 } else if (*f == '6' && f[1] == '4') { 103 f += 2; 104 quad = 1; 105 } 106 #ifdef _WIN64 107 else { 108 quad = 1; 109 } 110 #endif 111 break; 112 #endif 113 default: 114 break; 115 } 116 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 117 if (strchr("diouxX", *f)) { 118 if (longdouble) 119 RETURN(pf,f,FMTCHECK_UNKNOWN); 120 if (lg) 121 RETURN(pf,f,FMTCHECK_LONG); 122 if (quad) 123 RETURN(pf,f,FMTCHECK_QUAD); 124 RETURN(pf,f,FMTCHECK_INT); 125 } 126 if (*f == 'n') { 127 if (longdouble) 128 RETURN(pf,f,FMTCHECK_UNKNOWN); 129 if (sh) 130 RETURN(pf,f,FMTCHECK_SHORTPOINTER); 131 if (lg) 132 RETURN(pf,f,FMTCHECK_LONGPOINTER); 133 if (quad) 134 RETURN(pf,f,FMTCHECK_QUADPOINTER); 135 RETURN(pf,f,FMTCHECK_INTPOINTER); 136 } 137 if (strchr("DOU", *f)) { 138 if (sh + lg + quad + longdouble) 139 RETURN(pf,f,FMTCHECK_UNKNOWN); 140 RETURN(pf,f,FMTCHECK_LONG); 141 } 142 if (strchr("eEfg", *f)) { 143 if (longdouble) 144 RETURN(pf,f,FMTCHECK_LONGDOUBLE); 145 if (sh + lg + quad) 146 RETURN(pf,f,FMTCHECK_UNKNOWN); 147 RETURN(pf,f,FMTCHECK_DOUBLE); 148 } 149 if (*f == 'c') { 150 if (sh + lg + quad + longdouble) 151 RETURN(pf,f,FMTCHECK_UNKNOWN); 152 RETURN(pf,f,FMTCHECK_INT); 153 } 154 if (*f == 's') { 155 if (sh + lg + quad + longdouble) 156 RETURN(pf,f,FMTCHECK_UNKNOWN); 157 RETURN(pf,f,FMTCHECK_STRING); 158 } 159 if (*f == 'p') { 160 if (sh + lg + quad + longdouble) 161 RETURN(pf,f,FMTCHECK_UNKNOWN); 162 RETURN(pf,f,FMTCHECK_LONG); 163 } 164 RETURN(pf,f,FMTCHECK_UNKNOWN); 165 /*NOTREACHED*/ 166 } 167 168 static EFT 169 get_next_format_from_width(const char **pf) 170 { 171 const char *f; 172 173 f = *pf; 174 if (*f == '.') { 175 f++; 176 if (*f == '*') { 177 RETURN(pf,f,FMTCHECK_PRECISION); 178 } 179 /* eat any precision (empty is allowed) */ 180 while (isdigit((unsigned char)*f)) f++; 181 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 182 } 183 RETURN(pf,f,get_next_format_from_precision(pf)); 184 /*NOTREACHED*/ 185 } 186 187 static EFT 188 get_next_format(const char **pf, EFT eft) 189 { 190 int infmt; 191 const char *f; 192 193 if (eft == FMTCHECK_WIDTH) { 194 (*pf)++; 195 return get_next_format_from_width(pf); 196 } else if (eft == FMTCHECK_PRECISION) { 197 (*pf)++; 198 return get_next_format_from_precision(pf); 199 } 200 201 f = *pf; 202 infmt = 0; 203 while (!infmt) { 204 f = strchr(f, '%'); 205 if (f == NULL) 206 RETURN(pf,f,FMTCHECK_DONE); 207 f++; 208 if (!*f) 209 RETURN(pf,f,FMTCHECK_UNKNOWN); 210 if (*f != '%') 211 infmt = 1; 212 else 213 f++; 214 } 215 216 /* Eat any of the flags */ 217 while (*f && (strchr("#0- +", *f))) 218 f++; 219 220 if (*f == '*') { 221 RETURN(pf,f,FMTCHECK_WIDTH); 222 } 223 /* eat any width */ 224 while (isdigit((unsigned char)*f)) f++; 225 if (!*f) { 226 RETURN(pf,f,FMTCHECK_UNKNOWN); 227 } 228 229 RETURN(pf,f,get_next_format_from_width(pf)); 230 /*NOTREACHED*/ 231 } 232 233 const char * 234 fmtcheck(const char *f1, const char *f2) 235 { 236 const char *f1p, *f2p; 237 EFT f1t, f2t; 238 239 if (!f1) return f2; 240 241 f1p = f1; 242 f1t = FMTCHECK_START; 243 f2p = f2; 244 f2t = FMTCHECK_START; 245 while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) { 246 if (f1t == FMTCHECK_UNKNOWN) 247 return f2; 248 f2t = get_next_format(&f2p, f2t); 249 if (f1t != f2t) 250 return f2; 251 } 252 return f1; 253 } 254