From 98a18b797c63ea9baab31768ed720ad32c0004e8 Mon Sep 17 00:00:00 2001 From: Guillaume Cottenceau Date: Mon, 14 May 2001 21:47:42 +0000 Subject: i can compile slang and newt with dietlibc now --- mdk-stage1/slang/slscanf.c | 718 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 718 insertions(+) create mode 100644 mdk-stage1/slang/slscanf.c (limited to 'mdk-stage1/slang/slscanf.c') diff --git a/mdk-stage1/slang/slscanf.c b/mdk-stage1/slang/slscanf.c new file mode 100644 index 000000000..5bd93ff41 --- /dev/null +++ b/mdk-stage1/slang/slscanf.c @@ -0,0 +1,718 @@ +/* sscanf function for S-Lang */ +/* Copyright (c) 1999, 2001 John E. Davis + * This file is part of the S-Lang library. + * + * You may distribute under the terms of either the GNU General Public + * License or the Perl Artistic License. + */ + +#include "slinclud.h" +#include +#include +#include + +#include "slang.h" +#include "_slang.h" + +static char *skip_whitespace (char *s) +{ + while (isspace (*s)) + s++; + + return s; +} + +static void init_map (unsigned char map[256], int base) +{ + memset ((char *) map, 0xFF, 256); + + map['0'] = 0; map['1'] = 1; map['2'] = 2; map['3'] = 3; + map['4'] = 4; map['5'] = 5; map['6'] = 6; map['7'] = 7; + if (base == 8) + return; + + map['8'] = 8; map['9'] = 9; + if (base == 10) + return; + + map['A'] = 10; map['B'] = 11; map['C'] = 12; map['D'] = 13; + map['E'] = 14; map['F'] = 15; map['a'] = 10; map['b'] = 11; + map['c'] = 12; map['d'] = 13; map['e'] = 14; map['f'] = 15; +} + +static char *get_sign (char *s, char *smax, int *sign) +{ + *sign = 1; + if (s + 1 < smax) + { + if (*s == '+') s++; + else if (*s == '-') + { + s++; + *sign = -1; + } + } + return s; +} + + +static int parse_long (char **sp, char *smax, long *np, + long base, unsigned char map[256]) +{ + char *s, *s0; + long n; + int sign; + + s = s0 = get_sign (*sp, smax, &sign); + + n = 0; + while (s < smax) + { + unsigned char value; + + value = map [(unsigned char) *s]; + if (value == 0xFF) + break; + + n = base * n + value; + s++; + } + + *sp = s; + if (s == s0) + return 0; + + *np = n * sign; + + return 1; +} + + +static int parse_int (char **sp, char *smax, int *np, + long base, unsigned char map[256]) +{ + long n; + int status; + + if (1 == (status = parse_long (sp, smax, &n, base, map))) + *np = (int) n; + return status; +} + +static int parse_short (char **sp, char *smax, short *np, + long base, unsigned char map[256]) +{ + long n; + int status; + + if (1 == (status = parse_long (sp, smax, &n, base, map))) + *np = (short) n; + return status; +} + +static int parse_ulong (char **sp, char *smax, unsigned long *np, + long base, unsigned char map[256]) +{ + return parse_long (sp, smax, (long *) np, base, map); +} + +static int parse_uint (char **sp, char *smax, unsigned int *np, + long base, unsigned char map[256]) +{ + return parse_int (sp, smax, (int *) np, base, map); +} + +static int parse_ushort (char **sp, char *smax, unsigned short *np, + long base, unsigned char map[256]) +{ + return parse_short (sp, smax, (short *) np, base, map); +} + +#if SLANG_HAS_FLOAT +/* + * In an ideal world, strtod would be the correct function to use. However, + * there may be problems relying on this function because some systems do + * not support and some that do get it wrong. So, I will handle the parsing + * of the string and let atof or strtod handle the arithmetic. + */ +static int parse_double (char **sp, char *smax, double *d) +{ + char *s, *s0; + int sign; + int expon; + unsigned char map[256]; + char buf[128]; + int has_leading_zeros; + char *start_pos, *sign_pos; + char *b, *bmax; + + start_pos = *sp; + s = get_sign (start_pos, smax, &sign); + if (s >= smax) + { + errno = _SLerrno_errno = EINVAL; + return 0; + } + + /* Prepare the buffer that will be passed to strtod */ + /* Allow the exponent to be 5 significant digits: E+xxxxx\0 */ + bmax = buf + (sizeof (buf) - 8); + buf[0] = '0'; buf[1] = '.'; + b = buf + 2; + + init_map (map, 10); + + /* Skip leading 0s */ + s0 = s; + while ((s < smax) && (*s == '0')) + s++; + has_leading_zeros = (s != s0); + + expon = 0; + while (s < smax) + { + unsigned char value = map [(unsigned char) *s]; + + if (value == 0xFF) + break; + + if (b < bmax) + *b++ = *s; + + expon++; + s++; + } + + if ((s < smax) && (*s == '.')) + { + s++; + if (b == buf + 2) /* nothing added yet */ + { + while ((s < smax) && (*s == '0')) + { + expon--; + s++; + } + } + + while (s < smax) + { + unsigned char value = map [(unsigned char) *s]; + + if (value == 0xFF) + break; + + if (b < bmax) + *b++ = *s; + s++; + } + } + + if ((b == buf + 2) + && (has_leading_zeros == 0)) + { + *sp = start_pos; + errno = EINVAL; + return 0; + } + + if ((s + 1 < smax) && ((*s == 'E') || (*s == 'e'))) + { + int e; + int esign; + + s0 = s; + s = get_sign (s + 1, smax, &esign); + sign_pos = s; + e = 0; + while (s < smax) + { + unsigned char value = map [(unsigned char) *s]; + if (value == 0xFF) + break; + if (e < 25000) /* avoid overflow if 16 bit */ + e = 10 * e + value; + s++; + } +#ifdef ERANGE + if (e >= 25000) + errno = ERANGE; +#endif + if (s == sign_pos) + s = s0; /* ...E-X */ + else + { + e = esign * e; + expon += e; + } + } + + if (expon != 0) + sprintf (b, "e%d", expon); + else + *b = 0; + + *sp = s; +#if HAVE_STRTOD + *d = sign * strtod (buf, NULL); +#else + *d = sign * atof (buf); +#endif + return 1; +} + +static int parse_float (char **sp, char *smax, float *d) +{ + double x; + if (1 == parse_double (sp, smax, &x)) + { + *d = (float) x; + return 1; + } + return 0; +} +#endif /* SLANG_HAS_FLOAT */ + +static int parse_string (char **sp, char *smax, char **str) +{ + char *s, *s0; + + s0 = s = *sp; + while (s < smax) + { + if (isspace (*s)) + break; + s++; + } + if (NULL == (*str = SLang_create_nslstring (s0, (unsigned int) (s - s0)))) + return -1; + + *sp = s; + return 1; +} + +static int parse_bstring (char **sp, char *smax, char **str) +{ + char *s; + + s = *sp; + if (NULL == (*str = SLang_create_nslstring (s, (unsigned int) (smax - s)))) + return -1; + + *sp = smax; + return 1; +} + +static int parse_range (char **sp, char *smax, char **fp, char **str) +{ + char *s, *s0; + char *range; + char *f; + unsigned char map[256]; + unsigned char reverse; + + /* How can one represent a range with just '^'? The naive answer is + * is [^]. However, this may be interpreted as meaning any character + * but ']' and others. Let's assume that the user will not use a range + * to match '^'. + */ + f = *fp; + /* f is a pointer to (one char after) [...]. */ + if (*f == '^') + { + f++; + reverse = 1; + } + else reverse = 0; + + s0 = f; + if (*f == ']') + f++; + + while (1) + { + char ch = *f; + + if (ch == 0) + { + SLang_verror (SL_INVALID_PARM, "Unexpected end of range in format"); + return -1; + } + if (ch == ']') + break; + f++; + } + if (NULL == (range = SLmake_nstring (s0, (unsigned int) (f - s0)))) + return -1; + *fp = f + 1; /* skip ] */ + + SLmake_lut (map, (unsigned char *) range, reverse); + SLfree (range); + + s0 = s = *sp; + while ((s < smax) && map [(unsigned char) *s]) + s++; + + if (NULL == (*str = SLang_create_nslstring (s0, (unsigned int) (s - s0)))) + return -1; + + *sp = s; + return 1; +} + + +int _SLang_sscanf (void) +{ + int num; + unsigned int num_refs; + char *format; + char *input_string, *input_string_max; + char *f, *s; + unsigned char map8[256], map10[256], map16[256]; + + if (SLang_Num_Function_Args < 2) + { + SLang_verror (SL_INVALID_PARM, "Int_Type sscanf (str, format, ...)"); + return -1; + } + + num_refs = (unsigned int) SLang_Num_Function_Args; + if (-1 == SLreverse_stack (num_refs)) + return -1; + num_refs -= 2; + + if (-1 == SLang_pop_slstring (&input_string)) + return -1; + + if (-1 == SLang_pop_slstring (&format)) + { + SLang_free_slstring (input_string); + return -1; + } + + f = format; + s = input_string; + input_string_max = input_string + strlen (input_string); + + init_map (map8, 8); + init_map (map10, 10); + init_map (map16, 16); + + num = 0; + + while (num_refs != 0) + { + SLang_Object_Type obj; + SLang_Ref_Type *ref; + char *smax; + unsigned char *map; + int base; + int no_assign; + int is_short; + int is_long; + int status; + char chf; + unsigned int width; + int has_width; + + chf = *f++; + + if (chf == 0) + { + /* Hmmm.... what is the most useful thing to do?? */ +#if 1 + break; +#else + SLang_verror (SL_INVALID_PARM, "sscanf: format not big enough for output list"); + goto return_error; +#endif + } + + if (isspace (chf)) + { + s = skip_whitespace (s); + continue; + } + + if ((chf != '%') + || ((chf = *f++) == '%')) + { + if (*s != chf) + break; + s++; + continue; + } + + no_assign = 0; + is_short = 0; + is_long = 0; + width = 0; + smax = input_string_max; + + /* Look for the flag character */ + if (chf == '*') + { + no_assign = 1; + chf = *f++; + } + + /* Width */ + has_width = isdigit (chf); + if (has_width) + { + f--; + (void) parse_uint (&f, f + strlen(f), &width, 10, map10); + chf = *f++; + } + + /* Now the type modifier */ + switch (chf) + { + case 'h': + is_short = 1; + chf = *f++; + break; + + case 'L': /* not implemented */ + case 'l': + is_long = 1; + chf = *f++; + break; + } + + status = -1; + + if ((chf != 'c') && (chf != '[')) + s = skip_whitespace (s); + + if (has_width) + { + if (width > (unsigned int) (input_string_max - s)) + width = (unsigned int) (input_string_max - s); + smax = s + width; + } + + /* Now the format descriptor */ + + map = map10; + base = 10; + + try_again: /* used by i, x, and o, conversions */ + switch (chf) + { + case 0: + SLang_verror (SL_INVALID_PARM, "sscanf: Unexpected end of format"); + goto return_error; + case 'D': + is_long = 1; + case 'd': + if (is_short) + { + obj.data_type = SLANG_SHORT_TYPE; + status = parse_short (&s, smax, &obj.v.short_val, base, map); + } + else if (is_long) + { + obj.data_type = SLANG_LONG_TYPE; + status = parse_long (&s, smax, &obj.v.long_val, base, map); + } + else + { + obj.data_type = SLANG_INT_TYPE; + status = parse_int (&s, smax, &obj.v.int_val, base, map); + } + break; + + + case 'U': + is_long = 1; + case 'u': + if (is_short) + { + obj.data_type = SLANG_USHORT_TYPE; + status = parse_ushort (&s, smax, &obj.v.ushort_val, base, map); + } + else if (is_long) + { + obj.data_type = SLANG_ULONG_TYPE; + status = parse_ulong (&s, smax, &obj.v.ulong_val, base, map); + } + else + { + obj.data_type = SLANG_INT_TYPE; + status = parse_uint (&s, smax, &obj.v.uint_val, base, map); + } + break; + + case 'I': + is_long = 1; + case 'i': + if ((s + 1 >= smax) + || (*s != 0)) + chf = 'd'; + else if (((s[1] == 'x') || (s[1] == 'X')) + && (s + 2 < smax)) + { + s += 2; + chf = 'x'; + } + else chf = 'o'; + goto try_again; + + case 'O': + is_long = 1; + case 'o': + map = map8; + base = 8; + chf = 'd'; + goto try_again; + + case 'X': + is_long = 1; + case 'x': + base = 16; + map = map16; + chf = 'd'; + goto try_again; + + case 'E': + case 'F': + is_long = 1; + case 'e': + case 'f': + case 'g': +#if SLANG_HAS_FLOAT + if (is_long) + { + obj.data_type = SLANG_DOUBLE_TYPE; + status = parse_double (&s, smax, &obj.v.double_val); + } + else + { + obj.data_type = SLANG_FLOAT_TYPE; + status = parse_float (&s, smax, &obj.v.float_val); + } +#else + SLang_verror (SL_NOT_IMPLEMENTED, + "This version of the S-Lang does not support floating point"); + status = -1; +#endif + break; + + case 's': + obj.data_type = SLANG_STRING_TYPE; + status = parse_string (&s, smax, &obj.v.s_val); + break; + + case 'c': + if (has_width == 0) + { + obj.data_type = SLANG_UCHAR_TYPE; + obj.v.uchar_val = *s++; + status = 1; + break; + } + obj.data_type = SLANG_STRING_TYPE; + status = parse_bstring (&s, smax, &obj.v.s_val); + break; + + case '[': + obj.data_type = SLANG_STRING_TYPE; + status = parse_range (&s, smax, &f, &obj.v.s_val); + break; + + case 'n': + obj.data_type = SLANG_UINT_TYPE; + obj.v.uint_val = (unsigned int) (s - input_string); + status = 1; + break; + + default: + status = -1; + SLang_verror (SL_NOT_IMPLEMENTED, "format specifier '%c' is not supported", chf); + break; + } + + if (status == 0) + break; + + if (status == -1) + goto return_error; + + if (no_assign) + { + SLang_free_object (&obj); + continue; + } + + if (-1 == SLang_pop_ref (&ref)) + { + SLang_free_object (&obj); + goto return_error; + } + + if (-1 == SLang_push (&obj)) + { + SLang_free_object (&obj); + SLang_free_ref (ref); + goto return_error; + } + + if (-1 == _SLang_deref_assign (ref)) + { + SLang_free_ref (ref); + goto return_error; + } + SLang_free_ref (ref); + + num++; + num_refs--; + } + + if (-1 == SLdo_pop_n (num_refs)) + goto return_error; + + SLang_free_slstring (format); + SLang_free_slstring (input_string); + return num; + + return_error: + /* NULLS ok */ + SLang_free_slstring (format); + SLang_free_slstring (input_string); + return -1; +} + + +# if SLANG_HAS_FLOAT + +#ifndef HAVE_STDLIB_H +/* Oh dear. Where is the prototype for atof? If not in stdlib, then + * I do not know where. Not in math.h on some systems either. + */ +extern double atof (); +#endif + +double _SLang_atof (char *s) +{ + double x; + + s = skip_whitespace (s); + errno = 0; + + if (1 != parse_double (&s, s + strlen (s), &x)) + { + if ((0 == strcmp ("NaN", s)) + || (0 == strcmp ("-Inf", s)) + || (0 == strcmp ("Inf", s))) + return atof (s); /* let this deal with it */ +#ifdef EINVAL + errno = _SLerrno_errno = EINVAL; +#endif + return 0.0; + } + if (errno) + _SLerrno_errno = errno; + return x; +} +#endif -- cgit v1.2.1