mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Make improvements
- Add hierarchical auto-completion to redbean's repl - Fetch latest localtime() and strftime() from Eggert - Shave a few milliseconds off redbean start latency - Fix redbean repl with multi-line statements - Make the Lua unix module code more elegant - Harden Lua data structure serialization
This commit is contained in:
parent
d57b81aac7
commit
6a145a9262
44 changed files with 2987 additions and 1941 deletions
|
@ -140,7 +140,7 @@ o/$(MODE)/examples/nesemu1.com: \
|
|||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/examples/.nesemu1/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/examples/.nesemu1/.symtab
|
||||
|
||||
o/$(MODE)/examples/hello.com.dbg: \
|
||||
|
|
|
@ -31,34 +31,35 @@
|
|||
.align 4
|
||||
.underrun
|
||||
kOpenFlags:
|
||||
.e O_RDWR,"RDWR" // order matters
|
||||
.e O_RDONLY,"RDONLY" //
|
||||
.e O_WRONLY,"WRONLY" //
|
||||
.e O_ACCMODE,"ACCMODE" // mask of prev three
|
||||
.e O_CREAT,"CREAT" //
|
||||
.e O_EXCL,"EXCL" //
|
||||
.e O_TRUNC,"TRUNC" //
|
||||
.e O_CLOEXEC,"CLOEXEC" //
|
||||
.e O_DIRECT,"DIRECT" // no-op on xnu/openbsd
|
||||
.e O_APPEND,"APPEND" // weird on nt
|
||||
.e O_TMPFILE,"TMPFILE" // linux, windows
|
||||
.e O_NOFOLLOW,"NOFOLLOW" // unix
|
||||
.e O_SYNC,"SYNC" // unix
|
||||
.e O_ASYNC,"ASYNC" // unix
|
||||
.e O_NOCTTY,"NOCTTY" // unix
|
||||
.e O_NOATIME,"NOATIME" // linux
|
||||
.e O_EXEC,"EXEC" // free/openbsd
|
||||
.e O_SEARCH,"SEARCH" // free/netbsd
|
||||
.e O_DSYNC,"DSYNC" // linux/xnu/open/netbsd
|
||||
.e O_RSYNC,"RSYNC" // linux/open/netbsd
|
||||
.e O_PATH,"PATH" // linux
|
||||
.e O_VERIFY,"VERIFY" // freebsd
|
||||
.e O_SHLOCK,"SHLOCK" // bsd
|
||||
.e O_EXLOCK,"EXLOCK" // bsd
|
||||
.e O_RANDOM,"RANDOM" // windows
|
||||
.e O_SEQUENTIAL,"SEQUENTIAL" // windows
|
||||
.e O_COMPRESSED,"COMPRESSED" // windows
|
||||
.e O_INDEXED,"INDEXED" // windows
|
||||
.e O_RDWR,"RDWR" // order matters
|
||||
.e O_RDONLY,"RDONLY" //
|
||||
.e O_WRONLY,"WRONLY" //
|
||||
.e O_ACCMODE,"ACCMODE" // mask of prev three
|
||||
.e O_CREAT,"CREAT" //
|
||||
.e O_EXCL,"EXCL" //
|
||||
.e O_TRUNC,"TRUNC" //
|
||||
.e O_CLOEXEC,"CLOEXEC" //
|
||||
.e O_NONBLOCK,"NONBLOCK" //
|
||||
.e O_DIRECT,"DIRECT" // no-op on xnu/openbsd
|
||||
.e O_APPEND,"APPEND" // weird on nt
|
||||
.e O_TMPFILE,"TMPFILE" // linux, windows
|
||||
.e O_NOFOLLOW,"NOFOLLOW" // unix
|
||||
.e O_SYNC,"SYNC" // unix
|
||||
.e O_ASYNC,"ASYNC" // unix
|
||||
.e O_NOCTTY,"NOCTTY" // unix
|
||||
.e O_NOATIME,"NOATIME" // linux
|
||||
.e O_EXEC,"EXEC" // free/openbsd
|
||||
.e O_SEARCH,"SEARCH" // free/netbsd
|
||||
.e O_DSYNC,"DSYNC" // linux/xnu/open/netbsd
|
||||
.e O_RSYNC,"RSYNC" // linux/open/netbsd
|
||||
.e O_PATH,"PATH" // linux
|
||||
.e O_VERIFY,"VERIFY" // freebsd
|
||||
.e O_SHLOCK,"SHLOCK" // bsd
|
||||
.e O_EXLOCK,"EXLOCK" // bsd
|
||||
.e O_RANDOM,"RANDOM" // windows
|
||||
.e O_SEQUENTIAL,"SEQUENTIAL" // windows
|
||||
.e O_COMPRESSED,"COMPRESSED" // windows
|
||||
.e O_INDEXED,"INDEXED" // windows
|
||||
.long MAGNUM_TERMINATOR
|
||||
.endobj kOpenFlags,globl,hidden
|
||||
.overrun
|
||||
|
|
|
@ -88,9 +88,9 @@ int __reservefd(int start) {
|
|||
/**
|
||||
* Closes non-stdio file descriptors to free dynamic memory.
|
||||
*/
|
||||
static void __freefds(void) {
|
||||
static void FreeFds(void) {
|
||||
int i;
|
||||
NTTRACE("__freefds()");
|
||||
NTTRACE("FreeFds()");
|
||||
for (i = 3; i < g_fds.n; ++i) {
|
||||
if (g_fds.p[i].kind) {
|
||||
close(i);
|
||||
|
@ -104,10 +104,10 @@ static void __freefds(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static textstartup void __freefds_init(void) {
|
||||
atexit(__freefds);
|
||||
static textstartup void FreeFdsInit(void) {
|
||||
atexit(FreeFds);
|
||||
}
|
||||
|
||||
const void *const __freefds_ctor[] initarray = {
|
||||
__freefds_init,
|
||||
const void *const FreeFdsCtor[] initarray = {
|
||||
FreeFdsInit,
|
||||
};
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
|
@ -23,6 +24,7 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nt/enum/computernameformat.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
|
|
@ -48,6 +48,26 @@ typedef __UINT_FAST32_TYPE__ uint_fast32_t;
|
|||
typedef __INT_FAST64_TYPE__ int_fast64_t;
|
||||
typedef __UINT_FAST64_TYPE__ uint_fast64_t;
|
||||
|
||||
#define TIME_T_MAX __INT64_MAX__
|
||||
#define UINT_FAST64_MAX __UINT_FAST64_MAX__
|
||||
#define UINT_FAST8_MAX __UINT_FAST8_MAX__
|
||||
#define INT_FAST32_MAX __INT_FAST32_MAX__
|
||||
#define INT_FAST16_MAX __INT_FAST16_MAX__
|
||||
#define UINT_FAST32_MAX __UINT_FAST32_MAX__
|
||||
#define INT_FAST8_MAX __INT_FAST8_MAX__
|
||||
#define INT_FAST64_MAX __INT_FAST64_MAX__
|
||||
#define UINT_FAST16_MAX __UINT_FAST16_MAX__
|
||||
|
||||
#define TIME_T_MIN (-TIME_T_MAX - 1)
|
||||
#define UINT_FAST64_MIN (-UINT_FAST64_MAX - 1)
|
||||
#define UINT_FAST8_MIN (-UINT_FAST8_MAX - 1)
|
||||
#define INT_FAST32_MIN (-INT_FAST32_MAX - 1)
|
||||
#define INT_FAST16_MIN (-INT_FAST16_MAX - 1)
|
||||
#define UINT_FAST32_MIN (-UINT_FAST32_MAX - 1)
|
||||
#define INT_FAST8_MIN (-INT_FAST8_MAX - 1)
|
||||
#define INT_FAST64_MIN (-INT_FAST64_MAX - 1)
|
||||
#define UINT_FAST16_MIN (-UINT_FAST16_MAX - 1)
|
||||
|
||||
#define atomic_bool _Atomic(_Bool)
|
||||
#define atomic_bool32 atomic_int_fast32_t
|
||||
#define atomic_char _Atomic(char)
|
||||
|
|
|
@ -44,17 +44,17 @@ int strerror_wr(int err, uint32_t winerr, char *buf, size_t size) {
|
|||
if (size > 1) *buf++ = c;
|
||||
if (size) *buf = 0;
|
||||
} else if (!IsWindows() || err == winerr || !winerr) {
|
||||
ksnprintf(buf, size, "%s:%d:%s", sym, err, msg);
|
||||
ksnprintf(buf, size, "%s/%d/%s", sym, err, msg);
|
||||
} else {
|
||||
if ((n = FormatMessage(
|
||||
kNtFormatMessageFromSystem | kNtFormatMessageIgnoreInserts, 0,
|
||||
winerr, MAKELANGID(kNtLangNeutral, kNtSublangDefault), winmsg,
|
||||
ARRAYLEN(winmsg), 0))) {
|
||||
while ((n && winmsg[n - 1] <= ' ') || winmsg[n - 1] == '.') --n;
|
||||
ksnprintf(buf, size, "%s:%d:%s:%d:%.*hs", sym, err, msg, winerr, n,
|
||||
ksnprintf(buf, size, "%s/%d/%s/%d/%.*hs", sym, err, msg, winerr, n,
|
||||
winmsg);
|
||||
} else {
|
||||
ksnprintf(buf, size, "%s:%d:%s:%d", sym, err, msg, winerr);
|
||||
ksnprintf(buf, size, "%s/%d/%s/%d", sym, err, msg, winerr);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -54,7 +54,7 @@ static ssize_t FindSymtabInZip(struct Zipos *zipos) {
|
|||
* @note This code can't depend on dlmalloc()
|
||||
*/
|
||||
static struct SymbolTable *GetSymbolTableFromZip(struct Zipos *zipos) {
|
||||
ssize_t cf, lf;
|
||||
ssize_t rc, cf, lf;
|
||||
size_t size, size2;
|
||||
struct DeflateState ds;
|
||||
struct SymbolTable *res = 0;
|
||||
|
@ -67,14 +67,16 @@ static struct SymbolTable *GetSymbolTableFromZip(struct Zipos *zipos) {
|
|||
case kZipCompressionNone:
|
||||
memcpy(res, (void *)ZIP_LFILE_CONTENT(zipos->map + lf), size);
|
||||
break;
|
||||
#if 0
|
||||
case kZipCompressionDeflate:
|
||||
if (undeflate(res, size, (void *)ZIP_LFILE_CONTENT(zipos->map + lf),
|
||||
GetZipLfileCompressedSize(zipos->map + lf),
|
||||
&ds) == -1) {
|
||||
rc = undeflate(res, size, (void *)ZIP_LFILE_CONTENT(zipos->map + lf),
|
||||
GetZipLfileCompressedSize(zipos->map + lf), &ds);
|
||||
if (rc == -1) {
|
||||
munmap(res, size2);
|
||||
res = 0;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
munmap(res, size2);
|
||||
res = 0;
|
||||
|
@ -115,11 +117,8 @@ static struct SymbolTable *GetSymbolTableFromElf(void) {
|
|||
* @return symbol table, or NULL w/ errno on first call
|
||||
*/
|
||||
struct SymbolTable *GetSymbolTable(void) {
|
||||
int ft, st;
|
||||
struct Zipos *z;
|
||||
if (!g_symtab && !__isworker) {
|
||||
ft = g_ftrace, g_ftrace = 0;
|
||||
st = __strace, __strace = 0;
|
||||
if (weaken(__zipos_get) && (z = weaken(__zipos_get)())) {
|
||||
if ((g_symtab = GetSymbolTableFromZip(z))) {
|
||||
g_symtab->names =
|
||||
|
@ -131,8 +130,6 @@ struct SymbolTable *GetSymbolTable(void) {
|
|||
if (!g_symtab) {
|
||||
g_symtab = GetSymbolTableFromElf();
|
||||
}
|
||||
g_ftrace = ft;
|
||||
__strace = st;
|
||||
}
|
||||
return g_symtab;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -80,4 +81,7 @@ void longsort(long *x, size_t n) {
|
|||
longsort_pure(x, n, t);
|
||||
}
|
||||
}
|
||||
if (n > 1000) {
|
||||
STRACE("longsort(%p, %'zu)", x, n);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ noasan static inline const char *strchrnul_sse(const char *s, unsigned char c) {
|
|||
/**
|
||||
* Returns pointer to first instance of character.
|
||||
*
|
||||
* If c is not found then a pointer to the nul byte is returned.
|
||||
*
|
||||
* @param s is a NUL-terminated string
|
||||
* @param c is masked with 255 as byte to search for
|
||||
* @return pointer to first instance of c, or pointer to
|
||||
|
|
|
@ -1110,9 +1110,6 @@ syscon pf PF_VSOCK 40 0 0 0 0 0
|
|||
syscon pf PF_WANPIPE 25 0 0 0 0 0
|
||||
syscon pf PF_X25 9 0 0 0 0 0
|
||||
|
||||
syscon exit EXIT_SUCCESS 0 0 0 0 0 0 # consensus
|
||||
syscon exit EXIT_FAILURE 1 1 1 1 1 1 # consensus
|
||||
|
||||
# Eric Allman's exit() codes
|
||||
#
|
||||
# - Broadly supported style guideline;
|
||||
|
|
|
@ -1,16 +1,7 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_EXIT_H_
|
||||
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_EXIT_H_
|
||||
#include "libc/runtime/symbolic.h"
|
||||
|
||||
#define EXIT_FAILURE SYMBOLIC(EXIT_FAILURE)
|
||||
#define EXIT_SUCCESS SYMBOLIC(EXIT_SUCCESS)
|
||||
#define EXIT_FAILURE 1
|
||||
#define EXIT_SUCCESS 0
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const long EXIT_FAILURE;
|
||||
extern const long EXIT_SUCCESS;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_EXIT_H_ */
|
||||
|
|
|
@ -1,31 +1,114 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/time/tz.internal.h"
|
||||
// clang-format off
|
||||
/* asctime and asctime_r a la POSIX and ISO C, except pad years before 1000. */
|
||||
|
||||
static char g_asctime_buf[64];
|
||||
/*
|
||||
** This file is in the public domain, so clarified as of
|
||||
** 1996-06-05 by Arthur David Olson.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Converts date time to string.
|
||||
*
|
||||
* @return date time string in statically allocated buffer
|
||||
* @see asctime_r for reentrant version
|
||||
*/
|
||||
char *asctime(const struct tm *date) {
|
||||
return asctime_r(date, g_asctime_buf);
|
||||
/*
|
||||
** Avoid the temptation to punt entirely to strftime;
|
||||
** the output of strftime is supposed to be locale specific
|
||||
** whereas the output of asctime is supposed to be constant.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Some systems only handle "%.2d"; others only handle "%02d";
|
||||
** "%02.2d" makes (most) everybody happy.
|
||||
** At least some versions of gcc warn about the %02.2d;
|
||||
** we conditionalize below to avoid the warning.
|
||||
*/
|
||||
/*
|
||||
** All years associated with 32-bit time_t values are exactly four digits long;
|
||||
** some years associated with 64-bit time_t values are not.
|
||||
** Vintage programs are coded for years that are always four digits long
|
||||
** and may assume that the newline always lands in the same place.
|
||||
** For years that are less than four digits, we pad the output with
|
||||
** leading zeroes to get the newline in the traditional place.
|
||||
** The -4 ensures that we get four characters of output even if
|
||||
** we call a strftime variant that produces fewer characters for some years.
|
||||
** The ISO C and POSIX standards prohibit padding the year,
|
||||
** but many implementations pad anyway; most likely the standards are buggy.
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
#define ASCTIME_FMT "%s %s%3d %2.2d:%2.2d:%2.2d %-4s\n"
|
||||
#else /* !defined __GNUC__ */
|
||||
#define ASCTIME_FMT "%s %s%3d %02.2d:%02.2d:%02.2d %-4s\n"
|
||||
#endif /* !defined __GNUC__ */
|
||||
/*
|
||||
** For years that are more than four digits we put extra spaces before the year
|
||||
** so that code trying to overwrite the newline won't end up overwriting
|
||||
** a digit within a year and truncating the year (operating on the assumption
|
||||
** that no output is better than wrong output).
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
#define ASCTIME_FMT_B "%s %s%3d %2.2d:%2.2d:%2.2d %s\n"
|
||||
#else /* !defined __GNUC__ */
|
||||
#define ASCTIME_FMT_B "%s %s%3d %02.2d:%02.2d:%02.2d %s\n"
|
||||
#endif /* !defined __GNUC__ */
|
||||
|
||||
#define STD_ASCTIME_BUF_SIZE 26
|
||||
/*
|
||||
** Big enough for something such as
|
||||
** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n
|
||||
** (two three-character abbreviations, five strings denoting integers,
|
||||
** seven explicit spaces, two explicit colons, a newline,
|
||||
** and a trailing NUL byte).
|
||||
** The values above are for systems where an int is 32 bits and are provided
|
||||
** as an example; the define below calculates the maximum for the system at
|
||||
** hand.
|
||||
*/
|
||||
#define MAX_ASCTIME_BUF_SIZE (2*3+5*INT_STRLEN_MAXIMUM(int)+7+2+1+1)
|
||||
|
||||
static char buf_asctime[MAX_ASCTIME_BUF_SIZE];
|
||||
|
||||
char *
|
||||
asctime_r(register const struct tm *timeptr, char *buf)
|
||||
{
|
||||
register const char * wn;
|
||||
register const char * mn;
|
||||
char year[INT_STRLEN_MAXIMUM(int) + 2];
|
||||
char result[MAX_ASCTIME_BUF_SIZE];
|
||||
|
||||
if (timeptr == NULL) {
|
||||
errno = EINVAL;
|
||||
return strcpy(buf, "??? ??? ?? ??:??:?? ????\n");
|
||||
}
|
||||
if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
|
||||
wn = "???";
|
||||
else wn = kWeekdayNameShort[timeptr->tm_wday];
|
||||
if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
|
||||
mn = "???";
|
||||
else mn = kMonthNameShort[timeptr->tm_mon];
|
||||
/*
|
||||
** Use strftime's %Y to generate the year, to avoid overflow problems
|
||||
** when computing timeptr->tm_year + TM_YEAR_BASE.
|
||||
** Assume that strftime is unaffected by other out-of-range members
|
||||
** (e.g., timeptr->tm_mday) when processing "%Y".
|
||||
*/
|
||||
strftime(year, sizeof year, "%Y", timeptr);
|
||||
/*
|
||||
** We avoid using snprintf since it's not available on all systems.
|
||||
*/
|
||||
(sprintf)(result,
|
||||
((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B),
|
||||
wn, mn,
|
||||
timeptr->tm_mday, timeptr->tm_hour,
|
||||
timeptr->tm_min, timeptr->tm_sec,
|
||||
year);
|
||||
if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime)
|
||||
return strcpy(buf, result);
|
||||
else {
|
||||
errno = EOVERFLOW;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
asctime(register const struct tm *timeptr)
|
||||
{
|
||||
return asctime_r(timeptr, buf_asctime);
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
static unsigned clip(unsigned index, unsigned count) {
|
||||
return index < count ? index : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts date time to string.
|
||||
*
|
||||
* @param buf needs to have 64 bytes
|
||||
* @return pointer to buf
|
||||
* @see asctime_r for reentrant version
|
||||
*/
|
||||
char *asctime_r(const struct tm *date, char buf[hasatleast 64]) {
|
||||
(snprintf)(buf, 64, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
|
||||
kWeekdayNameShort[clip(date->tm_wday, 7)],
|
||||
kMonthNameShort[clip(date->tm_mon, 12)], date->tm_mday,
|
||||
date->tm_hour, date->tm_min, date->tm_sec, 1900 + date->tm_year);
|
||||
return buf;
|
||||
}
|
|
@ -1,21 +1,13 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
char *ctime(const int64_t *timep) { return asctime(localtime(timep)); }
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,25 +1,9 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
char *ctime_r(const int64_t *timep, char buf[hasatleast 64]) {
|
||||
struct tm date[1];
|
||||
return asctime_r(localtime_r(timep, date), buf);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,21 +1,61 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
/*-*- mode:c; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/time/tz.internal.h"
|
||||
// clang-format off
|
||||
/* Return the difference between two timestamps. */
|
||||
|
||||
double difftime(int64_t x, int64_t y) { return x - y; }
|
||||
/*
|
||||
** This file is in the public domain, so clarified as of
|
||||
** 1996-06-05 by Arthur David Olson.
|
||||
*/
|
||||
|
||||
/* Return -X as a double. Using this avoids casting to 'double'. */
|
||||
static inline double
|
||||
dminus(double x)
|
||||
{
|
||||
return -x;
|
||||
}
|
||||
|
||||
double
|
||||
difftime(time_t time1, time_t time0)
|
||||
{
|
||||
/*
|
||||
** If double is large enough, simply convert and subtract
|
||||
** (assuming that the larger type has more precision).
|
||||
*/
|
||||
if (sizeof(time_t) < sizeof(double)) {
|
||||
double t1 = time1, t0 = time0;
|
||||
return t1 - t0;
|
||||
}
|
||||
|
||||
/*
|
||||
** The difference of two unsigned values can't overflow
|
||||
** if the minuend is greater than or equal to the subtrahend.
|
||||
*/
|
||||
if (!TYPE_SIGNED(time_t))
|
||||
return time0 <= time1 ? time1 - time0 : dminus(time0 - time1);
|
||||
|
||||
/* Use uintmax_t if wide enough. */
|
||||
if (sizeof(time_t) <= sizeof(uintmax_t)) {
|
||||
uintmax_t t1 = time1, t0 = time0;
|
||||
return time0 <= time1 ? t1 - t0 : dminus(t0 - t1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Handle cases where both time1 and time0 have the same sign
|
||||
** (meaning that their difference cannot overflow).
|
||||
*/
|
||||
if ((time1 < 0) == (time0 < 0))
|
||||
return time1 - time0;
|
||||
|
||||
/*
|
||||
** The values have opposite signs and uintmax_t is too narrow.
|
||||
** This suffers from double rounding; attempt to lessen that
|
||||
** by using long double temporaries.
|
||||
*/
|
||||
{
|
||||
long double t1 = time1, t0 = time0;
|
||||
return t1 - t0;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
/*-*- mode:c; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright (c) 1989 The Regents of the University of California. │
|
||||
│ All rights reserved. │
|
||||
|
@ -16,354 +16,529 @@
|
|||
│ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "libc/inttypes.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/time/tzfile.internal.h"
|
||||
#include "libc/time/tz.internal.h"
|
||||
#include "libc/unicode/locale.h"
|
||||
// clang-format off
|
||||
// converts broken-down timestamp to string
|
||||
|
||||
#define DIVISOR 100
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
strftime (BSD-3)\\n\
|
||||
Copyright 1989 The Regents of the University of California\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
static char *strftime_add(char *p, const char *pe, const char *str) {
|
||||
while (p < pe && (*p = *str++)) ++p;
|
||||
return p;
|
||||
/*
|
||||
** Based on the UCB version with the copyright notice appearing above.
|
||||
**
|
||||
** This is ANSIish only when "multibyte character == plain character".
|
||||
*/
|
||||
|
||||
struct lc_time_T {
|
||||
const char * mon[MONSPERYEAR];
|
||||
const char * month[MONSPERYEAR];
|
||||
const char * wday[DAYSPERWEEK];
|
||||
const char * weekday[DAYSPERWEEK];
|
||||
const char * X_fmt;
|
||||
const char * x_fmt;
|
||||
const char * c_fmt;
|
||||
const char * am;
|
||||
const char * pm;
|
||||
const char * date_fmt;
|
||||
};
|
||||
|
||||
#define Locale (&C_time_locale)
|
||||
|
||||
static const struct lc_time_T C_time_locale = {
|
||||
{
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
}, {
|
||||
"January", "February", "March", "April", "May", "June",
|
||||
"July", "August", "September", "October", "November", "December"
|
||||
}, {
|
||||
"Sun", "Mon", "Tue", "Wed",
|
||||
"Thu", "Fri", "Sat"
|
||||
}, {
|
||||
"Sunday", "Monday", "Tuesday", "Wednesday",
|
||||
"Thursday", "Friday", "Saturday"
|
||||
},
|
||||
|
||||
/* X_fmt */
|
||||
"%H:%M:%S",
|
||||
|
||||
/*
|
||||
** x_fmt
|
||||
** C99 and later require this format.
|
||||
** Using just numbers (as here) makes Quakers happier;
|
||||
** it's also compatible with SVR4.
|
||||
*/
|
||||
"%m/%d/%y",
|
||||
|
||||
/*
|
||||
** c_fmt
|
||||
** C99 and later require this format.
|
||||
** Previously this code used "%D %X", but we now conform to C99.
|
||||
** Note that
|
||||
** "%a %b %d %H:%M:%S %Y"
|
||||
** is used by Solaris 2.3.
|
||||
*/
|
||||
"%a %b %e %T %Y",
|
||||
|
||||
/* am */
|
||||
"AM",
|
||||
|
||||
/* pm */
|
||||
"PM",
|
||||
|
||||
/* date_fmt */
|
||||
"%a %b %e %H:%M:%S %Z %Y"
|
||||
};
|
||||
|
||||
enum warn { IN_NONE, IN_SOME, IN_THIS, IN_ALL };
|
||||
|
||||
#ifndef YEAR_2000_NAME
|
||||
#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
|
||||
#endif /* !defined YEAR_2000_NAME */
|
||||
|
||||
static char *
|
||||
_add(const char *str, char *pt, const char *ptlim)
|
||||
{
|
||||
while (pt < ptlim && (*pt = *str++) != '\0')
|
||||
++pt;
|
||||
return pt;
|
||||
}
|
||||
|
||||
static char *strftime_conv(char *p, const char *pe, int n, const char *format) {
|
||||
char buf[22];
|
||||
(snprintf)(buf, sizeof(buf), format, n);
|
||||
return strftime_add(p, pe, buf);
|
||||
static char *
|
||||
_conv(int n, const char *format, char *pt, const char *ptlim)
|
||||
{
|
||||
char buf[INT_STRLEN_MAXIMUM(int) + 1];
|
||||
(sprintf)(buf, format, n);
|
||||
return _add(buf, pt, ptlim);
|
||||
}
|
||||
|
||||
static char *strftime_secs(char *p, const char *pe, const struct tm *t) {
|
||||
char ibuf[21];
|
||||
struct tm tmp;
|
||||
int64_t s;
|
||||
tmp = *t; /* Make a copy, mktime(3) modifies the tm struct. */
|
||||
s = mktime(&tmp);
|
||||
FormatInt64(ibuf, s);
|
||||
return strftime_add(p, pe, ibuf);
|
||||
/*
|
||||
** POSIX and the C Standard are unclear or inconsistent about
|
||||
** what %C and %y do if the year is negative or exceeds 9999.
|
||||
** Use the convention that %C concatenated with %y yields the
|
||||
** same output as %Y, and that %Y contains at least 4 bytes,
|
||||
** with more only if necessary.
|
||||
*/
|
||||
|
||||
static char *
|
||||
_yconv(int a, int b, bool convert_top, bool convert_yy,
|
||||
char *pt, const char *ptlim)
|
||||
{
|
||||
register int lead;
|
||||
register int trail;
|
||||
|
||||
trail = a % DIVISOR + b % DIVISOR;
|
||||
lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
|
||||
trail %= DIVISOR;
|
||||
if (trail < 0 && lead > 0) {
|
||||
trail += DIVISOR;
|
||||
--lead;
|
||||
} else if (lead < 0 && trail > 0) {
|
||||
trail -= DIVISOR;
|
||||
++lead;
|
||||
}
|
||||
if (convert_top) {
|
||||
if (lead == 0 && trail < 0)
|
||||
pt = _add("-0", pt, ptlim);
|
||||
else pt = _conv(lead, "%02d", pt, ptlim);
|
||||
}
|
||||
if (convert_yy)
|
||||
pt = _conv(((trail < 0) ? -trail : trail), "%02d", pt, ptlim);
|
||||
return pt;
|
||||
}
|
||||
|
||||
static char *strftime_timefmt(char *p, const char *pe, const char *format,
|
||||
const struct tm *t) {
|
||||
int i;
|
||||
long diff;
|
||||
char const *sign;
|
||||
/* size_t z1, z2, z3; */
|
||||
for (; *format; ++format) {
|
||||
if (*format == '%') {
|
||||
label:
|
||||
switch (*++format) {
|
||||
case '\0':
|
||||
--format;
|
||||
break;
|
||||
case 'A':
|
||||
p = strftime_add(p, pe,
|
||||
(t->tm_wday < 0 || t->tm_wday > 6)
|
||||
? "?"
|
||||
: kWeekdayName[t->tm_wday]);
|
||||
continue;
|
||||
case 'a':
|
||||
p = strftime_add(p, pe,
|
||||
(t->tm_wday < 0 || t->tm_wday > 6)
|
||||
? "?"
|
||||
: kWeekdayNameShort[t->tm_wday]);
|
||||
continue;
|
||||
case 'B':
|
||||
p = strftime_add(
|
||||
p, pe,
|
||||
(t->tm_mon < 0 || t->tm_mon > 11) ? "?" : kMonthName[t->tm_mon]);
|
||||
continue;
|
||||
case 'b':
|
||||
case 'h':
|
||||
p = strftime_add(p, pe,
|
||||
(t->tm_mon < 0 || t->tm_mon > 11)
|
||||
? "?"
|
||||
: kMonthNameShort[t->tm_mon]);
|
||||
continue;
|
||||
case 'c':
|
||||
p = strftime_timefmt(p, pe, "%D %X", t);
|
||||
continue;
|
||||
case 'C':
|
||||
/*
|
||||
** %C used to do a...
|
||||
** strftime_timefmt("%a %b %e %X %Y", t);
|
||||
** ...whereas now POSIX 1003.2 calls for
|
||||
** something completely different.
|
||||
** (ado, 5/24/93)
|
||||
*/
|
||||
p = strftime_conv(p, pe, div100int64(t->tm_year + TM_YEAR_BASE),
|
||||
"%02d");
|
||||
continue;
|
||||
case 'D':
|
||||
p = strftime_timefmt(p, pe, "%m/%d/%y", t);
|
||||
continue;
|
||||
case 'x':
|
||||
/*
|
||||
** Version 3.0 of strftime from Arnold Robbins
|
||||
** (arnold@skeeve.atl.ga.us) does the
|
||||
** equivalent of...
|
||||
** strftime_timefmt("%a %b %e %Y");
|
||||
** ...for %x; since the X3J11 C language
|
||||
** standard calls for "date, using locale's
|
||||
** date format," anything goes. Using just
|
||||
** numbers (as here) makes Quakers happier.
|
||||
** Word from Paul Eggert (eggert@twinsun.com)
|
||||
** is that %Y-%m-%d is the ISO standard date
|
||||
** format, specified in ISO 2014 and later
|
||||
** ISO 8601:1988, with a summary available in
|
||||
** pub/doc/ISO/english/ISO8601.ps.Z on
|
||||
** ftp.uni-erlangen.de.
|
||||
** (ado, 5/30/93)
|
||||
*/
|
||||
p = strftime_timefmt(p, pe, "%m/%d/%y", t);
|
||||
continue;
|
||||
case 'd':
|
||||
p = strftime_conv(p, pe, t->tm_mday, "%02d");
|
||||
continue;
|
||||
case 'E':
|
||||
case 'O':
|
||||
/*
|
||||
** POSIX locale extensions, a la
|
||||
** Arnold Robbins' strftime version 3.0.
|
||||
** The sequences
|
||||
** %Ec %EC %Ex %Ey %EY
|
||||
** %Od %oe %OH %OI %Om %OM
|
||||
** %OS %Ou %OU %OV %Ow %OW %Oy
|
||||
** are supposed to provide alternate
|
||||
** representations.
|
||||
** (ado, 5/24/93)
|
||||
*/
|
||||
goto label;
|
||||
case 'e':
|
||||
p = strftime_conv(p, pe, t->tm_mday, "%2d");
|
||||
continue;
|
||||
case 'H':
|
||||
p = strftime_conv(p, pe, t->tm_hour, "%02d");
|
||||
continue;
|
||||
case 'I':
|
||||
p = strftime_conv(p, pe, (t->tm_hour % 12) ? (t->tm_hour % 12) : 12,
|
||||
"%02d");
|
||||
continue;
|
||||
case 'j':
|
||||
p = strftime_conv(p, pe, t->tm_yday + 1, "%03d");
|
||||
continue;
|
||||
case 'k':
|
||||
/*
|
||||
** This used to be...
|
||||
** strftime_conv(t->tm_hour % 12 ?
|
||||
** t->tm_hour % 12 : 12, 2, ' ');
|
||||
** ...and has been changed to the below to
|
||||
** match SunOS 4.1.1 and Arnold Robbins'
|
||||
** strftime version 3.0. That is, "%k" and
|
||||
** "%l" have been swapped.
|
||||
** (ado, 5/24/93)
|
||||
*/
|
||||
p = strftime_conv(p, pe, t->tm_hour, "%2d");
|
||||
continue;
|
||||
static char *
|
||||
_fmt(const char *format, const struct tm *t, char *pt,
|
||||
const char *ptlim, enum warn *warnp)
|
||||
{
|
||||
for ( ; *format; ++format) {
|
||||
if (*format == '%') {
|
||||
label:
|
||||
switch (*++format) {
|
||||
case '\0':
|
||||
--format;
|
||||
break;
|
||||
case 'A':
|
||||
pt = _add((t->tm_wday < 0 ||
|
||||
t->tm_wday >= DAYSPERWEEK) ?
|
||||
"?" : Locale->weekday[t->tm_wday],
|
||||
pt, ptlim);
|
||||
continue;
|
||||
case 'a':
|
||||
pt = _add((t->tm_wday < 0 ||
|
||||
t->tm_wday >= DAYSPERWEEK) ?
|
||||
"?" : Locale->wday[t->tm_wday],
|
||||
pt, ptlim);
|
||||
continue;
|
||||
case 'B':
|
||||
pt = _add((t->tm_mon < 0 ||
|
||||
t->tm_mon >= MONSPERYEAR) ?
|
||||
"?" : Locale->month[t->tm_mon],
|
||||
pt, ptlim);
|
||||
continue;
|
||||
case 'b':
|
||||
case 'h':
|
||||
pt = _add((t->tm_mon < 0 ||
|
||||
t->tm_mon >= MONSPERYEAR) ?
|
||||
"?" : Locale->mon[t->tm_mon],
|
||||
pt, ptlim);
|
||||
continue;
|
||||
case 'C':
|
||||
/*
|
||||
** %C used to do a...
|
||||
** _fmt("%a %b %e %X %Y", t);
|
||||
** ...whereas now POSIX 1003.2 calls for
|
||||
** something completely different.
|
||||
** (ado, 1993-05-24)
|
||||
*/
|
||||
pt = _yconv(t->tm_year, TM_YEAR_BASE,
|
||||
true, false, pt, ptlim);
|
||||
continue;
|
||||
case 'c':
|
||||
{
|
||||
enum warn warn2 = IN_SOME;
|
||||
|
||||
pt = _fmt(Locale->c_fmt, t, pt, ptlim, &warn2);
|
||||
if (warn2 == IN_ALL)
|
||||
warn2 = IN_THIS;
|
||||
if (warn2 > *warnp)
|
||||
*warnp = warn2;
|
||||
}
|
||||
continue;
|
||||
case 'D':
|
||||
pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
|
||||
continue;
|
||||
case 'd':
|
||||
pt = _conv(t->tm_mday, "%02d", pt, ptlim);
|
||||
continue;
|
||||
case 'E':
|
||||
case 'O':
|
||||
/*
|
||||
** Locale modifiers of C99 and later.
|
||||
** The sequences
|
||||
** %Ec %EC %Ex %EX %Ey %EY
|
||||
** %Od %oe %OH %OI %Om %OM
|
||||
** %OS %Ou %OU %OV %Ow %OW %Oy
|
||||
** are supposed to provide alternative
|
||||
** representations.
|
||||
*/
|
||||
goto label;
|
||||
case 'e':
|
||||
pt = _conv(t->tm_mday, "%2d", pt, ptlim);
|
||||
continue;
|
||||
case 'F':
|
||||
pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
|
||||
continue;
|
||||
case 'H':
|
||||
pt = _conv(t->tm_hour, "%02d", pt, ptlim);
|
||||
continue;
|
||||
case 'I':
|
||||
pt = _conv((t->tm_hour % 12) ?
|
||||
(t->tm_hour % 12) : 12,
|
||||
"%02d", pt, ptlim);
|
||||
continue;
|
||||
case 'j':
|
||||
pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);
|
||||
continue;
|
||||
case 'k':
|
||||
/*
|
||||
** This used to be...
|
||||
** _conv(t->tm_hour % 12 ?
|
||||
** t->tm_hour % 12 : 12, 2, ' ');
|
||||
** ...and has been changed to the below to
|
||||
** match SunOS 4.1.1 and Arnold Robbins'
|
||||
** strftime version 3.0. That is, "%k" and
|
||||
** "%l" have been swapped.
|
||||
** (ado, 1993-05-24)
|
||||
*/
|
||||
pt = _conv(t->tm_hour, "%2d", pt, ptlim);
|
||||
continue;
|
||||
#ifdef KITCHEN_SINK
|
||||
case 'K':
|
||||
/*
|
||||
** After all this time, still unclaimed!
|
||||
*/
|
||||
p = strftime_add(p, pe, "kitchen sink");
|
||||
continue;
|
||||
case 'K':
|
||||
/*
|
||||
** After all this time, still unclaimed!
|
||||
*/
|
||||
pt = _add("kitchen sink", pt, ptlim);
|
||||
continue;
|
||||
#endif /* defined KITCHEN_SINK */
|
||||
case 'l':
|
||||
/*
|
||||
** This used to be...
|
||||
** strftime_conv(t->tm_hour, 2, ' ');
|
||||
** ...and has been changed to the below to
|
||||
** match SunOS 4.1.1 and Arnold Robbin's
|
||||
** strftime version 3.0. That is, "%k" and
|
||||
** "%l" have been swapped.
|
||||
** (ado, 5/24/93)
|
||||
*/
|
||||
p = strftime_conv(p, pe, (t->tm_hour % 12) ? (t->tm_hour % 12) : 12,
|
||||
"%2d");
|
||||
continue;
|
||||
case 'M':
|
||||
p = strftime_conv(p, pe, t->tm_min, "%02d");
|
||||
continue;
|
||||
case 'm':
|
||||
p = strftime_conv(p, pe, t->tm_mon + 1, "%02d");
|
||||
continue;
|
||||
case 'n':
|
||||
p = strftime_add(p, pe, "\n");
|
||||
continue;
|
||||
case 'p':
|
||||
p = strftime_add(p, pe, t->tm_hour >= 12 ? "PM" : "AM");
|
||||
continue;
|
||||
case 'R':
|
||||
p = strftime_timefmt(p, pe, "%H:%M", t);
|
||||
continue;
|
||||
case 'r':
|
||||
p = strftime_timefmt(p, pe, "%I:%M:%S %p", t);
|
||||
continue;
|
||||
case 'S':
|
||||
p = strftime_conv(p, pe, t->tm_sec, "%02d");
|
||||
continue;
|
||||
case 's':
|
||||
p = strftime_secs(p, pe, t);
|
||||
continue;
|
||||
case 'T':
|
||||
case 'X':
|
||||
p = strftime_timefmt(p, pe, "%H:%M:%S", t);
|
||||
continue;
|
||||
case 't':
|
||||
p = strftime_add(p, pe, "\t");
|
||||
continue;
|
||||
case 'U':
|
||||
p = strftime_conv(p, pe, (t->tm_yday + 7 - t->tm_wday) / 7, "%02d");
|
||||
continue;
|
||||
case 'u':
|
||||
/*
|
||||
** From Arnold Robbins' strftime version 3.0:
|
||||
** "ISO 8601: Weekday as a decimal number
|
||||
** [1 (Monday) - 7]"
|
||||
** (ado, 5/24/93)
|
||||
*/
|
||||
p = strftime_conv(p, pe, (t->tm_wday == 0) ? 7 : t->tm_wday, "%d");
|
||||
continue;
|
||||
case 'V':
|
||||
/*
|
||||
** From Arnold Robbins' strftime version 3.0:
|
||||
** "the week number of the year (the first
|
||||
** Monday as the first day of week 1) as a
|
||||
** decimal number (01-53). The method for
|
||||
** determining the week number is as specified
|
||||
** by ISO 8601 (to wit: if the week containing
|
||||
** January 1 has four or more days in the new
|
||||
** year, then it is week 1, otherwise it is
|
||||
** week 53 of the previous year and the next
|
||||
** week is week 1)."
|
||||
** (ado, 5/24/93)
|
||||
*/
|
||||
/*
|
||||
** XXX--If January 1 falls on a Friday,
|
||||
** January 1-3 are part of week 53 of the
|
||||
** previous year. By analogy, if January
|
||||
** 1 falls on a Thursday, are December 29-31
|
||||
** of the PREVIOUS year part of week 1???
|
||||
** (ado 5/24/93)
|
||||
**
|
||||
** You are understood not to expect this.
|
||||
*/
|
||||
i = (t->tm_yday + 10 - (t->tm_wday ? (t->tm_wday - 1) : 6)) / 7;
|
||||
if (i == 0) {
|
||||
/*
|
||||
** What day of the week does
|
||||
** January 1 fall on?
|
||||
*/
|
||||
i = t->tm_wday - (t->tm_yday - 1);
|
||||
/*
|
||||
** Fri Jan 1: 53
|
||||
** Sun Jan 1: 52
|
||||
** Sat Jan 1: 53 if previous
|
||||
** year a leap
|
||||
** year, else 52
|
||||
*/
|
||||
if (i == TM_FRIDAY)
|
||||
i = 53;
|
||||
else if (i == TM_SUNDAY)
|
||||
i = 52;
|
||||
else
|
||||
i = isleap(t->tm_year + TM_YEAR_BASE) ? 53 : 52;
|
||||
#ifdef XPG4_1994_04_09
|
||||
/*
|
||||
** As of 4/9/94, though,
|
||||
** XPG4 calls for 53
|
||||
** unconditionally.
|
||||
*/
|
||||
i = 53;
|
||||
#endif /* defined XPG4_1994_04_09 */
|
||||
}
|
||||
p = strftime_conv(p, pe, i, "%02d");
|
||||
continue;
|
||||
case 'v':
|
||||
/*
|
||||
** From Arnold Robbins' strftime version 3.0:
|
||||
** "date as dd-bbb-YYYY"
|
||||
** (ado, 5/24/93)
|
||||
*/
|
||||
p = strftime_timefmt(p, pe, "%e-%b-%Y", t);
|
||||
continue;
|
||||
case 'W':
|
||||
p = strftime_conv(
|
||||
p, pe, (t->tm_yday + 7 - (t->tm_wday ? (t->tm_wday - 1) : 6)) / 7,
|
||||
"%02d");
|
||||
continue;
|
||||
case 'w':
|
||||
p = strftime_conv(p, pe, t->tm_wday, "%d");
|
||||
continue;
|
||||
case 'y':
|
||||
p = strftime_conv(p, pe, (t->tm_year + TM_YEAR_BASE) % 100, "%02d");
|
||||
continue;
|
||||
case 'Y':
|
||||
p = strftime_conv(p, pe, t->tm_year + TM_YEAR_BASE, "%04d");
|
||||
continue;
|
||||
case 'Z':
|
||||
if (t->tm_zone) {
|
||||
p = strftime_add(p, pe, t->tm_zone);
|
||||
} else {
|
||||
if (t->tm_isdst == 0 || t->tm_isdst == 1) {
|
||||
p = strftime_add(p, pe, tzname[t->tm_isdst]);
|
||||
} else {
|
||||
p = strftime_add(p, pe, "?");
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case 'z':
|
||||
if (t->tm_isdst < 0) continue;
|
||||
#ifdef TM_GMTOFF
|
||||
diff = t->TM_GMTOFF;
|
||||
#else /* !defined TM_GMTOFF */
|
||||
if (t->tm_isdst == 0)
|
||||
#ifdef USG_COMPAT
|
||||
diff = -timezone;
|
||||
#else /* !defined USG_COMPAT */
|
||||
continue;
|
||||
#endif /* !defined USG_COMPAT */
|
||||
else
|
||||
#ifdef ALTZONE
|
||||
diff = -altzone;
|
||||
#else /* !defined ALTZONE */
|
||||
continue;
|
||||
#endif /* !defined ALTZONE */
|
||||
#endif /* !defined TM_GMTOFF */
|
||||
if (diff < 0) {
|
||||
sign = "-";
|
||||
diff = -diff;
|
||||
} else {
|
||||
sign = "+";
|
||||
}
|
||||
p = strftime_add(p, pe, sign);
|
||||
diff /= SECSPERMIN;
|
||||
diff = (diff / MINSPERHOUR) * 100 + (diff % MINSPERHOUR);
|
||||
p = strftime_conv(p, pe, diff, "%04d");
|
||||
continue;
|
||||
case '%':
|
||||
/*
|
||||
* X311J/88-090 (4.12.3.5): if conversion char is
|
||||
* undefined, behavior is undefined. Print out the
|
||||
* character itself as printf(3) also does.
|
||||
*/
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (p >= pe) break;
|
||||
*p++ = *format;
|
||||
}
|
||||
return p;
|
||||
case 'l':
|
||||
/*
|
||||
** This used to be...
|
||||
** _conv(t->tm_hour, 2, ' ');
|
||||
** ...and has been changed to the below to
|
||||
** match SunOS 4.1.1 and Arnold Robbin's
|
||||
** strftime version 3.0. That is, "%k" and
|
||||
** "%l" have been swapped.
|
||||
** (ado, 1993-05-24)
|
||||
*/
|
||||
pt = _conv((t->tm_hour % 12) ?
|
||||
(t->tm_hour % 12) : 12,
|
||||
"%2d", pt, ptlim);
|
||||
continue;
|
||||
case 'M':
|
||||
pt = _conv(t->tm_min, "%02d", pt, ptlim);
|
||||
continue;
|
||||
case 'm':
|
||||
pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);
|
||||
continue;
|
||||
case 'n':
|
||||
pt = _add("\n", pt, ptlim);
|
||||
continue;
|
||||
case 'p':
|
||||
pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
|
||||
Locale->pm :
|
||||
Locale->am,
|
||||
pt, ptlim);
|
||||
continue;
|
||||
case 'R':
|
||||
pt = _fmt("%H:%M", t, pt, ptlim, warnp);
|
||||
continue;
|
||||
case 'r':
|
||||
pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp);
|
||||
continue;
|
||||
case 'S':
|
||||
pt = _conv(t->tm_sec, "%02d", pt, ptlim);
|
||||
continue;
|
||||
case 's':
|
||||
{
|
||||
struct tm tm;
|
||||
char buf[INT_STRLEN_MAXIMUM(
|
||||
time_t) + 1];
|
||||
time_t mkt;
|
||||
|
||||
tm = *t;
|
||||
tm.tm_yday = -1;
|
||||
mkt = mktime(&tm);
|
||||
if (mkt == (time_t) -1) {
|
||||
/* Fail unless this -1 represents
|
||||
a valid time. */
|
||||
struct tm tm_1;
|
||||
if (!localtime_r(&mkt, &tm_1))
|
||||
return NULL;
|
||||
if (!(tm.tm_year == tm_1.tm_year
|
||||
&& tm.tm_yday == tm_1.tm_yday
|
||||
&& tm.tm_hour == tm_1.tm_hour
|
||||
&& tm.tm_min == tm_1.tm_min
|
||||
&& tm.tm_sec == tm_1.tm_sec))
|
||||
return NULL;
|
||||
}
|
||||
if (TYPE_SIGNED(time_t)) {
|
||||
intmax_t n = mkt;
|
||||
(sprintf)(buf, "%"PRIdMAX, n);
|
||||
} else {
|
||||
uintmax_t n = mkt;
|
||||
(sprintf)(buf, "%"PRIuMAX, n);
|
||||
}
|
||||
pt = _add(buf, pt, ptlim);
|
||||
}
|
||||
continue;
|
||||
case 'T':
|
||||
pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
|
||||
continue;
|
||||
case 't':
|
||||
pt = _add("\t", pt, ptlim);
|
||||
continue;
|
||||
case 'U':
|
||||
pt = _conv((t->tm_yday + DAYSPERWEEK -
|
||||
t->tm_wday) / DAYSPERWEEK,
|
||||
"%02d", pt, ptlim);
|
||||
continue;
|
||||
case 'u':
|
||||
/*
|
||||
** From Arnold Robbins' strftime version 3.0:
|
||||
** "ISO 8601: Weekday as a decimal number
|
||||
** [1 (Monday) - 7]"
|
||||
** (ado, 1993-05-24)
|
||||
*/
|
||||
pt = _conv((t->tm_wday == 0) ?
|
||||
DAYSPERWEEK : t->tm_wday,
|
||||
"%d", pt, ptlim);
|
||||
continue;
|
||||
case 'V': /* ISO 8601 week number */
|
||||
case 'G': /* ISO 8601 year (four digits) */
|
||||
case 'g': /* ISO 8601 year (two digits) */
|
||||
/*
|
||||
** From Arnold Robbins' strftime version 3.0: "the week number of the
|
||||
** year (the first Monday as the first day of week 1) as a decimal number
|
||||
** (01-53)."
|
||||
** (ado, 1993-05-24)
|
||||
**
|
||||
** From <https://www.cl.cam.ac.uk/~mgk25/iso-time.html> by Markus Kuhn:
|
||||
** "Week 01 of a year is per definition the first week which has the
|
||||
** Thursday in this year, which is equivalent to the week which contains
|
||||
** the fourth day of January. In other words, the first week of a new year
|
||||
** is the week which has the majority of its days in the new year. Week 01
|
||||
** might also contain days from the previous year and the week before week
|
||||
** 01 of a year is the last week (52 or 53) of the previous year even if
|
||||
** it contains days from the new year. A week starts with Monday (day 1)
|
||||
** and ends with Sunday (day 7). For example, the first week of the year
|
||||
** 1997 lasts from 1996-12-30 to 1997-01-05..."
|
||||
** (ado, 1996-01-02)
|
||||
*/
|
||||
{
|
||||
int year;
|
||||
int base;
|
||||
int yday;
|
||||
int wday;
|
||||
int w;
|
||||
|
||||
year = t->tm_year;
|
||||
base = TM_YEAR_BASE;
|
||||
yday = t->tm_yday;
|
||||
wday = t->tm_wday;
|
||||
for ( ; ; ) {
|
||||
int len;
|
||||
int bot;
|
||||
int top;
|
||||
|
||||
len = isleap_sum(year, base) ?
|
||||
DAYSPERLYEAR :
|
||||
DAYSPERNYEAR;
|
||||
/*
|
||||
** What yday (-3 ... 3) does
|
||||
** the ISO year begin on?
|
||||
*/
|
||||
bot = ((yday + 11 - wday) %
|
||||
DAYSPERWEEK) - 3;
|
||||
/*
|
||||
** What yday does the NEXT
|
||||
** ISO year begin on?
|
||||
*/
|
||||
top = bot -
|
||||
(len % DAYSPERWEEK);
|
||||
if (top < -3)
|
||||
top += DAYSPERWEEK;
|
||||
top += len;
|
||||
if (yday >= top) {
|
||||
++base;
|
||||
w = 1;
|
||||
break;
|
||||
}
|
||||
if (yday >= bot) {
|
||||
w = 1 + ((yday - bot) /
|
||||
DAYSPERWEEK);
|
||||
break;
|
||||
}
|
||||
--base;
|
||||
yday += isleap_sum(year, base) ?
|
||||
DAYSPERLYEAR :
|
||||
DAYSPERNYEAR;
|
||||
}
|
||||
if (*format == 'V')
|
||||
pt = _conv(w, "%02d",
|
||||
pt, ptlim);
|
||||
else if (*format == 'g') {
|
||||
*warnp = IN_ALL;
|
||||
pt = _yconv(year, base,
|
||||
false, true,
|
||||
pt, ptlim);
|
||||
} else pt = _yconv(year, base,
|
||||
true, true,
|
||||
pt, ptlim);
|
||||
}
|
||||
continue;
|
||||
case 'v':
|
||||
/*
|
||||
** From Arnold Robbins' strftime version 3.0:
|
||||
** "date as dd-bbb-YYYY"
|
||||
** (ado, 1993-05-24)
|
||||
*/
|
||||
pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
|
||||
continue;
|
||||
case 'W':
|
||||
pt = _conv((t->tm_yday + DAYSPERWEEK -
|
||||
(t->tm_wday ?
|
||||
(t->tm_wday - 1) :
|
||||
(DAYSPERWEEK - 1))) / DAYSPERWEEK,
|
||||
"%02d", pt, ptlim);
|
||||
continue;
|
||||
case 'w':
|
||||
pt = _conv(t->tm_wday, "%d", pt, ptlim);
|
||||
continue;
|
||||
case 'X':
|
||||
pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp);
|
||||
continue;
|
||||
case 'x':
|
||||
{
|
||||
enum warn warn2 = IN_SOME;
|
||||
|
||||
pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2);
|
||||
if (warn2 == IN_ALL)
|
||||
warn2 = IN_THIS;
|
||||
if (warn2 > *warnp)
|
||||
*warnp = warn2;
|
||||
}
|
||||
continue;
|
||||
case 'y':
|
||||
*warnp = IN_ALL;
|
||||
pt = _yconv(t->tm_year, TM_YEAR_BASE,
|
||||
false, true,
|
||||
pt, ptlim);
|
||||
continue;
|
||||
case 'Y':
|
||||
pt = _yconv(t->tm_year, TM_YEAR_BASE,
|
||||
true, true,
|
||||
pt, ptlim);
|
||||
continue;
|
||||
case 'Z':
|
||||
pt = _add(t->tm_zone, pt, ptlim);
|
||||
/*
|
||||
** C99 and later say that %Z must be
|
||||
** replaced by the empty string if the
|
||||
** time zone abbreviation is not
|
||||
** determinable.
|
||||
*/
|
||||
continue;
|
||||
case 'z':
|
||||
{
|
||||
long diff;
|
||||
char const * sign;
|
||||
bool negative;
|
||||
|
||||
diff = t->tm_gmtoff;
|
||||
negative = diff < 0;
|
||||
if (diff == 0) {
|
||||
negative = t->tm_zone[0] == '-';
|
||||
}
|
||||
if (negative) {
|
||||
sign = "-";
|
||||
diff = -diff;
|
||||
} else sign = "+";
|
||||
pt = _add(sign, pt, ptlim);
|
||||
diff /= SECSPERMIN;
|
||||
diff = (diff / MINSPERHOUR) * 100 +
|
||||
(diff % MINSPERHOUR);
|
||||
pt = _conv(diff, "%04d", pt, ptlim);
|
||||
}
|
||||
continue;
|
||||
case '+':
|
||||
pt = _fmt(Locale->date_fmt, t, pt, ptlim,
|
||||
warnp);
|
||||
continue;
|
||||
case '%':
|
||||
/*
|
||||
** X311J/88-090 (4.12.3.5): if conversion char is
|
||||
** undefined, behavior is undefined. Print out the
|
||||
** character itself as printf(3) also does.
|
||||
*/
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pt == ptlim)
|
||||
break;
|
||||
*pt++ = *format;
|
||||
}
|
||||
return pt;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -379,14 +554,32 @@ static char *strftime_timefmt(char *p, const char *pe, const char *format,
|
|||
*
|
||||
* @return bytes copied excluding nul, or 0 on error
|
||||
*/
|
||||
size_t strftime(char *s, size_t size, const char *f, const struct tm *t) {
|
||||
char *p;
|
||||
p = strftime_timefmt(s, s + size, f, t);
|
||||
if (p < s + size) {
|
||||
*p = '\0';
|
||||
return p - s;
|
||||
} else {
|
||||
s[size - 1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
size_t
|
||||
strftime(char *s, size_t maxsize, const char *format, const struct tm *t)
|
||||
{
|
||||
char * p;
|
||||
int saved_errno = errno;
|
||||
enum warn warn = IN_NONE;
|
||||
|
||||
tzset();
|
||||
p = _fmt(format, t, s, s + maxsize, &warn);
|
||||
if (!p) {
|
||||
errno = EOVERFLOW;
|
||||
return 0;
|
||||
}
|
||||
if (p == s + maxsize) {
|
||||
errno = ERANGE;
|
||||
return 0;
|
||||
}
|
||||
*p = '\0';
|
||||
errno = saved_errno;
|
||||
return p - s;
|
||||
}
|
||||
|
||||
size_t
|
||||
strftime_l(char *s, size_t maxsize, char const *format, struct tm const *t,
|
||||
locale_t locale)
|
||||
{
|
||||
/* Just call strftime, as only the C locale is supported. */
|
||||
return strftime(s, maxsize, format, t);
|
||||
}
|
||||
|
|
|
@ -67,6 +67,10 @@ o/$(MODE)/libc/time/strftime.o: \
|
|||
-fdata-sections \
|
||||
-ffunction-sections
|
||||
|
||||
o/$(MODE)/libc/time/localtime.o: \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
||||
o/$(MODE)/libc/time/now.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-O3
|
||||
|
|
542
libc/time/tz.internal.h
Normal file
542
libc/time/tz.internal.h
Normal file
|
@ -0,0 +1,542 @@
|
|||
#ifndef COSMOPOLITAN_THIRD_PARTY_TZ_PRIVATE_H_
|
||||
#define COSMOPOLITAN_THIRD_PARTY_TZ_PRIVATE_H_
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/inttypes.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
/* clang-format off */
|
||||
/* Private header for tzdb code. */
|
||||
|
||||
/*
|
||||
** This file is in the public domain, so clarified as of
|
||||
** 1996-06-05 by Arthur David Olson.
|
||||
*/
|
||||
|
||||
/*
|
||||
** This header is for use ONLY with the time conversion code.
|
||||
** There is no guarantee that it will remain unchanged,
|
||||
** or that it will remain at all.
|
||||
** Do NOT copy it to any system include directory.
|
||||
** Thank you!
|
||||
*/
|
||||
|
||||
/*
|
||||
** zdump has been made independent of the rest of the time
|
||||
** conversion package to increase confidence in the verification it provides.
|
||||
** You can use zdump to help in verifying other implementations.
|
||||
** To do this, compile with -DUSE_LTZ=0 and link without the tz library.
|
||||
*/
|
||||
#ifndef USE_LTZ
|
||||
# define USE_LTZ 1
|
||||
#endif
|
||||
|
||||
/* This string was in the Factory zone through version 2016f. */
|
||||
#define GRANDPARENTED "Local time zone must be set--see zic manual page"
|
||||
|
||||
/*
|
||||
** Defaults for preprocessor symbols.
|
||||
** You can override these in your C compiler options, e.g. '-DHAVE_GETTEXT=1'.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_DECL_ASCTIME_R
|
||||
#define HAVE_DECL_ASCTIME_R 1
|
||||
#endif
|
||||
|
||||
#if !defined HAVE_GENERIC && defined __has_extension
|
||||
# if __has_extension(c_generic_selections)
|
||||
# define HAVE_GENERIC 1
|
||||
# else
|
||||
# define HAVE_GENERIC 0
|
||||
# endif
|
||||
#endif
|
||||
/* _Generic is buggy in pre-4.9 GCC. */
|
||||
#if !defined HAVE_GENERIC && defined __GNUC__
|
||||
# define HAVE_GENERIC (4 < __GNUC__ + (9 <= __GNUC_MINOR__))
|
||||
#endif
|
||||
#ifndef HAVE_GENERIC
|
||||
# define HAVE_GENERIC (201112 <= __STDC_VERSION__)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETTEXT
|
||||
#define HAVE_GETTEXT 0
|
||||
#endif /* !defined HAVE_GETTEXT */
|
||||
|
||||
#ifndef HAVE_INCOMPATIBLE_CTIME_R
|
||||
#define HAVE_INCOMPATIBLE_CTIME_R 0
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_LINK
|
||||
#define HAVE_LINK 1
|
||||
#endif /* !defined HAVE_LINK */
|
||||
|
||||
#ifndef HAVE_MALLOC_ERRNO
|
||||
#define HAVE_MALLOC_ERRNO 1
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_POSIX_DECLS
|
||||
#define HAVE_POSIX_DECLS 1
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRTOLL
|
||||
#define HAVE_STRTOLL 1
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SYMLINK
|
||||
#define HAVE_SYMLINK 1
|
||||
#endif /* !defined HAVE_SYMLINK */
|
||||
|
||||
#if HAVE_INCOMPATIBLE_CTIME_R
|
||||
#define asctime_r _incompatible_asctime_r
|
||||
#define ctime_r _incompatible_ctime_r
|
||||
#endif /* HAVE_INCOMPATIBLE_CTIME_R */
|
||||
|
||||
/*
|
||||
** Nested includes
|
||||
*/
|
||||
|
||||
/* Avoid clashes with NetBSD by renaming NetBSD's declarations.
|
||||
If defining the 'timezone' variable, avoid a clash with FreeBSD's
|
||||
'timezone' function by renaming its declaration. */
|
||||
#define localtime_rz sys_localtime_rz
|
||||
#define mktime_z sys_mktime_z
|
||||
#define posix2time_z sys_posix2time_z
|
||||
#define time2posix_z sys_time2posix_z
|
||||
#if defined USG_COMPAT && USG_COMPAT == 2
|
||||
# define timezone sys_timezone
|
||||
#endif
|
||||
#define timezone_t sys_timezone_t
|
||||
#define tzalloc sys_tzalloc
|
||||
#define tzfree sys_tzfree
|
||||
#undef localtime_rz
|
||||
#undef mktime_z
|
||||
#undef posix2time_z
|
||||
#undef time2posix_z
|
||||
#if defined USG_COMPAT && USG_COMPAT == 2
|
||||
# undef timezone
|
||||
#endif
|
||||
#undef timezone_t
|
||||
#undef tzalloc
|
||||
#undef tzfree
|
||||
|
||||
#if HAVE_GETTEXT
|
||||
#include <libintl.h>
|
||||
#endif /* HAVE_GETTEXT */
|
||||
|
||||
#ifndef HAVE_STRFTIME_L
|
||||
# if _POSIX_VERSION < 200809
|
||||
# define HAVE_STRFTIME_L 0
|
||||
# else
|
||||
# define HAVE_STRFTIME_L 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef USG_COMPAT
|
||||
# ifndef _XOPEN_VERSION
|
||||
# define USG_COMPAT 0
|
||||
# else
|
||||
# define USG_COMPAT 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_TZNAME
|
||||
# if _POSIX_VERSION < 198808 && !USG_COMPAT
|
||||
# define HAVE_TZNAME 0
|
||||
# else
|
||||
# define HAVE_TZNAME 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef ALTZONE
|
||||
# if defined __sun || defined _M_XENIX
|
||||
# define ALTZONE 1
|
||||
# else
|
||||
# define ALTZONE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef R_OK
|
||||
#define R_OK 4
|
||||
#endif /* !defined R_OK */
|
||||
|
||||
#if 3 <= __GNUC__
|
||||
# define ATTRIBUTE_FORMAT(spec) __attribute__((__format__ spec))
|
||||
#else
|
||||
# define ATTRIBUTE_FORMAT(spec) /* empty */
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Workarounds for compilers/systems.
|
||||
*/
|
||||
|
||||
#ifndef EPOCH_LOCAL
|
||||
# define EPOCH_LOCAL 0
|
||||
#endif
|
||||
#ifndef EPOCH_OFFSET
|
||||
# define EPOCH_OFFSET 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Compile with -Dtime_tz=T to build the tz package with a private
|
||||
** int64_t type equivalent to T rather than the system-supplied int64_t.
|
||||
** This debugging feature can test unusual design decisions
|
||||
** (e.g., int64_t wider than 'long', or unsigned int64_t) even on
|
||||
** typical platforms.
|
||||
*/
|
||||
#if defined time_tz || EPOCH_LOCAL || EPOCH_OFFSET != 0
|
||||
# define TZ_INT64_T 1
|
||||
#else
|
||||
# define TZ_INT64_T 0
|
||||
#endif
|
||||
|
||||
#if defined LOCALTIME_IMPLEMENTATION && TZ_INT64_T
|
||||
static int64_t sys_time(int64_t *x) { return time(x); }
|
||||
#endif
|
||||
|
||||
#if TZ_INT64_T
|
||||
|
||||
typedef time_tz tz_int64_t;
|
||||
|
||||
# undef asctime
|
||||
# define asctime tz_asctime
|
||||
# undef asctime_r
|
||||
# define asctime_r tz_asctime_r
|
||||
# undef ctime
|
||||
# define ctime tz_ctime
|
||||
# undef ctime_r
|
||||
# define ctime_r tz_ctime_r
|
||||
# undef difftime
|
||||
# define difftime tz_difftime
|
||||
# undef gmtime
|
||||
# define gmtime tz_gmtime
|
||||
# undef gmtime_r
|
||||
# define gmtime_r tz_gmtime_r
|
||||
# undef localtime
|
||||
# define localtime tz_localtime
|
||||
# undef localtime_r
|
||||
# define localtime_r tz_localtime_r
|
||||
# undef localtime_rz
|
||||
# define localtime_rz tz_localtime_rz
|
||||
# undef mktime
|
||||
# define mktime tz_mktime
|
||||
# undef mktime_z
|
||||
# define mktime_z tz_mktime_z
|
||||
# undef offtime
|
||||
# define offtime tz_offtime
|
||||
# undef posix2time
|
||||
# define posix2time tz_posix2time
|
||||
# undef posix2time_z
|
||||
# define posix2time_z tz_posix2time_z
|
||||
# undef strftime
|
||||
# define strftime tz_strftime
|
||||
# undef time
|
||||
# define time tz_time
|
||||
# undef time2posix
|
||||
# define time2posix tz_time2posix
|
||||
# undef time2posix_z
|
||||
# define time2posix_z tz_time2posix_z
|
||||
# undef int64_t
|
||||
# define int64_t tz_int64_t
|
||||
# undef timegm
|
||||
# define timegm tz_timegm
|
||||
# undef timelocal
|
||||
# define timelocal tz_timelocal
|
||||
# undef timeoff
|
||||
# define timeoff tz_timeoff
|
||||
# undef tzalloc
|
||||
# define tzalloc tz_tzalloc
|
||||
# undef tzfree
|
||||
# define tzfree tz_tzfree
|
||||
# undef tzset
|
||||
# define tzset tz_tzset
|
||||
# if HAVE_STRFTIME_L
|
||||
# undef strftime_l
|
||||
# define strftime_l tz_strftime_l
|
||||
# endif
|
||||
# if HAVE_TZNAME
|
||||
# undef tzname
|
||||
# define tzname tz_tzname
|
||||
# endif
|
||||
# if USG_COMPAT
|
||||
# undef daylight
|
||||
# define daylight tz_daylight
|
||||
# undef timezone
|
||||
# define timezone tz_timezone
|
||||
# endif
|
||||
# if ALTZONE
|
||||
# undef altzone
|
||||
# define altzone tz_altzone
|
||||
# endif
|
||||
|
||||
char *asctime(struct tm const *);
|
||||
char *asctime_r(struct tm const *restrict, char *restrict);
|
||||
char *ctime(int64_t const *);
|
||||
char *ctime_r(int64_t const *, char *);
|
||||
double difftime(int64_t, int64_t) pureconst;
|
||||
size_t strftime(char *restrict, size_t, char const *restrict,
|
||||
struct tm const *restrict);
|
||||
# if HAVE_STRFTIME_L
|
||||
size_t strftime_l(char *restrict, size_t, char const *restrict,
|
||||
struct tm const *restrict, locale_t);
|
||||
# endif
|
||||
struct tm *gmtime(int64_t const *);
|
||||
struct tm *gmtime_r(int64_t const *restrict, struct tm *restrict);
|
||||
struct tm *localtime(int64_t const *);
|
||||
struct tm *localtime_r(int64_t const *restrict, struct tm *restrict);
|
||||
int64_t mktime(struct tm *);
|
||||
int64_t time(int64_t *);
|
||||
void tzset(void);
|
||||
#endif
|
||||
|
||||
#if !HAVE_DECL_ASCTIME_R && !defined asctime_r
|
||||
extern char *asctime_r(struct tm const *restrict, char *restrict);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DECL_ENVIRON
|
||||
# if defined environ || defined __USE_GNU
|
||||
# define HAVE_DECL_ENVIRON 1
|
||||
# else
|
||||
# define HAVE_DECL_ENVIRON 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if 2 <= HAVE_TZNAME + (TZ_INT64_T || !HAVE_POSIX_DECLS)
|
||||
extern char *tzname[];
|
||||
#endif
|
||||
#if 2 <= USG_COMPAT + (TZ_INT64_T || !HAVE_POSIX_DECLS)
|
||||
extern long timezone;
|
||||
extern int daylight;
|
||||
#endif
|
||||
#if 2 <= ALTZONE + (TZ_INT64_T || !HAVE_POSIX_DECLS)
|
||||
extern long altzone;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The STD_INSPIRED functions are similar, but most also need
|
||||
** declarations if time_tz is defined.
|
||||
*/
|
||||
|
||||
#ifdef STD_INSPIRED
|
||||
# if TZ_INT64_T || !defined offtime
|
||||
struct tm *offtime(int64_t const *, long);
|
||||
# endif
|
||||
# if TZ_INT64_T || !defined timegm
|
||||
int64_t timegm(struct tm *);
|
||||
# endif
|
||||
# if TZ_INT64_T || !defined timelocal
|
||||
int64_t timelocal(struct tm *);
|
||||
# endif
|
||||
# if TZ_INT64_T || !defined timeoff
|
||||
int64_t timeoff(struct tm *, long);
|
||||
# endif
|
||||
# if TZ_INT64_T || !defined time2posix
|
||||
int64_t time2posix(int64_t);
|
||||
# endif
|
||||
# if TZ_INT64_T || !defined posix2time
|
||||
int64_t posix2time(int64_t);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Infer TM_ZONE on systems where this information is known, but suppress
|
||||
guessing if NO_TM_ZONE is defined. Similarly for TM_GMTOFF. */
|
||||
#define TM_GMTOFF tm_gmtoff
|
||||
#define TM_ZONE tm_zone
|
||||
|
||||
/*
|
||||
** Define functions that are ABI compatible with NetBSD but have
|
||||
** better prototypes. NetBSD 6.1.4 defines a pointer type timezone_t
|
||||
** and labors under the misconception that 'const timezone_t' is a
|
||||
** pointer to a constant. This use of 'const' is ineffective, so it
|
||||
** is not done here. What we call 'struct state' NetBSD calls
|
||||
** 'struct __state', but this is a private name so it doesn't matter.
|
||||
*/
|
||||
#if NETBSD_INSPIRED
|
||||
typedef struct state *timezone_t;
|
||||
struct tm *localtime_rz(timezone_t restrict, int64_t const *restrict,
|
||||
struct tm *restrict);
|
||||
int64_t mktime_z(timezone_t restrict, struct tm *restrict);
|
||||
timezone_t tzalloc(char const *);
|
||||
void tzfree(timezone_t);
|
||||
# ifdef STD_INSPIRED
|
||||
# if TZ_INT64_T || !defined posix2time_z
|
||||
int64_t posix2time_z(timezone_t, int64_t) nosideeffect;
|
||||
# endif
|
||||
# if TZ_INT64_T || !defined time2posix_z
|
||||
int64_t time2posix_z(timezone_t, int64_t) nosideeffect;
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Finally, some convenience items.
|
||||
*/
|
||||
|
||||
#define TYPE_BIT(type) (sizeof(type) * CHAR_BIT)
|
||||
#define TYPE_SIGNED(type) (((type) -1) < 0)
|
||||
#define TWOS_COMPLEMENT(t) ((t) ~ (t) 0 < 0)
|
||||
|
||||
/* Max and min values of the integer type T, of which only the bottom
|
||||
B bits are used, and where the highest-order used bit is considered
|
||||
to be a sign bit if T is signed. */
|
||||
#define MAXVAL(t, b) \
|
||||
((t) (((t) 1 << ((b) - 1 - TYPE_SIGNED(t))) \
|
||||
- 1 + ((t) 1 << ((b) - 1 - TYPE_SIGNED(t)))))
|
||||
#define MINVAL(t, b) \
|
||||
((t) (TYPE_SIGNED(t) ? - TWOS_COMPLEMENT(t) - MAXVAL(t, b) : 0))
|
||||
|
||||
/* The extreme time values, assuming no padding. */
|
||||
#define INT64_T_MIN_NO_PADDING MINVAL(int64_t, TYPE_BIT(int64_t))
|
||||
#define INT64_T_MAX_NO_PADDING MAXVAL(int64_t, TYPE_BIT(int64_t))
|
||||
|
||||
/* The extreme time values. These are macros, not constants, so that
|
||||
any portability problems occur only when compiling .c files that use
|
||||
the macros, which is safer for applications that need only zdump and zic.
|
||||
This implementation assumes no padding if int64_t is signed and
|
||||
either the compiler lacks support for _Generic or int64_t is not one
|
||||
of the standard signed integer types. */
|
||||
#if HAVE_GENERIC
|
||||
# define INT64_T_MIN \
|
||||
_Generic((int64_t) 0, \
|
||||
signed char: SCHAR_MIN, short: SHRT_MIN, \
|
||||
int: INT_MIN, long: LONG_MIN, long long: LLONG_MIN, \
|
||||
default: INT64_T_MIN_NO_PADDING)
|
||||
# define INT64_T_MAX \
|
||||
(TYPE_SIGNED(int64_t) \
|
||||
? _Generic((int64_t) 0, \
|
||||
signed char: SCHAR_MAX, short: SHRT_MAX, \
|
||||
int: INT_MAX, long: LONG_MAX, long long: LLONG_MAX, \
|
||||
default: INT64_T_MAX_NO_PADDING) \
|
||||
: (int64_t) -1)
|
||||
#else
|
||||
# define INT64_T_MIN INT64_T_MIN_NO_PADDING
|
||||
# define INT64_T_MAX INT64_T_MAX_NO_PADDING
|
||||
#endif
|
||||
|
||||
/*
|
||||
** 302 / 1000 is log10(2.0) rounded up.
|
||||
** Subtract one for the sign bit if the type is signed;
|
||||
** add one for integer division truncation;
|
||||
** add one more for a minus sign if the type is signed.
|
||||
*/
|
||||
#define INT_STRLEN_MAXIMUM(type) \
|
||||
((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
|
||||
1 + TYPE_SIGNED(type))
|
||||
|
||||
/*
|
||||
** INITIALIZE(x)
|
||||
*/
|
||||
|
||||
#define INITIALIZE(x) ((x) = 0)
|
||||
|
||||
/* Whether memory access must strictly follow the C standard.
|
||||
If 0, it's OK to read uninitialized storage so long as the value is
|
||||
not relied upon. Defining it to 0 lets mktime access parts of
|
||||
struct tm that might be uninitialized, as a heuristic when the
|
||||
standard doesn't say what to return and when tm_gmtoff can help
|
||||
mktime likely infer a better value. */
|
||||
#ifndef UNINIT_TRAP
|
||||
# define UNINIT_TRAP 0
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
# define UNREACHABLE() abort()
|
||||
#elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__)
|
||||
# define UNREACHABLE() __builtin_unreachable()
|
||||
#elif defined __has_builtin
|
||||
# if __has_builtin(__builtin_unreachable)
|
||||
# define UNREACHABLE() __builtin_unreachable()
|
||||
# endif
|
||||
#endif
|
||||
#ifndef UNREACHABLE
|
||||
# define UNREACHABLE() ((void) 0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** For the benefit of GNU folk...
|
||||
** '_(MSGID)' uses the current locale's message library string for MSGID.
|
||||
** The default is to use gettext if available, and use MSGID otherwise.
|
||||
*/
|
||||
|
||||
#if HAVE_GETTEXT
|
||||
#define _(msgid) gettext(msgid)
|
||||
#else /* !HAVE_GETTEXT */
|
||||
#define _(msgid) msgid
|
||||
#endif /* !HAVE_GETTEXT */
|
||||
|
||||
#if !defined TZ_DOMAIN && defined HAVE_GETTEXT
|
||||
# define TZ_DOMAIN "tz"
|
||||
#endif
|
||||
|
||||
#if HAVE_INCOMPATIBLE_CTIME_R
|
||||
#undef asctime_r
|
||||
#undef ctime_r
|
||||
char *asctime_r(struct tm const *, char *);
|
||||
char *ctime_r(int64_t const *, char *);
|
||||
#endif /* HAVE_INCOMPATIBLE_CTIME_R */
|
||||
|
||||
/* Handy macros that are independent of tzfile implementation. */
|
||||
|
||||
#define SECSPERMIN 60
|
||||
#define MINSPERHOUR 60
|
||||
#define HOURSPERDAY 24
|
||||
#define DAYSPERWEEK 7
|
||||
#define DAYSPERNYEAR 365
|
||||
#define DAYSPERLYEAR 366
|
||||
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
|
||||
#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY)
|
||||
#define MONSPERYEAR 12
|
||||
|
||||
#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
|
||||
#define DAYSPERREPEAT ((int_fast32_t) 400 * 365 + 100 - 4 + 1)
|
||||
#define SECSPERREPEAT ((int_fast64_t) DAYSPERREPEAT * SECSPERDAY)
|
||||
#define AVGSECSPERYEAR (SECSPERREPEAT / YEARSPERREPEAT)
|
||||
|
||||
#define TM_SUNDAY 0
|
||||
#define TM_MONDAY 1
|
||||
#define TM_TUESDAY 2
|
||||
#define TM_WEDNESDAY 3
|
||||
#define TM_THURSDAY 4
|
||||
#define TM_FRIDAY 5
|
||||
#define TM_SATURDAY 6
|
||||
|
||||
#define TM_JANUARY 0
|
||||
#define TM_FEBRUARY 1
|
||||
#define TM_MARCH 2
|
||||
#define TM_APRIL 3
|
||||
#define TM_MAY 4
|
||||
#define TM_JUNE 5
|
||||
#define TM_JULY 6
|
||||
#define TM_AUGUST 7
|
||||
#define TM_SEPTEMBER 8
|
||||
#define TM_OCTOBER 9
|
||||
#define TM_NOVEMBER 10
|
||||
#define TM_DECEMBER 11
|
||||
|
||||
#define TM_YEAR_BASE 1900
|
||||
#define TM_WDAY_BASE TM_MONDAY
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
#define EPOCH_WDAY TM_THURSDAY
|
||||
|
||||
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
|
||||
|
||||
/*
|
||||
** Since everything in isleap is modulo 400 (or a factor of 400), we know that
|
||||
** isleap(y) == isleap(y % 400)
|
||||
** and so
|
||||
** isleap(a + b) == isleap((a + b) % 400)
|
||||
** or
|
||||
** isleap(a + b) == isleap(a % 400 + b % 400)
|
||||
** This is true even if % means modulo rather than Fortran remainder
|
||||
** (which is allowed by C89 but not by C99 or later).
|
||||
** We use this to avoid addition overflow problems.
|
||||
*/
|
||||
|
||||
#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_THIRD_PARTY_TZ_PRIVATE_H_ */
|
|
@ -1,46 +1,56 @@
|
|||
#ifndef TZFILE_H
|
||||
#define TZFILE_H
|
||||
|
||||
#define TM_ZONE tm_zone
|
||||
#define TM_GMTOFF tm_gmtoff
|
||||
/* clang-format off */
|
||||
/* Layout and location of TZif files. */
|
||||
|
||||
/*
|
||||
** This file is in the public domain, so clarified as of
|
||||
** 1996-06-05 by Arthur David Olson.
|
||||
*/
|
||||
|
||||
/*
|
||||
** This header is for use ONLY with the time conversion code.
|
||||
** There is no guarantee that it will remain unchanged,
|
||||
** or that it will remain at all.
|
||||
** Do NOT copy it to any system include directory.
|
||||
** Thank you!
|
||||
*/
|
||||
|
||||
/*
|
||||
** Information about time zone files.
|
||||
*/
|
||||
|
||||
#ifndef TZDIR
|
||||
#define TZDIR "/zip/usr/share/zoneinfo"
|
||||
#endif
|
||||
#define TZDIR "/zip/usr/share/zoneinfo" /* Time zone object file directory */
|
||||
#endif /* !defined TZDIR */
|
||||
|
||||
#ifndef TZDEFAULT
|
||||
#define TZDEFAULT "GST"
|
||||
#endif
|
||||
#define TZDEFAULT "GST"
|
||||
#endif /* !defined TZDEFAULT */
|
||||
|
||||
#ifndef TZDEFRULES
|
||||
#define TZDEFRULES "New_York"
|
||||
#endif
|
||||
#define TZDEFRULES "New_York"
|
||||
#endif /* !defined TZDEFRULES */
|
||||
|
||||
|
||||
/* See Internet RFC 8536 for more details about the following format. */
|
||||
|
||||
/*
|
||||
** Each file begins with. . .
|
||||
*/
|
||||
|
||||
#define TZ_MAGIC "TZif"
|
||||
#define TZ_MAGIC "TZif"
|
||||
|
||||
struct tzhead {
|
||||
char tzh_magic[4]; /* TZ_MAGIC */
|
||||
char tzh_version[1]; /* '\0' or '2' or '3' as of 2013 */
|
||||
char tzh_reserved[15]; /* reserved; must be zero */
|
||||
char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
|
||||
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
|
||||
char tzh_leapcnt[4]; /* coded number of leap seconds */
|
||||
char tzh_timecnt[4]; /* coded number of transition times */
|
||||
char tzh_typecnt[4]; /* coded number of local time types */
|
||||
char tzh_charcnt[4]; /* coded number of abbr. chars */
|
||||
char tzh_magic[4]; /* TZ_MAGIC */
|
||||
char tzh_version[1]; /* '\0' or '2'-'4' as of 2021 */
|
||||
char tzh_reserved[15]; /* reserved; must be zero */
|
||||
char tzh_ttisutcnt[4]; /* coded number of trans. time flags */
|
||||
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
|
||||
char tzh_leapcnt[4]; /* coded number of leap seconds */
|
||||
char tzh_timecnt[4]; /* coded number of transition times */
|
||||
char tzh_typecnt[4]; /* coded number of local time types */
|
||||
char tzh_charcnt[4]; /* coded number of abbr. chars */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -58,14 +68,15 @@ struct tzhead {
|
|||
** one (char [4]) total correction after above
|
||||
** tzh_ttisstdcnt (char)s indexed by type; if 1, transition
|
||||
** time is standard time, if 0,
|
||||
** transition time is wall clock time
|
||||
** if absent, transition times are
|
||||
** assumed to be wall clock time
|
||||
** tzh_ttisgmtcnt (char)s indexed by type; if 1, transition
|
||||
** time is UT, if 0,
|
||||
** transition time is local time
|
||||
** if absent, transition times are
|
||||
** transition time is local (wall clock)
|
||||
** time; if absent, transition times are
|
||||
** assumed to be local time
|
||||
** tzh_ttisutcnt (char)s indexed by type; if 1, transition
|
||||
** time is UT, if 0, transition time is
|
||||
** local time; if absent, transition
|
||||
** times are assumed to be local time.
|
||||
** When this is 1, the corresponding
|
||||
** std/wall indicator must also be 1.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -91,73 +102,21 @@ struct tzhead {
|
|||
*/
|
||||
|
||||
#ifndef TZ_MAX_TIMES
|
||||
#define TZ_MAX_TIMES 1200
|
||||
#define TZ_MAX_TIMES 2000
|
||||
#endif /* !defined TZ_MAX_TIMES */
|
||||
|
||||
#ifndef TZ_MAX_TYPES
|
||||
/* This must be at least 17 for Europe/Samara and Europe/Vilnius. */
|
||||
#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
|
||||
#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
|
||||
#endif /* !defined TZ_MAX_TYPES */
|
||||
|
||||
#ifndef TZ_MAX_CHARS
|
||||
#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
|
||||
/* (limited by what unsigned chars can hold) */
|
||||
#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
|
||||
/* (limited by what unsigned chars can hold) */
|
||||
#endif /* !defined TZ_MAX_CHARS */
|
||||
|
||||
#ifndef TZ_MAX_LEAPS
|
||||
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
|
||||
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
|
||||
#endif /* !defined TZ_MAX_LEAPS */
|
||||
|
||||
#define SECSPERMIN 60
|
||||
#define MINSPERHOUR 60
|
||||
#define HOURSPERDAY 24
|
||||
#define DAYSPERWEEK 7
|
||||
#define DAYSPERNYEAR 365
|
||||
#define DAYSPERLYEAR 366
|
||||
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
|
||||
#define SECSPERDAY ((int_fast32_t)SECSPERHOUR * HOURSPERDAY)
|
||||
#define MONSPERYEAR 12
|
||||
|
||||
#define TM_SUNDAY 0
|
||||
#define TM_MONDAY 1
|
||||
#define TM_TUESDAY 2
|
||||
#define TM_WEDNESDAY 3
|
||||
#define TM_THURSDAY 4
|
||||
#define TM_FRIDAY 5
|
||||
#define TM_SATURDAY 6
|
||||
|
||||
#define TM_JANUARY 0
|
||||
#define TM_FEBRUARY 1
|
||||
#define TM_MARCH 2
|
||||
#define TM_APRIL 3
|
||||
#define TM_MAY 4
|
||||
#define TM_JUNE 5
|
||||
#define TM_JULY 6
|
||||
#define TM_AUGUST 7
|
||||
#define TM_SEPTEMBER 8
|
||||
#define TM_OCTOBER 9
|
||||
#define TM_NOVEMBER 10
|
||||
#define TM_DECEMBER 11
|
||||
|
||||
#define TM_YEAR_BASE 1900
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
#define EPOCH_WDAY TM_THURSDAY
|
||||
|
||||
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
|
||||
|
||||
/*
|
||||
** Since everything in isleap is modulo 400 (or a factor of 400), we know that
|
||||
** isleap(y) == isleap(y % 400)
|
||||
** and so
|
||||
** isleap(a + b) == isleap((a + b) % 400)
|
||||
** or
|
||||
** isleap(a + b) == isleap(a % 400 + b % 400)
|
||||
** This is true even if % means modulo rather than Fortran remainder
|
||||
** (which is allowed by C89 but not C99).
|
||||
** We use this to avoid addition overflow problems.
|
||||
*/
|
||||
|
||||
#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
|
||||
|
||||
#endif /* !defined TZFILE_H */
|
||||
|
|
2
third_party/chibicc/chibicc.mk
vendored
2
third_party/chibicc/chibicc.mk
vendored
|
@ -116,7 +116,7 @@ o/$(MODE)/third_party/chibicc/chibicc.com: \
|
|||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/third_party/chibicc/.chibicc/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/third_party/chibicc/.chibicc/.symtab
|
||||
|
||||
o/$(MODE)/third_party/chibicc/as.com.dbg: \
|
||||
|
|
15
third_party/linenoise/linenoise.c
vendored
15
third_party/linenoise/linenoise.c
vendored
|
@ -339,7 +339,7 @@ static int notwseparator(wint_t c) {
|
|||
}
|
||||
|
||||
static int iswname(wint_t c) {
|
||||
return !iswseparator(c) || c == '_' || c == '-' || c == '.';
|
||||
return !iswseparator(c) || c == '_' || c == '-' || c == '.' || c == ':';
|
||||
}
|
||||
|
||||
static int notwname(wint_t c) {
|
||||
|
@ -1956,23 +1956,22 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf,
|
|||
|
||||
// handle tab and tab-tab completion
|
||||
if (seq[0] == '\t' && completionCallback) {
|
||||
size_t i, j, k, n, m, itemlen;
|
||||
size_t i, n, m;
|
||||
// we know that the user pressed tab once
|
||||
rc = 0;
|
||||
linenoiseFreeCompletions(&l->lc);
|
||||
i = Backwards(l, l->pos, iswname);
|
||||
j = l->pos;
|
||||
{
|
||||
char *s = strndup(l->buf + i, j - i);
|
||||
char *s = strndup(l->buf + i, l->pos - i);
|
||||
completionCallback(s, &l->lc);
|
||||
free(s);
|
||||
}
|
||||
m = GetCommonPrefixLength(&l->lc);
|
||||
if (m > j - i || (m == j - i && l->lc.len == 1)) {
|
||||
if (m > l->pos - i || (m == l->pos - i && l->lc.len == 1)) {
|
||||
// on common prefix (or single completion) we complete and return
|
||||
n = i + m + (l->len - j);
|
||||
n = i + m + (l->len - l->pos);
|
||||
if (linenoiseGrow(l, n + 1)) {
|
||||
memmove(l->buf + i + m, l->buf + i + j, l->len - j + 1);
|
||||
memmove(l->buf + i + m, l->buf + l->pos, l->len - l->pos + 1);
|
||||
memcpy(l->buf + i, l->lc.cvec[0], m);
|
||||
l->pos = i + m;
|
||||
l->len = n;
|
||||
|
@ -1994,7 +1993,7 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf,
|
|||
if (rc == 1 && seq[0] == '\t') {
|
||||
const char **p;
|
||||
struct abuf ab;
|
||||
int i, x, y, xn, yn, xy;
|
||||
int i, k, x, y, xn, yn, xy, itemlen;
|
||||
itemlen = linenoiseMaxCompletionWidth(&l->lc) + 4;
|
||||
xn = MAX(1, (l->ws.ws_col - 1) / itemlen);
|
||||
yn = (l->lc.len + (xn - 1)) / xn;
|
||||
|
|
4
third_party/lua/cosmo.h
vendored
4
third_party/lua/cosmo.h
vendored
|
@ -8,8 +8,8 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
char *LuaFormatStack(lua_State *) dontdiscard;
|
||||
int LuaCallWithTrace(lua_State *, int, int, lua_State *);
|
||||
int LuaEncodeJsonData(lua_State *, char **, int, char *, int);
|
||||
int LuaEncodeLuaData(lua_State *, char **, int, char *, int);
|
||||
int LuaEncodeJsonData(lua_State *, char **, char *, int);
|
||||
int LuaEncodeLuaData(lua_State *, char **, char *, int);
|
||||
int LuaEncodeUrl(lua_State *);
|
||||
int LuaParseUrl(lua_State *);
|
||||
int LuaPushHeader(lua_State *, struct HttpMessage *, char *, int);
|
||||
|
|
3
third_party/lua/ldo.c
vendored
3
third_party/lua/ldo.c
vendored
|
@ -27,6 +27,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ldo_c
|
||||
#define LUA_CORE
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "third_party/lua/lapi.h"
|
||||
#include "third_party/lua/ldebug.h"
|
||||
|
@ -148,7 +149,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
|
|||
lua_unlock(L);
|
||||
g->panic(L); /* call panic function (last chance to jump out) */
|
||||
}
|
||||
abort();
|
||||
__die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
73
third_party/lua/lrepl.c
vendored
73
third_party/lua/lrepl.c
vendored
|
@ -29,15 +29,18 @@
|
|||
#include "libc/alg/alg.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/linenoise/linenoise.h"
|
||||
#include "third_party/lua/cosmo.h"
|
||||
#include "third_party/lua/lauxlib.h"
|
||||
#include "third_party/lua/lprefix.h"
|
||||
#include "third_party/lua/lrepl.h"
|
||||
|
@ -87,37 +90,74 @@ static const char *g_historypath;
|
|||
#endif
|
||||
|
||||
|
||||
static void lua_readline_addcompletion (linenoiseCompletions *c, const char *s) {
|
||||
char **p, *t;
|
||||
static void lua_readline_addcompletion (linenoiseCompletions *c, char *s) {
|
||||
char **p;
|
||||
if ((p = realloc(c->cvec, (c->len + 1) * sizeof(*p)))) {
|
||||
c->cvec = p;
|
||||
if ((t = strdup(s))) {
|
||||
c->cvec[c->len++] = t;
|
||||
}
|
||||
c->cvec[c->len++] = s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void lua_readline_completions (const char *p, linenoiseCompletions *c) {
|
||||
int i;
|
||||
bool found;
|
||||
lua_State *L;
|
||||
const char *name;
|
||||
for (i = 0; i < ARRAYLEN(kKeywordHints); ++i) {
|
||||
if (startswithi(kKeywordHints[i], p)) {
|
||||
lua_readline_addcompletion(c, kKeywordHints[i]);
|
||||
}
|
||||
}
|
||||
char *a, *b, *component;
|
||||
|
||||
// start searching globals
|
||||
L = globalL;
|
||||
lua_pushglobaltable(L);
|
||||
|
||||
// traverse parent objects
|
||||
// split foo.bar and foo:bar
|
||||
a = p;
|
||||
b = strpbrk(a, ".:");
|
||||
while (b) {
|
||||
component = strndup(a, b - a);
|
||||
found = false;
|
||||
lua_pushnil(L); // search key
|
||||
while (lua_next(L, -2)) {
|
||||
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||
name = lua_tostring(L, -2);
|
||||
if (!strcmp(name, component)) {
|
||||
lua_remove(L, -3); // remove table
|
||||
lua_remove(L, -2); // remove key
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1); // pop value
|
||||
}
|
||||
free(component);
|
||||
if (!found) {
|
||||
lua_pop(L, 1); // pop table
|
||||
return;
|
||||
}
|
||||
a = b + 1;
|
||||
b = strpbrk(a, ".:");
|
||||
}
|
||||
|
||||
// search final object
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0) {
|
||||
name = lua_tostring(L, -2);
|
||||
if (startswithi(name, p)) {
|
||||
lua_readline_addcompletion(c, name);
|
||||
while (lua_next(L, -2)) {
|
||||
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||
name = lua_tostring(L, -2);
|
||||
if (startswithi(name, a)) {
|
||||
lua_readline_addcompletion(c, xasprintf("%.*s%s", a - p, p, name));
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
for (i = 0; i < ARRAYLEN(kKeywordHints); ++i) {
|
||||
if (startswithi(kKeywordHints[i], p)) {
|
||||
lua_readline_addcompletion(c, xstrdup(kKeywordHints[i]));
|
||||
}
|
||||
}
|
||||
if (lua_repl_completions_callback) {
|
||||
lua_repl_completions_callback(p, c);
|
||||
}
|
||||
|
@ -191,7 +231,7 @@ static ssize_t pushline (lua_State *L, int firstline) {
|
|||
prmt = strdup(get_prompt(L, firstline));
|
||||
lua_pop(L, 1); /* remove prompt */
|
||||
LUA_REPL_UNLOCK;
|
||||
rc = linenoiseEdit(lua_repl_linenoise, 0, &b, !firstline || lua_repl_blocking);
|
||||
rc = linenoiseEdit(lua_repl_linenoise, prmt, &b, !firstline || lua_repl_blocking);
|
||||
free(prmt);
|
||||
if (rc != -1) {
|
||||
if (b && *b) {
|
||||
|
@ -207,6 +247,9 @@ static ssize_t pushline (lua_State *L, int firstline) {
|
|||
LUA_REPL_LOCK;
|
||||
rc = b ? 1 : -1;
|
||||
}
|
||||
if (!(rc == -1 && errno == EAGAIN)) {
|
||||
write(1, "\n", 1);
|
||||
}
|
||||
if (rc == -1 || (!rc && !b)) {
|
||||
return rc;
|
||||
}
|
||||
|
|
2
third_party/lua/ltests.c
vendored
2
third_party/lua/ltests.c
vendored
|
@ -1724,7 +1724,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
|
|||
lua_error(L1);
|
||||
}
|
||||
else if EQ("abort") {
|
||||
abort();
|
||||
__die();
|
||||
}
|
||||
else if EQ("throw") {
|
||||
#if defined(__cplusplus)
|
||||
|
|
2
third_party/lua/lua.main.c
vendored
2
third_party/lua/lua.main.c
vendored
|
@ -324,7 +324,6 @@ static void doREPL (lua_State *L) {
|
|||
progname = oldprogname;
|
||||
return;
|
||||
}
|
||||
lua_writeline();
|
||||
if (status == LUA_OK)
|
||||
status = lua_runchunk(L, 0, LUA_MULTRET);
|
||||
if (status == LUA_OK) {
|
||||
|
@ -335,7 +334,6 @@ static void doREPL (lua_State *L) {
|
|||
}
|
||||
lua_freerepl();
|
||||
lua_settop(L, 0); /* clear stack */
|
||||
lua_writeline();
|
||||
progname = oldprogname;
|
||||
}
|
||||
|
||||
|
|
2
third_party/lua/lua.mk
vendored
2
third_party/lua/lua.mk
vendored
|
@ -77,7 +77,7 @@ o/$(MODE)/third_party/lua/lua.com: \
|
|||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/third_party/lua/.lua/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/third_party/lua/.lua/.symtab
|
||||
|
||||
o//third_party/lua/lgc.o: \
|
||||
|
|
14
third_party/lua/luaencodejsondata.c
vendored
14
third_party/lua/luaencodejsondata.c
vendored
|
@ -25,8 +25,8 @@
|
|||
#include "third_party/lua/lauxlib.h"
|
||||
#include "third_party/lua/lua.h"
|
||||
|
||||
int LuaEncodeJsonData(lua_State *L, char **buf, int level, char *numformat,
|
||||
int idx) {
|
||||
static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
||||
char *numformat, int idx) {
|
||||
char *s;
|
||||
bool isarray;
|
||||
size_t tbllen, z;
|
||||
|
@ -93,7 +93,7 @@ int LuaEncodeJsonData(lua_State *L, char **buf, int level, char *numformat,
|
|||
for (size_t i = 1; i <= tbllen; i++) {
|
||||
if (i > 1) appendw(buf, ',');
|
||||
lua_rawgeti(L, -1, i); // table/-2, value/-1
|
||||
LuaEncodeJsonData(L, buf, level - 1, numformat, -1);
|
||||
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
} else {
|
||||
|
@ -121,7 +121,7 @@ int LuaEncodeJsonData(lua_State *L, char **buf, int level, char *numformat,
|
|||
lua_remove(L, -1); // remove copied key: tab/-3, key/-2, val/-1
|
||||
}
|
||||
appendw(buf, '"' | ':' << 010);
|
||||
LuaEncodeJsonData(L, buf, level - 1, numformat, -1);
|
||||
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1);
|
||||
lua_pop(L, 1); // table/-2, key/-1
|
||||
}
|
||||
// stack: table/-1, as the key was popped by lua_next
|
||||
|
@ -137,3 +137,9 @@ int LuaEncodeJsonData(lua_State *L, char **buf, int level, char *numformat,
|
|||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
int LuaEncodeJsonData(lua_State *L, char **buf, char *numformat, int idx) {
|
||||
int rc;
|
||||
rc = LuaEncodeJsonDataImpl(L, buf, 64, numformat, idx);
|
||||
return rc;
|
||||
}
|
||||
|
|
118
third_party/lua/luaencodeluadata.c
vendored
118
third_party/lua/luaencodeluadata.c
vendored
|
@ -16,42 +16,98 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/lua/cosmo.h"
|
||||
#include "third_party/lua/lauxlib.h"
|
||||
#include "third_party/lua/lua.h"
|
||||
|
||||
int LuaEncodeLuaData(lua_State *L, char **buf, int level, char *numformat,
|
||||
int idx) {
|
||||
struct Visited {
|
||||
int n;
|
||||
void **p;
|
||||
};
|
||||
|
||||
static bool PushVisit(struct Visited *visited, void *p) {
|
||||
int i;
|
||||
for (i = 0; i < visited->n; ++i) {
|
||||
if (visited->p[i] == p) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
visited->p = xrealloc(visited->p, ++visited->n * sizeof(*visited->p));
|
||||
visited->p[visited->n - 1] = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void PopVisit(struct Visited *visited) {
|
||||
assert(visited->n > 0);
|
||||
--visited->n;
|
||||
}
|
||||
|
||||
static int LuaEncodeLuaDataImpl(lua_State *L, char **buf, int level,
|
||||
char *numformat, int idx,
|
||||
struct Visited *visited) {
|
||||
char *s;
|
||||
int ktype;
|
||||
bool didcomma;
|
||||
lua_Integer i;
|
||||
int ktype, vtype;
|
||||
size_t tbllen, buflen, slen;
|
||||
char ibuf[21], fmt[] = "%.14g";
|
||||
if (level > 0) {
|
||||
switch (lua_type(L, idx)) {
|
||||
|
||||
case LUA_TNIL:
|
||||
appendw(buf, READ32LE("nil"));
|
||||
return 0;
|
||||
|
||||
case LUA_TSTRING:
|
||||
s = lua_tolstring(L, idx, &slen);
|
||||
EscapeLuaString(s, slen, buf);
|
||||
return 0;
|
||||
|
||||
case LUA_TFUNCTION:
|
||||
appendf(buf, "\"func@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
case LUA_TUSERDATA:
|
||||
appendf(buf, "\"udata@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
appendf(buf, "\"light@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
|
||||
case LUA_TTHREAD:
|
||||
appendf(buf, "\"thread@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
|
||||
case LUA_TUSERDATA:
|
||||
if (luaL_callmeta(L, idx, "__repr")) {
|
||||
if (lua_type(L, -1) == LUA_TSTRING) {
|
||||
s = lua_tolstring(L, -1, &slen);
|
||||
appendd(buf, s, slen);
|
||||
} else {
|
||||
appendf(buf, "[[error %s returned a %s value]]", "__repr",
|
||||
luaL_typename(L, -1));
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
return 0;
|
||||
}
|
||||
if (luaL_callmeta(L, idx, "__tostring")) {
|
||||
if (lua_type(L, -1) == LUA_TSTRING) {
|
||||
s = lua_tolstring(L, -1, &slen);
|
||||
EscapeLuaString(s, slen, buf);
|
||||
} else {
|
||||
appendf(buf, "[[error %s returned a %s value]]", "__tostring",
|
||||
luaL_typename(L, -1));
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
return 0;
|
||||
}
|
||||
appendf(buf, "\"udata@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
|
||||
case LUA_TNUMBER:
|
||||
if (lua_isinteger(L, idx)) {
|
||||
appendd(buf, ibuf,
|
||||
|
@ -69,11 +125,13 @@ int LuaEncodeLuaData(lua_State *L, char **buf, int level, char *numformat,
|
|||
fmt[4] = *numformat;
|
||||
break;
|
||||
default:
|
||||
return luaL_error(L, "numformat string not allowed");
|
||||
luaL_error(L, "numformat string not allowed");
|
||||
unreachable;
|
||||
}
|
||||
appendf(buf, fmt, lua_tonumber(L, idx));
|
||||
}
|
||||
return 0;
|
||||
|
||||
case LUA_TBOOLEAN:
|
||||
if (lua_toboolean(L, idx)) {
|
||||
appendw(buf, READ32LE("true"));
|
||||
|
@ -81,26 +139,47 @@ int LuaEncodeLuaData(lua_State *L, char **buf, int level, char *numformat,
|
|||
appendw(buf, READ64LE("false\0\0"));
|
||||
}
|
||||
return 0;
|
||||
|
||||
case LUA_TTABLE:
|
||||
i = 0;
|
||||
didcomma = false;
|
||||
appendw(buf, '{');
|
||||
lua_pushvalue(L, idx);
|
||||
lua_pushnil(L); // push the first key
|
||||
while (lua_next(L, -2) != 0) {
|
||||
while (lua_next(L, -2)) {
|
||||
++i;
|
||||
ktype = lua_type(L, -2);
|
||||
if (i++ > 0) appendw(buf, ',');
|
||||
vtype = lua_type(L, -1);
|
||||
if (ktype != LUA_TNUMBER || lua_tointeger(L, -2) != i) {
|
||||
appendw(buf, '[');
|
||||
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
|
||||
LuaEncodeLuaData(L, buf, level - 1, numformat, -1);
|
||||
lua_remove(L, -1); // remove copied key: table/-3, key/-2, value/-1
|
||||
appendw(buf, ']' | '=' << 010);
|
||||
if (PushVisit(visited, lua_touserdata(L, -2))) {
|
||||
if (i > 1) appendw(buf, ',' | ' ' << 8);
|
||||
didcomma = true;
|
||||
appendw(buf, '[');
|
||||
LuaEncodeLuaDataImpl(L, buf, level - 1, numformat, -2, visited);
|
||||
appendw(buf, ']' | '=' << 010);
|
||||
PopVisit(visited);
|
||||
} else {
|
||||
// TODO: Strange Lua data structure, do nothing.
|
||||
lua_pop(L, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (PushVisit(visited, lua_touserdata(L, -1))) {
|
||||
if (!didcomma && i > 1) appendw(buf, ',' | ' ' << 8);
|
||||
LuaEncodeLuaDataImpl(L, buf, level - 1, numformat, -1, visited);
|
||||
PopVisit(visited);
|
||||
} else {
|
||||
// TODO: Strange Lua data structure, do nothing.
|
||||
lua_pop(L, 1);
|
||||
continue;
|
||||
}
|
||||
LuaEncodeLuaData(L, buf, level - 1, numformat, -1);
|
||||
lua_pop(L, 1); // table/-2, key/-1
|
||||
}
|
||||
lua_pop(L, 1); // table
|
||||
// stack: table/-1, as the key was popped by lua_next
|
||||
appendw(buf, '}');
|
||||
return 0;
|
||||
|
||||
default:
|
||||
luaL_error(L, "can't serialize value of this type");
|
||||
unreachable;
|
||||
|
@ -110,3 +189,12 @@ int LuaEncodeLuaData(lua_State *L, char **buf, int level, char *numformat,
|
|||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
int LuaEncodeLuaData(lua_State *L, char **buf, char *numformat, int idx) {
|
||||
int rc;
|
||||
struct Visited visited = {0};
|
||||
rc = LuaEncodeLuaDataImpl(L, buf, 64, numformat, idx, &visited);
|
||||
assert(!visited.n);
|
||||
free(visited.p);
|
||||
return rc;
|
||||
}
|
||||
|
|
2
third_party/lua/luaformatstack.c
vendored
2
third_party/lua/luaformatstack.c
vendored
|
@ -28,7 +28,7 @@ dontdiscard char *LuaFormatStack(lua_State *L) {
|
|||
for (i = 1; i <= top; i++) {
|
||||
if (i > 1) appendw(&b, '\n');
|
||||
appendf(&b, "\t%d\t%s\t", i, luaL_typename(L, i));
|
||||
LuaEncodeLuaData(L, &b, 64, "g", -1);
|
||||
LuaEncodeLuaData(L, &b, "g", i);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
|
2
third_party/make/make.mk
vendored
2
third_party/make/make.mk
vendored
|
@ -131,7 +131,7 @@ o/$(MODE)/third_party/make/make.com: \
|
|||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/third_party/make/.make/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/third_party/make/.make/.symtab
|
||||
|
||||
$(THIRD_PARTY_MAKE_OBJS): \
|
||||
|
|
2
third_party/python/python.mk
vendored
2
third_party/python/python.mk
vendored
|
@ -4197,7 +4197,7 @@ o/$(MODE)/third_party/python/python.com: \
|
|||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/third_party/python/.python/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/third_party/python/.python/.symtab
|
||||
|
||||
################################################################################
|
||||
|
|
2
third_party/quickjs/quickjs.mk
vendored
2
third_party/quickjs/quickjs.mk
vendored
|
@ -154,7 +154,7 @@ o/$(MODE)/third_party/quickjs/qjs.com: \
|
|||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/third_party/quickjs/.qjs/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/third_party/quickjs/.qjs/.symtab
|
||||
|
||||
o/$(MODE)/third_party/quickjs/qjsc.com.dbg: \
|
||||
|
|
2
third_party/sqlite3/sqlite3.mk
vendored
2
third_party/sqlite3/sqlite3.mk
vendored
|
@ -83,7 +83,7 @@ o/$(MODE)/third_party/sqlite3/sqlite3.com: \
|
|||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/third_party/sqlite3/.sqlite3/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/third_party/sqlite3/.sqlite3/.symtab
|
||||
|
||||
$(THIRD_PARTY_SQLITE3_A): \
|
||||
|
|
|
@ -97,7 +97,7 @@ o/$(MODE)/tool/build/blinkenlights.com: \
|
|||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/tool/build/.blinkenlights/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/tool/build/.blinkenlights/.symtab
|
||||
|
||||
o/$(MODE)/tool/build/ar.com.dbg: \
|
||||
|
|
|
@ -585,7 +585,6 @@ FUNCTIONS
|
|||
ignored if used outside of request handling code.
|
||||
- numformat: sets numeric format to be used, which can be 'g',
|
||||
'f', or 'a' [experimental api]
|
||||
- maxdepth: (number=64) sets the max number of nested tables.
|
||||
|
||||
EncodeLua(value[,options:table]) → json:str
|
||||
Turns passed Lua value into a Lua string. The following options
|
||||
|
@ -593,7 +592,6 @@ FUNCTIONS
|
|||
- useoutput: (bool=false) encodes the result directly to the
|
||||
output buffer and returns `nil` value. This option is
|
||||
ignored if used outside of request handling code.
|
||||
- maxdepth: (number=64) sets the max number of nested tables.
|
||||
|
||||
EncodeLatin1(utf-8:str[,flags:int]) → iso-8859-1:str
|
||||
Turns UTF-8 into ISO-8859-1 string.
|
||||
|
@ -1421,11 +1419,12 @@ UNIX MODULE
|
|||
|
||||
The following values may also be OR'd into `flags`:
|
||||
|
||||
- `O_CREAT`: create file if it doesn't exist
|
||||
- `O_CREAT` create file if it doesn't exist
|
||||
- `O_TRUNC` automatic ftruncate(fd,0) if exists
|
||||
- `O_CLOEXEC`: automatic close() upon execve()
|
||||
- `O_EXCL`: exclusive access (see below)
|
||||
- `O_APPEND`: open file for append only
|
||||
- `O_CLOEXEC` automatic close() upon execve()
|
||||
- `O_EXCL` exclusive access (see below)
|
||||
- `O_APPEND` open file for append only
|
||||
- `O_NONBLOCK` asks read/write to fail with EAGAIN rather than block
|
||||
- `O_DIRECT` it's complicated (not supported on Apple and OpenBSD)
|
||||
- `O_DIRECTORY` useful for stat'ing (hint on UNIX but required on NT)
|
||||
- `O_TMPFILE` try to make temp more secure (Linux and Windows only)
|
||||
|
@ -1615,7 +1614,7 @@ UNIX MODULE
|
|||
|
||||
- `O_CLOEXEC`: Automatically close file descriptor upon execve()
|
||||
|
||||
- `O_NONBLOCK`: Request `EAGAIN` be raised rather than blocking.
|
||||
- `O_NONBLOCK`: Request `EAGAIN` be raised rather than blocking
|
||||
|
||||
- `O_DIRECT`: Enable packet mode w/ atomic reads and writes, so long
|
||||
as they're no larger than `PIPE_BUF` (guaranteed to be 512+ bytes)
|
||||
|
@ -2634,6 +2633,52 @@ UNIX MODULE
|
|||
|
||||
Returns information about resource limit.
|
||||
|
||||
unix.gmtime(unixts:int)
|
||||
├─→ year,mon,mday,hour,min,sec,gmtoffsec,wday,yday,dst:int,zone:str
|
||||
└─→ nil,unix.Errno
|
||||
|
||||
Breaks down UNIX timestamp into Zulu Time numbers.
|
||||
|
||||
- `mon` 1 ≤ mon ≤ 12
|
||||
- `mday` 1 ≤ mday ≤ 31
|
||||
- `hour` 0 ≤ hour ≤ 23
|
||||
- `min` 0 ≤ min ≤ 59
|
||||
- `sec` 0 ≤ sec ≤ 60
|
||||
- `gmtoff` ±93600 seconds
|
||||
- `wday` 0 ≤ wday ≤ 6
|
||||
- `yday` 0 ≤ yday ≤ 365
|
||||
- `dst` 1 if daylight savings, 0 if not, -1 if not unknown
|
||||
|
||||
unix.localtime(unixts:int)
|
||||
├─→ year,mon,mday,hour,min,sec,gmtoffsec,wday,yday,dst:int,zone:str
|
||||
└─→ nil,unix.Errno
|
||||
|
||||
Breaks down UNIX timestamp into local time numbers.
|
||||
|
||||
This follows the same API as gmtime() which has further details.
|
||||
|
||||
Your redbean ships with a subset of the time zone database.
|
||||
|
||||
- `/zip/usr/share/zoneinfo/Honolulu`
|
||||
- `/zip/usr/share/zoneinfo/Anchorage`
|
||||
- `/zip/usr/share/zoneinfo/GST`
|
||||
- `/zip/usr/share/zoneinfo/Boulder`
|
||||
- `/zip/usr/share/zoneinfo/Chicago`
|
||||
- `/zip/usr/share/zoneinfo/New_York`
|
||||
- `/zip/usr/share/zoneinfo/UTC`
|
||||
- `/zip/usr/share/zoneinfo/London`
|
||||
- `/zip/usr/share/zoneinfo/Berlin`
|
||||
- `/zip/usr/share/zoneinfo/Israel`
|
||||
- `/zip/usr/share/zoneinfo/Beijing`
|
||||
- `/zip/usr/share/zoneinfo/Japan`
|
||||
- `/zip/usr/share/zoneinfo/Sydney`
|
||||
|
||||
You can control which timezone is used using the `TZ` environment
|
||||
variable. If your time zone isn't included in the above list, you
|
||||
can simply copy it inside your redbean. The same is also the case
|
||||
for future updates to the database, which can be swapped out when
|
||||
needed, without having to recompile.
|
||||
|
||||
unix.stat(path:str[, flags:int[, dirfd:int]])
|
||||
├─→ unix.Stat
|
||||
└─→ nil, unix.Errno
|
||||
|
@ -2847,7 +2892,7 @@ UNIX MODULE
|
|||
actually consumes. For example, for small file systems, your system
|
||||
might report this number as being 8, which means 4096 bytes.
|
||||
|
||||
On Windows NT, if compression is enabled for a file, then this
|
||||
On Windows NT, if `O_COMPRESSED` is used for a file, then this
|
||||
number will reflect the size *after* compression. you can use:
|
||||
|
||||
st = assert(unix.stat("moby.txt"))
|
||||
|
|
130
tool/net/lunix.c
130
tool/net/lunix.c
|
@ -98,15 +98,9 @@ struct UnixDir {
|
|||
DIR *dir;
|
||||
};
|
||||
|
||||
struct UnixStat {
|
||||
int refs;
|
||||
struct stat st;
|
||||
};
|
||||
|
||||
struct UnixErrno {
|
||||
int refs;
|
||||
uint16_t errno;
|
||||
uint16_t winerr;
|
||||
int errno;
|
||||
int winerr;
|
||||
const char *call;
|
||||
};
|
||||
|
||||
|
@ -137,12 +131,17 @@ static void *LuaUnixAlloc(lua_State *L, size_t n) {
|
|||
}
|
||||
|
||||
static void LuaPushSigset(lua_State *L, struct sigset set) {
|
||||
struct sigset *sp;
|
||||
sp = lua_newuserdatauv(L, sizeof(*sp), 1);
|
||||
struct sigset *sp = lua_newuserdatauv(L, sizeof(*sp), 1);
|
||||
luaL_setmetatable(L, "unix.Sigset");
|
||||
*sp = set;
|
||||
}
|
||||
|
||||
static void LuaPushStat(lua_State *L, struct stat *st) {
|
||||
struct stat *stp = lua_newuserdatauv(L, sizeof(*stp), 1);
|
||||
luaL_setmetatable(L, "unix.Stat");
|
||||
*stp = *st;
|
||||
}
|
||||
|
||||
static void LuaSetIntField(lua_State *L, const char *k, lua_Integer v) {
|
||||
lua_pushinteger(L, v);
|
||||
lua_setfield(L, -2, k);
|
||||
|
@ -163,19 +162,8 @@ static dontinline int ReturnString(lua_State *L, const char *x) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void LuaUnixPushErrno(lua_State *L, const char *sc, int uerr, int werr) {
|
||||
struct UnixErrno *ue, **uep;
|
||||
ue = LuaUnixAlloc(L, sizeof(*ue));
|
||||
ue->refs = 1;
|
||||
ue->call = sc;
|
||||
ue->errno = uerr;
|
||||
ue->winerr = werr;
|
||||
uep = lua_newuserdatauv(L, sizeof(*uep), 1);
|
||||
luaL_setmetatable(L, "unix.Errno");
|
||||
*uep = ue;
|
||||
}
|
||||
|
||||
static dontinline int SysretErrno(lua_State *L, const char *call, int olderr) {
|
||||
static int SysretErrno(lua_State *L, const char *call, int olderr) {
|
||||
struct UnixErrno *ep;
|
||||
int i, unixerr, winerr;
|
||||
unixerr = errno;
|
||||
winerr = GetLastError();
|
||||
|
@ -183,7 +171,11 @@ static dontinline int SysretErrno(lua_State *L, const char *call, int olderr) {
|
|||
WARNF("errno should not be %d", unixerr);
|
||||
}
|
||||
lua_pushnil(L);
|
||||
LuaUnixPushErrno(L, call, unixerr, winerr);
|
||||
ep = lua_newuserdatauv(L, sizeof(*ep), 1);
|
||||
luaL_setmetatable(L, "unix.Errno");
|
||||
ep->errno = unixerr;
|
||||
ep->winerr = winerr;
|
||||
ep->call = call;
|
||||
errno = olderr;
|
||||
return 2;
|
||||
}
|
||||
|
@ -936,49 +928,33 @@ static int LuaUnixWrite(lua_State *L) {
|
|||
return SysretInteger(L, "write", olderr, rc);
|
||||
}
|
||||
|
||||
static int ReturnStat(lua_State *L, struct UnixStat *ust) {
|
||||
struct UnixStat **ustp;
|
||||
ust->refs = 1;
|
||||
ustp = lua_newuserdatauv(L, sizeof(*ustp), 1);
|
||||
luaL_setmetatable(L, "unix.Stat");
|
||||
*ustp = ust;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// unix.stat(path:str[, flags:int[, dirfd:int]])
|
||||
// ├─→ unix.Stat
|
||||
// └─→ nil, unix.Errno
|
||||
static int LuaUnixStat(lua_State *L) {
|
||||
const char *path;
|
||||
struct UnixStat *ust;
|
||||
int dirfd, flags, olderr = errno;
|
||||
path = luaL_checkstring(L, 1);
|
||||
flags = luaL_optinteger(L, 2, 0);
|
||||
dirfd = luaL_optinteger(L, 3, AT_FDCWD);
|
||||
if ((ust = LuaUnixAllocRaw(L, sizeof(*ust)))) {
|
||||
if (!fstatat(dirfd, path, &ust->st, flags)) {
|
||||
return ReturnStat(L, ust);
|
||||
}
|
||||
free(ust);
|
||||
struct stat st;
|
||||
int olderr = errno;
|
||||
if (!fstatat(luaL_optinteger(L, 3, AT_FDCWD), luaL_checkstring(L, 1), &st,
|
||||
luaL_optinteger(L, 2, 0))) {
|
||||
LuaPushStat(L, &st);
|
||||
return 1;
|
||||
} else {
|
||||
return SysretErrno(L, "stat", olderr);
|
||||
}
|
||||
return SysretErrno(L, "stat", olderr);
|
||||
}
|
||||
|
||||
// unix.fstat(fd:int)
|
||||
// ├─→ unix.Stat
|
||||
// └─→ nil, unix.Errno
|
||||
static int LuaUnixFstat(lua_State *L) {
|
||||
int fd, olderr = errno;
|
||||
struct UnixStat *ust;
|
||||
olderr = errno;
|
||||
fd = luaL_checkinteger(L, 1);
|
||||
if ((ust = LuaUnixAllocRaw(L, sizeof(*ust)))) {
|
||||
if (!fstat(fd, &ust->st)) {
|
||||
return ReturnStat(L, ust);
|
||||
}
|
||||
free(ust);
|
||||
struct stat st;
|
||||
int olderr = errno;
|
||||
if (!fstat(luaL_checkinteger(L, 1), &st)) {
|
||||
LuaPushStat(L, &st);
|
||||
return 1;
|
||||
} else {
|
||||
return SysretErrno(L, "fstat", olderr);
|
||||
}
|
||||
return SysretErrno(L, "fstat", olderr);
|
||||
}
|
||||
|
||||
static bool IsSockoptBool(int l, int x) {
|
||||
|
@ -1746,9 +1722,7 @@ static int LuaUnixMinor(lua_State *L) {
|
|||
// unix.Stat object
|
||||
|
||||
static dontinline struct stat *GetUnixStat(lua_State *L) {
|
||||
struct UnixStat **ust;
|
||||
ust = luaL_checkudata(L, 1, "unix.Stat");
|
||||
return &(*ust)->st;
|
||||
return luaL_checkudata(L, 1, "unix.Stat");
|
||||
}
|
||||
|
||||
// unix.Stat:size()
|
||||
|
@ -1853,28 +1827,12 @@ static int LuaUnixStatFlags(lua_State *L) {
|
|||
return ReturnInteger(L, GetUnixStat(L)->st_flags);
|
||||
}
|
||||
|
||||
static void FreeUnixStat(struct UnixStat *stat) {
|
||||
if (!--stat->refs) {
|
||||
free(stat);
|
||||
}
|
||||
}
|
||||
|
||||
static int LuaUnixStatToString(lua_State *L) {
|
||||
struct stat *st = GetUnixStat(L);
|
||||
lua_pushstring(L, "unix.Stat{}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int LuaUnixStatGc(lua_State *L) {
|
||||
struct UnixStat **ust;
|
||||
ust = luaL_checkudata(L, 1, "unix.Stat");
|
||||
if (*ust) {
|
||||
FreeUnixStat(*ust);
|
||||
*ust = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const luaL_Reg kLuaUnixStatMeth[] = {
|
||||
{"atim", LuaUnixStatAtim}, //
|
||||
{"birthtim", LuaUnixStatBirthtim}, //
|
||||
|
@ -1897,7 +1855,6 @@ static const luaL_Reg kLuaUnixStatMeth[] = {
|
|||
|
||||
static const luaL_Reg kLuaUnixStatMeta[] = {
|
||||
{"__tostring", LuaUnixStatToString}, //
|
||||
{"__gc", LuaUnixStatGc}, //
|
||||
{0}, //
|
||||
};
|
||||
|
||||
|
@ -1913,10 +1870,8 @@ static void LuaUnixStatObj(lua_State *L) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// unix.Errno object
|
||||
|
||||
static dontinline struct UnixErrno *GetUnixErrno(lua_State *L) {
|
||||
struct UnixErrno **ep;
|
||||
ep = luaL_checkudata(L, 1, "unix.Errno");
|
||||
return *ep;
|
||||
static struct UnixErrno *GetUnixErrno(lua_State *L) {
|
||||
return luaL_checkudata(L, 1, "unix.Errno");
|
||||
}
|
||||
|
||||
static int LuaUnixErrnoErrno(lua_State *L) {
|
||||
|
@ -1948,22 +1903,6 @@ static int LuaUnixErrnoToString(lua_State *L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void FreeUnixErrno(struct UnixErrno *errno) {
|
||||
if (!--errno->refs) {
|
||||
free(errno);
|
||||
}
|
||||
}
|
||||
|
||||
static int LuaUnixErrnoGc(lua_State *L) {
|
||||
struct UnixErrno **ue;
|
||||
ue = luaL_checkudata(L, 1, "unix.Errno");
|
||||
if (*ue) {
|
||||
FreeUnixErrno(*ue);
|
||||
*ue = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const luaL_Reg kLuaUnixErrnoMeth[] = {
|
||||
{"strerror", LuaUnixErrnoToString}, //
|
||||
{"errno", LuaUnixErrnoErrno}, //
|
||||
|
@ -1975,7 +1914,6 @@ static const luaL_Reg kLuaUnixErrnoMeth[] = {
|
|||
|
||||
static const luaL_Reg kLuaUnixErrnoMeta[] = {
|
||||
{"__tostring", LuaUnixErrnoToString}, //
|
||||
{"__gc", LuaUnixErrnoGc}, //
|
||||
{0}, //
|
||||
};
|
||||
|
||||
|
|
|
@ -117,9 +117,10 @@ o/$(MODE)/tool/net/redbean.com: \
|
|||
@$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/.redbean
|
||||
@$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.redbean/.ape bs=64 count=11 conv=notrunc 2>/dev/null
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com -o o/$(MODE)/tool/net/.redbean/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/tool/net/.redbean/.symtab
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
o/$(MODE)/tool/net/.redbean/.ape \
|
||||
o/$(MODE)/tool/net/.redbean/.symtab \
|
||||
tool/net/help.txt \
|
||||
tool/net/.init.lua \
|
||||
tool/net/favicon.ico \
|
||||
|
@ -262,9 +263,10 @@ o/$(MODE)/tool/net/redbean-demo.com: \
|
|||
@$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.redbean-demo/.ape bs=64 count=11 conv=notrunc 2>/dev/null
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/tool/net/.redbean-demo/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/tool/net/.redbean-demo/.symtab
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
o/$(MODE)/tool/net/.redbean-demo/.ape \
|
||||
o/$(MODE)/tool/net/.redbean-demo/.symtab \
|
||||
tool/net/help.txt
|
||||
|
||||
# REDBEAN-STATIC.COM
|
||||
|
@ -284,9 +286,10 @@ o/$(MODE)/tool/net/redbean-static.com: \
|
|||
@$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.redbean-static/.ape bs=64 count=11 conv=notrunc 2>/dev/null
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/tool/net/.redbean-static/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/tool/net/.redbean-static/.symtab
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
o/$(MODE)/tool/net/.redbean-static/.ape \
|
||||
o/$(MODE)/tool/net/.redbean-static/.symtab \
|
||||
tool/net/help.txt \
|
||||
tool/net/favicon.ico \
|
||||
tool/net/redbean.png
|
||||
|
@ -320,9 +323,10 @@ o/$(MODE)/tool/net/redbean-unsecure.com: \
|
|||
@$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.redbean-unsecure/.ape bs=64 count=11 conv=notrunc 2>/dev/null
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/tool/net/.redbean-unsecure/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/tool/net/.redbean-unsecure/.symtab
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
o/$(MODE)/tool/net/.redbean-unsecure/.ape \
|
||||
o/$(MODE)/tool/net/.redbean-unsecure/.symtab \
|
||||
tool/net/help.txt \
|
||||
tool/net/favicon.ico \
|
||||
tool/net/redbean.png
|
||||
|
@ -363,9 +367,10 @@ o/$(MODE)/tool/net/redbean-original.com: \
|
|||
@$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.redbean-original/.ape bs=64 count=11 conv=notrunc 2>/dev/null
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/tool/net/.redbean-original/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/tool/net/.redbean-original/.symtab
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
o/$(MODE)/tool/net/.redbean-original/.ape \
|
||||
o/$(MODE)/tool/net/.redbean-original/.symtab \
|
||||
tool/net/help.txt \
|
||||
tool/net/favicon.ico \
|
||||
tool/net/redbean.png
|
||||
|
@ -436,6 +441,8 @@ o/$(MODE)/tool/net/redbean-assimilate.com: \
|
|||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/.redbean-assimilate
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com -o o/$(MODE)/tool/net/.redbean-assimilate/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/tool/net/.redbean-assimilate/.symtab
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
o/$(MODE)/tool/net/.redbean-assimilate/.symtab \
|
||||
tool/net/help.txt \
|
||||
|
|
|
@ -4120,7 +4120,7 @@ static int LuaLog(lua_State *L) {
|
|||
}
|
||||
|
||||
static int LuaEncodeSmth(lua_State *L,
|
||||
int Encoder(lua_State *, char **, int, char *, int)) {
|
||||
int Encoder(lua_State *, char **, char *, int)) {
|
||||
int useoutput = false;
|
||||
int maxdepth = 64;
|
||||
char *numformat = "%.14g";
|
||||
|
@ -4129,15 +4129,14 @@ static int LuaEncodeSmth(lua_State *L,
|
|||
lua_settop(L, 2); // discard any extra arguments
|
||||
lua_getfield(L, 2, "useoutput");
|
||||
// ignore useoutput outside of request handling
|
||||
if (ishandlingrequest && lua_isboolean(L, -1))
|
||||
if (ishandlingrequest && lua_isboolean(L, -1)) {
|
||||
useoutput = lua_toboolean(L, -1);
|
||||
lua_getfield(L, 2, "maxdepth");
|
||||
maxdepth = luaL_optinteger(L, -1, maxdepth);
|
||||
}
|
||||
lua_getfield(L, 2, "numformat");
|
||||
numformat = luaL_optstring(L, -1, numformat);
|
||||
}
|
||||
lua_settop(L, 1); // keep the passed argument on top
|
||||
Encoder(L, useoutput ? &outbuf : &p, maxdepth, numformat, -1);
|
||||
Encoder(L, useoutput ? &outbuf : &p, numformat, -1);
|
||||
if (useoutput) {
|
||||
lua_pushnil(L);
|
||||
} else {
|
||||
|
@ -5185,7 +5184,7 @@ static void LuaPrint(lua_State *L) {
|
|||
if (n > 0) {
|
||||
for (i = 1; i <= n; i++) {
|
||||
if (i > 1) appendw(&b, '\t');
|
||||
LuaEncodeLuaData(L, &b, 64, "g", i);
|
||||
LuaEncodeLuaData(L, &b, "g", i);
|
||||
}
|
||||
appendw(&b, '\n');
|
||||
WRITE(1, b, appendz(b).i);
|
||||
|
@ -5222,7 +5221,6 @@ static void LuaInterpreter(lua_State *L) {
|
|||
}
|
||||
for (;;) {
|
||||
status = lua_loadline(L);
|
||||
write(1, "\n", 1);
|
||||
if (status == -1) break; // eof
|
||||
if (status == -2) {
|
||||
if (errno == EINTR) {
|
||||
|
@ -6502,7 +6500,6 @@ static int HandleReadline(void) {
|
|||
if (status == -1) {
|
||||
OnTerm(SIGHUP); // eof
|
||||
INFOF("got repl eof");
|
||||
write(1, "\n", 1);
|
||||
return -1;
|
||||
} else if (errno == EINTR) {
|
||||
errno = 0;
|
||||
|
@ -6516,7 +6513,6 @@ static int HandleReadline(void) {
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
write(1, "\n", 1);
|
||||
linenoiseDisableRawMode();
|
||||
LUA_REPL_LOCK;
|
||||
if (status == LUA_OK) {
|
||||
|
|
|
@ -55,7 +55,7 @@ o/$(MODE)/tool/plinko/plinko.com: \
|
|||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/plinko/.redbean
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com -o o/$(MODE)/tool/plinko/.plinko/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/tool/plinko/.plinko/.symtab
|
||||
|
||||
$(TOOL_PLINKO_OBJS): \
|
||||
|
|
|
@ -88,7 +88,7 @@ o/$(MODE)/tool/viz/printimage.com: \
|
|||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/tool/viz/.printimage/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/tool/viz/.printimage/.symtab
|
||||
|
||||
o/$(MODE)/tool/viz/printvideo.com: \
|
||||
|
@ -98,7 +98,7 @@ o/$(MODE)/tool/viz/printvideo.com: \
|
|||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/tool/viz/.printvideo/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/tool/viz/.printvideo/.symtab
|
||||
|
||||
o/$(MODE)/tool/viz/derasterize.o: \
|
||||
|
|
BIN
usr/share/zoneinfo/Anchorage
Normal file
BIN
usr/share/zoneinfo/Anchorage
Normal file
Binary file not shown.
Loading…
Reference in a new issue