Update Musl Libc code

We now have implement all of Musl's localization code, the same way that
Musl implements localization. You may need setlocale(LC_ALL, "C.UTF-8"),
just in case anything stops working as expected.
This commit is contained in:
Justine Tunney 2024-07-30 09:14:57 -07:00
parent d0360bf4bd
commit bb815eafaf
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
116 changed files with 6525 additions and 5523 deletions

View file

@ -30,7 +30,8 @@ THIRD_PARTY_MUSL_A_DIRECTDEPS = \
LIBC_STR \
LIBC_SYSV \
LIBC_THREAD \
THIRD_PARTY_ZLIB
THIRD_PARTY_TZ \
THIRD_PARTY_ZLIB \
THIRD_PARTY_MUSL_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_MUSL_A_DIRECTDEPS),$($(x))))

72
third_party/musl/__mo_lookup.c vendored Normal file
View file

@ -0,0 +1,72 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/str/str.h"
#include "libc/str/locale.internal.h"
__static_yoink("musl_libc_notice");
#pragma GCC diagnostic ignored "-Wparentheses"
static inline uint32_t swapc(uint32_t x, int c)
{
return c ? x>>24 | x>>8&0xff00 | x<<8&0xff0000 | x<<24 : x;
}
const char *__mo_lookup(const void *p, size_t size, const char *s)
{
const uint32_t *mo = p;
int sw = *mo - 0x950412de;
uint32_t b = 0, n = swapc(mo[2], sw);
uint32_t o = swapc(mo[3], sw);
uint32_t t = swapc(mo[4], sw);
if (n>=size/4 || o>=size-4*n || t>=size-4*n || ((o|t)%4))
return 0;
o/=4;
t/=4;
for (;;) {
uint32_t ol = swapc(mo[o+2*(b+n/2)], sw);
uint32_t os = swapc(mo[o+2*(b+n/2)+1], sw);
if (os >= size || ol >= size-os || ((char *)p)[os+ol])
return 0;
int sign = strcmp(s, (char *)p + os);
if (!sign) {
uint32_t tl = swapc(mo[t+2*(b+n/2)], sw);
uint32_t ts = swapc(mo[t+2*(b+n/2)+1], sw);
if (ts >= size || tl >= size-ts || ((char *)p)[ts+tl])
return 0;
return (char *)p + ts;
}
else if (n == 1) return 0;
else if (sign < 0)
n /= 2;
else {
b += n/2;
n -= n/2;
}
}
return 0;
}

10
third_party/musl/__month_to_secs.c vendored Normal file
View file

@ -0,0 +1,10 @@
int __month_to_secs(int month, int is_leap)
{
static const int secs_through_month[] = {
0, 31*86400, 59*86400, 90*86400,
120*86400, 151*86400, 181*86400, 212*86400,
243*86400, 273*86400, 304*86400, 334*86400 };
int t = secs_through_month[month];
if (is_leap && month >= 2) t+=86400;
return t;
}

82
third_party/musl/__secs_to_tm.c vendored Normal file
View file

@ -0,0 +1,82 @@
#include "time_impl.h"
#include <limits.h>
/* 2000-03-01 (mod 400 year, immediately after feb29 */
#define LEAPOCH (946684800LL + 86400*(31+29))
#define DAYS_PER_400Y (365*400 + 97)
#define DAYS_PER_100Y (365*100 + 24)
#define DAYS_PER_4Y (365*4 + 1)
int __secs_to_tm(long long t, struct tm *tm)
{
long long days, secs, years;
int remdays, remsecs, remyears;
int qc_cycles, c_cycles, q_cycles;
int months;
int wday, yday, leap;
static const char days_in_month[] = {31,30,31,30,31,31,30,31,30,31,31,29};
/* Reject time_t values whose year would overflow int */
if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL)
return -1;
secs = t - LEAPOCH;
days = secs / 86400;
remsecs = secs % 86400;
if (remsecs < 0) {
remsecs += 86400;
days--;
}
wday = (3+days)%7;
if (wday < 0) wday += 7;
qc_cycles = days / DAYS_PER_400Y;
remdays = days % DAYS_PER_400Y;
if (remdays < 0) {
remdays += DAYS_PER_400Y;
qc_cycles--;
}
c_cycles = remdays / DAYS_PER_100Y;
if (c_cycles == 4) c_cycles--;
remdays -= c_cycles * DAYS_PER_100Y;
q_cycles = remdays / DAYS_PER_4Y;
if (q_cycles == 25) q_cycles--;
remdays -= q_cycles * DAYS_PER_4Y;
remyears = remdays / 365;
if (remyears == 4) remyears--;
remdays -= remyears * 365;
leap = !remyears && (q_cycles || !c_cycles);
yday = remdays + 31 + 28 + leap;
if (yday >= 365+leap) yday -= 365+leap;
years = remyears + 4*q_cycles + 100*c_cycles + 400LL*qc_cycles;
for (months=0; days_in_month[months] <= remdays; months++)
remdays -= days_in_month[months];
if (months >= 10) {
months -= 12;
years++;
}
if (years+100 > INT_MAX || years+100 < INT_MIN)
return -1;
tm->tm_year = years + 100;
tm->tm_mon = months + 2;
tm->tm_mday = remdays + 1;
tm->tm_wday = wday;
tm->tm_yday = yday;
tm->tm_hour = remsecs / 3600;
tm->tm_min = remsecs / 60 % 60;
tm->tm_sec = remsecs % 60;
return 0;
}

24
third_party/musl/__tm_to_secs.c vendored Normal file
View file

@ -0,0 +1,24 @@
#include "time_impl.h"
long long __tm_to_secs(const struct tm *tm)
{
int is_leap;
long long year = tm->tm_year;
int month = tm->tm_mon;
if (month >= 12 || month < 0) {
int adj = month / 12;
month %= 12;
if (month < 0) {
adj--;
month += 12;
}
year += adj;
}
long long t = __year_to_secs(year, &is_leap);
t += __month_to_secs(month, is_leap);
t += 86400LL * (tm->tm_mday-1);
t += 3600LL * tm->tm_hour;
t += 60LL * tm->tm_min;
t += tm->tm_sec;
return t;
}

47
third_party/musl/__year_to_secs.c vendored Normal file
View file

@ -0,0 +1,47 @@
long long __year_to_secs(long long year, int *is_leap)
{
if (year-2ULL <= 136) {
int y = year;
int leaps = (y-68)>>2;
if (!((y-68)&3)) {
leaps--;
if (is_leap) *is_leap = 1;
} else if (is_leap) *is_leap = 0;
return 31536000*(y-70) + 86400*leaps;
}
int cycles, centuries, leaps, rem, dummy;
if (!is_leap) is_leap = &dummy;
cycles = (year-100) / 400;
rem = (year-100) % 400;
if (rem < 0) {
cycles--;
rem += 400;
}
if (!rem) {
*is_leap = 1;
centuries = 0;
leaps = 0;
} else {
if (rem >= 200) {
if (rem >= 300) centuries = 3, rem -= 300;
else centuries = 2, rem -= 200;
} else {
if (rem >= 100) centuries = 1, rem -= 100;
else centuries = 0;
}
if (!rem) {
*is_leap = 0;
leaps = 0;
} else {
leaps = rem / 4U;
rem %= 4U;
*is_leap = !rem;
}
}
leaps += 97*cycles + 24*centuries - *is_leap;
return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400;
}

10
third_party/musl/asctime.c vendored Normal file
View file

@ -0,0 +1,10 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
#include "libc/time.h"
char *asctime(const struct tm *tm)
{
static char buf[26];
return asctime_r(tm, buf);
}

52
third_party/musl/asctime_r.c vendored Normal file
View file

@ -0,0 +1,52 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/stdio/stdio.h"
#include "libc/str/langinfo.h"
#include "libc/str/locale.internal.h"
__static_yoink("musl_libc_notice");
char *asctime_r(const struct tm *tm, char *buf)
{
if (snprintf(buf, 26, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
nl_langinfo_l(ABDAY_1+tm->tm_wday, C_LOCALE),
nl_langinfo_l(ABMON_1+tm->tm_mon, C_LOCALE),
tm->tm_mday, tm->tm_hour,
tm->tm_min, tm->tm_sec,
1900 + tm->tm_year) >= 26)
{
/* ISO C requires us to use the above format string,
* even if it will not fit in the buffer. Thus asctime_r
* is _supposed_ to crash if the fields in tm are too large.
* We follow this behavior and crash "gracefully" to warn
* application developers that they may not be so lucky
* on other implementations (e.g. stack smashing..).
*/
__builtin_trap();
}
return buf;
}

38
third_party/musl/btowc.c vendored Normal file
View file

@ -0,0 +1,38 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <wchar.h>
#include <stdlib.h>
#include "multibyte.h"
__static_yoink("musl_libc_notice");
wint_t btowc(int c)
{
int b = (unsigned char)c;
return b<128U ? b : (MB_CUR_MAX==1 && c!=EOF) ? CODEUNIT(c) : WEOF;
}

65
third_party/musl/c16rtomb.c vendored Normal file
View file

@ -0,0 +1,65 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <uchar.h>
#include <errno.h>
#include <wchar.h>
__static_yoink("musl_libc_notice");
#pragma GCC diagnostic ignored "-Wparentheses"
size_t c16rtomb(char *restrict s, char16_t c16, mbstate_t *restrict ps)
{
static unsigned internal_state;
if (!ps) ps = (void *)&internal_state;
unsigned *x = (unsigned *)ps;
wchar_t wc;
if (!s) {
if (*x) goto ilseq;
return 1;
}
if (!*x && c16 - 0xd800u < 0x400) {
*x = c16 - 0xd7c0 << 10;
return 0;
}
if (*x) {
if (c16 - 0xdc00u >= 0x400) goto ilseq;
else wc = *x + c16 - 0xdc00;
*x = 0;
} else {
wc = c16;
}
return wcrtomb(s, wc, 0);
ilseq:
*x = 0;
errno = EILSEQ;
return -1;
}

35
third_party/musl/c32rtomb.c vendored Normal file
View file

@ -0,0 +1,35 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <uchar.h>
#include <wchar.h>
__static_yoink("musl_libc_notice");
size_t c32rtomb(char *restrict s, char32_t c32, mbstate_t *restrict ps)
{
return wcrtomb(s, c32, ps);
}

View file

@ -30,6 +30,7 @@
#include <stdint.h>
#include <endian.h>
#include <sys/mman.h>
__static_yoink("musl_libc_notice");
#define V(p) be32toh(*(uint32_t *)(p))

View file

@ -31,6 +31,7 @@
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
__static_yoink("musl_libc_notice");
#define V(p) be32toh(*(uint32_t *)(p))

View file

@ -35,6 +35,7 @@
#include <locale.h>
#include "third_party/musl/mapfile.internal.h"
#include <sys/mman.h>
__static_yoink("musl_libc_notice");
#define V(p) be32toh(*(uint32_t *)(p))

22
third_party/musl/ctime.c vendored Normal file
View file

@ -0,0 +1,22 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
#include "libc/calls/weirdtypes.h"
#include "libc/time.h"
/**
* Represents time as string.
* @threadunsafe
*/
char *
ctime(const time_t *timep)
{
/*
** Section 4.12.3.2 of X3.159-1989 requires that
** The ctime function converts the calendar time pointed to by timer
** to local time in the form of a string. It is equivalent to
** asctime(localtime(timer))
*/
struct tm *tmp = localtime(timep);
return tmp ? asctime(tmp) : NULL;
}

13
third_party/musl/ctime_r.c vendored Normal file
View file

@ -0,0 +1,13 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
#include "libc/calls/weirdtypes.h"
#include "libc/time.h"
char *
ctime_r(const time_t *timep, char *buf)
{
struct tm mytm;
struct tm *tmp = localtime_r(timep, &mytm);
return tmp ? asctime_r(tmp, buf) : NULL;
}

45
third_party/musl/duplocale.c vendored Normal file
View file

@ -0,0 +1,45 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/runtime/runtime.h"
#include "libc/str/locale.internal.h"
#include "libc/str/str.h"
__static_yoink("musl_libc_notice");
#define malloc _mapanon
#define calloc undef
#define realloc undef
#define free undef
locale_t duplocale(locale_t old)
{
locale_t new = malloc(sizeof *new);
if (!new) return 0;
if (old == LC_GLOBAL_LOCALE) old = &__global_locale;
*new = *old;
return new;
}

View file

