diff options
| author | Xavi Del Campo <xavi.dcr@tutanota.com> | 2020-01-31 10:32:23 +0100 |
|---|---|---|
| committer | Xavi Del Campo <xavi.dcr@tutanota.com> | 2020-01-31 10:32:23 +0100 |
| commit | 7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch) | |
| tree | c28d0748652ad4b4222309e46e6cfc82c0906220 /libpsx/src/libc/scanf.c | |
| parent | a2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff) | |
| download | psxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz | |
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'libpsx/src/libc/scanf.c')
| -rw-r--r-- | libpsx/src/libc/scanf.c | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/libpsx/src/libc/scanf.c b/libpsx/src/libc/scanf.c new file mode 100644 index 0000000..d419030 --- /dev/null +++ b/libpsx/src/libc/scanf.c @@ -0,0 +1,425 @@ +// vsscanf +// Programmed by Giuseppe Gatta, 2011 + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +char libc_vsscanf_buf[512]; +char libc_vsscanf_allow[256]; + +enum +{ + elem_skip_space = 1, +}; + +int libc_vsscanf_get_element(char *dst, const char *src, int flag, int s) +{ + int i; + const char *osrc = src; + + if(flag & elem_skip_space) + { + while(*src == ' ') + src++; + } + + for(i=0;i<s;i++) + { + if((flag & elem_skip_space) && *src == ' ') + break; + + if(*src != 0) + *(dst++) = *(src++); + else + break; + } + + *dst = 0; + + return src - osrc; +} + +enum +{ + scanf_s_char, scanf_s_short, scanf_s_int, + scanf_s_long, + scanf_s_long_long +}; + +int vsscanf(const char *str, const char *format, va_list ap) +{ + int fp = 0; + int sp = 0; + int conv = 0; + int sz = scanf_s_int; // size for numbers defaults to 32-bit + int i,x,y,z;// h; + int suppress = 0; +// int neg = 0; + int fsz = 512; + int def_fsz = 1; + int exspace = 0; +// int alt = 0; + int r = 0; + int exit_loop=0; + char *ep; + long long buf; + double fbuf; + + + while(format[fp] && str[sp] && !exit_loop) + { + if(conv) + { + switch(format[fp]) + { + case '%': // Percent, assignment does not occur + conv = 0; + break; + + case 'h': // Halve size + sz--; + break; + + case 'l': // Double size + sz++; + break; + + case '*': // Suppress + suppress = 1; + break; + + case ' ': // Explicit space + exspace = 1; + break; + + case '#': // Alternate format + //alt = 1; + break; + + case '0' ... '9': // '0' ... '9' is a GNU C extension! + if(def_fsz) + { + def_fsz = 0; + fsz = 0; + } + + fsz *= 10; + fsz+=format[fp]-'0'; + + if(fsz > 512) + fsz = 512; // 512 is the maximum. + break; + + case '@': // Binary. Non-standard extension + libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz); + buf = strtoll(libc_vsscanf_buf, &ep, 2); + sp += ep - libc_vsscanf_buf; + + if(!suppress) + { + switch(sz) + { + case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf;break; + case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break; + case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break; + case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break; + case scanf_s_long_long: *(va_arg(ap, long long*)) = buf; break; + } + r++; + } + + conv = 0; + break; + + case 'D': + sz++; + case 'd': // Decimal + case 'u': + libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz); + buf = strtoll(libc_vsscanf_buf, &ep, 10); + sp += ep - libc_vsscanf_buf; + + if(!suppress) + { + switch(sz) + { + case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf;break; + case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break; + case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break; + case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break; + case scanf_s_long_long: *(va_arg(ap, long long*)) = buf; break; + } + r++; + } + + conv = 0; + break; + + case 's': // String + sp += libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz); + + if(!suppress) + { + strcpy(va_arg(ap, char*), libc_vsscanf_buf); + r++; + } + + conv = 0; + break; + + case 'c': + if(def_fsz) + fsz = 1; + + sp += (i = libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], (exspace ? elem_skip_space : 0), fsz)); + if(!suppress) + { + memcpy(va_arg(ap, char*), libc_vsscanf_buf, (fsz>i)?i:fsz); + r++; + } + break; + + case 'n': + if(!suppress) + { + *(va_arg(ap, int*)) = sp; + r++; + } + break; + + case 'p': + case 'x': + case 'X': + libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz); + buf = strtoll(libc_vsscanf_buf, &ep, 16); + sp += ep - libc_vsscanf_buf; + + if(!suppress) + { + switch(sz) + { + case scanf_s_char: *(va_arg(ap, unsigned char*)) = (unsigned char)buf; break; + case scanf_s_short: *(va_arg(ap, unsigned short*)) = (unsigned short)buf; break; + case scanf_s_int: *(va_arg(ap, unsigned int*)) = (unsigned int)buf; break; + case scanf_s_long: *(va_arg(ap, unsigned long*)) = (unsigned long)buf; break; + case scanf_s_long_long: *(va_arg(ap, unsigned long long*)) = (unsigned long long)buf; break; + } + r++; + } + + conv = 0; + break; + + case 'O': + sz++; + case 'o': // Octal integer + libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz); + buf = strtoll(libc_vsscanf_buf, &ep, 8); + sp += ep - libc_vsscanf_buf; + + if(!suppress) + { + switch(sz) + { + case scanf_s_char: *(va_arg(ap, unsigned char*)) = (unsigned char)buf;break; + case scanf_s_short: *(va_arg(ap, unsigned short*)) = (unsigned short)buf; break; + case scanf_s_int: *(va_arg(ap, unsigned int*)) = (unsigned int)buf;break; + case scanf_s_long: *(va_arg(ap, unsigned long*)) = (unsigned long)buf; break; + case scanf_s_long_long: *(va_arg(ap, unsigned long long*)) = (unsigned long long)buf;break; + } + r++; + } + + conv = 0; + break; + + case 'i': + libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz); + + if(libc_vsscanf_buf[0] == '0') + { + if(libc_vsscanf_buf[1] == 'x' || libc_vsscanf_buf[1] == 'X') + i = 16; + else + i = 8; + } + else + i = 10; + + buf = strtoll(libc_vsscanf_buf, &ep, i); + sp += ep - libc_vsscanf_buf; + + if(!suppress) + { + switch(sz) + { + case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf; break; + case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break; + case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break; + case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break; + case scanf_s_long_long: *(va_arg(ap, long long*)) = (long long)buf; break; + } + r++; + } + + conv = 0; + break; + + case '[': + i=0; + x=0; // Exclusion? + //h=0; // Hyphen? + + fp++; + i++; + + while(format[fp]) + { + if(format[fp] == '^' && i==1) + { + memset(libc_vsscanf_allow, 1, 256); + x = 1; + fp++; i++; continue; + } + + if(x) + { + if(format[fp] == ']' && i>=3) + break; + } + else + { + if(format[fp] == ']' && i>=2) + break; + } + + if(format[fp] == '-') + { + if(format[fp+1] != ']') + y = 1; + else + libc_vsscanf_allow['-'] = x^1; + } + else + { + if(y == 1) + { + if(format[fp] < format[fp-2]) + libc_vsscanf_allow[(unsigned char)format[fp]] = x^1; + else + for(z = format[fp-2]; z <= format[fp]; z++) + libc_vsscanf_allow[z] = x^1; + + y = 0; + + //printf("%s all chars from %c to %c\n", x?"Excluding":"Including",format[fp-2], format[fp]); + } + else + libc_vsscanf_allow[(unsigned char)format[fp]] = x^1; + } + + fp++; + i++; + } + +// Now as we know what our character set is, let's get data from the string + /* puts("Character set:"); + + for(y=0;y<16;y++) + { + for(x=0;x<16;x++) + if(libc_vsscanf_allow[(y*16) + x]) + putchar((y*16)+x); + else + putchar('*'); + + putchar('\n'); + } + */ + i = 0; + + while(libc_vsscanf_allow[(unsigned char)str[sp]] && i<512) + libc_vsscanf_buf[i++] = str[sp++]; + + libc_vsscanf_buf[i] = 0; + + if(!suppress) + { + strcpy(va_arg(ap, char*), libc_vsscanf_buf); + r++; + } + break; + + case 'f': // Floating point number + libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz); + fbuf = strtod(libc_vsscanf_buf, &ep); + sp += ep - libc_vsscanf_buf; + + if(!suppress) + { + switch(sz) + { + case scanf_s_char: + case scanf_s_short: + case scanf_s_int: + *(va_arg(ap, float*)) = (float)fbuf; + break; + + case scanf_s_long: + case scanf_s_long_long: + *(va_arg(ap, double*)) = fbuf; + break; + } + r++; + } + + conv = 0; + break; + + } + } + else + { + if(format[fp] == '%') + { + // conv = 1; + // neg = 0; + suppress = 0; + sz = scanf_s_int; + fsz = 512; + def_fsz = 1; + exspace = 0; + // alt = 0; + bzero(libc_vsscanf_allow, 256); + //chset = 0; + } + else if(format[fp] != ' ') + { + if(format[fp] != str[sp]) + exit_loop=1; + + sp++; + } + + } + + fp++; + } + + return r; +} + +int sscanf(const char *str, const char *fmt, ...) +{ + int r; + va_list ap; + + va_start(ap, fmt); + r = vsscanf(str, fmt, ap); + + va_end(ap); + return r; +} |
