forked from KolibriOS/kolibrios
added *scanf family
git-svn-id: svn://kolibrios.org@6431 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
0b28f93f8e
commit
9eb1268c4d
@ -68,4 +68,8 @@ int getchar (void);
|
||||
int puts (const char * str);
|
||||
char * gets (char * str);
|
||||
|
||||
typedef int (*virtual_getc)(void *sp, const void *obj);
|
||||
typedef void (*virtual_ungetc)(void *sp, int c, const void *obj);
|
||||
int format_scan(const void *src, const char *fmt, va_list argp, virtual_getc vgetc, virtual_ungetc vungetc);
|
||||
|
||||
#endif
|
||||
|
415
programs/develop/ktcc/trunk/libc/stdio/format_scan.c
Normal file
415
programs/develop/ktcc/trunk/libc/stdio/format_scan.c
Normal file
@ -0,0 +1,415 @@
|
||||
/*
|
||||
function for format read from any source
|
||||
|
||||
Siemargl formats as http://www.cplusplus.com/reference/cstdio/scanf/, no wchar though
|
||||
http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap05.html is used too
|
||||
|
||||
todo:
|
||||
[characters], [^characters]
|
||||
-%n nothing scanned, filled only if good result
|
||||
-%d, i, u, o, x, p read similar - detect base by prefix 0 or 0x
|
||||
-%a
|
||||
-can overflow unsigned as signed
|
||||
-radix point always '.', no LOCALEs
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
enum flags_t
|
||||
{
|
||||
flag_unsigned = 0x02,
|
||||
flag_register = 0x04,
|
||||
flag_plus = 0x08,
|
||||
flag_left_just = 0x10,
|
||||
flag_lead_zeros = 0x20,
|
||||
flag_space_plus = 0x40,
|
||||
flag_hash_sign = 0x80,
|
||||
flag_point = 0x100
|
||||
};
|
||||
|
||||
int try_parse_real(long double *real, int ch, const void *src, void *save, virtual_getc vgetc, virtual_ungetc vungetc)
|
||||
// returns 1 if OK, -1 == EOF, -2 parse broken
|
||||
{
|
||||
int sign = 1, have_digits = 0;
|
||||
long long div;
|
||||
|
||||
if (ch == '+')
|
||||
{
|
||||
ch = vgetc(save, src);
|
||||
if (ch == EOF) return EOF;
|
||||
} else
|
||||
if (ch == '-')
|
||||
{
|
||||
sign = -1;
|
||||
ch = vgetc(save, src);
|
||||
if (ch == EOF) return EOF;
|
||||
};
|
||||
*real = 0.0;
|
||||
for (;;) // mantissa before point
|
||||
{
|
||||
// test ch is valid
|
||||
if (isdigit(ch))
|
||||
{
|
||||
*real = *real * 10 + ch - '0';
|
||||
have_digits++;
|
||||
ch = vgetc(save, src);
|
||||
if (ch == EOF || isspace(ch)) break; // ok, just finish num
|
||||
} else
|
||||
if (ch == '.' || ch == 'E' || ch == 'e')
|
||||
{
|
||||
break; // ok
|
||||
}
|
||||
else
|
||||
{
|
||||
vungetc(save, ch, src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ch != '.' && ch != 'E' && ch != 'e') // ok, just integer part
|
||||
{
|
||||
*real *= sign;
|
||||
if (have_digits)
|
||||
return 1;
|
||||
else
|
||||
return -2;
|
||||
}
|
||||
|
||||
if(ch == '.')
|
||||
{
|
||||
ch = vgetc(save, src);
|
||||
div = 10; // use as divisor
|
||||
for (;;) // mantissa after point
|
||||
{
|
||||
// test ch is valid
|
||||
if (isdigit(ch))
|
||||
{
|
||||
*real += (double)(ch - '0') / div;
|
||||
div *= 10;
|
||||
have_digits++;
|
||||
ch = vgetc(save, src);
|
||||
if (ch == EOF || isspace(ch)) break; // ok, just finish num
|
||||
} else
|
||||
if (ch == 'E' || ch == 'e')
|
||||
{
|
||||
break; // ok
|
||||
}
|
||||
else
|
||||
{
|
||||
vungetc(save, ch, src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ch != 'E' && ch != 'e') // ok, real as XX.YY
|
||||
{
|
||||
*real *= sign;
|
||||
if (have_digits)
|
||||
return 1;
|
||||
else
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
ch = vgetc(save, src);
|
||||
*real *= sign;
|
||||
// exponent
|
||||
sign = 1;
|
||||
if (ch == '+')
|
||||
{
|
||||
ch = vgetc(save, src);
|
||||
if (ch == EOF) return EOF;
|
||||
} else
|
||||
if (ch == '-')
|
||||
{
|
||||
sign = -1;
|
||||
ch = vgetc(save, src);
|
||||
if (ch == EOF) return EOF;
|
||||
};
|
||||
div = 0;
|
||||
for (;;)
|
||||
{
|
||||
// test ch is valid
|
||||
if (isdigit(ch))
|
||||
{
|
||||
div = div * 10 + ch - '0';
|
||||
ch = vgetc(save, src);
|
||||
if (ch == EOF || isspace(ch)) break; // ok, just finish num
|
||||
}
|
||||
else
|
||||
{
|
||||
vungetc(save, ch, src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
div *= sign;
|
||||
*real *= pow(10, div);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int try_parse_int(long long *digit, int ch, const void *src, void *save, virtual_getc vgetc, virtual_ungetc vungetc)
|
||||
{
|
||||
int sign = 1, base = 10, have_digits = 0;
|
||||
|
||||
if (ch == '+')
|
||||
{
|
||||
ch = vgetc(save, src);
|
||||
if (ch == EOF) return EOF;
|
||||
} else
|
||||
if (ch == '-')
|
||||
{
|
||||
sign = -1;
|
||||
ch = vgetc(save, src);
|
||||
if (ch == EOF) return EOF;
|
||||
};
|
||||
|
||||
if (ch == '0') // octal or hex, read next
|
||||
{
|
||||
base = 8;
|
||||
ch = vgetc(save, src);
|
||||
if (ch == EOF) return EOF;
|
||||
if (ch == 'x' || ch == 'X')
|
||||
{
|
||||
base = 16;
|
||||
ch = vgetc(save, src);
|
||||
if (ch == EOF) return EOF;
|
||||
}
|
||||
}
|
||||
*digit = 0;
|
||||
for (;;)
|
||||
{
|
||||
// test ch is valid
|
||||
if ((isdigit(ch) && base == 10) ||
|
||||
(isdigit(ch) && base == 8 && ch < '8') ||
|
||||
(isxdigit(ch) && base == 16))
|
||||
{
|
||||
if (base == 16)
|
||||
{
|
||||
if (ch <= '9') ch-= '0';
|
||||
else
|
||||
if (ch <= 'F') ch = 10 + ch - 'A';
|
||||
else
|
||||
ch = 10 + ch - 'a';
|
||||
}
|
||||
else
|
||||
ch -= '0';
|
||||
*digit = *digit * base + ch;
|
||||
have_digits++;
|
||||
ch = vgetc(save, src);
|
||||
if (ch == EOF || isspace(ch)) break; // ok, just finish num
|
||||
}
|
||||
else
|
||||
{
|
||||
vungetc(save, ch, src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*digit *= sign;
|
||||
if (have_digits)
|
||||
return 1;
|
||||
else
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int format_scan(const void *src, const char *fmt, va_list argp, virtual_getc vgetc, virtual_ungetc vungetc)
|
||||
{
|
||||
int i;
|
||||
int length;
|
||||
int fmt1, fmt2; // width, precision
|
||||
size_t pos, posc;
|
||||
const char *fmtc; // first point to %, fmtc points to specifier
|
||||
int ch;
|
||||
int format_flag;
|
||||
int flag_long; // 2 = long double or long long int or wchar
|
||||
int *point_to_n = NULL, nread = 0;
|
||||
int flags; // parsed flags
|
||||
int save = 0;
|
||||
char *arg_str;
|
||||
int *arg_int;
|
||||
long *arg_long;
|
||||
long long *arg_longlong;
|
||||
float *arg_float;
|
||||
double *arg_double;
|
||||
long double *arg_longdouble;
|
||||
long long digit;
|
||||
long double real;
|
||||
|
||||
|
||||
pos = 0;
|
||||
while(*fmt)
|
||||
{
|
||||
while (*fmt && isspace(*fmt)) fmt++; // skip paces in format str
|
||||
|
||||
if (*fmt != '%') // usual char
|
||||
{
|
||||
ch = vgetc(&save, src);
|
||||
if (ch != *fmt++) // char not match format
|
||||
{
|
||||
vungetc(&save, ch, src);
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*(fmt + 1) == '%') // %%
|
||||
{
|
||||
ch = vgetc(&save, src);
|
||||
if (ch != '%') // char not match format
|
||||
{
|
||||
vungetc(&save, ch, src);
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
fmt += 2;
|
||||
continue;
|
||||
}
|
||||
//checking to containg format in the string
|
||||
fmtc = fmt;
|
||||
posc = pos;
|
||||
|
||||
flags = 0;
|
||||
format_flag = 0;
|
||||
flag_long = 0; // 2 = long double or long long int or wchar
|
||||
|
||||
while(*fmtc != '\0' && !format_flag) // searching end of format
|
||||
{
|
||||
fmtc++; posc++;
|
||||
switch( *fmtc )
|
||||
{
|
||||
case 'a':
|
||||
format_flag = 1;
|
||||
flags |= flag_unsigned;
|
||||
break;
|
||||
case 'c': case 'd': case 'i': case 'e': case 'f': case 'g': case 's': case 'n':
|
||||
format_flag = 1;
|
||||
break;
|
||||
case 'l':
|
||||
flag_long = flag_long ? 2 : 1; // ll.eq.L
|
||||
break;
|
||||
case 'L':
|
||||
flag_long = 2;
|
||||
break;
|
||||
case 'o': case 'u': case 'x': case 'p':
|
||||
format_flag = 1;
|
||||
flags |= flag_unsigned;
|
||||
break;
|
||||
case '*': case '.': // just skip
|
||||
break;
|
||||
default:
|
||||
if(isdigit(*fmtc)) break;
|
||||
goto exit_me; // non format char found - user error
|
||||
}
|
||||
}
|
||||
|
||||
if (format_flag == 0)
|
||||
{
|
||||
goto exit_me; // format char not found - user error
|
||||
}
|
||||
|
||||
fmt1 = 0;
|
||||
fmt2 = 0;
|
||||
if (posc - pos > 1) // try to read width, precision
|
||||
{
|
||||
fmt++;
|
||||
for(i = pos + 1; i < posc; i++)
|
||||
{
|
||||
switch(*fmt)
|
||||
{
|
||||
case '0':
|
||||
if(fmt1 == 0 && (flags & flag_point) == 0) flags |= flag_lead_zeros;
|
||||
case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
if ((flags & flag_point) == 0)
|
||||
fmt1 = fmt1 * 10 + (*fmt -'0');
|
||||
else
|
||||
fmt2 = fmt2 * 10 + (*fmt -'0');
|
||||
break;
|
||||
case '*':
|
||||
if (flag_point == 0)
|
||||
fmt1 = va_arg(argp, int);
|
||||
else
|
||||
fmt2 = va_arg(argp, int);
|
||||
break;
|
||||
case '.':
|
||||
flags |= flag_point;
|
||||
break;
|
||||
case 'l': case 'L': // valid chars - skip
|
||||
break;
|
||||
default: // must be error
|
||||
goto exit_me; // format char not found - user error
|
||||
}
|
||||
fmt++;
|
||||
}
|
||||
}
|
||||
|
||||
// do real work - format arguments values
|
||||
// skip input spaces
|
||||
do {
|
||||
ch = vgetc(&save, src);
|
||||
if (ch == EOF) goto exit_me;
|
||||
} while (isspace(ch));
|
||||
|
||||
switch(*fmtc)
|
||||
{
|
||||
case 'n':
|
||||
point_to_n = va_arg(argp, int*);
|
||||
vungetc(&save, ch, src);
|
||||
break;
|
||||
case 'c': // read width chars, ever spaces
|
||||
arg_str = va_arg(argp, char*);
|
||||
if (fmt1 == 0) length = 1;
|
||||
else length = fmt1;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
*arg_str++ = ch;
|
||||
ch = vgetc(&save, src);
|
||||
if (ch == EOF) break;
|
||||
}
|
||||
if (i < length) goto exit_me; // not enough chars
|
||||
break;
|
||||
case 's':
|
||||
arg_str = va_arg(argp, char*);
|
||||
if (fmt1 == 0) length = 4095; // max string scan 4096
|
||||
else length = fmt1;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
*arg_str++ = ch;
|
||||
ch = vgetc(&save, src);
|
||||
if (ch == EOF || isspace(ch)) break; // ok, just finish string
|
||||
}
|
||||
*arg_str++ = '\0';
|
||||
break;
|
||||
case 'd': case 'i': case 'u':
|
||||
case 'o': case 'p': case 'x':
|
||||
i = try_parse_int(&digit, ch, src, &save, vgetc, vungetc);
|
||||
if (i < 0) goto exit_me;
|
||||
|
||||
if (flag_long == 0) { arg_int = va_arg(argp, int*); *arg_int = (int)digit; } else
|
||||
if (flag_long == 1) { arg_long = va_arg(argp, long*); *arg_long = (long)digit; } else
|
||||
if (flag_long == 2) { arg_longlong = va_arg(argp, long long*); *arg_longlong = digit; }
|
||||
break;
|
||||
case 'a': case 'A': case 'f': case 'F':
|
||||
case 'e': case 'E':
|
||||
case 'g': case 'G':
|
||||
i = try_parse_real(&real, ch, src, &save, vgetc, vungetc);
|
||||
if (i < 0) goto exit_me;
|
||||
|
||||
if (flag_long == 0) { arg_float = va_arg(argp, float*); *arg_float = (float)real; } else
|
||||
if (flag_long == 1) { arg_double = va_arg(argp, double*); *arg_double = (double)real; } else
|
||||
if (flag_long == 2) { arg_longdouble = va_arg(argp, long double*); *arg_longdouble = real; }
|
||||
break;
|
||||
}
|
||||
|
||||
fmt = fmtc + 1;
|
||||
nread++;
|
||||
}
|
||||
exit_me:
|
||||
if (point_to_n) *point_to_n = nread;
|
||||
return nread;
|
||||
}
|
@ -1,189 +1,39 @@
|
||||
#include <stdio.h>
|
||||
void skipspaces(FILE* file)
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int virtual_getc_file(void *sp, const void *obj)
|
||||
// get next chat from file obj, save point is ptr to string char ptr
|
||||
{
|
||||
int c;
|
||||
while(1)
|
||||
{
|
||||
c=fgetc(file);
|
||||
if (c!=' ' && c!='\r' && c!='\n')
|
||||
{
|
||||
ungetc(c,file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
FILE *f = (FILE *)obj;
|
||||
|
||||
return fgetc(f);
|
||||
}
|
||||
|
||||
int fscanf(FILE* file,const char* format, ...)
|
||||
void virtual_ungetc_file(void *sp, int c, const void *obj)
|
||||
// if can, one step back savepoint in s
|
||||
{
|
||||
int res;
|
||||
void* arg;
|
||||
int i;
|
||||
int c;
|
||||
int contflag;
|
||||
int longflag;
|
||||
int sign;
|
||||
long long number;
|
||||
long double rnumber;
|
||||
char* str;
|
||||
res=0;
|
||||
arg=&format;
|
||||
arg+=sizeof(const char*);
|
||||
while (*format!='\0')
|
||||
{
|
||||
if (*format!='%')
|
||||
{
|
||||
c=fgetc(file);
|
||||
if (c!=*format)
|
||||
{
|
||||
ungetc(c,file);
|
||||
return -1;
|
||||
}
|
||||
format++;
|
||||
continue;
|
||||
}
|
||||
contflag=1;
|
||||
longflag=0;
|
||||
while (*format && contflag)
|
||||
{
|
||||
switch(*format)
|
||||
{
|
||||
case '.':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
format++;
|
||||
continue;
|
||||
break;
|
||||
case 'l':
|
||||
if (longflag==0)
|
||||
longflag=1;
|
||||
else
|
||||
longflag=2;
|
||||
format++;
|
||||
break;
|
||||
case 'L':
|
||||
longflag=2;
|
||||
format++;
|
||||
break;
|
||||
case 'f':
|
||||
case 'd':
|
||||
case 'c':
|
||||
case 's':
|
||||
case '%':
|
||||
contflag=0;
|
||||
break;
|
||||
default:
|
||||
contflag=0;
|
||||
}
|
||||
}
|
||||
if (contflag)
|
||||
break;
|
||||
switch(*format)
|
||||
{
|
||||
case '%':
|
||||
c=fgetc(file);
|
||||
if (c!='%')
|
||||
{
|
||||
ungetc(c,file);
|
||||
return -1;
|
||||
}
|
||||
res--;
|
||||
break;
|
||||
case 'd':
|
||||
number=0;
|
||||
sign=1;
|
||||
skipspaces(file);
|
||||
c=fgetc(file);
|
||||
if (c=='-')
|
||||
{
|
||||
sign=-1;
|
||||
}else if (c!='+')
|
||||
ungetc(c,file);
|
||||
contflag=0;
|
||||
while(1)
|
||||
{
|
||||
c=fgetc(file);
|
||||
if (c>='0' && c<='9')
|
||||
{
|
||||
contflag++;
|
||||
number=number*10+(c-'0');
|
||||
}else
|
||||
break;
|
||||
}
|
||||
ungetc(c,file);
|
||||
if (!contflag)
|
||||
return res;
|
||||
if (longflag<=1)
|
||||
{
|
||||
*((int*)arg)=number;
|
||||
arg+=sizeof(int);
|
||||
}else
|
||||
{
|
||||
*((long long*)arg)=number;
|
||||
arg+=sizeof(long long);
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
c=fgetc(file);
|
||||
if (c==EOF)
|
||||
return res;
|
||||
*((char*)arg)=c;
|
||||
arg+=sizeof(char);
|
||||
break;
|
||||
case 's':
|
||||
skipspaces(file);
|
||||
contflag=0;
|
||||
str=*((char**)arg);
|
||||
arg+=sizeof(char*);
|
||||
while(1)
|
||||
{
|
||||
c=fgetc(file);
|
||||
if (c==EOF || c==' ' || c=='\n' || c=='\r')
|
||||
{
|
||||
ungetc(c,file);
|
||||
break;
|
||||
}
|
||||
*str=c;
|
||||
str++;
|
||||
contflag++;
|
||||
}
|
||||
if (!contflag)
|
||||
return res;
|
||||
break;
|
||||
case 'f':
|
||||
skipspaces(file);
|
||||
// TODO: read real numbers
|
||||
rnumber=0;
|
||||
switch (longflag)
|
||||
{
|
||||
case 0:
|
||||
*((float*)arg)=rnumber;
|
||||
arg+=sizeof(float);
|
||||
break;
|
||||
case 1:
|
||||
*((double*)arg)=rnumber;
|
||||
arg+=sizeof(double);
|
||||
break;
|
||||
case 2:
|
||||
*((long double*)arg)=rnumber;
|
||||
arg+=sizeof(long double);
|
||||
break;
|
||||
default:
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
format++;
|
||||
res++;
|
||||
}
|
||||
return res;
|
||||
FILE *f = (FILE *)obj;
|
||||
|
||||
if (f) ungetc(c, f);
|
||||
}
|
||||
|
||||
|
||||
int vfscanf ( FILE * stream, const char * format, va_list arg )
|
||||
{
|
||||
return format_scan(stream, format, arg, &virtual_getc_file, &virtual_ungetc_file);
|
||||
};
|
||||
|
||||
int fscanf ( FILE * stream, const char * format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
int n;
|
||||
va_start(arg, format);
|
||||
|
||||
n = vfscanf(stream, format, arg);
|
||||
|
||||
va_end(arg);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
|
66
programs/develop/ktcc/trunk/libc/stdio/scanf.c
Normal file
66
programs/develop/ktcc/trunk/libc/stdio/scanf.c
Normal file
@ -0,0 +1,66 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
char *__scanf_buffer = 0;
|
||||
|
||||
int virtual_getc_con(void *sp, const void *obj)
|
||||
// get next chat from string obj, save point is ptr to string char ptr
|
||||
{
|
||||
int ch;
|
||||
const char**spc= (const char**)sp;
|
||||
if (!spc) return EOF; // error
|
||||
|
||||
if (!*spc) *spc = __scanf_buffer; // first call, init savepoint
|
||||
|
||||
while (!**spc) // need to read more
|
||||
{
|
||||
if(!gets(__scanf_buffer)) return EOF;
|
||||
*spc = __scanf_buffer;
|
||||
strcat(__scanf_buffer,"\n"); // imitate delimiter
|
||||
}
|
||||
if (**spc == 26 || **spc == 3) // ^C ^Z end of scan, clear buffer
|
||||
{
|
||||
*spc = __scanf_buffer;
|
||||
*__scanf_buffer = 0;
|
||||
return EOF; // ^C ^Z
|
||||
}
|
||||
|
||||
ch = **spc; (*spc)++ ;
|
||||
|
||||
//printf("getc '%c'[%d];", ch, ch);
|
||||
return ch;
|
||||
}
|
||||
|
||||
void virtual_ungetc_con(void *sp, int c, const void *obj)
|
||||
// if can, one step back savepoint in s
|
||||
{
|
||||
const char**spc= (const char**)sp;
|
||||
|
||||
if (spc && *spc > __scanf_buffer) (*spc)--;
|
||||
//printf("Ungetc '%c'[%d];", c, c);
|
||||
}
|
||||
|
||||
|
||||
int vscanf ( const char * format, va_list arg )
|
||||
{
|
||||
return format_scan(NULL, format, arg, &virtual_getc_con, &virtual_ungetc_con);
|
||||
};
|
||||
|
||||
int kos_scanf ( const char * format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
int n;
|
||||
va_start(arg, format);
|
||||
|
||||
if(__scanf_buffer == NULL) __scanf_buffer = malloc(4096);
|
||||
if(__scanf_buffer == NULL) return -3;
|
||||
|
||||
*__scanf_buffer = 0;
|
||||
n = vscanf(format, arg);
|
||||
|
||||
va_end(arg);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
46
programs/develop/ktcc/trunk/libc/stdio/sscanf.c
Normal file
46
programs/develop/ktcc/trunk/libc/stdio/sscanf.c
Normal file
@ -0,0 +1,46 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
int virtual_getc_str(void *sp, const void *obj)
|
||||
// get next chat from string obj, save point is ptr to string char ptr
|
||||
{
|
||||
int ch;
|
||||
const char *s = (const char *)obj;
|
||||
const char**spc= (const char**)sp;
|
||||
if (!s || !spc) return EOF; // error
|
||||
|
||||
if (!*spc) *spc = s; // first call, init savepoint
|
||||
|
||||
if (!**spc) return EOF; // EOS
|
||||
|
||||
ch = **spc; (*spc)++ ;
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
void virtual_ungetc_str(void *sp, int c, const void *obj)
|
||||
// if can, one step back savepoint in s
|
||||
{
|
||||
const char *s = (const char *)obj;
|
||||
const char**spc= (const char**)sp;
|
||||
|
||||
if (s && spc && *spc > s) (*spc)--;
|
||||
}
|
||||
|
||||
int vsscanf ( const char * s, const char * format, va_list arg )
|
||||
{
|
||||
return format_scan(s, format, arg, &virtual_getc_str, &virtual_ungetc_str);
|
||||
};
|
||||
|
||||
int sscanf ( const char * s, const char * format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
int n;
|
||||
va_start(arg, format);
|
||||
|
||||
n = vsscanf(s, format, arg);
|
||||
|
||||
va_end(arg);
|
||||
return n;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user