@ -25,10 +25,12 @@
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/limits.h"
#include "libc/str/str.h"
#include "libc/wctype.h"
#include "third_party/musl/fnmatch.h"
#include <string.h>
#include <fnmatch.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include "libc/str/locale.internal.h"
__static_yoink("musl_libc_notice");
/*
@ -46,284 +48,279 @@ __static_yoink("musl_libc_notice");
* - Rich Felker, April 2012
*/
#define END 0
#define END 0
#define UNMATCHABLE -2
#define BRACKET -3
#define QUESTION -4
#define STAR -5
#define BRACKET -3
#define QUESTION -4
#define STAR -5
static int FnmatchNextString(const char *str, size_t n, size_t *step) {
if (!n) {
*step = 0;
return 0;
}
if (str[0] >= 128U) {
wchar_t wc;
int k = mbtowc(&wc, str, n);
if (k < 0) {
*step = 1;
return -1;
}
*step = k;
return wc;
}
*step = 1;
return str[0];
static int str_next(const char *str, size_t n, size_t *step)
{
if (!n) {
*step = 0;
return 0;
}
if (str[0] >= 128U) {
wchar_t wc;
int k = mbtowc(&wc, str, n);
if (k<0) {
*step = 1;
return -1;
}
*step = k;
return wc;
}
*step = 1;
return str[0];
}
static int FnmatchNextPattern(const char *pat, size_t m, size_t *step,
int flags) {
int esc = 0;
if (!m || !*pat) {
*step = 0;
return END;
}
*step = 1;
if (pat[0] == '\\' && pat[1] && !(flags & FNM_NOESCAPE)) {
*step = 2;
pat++;
esc = 1;
goto escaped;
}
if (pat[0] == '[') {
size_t k = 1;
if (k < m)
if (pat[k] == '^' || pat[k] == '!') k++;
if (k < m)
if (pat[k] == ']') k++;
for (; k < m && pat[k] && pat[k] != ']'; k++) {
if (k + 1 < m && pat[k + 1] && pat[k] == '[' &&
(pat[k + 1] == ':' || pat[k + 1] == '.' || pat[k + 1] == '=')) {
int z = pat[k + 1];
k += 2;
if (k < m && pat[k]) k++;
while (k < m && pat[k] && (pat[k - 1] != z || pat[k] != ']')) k++;
if (k == m || !pat[k]) break;
}
}
if (k == m || !pat[k]) {
*step = 1;
return '[';
}
*step = k + 1;
return BRACKET;
}
if (pat[0] == '*') return STAR;
if (pat[0] == '?') return QUESTION;
static int pat_next(const char *pat, size_t m, size_t *step, int flags)
{
int esc = 0;
if (!m || !*pat) {
*step = 0;
return END;
}
*step = 1;
if (pat[0]=='\\' && pat[1] && !(flags & FNM_NOESCAPE)) {
*step = 2;
pat++;
esc = 1;
goto escaped;
}
if (pat[0]=='[') {
size_t k = 1;
if (k<m) if (pat[k] == '^' || pat[k] == '!') k++;
if (k<m) if (pat[k] == ']') k++;
for (; k<m && pat[k] && pat[k]!=']'; k++) {
if (k+1<m && pat[k+1] && pat[k]=='[' && (pat[k+1]==':' || pat[k+1]=='.' || pat[k+1]=='=')) {
int z = pat[k+1];
k+=2;
if (k<m && pat[k]) k++;
while (k<m && pat[k] && (pat[k-1]!=z || pat[k]!=']')) k++;
if (k==m || !pat[k]) break;
}
}
if (k==m || !pat[k]) {
*step = 1;
return '[';
}
*step = k+1;
return BRACKET;
}
if (pat[0] == '*')
return STAR;
if (pat[0] == '?')
return QUESTION;
escaped:
if (pat[0] >= 128U) {
wchar_t wc;
int k = mbtowc(&wc, pat, m);
if (k < 0) {
*step = 0;
return UNMATCHABLE;
}
*step = k + esc;
return wc;
}
return pat[0];
if (pat[0] >= 128U) {
wchar_t wc;
int k = mbtowc(&wc, pat, m);
if (k<0) {
*step = 0;
return UNMATCHABLE;
}
*step = k + esc;
return wc;
}
return pat[0];
}
static int FnmatchCaseFold(int k) {
int c = towupper(k);
return c == k ? towlower(k) : c;
static int casefold(int k)
{
int c = towupper(k);
return c == k ? towlower(k) : c;
}
static int FnmatchBracket(const char *p, int k, int kfold) {
wchar_t wc;
int inv = 0;
p++;
if (*p == '^' || *p == '!') {
inv = 1;
p++;
}
if (*p == ']') {
if (k == ']') return !inv;
p++;
} else if (*p == '-') {
if (k == '-') return !inv;
p++;
}
wc = p[-1];
for (; *p != ']'; p++) {
if (p[0] == '-' && p[1] != ']') {
wchar_t wc2;
int l = mbtowc(&wc2, p + 1, 4);
if (l < 0) return 0;
if (wc <= wc2)
if ((unsigned)k - wc <= wc2 - wc || (unsigned)kfold - wc <= wc2 - wc)
return !inv;
p += l - 1;
continue;
}
if (p[0] == '[' && (p[1] == ':' || p[1] == '.' || p[1] == '=')) {
const char *p0 = p + 2;
int z = p[1];
p += 3;
while (p[-1] != z || p[0] != ']') p++;
if (z == ':' && p - 1 - p0 < 16) {
char buf[16];
memcpy(buf, p0, p - 1 - p0);
buf[p - 1 - p0] = 0;
if (iswctype(k, wctype(buf)) || iswctype(kfold, wctype(buf)))
return !inv;
}
continue;
}
if (*p < 128U) {
wc = (unsigned char)*p;
} else {
int l = mbtowc(&wc, p, 4);
if (l < 0) return 0;
p += l - 1;
}
if (wc == k || wc == kfold) return !inv;
}
return inv;
static int match_bracket(const char *p, int k, int kfold)
{
wchar_t wc;
int inv = 0;
p++;
if (*p=='^' || *p=='!') {
inv = 1;
p++;
}
if (*p==']') {
if (k==']') return !inv;
p++;
} else if (*p=='-') {
if (k=='-') return !inv;
p++;
}
wc = p[-1];
for (; *p != ']'; p++) {
if (p[0]=='-' && p[1]!=']') {
wchar_t wc2;
int l = mbtowc(&wc2, p+1, 4);
if (l < 0) return 0;
if (wc <= wc2)
if ((unsigned)k-wc <= wc2-wc ||
(unsigned)kfold-wc <= wc2-wc)
return !inv;
p += l-1;
continue;
}
if (p[0]=='[' && (p[1]==':' || p[1]=='.' || p[1]=='=')) {
const char *p0 = p+2;
int z = p[1];
p+=3;
while (p[-1]!=z || p[0]!=']') p++;
if (z == ':' && p-1-p0 < 16) {
char buf[16];
memcpy(buf, p0, p-1-p0);
buf[p-1-p0] = 0;
if (iswctype(k, wctype(buf)) ||
iswctype(kfold, wctype(buf)))
return !inv;
}
continue;
}
if (*p < 128U) {
wc = (unsigned char)*p;
} else {
int l = mbtowc(&wc, p, 4);
if (l < 0) return 0;
p += l-1;
}
if (wc==k || wc==kfold) return !inv;
}
return inv;
}
static int FnmatchPerform(const char *pat, size_t m, const char *str, size_t n,
int flags) {
const char *p, *ptail, *endpat;
const char *s, *stail, *endstr;
size_t pinc, sinc, tailcnt = 0;
int c, k, kfold;
static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n, int flags)
{
const char *p, *ptail, *endpat;
const char *s, *stail, *endstr;
size_t pinc, sinc, tailcnt=0;
int c, k, kfold;
if (flags & FNM_PERIOD) {
if (*str == '.' && *pat != '.') {
return FNM_NOMATCH;
}
}
if (flags & FNM_PERIOD) {
if (*str == '.' && *pat != '.')
return FNM_NOMATCH;
}
for (;;) {
switch ((c = pat_next(pat, m, &pinc, flags))) {
case UNMATCHABLE:
return FNM_NOMATCH;
case STAR:
pat++;
m--;
break;
default:
k = str_next(str, n, &sinc);
if (k <= 0)
return (c==END) ? 0 : FNM_NOMATCH;
str += sinc;
n -= sinc;
kfold = flags & FNM_CASEFOLD ? casefold(k) : k;
if (c == BRACKET) {
if (!match_bracket(pat, k, kfold))
return FNM_NOMATCH;
} else if (c != QUESTION && k != c && kfold != c) {
return FNM_NOMATCH;
}
pat+=pinc;
m-=pinc;
continue;
}
break;
}
for (;;) {
switch ((c = FnmatchNextPattern(pat, m, &pinc, flags))) {
case UNMATCHABLE:
return FNM_NOMATCH;
case STAR:
pat++;
m--;
break;
default:
k = FnmatchNextString(str, n, &sinc);
if (k <= 0) return (c == END) ? 0 : FNM_NOMATCH;
str += sinc;
n -= sinc;
kfold = flags & FNM_CASEFOLD ? FnmatchCaseFold(k) : k;
if (c == BRACKET) {
if (!FnmatchBracket(pat, k, kfold)) return FNM_NOMATCH;
} else if (c != QUESTION && k != c && kfold != c) {
return FNM_NOMATCH;
}
pat += pinc;
m -= pinc;
continue;
}
break;
}
/* Compute real pat length if it was initially unknown/-1 */
m = strnlen(pat, m);
endpat = pat + m;
/* Compute real pat length if it was initially unknown/-1 */
m = strnlen(pat, m);
endpat = pat + m;
/* Find the last * in pat and count chars needed after it */
for (p=ptail=pat; p<endpat; p+=pinc) {
switch (pat_next(p, endpat-p, &pinc, flags)) {
case UNMATCHABLE:
return FNM_NOMATCH;
case STAR:
tailcnt=0;
ptail = p+1;
break;
default:
tailcnt++;
break;
}
}
/* Find the last * in pat and count chars needed after it */
for (p = ptail = pat; p < endpat; p += pinc) {
switch (FnmatchNextPattern(p, endpat - p, &pinc, flags)) {
case UNMATCHABLE:
return FNM_NOMATCH;
case STAR:
tailcnt = 0;
ptail = p + 1;
break;
default:
tailcnt++;
break;
}
}
/* Past this point we need not check for UNMATCHABLE in pat,
* because all of pat has already been parsed once. */
/* Past this point we need not check for UNMATCHABLE in pat,
* because all of pat has already been parsed once. */
/* Compute real str length if it was initially unknown/-1 */
n = strnlen(str, n);
endstr = str + n;
if (n < tailcnt) return FNM_NOMATCH;
/* Compute real str length if it was initially unknown/-1 */
n = strnlen(str, n);
endstr = str + n;
if (n < tailcnt) {
return FNM_NOMATCH;
}
/* Find the final tailcnt chars of str, accounting for UTF-8.
* On illegal sequences we may get it wrong, but in that case
* we necessarily have a matching failure anyway. */
for (s=endstr; s>str && tailcnt; tailcnt--) {
if (s[-1] < 128U || MB_CUR_MAX==1) s--;
else while ((unsigned char)*--s-0x80U<0x40 && s>str);
}
if (tailcnt) return FNM_NOMATCH;
stail = s;
/* Find the final tailcnt chars of str, accounting for UTF-8.
* On illegal sequences we may get it wrong, but in that case
* we necessarily have a matching failure anyway. */
for (s = endstr; s > str && tailcnt; tailcnt--) {
if (s[-1] < 128U || MB_CUR_MAX == 1) {
s--;
} else {
while ((unsigned char)*--s - 0x80U < 0x40 && s > str)
;
}
}
if (tailcnt) return FNM_NOMATCH;
stail = s;
/* Check that the pat and str tails match */
p = ptail;
for (;;) {
c = pat_next(p, endpat-p, &pinc, flags);
p += pinc;
if ((k = str_next(s, endstr-s, &sinc)) <= 0) {
if (c != END) return FNM_NOMATCH;
break;
}
s += sinc;
kfold = flags & FNM_CASEFOLD ? casefold(k) : k;
if (c == BRACKET) {
if (!match_bracket(p-pinc, k, kfold))
return FNM_NOMATCH;
} else if (c != QUESTION && k != c && kfold != c) {
return FNM_NOMATCH;
}
}
/* Check that the pat and str tails match */
p = ptail;
for (;;) {
c = FnmatchNextPattern(p, endpat - p, &pinc, flags);
p += pinc;
if ((k = FnmatchNextString(s, endstr - s, &sinc)) <= 0) {
if (c != END) return FNM_NOMATCH;
break;
}
s += sinc;
kfold = flags & FNM_CASEFOLD ? FnmatchCaseFold(k) : k;
if (c == BRACKET) {
if (!FnmatchBracket(p - pinc, k, kfold)) return FNM_NOMATCH;
} else if (c != QUESTION && k != c && kfold != c) {
return FNM_NOMATCH;
}
}
/* We're all done with the tails now, so throw them out */
endstr = stail;
endpat = ptail;
/* We're all done with the tails now, so throw them out */
endstr = stail;
endpat = ptail;
/* Match pattern components until there are none left */
while (pat<endpat) {
p = pat;
s = str;
for (;;) {
c = pat_next(p, endpat-p, &pinc, flags);
p += pinc;
/* Encountering * completes/commits a component */
if (c == STAR) {
pat = p;
str = s;
break;
}
k = str_next(s, endstr-s, &sinc);
if (!k)
return FNM_NOMATCH;
kfold = flags & FNM_CASEFOLD ? casefold(k) : k;
if (c == BRACKET) {
if (!match_bracket(p-pinc, k, kfold))
break;
} else if (c != QUESTION && k != c && kfold != c) {
break;
}
s += sinc;
}
if (c == STAR) continue;
/* If we failed, advance str, by 1 char if it's a valid
* char, or past all invalid bytes otherwise. */
k = str_next(str, endstr-str, &sinc);
if (k > 0) str += sinc;
else for (str++; str_next(str, endstr-str, &sinc)<0; str++);
}
/* Match pattern components until there are none left */
while (pat < endpat) {
p = pat;
s = str;
for (;;) {
c = FnmatchNextPattern(p, endpat - p, &pinc, flags);
p += pinc;
/* Encountering * completes/commits a component */
if (c == STAR) {
pat = p;
str = s;
break;
}
k = FnmatchNextString(s, endstr - s, &sinc);
if (!k) return FNM_NOMATCH;
kfold = flags & FNM_CASEFOLD ? FnmatchCaseFold(k) : k;
if (c == BRACKET) {
if (!FnmatchBracket(p - pinc, k, kfold)) break;
} else if (c != QUESTION && k != c && kfold != c) {
break;
}
s += sinc;
}
if (c == STAR) continue;
/* If we failed, advance str, by 1 char if it's a valid
* char, or past all invalid bytes otherwise. */
k = FnmatchNextString(str, endstr - str, &sinc);
if (k > 0) {
str += sinc;
} else {
str++;
while (FnmatchNextString(str, endstr - str, &sinc) < 0) {
str++;
}
}
}
return 0;
return 0;
}
/**
@ -337,29 +334,27 @@ static int FnmatchPerform(const char *pat, size_t m, const char *str, size_t n,
*
* @see glob()
*/
int fnmatch(const char *pat, const char *str, int flags) {
const char *s, *p;
size_t inc;
int c;
if (flags & FNM_PATHNAME) {
for (;;) {
for (s = str; *s && *s != '/'; s++)
;
for (p = pat;
(c = FnmatchNextPattern(p, -1, &inc, flags)) != END && c != '/';
p += inc)
;
if (c != *s && (!*s || !(flags & FNM_LEADING_DIR))) return FNM_NOMATCH;
if (FnmatchPerform(pat, p - pat, str, s - str, flags)) return FNM_NOMATCH;
if (!c) return 0;
str = s + 1;
pat = p + inc;
}
} else if (flags & FNM_LEADING_DIR) {
for (s = str; *s; s++) {
if (*s != '/') continue;
if (!FnmatchPerform(pat, -1, str, s - str, flags)) return 0;
}
}
return FnmatchPerform(pat, -1, str, -1, flags);
int fnmatch(const char *pat, const char *str, int flags)
{
const char *s, *p;
size_t inc;
int c;
if (flags & FNM_PATHNAME) for (;;) {
for (s=str; *s && *s!='/'; s++);
for (p=pat; (c=pat_next(p, -1, &inc, flags))!=END && c!='/'; p+=inc);
if (c!=*s && (!*s || !(flags & FNM_LEADING_DIR)))
return FNM_NOMATCH;
if (fnmatch_internal(pat, p-pat, str, s-str, flags))
return FNM_NOMATCH;
if (!c) return 0;
str = s+1;
pat = p+inc;
} else if (flags & FNM_LEADING_DIR) {
for (s=str; *s; s++) {
if (*s != '/') continue;
if (!fnmatch_internal(pat, -1, str, s-str, flags))
return 0;
}
}
return fnmatch_internal(pat, -1, str, -1, flags);
}

41
third_party/musl/freelocale.c vendored Normal file
View file

@ -0,0 +1,41 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/str/locale.internal.h"
__static_yoink("musl_libc_notice");
#define malloc undef
#define calloc undef
#define realloc undef
#define free(p) munmap(p, sizeof(struct __locale_struct))
void freelocale(locale_t l)
{
if (__loc_is_allocated(l)) free(l);
}

View file

@ -35,190 +35,227 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/dt.h"
#include "libc/sysv/consts/s.h"
#include "libc/limits.h"
#include "libc/str/str.h"
#include "libc/runtime/runtime.h"
#include "third_party/musl/passwd.h"
#include "third_party/musl/fnmatch.h"
__static_yoink("musl_libc_notice");
#define MAXPATH 1024
#pragma GCC diagnostic ignored "-Wparentheses"
struct GlobList {
struct GlobList *next;
char name[];
struct match
{
struct match *next;
char name[];
};
static int AppendGlob(struct GlobList **tail, const char *name, size_t len,
int mark) {
struct GlobList *new;
if ((new = malloc(sizeof(struct GlobList) + len + 2))) {
(*tail)->next = new;
new->next = NULL;
memcpy(new->name, name, len + 1);
if (mark && len && name[len - 1] != '/') {
new->name[len] = '/';
new->name[len + 1] = 0;
}
*tail = new;
return 0;
} else {
return -1;
}
static int append(struct match **tail, const char *name, size_t len, int mark)
{
struct match *new = malloc(sizeof(struct match) + len + 2);
if (!new) return -1;
(*tail)->next = new;
new->next = NULL;
memcpy(new->name, name, len+1);
if (mark && len && name[len-1]!='/') {
new->name[len] = '/';
new->name[len+1] = 0;
}
*tail = new;
return 0;
}
static int PerformGlob(char *buf, size_t pos, int type, char *pat, int flags,
int (*errfunc)(const char *path, int err),
struct GlobList **tail) {
DIR *dir;
size_t l;
char *p, *p2;
char saved_sep;
ptrdiff_t i, j;
struct stat st;
struct dirent *de;
int r, readerr, in_bracket, overflow, old_errno, fnm_flags;
/* If GLOB_MARK is unused, we don't care about type. */
if (!type && !(flags & GLOB_MARK)) type = DT_REG;
/* Special-case the remaining pattern being all slashes, in
* which case we can use caller-passed type if it's a dir. */
if (*pat && type != DT_DIR) type = 0;
while (pos + 1 < MAXPATH && *pat == '/') {
buf[pos++] = *pat++;
}
/* Consume maximal [escaped-]literal prefix of pattern, copying
* and un-escaping it to the running buffer as we go. */
i = 0;
j = 0;
overflow = 0;
in_bracket = 0;
for (; pat[i] != '*' && pat[i] != '?' && (!in_bracket || pat[i] != ']');
i++) {
if (!pat[i]) {
if (overflow) return 0;
pat += i;
pos += j;
i = j = 0;
break;
} else if (pat[i] == '[') {
in_bracket = 1;
} else if (pat[i] == '\\' && !(flags & GLOB_NOESCAPE)) {
/* Backslashes inside a bracket are (at least by
* our interpretation) non-special, so if next
* char is ']' we have a complete expression. */
if (in_bracket && pat[i + 1] == ']') break;
/* Unpaired final backslash never matches. */
if (!pat[i + 1]) return 0;
i++;
}
if (pat[i] == '/') {
if (overflow) return 0;
in_bracket = 0;
pat += i + 1;
i = -1;
pos += j + 1;
j = -1;
}
/* Only store a character if it fits in the buffer, but if
* a potential bracket expression is open, the overflow
* must be remembered and handled later only if the bracket
* is unterminated (and thereby a literal), so as not to
* disallow long bracket expressions with short matches. */
if (pos + (j + 1) < MAXPATH) {
buf[pos + j++] = pat[i];
} else if (in_bracket) {
overflow = 1;
} else {
return 0;
}
/* If we consume any new components, the caller-passed type
* or dummy type from above is no longer valid. */
type = 0;
}
buf[pos] = 0;
if (!*pat) {
/* If we consumed any components above, or if GLOB_MARK is
* requested and we don't yet know if the match is a dir,
* we must call stat to confirm the file exists and/or
* determine its type. */
if ((flags & GLOB_MARK) && type == DT_LNK) type = 0;
if (!type && stat(buf, &st)) {
if (errno != ENOENT && (errfunc(buf, errno) || (flags & GLOB_ERR))) {
return GLOB_ABORTED;
}
return 0;
}
if (!type && S_ISDIR(st.st_mode)) type = DT_DIR;
if (AppendGlob(tail, buf, pos, (flags & GLOB_MARK) && type == DT_DIR)) {
return GLOB_NOSPACE;
}
return 0;
}
p2 = strchr(pat, '/');
saved_sep = '/';
/* Check if the '/' was escaped and, if so, remove the escape char
* so that it will not be unpaired when passed to fnmatch. */
if (p2 && !(flags & GLOB_NOESCAPE)) {
for (p = p2; p > pat && p[-1] == '\\'; p--)
;
if ((p2 - p) % 2) {
p2--;
saved_sep = '\\';
}
}
dir = opendir(pos ? buf : ".");
if (!dir) {
if (errfunc(buf, errno) || (flags & GLOB_ERR)) return GLOB_ABORTED;
return 0;
}
old_errno = errno;
while (errno = 0, de = readdir(dir)) {
/* Quickly skip non-directories when there's pattern left. */
if (p2 && de->d_type && de->d_type != DT_DIR && de->d_type != DT_LNK) {
continue;
}
l = strlen(de->d_name);
if (l >= MAXPATH - pos) continue;
if (p2) *p2 = 0;
fnm_flags = ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) |
((!(flags & GLOB_PERIOD)) ? FNM_PERIOD : 0);
if (fnmatch(pat, de->d_name, fnm_flags)) continue;
/* With GLOB_PERIOD don't allow matching . or .. unless fnmatch()
* would match them with FNM_PERIOD rules in effect. */
if (p2 && (flags & GLOB_PERIOD) && de->d_name[0] == '.' &&
(!de->d_name[1] || (de->d_name[1] == '.' && !de->d_name[2])) &&
fnmatch(pat, de->d_name, fnm_flags | FNM_PERIOD)) {
continue;
}
memcpy(buf + pos, de->d_name, l + 1);
if (p2) *p2 = saved_sep;
r = PerformGlob(buf, pos + l, de->d_type, p2 ? p2 : "", flags, errfunc,
tail);
if (r) {
closedir(dir);
return r;
}
}
readerr = errno;
if (p2) *p2 = saved_sep;
closedir(dir);
if (readerr && (errfunc(buf, errno) || (flags & GLOB_ERR))) {
return GLOB_ABORTED;
}
errno = old_errno;
return 0;
static int do_glob(char *buf, size_t pos, int type, char *pat, int flags, int (*errfunc)(const char *path, int err), struct match **tail)
{
/* If GLOB_MARK is unused, we don't care about type. */
if (!type && !(flags & GLOB_MARK)) type = DT_REG;
/* Special-case the remaining pattern being all slashes, in
* which case we can use caller-passed type if it's a dir. */
if (*pat && type!=DT_DIR) type = 0;
while (pos+1 < PATH_MAX && *pat=='/') buf[pos++] = *pat++;
/* Consume maximal [escaped-]literal prefix of pattern, copying
* and un-escaping it to the running buffer as we go. */
ptrdiff_t i=0, j=0;
int in_bracket = 0, overflow = 0;
for (; pat[i]!='*' && pat[i]!='?' && (!in_bracket || pat[i]!=']'); i++) {
if (!pat[i]) {
if (overflow) return 0;
pat += i;
pos += j;
i = j = 0;
break;
} else if (pat[i] == '[') {
in_bracket = 1;
} else if (pat[i] == '\\' && !(flags & GLOB_NOESCAPE)) {
/* Backslashes inside a bracket are (at least by
* our interpretation) non-special, so if next
* char is ']' we have a complete expression. */
if (in_bracket && pat[i+1]==']') break;
/* Unpaired final backslash never matches. */
if (!pat[i+1]) return 0;
i++;
}
if (pat[i] == '/') {
if (overflow) return 0;
in_bracket = 0;
pat += i+1;
i = -1;
pos += j+1;
j = -1;
}
/* Only store a character if it fits in the buffer, but if
* a potential bracket expression is open, the overflow
* must be remembered and handled later only if the bracket
* is unterminated (and thereby a literal), so as not to
* disallow long bracket expressions with short matches. */
if (pos+(j+1) < PATH_MAX) {
buf[pos+j++] = pat[i];
} else if (in_bracket) {
overflow = 1;
} else {
return 0;
}
/* If we consume any new components, the caller-passed type
* or dummy type from above is no longer valid. */
type = 0;
}
buf[pos] = 0;
if (!*pat) {
/* If we consumed any components above, or if GLOB_MARK is
* requested and we don't yet know if the match is a dir,
* we must confirm the file exists and/or determine its type.
*
* If marking dirs, symlink type is inconclusive; we need the
* type for the symlink target, and therefore must try stat
* first unless type is known not to be a symlink. Otherwise,
* or if that fails, use lstat for determining existence to
* avoid false negatives in the case of broken symlinks. */
struct stat st;
if ((flags & GLOB_MARK) && (!type||type==DT_LNK) && !stat(buf, &st)) {
if (S_ISDIR(st.st_mode)) type = DT_DIR;
else type = DT_REG;
}
if (!type && lstat(buf, &st)) {
if (errno!=ENOENT && (errfunc(buf, errno) || (flags & GLOB_ERR)))
return GLOB_ABORTED;
return 0;
}
if (append(tail, buf, pos, (flags & GLOB_MARK) && type==DT_DIR))
return GLOB_NOSPACE;
return 0;
}
char *p2 = strchr(pat, '/'), saved_sep = '/';
/* Check if the '/' was escaped and, if so, remove the escape char
* so that it will not be unpaired when passed to fnmatch. */
if (p2 && !(flags & GLOB_NOESCAPE)) {
char *p;
for (p=p2; p>pat && p[-1]=='\\'; p--);
if ((p2-p)%2) {
p2--;
saved_sep = '\\';
}
}
DIR *dir = opendir(pos ? buf : ".");
if (!dir) {
if (errfunc(buf, errno) || (flags & GLOB_ERR))
return GLOB_ABORTED;
return 0;
}
int old_errno = errno;
struct dirent *de;
while (errno=0, de=readdir(dir)) {
/* Quickly skip non-directories when there's pattern left. */
if (p2 && de->d_type && de->d_type!=DT_DIR && de->d_type!=DT_LNK)
continue;
size_t l = strlen(de->d_name);
if (l >= PATH_MAX-pos) continue;
if (p2) *p2 = 0;
int fnm_flags= ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
| ((!(flags & GLOB_PERIOD)) ? FNM_PERIOD : 0);
if (fnmatch(pat, de->d_name, fnm_flags))
continue;
/* With GLOB_PERIOD, don't allow matching . or .. unless
* fnmatch would match them with FNM_PERIOD rules in effect. */
if (p2 && (flags & GLOB_PERIOD) && de->d_name[0]=='.'
&& (!de->d_name[1] || de->d_name[1]=='.' && !de->d_name[2])
&& fnmatch(pat, de->d_name, fnm_flags | FNM_PERIOD))
continue;
memcpy(buf+pos, de->d_name, l+1);
if (p2) *p2 = saved_sep;
int r = do_glob(buf, pos+l, de->d_type, p2 ? p2 : "", flags, errfunc, tail);
if (r) {
closedir(dir);
return r;
}
}
int readerr = errno;
if (p2) *p2 = saved_sep;
closedir(dir);
if (readerr && (errfunc(buf, errno) || (flags & GLOB_ERR)))
return GLOB_ABORTED;
errno = old_errno;
return 0;
}
static int IgnoreGlobError(const char *path, int err) {
return 0;
static int ignore_err(const char *path, int err)
{
return 0;
}
static void FreeGlobList(struct GlobList *head) {
struct GlobList *match, *next;
for (match = head->next; match; match = next) {
next = match->next;
free(match);
}
static void freelist(struct match *head)
{
struct match *match, *next;
for (match=head->next; match; match=next) {
next = match->next;
free(match);
}
}
static int GlobPredicate(const void *a, const void *b) {
return strcmp(*(const char **)a, *(const char **)b);
static int sort(const void *a, const void *b)
{
return strcmp(*(const char **)a, *(const char **)b);
}
static int expand_tilde(char **pat, char *buf, size_t *pos)
{
char *p = *pat + 1;
size_t i = 0;
char delim, *name_end = strchrnul(p, '/');
if ((delim = *name_end)) *name_end++ = 0;
*pat = name_end;
char *home = *p ? NULL : getenv("HOME");
if (!home) {
struct passwd pw, *res;
int e = *p ? getpwnam_r(p, &pw, buf, PATH_MAX, &res)
: getpwuid_r(getuid(), &pw, buf, PATH_MAX, &res);
if (e == ENOMEM) {
return GLOB_NOSPACE;
} else if (e == 0) {
if (!res)
return GLOB_NOMATCH;
} else {
return GLOB_NOMATCH;
}
home = pw.pw_dir;
}
while (i < PATH_MAX - 2 && *home)
buf[i++] = *home++;
if (*home)
return GLOB_NOMATCH;
if ((buf[i] = delim))
buf[++i] = 0;
*pos = i;
return 0;
}
/**
@ -239,81 +276,88 @@ static int GlobPredicate(const void *a, const void *b) {
* @return 0 on success or GLOB_NOMATCH, GLOB_NOSPACE on OOM, or
* GLOB_ABORTED on read error
*/
int glob(const char *pat, int flags, int errfunc(const char *path, int err),
glob_t *g) {
int error = 0;
size_t cnt, i;
char **pathv, buf[MAXPATH];
struct GlobList head = {.next = NULL}, *tail = &head;
size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0;
if (!errfunc) errfunc = IgnoreGlobError;
if (!(flags & GLOB_APPEND)) {
g->gl_offs = offs;
g->gl_pathc = 0;
g->gl_pathv = NULL;
}
if (*pat) {
char *p = strdup(pat);
if (!p) return GLOB_NOSPACE;
buf[0] = 0;
error = PerformGlob(buf, 0, 0, p, flags, errfunc, &tail);
free(p);
}
if (error == GLOB_NOSPACE) {
FreeGlobList(&head);
return error;
}
for (cnt = 0, tail = head.next; tail; tail = tail->next, cnt++)
;
if (!cnt) {
if (flags & GLOB_NOCHECK) {
tail = &head;
if (AppendGlob(&tail, pat, strlen(pat), 0)) {
return GLOB_NOSPACE;
}
cnt++;
} else
return GLOB_NOMATCH;
}
if (flags & GLOB_APPEND) {
pathv =
realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *));
if (!pathv) {
FreeGlobList(&head);
return GLOB_NOSPACE;
}
g->gl_pathv = pathv;
offs += g->gl_pathc;
} else {
g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *));
if (!g->gl_pathv) {
FreeGlobList(&head);
return GLOB_NOSPACE;
}
for (i = 0; i < offs; i++) {
g->gl_pathv[i] = NULL;
}
}
for (i = 0, tail = head.next; i < cnt; tail = tail->next, i++) {
g->gl_pathv[offs + i] = tail->name;
}
g->gl_pathv[offs + i] = NULL;
g->gl_pathc += cnt;
if (!(flags & GLOB_NOSORT)) {
qsort(g->gl_pathv + offs, cnt, sizeof(char *), GlobPredicate);
}
return error;
int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, int err), glob_t *restrict g)
{
struct match head = { .next = NULL }, *tail = &head;
size_t cnt, i;
size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0;
int error = 0;
char buf[PATH_MAX];
if (!errfunc) errfunc = ignore_err;
if (!(flags & GLOB_APPEND)) {
g->gl_offs = offs;
g->gl_pathc = 0;
g->gl_pathv = NULL;
}
if (*pat) {
char *p = strdup(pat);
if (!p) return GLOB_NOSPACE;
buf[0] = 0;
size_t pos = 0;
char *s = p;
if ((flags & (GLOB_TILDE | GLOB_TILDE_CHECK)) && *p == '~')
error = expand_tilde(&s, buf, &pos);
if (!error)
error = do_glob(buf, pos, 0, s, flags, errfunc, &tail);
free(p);
}
if (error == GLOB_NOSPACE) {
freelist(&head);
return error;
}
for (cnt=0, tail=head.next; tail; tail=tail->next, cnt++);
if (!cnt) {
if (flags & GLOB_NOCHECK) {
tail = &head;
if (append(&tail, pat, strlen(pat), 0))
return GLOB_NOSPACE;
cnt++;
} else if (!error)
return GLOB_NOMATCH;
}
if (flags & GLOB_APPEND) {
char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *));
if (!pathv) {
freelist(&head);
return GLOB_NOSPACE;
}
g->gl_pathv = pathv;
offs += g->gl_pathc;
} else {
g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *));
if (!g->gl_pathv) {
freelist(&head);
return GLOB_NOSPACE;
}
for (i=0; i<offs; i++)
g->gl_pathv[i] = NULL;
}
for (i=0, tail=head.next; i<cnt; tail=tail->next, i++)
g->gl_pathv[offs + i] = tail->name;
g->gl_pathv[offs + i] = NULL;
g->gl_pathc += cnt;
if (!(flags & GLOB_NOSORT))
qsort(g->gl_pathv+offs, cnt, sizeof(char *), sort);
return error;
}
/**
* Frees entries allocated by glob().
*/
void globfree(glob_t *g) {
size_t i;
for (i = 0; i < g->gl_pathc; i++) {
free(g->gl_pathv[g->gl_offs + i] - offsetof(struct GlobList, name));
}
free(g->gl_pathv);
g->gl_pathc = 0;
g->gl_pathv = NULL;
void globfree(glob_t *g)
{
size_t i;
for (i=0; i<g->gl_pathc; i++)
free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name));
free(g->gl_pathv);
g->gl_pathc = 0;
g->gl_pathv = NULL;
}

