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