1 /*- 2 * Copyright (c) 2000 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code was contributed to The NetBSD Foundation by Allen Briggs. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the NetBSD 18 * Foundation, Inc. and its contributors. 19 * 4. Neither the name of The NetBSD Foundation nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /* $NetBSD: fmtcheck.c,v 1.2 2000/11/01 01:17:20 briggs Exp $ */ 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #include <stdio.h> 41 #include <string.h> 42 #include <ctype.h> 43 44 __weak_reference(__fmtcheck, fmtcheck); 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 default: 104 break; 105 } 106 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 107 if (strchr("diouxX", *f)) { 108 if (longdouble) 109 RETURN(pf,f,FMTCHECK_UNKNOWN); 110 if (lg) 111 RETURN(pf,f,FMTCHECK_LONG); 112 if (quad) 113 RETURN(pf,f,FMTCHECK_QUAD); 114 RETURN(pf,f,FMTCHECK_INT); 115 } 116 if (*f == 'n') { 117 if (longdouble) 118 RETURN(pf,f,FMTCHECK_UNKNOWN); 119 if (sh) 120 RETURN(pf,f,FMTCHECK_SHORTPOINTER); 121 if (lg) 122 RETURN(pf,f,FMTCHECK_LONGPOINTER); 123 if (quad) 124 RETURN(pf,f,FMTCHECK_QUADPOINTER); 125 RETURN(pf,f,FMTCHECK_INTPOINTER); 126 } 127 if (strchr("DOU", *f)) { 128 if (sh + lg + quad + longdouble) 129 RETURN(pf,f,FMTCHECK_UNKNOWN); 130 RETURN(pf,f,FMTCHECK_LONG); 131 } 132 if (strchr("eEfg", *f)) { 133 if (longdouble) 134 RETURN(pf,f,FMTCHECK_LONGDOUBLE); 135 if (sh + lg + quad) 136 RETURN(pf,f,FMTCHECK_UNKNOWN); 137 RETURN(pf,f,FMTCHECK_DOUBLE); 138 } 139 if (*f == 'c') { 140 if (sh + lg + quad + longdouble) 141 RETURN(pf,f,FMTCHECK_UNKNOWN); 142 RETURN(pf,f,FMTCHECK_INT); 143 } 144 if (*f == 's') { 145 if (sh + lg + quad + longdouble) 146 RETURN(pf,f,FMTCHECK_UNKNOWN); 147 RETURN(pf,f,FMTCHECK_STRING); 148 } 149 if (*f == 'p') { 150 if (sh + lg + quad + longdouble) 151 RETURN(pf,f,FMTCHECK_UNKNOWN); 152 RETURN(pf,f,FMTCHECK_LONG); 153 } 154 RETURN(pf,f,FMTCHECK_UNKNOWN); 155 /*NOTREACHED*/ 156 } 157 158 static EFT 159 get_next_format_from_width(const char **pf) 160 { 161 const char *f; 162 163 f = *pf; 164 if (*f == '.') { 165 f++; 166 if (*f == '*') { 167 RETURN(pf,f,FMTCHECK_PRECISION); 168 } 169 /* eat any precision (empty is allowed) */ 170 while (isdigit(*f)) f++; 171 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 172 } 173 RETURN(pf,f,get_next_format_from_precision(pf)); 174 /*NOTREACHED*/ 175 } 176 177 static EFT 178 get_next_format(const char **pf, EFT eft) 179 { 180 int infmt; 181 const char *f; 182 183 if (eft == FMTCHECK_WIDTH) { 184 (*pf)++; 185 return get_next_format_from_width(pf); 186 } else if (eft == FMTCHECK_PRECISION) { 187 (*pf)++; 188 return get_next_format_from_precision(pf); 189 } 190 191 f = *pf; 192 infmt = 0; 193 while (!infmt) { 194 f = strchr(f, '%'); 195 if (f == NULL) 196 RETURN(pf,f,FMTCHECK_DONE); 197 f++; 198 if (!*f) 199 RETURN(pf,f,FMTCHECK_UNKNOWN); 200 if (*f != '%') 201 infmt = 1; 202 else 203 f++; 204 } 205 206 /* Eat any of the flags */ 207 while (*f && (strchr("#0- +", *f))) 208 f++; 209 210 if (*f == '*') { 211 RETURN(pf,f,FMTCHECK_WIDTH); 212 } 213 /* eat any width */ 214 while (isdigit(*f)) f++; 215 if (!*f) { 216 RETURN(pf,f,FMTCHECK_UNKNOWN); 217 } 218 219 RETURN(pf,f,get_next_format_from_width(pf)); 220 /*NOTREACHED*/ 221 } 222 223 __const char * 224 __fmtcheck(const char *f1, const char *f2) 225 { 226 const char *f1p, *f2p; 227 EFT f1t, f2t; 228 229 if (!f1) return f2; 230 231 f1p = f1; 232 f1t = FMTCHECK_START; 233 f2p = f2; 234 f2t = FMTCHECK_START; 235 while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) { 236 if (f1t == FMTCHECK_UNKNOWN) 237 return f2; 238 f2t = get_next_format(&f2p, f2t); 239 if (f1t != f2t) 240 return f2; 241 } 242 return f1; 243 } 244