727
third_party/musl/iconv.c vendored Normal file
View file

@ -0,0 +1,727 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/stdio/iconv.h"
#include "libc/errno.h"
#include "libc/mem/mem.h"
#include "libc/str/locale.h"
#include "libc/str/locale.internal.h"
#include "libc/str/str.h"
#include "libc/thread/tls.h"
// clang-format off
__static_yoink("musl_libc_notice");
#define UTF_32BE 0300
#define UTF_16LE 0301
#define UTF_16BE 0302
#define UTF_32LE 0303
#define UCS2BE 0304
#define UCS2LE 0305
#define WCHAR_T 0306
#define US_ASCII 0307
#define UTF_8 0310
#define UTF_16 0312
#define UTF_32 0313
#define UCS2 0314
#define EUC_JP 0320
#define SHIFT_JIS 0321
#define ISO2022_JP 0322
#define GB18030 0330
#define GBK 0331
#define GB2312 0332
#define BIG5 0340
#define EUC_KR 0350
/* Definitions of charmaps. Each charmap consists of:
* 1. Empty-string-terminated list of null-terminated aliases.
* 2. Special type code or number of elided quads of entries.
* 3. Character table (size determined by field 2), consisting
* of 5 bytes for every 4 characters, interpreted as 10-bit
* indices into the legacy_chars table. */
static const unsigned char charmaps[] =
"utf8\0char\0\0\310"
"wchart\0\0\306"
"ucs2be\0\0\304"
"ucs2le\0\0\305"
"utf16be\0\0\302"
"utf16le\0\0\301"
"ucs4be\0utf32be\0\0\300"
"ucs4le\0utf32le\0\0\303"
"ascii\0usascii\0iso646\0iso646us\0\0\307"
"utf16\0\0\312"
"ucs4\0utf32\0\0\313"
"ucs2\0\0\314"
"eucjp\0\0\320"
"shiftjis\0sjis\0cp932\0\0\321"
"iso2022jp\0\0\322"
"gb18030\0\0\330"
"gbk\0cp936\0windows936\0\0\331"
"gb2312\0\0\332"
"big5\0bigfive\0cp950\0big5hkscs\0\0\340"
"euckr\0ksc5601\0ksx1001\0cp949\0\0\350"
#include "libc/stdio/codepages.inc"
;
#pragma GCC diagnostic ignored "-Wmissing-braces"
#pragma GCC diagnostic ignored "-Wparentheses"
/* Table of characters that appear in legacy 8-bit codepages,
* limited to 1024 slots (10 bit indices). The first 256 entries
* are elided since those characters are obviously all included. */
static const unsigned short legacy_chars[] = {
#include "libc/stdio/legacychars.inc"
};
static const unsigned short jis0208[84][94] = {
#include "libc/stdio/jis0208.inc"
};
static const unsigned short gb18030[126][190] = {
#include "libc/stdio/gb18030.inc"
};
static const unsigned short big5[89][157] = {
#include "libc/stdio/big5.inc"
};
static const unsigned short hkscs[] = {
#include "libc/stdio/hkscs.inc"
};
static const unsigned short ksc[93][94] = {
#include "libc/stdio/ksc.inc"
};
static const unsigned short rev_jis[] = {
#include "libc/stdio/revjis.inc"
};
static int fuzzycmp(const unsigned char *a, const unsigned char *b)
{
for (; *a && *b; a++, b++) {
while (*a && (*a|32U)-'a'>26 && *a-'0'>10U) a++;
if ((*a|32U) != *b) return 1;
}
return *a != *b;
}
static size_t find_charmap(const void *name)
{
const unsigned char *s;
if (!*(char *)name) name=charmaps; /* "utf8" */
for (s=charmaps; *s; ) {
if (!fuzzycmp(name, s)) {
for (; *s; s+=strlen((void *)s)+1);
return s+1-charmaps;
}
s += strlen((void *)s)+1;
if (!*s) {
if (s[1] > 0200) s+=2;
else s+=2+(64U-s[1])*5;
}
}
return -1;
}
struct stateful_cd {
iconv_t base_cd;
unsigned state;
};
static iconv_t combine_to_from(size_t t, size_t f)
{
return (void *)(f<<16 | t<<1 | 1);
}
static size_t extract_from(iconv_t cd)
{
return (size_t)cd >> 16;
}
static size_t extract_to(iconv_t cd)
{
return (size_t)cd >> 1 & 0x7fff;
}
iconv_t iconv_open(const char *to, const char *from)
{
size_t f, t;
struct stateful_cd *scd;
if ((t = find_charmap(to))==-1
|| (f = find_charmap(from))==-1
|| (charmaps[t] >= 0330)) {
errno = EINVAL;
return (iconv_t)-1;
}
iconv_t cd = combine_to_from(t, f);
switch (charmaps[f]) {
case UTF_16:
case UTF_32:
case UCS2:
case ISO2022_JP:
scd = malloc(sizeof *scd);
if (!scd) return (iconv_t)-1;
scd->base_cd = cd;
scd->state = 0;
cd = (iconv_t)scd;
}
return cd;
}
int iconv_close(iconv_t cd)
{
if (!((size_t)cd & 1)) free((void *)cd);
return 0;
}
static unsigned get_16(const unsigned char *s, int e)
{
e &= 1;
return s[e]<<8 | s[1-e];
}
static void put_16(unsigned char *s, unsigned c, int e)
{
e &= 1;
s[e] = c>>8;
s[1-e] = c;
}
static unsigned get_32(const unsigned char *s, int e)
{
e &= 3;
return (s[e]+0U)<<24 | s[e^1]<<16 | s[e^2]<<8 | s[e^3];
}
static void put_32(unsigned char *s, unsigned c, int e)
{
e &= 3;
s[e^0] = c>>24;
s[e^1] = c>>16;
s[e^2] = c>>8;
s[e^3] = c;
}
/* Adapt as needed */
#define mbrtowc_utf8 mbrtowc
#define wctomb_utf8 wctomb
static unsigned legacy_map(const unsigned char *map, unsigned c)
{
if (c < 4*map[-1]) return c;
unsigned x = c - 4*map[-1];
x = map[x*5/4]>>2*x%8 | map[x*5/4+1]<<8-2*x%8 & 1023;
return x < 256 ? x : legacy_chars[x-256];
}
static unsigned uni_to_jis(unsigned c)
{
unsigned nel = sizeof rev_jis / sizeof *rev_jis;
unsigned d, j, i, b = 0;
for (;;) {
i = nel/2;
j = rev_jis[b+i];
d = jis0208[j/256][j%256];
if (d==c) return j + 0x2121;
else if (nel == 1) return 0;
else if (c < d)
nel /= 2;
else {
b += i;
nel -= nel/2;
}
}
}
size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restrict out, size_t *restrict outb)
{
size_t x=0;
struct stateful_cd *scd=0;
if (!((size_t)cd & 1)) {
scd = (void *)cd;
cd = scd->base_cd;
}
unsigned to = extract_to(cd);
unsigned from = extract_from(cd);
const unsigned char *map = charmaps+from+1;
const unsigned char *tomap = charmaps+to+1;
mbstate_t st = {0};
wchar_t wc;
unsigned c, d;
size_t k, l;
int err;
unsigned char type = map[-1];
unsigned char totype = tomap[-1];
locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
if (!in || !*in || !*inb) return 0;
*ploc = UTF8_LOCALE;
for (; *inb; *in+=l, *inb-=l) {
c = *(unsigned char *)*in;
l = 1;
switch (type) {
case UTF_8:
if (c < 128) break;
l = mbrtowc_utf8(&wc, *in, *inb, &st);
if (l == (size_t)-1) goto ilseq;
if (l == (size_t)-2) goto starved;
c = wc;
break;
case US_ASCII:
if (c >= 128) goto ilseq;
break;
case WCHAR_T:
l = sizeof(wchar_t);
if (*inb < l) goto starved;
c = *(wchar_t *)*in;
if (0) {
case UTF_32BE:
case UTF_32LE:
l = 4;
if (*inb < 4) goto starved;
c = get_32((void *)*in, type);
}
if (c-0xd800u < 0x800u || c >= 0x110000u) goto ilseq;
break;
case UCS2BE:
case UCS2LE:
case UTF_16BE:
case UTF_16LE:
l = 2;
if (*inb < 2) goto starved;
c = get_16((void *)*in, type);
if ((unsigned)(c-0xdc00) < 0x400) goto ilseq;
if ((unsigned)(c-0xd800) < 0x400) {
if (type-UCS2BE < 2U) goto ilseq;
l = 4;
if (*inb < 4) goto starved;
d = get_16((void *)(*in + 2), type);
if ((unsigned)(d-0xdc00) >= 0x400) goto ilseq;
c = ((c-0xd7c0)<<10) + (d-0xdc00);
}
break;
case UCS2:
case UTF_16:
l = 0;
if (!scd->state) {
if (*inb < 2) goto starved;
c = get_16((void *)*in, 0);
scd->state = type==UCS2
? c==0xfffe ? UCS2LE : UCS2BE
: c==0xfffe ? UTF_16LE : UTF_16BE;
if (c == 0xfffe || c == 0xfeff)
l = 2;
}
type = scd->state;
continue;
case UTF_32:
l = 0;
if (!scd->state) {
if (*inb < 4) goto starved;
c = get_32((void *)*in, 0);
scd->state = c==0xfffe0000 ? UTF_32LE : UTF_32BE;
if (c == 0xfffe0000 || c == 0xfeff)
l = 4;
}
type = scd->state;
continue;
case SHIFT_JIS:
if (c < 128) break;
if (c-0xa1 <= 0xdf-0xa1) {
c += 0xff61-0xa1;
break;
}
l = 2;
if (*inb < 2) goto starved;
d = *((unsigned char *)*in + 1);
if (c-129 <= 159-129) c -= 129;
else if (c-224 <= 239-224) c -= 193;
else goto ilseq;
c *= 2;
if (d-64 <= 158-64) {
if (d==127) goto ilseq;
if (d>127) d--;
d -= 64;
} else if (d-159 <= 252-159) {
c++;
d -= 159;
}
if (c>=84) goto ilseq;
c = jis0208[c][d];
if (!c) goto ilseq;
break;
case EUC_JP:
if (c < 128) break;
l = 2;
if (*inb < 2) goto starved;
d = *((unsigned char *)*in + 1);
if (c==0x8e) {
c = d;
if (c-0xa1 > 0xdf-0xa1) goto ilseq;
c += 0xff61 - 0xa1;
break;
}
c -= 0xa1;
d -= 0xa1;
if (c >= 84 || d >= 94) goto ilseq;
c = jis0208[c][d];
if (!c) goto ilseq;
break;
case ISO2022_JP:
if (c >= 128) goto ilseq;
if (c == '\033') {
l = 3;
if (*inb < 3) goto starved;
c = *((unsigned char *)*in + 1);
d = *((unsigned char *)*in + 2);
if (c != '(' && c != '$') goto ilseq;
switch (128*(c=='$') + d) {
case 'B': scd->state=0; continue;
case 'J': scd->state=1; continue;
case 'I': scd->state=4; continue;
case 128+'@': scd->state=2; continue;
case 128+'B': scd->state=3; continue;
}
goto ilseq;
}
switch (scd->state) {
case 1:
if (c=='\\') c = 0xa5;
if (c=='~') c = 0x203e;
break;
case 2:
case 3:
l = 2;
if (*inb < 2) goto starved;
d = *((unsigned char *)*in + 1);
c -= 0x21;
d -= 0x21;
if (c >= 84 || d >= 94) goto ilseq;
c = jis0208[c][d];
if (!c) goto ilseq;
break;
case 4:
if (c-0x60 < 0x1f) goto ilseq;
if (c-0x21 < 0x5e) c += 0xff61-0x21;
break;
}
break;
case GB2312:
if (c < 128) break;
if (c < 0xa1) goto ilseq;
case GBK:
if (c == 128) {
c = 0x20ac;
break;
}
case GB18030:
if (c < 128) break;
c -= 0x81;
if (c >= 126) goto ilseq;
l = 2;
if (*inb < 2) goto starved;
d = *((unsigned char *)*in + 1);
if (d < 0xa1 && type == GB2312) goto ilseq;
if (d-0x40>=191 || d==127) {
if (d-'0'>9 || type != GB18030)
goto ilseq;
l = 4;
if (*inb < 4) goto starved;
c = (10*c + d-'0') * 1260;
d = *((unsigned char *)*in + 2);
if (d-0x81>126) goto ilseq;
c += 10*(d-0x81);
d = *((unsigned char *)*in + 3);
if (d-'0'>9) goto ilseq;
c += d-'0';
c += 128;
for (d=0; d<=c; ) {
k = 0;
for (int i=0; i<126; i++)
for (int j=0; j<190; j++)
if (gb18030[i][j]-d <= c-d)
k++;
d = c+1;
c += k;
}
break;
}
d -= 0x40;
if (d>63) d--;
c = gb18030[c][d];
break;
case BIG5:
if (c < 128) break;
l = 2;
if (*inb < 2) goto starved;
d = *((unsigned char *)*in + 1);
if (d-0x40>=0xff-0x40 || d-0x7f<0xa1-0x7f) goto ilseq;
d -= 0x40;
if (d > 0x3e) d -= 0x22;
if (c-0xa1>=0xfa-0xa1) {
if (c-0x87>=0xff-0x87) goto ilseq;
if (c < 0xa1) c -= 0x87;
else c -= 0x87 + (0xfa-0xa1);
c = (hkscs[4867+(c*157+d)/16]>>(c*157+d)%16)%2<<17
| hkscs[c*157+d];
/* A few HKSCS characters map to pairs of UCS
* characters. These are mapped to surrogate
* range in the hkscs table then hard-coded
* here. Ugly, yes. */
if (c/256 == 0xdc) {
union {
char c[8];
wchar_t wc[2];
} tmp;
char *ptmp = tmp.c;
size_t tmpx = iconv(combine_to_from(to, find_charmap("utf8")),
&(char *){"\303\212\314\204"
"\303\212\314\214"
"\303\252\314\204"
"\303\252\314\214"
+c%256}, &(size_t){4},
&ptmp, &(size_t){sizeof tmp});
size_t tmplen = ptmp - tmp.c;
if (tmplen > *outb) goto toobig;
if (tmpx) x++;
memcpy(*out, &tmp, tmplen);
*out += tmplen;
*outb -= tmplen;
continue;
}
if (!c) goto ilseq;
break;
}
c -= 0xa1;
c = big5[c][d]|(c==0x27&&(d==0x3a||d==0x3c||d==0x42))<<17;
if (!c) goto ilseq;
break;
case EUC_KR:
if (c < 128) break;
l = 2;
if (*inb < 2) goto starved;
d = *((unsigned char *)*in + 1);
c -= 0xa1;
d -= 0xa1;
if (c >= 93 || d >= 94) {
c += (0xa1-0x81);
d += 0xa1;
if (c >= 93 || c>=0xc6-0x81 && d>0x52)
goto ilseq;
if (d-'A'<26) d = d-'A';
else if (d-'a'<26) d = d-'a'+26;
else if (d-0x81<0xff-0x81) d = d-0x81+52;
else goto ilseq;
if (c < 0x20) c = 178*c + d;
else c = 178*0x20 + 84*(c-0x20) + d;
c += 0xac00;
for (d=0xac00; d<=c; ) {
k = 0;
for (int i=0; i<93; i++)
for (int j=0; j<94; j++)
if (ksc[i][j]-d <= c-d)
k++;
d = c+1;
c += k;
}
break;
}
c = ksc[c][d];
if (!c) goto ilseq;
break;
default:
if (!c) break;
c = legacy_map(map, c);
if (!c) goto ilseq;
}
switch (totype) {
case WCHAR_T:
if (*outb < sizeof(wchar_t)) goto toobig;
*(wchar_t *)*out = c;
*out += sizeof(wchar_t);
*outb -= sizeof(wchar_t);
break;
case UTF_8:
if (*outb < 4) {
char tmp[4];
k = wctomb_utf8(tmp, c);
if (*outb < k) goto toobig;
memcpy(*out, tmp, k);
} else k = wctomb_utf8(*out, c);
*out += k;
*outb -= k;
break;
case US_ASCII:
if (c > 0x7f) subst: x++, c='*';
default:
if (*outb < 1) goto toobig;
if (c<256 && c==legacy_map(tomap, c)) {
revout:
if (*outb < 1) goto toobig;
*(*out)++ = c;
*outb -= 1;
break;
}
d = c;
for (c=4*totype; c<256; c++) {
if (d == legacy_map(tomap, c)) {
goto revout;
}
}
goto subst;
case SHIFT_JIS:
if (c < 128) goto revout;
if (c == 0xa5) {
x++;
c = '\\';
goto revout;
}
if (c == 0x203e) {
x++;
c = '~';
goto revout;
}
if (c-0xff61 <= 0xdf-0xa1) {
c += 0xa1 - 0xff61;
goto revout;
}
c = uni_to_jis(c);
if (!c) goto subst;
if (*outb < 2) goto toobig;
d = c%256;
c = c/256;
*(*out)++ = (c+1)/2 + (c<95 ? 112 : 176);
*(*out)++ = c%2 ? d + 31 + d/96 : d + 126;
*outb -= 2;
break;
case EUC_JP:
if (c < 128) goto revout;
if (c-0xff61 <= 0xdf-0xa1) {
c += 0x0e00 + 0x21 - 0xff61;
} else {
c = uni_to_jis(c);
}
if (!c) goto subst;
if (*outb < 2) goto toobig;
*(*out)++ = c/256 + 0x80;
*(*out)++ = c%256 + 0x80;
*outb -= 2;
break;
case ISO2022_JP:
if (c < 128) goto revout;
if (c-0xff61 <= 0xdf-0xa1 || c==0xa5 || c==0x203e) {
if (*outb < 7) goto toobig;
*(*out)++ = '\033';
*(*out)++ = '(';
if (c==0xa5) {
*(*out)++ = 'J';
*(*out)++ = '\\';
} else if (c==0x203e) {
*(*out)++ = 'J';
*(*out)++ = '~';
} else {
*(*out)++ = 'I';
*(*out)++ = c-0xff61+0x21;
}
*(*out)++ = '\033';
*(*out)++ = '(';
*(*out)++ = 'B';
*outb -= 7;
break;
}
c = uni_to_jis(c);
if (!c) goto subst;
if (*outb < 8) goto toobig;
*(*out)++ = '\033';
*(*out)++ = '$';
*(*out)++ = 'B';
*(*out)++ = c/256;
*(*out)++ = c%256;
*(*out)++ = '\033';
*(*out)++ = '(';
*(*out)++ = 'B';
*outb -= 8;
break;
case UCS2:
totype = UCS2BE;
case UCS2BE:
case UCS2LE:
case UTF_16:
case UTF_16BE:
case UTF_16LE:
if (c < 0x10000 || totype-UCS2BE < 2U) {
if (c >= 0x10000) c = 0xFFFD;
if (*outb < 2) goto toobig;
put_16((void *)*out, c, totype);
*out += 2;
*outb -= 2;
break;
}
if (*outb < 4) goto toobig;
c -= 0x10000;
put_16((void *)*out, (c>>10)|0xd800, totype);
put_16((void *)(*out + 2), (c&0x3ff)|0xdc00, totype);
*out += 4;
*outb -= 4;
break;
case UTF_32:
totype = UTF_32BE;
case UTF_32BE:
case UTF_32LE:
if (*outb < 4) goto toobig;
put_32((void *)*out, c, totype);
*out += 4;
*outb -= 4;
break;
}
}
*ploc = loc;
return x;
ilseq:
err = EILSEQ;
x = -1;
goto end;
toobig:
err = E2BIG;
x = -1;
goto end;
starved:
err = EINVAL;
x = -1;
end:
errno = err;
*ploc = loc;
return x;
}

