tmux/local.c
2007-11-25 10:59:44 +00:00

794 lines
19 KiB
C

/* $Id: local.c,v 1.22 2007-11-25 10:59:44 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <curses.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#define TTYDEFCHARS
/* glibc requires unistd.h before termios.h for TTYDEFCHARS. */
#include <unistd.h>
#include <termios.h>
#include <term.h>
#include "tmux.h"
/*
* Functions to translate input and write output to the local client terminal.
* This file should probably be called tty or terminal.c.
*/
int local_cmp(const void *, const void *);
int local_putc(int);
void local_putp(const char *);
void local_attributes(u_char, u_char);
u_char local_translate_acs(u_char);
/* Local key types and key codes. */
struct local_key {
const char *name;
char *string;
size_t size;
int code;
};
struct local_key local_keys[] = {
{ "ka1", NULL, 0, KEYC_A1 },
{ "ka3", NULL, 0, KEYC_A3 },
{ "kb2", NULL, 0, KEYC_B2 },
{ "kbeg", NULL, 0, KEYC_BEG },
{ "kcbt", NULL, 0, KEYC_BTAB },
{ "kc1", NULL, 0, KEYC_C1 },
{ "kc3", NULL, 0, KEYC_C3 },
{ "kcan", NULL, 0, KEYC_CANCEL },
{ "ktbc", NULL, 0, KEYC_CATAB },
{ "kclr", NULL, 0, KEYC_CLEAR },
{ "kclo", NULL, 0, KEYC_CLOSE },
{ "kcmd", NULL, 0, KEYC_COMMAND },
{ "kcpy", NULL, 0, KEYC_COPY },
{ "kcrt", NULL, 0, KEYC_CREATE },
{ "kctab", NULL, 0, KEYC_CTAB },
{ "kdch1", NULL, 0, KEYC_DC },
{ "kdl1", NULL, 0, KEYC_DL },
{ "kcud1", NULL, 0, KEYC_DOWN },
{ "krmir", NULL, 0, KEYC_EIC },
{ "kend", NULL, 0, KEYC_END },
{ "kent", NULL, 0, KEYC_ENTER },
{ "kel", NULL, 0, KEYC_EOL },
{ "ked", NULL, 0, KEYC_EOS },
{ "kext", NULL, 0, KEYC_EXIT },
{ "kf0", NULL, 0, KEYC_F0 },
{ "kf1", NULL, 0, KEYC_F1 },
{ "kf10", NULL, 0, KEYC_F10 },
{ "kf11", NULL, 0, KEYC_F11 },
{ "kf12", NULL, 0, KEYC_F12 },
{ "kf13", NULL, 0, KEYC_F13 },
{ "kf14", NULL, 0, KEYC_F14 },
{ "kf15", NULL, 0, KEYC_F15 },
{ "kf16", NULL, 0, KEYC_F16 },
{ "kf17", NULL, 0, KEYC_F17 },
{ "kf18", NULL, 0, KEYC_F18 },
{ "kf19", NULL, 0, KEYC_F19 },
{ "kf2", NULL, 0, KEYC_F2 },
{ "kf20", NULL, 0, KEYC_F20 },
{ "kf21", NULL, 0, KEYC_F21 },
{ "kf22", NULL, 0, KEYC_F22 },
{ "kf23", NULL, 0, KEYC_F23 },
{ "kf24", NULL, 0, KEYC_F24 },
{ "kf25", NULL, 0, KEYC_F25 },
{ "kf26", NULL, 0, KEYC_F26 },
{ "kf27", NULL, 0, KEYC_F27 },
{ "kf28", NULL, 0, KEYC_F28 },
{ "kf29", NULL, 0, KEYC_F29 },
{ "kf3", NULL, 0, KEYC_F3 },
{ "kf30", NULL, 0, KEYC_F30 },
{ "kf31", NULL, 0, KEYC_F31 },
{ "kf32", NULL, 0, KEYC_F32 },
{ "kf33", NULL, 0, KEYC_F33 },
{ "kf34", NULL, 0, KEYC_F34 },
{ "kf35", NULL, 0, KEYC_F35 },
{ "kf36", NULL, 0, KEYC_F36 },
{ "kf37", NULL, 0, KEYC_F37 },
{ "kf38", NULL, 0, KEYC_F38 },
{ "kf39", NULL, 0, KEYC_F39 },
{ "kf4", NULL, 0, KEYC_F4 },
{ "kf40", NULL, 0, KEYC_F40 },
{ "kf41", NULL, 0, KEYC_F41 },
{ "kf42", NULL, 0, KEYC_F42 },
{ "kf43", NULL, 0, KEYC_F43 },
{ "kf44", NULL, 0, KEYC_F44 },
{ "kf45", NULL, 0, KEYC_F45 },
{ "kf46", NULL, 0, KEYC_F46 },
{ "kf47", NULL, 0, KEYC_F47 },
{ "kf48", NULL, 0, KEYC_F48 },
{ "kf49", NULL, 0, KEYC_F49 },
{ "kf5", NULL, 0, KEYC_F5 },
{ "kf50", NULL, 0, KEYC_F50 },
{ "kf51", NULL, 0, KEYC_F51 },
{ "kf52", NULL, 0, KEYC_F52 },
{ "kf53", NULL, 0, KEYC_F53 },
{ "kf54", NULL, 0, KEYC_F54 },
{ "kf55", NULL, 0, KEYC_F55 },
{ "kf56", NULL, 0, KEYC_F56 },
{ "kf57", NULL, 0, KEYC_F57 },
{ "kf58", NULL, 0, KEYC_F58 },
{ "kf59", NULL, 0, KEYC_F59 },
{ "kf6", NULL, 0, KEYC_F6 },
{ "kf60", NULL, 0, KEYC_F60 },
{ "kf61", NULL, 0, KEYC_F61 },
{ "kf62", NULL, 0, KEYC_F62 },
{ "kf63", NULL, 0, KEYC_F63 },
{ "kf7", NULL, 0, KEYC_F7 },
{ "kf8", NULL, 0, KEYC_F8 },
{ "kf9", NULL, 0, KEYC_F9 },
{ "kfnd", NULL, 0, KEYC_FIND },
{ "khlp", NULL, 0, KEYC_HELP },
{ "khome", NULL, 0, KEYC_HOME },
{ "kich1", NULL, 0, KEYC_IC },
{ "kil1", NULL, 0, KEYC_IL },
{ "kcub1", NULL, 0, KEYC_LEFT },
{ "kll", NULL, 0, KEYC_LL },
{ "kmrk", NULL, 0, KEYC_MARK },
{ "kmsg", NULL, 0, KEYC_MESSAGE },
{ "kmov", NULL, 0, KEYC_MOVE },
{ "knxt", NULL, 0, KEYC_NEXT },
{ "knp", NULL, 0, KEYC_NPAGE },
{ "kopn", NULL, 0, KEYC_OPEN },
{ "kopt", NULL, 0, KEYC_OPTIONS },
{ "kpp", NULL, 0, KEYC_PPAGE },
{ "kprv", NULL, 0, KEYC_PREVIOUS },
{ "kprt", NULL, 0, KEYC_PRINT },
{ "krdo", NULL, 0, KEYC_REDO },
{ "kref", NULL, 0, KEYC_REFERENCE },
{ "krfr", NULL, 0, KEYC_REFRESH },
{ "krpl", NULL, 0, KEYC_REPLACE },
{ "krst", NULL, 0, KEYC_RESTART },
{ "kres", NULL, 0, KEYC_RESUME },
{ "kcuf1", NULL, 0, KEYC_RIGHT },
{ "ksav", NULL, 0, KEYC_SAVE },
{ "kBEG", NULL, 0, KEYC_SBEG },
{ "kCAN", NULL, 0, KEYC_SCANCEL },
{ "kCMD", NULL, 0, KEYC_SCOMMAND },
{ "kCPY", NULL, 0, KEYC_SCOPY },
{ "kCRT", NULL, 0, KEYC_SCREATE },
{ "kDC", NULL, 0, KEYC_SDC },
{ "kDL", NULL, 0, KEYC_SDL },
{ "kslt", NULL, 0, KEYC_SELECT },
{ "kEND", NULL, 0, KEYC_SEND },
{ "kEOL", NULL, 0, KEYC_SEOL },
{ "kEXT", NULL, 0, KEYC_SEXIT },
{ "kind", NULL, 0, KEYC_SF },
{ "kFND", NULL, 0, KEYC_SFIND },
{ "kHLP", NULL, 0, KEYC_SHELP },
{ "kHOM", NULL, 0, KEYC_SHOME },
{ "kIC", NULL, 0, KEYC_SIC },
{ "kLFT", NULL, 0, KEYC_SLEFT },
{ "kMSG", NULL, 0, KEYC_SMESSAGE },
{ "kMOV", NULL, 0, KEYC_SMOVE },
{ "kNXT", NULL, 0, KEYC_SNEXT },
{ "kOPT", NULL, 0, KEYC_SOPTIONS },
{ "kPRV", NULL, 0, KEYC_SPREVIOUS },
{ "kPRT", NULL, 0, KEYC_SPRINT },
{ "kri", NULL, 0, KEYC_SR },
{ "kRDO", NULL, 0, KEYC_SREDO },
{ "kRPL", NULL, 0, KEYC_SREPLACE },
{ "kRIT", NULL, 0, KEYC_SRIGHT },
{ "kRES", NULL, 0, KEYC_SRSUME },
{ "kSAV", NULL, 0, KEYC_SSAVE },
{ "kSPD", NULL, 0, KEYC_SSUSPEND },
{ "khts", NULL, 0, KEYC_STAB },
{ "kUND", NULL, 0, KEYC_SUNDO },
{ "kspd", NULL, 0, KEYC_SUSPEND },
{ "kund", NULL, 0, KEYC_UNDO },
{ "kcuu1", NULL, 0, KEYC_UP },
{ "pmous", NULL, 0, KEYC_MOUSE },
{ NULL, NULL, 0, KEYC_NONE }
};
/* tty file descriptor and local terminal buffers. */
int local_fd = -1;
int local_log = -1;
struct buffer *local_in;
struct buffer *local_out;
struct termios local_tio;
u_char local_attr;
u_char local_colr;
/* Initialise local terminal. */
int
local_init(struct buffer **in, struct buffer **out)
{
char *tty, *path;
const char *name;
int mode, error;
struct termios tio;
struct local_key *lk;
u_int i, j;
static const char *const reqd[] = {
"carriage_return",
"change_scroll_region",
"clear_screen",
"clr_bol",
"clr_eol",
"cursor_address",
"cursor_left",
"cursor_down",
"parm_dch",
"parm_delete_line",
"parm_down_cursor",
"parm_ich",
"parm_insert_line",
"parm_left_cursor",
"parm_right_cursor",
"parm_up_cursor",
"scroll_reverse",
NULL
};
if ((tty = ttyname(STDOUT_FILENO)) == NULL)
fatal("ttyname failed");
if ((local_fd = open(tty, O_RDWR)) == -1)
fatal("open failed");
if ((mode = fcntl(local_fd, F_GETFL)) == -1)
fatal("fcntl failed");
if (fcntl(local_fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed");
if ((name = getenv("TERM")) == NULL || *name == '\0')
name = "unknown";
if (newterm(name, stdout, stdin) == NULL) {
log_warnx("error opening terminal: %s", name);
return (-1);
}
for (i = 0; reqd[i] != NULL; i++) {
error = 0;
for (j = 0; strfnames[j] != NULL; j++) {
if (strcmp(strfnames[j], reqd[i]) == 0) {
if (strcodes[j] == NULL)
error = -1;
break;
}
}
if (error != -1) {
for (j = 0; numfnames[j] != NULL; j++) {
if (strcmp(numfnames[j], reqd[i]) == 0) {
if (numcodes[j] == NULL)
error = -1;
break;
}
}
}
if (error != -1) {
for (j = 0; boolfnames[j] != NULL; j++) {
if (strcmp(boolfnames[j], reqd[i]) == 0) {
if (boolcodes[j] == NULL)
error = -1;
break;
}
}
}
if (error == -1) {
log_warnx("required capability missing: %s", reqd[i]);
return (-1);
}
}
*in = local_in = buffer_create(BUFSIZ);
*out = local_out = buffer_create(BUFSIZ);
if (tcgetattr(local_fd, &local_tio) != 0)
fatal("tcgetattr failed");
memset(&tio, 0, sizeof tio);
tio.c_iflag = TTYDEF_IFLAG & ~(IXON|IXOFF|ICRNL|INLCR);
tio.c_oflag = TTYDEF_OFLAG & ~(OPOST|ONLCR|OCRNL|ONLRET);
tio.c_lflag =
TTYDEF_LFLAG & ~(IEXTEN|ICANON|ECHO|ECHOE|ECHOKE|ECHOCTL|ISIG);
tio.c_cflag = TTYDEF_CFLAG;
memcpy(&tio.c_cc, ttydefchars, sizeof tio.c_cc);
cfsetspeed(&tio, TTYDEF_SPEED);
if (tcsetattr(local_fd, TCSANOW, &tio) != 0)
fatal("tcsetattr failed");
if (enter_ca_mode != NULL)
local_putp(enter_ca_mode);
if (keypad_xmit != NULL)
local_putp(keypad_xmit);
if (ena_acs != NULL)
local_putp(ena_acs);
local_putp(clear_screen);
for (lk = local_keys; lk->name != NULL; lk++) {
lk->string = tigetstr(lk->name);
if (lk->string == (char *) -1 || lk->string == (char *) 0)
lk->string = NULL;
else {
lk->size = strlen(lk->string);
log_debug("string for %s (%d): \"%s\", length %zu",
lk->name, lk->code, lk->string, lk->size);
}
}
qsort(local_keys, sizeof local_keys /
sizeof local_keys[0], sizeof local_keys[0], local_cmp);
local_attr = 0;
local_colr = 0x88;
if (debug_level > 2) {
xasprintf(
&path, "%s-output-%ld.log", __progname,(long) getpid());
local_log = open(
path, O_RDWR|O_APPEND|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
xfree(path);
}
return (local_fd);
}
/* Compare keys. */
int
local_cmp(const void *ptr1, const void *ptr2)
{
const struct local_key *lk1 = ptr1, *lk2 = ptr2;
if (lk1->string == NULL && lk2->string == NULL)
return (0);
if (lk1->string == NULL)
return (1);
if (lk2->string == NULL)
return (-1);
return (lk2->size - lk1->size);
}
/* Tidy up and reset local terminal. */
void
local_done(void)
{
struct winsize ws;
buffer_destroy(local_in);
buffer_destroy(local_out);
if (tcsetattr(local_fd, TCSANOW, &local_tio) != 0)
fatal("tcsetattr failed");
close(local_fd);
if (local_log != -1)
close(local_log);
if (change_scroll_region != NULL) {
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl(TIOCGWINSZ)");
putp(tparm(change_scroll_region, 0, ws.ws_row - 1));
}
endwin();
if (keypad_local != NULL)
putp(keypad_local); /* not local_putp */
if (exit_ca_mode != NULL)
putp(exit_ca_mode);
putp(clear_screen);
if (cursor_normal != NULL)
putp(cursor_normal);
if (exit_attribute_mode != NULL)
putp(exit_attribute_mode);
}
/* Put a character. Used as parameter to tputs. */
int
local_putc(int c)
{
u_char ch = c;
if (c < 0 || c > (int) UCHAR_MAX)
fatalx("invalid character");
if (local_log != -1)
write(local_log, &ch, 1);
if (acs_chars != NULL && local_attr & ATTR_DRAWING) {
ch = local_translate_acs(ch);
if (ch == '\0')
ch = '?';
}
buffer_write(local_out, &ch, 1);
return (c);
}
/* Put terminfo string. */
void
local_putp(const char *s)
{
if (s == NULL)
fatalx("null pointer");
tputs(s, 1, local_putc);
}
/* Return waiting keys if any. */
int
local_key(void)
{
struct local_key *lk;
u_int i;
size_t size;
size = BUFFER_USED(local_in);
if (size == 0)
return (KEYC_NONE);
i = 0;
lk = local_keys;
while (lk->string != NULL) {
if (strncmp(BUFFER_OUT(local_in), lk->string, size) == 0) {
if (size < lk->size)
return (KEYC_NONE);
log_debug("got key: "
"%s %d \"%s\"", lk->name, lk->code, lk->string);
buffer_remove(local_in, lk->size);
return (lk->code);
}
i++;
lk = local_keys + i;
}
return (input_extract8(local_in));
}
/* Display output data. */
void
local_output(struct buffer *b, size_t size)
{
u_char ch;
uint16_t ua, ub;
while (size != 0) {
if (size < 1)
break;
size--;
ch = input_extract8(b);
if (ch != '\e') {
switch (ch) {
case '\n': /* LF */
local_putp(cursor_down);
break;
case '\r': /* CR */
local_putp(carriage_return);
break;
case '\007': /* BEL */
if (bell != NULL)
local_putp(bell);
break;
case '\010': /* BS */
local_putp(cursor_left);
break;
default:
local_putc(ch);
break;
}
continue;
}
if (size < 1)
fatalx("underflow");
size--;
ch = input_extract8(b);
log_debug("received code %hhu", ch);
switch (ch) {
case CODE_CURSORUP:
if (size < 2)
fatalx("CODE_CURSORUP underflow");
size -= 2;
ua = input_extract16(b);
local_putp(tparm(parm_up_cursor, ua));
break;
case CODE_CURSORDOWN:
if (size < 2)
fatalx("CODE_CURSORDOWN underflow");
size -= 2;
ua = input_extract16(b);
local_putp(tparm(parm_down_cursor, ua));
break;
case CODE_CURSORRIGHT:
if (size < 2)
fatalx("CODE_CURSORRIGHT underflow");
size -= 2;
ua = input_extract16(b);
local_putp(tparm(parm_right_cursor, ua));
break;
case CODE_CURSORLEFT:
if (size < 2)
fatalx("CODE_CURSORLEFT underflow");
size -= 2;
ua = input_extract16(b);
local_putp(tparm(parm_left_cursor, ua));
break;
case CODE_CURSORMOVE:
if (size < 4)
fatalx("CODE_CURSORMOVE underflow");
size -= 4;
ua = input_extract16(b);
ub = input_extract16(b);
local_putp(tparm(cursor_address, ua - 1, ub - 1));
break;
case CODE_CLEARENDOFLINE:
local_putp(clr_eol);
break;
case CODE_CLEARSTARTOFLINE:
local_putp(clr_bol);
break;
case CODE_CLEARLINE:
local_putp(clr_eol); /* XXX */
break;
case CODE_INSERTLINE:
if (size < 2)
fatalx("CODE_INSERTLINE underflow");
size -= 2;
ua = input_extract16(b);
local_putp(tparm(parm_insert_line, ua));
break;
case CODE_DELETELINE:
if (size < 2)
fatalx("CODE_DELETELINE underflow");
size -= 2;
ua = input_extract16(b);
local_putp(tparm(parm_delete_line, ua));
break;
case CODE_INSERTCHARACTER:
if (size < 2)
fatalx("CODE_INSERTCHARACTER underflow");
size -= 2;
ua = input_extract16(b);
local_putp(tparm(parm_ich, ua));
break;
case CODE_DELETECHARACTER:
if (size < 2)
fatalx("CODE_DELETECHARACTER underflow");
size -= 2;
ua = input_extract16(b);
local_putp(tparm(parm_dch, ua));
break;
case CODE_CURSORON:
if (cursor_normal != NULL)
local_putp(cursor_normal);
break;
case CODE_CURSOROFF:
if (cursor_invisible != NULL)
local_putp(cursor_invisible);
break;
case CODE_REVERSEINDEX:
local_putp(scroll_reverse);
break;
case CODE_SCROLLREGION:
if (size < 4)
fatalx("CODE_SCROLLREGION underflow");
size -= 4;
ua = input_extract16(b);
ub = input_extract16(b);
local_putp(tparm(change_scroll_region, ua - 1, ub - 1));
break;
case CODE_INSERTON:
if (enter_insert_mode != NULL)
local_putp(enter_insert_mode);
break;
case CODE_INSERTOFF:
if (exit_insert_mode != NULL)
local_putp(exit_insert_mode);
break;
case CODE_KCURSOROFF:
/*
t = tigetstr("CE");
if (t != (char *) 0 && t != (char *) -1)
local_putp(t);
*/
break;
case CODE_KCURSORON:
/*
t = tigetstr("CS");
if (t != (char *) 0 && t != (char *) -1)
local_putp(t);
*/
break;
case CODE_KKEYPADOFF:
/*
if (keypad_local != NULL)
local_putp(keypad_local);
*/
break;
case CODE_KKEYPADON:
/*
if (keypad_xmit != NULL)
local_putp(keypad_xmit);
*/
break;
case CODE_TITLE:
if (size < 2)
fatalx("CODE_TITLE underflow");
size -= 2;
ua = input_extract16(b);
if (size < ua)
fatalx("CODE_TITLE underflow");
size -= ua;
buffer_remove(b, ua);
break;
case CODE_ATTRIBUTES:
if (size < 4)
fatalx("CODE_ATTRIBUTES underflow");
size -= 4;
ua = input_extract16(b);
ub = input_extract16(b);
local_attributes(ua, ub);
break;
}
}
}
void
local_attributes(u_char attr, u_char colr)
{
u_char fg, bg;
if (attr == local_attr && colr == local_colr)
return;
/* If any bits are being cleared, reset everything. */
if (local_attr & ~attr) {
if ((local_attr & ATTR_DRAWING) &&
exit_alt_charset_mode != NULL)
local_putp(exit_alt_charset_mode);
local_putp(exit_attribute_mode);
local_colr = 0x88;
local_attr = 0;
}
/* Filter out bits already set. */
attr &= ~local_attr;
local_attr |= attr;
if ((attr & ATTR_BRIGHT) && enter_bold_mode != NULL)
local_putp(enter_bold_mode);
if ((attr & ATTR_DIM) && enter_dim_mode != NULL)
local_putp(enter_dim_mode);
if ((attr & ATTR_ITALICS) && enter_standout_mode != NULL)
local_putp(enter_standout_mode);
if ((attr & ATTR_UNDERSCORE) && enter_underline_mode != NULL)
local_putp(enter_underline_mode);
if ((attr & ATTR_BLINK) && enter_blink_mode != NULL)
local_putp(enter_blink_mode);
if ((attr & ATTR_REVERSE) && enter_reverse_mode != NULL)
local_putp(enter_reverse_mode);
if ((attr & ATTR_HIDDEN) && enter_secure_mode != NULL)
local_putp(enter_secure_mode);
if ((attr & ATTR_DRAWING) && enter_alt_charset_mode != NULL)
local_putp(enter_alt_charset_mode);
fg = (colr >> 4) & 0xf;
if (fg != ((local_colr >> 4) & 0xf)) {
if (tigetflag("AX") == TRUE) {
if (fg == 7)
fg = 8;
} else {
if (fg == 8)
fg = 7;
}
if (fg == 8)
local_putp("\e[39m");
else if (set_a_foreground != NULL)
local_putp(tparm(set_a_foreground, fg));
}
bg = colr & 0xf;
if (bg != (local_colr & 0xf)) {
if (tigetflag("AX") == TRUE) {
if (bg == 0)
bg = 8;
} else {
if (bg == 8)
bg = 0;
}
if (bg == 8)
local_putp("\e[49m");
else if (set_a_background != NULL)
local_putp(tparm(set_a_background, bg));
}
local_colr = colr;
}
u_char
local_translate_acs(u_char ch)
{
switch (ch) {
case '~':
return (ACS_BULLET);
case '}':
return (ACS_STERLING);
case '|':
return (ACS_NEQUAL);
case '{':
return (ACS_PI);
case 'z':
return (ACS_GEQUAL);
case 'y':
return (ACS_LEQUAL);
case 'x':
return (ACS_VLINE);
case 'w':
return (ACS_TTEE);
case 'v':
return (ACS_BTEE);
case 'u':
return (ACS_RTEE);
case 't':
return (ACS_LTEE);
case 's':
return (ACS_S9);
case 'r':
return (ACS_S7);
case 'q':
return (ACS_HLINE);
case 'p':
return (ACS_S3);
case 'o':
return (ACS_S1);
case 'n':
return (ACS_PLUS);
case 'm':
return (ACS_LLCORNER);
case 'l':
return (ACS_ULCORNER);
case 'k':
return (ACS_URCORNER);
case 'j':
return (ACS_LRCORNER);
case 'i':
return (ACS_LANTERN);
case 'h':
return (ACS_BOARD);
case 'g':
return (ACS_PLMINUS);
case 'f':
return (ACS_DEGREE);
case 'a':
return (ACS_CKBOARD);
case '`':
return (ACS_DIAMOND);
case '0':
return (ACS_BLOCK);
case '.':
return (ACS_DARROW);
case '-':
return (ACS_UARROW);
case ',':
return (ACS_LARROW);
case '+':
return (ACS_RARROW);
}
return (ch);
}