aboutsummaryrefslogtreecommitdiffstats
path: root/com32/lib
diff options
context:
space:
mode:
Diffstat (limited to 'com32/lib')
-rw-r--r--com32/lib/MCONFIG57
-rw-r--r--com32/lib/Makefile102
-rw-r--r--com32/lib/abort.c19
-rw-r--r--com32/lib/atexit.c10
-rw-r--r--com32/lib/atexit.h17
-rw-r--r--com32/lib/atoi.c3
-rw-r--r--com32/lib/atol.c3
-rw-r--r--com32/lib/atoll.c3
-rw-r--r--com32/lib/atox.c14
-rw-r--r--com32/lib/calloc.c21
-rw-r--r--com32/lib/creat.c12
-rw-r--r--com32/lib/ctypes.c284
-rw-r--r--com32/lib/errno.c7
-rw-r--r--com32/lib/exit.c0
-rw-r--r--com32/lib/fgetc.c20
-rw-r--r--com32/lib/fgets.c33
-rw-r--r--com32/lib/fopen.c46
-rw-r--r--com32/lib/fprintf.c19
-rw-r--r--com32/lib/fputc.c14
-rw-r--r--com32/lib/fputs.c15
-rw-r--r--com32/lib/fread.c35
-rw-r--r--com32/lib/fread2.c13
-rw-r--r--com32/lib/free.c78
-rw-r--r--com32/lib/fwrite.c35
-rw-r--r--com32/lib/fwrite2.c13
-rw-r--r--com32/lib/getopt.c74
-rw-r--r--com32/lib/init.h15
-rw-r--r--com32/lib/lrand48.c42
-rw-r--r--com32/lib/malloc.c120
-rw-r--r--com32/lib/memccpy.c23
-rw-r--r--com32/lib/memchr.c18
-rw-r--r--com32/lib/memcmp.c19
-rw-r--r--com32/lib/memcpy.c29
-rw-r--r--com32/lib/memmem.c44
-rw-r--r--com32/lib/memmove.c34
-rw-r--r--com32/lib/memset.c30
-rw-r--r--com32/lib/memswap.c23
-rw-r--r--com32/lib/onexit.c39
-rw-r--r--com32/lib/perror.c12
-rw-r--r--com32/lib/printf.c19
-rw-r--r--com32/lib/puts.c13
-rw-r--r--com32/lib/qsort.c42
-rw-r--r--com32/lib/realloc.c49
-rw-r--r--com32/lib/seed48.c19
-rw-r--r--com32/lib/setjmp.S58
-rw-r--r--com32/lib/snprintf.c16
-rw-r--r--com32/lib/sprintf.c18
-rw-r--r--com32/lib/srand48.c16
-rw-r--r--com32/lib/sscanf.c17
-rw-r--r--com32/lib/stack.c4
-rw-r--r--com32/lib/strcasecmp.c23
-rw-r--r--com32/lib/strcat.c11
-rw-r--r--com32/lib/strchr.c16
-rw-r--r--com32/lib/strcmp.c20
-rw-r--r--com32/lib/strcpy.c20
-rw-r--r--com32/lib/strdup.c17
-rw-r--r--com32/lib/strerror.c24
-rw-r--r--com32/lib/strlen.c14
-rw-r--r--com32/lib/strncasecmp.c23
-rw-r--r--com32/lib/strncat.c11
-rw-r--r--com32/lib/strncmp.c20
-rw-r--r--com32/lib/strncpy.c22
-rw-r--r--com32/lib/strndup.c17
-rw-r--r--com32/lib/strntoimax.c13
-rw-r--r--com32/lib/strntoumax.c75
-rw-r--r--com32/lib/strrchr.c18
-rw-r--r--com32/lib/strsep.c21
-rw-r--r--com32/lib/strspn.c67
-rw-r--r--com32/lib/strstr.c10
-rw-r--r--com32/lib/strtoimax.c3
-rw-r--r--com32/lib/strtok.c16
-rw-r--r--com32/lib/strtol.c3
-rw-r--r--com32/lib/strtoll.c3
-rw-r--r--com32/lib/strtoul.c3
-rw-r--r--com32/lib/strtoull.c3
-rw-r--r--com32/lib/strtoumax.c3
-rw-r--r--com32/lib/strtox.c13
-rw-r--r--com32/lib/sys/close.c57
-rw-r--r--com32/lib/sys/entry.S83
-rw-r--r--com32/lib/sys/exit.S27
-rw-r--r--com32/lib/sys/file.h69
-rw-r--r--com32/lib/sys/fileinfo.c3
-rw-r--r--com32/lib/sys/open.c79
-rw-r--r--com32/lib/sys/read.c92
-rw-r--r--com32/lib/sys/write.c58
-rw-r--r--com32/lib/vfprintf.c26
-rw-r--r--com32/lib/vprintf.c11
-rw-r--r--com32/lib/vsnprintf.c433
-rw-r--r--com32/lib/vsprintf.c11
-rw-r--r--com32/lib/vsscanf.c365
90 files changed, 3469 insertions, 0 deletions
diff --git a/com32/lib/MCONFIG b/com32/lib/MCONFIG
new file mode 100644
index 00000000..06136641
--- /dev/null
+++ b/com32/lib/MCONFIG
@@ -0,0 +1,57 @@
+CC = gcc
+LD = ld
+INCLUDE = -I.
+AR = ar
+RANLIB = ranlib
+NM = nm
+PERL = perl
+STRIP = strip --strip-all -R .comment -R .note
+OBJCOPY = objcopy
+
+REQFLAGS = -m32 -I. -I./sys -I../include
+OPTFLAGS = -Os -march=i386 -falign-functions=0 -falign-jumps=0 -falign-labels=0
+WARNFLAGS = -W -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Winline
+
+CFLAGS = -Wp,-MT,$@,-MD,$(dir $@).$(notdir $@).d $(OPTFLAGS) \
+ $(REQFLAGS) $(WARNFLAGS)
+LDFLAGS = -m elf32_i386
+
+.SUFFIXES: .c .o .a .so .lo .i .S .s .ls .ss .lss
+
+% : %.c # Cancel default rule
+
+% : %.S
+
+.c.o:
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+.c.i:
+ $(CC) $(CFLAGS) -E -o $@ $<
+
+.c.s:
+ $(CC) $(CFLAGS) -S -o $@ $<
+
+.S.o:
+ $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $<
+
+.S.s:
+ $(CC) $(CFLAGS) -D__ASSEMBLY__ -E -o $@ $<
+
+.S.lo:
+ $(CC) $(CFLAGS) $(SOFLAGS) -D__ASSEMBLY__ -c -o $@ $<
+
+.S.ls:
+ $(CC) $(CFLAGS) $(SOFLAGS) -D__ASSEMBLY__ -E -o $@ $<
+
+.s.o:
+ $(CC) $(CFLAGS) -x assembler -c -o $@ $<
+
+.ls.lo:
+ $(CC) $(CFLAGS) $(SOFLAGS) -x assembler -c -o $@ $<
+
+.c.lo:
+ $(CC) $(CFLAGS) $(SOFLAGS) -c -o $@ $<
+
+.c.ls:
+ $(CC) $(CFLAGS) $(SOFLAGS) -S -o $@ $<
+
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
new file mode 100644
index 00000000..6b5ab015
--- /dev/null
+++ b/com32/lib/Makefile
@@ -0,0 +1,102 @@
+# Include configuration rules
+include MCONFIG
+
+LIBOBJS = \
+ abort.o \
+ atexit.o \
+ atoi.o \
+ atol.o \
+ atoll.o \
+ calloc.o \
+ creat.o \
+ ctypes.o \
+ errno.o \
+ fgetc.o \
+ fgets.o \
+ fopen.o \
+ fprintf.o \
+ fputc.o \
+ fputs.o \
+ fread2.o \
+ fread.o \
+ free.o \
+ fwrite2.o \
+ fwrite.o \
+ getopt.o \
+ lrand48.o \
+ malloc.o \
+ memccpy.o \
+ memchr.o \
+ memcmp.o \
+ memcpy.o \
+ memmem.o \
+ memmove.o \
+ memset.o \
+ memswap.o \
+ onexit.o \
+ perror.o \
+ printf.o \
+ puts.o \
+ qsort.o \
+ realloc.o \
+ seed48.o \
+ snprintf.o \
+ sprintf.o \
+ srand48.o \
+ sscanf.o \
+ stack.o \
+ strcasecmp.o \
+ strcat.o \
+ strchr.o \
+ strcmp.o \
+ strcpy.o \
+ strdup.o \
+ strerror.o \
+ strlen.o \
+ strncasecmp.o \
+ strncat.o \
+ strncmp.o \
+ strncpy.o \
+ strndup.o \
+ strntoimax.o \
+ strntoumax.o \
+ strrchr.o \
+ strsep.o \
+ strspn.o \
+ strstr.o \
+ strtoimax.o \
+ strtok.o \
+ strtol.o \
+ strtoll.o \
+ strtoul.o \
+ strtoull.o \
+ strtoumax.o \
+ vfprintf.o \
+ vprintf.o \
+ vsnprintf.o \
+ vsprintf.o \
+ vsscanf.o \
+ sys/entry.o sys/exit.o \
+ sys/open.o \
+ sys/fileinfo.o \
+ sys/close.o \
+ sys/read.o \
+ sys/write.o
+
+all: libcom32.a
+
+libcom32.a : $(LIBOBJS)
+ rm -f $@
+ $(AR) cq $@ $^
+ $(RANLIB) $@
+
+tidy:
+ rm -f *.o .*.d */*.o */.*.d
+
+clean: tidy
+ rm -f *.a
+
+spotless: clean
+ rm -f *~ \#* */*~ */\#*
+
+-include .*.d
diff --git a/com32/lib/abort.c b/com32/lib/abort.c
new file mode 100644
index 00000000..9280d986
--- /dev/null
+++ b/com32/lib/abort.c
@@ -0,0 +1,19 @@
+/*
+ * abort.c
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+void abort(void)
+{
+ sigset_t set;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGABRT);
+ sigprocmask(SIG_UNBLOCK, &set, NULL);
+ raise(SIGABRT);
+ _exit(255); /* raise() should have killed us */
+}
+
diff --git a/com32/lib/atexit.c b/com32/lib/atexit.c
new file mode 100644
index 00000000..078dd8b2
--- /dev/null
+++ b/com32/lib/atexit.c
@@ -0,0 +1,10 @@
+/*
+ * atexit.c
+ */
+
+#include <stdlib.h>
+
+int atexit(void (*fctn)(void))
+{
+ return on_exit((void (*)(int, void *))fctn, NULL);
+}
diff --git a/com32/lib/atexit.h b/com32/lib/atexit.h
new file mode 100644
index 00000000..792141de
--- /dev/null
+++ b/com32/lib/atexit.h
@@ -0,0 +1,17 @@
+/*
+ * atexit.h
+ *
+ * atexit()/on_exit() internal definitions
+ */
+
+#ifndef ATEXIT_H
+#define ATEXIT_H
+
+struct atexit {
+ void (*fctn)(int, void *);
+ void *arg; /* on_exit() parameter */
+ struct atexit *next;
+};
+
+#endif /* ATEXIT_H */
+
diff --git a/com32/lib/atoi.c b/com32/lib/atoi.c
new file mode 100644
index 00000000..a6ec0bf7
--- /dev/null
+++ b/com32/lib/atoi.c
@@ -0,0 +1,3 @@
+#define TYPE int
+#define NAME atoi
+#include "atox.c"
diff --git a/com32/lib/atol.c b/com32/lib/atol.c
new file mode 100644
index 00000000..e65484e7
--- /dev/null
+++ b/com32/lib/atol.c
@@ -0,0 +1,3 @@
+#define TYPE long
+#define NAME atol
+#include "atox.c"
diff --git a/com32/lib/atoll.c b/com32/lib/atoll.c
new file mode 100644
index 00000000..25df79e1
--- /dev/null
+++ b/com32/lib/atoll.c
@@ -0,0 +1,3 @@
+#define TYPE long long
+#define NAME atoll
+#include "atox.c"
diff --git a/com32/lib/atox.c b/com32/lib/atox.c
new file mode 100644
index 00000000..56f8d93b
--- /dev/null
+++ b/com32/lib/atox.c
@@ -0,0 +1,14 @@
+/*
+ * atox.c
+ *
+ * atoi(), atol(), atoll()
+ */
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+TYPE NAME (const char *nptr)
+{
+ return (TYPE) strntoumax(nptr, (char **)NULL, 10, ~(size_t)0);
+}
diff --git a/com32/lib/calloc.c b/com32/lib/calloc.c
new file mode 100644
index 00000000..228a1b70
--- /dev/null
+++ b/com32/lib/calloc.c
@@ -0,0 +1,21 @@
+/*
+ * calloc.c
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+/* FIXME: This should look for multiplication overflow */
+
+void *calloc(size_t nmemb, size_t size)
+{
+ void *ptr;
+
+ size *= nmemb;
+ ptr = malloc(size);
+ if ( ptr )
+ memset(ptr, 0, size);
+
+ return ptr;
+}
+
diff --git a/com32/lib/creat.c b/com32/lib/creat.c
new file mode 100644
index 00000000..9bd22172
--- /dev/null
+++ b/com32/lib/creat.c
@@ -0,0 +1,12 @@
+/*
+ * creat.c
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int creat(const char *pathname, mode_t mode)
+{
+ return open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode);
+}
diff --git a/com32/lib/ctypes.c b/com32/lib/ctypes.c
new file mode 100644
index 00000000..acfa05ab
--- /dev/null
+++ b/com32/lib/ctypes.c
@@ -0,0 +1,284 @@
+/*
+ * ctypes.c
+ *
+ * This is the array that defines <ctype.h> classes.
+ * This assumes ISO 8859-1.
+ */
+
+#include <ctype.h>
+
+const unsigned char __ctypes[257] = {
+ 0, /* EOF */
+
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl|__ctype_space, /* BS */
+ __ctype_cntrl|__ctype_space, /* TAB */
+ __ctype_cntrl|__ctype_space, /* LF */
+ __ctype_cntrl|__ctype_space, /* VT */
+ __ctype_cntrl|__ctype_space, /* FF */
+ __ctype_cntrl|__ctype_space, /* CR */
+ __ctype_cntrl, /* control character */
+
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+
+ __ctype_print|__ctype_space, /* space */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+
+ __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */
+ __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */
+ __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */
+ __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */
+ __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */
+ __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */
+ __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */
+ __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */
+ __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */
+ __ctype_print|__ctype_digit|__ctype_xdigit, /* digit */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_upper|__ctype_xdigit, /* A-F */
+ __ctype_print|__ctype_upper|__ctype_xdigit, /* A-F */
+ __ctype_print|__ctype_upper|__ctype_xdigit, /* A-F */
+ __ctype_print|__ctype_upper|__ctype_xdigit, /* A-F */
+ __ctype_print|__ctype_upper|__ctype_xdigit, /* A-F */
+ __ctype_print|__ctype_upper|__ctype_xdigit, /* A-F */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_upper, /* G-Z */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_lower|__ctype_xdigit, /* a-f */
+ __ctype_print|__ctype_lower|__ctype_xdigit, /* a-f */
+ __ctype_print|__ctype_lower|__ctype_xdigit, /* a-f */
+ __ctype_print|__ctype_lower|__ctype_xdigit, /* a-f */
+ __ctype_print|__ctype_lower|__ctype_xdigit, /* a-f */
+ __ctype_print|__ctype_lower|__ctype_xdigit, /* a-f */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_lower, /* g-z */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_cntrl, /* control character */
+
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+
+ __ctype_print|__ctype_space, /* NBSP */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_punct, /* punctuation */
+
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_upper, /* upper accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_punct, /* punctuation */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+ __ctype_print|__ctype_lower, /* lower accented */
+};
diff --git a/com32/lib/errno.c b/com32/lib/errno.c
new file mode 100644
index 00000000..f280e309
--- /dev/null
+++ b/com32/lib/errno.c
@@ -0,0 +1,7 @@
+/*
+ * errno.c
+ *
+ */
+#include <errno.h>
+
+int errno;
diff --git a/com32/lib/exit.c b/com32/lib/exit.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/com32/lib/exit.c
diff --git a/com32/lib/fgetc.c b/com32/lib/fgetc.c
new file mode 100644
index 00000000..83eee16f
--- /dev/null
+++ b/com32/lib/fgetc.c
@@ -0,0 +1,20 @@
+/*
+ * fgetc.c
+ *
+ * Extremely slow fgetc implementation, using _fread(). If people
+ * actually need character-oriented input to be fast, we may actually
+ * have to implement buffering. Sigh.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+int fgetc(FILE *f)
+{
+ unsigned char ch;
+
+ return (_fread(&ch, 1, f) == 1) ? (int)ch : EOF;
+}
+
diff --git a/com32/lib/fgets.c b/com32/lib/fgets.c
new file mode 100644
index 00000000..88a145a6
--- /dev/null
+++ b/com32/lib/fgets.c
@@ -0,0 +1,33 @@
+/*
+ * fgets.c
+ *
+ * This will be very slow due to the implementation of getc(),
+ * but we can't afford to drain characters we don't need from
+ * the input.
+ */
+
+#include <stdio.h>
+
+char *fgets(char *s, int n, FILE *f)
+{
+ int ch;
+ char *p = s;
+
+ while ( n > 1 ) {
+ ch = getc(f);
+ if ( ch == EOF ) {
+ *p = '\0';
+ return NULL;
+ }
+ *p++ = ch;
+ if ( ch == '\n' )
+ break;
+ }
+ if ( n )
+ *p = '\0';
+
+ return s;
+}
+
+
+
diff --git a/com32/lib/fopen.c b/com32/lib/fopen.c
new file mode 100644
index 00000000..5c841848
--- /dev/null
+++ b/com32/lib/fopen.c
@@ -0,0 +1,46 @@
+/*
+ * fopen.c
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/* This depends on O_RDONLY == 0, O_WRONLY == 1, O_RDWR == 2 */
+
+
+FILE *fopen(const char *file, const char *mode)
+{
+ int flags = O_RDONLY;
+ int plus = 0;
+ int fd;
+
+ while ( *mode ) {
+ switch ( *mode ) {
+ case 'r':
+ flags = O_RDONLY;
+ break;
+ case 'w':
+ flags = O_WRONLY|O_CREAT|O_TRUNC;
+ break;
+ case 'a':
+ flags = O_WRONLY|O_CREAT|O_APPEND;
+ break;
+ case '+':
+ plus = 1;
+ break;
+ }
+ mode++;
+ }
+
+ if ( plus ) {
+ flags = (flags & ~(O_RDONLY|O_WRONLY)) | O_RDWR;
+ }
+
+ fd = open(file, flags, 0666);
+
+ if ( fd < 0 )
+ return NULL;
+ else
+ return fdopen(fd, mode);
+}
diff --git a/com32/lib/fprintf.c b/com32/lib/fprintf.c
new file mode 100644
index 00000000..df3823ea
--- /dev/null
+++ b/com32/lib/fprintf.c
@@ -0,0 +1,19 @@
+/*
+ * fprintf.c
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#define BUFFER_SIZE 16384
+
+int fprintf(FILE *file, const char *format, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, format);
+ rv = vfprintf(file, format, ap);
+ va_end(ap);
+ return rv;
+}
diff --git a/com32/lib/fputc.c b/com32/lib/fputc.c
new file mode 100644
index 00000000..61aff164
--- /dev/null
+++ b/com32/lib/fputc.c
@@ -0,0 +1,14 @@
+/*
+ * fputc.c
+ *
+ * gcc "printf decompilation" expects this to exist...
+ */
+
+#include <stdio.h>
+
+int fputc(int c, FILE *f)
+{
+ unsigned char ch = c;
+
+ return _fwrite(&ch, 1, f) == 1 ? ch : EOF;
+}
diff --git a/com32/lib/fputs.c b/com32/lib/fputs.c
new file mode 100644
index 00000000..4b68f968
--- /dev/null
+++ b/com32/lib/fputs.c
@@ -0,0 +1,15 @@
+/*
+ * fputs.c
+ *
+ * This isn't quite fputs() in the stdio sense, since we don't
+ * have stdio, but it takes a file descriptor argument instead
+ * of the FILE *.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+int fputs(const char *s, FILE *file)
+{
+ return _fwrite(s, strlen(s), file);
+}
diff --git a/com32/lib/fread.c b/com32/lib/fread.c
new file mode 100644
index 00000000..8f7dba9c
--- /dev/null
+++ b/com32/lib/fread.c
@@ -0,0 +1,35 @@
+/*
+ * fread.c
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+
+size_t _fread(void *buf, size_t count, FILE *f)
+{
+ size_t bytes = 0;
+ ssize_t rv;
+ char *p = buf;
+
+ while ( count ) {
+ rv = read(fileno(f), p, count);
+ if ( rv == -1 ) {
+ if ( errno == EINTR )
+ continue;
+ else
+ break;
+ } else if ( rv == 0 ) {
+ break;
+ }
+
+ p += rv;
+ bytes += rv;
+ count -= rv;
+ }
+
+ return bytes;
+}
+
+
+
diff --git a/com32/lib/fread2.c b/com32/lib/fread2.c
new file mode 100644
index 00000000..9e5ac81f
--- /dev/null
+++ b/com32/lib/fread2.c
@@ -0,0 +1,13 @@
+/*
+ * fread2.c
+ *
+ * The actual fread() function as a non-inline
+ */
+
+#define __NO_FREAD_FWRITE_INLINES
+#include <stdio.h>
+
+size_t fread(void *ptr, size_t size, size_t nmemb, FILE *f)
+{
+ return _fread(ptr, size*nmemb, f)/size;
+}
diff --git a/com32/lib/free.c b/com32/lib/free.c
new file mode 100644
index 00000000..aa17080d
--- /dev/null
+++ b/com32/lib/free.c
@@ -0,0 +1,78 @@
+/*
+ * free.c
+ *
+ * Very simple linked-list based malloc()/free().
+ */
+
+#include <stdlib.h>
+#include "malloc.h"
+
+static struct free_arena_header *
+__free_block(struct free_arena_header *ah)
+{
+ struct free_arena_header *pah, *nah;
+
+ pah = ah->a.prev;
+ nah = ah->a.next;
+ if ( pah->a.type == ARENA_TYPE_FREE &&
+ (char *)pah+pah->a.size == (char *)ah ) {
+ /* Coalesce into the previous block */
+ pah->a.size += ah->a.size;
+ pah->a.next = nah;
+ nah->a.prev = pah;
+
+#ifdef DEBUG_MALLOC
+ ah->a.type = ARENA_TYPE_DEAD;
+#endif
+
+ ah = pah;
+ pah = ah->a.prev;
+ } else {
+ /* Need to add this block to the free chain */
+ ah->a.type = ARENA_TYPE_FREE;
+
+ ah->next_free = __malloc_head.next_free;
+ ah->prev_free = &__malloc_head;
+ __malloc_head.next_free = ah;
+ ah->next_free->prev_free = ah;
+ }
+
+ /* In either of the previous cases, we might be able to merge
+ with the subsequent block... */
+ if ( nah->a.type == ARENA_TYPE_FREE &&
+ (char *)ah+ah->a.size == (char *)nah ) {
+ ah->a.size += nah->a.size;
+
+ /* Remove the old block from the chains */
+ nah->next_free->prev_free = nah->prev_free;
+ nah->prev_free->next_free = nah->next_free;
+ ah->a.next = nah->a.next;
+ nah->a.next->a.prev = ah;
+
+#ifdef DEBUG_MALLOC
+ nah->a.type = ARENA_TYPE_DEAD;
+#endif
+ }
+
+ /* Return the block that contains the called block */
+ return ah;
+}
+
+void free(void *ptr)
+{
+ struct free_arena_header *ah;
+
+ if ( !ptr )
+ return;
+
+ ah = (struct free_arena_header *)
+ ((struct arena_header *)ptr - 1);
+
+#ifdef DEBUG_MALLOC
+ assert( ah->a.type == ARENA_TYPE_USED );
+#endif
+
+ __free_block(ah);
+
+ /* Here we could insert code to return memory to the system. */
+}
diff --git a/com32/lib/fwrite.c b/com32/lib/fwrite.c
new file mode 100644
index 00000000..0a73188c
--- /dev/null
+++ b/com32/lib/fwrite.c
@@ -0,0 +1,35 @@
+/*
+ * fwrite.c
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+
+size_t _fwrite(const void *buf, size_t count, FILE *f)
+{
+ size_t bytes = 0;
+ ssize_t rv;
+ const char *p = buf;
+
+ while ( count ) {
+ rv = write(fileno(f), p, count);
+ if ( rv == -1 ) {
+ if ( errno == EINTR )
+ continue;
+ else
+ break;
+ } else if ( rv == 0 ) {
+ break;
+ }
+
+ p += rv;
+ bytes += rv;
+ count -= rv;
+ }
+
+ return bytes;
+}
+
+
+
diff --git a/com32/lib/fwrite2.c b/com32/lib/fwrite2.c
new file mode 100644
index 00000000..82ec832b
--- /dev/null
+++ b/com32/lib/fwrite2.c
@@ -0,0 +1,13 @@
+/*
+ * fwrite2.c
+ *
+ * The actual fwrite() function as a non-inline
+ */
+
+#define __NO_FREAD_FWRITE_INLINES
+#include <stdio.h>
+
+size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *f)
+{
+ return _fwrite(ptr, size*nmemb, f)/size;
+}
diff --git a/com32/lib/getopt.c b/com32/lib/getopt.c
new file mode 100644
index 00000000..5a992dcd
--- /dev/null
+++ b/com32/lib/getopt.c
@@ -0,0 +1,74 @@
+/*
+ * getopt.c
+ *
+ * Simple POSIX getopt(), no GNU extensions...
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+
+char *optarg;
+int optind = 1;
+int opterr, optopt;
+static const char *__optptr;
+
+int getopt(int argc, char * const *argv, const char *optstring)
+{
+ const char *carg = argv[optind];
+ const char *osptr;
+ int opt;
+
+ /* We don't actually need argc */
+ (void)argc;
+
+ /* First, eliminate all non-option cases */
+
+ if ( !carg || carg[0] != '-' || !carg[1] ) {
+ return -1;
+ }
+
+ if ( carg[1] == '-' && !carg[2] ) {
+ optind++;
+ return -1;
+ }
+
+ if ( (uintptr_t)(__optptr-carg) > (uintptr_t)strlen(carg) )
+ __optptr = carg+1; /* Someone frobbed optind, change to new opt. */
+
+ opt = *__optptr++;
+
+ if ( opt != ':' && (osptr = strchr(optstring, opt)) ) {
+ if ( osptr[1] == ':' ) {
+ if ( *__optptr ) {
+ /* Argument-taking option with attached argument */
+ optarg = (char *)__optptr;
+ optind++;
+ } else {
+ /* Argument-taking option with non-attached argument */
+ if ( argv[optind+1] ) {
+ optarg = (char *)argv[optind+1];
+ optind += 2;
+ } else {
+ /* Missing argument */
+ return (optstring[0] == ':') ? ':' : '?';
+ }
+ }
+ return opt;
+ } else {
+ /* Non-argument-taking option */
+ /* __optptr will remember the exact position to resume at */
+ if ( ! *__optptr )
+ optind++;
+ return opt;
+ }
+ } else {
+ /* Unknown option */
+ optopt = opt;
+ if ( ! *__optptr )
+ optind++;
+ return '?';
+ }
+}
+
+
diff --git a/com32/lib/init.h b/com32/lib/init.h
new file mode 100644
index 00000000..2d983427
--- /dev/null
+++ b/com32/lib/init.h
@@ -0,0 +1,15 @@
+/*
+ * init.h
+ *
+ * Magic to set up initializers
+ */
+
+#ifndef _INIT_H
+#define _INIT_H 1
+
+#include <inttypes.h>
+
+#define COM32_INIT(x) static const void * const __COM32_INIT \
+ __attribute__((section(".init_array"),unused)) = (const void * const)&x
+
+#endif /* _INIT_H */
diff --git a/com32/lib/lrand48.c b/com32/lib/lrand48.c
new file mode 100644
index 00000000..4d05de2e
--- /dev/null
+++ b/com32/lib/lrand48.c
@@ -0,0 +1,42 @@
+/*
+ * lrand48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+unsigned short __rand48_seed[3];
+
+long jrand48(unsigned short xsubi[3])
+{
+ uint64_t x;
+
+ /* The xsubi[] array is littleendian by spec */
+ x = (uint64_t)xsubi[0] +
+ ((uint64_t)xsubi[1] << 16) +
+ ((uint64_t)xsubi[2] << 32);
+
+ x = (0x5deece66dULL * x) + 0xb;
+
+ xsubi[0] = (unsigned short)x;
+ xsubi[1] = (unsigned short)(x >> 16);
+ xsubi[2] = (unsigned short)(x >> 32);
+
+ return (long)(int32_t)(x >> 16);
+}
+
+long mrand48(void)
+{
+ return jrand48(__rand48_seed);
+}
+
+long nrand48(unsigned short xsubi[3])
+{
+ return (long)((uint32_t)jrand48(xsubi) >> 1);
+}
+
+long lrand48(void)
+{
+ return (long)((uint32_t)(mrand48() >> 1));
+}
+
diff --git a/com32/lib/malloc.c b/com32/lib/malloc.c
new file mode 100644
index 00000000..4efd89c1
--- /dev/null
+++ b/com32/lib/malloc.c
@@ -0,0 +1,120 @@
+/*
+ * malloc.c
+ *
+ * Very simple linked-list based malloc()/free().
+ */
+
+#include <stdlib.h>
+#include "init.h"
+#include "malloc.h"
+
+struct free_arena_header __malloc_head =
+{
+ {
+ ARENA_TYPE_HEAD,
+ 0,
+ &__malloc_head,
+ &__malloc_head,
+ },
+ &__malloc_head,
+ &__malloc_head
+};
+
+/* This is extern so it can be overridden by the user application */
+extern size_t __stack_size;
+
+static inline size_t sp(void)
+{
+ size_t sp;
+ asm volatile("movl %%esp,%0" : "=rm" (sp));
+ return sp;
+}
+
+static void __constructor init_memory_arena(void)
+{
+ extern char _end[]; /* Symbol created by the linker */
+ struct free_arena_header *fp;
+ size_t start, total_space;
+
+ start = (size_t)ARENA_ALIGN_UP(_end);
+ total_space = sp() - start;
+
+ if ( __stack_size == 0 || __stack_size > total_space >> 1 )
+ __stack_size = total_space >> 1; /* Half for the stack, half for the heap... */
+
+ if ( total_space < __stack_size + 4*sizeof(struct arena_header) )
+ __stack_size = total_space - 4*sizeof(struct arena_header);
+
+ fp = (struct free_arena_header *)start;
+ fp->a.type = ARENA_TYPE_FREE;
+ fp->a.size = total_space - __stack_size;
+
+ /* Insert into chains */
+ fp->a.next = fp->a.prev = &__malloc_head;
+ fp->next_free = fp->prev_free = &__malloc_head;
+ __malloc_head.a.next = __malloc_head.a.prev = fp;
+ __malloc_head.next_free = __malloc_head.prev_free = fp;
+}
+
+static void *__malloc_from_block(struct free_arena_header *fp, size_t size)
+{
+ size_t fsize;
+ struct free_arena_header *nfp, *na;
+
+ fsize = fp->a.size;
+
+ /* We need the 2* to account for the larger requirements of a free block */
+ if ( fsize >= size+2*sizeof(struct arena_header) ) {
+ /* Bigger block than required -- split block */
+ nfp = (struct free_arena_header *)((char *)fp + size);
+ na = fp->a.next;
+
+ nfp->a.type = ARENA_TYPE_FREE;
+ nfp->a.size = fsize-size;
+ fp->a.type = ARENA_TYPE_USED;
+ fp->a.size = size;
+
+ /* Insert into all-block chain */
+ nfp->a.prev = fp;
+ nfp->a.next = na;
+ na->a.prev = nfp;
+ fp->a.next = nfp;
+
+ /* Replace current block on free chain */
+ nfp->next_free = fp->next_free;
+ nfp->prev_free = fp->prev_free;
+ fp->next_free->prev_free = nfp;
+ fp->prev_free->next_free = nfp;
+ } else {
+ /* Allocate the whole block */
+ fp->a.type = ARENA_TYPE_USED;
+
+ /* Remove from free chain */
+ fp->next_free->prev_free = fp->prev_free;
+ fp->prev_free->next_free = fp->next_free;
+ }
+
+ return (void *)(&fp->a + 1);
+}
+
+void *malloc(size_t size)
+{
+ struct free_arena_header *fp;
+
+ if ( size == 0 )
+ return NULL;
+
+ /* Add the obligatory arena header, and round up */
+ size = (size+2*sizeof(struct arena_header)-1) & ARENA_SIZE_MASK;
+
+ for ( fp = __malloc_head.next_free ; fp->a.type != ARENA_TYPE_HEAD ;
+ fp = fp->next_free ) {
+ if ( fp->a.size >= size ) {
+ /* Found fit -- allocate out of this block */
+ return __malloc_from_block(fp, size);
+ }
+ }
+
+ /* Nothing found... need to request a block from the kernel */
+ return NULL; /* No kernel to get stuff from */
+}
diff --git a/com32/lib/memccpy.c b/com32/lib/memccpy.c
new file mode 100644
index 00000000..22f68dea
--- /dev/null
+++ b/com32/lib/memccpy.c
@@ -0,0 +1,23 @@
+/*
+ * memccpy.c
+ *
+ * memccpy()
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+void *memccpy(void *dst, const void *src, int c, size_t n)
+{
+ char *q = dst;
+ const char *p = src;
+ char ch;
+
+ while ( n-- ) {
+ *q++ = ch = *p++;
+ if ( ch == (char)c )
+ return q;
+ }
+
+ return NULL; /* No instance of "c" found */
+}
diff --git a/com32/lib/memchr.c b/com32/lib/memchr.c
new file mode 100644
index 00000000..c5c5fa29
--- /dev/null
+++ b/com32/lib/memchr.c
@@ -0,0 +1,18 @@
+/*
+ * memchr.c
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+void *memchr(const void *s, int c, size_t n)
+{
+ const unsigned char *sp = s;
+
+ while ( n-- ) {
+ if ( *sp == (unsigned char)c )
+ return (void *)sp;
+ }
+
+ return NULL;
+}
diff --git a/com32/lib/memcmp.c b/com32/lib/memcmp.c
new file mode 100644
index 00000000..f6bc1728
--- /dev/null
+++ b/com32/lib/memcmp.c
@@ -0,0 +1,19 @@
+/*
+ * memcmp.c
+ */
+
+#include <string.h>
+
+int memcmp(const void *s1, const void *s2, size_t n)
+{
+ const unsigned char *c1 = s1, *c2 = s2;
+ int d = 0;
+
+ while ( n-- ) {
+ d = (int)*c1++ - (int)*c2++;
+ if ( d )
+ break;
+ }
+
+ return d;
+}
diff --git a/com32/lib/memcpy.c b/com32/lib/memcpy.c
new file mode 100644
index 00000000..b9171c30
--- /dev/null
+++ b/com32/lib/memcpy.c
@@ -0,0 +1,29 @@
+/*
+ * memcpy.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void *memcpy(void *dst, const void *src, size_t n)
+{
+ const char *p = src;
+ char *q = dst;
+#if defined(__i386__)
+ size_t nl = n >> 2;
+ asm volatile("cld ; rep ; movsl ; movl %3,%0 ; rep ; movsb"
+ : "+c" (nl), "+S" (p), "+D" (q)
+ : "r" (n & 3));
+#elif defined(__x86_64__)
+ size_t nq = n >> 3;
+ asm volatile("cld ; rep ; movsq ; movl %3,%%ecx ; rep ; movsb"
+ : "+c" (nq), "+S" (p), "+D" (q)
+ : "r" ((uint32_t)(n & 7)));
+#else
+ while ( n-- ) {
+ *q++ = *p++;
+ }
+#endif
+
+ return dst;
+}
diff --git a/com32/lib/memmem.c b/com32/lib/memmem.c
new file mode 100644
index 00000000..0f59938f
--- /dev/null
+++ b/com32/lib/memmem.c
@@ -0,0 +1,44 @@
+/*
+ * memmem.c
+ *
+ * Find a byte string inside a longer byte string
+ *
+ * This uses the "Not So Naive" algorithm, a very simple but
+ * usually effective algorithm, see:
+ *
+ * http://www-igm.univ-mlv.fr/~lecroq/string/
+ */
+
+#include <string.h>
+
+void *memmem(const void *haystack, size_t n, const void *needle, size_t m)
+{
+ const unsigned char *y = (const unsigned char *)haystack;
+ const unsigned char *x = (const unsigned char *)needle;
+
+ size_t j, k, l;
+
+ if ( m > n )
+ return NULL;
+
+ if ( x[0] == x[1] ) {
+ k = 2;
+ l = 1;
+ } else {
+ k = 1;
+ l = 2;
+ }
+
+ j = 0;
+ while ( j <= n-m ) {
+ if (x[1] != y[j+1]) {
+ j += k;
+ } else {
+ if ( !memcmp(x+2, y+j+2, m-2) && x[0] == y[j] )
+ return (void *)&y[j];
+ j += l;
+ }
+ }
+
+ return NULL;
+}
diff --git a/com32/lib/memmove.c b/com32/lib/memmove.c
new file mode 100644
index 00000000..c1f042af
--- /dev/null
+++ b/com32/lib/memmove.c
@@ -0,0 +1,34 @@
+/*
+ * memmove.c
+ */
+
+#include <string.h>
+
+void *memmove(void *dst, const void *src, size_t n)
+{
+ const char *p = src;
+ char *q = dst;
+#if defined(__i386__) || defined(__x86_64__)
+ if ( q < p ) {
+ asm volatile("cld ; rep ; movsb" : "+c" (n), "+S" (p), "+D" (q));
+ } else {
+ p += (n-1);
+ q += (n-1);
+ asm volatile("std ; rep ; movsb" : "+c" (n), "+S" (p), "+D" (q));
+ }
+#else
+ if ( q < p ) {
+ while ( n-- ) {
+ *q++ = *p++;
+ }
+ } else {
+ p += n;
+ q += n;
+ while ( n-- ) {
+ *--q = *--p;
+ }
+ }
+#endif
+
+ return dst;
+}
diff --git a/com32/lib/memset.c b/com32/lib/memset.c
new file mode 100644
index 00000000..522cc59a
--- /dev/null
+++ b/com32/lib/memset.c
@@ -0,0 +1,30 @@
+/*
+ * memset.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void *memset(void *dst, int c, size_t n)
+{
+ char *q = dst;
+
+#if defined(__i386__)
+ size_t nl = n >> 2;
+ asm volatile("cld ; rep ; stosl ; movl %3,%0 ; rep ; stosb"
+ : "+c" (nl), "+D" (q)
+ : "a" ((unsigned char)c * 0x01010101U), "r" (n & 3));
+#elif defined(__x86_64__)
+ size_t nq = n >> 3;
+ asm volatile("cld ; rep ; stosq ; movl %3,%%ecx ; rep ; stosb"
+ : "+c" (nq), "+D" (q)
+ : "a" ((unsigned char)c * 0x0101010101010101U),
+ "r" ((uint32_t)n & 7));
+#else
+ while ( n-- ) {
+ *q++ = c;
+ }
+#endif
+
+ return dst;
+}
diff --git a/com32/lib/memswap.c b/com32/lib/memswap.c
new file mode 100644
index 00000000..10440e34
--- /dev/null
+++ b/com32/lib/memswap.c
@@ -0,0 +1,23 @@
+/*
+ * memswap()
+ *
+ * Swaps the contents of two nonoverlapping memory areas.
+ * This really could be done faster...
+ */
+
+#include <string.h>
+
+void memswap(void *m1, void *m2, size_t n)
+{
+ char *p = m1;
+ char *q = m2;
+ char tmp;
+
+ while ( n-- ) {
+ tmp = *p;
+ *p = *q;
+ *q = tmp;
+
+ p++; q++;
+ }
+}
diff --git a/com32/lib/onexit.c b/com32/lib/onexit.c
new file mode 100644
index 00000000..70a9c01f
--- /dev/null
+++ b/com32/lib/onexit.c
@@ -0,0 +1,39 @@
+/*
+ * onexit.c
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include "atexit.h"
+
+extern __noreturn (*__exit_handler)(int);
+static struct atexit *__atexit_list;
+
+static __noreturn on_exit_exit(int rv)
+{
+ struct atexit *ap;
+
+ for ( ap = __atexit_list ; ap ; ap = ap->next ) {
+ ap->fctn(rv, ap->arg); /* This assumes extra args are harmless */
+ }
+
+ _exit(rv);
+}
+
+int on_exit(void (*fctn)(int, void *), void *arg)
+{
+ struct atexit *as = malloc(sizeof(struct atexit));
+
+ if ( !as )
+ return -1;
+
+ as->fctn = fctn;
+ as->arg = arg;
+
+ as->next = __atexit_list;
+ __atexit_list = as;
+
+ __exit_handler = on_exit_exit;
+
+ return 0;
+}
diff --git a/com32/lib/perror.c b/com32/lib/perror.c
new file mode 100644
index 00000000..45585cd5
--- /dev/null
+++ b/com32/lib/perror.c
@@ -0,0 +1,12 @@
+/*
+ * perror.c
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+void perror(const char *s)
+{
+ fprintf(stderr, "%s: error %d\n", s, errno);
+}
diff --git a/com32/lib/printf.c b/com32/lib/printf.c
new file mode 100644
index 00000000..34237592
--- /dev/null
+++ b/com32/lib/printf.c
@@ -0,0 +1,19 @@
+/*
+ * printf.c
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#define BUFFER_SIZE 16384
+
+int printf(const char *format, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, format);
+ rv = vfprintf(stdout, format, ap);
+ va_end(ap);
+ return rv;
+}
diff --git a/com32/lib/puts.c b/com32/lib/puts.c
new file mode 100644
index 00000000..ecebf275
--- /dev/null
+++ b/com32/lib/puts.c
@@ -0,0 +1,13 @@
+/*
+ * puts.c
+ */
+
+#include <stdio.h>
+
+int puts(const char *s)
+{
+ if ( fputs(s, stdout) < 0 )
+ return -1;
+
+ return _fwrite("\n", 1, stdout);
+}
diff --git a/com32/lib/qsort.c b/com32/lib/qsort.c
new file mode 100644
index 00000000..e2197ea2
--- /dev/null
+++ b/com32/lib/qsort.c
@@ -0,0 +1,42 @@
+/*
+ * qsort.c
+ *
+ * This is actually combsort. It's an O(n log n) algorithm with
+ * simplicity/small code size being its main virtue.
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+static inline size_t newgap(size_t gap)
+{
+ gap = (gap*10)/13;
+ if ( gap == 9 || gap == 10 )
+ gap = 11;
+
+ if ( gap < 1 )
+ gap = 1;
+ return gap;
+}
+
+void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *))
+{
+ size_t gap = nmemb;
+ size_t i, j;
+ void *p1, *p2;
+ int swapped;
+
+ do {
+ gap = newgap(gap);
+ swapped = 0;
+
+ for ( i = 0, p1 = base ; i < nmemb-gap ; i++, (char *)p1 += size ) {
+ j = i+gap;
+ if ( compar(p1, p2 = (char *)base+j*size) > 0 ) {
+ memswap(p1, p2, size);
+ swapped = 1;
+ }
+ }
+ } while ( gap > 1 || swapped );
+}
+
diff --git a/com32/lib/realloc.c b/com32/lib/realloc.c
new file mode 100644
index 00000000..577c2001
--- /dev/null
+++ b/com32/lib/realloc.c
@@ -0,0 +1,49 @@
+/*
+ * realloc.c
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "malloc.h"
+
+/* FIXME: This is cheesy, it should be fixed later */
+
+void *realloc(void *ptr, size_t size)
+{
+ struct free_arena_header *ah;
+ void *newptr;
+ size_t oldsize;
+
+ if ( !ptr )
+ return malloc(size);
+
+ if ( size == 0 ) {
+ free(ptr);
+ return NULL;
+ }
+
+ /* Add the obligatory arena header, and round up */
+ size = (size+2*sizeof(struct arena_header)-1) & ARENA_SIZE_MASK;
+
+ ah = (struct free_arena_header *)
+ ((struct arena_header *)ptr - 1);
+
+ if ( ah->a.size >= size && size >= (ah->a.size >> 2) ) {
+ /* This field is a good size already. */
+ return ptr;
+ } else {
+ /* Make me a new block. This is kind of bogus; we should
+ be checking the adjacent blocks to see if we can do an
+ in-place adjustment... fix that later. */
+
+ oldsize = ah->a.size - sizeof(struct arena_header);
+
+ newptr = malloc(size);
+ memcpy(newptr, ptr, (size < oldsize) ? size : oldsize);
+ free(ptr);
+
+ return newptr;
+ }
+}
+
diff --git a/com32/lib/seed48.c b/com32/lib/seed48.c
new file mode 100644
index 00000000..f8353c87
--- /dev/null
+++ b/com32/lib/seed48.c
@@ -0,0 +1,19 @@
+/*
+ * seed48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+extern unsigned short __rand48_seed[3];
+
+unsigned short *seed48(const unsigned short xsubi[3])
+{
+ static unsigned short oldseed[3];
+ memcpy(oldseed, __rand48_seed, sizeof __rand48_seed);
+ memcpy(__rand48_seed, xsubi, sizeof __rand48_seed);
+
+ return oldseed;
+}
+
diff --git a/com32/lib/setjmp.S b/com32/lib/setjmp.S
new file mode 100644
index 00000000..bea900c5
--- /dev/null
+++ b/com32/lib/setjmp.S
@@ -0,0 +1,58 @@
+#
+# arch/i386/setjmp.S
+#
+# setjmp/longjmp for the i386 architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+# %ebx
+# %esp
+# %ebp
+# %esi
+# %edi
+# <return address>
+#
+
+ .text
+ .align 4
+ .globl setjmp
+ .type setjmp, @function
+setjmp:
+#ifdef REGPARM
+ movl %eax,%edx
+#else
+ movl 4(%esp),%edx
+#endif
+ popl %ecx # Return address, and adjust the stack
+ xorl %eax,%eax # Return value
+ movl %ebx,(%edx)
+ movl %esp,4(%edx) # Post-return %esp!
+ pushl %ecx # Make the call/return stack happy
+ movl %ebp,8(%edx)
+ movl %esi,12(%edx)
+ movl %edi,16(%edx)
+ movl %ecx,20(%edx) # Return address
+ ret
+
+ .size setjmp,.-setjmp
+
+ .text
+ .align 4
+ .globl longjmp
+ .type longjmp, @function
+longjmp:
+#ifdef REGPARM
+ xchgl %eax,%edx
+#else
+ movl 4(%esp),%edx # jmp_ptr address
+ movl 8(%esp),%eax # Return value
+#endif
+ movl (%edx),%ebx
+ movl 4(%edx),%esp
+ movl 8(%edx),%ebp
+ movl 12(%edx),%esi
+ movl 16(%edx),%edi
+ jmp *20(%edx)
+
+ .size longjmp,.-longjmp
diff --git a/com32/lib/snprintf.c b/com32/lib/snprintf.c
new file mode 100644
index 00000000..c642851b
--- /dev/null
+++ b/com32/lib/snprintf.c
@@ -0,0 +1,16 @@
+/*
+ * snprintf.c
+ */
+
+#include <stdio.h>
+
+int snprintf(char *buffer, size_t n, const char *format, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, format);
+ rv = vsnprintf(buffer, n, format, ap);
+ va_end(ap);
+ return rv;
+}
diff --git a/com32/lib/sprintf.c b/com32/lib/sprintf.c
new file mode 100644
index 00000000..31f28af0
--- /dev/null
+++ b/com32/lib/sprintf.c
@@ -0,0 +1,18 @@
+/*
+ * sprintf.c
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int sprintf(char *buffer, const char *format, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, format);
+ rv = vsnprintf(buffer, ~(size_t)0, format, ap);
+ va_end(ap);
+
+ return rv;
+}
diff --git a/com32/lib/srand48.c b/com32/lib/srand48.c
new file mode 100644
index 00000000..a3df16d9
--- /dev/null
+++ b/com32/lib/srand48.c
@@ -0,0 +1,16 @@
+/*
+ * srand48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+extern unsigned short __rand48_seed[3];
+
+
+void srand48(long seedval)
+{
+ __rand48_seed[0] = 0x330e;
+ __rand48_seed[1] = (unsigned short)seedval;
+ __rand48_seed[2] = (unsigned short)((uint32_t)seedval >> 16);
+}
diff --git a/com32/lib/sscanf.c b/com32/lib/sscanf.c
new file mode 100644
index 00000000..81aab9e0
--- /dev/null
+++ b/com32/lib/sscanf.c
@@ -0,0 +1,17 @@
+/*
+ * sscanf()
+ */
+
+#include <stdio.h>
+
+int sscanf(const char *str, const char *format, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, format);
+ rv = vsscanf(str, format, ap);
+ va_end(ap);
+
+ return rv;
+}
diff --git a/com32/lib/stack.c b/com32/lib/stack.c
new file mode 100644
index 00000000..e778e8e2
--- /dev/null
+++ b/com32/lib/stack.c
@@ -0,0 +1,4 @@
+#include <stdlib.h>
+
+/* Default stack size 8 MB */
+size_t stack_size = 8 << 20;
diff --git a/com32/lib/strcasecmp.c b/com32/lib/strcasecmp.c
new file mode 100644
index 00000000..12aef40d
--- /dev/null
+++ b/com32/lib/strcasecmp.c
@@ -0,0 +1,23 @@
+/*
+ * strcasecmp.c
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+int strcasecmp(const char *s1, const char *s2)
+{
+ const unsigned char *c1 = s1, *c2 = s2;
+ unsigned char ch;
+ int d = 0;
+
+ while ( 1 ) {
+ /* toupper() expects an unsigned char (implicitly cast to int)
+ as input, and returns an int, which is exactly what we want. */
+ d = toupper(ch = *c1++) - toupper(*c2++);
+ if ( d || !ch )
+ break;
+ }
+
+ return d;
+}
diff --git a/com32/lib/strcat.c b/com32/lib/strcat.c
new file mode 100644
index 00000000..a5f94778
--- /dev/null
+++ b/com32/lib/strcat.c
@@ -0,0 +1,11 @@
+/*
+ * strcat.c
+ */
+
+#include <string.h>
+
+char *strcat(char *dst, const char *src)
+{
+ strcpy(strchr(dst, '\0'), src);
+ return dst;
+}
diff --git a/com32/lib/strchr.c b/com32/lib/strchr.c
new file mode 100644
index 00000000..192f8360
--- /dev/null
+++ b/com32/lib/strchr.c
@@ -0,0 +1,16 @@
+/*
+ * strchr.c
+ */
+
+#include <string.h>
+
+char *strchr(const char *s, int c)
+{
+ while ( *s != (char)c ) {
+ if ( ! *s )
+ return NULL;
+ s++;
+ }
+
+ return (char *)s;
+}
diff --git a/com32/lib/strcmp.c b/com32/lib/strcmp.c
new file mode 100644
index 00000000..f44774f4
--- /dev/null
+++ b/com32/lib/strcmp.c
@@ -0,0 +1,20 @@
+/*
+ * strcmp.c
+ */
+
+#include <string.h>
+
+int strcmp(const char *s1, const char *s2)
+{
+ const unsigned char *c1 = s1, *c2 = s2;
+ unsigned char ch;
+ int d = 0;
+
+ while ( 1 ) {
+ d = (int)(ch = *c1++) - (int)*c2++;
+ if ( d || !ch )
+ break;
+ }
+
+ return d;
+}
diff --git a/com32/lib/strcpy.c b/com32/lib/strcpy.c
new file mode 100644
index 00000000..8372eba5
--- /dev/null
+++ b/com32/lib/strcpy.c
@@ -0,0 +1,20 @@
+/*
+ * strcpy.c
+ *
+ * strcpy()
+ */
+
+#include <string.h>
+
+char *strcpy(char *dst, const char *src)
+{
+ char *q = dst;
+ const char *p = src;
+ char ch;
+
+ do {
+ *q++ = ch = *p++;
+ } while ( ch );
+
+ return dst;
+}
diff --git a/com32/lib/strdup.c b/com32/lib/strdup.c
new file mode 100644
index 00000000..eb170c26
--- /dev/null
+++ b/com32/lib/strdup.c
@@ -0,0 +1,17 @@
+/*
+ * strdup.c
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+char *strdup(const char *s)
+{
+ int l = strlen(s)+1;
+ char *d = malloc(l);
+
+ if ( d )
+ memcpy(d, s, l);
+
+ return d;
+}
diff --git a/com32/lib/strerror.c b/com32/lib/strerror.c
new file mode 100644
index 00000000..62705553
--- /dev/null
+++ b/com32/lib/strerror.c
@@ -0,0 +1,24 @@
+/*
+ * strerror.c
+ */
+
+#include <string.h>
+
+char *strerror(int errnum)
+{
+ static char message[32] = "error "; /* enough for error 2^63-1 */
+
+ char numbuf[32];
+ char *p;
+
+ p = numbuf+sizeof numbuf;
+ *--p = '\0';
+
+ do {
+ *--p = (errnum % 10) + '0';
+ errnum /= 10;
+ } while ( errnum );
+
+ return (char *)memcpy(message+6, p, (numbuf+sizeof numbuf)-p);
+}
+
diff --git a/com32/lib/strlen.c b/com32/lib/strlen.c
new file mode 100644
index 00000000..4d773f9a
--- /dev/null
+++ b/com32/lib/strlen.c
@@ -0,0 +1,14 @@
+/*
+ * strlen()
+ */
+
+#include <string.h>
+
+size_t strlen(const char *s)
+{
+ const char *ss = s;
+ while ( *ss )
+ ss++;
+ return ss-s;
+}
+
diff --git a/com32/lib/strncasecmp.c b/com32/lib/strncasecmp.c
new file mode 100644
index 00000000..3309d1a7
--- /dev/null
+++ b/com32/lib/strncasecmp.c
@@ -0,0 +1,23 @@
+/*
+ * strncasecmp.c
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+int strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ const unsigned char *c1 = s1, *c2 = s2;
+ unsigned char ch;
+ int d = 0;
+
+ while ( n-- ) {
+ /* toupper() expects an unsigned char (implicitly cast to int)
+ as input, and returns an int, which is exactly what we want. */
+ d = toupper(ch = *c1++) - toupper(*c2++);
+ if ( d || !ch )
+ break;
+ }
+
+ return d;
+}
diff --git a/com32/lib/strncat.c b/com32/lib/strncat.c
new file mode 100644
index 00000000..99d95759
--- /dev/null
+++ b/com32/lib/strncat.c
@@ -0,0 +1,11 @@
+/*
+ * strncat.c
+ */
+
+#include <string.h>
+
+char *strncat(char *dst, const char *src, size_t n)
+{
+ strncpy(strchr(dst, '\0'), src, n);
+ return dst;
+}
diff --git a/com32/lib/strncmp.c b/com32/lib/strncmp.c
new file mode 100644
index 00000000..4dbde138
--- /dev/null
+++ b/com32/lib/strncmp.c
@@ -0,0 +1,20 @@
+/*
+ * strncmp.c
+ */
+
+#include <string.h>
+
+int strncmp(const char *s1, const char *s2, size_t n)
+{
+ const unsigned char *c1 = s1, *c2 = s2;
+ unsigned char ch;
+ int d = 0;
+
+ while ( n-- ) {
+ d = (int)(ch = *c1++) - (int)*c2++;
+ if ( d || !ch )
+ break;
+ }
+
+ return d;
+}
diff --git a/com32/lib/strncpy.c b/com32/lib/strncpy.c
new file mode 100644
index 00000000..a8fe45fc
--- /dev/null
+++ b/com32/lib/strncpy.c
@@ -0,0 +1,22 @@
+/*
+ * strncpy.c
+ *
+ * strncpy()
+ */
+
+#include <string.h>
+
+char *strncpy(char *dst, const char *src, size_t n)
+{
+ char *q = dst;
+ const char *p = src;
+ char ch;
+
+ while ( n-- ) {
+ *q++ = ch = *p++;
+ if ( !ch )
+ break;
+ }
+
+ return dst;
+}
diff --git a/com32/lib/strndup.c b/com32/lib/strndup.c
new file mode 100644
index 00000000..1b44e6f9
--- /dev/null
+++ b/com32/lib/strndup.c
@@ -0,0 +1,17 @@
+/*
+ * strndup.c
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+char *strndup(const char *s, size_t n)
+{
+ int l = n > strlen(s) ? strlen(s)+1 : n+1;
+ char *d = malloc(l);
+
+ if (d)
+ memcpy(d, s, l);
+ d[n] = '\0';
+ return d;
+}
diff --git a/com32/lib/strntoimax.c b/com32/lib/strntoimax.c
new file mode 100644
index 00000000..f53a266d
--- /dev/null
+++ b/com32/lib/strntoimax.c
@@ -0,0 +1,13 @@
+/*
+ * strntoimax.c
+ *
+ * strntoimax()
+ */
+
+#include <stddef.h>
+#include <inttypes.h>
+
+intmax_t strntoimax(const char *nptr, char **endptr, int base, size_t n)
+{
+ return (intmax_t) strntoumax(nptr, endptr, base, n);
+}
diff --git a/com32/lib/strntoumax.c b/com32/lib/strntoumax.c
new file mode 100644
index 00000000..4e30637d
--- /dev/null
+++ b/com32/lib/strntoumax.c
@@ -0,0 +1,75 @@
+/*
+ * strntoumax.c
+ *
+ * The strntoumax() function and associated
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <ctype.h>
+
+static inline int digitval(int ch)
+{
+ if ( ch >= '0' && ch <= '9' ) {
+ return ch-'0';
+ } else if ( ch >= 'A' && ch <= 'Z' ) {
+ return ch-'A'+10;
+ } else if ( ch >= 'a' && ch <= 'z' ) {
+ return ch-'a'+10;
+ } else {
+ return -1;
+ }
+}
+
+uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n)
+{
+ int minus = 0;
+ uintmax_t v = 0;
+ int d;
+
+ while ( n && isspace((unsigned char)*nptr) ) {
+ nptr++;
+ n--;
+ }
+
+ /* Single optional + or - */
+ if ( n && *nptr == '-' ) {
+ minus = 1;
+ nptr++;
+ n--;
+ } else if ( n && *nptr == '+' ) {
+ nptr++;
+ }
+
+ if ( base == 0 ) {
+ if ( n >= 2 && nptr[0] == '0' &&
+ (nptr[1] == 'x' || nptr[1] == 'X') ) {
+ n -= 2;
+ nptr += 2;
+ base = 16;
+ } else if ( n >= 1 && nptr[0] == '0' ) {
+ n--;
+ nptr++;
+ base = 8;
+ } else {
+ base = 10;
+ }
+ } else if ( base == 16 ) {
+ if ( n >= 2 && nptr[0] == '0' &&
+ (nptr[1] == 'x' || nptr[1] == 'X') ) {
+ n -= 2;
+ nptr += 2;
+ }
+ }
+
+ while ( n && (d = digitval(*nptr)) >= 0 && d < base ) {
+ v = v*base + d;
+ n--;
+ nptr++;
+ }
+
+ if ( endptr )
+ *endptr = (char *)nptr;
+
+ return minus ? -v : v;
+}
diff --git a/com32/lib/strrchr.c b/com32/lib/strrchr.c
new file mode 100644
index 00000000..3b424640
--- /dev/null
+++ b/com32/lib/strrchr.c
@@ -0,0 +1,18 @@
+/*
+ * strrchr.c
+ */
+
+#include <string.h>
+
+char *strrchr(const char *s, int c)
+{
+ const char *found = NULL;
+
+ while ( *s ) {
+ if ( *s == (char) c )
+ found = s;
+ s++;
+ }
+
+ return (char *)found;
+}
diff --git a/com32/lib/strsep.c b/com32/lib/strsep.c
new file mode 100644
index 00000000..58a7a077
--- /dev/null
+++ b/com32/lib/strsep.c
@@ -0,0 +1,21 @@
+/*
+ * strsep.c
+ */
+
+#include <string.h>
+
+char *strsep(char **stringp, const char *delim)
+{
+ char *s = *stringp;
+ char *e;
+
+ if ( !s )
+ return NULL;
+
+ e = strpbrk(s, delim);
+ if (e)
+ *e++ = '\0';
+
+ *stringp = e;
+ return s;
+}
diff --git a/com32/lib/strspn.c b/com32/lib/strspn.c
new file mode 100644
index 00000000..856a9641
--- /dev/null
+++ b/com32/lib/strspn.c
@@ -0,0 +1,67 @@
+/*
+ * strspn, strcspn
+ */
+
+#include <string.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <limits.h>
+
+#ifndef LONG_BIT
+#define LONG_BIT (CHAR_BIT*sizeof(long))
+#endif
+
+static inline void
+set_bit(unsigned long *bitmap, unsigned int bit)
+{
+ bitmap[bit/LONG_BIT] |= 1UL << (bit%LONG_BIT);
+}
+
+static inline int
+test_bit(unsigned long *bitmap, unsigned int bit)
+{
+ return (int)(bitmap[bit/LONG_BIT] >> (bit%LONG_BIT)) & 1;
+}
+
+static size_t
+strxspn(const char *s, const char *map, int parity)
+{
+ unsigned long matchmap[((1 << CHAR_BIT)+LONG_BIT-1)/LONG_BIT];
+ size_t n = 0;
+
+ /* Create bitmap */
+ memset(matchmap, 0, sizeof matchmap);
+ while ( *map )
+ set_bit(matchmap, (unsigned char) *map++);
+
+ /* Make sure the null character never matches */
+ if ( parity )
+ set_bit(matchmap, 0);
+
+ /* Calculate span length */
+ while ( test_bit(matchmap, (unsigned char) *s++)^parity )
+ n++;
+
+ return n;
+}
+
+size_t
+strspn(const char *s, const char *accept)
+{
+ return strxspn(s, accept, 0);
+}
+
+size_t
+strcspn(const char *s, const char *reject)
+{
+ return strxspn(s, reject, 1);
+}
+
+char *
+strpbrk(const char *s, const char *accept)
+{
+ const char *ss = s+strxspn(s, accept, 1);
+
+ return *ss ? (char *)ss : NULL;
+}
+
diff --git a/com32/lib/strstr.c b/com32/lib/strstr.c
new file mode 100644
index 00000000..10222dfd
--- /dev/null
+++ b/com32/lib/strstr.c
@@ -0,0 +1,10 @@
+/*
+ * strstr.c
+ */
+
+#include <string.h>
+
+char *strstr(const char *haystack, const char *needle)
+{
+ return (char *)memmem(haystack, strlen(haystack), needle, strlen(needle));
+}
diff --git a/com32/lib/strtoimax.c b/com32/lib/strtoimax.c
new file mode 100644
index 00000000..0cdd088e
--- /dev/null
+++ b/com32/lib/strtoimax.c
@@ -0,0 +1,3 @@
+#define TYPE intmax_t
+#define NAME strtoimax
+#include "strtox.c"
diff --git a/com32/lib/strtok.c b/com32/lib/strtok.c
new file mode 100644
index 00000000..6e84f1df
--- /dev/null
+++ b/com32/lib/strtok.c
@@ -0,0 +1,16 @@
+/*
+ * strtok.c
+ */
+
+#include <string.h>
+
+char *strtok(char *s, const char *delim)
+{
+ static char *holder;
+
+ if ( s )
+ holder = s;
+
+ return strsep(&holder, delim);
+}
+
diff --git a/com32/lib/strtol.c b/com32/lib/strtol.c
new file mode 100644
index 00000000..9efc8b9e
--- /dev/null
+++ b/com32/lib/strtol.c
@@ -0,0 +1,3 @@
+#define TYPE signed long
+#define NAME strtol
+#include "strtox.c"
diff --git a/com32/lib/strtoll.c b/com32/lib/strtoll.c
new file mode 100644
index 00000000..a9428c7f
--- /dev/null
+++ b/com32/lib/strtoll.c
@@ -0,0 +1,3 @@
+#define TYPE signed long long
+#define NAME strtoll
+#include "strtox.c"
diff --git a/com32/lib/strtoul.c b/com32/lib/strtoul.c
new file mode 100644
index 00000000..3189aaa7
--- /dev/null
+++ b/com32/lib/strtoul.c
@@ -0,0 +1,3 @@
+#define TYPE unsigned long
+#define NAME strtoul
+#include "strtox.c"
diff --git a/com32/lib/strtoull.c b/com32/lib/strtoull.c
new file mode 100644
index 00000000..83c14e91
--- /dev/null
+++ b/com32/lib/strtoull.c
@@ -0,0 +1,3 @@
+#define TYPE unsigned long long
+#define NAME strtoull
+#include "strtox.c"
diff --git a/com32/lib/strtoumax.c b/com32/lib/strtoumax.c
new file mode 100644
index 00000000..a3797105
--- /dev/null
+++ b/com32/lib/strtoumax.c
@@ -0,0 +1,3 @@
+#define TYPE uintmax_t
+#define NAME strtoumax
+#include "strtox.c"
diff --git a/com32/lib/strtox.c b/com32/lib/strtox.c
new file mode 100644
index 00000000..7c228b6f
--- /dev/null
+++ b/com32/lib/strtox.c
@@ -0,0 +1,13 @@
+/*
+ * strtox.c
+ *
+ * strto...() functions, by macro definition
+ */
+
+#include <stddef.h>
+#include <inttypes.h>
+
+TYPE NAME (const char *nptr, char **endptr, int base)
+{
+ return (TYPE) strntoumax(nptr, endptr, base, ~(size_t)0);
+}
diff --git a/com32/lib/sys/close.c b/com32/lib/sys/close.c
new file mode 100644
index 00000000..b81d77ef
--- /dev/null
+++ b/com32/lib/sys/close.c
@@ -0,0 +1,57 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * close.c
+ */
+
+#include <errno.h>
+#include <com32.h>
+#include <string.h>
+#include "file.h"
+
+int close(int fd)
+{
+ com32sys_t regs;
+ struct file_info *fp = &__file_info[fd];
+
+ if ( fd >= NFILES || fp->blocklg2 == 0 ) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if ( fp->filedes ) {
+ memset(&regs, 0, sizeof regs);
+ regs.eax.w[0] = 0x0008; /* Close file */
+ regs.esi.w[0] = fp->filedes;
+
+ __com32.cs_intcall(0x22, &regs, NULL);
+ }
+
+ return 0;
+}
diff --git a/com32/lib/sys/entry.S b/com32/lib/sys/entry.S
new file mode 100644
index 00000000..40194528
--- /dev/null
+++ b/com32/lib/sys/entry.S
@@ -0,0 +1,83 @@
+#ident "$Id$"
+# -----------------------------------------------------------------------
+#
+# Copyright 2003-2004 H. Peter Anvin - All Rights Reserved
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom
+# the Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall
+# be included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# -----------------------------------------------------------------------
+
+# COM32 start up code - must be linked first in the binary
+
+
+ .section ".init","ax"
+ .globl _start
+ .type _start, @function
+_start:
+ # This first instruction acts as COM32 magic number
+ movl $0x21cd4cff,%eax
+
+ # Upwards string operations
+ cld
+
+ # Zero the .bss segment
+ xorl %eax,%eax
+ movl $__bss_start,%edi # Symbol provided by linker
+ movl $_end+3,%ecx # Symbol provided by linker
+ subl %edi,%ecx
+ shrl $2,%ecx
+ rep ; stosl
+
+ # Copy COM32 invocation parameters
+ leal 4(%esp),%esi # Argument list
+ movl $__com32,%edi
+ movl $6,%ecx
+ movl %esp,-4(%edi) # Save the initial stack ptr
+ cmpl (%esi),%ecx
+ jbe 1f
+ movl (%esi),%ecx
+1: rep ; movsl
+
+ # Look for library initialization functions
+ movl $__ctors_start, %esi
+2:
+ cmpl $__ctors_end, %esi
+ jae 3f
+ call *(%esi)
+ addl $4,%esi
+ jmp 2b
+
+#
+# Run program. Note that we dont actually pass argc, argv to main...
+#
+3:
+ call main
+ pushl %eax
+ call *(__exit_handler)
+ hlt
+ .size _start, .-_start
+
+ .bss
+ .globl __entry_esp
+__entry_esp: .space 4
+ .globl __com32
+__com32: .space 4*6
diff --git a/com32/lib/sys/exit.S b/com32/lib/sys/exit.S
new file mode 100644
index 00000000..76c8b5da
--- /dev/null
+++ b/com32/lib/sys/exit.S
@@ -0,0 +1,27 @@
+# $Id$
+#
+# Implementation of _exit() for com32 based on c32entry.S
+#
+ .text
+ .globl _exit
+ .type _exit, @function
+_exit:
+ # Run any destructors
+ movl $__dtors_start, %esi
+2:
+ cmpl $__dtors_end, %esi
+ jae 1f
+ call *(%esi)
+ addl $4,%esi
+ jmp 2b
+
+1:
+ movl 4(%esp),%eax # Exit code in %eax = return value
+ movl (__entry_esp),%esp # Return stack pointer to entry value
+ ret # Return to termination address
+ .size _exit, .-_exit
+
+ .data
+__exit_handler:
+ .globl __exit_handler
+ .long _exit
diff --git a/com32/lib/sys/file.h b/com32/lib/sys/file.h
new file mode 100644
index 00000000..6a56f587
--- /dev/null
+++ b/com32/lib/sys/file.h
@@ -0,0 +1,69 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * file.h
+ *
+ * Internal implementation of file I/O for COM32
+ */
+
+#ifndef _COM32_SYS_FILE_H
+#define _COM32_SYS_FILE_H
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+/* Ordinary file */
+
+#define NFILES 32 /* Number of files to support */
+#define MAXBLOCK 16384 /* Defined by ABI */
+
+struct file_info {
+ int blocklg2; /* Blocksize log 2 */
+ size_t offset; /* Current file offset */
+ size_t length; /* Total file length */
+ uint16_t filedes; /* File descriptor */
+ uint16_t _filler; /* Unused */
+ size_t nbytes; /* Number of bytes available in buffer */
+ char *datap; /* Current data pointer */
+ char buf[MAXBLOCK];
+};
+
+extern struct file_info __file_info[NFILES];
+
+/* Special device (tty et al) */
+
+#define __DEV_MAGIC 0x504af4e7
+struct dev_info {
+ uint32_t dev_magic; /* Magic number */
+ ssize_t (*read)(int, void *, size_t);
+ ssize_t (*write)(int, const void *, size_t);
+};
+
+#endif /* _COM32_SYS_FILE_H */
diff --git a/com32/lib/sys/fileinfo.c b/com32/lib/sys/fileinfo.c
new file mode 100644
index 00000000..a1fc7c94
--- /dev/null
+++ b/com32/lib/sys/fileinfo.c
@@ -0,0 +1,3 @@
+#include "file.h"
+
+struct file_info __file_info[NFILES];
diff --git a/com32/lib/sys/open.c b/com32/lib/sys/open.c
new file mode 100644
index 00000000..3f84e5f7
--- /dev/null
+++ b/com32/lib/sys/open.c
@@ -0,0 +1,79 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <errno.h>
+#include <com32.h>
+#include <string.h>
+#include "file.h"
+
+int open(const char *pathname, int flags, mode_t mode)
+{
+ com32sys_t regs;
+ int fd;
+ struct file_info *fp;
+
+ if ( flags ) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ for ( fd = 0, fp = __file_info ; fd < NFILES ; fd++, fp++ )
+ if ( fp->blocklg2 == 0 )
+ break;
+
+ if ( fd >= NFILES ) {
+ errno = EMFILE;
+ return -1;
+ }
+
+ strlcpy(__com32.cs_bounce, pathname, __com32.cs_bounce_size);
+
+ regs.eax.w[0] = 0x0006;
+ regs.esi.w[0] = OFFS(__com32.cs_bounce);
+ regs.es = SEG(__com32.cs_bounce);
+
+ __com32.cs_intcall(0x22, &regs, &regs);
+
+ if ( (regs.eflags.l & EFLAGS_CF) || regs.esi.w[0] == 0 ) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ {
+ uint16_t blklg2;
+ asm("bsrw %1,%0" : "=r" (blklg2) : "rm" (regs.ecx.w[0]));
+ fp->blocklg2 = blklg2;
+ }
+ fp->length = regs.eax.l;
+ fp->filedes = regs.esi.w[0];
+ fp->offset = 0;
+ fp->nbytes = 0;
+ fp->datap = fp->buf;
+
+ return fd;
+}
diff --git a/com32/lib/sys/read.c b/com32/lib/sys/read.c
new file mode 100644
index 00000000..1c16ce47
--- /dev/null
+++ b/com32/lib/sys/read.c
@@ -0,0 +1,92 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * read.c
+ *
+ * Reading from a file
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <com32.h>
+#include <minmax.h>
+#include "file.h"
+
+ssize_t read(int fd, void *buf, size_t count)
+{
+ com32sys_t ireg, oreg;
+ struct file_info *fp = &__file_info[fd];
+ char *bufp = buf;
+ size_t n = 0;
+ size_t ncopy;
+
+ if ( fd >= NFILES || fp->blocklg2 == 0 ) {
+ errno = EBADF;
+ return -1;
+ }
+
+ memset(&ireg, 0, sizeof ireg);
+ ireg.eax.w[0] = 0x0007; /* Read file */
+ ireg.esi.w[0] = OFFS(__com32.cs_bounce);
+ ireg.es = SEG(__com32.cs_bounce);
+
+ while ( count ) {
+ if ( fp->nbytes == 0 ) {
+ if ( fp->offset >= fp->length || !fp->filedes )
+ return n; /* As good as it gets... */
+
+ ireg.esi.w[0] = fp->filedes;
+ ireg.ecx.w[0] = MAXBLOCK >> fp->blocklg2;
+
+ __intcall(0x22, &ireg, &oreg);
+
+ if ( oreg.eflags.l & EFLAGS_CF ) {
+ errno = EIO;
+ return -1;
+ }
+
+ fp->filedes = ireg.esi.w[0];
+ fp->nbytes = min(fp->length-fp->offset, (unsigned)MAXBLOCK);
+ fp->datap = fp->buf;
+ memcpy(fp->buf, __com32.cs_bounce, fp->nbytes);
+ }
+
+ ncopy = min(count, fp->nbytes);
+ memcpy(bufp, fp->datap, ncopy);
+
+ n += ncopy;
+ bufp += ncopy;
+ count -= ncopy;
+ fp->datap += ncopy;
+ fp->offset += ncopy;
+ fp->nbytes -= ncopy;
+ }
+
+ return n;
+}
diff --git a/com32/lib/sys/write.c b/com32/lib/sys/write.c
new file mode 100644
index 00000000..b908f362
--- /dev/null
+++ b/com32/lib/sys/write.c
@@ -0,0 +1,58 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * write.c
+ *
+ * Writing to the console
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <com32.h>
+#include <minmax.h>
+#include "file.h"
+
+ssize_t write(int fd, void *buf, size_t count)
+{
+ com32sys_t ireg;
+ struct file_info *fp = &__file_info[fd];
+ char *bufp = buf;
+ size_t n = 0;
+
+ memset(&ireg, 0, sizeof ireg);
+ ireg.eax.b[1] = 0x02;
+
+ while ( count-- ) {
+ ireg.edx.b[0] = *bufp++;
+ __intcall(0x21, &ireg, NULL);
+ n++;
+ }
+
+ return n;
+}
diff --git a/com32/lib/vfprintf.c b/com32/lib/vfprintf.c
new file mode 100644
index 00000000..39cf9838
--- /dev/null
+++ b/com32/lib/vfprintf.c
@@ -0,0 +1,26 @@
+/*
+ * vfprintf.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#define BUFFER_SIZE 32768
+
+int vfprintf(FILE *file, const char *format, va_list ap)
+{
+ int rv;
+ char buffer[BUFFER_SIZE];
+
+ rv = vsnprintf(buffer, BUFFER_SIZE, format, ap);
+
+ if ( rv < 0 )
+ return rv;
+
+ if ( rv > BUFFER_SIZE-1 )
+ rv = BUFFER_SIZE-1;
+
+ return _fwrite(buffer, rv, file);
+}
diff --git a/com32/lib/vprintf.c b/com32/lib/vprintf.c
new file mode 100644
index 00000000..7d606658
--- /dev/null
+++ b/com32/lib/vprintf.c
@@ -0,0 +1,11 @@
+/*
+ * vprintf.c
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+int vprintf(const char *format, va_list ap)
+{
+ return vfprintf(stdout, format, ap);
+}
diff --git a/com32/lib/vsnprintf.c b/com32/lib/vsnprintf.c
new file mode 100644
index 00000000..5cb93319
--- /dev/null
+++ b/com32/lib/vsnprintf.c
@@ -0,0 +1,433 @@
+/*
+ * vsnprintf.c
+ *
+ * vsnprintf(), from which the rest of the printf()
+ * family is built
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+
+enum flags {
+ FL_ZERO = 0x01, /* Zero modifier */
+ FL_MINUS = 0x02, /* Minus modifier */
+ FL_PLUS = 0x04, /* Plus modifier */
+ FL_TICK = 0x08, /* ' modifier */
+ FL_SPACE = 0x10, /* Space modifier */
+ FL_HASH = 0x20, /* # modifier */
+ FL_SIGNED = 0x40, /* Number is signed */
+ FL_UPPER = 0x80 /* Upper case digits */
+};
+
+/* These may have to be adjusted on certain implementations */
+enum ranks {
+ rank_char = -2,
+ rank_short = -1,
+ rank_int = 0,
+ rank_long = 1,
+ rank_longlong = 2
+};
+
+#define MIN_RANK rank_char
+#define MAX_RANK rank_longlong
+
+#define INTMAX_RANK rank_longlong
+#define SIZE_T_RANK rank_long
+#define PTRDIFF_T_RANK rank_long
+
+#define EMIT(x) ({ if (o<n){*q++ = (x);} o++; })
+
+static size_t
+format_int(char *q, size_t n, uintmax_t val, enum flags flags,
+ int base, int width, int prec)
+{
+ char *qq;
+ size_t o = 0, oo;
+ static const char lcdigits[] = "0123456789abcdef";
+ static const char ucdigits[] = "0123456789ABCDEF";
+ const char *digits;
+ uintmax_t tmpval;
+ int minus = 0;
+ int ndigits = 0, nchars;
+ int tickskip, b4tick;
+
+ /* Select type of digits */
+ digits = (flags & FL_UPPER) ? ucdigits : lcdigits;
+
+ /* If signed, separate out the minus */
+ if ( flags & FL_SIGNED && (intmax_t)val < 0 ) {
+ minus = 1;
+ val = (uintmax_t)(-(intmax_t)val);
+ }
+
+ /* Count the number of digits needed. This returns zero for 0. */
+ tmpval = val;
+ while ( tmpval ) {
+ tmpval /= base;
+ ndigits++;
+ }
+
+ /* Adjust ndigits for size of output */
+
+ if ( flags & FL_HASH && base == 8 ) {
+ if ( prec < ndigits+1 )
+ prec = ndigits+1;
+ }
+
+ if ( ndigits < prec ) {
+ ndigits = prec; /* Mandatory number padding */
+ } else if ( val == 0 ) {
+ ndigits = 1; /* Zero still requires space */
+ }
+
+ /* For ', figure out what the skip should be */
+ if ( flags & FL_TICK ) {
+ tickskip = (base == 16) ? 4 : 3;
+ } else {
+ tickskip = ndigits; /* No tick marks */
+ }
+
+ /* Tick marks aren't digits, but generated by the number converter */
+ ndigits += (ndigits-1)/tickskip;
+
+ /* Now compute the number of nondigits */
+ nchars = ndigits;
+
+ if ( minus || (flags & (FL_PLUS|FL_SPACE)) )
+ nchars++; /* Need space for sign */
+ if ( (flags & FL_HASH) && base == 16 ) {
+ nchars += 2; /* Add 0x for hex */
+ }
+
+ /* Emit early space padding */
+ if ( !(flags & (FL_MINUS|FL_ZERO)) && width > nchars ) {
+ while ( width > nchars ) {
+ EMIT(' ');
+ width--;
+ }
+ }
+
+ /* Emit nondigits */
+ if ( minus )
+ EMIT('-');
+ else if ( flags & FL_PLUS )
+ EMIT('+');
+ else if ( flags & FL_SPACE )
+ EMIT(' ');
+
+ if ( (flags & FL_HASH) && base == 16 ) {
+ EMIT('0');
+ EMIT((flags & FL_UPPER) ? 'X' : 'x');
+ }
+
+ /* Emit zero padding */
+ if ( (flags & (FL_MINUS|FL_ZERO)) == FL_ZERO && width > ndigits ) {
+ while ( width > nchars ) {
+ EMIT('0');
+ width--;
+ }
+ }
+
+ /* Generate the number. This is done from right to left. */
+ q += ndigits; /* Advance the pointer to end of number */
+ o += ndigits;
+ qq = q; oo = o; /* Temporary values */
+
+ b4tick = tickskip;
+ while ( ndigits > 0 ) {
+ if ( !b4tick-- ) {
+ qq--; oo--; ndigits--;
+ if ( oo < n ) *qq = '_';
+ b4tick = tickskip-1;
+ }
+ qq--; oo--; ndigits--;
+ if ( oo < n ) *qq = digits[val%base];
+ val /= base;
+ }
+
+ /* Emit late space padding */
+ while ( (flags & FL_MINUS) && width > nchars ) {
+ EMIT(' ');
+ width--;
+ }
+
+ return o;
+}
+
+
+int vsnprintf(char *buffer, size_t n, const char *format, va_list ap)
+{
+ const char *p = format;
+ char ch;
+ char *q = buffer;
+ size_t o = 0; /* Number of characters output */
+ uintmax_t val = 0;
+ int rank = rank_int; /* Default rank */
+ int width = 0;
+ int prec = -1;
+ int base;
+ size_t sz;
+ enum flags flags = 0;
+ enum {
+ st_normal, /* Ground state */
+ st_flags, /* Special flags */
+ st_width, /* Field width */
+ st_prec, /* Field precision */
+ st_modifiers /* Length or conversion modifiers */
+ } state = st_normal;
+ const char *sarg; /* %s string argument */
+ char carg; /* %c char argument */
+ int slen; /* String length */
+
+ while ( (ch = *p++) ) {
+ switch ( state ) {
+ case st_normal:
+ if ( ch == '%' ) {
+ state = st_flags;
+ flags = 0; rank = rank_int; width = 0; prec = -1;
+ } else {
+ EMIT(ch);
+ }
+ break;
+
+ case st_flags:
+ switch ( ch ) {
+ case '-':
+ flags |= FL_MINUS;
+ break;
+ case '+':
+ flags |= FL_PLUS;
+ break;
+ case '\'':
+ flags |= FL_TICK;
+ break;
+ case ' ':
+ flags |= FL_SPACE;
+ break;
+ case '#':
+ flags |= FL_HASH;
+ break;
+ case '0':
+ flags |= FL_ZERO;
+ break;
+ default:
+ state = st_width;
+ p--; /* Process this character again */
+ break;
+ }
+ break;
+
+ case st_width:
+ if ( ch >= '0' && ch <= '9' ) {
+ width = width*10+(ch-'0');
+ } else if ( ch == '*' ) {
+ width = va_arg(ap, int);
+ if ( width < 0 ) {
+ width = -width;
+ flags |= FL_MINUS;
+ }
+ } else if ( ch == '.' ) {
+ prec = 0; /* Precision given */
+ state = st_prec;
+ } else {
+ state = st_modifiers;
+ p--; /* Process this character again */
+ }
+ break;
+
+ case st_prec:
+ if ( ch >= '0' && ch <= '9' ) {
+ prec = prec*10+(ch-'0');
+ } else if ( ch == '*' ) {
+ prec = va_arg(ap, int);
+ if ( prec < 0 )
+ prec = -1;
+ } else {
+ state = st_modifiers;
+ p--; /* Process this character again */
+ }
+ break;
+
+ case st_modifiers:
+ switch ( ch ) {
+ /* Length modifiers - nonterminal sequences */
+ case 'h':
+ rank--; /* Shorter rank */
+ break;
+ case 'l':
+ rank++; /* Longer rank */
+ break;
+ case 'j':
+ rank = INTMAX_RANK;
+ break;
+ case 'z':
+ rank = SIZE_T_RANK;
+ break;
+ case 't':
+ rank = PTRDIFF_T_RANK;
+ break;
+ case 'L':
+ case 'q':
+ rank += 2;
+ break;
+ default:
+ /* Output modifiers - terminal sequences */
+ state = st_normal; /* Next state will be normal */
+ if ( rank < MIN_RANK ) /* Canonicalize rank */
+ rank = MIN_RANK;
+ else if ( rank > MAX_RANK )
+ rank = MAX_RANK;
+
+ switch ( ch ) {
+ case 'P': /* Upper case pointer */
+ flags |= FL_UPPER;
+ /* fall through */
+ case 'p': /* Pointer */
+ base = 16;
+ prec = (CHAR_BIT*sizeof(void *)+3)/4;
+ flags |= FL_HASH;
+ val = (uintmax_t)(uintptr_t)va_arg(ap, void *);
+ goto is_integer;
+
+ case 'd': /* Signed decimal output */
+ case 'i':
+ base = 10;
+ flags |= FL_SIGNED;
+ switch (rank) {
+ case rank_char:
+ /* Yes, all these casts are needed... */
+ val = (uintmax_t)(intmax_t)(signed char)va_arg(ap, signed int);
+ break;
+ case rank_short:
+ val = (uintmax_t)(intmax_t)(signed short)va_arg(ap, signed int);
+ break;
+ case rank_int:
+ val = (uintmax_t)(intmax_t)va_arg(ap, signed int);
+ break;
+ case rank_long:
+ val = (uintmax_t)(intmax_t)va_arg(ap, signed long);
+ break;
+ case rank_longlong:
+ val = (uintmax_t)(intmax_t)va_arg(ap, signed long long);
+ break;
+ }
+ goto is_integer;
+ case 'o': /* Octal */
+ base = 8;
+ goto is_unsigned;
+ case 'u': /* Unsigned decimal */
+ base = 10;
+ goto is_unsigned;
+ case 'X': /* Upper case hexadecimal */
+ flags |= FL_UPPER;
+ /* fall through */
+ case 'x': /* Hexadecimal */
+ base = 16;
+ goto is_unsigned;
+
+ is_unsigned:
+ switch (rank) {
+ case rank_char:
+ val = (uintmax_t)(unsigned char)va_arg(ap, unsigned int);
+ break;
+ case rank_short:
+ val = (uintmax_t)(unsigned short)va_arg(ap, unsigned int);
+ break;
+ case rank_int:
+ val = (uintmax_t)va_arg(ap, unsigned int);
+ break;
+ case rank_long:
+ val = (uintmax_t)va_arg(ap, unsigned long);
+ break;
+ case rank_longlong:
+ val = (uintmax_t)va_arg(ap, unsigned long long);
+ break;
+ }
+ /* fall through */
+
+ is_integer:
+ sz = format_int(q, (o<n) ? n-o : 0, val, flags, base, width, prec);
+ q += sz; o += sz;
+ break;
+
+ case 'c': /* Character */
+ carg = (char)va_arg(ap, int);
+ sarg = &carg;
+ slen = 1;
+ goto is_string;
+ case 's': /* String */
+ sarg = va_arg(ap, const char *);
+ sarg = sarg ? sarg : "(null)";
+ slen = strlen(sarg);
+ goto is_string;
+
+ is_string:
+ {
+ char sch;
+ int i;
+
+ if ( prec != -1 && slen > prec )
+ slen = prec;
+
+ if ( width > slen && !(flags & FL_MINUS) ) {
+ char pad = (flags & FL_ZERO) ? '0' : ' ';
+ while ( width > slen ) {
+ EMIT(pad);
+ width--;
+ }
+ }
+ for ( i = slen ; i ; i-- ) {
+ sch = *sarg++;
+ EMIT(sch);
+ }
+ if ( width > slen && (flags & FL_MINUS) ) {
+ while ( width > slen ) {
+ EMIT(' ');
+ width--;
+ }
+ }
+ }
+ break;
+
+ case 'n': /* Output the number of characters written */
+ {
+ switch (rank) {
+ case rank_char:
+ *va_arg(ap, signed char *) = o;
+ break;
+ case rank_short:
+ *va_arg(ap, signed short *) = o;
+ break;
+ case rank_int:
+ *va_arg(ap, signed int *) = o;
+ break;
+ case rank_long:
+ *va_arg(ap, signed long *) = o;
+ break;
+ case rank_longlong:
+ *va_arg(ap, signed long long *) = o;
+ break;
+ }
+ }
+ break;
+
+ default: /* Anything else, including % */
+ EMIT(ch);
+ break;
+ }
+ }
+ }
+ }
+
+ /* Null-terminate the string */
+ if ( o<n )
+ *q = '\0'; /* No overflow */
+ else if ( n>0 )
+ buffer[n-1] = '\0'; /* Overflow - terminate at end of buffer */
+
+ return o;
+}
diff --git a/com32/lib/vsprintf.c b/com32/lib/vsprintf.c
new file mode 100644
index 00000000..4a6100e7
--- /dev/null
+++ b/com32/lib/vsprintf.c
@@ -0,0 +1,11 @@
+/*
+ * vsprintf.c
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int vsprintf(char *buffer, const char *format, va_list ap)
+{
+ return vsnprintf(buffer, ~(size_t)0, format, ap);
+}
diff --git a/com32/lib/vsscanf.c b/com32/lib/vsscanf.c
new file mode 100644
index 00000000..12a82b27
--- /dev/null
+++ b/com32/lib/vsscanf.c
@@ -0,0 +1,365 @@
+/*
+ * vsscanf.c
+ *
+ * vsscanf(), from which the rest of the scanf()
+ * family is built
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+
+#ifndef LONG_BIT
+#define LONG_BIT (CHAR_BIT*sizeof(long))
+#endif
+
+enum flags {
+ FL_SPLAT = 0x01, /* Drop the value, do not assign */
+ FL_INV = 0x02, /* Character-set with inverse */
+ FL_WIDTH = 0x04, /* Field width specified */
+ FL_MINUS = 0x08, /* Negative number */
+};
+
+enum ranks {
+ rank_char = -2,
+ rank_short = -1,
+ rank_int = 0,
+ rank_long = 1,
+ rank_longlong = 2,
+ rank_ptr = INT_MAX /* Special value used for pointers */
+};
+
+#define MIN_RANK rank_char
+#define MAX_RANK rank_longlong
+
+#define INTMAX_RANK rank_longlong
+#define SIZE_T_RANK rank_long
+#define PTRDIFF_T_RANK rank_long
+
+enum bail {
+ bail_none = 0, /* No error condition */
+ bail_eof, /* Hit EOF */
+ bail_err /* Conversion mismatch */
+};
+
+static inline const char *
+skipspace(const char *p)
+{
+ while ( isspace((unsigned char)*p) ) p++;
+ return p;
+}
+
+#undef set_bit
+static inline void
+set_bit(unsigned long *bitmap, unsigned int bit)
+{
+ bitmap[bit/LONG_BIT] |= 1UL << (bit%LONG_BIT);
+}
+
+#undef test_bit
+static inline int
+test_bit(unsigned long *bitmap, unsigned int bit)
+{
+ return (int)(bitmap[bit/LONG_BIT] >> (bit%LONG_BIT)) & 1;
+}
+
+int vsscanf(const char *buffer, const char *format, va_list ap)
+{
+ const char *p = format;
+ char ch;
+ const char *q = buffer;
+ const char *qq;
+ uintmax_t val = 0;
+ int rank = rank_int; /* Default rank */
+ unsigned int width = UINT_MAX;
+ int base;
+ enum flags flags = 0;
+ enum {
+ st_normal, /* Ground state */
+ st_flags, /* Special flags */
+ st_width, /* Field width */
+ st_modifiers, /* Length or conversion modifiers */
+ st_match_init, /* Initial state of %[ sequence */
+ st_match, /* Main state of %[ sequence */
+ st_match_range, /* After - in a %[ sequence */
+ } state = st_normal;
+ char *sarg = NULL; /* %s %c or %[ string argument */
+ enum bail bail = bail_none;
+ int sign;
+ int converted = 0; /* Successful conversions */
+ unsigned long matchmap[((1 << CHAR_BIT)+(LONG_BIT-1))/LONG_BIT];
+ int matchinv = 0; /* Is match map inverted? */
+ unsigned char range_start = 0;
+
+ while ( (ch = *p++) && !bail ) {
+ switch ( state ) {
+ case st_normal:
+ if ( ch == '%' ) {
+ state = st_flags;
+ flags = 0; rank = rank_int; width = UINT_MAX;
+ } else if ( isspace((unsigned char)ch) ) {
+ q = skipspace(q);
+ } else {
+ if ( *q == ch )
+ q++;
+ else
+ bail = bail_err; /* Match failure */
+ }
+ break;
+
+ case st_flags:
+ switch ( ch ) {
+ case '*':
+ flags |= FL_SPLAT;
+ break;
+ case '0' ... '9':
+ width = (ch-'0');
+ state = st_width;
+ flags |= FL_WIDTH;
+ break;
+ default:
+ state = st_modifiers;
+ p--; /* Process this character again */
+ break;
+ }
+ break;
+
+ case st_width:
+ if ( ch >= '0' && ch <= '9' ) {
+ width = width*10+(ch-'0');
+ } else {
+ state = st_modifiers;
+ p--; /* Process this character again */
+ }
+ break;
+
+ case st_modifiers:
+ switch ( ch ) {
+ /* Length modifiers - nonterminal sequences */
+ case 'h':
+ rank--; /* Shorter rank */
+ break;
+ case 'l':
+ rank++; /* Longer rank */
+ break;
+ case 'j':
+ rank = INTMAX_RANK;
+ break;
+ case 'z':
+ rank = SIZE_T_RANK;
+ break;
+ case 't':
+ rank = PTRDIFF_T_RANK;
+ break;
+ case 'L':
+ case 'q':
+ rank = rank_longlong; /* long double/long long */
+ break;
+
+ default:
+ /* Output modifiers - terminal sequences */
+ state = st_normal; /* Next state will be normal */
+ if ( rank < MIN_RANK ) /* Canonicalize rank */
+ rank = MIN_RANK;
+ else if ( rank > MAX_RANK )
+ rank = MAX_RANK;
+
+ switch ( ch ) {
+ case 'P': /* Upper case pointer */
+ case 'p': /* Pointer */
+#if 0 /* Enable this to allow null pointers by name */
+ q = skipspace(q);
+ if ( !isdigit((unsigned char)*q) ) {
+ static const char * const nullnames[] =
+ { "null", "nul", "nil", "(null)", "(nul)", "(nil)", 0 };
+ const char * const *np;
+
+ /* Check to see if it's a null pointer by name */
+ for ( np = nullnames ; *np ; np++ ) {
+ if ( !strncasecmp(q, *np, strlen(*np)) ) {
+ val = (uintmax_t)((void *)NULL);
+ goto set_integer;
+ }
+ }
+ /* Failure */
+ bail = bail_err;
+ break;
+ }
+ /* else */
+#endif
+ rank = rank_ptr;
+ base = 0; sign = 0;
+ goto scan_int;
+
+ case 'i': /* Base-independent integer */
+ base = 0; sign = 1;
+ goto scan_int;
+
+ case 'd': /* Decimal integer */
+ base = 10; sign = 1;
+ goto scan_int;
+
+ case 'o': /* Octal integer */
+ base = 8; sign = 0;
+ goto scan_int;
+
+ case 'u': /* Unsigned decimal integer */
+ base = 10; sign = 0;
+ goto scan_int;
+
+ case 'x': /* Hexadecimal integer */
+ case 'X':
+ base = 16; sign = 0;
+ goto scan_int;
+
+ case 'n': /* Number of characters consumed */
+ val = (q-buffer);
+ goto set_integer;
+
+ scan_int:
+ q = skipspace(q);
+ if ( !*q ) {
+ bail = bail_eof;
+ break;
+ }
+ val = strntoumax(q, (char **)&qq, base, width);
+ if ( qq == q ) {
+ bail = bail_err;
+ break;
+ }
+ q = qq;
+ converted++;
+ /* fall through */
+
+ set_integer:
+ if ( !(flags & FL_SPLAT) ) {
+ switch(rank) {
+ case rank_char:
+ *va_arg(ap, unsigned char *) = (unsigned char)val;
+ break;
+ case rank_short:
+ *va_arg(ap, unsigned short *) = (unsigned short)val;
+ break;
+ case rank_int:
+ *va_arg(ap, unsigned int *) = (unsigned int)val;
+ break;
+ case rank_long:
+ *va_arg(ap, unsigned long *) = (unsigned long)val;
+ break;
+ case rank_longlong:
+ *va_arg(ap, unsigned long long *) = (unsigned long long)val;
+ break;
+ case rank_ptr:
+ *va_arg(ap, void **) = (void *)(uintptr_t)val;
+ break;
+ }
+ }
+ break;
+
+ case 'c': /* Character */
+ width = (flags & FL_WIDTH) ? width : 1; /* Default width == 1 */
+ sarg = va_arg(ap, char *);
+ while ( width-- ) {
+ if ( !*q ) {
+ bail = bail_eof;
+ break;
+ }
+ *sarg++ = *q++;
+ }
+ if ( !bail )
+ converted++;
+ break;
+
+ case 's': /* String */
+ {
+ char *sp;
+ sp = sarg = va_arg(ap, char *);
+ while ( width-- && *q && !isspace((unsigned char)*q) ) {
+ *sp++ = *q++;
+ }
+ if ( sarg != sp ) {
+ *sp = '\0'; /* Terminate output */
+ converted++;
+ } else {
+ bail = bail_eof;
+ }
+ }
+ break;
+
+ case '[': /* Character range */
+ sarg = va_arg(ap, char *);
+ state = st_match_init;
+ matchinv = 0;
+ memset(matchmap, 0, sizeof matchmap);
+ break;
+
+ case '%': /* %% sequence */
+ if ( *q == '%' )
+ q++;
+ else
+ bail = bail_err;
+ break;
+
+ default: /* Anything else */
+ bail = bail_err; /* Unknown sequence */
+ break;
+ }
+ }
+ break;
+
+ case st_match_init: /* Initial state for %[ match */
+ if ( ch == '^' && !(flags & FL_INV) ) {
+ matchinv = 1;
+ } else {
+ set_bit(matchmap, (unsigned char)ch);
+ state = st_match;
+ }
+ break;
+
+ case st_match: /* Main state for %[ match */
+ if ( ch == ']' ) {
+ goto match_run;
+ } else if ( ch == '-' ) {
+ range_start = (unsigned char)ch;
+ state = st_match_range;
+ } else {
+ set_bit(matchmap, (unsigned char)ch);
+ }
+ break;
+
+ case st_match_range: /* %[ match after - */
+ if ( ch == ']' ) {
+ set_bit(matchmap, (unsigned char)'-'); /* - was last character */
+ goto match_run;
+ } else {
+ int i;
+ for ( i = range_start ; i < (unsigned char)ch ; i++ )
+ set_bit(matchmap, i);
+ state = st_match;
+ }
+ break;
+
+ match_run: /* Match expression finished */
+ qq = q;
+ while ( width && *q && test_bit(matchmap, (unsigned char)*q)^matchinv ) {
+ *sarg++ = *q++;
+ }
+ if ( q != qq ) {
+ *sarg = '\0';
+ converted++;
+ } else {
+ bail = *q ? bail_err : bail_eof;
+ }
+ break;
+ }
+ }
+
+ if ( bail == bail_eof && !converted )
+ converted = -1; /* Return EOF (-1) */
+
+ return converted;
+}