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