Add x86_64-linux-gnu emulator
I wanted a tiny scriptable meltdown proof way to run userspace programs and visualize how program execution impacts memory. It helps to explain how things like Actually Portable Executable works. It can show you how the GCC generated code is going about manipulating matrices and more. I didn't feel fully comfortable with Qemu and Bochs because I'm not smart enough to understand them. I wanted something like gVisor but with much stronger levels of assurances. I wanted a single binary that'll run, on all major operating systems with an embedded GPL barrier ZIP filesystem that is tiny enough to transpile to JavaScript and run in browsers too. https://justine.storage.googleapis.com/emulator625.mp4main
parent
467504308a
commit
f4f4caab0e
|
@ -7,9 +7,10 @@ AlignConsecutiveDeclarations: false
|
|||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
---
|
||||
Language: Cpp
|
||||
AllowShortFunctionsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
---
|
||||
Language: Proto
|
||||
...
|
||||
|
|
82
Makefile
82
Makefile
|
@ -60,7 +60,7 @@
|
|||
#
|
||||
# build/config.mk
|
||||
|
||||
SHELL = dash
|
||||
SHELL = /bin/sh
|
||||
HOSTS ?= freebsd openbsd alpine
|
||||
|
||||
.SUFFIXES:
|
||||
|
@ -69,8 +69,7 @@ HOSTS ?= freebsd openbsd alpine
|
|||
.PHONY: all o bins check test depend tags
|
||||
|
||||
all: o
|
||||
o: o/libc \
|
||||
o/$(MODE)/ape \
|
||||
o: o/$(MODE)/ape \
|
||||
o/$(MODE)/dsp \
|
||||
o/$(MODE)/net \
|
||||
o/$(MODE)/libc \
|
||||
|
@ -81,6 +80,7 @@ o: o/libc \
|
|||
|
||||
PKGS =
|
||||
|
||||
-include ~/.cosmo.mk #──No.1
|
||||
include build/functions.mk #─┐
|
||||
include build/definitions.mk # ├──meta
|
||||
include build/config.mk # │
|
||||
|
@ -89,6 +89,7 @@ include build/online.mk # │
|
|||
include libc/stubs/stubs.mk #─┘
|
||||
include libc/nexgen32e/nexgen32e.mk #─┐
|
||||
include libc/intrin/intrin.mk # │
|
||||
include libc/linux/linux.mk # │
|
||||
include libc/math/math.mk # ├──metal
|
||||
include libc/tinymath/tinymath.mk # │
|
||||
include third_party/compiler_rt/compiler_rt.mk # │
|
||||
|
@ -106,6 +107,7 @@ include libc/fmt/fmt.mk # │
|
|||
include libc/rand/rand.mk #─┘
|
||||
include libc/calls/calls.mk #─┐
|
||||
include libc/runtime/runtime.mk # ├──systems
|
||||
include libc/crt/crt.mk # │
|
||||
include libc/unicode/unicode.mk # │
|
||||
include third_party/dlmalloc/dlmalloc.mk # │
|
||||
include libc/mem/mem.mk # │
|
||||
|
@ -140,9 +142,9 @@ include third_party/editline/editline.mk
|
|||
include third_party/duktape/duktape.mk
|
||||
include third_party/regex/regex.mk
|
||||
include third_party/avir/avir.mk
|
||||
include third_party/ctags/ctags.mk
|
||||
include third_party/third_party.mk
|
||||
include libc/testlib/testlib.mk
|
||||
include libc/crt/crt.mk
|
||||
include tool/viz/lib/vizlib.mk
|
||||
include examples/examples.mk
|
||||
include third_party/lex/lex.mk
|
||||
|
@ -150,6 +152,8 @@ include third_party/m4/m4.mk
|
|||
include third_party/lz4cli/lz4cli.mk
|
||||
include third_party/bzip2/bzip2.mk
|
||||
include tool/build/lib/buildlib.mk
|
||||
include tool/build/emucrt/emucrt.mk
|
||||
include tool/build/emubin/emubin.mk
|
||||
include tool/build/build.mk
|
||||
include tool/debug/debug.mk
|
||||
include tool/decode/lib/decodelib.mk
|
||||
|
@ -213,7 +217,7 @@ depend: o/$(MODE)/depend
|
|||
tags: TAGS HTAGS
|
||||
|
||||
o/$(MODE)/.x:
|
||||
@$(MKDIR) $(dir $@) && touch $@
|
||||
@$(MKDIR) $(@D) && touch $@
|
||||
|
||||
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
|
||||
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
|
||||
|
@ -236,6 +240,71 @@ loc: o/$(MODE)/tool/build/summy.com
|
|||
find -name \*.h -or -name \*.c -or -name \*.S | \
|
||||
$(XARGS) wc -l | grep total | awk '{print $$1}' | $<
|
||||
|
||||
COSMOPOLITAN_OBJECTS = \
|
||||
APE_LIB \
|
||||
LIBC \
|
||||
LIBC_ALG \
|
||||
LIBC_BITS \
|
||||
LIBC_CALLS \
|
||||
LIBC_CALLS_HEFTY \
|
||||
LIBC_CONV \
|
||||
LIBC_CRYPTO \
|
||||
LIBC_DNS \
|
||||
LIBC_FMT \
|
||||
LIBC_ELF \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT \
|
||||
LIBC_OHMYPLUS \
|
||||
LIBC_RAND \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_UNICODE \
|
||||
LIBC_ZIPOS \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_DTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_REGEX
|
||||
|
||||
COSMOPOLITAN_HEADERS = \
|
||||
LIBC \
|
||||
LIBC_CALLS \
|
||||
LIBC_CONV \
|
||||
LIBC_CRYPTO \
|
||||
LIBC_DNS \
|
||||
LIBC_FMT \
|
||||
LIBC_MEM \
|
||||
LIBC_RAND \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_TIME \
|
||||
LIBC_UNICODE \
|
||||
LIBC_ZIPOS \
|
||||
LIBC_SYSV \
|
||||
LIBC_NT \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_DTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_REGEX
|
||||
|
||||
o/$(MODE)/cosmopolitan.a: $(filter-out o/libc/stubs/exit11.o,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_OBJS)))
|
||||
o/$(MODE)/.cosmopolitan.h: $(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS))
|
||||
build/rollup $^ >$@
|
||||
o/$(MODE)/cosmopolitan.h: o/$(MODE)/.cosmopolitan.h
|
||||
build/compile $(PREPROCESS) -P $(OUTPUT_OPTION) $<
|
||||
clang-format-10 -i $@
|
||||
|
||||
# UNSPECIFIED PREREQUISITES TUTORIAL
|
||||
#
|
||||
# A build rule must exist for all files that make needs to consider in
|
||||
|
@ -255,11 +324,12 @@ loc: o/$(MODE)/tool/build/summy.com
|
|||
# never get executed since they're not members of the transitive closure
|
||||
# of `make all`. In that case the build config could be improved.
|
||||
%.mk:
|
||||
~/.cosmo.mk:
|
||||
$(SRCS):
|
||||
$(HDRS):
|
||||
.DEFAULT:
|
||||
@echo >&2
|
||||
@echo NOTE: deleting o/$(MODE)/depend due to unspecified prerequisite: $@ >&2
|
||||
@echo NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2
|
||||
@echo >&2
|
||||
rm -f o/$(MODE)/depend
|
||||
|
||||
|
|
47
ape/ape.S
47
ape/ape.S
|
@ -44,6 +44,7 @@
|
|||
#include "libc/nexgen32e/uart.h"
|
||||
#include "libc/nexgen32e/vidya.h"
|
||||
#include "libc/nt/pedef.h"
|
||||
#include "libc/nexgen32e/vidya.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
.source "NOTICE"
|
||||
|
@ -136,43 +137,24 @@ ape.mz: .ascii "MZ" # Mark 'Zibo' Joseph Zbikowski
|
|||
.short 0 # MZ: OEM information
|
||||
.org 0x40-4 # MZ: bytes reserved for you
|
||||
.long RVA(ape.pe) # PE: the new technology
|
||||
.endobj ape.mz,globl,hidden
|
||||
.endfn ape.mz,globl,hidden
|
||||
|
||||
/ Disk Operating System Stub
|
||||
/ @noreturn
|
||||
.org 0x40 # mz/elf header length
|
||||
stub: mov $0x40,%dl # *literally* dos
|
||||
jmp 1f # good bios skips here
|
||||
1: jmp pc
|
||||
1: jmp pc # thus avoiding heroics
|
||||
nop # system five bootpoint
|
||||
.org 0x48,0x90 # ⌂ELF → JNLE 47
|
||||
jmp 3f
|
||||
2: push %rdx # don't move or shell script breaks
|
||||
xor %edx,%edx # Z in MZ ate BIOS drive letter :(
|
||||
3: .byte 0xbd,0,0 # mov $0x????0000,%[e]bp
|
||||
jmp pc
|
||||
jmp ape.hop # already in userspace
|
||||
.org 0x48,0x90 # note ⌂ELF means JG 47
|
||||
jmp 3f # MZ also means pop r10
|
||||
2: sub $8,%rsp # a.k.a. dec %ax sub %sp
|
||||
xor %edx,%edx # MZ ate BIOS drive code
|
||||
3: .byte 0xbd,0,0 # a.k.a. mov imm,%bp
|
||||
jmp pc # real mode, is real
|
||||
jmp _start # surprise it's unix
|
||||
.endfn stub
|
||||
|
||||
/ Mitigate incidental quotation marks.
|
||||
.real
|
||||
ape.hop:pop %rdx
|
||||
push %r10 # MZ → pop %r10 w/ NexGen32e
|
||||
.weak __imp_GetStartupInfoW
|
||||
ezlea __imp_GetStartupInfoW,ax
|
||||
test %rax,%rax
|
||||
jz 0f
|
||||
.weak KernelBase.GetStartupInfo
|
||||
test %rax,%rax
|
||||
/ TODO(jart)
|
||||
/ cmpq $RVA(KernelBase.GetStartupInfo),(%rax)
|
||||
jz 0f
|
||||
jmp WinMain
|
||||
0: .weak _start
|
||||
jmp _start
|
||||
.endfn ape.hop
|
||||
.previous
|
||||
|
||||
/*─────────────────────────────────────────────────────────────────────────────╗
|
||||
│ αcτµαlly pδrταblε εxεcµταblε § ibm personal computer │
|
||||
╚──────────────────────────────────────────────────────────────────────────────┘
|
||||
|
@ -835,9 +817,9 @@ ape.pe: .ascin "PE",4
|
|||
.short v_ntsubsystem # Subsystem: 0=Neutral,2=GUI,3=Console
|
||||
.short .LDLLEXE # DllCharacteristics
|
||||
.quad 0x0000000000100000 # StackReserve
|
||||
.quad 0x0000000000030000 # StackCommit (64kb [goog] + arg + env)
|
||||
.quad 0x0000000000100000 # StackCommit
|
||||
.quad 0x0000000000080000 # HeapReserve
|
||||
.quad 0x0000000000001000 # HeapCommit (we make our own heap)
|
||||
.quad 0x0000000000001000 # HeapCommit
|
||||
.long 0x00000000 # LoaderFlags
|
||||
.long 16 # NumberOfDirectoryEntries
|
||||
.long 0,0 # ExportsDirectory
|
||||
|
@ -1933,5 +1915,10 @@ __data_start:
|
|||
.type __piro_start,@object
|
||||
.hidden __piro_start
|
||||
|
||||
.type __ubsan_data_start,@object
|
||||
.type __ubsan_data_end,@object
|
||||
.type __ubsan_types_start,@object
|
||||
.type __ubsan_types_end,@object
|
||||
|
||||
.end
|
||||
|
60
ape/ape.lds
60
ape/ape.lds
|
@ -435,36 +435,36 @@ SECTIONS {
|
|||
/*END: linux addressability guarantee */
|
||||
/*END: xnu addressability guarantee */
|
||||
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
.debug_macro 0 : { *(.debug_macro) }
|
||||
.debug_addr 0 : { *(.debug_addr) }
|
||||
.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
|
||||
.GCC.command.line 0 : { *(.GCC.command.line) }
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
.debug_macro 0 : { *(.debug_macro) }
|
||||
.debug_addr 0 : { *(.debug_addr) }
|
||||
.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
|
||||
.GCC.command.line 0 : { *(.GCC.command.line) }
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.discard)
|
||||
|
|
18
ape/ape.mk
18
ape/ape.mk
|
@ -21,8 +21,7 @@ APE = $(APE_DEPS) \
|
|||
|
||||
APELINK = \
|
||||
ACTION=LINK.ape \
|
||||
$(MKDIR) \
|
||||
$(dir $@) && \
|
||||
$(MKDIR) $(@D) && \
|
||||
$(LINK) \
|
||||
$(LINKARGS) \
|
||||
$(OUTPUT_OPTION) && \
|
||||
|
@ -32,18 +31,6 @@ APELINK = \
|
|||
$(ZFLAGS) \
|
||||
-f $@.map
|
||||
|
||||
APECOPY = \
|
||||
ACTION=OBJCOPY.ape \
|
||||
TARGET=$@ \
|
||||
build/do \
|
||||
$(OBJCOPY) \
|
||||
-SO binary \
|
||||
$< \
|
||||
$@
|
||||
|
||||
DEFAULT_COPTS += -mno-red-zone
|
||||
DEFAULT_LDFLAGS += -z max-page-size=0x1000
|
||||
|
||||
APE_FILES := $(wildcard ape/*.*)
|
||||
APE_HDRS = $(filter %.h,$(APE_FILES))
|
||||
APE_SRCS = $(filter %.S,$(APE_FILES))
|
||||
|
@ -51,9 +38,6 @@ APE_OBJS = $(APE_SRCS:%.S=o/$(MODE)/%.o)
|
|||
APE_DEPS = $(APE_LIB)
|
||||
APE_CHECKS = $(APE_HDRS:%=o/%.ok)
|
||||
|
||||
o/%.com: o/%.com.dbg
|
||||
@$(APECOPY)
|
||||
|
||||
o/ape/idata.inc: \
|
||||
ape/idata.h \
|
||||
ape/relocations.h
|
||||
|
|
32
ape/idata.h
32
ape/idata.h
|
@ -32,39 +32,35 @@
|
|||
/ @see libc/nt/master.sh
|
||||
/ @see ape/ape.lds
|
||||
/ @see winimp
|
||||
.macro .imp dll:req fn:req actual hint
|
||||
.macro .imp dll:req fn:req actual:req hint
|
||||
.dll \dll
|
||||
.section .piro.data.sort.iat.2.\dll\().2.\fn,"aw",@progbits
|
||||
.section .piro.data.sort.iat.2.\dll\().2.\actual,"aw",@progbits
|
||||
.type \fn,@object
|
||||
.align __SIZEOF_POINTER__
|
||||
\fn: .quad RVA((.L\dll\().\fn))
|
||||
\fn: .quad RVA((\dll\().\actual))
|
||||
.size \fn,.-\fn
|
||||
.globl \fn
|
||||
.hidden \fn
|
||||
.previous
|
||||
.section .idata.ro.ilt.\dll\().2.\fn,"a",@progbits
|
||||
.Lidata.ilt.\dll\().\fn:
|
||||
.quad RVA((.L\dll\().\fn))
|
||||
.type .Lidata.ilt..L\dll\().\fn,@object
|
||||
.size .Lidata.ilt..L\dll\().\fn,.-.Lidata.ilt.\dll\().\fn
|
||||
.section .idata.ro.ilt.\dll\().2.\actual,"a",@progbits
|
||||
.Lidata.ilt.\dll\().\actual:
|
||||
.quad RVA((\dll\().\actual))
|
||||
.type .Lidata.ilt.\dll\().\actual,@object
|
||||
.size .Lidata.ilt.\dll\().\actual,.-.Lidata.ilt.\dll\().\actual
|
||||
.previous
|
||||
.section .idata.ro.hnt.\dll\().2.\fn,"a",@progbits
|
||||
.L\dll\().\fn:
|
||||
.section .idata.ro.hnt.\dll\().2.\actual,"a",@progbits
|
||||
\dll\().\actual:
|
||||
.ifnb \hint # hint i.e. guess function ordinal
|
||||
.short \hint
|
||||
.else
|
||||
.short 0
|
||||
.endif
|
||||
.ifnb \actual # name
|
||||
.asciz "\actual"
|
||||
.else
|
||||
.asciz "\fn"
|
||||
.endif
|
||||
.align 2 # documented requirement
|
||||
/ .globl .L\dll\().\fn
|
||||
/ .hidden .L\dll\().\fn
|
||||
.type .L\dll\().\fn,@object
|
||||
.size .L\dll\().\fn,.-.L\dll\().\fn
|
||||
.globl \dll\().\actual
|
||||
.hidden \dll\().\actual
|
||||
.type \dll\().\actual,@object
|
||||
.size \dll\().\actual,.-\dll\().\actual
|
||||
.previous
|
||||
.endm
|
||||
|
||||
|
|
|
@ -52,11 +52,13 @@
|
|||
SF: Stack Fault ────────────────┐││││││
|
||||
ES: Exception Summary Status ──┐│││││││
|
||||
C0-3: Condition Codes ──┬────┐ ││││││││
|
||||
Top of Stack Pointer ─────┐ │ ││││││││
|
||||
TOP of Stack Pointer ─────┐ │ ││││││││
|
||||
B: FPU Busy ───────────┐│ │ │ ││││││││
|
||||
││┌┴┐┌┼┐││││││││
|
||||
│↓│ │↓↓↓││││││││*/
|
||||
#define FPU_IE 0b0000000000100000000000001
|
||||
#define FPU_ZE 0b0000000000100000000000100
|
||||
#define FPU_SF 0b0000000000000000001000000
|
||||
#define FPU_C0 0b0000000000000000100000000
|
||||
#define FPU_C1 0b0000000000000001000000000
|
||||
#define FPU_C2 0b0000000000000010000000000
|
||||
|
@ -151,6 +153,7 @@
|
|||
#define PAGE_V /* */ 0b000000001
|
||||
#define PAGE_RW /* */ 0b000000010
|
||||
#define PAGE_U /* */ 0b000000100
|
||||
#define PAGE_4KB /* */ 0b010000000
|
||||
#define PAGE_2MB /* */ 0b110000000
|
||||
#define PAGE_1GB /* */ 0b110000000
|
||||
#define PAGE_TA 0b11111111111111111111111111111111111111000000000000
|
||||
|
|
|
@ -48,6 +48,7 @@ for x; do
|
|||
done
|
||||
|
||||
set -- "$AR" "$ARFLAGS" "$OUT" "$@"
|
||||
printf %s\\n "$*" >"$OUT.cmd"
|
||||
|
||||
OUTDIR="${OUT%/*}"
|
||||
if [ "$OUTDIR" != "$OUT" ] && [ ! -d "$OUTDIR" ]; then
|
||||
|
|
Binary file not shown.
|
@ -151,9 +151,11 @@ if [ "${PLAT#*clang}" != "${PLAT}" ]; then
|
|||
FIRST=0
|
||||
continue
|
||||
fi
|
||||
TRAPV= # clang handles -f{,no-}{trap,wrap}v weird
|
||||
# removes flags clang whines about
|
||||
case "$x" in
|
||||
-gstabs) ;;
|
||||
-ftrapv) ;;
|
||||
-ffixed-*) ;;
|
||||
-fcall-saved*) ;;
|
||||
-fsignaling-nans) ;;
|
||||
|
@ -161,6 +163,7 @@ if [ "${PLAT#*clang}" != "${PLAT}" ]; then
|
|||
-fno-fp-int-builtin-inexact) ;;
|
||||
-Wno-unused-but-set-variable) ;;
|
||||
-Wunsafe-loop-optimizations) ;;
|
||||
-mdispatch-scheduler) ;;
|
||||
-ftracer) ;;
|
||||
-frounding-math) ;;
|
||||
-fmerge-constants) ;;
|
||||
|
@ -189,6 +192,7 @@ if [ "${PLAT#*clang}" != "${PLAT}" ]; then
|
|||
-fschedule-insns) ;;
|
||||
-fno-semantic-interposition) ;;
|
||||
-mno-fentry) ;;
|
||||
-f*shrink-wrap) ;;
|
||||
-f*schedule-insns2) ;;
|
||||
-fvect-cost-model=*) ;;
|
||||
-fsimd-cost-model=*) ;;
|
||||
|
@ -228,6 +232,7 @@ if [ "${PLAT#*clang}" != "${PLAT}" ]; then
|
|||
;;
|
||||
esac
|
||||
done
|
||||
set -- "$@" -fno-stack-protector
|
||||
else
|
||||
# removes flags only clang supports
|
||||
FIRST=1
|
||||
|
|
|
@ -17,8 +17,11 @@ CONFIG_CCFLAGS += \
|
|||
$(FTRACE) \
|
||||
-Og
|
||||
|
||||
CONFIG_COPTS += \
|
||||
-ftrapv
|
||||
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
-march=k8-sse3
|
||||
|
||||
RAGELFLAGS ?= -G2
|
||||
|
||||
|
@ -71,10 +74,7 @@ CONFIG_CPPFLAGS += \
|
|||
|
||||
CONFIG_CCFLAGS += \
|
||||
$(BACKTRACES) \
|
||||
-O3
|
||||
|
||||
#TARGET_ARCH ?= \
|
||||
-msse3
|
||||
-O2
|
||||
|
||||
RAGELFLAGS = -G2
|
||||
|
||||
|
@ -103,6 +103,12 @@ CONFIG_COPTS += \
|
|||
$(SECURITY_BLANKETS) \
|
||||
$(SANITIZER)
|
||||
|
||||
CONFIG_COPTS += \
|
||||
-ftrapv
|
||||
|
||||
TARGET_ARCH ?= \
|
||||
-march=k8-sse3
|
||||
|
||||
OVERRIDE_CCFLAGS += \
|
||||
-fno-pie
|
||||
|
||||
|
@ -135,7 +141,7 @@ CONFIG_CCFLAGS += \
|
|||
-fno-align-loops
|
||||
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
-march=k8-sse3
|
||||
|
||||
endif
|
||||
|
||||
|
@ -172,6 +178,8 @@ endif
|
|||
ifeq ($(MODE), ansi)
|
||||
|
||||
CONFIG_CFLAGS += -std=c11
|
||||
#CONFIG_CPPFLAGS += -ansi
|
||||
CONFIG_CXXFLAGS += -std=c++11
|
||||
TARGET_ARCH ?= -march=k8-sse3
|
||||
|
||||
endif
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
# ASFLAGS assembler flags (don't use -Wa, frontend prefix)
|
||||
# TARGET_ARCH microarchitecture flags (e.g. -march=native)
|
||||
|
||||
SHELL = /bin/sh
|
||||
DD ?= /bin/dd
|
||||
CP ?= /bin/cp -f
|
||||
RM ?= /bin/rm -f
|
||||
|
@ -53,15 +52,14 @@ SED ?= /bin/sed
|
|||
MKDIR ?= /bin/mkdir -p
|
||||
TAGS ?= /usr/bin/ctags # emacs source builds or something breaks it
|
||||
ARFLAGS = rcsD
|
||||
TAGSFLAGS ?= -e -a --if0=no --langmap=c:.c.h.i --line-directives=yes
|
||||
SILENT ?= 1
|
||||
ZFLAGS ?= -4 --rsyncable
|
||||
ZFLAGS ?=
|
||||
XARGS ?= xargs -P4 -rs8000
|
||||
NICE ?= build/actuallynice
|
||||
RAGEL ?= ragel
|
||||
DOT ?= dot
|
||||
GZ ?= gzip
|
||||
CLANG = clang-11
|
||||
CLANG = clang-10
|
||||
FC = gfortran #/opt/cross9f/bin/x86_64-linux-musl-gfortran
|
||||
|
||||
# see build/compile, etc. which run third_party/gcc/unbundle.sh
|
||||
|
@ -108,8 +106,8 @@ FTRACE = \
|
|||
-pg
|
||||
|
||||
SANITIZER = \
|
||||
-fsanitize=undefined \
|
||||
-fsanitize=leak \
|
||||
-fsanitize=undefined \
|
||||
-fsanitize=implicit-signed-integer-truncation \
|
||||
-fsanitize=implicit-integer-sign-change
|
||||
|
||||
|
@ -139,6 +137,7 @@ DEFAULT_OFLAGS = \
|
|||
-gdescribe-dies
|
||||
|
||||
DEFAULT_COPTS = \
|
||||
-mno-red-zone \
|
||||
-fno-math-errno \
|
||||
-fno-trapping-math \
|
||||
-fno-fp-int-builtin-inexact \
|
||||
|
@ -149,9 +148,13 @@ DEFAULT_COPTS = \
|
|||
-fstrict-aliasing \
|
||||
-fstrict-overflow \
|
||||
-fno-omit-frame-pointer \
|
||||
-fno-optimize-sibling-calls \
|
||||
-fno-semantic-interposition \
|
||||
-mno-omit-leaf-frame-pointer
|
||||
|
||||
MATHEMATICAL = \
|
||||
-O3 \
|
||||
-fwrapv
|
||||
|
||||
DEFAULT_CPPFLAGS = \
|
||||
-DIMAGE_BASE_VIRTUAL=$(IMAGE_BASE_VIRTUAL) \
|
||||
-nostdinc \
|
||||
|
@ -176,15 +179,14 @@ DEFAULT_ASFLAGS = \
|
|||
--noexecstack
|
||||
|
||||
DEFAULT_LDFLAGS = \
|
||||
-h \
|
||||
-static \
|
||||
--relax \
|
||||
-nostdlib \
|
||||
-m elf_x86_64 \
|
||||
--gc-sections \
|
||||
--build-id=none \
|
||||
--cref -Map=$@.map \
|
||||
--no-dynamic-linker \
|
||||
-z max-page-size=0x1000 \
|
||||
-Ttext-segment=$(IMAGE_BASE_VIRTUAL)
|
||||
|
||||
ASONLYFLAGS = \
|
||||
|
@ -270,8 +272,8 @@ COMPILE.F.flags = $(cc.flags) $(cpp.flags) $(copt.flags) $(f.flags)
|
|||
COMPILE.i.flags = $(cc.flags) $(copt.flags) $(c.flags)
|
||||
COMPILE.ii.flags = $(cc.flags) $(copt.flags) $(cxx.flags)
|
||||
LINK.flags = $(DEFAULT_LDFLAGS) $(CONFIG_LDFLAGS) $(LDFLAGS)
|
||||
OBJECTIFY.c.flags = $(OBJECTIFY.S.flags) $(copt.flags) $(c.flags)
|
||||
OBJECTIFY.cxx.flags = $(OBJECTIFY.S.flags) $(copt.flags) $(cxx.flags)
|
||||
OBJECTIFY.c.flags = $(OBJECTIFY.S.flags) $(c.flags)
|
||||
OBJECTIFY.cxx.flags = $(OBJECTIFY.S.flags) $(cxx.flags)
|
||||
OBJECTIFY.s.flags = $(ASONLYFLAGS) $(s.flags)
|
||||
OBJECTIFY.S.flags = $(copt.flags) $(cc.flags) $(o.flags) $(cpp.flags) $(S.flags)
|
||||
OBJECTIFY.f.flags = $(copt.flags) $(cc.flags) $(o.flags) $(copt.flags) $(S.flags) $(f.flags)
|
||||
|
@ -339,7 +341,6 @@ OBJECTIFY.ncabi.c = \
|
|||
-fno-stack-protector \
|
||||
-fno-instrument-functions \
|
||||
-fno-optimize-sibling-calls \
|
||||
-mpreferred-stack-boundary=3 \
|
||||
-fno-sanitize=all \
|
||||
-fcall-saved-rcx \
|
||||
-fcall-saved-rdx \
|
||||
|
@ -352,10 +353,26 @@ OBJECTIFY.ncabi.c = \
|
|||
-c \
|
||||
-xc
|
||||
|
||||
BUILD_SRCS = \
|
||||
build/definitions.mk \
|
||||
build/rules.mk \
|
||||
build/compile \
|
||||
build/link \
|
||||
build/lolsan \
|
||||
build/remote
|
||||
# Initializer ABI
|
||||
#
|
||||
# Doesn't clobber RDI and RSI.
|
||||
OBJECTIFY.initabi.c = \
|
||||
$(GCC) \
|
||||
$(OBJECTIFY.c.flags) \
|
||||
-mno-fentry \
|
||||
-fno-stack-protector \
|
||||
-fno-instrument-functions \
|
||||
-fno-optimize-sibling-calls \
|
||||
-fno-sanitize=all \
|
||||
-fcall-saved-rdi \
|
||||
-fcall-saved-rsi \
|
||||
-c
|
||||
|
||||
TAGSFLAGS = \
|
||||
-e \
|
||||
-a \
|
||||
--if0=no \
|
||||
--langmap=c:.c.h.i \
|
||||
--line-directives=yes \
|
||||
--exclude=libc/nt/struct/imagefileheader.h \
|
||||
--exclude=libc/nt/struct/filesegmentelement.h
|
||||
|
|
15
build/htags
15
build/htags
|
@ -54,4 +54,17 @@ set -- --regex-c='/^[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]
|
|||
# extern int32_t (*const SetEvent)(int64_t hEvent) wincall;
|
||||
set -- --regex-c='/^extern [^(]*(\*const \([^)]*\))(/\1/b' "$@"
|
||||
|
||||
exec ${TAGS:-ctags} -e --langmap=c:.c.h "$@"
|
||||
# ctags doesn't understand forward declarations, e.g.
|
||||
# struct WorstSoftwareEver;
|
||||
set -- --regex-c='/^struct.*;$/uehocruehcroue/b' "$@"
|
||||
|
||||
exec ${TAGS:-ctags} \
|
||||
-e \
|
||||
--langmap=c:.c.h \
|
||||
--exclude=libc/nt/struct/imagefileheader.h \
|
||||
--exclude=libc/nt/struct/imageseparatedebugheader.h \
|
||||
--exclude=libc/nt/struct/importobjectheader.h \
|
||||
--exclude=libc/nt/struct/nonpageddebuginfo.h \
|
||||
--exclude=libc/nt/struct/ansistring.h \
|
||||
--exclude=libc/nt/struct/filesegmentelement.h \
|
||||
"$@"
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#-*-mode:sh;indent-tabs-mode:nil;tab-width:2;coding:utf-8-*-┐
|
||||
#───vi: set net ft=sh ts=2 sts=2 fenc=utf-8 :vi─────────────┘
|
||||
|
||||
for x; do
|
||||
printf '#include "%s"\n' "$x"
|
||||
done
|
|
@ -37,6 +37,7 @@ o/%.greg.o: %.greg.c; @ACTION=OBJECTIFY.greg build/compile $(OBJECTIFY.greg.c) $
|
|||
o/%.zip.o: o/%; @build/zipobj $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%.a:; @$(ARCHIVE) $@ $^
|
||||
o/$(MODE)/%: o/$(MODE)/%.dbg; @ACTION=OBJCOPY TARGET=$@ build/do $(OBJCOPY) -SO binary $< $@
|
||||
o/$(MODE)/%.o: %.s; @TARGET=$@ build/assemble $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.o: o/$(MODE)/%.s; @TARGET=$@ build/assemble $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.s: %.S; @ACTION=PREPROCESS build/compile $(PREPROCESS) $(OUTPUT_OPTION) $<
|
||||
|
@ -75,15 +76,15 @@ o/$(MODE)/%.runs: o/$(MODE)/%; @ACTION=CHECK.runs TARGET=$< build/runcom $< $(TE
|
|||
o/$(MODE)/%.pkg:; @build/package $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^)
|
||||
o/$(MODE)/%.zip.o: %; @build/zipobj $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%-gcc.asm: %.c; @ACTION=COMPILE.c build/compile $(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-gcc.asm: %.c; @ACTION=OBJECTIFY.c build/compile $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-clang.asm: CC = $(CLANG)
|
||||
o/$(MODE)/%-clang.asm: %.c; @ACTION=COMPILE.c build/compile $(COMPILE.c) $(OUTPUT_OPTION) $< || echo / need $(CLANG) >$@
|
||||
o/$(MODE)/%-gcc.asm: %.f; @ACTION=COMPILE.f build/compile $(COMPILE.f) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-clang.asm: %.c; @ACTION=OBJECTIFY.c build/compile $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $< || echo / need $(CLANG) >$@
|
||||
o/$(MODE)/%-gcc.asm: %.f; @ACTION=OBJECTIFY.f build/compile $(OBJECTIFY.f) -S -g0 $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-clang.asm: CC = $(CLANG)
|
||||
o/$(MODE)/%-clang.asm: %.f; @ACTION=COMPILE.f build/compile $(COMPILE.f) $(OUTPUT_OPTION) $< || echo / need $(CLANG) >$@
|
||||
o/$(MODE)/%-gcc.asm: %.F; @ACTION=COMPILE.F build/compile $(COMPILE.F) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-clang.asm: %.f; @ACTION=OBJECTIFY.f build/compile $(OBJECTIFY.f) -S -g0 $(OUTPUT_OPTION) $< || echo / need $(CLANG) >$@
|
||||
o/$(MODE)/%-gcc.asm: %.F; @ACTION=OBJECTIFY.F build/compile $(OBJECTIFY.F) -S -g0 $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-clang.asm: CC = $(CLANG)
|
||||
o/$(MODE)/%-clang.asm: %.F; @ACTION=COMPILE.F build/compile $(COMPILE.F) $(OUTPUT_OPTION) $< || echo / need $(CLANG) >$@
|
||||
o/$(MODE)/%-clang.asm: %.F; @ACTION=OBJECTIFY.F build/compile $(OBJECTIFY.F) -S -g0 $(OUTPUT_OPTION) $< || echo / need $(CLANG) >$@
|
||||
|
||||
# ragel state machine compiler
|
||||
.PRECIOUS: build/bootstrap/%.c.gz
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "dsp/mpeg/idct.h"
|
||||
#include "dsp/mpeg/mpeg.h"
|
||||
#include "dsp/mpeg/video.h"
|
||||
#include "libc/bits/initializer.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
|
@ -455,18 +456,6 @@ long plmpegdecode_latency_;
|
|||
static plm_vlc_t *PLM_VIDEO_MACROBLOCK_TYPE[4];
|
||||
static plm_vlc_t *PLM_VIDEO_DCT_SIZE[3];
|
||||
|
||||
static textstartup void __init_mpeg1(void) {
|
||||
PLM_VIDEO_MACROBLOCK_TYPE[0] = NULL;
|
||||
PLM_VIDEO_MACROBLOCK_TYPE[1] = PLM_VIDEO_MACROBLOCK_TYPE_INTRA;
|
||||
PLM_VIDEO_MACROBLOCK_TYPE[2] = PLM_VIDEO_MACROBLOCK_TYPE_PREDICTIVE,
|
||||
PLM_VIDEO_MACROBLOCK_TYPE[3] = PLM_VIDEO_MACROBLOCK_TYPE_B;
|
||||
PLM_VIDEO_DCT_SIZE[0] = PLM_VIDEO_DCT_SIZE_LUMINANCE;
|
||||
PLM_VIDEO_DCT_SIZE[1] = PLM_VIDEO_DCT_SIZE_CHROMINANCE;
|
||||
PLM_VIDEO_DCT_SIZE[2] = PLM_VIDEO_DCT_SIZE_CHROMINANCE;
|
||||
}
|
||||
|
||||
INITIALIZER(300, _init_mpeg1, __init_mpeg1());
|
||||
|
||||
#define plm_clamp(n) MIN(255, MAX(0, n))
|
||||
|
||||
void plm_video_destroy(plm_video_t *self) {
|
||||
|
@ -1113,3 +1102,15 @@ plm_video_t *plm_video_create_with_buffer(plm_buffer_t *buffer,
|
|||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static textstartup void plm_video_init(void) {
|
||||
PLM_VIDEO_MACROBLOCK_TYPE[0] = NULL;
|
||||
PLM_VIDEO_MACROBLOCK_TYPE[1] = PLM_VIDEO_MACROBLOCK_TYPE_INTRA;
|
||||
PLM_VIDEO_MACROBLOCK_TYPE[2] = PLM_VIDEO_MACROBLOCK_TYPE_PREDICTIVE,
|
||||
PLM_VIDEO_MACROBLOCK_TYPE[3] = PLM_VIDEO_MACROBLOCK_TYPE_B;
|
||||
PLM_VIDEO_DCT_SIZE[0] = PLM_VIDEO_DCT_SIZE_LUMINANCE;
|
||||
PLM_VIDEO_DCT_SIZE[1] = PLM_VIDEO_DCT_SIZE_CHROMINANCE;
|
||||
PLM_VIDEO_DCT_SIZE[2] = PLM_VIDEO_DCT_SIZE_CHROMINANCE;
|
||||
}
|
||||
|
||||
const void *const plm_video_init_ctor[] initarray = {plm_video_init};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef COSMOPOLITAN_DSP_MPEG_YCBCRIO_H_
|
||||
#define COSMOPOLITAN_DSP_MPEG_YCBCRIO_H_
|
||||
#include "dsp/mpeg/mpeg.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/bswap.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
@ -44,7 +43,7 @@
|
|||
* @see Magikarp
|
||||
*/
|
||||
|
||||
#define M 14
|
||||
#define M 15
|
||||
#define SQR(X) ((X) * (X))
|
||||
|
||||
struct SamplingSolution {
|
||||
|
@ -148,9 +147,9 @@ static int Sharpen(int ax, int bx, int cx) {
|
|||
|
||||
static void GyaradosImpl(long dyw, long dxw, int dst[dyw][dxw], long syw,
|
||||
long sxw, const int src[syw][sxw], long dyn, long dxn,
|
||||
long syn, long sxn, int tmp0[restrict dyn][sxn],
|
||||
int tmp1[restrict dyn][sxn],
|
||||
int tmp2[restrict dyn][dxn], long yfn, long xfn,
|
||||
long syn, long sxn, short tmp0[restrict dyn][sxn],
|
||||
short tmp1[restrict dyn][sxn],
|
||||
short tmp2[restrict dyn][dxn], long yfn, long xfn,
|
||||
const short fyi[dyn][yfn], const short fyw[dyn][yfn],
|
||||
const short fxi[dxn][xfn], const short fxw[dxn][xfn],
|
||||
bool sharpen) {
|
||||
|
@ -165,7 +164,6 @@ static void GyaradosImpl(long dyw, long dxw, int dst[dyw][dxw], long syw,
|
|||
}
|
||||
}
|
||||
for (dy = 0; dy < dyn; ++dy) {
|
||||
/* TODO: pmulhrsw() would probably make this much faster */
|
||||
for (sx = 0; sx < sxn; ++sx) {
|
||||
tmp1[dy][sx] = sharpen ? Sharpen(tmp0[MIN(dyn - 1, MAX(0, dy - 1))][sx],
|
||||
tmp0[dy][sx],
|
||||
|
@ -218,9 +216,9 @@ void *Gyarados(long dyw, long dxw, int dst[dyw][dxw], long syw, long sxw,
|
|||
CHECK_LE(syn, 0x7fff);
|
||||
CHECK_LE(sxn, 0x7fff);
|
||||
GyaradosImpl(dyw, dxw, dst, syw, sxw, src, dyn, dxn, syn, sxn,
|
||||
gc(xmemalign(64, sizeof(int) * dyn * sxn)),
|
||||
gc(xmemalign(64, sizeof(int) * dyn * sxn)),
|
||||
gc(xmemalign(64, sizeof(int) * dyn * dxn)), cy->s, cx->s,
|
||||
gc(xmemalign(64, sizeof(short) * dyn * sxn)),
|
||||
gc(xmemalign(64, sizeof(short) * dyn * sxn)),
|
||||
gc(xmemalign(64, sizeof(short) * dyn * dxn)), cy->s, cx->s,
|
||||
cy->indices, cy->weights, cx->indices, cx->weights, sharpen);
|
||||
} else {
|
||||
ZeroMatrix(dyw, dxw, dst, dyn, dxn);
|
||||
|
|
|
@ -47,6 +47,13 @@ $(DSP_SCALE_A).pkg: \
|
|||
$(DSP_SCALE_A_OBJS) \
|
||||
$(foreach x,$(DSP_SCALE_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/dsp/scale/cdecimate2xuint8x8.o \
|
||||
o/$(MODE)/dsp/scale/gyarados.o \
|
||||
o/$(MODE)/dsp/scale/magikarp.o \
|
||||
o/$(MODE)/dsp/scale/scale.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
$(MATHEMATICAL)
|
||||
|
||||
DSP_SCALE_LIBS = $(foreach x,$(DSP_SCALE_ARTIFACTS),$($(x)))
|
||||
DSP_SCALE_SRCS = $(foreach x,$(DSP_SCALE_ARTIFACTS),$($(x)_SRCS))
|
||||
DSP_SCALE_HDRS = $(foreach x,$(DSP_SCALE_ARTIFACTS),$($(x)_HDRS))
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
|
|
|
@ -19,15 +19,15 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/itoa8.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/initializer.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
struct Itoa8 kItoa8;
|
||||
|
||||
static nooptimize textstartup void itoa8init(void) {
|
||||
size_t i;
|
||||
static textstartup void itoa8_init(void) {
|
||||
int i;
|
||||
uint8_t z;
|
||||
char p[4];
|
||||
/*102*/
|
||||
for (i = 0; i < 256; ++i) {
|
||||
memset(p, 0, sizeof(p));
|
||||
if (i < 10) {
|
||||
|
@ -48,4 +48,4 @@ static nooptimize textstartup void itoa8init(void) {
|
|||
}
|
||||
}
|
||||
|
||||
INITIALIZER(301, _init_itoa8, itoa8init());
|
||||
const void *const itoa8_init_ctor[] initarray = {itoa8_init};
|
||||
|
|
|
@ -64,9 +64,10 @@ extern double g_xterm256_gamma;
|
|||
extern struct TtyRgb g_ansi2rgb_[256];
|
||||
extern struct TtyQuant g_ttyquant_;
|
||||
extern const uint8_t kXtermXlat[2][256];
|
||||
extern const uint8_t kXtermCube[6];
|
||||
|
||||
void ttyquantinit(enum TtyQuantizationAlgorithm, enum TtyQuantizationChannels,
|
||||
enum TtyBlocksSelection);
|
||||
void ttyquantsetup(enum TtyQuantizationAlgorithm, enum TtyQuantizationChannels,
|
||||
enum TtyBlocksSelection);
|
||||
|
||||
extern char *ttyraster(char *, const struct TtyRgb *, size_t, size_t,
|
||||
struct TtyRgb, struct TtyRgb);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "dsp/core/core.h"
|
||||
#include "dsp/tty/quant.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/initializer.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
|
@ -32,12 +33,8 @@
|
|||
#define SQR(X) ((X) * (X))
|
||||
#define SUM(X, Y, Z) ((X) + (Y) + (Z))
|
||||
|
||||
static const uint8_t kXtermCube[] = {0, 0137, 0207, 0257, 0327, 0377};
|
||||
const uint8_t kXtermCube[6] = {0, 0137, 0207, 0257, 0327, 0377};
|
||||
struct TtyRgb g_ansi2rgb_[256];
|
||||
static uint8_t g_quant[256];
|
||||
static uint8_t g_rindex[256];
|
||||
static uint8_t g_gindex[256];
|
||||
static uint8_t g_bindex[256];
|
||||
double g_xterm256_gamma;
|
||||
|
||||
struct TtyRgb tty2rgb_(struct TtyRgb rgbxt) {
|
||||
|
@ -101,17 +98,10 @@ static int uncube(int x) {
|
|||
return x < 48 ? 0 : x < 115 ? 1 : (x - 35) / 40;
|
||||
}
|
||||
|
||||
static optimizesize textstartup void xterm2rgbsetup_(void) {
|
||||
static textstartup void rgb2ansi_init(void) {
|
||||
uint8_t c, y;
|
||||
uint32_t i, j;
|
||||
memcpy(g_ansi2rgb_, &kCgaPalette, sizeof(kCgaPalette));
|
||||
for (i = 0; i < 256; ++i) {
|
||||
j = uncube(i);
|
||||
g_quant[i] = kXtermCube[j];
|
||||
g_rindex[i] = j * 36;
|
||||
g_gindex[i] = j * 6;
|
||||
g_bindex[i] = j + 16;
|
||||
}
|
||||
for (i = 16; i < 232; ++i) {
|
||||
g_ansi2rgb_[i].r = kXtermCube[((i - 020) / 044) % 06];
|
||||
g_ansi2rgb_[i].g = kXtermCube[((i - 020) / 06) % 06];
|
||||
|
@ -126,4 +116,4 @@ static optimizesize textstartup void xterm2rgbsetup_(void) {
|
|||
}
|
||||
}
|
||||
|
||||
INITIALIZER(301, _init_ansi2rgb, xterm2rgbsetup_());
|
||||
const void *const rgb2ansi_init_ctor[] initarray = {rgb2ansi_init};
|
||||
|
|
|
@ -1,71 +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 │
|
||||
│ │
|
||||
│ 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 "dsp/tty/rgb2xterm256.h"
|
||||
|
||||
/* 1bc */
|
||||
forceinline int sqr(int x) { return x * x; }
|
||||
/* forceinline int dst6(int x) { return x * x; } */
|
||||
int rgb2xterm256v2(int r, int g, int b) {
|
||||
static const int i2cv[] = {0, 0137, 0207, 0257, 0327, 0377, 0377};
|
||||
#define v2ci(v) (v < 060 ? 0 : v < 0163 ? 01 : (v - 043) / 050)
|
||||
#define dst6(A, B, C, a, b, c) (sqr(A - a) + sqr(B - b) + sqr(C - c))
|
||||
int ir = v2ci(r);
|
||||
int ig = v2ci(g);
|
||||
int ib = v2ci(b);
|
||||
int avg = (r + g + b) / 3;
|
||||
int cr = i2cv[ir];
|
||||
int cg = i2cv[ig];
|
||||
int cb = i2cv[ib];
|
||||
int gidx = avg > 238 ? 23 : (avg - 3) / 10;
|
||||
int gv = 8 + 10 * gidx;
|
||||
int cerr = dst6(cr, cg, cb, r, g, b);
|
||||
int gerr = dst6(gv, gv, gv, r, g, b);
|
||||
return cerr <= gerr ? 16 + (36 * ir + 6 * ig + ib) : 232 + gidx;
|
||||
#undef dst6
|
||||
#undef cidx
|
||||
#undef v2ci
|
||||
}
|
||||
|
||||
/* 1e3 */
|
||||
// Convert RGB24 to xterm-256 8-bit value
|
||||
// For simplicity, assume RGB space is perceptually uniform.
|
||||
// There are 5 places where one of two outputs needs to be chosen when
|
||||
// input is the exact middle:
|
||||
// - The r/g/b channels and the gray value: choose higher value output
|
||||
// - If gray and color have same distance from input - choose color
|
||||
int rgb2xterm256(uint8_t r, uint8_t g, uint8_t b) {
|
||||
// Calculate the nearest 0-based color index at 16 .. 231
|
||||
#define v2ci(v) (v < 48 ? 0 : v < 115 ? 1 : (v - 35) / 40)
|
||||
int ir = v2ci(r), ig = v2ci(g), ib = v2ci(b); // 0..5 each
|
||||
#define color_index() (36 * ir + 6 * ig + ib) /* 0..215, lazy eval */
|
||||
// Calculate the nearest 0-based gray index at 232 .. 255
|
||||
int average = (r + g + b) / 3;
|
||||
int gray_index = average > 238 ? 23 : (average - 3) / 10; // 0..23
|
||||
// Calculate the represented colors back from the index
|
||||
static const int i2cv[6] = {0, 0x5f, 0x87, 0xaf, 0xd7, 0xff};
|
||||
int cr = i2cv[ir], cg = i2cv[ig], cb = i2cv[ib]; // r/g/b, 0..255 each
|
||||
int gv = 8 + 10 * gray_index; // same value for r/g/b, 0..255
|
||||
// Return the one which is nearer to the original input rgb value
|
||||
#define dist_square(A, B, C, a, b, c) \
|
||||
((A - a) * (A - a) + (B - b) * (B - b) + (C - c) * (C - c))
|
||||
int color_err = dist_square(cr, cg, cb, r, g, b);
|
||||
int gray_err = dist_square(gv, gv, gv, r, g, b);
|
||||
return color_err <= gray_err ? 16 + color_index() : 232 + gray_index;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_DSP_TTY_RGB2XTERM256_H_
|
||||
#define COSMOPOLITAN_DSP_TTY_RGB2XTERM256_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int rgb2xterm256(uint8_t, uint8_t, uint8_t);
|
||||
int rgb2xterm256v2(int, int, int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_TTY_RGB2XTERM256_H_ */
|
|
@ -19,6 +19,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/internal.h"
|
||||
#include "dsp/tty/quant.h"
|
||||
#include "libc/bits/initializer.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
@ -29,9 +30,9 @@ struct TtyQuant g_ttyquant_;
|
|||
/**
|
||||
* Chooses xterm quantization mode.
|
||||
*/
|
||||
optimizesize textstartup void ttyquantinit(enum TtyQuantizationAlgorithm alg,
|
||||
enum TtyQuantizationChannels chans,
|
||||
enum TtyBlocksSelection blocks) {
|
||||
textstartup void ttyquantsetup(enum TtyQuantizationAlgorithm alg,
|
||||
enum TtyQuantizationChannels chans,
|
||||
enum TtyBlocksSelection blocks) {
|
||||
switch (alg) {
|
||||
case kTtyQuantAnsi:
|
||||
TTYQUANT()->rgb2tty = rgb2ansi_;
|
||||
|
@ -74,5 +75,8 @@ optimizesize textstartup void ttyquantinit(enum TtyQuantizationAlgorithm alg,
|
|||
TTYQUANT()->blocks = blocks;
|
||||
}
|
||||
|
||||
INITIALIZER(400, _init_ttyquant,
|
||||
ttyquantinit(kTtyQuantXterm256, kTtyQuantRgb, kTtyBlocksUnicode));
|
||||
textstartup void ttyquant_init(void) {
|
||||
ttyquantsetup(kTtyQuantXterm256, kTtyQuantRgb, kTtyBlocksUnicode);
|
||||
}
|
||||
|
||||
const void *const ttyquant_init_ctor[] initarray = {ttyquant_init};
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
static struct TtyRaw {
|
||||
bool setup;
|
||||
bool hasold;
|
||||
bool noreentry;
|
||||
bool initialized;
|
||||
enum TtyRawFlags flags;
|
||||
|
@ -51,12 +52,15 @@ static struct TtyRaw {
|
|||
} g_ttyraw;
|
||||
|
||||
static textstartup int ttyraw_setup(void) {
|
||||
if (isatty(FD) &&
|
||||
ttyconfig(FD, ttysetrawmode, g_ttyraw.flags, &g_ttyraw.old) != -1) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
struct termios *old;
|
||||
if (isatty(FD)) {
|
||||
old = !g_ttyraw.hasold ? &g_ttyraw.old : NULL;
|
||||
if (ttyconfig(FD, ttysetrawmode, g_ttyraw.flags, old) != -1) {
|
||||
g_ttyraw.hasold = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static textstartup int ttyraw_enable(void) {
|
||||
|
|
|
@ -0,0 +1,282 @@
|
|||
/*-*- 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 "dsp/tty/xtermname.h"
|
||||
|
||||
/**
|
||||
* 256-entry double-nul-terminated list of XTERM256 names.
|
||||
*/
|
||||
const char kXtermName[] = "\
|
||||
Black\0\
|
||||
Maroon\0\
|
||||
Green\0\
|
||||
Olive\0\
|
||||
Navy\0\
|
||||
Purple\0\
|
||||
Teal\0\
|
||||
Silver\0\
|
||||
Grey\0\
|
||||
Red\0\
|
||||
Lime\0\
|
||||
Yellow\0\
|
||||
Blue\0\
|
||||
Fuchsia\0\
|
||||
Aqua\0\
|
||||
White\0\
|
||||
Grey0\0\
|
||||
NavyBlue\0\
|
||||
DarkBlue\0\
|
||||
Blue3\0\
|
||||
Blue3\0\
|
||||
Blue1\0\
|
||||
DarkGreen\0\
|
||||
DeepSkyBlue4\0\
|
||||
DeepSkyBlue4\0\
|
||||
DeepSkyBlue4\0\
|
||||
DodgerBlue3\0\
|
||||
DodgerBlue2\0\
|
||||
Green4\0\
|
||||
SpringGreen4\0\
|
||||
Turquoise4\0\
|
||||
DeepSkyBlue3\0\
|
||||
DeepSkyBlue3\0\
|
||||
DodgerBlue1\0\
|
||||
Green3\0\
|
||||
SpringGreen3\0\
|
||||
DarkCyan\0\
|
||||
LightSeaGreen\0\
|
||||
DeepSkyBlue2\0\
|
||||
DeepSkyBlue1\0\
|
||||
Green3\0\
|
||||
SpringGreen3\0\
|
||||
SpringGreen2\0\
|
||||
Cyan3\0\
|
||||
DarkTurquoise\0\
|
||||
Turquoise2\0\
|
||||
Green1\0\
|
||||
SpringGreen2\0\
|
||||
SpringGreen1\0\
|
||||
MediumSpringGreen\0\
|
||||
Cyan2\0\
|
||||
Cyan1\0\
|
||||
DarkRed\0\
|
||||
DeepPink4\0\
|
||||
Purple4\0\
|
||||
Purple4\0\
|
||||
Purple3\0\
|
||||
BlueViolet\0\
|
||||
Orange4\0\
|
||||
Grey37\0\
|
||||
MediumPurple4\0\
|
||||
SlateBlue3\0\
|
||||
SlateBlue3\0\
|
||||
RoyalBlue1\0\
|
||||
Chartreuse4\0\
|
||||
DarkSeaGreen4\0\
|
||||
PaleTurquoise4\0\
|
||||
SteelBlue\0\
|
||||
SteelBlue3\0\
|
||||
CornflowerBlue\0\
|
||||
Chartreuse3\0\
|
||||
DarkSeaGreen4\0\
|
||||
CadetBlue\0\
|
||||
CadetBlue\0\
|
||||
SkyBlue3\0\
|
||||
SteelBlue1\0\
|
||||
Chartreuse3\0\
|
||||
PaleGreen3\0\
|
||||
SeaGreen3\0\
|
||||
Aquamarine3\0\
|
||||
MediumTurquoise\0\
|
||||
SteelBlue1\0\
|
||||
Chartreuse2\0\
|
||||
SeaGreen2\0\
|
||||
SeaGreen1\0\
|
||||
SeaGreen1\0\
|
||||
Aquamarine1\0\
|
||||
DarkSlateGray2\0\
|
||||
DarkRed\0\
|
||||
DeepPink4\0\
|
||||
DarkMagenta\0\
|
||||
DarkMagenta\0\
|
||||
DarkViolet\0\
|
||||
Purple\0\
|
||||
Orange4\0\
|
||||
LightPink4\0\
|
||||
Plum4\0\
|
||||
MediumPurple3\0\
|
||||
MediumPurple3\0\
|
||||
SlateBlue1\0\
|
||||
Yellow4\0\
|
||||
Wheat4\0\
|
||||
Grey53\0\
|
||||
LightSlateGrey\0\
|
||||
MediumPurple\0\
|
||||
LightSlateBlue\0\
|
||||
Yellow4\0\
|
||||
DarkOliveGreen3\0\
|
||||
DarkSeaGreen\0\
|
||||
LightSkyBlue3\0\
|
||||
LightSkyBlue3\0\
|
||||
SkyBlue2\0\
|
||||
Chartreuse2\0\
|
||||
DarkOliveGreen3\0\
|
||||
PaleGreen3\0\
|
||||
DarkSeaGreen3\0\
|
||||
DarkSlateGray3\0\
|
||||
SkyBlue1\0\
|
||||
Chartreuse1\0\
|
||||
LightGreen\0\
|
||||
LightGreen\0\
|
||||
PaleGreen1\0\
|
||||
Aquamarine1\0\
|
||||
DarkSlateGray1\0\
|
||||
Red3\0\
|
||||
DeepPink4\0\
|
||||
MediumVioletRed\0\
|
||||
Magenta3\0\
|
||||
DarkViolet\0\
|
||||
Purple\0\
|
||||
DarkOrange3\0\
|
||||
IndianRed\0\
|
||||
HotPink3\0\
|
||||
MediumOrchid3\0\
|
||||
MediumOrchid\0\
|
||||
MediumPurple2\0\
|
||||
DarkGoldenrod\0\
|
||||
LightSalmon3\0\
|
||||
RosyBrown\0\
|
||||
Grey63\0\
|
||||
MediumPurple2\0\
|
||||
MediumPurple1\0\
|
||||
Gold3\0\
|
||||
DarkKhaki\0\
|
||||
NavajoWhite3\0\
|
||||
Grey69\0\
|
||||
LightSteelBlue3\0\
|
||||
LightSteelBlue\0\
|
||||
Yellow3\0\
|
||||
DarkOliveGreen3\0\
|
||||
DarkSeaGreen3\0\
|
||||
DarkSeaGreen2\0\
|
||||
LightCyan3\0\
|
||||
LightSkyBlue1\0\
|
||||
GreenYellow\0\
|
||||
DarkOliveGreen2\0\
|
||||
PaleGreen1\0\
|
||||
DarkSeaGreen2\0\
|
||||
DarkSeaGreen1\0\
|
||||
PaleTurquoise1\0\
|
||||
Red3\0\
|
||||
DeepPink3\0\
|
||||
DeepPink3\0\
|
||||
Magenta3\0\
|
||||
Magenta3\0\
|
||||
Magenta2\0\
|
||||
DarkOrange3\0\
|
||||
IndianRed\0\
|
||||
HotPink3\0\
|
||||
HotPink2\0\
|
||||
Orchid\0\
|
||||
MediumOrchid1\0\
|
||||
Orange3\0\
|
||||
LightSalmon3\0\
|
||||
LightPink3\0\
|
||||
Pink3\0\
|
||||
Plum3\0\
|
||||
Violet\0\
|
||||
Gold3\0\
|
||||
LightGoldenrod3\0\
|
||||
Tan\0\
|
||||
MistyRose3\0\
|
||||
Thistle3\0\
|
||||
Plum2\0\
|
||||
Yellow3\0\
|
||||
Khaki3\0\
|
||||
LightGoldenrod2\0\
|
||||
LightYellow3\0\
|
||||
Grey84\0\
|
||||
LightSteelBlue1\0\
|
||||
Yellow2\0\
|
||||
DarkOliveGreen1\0\
|
||||
DarkOliveGreen1\0\
|
||||
DarkSeaGreen1\0\
|
||||
Honeydew2\0\
|
||||
LightCyan1\0\
|
||||
Red1\0\
|
||||
DeepPink2\0\
|
||||
DeepPink1\0\
|
||||
DeepPink1\0\
|
||||
Magenta2\0\
|
||||
Magenta1\0\
|
||||
OrangeRed1\0\
|
||||
IndianRed1\0\
|
||||
IndianRed1\0\
|
||||
HotPink\0\
|
||||
HotPink\0\
|
||||
MediumOrchid1\0\
|
||||
DarkOrange\0\
|
||||
Salmon1\0\
|
||||
LightCoral\0\
|
||||
PaleVioletRed1\0\
|
||||
Orchid2\0\
|
||||
Orchid1\0\
|
||||
Orange1\0\
|
||||
SandyBrown\0\
|
||||
LightSalmon1\0\
|
||||
LightPink1\0\
|
||||
Pink1\0\
|
||||
Plum1\0\
|
||||
Gold1\0\
|
||||
LightGoldenrod2\0\
|
||||
LightGoldenrod2\0\
|
||||
NavajoWhite1\0\
|
||||
MistyRose1\0\
|
||||
Thistle1\0\
|
||||
Yellow1\0\
|
||||
LightGoldenrod1\0\
|
||||
Khaki1\0\
|
||||
Wheat1\0\
|
||||
Cornsilk1\0\
|
||||
Grey100\0\
|
||||
Grey3\0\
|
||||
Grey7\0\
|
||||
Grey11\0\
|
||||
Grey15\0\
|
||||
Grey19\0\
|
||||
Grey23\0\
|
||||
Grey27\0\
|
||||
Grey30\0\
|
||||
Grey35\0\
|
||||
Grey39\0\
|
||||
Grey42\0\
|
||||
Grey46\0\
|
||||
Grey50\0\
|
||||
Grey54\0\
|
||||
Grey58\0\
|
||||
Grey62\0\
|
||||
Grey66\0\
|
||||
Grey70\0\
|
||||
Grey74\0\
|
||||
Grey78\0\
|
||||
Grey82\0\
|
||||
Grey85\0\
|
||||
Grey89\0\
|
||||
Grey93\0\
|
||||
\0";
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef COSMOPOLITAN_DSP_TTY_XTERMNAME_H_
|
||||
#define COSMOPOLITAN_DSP_TTY_XTERMNAME_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const char kXtermName[];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_TTY_XTERMNAME_H_ */
|
|
@ -8,6 +8,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/hefty/copyfile.h"
|
||||
#include "libc/calls/hefty/spawn.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/log/check.h"
|
||||
|
@ -87,7 +88,7 @@ int main(int argc, char *argv[]) {
|
|||
CHECK_NE(-1, close(fd));
|
||||
|
||||
t1 = dtime(CLOCK_REALTIME);
|
||||
CHECK_NE(-1, copyfile(core, core2, false));
|
||||
CHECK_NE(-1, copyfile(core, core2, 0));
|
||||
t2 = dtime(CLOCK_REALTIME);
|
||||
printf("%.6Lf\n", t2 - t1);
|
||||
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
#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/calls/calls.h"
|
||||
#include "libc/calls/hefty/copyfile.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
|
||||
#define USAGE \
|
||||
" SRC... DST\n\
|
||||
\n\
|
||||
SYNOPSIS\n\
|
||||
\n\
|
||||
Copies Files\n\
|
||||
\n\
|
||||
FLAGS\n\
|
||||
\n\
|
||||
-?\n\
|
||||
-h help\n\
|
||||
-f force\n\
|
||||
-n no clobber\n\
|
||||
-a preserve all\n\
|
||||
-p preserve owner and timestamps\n\
|
||||
\n"
|
||||
|
||||
int flags;
|
||||
bool force;
|
||||
|
||||
noreturn void PrintUsage(int rc, FILE *f) {
|
||||
fprintf(f, "%s%s%s", "Usage: ", program_invocation_name, USAGE);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "?hfnap")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
force = true;
|
||||
break;
|
||||
case 'n':
|
||||
flags |= COPYFILE_NOCLOBBER;
|
||||
break;
|
||||
case 'a':
|
||||
case 'p':
|
||||
flags |= COPYFILE_PRESERVE_OWNER;
|
||||
flags |= COPYFILE_PRESERVE_TIMESTAMPS;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cp(const char *src, const char *dst) {
|
||||
if (endswith(dst, "/") || isdirectory(dst)) {
|
||||
dst = gc(xasprintf("%s/%s", dst, basename));
|
||||
}
|
||||
if (!force && access(dst, W_OK) == -1 && errno != ENOENT) goto OnFail;
|
||||
if (copyfile(src, dst, flags) == -1) goto OnFail;
|
||||
return 0;
|
||||
OnFail:
|
||||
fprintf(stderr, "%s %s %s: %s\n", "error: cp", src, dst, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
GetOpts(argc, argv);
|
||||
if (argc - optind < 2) PrintUsage(EX_USAGE, stderr);
|
||||
for (i = optind; i < argc - 1; ++i) {
|
||||
if (cp(argv[i], argv[argc - 1]) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -8,120 +8,135 @@ EXAMPLES_MAINS_S = $(filter %.S,$(EXAMPLES_FILES))
|
|||
EXAMPLES_MAINS_C = $(filter %.c,$(EXAMPLES_FILES))
|
||||
EXAMPLES_MAINS_CC = $(filter %.cc,$(EXAMPLES_FILES))
|
||||
|
||||
EXAMPLES_SRCS = \
|
||||
$(EXAMPLES_MAINS_S) \
|
||||
$(EXAMPLES_MAINS_C) \
|
||||
EXAMPLES_SRCS = \
|
||||
$(EXAMPLES_MAINS_S) \
|
||||
$(EXAMPLES_MAINS_C) \
|
||||
$(EXAMPLES_MAINS_CC)
|
||||
|
||||
EXAMPLES_MAINS = \
|
||||
$(EXAMPLES_MAINS_S) \
|
||||
$(EXAMPLES_MAINS_C) \
|
||||
EXAMPLES_MAINS = \
|
||||
$(EXAMPLES_MAINS_S) \
|
||||
$(EXAMPLES_MAINS_C) \
|
||||
$(EXAMPLES_MAINS_CC)
|
||||
|
||||
EXAMPLES_OBJS = \
|
||||
$(EXAMPLES_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(EXAMPLES_MAINS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(EXAMPLES_MAINS_C:%.c=o/$(MODE)/%.o) \
|
||||
EXAMPLES_OBJS = \
|
||||
$(EXAMPLES_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(EXAMPLES_MAINS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(EXAMPLES_MAINS_C:%.c=o/$(MODE)/%.o) \
|
||||
$(EXAMPLES_MAINS_CC:%.cc=o/$(MODE)/%.o)
|
||||
|
||||
EXAMPLES_COMS = \
|
||||
$(EXAMPLES_OBJS:%.o=%.com)
|
||||
EXAMPLES_COMS = \
|
||||
$(EXAMPLES_MAINS_S:%.S=o/$(MODE)/%.com) \
|
||||
$(EXAMPLES_MAINS_C:%.c=o/$(MODE)/%.com) \
|
||||
$(EXAMPLES_MAINS_CC:%.cc=o/$(MODE)/%.com)
|
||||
|
||||
EXAMPLES_ELFS = \
|
||||
EXAMPLES_ELFS = \
|
||||
$(EXAMPLES_OBJS:%.o=%.elf)
|
||||
|
||||
EXAMPLES_BINS = \
|
||||
$(EXAMPLES_ELFS) \
|
||||
$(EXAMPLES_COMS) \
|
||||
EXAMPLES_BINS = \
|
||||
$(EXAMPLES_ELFS) \
|
||||
$(EXAMPLES_COMS) \
|
||||
$(EXAMPLES_COMS:%=%.dbg)
|
||||
|
||||
EXAMPLES_DIRECTDEPS = \
|
||||
APE_LIB \
|
||||
DSP_CORE \
|
||||
DSP_SCALE \
|
||||
DSP_TTY \
|
||||
LIBC_ALG \
|
||||
LIBC_BITS \
|
||||
LIBC_CALLS \
|
||||
LIBC_CALLS_HEFTY \
|
||||
LIBC_CONV \
|
||||
LIBC_FMT \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_KERNELBASE \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_OHMYPLUS \
|
||||
LIBC_RAND \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_UNICODE \
|
||||
LIBC_X \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_DTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_STB \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
EXAMPLES_DIRECTDEPS = \
|
||||
APE_LIB \
|
||||
DSP_CORE \
|
||||
DSP_SCALE \
|
||||
DSP_TTY \
|
||||
LIBC_ALG \
|
||||
LIBC_BITS \
|
||||
LIBC_CALLS \
|
||||
LIBC_CALLS_HEFTY \
|
||||
LIBC_CONV \
|
||||
LIBC_FMT \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_KERNELBASE \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_OHMYPLUS \
|
||||
LIBC_RAND \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_UNICODE \
|
||||
LIBC_X \
|
||||
LIBC_ZIPOS \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_DTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_STB \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
TOOL_VIZ_LIB
|
||||
|
||||
EXAMPLES_DEPS := \
|
||||
EXAMPLES_DEPS := \
|
||||
$(call uniq,$(foreach x,$(EXAMPLES_DIRECTDEPS),$($(x))))
|
||||
|
||||
o/$(MODE)/examples/examples.pkg: \
|
||||
$(EXAMPLES_OBJS) \
|
||||
$(THIRD_PARTY_DUKTAPE_A).pkg \
|
||||
o/$(MODE)/examples/examples.pkg: \
|
||||
$(EXAMPLES_OBJS) \
|
||||
$(THIRD_PARTY_DUKTAPE_A).pkg \
|
||||
$(foreach x,$(EXAMPLES_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/examples/unbourne.o: \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
o/$(MODE)/examples/unbourne.o: \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
||||
o/$(MODE)/examples/%.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/%.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
o/$(MODE)/examples/%.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/%.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/examples/%.elf: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
$(THIRD_PARTY_DUKTAPE) \
|
||||
o/$(MODE)/examples/%.o \
|
||||
$(CRT) \
|
||||
o/$(MODE)/examples/%.elf: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
$(THIRD_PARTY_DUKTAPE) \
|
||||
o/$(MODE)/examples/%.o \
|
||||
$(CRT) \
|
||||
$(ELF)
|
||||
@$(ELFLINK)
|
||||
|
||||
$(EXAMPLES_OBJS): examples/examples.mk
|
||||
|
||||
o/$(MODE)/examples/hellojs.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
$(THIRD_PARTY_DUKTAPE) \
|
||||
o/$(MODE)/examples/hellojs.o \
|
||||
o/$(MODE)/examples/hello.js.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
o/$(MODE)/examples/hellojs.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
$(THIRD_PARTY_DUKTAPE) \
|
||||
o/$(MODE)/examples/hellojs.o \
|
||||
o/$(MODE)/examples/hello.js.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/examples/ispell.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/ispell.o \
|
||||
o/$(MODE)/usr/share/dict/words.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
o/$(MODE)/examples/ispell.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/ispell.o \
|
||||
o/$(MODE)/usr/share/dict/words.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/examples/nesemu1.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
$(THIRD_PARTY_DUKTAPE) \
|
||||
o/$(MODE)/examples/nesemu1.o \
|
||||
o/$(MODE)/usr/share/rom/mario.nes.zip.o \
|
||||
o/$(MODE)/usr/share/rom/zelda.nes.zip.o \
|
||||
o/$(MODE)/usr/share/rom/tetris.nes.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
|
@ -129,7 +144,11 @@ o/$(MODE)/usr/share/dict/words: usr/share/dict/words.gz
|
|||
@$(MKDIR) $(dir $@)
|
||||
@$(GZ) $(ZFLAGS) <$< >$@
|
||||
|
||||
o/$(MODE)/examples/ugh.ok: o/$(MODE)/examples/wut.com
|
||||
$<
|
||||
touch $@
|
||||
|
||||
.PHONY: o/$(MODE)/examples
|
||||
o/$(MODE)/examples: \
|
||||
o/$(MODE)/examples/package \
|
||||
o/$(MODE)/examples: \
|
||||
o/$(MODE)/examples/package \
|
||||
$(EXAMPLES_BINS)
|
||||
|
|
|
@ -28,6 +28,7 @@ static const char *magic_;
|
|||
void OnInterrupt(int sig) {
|
||||
showprogress_ = true;
|
||||
}
|
||||
|
||||
void ShowProgress(uintmax_t i, uintmax_t j, uintmax_t n) {
|
||||
fprintf(stderr, "%s%,40jd%,40jd%,40jd\r\n", magic_, i, j, n);
|
||||
showprogress_ = false;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
int main() {
|
||||
|
@ -19,5 +20,5 @@ int main() {
|
|||
* have that string consist solely of directives.
|
||||
*/
|
||||
printf("%s\n", "hello world");
|
||||
return errno;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ Contact: antirez@gmail.com\"\n\
|
|||
#define _GNU_SOURCE
|
||||
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/arraylist.h"
|
||||
#include "libc/alg/arraylist2.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
|
@ -879,7 +879,7 @@ struct abuf {
|
|||
};
|
||||
|
||||
static void abAppend(struct abuf *ab, const char *s, int len) {
|
||||
concat(ab, s, len);
|
||||
CONCAT(&ab->p, &ab->i, &ab->n, s, len);
|
||||
}
|
||||
|
||||
/* This function writes the whole screen using VT100 escape characters
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
/* TRADEMARKS ARE OWNED BY THEIR RESPECTIVE OWNERS LAWYERCATS LUV TAUTOLOGIES */
|
||||
/* https://bisqwit.iki.fi/jutut/kuvat/programming_examples/nesemu1/nesemu1.cc */
|
||||
#include "dsp/core/core.h"
|
||||
#include "dsp/core/half.h"
|
||||
#include "dsp/core/illumination.h"
|
||||
#include "dsp/scale/scale.h"
|
||||
#include "dsp/tty/itoa8.h"
|
||||
#include "dsp/tty/quant.h"
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/alg/arraylist2.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
|
@ -16,6 +18,7 @@
|
|||
#include "libc/calls/hefty/spawn.h"
|
||||
#include "libc/calls/struct/itimerval.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/inttypes.h"
|
||||
|
@ -30,6 +33,8 @@
|
|||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -37,24 +42,77 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/zip.h"
|
||||
#include "libc/zipos/zipos.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "tool/viz/lib/knobs.h"
|
||||
|
||||
#define DYN 240
|
||||
#define DXN 256
|
||||
#define FPS 60.0988
|
||||
#define HZ 1789773
|
||||
#define KEYHZ 20
|
||||
#define GAMMA 2.2
|
||||
#define USAGE \
|
||||
" [ROM] [FMV]\n\
|
||||
\n\
|
||||
SYNOPSIS\n\
|
||||
\n\
|
||||
Emulates NES Video Games in Terminal\n\
|
||||
\n\
|
||||
FLAGS\n\
|
||||
\n\
|
||||
-A ansi color mode\n\
|
||||
-t normal color mode\n\
|
||||
-x xterm256 color mode\n\
|
||||
-4 unicode character set\n\
|
||||
-3 ibm cp437 character set\n\
|
||||
-1 ntsc crt artifact emulation\n\
|
||||
-h\n\
|
||||
-? shows this information\n\
|
||||
\n\
|
||||
KEYBOARD\n\
|
||||
\n\
|
||||
We support Emacs / Mac OS X control key bindings. We also support\n\
|
||||
Vim. We support arrow keys. We also support WASD QWERTY & Dvorak.\n\
|
||||
The 'A' button is mapped to SPACE. The 'B' button is mapped to b.\n\
|
||||
Lastly TAB is SELECT and ENTER is START.\n\
|
||||
\n\
|
||||
Teletypewriters are naturally limited in terms of keyboard input.\n\
|
||||
They don't exactly have n-key rollover. More like 1-key rollover.\n\
|
||||
\n\
|
||||
Try tapping rather than holding keys. You can tune the activation\n\
|
||||
duration by pressing '8' and '9'. You can also adjust the keyboard\n\
|
||||
repeat delay in your operating system settings to make it shorter.\n\
|
||||
\n\
|
||||
Ideally we should send patches to all the terms that introduces a\n\
|
||||
new ANSI escape sequences for key down / key up events. It'd also\n\
|
||||
be great to have inband audio with terminals too.\n\
|
||||
\n\
|
||||
GRAPHICS\n\
|
||||
\n\
|
||||
The '1' key toggles CRT monitor artifact emulation, which can make\n\
|
||||
some games like Zelda II look better. The '3' and '4' keys toggle\n\
|
||||
the selection of UNICODE block characters.\n\
|
||||
\n\
|
||||
ZIP\n\
|
||||
\n\
|
||||
This executable is also a ZIP archive. If you change the extension\n\
|
||||
then you can modify its inner structure, to place roms inside it.\n\
|
||||
\n\
|
||||
AUTHORS\n\
|
||||
\n\
|
||||
Joel Yliluoma <http://iki.fi/bisqwit/>\n\
|
||||
Justine Tunney <jtunney@gmail.com/>\n\
|
||||
\n\
|
||||
\n"
|
||||
|
||||
#define DYN 240
|
||||
#define DXN 256
|
||||
#define FPS 60.0988
|
||||
#define HZ 1789773
|
||||
#define GAMMA 2.2
|
||||
#define CTRL(C) ((C) ^ 0100)
|
||||
#define ALT(C) ((033 << 010) | (C))
|
||||
|
||||
static const char* inputfn;
|
||||
|
||||
typedef uint32_t u32;
|
||||
typedef uint16_t u16;
|
||||
typedef uint8_t u8;
|
||||
typedef int8_t s8;
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
|
||||
static const struct itimerval kNesFps = {
|
||||
{0, 1. / FPS * 1e6},
|
||||
|
@ -75,9 +133,19 @@ struct Audio {
|
|||
int16_t p[FRAMESIZE];
|
||||
};
|
||||
|
||||
struct Status {
|
||||
int wait;
|
||||
char text[80];
|
||||
};
|
||||
|
||||
struct ZipGames {
|
||||
size_t i, n;
|
||||
char** p;
|
||||
};
|
||||
|
||||
static int frame_;
|
||||
static int drain_;
|
||||
static int playfd_;
|
||||
static bool piped_;
|
||||
static int devnull_;
|
||||
static int playpid_;
|
||||
static bool exited_;
|
||||
|
@ -87,22 +155,32 @@ static size_t vtsize_;
|
|||
static bool artifacts_;
|
||||
static long tyn_, txn_;
|
||||
static const char* ffplay_;
|
||||
static struct Audio audio_;
|
||||
static struct TtyRgb* ttyrgb_;
|
||||
static struct Frame vf_[2];
|
||||
static struct Audio audio_;
|
||||
static const char* inputfn_;
|
||||
static struct Status status_;
|
||||
static struct TtyRgb* ttyrgb_;
|
||||
static unsigned char *R, *G, *B;
|
||||
static struct ZipGames zipgames_;
|
||||
static struct Action arrow_, button_;
|
||||
static struct SamplingSolution* asx_;
|
||||
static struct SamplingSolution* ssy_;
|
||||
static struct SamplingSolution* ssx_;
|
||||
static unsigned char pixels_[3][DYN][DXN];
|
||||
static unsigned char palette_[3][64][512][3];
|
||||
static int joy_current_[2] = {0, 0};
|
||||
static int joy_next_[2] = {0, 0};
|
||||
static int joypos_[2] = {0, 0};
|
||||
static int joy_current_[2], joy_next_[2], joypos_[2];
|
||||
|
||||
static int Clamp(int v) { return MAX(0, MIN(255, v)); }
|
||||
static double FixGamma(double x) { return tv2pcgamma(x, GAMMA); }
|
||||
static int keyframes_ = 20;
|
||||
static enum TtyBlocksSelection blocks_ = kTtyBlocksUnicode;
|
||||
static enum TtyQuantizationAlgorithm quant_ = kTtyQuantTrue;
|
||||
|
||||
static int Clamp(int v) {
|
||||
return MAX(0, MIN(255, v));
|
||||
}
|
||||
|
||||
static double FixGamma(double x) {
|
||||
return tv2pcgamma(x, GAMMA);
|
||||
}
|
||||
|
||||
void InitPalette(void) {
|
||||
// The input value is a NES color index (with de-emphasis bits).
|
||||
|
@ -110,7 +188,7 @@ void InitPalette(void) {
|
|||
// We need RGB values. To produce a RGB value, we emulate the NTSC circuitry.
|
||||
double A[3] = {-1.109, -.275, .947};
|
||||
double B[3] = {1.709, -.636, .624};
|
||||
double rgbc[3], lightbulb[3][3], rgbd65[3];
|
||||
double rgbc[3], lightbulb[3][3], rgbd65[3], sc[2];
|
||||
int o, u, r, c, b, p, y, i, l, q, e, p0, p1, pixel;
|
||||
signed char volt[] = "\372\273\32\305\35\311I\330D\357\175\13D!}N";
|
||||
GetChromaticAdaptationMatrix(lightbulb, kIlluminantC, kIlluminantD65);
|
||||
|
@ -119,9 +197,7 @@ void InitPalette(void) {
|
|||
for (p1 = 0; p1 < 64; ++p1) {
|
||||
for (u = 0; u < 3; ++u) {
|
||||
// Calculate the luma and chroma by emulating the relevant circuits:
|
||||
y = 0;
|
||||
i = 0;
|
||||
q = 0;
|
||||
y = i = q = 0;
|
||||
// 12 samples of NTSC signal constitute a color.
|
||||
for (p = 0; p < 12; ++p) {
|
||||
// Sample either the previous or the current pixel.
|
||||
|
@ -140,9 +216,10 @@ void InitPalette(void) {
|
|||
b = 40 + volt[(c > 12 * ((c + 8 + p) % 12 < 6)) +
|
||||
2 * !(0451326 >> p / 2 * 3 & e) + l];
|
||||
// Ideal TV NTSC demodulator?
|
||||
sincos(M_PI * p / 6, &sc[0], &sc[1]);
|
||||
y += b;
|
||||
i += b * round(cos(M_PI * p / 6) * 5909);
|
||||
q += b * round(sin(M_PI * p / 6) * 5909);
|
||||
i += b * sc[1] * 5909;
|
||||
q += b * sc[0] * 5909;
|
||||
}
|
||||
// Converts YIQ to RGB
|
||||
// Store color at subpixel precision
|
||||
|
@ -161,31 +238,62 @@ static void WriteStringNow(const char* s) {
|
|||
ttywrite(STDOUT_FILENO, s, strlen(s));
|
||||
}
|
||||
|
||||
void CleanupTerminal(void) {
|
||||
ttyraw((enum TtyRawFlags)(-1u));
|
||||
ttyshowcursor(STDOUT_FILENO);
|
||||
void Exit(int rc) {
|
||||
WriteStringNow("\r\n\e[0m\e[J");
|
||||
if (rc && errno) {
|
||||
fprintf(stderr, "%s%s\r\n", "error: ", strerror(errno));
|
||||
}
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void OnTimer(void) { timeout_ = true; }
|
||||
void OnResize(void) { resized_ = true; }
|
||||
void OnCtrlC(void) { exited_ = true; }
|
||||
void OnSigChld(void) { piped_ = true, playpid_ = 0; }
|
||||
void Cleanup(void) {
|
||||
ttyraw((enum TtyRawFlags)(-1u));
|
||||
ttyshowcursor(STDOUT_FILENO);
|
||||
if (playpid_) kill(playpid_, SIGTERM), sched_yield();
|
||||
}
|
||||
|
||||
void OnTimer(void) {
|
||||
timeout_ = true; // also sends EINTR to poll()
|
||||
}
|
||||
|
||||
void OnResize(void) {
|
||||
resized_ = true;
|
||||
}
|
||||
|
||||
void OnPiped(void) {
|
||||
exited_ = true;
|
||||
}
|
||||
|
||||
void OnCtrlC(void) {
|
||||
drain_ = exited_ = true;
|
||||
}
|
||||
|
||||
void OnSigChld(void) {
|
||||
exited_ = true, playpid_ = 0;
|
||||
}
|
||||
|
||||
void InitFrame(struct Frame* f) {
|
||||
f->p = f->w = f->mem = (char*)realloc(f->mem, vtsize_);
|
||||
}
|
||||
|
||||
long ChopAxis(long dn, long sn) {
|
||||
while (HALF(sn) > dn) {
|
||||
sn = HALF(sn);
|
||||
}
|
||||
return sn;
|
||||
}
|
||||
|
||||
void GetTermSize(void) {
|
||||
struct winsize wsize_;
|
||||
wsize_.ws_row = 25;
|
||||
wsize_.ws_col = 80;
|
||||
getttysize(STDOUT_FILENO, &wsize_);
|
||||
tyn_ = wsize_.ws_row * 2;
|
||||
txn_ = wsize_.ws_col * 2;
|
||||
getttysize(STDIN_FILENO, &wsize_);
|
||||
FreeSamplingSolution(ssy_);
|
||||
FreeSamplingSolution(ssx_);
|
||||
ssy_ = ComputeSamplingSolution(tyn_, DYN, 0, 0, 2);
|
||||
ssx_ = ComputeSamplingSolution(txn_, DXN, 0, 0, 0);
|
||||
tyn_ = wsize_.ws_row * 2;
|
||||
txn_ = wsize_.ws_col * 2;
|
||||
ssy_ = ComputeSamplingSolution(tyn_, ChopAxis(tyn_, DYN), 0, 0, 2);
|
||||
ssx_ = ComputeSamplingSolution(txn_, ChopAxis(txn_, DXN), 0, 0, 0);
|
||||
R = (unsigned char*)realloc(R, tyn_ * txn_);
|
||||
G = (unsigned char*)realloc(G, tyn_ * txn_);
|
||||
B = (unsigned char*)realloc(B, tyn_ * txn_);
|
||||
|
@ -216,20 +324,23 @@ bool TrySpeaker(const char* prog, char* const* args) {
|
|||
void IoInit(void) {
|
||||
GetTermSize();
|
||||
xsigaction(SIGINT, (void*)OnCtrlC, 0, 0, NULL);
|
||||
xsigaction(SIGPIPE, (void*)OnPiped, 0, 0, NULL);
|
||||
xsigaction(SIGWINCH, (void*)OnResize, 0, 0, NULL);
|
||||
xsigaction(SIGALRM, (void*)OnTimer, 0, 0, NULL);
|
||||
xsigaction(SIGCHLD, (void*)OnSigChld, 0, 0, NULL);
|
||||
setitimer(ITIMER_REAL, &kNesFps, NULL);
|
||||
ttyhidecursor(STDOUT_FILENO);
|
||||
ttyraw(kTtySigs);
|
||||
ttyquantinit(kTtyQuantTrue, kTtyQuantRgb, kTtyBlocksUnicode);
|
||||
atexit(CleanupTerminal);
|
||||
ttyquantsetup(quant_, kTtyQuantRgb, blocks_);
|
||||
atexit(Cleanup);
|
||||
}
|
||||
|
||||
void SystemFailure(void) {
|
||||
fputs("error: ", stderr);
|
||||
fputs(strerror(errno), stderr);
|
||||
fputc('\n', stderr);
|
||||
exit(7);
|
||||
void SetStatus(const char* fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
vsnprintf(status_.text, sizeof(status_.text), fmt, va);
|
||||
va_end(va);
|
||||
status_.wait = FPS / 2;
|
||||
}
|
||||
|
||||
void ReadKeyboard(void) {
|
||||
|
@ -238,6 +349,7 @@ void ReadKeyboard(void) {
|
|||
ssize_t i, rc;
|
||||
memset(b, -1, sizeof(b));
|
||||
if ((rc = read(STDIN_FILENO, b, 16)) != -1) {
|
||||
if (!rc) exited_ = true;
|
||||
for (i = 0; i < rc; ++i) {
|
||||
ch = b[i];
|
||||
if (b[i] == '\e') {
|
||||
|
@ -263,71 +375,105 @@ void ReadKeyboard(void) {
|
|||
}
|
||||
}
|
||||
switch (ch) {
|
||||
case '1':
|
||||
artifacts_ = !artifacts_;
|
||||
InitPalette();
|
||||
break;
|
||||
case ' ':
|
||||
button_.code = 0b00100000; // A
|
||||
button_.wait = KEYHZ;
|
||||
button_.wait = keyframes_;
|
||||
break;
|
||||
case 'b':
|
||||
button_.code = 0b00010000; // B
|
||||
button_.wait = KEYHZ;
|
||||
button_.wait = keyframes_;
|
||||
break;
|
||||
case '\r': // enter
|
||||
button_.code = 0b10000000; // START
|
||||
button_.wait = KEYHZ;
|
||||
button_.wait = keyframes_;
|
||||
break;
|
||||
case '\t': // tab
|
||||
button_.code = 0b01000000; // SELECT
|
||||
button_.wait = KEYHZ;
|
||||
button_.wait = keyframes_;
|
||||
break;
|
||||
case 'k': // vim
|
||||
case 'w': // wasd qwerty
|
||||
case ',': // wasd dvorak
|
||||
case CTRL('P'): // emacs
|
||||
arrow_.code = 0b00000100; // UP
|
||||
arrow_.wait = KEYHZ;
|
||||
arrow_.wait = keyframes_;
|
||||
break;
|
||||
case 'j': // vim
|
||||
case 's': // wasd qwerty
|
||||
case 'o': // wasd dvorak
|
||||
case CTRL('N'): // emacs
|
||||
arrow_.code = 0b00001000; // DOWN
|
||||
arrow_.wait = KEYHZ;
|
||||
arrow_.wait = keyframes_;
|
||||
break;
|
||||
case 'h': // vim
|
||||
case 'a': // wasd qwerty & dvorak
|
||||
case CTRL('B'): // emacs
|
||||
arrow_.code = 0b00000010; // LEFT
|
||||
arrow_.wait = KEYHZ;
|
||||
arrow_.wait = keyframes_;
|
||||
break;
|
||||
case 'l': // vim
|
||||
case 'd': // wasd qwerty
|
||||
case 'e': // wasd dvorak
|
||||
case CTRL('F'): // emacs
|
||||
arrow_.code = 0b00000001; // RIGHT
|
||||
arrow_.wait = KEYHZ;
|
||||
arrow_.wait = keyframes_;
|
||||
break;
|
||||
case 'A': // ansi 4-bit color mode
|
||||
quant_ = kTtyQuantAnsi;
|
||||
ttyquantsetup(quant_, kTtyQuantRgb, blocks_);
|
||||
SetStatus("ansi color");
|
||||
break;
|
||||
case 'x': // xterm256 color mode
|
||||
ttyquantinit(kTtyQuantXterm256, kTtyQuantRgb, kTtyBlocksUnicode);
|
||||
quant_ = kTtyQuantXterm256;
|
||||
ttyquantsetup(quant_, kTtyQuantRgb, blocks_);
|
||||
SetStatus("xterm256 color");
|
||||
break;
|
||||
case 't': // ansi 24bit color mode
|
||||
ttyquantinit(kTtyQuantTrue, kTtyQuantRgb, kTtyBlocksUnicode);
|
||||
quant_ = kTtyQuantTrue;
|
||||
ttyquantsetup(quant_, kTtyQuantRgb, blocks_);
|
||||
SetStatus("24-bit color");
|
||||
break;
|
||||
case '1':
|
||||
artifacts_ = !artifacts_;
|
||||
InitPalette();
|
||||
SetStatus("artifacts %s", artifacts_ ? "on" : "off");
|
||||
break;
|
||||
case '3': // oldskool ibm unicode rasterization
|
||||
blocks_ = kTtyBlocksCp437;
|
||||
ttyquantsetup(quant_, kTtyQuantRgb, blocks_);
|
||||
SetStatus("IBM CP437");
|
||||
break;
|
||||
case '4': // newskool unicode rasterization
|
||||
blocks_ = kTtyBlocksUnicode;
|
||||
ttyquantsetup(quant_, kTtyQuantRgb, blocks_);
|
||||
SetStatus("UNICODE");
|
||||
break;
|
||||
case '8':
|
||||
keyframes_ = MAX(1, keyframes_ - 1);
|
||||
SetStatus("%d key frames", keyframes_);
|
||||
break;
|
||||
case '9':
|
||||
keyframes_ = keyframes_ + 1;
|
||||
SetStatus("%d key frames", keyframes_);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SystemFailure();
|
||||
}
|
||||
}
|
||||
|
||||
bool HasVideo(struct Frame* f) { return f->w < f->p; }
|
||||
bool HasPendingVideo(void) { return HasVideo(&vf_[0]) || HasVideo(&vf_[1]); }
|
||||
bool HasPendingAudio(void) { return playpid_ && audio_.i; }
|
||||
bool HasVideo(struct Frame* f) {
|
||||
return f->w < f->p;
|
||||
}
|
||||
|
||||
bool HasPendingVideo(void) {
|
||||
return HasVideo(&vf_[0]) || HasVideo(&vf_[1]);
|
||||
}
|
||||
|
||||
bool HasPendingAudio(void) {
|
||||
return playpid_ && audio_.i;
|
||||
}
|
||||
|
||||
struct Frame* FlipFrameBuffer(void) {
|
||||
frame_ = !frame_;
|
||||
|
@ -341,8 +487,10 @@ void TransmitVideo(void) {
|
|||
if (!HasVideo(f)) f = FlipFrameBuffer();
|
||||
if ((rc = write(STDOUT_FILENO, f->w, f->p - f->w)) != -1) {
|
||||
f->w += rc;
|
||||
} else {
|
||||
SystemFailure();
|
||||
} else if (errno == EPIPE) {
|
||||
Exit(0);
|
||||
} else if (errno != EINTR) {
|
||||
Exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -353,19 +501,36 @@ void TransmitAudio(void) {
|
|||
rc /= sizeof(short);
|
||||
memmove(audio_.p, audio_.p + rc, (audio_.i - rc) * sizeof(short));
|
||||
audio_.i -= rc;
|
||||
} else {
|
||||
SystemFailure();
|
||||
} else if (errno == EPIPE) {
|
||||
Exit(0);
|
||||
} else if (errno != EINTR) {
|
||||
Exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void ScaleVideoFrameToTeletypewriter(void) {
|
||||
long y, x;
|
||||
GyaradosUint8(tyn_, txn_, R, DYN, DXN, pixels_[0], tyn_, txn_, DYN, DXN, 0,
|
||||
255, ssy_, ssx_, true);
|
||||
GyaradosUint8(tyn_, txn_, G, DYN, DXN, pixels_[1], tyn_, txn_, DYN, DXN, 0,
|
||||
255, ssy_, ssx_, true);
|
||||
GyaradosUint8(tyn_, txn_, B, DYN, DXN, pixels_[2], tyn_, txn_, DYN, DXN, 0,
|
||||
255, ssy_, ssx_, true);
|
||||
long y, x, yn, xn;
|
||||
yn = DYN, xn = DXN;
|
||||
while (HALF(yn) > tyn_ || HALF(xn) > txn_) {
|
||||
if (HALF(xn) > txn_) {
|
||||
Magikarp2xX(DYN, DXN, pixels_[0], yn, xn);
|
||||
Magikarp2xX(DYN, DXN, pixels_[1], yn, xn);
|
||||
Magikarp2xX(DYN, DXN, pixels_[2], yn, xn);
|
||||
xn = HALF(xn);
|
||||
}
|
||||
if (HALF(yn) > tyn_) {
|
||||
Magikarp2xY(DYN, DXN, pixels_[0], yn, xn);
|
||||
Magikarp2xY(DYN, DXN, pixels_[1], yn, xn);
|
||||
Magikarp2xY(DYN, DXN, pixels_[2], yn, xn);
|
||||
yn = HALF(yn);
|
||||
}
|
||||
}
|
||||
GyaradosUint8(tyn_, txn_, R, DYN, DXN, pixels_[0], tyn_, txn_, yn, xn, 0, 255,
|
||||
ssy_, ssx_, true);
|
||||
GyaradosUint8(tyn_, txn_, G, DYN, DXN, pixels_[1], tyn_, txn_, yn, xn, 0, 255,
|
||||
ssy_, ssx_, true);
|
||||
GyaradosUint8(tyn_, txn_, B, DYN, DXN, pixels_[2], tyn_, txn_, yn, xn, 0, 255,
|
||||
ssy_, ssx_, true);
|
||||
for (y = 0; y < tyn_; ++y) {
|
||||
for (x = 0; x < txn_; ++x) {
|
||||
ttyrgb_[y * txn_ + x] =
|
||||
|
@ -382,15 +547,10 @@ void KeyCountdown(struct Action* a) {
|
|||
}
|
||||
}
|
||||
|
||||
void DrainAndExit(void) {
|
||||
while (HasPendingVideo()) TransmitVideo();
|
||||
WriteStringNow("\r\n\e[0m\e[J");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void PollAndSynchronize(void) {
|
||||
struct pollfd fds[3];
|
||||
do {
|
||||
errno = 0;
|
||||
fds[0].fd = STDIN_FILENO;
|
||||
fds[0].events = POLLIN;
|
||||
fds[1].fd = HasPendingVideo() ? STDOUT_FILENO : -1;
|
||||
|
@ -402,10 +562,15 @@ void PollAndSynchronize(void) {
|
|||
if (fds[1].revents & (POLLOUT | POLLERR)) TransmitVideo();
|
||||
if (fds[2].revents & (POLLOUT | POLLERR)) TransmitAudio();
|
||||
} else if (errno != EINTR) {
|
||||
SystemFailure();
|
||||
Exit(1);
|
||||
}
|
||||
if (exited_) {
|
||||
DrainAndExit();
|
||||
if (drain_) {
|
||||
while (HasPendingVideo()) {
|
||||
TransmitVideo();
|
||||
}
|
||||
}
|
||||
Exit(0);
|
||||
}
|
||||
if (resized_) {
|
||||
resized_ = false;
|
||||
|
@ -429,6 +594,11 @@ void Raster(void) {
|
|||
f->p = f->w = f->mem;
|
||||
f->p = stpcpy(f->p, "\e[0m\e[H");
|
||||
f->p = ttyraster(f->p, ttyrgb_, tyn_, txn_, bg, fg);
|
||||
if (status_.wait) {
|
||||
status_.wait--;
|
||||
f->p = stpcpy(f->p, "\e[0m\e[H");
|
||||
f->p = stpcpy(f->p, status_.text);
|
||||
}
|
||||
CHECK_LT(f->p - f->mem, vtsize_);
|
||||
PollAndSynchronize();
|
||||
}
|
||||
|
@ -443,13 +613,8 @@ void FlushScanline(unsigned py) {
|
|||
}
|
||||
|
||||
static void PutPixel(unsigned px, unsigned py, unsigned pixel, int offset) {
|
||||
static bool once;
|
||||
static unsigned prev;
|
||||
unsigned rgb;
|
||||
if (!once) {
|
||||
InitPalette();
|
||||
once = true;
|
||||
}
|
||||
static unsigned prev;
|
||||
pixels_[0][py][px] = palette_[offset][prev % 64][pixel][2];
|
||||
pixels_[1][py][px] = palette_[offset][prev % 64][pixel][1];
|
||||
pixels_[2][py][px] = palette_[offset][prev % 64][pixel][0];
|
||||
|
@ -491,8 +656,12 @@ struct RegBit {
|
|||
data = (data & ~(mask << bitno)) | ((nbits > 1 ? v & mask : !!v) << bitno);
|
||||
return *this;
|
||||
}
|
||||
operator unsigned() const { return (data >> bitno) & mask; }
|
||||
RegBit& operator++() { return *this = *this + 1; }
|
||||
operator unsigned() const {
|
||||
return (data >> bitno) & mask;
|
||||
}
|
||||
RegBit& operator++() {
|
||||
return *this = *this + 1;
|
||||
}
|
||||
unsigned operator++(int) {
|
||||
unsigned r = *this;
|
||||
++*this;
|
||||
|
@ -602,8 +771,12 @@ bool intr = false;
|
|||
|
||||
template <bool write>
|
||||
u8 MemAccess(u16 addr, u8 v = 0);
|
||||
u8 RB(u16 addr) { return MemAccess<0>(addr); }
|
||||
u8 WB(u16 addr, u8 v) { return MemAccess<1>(addr, v); }
|
||||
u8 RB(u16 addr) {
|
||||
return MemAccess<0>(addr);
|
||||
}
|
||||
u8 WB(u16 addr, u8 v) {
|
||||
return MemAccess<1>(addr, v);
|
||||
}
|
||||
void Tick();
|
||||
|
||||
} // namespace CPU
|
||||
|
@ -922,8 +1095,8 @@ void RenderPixel() {
|
|||
|
||||
void ReadToolAssistedSpeedrunRobotKeys() {
|
||||
static FILE* fp;
|
||||
if (!fp && !isempty(inputfn)) {
|
||||
fp = fopen(inputfn, "rb");
|
||||
if (!fp && !isempty(inputfn_)) {
|
||||
fp = fopen(inputfn_, "rb");
|
||||
}
|
||||
if (fp) {
|
||||
static unsigned ctrlmask = 0;
|
||||
|
@ -1039,7 +1212,9 @@ bool ChannelsEnabled[5];
|
|||
bool PeriodicIRQ;
|
||||
bool DMC_IRQ;
|
||||
|
||||
bool count(int& v, int reset) { return --v < 0 ? (v = reset), true : false; }
|
||||
bool count(int& v, int reset) {
|
||||
return --v < 0 ? (v = reset), true : false;
|
||||
}
|
||||
|
||||
struct channel {
|
||||
int length_counter, linear_counter, address, envelope;
|
||||
|
@ -1119,9 +1294,11 @@ struct channel {
|
|||
// Note: Re-entrant! But not recursive, because even
|
||||
// the shortest wave length is greater than the read time.
|
||||
// TODO: proper clock
|
||||
if (ch.reg.WaveLength > 20)
|
||||
for (unsigned t = 0; t < 3; ++t)
|
||||
CPU::RB(u16(ch.address) | 0x8000); // timing
|
||||
if (ch.reg.WaveLength > 20) {
|
||||
for (unsigned t = 0; t < 3; ++t) {
|
||||
CPU::RB(u16(ch.address) | 0x8000); // timing
|
||||
}
|
||||
}
|
||||
ch.hold = CPU::RB(u16(ch.address++) | 0x8000); // Fetch byte
|
||||
ch.phase = 8;
|
||||
--ch.length_counter;
|
||||
|
@ -1357,13 +1534,19 @@ union { /* Status flags: */
|
|||
RegBit<7> N; // negative
|
||||
} P;
|
||||
|
||||
u16 wrap(u16 oldaddr, u16 newaddr) { return (oldaddr & 0xFF00) + u8(newaddr); }
|
||||
u16 wrap(u16 oldaddr, u16 newaddr) {
|
||||
return (oldaddr & 0xFF00) + u8(newaddr);
|
||||
}
|
||||
void Misfire(u16 old, u16 addr) {
|
||||
u16 q = wrap(old, addr);
|
||||
if (q != addr) RB(q);
|
||||
}
|
||||
u8 Pop() { return RB(0x100 | u8(++S)); }
|
||||
void Push(u8 v) { WB(0x100 | u8(S--), v); }
|
||||
u8 Pop() {
|
||||
return RB(0x100 | u8(++S));
|
||||
}
|
||||
void Push(u8 v) {
|
||||
WB(0x100 | u8(S--), v);
|
||||
}
|
||||
|
||||
template <u16 op> // Execute a single CPU instruction, defined by opcode "op".
|
||||
void Ins() { // With template magic, the compiler will literally synthesize
|
||||
|
@ -1503,47 +1686,59 @@ void Op() {
|
|||
|
||||
} // namespace CPU
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
char* GetLine(void) {
|
||||
static char* line;
|
||||
static size_t linesize;
|
||||
if (getline(&line, &linesize, stdin) > 0) {
|
||||
return chomp(line);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int PlayGame(const char* romfile, const char* opt_tasfile) {
|
||||
FILE* fp;
|
||||
inputfn_ = opt_tasfile;
|
||||
|
||||
if (argc <= 1 || (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-?") == 0 ||
|
||||
strcmp(argv[1], "--help") == 0)) {
|
||||
fprintf(stderr, "%s%s%s\n", "Usage: ", argv[0], " ROM [FMV]");
|
||||
exit(1);
|
||||
if (!(fp = fopen(romfile, "rb"))) {
|
||||
fprintf(stderr, "%s%s\n", "failed to open: ", romfile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Open the ROM file specified on commandline
|
||||
fp = fopen(argv[1], "rb"); /* your .nes file */
|
||||
inputfn = argc >= 3 ? argv[2] : NULL; /* some tas thing */
|
||||
|
||||
if (!fp) {
|
||||
fprintf(stderr, "%s%s\n", "not a nes rom file: ", argv[1]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if (!(fgetc(fp) == 'N' && fgetc(fp) == 'E' && fgetc(fp) == 'S' &&
|
||||
fgetc(fp) == CTRL('Z'))) {
|
||||
fprintf(stderr, "%s%s\n", "not a nes rom file: ", argv[1]);
|
||||
exit(3);
|
||||
fprintf(stderr, "%s%s\n", "not a nes rom file: ", romfile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
InitPalette();
|
||||
|
||||
// open speaker
|
||||
// todo: this needs plenty of work
|
||||
devnull_ = open("/dev/null", O_WRONLY);
|
||||
ffplay_ = commandvenv("FFPLAY", "ffplay");
|
||||
if (devnull_ != -1 && ffplay_) {
|
||||
if ((ffplay_ = commandvenv("FFPLAY", "ffplay"))) {
|
||||
const char* args[] = {
|
||||
"ffplay", "-nodisp", "-loglevel", "quiet", "-fflags", "nobuffer", "-ac",
|
||||
"1", "-ar", "1789773", "-f", "s16le", "pipe:", NULL,
|
||||
};
|
||||
TrySpeaker(ffplay_, (char* const*)args);
|
||||
} else {
|
||||
fputs("\nWARNING\n\
|
||||
\n\
|
||||
Need `ffplay` command to play audio\n\
|
||||
Try `sudo apt install ffmpeg` on Linux\n\
|
||||
You can specify it on `PATH` or in `FFPLAY`\n\
|
||||
\n\
|
||||
Press enter to continue without sound: ",
|
||||
stdout);
|
||||
fflush(stdout);
|
||||
GetLine();
|
||||
}
|
||||
|
||||
// Read the ROM file header
|
||||
u8 rom16count = fgetc(fp);
|
||||
u8 vrom8count = fgetc(fp);
|
||||
u8 ctrlbyte = fgetc(fp);
|
||||
u8 mappernum = fgetc(fp) | (ctrlbyte >> 4);
|
||||
u8 mappernum = fgetc(fp) | ctrlbyte >> 4;
|
||||
|
||||
fgetc(fp);
|
||||
fgetc(fp);
|
||||
|
@ -1578,3 +1773,96 @@ int main(int argc, char** argv) {
|
|||
// Run the CPU until the program is killed.
|
||||
for (;;) CPU::Op();
|
||||
}
|
||||
|
||||
noreturn void PrintUsage(int rc, FILE* f) {
|
||||
fprintf(f, "%s%s%s", "Usage: ", program_invocation_name, USAGE);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void GetOpts(int argc, char* argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "?hAxt134")) != -1) {
|
||||
switch (opt) {
|
||||
case 'A':
|
||||
quant_ = kTtyQuantAnsi;
|
||||
break;
|
||||
case 'x':
|
||||
quant_ = kTtyQuantXterm256;
|
||||
break;
|
||||
case 't':
|
||||
quant_ = kTtyQuantTrue;
|
||||
break;
|
||||
case '1':
|
||||
artifacts_ = !artifacts_;
|
||||
break;
|
||||
case '3':
|
||||
blocks_ = kTtyBlocksCp437;
|
||||
break;
|
||||
case '4':
|
||||
blocks_ = kTtyBlocksUnicode;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t FindZipGames(void) {
|
||||
char* name;
|
||||
struct Zipos* zipos;
|
||||
size_t i, cf, namesize;
|
||||
if ((zipos = __zipos_get())) {
|
||||
for (i = 0, cf = ZIP_CDIR_OFFSET(zipos->cdir);
|
||||
i < ZIP_CDIR_RECORDS(zipos->cdir);
|
||||
++i, cf += ZIP_CFILE_HDRSIZE(zipos->map + cf)) {
|
||||
if ((name = strndup(ZIP_CFILE_NAME(zipos->map + cf),
|
||||
ZIP_CFILE_NAMESIZE(zipos->map + cf))) &&
|
||||
endswith(name, ".nes")) {
|
||||
APPEND(&zipgames_.p, &zipgames_.i, &zipgames_.n, &name);
|
||||
} else {
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return zipgames_.i;
|
||||
}
|
||||
|
||||
int SelectGameFromZip(void) {
|
||||
int i, rc;
|
||||
char *line, *uri;
|
||||
fputs("\nCOSMOPOLITAN NESEMU1\n\n", stdout);
|
||||
for (i = 0; i < zipgames_.i; ++i) {
|
||||
printf(" [%d] %s\n", i, zipgames_.p[i]);
|
||||
}
|
||||
fputs("\nPlease choose a game (or CTRL-C to quit) [default 0]: ", stdout);
|
||||
fflush(stdout);
|
||||
rc = 0;
|
||||
if ((line = GetLine())) {
|
||||
i = MAX(0, MIN(zipgames_.i - 1, atoi(line)));
|
||||
uri = xasprintf("zip:%s", zipgames_.p[i]);
|
||||
rc = PlayGame(uri, NULL);
|
||||
free(uri);
|
||||
} else {
|
||||
fputs("\n", stdout);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int rc;
|
||||
GetOpts(argc, argv);
|
||||
if (optind + 1 < argc) {
|
||||
rc = PlayGame(argv[optind], argv[optind + 1]);
|
||||
} else if (optind < argc) {
|
||||
rc = PlayGame(argv[optind], NULL);
|
||||
} else {
|
||||
if (!FindZipGames()) {
|
||||
PrintUsage(0, stderr);
|
||||
}
|
||||
rc = SelectGameFromZip();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -50,19 +50,22 @@ const struct AuxiliaryValue {
|
|||
};
|
||||
|
||||
int main(int argc, char *argv[], char **envp) {
|
||||
long key;
|
||||
unsigned i;
|
||||
unsigned long val;
|
||||
char fmt[64], **env;
|
||||
printf("\nArguments:\n");
|
||||
for (unsigned i = 0; i < argc; ++i) {
|
||||
for (i = 0; i < argc; ++i) {
|
||||
printf(" ☼ %s\n", argv[i]);
|
||||
}
|
||||
printf("\nEnvironment:\n");
|
||||
for (char **env = envp; *env; ++env) {
|
||||
for (env = envp; *env; ++env) {
|
||||
printf(" ☼ %s\n", *env);
|
||||
}
|
||||
printf("\nAuxiliary Values:\n");
|
||||
for (unsigned i = 0; i < ARRAYLEN(kAuxiliaryValues); ++i) {
|
||||
long key = *kAuxiliaryValues[i].id;
|
||||
unsigned long val = getauxval(key);
|
||||
char fmt[64];
|
||||
for (i = 0; i < ARRAYLEN(kAuxiliaryValues); ++i) {
|
||||
key = *kAuxiliaryValues[i].id;
|
||||
val = getauxval(key);
|
||||
printf(PROGN(stpcpy(stpcpy(stpcpy(fmt, "%16s[%p] = "),
|
||||
kAuxiliaryValues[i].fmt),
|
||||
" # %s\n"),
|
||||
|
|
|
@ -431,40 +431,40 @@
|
|||
/*
|
||||
* Evaluate a command.
|
||||
*/
|
||||
#define ALIASCMD (builtincmd + 3)
|
||||
#define BGCMD (builtincmd + 4)
|
||||
#define BREAKCMD (builtincmd + 5)
|
||||
#define CDCMD (builtincmd + 6)
|
||||
#define COMMANDCMD (builtincmd + 8)
|
||||
#define DOTCMD (builtincmd + 0)
|
||||
#define ECHOCMD (builtincmd + 10)
|
||||
#define EVALCMD (builtincmd + 11)
|
||||
#define EXECCMD (builtincmd + 12)
|
||||
#define EXITCMD (builtincmd + 13)
|
||||
#define EXPORTCMD (builtincmd + 14)
|
||||
#define FALSECMD (builtincmd + 15)
|
||||
#define FGCMD (builtincmd + 16)
|
||||
#define GETOPTSCMD (builtincmd + 17)
|
||||
#define HASHCMD (builtincmd + 18)
|
||||
#define JOBSCMD (builtincmd + 19)
|
||||
#define KILLCMD (builtincmd + 20)
|
||||
#define LOCALCMD (builtincmd + 21)
|
||||
#define PRINTFCMD (builtincmd + 22)
|
||||
#define PWDCMD (builtincmd + 23)
|
||||
#define READCMD (builtincmd + 24)
|
||||
#define RETURNCMD (builtincmd + 26)
|
||||
#define SETCMD (builtincmd + 27)
|
||||
#define SHIFTCMD (builtincmd + 28)
|
||||
#define TESTCMD (builtincmd + 2)
|
||||
#define TIMESCMD (builtincmd + 30)
|
||||
#define TRAPCMD (builtincmd + 31)
|
||||
#define TRUECMD (builtincmd + 1)
|
||||
#define TYPECMD (builtincmd + 33)
|
||||
#define ULIMITCMD (builtincmd + 34)
|
||||
#define UMASKCMD (builtincmd + 35)
|
||||
#define UNALIASCMD (builtincmd + 36)
|
||||
#define UNSETCMD (builtincmd + 37)
|
||||
#define WAITCMD (builtincmd + 38)
|
||||
#define ALIASCMD (kBuiltinCmds + 3)
|
||||
#define BGCMD (kBuiltinCmds + 4)
|
||||
#define BREAKCMD (kBuiltinCmds + 5)
|
||||
#define CDCMD (kBuiltinCmds + 6)
|
||||
#define COMMANDCMD (kBuiltinCmds + 8)
|
||||
#define DOTCMD (kBuiltinCmds + 0)
|
||||
#define ECHOCMD (kBuiltinCmds + 10)
|
||||
#define EVALCMD (kBuiltinCmds + 11)
|
||||
#define EXECCMD (kBuiltinCmds + 12)
|
||||
#define EXITCMD (kBuiltinCmds + 13)
|
||||
#define EXPORTCMD (kBuiltinCmds + 14)
|
||||
#define FALSECMD (kBuiltinCmds + 15)
|
||||
#define FGCMD (kBuiltinCmds + 16)
|
||||
#define GETOPTSCMD (kBuiltinCmds + 17)
|
||||
#define HASHCMD (kBuiltinCmds + 18)
|
||||
#define JOBSCMD (kBuiltinCmds + 19)
|
||||
#define KILLCMD (kBuiltinCmds + 20)
|
||||
#define LOCALCMD (kBuiltinCmds + 21)
|
||||
#define PRINTFCMD (kBuiltinCmds + 22)
|
||||
#define PWDCMD (kBuiltinCmds + 23)
|
||||
#define READCMD (kBuiltinCmds + 24)
|
||||
#define RETURNCMD (kBuiltinCmds + 26)
|
||||
#define SETCMD (kBuiltinCmds + 27)
|
||||
#define SHIFTCMD (kBuiltinCmds + 28)
|
||||
#define TESTCMD (kBuiltinCmds + 2)
|
||||
#define TIMESCMD (kBuiltinCmds + 30)
|
||||
#define TRAPCMD (kBuiltinCmds + 31)
|
||||
#define TRUECMD (kBuiltinCmds + 1)
|
||||
#define TYPECMD (kBuiltinCmds + 33)
|
||||
#define ULIMITCMD (kBuiltinCmds + 34)
|
||||
#define UMASKCMD (kBuiltinCmds + 35)
|
||||
#define UNALIASCMD (kBuiltinCmds + 36)
|
||||
#define UNSETCMD (kBuiltinCmds + 37)
|
||||
#define WAITCMD (kBuiltinCmds + 38)
|
||||
|
||||
#define BUILTIN_SPECIAL 0x1
|
||||
#define BUILTIN_REGULAR 0x2
|
||||
|
@ -620,12 +620,12 @@
|
|||
#define octtobin(c) ((c) - '0')
|
||||
#define scopy(s1, s2) ((void)strcpy(s2, s1))
|
||||
|
||||
#define TRACE(param)
|
||||
/* #define TRACE(param) \ */
|
||||
/* do { \ */
|
||||
/* printf("TRACE: "); \ */
|
||||
/* printf param; \ */
|
||||
/* } while (0) */
|
||||
/* #define TRACE(param) */
|
||||
#define TRACE(param) \
|
||||
do { \
|
||||
printf("TRACE: "); \
|
||||
printf param; \
|
||||
} while (0)
|
||||
|
||||
#define TRACEV(param)
|
||||
#define digit_val(c) ((c) - '0')
|
||||
|
@ -1184,13 +1184,16 @@ static const char dolatstr[] = {CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUO
|
|||
/* Some macros depend on the order, add new variables to the end. */
|
||||
static void changepath(const char *);
|
||||
static void getoptsreset(const char *);
|
||||
static struct Var varinit[] = {{0, VSTRFIXED | VTEXTFIXED, defifsvar, 0},
|
||||
{0, VSTRFIXED | VTEXTFIXED, defpathvar, changepath},
|
||||
{0, VSTRFIXED | VTEXTFIXED, "PS1=$ ", 0},
|
||||
{0, VSTRFIXED | VTEXTFIXED, "PS2=> ", 0},
|
||||
{0, VSTRFIXED | VTEXTFIXED, "PS4=+ ", 0},
|
||||
{0, VSTRFIXED | VTEXTFIXED, defoptindvar, getoptsreset},
|
||||
{0, VSTRFIXED | VTEXTFIXED, linenovar, 0}};
|
||||
|
||||
static struct Var varinit[] = {
|
||||
{0, VSTRFIXED | VTEXTFIXED, defifsvar, 0},
|
||||
{0, VSTRFIXED | VTEXTFIXED, defpathvar, changepath},
|
||||
{0, VSTRFIXED | VTEXTFIXED, "PS1=$ ", 0},
|
||||
{0, VSTRFIXED | VTEXTFIXED, "PS2=> ", 0},
|
||||
{0, VSTRFIXED | VTEXTFIXED, "PS4=+ ", 0},
|
||||
{0, VSTRFIXED | VTEXTFIXED, defoptindvar, getoptsreset},
|
||||
{0, VSTRFIXED | VTEXTFIXED, linenovar, 0},
|
||||
};
|
||||
|
||||
static const char kPrec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = {
|
||||
#define ARITH_PRECEDENCE(OP, PREC) [OP - ARITH_BINOP_MIN] = PREC
|
||||
|
@ -1308,7 +1311,8 @@ static const char sqsyntax[] = {
|
|||
CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD,
|
||||
CCTL, CCTL, CCTL, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD,
|
||||
CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD,
|
||||
CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CCTL, CWORD};
|
||||
CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CCTL, CWORD,
|
||||
};
|
||||
|
||||
/* syntax table used when in arithmetic */
|
||||
static const char arisyntax[] = {
|
||||
|
@ -1331,7 +1335,8 @@ static const char arisyntax[] = {
|
|||
CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD,
|
||||
CWORD, CBACK, CWORD, CWORD, CWORD, CBQUOTE, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD,
|
||||
CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD,
|
||||
CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CENDVAR, CWORD, CWORD};
|
||||
CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CENDVAR, CWORD, CWORD,
|
||||
};
|
||||
|
||||
/* character classification table */
|
||||
static const char is_type[] /* clang-format off */ = {
|
||||
|
@ -1405,20 +1410,47 @@ static int unaliascmd();
|
|||
static int unsetcmd();
|
||||
static int waitcmd();
|
||||
|
||||
static const struct builtincmd builtincmd[] = {
|
||||
{".", dotcmd, 3}, {":", truecmd, 3}, {"[", testcmd, 0},
|
||||
{"alias", aliascmd, 6}, {"bg", bgcmd, 2}, {"break", breakcmd, 3},
|
||||
{"cd", cdcmd, 2}, {"chdir", cdcmd, 0}, {"command", commandcmd, 2},
|
||||
{"continue", breakcmd, 3}, {"echo", echocmd, 0}, {"eval", NULL, 3},
|
||||
{"exec", execcmd, 3}, {"exit", exitcmd, 3}, {"export", exportcmd, 7},
|
||||
{"false", falsecmd, 2}, {"fg", fgcmd, 2}, {"getopts", getoptscmd, 2},
|
||||
{"hash", hashcmd, 2}, {"jobs", jobscmd, 2}, {"kill", killcmd, 2},
|
||||
{"local", localcmd, 7}, {"printf", printfcmd, 0}, {"pwd", pwdcmd, 2},
|
||||
{"read", readcmd, 2}, {"readonly", exportcmd, 7}, {"return", returncmd, 3},
|
||||
{"set", setcmd, 3}, {"shift", shiftcmd, 3}, {"test", testcmd, 0},
|
||||
{"times", timescmd, 3}, {"trap", trapcmd, 3}, {"true", truecmd, 2},
|
||||
{"type", typecmd, 2}, {"ulimit", ulimitcmd, 2}, {"umask", umaskcmd, 2},
|
||||
{"unalias", unaliascmd, 2}, {"unset", unsetcmd, 3}, {"wait", waitcmd, 2}};
|
||||
static const struct builtincmd kBuiltinCmds[] = {
|
||||
{".", dotcmd, 3}, //
|
||||
{":", truecmd, 3}, //
|
||||
{"[", testcmd, 0}, //
|
||||
{"alias", aliascmd, 6}, //
|
||||
{"bg", bgcmd, 2}, //
|
||||
{"break", breakcmd, 3}, //
|
||||
{"cd", cdcmd, 2}, //
|
||||
{"chdir", cdcmd, 0}, //
|
||||
{"command", commandcmd, 2}, //
|
||||
{"continue", breakcmd, 3}, //
|
||||
{"echo", echocmd, 0}, //
|
||||
{"eval", NULL, 3}, //
|
||||
{"exec", execcmd, 3}, //
|
||||
{"exit", exitcmd, 3}, //
|
||||
{"export", exportcmd, 7}, //
|
||||
{"false", falsecmd, 2}, //
|
||||
{"fg", fgcmd, 2}, //
|
||||
{"getopts", getoptscmd, 2}, //
|
||||
{"hash", hashcmd, 2}, //
|
||||
{"jobs", jobscmd, 2}, //
|
||||
{"kill", killcmd, 2}, //
|
||||
{"local", localcmd, 7}, //
|
||||
{"printf", printfcmd, 0}, //
|
||||
{"pwd", pwdcmd, 2}, //
|
||||
{"read", readcmd, 2}, //
|
||||
{"readonly", exportcmd, 7}, //
|
||||
{"return", returncmd, 3}, //
|
||||
{"set", setcmd, 3}, //
|
||||
{"shift", shiftcmd, 3}, //
|
||||
{"test", testcmd, 0}, //
|
||||
{"times", timescmd, 3}, //
|
||||
{"trap", trapcmd, 3}, //
|
||||
{"true", truecmd, 2}, //
|
||||
{"type", typecmd, 2}, //
|
||||
{"ulimit", ulimitcmd, 2}, //
|
||||
{"umask", umaskcmd, 2}, //
|
||||
{"unalias", unaliascmd, 2}, //
|
||||
{"unset", unsetcmd, 3}, //
|
||||
{"wait", waitcmd, 2}, //
|
||||
};
|
||||
|
||||
enum token {
|
||||
EOI,
|
||||
|
@ -2115,7 +2147,7 @@ static int olderf(const char *, const char *);
|
|||
static int64_t openhere(union node *);
|
||||
static int openredirect(union node *);
|
||||
static int options(int);
|
||||
static int padvance_magic(const char **path, const char *name, int magic);
|
||||
static int padvance_magic(const char **, const char *, int);
|
||||
static int patmatch(char *, const char *);
|
||||
static int peektoken(void);
|
||||
static int pgetc(void);
|
||||
|
@ -2882,7 +2914,7 @@ step6:
|
|||
goto docd;
|
||||
err:
|
||||
sh_error("can't cd to %s", dest);
|
||||
/* NOTREACHED */
|
||||
unreachable;
|
||||
out:
|
||||
if (flags & CD_PRINT) out1fmt(snlfmt, curdir);
|
||||
return 0;
|
||||
|
@ -3446,7 +3478,7 @@ static void evalbackcmd(union node *n, struct backcmd *result) {
|
|||
}
|
||||
ifsfree();
|
||||
evaltreenr(n, EV_EXIT);
|
||||
/* NOTREACHED */
|
||||
unreachable;
|
||||
}
|
||||
close(pip[1]);
|
||||
result->fd = pip[0];
|
||||
|
@ -3629,7 +3661,7 @@ static int evalcommand(union node *cmd, int flags) {
|
|||
break;
|
||||
}
|
||||
shellexec(argv, path, cmdentry.u.index);
|
||||
/* NOTREACHED */
|
||||
unreachable;
|
||||
case CMDBUILTIN:
|
||||
if (evalbltin(cmdentry.u.cmd, argc, argv, flags) &&
|
||||
!(exception == EXERROR && spclbltin <= 0)) {
|
||||
|
@ -3742,9 +3774,11 @@ funcdone:
|
|||
*/
|
||||
static void prehash(union node *n) {
|
||||
struct cmdentry entry;
|
||||
if (n->type == NCMD && n->ncmd.args)
|
||||
if (goodname(n->ncmd.args->narg.text))
|
||||
if (n->type == NCMD && n->ncmd.args) {
|
||||
if (goodname(n->ncmd.args->narg.text)) {
|
||||
find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
|
@ -4014,10 +4048,8 @@ static void readcmdfile(char *name) {
|
|||
* Search the table of builtin commands.
|
||||
*/
|
||||
static struct builtincmd *find_builtin(const char *name) {
|
||||
struct builtincmd *bp;
|
||||
bp = bsearch(&name, builtincmd, sizeof(builtincmd) / sizeof(builtincmd[0]), sizeof(builtincmd[0]),
|
||||
pstrcmp);
|
||||
return bp;
|
||||
return bsearch(&name, kBuiltinCmds, sizeof(kBuiltinCmds) / sizeof(kBuiltinCmds[0]),
|
||||
sizeof(kBuiltinCmds[0]), pstrcmp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4025,15 +4057,11 @@ static struct builtincmd *find_builtin(const char *name) {
|
|||
* change the shellexec routine as well.
|
||||
*/
|
||||
static void find_command(char *name, struct cmdentry *entry, int act, const char *path) {
|
||||
struct tblentry *cmdp;
|
||||
int idx;
|
||||
int prev;
|
||||
char *fullname;
|
||||
struct stat statb;
|
||||
int e;
|
||||
int updatetbl;
|
||||
struct tblentry *cmdp;
|
||||
struct builtincmd *bcmd;
|
||||
int len;
|
||||
int e, bit, idx, prev, updatetbl, len;
|
||||
/* If name contains a slash, don't use PATH or hash table */
|
||||
if (strchr(name, '/') != NULL) {
|
||||
entry->u.index = -1;
|
||||
|
@ -4050,7 +4078,6 @@ static void find_command(char *name, struct cmdentry *entry, int act, const char
|
|||
if (!updatetbl) act |= DO_ALTPATH;
|
||||
/* If name is in the table, check answer will be ok */
|
||||
if ((cmdp = cmdlookup(name, 0)) != NULL) {
|
||||
int bit;
|
||||
switch (cmdp->cmdtype) {
|
||||
default:
|
||||
case CMDNORMAL:
|
||||
|
@ -4067,9 +4094,10 @@ static void find_command(char *name, struct cmdentry *entry, int act, const char
|
|||
if (act & bit & DO_REGBLTIN) goto fail;
|
||||
updatetbl = 0;
|
||||
cmdp = NULL;
|
||||
} else if (cmdp->rehash == 0)
|
||||
} else if (cmdp->rehash == 0) {
|
||||
/* if not invalidated by cd, we're done */
|
||||
goto success;
|
||||
}
|
||||
}
|
||||
/* If %builtin not in path, check for builtin next */
|
||||
bcmd = find_builtin(name);
|
||||
|
@ -4744,7 +4772,7 @@ static void expbackq(union node *cmd, int flag) {
|
|||
recordregion(startloc, dest - (char *)stackblock(), 0);
|
||||
}
|
||||
TRACE(("evalbackq: size=%d: \"%.*s\"\n", (dest - (char *)stackblock()) - startloc,
|
||||
(dest - (char *)stackblock()) - startloc, stackblock() + startloc));
|
||||
(dest - (char *)stackblock()) - startloc, (char *)stackblock() + startloc));
|
||||
out:
|
||||
argbackq = argbackq->next;
|
||||
}
|
||||
|
@ -4822,7 +4850,7 @@ static char *subevalvar(char *start, char *str, int strloc, int startloc, int va
|
|||
goto out;
|
||||
case VSQUESTION:
|
||||
varunset(start, str, startp, varflags);
|
||||
/* NOTREACHED */
|
||||
unreachable;
|
||||
}
|
||||
subtype -= VSTRIMRIGHT;
|
||||
rmesc = startp;
|
||||
|
@ -6450,7 +6478,7 @@ static void forkparent(struct job *jp, union node *n, int mode, int pid) {
|
|||
TRACE(("Fork failed, errno=%d", errno));
|
||||
if (jp) freejob(jp);
|
||||
sh_error("Cannot fork");
|
||||
/* NOTREACHED */
|
||||
unreachable;
|
||||
}
|
||||
TRACE(("In parent shell: child = %d\n", pid));
|
||||
if (!jp) return;
|
||||
|
@ -6480,10 +6508,11 @@ static int forkshell(struct job *jp, union node *n, int mode) {
|
|||
int pid;
|
||||
TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
|
||||
pid = fork();
|
||||
if (pid == 0)
|
||||
if (pid == 0) {
|
||||
forkchild(jp, n, mode);
|
||||
else
|
||||
} else {
|
||||
forkparent(jp, n, mode, pid);
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
@ -6498,7 +6527,7 @@ static struct job *vforkexec(union node *n, char **argv, const char *path, int i
|
|||
forkchild(jp, n, FORK_FG);
|
||||
sigclearmask();
|
||||
shellexec(argv, path, idx);
|
||||
/* NOTREACHED */
|
||||
unreachable;
|
||||
}
|
||||
vforked = 0;
|
||||
sigclearmask();
|
||||
|
@ -7355,7 +7384,7 @@ static void setoption(int flag, int val) {
|
|||
return;
|
||||
}
|
||||
sh_error("Illegal option -%c", flag);
|
||||
/* NOTREACHED */
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -7799,7 +7828,7 @@ static union node *command(void) {
|
|||
switch (readtoken()) {
|
||||
default:
|
||||
synexpect(-1);
|
||||
/* NOTREACHED */
|
||||
unreachable;
|
||||
case TIF:
|
||||
n1 = (union node *)stalloc(sizeof(struct nif));
|
||||
n1->type = NIF;
|
||||
|
@ -9998,10 +10027,10 @@ static void initvar(void) {
|
|||
vp->next = *vpp;
|
||||
*vpp = vp;
|
||||
} while (++vp < end);
|
||||
/*
|
||||
* PS1 depends on uid
|
||||
*/
|
||||
if (!geteuid()) vps1.text = "PS1=# ";
|
||||
/* PS1 depends on uid */
|
||||
if (!geteuid()) {
|
||||
vps1.text = "PS1=# ";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -10749,7 +10778,7 @@ static int exitcmd(int argc, char **argv) {
|
|||
exraise(EXEXIT);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Main routine. We initialize things, parse the arguments, execute
|
||||
* profiles if we're a login shell, and then call cmdloop to execute
|
||||
* commands. The setjmp call sets up the location to jump to when an
|
||||
|
|
|
@ -39,7 +39,7 @@ int main(int argc, char *argv[argc]) {
|
|||
errno = err;
|
||||
break;
|
||||
}
|
||||
l = xedd.decoded_length;
|
||||
l = xedd.length;
|
||||
if (l <= 0 || l > i) abort();
|
||||
for (j = 0; j < l; ++j) {
|
||||
if (fputhex(buf[j], stdout) == -1) {
|
||||
|
|
|
@ -48,7 +48,3 @@ OVERVIEW
|
|||
be compared to something more along the lines of, "the Russians
|
||||
just used a pencil to write in space", versus spending millions
|
||||
researching a pen like NASA.
|
||||
|
||||
One cost worth noting, concerning stateless API translation, is
|
||||
file descriptors needed to change from `int` to `int64_t`, thus
|
||||
requiring a certain degree of added care when porting software.
|
||||
|
|
|
@ -18,9 +18,8 @@ void qsort(void *, size_t, size_t, int (*)(const void *, const void *))
|
|||
void qsort_r(void *, size_t, size_t,
|
||||
int cmp(const void *, const void *, void *), void *arg)
|
||||
paramsnonnull((1, 4));
|
||||
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;
|
||||
int tarjan(int, const int (*)[2], int, int[], int[], int *)
|
||||
paramsnonnull((2, 4)) nocallback nothrow;
|
||||
|
||||
void *memmem(const void *, size_t, const void *, size_t)
|
||||
paramsnonnull() nothrow nocallback nosideeffect;
|
||||
|
|
|
@ -19,6 +19,11 @@ COSMOPOLITAN_C_START_
|
|||
size_t SizE = sizeof(*Item); \
|
||||
size_t Count = (COUNT); \
|
||||
ssize_t Entry = -1; \
|
||||
/* NOTE: We use `<` to guarantee one additional slot */ \
|
||||
/* grow() will memset(0) extended memory, thus */ \
|
||||
/* you get a nul-terminator for free sometimes */ \
|
||||
/* the exception is if you list.i=0 and re-use */ \
|
||||
/* so you need concat(...); list.p[list.i++]=0 */ \
|
||||
if (*ListI + Count < *ListN || grow(ListP, ListN, SizE, Count)) { \
|
||||
memcpy(&(*ListP)[*ListI], Item, (SizE) * (Count)); \
|
||||
Entry = *ListI; \
|
||||
|
|
|
@ -71,25 +71,25 @@ static void cycle(size_t width, unsigned char *ar[], size_t n) {
|
|||
|
||||
forceinline void shl(unsigned p[2], size_t n) {
|
||||
assert(n > 0);
|
||||
if (n >= 8 * sizeof(unsigned)) {
|
||||
n -= 8 * sizeof(unsigned);
|
||||
if (n >= CHAR_BIT * sizeof(unsigned)) {
|
||||
n -= CHAR_BIT * sizeof(unsigned);
|
||||
p[1] = p[0];
|
||||
p[0] = 0;
|
||||
}
|
||||
p[1] <<= n;
|
||||
p[1] |= p[0] >> (sizeof(unsigned) * 8 - n);
|
||||
p[1] |= p[0] >> (sizeof(unsigned) * CHAR_BIT - n);
|
||||
p[0] <<= n;
|
||||
}
|
||||
|
||||
forceinline void shr(unsigned p[2], size_t n) {
|
||||
assert(n > 0);
|
||||
if (n >= 8 * sizeof(unsigned)) {
|
||||
n -= 8 * sizeof(unsigned);
|
||||
if (n >= CHAR_BIT * sizeof(unsigned)) {
|
||||
n -= CHAR_BIT * sizeof(unsigned);
|
||||
p[0] = p[1];
|
||||
p[1] = 0;
|
||||
}
|
||||
p[0] >>= n;
|
||||
p[0] |= p[1] << (sizeof(unsigned) * 8 - n);
|
||||
p[0] |= p[1] << (sizeof(unsigned) * CHAR_BIT - n);
|
||||
p[1] >>= n;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#undef strlen
|
||||
#undef replacestr
|
||||
#define replacestr replacestr16
|
||||
#define char char16_t
|
||||
#define strlen strlen16
|
||||
#include "libc/alg/replacestr.c"
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
||||
/**
|
||||
|
@ -33,79 +33,77 @@
|
|||
* topological sorting as a byproduct.” ──D.E. Knuth
|
||||
*/
|
||||
|
||||
struct Vertex {
|
||||
uint32_t Vi;
|
||||
uint32_t Ei;
|
||||
uint32_t index;
|
||||
uint32_t lowlink;
|
||||
bool onstack;
|
||||
bool selfreferential;
|
||||
};
|
||||
|
||||
struct TarjanStack {
|
||||
size_t i;
|
||||
size_t n;
|
||||
uint32_t *p;
|
||||
};
|
||||
|
||||
struct Tarjan {
|
||||
uint32_t Vn;
|
||||
uint32_t En;
|
||||
struct Vertex *V;
|
||||
const uint32_t (*E)[2];
|
||||
uint32_t *R;
|
||||
uint32_t *C;
|
||||
uint32_t Ci;
|
||||
uint32_t Ri;
|
||||
uint32_t index;
|
||||
struct TarjanStack S;
|
||||
int Vn, En, Ci, Ri, *R, *C, index;
|
||||
const int (*E)[2];
|
||||
struct Vertex {
|
||||
int Vi;
|
||||
int Ei;
|
||||
int index;
|
||||
int lowlink;
|
||||
bool onstack;
|
||||
bool selfreferential;
|
||||
} * V;
|
||||
struct TarjanStack {
|
||||
int i;
|
||||
int n;
|
||||
int *p;
|
||||
} S;
|
||||
};
|
||||
|
||||
static uint32_t TarjanPush(struct TarjanStack *st, uint32_t Vi) {
|
||||
if (st->i < st->n || grow(&st->p, &st->n, sizeof(uint32_t), 0)) {
|
||||
return (st->p[st->i++] = Vi);
|
||||
} else {
|
||||
return -1;
|
||||
static bool TarjanPush(struct Tarjan *t, int v) {
|
||||
int *q;
|
||||
assert(t->S.i >= 0);
|
||||
assert(t->S.n >= 0);
|
||||
assert(0 <= v && v < t->Vn);
|
||||
if (t->S.i == t->S.n) {
|
||||
if ((q = realloc(t->S.p, (t->S.n + (t->S.n >> 1) + 8) * sizeof(*t->S.p)))) {
|
||||
t->S.p = q;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
t->S.p[t->S.i++] = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t TarjanPop(struct TarjanStack *st) {
|
||||
assert(st->i != 0);
|
||||
return st->p[--st->i];
|
||||
static int TarjanPop(struct Tarjan *t) {
|
||||
assert(t->S.i > 0);
|
||||
return t->S.p[--t->S.i];
|
||||
}
|
||||
|
||||
static int TarjanConnect(struct Tarjan **tj, uint32_t Vi) {
|
||||
struct Vertex *v = &(*tj)->V[Vi];
|
||||
v->index = (*tj)->index;
|
||||
v->lowlink = (*tj)->index;
|
||||
v->onstack = true;
|
||||
(*tj)->index++;
|
||||
if (TarjanPush(&(*tj)->S, Vi) == -1) return -1;
|
||||
uint32_t fs = (*tj)->V[Vi].Ei;
|
||||
static bool TarjanConnect(struct Tarjan *t, int v) {
|
||||
int fs, w, e;
|
||||
assert(0 <= v && v < t->Vn);
|
||||
t->V[v].index = t->index;
|
||||
t->V[v].lowlink = t->index;
|
||||
t->V[v].onstack = true;
|
||||
t->index++;
|
||||
if (!TarjanPush(t, v)) return false;
|
||||
fs = t->V[v].Ei;
|
||||
if (fs != -1) {
|
||||
for (uint32_t Ei = fs; Ei < (*tj)->En && Vi == (*tj)->E[Ei][0]; ++Ei) {
|
||||
struct Vertex *w = &(*tj)->V[(*tj)->E[Ei][1]];
|
||||
if (!w->index) {
|
||||
if (TarjanConnect(tj, w->Vi) == -1) return -1;
|
||||
v->lowlink = min(v->lowlink, w->lowlink);
|
||||
} else if (w->onstack) {
|
||||
v->lowlink = min(v->lowlink, w->index);
|
||||
for (e = fs; e < t->En && v == t->E[e][0]; ++e) {
|
||||
w = t->E[e][1];
|
||||
if (!t->V[w].index) {
|
||||
if (!TarjanConnect(t, t->V[w].Vi)) return false;
|
||||
t->V[v].lowlink = MIN(t->V[v].lowlink, t->V[w].lowlink);
|
||||
} else if (t->V[w].onstack) {
|
||||
t->V[v].lowlink = MIN(t->V[v].lowlink, t->V[w].index);
|
||||
}
|
||||
if (w == v) {
|
||||
w->selfreferential = true;
|
||||
t->V[w].selfreferential = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (v->lowlink == v->index) {
|
||||
struct Vertex *w;
|
||||
if (t->V[v].lowlink == t->V[v].index) {
|
||||
do {
|
||||
w = &(*tj)->V[TarjanPop(&(*tj)->S)];
|
||||
w->onstack = false;
|
||||
(*tj)->R[(*tj)->Ri++] = w->Vi;
|
||||
w = TarjanPop(t);
|
||||
t->V[w].onstack = false;
|
||||
t->R[t->Ri++] = t->V[w].Vi;
|
||||
} while (w != v);
|
||||
if ((*tj)->C) (*tj)->C[(*tj)->Ci++] = (*tj)->Ri;
|
||||
if (t->C) t->C[t->Ci++] = t->Ri;
|
||||
}
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,51 +131,53 @@ static int TarjanConnect(struct Tarjan **tj, uint32_t Vi) {
|
|||
* @error ENOMEM
|
||||
* @note Tarjan's Algorithm is O(|V|+|E|)
|
||||
*/
|
||||
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) {
|
||||
assert(edge_count <= INT_MAX);
|
||||
assert(vertex_count <= INT_MAX);
|
||||
for (unsigned i = 0; i < edge_count; ++i) {
|
||||
int tarjan(int vertex_count, const int (*edges)[2], int edge_count,
|
||||
int out_sorted[], int out_opt_components[],
|
||||
int *out_opt_componentcount) {
|
||||
int i, rc, v, e;
|
||||
struct Tarjan *t;
|
||||
assert(0 <= edge_count && edge_count <= INT_MAX);
|
||||
assert(0 <= vertex_count && vertex_count <= INT_MAX);
|
||||
for (i = 0; i < edge_count; ++i) {
|
||||
if (i) assert(edges[i - 1][0] <= edges[i][0]);
|
||||
assert(edges[i][0] < vertex_count);
|
||||
assert(edges[i][1] < vertex_count);
|
||||
}
|
||||
int rc;
|
||||
struct Tarjan *tj;
|
||||
if ((tj = calloc(1, (sizeof(struct Tarjan) +
|
||||
if (!(t = calloc(1, (sizeof(struct Tarjan) +
|
||||
sizeof(struct Vertex) * vertex_count)))) {
|
||||
tj->V = (struct Vertex *)((char *)tj + sizeof(struct Tarjan));
|
||||
tj->Vn = vertex_count;
|
||||
tj->E = edges;
|
||||
tj->En = edge_count;
|
||||
tj->R = out_sorted;
|
||||
tj->C = out_opt_components;
|
||||
tj->index = 1;
|
||||
uint32_t Vi, Ei;
|
||||
for (Vi = 0; Vi < tj->Vn; ++Vi) {
|
||||
tj->V[Vi].Vi = Vi;
|
||||
tj->V[Vi].Ei = -1u;
|
||||
}
|
||||
for (Ei = 0, Vi = -1u; Ei < tj->En; ++Ei) {
|
||||
if (tj->E[Ei][0] == Vi) continue;
|
||||
Vi = tj->E[Ei][0];
|
||||
tj->V[Vi].Ei = Ei;
|
||||
}
|
||||
rc = 0;
|
||||
for (Vi = 0; Vi < tj->Vn; ++Vi) {
|
||||
if (!tj->V[Vi].index) {
|
||||
if ((rc = TarjanConnect(&tj, Vi)) == -1) {
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
t->V = (struct Vertex *)((char *)t + sizeof(struct Tarjan));
|
||||
t->Vn = vertex_count;
|
||||
t->E = edges;
|
||||
t->En = edge_count;
|
||||
t->R = out_sorted;
|
||||
t->C = out_opt_components;
|
||||
t->index = 1;
|
||||
for (v = 0; v < t->Vn; ++v) {
|
||||
t->V[v].Vi = v;
|
||||
t->V[v].Ei = -1;
|
||||
}
|
||||
for (e = 0, v = -1; e < t->En; ++e) {
|
||||
if (t->E[e][0] == v) continue;
|
||||
v = t->E[e][0];
|
||||
t->V[v].Ei = e;
|
||||
}
|
||||
rc = 0;
|
||||
for (v = 0; v < t->Vn; ++v) {
|
||||
if (!t->V[v].index) {
|
||||
if (!TarjanConnect(t, v)) {
|
||||
free(t->S.p);
|
||||
free(t);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
free(tj->S.p);
|
||||
assert(tj->Ri == vertex_count);
|
||||
if (out_opt_components) *out_opt_componentcount = tj->Ci;
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
free(tj);
|
||||
if (out_opt_components) {
|
||||
*out_opt_componentcount = t->Ci;
|
||||
}
|
||||
assert(t->Ri == vertex_count);
|
||||
free(t->S.p);
|
||||
free(t);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/bswap.h"
|
||||
|
||||
uint32_t(bitreverse32)(uint32_t x) {
|
||||
x = bswap_32(x);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/bswap.h"
|
||||
|
||||
uint64_t bitreverse64(uint64_t x) {
|
||||
x = bswap_64(x);
|
||||
|
|
112
libc/bits/bits.h
112
libc/bits/bits.h
|
@ -13,9 +13,6 @@ extern const bool kTrue;
|
|||
extern const bool kFalse;
|
||||
extern const uint8_t kReverseBits[256];
|
||||
|
||||
uint16_t bswap_16(uint16_t) pureconst;
|
||||
uint32_t bswap_32(uint32_t) pureconst;
|
||||
uint32_t bswap_64(uint32_t) pureconst;
|
||||
uint32_t gray(uint32_t) pureconst;
|
||||
uint32_t ungray(uint32_t) pureconst;
|
||||
unsigned bcdadd(unsigned, unsigned) pureconst;
|
||||
|
@ -157,16 +154,6 @@ unsigned long hamming(unsigned long, unsigned long) pureconst;
|
|||
#define ABOVEFLAG_ASM(OP) OP "\n\tseta\t%b0"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Reads scalar from memory, offset by segment.
|
||||
*
|
||||
* @return *(MEM) relative to segment
|
||||
* @see arch_prctl()
|
||||
* @see pushpop()
|
||||
*/
|
||||
#define fs(MEM) __peek("fs", MEM)
|
||||
#define gs(MEM) __peek("gs", MEM)
|
||||
|
||||
/**
|
||||
* Reads scalar from memory w/ one operation.
|
||||
*
|
||||
|
@ -374,115 +361,16 @@ unsigned long hamming(unsigned long, unsigned long) pureconst;
|
|||
#define invlpg(MEM) \
|
||||
asm volatile("invlpg\t(%0)" : /* no outputs */ : "r"(MEM) : "memory")
|
||||
|
||||
/**
|
||||
* Teleports code fragment inside _init().
|
||||
*/
|
||||
#define INITIALIZER(PRI, NAME, CODE) \
|
||||
asm(".pushsection .init." #PRI "." #NAME ",\"ax\",@progbits\n\t" \
|
||||
"call\t" #NAME "\n\t" \
|
||||
".popsection"); \
|
||||
textstartup optimizesize void NAME(char *rdi, const char *rsi) { \
|
||||
CODE; \
|
||||
asm volatile("" : /* no outputs */ : "D"(rdi), "S"(rsi)); \
|
||||
}
|
||||
|
||||
#ifndef __STRICT_ANSI__
|
||||
#if __PIC__ + __code_model_medium__ + __code_model_large__ + 0 > 1
|
||||
#define __EZLEA(SYMBOL) "lea\t" SYMBOL "(%%rip),%"
|
||||
#else
|
||||
#define __EZLEA(SYMBOL) "mov\t$" SYMBOL ",%k"
|
||||
#endif
|
||||
#define weaken(symbol) ((const typeof(&(symbol)))weakaddr(#symbol))
|
||||
#define strongaddr(symbolstr) \
|
||||
({ \
|
||||
intptr_t waddr; \
|
||||
asm(__EZLEA(symbolstr) "0" : "=r"(waddr)); \
|
||||
waddr; \
|
||||
})
|
||||
#define weakaddr(symbolstr) \
|
||||
({ \
|
||||
intptr_t waddr; \
|
||||
asm(".weak\t" symbolstr "\n\t" __EZLEA(symbolstr) "0" : "=r"(waddr)); \
|
||||
waddr; \
|
||||
})
|
||||
#else
|
||||
#define weaken(symbol) symbol
|
||||
#define weakaddr(symbolstr) &(symbolstr)
|
||||
#endif
|
||||
|
||||
#define slowcall(fn, arg1, arg2, arg3, arg4, arg5, arg6) \
|
||||
({ \
|
||||
void *ax; \
|
||||
asm volatile("push\t%7\n\t" \
|
||||
"push\t%6\n\t" \
|
||||
"push\t%5\n\t" \
|
||||
"push\t%4\n\t" \
|
||||
"push\t%3\n\t" \
|
||||
"push\t%2\n\t" \
|
||||
"push\t%1\n\t" \
|
||||
"call\tslowcall" \
|
||||
: "=a"(ax) \
|
||||
: "g"(fn), "g"(arg1), "g"(arg2), "g"(arg3), "g"(arg4), \
|
||||
"g"(arg5), "g"(arg6) \
|
||||
: "memory"); \
|
||||
ax; \
|
||||
})
|
||||
|
||||
#define IsAddressCanonicalForm(P) \
|
||||
({ \
|
||||
intptr_t p2 = (intptr_t)(P); \
|
||||
(0xffff800000000000l <= p2 && p2 <= 0x00007fffffffffffl); \
|
||||
})
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § bits » optimizations ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
|
||||
#define bswap_16(U16) \
|
||||
(isconstant(U16) ? ((((U16)&0xff00) >> 010) | (((U16)&0x00ff) << 010)) : ({ \
|
||||
uint16_t Swapped16, Werd16 = (U16); \
|
||||
asm("xchg\t%b0,%h0" : "=Q"(Swapped16) : "0"(Werd16)); \
|
||||
Swapped16; \
|
||||
}))
|
||||
|
||||
#define bswap_32(U32) \
|
||||
(isconstant(U32) \
|
||||
? ((((U32)&0xff000000) >> 030) | (((U32)&0x000000ff) << 030) | \
|
||||
(((U32)&0x00ff0000) >> 010) | (((U32)&0x0000ff00) << 010)) \
|
||||
: ({ \
|
||||
uint32_t Swapped32, Werd32 = (U32); \
|
||||
asm("bswap\t%0" : "=r"(Swapped32) : "0"(Werd32)); \
|
||||
Swapped32; \
|
||||
}))
|
||||
|
||||
#define bswap_64(U64) \
|
||||
(isconstant(U64) ? ((((U64)&0xff00000000000000ul) >> 070) | \
|
||||
(((U64)&0x00000000000000fful) << 070) | \
|
||||
(((U64)&0x00ff000000000000ul) >> 050) | \
|
||||
(((U64)&0x000000000000ff00ul) << 050) | \
|
||||
(((U64)&0x0000ff0000000000ul) >> 030) | \
|
||||
(((U64)&0x0000000000ff0000ul) << 030) | \
|
||||
(((U64)&0x000000ff00000000ul) >> 010) | \
|
||||
(((U64)&0x00000000ff000000ul) << 010)) \
|
||||
: ({ \
|
||||
uint64_t Swapped64, Werd64 = (U64); \
|
||||
asm("bswap\t%0" : "=r"(Swapped64) : "0"(Werd64)); \
|
||||
Swapped64; \
|
||||
}))
|
||||
|
||||
#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § bits » implementation details ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#define __peek(SEGMENT, ADDRESS) \
|
||||
({ \
|
||||
typeof(*(ADDRESS)) Pk; \
|
||||
asm("mov\t%%" SEGMENT ":%1,%0" : "=r"(Pk) : "m"(*(ADDRESS))); \
|
||||
Pk; \
|
||||
})
|
||||
|
||||
#define __ArithmeticOp1(OP, MEM) \
|
||||
({ \
|
||||
asm(OP "%z0\t%0" : "+m"(*(MEM)) : /* no inputs */ : "cc"); \
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_BSWAP_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_BSWAP_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
uint16_t bswap_16(uint16_t) pureconst;
|
||||
uint32_t bswap_32(uint32_t) pureconst;
|
||||
uint32_t bswap_64(uint32_t) pureconst;
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
|
||||
#define bswap_16(U16) \
|
||||
(isconstant(U16) ? ((((U16)&0xff00) >> 010) | (((U16)&0x00ff) << 010)) : ({ \
|
||||
uint16_t Swapped16, Werd16 = (U16); \
|
||||
asm("xchg\t%b0,%h0" : "=Q"(Swapped16) : "0"(Werd16)); \
|
||||
Swapped16; \
|
||||
}))
|
||||
|
||||
#define bswap_32(U32) \
|
||||
(isconstant(U32) \
|
||||
? ((((U32)&0xff000000) >> 030) | (((U32)&0x000000ff) << 030) | \
|
||||
(((U32)&0x00ff0000) >> 010) | (((U32)&0x0000ff00) << 010)) \
|
||||
: ({ \
|
||||
uint32_t Swapped32, Werd32 = (U32); \
|
||||
asm("bswap\t%0" : "=r"(Swapped32) : "0"(Werd32)); \
|
||||
Swapped32; \
|
||||
}))
|
||||
|
||||
#define bswap_64(U64) \
|
||||
(isconstant(U64) ? ((((U64)&0xff00000000000000ul) >> 070) | \
|
||||
(((U64)&0x00000000000000fful) << 070) | \
|
||||
(((U64)&0x00ff000000000000ul) >> 050) | \
|
||||
(((U64)&0x000000000000ff00ul) << 050) | \
|
||||
(((U64)&0x0000ff0000000000ul) >> 030) | \
|
||||
(((U64)&0x0000000000ff0000ul) << 030) | \
|
||||
(((U64)&0x000000ff00000000ul) >> 010) | \
|
||||
(((U64)&0x00000000ff000000ul) << 010)) \
|
||||
: ({ \
|
||||
uint64_t Swapped64, Werd64 = (U64); \
|
||||
asm("bswap\t%0" : "=r"(Swapped64) : "0"(Werd64)); \
|
||||
Swapped64; \
|
||||
}))
|
||||
|
||||
#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_BSWAP_H_ */
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_EZLEA_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_EZLEA_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
#if __pic__ + __pie__ + __code_model_medium__ + __code_model_large__ + 0 > 1
|
||||
#define ezlea(symbol) "lea\t" symbol "(%%rip),%"
|
||||
#else
|
||||
#define ezlea(symbol) "mov\t$" symbol ",%k"
|
||||
#endif
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_EZLEA_H_ */
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_INITIALIZER_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_INITIALIZER_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/**
|
||||
* Teleports code fragment inside _init().
|
||||
*/
|
||||
#define INITIALIZER(PRI, NAME, CODE) \
|
||||
asm(".pushsection .init." #PRI "." #NAME ",\"ax\",@progbits\n\t" \
|
||||
"call\t" #NAME "\n\t" \
|
||||
".popsection"); \
|
||||
textstartup optimizesize void NAME(char *rdi, const char *rsi) { \
|
||||
CODE; \
|
||||
asm volatile("" : /* no outputs */ : "D"(rdi), "S"(rsi)); \
|
||||
}
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_INITIALIZER_H_ */
|
|
@ -19,18 +19,13 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/popcnt.h"
|
||||
|
||||
static uint32_t popcnt32(uint32_t x) {
|
||||
x -= (x >> 1) & 0x55555555;
|
||||
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
|
||||
return (((x + (x >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
|
||||
}
|
||||
|
||||
unsigned long(popcnt)(unsigned long x) {
|
||||
unsigned long r;
|
||||
r = 0;
|
||||
while (x) {
|
||||
r += popcnt32(x);
|
||||
x >>= 32;
|
||||
}
|
||||
return r;
|
||||
uint64_t(popcnt)(uint64_t x) {
|
||||
uint32_t r;
|
||||
x = x - ((x >> 1) & 0x5555555555555555);
|
||||
x = ((x >> 2) & 0x3333333333333333) + (x & 0x3333333333333333);
|
||||
x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;
|
||||
x = (x + (x >> 32)) & 0xffffffff;
|
||||
x = x + (x >> 16);
|
||||
x = (x + (x >> 8)) & 0x0000007f;
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ unsigned long popcnt(unsigned long) pureconst;
|
|||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define popcnt(X) \
|
||||
(isconstant(X) ? __builtin_popcount(X) : ({ \
|
||||
(isconstant(X) ? __builtin_popcountll(X) : ({ \
|
||||
unsigned long Res, Pop = (X); \
|
||||
if (X86_HAVE(POPCNT)) { \
|
||||
asm("popcnt\t%1,%0" : "=r"(Res) : "r"(Pop) : "cc"); \
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#endif
|
||||
|
||||
#if !defined(__GNUC__) || defined(__STRICT_ANSI__)
|
||||
#define pushmov(d, x) ((d) = (x))
|
||||
#define pushmov(d, x) (*(d) = (x))
|
||||
#else
|
||||
#define pushmov(d, x) \
|
||||
({ \
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_SAFEMACROS_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_SAFEMACROS_H_
|
||||
#ifndef __STRICT_ANSI__
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
long min(long x, long y);
|
||||
long max(long x, long y);
|
||||
long roundup(long w, long k);
|
||||
long rounddown(long w, long k);
|
||||
bool isempty(const char *s);
|
||||
const char *nulltoempty(const char *s);
|
||||
const char *emptytonull(const char *s);
|
||||
const char *firstnonnull(const char *a, const char *b);
|
||||
uint64_t(unsignedsubtract)(uint64_t x, uint64_t y) pureconst;
|
||||
long min(long, long);
|
||||
long max(long, long);
|
||||
long roundup(long, long);
|
||||
long rounddown(long, long);
|
||||
bool isempty(const char *);
|
||||
const char *nulltoempty(const char *);
|
||||
const char *emptytonull(const char *);
|
||||
const char *firstnonnull(const char *, const char *);
|
||||
uint64_t(unsignedsubtract)(uint64_t, uint64_t) pureconst;
|
||||
|
||||
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
|
||||
|
||||
|
@ -83,4 +84,5 @@ uint64_t(unsignedsubtract)(uint64_t x, uint64_t y) pureconst;
|
|||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* !ANSI */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_SAFEMACROS_H_ */
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_SEGMENTATION_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_SEGMENTATION_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/**
|
||||
* Reads scalar from memory, offset by segment.
|
||||
*
|
||||
* @return *(MEM) relative to segment
|
||||
* @see arch_prctl()
|
||||
* @see pushpop()
|
||||
*/
|
||||
#define fs(MEM) __peek("fs", MEM)
|
||||
#define gs(MEM) __peek("gs", MEM)
|
||||
|
||||
#define __peek(SEGMENT, ADDRESS) \
|
||||
({ \
|
||||
typeof(*(ADDRESS)) Pk; \
|
||||
asm("mov\t%%" SEGMENT ":%1,%0" : "=r"(Pk) : "m"(*(ADDRESS))); \
|
||||
Pk; \
|
||||
})
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_SEGMENTATION_H_ */
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_WEAKEN_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_WEAKEN_H_
|
||||
#include "libc/bits/ezlea.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
#ifndef __STRICT_ANSI__
|
||||
|
||||
#define weaken(symbol) ((const typeof(&(symbol)))weakaddr(#symbol))
|
||||
|
||||
#define strongaddr(symbolstr) \
|
||||
({ \
|
||||
intptr_t waddr; \
|
||||
asm(ezlea(symbolstr) "0" : "=r"(waddr)); \
|
||||
waddr; \
|
||||
})
|
||||
|
||||
#define weakaddr(symbolstr) \
|
||||
({ \
|
||||
intptr_t waddr; \
|
||||
asm(".weak\t" symbolstr "\n\t" ezlea(symbolstr) "0" : "=r"(waddr)); \
|
||||
waddr; \
|
||||
})
|
||||
|
||||
#else
|
||||
#define weaken(symbol) symbol
|
||||
#define weakaddr(symbolstr) &(symbolstr)
|
||||
#endif /* __STRICT_ANSI__ */
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_WEAKEN_H_ */
|
|
@ -81,20 +81,19 @@ bool isregularfile(const char *);
|
|||
bool32 isatty(int) nosideeffect;
|
||||
bool32 ischardev(int) nosideeffect;
|
||||
char *get_current_dir_name(void) nodiscard;
|
||||
char *getcwd(char *, size_t) paramsnonnull();
|
||||
char *getcwd(char *, size_t);
|
||||
char *realpath(const char *, char *);
|
||||
char *replaceuser(const char *) nodiscard;
|
||||
char *slurp(const char *, size_t *) nodiscard;
|
||||
char *ttyname(int);
|
||||
const char *commandv(const char *);
|
||||
int access(const char *, int) nothrow paramsnonnull();
|
||||
int access(const char *, int) nothrow;
|
||||
int arch_prctl();
|
||||
int chdir(const char *) paramsnonnull();
|
||||
int chdir(const char *);
|
||||
int chmod(const char *, uint32_t);
|
||||
int chown(const char *, uint32_t, uint32_t) paramsnonnull();
|
||||
int chown(const char *, uint32_t, uint32_t);
|
||||
int close(int);
|
||||
int closedir(DIR *);
|
||||
int copyfile(const char *, const char *, bool);
|
||||
int creat(const char *, uint32_t) nodiscard;
|
||||
int dirfd(DIR *);
|
||||
int dup(int) nodiscard;
|
||||
|
@ -119,7 +118,7 @@ int fdatasync(int);
|
|||
int filecmp(const char *, const char *);
|
||||
int flock(int, int);
|
||||
int fork(void);
|
||||
int fstat(int, struct stat *) paramsnonnull();
|
||||
int fstat(int, struct stat *);
|
||||
int fstatat(int, const char *, struct stat *, uint32_t);
|
||||
int fsync(int);
|
||||
int ftruncate(int, int64_t);
|
||||
|
@ -131,7 +130,7 @@ int kill(int, int);
|
|||
int killpg(int, int);
|
||||
int link(const char *, const char *) nothrow;
|
||||
int linkat(int, const char *, int, const char *, uint32_t);
|
||||
int lstat(const char *, struct stat *) paramsnonnull();
|
||||
int lstat(const char *, struct stat *);
|
||||
int madvise(void *, uint64_t, int);
|
||||
int mkdir(const char *, uint32_t);
|
||||
int mkdirat(int, const char *, uint32_t);
|
||||
|
@ -141,7 +140,7 @@ int mknodat(int, const char *, int32_t, uint64_t);
|
|||
int mlock(const void *, size_t);
|
||||
int mlock2(const void *, size_t, int);
|
||||
int mlockall(int);
|
||||
int mprotect(void *, uint64_t, int) paramsnonnull() privileged;
|
||||
int mprotect(void *, uint64_t, int) privileged;
|
||||
int msync(void *, size_t, int);
|
||||
int munlock(const void *, size_t);
|
||||
int munlockall(void);
|
||||
|
@ -150,11 +149,11 @@ int munmap_s(void *, uint64_t);
|
|||
int nice(int);
|
||||
int open(const char *, int, ...) nodiscard;
|
||||
int openanon(char *, unsigned) nodiscard;
|
||||
int openat();
|
||||
int openat(int, const char *, int, ...);
|
||||
int pause(void);
|
||||
int personality(uint64_t);
|
||||
int pipe(int[hasatleast 2]) paramsnonnull() nodiscard;
|
||||
int pipe2(int[hasatleast 2], int) paramsnonnull() nodiscard;
|
||||
int pipe(int[hasatleast 2]) nodiscard;
|
||||
int pipe2(int[hasatleast 2], int) nodiscard;
|
||||
int posix_fadvise(int, uint64_t, uint64_t, int);
|
||||
int posix_fallocate(int, int64_t, int64_t);
|
||||
int posix_madvise(void *, uint64_t, int);
|
||||
|
@ -184,7 +183,7 @@ int sigaction(int, const struct sigaction *, struct sigaction *);
|
|||
int sigignore(int);
|
||||
int sigprocmask(int, const struct sigset *, struct sigset *);
|
||||
int sigsuspend(const struct sigset *);
|
||||
int stat(const char *, struct stat *) paramsnonnull();
|
||||
int stat(const char *, struct stat *);
|
||||
int symlink(const char *, const char *);
|
||||
int symlinkat(const char *, int, const char *);
|
||||
int sync_file_range(int, int64_t, int64_t, unsigned);
|
||||
|
@ -230,7 +229,7 @@ uint32_t gettid(void) nosideeffect;
|
|||
uint32_t getuid(void) nosideeffect;
|
||||
uint32_t umask(int32_t);
|
||||
void *getprocaddressmodule(const char *, const char *);
|
||||
void *mmap(void *, uint64_t, int32_t, int32_t, int32_t, int64_t) vallocesque;
|
||||
void *mmap(void *, uint64_t, int32_t, int32_t, int32_t, int64_t);
|
||||
void *mremap(void *, uint64_t, uint64_t, int32_t, void *);
|
||||
|
||||
#define getcwd(BUF, SIZE) \
|
||||
|
|
|
@ -20,12 +20,14 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Sets current directory.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int chdir(const char *path) {
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return chdir$sysv(path);
|
||||
} else {
|
||||
|
|
|
@ -45,5 +45,6 @@
|
|||
* @see fchmod()
|
||||
*/
|
||||
int chmod(const char *pathname, uint32_t mode) {
|
||||
if (!pathname) return efault();
|
||||
return fchmodat$sysv(AT_FDCWD, pathname, mode, 0);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Changes owner and/or group of pathname.
|
||||
|
@ -34,5 +35,6 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int chown(const char *pathname, uint32_t uid, uint32_t gid) {
|
||||
if (!pathname) return efault();
|
||||
return fchownat$sysv(AT_FDCWD, pathname, uid, gid, 0);
|
||||
}
|
||||
|
|
|
@ -17,10 +17,9 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.h"
|
||||
|
@ -33,7 +32,7 @@
|
|||
*/
|
||||
int close(int fd) {
|
||||
int rc;
|
||||
if (fd == -1) return 0;
|
||||
if (fd == -1) return einval();
|
||||
if (isfdkind(fd, kFdZip)) {
|
||||
rc = weaken(__zipos_close)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle);
|
||||
|
|
|
@ -49,9 +49,9 @@ textwindows int fstat$nt(int64_t handle, struct stat *st) {
|
|||
: (((filetype == kNtFileTypeDisk) ? S_IFBLK : 0) |
|
||||
((filetype == kNtFileTypeChar) ? S_IFCHR : 0) |
|
||||
((filetype == kNtFileTypePipe) ? S_IFIFO : 0))));
|
||||
filetimetotimespec(&st->st_atim, wst.ftLastAccessFileTime);
|
||||
filetimetotimespec(&st->st_mtim, wst.ftLastWriteFileTime);
|
||||
filetimetotimespec(&st->st_ctim, wst.ftCreationFileTime);
|
||||
st->st_atim = filetimetotimespec(wst.ftLastAccessFileTime);
|
||||
st->st_mtim = filetimetotimespec(wst.ftLastWriteFileTime);
|
||||
st->st_ctim = filetimetotimespec(wst.ftCreationFileTime);
|
||||
st->st_size = (uint64_t)wst.nFileSizeHigh << 32 | wst.nFileSizeLow;
|
||||
st->st_blksize = PAGESIZE;
|
||||
st->st_dev = wst.dwVolumeSerialNumber;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
* Supports fstat(), etc. implementations.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int32_t fstat$sysv(int32_t fd, struct stat *st) {
|
||||
textstartup int32_t fstat$sysv(int32_t fd, struct stat *st) {
|
||||
int res;
|
||||
if ((res = __fstat$sysv(fd, st)) != -1) {
|
||||
stat2linux(st);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
|
|
@ -17,18 +17,19 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/initializer.h"
|
||||
#include "libc/bits/pushpop.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
|
||||
STATIC_YOINK("_init_g_fds");
|
||||
|
||||
struct Fds g_fds;
|
||||
|
||||
INITIALIZER(300, _init_g_fds, {
|
||||
void InitializeFileDescriptors(void) {
|
||||
struct Fds *fds;
|
||||
fds = VEIL("D", &g_fds);
|
||||
fds = VEIL("r", &g_fds);
|
||||
pushmov(&fds->f, 3ul);
|
||||
pushmov(&fds->n, ARRAYLEN(fds->__init_p));
|
||||
fds->p = fds->__init_p;
|
||||
|
@ -40,4 +41,4 @@ INITIALIZER(300, _init_g_fds, {
|
|||
GetStdHandle(pushpop(kNtStdOutputHandle));
|
||||
fds->__init_p[STDERR_FILENO].handle =
|
||||
GetStdHandle(pushpop(kNtStdErrorHandle));
|
||||
})
|
||||
}
|
||||
|
|
|
@ -18,16 +18,12 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
.source __FILE__
|
||||
|
||||
mapanon:push %rbp
|
||||
mov %rsp,%rbp
|
||||
push %rbx
|
||||
push %rbx
|
||||
ezlea _base,bx
|
||||
call __mapanon
|
||||
pop %rbx
|
||||
pop %rbx
|
||||
pop %rbp
|
||||
ret
|
||||
.endfn mapanon,globl
|
||||
.init.start 300,_init_g_fds
|
||||
push %rdi
|
||||
push %rsi
|
||||
call InitializeFileDescriptors
|
||||
pop %rsi
|
||||
pop %rdi
|
||||
.init.end 300,_init_g_fds
|
||||
.source __FILE__
|
|
@ -35,23 +35,28 @@
|
|||
* @error ERANGE, EINVAL
|
||||
*/
|
||||
char *(getcwd)(char *buf, size_t size) {
|
||||
buf[0] = '\0';
|
||||
if (!IsWindows()) {
|
||||
int olderr = errno;
|
||||
if (getcwd$sysv(buf, size) != NULL) {
|
||||
return buf;
|
||||
} else if (IsXnu() && errno == ENOSYS) {
|
||||
if (size >= 2) {
|
||||
buf[0] = '.'; /* XXX: could put forth more effort */
|
||||
buf[1] = '\0';
|
||||
errno = olderr;
|
||||
if (buf) {
|
||||
buf[0] = '\0';
|
||||
if (!IsWindows()) {
|
||||
int olderr = errno;
|
||||
if (getcwd$sysv(buf, size) != NULL) {
|
||||
return buf;
|
||||
} else {
|
||||
erange();
|
||||
} else if (IsXnu() && errno == ENOSYS) {
|
||||
if (size >= 2) {
|
||||
buf[0] = '.'; /* XXX: could put forth more effort */
|
||||
buf[1] = '\0';
|
||||
errno = olderr;
|
||||
return buf;
|
||||
} else {
|
||||
erange();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
} else {
|
||||
return getcwd$nt(buf, size);
|
||||
}
|
||||
return NULL;
|
||||
} else {
|
||||
return getcwd$nt(buf, size);
|
||||
efault();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,10 +26,13 @@
|
|||
* Returns value of environment variable, or NULL if not found.
|
||||
*/
|
||||
char *getenv(const char *name) {
|
||||
char *empty[1] = {NULL};
|
||||
char **ep = firstnonnull(environ, empty);
|
||||
unsigned namelen = strlen(name);
|
||||
for (int i = 0; ep[i]; ++i) {
|
||||
char **ep;
|
||||
size_t i, namelen;
|
||||
char *empty[1] = {0};
|
||||
ep = environ;
|
||||
if (!ep) ep = empty;
|
||||
namelen = strlen(name);
|
||||
for (i = 0; ep[i]; ++i) {
|
||||
if (strncmp(ep[i], name, namelen) == 0 && ep[i][namelen] == '=') {
|
||||
return &ep[i][namelen + 1];
|
||||
}
|
||||
|
|
|
@ -17,32 +17,29 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/phaddw.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/nt/accounting.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "tool/viz/lib/formatstringtable-testlib.h"
|
||||
/* clang-format off */
|
||||
#include "libc/sysv/consts/rusage.h"
|
||||
|
||||
FIXTURE(phaddw, disableHardwareExtensions) {
|
||||
memset((/*unconst*/ void *)kCpuids, 0, sizeof(kCpuids));
|
||||
}
|
||||
|
||||
TEST(phaddw, testOverflow_wrapsAround) {
|
||||
short M[2][8] = {
|
||||
{0x7fff, 0, 0x7fff, 1, 13004, -30425, 20777, -16389},
|
||||
{-28040, 13318, -1336, -24798, -13876, 3599, -7346, -23575},
|
||||
};
|
||||
phaddw(M[0], M[0], M[1]);
|
||||
EXPECT_SHRTMATRIXEQ(2, 8, M, "\n\
|
||||
32767 -32768 -17421 4388 -14722 -26134 -10277 -30921\n\
|
||||
-28040 13318 -1336 -24798 -13876 3599 -7346 -23575");
|
||||
}
|
||||
|
||||
TEST(phaddw, testAliasing_isOk) {
|
||||
short M[1][8] = {
|
||||
{0,1, 2,3, 4,5, 6,7},
|
||||
};
|
||||
phaddw(M[0],M[0],M[0]);
|
||||
EXPECT_SHRTMATRIXEQ(1, 8, M, "\n\
|
||||
1 5 9 13 1 5 9 13");
|
||||
textwindows int getrusage$nt(int who, struct rusage *usage) {
|
||||
struct NtFileTime CreationFileTime;
|
||||
struct NtFileTime ExitFileTime;
|
||||
struct NtFileTime KernelFileTime;
|
||||
struct NtFileTime UserFileTime;
|
||||
memset(usage, 0, sizeof(*usage));
|
||||
if ((who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)(
|
||||
(who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(),
|
||||
&CreationFileTime, &ExitFileTime, &KernelFileTime, &UserFileTime)) {
|
||||
filetimetotimeval(&usage->ru_utime, UserFileTime);
|
||||
filetimetotimeval(&usage->ru_stime, KernelFileTime);
|
||||
return 0;
|
||||
} else {
|
||||
return winerr();
|
||||
}
|
||||
}
|
|
@ -19,35 +19,8 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/accounting.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/filetime.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/rusage.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static textwindows noinline int getrusage$nt(int who, struct rusage *usage) {
|
||||
struct NtFileTime CreationFileTime;
|
||||
struct NtFileTime ExitFileTime;
|
||||
struct NtFileTime KernelFileTime;
|
||||
struct NtFileTime UserFileTime;
|
||||
memset(usage, 0, sizeof(*usage));
|
||||
if ((who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)(
|
||||
(who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(),
|
||||
&CreationFileTime, &ExitFileTime, &KernelFileTime, &UserFileTime)) {
|
||||
filetimetotimeval(&usage->ru_utime, UserFileTime);
|
||||
filetimetotimeval(&usage->ru_stime, KernelFileTime);
|
||||
return 0;
|
||||
} else {
|
||||
return winerr();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns resource usage statistics.
|
||||
*
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
|
|
@ -17,10 +17,11 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Checks if effective user can access path in particular ways.
|
||||
|
@ -31,6 +32,7 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int access(const char *path, int mode) {
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return faccessat$sysv(AT_FDCWD, path, mode, 0);
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
/*-*- 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/calls/hefty/copyfile.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/madv.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
static textwindows int copyfile$nt(const char *src, const char *dst,
|
||||
int flags) {
|
||||
int64_t fhsrc, fhdst;
|
||||
struct NtFileTime accessed, modified;
|
||||
char16_t src16[PATH_MAX], dst16[PATH_MAX];
|
||||
if (mkntpath(src, src16) == -1) return -1;
|
||||
if (mkntpath(dst, dst16) == -1) return -1;
|
||||
if (CopyFile(src16, dst16, !!(flags & COPYFILE_NOCLOBBER))) {
|
||||
if (flags & COPYFILE_PRESERVE_TIMESTAMPS) {
|
||||
fhsrc = CreateFile(src16, kNtFileReadAttributes, kNtFileShareRead, NULL,
|
||||
kNtOpenExisting, kNtFileAttributeNormal, 0);
|
||||
fhdst = CreateFile(dst16, kNtFileWriteAttributes, kNtFileShareRead, NULL,
|
||||
kNtOpenExisting, kNtFileAttributeNormal, 0);
|
||||
if (fhsrc != -1 && fhdst != -1) {
|
||||
GetFileTime(fhsrc, NULL, &accessed, &modified);
|
||||
SetFileTime(fhdst, NULL, &accessed, &modified);
|
||||
}
|
||||
CloseHandle(fhsrc);
|
||||
CloseHandle(fhdst);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return winerr();
|
||||
}
|
||||
}
|
||||
|
||||
static int copyfile$sysv(const char *src, const char *dst, int flags) {
|
||||
struct stat st;
|
||||
size_t remaining;
|
||||
ssize_t transferred;
|
||||
struct timespec amtime[2];
|
||||
int64_t inoffset, outoffset;
|
||||
int rc, srcfd, dstfd, oflags, omode;
|
||||
rc = -1;
|
||||
if ((srcfd = openat$sysv(AT_FDCWD, src, O_RDONLY, 0)) != -1) {
|
||||
if (fstat$sysv(srcfd, &st) != -1) {
|
||||
omode = st.st_mode & 0777;
|
||||
oflags = O_WRONLY | O_CREAT;
|
||||
if (flags & COPYFILE_NOCLOBBER) oflags |= O_EXCL;
|
||||
if ((dstfd = openat$sysv(AT_FDCWD, dst, oflags, omode)) != -1) {
|
||||
remaining = st.st_size;
|
||||
ftruncate(dstfd, remaining);
|
||||
inoffset = 0;
|
||||
outoffset = 0;
|
||||
while (remaining &&
|
||||
(transferred = copy_file_range(
|
||||
srcfd, &inoffset, dstfd, &outoffset, remaining, 0)) != -1) {
|
||||
remaining -= transferred;
|
||||
}
|
||||
if (!remaining) {
|
||||
rc = 0;
|
||||
if (flags & COPYFILE_PRESERVE_TIMESTAMPS) {
|
||||
amtime[0] = st.st_atim;
|
||||
amtime[1] = st.st_mtim;
|
||||
utimensat$sysv(dstfd, NULL, amtime, 0);
|
||||
}
|
||||
}
|
||||
rc |= close$sysv(dstfd);
|
||||
}
|
||||
}
|
||||
rc |= close$sysv(srcfd);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies file.
|
||||
*/
|
||||
int copyfile(const char *src, const char *dst, int flags) {
|
||||
if (!IsWindows()) {
|
||||
return copyfile$sysv(src, dst, flags);
|
||||
} else {
|
||||
return copyfile$nt(src, dst, flags);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_
|
||||
|
||||
#define COPYFILE_NOCLOBBER 1
|
||||
#define COPYFILE_PRESERVE_OWNER 2
|
||||
#define COPYFILE_PRESERVE_TIMESTAMPS 4
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int copyfile(const char *, const char *, int) paramsnonnull();
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_ */
|
|
@ -0,0 +1,30 @@
|
|||
/*-*- 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/calls/hefty/internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int faccessat$nt(int dirfd, const char *path, int mode, uint32_t flags) {
|
||||
char16_t path16[PATH_MAX];
|
||||
if (dirfd != AT_FDCWD || flags) return einval();
|
||||
if (mkntpath(path, path16) == -1) return -1;
|
||||
return ntaccesscheck(path16, mode);
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/hefty/internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
@ -33,12 +34,10 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int faccessat(int dirfd, const char *path, int mode, uint32_t flags) {
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return faccessat$sysv(dirfd, path, mode, flags);
|
||||
} else {
|
||||
char16_t path16[PATH_MAX];
|
||||
if (dirfd != AT_FDCWD || flags) return einval();
|
||||
if (mkntpath(path, path16) == -1) return -1;
|
||||
return ntaccesscheck(path16, mode);
|
||||
return faccessat$nt(dirfd, path, mode, flags);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,17 +36,18 @@ LIBC_CALLS_HEFTY_A_CHECKS = \
|
|||
|
||||
LIBC_CALLS_HEFTY_A_DIRECTDEPS = \
|
||||
LIBC_ALG \
|
||||
LIBC_CALLS \
|
||||
LIBC_CONV \
|
||||
LIBC_FMT \
|
||||
LIBC_MEM \
|
||||
LIBC_STR \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_CALLS \
|
||||
LIBC_STUBS \
|
||||
LIBC_NT_KERNELBASE \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_SYSV
|
||||
LIBC_TIME
|
||||
|
||||
LIBC_CALLS_HEFTY_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x))))
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int faccessat$nt(int, const char *, int, uint32_t) hidden;
|
||||
int execve$nt(const char *, char *const[], char *const[]) hidden;
|
||||
int spawnve$nt(unsigned, int[3], const char *, char *const[],
|
||||
char *const[]) hidden;
|
||||
|
|
|
@ -35,36 +35,32 @@
|
|||
* @return freshly allocated lpEnvironment or NULL w/ errno
|
||||
*/
|
||||
textwindows char16_t *mkntenvblock(char *const envp[]) {
|
||||
size_t block_i = 0;
|
||||
size_t block_n = 0;
|
||||
char16_t *block_p = NULL;
|
||||
size_t i, j;
|
||||
if (!(envp = sortenvp(envp))) goto error;
|
||||
const char16_t kNul = u'\0';
|
||||
for (i = 0; envp[i]; ++i) {
|
||||
unsigned consumed;
|
||||
for (j = 0;; j += consumed) {
|
||||
wint_t wc;
|
||||
char16_t cbuf[2];
|
||||
consumed = abs(tpdecode(&envp[i][j], &wc));
|
||||
if (CONCAT(&block_p, &block_i, &block_n, cbuf,
|
||||
abs(pututf16(cbuf, ARRAYLEN(cbuf), wc, false))) == -1) {
|
||||
goto error;
|
||||
wint_t wc;
|
||||
size_t i, j, bi, bn;
|
||||
char16_t *bp, cbuf[2];
|
||||
unsigned consumed, produced;
|
||||
bi = 0;
|
||||
bn = 8;
|
||||
bp = NULL;
|
||||
if ((envp = sortenvp(envp)) && (bp = calloc(bn, sizeof(char16_t)))) {
|
||||
for (i = 0; envp[i]; ++i) {
|
||||
for (j = 0;; j += consumed) {
|
||||
consumed = abs(tpdecode(&envp[i][j], &wc));
|
||||
produced = abs(pututf16(cbuf, ARRAYLEN(cbuf), wc, false));
|
||||
if (CONCAT(&bp, &bi, &bn, cbuf, produced) == -1) goto error;
|
||||
if (!wc) break;
|
||||
}
|
||||
if (!wc) break;
|
||||
}
|
||||
++bi;
|
||||
if (bi > ENV_MAX) {
|
||||
e2big();
|
||||
goto error;
|
||||
}
|
||||
free(envp);
|
||||
return bp;
|
||||
}
|
||||
if (APPEND(&block_p, &block_i, &block_n, &kNul) == -1) {
|
||||
goto error;
|
||||
}
|
||||
if (block_i > ENV_MAX) {
|
||||
e2big();
|
||||
goto error;
|
||||
}
|
||||
free(envp);
|
||||
return block_p;
|
||||
error:
|
||||
free(envp);
|
||||
free(block_p);
|
||||
free(bp);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -19,12 +19,14 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_
|
||||
#ifndef __STRICT_ANSI__
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/struct/securityattributes.h"
|
||||
#include "libc/nt/struct/startupinfo.h"
|
||||
#include "libc/nt/struct/systeminfo.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
#define kSigactionMinRva 8 /* >SIG_{ERR,DFL,IGN,...} */
|
||||
|
@ -36,6 +38,7 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
struct NtContext;
|
||||
struct NtWin32FileAttributeData;
|
||||
struct ZiposHandle;
|
||||
struct __darwin_siginfo;
|
||||
struct __darwin_ucontext;
|
||||
struct itimerval;
|
||||
|
@ -45,7 +48,7 @@ struct sigset;
|
|||
struct sysinfo;
|
||||
struct timeval;
|
||||
struct timezone;
|
||||
struct ZiposHandle;
|
||||
struct utimbuf;
|
||||
|
||||
struct IoctlPtmGet {
|
||||
int theduxfd;
|
||||
|
@ -62,7 +65,8 @@ struct IoctlPtmGet {
|
|||
* and helps us abstract peculiarities like close() vs. closesocket().
|
||||
*/
|
||||
struct Fds {
|
||||
size_t f, n;
|
||||
size_t f; // length
|
||||
size_t n; // capacity
|
||||
struct Fd {
|
||||
int64_t handle;
|
||||
int64_t extra;
|
||||
|
@ -132,6 +136,7 @@ i32 __dup3$sysv(i32, i32, i32) hidden;
|
|||
i32 __fstat$sysv(i32, struct stat *) hidden;
|
||||
i32 __fstatat$sysv(i32, const char *, struct stat *, i32) hidden;
|
||||
i32 __pipe2$sysv(i32[hasatleast 2], u32) hidden;
|
||||
i32 __utimensat$sysv(i32, const char *, const struct timespec *, i32) hidden;
|
||||
i32 chdir$sysv(const char *) hidden;
|
||||
i32 clock_gettime$sysv(i32, struct timespec *) hidden;
|
||||
i32 close$sysv(i32) hidden;
|
||||
|
@ -154,6 +159,8 @@ i32 fstat$sysv(i32, struct stat *) hidden;
|
|||
i32 fstatat$sysv(i32, const char *, struct stat *, i32) hidden;
|
||||
i32 fsync$sysv(i32) hidden;
|
||||
i32 ftruncate$sysv(i32, i64) hidden;
|
||||
i32 futimes$sysv(i32, const struct timeval *) hidden;
|
||||
i32 futimesat$sysv(i32, const char *, const struct timeval *) hidden;
|
||||
i32 getdents(i32, char *, u32) hidden;
|
||||
i32 getppid$sysv(void) hidden;
|
||||
i32 getpriority$sysv(i32, u32) hidden;
|
||||
|
@ -164,6 +171,7 @@ i32 ioctl$sysv(i32, u64, void *) hidden;
|
|||
i32 kill$sysv(i32, i32, i32) hidden;
|
||||
i32 linkat$sysv(i32, const char *, i32, const char *, i32) hidden;
|
||||
i32 lseek$sysv(i32, i64, i32) hidden;
|
||||
i32 lutimes$sysv(const char *, const struct timeval *) hidden;
|
||||
i32 madvise$sysv(void *, size_t, i32) hidden;
|
||||
i32 memfd_create$sysv(const char *, u32) hidden;
|
||||
i32 mkdirat$sysv(i32, const char *, u32) hidden;
|
||||
|
@ -194,6 +202,8 @@ i32 sysinfo$sysv(struct sysinfo *) hidden;
|
|||
i32 truncate$sysv(const char *, u64) hidden;
|
||||
i32 uname$sysv(char *) hidden;
|
||||
i32 unlinkat$sysv(i32, const char *, i32) hidden;
|
||||
i32 utime$sysv(const char *, const struct utimbuf *) hidden;
|
||||
i32 utimensat$sysv(i32, const char *, const struct timespec *, i32) hidden;
|
||||
i32 utimes$sysv(const char *, const struct timeval *) hidden;
|
||||
i32 wait4$sysv(i32, i32 *, i32, struct rusage *) hidden;
|
||||
i64 copy_file_range$sysv(i32, long *, i32, long *, u64, u32) hidden;
|
||||
|
@ -207,12 +217,12 @@ i64 sendfile$sysv(i32, i32, i64 *, u64) hidden;
|
|||
i64 splice$sysv(i32, i64 *, i32, i64 *, u64, u32) hidden;
|
||||
i64 vmsplice$sysv(i32, const struct iovec *, i64, u32) hidden;
|
||||
i64 write$sysv(i32, const void *, u64) hidden;
|
||||
int setresgid$sysv(uint32_t, uint32_t, uint32_t) hidden;
|
||||
int setresuid$sysv(uint32_t, uint32_t, uint32_t) hidden;
|
||||
u32 getgid$sysv(void) hidden;
|
||||
u32 getpid$sysv(void) hidden;
|
||||
u32 gettid$sysv(void) hidden;
|
||||
u32 getuid$sysv(void) hidden;
|
||||
int setresuid$sysv(uint32_t, uint32_t, uint32_t) hidden;
|
||||
int setresgid$sysv(uint32_t, uint32_t, uint32_t) hidden;
|
||||
void *mmap$sysv(void *, u64, u32, u32, i64, i64) hidden;
|
||||
void *mremap$sysv(void *, u64, u64, i32, void *) hidden;
|
||||
|
||||
|
@ -223,13 +233,13 @@ void *mremap$sysv(void *, u64, u64, i32, void *) hidden;
|
|||
int __getpid(void) hidden;
|
||||
void __onfork(void) hidden;
|
||||
bool32 __sigenter(i32, struct siginfo *, struct ucontext *) hidden;
|
||||
i32 __mprotect(void *, u64, i32) privileged;
|
||||
i32 fixupnewfd$sysv(i32, i32) hidden;
|
||||
i32 tunefd$sysv(i32, i32, i32, i32) hidden;
|
||||
u32 fprot2nt(i32, i32) hidden;
|
||||
u32 prot2nt(i32, i32) privileged;
|
||||
void __restore_rt() hidden;
|
||||
void __sigenter$xnu(void *, i32, i32, void *, void *) hidden noreturn;
|
||||
int utimensat$xnu(int, const char *, const struct timespec *, int) hidden;
|
||||
void stat2linux(void *) hidden;
|
||||
void xnutrampoline(void *, i32, i32, const struct __darwin_siginfo *,
|
||||
const struct __darwin_ucontext *) hidden noreturn;
|
||||
|
@ -271,6 +281,8 @@ int wait4$nt(int, int *, int, struct rusage *) hidden;
|
|||
i64 lseek$nt(int, i64, int) hidden;
|
||||
ssize_t read$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
|
||||
ssize_t write$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
|
||||
int utimensat$nt(int, const char *, const struct timespec *, int) hidden;
|
||||
int getrusage$nt(int, struct rusage *) hidden;
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § syscalls » windows nt » support ─╬─│┼
|
||||
|
@ -317,4 +329,5 @@ int __mkntpath(const char *, unsigned, char16_t[hasatleast PATH_MAX - 16])
|
|||
#undef u64
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* !ANSI */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_ */
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/ioctl.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
|
|
|
@ -32,18 +32,17 @@ textwindows int ioctl$tiocgwinsz$nt(int fd, struct winsize *ws) {
|
|||
struct NtConsoleScreenBufferInfoEx sbinfo;
|
||||
if (!isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (!GetConsoleMode(g_fds.p[fd].handle, &mode)) return enotty();
|
||||
if (g_ntstartupinfo.dwFlags & kNtStartfUsecountchars) {
|
||||
ws->ws_col = g_ntstartupinfo.dwXCountChars;
|
||||
ws->ws_row = g_ntstartupinfo.dwYCountChars;
|
||||
ws->ws_xpixel = 0;
|
||||
ws->ws_ypixel = 0;
|
||||
return 0;
|
||||
}
|
||||
memset(&sbinfo, 0, sizeof(sbinfo));
|
||||
sbinfo.cbSize = sizeof(sbinfo);
|
||||
if (GetConsoleScreenBufferInfoEx(g_fds.p[fd].handle, &sbinfo)) {
|
||||
ws->ws_col = sbinfo.srWindow.Right;
|
||||
ws->ws_row = sbinfo.srWindow.Bottom;
|
||||
ws->ws_col = sbinfo.srWindow.Right - sbinfo.srWindow.Left;
|
||||
ws->ws_row = sbinfo.srWindow.Bottom - sbinfo.srWindow.Top;
|
||||
ws->ws_xpixel = 0;
|
||||
ws->ws_ypixel = 0;
|
||||
return 0;
|
||||
} else if (g_ntstartupinfo.dwFlags & kNtStartfUsecountchars) {
|
||||
ws->ws_col = g_ntstartupinfo.dwXCountChars;
|
||||
ws->ws_row = g_ntstartupinfo.dwYCountChars;
|
||||
ws->ws_xpixel = 0;
|
||||
ws->ws_ypixel = 0;
|
||||
return 0;
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#ifdef __STRICT_ANSI__
|
||||
#undef __STRICT_ANSI__
|
||||
#endif
|
||||
#include "libc/calls/ioctl.h"
|
||||
|
||||
#define EQUAL(X, Y) ((X) == (Y))
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
/**
|
||||
* Returns true if file descriptor is backed by character i/o.
|
||||
*/
|
||||
bool32 ischardev(int fd) {
|
||||
textstartup bool32 ischardev(int fd) {
|
||||
int olderr;
|
||||
struct stat st;
|
||||
if (!IsWindows()) {
|
||||
|
|
|
@ -24,13 +24,14 @@
|
|||
#include "libc/conv/conv.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/vendor.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
#define kBufSize 1024
|
||||
#define kBufSize 1024
|
||||
#define kProcStatus "/proc/self/status"
|
||||
alignas(16) static const char kGdbPid[] = "TracerPid:\t";
|
||||
|
||||
|
@ -43,18 +44,20 @@ int IsDebuggerPresent(bool force) {
|
|||
ssize_t got;
|
||||
char buf[1024];
|
||||
res = 0;
|
||||
if (force || isempty(getenv("HEISENDEBUG"))) {
|
||||
if (IsWindows()) {
|
||||
res = NtGetPeb()->BeingDebugged;
|
||||
} else if (IsLinux()) {
|
||||
if ((fd = openat$sysv(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) {
|
||||
if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kGdbPid))) != -1) {
|
||||
buf[got] = '\0';
|
||||
res = atoi(firstnonnull(strstr(buf, kGdbPid), kGdbPid) +
|
||||
strlen(kGdbPid));
|
||||
}
|
||||
close$sysv(fd);
|
||||
if (!force) {
|
||||
if (getenv("HEISENDEBUG")) return false;
|
||||
if (IsGenuineCosmo()) return false;
|
||||
}
|
||||
if (IsWindows()) {
|
||||
res = NtGetPeb()->BeingDebugged;
|
||||
} else if (IsLinux()) {
|
||||
if ((fd = openat$sysv(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) {
|
||||
if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kGdbPid))) != -1) {
|
||||
buf[got] = '\0';
|
||||
res =
|
||||
atoi(firstnonnull(strstr(buf, kGdbPid), kGdbPid) + strlen(kGdbPid));
|
||||
}
|
||||
close$sysv(fd);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/errno.h"
|
||||
|
||||
/**
|
||||
* Returns true if file exists and is a directory
|
||||
* Returns true if file exists and is a directory.
|
||||
*/
|
||||
bool isdirectory(const char *path) {
|
||||
struct stat st;
|
||||
|
|
|
@ -24,33 +24,35 @@
|
|||
#include "libc/nt/enum/processcreationflags.h"
|
||||
#include "libc/nt/enum/threadpriority.h"
|
||||
|
||||
#define FFS(x) __builtin_ffs(x)
|
||||
|
||||
const struct NtPriorityCombo kNtPriorityCombos[] = {
|
||||
{-20, ffs(kNtHighPriorityClass), kNtThreadPriorityHighest, 15},
|
||||
{-18, ffs(kNtHighPriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-17, ffs(kNtNormalPriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-15, ffs(kNtIdlePriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-13, ffs(kNtHighPriorityClass), kNtThreadPriorityAboveNormal, 14},
|
||||
{-11, ffs(kNtHighPriorityClass), kNtThreadPriorityNormal, 13},
|
||||
{-9, ffs(kNtHighPriorityClass), kNtThreadPriorityBelowNormal, 12},
|
||||
{-7, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 11},
|
||||
{-5, ffs(kNtHighPriorityClass), kNtThreadPriorityLowest, 11},
|
||||
{-3, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 10},
|
||||
{-1, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 9},
|
||||
{0, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 9},
|
||||
{1, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 8},
|
||||
{2, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 8},
|
||||
{3, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 7},
|
||||
{4, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 7},
|
||||
{5, ffs(kNtIdlePriorityClass), kNtThreadPriorityHighest, 6},
|
||||
{6, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 6},
|
||||
{7, ffs(kNtIdlePriorityClass), kNtThreadPriorityAboveNormal, 5},
|
||||
{9, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 5},
|
||||
{11, ffs(kNtIdlePriorityClass), kNtThreadPriorityNormal, 4},
|
||||
{13, ffs(kNtIdlePriorityClass), kNtThreadPriorityBelowNormal, 3},
|
||||
{15, ffs(kNtIdlePriorityClass), kNtThreadPriorityLowest, 2},
|
||||
{17, ffs(kNtHighPriorityClass), kNtThreadPriorityIdle, 1},
|
||||
{18, ffs(kNtNormalPriorityClass), kNtThreadPriorityIdle, 1},
|
||||
{19, ffs(kNtIdlePriorityClass), kNtThreadPriorityIdle, 1},
|
||||
{-20, FFS(kNtHighPriorityClass), kNtThreadPriorityHighest, 15},
|
||||
{-18, FFS(kNtHighPriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-17, FFS(kNtNormalPriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-15, FFS(kNtIdlePriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-13, FFS(kNtHighPriorityClass), kNtThreadPriorityAboveNormal, 14},
|
||||
{-11, FFS(kNtHighPriorityClass), kNtThreadPriorityNormal, 13},
|
||||
{-9, FFS(kNtHighPriorityClass), kNtThreadPriorityBelowNormal, 12},
|
||||
{-7, FFS(kNtNormalPriorityClass), kNtThreadPriorityHighest, 11},
|
||||
{-5, FFS(kNtHighPriorityClass), kNtThreadPriorityLowest, 11},
|
||||
{-3, FFS(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 10},
|
||||
{-1, FFS(kNtNormalPriorityClass), kNtThreadPriorityHighest, 9},
|
||||
{0, FFS(kNtNormalPriorityClass), kNtThreadPriorityNormal, 9},
|
||||
{1, FFS(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 8},
|
||||
{2, FFS(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 8},
|
||||
{3, FFS(kNtNormalPriorityClass), kNtThreadPriorityNormal, 7},
|
||||
{4, FFS(kNtNormalPriorityClass), kNtThreadPriorityLowest, 7},
|
||||
{5, FFS(kNtIdlePriorityClass), kNtThreadPriorityHighest, 6},
|
||||
{6, FFS(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 6},
|
||||
{7, FFS(kNtIdlePriorityClass), kNtThreadPriorityAboveNormal, 5},
|
||||
{9, FFS(kNtNormalPriorityClass), kNtThreadPriorityLowest, 5},
|
||||
{11, FFS(kNtIdlePriorityClass), kNtThreadPriorityNormal, 4},
|
||||
{13, FFS(kNtIdlePriorityClass), kNtThreadPriorityBelowNormal, 3},
|
||||
{15, FFS(kNtIdlePriorityClass), kNtThreadPriorityLowest, 2},
|
||||
{17, FFS(kNtHighPriorityClass), kNtThreadPriorityIdle, 1},
|
||||
{18, FFS(kNtNormalPriorityClass), kNtThreadPriorityIdle, 1},
|
||||
{19, FFS(kNtIdlePriorityClass), kNtThreadPriorityIdle, 1},
|
||||
};
|
||||
|
||||
const unsigned kNtPriorityCombosLen = ARRAYLEN(kNtPriorityCombos);
|
||||
|
|
|
@ -17,16 +17,14 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
/**
|
||||
* Modifies restrictions on virtual memory address range.
|
||||
*
|
||||
* @param prot can have PROT_{NONE,READ,WRITE,EXEC,GROWSDOWN}
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see mmap()
|
||||
*/
|
||||
int mprotect(void *addr, uint64_t len, int prot) {
|
||||
return __mprotect(addr, len, prot);
|
||||
int mkdirat(int dirfd, const char *pathname, unsigned mode) {
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return mkdir(pathname, mode);
|
||||
} else {
|
||||
return mkdirat$sysv(dirfd, pathname, mode);
|
||||
}
|
||||
}
|
|
@ -39,8 +39,9 @@
|
|||
* @return short count excluding NUL on success, or -1 w/ errno
|
||||
* @error ENAMETOOLONG
|
||||
*/
|
||||
textwindows int(mkntpath)(const char *path, unsigned flags,
|
||||
char16_t path16[hasatleast PATH_MAX - 16]) {
|
||||
forcealignargpointer textwindows int(mkntpath)(
|
||||
const char *path, unsigned flags,
|
||||
char16_t path16[hasatleast PATH_MAX - 16]) {
|
||||
/*
|
||||
* 1. Reserve +1 for NUL-terminator
|
||||
* 2. Reserve +1 for UTF-16 overflow
|
||||
|
|
|
@ -26,7 +26,14 @@
|
|||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
|
||||
privileged int __mprotect(void *addr, uint64_t len, int prot) {
|
||||
/**
|
||||
* Modifies restrictions on virtual memory address range.
|
||||
*
|
||||
* @param prot can have PROT_{NONE,READ,WRITE,EXEC,GROWSDOWN}
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see mmap()
|
||||
*/
|
||||
int mprotect(void *addr, uint64_t len, int prot) {
|
||||
extern __msabi typeof(VirtualProtect) *const __imp_VirtualProtect;
|
||||
bool cf;
|
||||
int64_t rc;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*-*- 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/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Opens file, the modern way.
|
||||
*
|
||||
* @param dirfd is normally AT_FDCWD or an open relative directory thing
|
||||
* @param file is a UTF-8 string, preferably relative w/ forward slashes
|
||||
* @param flags should be O_RDONLY, O_WRONLY, or O_RDWR, and can be or'd
|
||||
* with O_CREAT, O_TRUNC, O_APPEND, O_EXCL, O_CLOEXEC, O_TMPFILE
|
||||
* @param mode is an octal user/group/other permission signifier, that's
|
||||
* ignored if O_CREAT or O_TMPFILE weren't passed
|
||||
* @return number needing close(), or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int openat(int dirfd, const char *pathname, int flags, ...) {
|
||||
va_list va;
|
||||
unsigned mode;
|
||||
va_start(va, flags);
|
||||
mode = va_arg(va, unsigned);
|
||||
va_end(va);
|
||||
if (!pathname) return efault();
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return open(pathname, flags, mode);
|
||||
} else {
|
||||
return openat$sysv(dirfd, pathname, flags, mode);
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Creates file-less file descriptors for inter-process communication.
|
||||
|
@ -30,6 +31,7 @@
|
|||
* @see pipe2()
|
||||
*/
|
||||
int pipe(int pipefd[hasatleast 2]) {
|
||||
if (!pipefd) return efault();
|
||||
if (!IsWindows()) {
|
||||
return pipe$sysv(pipefd);
|
||||
} else {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Creates file-less file descriptors for interprocess communication.
|
||||
|
@ -29,6 +30,7 @@
|
|||
* @return 0 on success, or -1 w/ errno and pipefd isn't modified
|
||||
*/
|
||||
int pipe2(int pipefd[hasatleast 2], int flags) {
|
||||
if (!pipefd) return efault();
|
||||
if (!IsWindows()) {
|
||||
return pipe2$sysv(pipefd, flags);
|
||||
} else {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
|
|
|
@ -17,17 +17,20 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Moves file the Unix way.
|
||||
*
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int rename(const char *oldpathname, const char *newpathname) {
|
||||
if (!oldpathname || !newpathname) return efault();
|
||||
if (!IsWindows()) {
|
||||
return renameat$sysv(AT_FDCWD, oldpathname, AT_FDCWD, newpathname);
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*-*- 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/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
int renameat(int olddirfd, const char *oldpath, int newdirfd,
|
||||
const char *newpath) {
|
||||
unsigned mode;
|
||||
if (olddirfd == AT_FDCWD && newdirfd == AT_FDCWD) {
|
||||
return rename(oldpath, newpath);
|
||||
} else {
|
||||
return renameat$sysv(olddirfd, oldpath, newdirfd, newpath);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue