1
/* Implementation of o_vscanf for GNUstep Base Library
3
Reworked by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
6
This file is part of the GNUstep Base Library.
8
This library is free software; you can redistribute it and/or
9
modify it under the terms of the GNU Library General Public
10
License as published by the Free Software Foundation; either
11
version 2 of the License, or (at your option) any later version.
13
This library is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
Library General Public License for more details.
18
You should have received a copy of the GNU Library General Public
19
License along with this library; if not, write to the Free
20
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
23
/* Copyright (C) 1991, 1992, 1993, 1996 Free Software Foundation, Inc.
24
This file is part of the GNU C Library.
26
The GNU C Library is free software; you can redistribute it and/or
27
modify it under the terms of the GNU Library General Public License as
28
published by the Free Software Foundation; either version 2 of the
29
License, or (at your option) any later version.
31
The GNU C Library is distributed in the hope that it will be useful,
32
but WITHOUT ANY WARRANTY; without even the implied warranty of
33
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
34
Library General Public License for more details.
36
You should have received a copy of the GNU Library General Public
37
License along with the GNU C Library; see the file COPYING.LIB. If
38
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
39
Cambridge, MA 02111, USA. */
43
/* Reworked from glibc by Andrew McCallum:
44
Fixed bug by adding "*f == 'a'" to type modifier checking.
45
Declared extern strtod and strtol.
46
Use function pointer argument to get next character.
47
Use objc_malloc() instead of malloc()
48
Use objc_realloc() instead of realloc()
50
This is a solution for StdioStream and MemoryStream.
51
It isn't ideal. Anyone have other suggestions? */
53
/* #include <ansidecl.h> */
54
/* #include <localeinfo.h> */
62
#include <objc/objc-api.h>
64
extern double strtod(const char *str, char **ptr);
65
extern long strtol(const char *str, char** ptr, int base);
69
#define LONGLONG long long
71
#define LONG_DOUBLE long double
78
/* #define inchar() ((c = getc(s)) == EOF ? EOF : (++read_in, c))*/
79
#define inchar() ((c = (*inchar_func)(stream)) == EOF ? EOF : (++read_in, c))
81
/* #define conv_error() return ((c == EOF || ungetc(c, s)), done) */
82
//#define conv_error() return ((c == EOF || ((*unchar_func)(stream,c),c)), done)
83
#define conv_error() return (c==EOF ? done : ((*unchar_func)(stream,c), done))
85
#define input_error() return (done == 0 ? EOF : done)
86
#define memory_error() return ((errno = ENOMEM), EOF)
89
/* Read formatted input from STREAM according to the format string
90
FORMAT, using the argument list in ARGPTR.
91
Return the number of assignments made, or -1 for an input error. */
93
o_vscanf (void *stream,
94
int (*inchar_func)(void*),
95
void (*unchar_func)(void*,int),
96
const char *format, va_list arg)
98
register CONST char *f = format;
99
register char fc; /* Current character of the format. */
100
register size_t done = 0; /* Assignments done. */
101
register size_t read_in = 0; /* Chars read in. */
102
register int c; /* Last char read. */
103
register int do_assign; /* Whether to do an assignment. */
104
register int width; /* Maximum field width. */
106
/* Type modifiers. */
107
char is_short, is_long, is_long_double;
109
/* We use the `L' modifier for `long long int'. */
110
#define is_longlong is_long_double
112
#define is_longlong 0
114
int malloc_string; /* Args are char ** to be filled in. */
115
/* Status for reading F-P nums. */
117
/* If a [...] is a [^...]. */
119
/* Base for integral numbers. */
121
/* Signedness for integral numbers. */
123
/* Integral holding variables. */
125
unsigned long int unum;
126
/* Floating-point holding variable. */
128
/* Character-buffer pointer. */
129
register char *str, **strptr;
133
char *w; /* Pointer into WORK. */
134
wchar_t decimal; /* Decimal point character. */
137
if (!__validfp(s) || !s->__mode.__read || format == NULL)
144
/* Figure out the decimal point character. */
146
if (mbtowc(&decimal, _numeric_info->decimal_point,
147
strlen(_numeric_info->decimal_point)) <= 0)
148
decimal = (wchar_t) *_numeric_info->decimal_point;
155
/* Run through the format string. */
160
/* Non-ASCII, may be a multibyte. */
161
int len = mblen(f, strlen(f));
178
/* Characters other than format specs must just match. */
183
/* Whitespace characters match any amount of whitespace. */
195
/* Check for the assignment-suppressant. */
204
/* Find the maximum field width. */
214
/* Check for type modifiers. */
215
is_short = is_long = is_long_double = malloc_string = 0;
216
while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'a')
220
/* int's are short int's. */
225
/* A double `l' is equivalent to an `L'. */
228
/* int's are long int's. */
232
/* double's are long double's, and int's are long long int's. */
236
/* String conversions (%s, %[) take a `char **'
237
arg and fill it in with a malloc'd pointer. */
242
/* End of the format string? */
246
/* Find the conversion specifier. */
249
if (fc != '[' && fc != 'c' && fc != 'n')
250
/* Eat whitespace. */
255
case '%': /* Must match a literal '%'. */
260
case 'n': /* Answer number of assignments done. */
262
*va_arg(arg, int *) = read_in;
265
case 'c': /* Match characters. */
268
str = va_arg (arg, char *);
283
while (inchar() != EOF && --width > 0);
286
while (inchar() != EOF && width > 0)
294
case 's': /* Read a string. */
300
/* The string is to be stored in a malloc'd buffer. */ \
301
strptr = va_arg (arg, char **); \
302
if (strptr == NULL) \
304
/* Allocate an initial buffer. */ \
306
*strptr = str = objc_malloc (strsize); \
309
str = va_arg (arg, char *); \
322
#define STRING_ADD_CHAR(c) \
326
if (malloc_string && str == *strptr + strsize) \
328
/* Enlarge the buffer. */ \
329
str = objc_realloc (*strptr, strsize * 2); \
332
/* Can't allocate that much. Last-ditch effort. */\
333
str = objc_realloc (*strptr, strsize + 1); \
336
/* We lose. Oh well. \
337
Terminate the string and stop converting, \
338
so at least we don't swallow any input. */ \
339
(*strptr)[strsize] = '\0'; \
359
} while (inchar () != EOF && (width <= 0 || --width > 0));
368
case 'x': /* Hexadecimal integer. */
369
case 'X': /* Ditto. */
374
case 'o': /* Octal integer. */
379
case 'u': /* Unsigned decimal integer. */
384
case 'd': /* Signed decimal integer. */
389
case 'i': /* Generic number. */
397
/* Check for a sign. */
398
if (c == '-' || c == '+')
406
/* Look for a leading indication of base. */
415
if (tolower(c) == 'x')
433
/* Read the number into WORK. */
436
if (base == 16 ? !isxdigit(c) :
437
(!isdigit(c) || c - '0' >= base))
442
} while (inchar() != EOF && width != 0);
445
(w - work == 1 && (work[0] == '+' || work[0] == '-')))
446
/* There was on number. */
449
/* Convert the number. */
452
num = strtol (work, &w, base);
455
unum = strtoul (work, &w, base);
457
unum = (unsigned long) strtol (work, &w, base);
467
*va_arg (arg, unsigned LONGLONG int *) = unum;
469
*va_arg (arg, unsigned long int *) = unum;
471
*va_arg (arg, unsigned short int *)
472
= (unsigned short int) unum;
474
*va_arg(arg, unsigned int *) = (unsigned int) unum;
479
*va_arg(arg, LONGLONG int *) = num;
481
*va_arg(arg, long int *) = num;
483
*va_arg(arg, short int *) = (short int) num;
485
*va_arg(arg, int *) = (int) num;
491
case 'e': /* Floating-point numbers. */
499
/* Check for a sign. */
500
if (c == '-' || c == '+')
504
/* EOF is only an input error before we read any chars. */
515
else if (got_e && w[-1] == 'e' && (c == '-' || c == '+'))
517
else if (!got_e && tolower(c) == 'e')
522
else if (c == decimal && !got_dot)
531
} while (inchar() != EOF && width != 0);
535
if (w[-1] == '-' || w[-1] == '+' || w[-1] == 'e')
539
/* Convert the number. */
541
fp_num = strtod(work, &w);
548
*va_arg(arg, LONG_DOUBLE *) = fp_num;
550
*va_arg(arg, double *) = (double) fp_num;
552
*va_arg(arg, float *) = (float) fp_num;
556
#endif /* MIB_HACKS */
558
case '[': /* Character class. */
572
while ((fc = *f++) != '\0' && fc != ']')
574
if (fc == '-' && *f != '\0' && *f != ']' &&
575
w > work && w[-1] <= *f)
576
/* Add all characters from the one before the '-'
577
up to (but not including) the next format char. */
578
for (fc = w[-1] + 1; fc < *f; ++fc)
581
/* Add the character to the list. */
591
if ((strchr (work, c) == NULL) != not_in)
596
} while (inchar () != EOF && width != 0);
607
case 'p': /* Generic pointer. */
609
/* A PTR must be the same size as a `long int'. */