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