summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhpa <hpa>2004-11-10 22:31:50 +0000
committerhpa <hpa>2004-11-10 22:31:50 +0000
commit17f967640cef484f83d755c9dd016a946711236f (patch)
tree00bf0c0f2926cd6a9761eb372b55d090305aca44
parentc67a2ac96611fa6aeb9ff3602c5e0c8265f1cc9d (diff)
downloadsyslinux-17f967640cef484f83d755c9dd016a946711236f.tar.gz
Very first cut at a klibc-derived C library for com32
-rw-r--r--com32/Makefile4
-rw-r--r--com32/include/bitsize/limits.h14
-rw-r--r--com32/include/bitsize/stddef.h18
-rw-r--r--com32/include/bitsize/stdint.h34
-rw-r--r--com32/include/bitsize/stdintconst.h18
-rw-r--r--com32/include/bitsize/stdintlimits.h22
-rw-r--r--com32/include/com32.h25
-rw-r--r--com32/include/ctype.h119
-rw-r--r--com32/include/errno.h135
-rw-r--r--com32/include/inttypes.h226
-rw-r--r--com32/include/klibc/compiler.h115
-rw-r--r--com32/include/klibc/extern.h14
-rw-r--r--com32/include/klibc/sysconfig.h34
-rw-r--r--com32/include/limits.h39
-rw-r--r--com32/include/malloc.h54
-rw-r--r--com32/include/minmax.h44
-rw-r--r--com32/include/stdarg.h14
-rw-r--r--com32/include/stddef.h24
-rw-r--r--com32/include/stdio.h112
-rw-r--r--com32/include/stdlib.h90
-rw-r--r--com32/include/string.h43
-rw-r--r--com32/include/sys/cpu.h78
-rw-r--r--com32/include/sys/io.h42
-rw-r--r--com32/include/sys/pci.h23
-rw-r--r--com32/include/sys/types.h16
-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
-rw-r--r--com32/modules/Makefile61
-rw-r--r--com32/modules/hello.c27
117 files changed, 4910 insertions, 4 deletions
diff --git a/com32/Makefile b/com32/Makefile
new file mode 100644
index 00000000..66b10017
--- /dev/null
+++ b/com32/Makefile
@@ -0,0 +1,4 @@
+SUBDIRS = lib modules
+
+all tidy clean spotless:
+ for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done
diff --git a/com32/include/bitsize/limits.h b/com32/include/bitsize/limits.h
new file mode 100644
index 00000000..f90e524b
--- /dev/null
+++ b/com32/include/bitsize/limits.h
@@ -0,0 +1,14 @@
+/*
+ * bits32/limits.h
+ */
+
+#ifndef _BITSIZE_LIMITS_H
+#define _BITSIZE_LIMITS_H
+
+#define LONG_BIT 32
+
+#define LONG_MIN (-2147483647L-1)
+#define LONG_MAX 2147483647L
+#define ULONG_MAX 4294967295UL
+
+#endif /* _BITSIZE_LIMITS_H */
diff --git a/com32/include/bitsize/stddef.h b/com32/include/bitsize/stddef.h
new file mode 100644
index 00000000..c486041f
--- /dev/null
+++ b/com32/include/bitsize/stddef.h
@@ -0,0 +1,18 @@
+/*
+ * bits32/stddef.h
+ */
+
+#ifndef _BITSIZE_STDDEF_H
+#define _BITSIZE_STDDEF_H
+
+#define _SIZE_T
+#if defined(__s390__) || defined(__hppa__) || defined(__cris__)
+typedef unsigned long size_t;
+#else
+typedef unsigned int size_t;
+#endif
+
+#define _PTRDIFF_T
+typedef signed int ptrdiff_t;
+
+#endif /* _BITSIZE_STDDEF_H */
diff --git a/com32/include/bitsize/stdint.h b/com32/include/bitsize/stdint.h
new file mode 100644
index 00000000..40b46496
--- /dev/null
+++ b/com32/include/bitsize/stdint.h
@@ -0,0 +1,34 @@
+/*
+ * bits32/stdint.h
+ */
+
+#ifndef _BITSIZE_STDINT_H
+#define _BITSIZE_STDINT_H
+
+typedef signed char int8_t;
+typedef short int int16_t;
+typedef int int32_t;
+typedef long long int int64_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short int uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long int uint64_t;
+
+typedef int int_fast16_t;
+typedef int int_fast32_t;
+
+typedef unsigned int uint_fast16_t;
+typedef unsigned int uint_fast32_t;
+
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+
+#define __INT64_C(c) c ## LL
+#define __UINT64_C(c) c ## ULL
+
+#define __PRI64_RANK "ll"
+#define __PRIFAST_RANK ""
+#define __PRIPTR_RANK ""
+
+#endif /* _BITSIZE_STDINT_H */
diff --git a/com32/include/bitsize/stdintconst.h b/com32/include/bitsize/stdintconst.h
new file mode 100644
index 00000000..8157dd06
--- /dev/null
+++ b/com32/include/bitsize/stdintconst.h
@@ -0,0 +1,18 @@
+/*
+ * bits32/stdintconst.h
+ */
+
+#ifndef _BITSIZE_STDINTCONST_H
+#define _BITSIZE_STDINTCONST_H
+
+#define INT_FAST16_C(c) INT32_C(c)
+#define INT_FAST32_C(c) INT32_C(c)
+
+#define UINT_FAST16_C(c) UINT32_C(c)
+#define UINT_FAST32_C(c) UINT32_C(c)
+
+#define INTPTR_C(c) INT32_C(c)
+#define UINTPTR_C(c) UINT32_C(c)
+#define PTRDIFF_C(c) INT32_C(c)
+
+#endif /* _BITSIZE_STDINTCONST_H */
diff --git a/com32/include/bitsize/stdintlimits.h b/com32/include/bitsize/stdintlimits.h
new file mode 100644
index 00000000..b44fe011
--- /dev/null
+++ b/com32/include/bitsize/stdintlimits.h
@@ -0,0 +1,22 @@
+/*
+ * bits32/stdintlimits.h
+ */
+
+#ifndef _BITSIZE_STDINTLIMITS_H
+#define _BITSIZE_STDINTLIMITS_H
+
+#define INT_FAST16_MIN INT32_MIN
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST16_MAX INT32_MAX
+#define INT_FAST32_MAX INT32_MAX
+#define UINT_FAST16_MAX UINT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+
+#define INTPTR_MIN INT32_MIN
+#define INTPTR_MAX INT32_MAX
+#define UINTPTR_MAX UINT32_MAX
+
+#define PTRDIFF_MIN INT32_MIN
+#define PTRDIFF_MAX INT32_MAX
+
+#endif /* _BITSIZE_STDINTLIMITS_H */
diff --git a/com32/include/com32.h b/com32/include/com32.h
index 2462607c..4548519f 100644
--- a/com32/include/com32.h
+++ b/com32/include/com32.h
@@ -20,7 +20,8 @@
*
* The syscall interface is:
*
- * __syscall(<interrupt #>, <source regs>, <return regs>)
+ * __intcall(interrupt_#, source_regs, return_regs)
+ * __farcall(seg, offs, source_regs, return_regs)
*/
typedef union {
uint32_t l;
@@ -75,6 +76,22 @@ extern struct com32_sys_args {
} __com32;
/*
+ * System call macros
+ */
+static inline void
+__intcall(uint8_t __i, const com32sys_t *__sr, com32sys_t *__dr)
+{
+ __com32.cs_intcall(__i, __sr, __dr);
+}
+
+static inline void
+__farcall(uint16_t __es, uint16_t __eo,
+ const com32sys_t *__sr, com32sys_t *__dr)
+{
+ __com32.cs_farcall((__es << 16) + __eo, __sr, __dr);
+}
+
+/*
* These functions convert between linear pointers in the range
* 0..0xFFFFF and real-mode style SEG:OFFS pointers. Note that a
* 32-bit linear pointer is not compatible with a SEG:OFFS pointer
@@ -82,18 +99,18 @@ extern struct com32_sys_args {
*/
static inline uint16_t SEG(void *__p)
{
- return (uint16_t)(((uint32_t)__p) >> 4);
+ return (uint16_t)(((uintptr_t)__p) >> 4);
}
static inline uint16_t OFFS(void *__p)
{
/* The double cast here is to shut up gcc */
- return (uint16_t)(uint32_t)__p & 0x000F;
+ return (uint16_t)(uintptr_t)__p & 0x000F;
}
static inline void *MK_PTR(uint16_t __seg, uint16_t __offs)
{
- return (void *)( ((uint32_t)__seg << 4) + (uint32_t)__offs );
+ return (void *)((__seg << 4) + __offs);
}
#endif /* _COM32_H */
diff --git a/com32/include/ctype.h b/com32/include/ctype.h
new file mode 100644
index 00000000..daa6a8ef
--- /dev/null
+++ b/com32/include/ctype.h
@@ -0,0 +1,119 @@
+/*
+ * ctype.h
+ *
+ * This assumes ISO 8859-1, being a reasonable superset of ASCII.
+ */
+
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+#ifndef __CTYPE_NO_INLINE
+# define __ctype_inline extern __inline__
+#else
+# define __ctype_inline
+#endif
+
+/*
+ * This relies on the following definitions:
+ *
+ * cntrl = !print
+ * alpha = upper|lower
+ * graph = punct|alpha|digit
+ * blank = '\t' || ' ' (per POSIX requirement)
+ */
+enum {
+ __ctype_upper = (1 << 0),
+ __ctype_lower = (1 << 1),
+ __ctype_digit = (1 << 2),
+ __ctype_xdigit = (1 << 3),
+ __ctype_space = (1 << 4),
+ __ctype_print = (1 << 5),
+ __ctype_punct = (1 << 6),
+ __ctype_cntrl = (1 << 7),
+};
+
+extern const unsigned char __ctypes[];
+
+__ctype_inline int isalnum(int __c)
+{
+ return __ctypes[__c+1] &
+ (__ctype_upper|__ctype_lower|__ctype_digit);
+}
+
+__ctype_inline int isalpha(int __c)
+{
+ return __ctypes[__c+1] &
+ (__ctype_upper|__ctype_lower);
+}
+
+__ctype_inline int isascii(int __c)
+{
+ return !(__c & ~0x7f);
+}
+
+__ctype_inline int isblank(int __c)
+{
+ return (__c == '\t') || (__c == ' ');
+}
+
+__ctype_inline int iscntrl(int __c)
+{
+ return __ctypes[__c+1] & __ctype_cntrl;
+}
+
+__ctype_inline int isdigit(int __c)
+{
+ return ((unsigned)__c - '0') <= 9;
+}
+
+__ctype_inline int isgraph(int __c)
+{
+ return __ctypes[__c+1] &
+ (__ctype_upper|__ctype_lower|__ctype_digit|__ctype_punct);
+}
+
+__ctype_inline int islower(int __c)
+{
+ return __ctypes[__c+1] & __ctype_lower;
+}
+
+__ctype_inline int isprint(int __c)
+{
+ return __ctypes[__c+1] & __ctype_print;
+}
+
+__ctype_inline int ispunct(int __c)
+{
+ return __ctypes[__c+1] & __ctype_punct;
+}
+
+__ctype_inline int isspace(int __c)
+{
+ return __ctypes[__c+1] & __ctype_space;
+}
+
+__ctype_inline int isupper(int __c)
+{
+ return __ctypes[__c+1] & __ctype_upper;
+}
+
+__ctype_inline int isxdigit(int __c)
+{
+ return __ctypes[__c+1] & __ctype_xdigit;
+}
+
+/* Note: this is decimal, not hex, to avoid accidental promotion to unsigned */
+#define _toupper(__c) ((__c) & ~32)
+#define _tolower(__c) ((__c) | 32)
+
+__ctype_inline int toupper(int __c)
+{
+ return islower(__c) ? _toupper(__c) : __c;
+}
+
+__ctype_inline int tolower(int __c)
+{
+ return isupper(__c) ? _tolower(__c) : __c;
+}
+
+#endif /* _CTYPE_H */
diff --git a/com32/include/errno.h b/com32/include/errno.h
new file mode 100644
index 00000000..d32f33f6
--- /dev/null
+++ b/com32/include/errno.h
@@ -0,0 +1,135 @@
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+extern int errno;
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* I/O error */
+#define ENXIO 6 /* No such device or address */
+#define E2BIG 7 /* Arg list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file number */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device or resource busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* No such device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* File table overflow */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Not a typewriter */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+#define EDOM 33 /* Math argument out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+#define EDEADLK 35 /* Resource deadlock would occur */
+#define ENAMETOOLONG 36 /* File name too long */
+#define ENOLCK 37 /* No record locks available */
+#define ENOSYS 38 /* Function not implemented */
+#define ENOTEMPTY 39 /* Directory not empty */
+#define ELOOP 40 /* Too many symbolic links encountered */
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define ENOMSG 42 /* No message of desired type */
+#define EIDRM 43 /* Identifier removed */
+#define ECHRNG 44 /* Channel number out of range */
+#define EL2NSYNC 45 /* Level 2 not synchronized */
+#define EL3HLT 46 /* Level 3 halted */
+#define EL3RST 47 /* Level 3 reset */
+#define ELNRNG 48 /* Link number out of range */
+#define EUNATCH 49 /* Protocol driver not attached */
+#define ENOCSI 50 /* No CSI structure available */
+#define EL2HLT 51 /* Level 2 halted */
+#define EBADE 52 /* Invalid exchange */
+#define EBADR 53 /* Invalid request descriptor */
+#define EXFULL 54 /* Exchange full */
+#define ENOANO 55 /* No anode */
+#define EBADRQC 56 /* Invalid request code */
+#define EBADSLT 57 /* Invalid slot */
+
+#define EDEADLOCK EDEADLK
+
+#define EBFONT 59 /* Bad font file format */
+#define ENOSTR 60 /* Device not a stream */
+#define ENODATA 61 /* No data available */
+#define ETIME 62 /* Timer expired */
+#define ENOSR 63 /* Out of streams resources */
+#define ENONET 64 /* Machine is not on the network */
+#define ENOPKG 65 /* Package not installed */
+#define EREMOTE 66 /* Object is remote */
+#define ENOLINK 67 /* Link has been severed */
+#define EADV 68 /* Advertise error */
+#define ESRMNT 69 /* Srmount error */
+#define ECOMM 70 /* Communication error on send */
+#define EPROTO 71 /* Protocol error */
+#define EMULTIHOP 72 /* Multihop attempted */
+#define EDOTDOT 73 /* RFS specific error */
+#define EBADMSG 74 /* Not a data message */
+#define EOVERFLOW 75 /* Value too large for defined data type */
+#define ENOTUNIQ 76 /* Name not unique on network */
+#define EBADFD 77 /* File descriptor in bad state */
+#define EREMCHG 78 /* Remote address changed */
+#define ELIBACC 79 /* Can not access a needed shared library */
+#define ELIBBAD 80 /* Accessing a corrupted shared library */
+#define ELIBSCN 81 /* .lib section in a.out corrupted */
+#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
+#define ELIBEXEC 83 /* Cannot exec a shared library directly */
+#define EILSEQ 84 /* Illegal byte sequence */
+#define ERESTART 85 /* Interrupted system call should be restarted */
+#define ESTRPIPE 86 /* Streams pipe error */
+#define EUSERS 87 /* Too many users */
+#define ENOTSOCK 88 /* Socket operation on non-socket */
+#define EDESTADDRREQ 89 /* Destination address required */
+#define EMSGSIZE 90 /* Message too long */
+#define EPROTOTYPE 91 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 92 /* Protocol not available */
+#define EPROTONOSUPPORT 93 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
+#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
+#define EPFNOSUPPORT 96 /* Protocol family not supported */
+#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
+#define EADDRINUSE 98 /* Address already in use */
+#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
+#define ENETDOWN 100 /* Network is down */
+#define ENETUNREACH 101 /* Network is unreachable */
+#define ENETRESET 102 /* Network dropped connection because of reset */
+#define ECONNABORTED 103 /* Software caused connection abort */
+#define ECONNRESET 104 /* Connection reset by peer */
+#define ENOBUFS 105 /* No buffer space available */
+#define EISCONN 106 /* Transport endpoint is already connected */
+#define ENOTCONN 107 /* Transport endpoint is not connected */
+#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
+#define ETOOMANYREFS 109 /* Too many references: cannot splice */
+#define ETIMEDOUT 110 /* Connection timed out */
+#define ECONNREFUSED 111 /* Connection refused */
+#define EHOSTDOWN 112 /* Host is down */
+#define EHOSTUNREACH 113 /* No route to host */
+#define EALREADY 114 /* Operation already in progress */
+#define EINPROGRESS 115 /* Operation now in progress */
+#define ESTALE 116 /* Stale NFS file handle */
+#define EUCLEAN 117 /* Structure needs cleaning */
+#define ENOTNAM 118 /* Not a XENIX named type file */
+#define ENAVAIL 119 /* No XENIX semaphores available */
+#define EISNAM 120 /* Is a named type file */
+#define EREMOTEIO 121 /* Remote I/O error */
+#define EDQUOT 122 /* Quota exceeded */
+
+#define ENOMEDIUM 123 /* No medium found */
+#define EMEDIUMTYPE 124 /* Wrong medium type */
+
+#endif /* _ERRNO_H */
+
diff --git a/com32/include/inttypes.h b/com32/include/inttypes.h
new file mode 100644
index 00000000..e00fa631
--- /dev/null
+++ b/com32/include/inttypes.h
@@ -0,0 +1,226 @@
+/*
+ * inttypes.h
+ */
+
+#ifndef _INTTYPES_H
+#define _INTTYPES_H
+
+#include <klibc/extern.h>
+#include <stdint.h>
+#include <stddef.h>
+
+static __inline__ intmax_t imaxabs(intmax_t __n)
+{
+ return (__n < (intmax_t)0) ? -__n : __n;
+}
+
+__extern intmax_t strtoimax(const char *, char **, int);
+__extern uintmax_t strtoumax(const char *, char **, int);
+
+/* extensions */
+__extern intmax_t strntoimax(const char *, char **, int, size_t);
+__extern uintmax_t strntoumax(const char *, char **, int, size_t);
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
+
+#define PRId8 "d"
+#define PRId16 "d"
+#define PRId32 "d"
+#define PRId64 __PRI64_RANK "d"
+
+#define PRIdLEAST8 "d"
+#define PRIdLEAST16 "d"
+#define PRIdLEAST32 "d"
+#define PRIdLEAST64 __PRI64_RANK "d"
+
+#define PRIdFAST8 "d"
+#define PRIdFAST16 __PRIFAST_RANK "d"
+#define PRIdFAST32 __PRIFAST_RANK "d"
+#define PRIdFAST64 __PRI64_RANK "d"
+
+#define PRIdMAX __PRI64_RANK "d"
+#define PRIdPTR __PRIPTR_RANK "d"
+
+#define PRIi8 "i"
+#define PRIi16 "i"
+#define PRIi32 "i"
+#define PRIi64 __PRI64_RANK "i"
+
+#define PRIiLEAST8 "i"
+#define PRIiLEAST16 "i"
+#define PRIiLEAST32 "i"
+#define PRIiLEAST64 __PRI64_RANK "i"
+
+#define PRIiFAST8 "i"
+#define PRIiFAST16 __PRIFAST_RANK "i"
+#define PRIiFAST32 __PRIFAST_RANK "i"
+#define PRIiFAST64 __PRI64_RANK "i"
+
+#define PRIiMAX __PRI64_RANK "i"
+#define PRIiPTR __PRIPTR_RANK "i"
+
+#define PRIo8 "o"
+#define PRIo16 "o"
+#define PRIo32 "o"
+#define PRIo64 __PRI64_RANK "o"
+
+#define PRIoLEAST8 "o"
+#define PRIoLEAST16 "o"
+#define PRIoLEAST32 "o"
+#define PRIoLEAST64 __PRI64_RANK "o"
+
+#define PRIoFAST8 "o"
+#define PRIoFAST16 __PRIFAST_RANK "o"
+#define PRIoFAST32 __PRIFAST_RANK "o"
+#define PRIoFAST64 __PRI64_RANK "o"
+
+#define PRIoMAX __PRI64_RANK "o"
+#define PRIoPTR __PRIPTR_RANK "o"
+
+#define PRIu8 "u"
+#define PRIu16 "u"
+#define PRIu32 "u"
+#define PRIu64 __PRI64_RANK "u"
+
+#define PRIuLEAST8 "u"
+#define PRIuLEAST16 "u"
+#define PRIuLEAST32 "u"
+#define PRIuLEAST64 __PRI64_RANK "u"
+
+#define PRIuFAST8 "u"
+#define PRIuFAST16 __PRIFAST_RANK "u"
+#define PRIuFAST32 __PRIFAST_RANK "u"
+#define PRIuFAST64 __PRI64_RANK "u"
+
+#define PRIuMAX __PRI64_RANK "u"
+#define PRIuPTR __PRIPTR_RANK "u"
+
+#define PRIx8 "x"
+#define PRIx16 "x"
+#define PRIx32 "x"
+#define PRIx64 __PRI64_RANK "x"
+
+#define PRIxLEAST8 "x"
+#define PRIxLEAST16 "x"
+#define PRIxLEAST32 "x"
+#define PRIxLEAST64 __PRI64_RANK "x"
+
+#define PRIxFAST8 "x"
+#define PRIxFAST16 __PRIFAST_RANK "x"
+#define PRIxFAST32 __PRIFAST_RANK "x"
+#define PRIxFAST64 __PRI64_RANK "x"
+
+#define PRIxMAX __PRI64_RANK "x"
+#define PRIxPTR __PRIPTR_RANK "x"
+
+#define PRIX8 "X"
+#define PRIX16 "X"
+#define PRIX32 "X"
+#define PRIX64 __PRI64_RANK "X"
+
+#define PRIXLEAST8 "X"
+#define PRIXLEAST16 "X"
+#define PRIXLEAST32 "X"
+#define PRIXLEAST64 __PRI64_RANK "X"
+
+#define PRIXFAST8 "X"
+#define PRIXFAST16 __PRIFAST_RANK "X"
+#define PRIXFAST32 __PRIFAST_RANK "X"
+#define PRIXFAST64 __PRI64_RANK "X"
+
+#define PRIXMAX __PRI64_RANK "X"
+#define PRIXPTR __PRIPTR_RANK "X"
+
+#define SCNd8 "hhd"
+#define SCNd16 "hd"
+#define SCNd32 "d"
+#define SCNd64 __PRI64_RANK "d"
+
+#define SCNdLEAST8 "hhd"
+#define SCNdLEAST16 "hd"
+#define SCNdLEAST32 "d"
+#define SCNdLEAST64 __PRI64_RANK "d"
+
+#define SCNdFAST8 "hhd"
+#define SCNdFAST16 __PRIFAST_RANK "d"
+#define SCNdFAST32 __PRIFAST_RANK "d"
+#define SCNdFAST64 __PRI64_RANK "d"
+
+#define SCNdMAX __PRI64_RANK "d"
+#define SCNdPTR __PRIPTR_RANK "d"
+
+#define SCNi8 "hhi"
+#define SCNi16 "hi"
+#define SCNi32 "i"
+#define SCNi64 __PRI64_RANK "i"
+
+#define SCNiLEAST8 "hhi"
+#define SCNiLEAST16 "hi"
+#define SCNiLEAST32 "i"
+#define SCNiLEAST64 __PRI64_RANK "i"
+
+#define SCNiFAST8 "hhi"
+#define SCNiFAST16 __PRIFAST_RANK "i"
+#define SCNiFAST32 __PRIFAST_RANK "i"
+#define SCNiFAST64 __PRI64_RANK "i"
+
+#define SCNiMAX __PRI64_RANK "i"
+#define SCNiPTR __PRIPTR_RANK "i"
+
+#define SCNo8 "hho"
+#define SCNo16 "ho"
+#define SCNo32 "o"
+#define SCNo64 __PRI64_RANK "o"
+
+#define SCNoLEAST8 "hho"
+#define SCNoLEAST16 "ho"
+#define SCNoLEAST32 "o"
+#define SCNoLEAST64 __PRI64_RANK "o"
+
+#define SCNoFAST8 "hho"
+#define SCNoFAST16 __PRIFAST_RANK "o"
+#define SCNoFAST32 __PRIFAST_RANK "o"
+#define SCNoFAST64 __PRI64_RANK "o"
+
+#define SCNoMAX __PRI64_RANK "o"
+#define SCNoPTR __PRIPTR_RANK "o"
+
+#define SCNu8 "hhu"
+#define SCNu16 "hu"
+#define SCNu32 "u"
+#define SCNu64 __PRI64_RANK "u"
+
+#define SCNuLEAST8 "hhu"
+#define SCNuLEAST16 "hu"
+#define SCNuLEAST32 "u"
+#define SCNuLEAST64 __PRI64_RANK "u"
+
+#define SCNuFAST8 "hhu"
+#define SCNuFAST16 __PRIFAST_RANK "u"
+#define SCNuFAST32 __PRIFAST_RANK "u"
+#define SCNuFAST64 __PRI64_RANK "u"
+
+#define SCNuMAX __PRI64_RANK "u"
+#define SCNuPTR __PRIPTR_RANK "u"
+
+#define SCNx8 "hhx"
+#define SCNx16 "hx"
+#define SCNx32 "x"
+#define SCNx64 __PRI64_RANK "x"
+
+#define SCNxLEAST8 "hhx"
+#define SCNxLEAST16 "hx"
+#define SCNxLEAST32 "x"
+#define SCNxLEAST64 __PRI64_RANK "x"
+
+#define SCNxFAST8 "hhx"
+#define SCNxFAST16 __PRIFAST_RANK "x"
+#define SCNxFAST32 __PRIFAST_RANK "x"
+#define SCNxFAST64 __PRI64_RANK "x"
+
+#define SCNxMAX __PRI64_RANK "x"
+#define SCNxPTR __PRIPTR_RANK "x"
+
+#endif
+
+#endif /* _INTTYPES_H */
diff --git a/com32/include/klibc/compiler.h b/com32/include/klibc/compiler.h
new file mode 100644
index 00000000..f8065066
--- /dev/null
+++ b/com32/include/klibc/compiler.h
@@ -0,0 +1,115 @@
+/*
+ * klibc/compiler.h
+ *
+ * Various compiler features
+ */
+
+#ifndef _KLIBC_COMPILER_H
+#define _KLIBC_COMPILER_H
+
+#define __user
+
+/* Specific calling conventions */
+/* __cdecl is used when we want varadic and non-varadic functions to have
+ the same binary calling convention. */
+#ifdef __i386__
+# ifdef __GNUC__
+# define __cdecl __attribute__((cdecl,regparm(0)))
+# else
+ /* Most other C compilers have __cdecl as a keyword */
+# endif
+#else
+# define __cdecl /* Meaningless on non-i386 */
+#endif
+
+/* How to declare a function that *must* be inlined */
+#ifdef __GNUC__
+# if __GNUC_MAJOR__ >= 3
+# define __must_inline static __inline__ __attribute__((always_inline))
+# else
+# define __must_inline extern __inline__
+# endif
+#else
+# define __must_inline inline /* Just hope this works... */
+#endif
+
+/* How to declare a function that does not return */
+#ifdef __GNUC__
+# define __noreturn void __attribute__((noreturn))
+#else
+# define __noreturn void
+#endif
+
+/* "const" function:
+
+ Many functions do not examine any values except their arguments,
+ and have no effects except the return value. Basically this is
+ just slightly more strict class than the `pure' attribute above,
+ since function is not allowed to read global memory.
+
+ Note that a function that has pointer arguments and examines the
+ data pointed to must _not_ be declared `const'. Likewise, a
+ function that calls a non-`const' function usually must not be
+ `const'. It does not make sense for a `const' function to return
+ `void'.
+*/
+#ifdef __GNUC__
+# define __constfunc __attribute__((const))
+#else
+# define __constfunc
+#endif
+#undef __attribute_const__
+#define __attribute_const__ __constfunc
+
+/* "pure" function:
+
+ Many functions have no effects except the return value and their
+ return value depends only on the parameters and/or global
+ variables. Such a function can be subject to common subexpression
+ elimination and loop optimization just as an arithmetic operator
+ would be. These functions should be declared with the attribute
+ `pure'.
+*/
+#ifdef __GNUC__
+# define __purefunc __attribute__((pure))
+#else
+# define __purefunc
+#endif
+#undef __attribute_pure__
+#define __attribute_pure__ __purefunc
+
+/* Format attribute */
+#ifdef __GNUC__
+# define __formatfunc(t,f,a) __attribute__((format(t,f,a)))
+#else
+# define __formatfunc(t,f,a)
+#endif
+
+/* malloc() function (returns unaliased pointer) */
+#if defined(__GNUC__) && (__GNUC_MAJOR__ >= 3)
+# define __mallocfunc __attribute__((malloc))
+#else
+# define __mallocfunc
+#endif
+
+/* likely/unlikely */
+#if defined(__GNUC__) && (__GNUC_MAJOR__ > 2 || (__GNUC_MAJOR__ == 2 && __GNUC_MINOR__ >= 95))
+# define __likely(x) __builtin_expect((x), 1)
+# define __unlikely(x) __builtin_expect((x), 0)
+#else
+# define __likely(x) (x)
+# define __unlikely(x) (x)
+#endif
+
+/* Possibly unused function */
+#ifdef __GNUC__
+# define __unusedfunc __attribute__((unused))
+#else
+# define __unusedfunc
+#endif
+
+/* Constructors and destructors */
+#define __constructor __attribute__((constructor))
+#define __destructor __attribute__((destructor))
+
+#endif
diff --git a/com32/include/klibc/extern.h b/com32/include/klibc/extern.h
new file mode 100644
index 00000000..f9c34672
--- /dev/null
+++ b/com32/include/klibc/extern.h
@@ -0,0 +1,14 @@
+/*
+ * klibc/extern.h
+ */
+
+#ifndef _KLIBC_EXTERN_H
+#define _KLIBC_EXTERN_H
+
+#ifdef __cplusplus
+#define __extern extern "C"
+#else
+#define __extern extern
+#endif
+
+#endif /* _KLIBC_EXTERN_H */
diff --git a/com32/include/klibc/sysconfig.h b/com32/include/klibc/sysconfig.h
new file mode 100644
index 00000000..efaaaf5c
--- /dev/null
+++ b/com32/include/klibc/sysconfig.h
@@ -0,0 +1,34 @@
+/*
+ * klibc/sysconfig.h
+ *
+ * Allows for definitions of some things which may be system-dependent
+ */
+
+#ifndef _KLIBC_SYSCONFIG_H
+#define _KLIBC_SYSCONFIG_H
+
+/*
+ * Define this to obtain memory using sbrk() instead
+ * of mmap(). This should make it friendlier on
+ * non-MMU architectures. This should become a
+ * per-architecture configurable.
+ */
+#define MALLOC_USING_SBRK
+
+/*
+ * This is the minimum chunk size we will ask the kernel for using
+ * malloc(); this should be a multiple of the page size on all
+ * architectures.
+ */
+#define MALLOC_CHUNK_SIZE 4096
+#define MALLOC_CHUNK_MASK (MALLOC_CHUNK_SIZE-1)
+
+/*
+ * This is the minimum alignment for the memory returned by sbrk().
+ * It must be a power of 2. If MALLOC_USING_SBRK is defined it should
+ * be no smaller than the size of struct arena_header in malloc.h (4
+ * pointers.)
+ */
+#define SBRK_ALIGNMENT 32
+
+#endif /* _KLIBC_SYSCONFIG_H */
diff --git a/com32/include/limits.h b/com32/include/limits.h
new file mode 100644
index 00000000..64ef974f
--- /dev/null
+++ b/com32/include/limits.h
@@ -0,0 +1,39 @@
+/*
+ * limits.h
+ */
+
+#ifndef _LIMITS_H
+#define _LIMITS_H
+
+#define CHAR_BIT 8
+#define SHRT_BIT 16
+#define INT_BIT 32
+#define LONGLONG_BIT 64
+
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+#define UCHAR_MAX 255
+
+#ifdef __CHAR_UNSIGNED__
+# define CHAR_MIN 0
+# define CHAR_MAX UCHAR_MAX
+#else
+# define CHAR_MIN SCHAR_MIN
+# define CHAR_MAX SCHAR_MAX
+#endif
+
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+#define USHRT_MAX 65535
+
+#define INT_MIN (-2147483647-1)
+#define INT_MAX 2147483647
+#define UINT_MAX 4294967295U
+
+#define LONGLONG_MIN (-9223372036854775807LL-1)
+#define LONGLONG_MAX 9223372036854775807LL
+#define ULONGLONG_MAX 18446744073709551615ULL
+
+#include <bitsize/limits.h>
+
+#endif /* _LIMITS_H */
diff --git a/com32/include/malloc.h b/com32/include/malloc.h
new file mode 100644
index 00000000..57b76526
--- /dev/null
+++ b/com32/include/malloc.h
@@ -0,0 +1,54 @@
+/*
+ * malloc.h
+ *
+ * Internals for the memory allocator
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+/*
+ * This is the minimum chunk size we will ask the kernel for; this should
+ * be a multiple of the page size on all architectures.
+ */
+#define MALLOC_CHUNK_SIZE 65536
+#define MALLOC_CHUNK_MASK (MALLOC_CHUNK_SIZE-1)
+
+/*
+ * This structure should be a power of two. This becomes the
+ * alignment unit.
+ */
+struct free_arena_header;
+
+struct arena_header {
+ size_t type;
+ size_t size; /* Also gives the location of the next entry */
+ struct free_arena_header *next, *prev;
+};
+
+#ifdef DEBUG_MALLOC
+#define ARENA_TYPE_USED 0x64e69c70
+#define ARENA_TYPE_FREE 0x012d610a
+#define ARENA_TYPE_HEAD 0x971676b5
+#define ARENA_TYPE_DEAD 0xeeeeeeee
+#else
+#define ARENA_TYPE_USED 0
+#define ARENA_TYPE_FREE 1
+#define ARENA_TYPE_HEAD 2
+#endif
+
+#define ARENA_SIZE_MASK (~(sizeof(struct arena_header)-1))
+
+#define ARENA_ALIGN_UP(p) ((char *)(((uintptr_t)(p) + ARENA_SIZE_MASK) & ARENA_SIZE_MASK))
+#define ARENA_ALIGN_DOWN(p) ((char *)((uintptr_t)(p) & ARENA_SIZE_MASK))
+
+/*
+ * This structure should be no more than twice the size of the
+ * previous structure.
+ */
+struct free_arena_header {
+ struct arena_header a;
+ struct free_arena_header *next_free, *prev_free;
+};
+
+extern struct free_arena_header __malloc_head;
diff --git a/com32/include/minmax.h b/com32/include/minmax.h
new file mode 100644
index 00000000..319db164
--- /dev/null
+++ b/com32/include/minmax.h
@@ -0,0 +1,44 @@
+#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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef _MINMAX_H
+#define _MINMAX_H
+
+/*
+ * minmax.h: Type-independent safe min/max macros
+ */
+
+#define min(x,y) ({ __typeof(x) xx = (x); \
+ __typeof(y) yy = (y); \
+ xx < yy ? xx : yy; })
+#define max(x,y) ({ __typeof(x) xx = (x); \
+ __typeof(y) yy = (y); \
+ xx > yy ? xx : yy; })
+
+#endif /* _MINMAX_H */
+
diff --git a/com32/include/stdarg.h b/com32/include/stdarg.h
new file mode 100644
index 00000000..cc324b82
--- /dev/null
+++ b/com32/include/stdarg.h
@@ -0,0 +1,14 @@
+/*
+ * stdarg.h
+ *
+ * This is just a wrapper for the gcc one, but defines va_copy()
+ * even if gcc doesn't.
+ */
+
+/* Note: the _STDARG_H macro belongs to the gcc header... */
+#include_next <stdarg.h>
+
+/* Older gcc considers this an extension, so it's double underbar only */
+#ifndef va_copy
+#define va_copy(d,s) __va_copy(d,s)
+#endif
diff --git a/com32/include/stddef.h b/com32/include/stddef.h
new file mode 100644
index 00000000..125d2352
--- /dev/null
+++ b/com32/include/stddef.h
@@ -0,0 +1,24 @@
+/*
+ * stddef.h
+ */
+
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+#ifndef __KLIBC__
+# define __KLIBC__ 1
+#endif
+
+#include <bitsize/stddef.h>
+
+#undef NULL
+#ifdef __cplusplus
+# define NULL 0
+#else
+# define NULL ((void *)0)
+#endif
+
+#undef offsetof
+#define offsetof(t,m) ((size_t)&((t *)0)->m)
+
+#endif /* _STDDEF_H */
diff --git a/com32/include/stdio.h b/com32/include/stdio.h
new file mode 100644
index 00000000..e40a3af8
--- /dev/null
+++ b/com32/include/stdio.h
@@ -0,0 +1,112 @@
+/*
+ * stdio.h
+ */
+
+#ifndef _STDIO_H
+#define _STDIO_H
+
+#include <klibc/extern.h>
+#include <stdarg.h>
+#include <stddef.h>
+
+/* This structure doesn't really exist, but it gives us something
+ to define FILE * with */
+struct _IO_file;
+typedef struct _IO_file FILE;
+
+#ifndef EOF
+# define EOF (-1)
+#endif
+
+#ifndef BUFSIZ
+# define BUFSIZ 4096
+#endif
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+/*
+ * Convert between a FILE * and a file descriptor. We don't actually
+ * have any in-memory data, so we just abuse the pointer itself to
+ * hold the data. Note, however, that for file descriptors, -1 is
+ * error and 0 is a valid value; for FILE *, NULL (0) is error and
+ * non-NULL are valid.
+ */
+static __inline__ int fileno(FILE *__f)
+{
+ /* This should really be intptr_t, but size_t should be the same size */
+ return (int)(size_t)__f - 1;
+}
+
+/* This is a macro so it can be used as initializer */
+#define __create_file(__fd) ((FILE *)(size_t)((__fd) + 1))
+
+#define stdin __create_file(0)
+#define stdout __create_file(1)
+#define stderr __create_file(2)
+
+__extern FILE *fopen(const char *, const char *);
+
+static __inline__ FILE *fdopen(int __fd, const char *__m)
+{
+ (void)__m; return __create_file(__fd);
+}
+static __inline__ int fclose(FILE *__f)
+{
+ extern int close(int);
+ return close(fileno(__f));
+}
+
+__extern int fputs(const char *, FILE *);
+__extern int puts(const char *);
+__extern int fputc(int, FILE *);
+#define putc(c,f) fputc((c),(f))
+#define putchar(c) fputc((c),stdout)
+
+__extern int fgetc(FILE *);
+__extern char * fgets(char *, int, FILE *);
+#define getc(f) fgetc(f)
+
+__extern size_t _fread(void *, size_t, FILE *);
+__extern size_t _fwrite(const void *, size_t, FILE *);
+
+#ifndef __NO_FREAD_FWRITE_INLINES
+extern __inline__ size_t
+fread(void *__p, size_t __s, size_t __n, FILE *__f)
+{
+ return _fread(__p, __s*__n, __f)/__s;
+}
+
+extern __inline__ size_t
+fwrite(void *__p, size_t __s, size_t __n, FILE *__f)
+{
+ return _fwrite(__p, __s*__n, __f)/__s;
+}
+#endif
+
+__extern int printf(const char *, ...);
+__extern int vprintf(const char *, va_list);
+__extern int fprintf(FILE *, const char *, ...);
+__extern int vfprintf(FILE *, const char *, va_list);
+__extern int sprintf(char *, const char *, ...);
+__extern int vsprintf(char *, const char *, va_list);
+__extern int snprintf(char *, size_t n, const char *, ...);
+__extern int vsnprintf(char *, size_t n, const char *, va_list);
+
+/* No buffering, so no flushing needed */
+extern __inline__ int
+fflush(FILE *__f)
+{
+ (void)__f;
+ return 0;
+}
+
+__extern int sscanf(const char *, const char *, ...);
+__extern int vsscanf(const char *, const char *, va_list);
+
+__extern void perror(const char *);
+
+__extern int rename(const char *, const char *);
+
+#endif /* _STDIO_H */
diff --git a/com32/include/stdlib.h b/com32/include/stdlib.h
new file mode 100644
index 00000000..be4e76ed
--- /dev/null
+++ b/com32/include/stdlib.h
@@ -0,0 +1,90 @@
+/*
+ * stdlib.h
+ */
+
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <stddef.h>
+
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+
+static __inline__ __noreturn _Exit(int __n) {
+ __extern __noreturn _exit(int);
+ _exit(__n);
+ for(;;); /* Some gcc versions are stupid */
+}
+__extern __noreturn abort(void);
+static __inline__ int abs(int __n) {
+ return (__n < 0) ? -__n : __n;
+}
+__extern int atexit(void (*)(void));
+__extern int on_exit(void (*)(int, void *), void *);
+__extern int atoi(const char *);
+__extern long atol(const char *);
+__extern long long atoll(const char *);
+__extern __noreturn exit(int);
+__extern void free(void *);
+static __inline__ long labs(long __n) {
+ return (__n < 0L) ? -__n : __n;
+}
+
+static __inline__ long long llabs(long long __n) {
+ return (__n < 0LL) ? -__n : __n;
+}
+
+__extern __mallocfunc void *malloc(size_t);
+__extern __mallocfunc void *calloc(size_t, size_t);
+__extern __mallocfunc void *realloc(void *, size_t);
+__extern long strtol(const char *, char **, int);
+__extern long long strtoll(const char *, char **, int);
+__extern unsigned long strtoul(const char *, char **, int);
+__extern unsigned long long strtoull(const char *, char **, int);
+
+__extern char *getenv(const char *);
+__extern int putenv(const char *);
+__extern int setenv(const char *, const char *, int);
+__extern int unsetenv(const char *);
+
+__extern void qsort(void *, size_t, size_t, int (*)(const void *, const void *));
+
+
+__extern long jrand48(unsigned short *);
+__extern long mrand48(void);
+__extern long nrand48(unsigned short *);
+__extern long lrand48(void);
+__extern unsigned short *seed48(const unsigned short *);
+__extern void srand48(long);
+
+#define RAND_MAX 0x7fffffff
+static __inline__ int rand(void) {
+ return (int)lrand48();
+}
+static __inline__ void srand(unsigned int __s) {
+ srand48(__s);
+}
+static __inline__ long random(void)
+{
+ return lrand48();
+}
+static __inline__ void srandom(unsigned int __s)
+{
+ srand48(__s);
+}
+
+/* Basic PTY functions. These only work if devpts is mounted! */
+
+__extern int unlockpt(int);
+__extern char *ptsname(int);
+__extern int getpt(void);
+
+static __inline__ int grantpt(int __fd)
+{
+ (void)__fd;
+ return 0; /* devpts does this all for us! */
+}
+
+#endif /* _STDLIB_H */
diff --git a/com32/include/string.h b/com32/include/string.h
new file mode 100644
index 00000000..3bbb217e
--- /dev/null
+++ b/com32/include/string.h
@@ -0,0 +1,43 @@
+/*
+ * string.h
+ */
+
+#ifndef _STRING_H
+#define _STRING_H
+
+#include <klibc/extern.h>
+#include <stddef.h>
+
+__extern void *memccpy(void *, const void *, int, size_t);
+__extern void *memchr(const void *, int, size_t);
+__extern int memcmp(const void *, const void *, size_t);
+__extern void *memcpy(void *, const void *, size_t);
+__extern void *memmove(void *, const void *, size_t);
+__extern void *memset(void *, int, size_t);
+__extern void *memmem(const void *, size_t, const void *, size_t);
+__extern void memswap(void *, void *, size_t);
+__extern int strcasecmp(const char *, const char *);
+__extern int strncasecmp(const char *, const char *, size_t);
+__extern char *strcat(char *, const char *);
+__extern char *strchr(const char *, int);
+__extern int strcmp(const char *, const char *);
+__extern char *strcpy(char *, const char *);
+__extern size_t strcspn(const char *, const char *);
+__extern char *strdup(const char *);
+__extern char *strndup(const char *, size_t);
+__extern char *strerror(int);
+__extern size_t strlen(const char *);
+__extern size_t strnlen(const char *, size_t);
+__extern char *strncat(char *, const char *, size_t);
+__extern size_t strlcat(char *, const char *, size_t);
+__extern int strncmp(const char *, const char *, size_t);
+__extern char *strncpy(char *, const char *, size_t);
+__extern size_t strlcpy(char *, const char *, size_t);
+__extern char *strpbrk(const char *, const char *);
+__extern char *strrchr(const char *, int);
+__extern char *strsep(char **, const char *);
+__extern size_t strspn(const char *, const char *);
+__extern char *strstr(const char *, const char *);
+__extern char *strtok(char *, const char *);
+
+#endif /* _STRING_H */
diff --git a/com32/include/sys/cpu.h b/com32/include/sys/cpu.h
new file mode 100644
index 00000000..1af2db71
--- /dev/null
+++ b/com32/include/sys/cpu.h
@@ -0,0 +1,78 @@
+#ifndef _CPU_H
+#define _CPU_H
+
+#include <inttypes.h>
+
+static inline uint64_t rdtsc(void)
+{
+ uint64_t v;
+ asm volatile("rdtsc" : "=A" (v));
+ return v;
+}
+
+static inline uint32_t rdtscl(void)
+{
+ uint32_t v;
+ asm volatile("rdtsc" : "=a" (v) : : "edx");
+ return v;
+}
+
+static inline uint32_t cpuid_eax(uint32_t level)
+{
+ uint32_t v;
+
+ asm("cpuid" : "=a" (v) : "a" (level) : "ebx", "ecx", "edx");
+ return v;
+}
+static inline uint32_t cpuid_ebx(uint32_t level)
+{
+ uint32_t v;
+
+ asm("cpuid" : "=b" (v), "+a" (level) : : "ecx", "edx");
+ return v;
+}
+static inline uint32_t cpuid_ecx(uint32_t level)
+{
+ uint32_t v;
+
+ asm("cpuid" : "=c" (v), "+a" (level) : : "ebx", "edx");
+ return v;
+}
+static inline uint32_t cpuid_edx(uint32_t level)
+{
+ uint32_t v;
+
+ asm("cpuid" : "=d" (v), "+a" (level) : : "ebx", "ecx");
+ return v;
+}
+
+static inline uint64_t rdmsr(uint32_t msr)
+{
+ uint64_t v;
+
+ asm volatile("rdmsr" : "=A" (v) : "c" (msr));
+ return v;
+}
+static inline void wrmsr(uint64_t v, uint32_t msr)
+{
+ asm volatile("wrmsr" : : "A" (v), "c" (msr));
+}
+
+static inline void cpu_relax(void)
+{
+ asm volatile("rep ; nop");
+}
+
+/* These are local cli/sti; not SMP-safe!!! */
+
+static inline void cli(void)
+{
+ asm volatile("cli");
+}
+
+static inline void sti(void)
+{
+ asm volatile("sti");
+}
+
+#endif
diff --git a/com32/include/sys/io.h b/com32/include/sys/io.h
new file mode 100644
index 00000000..460f2309
--- /dev/null
+++ b/com32/include/sys/io.h
@@ -0,0 +1,42 @@
+#ifndef _SYS_IO_H
+#define _SYS_IO_H
+
+#include <inttypes.h>
+
+static inline uint8_t inb(uint16_t p)
+{
+ uint8_t v;
+ asm volatile("inb %1,%0" : "=a" (v) : "Nd" (p));
+ return v;
+}
+
+static inline uint16_t inw(uint16_t p)
+{
+ uint16_t v;
+ asm volatile("inw %1,%0" : "=a" (v) : "Nd" (p));
+ return v;
+}
+
+static inline uint32_t inl(uint16_t p)
+{
+ uint32_t v;
+ asm volatile("inl %1,%0" : "=a" (v) : "Nd" (p));
+ return v;
+}
+
+static inline void outb(uint8_t v, uint16_t p)
+{
+ asm volatile("outb %0,%1" : : "a" (v), "Nd" (p));
+}
+
+static inline void outw(uint16_t v, uint16_t p)
+{
+ asm volatile("outw %0,%1" : : "a" (v), "Nd" (p));
+}
+
+static inline void outl(uint32_t v, uint16_t p)
+{
+ asm volatile("outl %0,%1" : : "a" (v), "Nd" (p));
+}
+
+#endif /* _SYS_IO_H */
diff --git a/com32/include/sys/pci.h b/com32/include/sys/pci.h
new file mode 100644
index 00000000..9a01cc47
--- /dev/null
+++ b/com32/include/sys/pci.h
@@ -0,0 +1,23 @@
+#ifndef _SYS_PCI_H
+#define _SYS_PCI_H
+
+#include <inttypes.h>
+#include <sys/io.h>
+
+typedef uint32_t pciaddr_t;
+
+static inline pciaddr_t pci_mkaddr(uint32_t bus, uint32_t dev,
+ uint32_t func, uint32_t reg)
+{
+ return 0x80000000 | ((bus & 0xff) << 16) | ((dev & 0x1f) << 11) |
+ ((func & 0x07) << 8) | (reg & 0xff);
+}
+
+uint8_t pci_read8(pciaddr_t a);
+uint16_t pci_read16(pciaddr_t a);
+uint32_t pci_read32(pciaddr_t a);
+void pci_write8(uint8_t v, pciaddr_t a);
+void pci_write16(uint16_t v, pciaddr_t a);
+void pci_write32(uint32_t v, pciaddr_t a);
+
+#endif /* _SYS_PCI_H */
diff --git a/com32/include/sys/types.h b/com32/include/sys/types.h
new file mode 100644
index 00000000..d7e9cba3
--- /dev/null
+++ b/com32/include/sys/types.h
@@ -0,0 +1,16 @@
+/*
+ * sys/types.h
+ */
+
+#ifndef _SYS_TYPES_H
+#define _SYS_TYPES_H
+
+#include <klibc/compiler.h>
+#include <stddef.h>
+#include <stdint.h>
+
+typedef ptrdiff_t ssize_t;
+typedef int mode_t;
+typedef int64_t off_t;
+
+#endif
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;
+}
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
new file mode 100644
index 00000000..a47e0a27
--- /dev/null
+++ b/com32/modules/Makefile
@@ -0,0 +1,61 @@
+#ident "$Id$"
+## -----------------------------------------------------------------------
+##
+## Copyright 2001-2004 H. Peter Anvin - All Rights Reserved
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+## USA; either version 2 of the License, or (at your option) any later
+## version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+##
+## samples for syslinux users
+##
+
+gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \
+ then echo $(1); else echo $(2); fi)
+
+M32 := $(call gcc_ok,-m32,)
+
+CC = gcc $(M32)
+LD = ld -m elf_i386
+AR = ar
+NASM = nasm
+RANLIB = ranlib
+CFLAGS = -W -Wall -march=i386 -Os -fomit-frame-pointer -I../com32/include
+SFLAGS = -march=i386
+LDFLAGS = -s -T ../lib/com32.ld
+OBJCOPY = objcopy
+PPMTOLSS16 = ../ppmtolss16
+LIB = ../lib/libcom32.a
+
+.SUFFIXES: .lss .c .o .elf .c32
+
+all: hello.c32
+
+.PRECIOUS: %.o
+%.o: %.S
+ $(CC) $(SFLAGS) -c -o $@ $<
+
+.PRECIOUS: %.o
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+.PRECIOUS: %.elf
+%.elf: %.o $(LIB)
+ $(LD) $(LDFLAGS) -o $@ $^
+
+%.c32: %.elf
+ $(OBJCOPY) -O binary $< $@
+
+tidy:
+ rm -f *.o *.a *.lst *.elf
+
+clean: tidy
+ rm -f *.lss *.o *.c32 *.com
+
+spotless: clean
+ rm -f *~ \#*
diff --git a/com32/modules/hello.c b/com32/modules/hello.c
new file mode 100644
index 00000000..bcb018d9
--- /dev/null
+++ b/com32/modules/hello.c
@@ -0,0 +1,27 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2002 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Bostom MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * hello.c
+ *
+ * Hello, World! using libcom32
+ */
+
+#include <stdio.h>
+
+int main(void)
+{
+ printf("Hello, World!\n");
+
+ return 0;
+}