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_PTRDIFFT, 53 FMTCHECK_SIZET, 54 FMTCHECK_SHORTPOINTER, 55 FMTCHECK_INTPOINTER, 56 FMTCHECK_LONGPOINTER, 57 FMTCHECK_QUADPOINTER, 58 FMTCHECK_PTRDIFFTPOINTER, 59 FMTCHECK_SIZETPOINTER, 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, ptrdifft, sizet; 79 const char *f; 80 81 sh = lg = quad = longdouble = ptrdifft = sizet = 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 't': 104 f++; 105 ptrdifft = 1; 106 break; 107 case 'z': 108 f++; 109 sizet = 1; 110 break; 111 case 'L': 112 f++; 113 longdouble = 1; 114 break; 115 default: 116 break; 117 } 118 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 119 if (strchr("diouxX", *f)) { 120 if (longdouble) 121 RETURN(pf,f,FMTCHECK_UNKNOWN); 122 if (lg) 123 RETURN(pf,f,FMTCHECK_LONG); 124 if (quad) 125 RETURN(pf,f,FMTCHECK_QUAD); 126 if (ptrdifft) 127 RETURN(pf,f,FMTCHECK_PTRDIFFT); 128 if (sizet) 129 RETURN(pf,f,FMTCHECK_SIZET); 130 RETURN(pf,f,FMTCHECK_INT); 131 } 132 if (*f == 'n') { 133 if (longdouble) 134 RETURN(pf,f,FMTCHECK_UNKNOWN); 135 if (sh) 136 RETURN(pf,f,FMTCHECK_SHORTPOINTER); 137 if (lg) 138 RETURN(pf,f,FMTCHECK_LONGPOINTER); 139 if (quad) 140 RETURN(pf,f,FMTCHECK_QUADPOINTER); 141 if (ptrdifft) 142 RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER); 143 if (sizet) 144 RETURN(pf,f,FMTCHECK_SIZETPOINTER); 145 RETURN(pf,f,FMTCHECK_INTPOINTER); 146 } 147 if (strchr("DOU", *f)) { 148 if (sh + lg + quad + longdouble + ptrdifft + sizet) 149 RETURN(pf,f,FMTCHECK_UNKNOWN); 150 RETURN(pf,f,FMTCHECK_LONG); 151 } 152 if (strchr("aAeEfFgG", *f)) { 153 if (longdouble) 154 RETURN(pf,f,FMTCHECK_LONGDOUBLE); 155 if (sh + lg + quad + ptrdifft + sizet) 156 RETURN(pf,f,FMTCHECK_UNKNOWN); 157 RETURN(pf,f,FMTCHECK_DOUBLE); 158 } 159 if (*f == 'c') { 160 if (sh + lg + quad + longdouble + ptrdifft + sizet) 161 RETURN(pf,f,FMTCHECK_UNKNOWN); 162 RETURN(pf,f,FMTCHECK_INT); 163 } 164 if (*f == 's') { 165 if (sh + lg + quad + longdouble + ptrdifft + sizet) 166 RETURN(pf,f,FMTCHECK_UNKNOWN); 167 RETURN(pf,f,FMTCHECK_STRING); 168 } 169 if (*f == 'p') { 170 if (sh + lg + quad + longdouble + ptrdifft + sizet) 171 RETURN(pf,f,FMTCHECK_UNKNOWN); 172 RETURN(pf,f,FMTCHECK_LONG); 173 } 174 RETURN(pf,f,FMTCHECK_UNKNOWN); 175 /*NOTREACHED*/ 176 } 177 178 static EFT 179 get_next_format_from_width(const char **pf) 180 { 181 const char *f; 182 183 f = *pf; 184 if (*f == '.') { 185 f++; 186 if (*f == '*') { 187 RETURN(pf,f,FMTCHECK_PRECISION); 188 } 189 /* eat any precision (empty is allowed) */ 190 while (isdigit(*f)) f++; 191 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 192 } 193 RETURN(pf,f,get_next_format_from_precision(pf)); 194 /*NOTREACHED*/ 195 } 196 197 static EFT 198 get_next_format(const char **pf, EFT eft) 199 { 200 int infmt; 201 const char *f; 202 203 if (eft == FMTCHECK_WIDTH) { 204 (*pf)++; 205 return get_next_format_from_width(pf); 206 } else if (eft == FMTCHECK_PRECISION) { 207 (*pf)++; 208 return get_next_format_from_precision(pf); 209 } 210 211 f = *pf; 212 infmt = 0; 213 while (!infmt) { 214 f = strchr(f, '%'); 215 if (f == NULL) 216 RETURN(pf,f,FMTCHECK_DONE); 217 f++; 218 if (!*f) 219 RETURN(pf,f,FMTCHECK_UNKNOWN); 220 if (*f != '%') 221 infmt = 1; 222 else 223 f++; 224 } 225 226 /* Eat any of the flags */ 227 while (*f && (strchr("#0- +", *f))) 228 f++; 229 230 if (*f == '*') { 231 RETURN(pf,f,FMTCHECK_WIDTH); 232 } 233 /* eat any width */ 234 while (isdigit(*f)) f++; 235 if (!*f) { 236 RETURN(pf,f,FMTCHECK_UNKNOWN); 237 } 238 239 RETURN(pf,f,get_next_format_from_width(pf)); 240 /*NOTREACHED*/ 241 } 242 243 __const char * 244 __fmtcheck(const char *f1, const char *f2) 245 { 246 const char *f1p, *f2p; 247 EFT f1t, f2t; 248 249 if (!f1) return f2; 250 251 f1p = f1; 252 f1t = FMTCHECK_START; 253 f2p = f2; 254 f2t = FMTCHECK_START; 255 while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) { 256 if (f1t == FMTCHECK_UNKNOWN) 257 return f2; 258 f2t = get_next_format(&f2p, f2t); 259 if (f1t != f2t) 260 return f2; 261 } 262 return f1; 263 } 264