GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcurses/base/vsscanf.c Lines: 0 1 0.0 %
Date: 2016-12-06 Branches: 0 0 0.0 %

Line Branch Exec Source
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 */