diff options
Diffstat (limited to 'mdk-stage1/slang/slscanf.c')
-rw-r--r-- | mdk-stage1/slang/slscanf.c | 718 |
1 files changed, 0 insertions, 718 deletions
diff --git a/mdk-stage1/slang/slscanf.c b/mdk-stage1/slang/slscanf.c deleted file mode 100644 index 5bd93ff41..000000000 --- a/mdk-stage1/slang/slscanf.c +++ /dev/null @@ -1,718 +0,0 @@ -/* 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 <ctype.h> -#include <math.h> -#include <errno.h> - -#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 |