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