1 /* $NetBSD: fmtcheck.c,v 1.1.1.2 2015/01/02 20:34:27 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 default: 97 break; 98 } 99 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 100 if (strchr("diouxX", *f)) { 101 if (longdouble) 102 RETURN(pf,f,FMTCHECK_UNKNOWN); 103 if (lg) 104 RETURN(pf,f,FMTCHECK_LONG); 105 if (quad) 106 RETURN(pf,f,FMTCHECK_QUAD); 107 RETURN(pf,f,FMTCHECK_INT); 108 } 109 if (*f == 'n') { 110 if (longdouble) 111 RETURN(pf,f,FMTCHECK_UNKNOWN); 112 if (sh) 113 RETURN(pf,f,FMTCHECK_SHORTPOINTER); 114 if (lg) 115 RETURN(pf,f,FMTCHECK_LONGPOINTER); 116 if (quad) 117 RETURN(pf,f,FMTCHECK_QUADPOINTER); 118 RETURN(pf,f,FMTCHECK_INTPOINTER); 119 } 120 if (strchr("DOU", *f)) { 121 if (sh + lg + quad + longdouble) 122 RETURN(pf,f,FMTCHECK_UNKNOWN); 123 RETURN(pf,f,FMTCHECK_LONG); 124 } 125 if (strchr("eEfg", *f)) { 126 if (longdouble) 127 RETURN(pf,f,FMTCHECK_LONGDOUBLE); 128 if (sh + lg + quad) 129 RETURN(pf,f,FMTCHECK_UNKNOWN); 130 RETURN(pf,f,FMTCHECK_DOUBLE); 131 } 132 if (*f == 'c') { 133 if (sh + lg + quad + longdouble) 134 RETURN(pf,f,FMTCHECK_UNKNOWN); 135 RETURN(pf,f,FMTCHECK_INT); 136 } 137 if (*f == 's') { 138 if (sh + lg + quad + longdouble) 139 RETURN(pf,f,FMTCHECK_UNKNOWN); 140 RETURN(pf,f,FMTCHECK_STRING); 141 } 142 if (*f == 'p') { 143 if (sh + lg + quad + longdouble) 144 RETURN(pf,f,FMTCHECK_UNKNOWN); 145 RETURN(pf,f,FMTCHECK_LONG); 146 } 147 RETURN(pf,f,FMTCHECK_UNKNOWN); 148 /*NOTREACHED*/ 149 } 150 151 static EFT 152 get_next_format_from_width(const char **pf) 153 { 154 const char *f; 155 156 f = *pf; 157 if (*f == '.') { 158 f++; 159 if (*f == '*') { 160 RETURN(pf,f,FMTCHECK_PRECISION); 161 } 162 /* eat any precision (empty is allowed) */ 163 while (isdigit((unsigned char)*f)) f++; 164 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 165 } 166 RETURN(pf,f,get_next_format_from_precision(pf)); 167 /*NOTREACHED*/ 168 } 169 170 static EFT 171 get_next_format(const char **pf, EFT eft) 172 { 173 int infmt; 174 const char *f; 175 176 if (eft == FMTCHECK_WIDTH) { 177 (*pf)++; 178 return get_next_format_from_width(pf); 179 } else if (eft == FMTCHECK_PRECISION) { 180 (*pf)++; 181 return get_next_format_from_precision(pf); 182 } 183 184 f = *pf; 185 infmt = 0; 186 while (!infmt) { 187 f = strchr(f, '%'); 188 if (f == NULL) 189 RETURN(pf,f,FMTCHECK_DONE); 190 f++; 191 if (!*f) 192 RETURN(pf,f,FMTCHECK_UNKNOWN); 193 if (*f != '%') 194 infmt = 1; 195 else 196 f++; 197 } 198 199 /* Eat any of the flags */ 200 while (*f && (strchr("#0- +", *f))) 201 f++; 202 203 if (*f == '*') { 204 RETURN(pf,f,FMTCHECK_WIDTH); 205 } 206 /* eat any width */ 207 while (isdigit((unsigned char)*f)) f++; 208 if (!*f) { 209 RETURN(pf,f,FMTCHECK_UNKNOWN); 210 } 211 212 RETURN(pf,f,get_next_format_from_width(pf)); 213 /*NOTREACHED*/ 214 } 215 216 const char * 217 fmtcheck(const char *f1, const char *f2) 218 { 219 const char *f1p, *f2p; 220 EFT f1t, f2t; 221 222 if (!f1) return f2; 223 224 f1p = f1; 225 f1t = FMTCHECK_START; 226 f2p = f2; 227 f2t = FMTCHECK_START; 228 while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) { 229 if (f1t == FMTCHECK_UNKNOWN) 230 return f2; 231 f2t = get_next_format(&f2p, f2t); 232 if (f1t != f2t) 233 return f2; 234 } 235 return f1; 236 } 237