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