Initial import

This commit is contained in:
Justine Tunney 2020-06-15 07:18:57 -07:00
commit c91b3c5006
14915 changed files with 590219 additions and 0 deletions

33
dsp/tty/altbuf.c Normal file
View file

@ -0,0 +1,33 @@
/*-*- 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/tty.h"
/**
* Asks teletypewriter to flip to alternate display page.
*
* The alternate buffer trick lets one restore the console exactly as it
* was, once the program is done running.
*/
int ttyenablealtbuf(int ttyfd) { return ttysend(ttyfd, "\e[?1049h"); }
/**
* Asks teletypewriter to restore blinking box thing.
*/
int ttydisablealtbuf(int ttyfd) { return ttysend(ttyfd, "\e[?1049l"); }

46
dsp/tty/config.c Normal file
View file

@ -0,0 +1,46 @@
/*-*- 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/tty.h"
#include "libc/assert.h"
#include "libc/calls/termios.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/termios.h"
/**
* Applies configuration to teletypewriter.
*
* @param opt_out_oldconf is only modified if successful
* @return 0 on success, or -1 w/ errno
* @see ttyconfig(), ttyrestore()
*/
int ttyconfig(int ttyfd, ttyconf_f fn, int64_t arg,
const struct termios *opt_out_oldconf) {
struct termios conf[2];
if (tcgetattr(ttyfd, &conf[0]) != -1 &&
fn(memcpy(&conf[1], &conf[0], sizeof(conf[0])), arg) != -1 &&
tcsetattr(ttyfd, TCSAFLUSH, &conf[1]) != -1) {
if (opt_out_oldconf) {
memcpy(opt_out_oldconf, &conf[0], sizeof(conf[0]));
}
return 0;
} else {
return -1;
}
}

77
dsp/tty/describe.c Normal file
View file

@ -0,0 +1,77 @@
/*-*- 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/tty.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/x/x.h"
#define BUFFY 48
static char *ttydescriber(char *b, const struct TtyIdent *ti) {
switch (ti->id) {
case 0:
snprintf(b, BUFFY, "%s %d", "putty", ti->version);
break;
case 1:
if (ti->version > 1000) {
snprintf(b, BUFFY, "%s %d", "gnome terminal", ti->version);
} else {
snprintf(b, BUFFY, "%s %d", "mlterm", ti->version);
}
break;
case kTtyIdScreen:
snprintf(b, BUFFY, "%s %d", "gnu screen", ti->version);
break;
case 77:
snprintf(b, BUFFY, "%s %d", "redhat mintty", ti->version);
break;
case 41:
snprintf(b, BUFFY, "%s %d", "xterm", ti->version);
break;
case 82:
snprintf(b, BUFFY, "%s %d", "rxvt", ti->version);
break;
default:
snprintf(b, BUFFY, "%s %d %d", "unknown teletypewriter no.", ti->id,
ti->version);
break;
}
return b;
}
/**
* Makes educated guess about name of teletypewriter.
*/
char *ttydescribe(char *out, size_t size, const struct TtyIdent *ti) {
char b1[BUFFY], b2[BUFFY];
if (ti) {
ttydescriber(b1, ti);
if (ti->next) {
snprintf(out, size, "%s%s%s", ttydescriber(b2, ti->next), " inside ", b1);
} else {
snprintf(out, size, "%s", b1);
}
} else {
snprintf(out, size, "%s", "no tty");
}
return out;
}

53
dsp/tty/hidecursor.c Normal file
View file

@ -0,0 +1,53 @@
/*-*- 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/tty.h"
#include "libc/bits/pushpop.h"
#include "libc/dce.h"
#include "libc/log/log.h"
#include "libc/nt/console.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/consolecursorinfo.h"
static int ttysetcursor(int fd, bool visible) {
struct NtConsoleCursorInfo ntcursor;
char code[8] = "\e[?25l";
if (isterminalinarticulate()) return 0;
if (visible) code[5] = 'h';
if (SupportsWindows()) {
GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
ntcursor.bVisible = visible;
SetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
}
return ttysend(fd, code);
}
/**
* Asks teletypewriter to hide blinking box.
*/
int ttyhidecursor(int fd) {
return ttysetcursor(fd, false);
}
/**
* Asks teletypewriter to restore blinking box.
*/
int ttyshowcursor(int fd) {
return ttysetcursor(fd, true);
}

95
dsp/tty/ident.c Normal file
View file

@ -0,0 +1,95 @@
/*-*- 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/tty.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/termios.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/errfuns.h"
static int ttyident_probe(struct TtyIdent *ti, int ttyinfd, int ttyoutfd,
const char *msg) {
ssize_t rc;
size_t got;
char buf[64];
int id, version;
if ((rc = write(ttyoutfd, msg, strlen(msg))) != -1) {
TryAgain:
if ((rc = read(ttyinfd, buf, sizeof(buf))) != -1) {
buf[min((got = (size_t)rc), sizeof(buf) - 1)] = '\0';
if (sscanf(buf, "\e[>%d;%d", &id, &version) >= 1) {
ti->id = id;
ti->version = version;
rc = 0;
} else {
rc = eio();
}
} else if (errno == EINTR) {
goto TryAgain;
} else if (errno == EAGAIN) {
if (poll((struct pollfd[]){{ttyinfd, POLLIN}}, 1, 100) != 0) {
goto TryAgain;
} else {
rc = etimedout();
}
}
}
return rc;
}
/**
* Identifies teletypewriter.
*
* For example, we can tell if process is running in a GNU Screen
* session Gnome Terminal.
*
* @return object if TTY responds, or NULL w/ errno
* @see ttyidentclear()
*/
int ttyident(struct TtyIdent *ti, int ttyinfd, int ttyoutfd) {
int rc;
struct termios old;
struct TtyIdent outer;
rc = -1;
if (!IsWindows()) {
if (ttyconfig(ttyinfd, ttysetrawdeadline, 3, &old) != -1) {
if (ttyident_probe(ti, ttyinfd, ttyoutfd, "\e[>c") != -1) {
rc = 0;
memset(&outer, 0, sizeof(outer));
if (ti->id == 83 /* GNU Screen */ && (ti->next || weaken(malloc)) &&
ttyident_probe(&outer, ttyinfd, ttyoutfd, "\eP\e[>c\e\\") != -1 &&
(ti->next = (ti->next ? ti->next
: weaken(malloc)(sizeof(struct TtyIdent))))) {
memcpy(ti->next, &outer, sizeof(outer));
} else {
free_s(&ti->next);
}
}
ttyrestore(ttyinfd, &old);
}
}
return rc;
}

43
dsp/tty/identclear.c Normal file
View file

@ -0,0 +1,43 @@
/*-*- 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/tty.h"
#include "libc/assert.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
static void ttyidentfree(struct TtyIdent *ti) {
if (ti) {
assert(ti != ti->next);
ttyidentfree(ti->next);
free_s(&ti);
}
}
/**
* Destroys TtyIdent object.
*
* @see ttyident()
*/
void ttyidentclear(struct TtyIdent *ti) {
assert(ti != ti->next);
ttyidentfree(ti->next);
memset(ti, 0, sizeof(*ti));
}

33
dsp/tty/internal.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef COSMOPOLITAN_DSP_TTY_INTERNAL_H_
#define COSMOPOLITAN_DSP_TTY_INTERNAL_H_
#include "dsp/tty/ttyrgb.h"
#include "libc/bits/xmmintrin.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct TtyRgb rgb2tty24f_(__m128);
struct TtyRgb rgb2ttyf2i_(__m128);
struct TtyRgb rgb2ttyi2f_(int, int, int);
struct TtyRgb rgb2ansi_(int, int, int);
struct TtyRgb rgb2ansihash_(int, int, int);
struct TtyRgb rgb2xterm24_(int, int, int);
struct TtyRgb rgb2xterm256gray_(__m128);
struct TtyRgb tty2rgb_(struct TtyRgb);
struct TtyRgb tty2rgb24_(struct TtyRgb);
__m128 tty2rgbf_(struct TtyRgb);
__m128 tty2rgbf24_(struct TtyRgb);
char *setbg16_(char *, struct TtyRgb);
char *setfg16_(char *, struct TtyRgb);
char *setbgfg16_(char *, struct TtyRgb, struct TtyRgb);
char *setbg256_(char *, struct TtyRgb);
char *setfg256_(char *, struct TtyRgb);
char *setbgfg256_(char *, struct TtyRgb, struct TtyRgb);
char *setbg24_(char *, struct TtyRgb);
char *setfg24_(char *, struct TtyRgb);
char *setbgfg24_(char *, struct TtyRgb, struct TtyRgb);
struct TtyRgb rgb2ansi8_(int, int, int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_DSP_TTY_INTERNAL_H_ */

51
dsp/tty/itoa8.c Normal file
View file

@ -0,0 +1,51 @@
/*-*- 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/itoa8.h"
#include "libc/bits/bits.h"
#include "libc/str/str.h"
struct Itoa8 kItoa8;
static nooptimize textstartup void itoa8init(void) {
size_t i;
uint8_t z;
char p[4];
/*102*/
for (i = 0; i < 256; ++i) {
memset(p, 0, sizeof(p));
if (i < 10) {
z = 1;
p[0] = '0' + i;
} else if (i < 100) {
z = 2;
p[0] = '0' + i / 10;
p[1] = '0' + i % 10;
} else {
z = 3;
p[0] = '0' + i / 100;
p[1] = '0' + i % 100 / 10;
p[2] = '0' + i % 100 % 10;
}
kItoa8.size[i] = z;
memcpy(&kItoa8.data[i], p, sizeof(p));
}
}
INITIALIZER(301, _init_itoa8, itoa8init());

