1 /* $OpenBSD: vsscanf.c,v 1.2 2015/09/27 05:25:00 guenther 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.2 2015/09/27 05:25:00 guenther 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 NCURSES_EXPORT(int) 165 vsscanf(const char *str, const char *format, va_list ap) 166 { 167 #if HAVE_VFSCANF || HAVE__DOSCAN 168 /* 169 * This code should work on anything descended from AT&T SVr1. 170 */ 171 FILE strbuf; 172 173 strbuf._flag = _IOREAD; 174 strbuf._ptr = strbuf._base = (unsigned char *) str; 175 strbuf._cnt = strlen(str); 176 strbuf._file = _NFILE; 177 178 #if HAVE_VFSCANF 179 return (vfscanf(&strbuf, format, ap)); 180 #else 181 return (_doscan(&strbuf, format, ap)); 182 #endif 183 #else 184 static int can_convert = -1; 185 186 int assigned = 0; 187 int consumed = 0; 188 189 T((T_CALLED("vsscanf(%s,%s,...)"), 190 _nc_visbuf2(1, str), 191 _nc_visbuf2(2, format))); 192 193 /* 194 * This relies on having a working "%n" format conversion. Check if it 195 * works. Only very old C libraries do not support it. 196 * 197 * FIXME: move this check into the configure script. 198 */ 199 if (can_convert < 0) { 200 int check1; 201 int check2; 202 if (sscanf("123", "%d%n", &check1, &check2) > 0 203 && check1 == 123 204 && check2 == 3) { 205 can_convert = 1; 206 } else { 207 can_convert = 0; 208 } 209 } 210 211 if (can_convert) { 212 size_t len_fmt = strlen(format) + 32; 213 char *my_fmt = malloc(len_fmt); 214 ChunkType chunk, ctest; 215 OtherType other, otest; 216 ScanState state; 217 unsigned n; 218 int eaten; 219 void *pointer; 220 221 if (my_fmt != 0) { 222 /* 223 * Split the original format into chunks, adding a "%n" to the end 224 * of each (except of course if it used %n), and use that 225 * information to decide where to start scanning the next chunk. 226 * 227 * FIXME: does %n count bytes or characters? If the latter, this 228 * will require further work for multibyte strings. 229 */ 230 while (*format != '\0') { 231 /* find a chunk */ 232 state = sUnknown; 233 chunk = cUnknown; 234 other = oUnknown; 235 pointer = 0; 236 for (n = 0; format[n] != 0 && state != sFinal; ++n) { 237 my_fmt[n] = format[n]; 238 switch (state) { 239 case sUnknown: 240 if (format[n] == '%') 241 state = sPercent; 242 break; 243 case sPercent: 244 if (format[n] == '%') { 245 state = sUnknown; 246 } else if (format[n] == L_SQUARE) { 247 state = sLeft; 248 } else { 249 state = sNormal; 250 --n; 251 } 252 break; 253 case sLeft: 254 state = sRange; 255 if (format[n] == '^') { 256 ++n; 257 my_fmt[n] = format[n]; 258 } 259 break; 260 case sRange: 261 if (format[n] == R_SQUARE) { 262 state = sFinal; 263 chunk = cRange; 264 } 265 break; 266 case sNormal: 267 if (format[n] == '*') { 268 state = sUnknown; 269 } else { 270 if ((ctest = final_ch(format[n], other)) != cUnknown) { 271 state = sFinal; 272 chunk = ctest; 273 } else if ((otest = other_ch(format[n])) != oUnknown) { 274 other = otest; 275 } else if (isalpha(UChar(format[n]))) { 276 state = sFinal; 277 chunk = cError; 278 } 279 } 280 break; 281 case sFinal: 282 break; 283 } 284 } 285 my_fmt[n] = '\0'; 286 format += n; 287 288 if (chunk == cUnknown 289 || chunk == cError) { 290 if (assigned == 0) 291 assigned = EOF; 292 break; 293 } 294 295 /* add %n, if the format was not that */ 296 if (chunk != cAssigned) { 297 strlcat(my_fmt, "%n", len_fmt); 298 } 299 300 switch (chunk) { 301 case cAssigned: 302 strlcat(my_fmt, "%n", len_fmt); 303 pointer = &eaten; 304 break; 305 case cInt: 306 pointer = va_arg(ap, int *); 307 break; 308 case cShort: 309 pointer = va_arg(ap, short *); 310 break; 311 case cFloat: 312 pointer = va_arg(ap, float *); 313 break; 314 case cDouble: 315 pointer = va_arg(ap, double *); 316 break; 317 case cLong: 318 pointer = va_arg(ap, long *); 319 break; 320 case cPointer: 321 pointer = va_arg(ap, void *); 322 break; 323 case cChar: 324 case cRange: 325 case cString: 326 pointer = va_arg(ap, char *); 327 break; 328 case cError: 329 case cUnknown: 330 break; 331 } 332 /* do the conversion */ 333 T(("...converting chunk #%d type %d(%s,%s)", 334 assigned + 1, chunk, 335 _nc_visbuf2(1, str + consumed), 336 _nc_visbuf2(2, my_fmt))); 337 if (sscanf(str + consumed, my_fmt, pointer, &eaten) > 0) 338 consumed += eaten; 339 else 340 break; 341 ++assigned; 342 } 343 free(my_fmt); 344 } 345 } 346 returnCode(assigned); 347 #endif 348 } 349 #else 350 extern 351 NCURSES_EXPORT(void) 352 _nc_vsscanf(void); /* quiet's gcc warning */ 353 NCURSES_EXPORT(void) 354 _nc_vsscanf(void) 355 { 356 } /* nonempty for strict ANSI compilers */ 357 #endif /* !HAVE_VSSCANF */ 358