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