From 167d5e33fcb821e51e2f9dcf460591737c3c7972 Mon Sep 17 00:00:00 2001 From: "Peter S. Mazinger" Date: Tue, 3 Jan 2006 14:50:18 +0000 Subject: Complete split of all the string functions. Hope haven't broken too much. wcscoll/strcoll needs some love ... --- libc/string/Makefile.in | 117 +- libc/string/__glibc_strerror_r.c | 19 + libc/string/__xpg_basename.c | 35 + libc/string/__xpg_strerror_r.c | 273 ++++ libc/string/_collate.c | 686 ++++++++ libc/string/_string.h | 33 + libc/string/_string_syserrmsgs.c | 146 ++ libc/string/_string_syssigmsgs.c | 50 + libc/string/_syserrmsg.h | 35 + libc/string/basename.c | 26 + libc/string/bcopy.c | 53 + libc/string/bzero.c | 31 + libc/string/dirname.c | 43 + libc/string/ffs.c | 54 + libc/string/memccpy.c | 22 + libc/string/memchr.c | 36 +- libc/string/memcmp.c | 39 +- libc/string/memcpy.c | 33 +- libc/string/memmem.c | 40 + libc/string/memmove.c | 53 +- libc/string/mempcpy.c | 33 +- libc/string/memrchr.c | 33 + libc/string/memset.c | 33 +- libc/string/psignal.c | 30 + libc/string/rawmemchr.c | 19 + libc/string/stpcpy.c | 27 +- libc/string/stpncpy.c | 37 +- libc/string/strcasecmp.c | 75 + libc/string/strcasecmp_l.c | 8 + libc/string/strcasestr.c | 51 + libc/string/strcat.c | 25 +- libc/string/strchr.c | 29 +- libc/string/strchrnul.c | 21 +- libc/string/strcmp.c | 46 +- libc/string/strcpy.c | 29 +- libc/string/strcspn.c | 28 +- libc/string/strdup.c | 33 +- libc/string/strerror.c | 21 + libc/string/strlcat.c | 46 + libc/string/strlcpy.c | 55 +- libc/string/strlen.c | 23 +- libc/string/strncasecmp.c | 78 + libc/string/strncasecmp_l.c | 8 + libc/string/strncat.c | 34 +- libc/string/strncmp.c | 38 +- libc/string/strncpy.c | 35 +- libc/string/strndup.c | 25 + libc/string/strnlen.c | 33 +- libc/string/strpbrk.c | 27 +- libc/string/strrchr.c | 31 +- libc/string/strsep.c | 31 + libc/string/strsignal.c | 144 ++ libc/string/strspn.c | 28 +- libc/string/strstr.c | 41 +- libc/string/strtok.c | 22 + libc/string/strtok_r.c | 54 +- libc/string/strxfrm.c | 9 + libc/string/strxfrm_l.c | 10 + libc/string/sys_errlist.c | 171 ++ libc/string/sys_siglist.c | 57 + libc/string/wcpcpy.c | 9 +- libc/string/wcpncpy.c | 9 +- libc/string/wcscasecmp.c | 8 + libc/string/wcscasecmp_l.c | 9 + libc/string/wcscat.c | 9 +- libc/string/wcschr.c | 9 +- libc/string/wcschrnul.c | 9 +- libc/string/wcscmp.c | 14 +- libc/string/wcscpy.c | 9 +- libc/string/wcscspn.c | 9 +- libc/string/wcsdup.c | 14 +- libc/string/wcslcpy.c | 11 +- libc/string/wcslen.c | 9 +- libc/string/wcsncasecmp.c | 8 + libc/string/wcsncasecmp_l.c | 9 + libc/string/wcsncat.c | 9 +- libc/string/wcsncmp.c | 9 +- libc/string/wcsncpy.c | 9 +- libc/string/wcsnlen.c | 9 +- libc/string/wcspbrk.c | 9 +- libc/string/wcsrchr.c | 9 +- libc/string/wcsspn.c | 9 +- libc/string/wcsstr.c | 11 +- libc/string/wcstok.c | 14 +- libc/string/wcsxfrm.c | 9 + libc/string/wcsxfrm_l.c | 10 + libc/string/wmemchr.c | 9 +- libc/string/wmemcmp.c | 9 +- libc/string/wmemcpy.c | 9 +- libc/string/wmemmove.c | 9 +- libc/string/wmempcpy.c | 9 +- libc/string/wmemset.c | 9 +- libc/string/wstring.c | 3247 -------------------------------------- 93 files changed, 3253 insertions(+), 3702 deletions(-) create mode 100644 libc/string/__glibc_strerror_r.c create mode 100644 libc/string/__xpg_basename.c create mode 100644 libc/string/__xpg_strerror_r.c create mode 100644 libc/string/_collate.c create mode 100644 libc/string/_string.h create mode 100644 libc/string/_string_syserrmsgs.c create mode 100644 libc/string/_string_syssigmsgs.c create mode 100644 libc/string/_syserrmsg.h create mode 100644 libc/string/basename.c create mode 100644 libc/string/bcopy.c create mode 100644 libc/string/bzero.c create mode 100644 libc/string/dirname.c create mode 100644 libc/string/ffs.c create mode 100644 libc/string/memccpy.c create mode 100644 libc/string/memmem.c create mode 100644 libc/string/memrchr.c create mode 100644 libc/string/psignal.c create mode 100644 libc/string/rawmemchr.c create mode 100644 libc/string/strcasecmp.c create mode 100644 libc/string/strcasecmp_l.c create mode 100644 libc/string/strcasestr.c create mode 100644 libc/string/strerror.c create mode 100644 libc/string/strlcat.c create mode 100644 libc/string/strncasecmp.c create mode 100644 libc/string/strncasecmp_l.c create mode 100644 libc/string/strndup.c create mode 100644 libc/string/strsep.c create mode 100644 libc/string/strsignal.c create mode 100644 libc/string/strtok.c create mode 100644 libc/string/strxfrm.c create mode 100644 libc/string/strxfrm_l.c create mode 100644 libc/string/sys_errlist.c create mode 100644 libc/string/sys_siglist.c create mode 100644 libc/string/wcscasecmp.c create mode 100644 libc/string/wcscasecmp_l.c create mode 100644 libc/string/wcsncasecmp.c create mode 100644 libc/string/wcsncasecmp_l.c create mode 100644 libc/string/wcsxfrm.c create mode 100644 libc/string/wcsxfrm_l.c delete mode 100644 libc/string/wstring.c diff --git a/libc/string/Makefile.in b/libc/string/Makefile.in index 0adcaee39..4f96b8354 100644 --- a/libc/string/Makefile.in +++ b/libc/string/Makefile.in @@ -9,112 +9,69 @@ -include $(top_srcdir)libc/string/$(TARGET_ARCH)/Makefile.arch include $(top_srcdir)libc/string/generic/Makefile.in -MSRC:=wstring.c -MOBJ:= basename.o bcopy.o bzero.o dirname.o ffs.o memccpy.o \ - memrchr.o rawmemchr.o strcasecmp.o strcasestr.o \ - strncasecmp.o strndup.o strsep.o \ - strtok.o strerror.o __xpg_strerror_r.o \ - _string_syserrmsgs.o __glibc_strerror_r.o \ - _string_syssigmsgs.o sys_siglist.o strsignal.o psignal.o \ - __xpg_basename.o strlcat.o sys_errlist.o memmem.o +STRING_DIR:=$(top_srcdir)libc/string +STRING_OUT:=$(top_builddir)libc/string -MOBJW:= -ifeq ($(UCLIBC_HAS_WCHAR),y) -MOBJW:= wcscasecmp.o wcsncasecmp.o \ - wcsxfrm.o strxfrm.o # wcscoll strcoll.o +STRING_ALL_WXSRC:=$(wildcard $(STRING_DIR)/w*_l.c) +ifeq ($(UCLIBC_HAS_LOCALE),y) +STRING_WXSRC:=$(STRING_ALL_WXSRC) +else +# wcscoll_l +STRING_WXSRC:=$(filter-out $(STRING_DIR)/wcsxfrm_l.c,$(STRING_ALL_WXSRC)) endif -MOBJx:= -MOBJWx:= -ifeq ($(UCLIBC_HAS_XLOCALE),y) -MOBJx:=strcasecmp_l.o strncasecmp_l.o -ifeq ($(UCLIBC_HAS_WCHAR),y) -MOBJWx:=wcscasecmp_l.o wcsncasecmp_l.o wcsxfrm_l.o strxfrm_l.o +STRING_ALL_XLSRC:=$(filter-out $(STRING_ALL_WXSRC),$(wildcard $(STRING_DIR)/*_l.c)) +ifeq ($(UCLIBC_HAS_LOCALE),y) +STRING_XLSRC:=$(STRING_ALL_XLSRC) +else +# strcoll_l +STRING_XLSRC:=$(filter-out $(STRING_DIR)/strxfrm_l.c,$(STRING_ALL_XLSRC)) endif -endif - -#ffsl ffsll -ifeq ($(UCLIBC_HAS_STRING_ARCH_OPT),y) -ifneq ($(strip $(STRING_ARCH_OBJS)),) -MOBJ:=$(filter-out $(notdir $(STRING_ARCH_OBJS)),$(MOBJ)) +STRING_ALL_WSRC:=$(filter-out $(STRING_ALL_WXSRC),$(wildcard $(STRING_DIR)/w*.c)) +ifeq ($(UCLIBC_HAS_LOCALE),y) +STRING_WSRC:=$(STRING_ALL_WSRC) +else +# wcscoll +STRING_WSRC:=$(filter-out $(STRING_DIR)/wcsxfrm.c,$(STRING_ALL_WSRC)) endif + +STRING_ALL_CSRC:=$(filter-out $(STRING_ALL_WXSRC) $(STRING_ALL_XLSRC) $(STRING_ALL_WSRC) $(STRING_DIR)/_collate.c,$(wildcard $(STRING_DIR)/*.c)) +ifeq ($(UCLIBC_HAS_LOCALE),y) +STRING_CSRC:=$(STRING_ALL_CSRC) +else +# strcoll +STRING_CSRC:=$(filter-out $(STRING_DIR)/strxfrm.c,$(STRING_ALL_CSRC)) endif -ifeq ($(UCLIBC_HAS_STRING_GENERIC_OPT),y) -ifneq ($(strip $(STRING_GENERIC_OBJS)),) -MOBJ:=$(filter-out $(notdir $(STRING_GENERIC_OBJS)),$(MOBJ)) +ifeq ($(UCLIBC_HAS_WCHAR),y) +STRING_CSRC+=$(STRING_WSRC) +endif +ifeq ($(UCLIBC_HAS_XLOCALE),y) +STRING_CSRC+=$(STRING_XLSRC) +ifeq ($(UCLIBC_HAS_WCHAR),y) +STRING_CSRC+=$(STRING_WXSRC) endif endif - -STRING_DIR:=$(top_srcdir)libc/string -STRING_OUT:=$(top_builddir)libc/string - -STRING_WSRC:=$(filter-out $(STRING_DIR)/wstring.c,$(wildcard $(STRING_DIR)/w*.c)) -STRING_CSRC:=$(filter-out $(STRING_DIR)/wstring.c $(STRING_WSRC),$(wildcard $(STRING_DIR)/*.c)) ifeq ($(UCLIBC_HAS_STRING_ARCH_OPT),y) ifneq ($(strip $(STRING_ARCH_OBJS)),) -MOBJ:=$(filter-out $(notdir $(STRING_ARCH_OBJS)),$(MOBJ)) STRING_CSRC:=$(filter-out $(patsubst %.o,$(STRING_DIR)/%.c,$(notdir $(STRING_ARCH_OBJS))),$(STRING_CSRC)) -STRING_WSRC:=$(filter-out $(patsubst %.o,$(STRING_DIR)/%.c,$(notdir $(STRING_ARCH_OBJS))),$(STRING_WSRC)) endif endif ifeq ($(UCLIBC_HAS_STRING_GENERIC_OPT),y) ifneq ($(strip $(STRING_GENERIC_OBJS)),) -MOBJ:=$(filter-out $(notdir $(STRING_GENERIC_OBJS)),$(MOBJ)) STRING_CSRC:=$(filter-out $(patsubst %.o,$(STRING_DIR)/%.c,$(notdir $(STRING_GENERIC_OBJS))),$(STRING_CSRC)) -STRING_WSRC:=$(filter-out $(patsubst %.o,$(STRING_DIR)/%.c,$(notdir $(STRING_GENERIC_OBJS))),$(STRING_WSRC)) endif endif - STRING_COBJ:=$(patsubst $(STRING_DIR)/%.c,$(STRING_OUT)/%.o,$(STRING_CSRC)) -ifeq ($(UCLIBC_HAS_WCHAR),y) -STRING_WOBJ:=$(patsubst $(STRING_DIR)/%.c,$(STRING_OUT)/%.o,$(STRING_WSRC)) -endif -STRING_MSRC:=$(patsubst %.c,$(STRING_DIR)/%.c,$(MSRC)) -STRING_MOBJ:=$(patsubst %.o,$(STRING_OUT)/%.o,$(MOBJ)) -STRING_MOBJW:=$(patsubst %.o,$(STRING_OUT)/%.o,$(MOBJW)) -STRING_MOBJx:=$(patsubst %.o,$(STRING_OUT)/%.o,$(MOBJx)) -STRING_MOBJWx:=$(patsubst %.o,$(STRING_OUT)/%.o,$(MOBJWx)) - -STRING_DEF:=$(patsubst %,-DL_%,$(subst .o,,$(notdir $(STRING_MOBJ)))) - -STRING_Wx:=$(STRING_MOBJW) $(STRING_MOBJx) $(STRING_MOBJWx) -STRING_OBJS:=$(STRING_COBJ) $(STRING_WOBJ) $(STRING_MOBJ) $(STRING_Wx) - -$(STRING_MOBJ): $(STRING_MSRC) - $(compile.m) - -$(STRING_MOBJ:.o=.os): $(STRING_MSRC) - $(compile.m) - -$(STRING_MOBJW): $(STRING_MSRC) - $(compile.m) -DWANT_WIDE - -$(STRING_MOBJW:.o=.os): $(STRING_MSRC) - $(compile.m) -DWANT_WIDE - -$(STRING_MOBJx): $(STRING_MSRC) - $(compile.m) -D__UCLIBC_DO_XLOCALE - -$(STRING_MOBJx:.o=.os): $(STRING_MSRC) - $(compile.m) -D__UCLIBC_DO_XLOCALE - -$(STRING_MOBJWx): $(STRING_MSRC) - $(compile.m) -DWANT_WIDE -D__UCLIBC_DO_XLOCALE - -$(STRING_MOBJWx:.o=.os): $(STRING_MSRC) - $(compile.m) -DWANT_WIDE -D__UCLIBC_DO_XLOCALE -libc-a-y+=$(STRING_OBJS) -libc-so-y+=$(STRING_OBJS:.o=.os) +libc-a-y+=$(STRING_COBJ) +libc-so-y+=$(STRING_COBJ:.o=.os) -CFLAGS-multi-y+=$(STRING_DEF) -libc-multi-y+=$(STRING_MSRC) $(STRING_CSRC) $(STRING_WSRC) -libc-nomulti-y+=$(STRING_Wx) +libc-multi-y+=$(STRING_CSRC) objclean-y+=string_objclean diff --git a/libc/string/__glibc_strerror_r.c b/libc/string/__glibc_strerror_r.c new file mode 100644 index 000000000..54955ec25 --- /dev/null +++ b/libc/string/__glibc_strerror_r.c @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include +#include + +char attribute_hidden *__glibc_strerror_r_internal(int errnum, char *strerrbuf, size_t buflen) +{ + __xpg_strerror_r_internal(errnum, strerrbuf, buflen); + + return strerrbuf; +} + +strong_alias(__glibc_strerror_r_internal,__glibc_strerror_r) +/*hidden_weak_alias(__glibc_strerror_r_internal,__strerror_r)*/ diff --git a/libc/string/__xpg_basename.c b/libc/string/__xpg_basename.c new file mode 100644 index 000000000..6281f015c --- /dev/null +++ b/libc/string/__xpg_basename.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include "_string.h" + +char *__xpg_basename(register char *path) +{ + static const char null_or_empty[] = "."; + char *first; + register char *last; + + first = (char *) null_or_empty; + + if (path && *path) { + first = path; + last = path - 1; + + do { + if ((*path != '/') && (path > ++last)) { + last = first = path; + } + } while (*++path); + + if (*first == '/') { + last = first; + } + last[1] = 0; + } + + return first; +} diff --git a/libc/string/__xpg_strerror_r.c b/libc/string/__xpg_strerror_r.c new file mode 100644 index 000000000..93dffc732 --- /dev/null +++ b/libc/string/__xpg_strerror_r.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include "_syserrmsg.h" + +#ifdef __UCLIBC_HAS_ERRNO_MESSAGES__ + +extern const char _string_syserrmsgs[]; + +#if defined(__alpha__) || defined(__mips__) || defined(__sparc__) + +static const unsigned char estridx[] = { + 0, /* success is always 0 */ + EPERM, + ENOENT, + ESRCH, + EINTR, + EIO, + ENXIO, + E2BIG, + ENOEXEC, + EBADF, + ECHILD, + EAGAIN, + ENOMEM, + EACCES, + EFAULT, + ENOTBLK, + EBUSY, + EEXIST, + EXDEV, + ENODEV, + ENOTDIR, + EISDIR, + EINVAL, + ENFILE, + EMFILE, + ENOTTY, + ETXTBSY, + EFBIG, + ENOSPC, + ESPIPE, + EROFS, + EMLINK, + EPIPE, + EDOM, + ERANGE, + EDEADLK, + ENAMETOOLONG, + ENOLCK, + ENOSYS, + ENOTEMPTY, + ELOOP, + 0, + ENOMSG, + EIDRM, + ECHRNG, + EL2NSYNC, + EL3HLT, + EL3RST, + ELNRNG, + EUNATCH, + ENOCSI, + EL2HLT, + EBADE, + EBADR, + EXFULL, + ENOANO, + EBADRQC, + EBADSLT, + 0, + EBFONT, + ENOSTR, + ENODATA, + ETIME, + ENOSR, + ENONET, + ENOPKG, + EREMOTE, + ENOLINK, + EADV, + ESRMNT, + ECOMM, + EPROTO, + EMULTIHOP, + EDOTDOT, + EBADMSG, + EOVERFLOW, + ENOTUNIQ, + EBADFD, + EREMCHG, + ELIBACC, + ELIBBAD, + ELIBSCN, + ELIBMAX, + ELIBEXEC, + EILSEQ, + ERESTART, + ESTRPIPE, + EUSERS, + ENOTSOCK, + EDESTADDRREQ, + EMSGSIZE, + EPROTOTYPE, + ENOPROTOOPT, + EPROTONOSUPPORT, + ESOCKTNOSUPPORT, + EOPNOTSUPP, + EPFNOSUPPORT, + EAFNOSUPPORT, + EADDRINUSE, + EADDRNOTAVAIL, + ENETDOWN, + ENETUNREACH, + ENETRESET, + ECONNABORTED, + ECONNRESET, + ENOBUFS, + EISCONN, + ENOTCONN, + ESHUTDOWN, + ETOOMANYREFS, + ETIMEDOUT, + ECONNREFUSED, + EHOSTDOWN, + EHOSTUNREACH, + EALREADY, + EINPROGRESS, + ESTALE, + EUCLEAN, + ENOTNAM, + ENAVAIL, + EISNAM, + EREMOTEIO, +#ifdef __mips__ + 0, /* mips has an outrageous value for this... */ +#else + EDQUOT, +#endif + ENOMEDIUM, + EMEDIUMTYPE, +#if defined(__mips__) || defined(__sparc__) + EDEADLOCK, +#endif +}; + +#endif + +/* __xpg_strerror_r is used in header */ +int attribute_hidden __xpg_strerror_r_internal(int errnum, char *strerrbuf, size_t buflen) +{ + register char *s; + int i, retval; + char buf[_STRERROR_BUFSIZE]; + static const char unknown[] = { + 'U', 'n', 'k', 'n', 'o', 'w', 'n', ' ', 'e', 'r', 'r', 'o', 'r', ' ' + }; + + retval = EINVAL; + + +#ifdef __UCLIBC_HAS_ERRNO_MESSAGES__ + +#if defined(__alpha__) || defined(__mips__) || defined(__sparc__) + /* Need to translate errno to string index. */ + for (i = 0 ; i < sizeof(estridx)/sizeof(estridx[0]) ; i++) { + if (estridx[i] == errnum) { + goto GOT_ESTRIDX; + } + } + i = INT_MAX; /* Failed, but may need to check mips special case. */ +#ifdef __mips__ + if (errnum == EDQUOT) { /* Deal with large EDQUOT value on mips */ + i = 122; + } +#endif /* __mips__ */ + GOT_ESTRIDX: +#else + /* No errno to string index translation needed. */ + i = errnum; +#endif + + if (((unsigned int) i) < _SYS_NERR) { + /* Trade time for space. This function should rarely be called + * so rather than keeping an array of pointers for the different + * messages, just run through the buffer until we find the + * correct string. */ + for (s = (char *) _string_syserrmsgs ; i ; ++s) { + if (!*s) { + --i; + } + } + if (*s) { /* Make sure we have an actual message. */ + retval = 0; + goto GOT_MESG; + } + } + +#endif /* __UCLIBC_HAS_ERRNO_MESSAGES__ */ + + s = _int10tostr(buf+sizeof(buf)-1, errnum) - sizeof(unknown); + __memcpy(s, unknown, sizeof(unknown)); + + GOT_MESG: + if (!strerrbuf) { /* SUSv3 */ + buflen = 0; + } + i = __strlen(s) + 1; + if (i > buflen) { + i = buflen; + retval = ERANGE; + } + + if (i) { + __memcpy(strerrbuf, s, i); + strerrbuf[i-1] = 0; /* In case buf was too small. */ + } + + if (retval) { + __set_errno(retval); + } + + return retval; +} + +#else /* __UCLIBC_HAS_ERRNO_MESSAGES__ */ + +int attribute_hidden __xpg_strerror_r_internal(int errnum, char *strerrbuf, size_t buflen) +{ + register char *s; + int i, retval; + char buf[_STRERROR_BUFSIZE]; + static const char unknown[] = { + 'U', 'n', 'k', 'n', 'o', 'w', 'n', ' ', 'e', 'r', 'r', 'o', 'r', ' ' + }; + + s = _int10tostr(buf+sizeof(buf)-1, errnum) - sizeof(unknown); + __memcpy(s, unknown, sizeof(unknown)); + + if (!strerrbuf) { /* SUSv3 */ + buflen = 0; + } + + retval = EINVAL; + + i = buf + sizeof(buf) - s; + + if (i > buflen) { + i = buflen; + retval = ERANGE; + } + + if (i) { + __memcpy(strerrbuf, s, i); + strerrbuf[i-1] = 0; /* In case buf was too small. */ + } + + __set_errno(retval); + + return retval; +} + +#endif /* __UCLIBC_HAS_ERRNO_MESSAGES__ */ + +strong_alias(__xpg_strerror_r_internal,__xpg_strerror_r) diff --git a/libc/string/_collate.c b/libc/string/_collate.c new file mode 100644 index 000000000..35fe7dc1b --- /dev/null +++ b/libc/string/_collate.c @@ -0,0 +1,686 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Dec 20, 2002 + * Initial test implementation of strcoll, strxfrm, wcscoll, and wcsxfrm. + * The code needs to be cleaned up a good bit, but I'd like to see people + * test it out. + * + */ + +#include "_string.h" +#include +#include +#include +#include +#include + +extern size_t __strlcpy(char *__restrict dst, const char *__restrict src, + size_t n) attribute_hidden; + +#ifdef WANT_WIDE +extern int __wcscmp (__const wchar_t *__s1, __const wchar_t *__s2) attribute_hidden; +extern size_t __wcsxfrm (wchar_t *__restrict __s1, + __const wchar_t *__restrict __s2, size_t __n) attribute_hidden; +#endif +#ifdef __UCLIBC_HAS_XLOCALE__ +extern int __strcoll_l (__const char *__s1, __const char *__s2, __locale_t __l) attribute_hidden; +extern size_t __strxfrm_l (char *__dest, __const char *__src, size_t __n, __locale_t __l) attribute_hidden; +extern int __wcscoll_l (__const wchar_t *__s1, __const wchar_t *__s2, __locale_t __loc) attribute_hidden; +extern size_t __wcsxfrm_l (wchar_t *__s1, __const wchar_t *__s2, size_t __n, __locale_t __loc) attribute_hidden; +#endif + +#ifdef __UCLIBC_HAS_LOCALE__ +#if defined(L_strxfrm) || defined(L_strxfrm_l) || defined(L_wcsxfrm) || defined(L_wcsxfrm_l) + +#ifdef L_strxfrm +#ifndef WANT_WIDE +#error WANT_WIDE should be defined for L_strxfrm +#endif +#ifdef L_wcsxfrm +#error L_wcsxfrm already defined for L_strxfrm +#endif +#endif /* L_strxfrm */ + +#if defined(L_strxfrm) || defined(L_strxfrm_l) + +#define wcscoll strcoll +#define __wcscoll __strcoll +#define wcscoll_l strcoll_l +#define __wcscoll_l __strcoll_l +#define wcsxfrm strxfrm +#define __wcsxfrm __strxfrm +#define wcsxfrm_l strxfrm_l +#define __wcsxfrm_l __strxfrm_l + +#undef WANT_WIDE +#undef Wvoid +#undef Wchar +#undef Wuchar +#undef Wint + +#define Wchar char + +#endif /* defined(L_strxfrm) || defined(L_strxfrm_l) */ + +#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) + +int attribute_hidden __wcscoll (const Wchar *s0, const Wchar *s1) +{ + return __wcscoll_l(s0, s1, __UCLIBC_CURLOCALE ); +} +strong_alias(__wcscoll,wcscoll) + +size_t attribute_hidden __wcsxfrm(Wchar *__restrict ws1, const Wchar *__restrict ws2, size_t n) +{ + return __wcsxfrm_l(ws1, ws2, n, __UCLIBC_CURLOCALE ); +} +strong_alias(__wcsxfrm,wcsxfrm) + +#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ + + +#if 0 +#define CUR_COLLATE (&__UCLIBC_CURLOCALE_DATA.collate) +#else +#define CUR_COLLATE (& __LOCALE_PTR->collate) +#endif + +#define MAX_PENDING 8 + +typedef struct { + const Wchar *s; + const Wchar *eob; /* end of backward */ + + __uwchar_t weight; + __uwchar_t ui_weight; /* undefined or invalid */ + int colitem; + int weightidx; + int rule; + size_t position; + /* should be wchar_t. if wchar < 0 do EILSEQ? */ + __uwchar_t *cip; + __uwchar_t ci_pending[MAX_PENDING]; /* nul-terminated */ + + char *back_buf; + char *bbe; /* end of back_buf (actual last... not 1 past end) */ + char *bp; /* ptr into backbuf, NULL if not in backward mode */ + char ibb[128]; + size_t bb_size; + + int ru_pushed; +} col_state_t; + + +#define WEIGHT_MASK 0x3fffU +#define RULE_MASK 0xc000U + +#define RULE_FORWARD (1 << 14) +#define RULE_POSITION (1 << 15) + +#define UI_IDX (WEIGHT_MASK-6) +#define POSIT_IDX (WEIGHT_MASK-5) +#define RANGE_IDX (WEIGHT_MASK-4) +#define UNDEF_IDX (WEIGHT_MASK-3) +#define INVAL_IDX (WEIGHT_MASK-2) +#define DITTO_IDX (WEIGHT_MASK-1) + + +#undef TRACE +#if 0 +#define TRACE(X) printf X +#else +#define TRACE(X) ((void)0) +#endif + +static int lookup(wchar_t wc __LOCALE_PARAM ) +{ + unsigned int sc, n, i0, i1; + + if (((__uwchar_t) wc) > 0xffffU) { + return 0; + } + + sc = wc & CUR_COLLATE->ti_mask; + wc >>= CUR_COLLATE->ti_shift; + n = wc & CUR_COLLATE->ii_mask; + wc >>= CUR_COLLATE->ii_shift; + + i0 = CUR_COLLATE->wcs2colidt_tbl[wc]; + i0 <<= CUR_COLLATE->ii_shift; + i1 = CUR_COLLATE->wcs2colidt_tbl[CUR_COLLATE->ii_len + i0 + n]; + i1 <<= CUR_COLLATE->ti_shift; + return CUR_COLLATE->wcs2colidt_tbl[CUR_COLLATE->ii_len + CUR_COLLATE->ti_len + i1 + sc]; + +} + +static void init_col_state(col_state_t *cs, const Wchar *wcs) +{ + __memset(cs, 0, sizeof(col_state_t)); + cs->s = wcs; + cs->bp = cs->back_buf = cs->ibb; + cs->bb_size = 128; + cs->bbe = cs->back_buf + (cs->bb_size -1); +} + +static void next_weight(col_state_t *cs, int pass __LOCALE_PARAM ) +{ + int r, w, ru, ri, popping_backup_stack; + ssize_t n; + const uint16_t *p; +#ifdef WANT_WIDE +#define WC (*cs->s) +#define N (1) +#else /* WANT_WIDE */ + wchar_t WC; + size_t n0, nx; +#define N n0 + +#endif /* WANT_WIDE */ + + do { + + if (cs->ru_pushed) { + ru = cs->ru_pushed; + TRACE(("ru_pushed = %d\n", ru)); + cs->ru_pushed = 0; + goto POSITION_SKIP; + } + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning should we walk pendings backwards? +#endif + if (cs->cip) { /* possible pending weight */ + if ((r = *(cs->cip++)) == 0) { + cs->cip = NULL; + continue; + } + cs->weightidx = r & WEIGHT_MASK; + assert(cs->weightidx); +/* assert(cs->weightidx != WEIGHT_MASK); */ + } else { /* get the next collation item from the string */ + TRACE(("clearing popping flag\n")); + popping_backup_stack = 0; + + IGNORE_LOOP: + /* keep first pos as 0 for a sentinal */ + if (*cs->bp) { /* pending backward chars */ + POP_BACKUP: + popping_backup_stack = 1; + TRACE(("setting popping flag\n")); + n = 0; + if (*cs->bp > 0) { /* singles pending */ + cs->s -= 1; + if ((*cs->bp -= 1) == 0) { + cs->bp -= 1; + } + } else { /* last was a multi */ + cs->s += *cs->bp; + cs->bp -= 1; + } + } else if (!*cs->s) { /* not in backward mode and end of string */ + cs->weight = 0; + return; + } else { + cs->position += 1; + } + + BACK_LOOP: +#ifdef WANT_WIDE + n = 1; + cs->colitem = r = lookup(*cs->s __LOCALE_ARG ); +#else /* WANT_WIDE */ + n = n0 = __locale_mbrtowc_l(&WC, cs->s, __LOCALE_PTR); + if (n < 0) { + __set_errno(EILSEQ); + cs->weight = 0; + return; + } + cs->colitem = r = lookup(WC __LOCALE_ARG ); +#endif /* WANT_WIDE */ + + TRACE((" r=%d WC=%#lx\n", r, (unsigned long)(WC))); + + if (r > CUR_COLLATE->max_col_index) { /* starting char for one or more sequences */ + p = CUR_COLLATE->multistart_tbl; + p += p[r-CUR_COLLATE->max_col_index -1]; + do { + n = N; + r = *p++; + do { + if (!*p) { /* found it */ + cs->colitem = r; + TRACE((" found multi %d\n", n)); + goto FOUND; + } +#ifdef WANT_WIDE + /* the lookup check here is safe since we're assured that *p is a valid colidx */ + if (!cs->s[n] || (lookup(cs->s[n] __LOCALE_ARG ) != *p)) { + do {} while (*p++); + break; + } + ++p; + ++n; +#else /* WANT_WIDE */ + if (cs->s[n]) { + nx = __locale_mbrtowc_l(&WC, cs->s + n, __LOCALE_PTR); + if (nx < 0) { + __set_errno(EILSEQ); + cs->weight = 0; + return; + } + } + if (!cs->s[n] || (lookup(WC __LOCALE_ARG ) != *p)) { + do {} while (*p++); + break; + } + ++p; + n += nx; /* Only gets here if cs->s[n] != 0, so nx is set. */ +#endif /* WANT_WIDE */ + } while (1); + } while (1); + } else if (r == 0) { /* illegal, undefined, or part of a range */ + if ((CUR_COLLATE->range_count) +#ifdef __UCLIBC_MJN3_ONLY__ +#warning .. need to introduce range as a collating item? +#endif + && (((__uwchar_t)(WC - CUR_COLLATE->range_low)) <= CUR_COLLATE->range_count) + ) { /* part of a range */ + /* Note: cs->colitem = 0 already. */ + TRACE((" found range\n")); + ru = CUR_COLLATE->ruletable[CUR_COLLATE->range_rule_offset*CUR_COLLATE->MAX_WEIGHTS + pass]; + assert((ru & WEIGHT_MASK) != DITTO_IDX); + if ((ru & WEIGHT_MASK) == WEIGHT_MASK) { + ru = (ru & RULE_MASK) | RANGE_IDX; + cs->weight = CUR_COLLATE->range_base_weight + (WC - CUR_COLLATE->range_low); + } + goto RANGE_SKIP_TO; + } else if (((__uwchar_t)(WC)) <= 0x7fffffffUL) { /* legal but undefined */ + UNDEFINED: + /* Note: cs->colitem = 0 already. */ + ri = CUR_COLLATE->undefined_idx; + assert(ri != 0); /* implicit undefined isn't supported */ + + TRACE((" found explicit UNDEFINED\n")); +#ifdef __UCLIBC_MJN3_ONLY__ +#warning right now single weight locales do not support .. +#endif + if (CUR_COLLATE->num_weights == 1) { + TRACE((" single weight UNDEFINED\n")); + cs->weightidx = RANGE_IDX; + cs->weight = ri; + cs->s += n; + goto PROCESS_WEIGHT; + } + + ri = CUR_COLLATE->index2ruleidx[ri - 1]; + ru = CUR_COLLATE->ruletable[ri * CUR_COLLATE->MAX_WEIGHTS + pass]; + assert((ru & WEIGHT_MASK) != WEIGHT_MASK); /* TODO: handle ".." */ + if ((ru & WEIGHT_MASK) == DITTO_IDX) { + cs->colitem = CUR_COLLATE->undefined_idx; + } + goto RANGE_SKIP_TO; + } else { /* illegal */ + TRACE((" found illegal\n")); + __set_errno(EINVAL); + /* We put all illegals in the same equiv class with maximal weight, + * and ignore them after the first pass. */ + if (pass > 0) { + cs->s += n; + goto IGNORE_LOOP; + } + ru = (RULE_FORWARD | RANGE_IDX); + cs->weight = 0xffffU; + goto RANGE_SKIP_TO; + } + } else if (CUR_COLLATE->num_weights == 1) { + TRACE((" single weight\n")); + cs->weightidx = RANGE_IDX; + cs->weight = cs->colitem; + cs->s += n; + goto PROCESS_WEIGHT; + } else { + TRACE((" normal\n")); + } + + /* if we get here, it is a normal char either singlely weighted, undefined, or in a range */ + FOUND: + ri = CUR_COLLATE->index2ruleidx[cs->colitem - 1]; + TRACE((" ri=%d ", ri)); +#ifdef __UCLIBC_MJN3_ONLY__ +#warning make sure this is correct +#endif + if (!ri) { + TRACE(("NOT IN THIS LOCALE\n")); + goto UNDEFINED; + } + ru = CUR_COLLATE->ruletable[ri * CUR_COLLATE->MAX_WEIGHTS + pass]; + + RANGE_SKIP_TO: + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning ignoreables probably should not interrupt backwards processing, but this is wrong +#endif +/* if (!(ru & WEIGHT_MASK)) { */ +/* TRACE(("IGNORE\n")); */ +/* cs->s += n; */ +/* continue; */ +/* } */ + + + TRACE((" rule = %#x weight = %#x popping = %d s = %p eob = %p\n", + ru & RULE_MASK, ru & WEIGHT_MASK, popping_backup_stack, + cs->s, cs->eob)); + /* now we need to check if we're going backwards... */ + + if (!popping_backup_stack) { + if (!(ru & RULE_MASK)) { /* backward */ + TRACE(("backwards\n")); + assert(cs->bp <= cs->bbe); + if (cs->bp == cs->bbe) { + if (cs->back_buf == cs->ibb) { /* was using internal buffer */ + cs->bp = malloc(cs->bb_size + 128); + if (!cs->bp) { + __set_errno(ENOMEM); +#ifdef __UCLIBC_MJN3_ONLY__ +#warning what to do here? +#endif + cs->weight = 0; + return; + } + __memcpy(cs->bp, cs->back_buf, cs->bb_size); + + } else { + cs->bp = realloc(cs->back_buf, cs->bb_size + 128); + if (!cs->bp) { + __set_errno(ENOMEM); +#ifdef __UCLIBC_MJN3_ONLY__ +#warning what to do here? +#endif + cs->weight = 0; + return; + } + } + cs->bb_size += 128; + cs->bbe = cs->bp + (cs->bbe - cs->back_buf); + cs->back_buf = cs->bp; + cs->bp = cs->bbe; + + } + if (n==1) { /* single char */ + if (*cs->bp && (((unsigned char)(*cs->bp)) < CHAR_MAX)) { + *cs->bp += 1; /* increment last single's count */ + } else { /* last was a multi, or just starting */ + if (!cs->bp) { + cs->bp = cs->back_buf; + } else { + assert(cs->bp < cs->bbe); + ++cs->bp; + } + *cs->bp = 1; + } + } else { /* multichar */ + assert(n>1); + assert(cs->bp < cs->bbe); + *++cs->bp = -n; + } + cs->s += n; + if (*cs->s) { + goto BACK_LOOP; + } + /* end-of-string so start popping */ + cs->eob = cs->s; + TRACE(("popping\n")); + goto POP_BACKUP; + } else if (*cs->bp) { /* was going backward but this element isn't */ + /* discard current and use previous backward element */ + assert(!cs->cip); + cs->eob = cs->s; + TRACE(("popping\n")); + goto POP_BACKUP; + } else { /* was and still going forward */ + TRACE(("forwards\n")); + if ((ru & (RULE_POSITION|WEIGHT_MASK)) > RULE_POSITION) { + assert(ru & WEIGHT_MASK); + cs->ru_pushed = ru; + cs->weight = cs->position; +#ifdef __UCLIBC_MJN3_ONLY__ +#warning devel code +#endif + cs->position = 0; /* reset to reduce size for strcoll? */ + cs->s += n; + cs->weightidx = RANGE_IDX; + goto PROCESS_WEIGHT; + } + } + } else { /* popping backwards stack */ + TRACE(("popping (continued)\n")); + if (!*cs->bp) { + cs->s = cs->eob; + } + cs->s -= n; + } + + cs->s += n; + POSITION_SKIP: + cs->weightidx = ru & WEIGHT_MASK; + cs->rule = ru & RULE_MASK; + } + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning for pending we only want the weight... _not_ the rule +#endif + if (!cs->weightidx) { /* ignore */ + continue; + } + + PROCESS_WEIGHT: + assert(cs->weightidx); + + + if (((unsigned int)(cs->weightidx - UI_IDX)) <= (INVAL_IDX-UI_IDX)) { + if (cs->weightidx == UI_IDX) { + cs->weight = cs->ui_weight; + } + return; + } + + assert(cs->weightidx != WEIGHT_MASK); + if (cs->weightidx == DITTO_IDX) { /* want the weight of the current collating item */ + TRACE(("doing ditto\n")); + w = CUR_COLLATE->index2weight[cs->colitem -1]; + } else if (cs->weightidx <= CUR_COLLATE->max_col_index) { /* normal */ + TRACE(("doing normal\n")); + w = CUR_COLLATE->index2weight[cs->weightidx -1]; + } else { /* a string */ + TRACE(("doing string\n")); + assert(!(cs->weightidx & RULE_MASK)); + /* note: iso14561 allows null string here */ + p = CUR_COLLATE->weightstr + (cs->weightidx - (CUR_COLLATE->max_col_index + 2)); + if (*p & WEIGHT_MASK) { + r = 0; + do { + assert(r < MAX_PENDING); + cs->ci_pending[r++] = *p++; + } while (*p & WEIGHT_MASK); + cs->cip = cs->ci_pending; + } + continue; + } + + cs->weight = w; + return; + } while (1); +} + +int attribute_hidden __UCXL(wcscoll) (const Wchar *s0, const Wchar *s1 __LOCALE_PARAM ) +{ + col_state_t ws[2]; + int pass; + + if (!CUR_COLLATE->num_weights) { /* C locale */ +#ifdef WANT_WIDE + return __wcscmp(s0, s1); +#else /* WANT_WIDE */ + return __strcmp(s0, s1); +#endif /* WANT_WIDE */ + } + + pass = 0; + do { /* loop through the weights levels */ + init_col_state(ws, s0); + init_col_state(ws+1, s1); + do { /* loop through the strings */ + /* for each string, get the next weight */ + next_weight(ws, pass __LOCALE_ARG ); + next_weight(ws+1, pass __LOCALE_ARG ); + TRACE(("w0=%lu w1=%lu\n", + (unsigned long) ws[0].weight, + (unsigned long) ws[1].weight)); + + if (ws[0].weight != ws[1].weight) { + return ws[0].weight - ws[1].weight; + } + } while (ws[0].weight); + } while (++pass < CUR_COLLATE->num_weights); + + return 0; +} +__UCXL_ALIAS(wcscoll) + +#ifdef WANT_WIDE + +size_t attribute_hidden __UCXL(wcsxfrm)(wchar_t *__restrict ws1, const wchar_t *__restrict ws2, + size_t n __LOCALE_PARAM ) +{ + col_state_t cs; + size_t count; + int pass; + + if (!CUR_COLLATE->num_weights) { /* C locale */ + return __wcsxfrm(ws1, ws2, n); + } + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning handle empty string as a special case +#endif + + count = pass = 0; + do { /* loop through the weights levels */ + init_col_state(&cs, ws2); + do { /* loop through the string */ + next_weight(&cs, pass __LOCALE_ARG ); + TRACE(("weight=%lu (%#lx)\n", (unsigned long) cs.weight, (unsigned long) cs.weight)); + if (count < n) { + ws1[count] = cs.weight +1; + } + ++count; + TRACE(("--------------------------------------------\n")); + } while (cs.weight); + if (count <= n) { /* overwrite the trailing 0 end-of-pass marker */ + ws1[count-1] = 1; + } + TRACE(("-------------------- pass %d --------------------\n", pass)); + } while (++pass < CUR_COLLATE->num_weights); + if (count <= n) { /* oops... change it back */ + ws1[count-1] = 0; + } + return count-1; +} + +__UCXL_ALIAS(wcsxfrm) + +#else /* WANT_WIDE */ + +static const unsigned long bound[] = { + 1UL << 7, + 1UL << 11, + 1UL << 16, + 1UL << 21, + 1UL << 26, +}; + +static unsigned char first[] = { + 0x0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc +}; + +/* Use an extension of UTF-8 to store a 32 bit val in max 6 bytes. */ + +static size_t store(unsigned char *s, size_t count, size_t n, __uwchar_t weight) +{ + int i, r; + + i = 0; + do { + if (weight < bound[i]) { + break; + } + } while (++i < sizeof(bound)/sizeof(bound[0])); + + r = i+1; + if (i + count < n) { + s += count; + s[0] = first[i]; + while (i) { + s[i] = 0x80 | (weight & 0x3f); + weight >>= 6; + --i; + } + s[0] |= weight; + } + + return r; +} + +size_t attribute_hidden __UCXL(strxfrm)(char *__restrict ws1, const char *__restrict ws2, size_t n + __LOCALE_PARAM ) +{ + col_state_t cs; + size_t count, inc; + int pass; + + if (!CUR_COLLATE->num_weights) { /* C locale */ + return __strlcpy(ws1, ws2, n); + } + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning handle empty string as a special case +#endif + + inc = count = pass = 0; + do { /* loop through the weights levels */ + init_col_state(&cs, ws2); + do { /* loop through the string */ + next_weight(&cs, pass __LOCALE_ARG ); + TRACE(("weight=%lu (%#lx)\n", (unsigned long) cs.weight, (unsigned long) cs.weight)); + inc = store((unsigned char *)ws1, count, n, cs.weight + 1); + count += inc; + TRACE(("--------------------------------------------\n")); + } while (cs.weight); + /* overwrite the trailing 0 end-of-pass marker */ + assert(inc == 1); + if (count <= n) { + ws1[count-1] = 1; + } + TRACE(("-------------------- pass %d --------------------\n", pass)); + } while (++pass < CUR_COLLATE->num_weights); + if (count <= n) { /* oops... change it back */ + ws1[count-1] = 0; + } + return count-1; +} + +__UCXL_ALIAS(strxfrm) + +#endif /* WANT_WIDE */ + +#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ + +#endif /* defined(L_strxfrm) || defined(L_strxfrm_l) || defined(L_wcsxfrm) || defined(L_wcsxfrm_l) */ + +#endif /* __UCLIBC_HAS_LOCALE__ */ +/**********************************************************************/ diff --git a/libc/string/_string.h b/libc/string/_string.h new file mode 100644 index 000000000..4ecde30a7 --- /dev/null +++ b/libc/string/_string.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#ifndef __STRING_H +#define __STRING_H + +#define _GNU_SOURCE +#include +#include +#include +#include + +#ifdef WANT_WIDE +# include +# include +# include +# define Wvoid wchar_t +# define Wchar wchar_t +# define Wuchar __uwchar_t +# define Wint wchar_t +#else +# define Wvoid void +# define Wchar char +typedef unsigned char __string_uchar_t; +# define Wuchar __string_uchar_t +# define Wint int +#endif + +#endif /* __STRING_H */ diff --git a/libc/string/_string_syserrmsgs.c b/libc/string/_string_syserrmsgs.c new file mode 100644 index 000000000..a76c0e3af --- /dev/null +++ b/libc/string/_string_syserrmsgs.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include + +#ifdef __UCLIBC_HAS_ERRNO_MESSAGES__ + +const char _string_syserrmsgs[] = { + /* 0: 0, 8 */ "Success\0" + /* 1: 8, 24 */ "Operation not permitted\0" + /* 2: 32, 26 */ "No such file or directory\0" + /* 3: 58, 16 */ "No such process\0" + /* 4: 74, 24 */ "Interrupted system call\0" + /* 5: 98, 19 */ "Input/output error\0" + /* 6: 117, 26 */ "No such device or address\0" + /* 7: 143, 23 */ "Argument list too long\0" + /* 8: 166, 18 */ "Exec format error\0" + /* 9: 184, 20 */ "Bad file descriptor\0" + /* 10: 204, 19 */ "No child processes\0" + /* 11: 223, 33 */ "Resource temporarily unavailable\0" + /* 12: 256, 23 */ "Cannot allocate memory\0" + /* 13: 279, 18 */ "Permission denied\0" + /* 14: 297, 12 */ "Bad address\0" + /* 15: 309, 22 */ "Block device required\0" + /* 16: 331, 24 */ "Device or resource busy\0" + /* 17: 355, 12 */ "File exists\0" + /* 18: 367, 26 */ "Invalid cross-device link\0" + /* 19: 393, 15 */ "No such device\0" + /* 20: 408, 16 */ "Not a directory\0" + /* 21: 424, 15 */ "Is a directory\0" + /* 22: 439, 17 */ "Invalid argument\0" + /* 23: 456, 30 */ "Too many open files in system\0" + /* 24: 486, 20 */ "Too many open files\0" + /* 25: 506, 31 */ "Inappropriate ioctl for device\0" + /* 26: 537, 15 */ "Text file busy\0" + /* 27: 552, 15 */ "File too large\0" + /* 28: 567, 24 */ "No space left on device\0" + /* 29: 591, 13 */ "Illegal seek\0" + /* 30: 604, 22 */ "Read-only file system\0" + /* 31: 626, 15 */ "Too many links\0" + /* 32: 641, 12 */ "Broken pipe\0" + /* 33: 653, 33 */ "Numerical argument out of domain\0" + /* 34: 686, 30 */ "Numerical result out of range\0" + /* 35: 716, 26 */ "Resource deadlock avoided\0" + /* 36: 742, 19 */ "File name too long\0" + /* 37: 761, 19 */ "No locks available\0" + /* 38: 780, 25 */ "Function not implemented\0" + /* 39: 805, 20 */ "Directory not empty\0" + /* 40: 825, 34 */ "Too many levels of symbolic links\0" + /* 41: 859, 1 */ "\0" + /* 42: 860, 27 */ "No message of desired type\0" + /* 43: 887, 19 */ "Identifier removed\0" + /* 44: 906, 28 */ "Channel number out of range\0" + /* 45: 934, 25 */ "Level 2 not synchronized\0" + /* 46: 959, 15 */ "Level 3 halted\0" + /* 47: 974, 14 */ "Level 3 reset\0" + /* 48: 988, 25 */ "Link number out of range\0" + /* 49: 1013, 29 */ "Protocol driver not attached\0" + /* 50: 1042, 27 */ "No CSI structure available\0" + /* 51: 1069, 15 */ "Level 2 halted\0" + /* 52: 1084, 17 */ "Invalid exchange\0" + /* 53: 1101, 27 */ "Invalid request descriptor\0" + /* 54: 1128, 14 */ "Exchange full\0" + /* 55: 1142, 9 */ "No anode\0" + /* 56: 1151, 21 */ "Invalid request code\0" + /* 57: 1172, 13 */ "Invalid slot\0" + /* 58: 1185, 1 */ "\0" + /* 59: 1186, 21 */ "Bad font file format\0" + /* 60: 1207, 20 */ "Device not a stream\0" + /* 61: 1227, 18 */ "No data available\0" + /* 62: 1245, 14 */ "Timer expired\0" + /* 63: 1259, 25 */ "Out of streams resources\0" + /* 64: 1284, 30 */ "Machine is not on the network\0" + /* 65: 1314, 22 */ "Package not installed\0" + /* 66: 1336, 17 */ "Object is remote\0" + /* 67: 1353, 22 */ "Link has been severed\0" + /* 68: 1375, 16 */ "Advertise error\0" + /* 69: 1391, 14 */ "Srmount error\0" + /* 70: 1405, 28 */ "Communication error on send\0" + /* 71: 1433, 15 */ "Protocol error\0" + /* 72: 1448, 19 */ "Multihop attempted\0" + /* 73: 1467, 19 */ "RFS specific error\0" + /* 74: 1486, 12 */ "Bad message\0" + /* 75: 1498, 38 */ "Value too large for defined data type\0" + /* 76: 1536, 27 */ "Name not unique on network\0" + /* 77: 1563, 29 */ "File descriptor in bad state\0" + /* 78: 1592, 23 */ "Remote address changed\0" + /* 79: 1615, 39 */ "Can not access a needed shared library\0" + /* 80: 1654, 37 */ "Accessing a corrupted shared library\0" + /* 81: 1691, 32 */ ".lib section in a.out corrupted\0" + /* 82: 1723, 48 */ "Attempting to link in too many shared libraries\0" + /* 83: 1771, 38 */ "Cannot exec a shared library directly\0" + /* 84: 1809, 50 */ "Invalid or incomplete multibyte or wide character\0" + /* 85: 1859, 44 */ "Interrupted system call should be restarted\0" + /* 86: 1903, 19 */ "Streams pipe error\0" + /* 87: 1922, 15 */ "Too many users\0" + /* 88: 1937, 31 */ "Socket operation on non-socket\0" + /* 89: 1968, 29 */ "Destination address required\0" + /* 90: 1997, 17 */ "Message too long\0" + /* 91: 2014, 31 */ "Protocol wrong type for socket\0" + /* 92: 2045, 23 */ "Protocol not available\0" + /* 93: 2068, 23 */ "Protocol not supported\0" + /* 94: 2091, 26 */ "Socket type not supported\0" + /* 95: 2117, 24 */ "Operation not supported\0" + /* 96: 2141, 30 */ "Protocol family not supported\0" + /* 97: 2171, 41 */ "Address family not supported by protocol\0" + /* 98: 2212, 23 */ "Address already in use\0" + /* 99: 2235, 32 */ "Cannot assign requested address\0" + /* 100: 2267, 16 */ "Network is down\0" + /* 101: 2283, 23 */ "Network is unreachable\0" + /* 102: 2306, 36 */ "Network dropped connection on reset\0" + /* 103: 2342, 33 */ "Software caused connection abort\0" + /* 104: 2375, 25 */ "Connection reset by peer\0" + /* 105: 2400, 26 */ "No buffer space available\0" + /* 106: 2426, 40 */ "Transport endpoint is already connected\0" + /* 107: 2466, 36 */ "Transport endpoint is not connected\0" + /* 108: 2502, 46 */ "Cannot send after transport endpoint shutdown\0" + /* 109: 2548, 35 */ "Too many references: cannot splice\0" + /* 110: 2583, 21 */ "Connection timed out\0" + /* 111: 2604, 19 */ "Connection refused\0" + /* 112: 2623, 13 */ "Host is down\0" + /* 113: 2636, 17 */ "No route to host\0" + /* 114: 2653, 30 */ "Operation already in progress\0" + /* 115: 2683, 26 */ "Operation now in progress\0" + /* 116: 2709, 22 */ "Stale NFS file handle\0" + /* 117: 2731, 25 */ "Structure needs cleaning\0" + /* 118: 2756, 28 */ "Not a XENIX named type file\0" + /* 119: 2784, 30 */ "No XENIX semaphores available\0" + /* 120: 2814, 21 */ "Is a named type file\0" + /* 121: 2835, 17 */ "Remote I/O error\0" + /* 122: 2852, 20 */ "Disk quota exceeded\0" + /* 123: 2872, 16 */ "No medium found\0" + /* 124: 2888, 18 */ "Wrong medium type" +#if defined(__mips__) || defined(__sparc__) + "\0" + /* 125: 2906, 28 */ "File locking deadlock error" +#endif + /* Note: for mips we are ignoring ECANCELED since glibc doesn't have a + * corresponsding message.*/ +}; + +#endif diff --git a/libc/string/_string_syssigmsgs.c b/libc/string/_string_syssigmsgs.c new file mode 100644 index 000000000..4a94ddf4f --- /dev/null +++ b/libc/string/_string_syssigmsgs.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include + +#ifdef __UCLIBC_HAS_SIGNUM_MESSAGES__ + +const char _string_syssigmsgs[] = { + /* 0: 0, 1 */ "\0" + /* 1: 1, 7 */ "Hangup\0" + /* 2: 8, 10 */ "Interrupt\0" + /* 3: 18, 5 */ "Quit\0" + /* 4: 23, 20 */ "Illegal instruction\0" + /* 5: 43, 22 */ "Trace/breakpoint trap\0" + /* 6: 65, 8 */ "Aborted\0" + /* 7: 73, 10 */ "Bus error\0" + /* 8: 83, 25 */ "Floating point exception\0" + /* 9: 108, 7 */ "Killed\0" + /* 10: 115, 22 */ "User defined signal 1\0" + /* 11: 137, 19 */ "Segmentation fault\0" + /* 12: 156, 22 */ "User defined signal 2\0" + /* 13: 178, 12 */ "Broken pipe\0" + /* 14: 190, 12 */ "Alarm clock\0" + /* 15: 202, 11 */ "Terminated\0" + /* 16: 213, 12 */ "Stack fault\0" + /* 17: 225, 13 */ "Child exited\0" + /* 18: 238, 10 */ "Continued\0" + /* 19: 248, 17 */ "Stopped (signal)\0" + /* 20: 265, 8 */ "Stopped\0" + /* 21: 273, 20 */ "Stopped (tty input)\0" + /* 22: 293, 21 */ "Stopped (tty output)\0" + /* 23: 314, 21 */ "Urgent I/O condition\0" + /* 24: 335, 24 */ "CPU time limit exceeded\0" + /* 25: 359, 25 */ "File size limit exceeded\0" + /* 26: 384, 22 */ "Virtual timer expired\0" + /* 27: 406, 24 */ "Profiling timer expired\0" + /* 28: 430, 15 */ "Window changed\0" + /* 29: 445, 13 */ "I/O possible\0" + /* 30: 458, 14 */ "Power failure\0" + /* 31: 472, 16 */ "Bad system call" +#if defined(__alpha__) || defined(__mips__) || defined(__hppa__) || defined(__sparc__) + /* 32: 488, 9 */ "\0EMT trap" +#endif +}; + +#endif diff --git a/libc/string/_syserrmsg.h b/libc/string/_syserrmsg.h new file mode 100644 index 000000000..efb7a1d59 --- /dev/null +++ b/libc/string/_syserrmsg.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#ifndef __SYSERRMSG_H +#define __SYSERRMSG_H 1 + +/**********************************************************************/ +/* NOTE: If we ever do internationalized syserr messages, this will + * have to be changed! */ + +#if defined(__mips__) || defined(__sparc__) +/* sparce and mips have an extra error entry, as EDEADLK and EDEADLOCK have + * different meanings on those platforms. */ +# define _SYS_NERR 126 +#else +# define _SYS_NERR 125 +#endif + +#ifdef __UCLIBC_HAS_ERRNO_MESSAGES__ +# define _SYS_ERRMSG_MAXLEN 50 +#else /* __UCLIBC_HAS_ERRNO_MESSAGES__ */ +# define _SYS_ERRMSG_MAXLEN 0 +#endif /* __UCLIBC_HAS_ERRNO_MESSAGES__ */ + +#if _SYS_ERRMSG_MAXLEN < __UIM_BUFLEN_INT + 14 +# define _STRERROR_BUFSIZE (__UIM_BUFLEN_INT + 14) +#else +# define _STRERROR_BUFSIZE _SYS_ERRMSG_MAXLEN +#endif + +#endif diff --git a/libc/string/basename.c b/libc/string/basename.c new file mode 100644 index 000000000..403cd770b --- /dev/null +++ b/libc/string/basename.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include "_string.h" + +char attribute_hidden *__basename(const char *path) +{ + register const char *s; + register const char *p; + + p = s = path; + + while (*s) { + if (*s++ == '/') { + p = s; + } + } + + return (char *) p; +} + +strong_alias(__basename,basename) diff --git a/libc/string/bcopy.c b/libc/string/bcopy.c new file mode 100644 index 000000000..59e586b34 --- /dev/null +++ b/libc/string/bcopy.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include "_string.h" + +void attribute_hidden __bcopy(const void *s2, void *s1, size_t n) +{ +#if 1 + __memmove(s1, s2, n); +#else +#ifdef __BCC__ + register char *s; + register const char *p; + + s = s1; + p = s2; + if (p >= s) { + while (n--) { + *s++ = *p++; + } + } else { + s += n; + p += n; + while (n--) { + *--s = *--p; + } + } +#else + register char *s; + register const char *p; + + s = s1; + p = s2; + if (p >= s) { + while (n) { + *s++ = *p++; + --n; + } + } else { + while (n) { + --n; + s[n] = p[n]; + } + } +#endif +#endif +} + +strong_alias(__bcopy,bcopy) diff --git a/libc/string/bzero.c b/libc/string/bzero.c new file mode 100644 index 000000000..0439e39a1 --- /dev/null +++ b/libc/string/bzero.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include "_string.h" + +void attribute_hidden __bzero(void *s, size_t n) +{ +#if 1 + (void)__memset(s, 0, n); +#else + register unsigned char *p = s; +#ifdef __BCC__ + /* bcc can optimize the counter if it thinks it is a pointer... */ + register const char *np = (const char *) n; +#else +#define np n +#endif + + while (np) { + *p++ = 0; + --np; + } +#endif +} +#undef np + +strong_alias(__bzero,bzero) diff --git a/libc/string/dirname.c b/libc/string/dirname.c new file mode 100644 index 000000000..a6242e238 --- /dev/null +++ b/libc/string/dirname.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include "_string.h" + +char *dirname(char *path) +{ + static const char null_or_empty_or_noslash[] = "."; + register char *s; + register char *last; + char *first; + + last = s = path; + + if (s != NULL) { + + LOOP: + while (*s && (*s != '/')) ++s; + first = s; + while (*s == '/') ++s; + if (*s) { + last = first; + goto LOOP; + } + + if (last == path) { + if (*last != '/') { + goto DOT; + } + if ((*++last == '/') && (last[1] == 0)) { + ++last; + } + } + *last = 0; + return path; + } + DOT: + return (char *) null_or_empty_or_noslash; +} diff --git a/libc/string/ffs.c b/libc/string/ffs.c new file mode 100644 index 000000000..fc76e6c70 --- /dev/null +++ b/libc/string/ffs.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* ffsl,ffsll */ + +#include "_string.h" + +int attribute_hidden __ffs(int i) +{ +#if 1 + /* inlined binary search method */ + char n = 1; +#if UINT_MAX == 0xffffU + /* nothing to do here -- just trying to avoiding possible problems */ +#elif UINT_MAX == 0xffffffffU + if (!(i & 0xffff)) { + n += 16; + i >>= 16; + } +#else +#error ffs needs rewriting! +#endif + + if (!(i & 0xff)) { + n += 8; + i >>= 8; + } + if (!(i & 0x0f)) { + n += 4; + i >>= 4; + } + if (!(i & 0x03)) { + n += 2; + i >>= 2; + } + return (i) ? (n + ((i+1) & 0x01)) : 0; + +#else + /* linear search -- slow, but small */ + int n; + + for (n = 0 ; i ; ++n) { + i >>= 1; + } + + return n; +#endif +} + +strong_alias(__ffs,ffs) diff --git a/libc/string/memccpy.c b/libc/string/memccpy.c new file mode 100644 index 000000000..81d20b19c --- /dev/null +++ b/libc/string/memccpy.c @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* No wide analog. */ + +#include "_string.h" + +void attribute_hidden *__memccpy(void * __restrict s1, const void * __restrict s2, int c, size_t n) +{ + register char *r1 = s1; + register const char *r2 = s2; + + while (n-- && (((unsigned char)(*r1++ = *r2++)) != ((unsigned char) c))); + + return (n == (size_t) -1) ? NULL : r1; +} + +strong_alias(__memccpy,memccpy) diff --git a/libc/string/memchr.c b/libc/string/memchr.c index d0aa004d7..288bd9748 100644 --- a/libc/string/memchr.c +++ b/libc/string/memchr.c @@ -1,14 +1,40 @@ /* + * Copyright (C) 2002 Manuel Novoa III * Copyright (C) 2000-2005 Erik Andersen * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ -#define L_memchr -#define Wmemchr __memchr +#include "_string.h" -#include "wstring.c" +#ifdef WANT_WIDE +# define __Wmemchr __wmemchr +# define Wmemchr wmemchr +#else +# define __Wmemchr __memchr +# define Wmemchr memchr +#endif -strong_alias(__memchr, memchr) +Wvoid attribute_hidden *__Wmemchr(const Wvoid *s, Wint c, size_t n) +{ + register const Wuchar *r = (const Wuchar *) s; +#ifdef __BCC__ + /* bcc can optimize the counter if it thinks it is a pointer... */ + register const char *np = (const char *) n; +#else +# define np n +#endif -#undef L_memchr + while (np) { + if (*r == ((Wuchar)c)) { + return (Wvoid *) r; /* silence the warning */ + } + ++r; + --np; + } + + return NULL; +} +#undef np + +strong_alias(__Wmemchr,Wmemchr) diff --git a/libc/string/memcmp.c b/libc/string/memcmp.c index 5963dd174..9808b3785 100644 --- a/libc/string/memcmp.c +++ b/libc/string/memcmp.c @@ -1,16 +1,43 @@ /* + * Copyright (C) 2002 Manuel Novoa III * Copyright (C) 2000-2005 Erik Andersen * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ -#define L_memcmp -#define Wmemcmp __memcmp +#include "_string.h" -#include "wstring.c" +#ifdef WANT_WIDE +# define __Wmemcmp __wmemcmp +# define Wmemcmp wmemcmp +#else +# define __Wmemcmp __memcmp +# define Wmemcmp memcmp +#endif -strong_alias(__memcmp, memcmp) +int attribute_hidden __Wmemcmp(const Wvoid *s1, const Wvoid *s2, size_t n) +{ + register const Wuchar *r1 = (const Wuchar *) s1; + register const Wuchar *r2 = (const Wuchar *) s2; -weak_alias(memcmp, bcmp) +#ifdef WANT_WIDE + while (n && (*r1 == *r2)) { + ++r1; + ++r2; + --n; + } -#undef L_memcmp + return (n == 0) ? 0 : ((*r1 < *r2) ? -1 : 1); +#else + int r = 0; + + while (n-- && ((r = ((int)(*r1++)) - *r2++) == 0)); + + return r; +#endif +} + +strong_alias(__Wmemcmp,Wmemcmp) +#ifndef WANT_WIDE +strong_alias(__memcmp,bcmp) +#endif diff --git a/libc/string/memcpy.c b/libc/string/memcpy.c index 6889271ae..abfe1b4ef 100644 --- a/libc/string/memcpy.c +++ b/libc/string/memcpy.c @@ -1,14 +1,37 @@ /* + * Copyright (C) 2002 Manuel Novoa III * Copyright (C) 2000-2005 Erik Andersen * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ -#define L_memcpy -#define Wmemcpy __memcpy +#include "_string.h" -#include "wstring.c" +#ifdef WANT_WIDE +# define __Wmemcpy __wmemcpy +# define Wmemcpy wmemcpy +#else +# define __Wmemcpy __memcpy +# define Wmemcpy memcpy +#endif -strong_alias(__memcpy, memcpy) +Wvoid attribute_hidden *__Wmemcpy(Wvoid * __restrict s1, const Wvoid * __restrict s2, size_t n) +{ + register Wchar *r1 = s1; + register const Wchar *r2 = s2; -#undef L_memcpy +#ifdef __BCC__ + while (n--) { + *r1++ = *r2++; + } +#else + while (n) { + *r1++ = *r2++; + --n; + } +#endif + + return s1; +} + +strong_alias(__Wmemcpy,Wmemcpy) diff --git a/libc/string/memmem.c b/libc/string/memmem.c new file mode 100644 index 000000000..a42176181 --- /dev/null +++ b/libc/string/memmem.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include "_string.h" + +void attribute_hidden *__memmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen) +{ + register const char *ph; + register const char *pn; + const char *plast; + size_t n; + + if (needlelen == 0) { + return (void *) haystack; + } + + if (haystacklen >= needlelen) { + ph = (const char *) haystack; + pn = (const char *) needle; + plast = ph + (haystacklen - needlelen); + + do { + n = 0; + while (ph[n] == pn[n]) { + if (++n == needlelen) { + return (void *) ph; + } + } + } while (++ph <= plast); + } + + return NULL; +} + +strong_alias(__memmem,memmem) diff --git a/libc/string/memmove.c b/libc/string/memmove.c index 0626ce1f5..9e50cf5a9 100644 --- a/libc/string/memmove.c +++ b/libc/string/memmove.c @@ -1,14 +1,57 @@ /* + * Copyright (C) 2002 Manuel Novoa III * Copyright (C) 2000-2005 Erik Andersen * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ -#define L_memmove -#define Wmemmove __memmove +#include "_string.h" -#include "wstring.c" +#ifdef WANT_WIDE +# define __Wmemmove __wmemmove +# define Wmemmove wmemmove +#else +# define __Wmemmove __memmove +# define Wmemmove memmove +#endif -strong_alias(__memmove, memmove) +Wvoid attribute_hidden *__Wmemmove(Wvoid *s1, const Wvoid *s2, size_t n) +{ +#ifdef __BCC__ + register Wchar *s = (Wchar *) s1; + register const Wchar *p = (const Wchar *) s2; -#undef L_memmove + if (p >= s) { + while (n--) { + *s++ = *p++; + } + } else { + s += n; + p += n; + while (n--) { + *--s = *--p; + } + } + + return s1; +#else + register Wchar *s = (Wchar *) s1; + register const Wchar *p = (const Wchar *) s2; + + if (p >= s) { + while (n) { + *s++ = *p++; + --n; + } + } else { + while (n) { + --n; + s[n] = p[n]; + } + } + + return s1; +#endif +} + +strong_alias(__Wmemmove,Wmemmove) diff --git a/libc/string/mempcpy.c b/libc/string/mempcpy.c index 9f7fab351..aed37d03a 100644 --- a/libc/string/mempcpy.c +++ b/libc/string/mempcpy.c @@ -1,14 +1,37 @@ /* + * Copyright (C) 2002 Manuel Novoa III * Copyright (C) 2000-2005 Erik Andersen * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ -#define L_mempcpy -#define Wmempcpy __mempcpy +#include "_string.h" -#include "wstring.c" +#ifdef WANT_WIDE +# define __Wmempcpy __wmempcpy +# define Wmempcpy wmempcpy +#else +# define __Wmempcpy __mempcpy +# define Wmempcpy mempcpy +#endif -strong_alias(__mempcpy,mempcpy) +Wvoid attribute_hidden *__Wmempcpy(Wvoid * __restrict s1, const Wvoid * __restrict s2, size_t n) +{ + register Wchar *r1 = s1; + register const Wchar *r2 = s2; -#undef L_mempcpy +#ifdef __BCC__ + while (n--) { + *r1++ = *r2++; + } +#else + while (n) { + *r1++ = *r2++; + --n; + } +#endif + + return r1; +} + +strong_alias(__Wmempcpy,Wmempcpy) diff --git a/libc/string/memrchr.c b/libc/string/memrchr.c new file mode 100644 index 000000000..fb696bc6d --- /dev/null +++ b/libc/string/memrchr.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include "_string.h" + +void attribute_hidden *__memrchr(const void *s, int c, size_t n) +{ + register const unsigned char *r; +#ifdef __BCC__ + /* bcc can optimize the counter if it thinks it is a pointer... */ + register const char *np = (const char *) n; +#else +#define np n +#endif + + r = ((unsigned char *)s) + ((size_t) np); + + while (np) { + if (*--r == ((unsigned char)c)) { + return (void *) r; /* silence the warning */ + } + --np; + } + + return NULL; +} +#undef np + +strong_alias(__memrchr,memrchr) diff --git a/libc/string/memset.c b/libc/string/memset.c index 8a5d69ce8..cb97dbce8 100644 --- a/libc/string/memset.c +++ b/libc/string/memset.c @@ -1,14 +1,37 @@ /* + * Copyright (C) 2002 Manuel Novoa III * Copyright (C) 2000-2005 Erik Andersen * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ -#define L_memset -#define Wmemset __memset +#include "_string.h" -#include "wstring.c" +#ifdef WANT_WIDE +# define __Wmemset __wmemset +# define Wmemset wmemset +#else +# define __Wmemset __memset +# define Wmemset memset +#endif -strong_alias(__memset, memset) +Wvoid attribute_hidden *__Wmemset(Wvoid *s, Wint c, size_t n) +{ + register Wuchar *p = (Wuchar *) s; +#ifdef __BCC__ + /* bcc can optimize the counter if it thinks it is a pointer... */ + register const char *np = (const char *) n; +#else +# define np n +#endif -#undef L_memset + while (np) { + *p++ = (Wuchar) c; + --np; + } + + return s; +} +#undef np + +strong_alias(__Wmemset,Wmemset) diff --git a/libc/string/psignal.c b/libc/string/psignal.c new file mode 100644 index 000000000..b6d6a30c0 --- /dev/null +++ b/libc/string/psignal.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include +#include +#include + +extern char *__strsignal (int __sig) __THROW attribute_hidden; + +/* TODO: make this threadsafe with a reentrant version of strsignal? */ + +void psignal(int signum, register const char *message) +{ + /* If the program is calling psignal, it's a safe bet that printf and + * friends are used as well. It is also possible that the calling + * program could buffer stderr, or reassign it. */ + + register const char *sep; + + sep = ": "; + if (!(message && *message)) { /* Caller did not supply a prefix message */ + message = (sep += 2); /* or passed an empty string. */ + } + + fprintf(stderr, "%s%s%s\n", message, sep, __strsignal(signum)); +} diff --git a/libc/string/rawmemchr.c b/libc/string/rawmemchr.c new file mode 100644 index 000000000..81d578a0f --- /dev/null +++ b/libc/string/rawmemchr.c @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2002 Manuel Novoa III + * Copyright (C) 2000-2005 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include "_string.h" + +void attribute_hidden *__rawmemchr(const void *s, int c) +{ + register const unsigned char *r = s; + + while (*r != ((unsigned char)c)) ++r; + + return (void *) r; /* silence the warning */ +} + +strong_alias(__rawmemchr,rawmemchr) diff --git a/libc/string/stpcpy.c b/libc/string/stpcpy.c index c7baf5b9d..540d04831 100644 --- a/libc/string/stpcpy.c +++ b/libc/string/stpcpy.c @@ -1,14 +1,31 @@ /* + * Copyright (C) 2002 Manuel Novoa III * Copyright (C) 2000-2005 Erik Andersen * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ -#define L_stpcpy -#define Wstpcpy __stpcpy +#include "_string.h" -#include "wstring.c" +#ifdef WANT_WIDE +# define __Wstpcpy __wcpcpy +# define Wstpcpy wcpcpy +#else +# define __Wstpcpy __stpcpy +# define Wstpcpy stpcpy +#endif -strong_alias(__stpcpy, stpcpy) +Wchar attribute_hidden *__Wstpcpy(register Wchar * __restrict s1, const Wchar * __restrict s2) +{ +#ifdef __BCC__ + do { + *s1 = *s2++; + } while (*s1++ != 0); +#else + while ( (*s1++ = *s2++) != 0 ); +#endif -#undef L_stpcpy + return s1 - 1; +} + +strong_alias(__Wstpcpy,Wstpcpy) diff --git a/libc/string/stpncpy.c b/libc/string/stpncpy.c index 9875ad4cf..5b45d0ef9 100644 --- a/libc/string/stpncpy.c +++ b/libc/string/stpncpy.c @@ -1,14 +1,41 @@ /* + * Copyright (C) 2002 Manuel Novoa III * Copyright (C) 2000-2005 Erik Andersen * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ -#define L_stpncpy -#define Wstpncpy __stpncpy +#include "_string.h" -#include "wstring.c" +#ifdef WANT_WIDE +# define __Wstpncpy __wcpncpy +# define Wstpncpy wcpncpy +#else +# define __Wstpncpy __stpncpy +# define Wstpncpy stpncpy +#endif -strong_alias(__stpncpy, stpncpy) +Wchar attribute_hidden *__Wstpncpy(register Wchar * __restrict s1, + register const Wchar * __restrict s2, + size_t n) +{ + Wchar *s = s1; + const Wchar *p = s2; -#undef L_stpncpy +#ifdef __BCC__ + while (n--) { + if ((*s = *s2) != 0) s2++; /* Need to fill tail with 0s. */ + ++s; + } + return s1 + (s2 - p); +#else + while (n) { + if ((*s = *s2) != 0) s2++; /* Need to fill tail with 0s. */