summaryrefslogtreecommitdiffstats
path: root/firmware/libc
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2010-05-06 21:04:40 +0000
committerThomas Martitz <kugel@rockbox.org>2010-05-06 21:04:40 +0000
commit50a6ca39ad4ed01922aa4f755f0ca579788226cf (patch)
treec7881b015b220558167310345b162324c96be15a /firmware/libc
parentadb506df14aded06ed6e9ebf8540e6fd383ffd6a (diff)
downloadrockbox-50a6ca39ad4ed01922aa4f755f0ca579788226cf.tar.gz
rockbox-50a6ca39ad4ed01922aa4f755f0ca579788226cf.tar.bz2
rockbox-50a6ca39ad4ed01922aa4f755f0ca579788226cf.zip
Move c/h files implementing/defining standard library stuff into a new libc directory, also standard'ify some parts of the code base (almost entirely #include fixes).
This is to a) to cleanup firmware/common and firmware/include a bit, but also b) for Rockbox as an application which should use the host system's c library and headers, separating makes it easy to exclude our files from the build. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25850 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/libc')
-rw-r--r--firmware/libc/atoi.c57
-rw-r--r--firmware/libc/ctype.c22
-rw-r--r--firmware/libc/errno.c1
-rw-r--r--firmware/libc/include/ctype.h75
-rw-r--r--firmware/libc/include/errno.h145
-rw-r--r--firmware/libc/include/inttypes.h29
-rw-r--r--firmware/libc/include/stdint.h107
-rw-r--r--firmware/libc/include/stdio.h60
-rw-r--r--firmware/libc/include/stdlib.h58
-rw-r--r--firmware/libc/include/string.h94
-rw-r--r--firmware/libc/include/time.h49
-rw-r--r--firmware/libc/memchr.c116
-rw-r--r--firmware/libc/memcmp.c113
-rw-r--r--firmware/libc/memcpy.c117
-rw-r--r--firmware/libc/memmove.c147
-rw-r--r--firmware/libc/memset.c110
-rw-r--r--firmware/libc/mktime.c61
-rw-r--r--firmware/libc/qsort.c222
-rw-r--r--firmware/libc/random.c119
-rw-r--r--firmware/libc/sprintf.c93
-rw-r--r--firmware/libc/sscanf.c282
-rw-r--r--firmware/libc/strcat.c14
-rw-r--r--firmware/libc/strchr.c108
-rw-r--r--firmware/libc/strcmp.c106
-rw-r--r--firmware/libc/strcpy.c99
-rw-r--r--firmware/libc/strlen.c93
-rw-r--r--firmware/libc/strncmp.c122
-rw-r--r--firmware/libc/strrchr.c59
-rw-r--r--firmware/libc/strstr.c38
-rw-r--r--firmware/libc/strtok.c63
30 files changed, 2779 insertions, 0 deletions
diff --git a/firmware/libc/atoi.c b/firmware/libc/atoi.c
new file mode 100644
index 0000000000..3393839b27
--- /dev/null
+++ b/firmware/libc/atoi.c
@@ -0,0 +1,57 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Gary Czvitkovicz
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include "ctype.h"
+
+int atoi (const char *str)
+{
+ int value = 0;
+ int sign = 1;
+
+ while (isspace(*str))
+ {
+ str++;
+ }
+
+ if ('-' == *str)
+ {
+ sign = -1;
+ str++;
+ }
+ else if ('+' == *str)
+ {
+ str++;
+ }
+
+ while ('0' == *str)
+ {
+ str++;
+ }
+
+ while (isdigit(*str))
+ {
+ value = (value * 10) + (*str - '0');
+ str++;
+ }
+
+ return value * sign;
+}
diff --git a/firmware/libc/ctype.c b/firmware/libc/ctype.c
new file mode 100644
index 0000000000..6e9b4eb601
--- /dev/null
+++ b/firmware/libc/ctype.c
@@ -0,0 +1,22 @@
+#include <ctype.h>
+
+const unsigned char _ctype_[257]={
+ 0,
+ _C, _C, _C, _C, _C, _C, _C, _C,
+ _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C,
+ _C, _C, _C, _C, _C, _C, _C, _C,
+ _C, _C, _C, _C, _C, _C, _C, _C,
+ _S|_B, _P, _P, _P, _P, _P, _P, _P,
+ _P, _P, _P, _P, _P, _P, _P, _P,
+ _N, _N, _N, _N, _N, _N, _N, _N,
+ _N, _N, _P, _P, _P, _P, _P, _P,
+ _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U,
+ _U, _U, _U, _U, _U, _U, _U, _U,
+ _U, _U, _U, _U, _U, _U, _U, _U,
+ _U, _U, _U, _P, _P, _P, _P, _P,
+ _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L,
+ _L, _L, _L, _L, _L, _L, _L, _L,
+ _L, _L, _L, _L, _L, _L, _L, _L,
+ _L, _L, _L, _P, _P, _P, _P, _C
+};
+
diff --git a/firmware/libc/errno.c b/firmware/libc/errno.c
new file mode 100644
index 0000000000..6e7bb62b51
--- /dev/null
+++ b/firmware/libc/errno.c
@@ -0,0 +1 @@
+int errno;
diff --git a/firmware/libc/include/ctype.h b/firmware/libc/include/ctype.h
new file mode 100644
index 0000000000..648e06dc5c
--- /dev/null
+++ b/firmware/libc/include/ctype.h
@@ -0,0 +1,75 @@
+#ifndef _CTYPE_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define _CTYPE_H_
+
+#include "_ansi.h"
+
+int _EXFUN(isalnum, (int __c));
+int _EXFUN(isalpha, (int __c));
+int _EXFUN(iscntrl, (int __c));
+int _EXFUN(isdigit, (int __c));
+int _EXFUN(isgraph, (int __c));
+int _EXFUN(islower, (int __c));
+int _EXFUN(isprint, (int __c));
+int _EXFUN(ispunct, (int __c));
+int _EXFUN(isspace, (int __c));
+int _EXFUN(isupper, (int __c));
+int _EXFUN(isxdigit,(int __c));
+int _EXFUN(tolower, (int __c));
+int _EXFUN(toupper, (int __c));
+
+#ifndef __STRICT_ANSI__
+int _EXFUN(isascii, (int __c));
+int _EXFUN(toascii, (int __c));
+int _EXFUN(_tolower, (int __c));
+int _EXFUN(_toupper, (int __c));
+#endif
+
+#define _U 01
+#define _L 02
+#define _N 04
+#define _S 010
+#define _P 020
+#define _C 040
+#define _X 0100
+#define _B 0200
+
+#ifdef PLUGIN
+#define _ctype_ (rb->_rbctype_)
+#else
+extern const unsigned char _ctype_[257];
+#endif
+
+#ifndef __cplusplus
+#define isalpha(c) ((_ctype_+1)[(unsigned char)(c)]&(_U|_L))
+#define isupper(c) ((_ctype_+1)[(unsigned char)(c)]&_U)
+#define islower(c) ((_ctype_+1)[(unsigned char)(c)]&_L)
+#define isdigit(c) ((_ctype_+1)[(unsigned char)(c)]&_N)
+#define isxdigit(c) ((_ctype_+1)[(unsigned char)(c)]&(_X|_N))
+#define isspace(c) ((_ctype_+1)[(unsigned char)(c)]&_S)
+#define ispunct(c) ((_ctype_+1)[(unsigned char)(c)]&_P)
+#define isalnum(c) ((_ctype_+1)[(unsigned char)(c)]&(_U|_L|_N))
+#define isprint(c) ((_ctype_+1)[(unsigned char)(c)]&(_P|_U|_L|_N|_B))
+#define isgraph(c) ((_ctype_+1)[(unsigned char)(c)]&(_P|_U|_L|_N))
+#define iscntrl(c) ((_ctype_+1)[(unsigned char)(c)]&_C)
+/* Non-gcc versions will get the library versions, and will be
+ slightly slower */
+#ifdef __GNUC__
+# define toupper(c) \
+ __extension__ ({ int __x = (unsigned char) (c); islower(__x) ? (__x - 'a' + 'A') : __x;})
+# define tolower(c) \
+ __extension__ ({ int __x = (unsigned char) (c); isupper(__x) ? (__x - 'A' + 'a') : __x;})
+#endif
+#endif /* !__cplusplus */
+
+#ifndef __STRICT_ANSI__
+#define isascii(c) ((unsigned char)(c)<=0177)
+#define toascii(c) ((c)&0177)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _CTYPE_H_ */
diff --git a/firmware/libc/include/errno.h b/firmware/libc/include/errno.h
new file mode 100644
index 0000000000..6a24a1938f
--- /dev/null
+++ b/firmware/libc/include/errno.h
@@ -0,0 +1,145 @@
+/* errno is not a global variable, because that would make using it
+ non-reentrant. Instead, its address is returned by the function
+ __errno. */
+
+#if (defined(SIMULATOR)||defined(__PCTOOL__)) && !defined(__MINGW32__) && !defined(__CYGWIN__)
+
+#include "/usr/include/errno.h" /* use the host system implementation */
+
+#else /* use our own implementation */
+
+#ifndef _SYS_ERRNO_H_
+
+#ifdef PLUGIN
+#define errno (*rb->__errno)
+#else
+extern int errno;
+#endif
+
+#define EPERM 1 /* Not super-user */
+#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 children */
+#define EAGAIN 11 /* No more processes */
+#define ENOMEM 12 /* Not enough core */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Mount device 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 /* Too many open files in system */
+#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 arg out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+#define ENOMSG 35 /* No message of desired type */
+#define EIDRM 36 /* Identifier removed */
+#define ECHRNG 37 /* Channel number out of range */
+#define EL2NSYNC 38 /* Level 2 not synchronized */
+#define EL3HLT 39 /* Level 3 halted */
+#define EL3RST 40 /* Level 3 reset */
+#define ELNRNG 41 /* Link number out of range */
+#define EUNATCH 42 /* Protocol driver not attached */
+#define ENOCSI 43 /* No CSI structure available */
+#define EL2HLT 44 /* Level 2 halted */
+#define EDEADLK 45 /* Deadlock condition */
+#define ENOLCK 46 /* No record locks available */
+#define EBADE 50 /* Invalid exchange */
+#define EBADR 51 /* Invalid request descriptor */
+#define EXFULL 52 /* Exchange full */
+#define ENOANO 53 /* No anode */
+#define EBADRQC 54 /* Invalid request code */
+#define EBADSLT 55 /* Invalid slot */
+#define EDEADLOCK 56 /* File locking deadlock error */
+#define EBFONT 57 /* Bad font file fmt */
+#define ENOSTR 60 /* Device not a stream */
+#define ENODATA 61 /* No data (for no delay io) */
+#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 /* The object is remote */
+#define ENOLINK 67 /* The 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 74 /* Multihop attempted */
+#define ELBIN 75 /* Inode is remote (not really error) */
+#define EDOTDOT 76 /* Cross mount point (not really error) */
+#define EBADMSG 77 /* Trying to read unreadable message */
+#define ENOTUNIQ 80 /* Given log. name not unique */
+#define EBADFD 81 /* f.d. invalid for this operation */
+#define EREMCHG 82 /* Remote address changed */
+#define ELIBACC 83 /* Can't access a needed shared lib */
+#define ELIBBAD 84 /* Accessing a corrupted shared lib */
+#define ELIBSCN 85 /* .lib section in a.out corrupted */
+#define ELIBMAX 86 /* Attempting to link in too many libs */
+#define ELIBEXEC 87 /* Attempting to exec a shared library */
+#define ENOSYS 88 /* Function not implemented */
+#define ENMFILE 89 /* No more files */
+#define ENOTEMPTY 90 /* Directory not empty */
+#define ENAMETOOLONG 91 /* File or path name too long */
+#define ELOOP 92 /* Too many symbolic links */
+#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
+#define EPFNOSUPPORT 96 /* Protocol family not supported */
+#define ECONNRESET 104 /* Connection reset by peer */
+#define ENOBUFS 105 /* No buffer space available */
+#define EAFNOSUPPORT 106 /* Address family not supported by protocol family */
+#define EPROTOTYPE 107 /* Protocol wrong type for socket */
+#define ENOTSOCK 108 /* Socket operation on non-socket */
+#define ENOPROTOOPT 109 /* Protocol not available */
+#define ESHUTDOWN 110 /* Can't send after socket shutdown */
+#define ECONNREFUSED 111 /* Connection refused */
+#define EADDRINUSE 112 /* Address already in use */
+#define ECONNABORTED 113 /* Connection aborted */
+#define ENETUNREACH 114 /* Network is unreachable */
+#define ENETDOWN 115 /* Network interface is not configured */
+#define ETIMEDOUT 116 /* Connection timed out */
+#define EHOSTDOWN 117 /* Host is down */
+#define EHOSTUNREACH 118 /* Host is unreachable */
+#define EINPROGRESS 119 /* Connection already in progress */
+#define EALREADY 120 /* Socket already connected */
+#define EDESTADDRREQ 121 /* Destination address required */
+#define EMSGSIZE 122 /* Message too long */
+#define EPROTONOSUPPORT 123 /* Unknown protocol */
+#define ESOCKTNOSUPPORT 124 /* Socket type not supported */
+#define EADDRNOTAVAIL 125 /* Address not available */
+#define ENETRESET 126
+#define EISCONN 127 /* Socket is already connected */
+#define ENOTCONN 128 /* Socket is not connected */
+#define ETOOMANYREFS 129
+#define EPROCLIM 130
+#define EUSERS 131
+#define EDQUOT 132
+#define ESTALE 133
+#define ENOTSUP 134 /* Not supported */
+#define ENOMEDIUM 135 /* No medium (in tape drive) */
+#define ENOSHARE 136 /* No such host or network path */
+#define ECASECLASH 137 /* Filename exists with different case */
+
+/* From cygwin32. */
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+
+#define __ELASTERROR 2000 /* Users can add values starting here */
+
+#endif /* _SYS_ERRNO_H */
+#endif /* !SIMULATOR */
diff --git a/firmware/libc/include/inttypes.h b/firmware/libc/include/inttypes.h
new file mode 100644
index 0000000000..c03609c6d8
--- /dev/null
+++ b/firmware/libc/include/inttypes.h
@@ -0,0 +1,29 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2005 by Dave Chapman
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef __INTTYPES_H__
+#define __INTTYPES_H__
+
+#include <stdint.h>
+
+/* could possibly have (f)printf format specifies here */
+
+#endif /* __INTTYPES_H__ */
diff --git a/firmware/libc/include/stdint.h b/firmware/libc/include/stdint.h
new file mode 100644
index 0000000000..93f234c0e8
--- /dev/null
+++ b/firmware/libc/include/stdint.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2005 by Dave Chapman
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef __STDINT_H__
+#define __STDINT_H__
+
+#include <limits.h>
+
+/* 8 bit */
+#define INT8_MIN SCHAR_MIN
+#define INT8_MAX SCHAR_MAX
+#define UINT8_MAX UCHAR_MAX
+#define int8_t signed char
+#define uint8_t unsigned char
+
+/* 16 bit */
+#if USHRT_MAX == 0xffff
+
+#define INT16_MIN SHRT_MIN
+#define INT16_MAX SHRT_MAX
+#define UINT16_MAX USHRT_MAX
+#define int16_t short
+#define uint16_t unsigned short
+
+#endif
+
+/* 32 bit */
+#if ULONG_MAX == 0xfffffffful
+
+#define INT32_MIN LONG_MIN
+#define INT32_MAX LONG_MAX
+#define UINT32_MAX ULONG_MAX
+#define int32_t long
+#define uint32_t unsigned long
+
+#define INTPTR_MIN LONG_MIN
+#define INTPTR_MAX LONG_MAX
+#define UINTPTR_MAX ULONG_MAX
+#define intptr_t long
+#define uintptr_t unsigned long
+
+#elif UINT_MAX == 0xffffffffu
+
+#define INT32_MIN INT_MIN
+#define INT32_MAX INT_MAX
+#define UINT32_MAX UINT_MAX
+#define int32_t int
+#define uint32_t unsigned int
+
+#endif
+
+/* 64 bit */
+#ifndef LLONG_MIN
+#define LLONG_MIN ((long long)9223372036854775808ull)
+#endif
+
+#ifndef LLONG_MAX
+#define LLONG_MAX 9223372036854775807ll
+#endif
+
+#ifndef ULLONG_MAX
+#define ULLONG_MAX 18446744073709551615ull
+#endif
+
+#if ULONG_MAX == 0xffffffffffffffffull
+
+#define INT64_MIN LONG_MIN
+#define INT64_MAX LONG_MAX
+#define UINT64_MAX ULONG_MAX
+#define int64_t long
+#define uint64_t unsigned long
+
+#define INTPTR_MIN LONG_MIN
+#define INTPTR_MAX LONG_MAX
+#define UINTPTR_MAX ULONG_MAX
+#define intptr_t long
+#define uintptr_t unsigned long
+
+#else
+
+#define INT64_MIN LLONG_MIN
+#define INT64_MAX LLONG_MAX
+#define UINT64_MAX ULLONG_MAX
+#define int64_t long long
+#define uint64_t unsigned long long
+
+#endif
+
+#endif /* __STDINT_H__ */
diff --git a/firmware/libc/include/stdio.h b/firmware/libc/include/stdio.h
new file mode 100644
index 0000000000..d9a6dce55f
--- /dev/null
+++ b/firmware/libc/include/stdio.h
@@ -0,0 +1,60 @@
+#ifndef _STDIO_H_
+#define _STDIO_H_
+
+#include <_ansi.h>
+
+#define __need_size_t
+#include <stddef.h>
+
+#define __need___va_list
+#include <stdarg.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define EOF (-1)
+
+#ifndef SEEK_SET
+#define SEEK_SET 0 /* set file offset to offset */
+#endif
+#ifndef SEEK_CUR
+#define SEEK_CUR 1 /* set file offset to current plus offset */
+#endif
+#ifndef SEEK_END
+#define SEEK_END 2 /* set file offset to EOF plus offset */
+#endif
+
+#define TMP_MAX 26
+
+#ifdef __GNUC__
+#define __VALIST __gnuc_va_list
+#else
+#define __VALIST char*
+#endif
+
+int vsnprintf (char *buf, size_t size, const char *fmt, __VALIST ap);
+
+int sprintf (char *buf, const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3);
+
+int snprintf (char *buf, size_t size, const char *fmt, ...)
+ ATTRIBUTE_PRINTF(3, 4);
+
+/* callback function is called for every output character (byte) with userp and
+ * should return 0 when ch is a char other than '\0' that should stop printing */
+int vuprintf(int (*push)(void *userp, unsigned char data),
+ void *userp, const char *fmt, __VALIST ap);
+
+int sscanf(const char *s, const char *fmt, ...)
+ ATTRIBUTE_SCANF(2, 3);
+
+#ifdef SIMULATOR
+typedef void FILE;
+int vfprintf(FILE *stream, const char *format, __VALIST ap);
+#ifdef WIN32
+#define FILENAME_MAX 260 /* ugly hard-coded value of a limit that is set
+ in file.h */
+#endif
+#endif
+
+#endif /* _STDIO_H_ */
diff --git a/firmware/libc/include/stdlib.h b/firmware/libc/include/stdlib.h
new file mode 100644
index 0000000000..5f6db6da8a
--- /dev/null
+++ b/firmware/libc/include/stdlib.h
@@ -0,0 +1,58 @@
+/*
+ * stdlib.h
+ *
+ * Definitions for common types, variables, and functions.
+ */
+
+#ifndef _STDLIB_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define _STDLIB_H_
+
+#include "_ansi.h"
+
+#define __need_size_t
+#define __need_wchar_t
+#include <stddef.h>
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+
+_VOID _EXFUN(qsort,(_PTR __base, size_t __nmemb, size_t __size, int(*_compar)(const _PTR, const _PTR)));
+
+void *malloc(size_t);
+void *calloc (size_t nmemb, size_t size);
+void free(void *);
+void *realloc(void *, size_t);
+
+#define RAND_MAX INT_MAX
+
+void srand(unsigned int seed);
+int rand(void);
+
+#ifndef ABS
+#if defined(__GNUC__)
+#define ABS(a) ({typeof (a) ___a = (a); ___a < 0 ? -___a: ___a; })
+#else
+#define ABS(a) (((a) < 0) ? -(a) : (a))
+#endif /* __GNUC__ */
+#endif
+
+#define abs(x) ((int)ABS(x))
+#define labs(x) ((long)abs(x))
+
+#ifdef SIMULATOR
+void exit(int status);
+#endif
+
+int atoi (const char *str);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _STDLIB_H_ */
diff --git a/firmware/libc/include/string.h b/firmware/libc/include/string.h
new file mode 100644
index 0000000000..8986bd6a0c
--- /dev/null
+++ b/firmware/libc/include/string.h
@@ -0,0 +1,94 @@
+/*
+ * string.h
+ *
+ * Definitions for memory and string functions.
+ */
+
+#ifndef _STRING_H_
+#define _STRING_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "_ansi.h"
+
+#include <stddef.h>
+
+#if !defined(__size_t_defined)&& !defined(_SIZE_T_) && !defined(size_t) && !defined(_SIZE_T_DECLARED)
+#define __size_t_defined
+#define _SIZE_T
+#define _SIZE_T_
+#define _SIZE_T_DECLARED
+#define size_t size_t
+typedef unsigned long size_t;
+#endif
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+_PTR _EXFUN(memchr,(const _PTR, int, size_t));
+int _EXFUN(memcmp,(const _PTR, const _PTR, size_t));
+_PTR _EXFUN(memcpy,(_PTR, const _PTR, size_t));
+_PTR _EXFUN(memmove,(_PTR, const _PTR, size_t));
+_PTR _EXFUN(memset,(_PTR, int, size_t));
+char *_EXFUN(strcat,(char *, const char *));
+char *_EXFUN(strchr,(const char *, int));
+int _EXFUN(strcmp,(const char *, const char *));
+int _EXFUN(strcoll,(const char *, const char *));
+char *_EXFUN(strcpy,(char *, const char *));
+size_t _EXFUN(strcspn,(const char *, const char *));
+char *_EXFUN(strerror,(int));
+size_t _EXFUN(strlen,(const char *));
+char *_EXFUN(strncat,(char *, const char *, size_t));
+int _EXFUN(strncmp,(const char *, const char *, size_t));
+char *_EXFUN(strpbrk,(const char *, const char *));
+char *_EXFUN(strrchr,(const char *, int));
+size_t _EXFUN(strspn,(const char *, const char *));
+char *_EXFUN(strstr,(const char *, const char *));
+char *_EXFUN(strcasestr,(const char *, const char *));
+
+size_t strlcpy(char *dst, const char *src, size_t siz);
+size_t strlcat(char *dst, const char *src, size_t siz);
+
+#ifndef _REENT_ONLY
+char *_EXFUN(strtok,(char *, const char *));
+#endif
+
+size_t _EXFUN(strxfrm,(char *, const char *, size_t));
+
+#ifndef __STRICT_ANSI__
+char *_EXFUN(strtok_r,(char *, const char *, char **));
+
+_PTR _EXFUN(memccpy,(_PTR, const _PTR, int, size_t));
+int _EXFUN(strcasecmp,(const char *, const char *));
+int _EXFUN(strncasecmp,(const char *, const char *, size_t));
+
+#ifdef __CYGWIN__
+#ifndef DEFS_H /* Kludge to work around problem compiling in gdb */
+const char *_EXFUN(strsignal, (int __signo));
+#endif
+int _EXFUN(strtosigno, (const char *__name));
+#endif
+
+/* These function names are used on Windows and perhaps other systems. */
+#ifndef strcmpi
+#define strcmpi strcasecmp
+#endif
+#ifndef stricmp
+#define stricmp strcasecmp
+#endif
+#ifndef strncmpi
+#define strncmpi strncasecmp
+#endif
+#ifndef strnicmp
+#define strnicmp strncasecmp
+#endif
+
+#endif /* ! __STRICT_ANSI__ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _STRING_H_ */
diff --git a/firmware/libc/include/time.h b/firmware/libc/include/time.h
new file mode 100644
index 0000000000..912fafe7ca
--- /dev/null
+++ b/firmware/libc/include/time.h
@@ -0,0 +1,49 @@
+/*
+ * time.h
+ *
+ * Struct declaration for dealing with time.
+ */
+
+#ifndef _TIME_H_
+#define _TIME_H_
+
+#ifdef WPSEDITOR
+#include "inttypes.h"
+#include <time.h>
+#endif
+
+struct tm
+{
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+};
+
+#if !defined(_TIME_T_DEFINED) && !defined(_TIME_T_DECLARED)
+typedef long time_t;
+
+/* this define below is used by the mingw headers to prevent duplicate
+ typedefs */
+#define _TIME_T_DEFINED
+#define _TIME_T_DECLARED
+time_t time(time_t *t);
+struct tm *localtime(const time_t *timep);
+time_t mktime(struct tm *t);
+
+#endif /* SIMULATOR */
+
+#ifdef __PCTOOL__
+/* this time.h does not define struct timespec,
+ so tell sys/stat.h not to use it */
+#undef __USE_MISC
+#endif
+
+#endif /* _TIME_H_ */
+
+
diff --git a/firmware/libc/memchr.c b/firmware/libc/memchr.c
new file mode 100644
index 0000000000..26bdb9eea3
--- /dev/null
+++ b/firmware/libc/memchr.c
@@ -0,0 +1,116 @@
+/*
+FUNCTION
+ <<memchr>>---search for character in memory
+
+INDEX
+ memchr
+
+ANSI_SYNOPSIS
+ #include <string.h>
+ void * memchr(const void *<[s1]>, int <[c]>, size_t <[n]>);
+
+TRAD_SYNOPSIS
+ #include <string.h>
+ void * memchr(<[s1]>, <[c]>, <[n]>);
+ void *<[string]>;
+ int *<[c]>;
+ size_t *<[n]>;
+
+DESCRIPTION
+ This function scans the first <[n]> bytes of the memory pointed
+ to by <[s1]> for the character <[c]> (converted to a char).
+
+RETURNS
+ Returns a pointer to the matching byte, or a null pointer if
+ <[c]> does not occur in <[s1]>.
+
+PORTABILITY
+<<memchr>> is ANSI C.
+
+<<memchr>> requires no supporting OS subroutines.
+
+QUICKREF
+ memchr ansi pure
+*/
+
+#include <string.h>
+#include <limits.h>
+
+/* Nonzero if X is not aligned on a "long" boundary. */
+#define UNALIGNED(X) ((long)X & (sizeof (long) - 1))
+
+/* How many bytes are loaded each iteration of the word copy loop. */
+#define LBLOCKSIZE (sizeof (long))
+
+#if LONG_MAX == 2147483647L
+#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
+#else
+#if LONG_MAX == 9223372036854775807L
+/* Nonzero if X (a long int) contains a NULL byte. */
+#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
+#else
+#error long int is not a 32bit or 64bit type.
+#endif
+#endif
+
+/* DETECTCHAR returns nonzero if (long)X contains the byte used
+ to fill (long)MASK. */
+#define DETECTCHAR(X,MASK) (DETECTNULL(X ^ MASK))
+
+void *
+_DEFUN (memchr, (s1, i, n),
+ _CONST void *s1 _AND
+ int i _AND size_t n)
+{
+ _CONST unsigned char *s = (_CONST unsigned char *)s1;
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+ unsigned char c = (unsigned char)i;
+
+ while (n-- > 0)
+ {
+ if (*s == c)
+ {
+ return (void *)s;
+ }
+ s++;
+ }
+
+ return NULL;
+#else
+ unsigned char c = (unsigned char)i;
+ unsigned long mask,j;
+ unsigned long *aligned_addr;
+
+ if (!UNALIGNED (s))
+ {
+ mask = 0;
+ for (j = 0; j < LBLOCKSIZE; j++)
+ mask = (mask << 8) | c;
+
+ aligned_addr = (unsigned long*)s;
+ while ((!DETECTCHAR (*aligned_addr, mask)) && (n>LBLOCKSIZE))
+ {
+ aligned_addr++;
+ n -= LBLOCKSIZE;
+ }
+
+ /* The block of bytes currently pointed to by aligned_addr
+ may contain the target character or there may be less than
+ LBLOCKSIZE bytes left to search. We check the last few
+ bytes using the bytewise search. */
+
+ s = (unsigned char*)aligned_addr;
+ }
+
+ while (n-- > 0)
+ {
+ if (*s == c)
+ {
+ return (void *)s;
+ }
+ s++;
+ }
+
+ return NULL;
+#endif /* not PREFER_SIZE_OVER_SPEED */
+}
diff --git a/firmware/libc/memcmp.c b/firmware/libc/memcmp.c
new file mode 100644
index 0000000000..1535fcf5b5
--- /dev/null
+++ b/firmware/libc/memcmp.c
@@ -0,0 +1,113 @@
+/*
+FUNCTION
+ <<memcmp>>---compare two memory areas
+
+INDEX
+ memcmp
+
+ANSI_SYNOPSIS
+ #include <string.h>
+ int memcmp(const void *<[s1]>, const void *<[s2]>, size_t <[n]>);
+
+TRAD_SYNOPSIS
+ #include <string.h>
+ int memcmp(<[s1]>, <[s2]>, <[n]>)
+ void *<[s1]>;
+ void *<[s2]>;
+ size_t <[n]>;
+
+DESCRIPTION
+ This function compares not more than <[n]> characters of the
+ object pointed to by <[s1]> with the object pointed to by <[s2]>.
+
+
+RETURNS
+ The function returns an integer greater than, equal to or
+ less than zero according to whether the object pointed to by
+ <[s1]> is greater than, equal to or less than the object
+ pointed to by <[s2]>.
+
+PORTABILITY
+<<memcmp>> is ANSI C.
+
+<<memcmp>> requires no supporting OS subroutines.
+
+QUICKREF
+ memcmp ansi pure
+*/
+
+#include <string.h>
+
+
+/* Nonzero if either X or Y is not aligned on a "long" boundary. */
+#define UNALIGNED(X, Y) \
+ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
+
+/* How many bytes are copied each iteration of the word copy loop. */
+#define LBLOCKSIZE (sizeof (long))
+
+/* Threshhold for punting to the byte copier. */
+#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE)
+
+int
+_DEFUN (memcmp, (m1, m2, n),
+ _CONST _PTR m1 _AND
+ _CONST _PTR m2 _AND
+ size_t n)
+{
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+ unsigned char *s1 = (unsigned char *) m1;
+ unsigned char *s2 = (unsigned char *) m2;
+
+ while (n--)
+ {
+ if (*s1 != *s2)
+ {
+ return *s1 - *s2;
+ }
+ s1++;
+ s2++;
+ }
+ return 0;
+#else
+ unsigned char *s1 = (unsigned char *) m1;
+ unsigned char *s2 = (unsigned char *) m2;
+ unsigned long *a1;
+ unsigned long *a2;
+
+ /* If the size is too small, or either pointer is unaligned,
+ then we punt to the byte compare loop. Hopefully this will
+ not turn up in inner loops. */
+ if (!TOO_SMALL(n) && !UNALIGNED(s1,s2))
+ {
+ /* Otherwise, load and compare the blocks of memory one
+ word at a time. */
+ a1 = (unsigned long*) s1;
+ a2 = (unsigned long*) s2;
+ while (n >= LBLOCKSIZE)
+ {
+ if (*a1 != *a2)
+ break;
+ a1++;
+ a2++;
+ n -= LBLOCKSIZE;
+ }
+
+ /* check m mod LBLOCKSIZE remaining characters */
+
+ s1 = (unsigned char*)a1;
+ s2 = (unsigned char*)a2;
+ }
+
+ while (n--)
+ {
+ if (*s1 != *s2)
+ return *s1 - *s2;
+ s1++;
+ s2++;
+ }
+
+ return 0;
+#endif /* not PREFER_SIZE_OVER_SPEED */
+}
+
diff --git a/firmware/libc/memcpy.c b/firmware/libc/memcpy.c
new file mode 100644
index 0000000000..a89ac3c557
--- /dev/null
+++ b/firmware/libc/memcpy.c
@@ -0,0 +1,117 @@
+/*
+FUNCTION
+ <<memcpy>>---copy memory regions
+
+ANSI_SYNOPSIS
+ #include <string.h>
+ void* memcpy(void *<[out]>, const void *<[in]>, size_t <[n]>);
+
+TRAD_SYNOPSIS
+ void *memcpy(<[out]>, <[in]>, <[n]>
+ void *<[out]>;
+ void *<[in]>;
+ size_t <[n]>;
+
+DESCRIPTION
+ This function copies <[n]> bytes from the memory region
+ pointed to by <[in]> to the memory region pointed to by
+ <[out]>.
+
+ If the regions overlap, the behavior is undefined.
+
+RETURNS
+ <<memcpy>> returns a pointer to the first byte of the <[out]>
+ region.
+
+PORTABILITY
+<<memcpy>> is ANSI C.
+
+<<memcpy>> requires no supporting OS subroutines.
+
+QUICKREF
+ memcpy ansi pure
+ */
+
+#include "config.h"
+#include <_ansi.h>
+#include <string.h>
+
+/* Nonzero if either X or Y is not aligned on a "long" boundary. */
+#define UNALIGNED(X, Y) \
+ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
+
+/* How many bytes are copied each iteration of the 4X unrolled loop. */
+#define BIGBLOCKSIZE (sizeof (long) << 2)
+
+/* How many bytes are copied each iteration of the word copy loop. */
+#define LITTLEBLOCKSIZE (sizeof (long))
+
+/* Threshold for punting to the byte copier. */
+#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE)
+
+_PTR
+_DEFUN (memcpy, (dst0, src0, len0),
+ _PTR dst0 _AND
+ _CONST _PTR src0 _AND
+ size_t len0) ICODE_ATTR;
+
+_PTR
+_DEFUN (memcpy, (dst0, src0, len0),
+ _PTR dst0 _AND
+ _CONST _PTR src0 _AND
+ size_t len0)
+{
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+ char *dst = (char *) dst0;
+ char *src = (char *) src0;
+
+ _PTR save = dst0;
+
+ while (len0--)
+ {
+ *dst++ = *src++;
+ }
+
+ return save;
+#else
+ char *dst = dst0;
+ _CONST char *src = src0;
+ long *aligned_dst;
+ _CONST long *aligned_src;
+ unsigned int len = len0;
+
+ /* If the size is small, or either SRC or DST is unaligned,
+ then punt into the byte copy loop. This should be rare. */
+ if (!TOO_SMALL(len) && !UNALIGNED (src, dst))
+ {
+ aligned_dst = (long*)dst;
+ aligned_src = (long*)src;
+
+ /* Copy 4X long words at a time if possible. */
+ while (len >= BIGBLOCKSIZE)
+ {
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ len -= (unsigned int)BIGBLOCKSIZE;
+ }
+
+ /* Copy one long word at a time if possible. */
+ while (len >= LITTLEBLOCKSIZE)
+ {
+ *aligned_dst++ = *aligned_src++;
+ len -= LITTLEBLOCKSIZE;
+ }
+
+ /* Pick up any residual with a byte copier. */
+ dst = (char*)aligned_dst;
+ src = (char*)aligned_src;
+ }
+
+ while (len--)
+ *dst++ = *src++;
+
+ return dst0;
+#endif /* not PREFER_SIZE_OVER_SPEED */
+}
diff --git a/firmware/libc/memmove.c b/firmware/libc/memmove.c
new file mode 100644
index 0000000000..5f423964bb
--- /dev/null
+++ b/firmware/libc/memmove.c
@@ -0,0 +1,147 @@
+/*
+FUNCTION
+ <<memmove>>---move possibly overlapping memory
+
+INDEX
+ memmove
+
+ANSI_SYNOPSIS
+ #include <string.h>
+ void *memmove(void *<[dst]>, const void *<[src]>, size_t <[length]>);
+
+TRAD_SYNOPSIS
+ #include <string.h>
+ void *memmove(<[dst]>, <[src]>, <[length]>)
+ void *<[dst]>;
+ void *<[src]>;
+ size_t <[length]>;
+
+DESCRIPTION
+ This function moves <[length]> characters from the block of
+ memory starting at <<*<[src]>>> to the memory starting at
+ <<*<[dst]>>>. <<memmove>> reproduces the characters correctly
+ at <<*<[dst]>>> even if the two areas overlap.
+
+
+RETURNS
+ The function returns <[dst]> as passed.
+
+PORTABILITY
+<<memmove>> is ANSI C.
+
+<<memmove>> requires no supporting OS subroutines.
+
+QUICKREF
+ memmove ansi pure
+*/
+
+#include "config.h"
+#include <_ansi.h>
+#include <string.h>
+
+/* Nonzero if either X or Y is not aligned on a "long" boundary. */
+#define UNALIGNED(X, Y) \
+ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
+
+/* How many bytes are copied each iteration of the 4X unrolled loop. */
+#define BIGBLOCKSIZE (sizeof (long) << 2)
+
+/* How many bytes are copied each iteration of the word copy loop. */
+#define LITTLEBLOCKSIZE (sizeof (long))
+
+/* Threshhold for punting to the byte copier. */
+#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE)
+
+_PTR
+_DEFUN (memmove, (dst_void, src_void, length),
+ _PTR dst_void _AND
+ _CONST _PTR src_void _AND
+ size_t length) ICODE_ATTR;
+
+_PTR
+_DEFUN (memmove, (dst_void, src_void, length),
+ _PTR dst_void _AND
+ _CONST _PTR src_void _AND
+ size_t length)
+{
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+ char *dst = dst_void;
+ _CONST char *src = src_void;
+
+ if (src < dst && dst < src + length)
+ {
+ /* Have to copy backwards */
+ src += length;
+ dst += length;
+ while (length--)
+ {
+ *--dst = *--src;
+ }
+ }
+ else
+ {
+ while (length--)
+ {
+ *dst++ = *src++;
+ }
+ }
+
+ return dst_void;
+#else
+ char *dst = dst_void;
+ _CONST char *src = src_void;
+ long *aligned_dst;
+ _CONST long *aligned_src;
+ unsigned int len = length;
+
+ if (src < dst && dst < src + len)
+ {
+ /* Destructive overlap...have to copy backwards */
+ src += len;
+ dst += len;
+ while (len--)
+ {
+ *--dst = *--src;
+ }
+ }
+ else
+ {
+ /* Use optimizing algorithm for a non-destructive copy to closely
+ match memcpy. If the size is small or either SRC or DST is unaligned,
+ then punt into the byte copy loop. This should be rare. */
+ if (!TOO_SMALL(len) && !UNALIGNED (src, dst))
+ {
+ aligned_dst = (long*)dst;
+ aligned_src = (long*)src;
+
+ /* Copy 4X long words at a time if possible. */
+ while (len >= BIGBLOCKSIZE)
+ {
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ len -= BIGBLOCKSIZE;
+ }
+
+ /* Copy one long word at a time if possible. */
+ while (len >= LITTLEBLOCKSIZE)
+ {
+ *aligned_dst++ = *aligned_src++;
+ len -= LITTLEBLOCKSIZE;
+ }
+
+ /* Pick up any residual with a byte copier. */
+ dst = (char*)aligned_dst;
+ src = (char*)aligned_src;
+ }
+
+ while (len--)
+ {
+ *dst++ = *src++;
+ }
+ }
+
+ return dst_void;
+#endif /* not PREFER_SIZE_OVER_SPEED */
+}
diff --git a/firmware/libc/memset.c b/firmware/libc/memset.c
new file mode 100644
index 0000000000..7b8d2137e8
--- /dev/null
+++ b/firmware/libc/memset.c
@@ -0,0 +1,110 @@
+/*
+FUNCTION
+ <<memset>>---set an area of memory
+
+INDEX
+ memset
+
+ANSI_SYNOPSIS
+ #include <string.h>
+ void *memset(const void *<[dst]>, int <[c]>, size_t <[length]>);
+
+TRAD_SYNOPSIS
+ #include <string.h>
+ void *memset(<[dst]>, <[c]>, <[length]>)
+ void *<[dst]>;
+ int <[c]>;
+ size_t <[length]>;
+
+DESCRIPTION
+ This function converts the argument <[c]> into an unsigned
+ char and fills the first <[length]> characters of the array
+ pointed to by <[dst]> to the value.
+
+RETURNS
+ <<memset>> returns the value of <[m]>.
+
+PORTABILITY
+<<memset>> is ANSI C.
+
+ <<memset>> requires no supporting OS subroutines.
+
+QUICKREF
+ memset ansi pure
+*/
+
+#include <string.h>
+#include "_ansi.h"
+
+#define LBLOCKSIZE (sizeof(long))
+#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1))
+#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE)
+
+_PTR
+_DEFUN (memset, (m, c, n),
+ _PTR m _AND
+ int c _AND
+ size_t n)
+{
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+ char *s = (char *) m;
+
+ while (n-- != 0)
+ {
+ *s++ = (char) c;
+ }
+
+ return m;
+#else
+ char *s = (char *) m;
+ unsigned int i;
+ unsigned long buffer;
+ unsigned long *aligned_addr;
+
+ if (!TOO_SMALL (n) && !UNALIGNED (m))
+ {
+ /* If we get this far, we know that n is large and m is word-aligned. */
+
+ aligned_addr = (unsigned long*)m;
+
+ /* Store C into each char sized location in BUFFER so that
+ we can set large blocks quickly. */
+ c &= 0xff;
+ if (LBLOCKSIZE == 4)
+ {
+ buffer = (c << 8) | c;
+ buffer |= (buffer << 16);
+ }
+ else
+ {
+ buffer = 0;
+ for (i = 0; i < LBLOCKSIZE; i++)
+ buffer = (buffer << 8) | c;
+ }
+
+ while (n >= LBLOCKSIZE*4)
+ {
+ *aligned_addr++ = buffer;
+ *aligned_addr++ = buffer;
+ *aligned_addr++ = buffer;
+ *aligned_addr++ = buffer;
+ n -= 4*LBLOCKSIZE;
+ }
+
+ while (n >= LBLOCKSIZE)
+ {
+ *aligned_addr++ = buffer;
+ n -= LBLOCKSIZE;
+ }
+ /* Pick up the remainder with a bytewise loop. */
+ s = (char*)aligned_addr;
+ }
+
+ while (n--)
+ {
+ *s++ = (char)c;
+ }
+
+ return m;
+#endif /* not PREFER_SIZE_OVER_SPEED */
+}
diff --git a/firmware/libc/mktime.c b/firmware/libc/mktime.c
new file mode 100644
index 0000000000..a52381ede5
--- /dev/null
+++ b/firmware/libc/mktime.c
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Linus Nielsen Feltzing
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+
+#include <time.h>
+#include "config.h"
+
+#if CONFIG_RTC
+/* mktime() code taken from lynx-2.8.5 source, written
+ by Philippe De Muyter <phdm@macqel.be> */
+time_t mktime(struct tm *t)
+{
+ short month, year;
+ time_t result;
+ static int m_to_d[12] =
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+
+ month = t->tm_mon;
+ year = t->tm_year + month / 12 + 1900;
+ month %= 12;
+ if (month < 0)
+ {
+ year -= 1;
+ month += 12;
+ }
+ result = (year - 1970) * 365 + (year - 1969) / 4 + m_to_d[month];
+ result = (year - 1970) * 365 + m_to_d[month];
+ if (month <= 1)
+ year -= 1;
+ result += (year - 1968) / 4;
+ result -= (year - 1900) / 100;
+ result += (year - 1600) / 400;
+ result += t->tm_mday;
+ result -= 1;
+ result *= 24;
+ result += t->tm_hour;
+ result *= 60;
+ result += t->tm_min;
+ result *= 60;
+ result += t->tm_sec;
+ return(result);
+}
+#endif
diff --git a/firmware/libc/qsort.c b/firmware/libc/qsort.c
new file mode 100644
index 0000000000..8c4d1ad511
--- /dev/null
+++ b/firmware/libc/qsort.c
@@ -0,0 +1,222 @@
+/*
+FUNCTION
+<<qsort>>---sort an array
+
+INDEX
+ qsort
+
+ANSI_SYNOPSIS
+ #include <stdlib.h>
+ void qsort(void *<[base]>, size_t <[nmemb]>, size_t <[size]>,
+ int (*<[compar]>)(const void *, const void *) );
+
+TRAD_SYNOPSIS
+ #include <stdlib.h>
+ qsort(<[base]>, <[nmemb]>, <[size]>, <[compar]> )
+ char *<[base]>;
+ size_t <[nmemb]>;
+ size_t <[size]>;
+ int (*<[compar]>)();
+
+DESCRIPTION
+<<qsort>> sorts an array (beginning at <[base]>) of <[nmemb]> objects.
+<[size]> describes the size of each element of the array.
+
+You must supply a pointer to a comparison function, using the argument
+shown as <[compar]>. (This permits sorting objects of unknown
+properties.) Define the comparison function to accept two arguments,
+each a pointer to an element of the array starting at <[base]>. The
+result of <<(*<[compar]>)>> must be negative if the first argument is
+less than the second, zero if the two arguments match, and positive if
+the first argument is greater than the second (where ``less than'' and
+``greater than'' refer to whatever arbitrary ordering is appropriate).
+
+The array is sorted in place; that is, when <<qsort>> returns, the
+array elements beginning at <[base]> have been reordered.
+
+RETURNS
+<<qsort>> does not return a result.
+
+PORTABILITY
+<<qsort>> is required by ANSI (without specifying the sorting algorithm).
+*/
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <_ansi.h>
+#include <stdlib.h>
+
+#ifndef __GNUC__
+#define inline
+#endif
+
+static inline char *med3 _PARAMS((char *, char *, char *, int (*cmp)(const _PTR,const _PTR)));
+static inline void swapfunc _PARAMS((char *, char *, int, int));
+
+#define min(a, b) (a) < (b) ? a : b
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) { \
+ long i = (n) / sizeof (TYPE); \
+ register TYPE *pi = (TYPE *) (parmi); \
+ register TYPE *pj = (TYPE *) (parmj); \
+ do { \
+ register TYPE t = *pi; \
+ *pi++ = *pj; \
+ *pj++ = t; \
+ } while (--i > 0); \
+}
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+ es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+
+static inline void
+_DEFUN(swapfunc, (a, b, n, swaptype),
+ char *a _AND
+ char *b _AND
+ int n _AND
+ int swaptype)
+{
+ if(swaptype <= 1)
+ swapcode(long, a, b, n)
+ else
+ swapcode(char, a, b, n)
+}
+
+#define swap(a, b) \
+ if (swaptype == 0) { \
+ long t = *(long *)(a); \
+ *(long *)(a) = *(long *)(b); \
+ *(long *)(b) = t; \
+ } else \
+ swapfunc(a, b, es, swaptype)
+
+#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+static inline char *
+_DEFUN(med3, (a, b, c, cmp),
+ char *a _AND
+ char *b _AND
+ char *c _AND
+ int (*cmp)(const _PTR,const _PTR))
+{
+ return cmp(a, b) < 0 ?
+ (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
+ :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
+}
+
+void
+_DEFUN(qsort, (a, n, es, cmp),
+ void *a _AND
+ size_t n _AND
+ size_t es _AND
+ int (*cmp)(const _PTR,const _PTR))
+{
+ char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+ int d, r, swaptype, swap_cnt;
+
+loop: SWAPINIT(a, es);
+ swap_cnt = 0;
+ if (n < 7) {
+ for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
+ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+ pl -= es)
+ swap(pl, pl - es);
+ return;
+ }
+ pm = (char *) a + (n / 2) * es;
+ if (n > 7) {
+ pl = a;
+ pn = (char *) a + (n - 1) * es;
+ if (n > 40) {
+ d = (n / 8) * es;
+ pl = med3(pl, pl + d, pl + 2 * d, cmp);
+ pm = med3(pm - d, pm, pm + d, cmp);
+ pn = med3(pn - 2 * d, pn - d, pn, cmp);
+ }
+ pm = med3(pl, pm, pn, cmp);
+ }
+ swap(a, pm);
+ pa = pb = (char *) a + es;
+
+ pc = pd = (char *) a + (n - 1) * es;
+ for (;;) {
+ while (pb <= pc && (r = cmp(pb, a)) <= 0) {
+ if (r == 0) {
+ swap_cnt = 1;
+ swap(pa, pb);
+ pa += es;
+ }
+ pb += es;
+ }
+ while (pb <= pc && (r = cmp(pc, a)) >= 0) {
+ if (r == 0) {
+ swap_cnt = 1;
+ swap(pc, pd);
+ pd -= es;
+ }
+ pc -= es;
+ }
+ if (pb > pc)
+ break;
+ swap(pb, pc);
+ swap_cnt = 1;
+ pb += es;
+ pc -= es;
+ }
+ if (swap_cnt == 0) { /* Switch to insertion sort */
+ for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
+ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+ pl -= es)
+ swap(pl, pl - es);
+ return;
+ }
+
+ pn = (char *) a + n * es;
+ r = min(pa - (char *)a, pb - pa);
+ vecswap(a, pb - r, r);
+ r = min((unsigned int)(pd - pc), pn - pd - es);
+ vecswap(pb, pn - r, r);
+ if ((unsigned int)(r = pb - pa) > es)
+ qsort(a, r / es, es, cmp);
+ if ((unsigned int)(r = pd - pc) > es) {
+ /* Iterate rather than recurse to save stack space */
+ a = pn - r;
+ n = r / es;
+ goto loop;
+ }
+/* qsort(pn - r, r / es, es, cmp);*/
+}
diff --git a/firmware/libc/random.c b/firmware/libc/random.c
new file mode 100644
index 0000000000..f3efe89351
--- /dev/null
+++ b/firmware/libc/random.c
@@ -0,0 +1,119 @@
+/*
+ A C-program for MT19937, with initialization improved 2002/2/10.
+ Coded by Takuji Nishimura and Makoto Matsumoto.
+ This is a faster version by taking Shawn Cokus's optimization,
+ Matthe Bellew's simplification.
+
+ Before using, initialize the state by using srand(seed).
+
+ Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The names of its contributors may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Any feedback is very welcome.
+ http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+ email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+*/
+
+/*
+ Adapted to Rockbox by Jens Arnold
+*/
+
+#include <stdlib.h>
+
+/* Period parameters */
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908b0dfUL /* constant vector a */
+#define UMASK 0x80000000UL /* most significant w-r bits */
+#define LMASK 0x7fffffffUL /* least significant r bits */
+#define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) )
+#define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL))
+
+static unsigned long state[N]; /* the array for the state vector */
+static int left = 0;
+static unsigned long *next;
+
+/* initializes state[N] with a seed */
+void srand(unsigned int seed)
+{
+ unsigned long x = seed & 0xffffffffUL;
+ unsigned long *s = state;
+ int j;
+
+ for (*s++ = x, j = 1; j < N; j++) {
+ x = (1812433253UL * (x ^ (x >> 30)) + j) & 0xffffffffUL;
+ *s++ = x;
+ /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+ /* In the previous versions, MSBs of the seed affect */
+ /* only MSBs of the array state[]. */
+ /* 2002/01/09 modified by Makoto Matsumoto */
+ }
+ left = 1;
+}
+
+static void next_state(void)
+{
+ unsigned long *p = state;
+ int j;
+
+ /* if srand() has not been called, */
+ /* a default initial seed is used */
+ if (left < 0)
+ srand(5489UL);
+
+ left = N;
+ next = state;
+
+ for (j = N - M + 1; --j; p++)
+ *p = p[M] ^ TWIST(p[0], p[1]);
+
+ for (j = M; --j; p++)
+ *p = p[M-N] ^ TWIST(p[0], p[1]);
+
+ *p = p[M-N] ^ TWIST(p[0], state[0]);
+}
+
+/* generates a random number on [0,RAND_MAX]-interval */
+int rand(void)
+{
+ unsigned long y;
+
+ if (--left <= 0)
+ next_state();
+ y = *next++;
+
+ /* Tempering */
+ y ^= (y >> 11);
+ y ^= (y << 7) & 0x9d2c5680UL;
+ y ^= (y << 15) & 0xefc60000UL;
+ y ^= (y >> 18);
+
+ return ((unsigned int)y) >> 1;
+}
diff --git a/firmware/libc/sprintf.c b/firmware/libc/sprintf.c
new file mode 100644
index 0000000000..b02f5a2fae
--- /dev/null
+++ b/firmware/libc/sprintf.c
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Gary Czvitkovicz
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+/*
+ * Minimal printf and snprintf formatting functions
+ *
+ * These support %c %s %d and %x
+ * Field width and zero-padding flag only
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <limits.h>
+#include "format.h"
+
+/* ALSA library requires a more advanced snprintf, so let's not
+ override it in simulator for Linux. Note that Cygwin requires
+ our snprintf or it produces garbled output after a while. */
+
+struct for_snprintf {
+ unsigned char *ptr; /* where to store it */
+ size_t bytes; /* amount already stored */
+ size_t max; /* max amount to store */
+};
+
+static int sprfunc(void *ptr, unsigned char letter)
+{
+ struct for_snprintf *pr = (struct for_snprintf *)ptr;
+ if(pr->bytes < pr->max) {
+ *pr->ptr = letter;
+ pr->ptr++;
+ pr->bytes++;
+ return true;
+ }
+ return false; /* filled buffer */
+}
+
+
+int snprintf(char *buf, size_t size, const char *fmt, ...)
+{
+ bool ok;
+ va_list ap;
+ struct for_snprintf pr;
+
+ pr.ptr = (unsigned char *)buf;
+ pr.bytes = 0;
+ pr.max = size;
+
+ va_start(ap, fmt);
+ ok = format(sprfunc, &pr, fmt, ap);
+ va_end(ap);
+
+ /* make sure it ends with a trailing zero */
+ pr.ptr[(pr.bytes < pr.max) ? 0 : -1] = '\0';
+
+ return pr.bytes;
+}
+
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
+{
+ bool ok;
+ struct for_snprintf pr;
+
+ pr.ptr = (unsigned char *)buf;
+ pr.bytes = 0;
+ pr.max = size;
+
+ ok = format(sprfunc, &pr, fmt, ap);
+
+ /* make sure it ends with a trailing zero */
+ pr.ptr[(pr.bytes < pr.max) ? 0 : -1] = '\0';
+
+ return pr.bytes;
+}
diff --git a/firmware/libc/sscanf.c b/firmware/libc/sscanf.c
new file mode 100644
index 0000000000..5fbe81f3e0
--- /dev/null
+++ b/firmware/libc/sscanf.c
@@ -0,0 +1,282 @@
+#include <stdarg.h>
+#include <string.h>
+#include <stdbool.h>
+
+static inline bool isspace(char c)
+{
+ return (c == ' ') || (c == '\t') || (c == '\n');
+}
+
+static inline bool isdigit(char c)
+{
+ return (c >= '0') && (c <= '9');
+}
+
+static inline bool isxdigit(char c)
+{
+ return ((c >= '0') && (c <= '9'))
+ || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'));
+}
+
+static int parse_dec(int (*peek)(void *userp),
+ void (*pop)(void *userp),
+ void *userp,
+ long *vp)
+{
+ long v = 0;
+ int n = 0;
+ int minus = 0;
+ char ch;
+
+ if ((*peek)(userp) == '-')
+ {
+ (*pop)(userp);
+ n++;
+ minus = 1;
+ }
+
+ ch = (*peek)(userp);
+ if (!isdigit(ch))
+ return -1;
+
+ do
+ {
+ v = v * 10 + ch - '0';
+ (*pop)(userp);
+ n++;
+ ch = (*peek)(userp);
+ } while (isdigit(ch));
+
+ *vp = minus ? -v : v;
+ return n;
+}
+
+static int parse_chars(int (*peek)(void *userp),
+ void (*pop)(void *userp),
+ void *userp,
+ char *vp,
+ bool fake)
+{
+ int n = 0;
+
+ char *pt=vp;
+
+ while (!isspace((*peek)(userp)))
+ {
+ if(fake==false)
+ *(pt++) = (*peek)(userp);
+
+ n++;
+ (*pop)(userp);
+ }
+
+ if(fake==false)
+ (*pt)='\0';
+
+ return n;
+}
+
+static int parse_hex(int (*peek)(void *userp),
+ void (*pop)(void *userp),
+ void *userp,
+ unsigned long *vp)
+{
+ unsigned long v = 0;
+ int n = 0;
+ char ch;
+
+ ch = (*peek)(userp);
+ if (!isxdigit(ch))
+ return -1;
+
+ do
+ {
+ if (ch >= 'a')
+ ch = ch - 'a' + 10;
+ else if (ch >= 'A')
+ ch = ch - 'A' + 10;
+ else
+ ch = ch - '0';
+ v = v * 16 + ch;
+ (*pop)(userp);
+ n++;
+ ch = (*peek)(userp);
+ } while (isxdigit(ch));
+
+ *vp = v;
+ return n;
+}
+
+static int skip_spaces(int (*peek)(void *userp),
+ void (*pop)(void *userp),
+ void *userp)
+{
+ int n = 0;
+ while (isspace((*peek)(userp))) {
+ n++;
+ (*pop)(userp);
+ }
+ return n;
+}
+
+static int scan(int (*peek)(void *userp),
+ void (*pop)(void *userp),
+ void *userp,
+ const char *fmt,
+ va_list ap)
+{
+ char ch;
+ int n = 0;
+ int n_chars = 0;
+ int r;
+ long lval;
+ bool skip=false;
+ unsigned long ulval;
+
+ while ((ch = *fmt++) != '\0')
+ {
+ bool literal = false;
+
+ if (ch == '%')
+ {
+ ch = *fmt++;
+
+ if(ch== '*') /* We should process this, but not store it in an arguement */
+ {
+ ch=*fmt++;
+ skip=true;
+ }
+ else
+ {
+ skip=false;
+ }
+
+ switch (ch)
+ {
+ case 'x':
+ n_chars += skip_spaces(peek, pop, userp);
+ if ((r = parse_hex(peek, pop, userp, &ulval)) >= 0)
+ {
+ if(skip==false)
+ {
+ *(va_arg(ap, unsigned int *)) = ulval;
+ n++;
+ }
+ n_chars += r;
+ }
+ else
+ return n;
+ break;
+ case 'd':
+ n_chars += skip_spaces(peek, pop, userp);
+ if ((r = parse_dec(peek, pop, userp, &lval)) >= 0)
+ {
+ if(skip==false)
+ {
+ *(va_arg(ap, int *)) = lval;
+ n++;
+ }
+ n_chars += r;
+ }
+ else
+ return n;
+ break;
+ case 'n':
+ if(skip==false)
+ {
+ *(va_arg(ap, int *)) = n_chars;
+ n++;
+ }
+ break;
+ case 'l':
+ n_chars += skip_spaces(peek, pop, userp);
+ ch = *fmt++;
+ switch (ch)
+ {
+ case 'x':
+ if ((r = parse_hex(peek, pop, userp, &ulval)) >= 0)
+ {
+ if(skip==false)
+ {
+ *(va_arg(ap, unsigned long *)) = ulval;
+ n++;
+ }
+ n_chars += r;
+ }
+ else
+ return n;
+ break;
+ case 'd':
+ if ((r = parse_dec(peek, pop, userp, &lval)) >= 0)
+ {
+ if(skip==false)
+ {
+ *(va_arg(ap, long *)) = lval;
+ n++;
+ }
+ n_chars += r;
+ }
+ else
+ return n;
+ break;
+ case '\0':
+ return n;
+ default:
+ literal = true;
+ break;
+ }
+ break;
+ case 's':
+ n_chars += skip_spaces(peek, pop, userp);
+ n_chars += parse_chars(peek,pop, userp,skip?0:va_arg(ap, char *), skip );
+ if(skip==false)
+ {
+ n++;
+ }
+ break;
+ case '\0':
+ return n;
+ default:
+ literal = true;
+ break;
+ }
+ } else
+ literal = true;
+
+ if (literal)
+ {
+ n_chars += skip_spaces(peek, pop, userp);
+ if ((*peek)(userp) != ch)
+ continue;
+ else
+ {
+ (*pop)(userp);
+ n_chars++;
+ }
+ }
+ }
+ return n;
+}
+
+static int sspeek(void *userp)
+{
+ return **((char **)userp);
+}
+
+static void sspop(void *userp)
+{
+ (*((char **)userp))++;
+}
+
+int sscanf(const char *s, const char *fmt, ...)
+{
+ int r;
+ va_list ap;
+ const char *p;
+
+ p = s;
+ va_start(ap, fmt);
+ r = scan(sspeek, sspop, &p, fmt, ap);
+ va_end(ap);
+ return r;
+}
diff --git a/firmware/libc/strcat.c b/firmware/libc/strcat.c
new file mode 100644
index 0000000000..221529519c
--- /dev/null
+++ b/firmware/libc/strcat.c
@@ -0,0 +1,14 @@
+#include <string.h>
+
+char *strcat(char *s1,
+ const char *s2)
+{
+ char *s = s1;
+
+ while (*s1)
+ s1++;
+
+ while ((*s1++ = *s2++))
+ ;
+ return s;
+}
diff --git a/firmware/libc/strchr.c b/firmware/libc/strchr.c
new file mode 100644
index 0000000000..96acf5edf6
--- /dev/null
+++ b/firmware/libc/strchr.c
@@ -0,0 +1,108 @@
+/*
+FUNCTION
+ <<strchr>>---search for character in string
+
+INDEX
+ strchr
+
+ANSI_SYNOPSIS
+ #include <string.h>
+ char * strchr(const char *<[string]>, int <[c]>);
+
+TRAD_SYNOPSIS
+ #include <string.h>
+ char * strchr(<[string]>, <[c]>);
+ char *<[string]>;
+ int *<[c]>;
+
+DESCRIPTION
+ This function finds the first occurence of <[c]> (converted to
+ a char) in the string pointed to by <[string]> (including the
+ terminating null character).
+
+RETURNS
+ Returns a pointer to the located character, or a null pointer
+ if <[c]> does not occur in <[string]>.
+
+PORTABILITY
+<<strchr>> is ANSI C.
+
+<<strchr>> requires no supporting OS subroutines.
+
+QUICKREF
+ strchr ansi pure
+*/
+
+#include <string.h>
+#include <limits.h>
+
+/* Nonzero if X is not aligned on a "long" boundary. */
+#define UNALIGNED(X) ((long)X & (sizeof (long) - 1))
+
+/* How many bytes are loaded each iteration of the word copy loop. */
+#define LBLOCKSIZE (sizeof (long))
+
+#if LONG_MAX == 2147483647L
+#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
+#else
+#if LONG_MAX == 9223372036854775807L
+/* Nonzero if X (a long int) contains a NULL byte. */
+#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
+#else
+#error long int is not a 32bit or 64bit type.
+#endif
+#endif
+
+/* DETECTCHAR returns nonzero if (long)X contains the byte used
+ to fill (long)MASK. */
+#define DETECTCHAR(X,MASK) (DETECTNULL(X ^ MASK))
+
+char *
+_DEFUN (strchr, (s1, i),
+ _CONST char *s1 _AND
+ int i)
+{
+ _CONST unsigned char *s = (_CONST unsigned char *)s1;
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+ unsigned char c = (unsigned int)i;
+
+ while (*s && *s != c)
+ {
+ s++;
+ }
+
+ if (*s != c)
+ {
+ s = NULL;
+ }
+
+ return (char *) s;
+#else
+ unsigned char c = (unsigned char)i;
+ unsigned long mask,j;
+ unsigned long *aligned_addr;
+
+ if (!UNALIGNED (s))
+ {
+ mask = 0;
+ for (j = 0; j < LBLOCKSIZE; j++)
+ mask = (mask << 8) | c;
+
+ aligned_addr = (unsigned long*)s;
+ while (!DETECTNULL (*aligned_addr) && !DETECTCHAR (*aligned_addr, mask))
+ aligned_addr++;
+
+ /* The block of bytes currently pointed to by aligned_addr
+ contains either a null or the target char, or both. We
+ catch it using the bytewise search. */
+
+ s = (unsigned char*)aligned_addr;
+ }
+
+ while (*s && *s != c)
+ s++;
+ if (*s == c)
+ return (char *)s;
+ return NULL;
+#endif /* not PREFER_SIZE_OVER_SPEED */
+}
diff --git a/firmware/libc/strcmp.c b/firmware/libc/strcmp.c
new file mode 100644
index 0000000000..bbbf4b174a
--- /dev/null
+++ b/firmware/libc/strcmp.c
@@ -0,0 +1,106 @@
+/*
+FUNCTION
+ <<strcmp>>---character string compare
+
+INDEX
+ strcmp
+
+ANSI_SYNOPSIS
+ #include <string.h>
+ int strcmp(const char *<[a]>, const char *<[b]>);
+
+TRAD_SYNOPSIS
+ #include <string.h>
+ int strcmp(<[a]>, <[b]>)
+ char *<[a]>;
+ char *<[b]>;
+
+DESCRIPTION
+ <<strcmp>> compares the string at <[a]> to
+ the string at <[b]>.
+
+RETURNS
+ If <<*<[a]>>> sorts lexicographically after <<*<[b]>>>,
+ <<strcmp>> returns a number greater than zero. If the two
+ strings match, <<strcmp>> returns zero. If <<*<[a]>>>
+ sorts lexicographically before <<*<[b]>>>, <<strcmp>> returns a
+ number less than zero.
+
+PORTABILITY
+<<strcmp>> is ANSI C.
+
+<<strcmp>> requires no supporting OS subroutines.
+
+QUICKREF
+ strcmp ansi pure
+*/
+
+#include <string.h>
+#include <limits.h>
+
+/* Nonzero if either X or Y is not aligned on a "long" boundary. */
+#define UNALIGNED(X, Y) \
+ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
+
+/* DETECTNULL returns nonzero if (long)X contains a NULL byte. */
+#if LONG_MAX == 2147483647L
+#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
+#else
+#if LONG_MAX == 9223372036854775807L
+#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
+#else
+#error long int is not a 32bit or 64bit type.
+#endif
+#endif
+
+#ifndef DETECTNULL
+#error long int is not a 32bit or 64bit byte
+#endif
+
+int
+_DEFUN (strcmp, (s1, s2),
+ _CONST char *s1 _AND
+ _CONST char *s2)
+{
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+ while (*s1 != '\0' && *s1 == *s2)
+ {
+ s1++;
+ s2++;
+ }
+
+ return (*(unsigned char *) s1) - (*(unsigned char *) s2);
+#else
+ unsigned long *a1;
+ unsigned long *a2;
+
+ /* If s1 or s2 are unaligned, then compare bytes. */
+ if (!UNALIGNED (s1, s2))
+ {
+ /* If s1 and s2 are word-aligned, compare them a word at a time. */
+ a1 = (unsigned long*)s1;
+ a2 = (unsigned long*)s2;
+ while (*a1 == *a2)
+ {
+ /* To get here, *a1 == *a2, thus if we find a null in *a1,
+ then the strings must be equal, so return zero. */
+ if (DETECTNULL (*a1))
+ return 0;
+
+ a1++;
+ a2++;
+ }
+
+ /* A difference was detected in last few bytes of s1, so search bytewise */
+ s1 = (char*)a1;
+ s2 = (char*)a2;
+ }
+
+ while (*s1 != '\0' && *s1 == *s2)
+ {
+ s1++;
+ s2++;
+ }
+ return (*(unsigned char *) s1) - (*(unsigned char *) s2);
+#endif /* not PREFER_SIZE_OVER_SPEED */
+}
diff --git a/firmware/libc/strcpy.c b/firmware/libc/strcpy.c
new file mode 100644
index 0000000000..077ae73cc6
--- /dev/null
+++ b/firmware/libc/strcpy.c
@@ -0,0 +1,99 @@
+/*
+FUNCTION
+ <<strcpy>>---copy string
+
+INDEX
+ strcpy
+
+ANSI_SYNOPSIS
+ #include <string.h>
+ char *strcpy(char *<[dst]>, const char *<[src]>);
+
+TRAD_SYNOPSIS
+ #include <string.h>
+ char *strcpy(<[dst]>, <[src]>)
+ char *<[dst]>;
+ char *<[src]>;
+
+DESCRIPTION
+ <<strcpy>> copies the string pointed to by <[src]>
+ (including the terminating null character) to the array
+ pointed to by <[dst]>.
+
+RETURNS
+ This function returns the initial value of <[dst]>.
+
+PORTABILITY
+<<strcpy>> is ANSI C.
+
+<<strcpy>> requires no supporting OS subroutines.
+
+QUICKREF
+ strcpy ansi pure
+*/
+
+#include <string.h>
+#include <limits.h>
+
+/*SUPPRESS 560*/
+/*SUPPRESS 530*/
+
+/* Nonzero if either X or Y is not aligned on a "long" boundary. */
+#define UNALIGNED(X, Y) \
+ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
+
+#if LONG_MAX == 2147483647L
+#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
+#else
+#if LONG_MAX == 9223372036854775807L
+/* Nonzero if X (a long int) contains a NULL byte. */
+#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
+#else
+#error long int is not a 32bit or 64bit type.
+#endif
+#endif
+
+#ifndef DETECTNULL
+#error long int is not a 32bit or 64bit byte
+#endif
+
+char*
+_DEFUN (strcpy, (dst0, src0),
+ char *dst0 _AND
+ _CONST char *src0)
+{
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+ char *s = dst0;
+
+ while ((*dst0++ = *src0++))
+ ;
+
+ return s;
+#else
+ char *dst = dst0;
+ _CONST char *src = src0;
+ long *aligned_dst;
+ _CONST long *aligned_src;
+
+ /* If SRC or DEST is unaligned, then copy bytes. */
+ if (!UNALIGNED (src, dst))
+ {
+ aligned_dst = (long*)dst;
+ aligned_src = (long*)src;
+
+ /* SRC and DEST are both "long int" aligned, try to do "long int"
+ sized copies. */
+ while (!DETECTNULL(*aligned_src))
+ {
+ *aligned_dst++ = *aligned_src++;
+ }
+
+ dst = (char*)aligned_dst;
+ src = (char*)aligned_src;
+ }
+
+ while ((*dst++ = *src++))
+ ;
+ return dst0;
+#endif /* not PREFER_SIZE_OVER_SPEED */
+}
diff --git a/firmware/libc/strlen.c b/firmware/libc/strlen.c
new file mode 100644
index 0000000000..4d33eafce6
--- /dev/null
+++ b/firmware/libc/strlen.c
@@ -0,0 +1,93 @@
+/*
+FUNCTION
+ <<strlen>>---character string length
+
+INDEX
+ strlen
+
+ANSI_SYNOPSIS
+ #include <string.h>
+ size_t strlen(const char *<[str]>);
+
+TRAD_SYNOPSIS
+ #include <string.h>
+ size_t strlen(<[str]>)
+ char *<[src]>;
+
+DESCRIPTION
+ The <<strlen>> function works out the length of the string
+ starting at <<*<[str]>>> by counting chararacters until it
+ reaches a <<NULL>> character.
+
+RETURNS
+ <<strlen>> returns the character count.
+
+PORTABILITY
+<<strlen>> is ANSI C.
+
+<<strlen>> requires no supporting OS subroutines.
+
+QUICKREF
+ strlen ansi pure
+*/
+
+#include "config.h"
+#include <_ansi.h>
+#include <string.h>
+#include <limits.h>
+
+#define LBLOCKSIZE (sizeof (long))
+#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1))
+
+#if LONG_MAX == 2147483647L
+#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
+#else
+#if LONG_MAX == 9223372036854775807L
+/* Nonzero if X (a long int) contains a NULL byte. */
+#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
+#else
+#error long int is not a 32bit or 64bit type.
+#endif
+#endif
+
+#ifndef DETECTNULL
+#error long int is not a 32bit or 64bit byte
+#endif
+
+size_t
+_DEFUN (strlen, (str),
+ _CONST char *str) ICODE_ATTR;
+
+size_t
+_DEFUN (strlen, (str),
+ _CONST char *str)
+{
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+ _CONST char *start = str;
+
+ while (*str)
+ str++;
+
+ return str - start;
+#else
+ _CONST char *start = str;
+ unsigned long *aligned_addr;
+
+ if (!UNALIGNED (str))
+ {
+ /* If the string is word-aligned, we can check for the presence of
+ a null in each word-sized block. */
+ aligned_addr = (unsigned long*)str;
+ while (!DETECTNULL (*aligned_addr))
+ aligned_addr++;
+
+ /* Once a null is detected, we check each byte in that block for a
+ precise position of the null. */
+ str = (char*)aligned_addr;
+ }
+
+ while (*str)
+ str++;
+ return str - start;
+#endif /* not PREFER_SIZE_OVER_SPEED */
+}
diff --git a/firmware/libc/strncmp.c b/firmware/libc/strncmp.c
new file mode 100644
index 0000000000..b1d8d9d43a
--- /dev/null
+++ b/firmware/libc/strncmp.c
@@ -0,0 +1,122 @@
+/*
+FUNCTION
+ <<strncmp>>---character string compare
+
+INDEX
+ strncmp
+
+ANSI_SYNOPSIS
+ #include <string.h>
+ int strncmp(const char *<[a]>, const char * <[b]>, size_t <[length]>);
+
+TRAD_SYNOPSIS
+ #include <string.h>
+ int strncmp(<[a]>, <[b]>, <[length]>)
+ char *<[a]>;
+ char *<[b]>;
+ size_t <[length]>
+
+DESCRIPTION
+ <<strncmp>> compares up to <[length]> characters
+ from the string at <[a]> to the string at <[b]>.
+
+RETURNS
+ If <<*<[a]>>> sorts lexicographically after <<*<[b]>>>,
+ <<strncmp>> returns a number greater than zero. If the two
+ strings are equivalent, <<strncmp>> returns zero. If <<*<[a]>>>
+ sorts lexicographically before <<*<[b]>>>, <<strncmp>> returns a
+ number less than zero.
+
+PORTABILITY
+<<strncmp>> is ANSI C.
+
+<<strncmp>> requires no supporting OS subroutines.
+
+QUICKREF
+ strncmp ansi pure
+*/
+
+#include <string.h>
+#include <limits.h>
+
+/* Nonzero if either X or Y is not aligned on a "long" boundary. */
+#define UNALIGNED(X, Y) \
+ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
+
+/* DETECTNULL returns nonzero if (long)X contains a NULL byte. */
+#if LONG_MAX == 2147483647L
+#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
+#else
+#if LONG_MAX == 9223372036854775807L
+#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
+#else
+#error long int is not a 32bit or 64bit type.
+#endif
+#endif
+
+#ifndef DETECTNULL
+#error long int is not a 32bit or 64bit byte
+#endif
+
+int
+_DEFUN (strncmp, (s1, s2, n),
+ _CONST char *s1 _AND
+ _CONST char *s2 _AND
+ size_t n)
+{
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+ if (n == 0)
+ return 0;
+
+ while (n-- != 0 && *s1 == *s2)
+ {
+ if (n == 0 || *s1 == '\0')
+ break;
+ s1++;
+ s2++;
+ }
+
+ return (*(unsigned char *) s1) - (*(unsigned char *) s2);
+#else
+ unsigned long *a1;
+ unsigned long *a2;
+
+ if (n == 0)
+ return 0;
+
+ /* If s1 or s2 are unaligned, then compare bytes. */
+ if (!UNALIGNED (s1, s2))
+ {
+ /* If s1 and s2 are word-aligned, compare them a word at a time. */
+ a1 = (unsigned long*)s1;
+ a2 = (unsigned long*)s2;
+ while (n >= sizeof (long) && *a1 == *a2)
+ {
+ n -= sizeof (long);
+
+ /* If we've run out of bytes or hit a null, return zero
+ since we already know *a1 == *a2. */
+ if (n == 0 || DETECTNULL (*a1))
+ return 0;
+
+ a1++;
+ a2++;
+ }
+
+ /* A difference was detected in last few bytes of s1, so search bytewise */
+ s1 = (char*)a1;
+ s2 = (char*)a2;
+ }
+
+ while (n-- > 0 && *s1 == *s2)
+ {
+ /* If we've run out of bytes or hit a null, return zero
+ since we already know *s1 == *s2. */
+ if (n == 0 || *s1 == '\0')
+ return 0;
+ s1++;
+ s2++;
+ }
+ return (*(unsigned char *) s1) - (*(unsigned char *) s2);
+#endif /* not PREFER_SIZE_OVER_SPEED */
+}
diff --git a/firmware/libc/strrchr.c b/firmware/libc/strrchr.c
new file mode 100644
index 0000000000..31b0d049b3
--- /dev/null
+++ b/firmware/libc/strrchr.c
@@ -0,0 +1,59 @@
+/*
+FUNCTION
+ <<strrchr>>---reverse search for character in string
+
+INDEX
+ strrchr
+
+ANSI_SYNOPSIS
+ #include <string.h>
+ char * strrchr(const char *<[string]>, int <[c]>);
+
+TRAD_SYNOPSIS
+ #include <string.h>
+ char * strrchr(<[string]>, <[c]>);
+ char *<[string]>;
+ int *<[c]>;
+
+DESCRIPTION
+ This function finds the last occurence of <[c]> (converted to
+ a char) in the string pointed to by <[string]> (including the
+ terminating null character).
+
+RETURNS
+ Returns a pointer to the located character, or a null pointer
+ if <[c]> does not occur in <[string]>.
+
+PORTABILITY
+<<strrchr>> is ANSI C.
+
+<<strrchr>> requires no supporting OS subroutines.
+
+QUICKREF
+ strrchr ansi pure
+*/
+
+#include <string.h>
+
+char *
+_DEFUN (strrchr, (s, i),
+ _CONST char *s _AND
+ int i)
+{
+ _CONST char *last = NULL;
+
+ if (i)
+ {
+ while ((s=strchr(s, i)))
+ {
+ last = s;
+ s++;
+ }
+ }
+ else
+ {
+ last = strchr(s, i);
+ }
+
+ return (char *) last;
+}
diff --git a/firmware/libc/strstr.c b/firmware/libc/strstr.c
new file mode 100644
index 0000000000..73fab1cc63
--- /dev/null
+++ b/firmware/libc/strstr.c
@@ -0,0 +1,38 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: $
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * (from linux/lib/string.c)
+ *
+ ****************************************************************************/
+
+#include <string.h>
+
+/**
+ * strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
+char *strstr(const char *s1, const char *s2)
+{
+ int l1, l2;
+
+ l2 = strlen(s2);
+ if (!l2)
+ return (char *)s1;
+ l1 = strlen(s1);
+ while (l1 >= l2) {
+ l1--;
+ if (!memcmp(s1, s2, l2))
+ return (char *)s1;
+ s1++;
+ }
+ return NULL;
+}
+
diff --git a/firmware/libc/strtok.c b/firmware/libc/strtok.c
new file mode 100644
index 0000000000..9e2eddf599
--- /dev/null
+++ b/firmware/libc/strtok.c
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Daniel Stenberg
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied. *
+ ****************************************************************************/
+
+#include "config.h"
+
+#ifndef HAVE_STRTOK_R
+#include <stddef.h>
+#include <string.h>
+
+char *
+strtok_r(char *ptr, const char *sep, char **end)
+{
+ if (!ptr)
+ /* we got NULL input so then we get our last position instead */
+ ptr = *end;
+
+ /* pass all letters that are including in the separator string */
+ while (*ptr && strchr(sep, *ptr))
+ ++ptr;
+
+ if (*ptr) {
+ /* so this is where the next piece of string starts */
+ char *start = ptr;
+
+ /* set the end pointer to the first byte after the start */
+ *end = start + 1;
+
+ /* scan through the string to find where it ends, it ends on a
+ null byte or a character that exists in the separator string */
+ while (**end && !strchr(sep, **end))
+ ++*end;
+
+ if (**end) {
+ /* the end is not a null byte */
+ **end = '\0'; /* zero terminate it! */
+ ++*end; /* advance last pointer to beyond the null byte */
+ }
+
+ return start; /* return the position where the string starts */
+ }
+
+ /* we ended up on a null byte, there are no more strings to find! */
+ return NULL;
+}
+
+#endif /* this was only compiled if strtok_r wasn't present */