diff --git a/libmaxsi/Makefile b/libmaxsi/Makefile
index 26327335..1c04a677 100644
--- a/libmaxsi/Makefile
+++ b/libmaxsi/Makefile
@@ -95,7 +95,12 @@ print.o \
read.o \
readdirents.o \
rmdir.o \
-scan.o \
+scanf.o \
+fscanf.o \
+sscanf.o \
+vscanf.o \
+vfscanf.o \
+vsscanf.o \
stat.o \
truncate.o \
umask.o \
diff --git a/libmaxsi/fscanf.cpp b/libmaxsi/fscanf.cpp
new file mode 100644
index 00000000..930d0e26
--- /dev/null
+++ b/libmaxsi/fscanf.cpp
@@ -0,0 +1,35 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of LibMaxsi.
+
+ LibMaxsi is free software: you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ LibMaxsi is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with LibMaxsi. If not, see .
+
+ fscanf.cpp
+ Input format conversion.
+
+*******************************************************************************/
+
+#include
+#include
+
+extern "C" int fscanf(FILE* fp, const char* format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ int ret = vfscanf(fp, format, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/libmaxsi/include/stdio.h b/libmaxsi/include/stdio.h
index 6af6d534..cf787a52 100644
--- a/libmaxsi/include/stdio.h
+++ b/libmaxsi/include/stdio.h
@@ -86,6 +86,8 @@ extern int fprintf(FILE* restrict stream, const char* restrict format, ...);
extern int fputc(int c, FILE* stream);
extern int fputs(const char* restrict s, FILE* restrict stream);
extern size_t fread(void* restrict ptr, size_t size, size_t nitems, FILE* restrict stream);
+extern FILE* freopen(const char* restrict filename, const char *restrict mode, FILE* restrict stream);
+extern int fscanf(FILE* restrict stream, const char* restrict format, ... );
extern int fseek(FILE* stream, long offset, int whence);
extern int fseeko(FILE* stream, off_t offset, int whence);
extern long ftell(FILE* stream);
@@ -101,29 +103,33 @@ extern int putc(int c, FILE* stream);
extern int putchar(int c);
extern int puts(const char* str);
extern int remove(const char* path);
+extern int rename(const char* oldname, const char* newname);
extern void rewind(FILE* stream);
extern int snprintf(char* restrict s, size_t n, const char* restrict format, ...);
+extern void setbuf(FILE* restrict stream, char* restrict buf);
extern char* sortix_gets(void);
extern int sortix_puts(const char* str);
extern int sprintf(char* restrict s, const char* restrict format, ...);
+extern int scanf(const char* restrict format, ...);
extern int sscanf(const char* restrict s, const char* restrict format, ...);
extern int ungetc(int c, FILE* stream);
extern int vfprintf(FILE* restrict stream, const char* restrict format, __gnuc_va_list ap);
+extern int vfscanf(FILE* restrict stream, const char* restrict format, __gnuc_va_list arg);
extern int vprintf(const char* restrict format, __gnuc_va_list ap);
+extern int vscanf(const char* restrict format, __gnuc_va_list arg);
extern int vsnprintf(char* restrict, size_t, const char* restrict, __gnuc_va_list);
extern int vsprintf(char* restrict s, const char* restrict format, __gnuc_va_list ap);
+extern int vsscanf(const char* restrict s, const char* restrict format, __gnuc_va_list arg);
/* TODO: These are not implemented in libmaxsi/sortix yet. */
#if defined(__SORTIX_SHOW_UNIMPLEMENTED)
extern char* ctermid(char* s);
extern FILE *fmemopen(void* restrict buf, size_t size, const char* restrict mode);
-extern FILE* freopen(const char* restrict filename, const char *restrict mode, FILE* restrict stream);
extern FILE* open_memstream(char** bufp, size_t* sizep);
extern FILE* popen(const char* command, const char* mode);
extern FILE* tmpfile(void);
extern int dprintf(int fildes, const char* restrict format, ...);
extern int fgetpos(FILE* restrict stream, fpos_t* restrict pos);
-extern int fscanf(FILE* restrict stream, const char* restrict format, ... );
extern int fsetpos(FILE* stream, const fpos_t* pos);
extern int ftrylockfile(FILE* file);
extern int getchar_unlocked(void);
@@ -131,17 +137,11 @@ extern int getc_unlocked(FILE* stream);
extern int pclose(FILE* steam);
extern int putchar_unlocked(int c);
extern int putc_unlocked(int c, FILE* steam);
-extern int rename(const char* oldname, const char* newname);
extern int renameat(int oldfd, const char* oldname, int newfd, const char* newname);
-extern int scanf(const char* restrict format, ...);
extern int setvbuf(FILE* restrict stream, char* restrict buf, int type, size_t size);
extern int vdprintf(int fildes, const char* restrict format, __gnuc_va_list ap);
-extern int vfscanf(FILE* restrict stream, const char* restrict format, __gnuc_va_list arg);
-extern int vscanf(const char* restrict format, __gnuc_va_list arg);
-extern int vsscanf(const char* restrict s, const char* restrict format, __gnuc_va_list arg);
extern void flockfile(FILE* file);
extern void funlockfile(FILE* file);
-extern void setbuf(FILE* restrict stream, char* restrict buf);
#if __POSIX_OBSOLETE <= 200801
extern char* tmpnam(char* s);
diff --git a/libmaxsi/scanf.cpp b/libmaxsi/scanf.cpp
new file mode 100644
index 00000000..82edf268
--- /dev/null
+++ b/libmaxsi/scanf.cpp
@@ -0,0 +1,35 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of LibMaxsi.
+
+ LibMaxsi is free software: you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ LibMaxsi is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with LibMaxsi. If not, see .
+
+ scanf.cpp
+ Input format conversion.
+
+*******************************************************************************/
+
+#include
+#include
+
+extern "C" int scanf(const char* format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ int ret = vscanf(format, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/libmaxsi/sscanf.cpp b/libmaxsi/sscanf.cpp
new file mode 100644
index 00000000..78f15477
--- /dev/null
+++ b/libmaxsi/sscanf.cpp
@@ -0,0 +1,35 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of LibMaxsi.
+
+ LibMaxsi is free software: you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ LibMaxsi is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with LibMaxsi. If not, see .
+
+ sscanf.cpp
+ Input format conversion.
+
+*******************************************************************************/
+
+#include
+#include
+
+extern "C" int sscanf(const char* str, const char* format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ int ret = vsscanf(str, format, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/libmaxsi/vfscanf.cpp b/libmaxsi/vfscanf.cpp
new file mode 100644
index 00000000..9f00d2c9
--- /dev/null
+++ b/libmaxsi/vfscanf.cpp
@@ -0,0 +1,317 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of LibMaxsi.
+
+ LibMaxsi is free software: you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ LibMaxsi is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with LibMaxsi. If not, see .
+
+ vfscanf.cpp
+ Input format conversion.
+
+*******************************************************************************/
+
+#define __STDC_LIMIT_MACROS
+#include
+#include
+#include
+#include
+#include
+#include
+
+enum scanmode
+{
+ MODE_INIT,
+ MODE_CONVSPEC,
+ MODE_SCANINT,
+ MODE_SCANINT_REAL,
+ MODE_SCANSTRING,
+ MODE_SCANSTRING_REAL,
+};
+
+enum scantype
+{
+ TYPE_SHORT,
+ TYPE_SHORTSHORT,
+ TYPE_INT,
+ TYPE_LONG,
+ TYPE_LONGLONG,
+ TYPE_SIZE,
+ TYPE_PTRDIFF,
+ TYPE_MAX,
+};
+
+static bool IsTypeModifier(char c)
+{
+ return c == 'h' || c == 'j' || c == 'l' || c == 'L' || c == 't' || c == 'z';
+}
+
+static int debase(char c, int base)
+{
+ if ( c == '0' )
+ return 0;
+ int ret = -1;
+ if ( '0' <= c && c <= '9' ) { ret = c - '0' + 0; }
+ if ( 'a' <= c && c <= 'f' ) { ret = c - 'a' + 10; }
+ if ( 'A' <= c && c <= 'F' ) { ret = c - 'A' + 10; }
+ if ( base <= ret )
+ return -1;
+ return ret;
+}
+
+extern "C" int vfscanf(FILE* fp, const char* origformat, va_list ap)
+{
+ union { const char* format; const unsigned char* formatuc; };
+ format = origformat;
+ int matcheditems = 0;
+ size_t fieldwidth;
+ bool escaped = false;
+ bool discard;
+ bool negint;
+ bool intunsigned;
+ bool leadingzero;
+ bool hasprefix;
+ bool string;
+ size_t intparsed;
+ uintmax_t intvalue;
+ int ic;
+ int base;
+ int cval;
+ const size_t UNDO_MAX = 4;
+ int undodata[UNDO_MAX];
+ size_t undoable = 0;
+ size_t strwritten;
+ char* strdest;
+ enum scantype scantype;
+ enum scanmode scanmode = MODE_INIT;
+ while ( true )
+ {
+ ic = fgetc(fp);
+ unsigned char uc = ic; char c = uc;
+ switch (scanmode)
+ {
+ case MODE_INIT:
+ if ( !*format )
+ goto break_loop;
+ if ( isspace(*formatuc) )
+ {
+ if ( isspace(ic) )
+ continue;
+ else
+ do format++;
+ while ( isspace(*formatuc) );
+ }
+ if ( *format == '%' && !escaped )
+ {
+ format++;
+ scanmode = MODE_CONVSPEC;
+ ungetc(ic, fp);
+ continue;
+ }
+ escaped = false;
+ if ( *format != c ) { ungetc(ic, fp); goto break_loop; }
+ format++;
+ break;
+ case MODE_CONVSPEC:
+ discard = false;
+ if ( *format == '*' ) { discard = true; format++; }
+ fieldwidth = 0;
+ while ( '0'<= *format && *format <= '9' )
+ fieldwidth = fieldwidth * 10 + *format++ - '0';
+ scantype = TYPE_INT;
+ while ( IsTypeModifier(*format) )
+ switch ( *format++ )
+ {
+ case 'h': scantype = scantype == TYPE_SHORT ? TYPE_SHORTSHORT
+ : TYPE_SHORT; break;
+ case 'j': scantype = TYPE_MAX; break;
+ case 'l': scantype = scantype == TYPE_LONG ? TYPE_LONGLONG
+ : TYPE_LONG; break;
+ case 'L': scantype = TYPE_LONGLONG; break;
+ case 't': scantype = TYPE_PTRDIFF; break;
+ case 'z': scantype = TYPE_SIZE; break;
+ }
+
+ switch ( char convc = *format++ )
+ {
+ case '%':
+ escaped = true;
+ default:
+ fprintf(stderr, "Warning: scanf does not support %c (%i)\n",
+ convc, convc);
+ fprintf(stderr, "Bailing out to prevent problems.\n");
+ errno = ENOTSUP;
+ return -1;
+ continue;
+ case 'd':
+ base = 10; scanmode = MODE_SCANINT; intunsigned = false; break;
+ case 'i':
+ base = 0; scanmode = MODE_SCANINT; intunsigned = false; break;
+ case 'o':
+ base = 0; scanmode = MODE_SCANINT; intunsigned = true; break;
+ case 'u':
+ base = 10; scanmode = MODE_SCANINT; intunsigned = true; break;
+ case 'x':
+ case 'X':
+ base = 16; scanmode = MODE_SCANINT; intunsigned = true; break;
+ case 'c':
+ string = false; scanmode = MODE_SCANSTRING; break;
+ case 's':
+ string = true; scanmode = MODE_SCANSTRING; break;
+ }
+ ungetc(ic, fp);
+ continue;
+ case MODE_SCANINT:
+ intparsed = 0;
+ intvalue = 0;
+ leadingzero = false;
+ negint = false;
+ hasprefix = false;
+ undoable = 0;
+ scanmode = MODE_SCANINT_REAL;
+ case MODE_SCANINT_REAL:
+ if ( fieldwidth )
+ {
+ fprintf(stderr, "Error: field width not supported for integers in scanf.\n");
+ errno = ENOTSUP;
+ return -1;
+ }
+ if ( !undoable && isspace(ic) )
+ continue;
+ if ( undoable < UNDO_MAX )
+ undodata[undoable++] = ic;
+ if ( c == '-' && !intunsigned && !negint )
+ {
+ negint = true;
+ continue;
+ }
+ if ( !intparsed && c == '0' && !hasprefix &&
+ (!base || base == 8 || base == 16) && !leadingzero )
+ leadingzero = true;
+ if ( intparsed == 1 && (c == 'x' || c == 'X') && !hasprefix &&
+ (!base || base == 16) && leadingzero )
+ {
+ base = 16;
+ leadingzero = false;
+ hasprefix = true;
+ intparsed = 0;
+ continue;
+ }
+ else if ( intparsed == 1 && '1' <= c && c <= '7' && !hasprefix &&
+ (!base || base == 8) && leadingzero )
+ {
+ base = 8;
+ hasprefix = true;
+ leadingzero = false;
+ }
+ else if ( !intparsed && '0' <= c && c <= '9' && !hasprefix &&
+ (!base || base == 10) && !leadingzero )
+ {
+ base = 10;
+ leadingzero = false;
+ hasprefix = true;
+ }
+ cval = debase(c, base);
+ if ( cval < 0 )
+ {
+ if ( !intparsed )
+ {
+ while ( undoable )
+ ungetc(undodata[--undoable], fp);
+ goto break_loop;
+ }
+ scanmode = MODE_INIT;
+ undoable = 0;
+ ungetc(ic, fp);
+ if ( discard ) { discard = false; continue; }
+ uintmax_t uintmaxval = intvalue;
+ // TODO: Possible truncation of INTMAX_MIN!
+ intmax_t intmaxval = uintmaxval;
+ if ( negint ) intmaxval = -intmaxval;
+ bool un = intunsigned;
+ switch ( scantype )
+ {
+ case TYPE_SHORTSHORT:
+ if ( un ) *va_arg(ap, unsigned char*) = uintmaxval;
+ else *va_arg(ap, signed char*) = intmaxval;
+ break;
+ case TYPE_SHORT:
+ if ( un ) *va_arg(ap, unsigned short*) = uintmaxval;
+ else *va_arg(ap, signed short*) = intmaxval;
+ break;
+ case TYPE_INT:
+ if ( un ) *va_arg(ap, unsigned int*) = uintmaxval;
+ else *va_arg(ap, signed int*) = intmaxval;
+ break;
+ case TYPE_LONG:
+ if ( un ) *va_arg(ap, unsigned long*) = uintmaxval;
+ else *va_arg(ap, signed long*) = intmaxval;
+ break;
+ case TYPE_LONGLONG:
+ if ( un ) *va_arg(ap, unsigned long long*) = uintmaxval;
+ else *va_arg(ap, signed long long*) = intmaxval;
+ break;
+ case TYPE_PTRDIFF:
+ *va_arg(ap, ptrdiff_t*) = intmaxval;
+ break;
+ case TYPE_SIZE:
+ if ( un ) *va_arg(ap, size_t*) = uintmaxval;
+ else *va_arg(ap, ssize_t*) = intmaxval;
+ break;
+ case TYPE_MAX:
+ if ( un ) *va_arg(ap, uintmax_t*) = uintmaxval;
+ else *va_arg(ap, intmax_t*) = intmaxval;
+ break;
+ }
+ matcheditems++;
+ continue;
+ }
+ intvalue = intvalue * (uintmax_t) base + (uintmax_t) cval;
+ intparsed++;
+ continue;
+ case MODE_SCANSTRING:
+ if ( !fieldwidth )
+ fieldwidth = string ? SIZE_MAX : 1;
+ scanmode = MODE_SCANSTRING_REAL;
+ strwritten = 0;
+ strdest = discard ? NULL : va_arg(ap, char*);
+ case MODE_SCANSTRING_REAL:
+ if ( string && !strwritten && isspace(ic) )
+ continue;
+ if ( string && strwritten &&
+ (ic == EOF || isspace(ic) || strwritten == fieldwidth) )
+ {
+ ungetc(ic, fp);
+ if ( !discard )
+ strdest[strwritten] = '\0';
+ matcheditems++;
+ scanmode = MODE_INIT;
+ continue;
+ }
+ if ( !string && strwritten == fieldwidth )
+ {
+ ungetc(ic, fp);
+ scanmode = MODE_INIT;
+ continue;
+ }
+ if ( ic == EOF )
+ goto break_loop;
+ if ( !discard )
+ strdest[strwritten++] = c;
+ continue;
+ }
+ }
+break_loop:
+ return matcheditems;
+}
diff --git a/libmaxsi/vscanf.cpp b/libmaxsi/vscanf.cpp
new file mode 100644
index 00000000..34fb9fdb
--- /dev/null
+++ b/libmaxsi/vscanf.cpp
@@ -0,0 +1,31 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of LibMaxsi.
+
+ LibMaxsi is free software: you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ LibMaxsi is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with LibMaxsi. If not, see .
+
+ vscanf.cpp
+ Input format conversion.
+
+*******************************************************************************/
+
+#include
+#include
+
+extern "C" int vscanf(const char* format, va_list ap)
+{
+ return vfscanf(stdin, format, ap);
+}
diff --git a/libmaxsi/scan.cpp b/libmaxsi/vsscanf.cpp
similarity index 53%
rename from libmaxsi/scan.cpp
rename to libmaxsi/vsscanf.cpp
index 6d4076f7..9d619996 100644
--- a/libmaxsi/scan.cpp
+++ b/libmaxsi/vsscanf.cpp
@@ -1,6 +1,6 @@
/*******************************************************************************
- Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
This file is part of LibMaxsi.
@@ -17,42 +17,31 @@
You should have received a copy of the GNU Lesser General Public License
along with LibMaxsi. If not, see .
- scan.cpp
- The scanf family of functions.
+ vsscanf.cpp
+ Input format conversion.
*******************************************************************************/
-#include
-#include
-#include
+#include
#include
-#include
+#include
#include
+#include
-namespace Maxsi {
-
-
-// TODO: This is an ugly hack to help build binutils.
-#warning Ugly sscanf hack to help build binutils
-extern "C" int sscanf(const char* s, const char* format, ...)
+extern "C" int vsscanf(const char* str, const char* format, va_list ap)
{
- if ( strcmp(format, "%x") != 0 )
- {
- fprintf(stderr, "sscanf hack doesn't implement: '%s'\n", format);
- abort();
- }
-
- va_list list;
- va_start(list, format);
- unsigned* dec = va_arg(list, unsigned*);
- *dec = strtol(s, NULL, 16);
- return strlen(s);
+ const char* filename = "/ugly-vsscanf-hack";
+ FILE* fp = fopen(filename, "w+");
+ if ( !fp )
+ return -1;
+ int ret = -1;
+ size_t len = strlen(str);
+ if ( fwrite(str, sizeof(char), len, fp) == len )
+ if ( fseek(fp, 0, SEEK_SET) == 0 )
+ ret = vfscanf(fp, format, ap);
+ int savederrno = errno;
+ fclose(fp);
+ unlink(filename);
+ errno = savederrno;
+ return ret;
}
-
-extern "C" int fscanf(FILE* /*fp*/, const char* /*format*/, ...)
-{
- fprintf(stderr, "fscanf(3) is not implemented\n");
- abort();
-}
-
-} // namespace Maxsi