99
third_party/musl/langinfo.c vendored Normal file
View file

@ -0,0 +1,99 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <locale.h>
#include <langinfo.h>
#include "libc/intrin/kprintf.h"
#include "libc/str/locale.internal.h"
__static_yoink("musl_libc_notice");
static const char c_time[] =
"Sun\0" "Mon\0" "Tue\0" "Wed\0" "Thu\0" "Fri\0" "Sat\0"
"Sunday\0" "Monday\0" "Tuesday\0" "Wednesday\0"
"Thursday\0" "Friday\0" "Saturday\0"
"Jan\0" "Feb\0" "Mar\0" "Apr\0" "May\0" "Jun\0"
"Jul\0" "Aug\0" "Sep\0" "Oct\0" "Nov\0" "Dec\0"
"January\0" "February\0" "March\0" "April\0"
"May\0" "June\0" "July\0" "August\0"
"September\0" "October\0" "November\0" "December\0"
"AM\0" "PM\0"
"%a %b %e %T %Y\0"
"%m/%d/%y\0"
"%H:%M:%S\0"
"%I:%M:%S %p\0"
"\0"
"\0"
"%m/%d/%y\0"
"0123456789\0"
"%a %b %e %T %Y\0"
"%H:%M:%S";
static const char c_messages[] = "^[yY]\0" "^[nN]\0" "yes\0" "no";
static const char c_numeric[] = ".\0" "";
char *nl_langinfo_l(nl_item item, locale_t loc)
{
int cat = item >> 16;
int idx = item & 65535;
const char *str;
if (item == CODESET) return loc->cat[LC_CTYPE] ? "UTF-8" : "ASCII";
/* _NL_LOCALE_NAME extension */
if (idx == 65535 && cat < LC_ALL)
return loc->cat[cat] ? (char *)loc->cat[cat]->name : "C";
switch (cat) {
case LC_NUMERIC:
if (idx > 1) return "";
str = c_numeric;
break;
case LC_TIME:
if (idx > 0x31) return "";
str = c_time;
break;
case LC_MONETARY:
if (idx > 0) return "";
str = "";
break;
case LC_MESSAGES:
if (idx > 3) return "";
str = c_messages;
break;
default:
return "";
}
for (; idx; idx--, str++) for (; *str; str++);
if (cat != LC_NUMERIC && *str) str = LCTRANS(str, cat, loc);
return (char *)str;
}
char *nl_langinfo(nl_item item)
{
return nl_langinfo_l(item, CURRENT_LOCALE);
}

