1 /* $OpenBSD: vsscanf.c,v 1.1 2010/01/12 23:22:06 nicm Exp $ */ 2 3 /**************************************************************************** 4 * Copyright (c) 1998-2003,2004 Free Software Foundation, Inc. * 5 * * 6 * Permission is hereby granted, free of charge, to any person obtaining a * 7 * copy of this software and associated documentation files (the * 8 * "Software"), to deal in the Software without restriction, including * 9 * without limitation the rights to use, copy, modify, merge, publish, * 10 * distribute, distribute with modifications, sublicense, and/or sell * 11 * copies of the Software, and to permit persons to whom the Software is * 12 * furnished to do so, subject to the following conditions: * 13 * * 14 * The above copyright notice and this permission notice shall be included * 15 * in all copies or substantial portions of the Software. * 16 * * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 20 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 23 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 24 * * 25 * Except as contained in this notice, the name(s) of the above copyright * 26 * holders shall not be used in advertising or otherwise to promote the * 27 * sale, use or other dealings in this Software without prior written * 28 * authorization. * 29 ****************************************************************************/ 30 31 /**************************************************************************** 32 * State-machine fallback written by Thomas E. Dickey 2002 * 33 ****************************************************************************/ 34 35 /* 36 * This function is needed to support vwscanw 37 */ 38 39 #include <curses.priv.h> 40 41 #if !HAVE_VSSCANF 42 43 MODULE_ID("$Id: vsscanf.c,v 1.1 2010/01/12 23:22:06 nicm Exp $") 44 45 #if !(HAVE_VFSCANF || HAVE__DOSCAN) 46 47 #include <ctype.h> 48 49 #define L_SQUARE '[' 50 #define R_SQUARE ']' 51 52 typedef enum { 53 cUnknown 54 ,cError /* anything that isn't ANSI */ 55 ,cAssigned 56 ,cChar 57 ,cInt 58 ,cFloat 59 ,cDouble 60 ,cPointer 61 ,cLong 62 ,cShort 63 ,cRange 64 ,cString 65 } ChunkType; 66 67 typedef enum { 68 oUnknown 69 ,oShort 70 ,oLong 71 } OtherType; 72 73 typedef enum { 74 sUnknown 75 ,sPercent /* last was '%' beginning a format */ 76 ,sNormal /* ...somewhere in the middle */ 77 ,sLeft /* last was left square bracket beginning a range */ 78 ,sRange /* ...somewhere in the middle */ 79 ,sFinal /* last finished a format */ 80 } ScanState; 81 82 static ChunkType 83 final_ch(int ch, OtherType other) 84 { 85 ChunkType result = cUnknown; 86 87 switch (ch) { 88 case 'c': 89 if (other == oUnknown) 90 result = cChar; 91 else 92 result = cError; 93 break; 94 case 'd': 95 case 'i': 96 case 'X': 97 case 'x': 98 switch (other) { 99 case oUnknown: 100 result = cInt; 101 break; 102 case oShort: 103 result = cShort; 104 break; 105 case oLong: 106 result = cLong; 107 break; 108 } 109 break; 110 case 'E': 111 case 'e': 112 case 'f': 113 case 'g': 114 switch (other) { 115 case oUnknown: 116 result = cFloat; 117 break; 118 case oShort: 119 result = cError; 120 break; 121 case oLong: 122 result = cDouble; 123 break; 124 } 125 break; 126 case 'n': 127 if (other == oUnknown) 128 result = cAssigned; 129 else 130 result = cError; 131 break; 132 case 'p': 133 if (other == oUnknown) 134 result = cPointer; 135 else 136 result = cError; 137 break; 138 case 's': 139 if (other == oUnknown) 140 result = cString; 141 else 142 result = cError; 143 break; 144 } 145 return result; 146 } 147 148 static OtherType 149 other_ch(int ch) 150 { 151 OtherType result = oUnknown; 152 switch (ch) { 153 case 'h': 154 result = oShort; 155 break; 156 case 'l': 157 result = oLong; 158 break; 159 } 160 return result; 161 } 162 #endif 163 164 /*VARARGS2*/ 165 NCURSES_EXPORT(int) 166 vsscanf(const char *str, const char *format, va_list ap) 167 { 168 #if HAVE_VFSCANF || HAVE__DOSCAN 169 /* 170 * This code should work on anything descended from AT&T SVr1. 171 */ 172 FILE strbuf; 173 174 strbuf._flag = _IOREAD; 175 strbuf._ptr = strbuf._base = (unsigned char *) str; 176 strbuf._cnt = strlen(str); 177 strbuf._file = _NFILE; 178 179 #if HAVE_VFSCANF 180 return (vfscanf(&strbuf, format, ap)); 181 #else 182 return (_doscan(&strbuf, format, ap)); 183 #endif 184 #else 185 static int can_convert = -1; 186 187 int assigned = 0; 188 int consumed = 0; 189 190 T((T_CALLED("vsscanf(%s,%s,...)"), 191 _nc_visbuf2(1, str), 192 _nc_visbuf2(2, format))); 193 194 /* 195 * This relies on having a working "%n" format conversion. Check if it 196 * works. Only very old C libraries do not support it. 197 * 198 * FIXME: move this check into the configure script. 199 */ 200 if (can_convert < 0) { 201 int check1; 202 int check2; 203 if (sscanf("123", "%d%n", &check1, &check2) > 0 204 && check1 == 123 205 && check2 == 3) { 206 can_convert = 1; 207 } else { 208 can_convert = 0; 209 } 210 } 211 212 if (can_convert) { 213 size_t len_fmt = strlen(format) + 32; 214 char *my_fmt = malloc(len_fmt); 215 ChunkType chunk, ctest; 216 OtherType other, otest; 217 ScanState state; 218 unsigned n; 219 int eaten; 220 void *pointer; 221 222 if (my_fmt != 0) { 223 /* 224 * Split the original format into chunks, adding a "%n" to the end 225 * of each (except of course if it used %n), and use that 226 * information to decide where to start scanning the next chunk. 227 * 228 * FIXME: does %n count bytes or characters? If the latter, this 229 * will require further work for multibyte strings. 230 */ 231 while (*format != '\0') { 232 /* find a chunk */ 233 state = sUnknown; 234 chunk = cUnknown; 235 other = oUnknown; 236 pointer = 0; 237 for (n = 0; format[n] != 0 && state != sFinal; ++n) { 238 my_fmt[n] = format[n]; 239 switch (state) { 240 case sUnknown: 241 if (format[n] == '%') 242 state = sPercent; 243 break; 244 case sPercent: 245 if (format[n] == '%') { 246 state = sUnknown; 247 } else if (format[n] == L_SQUARE) { 248 state = sLeft; 249 } else { 250 state = sNormal; 251 --n; 252 } 253 break; 254 case sLeft: 255 state = sRange; 256 if (format[n] == '^') { 257 ++n; 258 my_fmt[n] = format[n]; 259 } 260 break; 261 case sRange: 262 if (format[n] == R_SQUARE) { 263 state = sFinal; 264 chunk = cRange; 265 } 266 break; 267 case sNormal: 268 if (format[n] == '*') { 269 state = sUnknown; 270 } else { 271 if ((ctest = final_ch(format[n], other)) != cUnknown) { 272 state = sFinal; 273 chunk = ctest; 274 } else if ((otest = other_ch(format[n])) != oUnknown) { 275 other = otest; 276 } else if (isalpha(UChar(format[n]))) { 277 state = sFinal; 278 chunk = cError; 279 } 280 } 281 break; 282 case sFinal: 283 break; 284 } 285 } 286 my_fmt[n] = '\0'; 287 format += n; 288 289 if (chunk == cUnknown 290 || chunk == cError) { 291 if (assigned == 0) 292 assigned = EOF; 293 break; 294 } 295 296 /* add %n, if the format was not that */ 297 if (chunk != cAssigned) { 298 strlcat(my_fmt, "%n", len_fmt); 299 } 300 301 switch (chunk) { 302 case cAssigned: 303 strlcat(my_fmt, "%n", len_fmt); 304 pointer = &eaten; 305 break; 306 case cInt: 307 pointer = va_arg(ap, int *); 308 break; 309 case cShort: 310 pointer = va_arg(ap, short *); 311 break; 312 case cFloat: 313 pointer = va_arg(ap, float *); 314 break; 315 case cDouble: 316 pointer = va_arg(ap, double *); 317 break; 318 case cLong: 319 pointer = va_arg(ap, long *); 320 break; 321 case cPointer: 322 pointer = va_arg(ap, void *); 323 break; 324 case cChar: 325 case cRange: 326 case cString: 327 pointer = va_arg(ap, char *); 328 break; 329 case cError: 330 case cUnknown: 331 break; 332 } 333 /* do the conversion */ 334 T(("...converting chunk #%d type %d(%s,%s)", 335 assigned + 1, chunk, 336 _nc_visbuf2(1, str + consumed), 337 _nc_visbuf2(2, my_fmt))); 338 if (sscanf(str + consumed, my_fmt, pointer, &eaten) > 0) 339 consumed += eaten; 340 else 341 break; 342 ++assigned; 343 } 344 free(my_fmt); 345 } 346 } 347 returnCode(assigned); 348 #endif 349 } 350 #else 351 extern 352 NCURSES_EXPORT(void) 353 _nc_vsscanf(void); /* quiet's gcc warning */ 354 NCURSES_EXPORT(void) 355 _nc_vsscanf(void) 356 { 357 } /* nonempty for strict ANSI compilers */ 358 #endif /* !HAVE_VSSCANF */ 359