From 5bcc00c1b85feff1996e3f34a1a9ebf3b624161e Mon Sep 17 00:00:00 2001 From: solar Date: Tue, 15 Sep 2009 04:30:12 +0000 Subject: [PATCH] Getting closer to scan(). --- functions/_PDCLIB/scan.c | 187 +++++++++++++++++- functions/ctype/isspace.c | 47 +++++ functions/ctype/tolower.c | 37 ++++ functions/stdio/vsscanf.c | 8 +- includes/ctype.h | 23 +++ internals/_PDCLIB_int.h | 6 +- .../example_64/internals/_PDCLIB_config.h | 27 ++- 7 files changed, 317 insertions(+), 18 deletions(-) create mode 100644 functions/ctype/isspace.c create mode 100644 functions/ctype/tolower.c create mode 100644 includes/ctype.h diff --git a/functions/_PDCLIB/scan.c b/functions/_PDCLIB/scan.c index d12e884..1502f62 100644 --- a/functions/_PDCLIB/scan.c +++ b/functions/_PDCLIB/scan.c @@ -7,10 +7,195 @@ */ #include +#include +#include +#include + +/* Using an integer's bits as flags for both the conversion flags and length + modifiers. +*/ +#define E_suppressed 1<<0 +#define E_char 1<<6 +#define E_short 1<<7 +#define E_long 1<<8 +#define E_llong 1<<9 +#define E_intmax 1<<10 +#define E_size 1<<11 +#define E_ptrdiff 1<<12 +#define E_intptr 1<<13 +#define E_ldouble 1<<14 +#define E_unsigned 1<<16 + + +static bool MATCH( const char x, struct _PDCLIB_status_t * status ) +{ + if ( status->stream != NULL ) + { + /* Matching against stream */ + if ( status->stream->buffer[ status->stream->bufidx ] == x ) + { + getc( status->stream ); + ++(status->i); + return true; + } + else + { + return false; + } + } + else + { + /* Matching against string */ + if ( *(status->s) == x ) + { + ++(status->s); + ++(status->i); + return true; + } + else + { + return false; + } + } +} + const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status ) { - return ++spec; + const char * orig_spec = spec; + if ( *(++spec) == '%' ) + { + /* %% -> match single '%' */ + MATCH( *spec, status ); + return ++spec; + } + /* Initializing status structure */ + status->flags = 0; + status->base = 0; + status->this = 0; + status->width = 0; + status->prec = 0; + + /* '*' suppresses assigning parsed value to variable */ + if ( *spec == '*' ) + { + status->flags |= E_suppressed; + ++spec; + } + + /* If a width is given, strtol() will return its value. If not given, + strtol() will return zero. In both cases, endptr will point to the + rest of the conversion specifier - just what we need. + */ + status->width = (int)strtol( spec, (char**)&spec, 10 ); + + /* Optional length modifier + We step one character ahead in any case, and step back only if we find + there has been no length modifier (or step ahead another character if it + has been "hh" or "ll"). + */ + switch ( *(spec++) ) + { + case 'h': + if ( *spec == 'h' ) + { + /* hh -> char */ + status->flags |= E_char; + ++spec; + } + else + { + /* h -> short */ + status->flags |= E_short; + } + break; + case 'l': + if ( *spec == 'l' ) + { + /* ll -> long long */ + status->flags |= E_llong; + ++spec; + } + else + { + /* l -> long */ + status->flags |= E_long; + } + break; + case 'j': + /* j -> intmax_t, which might or might not be long long */ + status->flags |= E_intmax; + break; + case 'z': + /* z -> size_t, which might or might not be unsigned int */ + status->flags |= E_size; + break; + case 't': + /* t -> ptrdiff_t, which might or might not be long */ + status->flags |= E_ptrdiff; + break; + case 'L': + /* L -> long double */ + status->flags |= E_ldouble; + break; + default: + --spec; + break; + } + + /* Conversion specifier */ + switch ( *spec ) + { + case 'd': + status->base = 10; + break; + case 'i': + /* status->base = 0; */ + break; + case 'o': + status->base = 8; + status->flags |= E_unsigned; + break; + case 'u': + status->base = 10; + status->flags |= E_unsigned; + break; + case 'x': + status->base = 16; + status->flags |= E_unsigned; + break; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + case 'a': + case 'A': + break; + case 'c': + /* TODO */ + break; + case 's': + /* TODO */ + break; + case 'p': + /* TODO */ + status->base = 16; + status->flags |= E_unsigned; + break; + case 'n': + { + int * val = va_arg( status->arg, int * ); + *val = status->i; + return ++spec; + } + default: + /* No conversion specifier. Bad conversion. */ + return orig_spec; + } + /* TODO: Actual conversions */ + return NULL; } #ifdef TEST diff --git a/functions/ctype/isspace.c b/functions/ctype/isspace.c new file mode 100644 index 0000000..346167e --- /dev/null +++ b/functions/ctype/isspace.c @@ -0,0 +1,47 @@ +/* $Id$ */ + +/* isspace( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include +#include + +#ifndef REGTEST + +int isspace( int c ) +{ + switch ( c ) + { + case ' ': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + return true; + default: + return false; + } +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> + +int main( void ) +{ + TESTCASE( isspace( ' ' ) ); + TESTCASE( isspace( '\f' ) ); + TESTCASE( isspace( '\n' ) ); + TESTCASE( isspace( '\r' ) ); + TESTCASE( isspace( '\t' ) ); + TESTCASE( isspace( '\v' ) ); + TESTCASE( ! isspace( 'a' ) ); + return TEST_RESULTS; +} + +#endif diff --git a/functions/ctype/tolower.c b/functions/ctype/tolower.c new file mode 100644 index 0000000..28c435d --- /dev/null +++ b/functions/ctype/tolower.c @@ -0,0 +1,37 @@ +/* $Id$ */ + +/* tolower( int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include + +#ifndef REGTEST + +int tolower( int c ) +{ + if ( ( c >= 'A' ) && ( c <= 'Z' ) ) + { + c += ( 'a' - 'A' ); + } + return c; +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> + +int main( void ) +{ + TESTCASE( tolower( 'A' ) == 'a' ); + TESTCASE( tolower( 'Z' ) == 'z' ); + TESTCASE( tolower( 'a' ) == 'a' ); + TESTCASE( tolower( 'z' ) == 'z' ); + TESTCASE( tolower( '@' ) == '@' ); + TESTCASE( tolower( '[' ) == '[' ); + return TEST_RESULTS; +} +#endif diff --git a/functions/stdio/vsscanf.c b/functions/stdio/vsscanf.c index c4565aa..34397ac 100644 --- a/functions/stdio/vsscanf.c +++ b/functions/stdio/vsscanf.c @@ -10,22 +10,16 @@ #include #ifndef REGTEST +#include int vsscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, va_list arg ) { struct _PDCLIB_status_t status; status.base = 0; status.flags = 0; - /* In _PDCLIB_print, status.n holds the maximum number of characters to be - written. As we don't need that for the scanf() functions, we (ab)use - this field to hold the number of matching conversion specifiers. - */ status.n = 0; status.i = 0; status.this = 0; - /* In _PDCLIB_print, status.s is the string *printed to*. In the scanf() - functions, we (ab)use this field to hold the string *scanned from*. - */ status.s = (char *)s; status.width = 0; status.prec = 0; diff --git a/includes/ctype.h b/includes/ctype.h new file mode 100644 index 0000000..2c8071c --- /dev/null +++ b/includes/ctype.h @@ -0,0 +1,23 @@ +/* $Id$ */ + +/* 7.4 Character handling + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_CTYPE_H +#define _PDCLIB_CTYPE_H _PDCLIB_CTYPE_H + +/* ------------------------------------------------------------------------- */ +/* THIS IS A STUB - THIS IS A STUB - THIS IS A STUB - THIS IS A STUB */ +/* ------------------------------------------------------------------------- */ +/* This implements two functions that are required by / */ +/* for the C locale only. Will be replaced in v0.6 by something compliant. */ +/* ------------------------------------------------------------------------- */ + +int tolower( int c ); +int isspace( int c ); + +#endif + diff --git a/internals/_PDCLIB_int.h b/internals/_PDCLIB_int.h index 62c38b2..9019f72 100644 --- a/internals/_PDCLIB_int.h +++ b/internals/_PDCLIB_int.h @@ -317,10 +317,12 @@ struct _PDCLIB_status_t { int base; /* base to which the value shall be converted */ _PDCLIB_int_fast32_t flags; /* flags and length modifiers */ - _PDCLIB_size_t n; /* maximum number of characters to be written */ + _PDCLIB_size_t n; /* print: maximum characters to be written */ + /* scan: number matched conversion specifiers */ _PDCLIB_size_t i; /* number of characters already written */ _PDCLIB_size_t this; /* output chars in the current conversion */ - char * s; /* target buffer */ + char * s; /* print: target buffer */ + /* scan: source string */ _PDCLIB_size_t width; /* width of current field */ _PDCLIB_size_t prec; /* precision of current field */ struct _PDCLIB_file_t * stream;/* for to-stream output */ diff --git a/platform/example_64/internals/_PDCLIB_config.h b/platform/example_64/internals/_PDCLIB_config.h index c8aa535..81fdb09 100644 --- a/platform/example_64/internals/_PDCLIB_config.h +++ b/platform/example_64/internals/_PDCLIB_config.h @@ -14,14 +14,6 @@ /* The character (sequence) your platform uses as newline. */ #define _PDCLIB_endl "\n" -/* The number of attempts to complete an I/O operation before giving up. */ -/* (Example: How often a buffer flushing is attempted before reporting fail.) */ -#define _PDCLIB_IO_RETRIES 1 - -/* What the system should do after an I/O operation did not succeed, before */ -/* trying again. (Empty by default.) */ -#define _PDCLIB_IO_RETRY_OP( stream ) - /* exit() can signal success to the host environment by the value of zero or */ /* the constant EXIT_SUCCESS. Failure is signaled by EXIT_FAILURE. Note that */ /* any other return value is "implementation-defined", i.e. your environment */ @@ -237,6 +229,25 @@ typedef int _PDCLIB_fd_t; */ #define _PDCLIB_NOHANDLE ( (_PDCLIB_fd_t) -1 ) +/* The default size for file buffers. Must be at least 256. */ +#define _PDCLIB_BUFSIZ 1024 + +/* The minimum number of files the implementation can open simultaneously. Must + be at least 8. Depends largely on how the bookkeeping is done by fopen() / + freopen() / fclose(). The example implementation limits the number of open + files only by available memory. +*/ +#define _PDCLIB_FOPEN_MAX 8 + +/* Length of the longest filename the implementation guarantees to support. */ +#define _PDCLIB_FILENAME_MAX 128 + +/* Buffer size for tmpnam(). */ +#define _PDCLIB_L_tmpnam 100 + +/* Number of distinct file names that can be generated by tmpnam(). */ +#define _PDCLIB_TMP_MAX 50 + /* The values of SEEK_SET, SEEK_CUR and SEEK_END, used by fseek(). Since at least one platform (POSIX) uses the same symbols for its own "seek" function, we use whatever the host defines (if it does define them). -- 2.40.0