21
dsp/tty/itoa8.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef COSMOPOLITAN_DSP_TTY_ITOA8_H_
#define COSMOPOLITAN_DSP_TTY_ITOA8_H_
#include "libc/str/str.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct Itoa8 {
uint8_t size[256];
uint32_t data[256];
};
extern struct Itoa8 kItoa8;
forceinline char *itoa8(char *p, uint8_t c) {
memcpy(p, &kItoa8.data[c], 4);
return p + kItoa8.size[c];
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_DSP_TTY_ITOA8_H_ */

29
dsp/tty/kcgapalette.c Normal file
View file

@ -0,0 +1,29 @@
#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 "dsp/tty/quant.h"
const ttypalette_t kCgaPalette = {
[0][0] = {0, 0, 0, 0}, /* normal black: \e[30m (or \e[38;5;0m) */
[1][0] = {85, 85, 85, 8}, /* bright black: \e[90m (or \e[38;5;8m) */
[0][1] = {170, 0, 0, 1}, /* normal red: \e[31m */
[1][1] = {255, 85, 85, 9}, /* bright red: \e[91m (or \e[1;31m) */
[0][2] = {0, 170, 0, 2}, /* normal green: \e[32m */
[1][2] = {85, 255, 85, 10}, /* bright green: \e[92m */
[0][3] = {170, 85, 0, 3}, /* normal yellow: \e[33m */
[1][3] = {255, 255, 85, 11}, /* bright yellow: \e[93m */
[0][4] = {0, 0, 170, 4}, /* normal blue: \e[34m */
[1][4] = {85, 85, 255, 12}, /* bright blue: \e[94m */
[0][5] = {170, 0, 170, 5}, /* normal magenta: \e[35m */
[1][5] = {255, 85, 255, 13}, /* bright magenta: \e[95m */
[0][6] = {0, 170, 170, 6}, /* normal cyan: \e[36m */
[1][6] = {85, 255, 255, 14}, /* bright cyan: \e[96m */
[0][7] = {170, 170, 170, 7}, /* normal white: \e[37m */
[1][7] = {255, 255, 255, 15}, /* bright white: \e[97m */
};

29
dsp/tty/ktangopalette.c Normal file
View file

@ -0,0 +1,29 @@
#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 "dsp/tty/quant.h"
const ttypalette_t kTangoPalette = {
[0][0] = {0x2E, 0x34, 0x36, 0}, /* aluminium1 */
[1][0] = {0x55, 0x57, 0x53, 8},
[0][1] = {0xCC, 0x00, 0x00, 1}, /* scarietred */
[1][1] = {0xEF, 0x29, 0x29, 9},
[0][2] = {0x4E, 0x9A, 0x06, 2}, /* chameleon */
[1][2] = {0x8A, 0xE2, 0x34, 10},
[0][3] = {0xC4, 0xA0, 0x00, 3}, /* butter */
[1][3] = {0xFC, 0xE9, 0x4F, 11},
[0][4] = {0x34, 0x65, 0xA4, 4}, /* skyblue */
[1][4] = {0x72, 0x9F, 0xCF, 12},
[0][5] = {0x75, 0x50, 0x7B, 5}, /* plum */
[1][5] = {0xAD, 0x7F, 0xA8, 13},
[0][6] = {0x06, 0x98, 0x9A, 6}, /* cyan */
[1][6] = {0x34, 0xE2, 0xE2, 14},
[0][7] = {0xD3, 0xD7, 0xCF, 7}, /* aluminium2 */
[1][7] = {0xEE, 0xEE, 0xEC, 15},
};

22
dsp/tty/kxtermcubesteps.c Normal file
View file

@ -0,0 +1,22 @@
/*-*- 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/quant.h"
const uint8_t kXtermCubeSteps[] = {0, 0137, 0207, 0257, 0327, 0377};

29
dsp/tty/kxtermpalette.c Normal file
View file

@ -0,0 +1,29 @@
#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 "dsp/tty/quant.h"
const ttypalette_t kXtermPalette = {
[0][0] = {0, 0, 0, 0}, /* normal black: \e[30m (or \e[38;5;0m) */
[1][0] = {127, 127, 127, 8}, /* bright black: \e[90m (or \e[38;5;8m) */
[0][1] = {205, 0, 0, 1}, /* normal red: \e[31m */
[1][1] = {255, 0, 0, 9}, /* bright red: \e[91m (or \e[1;31m) */
[0][2] = {0, 205, 0, 2}, /* normal green: \e[32m */
[1][2] = {0, 255, 0, 10}, /* bright green: \e[92m */
[0][3] = {205, 205, 0, 3}, /* normal yellow: \e[33m */
[1][3] = {255, 255, 0, 11}, /* bright yellow: \e[93m */
[0][4] = {0, 0, 238, 4}, /* normal blue: \e[34m */
[1][4] = {92, 92, 255, 12}, /* bright blue: \e[94m */
[0][5] = {205, 0, 205, 5}, /* normal magenta: \e[35m */
[1][5] = {255, 0, 255, 13}, /* bright magenta: \e[95m */
[0][6] = {0, 205, 205, 6}, /* normal cyan: \e[36m */
[1][6] = {0, 255, 255, 14}, /* bright cyan: \e[96m */
[0][7] = {229, 229, 229, 7}, /* normal white: \e[37m */
[1][7] = {255, 255, 255, 15}, /* bright white: \e[97m */
};

29
dsp/tty/mpsadbw.S Normal file
View file

@ -0,0 +1,29 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.h"
/ TODO(jart): write me
movdqa a,%xmm0
mpsadbw $0,inv,%xmm0
.rodata.cst32
a: .byte 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
inv: .byte 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0

84
dsp/tty/quant.h Normal file
View file

@ -0,0 +1,84 @@
#ifndef DSP_TTY_QUANT_H_
#define DSP_TTY_QUANT_H_
#include "dsp/tty/ttyrgb.h"
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/xmmintrin.h"
#include "libc/limits.h"
#include "libc/str/str.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define TL 0
#define TR 1
#define BL 2
#define BR 3
typedef __m128 (*tty2rgbf_f)(struct TtyRgb);
typedef char *(*setbg_f)(char *, struct TtyRgb);
typedef char *(*setbgfg_f)(char *, struct TtyRgb, struct TtyRgb);
typedef char *(*setfg_f)(char *, struct TtyRgb);
typedef struct TtyRgb (*rgb2tty_f)(int, int, int);
typedef struct TtyRgb (*rgb2ttyf_f)(__m128);
typedef struct TtyRgb (*tty2rgb_f)(struct TtyRgb);
typedef struct TtyRgb ttypalette_t[2][8];
struct TtyQuant {
enum TtyQuantizationAlgorithm {
kTtyQuantAnsi,
kTtyQuantTrue,
kTtyQuantXterm256,
} alg;
enum TtyBlocksSelection {
kTtyBlocksUnicode,
kTtyBlocksCp437,
} blocks;
enum TtyQuantizationChannels {
kTtyQuantGrayscale = 1,
kTtyQuantRgb = 3,
} chans;
unsigned min;
unsigned max;
setbg_f setbg;
setfg_f setfg;
setbgfg_f setbgfg;
rgb2tty_f rgb2tty;
rgb2ttyf_f rgb2ttyf;
tty2rgb_f tty2rgb;
tty2rgbf_f tty2rgbf;
const ttypalette_t *palette;
};
extern const ttypalette_t kCgaPalette;
extern const ttypalette_t kXtermPalette;
extern const ttypalette_t kTangoPalette;
extern const uint8_t kXtermCubeSteps[6];
extern double g_xterm256_gamma;
extern struct TtyRgb g_ansi2rgb_[256];
extern struct TtyQuant g_ttyquant_;
extern const uint8_t kXtermXlat[2][256];
void ttyquantinit(enum TtyQuantizationAlgorithm, enum TtyQuantizationChannels,
enum TtyBlocksSelection);
extern char *ttyraster(char *, const struct TtyRgb *, size_t, size_t,
struct TtyRgb, struct TtyRgb);
#define ttyquant() (&g_ttyquant_)
#define TTYQUANT() VEIL("r", &g_ttyquant_)
#define rgb2tty(...) (ttyquant()->rgb2tty(__VA_ARGS__))
#define tty2rgb(...) (ttyquant()->tty2rgb(__VA_ARGS__))
#define rgb2ttyf(...) (ttyquant()->rgb2ttyf(__VA_ARGS__))
#define tty2rgbf(...) (ttyquant()->tty2rgbf(__VA_ARGS__))
#define setbg(...) (ttyquant()->setbg(__VA_ARGS__))
#define setfg(...) (ttyquant()->setfg(__VA_ARGS__))
#define setbgfg(...) (ttyquant()->setbgfg(__VA_ARGS__))
forceinline bool ttyeq(struct TtyRgb x, struct TtyRgb y) {
return x.r == y.r && x.g == y.g && x.b == y.b;
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* DSP_TTY_QUANT_H_ */

78
dsp/tty/quantinit.c Normal file
View file

@ -0,0 +1,78 @@
/*-*- 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/internal.h"
#include "dsp/tty/quant.h"
#include "libc/dce.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
struct TtyQuant g_ttyquant_;
/**
* Chooses xterm quantization mode.
*/
optimizesize textstartup void ttyquantinit(enum TtyQuantizationAlgorithm alg,
enum TtyQuantizationChannels chans,
enum TtyBlocksSelection blocks) {
switch (alg) {
case kTtyQuantAnsi:
TTYQUANT()->rgb2tty = rgb2ansi_;
TTYQUANT()->rgb2ttyf = rgb2ttyf2i_;
TTYQUANT()->tty2rgb = tty2rgb_;
TTYQUANT()->tty2rgbf = tty2rgbf_;
TTYQUANT()->setbg = setbg16_;
TTYQUANT()->setfg = setfg16_;
TTYQUANT()->setbgfg = setbgfg16_;
TTYQUANT()->min = 0;
TTYQUANT()->max = 16;
break;
case kTtyQuantTrue:
TTYQUANT()->rgb2tty = rgb2xterm24_;
TTYQUANT()->rgb2ttyf = rgb2tty24f_;
TTYQUANT()->tty2rgb = tty2rgb24_;
TTYQUANT()->tty2rgbf = tty2rgbf24_;
TTYQUANT()->setbg = setbg24_;
TTYQUANT()->setfg = setfg24_;
TTYQUANT()->setbgfg = setbgfg24_;
TTYQUANT()->min = 16;
TTYQUANT()->max = 256;
break;
case kTtyQuantXterm256:
TTYQUANT()->rgb2tty = rgb2ansi_;
TTYQUANT()->rgb2ttyf = rgb2ttyf2i_;
TTYQUANT()->tty2rgb = tty2rgb_;
TTYQUANT()->tty2rgbf = tty2rgbf_;
TTYQUANT()->setbg = setbg256_;
TTYQUANT()->setfg = setfg256_;
TTYQUANT()->setbgfg = setbgfg256_;
TTYQUANT()->min = 16;
TTYQUANT()->max = 256;
break;
default:
abort();
}
TTYQUANT()->chans = chans;
TTYQUANT()->alg = alg;
TTYQUANT()->blocks = blocks;
}
INITIALIZER(400, _init_ttyquant,
ttyquantinit(kTtyQuantXterm256, kTtyQuantRgb, kTtyBlocksUnicode));

29
dsp/tty/restore.c Normal file
View file

@ -0,0 +1,29 @@
/*-*- 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/tty.h"
#include "libc/calls/termios.h"
#include "libc/sysv/consts/termios.h"
/**
* Puts teletypewriter back into previous configuration.
*/
int ttyrestore(int ttyoutfd, const struct termios *conf) {
return tcsetattr(ttyoutfd, TCSADRAIN, conf);
}

129
dsp/tty/rgb2ansi.c Normal file
View file

@ -0,0 +1,129 @@
/*-*- 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/core/core.h"
#include "dsp/tty/quant.h"
#include "libc/assert.h"
#include "libc/limits.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/str/str.h"
#define CUTOFF_VALUE 200
#define DIST(X, Y) ((X) - (Y))
#define SQR(X) ((X) * (X))
#define SUM(X, Y, Z) ((X) + (Y) + (Z))
static const uint8_t kXtermCube[] = {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) {
return g_ansi2rgb_[rgbxt.xt];
}
__m128 tty2rgbf_(struct TtyRgb rgbxt) {
rgbxt = g_ansi2rgb_[rgbxt.xt];
return (__m128){(int)rgbxt.r, (int)rgbxt.g, (int)rgbxt.b} / 255;
}
static int rgb2xterm256_(int r, int g, int b) {
int cerr, gerr, ir, ig, ib, gray, grai, cr, cg, cb, gv;
gray = round(r * .299 + g * .587 + b * .114);
grai = gray > 238 ? 23 : (gray - 3) / 10;
ir = r < 48 ? 0 : r < 115 ? 1 : (r - 35) / 40;
ig = g < 48 ? 0 : g < 115 ? 1 : (g - 35) / 40;
ib = b < 48 ? 0 : b < 115 ? 1 : (b - 35) / 40;
cr = kXtermCube[ir];
cg = kXtermCube[ig];
cb = kXtermCube[ib];
gv = 8 + 10 * grai;
cerr = SQR(DIST(cr, r)) + SQR(DIST(cg, g)) + SQR(DIST(cb, b));
gerr = SQR(DIST(gv, r)) + SQR(DIST(gv, g)) + SQR(DIST(gv, b));
if (cerr <= gerr) {
return 16 + 36 * ir + 6 * ig + ib;
} else {
return 232 + grai;
}
}
/**
* Quantizes RGB to ANSI w/ euclidean distance in 3D color space.
*/
struct TtyRgb rgb2ansi_(int r, int g, int b) {
uint32_t d, least;
size_t c, best, min, max;
r = MAX(MIN(r, 255), 0);
g = MAX(MIN(g, 255), 0);
b = MAX(MIN(b, 255), 0);
min = ttyquant()->min;
max = ttyquant()->max;
if (min == 16 && max == 256) {
return (struct TtyRgb){r, g, b, rgb2xterm256_(r, g, b)};
} else {
least = UINT32_MAX;
best = 0;
for (c = min; c < max; c++) {
d = SUM(SQR(DIST(g_ansi2rgb_[c].r, r)), SQR(DIST(g_ansi2rgb_[c].g, g)),
SQR(DIST(g_ansi2rgb_[c].b, b)));
if (d < least) {
least = d;
best = c;
}
}
return (struct TtyRgb){r, g, b, best};
}
}
static int uncube(int x) {
return x < 48 ? 0 : x < 115 ? 1 : (x - 35) / 40;
}
static optimizesize textstartup void xterm2rgbsetup_(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];
g_ansi2rgb_[i].b = kXtermCube[(i - 020) % 06];
g_ansi2rgb_[i].xt = i;
}
for (i = 232, c = 8; i < 256; i++, c += 10) {
g_ansi2rgb_[i].r = c;
g_ansi2rgb_[i].g = c;
g_ansi2rgb_[i].b = c;
g_ansi2rgb_[i].xt = i;
}
}
INITIALIZER(301, _init_ansi2rgb, xterm2rgbsetup_());

