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