summaryrefslogtreecommitdiff
path: root/libpsx/src/libc/scanf.c
diff options
context:
space:
mode:
authorXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
committerXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
commit7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch)
treec28d0748652ad4b4222309e46e6cfc82c0906220 /libpsx/src/libc/scanf.c
parenta2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff)
downloadpsxsdk-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.c425
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;
+}