29
dsp/tty/rgb2ttyf2i.c Normal file
View file

@ -0,0 +1,29 @@
/*-*- 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/quant.h"
#include "libc/bits/xmmintrin.h"
struct TtyRgb rgb2ttyf2i_(__m128 rgb) {
__v4si i4;
rgb *= 255;
/* i4 = __builtin_ia32_cvtps2dq(rgb); */
asm("cvttps2dq\t%0,%1" : "+%x"(rgb), "=x"(i4));
return rgb2tty(i4[0], i4[1], i4[2]);
}

26
dsp/tty/rgb2ttyi2f.c Normal file
View file

@ -0,0 +1,26 @@
/*-*- 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/quant.h"
#include "libc/log/check.h"
#include "libc/macros.h"
struct TtyRgb rgb2ttyi2f_(int r, int g, int b) {
return rgb2ttyf((__m128){r, g, b} / 255);
}

26
dsp/tty/rgb2xterm24.c Normal file
View file

@ -0,0 +1,26 @@
/*-*- 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/quant.h"
#include "libc/macros.h"
struct TtyRgb rgb2xterm24_(int r, int g, int b) {
return (struct TtyRgb){MAX(MIN(r, 255), 0), MAX(MIN(g, 255), 0),
MAX(MIN(b, 255), 0), 0};
}

42
dsp/tty/rgb2xterm24f.c Normal file
View file

@ -0,0 +1,42 @@
/*-*- 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/quant.h"
#include "libc/math.h"
/*
struct TtyRgb rgb2tty24f_(__m128 rgb) {
const __v4si kMax = {255, 255, 255, 255};
const __v4si kMin = {0, 0, 0, 0};
struct TtyRgb res;
__v4si rgb255;
rgb255 = _mm_min_ps(_mm_max_ps(_mm_cvtps_epi32(rgb * 255), kMin), kMax);
res = (struct TtyRgb){rgb255[0], rgb255[1], rgb255[2], rgb255[3]};
return res;
}
*/
struct TtyRgb rgb2tty24f_(__m128 rgb) {
const __m128 kMax = {1, 1, 1, 1};
const __m128 kMin = {0, 0, 0, 0};
struct TtyRgb res;
rgb = _mm_min_ps(_mm_max_ps(rgb, kMin), kMax) * 255;
res = (struct TtyRgb){rgb[0], rgb[1], rgb[2], rgb[3]};
return res;
}

71
dsp/tty/rgb2xterm256.c Normal file
View file

@ -0,0 +1,71 @@
/*-*- 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 Normal file
View file

@ -0,0 +1,11 @@
#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_ */

30
dsp/tty/savecursor.c Normal file
View file

@ -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 "dsp/tty/tty.h"
/**
* Asks teletypewriter to push current position.
*/
int ttysavecursor(int ttyfd) { return ttysend(ttyfd, "\e[s"); }
/**
* Asks teletypewriter to pop previous position.
*/
int ttyrestorecursor(int ttyfd) { return ttysend(ttyfd, "\e[u"); }

30
dsp/tty/send.c Normal file
View file

@ -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 "dsp/tty/tty.h"
#include "libc/str/str.h"
/**
* Sends data to teletypewriter.
*
* This function blocks until the full amount is transmitted.
*
* @return 0 on success, or -1 w/ errno
*/
int ttysend(int fd, const char *str) { return ttywrite(fd, str, strlen(str)); }

41
dsp/tty/sendtitle.c Normal file
View file

@ -0,0 +1,41 @@
/*-*- 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/tty.h"
#include "libc/alg/arraylist2.h"
#include "libc/runtime/gc.h"
#include "libc/x/x.h"
/**
* Changes text in title bar of pseudo-teletypewriter window.
*
* @param title is trustworthy text without any BEL characters
* @param ti comes from ttyident() and null means no-op
*/
int ttysendtitle(int ttyfd, const char *title, const struct TtyIdent *ti) {
if (ti) {
if (ti->id == kTtyIdScreen) {
return ttysend(ttyfd, gc(xstrcat("\eP\e]0;", title, "\a\e\\")));
} else {
return ttysend(ttyfd, gc(xstrcat("\e]0;", title, "\a")));
}
} else {
return 0;
}
}

25
dsp/tty/setansipalette.c Normal file
View file

@ -0,0 +1,25 @@
/*-*- 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/quant.h"
#include "libc/str/str.h"
void setansipalette(ttypalette_t palette) {
memcpy(g_ansi2rgb_, palette, sizeof(struct TtyRgb) * 2 * 8);
}

43
dsp/tty/setbgfg16.c Normal file
View file

@ -0,0 +1,43 @@
/*-*- 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/itoa8.h"
#include "dsp/tty/quant.h"
#include "libc/limits.h"
static char *ansitoa(char *p, unsigned xt, unsigned base) {
if (xt >= 8) xt -= 8, base += 60;
return itoa8(p, xt + base);
}
static char *setansibgfg(char *p, unsigned bg, unsigned fg) {
*p++ = '\e';
*p++ = '[';
if (bg != -1u) p = ansitoa(p, bg, 40);
if (bg != -1u && fg != -1u) *p++ = ';';
if (fg != -1u) p = ansitoa(p, fg, 30);
*p++ = 'm';
return p;
}
char *setbg16_(char *p, struct TtyRgb bg) { return setansibgfg(p, bg.xt, -1u); }
char *setfg16_(char *p, struct TtyRgb fg) { return setansibgfg(p, -1u, fg.xt); }
char *setbgfg16_(char *p, struct TtyRgb bg, struct TtyRgb fg) {
return setansibgfg(p, bg.xt, fg.xt);
}

54
dsp/tty/setbgfg24.c Normal file
View file

@ -0,0 +1,54 @@
/*-*- 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/itoa8.h"
#include "dsp/tty/quant.h"
#include "libc/str/str.h"
static char *rgbcpy(char *p, struct TtyRgb bg) {
memcpy(p, ";2;\0", 4);
p = itoa8(p + 3, bg.r);
*p++ = ';';
p = itoa8(p, bg.g);
*p++ = ';';
return itoa8(p, bg.b);
}
char *setbg24_(char *p, struct TtyRgb bg) {
memcpy(p, "\e[48", 4);
p = rgbcpy(p + 4, bg);
*p++ = 'm';
return p;
}
char *setfg24_(char *p, struct TtyRgb fg) {
memcpy(p, "\e[38", 4);
p = rgbcpy(p + 4, fg);
*p++ = 'm';
return p;
}
char *setbgfg24_(char *p, struct TtyRgb bg, struct TtyRgb fg) {
memcpy(p, "\e[48", 4);
p = rgbcpy(p + 4, bg);
memcpy(p, ";38\0", 4);
p = rgbcpy(p + 3, fg);
*p++ = 'm';
return p;
}

48
dsp/tty/setbgfg256.c Normal file
View file

@ -0,0 +1,48 @@
/*-*- 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/itoa8.h"
#include "dsp/tty/quant.h"
char *setbg256_(char *p, struct TtyRgb bg) {
memcpy(p, "\e[48", 4);
memcpy(p + 4, ";5;\0", 4);
p = itoa8(p + 7, bg.xt);
*p++ = 'm';
return p;
}
char *setfg256_(char *p, struct TtyRgb fg) {
memcpy(p, "\e[38", 4);
memcpy(p + 4, ";5;\0", 4);
p = itoa8(p + 7, fg.xt);
*p++ = 'm';
return p;
}
char *setbgfg256_(char *p, struct TtyRgb bg, struct TtyRgb fg) {
memcpy(p, "\e[48", 4);
memcpy(p + 4, ";5;\0", 4);
p = itoa8(p + 7, bg.xt);
memcpy(p, ";38;", 4);
memcpy(p + 4, "5;\0", 4);
p = itoa8(p + 6, fg.xt);
*p++ = 'm';
return p;
}

52
dsp/tty/setraw.c Normal file
View file

@ -0,0 +1,52 @@
/*-*- 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/tty.h"
#include "libc/calls/termios.h"
#include "libc/sysv/consts/termios.h"
/**
* Enables direct teletypewriter communication.
*
* @see ttyconfig(), ttyrestore()
*/
int ttysetraw(struct termios *conf, int64_t flags) {
conf->c_iflag &= ~(INPCK | ISTRIP | PARMRK | INLCR | IGNCR | ICRNL | IXON);
conf->c_lflag &= ~(IEXTEN | ICANON);
conf->c_cflag &= ~(CSIZE | PARENB);
conf->c_cflag |= CS8;
conf->c_iflag |= IUTF8;
/* if (flags & kTtyLfToCrLf) { */
/* /\* conf->c_oflag &= ~(OLCUC | OCRNL | ONLRET | OFILL | OFDEL); *\/ */
/* /\* conf->c_oflag |= ONLCR | ONOCR; *\/ */
/* conf->c_oflag |= ONLCR; */
/* } else { */
/* conf->c_oflag &= ~OPOST; */
/* } */
if (!(flags & kTtySigs)) {
conf->c_iflag &= ~(IGNBRK | BRKINT);
conf->c_lflag &= ~(ISIG);
}
if (flags & kTtyEcho) {
conf->c_lflag |= ECHO | ECHONL;
} else {
conf->c_lflag &= ~(ECHO | ECHONL);
}
return 0;
}

34
dsp/tty/setrawdeadline.c Normal file
View file

@ -0,0 +1,34 @@
/*-*- 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/tty.h"
#include "libc/assert.h"
#include "libc/calls/termios.h"
#include "libc/sysv/consts/termios.h"
/**
* Enables direct teletypewriter communication w/ read timeouts.
* @see ttyconfig(), ttyrestore()
*/
int ttysetrawdeadline(struct termios *conf, int64_t deciseconds) {
assert(0 < deciseconds && deciseconds < 256);
conf->c_cc[VMIN] = 0;
conf->c_cc[VTIME] = deciseconds;
return ttysetraw(conf, 0);
}

33
dsp/tty/setrawmode.c Normal file
View file

@ -0,0 +1,33 @@
/*-*- 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/tty.h"
#include "libc/assert.h"
#include "libc/calls/termios.h"
#include "libc/sysv/consts/termios.h"
/**
* Enables blocking raw mode for teletypewriter w/ recommended settings.
* @see ttyconfig(), ttyrestore()
*/
int ttysetrawmode(struct termios *conf, int64_t flags) {
conf->c_cc[VMIN] = 1;
conf->c_cc[VTIME] = 1;
return ttysetraw(conf, flags);
}

59
dsp/tty/tty.h Normal file
View file

