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