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