mirror of
https://git.planet-casio.com/Vhex-Kernel-Core/fxlibc.git
synced 2024-12-28 04:23:38 +01:00
stdio: slight cleanup and documentation
This commit is contained in:
parent
177c4eea3f
commit
0cef8ca891
1 changed files with 45 additions and 75 deletions
|
@ -5,6 +5,28 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/* Features of this implementation:
|
||||||
|
- Specifiers:
|
||||||
|
* Integers (%i, %d, %o, %u, %x, %X)
|
||||||
|
* Floating-point numbers (%e, %f, %F, %g, %a)
|
||||||
|
* Strings (%c, %s, %[])
|
||||||
|
* Pointers (%p)
|
||||||
|
* Total number of bytes read so far (%n)
|
||||||
|
- Integer size modifiers: hh, h, l, ll, L, j, z, t. Supported for all
|
||||||
|
integer conversions, i.e. %i, %d, %u, %o, %x, %X and %n.
|
||||||
|
- Floating-point size modifiers: l, L for %a, %e, %f, %g.
|
||||||
|
- Assignment suppression character '*'.
|
||||||
|
- Maximum field width (but buggy for floating-point, see below).
|
||||||
|
|
||||||
|
NOT SUPPORTED:
|
||||||
|
- Wide characters: %lc, %ls.
|
||||||
|
- q size modifier.
|
||||||
|
- "'" (quote) specifier for locale-specific thousand separators.
|
||||||
|
- String allocation: %mc, %ms.
|
||||||
|
- Out-of-order assignments "%n$".
|
||||||
|
- TODO: Maximum field width for floating-point is mostly untested and likely
|
||||||
|
has bugs when the field ends in the middle of the number. */
|
||||||
|
|
||||||
void __scanf_start(struct __scanf_input *in)
|
void __scanf_start(struct __scanf_input *in)
|
||||||
{
|
{
|
||||||
if(in->fp)
|
if(in->fp)
|
||||||
|
@ -38,12 +60,13 @@ void __scanf_end(struct __scanf_input *in)
|
||||||
in->str--;
|
in->str--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __purge_space( struct __scanf_input * __restrict__ in )
|
static void __skip_spaces(struct __scanf_input *in)
|
||||||
{
|
{
|
||||||
while (isspace(__scanf_peek(in))) __scanf_in(in);
|
while(isspace(__scanf_peek(in)))
|
||||||
|
__scanf_in(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __scanf_store_i(int64_t value, int size, va_list *args)
|
static void __scanf_store_i(int64_t value, int size, va_list *args)
|
||||||
{
|
{
|
||||||
if(size == 1)
|
if(size == 1)
|
||||||
*va_arg(*args, int8_t *) = value;
|
*va_arg(*args, int8_t *) = value;
|
||||||
|
@ -55,7 +78,7 @@ void __scanf_store_i(int64_t value, int size, va_list *args)
|
||||||
*va_arg(*args, int64_t *) = value;
|
*va_arg(*args, int64_t *) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __scanf_store_d(long double value, int size, va_list *args)
|
static void __scanf_store_d(long double value, int size, va_list *args)
|
||||||
{
|
{
|
||||||
if(size == sizeof(float))
|
if(size == sizeof(float))
|
||||||
*va_arg(*args, float *) = value;
|
*va_arg(*args, float *) = value;
|
||||||
|
@ -65,47 +88,6 @@ void __scanf_store_d(long double value, int size, va_list *args)
|
||||||
*va_arg(*args, long double *) = value;
|
*va_arg(*args, long double *) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* STATUS OF __scanf DEVELOPMENT */
|
|
||||||
|
|
||||||
// XX = not done yet (but will be done)
|
|
||||||
// OK = OK, done and tested
|
|
||||||
// -- = not applicable
|
|
||||||
// NO = not supported (and will not be done) only for %lc as long char are not supported by gint
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************************************************/
|
|
||||||
/* Specifier * Explanation * num * hh * h *none* l * ll * j * z * t * L */
|
|
||||||
/*************************************************************************************************************/
|
|
||||||
/* % * Parse literal '%' * -- * -- * -- * OK * -- * -- * -- * -- * -- * -- */
|
|
||||||
/*************************************************************************************************************/
|
|
||||||
/* c * match a char or several char * OK * -- * -- * OK * NO * -- * -- * -- * -- * -- */
|
|
||||||
/*************************************************************************************************************/
|
|
||||||
/* s * match a string * OK * -- * -- * OK * NO * -- * -- * -- * -- * -- */
|
|
||||||
/*************************************************************************************************************/
|
|
||||||
/* [set] * match a set of char * OK * -- * -- * OK * -- * -- * -- * -- * -- * -- */
|
|
||||||
/*************************************************************************************************************/
|
|
||||||
/* d * match a decimal integer * OK * OK * OK * OK * OK * OK * OK * OK * OK * -- */
|
|
||||||
/*************************************************************************************************************/
|
|
||||||
/* i * match an integer * OK * OK * OK * OK * OK * OK * OK * OK * OK * -- */
|
|
||||||
/*************************************************************************************************************/
|
|
||||||
/* d * match an unsigned decimal integer * OK * OK * OK * OK * OK * OK * OK * OK * OK * -- */
|
|
||||||
/*************************************************************************************************************/
|
|
||||||
/* o * match a unsigned octal integer * OK * OK * OK * OK * OK * OK * OK * OK * OK * -- */
|
|
||||||
/*************************************************************************************************************/
|
|
||||||
/* x,X * match a unsigned hexadecimal integer * OK * OK * OK * OK * OK * OK * OK * OK * OK * -- */
|
|
||||||
/*************************************************************************************************************/
|
|
||||||
/* n * return the nb of chars read so far * -- * -- * -- * OK * -- * -- * -- * -- * -- * -- */
|
|
||||||
/*************************************************************************************************************/
|
|
||||||
/* a,A * match a floating point number * OK * -- * -- * OK * OK * -- * -- * -- * -- * OK */
|
|
||||||
/* e,E * match a floating point number * OK * -- * -- * OK * OK * -- * -- * -- * -- * OK */
|
|
||||||
/* f,F * match a floating point number * OK * -- * -- * OK * OK * -- * -- * -- * -- * OK */
|
|
||||||
/* g,G * match a floating point number * OK * -- * -- * OK * OK * -- * -- * -- * -- * OK */
|
|
||||||
/*************************************************************************************************************/
|
|
||||||
/* p * match a pointer * -- * -- * -- * OK * -- * -- * -- * -- * -- * -- */
|
|
||||||
/*************************************************************************************************************/
|
|
||||||
|
|
||||||
// %ms and %m[set] are not implemented (with memory allocation while parsing a chain or a set of characters)
|
|
||||||
|
|
||||||
struct scanf_format {
|
struct scanf_format {
|
||||||
/* Maximum field width */
|
/* Maximum field width */
|
||||||
int field_width;
|
int field_width;
|
||||||
|
@ -113,7 +95,6 @@ struct scanf_format {
|
||||||
uint8_t size;
|
uint8_t size;
|
||||||
/* Whether to skip assignment */
|
/* Whether to skip assignment */
|
||||||
bool skip;
|
bool skip;
|
||||||
|
|
||||||
/* Set of bytes allowed for bracket sets in %[] */
|
/* Set of bytes allowed for bracket sets in %[] */
|
||||||
uint8_t bracket_set[32];
|
uint8_t bracket_set[32];
|
||||||
};
|
};
|
||||||
|
@ -182,6 +163,7 @@ static bool bracket_set_parse(uint8_t *set, char const *format, int *pos)
|
||||||
return (format[*pos] == ']');
|
return (format[*pos] == ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse a format in the format string. Returns specifier, 0 on error. */
|
||||||
static int parse_fmt(char const *fmt, int *pos, struct scanf_format *opt)
|
static int parse_fmt(char const *fmt, int *pos, struct scanf_format *opt)
|
||||||
{
|
{
|
||||||
opt->field_width = INT_MAX;
|
opt->field_width = INT_MAX;
|
||||||
|
@ -255,7 +237,7 @@ int __scanf(
|
||||||
|
|
||||||
for(int pos = 0; format[pos]; pos++) {
|
for(int pos = 0; format[pos]; pos++) {
|
||||||
if(format[pos] == ' ') {
|
if(format[pos] == ' ') {
|
||||||
__purge_space(in);
|
__skip_spaces(in);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if(format[pos] != '%' || format[pos + 1] == '%') {
|
else if(format[pos] != '%' || format[pos + 1] == '%') {
|
||||||
|
@ -275,21 +257,19 @@ int __scanf(
|
||||||
|
|
||||||
switch(spec) {
|
switch(spec) {
|
||||||
case '[': {
|
case '[': {
|
||||||
int currentlength = 0;
|
|
||||||
// we need to assign the read char to the corresponding pointer
|
|
||||||
char *c = opt.skip ? NULL : va_arg(*args, char *);
|
char *c = opt.skip ? NULL : va_arg(*args, char *);
|
||||||
for(int u=0; u<opt.field_width; u++) {
|
int i;
|
||||||
|
for(i = 0; i < opt.field_width; i++) {
|
||||||
int temp = __scanf_peek(in);
|
int temp = __scanf_peek(in);
|
||||||
if(bracket_set_test(opt.bracket_set, temp)) {
|
if(bracket_set_test(opt.bracket_set, temp)) {
|
||||||
__scanf_in(in);
|
__scanf_in(in);
|
||||||
if(c) *c++ = temp;
|
if(c) *c++ = temp;
|
||||||
currentlength++;
|
|
||||||
}
|
}
|
||||||
else if(temp==EOF && !currentlength && !validrets)
|
else if(temp==EOF && !i && !validrets)
|
||||||
return EOF;
|
return EOF;
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
if(!currentlength)
|
if(!i)
|
||||||
return validrets;
|
return validrets;
|
||||||
*c = '\0';
|
*c = '\0';
|
||||||
validrets += !opt.skip;
|
validrets += !opt.skip;
|
||||||
|
@ -297,7 +277,7 @@ int __scanf(
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'n':
|
case 'n':
|
||||||
*va_arg(*args, int *) = in->bytes_read;
|
__scanf_store_i(in->bytes_read, opt.size, args);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
|
@ -331,8 +311,6 @@ int __scanf(
|
||||||
case 'F':
|
case 'F':
|
||||||
case 'g':
|
case 'g':
|
||||||
case 'G': {
|
case 'G': {
|
||||||
// read a double from the current input stream
|
|
||||||
// and store in the corresponding arg as a char by reference
|
|
||||||
long double temp;
|
long double temp;
|
||||||
int err = __strto_fp(in, NULL, NULL, &temp, opt.field_width);
|
int err = __strto_fp(in, NULL, NULL, &temp, opt.field_width);
|
||||||
if(err == EOF && validrets == 0) return EOF;
|
if(err == EOF && validrets == 0) return EOF;
|
||||||
|
@ -344,15 +322,11 @@ int __scanf(
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'p': {
|
case 'p': {
|
||||||
long int temp;
|
void *p = opt.skip ? NULL : va_arg(*args, void *);
|
||||||
int err = 0;
|
_Static_assert(sizeof(p) == sizeof(long));
|
||||||
if(!opt.skip) {
|
int err = __strto_int(in, 0, p, NULL, true, opt.field_width);
|
||||||
void *p = va_arg(*args, void *);
|
|
||||||
err = __strto_int(in, 0, p, NULL, true, opt.field_width);
|
|
||||||
validrets += (err == 0);
|
|
||||||
}
|
|
||||||
else err = __strto_int(in, 0, &temp, NULL, true, opt.field_width);
|
|
||||||
if(err) return validrets;
|
if(err) return validrets;
|
||||||
|
validrets += !opt.skip;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,15 +343,13 @@ int __scanf(
|
||||||
}
|
}
|
||||||
|
|
||||||
case 's': {
|
case 's': {
|
||||||
char temp;
|
|
||||||
int curstrlength = 0;
|
|
||||||
__purge_space(in);
|
|
||||||
|
|
||||||
char *c = opt.skip ? NULL : va_arg(*args, char *);
|
char *c = opt.skip ? NULL : va_arg(*args, char *);
|
||||||
for(int u = 0; u < opt.field_width; u++) {
|
__skip_spaces(in);
|
||||||
temp = __scanf_peek(in);
|
|
||||||
if(temp==EOF && curstrlength==0) return validrets;
|
for(int i = 0; i < opt.field_width; i++) {
|
||||||
if(isspace(temp) || ((temp==EOF && curstrlength!=0))) {
|
int temp = __scanf_peek(in);
|
||||||
|
if(temp==EOF && !i) return validrets;
|
||||||
|
if(isspace(temp) || temp==EOF) {
|
||||||
if(c) {
|
if(c) {
|
||||||
*c = 0;
|
*c = 0;
|
||||||
validrets++;
|
validrets++;
|
||||||
|
@ -386,9 +358,7 @@ int __scanf(
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int temp = __scanf_in(in);
|
int temp = __scanf_in(in);
|
||||||
if(c)
|
if(c) *c++ = temp;
|
||||||
*c++ = temp;
|
|
||||||
curstrlength++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue