197049Speter/**************************************************************************** 2262685Sdelphij * Copyright (c) 1998-2004,2012 Free Software Foundation, Inc. * 397049Speter * * 497049Speter * Permission is hereby granted, free of charge, to any person obtaining a * 597049Speter * copy of this software and associated documentation files (the * 697049Speter * "Software"), to deal in the Software without restriction, including * 797049Speter * without limitation the rights to use, copy, modify, merge, publish, * 897049Speter * distribute, distribute with modifications, sublicense, and/or sell * 997049Speter * copies of the Software, and to permit persons to whom the Software is * 1097049Speter * furnished to do so, subject to the following conditions: * 1197049Speter * * 1297049Speter * The above copyright notice and this permission notice shall be included * 1397049Speter * in all copies or substantial portions of the Software. * 1497049Speter * * 1597049Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 1697049Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 1797049Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 1897049Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 1997049Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 2097049Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 2197049Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 2297049Speter * * 2397049Speter * Except as contained in this notice, the name(s) of the above copyright * 2497049Speter * holders shall not be used in advertising or otherwise to promote the * 2597049Speter * sale, use or other dealings in this Software without prior written * 2697049Speter * authorization. * 2797049Speter ****************************************************************************/ 2897049Speter 2997049Speter/**************************************************************************** 3097049Speter * State-machine fallback written by Thomas E. Dickey 2002 * 3197049Speter ****************************************************************************/ 3297049Speter 3350276Speter/* 3450276Speter * This function is needed to support vwscanw 3550276Speter */ 3650276Speter 3750276Speter#include <curses.priv.h> 3850276Speter 3950276Speter#if !HAVE_VSSCANF 4050276Speter 41262685SdelphijMODULE_ID("$Id: vsscanf.c,v 1.20 2012/02/22 22:26:58 tom Exp $") 4250276Speter 4397049Speter#if !(HAVE_VFSCANF || HAVE__DOSCAN) 4497049Speter 4597049Speter#include <ctype.h> 4697049Speter 4797049Speter#define L_SQUARE '[' 4897049Speter#define R_SQUARE ']' 4997049Speter 5097049Spetertypedef enum { 5197049Speter cUnknown 5297049Speter ,cError /* anything that isn't ANSI */ 5397049Speter ,cAssigned 5497049Speter ,cChar 5597049Speter ,cInt 5697049Speter ,cFloat 5797049Speter ,cDouble 5897049Speter ,cPointer 5997049Speter ,cLong 6097049Speter ,cShort 6197049Speter ,cRange 6297049Speter ,cString 6397049Speter} ChunkType; 6497049Speter 6597049Spetertypedef enum { 6697049Speter oUnknown 6797049Speter ,oShort 6897049Speter ,oLong 6997049Speter} OtherType; 7097049Speter 7197049Spetertypedef enum { 7297049Speter sUnknown 7397049Speter ,sPercent /* last was '%' beginning a format */ 7497049Speter ,sNormal /* ...somewhere in the middle */ 7597049Speter ,sLeft /* last was left square bracket beginning a range */ 7697049Speter ,sRange /* ...somewhere in the middle */ 7797049Speter ,sFinal /* last finished a format */ 7897049Speter} ScanState; 7997049Speter 8097049Speterstatic ChunkType 8197049Speterfinal_ch(int ch, OtherType other) 8297049Speter{ 8397049Speter ChunkType result = cUnknown; 8497049Speter 8597049Speter switch (ch) { 8697049Speter case 'c': 8797049Speter if (other == oUnknown) 8897049Speter result = cChar; 8997049Speter else 9097049Speter result = cError; 9197049Speter break; 9297049Speter case 'd': 9397049Speter case 'i': 9497049Speter case 'X': 9597049Speter case 'x': 9697049Speter switch (other) { 9797049Speter case oUnknown: 9897049Speter result = cInt; 9997049Speter break; 10097049Speter case oShort: 10197049Speter result = cShort; 10297049Speter break; 10397049Speter case oLong: 10497049Speter result = cLong; 10597049Speter break; 10697049Speter } 10797049Speter break; 10897049Speter case 'E': 10997049Speter case 'e': 11097049Speter case 'f': 11197049Speter case 'g': 11297049Speter switch (other) { 11397049Speter case oUnknown: 11497049Speter result = cFloat; 11597049Speter break; 11697049Speter case oShort: 11797049Speter result = cError; 11897049Speter break; 11997049Speter case oLong: 12097049Speter result = cDouble; 12197049Speter break; 12297049Speter } 12397049Speter break; 12497049Speter case 'n': 12597049Speter if (other == oUnknown) 12697049Speter result = cAssigned; 12797049Speter else 12897049Speter result = cError; 12997049Speter break; 13097049Speter case 'p': 13197049Speter if (other == oUnknown) 13297049Speter result = cPointer; 13397049Speter else 13497049Speter result = cError; 13597049Speter break; 13697049Speter case 's': 13797049Speter if (other == oUnknown) 13897049Speter result = cString; 13997049Speter else 14097049Speter result = cError; 14197049Speter break; 14297049Speter } 14397049Speter return result; 14497049Speter} 14597049Speter 14697049Speterstatic OtherType 14797049Speterother_ch(int ch) 14897049Speter{ 14997049Speter OtherType result = oUnknown; 15097049Speter switch (ch) { 15197049Speter case 'h': 15297049Speter result = oShort; 15397049Speter break; 15497049Speter case 'l': 15597049Speter result = oLong; 15697049Speter break; 15797049Speter } 15897049Speter return result; 15997049Speter} 16097049Speter#endif 16197049Speter 16250276Speter/*VARARGS2*/ 16376726SpeterNCURSES_EXPORT(int) 16497049Spetervsscanf(const char *str, const char *format, va_list ap) 16550276Speter{ 16697049Speter#if HAVE_VFSCANF || HAVE__DOSCAN 16776726Speter /* 16876726Speter * This code should work on anything descended from AT&T SVr1. 16976726Speter */ 17076726Speter FILE strbuf; 17150276Speter 17276726Speter strbuf._flag = _IOREAD; 17376726Speter strbuf._ptr = strbuf._base = (unsigned char *) str; 17476726Speter strbuf._cnt = strlen(str); 17576726Speter strbuf._file = _NFILE; 17650276Speter 17750276Speter#if HAVE_VFSCANF 17876726Speter return (vfscanf(&strbuf, format, ap)); 17950276Speter#else 18076726Speter return (_doscan(&strbuf, format, ap)); 18150276Speter#endif 18250276Speter#else 18397049Speter static int can_convert = -1; 18497049Speter 18597049Speter int assigned = 0; 18697049Speter int consumed = 0; 18797049Speter 18897049Speter T((T_CALLED("vsscanf(%s,%s,...)"), 18997049Speter _nc_visbuf2(1, str), 19097049Speter _nc_visbuf2(2, format))); 19197049Speter 19276726Speter /* 19397049Speter * This relies on having a working "%n" format conversion. Check if it 19497049Speter * works. Only very old C libraries do not support it. 19597049Speter * 19697049Speter * FIXME: move this check into the configure script. 19776726Speter */ 19897049Speter if (can_convert < 0) { 19997049Speter int check1; 20097049Speter int check2; 20197049Speter if (sscanf("123", "%d%n", &check1, &check2) > 0 20297049Speter && check1 == 123 20397049Speter && check2 == 3) { 20497049Speter can_convert = 1; 20597049Speter } else { 20697049Speter can_convert = 0; 20797049Speter } 20897049Speter } 20997049Speter 21097049Speter if (can_convert) { 21197049Speter size_t len_fmt = strlen(format) + 32; 21297049Speter char *my_fmt = malloc(len_fmt); 213166124Srafan ChunkType chunk, ctest; 214166124Srafan OtherType other, otest; 21597049Speter ScanState state; 21697049Speter unsigned n; 21797049Speter int eaten; 21897049Speter void *pointer; 21997049Speter 22097049Speter if (my_fmt != 0) { 22197049Speter /* 22297049Speter * Split the original format into chunks, adding a "%n" to the end 22397049Speter * of each (except of course if it used %n), and use that 22497049Speter * information to decide where to start scanning the next chunk. 22597049Speter * 22697049Speter * FIXME: does %n count bytes or characters? If the latter, this 22797049Speter * will require further work for multibyte strings. 22897049Speter */ 22997049Speter while (*format != '\0') { 23097049Speter /* find a chunk */ 23197049Speter state = sUnknown; 23297049Speter chunk = cUnknown; 233166124Srafan other = oUnknown; 23497049Speter pointer = 0; 23597049Speter for (n = 0; format[n] != 0 && state != sFinal; ++n) { 23697049Speter my_fmt[n] = format[n]; 23797049Speter switch (state) { 23897049Speter case sUnknown: 23997049Speter if (format[n] == '%') 24097049Speter state = sPercent; 24197049Speter break; 24297049Speter case sPercent: 24397049Speter if (format[n] == '%') { 24497049Speter state = sUnknown; 24597049Speter } else if (format[n] == L_SQUARE) { 24697049Speter state = sLeft; 24797049Speter } else { 24897049Speter state = sNormal; 24997049Speter --n; 25097049Speter } 25197049Speter break; 25297049Speter case sLeft: 25397049Speter state = sRange; 25497049Speter if (format[n] == '^') { 25597049Speter ++n; 25697049Speter my_fmt[n] = format[n]; 25797049Speter } 25897049Speter break; 25997049Speter case sRange: 26097049Speter if (format[n] == R_SQUARE) { 26197049Speter state = sFinal; 26297049Speter chunk = cRange; 26397049Speter } 26497049Speter break; 26597049Speter case sNormal: 26697049Speter if (format[n] == '*') { 26797049Speter state = sUnknown; 26897049Speter } else { 269166124Srafan if ((ctest = final_ch(format[n], other)) != cUnknown) { 27097049Speter state = sFinal; 271166124Srafan chunk = ctest; 272166124Srafan } else if ((otest = other_ch(format[n])) != oUnknown) { 273166124Srafan other = otest; 274166124Srafan } else if (isalpha(UChar(format[n]))) { 27597049Speter state = sFinal; 27697049Speter chunk = cError; 27797049Speter } 27897049Speter } 27997049Speter break; 28097049Speter case sFinal: 28197049Speter break; 28297049Speter } 28397049Speter } 28497049Speter my_fmt[n] = '\0'; 28597049Speter format += n; 28697049Speter 28797049Speter if (chunk == cUnknown 28897049Speter || chunk == cError) { 28997049Speter if (assigned == 0) 29097049Speter assigned = EOF; 29197049Speter break; 29297049Speter } 29397049Speter 29497049Speter /* add %n, if the format was not that */ 29597049Speter if (chunk != cAssigned) { 296262685Sdelphij _nc_STRCAT(my_fmt, "%n", len_fmt); 29797049Speter } 29897049Speter 29997049Speter switch (chunk) { 30097049Speter case cAssigned: 301262685Sdelphij _nc_STRCAT(my_fmt, "%n", len_fmt); 30297049Speter pointer = &eaten; 30397049Speter break; 30497049Speter case cInt: 30597049Speter pointer = va_arg(ap, int *); 30697049Speter break; 30797049Speter case cShort: 30897049Speter pointer = va_arg(ap, short *); 30997049Speter break; 31097049Speter case cFloat: 31197049Speter pointer = va_arg(ap, float *); 31297049Speter break; 31397049Speter case cDouble: 31497049Speter pointer = va_arg(ap, double *); 31597049Speter break; 31697049Speter case cLong: 31797049Speter pointer = va_arg(ap, long *); 31897049Speter break; 31997049Speter case cPointer: 32097049Speter pointer = va_arg(ap, void *); 32197049Speter break; 32297049Speter case cChar: 32397049Speter case cRange: 32497049Speter case cString: 32597049Speter pointer = va_arg(ap, char *); 32697049Speter break; 32797049Speter case cError: 32897049Speter case cUnknown: 32997049Speter break; 33097049Speter } 33197049Speter /* do the conversion */ 33297049Speter T(("...converting chunk #%d type %d(%s,%s)", 33397049Speter assigned + 1, chunk, 33497049Speter _nc_visbuf2(1, str + consumed), 33597049Speter _nc_visbuf2(2, my_fmt))); 33697049Speter if (sscanf(str + consumed, my_fmt, pointer, &eaten) > 0) 33797049Speter consumed += eaten; 33897049Speter else 33997049Speter break; 34097049Speter ++assigned; 34197049Speter } 34297049Speter free(my_fmt); 34397049Speter } 34497049Speter } 34597049Speter returnCode(assigned); 34697049Speter#endif 34750276Speter} 34850276Speter#else 34976726Speterextern 35076726SpeterNCURSES_EXPORT(void) 35176726Speter_nc_vsscanf(void); /* quiet's gcc warning */ 35276726SpeterNCURSES_EXPORT(void) 35376726Speter_nc_vsscanf(void) 35476726Speter{ 35576726Speter} /* nonempty for strict ANSI compilers */ 35650276Speter#endif /* !HAVE_VSSCANF */ 357