@ -0,0 +1,59 @@
#ifndef COSMOPOLITAN_DSP_TTY_TTY_H_
#define COSMOPOLITAN_DSP_TTY_TTY_H_
#define kTtyIdScreen 83
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct FILE;
struct termios;
struct TtyIdent {
int id; /* first number sent back by \e[>c */
int version; /* second number sent back by \e[>c */
struct TtyIdent *next; /* yo dawg */
};
struct TtyCursor {
int y;
int x;
int bg;
int fg;
};
enum TtyRawFlags {
kTtyEcho = 1 << 0, /* echo input */
kTtyCursor = 1 << 1, /* show cursor */
kTtySigs = 1 << 2, /* auto raise() on CTRL+C, CTRL+Z, and CTRL+\ */
kTtyLfToCrLf = 1 << 3, /* enables unix newline magic */
};
typedef int (*ttyconf_f)(struct termios *, int64_t);
int ttyraw(enum TtyRawFlags);
int ttyhidecursor(int);
int ttyshowcursor(int);
int ttysavecursor(int);
int ttyrestorecursor(int);
int ttyenablealtbuf(int);
int ttydisablealtbuf(int);
int ttysend(int, const char *);
int ttywrite(int, const void *, size_t);
int ttysendtitle(int, const char *, const struct TtyIdent *);
int ttyident(struct TtyIdent *, int, int);
void ttyidentclear(struct TtyIdent *);
char *ttydescribe(char *, size_t, const struct TtyIdent *);
int ttyconfig(int, ttyconf_f, int64_t, const struct termios *);
int ttyrestore(int, const struct termios *);
int ttysetrawdeadline(struct termios *, int64_t);
int ttysetrawmode(struct termios *, int64_t);
int ttysetraw(struct termios *, int64_t);
char *ttymove(struct TtyCursor *, char *, int, int)
paramsnonnull() returnsnonnull;
void ttyhisto(uint32_t[hasatleast 256], uint8_t[hasatleast 256],
const uint8_t *, const uint8_t *, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_DSP_TTY_TTY_H_ */

70
dsp/tty/tty.mk Normal file
View file

@ -0,0 +1,70 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += DSP_TTY
DSP_TTY_ARTIFACTS += DSP_TTY_A
DSP_TTY = $(DSP_TTY_A_DEPS) $(DSP_TTY_A)
DSP_TTY_A = o/$(MODE)/dsp/tty/tty.a
DSP_TTY_A_FILES := $(wildcard dsp/tty/*)
DSP_TTY_A_HDRS = $(filter %.h,$(DSP_TTY_A_FILES))
DSP_TTY_A_SRCS_S = $(filter %.S,$(DSP_TTY_A_FILES))
DSP_TTY_A_SRCS_C = $(filter %.c,$(DSP_TTY_A_FILES))
DSP_TTY_A_SRCS = \
$(DSP_TTY_A_SRCS_S) \
$(DSP_TTY_A_SRCS_C)
DSP_TTY_A_OBJS = \
$(DSP_TTY_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(DSP_TTY_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(DSP_TTY_A_SRCS_C:%.c=o/$(MODE)/%.o)
DSP_TTY_A_CHECKS = \
$(DSP_TTY_A).pkg \
$(DSP_TTY_A_HDRS:%=o/$(MODE)/%.ok)
DSP_TTY_A_DIRECTDEPS = \
DSP_CORE \
LIBC_ALG \
LIBC_CALLS \
LIBC_FMT \
LIBC_LOG \
LIBC_RUNTIME \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_NT_KERNELBASE \
LIBC_STR \
LIBC_STDIO \
LIBC_STUBS \
LIBC_SOCK \
LIBC_SYSV \
LIBC_TINYMATH \
LIBC_TIME \
LIBC_X \
LIBC_UNICODE
DSP_TTY_A_DEPS := \
$(call uniq,$(foreach x,$(DSP_TTY_A_DIRECTDEPS),$($(x))))
$(DSP_TTY_A): dsp/tty/ \
$(DSP_TTY_A).pkg \
$(DSP_TTY_A_OBJS)
$(DSP_TTY_A).pkg: \
$(DSP_TTY_A_OBJS) \
$(foreach x,$(DSP_TTY_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/dsp/tty/ttyraster.o: \
OVERRIDE_CFLAGS += \
$(MATHEMATICAL)
DSP_TTY_LIBS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)))
DSP_TTY_SRCS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_SRCS))
DSP_TTY_HDRS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_HDRS))
DSP_TTY_CHECKS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_CHECKS))
DSP_TTY_OBJS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_OBJS))
$(DSP_TTY_OBJS): $(BUILD_FILES) dsp/tty/tty.mk
.PHONY: o/$(MODE)/dsp/tty
o/$(MODE)/dsp/tty: $(DSP_TTY_CHECKS)

24
dsp/tty/tty2rgb24.c Normal file
View file

@ -0,0 +1,24 @@
/*-*- 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/quant.h"
struct TtyRgb tty2rgb24_(struct TtyRgb rgbxt) {
return rgbxt;
}

24
dsp/tty/tty2rgbf24.c Normal file
View file

@ -0,0 +1,24 @@
/*-*- 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/quant.h"
__m128 tty2rgbf24_(struct TtyRgb rgbxt) {
return (__m128){(int)rgbxt.r, (int)rgbxt.g, (int)rgbxt.b} / 255;
}

51
dsp/tty/ttyhisto.c Normal file
View file

@ -0,0 +1,51 @@
/*-*- 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/tty.h"
#include "libc/alg/alg.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/str/str.h"
static int histcmp(const uint8_t *i1p, const uint8_t *i2p,
uint32_t histogram[hasatleast 256]) {
if (histogram[*i1p] > histogram[*i2p]) {
return -1;
} else if (histogram[*i1p] < histogram[*i2p]) {
return 1;
} else {
return 0;
}
}
void ttyhisto(uint32_t histogram[hasatleast 256],
uint8_t dominant[hasatleast 256], const uint8_t *xtcolors,
const uint8_t *eqmask, size_t size) {
size_t i;
uint64_t q;
memset(histogram, 0, sizeof(uint32_t) * 256);
for (i = 0; i < size / 8; ++i) {
memcpy(&q, &xtcolors[i * 8], 8);
if (q == (xtcolors[i * 8] & 0xff) * 0x0101010101010101ul) {
histogram[xtcolors[i * 8]]++;
}
}
imapxlatab(dominant);
qsort_r(dominant, 256, 1, (void *)histcmp, histogram);
}

198
dsp/tty/ttymove.c Normal file
View file

@ -0,0 +1,198 @@
/*-*- 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/itoa8.h"
#include "dsp/tty/tty.h"
#include "libc/bits/safemacros.h"
#include "libc/limits.h"
#include "libc/log/check.h"
/**
* Moves teletypewriter cursor to new coordinate.
*
* This uses codings defined by ANSI X3.4-1967 / X3.64-1979.
*
* @param c [in/out] tracks cursor coordinate
* @param p [out] buffer receives ANSI/VT sequences
* @param y is 0-indexed row
* @param x is 0-indexed column
* @return p + written, like mempcpy()
*/
char *ttymove(struct TtyCursor *c, char *p, int y, int x) {
int d;
DCHECK_GE(y, 0);
DCHECK_GE(x, 0);
DCHECK_LE(y, UINT16_MAX);
DCHECK_LE(x, UINT16_MAX);
if (y != c->y || x != c->x) {
do {
if (y != c->y && x != c->x) {
if (y == c->y + 1 && x == 0) {
p[0] = '\r';
p[1] = '\n';
p[2] = '\0';
p[3] = '\0';
p += 2;
c->y++;
c->x = 0;
break;
} else if (x < 256 && y < 256) {
if (y == 0 && x == 0) {
if (c->y == 0) {
p[0] = '\r';
p[1] = '\0';
p += 1;
c->x = 0;
} else {
p[0] = '\e'; /* CUP(1,1) */
p[1] = '[';
p[2] = 'H';
p[3] = '\0';
p += 3;
c->y = 0;
c->x = 0;
}
} else if (x == 0) {
*p++ = '\e'; /* CUP(y,1) */
*p++ = '[';
p = itoa8(p, y + 1);
*p++ = 'H';
*p = '\0';
c->y = y;
c->x = 0;
} else if (y == 0) {
*p++ = '\e'; /* CUP(1,x) */
*p++ = '[';
*p++ = ';';
*p = '\0';
p = itoa8(p, x + 1);
*p++ = 'H';
*p = '\0';
c->y = 0;
c->x = x;
} else {
*p++ = '\e'; /* CUP(y,1) */
*p++ = '[';
p = itoa8(p, y + 1);
*p++ = ';';
p = itoa8(p, x + 1);
*p++ = 'H';
*p = '\0';
c->y = y;
c->x = x;
}
break;
}
}
if (x != c->x) {
if (!x) {
p[0] = '\r'; /* goto beginning of line */
p[1] = '\0';
p += 1;
c->x = 0;
} else if (x > c->x) {
d = min(255, x - c->x);
if (d == 1) {
p[0] = '\e';
p[1] = '[';
p[2] = 'C'; /* cursor forward (CUF) */
p[3] = '\0';
p += 3;
} else {
p[0] = '\e';
p[1] = '[';
p = itoa8(p + 2, d);
p[0] = 'C'; /* cursor forward (CUF) */
p[1] = '\0';
p[2] = '\0';
p[3] = '\0';
p += 1;
}
c->x += d;
} else {
d = min(255, c->x - x);
if (d == 1) {
p[0] = '\e';
p[1] = '[';
p[2] = 'D'; /* cursor backward (CUB) */
p[3] = '\0';
p += 3;
} else {
p[0] = '\e';
p[1] = '[';
p = itoa8(p + 2, d);
p[0] = 'D'; /* cursor backward (CUB) */
p[1] = '\0';
p[2] = '\0';
p[3] = '\0';
p += 1;
}
c->x -= d;
}
}
if (y != c->y) {
if (y > c->y) {
d = min(255, y - c->y);
if (d == 1) {
p[0] = '\e';
p[1] = 'D'; /* index down (IND) */
p[2] = '\0';
p[3] = '\0';
p += 2;
} else {
p[0] = '\e';
p[1] = '[';
p = itoa8(p + 2, d);
p[0] = 'B'; /* cursor down (CUD) */
p[1] = '\0';
p[2] = '\0';
p[3] = '\0';
p += 1;
}
c->y += d;
} else {
d = min(255, c->y - y);
if (d == 1) {
p[0] = '\e';
p[1] = 'M'; /* reverse index (RI) */
p[2] = '\0';
p[3] = '\0';
p += 2;
} else {
p[0] = '\e';
p[1] = '[';
p = itoa8(p + 2, d);
p[0] = 'A'; /* cursor up (CUU) */
p[1] = '\0';
p[2] = '\0';
p[3] = '\0';
p += 1;
}
c->y -= d;
}
}
} while (x != c->x || y != c->y);
} else {
p[0] = '\0';
}
DCHECK_EQ(y, c->y);
DCHECK_EQ(x, c->x);
DCHECK_EQ(p[0], '\0');
return p;
}

799
dsp/tty/ttyraster.c Normal file
View file

@ -0,0 +1,799 @@
/*-*- 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/core/twixt8.h"
#include "dsp/tty/quant.h"
#include "dsp/tty/tty.h"
#include "dsp/tty/ttyrgb.h"
#include "dsp/tty/windex.h"
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#define SQR(X) ((X) * (X))
#define DIST(X, Y) ((X) - (Y))
#define QSUB(A, B, C) ABS(DIST(A##C, B##C))
#define DIFF(A, B) (QSUB(A, B, r) + QSUB(A, B, g) + QSUB(A, B, b))
#define JUDGE(M) (DIFF(ttl, M) + DIFF(ttr, M) + DIFF(tbl, M) + DIFF(tbr, M))
static const struct Glyph {
char c1, c2, c3, len;
} kGlyphs[2][11] = {
{{0x20, 0x00, 0x00, 1}, /* */
{0xE2, 0x96, 0x84, 3}, /* ▄ */
{0xE2, 0x96, 0x8C, 3}, /* ▌ */
{0xE2, 0x96, 0x9D, 3}, /* ▝ */
{0xE2, 0x96, 0x97, 3}, /* ▗ */
{0xE2, 0x96, 0x96, 3}, /* ▖ */
{0xE2, 0x96, 0x9E, 3}, /* ▞ */
{0xE2, 0x96, 0x98, 3}, /* ▘ */
{0xE2, 0x96, 0x91, 3}, /* ░ */
{0xE2, 0x96, 0x93, 3}, /* ▓ */
{0xE2, 0x96, 0x92, 3}}, /* ▒ */
{{0xE2, 0x96, 0x88, 3}, /* █ */
{0xE2, 0x96, 0x80, 3}, /* ▀ */
{0xE2, 0x96, 0x90, 3}, /* ▐ */
{0xE2, 0x96, 0x99, 3}, /* ▙ */
{0xE2, 0x96, 0x9B, 3}, /* ▛ */
{0xE2, 0x96, 0x9C, 3}, /* ▜ */
{0xE2, 0x96, 0x9A, 3}, /* ▚ */
{0xE2, 0x96, 0x9F, 3}, /* ▟ */
{0xE2, 0x96, 0x93, 3}, /* ▓ */
{0xE2, 0x96, 0x91, 3}, /* ░ */
{0xE2, 0x96, 0x92, 3}}, /* ▒ */
};
static const struct Pick {
unsigned char fg, bg, k;
} kPicksUnicode[96] = {
{-1, BL, 0}, /* */
{BR, BL, 4}, /* ▗ */
{TL, BL, 4}, /* ▗ */
{TR, BL, 4}, /* ▗ */
{BR, BL, 5}, /* ▖ */
{BR, BL, 1}, /* ▄ */
{TL, BL, 5}, /* ▖ */
{TL, BL, 1}, /* ▄ */
{TR, BL, 5}, /* ▖ */
{TR, BL, 1}, /* ▄ */
{BR, BL, 3}, /* ▝ */
{BL, BR, 2}, /* ▌ */
{BR, BL, 6}, /* ▞ */
{BL, BR, 7}, /* ▘ */
{TL, BL, 3}, /* ▝ */
{BL, TL, 2}, /* ▌ */
{TL, BL, 6}, /* ▞ */
{BL, TL, 7}, /* ▘ */
{TR, BL, 3}, /* ▝ */
{BL, TR, 2}, /* ▌ */
{TR, BL, 6}, /* ▞ */
{BL, TR, 7}, /* ▘ */
{BR, BL, 7}, /* ▘ */
{BL, BR, 6}, /* ▞ */
{BR, BL, 2}, /* ▌ */
{BL, BR, 3}, /* ▝ */
{BL, BR, 1}, /* ▄ */
{BL, BR, 5}, /* ▖ */
{BL, BR, 4}, /* ▗ */
{-1, BR, 0}, /* */
{TL, BR, 4}, /* ▗ */
{TR, BR, 4}, /* ▗ */
{TL, BR, 5}, /* ▖ */
{TL, BR, 1}, /* ▄ */
{TR, BR, 5}, /* ▖ */
{TR, BR, 1}, /* ▄ */
{TL, BR, 3}, /* ▝ */
{BR, TL, 2}, /* ▌ */
{TL, BR, 6}, /* ▞ */
{BR, TL, 7}, /* ▘ */
{TR, BR, 3}, /* ▝ */
{BR, TR, 2}, /* ▌ */
{TR, BR, 6}, /* ▞ */
{BR, TR, 7}, /* ▘ */
{TL, BL, 7}, /* ▘ */
{BL, TL, 6}, /* ▞ */
{TL, BL, 2}, /* ▌ */
{BL, TL, 3}, /* ▝ */
{TL, BR, 7}, /* ▘ */
{BR, TL, 6}, /* ▞ */
{TL, BR, 2}, /* ▌ */
{BR, TL, 3}, /* ▝ */
{BL, TL, 1}, /* ▄ */
{BL, TL, 5}, /* ▖ */
{BR, TL, 1}, /* ▄ */
{BR, TL, 5}, /* ▖ */
{BL, TL, 4}, /* ▗ */
{BR, TL, 4}, /* ▗ */
{-1, TL, 0}, /* */
{TR, TL, 4}, /* ▗ */
{TR, TL, 5}, /* ▖ */
{TR, TL, 1}, /* ▄ */
{TR, TL, 3}, /* ▝ */
{TL, TR, 2}, /* ▌ */
{TR, TL, 6}, /* ▞ */
{TL, TR, 7}, /* ▘ */
{TR, BL, 7}, /* ▘ */
{BL, TR, 6}, /* ▞ */
{TR, BL, 2}, /* ▌ */
{BL, TR, 3}, /* ▝ */
{TR, BR, 7}, /* ▘ */
{BR, TR, 6}, /* ▞ */
{TR, BR, 2}, /* ▌ */
{BR, TR, 3}, /* ▝ */
{TR, TL, 7}, /* ▘ */
{TL, TR, 6}, /* ▞ */
{TR, TL, 2}, /* ▌ */
{TL, TR, 3}, /* ▝ */
{BL, TR, 1}, /* ▄ */
{BL, TR, 5}, /* ▖ */
{BR, TR, 1}, /* ▄ */
{BR, TR, 5}, /* ▖ */
{TL, TR, 1}, /* ▄ */
{TL, TR, 5}, /* ▖ */
{BL, TR, 4}, /* ▗ */
{BR, TR, 4}, /* ▗ */
{TL, TR, 4}, /* ▗ */
{-1, TR, 0}, /* */
{-1, -1, -1}, /* X */
{-1, -1, -1}, /* X */
{-1, -1, -1}, /* X */
{-1, -1, -1}, /* X */
{-1, -1, -1}, /* X */
{-1, -1, -1}, /* X */
{-1, -1, -1}, /* X */
{-1, -1, -1}, /* X */
};
static const struct Pick kPicksCp437[32] = {
{-1, BL, 0}, /* */
{BR, BL, 1}, /* ▄ */
{TL, BL, 1}, /* ▄ */
{TR, BL, 1}, /* ▄ */
{BL, BR, 1}, /* ▄ */
{BL, TL, 1}, /* ▄ */
{BL, TR, 1}, /* ▄ */
{BL, BR, 2}, /* ▌ */
{BL, TL, 2}, /* ▌ */
{BL, TR, 2}, /* ▌ */
{BR, BL, 2}, /* ▌ */
{-1, BR, 0}, /* */
{TL, BR, 1}, /* ▄ */
{TR, BR, 1}, /* ▄ */
{BR, TL, 2}, /* ▌ */
{BR, TR, 2}, /* ▌ */
{TL, BL, 2}, /* ▌ */
{TL, BR, 2}, /* ▌ */
{BR, TL, 1}, /* ▄ */
{-1, TL, 0}, /* */
{TR, TL, 1}, /* ▄ */
{TL, TR, 2}, /* ▌ */
{TR, BL, 2}, /* ▌ */
{TR, BR, 2}, /* ▌ */
{TR, TL, 2}, /* ▌ */
{BR, TR, 1}, /* ▄ */
{TL, TR, 1}, /* ▄ */
{-1, TR, 0}, /* */
{-1, -1, -1}, /* X */
{-1, -1, -1}, /* X */
{-1, -1, -1}, /* X */
{-1, -1, -1}, /* X */
};
static const struct Pick kPicksMixBlock[32] = {
{BR, BL, 8}, /* ░ */
{BR, BL, 9}, /* ▓ */
{TL, BL, 8}, /* ░ */
{TL, BL, 9}, /* ▓ */
{TR, BL, 8}, /* ░ */
{TR, BL, 9}, /* ▓ */
{TL, BR, 8}, /* ░ */
{TL, BR, 9}, /* ▓ */
{TR, BR, 8}, /* ░ */
{TR, BR, 9}, /* ▓ */
{BL, TL, 8}, /* ░ */
{BL, TL, 9}, /* ▓ */
{BL, TL, 8}, /* ░ */
{BL, TL, 9}, /* ▓ */
{TR, TL, 8}, /* ░ */
{TR, TL, 9}, /* ▓ */
{BL, TR, 8}, /* ░ */
{BL, TR, 9}, /* ▓ */
{BR, TR, 8}, /* ░ */
{BR, TR, 9}, /* ▓ */
{TL, TR, 8}, /* ░ */
{TL, TR, 9}, /* ▓ */
/**/
{BL, TL, 8}, /* ░ */
{BL, TL, 9}, /* ▓ */
{TR, TL, 8}, /* ░ */
{TR, TL, 9}, /* ▓ */
{BL, TR, 8}, /* ░ */
{BL, TR, 9}, /* ▓ */
{BR, TR, 8}, /* ░ */
{BR, TR, 9}, /* ▓ */
{TL, TR, 8}, /* ░ */
{TL, TR, 9}, /* ▓ */
};
static unsigned short bdist(struct TtyRgb a, struct TtyRgb b, struct TtyRgb c,
struct TtyRgb d, struct TtyRgb w, struct TtyRgb x,
struct TtyRgb y, struct TtyRgb z) {
unsigned short dist;
dist = 0;
dist += ABS(a.r - w.r);
dist += ABS(a.g - w.g);
dist += ABS(a.b - w.b);
dist += ABS(b.r - x.r);
dist += ABS(b.g - x.g);
dist += ABS(b.b - x.b);
dist += ABS(c.r - y.r);
dist += ABS(c.g - y.g);
dist += ABS(c.b - y.b);
dist += ABS(d.r - z.r);
dist += ABS(d.g - z.g);
dist += ABS(d.b - z.b);
return dist;
}
static uint16_t *mixblock(uint16_t *p, struct TtyRgb ttl, struct TtyRgb ttr,
struct TtyRgb tbl, struct TtyRgb tbr,
struct TtyRgb qtl, struct TtyRgb qtr,
struct TtyRgb qbl, struct TtyRgb qbr) {
unsigned char ttlr, ttlg, ttlb, qtlr, qtlg, qtlb, ttrr, ttrg, ttrb, qtrr,
qtrg, qtrb, tblr, tblg, tblb, qblr, qblg, qblb, tbrr, tbrg, tbrb, qbrr,
qbrg, qbrb, l00r, l00g, l00b, l01r, l01g, l01b, l02r, l02g, l02b, l03r,
l03g, l03b, l04r, l04g, l04b, l05r, l05g, l05b, l06r, l06g, l06b, l07r,
l07g, l07b, l08r, l08g, l08b, l09r, l09g, l09b, l10r, l10g, l10b, l11r,
l11g, l11b, l12r, l12g, l12b, l13r, l13g, l13b, l14r, l14g, l14b, l15r,
l15g, l15b, l16r, l16g, l16b, l17r, l17g, l17b, l18r, l18g, l18b, l19r,
l19g, l19b, l20r, l20g, l20b, l21r, l21g, l21b, l22r, l22g, l22b, l23r,
l23g, l23b, l24r, l24g, l24b, l25r, l25g, l25b, l26r, l26g, l26b, l27r,
l27g, l27b, l28r, l28g, l28b, l29r, l29g, l29b, l30r, l30g, l30b, l31r,
l31g, l31b;
unsigned short p00, p01, p02, p03, p04, p05, p06, p07, p08, p09, p10, p11,
p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26,
p27, p28, p29, p30, p31;
ttlr = ttl.r;
ttlg = ttl.g;
ttlb = ttl.b;
qtlr = qtl.r;
qtlg = qtl.g;
qtlb = qtl.b;
ttrr = ttr.r;
ttrg = ttr.g;
ttrb = ttr.b;
qtrr = qtr.r;
qtrg = qtr.g;
qtrb = qtr.b;
tblr = tbl.r;
tblg = tbl.g;
tblb = tbl.b;
qblr = qbl.r;
qblg = qbl.g;
qblb = qbl.b;
tbrr = tbr.r;
tbrg = tbr.g;
tbrb = tbr.b;
qbrr = qbr.r;
qbrg = qbr.g;
qbrb = qbr.b;
l00r = twixt8(qblr, qbrr, 0100);
l00g = twixt8(qblg, qbrg, 0100);
l00b = twixt8(qblb, qbrb, 0100);
l01r = twixt8(qblr, qbrr, 0300);
l01g = twixt8(qblg, qbrg, 0300);
l01b = twixt8(qblb, qbrb, 0300);
l02r = twixt8(qblr, qbrr, 0200);
l02g = twixt8(qblg, qbrg, 0200);
l02b = twixt8(qblb, qbrb, 0200);
l03r = twixt8(qblr, qtlr, 0100);
l03g = twixt8(qblg, qtlg, 0100);
l03b = twixt8(qblb, qtlb, 0100);
l04r = twixt8(qblr, qtlr, 0300);
l04g = twixt8(qblg, qtlg, 0300);
l04b = twixt8(qblb, qtlb, 0300);
l05r = twixt8(qblr, qtlr, 0200);
l05g = twixt8(qblg, qtlg, 0200);
l05b = twixt8(qblb, qtlb, 0200);
l06r = twixt8(qblr, qtrr, 0100);
l06g = twixt8(qblg, qtrg, 0100);
l06b = twixt8(qblb, qtrb, 0100);
l07r = twixt8(qblr, qtrr, 0300);
l07g = twixt8(qblg, qtrg, 0300);
l07b = twixt8(qblb, qtrb, 0300);
l08r = twixt8(qblr, qtrr, 0200);
l08g = twixt8(qblg, qtrg, 0200);
l08b = twixt8(qblb, qtrb, 0200);
l09r = twixt8(qbrr, qtlr, 0100);
l09g = twixt8(qbrg, qtlg, 0100);
l09b = twixt8(qbrb, qtlb, 0100);
l10r = twixt8(qbrr, qtlr, 0300);
l10g = twixt8(qbrg, qtlg, 0300);
l10b = twixt8(qbrb, qtlb, 0300);
l11r = twixt8(qbrr, qtlr, 0200);
l11g = twixt8(qbrg, qtlg, 0200);
l11b = twixt8(qbrb, qtlb, 0200);
l12r = twixt8(qbrr, qtrr, 0100);
l12g = twixt8(qbrg, qtrg, 0100);
l12b = twixt8(qbrb, qtrb, 0100);
l13r = twixt8(qbrr, qtrr, 0300);
l13g = twixt8(qbrg, qtrg, 0300);
l13b = twixt8(qbrb, qtrb, 0300);
l14r = twixt8(qbrr, qtrr, 0200);
l14g = twixt8(qbrg, qtrg, 0200);
l14b = twixt8(qbrb, qtrb, 0200);
l15r = twixt8(qtlr, qblr, 0100);
l15g = twixt8(qtlg, qblg, 0100);
l15b = twixt8(qtlb, qblb, 0100);
l16r = twixt8(qtlr, qblr, 0300);
l16g = twixt8(qtlg, qblg, 0300);
l16b = twixt8(qtlb, qblb, 0300);
l17r = twixt8(qtlr, qblr, 0200);
l17g = twixt8(qtlg, qblg, 0200);
l17b = twixt8(qtlb, qblb, 0200);
l18r = twixt8(qtlr, qbrr, 0100);
l18g = twixt8(qtlg, qbrg, 0100);
l18b = twixt8(qtlb, qbrb, 0100);
l19r = twixt8(qtlr, qbrr, 0300);
l19g = twixt8(qtlg, qbrg, 0300);
l19b = twixt8(qtlb, qbrb, 0300);
l20r = twixt8(qtlr, qbrr, 0200);
l20g = twixt8(qtlg, qbrg, 0200);
l20b = twixt8(qtlb, qbrb, 0200);
l21r = twixt8(qtlr, qtrr, 0100);
l21g = twixt8(qtlg, qtrg, 0100);
l21b = twixt8(qtlb, qtrb, 0100);
l22r = twixt8(qtlr, qtrr, 0300);
l22g = twixt8(qtlg, qtrg, 0300);
l22b = twixt8(qtlb, qtrb, 0300);
l23r = twixt8(qtlr, qtrr, 0200);
l23g = twixt8(qtlg, qtrg, 0200);
l23b = twixt8(qtlb, qtrb, 0200);
l24r = twixt8(qtrr, qblr, 0100);
l24g = twixt8(qtrg, qblg, 0100);
l24b = twixt8(qtrb, qblb, 0100);
l25r = twixt8(qtrr, qblr, 0300);
l25g = twixt8(qtrg, qblg, 0300);
l25b = twixt8(qtrb, qblb, 0300);
l26r = twixt8(qtrr, qblr, 0200);
l26g = twixt8(qtrg, qblg, 0200);
l26b = twixt8(qtrb, qblb, 0200);
l27r = twixt8(qtrr, qbrr, 0100);
l27g = twixt8(qtrg, qbrg, 0100);
l27b = twixt8(qtrb, qbrb, 0100);
l28r = twixt8(qtrr, qbrr, 0300);
l28g = twixt8(qtrg, qbrg, 0300);
l28b = twixt8(qtrb, qbrb, 0300);
l29r = twixt8(qtrr, qbrr, 0200);
l29g = twixt8(qtrg, qbrg, 0200);
l29b = twixt8(qtrb, qbrb, 0200);
l30r = twixt8(qtrr, qtlr, 0100);
l30g = twixt8(qtrg, qtlg, 0100);
l30b = twixt8(qtrb, qtlb, 0100);
l31r = twixt8(qtrr, qtlr, 0300);
l31g = twixt8(qtrg, qtlg, 0300);
l31b = twixt8(qtrb, qtlb, 0300);
p00 = JUDGE(l00);
p01 = JUDGE(l01);
p02 = JUDGE(l02);
p03 = JUDGE(l03);
p04 = JUDGE(l04);
p05 = JUDGE(l05);
p06 = JUDGE(l06);
p07 = JUDGE(l07);
p08 = JUDGE(l08);
p09 = JUDGE(l09);
p10 = JUDGE(l10);
p11 = JUDGE(l11);
p12 = JUDGE(l12);
p13 = JUDGE(l13);
p14 = JUDGE(l14);
p15 = JUDGE(l15);
p16 = JUDGE(l16);
p17 = JUDGE(l17);
p18 = JUDGE(l18);
p19 = JUDGE(l19);
p20 = JUDGE(l20);
p21 = JUDGE(l21);
p22 = JUDGE(l22);
p23 = JUDGE(l23);
p24 = JUDGE(l24);
p25 = JUDGE(l25);
p26 = JUDGE(l26);
p27 = JUDGE(l27);
p28 = JUDGE(l28);
p29 = JUDGE(l29);
p30 = JUDGE(l30);
p31 = JUDGE(l31);
*p++ = p00;
*p++ = p01;
*p++ = p02;
*p++ = p03;
*p++ = p04;
*p++ = p05;
*p++ = p06;
*p++ = p07;
*p++ = p08;
*p++ = p09;
*p++ = p10;
*p++ = p11;
*p++ = p12;
*p++ = p13;
*p++ = p14;
*p++ = p15;
*p++ = p16;
*p++ = p17;
*p++ = p18;
*p++ = p19;
*p++ = p20;
*p++ = p21;
*p++ = p22;
*p++ = p23;
*p++ = p24;
*p++ = p25;
*p++ = p26;
*p++ = p27;
*p++ = p28;
*p++ = p29;
*p++ = p30;
*p++ = p31;
return p;
}
static struct TtyRgb getquant(struct TtyRgb rgb) {
return g_ansi2rgb_[rgb.xt];
}
static uint16_t *pickunicode(uint16_t *p, struct TtyRgb tl, struct TtyRgb tr,
struct TtyRgb bl, struct TtyRgb br,
struct TtyRgb tl2, struct TtyRgb tr2,
struct TtyRgb bl2, struct TtyRgb br2) {
#define PICK(A, B, C, D) *p++ = bdist(tl, tr, bl, br, A, B, C, D)
PICK(bl2, bl2, bl2, bl2); /* k=0 bg=bl fg=NULL */
PICK(bl2, bl2, bl2, br2); /* ▗ k=4 bg=bl fg=br */
PICK(bl2, bl2, bl2, tl2); /* ▗ k=4 bg=bl fg=tl */
PICK(bl2, bl2, bl2, tr2); /* ▗ k=4 bg=bl fg=tr */
PICK(bl2, bl2, br2, bl2); /* ▖ k=5 bg=bl fg=br */
PICK(bl2, bl2, br2, br2); /* ▄ k=1 bg=bl fg=br */
PICK(bl2, bl2, tl2, bl2); /* ▖ k=5 bg=bl fg=tl */
PICK(bl2, bl2, tl2, tl2); /* ▄ k=1 bg=bl fg=tl */
PICK(bl2, bl2, tr2, bl2); /* ▖ k=5 bg=bl fg=tr */
PICK(bl2, bl2, tr2, tr2); /* ▄ k=1 bg=bl fg=tr */
PICK(bl2, br2, bl2, bl2); /* ▝ k=3 bg=bl fg=br */
PICK(bl2, br2, bl2, br2); /* ▌ k=2 bg=br fg=bl */
PICK(bl2, br2, br2, bl2); /* ▞ k=6 bg=bl fg=br */
PICK(bl2, br2, br2, br2); /* ▘ k=7 bg=br fg=bl */
PICK(bl2, tl2, bl2, bl2); /* ▝ k=3 bg=bl fg=tl */
PICK(bl2, tl2, bl2, tl2); /* ▌ k=2 bg=tl fg=bl */
PICK(bl2, tl2, tl2, bl2); /* ▞ k=6 bg=bl fg=tl */
PICK(bl2, tl2, tl2, tl2); /* ▘ k=7 bg=tl fg=bl */
PICK(bl2, tr2, bl2, bl2); /* ▝ k=3 bg=bl fg=tr */
PICK(bl2, tr2, bl2, tr2); /* ▌ k=2 bg=tr fg=bl */
PICK(bl2, tr2, tr2, bl2); /* ▞ k=6 bg=bl fg=tr */
PICK(bl2, tr2, tr2, tr2); /* ▘ k=7 bg=tr fg=bl */
PICK(br2, bl2, bl2, bl2); /* ▘ k=7 bg=bl fg=br */
PICK(br2, bl2, bl2, br2); /* ▞ k=6 bg=br fg=bl */
PICK(br2, bl2, br2, bl2); /* ▌ k=2 bg=bl fg=br */
PICK(br2, bl2, br2, br2); /* ▝ k=3 bg=br fg=bl */
PICK(br2, br2, bl2, bl2); /* ▄ k=1 bg=br fg=bl */
PICK(br2, br2, bl2, br2); /* ▖ k=5 bg=br fg=bl */
PICK(br2, br2, br2, bl2); /* ▗ k=4 bg=br fg=bl */
PICK(br2, br2, br2, br2); /* k=0 bg=br fg=NULL */
PICK(br2, br2, br2, tl2); /* ▗ k=4 bg=br fg=tl */
PICK(br2, br2, br2, tr2); /* ▗ k=4 bg=br fg=tr */
PICK(br2, br2, tl2, br2); /* ▖ k=5 bg=br fg=tl */
PICK(br2, br2, tl2, tl2); /* ▄ k=1 bg=br fg=tl */
PICK(br2, br2, tr2, br2); /* ▖ k=5 bg=br fg=tr */
PICK(br2, br2, tr2, tr2); /* ▄ k=1 bg=br fg=tr */
PICK(br2, tl2, br2, br2); /* ▝ k=3 bg=br fg=tl */
PICK(br2, tl2, br2, tl2); /* ▌ k=2 bg=tl fg=br */
PICK(br2, tl2, tl2, br2); /* ▞ k=6 bg=br fg=tl */
PICK(br2, tl2, tl2, tl2); /* ▘ k=7 bg=tl fg=br */
PICK(br2, tr2, br2, br2); /* ▝ k=3 bg=br fg=tr */
PICK(br2, tr2, br2, tr2); /* ▌ k=2 bg=tr fg=br */
PICK(br2, tr2, tr2, br2); /* ▞ k=6 bg=br fg=tr */
PICK(br2, tr2, tr2, tr2); /* ▘ k=7 bg=tr fg=br */
PICK(tl2, bl2, bl2, bl2); /* ▘ k=7 bg=bl fg=tl */
PICK(tl2, bl2, bl2, tl2); /* ▞ k=6 bg=tl fg=bl */
PICK(tl2, bl2, tl2, bl2); /* ▌ k=2 bg=bl fg=tl */
PICK(tl2, bl2, tl2, tl2); /* ▝ k=3 bg=tl fg=bl */
PICK(tl2, br2, br2, br2); /* ▘ k=7 bg=br fg=tl */
PICK(tl2, br2, br2, tl2); /* ▞ k=6 bg=tl fg=br */
PICK(tl2, br2, tl2, br2); /* ▌ k=2 bg=br fg=tl */
PICK(tl2, br2, tl2, tl2); /* ▝ k=3 bg=tl fg=br */
PICK(tl2, tl2, bl2, bl2); /* ▄ k=1 bg=tl fg=bl */
PICK(tl2, tl2, bl2, tl2); /* ▖ k=5 bg=tl fg=bl */
PICK(tl2, tl2, br2, br2); /* ▄ k=1 bg=tl fg=br */
PICK(tl2, tl2, br2, tl2); /* ▖ k=5 bg=tl fg=br */
PICK(tl2, tl2, tl2, bl2); /* ▗ k=4 bg=tl fg=bl */
PICK(tl2, tl2, tl2, br2); /* ▗ k=4 bg=tl fg=br */
PICK(tl2, tl2, tl2, tl2); /* k=0 bg=tl fg=NULL */
PICK(tl2, tl2, tl2, tr2); /* ▗ k=4 bg=tl fg=tr */
PICK(tl2, tl2, tr2, tl2); /* ▖ k=5 bg=tl fg=tr */
PICK(tl2, tl2, tr2, tr2); /* ▄ k=1 bg=tl fg=tr */
PICK(tl2, tr2, tl2, tl2); /* ▝ k=3 bg=tl fg=tr */
PICK(tl2, tr2, tl2, tr2); /* ▌ k=2 bg=tr fg=tl */
PICK(tl2, tr2, tr2, tl2); /* ▞ k=6 bg=tl fg=tr */
PICK(tl2, tr2, tr2, tr2); /* ▘ k=7 bg=tr fg=tl */
PICK(tr2, bl2, bl2, bl2); /* ▘ k=7 bg=bl fg=tr */
PICK(tr2, bl2, bl2, tr2); /* ▞ k=6 bg=tr fg=bl */
PICK(tr2, bl2, tr2, bl2); /* ▌ k=2 bg=bl fg=tr */
PICK(tr2, bl2, tr2, tr2); /* ▝ k=3 bg=tr fg=bl */
PICK(tr2, br2, br2, br2); /* ▘ k=7 bg=br fg=tr */
PICK(tr2, br2, br2, tr2); /* ▞ k=6 bg=tr fg=br */
PICK(tr2, br2, tr2, br2); /* ▌ k=2 bg=br fg=tr */
PICK(tr2, br2, tr2, tr2); /* ▝ k=3 bg=tr fg=br */
PICK(tr2, tl2, tl2, tl2); /* ▘ k=7 bg=tl fg=tr */
PICK(tr2, tl2, tl2, tr2); /* ▞ k=6 bg=tr fg=tl */
PICK(tr2, tl2, tr2, tl2); /* ▌ k=2 bg=tl fg=tr */
PICK(tr2, tl2, tr2, tr2); /* ▝ k=3 bg=tr fg=tl */
PICK(tr2, tr2, bl2, bl2); /* ▄ k=1 bg=tr fg=bl */
PICK(tr2, tr2, bl2, tr2); /* ▖ k=5 bg=tr fg=bl */
PICK(tr2, tr2, br2, br2); /* ▄ k=1 bg=tr fg=br */
PICK(tr2, tr2, br2, tr2); /* ▖ k=5 bg=tr fg=br */
PICK(tr2, tr2, tl2, tl2); /* ▄ k=1 bg=tr fg=tl */
PICK(tr2, tr2, tl2, tr2); /* ▖ k=5 bg=tr fg=tl */
PICK(tr2, tr2, tr2, bl2); /* ▗ k=4 bg=tr fg=bl */
PICK(tr2, tr2, tr2, br2); /* ▗ k=4 bg=tr fg=br */
PICK(tr2, tr2, tr2, tl2); /* ▗ k=4 bg=tr fg=tl */
PICK(tr2, tr2, tr2, tr2); /* k=0 bg=tr fg=NULL */
#undef PICK
return p;
}
static uint16_t *pickcp437(uint16_t *p, struct TtyRgb tl, struct TtyRgb tr,
struct TtyRgb bl, struct TtyRgb br,
struct TtyRgb tl2, struct TtyRgb tr2,
struct TtyRgb bl2, struct TtyRgb br2) {
#define PICK(A, B, C, D) *p++ = bdist(tl, tr, bl, br, A, B, C, D)
PICK(bl2, bl2, bl2, bl2); /* k=0 bg=bl fg=NULL */
PICK(bl2, bl2, br2, br2); /* ▄ k=1 bg=bl fg=br */
PICK(bl2, bl2, tl2, tl2); /* ▄ k=1 bg=bl fg=tl */
PICK(bl2, bl2, tr2, tr2); /* ▄ k=1 bg=bl fg=tr */
PICK(br2, br2, bl2, bl2); /* ▄ k=1 bg=br fg=bl */
PICK(tl2, tl2, bl2, bl2); /* ▄ k=1 bg=tl fg=bl */
PICK(tr2, tr2, bl2, bl2); /* ▄ k=1 bg=tr fg=bl */
PICK(bl2, br2, bl2, br2); /* ▌ k=2 bg=br fg=bl */
PICK(bl2, tl2, bl2, tl2); /* ▌ k=2 bg=tl fg=bl */
PICK(bl2, tr2, bl2, tr2); /* ▌ k=2 bg=tr fg=bl */
PICK(br2, bl2, br2, bl2); /* ▌ k=2 bg=bl fg=br */
PICK(br2, br2, br2, br2); /* k=0 bg=br fg=NULL */
PICK(br2, br2, tl2, tl2); /* ▄ k=1 bg=br fg=tl */
PICK(br2, br2, tr2, tr2); /* ▄ k=1 bg=br fg=tr */
PICK(br2, tl2, br2, tl2); /* ▌ k=2 bg=tl fg=br */
PICK(br2, tr2, br2, tr2); /* ▌ k=2 bg=tr fg=br */
PICK(tl2, bl2, tl2, bl2); /* ▌ k=2 bg=bl fg=tl */
PICK(tl2, br2, tl2, br2); /* ▌ k=2 bg=br fg=tl */
PICK(tl2, tl2, br2, br2); /* ▄ k=1 bg=tl fg=br */
PICK(tl2, tl2, tl2, tl2); /* k=0 bg=tl fg=NULL */
PICK(tl2, tl2, tr2, tr2); /* ▄ k=1 bg=tl fg=tr */
PICK(tl2, tr2, tl2, tr2); /* ▌ k=2 bg=tr fg=tl */
PICK(tr2, bl2, tr2, bl2); /* ▌ k=2 bg=bl fg=tr */
PICK(tr2, br2, tr2, br2); /* ▌ k=2 bg=br fg=tr */
PICK(tr2, tl2, tr2, tl2); /* ▌ k=2 bg=tl fg=tr */
PICK(tr2, tr2, br2, br2); /* ▄ k=1 bg=tr fg=br */
PICK(tr2, tr2, tl2, tl2); /* ▄ k=1 bg=tr fg=tl */
PICK(tr2, tr2, tr2, tr2); /* k=0 bg=tr fg=NULL */
#undef PICK
return p;
}
static struct Pick pickblock_unicode_ansi(struct TtyRgb tl, struct TtyRgb tr,
struct TtyRgb bl, struct TtyRgb br) {
struct TtyRgb tl2 = getquant(tl);
struct TtyRgb tr2 = getquant(tr);
struct TtyRgb bl2 = getquant(bl);
struct TtyRgb br2 = getquant(br);
unsigned i, p1, p2;
uint16_t picks1[96] aligned(32);
uint16_t picks2[32] aligned(32);
memset(picks1, 0x79, sizeof(picks1));
memset(picks2, 0x79, sizeof(picks2));
pickunicode(picks1, tl, tr, bl, br, tl2, tr2, bl2, br2);
mixblock(picks2, tl, tr, bl, br, tl2, tr2, bl2, br2);
p1 = windex(picks1, 96);
p2 = windex(picks2, 32);
return picks1[p1] <= picks2[p2] ? kPicksUnicode[p1] : kPicksMixBlock[p2];
}
static struct Pick pickblock_unicode_true(struct TtyRgb tl, struct TtyRgb tr,
struct TtyRgb bl, struct TtyRgb br) {
unsigned i;
uint16_t picks[96] aligned(32);
memset(picks, 0x79, sizeof(picks));
pickunicode(picks, tl, tr, bl, br, tl, tr, bl, br);
i = windex(picks, 96);
if (i >= 88) {
unsigned j;
fprintf(stderr, "uint16_t picks[96] = {");
for (j = 0; j < 96; ++j) {
fprintf(stderr, "%3d,", picks[j]);
}
fprintf(stderr, "}\n");
}
CHECK_LT(i, 88);
return kPicksUnicode[i];
}
static struct Pick pickblock_cp437_ansi(struct TtyRgb tl, struct TtyRgb tr,
struct TtyRgb bl, struct TtyRgb br) {
struct TtyRgb tl2 = getquant(tl);
struct TtyRgb tr2 = getquant(tr);
struct TtyRgb bl2 = getquant(bl);
struct TtyRgb br2 = getquant(br);
unsigned i, p1, p2;
uint16_t picks1[32] aligned(32);
uint16_t picks2[32] aligned(32);
memset(picks1, 0x79, sizeof(picks1));
memset(picks2, 0x79, sizeof(picks2));
pickcp437(picks1, tl, tr, bl, br, tl2, tr2, bl2, br2);
mixblock(picks2, tl, tr, bl, br, tl2, tr2, bl2, br2);
p1 = windex(picks1, 32);
p2 = windex(picks2, 32);
return picks1[p1] <= picks2[p2] ? kPicksCp437[p1] : kPicksMixBlock[p2];
}
static struct Pick pickblock_cp437_true(struct TtyRgb tl, struct TtyRgb tr,
struct TtyRgb bl, struct TtyRgb br) {
unsigned i;
uint16_t picks[32] aligned(32);
memset(picks, 0x79, sizeof(picks));
pickcp437(picks, tl, tr, bl, br, tl, tr, bl, br);
return kPicksCp437[windex(picks, 32)];
}
static char *copyglyph(char *v, struct Glyph glyph) {
memcpy(v, &glyph, 4);
return v + glyph.len;
}
static char *copyblock(char *v, const struct TtyRgb chunk[hasatleast 4],
struct Pick pick, struct TtyRgb *bg, struct TtyRgb *fg,
struct Glyph *glyph) {
unsigned i;
CHECK_LT(pick.bg, 4);
if (pick.fg != 0xff) CHECK_LT(pick.fg, 4);
i = 0;
if (pick.fg == 0xff) {
if (!ttyeq(*bg, chunk[pick.bg])) {
if (ttyeq(*fg, chunk[pick.bg])) {
if (memcmp(glyph, &kGlyphs[1][0], sizeof(*glyph)) == 0) {
v = setbg(v, (*bg = *fg));
} else {
i = 1;
}
} else {
v = setbg(v, (*bg = chunk[pick.bg]));
}
}
} else if (ttyeq(chunk[pick.bg], chunk[pick.fg])) {
pick.k = 0;
if (!ttyeq(*bg, chunk[pick.bg])) {
if (ttyeq(*fg, chunk[pick.bg])) {
if (memcmp(glyph, &kGlyphs[1][0], sizeof(*glyph)) == 0) {
v = setbg(v, (*bg = *fg));
} else {
i = 1;
}
} else {
v = setbg(v, (*bg = chunk[pick.bg]));
}
}
} else if (!ttyeq(*fg, chunk[pick.fg])) {
if (!ttyeq(*bg, chunk[pick.bg])) {
if (ttyeq(*fg, chunk[pick.bg]) && ttyeq(*bg, chunk[pick.fg])) {
if (pick.k == 0 && memcmp(glyph, &kGlyphs[1][0], sizeof(*glyph)) == 0) {
v = setbg(v, (*bg = *fg));
} else {
i = 1;
}
} else {
v = setbgfg(v, (*bg = chunk[pick.bg]), (*fg = chunk[pick.fg]));
}
} else {
v = setfg(v, (*fg = chunk[pick.fg]));
}
} else if (!ttyeq(*bg, chunk[pick.bg])) {
v = setbg(v, (*bg = chunk[pick.bg]));
}
return copyglyph(v, (*glyph = kGlyphs[i][pick.k]));
}
static bool chunkeq(struct TtyRgb c[hasatleast 4],
struct TtyRgb c2[hasatleast 4]) {
return ttyeq(c[TL], c[TR]) && ttyeq(c[BL], c[BR]) && ttyeq(c2[TL], c2[TR]) &&
ttyeq(c2[BL], c2[BR]);
}
static struct TtyRgb *copychunk(struct TtyRgb chunk[hasatleast 4],
const struct TtyRgb *c, size_t n) {
chunk[TL] = c[0 + 0];
chunk[TR] = c[0 + 1];
chunk[BL] = c[n + 0];
chunk[BR] = c[n + 1];
return chunk;
}
static noinline char *copyrun(char *v, size_t n,
struct TtyRgb lastchunk[hasatleast 4],
const struct TtyRgb **c, size_t *x,
struct TtyRgb *bg, struct TtyRgb *fg,
struct Glyph *glyph) {
struct TtyRgb chunk[4];
if (memcmp(glyph, &kGlyphs[1][0], sizeof(*glyph)) == 0) {
if (!ttyeq(*bg, *fg)) {
v = setbg(v, (*bg = *fg));
}
*glyph = kGlyphs[0][0];
}
do {
v = copyglyph(v, *glyph);
*x += 2;
*c += 2;
if (*x >= n) break;
copychunk(chunk, *c, n);
} while (chunkeq(chunk, lastchunk));
*x -= 2;
*c -= 2;
return v;
}
/**
* Maps 2×2 pixel chunks onto ANSI UNICODE cells.
* @note h/t Nick Black for his quadrant blitting work on notcurses
*/
char *ttyraster(char *v, const struct TtyRgb *c, size_t yn, size_t n,
struct TtyRgb bg, struct TtyRgb fg) {
unsigned y, x;
struct Pick p;
struct Glyph glyph;
struct TtyRgb chun[4], lastchunk[4];
for (y = 0; y < yn; y += 2, c += n) {
if (y) *v++ = '\r', *v++ = '\n';
for (x = 0; x < n; x += 2, c += 2) {
copychunk(chun, c, n);
if (ttyquant()->alg == kTtyQuantTrue) {
if (ttyquant()->blocks == kTtyBlocksCp437) {
p = pickblock_cp437_true(chun[TL], chun[TR], chun[BL], chun[BR]);
} else {
p = pickblock_unicode_true(chun[TL], chun[TR], chun[BL], chun[BR]);
}
} else {
if (ttyquant()->blocks == kTtyBlocksCp437) {
p = pickblock_cp437_ansi(chun[TL], chun[TR], chun[BL], chun[BR]);
} else {
p = pickblock_unicode_ansi(chun[TL], chun[TR], chun[BL], chun[BR]);
}
}
v = copyblock(v, chun, p, &bg, &fg, &glyph);
memcpy(lastchunk, chun, sizeof(chun));
}
}
*v = '\0';
return v;
}

