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