mirror of
https://github.com/cc65/cc65.git
synced 2025-02-03 07:30:52 +00:00
Working on the ..scanf functions
git-svn-id: svn://svn.cc65.org/cc65/trunk@691 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
dccc89edae
commit
71e40d42f5
@ -1,7 +1,8 @@
|
||||
*.lst
|
||||
*.lst
|
||||
_afailed.s
|
||||
_fopen.s
|
||||
_hextab.s
|
||||
_scanf.s
|
||||
abort.s
|
||||
bsearch.s
|
||||
calloc.s
|
||||
|
@ -14,6 +14,7 @@
|
||||
C_OBJS = _afailed.o \
|
||||
_fopen.o \
|
||||
_hextab.o \
|
||||
_scanf.o \
|
||||
abort.o \
|
||||
bsearch.o \
|
||||
calloc.o \
|
||||
|
369
libsrc/common/_scanf.c
Normal file
369
libsrc/common/_scanf.c
Normal file
@ -0,0 +1,369 @@
|
||||
/*
|
||||
* _scanf.c
|
||||
*
|
||||
* (C) Copyright 2001 Ullrich von Bassewitz (uz@cc65.org)
|
||||
*
|
||||
* This is the basic layer for all scanf type functions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <setjmp.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "_scanf.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* SetJmp return codes */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#define RC_OK 0 /* Regular call */
|
||||
#define RC_EOF 1 /* EOF reached */
|
||||
#define RC_NOCONV 2 /* No conversion possible */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static jmp_buf JumpBuf; /* Label that is used in case of EOF */
|
||||
static char C; /* Character from input */
|
||||
static unsigned Width; /* Maximum field width */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Character sets */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void ReadChar (struct indesc* d)
|
||||
/* Get an input character, count characters */
|
||||
{
|
||||
C = d->fin (d);
|
||||
++d->ccount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void SkipWhite (struct indesc* d)
|
||||
/* Skip white space in the input and return the first non white character */
|
||||
{
|
||||
while (isspace (C)) {
|
||||
ReadChar (d);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned char ReadSign (struct indesc* d)
|
||||
/* Read an optional sign and skip it. Return 1 if the value is positive,
|
||||
* return 0 otherwise.
|
||||
*/
|
||||
{
|
||||
switch (C) {
|
||||
case '-':
|
||||
ReadChar (d);
|
||||
return 0;
|
||||
case '+':
|
||||
ReadChar (d);
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned char HexVal (char C)
|
||||
/* Convert a digit to a value */
|
||||
{
|
||||
|
||||
if (isdigit (C)) {
|
||||
return C - '0';
|
||||
} else {
|
||||
return C - toupper (C) + ('A' + 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned long ReadInt (struct indesc* d, unsigned char Base)
|
||||
/* Read an integer */
|
||||
{
|
||||
unsigned long V = 0;
|
||||
|
||||
/* Value must start with a digit */
|
||||
if (!isdigit (C)) {
|
||||
longjmp (JumpBuf, RC_NOCONV);
|
||||
}
|
||||
|
||||
/* Read the value */
|
||||
while (isxdigit (C) && Width-- > 0) {
|
||||
printf ("ReadInt: '%c'\n", C);
|
||||
V = V * Base + HexVal (C);
|
||||
ReadChar (d);
|
||||
}
|
||||
|
||||
/* Return the read value */
|
||||
return V;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _scanf (struct indesc* d, const char* format, va_list ap)
|
||||
/* This is the routine used to do the actual work. It is called from several
|
||||
* types of wrappers to implement the actual ISO xxscanf functions.
|
||||
*/
|
||||
{
|
||||
unsigned Conversions; /* Number of conversions */
|
||||
|
||||
char F; /* Character from format string */
|
||||
unsigned char NoAssign; /* Supppress assigment */
|
||||
unsigned char IsShort; /* Short type */
|
||||
unsigned char IsLong; /* Long type */
|
||||
unsigned char Positive; /* Flag for positive value */
|
||||
unsigned char Result; /* setjmp result */
|
||||
|
||||
/* Variables that hold intermediate values */
|
||||
void* P;
|
||||
long L;
|
||||
|
||||
|
||||
/* Initialize variables */
|
||||
Conversions = 0;
|
||||
d->ccount = 0;
|
||||
|
||||
/* Set up the jump label. The get() routine will use this label when EOF
|
||||
* is reached.
|
||||
*/
|
||||
Result = setjmp (JumpBuf);
|
||||
printf ("Result = %u\n", Result);
|
||||
if (Result == RC_OK) {
|
||||
|
||||
Again:
|
||||
/* Get the next input character */
|
||||
ReadChar (d);
|
||||
|
||||
/* Walk over the format string */
|
||||
while (F = *format++) {
|
||||
|
||||
/* Check for a conversion */
|
||||
if (F != '%' || *format == '%') {
|
||||
|
||||
/* %% or any char other than % */
|
||||
if (F == '%') {
|
||||
++format;
|
||||
}
|
||||
|
||||
/* Check for a match */
|
||||
if (isspace (F)) {
|
||||
|
||||
/* Special white space handling: Any whitespace matches
|
||||
* any amount of whitespace including none(!). So this
|
||||
* match will never fail.
|
||||
*/
|
||||
SkipWhite (d);
|
||||
continue;
|
||||
|
||||
} else if (F != C) {
|
||||
|
||||
/* A mismatch. We will stop scanning the input and return
|
||||
* the number of conversions.
|
||||
*/
|
||||
printf ("F = '%c', C = '%c' --> mismatch\n", F, C);
|
||||
return Conversions;
|
||||
|
||||
} else {
|
||||
|
||||
/* A match. Read the next input character and start over */
|
||||
goto Again;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* A conversion. Skip the percent sign. */
|
||||
F = *format++;
|
||||
|
||||
/* Initialize variables */
|
||||
NoAssign = 0;
|
||||
IsShort = 0;
|
||||
IsLong = 0;
|
||||
Width = UINT_MAX;
|
||||
|
||||
/* Check for flags. */
|
||||
while (1) {
|
||||
if (isdigit (F)) {
|
||||
Width = 0;
|
||||
do {
|
||||
/* ### Non portable ### */
|
||||
Width = Width * 10 + (F & 0x0F);
|
||||
F = *format++;
|
||||
} while (isdigit (F));
|
||||
} else {
|
||||
switch (F) {
|
||||
case '*': NoAssign = 1; break;
|
||||
case 'h': IsShort = 1; break;
|
||||
case 'l':
|
||||
case 'L': IsLong = 1; break;
|
||||
default: goto FlagsDone;
|
||||
}
|
||||
F = *format++;
|
||||
}
|
||||
}
|
||||
FlagsDone:
|
||||
|
||||
/* Check for the actual conversion character */
|
||||
printf ("F = '%c'\n", F);
|
||||
switch (F) {
|
||||
|
||||
case 'D':
|
||||
IsLong = 1;
|
||||
case 'd':
|
||||
/* Optionally signed decimal integer */
|
||||
SkipWhite (d);
|
||||
Positive = ReadSign (d);
|
||||
L = ReadInt (d, 10);
|
||||
if (!Positive) {
|
||||
L = -L;
|
||||
}
|
||||
if (!NoAssign) {
|
||||
/* All pointers have the same size, so save some
|
||||
* code here.
|
||||
*/
|
||||
P = va_arg (ap, void*);
|
||||
if (IsLong) {
|
||||
*(long*)P = L;
|
||||
} else {
|
||||
*(int*)P = (int) L;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
/* Optionally signed integer with a base */
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
/* Unsigned octal integer */
|
||||
L = ReadInt (d, 8);
|
||||
if (!NoAssign) {
|
||||
/* All pointers have the same size, so save some
|
||||
* code here.
|
||||
*/
|
||||
P = va_arg (ap, void*);
|
||||
if (IsLong) {
|
||||
*(long*)P = L;
|
||||
} else {
|
||||
*(int*)P = (int) L;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
/* Unsigned decimal integer */
|
||||
L = ReadInt (d, 10);
|
||||
if (!NoAssign) {
|
||||
/* All pointers have the same size, so save some
|
||||
* code here.
|
||||
*/
|
||||
P = va_arg (ap, void*);
|
||||
if (IsLong) {
|
||||
*(long*)P = L;
|
||||
} else {
|
||||
*(int*)P = (int) L;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
/* Unsigned hexadecimal integer */
|
||||
L = ReadInt (d, 16);
|
||||
if (!NoAssign) {
|
||||
/* All pointers have the same size, so save some
|
||||
* code here.
|
||||
*/
|
||||
P = va_arg (ap, void*);
|
||||
if (IsLong) {
|
||||
*(long*)P = L;
|
||||
} else {
|
||||
*(int*)P = (int) L;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
/* Optionally signed float */
|
||||
break;
|
||||
|
||||
case 's':
|
||||
/* Whitespace terminated string */
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
/* Fixed length string */
|
||||
break;
|
||||
|
||||
case '[':
|
||||
/* String using characters from a set */
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
/* Pointer */
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
/* Store characters consumed so far */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Invalid conversion */
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* Skip the format char */
|
||||
goto Again;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (Result == RC_EOF) {
|
||||
|
||||
/* Jump via JumpBuf means EOF on input */
|
||||
if (d->ccount == 0) {
|
||||
/* Special case: error */
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of conversions */
|
||||
return Conversions;
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,8 +15,10 @@
|
||||
/* Forward */
|
||||
struct indesc;
|
||||
|
||||
/* Type of the function that is called to input data */
|
||||
typedef void (*infunc) (struct indesc* desc, const char* buf, unsigned count);
|
||||
/* Type of the function that is called to input data. The function will
|
||||
* return EOF if no more data is available.
|
||||
*/
|
||||
typedef char (*infunc) (struct indesc* desc);
|
||||
|
||||
|
||||
|
||||
@ -25,11 +27,14 @@ typedef void (*infunc) (struct indesc* desc, const char* buf, unsigned count);
|
||||
* level, so check this when altering the structure.
|
||||
*/
|
||||
struct indesc {
|
||||
char* buf; /* Pointer to input buffer */
|
||||
unsigned size; /* Size of input buffer */
|
||||
unsigned fill; /* Fill mark of input buffer */
|
||||
unsigned ridx; /* Read index of input buffer */
|
||||
infunc fin; /* Pointer to input routine */
|
||||
infunc fin; /* Pointer to input routine */
|
||||
unsigned ccount; /* Number of chars read */
|
||||
|
||||
/* Fields used outside from _scanf */
|
||||
char* buf; /* Pointer to input buffer */
|
||||
unsigned size; /* Size of input buffer */
|
||||
unsigned fill; /* Fill mark of input buffer */
|
||||
unsigned ridx; /* Read index of input buffer */
|
||||
};
|
||||
|
||||
|
||||
@ -44,3 +49,4 @@ int _scanf (struct indesc* d, const char* format, va_list ap);
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -19,6 +19,19 @@
|
||||
|
||||
|
||||
|
||||
static char get (struct indesc* d)
|
||||
/* Read a character from the input string and return it */
|
||||
{
|
||||
char C;
|
||||
if (C = d->buf[d->ridx]) {
|
||||
/* Increment index only if end not reached */
|
||||
++d->ridx;
|
||||
}
|
||||
return C;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int sscanf (const char* str, const char* format, ...)
|
||||
/* Standard C function */
|
||||
{
|
||||
@ -28,8 +41,9 @@ int sscanf (const char* str, const char* format, ...)
|
||||
/* Initialize the indesc struct. We leave all fields uninitialized that we
|
||||
* don't need
|
||||
*/
|
||||
id.fin = (infunc) get;
|
||||
id.buf = (char*) str;
|
||||
id.fill = strlen (str);
|
||||
id.ridx = 0;
|
||||
|
||||
/* Setup for variable arguments */
|
||||
va_start (ap, format);
|
||||
|
Loading…
x
Reference in New Issue
Block a user