155
dsp/tty/ttyraw.c Normal file
View file

@ -0,0 +1,155 @@
/*-*- 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/tty.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/termios.h"
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/rbx.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/x/x.h"
#define FD STDOUT_FILENO
static struct TtyRaw {
bool setup;
bool noreentry;
bool initialized;
enum TtyRawFlags flags;
sigaction_f next[10];
unsigned char sigs[10];
struct termios old;
} 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;
}
}
static textstartup int ttyraw_enable(void) {
int rc;
g_ttyraw.setup = (rc = ttyraw_setup()) != -1 || g_ttyraw.setup;
return rc;
}
static textstartup void ttyraw_hidecursor(void) {
if (!g_ttyraw.setup) return;
if (g_ttyraw.flags & kTtyCursor) return;
ttyhidecursor(FD);
}
static textexit int ttyraw_disable(void) {
if (!g_ttyraw.setup) return 0;
ttyshowcursor(FD);
return ttyrestore(FD, &g_ttyraw.old);
}
static textexit void ttyraw_onexit(void) {
ttyraw_disable();
}
static relegated void ttyraw_onsig(int sig, struct siginfo *info,
struct ucontext *ctx) {
size_t i;
if (g_ttyraw.noreentry) _Exit(128 + sig);
g_ttyraw.noreentry = true;
if (g_ttyraw.flags != -1) {
if (sig == SIGCONT) {
ttyraw_enable();
} else {
ttyraw_disable();
}
}
for (i = 0; i < ARRAYLEN(g_ttyraw.sigs); ++i) {
if (g_ttyraw.sigs[i] == sig) {
if (g_ttyraw.next[i] != SIG_IGN) {
if (g_ttyraw.next[i] != SIG_DFL) {
g_ttyraw.next[i](sig, info, ctx);
} else if (sig != SIGCONT) {
_Exit(128 + sig);
}
}
break;
}
}
g_ttyraw.noreentry = false;
}
static textstartup void ttyraw_initsig(int sig, unsigned flags, unsigned mask) {
static unsigned i;
struct sigaction old;
g_ttyraw.next[i] = xsigaction(sig, ttyraw_onsig, flags, mask, &old) != -1
? old.sa_sigaction
: SIG_DFL;
g_ttyraw.sigs[i++] = sig;
}
static textstartup void ttyraw_init(void) {
unsigned crashmask = ~(SIGILL | SIGBUS | SIGSEGV | SIGABRT);
ttyraw_initsig(SIGILL, SA_SIGINFO | SA_NODEFER | SA_ONSTACK, crashmask);
ttyraw_initsig(SIGSEGV, SA_SIGINFO | SA_NODEFER | SA_ONSTACK, crashmask);
ttyraw_initsig(SIGBUS, SA_SIGINFO | SA_NODEFER | SA_ONSTACK, crashmask);
ttyraw_initsig(SIGABRT, SA_SIGINFO | SA_NODEFER, crashmask);
ttyraw_initsig(SIGFPE, SA_SIGINFO | SA_RESTART, crashmask);
ttyraw_initsig(SIGTRAP, SA_SIGINFO | SA_RESTART, crashmask);
ttyraw_initsig(SIGHUP, SA_SIGINFO | SA_RESTART, crashmask);
ttyraw_initsig(SIGINT, SA_SIGINFO | SA_RESTART, crashmask);
ttyraw_initsig(SIGQUIT, SA_SIGINFO | SA_RESTART, crashmask);
ttyraw_initsig(SIGCONT, SA_SIGINFO | SA_RESTART, crashmask);
atexit(ttyraw_onexit);
}
/**
* Sets raw mode, safely, the easy way.
*
* This should be called after your signal handlers have been installed.
*/
textstartup int ttyraw(enum TtyRawFlags flags) {
int rc;
if ((g_ttyraw.flags = flags) != -1) {
if (!g_ttyraw.initialized) {
g_ttyraw.initialized = true;
ttyraw_init();
}
if ((rc = ttyraw_enable()) != -1) {
ttyraw_hidecursor();
}
} else {
rc = ttyraw_disable();
}
cancolor();
return rc;
}

