home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
OS2
/
EMXFIX04.ZIP
/
INPUT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-22
|
13KB
|
607 lines
/* input.c (emx+gcc) -- Copyright (c) 1990-1994 by Eberhard Mattes */
#include <sys/emx.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <setjmp.h>
#include <limits.h>
#define JEOF 1 /* longjmp: EOF reached */
#define JDONE 2 /* longjmp: input doesn't match */
/* This structure holds the local variables of _input() which are
passed to the functions called by _input(). */
typedef struct
{
FILE *stream; /* Where input comes from */
int width; /* Field width or what's left over of it */
int chars; /* Number of characters read */
int volatile count; /* Number of fields assigned */
char * volatile more; /* Big buffer for %e format */
int collected; /* Number of characters collected */
size_t more_size; /* Size of the above */
char size; /* Size (0, 'h', 'l' or 'L') */
char at_eof; /* End of file or string reached */
jmp_buf jump; /* Jump there when done or on error */
} ilocal;
static unsigned char next (ilocal *v)
{
int c;
c = getc (v->stream);
if (c == EOF)
longjmp (v->jump, JEOF);
++v->chars;
return ((unsigned char)c);
}
static int get (ilocal *v, unsigned char *pc)
{
int c;
c = getc (v->stream);
if (c == EOF)
{
v->at_eof = 1;
return (0);
}
*pc = (unsigned char)c;
++v->chars;
return (1);
}
static void push_back (ilocal *v, unsigned char c)
{
ungetc (c, v->stream);
--v->chars;
}
#define COLLECT(X) collect (v, buf, sizeof (buf), X)
static void collect (ilocal *v, unsigned char *buf, size_t buf_size,
unsigned char c)
{
if (v->more == NULL && v->collected < buf_size)
buf[v->collected] = c;
else
{
if (v->collected >= v->more_size)
{
v->more_size += 512;
v->more = realloc (v->more, v->more_size);
if (v->more == NULL)
longjmp (v->jump, JDONE);
if (v->collected == buf_size)
memcpy (v->more, buf, buf_size);
}
v->more[v->collected] = c;
}
++v->collected;
}
static unsigned char skip (ilocal *v)
{
unsigned char c;
do
{
c = next (v);
} while (isspace (c));
return (c);
}
static void inp_char (ilocal *v, unsigned char *dst)
{
unsigned char c;
int width;
width = ((v->width == INT_MAX) ? 1 : v->width);
while (width > 0)
{
--width;
c = next (v);
if (dst != NULL)
{
*dst++ = c;
++v->count;
}
}
}
static void inp_string (ilocal *v, unsigned char c, char *map, char end,
unsigned char *dst)
{
while (v->width > 0 && map[c] != end)
{
--v->width;
if (dst != NULL)
*dst++ = c;
if (!get (v, &c))
break;
}
if (dst != NULL)
{
*dst = 0;
++v->count;
}
if (v->at_eof)
longjmp (v->jump, JEOF);
push_back (v, c);
}
static void inp_str (ilocal *v, unsigned char *dst)
{
char map[256];
unsigned char c;
memset (map, 0, 256);
map[' '] = 1;
map['\n'] = 1;
map['\t'] = 1;
c = skip (v);
inp_string (v, c, map, 1, dst);
}
static void inp_set (ilocal *v, const char **pfmt, void *dst)
{
char map[256], end, done;
unsigned char f;
const char *format;
int i;
format = *pfmt;
memset (map, 0, 256);
end = 0;
++format;
if (*format == '^')
{
++format; end = 1;
}
i = 0; done = 0;
do
{
f = (unsigned char)*format;
switch (f)
{
case 0:
*pfmt = format - 1; /* Avoid skipping past 0 */
done = 1;
break;
case ']':
if (i > 0)
{
*pfmt = format;
done = 1;
break;
}
/* no break */
default:
if (format[1] == '-' && format[2] != 0 &&
f < (unsigned char)format[2])
{
memset (map+f, 1, (unsigned char)format[2]-f);
format += 2;
}
else
map[f] = 1;
break;
}
++format; ++i;
} while (!done);
inp_string (v, next (v), map, end, dst);
}
static void inp_int_base (ilocal *v, void *dst, unsigned char c, int base)
{
char neg, ok;
unsigned long long n;
int digit;
neg = FALSE;
if (v->width > 0)
{
if (c == '+')
{
c = next (v); --v->width;
}
else if (c == '-')
{
neg = TRUE;
c = next (v); --v->width;
}
}
n = 0; ok = FALSE;
if (base == 0)
{
base = 10;
if (v->width > 0 && c == '0')
{
c = next (v); --v->width;
if (v->width > 0 && (c == 'x' || c == 'X'))
{
base = 16;
c = next (v); --v->width;
}
else
{
base = 8;
ok = TRUE; /* We've seen a digit! */
}
}
}
while (v->width > 0)
{
--v->width;
if (isdigit (c))
digit = c - '0';
else if (isupper (c))
digit = c - 'A' + 10;
else if (islower (c))
digit = c - 'a' + 10;
else
break;
if (digit < 0 || digit >= base)
break;
ok = TRUE;
n = n * base + digit;
if (!get (v, &c))
break;
}
if (!ok)
longjmp (v->jump, JDONE);
if (neg)
n = -n;
if (dst != NULL)
{
switch (v->size)
{
case 'L':
*(long long *)dst = n;
break;
case 'h':
*(short *)dst = n;
break;
default:
*(int *)dst = n;
break;
}
++v->count;
}
if (v->at_eof)
longjmp (v->jump, JDONE);
push_back (v, c);
}
static void inp_int (ilocal *v, unsigned char f, void *dst)
{
unsigned char c;
c = skip (v);
switch (f)
{
case 'i':
inp_int_base (v, dst, c, 0);
break;
case 'd':
inp_int_base (v, dst, c, 10);
break;
case 'u':
inp_int_base (v, dst, c, 10);
break;
case 'o':
inp_int_base (v, dst, c, 8);
break;
case 'x':
case 'X':
case 'p':
inp_int_base (v, dst, c, 16);
break;
default:
abort ();
}
}
static void inp_float (ilocal *v, void *dst)
{
unsigned char c;
char *q;
int width;
char ok;
char buf[128];
long double x;
v->collected = 0;
width = v->width;
c = skip (v);
ok = FALSE;
if (c == '+' || c == '-')
{
COLLECT (c);
c = next (v); --width;
}
while (width > 0 && isdigit (c))
{
--width;
COLLECT (c);
ok = TRUE;
if (!get (v, &c))
break;
}
if (width > 0 && !v->at_eof && c == '.')
{
--width;
COLLECT (c);
while (get (v, &c) && width > 0 && isdigit (c))
{
--width;
COLLECT (c);
ok = TRUE;
}
}
if (!ok)
longjmp (v->jump, JDONE);
if (width > 0 && !v->at_eof && (c == 'e' || c == 'E'))
{
COLLECT (c);
c = next (v); --width;
if (width > 0 && (c == '+' || c == '-'))
{
COLLECT (c);
c = next (v); --width;
}
if (!(width > 0 && isdigit (c)))
{
push_back (v, c);
longjmp (v->jump, JDONE);
}
while (width > 0 && isdigit (c))
{
--width;
COLLECT (c);
if (!get (v, &c))
break;
}
}
if (!v->at_eof)
push_back (v, c);
COLLECT (0);
x = _strtold (((v->more != NULL) ? v->more : buf), &q);
if (q == buf || *q != 0) /* Ignore overflow! */
longjmp (v->jump, JDONE);
if (dst != NULL)
{
switch (v->size)
{
case 'L':
*(long double *)dst = x;
break;
case 'l':
*(double *)dst = x;
break;
default:
*(float *)dst = x;
break;
}
++v->count;
}
if (v->at_eof)
longjmp (v->jump, JEOF);
}
static int inp_main (ilocal *v, const char *format, char *arg_ptr)
{
void *dst;
unsigned char f, c;
char assign;
c = 0;
while ((f = *format) != 0)
{
if (isspace (f))
{
do
{
++format; f = *format;
} while (isspace (f));
do
{
if (!get (v, &c))
{
if (f == 0 || v->count != 0)
return (v->count);
else
return (EOF);
}
} while (isspace (c));
push_back (v, c);
}
else if (f != '%')
{
c = next (v);
if (c != f)
{
push_back (v, c);
return (v->count);
}
++format;
}
else
{
v->size = 0; v->width = INT_MAX; assign = TRUE; dst = NULL;
++format;
if (*format == '*')
{
assign = FALSE;
++format;
}
if (isdigit (*format))
{
v->width = 0;
while (isdigit (*format))
v->width = v->width * 10 + (*format++ - '0');
if (v->width == 0)
v->width = INT_MAX;
}
if (*format == 'h' || *format == 'l' || *format == 'L')
v->size = *format++;
f = *format;
switch (f)
{
case 'c':
if (assign)
dst = va_arg (arg_ptr, char *);
inp_char (v, dst);
break;
case '[':
if (assign)
dst = va_arg (arg_ptr, char *);
inp_set (v, &format, dst);
break;
case 's':
if (assign)
dst = va_arg (arg_ptr, char *);
inp_str (v, dst);
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
if (assign)
switch (v->size)
{
case 'L':
dst = va_arg (arg_ptr, long double *);
break;
case 'l':
dst = va_arg (arg_ptr, double *);
break;
default:
dst = va_arg (arg_ptr, float *);
break;
}
inp_float (v, dst);
break;
case 'i':
case 'd':
case 'u':
case 'o':
case 'x':
case 'X':
case 'p':
if (assign)
switch (v->size)
{
case 'L':
dst = va_arg (arg_ptr, long long *);
break;
case 'h':
dst = va_arg (arg_ptr, short *);
break;
default:
dst = va_arg (arg_ptr, int *);
break;
}
inp_int (v, f, dst);
break;
case 'n':
if (assign)
switch (v->size)
{
case 'L':
*(va_arg (arg_ptr, long long *)) = v->chars;
break;
case 'h':
*(va_arg (arg_ptr, short *)) = v->chars;
break;
default:
*(va_arg (arg_ptr, int *)) = v->chars;
break;
}
break;
default:
if (f == 0) /* % at end of string */
return (v->count);
c = next (v);
if (c != f)
return (v->count);
break;
}
++format;
}
}
return (v->count);
}
int _input (FILE *stream, const char *format, char *arg_ptr)
{
ilocal v;
int rc;
v.stream = stream;
v.more = NULL; v.more_size = 0;
v.count = 0; v.chars = 0; v.at_eof = 0;
switch (setjmp (v.jump))
{
case JEOF:
/* End of file (or string) reached. If no fields were assigned,
return EOF. Otherwise return the number of fields
assigned. */
rc = ((v.count == 0) ? EOF : v.count);
break;
case JDONE:
/* Stop conversion due to non-matching character. Return the
number of fields assigned. */
rc = v.count;
break;
default:
/* This is the main line. */
rc = inp_main (&v, format, arg_ptr);
break;
}
if (v.more != NULL)
free (v.more);
return (rc);
}