diff options
author | Timo Teräs <timo.teras@iki.fi> | 2014-09-20 10:20:54 +0300 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2014-09-20 10:29:46 +0300 |
commit | 73ccb8f1afc77801f69c6b38164467fb21e8a3e1 (patch) | |
tree | 63f8a6c71c501b987d86ed32245f0854557ee9c8 /main/musl | |
parent | 4cf4058c180ac24d16c0facc784aa88d19de6b8a (diff) | |
download | aports-73ccb8f1afc77801f69c6b38164467fb21e8a3e1.tar.bz2 aports-73ccb8f1afc77801f69c6b38164467fb21e8a3e1.tar.xz |
main/musl: upgrade to git snapshot of 2014-09-20
Introduces C11 features, and multiple bug fixes. Notably
fixes flockfile() corruption (regression) that caused
claws-mail to crash often. Alignas patch was upstreamed
so remove that.
Diffstat (limited to 'main/musl')
-rw-r--r-- | main/musl/0005-4674809b-to-3e936ce8.patch | 3400 | ||||
-rw-r--r-- | main/musl/APKBUILD | 11 | ||||
-rw-r--r-- | main/musl/alignas.patch | 17 |
3 files changed, 3406 insertions, 22 deletions
diff --git a/main/musl/0005-4674809b-to-3e936ce8.patch b/main/musl/0005-4674809b-to-3e936ce8.patch new file mode 100644 index 0000000000..9180e7eab6 --- /dev/null +++ b/main/musl/0005-4674809b-to-3e936ce8.patch @@ -0,0 +1,3400 @@ +diff --git a/arch/arm/bits/alltypes.h.in b/arch/arm/bits/alltypes.h.in +index 183c4c4..bbe3ce6 100644 +--- a/arch/arm/bits/alltypes.h.in ++++ b/arch/arm/bits/alltypes.h.in +@@ -20,6 +20,8 @@ TYPEDEF long suseconds_t; + + TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t; + TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t; ++TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } mtx_t; + TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t; ++TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } cnd_t; + TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t; + TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t; +diff --git a/arch/i386/bits/alltypes.h.in b/arch/i386/bits/alltypes.h.in +index 8ba8f6f..646922b 100644 +--- a/arch/i386/bits/alltypes.h.in ++++ b/arch/i386/bits/alltypes.h.in +@@ -27,13 +27,19 @@ TYPEDEF long double float_t; + TYPEDEF long double double_t; + #endif + ++#ifdef __cplusplus ++TYPEDEF struct { alignas(8) long long __ll; long double __ld; } max_align_t; ++#else + TYPEDEF struct { _Alignas(8) long long __ll; long double __ld; } max_align_t; ++#endif + + TYPEDEF long time_t; + TYPEDEF long suseconds_t; + + TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t; + TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t; ++TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } mtx_t; + TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t; ++TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } cnd_t; + TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t; + TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t; +diff --git a/arch/microblaze/bits/alltypes.h.in b/arch/microblaze/bits/alltypes.h.in +index a03e1b8..95f1ebb 100644 +--- a/arch/microblaze/bits/alltypes.h.in ++++ b/arch/microblaze/bits/alltypes.h.in +@@ -20,6 +20,8 @@ TYPEDEF long suseconds_t; + + TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t; + TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t; ++TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } mtx_t; + TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t; ++TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } cnd_t; + TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t; + TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t; +diff --git a/arch/mips/bits/alltypes.h.in b/arch/mips/bits/alltypes.h.in +index a03e1b8..95f1ebb 100644 +--- a/arch/mips/bits/alltypes.h.in ++++ b/arch/mips/bits/alltypes.h.in +@@ -20,6 +20,8 @@ TYPEDEF long suseconds_t; + + TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t; + TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t; ++TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } mtx_t; + TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t; ++TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } cnd_t; + TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t; + TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t; +diff --git a/arch/or1k/bits/alltypes.h.in b/arch/or1k/bits/alltypes.h.in +index 183c4c4..bbe3ce6 100644 +--- a/arch/or1k/bits/alltypes.h.in ++++ b/arch/or1k/bits/alltypes.h.in +@@ -20,6 +20,8 @@ TYPEDEF long suseconds_t; + + TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t; + TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t; ++TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } mtx_t; + TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t; ++TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } cnd_t; + TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t; + TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t; +diff --git a/arch/powerpc/bits/alltypes.h.in b/arch/powerpc/bits/alltypes.h.in +index ee7f137..7446ab4 100644 +--- a/arch/powerpc/bits/alltypes.h.in ++++ b/arch/powerpc/bits/alltypes.h.in +@@ -20,6 +20,8 @@ TYPEDEF long suseconds_t; + + TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t; + TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t; ++TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } mtx_t; + TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t; ++TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } cnd_t; + TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t; + TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t; +diff --git a/arch/sh/bits/alltypes.h.in b/arch/sh/bits/alltypes.h.in +index ee7f137..7446ab4 100644 +--- a/arch/sh/bits/alltypes.h.in ++++ b/arch/sh/bits/alltypes.h.in +@@ -20,6 +20,8 @@ TYPEDEF long suseconds_t; + + TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t; + TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t; ++TYPEDEF struct { union { int __i[6]; volatile void *volatile __p[6]; } __u; } mtx_t; + TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t; ++TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } cnd_t; + TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t; + TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t; +diff --git a/arch/x32/bits/alltypes.h.in b/arch/x32/bits/alltypes.h.in +index 8e396c9..a469d5c 100644 +--- a/arch/x32/bits/alltypes.h.in ++++ b/arch/x32/bits/alltypes.h.in +@@ -25,6 +25,8 @@ TYPEDEF long long suseconds_t; + + TYPEDEF struct { union { int __i[14]; unsigned long __s[7]; } __u; } pthread_attr_t; + TYPEDEF struct { union { int __i[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t; ++TYPEDEF struct { union { int __i[10]; volatile void *volatile __p[5]; } __u; } mtx_t; + TYPEDEF struct { union { int __i[12]; void *__p[6]; } __u; } pthread_cond_t; ++TYPEDEF struct { union { int __i[12]; void *__p[6]; } __u; } cnd_t; + TYPEDEF struct { union { int __i[14]; void *__p[7]; } __u; } pthread_rwlock_t; + TYPEDEF struct { union { int __i[8]; void *__p[4]; } __u; } pthread_barrier_t; +diff --git a/arch/x86_64/bits/alltypes.h.in b/arch/x86_64/bits/alltypes.h.in +index 7b4f3e7..2ce8e4a 100644 +--- a/arch/x86_64/bits/alltypes.h.in ++++ b/arch/x86_64/bits/alltypes.h.in +@@ -25,6 +25,8 @@ TYPEDEF long suseconds_t; + + TYPEDEF struct { union { int __i[14]; unsigned long __s[7]; } __u; } pthread_attr_t; + TYPEDEF struct { union { int __i[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t; ++TYPEDEF struct { union { int __i[10]; volatile void *volatile __p[5]; } __u; } mtx_t; + TYPEDEF struct { union { int __i[12]; void *__p[6]; } __u; } pthread_cond_t; ++TYPEDEF struct { union { int __i[12]; void *__p[6]; } __u; } cnd_t; + TYPEDEF struct { union { int __i[14]; void *__p[7]; } __u; } pthread_rwlock_t; + TYPEDEF struct { union { int __i[8]; void *__p[4]; } __u; } pthread_barrier_t; +diff --git a/include/fcntl.h b/include/fcntl.h +index 2d8fa6e..ff9fcb9 100644 +--- a/include/fcntl.h ++++ b/include/fcntl.h +@@ -46,6 +46,10 @@ int posix_fallocate(int, off_t, off_t); + #define O_WRONLY 01 + #define O_RDWR 02 + ++#define F_OFD_GETLK 36 ++#define F_OFD_SETLK 37 ++#define F_OFD_SETLKW 38 ++ + #define F_DUPFD_CLOEXEC 1030 + + #define F_RDLCK 0 +diff --git a/include/features.h b/include/features.h +index 294c61d..3cc3e57 100644 +--- a/include/features.h ++++ b/include/features.h +@@ -1,10 +1,14 @@ + #ifndef _FEATURES_H + #define _FEATURES_H + +-#ifdef _ALL_SOURCE ++#if defined(_ALL_SOURCE) && !defined(_GNU_SOURCE) + #define _GNU_SOURCE 1 + #endif + ++#if defined(_DEFAULT_SOURCE) && !defined(_BSD_SOURCE) ++#define _BSD_SOURCE 1 ++#endif ++ + #if !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) \ + && !defined(_XOPEN_SOURCE) && !defined(_GNU_SOURCE) \ + && !defined(_BSD_SOURCE) && !defined(__STRICT_ANSI__) +diff --git a/include/glob.h b/include/glob.h +index 9fbbaa6..76f6c1c 100644 +--- a/include/glob.h ++++ b/include/glob.h +@@ -39,6 +39,7 @@ void globfree(glob_t *); + #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) + #define glob64 glob + #define globfree64 globfree ++#define glob64_t glob_t + #endif + + #ifdef __cplusplus +diff --git a/include/signal.h b/include/signal.h +index c36e4d5..87301ba 100644 +--- a/include/signal.h ++++ b/include/signal.h +@@ -196,7 +196,7 @@ void psignal(int, const char *); + + #endif + +-#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) ++#if defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE) + int killpg(pid_t, int); + int sigaltstack(const stack_t *__restrict, stack_t *__restrict); + int sighold(int); +diff --git a/include/stdlib.h b/include/stdlib.h +index db569d9..97ce5a7 100644 +--- a/include/stdlib.h ++++ b/include/stdlib.h +@@ -114,9 +114,6 @@ long int random (void); + void srandom (unsigned int); + char *initstate (unsigned int, char *, size_t); + char *setstate (char *); +-#endif +- +-#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) + int putenv (char *); + int posix_openpt (int); + int grantpt (int); +diff --git a/include/sys/stat.h b/include/sys/stat.h +index c6abab5..82a6490 100644 +--- a/include/sys/stat.h ++++ b/include/sys/stat.h +@@ -100,8 +100,9 @@ int lchmod(const char *, mode_t); + #define fstat64 fstat + #define lstat64 lstat + #define fstatat64 fstatat +-#define blksize64_t blksize_t + #define blkcnt64_t blkcnt_t ++#define fsblkcnt64_t fsblkcnt_t ++#define fsfilcnt64_t fsfilcnt_t + #define ino64_t ino_t + #define off64_t off_t + #endif +diff --git a/include/sys/types.h b/include/sys/types.h +index f00db03..75e489c 100644 +--- a/include/sys/types.h ++++ b/include/sys/types.h +@@ -73,7 +73,6 @@ typedef unsigned long long u_quad_t; + #endif + + #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +-#define blksize64_t blksize_t + #define blkcnt64_t blkcnt_t + #define fsblkcnt64_t fsblkcnt_t + #define fsfilcnt64_t fsfilcnt_t +diff --git a/include/threads.h b/include/threads.h +new file mode 100644 +index 0000000..0e5836c +--- /dev/null ++++ b/include/threads.h +@@ -0,0 +1,85 @@ ++#ifndef _THREADS_H ++#define _THREADS_H ++ ++#include <features.h> ++#include <time.h> ++ ++#ifdef __cplusplus ++extern "C" { ++typedef unsigned long thrd_t; ++#else ++typedef struct __pthread *thrd_t; ++#define thread_local _Thread_local ++#endif ++ ++typedef int once_flag; ++typedef unsigned tss_t; ++typedef int (*thrd_start_t)(void *); ++typedef void (*tss_dtor_t)(void *); ++ ++#define __NEED_cnd_t ++#define __NEED_mtx_t ++ ++#include <bits/alltypes.h> ++ ++#define TSS_DTOR_ITERATIONS 4 ++ ++enum { ++ thrd_success = 0, ++ thrd_busy = 1, ++ thrd_error = 2, ++ thrd_nomem = 3, ++ thrd_timedout = 4, ++}; ++ ++enum { ++ mtx_plain = 0, ++ mtx_recursive = 1, ++ mtx_timed = 2, ++}; ++ ++#define ONCE_FLAG_INIT 0 ++ ++int thrd_create(thrd_t *, thrd_start_t, void *); ++_Noreturn void thrd_exit(int); ++ ++int thrd_detach(thrd_t); ++int thrd_join(thrd_t, int *); ++ ++int thrd_sleep(const struct timespec *, struct timespec *); ++void thrd_yield(void); ++ ++thrd_t thrd_current(void); ++int thrd_equal(thrd_t, thrd_t); ++#define thrd_equal(A, B) ((A) == (B)) ++ ++void call_once(once_flag *, void (*)(void)); ++ ++int mtx_init(mtx_t *, int); ++void mtx_destroy(mtx_t *); ++ ++int mtx_lock(mtx_t *); ++int mtx_timedlock(mtx_t *__restrict, const struct timespec *__restrict); ++int mtx_trylock(mtx_t *); ++int mtx_unlock(mtx_t *); ++ ++int cnd_init(cnd_t *); ++void cnd_destroy(cnd_t *); ++ ++int cnd_broadcast(cnd_t *); ++int cnd_signal(cnd_t *); ++ ++int cnd_timedwait(cnd_t *__restrict, mtx_t *__restrict, const struct timespec *__restrict); ++int cnd_wait(cnd_t *, mtx_t *); ++ ++int tss_create(tss_t *, tss_dtor_t); ++void tss_delete(tss_t key); ++ ++int tss_set(tss_t, void *); ++void *tss_get(tss_t); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/include/time.h b/include/time.h +index dc88070..16ec08a 100644 +--- a/include/time.h ++++ b/include/time.h +@@ -17,11 +17,11 @@ extern "C" { + #define __NEED_size_t + #define __NEED_time_t + #define __NEED_clock_t ++#define __NEED_struct_timespec + + #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ + || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \ + || defined(_BSD_SOURCE) +-#define __NEED_struct_timespec + #define __NEED_clockid_t + #define __NEED_timer_t + #define __NEED_pid_t +@@ -59,9 +59,11 @@ struct tm *gmtime (const time_t *); + struct tm *localtime (const time_t *); + char *asctime (const struct tm *); + char *ctime (const time_t *); ++int timespec_get(struct timespec *, int); + + #define CLOCKS_PER_SEC 1000000L + ++#define TIME_UTC 1 + + #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ + || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \ +@@ -114,7 +116,7 @@ int timer_getoverrun (timer_t); + #endif + + +-#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) ++#if defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE) + char *strptime (const char *__restrict, const char *__restrict, struct tm *__restrict); + extern int daylight; + extern long timezone; +diff --git a/include/unistd.h b/include/unistd.h +index ac6055a..0fe75d5 100644 +--- a/include/unistd.h ++++ b/include/unistd.h +@@ -140,9 +140,6 @@ int lockf(int, int, off_t); + long gethostid(void); + int nice(int); + void sync(void); +-#endif +- +-#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) + pid_t setpgrp(void); + char *crypt(const char *, const char *); + void encrypt(char *, int); +diff --git a/src/aio/aio_cancel.c b/src/aio/aio_cancel.c +index 5a753b1..16fc431 100644 +--- a/src/aio/aio_cancel.c ++++ b/src/aio/aio_cancel.c +@@ -1,6 +1,7 @@ + #include <aio.h> + #include <pthread.h> + #include <errno.h> ++#include "libc.h" + + int aio_cancel(int fd, struct aiocb *cb) + { +@@ -14,3 +15,5 @@ int aio_cancel(int fd, struct aiocb *cb) + } + return cb->__err==EINPROGRESS ? AIO_NOTCANCELED : AIO_ALLDONE; + } ++ ++LFS64(aio_cancel); +diff --git a/src/aio/aio_error.c b/src/aio/aio_error.c +index a780fd3..fd42ea1 100644 +--- a/src/aio/aio_error.c ++++ b/src/aio/aio_error.c +@@ -1,6 +1,9 @@ + #include <aio.h> ++#include "libc.h" + + int aio_error(const struct aiocb *cb) + { + return cb->__err; + } ++ ++LFS64(aio_error); +diff --git a/src/aio/aio_fsync.c b/src/aio/aio_fsync.c +index 0ac6ea8..6e1a70a 100644 +--- a/src/aio/aio_fsync.c ++++ b/src/aio/aio_fsync.c +@@ -1,5 +1,6 @@ + #include <aio.h> + #include <errno.h> ++#include "libc.h" + + int aio_fsync(int op, struct aiocb *cb) + { +@@ -7,3 +8,5 @@ int aio_fsync(int op, struct aiocb *cb) + errno = EINVAL; + return -1; + } ++ ++LFS64(aio_fsync); +diff --git a/src/aio/aio_readwrite.c b/src/aio/aio_readwrite.c +index 2278226..8753ffd 100644 +--- a/src/aio/aio_readwrite.c ++++ b/src/aio/aio_readwrite.c +@@ -105,3 +105,6 @@ int aio_write(struct aiocb *cb) + cb->aio_lio_opcode = LIO_WRITE; + return new_req(cb); + } ++ ++LFS64(aio_read); ++LFS64(aio_write); +diff --git a/src/aio/aio_return.c b/src/aio/aio_return.c +index df10bdb..c1ce450 100644 +--- a/src/aio/aio_return.c ++++ b/src/aio/aio_return.c +@@ -1,6 +1,9 @@ + #include <aio.h> ++#include "libc.h" + + ssize_t aio_return(struct aiocb *cb) + { + return cb->__ret; + } ++ ++LFS64(aio_return); +diff --git a/src/aio/aio_suspend.c b/src/aio/aio_suspend.c +index 39a1d3a..dcdf601 100644 +--- a/src/aio/aio_suspend.c ++++ b/src/aio/aio_suspend.c +@@ -1,6 +1,7 @@ + #include <aio.h> + #include <errno.h> + #include "pthread_impl.h" ++#include "libc.h" + + /* Due to the requirement that aio_suspend be async-signal-safe, we cannot + * use any locks, wait queues, etc. that would make it more efficient. The +@@ -55,3 +56,5 @@ int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec + } + } + } ++ ++LFS64(aio_suspend); +diff --git a/src/aio/lio_listio.c b/src/aio/lio_listio.c +index 75ed225..bd37767 100644 +--- a/src/aio/lio_listio.c ++++ b/src/aio/lio_listio.c +@@ -141,3 +141,4 @@ int lio_listio(int mode, struct aiocb *restrict const *restrict cbs, int cnt, st + return 0; + } + ++LFS64(lio_listio); +diff --git a/src/conf/fpathconf.c b/src/conf/fpathconf.c +index 28c4345..8eb037e 100644 +--- a/src/conf/fpathconf.c ++++ b/src/conf/fpathconf.c +@@ -27,7 +27,7 @@ long fpathconf(int fd, int name) + [_PC_SYMLINK_MAX] = SYMLINK_MAX, + [_PC_2_SYMLINKS] = 1 + }; +- if (name > sizeof(values)/sizeof(values[0])) { ++ if (name >= sizeof(values)/sizeof(values[0])) { + errno = EINVAL; + return -1; + } +diff --git a/src/dirent/versionsort.c b/src/dirent/versionsort.c +index 9769610..410cb70 100644 +--- a/src/dirent/versionsort.c ++++ b/src/dirent/versionsort.c +@@ -1,8 +1,12 @@ + #define _GNU_SOURCE + #include <string.h> + #include <dirent.h> ++#include "libc.h" + + int versionsort(const struct dirent **a, const struct dirent **b) + { + return strverscmp((*a)->d_name, (*b)->d_name); + } ++ ++#undef versionsort64 ++LFS64(versionsort); +diff --git a/src/internal/intscan.c b/src/internal/intscan.c +index 69350ef..65d497e 100644 +--- a/src/internal/intscan.c ++++ b/src/internal/intscan.c +@@ -83,6 +83,7 @@ unsigned long long __intscan(FILE *f, unsigned base, int pok, unsigned long long + for (; val[c]<base; c=shgetc(f)); + errno = ERANGE; + y = lim; ++ if (lim&1) neg = 0; + } + done: + shunget(f); +diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h +index 74c62cc..ae6e60b 100644 +--- a/src/internal/pthread_impl.h ++++ b/src/internal/pthread_impl.h +@@ -128,4 +128,6 @@ void __restore_sigs(void *); + #define DEFAULT_STACK_SIZE 81920 + #define DEFAULT_GUARD_SIZE PAGE_SIZE + ++#define __ATTRP_C11_THREAD ((void*)(uintptr_t)-1) ++ + #endif +diff --git a/src/locale/__lctrans.c b/src/locale/__lctrans.c +index 2769c08..15994c5 100644 +--- a/src/locale/__lctrans.c ++++ b/src/locale/__lctrans.c +@@ -2,7 +2,7 @@ + #include "locale_impl.h" + #include "libc.h" + +-const char *dummy(const char *msg, const struct __locale_map *lm) ++static const char *dummy(const char *msg, const struct __locale_map *lm) + { + return msg; + } +diff --git a/src/math/__polevll.c b/src/math/__polevll.c +index a272865..ce1a840 100644 +--- a/src/math/__polevll.c ++++ b/src/math/__polevll.c +@@ -56,6 +56,8 @@ + + #include "libm.h" + ++#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 ++#else + /* + * Polynomial evaluator: + * P[0] x^n + P[1] x^(n-1) + ... + P[n] +@@ -88,3 +90,4 @@ long double __p1evll(long double x, const long double *P, int n) + + return y; + } ++#endif +diff --git a/src/math/exp10.c b/src/math/exp10.c +index 16d704a..9f5e3c2 100644 +--- a/src/math/exp10.c ++++ b/src/math/exp10.c +@@ -1,5 +1,6 @@ + #define _GNU_SOURCE + #include <math.h> ++#include <stdint.h> + #include "libc.h" + + double exp10(double x) +@@ -11,7 +12,9 @@ double exp10(double x) + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15 + }; + double n, y = modf(x, &n); +- if (fabs(n) < 16) { ++ union {double f; uint64_t i;} u = {n}; ++ /* fabs(n) < 16 without raising invalid on nan */ ++ if ((u.i>>52 & 0x7ff) < 0x3ff+4) { + if (!y) return p10[(int)n+15]; + y = exp2(3.32192809488736234787031942948939 * y); + return y * p10[(int)n+15]; +diff --git a/src/math/exp10f.c b/src/math/exp10f.c +index 5fd1af9..7a8d447 100644 +--- a/src/math/exp10f.c ++++ b/src/math/exp10f.c +@@ -1,5 +1,6 @@ + #define _GNU_SOURCE + #include <math.h> ++#include <stdint.h> + #include "libc.h" + + float exp10f(float x) +@@ -9,7 +10,9 @@ float exp10f(float x) + 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 + }; + float n, y = modff(x, &n); +- if (fabsf(n) < 8) { ++ union {float f; uint32_t i;} u = {n}; ++ /* fabsf(n) < 8 without raising invalid on nan */ ++ if ((u.i>>23 & 0xff) < 0x7f+3) { + if (!y) return p10[(int)n+7]; + y = exp2f(3.32192809488736234787031942948939f * y); + return y * p10[(int)n+7]; +diff --git a/src/math/exp10l.c b/src/math/exp10l.c +index 22a4636..b758ebf 100644 +--- a/src/math/exp10l.c ++++ b/src/math/exp10l.c +@@ -1,7 +1,15 @@ + #define _GNU_SOURCE ++#include <float.h> + #include <math.h> + #include "libc.h" ++#include "libm.h" + ++#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 ++long double exp10l(long double x) ++{ ++ return exp10(x); ++} ++#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + long double exp10l(long double x) + { + static const long double p10[] = { +@@ -11,12 +19,15 @@ long double exp10l(long double x) + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15 + }; + long double n, y = modfl(x, &n); +- if (fabsl(n) < 16) { ++ union ldshape u = {n}; ++ /* fabsl(n) < 16 without raising invalid on nan */ ++ if ((u.i.se & 0x7fff) < 0x3fff+4) { + if (!y) return p10[(int)n+15]; + y = exp2l(3.32192809488736234787031942948939L * y); + return y * p10[(int)n+15]; + } + return powl(10.0, x); + } ++#endif + + weak_alias(exp10l, pow10l); +diff --git a/src/mman/mprotect.c b/src/mman/mprotect.c +index f488486..535787b 100644 +--- a/src/mman/mprotect.c ++++ b/src/mman/mprotect.c +@@ -2,10 +2,12 @@ + #include "libc.h" + #include "syscall.h" + +-int mprotect(void *addr, size_t len, int prot) ++int __mprotect(void *addr, size_t len, int prot) + { + size_t start, end; + start = (size_t)addr & -PAGE_SIZE; + end = (size_t)((char *)addr + len + PAGE_SIZE-1) & -PAGE_SIZE; + return syscall(SYS_mprotect, start, end-start, prot); + } ++ ++weak_alias(__mprotect, mprotect); +diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c +index 2ba66e3..3484fc6 100644 +--- a/src/network/getnameinfo.c ++++ b/src/network/getnameinfo.c +@@ -96,7 +96,7 @@ static void reverse_services(char *buf, int port, int dgram) + if ((p=strchr(line, '#'))) *p++='\n', *p=0; + + for (p=line; *p && !isspace(*p); p++); +- if (!p) continue; ++ if (!*p) continue; + *p++ = 0; + svport = strtoul(p, &z, 10); + +diff --git a/src/network/lookup_serv.c b/src/network/lookup_serv.c +index bf4cba0..a9be0f3 100644 +--- a/src/network/lookup_serv.c ++++ b/src/network/lookup_serv.c +@@ -52,7 +52,6 @@ int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int pro + + /* Skip past canonical name at beginning of line */ + for (p=line; *p && !isspace(*p); p++); +- if (!p) continue; + + port = strtoul(p, &z, 10); + if (port > 65535 || z==p) continue; +diff --git a/src/regex/regcomp.c b/src/regex/regcomp.c +index d907627..4cdaa1e 100644 +--- a/src/regex/regcomp.c ++++ b/src/regex/regcomp.c +@@ -34,6 +34,7 @@ + #include <regex.h> + #include <limits.h> + #include <stdint.h> ++#include <ctype.h> + + #include "tre.h" + +@@ -135,108 +136,88 @@ typedef struct { + tre_ast_node_t *right; + } tre_union_t; + +-static tre_ast_node_t * +-tre_ast_new_node(tre_mem_t mem, tre_ast_type_t type, size_t size); +- +-static tre_ast_node_t * +-tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position); +- +-static tre_ast_node_t * +-tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max, +- int minimal); +- +-static tre_ast_node_t * +-tre_ast_new_union(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right); +- +-static tre_ast_node_t * +-tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left, +- tre_ast_node_t *right); +- + + static tre_ast_node_t * +-tre_ast_new_node(tre_mem_t mem, tre_ast_type_t type, size_t size) ++tre_ast_new_node(tre_mem_t mem, int type, void *obj) + { +- tre_ast_node_t *node; +- +- node = tre_mem_calloc(mem, sizeof(*node)); +- if (!node) +- return NULL; +- node->obj = tre_mem_calloc(mem, size); +- if (!node->obj) +- return NULL; +- node->type = type; +- node->nullable = -1; +- node->submatch_id = -1; +- +- return node; ++ tre_ast_node_t *node = tre_mem_calloc(mem, sizeof *node); ++ if (!node || !obj) ++ return 0; ++ node->obj = obj; ++ node->type = type; ++ node->nullable = -1; ++ node->submatch_id = -1; ++ return node; + } + + static tre_ast_node_t * + tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position) + { +- tre_ast_node_t *node; +- tre_literal_t *lit; +- +- node = tre_ast_new_node(mem, LITERAL, sizeof(tre_literal_t)); +- if (!node) +- return NULL; +- lit = node->obj; +- lit->code_min = code_min; +- lit->code_max = code_max; +- lit->position = position; +- +- return node; ++ tre_ast_node_t *node; ++ tre_literal_t *lit; ++ ++ lit = tre_mem_calloc(mem, sizeof *lit); ++ node = tre_ast_new_node(mem, LITERAL, lit); ++ if (!node) ++ return 0; ++ lit->code_min = code_min; ++ lit->code_max = code_max; ++ lit->position = position; ++ return node; + } + + static tre_ast_node_t * +-tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max, +- int minimal) ++tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max, int minimal) + { +- tre_ast_node_t *node; +- tre_iteration_t *iter; +- +- node = tre_ast_new_node(mem, ITERATION, sizeof(tre_iteration_t)); +- if (!node) +- return NULL; +- iter = node->obj; +- iter->arg = arg; +- iter->min = min; +- iter->max = max; +- iter->minimal = minimal; +- node->num_submatches = arg->num_submatches; +- +- return node; ++ tre_ast_node_t *node; ++ tre_iteration_t *iter; ++ ++ iter = tre_mem_calloc(mem, sizeof *iter); ++ node = tre_ast_new_node(mem, ITERATION, iter); ++ if (!node) ++ return 0; ++ iter->arg = arg; ++ iter->min = min; ++ iter->max = max; ++ iter->minimal = minimal; ++ node->num_submatches = arg->num_submatches; ++ return node; + } + + static tre_ast_node_t * + tre_ast_new_union(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right) + { +- tre_ast_node_t *node; +- +- node = tre_ast_new_node(mem, UNION, sizeof(tre_union_t)); +- if (node == NULL) +- return NULL; +- ((tre_union_t *)node->obj)->left = left; +- ((tre_union_t *)node->obj)->right = right; +- node->num_submatches = left->num_submatches + right->num_submatches; +- +- return node; ++ tre_ast_node_t *node; ++ tre_union_t *un; ++ ++ if (!left) ++ return right; ++ un = tre_mem_calloc(mem, sizeof *un); ++ node = tre_ast_new_node(mem, UNION, un); ++ if (!node || !right) ++ return 0; ++ un->left = left; ++ un->right = right; ++ node->num_submatches = left->num_submatches + right->num_submatches; ++ return node; + } + + static tre_ast_node_t * +-tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left, +- tre_ast_node_t *right) ++tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right) + { +- tre_ast_node_t *node; +- +- node = tre_ast_new_node(mem, CATENATION, sizeof(tre_catenation_t)); +- if (node == NULL) +- return NULL; +- ((tre_catenation_t *)node->obj)->left = left; +- ((tre_catenation_t *)node->obj)->right = right; +- node->num_submatches = left->num_submatches + right->num_submatches; +- +- return node; ++ tre_ast_node_t *node; ++ tre_catenation_t *cat; ++ ++ if (!left) ++ return right; ++ cat = tre_mem_calloc(mem, sizeof *cat); ++ node = tre_ast_new_node(mem, CATENATION, cat); ++ if (!node) ++ return 0; ++ cat->left = left; ++ cat->right = right; ++ node->num_submatches = left->num_submatches + right->num_submatches; ++ return node; + } + + +@@ -412,1077 +393,654 @@ define_popf(voidptr, void *) + + /* Parse context. */ + typedef struct { +- /* Memory allocator. The AST is allocated using this. */ +- tre_mem_t mem; +- /* Stack used for keeping track of regexp syntax. */ +- tre_stack_t *stack; +- /* The parse result. */ +- tre_ast_node_t *result; +- /* The regexp to parse and its length. */ +- const char *re; +- /* The first character of the entire regexp. */ +- const char *re_start; +- /* Current submatch ID. */ +- int submatch_id; +- /* Current position (number of literal). */ +- int position; +- /* The highest back reference or -1 if none seen so far. */ +- int max_backref; +- /* This flag is set if the regexp uses approximate matching. */ +- int have_approx; +- /* Compilation flags. */ +- int cflags; +- /* If this flag is set the top-level submatch is not captured. */ +- int nofirstsub; ++ /* Memory allocator. The AST is allocated using this. */ ++ tre_mem_t mem; ++ /* Stack used for keeping track of regexp syntax. */ ++ tre_stack_t *stack; ++ /* The parsed node after a parse function returns. */ ++ tre_ast_node_t *n; ++ /* Position in the regexp pattern after a parse function returns. */ ++ const char *s; ++ /* The first character of the regexp. */ ++ const char *re; ++ /* Current submatch ID. */ ++ int submatch_id; ++ /* Current position (number of literal). */ ++ int position; ++ /* The highest back reference or -1 if none seen so far. */ ++ int max_backref; ++ /* Compilation flags. */ ++ int cflags; + } tre_parse_ctx_t; + +-/* Parses a wide character regexp pattern into a syntax tree. This parser +- handles both syntaxes (BRE and ERE), including the TRE extensions. */ +-static reg_errcode_t +-tre_parse(tre_parse_ctx_t *ctx); +- +- +-/* +- This parser is just a simple recursive descent parser for POSIX.2 +- regexps. The parser supports both the obsolete default syntax and +- the "extended" syntax, and some nonstandard extensions. +-*/ +- +-/* Characters with special meanings in regexp syntax. */ +-#define CHAR_PIPE '|' +-#define CHAR_LPAREN '(' +-#define CHAR_RPAREN ')' +-#define CHAR_LBRACE '{' +-#define CHAR_RBRACE '}' +-#define CHAR_LBRACKET '[' +-#define CHAR_RBRACKET ']' +-#define CHAR_MINUS '-' +-#define CHAR_STAR '*' +-#define CHAR_QUESTIONMARK '?' +-#define CHAR_PLUS '+' +-#define CHAR_PERIOD '.' +-#define CHAR_COLON ':' +-#define CHAR_EQUAL '=' +-#define CHAR_COMMA ',' +-#define CHAR_CARET '^' +-#define CHAR_DOLLAR '$' +-#define CHAR_BACKSLASH '\\' +-#define CHAR_HASH '#' +-#define CHAR_TILDE '~' +- +- + /* Some macros for expanding \w, \s, etc. */ +-static const struct tre_macro_struct { +- const char c; +- const char *expansion; +-} tre_macros[] = +- { {'t', "\t"}, {'n', "\n"}, {'r', "\r"}, +- {'f', "\f"}, {'a', "\a"}, {'e', "\033"}, +- {'w', "[[:alnum:]_]"}, {'W', "[^[:alnum:]_]"}, {'s', "[[:space:]]"}, +- {'S', "[^[:space:]]"}, {'d', "[[:digit:]]"}, {'D', "[^[:digit:]]"}, +- { 0, NULL } +- }; +- ++static const struct { ++ char c; ++ const char *expansion; ++} tre_macros[] = { ++ {'t', "\t"}, {'n', "\n"}, {'r', "\r"}, ++ {'f', "\f"}, {'a', "\a"}, {'e', "\033"}, ++ {'w', "[[:alnum:]_]"}, {'W', "[^[:alnum:]_]"}, {'s', "[[:space:]]"}, ++ {'S', "[^[:space:]]"}, {'d', "[[:digit:]]"}, {'D', "[^[:digit:]]"}, ++ { 0, 0 } ++}; + + /* Expands a macro delimited by `regex' and `regex_end' to `buf', which + must have at least `len' items. Sets buf[0] to zero if the there + is no match in `tre_macros'. */ +-static const char * +-tre_expand_macro(const char *regex) ++static const char *tre_expand_macro(const char *s) + { +- int i; +- +- if (!*regex) +- return 0; +- +- for (i = 0; tre_macros[i].expansion && tre_macros[i].c != *regex; i++); +- return tre_macros[i].expansion; ++ int i; ++ for (i = 0; tre_macros[i].c && tre_macros[i].c != *s; i++); ++ return tre_macros[i].expansion; + } + +-static reg_errcode_t +-tre_new_item(tre_mem_t mem, int min, int max, int *i, int *max_i, +- tre_ast_node_t ***items) ++static int ++tre_compare_lit(const void *a, const void *b) + { +- reg_errcode_t status; +- tre_ast_node_t **array = *items; +- /* Allocate more space if necessary. */ +- if (*i >= *max_i) +- { +- tre_ast_node_t **new_items; +- /* If the array is already 1024 items large, give up -- there's +- probably an error in the regexp (e.g. not a '\0' terminated +- string and missing ']') */ +- if (*max_i > 1024) +- return REG_ESPACE; +- *max_i *= 2; +- new_items = xrealloc(array, sizeof(*array) * *max_i); +- if (new_items == NULL) +- return REG_ESPACE; +- *items = array = new_items; +- } +- array[*i] = tre_ast_new_literal(mem, min, max, -1); +- status = array[*i] == NULL ? REG_ESPACE : REG_OK; +- (*i)++; +- return status; ++ const tre_literal_t *const *la = a; ++ const tre_literal_t *const *lb = b; ++ /* assumes the range of valid code_min is < INT_MAX */ ++ return la[0]->code_min - lb[0]->code_min; + } + ++struct literals { ++ tre_mem_t mem; ++ tre_literal_t **a; ++ int len; ++ int cap; ++}; + +-static int +-tre_compare_items(const void *a, const void *b) ++static tre_literal_t *tre_new_lit(struct literals *p) + { +- const tre_ast_node_t *node_a = *(tre_ast_node_t * const *)a; +- const tre_ast_node_t *node_b = *(tre_ast_node_t * const *)b; +- tre_literal_t *l_a = node_a->obj, *l_b = node_b->obj; +- int a_min = l_a->code_min, b_min = l_b->code_min; +- +- if (a_min < b_min) +- return -1; +- else if (a_min > b_min) +- return 1; +- else +- return 0; ++ tre_literal_t **a; ++ if (p->len >= p->cap) { ++ if (p->cap >= 1<<15) ++ return 0; ++ p->cap *= 2; ++ a = xrealloc(p->a, p->cap * sizeof *p->a); ++ if (!a) ++ return 0; ++ p->a = a; ++ } ++ a = p->a + p->len++; ++ *a = tre_mem_calloc(p->mem, sizeof **a); ++ return *a; + } + +-/* Maximum number of character classes that can occur in a negated bracket +- expression. */ +-#define MAX_NEG_CLASSES 64 +- +-/* Maximum length of character class names. */ +-#define MAX_CLASS_NAME +- +-static reg_errcode_t +-tre_parse_bracket_items(tre_parse_ctx_t *ctx, int negate, +- tre_ctype_t neg_classes[], int *num_neg_classes, +- tre_ast_node_t ***items, int *num_items, +- int *items_size) ++static int add_icase_literals(struct literals *ls, int min, int max) + { +- const char *re = ctx->re; +- reg_errcode_t status = REG_OK; +- tre_ctype_t class = (tre_ctype_t)0; +- int i = *num_items; +- int max_i = *items_size; +- int skip; +- +- /* Build an array of the items in the bracket expression. */ +- while (status == REG_OK) +- { +- skip = 0; +- if (!*re) +- { +- status = REG_EBRACK; +- } +- else if (*re == CHAR_RBRACKET && re > ctx->re) +- { +- re++; +- break; ++ tre_literal_t *lit; ++ int b, e, c; ++ for (c=min; c<=max; ) { ++ /* assumes islower(c) and isupper(c) are exclusive ++ and toupper(c)!=c if islower(c). ++ multiple opposite case characters are not supported */ ++ if (tre_islower(c)) { ++ b = e = tre_toupper(c); ++ for (c++, e++; c<=max; c++, e++) ++ if (tre_toupper(c) != e) break; ++ } else if (tre_isupper(c)) { ++ b = e = tre_tolower(c); ++ for (c++, e++; c<=max; c++, e++) ++ if (tre_tolower(c) != e) break; ++ } else { ++ c++; ++ continue; ++ } ++ lit = tre_new_lit(ls); ++ if (!lit) ++ return -1; ++ lit->code_min = b; ++ lit->code_max = e-1; ++ lit->position = -1; + } +- else +- { +- tre_cint_t min = 0, max = 0; +- wchar_t wc; +- int clen = mbtowc(&wc, re, -1); ++ return 0; ++} + +- if (clen<0) clen=1, wc=WEOF; + +- class = (tre_ctype_t)0; +- if (*(re + clen) == CHAR_MINUS && *(re + clen + 1) != CHAR_RBRACKET) +- { +- min = wc; +- re += clen+1; +- clen = mbtowc(&wc, re, -1); +- if (clen<0) clen=1, wc=WEOF; +- max = wc; +- re += clen; +- /* XXX - Should use collation order instead of encoding values +- in character ranges. */ +- if (min > max) +- status = REG_ERANGE; +- } +- else if (*re == CHAR_LBRACKET && *(re + 1) == CHAR_PERIOD) +- status = REG_ECOLLATE; +- else if (*re == CHAR_LBRACKET && *(re + 1) == CHAR_EQUAL) +- status = REG_ECOLLATE; +- else if (*re == CHAR_LBRACKET && *(re + 1) == CHAR_COLON) +- { +- char tmp_str[64]; +- const char *endptr = re + 2; +- int len; +- while (*endptr && *endptr != CHAR_COLON) +- endptr++; +- if (*endptr) +- { +- len = MIN(endptr - re - 2, 63); +- strncpy(tmp_str, re + 2, len); +- tmp_str[len] = '\0'; +- class = tre_ctype(tmp_str); +- if (!class) +- status = REG_ECTYPE; +- re = endptr + 2; +- } +- else +- status = REG_ECTYPE; +- min = 0; +- max = TRE_CHAR_MAX; +- } +- else +- { +- if (*re == CHAR_MINUS && *(re + 1) != CHAR_RBRACKET +- && ctx->re != re) +- /* Two ranges are not allowed to share and endpoint. */ +- status = REG_ERANGE; +- min = max = wc; +- re += clen; +- } ++/* Maximum number of character classes in a negated bracket expression. */ ++#define MAX_NEG_CLASSES 64 + +- if (status != REG_OK) +- break; ++struct neg { ++ int negate; ++ int len; ++ tre_ctype_t a[MAX_NEG_CLASSES]; ++}; + +- if (class && negate) +- if (*num_neg_classes >= MAX_NEG_CLASSES) +- status = REG_ESPACE; +- else +- neg_classes[(*num_neg_classes)++] = class; +- else if (!skip) +- { +- status = tre_new_item(ctx->mem, min, max, &i, &max_i, items); +- if (status != REG_OK) +- break; +- ((tre_literal_t*)((*items)[i-1])->obj)->class = class; +- } ++// TODO: parse bracket into a set of non-overlapping [lo,hi] ranges + +- /* Add opposite-case counterpoints if REG_ICASE is present. +- This is broken if there are more than two "same" characters. */ +- if (ctx->cflags & REG_ICASE && !class && status == REG_OK && !skip) +- { +- tre_cint_t cmin, ccurr; ++/* ++bracket grammar: ++Bracket = '[' List ']' | '[^' List ']' ++List = Term | List Term ++Term = Char | Range | Chclass | Eqclass ++Range = Char '-' Char | Char '-' '-' ++Char = Coll | coll_single ++Meta = ']' | '-' ++Coll = '[.' coll_single '.]' | '[.' coll_multi '.]' | '[.' Meta '.]' ++Eqclass = '[=' coll_single '=]' | '[=' coll_multi '=]' ++Chclass = '[:' class ':]' ++ ++coll_single is a single char collating element but it can be ++ '-' only at the beginning or end of a List and ++ ']' only at the beginning of a List and ++ '^' anywhere except after the openning '[' ++*/ + +- while (min <= max) +- { +- if (tre_islower(min)) +- { +- cmin = ccurr = tre_toupper(min++); +- while (tre_islower(min) && tre_toupper(min) == ccurr + 1 +- && min <= max) +- ccurr = tre_toupper(min++); +- status = tre_new_item(ctx->mem, cmin, ccurr, +- &i, &max_i, items); +- } +- else if (tre_isupper(min)) +- { +- cmin = ccurr = tre_tolower(min++); +- while (tre_isupper(min) && tre_tolower(min) == ccurr + 1 +- && min <= max) +- ccurr = tre_tolower(min++); +- status = tre_new_item(ctx->mem, cmin, ccurr, +- &i, &max_i, items); +- } +- else min++; +- if (status != REG_OK) +- break; ++static reg_errcode_t parse_bracket_terms(tre_parse_ctx_t *ctx, const char *s, struct literals *ls, struct neg *neg) ++{ ++ const char *start = s; ++ tre_ctype_t class; ++ int min, max; ++ wchar_t wc; ++ int len; ++ ++ for (;;) { ++ class = 0; ++ len = mbtowc(&wc, s, -1); ++ if (len <= 0) ++ return *s ? REG_BADPAT : REG_EBRACK; ++ if (*s == ']' && s != start) { ++ ctx->s = s+1; ++ return REG_OK; ++ } ++ if (*s == '-' && s != start && s[1] != ']' && ++ /* extension: [a-z--@] is accepted as [a-z]|[--@] */ ++ (s[1] != '-' || s[2] == ']')) ++ return REG_ERANGE; ++ if (*s == '[' && (s[1] == '.' || s[1] == '=')) ++ /* collating symbols and equivalence classes are not supported */ ++ return REG_ECOLLATE; ++ if (*s == '[' && s[1] == ':') { ++ char tmp[CHARCLASS_NAME_MAX+1]; ++ s += 2; ++ for (len=0; len < CHARCLASS_NAME_MAX && s[len]; len++) { ++ if (s[len] == ':') { ++ memcpy(tmp, s, len); ++ tmp[len] = 0; ++ class = tre_ctype(tmp); ++ break; ++ } ++ } ++ if (!class || s[len+1] != ']') ++ return REG_ECTYPE; ++ min = 0; ++ max = TRE_CHAR_MAX; ++ s += len+2; ++ } else { ++ min = max = wc; ++ s += len; ++ if (*s == '-' && s[1] != ']') { ++ s++; ++ len = mbtowc(&wc, s, -1); ++ max = wc; ++ /* XXX - Should use collation order instead of ++ encoding values in character ranges. */ ++ if (len <= 0 || min > max) ++ return REG_ERANGE; ++ s += len; ++ } ++ } ++ ++ if (class && neg->negate) { ++ if (neg->len >= MAX_NEG_CLASSES) ++ return REG_ESPACE; ++ neg->a[neg->len++] = class; ++ } else { ++ tre_literal_t *lit = tre_new_lit(ls); ++ if (!lit) ++ return REG_ESPACE; ++ lit->code_min = min; ++ lit->code_max = max; ++ lit->class = class; ++ lit->position = -1; ++ ++ /* Add opposite-case codepoints if REG_ICASE is present. ++ It seems that POSIX requires that bracket negation ++ should happen before case-folding, but most practical ++ implementations do it the other way around. Changing ++ the order would need efficient representation of ++ case-fold ranges and bracket range sets even with ++ simple patterns so this is ok for now. */ ++ if (ctx->cflags & REG_ICASE && !class) ++ if (add_icase_literals(ls, min, max)) ++ return REG_ESPACE; + } +- if (status != REG_OK) +- break; +- } + } +- } +- *num_items = i; +- *items_size = max_i; +- ctx->re = re; +- return status; + } + +-static reg_errcode_t +-tre_parse_bracket(tre_parse_ctx_t *ctx, tre_ast_node_t **result) ++static reg_errcode_t parse_bracket(tre_parse_ctx_t *ctx, const char *s) + { +- tre_ast_node_t *node = NULL; +- int negate = 0; +- reg_errcode_t status = REG_OK; +- tre_ast_node_t **items, *u, *n; +- int i = 0, j, max_i = 32, curr_max, curr_min; +- tre_ctype_t neg_classes[MAX_NEG_CLASSES]; +- int num_neg_classes = 0; +- +- /* Start off with an array of `max_i' elements. */ +- items = xmalloc(sizeof(*items) * max_i); +- if (items == NULL) +- return REG_ESPACE; +- +- if (*ctx->re == CHAR_CARET) +- { +- negate = 1; +- ctx->re++; +- } +- +- status = tre_parse_bracket_items(ctx, negate, neg_classes, &num_neg_classes, +- &items, &i, &max_i); +- +- if (status != REG_OK) +- goto parse_bracket_done; +- +- /* Sort the array if we need to negate it. */ +- if (negate) +- qsort(items, (unsigned)i, sizeof(*items), tre_compare_items); +- +- curr_max = curr_min = 0; +- /* Build a union of the items in the array, negated if necessary. */ +- for (j = 0; j < i && status == REG_OK; j++) +- { +- int min, max; +- tre_literal_t *l = items[j]->obj; +- min = l->code_min; +- max = l->code_max; +- +- if (negate) +- { +- if (min < curr_max) +- { +- /* Overlap. */ +- curr_max = MAX(max + 1, curr_max); +- l = NULL; +- } +- else +- { +- /* No overlap. */ +- curr_max = min - 1; +- if (curr_max >= curr_min) +- { +- l->code_min = curr_min; +- l->code_max = curr_max; ++ int i, max, min, negmax, negmin; ++ tre_ast_node_t *node = 0, *n; ++ tre_ctype_t *nc = 0; ++ tre_literal_t *lit; ++ struct literals ls; ++ struct neg neg; ++ reg_errcode_t err; ++ ++ ls.mem = ctx->mem; ++ ls.len = 0; ++ ls.cap = 32; ++ ls.a = xmalloc(ls.cap * sizeof *ls.a); ++ if (!ls.a) ++ return REG_ESPACE; ++ neg.len = 0; ++ neg.negate = *s == '^'; ++ if (neg.negate) ++ s++; ++ ++ err = parse_bracket_terms(ctx, s, &ls, &neg); ++ if (err != REG_OK) ++ goto parse_bracket_done; ++ ++ if (neg.negate) { ++ /* Sort the array if we need to negate it. */ ++ qsort(ls.a, ls.len, sizeof *ls.a, tre_compare_lit); ++ /* extra lit for the last negated range */ ++ lit = tre_new_lit(&ls); ++ if (!lit) { ++ err = REG_ESPACE; ++ goto parse_bracket_done; + } +- else +- { +- l = NULL; ++ lit->code_min = TRE_CHAR_MAX+1; ++ lit->code_max = TRE_CHAR_MAX+1; ++ lit->position = -1; ++ /* negated classes */ ++ if (neg.len) { ++ nc = tre_mem_alloc(ctx->mem, (neg.len+1)*sizeof *neg.a); ++ if (!nc) { ++ err = REG_ESPACE; ++ goto parse_bracket_done; ++ } ++ memcpy(nc, neg.a, neg.len*sizeof *neg.a); ++ nc[neg.len] = 0; + } +- curr_min = curr_max = max + 1; +- } + } + +- if (l != NULL) +- { +- int k; +- l->position = ctx->position; +- if (num_neg_classes > 0) +- { +- l->neg_classes = tre_mem_alloc(ctx->mem, +- (sizeof(*l->neg_classes) +- * (num_neg_classes + 1))); +- if (l->neg_classes == NULL) +- { +- status = REG_ESPACE; +- break; ++ /* Build a union of the items in the array, negated if necessary. */ ++ negmax = negmin = 0; ++ for (i = 0; i < ls.len; i++) { ++ lit = ls.a[i]; ++ min = lit->code_min; ++ max = lit->code_max; ++ if (neg.negate) { ++ if (min <= negmin) { ++ /* Overlap. */ ++ negmin = MAX(max + 1, negmin); ++ continue; ++ } ++ negmax = min - 1; ++ lit->code_min = negmin; ++ lit->code_max = negmax; ++ negmin = max + 1; + } +- for (k = 0; k < num_neg_classes; k++) +- l->neg_classes[k] = neg_classes[k]; +- l->neg_classes[k] = (tre_ctype_t)0; +- } +- else +- l->neg_classes = NULL; +- if (node == NULL) +- node = items[j]; +- else +- { +- u = tre_ast_new_union(ctx->mem, node, items[j]); +- if (u == NULL) +- status = REG_ESPACE; +- node = u; +- } +- } +- } +- +- if (status != REG_OK) +- goto parse_bracket_done; +- +- if (negate) +- { +- int k; +- n = tre_ast_new_literal(ctx->mem, curr_min, TRE_CHAR_MAX, ctx->position); +- if (n == NULL) +- status = REG_ESPACE; +- else +- { +- tre_literal_t *l = n->obj; +- if (num_neg_classes > 0) +- { +- l->neg_classes = tre_mem_alloc(ctx->mem, +- (sizeof(*l->neg_classes) +- * (num_neg_classes + 1))); +- if (l->neg_classes == NULL) +- { +- status = REG_ESPACE; +- goto parse_bracket_done; ++ lit->position = ctx->position; ++ lit->neg_classes = nc; ++ n = tre_ast_new_node(ctx->mem, LITERAL, lit); ++ node = tre_ast_new_union(ctx->mem, node, n); ++ if (!node) { ++ err = REG_ESPACE; ++ break; + } +- for (k = 0; k < num_neg_classes; k++) +- l->neg_classes[k] = neg_classes[k]; +- l->neg_classes[k] = (tre_ctype_t)0; +- } +- else +- l->neg_classes = NULL; +- if (node == NULL) +- node = n; +- else +- { +- u = tre_ast_new_union(ctx->mem, node, n); +- if (u == NULL) +- status = REG_ESPACE; +- node = u; +- } + } +- } +- +- if (status != REG_OK) +- goto parse_bracket_done; + +-#ifdef TRE_DEBUG +- tre_ast_print(node); +-#endif /* TRE_DEBUG */ +- +- parse_bracket_done: +- xfree(items); +- ctx->position++; +- *result = node; +- return status; ++parse_bracket_done: ++ xfree(ls.a); ++ ctx->position++; ++ ctx->n = node; ++ return err; + } + +- +-/* Parses a positive decimal integer. Returns -1 if the string does not +- contain a valid number. */ +-static int +-tre_parse_int(const char **regex) ++static const char *parse_dup_count(const char *s, int *n) + { +- int num = -1; +- const char *r = *regex; +- while (*r-'0'<10U) +- { +- if (num < 0) +- num = 0; +- num = num * 10 + *r - '0'; +- r++; +- } +- *regex = r; +- return num; ++ *n = -1; ++ if (!isdigit(*s)) ++ return s; ++ *n = 0; ++ for (;;) { ++ *n = 10 * *n + (*s - '0'); ++ s++; ++ if (!isdigit(*s) || *n > RE_DUP_MAX) ++ break; ++ } ++ return s; + } + +- +-static reg_errcode_t +-tre_parse_bound(tre_parse_ctx_t *ctx, tre_ast_node_t **result) ++static reg_errcode_t parse_dup(tre_parse_ctx_t *ctx, const char *s) + { +- int min, max; +- const char *r = ctx->re; +- int minimal = 0; +- +- /* Parse number (minimum repetition count). */ +- min = -1; +- if (*r >= '0' && *r <= '9') { +- min = tre_parse_int(&r); +- } +- +- /* Parse comma and second number (maximum repetition count). */ +- max = min; +- if (*r == CHAR_COMMA) +- { +- r++; +- max = tre_parse_int(&r); +- } +- +- /* Check that the repeat counts are sane. */ +- if ((max >= 0 && min > max) || max > RE_DUP_MAX) +- return REG_BADBR; +- +- /* Missing }. */ +- if (!*r) +- return REG_EBRACE; +- +- /* Empty contents of {}. */ +- if (r == ctx->re) +- return REG_BADBR; +- +- /* Parse the ending '}' or '\}'.*/ +- if (ctx->cflags & REG_EXTENDED) +- { +- if (*r != CHAR_RBRACE) +- return REG_BADBR; +- r++; +- } +- else +- { +- if (*r != CHAR_BACKSLASH || *(r + 1) != CHAR_RBRACE) +- return REG_BADBR; +- r += 2; +- } +- +- /* Create the AST node(s). */ +- if (min == 0 && max == 0) +- { +- *result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); +- if (*result == NULL) +- return REG_ESPACE; +- } +- else +- { +- if (min < 0 && max < 0) +- /* Only approximate parameters set, no repetitions. */ +- min = max = 1; +- +- *result = tre_ast_new_iter(ctx->mem, *result, min, max, minimal); +- if (!*result) +- return REG_ESPACE; +- } +- +- ctx->re = r; +- return REG_OK; ++ int min, max; ++ ++ s = parse_dup_count(s, &min); ++ if (*s == ',') ++ s = parse_dup_count(s+1, &max); ++ else ++ max = min; ++ ++ if ( ++ (max < min && max >= 0) || ++ max > RE_DUP_MAX || ++ min > RE_DUP_MAX || ++ min < 0 || ++ (!(ctx->cflags & REG_EXTENDED) && *s++ != '\\') || ++ *s++ != '}' ++ ) ++ return REG_BADBR; ++ ++ if (min == 0 && max == 0) ++ ctx->n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); ++ else ++ ctx->n = tre_ast_new_iter(ctx->mem, ctx->n, min, max, 0); ++ if (!ctx->n) ++ return REG_ESPACE; ++ ctx->s = s; ++ return REG_OK; + } + +-typedef enum { +- PARSE_RE = 0, +- PARSE_ATOM, +- PARSE_MARK_FOR_SUBMATCH, +- PARSE_BRANCH, +- PARSE_PIECE, +- PARSE_CATENATION, +- PARSE_POST_CATENATION, +- PARSE_UNION, +- PARSE_POST_UNION, +- PARSE_POSTFIX, +- PARSE_RESTORE_CFLAGS +-} tre_parse_re_stack_symbol_t; +- +- +-static reg_errcode_t +-tre_parse(tre_parse_ctx_t *ctx) ++static int hexval(unsigned c) + { +- tre_ast_node_t *result = NULL; +- tre_parse_re_stack_symbol_t symbol; +- reg_errcode_t status = REG_OK; +- tre_stack_t *stack = ctx->stack; +- int bottom = tre_stack_num_objects(stack); +- int depth = 0; +- wchar_t wc; +- int clen; +- +- if (!ctx->nofirstsub) +- { +- STACK_PUSH(stack, int, ctx->submatch_id); +- STACK_PUSH(stack, int, PARSE_MARK_FOR_SUBMATCH); +- ctx->submatch_id++; +- } +- STACK_PUSH(stack, int, PARSE_RE); +- ctx->re_start = ctx->re; +- +- +- /* The following is basically just a recursive descent parser. I use +- an explicit stack instead of recursive functions mostly because of +- two reasons: compatibility with systems which have an overflowable +- call stack, and efficiency (both in lines of code and speed). */ +- while (tre_stack_num_objects(stack) > bottom && status == REG_OK) +- { +- if (status != REG_OK) +- break; +- symbol = tre_stack_pop_int(stack); +- switch (symbol) +- { +- case PARSE_RE: +- /* Parse a full regexp. A regexp is one or more branches, +- separated by the union operator `|'. */ +- if (ctx->cflags & REG_EXTENDED) +- STACK_PUSHX(stack, int, PARSE_UNION); +- STACK_PUSHX(stack, int, PARSE_BRANCH); +- break; +- +- case PARSE_BRANCH: +- /* Parse a branch. A branch is one or more pieces, concatenated. +- A piece is an atom possibly followed by a postfix operator. */ +- STACK_PUSHX(stack, int, PARSE_CATENATION); +- STACK_PUSHX(stack, int, PARSE_PIECE); +- break; +- +- case PARSE_PIECE: +- /* Parse a piece. A piece is an atom possibly followed by one +- or more postfix operators. */ +- STACK_PUSHX(stack, int, PARSE_POSTFIX); +- STACK_PUSHX(stack, int, PARSE_ATOM); +- break; +- +- case PARSE_CATENATION: +- /* If the expression has not ended, parse another piece. */ +- { +- tre_char_t c; +- if (!*ctx->re) +- break; +- c = *ctx->re; +- if (ctx->cflags & REG_EXTENDED && c == CHAR_PIPE) +- break; +- if ((ctx->cflags & REG_EXTENDED +- && c == CHAR_RPAREN && depth > 0) +- || (!(ctx->cflags & REG_EXTENDED) +- && (c == CHAR_BACKSLASH +- && *(ctx->re + 1) == CHAR_RPAREN))) +- { +- if (!(ctx->cflags & REG_EXTENDED) && depth == 0) +- status = REG_EPAREN; +- depth--; +- if (!(ctx->cflags & REG_EXTENDED)) +- ctx->re += 2; +- break; +- } +- +- { +- /* Default case, left associative concatenation. */ +- STACK_PUSHX(stack, int, PARSE_CATENATION); +- STACK_PUSHX(stack, voidptr, result); +- STACK_PUSHX(stack, int, PARSE_POST_CATENATION); +- STACK_PUSHX(stack, int, PARSE_PIECE); +- } +- break; +- } +- +- case PARSE_POST_CATENATION: +- { +- tre_ast_node_t *tree = tre_stack_pop_voidptr(stack); +- tre_ast_node_t *tmp_node; +- tmp_node = tre_ast_new_catenation(ctx->mem, tree, result); +- if (!tmp_node) +- return REG_ESPACE; +- result = tmp_node; +- break; +- } +- +- case PARSE_UNION: +- switch (*ctx->re) +- { +- case CHAR_PIPE: +- STACK_PUSHX(stack, int, PARSE_UNION); +- STACK_PUSHX(stack, voidptr, result); +- STACK_PUSHX(stack, int, PARSE_POST_UNION); +- STACK_PUSHX(stack, int, PARSE_BRANCH); +- ctx->re++; +- break; +- +- case CHAR_RPAREN: +- ctx->re++; +- break; +- +- default: +- break; +- } +- break; +- +- case PARSE_POST_UNION: +- { +- tre_ast_node_t *tmp_node; +- tre_ast_node_t *tree = tre_stack_pop_voidptr(stack); +- tmp_node = tre_ast_new_union(ctx->mem, tree, result); +- if (!tmp_node) +- return REG_ESPACE; +- result = tmp_node; +- break; +- } +- +- case PARSE_POSTFIX: +- /* Parse postfix operators. */ +- switch (*ctx->re) +- { +- case CHAR_PLUS: +- case CHAR_QUESTIONMARK: +- if (!(ctx->cflags & REG_EXTENDED)) +- break; +- /*FALLTHROUGH*/ +- case CHAR_STAR: +- { +- tre_ast_node_t *tmp_node; +- int minimal = 0; +- int rep_min = 0; +- int rep_max = -1; +- +- if (*ctx->re == CHAR_PLUS) +- rep_min = 1; +- if (*ctx->re == CHAR_QUESTIONMARK) +- rep_max = 1; +- +- ctx->re++; +- tmp_node = tre_ast_new_iter(ctx->mem, result, rep_min, rep_max, +- minimal); +- if (tmp_node == NULL) +- return REG_ESPACE; +- result = tmp_node; +- STACK_PUSHX(stack, int, PARSE_POSTFIX); +- } +- break; +- +- case CHAR_BACKSLASH: +- /* "\{" is special without REG_EXTENDED */ +- if (!(ctx->cflags & REG_EXTENDED) +- && *(ctx->re + 1) == CHAR_LBRACE) +- { +- ctx->re++; +- goto parse_brace; +- } +- else +- break; +- +- case CHAR_LBRACE: +- /* "{" is literal without REG_EXTENDED */ +- if (!(ctx->cflags & REG_EXTENDED)) +- break; +- +- parse_brace: +- ctx->re++; ++ if (c-'0'<10) return c-'0'; ++ c |= 32; ++ if (c-'a'<6) return c-'a'+10; ++ return -1; ++} + +- status = tre_parse_bound(ctx, &result); +- if (status != REG_OK) +- return status; +- STACK_PUSHX(stack, int, PARSE_POSTFIX); +- break; +- } +- break; ++static reg_errcode_t marksub(tre_parse_ctx_t *ctx, tre_ast_node_t *node, int subid) ++{ ++ if (node->submatch_id >= 0) { ++ tre_ast_node_t *n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); ++ if (!n) ++ return REG_ESPACE; ++ n = tre_ast_new_catenation(ctx->mem, n, node); ++ if (!n) ++ return REG_ESPACE; ++ n->num_submatches = node->num_submatches; ++ node = n; ++ } ++ node->submatch_id = subid; ++ node->num_submatches++; ++ ctx->n = node; ++ return REG_OK; ++} + +- case PARSE_ATOM: +- /* Parse an atom. An atom is a regular expression enclosed in `()', +- an empty set of `()', a bracket expression, `.', `^', `$', +- a `\' followed by a character, or a single character. */ ++/* ++BRE grammar: ++Regex = Branch | '^' | '$' | '^$' | '^' Branch | Branch '$' | '^' Branch '$' ++Branch = Atom | Branch Atom ++Atom = char | quoted_char | '.' | Bracket | Atom Dup | '\(' Branch '\)' | back_ref ++Dup = '*' | '\{' Count '\}' | '\{' Count ',\}' | '\{' Count ',' Count '\}' + +- switch (*ctx->re) +- { +- case CHAR_LPAREN: /* parenthesized subexpression */ ++(leading ^ and trailing $ in a sub expr may be an anchor or literal as well) + +- if (ctx->cflags & REG_EXTENDED) +- { +- lparen: +- depth++; +- { +- ctx->re++; +- /* First parse a whole RE, then mark the resulting tree +- for submatching. */ +- STACK_PUSHX(stack, int, ctx->submatch_id); +- STACK_PUSHX(stack, int, PARSE_MARK_FOR_SUBMATCH); +- STACK_PUSHX(stack, int, PARSE_RE); +- ctx->submatch_id++; +- } +- } +- else +- goto parse_literal; +- break; ++ERE grammar: ++Regex = Branch | Regex '|' Branch ++Branch = Atom | Branch Atom ++Atom = char | quoted_char | '.' | Bracket | Atom Dup | '(' Regex ')' | '^' | '$' ++Dup = '*' | '+' | '?' | '{' Count '}' | '{' Count ',}' | '{' Count ',' Count '}' + +- case CHAR_LBRACKET: /* bracket expression */ +- ctx->re++; +- status = tre_parse_bracket(ctx, &result); +- if (status != REG_OK) +- return status; +- break; ++(a*+?, ^*, $+, \X, {, (|a) are unspecified) ++*/ + +- case CHAR_BACKSLASH: +- /* If this is "\(" or "\)" chew off the backslash and +- try again. */ +- if (!(ctx->cflags & REG_EXTENDED) && *(ctx->re + 1) == CHAR_LPAREN) +- { +- ctx->re++; +- goto lparen; +- } +- if (!(ctx->cflags & REG_EXTENDED) && *(ctx->re + 1) == CHAR_RPAREN) +- { +- goto empty_atom; ++static reg_errcode_t parse_atom(tre_parse_ctx_t *ctx, const char *s) ++{ ++ int len, ere = ctx->cflags & REG_EXTENDED; ++ const char *p; ++ tre_ast_node_t *node; ++ wchar_t wc; ++ switch (*s) { ++ case '[': ++ return parse_bracket(ctx, s+1); ++ case '\\': ++ p = tre_expand_macro(s+1); ++ if (p) { ++ /* assume \X expansion is a single atom */ ++ reg_errcode_t err = parse_atom(ctx, p); ++ ctx->s = s+2; ++ return err; + } +- +- /* If a macro is used, parse the expanded macro recursively. */ +- { +- const char *buf = tre_expand_macro(ctx->re + 1); +- if (buf) +- { +- tre_parse_ctx_t subctx; +- memcpy(&subctx, ctx, sizeof(subctx)); +- subctx.re = buf; +- subctx.nofirstsub = 1; +- status = tre_parse(&subctx); +- if (status != REG_OK) +- return status; +- ctx->re += 2; +- ctx->position = subctx.position; +- result = subctx.result; +- break; +- } +- } +- +- if (!ctx->re[1]) +- /* Trailing backslash. */ +- return REG_EESCAPE; +- +- ctx->re++; +- switch (*ctx->re) +- { ++ /* extensions: \b, \B, \<, \>, \xHH \x{HHHH} */ ++ switch (*++s) { ++ case 0: ++ return REG_EESCAPE; + case 'b': +- result = tre_ast_new_literal(ctx->mem, ASSERTION, +- ASSERT_AT_WB, -1); +- ctx->re++; +- break; ++ node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_WB, -1); ++ break; + case 'B': +- result = tre_ast_new_literal(ctx->mem, ASSERTION, +- ASSERT_AT_WB_NEG, -1); +- ctx->re++; +- break; ++ node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_WB_NEG, -1); ++ break; + case '<': +- result = tre_ast_new_literal(ctx->mem, ASSERTION, +- ASSERT_AT_BOW, -1); +- ctx->re++; +- break; ++ node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_BOW, -1); ++ break; + case '>': +- result = tre_ast_new_literal(ctx->mem, ASSERTION, +- ASSERT_AT_EOW, -1); +- ctx->re++; +- break; ++ node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_EOW, -1); ++ break; + case 'x': +- ctx->re++; +- if (ctx->re[0] != CHAR_LBRACE) +- { +- /* 8 bit hex char. */ +- char tmp[3] = {0, 0, 0}; +- long val; +- +- if (tre_isxdigit(ctx->re[0])) +- { +- tmp[0] = (char)ctx->re[0]; +- ctx->re++; ++ s++; ++ int i, v = 0, c; ++ len = 2; ++ if (*s == '{') { ++ len = 8; ++ s++; + } +- if (tre_isxdigit(ctx->re[0])) +- { +- tmp[1] = (char)ctx->re[0]; +- ctx->re++; ++ for (i=0; i<len && v<0x110000; i++) { ++ c = hexval(s[i]); ++ if (c < 0) break; ++ v = 16*v + c; + } +- val = strtol(tmp, NULL, 16); +- result = tre_ast_new_literal(ctx->mem, (int)val, +- (int)val, ctx->position); +- ctx->position++; +- break; +- } +- else if (*ctx->re) +- { +- /* Wide char. */ +- char tmp[32]; +- long val; +- int i = 0; +- ctx->re++; +- while (*ctx->re && i < sizeof tmp) +- { +- if (ctx->re[0] == CHAR_RBRACE) +- break; +- if (tre_isxdigit(ctx->re[0])) +- { +- tmp[i] = (char)ctx->re[0]; +- i++; +- ctx->re++; +- continue; +- } +- return REG_EBRACE; ++ s += i; ++ if (len == 8) { ++ if (*s != '}') ++ return REG_EBRACE; ++ s++; + } +- ctx->re++; +- tmp[i] = 0; +- val = strtol(tmp, NULL, 16); +- result = tre_ast_new_literal(ctx->mem, (int)val, (int)val, +- ctx->position); +- ctx->position++; +- break; +- } +- /*FALLTHROUGH*/ +- ++ node = tre_ast_new_literal(ctx->mem, v, v, ctx->position); ++ ctx->position++; ++ s--; ++ break; + default: +- if (tre_isdigit(*ctx->re)) +- { +- /* Back reference. */ +- int val = *ctx->re - '0'; +- result = tre_ast_new_literal(ctx->mem, BACKREF, val, +- ctx->position); +- if (result == NULL) +- return REG_ESPACE; +- ctx->position++; +- ctx->max_backref = MAX(val, ctx->max_backref); +- ctx->re++; +- } +- else +- { +- /* Escaped character. */ +- result = tre_ast_new_literal(ctx->mem, *ctx->re, *ctx->re, +- ctx->position); +- ctx->position++; +- ctx->re++; +- } +- break; +- } +- if (result == NULL) +- return REG_ESPACE; +- break; +- +- case CHAR_PERIOD: /* the any-symbol */ +- if (ctx->cflags & REG_NEWLINE) +- { +- tre_ast_node_t *tmp1; +- tre_ast_node_t *tmp2; +- tmp1 = tre_ast_new_literal(ctx->mem, 0, '\n' - 1, +- ctx->position); +- if (!tmp1) +- return REG_ESPACE; +- tmp2 = tre_ast_new_literal(ctx->mem, '\n' + 1, TRE_CHAR_MAX, +- ctx->position + 1); +- if (!tmp2) +- return REG_ESPACE; +- result = tre_ast_new_union(ctx->mem, tmp1, tmp2); +- if (!result) +- return REG_ESPACE; +- ctx->position += 2; +- } +- else +- { +- result = tre_ast_new_literal(ctx->mem, 0, TRE_CHAR_MAX, +- ctx->position); +- if (!result) +- return REG_ESPACE; +- ctx->position++; ++ if (isdigit(*s)) { ++ /* back reference */ ++ int val = *s - '0'; ++ node = tre_ast_new_literal(ctx->mem, BACKREF, val, ctx->position); ++ ctx->max_backref = MAX(val, ctx->max_backref); ++ } else { ++ /* extension: accept unknown escaped char ++ as a literal */ ++ node = tre_ast_new_literal(ctx->mem, *s, *s, ctx->position); ++ } ++ ctx->position++; + } +- ctx->re++; +- break; +- +- case CHAR_CARET: /* beginning of line assertion */ +- /* '^' has a special meaning everywhere in EREs, and at +- beginning of BRE. */ +- if (ctx->cflags & REG_EXTENDED +- || ctx->re == ctx->re_start) +- { +- if (!(ctx->cflags & REG_EXTENDED)) +- STACK_PUSHX(stack, int, PARSE_CATENATION); +- result = tre_ast_new_literal(ctx->mem, ASSERTION, +- ASSERT_AT_BOL, -1); +- if (result == NULL) +- return REG_ESPACE; +- ctx->re++; ++ s++; ++ break; ++ case '.': ++ if (ctx->cflags & REG_NEWLINE) { ++ tre_ast_node_t *tmp1, *tmp2; ++ tmp1 = tre_ast_new_literal(ctx->mem, 0, '\n'-1, ctx->position++); ++ tmp2 = tre_ast_new_literal(ctx->mem, '\n'+1, TRE_CHAR_MAX, ctx->position++); ++ if (tmp1 && tmp2) ++ node = tre_ast_new_union(ctx->mem, tmp1, tmp2); ++ else ++ node = 0; ++ } else { ++ node = tre_ast_new_literal(ctx->mem, 0, TRE_CHAR_MAX, ctx->position++); + } +- else +- goto parse_literal; +- break; +- +- case CHAR_DOLLAR: /* end of line assertion. */ +- /* '$' is special everywhere in EREs, and in the end of the +- string in BREs. */ +- if (ctx->cflags & REG_EXTENDED +- || !*(ctx->re + 1)) +- { +- result = tre_ast_new_literal(ctx->mem, ASSERTION, +- ASSERT_AT_EOL, -1); +- if (result == NULL) +- return REG_ESPACE; +- ctx->re++; ++ s++; ++ break; ++ case '^': ++ /* '^' has a special meaning everywhere in EREs, and at beginning of BRE. */ ++ if (!ere && s != ctx->re) ++ goto parse_literal; ++ node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_BOL, -1); ++ s++; ++ break; ++ case '$': ++ /* '$' is special everywhere in EREs, and in the end of the string in BREs. */ ++ if (!ere && s[1]) ++ goto parse_literal; ++ node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_EOL, -1); ++ s++; ++ break; ++ case '*': ++ case '|': ++ case '{': ++ case '+': ++ case '?': ++ if (!ere) ++ goto parse_literal; ++ case 0: ++ node = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); ++ break; ++ default: ++parse_literal: ++ len = mbtowc(&wc, s, -1); ++ if (len < 0) ++ return REG_BADPAT; ++ if (ctx->cflags & REG_ICASE && (tre_isupper(wc) || tre_islower(wc))) { ++ tre_ast_node_t *tmp1, *tmp2; ++ /* multiple opposite case characters are not supported */ ++ tmp1 = tre_ast_new_literal(ctx->mem, tre_toupper(wc), tre_toupper(wc), ctx->position); ++ tmp2 = tre_ast_new_literal(ctx->mem, tre_tolower(wc), tre_tolower(wc), ctx->position); ++ if (tmp1 && tmp2) ++ node = tre_ast_new_union(ctx->mem, tmp1, tmp2); ++ else ++ node = 0; ++ } else { ++ node = tre_ast_new_literal(ctx->mem, wc, wc, ctx->position); + } +- else +- goto parse_literal; +- break; +- +- case CHAR_RPAREN: +- if (!depth) +- goto parse_literal; +- case CHAR_STAR: +- case CHAR_PIPE: +- case CHAR_LBRACE: +- case CHAR_PLUS: +- case CHAR_QUESTIONMARK: +- if (!(ctx->cflags & REG_EXTENDED)) +- goto parse_literal; +- +- case 0: +- empty_atom: +- result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); +- if (!result) ++ ctx->position++; ++ s += len; ++ break; ++ } ++ if (!node) + return REG_ESPACE; +- break; ++ ctx->n = node; ++ ctx->s = s; ++ return REG_OK; ++} + +- default: +- parse_literal: ++#define PUSHPTR(err, s, v) do { \ ++ if ((err = tre_stack_push_voidptr(s, v)) != REG_OK) \ ++ return err; \ ++} while(0) + +- clen = mbtowc(&wc, ctx->re, -1); +- if (clen<0) clen=1, wc=WEOF; ++#define PUSHINT(err, s, v) do { \ ++ if ((err = tre_stack_push_int(s, v)) != REG_OK) \ ++ return err; \ ++} while(0) + +- /* Note that we can't use an tre_isalpha() test here, since there +- may be characters which are alphabetic but neither upper or +- lower case. */ +- if (ctx->cflags & REG_ICASE +- && (tre_isupper(wc) || tre_islower(wc))) +- { +- tre_ast_node_t *tmp1; +- tre_ast_node_t *tmp2; +- +- /* XXX - Can there be more than one opposite-case +- counterpoints for some character in some locale? Or +- more than two characters which all should be regarded +- the same character if case is ignored? If yes, there +- does not seem to be a portable way to detect it. I guess +- that at least for multi-character collating elements there +- could be several opposite-case counterpoints, but they +- cannot be supported portably anyway. */ +- tmp1 = tre_ast_new_literal(ctx->mem, tre_toupper(wc), +- tre_toupper(wc), +- ctx->position); +- if (!tmp1) +- return REG_ESPACE; +- tmp2 = tre_ast_new_literal(ctx->mem, tre_tolower(wc), +- tre_tolower(wc), +- ctx->position); +- if (!tmp2) +- return REG_ESPACE; +- result = tre_ast_new_union(ctx->mem, tmp1, tmp2); +- if (!result) +- return REG_ESPACE; ++static reg_errcode_t tre_parse(tre_parse_ctx_t *ctx) ++{ ++ tre_ast_node_t *nbranch=0, *nunion=0; ++ int ere = ctx->cflags & REG_EXTENDED; ++ const char *s = ctx->re; ++ int subid = 0; ++ int depth = 0; ++ reg_errcode_t err; ++ tre_stack_t *stack = ctx->stack; ++ ++ PUSHINT(err, stack, subid++); ++ for (;;) { ++ if ((!ere && *s == '\\' && s[1] == '(') || ++ (ere && *s == '(')) { ++ PUSHPTR(err, stack, nunion); ++ PUSHPTR(err, stack, nbranch); ++ PUSHINT(err, stack, subid++); ++ s++; ++ if (!ere) ++ s++; ++ depth++; ++ nbranch = nunion = 0; ++ continue; + } +- else +- { +- result = tre_ast_new_literal(ctx->mem, wc, wc, +- ctx->position); +- if (!result) +- return REG_ESPACE; ++ if ((!ere && *s == '\\' && s[1] == ')') || ++ (ere && *s == ')' && depth)) { ++ ctx->n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); ++ if (!ctx->n) ++ return REG_ESPACE; ++ } else { ++ err = parse_atom(ctx, s); ++ if (err != REG_OK) ++ return err; ++ s = ctx->s; + } +- ctx->position++; +- ctx->re += clen; +- break; +- } +- break; +- +- case PARSE_MARK_FOR_SUBMATCH: +- { +- int submatch_id = tre_stack_pop_int(stack); + +- if (result->submatch_id >= 0) +- { +- tre_ast_node_t *n, *tmp_node; +- n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); +- if (n == NULL) +- return REG_ESPACE; +- tmp_node = tre_ast_new_catenation(ctx->mem, n, result); +- if (tmp_node == NULL) +- return REG_ESPACE; +- tmp_node->num_submatches = result->num_submatches; +- result = tmp_node; +- } +- result->submatch_id = submatch_id; +- result->num_submatches++; +- break; +- } +- +- case PARSE_RESTORE_CFLAGS: +- ctx->cflags = tre_stack_pop_int(stack); +- break; ++ parse_iter: ++ /* extension: repetitions are accepted after an empty node ++ eg. (+), ^*, a$?, a|{2} */ ++ switch (*s) { ++ case '+': ++ case '?': ++ if (!ere) ++ break; ++ /* fallthrough */ ++ case '*':; ++ int min=0, max=-1; ++ if (*s == '+') ++ min = 1; ++ if (*s == '?') ++ max = 1; ++ s++; ++ ctx->n = tre_ast_new_iter(ctx->mem, ctx->n, min, max, 0); ++ if (!ctx->n) ++ return REG_ESPACE; ++ /* extension: multiple consecutive *+?{,} is unspecified, ++ but (a+)+ has to be supported so accepting a++ makes ++ sense, note however that the RE_DUP_MAX limit can be ++ circumvented: (a{255}){255} uses a lot of memory.. */ ++ goto parse_iter; ++ case '\\': ++ if (ere || s[1] != '{') ++ break; ++ s++; ++ goto parse_brace; ++ case '{': ++ if (!ere) ++ break; ++ parse_brace: ++ err = parse_dup(ctx, s+1); ++ if (err != REG_OK) ++ return err; ++ s = ctx->s; ++ goto parse_iter; ++ } + +- default: +- assert(0); +- break; ++ nbranch = tre_ast_new_catenation(ctx->mem, nbranch, ctx->n); ++ if ((ere && *s == '|') || ++ (ere && *s == ')' && depth) || ++ (!ere && *s == '\\' && s[1] == ')') || ++ !*s) { ++ /* extension: empty branch is unspecified (), (|a), (a|) ++ here they are not rejected but match on empty string */ ++ int c = *s; ++ nunion = tre_ast_new_union(ctx->mem, nunion, nbranch); ++ nbranch = 0; ++ if (c != '|') { ++ if (c == '\\') { ++ if (!depth) return REG_EPAREN; ++ s+=2; ++ } else if (c == ')') ++ s++; ++ depth--; ++ err = marksub(ctx, nunion, tre_stack_pop_int(stack)); ++ if (err != REG_OK) ++ return err; ++ if (!c && depth<0) { ++ ctx->submatch_id = subid; ++ return REG_OK; ++ } ++ if (!c || depth<0) ++ return REG_EPAREN; ++ nbranch = tre_stack_pop_voidptr(stack); ++ nunion = tre_stack_pop_voidptr(stack); ++ goto parse_iter; ++ } ++ s++; ++ } + } +- } +- +- /* Check for missing closing parentheses. */ +- if (depth > 0) +- return REG_EPAREN; +- +- if (status == REG_OK) +- ctx->result = result; +- +- return status; + } + + +- + /*********************************************************************** + from tre-compile.c + ***********************************************************************/ +@@ -3122,12 +2680,7 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags) + if (errcode != REG_OK) + ERROR_EXIT(errcode); + preg->re_nsub = parse_ctx.submatch_id - 1; +- tree = parse_ctx.result; +- +- /* Back references and approximate matching cannot currently be used +- in the same regexp. */ +- if (parse_ctx.max_backref >= 0 && parse_ctx.have_approx) +- ERROR_EXIT(REG_BADPAT); ++ tree = parse_ctx.n; + + #ifdef TRE_DEBUG + tre_ast_print(tree); +@@ -3142,7 +2695,7 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags) + if (tnfa == NULL) + ERROR_EXIT(REG_ESPACE); + tnfa->have_backrefs = parse_ctx.max_backref >= 0; +- tnfa->have_approx = parse_ctx.have_approx; ++ tnfa->have_approx = 0; + tnfa->num_submatches = parse_ctx.submatch_id; + + /* Set up tags for submatch addressing. If REG_NOSUB is set and the +diff --git a/src/regex/regexec.c b/src/regex/regexec.c +index 2e35b83..16c5d0a 100644 +--- a/src/regex/regexec.c ++++ b/src/regex/regexec.c +@@ -52,7 +52,7 @@ tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags, + #define GET_NEXT_WCHAR() do { \ + prev_c = next_c; pos += pos_add_next; \ + if ((pos_add_next = mbtowc(&next_c, str_byte, MB_LEN_MAX)) <= 0) { \ +- if (pos_add_next < 0) return REG_NOMATCH; \ ++ if (pos_add_next < 0) { ret = REG_NOMATCH; goto error_exit; } \ + else pos_add_next++; \ + } \ + str_byte += pos_add_next; \ +@@ -181,6 +181,7 @@ tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string, + int reg_notbol = eflags & REG_NOTBOL; + int reg_noteol = eflags & REG_NOTEOL; + int reg_newline = tnfa->cflags & REG_NEWLINE; ++ reg_errcode_t ret; + + char *buf; + tre_tnfa_transition_t *trans_i; +@@ -439,11 +440,11 @@ tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string, + reach_next_i->state = NULL; + } + +- if (buf) +- xfree(buf); +- + *match_end_ofs = match_eo; +- return match_eo >= 0 ? REG_OK : REG_NOMATCH; ++ ret = match_eo >= 0 ? REG_OK : REG_NOMATCH; ++error_exit: ++ xfree(buf); ++ return ret; + } + + +diff --git a/src/stdio/ftrylockfile.c b/src/stdio/ftrylockfile.c +index 6f9a4b8..eb13c83 100644 +--- a/src/stdio/ftrylockfile.c ++++ b/src/stdio/ftrylockfile.c +@@ -34,6 +34,7 @@ int ftrylockfile(FILE *f) + f->lockcount = 1; + f->prev_locked = 0; + f->next_locked = self->stdio_locks; ++ if (f->next_locked) f->next_locked->prev_locked = f; + self->stdio_locks = f; + return 0; + } +diff --git a/src/thread/__timedwait.c b/src/thread/__timedwait.c +index d6f1233..c9ec70c 100644 +--- a/src/thread/__timedwait.c ++++ b/src/thread/__timedwait.c +@@ -4,6 +4,9 @@ + #include "futex.h" + #include "syscall.h" + ++int __pthread_setcancelstate(int, int *); ++int __clock_gettime(clockid_t, struct timespec *); ++ + int __timedwait(volatile int *addr, int val, + clockid_t clk, const struct timespec *at, + void (*cleanup)(void *), void *arg, int priv) +@@ -15,7 +18,7 @@ int __timedwait(volatile int *addr, int val, + + if (at) { + if (at->tv_nsec >= 1000000000UL) return EINVAL; +- if (clock_gettime(clk, &to)) return EINVAL; ++ if (__clock_gettime(clk, &to)) return EINVAL; + to.tv_sec = at->tv_sec - to.tv_sec; + if ((to.tv_nsec = at->tv_nsec - to.tv_nsec) < 0) { + to.tv_sec--; +@@ -25,7 +28,7 @@ int __timedwait(volatile int *addr, int val, + top = &to; + } + +- if (!cleanup) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); ++ if (!cleanup) __pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + pthread_cleanup_push(cleanup, arg); + + r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT|priv, val, top); +@@ -33,7 +36,7 @@ int __timedwait(volatile int *addr, int val, + if (r != EINTR && r != ETIMEDOUT) r = 0; + + pthread_cleanup_pop(0); +- if (!cleanup) pthread_setcancelstate(cs, 0); ++ if (!cleanup) __pthread_setcancelstate(cs, 0); + + return r; + } +diff --git a/src/thread/call_once.c b/src/thread/call_once.c +new file mode 100644 +index 0000000..a7bc935 +--- /dev/null ++++ b/src/thread/call_once.c +@@ -0,0 +1,8 @@ ++#include <threads.h> ++ ++int __pthread_once(once_flag *, void (*)(void)); ++ ++void call_once(once_flag *flag, void (*func)(void)) ++{ ++ __pthread_once(flag, func); ++} +diff --git a/src/thread/cnd_broadcast.c b/src/thread/cnd_broadcast.c +new file mode 100644 +index 0000000..85d4d3e +--- /dev/null ++++ b/src/thread/cnd_broadcast.c +@@ -0,0 +1,10 @@ ++#include <threads.h> ++ ++int __private_cond_signal(cnd_t *, int); ++ ++int cnd_broadcast(cnd_t *c) ++{ ++ /* This internal function never fails, and always returns zero, ++ * which matches the value thrd_success is defined with. */ ++ return __private_cond_signal(c, -1); ++} +diff --git a/src/thread/cnd_destroy.c b/src/thread/cnd_destroy.c +new file mode 100644 +index 0000000..453c90b +--- /dev/null ++++ b/src/thread/cnd_destroy.c +@@ -0,0 +1,6 @@ ++#include <threads.h> ++ ++void cnd_destroy(cnd_t *c) ++{ ++ /* For private cv this is a no-op */ ++} +diff --git a/src/thread/cnd_init.c b/src/thread/cnd_init.c +new file mode 100644 +index 0000000..18c5085 +--- /dev/null ++++ b/src/thread/cnd_init.c +@@ -0,0 +1,7 @@ ++#include <threads.h> ++ ++int cnd_init(cnd_t *c) ++{ ++ *c = (cnd_t){ 0 }; ++ return thrd_success; ++} +diff --git a/src/thread/cnd_signal.c b/src/thread/cnd_signal.c +new file mode 100644 +index 0000000..1211260 +--- /dev/null ++++ b/src/thread/cnd_signal.c +@@ -0,0 +1,10 @@ ++#include <threads.h> ++ ++int __private_cond_signal(cnd_t *, int); ++ ++int cnd_signal(cnd_t *c) ++{ ++ /* This internal function never fails, and always returns zero, ++ * which matches the value thrd_success is defined with. */ ++ return __private_cond_signal(c, 1); ++} +diff --git a/src/thread/cnd_timedwait.c b/src/thread/cnd_timedwait.c +new file mode 100644 +index 0000000..5997679 +--- /dev/null ++++ b/src/thread/cnd_timedwait.c +@@ -0,0 +1,15 @@ ++#include <threads.h> ++#include <errno.h> ++ ++int __pthread_cond_timedwait(cnd_t *restrict, mtx_t *restrict, const struct timespec *restrict); ++ ++int cnd_timedwait(cnd_t *restrict c, mtx_t *restrict m, const struct timespec *restrict ts) ++{ ++ int ret = __pthread_cond_timedwait(c, m, ts); ++ switch (ret) { ++ /* May also return EINVAL or EPERM. */ ++ default: return thrd_error; ++ case 0: return thrd_success; ++ case ETIMEDOUT: return thrd_timedout; ++ } ++} +diff --git a/src/thread/cnd_wait.c b/src/thread/cnd_wait.c +new file mode 100644 +index 0000000..602796f +--- /dev/null ++++ b/src/thread/cnd_wait.c +@@ -0,0 +1,9 @@ ++#include <threads.h> ++ ++int cnd_wait(cnd_t *c, mtx_t *m) ++{ ++ /* Calling cnd_timedwait with a null pointer is an extension. ++ * It is convenient here to avoid duplication of the logic ++ * for return values. */ ++ return cnd_timedwait(c, m, 0); ++} +diff --git a/src/thread/mtx_destroy.c b/src/thread/mtx_destroy.c +new file mode 100644 +index 0000000..40a0899 +--- /dev/null ++++ b/src/thread/mtx_destroy.c +@@ -0,0 +1,5 @@ ++#include <threads.h> ++ ++void mtx_destroy(mtx_t *mtx) ++{ ++} +diff --git a/src/thread/mtx_init.c b/src/thread/mtx_init.c +new file mode 100644 +index 0000000..4826f76 +--- /dev/null ++++ b/src/thread/mtx_init.c +@@ -0,0 +1,10 @@ ++#include "pthread_impl.h" ++#include <threads.h> ++ ++int mtx_init(mtx_t *m, int type) ++{ ++ *m = (mtx_t){ ++ ._m_type = ((type&mtx_recursive) ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL), ++ }; ++ return thrd_success; ++} +diff --git a/src/thread/mtx_lock.c b/src/thread/mtx_lock.c +new file mode 100644 +index 0000000..5c2415c +--- /dev/null ++++ b/src/thread/mtx_lock.c +@@ -0,0 +1,12 @@ ++#include "pthread_impl.h" ++#include <threads.h> ++ ++int mtx_lock(mtx_t *m) ++{ ++ if (m->_m_type == PTHREAD_MUTEX_NORMAL && !a_cas(&m->_m_lock, 0, EBUSY)) ++ return thrd_success; ++ /* Calling mtx_timedlock with a null pointer is an extension. ++ * It is convenient, here to avoid duplication of the logic ++ * for return values. */ ++ return mtx_timedlock(m, 0); ++} +diff --git a/src/thread/mtx_timedlock.c b/src/thread/mtx_timedlock.c +new file mode 100644 +index 0000000..bcc152c +--- /dev/null ++++ b/src/thread/mtx_timedlock.c +@@ -0,0 +1,14 @@ ++#include <threads.h> ++#include <errno.h> ++ ++int __pthread_mutex_timedlock(mtx_t *restrict, const struct timespec *restrict); ++ ++int mtx_timedlock(mtx_t *restrict m, const struct timespec *restrict ts) ++{ ++ int ret = __pthread_mutex_timedlock(m, ts); ++ switch (ret) { ++ default: return thrd_error; ++ case 0: return thrd_success; ++ case ETIMEDOUT: return thrd_timedout; ++ } ++} +diff --git a/src/thread/mtx_trylock.c b/src/thread/mtx_trylock.c +new file mode 100644 +index 0000000..61e7694 +--- /dev/null ++++ b/src/thread/mtx_trylock.c +@@ -0,0 +1,17 @@ ++#include "pthread_impl.h" ++#include <threads.h> ++ ++int __pthread_mutex_trylock(mtx_t *); ++ ++int mtx_trylock(mtx_t *m) ++{ ++ if (m->_m_type == PTHREAD_MUTEX_NORMAL) ++ return (a_cas(&m->_m_lock, 0, EBUSY) & EBUSY) ? thrd_busy : thrd_success; ++ ++ int ret = __pthread_mutex_trylock(m); ++ switch (ret) { ++ default: return thrd_error; ++ case 0: return thrd_success; ++ case EBUSY: return thrd_busy; ++ } ++} +diff --git a/src/thread/mtx_unlock.c b/src/thread/mtx_unlock.c +new file mode 100644 +index 0000000..5033ace +--- /dev/null ++++ b/src/thread/mtx_unlock.c +@@ -0,0 +1,11 @@ ++#include <threads.h> ++ ++int __pthread_mutex_unlock(mtx_t *); ++ ++int mtx_unlock(mtx_t *mtx) ++{ ++ /* The only cases where pthread_mutex_unlock can return an ++ * error are undefined behavior for C11 mtx_unlock, so we can ++ * assume it does not return an error and simply tail call. */ ++ return __pthread_mutex_unlock(mtx); ++} +diff --git a/src/thread/pthread_cond_timedwait.c b/src/thread/pthread_cond_timedwait.c +index 2d192b0..0a80d30 100644 +--- a/src/thread/pthread_cond_timedwait.c ++++ b/src/thread/pthread_cond_timedwait.c +@@ -1,5 +1,9 @@ + #include "pthread_impl.h" + ++void __pthread_testcancel(void); ++int __pthread_mutex_lock(pthread_mutex_t *); ++int __pthread_mutex_unlock(pthread_mutex_t *); ++ + /* + * struct waiter + * +@@ -119,7 +123,7 @@ static void unwait(void *arg) + } + } + +-int pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restrict m, const struct timespec *restrict ts) ++int __pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restrict m, const struct timespec *restrict ts) + { + struct waiter node = { .cond = c, .mutex = m }; + int e, seq, *fut, clock = c->_c_clock; +@@ -130,7 +134,7 @@ int pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restrict + if (ts && ts->tv_nsec >= 1000000000UL) + return EINVAL; + +- pthread_testcancel(); ++ __pthread_testcancel(); + + if (c->_c_shared) { + node.shared = 1; +@@ -151,7 +155,7 @@ int pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restrict + unlock(&c->_c_lock); + } + +- pthread_mutex_unlock(m); ++ __pthread_mutex_unlock(m); + + do e = __timedwait(fut, seq, clock, ts, unwait, &node, !node.shared); + while (*fut==seq && (!e || e==EINTR)); +@@ -197,3 +201,5 @@ int __private_cond_signal(pthread_cond_t *c, int n) + + return 0; + } ++ ++weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait); +diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c +index e441bda..1a47ed1 100644 +--- a/src/thread/pthread_create.c ++++ b/src/thread/pthread_create.c +@@ -5,6 +5,10 @@ + #include <sys/mman.h> + #include <string.h> + ++void *__mmap(void *, size_t, int, int, int, off_t); ++int __munmap(void *, size_t); ++int __mprotect(void *, size_t, int); ++ + static void dummy_0() + { + } +@@ -14,7 +18,7 @@ weak_alias(dummy_0, __pthread_tsd_run_dtors); + weak_alias(dummy_0, __do_private_robust_list); + weak_alias(dummy_0, __do_orphaned_stdio_locks); + +-_Noreturn void pthread_exit(void *result) ++_Noreturn void __pthread_exit(void *result) + { + pthread_t self = __pthread_self(); + sigset_t set; +@@ -115,7 +119,15 @@ static int start(void *p) + if (self->unblock_cancel) + __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, + SIGPT_SET, 0, _NSIG/8); +- pthread_exit(self->start(self->start_arg)); ++ __pthread_exit(self->start(self->start_arg)); ++ return 0; ++} ++ ++static int start_c11(void *p) ++{ ++ pthread_t self = p; ++ int (*start)(void*) = (int(*)(void*)) self->start; ++ __pthread_exit((void *)(uintptr_t)start(self->start_arg)); + return 0; + } + +@@ -139,9 +151,9 @@ static void init_file_lock(FILE *f) + + void *__copy_tls(unsigned char *); + +-int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg) ++int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg) + { +- int ret; ++ int ret, c11 = (attrp == __ATTRP_C11_THREAD); + size_t size, guard; + struct pthread *self, *new; + unsigned char *map = 0, *stack = 0, *tsd = 0, *stack_limit; +@@ -163,7 +175,7 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp + self->tsd = (void **)__pthread_tsd_main; + libc.threaded = 1; + } +- if (attrp) attr = *attrp; ++ if (attrp && !c11) attr = *attrp; + + __acquire_ptc(); + +@@ -191,14 +203,14 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp + + if (!tsd) { + if (guard) { +- map = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0); ++ map = __mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0); + if (map == MAP_FAILED) goto fail; +- if (mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE)) { +- munmap(map, size); ++ if (__mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE)) { ++ __munmap(map, size); + goto fail; + } + } else { +- map = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); ++ map = __mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); + if (map == MAP_FAILED) goto fail; + } + tsd = map + size - __pthread_tsd_size; +@@ -230,7 +242,7 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp + new->canary = self->canary; + + a_inc(&libc.threads_minus_1); +- ret = __clone(start, stack, flags, new, &new->tid, TP_ADJ(new), &new->tid); ++ ret = __clone((c11 ? start_c11 : start), stack, flags, new, &new->tid, TP_ADJ(new), &new->tid); + + __release_ptc(); + +@@ -240,7 +252,7 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp + + if (ret < 0) { + a_dec(&libc.threads_minus_1); +- if (map) munmap(map, size); ++ if (map) __munmap(map, size); + return EAGAIN; + } + +@@ -258,3 +270,6 @@ fail: + __release_ptc(); + return EAGAIN; + } ++ ++weak_alias(__pthread_exit, pthread_exit); ++weak_alias(__pthread_create, pthread_create); +diff --git a/src/thread/pthread_detach.c b/src/thread/pthread_detach.c +index 651c38e..ed77f74 100644 +--- a/src/thread/pthread_detach.c ++++ b/src/thread/pthread_detach.c +@@ -1,11 +1,17 @@ + #include "pthread_impl.h" ++#include <threads.h> + +-int pthread_detach(pthread_t t) ++int __pthread_join(pthread_t, void **); ++ ++static int __pthread_detach(pthread_t t) + { + /* Cannot detach a thread that's already exiting */ + if (a_swap(t->exitlock, 1)) +- return pthread_join(t, 0); ++ return __pthread_join(t, 0); + t->detached = 2; + __unlock(t->exitlock); + return 0; + } ++ ++weak_alias(__pthread_detach, pthread_detach); ++weak_alias(__pthread_detach, thrd_detach); +diff --git a/src/thread/pthread_equal.c b/src/thread/pthread_equal.c +index 3e3df4f..7c31482 100644 +--- a/src/thread/pthread_equal.c ++++ b/src/thread/pthread_equal.c +@@ -1,6 +1,11 @@ + #include <pthread.h> ++#include <threads.h> ++#include "libc.h" + +-int (pthread_equal)(pthread_t a, pthread_t b) ++static int __pthread_equal(pthread_t a, pthread_t b) + { + return a==b; + } ++ ++weak_alias(__pthread_equal, pthread_equal); ++weak_alias(__pthread_equal, thrd_equal); +diff --git a/src/thread/pthread_getspecific.c b/src/thread/pthread_getspecific.c +index b2a282c..d9342a5 100644 +--- a/src/thread/pthread_getspecific.c ++++ b/src/thread/pthread_getspecific.c +@@ -1,7 +1,11 @@ + #include "pthread_impl.h" ++#include <threads.h> + +-void *pthread_getspecific(pthread_key_t k) ++static void *__pthread_getspecific(pthread_key_t k) + { + struct pthread *self = __pthread_self(); + return self->tsd[k]; + } ++ ++weak_alias(__pthread_getspecific, pthread_getspecific); ++weak_alias(__pthread_getspecific, tss_get); +diff --git a/src/thread/pthread_join.c b/src/thread/pthread_join.c +index abd2d66..19e6b54 100644 +--- a/src/thread/pthread_join.c ++++ b/src/thread/pthread_join.c +@@ -1,16 +1,20 @@ + #include "pthread_impl.h" + #include <sys/mman.h> + ++int __munmap(void *, size_t); ++ + static void dummy(void *p) + { + } + +-int pthread_join(pthread_t t, void **res) ++int __pthread_join(pthread_t t, void **res) + { + int tmp; + pthread_testcancel(); + while ((tmp = t->tid)) __timedwait(&t->tid, tmp, 0, 0, dummy, 0, 0); + if (res) *res = t->result; +- if (t->map_base) munmap(t->map_base, t->map_size); ++ if (t->map_base) __munmap(t->map_base, t->map_size); + return 0; + } ++ ++weak_alias(__pthread_join, pthread_join); +diff --git a/src/thread/pthread_key_create.c b/src/thread/pthread_key_create.c +index a9187f7..bfcd597 100644 +--- a/src/thread/pthread_key_create.c ++++ b/src/thread/pthread_key_create.c +@@ -9,7 +9,7 @@ static void nodtor(void *dummy) + { + } + +-int pthread_key_create(pthread_key_t *k, void (*dtor)(void *)) ++int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *)) + { + unsigned i = (uintptr_t)&k / 16 % PTHREAD_KEYS_MAX; + unsigned j = i; +@@ -31,7 +31,7 @@ int pthread_key_create(pthread_key_t *k, void (*dtor)(void *)) + return EAGAIN; + } + +-int pthread_key_delete(pthread_key_t k) ++int __pthread_key_delete(pthread_key_t k) + { + keys[k] = 0; + return 0; +@@ -53,3 +53,6 @@ void __pthread_tsd_run_dtors() + } + } + } ++ ++weak_alias(__pthread_key_delete, pthread_key_delete); ++weak_alias(__pthread_key_create, pthread_key_create); +diff --git a/src/thread/pthread_mutex_lock.c b/src/thread/pthread_mutex_lock.c +index 2a9a3aa..d0c93ca 100644 +--- a/src/thread/pthread_mutex_lock.c ++++ b/src/thread/pthread_mutex_lock.c +@@ -1,10 +1,14 @@ + #include "pthread_impl.h" + +-int pthread_mutex_lock(pthread_mutex_t *m) ++int __pthread_mutex_timedlock(pthread_mutex_t *restrict, const struct timespec *restrict); ++ ++int __pthread_mutex_lock(pthread_mutex_t *m) + { + if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL + && !a_cas(&m->_m_lock, 0, EBUSY)) + return 0; + +- return pthread_mutex_timedlock(m, 0); ++ return __pthread_mutex_timedlock(m, 0); + } ++ ++weak_alias(__pthread_mutex_lock, pthread_mutex_lock); +diff --git a/src/thread/pthread_mutex_timedlock.c b/src/thread/pthread_mutex_timedlock.c +index ae883f9..16241ee 100644 +--- a/src/thread/pthread_mutex_timedlock.c ++++ b/src/thread/pthread_mutex_timedlock.c +@@ -1,6 +1,6 @@ + #include "pthread_impl.h" + +-int pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *restrict at) ++int __pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *restrict at) + { + if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL + && !a_cas(&m->_m_lock, 0, EBUSY)) +@@ -30,3 +30,5 @@ int pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec * + } + return r; + } ++ ++weak_alias(__pthread_mutex_timedlock, pthread_mutex_timedlock); +diff --git a/src/thread/pthread_mutex_trylock.c b/src/thread/pthread_mutex_trylock.c +index e851517..cb93565 100644 +--- a/src/thread/pthread_mutex_trylock.c ++++ b/src/thread/pthread_mutex_trylock.c +@@ -50,9 +50,11 @@ int __pthread_mutex_trylock_owner(pthread_mutex_t *m) + return 0; + } + +-int pthread_mutex_trylock(pthread_mutex_t *m) ++int __pthread_mutex_trylock(pthread_mutex_t *m) + { + if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL) + return a_cas(&m->_m_lock, 0, EBUSY) & EBUSY; + return __pthread_mutex_trylock_owner(m); + } ++ ++weak_alias(__pthread_mutex_trylock, pthread_mutex_trylock); +diff --git a/src/thread/pthread_mutex_unlock.c b/src/thread/pthread_mutex_unlock.c +index 46761d9..a7f39c7 100644 +--- a/src/thread/pthread_mutex_unlock.c ++++ b/src/thread/pthread_mutex_unlock.c +@@ -3,7 +3,7 @@ + void __vm_lock_impl(int); + void __vm_unlock_impl(void); + +-int pthread_mutex_unlock(pthread_mutex_t *m) ++int __pthread_mutex_unlock(pthread_mutex_t *m) + { + pthread_t self; + int waiters = m->_m_waiters; +@@ -36,3 +36,5 @@ int pthread_mutex_unlock(pthread_mutex_t *m) + __wake(&m->_m_lock, 1, priv); + return 0; + } ++ ++weak_alias(__pthread_mutex_unlock, pthread_mutex_unlock); +diff --git a/src/thread/pthread_once.c b/src/thread/pthread_once.c +index 2eb0f93..05ebe69 100644 +--- a/src/thread/pthread_once.c ++++ b/src/thread/pthread_once.c +@@ -6,7 +6,7 @@ static void undo(void *control) + __wake(control, 1, 1); + } + +-int pthread_once(pthread_once_t *control, void (*init)(void)) ++int __pthread_once(pthread_once_t *control, void (*init)(void)) + { + static int waiters; + +@@ -34,3 +34,5 @@ int pthread_once(pthread_once_t *control, void (*init)(void)) + return 0; + } + } ++ ++weak_alias(__pthread_once, pthread_once); +diff --git a/src/thread/pthread_self.c b/src/thread/pthread_self.c +index 5f9e651..241a620 100644 +--- a/src/thread/pthread_self.c ++++ b/src/thread/pthread_self.c +@@ -1,6 +1,11 @@ + #include "pthread_impl.h" ++#include <threads.h> ++#include "libc.h" + +-pthread_t pthread_self() ++static pthread_t __pthread_self_internal() + { + return __pthread_self(); + } ++ ++weak_alias(__pthread_self_internal, pthread_self); ++weak_alias(__pthread_self_internal, thrd_current); +diff --git a/src/thread/pthread_setcancelstate.c b/src/thread/pthread_setcancelstate.c +index 060bcdc..2268217 100644 +--- a/src/thread/pthread_setcancelstate.c ++++ b/src/thread/pthread_setcancelstate.c +@@ -1,6 +1,6 @@ + #include "pthread_impl.h" + +-int pthread_setcancelstate(int new, int *old) ++int __pthread_setcancelstate(int new, int *old) + { + if (new > 1U) return EINVAL; + if (!libc.has_thread_pointer) return ENOSYS; +@@ -9,3 +9,5 @@ int pthread_setcancelstate(int new, int *old) + self->canceldisable = new; + return 0; + } ++ ++weak_alias(__pthread_setcancelstate, pthread_setcancelstate); +diff --git a/src/thread/pthread_testcancel.c b/src/thread/pthread_testcancel.c +index ba5f7c6..ee48e6d 100644 +--- a/src/thread/pthread_testcancel.c ++++ b/src/thread/pthread_testcancel.c +@@ -7,7 +7,9 @@ static void dummy() + + weak_alias(dummy, __testcancel); + +-void pthread_testcancel() ++void __pthread_testcancel() + { + __testcancel(); + } ++ ++weak_alias(__pthread_testcancel, pthread_testcancel); +diff --git a/src/thread/thrd_create.c b/src/thread/thrd_create.c +new file mode 100644 +index 0000000..e033669 +--- /dev/null ++++ b/src/thread/thrd_create.c +@@ -0,0 +1,14 @@ ++#include "pthread_impl.h" ++#include <threads.h> ++ ++int __pthread_create(pthread_t *restrict, const pthread_attr_t *restrict, void *(*)(void *), void *restrict); ++ ++int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) ++{ ++ int ret = __pthread_create(thr, __ATTRP_C11_THREAD, (void *(*)(void *))func, arg); ++ switch (ret) { ++ case 0: return thrd_success; ++ case EAGAIN: return thrd_nomem; ++ default: return thrd_error; ++ } ++} +diff --git a/src/thread/thrd_exit.c b/src/thread/thrd_exit.c +new file mode 100644 +index 0000000..b66bd99 +--- /dev/null ++++ b/src/thread/thrd_exit.c +@@ -0,0 +1,9 @@ ++#include "pthread_impl.h" ++#include <threads.h> ++ ++_Noreturn void __pthread_exit(void *); ++ ++_Noreturn void thrd_exit(int result) ++{ ++ __pthread_exit((void*)(intptr_t)result); ++} +diff --git a/src/thread/thrd_join.c b/src/thread/thrd_join.c +new file mode 100644 +index 0000000..ac66789 +--- /dev/null ++++ b/src/thread/thrd_join.c +@@ -0,0 +1,12 @@ ++#include <stdint.h> ++#include <threads.h> ++ ++int __pthread_join(thrd_t, void**); ++ ++int thrd_join(thrd_t t, int *res) ++{ ++ void *pthread_res; ++ __pthread_join(t, &pthread_res); ++ if (res) *res = (int)(intptr_t)pthread_res; ++ return thrd_success; ++} +diff --git a/src/thread/thrd_sleep.c b/src/thread/thrd_sleep.c +new file mode 100644 +index 0000000..e8dfe40 +--- /dev/null ++++ b/src/thread/thrd_sleep.c +@@ -0,0 +1,13 @@ ++#include <threads.h> ++#include <errno.h> ++#include "syscall.h" ++ ++int thrd_sleep(const struct timespec *req, struct timespec *rem) ++{ ++ int ret = __syscall(SYS_nanosleep, req, rem); ++ switch (ret) { ++ case 0: return 0; ++ case -EINTR: return -1; /* value specified by C11 */ ++ default: return -2; ++ } ++} +diff --git a/src/thread/thrd_yield.c b/src/thread/thrd_yield.c +new file mode 100644 +index 0000000..f7ad132 +--- /dev/null ++++ b/src/thread/thrd_yield.c +@@ -0,0 +1,7 @@ ++#include <threads.h> ++#include "syscall.h" ++ ++void thrd_yield() ++{ ++ __syscall(SYS_sched_yield); ++} +diff --git a/src/thread/tss_create.c b/src/thread/tss_create.c +new file mode 100644 +index 0000000..251d22b +--- /dev/null ++++ b/src/thread/tss_create.c +@@ -0,0 +1,11 @@ ++#include <threads.h> ++ ++int __pthread_key_create(tss_t *, void (*)(void *)); ++ ++int tss_create(tss_t *tss, tss_dtor_t dtor) ++{ ++ /* Different error returns are possible. C glues them together into ++ * just failure notification. Can't be optimized to a tail call, ++ * unless thrd_error equals EAGAIN. */ ++ return __pthread_key_create(tss, dtor) ? thrd_error : thrd_success; ++} +diff --git a/src/thread/tss_delete.c b/src/thread/tss_delete.c +new file mode 100644 +index 0000000..35db103 +--- /dev/null ++++ b/src/thread/tss_delete.c +@@ -0,0 +1,8 @@ ++#include <threads.h> ++ ++int __pthread_key_delete(tss_t k); ++ ++void tss_delete(tss_t key) ++{ ++ __pthread_key_delete(key); ++} +diff --git a/src/thread/tss_set.c b/src/thread/tss_set.c +new file mode 100644 +index 0000000..70c4fb7 +--- /dev/null ++++ b/src/thread/tss_set.c +@@ -0,0 +1,13 @@ ++#include "pthread_impl.h" ++#include <threads.h> ++ ++int tss_set(tss_t k, void *x) ++{ ++ struct pthread *self = __pthread_self(); ++ /* Avoid unnecessary COW */ ++ if (self->tsd[k] != x) { ++ self->tsd[k] = x; ++ self->tsd_used = 1; ++ } ++ return thrd_success; ++} +diff --git a/src/time/timespec_get.c b/src/time/timespec_get.c +new file mode 100644 +index 0000000..03c5a77 +--- /dev/null ++++ b/src/time/timespec_get.c +@@ -0,0 +1,12 @@ ++#include <time.h> ++ ++int __clock_gettime(clockid_t, struct timespec *); ++ ++/* There is no other implemented value than TIME_UTC; all other values ++ * are considered erroneous. */ ++int timespec_get(struct timespec * ts, int base) ++{ ++ if (base != TIME_UTC) return 0; ++ int ret = __clock_gettime(CLOCK_REALTIME, ts); ++ return ret < 0 ? 0 : base; ++} diff --git a/main/musl/APKBUILD b/main/musl/APKBUILD index 6cf0c3143e..1998acee67 100644 --- a/main/musl/APKBUILD +++ b/main/musl/APKBUILD @@ -2,7 +2,7 @@ # Maintainer: Timo Teräs <timo.teras@iki.fi> pkgname=musl pkgver=1.1.4 -pkgrel=7 +pkgrel=8 pkgdesc="the musl c library (libc) implementation" url="http://www.musl-libc.org/" arch="all" @@ -17,10 +17,11 @@ source="http://www.musl-libc.org/releases/musl-$pkgver.tar.gz 0002-d86af2a0-to-4992ace9.patch 0003-4992ace9-to-6e2bb7ac.patch 0004-6e2bb7ac-to-4674809b.patch + 0005-4674809b-to-3e936ce8.patch + 1001-add-basic-dns-record-parsing-functions.patch 1002-check-lockcount-in-funlockfile.patch 1003-remove-ulimit-fiddling-from-setxid.patch - alignas.patch ldconfig getopt_long.c @@ -128,10 +129,10 @@ md5sums="f18f3bdbe088438cd64a5313c19a7312 musl-1.1.4.tar.gz 04eef5b44c0b56b79055340bee1febc2 0002-d86af2a0-to-4992ace9.patch 6710102c768f5a971b93100219de3fbb 0003-4992ace9-to-6e2bb7ac.patch 294d3d382098977ea0770731a4803322 0004-6e2bb7ac-to-4674809b.patch +5e7769c1f65acbdb9decf3012a70b411 0005-4674809b-to-3e936ce8.patch 2371eb1ce057fcb709a0e6a81f0d356c 1001-add-basic-dns-record-parsing-functions.patch 8a763b1853ee16d034abe038a0c44641 1002-check-lockcount-in-funlockfile.patch 71b2a4dcc39c436a6b89173943424043 1003-remove-ulimit-fiddling-from-setxid.patch -20014a2b6bbf5e1e7ad95de338a66562 alignas.patch 830d01f7821b978df770b06db3790921 ldconfig 61c6c1e84ed1df82abbe6d75e90cf21c getopt_long.c 0df687757221bbb0fc1aa67f1bd646f9 __stack_chk_fail_local.c @@ -143,10 +144,10 @@ sha256sums="658c65ad3c3a9b281a96c5281e75720c758d91fcaae35ab987f2fdfb4f88f5cd mu c7521464f3096befb5b44d303819e9169a43a6a5a3c93566ac1cdf523a6a389d 0002-d86af2a0-to-4992ace9.patch 7a716e03084724e3776300d8ed498e835b2cad4321b638a3eec5a9d8f28de8d9 0003-4992ace9-to-6e2bb7ac.patch e727b50aa65886563960c10449f60e229ffb94dd3476df1098e877ce599358c4 0004-6e2bb7ac-to-4674809b.patch +1672b904cf69c9c9b349e7b07f534663cd2083a878778db188f74104bfc051b5 0005-4674809b-to-3e936ce8.patch 75053a31f6b84a64846d92c0ec631c76d7f747a9c0dc92a6dc1aa1bddfe2ea76 1001-add-basic-dns-record-parsing-functions.patch eebc0afce600cbe2f41055404c7735f1a7be6e262df602dbcbfde7321633bdd9 1002-check-lockcount-in-funlockfile.patch fb542c2bd5081ff2f601c519edb3dac8f54ca5c888f44bc6cfb84e6565472025 1003-remove-ulimit-fiddling-from-setxid.patch -91a20ddcbbeb1d14e805afe45d5914dda5dea51a945f9f53afd589a60a3ab9ba alignas.patch b4a2c06db38742e8c42c3c9838b285a7d8cdac6c091ff3df5ff9a15f1e41b9c7 ldconfig d9b644ec20bc33e81a7c52b9fcf7973d835923a69faf50f03db45534b811bd96 getopt_long.c 299a7d75a09de3e2e11e7fb4acc3182e4a14e868093d2f30938fce9bfcff13da __stack_chk_fail_local.c @@ -158,10 +159,10 @@ sha512sums="a46fb1db23f518beaa959e9bebcb3bf0574e583c197792d30dcd52b3974e3c285594 0e892a0d0e2abf09cb52d27759769a4cdd39ebd87fb1af89f502da00a4c9453309291aeb69862d60d88a8d0a0c2517aabcc92b50214d67279b12113b3c5a0157 0002-d86af2a0-to-4992ace9.patch af92b766d2ca9fcf58b57c705b65ec0b60ecd9af1d38f1b9697a6b999baa56d8cb0ecf94bc02267022a13763e4a1a13a3f73bc03fdf73c0cd8f80126c2949a13 0003-4992ace9-to-6e2bb7ac.patch 8aa879e31c3eb18f9b00ea98d25872d94cad9120c05a80419965dcf7d3a4e0a69c370b35e2871cb11b639bbcf606842a48d3ad64ec916bc34b2eb21d3c4a3efa 0004-6e2bb7ac-to-4674809b.patch +7104eb3753135b5cd2a291552c6fbf36034d7169178ae45ef99d634a4055afa30a7e89ce7a01695b120c4a872ec51f1a837b34c4e83d69778b0248ca6c931d48 0005-4674809b-to-3e936ce8.patch 5b8ffa0a50419581adbf6ce2dae5797774022551c6331fa5aa2ff13635eb72b74eedd8a92cb478d45d73e1956af2f588669681ac414f3a255abd4d8ba8579448 1001-add-basic-dns-record-parsing-functions.patch beb515f46fa7c18eafe72cc612c5e8877dd1fd083e05c427af3a2a4d4281df06c6c1727c39d136d8e3f267be8832ea133362f5088a2b6a26b33c9e184acf1884 1002-check-lockcount-in-funlockfile.patch dae010b45419fcab64410568466f659cdc874e63113025e2cbc2fbab047b470fec23851ecbef08886505924482a069caf37c16b483b6922535fbd31832f1c4a3 1003-remove-ulimit-fiddling-from-setxid.patch -3cba68979fddff66d4989290c989c51b1f1b1f45d371ab23ee8622c6caf8a12409eecb3a15ad88c1b1f4d5c9c62380e9c0073b6c45f117e0312c4f50df4a7ad8 alignas.patch 8d3a2d5315fc56fee7da9abb8b89bb38c6046c33d154c10d168fb35bfde6b0cf9f13042a3bceee34daf091bc409d699223735dcf19f382eeee1f6be34154f26f ldconfig 140f3f20d30bd95ebce8c41b8cc7f616c6cbedf4ea06c729c21014e74f6043796825cc40ebc5180620ea38173afdba23f09ebf6d8b11fa05440b14d23764fca9 getopt_long.c 062bb49fa54839010acd4af113e20f7263dde1c8a2ca359b5fb2661ef9ed9d84a0f7c3bc10c25dcfa10bb3c5a4874588dff636ac43d5dbb3d748d75400756d0b __stack_chk_fail_local.c diff --git a/main/musl/alignas.patch b/main/musl/alignas.patch deleted file mode 100644 index 61dd221cb7..0000000000 --- a/main/musl/alignas.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/arch/i386/bits/alltypes.h.in b/arch/i386/bits/alltypes.h.in -index a7882ed..c4ba2c7 100644 ---- a/arch/i386/bits/alltypes.h.in -+++ b/arch/i386/bits/alltypes.h.in -@@ -27,7 +27,11 @@ TYPEDEF long double float_t; - TYPEDEF long double double_t; - #endif - -+#if __cplusplus >= 201103L -+TYPEDEF struct { alignas(8) long long __ll; long double __ld; } max_align_t; -+#else - TYPEDEF struct { _Alignas(8) long long __ll; long double __ld; } max_align_t; -+#endif - - TYPEDEF long time_t; - TYPEDEF long suseconds_t; - |