diff --git a/Makefile b/Makefile index 5e7a4e8a..5fb4b1df 100644 --- a/Makefile +++ b/Makefile @@ -231,8 +231,9 @@ HTAGS: o/$(MODE)/hdrs.txt $(HDRS) @rm -f $@ @ACTION=TAGS TARGET=$@ build/do build/htags -L $< -o $@ -loc:; find -name \*.h -or -name \*.c -or -name \*.S | \ - $(XARGS) wc -l | grep total | awk '{print $$1}' | summy +loc: o/$(MODE)/tool/build/summy.com + find -name \*.h -or -name \*.c -or -name \*.S | \ + $(XARGS) wc -l | grep total | awk '{print $$1}' | $< # UNSPECIFIED PREREQUISITES TUTORIAL # diff --git a/NOTICE b/NOTICE index 5b1b10d7..6b2b5ed6 100644 --- a/NOTICE +++ b/NOTICE @@ -1,16 +1,3 @@ -Cosmopolitan is Free Software licensed under the GPLv2. The build config -**will embed all linked sources inside your binaries** so the compliance -is easy while facilitating trust and transparency similar to JavaScript. -You can audit your source filesystem using ZIP GUIs e.g. WIN10, InfoZip. - -If you want to be able to distribute binaries in binary form only, then -please send $1,000 to jtunney@gmail.com on PayPal for a license lasting -1 year. Please be sure to provide your contact information, and details -on whether or not the license is for an individual or a corporation. If -you want your license to last 5 years, send $10,000 to the author above -who is Justine Tunney . Reach out, for more details. - -──────────────────────────────────────────────────────────────────────── GNU GENERAL PUBLIC LICENSE Version 2, June 1991 diff --git a/README.md b/README.md index d165b1ff..45b04ad0 100644 --- a/README.md +++ b/README.md @@ -18,17 +18,19 @@ Cosmopolitan provides a native development environment similar to those currently being offered by RedHat, Google, Apple, Microsoft, etc. We're different in two ways: (1) we're not a platform therefore we don't have any commercial interest in making our tooling work better on one rather -than another; and (2) we're only focused on catering towards interfaces -all platforms agree upon. Goal is software that stands the test of time +than another; and (2) we cater primarily towards features having gained +cross-platform agreement. Goal is software that stands the test of time without the costs and restrictions cross-platform distribution entails. + That makes Cosmopolitan an excellent fit for writing small CLI programs -that do things like heavyweight numerical computations as a subprocess. +that do things like matrix multiplication relu stdio as a subprocess or +perhaps a web server having the minimum surface area that you require. ## Getting Started Just clone the repository and put your own folder in it. Please choose a name that's based on a .com or .org domain name registration you control -which is scout's honor but might change to require TXT records in future +which is scout's honor but could change to verify TXT records in future. We provide a script that makes it easy to start a new package: @@ -37,11 +39,11 @@ We provide a script that makes it easy to start a new package: make o//com/github/user/project/program.com o//com/github/user/project/program.com -Please note GNU make is awesome. Little known fact: make is a functional +Please note GNU Make is awesome. Little known fact: make is a functional programming language. We improved upon it too! In [tool/build/package.c] which performs strict dependency checking, to correct Google's published mistakes c. 2006 which was when they switched from using a GNU Make repo -in favor of an inhouse derivative called Blaze which does strictness too +in favor of an inhouse derivative called Blaze which does graph checking thereby allowing the repository to grow gracefully with any requirements ## Performance @@ -66,18 +68,20 @@ Furthermore Cosmopolitan provides you with Intel's official instruction length decoder Xed ravaged down to 3kb in size using Tim Patterson code stunts. So you can absolutely code high-performance lightweight fabless x86 microprocessors using any hobbyist board without royalties, because -Xed tells us which parts of the encoding space now belong to the people +Xed tells us which parts of the encoding space now belong to the people. +Please see [third_party/xed/x86ild.greg.c] to learn more. ## Integrated Development Environment -Your Cosmopolitan IDE is based on Emacs. When used alongside `make tags` -it can automate certain toilsome problems such as adding an include line -by typing `C-c C-h` with the cursor over a symbol. Please install these: +Your Cosmopolitan IDE is based on whichever editor you love most. Emacs +configs are provided, showing how `make tags` can be used to automate +certain toil, such as adding include lines by typing `C-c C-h` over a +symbol. We recommend trying the following: sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" - sudo apt install gdb ragel ctags clang-format-10 # <-recommended + sudo apt install gdb ragel ctags clang-format-10 git clone git@github.com:jart/cosmopolitan.git && cd cosmopolitan - tool/scripts/install-emacs.sh # recommended over apt + tool/scripts/install-emacs.sh # Emacs 26.1 has a bug tool/scripts/configure-emacs.sh # adds load statements make tags # index all the symbol emacs # for power and glory! @@ -95,10 +99,9 @@ should explain how easy it is to do pe+sh+elf+macho+bootloader overlays enabling gnu ld.bfd to produce a simple portable 12kb .com program file Please send feedback and concerns to since we would -love to do an even better job. Please also report GPL abuse the address -above as well. We believe this binary structure is novel, and therefore -easily recognizable. So if some goofball isn't bundling the source code -please let us know, so we can reach out and ask if they want a license. +love to do an even better job. Please also let us know if some goofball +is distributing without bundling their source code, so we can reach out +and ask if they would like to purchase a commercial license. make -j10 -O MODE=tiny CPPFLAGS=-DIM_FEELING_NAUGHTY o/tiny/tool/viz/bing.com $@ - $(LIBC__A_SRCS:%=o/$(MODE)/%.zip.o) \ diff --git a/examples/ntdll.c b/examples/ntdll.c deleted file mode 100644 index 0e71e2d4..00000000 --- a/examples/ntdll.c +++ /dev/null @@ -1,37 +0,0 @@ -#if 0 -/*─────────────────────────────────────────────────────────────────╗ -│ To the extent possible under law, Justine Tunney has waived │ -│ all copyright and related or neighboring rights to this file, │ -│ as it is written in the following disclaimers: │ -│ • http://unlicense.org/ │ -│ • http://creativecommons.org/publicdomain/zero/1.0/ │ -╚─────────────────────────────────────────────────────────────────*/ -#endif -#include "libc/dce.h" -#include "libc/nt/dll.h" -#include "libc/nt/nt/process.h" -#include "libc/runtime/runtime.h" -#include "libc/stdio/stdio.h" -#include "libc/sysv/consts/exit.h" - -int main() { - if (IsWindows()) { - /* - * Cosmopolitan imports this automatically if it's referenced the - * normal way. But Microsoft wants us to use loose coupling when - * referencing their internal APIs. Don't think for a moment they - * won't break open source projects that fail to heed the warning. - */ - typeof(NtTerminateProcess) *NtTerminateProcess_ = - GetProcAddress(GetModuleHandle("ntdll.dll"), "NtTerminateProcess"); - printf("%ld\n", GetModuleHandle("ntdll.dll")); - printf("%p\n", NtTerminateProcess_); - if (NtTerminateProcess_) { - fflush(stdout); - for (;;) NtTerminateProcess_(-1, 42); - } - } else { - fprintf(stderr, "error: intended for windows\n"); - } - return EXIT_FAILURE; -} diff --git a/libc/alg/alg.h b/libc/alg/alg.h index dea4dff4..467eb3a6 100644 --- a/libc/alg/alg.h +++ b/libc/alg/alg.h @@ -13,17 +13,14 @@ void *bsearch_r(const void *, const void *, size_t, size_t, int cmp(const void *, const void *, void *), void *) paramsnonnull((1, 2, 5)) nothrow nosideeffect; void djbsort(size_t n, int32_t[n]); -void qsort(void *items, size_t itemcount, size_t itemsize, - int cmp(const void *, const void *)) paramsnonnull(); -void qsort_r(void *items, size_t itemcount, size_t itemsize, +void qsort(void *, size_t, size_t, int (*)(const void *, const void *)) + paramsnonnull(); +void qsort_r(void *, size_t, size_t, int cmp(const void *, const void *, void *), void *arg) paramsnonnull((1, 4)); -int tarjan(uint32_t vertex_count, const uint32_t (*edges)[2], - uint32_t edge_count, uint32_t out_sorted[], - uint32_t out_opt_components[], uint32_t *out_opt_componentcount) - paramsnonnull((2, 4)) nocallback nothrow; -void heapsortcar(int32_t (*A)[2], unsigned n) - paramsnonnull() nocallback nothrow; +int tarjan(uint32_t, const uint32_t (*)[2], uint32_t, uint32_t[], uint32_t[], + uint32_t *) paramsnonnull((2, 4)) nocallback nothrow; +void heapsortcar(int32_t (*)[2], unsigned) paramsnonnull() nocallback nothrow; void *memmem(const void *, size_t, const void *, size_t) paramsnonnull() nothrow nocallback nosideeffect; @@ -56,16 +53,16 @@ struct critbit0 { size_t count; }; -bool critbit0_contains(struct critbit0 *t, const char *u) nothrow nosideeffect +bool critbit0_contains(struct critbit0 *, const char *) nothrow nosideeffect paramsnonnull(); -bool critbit0_insert(struct critbit0 *t, const char *u) paramsnonnull(); -bool critbit0_delete(struct critbit0 *t, const char *u) nothrow paramsnonnull(); -void critbit0_clear(struct critbit0 *t) nothrow paramsnonnull(); -char *critbit0_get(struct critbit0 *t, const char *u); -intptr_t critbit0_allprefixed(struct critbit0 *t, const char *prefix, - intptr_t (*callback)(const char *elem, void *arg), - void *arg) paramsnonnull((1, 2, 3)) nothrow; -bool critbit0_emplace(struct critbit0 *t, char *u, size_t ulen) paramsnonnull(); +bool critbit0_insert(struct critbit0 *, const char *) paramsnonnull(); +bool critbit0_delete(struct critbit0 *, const char *) nothrow paramsnonnull(); +void critbit0_clear(struct critbit0 *) nothrow paramsnonnull(); +char *critbit0_get(struct critbit0 *, const char *); +intptr_t critbit0_allprefixed(struct critbit0 *, const char *, + intptr_t (*)(const char *, void *), void *) + paramsnonnull((1, 2, 3)) nothrow; +bool critbit0_emplace(struct critbit0 *, char *, size_t) paramsnonnull(); /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § algorithms » comparators ─╬─│┼ diff --git a/libc/calls/hefty/dirstream.c b/libc/calls/hefty/dirstream.c index caaed6b3..7da1a786 100644 --- a/libc/calls/hefty/dirstream.c +++ b/libc/calls/hefty/dirstream.c @@ -76,6 +76,7 @@ static textwindows noinline DIR *opendir$nt(const char *name) { * * @returns newly allocated DIR object, or NULL w/ errno * @errors ENOENT, ENOTDIR, EACCES, EMFILE, ENFILE, ENOMEM + * @see glob() */ DIR *opendir(const char *name) { if (!IsWindows() && !IsXnu()) { diff --git a/libc/calls/ioctl.h b/libc/calls/ioctl.h index ed8493b3..e098fa16 100644 --- a/libc/calls/ioctl.h +++ b/libc/calls/ioctl.h @@ -12,7 +12,7 @@ int ioctl(int, uint64_t, void *); /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § system calls » input output control » undiamonding ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -#ifdef __GNUC__ +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) #include "libc/macros.h" #include "libc/sysv/consts/termios.h" @@ -46,7 +46,7 @@ forceinline int ioctl$dispatch(int fd, uint64_t request, void *memory) { return ioctl$default(fd, request, memory); } -#endif /* GNUC */ +#endif /* GNUC && !ANSI */ COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_CALLS_IOCTL_H_ */ diff --git a/libc/calls/termios.h b/libc/calls/termios.h index dcc7f935..b02ff646 100644 --- a/libc/calls/termios.h +++ b/libc/calls/termios.h @@ -28,8 +28,9 @@ int unlockpt(int); int posix_openpt(int) nodiscard; /*───────────────────────────────────────────────────────────────────────────│─╗ -│ cosmopolitan § teletypewriter » optimizations ─╬─│┼ +│ cosmopolitan § teletypewriter » undiamonding ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) #define tcsetattr(FD, OPT, TIO) tcsetattr$dispatch(FD, OPT, TIO) forceinline int tcsetattr$dispatch(int fd, int opt, const struct termios *tio) { @@ -44,6 +45,7 @@ forceinline int tcgetattr$dispatch(int fd, const struct termios *tio) { return ioctl(fd, TCGETS, (void *)tio); } +#endif /* GNUC && !ANSI */ COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_CALLS_TERMIOS_H_ */ diff --git a/libc/calls/weirdtypes.h b/libc/calls/weirdtypes.h index b90f8f25..f23cad20 100644 --- a/libc/calls/weirdtypes.h +++ b/libc/calls/weirdtypes.h @@ -3,7 +3,7 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) /** - * @fileoverview Types for scoundrels. + * @fileoverview Types we'd prefer hadn't been invented. */ #define blkcnt_t int64_t diff --git a/libc/crypto/rijndael.h b/libc/crypto/rijndael.h index 4cb9e149..09c63091 100644 --- a/libc/crypto/rijndael.h +++ b/libc/crypto/rijndael.h @@ -49,7 +49,7 @@ aes_block_t unrijndael(uint32_t, aes_block_t, const struct Rijndael *); aligned(64) extern const uint8_t kAesSbox[256]; aligned(64) extern const uint8_t kAesSboxInverse[256]; -aes_block_t InvMixColumns(aes_block_t x) hidden; +aes_block_t InvMixColumns(aes_block_t) hidden; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/elf/elf.h b/libc/elf/elf.h index 3144ec5e..97f5f040 100644 --- a/libc/elf/elf.h +++ b/libc/elf/elf.h @@ -18,12 +18,10 @@ COSMOPOLITAN_C_START_ struct MappedFile; -Elf64_Ehdr *mapelfread(const char *filename, struct MappedFile *mf); -char *getelfstringtable(const Elf64_Ehdr *elf, size_t mapsize); -Elf64_Sym *getelfsymboltable(const Elf64_Ehdr *elf, size_t mapsize, - Elf64_Xword *out_count); -Elf64_Shdr *getelfsectionbyaddress(const Elf64_Ehdr *elf, size_t mapsize, - void *addr); +Elf64_Ehdr *mapelfread(const char *, struct MappedFile *); +char *getelfstringtable(const Elf64_Ehdr *, size_t); +Elf64_Sym *getelfsymboltable(const Elf64_Ehdr *, size_t, Elf64_Xword *); +Elf64_Shdr *getelfsectionbyaddress(const Elf64_Ehdr *, size_t, void *); forceinline void checkelfaddress(const Elf64_Ehdr *elf, size_t mapsize, intptr_t addr, size_t addrsize) { @@ -66,8 +64,9 @@ static inline Elf64_Shdr *getelfsectionheaderaddress(const Elf64_Ehdr *elf, static inline void *getelfsectionaddress(const Elf64_Ehdr *elf, size_t mapsize, const Elf64_Shdr *shdr) { - intptr_t addr = (intptr_t)elf + (intptr_t)shdr->sh_offset; - intptr_t size = (intptr_t)shdr->sh_size; + intptr_t addr, size; + addr = (intptr_t)elf + (intptr_t)shdr->sh_offset; + size = (intptr_t)shdr->sh_size; checkelfaddress(elf, mapsize, addr, size); return (void *)addr; } @@ -83,13 +82,16 @@ static inline void getelfvirtualaddressrange(const Elf64_Ehdr *elf, size_t elfsize, intptr_t *out_start, intptr_t *out_end) { - intptr_t start = INTPTR_MAX; - intptr_t end = 0; - for (unsigned i = 0; i < elf->e_phnum; ++i) { - Elf64_Phdr *phdr = getelfsegmentheaderaddress(elf, elfsize, i); + unsigned i; + Elf64_Phdr *phdr; + intptr_t start, end, pstart, pend; + start = INTPTR_MAX; + end = 0; + for (i = 0; i < elf->e_phnum; ++i) { + phdr = getelfsegmentheaderaddress(elf, elfsize, i); if (phdr->p_type != PT_LOAD) continue; - intptr_t pstart = phdr->p_vaddr; - intptr_t pend = phdr->p_vaddr + phdr->p_memsz; + pstart = phdr->p_vaddr; + pend = phdr->p_vaddr + phdr->p_memsz; if (pstart < start) start = pstart; if (pend > end) end = pend; } diff --git a/libc/elf/getelfsectionbyaddress.c b/libc/elf/getelfsectionbyaddress.c index 41cd76c0..a37b50c5 100644 --- a/libc/elf/getelfsectionbyaddress.c +++ b/libc/elf/getelfsectionbyaddress.c @@ -23,9 +23,10 @@ Elf64_Shdr *getelfsectionbyaddress(const Elf64_Ehdr *elf, size_t mapsize, void *addr) { Elf64_Half i; + Elf64_Shdr *shdr; if (elf) { for (i = elf->e_shnum; i > 0; --i) { - Elf64_Shdr *shdr = getelfsectionheaderaddress(elf, mapsize, i - 1); + shdr = getelfsectionheaderaddress(elf, mapsize, i - 1); if ((intptr_t)addr >= shdr->sh_addr && (intptr_t)addr < shdr->sh_addr + shdr->sh_size) { return shdr; diff --git a/libc/escape/escape.h b/libc/escape/escape.h index 0639ebc8..75340045 100644 --- a/libc/escape/escape.h +++ b/libc/escape/escape.h @@ -7,20 +7,15 @@ COSMOPOLITAN_C_START_ │ cosmopolitan § escaping ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -unsigned cescapec(int c); -int escapec(char *buf, unsigned size, const char *unescaped, unsigned length) +unsigned cescapec(int); +int escapec(char *, unsigned, const char *, unsigned) paramsnonnull((3)) nothrow nocallback; -int escapesh(char *buf, unsigned size, const char *unescaped, unsigned length) - paramsnonnull((3)); -bool escapedos(char16_t *buffer, unsigned buflen, const char16_t *unquoted, - unsigned len); -int aescapec(char **escaped, const char *unescaped, unsigned length) - paramsnonnull(); -int aescapesh(char **escaped, const char *unescaped, unsigned length) - paramsnonnull(); -int aescape(char **escaped, size_t size, const char *unescaped, unsigned length, - int impl(char *escaped, unsigned size, const char *unescaped, - unsigned length)) hidden; +int escapesh(char *, unsigned, const char *, unsigned) paramsnonnull((3)); +bool escapedos(char16_t *, unsigned, const char16_t *, unsigned); +int aescapec(char **, const char *, unsigned) paramsnonnull(); +int aescapesh(char **, const char *, unsigned) paramsnonnull(); +int aescape(char **, size_t, const char *, unsigned, + int (*)(char *, unsigned, const char *, unsigned)) hidden; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/escape/escapedos.c b/libc/escape/escapedos.c index b373a9dd..e4a784d6 100644 --- a/libc/escape/escapedos.c +++ b/libc/escape/escapedos.c @@ -20,11 +20,6 @@ #include "libc/escape/escape.h" #include "libc/str/str.h" -asm(".ident\t\"\\n\\n\ -NSSM (Public Domain)\\n\ -Credit: Iain Patterson\n\ -http://iain.cx/\""); - static textwindows bool shouldescapedos(const char16_t c) { if (c == u'"') return true; if (c == u'&') return true; @@ -48,6 +43,7 @@ static textwindows bool shouldquotedos(const char16_t c) { /** * Escapes command so DOS can run it. + * @see Iain Patterson's NSSM for original code in public domain */ textwindows bool escapedos(char16_t *buffer, unsigned buflen, const char16_t *unquoted, unsigned len) { diff --git a/libc/fmt/kerrnonames.S b/libc/fmt/kerrnonames.S index 6f58bba0..f4263722 100644 --- a/libc/fmt/kerrnonames.S +++ b/libc/fmt/kerrnonames.S @@ -170,138 +170,138 @@ kErrnoNames: / @assume linker invoked as LC_ALL=C ld ... / @see libc/sysv/systemfive.S / @see libc/sysv/consts/syscon.h - yoink E2BIG - yoink EACCES - yoink EADDRINUSE - yoink EADDRNOTAVAIL - yoink EADV - yoink EAFNOSUPPORT - yoink EAGAIN - yoink EALREADY - yoink EBADE - yoink EBADF - yoink EBADFD - yoink EBADMSG - yoink EBADR - yoink EBADRQC - yoink EBADSLT - yoink EBFONT - yoink EBUSY - yoink ECANCELED - yoink ECHILD - yoink ECHRNG - yoink ECOMM - yoink ECONNABORTED - yoink ECONNREFUSED - yoink ECONNRESET - yoink EDEADLK - yoink EDESTADDRREQ - yoink EDOM - yoink EDOTDOT - yoink EDQUOT - yoink EEXIST - yoink EFAULT - yoink EFBIG - yoink EHOSTDOWN - yoink EHOSTUNREACH - yoink EHWPOISON - yoink EIDRM - yoink EILSEQ - yoink EINPROGRESS - yoink EINTR - yoink EINVAL - yoink EIO - yoink EISCONN - yoink EISDIR - yoink EISNAM - yoink EKEYEXPIRED - yoink EKEYREJECTED - yoink EKEYREVOKED - yoink EL2HLT - yoink EL2NSYNC - yoink EL3HLT - yoink EL3RST - yoink ELIBACC - yoink ELIBBAD - yoink ELIBEXEC - yoink ELIBMAX - yoink ELIBSCN - yoink ELNRNG - yoink ELOOP - yoink EMEDIUMTYPE - yoink EMFILE - yoink EMLINK - yoink EMSGSIZE - yoink EMULTIHOP - yoink ENAMETOOLONG - yoink ENAVAIL - yoink ENETDOWN - yoink ENETRESET - yoink ENETUNREACH - yoink ENFILE - yoink ENOANO - yoink ENOBUFS - yoink ENOCSI - yoink ENODATA - yoink ENODEV - yoink ENOENT - yoink ENOEXEC - yoink ENOKEY - yoink ENOLCK - yoink ENOLINK - yoink ENOMEDIUM - yoink ENOMEM - yoink ENOMSG - yoink ENONET - yoink ENOPKG - yoink ENOPROTOOPT - yoink ENOSPC - yoink ENOSR - yoink ENOSTR - yoink ENOSYS - yoink ENOTBLK - yoink ENOTCONN - yoink ENOTDIR - yoink ENOTEMPTY - yoink ENOTNAM - yoink ENOTRECOVERABLE - yoink ENOTSOCK - yoink ENOTSUP - yoink ENOTTY - yoink ENOTUNIQ - yoink ENXIO - yoink EOPNOTSUPP - yoink EOVERFLOW - yoink EOWNERDEAD - yoink EPERM - yoink EPFNOSUPPORT - yoink EPIPE - yoink EPROTO - yoink EPROTONOSUPPORT - yoink EPROTOTYPE - yoink ERANGE - yoink EREMCHG - yoink EREMOTE - yoink EREMOTEIO - yoink ERESTART - yoink ERFKILL - yoink EROFS - yoink ESHUTDOWN - yoink ESOCKTNOSUPPORT - yoink ESPIPE - yoink ESRCH - yoink ESRMNT - yoink ESTALE - yoink ESTRPIPE - yoink ETIME - yoink ETIMEDOUT - yoink ETOOMANYREFS - yoink ETXTBSY - yoink EUCLEAN - yoink EUNATCH - yoink EUSERS - yoink EXDEV - yoink EXFULL + .yoink E2BIG + .yoink EACCES + .yoink EADDRINUSE + .yoink EADDRNOTAVAIL + .yoink EADV + .yoink EAFNOSUPPORT + .yoink EAGAIN + .yoink EALREADY + .yoink EBADE + .yoink EBADF + .yoink EBADFD + .yoink EBADMSG + .yoink EBADR + .yoink EBADRQC + .yoink EBADSLT + .yoink EBFONT + .yoink EBUSY + .yoink ECANCELED + .yoink ECHILD + .yoink ECHRNG + .yoink ECOMM + .yoink ECONNABORTED + .yoink ECONNREFUSED + .yoink ECONNRESET + .yoink EDEADLK + .yoink EDESTADDRREQ + .yoink EDOM + .yoink EDOTDOT + .yoink EDQUOT + .yoink EEXIST + .yoink EFAULT + .yoink EFBIG + .yoink EHOSTDOWN + .yoink EHOSTUNREACH + .yoink EHWPOISON + .yoink EIDRM + .yoink EILSEQ + .yoink EINPROGRESS + .yoink EINTR + .yoink EINVAL + .yoink EIO + .yoink EISCONN + .yoink EISDIR + .yoink EISNAM + .yoink EKEYEXPIRED + .yoink EKEYREJECTED + .yoink EKEYREVOKED + .yoink EL2HLT + .yoink EL2NSYNC + .yoink EL3HLT + .yoink EL3RST + .yoink ELIBACC + .yoink ELIBBAD + .yoink ELIBEXEC + .yoink ELIBMAX + .yoink ELIBSCN + .yoink ELNRNG + .yoink ELOOP + .yoink EMEDIUMTYPE + .yoink EMFILE + .yoink EMLINK + .yoink EMSGSIZE + .yoink EMULTIHOP + .yoink ENAMETOOLONG + .yoink ENAVAIL + .yoink ENETDOWN + .yoink ENETRESET + .yoink ENETUNREACH + .yoink ENFILE + .yoink ENOANO + .yoink ENOBUFS + .yoink ENOCSI + .yoink ENODATA + .yoink ENODEV + .yoink ENOENT + .yoink ENOEXEC + .yoink ENOKEY + .yoink ENOLCK + .yoink ENOLINK + .yoink ENOMEDIUM + .yoink ENOMEM + .yoink ENOMSG + .yoink ENONET + .yoink ENOPKG + .yoink ENOPROTOOPT + .yoink ENOSPC + .yoink ENOSR + .yoink ENOSTR + .yoink ENOSYS + .yoink ENOTBLK + .yoink ENOTCONN + .yoink ENOTDIR + .yoink ENOTEMPTY + .yoink ENOTNAM + .yoink ENOTRECOVERABLE + .yoink ENOTSOCK + .yoink ENOTSUP + .yoink ENOTTY + .yoink ENOTUNIQ + .yoink ENXIO + .yoink EOPNOTSUPP + .yoink EOVERFLOW + .yoink EOWNERDEAD + .yoink EPERM + .yoink EPFNOSUPPORT + .yoink EPIPE + .yoink EPROTO + .yoink EPROTONOSUPPORT + .yoink EPROTOTYPE + .yoink ERANGE + .yoink EREMCHG + .yoink EREMOTE + .yoink EREMOTEIO + .yoink ERESTART + .yoink ERFKILL + .yoink EROFS + .yoink ESHUTDOWN + .yoink ESOCKTNOSUPPORT + .yoink ESPIPE + .yoink ESRCH + .yoink ESRMNT + .yoink ESTALE + .yoink ESTRPIPE + .yoink ETIME + .yoink ETIMEDOUT + .yoink ETOOMANYREFS + .yoink ETXTBSY + .yoink EUCLEAN + .yoink EUNATCH + .yoink EUSERS + .yoink EXDEV + .yoink EXFULL .type kErrnoStart,@object .type kErrnoEnd,@object diff --git a/libc/fmt/palandftoa.c b/libc/fmt/palandftoa.c index b9051a72..0cf3974d 100644 --- a/libc/fmt/palandftoa.c +++ b/libc/fmt/palandftoa.c @@ -37,6 +37,12 @@ static const int kPow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; +/** + * Formats floating point number. + * + * @see xdtoa() for higher precision at the cost of bloat + * @see palandprintf() which is intended caller + */ int ftoa(int out(int, void *), void *arg, long double value, unsigned long prec, unsigned long width, unsigned long flags) { long whole, frac; diff --git a/libc/fmt/palandprintf.c b/libc/fmt/palandprintf.c index 819212c8..407658c1 100644 --- a/libc/fmt/palandprintf.c +++ b/libc/fmt/palandprintf.c @@ -56,7 +56,52 @@ static unsigned ppatoi(const char **str) { /** * Implements {,v}{,s{,n},{,{,x}as},f,d}printf state machine. - * @see libc/stdio/printf.c for documentation + * + * Type Specifiers + * + * - `%s` char * (thompson-pike unicode) + * - `%ls` wchar_t * (32-bit unicode → thompson-pike unicode) + * - `%hs` char16_t * (16-bit unicode → thompson-pike unicode) + * - `%b` int (radix 2 binary) + * - `%o` int (radix 8 octal) + * - `%d` int (radix 10 decimal) + * - `%x` int (radix 16 hexadecimal) + * - `%X` int (radix 16 hexadecimal uppercase) + * - `%u` unsigned + * - `%f` double + * - `%Lf` long double + * - `%p` pointer (48-bit hexadecimal) + * + * Length Modifiers + * + * - `%hhd` char (8-bit) + * - `%hd` short (16-bit) + * - `%ld` long (64-bit) + * - `%lu` unsigned long (64-bit) + * - `%lx` unsigned long (64-bit hexadecimal) + * - `%jd` intmax_t (128-bit) + * + * Width Modifiers + * + * - `%08d` fixed columns w/ zero leftpadding + * - `%8d` fixed columns w/ space leftpadding + * - `%*s` variable column string (thompson-pike) + * - `%.*s` variable column data (ignore nul terminator) + * + * Formatting Modifiers + * + * - `%,d` thousands separators + * - `%'s` escaped c string literal + * - `%'c` escaped c character literal + * - `%`s` escaped double quoted c string literal + * - `%`c` escaped double quoted c character literal + * - `%+d` plus leftpad if positive (aligns w/ negatives) + * - `% d` space leftpad if positive (aligns w/ negatives) + * - `%#s` datum (radix 256 null-terminated ibm cp437) + * - `%#x` int (radix 16 hexadecimal w/ 0x prefix if not zero) + * + * @note implementation detail of printf(), snprintf(), etc. + * @see printf() for wordier documentation */ hidden int palandprintf(void *fn, void *arg, const char *format, va_list va) { int (*out)(int, void *); diff --git a/libc/fmt/pflink.h b/libc/fmt/pflink.h index c55d1f5d..9cffa7b7 100644 --- a/libc/fmt/pflink.h +++ b/libc/fmt/pflink.h @@ -50,8 +50,18 @@ #endif #if defined(__GNUC__) && __GNUC__ < 6 +/* + * Compilers don't understand the features we've added to the format + * string DSL, such as c string escaping, therefore we can't use it. + * Ideally compilers should grant us more flexibility to define DSLs + * + * The recommended approach to turning this back on is `CFLAGS=-std=c11` + * which puts the compiler in __STRICT_ANSI__ mode, which Cosmopolitan + * respects by disabling all the esoteric tuning in headers like this. + */ #pragma GCC diagnostic ignored "-Wformat-security" #endif /* __GNUC__ + 0 < 6 */ + #else #define PFLINK(FMT) FMT #define SFLINK(FMT) FMT diff --git a/libc/fmt/snprintf.c b/libc/fmt/snprintf.c index 0b41a310..47d43c71 100644 --- a/libc/fmt/snprintf.c +++ b/libc/fmt/snprintf.c @@ -25,7 +25,7 @@ * @return number of bytes written, excluding the NUL terminator; or, * if the output buffer wasn't passed, or was too short, then the * number of characters that *would* have been written is returned - * @see libc/fmt/fmt.h for documentation + * @see palandprintf() and printf() for detailed documentation */ int(snprintf)(char* buf, size_t count, const char* fmt, ...) { int rc; diff --git a/libc/fmt/sprintf.c b/libc/fmt/sprintf.c index 0b361366..59bc9cb1 100644 --- a/libc/fmt/sprintf.c +++ b/libc/fmt/sprintf.c @@ -20,6 +20,12 @@ #include "libc/fmt/fmt.h" #include "libc/limits.h" +/** + * Formats string to buffer that's hopefully large enough. + * + * @see palandprintf() and printf() for detailed documentation + * @see snprintf() for same w/ buf size param + */ int(sprintf)(char *buf, const char *fmt, ...) { int rc; va_list va; diff --git a/libc/fmt/stoa.c b/libc/fmt/stoa.c index 93152a39..2ce5b5c2 100644 --- a/libc/fmt/stoa.c +++ b/libc/fmt/stoa.c @@ -74,6 +74,8 @@ forceinline int emitquote(int out(int, void *), void *arg, unsigned flags, * This function is used by palandprintf() to implement the %s and %c * directives. The content outputted to the array is always UTF-8, but * the input may be UTF-16 or UTF-32. + * + * @see palandprintf() */ int stoa(int out(int, void *), void *arg, void *data, unsigned long flags, unsigned long precision, unsigned long width, unsigned char signbit, diff --git a/libc/fmt/vcscanf.h b/libc/fmt/vcscanf.h index d8089ad9..23209e05 100644 --- a/libc/fmt/vcscanf.h +++ b/libc/fmt/vcscanf.h @@ -34,6 +34,9 @@ * 8-bit through 128-bit integers (with validation), floating point * numbers, etc. It can also be used to convert UTF-8 to UTF-16/32. * + * - `%d` parses integer + * - `%ms` parses string allocating buffer assigning pointer + * * @param callback supplies UTF-8 characters using -1 sentinel * @param fmt is a computer program embedded inside a c string, written * in a domain-specific programming language that, by design, lacks diff --git a/libc/fmt/vsnprintf.c b/libc/fmt/vsnprintf.c index 3767e40c..f557b659 100644 --- a/libc/fmt/vsnprintf.c +++ b/libc/fmt/vsnprintf.c @@ -40,7 +40,7 @@ static int vsnprintfputchar(unsigned char c, struct SprintfStr *str) { } /** - * Formats string to buffer. + * Formats string to buffer w/ preexisting vararg state. * * @param buf stores output and a NUL-terminator is always written, * provided buf!=NULL && size!=0 @@ -50,7 +50,7 @@ static int vsnprintfputchar(unsigned char c, struct SprintfStr *str) { * number of characters that *would* have been written is returned * @throw EOVERFLOW when a formatted field exceeds its limit, which can * be checked by setting errno to 0 before calling - * @see libc/fmt/fmt.h for further documentation + * @see palandprintf() and printf() for detailed documentation */ int(vsnprintf)(char *buf, size_t size, const char *fmt, va_list va) { struct SprintfStr str = {buf, 0, size}; diff --git a/libc/fmt/vsprintf.c b/libc/fmt/vsprintf.c index d1b0a3e6..a04cfa90 100644 --- a/libc/fmt/vsprintf.c +++ b/libc/fmt/vsprintf.c @@ -20,6 +20,12 @@ #include "libc/fmt/fmt.h" #include "libc/limits.h" +/** + * Formats string to buffer hopefully large enough w/ vararg state. + * + * @see palandprintf() and printf() for detailed documentation + * @see vsnprintf() for modern alternative w/ buf size param + */ int(vsprintf)(char *buf, const char *fmt, va_list va) { return (vsnprintf)(buf, INT_MAX, fmt, va); } diff --git a/libc/fmt/vsscanf.c b/libc/fmt/vsscanf.c index facb41a6..67e286b7 100644 --- a/libc/fmt/vsscanf.c +++ b/libc/fmt/vsscanf.c @@ -21,7 +21,7 @@ #include "libc/fmt/vsscanf.h" /** - * String decoder. + * Decodes string. * * @see libc/fmt/vcscanf.h (for docs and implementation) * @note to offer the best performance, we assume small codebases diff --git a/libc/integral/c.inc b/libc/integral/c.inc index 284b9758..d45562f8 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -1015,8 +1015,9 @@ typedef uint64_t uintmax_t; /** * Pulls source of object being compiled into zip. - * @note automates compliance with gpl terms - * @see -DIM_FEELING_NAUGHTY + * @note automates most compliance with gpl terms + * @see libc/zipos/zipcentraldir.S + * @see ape/ape.lds */ #ifdef __BASE_FILE__ STATIC_YOINK_SOURCE(__BASE_FILE__); diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index 4fab1cf1..4d206263 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -50,8 +50,7 @@ void exit(int) noreturn; void quick_exit(int) noreturn; void _exit(int) libcesque noreturn; void _Exit(int) libcesque noreturn; -void abort(void) noreturn noinstrument forcealignargpointer; -void abort_(void) asm("abort") noreturn noinstrument privileged; +void abort(void) noreturn noinstrument; void panic(void) noreturn noinstrument privileged; void triplf(void) noreturn noinstrument privileged; int __cxa_atexit(void *, void *, void *) libcesque; diff --git a/libc/stdio/fread.c b/libc/stdio/fread.c index f9c3ea47..bb90aaad 100644 --- a/libc/stdio/fread.c +++ b/libc/stdio/fread.c @@ -44,7 +44,7 @@ size_t fread(void *buf, size_t stride, size_t count, FILE *f) { if (i % stride != 0) abort(); /* todo(jart) */ return i / stride; } - p[i] = (unsigned char)c; + p[i] = c & 0xff; } return count; } diff --git a/libc/stdio/internal.h b/libc/stdio/internal.h index c57e872e..3e50bf54 100644 --- a/libc/stdio/internal.h +++ b/libc/stdio/internal.h @@ -12,13 +12,13 @@ extern unsigned char g_stderrbuf[BUFSIZ]; int fflushregister(FILE *) hidden; void fflushunregister(FILE *) hidden; -int freadbuf(FILE *f) hidden; -int fwritebuf(FILE *f) hidden; -int fsreadbuf(FILE *f) hidden; -int fswritebuf(FILE *f) hidden; -long fseteof(FILE *f) hidden; -long fseterrno(FILE *f) hidden; -long fseterr(FILE *f, int err) hidden; +int freadbuf(FILE *) hidden; +int fwritebuf(FILE *) hidden; +int fsreadbuf(FILE *) hidden; +int fswritebuf(FILE *) hidden; +long fseteof(FILE *) hidden; +long fseterrno(FILE *) hidden; +long fseterr(FILE *, int) hidden; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c index 4d6b8f3e..2cd3cfdc 100644 --- a/libc/stdio/printf.c +++ b/libc/stdio/printf.c @@ -59,6 +59,7 @@ * it implies the quoting modifier, wraps the value with {,u,L}['"] * quotes, displays NULL as "NULL" rather than "(null)", etc. * + * @see palandprintf() for intuitive reference documentation * @see {,v}{,s{,n},{,{,x}as},f,d}printf */ int(printf)(const char* fmt, ...) { diff --git a/libc/stdio/unlocked.h b/libc/stdio/unlocked.h index f6e7330b..d73ba55c 100644 --- a/libc/stdio/unlocked.h +++ b/libc/stdio/unlocked.h @@ -4,29 +4,29 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -int getc_unlocked(FILE *f) paramsnonnull(); +int getc_unlocked(FILE *) paramsnonnull(); int getchar_unlocked(void); -int putc_unlocked(int c, FILE *f) paramsnonnull(); -int putchar_unlocked(int c); -void clearerr_unlocked(FILE *f); -int feof_unlocked(FILE *f); -int ferror_unlocked(FILE *f); -int fileno_unlocked(FILE *f); -int fflush_unlocked(FILE *f); -int fgetc_unlocked(FILE *f); -int fputc_unlocked(int c, FILE *f); -size_t fread_unlocked(void *ptr, size_t size, size_t n, FILE *f); -size_t fwrite_unlocked(const void *ptr, size_t size, size_t n, FILE *f); -char *fgets_unlocked(char *s, int n, FILE *f); -int fputs_unlocked(const char *s, FILE *f); -wint_t getwc_unlocked(FILE *f); +int putc_unlocked(int, FILE *) paramsnonnull(); +int putchar_unlocked(int); +void clearerr_unlocked(FILE *); +int feof_unlocked(FILE *); +int ferror_unlocked(FILE *); +int fileno_unlocked(FILE *); +int fflush_unlocked(FILE *); +int fgetc_unlocked(FILE *); +int fputc_unlocked(int, FILE *); +size_t fread_unlocked(void *, size_t, size_t, FILE *); +size_t fwrite_unlocked(const void *, size_t, size_t, FILE *); +char *fgets_unlocked(char *, int, FILE *); +int fputs_unlocked(const char *, FILE *); +wint_t getwc_unlocked(FILE *); wint_t getwchar_unlocked(void); -wint_t fgetwc_unlocked(FILE *f); -wint_t fputwc_unlocked(wchar_t wc, FILE *f); -wint_t putwc_unlocked(wchar_t wc, FILE *f); -wint_t putwchar_unlocked(wchar_t wc); -wchar_t *fgetws_unlocked(wchar_t *ws, int n, FILE *f); -int fputws_unlocked(const wchar_t *ws, FILE *f); +wint_t fgetwc_unlocked(FILE *); +wint_t fputwc_unlocked(wchar_t, FILE *); +wint_t putwc_unlocked(wchar_t, FILE *); +wint_t putwchar_unlocked(wchar_t); +wchar_t *fgetws_unlocked(wchar_t *, int, FILE *); +int fputws_unlocked(const wchar_t *, FILE *); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/stdio/unlocked/clearerr_unlocked.S b/libc/stdio/unlocked/clearerr_unlocked.S index e18a39d4..41c19835 100644 --- a/libc/stdio/unlocked/clearerr_unlocked.S +++ b/libc/stdio/unlocked/clearerr_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ clearerr_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call clearerr - .leafepilogue + pop %rbp + ret .endfn clearerr_unlocked,globl diff --git a/libc/stdio/unlocked/feof_unlocked.S b/libc/stdio/unlocked/feof_unlocked.S index 56a73410..0d4fb4d6 100644 --- a/libc/stdio/unlocked/feof_unlocked.S +++ b/libc/stdio/unlocked/feof_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ feof_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call feof - .leafepilogue + pop %rbp + ret .endfn feof_unlocked,globl diff --git a/libc/stdio/unlocked/ferror_unlocked.S b/libc/stdio/unlocked/ferror_unlocked.S index fe4ea35e..a9c2caf6 100644 --- a/libc/stdio/unlocked/ferror_unlocked.S +++ b/libc/stdio/unlocked/ferror_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ ferror_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call ferror - .leafepilogue + pop %rbp + ret .endfn ferror_unlocked,globl diff --git a/libc/stdio/unlocked/fflush_unlocked.S b/libc/stdio/unlocked/fflush_unlocked.S index 73a8664a..f6a4424d 100644 --- a/libc/stdio/unlocked/fflush_unlocked.S +++ b/libc/stdio/unlocked/fflush_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ fflush_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call fflush - .leafepilogue + pop %rbp + ret .endfn fflush_unlocked,globl diff --git a/libc/stdio/unlocked/fgetc_unlocked.S b/libc/stdio/unlocked/fgetc_unlocked.S index 566ebe3a..8c1628d1 100644 --- a/libc/stdio/unlocked/fgetc_unlocked.S +++ b/libc/stdio/unlocked/fgetc_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ fgetc_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call fgetc - .leafepilogue + pop %rbp + ret .endfn fgetc_unlocked,globl diff --git a/libc/stdio/unlocked/fgets_unlocked.S b/libc/stdio/unlocked/fgets_unlocked.S index d3ac3250..229918f7 100644 --- a/libc/stdio/unlocked/fgets_unlocked.S +++ b/libc/stdio/unlocked/fgets_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ fgets_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call fgets - .leafepilogue + pop %rbp + ret .endfn fgets_unlocked,globl diff --git a/libc/stdio/unlocked/fgetwc_unlocked.S b/libc/stdio/unlocked/fgetwc_unlocked.S index db93268a..c069d27c 100644 --- a/libc/stdio/unlocked/fgetwc_unlocked.S +++ b/libc/stdio/unlocked/fgetwc_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ fgetwc_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call fgetwc - .leafepilogue + pop %rbp + ret .endfn fgetwc_unlocked,globl diff --git a/libc/stdio/unlocked/fgetws_unlocked.S b/libc/stdio/unlocked/fgetws_unlocked.S index 7b46bd40..70348cf5 100644 --- a/libc/stdio/unlocked/fgetws_unlocked.S +++ b/libc/stdio/unlocked/fgetws_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ fgetws_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call fgetws - .leafepilogue + pop %rbp + ret .endfn fgetws_unlocked,globl diff --git a/libc/stdio/unlocked/fileno_unlocked.S b/libc/stdio/unlocked/fileno_unlocked.S index 2d6d5e6a..5790e66d 100644 --- a/libc/stdio/unlocked/fileno_unlocked.S +++ b/libc/stdio/unlocked/fileno_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ fileno_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call fileno - .leafepilogue + pop %rbp + ret .endfn fileno_unlocked,globl diff --git a/libc/stdio/unlocked/fputc_unlocked.S b/libc/stdio/unlocked/fputc_unlocked.S index 7477b85d..83051a99 100644 --- a/libc/stdio/unlocked/fputc_unlocked.S +++ b/libc/stdio/unlocked/fputc_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ fputc_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call fputc - .leafepilogue + pop %rbp + ret .endfn fputc_unlocked,globl diff --git a/libc/stdio/unlocked/fputs_unlocked.S b/libc/stdio/unlocked/fputs_unlocked.S index 86637ced..d694eef7 100644 --- a/libc/stdio/unlocked/fputs_unlocked.S +++ b/libc/stdio/unlocked/fputs_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ fputs_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call fputs - .leafepilogue + pop %rbp + ret .endfn fputs_unlocked,globl diff --git a/libc/stdio/unlocked/fputwc_unlocked.S b/libc/stdio/unlocked/fputwc_unlocked.S index 32cbd42c..2ba5c1bf 100644 --- a/libc/stdio/unlocked/fputwc_unlocked.S +++ b/libc/stdio/unlocked/fputwc_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ fputwc_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call fputwc - .leafepilogue + pop %rbp + ret .endfn fputwc_unlocked,globl diff --git a/libc/stdio/unlocked/fputws_unlocked.S b/libc/stdio/unlocked/fputws_unlocked.S index 46683347..ef1c8ccf 100644 --- a/libc/stdio/unlocked/fputws_unlocked.S +++ b/libc/stdio/unlocked/fputws_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ fputws_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call fputws - .leafepilogue + pop %rbp + ret .endfn fputws_unlocked,globl diff --git a/libc/stdio/unlocked/fread_unlocked.S b/libc/stdio/unlocked/fread_unlocked.S index 8ef491a5..47884f7c 100644 --- a/libc/stdio/unlocked/fread_unlocked.S +++ b/libc/stdio/unlocked/fread_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ fread_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call fread - .leafepilogue + pop %rbp + ret .endfn fread_unlocked,globl diff --git a/libc/stdio/unlocked/fwrite_unlocked.S b/libc/stdio/unlocked/fwrite_unlocked.S index bd2a53b3..4bf7a268 100644 --- a/libc/stdio/unlocked/fwrite_unlocked.S +++ b/libc/stdio/unlocked/fwrite_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ fwrite_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call fwrite - .leafepilogue + pop %rbp + ret .endfn fwrite_unlocked,globl diff --git a/libc/stdio/unlocked/getc_unlocked.S b/libc/stdio/unlocked/getc_unlocked.S index 8cfa256d..d6bf704f 100644 --- a/libc/stdio/unlocked/getc_unlocked.S +++ b/libc/stdio/unlocked/getc_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ getc_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call getc - .leafepilogue + pop %rbp + ret .endfn getc_unlocked,globl diff --git a/libc/stdio/unlocked/getchar_unlocked.S b/libc/stdio/unlocked/getchar_unlocked.S index 44e27b34..c14b11db 100644 --- a/libc/stdio/unlocked/getchar_unlocked.S +++ b/libc/stdio/unlocked/getchar_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ getchar_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call getchar - .leafepilogue + pop %rbp + ret .endfn getchar_unlocked,globl diff --git a/libc/stdio/unlocked/getwc_unlocked.S b/libc/stdio/unlocked/getwc_unlocked.S index 428fe347..dab29c9f 100644 --- a/libc/stdio/unlocked/getwc_unlocked.S +++ b/libc/stdio/unlocked/getwc_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ getwc_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call fgetwc_unlocked - .leafepilogue + pop %rbp + ret .endfn getwc_unlocked,globl diff --git a/libc/stdio/unlocked/getwchar_unlocked.S b/libc/stdio/unlocked/getwchar_unlocked.S index 5a865f60..8556100e 100644 --- a/libc/stdio/unlocked/getwchar_unlocked.S +++ b/libc/stdio/unlocked/getwchar_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ getwchar_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call getwchar - .leafepilogue + pop %rbp + ret .endfn getwchar_unlocked,globl diff --git a/libc/stdio/unlocked/putc_unlocked.S b/libc/stdio/unlocked/putc_unlocked.S index 787b360e..8fe64b8f 100644 --- a/libc/stdio/unlocked/putc_unlocked.S +++ b/libc/stdio/unlocked/putc_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ putc_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call putc - .leafepilogue + pop %rbp + ret .endfn putc_unlocked,globl diff --git a/libc/stdio/unlocked/putchar_unlocked.S b/libc/stdio/unlocked/putchar_unlocked.S index 88bc3b87..0e598c99 100644 --- a/libc/stdio/unlocked/putchar_unlocked.S +++ b/libc/stdio/unlocked/putchar_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ putchar_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call putchar - .leafepilogue + pop %rbp + ret .endfn putchar_unlocked,globl diff --git a/libc/stdio/unlocked/putwc_unlocked.S b/libc/stdio/unlocked/putwc_unlocked.S index 90e97a19..3976a3e5 100644 --- a/libc/stdio/unlocked/putwc_unlocked.S +++ b/libc/stdio/unlocked/putwc_unlocked.S @@ -21,8 +21,10 @@ .source __FILE__ putwc_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call fputwc_unlocked - .leafepilogue + pop %rbp + ret .endfn putwc_unlocked,globl diff --git a/libc/stdio/unlocked/putwchar_unlocked.S b/libc/stdio/unlocked/putwchar_unlocked.S index 7015247a..af1282e0 100644 --- a/libc/stdio/unlocked/putwchar_unlocked.S +++ b/libc/stdio/unlocked/putwchar_unlocked.S @@ -22,8 +22,10 @@ .source __FILE__ putwchar_unlocked: - .leafprologue - .profilable # so we can fix code supporting this abomination + push %rbp + mov %rsp,%rbp + .profilable # note: no consensus for threads exists in abis call putwchar - .leafepilogue + pop %rbp + ret .endfn putwchar_unlocked,globl diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index 9a265f3a..e8221fd4 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -1760,18 +1760,6 @@ syscon misc READ_POSITION 52 0 0 0 0 syscon misc READ_REVERSE 15 0 0 0 0 syscon misc READ_TOC 67 0 0 0 0 -syscon glob GLOB_NOCHECK 0x10 0x10 0x10 0x10 0 # unix consensus -syscon glob GLOB_ABORTED 2 -2 -2 -2 0 # bsd consensus -syscon glob GLOB_APPEND 0x20 1 1 1 0 # bsd consensus -syscon glob GLOB_DOOFFS 8 2 2 2 0 # bsd consensus -syscon glob GLOB_ERR 1 4 4 4 0 # bsd consensus -syscon glob GLOB_MARK 2 8 8 8 0 # bsd consensus -syscon glob GLOB_NOMATCH 3 -3 -3 -3 0 # bsd consensus -syscon glob GLOB_NOSORT 4 0x20 0x20 0x20 0 # bsd consensus -syscon glob GLOB_NOSPACE 1 -1 -1 -1 0 # bsd consensus -syscon glob GLOB_NOSYS 4 -4 -4 -4 0 # bsd consensus -syscon glob GLOB_NOESCAPE 0x40 0x2000 0x2000 0x1000 0 - # getpriority() / setpriority() magnums (a.k.a. nice) # # group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary diff --git a/libc/sysv/consts/glob.h b/libc/sysv/consts/glob.h deleted file mode 100644 index 20052227..00000000 --- a/libc/sysv/consts/glob.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_GLOB_H_ -#define COSMOPOLITAN_LIBC_SYSV_CONSTS_GLOB_H_ -#include "libc/runtime/symbolic.h" - -#define GLOB_ABORTED SYMBOLIC(GLOB_ABORTED) -#define GLOB_APPEND SYMBOLIC(GLOB_APPEND) -#define GLOB_DOOFFS SYMBOLIC(GLOB_DOOFFS) -#define GLOB_ERR SYMBOLIC(GLOB_ERR) -#define GLOB_MARK SYMBOLIC(GLOB_MARK) -#define GLOB_NOCHECK SYMBOLIC(GLOB_NOCHECK) -#define GLOB_NOESCAPE SYMBOLIC(GLOB_NOESCAPE) -#define GLOB_NOMATCH SYMBOLIC(GLOB_NOMATCH) -#define GLOB_NOSORT SYMBOLIC(GLOB_NOSORT) -#define GLOB_NOSPACE SYMBOLIC(GLOB_NOSPACE) -#define GLOB_NOSYS SYMBOLIC(GLOB_NOSYS) - -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -hidden extern const long GLOB_ABORTED; -hidden extern const long GLOB_APPEND; -hidden extern const long GLOB_DOOFFS; -hidden extern const long GLOB_ERR; -hidden extern const long GLOB_MARK; -hidden extern const long GLOB_NOCHECK; -hidden extern const long GLOB_NOESCAPE; -hidden extern const long GLOB_NOMATCH; -hidden extern const long GLOB_NOSORT; -hidden extern const long GLOB_NOSPACE; -hidden extern const long GLOB_NOSYS; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_GLOB_H_ */ diff --git a/libc/x/x.h b/libc/x/x.h index d12a7e47..51d30c4d 100644 --- a/libc/x/x.h +++ b/libc/x/x.h @@ -60,6 +60,7 @@ void *xvalloc(size_t) attributeallocsize((1)) _XMALPG; void *xmemalign(size_t, size_t) attributeallocalign((1)) attributeallocsize((2)) _XMAL; char *xstrdup(const char *) _XPNN _XMAL; +char *xstrndup(const char *, size_t) _XPNN _XMAL; char *xstrcat(const char *, ...) paramsnonnull((1)) nullterminated() _XMAL; char *xstrmul(const char *, size_t) paramsnonnull((1)) _XMAL; char *xinet_ntop(int, const void *) _XPNN _XMAL; diff --git a/libc/x/xstrndup.c b/libc/x/xstrndup.c new file mode 100644 index 00000000..4927a6ee --- /dev/null +++ b/libc/x/xstrndup.c @@ -0,0 +1,36 @@ +/*-*- 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 │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/log/log.h" +#include "libc/mem/mem.h" +#include "libc/x/x.h" + +/** + * Allocates new copy of string, with byte limit. + * + * @param s is a NUL-terminated byte string + * @param n if less than strlen(s) will truncate the string + * @return new string or NULL w/ errno + * @error ENOMEM + */ +char *xstrndup(const char *s, size_t n) { + void *res = strndup(s, n); + if (!res) die(); + return res; +} diff --git a/test/libc/fmt/sprintf_s.inc b/test/libc/fmt/sprintf_s.inc index 37e1c82a..31e17a19 100644 --- a/test/libc/fmt/sprintf_s.inc +++ b/test/libc/fmt/sprintf_s.inc @@ -41,6 +41,7 @@ TEST(SUITE(sprintf), testCharacterCounting) { TEST(SUITE(snprintf), testTableFlip) { EXPECT_STREQ("Table flip ", Format("%-20ls", L"Table flip")); EXPECT_STREQ("(╯°□°)╯︵ ┻━┻ ", Format("%-20ls", L"(╯°□°)╯︵ ┻━┻")); + EXPECT_STREQ("(╯°□°)╯︵ ┻━┻ ", Format("%-20hs", u"(╯°□°)╯︵ ┻━┻")); EXPECT_STREQ("ちゃぶ台返し ", Format("%-20ls", L"ちゃぶ台返し")); EXPECT_STREQ(" (╯°□°)╯︵ ┻━┻", Format("%20ls", L"(╯°□°)╯︵ ┻━┻")); EXPECT_STREQ(" ちゃぶ台返し", Format("%20ls", L"ちゃぶ台返し")); diff --git a/test/libc/xed/x86ild_test.c b/test/libc/xed/x86ild_test.c index 1e078688..c24635f3 100644 --- a/test/libc/xed/x86ild_test.c +++ b/test/libc/xed/x86ild_test.c @@ -27,8 +27,8 @@ * * It is demonstrated that our 3.5kb x86 parser supports all legal x86 * instruction set architectures and addressing modes since the 1970's, - * including the really complicated ones, e.g. avx512; or the unpopular - * ones, e.g. amd 3dnow. + * including the really sophisticated ones, e.g. avx512, as well as the + * less popular ones, e.g. 3dnow. */ TEST(x86ild, testSomeThingsNeverChange) { diff --git a/third_party/avir/avir1.h b/third_party/avir/avir1.h index 541811b8..f803de03 100644 --- a/third_party/avir/avir1.h +++ b/third_party/avir/avir1.h @@ -7,11 +7,10 @@ struct avir1 { void *p; }; -void avir1init(struct avir1 *self); -void avir1free(struct avir1 *self); -void avir1(struct avir1 *resizer, size_t dyn, size_t dxn, void *dst, - size_t dstsize, size_t syn, size_t sxn, size_t ssw, const void *src, - size_t srcsize); +void avir1init(struct avir1 *); +void avir1free(struct avir1 *); +void avir1(struct avir1 *, size_t, size_t, void *, size_t, size_t, size_t, + size_t, const void *, size_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/third_party/avir/avir_float4_sse.h b/third_party/avir/avir_float4_sse.h index 115e2ddc..6d3cb1ff 100644 --- a/third_party/avir/avir_float4_sse.h +++ b/third_party/avir/avir_float4_sse.h @@ -20,6 +20,7 @@ #include "libc/bits/mmintrin.h" #include "libc/bits/xmmintrin.h" #include "libc/bits/xmmintrin.h" +#include "libc/bits/xmmintrin.h" #include "libc/bits/emmintrin.h" namespace avir { diff --git a/third_party/musl/fnmatch.c b/third_party/musl/fnmatch.c new file mode 100644 index 00000000..058b5d80 --- /dev/null +++ b/third_party/musl/fnmatch.c @@ -0,0 +1,368 @@ +/*-*- 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│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2014 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/limits.h" +#include "libc/str/str.h" +#include "third_party/musl/fnmatch.h" + +/* + * An implementation of what I call the "Sea of Stars" algorithm for + * POSIX fnmatch(). The basic idea is that we factor the pattern into + * a head component (which we match first and can reject without ever + * measuring the length of the string), an optional tail component + * (which only exists if the pattern contains at least one star), and + * an optional "sea of stars", a set of star-separated components + * between the head and tail. After the head and tail matches have + * been removed from the input string, the components in the "sea of + * stars" are matched sequentially by searching for their first + * occurrence past the end of the previous match. + * + * - Rich Felker, April 2012 + */ + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2014 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); + +#define END 0 +#define UNMATCHABLE -2 +#define BRACKET -3 +#define QUESTION -4 +#define STAR -5 + +static int FnmatchNextString(const char *str, size_t n, size_t *step) { + if (!n) { + *step = 0; + return 0; + } + if (str[0] >= 128U) { + wchar_t wc; + int k = mbtowc(&wc, str, n); + if (k < 0) { + *step = 1; + return -1; + } + *step = k; + return wc; + } + *step = 1; + return str[0]; +} + +static int FnmatchNextPattern(const char *pat, size_t m, size_t *step, + int flags) { + int esc = 0; + if (!m || !*pat) { + *step = 0; + return END; + } + *step = 1; + if (pat[0] == '\\' && pat[1] && !(flags & FNM_NOESCAPE)) { + *step = 2; + pat++; + esc = 1; + goto escaped; + } + if (pat[0] == '[') { + size_t k = 1; + if (k < m) + if (pat[k] == '^' || pat[k] == '!') k++; + if (k < m) + if (pat[k] == ']') k++; + for (; k < m && pat[k] && pat[k] != ']'; k++) { + if (k + 1 < m && pat[k + 1] && pat[k] == '[' && + (pat[k + 1] == ':' || pat[k + 1] == '.' || pat[k + 1] == '=')) { + int z = pat[k + 1]; + k += 2; + if (k < m && pat[k]) k++; + while (k < m && pat[k] && (pat[k - 1] != z || pat[k] != ']')) k++; + if (k == m || !pat[k]) break; + } + } + if (k == m || !pat[k]) { + *step = 1; + return '['; + } + *step = k + 1; + return BRACKET; + } + if (pat[0] == '*') return STAR; + if (pat[0] == '?') return QUESTION; +escaped: + if (pat[0] >= 128U) { + wchar_t wc; + int k = mbtowc(&wc, pat, m); + if (k < 0) { + *step = 0; + return UNMATCHABLE; + } + *step = k + esc; + return wc; + } + return pat[0]; +} + +static int FnmatchCaseFold(int k) { + int c = towupper(k); + return c == k ? towlower(k) : c; +} + +static int FnmatchBracket(const char *p, int k, int kfold) { + wchar_t wc; + int inv = 0; + p++; + if (*p == '^' || *p == '!') { + inv = 1; + p++; + } + if (*p == ']') { + if (k == ']') return !inv; + p++; + } else if (*p == '-') { + if (k == '-') return !inv; + p++; + } + wc = p[-1]; + for (; *p != ']'; p++) { + if (p[0] == '-' && p[1] != ']') { + wchar_t wc2; + int l = mbtowc(&wc2, p + 1, 4); + if (l < 0) return 0; + if (wc <= wc2) + if ((unsigned)k - wc <= wc2 - wc || (unsigned)kfold - wc <= wc2 - wc) + return !inv; + p += l - 1; + continue; + } + if (p[0] == '[' && (p[1] == ':' || p[1] == '.' || p[1] == '=')) { + const char *p0 = p + 2; + int z = p[1]; + p += 3; + while (p[-1] != z || p[0] != ']') p++; + if (z == ':' && p - 1 - p0 < 16) { + char buf[16]; + memcpy(buf, p0, p - 1 - p0); + buf[p - 1 - p0] = 0; + if (iswctype(k, wctype(buf)) || iswctype(kfold, wctype(buf))) + return !inv; + } + continue; + } + if (*p < 128U) { + wc = (unsigned char)*p; + } else { + int l = mbtowc(&wc, p, 4); + if (l < 0) return 0; + p += l - 1; + } + if (wc == k || wc == kfold) return !inv; + } + return inv; +} + +static int FnmatchPerform(const char *pat, size_t m, const char *str, size_t n, + int flags) { + const char *p, *ptail, *endpat; + const char *s, *stail, *endstr; + size_t pinc, sinc, tailcnt = 0; + int c, k, kfold; + + if (flags & FNM_PERIOD) { + if (*str == '.' && *pat != '.') { + return FNM_NOMATCH; + } + } + + for (;;) { + switch ((c = FnmatchNextPattern(pat, m, &pinc, flags))) { + case UNMATCHABLE: + return FNM_NOMATCH; + case STAR: + pat++; + m--; + break; + default: + k = FnmatchNextString(str, n, &sinc); + if (k <= 0) return (c == END) ? 0 : FNM_NOMATCH; + str += sinc; + n -= sinc; + kfold = flags & FNM_CASEFOLD ? FnmatchCaseFold(k) : k; + if (c == BRACKET) { + if (!FnmatchBracket(pat, k, kfold)) return FNM_NOMATCH; + } else if (c != QUESTION && k != c && kfold != c) { + return FNM_NOMATCH; + } + pat += pinc; + m -= pinc; + continue; + } + break; + } + + /* Compute real pat length if it was initially unknown/-1 */ + m = strnlen(pat, m); + endpat = pat + m; + + /* Find the last * in pat and count chars needed after it */ + for (p = ptail = pat; p < endpat; p += pinc) { + switch (FnmatchNextPattern(p, endpat - p, &pinc, flags)) { + case UNMATCHABLE: + return FNM_NOMATCH; + case STAR: + tailcnt = 0; + ptail = p + 1; + break; + default: + tailcnt++; + break; + } + } + + /* Past this point we need not check for UNMATCHABLE in pat, + * because all of pat has already been parsed once. */ + + /* Compute real str length if it was initially unknown/-1 */ + n = strnlen(str, n); + endstr = str + n; + if (n < tailcnt) { + return FNM_NOMATCH; + } + + /* Find the final tailcnt chars of str, accounting for UTF-8. + * On illegal sequences we may get it wrong, but in that case + * we necessarily have a matching failure anyway. */ + for (s = endstr; s > str && tailcnt; tailcnt--) { + if (s[-1] < 128U || MB_CUR_MAX == 1) { + s--; + } else { + while ((unsigned char)*--s - 0x80U < 0x40 && s > str) + ; + } + } + if (tailcnt) return FNM_NOMATCH; + stail = s; + + /* Check that the pat and str tails match */ + p = ptail; + for (;;) { + c = FnmatchNextPattern(p, endpat - p, &pinc, flags); + p += pinc; + if ((k = FnmatchNextString(s, endstr - s, &sinc)) <= 0) { + if (c != END) return FNM_NOMATCH; + break; + } + s += sinc; + kfold = flags & FNM_CASEFOLD ? FnmatchCaseFold(k) : k; + if (c == BRACKET) { + if (!FnmatchBracket(p - pinc, k, kfold)) return FNM_NOMATCH; + } else if (c != QUESTION && k != c && kfold != c) { + return FNM_NOMATCH; + } + } + + /* We're all done with the tails now, so throw them out */ + endstr = stail; + endpat = ptail; + + /* Match pattern components until there are none left */ + while (pat < endpat) { + p = pat; + s = str; + for (;;) { + c = FnmatchNextPattern(p, endpat - p, &pinc, flags); + p += pinc; + /* Encountering * completes/commits a component */ + if (c == STAR) { + pat = p; + str = s; + break; + } + k = FnmatchNextString(s, endstr - s, &sinc); + if (!k) return FNM_NOMATCH; + kfold = flags & FNM_CASEFOLD ? FnmatchCaseFold(k) : k; + if (c == BRACKET) { + if (!FnmatchBracket(p - pinc, k, kfold)) break; + } else if (c != QUESTION && k != c && kfold != c) { + break; + } + s += sinc; + } + if (c == STAR) continue; + /* If we failed, advance str, by 1 char if it's a valid + * char, or past all invalid bytes otherwise. */ + k = FnmatchNextString(str, endstr - str, &sinc); + if (k > 0) { + str += sinc; + } else { + str++; + while (FnmatchNextString(str, endstr - str, &sinc) < 0) { + str++; + } + } + } + + return 0; +} + +/** + * Matches filename. + * + * - `*` for wildcard + * - `?` for single character + * - `[abc]` to match character within set + * - `[!abc]` to match character not within set + * - `\*\?\[\]` for escaping above special syntax + * + * @see glob() + */ +int fnmatch(const char *pat, const char *str, int flags) { + const char *s, *p; + size_t inc; + int c; + if (flags & FNM_PATHNAME) { + for (;;) { + for (s = str; *s && *s != '/'; s++) + ; + for (p = pat; + (c = FnmatchNextPattern(p, -1, &inc, flags)) != END && c != '/'; + p += inc) + ; + if (c != *s && (!*s || !(flags & FNM_LEADING_DIR))) return FNM_NOMATCH; + if (FnmatchPerform(pat, p - pat, str, s - str, flags)) return FNM_NOMATCH; + if (!c) return 0; + str = s + 1; + pat = p + inc; + } + } else if (flags & FNM_LEADING_DIR) { + for (s = str; *s; s++) { + if (*s != '/') continue; + if (!FnmatchPerform(pat, -1, str, s - str, flags)) return 0; + } + } + return FnmatchPerform(pat, -1, str, -1, flags); +} diff --git a/third_party/musl/fnmatch.h b/third_party/musl/fnmatch.h new file mode 100644 index 00000000..aab73ce5 --- /dev/null +++ b/third_party/musl/fnmatch.h @@ -0,0 +1,20 @@ +#ifndef COSMOPOLITAN_THIRD_PARTY_REGEX_FNMATCH_H_ +#define COSMOPOLITAN_THIRD_PARTY_REGEX_FNMATCH_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +#define FNM_PATHNAME 0x1 +#define FNM_NOESCAPE 0x2 +#define FNM_PERIOD 0x4 +#define FNM_LEADING_DIR 0x8 +#define FNM_CASEFOLD 0x10 +#define FNM_FILE_NAME FNM_PATHNAME + +#define FNM_NOMATCH 1 +#define FNM_NOSYS (-1) + +int fnmatch(const char *, const char *, int); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_THIRD_PARTY_REGEX_FNMATCH_H_ */ diff --git a/third_party/musl/glob.c b/third_party/musl/glob.c new file mode 100644 index 00000000..336e38f4 --- /dev/null +++ b/third_party/musl/glob.c @@ -0,0 +1,320 @@ +/*-*- 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│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2014 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/alg/alg.h" +#include "libc/calls/calls.h" +#include "libc/calls/struct/dirent.h" +#include "libc/calls/struct/stat.h" +#include "libc/errno.h" +#include "libc/mem/mem.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/dt.h" +#include "third_party/musl/fnmatch.h" +#include "third_party/musl/glob.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2014 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); + +struct GlobList { + struct GlobList *next; + char name[]; +}; + +static int AppendGlob(struct GlobList **tail, const char *name, size_t len, + int mark) { + struct GlobList *new; + if ((new = malloc(sizeof(struct GlobList) + len + 2))) { + (*tail)->next = new; + new->next = NULL; + memcpy(new->name, name, len + 1); + if (mark && len && name[len - 1] != '/') { + new->name[len] = '/'; + new->name[len + 1] = 0; + } + *tail = new; + return 0; + } else { + return -1; + } +} + +static int PerformGlob(char *buf, size_t pos, int type, char *pat, int flags, + int (*errfunc)(const char *path, int err), + struct GlobList **tail) { + DIR *dir; + size_t l; + char *p, *p2; + char saved_sep; + ptrdiff_t i, j; + struct stat st; + struct dirent *de; + int r, readerr, in_bracket, overflow, old_errno, fnm_flags; + /* If GLOB_MARK is unused, we don't care about type. */ + if (!type && !(flags & GLOB_MARK)) type = DT_REG; + /* Special-case the remaining pattern being all slashes, in + * which case we can use caller-passed type if it's a dir. */ + if (*pat && type != DT_DIR) type = 0; + while (pos + 1 < PATH_MAX && *pat == '/') { + buf[pos++] = *pat++; + } + /* Consume maximal [escaped-]literal prefix of pattern, copying + * and un-escaping it to the running buffer as we go. */ + i = 0; + j = 0; + overflow = 0; + in_bracket = 0; + for (; pat[i] != '*' && pat[i] != '?' && (!in_bracket || pat[i] != ']'); + i++) { + if (!pat[i]) { + if (overflow) return 0; + pat += i; + pos += j; + i = j = 0; + break; + } else if (pat[i] == '[') { + in_bracket = 1; + } else if (pat[i] == '\\' && !(flags & GLOB_NOESCAPE)) { + /* Backslashes inside a bracket are (at least by + * our interpretation) non-special, so if next + * char is ']' we have a complete expression. */ + if (in_bracket && pat[i + 1] == ']') break; + /* Unpaired final backslash never matches. */ + if (!pat[i + 1]) return 0; + i++; + } + if (pat[i] == '/') { + if (overflow) return 0; + in_bracket = 0; + pat += i + 1; + i = -1; + pos += j + 1; + j = -1; + } + /* Only store a character if it fits in the buffer, but if + * a potential bracket expression is open, the overflow + * must be remembered and handled later only if the bracket + * is unterminated (and thereby a literal), so as not to + * disallow long bracket expressions with short matches. */ + if (pos + (j + 1) < PATH_MAX) { + buf[pos + j++] = pat[i]; + } else if (in_bracket) { + overflow = 1; + } else { + return 0; + } + /* If we consume any new components, the caller-passed type + * or dummy type from above is no longer valid. */ + type = 0; + } + buf[pos] = 0; + if (!*pat) { + /* If we consumed any components above, or if GLOB_MARK is + * requested and we don't yet know if the match is a dir, + * we must call stat to confirm the file exists and/or + * determine its type. */ + if ((flags & GLOB_MARK) && type == DT_LNK) type = 0; + if (!type && stat(buf, &st)) { + if (errno != ENOENT && (errfunc(buf, errno) || (flags & GLOB_ERR))) { + return GLOB_ABORTED; + } + return 0; + } + if (!type && S_ISDIR(st.st_mode)) type = DT_DIR; + if (AppendGlob(tail, buf, pos, (flags & GLOB_MARK) && type == DT_DIR)) { + return GLOB_NOSPACE; + } + return 0; + } + p2 = strchr(pat, '/'); + saved_sep = '/'; + /* Check if the '/' was escaped and, if so, remove the escape char + * so that it will not be unpaired when passed to fnmatch. */ + if (p2 && !(flags & GLOB_NOESCAPE)) { + for (p = p2; p > pat && p[-1] == '\\'; p--) + ; + if ((p2 - p) % 2) { + p2--; + saved_sep = '\\'; + } + } + dir = opendir(pos ? buf : "."); + if (!dir) { + if (errfunc(buf, errno) || (flags & GLOB_ERR)) return GLOB_ABORTED; + return 0; + } + old_errno = errno; + while (errno = 0, de = readdir(dir)) { + /* Quickly skip non-directories when there's pattern left. */ + if (p2 && de->d_type && de->d_type != DT_DIR && de->d_type != DT_LNK) { + continue; + } + l = strlen(de->d_name); + if (l >= PATH_MAX - pos) continue; + if (p2) *p2 = 0; + fnm_flags = ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) | + ((!(flags & GLOB_PERIOD)) ? FNM_PERIOD : 0); + if (fnmatch(pat, de->d_name, fnm_flags)) continue; + /* With GLOB_PERIOD don't allow matching . or .. unless fnmatch() + * would match them with FNM_PERIOD rules in effect. */ + if (p2 && (flags & GLOB_PERIOD) && de->d_name[0] == '.' && + (!de->d_name[1] || de->d_name[1] == '.' && !de->d_name[2]) && + fnmatch(pat, de->d_name, fnm_flags | FNM_PERIOD)) { + continue; + } + memcpy(buf + pos, de->d_name, l + 1); + if (p2) *p2 = saved_sep; + r = PerformGlob(buf, pos + l, de->d_type, p2 ? p2 : "", flags, errfunc, + tail); + if (r) { + closedir(dir); + return r; + } + } + readerr = errno; + if (p2) *p2 = saved_sep; + closedir(dir); + if (readerr && (errfunc(buf, errno) || (flags & GLOB_ERR))) { + return GLOB_ABORTED; + } + errno = old_errno; + return 0; +} + +static int IgnoreGlobError(const char *path, int err) { + return 0; +} + +static void FreeGlobList(struct GlobList *head) { + struct GlobList *match, *next; + for (match = head->next; match; match = next) { + next = match->next; + free(match); + } +} + +static int GlobPredicate(const void *a, const void *b) { + return strcmp(*(const char **)a, *(const char **)b); +} + +/** + * Finds pathnames matching pattern. + * + * For example: + * + * glob_t g = {.gl_offs = 2}; + * glob("*.*", GLOB_DOOFFS, NULL, &g); + * glob("../.*", GLOB_DOOFFS | GLOB_APPEND, NULL, &g); + * g.gl_pathv[0] = "ls"; + * g.gl_pathv[1] = "-l"; + * execvp("ls", &g.gl_pathv[0]); + * globfree(g); + * + * @param pat can have star wildcard see fnmatch() + * @param g will receive matching entries and needs globfree() + * @return 0 on success or GLOB_NOMATCH, GLOB_NOSPACE on OOM, or + * GLOB_ABORTED on read error + */ +int glob(const char *pat, int flags, int errfunc(const char *path, int err), + glob_t *g) { + int error = 0; + size_t cnt, i; + char *p, **pathv, buf[PATH_MAX]; + struct GlobList head = {.next = NULL}, *tail = &head; + size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0; + if (!errfunc) errfunc = IgnoreGlobError; + if (!(flags & GLOB_APPEND)) { + g->gl_offs = offs; + g->gl_pathc = 0; + g->gl_pathv = NULL; + } + if (*pat) { + char *p = strdup(pat); + if (!p) return GLOB_NOSPACE; + buf[0] = 0; + error = PerformGlob(buf, 0, 0, p, flags, errfunc, &tail); + free(p); + } + if (error == GLOB_NOSPACE) { + FreeGlobList(&head); + return error; + } + for (cnt = 0, tail = head.next; tail; tail = tail->next, cnt++) + ; + if (!cnt) { + if (flags & GLOB_NOCHECK) { + tail = &head; + if (AppendGlob(&tail, pat, strlen(pat), 0)) { + return GLOB_NOSPACE; + } + cnt++; + } else + return GLOB_NOMATCH; + } + if (flags & GLOB_APPEND) { + pathv = + realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *)); + if (!pathv) { + FreeGlobList(&head); + return GLOB_NOSPACE; + } + g->gl_pathv = pathv; + offs += g->gl_pathc; + } else { + g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *)); + if (!g->gl_pathv) { + FreeGlobList(&head); + return GLOB_NOSPACE; + } + for (i = 0; i < offs; i++) { + g->gl_pathv[i] = NULL; + } + } + for (i = 0, tail = head.next; i < cnt; tail = tail->next, i++) { + g->gl_pathv[offs + i] = tail->name; + } + g->gl_pathv[offs + i] = NULL; + g->gl_pathc += cnt; + if (!(flags & GLOB_NOSORT)) { + qsort(g->gl_pathv + offs, cnt, sizeof(char *), GlobPredicate); + } + return error; +} + +/** + * Frees entries allocated by glob(). + */ +void globfree(glob_t *g) { + size_t i; + for (i = 0; i < g->gl_pathc; i++) { + free(g->gl_pathv[g->gl_offs + i] - offsetof(struct GlobList, name)); + } + free(g->gl_pathv); + g->gl_pathc = 0; + g->gl_pathv = NULL; +} diff --git a/third_party/musl/glob.h b/third_party/musl/glob.h new file mode 100644 index 00000000..21758f15 --- /dev/null +++ b/third_party/musl/glob.h @@ -0,0 +1,36 @@ +#ifndef COSMOPOLITAN_THIRD_PARTY_MUSL_GLOB_H_ +#define COSMOPOLITAN_THIRD_PARTY_MUSL_GLOB_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +#define GLOB_ERR 0x01 +#define GLOB_MARK 0x02 +#define GLOB_NOSORT 0x04 +#define GLOB_DOOFFS 0x08 /* reserves null slots at start of gl_pathv */ +#define GLOB_NOCHECK 0x10 /* just yield pattern if GLOB_NOMATCH happens */ +#define GLOB_APPEND 0x20 /* enables us to call glob() multiple times */ +#define GLOB_NOESCAPE 0x40 /* don't allow things like \*\?\[\] escaping */ +#define GLOB_PERIOD 0x80 + +#define GLOB_TILDE 0x1000 +#define GLOB_TILDE_CHECK 0x4000 + +#define GLOB_NOSPACE 1 +#define GLOB_ABORTED 2 +#define GLOB_NOMATCH 3 +#define GLOB_NOSYS 4 + +typedef struct { + size_t gl_pathc; + char **gl_pathv; + size_t gl_offs; + int __dummy1; + void *__dummy2[5]; +} glob_t; + +int glob(const char *, int, int (*)(const char *, int), glob_t *); +void globfree(glob_t *); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_THIRD_PARTY_MUSL_GLOB_H_ */ diff --git a/third_party/musl/musl.mk b/third_party/musl/musl.mk index b6975925..6c66ddae 100644 --- a/third_party/musl/musl.mk +++ b/third_party/musl/musl.mk @@ -18,7 +18,9 @@ THIRD_PARTY_MUSL_A_OBJS = \ $(THIRD_PARTY_MUSL_A_SRCS:%.c=o/$(MODE)/%.o) THIRD_PARTY_MUSL_A_DIRECTDEPS = \ + LIBC_ALG \ LIBC_CALLS \ + LIBC_CALLS_HEFTY \ LIBC_MEM \ LIBC_NEXGEN32E \ LIBC_STDIO \ diff --git a/third_party/regex/glob.c.todo b/third_party/regex/glob.c.todo deleted file mode 100644 index b0118091..00000000 --- a/third_party/regex/glob.c.todo +++ /dev/null @@ -1,294 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi│ -╚─────────────────────────────────────────────────────────────────────────────*/ -/* clang-format off */ - -/* - Musl Libc - Copyright © 2005-2014 Rich Felker, et al. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#define _BSD_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include - -asm(".ident\t\"\\n\\n\ -Musl Libc » glob (MIT License)\\n\ -Copyright 2005-2014 Rich Felker\""); - -struct match -{ - struct match *next; - char name[]; -}; - -static int append(struct match **tail, const char *name, size_t len, int mark) -{ - struct match *new = malloc(sizeof(struct match) + len + 2); - if (!new) return -1; - (*tail)->next = new; - new->next = NULL; - memcpy(new->name, name, len+1); - if (mark && len && name[len-1]!='/') { - new->name[len] = '/'; - new->name[len+1] = 0; - } - *tail = new; - return 0; -} - -static int do_glob(char *buf, size_t pos, int type, char *pat, int flags, int (*errfunc)(const char *path, int err), struct match **tail) -{ - /* If GLOB_MARK is unused, we don't care about type. */ - if (!type && !(flags & GLOB_MARK)) type = DT_REG; - - /* Special-case the remaining pattern being all slashes, in - * which case we can use caller-passed type if it's a dir. */ - if (*pat && type!=DT_DIR) type = 0; - while (pos+1 < PATH_MAX && *pat=='/') buf[pos++] = *pat++; - - /* Consume maximal [escaped-]literal prefix of pattern, copying - * and un-escaping it to the running buffer as we go. */ - ptrdiff_t i=0, j=0; - int in_bracket = 0, overflow = 0; - for (; pat[i]!='*' && pat[i]!='?' && (!in_bracket || pat[i]!=']'); i++) { - if (!pat[i]) { - if (overflow) return 0; - pat += i; - pos += j; - i = j = 0; - break; - } else if (pat[i] == '[') { - in_bracket = 1; - } else if (pat[i] == '\\' && !(flags & GLOB_NOESCAPE)) { - /* Backslashes inside a bracket are (at least by - * our interpretation) non-special, so if next - * char is ']' we have a complete expression. */ - if (in_bracket && pat[i+1]==']') break; - /* Unpaired final backslash never matches. */ - if (!pat[i+1]) return 0; - i++; - } - if (pat[i] == '/') { - if (overflow) return 0; - in_bracket = 0; - pat += i+1; - i = -1; - pos += j+1; - j = -1; - } - /* Only store a character if it fits in the buffer, but if - * a potential bracket expression is open, the overflow - * must be remembered and handled later only if the bracket - * is unterminated (and thereby a literal), so as not to - * disallow long bracket expressions with short matches. */ - if (pos+(j+1) < PATH_MAX) { - buf[pos+j++] = pat[i]; - } else if (in_bracket) { - overflow = 1; - } else { - return 0; - } - /* If we consume any new components, the caller-passed type - * or dummy type from above is no longer valid. */ - type = 0; - } - buf[pos] = 0; - if (!*pat) { - /* If we consumed any components above, or if GLOB_MARK is - * requested and we don't yet know if the match is a dir, - * we must call stat to confirm the file exists and/or - * determine its type. */ - struct stat st; - if ((flags & GLOB_MARK) && type==DT_LNK) type = 0; - if (!type && stat(buf, &st)) { - if (errno!=ENOENT && (errfunc(buf, errno) || (flags & GLOB_ERR))) - return GLOB_ABORTED; - return 0; - } - if (!type && S_ISDIR(st.st_mode)) type = DT_DIR; - if (append(tail, buf, pos, (flags & GLOB_MARK) && type==DT_DIR)) - return GLOB_NOSPACE; - return 0; - } - char *p2 = strchr(pat, '/'), saved_sep = '/'; - /* Check if the '/' was escaped and, if so, remove the escape char - * so that it will not be unpaired when passed to fnmatch. */ - if (p2 && !(flags & GLOB_NOESCAPE)) { - char *p; - for (p=p2; p>pat && p[-1]=='\\'; p--); - if ((p2-p)%2) { - p2--; - saved_sep = '\\'; - } - } - DIR *dir = opendir(pos ? buf : "."); - if (!dir) { - if (errfunc(buf, errno) || (flags & GLOB_ERR)) - return GLOB_ABORTED; - return 0; - } - int old_errno = errno; - struct dirent *de; - while (errno=0, de=readdir(dir)) { - /* Quickly skip non-directories when there's pattern left. */ - if (p2 && de->d_type && de->d_type!=DT_DIR && de->d_type!=DT_LNK) - continue; - - size_t l = strlen(de->d_name); - if (l >= PATH_MAX-pos) continue; - - if (p2) *p2 = 0; - - int fnm_flags= ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) - | ((!(flags & GLOB_PERIOD)) ? FNM_PERIOD : 0); - - if (fnmatch(pat, de->d_name, fnm_flags)) - continue; - - /* With GLOB_PERIOD, don't allow matching . or .. unless - * fnmatch would match them with FNM_PERIOD rules in effect. */ - if (p2 && (flags & GLOB_PERIOD) && de->d_name[0]=='.' - && (!de->d_name[1] || de->d_name[1]=='.' && !de->d_name[2]) - && fnmatch(pat, de->d_name, fnm_flags | FNM_PERIOD)) - continue; - - memcpy(buf+pos, de->d_name, l+1); - if (p2) *p2 = saved_sep; - int r = do_glob(buf, pos+l, de->d_type, p2 ? p2 : "", flags, errfunc, tail); - if (r) { - closedir(dir); - return r; - } - } - int readerr = errno; - if (p2) *p2 = saved_sep; - closedir(dir); - if (readerr && (errfunc(buf, errno) || (flags & GLOB_ERR))) - return GLOB_ABORTED; - errno = old_errno; - return 0; -} - -static int ignore_err(const char *path, int err) -{ - return 0; -} - -static void freelist(struct match *head) -{ - struct match *match, *next; - for (match=head->next; match; match=next) { - next = match->next; - free(match); - } -} - -static int sort(const void *a, const void *b) -{ - return strcmp(*(const char **)a, *(const char **)b); -} - -int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, int err), glob_t *restrict g) -{ - struct match head = { .next = NULL }, *tail = &head; - size_t cnt, i; - size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0; - int error = 0; - char buf[PATH_MAX]; - - if (!errfunc) errfunc = ignore_err; - - if (!(flags & GLOB_APPEND)) { - g->gl_offs = offs; - g->gl_pathc = 0; - g->gl_pathv = NULL; - } - - if (*pat) { - char *p = strdup(pat); - if (!p) return GLOB_NOSPACE; - buf[0] = 0; - error = do_glob(buf, 0, 0, p, flags, errfunc, &tail); - free(p); - } - - if (error == GLOB_NOSPACE) { - freelist(&head); - return error; - } - - for (cnt=0, tail=head.next; tail; tail=tail->next, cnt++); - if (!cnt) { - if (flags & GLOB_NOCHECK) { - tail = &head; - if (append(&tail, pat, strlen(pat), 0)) - return GLOB_NOSPACE; - cnt++; - } else - return GLOB_NOMATCH; - } - - if (flags & GLOB_APPEND) { - char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *)); - if (!pathv) { - freelist(&head); - return GLOB_NOSPACE; - } - g->gl_pathv = pathv; - offs += g->gl_pathc; - } else { - g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *)); - if (!g->gl_pathv) { - freelist(&head); - return GLOB_NOSPACE; - } - for (i=0; igl_pathv[i] = NULL; - } - for (i=0, tail=head.next; inext, i++) - g->gl_pathv[offs + i] = tail->name; - g->gl_pathv[offs + i] = NULL; - g->gl_pathc += cnt; - - if (!(flags & GLOB_NOSORT)) - qsort(g->gl_pathv+offs, cnt, sizeof(char *), sort); - - return error; -} - -void globfree(glob_t *g) -{ - size_t i; - for (i=0; igl_pathc; i++) - free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name)); - free(g->gl_pathv); - g->gl_pathc = 0; - g->gl_pathv = NULL; -} diff --git a/third_party/xed/x86ild.greg.c b/third_party/xed/x86ild.greg.c index 0cc722b2..e825c535 100644 --- a/third_party/xed/x86ild.greg.c +++ b/third_party/xed/x86ild.greg.c @@ -1229,7 +1229,7 @@ privileged static void xed_decode_instruction_length( * * @return d->decoded_length is byte length, or 1 w/ error code * @note binary footprint increases ~4kb if this is used - * @see cf. biggest thing in tensorflow, gdb, clang, etc. binaries + * @see biggest code in gdb/clang/tensorflow binaries */ privileged enum XedError xed_instruction_length_decode( struct XedDecodedInst *xedd, const uint8_t *itext, const size_t bytes) { diff --git a/third_party/xed/x86tab.S b/third_party/xed/x86tab.S index 86434b4c..d47b1389 100644 --- a/third_party/xed/x86tab.S +++ b/third_party/xed/x86tab.S @@ -1,25 +1,25 @@ /*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ │vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2018 Intel Corporation │ │ Copyright 2020 Justine Alexandra Roberts Tunney │ │ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ +│ Licensed under the Apache License, Version 2.0 (the "License"); │ +│ you may not use this file except in compliance with the License. │ +│ You may obtain a copy of the License at │ │ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ +│ http://www.apache.org/licenses/LICENSE-2.0 │ │ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ +│ Unless required by applicable law or agreed to in writing, software │ +│ distributed under the License is distributed on an "AS IS" BASIS, │ +│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ +│ See the License for the specific language governing permissions and │ +│ limitations under the License. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" / Phash tables for instruction length decoding. +/ @see build/rle.py for more context here .initbss 300,_init_x86tab xed_prefix_table_bit: diff --git a/third_party/xed/xed.mk b/third_party/xed/xed.mk index c9a019fa..8acb636b 100644 --- a/third_party/xed/xed.mk +++ b/third_party/xed/xed.mk @@ -7,7 +7,7 @@ # # DESCRIPTION # -# See test/libc/x86ild_test.c for more information. +# See test/libc/xed/x86ild_test.c for more information. PKGS += THIRD_PARTY_XED diff --git a/tool/build/summy.c b/tool/build/summy.c new file mode 100644 index 00000000..af499a19 --- /dev/null +++ b/tool/build/summy.c @@ -0,0 +1,31 @@ +/*-*- 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 │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/stdio/stdio.h" + +/** + * @fileoverview Sums per-line integers from stdin. + */ + +int main(int argc, char *argv[]) { + long x, sum = 0; + while (scanf("%ld", &x) > 0) sum += x; + printf("%,ld\n", sum); + return 0; +} diff --git a/tool/build/zipobj.c b/tool/build/zipobj.c index f42f465f..2db00188 100644 --- a/tool/build/zipobj.c +++ b/tool/build/zipobj.c @@ -62,6 +62,7 @@ char *symbol_; char *outpath_; +char *yoink_; const size_t kMinCompressSize = 32; const char kNoCompressExts[][8] = {".gz", ".xz", ".jpg", ".png", @@ -70,13 +71,14 @@ const char kNoCompressExts[][8] = {".gz", ".xz", ".jpg", ".png", noreturn void PrintUsage(int rc, FILE *f) { fprintf(f, "%s%s%s\n", "Usage: ", program_invocation_name, - " [-o FILE] [-s SYMBOL] [FILE...]\n"); + " [-o FILE] [-s SYMBOL] [-y YOINK] [FILE...]\n"); exit(rc); } void GetOpts(int *argc, char ***argv) { int opt; - while ((opt = getopt(*argc, *argv, "?ho:s:")) != -1) { + yoink_ = "__zip_start"; + while ((opt = getopt(*argc, *argv, "?ho:s:y:")) != -1) { switch (opt) { case 'o': outpath_ = optarg; @@ -84,6 +86,9 @@ void GetOpts(int *argc, char ***argv) { case 's': symbol_ = optarg; break; + case 'y': + yoink_ = optarg; + break; case '?': case 'h': PrintUsage(EXIT_SUCCESS, stdout); @@ -273,8 +278,7 @@ void PullEndOfCentralDirectoryIntoLinkage(struct ElfWriter *elf) { elfwriter_align(elf, 1, 0); elfwriter_startsection(elf, ".yoink", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); - elfwriter_yoink(elf, "__zip_start"); - elfwriter_yoink(elf, "__zip_end"); + elfwriter_yoink(elf, yoink_); elfwriter_finishsection(elf); } diff --git a/tool/emacs/cosmo-asm-mode.el b/tool/emacs/cosmo-asm-mode.el index 7f345116..0253c628 100644 --- a/tool/emacs/cosmo-asm-mode.el +++ b/tool/emacs/cosmo-asm-mode.el @@ -337,4 +337,10 @@ (add-hook 'asm-mode-hook 'cosmo-asm-supplemental-hook) (setq asm-font-lock-keywords cosmo-asm-font-lock-keywords)) +;; Make -*-unix-assembly-*- mode line work correctly. +;; TODO(jart): Would be nice to use GitHub's name instead of changing asm-mode. +(defun unix-assembly-mode () + (interactive) + (asm-mode)) + (provide 'cosmo-asm-mode) diff --git a/tool/scripts/install-emacs.sh b/tool/scripts/install-emacs.sh index 052d5e93..6b43f4cc 100755 --- a/tool/scripts/install-emacs.sh +++ b/tool/scripts/install-emacs.sh @@ -6,7 +6,7 @@ sudo apt build-dep emacs cd "$HOME" export CFLAGS="-O2" rm -rf emacs-26.3 -wget http://mirrors.kernel.org/gnu/emacs/emacs-26.3.tar.gz +wget https://mirrors.kernel.org/gnu/emacs/emacs-26.3.tar.gz tar xf emacs-26.3.tar.gz cd emacs-26.3 ./configure