12
dsp/tty/ttyrgb.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef COSMOPOLITAN_DSP_TTY_RGB_H_
#define COSMOPOLITAN_DSP_TTY_RGB_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct TtyRgb {
uint8_t r, g, b, xt;
};
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_DSP_TTY_RGB_H_ */

72
dsp/tty/windex-avx2.S Normal file
View file

@ -0,0 +1,72 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.h"
.yoink __FILE__
/ Returns index of minimum uint16 in array.
/
/ @param rdi points to nonempty array
/ @param rsi is item count divisible by 16
/ @note needs avx2 (haswell+)
windex$avx2:
push %rbp
mov %rsp,%rbp
.profilable
and $-32,%rsp
sub $32,%rsp
vmovdqa (%rdi),%ymm1
vmovdqa .Lidx(%rip),%ymm3
vmovdqa .Linc(%rip),%ymm5
cmp $16,%esi
jbe 2f
vmovdqa %ymm3,%ymm0
mov $16,%eax
3: vpaddw %ymm0,%ymm5,%ymm0
mov %eax,%edx
vmovdqa (%rdi,%rdx,2),%ymm2
vpcmpgtw %ymm2,%ymm1,%ymm4
vpblendvb %ymm4,%ymm0,%ymm3,%ymm3
vpminsw %ymm1,%ymm2,%ymm1
add $16,%eax
cmp %eax,%esi
ja 3b
2: vphminposuw %xmm1,%xmm0
vextracti128 $0x1,%ymm1,%xmm1
vphminposuw %xmm1,%xmm1
vmovdqa %ymm3,(%rsp)
vmovq %xmm0,%rdx
vmovq %xmm1,%rax
cmp %dx,%ax
jbe 4f
sar $16,%rdx
movzwl %dx,%edx
movzwl (%rsp,%rdx,2),%eax
jmp 5f
4: sar $16,%rax
movzwl %ax,%eax
movzwl 16(%rsp,%rax,2),%eax
5: vzeroupper
leave
ret
.endfn windex$avx2,globl
.rodata.cst32
.Lidx: .short 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
.Linc: .value 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16

34
dsp/tty/windex-k8.c Normal file
View file

@ -0,0 +1,34 @@
/*-*- 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/tty.h"
#include "libc/assert.h"
unsigned windex$k8(short *a, size_t n) {
unsigned short min, res, i;
res = 0;
min = a[0];
for (i = 1; i < n; ++i) {
if (a[i] < min) {
min = a[i];
res = i;
}
}
return res;
}

62
dsp/tty/windex-sse4.S Normal file
View file

@ -0,0 +1,62 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.h"
.yoink __FILE__
/ Returns index of minimum positive int16 in array.
/
/ @param rdi points to nonempty array
/ @param esi is 16-byte aligned 8+ / 8 multiple array item count
/ @note needs sse4 (nehalem+)
windex$sse4:
push %rbp
mov %rsp,%rbp
.profilable
mov $8,%eax
sub $32,%rsp
movdqa (%rdi),%xmm2
movdqa .Lidx(%rip),%xmm1
movdqa .Linc(%rip),%xmm6
movdqa %xmm1,%xmm3
0: cmp %eax,%esi
je 1f
add $8,%eax
movdqa -16(%rdi,%rax,2),%xmm4
movdqa %xmm2,%xmm7
movdqa %xmm3,%xmm5
paddw %xmm6,%xmm5
movdqa %xmm5,%xmm3
pcmpgtw %xmm4,%xmm7
pminsw %xmm4,%xmm2
movdqa %xmm7,%xmm0
pblendvb %xmm0,%xmm5,%xmm1
jmp 0b
1: phminposuw %xmm2,%xmm0
movd %xmm0,%eax
movdqa %xmm1,-32(%rbp)
shr $16,%eax
movzwl -32(%rbp,%rax,2),%eax
leave
ret
.endfn windex$sse4,globl
.rodata.cst16
.Lidx: .short 0,1,2,3,4,5,6,7
.Linc: .value 8,8,8,8,8,8,8,8

43
dsp/tty/windex.S Normal file
View file

@ -0,0 +1,43 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/nexgen32e/x86feature.h"
#include "libc/macros.h"
.yoink __FILE__
/ Dispatches to fastest windex() implementation.
.initbss 300,_init_windex
windex: .quad 0
.endobj windex,globl
.previous
.init.start 300,_init_windex
ezlea windex$avx2,ax
#if !X86_NEED(AVX2)
ezlea windex$sse4,dx
testb X86_HAVE(AVX2)+kCpuids(%rip)
cmovz %rdx,%rax
#endif /* AVX */
#if !X86_NEED(SSE4_2)
ezlea windex$k8,dx
testb X86_HAVE(SSE4_2)+kCpuids(%rip)
cmovz %rdx,%rax
#endif /* SSE4 */
stosq
.init.end 300,_init_windex

10
dsp/tty/windex.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef COSMOPOLITAN_DSP_TTY_WINDEX_H_
#define COSMOPOLITAN_DSP_TTY_WINDEX_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern unsigned (*const windex)(uint16_t *, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_DSP_TTY_WINDEX_H_ */

59
dsp/tty/write.c Normal file
View file

@ -0,0 +1,59 @@
/*-*- 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/tty.h"
#include "libc/calls/calls.h"
#include "libc/calls/termios.h"
#include "libc/errno.h"
#include "libc/sock/sock.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/termios.h"
/**
* Sends data to teletypewriter the pain-free way.
*
* This function blocks forever until the full amount is transmitted,
* regardless of whether or not the character device is in non-blocking
* mode, regardless of whether or not it's interrupted by a signal. It
* can still be escaped by longjmp'ing out of a signal handler.
*
* @return 0 on success, or -1 w/ errno
*/
int ttywrite(int fd, const void *data, size_t size) {
char *p;
ssize_t rc;
size_t wrote, n;
p = data;
n = size;
do {
TryAgain:
if ((rc = write(fd, p, n)) != -1) {
wrote = rc;
p += wrote;
n -= wrote;
} else if (errno == EINTR) {
goto TryAgain;
} else if (errno == EAGAIN) {
poll((struct pollfd[]){{fd, POLLOUT}}, 1, -1);
} else {
return -1;
}
} while (n);
return 0;
}