/* Copyright (C) 2002 Manuel Novoa III * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! * * Besides uClibc, I'm using this code in my libc for elks, which is * a 16-bit environment with a fairly limited compiler. It would make * things much easier for me if this file isn't modified unnecessarily. * In particular, please put any new or replacement functions somewhere * else, and modify the makefile to use your version instead. * Thanks. Manuel * * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */ /* 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. * * Sep 11, 2003 * Patch by Atsushi Nemoto <anemo@mba.ocn.ne.jp> to do arch-required * mapping of signal strings (alpha, mips, hppa, sparc). */ #define _STDIO_UTILITY #define _GNU_SOURCE #include <string.h> #include <strings.h> #include <stdio.h> #include <limits.h> #include <ctype.h> #include <stdlib.h> #include <errno.h> #include <signal.h> #include <assert.h> #include <locale.h> #ifdef WANT_WIDE #include <wchar.h> #include <wctype.h> #include <bits/uClibc_uwchar.h> #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 /**********************************************************************/ /* NOTE: If we ever do internationalized syserr messages, this will * have to be changed! */ #define _SYS_NERR 125 #if defined(__mips__) || defined(__sparc__) /* sparce and mips have an extra error entry, as EDEADLK and EDEADLOCK have * different meanings on those platforms. */ #undef _SYS_NERR #define _SYS_NERR 126 #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__ */ extern const char _string_syserrmsgs[]; #define _SYS_NSIG 32 #ifdef __UCLIBC_HAS_SIGNUM_MESSAGES__ #define _SYS_SIGMSG_MAXLEN 25 #else /* __UCLIBC_HAS_SIGNUM_MESSAGES__ */ #define _SYS_SIGMSG_MAXLEN 0 #endif /* __UCLIBC_HAS_SIGNUM_MESSAGES__ */ extern const char _string_syssigmsgs[]; #if _SYS_ERRMSG_MAXLEN < __UIM_BUFLEN_INT + 14 #define _STRERROR_BUFSIZE (__UIM_BUFLEN_INT + 14) #else #define _STRERROR_BUFSIZE _SYS_ERRMSG_MAXLEN #endif #if _SYS_SIGMSG_MAXLEN < __UIM_BUFLEN_INT + 15 #define _STRSIGNAL_BUFSIZE (__UIM_BUFLEN_INT + 15) #else #define _STRSIGNAL_BUFSIZE _SYS_SIGMSG_MAXLEN #endif /**********************************************************************/ #if defined(L__string_syserrmsgs) && defined(__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 /**********************************************************************/ #if defined(L_sys_errlist) && defined(__UCLIBC_HAS_SYS_ERRLIST__) link_warning(_sys_errlist, "sys_nerr and sys_errlist are obsolete and uClibc support for them (in at least some configurations) will probably be unavailable in the near future.") const char *const sys_errlist[] = { [0] = _string_syserrmsgs + 0, [EPERM] = _string_syserrmsgs + 8, [ENOENT] = _string_syserrmsgs + 32, [ESRCH] = _string_syserrmsgs + 58, [EINTR] = _string_syserrmsgs + 74, [EIO] = _string_syserrmsgs + 98, [ENXIO] = _string_syserrmsgs + 117, [E2BIG] = _string_syserrmsgs + 143, [ENOEXEC] = _string_syserrmsgs + 166, [EBADF] = _string_syserrmsgs + 184, [ECHILD] = _string_syserrmsgs + 204, [EAGAIN] = _string_syserrmsgs + 223, [ENOMEM] = _string_syserrmsgs + 256, [EACCES] = _string_syserrmsgs + 279, [EFAULT] = _string_syserrmsgs + 297, [ENOTBLK] = _string_syserrmsgs + 309, [EBUSY] = _string_syserrmsgs + 331, [EEXIST] = _string_syserrmsgs + 355, [EXDEV] = _string_syserrmsgs + 367, [ENODEV] = _string_syserrmsgs + 393, [ENOTDIR] = _string_syserrmsgs + 408, [EISDIR] = _string_syserrmsgs + 424, [EINVAL] = _string_syserrmsgs + 439, [ENFILE] = _string_syserrmsgs + 456, [EMFILE] = _string_syserrmsgs + 486, [ENOTTY] = _string_syserrmsgs + 506, [ETXTBSY] = _string_syserrmsgs + 537, [EFBIG] = _string_syserrmsgs + 552, [ENOSPC] = _string_syserrmsgs + 567, [ESPIPE] = _string_syserrmsgs + 591, [EROFS] = _string_syserrmsgs + 604, [EMLINK] = _string_syserrmsgs + 626, [EPIPE] = _string_syserrmsgs + 641, [EDOM] = _string_syserrmsgs + 653, [ERANGE] = _string_syserrmsgs + 686, [EDEADLK] = _string_syserrmsgs + 716, [ENAMETOOLONG] = _string_syserrmsgs + 742, [ENOLCK] = _string_syserrmsgs + 761, [ENOSYS] = _string_syserrmsgs + 780, [ENOTEMPTY] = _string_syserrmsgs + 805, [ELOOP] = _string_syserrmsgs + 825, /* _string_syserrmsgs + 859, */ [ENOMSG] = _string_syserrmsgs + 860, [EIDRM] = _string_syserrmsgs + 887, [ECHRNG] = _string_syserrmsgs + 906, [EL2NSYNC] = _string_syserrmsgs + 934, [EL3HLT] = _string_syserrmsgs + 959, [EL3RST] = _string_syserrmsgs + 974, [ELNRNG] = _string_syserrmsgs + 988, [EUNATCH] = _string_syserrmsgs + 1013, [ENOCSI] = _string_syserrmsgs + 1042, [EL2HLT] = _string_syserrmsgs + 1069, [EBADE] = _string_syserrmsgs + 1084, [EBADR] = _string_syserrmsgs + 1101, [EXFULL] = _string_syserrmsgs + 1128, [ENOANO] = _string_syserrmsgs + 1142, [EBADRQC] = _string_syserrmsgs + 1151, [EBADSLT] = _string_syserrmsgs + 1172, /* _string_syserrmsgs + 1185, */ [EBFONT] = _string_syserrmsgs + 1186, [ENOSTR] = _string_syserrmsgs + 1207, [ENODATA] = _string_syserrmsgs + 1227, [ETIME] = _string_syserrmsgs + 1245, [ENOSR] = _string_syserrmsgs + 1259, [ENONET] = _string_syserrmsgs + 1284, [ENOPKG] = _string_syserrmsgs + 1314, [EREMOTE] = _string_syserrmsgs + 1336, [ENOLINK] = _string_syserrmsgs + 1353, [EADV] = _string_syserrmsgs + 1375, [ESRMNT] = _string_syserrmsgs + 1391, [ECOMM] = _string_syserrmsgs + 1405, [EPROTO] = _string_syserrmsgs + 1433, [EMULTIHOP] = _string_syserrmsgs + 1448, [EDOTDOT] = _string_syserrmsgs + 1467, [EBADMSG] = _string_syserrmsgs + 1486, [EOVERFLOW] = _string_syserrmsgs + 1498, [ENOTUNIQ] = _string_syserrmsgs + 1536, [EBADFD] = _string_syserrmsgs + 1563, [EREMCHG] = _string_syserrmsgs + 1592, [ELIBACC] = _string_syserrmsgs + 1615, [ELIBBAD] = _string_syserrmsgs + 1654, [ELIBSCN] = _string_syserrmsgs + 1691, [ELIBMAX] = _string_syserrmsgs + 1723, [ELIBEXEC] = _string_syserrmsgs + 1771, [EILSEQ] = _string_syserrmsgs + 1809, [ERESTART] = _string_syserrmsgs + 1859, [ESTRPIPE] = _string_syserrmsgs + 1903, [EUSERS] = _string_syserrmsgs + 1922, [ENOTSOCK] = _string_syserrmsgs + 1937, [EDESTADDRREQ] = _string_syserrmsgs + 1968, [EMSGSIZE] = _string_syserrmsgs + 1997, [EPROTOTYPE] = _string_syserrmsgs + 2014, [ENOPROTOOPT] = _string_syserrmsgs + 2045, [EPROTONOSUPPORT] = _string_syserrmsgs + 2068, [ESOCKTNOSUPPORT] = _string_syserrmsgs + 2091, [EOPNOTSUPP] = _string_syserrmsgs + 2117, [EPFNOSUPPORT] = _string_syserrmsgs + 2141, [EAFNOSUPPORT] = _string_syserrmsgs + 2171, [EADDRINUSE] = _string_syserrmsgs + 2212, [EADDRNOTAVAIL] = _string_syserrmsgs + 2235, [ENETDOWN] = _string_syserrmsgs + 2267, [ENETUNREACH] = _string_syserrmsgs + 2283, [ENETRESET] = _string_syserrmsgs + 2306, [ECONNABORTED] = _string_syserrmsgs + 2342, [ECONNRESET] = _string_syserrmsgs + 2375, [ENOBUFS] = _string_syserrmsgs + 2400, [EISCONN] = _string_syserrmsgs + 2426, [ENOTCONN] = _string_syserrmsgs + 2466, [ESHUTDOWN] = _string_syserrmsgs + 2502, [ETOOMANYREFS] = _string_syserrmsgs + 2548, [ETIMEDOUT] = _string_syserrmsgs + 2583, [ECONNREFUSED] = _string_syserrmsgs + 2604, [EHOSTDOWN] = _string_syserrmsgs + 2623, [EHOSTUNREACH] = _string_syserrmsgs + 2636, [EALREADY] = _string_syserrmsgs + 2653, [EINPROGRESS] = _string_syserrmsgs + 2683, [ESTALE] = _string_syserrmsgs + 2709, [EUCLEAN] = _string_syserrmsgs + 2731, [ENOTNAM] = _string_syserrmsgs + 2756, [ENAVAIL] = _string_syserrmsgs + 2784, [EISNAM] = _string_syserrmsgs + 2814, [EREMOTEIO] = _string_syserrmsgs + 2835, [EDQUOT] = _string_syserrmsgs + 2852, [ENOMEDIUM] = _string_syserrmsgs + 2872, [EMEDIUMTYPE] = _string_syserrmsgs + 2888, #if EDEADLOCK != EDEADLK [EDEADLOCK] = _string_syserrmsgs + 2906, #endif #if EWOULDBLOCK != EAGAIN #error EWOULDBLOCK does not equal EAGAIN #endif /* For now, ignore the other arch-specific errors. glibc only maps EPROCLIM. */ /* some other mips errors */ #ifdef ECANCELED #endif #ifdef EINIT #endif #ifdef EREMDEV #endif /* some other sparc errors */ #ifdef EPROCLIM #endif #ifdef ERREMOTE #endif }; int sys_nerr = sizeof(sys_errlist)/sizeof(sys_errlist[0]); #endif /**********************************************************************/ #ifdef L_wmemcpy #define L_memcpy #define Wmemcpy wmemcpy #else #define Wmemcpy memcpy #endif #ifdef L_memcpy Wvoid *Wmemcpy(Wvoid * __restrict s1, const Wvoid * __restrict s2, size_t n) { register Wchar *r1 = s1; register const Wchar *r2 = s2; #ifdef __BCC__ while (n--) { *r1++ = *r2++; } #else while (n) { *r1++ = *r2++; --n; } #endif return s1; } #endif /**********************************************************************/ #ifdef L_wmemmove #define L_memmove #define Wmemmove wmemmove #else #define Wmemmove memmove #endif #ifdef L_memmove Wvoid *Wmemmove(Wvoid *s1, const Wvoid *s2, size_t n) { #ifdef __BCC__ register Wchar *s = (Wchar *) s1; register const Wchar *p = (const Wchar *) s2; 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 } #endif /**********************************************************************/ #ifdef L_wcscpy #define L_strcpy #define Wstrcpy wcscpy #else #define Wstrcpy strcpy #endif #ifdef L_strcpy Wchar *Wstrcpy(Wchar * __restrict s1, const Wchar * __restrict s2) { register Wchar *s = s1; #ifdef __BCC__ do { *s = *s2++; } while (*s++ != 0); #else while ( (*s++ = *s2++) != 0 ); #endif return s1; } #endif /**********************************************************************/ #ifdef L_wcsncpy #define L_strncpy #define Wstrncpy wcsncpy #else #define Wstrncpy strncpy #endif #ifdef L_strncpy Wchar *Wstrncpy(Wchar * __restrict s1, register const Wchar * __restrict s2, size_t n) { register Wchar *s = s1; #ifdef __BCC__ while (n--) { if ((*s = *s2) != 0) s2++; /* Need to fill tail with 0s. */ ++s; } #else while (n) { if ((*s = *s2) != 0) s2++; /* Need to fill tail with 0s. */ ++s; --n; } #endif return s1; } #endif /**********************************************************************/ #ifdef L_wcscat #define L_strcat #define Wstrcat wcscat #else #define Wstrcat strcat #endif #ifdef L_strcat Wchar *Wstrcat(Wchar * __restrict s1, register const Wchar * __restrict s2) { register Wchar *s = s1; while (*s++); --s; while ((*s++ = *s2++) != 0); return s1; } #endif /**********************************************************************/ #ifdef L_wcsncat #define L_strncat #define Wstrncat wcsncat #else #define Wstrncat strncat #endif #ifdef L_strncat Wchar *Wstrncat(Wchar * __restrict s1, register const Wchar * __restrict s2, size_t n) { register Wchar *s = s1; while (*s++); --s; #if __BCC__ while (n-- && ((*s = *s2++) != 0)) ++s; #else while (n && ((*s = *s2++) != 0)) { --n; ++s; } #endif *s = 0; return s1; } #endif /**********************************************************************/ #ifdef L_wmemcmp #define L_memcmp #define Wmemcmp wmemcmp #else #define Wmemcmp memcmp #endif #ifdef L_memcmp #ifndef L_wmemcmp weak_alias(memcmp,bcmp); #endif int Wmemcmp(const Wvoid *s1, const Wvoid *s2, size_t n) { register const Wuchar *r1 = (const Wuchar *) s1; register const Wuchar *r2 = (const Wuchar *) s2; #ifdef WANT_WIDE while (n && (*r1 == *r2)) { ++r1; ++r2; --n; } return (n == 0) ? 0 : ((*r1 < *r2) ? -1 : 1); #else int r = 0; while (n-- && ((r = ((int)(*r1++)) - *r2++) == 0)); return r; #endif } #endif /**********************************************************************/ #ifdef L_wcscmp #define L_strcmp #define Wstrcmp wcscmp #else #define Wstrcmp strcmp #endif #ifdef L_strcmp #ifdef __LOCALE_C_ONLY #ifdef L_wcscmp weak_alias(wcscmp,wcscoll); #else /* L_wcscmp */ weak_alias(strcmp,strcoll); #endif /* L_wcscmp */ #endif /* __LOCALE_C_ONLY */ int Wstrcmp(register const Wchar *s1, register const Wchar *s2) { #ifdef WANT_WIDE while (*((Wuchar *)s1) == *((Wuchar *)s2)) { if (!*s1++) { return 0; } ++s2; } return (*((Wuchar *)s1) < *((Wuchar *)s2)) ? -1 : 1; #else int r; while (((r = ((int)(*((Wuchar *)s1))) - *((Wuchar *)s2++)) == 0) && *s1++); return r; #endif } #endif /**********************************************************************/ #ifdef L_wcsncmp #define L_strncmp #define Wstrncmp wcsncmp #else #define Wstrncmp strncmp #endif #ifdef L_strncmp int Wstrncmp(register const Wchar *s1, register const Wchar *s2, size_t n) { #ifdef WANT_WIDE while (n && (*((Wuchar *)s1) == *((Wuchar *)s2))) { if (!*s1++) { return 0; } ++s2; --n; } return (n == 0) ? 0 : ((*((Wuchar *)s1) < *((Wuchar *)s2)) ? -1 : 1); #else int r = 0; while (n-- && ((r = ((int)(*((unsigned char *)s1))) - *((unsigned char *)s2++)) == 0) && *s1++); return r; #endif } #endif /**********************************************************************/ #ifdef L_wmemchr #define L_memchr #define Wmemchr wmemchr #else #define Wmemchr memchr #endif #ifdef L_memchr Wvoid *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 while (np) { if (*r == ((Wuchar)c)) { return (Wvoid *) r; /* silence the warning */ } ++r; --np; } return NULL; } #undef np #endif /**********************************************************************/ #ifdef L_wcschr #define L_strchr #define Wstrchr wcschr #else #define Wstrchr strchr #endif #ifdef L_strchr #ifndef L_wcschr weak_alias(strchr,index); #endif Wchar *Wstrchr(register const Wchar *s, Wint c) { do { if (*s == ((Wchar)c)) { return (Wchar *) s; /* silence the warning */ } } while (*s++); return NULL; } #endif /**********************************************************************/ #ifdef L_wcscspn #define L_strcspn #define Wstrcspn wcscspn #else #define Wstrcspn strcspn #endif #ifdef L_strcspn size_t Wstrcspn(const Wchar *s1, const Wchar *s2) { register const Wchar *s; register const Wchar *p; for ( s=s1 ; *s ; s++ ) { for ( p=s2 ; *p ; p++ ) { if (*p == *s) goto done; } } done: return s - s1; } #endif /**********************************************************************/ #ifdef L_wcspbrk #define L_strpbrk #define Wstrpbrk wcspbrk #else #define Wstrpbrk strpbrk #endif #ifdef L_strpbrk Wchar *Wstrpbrk(const Wchar *s1, const Wchar *s2) { register const Wchar *s; register const Wchar *p; for ( s=s1 ; *s ; s++ ) { for ( p=s2 ; *p ; p++ ) { if (*p == *s) return (Wchar *) s; /* silence the warning */ } } return NULL; } #endif /**********************************************************************/ #ifdef L_wcsrchr #define L_strrchr #define Wstrrchr wcsrchr #else #define Wstrrchr strrchr #endif #ifdef L_strrchr #ifndef L_wcsrchr weak_alias(strrchr,rindex); #endif Wchar *Wstrrchr(register const Wchar *s, Wint c) { register const Wchar *p; p = NULL; do { if (*s == (Wchar) c) { p = s; } } while (*s++); return (Wchar *) p; /* silence the warning */ } #endif /**********************************************************************/ #ifdef L_wcsspn #define L_strspn #define Wstrspn wcsspn #else #define Wstrspn strspn #endif #ifdef L_strspn size_t Wstrspn(const Wchar *s1, const Wchar *s2) { register const Wchar *s = s1; register const Wchar *p = s2; while (*p) { if (*p++ == *s) { ++s; p = s2; } } return s - s1; } #endif /**********************************************************************/ #ifdef L_wcsstr #define L_strstr #define Wstrstr wcsstr #else #define Wstrstr strstr #endif #ifdef L_strstr /* NOTE: This is the simple-minded O(len(s1) * len(s2)) worst-case approach. */ #ifdef L_wcsstr weak_alias(wcsstr,wcswcs); #endif Wchar *Wstrstr(const Wchar *s1, const Wchar *s2) { register const Wchar *s = s1; register const Wchar *p = s2; do { if (!*p) { return (Wchar *) s1;; } if (*p == *s) { ++p; ++s; } else { p = s2; if (!*s) { return NULL; } s = ++s1; } } while (1); } #endif /**********************************************************************/ #undef Wstrspn #undef Wstrpbrk #ifdef L_wcstok #define L_strtok_r #define Wstrtok_r wcstok #define Wstrspn wcsspn #define Wstrpbrk wcspbrk #else #define Wstrtok_r strtok_r #define Wstrspn strspn #define Wstrpbrk strpbrk #endif #ifdef L_strtok_r Wchar *Wstrtok_r(Wchar * __restrict s1, const Wchar * __restrict s2, Wchar ** __restrict next_start) { register Wchar *s; register Wchar *p; #if 1 if (((s = s1) != NULL) || ((s = *next_start) != NULL)) { if (*(s += Wstrspn(s, s2))) { if ((p = Wstrpbrk(s, s2)) != NULL) { *p++ = 0; } } else { p = s = NULL; } *next_start = p; } return s; #else if (!(s = s1)) { s = *next_start; } if (s && *(s += Wstrspn(s, s2))) { if (*(p = s + Wstrcspn(s, s2))) { *p++ = 0; } *next_start = p; return s; } return NULL; /* TODO: set *next_start = NULL for safety? */ #endif } #endif /**********************************************************************/ /* #ifdef L_wcstok */ /* #define L_strtok */ /* #define Wstrtok wcstok */ /* #define Wstrtok_r wcstok_r */ /* #else */ /* #define Wstrtok strtok */ /* #define Wstrtok_r strtok_r */ /* #endif */ #ifdef L_strtok #define Wstrtok strtok #define Wstrtok_r strtok_r Wchar *Wstrtok(Wchar * __restrict s1, const Wchar * __restrict s2) { static Wchar *next_start; /* Initialized to 0 since in bss. */ return Wstrtok_r(s1, s2, &next_start); } #endif /**********************************************************************/ #ifdef L_wmemset #define L_memset #define Wmemset wmemset #else #define Wmemset memset #endif #ifdef L_memset Wvoid *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 while (np) { *p++ = (Wuchar) c; --np; } return s; } #undef np #endif /**********************************************************************/ #ifdef L_wcslen #define L_strlen #define Wstrlen wcslen #else #define Wstrlen strlen #endif #ifdef L_strlen size_t Wstrlen(const Wchar *s) { register const Wchar *p; for (p=s ; *p ; p++); return p - s; } #endif /**********************************************************************/ /* ANSI/ISO end here */ /**********************************************************************/ #ifdef L_ffs int 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 } #endif /**********************************************************************/ #if defined(L_strcasecmp) || defined(L_strcasecmp_l) || defined(L_wcscasecmp) || defined(L_wcscasecmp_l) #if defined(L_wcscasecmp) || defined(L_wcscasecmp_l) #define strcasecmp wcscasecmp #define strcasecmp_l wcscasecmp_l #define __strcasecmp_l __wcscasecmp_l #ifdef __UCLIBC_DO_XLOCALE #define TOLOWER(C) __towlower_l((C), locale_arg) #else #define TOLOWER(C) towlower((C)) #endif #else /* defined(L_wcscasecmp) || defined(L_wcscasecmp_l) */ #ifdef __UCLIBC_DO_XLOCALE #define TOLOWER(C) __tolower_l((C), locale_arg) #else #define TOLOWER(C) tolower((C)) #endif #endif /* defined(L_wcscasecmp) || defined(L_wcscasecmp_l) */ #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) int strcasecmp(register const Wchar *s1, register const Wchar *s2) { return __strcasecmp_l(s1, s2, __UCLIBC_CURLOCALE); } #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ int __XL(strcasecmp)(register const Wchar *s1, register const Wchar *s2 __LOCALE_PARAM ) { #ifdef WANT_WIDE while ((*s1 == *s2) || (TOLOWER(*s1) == TOLOWER(*s2))) { if (!*s1++) { return 0; } ++s2; } return (((Wuchar)TOLOWER(*s1)) < ((Wuchar)TOLOWER(*s2))) ? -1 : 1; /* TODO -- should wide cmp funcs do wchar or Wuchar compares? */ #else int r = 0; while ( ((s1 == s2) || !(r = ((int)( TOLOWER(*((Wuchar *)s1)))) - TOLOWER(*((Wuchar *)s2)))) && (++s2, *s1++)); return r; #endif } __XL_ALIAS(strcasecmp) #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ #endif /**********************************************************************/ #if defined(L_strncasecmp) || defined(L_strncasecmp_l) || defined(L_wcsncasecmp) || defined(L_wcsncasecmp_l) #if defined(L_wcsncasecmp) || defined(L_wcsncasecmp_l) #define strncasecmp wcsncasecmp #define strncasecmp_l wcsncasecmp_l #define __strncasecmp_l __wcsncasecmp_l #ifdef __UCLIBC_DO_XLOCALE #define TOLOWER(C) __towlower_l((C), locale_arg) #else #define TOLOWER(C) towlower((C)) #endif #else /* defined(L_wcsncasecmp) || defined(L_wcsncasecmp_l) */ #ifdef __UCLIBC_DO_XLOCALE #define TOLOWER(C) __tolower_l((C), locale_arg) #else #define TOLOWER(C) tolower((C)) #endif #endif /* defined(L_wcsncasecmp) || defined(L_wcsncasecmp_l) */ #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) int strncasecmp(register const Wchar *s1, register const Wchar *s2, size_t n) { return __strncasecmp_l(s1, s2, n, __UCLIBC_CURLOCALE); } #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ int __XL(strncasecmp)(register const Wchar *s1, register const Wchar *s2, size_t n __LOCALE_PARAM ) { #ifdef WANT_WIDE while (n && ((*s1 == *s2) || (TOLOWER(*s1) == TOLOWER(*s2)))) { if (!*s1++) { return 0; } ++s2; --n; } return (n == 0) ? 0 : ((((Wuchar)TOLOWER(*s1)) < ((Wuchar)TOLOWER(*s2))) ? -1 : 1); /* TODO -- should wide cmp funcs do wchar or Wuchar compares? */ #else int r = 0; while ( n && ((s1 == s2) || !(r = ((int)( TOLOWER(*((unsigned char *)s1)))) - TOLOWER(*((unsigned char *)s2)))) && (--n, ++s2, *s1++)); return r; #endif } __XL_ALIAS(strncasecmp) #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ #endif /**********************************************************************/ #ifdef L_wcsnlen #define L_strnlen #define Wstrnlen wcsnlen #else #define Wstrnlen strnlen #endif #ifdef L_strnlen size_t Wstrnlen(const Wchar *s, size_t max) { register const Wchar *p = s; #ifdef __BCC__ /* bcc can optimize the counter if it thinks it is a pointer... */ register const char *maxp = (const char *) max; #else #define maxp max #endif while (maxp && *p) { ++p; --maxp; } return p - s; } #undef maxp #endif /**********************************************************************/ /* No wide analog. */ #ifdef L_memccpy void *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; } #endif /**********************************************************************/ #undef Wstrlen #undef Wstrcpy #ifdef L_wcsdup #define L_strdup #define Wstrdup wcsdup #define Wstrlen wcslen #define Wstrcpy wcscpy #else #define Wstrdup strdup #define Wstrlen strlen #define Wstrcpy strcpy #endif #ifdef L_strdup Wchar *Wstrdup(register const Wchar *s1) { register Wchar *s; if ((s = malloc((Wstrlen(s1) + 1) * sizeof(Wchar))) != NULL) { Wstrcpy(s, s1); } return s; } #endif /**********************************************************************/ #ifdef L_strerror char *strerror(int errnum) { static char buf[_STRERROR_BUFSIZE]; _susv3_strerror_r(errnum, buf, sizeof(buf)); return buf; } #endif /**********************************************************************/ /* SUSv3 functions. */ /**********************************************************************/ #ifdef L__susv3_strerror_r #ifdef __UCLIBC_HAS_ERRNO_MESSAGES__ #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 int _susv3_strerror_r(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 _susv3_strerror_r(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__ */ #endif /**********************************************************************/ /* GNU extension functions. */ /**********************************************************************/ #ifdef L__glibc_strerror_r weak_alias(_glibc_strerror_r,__strerror_r); char *_glibc_strerror_r(int errnum, char *strerrbuf, size_t buflen) { _susv3_strerror_r(errnum, strerrbuf, buflen); return strerrbuf; } #endif /**********************************************************************/ #ifdef L_memmem void *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; } #endif /**********************************************************************/ #ifdef L_wmempcpy #define L_mempcpy #define Wmempcpy wmempcpy #else #define Wmempcpy mempcpy #endif #ifdef L_mempcpy #ifndef L_wmempcpy /* uClibc's old string implementation did this to cater to some app. */ weak_alias(mempcpy,__mempcpy); #endif Wvoid *Wmempcpy(Wvoid * __restrict s1, const Wvoid * __restrict s2, size_t n) { register Wchar *r1 = s1; register const Wchar *r2 = s2; #ifdef __BCC__ while (n--) { *r1++ = *r2++; } #else while (n) { *r1++ = *r2++; --n; } #endif return r1; } #endif /**********************************************************************/ #ifdef L_memrchr void *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 #endif /**********************************************************************/ #ifdef L_wcpcpy #define L_stpcpy #define Wstpcpy wcpcpy #else #define Wstpcpy stpcpy #endif #ifdef L_stpcpy Wchar *Wstpcpy(register Wchar * __restrict s1, const Wchar * __restrict s2) { #ifdef __BCC__ do { *s1 = *s2++; } while (*s1++ != 0); #else while ( (*s1++ = *s2++) != 0 ); #endif return s1 - 1; } #endif /**********************************************************************/ #ifdef L_wcpncpy #define L_stpncpy #define Wstpncpy wcpncpy #else #define Wstpncpy stpncpy #endif #ifdef L_stpncpy Wchar *Wstpncpy(register Wchar * __restrict s1, register const Wchar * __restrict s2, size_t n) { Wchar *s = s1; const Wchar *p = s2; #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. */ ++s; --n; } return s1 + (s2 - p); #endif } #endif /**********************************************************************/ #ifdef L_bzero void bzero(void *s, size_t n) { 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; } } #undef np #endif /**********************************************************************/ #ifdef L_bcopy void 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 } #endif /**********************************************************************/ #ifdef L_strcasestr char *strcasestr(const char *s1, const char *s2) { register const char *s = s1; register const char *p = s2; #if 1 do { if (!*p) { return (char *) s1;; } if ((*p == *s) || (tolower(*((unsigned char *)p)) == tolower(*((unsigned char *)s))) ) { ++p; ++s; } else { p = s2; if (!*s) { return NULL; } s = ++s1; } } while (1); #else while (*p && *s) { if ((*p == *s) || (tolower(*((unsigned char *)p)) == tolower(*((unsigned char *)s))) ) { ++p; ++s; } else { p = s2; s = ++s1; } } return (*p) ? NULL : (char *) s1; #endif } #endif /**********************************************************************/ #ifdef L_strndup char *strndup(register const char *s1, size_t n) { register char *s; n = strnlen(s1,n); /* Avoid problems if s1 not nul-terminated. */ if ((s = malloc(n + 1)) != NULL) { memcpy(s, s1, n); s[n] = 0; } return s; } #endif /**********************************************************************/ #ifdef L_strsep char *strsep(char ** __restrict s1, const char * __restrict s2) { register char *s = *s1; register char *p; #if 1 p = NULL; if (s && *s && (p = strpbrk(s, s2))) { *p++ = 0; } #else if (s && *s && *(p = s + strcspn(s, s2))) { *p++ = 0; } else { p = NULL; } #endif *s1 = p; return s; } #endif /**********************************************************************/ #ifdef L_wcschrnul #define L_strchrnul #define __Wstrchrnul __wcschrnul #define Wstrchrnul wcschrnul #else #define __Wstrchrnul __strchrnul #define Wstrchrnul strchrnul #endif #ifdef L_strchrnul extern Wchar *__Wstrchrnul(register const Wchar *s, Wint c); weak_alias(__Wstrchrnul, Wstrchrnul); Wchar *__Wstrchrnul(register const Wchar *s, Wint c) { --s; while (*++s && (*s != ((Wchar)c))); return (Wchar *) s; } #endif /**********************************************************************/ #ifdef L_rawmemchr void *rawmemchr(const void *s, int c) { register const unsigned char *r = s; while (*r != ((unsigned char)c)) ++r; return (void *) r; /* silence the warning */ } #endif /**********************************************************************/ #ifdef L_basename char *basename(const char *path) { register const char *s; register const char *p; p = s = path; while (*s) { if (*s++ == '/') { p = s; } } return (char *) p; } #endif /**********************************************************************/ #ifdef L___xpg_basename 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; } #endif /**********************************************************************/ #ifdef L_dirname 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; } #endif /**********************************************************************/ #ifdef L_strlcat /* OpenBSD function: * Append at most n-1-strlen(dst) chars from src to dst and nul-terminate dst. * Returns strlen(src) + strlen({original} dst), so truncation occurred if the * return val is >= n. * Note: If dst doesn't contain a nul in the first n chars, strlen(dst) is * taken as n. */ size_t strlcat(register char *__restrict dst, register const char *__restrict src, size_t n) { size_t len; char dummy[1]; len = 0; while (1) { if (len >= n) { dst = dummy; break; } if (!*dst) { break; } ++dst; ++len; } while ((*dst = *src) != 0) { if (++len < n) { ++dst; } ++src; } return len; } #endif /**********************************************************************/ #ifdef WANT_WIDE extern size_t __wcslcpy(wchar_t *__restrict dst, const wchar_t *__restrict src, size_t n); #endif #ifdef L___wcslcpy #define L_strlcpy #define Wstrlcpy __wcslcpy #ifdef __LOCALE_C_ONLY weak_alias(__wcslcpy,wcsxfrm); #endif #endif #ifdef L_strlcpy #ifndef L___wcslcpy #define Wstrlcpy strlcpy #ifdef __LOCALE_C_ONLY weak_alias(strlcpy,strxfrm); #endif #endif /* OpenBSD function: * Copy at most n-1 chars from src to dst and nul-terminate dst. * Returns strlen(src), so truncation occurred if the return value is >= n. */ size_t Wstrlcpy(register Wchar *__restrict dst, register const Wchar *__restrict src, size_t n) { const Wchar *src0 = src; Wchar dummy[1]; if (!n) { dst = dummy; } else { --n; } while ((*dst = *src) != 0) { if (n) { --n; ++dst; } ++src; } return src - src0; } #endif /**********************************************************************/ #if defined(L__string_syssigmsgs) && defined(__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 /**********************************************************************/ #if defined(L_sys_siglist) && defined(__UCLIBC_HAS_SYS_SIGLIST__) const char *const sys_siglist[_NSIG] = { [0] = NULL, [SIGHUP] = _string_syssigmsgs + 1, [SIGINT] = _string_syssigmsgs + 8, [SIGQUIT] = _string_syssigmsgs + 18, [SIGILL] = _string_syssigmsgs + 23, [SIGTRAP] = _string_syssigmsgs + 43, [SIGABRT] = _string_syssigmsgs + 65, [SIGBUS] = _string_syssigmsgs + 73, [SIGFPE] = _string_syssigmsgs + 83, [SIGKILL] = _string_syssigmsgs + 108, [SIGUSR1] = _string_syssigmsgs + 115, [SIGSEGV] = _string_syssigmsgs + 137, [SIGUSR2] = _string_syssigmsgs + 156, [SIGPIPE] = _string_syssigmsgs + 178, [SIGALRM] = _string_syssigmsgs + 190, [SIGTERM] = _string_syssigmsgs + 202, #if !(defined(__alpha__) || defined(__mips__) || defined(__sparc__)) [SIGSTKFLT] = _string_syssigmsgs + 213, #endif [SIGCHLD] = _string_syssigmsgs + 225, [SIGCONT] = _string_syssigmsgs + 238, [SIGSTOP] = _string_syssigmsgs + 248, [SIGTSTP] = _string_syssigmsgs + 265, [SIGTTIN] = _string_syssigmsgs + 273, [SIGTTOU] = _string_syssigmsgs + 293, [SIGURG] = _string_syssigmsgs + 314, [SIGXCPU] = _string_syssigmsgs + 335, [SIGXFSZ] = _string_syssigmsgs + 359, [SIGVTALRM] = _string_syssigmsgs + 384, [SIGPROF] = _string_syssigmsgs + 406, [SIGWINCH] = _string_syssigmsgs + 430, [SIGIO] = _string_syssigmsgs + 445, [SIGPWR] = _string_syssigmsgs + 458, [SIGSYS] = _string_syssigmsgs + 472, #if defined(__alpha__) || defined(__mips__) || defined(__hppa__) || defined(__sparc__) [SIGEMT] = _string_syssigmsgs + 488, #endif }; #endif /**********************************************************************/ #ifdef L_strsignal /* TODO: make a threadsafe version? */ #ifdef __UCLIBC_HAS_SIGNUM_MESSAGES__ #if defined(__alpha__) || defined(__mips__) || defined(__hppa__) || defined(__sparc__) static const unsigned char sstridx[] = { 0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGIOT, SIGBUS, SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, #if defined(__alpha__) || defined(__mips__) || defined(__sparc__) 0, #else SIGSTKFLT, #endif SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS, #if defined(__alpha__) || defined(__mips__) || defined(__hppa__) || defined(__sparc__) SIGEMT, #endif }; #endif char *strsignal(int signum) { register char *s; int i; static char buf[_STRSIGNAL_BUFSIZE]; static const char unknown[] = { 'U', 'n', 'k', 'n', 'o', 'w', 'n', ' ', 's', 'i', 'g', 'n', 'a', 'l', ' ' }; #if defined(__alpha__) || defined(__mips__) || defined(__hppa__) || defined(__sparc__) /* Need to translate signum to string index. */ for (i = 0 ; i < sizeof(sstridx)/sizeof(sstridx[0]) ; i++) { if (sstridx[i] == signum) { goto GOT_SSTRIDX; } } i = INT_MAX; /* Failed. */ GOT_SSTRIDX: #else /* No signum to string index translation needed. */ i = signum; #endif if (((unsigned int) signum) < _SYS_NSIG) { /* 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_syssigmsgs ; i ; ++s) { if (!*s) { --i; } } if (*s) { /* Make sure we have an actual message. */ goto DONE; } } s = _int10tostr(buf+sizeof(buf)-1, signum) - sizeof(unknown); memcpy(s, unknown, sizeof(unknown)); DONE: return s; } #else /* __UCLIBC_HAS_SIGNUM_MESSAGES__ */ char *strsignal(int signum) { static char buf[_STRSIGNAL_BUFSIZE]; static const char unknown[] = { 'U', 'n', 'k', 'n', 'o', 'w', 'n', ' ', 's', 'i', 'g', 'n', 'a', 'l', ' ' }; return (char *) memcpy(_int10tostr(buf+sizeof(buf)-1, signum) - sizeof(unknown), unknown, sizeof(unknown)); } #endif /* __UCLIBC_HAS_SIGNUM_MESSAGES__ */ #endif /**********************************************************************/ #ifdef L_psignal /* 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. */ } #if 1 fprintf(stderr, "%s%s%s\n", message, sep, strsignal(signum)); #else /* Note: Assumes stderr not closed or buffered. */ __STDIO_THREADLOCK(stderr); _stdio_fdout(STDERR_FILENO, message, sep, strsignal(signum)); __STDIO_THREADUNLOCK(stderr); #endif } #endif /**********************************************************************/ #ifndef __LOCALE_C_ONLY #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_l strcoll_l #define __wcscoll_l __strcoll_l #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 wcscoll (const Wchar *s0, const Wchar *s1) { return __wcscoll_l(s0, s1, __UCLIBC_CURLOCALE ); } size_t wcsxfrm(Wchar *__restrict ws1, const Wchar *__restrict ws2, size_t n) { return __wcsxfrm_l(ws1, ws2, n, __UCLIBC_CURLOCALE ); } #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 __XL(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; } __XL_ALIAS(wcscoll) #ifdef WANT_WIDE size_t __XL(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 __wcslcpy(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; } __XL_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 __XL(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; } __XL_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 /* __LOCALE_C_ONLY */ /**********************************************************************/