46
third_party/musl/lctrans.c vendored Normal file
View file

@ -0,0 +1,46 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/str/locale.internal.h"
__static_yoink("musl_libc_notice");
const char *__lctrans_dummy(const char *msg, const struct __locale_map *lm)
{
return msg;
}
__weak_reference(__lctrans_dummy, __lctrans_impl);
const char *__lctrans(const char *msg, const struct __locale_map *lm)
{
return __lctrans_impl(msg, lm);
}
const char *__lctrans_cur(const char *msg)
{
return __lctrans_impl(msg, CURRENT_LOCALE->cat[LC_MESSAGES]);
}

137
third_party/musl/locale_map.c vendored Normal file
View file

@ -0,0 +1,137 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/str/str.h"
#include "libc/calls/calls.h"
#include "third_party/musl/mapfile.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/locale.internal.h"
__static_yoink("musl_libc_notice");
#define malloc _mapanon
#define calloc undef
#define realloc undef
#define free undef
#pragma GCC diagnostic ignored "-Wparentheses"
const char *__lctrans_impl(const char *msg, const struct __locale_map *lm)
{
const char *trans = 0;
if (lm) trans = __mo_lookup(lm->map, lm->map_size, msg);
return trans ? trans : msg;
}
static const char envvars[][12] = {
"LC_CTYPE",
"LC_NUMERIC",
"LC_TIME",
"LC_COLLATE",
"LC_MONETARY",
"LC_MESSAGES",
};
const struct __locale_map *__get_locale(int cat, const char *val)
{
static void *volatile loc_head;
const struct __locale_map *p;
struct __locale_map *new = 0;
const char *path = 0, *z;
char buf[256];
size_t l, n;
if (!*val) {
(val = getenv("LC_ALL")) && *val ||
(val = getenv(envvars[cat])) && *val ||
(val = getenv("LANG")) && *val ||
(val = "C.UTF-8");
}
/* Limit name length and forbid leading dot or any slashes. */
for (n=0; n<LOCALE_NAME_MAX && val[n] && val[n]!='/'; n++);
if (val[0]=='.' || val[n]) val = "C.UTF-8";
int builtin = (val[0]=='C' && !val[1])
|| !strcmp(val, "C.UTF-8")
|| !strcmp(val, "POSIX");
if (builtin) {
if (cat == LC_CTYPE && val[1]=='.')
return (void *)&__c_dot_utf8;
return 0;
}
for (p=loc_head; p; p=p->next)
if (!strcmp(val, p->name)) return p;
path = secure_getenv("MUSL_LOCPATH");
/* FIXME: add a default path? */
if (path) for (; *path; path=z+!!*z) {
z = strchrnul(path, ':');
l = z - path;
if (l >= sizeof buf - n - 2) continue;
memcpy(buf, path, l);
buf[l] = '/';
memcpy(buf+l+1, val, n);
buf[l+1+n] = 0;
size_t map_size;
const void *map = __map_file(buf, &map_size);
if (map) {
new = malloc(sizeof *new);
if (!new) {
munmap((void *)map, map_size);
break;
}
new->map = map;
new->map_size = map_size;
memcpy(new->name, val, n);
new->name[n] = 0;
new->next = loc_head;
loc_head = new;
break;
}
}
/* If no locale definition was found, make a locale map
* object anyway to store the name, which is kept for the
* sake of being able to do message translations at the
* application level. */
if (!new && (new = malloc(sizeof *new))) {
new->map = __c_dot_utf8.map;
new->map_size = __c_dot_utf8.map_size;
memcpy(new->name, val, n);
new->name[n] = 0;
new->next = loc_head;
loc_head = new;
}
/* For LC_CTYPE, never return a null pointer unless the
* requested name was "C" or "POSIX". */
if (!new && cat == LC_CTYPE) new = (void *)&__c_dot_utf8;
return new;
}

34
third_party/musl/mblen.c vendored Normal file
View file

@ -0,0 +1,34 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
__static_yoink("musl_libc_notice");
int mblen(const char *s, size_t n)
{
return mbtowc(0, s, n);
}

35
third_party/musl/mbrlen.c vendored Normal file
View file

@ -0,0 +1,35 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <wchar.h>
__static_yoink("musl_libc_notice");
size_t mbrlen(const char *restrict s, size_t n, mbstate_t *restrict st)
{
static unsigned internal;
return mbrtowc(0, s, n, st ? st : (mbstate_t *)&internal);
}

58
third_party/musl/mbrtoc16.c vendored Normal file
View file

@ -0,0 +1,58 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <uchar.h>
#include <wchar.h>
__static_yoink("musl_libc_notice");
size_t mbrtoc16(char16_t *restrict pc16, const char *restrict s, size_t n, mbstate_t *restrict ps)
{
static unsigned internal_state;
if (!ps) ps = (void *)&internal_state;
unsigned *pending = (unsigned *)ps;
if (!s) return mbrtoc16(0, "", 1, ps);
/* mbrtowc states for partial UTF-8 characters have the high bit set;
* we use nonzero states without high bit for pending surrogates. */
if ((int)*pending > 0) {
if (pc16) *pc16 = *pending;
*pending = 0;
return -3;
}
wchar_t wc;
size_t ret = mbrtowc(&wc, s, n, ps);
if (ret <= 4) {
if (wc >= 0x10000) {
*pending = (wc & 0x3ff) + 0xdc00;
wc = 0xd7c0 + (wc >> 10);
}
if (pc16) *pc16 = wc;
}
return ret;
}

41
third_party/musl/mbrtoc32.c vendored Normal file
View file

@ -0,0 +1,41 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <uchar.h>
#include <wchar.h>
__static_yoink("musl_libc_notice");
size_t mbrtoc32(char32_t *restrict pc32, const char *restrict s, size_t n, mbstate_t *restrict ps)
{
static unsigned internal_state;
if (!ps) ps = (void *)&internal_state;
if (!s) return mbrtoc32(0, "", 1, ps);
wchar_t wc;
size_t ret = mbrtowc(&wc, s, n, ps);
if (ret <= 4 && pc32) *pc32 = wc;
return ret;
}

