Browse Source

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.mp4
main
Justine Tunney 1 year ago
parent
commit
f4f4caab0e
  1. 3
      .clang-format
  2. 82
      Makefile
  3. 47
      ape/ape.S
  4. 60
      ape/ape.lds
  5. 18
      ape/ape.mk
  6. 32
      ape/idata.h
  7. 5
      ape/lib/pc.h
  8. 1
      build/archive
  9. BIN
      build/bootstrap/mkdeps.com
  10. 5
      build/compile
  11. 20
      build/config.mk
  12. 53
      build/definitions.mk
  13. 15
      build/htags
  14. 6
      build/rollup
  15. 13
      build/rules.mk
  16. 25
      dsp/mpeg/mpeg1.c
  17. 2
      dsp/mpeg/ycbcrio.h
  18. 16
      dsp/scale/gyarados.c
  19. 7
      dsp/scale/scale.mk
  20. 2
      dsp/tty/ident.c
  21. 8
      dsp/tty/itoa8.c
  22. 5
      dsp/tty/quant.h
  23. 18
      dsp/tty/rgb2ansi.c
  24. 71
      dsp/tty/rgb2xterm256.c
  25. 11
      dsp/tty/rgb2xterm256.h
  26. 14
      dsp/tty/ttyquant.c
  27. 14
      dsp/tty/ttyraw.c
  28. 282
      dsp/tty/xtermname.c
  29. 10
      dsp/tty/xtermname.h
  30. 3
      examples/bigmem.c
  31. 96
      examples/cp.c
  32. 191
      examples/examples.mk
  33. 1
      examples/findprime.c
  34. 3
      examples/hello.c
  35. 4
      examples/kilo.c
  36. 524
      examples/nesemu1.cc
  37. 15
      examples/printargs.c
  38. 217
      examples/unbourne.c
  39. 2
      examples/x86split.c
  40. 4
      libc/README.md
  41. 5
      libc/alg/alg.h
  42. 5
      libc/alg/arraylist2.h
  43. 12
      libc/alg/qsort.c
  44. 2
      libc/alg/replacestr16.c
  45. 190
      libc/alg/tarjan.c
  46. 1
      libc/bits/bitreverse32.c
  47. 1
      libc/bits/bitreverse64.c
  48. 112
      libc/bits/bits.h
  49. 48
      libc/bits/bswap.h
  50. 12
      libc/bits/ezlea.h
  51. 18
      libc/bits/initializer.h
  52. 23
      libc/bits/popcnt.c
  53. 2
      libc/bits/popcnt.h
  54. 2
      libc/bits/pushpop.h
  55. 20
      libc/bits/safemacros.h
  56. 23
      libc/bits/segmentation.h
  57. 28
      libc/bits/weaken.h
  58. 25
      libc/calls/calls.h
  59. 2
      libc/calls/chdir.c
  60. 1
      libc/calls/chmod.c
  61. 2
      libc/calls/chown.c
  62. 5
      libc/calls/close.c
  63. 6
      libc/calls/fstat-nt.c
  64. 2
      libc/calls/fstat-sysv.c
  65. 2
      libc/calls/fstat.c
  66. 11
      libc/calls/g_fds.c
  67. 20
      libc/calls/g_fds_init.S
  68. 33
      libc/calls/getcwd.c
  69. 11
      libc/calls/getenv.c
  70. 49
      libc/calls/getrusage-nt.c
  71. 27
      libc/calls/getrusage.c
  72. 2
      libc/calls/growfds.c
  73. 6
      libc/calls/hefty/access.c
  74. 108
      libc/calls/hefty/copyfile.c
  75. 15
      libc/calls/hefty/copyfile.h
  76. 30
      libc/calls/hefty/faccessat-nt.c
  77. 7
      libc/calls/hefty/faccessat.c
  78. 9
      libc/calls/hefty/hefty.mk
  79. 1
      libc/calls/hefty/internal.h
  80. 48
      libc/calls/hefty/mkntenvblock.c
  81. 23
      libc/calls/internal.h
  82. 2
      libc/calls/ioctl-default.c
  83. 17
      libc/calls/ioctl-tiocgwinsz-nt.c
  84. 3
      libc/calls/ioctl.c
  85. 2
      libc/calls/ischardev.c
  86. 27
      libc/calls/isdebuggerpresent.c
  87. 6
      libc/calls/isdirectory.c
  88. 54
      libc/calls/kntprioritycombos.c
  89. 18
      libc/calls/mkdirat.c
  90. 5
      libc/calls/mkntpath.ncabi.c
  91. 9
      libc/calls/mprotect.greg.c
  92. 2
      libc/calls/open.c
  93. 49
      libc/calls/openat.c
  94. 2
      libc/calls/pipe.c
  95. 2
      libc/calls/pipe2.c
  96. 2
      libc/calls/pread.c
  97. 2
      libc/calls/read.c
  98. 1
      libc/calls/readv.c
  99. 7
      libc/calls/rename.c
  100. 32
      libc/calls/renameat.c

3
.clang-format

@ -7,9 +7,10 @@ AlignConsecutiveDeclarations: false
AlwaysBreakBeforeMultilineStrings: false
AllowShortFunctionsOnASingleLine: false
KeepEmptyLinesAtTheStartOfBlocks: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
---
Language: Cpp
AllowShortFunctionsOnASingleLine: true
AllowShortFunctionsOnASingleLine: false
---
Language: Proto
...

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

@ -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

@ -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

@ -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,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

5
ape/lib/pc.h

@ -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

1
build/archive

@ -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

BIN
build/bootstrap/mkdeps.com

5
build/compile

@ -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

20
build/config.mk

@ -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

53
build/definitions.mk

@ -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

@ -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 \
"$@"

6
build/rollup

@ -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

13
build/rules.mk

@ -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

25
dsp/mpeg/mpeg1.c

@ -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};

2
dsp/mpeg/ycbcrio.h

@ -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_

16
dsp/scale/gyarados.c

@ -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);

7
dsp/scale/scale.mk

@ -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))

2
dsp/tty/ident.c

@ -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"

8
dsp/tty/itoa8.c

@ -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};

5
dsp/tty/quant.h

@ -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);

18
dsp/tty/rgb2ansi.c

@ -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};

71
dsp/tty/rgb2xterm256.c

@ -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;
}

11
dsp/tty/rgb2xterm256.h

@ -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_ */

14
dsp/tty/quantinit.c → dsp/tty/ttyquant.c

@ -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};

14
dsp/tty/ttyraw.c

@ -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) {

282
dsp/tty/xtermname.c

@ -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\