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