81
third_party/musl/mbrtowc.c vendored Normal file
View file

@ -0,0 +1,81 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <wchar.h>
#include <errno.h>
#include "multibyte.h"
__static_yoink("musl_libc_notice");
#pragma GCC diagnostic ignored "-Wparentheses"
size_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate_t *restrict st)
{
static unsigned internal_state;
unsigned c;
const unsigned char *s = (const void *)src;
const size_t N = n;
wchar_t dummy;
if (!st) st = (void *)&internal_state;
c = *(unsigned *)st;
if (!s) {
if (c) goto ilseq;
return 0;
} else if (!wc) wc = &dummy;
if (!n) return -2;
if (!c) {
if (*s < 0x80) return !!(*wc = *s);
if (MB_CUR_MAX==1) return (*wc = CODEUNIT(*s)), 1;
if (*s-SA > SB-SA) goto ilseq;
c = bittab[*s++-SA]; n--;
}
if (n) {
if (OOB(c,*s)) goto ilseq;
loop:
c = c<<6 | *s++-0x80; n--;
if (!(c&(1U<<31))) {
*(unsigned *)st = 0;
*wc = c;
return N-n;
}
if (n) {
if (*s-0x80u >= 0x40) goto ilseq;
goto loop;
}
}
*(unsigned *)st = c;
return -2;
ilseq:
*(unsigned *)st = 0;
errno = EILSEQ;
return -1;
}

34
third_party/musl/mbsinit.c vendored Normal file
View file

@ -0,0 +1,34 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <wchar.h>
__static_yoink("musl_libc_notice");
int mbsinit(const mbstate_t *st)
{
return !st || !*(unsigned *)st;
}

83
third_party/musl/mbsnrtowcs.c vendored Normal file
View file

@ -0,0 +1,83 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <wchar.h>
__static_yoink("musl_libc_notice");
size_t mbsnrtowcs(wchar_t *restrict wcs, const char **restrict src, size_t n, size_t wn, mbstate_t *restrict st)
{
size_t l, cnt=0, n2;
wchar_t *ws, wbuf[256];
const char *s = *src;
const char *tmp_s;
if (!wcs) ws = wbuf, wn = sizeof wbuf / sizeof *wbuf;
else ws = wcs;
/* making sure output buffer size is at most n/4 will ensure
* that mbsrtowcs never reads more than n input bytes. thus
* we can use mbsrtowcs as long as it's practical.. */
while ( s && wn && ( (n2=n/4)>=wn || n2>32 ) ) {
if (n2>=wn) n2=wn;
tmp_s = s;
l = mbsrtowcs(ws, &s, n2, st);
if (!(l+1)) {
cnt = l;
wn = 0;
break;
}
if (ws != wbuf) {
ws += l;
wn -= l;
}
n = s ? n - (s - tmp_s) : 0;
cnt += l;
}
if (s) while (wn && n) {
l = mbrtowc(ws, s, n, st);
if (l+2<=2) {
if (!(l+1)) {
cnt = l;
break;
}
if (!l) {
s = 0;
break;
}
/* have to roll back partial character */
*(unsigned *)st = 0;
break;
}
s += l; n -= l;
/* safe - this loop runs fewer than sizeof(wbuf)/8 times */
ws++; wn--;
cnt++;
}
if (wcs) *src = s;
return cnt;
}

150
third_party/musl/mbsrtowcs.c vendored Normal file
View file

@ -0,0 +1,150 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdint.h>
#include <wchar.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include "multibyte.h"
__static_yoink("musl_libc_notice");
#pragma GCC diagnostic ignored "-Wparentheses"
size_t mbsrtowcs(wchar_t *restrict ws, const char **restrict src, size_t wn, mbstate_t *restrict st)
{
const unsigned char *s = (const void *)*src;
size_t wn0 = wn;
unsigned c = 0;
if (st && (c = *(unsigned *)st)) {
if (ws) {
*(unsigned *)st = 0;
goto resume;
} else {
goto resume0;
}
}
if (MB_CUR_MAX==1) {
if (!ws) return strlen((const char *)s);
for (;;) {
if (!wn) {
*src = (const void *)s;
return wn0;
}
if (!*s) break;
c = *s++;
*ws++ = CODEUNIT(c);
wn--;
}
*ws = 0;
*src = 0;
return wn0-wn;
}
if (!ws) for (;;) {
#ifdef __GNUC__
typedef uint32_t __attribute__((__may_alias__)) w32;
if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) {
while (!(( *(w32*)s | *(w32*)s-0x01010101) & 0x80808080)) {
s += 4;
wn -= 4;
}
}
#endif
if (*s-1u < 0x7f) {
s++;
wn--;
continue;
}
if (*s-SA > SB-SA) break;
c = bittab[*s++-SA];
resume0:
if (OOB(c,*s)) { s--; break; }
s++;
if (c&(1U<<25)) {
if (*s-0x80u >= 0x40) { s-=2; break; }
s++;
if (c&(1U<<19)) {
if (*s-0x80u >= 0x40) { s-=3; break; }
s++;
}
}
wn--;
c = 0;
} else for (;;) {
if (!wn) {
*src = (const void *)s;
return wn0;
}
#ifdef __GNUC__
typedef uint32_t __attribute__((__may_alias__)) w32;
if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) {
while (wn>=5 && !(( *(w32*)s | *(w32*)s-0x01010101) & 0x80808080)) {
*ws++ = *s++;
*ws++ = *s++;
*ws++ = *s++;
*ws++ = *s++;
wn -= 4;
}
}
#endif
if (*s-1u < 0x7f) {
*ws++ = *s++;
wn--;
continue;
}
if (*s-SA > SB-SA) break;
c = bittab[*s++-SA];
resume:
if (OOB(c,*s)) { s--; break; }
c = (c<<6) | *s++-0x80;
if (c&(1U<<31)) {
if (*s-0x80u >= 0x40) { s-=2; break; }
c = (c<<6) | *s++-0x80;
if (c&(1U<<31)) {
if (*s-0x80u >= 0x40) { s-=3; break; }
c = (c<<6) | *s++-0x80;
}
}
*ws++ = c;
wn--;
c = 0;
}
if (!c && !*s) {
if (ws) {
*ws = 0;
*src = 0;
}
return wn0-wn;
}
errno = EILSEQ;
if (ws) *src = (const void *)s;
return -1;
}

35
third_party/musl/mbstowcs.c vendored Normal file
View file

@ -0,0 +1,35 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <wchar.h>
__static_yoink("musl_libc_notice");
size_t mbstowcs(wchar_t *restrict ws, const char *restrict s, size_t wn)
{
return mbsrtowcs(ws, (void*)&s, wn, 0);
}

77
third_party/musl/mbtowc.c vendored Normal file
View file

@ -0,0 +1,77 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <wchar.h>
#include <errno.h>
#include "multibyte.h"
__static_yoink("musl_libc_notice");
#pragma GCC diagnostic ignored "-Wparentheses"
int mbtowc(wchar_t *restrict wc, const char *restrict src, size_t n)
{
unsigned c;
const unsigned char *s = (const void *)src;
wchar_t dummy;
if (!s) return 0;
if (!n) goto ilseq;
if (!wc) wc = &dummy;
if (*s < 0x80) return !!(*wc = *s);
if (MB_CUR_MAX==1) return (*wc = CODEUNIT(*s)), 1;
if (*s-SA > SB-SA) goto ilseq;
c = bittab[*s++-SA];
/* Avoid excessive checks against n: If shifting the state n-1
* times does not clear the high bit, then the value of n is
* insufficient to read a character */
if (n<4 && ((c<<(6*n-6)) & (1U<<31))) goto ilseq;
if (OOB(c,*s)) goto ilseq;
c = c<<6 | *s++-0x80;
if (!(c&(1U<<31))) {
*wc = c;
return 2;
}
if (*s-0x80u >= 0x40) goto ilseq;
c = c<<6 | *s++-0x80;
if (!(c&(1U<<31))) {
*wc = c;
return 3;
}
if (*s-0x80u >= 0x40) goto ilseq;
*wc = c<<6 | *s++-0x80;
return 4;
ilseq:
errno = EILSEQ;
return -1;
}

53
third_party/musl/multibyte.c vendored Normal file
View file

@ -0,0 +1,53 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "multibyte.h"
#define C(x) ( x<2 ? -1 : ( R(0x80,0xc0) | x ) )
#define D(x) C((x+16))
#define E(x) ( ( x==0 ? R(0xa0,0xc0) : \
x==0xd ? R(0x80,0xa0) : \
R(0x80,0xc0) ) \
| ( R(0x80,0xc0) >> 6 ) \
| x )
#define F(x) ( ( x>=5 ? 0 : \
x==0 ? R(0x90,0xc0) : \
x==4 ? R(0x80,0x90) : \
R(0x80,0xc0) ) \
| ( R(0x80,0xc0) >> 6 ) \
| ( R(0x80,0xc0) >> 12 ) \
| x )
const uint32_t bittab[] = {
C(0x2),C(0x3),C(0x4),C(0x5),C(0x6),C(0x7),
C(0x8),C(0x9),C(0xa),C(0xb),C(0xc),C(0xd),C(0xe),C(0xf),
D(0x0),D(0x1),D(0x2),D(0x3),D(0x4),D(0x5),D(0x6),D(0x7),
D(0x8),D(0x9),D(0xa),D(0xb),D(0xc),D(0xd),D(0xe),D(0xf),
E(0x0),E(0x1),E(0x2),E(0x3),E(0x4),E(0x5),E(0x6),E(0x7),
E(0x8),E(0x9),E(0xa),E(0xb),E(0xc),E(0xd),E(0xe),E(0xf),
F(0x0),F(0x1),F(0x2),F(0x3),F(0x4)
};

26
third_party/musl/multibyte.h vendored Normal file
View file

@ -0,0 +1,26 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_MUSL_MULTIBYTE_H_
#define COSMOPOLITAN_THIRD_PARTY_MUSL_MULTIBYTE_H_
#define bittab __fsmu8
extern const uint32_t bittab[];
/* Upper 6 state bits are a negative integer offset to bound-check next byte */
/* equivalent to: ( (b-0x80) | (b+offset) ) & ~0x3f */
#define OOB(c,b) (((((b)>>3)-0x10)|(((b)>>3)+((int32_t)(c)>>26))) & ~7)
/* Interval [a,b). Either a must be 80 or b must be c0, lower 3 bits clear. */
#define R(a,b) ((uint32_t)((a==0x80 ? 0x40u-b : 0u-a) << 23))
#define FAILSTATE R(0x80,0x80)
#define SA 0xc2u
#define SB 0xf4u
/* Arbitrary encoding for representing code units instead of characters. */
#define CODEUNIT(c) (0xdfff & (signed char)(c))
#define IS_CODEUNIT(c) ((unsigned)(c)-0xdf80 < 0x80)
/* Get inline definition of MB_CUR_MAX. */
#include "libc/str/locale.internal.h"
#endif /* COSMOPOLITAN_THIRD_PARTY_MUSL_MULTIBYTE_H_ */

94
third_party/musl/newlocale.c vendored Normal file
View file

@ -0,0 +1,94 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/str/locale.internal.h"
__static_yoink("musl_libc_notice");
#define malloc _mapanon
#define calloc undef
#define realloc undef
#define free undef
static int default_locale_init_done;
static struct __locale_struct default_locale, default_ctype_locale;
int __loc_is_allocated(locale_t loc)
{
return loc && loc != C_LOCALE && loc != UTF8_LOCALE
&& loc != &default_locale && loc != &default_ctype_locale;
}
static locale_t do_newlocale(int mask, const char *name, locale_t loc)
{
struct __locale_struct tmp;
for (int i=0; i<LC_ALL; i++) {
tmp.cat[i] = (!(mask & (1<<i)) && loc) ? loc->cat[i] :
__get_locale(i, (mask & (1<<i)) ? name : "");
if (tmp.cat[i] == LOC_MAP_FAILED)
return 0;
}
/* For locales with allocated storage, modify in-place. */
if (__loc_is_allocated(loc)) {
*loc = tmp;
return loc;
}
/* Otherwise, first see if we can use one of the builtin locales.
* This makes the common usage case for newlocale, getting a C locale
* with predictable behavior, very fast, and more importantly, fail-safe. */
if (!memcmp(&tmp, C_LOCALE, sizeof tmp)) return C_LOCALE;
if (!memcmp(&tmp, UTF8_LOCALE, sizeof tmp)) return UTF8_LOCALE;
/* And provide builtins for the initial default locale, and a
* variant of the C locale honoring the default locale's encoding. */
if (!default_locale_init_done) {
for (int i=0; i<LC_ALL; i++)
default_locale.cat[i] = __get_locale(i, "");
default_ctype_locale.cat[LC_CTYPE] = default_locale.cat[LC_CTYPE];
default_locale_init_done = 1;
}
if (!memcmp(&tmp, &default_locale, sizeof tmp)) return &default_locale;
if (!memcmp(&tmp, &default_ctype_locale, sizeof tmp))
return &default_ctype_locale;
/* If no builtin locale matched, attempt to allocate and copy. */
if ((loc = malloc(sizeof *loc))) *loc = tmp;
return loc;
}
locale_t newlocale(int mask, const char *name, locale_t loc)
{
pthread_mutex_lock(&__locale_lock);
loc = do_newlocale(mask, name, loc);
pthread_mutex_unlock(&__locale_lock);
return loc;
}

102
third_party/musl/setlocale.c vendored Normal file
View file

@ -0,0 +1,102 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/str/str.h"
#include "libc/str/locale.internal.h"
__static_yoink("musl_libc_notice");
static char buf[LC_ALL*(LOCALE_NAME_MAX+1)];
char *setlocale(int cat, const char *name)
{
const struct __locale_map *lm;
if ((unsigned)cat > LC_ALL) return 0;
pthread_mutex_lock(&__locale_lock);
/* For LC_ALL, setlocale is required to return a string which
* encodes the current setting for all categories. The format of
* this string is unspecified, and only the following code, which
* performs both the serialization and deserialization, depends
* on the format, so it can easily be changed if needed. */
if (cat == LC_ALL) {
int i;
if (name) {
struct __locale_struct tmp_locale;
char part[LOCALE_NAME_MAX+1] = "C.UTF-8";
const char *p = name;
for (i=0; i<LC_ALL; i++) {
const char *z = strchrnul(p, ';');
if (z-p <= LOCALE_NAME_MAX) {
memcpy(part, p, z-p);
part[z-p] = 0;
if (*z) p = z+1;
}
lm = __get_locale(i, part);
if (lm == LOC_MAP_FAILED) {
pthread_mutex_unlock(&__locale_lock);
return 0;
}
tmp_locale.cat[i] = lm;
}
__global_locale = tmp_locale;
}
char *s = buf;
const char *part;
int same = 0;
for (i=0; i<LC_ALL; i++) {
const struct __locale_map *lm =
__global_locale.cat[i];
if (lm == __global_locale.cat[0]) same++;
part = lm ? lm->name : "C";
size_t l = strlen(part);
memcpy(s, part, l);
s[l] = ';';
s += l+1;
}
*--s = 0;
pthread_mutex_unlock(&__locale_lock);
return same==LC_ALL ? (char *)part : buf;
}
if (name) {
lm = __get_locale(cat, name);
if (lm == LOC_MAP_FAILED) {
pthread_mutex_unlock(&__locale_lock);
return 0;
}
__global_locale.cat[cat] = lm;
} else {
lm = __global_locale.cat[cat];
}
char *ret = lm ? (char *)lm->name : "C";
pthread_mutex_unlock(&__locale_lock);
return ret;
}

