fmtcheck.c revision 299236
1193323Sed/* $NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp $ */ 2193323Sed 3193323Sed/*- 4193323Sed * Copyright (c) 2000 The NetBSD Foundation, Inc. 5193323Sed * All rights reserved. 6193323Sed * 7193323Sed * This code was contributed to The NetBSD Foundation by Allen Briggs. 8193323Sed * 9193323Sed * Redistribution and use in source and binary forms, with or without 10193323Sed * modification, are permitted provided that the following conditions 11193323Sed * are met: 12193323Sed * 1. Redistributions of source code must retain the above copyright 13193323Sed * notice, this list of conditions and the following disclaimer. 14193323Sed * 2. Redistributions in binary form must reproduce the above copyright 15193323Sed * notice, this list of conditions and the following disclaimer in the 16218893Sdim * documentation and/or other materials provided with the distribution. 17193323Sed * 18193323Sed * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19193323Sed * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20193323Sed * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21193323Sed * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22193323Sed * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23193323Sed * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24194612Sed * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25194612Sed * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26193323Sed * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27193323Sed * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28193323Sed * POSSIBILITY OF SUCH DAMAGE. 29193323Sed */ 30234353Sdim 31193323Sed#include "file.h" 32234353Sdim 33234353Sdim#include <stdio.h> 34234353Sdim#include <string.h> 35234353Sdim#include <ctype.h> 36234353Sdim 37193323Sedenum __e_fmtcheck_types { 38234353Sdim FMTCHECK_START, 39193323Sed FMTCHECK_SHORT, 40193323Sed FMTCHECK_INT, 41193323Sed FMTCHECK_LONG, 42193323Sed FMTCHECK_QUAD, 43193323Sed FMTCHECK_SHORTPOINTER, 44193323Sed FMTCHECK_INTPOINTER, 45193323Sed FMTCHECK_LONGPOINTER, 46194612Sed FMTCHECK_QUADPOINTER, 47193323Sed FMTCHECK_DOUBLE, 48193323Sed FMTCHECK_LONGDOUBLE, 49193323Sed FMTCHECK_STRING, 50193323Sed FMTCHECK_WIDTH, 51193323Sed FMTCHECK_PRECISION, 52193323Sed FMTCHECK_DONE, 53193323Sed FMTCHECK_UNKNOWN 54193323Sed}; 55193323Sedtypedef enum __e_fmtcheck_types EFT; 56193323Sed 57193323Sed#define RETURN(pf,f,r) do { \ 58193323Sed *(pf) = (f); \ 59193323Sed return r; \ 60193323Sed } /*NOTREACHED*/ /*CONSTCOND*/ while (0) 61193323Sed 62193323Sedstatic EFT 63193323Sedget_next_format_from_precision(const char **pf) 64193323Sed{ 65193323Sed int sh, lg, quad, longdouble; 66193323Sed const char *f; 67193323Sed 68193323Sed sh = lg = quad = longdouble = 0; 69193323Sed 70193323Sed f = *pf; 71193323Sed switch (*f) { 72193323Sed case 'h': 73193323Sed f++; 74193323Sed sh = 1; 75193323Sed break; 76193323Sed case 'l': 77193323Sed f++; 78193323Sed if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 79193323Sed if (*f == 'l') { 80194612Sed f++; 81193323Sed quad = 1; 82 } else { 83 lg = 1; 84 } 85 break; 86 case 'q': 87 f++; 88 quad = 1; 89 break; 90 case 'L': 91 f++; 92 longdouble = 1; 93 break; 94 default: 95 break; 96 } 97 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 98 if (strchr("diouxX", *f)) { 99 if (longdouble) 100 RETURN(pf,f,FMTCHECK_UNKNOWN); 101 if (lg) 102 RETURN(pf,f,FMTCHECK_LONG); 103 if (quad) 104 RETURN(pf,f,FMTCHECK_QUAD); 105 RETURN(pf,f,FMTCHECK_INT); 106 } 107 if (*f == 'n') { 108 if (longdouble) 109 RETURN(pf,f,FMTCHECK_UNKNOWN); 110 if (sh) 111 RETURN(pf,f,FMTCHECK_SHORTPOINTER); 112 if (lg) 113 RETURN(pf,f,FMTCHECK_LONGPOINTER); 114 if (quad) 115 RETURN(pf,f,FMTCHECK_QUADPOINTER); 116 RETURN(pf,f,FMTCHECK_INTPOINTER); 117 } 118 if (strchr("DOU", *f)) { 119 if (sh + lg + quad + longdouble) 120 RETURN(pf,f,FMTCHECK_UNKNOWN); 121 RETURN(pf,f,FMTCHECK_LONG); 122 } 123 if (strchr("eEfg", *f)) { 124 if (longdouble) 125 RETURN(pf,f,FMTCHECK_LONGDOUBLE); 126 if (sh + lg + quad) 127 RETURN(pf,f,FMTCHECK_UNKNOWN); 128 RETURN(pf,f,FMTCHECK_DOUBLE); 129 } 130 if (*f == 'c') { 131 if (sh + lg + quad + longdouble) 132 RETURN(pf,f,FMTCHECK_UNKNOWN); 133 RETURN(pf,f,FMTCHECK_INT); 134 } 135 if (*f == 's') { 136 if (sh + lg + quad + longdouble) 137 RETURN(pf,f,FMTCHECK_UNKNOWN); 138 RETURN(pf,f,FMTCHECK_STRING); 139 } 140 if (*f == 'p') { 141 if (sh + lg + quad + longdouble) 142 RETURN(pf,f,FMTCHECK_UNKNOWN); 143 RETURN(pf,f,FMTCHECK_LONG); 144 } 145 RETURN(pf,f,FMTCHECK_UNKNOWN); 146 /*NOTREACHED*/ 147} 148 149static EFT 150get_next_format_from_width(const char **pf) 151{ 152 const char *f; 153 154 f = *pf; 155 if (*f == '.') { 156 f++; 157 if (*f == '*') { 158 RETURN(pf,f,FMTCHECK_PRECISION); 159 } 160 /* eat any precision (empty is allowed) */ 161 while (isdigit((unsigned char)*f)) f++; 162 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 163 } 164 RETURN(pf,f,get_next_format_from_precision(pf)); 165 /*NOTREACHED*/ 166} 167 168static EFT 169get_next_format(const char **pf, EFT eft) 170{ 171 int infmt; 172 const char *f; 173 174 if (eft == FMTCHECK_WIDTH) { 175 (*pf)++; 176 return get_next_format_from_width(pf); 177 } else if (eft == FMTCHECK_PRECISION) { 178 (*pf)++; 179 return get_next_format_from_precision(pf); 180 } 181 182 f = *pf; 183 infmt = 0; 184 while (!infmt) { 185 f = strchr(f, '%'); 186 if (f == NULL) 187 RETURN(pf,f,FMTCHECK_DONE); 188 f++; 189 if (!*f) 190 RETURN(pf,f,FMTCHECK_UNKNOWN); 191 if (*f != '%') 192 infmt = 1; 193 else 194 f++; 195 } 196 197 /* Eat any of the flags */ 198 while (*f && (strchr("#0- +", *f))) 199 f++; 200 201 if (*f == '*') { 202 RETURN(pf,f,FMTCHECK_WIDTH); 203 } 204 /* eat any width */ 205 while (isdigit((unsigned char)*f)) f++; 206 if (!*f) { 207 RETURN(pf,f,FMTCHECK_UNKNOWN); 208 } 209 210 RETURN(pf,f,get_next_format_from_width(pf)); 211 /*NOTREACHED*/ 212} 213 214const char * 215fmtcheck(const char *f1, const char *f2) 216{ 217 const char *f1p, *f2p; 218 EFT f1t, f2t; 219 220 if (!f1) return f2; 221 222 f1p = f1; 223 f1t = FMTCHECK_START; 224 f2p = f2; 225 f2t = FMTCHECK_START; 226 while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) { 227 if (f1t == FMTCHECK_UNKNOWN) 228 return f2; 229 f2t = get_next_format(&f2p, f2t); 230 if (f1t != f2t) 231 return f2; 232 } 233 return f1; 234} 235