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