View file

@ -27,7 +27,7 @@
*/
#include "libc/errno.h"
#include "libc/stdio/stdio.h"
#include "libc/str/locale.h"
#include "libc/str/locale.internal.h"
#include "libc/str/str.h"
#include "libc/ctype.h"
#include "libc/thread/tls.h"
@ -37,7 +37,7 @@ static ssize_t vstrfmon_l(char *s, size_t n, locale_t loc, const char *fmt, va_l
{
size_t l;
double x;
int left;
int fill, nogrp, negpar, nosym, left, intl;
int lp, rp, w, fw;
char *s0=s;
for (; n && *fmt; ) {
@ -50,17 +50,29 @@ static ssize_t vstrfmon_l(char *s, size_t n, locale_t loc, const char *fmt, va_l
fmt++;
if (*fmt == '%') goto literal;
fill = ' ';
nogrp = 0;
negpar = 0;
nosym = 0;
left = 0;
for (; ; fmt++) {
switch (*fmt) {
case '=':
fill = *++fmt;
(void)fill;
continue;
case '^':
nogrp = 1;
(void)nogrp;
continue;
case '(':
negpar = 1;
(void)negpar;
case '+':
continue;
case '!':
nosym = 1;
(void)nosym;
continue;
case '-':
left = 1;
@ -78,6 +90,9 @@ static ssize_t vstrfmon_l(char *s, size_t n, locale_t loc, const char *fmt, va_l
if (*fmt=='.') for (rp=0, fmt++; isdigit(*fmt); fmt++)
rp = 10*rp + (*fmt-'0');
intl = *fmt++ == 'i';
(void)intl;
w = lp + 1 + rp;
if (!left && fw>w) w = fw;
@ -112,7 +127,7 @@ ssize_t strfmon(char *restrict s, size_t n, const char *restrict fmt, ...)
ssize_t ret;
va_start(ap, fmt);
ret = vstrfmon_l(s, n, (locale_t)__get_tls()->tib_locale, fmt, ap);
ret = vstrfmon_l(s, n, CURRENT_LOCALE, fmt, ap);
va_end(ap);
return ret;

313
third_party/musl/strftime.c vendored Normal file
View file

@ -0,0 +1,313 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/ctype.h"
#include "libc/limits.h"
#include "libc/stdio/stdio.h"
#include "libc/str/langinfo.h"
#include "libc/str/locale.h"
#include "libc/str/locale.internal.h"
#include "libc/str/nltypes.h"
#include "libc/str/str.h"
#include "libc/time.h"
#include "third_party/musl/time_impl.h"
__static_yoink("musl_libc_notice");
static int is_leap(int y)
{
/* Avoid overflow */
if (y>INT_MAX-1900) y -= 2000;
y += 1900;
return !(y%4) && ((y%100) || !(y%400));
}
static int week_num(const struct tm *tm)
{
int val = (tm->tm_yday + 7U - (tm->tm_wday+6U)%7) / 7;
/* If 1 Jan is just 1-3 days past Monday,
* the previous week is also in this year. */
if ((tm->tm_wday + 371U - tm->tm_yday - 2) % 7 <= 2)
val++;
if (!val) {
val = 52;
/* If 31 December of prev year a Thursday,
* or Friday of a leap year, then the
* prev year has 53 weeks. */
int dec31 = (tm->tm_wday + 7U - tm->tm_yday - 1) % 7;
if (dec31 == 4 || (dec31 == 5 && is_leap(tm->tm_year%400-1)))
val++;
} else if (val == 53) {
/* If 1 January is not a Thursday, and not
* a Wednesday of a leap year, then this
* year has only 52 weeks. */
int jan1 = (tm->tm_wday + 371U - tm->tm_yday) % 7;
if (jan1 != 4 && (jan1 != 3 || !is_leap(tm->tm_year)))
val = 1;
}
return val;
}
const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc, int pad)
{
nl_item item;
long long val;
const char *fmt = "-";
int width = 2, def_pad = '0';
switch (f) {
case 'a':
if (tm->tm_wday > 6U) goto string;
item = ABDAY_1 + tm->tm_wday;
goto nl_strcat;
case 'A':
if (tm->tm_wday > 6U) goto string;
item = DAY_1 + tm->tm_wday;
goto nl_strcat;
case 'h':
case 'b':
if (tm->tm_mon > 11U) goto string;
item = ABMON_1 + tm->tm_mon;
goto nl_strcat;
case 'B':
if (tm->tm_mon > 11U) goto string;
item = MON_1 + tm->tm_mon;
goto nl_strcat;
case 'c':
item = D_T_FMT;
goto nl_strftime;
case 'C':
val = (1900LL+tm->tm_year) / 100;
goto number;
case 'e':
def_pad = '_';
case 'd':
val = tm->tm_mday;
goto number;
case 'D':
fmt = "%m/%d/%y";
goto recu_strftime;
case 'F':
fmt = "%Y-%m-%d";
goto recu_strftime;
case 'g':
case 'G':
val = tm->tm_year + 1900LL;
if (tm->tm_yday < 3 && week_num(tm) != 1) val--;
else if (tm->tm_yday > 360 && week_num(tm) == 1) val++;
if (f=='g') val %= 100;
else width = 4;
goto number;
case 'H':
val = tm->tm_hour;
goto number;
case 'I':
val = tm->tm_hour;
if (!val) val = 12;
else if (val > 12) val -= 12;
goto number;
case 'j':
val = tm->tm_yday+1;
width = 3;
goto number;
case 'm':
val = tm->tm_mon+1;
goto number;
case 'M':
val = tm->tm_min;
goto number;
case 'n':
*l = 1;
return "\n";
case 'p':
item = tm->tm_hour >= 12 ? PM_STR : AM_STR;
goto nl_strcat;
case 'r':
item = T_FMT_AMPM;
goto nl_strftime;
case 'R':
fmt = "%H:%M";
goto recu_strftime;
case 's':
val = __tm_to_secs(tm) - tm->tm_gmtoff;
width = 1;
goto number;
case 'S':
val = tm->tm_sec;
goto number;
case 't':
*l = 1;
return "\t";
case 'T':
fmt = "%H:%M:%S";
goto recu_strftime;
case 'u':
val = tm->tm_wday ? tm->tm_wday : 7;
width = 1;
goto number;
case 'U':
val = (tm->tm_yday + 7U - tm->tm_wday) / 7;
goto number;
case 'W':
val = (tm->tm_yday + 7U - (tm->tm_wday+6U)%7) / 7;
goto number;
case 'V':
val = week_num(tm);
goto number;
case 'w':
val = tm->tm_wday;
width = 1;
goto number;
case 'x':
item = D_FMT;
goto nl_strftime;
case 'X':
item = T_FMT;
goto nl_strftime;
case 'y':
val = (tm->tm_year + 1900LL) % 100;
if (val < 0) val = -val;
goto number;
case 'Y':
val = tm->tm_year + 1900LL;
if (val >= 10000) {
*l = snprintf(*s, sizeof *s, "%lld", val);
return *s;
}
width = 4;
goto number;
case 'z':
if (tm->tm_isdst < 0) {
*l = 0;
return "";
}
*l = snprintf(*s, sizeof *s, "%+.4ld",
tm->tm_gmtoff/3600*100 + tm->tm_gmtoff%3600/60);
return *s;
case 'Z':
if (tm->tm_isdst < 0 || !tm->tm_zone) {
*l = 0;
return "";
}
fmt = tm->tm_zone;
goto string;
case '%':
*l = 1;
return "%";
default:
return 0;
}
number:
switch (pad ? pad : def_pad) {
case '-': *l = snprintf(*s, sizeof *s, "%lld", val); break;
case '_': *l = snprintf(*s, sizeof *s, "%*lld", width, val); break;
case '0':
default: *l = snprintf(*s, sizeof *s, "%0*lld", width, val); break;
}
return *s;
nl_strcat:
fmt = nl_langinfo_l(item, loc);
string:
*l = strlen(fmt);
return fmt;
nl_strftime:
fmt = nl_langinfo_l(item, loc);
recu_strftime:
*l = strftime_l(*s, sizeof *s, fmt, tm, loc);
if (!*l) return 0;
return *s;
}
size_t strftime_l(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm, locale_t loc)
{
size_t l, k;
char buf[100];
char *p;
const char *t;
int pad, plus;
unsigned long width;
for (l=0; l<n; f++) {
if (!*f) {
s[l] = 0;
return l;
}
if (*f != '%') {
s[l++] = *f;
continue;
}
f++;
pad = 0;
if (*f == '-' || *f == '_' || *f == '0') pad = *f++;
if ((plus = (*f == '+'))) f++;
if (isdigit(*f)) {
width = strtoul(f, &p, 10);
} else {
width = 0;
p = (void *)f;
}
if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
if (!width && p!=f) width = 1;
} else {
width = 0;
}
f = p;
if (*f == 'E' || *f == 'O') f++;
t = __strftime_fmt_1(&buf, &k, *f, tm, loc, pad);
if (!t) break;
if (width) {
/* Trim off any sign and leading zeros, then
* count remaining digits to determine behavior
* for the + flag. */
if (*t=='+' || *t=='-') t++, k--;
for (; *t=='0' && t[1]-'0'<10U; t++, k--);
if (width < k) width = k;
size_t d;
for (d=0; t[d]-'0'<10U; d++);
if (tm->tm_year < -1900) {
s[l++] = '-';
width--;
} else if (plus && d+(width-k) >= (*p=='C'?3:5)) {
s[l++] = '+';
width--;
}
for (; width > k && l < n; width--)
s[l++] = '0';
}
if (k > n-l) k = n-l;
memcpy(s+l, t, k);
l += k;
}
if (n) {
if (l==n) l=n-1;
s[l] = 0;
}
return 0;
}
size_t strftime(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm)
{
return strftime_l(s, n, f, tm, CURRENT_LOCALE);
}

View file

@ -29,248 +29,269 @@
#include "libc/macros.internal.h"
#include "libc/str/str.h"
#include "libc/ctype.h"
#include "libc/str/langinfo.h"
#include "libc/time.h"
__static_yoink("musl_libc_notice");
char *
strptime(const char *s, const char *f, struct tm *tm)
char *strptime(const char *restrict s, const char *restrict f, struct tm *restrict tm)
{
int i, w, neg, adj, min, range, itemsize, *dest, dummy;
const char *ex, *ss;
int i, w, neg, adj, min, range, *dest, dummy;
const char *ex;
size_t len;
int want_century = 0, century = 0, relyear = 0;
while (*f) {
if (*f != '%') {
if (isspace(*f)) {
for (; *s && isspace(*s); s++);
} else if (*s != *f) {
return 0;
} else {
s++;
}
if (isspace(*f)) for (; *s && isspace(*s); s++);
else if (*s != *f) return 0;
else s++;
f++;
continue;
}
f++;
if (*f == '+')
f++;
if (*f == '+') f++;
if (isdigit(*f)) {
char *new_f;
w = strtoul(f, &new_f, 10);
w=strtoul(f, &new_f, 10);
f = new_f;
} else {
w = -1;
w=-1;
}
adj = 0;
adj=0;
switch (*f++) {
case 'a':
dest = &tm->tm_wday;
ss = (const char *)kWeekdayNameShort;
range = ARRAYLEN(kWeekdayNameShort);
itemsize = sizeof(kWeekdayNameShort[0]);
goto symbolic_range;
case 'A':
dest = &tm->tm_wday;
ss = (const char *)kWeekdayName;
range = ARRAYLEN(kWeekdayName);
itemsize = sizeof(kWeekdayName[0]);
goto symbolic_range;
case 'b':
case 'h':
dest = &tm->tm_mon;
ss = (const char *)kMonthNameShort;
range = ARRAYLEN(kMonthNameShort);
itemsize = sizeof(kMonthNameShort[0]);
goto symbolic_range;
case 'B':
dest = &tm->tm_mon;
ss = (const char *)kMonthName;
range = ARRAYLEN(kMonthName);
itemsize = sizeof(kMonthName[0]);
goto symbolic_range;
case 'c':
s = strptime(s, "%a %b %e %T %Y", tm);
if (!s)
return 0;
case 'a': case 'A':
dest = &tm->tm_wday;
min = ABDAY_1;
range = 7;
goto symbolic_range;
case 'b': case 'B': case 'h':
dest = &tm->tm_mon;
min = ABMON_1;
range = 12;
goto symbolic_range;
case 'c':
s = strptime(s, nl_langinfo(D_T_FMT), tm);
if (!s) return 0;
break;
case 'C':
dest = &century;
if (w<0) w=2;
want_century |= 2;
goto numeric_digits;
case 'd': case 'e':
dest = &tm->tm_mday;
min = 1;
range = 31;
goto numeric_range;
case 'D':
s = strptime(s, "%m/%d/%y", tm);
if (!s) return 0;
break;
case 'F':
/* Use temp buffer to implement the odd requirement
* that entire field be width-limited but the year
* subfield not itself be limited. */
i = 0;
char tmp[20];
if (*s == '-' || *s == '+') tmp[i++] = *s++;
while (*s=='0' && isdigit(s[1])) s++;
for (; *s && i<(size_t)w && i+1<sizeof tmp; i++) {
tmp[i] = *s++;
}
tmp[i] = 0;
char *p = strptime(tmp, "%12Y-%m-%d", tm);
if (!p) return 0;
s -= tmp+i-p;
break;
case 'H':
dest = &tm->tm_hour;
min = 0;
range = 24;
goto numeric_range;
case 'I':
dest = &tm->tm_hour;
min = 1;
range = 12;
goto numeric_range;
case 'j':
dest = &tm->tm_yday;
min = 1;
range = 366;
adj = 1;
goto numeric_range;
case 'm':
dest = &tm->tm_mon;
min = 1;
range = 12;
adj = 1;
goto numeric_range;
case 'M':
dest = &tm->tm_min;
min = 0;
range = 60;
goto numeric_range;
case 'n': case 't':
for (; *s && isspace(*s); s++);
break;
case 'p':
ex = nl_langinfo(AM_STR);
len = strlen(ex);
if (!strncasecmp(s, ex, len)) {
tm->tm_hour %= 12;
s += len;
break;
case 'C':
dest = &century;
if (w < 0)
w = 2;
want_century |= 2;
goto numeric_digits;
case 'd':
case 'e':
dest = &tm->tm_mday;
min = 1;
range = 31;
goto numeric_range;
case 'D':
s = strptime(s, "%m/%d/%y", tm);
if (!s)
return 0;
}
ex = nl_langinfo(PM_STR);
len = strlen(ex);
if (!strncasecmp(s, ex, len)) {
tm->tm_hour %= 12;
tm->tm_hour += 12;
s += len;
break;
case 'H':
dest = &tm->tm_hour;
min = 0;
range = 24;
goto numeric_range;
case 'I':
dest = &tm->tm_hour;
min = 1;
range = 12;
goto numeric_range;
case 'j':
dest = &tm->tm_yday;
min = 1;
range = 366;
adj = 1;
goto numeric_range;
case 'm':
dest = &tm->tm_mon;
min = 1;
range = 12;
adj = 1;
goto numeric_range;
case 'M':
dest = &tm->tm_min;
min = 0;
range = 60;
goto numeric_range;
case 'n':
case 't':
for (; *s && isspace(*s); s++);
break;
case 'p':
ex = "AM";
}
return 0;
case 'r':
s = strptime(s, nl_langinfo(T_FMT_AMPM), tm);
if (!s) return 0;
break;
case 'R':
s = strptime(s, "%H:%M", tm);
if (!s) return 0;
break;
case 's':
/* Parse only. Effect on tm is unspecified
* and presently no effect is implemented.. */
if (*s == '-') s++;
if (!isdigit(*s)) return 0;
while (isdigit(*s)) s++;
break;
case 'S':
dest = &tm->tm_sec;
min = 0;
range = 61;
goto numeric_range;
case 'T':
s = strptime(s, "%H:%M:%S", tm);
if (!s) return 0;
break;
case 'U':
case 'W':
/* Throw away result of %U, %V, %W, %g, and %G. Effect
* is unspecified and there is no clear right choice. */
dest = &dummy;
min = 0;
range = 54;
goto numeric_range;
case 'V':
dest = &dummy;
min = 1;
range = 53;
goto numeric_range;
case 'g':
dest = &dummy;
w = 2;
goto numeric_digits;
case 'G':
dest = &dummy;
if (w<0) w=4;
goto numeric_digits;
case 'u':
dest = &tm->tm_wday;
min = 1;
range = 7;
goto numeric_range;
case 'w':
dest = &tm->tm_wday;
min = 0;
range = 7;
goto numeric_range;
case 'x':
s = strptime(s, nl_langinfo(D_FMT), tm);
if (!s) return 0;
break;
case 'X':
s = strptime(s, nl_langinfo(T_FMT), tm);
if (!s) return 0;
break;
case 'y':
dest = &relyear;
w = 2;
want_century |= 1;
goto numeric_digits;
case 'Y':
dest = &tm->tm_year;
if (w<0) w=4;
adj = 1900;
want_century = 0;
goto numeric_digits;
case 'z':
if (*s == '+') neg = 0;
else if (*s == '-') neg = 1;
else return 0;
for (i=0; i<4; i++) if (!isdigit(s[1+i])) return 0;
tm->tm_gmtoff = (s[1]-'0')*36000+(s[2]-'0')*3600
+ (s[3]-'0')*600 + (s[4]-'0')*60;
if (neg) tm->tm_gmtoff = -tm->tm_gmtoff;
s += 5;
break;
case 'Z':
if (!strncmp(s, tzname[0], len = strlen(tzname[0]))) {
tm->tm_isdst = 0;
s += len;
} else if (!strncmp(s, tzname[1], len=strlen(tzname[1]))) {
tm->tm_isdst = 1;
s += len;
} else {
/* FIXME: is this supposed to be an error? */
while ((*s|32)-'a' <= 'z'-'a') s++;
}
break;
case '%':
if (*s++ != '%') return 0;
break;
default:
return 0;
numeric_range:
if (!isdigit(*s)) return 0;
*dest = 0;
for (i=1; i<=min+range && isdigit(*s); i*=10)
*dest = *dest * 10 + *s++ - '0';
if (*dest - min >= (unsigned)range) return 0;
*dest -= adj;
switch((char *)dest - (char *)tm) {
case offsetof(struct tm, tm_yday):
;
}
goto update;
numeric_digits:
neg = 0;
if (*s == '+') s++;
else if (*s == '-') neg=1, s++;
if (!isdigit(*s)) return 0;
for (*dest=i=0; i<w && isdigit(*s); i++)
*dest = *dest * 10 + *s++ - '0';
if (neg) *dest = -*dest;
*dest -= adj;
goto update;
symbolic_range:
for (i=2*range-1; i>=0; i--) {
ex = nl_langinfo(min+i);
len = strlen(ex);
if (!strncasecmp(s, ex, len)) {
tm->tm_hour %= 12;
s += len;
break;
}
ex = "PM";
len = strlen(ex);
if (!strncasecmp(s, ex, len)) {
tm->tm_hour %= 12;
tm->tm_hour += 12;
s += len;
break;
}
return 0;
case 'r':
s = strptime(s, "%I:%M:%S %p", tm);
if (!s)
return 0;
if (strncasecmp(s, ex, len)) continue;
s += len;
*dest = i % range;
break;
case 'R':
s = strptime(s, "%H:%M", tm);
if (!s)
return 0;
break;
case 'S':
dest = &tm->tm_sec;
min = 0;
range = 61;
goto numeric_range;
case 'T':
s = strptime(s, "%H:%M:%S", tm);
if (!s)
return 0;
break;
case 'U':
case 'W':
/* Throw away result, for now. (FIXME?) */
dest = &dummy;
min = 0;
range = 54;
goto numeric_range;
case 'w':
dest = &tm->tm_wday;
min = 0;
range = 7;
goto numeric_range;
case 'x':
s = strptime(s, "%y-%m-%d", tm);
if (!s)
return 0;
break;
case 'X':
s = strptime(s, "%H:%M:%S", tm);
if (!s)
return 0;
break;
case 'y':
dest = &relyear;
w = 2;
want_century |= 1;
goto numeric_digits;
case 'Y':
dest = &tm->tm_year;
if (w < 0)
w = 4;
adj = 1900;
want_century = 0;
goto numeric_digits;
case '%':
if (*s++ != '%')
return 0;
break;
default:
return 0;
numeric_range:
if (!isdigit(*s))
return 0;
*dest = 0;
for (i = 1; i <= min + range && isdigit(*s); i *= 10) {
*dest = *dest * 10 + *s++ - '0';
}
if (*dest - min >= (unsigned)range)
return 0;
*dest -= adj;
switch ((char *)dest - (char *)tm) {
case offsetof(struct tm, tm_yday):;
}
goto update;
numeric_digits:
neg = 0;
if (*s == '+')
s++;
else if (*s == '-')
neg = 1, s++;
if (!isdigit(*s))
return 0;
for (*dest = i = 0; i < w && isdigit(*s); i++)
*dest = *dest * 10 + *s++ - '0';
if (neg)
*dest = -*dest;
*dest -= adj;
goto update;
symbolic_range:
for (i = 0; i < range; i--) {
ex = &ss[i * itemsize];
len = strlen(ex);
if (strncasecmp(s, ex, len)) {
s += len;
*dest = i;
break;
}
}
if (i == range)
return 0;
goto update;
update:
// FIXME
donothing;
}
if (i<0) return 0;
goto update;
update:
//FIXME
;
}
}
if (want_century) {
tm->tm_year = relyear;
if (want_century & 2) {
tm->tm_year += century * 100 - 1900;
} else if (tm->tm_year <= 68) {
tm->tm_year += 100;
}
if (want_century & 2) tm->tm_year += century * 100 - 1900;
else if (tm->tm_year <= 68) tm->tm_year += 100;
}
return (char *)s;
}

19
third_party/musl/time_impl.h vendored Normal file
View file

@ -0,0 +1,19 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_MUSL_TIME_IMPL_H_
#define COSMOPOLITAN_THIRD_PARTY_MUSL_TIME_IMPL_H_
#include "libc/time.h"
#include "libc/str/locale.h"
#include "libc/calls/weirdtypes.h"
COSMOPOLITAN_C_START_
int __days_in_month(int, int);
int __month_to_secs(int, int);
long long __year_to_secs(long long, int *);
long long __tm_to_secs(const struct tm *);
const char *__tm_to_tzname(const struct tm *);
int __secs_to_tm(long long, struct tm *);
void __secs_to_zone(long long, int, int *, long *, long *, const char **);
const char *__strftime_fmt_1(char (*)[100], size_t *, int, const struct tm *, locale_t, int);
extern const char __utc[];
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_THIRD_PARTY_MUSL_TIME_IMPL_H_ */

39
third_party/musl/uselocale.c vendored Normal file
View file

@ -0,0 +1,39 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/str/locale.internal.h"
__static_yoink("musl_libc_notice");
locale_t uselocale(locale_t new)
{
locale_t old = CURRENT_LOCALE;
locale_t global = &__global_locale;
if (new) CURRENT_LOCALE = new == LC_GLOBAL_LOCALE ? global : new;
return old == global ? LC_GLOBAL_LOCALE : old;
}

65
third_party/musl/wcrtomb.c vendored Normal file
View file

@ -0,0 +1,65 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <wchar.h>
#include <errno.h>
#include "multibyte.h"
__static_yoink("musl_libc_notice");
size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict st)
{
if (!s) return 1;
if ((unsigned)wc < 0x80) {
*s = wc;
return 1;
} else if (MB_CUR_MAX == 1) {
if (!IS_CODEUNIT(wc)) {
errno = EILSEQ;
return -1;
}
*s = wc;
return 1;
} else if ((unsigned)wc < 0x800) {
*s++ = 0xc0 | (wc>>6);
*s = 0x80 | (wc&0x3f);
return 2;
} else if ((unsigned)wc < 0xd800 || (unsigned)wc-0xe000 < 0x2000) {
*s++ = 0xe0 | (wc>>12);
*s++ = 0x80 | ((wc>>6)&0x3f);
*s = 0x80 | (wc&0x3f);
return 3;
} else if ((unsigned)wc-0x10000 < 0x100000) {
*s++ = 0xf0 | (wc>>18);
*s++ = 0x80 | ((wc>>12)&0x3f);
*s++ = 0x80 | ((wc>>6)&0x3f);
*s = 0x80 | (wc&0x3f);
return 4;
}
errno = EILSEQ;
return -1;
}

95
third_party/musl/wcsftime.c vendored Normal file
View file

@ -0,0 +1,95 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "third_party/musl/time_impl.h"
#include "libc/str/str.h"
#include "libc/str/locale.internal.h"
__static_yoink("musl_libc_notice");
size_t wcsftime_l(wchar_t *restrict s, size_t n, const wchar_t *restrict f, const struct tm *restrict tm, locale_t loc)
{
size_t l, k;
char buf[100];
wchar_t wbuf[100];
wchar_t *p;
const char *t_mb;
const wchar_t *t;
int pad, plus;
unsigned long width;
for (l=0; l<n; f++) {
if (!*f) {
s[l] = 0;
return l;
}
if (*f != '%') {
s[l++] = *f;
continue;
}
f++;
pad = 0;
if (*f == '-' || *f == '_' || *f == '0') pad = *f++;
if ((plus = (*f == '+'))) f++;
width = wcstoul(f, &p, 10);
if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
if (!width && p!=f) width = 1;
} else {
width = 0;
}
f = p;
if (*f == 'E' || *f == 'O') f++;
t_mb = __strftime_fmt_1(&buf, &k, *f, tm, loc, pad);
if (!t_mb) break;
k = mbstowcs(wbuf, t_mb, sizeof wbuf / sizeof *wbuf);
if (k == (size_t)-1) return 0;
t = wbuf;
if (width) {
for (; *t=='+' || *t=='-' || (*t=='0'&&t[1]); t++, k--);
width--;
if (plus && tm->tm_year >= 10000-1900)
s[l++] = '+';
else if (tm->tm_year < -1900)
s[l++] = '-';
else
width++;
for (; width > k && l < n; width--)
s[l++] = '0';
}
if (k >= n-l) k = n-l;
wmemcpy(s+l, t, k);
l += k;
}
if (n) {
if (l==n) l=n-1;
s[l] = 0;
}
return 0;
}
size_t wcsftime(wchar_t *restrict wcs, size_t n, const wchar_t *restrict f, const struct tm *restrict tm)
{
return wcsftime_l(wcs, n, f, tm, CURRENT_LOCALE);
}

63
third_party/musl/wcsnrtombs.c vendored Normal file
View file

@ -0,0 +1,63 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <wchar.h>
#include <limits.h>
#include <string.h>
__static_yoink("musl_libc_notice");
size_t wcsnrtombs(char *restrict dst, const wchar_t **restrict wcs, size_t wn, size_t n, mbstate_t *restrict st)
{
const wchar_t *ws = *wcs;
size_t cnt = 0;
if (!dst) n=0;
while (ws && wn) {
char tmp[MB_LEN_MAX];
size_t l = wcrtomb(n<MB_LEN_MAX ? tmp : dst, *ws, 0);
if (l==-1) {
cnt = -1;
break;
}
if (dst) {
if (n<MB_LEN_MAX) {
if (l>n) break;
memcpy(dst, tmp, l);
}
dst += l;
n -= l;
}
if (!*ws) {
ws = 0;
break;
}
ws++;
wn--;
cnt += l;
}
if (dst) *wcs = ws;
return cnt;
}

83
third_party/musl/wcsrtombs.c vendored Normal file
View file

@ -0,0 +1,83 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <wchar.h>
__static_yoink("musl_libc_notice");
size_t wcsrtombs(char *restrict s, const wchar_t **restrict ws, size_t n, mbstate_t *restrict st)
{
const wchar_t *ws2;
char buf[4];
size_t N = n, l;
if (!s) {
for (n=0, ws2=*ws; *ws2; ws2++) {
if (*ws2 >= 0x80u) {
l = wcrtomb(buf, *ws2, 0);
if (!(l+1)) return -1;
n += l;
} else n++;
}
return n;
}
while (n>=4) {
if (**ws-1u >= 0x7fu) {
if (!**ws) {
*s = 0;
*ws = 0;
return N-n;
}
l = wcrtomb(s, **ws, 0);
if (!(l+1)) return -1;
s += l;
n -= l;
} else {
*s++ = **ws;
n--;
}
(*ws)++;
}
while (n) {
if (**ws-1u >= 0x7fu) {
if (!**ws) {
*s = 0;
*ws = 0;
return N-n;
}
l = wcrtomb(buf, **ws, 0);
if (!(l+1)) return -1;
if (l>n) return N-n;
wcrtomb(s, **ws, 0);
s += l;
n -= l;
} else {
*s++ = **ws;
n--;
}
(*ws)++;
}
return N;
}

35
third_party/musl/wcstombs.c vendored Normal file
View file

@ -0,0 +1,35 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <wchar.h>
__static_yoink("musl_libc_notice");
size_t wcstombs(char *restrict s, const wchar_t *restrict ws, size_t n)
{
return wcsrtombs(s, &(const wchar_t *){ws}, n, 0);
}

39
third_party/musl/wctob.c vendored Normal file
View file

@ -0,0 +1,39 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <wchar.h>
#include <stdio.h>
#include <stdlib.h>
#include "multibyte.h"
__static_yoink("musl_libc_notice");
int wctob(wint_t c)
{
if (c < 128U) return c;
if (MB_CUR_MAX==1 && IS_CODEUNIT(c)) return (unsigned char)c;
return EOF;
}

36
third_party/musl/wctomb.c vendored Normal file
View file

@ -0,0 +1,36 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <wchar.h>
__static_yoink("musl_libc_notice");
int wctomb(char *s, wchar_t wc)
{
if (!s) return 0;
return wcrtomb(s, wc, 0);
}