fmtcheck.c revision 79779
1235070Sjmallett/* $FreeBSD: head/lib/libc/gen/fmtcheck.c 79779 2001-07-16 04:48:28Z kris $ */ 2235070Sjmallett/* $NetBSD: fmtcheck.c,v 1.2 2000/11/01 01:17:20 briggs Exp $ */ 3235070Sjmallett 4235070Sjmallett/*- 5235070Sjmallett * Copyright (c) 2000 The NetBSD Foundation, Inc. 6235070Sjmallett * All rights reserved. 7235070Sjmallett * 8235070Sjmallett * This code was contributed to The NetBSD Foundation by Allen Briggs. 9235070Sjmallett * 10235070Sjmallett * Redistribution and use in source and binary forms, with or without 11235070Sjmallett * modification, are permitted provided that the following conditions 12235070Sjmallett * are met: 13235070Sjmallett * 1. Redistributions of source code must retain the above copyright 14235070Sjmallett * notice, this list of conditions and the following disclaimer. 15235070Sjmallett * 2. Redistributions in binary form must reproduce the above copyright 16235070Sjmallett * notice, this list of conditions and the following disclaimer in the 17235070Sjmallett * documentation and/or other materials provided with the distribution. 18235070Sjmallett * 3. All advertising materials mentioning features or use of this software 19235070Sjmallett * must display the following acknowledgement: 20235070Sjmallett * This product includes software developed by the NetBSD 21235070Sjmallett * Foundation, Inc. and its contributors. 22235070Sjmallett * 4. Neither the name of The NetBSD Foundation nor the names of its 23235070Sjmallett * contributors may be used to endorse or promote products derived 24235070Sjmallett * from this software without specific prior written permission. 25235070Sjmallett * 26235070Sjmallett * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27235070Sjmallett * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28235070Sjmallett * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29235070Sjmallett * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30235070Sjmallett * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31235070Sjmallett * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32235070Sjmallett * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33235070Sjmallett * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34235070Sjmallett * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35235070Sjmallett * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36235070Sjmallett * POSSIBILITY OF SUCH DAMAGE. 37235070Sjmallett */ 38235070Sjmallett 39235118Sjmallett#include <sys/cdefs.h> 40235070Sjmallett#ifndef lint 41235070Sjmallettstatic const char rcsid[] = 42235070Sjmallett "$FreeBSD: head/lib/libc/gen/fmtcheck.c 79779 2001-07-16 04:48:28Z kris $"; 43235070Sjmallett#endif /* not lint */ 44235118Sjmallett 45235070Sjmallett#include "namespace.h" 46255212Sgonzo 47235070Sjmallett#include <stdio.h> 48235070Sjmallett#include <string.h> 49235070Sjmallett#include <ctype.h> 50235070Sjmallett 51255212Sgonzo#ifdef __weak_alias 52255212Sgonzo__weak_alias(fmtcheck,__fmtcheck) 53255212Sgonzo#endif 54255212Sgonzo 55255212Sgonzoenum __e_fmtcheck_types { 56255212Sgonzo FMTCHECK_START, 57235070Sjmallett FMTCHECK_SHORT, 58235070Sjmallett FMTCHECK_INT, 59235070Sjmallett FMTCHECK_LONG, 60235070Sjmallett FMTCHECK_QUAD, 61235070Sjmallett FMTCHECK_SHORTPOINTER, 62235070Sjmallett FMTCHECK_INTPOINTER, 63 FMTCHECK_LONGPOINTER, 64 FMTCHECK_QUADPOINTER, 65 FMTCHECK_DOUBLE, 66 FMTCHECK_LONGDOUBLE, 67 FMTCHECK_STRING, 68 FMTCHECK_WIDTH, 69 FMTCHECK_PRECISION, 70 FMTCHECK_DONE, 71 FMTCHECK_UNKNOWN 72}; 73typedef enum __e_fmtcheck_types EFT; 74 75#define RETURN(pf,f,r) do { \ 76 *(pf) = (f); \ 77 return r; \ 78 } /*NOTREACHED*/ /*CONSTCOND*/ while (0) 79 80static EFT 81get_next_format_from_precision(const char **pf) 82{ 83 int sh, lg, quad, longdouble; 84 const char *f; 85 86 sh = lg = quad = longdouble = 0; 87 88 f = *pf; 89 switch (*f) { 90 case 'h': 91 f++; 92 sh = 1; 93 break; 94 case 'l': 95 f++; 96 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 97 if (*f == 'l') { 98 f++; 99 quad = 1; 100 } else { 101 lg = 1; 102 } 103 break; 104 case 'q': 105 f++; 106 quad = 1; 107 break; 108 case 'L': 109 f++; 110 longdouble = 1; 111 break; 112 default: 113 break; 114 } 115 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 116 if (strchr("diouxX", *f)) { 117 if (longdouble) 118 RETURN(pf,f,FMTCHECK_UNKNOWN); 119 if (lg) 120 RETURN(pf,f,FMTCHECK_LONG); 121 if (quad) 122 RETURN(pf,f,FMTCHECK_QUAD); 123 RETURN(pf,f,FMTCHECK_INT); 124 } 125 if (*f == 'n') { 126 if (longdouble) 127 RETURN(pf,f,FMTCHECK_UNKNOWN); 128 if (sh) 129 RETURN(pf,f,FMTCHECK_SHORTPOINTER); 130 if (lg) 131 RETURN(pf,f,FMTCHECK_LONGPOINTER); 132 if (quad) 133 RETURN(pf,f,FMTCHECK_QUADPOINTER); 134 RETURN(pf,f,FMTCHECK_INTPOINTER); 135 } 136 if (strchr("DOU", *f)) { 137 if (sh + lg + quad + longdouble) 138 RETURN(pf,f,FMTCHECK_UNKNOWN); 139 RETURN(pf,f,FMTCHECK_LONG); 140 } 141 if (strchr("eEfg", *f)) { 142 if (longdouble) 143 RETURN(pf,f,FMTCHECK_LONGDOUBLE); 144 if (sh + lg + quad) 145 RETURN(pf,f,FMTCHECK_UNKNOWN); 146 RETURN(pf,f,FMTCHECK_DOUBLE); 147 } 148 if (*f == 'c') { 149 if (sh + lg + quad + longdouble) 150 RETURN(pf,f,FMTCHECK_UNKNOWN); 151 RETURN(pf,f,FMTCHECK_INT); 152 } 153 if (*f == 's') { 154 if (sh + lg + quad + longdouble) 155 RETURN(pf,f,FMTCHECK_UNKNOWN); 156 RETURN(pf,f,FMTCHECK_STRING); 157 } 158 if (*f == 'p') { 159 if (sh + lg + quad + longdouble) 160 RETURN(pf,f,FMTCHECK_UNKNOWN); 161 RETURN(pf,f,FMTCHECK_LONG); 162 } 163 RETURN(pf,f,FMTCHECK_UNKNOWN); 164 /*NOTREACHED*/ 165} 166 167static EFT 168get_next_format_from_width(const char **pf) 169{ 170 const char *f; 171 172 f = *pf; 173 if (*f == '.') { 174 f++; 175 if (*f == '*') { 176 RETURN(pf,f,FMTCHECK_PRECISION); 177 } 178 /* eat any precision (empty is allowed) */ 179 while (isdigit(*f)) f++; 180 if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); 181 } 182 RETURN(pf,f,get_next_format_from_precision(pf)); 183 /*NOTREACHED*/ 184} 185 186static EFT 187get_next_format(const char **pf, EFT eft) 188{ 189 int infmt; 190 const char *f; 191 192 if (eft == FMTCHECK_WIDTH) { 193 (*pf)++; 194 return get_next_format_from_width(pf); 195 } else if (eft == FMTCHECK_PRECISION) { 196 (*pf)++; 197 return get_next_format_from_precision(pf); 198 } 199 200 f = *pf; 201 infmt = 0; 202 while (!infmt) { 203 f = strchr(f, '%'); 204 if (f == NULL) 205 RETURN(pf,f,FMTCHECK_DONE); 206 f++; 207 if (!*f) 208 RETURN(pf,f,FMTCHECK_UNKNOWN); 209 if (*f != '%') 210 infmt = 1; 211 else 212 f++; 213 } 214 215 /* Eat any of the flags */ 216 while (*f && (strchr("#0- +", *f))) 217 f++; 218 219 if (*f == '*') { 220 RETURN(pf,f,FMTCHECK_WIDTH); 221 } 222 /* eat any width */ 223 while (isdigit(*f)) f++; 224 if (!*f) { 225 RETURN(pf,f,FMTCHECK_UNKNOWN); 226 } 227 228 RETURN(pf,f,get_next_format_from_width(pf)); 229 /*NOTREACHED*/ 230} 231 232__const char * 233fmtcheck(const char *f1, const char *f2) 234{ 235 const char *f1p, *f2p; 236 EFT f1t, f2t; 237 238 if (!f1) return f2; 239 240 f1p = f1; 241 f1t = FMTCHECK_START; 242 f2p = f2; 243 f2t = FMTCHECK_START; 244 while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) { 245 if (f1t == FMTCHECK_UNKNOWN) 246 return f2; 247 f2t = get_next_format(&f2p, f2t); 248 if (f1t != f2t) 249 return f2; 250 } 251 return f1; 252} 253