From 2cde36a2c1954174ad46596e23a798f60affd8c6 Mon Sep 17 00:00:00 2001 From: zcake Date: Fri, 15 Jan 2021 09:36:25 +0800 Subject: [PATCH] remove scrollback patch --- config.def.h | 4 +- config.def.h.orig | 499 +++ config.def.h.rej | 11 + config.def.h.rej.orig | 11 + config.def.h.rej.rej | 19 + config.h | 10 +- config.h.orig | 511 +++ config.h.rej | 50 + patches/st-scrollback-20200419-72e3f6c.diff | 351 -- .../st-scrollback-mouse-20191024-a2c479c.diff | 13 - st | Bin 123840 -> 119624 bytes st.c | 121 +- st.c.orig | 3048 ++++++++++++++++ st.c.orig.orig | 3051 +++++++++++++++++ st.c.rej | 14 + st.h | 3 +- st.h.orig | 134 + st.h.orig.orig | 142 + st.h.orig.rej | 16 + st.h.rej | 11 + st.h.rej.orig | 11 + st.h.rej.rej | 19 + st.o | Bin 83768 -> 78136 bytes x.o | Bin 82992 -> 82784 bytes 24 files changed, 7578 insertions(+), 471 deletions(-) create mode 100644 config.def.h.orig create mode 100644 config.def.h.rej create mode 100644 config.def.h.rej.orig create mode 100644 config.def.h.rej.rej create mode 100644 config.h.orig create mode 100644 config.h.rej delete mode 100644 patches/st-scrollback-20200419-72e3f6c.diff delete mode 100644 patches/st-scrollback-mouse-20191024-a2c479c.diff create mode 100644 st.c.orig create mode 100644 st.c.orig.orig create mode 100644 st.c.rej create mode 100644 st.h.orig create mode 100644 st.h.orig.orig create mode 100644 st.h.orig.rej create mode 100644 st.h.rej create mode 100644 st.h.rej.orig create mode 100644 st.h.rej.rej diff --git a/config.def.h b/config.def.h index 4280e97..a807f2b 100644 --- a/config.def.h +++ b/config.def.h @@ -168,7 +168,7 @@ unsigned int defaultunderline = 7; * 7: Blinking st cursor * 8: Steady st cursor */ -static unsigned int cursorstyle = 4; +static unsigned int cursorstyle = 1; static Rune stcursor = 0x2603; /* snowman (U+2603) */ /* @@ -236,8 +236,6 @@ static Shortcut shortcuts[] = { { ShiftMask, XK_Insert, selpaste, {.i = 0} }, { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, { TERMMOD, XK_I, iso14755, {.i = 0} }, - { ShiftMask, XK_Page_Up, kscrollup, {.i = 0.5} }, - { ShiftMask, XK_Page_Down, kscrolldown, {.i = 0.5} }, }; /* diff --git a/config.def.h.orig b/config.def.h.orig new file mode 100644 index 0000000..c76afe4 --- /dev/null +++ b/config.def.h.orig @@ -0,0 +1,499 @@ +/* See LICENSE file for copyright and license details. */ + +/* + * appearance + * + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html + */ +static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; +/* Spare fonts */ +static char *font2[] = { +/* "Inconsolata for Powerline:pixelsize=12:antialias=true:autohint=true", */ +/* "Hack Nerd Font Mono:pixelsize=11:antialias=true:autohint=true", */ +}; + +static int borderpx = 2; + +/* + * What program is execed by st depends of these precedence rules: + * 1: program passed with -e + * 2: scroll and/or utmp + * 3: SHELL environment variable + * 4: value of shell in /etc/passwd + * 5: value of shell in config.h + */ +static char *shell = "/bin/sh"; +char *utmp = NULL; +/* scroll program: to enable use a string like "scroll" */ +char *scroll = "scroll"; +char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; + +/* identification sequence returned in DA and DECID */ +char *vtiden = "\033[?6c"; + +/* Kerning / character bounding-box multipliers */ +static float cwscale = 1.0; +static float chscale = 1.0; + +/* + * word delimiter string + * + * More advanced example: L" `'\"()[]{}" + */ +wchar_t *worddelimiters = L" "; + +/* selection timeouts (in milliseconds) */ +static unsigned int doubleclicktimeout = 300; +static unsigned int tripleclicktimeout = 600; + +/* alt screens */ +int allowaltscreen = 1; + +/* allow certain non-interactive (insecure) window operations such as: + setting the clipboard text */ +int allowwindowops = 0; + +/* + * draw latency range in ms - from new content/keypress/etc until drawing. + * within this range, st draws when content stops arriving (idle). mostly it's + * near minlatency, but it waits longer for slow updates to avoid partial draw. + * low minlatency will tear/flicker more, as it can "detect" idle too early. + */ +static double minlatency = 8; +static double maxlatency = 33; + +/* + * blinking timeout (set to 0 to disable blinking) for the terminal blinking + * attribute. + */ +static unsigned int blinktimeout = 800; + +/* + * thickness of underline and bar cursors + */ +static unsigned int cursorthickness = 2; + +/* + * bell volume. It must be a value between -100 and 100. Use 0 for disabling + * it + */ +static int bellvolume = 0; + +/* default TERM value */ +char *termname = "st-256color"; + +/* + * spaces per tab + * + * When you are changing this value, don't forget to adapt the »it« value in + * the st.info and appropriately install the st.info in the environment where + * you use this st version. + * + * it#$tabspaces, + * + * Secondly make sure your kernel is not expanding tabs. When running `stty + * -a` »tab0« should appear. You can tell the terminal to not expand tabs by + * running following command: + * + * stty tabs + */ +unsigned int tabspaces = 8; + +/* bg opacity */ +float alpha = 0.8, alphaUnfocused = 0.6; + +/* Terminal colors (16 first used in escape sequence) */ +static const char *colorname[] = { +/* 8 normal colors */ + [0] = "#000000", /* black */ + [1] = "#ff5555", /* red */ + [2] = "#50fa7b", /* green */ + [3] = "#f1fa8c", /* yellow */ + [4] = "#bd93f9", /* blue */ + [5] = "#ff79c6", /* magenta */ + [6] = "#8be9fd", /* cyan */ + [7] = "#bbbbbb", /* white */ + + /* 8 bright colors */ + [8] = "#44475a", /* black */ + [9] = "#ff5555", /* red */ + [10] = "#50fa7b", /* green */ + [11] = "#f1fa8c", /* yellow */ + [12] = "#bd93f9", /* blue */ + [13] = "#ff79c6", /* magenta */ + [14] = "#8be9fd", /* cyan */ + [15] = "#ffffff", /* white */ + + /* special colors */ + [256] = "#282a36", /* background */ + [257] = "#f8f8f2", /* foreground */ +}; +/* + * Default colors (colorname index) + * foreground, background, cursor, reverse cursor + */ +unsigned int defaultfg = 257; +unsigned int defaultbg = 256; +static unsigned int defaultcs = 257; +static unsigned int defaultrcs = 256; +/* ++ * Colors used, when the specific fg == defaultfg. So in reverse mode this ++ * will reverse too. Another logic would only make the simple feature too ++ * complex. ++ */ +unsigned int defaultitalic = 7; +unsigned int defaultunderline = 7; +/* + * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81 + * Default style of cursor + * 0: Blinking block + * 1: Blinking block (default) + * 2: Steady block ("█") + * 3: Blinking underline + * 4: Steady underline ("_") + * 5: Blinking bar + * 6: Steady bar ("|") + * 7: Blinking st cursor + * 8: Steady st cursor + */ +static unsigned int cursorstyle = 4; +static Rune stcursor = 0x2603; /* snowman (U+2603) */ + +/* + * Default columns and rows numbers + */ + +static unsigned int cols = 80; +static unsigned int rows = 24; + +/* + * Default colour and shape of the mouse cursor + */ +static unsigned int mouseshape = XC_xterm; +static unsigned int mousefg = 7; +static unsigned int mousebg = 0; + +/* + * Color used to display font attributes when fontconfig selected a font which + * doesn't match the ones requested. + */ +static unsigned int defaultattr = 11; + +/* + * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set). + * Note that if you want to use ShiftMask with selmasks, set this to an other + * modifier, set to 0 to not use it. + */ +static uint forcemousemod = ShiftMask; + +/* + * Command used to query unicode glyphs. + */ +char *iso14755_cmd = "dmenu -w \"$WINDOWID\" -p codepoint: 0: keypad application mode enabled + * * = 2: term.numlock = 1 + * * < 0: keypad application mode disabled + * appcursor value: + * * 0: no value + * * > 0: cursor application mode enabled + * * < 0: cursor application mode disabled + * + * Be careful with the order of the definitions because st searches in + * this table sequentially, so any XK_ANY_MOD must be in the last + * position for a key. + */ + +/* + * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) + * to be mapped below, add them to this array. + */ +static KeySym mappedkeys[] = { -1 }; + +/* + * State bits to ignore when matching key or button events. By default, + * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored. + */ +static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; + +/* + * This is the huge key array which defines all compatibility to the Linux + * world. Please decide about changes wisely. + */ +static Key key[] = { + /* keysym mask string appkey appcursor */ + { XK_KP_Home, ShiftMask, "\033[2J", 0, -1}, + { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1}, + { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1}, + { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1}, + { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0}, + { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1}, + { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1}, + { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0}, + { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1}, + { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1}, + { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0}, + { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1}, + { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1}, + { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0}, + { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1}, + { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1}, + { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0}, + { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, + { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0}, + { XK_KP_End, ControlMask, "\033[J", -1, 0}, + { XK_KP_End, ControlMask, "\033[1;5F", +1, 0}, + { XK_KP_End, ShiftMask, "\033[K", -1, 0}, + { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0}, + { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0}, + { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0}, + { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0}, + { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0}, + { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0}, + { XK_KP_Insert, ControlMask, "\033[L", -1, 0}, + { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0}, + { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, + { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, + { XK_KP_Delete, ControlMask, "\033[M", -1, 0}, + { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0}, + { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0}, + { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0}, + { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0}, + { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, + { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0}, + { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0}, + { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0}, + { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0}, + { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0}, + { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0}, + { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0}, + { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0}, + { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0}, + { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0}, + { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0}, + { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0}, + { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0}, + { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0}, + { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0}, + { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0}, + { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0}, + { XK_Up, ShiftMask, "\033[1;2A", 0, 0}, + { XK_Up, Mod1Mask, "\033[1;3A", 0, 0}, + { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0}, + { XK_Up, ControlMask, "\033[1;5A", 0, 0}, + { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0}, + { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0}, + { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0}, + { XK_Up, XK_ANY_MOD, "\033[A", 0, -1}, + { XK_Up, XK_ANY_MOD, "\033OA", 0, +1}, + { XK_Down, ShiftMask, "\033[1;2B", 0, 0}, + { XK_Down, Mod1Mask, "\033[1;3B", 0, 0}, + { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0}, + { XK_Down, ControlMask, "\033[1;5B", 0, 0}, + { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0}, + { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0}, + { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0}, + { XK_Down, XK_ANY_MOD, "\033[B", 0, -1}, + { XK_Down, XK_ANY_MOD, "\033OB", 0, +1}, + { XK_Left, ShiftMask, "\033[1;2D", 0, 0}, + { XK_Left, Mod1Mask, "\033[1;3D", 0, 0}, + { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0}, + { XK_Left, ControlMask, "\033[1;5D", 0, 0}, + { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0}, + { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0}, + { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0}, + { XK_Left, XK_ANY_MOD, "\033[D", 0, -1}, + { XK_Left, XK_ANY_MOD, "\033OD", 0, +1}, + { XK_Right, ShiftMask, "\033[1;2C", 0, 0}, + { XK_Right, Mod1Mask, "\033[1;3C", 0, 0}, + { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0}, + { XK_Right, ControlMask, "\033[1;5C", 0, 0}, + { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0}, + { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0}, + { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0}, + { XK_Right, XK_ANY_MOD, "\033[C", 0, -1}, + { XK_Right, XK_ANY_MOD, "\033OC", 0, +1}, + { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0}, + { XK_Return, Mod1Mask, "\033\r", 0, 0}, + { XK_Return, XK_ANY_MOD, "\r", 0, 0}, + { XK_Insert, ShiftMask, "\033[4l", -1, 0}, + { XK_Insert, ShiftMask, "\033[2;2~", +1, 0}, + { XK_Insert, ControlMask, "\033[L", -1, 0}, + { XK_Insert, ControlMask, "\033[2;5~", +1, 0}, + { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, + { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, + { XK_Delete, ControlMask, "\033[M", -1, 0}, + { XK_Delete, ControlMask, "\033[3;5~", +1, 0}, + { XK_Delete, ShiftMask, "\033[2K", -1, 0}, + { XK_Delete, ShiftMask, "\033[3;2~", +1, 0}, + { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0}, + { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, + { XK_BackSpace, XK_NO_MOD, "\177", 0, 0}, + { XK_BackSpace, Mod1Mask, "\033\177", 0, 0}, + { XK_Home, ShiftMask, "\033[2J", 0, -1}, + { XK_Home, ShiftMask, "\033[1;2H", 0, +1}, + { XK_Home, XK_ANY_MOD, "\033[H", 0, -1}, + { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1}, + { XK_End, ControlMask, "\033[J", -1, 0}, + { XK_End, ControlMask, "\033[1;5F", +1, 0}, + { XK_End, ShiftMask, "\033[K", -1, 0}, + { XK_End, ShiftMask, "\033[1;2F", +1, 0}, + { XK_End, XK_ANY_MOD, "\033[4~", 0, 0}, + { XK_Prior, ControlMask, "\033[5;5~", 0, 0}, + { XK_Prior, ShiftMask, "\033[5;2~", 0, 0}, + { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, + { XK_Next, ControlMask, "\033[6;5~", 0, 0}, + { XK_Next, ShiftMask, "\033[6;2~", 0, 0}, + { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0}, + { XK_F1, XK_NO_MOD, "\033OP" , 0, 0}, + { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0}, + { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0}, + { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0}, + { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0}, + { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0}, + { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0}, + { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0}, + { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0}, + { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0}, + { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0}, + { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0}, + { XK_F3, XK_NO_MOD, "\033OR" , 0, 0}, + { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0}, + { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0}, + { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0}, + { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0}, + { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0}, + { XK_F4, XK_NO_MOD, "\033OS" , 0, 0}, + { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0}, + { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0}, + { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0}, + { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0}, + { XK_F5, XK_NO_MOD, "\033[15~", 0, 0}, + { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0}, + { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0}, + { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0}, + { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0}, + { XK_F6, XK_NO_MOD, "\033[17~", 0, 0}, + { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0}, + { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0}, + { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0}, + { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0}, + { XK_F7, XK_NO_MOD, "\033[18~", 0, 0}, + { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0}, + { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0}, + { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0}, + { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0}, + { XK_F8, XK_NO_MOD, "\033[19~", 0, 0}, + { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0}, + { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0}, + { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0}, + { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0}, + { XK_F9, XK_NO_MOD, "\033[20~", 0, 0}, + { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0}, + { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0}, + { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0}, + { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0}, + { XK_F10, XK_NO_MOD, "\033[21~", 0, 0}, + { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0}, + { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0}, + { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0}, + { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0}, + { XK_F11, XK_NO_MOD, "\033[23~", 0, 0}, + { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0}, + { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0}, + { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0}, + { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0}, + { XK_F12, XK_NO_MOD, "\033[24~", 0, 0}, + { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0}, + { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0}, + { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0}, + { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0}, + { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0}, + { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0}, + { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0}, + { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0}, + { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0}, + { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0}, + { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0}, + { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0}, + { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0}, + { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0}, + { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0}, + { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0}, + { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0}, + { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0}, + { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0}, + { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0}, + { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0}, + { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0}, + { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0}, + { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0}, + { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0}, + { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0}, + { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0}, +}; + +/* + * Selection types' masks. + * Use the same masks as usual. + * Button1Mask is always unset, to make masks match between ButtonPress. + * ButtonRelease and MotionNotify. + * If no match is found, regular selection is used. + */ +static uint selmasks[] = { + [SEL_RECTANGULAR] = Mod1Mask, +}; + +/* + * Printable characters in ASCII, used to estimate the advance width + * of single wide characters. + */ +static char ascii_printable[] = + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"; diff --git a/config.def.h.rej b/config.def.h.rej new file mode 100644 index 0000000..cedeeb6 --- /dev/null +++ b/config.def.h.rej @@ -0,0 +1,11 @@ +--- config.def.h ++++ config.def.h +@@ -196,7 +196,7 @@ static uint forcemousemod = ShiftMask; + /* + * Command used to query unicode glyphs. + */ +-char *iso14755_cmd = "dmenu -w \"$WINDOWID\" -p -b codepoint: 0: keypad application mode enabled + * * = 2: term.numlock = 1 + * * < 0: keypad application mode disabled + * appcursor value: + * * 0: no value + * * > 0: cursor application mode enabled + * * < 0: cursor application mode disabled + * + * Be careful with the order of the definitions because st searches in + * this table sequentially, so any XK_ANY_MOD must be in the last + * position for a key. + */ + +/* + * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) + * to be mapped below, add them to this array. + */ +static KeySym mappedkeys[] = { -1 }; + +/* + * State bits to ignore when matching key or button events. By default, + * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored. + */ +static uint ignoremod = NULL; + +/* + * This is the huge key array which defines all compatibility to the Linux + * world. Please decide about changes wisely. + */ +static Key key[] = { + /* keysym mask string appkey appcursor */ + { XK_KP_Home, ShiftMask, "\033[2J", 0, -1}, + { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1}, + { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1}, + { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1}, + { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0}, + { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1}, + { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1}, + { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0}, + { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1}, + { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1}, + { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0}, + { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1}, + { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1}, + { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0}, + { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1}, + { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1}, + { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0}, + { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, + { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0}, + { XK_KP_End, ControlMask, "\033[J", -1, 0}, + { XK_KP_End, ControlMask, "\033[1;5F", +1, 0}, + { XK_KP_End, ShiftMask, "\033[K", -1, 0}, + { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0}, + { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0}, + { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0}, + { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0}, + { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0}, + { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0}, + { XK_KP_Insert, ControlMask, "\033[L", -1, 0}, + { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0}, + { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, + { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, + { XK_KP_Delete, ControlMask, "\033[M", -1, 0}, + { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0}, + { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0}, + { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0}, + { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0}, + { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, + { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0}, + { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0}, + { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0}, + { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0}, + { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0}, + { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0}, + { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0}, + { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0}, + { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0}, + { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0}, + { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0}, + { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0}, + { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0}, + { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0}, + { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0}, + { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0}, + { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0}, + { XK_Up, ShiftMask, "\033[1;2A", 0, 0}, + { XK_Up, Mod1Mask, "\033[1;3A", 0, 0}, + { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0}, + { XK_Up, ControlMask, "\033[1;5A", 0, 0}, + { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0}, + { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0}, + { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0}, + { XK_Up, XK_ANY_MOD, "\033[A", 0, -1}, + { XK_Up, XK_ANY_MOD, "\033OA", 0, +1}, + { XK_Down, ShiftMask, "\033[1;2B", 0, 0}, + { XK_Down, Mod1Mask, "\033[1;3B", 0, 0}, + { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0}, + { XK_Down, ControlMask, "\033[1;5B", 0, 0}, + { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0}, + { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0}, + { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0}, + { XK_Down, XK_ANY_MOD, "\033[B", 0, -1}, + { XK_Down, XK_ANY_MOD, "\033OB", 0, +1}, + { XK_Left, ShiftMask, "\033[1;2D", 0, 0}, + { XK_Left, Mod1Mask, "\033[1;3D", 0, 0}, + { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0}, + { XK_Left, ControlMask, "\033[1;5D", 0, 0}, + { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0}, + { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0}, + { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0}, + { XK_Left, XK_ANY_MOD, "\033[D", 0, -1}, + { XK_Left, XK_ANY_MOD, "\033OD", 0, +1}, + { XK_Right, ShiftMask, "\033[1;2C", 0, 0}, + { XK_Right, Mod1Mask, "\033[1;3C", 0, 0}, + { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0}, + { XK_Right, ControlMask, "\033[1;5C", 0, 0}, + { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0}, + { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0}, + { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0}, + { XK_Right, XK_ANY_MOD, "\033[C", 0, -1}, + { XK_Right, XK_ANY_MOD, "\033OC", 0, +1}, + { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0}, + { XK_Return, Mod1Mask, "\033\r", 0, 0}, + { XK_Return, XK_ANY_MOD, "\r", 0, 0}, + { XK_Insert, ShiftMask, "\033[4l", -1, 0}, + { XK_Insert, ShiftMask, "\033[2;2~", +1, 0}, + { XK_Insert, ControlMask, "\033[L", -1, 0}, + { XK_Insert, ControlMask, "\033[2;5~", +1, 0}, + { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, + { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, + { XK_Delete, ControlMask, "\033[M", -1, 0}, + { XK_Delete, ControlMask, "\033[3;5~", +1, 0}, + { XK_Delete, ShiftMask, "\033[2K", -1, 0}, + { XK_Delete, ShiftMask, "\033[3;2~", +1, 0}, + { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0}, + { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, + { XK_BackSpace, XK_NO_MOD, "\177", 0, 0}, + { XK_BackSpace, Mod1Mask, "\033\177", 0, 0}, + { XK_Home, ShiftMask, "\033[2J", 0, -1}, + { XK_Home, ShiftMask, "\033[1;2H", 0, +1}, + { XK_Home, XK_ANY_MOD, "\033[H", 0, -1}, + { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1}, + { XK_End, ControlMask, "\033[J", -1, 0}, + { XK_End, ControlMask, "\033[1;5F", +1, 0}, + { XK_End, ShiftMask, "\033[K", -1, 0}, + { XK_End, ShiftMask, "\033[1;2F", +1, 0}, + { XK_End, XK_ANY_MOD, "\033[4~", 0, 0}, + { XK_Prior, ControlMask, "\033[5;5~", 0, 0}, + { XK_Prior, ShiftMask, "\033[5;2~", 0, 0}, + { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, + { XK_Next, ControlMask, "\033[6;5~", 0, 0}, + { XK_Next, ShiftMask, "\033[6;2~", 0, 0}, + { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0}, + { XK_F1, XK_NO_MOD, "\033OP" , 0, 0}, + { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0}, + { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0}, + { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0}, + { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0}, + { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0}, + { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0}, + { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0}, + { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0}, + { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0}, + { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0}, + { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0}, + { XK_F3, XK_NO_MOD, "\033OR" , 0, 0}, + { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0}, + { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0}, + { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0}, + { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0}, + { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0}, + { XK_F4, XK_NO_MOD, "\033OS" , 0, 0}, + { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0}, + { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0}, + { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0}, + { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0}, + { XK_F5, XK_NO_MOD, "\033[15~", 0, 0}, + { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0}, + { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0}, + { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0}, + { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0}, + { XK_F6, XK_NO_MOD, "\033[17~", 0, 0}, + { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0}, + { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0}, + { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0}, + { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0}, + { XK_F7, XK_NO_MOD, "\033[18~", 0, 0}, + { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0}, + { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0}, + { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0}, + { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0}, + { XK_F8, XK_NO_MOD, "\033[19~", 0, 0}, + { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0}, + { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0}, + { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0}, + { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0}, + { XK_F9, XK_NO_MOD, "\033[20~", 0, 0}, + { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0}, + { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0}, + { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0}, + { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0}, + { XK_F10, XK_NO_MOD, "\033[21~", 0, 0}, + { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0}, + { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0}, + { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0}, + { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0}, + { XK_F11, XK_NO_MOD, "\033[23~", 0, 0}, + { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0}, + { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0}, + { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0}, + { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0}, + { XK_F12, XK_NO_MOD, "\033[24~", 0, 0}, + { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0}, + { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0}, + { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0}, + { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0}, + { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0}, + { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0}, + { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0}, + { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0}, + { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0}, + { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0}, + { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0}, + { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0}, + { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0}, + { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0}, + { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0}, + { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0}, + { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0}, + { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0}, + { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0}, + { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0}, + { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0}, + { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0}, + { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0}, + { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0}, + { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0}, + { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0}, + { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0}, +}; + +/* + * Selection types' masks. + * Use the same masks as usual. + * Button1Mask is always unset, to make masks match between ButtonPress. + * ButtonRelease and MotionNotify. + * If no match is found, regular selection is used. + */ +static uint selmasks[] = { + [SEL_RECTANGULAR] = Mod1Mask, +}; + +/* + * Printable characters in ASCII, used to estimate the advance width + * of single wide characters. + */ +static char ascii_printable[] = + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"; diff --git a/config.h.rej b/config.h.rej new file mode 100644 index 0000000..bd7768d --- /dev/null +++ b/config.h.rej @@ -0,0 +1,50 @@ +--- config.h ++++ config.h +@@ -5,10 +5,9 @@ + * + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html + */ +-static char *font = "Inconsolata Nerd Font:style=Regular;size=8"; ++static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; + /* Spare fonts */ + static char *font2[] = { +- "Inconsolata Nerd Font:style=Regular;size=8" + /* "Inconsolata for Powerline:pixelsize=12:antialias=true:autohint=true", */ + /* "Hack Nerd Font Mono:pixelsize=11:antialias=true:autohint=true", */ + }; +@@ -164,7 +163,7 @@ static unsigned int defaultrcs = 256; + * 7: Blinking st cursor + * 8: Steady st cursor + */ +-static unsigned int cursorstyle = 3; ++static unsigned int cursorstyle = 1; + static Rune stcursor = 0x2603; /* snowman (U+2603) */ + + /* +@@ -197,7 +196,7 @@ static uint forcemousemod = ShiftMask; + /* + * Command used to query unicode glyphs. + */ +-char *iso14755_cmd = "dmenu -w \"$WINDOWID\" -p -b codepoint: 0 && term.line[y][i - 1].u == ' ') -+ while (i > 0 && TLINE(y)[i - 1].u == ' ') - --i; - - return i; -@@ -527,7 +534,7 @@ selsnap(int *x, int *y, int direction) - * Snap around if the word wraps around at the end or - * beginning of a line. - */ -- prevgp = &term.line[*y][*x]; -+ prevgp = &TLINE(*y)[*x]; - prevdelim = ISDELIM(prevgp->u); - for (;;) { - newx = *x + direction; -@@ -542,14 +549,14 @@ selsnap(int *x, int *y, int direction) - yt = *y, xt = *x; - else - yt = newy, xt = newx; -- if (!(term.line[yt][xt].mode & ATTR_WRAP)) -+ if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) - break; - } - - if (newx >= tlinelen(newy)) - break; - -- gp = &term.line[newy][newx]; -+ gp = &TLINE(newy)[newx]; - delim = ISDELIM(gp->u); - if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim - || (delim && gp->u != prevgp->u))) -@@ -570,14 +577,14 @@ selsnap(int *x, int *y, int direction) - *x = (direction < 0) ? 0 : term.col - 1; - if (direction < 0) { - for (; *y > 0; *y += direction) { -- if (!(term.line[*y-1][term.col-1].mode -+ if (!(TLINE(*y-1)[term.col-1].mode - & ATTR_WRAP)) { - break; - } - } - } else if (direction > 0) { - for (; *y < term.row-1; *y += direction) { -- if (!(term.line[*y][term.col-1].mode -+ if (!(TLINE(*y)[term.col-1].mode - & ATTR_WRAP)) { - break; - } -@@ -608,13 +615,13 @@ getsel(void) - } - - if (sel.type == SEL_RECTANGULAR) { -- gp = &term.line[y][sel.nb.x]; -+ gp = &TLINE(y)[sel.nb.x]; - lastx = sel.ne.x; - } else { -- gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; -+ gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; - lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; - } -- last = &term.line[y][MIN(lastx, linelen-1)]; -+ last = &TLINE(y)[MIN(lastx, linelen-1)]; - while (last >= gp && last->u == ' ') - --last; - -@@ -849,6 +856,9 @@ void - ttywrite(const char *s, size_t n, int may_echo) - { - const char *next; -+ Arg arg = (Arg) { .i = term.scr }; -+ -+ kscrolldown(&arg); - - if (may_echo && IS_SET(MODE_ECHO)) - twrite(s, n, 1); -@@ -1060,13 +1070,53 @@ tswapscreen(void) - } - - void --tscrolldown(int orig, int n) -+kscrolldown(const Arg* a) -+{ -+ int n = a->i; -+ -+ if (n < 0) -+ n = term.row + n; -+ -+ if (n > term.scr) -+ n = term.scr; -+ -+ if (term.scr > 0) { -+ term.scr -= n; -+ selscroll(0, -n); -+ tfulldirt(); -+ } -+} -+ -+void -+kscrollup(const Arg* a) -+{ -+ int n = a->i; -+ -+ if (n < 0) -+ n = term.row + n; -+ -+ if (term.scr <= HISTSIZE-n) { -+ term.scr += n; -+ selscroll(0, n); -+ tfulldirt(); -+ } -+} -+ -+void -+tscrolldown(int orig, int n, int copyhist) - { - int i; - Line temp; - - LIMIT(n, 0, term.bot-orig+1); - -+ if (copyhist) { -+ term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE; -+ temp = term.hist[term.histi]; -+ term.hist[term.histi] = term.line[term.bot]; -+ term.line[term.bot] = temp; -+ } -+ - tsetdirt(orig, term.bot-n); - tclearregion(0, term.bot-n+1, term.col-1, term.bot); - -@@ -1076,17 +1126,28 @@ tscrolldown(int orig, int n) - term.line[i-n] = temp; - } - -- selscroll(orig, n); -+ if (term.scr == 0) -+ selscroll(orig, n); - } - - void --tscrollup(int orig, int n) -+tscrollup(int orig, int n, int copyhist) - { - int i; - Line temp; - - LIMIT(n, 0, term.bot-orig+1); - -+ if (copyhist) { -+ term.histi = (term.histi + 1) % HISTSIZE; -+ temp = term.hist[term.histi]; -+ term.hist[term.histi] = term.line[orig]; -+ term.line[orig] = temp; -+ } -+ -+ if (term.scr > 0 && term.scr < HISTSIZE) -+ term.scr = MIN(term.scr + n, HISTSIZE-1); -+ - tclearregion(0, orig, term.col-1, orig+n-1); - tsetdirt(orig+n, term.bot); - -@@ -1096,7 +1157,8 @@ tscrollup(int orig, int n) - term.line[i+n] = temp; - } - -- selscroll(orig, -n); -+ if (term.scr == 0) -+ selscroll(orig, -n); - } - - void -@@ -1135,7 +1197,7 @@ tnewline(int first_col) - int y = term.c.y; - - if (y == term.bot) { -- tscrollup(term.top, 1); -+ tscrollup(term.top, 1, 1); - } else { - y++; - } -@@ -1300,14 +1362,14 @@ void - tinsertblankline(int n) - { - if (BETWEEN(term.c.y, term.top, term.bot)) -- tscrolldown(term.c.y, n); -+ tscrolldown(term.c.y, n, 0); - } - - void - tdeleteline(int n) - { - if (BETWEEN(term.c.y, term.top, term.bot)) -- tscrollup(term.c.y, n); -+ tscrollup(term.c.y, n, 0); - } - - int32_t -@@ -1738,11 +1800,11 @@ csihandle(void) - break; - case 'S': /* SU -- Scroll line up */ - DEFAULT(csiescseq.arg[0], 1); -- tscrollup(term.top, csiescseq.arg[0]); -+ tscrollup(term.top, csiescseq.arg[0], 0); - break; - case 'T': /* SD -- Scroll line down */ - DEFAULT(csiescseq.arg[0], 1); -- tscrolldown(term.top, csiescseq.arg[0]); -+ tscrolldown(term.top, csiescseq.arg[0], 0); - break; - case 'L': /* IL -- Insert blank lines */ - DEFAULT(csiescseq.arg[0], 1); -@@ -2248,7 +2310,7 @@ eschandle(uchar ascii) - return 0; - case 'D': /* IND -- Linefeed */ - if (term.c.y == term.bot) { -- tscrollup(term.top, 1); -+ tscrollup(term.top, 1, 1); - } else { - tmoveto(term.c.x, term.c.y+1); - } -@@ -2261,7 +2323,7 @@ eschandle(uchar ascii) - break; - case 'M': /* RI -- Reverse index */ - if (term.c.y == term.top) { -- tscrolldown(term.top, 1); -+ tscrolldown(term.top, 1, 1); - } else { - tmoveto(term.c.x, term.c.y-1); - } -@@ -2482,7 +2544,7 @@ twrite(const char *buf, int buflen, int show_ctrl) - void - tresize(int col, int row) - { -- int i; -+ int i, j; - int minrow = MIN(row, term.row); - int mincol = MIN(col, term.col); - int *bp; -@@ -2519,6 +2581,14 @@ tresize(int col, int row) - term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); - term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); - -+ for (i = 0; i < HISTSIZE; i++) { -+ term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); -+ for (j = mincol; j < col; j++) { -+ term.hist[i][j] = term.c.attr; -+ term.hist[i][j].u = ' '; -+ } -+ } -+ - /* resize each row to new width, zero-pad if needed */ - for (i = 0; i < minrow; i++) { - term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); -@@ -2577,7 +2647,7 @@ drawregion(int x1, int y1, int x2, int y2) - continue; - - term.dirty[y] = 0; -- xdrawline(term.line[y], x1, y, x2); -+ xdrawline(TLINE(y), x1, y, x2); - } - } - -@@ -2598,8 +2668,9 @@ draw(void) - cx--; - - drawregion(0, 0, term.col, term.row); -- xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], -- term.ocx, term.ocy, term.line[term.ocy][term.ocx]); -+ if (term.scr == 0) -+ xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], -+ term.ocx, term.ocy, term.line[term.ocy][term.ocx]); - term.ocx = cx; - term.ocy = term.c.y; - xfinishdraw(); -diff --git a/st.h b/st.h -index d978458..b9a4eeb 100644 ---- a/st.h -+++ b/st.h -@@ -81,6 +81,8 @@ void die(const char *, ...); - void redraw(void); - void draw(void); - -+void kscrolldown(const Arg *); -+void kscrollup(const Arg *); - void printscreen(const Arg *); - void printsel(const Arg *); - void sendbreak(const Arg *); diff --git a/patches/st-scrollback-mouse-20191024-a2c479c.diff b/patches/st-scrollback-mouse-20191024-a2c479c.diff deleted file mode 100644 index 49eba8e..0000000 --- a/patches/st-scrollback-mouse-20191024-a2c479c.diff +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index ec1b576..4b3bf15 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -163,6 +163,8 @@ static uint forcemousemod = ShiftMask; - */ - static MouseShortcut mshortcuts[] = { - /* mask button function argument release */ -+ { ShiftMask, Button4, kscrollup, {.i = 1} }, -+ { ShiftMask, Button5, kscrolldown, {.i = 1} }, - { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, - { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, - { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} }, diff --git a/st b/st index a64a3a945cf15ccd946cc1a870536c4a4f06fbd9..3754a2c6ba79c5bc1483358fe07c34afa8a3d3ce 100755 GIT binary patch literal 119624 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 ME#$hsy$hWDH$1N|)Bpeg literal 123840 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 0 && TLINE(y)[i - 1].u == ' ') + while (i > 0 && term.line[y][i - 1].u == ' ') --i; return i; @@ -537,7 +530,7 @@ selsnap(int *x, int *y, int direction) * Snap around if the word wraps around at the end or * beginning of a line. */ - prevgp = &TLINE(*y)[*x]; + prevgp = &term.line[*y][*x]; prevdelim = ISDELIM(prevgp->u); for (;;) { newx = *x + direction; @@ -552,14 +545,14 @@ selsnap(int *x, int *y, int direction) yt = *y, xt = *x; else yt = newy, xt = newx; - if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) + if (!(term.line[yt][xt].mode & ATTR_WRAP)) break; } if (newx >= tlinelen(newy)) break; - gp = &TLINE(newy)[newx]; + gp = &term.line[newy][newx]; delim = ISDELIM(gp->u); if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim || (delim && gp->u != prevgp->u))) @@ -580,14 +573,14 @@ selsnap(int *x, int *y, int direction) *x = (direction < 0) ? 0 : term.col - 1; if (direction < 0) { for (; *y > 0; *y += direction) { - if (!(TLINE(*y-1)[term.col-1].mode + if (!(term.line[*y-1][term.col-1].mode & ATTR_WRAP)) { break; } } } else if (direction > 0) { for (; *y < term.row-1; *y += direction) { - if (!(TLINE(*y)[term.col-1].mode + if (!(term.line[*y][term.col-1].mode & ATTR_WRAP)) { break; } @@ -618,13 +611,13 @@ getsel(void) } if (sel.type == SEL_RECTANGULAR) { - gp = &TLINE(y)[sel.nb.x]; + gp = &term.line[y][sel.nb.x]; lastx = sel.ne.x; } else { - gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; + gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; } - last = &TLINE(y)[MIN(lastx, linelen-1)]; + last = &term.line[y][MIN(lastx, linelen-1)]; while (last >= gp && last->u == ' ') --last; @@ -857,9 +850,6 @@ void ttywrite(const char *s, size_t n, int may_echo) { const char *next; - Arg arg = (Arg) { .i = term.scr }; - - kscrolldown(&arg); if (may_echo && IS_SET(MODE_ECHO)) twrite(s, n, 1); @@ -1096,53 +1086,13 @@ static char *getcwd_by_pid(pid_t pid) { } void -kscrolldown(const Arg* a) -{ - int n = a->i; - - if (n < 0) - n = term.row + n; - - if (n > term.scr) - n = term.scr; - - if (term.scr > 0) { - term.scr -= n; - selscroll(0, -n); - tfulldirt(); - } -} - -void -kscrollup(const Arg* a) -{ - int n = a->i; - - if (n < 0) - n = term.row + n; - - if (term.scr <= HISTSIZE-n) { - term.scr += n; - selscroll(0, n); - tfulldirt(); - } -} - -void -tscrolldown(int orig, int n, int copyhist) +tscrolldown(int orig, int n) { int i; Line temp; LIMIT(n, 0, term.bot-orig+1); - if (copyhist) { - term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE; - temp = term.hist[term.histi]; - term.hist[term.histi] = term.line[term.bot]; - term.line[term.bot] = temp; - } - tsetdirt(orig, term.bot-n); tclearregion(0, term.bot-n+1, term.col-1, term.bot); @@ -1152,28 +1102,17 @@ tscrolldown(int orig, int n, int copyhist) term.line[i-n] = temp; } - if (term.scr == 0) - selscroll(orig, n); + selscroll(orig, n); } void -tscrollup(int orig, int n, int copyhist) +tscrollup(int orig, int n) { int i; Line temp; LIMIT(n, 0, term.bot-orig+1); - if (copyhist) { - term.histi = (term.histi + 1) % HISTSIZE; - temp = term.hist[term.histi]; - term.hist[term.histi] = term.line[orig]; - term.line[orig] = temp; - } - - if (term.scr > 0 && term.scr < HISTSIZE) - term.scr = MIN(term.scr + n, HISTSIZE-1); - tclearregion(0, orig, term.col-1, orig+n-1); tsetdirt(orig+n, term.bot); @@ -1183,8 +1122,7 @@ tscrollup(int orig, int n, int copyhist) term.line[i+n] = temp; } - if (term.scr == 0) - selscroll(orig, -n); + selscroll(orig, -n); } void @@ -1213,7 +1151,7 @@ tnewline(int first_col) int y = term.c.y; if (y == term.bot) { - tscrollup(term.top, 1, 1); + tscrollup(term.top, 1); } else { y++; } @@ -1381,14 +1319,14 @@ void tinsertblankline(int n) { if (BETWEEN(term.c.y, term.top, term.bot)) - tscrolldown(term.c.y, n, 0); + tscrolldown(term.c.y, n); } void tdeleteline(int n) { if (BETWEEN(term.c.y, term.top, term.bot)) - tscrollup(term.c.y, n, 0); + tscrollup(term.c.y, n); } int32_t @@ -1825,11 +1763,11 @@ csihandle(void) break; case 'S': /* SU -- Scroll line up */ DEFAULT(csiescseq.arg[0], 1); - tscrollup(term.top, csiescseq.arg[0], 0); + tscrollup(term.top, csiescseq.arg[0]); break; case 'T': /* SD -- Scroll line down */ DEFAULT(csiescseq.arg[0], 1); - tscrolldown(term.top, csiescseq.arg[0], 0); + tscrolldown(term.top, csiescseq.arg[0]); break; case 'L': /* IL -- Insert blank lines */ DEFAULT(csiescseq.arg[0], 1); @@ -2342,7 +2280,7 @@ eschandle(uchar ascii) return 0; case 'D': /* IND -- Linefeed */ if (term.c.y == term.bot) { - tscrollup(term.top, 1, 1); + tscrollup(term.top, 1); } else { tmoveto(term.c.x, term.c.y+1); } @@ -2355,7 +2293,7 @@ eschandle(uchar ascii) break; case 'M': /* RI -- Reverse index */ if (term.c.y == term.top) { - tscrolldown(term.top, 1, 1); + tscrolldown(term.top, 1); } else { tmoveto(term.c.x, term.c.y-1); } @@ -2565,7 +2503,7 @@ twrite(const char *buf, int buflen, int show_ctrl) void tresize(int col, int row) { - int i, j; + int i; int minrow = MIN(row, term.row); int mincol = MIN(col, term.col); int *bp; @@ -2605,14 +2543,6 @@ tresize(int col, int row) term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); - for (i = 0; i < HISTSIZE; i++) { - term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); - for (j = mincol; j < col; j++) { - term.hist[i][j] = term.c.attr; - term.hist[i][j].u = ' '; - } - } - /* resize each row to new width, zero-pad if needed */ for (i = 0; i < minrow; i++) { term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); @@ -2671,7 +2601,7 @@ drawregion(int x1, int y1, int x2, int y2) continue; term.dirty[y] = 0; - xdrawline(TLINE(y), x1, y, x2); + xdrawline(term.line[y], x1, y, x2); } } @@ -2692,7 +2622,6 @@ draw(void) cx--; drawregion(0, 0, term.col, term.row); - if (term.scr == 0) xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], term.ocx, term.ocy, term.line[term.ocy][term.ocx], term.line[term.ocy], term.col); diff --git a/st.c.orig b/st.c.orig new file mode 100644 index 0000000..8175170 --- /dev/null +++ b/st.c.orig @@ -0,0 +1,3048 @@ +/* See LICENSE for license details. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "st.h" +#include "win.h" + +#if defined(__linux) + #include +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) + #include +#elif defined(__FreeBSD__) || defined(__DragonFly__) + #include +#endif + +/* Arbitrary sizes */ +#define UTF_INVALID 0xFFFD +#define UTF_SIZ 4 +#define ESC_BUF_SIZ (128*UTF_SIZ) +#define ESC_ARG_SIZ 16 +#define STR_BUF_SIZ ESC_BUF_SIZ +#define STR_ARG_SIZ ESC_ARG_SIZ +#define HISTSIZE 2000 + +/* macros */ +#define IS_SET(flag) ((term.mode & (flag)) != 0) +#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == 0x7f) +#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) +#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) +#define ISDELIM(u) (u && wcschr(worddelimiters, u)) +#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \ + term.scr + HISTSIZE + 1) % HISTSIZE] : \ + term.line[(y) - term.scr]) + +enum term_mode { + MODE_WRAP = 1 << 0, + MODE_INSERT = 1 << 1, + MODE_ALTSCREEN = 1 << 2, + MODE_CRLF = 1 << 3, + MODE_ECHO = 1 << 4, + MODE_PRINT = 1 << 5, + MODE_UTF8 = 1 << 6, +}; + +enum cursor_movement { + CURSOR_SAVE, + CURSOR_LOAD +}; + +enum cursor_state { + CURSOR_DEFAULT = 0, + CURSOR_WRAPNEXT = 1, + CURSOR_ORIGIN = 2 +}; + +enum charset { + CS_GRAPHIC0, + CS_GRAPHIC1, + CS_UK, + CS_USA, + CS_MULTI, + CS_GER, + CS_FIN +}; + +enum escape_state { + ESC_START = 1, + ESC_CSI = 2, + ESC_STR = 4, /* DCS, OSC, PM, APC */ + ESC_ALTCHARSET = 8, + ESC_STR_END = 16, /* a final string was encountered */ + ESC_TEST = 32, /* Enter in test mode */ + ESC_UTF8 = 64, +}; + +typedef struct { + Glyph attr; /* current char attributes */ + int x; + int y; + char state; +} TCursor; + +typedef struct { + int mode; + int type; + int snap; + /* + * Selection variables: + * nb – normalized coordinates of the beginning of the selection + * ne – normalized coordinates of the end of the selection + * ob – original coordinates of the beginning of the selection + * oe – original coordinates of the end of the selection + */ + struct { + int x, y; + } nb, ne, ob, oe; + + int alt; +} Selection; + +/* Internal representation of the screen */ +typedef struct { + int row; /* nb row */ + int col; /* nb col */ + Line *line; /* screen */ + Line *alt; /* alternate screen */ + Line hist[HISTSIZE]; /* history buffer */ + int histi; /* history index */ + int scr; /* scroll back */ + int *dirty; /* dirtyness of lines */ + TCursor c; /* cursor */ + int ocx; /* old cursor col */ + int ocy; /* old cursor row */ + int top; /* top scroll limit */ + int bot; /* bottom scroll limit */ + int mode; /* terminal mode flags */ + int esc; /* escape state flags */ + char trantbl[4]; /* charset table translation */ + int charset; /* current charset */ + int icharset; /* selected charset for sequence */ + int *tabs; + Rune lastc; /* last printed char outside of sequence, 0 if control */ +} Term; + +/* CSI Escape sequence structs */ +/* ESC '[' [[ [] [;]] []] */ +typedef struct { + char buf[ESC_BUF_SIZ]; /* raw string */ + size_t len; /* raw string length */ + char priv; + int arg[ESC_ARG_SIZ]; + int narg; /* nb of args */ + char mode[2]; +} CSIEscape; + +/* STR Escape sequence structs */ +/* ESC type [[ [] [;]] ] ESC '\' */ +typedef struct { + char type; /* ESC type ... */ + char *buf; /* allocated raw string */ + size_t siz; /* allocation size */ + size_t len; /* raw string length */ + char *args[STR_ARG_SIZ]; + int narg; /* nb of args */ +} STREscape; + +static void execsh(char *, char **); +static char *getcwd_by_pid(pid_t pid); +static void stty(char **); +static void sigchld(int); +static void ttywriteraw(const char *, size_t); + +static void csidump(void); +static void csihandle(void); +static void csiparse(void); +static void csireset(void); +static int eschandle(uchar); +static void strdump(void); +static void strhandle(void); +static void strparse(void); +static void strreset(void); + +static void tprinter(char *, size_t); +static void tdumpsel(void); +static void tdumpline(int); +static void tdump(void); +static void tclearregion(int, int, int, int); +static void tcursor(int); +static void tdeletechar(int); +static void tdeleteline(int); +static void tinsertblank(int); +static void tinsertblankline(int); +static int tlinelen(int); +static void tmoveto(int, int); +static void tmoveato(int, int); +static void tnewline(int); +static void tputtab(int); +static void tputc(Rune); +static void treset(void); +static void tscrollup(int, int, int); +static void tscrolldown(int, int, int); +static void tsetattr(int *, int); +static void tsetchar(Rune, Glyph *, int, int); +static void tsetdirt(int, int); +static void tsetscroll(int, int); +static void tswapscreen(void); +static void tsetmode(int, int, int *, int); +static int twrite(const char *, int, int); +static void tcontrolcode(uchar ); +static void tdectest(char ); +static void tdefutf8(char); +static int32_t tdefcolor(int *, int *, int); +static void tdeftran(char); +static void tstrsequence(uchar); +static void tsetcolor(int, int, int, uint32_t, uint32_t); +static char * findlastany(char *, const char**, size_t); + +static void drawregion(int, int, int, int); + +static void selnormalize(void); +static void selscroll(int, int); +static void selsnap(int *, int *, int); + +static size_t utf8decode(const char *, Rune *, size_t); +static Rune utf8decodebyte(char, size_t *); +static char utf8encodebyte(Rune, size_t); +static size_t utf8validate(Rune *, size_t); + +static char *base64dec(const char *); +static char base64dec_getc(const char **); + +static ssize_t xwrite(int, const char *, size_t); + +/* Globals */ +static Term term; +static Selection sel; +static CSIEscape csiescseq; +static STREscape strescseq; +static int iofd = 1; +static int cmdfd; +static pid_t pid; + +static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + +ssize_t +xwrite(int fd, const char *s, size_t len) +{ + size_t aux = len; + ssize_t r; + + while (len > 0) { + r = write(fd, s, len); + if (r < 0) + return r; + len -= r; + s += r; + } + + return aux; +} + +void * +xmalloc(size_t len) +{ + void *p; + + if (!(p = malloc(len))) + die("malloc: %s\n", strerror(errno)); + + return p; +} + +void * +xrealloc(void *p, size_t len) +{ + if ((p = realloc(p, len)) == NULL) + die("realloc: %s\n", strerror(errno)); + + return p; +} + +char * +xstrdup(char *s) +{ + if ((s = strdup(s)) == NULL) + die("strdup: %s\n", strerror(errno)); + + return s; +} + +size_t +utf8decode(const char *c, Rune *u, size_t clen) +{ + size_t i, j, len, type; + Rune udecoded; + + *u = UTF_INVALID; + if (!clen) + return 0; + udecoded = utf8decodebyte(c[0], &len); + if (!BETWEEN(len, 1, UTF_SIZ)) + return 1; + for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); + if (type != 0) + return j; + } + if (j < len) + return 0; + *u = udecoded; + utf8validate(u, len); + + return len; +} + +Rune +utf8decodebyte(char c, size_t *i) +{ + for (*i = 0; *i < LEN(utfmask); ++(*i)) + if (((uchar)c & utfmask[*i]) == utfbyte[*i]) + return (uchar)c & ~utfmask[*i]; + + return 0; +} + +size_t +utf8encode(Rune u, char *c) +{ + size_t len, i; + + len = utf8validate(&u, 0); + if (len > UTF_SIZ) + return 0; + + for (i = len - 1; i != 0; --i) { + c[i] = utf8encodebyte(u, 0); + u >>= 6; + } + c[0] = utf8encodebyte(u, len); + + return len; +} + +char +utf8encodebyte(Rune u, size_t i) +{ + return utfbyte[i] | (u & ~utfmask[i]); +} + +size_t +utf8validate(Rune *u, size_t i) +{ + if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) + *u = UTF_INVALID; + for (i = 1; *u > utfmax[i]; ++i) + ; + + return i; +} + +static const char base64_digits[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, + 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, -1, 0, 0, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +char +base64dec_getc(const char **src) +{ + while (**src && !isprint(**src)) + (*src)++; + return **src ? *((*src)++) : '='; /* emulate padding if string ends */ +} + +char * +base64dec(const char *src) +{ + size_t in_len = strlen(src); + char *result, *dst; + + if (in_len % 4) + in_len += 4 - (in_len % 4); + result = dst = xmalloc(in_len / 4 * 3 + 1); + while (*src) { + int a = base64_digits[(unsigned char) base64dec_getc(&src)]; + int b = base64_digits[(unsigned char) base64dec_getc(&src)]; + int c = base64_digits[(unsigned char) base64dec_getc(&src)]; + int d = base64_digits[(unsigned char) base64dec_getc(&src)]; + + /* invalid input. 'a' can be -1, e.g. if src is "\n" (c-str) */ + if (a == -1 || b == -1) + break; + + *dst++ = (a << 2) | ((b & 0x30) >> 4); + if (c == -1) + break; + *dst++ = ((b & 0x0f) << 4) | ((c & 0x3c) >> 2); + if (d == -1) + break; + *dst++ = ((c & 0x03) << 6) | d; + } + *dst = '\0'; + return result; +} + +void +selinit(void) +{ + sel.mode = SEL_IDLE; + sel.snap = 0; + sel.ob.x = -1; +} + +int +tlinelen(int y) +{ + int i = term.col; + + if (TLINE(y)[i - 1].mode & ATTR_WRAP) + return i; + + while (i > 0 && TLINE(y)[i - 1].u == ' ') + --i; + + return i; +} + +void +selstart(int col, int row, int snap) +{ + selclear(); + sel.mode = SEL_EMPTY; + sel.type = SEL_REGULAR; + sel.alt = IS_SET(MODE_ALTSCREEN); + sel.snap = snap; + sel.oe.x = sel.ob.x = col; + sel.oe.y = sel.ob.y = row; + selnormalize(); + + if (sel.snap != 0) + sel.mode = SEL_READY; + tsetdirt(sel.nb.y, sel.ne.y); +} + +void +selextend(int col, int row, int type, int done) +{ + int oldey, oldex, oldsby, oldsey, oldtype; + + if (sel.mode == SEL_IDLE) + return; + if (done && sel.mode == SEL_EMPTY) { + selclear(); + return; + } + + oldey = sel.oe.y; + oldex = sel.oe.x; + oldsby = sel.nb.y; + oldsey = sel.ne.y; + oldtype = sel.type; + + sel.oe.x = col; + sel.oe.y = row; + selnormalize(); + sel.type = type; + + if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY) + tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); + + sel.mode = done ? SEL_IDLE : SEL_READY; +} + +void +selnormalize(void) +{ + int i; + + if (sel.type == SEL_REGULAR && sel.ob.y != sel.oe.y) { + sel.nb.x = sel.ob.y < sel.oe.y ? sel.ob.x : sel.oe.x; + sel.ne.x = sel.ob.y < sel.oe.y ? sel.oe.x : sel.ob.x; + } else { + sel.nb.x = MIN(sel.ob.x, sel.oe.x); + sel.ne.x = MAX(sel.ob.x, sel.oe.x); + } + sel.nb.y = MIN(sel.ob.y, sel.oe.y); + sel.ne.y = MAX(sel.ob.y, sel.oe.y); + + selsnap(&sel.nb.x, &sel.nb.y, -1); + selsnap(&sel.ne.x, &sel.ne.y, +1); + + /* expand selection over line breaks */ + if (sel.type == SEL_RECTANGULAR) + return; + i = tlinelen(sel.nb.y); + if (i < sel.nb.x) + sel.nb.x = i; + if (tlinelen(sel.ne.y) <= sel.ne.x) + sel.ne.x = term.col - 1; +} + +int +selected(int x, int y) +{ + if (sel.mode == SEL_EMPTY || sel.ob.x == -1 || + sel.alt != IS_SET(MODE_ALTSCREEN)) + return 0; + + if (sel.type == SEL_RECTANGULAR) + return BETWEEN(y, sel.nb.y, sel.ne.y) + && BETWEEN(x, sel.nb.x, sel.ne.x); + + return BETWEEN(y, sel.nb.y, sel.ne.y) + && (y != sel.nb.y || x >= sel.nb.x) + && (y != sel.ne.y || x <= sel.ne.x); +} + +void +selsnap(int *x, int *y, int direction) +{ + int newx, newy, xt, yt; + int delim, prevdelim; + Glyph *gp, *prevgp; + + switch (sel.snap) { + case SNAP_WORD: + /* + * Snap around if the word wraps around at the end or + * beginning of a line. + */ + prevgp = &TLINE(*y)[*x]; + prevdelim = ISDELIM(prevgp->u); + for (;;) { + newx = *x + direction; + newy = *y; + if (!BETWEEN(newx, 0, term.col - 1)) { + newy += direction; + newx = (newx + term.col) % term.col; + if (!BETWEEN(newy, 0, term.row - 1)) + break; + + if (direction > 0) + yt = *y, xt = *x; + else + yt = newy, xt = newx; + if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) + break; + } + + if (newx >= tlinelen(newy)) + break; + + gp = &TLINE(newy)[newx]; + delim = ISDELIM(gp->u); + if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim + || (delim && gp->u != prevgp->u))) + break; + + *x = newx; + *y = newy; + prevgp = gp; + prevdelim = delim; + } + break; + case SNAP_LINE: + /* + * Snap around if the the previous line or the current one + * has set ATTR_WRAP at its end. Then the whole next or + * previous line will be selected. + */ + *x = (direction < 0) ? 0 : term.col - 1; + if (direction < 0) { + for (; *y > 0; *y += direction) { + if (!(TLINE(*y-1)[term.col-1].mode + & ATTR_WRAP)) { + break; + } + } + } else if (direction > 0) { + for (; *y < term.row-1; *y += direction) { + if (!(TLINE(*y)[term.col-1].mode + & ATTR_WRAP)) { + break; + } + } + } + break; + } +} + +char * +getsel(void) +{ + char *str, *ptr; + int y, bufsize, lastx, linelen; + Glyph *gp, *last; + + if (sel.ob.x == -1) + return NULL; + + bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ; + ptr = str = xmalloc(bufsize); + + /* append every set & selected glyph to the selection */ + for (y = sel.nb.y; y <= sel.ne.y; y++) { + if ((linelen = tlinelen(y)) == 0) { + *ptr++ = '\n'; + continue; + } + + if (sel.type == SEL_RECTANGULAR) { + gp = &TLINE(y)[sel.nb.x]; + lastx = sel.ne.x; + } else { + gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; + lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; + } + last = &TLINE(y)[MIN(lastx, linelen-1)]; + while (last >= gp && last->u == ' ') + --last; + + for ( ; gp <= last; ++gp) { + if (gp->mode & ATTR_WDUMMY) + continue; + + ptr += utf8encode(gp->u, ptr); + } + + /* + * Copy and pasting of line endings is inconsistent + * in the inconsistent terminal and GUI world. + * The best solution seems like to produce '\n' when + * something is copied from st and convert '\n' to + * '\r', when something to be pasted is received by + * st. + * FIXME: Fix the computer world. + */ + if ((y < sel.ne.y || lastx >= linelen) && + (!(last->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR)) + *ptr++ = '\n'; + } + *ptr = 0; + return str; +} + +void +selclear(void) +{ + if (sel.ob.x == -1) + return; + sel.mode = SEL_IDLE; + sel.ob.x = -1; + tsetdirt(sel.nb.y, sel.ne.y); +} + +void +die(const char *errstr, ...) +{ + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(1); +} + +void +execsh(char *cmd, char **args) +{ + char *sh, *prog, *arg; + const struct passwd *pw; + + errno = 0; + if ((pw = getpwuid(getuid())) == NULL) { + if (errno) + die("getpwuid: %s\n", strerror(errno)); + else + die("who are you?\n"); + } + + if ((sh = getenv("SHELL")) == NULL) + sh = (pw->pw_shell[0]) ? pw->pw_shell : cmd; + + if (args) { + prog = args[0]; + arg = NULL; + } else if (scroll) { + prog = scroll; + arg = utmp ? utmp : sh; + } else if (utmp) { + prog = utmp; + arg = NULL; + } else { + prog = sh; + arg = NULL; + } + DEFAULT(args, ((char *[]) {prog, arg, NULL})); + + unsetenv("COLUMNS"); + unsetenv("LINES"); + unsetenv("TERMCAP"); + setenv("LOGNAME", pw->pw_name, 1); + setenv("USER", pw->pw_name, 1); + setenv("SHELL", sh, 1); + setenv("HOME", pw->pw_dir, 1); + setenv("TERM", termname, 1); + + signal(SIGCHLD, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGALRM, SIG_DFL); + + execvp(prog, args); + _exit(1); +} + +void +sigchld(int a) +{ + int stat; + pid_t p; + + if ((p = waitpid(pid, &stat, WNOHANG)) < 0) + die("waiting for pid %hd failed: %s\n", pid, strerror(errno)); + + if (pid != p) + if (WIFEXITED(stat) && WEXITSTATUS(stat)) + die("child exited with status %d\n", WEXITSTATUS(stat)); + else if (WIFSIGNALED(stat)) + die("child terminated due to signal %d\n", WTERMSIG(stat)); + _exit(0); +} + +void +stty(char **args) +{ + char cmd[_POSIX_ARG_MAX], **p, *q, *s; + size_t n, siz; + + if ((n = strlen(stty_args)) > sizeof(cmd)-1) + die("incorrect stty parameters\n"); + memcpy(cmd, stty_args, n); + q = cmd + n; + siz = sizeof(cmd) - n; + for (p = args; p && (s = *p); ++p) { + if ((n = strlen(s)) > siz-1) + die("stty parameter length too long\n"); + *q++ = ' '; + memcpy(q, s, n); + q += n; + siz -= n + 1; + } + *q = '\0'; + if (system(cmd) != 0) + perror("Couldn't call stty"); +} + +int +ttynew(char *line, char *cmd, char *out, char **args) +{ + int m, s; + + if (out) { + term.mode |= MODE_PRINT; + iofd = (!strcmp(out, "-")) ? + 1 : open(out, O_WRONLY | O_CREAT, 0666); + if (iofd < 0) { + fprintf(stderr, "Error opening %s:%s\n", + out, strerror(errno)); + } + } + + if (line) { + if ((cmdfd = open(line, O_RDWR)) < 0) + die("open line '%s' failed: %s\n", + line, strerror(errno)); + dup2(cmdfd, 0); + stty(args); + return cmdfd; + } + + /* seems to work fine on linux, openbsd and freebsd */ + if (openpty(&m, &s, NULL, NULL, NULL) < 0) + die("openpty failed: %s\n", strerror(errno)); + + switch (pid = fork()) { + case -1: + die("fork failed: %s\n", strerror(errno)); + break; + case 0: + close(iofd); + setsid(); /* create a new process group */ + dup2(s, 0); + dup2(s, 1); + dup2(s, 2); + if (ioctl(s, TIOCSCTTY, NULL) < 0) + die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); + close(s); + close(m); +#ifdef __OpenBSD__ + if (pledge("stdio getpw proc exec", NULL) == -1) + die("pledge\n"); +#endif + execsh(cmd, args); + break; + default: +#ifdef __OpenBSD__ + if (pledge("stdio rpath tty proc", NULL) == -1) + die("pledge\n"); +#endif + close(s); + cmdfd = m; + signal(SIGCHLD, sigchld); + break; + } + return cmdfd; +} + +size_t +ttyread(void) +{ + static char buf[BUFSIZ]; + static int buflen = 0; + int ret, written; + + /* append read bytes to unprocessed bytes */ + ret = read(cmdfd, buf+buflen, LEN(buf)-buflen); + + switch (ret) { + case 0: + exit(0); + case -1: + die("couldn't read from shell: %s\n", strerror(errno)); + default: + buflen += ret; + written = twrite(buf, buflen, 0); + buflen -= written; + /* keep any incomplete UTF-8 byte sequence for the next call */ + if (buflen > 0) + memmove(buf, buf + written, buflen); + return ret; + } +} + +void +ttywrite(const char *s, size_t n, int may_echo) +{ + const char *next; + Arg arg = (Arg) { .i = term.scr }; + + kscrolldown(&arg); + + if (may_echo && IS_SET(MODE_ECHO)) + twrite(s, n, 1); + + if (!IS_SET(MODE_CRLF)) { + ttywriteraw(s, n); + return; + } + + /* This is similar to how the kernel handles ONLCR for ttys */ + while (n > 0) { + if (*s == '\r') { + next = s + 1; + ttywriteraw("\r\n", 2); + } else { + next = memchr(s, '\r', n); + DEFAULT(next, s + n); + ttywriteraw(s, next - s); + } + n -= next - s; + s = next; + } +} + +void +ttywriteraw(const char *s, size_t n) +{ + fd_set wfd, rfd; + ssize_t r; + size_t lim = 256; + + /* + * Remember that we are using a pty, which might be a modem line. + * Writing too much will clog the line. That's why we are doing this + * dance. + * FIXME: Migrate the world to Plan 9. + */ + while (n > 0) { + FD_ZERO(&wfd); + FD_ZERO(&rfd); + FD_SET(cmdfd, &wfd); + FD_SET(cmdfd, &rfd); + + /* Check if we can write. */ + if (pselect(cmdfd+1, &rfd, &wfd, NULL, NULL, NULL) < 0) { + if (errno == EINTR) + continue; + die("select failed: %s\n", strerror(errno)); + } + if (FD_ISSET(cmdfd, &wfd)) { + /* + * Only write the bytes written by ttywrite() or the + * default of 256. This seems to be a reasonable value + * for a serial line. Bigger values might clog the I/O. + */ + if ((r = write(cmdfd, s, (n < lim)? n : lim)) < 0) + goto write_error; + if (r < n) { + /* + * We weren't able to write out everything. + * This means the buffer is getting full + * again. Empty it. + */ + if (n < lim) + lim = ttyread(); + n -= r; + s += r; + } else { + /* All bytes have been written. */ + break; + } + } + if (FD_ISSET(cmdfd, &rfd)) + lim = ttyread(); + } + return; + +write_error: + die("write error on tty: %s\n", strerror(errno)); +} + +void +ttyresize(int tw, int th) +{ + struct winsize w; + + w.ws_row = term.row; + w.ws_col = term.col; + w.ws_xpixel = tw; + w.ws_ypixel = th; + if (ioctl(cmdfd, TIOCSWINSZ, &w) < 0) + fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno)); +} + +void +ttyhangup() +{ + /* Send SIGHUP to shell */ + kill(pid, SIGHUP); +} + +int +tattrset(int attr) +{ + int i, j; + + for (i = 0; i < term.row-1; i++) { + for (j = 0; j < term.col-1; j++) { + if (term.line[i][j].mode & attr) + return 1; + } + } + + return 0; +} + +void +tsetdirt(int top, int bot) +{ + int i; + + LIMIT(top, 0, term.row-1); + LIMIT(bot, 0, term.row-1); + + for (i = top; i <= bot; i++) + term.dirty[i] = 1; +} + +void +tsetdirtattr(int attr) +{ + int i, j; + + for (i = 0; i < term.row-1; i++) { + for (j = 0; j < term.col-1; j++) { + if (term.line[i][j].mode & attr) { + tsetdirt(i, i); + break; + } + } + } +} + +void +tfulldirt(void) +{ + tsetdirt(0, term.row-1); +} + +void +tcursor(int mode) +{ + static TCursor c[2]; + int alt = IS_SET(MODE_ALTSCREEN); + + if (mode == CURSOR_SAVE) { + c[alt] = term.c; + } else if (mode == CURSOR_LOAD) { + term.c = c[alt]; + tmoveto(c[alt].x, c[alt].y); + } +} + +void +treset(void) +{ + uint i; + + term.c = (TCursor){{ + .mode = ATTR_NULL, + .fg = defaultfg, + .bg = defaultbg + }, .x = 0, .y = 0, .state = CURSOR_DEFAULT}; + + memset(term.tabs, 0, term.col * sizeof(*term.tabs)); + for (i = tabspaces; i < term.col; i += tabspaces) + term.tabs[i] = 1; + term.top = 0; + term.bot = term.row - 1; + term.mode = MODE_WRAP|MODE_UTF8; + memset(term.trantbl, CS_USA, sizeof(term.trantbl)); + term.charset = 0; + + for (i = 0; i < 2; i++) { + tmoveto(0, 0); + tcursor(CURSOR_SAVE); + tclearregion(0, 0, term.col-1, term.row-1); + tswapscreen(); + } +} + +void +tnew(int col, int row) +{ + term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } }; + tresize(col, row); + treset(); +} + +int tisaltscr(void) +{ + return IS_SET(MODE_ALTSCREEN); +} + +void +tswapscreen(void) +{ + Line *tmp = term.line; + + term.line = term.alt; + term.alt = tmp; + term.mode ^= MODE_ALTSCREEN; + tfulldirt(); +} + +void +newterm(const Arg* a) +{ + switch (fork()) { + case -1: + die("fork failed: %s\n", strerror(errno)); + break; + case 0: + chdir(getcwd_by_pid(pid)); + execlp("st", "./st", NULL); + break; + } +} + +static char *getcwd_by_pid(pid_t pid) { + char buf[32]; + snprintf(buf, sizeof buf, "/proc/%d/cwd", pid); + return realpath(buf, NULL); +} + +void +kscrolldown(const Arg* a) +{ + int n = a->i; + + if (n < 0) + n = term.row + n; + + if (n > term.scr) + n = term.scr; + + if (term.scr > 0) { + term.scr -= n; + selscroll(0, -n); + tfulldirt(); + } +} + +void +kscrollup(const Arg* a) +{ + int n = a->i; + + if (n < 0) + n = term.row + n; + + if (term.scr <= HISTSIZE-n) { + term.scr += n; + selscroll(0, n); + tfulldirt(); + } +} + +void +tscrolldown(int orig, int n, int copyhist) +{ + int i; + Line temp; + + LIMIT(n, 0, term.bot-orig+1); + + if (copyhist) { + term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE; + temp = term.hist[term.histi]; + term.hist[term.histi] = term.line[term.bot]; + term.line[term.bot] = temp; + } + + tsetdirt(orig, term.bot-n); + tclearregion(0, term.bot-n+1, term.col-1, term.bot); + + for (i = term.bot; i >= orig+n; i--) { + temp = term.line[i]; + term.line[i] = term.line[i-n]; + term.line[i-n] = temp; + } + + if (term.scr == 0) + selscroll(orig, n); +} + +void +tscrollup(int orig, int n, int copyhist) +{ + int i; + Line temp; + + LIMIT(n, 0, term.bot-orig+1); + + if (copyhist) { + term.histi = (term.histi + 1) % HISTSIZE; + temp = term.hist[term.histi]; + term.hist[term.histi] = term.line[orig]; + term.line[orig] = temp; + } + + if (term.scr > 0 && term.scr < HISTSIZE) + term.scr = MIN(term.scr + n, HISTSIZE-1); + + tclearregion(0, orig, term.col-1, orig+n-1); + tsetdirt(orig+n, term.bot); + + for (i = orig; i <= term.bot-n; i++) { + temp = term.line[i]; + term.line[i] = term.line[i+n]; + term.line[i+n] = temp; + } + + if (term.scr == 0) + selscroll(orig, -n); +} + +void +selscroll(int orig, int n) +{ + if (sel.ob.x == -1) + return; + + if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) { + selclear(); + } else if (BETWEEN(sel.nb.y, orig, term.bot)) { + sel.ob.y += n; + sel.oe.y += n; + if (sel.ob.y < term.top || sel.ob.y > term.bot || + sel.oe.y < term.top || sel.oe.y > term.bot) { + selclear(); + } else { + selnormalize(); + } + } +} + +void +tnewline(int first_col) +{ + int y = term.c.y; + + if (y == term.bot) { + tscrollup(term.top, 1, 1); + } else { + y++; + } + tmoveto(first_col ? 0 : term.c.x, y); +} + +void +csiparse(void) +{ + char *p = csiescseq.buf, *np; + long int v; + + csiescseq.narg = 0; + if (*p == '?') { + csiescseq.priv = 1; + p++; + } + + csiescseq.buf[csiescseq.len] = '\0'; + while (p < csiescseq.buf+csiescseq.len) { + np = NULL; + v = strtol(p, &np, 10); + if (np == p) + v = 0; + if (v == LONG_MAX || v == LONG_MIN) + v = -1; + csiescseq.arg[csiescseq.narg++] = v; + p = np; + if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ) + break; + p++; + } + csiescseq.mode[0] = *p++; + csiescseq.mode[1] = (p < csiescseq.buf+csiescseq.len) ? *p : '\0'; +} + +/* for absolute user moves, when decom is set */ +void +tmoveato(int x, int y) +{ + tmoveto(x, y + ((term.c.state & CURSOR_ORIGIN) ? term.top: 0)); +} + +void +tmoveto(int x, int y) +{ + int miny, maxy; + + if (term.c.state & CURSOR_ORIGIN) { + miny = term.top; + maxy = term.bot; + } else { + miny = 0; + maxy = term.row - 1; + } + term.c.state &= ~CURSOR_WRAPNEXT; + term.c.x = LIMIT(x, 0, term.col-1); + term.c.y = LIMIT(y, miny, maxy); +} + +void +tsetchar(Rune u, Glyph *attr, int x, int y) +{ + static char *vt100_0[62] = { /* 0x41 - 0x7e */ + "↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */ + 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ + 0, 0, 0, 0, 0, 0, 0, 0, /* P - W */ + 0, 0, 0, 0, 0, 0, 0, " ", /* X - _ */ + "◆", "▒", "␉", "␌", "␍", "␊", "°", "±", /* ` - g */ + "␤", "␋", "┘", "┐", "┌", "└", "┼", "⎺", /* h - o */ + "⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */ + "│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */ + }; + + /* + * The table is proudly stolen from rxvt. + */ + if (term.trantbl[term.charset] == CS_GRAPHIC0 && + BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41]) + utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ); + + if (term.line[y][x].mode & ATTR_WIDE) { + if (x+1 < term.col) { + term.line[y][x+1].u = ' '; + term.line[y][x+1].mode &= ~ATTR_WDUMMY; + } + } else if (term.line[y][x].mode & ATTR_WDUMMY) { + term.line[y][x-1].u = ' '; + term.line[y][x-1].mode &= ~ATTR_WIDE; + } + + term.dirty[y] = 1; + term.line[y][x] = *attr; + term.line[y][x].u = u; +} + +void +tclearregion(int x1, int y1, int x2, int y2) +{ + int x, y, temp; + Glyph *gp; + + if (x1 > x2) + temp = x1, x1 = x2, x2 = temp; + if (y1 > y2) + temp = y1, y1 = y2, y2 = temp; + + LIMIT(x1, 0, term.col-1); + LIMIT(x2, 0, term.col-1); + LIMIT(y1, 0, term.row-1); + LIMIT(y2, 0, term.row-1); + + for (y = y1; y <= y2; y++) { + term.dirty[y] = 1; + for (x = x1; x <= x2; x++) { + gp = &term.line[y][x]; + if (selected(x, y)) + selclear(); + gp->fg = term.c.attr.fg; + gp->bg = term.c.attr.bg; + gp->mode = 0; + gp->u = ' '; + } + } +} + +void +tdeletechar(int n) +{ + int dst, src, size; + Glyph *line; + + LIMIT(n, 0, term.col - term.c.x); + + dst = term.c.x; + src = term.c.x + n; + size = term.col - src; + line = term.line[term.c.y]; + + memmove(&line[dst], &line[src], size * sizeof(Glyph)); + tclearregion(term.col-n, term.c.y, term.col-1, term.c.y); +} + +void +tinsertblank(int n) +{ + int dst, src, size; + Glyph *line; + + LIMIT(n, 0, term.col - term.c.x); + + dst = term.c.x + n; + src = term.c.x; + size = term.col - dst; + line = term.line[term.c.y]; + + memmove(&line[dst], &line[src], size * sizeof(Glyph)); + tclearregion(src, term.c.y, dst - 1, term.c.y); +} + +void +tinsertblankline(int n) +{ + if (BETWEEN(term.c.y, term.top, term.bot)) + tscrolldown(term.c.y, n, 0); +} + +void +tdeleteline(int n) +{ + if (BETWEEN(term.c.y, term.top, term.bot)) + tscrollup(term.c.y, n, 0); +} + +int32_t +tdefcolor(int *attr, int *npar, int l) +{ + int32_t idx = -1; + uint r, g, b; + + switch (attr[*npar + 1]) { + case 2: /* direct color in RGB space */ + if (*npar + 4 >= l) { + fprintf(stderr, + "erresc(38): Incorrect number of parameters (%d)\n", + *npar); + break; + } + r = attr[*npar + 2]; + g = attr[*npar + 3]; + b = attr[*npar + 4]; + *npar += 4; + if (!BETWEEN(r, 0, 255) || !BETWEEN(g, 0, 255) || !BETWEEN(b, 0, 255)) + fprintf(stderr, "erresc: bad rgb color (%u,%u,%u)\n", + r, g, b); + else + idx = TRUECOLOR(r, g, b); + break; + case 5: /* indexed color */ + if (*npar + 2 >= l) { + fprintf(stderr, + "erresc(38): Incorrect number of parameters (%d)\n", + *npar); + break; + } + *npar += 2; + if (!BETWEEN(attr[*npar], 0, 255)) + fprintf(stderr, "erresc: bad fgcolor %d\n", attr[*npar]); + else + idx = attr[*npar]; + break; + case 0: /* implemented defined (only foreground) */ + case 1: /* transparent */ + case 3: /* direct color in CMY space */ + case 4: /* direct color in CMYK space */ + default: + fprintf(stderr, + "erresc(38): gfx attr %d unknown\n", attr[*npar]); + break; + } + + return idx; +} + +void +tsetattr(int *attr, int l) +{ + int i; + int32_t idx; + + for (i = 0; i < l; i++) { + switch (attr[i]) { + case 0: + term.c.attr.mode &= ~( + ATTR_BOLD | + ATTR_FAINT | + ATTR_ITALIC | + ATTR_UNDERLINE | + ATTR_BLINK | + ATTR_REVERSE | + ATTR_INVISIBLE | + ATTR_STRUCK ); + term.c.attr.fg = defaultfg; + term.c.attr.bg = defaultbg; + break; + case 1: + term.c.attr.mode |= ATTR_BOLD; + break; + case 2: + term.c.attr.mode |= ATTR_FAINT; + break; + case 3: + term.c.attr.mode |= ATTR_ITALIC; + break; + case 4: + term.c.attr.mode |= ATTR_UNDERLINE; + break; + case 5: /* slow blink */ + /* FALLTHROUGH */ + case 6: /* rapid blink */ + term.c.attr.mode |= ATTR_BLINK; + break; + case 7: + term.c.attr.mode |= ATTR_REVERSE; + break; + case 8: + term.c.attr.mode |= ATTR_INVISIBLE; + break; + case 9: + term.c.attr.mode |= ATTR_STRUCK; + break; + case 22: + term.c.attr.mode &= ~(ATTR_BOLD | ATTR_FAINT); + break; + case 23: + term.c.attr.mode &= ~ATTR_ITALIC; + break; + case 24: + term.c.attr.mode &= ~ATTR_UNDERLINE; + break; + case 25: + term.c.attr.mode &= ~ATTR_BLINK; + break; + case 27: + term.c.attr.mode &= ~ATTR_REVERSE; + break; + case 28: + term.c.attr.mode &= ~ATTR_INVISIBLE; + break; + case 29: + term.c.attr.mode &= ~ATTR_STRUCK; + break; + case 38: + if ((idx = tdefcolor(attr, &i, l)) >= 0) + term.c.attr.fg = idx; + break; + case 39: + term.c.attr.fg = defaultfg; + break; + case 48: + if ((idx = tdefcolor(attr, &i, l)) >= 0) + term.c.attr.bg = idx; + break; + case 49: + term.c.attr.bg = defaultbg; + break; + default: + if (BETWEEN(attr[i], 30, 37)) { + term.c.attr.fg = attr[i] - 30; + } else if (BETWEEN(attr[i], 40, 47)) { + term.c.attr.bg = attr[i] - 40; + } else if (BETWEEN(attr[i], 90, 97)) { + term.c.attr.fg = attr[i] - 90 + 8; + } else if (BETWEEN(attr[i], 100, 107)) { + term.c.attr.bg = attr[i] - 100 + 8; + } else { + fprintf(stderr, + "erresc(default): gfx attr %d unknown\n", + attr[i]); + csidump(); + } + break; + } + } +} + +void +tsetscroll(int t, int b) +{ + int temp; + + LIMIT(t, 0, term.row-1); + LIMIT(b, 0, term.row-1); + if (t > b) { + temp = t; + t = b; + b = temp; + } + term.top = t; + term.bot = b; +} + +void +tsetmode(int priv, int set, int *args, int narg) +{ + int alt, *lim; + + for (lim = args + narg; args < lim; ++args) { + if (priv) { + switch (*args) { + case 1: /* DECCKM -- Cursor key */ + xsetmode(set, MODE_APPCURSOR); + break; + case 5: /* DECSCNM -- Reverse video */ + xsetmode(set, MODE_REVERSE); + break; + case 6: /* DECOM -- Origin */ + MODBIT(term.c.state, set, CURSOR_ORIGIN); + tmoveato(0, 0); + break; + case 7: /* DECAWM -- Auto wrap */ + MODBIT(term.mode, set, MODE_WRAP); + break; + case 0: /* Error (IGNORED) */ + case 2: /* DECANM -- ANSI/VT52 (IGNORED) */ + case 3: /* DECCOLM -- Column (IGNORED) */ + case 4: /* DECSCLM -- Scroll (IGNORED) */ + case 8: /* DECARM -- Auto repeat (IGNORED) */ + case 18: /* DECPFF -- Printer feed (IGNORED) */ + case 19: /* DECPEX -- Printer extent (IGNORED) */ + case 42: /* DECNRCM -- National characters (IGNORED) */ + case 12: /* att610 -- Start blinking cursor (IGNORED) */ + break; + case 25: /* DECTCEM -- Text Cursor Enable Mode */ + xsetmode(!set, MODE_HIDE); + break; + case 9: /* X10 mouse compatibility mode */ + xsetpointermotion(0); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEX10); + break; + case 1000: /* 1000: report button press */ + xsetpointermotion(0); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEBTN); + break; + case 1002: /* 1002: report motion on button press */ + xsetpointermotion(0); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEMOTION); + break; + case 1003: /* 1003: enable all mouse motions */ + xsetpointermotion(set); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEMANY); + break; + case 1004: /* 1004: send focus events to tty */ + xsetmode(set, MODE_FOCUS); + break; + case 1006: /* 1006: extended reporting mode */ + xsetmode(set, MODE_MOUSESGR); + break; + case 1034: + xsetmode(set, MODE_8BIT); + break; + case 1049: /* swap screen & set/restore cursor as xterm */ + if (!allowaltscreen) + break; + tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); + /* FALLTHROUGH */ + case 47: /* swap screen */ + case 1047: + if (!allowaltscreen) + break; + alt = IS_SET(MODE_ALTSCREEN); + if (alt) { + tclearregion(0, 0, term.col-1, + term.row-1); + } + if (set ^ alt) /* set is always 1 or 0 */ + tswapscreen(); + if (*args != 1049) + break; + /* FALLTHROUGH */ + case 1048: + tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); + break; + case 2004: /* 2004: bracketed paste mode */ + xsetmode(set, MODE_BRCKTPASTE); + break; + /* Not implemented mouse modes. See comments there. */ + case 1001: /* mouse highlight mode; can hang the + terminal by design when implemented. */ + case 1005: /* UTF-8 mouse mode; will confuse + applications not supporting UTF-8 + and luit. */ + case 1015: /* urxvt mangled mouse mode; incompatible + and can be mistaken for other control + codes. */ + break; + default: + fprintf(stderr, + "erresc: unknown private set/reset mode %d\n", + *args); + break; + } + } else { + switch (*args) { + case 0: /* Error (IGNORED) */ + break; + case 2: + xsetmode(set, MODE_KBDLOCK); + break; + case 4: /* IRM -- Insertion-replacement */ + MODBIT(term.mode, set, MODE_INSERT); + break; + case 12: /* SRM -- Send/Receive */ + MODBIT(term.mode, !set, MODE_ECHO); + break; + case 20: /* LNM -- Linefeed/new line */ + MODBIT(term.mode, set, MODE_CRLF); + break; + default: + fprintf(stderr, + "erresc: unknown set/reset mode %d\n", + *args); + break; + } + } + } +} + +void +csihandle(void) +{ + char buf[40]; + int len; + + switch (csiescseq.mode[0]) { + default: + unknown: + fprintf(stderr, "erresc: unknown csi "); + csidump(); + /* die(""); */ + break; + case '@': /* ICH -- Insert blank char */ + DEFAULT(csiescseq.arg[0], 1); + tinsertblank(csiescseq.arg[0]); + break; + case 'A': /* CUU -- Cursor Up */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x, term.c.y-csiescseq.arg[0]); + break; + case 'B': /* CUD -- Cursor Down */ + case 'e': /* VPR --Cursor Down */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x, term.c.y+csiescseq.arg[0]); + break; + case 'i': /* MC -- Media Copy */ + switch (csiescseq.arg[0]) { + case 0: + tdump(); + break; + case 1: + tdumpline(term.c.y); + break; + case 2: + tdumpsel(); + break; + case 4: + term.mode &= ~MODE_PRINT; + break; + case 5: + term.mode |= MODE_PRINT; + break; + } + break; + case 'c': /* DA -- Device Attributes */ + if (csiescseq.arg[0] == 0) + ttywrite(vtiden, strlen(vtiden), 0); + break; + case 'b': /* REP -- if last char is printable print it more times */ + DEFAULT(csiescseq.arg[0], 1); + if (term.lastc) + while (csiescseq.arg[0]-- > 0) + tputc(term.lastc); + break; + case 'C': /* CUF -- Cursor Forward */ + case 'a': /* HPR -- Cursor Forward */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x+csiescseq.arg[0], term.c.y); + break; + case 'D': /* CUB -- Cursor Backward */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x-csiescseq.arg[0], term.c.y); + break; + case 'E': /* CNL -- Cursor Down and first col */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(0, term.c.y+csiescseq.arg[0]); + break; + case 'F': /* CPL -- Cursor Up and first col */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(0, term.c.y-csiescseq.arg[0]); + break; + case 'g': /* TBC -- Tabulation clear */ + switch (csiescseq.arg[0]) { + case 0: /* clear current tab stop */ + term.tabs[term.c.x] = 0; + break; + case 3: /* clear all the tabs */ + memset(term.tabs, 0, term.col * sizeof(*term.tabs)); + break; + default: + goto unknown; + } + break; + case 'G': /* CHA -- Move to */ + case '`': /* HPA */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(csiescseq.arg[0]-1, term.c.y); + break; + case 'H': /* CUP -- Move to */ + case 'f': /* HVP */ + DEFAULT(csiescseq.arg[0], 1); + DEFAULT(csiescseq.arg[1], 1); + tmoveato(csiescseq.arg[1]-1, csiescseq.arg[0]-1); + break; + case 'I': /* CHT -- Cursor Forward Tabulation tab stops */ + DEFAULT(csiescseq.arg[0], 1); + tputtab(csiescseq.arg[0]); + break; + case 'J': /* ED -- Clear screen */ + switch (csiescseq.arg[0]) { + case 0: /* below */ + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); + if (term.c.y < term.row-1) { + tclearregion(0, term.c.y+1, term.col-1, + term.row-1); + } + break; + case 1: /* above */ + if (term.c.y > 1) + tclearregion(0, 0, term.col-1, term.c.y-1); + tclearregion(0, term.c.y, term.c.x, term.c.y); + break; + case 2: /* all */ + tclearregion(0, 0, term.col-1, term.row-1); + break; + default: + goto unknown; + } + break; + case 'K': /* EL -- Clear line */ + switch (csiescseq.arg[0]) { + case 0: /* right */ + tclearregion(term.c.x, term.c.y, term.col-1, + term.c.y); + break; + case 1: /* left */ + tclearregion(0, term.c.y, term.c.x, term.c.y); + break; + case 2: /* all */ + tclearregion(0, term.c.y, term.col-1, term.c.y); + break; + } + break; + case 'S': /* SU -- Scroll line up */ + DEFAULT(csiescseq.arg[0], 1); + tscrollup(term.top, csiescseq.arg[0], 0); + break; + case 'T': /* SD -- Scroll line down */ + DEFAULT(csiescseq.arg[0], 1); + tscrolldown(term.top, csiescseq.arg[0], 0); + break; + case 'L': /* IL -- Insert blank lines */ + DEFAULT(csiescseq.arg[0], 1); + tinsertblankline(csiescseq.arg[0]); + break; + case 'l': /* RM -- Reset Mode */ + tsetmode(csiescseq.priv, 0, csiescseq.arg, csiescseq.narg); + break; + case 'M': /* DL -- Delete lines */ + DEFAULT(csiescseq.arg[0], 1); + tdeleteline(csiescseq.arg[0]); + break; + case 'X': /* ECH -- Erase char */ + DEFAULT(csiescseq.arg[0], 1); + tclearregion(term.c.x, term.c.y, + term.c.x + csiescseq.arg[0] - 1, term.c.y); + break; + case 'P': /* DCH -- Delete char */ + DEFAULT(csiescseq.arg[0], 1); + tdeletechar(csiescseq.arg[0]); + break; + case 'Z': /* CBT -- Cursor Backward Tabulation tab stops */ + DEFAULT(csiescseq.arg[0], 1); + tputtab(-csiescseq.arg[0]); + break; + case 'd': /* VPA -- Move to */ + DEFAULT(csiescseq.arg[0], 1); + tmoveato(term.c.x, csiescseq.arg[0]-1); + break; + case 'h': /* SM -- Set terminal mode */ + tsetmode(csiescseq.priv, 1, csiescseq.arg, csiescseq.narg); + break; + case 'm': /* SGR -- Terminal attribute (color) */ + tsetattr(csiescseq.arg, csiescseq.narg); + break; + case 'n': /* DSR – Device Status Report (cursor position) */ + if (csiescseq.arg[0] == 6) { + len = snprintf(buf, sizeof(buf), "\033[%i;%iR", + term.c.y+1, term.c.x+1); + ttywrite(buf, len, 0); + } + break; + case 'r': /* DECSTBM -- Set Scrolling Region */ + if (csiescseq.priv) { + goto unknown; + } else { + DEFAULT(csiescseq.arg[0], 1); + DEFAULT(csiescseq.arg[1], term.row); + tsetscroll(csiescseq.arg[0]-1, csiescseq.arg[1]-1); + tmoveato(0, 0); + } + break; + case 's': /* DECSC -- Save cursor position (ANSI.SYS) */ + tcursor(CURSOR_SAVE); + break; + case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */ + tcursor(CURSOR_LOAD); + break; + case ' ': + switch (csiescseq.mode[1]) { + case 'q': /* DECSCUSR -- Set Cursor Style */ + if (xsetcursor(csiescseq.arg[0])) + goto unknown; + break; + default: + goto unknown; + } + break; + } +} + +void +csidump(void) +{ + size_t i; + uint c; + + fprintf(stderr, "ESC["); + for (i = 0; i < csiescseq.len; i++) { + c = csiescseq.buf[i] & 0xff; + if (isprint(c)) { + putc(c, stderr); + } else if (c == '\n') { + fprintf(stderr, "(\\n)"); + } else if (c == '\r') { + fprintf(stderr, "(\\r)"); + } else if (c == 0x1b) { + fprintf(stderr, "(\\e)"); + } else { + fprintf(stderr, "(%02x)", c); + } + } + putc('\n', stderr); +} + +void +csireset(void) +{ + memset(&csiescseq, 0, sizeof(csiescseq)); +} + +void +strhandle(void) +{ + char *p = NULL, *dec; + int j, narg, par; + + term.esc &= ~(ESC_STR_END|ESC_STR); + strparse(); + par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0; + + switch (strescseq.type) { + case ']': /* OSC -- Operating System Command */ + switch (par) { + case 0: + if (narg > 1) { + title(); + xseticontitle(strescseq.args[1]); + } + return; + case 1: + if (narg > 1) + xseticontitle(strescseq.args[1]); + return; + case 2: + if (narg > 1) + title(); + return; + case 52: + if (narg > 2 && allowwindowops) { + dec = base64dec(strescseq.args[2]); + if (dec) { + xsetsel(dec); + xclipcopy(); + } else { + fprintf(stderr, "erresc: invalid base64\n"); + } + } + return; + case 4: /* color set */ + if (narg < 3) + break; + p = strescseq.args[2]; + /* FALLTHROUGH */ + case 104: /* color reset, here p = NULL */ + j = (narg > 1) ? atoi(strescseq.args[1]) : -1; + if (xsetcolorname(j, p)) { + if (par == 104 && narg <= 1) + return; /* color reset without parameter */ + fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", + j, p ? p : "(null)"); + } else { + /* + * TODO if defaultbg color is changed, borders + * are dirty + */ + redraw(); + } + return; + } + break; + case 'k': /* old title set compatibility */ + title(); + return; + case 'P': /* DCS -- Device Control String */ + case '_': /* APC -- Application Program Command */ + case '^': /* PM -- Privacy Message */ + return; + } + + fprintf(stderr, "erresc: unknown str "); + strdump(); +} + +void +strparse(void) +{ + int c; + char *p = strescseq.buf; + + strescseq.narg = 0; + strescseq.buf[strescseq.len] = '\0'; + + if (*p == '\0') + return; + + while (strescseq.narg < STR_ARG_SIZ) { + strescseq.args[strescseq.narg++] = p; + while ((c = *p) != ';' && c != '\0') + ++p; + if (c == '\0') + return; + *p++ = '\0'; + } +} + + +void +strdump(void) +{ + size_t i; + uint c; + + fprintf(stderr, "ESC%c", strescseq.type); + for (i = 0; i < strescseq.len; i++) { + c = strescseq.buf[i] & 0xff; + if (c == '\0') { + putc('\n', stderr); + return; + } else if (isprint(c)) { + putc(c, stderr); + } else if (c == '\n') { + fprintf(stderr, "(\\n)"); + } else if (c == '\r') { + fprintf(stderr, "(\\r)"); + } else if (c == 0x1b) { + fprintf(stderr, "(\\e)"); + } else { + fprintf(stderr, "(%02x)", c); + } + } + fprintf(stderr, "ESC\\\n"); +} + +void +strreset(void) +{ + strescseq = (STREscape){ + .buf = xrealloc(strescseq.buf, STR_BUF_SIZ), + .siz = STR_BUF_SIZ, + }; +} + +void +sendbreak(const Arg *arg) +{ + if (tcsendbreak(cmdfd, 0)) + perror("Error sending break"); +} + +void +tprinter(char *s, size_t len) +{ + if (iofd != -1 && xwrite(iofd, s, len) < 0) { + perror("Error writing to output file"); + close(iofd); + iofd = -1; + } +} + +void +toggleprinter(const Arg *arg) +{ + term.mode ^= MODE_PRINT; +} + +void +printscreen(const Arg *arg) +{ + tdump(); +} + +void +printsel(const Arg *arg) +{ + tdumpsel(); +} + +void +tdumpsel(void) +{ + char *ptr; + + if ((ptr = getsel())) { + tprinter(ptr, strlen(ptr)); + free(ptr); + } +} + +void +tdumpline(int n) +{ + char buf[UTF_SIZ]; + Glyph *bp, *end; + + bp = &term.line[n][0]; + end = &bp[MIN(tlinelen(n), term.col) - 1]; + if (bp != end || bp->u != ' ') { + for ( ; bp <= end; ++bp) + tprinter(buf, utf8encode(bp->u, buf)); + } + tprinter("\n", 1); +} + +void +tdump(void) +{ + int i; + + for (i = 0; i < term.row; ++i) + tdumpline(i); +} + +void +tputtab(int n) +{ + uint x = term.c.x; + + if (n > 0) { + while (x < term.col && n--) + for (++x; x < term.col && !term.tabs[x]; ++x) + /* nothing */ ; + } else if (n < 0) { + while (x > 0 && n++) + for (--x; x > 0 && !term.tabs[x]; --x) + /* nothing */ ; + } + term.c.x = LIMIT(x, 0, term.col-1); +} + +void +tdefutf8(char ascii) +{ + if (ascii == 'G') + term.mode |= MODE_UTF8; + else if (ascii == '@') + term.mode &= ~MODE_UTF8; +} + +void +tdeftran(char ascii) +{ + static char cs[] = "0B"; + static int vcs[] = {CS_GRAPHIC0, CS_USA}; + char *p; + + if ((p = strchr(cs, ascii)) == NULL) { + fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii); + } else { + term.trantbl[term.icharset] = vcs[p - cs]; + } +} + +void +tdectest(char c) +{ + int x, y; + + if (c == '8') { /* DEC screen alignment test. */ + for (x = 0; x < term.col; ++x) { + for (y = 0; y < term.row; ++y) + tsetchar('E', &term.c.attr, x, y); + } + } +} + +void +tstrsequence(uchar c) +{ + switch (c) { + case 0x90: /* DCS -- Device Control String */ + c = 'P'; + break; + case 0x9f: /* APC -- Application Program Command */ + c = '_'; + break; + case 0x9e: /* PM -- Privacy Message */ + c = '^'; + break; + case 0x9d: /* OSC -- Operating System Command */ + c = ']'; + break; + } + strreset(); + strescseq.type = c; + term.esc |= ESC_STR; +} + +void +tcontrolcode(uchar ascii) +{ + switch (ascii) { + case '\t': /* HT */ + tputtab(1); + return; + case '\b': /* BS */ + tmoveto(term.c.x-1, term.c.y); + return; + case '\r': /* CR */ + tmoveto(0, term.c.y); + return; + case '\f': /* LF */ + case '\v': /* VT */ + case '\n': /* LF */ + /* go to first col if the mode is set */ + tnewline(IS_SET(MODE_CRLF)); + return; + case '\a': /* BEL */ + if (term.esc & ESC_STR_END) { + /* backwards compatibility to xterm */ + strhandle(); + } else { + xbell(); + } + break; + case '\033': /* ESC */ + csireset(); + term.esc &= ~(ESC_CSI|ESC_ALTCHARSET|ESC_TEST); + term.esc |= ESC_START; + return; + case '\016': /* SO (LS1 -- Locking shift 1) */ + case '\017': /* SI (LS0 -- Locking shift 0) */ + term.charset = 1 - (ascii - '\016'); + return; + case '\032': /* SUB */ + tsetchar('?', &term.c.attr, term.c.x, term.c.y); + /* FALLTHROUGH */ + case '\030': /* CAN */ + csireset(); + break; + case '\005': /* ENQ (IGNORED) */ + case '\000': /* NUL (IGNORED) */ + case '\021': /* XON (IGNORED) */ + case '\023': /* XOFF (IGNORED) */ + case 0177: /* DEL (IGNORED) */ + return; + case 0x80: /* TODO: PAD */ + case 0x81: /* TODO: HOP */ + case 0x82: /* TODO: BPH */ + case 0x83: /* TODO: NBH */ + case 0x84: /* TODO: IND */ + break; + case 0x85: /* NEL -- Next line */ + tnewline(1); /* always go to first col */ + break; + case 0x86: /* TODO: SSA */ + case 0x87: /* TODO: ESA */ + break; + case 0x88: /* HTS -- Horizontal tab stop */ + term.tabs[term.c.x] = 1; + break; + case 0x89: /* TODO: HTJ */ + case 0x8a: /* TODO: VTS */ + case 0x8b: /* TODO: PLD */ + case 0x8c: /* TODO: PLU */ + case 0x8d: /* TODO: RI */ + case 0x8e: /* TODO: SS2 */ + case 0x8f: /* TODO: SS3 */ + case 0x91: /* TODO: PU1 */ + case 0x92: /* TODO: PU2 */ + case 0x93: /* TODO: STS */ + case 0x94: /* TODO: CCH */ + case 0x95: /* TODO: MW */ + case 0x96: /* TODO: SPA */ + case 0x97: /* TODO: EPA */ + case 0x98: /* TODO: SOS */ + case 0x99: /* TODO: SGCI */ + break; + case 0x9a: /* DECID -- Identify Terminal */ + ttywrite(vtiden, strlen(vtiden), 0); + break; + case 0x9b: /* TODO: CSI */ + case 0x9c: /* TODO: ST */ + break; + case 0x90: /* DCS -- Device Control String */ + case 0x9d: /* OSC -- Operating System Command */ + case 0x9e: /* PM -- Privacy Message */ + case 0x9f: /* APC -- Application Program Command */ + tstrsequence(ascii); + return; + } + /* only CAN, SUB, \a and C1 chars interrupt a sequence */ + term.esc &= ~(ESC_STR_END|ESC_STR); +} + +/* + * returns 1 when the sequence is finished and it hasn't to read + * more characters for this sequence, otherwise 0 + */ +int +eschandle(uchar ascii) +{ + switch (ascii) { + case '[': + term.esc |= ESC_CSI; + return 0; + case '#': + term.esc |= ESC_TEST; + return 0; + case '%': + term.esc |= ESC_UTF8; + return 0; + case 'P': /* DCS -- Device Control String */ + case '_': /* APC -- Application Program Command */ + case '^': /* PM -- Privacy Message */ + case ']': /* OSC -- Operating System Command */ + case 'k': /* old title set compatibility */ + tstrsequence(ascii); + return 0; + case 'n': /* LS2 -- Locking shift 2 */ + case 'o': /* LS3 -- Locking shift 3 */ + term.charset = 2 + (ascii - 'n'); + break; + case '(': /* GZD4 -- set primary charset G0 */ + case ')': /* G1D4 -- set secondary charset G1 */ + case '*': /* G2D4 -- set tertiary charset G2 */ + case '+': /* G3D4 -- set quaternary charset G3 */ + term.icharset = ascii - '('; + term.esc |= ESC_ALTCHARSET; + return 0; + case 'D': /* IND -- Linefeed */ + if (term.c.y == term.bot) { + tscrollup(term.top, 1, 1); + } else { + tmoveto(term.c.x, term.c.y+1); + } + break; + case 'E': /* NEL -- Next line */ + tnewline(1); /* always go to first col */ + break; + case 'H': /* HTS -- Horizontal tab stop */ + term.tabs[term.c.x] = 1; + break; + case 'M': /* RI -- Reverse index */ + if (term.c.y == term.top) { + tscrolldown(term.top, 1, 1); + } else { + tmoveto(term.c.x, term.c.y-1); + } + break; + case 'Z': /* DECID -- Identify Terminal */ + ttywrite(vtiden, strlen(vtiden), 0); + break; + case 'c': /* RIS -- Reset to initial state */ + treset(); + resettitle(); + xloadcols(); + break; + case '=': /* DECPAM -- Application keypad */ + xsetmode(1, MODE_APPKEYPAD); + break; + case '>': /* DECPNM -- Normal keypad */ + xsetmode(0, MODE_APPKEYPAD); + break; + case '7': /* DECSC -- Save Cursor */ + tcursor(CURSOR_SAVE); + break; + case '8': /* DECRC -- Restore Cursor */ + tcursor(CURSOR_LOAD); + break; + case '\\': /* ST -- String Terminator */ + if (term.esc & ESC_STR_END) + strhandle(); + break; + default: + fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n", + (uchar) ascii, isprint(ascii)? ascii:'.'); + break; + } + return 1; +} + +void +tputc(Rune u) +{ + char c[UTF_SIZ]; + int control; + int width, len; + Glyph *gp; + + control = ISCONTROL(u); + if (u < 127 || !IS_SET(MODE_UTF8)) { + c[0] = u; + width = len = 1; + } else { + len = utf8encode(u, c); + if (!control && (width = wcwidth(u)) == -1) + width = 1; + } + + if (IS_SET(MODE_PRINT)) + tprinter(c, len); + + /* + * STR sequence must be checked before anything else + * because it uses all following characters until it + * receives a ESC, a SUB, a ST or any other C1 control + * character. + */ + if (term.esc & ESC_STR) { + if (u == '\a' || u == 030 || u == 032 || u == 033 || + ISCONTROLC1(u)) { + term.esc &= ~(ESC_START|ESC_STR); + term.esc |= ESC_STR_END; + goto check_control_code; + } + + if (strescseq.len+len >= strescseq.siz) { + /* + * Here is a bug in terminals. If the user never sends + * some code to stop the str or esc command, then st + * will stop responding. But this is better than + * silently failing with unknown characters. At least + * then users will report back. + * + * In the case users ever get fixed, here is the code: + */ + /* + * term.esc = 0; + * strhandle(); + */ + if (strescseq.siz > (SIZE_MAX - UTF_SIZ) / 2) + return; + strescseq.siz *= 2; + strescseq.buf = xrealloc(strescseq.buf, strescseq.siz); + } + + memmove(&strescseq.buf[strescseq.len], c, len); + strescseq.len += len; + return; + } + +check_control_code: + /* + * Actions of control codes must be performed as soon they arrive + * because they can be embedded inside a control sequence, and + * they must not cause conflicts with sequences. + */ + if (control) { + tcontrolcode(u); + /* + * control codes are not shown ever + */ + if (!term.esc) + term.lastc = 0; + return; + } else if (term.esc & ESC_START) { + if (term.esc & ESC_CSI) { + csiescseq.buf[csiescseq.len++] = u; + if (BETWEEN(u, 0x40, 0x7E) + || csiescseq.len >= \ + sizeof(csiescseq.buf)-1) { + term.esc = 0; + csiparse(); + csihandle(); + } + return; + } else if (term.esc & ESC_UTF8) { + tdefutf8(u); + } else if (term.esc & ESC_ALTCHARSET) { + tdeftran(u); + } else if (term.esc & ESC_TEST) { + tdectest(u); + } else { + if (!eschandle(u)) + return; + /* sequence already finished */ + } + term.esc = 0; + /* + * All characters which form part of a sequence are not + * printed + */ + return; + } + if (selected(term.c.x, term.c.y)) + selclear(); + + gp = &term.line[term.c.y][term.c.x]; + if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) { + gp->mode |= ATTR_WRAP; + tnewline(1); + gp = &term.line[term.c.y][term.c.x]; + } + + if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) + memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph)); + + if (term.c.x+width > term.col) { + tnewline(1); + gp = &term.line[term.c.y][term.c.x]; + } + + tsetchar(u, &term.c.attr, term.c.x, term.c.y); + term.lastc = u; + + if (width == 2) { + gp->mode |= ATTR_WIDE; + if (term.c.x+1 < term.col) { + gp[1].u = '\0'; + gp[1].mode = ATTR_WDUMMY; + } + } + if (term.c.x+width < term.col) { + tmoveto(term.c.x+width, term.c.y); + } else { + term.c.state |= CURSOR_WRAPNEXT; + } +} + +int +twrite(const char *buf, int buflen, int show_ctrl) +{ + int charsize; + Rune u; + int n; + + for (n = 0; n < buflen; n += charsize) { + if (IS_SET(MODE_UTF8)) { + /* process a complete utf8 char */ + charsize = utf8decode(buf + n, &u, buflen - n); + if (charsize == 0) + break; + } else { + u = buf[n] & 0xFF; + charsize = 1; + } + if (show_ctrl && ISCONTROL(u)) { + if (u & 0x80) { + u &= 0x7f; + tputc('^'); + tputc('['); + } else if (u != '\n' && u != '\r' && u != '\t') { + u ^= 0x40; + tputc('^'); + } + } + tputc(u); + } + return n; +} + +void +tresize(int col, int row) +{ + int i, j; + int minrow = MIN(row, term.row); + int mincol = MIN(col, term.col); + int *bp; + TCursor c; + + if ( row < term.row || col < term.col ) + toggle_winmode(trt_kbdselect(XK_Escape, NULL, 0)); + + if (col < 1 || row < 1) { + fprintf(stderr, + "tresize: error resizing to %dx%d\n", col, row); + return; + } + + /* + * slide screen to keep cursor where we expect it - + * tscrollup would work here, but we can optimize to + * memmove because we're freeing the earlier lines + */ + for (i = 0; i <= term.c.y - row; i++) { + free(term.line[i]); + free(term.alt[i]); + } + /* ensure that both src and dst are not NULL */ + if (i > 0) { + memmove(term.line, term.line + i, row * sizeof(Line)); + memmove(term.alt, term.alt + i, row * sizeof(Line)); + } + for (i += row; i < term.row; i++) { + free(term.line[i]); + free(term.alt[i]); + } + + /* resize to new height */ + term.line = xrealloc(term.line, row * sizeof(Line)); + term.alt = xrealloc(term.alt, row * sizeof(Line)); + term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); + term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); + + for (i = 0; i < HISTSIZE; i++) { + term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); + for (j = mincol; j < col; j++) { + term.hist[i][j] = term.c.attr; + term.hist[i][j].u = ' '; + } + } + + /* resize each row to new width, zero-pad if needed */ + for (i = 0; i < minrow; i++) { + term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); + term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph)); + } + + /* allocate any new rows */ + for (/* i = minrow */; i < row; i++) { + term.line[i] = xmalloc(col * sizeof(Glyph)); + term.alt[i] = xmalloc(col * sizeof(Glyph)); + } + if (col > term.col) { + bp = term.tabs + term.col; + + memset(bp, 0, sizeof(*term.tabs) * (col - term.col)); + while (--bp > term.tabs && !*bp) + /* nothing */ ; + for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces) + *bp = 1; + } + /* update terminal size */ + term.col = col; + term.row = row; + /* reset scrolling region */ + tsetscroll(0, row-1); + /* make use of the LIMIT in tmoveto */ + tmoveto(term.c.x, term.c.y); + /* Clearing both screens (it makes dirty all lines) */ + c = term.c; + for (i = 0; i < 2; i++) { + if (mincol < col && 0 < minrow) { + tclearregion(mincol, 0, col - 1, minrow - 1); + } + if (0 < col && minrow < row) { + tclearregion(0, minrow, col - 1, row - 1); + } + tswapscreen(); + tcursor(CURSOR_LOAD); + } + term.c = c; +} + +void +resettitle(void) +{ + title(); +} + +void +drawregion(int x1, int y1, int x2, int y2) +{ + int y; + + for (y = y1; y < y2; y++) { + if (!term.dirty[y]) + continue; + + term.dirty[y] = 0; + xdrawline(TLINE(y), x1, y, x2); + } +} + +void +draw(void) +{ + int cx = term.c.x, ocx = term.ocx, ocy = term.ocy; + + if (!xstartdraw()) + return; + + /* adjust cursor position */ + LIMIT(term.ocx, 0, term.col-1); + LIMIT(term.ocy, 0, term.row-1); + if (term.line[term.ocy][term.ocx].mode & ATTR_WDUMMY) + term.ocx--; + if (term.line[term.c.y][cx].mode & ATTR_WDUMMY) + cx--; + + drawregion(0, 0, term.col, term.row); + if (term.scr == 0) + xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], + term.ocx, term.ocy, term.line[term.ocy][term.ocx], + term.line[term.ocy], term.col); + term.ocx = cx; + term.ocy = term.c.y; + xfinishdraw(); + if (ocx != term.ocx || ocy != term.ocy) + xximspot(term.ocx, term.ocy); +} + +void +redraw(void) +{ + tfulldirt(); + draw(); +} + +void set_notifmode(int type, KeySym ksym) { + static char *lib[] = { " MOVE ", " SEL "}; + static Glyph *g, *deb, *fin; + static int col, bot; + + if ( ksym == -1 ) { + free(g); + col = term.col, bot = term.bot; + g = xmalloc(col * sizeof(Glyph)); + memcpy(g, term.line[bot], col * sizeof(Glyph)); + + } + else if ( ksym == -2 ) + memcpy(term.line[bot], g, col * sizeof(Glyph)); + + if ( type < 2 ) { + char *z = lib[type]; + for (deb = &term.line[bot][col - 6], fin = &term.line[bot][col]; deb < fin; z++, deb++) + deb->mode = ATTR_REVERSE, + deb->u = *z, + deb->fg = defaultfg, deb->bg = defaultbg; + } + else if ( type < 5 ) + memcpy(term.line[bot], g, col * sizeof(Glyph)); + else { + for (deb = &term.line[bot][0], fin = &term.line[bot][col]; deb < fin; deb++) + deb->mode = ATTR_REVERSE, + deb->u = ' ', + deb->fg = defaultfg, deb->bg = defaultbg; + term.line[bot][0].u = ksym; + } + + term.dirty[bot] = 1; + drawregion(0, bot, col, bot + 1); +} + +void select_or_drawcursor(int selectsearch_mode, int type) { + int done = 0; + + if ( selectsearch_mode & 1 ) { + selextend(term.c.x, term.c.y, type, done); + xsetsel(getsel()); + } + else + xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x], + term.ocx, term.ocy, term.line[term.ocy][term.ocx], + term.line[term.ocy], term.col); +} + +void search(int selectsearch_mode, Rune *target, int ptarget, int incr, int type, TCursor *cu) { + Rune *r; + int i, bound = (term.col * cu->y + cu->x) * (incr > 0) + incr; + + for (i = term.col * term.c.y + term.c.x + incr; i != bound; i += incr) { + for (r = target; r - target < ptarget; r++) { + if ( *r == term.line[(i + r - target) / term.col][(i + r - target) % term.col].u ) { + if ( r - target == ptarget - 1 ) break; + } else { + r = NULL; + break; + } + } + if ( r != NULL ) break; + } + + if ( i != bound ) { + term.c.y = i / term.col, term.c.x = i % term.col; + select_or_drawcursor(selectsearch_mode, type); + } +} + +int trt_kbdselect(KeySym ksym, char *buf, int len) { + static TCursor cu; + static Rune target[64]; + static int type = 1, ptarget, in_use; + static int sens, quant; + static char selectsearch_mode; + int i, bound, *xy; + + + if ( selectsearch_mode & 2 ) { + if ( ksym == XK_Return ) { + selectsearch_mode ^= 2; + set_notifmode(selectsearch_mode, -2); + if ( ksym == XK_Escape ) ptarget = 0; + return 0; + } + else if ( ksym == XK_BackSpace ) { + if ( !ptarget ) return 0; + term.line[term.bot][ptarget--].u = ' '; + } + else if ( len < 1 ) { + return 0; + } + else if ( ptarget == term.col || ksym == XK_Escape ) { + return 0; + } + else { + utf8decode(buf, &target[ptarget++], len); + term.line[term.bot][ptarget].u = target[ptarget - 1]; + } + + if ( ksym != XK_BackSpace ) + search(selectsearch_mode, &target[0], ptarget, sens, type, &cu); + + term.dirty[term.bot] = 1; + drawregion(0, term.bot, term.col, term.bot + 1); + return 0; + } + + switch ( ksym ) { + case -1 : + in_use = 1; + cu.x = term.c.x, cu.y = term.c.y; + set_notifmode(0, ksym); + return MODE_KBDSELECT; + case XK_v : + if ( selectsearch_mode & 1 ) + selclear(); + else + selstart(term.c.x, term.c.y, 0); + set_notifmode(selectsearch_mode ^= 1, ksym); + break; + case XK_t : + selextend(term.c.x, term.c.y, type ^= 3, i = 0); /* 2 fois */ + selextend(term.c.x, term.c.y, type, i = 0); + break; + case XK_slash : + case XK_KP_Divide : + case XK_question : + ksym &= XK_question; /* Divide to slash */ + sens = (ksym == XK_slash) ? -1 : 1; + ptarget = 0; + set_notifmode(15, ksym); + selectsearch_mode ^= 2; + break; + case XK_Escape : + if ( !in_use ) break; + selclear(); + case XK_Return : + set_notifmode(4, ksym); + term.c.x = cu.x, term.c.y = cu.y; + select_or_drawcursor(selectsearch_mode = 0, type); + in_use = quant = 0; + return MODE_KBDSELECT; + case XK_n : + case XK_N : + if ( ptarget ) + search(selectsearch_mode, &target[0], ptarget, (ksym == XK_n) ? -1 : 1, type, &cu); + break; + case XK_BackSpace : + term.c.x = 0; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_dollar : + term.c.x = term.col - 1; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_g : + term.c.x = 0, term.c.y = 0; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_f : + term.c.x = cu.x, term.c.y = cu.y; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_Page_Up : + case XK_Page_Down : + term.c.y = (ksym == XK_Prior ) ? 0 : cu.y; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_exclam : + term.c.x = term.col >> 1; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_asterisk : + case XK_KP_Multiply : + term.c.x = term.col >> 1; + case XK_underscore : + term.c.y = cu.y >> 1; + select_or_drawcursor(selectsearch_mode, type); + break; + default : + if ( ksym >= XK_0 && ksym <= XK_9 ) { /* 0-9 keyboard */ + quant = (quant * 10) + (ksym ^ XK_0); + return 0; + } + else if ( ksym >= XK_KP_0 && ksym <= XK_KP_9 ) { /* 0-9 numpad */ + quant = (quant * 10) + (ksym ^ XK_KP_0); + return 0; + } + else if ( ksym == XK_k || ksym == XK_h ) + i = ksym & 1; + else if ( ksym == XK_l || ksym == XK_j ) + i = ((ksym & 6) | 4) >> 1; + else if ( (XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3 ) + break; + + xy = (i & 1) ? &term.c.y : &term.c.x; + sens = (i & 2) ? 1 : -1; + bound = (i >> 1 ^ 1) ? 0 : (i ^ 3) ? term.col - 1 : term.bot; + + if ( quant == 0 ) + quant++; + + if ( *xy == bound && ((sens < 0 && bound == 0) || (sens > 0 && bound > 0)) ) + break; + + *xy += quant * sens; + if ( *xy < 0 || ( bound > 0 && *xy > bound) ) + *xy = bound; + + select_or_drawcursor(selectsearch_mode, type); + } + quant = 0; + return 0; +} + +void +tsetcolor( int row, int start, int end, uint32_t fg, uint32_t bg ) +{ + int i = start; + for( ; i < end; ++i ) + { + term.line[row][i].fg = fg; + term.line[row][i].bg = bg; + } +} + +char * +findlastany(char *str, const char** find, size_t len) +{ + char* found = NULL; + int i = 0; + for(found = str + strlen(str) - 1; found >= str; --found) { + for(i = 0; i < len; i++) { + if(strncmp(found, find[i], strlen(find[i])) == 0) { + return found; + } + } + } + + return NULL; +} + +/* +** Select and copy the previous url on screen (do nothing if there's no url). +** +** FIXME: doesn't handle urls that span multiple lines; will need to add support +** for multiline "getsel()" first +*/ +void +copyurl(const Arg *arg) { + /* () and [] can appear in urls, but excluding them here will reduce false + * positives when figuring out where a given url ends. + */ + static char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-._~:/?#@!$&'*+,;=%"; + + static const char* URLSTRINGS[] = {"http://", "https://"}; + + /* remove highlighting from previous selection if any */ + if(sel.ob.x >= 0 && sel.oe.x >= 0) + tsetcolor(sel.nb.y, sel.ob.x, sel.oe.x + 1, defaultfg, defaultbg); + + int i = 0, + row = 0, /* row of current URL */ + col = 0, /* column of current URL start */ + startrow = 0, /* row of last occurrence */ + colend = 0, /* column of last occurrence */ + passes = 0; /* how many rows have been scanned */ + + char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ + char *c = NULL, + *match = NULL; + + row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot; + LIMIT(row, term.top, term.bot); + startrow = row; + + colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col; + LIMIT(colend, 0, term.col); + + /* + ** Scan from (term.bot,term.col) to (0,0) and find + ** next occurrance of a URL + */ + while(passes !=term.bot + 2) { + /* Read in each column of every row until + ** we hit previous occurrence of URL + */ + for (col = 0, i = 0; col < colend; ++col,++i) { + /* assume ascii */ + if (term.line[row][col].u > 127) + continue; + linestr[i] = term.line[row][col].u; + } + linestr[term.col] = '\0'; + + if ((match = findlastany(linestr, URLSTRINGS, + sizeof(URLSTRINGS)/sizeof(URLSTRINGS[0])))) + break; + + if (--row < term.top) + row = term.bot; + + colend = term.col; + passes++; + }; + + if (match) { + /* must happen before trim */ + selclear(); + sel.ob.x = strlen(linestr) - strlen(match); + + /* trim the rest of the line from the url match */ + for (c = match; *c != '\0'; ++c) + if (!strchr(URLCHARS, *c)) { + *c = '\0'; + break; + } + + /* highlight selection by inverting terminal colors */ + tsetcolor(row, sel.ob.x, sel.ob.x + strlen( match ),9, defaultbg); + + /* select and copy */ + sel.mode = 1; + sel.type = SEL_REGULAR; + sel.oe.x = sel.ob.x + strlen(match)-1; + sel.ob.y = sel.oe.y = row; + selnormalize(); + tsetdirt(sel.nb.y, sel.ne.y); + xsetsel(getsel()); + xclipcopy(); + } + + free(linestr); +} diff --git a/st.c.orig.orig b/st.c.orig.orig new file mode 100644 index 0000000..9004c46 --- /dev/null +++ b/st.c.orig.orig @@ -0,0 +1,3051 @@ +/* See LICENSE for license details. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "st.h" +#include "win.h" + +#if defined(__linux) + #include +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) + #include +#elif defined(__FreeBSD__) || defined(__DragonFly__) + #include +#endif + +/* Arbitrary sizes */ +#define UTF_INVALID 0xFFFD +#define UTF_SIZ 4 +#define ESC_BUF_SIZ (128*UTF_SIZ) +#define ESC_ARG_SIZ 16 +#define STR_BUF_SIZ ESC_BUF_SIZ +#define STR_ARG_SIZ ESC_ARG_SIZ +#define HISTSIZE 2000 + +/* macros */ +#define IS_SET(flag) ((term.mode & (flag)) != 0) +#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == 0x7f) +#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) +#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) +#define ISDELIM(u) (u && wcschr(worddelimiters, u)) +#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \ + term.scr + HISTSIZE + 1) % HISTSIZE] : \ + term.line[(y) - term.scr]) + +enum term_mode { + MODE_WRAP = 1 << 0, + MODE_INSERT = 1 << 1, + MODE_ALTSCREEN = 1 << 2, + MODE_CRLF = 1 << 3, + MODE_ECHO = 1 << 4, + MODE_PRINT = 1 << 5, + MODE_UTF8 = 1 << 6, +}; + +enum cursor_movement { + CURSOR_SAVE, + CURSOR_LOAD +}; + +enum cursor_state { + CURSOR_DEFAULT = 0, + CURSOR_WRAPNEXT = 1, + CURSOR_ORIGIN = 2 +}; + +enum charset { + CS_GRAPHIC0, + CS_GRAPHIC1, + CS_UK, + CS_USA, + CS_MULTI, + CS_GER, + CS_FIN +}; + +enum escape_state { + ESC_START = 1, + ESC_CSI = 2, + ESC_STR = 4, /* DCS, OSC, PM, APC */ + ESC_ALTCHARSET = 8, + ESC_STR_END = 16, /* a final string was encountered */ + ESC_TEST = 32, /* Enter in test mode */ + ESC_UTF8 = 64, +}; + +typedef struct { + Glyph attr; /* current char attributes */ + int x; + int y; + char state; +} TCursor; + +typedef struct { + int mode; + int type; + int snap; + /* + * Selection variables: + * nb – normalized coordinates of the beginning of the selection + * ne – normalized coordinates of the end of the selection + * ob – original coordinates of the beginning of the selection + * oe – original coordinates of the end of the selection + */ + struct { + int x, y; + } nb, ne, ob, oe; + + int alt; +} Selection; + +/* Internal representation of the screen */ +typedef struct { + int row; /* nb row */ + int col; /* nb col */ + Line *line; /* screen */ + Line *alt; /* alternate screen */ + Line hist[HISTSIZE]; /* history buffer */ + int histi; /* history index */ + int scr; /* scroll back */ + int *dirty; /* dirtyness of lines */ + TCursor c; /* cursor */ + int ocx; /* old cursor col */ + int ocy; /* old cursor row */ + int top; /* top scroll limit */ + int bot; /* bottom scroll limit */ + int mode; /* terminal mode flags */ + int esc; /* escape state flags */ + char trantbl[4]; /* charset table translation */ + int charset; /* current charset */ + int icharset; /* selected charset for sequence */ + int *tabs; + Rune lastc; /* last printed char outside of sequence, 0 if control */ +} Term; + +/* CSI Escape sequence structs */ +/* ESC '[' [[ [] [;]] []] */ +typedef struct { + char buf[ESC_BUF_SIZ]; /* raw string */ + size_t len; /* raw string length */ + char priv; + int arg[ESC_ARG_SIZ]; + int narg; /* nb of args */ + char mode[2]; +} CSIEscape; + +/* STR Escape sequence structs */ +/* ESC type [[ [] [;]] ] ESC '\' */ +typedef struct { + char type; /* ESC type ... */ + char *buf; /* allocated raw string */ + size_t siz; /* allocation size */ + size_t len; /* raw string length */ + char *args[STR_ARG_SIZ]; + int narg; /* nb of args */ +} STREscape; + +static void execsh(char *, char **); +static char *getcwd_by_pid(pid_t pid); +static void stty(char **); +static void sigchld(int); +static void ttywriteraw(const char *, size_t); + +static void csidump(void); +static void csihandle(void); +static void csiparse(void); +static void csireset(void); +static int eschandle(uchar); +static void strdump(void); +static void strhandle(void); +static void strparse(void); +static void strreset(void); + +static void tprinter(char *, size_t); +static void tdumpsel(void); +static void tdumpline(int); +static void tdump(void); +static void tclearregion(int, int, int, int); +static void tcursor(int); +static void tdeletechar(int); +static void tdeleteline(int); +static void tinsertblank(int); +static void tinsertblankline(int); +static int tlinelen(int); +static void tmoveto(int, int); +static void tmoveato(int, int); +static void tnewline(int); +static void tputtab(int); +static void tputc(Rune); +static void treset(void); +static void tscrollup(int, int, int); +static void tscrolldown(int, int, int); +static void tsetattr(int *, int); +static void tsetchar(Rune, Glyph *, int, int); +static void tsetdirt(int, int); +static void tsetscroll(int, int); +static void tswapscreen(void); +static void tsetmode(int, int, int *, int); +static int twrite(const char *, int, int); +static void tcontrolcode(uchar ); +static void tdectest(char ); +static void tdefutf8(char); +static int32_t tdefcolor(int *, int *, int); +static void tdeftran(char); +static void tstrsequence(uchar); +static void tsetcolor(int, int, int, uint32_t, uint32_t); +static char * findlastany(char *, const char**, size_t); + +static void drawregion(int, int, int, int); + +static void selnormalize(void); +static void selscroll(int, int); +static void selsnap(int *, int *, int); + +static size_t utf8decode(const char *, Rune *, size_t); +static Rune utf8decodebyte(char, size_t *); +static char utf8encodebyte(Rune, size_t); +static size_t utf8validate(Rune *, size_t); + +static char *base64dec(const char *); +static char base64dec_getc(const char **); + +static ssize_t xwrite(int, const char *, size_t); + +/* Globals */ +static Term term; +static Selection sel; +static CSIEscape csiescseq; +static STREscape strescseq; +static int iofd = 1; +static int cmdfd; +static pid_t pid; + +static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + +ssize_t +xwrite(int fd, const char *s, size_t len) +{ + size_t aux = len; + ssize_t r; + + while (len > 0) { + r = write(fd, s, len); + if (r < 0) + return r; + len -= r; + s += r; + } + + return aux; +} + +void * +xmalloc(size_t len) +{ + void *p; + + if (!(p = malloc(len))) + die("malloc: %s\n", strerror(errno)); + + return p; +} + +void * +xrealloc(void *p, size_t len) +{ + if ((p = realloc(p, len)) == NULL) + die("realloc: %s\n", strerror(errno)); + + return p; +} + +char * +xstrdup(char *s) +{ + if ((s = strdup(s)) == NULL) + die("strdup: %s\n", strerror(errno)); + + return s; +} + +size_t +utf8decode(const char *c, Rune *u, size_t clen) +{ + size_t i, j, len, type; + Rune udecoded; + + *u = UTF_INVALID; + if (!clen) + return 0; + udecoded = utf8decodebyte(c[0], &len); + if (!BETWEEN(len, 1, UTF_SIZ)) + return 1; + for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); + if (type != 0) + return j; + } + if (j < len) + return 0; + *u = udecoded; + utf8validate(u, len); + + return len; +} + +Rune +utf8decodebyte(char c, size_t *i) +{ + for (*i = 0; *i < LEN(utfmask); ++(*i)) + if (((uchar)c & utfmask[*i]) == utfbyte[*i]) + return (uchar)c & ~utfmask[*i]; + + return 0; +} + +size_t +utf8encode(Rune u, char *c) +{ + size_t len, i; + + len = utf8validate(&u, 0); + if (len > UTF_SIZ) + return 0; + + for (i = len - 1; i != 0; --i) { + c[i] = utf8encodebyte(u, 0); + u >>= 6; + } + c[0] = utf8encodebyte(u, len); + + return len; +} + +char +utf8encodebyte(Rune u, size_t i) +{ + return utfbyte[i] | (u & ~utfmask[i]); +} + +size_t +utf8validate(Rune *u, size_t i) +{ + if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) + *u = UTF_INVALID; + for (i = 1; *u > utfmax[i]; ++i) + ; + + return i; +} + +static const char base64_digits[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, + 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, -1, 0, 0, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +char +base64dec_getc(const char **src) +{ + while (**src && !isprint(**src)) + (*src)++; + return **src ? *((*src)++) : '='; /* emulate padding if string ends */ +} + +char * +base64dec(const char *src) +{ + size_t in_len = strlen(src); + char *result, *dst; + + if (in_len % 4) + in_len += 4 - (in_len % 4); + result = dst = xmalloc(in_len / 4 * 3 + 1); + while (*src) { + int a = base64_digits[(unsigned char) base64dec_getc(&src)]; + int b = base64_digits[(unsigned char) base64dec_getc(&src)]; + int c = base64_digits[(unsigned char) base64dec_getc(&src)]; + int d = base64_digits[(unsigned char) base64dec_getc(&src)]; + + /* invalid input. 'a' can be -1, e.g. if src is "\n" (c-str) */ + if (a == -1 || b == -1) + break; + + *dst++ = (a << 2) | ((b & 0x30) >> 4); + if (c == -1) + break; + *dst++ = ((b & 0x0f) << 4) | ((c & 0x3c) >> 2); + if (d == -1) + break; + *dst++ = ((c & 0x03) << 6) | d; + } + *dst = '\0'; + return result; +} + +void +selinit(void) +{ + sel.mode = SEL_IDLE; + sel.snap = 0; + sel.ob.x = -1; +} + +int +tlinelen(int y) +{ + int i = term.col; + + if (TLINE(y)[i - 1].mode & ATTR_WRAP) + return i; + + while (i > 0 && TLINE(y)[i - 1].u == ' ') + --i; + + return i; +} + +void +selstart(int col, int row, int snap) +{ + selclear(); + sel.mode = SEL_EMPTY; + sel.type = SEL_REGULAR; + sel.alt = IS_SET(MODE_ALTSCREEN); + sel.snap = snap; + sel.oe.x = sel.ob.x = col; + sel.oe.y = sel.ob.y = row; + selnormalize(); + + if (sel.snap != 0) + sel.mode = SEL_READY; + tsetdirt(sel.nb.y, sel.ne.y); +} + +void +selextend(int col, int row, int type, int done) +{ + int oldey, oldex, oldsby, oldsey, oldtype; + + if (sel.mode == SEL_IDLE) + return; + if (done && sel.mode == SEL_EMPTY) { + selclear(); + return; + } + + oldey = sel.oe.y; + oldex = sel.oe.x; + oldsby = sel.nb.y; + oldsey = sel.ne.y; + oldtype = sel.type; + + sel.oe.x = col; + sel.oe.y = row; + selnormalize(); + sel.type = type; + + if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY) + tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); + + sel.mode = done ? SEL_IDLE : SEL_READY; +} + +void +selnormalize(void) +{ + int i; + + if (sel.type == SEL_REGULAR && sel.ob.y != sel.oe.y) { + sel.nb.x = sel.ob.y < sel.oe.y ? sel.ob.x : sel.oe.x; + sel.ne.x = sel.ob.y < sel.oe.y ? sel.oe.x : sel.ob.x; + } else { + sel.nb.x = MIN(sel.ob.x, sel.oe.x); + sel.ne.x = MAX(sel.ob.x, sel.oe.x); + } + sel.nb.y = MIN(sel.ob.y, sel.oe.y); + sel.ne.y = MAX(sel.ob.y, sel.oe.y); + + selsnap(&sel.nb.x, &sel.nb.y, -1); + selsnap(&sel.ne.x, &sel.ne.y, +1); + + /* expand selection over line breaks */ + if (sel.type == SEL_RECTANGULAR) + return; + i = tlinelen(sel.nb.y); + if (i < sel.nb.x) + sel.nb.x = i; + if (tlinelen(sel.ne.y) <= sel.ne.x) + sel.ne.x = term.col - 1; +} + +int +selected(int x, int y) +{ + if (sel.mode == SEL_EMPTY || sel.ob.x == -1 || + sel.alt != IS_SET(MODE_ALTSCREEN)) + return 0; + + if (sel.type == SEL_RECTANGULAR) + return BETWEEN(y, sel.nb.y, sel.ne.y) + && BETWEEN(x, sel.nb.x, sel.ne.x); + + return BETWEEN(y, sel.nb.y, sel.ne.y) + && (y != sel.nb.y || x >= sel.nb.x) + && (y != sel.ne.y || x <= sel.ne.x); +} + +void +selsnap(int *x, int *y, int direction) +{ + int newx, newy, xt, yt; + int delim, prevdelim; + Glyph *gp, *prevgp; + + switch (sel.snap) { + case SNAP_WORD: + /* + * Snap around if the word wraps around at the end or + * beginning of a line. + */ + prevgp = &TLINE(*y)[*x]; + prevdelim = ISDELIM(prevgp->u); + for (;;) { + newx = *x + direction; + newy = *y; + if (!BETWEEN(newx, 0, term.col - 1)) { + newy += direction; + newx = (newx + term.col) % term.col; + if (!BETWEEN(newy, 0, term.row - 1)) + break; + + if (direction > 0) + yt = *y, xt = *x; + else + yt = newy, xt = newx; + if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) + break; + } + + if (newx >= tlinelen(newy)) + break; + + gp = &TLINE(newy)[newx]; + delim = ISDELIM(gp->u); + if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim + || (delim && gp->u != prevgp->u))) + break; + + *x = newx; + *y = newy; + prevgp = gp; + prevdelim = delim; + } + break; + case SNAP_LINE: + /* + * Snap around if the the previous line or the current one + * has set ATTR_WRAP at its end. Then the whole next or + * previous line will be selected. + */ + *x = (direction < 0) ? 0 : term.col - 1; + if (direction < 0) { + for (; *y > 0; *y += direction) { + if (!(TLINE(*y-1)[term.col-1].mode + & ATTR_WRAP)) { + break; + } + } + } else if (direction > 0) { + for (; *y < term.row-1; *y += direction) { + if (!(TLINE(*y)[term.col-1].mode + & ATTR_WRAP)) { + break; + } + } + } + break; + } +} + +char * +getsel(void) +{ + char *str, *ptr; + int y, bufsize, lastx, linelen; + Glyph *gp, *last; + + if (sel.ob.x == -1) + return NULL; + + bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ; + ptr = str = xmalloc(bufsize); + + /* append every set & selected glyph to the selection */ + for (y = sel.nb.y; y <= sel.ne.y; y++) { + if ((linelen = tlinelen(y)) == 0) { + *ptr++ = '\n'; + continue; + } + + if (sel.type == SEL_RECTANGULAR) { + gp = &TLINE(y)[sel.nb.x]; + lastx = sel.ne.x; + } else { + gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; + lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; + } + last = &TLINE(y)[MIN(lastx, linelen-1)]; + while (last >= gp && last->u == ' ') + --last; + + for ( ; gp <= last; ++gp) { + if (gp->mode & ATTR_WDUMMY) + continue; + + ptr += utf8encode(gp->u, ptr); + } + + /* + * Copy and pasting of line endings is inconsistent + * in the inconsistent terminal and GUI world. + * The best solution seems like to produce '\n' when + * something is copied from st and convert '\n' to + * '\r', when something to be pasted is received by + * st. + * FIXME: Fix the computer world. + */ + if ((y < sel.ne.y || lastx >= linelen) && + (!(last->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR)) + *ptr++ = '\n'; + } + *ptr = 0; + return str; +} + +void +selclear(void) +{ + if (sel.ob.x == -1) + return; + sel.mode = SEL_IDLE; + sel.ob.x = -1; + tsetdirt(sel.nb.y, sel.ne.y); +} + +void +die(const char *errstr, ...) +{ + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(1); +} + +void +execsh(char *cmd, char **args) +{ + char *sh, *prog, *arg; + const struct passwd *pw; + + errno = 0; + if ((pw = getpwuid(getuid())) == NULL) { + if (errno) + die("getpwuid: %s\n", strerror(errno)); + else + die("who are you?\n"); + } + + if ((sh = getenv("SHELL")) == NULL) + sh = (pw->pw_shell[0]) ? pw->pw_shell : cmd; + + if (args) { + prog = args[0]; + arg = NULL; + } else if (scroll) { + prog = scroll; + arg = utmp ? utmp : sh; + } else if (utmp) { + prog = utmp; + arg = NULL; + } else { + prog = sh; + arg = NULL; + } + DEFAULT(args, ((char *[]) {prog, arg, NULL})); + + unsetenv("COLUMNS"); + unsetenv("LINES"); + unsetenv("TERMCAP"); + setenv("LOGNAME", pw->pw_name, 1); + setenv("USER", pw->pw_name, 1); + setenv("SHELL", sh, 1); + setenv("HOME", pw->pw_dir, 1); + setenv("TERM", termname, 1); + + signal(SIGCHLD, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGALRM, SIG_DFL); + + execvp(prog, args); + _exit(1); +} + +void +sigchld(int a) +{ + int stat; + pid_t p; + + if ((p = waitpid(pid, &stat, WNOHANG)) < 0) + die("waiting for pid %hd failed: %s\n", pid, strerror(errno)); + + if (pid != p) + if (WIFEXITED(stat) && WEXITSTATUS(stat)) + die("child exited with status %d\n", WEXITSTATUS(stat)); + else if (WIFSIGNALED(stat)) + die("child terminated due to signal %d\n", WTERMSIG(stat)); + _exit(0); +} + +void +stty(char **args) +{ + char cmd[_POSIX_ARG_MAX], **p, *q, *s; + size_t n, siz; + + if ((n = strlen(stty_args)) > sizeof(cmd)-1) + die("incorrect stty parameters\n"); + memcpy(cmd, stty_args, n); + q = cmd + n; + siz = sizeof(cmd) - n; + for (p = args; p && (s = *p); ++p) { + if ((n = strlen(s)) > siz-1) + die("stty parameter length too long\n"); + *q++ = ' '; + memcpy(q, s, n); + q += n; + siz -= n + 1; + } + *q = '\0'; + if (system(cmd) != 0) + perror("Couldn't call stty"); +} + +int +ttynew(char *line, char *cmd, char *out, char **args) +{ + int m, s; + + if (out) { + term.mode |= MODE_PRINT; + iofd = (!strcmp(out, "-")) ? + 1 : open(out, O_WRONLY | O_CREAT, 0666); + if (iofd < 0) { + fprintf(stderr, "Error opening %s:%s\n", + out, strerror(errno)); + } + } + + if (line) { + if ((cmdfd = open(line, O_RDWR)) < 0) + die("open line '%s' failed: %s\n", + line, strerror(errno)); + dup2(cmdfd, 0); + stty(args); + return cmdfd; + } + + /* seems to work fine on linux, openbsd and freebsd */ + if (openpty(&m, &s, NULL, NULL, NULL) < 0) + die("openpty failed: %s\n", strerror(errno)); + + switch (pid = fork()) { + case -1: + die("fork failed: %s\n", strerror(errno)); + break; + case 0: + close(iofd); + setsid(); /* create a new process group */ + dup2(s, 0); + dup2(s, 1); + dup2(s, 2); + if (ioctl(s, TIOCSCTTY, NULL) < 0) + die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); + close(s); + close(m); +#ifdef __OpenBSD__ + if (pledge("stdio getpw proc exec", NULL) == -1) + die("pledge\n"); +#endif + execsh(cmd, args); + break; + default: +#ifdef __OpenBSD__ + if (pledge("stdio rpath tty proc", NULL) == -1) + die("pledge\n"); +#endif + close(s); + cmdfd = m; + signal(SIGCHLD, sigchld); + break; + } + return cmdfd; +} + +size_t +ttyread(void) +{ + static char buf[BUFSIZ]; + static int buflen = 0; + int ret, written; + + /* append read bytes to unprocessed bytes */ + ret = read(cmdfd, buf+buflen, LEN(buf)-buflen); + + switch (ret) { + case 0: + exit(0); + case -1: + die("couldn't read from shell: %s\n", strerror(errno)); + default: + buflen += ret; + written = twrite(buf, buflen, 0); + buflen -= written; + /* keep any incomplete UTF-8 byte sequence for the next call */ + if (buflen > 0) + memmove(buf, buf + written, buflen); + return ret; + } +} + +void +ttywrite(const char *s, size_t n, int may_echo) +{ + const char *next; + Arg arg = (Arg) { .i = term.scr }; + + kscrolldown(&arg); + + if (may_echo && IS_SET(MODE_ECHO)) + twrite(s, n, 1); + + if (!IS_SET(MODE_CRLF)) { + ttywriteraw(s, n); + return; + } + + /* This is similar to how the kernel handles ONLCR for ttys */ + while (n > 0) { + if (*s == '\r') { + next = s + 1; + ttywriteraw("\r\n", 2); + } else { + next = memchr(s, '\r', n); + DEFAULT(next, s + n); + ttywriteraw(s, next - s); + } + n -= next - s; + s = next; + } +} + +void +ttywriteraw(const char *s, size_t n) +{ + fd_set wfd, rfd; + ssize_t r; + size_t lim = 256; + + /* + * Remember that we are using a pty, which might be a modem line. + * Writing too much will clog the line. That's why we are doing this + * dance. + * FIXME: Migrate the world to Plan 9. + */ + while (n > 0) { + FD_ZERO(&wfd); + FD_ZERO(&rfd); + FD_SET(cmdfd, &wfd); + FD_SET(cmdfd, &rfd); + + /* Check if we can write. */ + if (pselect(cmdfd+1, &rfd, &wfd, NULL, NULL, NULL) < 0) { + if (errno == EINTR) + continue; + die("select failed: %s\n", strerror(errno)); + } + if (FD_ISSET(cmdfd, &wfd)) { + /* + * Only write the bytes written by ttywrite() or the + * default of 256. This seems to be a reasonable value + * for a serial line. Bigger values might clog the I/O. + */ + if ((r = write(cmdfd, s, (n < lim)? n : lim)) < 0) + goto write_error; + if (r < n) { + /* + * We weren't able to write out everything. + * This means the buffer is getting full + * again. Empty it. + */ + if (n < lim) + lim = ttyread(); + n -= r; + s += r; + } else { + /* All bytes have been written. */ + break; + } + } + if (FD_ISSET(cmdfd, &rfd)) + lim = ttyread(); + } + return; + +write_error: + die("write error on tty: %s\n", strerror(errno)); +} + +void +ttyresize(int tw, int th) +{ + struct winsize w; + + w.ws_row = term.row; + w.ws_col = term.col; + w.ws_xpixel = tw; + w.ws_ypixel = th; + if (ioctl(cmdfd, TIOCSWINSZ, &w) < 0) + fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno)); +} + +void +ttyhangup() +{ + /* Send SIGHUP to shell */ + kill(pid, SIGHUP); +} + +int +tattrset(int attr) +{ + int i, j; + + for (i = 0; i < term.row-1; i++) { + for (j = 0; j < term.col-1; j++) { + if (term.line[i][j].mode & attr) + return 1; + } + } + + return 0; +} + +void +tsetdirt(int top, int bot) +{ + int i; + + LIMIT(top, 0, term.row-1); + LIMIT(bot, 0, term.row-1); + + for (i = top; i <= bot; i++) + term.dirty[i] = 1; +} + +void +tsetdirtattr(int attr) +{ + int i, j; + + for (i = 0; i < term.row-1; i++) { + for (j = 0; j < term.col-1; j++) { + if (term.line[i][j].mode & attr) { + tsetdirt(i, i); + break; + } + } + } +} + +void +tfulldirt(void) +{ + tsetdirt(0, term.row-1); +} + +void +tcursor(int mode) +{ + static TCursor c[2]; + int alt = IS_SET(MODE_ALTSCREEN); + + if (mode == CURSOR_SAVE) { + c[alt] = term.c; + } else if (mode == CURSOR_LOAD) { + term.c = c[alt]; + tmoveto(c[alt].x, c[alt].y); + } +} + +void +treset(void) +{ + uint i; + + term.c = (TCursor){{ + .mode = ATTR_NULL, + .fg = defaultfg, + .bg = defaultbg + }, .x = 0, .y = 0, .state = CURSOR_DEFAULT}; + + memset(term.tabs, 0, term.col * sizeof(*term.tabs)); + for (i = tabspaces; i < term.col; i += tabspaces) + term.tabs[i] = 1; + term.top = 0; + term.bot = term.row - 1; + term.mode = MODE_WRAP|MODE_UTF8; + memset(term.trantbl, CS_USA, sizeof(term.trantbl)); + term.charset = 0; + + for (i = 0; i < 2; i++) { + tmoveto(0, 0); + tcursor(CURSOR_SAVE); + tclearregion(0, 0, term.col-1, term.row-1); + tswapscreen(); + } +} + +void +tnew(int col, int row) +{ + term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } }; + tresize(col, row); + treset(); +} + +int tisaltscr(void) +{ + return IS_SET(MODE_ALTSCREEN); +} + +void +tswapscreen(void) +{ + Line *tmp = term.line; + + term.line = term.alt; + term.alt = tmp; + term.mode ^= MODE_ALTSCREEN; + tfulldirt(); +} + +void +newterm(const Arg* a) +{ + switch (fork()) { + case -1: + die("fork failed: %s\n", strerror(errno)); + break; + case 0: + chdir(getcwd_by_pid(pid)); + execlp("st", "./st", NULL); + break; + } +} + +static char *getcwd_by_pid(pid_t pid) { + char buf[32]; + snprintf(buf, sizeof buf, "/proc/%d/cwd", pid); + return realpath(buf, NULL); +} + +void +kscrolldown(const Arg* a) +{ + int n = a->i; + + if (n < 0) + n = term.row + n; + + if (n > term.scr) + n = term.scr; + + if (term.scr > 0) { + term.scr -= n; + selscroll(0, -n); + tfulldirt(); + } +} + +void +kscrollup(const Arg* a) +{ + int n = a->i; + + if (n < 0) + n = term.row + n; + + if (term.scr <= HISTSIZE-n) { + term.scr += n; + selscroll(0, n); + tfulldirt(); + } +} + +void +tscrolldown(int orig, int n, int copyhist) +{ + int i; + Line temp; + + LIMIT(n, 0, term.bot-orig+1); + + if (copyhist) { + term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE; + temp = term.hist[term.histi]; + term.hist[term.histi] = term.line[term.bot]; + term.line[term.bot] = temp; + } + + tsetdirt(orig, term.bot-n); + tclearregion(0, term.bot-n+1, term.col-1, term.bot); + + for (i = term.bot; i >= orig+n; i--) { + temp = term.line[i]; + term.line[i] = term.line[i-n]; + term.line[i-n] = temp; + } + + if (term.scr == 0) + selscroll(orig, n); +} + +void +tscrollup(int orig, int n, int copyhist) +{ + int i; + Line temp; + + LIMIT(n, 0, term.bot-orig+1); + + if (copyhist) { + term.histi = (term.histi + 1) % HISTSIZE; + temp = term.hist[term.histi]; + term.hist[term.histi] = term.line[orig]; + term.line[orig] = temp; + } + + if (term.scr > 0 && term.scr < HISTSIZE) + term.scr = MIN(term.scr + n, HISTSIZE-1); + + tclearregion(0, orig, term.col-1, orig+n-1); + tsetdirt(orig+n, term.bot); + + for (i = orig; i <= term.bot-n; i++) { + temp = term.line[i]; + term.line[i] = term.line[i+n]; + term.line[i+n] = temp; + } + + if (term.scr == 0) + selscroll(orig, -n); +} + +void +selscroll(int orig, int n) +{ + if (sel.ob.x == -1) + return; + + if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) { + selclear(); + } else if (BETWEEN(sel.nb.y, orig, term.bot)) { + sel.ob.y += n; + sel.oe.y += n; + if (sel.ob.y < term.top || sel.ob.y > term.bot || + sel.oe.y < term.top || sel.oe.y > term.bot) { + selclear(); + } else { + selnormalize(); + } + } +} + +void +tnewline(int first_col) +{ + int y = term.c.y; + + if (y == term.bot) { + tscrollup(term.top, 1, 1); + } else { + y++; + } + tmoveto(first_col ? 0 : term.c.x, y); +} + +void +csiparse(void) +{ + char *p = csiescseq.buf, *np; + long int v; + + csiescseq.narg = 0; + if (*p == '?') { + csiescseq.priv = 1; + p++; + } + + csiescseq.buf[csiescseq.len] = '\0'; + while (p < csiescseq.buf+csiescseq.len) { + np = NULL; + v = strtol(p, &np, 10); + if (np == p) + v = 0; + if (v == LONG_MAX || v == LONG_MIN) + v = -1; + csiescseq.arg[csiescseq.narg++] = v; + p = np; + if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ) + break; + p++; + } + csiescseq.mode[0] = *p++; + csiescseq.mode[1] = (p < csiescseq.buf+csiescseq.len) ? *p : '\0'; +} + +/* for absolute user moves, when decom is set */ +void +tmoveato(int x, int y) +{ + tmoveto(x, y + ((term.c.state & CURSOR_ORIGIN) ? term.top: 0)); +} + +void +tmoveto(int x, int y) +{ + int miny, maxy; + + if (term.c.state & CURSOR_ORIGIN) { + miny = term.top; + maxy = term.bot; + } else { + miny = 0; + maxy = term.row - 1; + } + term.c.state &= ~CURSOR_WRAPNEXT; + term.c.x = LIMIT(x, 0, term.col-1); + term.c.y = LIMIT(y, miny, maxy); +} + +void +tsetchar(Rune u, Glyph *attr, int x, int y) +{ + static char *vt100_0[62] = { /* 0x41 - 0x7e */ + "↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */ + 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ + 0, 0, 0, 0, 0, 0, 0, 0, /* P - W */ + 0, 0, 0, 0, 0, 0, 0, " ", /* X - _ */ + "◆", "▒", "␉", "␌", "␍", "␊", "°", "±", /* ` - g */ + "␤", "␋", "┘", "┐", "┌", "└", "┼", "⎺", /* h - o */ + "⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */ + "│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */ + }; + + /* + * The table is proudly stolen from rxvt. + */ + if (term.trantbl[term.charset] == CS_GRAPHIC0 && + BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41]) + utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ); + + if (term.line[y][x].mode & ATTR_WIDE) { + if (x+1 < term.col) { + term.line[y][x+1].u = ' '; + term.line[y][x+1].mode &= ~ATTR_WDUMMY; + } + } else if (term.line[y][x].mode & ATTR_WDUMMY) { + term.line[y][x-1].u = ' '; + term.line[y][x-1].mode &= ~ATTR_WIDE; + } + + term.dirty[y] = 1; + term.line[y][x] = *attr; + term.line[y][x].u = u; + + if (isboxdraw(u)) + term.line[y][x].mode |= ATTR_BOXDRAW; +} + +void +tclearregion(int x1, int y1, int x2, int y2) +{ + int x, y, temp; + Glyph *gp; + + if (x1 > x2) + temp = x1, x1 = x2, x2 = temp; + if (y1 > y2) + temp = y1, y1 = y2, y2 = temp; + + LIMIT(x1, 0, term.col-1); + LIMIT(x2, 0, term.col-1); + LIMIT(y1, 0, term.row-1); + LIMIT(y2, 0, term.row-1); + + for (y = y1; y <= y2; y++) { + term.dirty[y] = 1; + for (x = x1; x <= x2; x++) { + gp = &term.line[y][x]; + if (selected(x, y)) + selclear(); + gp->fg = term.c.attr.fg; + gp->bg = term.c.attr.bg; + gp->mode = 0; + gp->u = ' '; + } + } +} + +void +tdeletechar(int n) +{ + int dst, src, size; + Glyph *line; + + LIMIT(n, 0, term.col - term.c.x); + + dst = term.c.x; + src = term.c.x + n; + size = term.col - src; + line = term.line[term.c.y]; + + memmove(&line[dst], &line[src], size * sizeof(Glyph)); + tclearregion(term.col-n, term.c.y, term.col-1, term.c.y); +} + +void +tinsertblank(int n) +{ + int dst, src, size; + Glyph *line; + + LIMIT(n, 0, term.col - term.c.x); + + dst = term.c.x + n; + src = term.c.x; + size = term.col - dst; + line = term.line[term.c.y]; + + memmove(&line[dst], &line[src], size * sizeof(Glyph)); + tclearregion(src, term.c.y, dst - 1, term.c.y); +} + +void +tinsertblankline(int n) +{ + if (BETWEEN(term.c.y, term.top, term.bot)) + tscrolldown(term.c.y, n, 0); +} + +void +tdeleteline(int n) +{ + if (BETWEEN(term.c.y, term.top, term.bot)) + tscrollup(term.c.y, n, 0); +} + +int32_t +tdefcolor(int *attr, int *npar, int l) +{ + int32_t idx = -1; + uint r, g, b; + + switch (attr[*npar + 1]) { + case 2: /* direct color in RGB space */ + if (*npar + 4 >= l) { + fprintf(stderr, + "erresc(38): Incorrect number of parameters (%d)\n", + *npar); + break; + } + r = attr[*npar + 2]; + g = attr[*npar + 3]; + b = attr[*npar + 4]; + *npar += 4; + if (!BETWEEN(r, 0, 255) || !BETWEEN(g, 0, 255) || !BETWEEN(b, 0, 255)) + fprintf(stderr, "erresc: bad rgb color (%u,%u,%u)\n", + r, g, b); + else + idx = TRUECOLOR(r, g, b); + break; + case 5: /* indexed color */ + if (*npar + 2 >= l) { + fprintf(stderr, + "erresc(38): Incorrect number of parameters (%d)\n", + *npar); + break; + } + *npar += 2; + if (!BETWEEN(attr[*npar], 0, 255)) + fprintf(stderr, "erresc: bad fgcolor %d\n", attr[*npar]); + else + idx = attr[*npar]; + break; + case 0: /* implemented defined (only foreground) */ + case 1: /* transparent */ + case 3: /* direct color in CMY space */ + case 4: /* direct color in CMYK space */ + default: + fprintf(stderr, + "erresc(38): gfx attr %d unknown\n", attr[*npar]); + break; + } + + return idx; +} + +void +tsetattr(int *attr, int l) +{ + int i; + int32_t idx; + + for (i = 0; i < l; i++) { + switch (attr[i]) { + case 0: + term.c.attr.mode &= ~( + ATTR_BOLD | + ATTR_FAINT | + ATTR_ITALIC | + ATTR_UNDERLINE | + ATTR_BLINK | + ATTR_REVERSE | + ATTR_INVISIBLE | + ATTR_STRUCK ); + term.c.attr.fg = defaultfg; + term.c.attr.bg = defaultbg; + break; + case 1: + term.c.attr.mode |= ATTR_BOLD; + break; + case 2: + term.c.attr.mode |= ATTR_FAINT; + break; + case 3: + term.c.attr.mode |= ATTR_ITALIC; + break; + case 4: + term.c.attr.mode |= ATTR_UNDERLINE; + break; + case 5: /* slow blink */ + /* FALLTHROUGH */ + case 6: /* rapid blink */ + term.c.attr.mode |= ATTR_BLINK; + break; + case 7: + term.c.attr.mode |= ATTR_REVERSE; + break; + case 8: + term.c.attr.mode |= ATTR_INVISIBLE; + break; + case 9: + term.c.attr.mode |= ATTR_STRUCK; + break; + case 22: + term.c.attr.mode &= ~(ATTR_BOLD | ATTR_FAINT); + break; + case 23: + term.c.attr.mode &= ~ATTR_ITALIC; + break; + case 24: + term.c.attr.mode &= ~ATTR_UNDERLINE; + break; + case 25: + term.c.attr.mode &= ~ATTR_BLINK; + break; + case 27: + term.c.attr.mode &= ~ATTR_REVERSE; + break; + case 28: + term.c.attr.mode &= ~ATTR_INVISIBLE; + break; + case 29: + term.c.attr.mode &= ~ATTR_STRUCK; + break; + case 38: + if ((idx = tdefcolor(attr, &i, l)) >= 0) + term.c.attr.fg = idx; + break; + case 39: + term.c.attr.fg = defaultfg; + break; + case 48: + if ((idx = tdefcolor(attr, &i, l)) >= 0) + term.c.attr.bg = idx; + break; + case 49: + term.c.attr.bg = defaultbg; + break; + default: + if (BETWEEN(attr[i], 30, 37)) { + term.c.attr.fg = attr[i] - 30; + } else if (BETWEEN(attr[i], 40, 47)) { + term.c.attr.bg = attr[i] - 40; + } else if (BETWEEN(attr[i], 90, 97)) { + term.c.attr.fg = attr[i] - 90 + 8; + } else if (BETWEEN(attr[i], 100, 107)) { + term.c.attr.bg = attr[i] - 100 + 8; + } else { + fprintf(stderr, + "erresc(default): gfx attr %d unknown\n", + attr[i]); + csidump(); + } + break; + } + } +} + +void +tsetscroll(int t, int b) +{ + int temp; + + LIMIT(t, 0, term.row-1); + LIMIT(b, 0, term.row-1); + if (t > b) { + temp = t; + t = b; + b = temp; + } + term.top = t; + term.bot = b; +} + +void +tsetmode(int priv, int set, int *args, int narg) +{ + int alt, *lim; + + for (lim = args + narg; args < lim; ++args) { + if (priv) { + switch (*args) { + case 1: /* DECCKM -- Cursor key */ + xsetmode(set, MODE_APPCURSOR); + break; + case 5: /* DECSCNM -- Reverse video */ + xsetmode(set, MODE_REVERSE); + break; + case 6: /* DECOM -- Origin */ + MODBIT(term.c.state, set, CURSOR_ORIGIN); + tmoveato(0, 0); + break; + case 7: /* DECAWM -- Auto wrap */ + MODBIT(term.mode, set, MODE_WRAP); + break; + case 0: /* Error (IGNORED) */ + case 2: /* DECANM -- ANSI/VT52 (IGNORED) */ + case 3: /* DECCOLM -- Column (IGNORED) */ + case 4: /* DECSCLM -- Scroll (IGNORED) */ + case 8: /* DECARM -- Auto repeat (IGNORED) */ + case 18: /* DECPFF -- Printer feed (IGNORED) */ + case 19: /* DECPEX -- Printer extent (IGNORED) */ + case 42: /* DECNRCM -- National characters (IGNORED) */ + case 12: /* att610 -- Start blinking cursor (IGNORED) */ + break; + case 25: /* DECTCEM -- Text Cursor Enable Mode */ + xsetmode(!set, MODE_HIDE); + break; + case 9: /* X10 mouse compatibility mode */ + xsetpointermotion(0); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEX10); + break; + case 1000: /* 1000: report button press */ + xsetpointermotion(0); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEBTN); + break; + case 1002: /* 1002: report motion on button press */ + xsetpointermotion(0); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEMOTION); + break; + case 1003: /* 1003: enable all mouse motions */ + xsetpointermotion(set); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEMANY); + break; + case 1004: /* 1004: send focus events to tty */ + xsetmode(set, MODE_FOCUS); + break; + case 1006: /* 1006: extended reporting mode */ + xsetmode(set, MODE_MOUSESGR); + break; + case 1034: + xsetmode(set, MODE_8BIT); + break; + case 1049: /* swap screen & set/restore cursor as xterm */ + if (!allowaltscreen) + break; + tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); + /* FALLTHROUGH */ + case 47: /* swap screen */ + case 1047: + if (!allowaltscreen) + break; + alt = IS_SET(MODE_ALTSCREEN); + if (alt) { + tclearregion(0, 0, term.col-1, + term.row-1); + } + if (set ^ alt) /* set is always 1 or 0 */ + tswapscreen(); + if (*args != 1049) + break; + /* FALLTHROUGH */ + case 1048: + tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); + break; + case 2004: /* 2004: bracketed paste mode */ + xsetmode(set, MODE_BRCKTPASTE); + break; + /* Not implemented mouse modes. See comments there. */ + case 1001: /* mouse highlight mode; can hang the + terminal by design when implemented. */ + case 1005: /* UTF-8 mouse mode; will confuse + applications not supporting UTF-8 + and luit. */ + case 1015: /* urxvt mangled mouse mode; incompatible + and can be mistaken for other control + codes. */ + break; + default: + fprintf(stderr, + "erresc: unknown private set/reset mode %d\n", + *args); + break; + } + } else { + switch (*args) { + case 0: /* Error (IGNORED) */ + break; + case 2: + xsetmode(set, MODE_KBDLOCK); + break; + case 4: /* IRM -- Insertion-replacement */ + MODBIT(term.mode, set, MODE_INSERT); + break; + case 12: /* SRM -- Send/Receive */ + MODBIT(term.mode, !set, MODE_ECHO); + break; + case 20: /* LNM -- Linefeed/new line */ + MODBIT(term.mode, set, MODE_CRLF); + break; + default: + fprintf(stderr, + "erresc: unknown set/reset mode %d\n", + *args); + break; + } + } + } +} + +void +csihandle(void) +{ + char buf[40]; + int len; + + switch (csiescseq.mode[0]) { + default: + unknown: + fprintf(stderr, "erresc: unknown csi "); + csidump(); + /* die(""); */ + break; + case '@': /* ICH -- Insert blank char */ + DEFAULT(csiescseq.arg[0], 1); + tinsertblank(csiescseq.arg[0]); + break; + case 'A': /* CUU -- Cursor Up */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x, term.c.y-csiescseq.arg[0]); + break; + case 'B': /* CUD -- Cursor Down */ + case 'e': /* VPR --Cursor Down */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x, term.c.y+csiescseq.arg[0]); + break; + case 'i': /* MC -- Media Copy */ + switch (csiescseq.arg[0]) { + case 0: + tdump(); + break; + case 1: + tdumpline(term.c.y); + break; + case 2: + tdumpsel(); + break; + case 4: + term.mode &= ~MODE_PRINT; + break; + case 5: + term.mode |= MODE_PRINT; + break; + } + break; + case 'c': /* DA -- Device Attributes */ + if (csiescseq.arg[0] == 0) + ttywrite(vtiden, strlen(vtiden), 0); + break; + case 'b': /* REP -- if last char is printable print it more times */ + DEFAULT(csiescseq.arg[0], 1); + if (term.lastc) + while (csiescseq.arg[0]-- > 0) + tputc(term.lastc); + break; + case 'C': /* CUF -- Cursor Forward */ + case 'a': /* HPR -- Cursor Forward */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x+csiescseq.arg[0], term.c.y); + break; + case 'D': /* CUB -- Cursor Backward */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(term.c.x-csiescseq.arg[0], term.c.y); + break; + case 'E': /* CNL -- Cursor Down and first col */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(0, term.c.y+csiescseq.arg[0]); + break; + case 'F': /* CPL -- Cursor Up and first col */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(0, term.c.y-csiescseq.arg[0]); + break; + case 'g': /* TBC -- Tabulation clear */ + switch (csiescseq.arg[0]) { + case 0: /* clear current tab stop */ + term.tabs[term.c.x] = 0; + break; + case 3: /* clear all the tabs */ + memset(term.tabs, 0, term.col * sizeof(*term.tabs)); + break; + default: + goto unknown; + } + break; + case 'G': /* CHA -- Move to */ + case '`': /* HPA */ + DEFAULT(csiescseq.arg[0], 1); + tmoveto(csiescseq.arg[0]-1, term.c.y); + break; + case 'H': /* CUP -- Move to */ + case 'f': /* HVP */ + DEFAULT(csiescseq.arg[0], 1); + DEFAULT(csiescseq.arg[1], 1); + tmoveato(csiescseq.arg[1]-1, csiescseq.arg[0]-1); + break; + case 'I': /* CHT -- Cursor Forward Tabulation tab stops */ + DEFAULT(csiescseq.arg[0], 1); + tputtab(csiescseq.arg[0]); + break; + case 'J': /* ED -- Clear screen */ + switch (csiescseq.arg[0]) { + case 0: /* below */ + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); + if (term.c.y < term.row-1) { + tclearregion(0, term.c.y+1, term.col-1, + term.row-1); + } + break; + case 1: /* above */ + if (term.c.y > 1) + tclearregion(0, 0, term.col-1, term.c.y-1); + tclearregion(0, term.c.y, term.c.x, term.c.y); + break; + case 2: /* all */ + tclearregion(0, 0, term.col-1, term.row-1); + break; + default: + goto unknown; + } + break; + case 'K': /* EL -- Clear line */ + switch (csiescseq.arg[0]) { + case 0: /* right */ + tclearregion(term.c.x, term.c.y, term.col-1, + term.c.y); + break; + case 1: /* left */ + tclearregion(0, term.c.y, term.c.x, term.c.y); + break; + case 2: /* all */ + tclearregion(0, term.c.y, term.col-1, term.c.y); + break; + } + break; + case 'S': /* SU -- Scroll line up */ + DEFAULT(csiescseq.arg[0], 1); + tscrollup(term.top, csiescseq.arg[0], 0); + break; + case 'T': /* SD -- Scroll line down */ + DEFAULT(csiescseq.arg[0], 1); + tscrolldown(term.top, csiescseq.arg[0], 0); + break; + case 'L': /* IL -- Insert blank lines */ + DEFAULT(csiescseq.arg[0], 1); + tinsertblankline(csiescseq.arg[0]); + break; + case 'l': /* RM -- Reset Mode */ + tsetmode(csiescseq.priv, 0, csiescseq.arg, csiescseq.narg); + break; + case 'M': /* DL -- Delete lines */ + DEFAULT(csiescseq.arg[0], 1); + tdeleteline(csiescseq.arg[0]); + break; + case 'X': /* ECH -- Erase char */ + DEFAULT(csiescseq.arg[0], 1); + tclearregion(term.c.x, term.c.y, + term.c.x + csiescseq.arg[0] - 1, term.c.y); + break; + case 'P': /* DCH -- Delete char */ + DEFAULT(csiescseq.arg[0], 1); + tdeletechar(csiescseq.arg[0]); + break; + case 'Z': /* CBT -- Cursor Backward Tabulation tab stops */ + DEFAULT(csiescseq.arg[0], 1); + tputtab(-csiescseq.arg[0]); + break; + case 'd': /* VPA -- Move to */ + DEFAULT(csiescseq.arg[0], 1); + tmoveato(term.c.x, csiescseq.arg[0]-1); + break; + case 'h': /* SM -- Set terminal mode */ + tsetmode(csiescseq.priv, 1, csiescseq.arg, csiescseq.narg); + break; + case 'm': /* SGR -- Terminal attribute (color) */ + tsetattr(csiescseq.arg, csiescseq.narg); + break; + case 'n': /* DSR – Device Status Report (cursor position) */ + if (csiescseq.arg[0] == 6) { + len = snprintf(buf, sizeof(buf), "\033[%i;%iR", + term.c.y+1, term.c.x+1); + ttywrite(buf, len, 0); + } + break; + case 'r': /* DECSTBM -- Set Scrolling Region */ + if (csiescseq.priv) { + goto unknown; + } else { + DEFAULT(csiescseq.arg[0], 1); + DEFAULT(csiescseq.arg[1], term.row); + tsetscroll(csiescseq.arg[0]-1, csiescseq.arg[1]-1); + tmoveato(0, 0); + } + break; + case 's': /* DECSC -- Save cursor position (ANSI.SYS) */ + tcursor(CURSOR_SAVE); + break; + case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */ + tcursor(CURSOR_LOAD); + break; + case ' ': + switch (csiescseq.mode[1]) { + case 'q': /* DECSCUSR -- Set Cursor Style */ + if (xsetcursor(csiescseq.arg[0])) + goto unknown; + break; + default: + goto unknown; + } + break; + } +} + +void +csidump(void) +{ + size_t i; + uint c; + + fprintf(stderr, "ESC["); + for (i = 0; i < csiescseq.len; i++) { + c = csiescseq.buf[i] & 0xff; + if (isprint(c)) { + putc(c, stderr); + } else if (c == '\n') { + fprintf(stderr, "(\\n)"); + } else if (c == '\r') { + fprintf(stderr, "(\\r)"); + } else if (c == 0x1b) { + fprintf(stderr, "(\\e)"); + } else { + fprintf(stderr, "(%02x)", c); + } + } + putc('\n', stderr); +} + +void +csireset(void) +{ + memset(&csiescseq, 0, sizeof(csiescseq)); +} + +void +strhandle(void) +{ + char *p = NULL, *dec; + int j, narg, par; + + term.esc &= ~(ESC_STR_END|ESC_STR); + strparse(); + par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0; + + switch (strescseq.type) { + case ']': /* OSC -- Operating System Command */ + switch (par) { + case 0: + if (narg > 1) { + title(); + xseticontitle(strescseq.args[1]); + } + return; + case 1: + if (narg > 1) + xseticontitle(strescseq.args[1]); + return; + case 2: + if (narg > 1) + title(); + return; + case 52: + if (narg > 2 && allowwindowops) { + dec = base64dec(strescseq.args[2]); + if (dec) { + xsetsel(dec); + xclipcopy(); + } else { + fprintf(stderr, "erresc: invalid base64\n"); + } + } + return; + case 4: /* color set */ + if (narg < 3) + break; + p = strescseq.args[2]; + /* FALLTHROUGH */ + case 104: /* color reset, here p = NULL */ + j = (narg > 1) ? atoi(strescseq.args[1]) : -1; + if (xsetcolorname(j, p)) { + if (par == 104 && narg <= 1) + return; /* color reset without parameter */ + fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", + j, p ? p : "(null)"); + } else { + /* + * TODO if defaultbg color is changed, borders + * are dirty + */ + redraw(); + } + return; + } + break; + case 'k': /* old title set compatibility */ + title(); + return; + case 'P': /* DCS -- Device Control String */ + case '_': /* APC -- Application Program Command */ + case '^': /* PM -- Privacy Message */ + return; + } + + fprintf(stderr, "erresc: unknown str "); + strdump(); +} + +void +strparse(void) +{ + int c; + char *p = strescseq.buf; + + strescseq.narg = 0; + strescseq.buf[strescseq.len] = '\0'; + + if (*p == '\0') + return; + + while (strescseq.narg < STR_ARG_SIZ) { + strescseq.args[strescseq.narg++] = p; + while ((c = *p) != ';' && c != '\0') + ++p; + if (c == '\0') + return; + *p++ = '\0'; + } +} + + +void +strdump(void) +{ + size_t i; + uint c; + + fprintf(stderr, "ESC%c", strescseq.type); + for (i = 0; i < strescseq.len; i++) { + c = strescseq.buf[i] & 0xff; + if (c == '\0') { + putc('\n', stderr); + return; + } else if (isprint(c)) { + putc(c, stderr); + } else if (c == '\n') { + fprintf(stderr, "(\\n)"); + } else if (c == '\r') { + fprintf(stderr, "(\\r)"); + } else if (c == 0x1b) { + fprintf(stderr, "(\\e)"); + } else { + fprintf(stderr, "(%02x)", c); + } + } + fprintf(stderr, "ESC\\\n"); +} + +void +strreset(void) +{ + strescseq = (STREscape){ + .buf = xrealloc(strescseq.buf, STR_BUF_SIZ), + .siz = STR_BUF_SIZ, + }; +} + +void +sendbreak(const Arg *arg) +{ + if (tcsendbreak(cmdfd, 0)) + perror("Error sending break"); +} + +void +tprinter(char *s, size_t len) +{ + if (iofd != -1 && xwrite(iofd, s, len) < 0) { + perror("Error writing to output file"); + close(iofd); + iofd = -1; + } +} + +void +toggleprinter(const Arg *arg) +{ + term.mode ^= MODE_PRINT; +} + +void +printscreen(const Arg *arg) +{ + tdump(); +} + +void +printsel(const Arg *arg) +{ + tdumpsel(); +} + +void +tdumpsel(void) +{ + char *ptr; + + if ((ptr = getsel())) { + tprinter(ptr, strlen(ptr)); + free(ptr); + } +} + +void +tdumpline(int n) +{ + char buf[UTF_SIZ]; + Glyph *bp, *end; + + bp = &term.line[n][0]; + end = &bp[MIN(tlinelen(n), term.col) - 1]; + if (bp != end || bp->u != ' ') { + for ( ; bp <= end; ++bp) + tprinter(buf, utf8encode(bp->u, buf)); + } + tprinter("\n", 1); +} + +void +tdump(void) +{ + int i; + + for (i = 0; i < term.row; ++i) + tdumpline(i); +} + +void +tputtab(int n) +{ + uint x = term.c.x; + + if (n > 0) { + while (x < term.col && n--) + for (++x; x < term.col && !term.tabs[x]; ++x) + /* nothing */ ; + } else if (n < 0) { + while (x > 0 && n++) + for (--x; x > 0 && !term.tabs[x]; --x) + /* nothing */ ; + } + term.c.x = LIMIT(x, 0, term.col-1); +} + +void +tdefutf8(char ascii) +{ + if (ascii == 'G') + term.mode |= MODE_UTF8; + else if (ascii == '@') + term.mode &= ~MODE_UTF8; +} + +void +tdeftran(char ascii) +{ + static char cs[] = "0B"; + static int vcs[] = {CS_GRAPHIC0, CS_USA}; + char *p; + + if ((p = strchr(cs, ascii)) == NULL) { + fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii); + } else { + term.trantbl[term.icharset] = vcs[p - cs]; + } +} + +void +tdectest(char c) +{ + int x, y; + + if (c == '8') { /* DEC screen alignment test. */ + for (x = 0; x < term.col; ++x) { + for (y = 0; y < term.row; ++y) + tsetchar('E', &term.c.attr, x, y); + } + } +} + +void +tstrsequence(uchar c) +{ + switch (c) { + case 0x90: /* DCS -- Device Control String */ + c = 'P'; + break; + case 0x9f: /* APC -- Application Program Command */ + c = '_'; + break; + case 0x9e: /* PM -- Privacy Message */ + c = '^'; + break; + case 0x9d: /* OSC -- Operating System Command */ + c = ']'; + break; + } + strreset(); + strescseq.type = c; + term.esc |= ESC_STR; +} + +void +tcontrolcode(uchar ascii) +{ + switch (ascii) { + case '\t': /* HT */ + tputtab(1); + return; + case '\b': /* BS */ + tmoveto(term.c.x-1, term.c.y); + return; + case '\r': /* CR */ + tmoveto(0, term.c.y); + return; + case '\f': /* LF */ + case '\v': /* VT */ + case '\n': /* LF */ + /* go to first col if the mode is set */ + tnewline(IS_SET(MODE_CRLF)); + return; + case '\a': /* BEL */ + if (term.esc & ESC_STR_END) { + /* backwards compatibility to xterm */ + strhandle(); + } else { + xbell(); + } + break; + case '\033': /* ESC */ + csireset(); + term.esc &= ~(ESC_CSI|ESC_ALTCHARSET|ESC_TEST); + term.esc |= ESC_START; + return; + case '\016': /* SO (LS1 -- Locking shift 1) */ + case '\017': /* SI (LS0 -- Locking shift 0) */ + term.charset = 1 - (ascii - '\016'); + return; + case '\032': /* SUB */ + tsetchar('?', &term.c.attr, term.c.x, term.c.y); + /* FALLTHROUGH */ + case '\030': /* CAN */ + csireset(); + break; + case '\005': /* ENQ (IGNORED) */ + case '\000': /* NUL (IGNORED) */ + case '\021': /* XON (IGNORED) */ + case '\023': /* XOFF (IGNORED) */ + case 0177: /* DEL (IGNORED) */ + return; + case 0x80: /* TODO: PAD */ + case 0x81: /* TODO: HOP */ + case 0x82: /* TODO: BPH */ + case 0x83: /* TODO: NBH */ + case 0x84: /* TODO: IND */ + break; + case 0x85: /* NEL -- Next line */ + tnewline(1); /* always go to first col */ + break; + case 0x86: /* TODO: SSA */ + case 0x87: /* TODO: ESA */ + break; + case 0x88: /* HTS -- Horizontal tab stop */ + term.tabs[term.c.x] = 1; + break; + case 0x89: /* TODO: HTJ */ + case 0x8a: /* TODO: VTS */ + case 0x8b: /* TODO: PLD */ + case 0x8c: /* TODO: PLU */ + case 0x8d: /* TODO: RI */ + case 0x8e: /* TODO: SS2 */ + case 0x8f: /* TODO: SS3 */ + case 0x91: /* TODO: PU1 */ + case 0x92: /* TODO: PU2 */ + case 0x93: /* TODO: STS */ + case 0x94: /* TODO: CCH */ + case 0x95: /* TODO: MW */ + case 0x96: /* TODO: SPA */ + case 0x97: /* TODO: EPA */ + case 0x98: /* TODO: SOS */ + case 0x99: /* TODO: SGCI */ + break; + case 0x9a: /* DECID -- Identify Terminal */ + ttywrite(vtiden, strlen(vtiden), 0); + break; + case 0x9b: /* TODO: CSI */ + case 0x9c: /* TODO: ST */ + break; + case 0x90: /* DCS -- Device Control String */ + case 0x9d: /* OSC -- Operating System Command */ + case 0x9e: /* PM -- Privacy Message */ + case 0x9f: /* APC -- Application Program Command */ + tstrsequence(ascii); + return; + } + /* only CAN, SUB, \a and C1 chars interrupt a sequence */ + term.esc &= ~(ESC_STR_END|ESC_STR); +} + +/* + * returns 1 when the sequence is finished and it hasn't to read + * more characters for this sequence, otherwise 0 + */ +int +eschandle(uchar ascii) +{ + switch (ascii) { + case '[': + term.esc |= ESC_CSI; + return 0; + case '#': + term.esc |= ESC_TEST; + return 0; + case '%': + term.esc |= ESC_UTF8; + return 0; + case 'P': /* DCS -- Device Control String */ + case '_': /* APC -- Application Program Command */ + case '^': /* PM -- Privacy Message */ + case ']': /* OSC -- Operating System Command */ + case 'k': /* old title set compatibility */ + tstrsequence(ascii); + return 0; + case 'n': /* LS2 -- Locking shift 2 */ + case 'o': /* LS3 -- Locking shift 3 */ + term.charset = 2 + (ascii - 'n'); + break; + case '(': /* GZD4 -- set primary charset G0 */ + case ')': /* G1D4 -- set secondary charset G1 */ + case '*': /* G2D4 -- set tertiary charset G2 */ + case '+': /* G3D4 -- set quaternary charset G3 */ + term.icharset = ascii - '('; + term.esc |= ESC_ALTCHARSET; + return 0; + case 'D': /* IND -- Linefeed */ + if (term.c.y == term.bot) { + tscrollup(term.top, 1, 1); + } else { + tmoveto(term.c.x, term.c.y+1); + } + break; + case 'E': /* NEL -- Next line */ + tnewline(1); /* always go to first col */ + break; + case 'H': /* HTS -- Horizontal tab stop */ + term.tabs[term.c.x] = 1; + break; + case 'M': /* RI -- Reverse index */ + if (term.c.y == term.top) { + tscrolldown(term.top, 1, 1); + } else { + tmoveto(term.c.x, term.c.y-1); + } + break; + case 'Z': /* DECID -- Identify Terminal */ + ttywrite(vtiden, strlen(vtiden), 0); + break; + case 'c': /* RIS -- Reset to initial state */ + treset(); + resettitle(); + xloadcols(); + break; + case '=': /* DECPAM -- Application keypad */ + xsetmode(1, MODE_APPKEYPAD); + break; + case '>': /* DECPNM -- Normal keypad */ + xsetmode(0, MODE_APPKEYPAD); + break; + case '7': /* DECSC -- Save Cursor */ + tcursor(CURSOR_SAVE); + break; + case '8': /* DECRC -- Restore Cursor */ + tcursor(CURSOR_LOAD); + break; + case '\\': /* ST -- String Terminator */ + if (term.esc & ESC_STR_END) + strhandle(); + break; + default: + fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n", + (uchar) ascii, isprint(ascii)? ascii:'.'); + break; + } + return 1; +} + +void +tputc(Rune u) +{ + char c[UTF_SIZ]; + int control; + int width, len; + Glyph *gp; + + control = ISCONTROL(u); + if (u < 127 || !IS_SET(MODE_UTF8)) { + c[0] = u; + width = len = 1; + } else { + len = utf8encode(u, c); + if (!control && (width = wcwidth(u)) == -1) + width = 1; + } + + if (IS_SET(MODE_PRINT)) + tprinter(c, len); + + /* + * STR sequence must be checked before anything else + * because it uses all following characters until it + * receives a ESC, a SUB, a ST or any other C1 control + * character. + */ + if (term.esc & ESC_STR) { + if (u == '\a' || u == 030 || u == 032 || u == 033 || + ISCONTROLC1(u)) { + term.esc &= ~(ESC_START|ESC_STR); + term.esc |= ESC_STR_END; + goto check_control_code; + } + + if (strescseq.len+len >= strescseq.siz) { + /* + * Here is a bug in terminals. If the user never sends + * some code to stop the str or esc command, then st + * will stop responding. But this is better than + * silently failing with unknown characters. At least + * then users will report back. + * + * In the case users ever get fixed, here is the code: + */ + /* + * term.esc = 0; + * strhandle(); + */ + if (strescseq.siz > (SIZE_MAX - UTF_SIZ) / 2) + return; + strescseq.siz *= 2; + strescseq.buf = xrealloc(strescseq.buf, strescseq.siz); + } + + memmove(&strescseq.buf[strescseq.len], c, len); + strescseq.len += len; + return; + } + +check_control_code: + /* + * Actions of control codes must be performed as soon they arrive + * because they can be embedded inside a control sequence, and + * they must not cause conflicts with sequences. + */ + if (control) { + tcontrolcode(u); + /* + * control codes are not shown ever + */ + if (!term.esc) + term.lastc = 0; + return; + } else if (term.esc & ESC_START) { + if (term.esc & ESC_CSI) { + csiescseq.buf[csiescseq.len++] = u; + if (BETWEEN(u, 0x40, 0x7E) + || csiescseq.len >= \ + sizeof(csiescseq.buf)-1) { + term.esc = 0; + csiparse(); + csihandle(); + } + return; + } else if (term.esc & ESC_UTF8) { + tdefutf8(u); + } else if (term.esc & ESC_ALTCHARSET) { + tdeftran(u); + } else if (term.esc & ESC_TEST) { + tdectest(u); + } else { + if (!eschandle(u)) + return; + /* sequence already finished */ + } + term.esc = 0; + /* + * All characters which form part of a sequence are not + * printed + */ + return; + } + if (selected(term.c.x, term.c.y)) + selclear(); + + gp = &term.line[term.c.y][term.c.x]; + if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) { + gp->mode |= ATTR_WRAP; + tnewline(1); + gp = &term.line[term.c.y][term.c.x]; + } + + if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) + memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph)); + + if (term.c.x+width > term.col) { + tnewline(1); + gp = &term.line[term.c.y][term.c.x]; + } + + tsetchar(u, &term.c.attr, term.c.x, term.c.y); + term.lastc = u; + + if (width == 2) { + gp->mode |= ATTR_WIDE; + if (term.c.x+1 < term.col) { + gp[1].u = '\0'; + gp[1].mode = ATTR_WDUMMY; + } + } + if (term.c.x+width < term.col) { + tmoveto(term.c.x+width, term.c.y); + } else { + term.c.state |= CURSOR_WRAPNEXT; + } +} + +int +twrite(const char *buf, int buflen, int show_ctrl) +{ + int charsize; + Rune u; + int n; + + for (n = 0; n < buflen; n += charsize) { + if (IS_SET(MODE_UTF8)) { + /* process a complete utf8 char */ + charsize = utf8decode(buf + n, &u, buflen - n); + if (charsize == 0) + break; + } else { + u = buf[n] & 0xFF; + charsize = 1; + } + if (show_ctrl && ISCONTROL(u)) { + if (u & 0x80) { + u &= 0x7f; + tputc('^'); + tputc('['); + } else if (u != '\n' && u != '\r' && u != '\t') { + u ^= 0x40; + tputc('^'); + } + } + tputc(u); + } + return n; +} + +void +tresize(int col, int row) +{ + int i, j; + int minrow = MIN(row, term.row); + int mincol = MIN(col, term.col); + int *bp; + TCursor c; + + if ( row < term.row || col < term.col ) + toggle_winmode(trt_kbdselect(XK_Escape, NULL, 0)); + + if (col < 1 || row < 1) { + fprintf(stderr, + "tresize: error resizing to %dx%d\n", col, row); + return; + } + + /* + * slide screen to keep cursor where we expect it - + * tscrollup would work here, but we can optimize to + * memmove because we're freeing the earlier lines + */ + for (i = 0; i <= term.c.y - row; i++) { + free(term.line[i]); + free(term.alt[i]); + } + /* ensure that both src and dst are not NULL */ + if (i > 0) { + memmove(term.line, term.line + i, row * sizeof(Line)); + memmove(term.alt, term.alt + i, row * sizeof(Line)); + } + for (i += row; i < term.row; i++) { + free(term.line[i]); + free(term.alt[i]); + } + + /* resize to new height */ + term.line = xrealloc(term.line, row * sizeof(Line)); + term.alt = xrealloc(term.alt, row * sizeof(Line)); + term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); + term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); + + for (i = 0; i < HISTSIZE; i++) { + term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); + for (j = mincol; j < col; j++) { + term.hist[i][j] = term.c.attr; + term.hist[i][j].u = ' '; + } + } + + /* resize each row to new width, zero-pad if needed */ + for (i = 0; i < minrow; i++) { + term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); + term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph)); + } + + /* allocate any new rows */ + for (/* i = minrow */; i < row; i++) { + term.line[i] = xmalloc(col * sizeof(Glyph)); + term.alt[i] = xmalloc(col * sizeof(Glyph)); + } + if (col > term.col) { + bp = term.tabs + term.col; + + memset(bp, 0, sizeof(*term.tabs) * (col - term.col)); + while (--bp > term.tabs && !*bp) + /* nothing */ ; + for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces) + *bp = 1; + } + /* update terminal size */ + term.col = col; + term.row = row; + /* reset scrolling region */ + tsetscroll(0, row-1); + /* make use of the LIMIT in tmoveto */ + tmoveto(term.c.x, term.c.y); + /* Clearing both screens (it makes dirty all lines) */ + c = term.c; + for (i = 0; i < 2; i++) { + if (mincol < col && 0 < minrow) { + tclearregion(mincol, 0, col - 1, minrow - 1); + } + if (0 < col && minrow < row) { + tclearregion(0, minrow, col - 1, row - 1); + } + tswapscreen(); + tcursor(CURSOR_LOAD); + } + term.c = c; +} + +void +resettitle(void) +{ + title(); +} + +void +drawregion(int x1, int y1, int x2, int y2) +{ + int y; + + for (y = y1; y < y2; y++) { + if (!term.dirty[y]) + continue; + + term.dirty[y] = 0; + xdrawline(TLINE(y), x1, y, x2); + } +} + +void +draw(void) +{ + int cx = term.c.x, ocx = term.ocx, ocy = term.ocy; + + if (!xstartdraw()) + return; + + /* adjust cursor position */ + LIMIT(term.ocx, 0, term.col-1); + LIMIT(term.ocy, 0, term.row-1); + if (term.line[term.ocy][term.ocx].mode & ATTR_WDUMMY) + term.ocx--; + if (term.line[term.c.y][cx].mode & ATTR_WDUMMY) + cx--; + + drawregion(0, 0, term.col, term.row); + if (term.scr == 0) + xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], + term.ocx, term.ocy, term.line[term.ocy][term.ocx], + term.line[term.ocy], term.col); + term.ocx = cx; + term.ocy = term.c.y; + xfinishdraw(); + if (ocx != term.ocx || ocy != term.ocy) + xximspot(term.ocx, term.ocy); +} + +void +redraw(void) +{ + tfulldirt(); + draw(); +} + +void set_notifmode(int type, KeySym ksym) { + static char *lib[] = { " MOVE ", " SEL "}; + static Glyph *g, *deb, *fin; + static int col, bot; + + if ( ksym == -1 ) { + free(g); + col = term.col, bot = term.bot; + g = xmalloc(col * sizeof(Glyph)); + memcpy(g, term.line[bot], col * sizeof(Glyph)); + + } + else if ( ksym == -2 ) + memcpy(term.line[bot], g, col * sizeof(Glyph)); + + if ( type < 2 ) { + char *z = lib[type]; + for (deb = &term.line[bot][col - 6], fin = &term.line[bot][col]; deb < fin; z++, deb++) + deb->mode = ATTR_REVERSE, + deb->u = *z, + deb->fg = defaultfg, deb->bg = defaultbg; + } + else if ( type < 5 ) + memcpy(term.line[bot], g, col * sizeof(Glyph)); + else { + for (deb = &term.line[bot][0], fin = &term.line[bot][col]; deb < fin; deb++) + deb->mode = ATTR_REVERSE, + deb->u = ' ', + deb->fg = defaultfg, deb->bg = defaultbg; + term.line[bot][0].u = ksym; + } + + term.dirty[bot] = 1; + drawregion(0, bot, col, bot + 1); +} + +void select_or_drawcursor(int selectsearch_mode, int type) { + int done = 0; + + if ( selectsearch_mode & 1 ) { + selextend(term.c.x, term.c.y, type, done); + xsetsel(getsel()); + } + else + xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x], + term.ocx, term.ocy, term.line[term.ocy][term.ocx], + term.line[term.ocy], term.col); +} + +void search(int selectsearch_mode, Rune *target, int ptarget, int incr, int type, TCursor *cu) { + Rune *r; + int i, bound = (term.col * cu->y + cu->x) * (incr > 0) + incr; + + for (i = term.col * term.c.y + term.c.x + incr; i != bound; i += incr) { + for (r = target; r - target < ptarget; r++) { + if ( *r == term.line[(i + r - target) / term.col][(i + r - target) % term.col].u ) { + if ( r - target == ptarget - 1 ) break; + } else { + r = NULL; + break; + } + } + if ( r != NULL ) break; + } + + if ( i != bound ) { + term.c.y = i / term.col, term.c.x = i % term.col; + select_or_drawcursor(selectsearch_mode, type); + } +} + +int trt_kbdselect(KeySym ksym, char *buf, int len) { + static TCursor cu; + static Rune target[64]; + static int type = 1, ptarget, in_use; + static int sens, quant; + static char selectsearch_mode; + int i, bound, *xy; + + + if ( selectsearch_mode & 2 ) { + if ( ksym == XK_Return ) { + selectsearch_mode ^= 2; + set_notifmode(selectsearch_mode, -2); + if ( ksym == XK_Escape ) ptarget = 0; + return 0; + } + else if ( ksym == XK_BackSpace ) { + if ( !ptarget ) return 0; + term.line[term.bot][ptarget--].u = ' '; + } + else if ( len < 1 ) { + return 0; + } + else if ( ptarget == term.col || ksym == XK_Escape ) { + return 0; + } + else { + utf8decode(buf, &target[ptarget++], len); + term.line[term.bot][ptarget].u = target[ptarget - 1]; + } + + if ( ksym != XK_BackSpace ) + search(selectsearch_mode, &target[0], ptarget, sens, type, &cu); + + term.dirty[term.bot] = 1; + drawregion(0, term.bot, term.col, term.bot + 1); + return 0; + } + + switch ( ksym ) { + case -1 : + in_use = 1; + cu.x = term.c.x, cu.y = term.c.y; + set_notifmode(0, ksym); + return MODE_KBDSELECT; + case XK_v : + if ( selectsearch_mode & 1 ) + selclear(); + else + selstart(term.c.x, term.c.y, 0); + set_notifmode(selectsearch_mode ^= 1, ksym); + break; + case XK_t : + selextend(term.c.x, term.c.y, type ^= 3, i = 0); /* 2 fois */ + selextend(term.c.x, term.c.y, type, i = 0); + break; + case XK_slash : + case XK_KP_Divide : + case XK_question : + ksym &= XK_question; /* Divide to slash */ + sens = (ksym == XK_slash) ? -1 : 1; + ptarget = 0; + set_notifmode(15, ksym); + selectsearch_mode ^= 2; + break; + case XK_Escape : + if ( !in_use ) break; + selclear(); + case XK_Return : + set_notifmode(4, ksym); + term.c.x = cu.x, term.c.y = cu.y; + select_or_drawcursor(selectsearch_mode = 0, type); + in_use = quant = 0; + return MODE_KBDSELECT; + case XK_n : + case XK_N : + if ( ptarget ) + search(selectsearch_mode, &target[0], ptarget, (ksym == XK_n) ? -1 : 1, type, &cu); + break; + case XK_BackSpace : + term.c.x = 0; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_dollar : + term.c.x = term.col - 1; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_g : + term.c.x = 0, term.c.y = 0; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_f : + term.c.x = cu.x, term.c.y = cu.y; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_Page_Up : + case XK_Page_Down : + term.c.y = (ksym == XK_Prior ) ? 0 : cu.y; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_exclam : + term.c.x = term.col >> 1; + select_or_drawcursor(selectsearch_mode, type); + break; + case XK_asterisk : + case XK_KP_Multiply : + term.c.x = term.col >> 1; + case XK_underscore : + term.c.y = cu.y >> 1; + select_or_drawcursor(selectsearch_mode, type); + break; + default : + if ( ksym >= XK_0 && ksym <= XK_9 ) { /* 0-9 keyboard */ + quant = (quant * 10) + (ksym ^ XK_0); + return 0; + } + else if ( ksym >= XK_KP_0 && ksym <= XK_KP_9 ) { /* 0-9 numpad */ + quant = (quant * 10) + (ksym ^ XK_KP_0); + return 0; + } + else if ( ksym == XK_k || ksym == XK_h ) + i = ksym & 1; + else if ( ksym == XK_l || ksym == XK_j ) + i = ((ksym & 6) | 4) >> 1; + else if ( (XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3 ) + break; + + xy = (i & 1) ? &term.c.y : &term.c.x; + sens = (i & 2) ? 1 : -1; + bound = (i >> 1 ^ 1) ? 0 : (i ^ 3) ? term.col - 1 : term.bot; + + if ( quant == 0 ) + quant++; + + if ( *xy == bound && ((sens < 0 && bound == 0) || (sens > 0 && bound > 0)) ) + break; + + *xy += quant * sens; + if ( *xy < 0 || ( bound > 0 && *xy > bound) ) + *xy = bound; + + select_or_drawcursor(selectsearch_mode, type); + } + quant = 0; + return 0; +} + +void +tsetcolor( int row, int start, int end, uint32_t fg, uint32_t bg ) +{ + int i = start; + for( ; i < end; ++i ) + { + term.line[row][i].fg = fg; + term.line[row][i].bg = bg; + } +} + +char * +findlastany(char *str, const char** find, size_t len) +{ + char* found = NULL; + int i = 0; + for(found = str + strlen(str) - 1; found >= str; --found) { + for(i = 0; i < len; i++) { + if(strncmp(found, find[i], strlen(find[i])) == 0) { + return found; + } + } + } + + return NULL; +} + +/* +** Select and copy the previous url on screen (do nothing if there's no url). +** +** FIXME: doesn't handle urls that span multiple lines; will need to add support +** for multiline "getsel()" first +*/ +void +copyurl(const Arg *arg) { + /* () and [] can appear in urls, but excluding them here will reduce false + * positives when figuring out where a given url ends. + */ + static char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-._~:/?#@!$&'*+,;=%"; + + static const char* URLSTRINGS[] = {"http://", "https://"}; + + /* remove highlighting from previous selection if any */ + if(sel.ob.x >= 0 && sel.oe.x >= 0) + tsetcolor(sel.nb.y, sel.ob.x, sel.oe.x + 1, defaultfg, defaultbg); + + int i = 0, + row = 0, /* row of current URL */ + col = 0, /* column of current URL start */ + startrow = 0, /* row of last occurrence */ + colend = 0, /* column of last occurrence */ + passes = 0; /* how many rows have been scanned */ + + char *linestr = calloc(sizeof(char), term.col+1); /* assume ascii */ + char *c = NULL, + *match = NULL; + + row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot; + LIMIT(row, term.top, term.bot); + startrow = row; + + colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col; + LIMIT(colend, 0, term.col); + + /* + ** Scan from (term.bot,term.col) to (0,0) and find + ** next occurrance of a URL + */ + while(passes !=term.bot + 2) { + /* Read in each column of every row until + ** we hit previous occurrence of URL + */ + for (col = 0, i = 0; col < colend; ++col,++i) { + /* assume ascii */ + if (term.line[row][col].u > 127) + continue; + linestr[i] = term.line[row][col].u; + } + linestr[term.col] = '\0'; + + if ((match = findlastany(linestr, URLSTRINGS, + sizeof(URLSTRINGS)/sizeof(URLSTRINGS[0])))) + break; + + if (--row < term.top) + row = term.bot; + + colend = term.col; + passes++; + }; + + if (match) { + /* must happen before trim */ + selclear(); + sel.ob.x = strlen(linestr) - strlen(match); + + /* trim the rest of the line from the url match */ + for (c = match; *c != '\0'; ++c) + if (!strchr(URLCHARS, *c)) { + *c = '\0'; + break; + } + + /* highlight selection by inverting terminal colors */ + tsetcolor(row, sel.ob.x, sel.ob.x + strlen( match ),9, defaultbg); + + /* select and copy */ + sel.mode = 1; + sel.type = SEL_REGULAR; + sel.oe.x = sel.ob.x + strlen(match)-1; + sel.ob.y = sel.oe.y = row; + selnormalize(); + tsetdirt(sel.nb.y, sel.ne.y); + xsetsel(getsel()); + xclipcopy(); + } + + free(linestr); +} diff --git a/st.c.rej b/st.c.rej new file mode 100644 index 0000000..06acd9b --- /dev/null +++ b/st.c.rej @@ -0,0 +1,14 @@ +--- st.c ++++ st.c +@@ -2604,9 +2534,8 @@ draw(void) + cx--; + + drawregion(0, 0, term.col, term.row); +- if (term.scr == 0) +- xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], +- term.ocx, term.ocy, term.line[term.ocy][term.ocx]); ++ xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], ++ term.ocx, term.ocy, term.line[term.ocy][term.ocx]); + term.ocx = cx; + term.ocy = term.c.y; + xfinishdraw(); diff --git a/st.h b/st.h index bb063a9..68d7da9 100644 --- a/st.h +++ b/st.h @@ -84,8 +84,6 @@ void redraw(void); void tfulldirt(void); void draw(void); void newterm(const Arg *); -void kscrolldown(const Arg *); -void kscrollup(const Arg *); void opencopied(const Arg *); void printscreen(const Arg *); void printsel(const Arg *); @@ -102,6 +100,7 @@ int ttynew(char *, char *, char *, char **); size_t ttyread(void); void ttyresize(int, int); void ttywrite(const char *, size_t, int); + void resettitle(void); void selclear(void); diff --git a/st.h.orig b/st.h.orig new file mode 100644 index 0000000..aa50de1 --- /dev/null +++ b/st.h.orig @@ -0,0 +1,134 @@ +/* See LICENSE for license details. */ +#include +#include + +/* macros */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) < (b) ? (b) : (a)) +#define LEN(a) (sizeof(a) / sizeof(a)[0]) +#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) +#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) +#define DEFAULT(a, b) (a) = (a) ? (a) : (b) +#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) +#define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) != ((b).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) || \ + (a).fg != (b).fg || \ + (a).bg != (b).bg) +#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ + (t1.tv_nsec-t2.tv_nsec)/1E6) +#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) + +#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) +#define IS_TRUECOL(x) (1 << 24 & (x)) + +enum glyph_attribute { + ATTR_NULL = 0, + ATTR_BOLD = 1 << 0, + ATTR_FAINT = 1 << 1, + ATTR_ITALIC = 1 << 2, + ATTR_UNDERLINE = 1 << 3, + ATTR_BLINK = 1 << 4, + ATTR_REVERSE = 1 << 5, + ATTR_INVISIBLE = 1 << 6, + ATTR_STRUCK = 1 << 7, + ATTR_WRAP = 1 << 8, + ATTR_WIDE = 1 << 9, + ATTR_WDUMMY = 1 << 10, + ATTR_BOXDRAW = 1 << 11, + ATTR_LIGA = 1 << 12, + ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, +}; + +enum selection_mode { + SEL_IDLE = 0, + SEL_EMPTY = 1, + SEL_READY = 2 +}; + +enum selection_type { + SEL_REGULAR = 1, + SEL_RECTANGULAR = 2 +}; + +enum selection_snap { + SNAP_WORD = 1, + SNAP_LINE = 2 +}; + +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned short ushort; + +typedef uint_least32_t Rune; + +#define Glyph Glyph_ +typedef struct { + Rune u; /* character code */ + ushort mode; /* attribute flags */ + uint32_t fg; /* foreground */ + uint32_t bg; /* background */ +} Glyph; + +typedef Glyph *Line; + +typedef union { + int i; + uint ui; + float f; + const void *v; + const char *s; +} Arg; + +void die(const char *, ...); +void redraw(void); +void tfulldirt(void); +void draw(void); +void newterm(const Arg *); +void kscrolldown(const Arg *); +void kscrollup(const Arg *); +void opencopied(const Arg *); +void printscreen(const Arg *); +void printsel(const Arg *); +void sendbreak(const Arg *); +void toggleprinter(const Arg *); +void copyurl(const Arg *); + +int tattrset(int); +void tnew(int, int); +void tresize(int, int); +void tsetdirtattr(int); +void ttyhangup(void); +int ttynew(char *, char *, char *, char **); +size_t ttyread(void); +void ttyresize(int, int); +void ttywrite(const char *, size_t, int); +void resettitle(void); + +void selclear(void); +void selinit(void); +void selstart(int, int, int); +void selextend(int, int, int, int); +int selected(int, int); +char *getsel(void); + +size_t utf8encode(Rune, char *); + +void *xmalloc(size_t); +void *xrealloc(void *, size_t); +char *xstrdup(char *); +int trt_kbdselect(KeySym, char *, int); + +/* config.h globals */ +extern char *utmp; +extern char *scroll; +extern char *stty_args; +extern char *vtiden; +extern wchar_t *worddelimiters; +extern int allowaltscreen; +extern int allowwindowops; +extern char *termname; +extern unsigned int tabspaces; +extern unsigned int defaultfg; +extern unsigned int defaultbg; +extern const int boxdraw, boxdraw_bold, boxdraw_braille; +extern float alpha, alphaUnfocused; diff --git a/st.h.orig.orig b/st.h.orig.orig new file mode 100644 index 0000000..bb063a9 --- /dev/null +++ b/st.h.orig.orig @@ -0,0 +1,142 @@ +/* See LICENSE for license details. */ +#include +#include + +/* macros */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) < (b) ? (b) : (a)) +#define LEN(a) (sizeof(a) / sizeof(a)[0]) +#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) +#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) +#define DEFAULT(a, b) (a) = (a) ? (a) : (b) +#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) +#define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) != ((b).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) || \ + (a).fg != (b).fg || \ + (a).bg != (b).bg) +#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ + (t1.tv_nsec-t2.tv_nsec)/1E6) +#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) + +#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) +#define IS_TRUECOL(x) (1 << 24 & (x)) + +enum glyph_attribute { + ATTR_NULL = 0, + ATTR_BOLD = 1 << 0, + ATTR_FAINT = 1 << 1, + ATTR_ITALIC = 1 << 2, + ATTR_UNDERLINE = 1 << 3, + ATTR_BLINK = 1 << 4, + ATTR_REVERSE = 1 << 5, + ATTR_INVISIBLE = 1 << 6, + ATTR_STRUCK = 1 << 7, + ATTR_WRAP = 1 << 8, + ATTR_WIDE = 1 << 9, + ATTR_WDUMMY = 1 << 10, + ATTR_BOXDRAW = 1 << 11, + ATTR_LIGA = 1 << 12, + ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, +}; + +enum selection_mode { + SEL_IDLE = 0, + SEL_EMPTY = 1, + SEL_READY = 2 +}; + +enum selection_type { + SEL_REGULAR = 1, + SEL_RECTANGULAR = 2 +}; + +enum selection_snap { + SNAP_WORD = 1, + SNAP_LINE = 2 +}; + +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned short ushort; + +typedef uint_least32_t Rune; + +#define Glyph Glyph_ +typedef struct { + Rune u; /* character code */ + ushort mode; /* attribute flags */ + uint32_t fg; /* foreground */ + uint32_t bg; /* background */ +} Glyph; + +typedef Glyph *Line; + +typedef union { + int i; + uint ui; + float f; + const void *v; + const char *s; +} Arg; + +void die(const char *, ...); +void redraw(void); +void tfulldirt(void); +void draw(void); +void newterm(const Arg *); +void kscrolldown(const Arg *); +void kscrollup(const Arg *); +void opencopied(const Arg *); +void printscreen(const Arg *); +void printsel(const Arg *); +void sendbreak(const Arg *); +void toggleprinter(const Arg *); +void copyurl(const Arg *); + +int tattrset(int); +void tnew(int, int); +void tresize(int, int); +void tsetdirtattr(int); +void ttyhangup(void); +int ttynew(char *, char *, char *, char **); +size_t ttyread(void); +void ttyresize(int, int); +void ttywrite(const char *, size_t, int); +void resettitle(void); + +void selclear(void); +void selinit(void); +void selstart(int, int, int); +void selextend(int, int, int, int); +int selected(int, int); +char *getsel(void); + +size_t utf8encode(Rune, char *); + +void *xmalloc(size_t); +void *xrealloc(void *, size_t); +char *xstrdup(char *); +int trt_kbdselect(KeySym, char *, int); + +int isboxdraw(Rune); +ushort boxdrawindex(const Glyph *); +#ifdef XFT_VERSION +/* only exposed to x.c, otherwise we'll need Xft.h for the types */ +void boxdraw_xinit(Display *, Colormap, XftDraw *, Visual *); +void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpec *, int); +#endif + +/* config.h globals */ +extern char *utmp; +extern char *scroll; +extern char *stty_args; +extern char *vtiden; +extern wchar_t *worddelimiters; +extern int allowaltscreen; +extern int allowwindowops; +extern char *termname; +extern unsigned int tabspaces; +extern unsigned int defaultfg; +extern unsigned int defaultbg; +extern const int boxdraw, boxdraw_bold, boxdraw_braille; +extern float alpha, alphaUnfocused; diff --git a/st.h.orig.rej b/st.h.orig.rej new file mode 100644 index 0000000..aacc53f --- /dev/null +++ b/st.h.orig.rej @@ -0,0 +1,16 @@ +--- st.h.orig ++++ st.h.orig +@@ -33,7 +33,6 @@ enum glyph_attribute { + ATTR_WRAP = 1 << 8, + ATTR_WIDE = 1 << 9, + ATTR_WDUMMY = 1 << 10, +- ATTR_BOXDRAW = 1 << 11, + ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, + }; + +@@ -124,5 +115,4 @@ extern char *termname; + extern unsigned int tabspaces; + extern unsigned int defaultfg; + extern unsigned int defaultbg; +-extern const int boxdraw, boxdraw_bold, boxdraw_braille; + extern char *iso14755_cmd; diff --git a/st.h.rej b/st.h.rej new file mode 100644 index 0000000..10c6483 --- /dev/null +++ b/st.h.rej @@ -0,0 +1,11 @@ +--- st.h ++++ st.h +@@ -81,8 +81,6 @@ typedef union { + void die(const char *, ...); + void redraw(void); + void draw(void); +-void kscrolldown(const Arg *); +-void kscrollup(const Arg *); + void iso14755(const Arg *); + void printscreen(const Arg *); + void printsel(const Arg *); diff --git a/st.h.rej.orig b/st.h.rej.orig new file mode 100644 index 0000000..10c6483 --- /dev/null +++ b/st.h.rej.orig @@ -0,0 +1,11 @@ +--- st.h ++++ st.h +@@ -81,8 +81,6 @@ typedef union { + void die(const char *, ...); + void redraw(void); + void draw(void); +-void kscrolldown(const Arg *); +-void kscrollup(const Arg *); + void iso14755(const Arg *); + void printscreen(const Arg *); + void printsel(const Arg *); diff --git a/st.h.rej.rej b/st.h.rej.rej new file mode 100644 index 0000000..22e0ded --- /dev/null +++ b/st.h.rej.rej @@ -0,0 +1,19 @@ +--- st.h.rej ++++ st.h.rej +@@ -1,11 +1,7 @@ + --- st.h + +++ st.h +-@@ -81,6 +81,8 @@ void die(const char *, ...); +- void redraw(void); +- void draw(void); +- +-+void kscrolldown(const Arg *); +-+void kscrollup(const Arg *); +- void printscreen(const Arg *); +- void printsel(const Arg *); +- void sendbreak(const Arg *); ++@@ -131,3 +140,4 @@ extern char *termname; ++ extern unsigned int tabspaces; ++ extern unsigned int defaultfg; ++ extern unsigned int defaultbg; +++extern const int boxdraw, boxdraw_bold, boxdraw_braille; diff --git a/st.o b/st.o index be29a17aa9c555cb84dda21f925019914701e9bd..91aa8436c3e4e88f5a915fe55c3d7f66364e9a16 100644 GIT binary patch literal 78136 zcmeFae|%KcwKu%y%miW*A%*}kpqcPPF(O8YkXS4;NstJr5Mo73Z)P$HBqorA3=n>l z3_sdpV|$52f>b4_ZGm!IdW*`m+}nUYmMXm$0TnH`PJmjj*n2?{69w~p*WPPSc8*MM z-}m{vpU?Zpb98df`R=vXUVH7e*Zy(VIW$e3d5`6A2z@xj%cA#AqeAQ(+lzW6>=7yA zIw6LOlqo`VTOxF{pAZ{g6QbpJZqZU$IX}0cazXBQgh*%-an%taO7dNzWdvwTQ^f^G zPfv*up<+vjR3SzsbT~`jwuC3_1djlC1U&dP`u8;ntGd!5N}_nXXz>Ft6^`m1;OWir z%+3_<*;6iO)W?JFxt?vrGaSLWREX+G+qSJDNwg4uH)Jfm?5N*~vOV%TqyAo8f7;VC z^vcR#@4Vs^EuVhV+WA?)x$}}!?E1{<*!8K?+J)+F6vET(z_0Umfph3+JNQQ|5nk&M zFY5Hp+dbVx=N961(NDY>aSq<~={NJiuVCkum9Om}89GNgS~@IG-aq&Bv~}L>>CSYC zH>V_t3um38^bv)XT`yBFz zERl8UR!?`nC0=akCuE*AU-rm6gTaULRY6Ce%<=Ag2X!QQBhI0_euBK8f-m830>2Zq z|Bmyg&Oy5fJB(|R1@&q@Vq)G8(qCF3HnfQ8{8Ccwd*FELt*u45jF+3ReeR-;Ri@(net9q@e_49>k2*L^+ld=eq%;T9P&OVL|({{ zb1KW<4*4m+2e#J)IcgyLHk{WTS(8p>!hXY4ce3Mhl)oPNoRHx|l&j^tvhugm28mCB z@Z_OS6$eE8M3yV;6^=x-W80OL2c#{jc0rrO=O2qW#GQ&xv=nqWTHLF?y~)v$`G!B< z(d-F{mi(mrogwX*>Ho(I2t@OuvYbh77n1OV`g^D8im1B|GVk`Y*NfMb;%<6K1wIwe>Fajfm3$dkz)PRfTeT__Xwmg)r-pfb=#5!fpD*0)?Mw|+0Fj!BJ@c7;itmX?r`=c8S$dtm#F*% z`Ks>fLinrSNgE@7_(en9&JiMnJ|i}g4|F?m{n4spnT=&#BZO!^HA!@5R{Hi0gI+s@ z$YK7{7vj1V`n~W)|840*kRMLIWjM}HJ3ZYAs2};qFB+!q?1bE(qHS&fHo+;vpIRc^ z1-@Uv|G1r=aHr)74-%=jqVJa+><8Z>230?f_N41MVo+jWz`^u}!`84TEyu0vQI~_D zFBOBUe}L<4mZ;x;bWOVNXeb@@-QE-aF82|4vxxUB7ni3^grClO?aQ9F4Dei-AW9B^ z#v-eQ9PG@>n2(s&XMNltCqG!4P^M@uiIYsq>cu^ug@5$+$ z1V0HKmpUEQp>B*ZT+g4Po~O_cSVz(p+^8>nVEwfhdrI8M6YbY*C(}RaDVd7C=fqFj zQ6c=W*A)t{uMBjpNp>`6!Vfz>o;DHcOC&!Z5OK|3@Pb`PTWf}{HlXY&D2vJK8y}a|moAMt9&jxBYu3MdP4L=;kA2qHQ;QGqS ze~sFw)&tpMdq3z-+NNl69QK5*S3P0sw5lyZb|5x3z>b2?SuMV! zp0NLQs*j`Eg0C(6wFnFN4BtT!wnQk!e~M_VmaoANjX)dvEoY1GW27eV9I#grDD757|_-6Qs zmWqq3k2xCy`^Z;JOvIoubE-?W60!mcDw_&Xwg{7sOnGb4n#m7}_Bqj$wx{0^Zk-@LRrmdDESh`22Bt*4x> z=)B=-<(&b|-;(Df($~e4Z?&pF1pkpJm*f$UC*!iS{;|({O3b;*)yjC|?~vmlXs)dM zm#96Gzq<%uN&E&wx4-Qt?%0lYrZy!zzq0Zb*{+u`H}v=P?EM7iQ{YjEzt}cJ(mfeJn_q(my~=`_pM~VK1;T<)V_^)A-ak}K<5ep1`jFm^bd;AzY05TL z9f*#wFJ#&Kr4E#w9t;1k{bGE>M zH-3g|^8F_)Pj@`zI)F2Lqx7L9{~F7y=D4s`-=o1?Yq;l$?L^a9*0}x4Ws@?-V15D{ z$jHHX1-s0sfqmml?ca&{tYCjkcGrP?v1I@A|B(J4|3ms)NY{2i1qhG5r@W--f~7s4DaG6it#ZP?c8vYypEn&l?M%x$N(+ruWJKjTZ=hVD%Nvr&;}(qx8j@uzuWrUnyo=AwYkYk zJ?FvtbOYp;zUURv(uuXLub)@8cPIKit#yBnv2h#Lts_te@++qA_$kt~O>}0cvByp8 zWUQZ+Pg1({!7pZnME!xwJtgN+A1V*|S~;(rxBL}ym~#mDoMNh1#5pLd1LHb;%5@>) zgZW$yWKsOpcuZ}jc%koMJkHo5!WnyLYzd{fhpV~x8Q74rfAY~7>u8<~d!u}M?Fj4+ zA9SMoNx@7{IDmCn{&AXjI;+>n@ssD-7?0h2AI*>Pvj+7bp72+)99k>9fw6|hRyTON zQ8r;ATx+@eb7wbV<|HZ++^xUFPKjEn(h zL;Lu4;|Ki;=+}2#gqNbdmb{AJVG#}ljdFF!#JhaReCPkc+?YK z@o%2+(qDVR%MN^naI#>>7p@X4)t+2>Phv{Yd1Ad`Coee*-B|N#w-5d z1$*wq8j|K<+Rn+IJNi?<>fM9LhrN_yE_@EQtJ+1`_O)n#eGi>f-wN4N;9C<=Pg>LI zv<&ov-F@ontbSeDJjO}2hoNbSPc`gW?Ym&SLf+S5w^aVm4Ev>fvS*b~w3K09JwjNC zWw3*aBUtZS1e{)^SCH-(y3 zZHi#6tjD=@jPEz29fqS1Q2o+yK85p8oT=aUfFGSrK7{G?_AJY0=eV=l&qVn^lI_HA>fReyx`T>eGVu}fGpUvv)7qCGL)KWQ(5?3(rn^qvIiD)V!- zmq&hT3Tz?^YizSVRF^RLM8{?JHy6=vG+uNH)ee|vha0Ta88l`zVUE;*eS)P{YNFQV za~K<6=_h7mY@UrdKI#`LUV<@Z`*ipb=a8&FeBRU6j%y(X%|O4bo{7G)25agC_?-d$ zX^e|ym>=C!>F*jX`Zs$jE4nrOpNPgMc88mk5c&O??WG*&OtLs zpJ^yd>!R0J^{$_(K5Cp7EfaFErw2YX?)ji+suRf@6yi>_hurf4->lalGx5}GRB8*I zzL(0g>kVV@-=jCJGtx~a>O%5=2W35vd(xvH80j%n?s0{RN1`m!T^aOEeXSb0>xZ?h z1N#v|STkM|;*HnNfBV=1%ya)Tu>Tuppv$$;n+Lia30+Rb-p5qvQeh*zrigy$pvyP0 zk4E~F_IL>M4yixPM|$=5bLs0lmx=CED@FI|CeeLno#_7a_eA#x&7%7+|A;xKuvR zI%iAg%{cc9rF720nt3434~g)p0?~4&tzhSwp^lwr+6s3TraE@g{E7A74SU8&tiYFXQ_k?Ngyc_#!dJKFQwoYrmG?bNwXDHvqT4)^n zkN5>_k>)N>r@C;Ui%F`H;D_>~CyT?u@f19MV2 zP9AC9T7vyJnvb4^Zw%2K4|Byen48g@mGCN>6TL!xU`Vy+*h4GM5gpbZA>o;*?0_6J<-%CNLk~^?S@0=u9+fy`bj7 z|L^R|*e8KczyOo7ZG}}YFdw3G5!zu}zE$5r=cQJCdt#`#H6@g;{lc#fCbc*`cy{)z zSK4^fYO%9vwF5s3KPP@J{NnKIhhKmE;_E=vW(|5H4fBzS zPOFQ=xb^(tuLQXoD+6|PxIR&M9Y7p{mlB9*BF2E zB9MjT!y4sImFDU0ytxSaRL^BYyxycavRcD?cCt>I^%@KLBoA7D5-;<4irycj{l8D} zZ1_{Ba~IE{yFH{I%)`jP9YcRq7NbrbRUDBIB%3**@LtN$foq^f?k~X z$+2>RqeZus8-0a%X<2Bj3ZWnPoFXUkfU^5fX2>(@+p9yjrSyR{|5wVlkBN5q?CB^! z+IN*K&=HqSZKJPc+b~Y`II!mXM|E1{nyyLFYb7uAAzCqa+J(Lyrfd3<-G{Cbdwcb* z^h0#+1hMx;{9Zy|0c})wv98JY_-(YYFxsOw`AE8yzU2_6Xp|2y>0y6Iwa(==+aq0j zjBB599pQaZqUqpk8viiPO8ap$?f=w1lpeA?;SROF|H_=llruQQL$rD1Pg_$qZ`~dB z8J_MTuN{B=ZN=?~t`)mGhbmd!*fVn@-b0UddVC=H;0wrR`t-rx{@ObSI0tz-Uvz$%soEjh z2lPCX^4|n`U&FlpedzOA`20-N;bzD_26OQ<@nZIR%zxt0zUya+mLBXa+y`IoTwc-T z$Mf%ia5ZC&yu4J1NBzJvJ)#Bc=ySBs`C~k@dLOYtHJGo%XBK1apGs%wE|u)!EBi&5 zbD-~Jp^j3{RFtXb7VsJMkAuH`u8)46RsLB|8`iFP4gw#7dSr;y>OY`NTAw_Rbx9NQ zUJH4)V?8^%G1&DSo)jV9$MJsNWfx#yM%{#1u) zC{yduq=D=$4(N^IFf1454~U&mq0%Vebd?v(4ARx1RDKIb(d} zl*n^HW|F%Ua^FIEpp)&Gr#Rd+RtzDXw~hq8yPxQoBktgR-cvkxsizI`aYG%LvuWNx#=W$a#v4;8-Y2kKm1xIJz^-Z=7{_&4-v^CDtdHJ*m+nKo>1!pA-gfBt@17hj z`+msYhV;|W|0(qA0QzD+e%iMCV=YAK!!dWFv$UCH?CCEuzf%19C99|^gj=2y*fdkf({-6rgUnX@87--j$VVzgMpb$!BPLwba@{+Acj8(0kT$-IXr7 zo9+_fvMlUXkHfiND4dTt0@9gpydF<__3ejVX>Ss7k0n@t>>33+C;CMI{bEG6r@L^j zdtaF>&q^GDF#>+Sx(L3N`m`IqFQZUkE{ypwwM!AMp+oX}oxc;~9VH^1F;|33z?0@k zBm>z?I@*=ag*XS$wq;jo+l|;~`U&=W;OFZRGbP6Xy}!kJkk1d)n4hQX7(fF(Mt;bQM!54gWFNV@Td0x)%DYOtK(u@^2hUHw>15jzEvea_@Ziaw@DPvE zkMEkOPQ&e(FROZD4=~4XKGEVt8T29T_F#9|g)IUh$(mJ3$kUB#JQBN!_QM@w-ktuc5WD z95;hs$Fm>elP^^JfL8`$)3($2in6Ic(0*9RxF`L7GAAFpq}XBaPUu+1FryB|`(Ohk zBdvRM8xcMIberfsK+_LMJLmXi&`P^-%<_cSTA>u|{UtbNVQuxaw>#sAGb}oiS_Gc` zPpNe0x`ih%G(zNzfL*G-j(Hu@DaIs(J~Aa$jg!5)M!$!c~a3G^4t z!#@)Bt~AezcJxd4a8Itj-wwaPYiz_jiZFO%Izh3IQcrSiJ19fs0F?10`52$6kA`-6 zyQ!{g4$jP*5_HJ%5zp7_I|ho9Kfsq~9Kl=xdr}$gj(YEnh=YPpcs!GIP5nERLU|+U za^2nf7RvlR^gd;kqyFA>oOe6wBiEx2z^8Z|_3gOs#5K)#Jm7tJ82kd_8)&}b$2IZ( zK^o0@WdDijnJ!1O8*M=8*t^^nL0mX^<%RJ4vK#x+m#|)^xN`0L z8!W89F{Yd*--ge9Gf-_76y2J(ewoE=bPLVAs0N z=#$;2tgpr)={yyzziZL_KsU&ncxX z>|Nz$p#Po4`YHqcIUar@1AVW9@7w>}Q=;tF(~a@J8~*Am^;I&$?$GX5$ILw4Za%d) z(i*}u$Byovy}D1CYe&6q8UmS4fS%@tQQI;4H9Z4UJ_OHa{?ylgbiZ0G^`_n-p?*jD zxU%x)K6|aShGoA`{;@kUjp#y0eP1H(D)v1RQx2F$R2!`9JdtcgBs0j;CuJ$rH(T&h9|IWca=I?H`L#$F_Ft5EI+s12gen zPNo<>o_HdExYZ^7pP1?S6%%tFrBBcSp z&<`8w9kCn(?;*2_`pA7l~o^)cxqKY#6A`Ia*4NhLuRuZyxpk(z>7U?cf^Wiy!H;%>>M*{B0`|vzsj!UFQ;2Q>s33_f32BWBqBOxE=%Hhlq z_E9MY6Lr>nsXg#(5kAFV-`mG&g+u=Dsdj^m;X6?->7)_$p*^W+-t16VU~Z1_yVz>X z+(-KsoL}x4>3OJyblMly_nn|yhxs7IO=@0NjTdp}m_ODyx=F@Cl_PR7mdtMY9DZs_ z=;(-$=kuzyqJ(W<)+Gb;ii}a1Q}_z+4a^Jf~>M3&?s#>zq-UnM<*Vh*Ljz zkmGDFVcdEU`b-n&pTKkdCv;mhpbgTXSIvv+?p~Lem$$&#LUnYAwB{-C;+G=3ZL9zO z{P0LTX9?VIAzmEzlVpWGJU1zipS7YLzUyJs%ZFH0AD+ok`DO6KJs5LOA+DG9{UXlm zcR>%W^v+eOxc;02{s}g9^gmJ7DWuW!1oDM+jk#$m-Jiz3j6cJndKQz3zUwP;HWxw+7P`0o5A;xO8$f0-!PgB<< z@=q6>(J=~hOzeMJA^H9h=vz|HSYZcjFH@w>fIWm?{kW%%#^j&=9eLJRjzr4yGUwT9 z=E2-3g!M4(>Cilkt~0RbVVfJ9O9|OFV^pFzG2VcSdCj-8R z(h{R-v<|wujfU{-e>ls~W2tr^A3g>2naQnDn|45_vM(j)_u++xlY0!rCyV*~mH7zp zG0P=dTC1&My3-~d=J_4i3!?eI8+&r3166mPdtGHNavR1Zs^^>F1Kt}qA@tArcL9B=h>7jn0&v_I{|ot8FxWc%hETOc#vO^=)J5M*2S)!&Qh_ zO{TB>JLzd}k>r?n75YB?oBS*I!%nMb`t{s}WWl?s+_p2ogXH)r^PCpt3B8Xh2wNKy zTWF3ULNoGuF#b}xUysuC)+<)Ihrf08a&O~uzsBX_onn}$oZCnHLm!@KBbrOCg|E`> z_7eMGY`#SEM((3EI`(MqS7Xp3Bkd~vY{qjJRGqGgL8sel4f-zG$z4o;#i7gW)l(+x z=|$GlMW#tbzvw~S71mw#KX_2ZDp6n1bB86icT?WRy#G2lSl@KKr!X%q#W!6nXWhW3 zVf?`UXrFuRl}6^Ef1zJSR5{i6VGY{;y1Us*$`6;mD(Wlo%t7VBe6FZ0*N?fYdxM%6 z%W`PGh;k@SQr&0Bds^G6`y1u`2hsZ*r0%bm z_q4W?_rV)esC@gtBC%yQ{H*&@&m_|6FOb$pufTTM=%<3d{UYe0^XKjKz@7!>X~bFt&wMJ;$B6G! zgtZ$O=voP@#2O298$g#|e*=Eb-+PS?@QAAMIF3`q`A*JU^K6zKKXFe z9?>W9T+PS*drlM=EiTxv6Mg8Db&eK_^@KmYj^=s!@JEig-hE#Sw&_5uot}FWe>_Xm zeJsy+81MPo`l`C;dEME3ZJ%kjCrfoD3Tx zTp!e(aFITq=4zvW6OTUeOm4O3f^lW9_DLh=g^JJw2n`I5$ZL*L`MWV7&i!|qv* zJZhr>;7j`^IzQ`=`ZIpmCj(6!m)&#<&j`_egb^M5R=6`NuP1yF?*ox9`|BW4G8pNI z+iQ7wt!Q}(&o8JP>=)_xg|JQ-k`;ojQ2cE>#&+x}RVQMv6MI3|wPOwdpH%%Jp2t$! zC(Jhqdmi*`GZW8aseEcTlBEN@DR#)jej~B;J{X=orP3T`D11BR`)AxY{Ig>=<%7?Y zyr^H(J$@|>&xzTC=D{|^4dZFwm-74=d2~9B*P=*`V-e^@%|Fyw@zQ^*GN@lm|0{WV z!av5mhxqIPPB!#5-}lB}^v(rGAf48tME`;zmn@gZPcB#1fqd{5E|;DyQn~Lif9lst zZWRNe`w;ahb3IFCJqFrI7%M>ENXG4syeH=6^)Z5dq;n@AAsu?D<>4DSc4&$f784A6O)HD3-r5?5EE5i><{-7llVF; z9Px}JFY&{C%_{~c(p=`8*{6}Voz{a$r?iid2E&ni^y@I6U5mNx8uSgcL)O1y?B4XK z2>%v)+!4^}zUT&zcFZd>!Gq>T&6ry&IZ&U7CodCYqaz~nShnuYX{0yx{LM2|?IqIw zxCu~IXHTB_!K88Ra^emlX%`Gu_Mn2+S6Ub#S?vD0ieR7wKU?mu+DU1NSoHCNBH?TsF#Yk>%4mt`hNG zyuO03jXtOLJ?aVn0)5H%K|a;(=n|NKjM*n9M9}SjIzcFI|W;!{ZG_e=>yLJ=v~;QKXG(VXPNPAT*^+* z`Kbt8{$o5etJg;?*Y*J zu(VGE1<4qpJY0Xi$Nq%|`8R* z#iP@^MG-4^l4BJ1sj&8QZMbiR7kfVRj?YxI6W*su#P^G;DNcuC9XwYiP3m~PA(!4` zy6C(<>jd5plJ7I&TTCLYbj42Wqd9~%dkWfuo&iuyw0!5uIV|fA@IxGY*6lb`OpXxg z#X2nu*lDS!UfHxhI*nLZftX+NMfO-&(g(%xnR-Hg?AQ0cU!(Y8y%AX#w#53Q`NH{z z?kAbT*(^9#kM^?LF-}t4f=9+4tFeUm(bz?28jCbPy4QVq&8dQLrVxp1PB~GA%qPca z%r)DPCu=RzF<+dq7U`v!gU~y5KG>*=`{?_f32Hxl_ea_rJx9B;a%c3tMv52v95PVs zvXX=C=4E9!-x#3Y=_h@Bfql>G-JzqOJnw9|_!5G!2m#JkY> z_>~o|eZ(4haBC*&@%##ZS3p?1o?nsK6~J{FuFG&uv4%R97<;o62fs_e-;zAOFM1|X z85Wn3k23O62J|S)$V3_b!ZnXLMjqJu+}L zHPbr^L>J3mba`a6)b`XTzrbEJ?KzwGpo9G&rsd_{F|%EW7iqjy-}ZS&j+qo2pxc^w zo9~X3k0D#8Zx*aoF}K7s>~pv$G5>JLkv8#D7vh*PoCG8gSb`|=}T%QP2z zlitCC%qs48&@Rkn+O9{sYP%s>dcFoZ&^sP|Zdi0!2KD0-$0|Jg?0ej?rU_ILGexmiE*YxIsj{MRo#FfXC!1aA1u zZFp{f8{+e}r64BMc&2>K#dUHnb#r4?SO3e7?)dZT!tsAyb?l6YZ|)JUbJ!z6EMEUz z{SY@7haX}YHU`iJ%2(iBzj(16YmIOjbZEuXcd~F!!dUM?93#e+c=V0GfEVeuzYyK5 zV~p!nT^Liye@LI;xCq-uT*gS~w%|nOzLCP2Xq_)WdZ_roI4O=5ddNrouj3+~n>4ELB=oN7u{J%N)4cX`vO^`mll7R{80c~$Zvc7cha7L- zB>FY?gI>v}zK=0?E&5l)*>6{W(kJr%7`lX=Z(NUaf9SFR&s3n}@bl246Z%|7XVxc; z(`PBx1mD&ZqTd^MKkEt7a|hlXqxNt^zvi0cZ`I{F)VXJ!h{iXyJM`R{_DJzwEyiHE zW|8wH>bvSEV|EbFO|ezV7VvBdG=8kB%AmJ$#6(qiJmG1GC;9;KM6Zwa?94|zQ9k0A ziV#l(n(!&a6a5A8L?1X4cKyYfh9j<`O)jk7j%)0{1k1JUsblR2k~1JOZ{6%zjJ7lk{=_M zSN`nw;e4{Dg4|A-=O;!J{EYLp7$;7=L#NBf_a$tuFSj(xz$ z#u57*Sf@)rK3pI5ij+7*hbT{ zjtkpiUs~o2v=jU_f@HY~ax^_5F8C1t^cZ;fK41An#(u<+rGUpSd=KTO zULIJ>hBH?=206fMAm#h6xZoXm^>lkVNkqTeap6FwK|g$|;&&CfD1V0ZyNE@V@wLjQ zHvJm)%1}Hk)Z-xLvhV{b!?6$MgKdyqh47v&ov*?C*Yl~uB8avAJ@gUbdpG1jjMy)| zH}uLQ*Fj_A!VY(;Tz^|>abbae>rO>no@_fcrwobq;y;ov*0zg%W^L1cj6*aZ3Zacj zzuGSS=~Ki0@gnTIaVlaF@lL;$oTqg}_CT~vJpGO{h2eEyZk5exEf9y2&W^K}V~jvVlKh%_)5cW6D1I+B59|X*s36q7RY15@ye3V-|_lrESFxmNnhiPb9j>!cI`HZy0o$9a!(e zF3D$lV8`X?H>BHbSg%FUZ+U)#aZ}t$*A&NH4!V)B=_dH+5MnQQyhV(RYgh#DAChl$ zb>y#j9BFRQ-ikiu+vRvOqiglYnbddtIp#RAf9Z)6cWQY_4$?V2qY$u(3^C!uOvH0J zKipOvu$I6@xT-Q z1FlIn5${gfp{Fm zyROJT2IHir)9u;NZ+NlUmZ!f|_DX!HUCDmP-{k+XCub!1>HMSND<}=$3k_$wldA8ZyGGW)B0QNVI*M;coBOEnl~`{Ex=#ldjr_7ko^Bgz82MOaP?v6 zd^6U}Pa?1G_wqe_k_$3H_jtzw-?Spx=srPoAGoyom=AG-@_vBm7EK=codbHucX-q4 zO`Ui@U%w;a8!x&MGgN;qeE-Y;wd&YiP2a{IQRt|a^DUG^&yw07RXS*YbVAo#D9etK zE}E?Lb88^)HtYK8h4AN}V$URk{fwcQLz#7d4?J}ot*3fI*L&b+-fP`%vj$i120zjx z*-$CIL6nHK4&6f+EsgyI#ixZgV}B6)pRkKi@!$_R_8mU;*Z?7sd=F#jG<-|W+8HUp{%*YJjx=M;OT+i_uwK>cTD|wA_j^yn&QIaliS7qf7uX-# zO0^foziHi*jga2j@H>SzaEL+8pqF-N-d7+G*)EModd>7JyaUtl`iN%BX<=_{^(OQK zxu&K3+bJyt-|xoz>t(bj16vE>J936B;f4g!j5tetvjS@xyk|vymwgMb4G~Lk35rFN zwAdF%9f)3>E5Mqt4YHiZH)kOy>Plq~%X$m@aV7_<9n> z9kiF|fuAA&$a(l3e&rjlhdoWgd^ipIy&MRI^}N}M{F)x$hmKzN!}T_-6=q`n8o+mK z)}pQ<%%4XI*93)dsIk=~b8?IBvc;GK!@*kodDIvVR(^Zq8xZ-fVN{@7nQfIjn2 zXxmTG{=dh0&7w$?z|&vp-!}z&s<*&yx z_bF5yBkdu}J!-@&>OGi90^WH;A3@z()jRw{qiF(Z=)Z5$dzbe@9{88pP0qp9FCN{R zp4MMnC--!*&lbXb^c3_>I8d^U8Kcr_i4#=OncTP!_p!@dCNQI&^plH%JpnP^wX4%p>x z#B*TYO!Yo+BkU37p-mDG+$6$pW#KnMgc0c3b|4+kC{jG(2hR3BL!>;k-=uY|_nmru z*6*Uvs5FgyM}y0wJ;Y1=9uj<3*pI!fE~LRwH$H+G*+=kR)tXD#Gv|Foaj9poBg2!s z2H$)AIrK?ocjBz;H5lu`VTII>hE+fM0lviuo1wmPcMO{8n2!<7IHbd$$|E};Pk(Ub z%`YgNde5|?d#BHsdEfmH%$i+1r{uwJJT&*=NBm`h@{0KjDytr?u35OKwyu70LvYE` zWsS>MWZyAB$^*)6H48j{Vx*qnUrj;>8sWfiV+uZ@J5T z@1j60ZUaI0q9qHXW99!*LX&R(0!1~tJc0A8au>{Rbo+zB#qQDN?j?(=7u7CX6fI}!;>F;*Y;jev zYS99Bu-09>Bv`j3=$>CyQ$ey!om22lI**yR=oWQe%;ySq9-TeD5m%bwLVrz7ZQw5V zXbcE+EUxGaGz1ryFRANIU*=aO&xaIsRpsu{mF4dFeiUA=Xabd0HRbM##;RaNxqDev zu+rTS^aqzTpf0iil@9$atXkwJn(`$TRE>tJ1&jPOno5YOsO}qr!R3b9S@6E7yQX5% z0+bc3t##MbE?STv3Tl_slrOqD=nkMhkRiBSR!`ifPD1Iiwyt6k>2Y+!U912?+%;8; zD%>}ZZn(Km)nraeuY*8lohbqOsQwBFys9=3tZ|pz`#`~*f|8Plze2L0B3QRdzQil)w-iF3gNGatO~{yAdiz4uR@gZq-H#rG9>XNj2)OuOHE z-&FD7oTq4f5O36Od_P zZFxm+yV&Vt(cNCRxHfS6=Zw zk$!bKnl8{#cWAI@68wsqfOVkItL;`~;sd4aRY5Ga}sN8OvrmZ^23*hg<%| zecN~C)v3*#Z{uU?e&geO{sEuAFV6?}$dfquOLacA@dZw&sWkYtZs9YR-^zSiTN&T4 z&OiJ$pAp4`<5X)%oqwp)|3%%mKFwz?r*$vi@8@-IQ}S?3$xC&LfddC7+@Z6D|M-w)D4ju!YpUf#nGKl~%>eer+tpAh}A>AXM$#TxNLu}AC||0Yg|Oh>8X+YaKpUH+Zs zm?O{cizjg2!Pk_&2YDY6)5SkKQjzyZ;$Iz^Ql6mWcaAcaZH2W7S8dh@!WEyCoSd3A zyu>)%qsELa$L_|Zh+lm1(ig9MG34^d%h{LjzFc~_`tr9gfA8{<%LA^A zz4F7$KfF9k{=IbBlII^@_Tu~yUsHPN<0R9~KcdEu2KUl2a>%F-*> zeMwh8ynM@-`MA30%Z^awJZ*-AL`USjGEMn6M1SMykD7_~^dyTW-1XogOivH}k}2{3 z$?E;u! zMmizX2&%9>l!zlF|I$CRC&a6KolR%&faGVaXC2f3^dAU6R_SNx0*B1|4VC^Nr&BpD zE`rv#*LGaC}Khw2axbY6CduG71*A{L{YE5j5-_rl7ep}=2Lw(DBmEE+i%X1wa(_0+(B; zbnJe{^{g|0lhx{2hVoQdQV)lj4(~ig^-uy55{BCDBTkpP_72E?rr)!11)E&0&L^$S zjv^4g^)_=8VlwE5Q$2CW_GbEgqAz^Xn(zfZ*@_Rb%zq1ca`3}DLGqZT zGE!Iv{@@*52)#hckbc#AURt(-#jBA z2uk#?GQFHp6%3H&6l(f5Yl~x^GDE7I8}t{M-qZu?HIKBZb(O|WRJOlY@ysWl-+0nB z{jHfqDjRv~lP<}#i0Nm7znD6pw~eMNO0p@uV<``}I!PPHdz|t}rMluEd&Yx0c@)v# zsmfkwuztn>+RN#(U)bBxubWYbxuA_OZ5Q$K4w&^!!n4=pKiO|{+|<_oo8qT#akja< zTOChX0W`#kcf9Ytix!m~cEGGn@vZ%dQf5Ii-M6{6IG?h%I;34rb`ety%OpF?`3N*a zI`j_^|M4flmH3r2-3g-Oep5hwhWbEdYvQIP)m65}J=Jg8vEy&O{qB4B_C+g{nY{OI z0oecXA9mou4ex1wveo*DJ*NL*8!R&pBk3-FLWs*rUx56}iqKdW>k{b>G=tfw7Q z$wPWK_kS|JcuQPcKkruOQ!cAmHI>v#0ciyK7~mtHO0Ji(ksr<{U4pk8zq8DLGOj@@ z>sq+UDmvy>hD9t|!0i+WZ|?+j`fQ zbuP=3@E?DoVMjZ&5@b2c`NtANZG+^y$rmpo>6yH!E&jfD@)O$PixTJJ?=(n4fB&H^ z-pYSRU3=T&7rcW%qrl38`6nHF=nv~e_W?*h^B5cp>7$bA+=@=NzxH|L8#Zuyh|+P8 zzMp2Soq)djo?+MbA*LmnKr8uAW1m6gpXKyiBYh^PlYa3%33=ow{U|>{J-%>r+>`yh zQ9ohzNO!Fqg|vJ%Mip^>>Brc<g=_YGJBwZW$N zInX5Ns4jb%-n7$cOiz4|b9x%_!y)U>SSkUmAM~8)93lQ1O2Cs=`g4`^F@GbS>QKb# zt5pB>c>4^l)`KufZDCTLMy8iCYJb4;1i^0$rz56-rI?Ve;%Me)98;k z`X`^R@ut5o$jU*hWTEP3r!e^0z)(a5PSuobUptsau1i)b|9&s~3-W`9I6a>Hyg6T;E9cs6*27eq<%>!IvO@fX^ngMj z_J#7P{yvrZI~nv-30trEQT)^WAKZNHlLM^HZ@)Da`Tuybca3u|c?FWMi20C>fR7x1 z^ct%YP$j3!`6!RSQ?=dD+KJ|Z^$BDU(-ZwPIkYNHyn_*pN@KenP^UBK1s7$aRoFu( z-l1~;#zE$aFg&@#V<&U+p3+xwo;=$UoZw_X)bxT%>3fhHw+#L>Ihp)E;rf0RTaFg~Ag`ZzHi?OgsMToa!h9*5;xR#FJz6im$bbXqB|zlyI0PJHzE zDc8EdHZcAwk6(082R#iS`kB;`aA-ZZF;0Gl=+6#UfX3a7@3}$Y z6d+BI-*}56)azd_<6CZ1xSapsa)##5+pKbaqDWvr zJh|t4Iw|}4Dn6U}RNkwIDyKKn#Y#_5bmNL%6S=6(9n{hTDp&#(6ay3_Gg3}X#NPd0P@x=zo$0hW=ZkPUylfBcC ztxf{ps*-%P9na=_SU` z+xYwojCj=8n@}63UlK5l>Jb4_*Fb#^6AC3{VG1Zs4DTF>pNeyej{H zi9x?T2EHQ({_`04{unrow^!4{D>3N*5CeY)cnT~rp2y7%tk6@8@8v?=jDN`ZamMv{ z@d@K+uTz9YOn;g2>=XrTVLT4{q;d~2-o^Mp#`mTvU^nA~V(7m*20onm;C&x?cgnKAI$%xB-QzH-tFnpZ0q@pe*gd)eXXdVMnn zeOV0r(HMAL417fld`%1-@8d~1&)lf$rRS~x7=wOu4E#qi@b(z^ju`kq#lU|P13wr8 zKNJK1_ZT>h$5(4dil?|5j(4=Liqm*}HTnxN@PCKeuSQSf@zwAvz^Okbk5uioN1a4} z43va-Fz#mjI^b91Glc0QOdn!;yn7}2_(mz9opG`Y;x9%kfRhE@S-dKLybpa~pa2!@Au{#F+FJs{07yHD0 zQ+->%rRe9WlSpO!JmY%3H9Q8Nkuh)t%#I6)QH^3raDHxiMF7FLWy^yV@>WL1B3Rc* z6G4hyMl`etBJQ-jYH?5m7uGJV2-d2zpDvKn5LjGWQzIyJJm@bIh#qZNGwFqI`LIvVNl2U{&2L$3}%a<&ylT0bvRg^FGFI!x(psE%k zPzuSTu4E}(ZlI>ZkI;HWri57nCW|VTDS8DVSedy%Fcc9)Fs%xc6^IuPRMwP3J&5cM zHZ1ekAxj0s)osGLA zN0ikD$K5eOpvlJFaR*f&A-WByc%ZVBL>!kV>Vp2o(Bn81sV*joz>;w}pk353ZX%-K zOP4fMjGG|pm-rV2$Bn0!Ug&SArn5E!1kx+Gk=v%UylO#Jut6-Px=f-<%qc0p_x@>f z#@!*72JgtuF3lcy$3#(61*yi1($a>YKTus7sH`qsu*AQ(ybnV0#9~?P;_~u}nyQ5e zC0^VhmIWFDm5ZT*a>NXaIvF@D0yVV_704PO)s>c&;-vyHU#YsPp{%x%%tFY&vVqB( z5$;Uw1hrHxszO6a^;DoqD{7>9&;?|J2~$#I5V7K-ysAPhoiA;1zGzf0FQ8P&u&9>G z^asiCsC6jfSwOYOOZU_z=EFclBfsGw8iC@~20?E$;7tZmN-r&dG`PGJP0=70RxAwE zEf)>T8-f)J$xvXN#3=x4r?&tEGLM&6cppH<|C8pHH!Lkx?=nE@AUcP71Art!ls}zh zxIbM~ELtj-ECLl>&>Inp@MejqXsie1kag=` zPWK`>AF=bY&o?4Xb^^MntCc->VXf2+z233RUqc>%x(f%m&tIUg$`(+~C2xOOL!CcR z(IA3V4JwC#4oFhbu!!4$v{~m5R*FC+N|w^sKyY-DMdd20KUlk9K~05rAM(s)t8286 z?5V-3U=5l_ws^0#1ePprKtndphmAB;D!j33VMASQ5ZUBC+9X(8gPib3^wy13Bi&U6 zY8NT4veN49huXRZNlJFn7^tbL3)G^Omj#wpm7^AoWr(RqFR3agSHjLgu~veR0l@eh zYij-FC{3CPIat+J{&G=A#u^Ap^Pyf+5iDH<&Ci$3q0&lg7nhRcTsP$r;ID$E)n(4nhVyVK?DQo( zj@jue8Mo8d#GpUJ_#~9eL#jm1GM;P0UAU*iPOtar?er&^ei+V=sI2nu8OBLYOd+F( zUawQVOkB?+?DUhdk3q)`Hu_nN+v!VU(AUMF4>E3-NADZj`R|RvUq5Hk^tnoGafIoI zu>2Z75ksDnG35EkMz8stkHNpoMz3{E`$BYReQG=j>rgth{MqVOBr~q*HBS3BbZC0L z-Wg+~*SOv{*YqkkVy$fS8ZWW&*Y%ytxLu#+Hu^$lRB7X{as8Z6%QKVdLpFMiKW^i% z<=n`)-F|5Qfey`I-64i927NX+gq>bLFVgzge2QYw&t%+AUlW7Aj&ZyEv@WK@F3$@w z`0MAOnqJ#UhmBt2hi&}%HX6UE<=1$`M(>l-32}z;8@YdJTt9En@-TVyd4s*a^ua4S zG`&yW;kg*&cK&;9^m~|oALCknjelgLk7xSxHvSr?^$Q*3hrg*V<=-^M$q$>jn{o2P zdJRMwbj+fzmu8jC^maYu#3(m6M!8)v%FX3RAi7-Lj*}VJ`q6lajb6(+*G8}Lx)}69 z#_jbw9E1Ky40;bYgqD9d7hK4=mS5wuZ1h^r62|TF1Y^)Q#-KlGquSldX#9+g zUdwYf27i3(OCGwun%>2@U4C~A`cX0HJu&DDW6+n_==ZZga~aq5)ws__ujMa~!GE_w zPme+xIl~@<-o*DZPW_R$6l9Klj8lI!@eanRKT@oSK87c#E7CJRf{}omaniGik7C?j z?ij}H+?9{c72{Z^+4m zK|pJ4uHZ2UET zHU|I8jN98qhf3J%mBb+wcKzovZnvMwjN9$UXVCLjxvW9CL2u$AgP!b=hxKSIt+sQG zx7+Bo?Y_Xc9#1vC-$t+bbTDq`f5Jx3>K7*&x7RnB;|NJ_6`C05G{&{wbh*PBx0hQI zgMMxd`WI~Uy67E@+vPmVILSF*6XQIW<2FdnEZpmTo_UND9}|C?ak49OAEupgvMUqc zWAN8)LdEYj_?x(XI6`tRAVNOe$?8J)>$8lHVw~h8zohZ8jN9eRX521kIpb8Wx&Nc% zK6N{Cv7(0QwY_P41LJo3EiveIe2krbAJg00@q~^44lekljlae}veCcF^yh8#8kb+0 z2aR1G7sut;oZ1fsGZll+HPT1%*uH&n8d+B!n z$VRVmJ&D)!tbXC*$-UhkW-?Cw=uu6K^DM^gd`e>QX|>U7dw!a6ZC4s^x6$jOUx>l~ zgpFSFIT?e$;5cu){4U1rddRiWA7+6jGp^;=_)HtUmVZ_Z{vjK^mVdpCzsB1cx3|mg z7<~4`;G^T+wH~ycylSJ@_z4?--S1A?=rw-UMqk8=_{c`Dar(yt=+N?X$UD3fY@^pW z{ez`+*y+<4*X`0FsW9)g(d%-@*yuHme<)HOc0GG+d^G<;8y}6&ve9e)^bb+dq2<(g zWeob781#)cdc_s*RWNS1=lzV^>*d0SMCs7_bg5er&$yOT^1FWTsJy}E4l z8c#}74DIqKGj5l^i*frr@G|4}d0^4?iobo`G?Q`rx~YV5vWG=nS31oz@LB_}H1K)@ zZ#3}51|Bl-1_R%~IO&0gtn-}qIOC)T6W?g?S!nQSH~3H=eU;N*U|hGa#`oFiHLLxM z+x35janetnCdN4_UEO@89T~UtnauIc#K&A0tT*tW!N1kOml*gC17B+39R}WL;71JH zY?l)TZnjH=aosKm>5|78#&x@B{H(#pY?o2PRX)3Z#xQQzPcGx6pJj&p`we`Bfgd(- zvtGvy+^pA0#&x}txn2>*b-grx#^7Vt>pbK3{&?GWb*fb+ew=Gp_Zl@eKwaQ_rn7 zJ|5v|nxd5$x#>!tA%jFUcnM!69KH}_9m8H&g*Pdwvxd4@A? z_j_)}Ngf)f^pS1QQ-6uD{5b}_iBD#n){CFRPMJ7 z`HwSB<(l|O#;IJ>AD%IA(;uE^T-)ba(Ond%39wZkFq2 zT$hWNsO2$=ab2#)$1qO(&HnB&@b!{|`cq`!-!br+jBESX0V zc35ZQqw%0YPgT|Li#IY(^)>Mj<5b`8f?gkwyVaFl&#eY->iKELwVvIq=XS=mo;Ci0 z!N=6|ZUZ;%YOjHt%LWRNDBoGoKn8AC1?=;1jg*q4#y^XteRs z_^KFuHrV*=VLp%B_-K5i!RH66Ncs0^8=rm5r`^U!<1fVEv&Y6qx657|AC2#e!RJ*Q zpAMGikd2SV569qhoN*d=erVM91miUBn0SP7ZEuIT+%t@8d(-$?#;L!U`n+i1rr#4I zln{1*m=ps~i-C`dfoI3SCmZ-b8hR)+aC7}K)4rLb3 z2A_q7JV66D`LAMJ^RKg1rV!(rzsA=ad`$iuYX9weCR~rracQa0Q zW#an``WAzJzd>)}kr?!6V$dgzR7}aP%z1Shi3-O?Q+J(M`yXnxV^oCqZEam zPb1@69?d5dgMK~ZcK-3Bug*V-aXbI9G3c`yxAULHIJIw^782*jWAND+gHNkLpMv~u zr((9npf~ZS87I3n?d>e%B+nK@p0u0P4dG82_$UK6>9b?tvlyp-VU}CMxVGE#Y`1e6 z*LJIMpTWP6-5R(l=OF_(9fz4|fv*Tuls8@MUwMguqb zJRJj%#K6alxwtfonKAHrG4Prgc#v_sJ{uXg>(h11)#Wc|+-^U02EAzy zPcu&C{>W&@c7uaajLJ0 zyC^sbhn+s2aXbAO#_e*BW!x@j4&!$JroY#q`OH*eh#fY1jqhiiD0kE$!X$8 z7$^OF$DohI;BzJhAJ?raGx0IU%_IXi$IVp6wg1Uw|C7eJ_CFdQZtyYZV`B_HE{LGV z!Lf{MeQG@0peO%a#C|)6ab2#)J&aSmwj27HY2eQp_$&i|-oWQFuIoFO%bmx#E?46| z8@-R|%Wd=;uVkF$e8DKU(ZJ1l#Rh{v=}qs?JkGe*o5nX9e12l^Z#VdmKK1)!FEFm_ zrSTmGAD_WzkHLrJ(Z^nckBN5~e14{haZVenZghXqNy8Z@c}zZI87IB{lP1PF$Hr$e zr{yxP^`mi*jb4{gXrtG7iH%+tJ(qF2od3JD^NDS2yX(07NWnmWFhmeUKt`k}rFlbM z8z4Y{0D-!#Uojd%wRw=iGCz?Mz%r=&R;WpGHEz zp77r@J?q*xfARy<&miy%(~}>Wo_Y4bz20NTKL}zp9klBn8$Mq z;2cNtazekD&@X|9d=4dUQ~0~CGljnp{XV#_+XvvjZnwc%7p*$r-p{Lq{yL#wxE~$q z-^cn>1ZUsK%L)BrLcf&IFDLY?rf0nsaIbd_JdDd%D9*Mm;eRi@BmD1#=YKLjU>~?X z4}eL)@156ol(~HIeY2O!!ZUkNVFESN{@tm{!|A( zoOO|(n|=@a3)7Piz(XJO`u_^t^SlQ4JaccvCI+8X>E{Tz>&FxNIpGh*r!HLcY$W_Q z!P&PSytcsEH}Y-q*ZHuU@PA?cefS@mKY1(R-%0o%oBt{N`{qx6lJLI(_i-G6`?%bI zvu^{;pIdPDjXd|kn3x|&Bf@nZ8wC&f=E~n1^50m#Q$EFPY?d<;Or0i2Dta9DL%TMY>JQa9ns&*;+`Y!uIQETgZpva z0cSts=w+`f#Yf{FiT+-QiyeBRSAGoc{p^E#KhMFL56{0B;5<)}55PlRUt#ju_FA~E zx3}P)Pwqo;XU``O&iT)Ebr_uEOI`pE`RMDiS#Y1{bKpMDtKjTI3ANS0InT*A68dIB zzh(L|{I^X{-c9I_68htWzMs(N@q!}Mi?<@~G8zUCeO5jR9{T*p$USUkg|~&Tn*T1I ztC&A|Q}jCjH$|^}-}HExJHQ=|7kS(C9LJ97$&XFXap{|${2V;==O3jH1M}fim*An# zTGy@k==*GipNe~OelEdi0-W`dPnn)^r@=jLIiX)n=$FAmy_)Ar!e=$%vu1ksvjNV! z$Tv)1L19hPlkb|Ieb@u{KD5EZy74uNvuy`FtQ*RE;Gqw1i~dyj*M$$jIgWhl65R6{ z|LLf3eF5C{vkCoNLcfsE7Zdt=Lcf;KZzS~1g#HRV^i$6-lRxw7K1_joA4;ZwKhD=> za9)RyuZTXZdvjU*a9b6BK24Z^^e4`kjP+-}HCMWIqnTz22Vb8TUBh ze`Ajim@An-`G)D4e>35~XL{zpZ~o*ha9;=7 z;JywVf%`geB3##jb8z;DaWBBVpO>cR`gUb{@>|o>Klih*9A#-v-!wh_w-Ww`rl)@^;omhq{f`p<7pABGAmM*wdivic z{6~H+D*Svs4$g6>PXXM=an|(Aa}M0+ZPE1fFD3jdrl)^3;lE~j`Zp5(+om62-QF>O z@)oZ24-s-^dI2z{ro&32?8gn9!FJ`f5U7OX#;v&pda)J^y{vvkwOe z|0C1WznAboF+KfH6aLqxr~ggDf9MyYqxU}#?)@*AzKDb-z}X-2qUo7`DdAr=J@c=b zKY7FS^j}Z-@0gx>?wUV&*Yu2gWP0+x>6y<7xcBqc^z_O7V%(GcBp(Ckc#)4M^pgqw zR6;+W&@UwPWz)0XMR2dTmeAJ|`fbzm@8s@)vp?jAre{8_gnvi$;e5gGXX}by`4PCE zr+VOio;nl#7nw}9Jr}+5OVRI&{z~-93%?XaVLpV{as2;B6X2o$$`|INKIE@)i{K%D z<#o|(+%?fFAApDR>>uXj_RI0U&)Xqzjw9#unCa;>4({`6M)YC4`1gNjMX!7TJmmQ| zG|#q+!oMzj1)TYx$0guhh(*yWUj`3(euK$m+g0)5 zHBorFB0kFNqF4Vl(JS8&eK;PQuLbvPD|+Soq7UEVpulxnLuS<$vqu-EC%-oRT@$h&H{d=W7JoG=Jf9_S&!>{mR}=b1LcgBS@0orH z1?-!i{Lu8Qw*~I?_7nP(g#Oa>(+F?{&i;@OExfy*c$mxM4)x@drf2?B;GTamp)V!$ ztEOk36>#Q5-UJWx{A)}m+irq~d9Hj1Jj`=_ANxSKuJdi-`uTE4_&-V9zVIF47YRQ3 zYfxC^8{z|tJEL{+QNAfYeY4dtC?MUe~Gk{ImEB5LEUEhvHuly#VzfI`#ABpippFhW9v+W4D_jwfD`#dQ=IAKy!GAKzQ>5Lf%Zi4%I@|0;dE72Xw|e=|M^dL6G3aE@2_ ze%Wvv1?PB?kBQHdD82hRDg0By%fdDPCE=RS3OMuWBcD}p=0jc)pC=NxD!eOv8{Efh z2i(W2Cq8Y*ozUMT^ur&INwW_F^kD>?eIPG_hw=S4srOub^mw@t zALV1e5qA##(f7N?!9#zP7eue`cTI?1c^RC2yZM$FZxNioe@MP$`aEh|Ha&U8^lU{H z+>fvQg#I9*KLihb{w&S2?XmEh@N?mx7k&lKKJck)aL;q392Ft1`iy}GpWmcOwjBo# zKFTLWuj4)?dgZI&J|8OJJ|C*0*Kx0jUil$7`@nH;f%|;un4Tqf!M$&1;NG|EgwIXF zXBbTkK2-+Iwj;vp!bgR_BYXm!_427naL>OkK3}Fd+ioO$nhBq->3O^yfwRx#)lbA= zo@Wi*^V|Rr{rPvvbKiY1xema2y~0gnmc#n&&RK=eZB=dA7ty^K65Ao;}fP z++%Q$djjrpPsJz1ox*kgnfNHbF+JzQt?9`ZKKbf#FM@krHE^Gwy9vIR@ZV4PcSNs! z>w(D`4)J{U(d7q z3EmNZt*a~k%KPGT#ALGVh57J%JqO?%NAfH2(Rp=aKGTSCYd++;--&{--s(6Gf%`lk z2KVtD6(6m44BW?eQuG>k3f$w)fP36I@zJ>R;2w8T^cr^w+~cl*d)$inXxu8e$K6Wk zw-fq3(@)^I-UsJ=Aa9$V>vPBSS0? zOXw@6=lQw{{xTmVv}Ss=IoC+|Z-`#|*%W`}+u)(kdOh3`AND51?t*(Cj>KQ}SK|Ml zOg`IQ3;!?SdAupZ{`0&!49@GB)CY-$FjSrYCQio^jizCqFiQ9{zoBe?Rb4^!VuDZjUqYFfPi^ z#Yg$I_zYzZtoH`o$K@8>-+$(pSo{0Wd3^X3^g92C!Gm7;EI8*g+K`(A_xZLD9_HKI z6o)zz{8;#Zi~dx&`V54ter_f1>~R;sz1||Y*V_R1de_0d-c~~2PU!pKp69LbdQNT+ z;{Bk1NAQsFuL>U#uGeEz!u9p|jBxGqe1ez2*&nWBWpK_<@@3J7>tx-vJ*p{T_J1_yPE&@k8)w z<8AP8+-ja(@Ok4s@S^cPc-i%E+@D<|&@QU#(@S5=(@HOMPZ;kb=8_$C`jgNqD z86N}RFA^V0;?<(D*EP+xR?q*LV@UXS@vFH@*aZYJ3I!+;|0iV7vx?Wqca_ zzcD@wJ|2f5_ulMz{3_TT;qgUYf{xcaY_+ z)J6SNxQNJZa2hIoj%;cjF$BTUJ+aqV6$&bDx@&f80FMVg^E5>`^JI2Sp zE9!g3>)##ujq&{VL_UswFzyyO`$x|2N3WTl-)p{M`~(a6j&Xi3b=&xKcoCW1E{ylU z`TsMR55J$7zn4wk8;w3E7&r30?~go(aU-w)K;)CgPr=K^TR0I_jj#M*^w~7N4Ss37 z@k3G1^@;hk!MU!GUxF{=cqMP)Kx`Q2_d2~We)z*N?xpdIABlY7+v1k~BR>`&SB-bU zH;waq4)%<%Ohlh!F?Q^H~Nj8Q*$;^r;)?-|uc3Z~a8nw~aSG5c#Qb z{(a<2<2~qyaeOn+Gw>SOi25O{TlC+>`?e+H z+jxJWYWxa3cmMgHKB+%=m~HFN;bo<4c<_^r(Mt*73h5YQo|C(rh00`VU^ByE|AGU&64g1UCPY#5=Qp6}QuW9=GAN z5aM9^=XgE-CWZVCPC4lLP(V=x0%T#keHC4g9M0V zg4kkXdx;qcB1%wuFHqX+ZBd!lYOr2QmEI!w1Fg4CfLdDcUQyIUgLyw||CpQ{7;pQ2 zpZ9s*KfXsZ=bX=8d+oK?UVH7e_u1#rGI#z>x~4I8XzY15c&AXt_IU^o)}960k~DTk8yF~N zELfy7md4nmglzsqNe|C?)>kGeQ*XItl`wNG*`!k2W8`a&&nAxY{ujgupbMSB%_(yaWUZ=5VReI0W zW*^ZRjJ?L<*s~GGnBAY<;{m_?UFX)kx|3w+nW(jQ>t^212L?KOE;svJPWHx}BzESc zgB5?eNZU07ynFMt_Lub3Q@=xfh-MB;J#~f7iqpz67WFvNcX!|0nENF12X&Tx>`JrG zqqAol;~3A=`t<8cTh)?H{uw#`(KdvGw>z+4dB;;_76CJ=1AR5 z*g;&AET~tg$HB6p&y60miRm=Mo^5Nxr2C&jUezXLTh@kM%$ew7dZDWzb9Cu1A1d-B zJ=u`eob{Nee_4m8xwX*wWw6M--Z|cP(ADNjLcLA)hU<{gmKATV%F@hPnT*wc1X;6S z10_LL-->IZVNO=>LmQFqh`*4<>~kOW^-}u(K-O+Y?<|Rj^POxVwY&FFFvF)0;w1BY zvKOSoUaP90TfKR0hZA*MkGf5UEk3ZIq_4apYahxS?MY_snaHzTmW?(q`UGXsnc?pY zu6GO!%%Zj@yCrN6Y_;l~uvbv@f9+bl)~2o* z>dLyVYuA&^U0F$NmmY8SWyP~TmTrcPbRlCV+SG*nB=3b}@*uzBH>ug|aG|`3%=x+_ z-qE&ng1PIa32aw6_|64iKltW@Zx+(^c)iV?W`@mVGmN&0${&njA1;fY?e?K}wPqMy z!Hgb<9<_h>!5hQop&PlLNvGsD$R5s09n&>oR=XgZ*o{6JacJ3;{t?e3^hq{)+p+6epR2;VZ=jZiF$CsF`M3|qbqMWq zCNg|`Mg-|&pqpoP*4~UVmY|IB;H&5(b66ib8OAZKP|DipI_mBHGq(%9@X0u{&&2&y z(9n4BRpZ=Uzd;(tnCz>7?bo%!F3@Q3X?eJx;b7shu*_9`t(!5q;M_)3Q z)8oj9`_4uC(s*?x+F~8X9G??q9WCw6 z!g%9z2E*=Tt<42}xc_$ZOpqi-&{pelhP~AP^sfWOrF@KJRac^Ye6Z10_){9YvY-=p z^JUUD*A==p42zD3#QU$1UH^vi_J257o)2}4%KzbDnHR}2wIO9rwv;(I22+_dKFooB zNH64fs183oKB$kS(8o>C$1v#QHP9+Or&_L)E!P)Wt`l&5Zq18PpMZ9yIEwfGt~j(K zzsLBo#0=}j)V_Mv#6#;c90joXu5}sOd=^dxO(XhU;23N7mYQMT-N+9=pkv%Cy_JO- z{Is`-VH^#n__DNiZ;ICbC)j5e?8@iC{dBGUJ=}Y5L_YYNApC1E#SFi8ZlJSuq_C;w z=u^~h4K`Swx5y0d2aWG`QQkq&DEY~z6g|aD=hnQ;eO9zSi(z*W*3PB~{@uL;#c=+E z^+jDZ)RF2;%Pk7tNsT5 z6HzY7!yr#)zoY)4F9(W`!B>70kJtYWIbH_Mxi!Cz+9QoIXE8pJj>bT@FU7HIcA%Z9 zP07yBt@#aa*UvEz@C^*?{S@b8h>?37X}b~I(|8u@V!h9Ybk+tNJ>|kUIP>d)=TtjV zI@zyR=j|LK-FtNwraottBNbzA0CR%97=u1bWqqFsnL@3XnvY;y?{hc#nl!C$7RC6# z&>5%A!T9@Gs@c~yJXl0ALK^aVk=})Ll$S?o!Zt-6h>ozYc-b#-9SAv14AExaI?MrF z_!Ahn8^|l>Jw`m+OJlm48vzfIjH#ec0}blm9(q!1hXHT=0@q`4KB}92@sMjj&hXQ) zKNceSTXnaX&%jo__XcwH3Fad^h^DEuX~)+qXJt-7YzQ03%t4F*yUeVHedA2+--Ede za|m8!ciqSrOLiK2zbXB{{+IN(kgn{2ViU+8odcR0ANxb+*1W>)Tt-o2YxQ{BJ3KmGR4SsYx05`yB1>}#wcxJ=2^z)ugb=a#opc^V|%GxdOl_C zi~9#U8`qj0N)Fc4*t;3ysK&w5&f@l2VyM)@z`-kdN%qq z*%j~0u+Pz<6xRNMo>~RE;;y2SKCL3K&pj}ZlUb3ouM4pb#XTP(4t^T3PMPjZL_Ag) z#JKKkzV5O0h;`N@=3F1Vc>L42jOYwUzp62kPdeNW8Lc)fZKw}(@xEi3Vr@tD^H%6? z26Xo&WLt;WGp)I~qZMsgjB^O*O!)B7ldW3=dRkkHo_5N_I>83W&HdVMSbGoFM7(is zZZ}w4AV0eMF^tdKvEGq|I*^Zo{YCvy2x-c0doo3QXwdo!)?I{u6MfJNADbCu_51q= zia$nus66CTJ`C-K^##abjYr_Wil|-@*g!Yti`4!>;)6D>hAe`=7~83>z)#F~BUl^A zW#LSd#;IV6F+t30kHZc{KO%pRaTD_#1M?Nir`8C7T@!>(6z0L4nyxYL;(4}1f30Y5 zQ5Iyu_-@GiC=ZOs)u_wRd|K7(7`te!Ho)IN`P*?#WhvQ*F<_avk37FU<23X;G_RxTH1vL4;#S%oD~7sv^EMFi4DrBUyDs$!IZ{mM(v3Mi z&EbCl8&k2$kiH_vB8)-VXVLFJ7jw&y;+G13u%RLiZKTbnHsXFS%%E%UR2IH3frVFG zioeTPIFNg3X{89^S&`fu)_G0W)zKh}m#18FErDk~bcg^s9x0>OVh&@-`XokJtWno__ z3ttV{R@}(K6#r(j^s4=qSTvJmpuNAnn%Z2|U&%U$jjM8Xb!L#vnV6%oLz^?Mh3qsR zjEvi!!J0A`QC~MuPpXfagNxWl_$crUQ5wY!fa zR&@&YE9O^p@2I*6HlXgIld3BrdkTE>XBguWa8_w#Z+nK+)lv1DuzQTXVr@#%5}zvA zG}gheo`>-dd0&I=Qu#lTHjG$-mp^FJusy`;SxisV7qhU_i#Zk6F*UDfcj}WAle)VK zR!9DId&V5*tnziaSNGr=<7am8%K@^L5RWDJT2`2kPt>-wcF_;}B!9>-r&)YxTL#_F zfn3I+2QvJaztFgKd>IS(I|t{h8lQtrsG1G>rt|Rhs@y|cGG-;%>Bm*gI@FobvkYT1 z*1DqYgg#wO`UB4h%84L76E^V^w3CWeXpQEpwQDpk)nfm_#_|e(QhcK1i_4Bo1FZx;6b2yJ=;TFUJt92Hp80BrmB$1 zcVRq9tytCDsE=)`)^z}5y#V*OSVnxF6Y+#mXE!pE7zA|{g(XI9N0-V)-bH~ zp}K^@#~Q24IYTy$9X(9w8u5F$QBNzR@uLNCS0mP0*6A!qjH4Kfu?B!KdbAg@h>2Ll zY&PV&$U440#Wpy`8(VG+8(5=qAZA#HIM0O`Yf@8buQQ4DO>D|Sye51Y*~gsR%=(kO zU!*2x&d#jw=|emUds2P*K0Pf_wd0c*qkj{}7NY!xn72T;!J<1c*6ldF7S964W?%E= zKxY@O8A~mMU#OaozS_F>{*Gn%I|2IR7@tca%S{!&-pOoun^{rbYgV{=y};rsCih}Z zaKqH!J<>p5w%Y#+LU}r71}2b zYXBP7#2M2IUuEp|S3kc0$THZ>Uq%go{RG-;9m+J(UK7z?b1VG4bJ1P`o7g*t#hpTX zy@54fIbN9IXd5B+QgI>am1NrxZKI!Y-`2B|^&MNo`i{4-z7r3yzCVAT^?lgJ`u_6I zh+oGCZ@_xN4aX)1Z#aH=@P-pt25Vz|4DCZ@d<7Y4JP&~W13j%O32U)x+^6|-I?74MGslZ@&cj)) zE#Cyc%P`NP*v}k+wf^m5jrFIAi0d9(8}5#=#;Vhr^m=`~@du+VmDX(wsjl=KaBP*C zfc}GZitW0%zHYb~zI!8dvMP{PtOm2ifhXAjDZQ+ncziSS>9fSoBAn z|4(!v%10lA|LGaWa1I{MqH(8#`xEXzsE#I{F-pJ3V+f*0A%|RA}#m;3w;Mc|5P5!mw7_NAq^#li5G#%mKvjWOrw=w?W7= z2J`wfo*vRu+s3hVhriHMUr$F&In%-RzJ+zW&vdp|@u0l$Cs;d3J@p&tXAAniSZ5u| z=Tpaw-Qd&qb{1===l((-Q6K9yVuQR0WFh%5-@I0&p`9+D2YsS%WBni~*AHl}Lw)bu z8grM_Nt>E4BOm8M>j}i`+!_(zs~8dS!){s|{uFyeK65yB%ehdWN%}!7O}_UC`lToz zw)!U7>iFr}n>S+Y5bHFmZw4JgP9D=@K6W;a?RBH=l^%&6a);S4vL|5^q`w~_wjut~ zF39fsdJqFg>p7nGp`>OjpQ7U5muCixT=B$T_y)z_>>rr<#dwlkjIHCq57$w9!x{%) z10R$hYqCiHV!YXR1bUKrqx8ZaxGnJhO0-Vs#eqLQ{?E|bRa+V8E0nHeq476}e&BVm zoCtg^rG3iBG^+35T9=^&aF849-oai z7Dmr6&dZxJv>eJSXoL^2(!>4^E1mOeX^(VmTCTm8>xf)4Cz@_~P2(WObZ$R}r2XI8 zhth+(8SWPAH0Q-}RyhM>O`^>se;P{Jyp@mN(yqtCuJ4QXO{%-u2f8yXIkffjD-p{g zJ{_2WXEE4|)fM$Mg02fOWe?;gKZ$)EyJ`Q&=g=w5F_ipjuAzKFKKLKUI3etw_It2) z4}3Xd+f|rfg^%6LRz(Wgs-8R8s$&n}Imx;o92RvEc5i6Wc|FD(A%_7!W?=7^8t(>u zJmM8wzomXS*k=dhfm4uK=8MM7F3}dzexTxK%6}PTeiieR51`YF;P+jq$K{ZJ3g#Rq z;@QIWh>eD!jn^+=?E_dRx()u^v8ue+hdn8N=4?akzp8|>dwsxNCTquf$SGR8#(t&t z53oexv?j@aI0y5)YuSXRr8t zpc88lcuoerq8^znt?KtEljb^4VgA*Eym*FPyaVeJlbZs)PeSf8)a&VFXB*WC?YOFi zrQW*(>t7zokNGZ_pY&*nC-@xI1^!fr#VAwh&`JZ@+coHo_DJbY#1PoeB*utKi)f5M zI@(06bE)-38heTlOl&J*X{U}ESXY<(6=@xZ)!3^Q zy{zvV&5D;pKPBl{$3x8a+-R0#IM(DbmO0&UT%V`$_74^XAU718Rsx;uK&+w}G+vA) zorfj?|0ysNx}kZ>2=GCJrM(PaokDpgv3fVkp!yTN=GcO>yk;Ase2Dg^B+E3cN#bnI z13#4a5U!QIB0t$8@1w+v_9vAXtlo?ADR#aMcG!sLHuMbPuj5$pTc}Sd+P7rqsCtI| zA`e5hk_q6CInYIj!%NDb1I(p9!gJ-4u2J=xw7K)-gr8FNrDwJ!JMk)a(TuzDBv z&sgLNv;Kjc$lJ7za%sbt*fZoyV#Ocm8GOHr7qVoQCD-?$Jg(0v$@LM;x2SKF0B0l@ z$+#f1-Ush_`t>X8a;*9;E<4Tq!*9WowRpL#qcb^@A>|%{rgAHK6>^Kdvo8tXr+;e+r zx-^CM|2E?OIrw8ye>Oex_Ko3f!1z7(HPZbS+!IeN8GLB%8SU5sENT;0`@ndv%K8Cl zG`2o^|2?`74yLc;Jfijy?*5;F93}hV&jva>k$xQdKZd^TM}PF-PuX_}>qeA59x)W1 zxy>YF&JF$Ywt-DD*jC8`>_J8QyiIWkZ{tgN9sS7TIX#e50{i!YPUG>E=pRdvHmH+K zPJb6Lp_5CwP8JE8YX#22REUkBn^)Ru9 zZ++&a^66q8!TS}hr$yH`;3sJRW@a1YkB#`aOux)4EvtLIW8FXVBZPp&wF19 zFIVwH{|x(}W7?a8J<-LOlkA=ZItTi$AAL6~P|{bh*w|Of%heOJFlJyJsG0{~Oa0t{ zFU-XLN*B^y)JBJJ4SlLu`PgsS^eo20nUNdA#o$YG29ks9=Q6Z2o$tiikG3woKwDpo zw%&oYEcpI<>}}*@gIX_?b>Pp3#5g0KGpoAsIUd%fP~Kr+A^4|jOwV`hw(DFzYyWf+p6%V^ zkn4l2J#F9G@R(QDhQ}TtzmK`*@Tfh&mImkjS+Hl)tBL)@s@;rNVBg564IkX2o)5Y? zSmX6!Pn)s>_kkPn>_F~!$9{Pi_H4AW1v6n|@MFB+P}$H!Fl;t?d)c9!HU=6t<<=uG z6uv%*zTHl?Mg2ncnV)=t=bhNkV8W-Vz8`q?#<2HAJg<38#2(&PY3+SX)ef|!kei;9 zjI9b3NYg1-2>7SyJ+{zc{e9%mo;qWr!x@GO6AZ8-mEdGFFgliFUz zer^xe%{-8M-XwFE7cxc?Ss3%ozGIH~-NzjxXf1)q9B*6fhsveD!S)pIZ%}*$T=})= z`x*j+ZD74FjmH7lA5z~viWUDJV^-!N z#6(zo%k0wX-IrodAbj1!E^0gSTfr2R5sG9mS`P`mg))DKcAV3!)!&kV^B%1}axv-v ze2%Hrcj3AR*L)2cybq3tzr#Ksip_kuCf+|xr}$3jns|1Dp77rz2BUjx8Y;%qJ{l|1 zo~8Q)R=-@_^Y$Vi6&Zs)a5AP<`6HN*5kLLx+DANy$1|PgC+_6nR#(60h|8(98E6Aa z$GY(D2;PSQpS&QRyZ7Ol!sm{0yXk!zW#f%H)*CQ>8i;Esc3JhBH<#`w$om!YK3(1i zCXdN}D~{#8JrX`4JuUmqPcn0r99{hb*Y-^` z`w)}lVc`aAUShq3fJEot%Cr{-mm-@R1Z7=e$_S7b_kHmIm zFD#98!PgzI$4SijjF0(qRi$r?X<{9!MQ3Mbu#TtK_#=9^j($USmSJlFMMZzI|X`^$Vy2KN26WFziE zA8MH?_WiZgz^-9;a(`BI-yc2KrLssr>tNR|Zrg+706nArrgYj*_D$)Bk*?~6dT>2a zSx;V|ESjTcqTlpDPS8f}-TEGwcevW8B-ZeWC-ra1J1-Oc?(2wl!fwqz#5H~JTj$kR@PXZ--Qn)@RJ(b_T2LrB((LQ*8`!J*ly#mAV;izxlVaeg z?Z~==KdoEA9z^V8{AsBDsD9PJ^(Nk(qkc#E&aHWV$l5Z^*M)o(C&5;3Cc5BZ@7LJ> z7-aQlzrQ^L&jjitIAiR}ZuwHHe+WKG)Din(hE1FGsb9;Ri819f%tIxwaL=$Q=vrjQ zX1G;Lo=LVdZx8Y%L*}j>pRh?swi)W;@utCf4jNZ+f>R} zvbhuQOt8$id;H{QL|?!z5D#5#!Mx0vITbN7&Fw)K%EDPMq*#;B+tC-`XS>9@dbC`Or=DRn zw&)2+pKf4Gz1PXoBJdHZY=(+I==~X4HewOTsY71HBZ9rjS0i?hRhE!B*4T};z=uQ| zBEAh5qHNO7Da1Fl9v98K@5L~~90X%|k>2FmN9#2rO{|rvSX)Or#pvpu_OE#mo6>$_ z#Y@j|_qj3VXgOLR=_9owD;ML+!j>=Lv*zGAP|*DHiU(P-><1f3E|oWPua0*X+M;GsAoO&7llWg&GjAP%1Uenpfk6>@gBdYH;V()c2 z^s9JL{f*y@$jkdzt)1$rvGle%@$BE(w9c)*+dbilc+TX%T@U+SgFPkbVN=E`W$_DE zcfpr^2X*sepSBmzCaL^V_~ikN!N;)Yoz^`gj*EArJ|TMdw1i!JN`t?GjUA@X6{mi}C$NQOkr|1iUAL51}#j#iyXziUv{wfZ3pwgiK`j8%^HHVD=qivzV4qYs* zkiix=oxxrdjMKkz{C)XabqWwd}tr(lQQ9tC~ZPCP0ZEpHcPSxvG3wf+K5ubj^=WAWr%=zWg+^bmD`K*-=^MG!wiP8MP zz}h6~K-68vW*3N6NBbK1dzJG-%=ffx59IRxa&7o$uxr8}(8Zb^?U}4X zpCBC_kuuPF1JR={qv3mscF4Z)x=g3}ZVP0jy@IMusJ~M=H1<%Qkj(RFeIMXP_P z{D(^}Ts{V&X!${@kDR}UH`=lE`X*hY4;D7c zzM5*`VfUx4=+jE~!zBIiDE*+$Tqu`8XH`;XUu!~VX=wWa?7PF9t^T6BM9e|`1c48q zCwwO2jE!S)|2F#Wkp#0HoiELM_x-EblJpes-8Za~<-^}0F2lOd@5HU3`2Qem#|^=3lUa<`5EXofX*{d zTlg|)vF~J@xzU2x0SEmC;2Ppti+r#J7CH`jT9HPvAoT@2{~he7cn;~6{r;XP&f1;m zOEg#b^Z~7%_8G(Hj;7eqL*v`9!8LL66B_nhs@R42-xB3x=9#bKTLl;JNx<6EFivVs z9%ZL|9MzckrUv{Ke-=SwW$phAbaG#VvZmsi%9zH>2o~ka`>SwoAU#LkPr-fWD_D#B zZS+|ol@scIRjdgaNT>N^%cWX9u8XmEyxwJfFZxZ2-!A6y+m+~Nq7JA#;Vff1#dVW` z6OSQ#zzne-W?+w%^0`?jUPK<9zP*BV0--|>r_(WHihDfEZDXc8Y}8$!N9{BcylMSK z@sK)1dz!pWiDsBAzvUR7siF-DBRcq|F!q5)+xRTrwIhFZ8}`#;E*SM8&*K@-D9~Zu z3Gd>;-ue7uT=q|3FSOsg3o!uJrm7OLW{Nc>+@o$7FX5xAvaz3*(m$2FPh%cJYiKS! z$0ix5{YW0{kxrw1S5|C4$1;XsF94%>=T-Q7%C`^qjX&48PsLn|^ZFh56CeDwH$KT0 zrk=PFdcB12KcqZAK^~P(V>>$}#<>V|BVrXXHo}4NGM)v$EZEH8emygM0&x=Y`We#5 zo^mmM&^`6>C~w<*meQZJrc>E+jFn|a$A-IQ*_$n8=gBhKqddNOUQFeE543;9yaO_Y z=#Mb!$Lc2I*&VHyKXinaSmdi zD-k!Vyc){fL32u^Q`%KXgCX(t{|68YuR~m{`XT&W_Hm5w9iQA7ehF*n474hZ=2GY* zi7xP=c#7WjQDxw{2I8ePc`l5h8oNGE%GlR)GwD%0y9|yK>y@+ydT!0{_`5Qo3(0z29@i_tJL2x^TURm}JY-P)K4m0_@IupK3)m4=p{A6vI_Ct8@LtG7hrT6JP zexDD&OZ8a+o^+;uO8meBcBCzw^Cs3>H>&Xsz8UK?K8o4oI;dCI7h*3#{T0Q7G-=iD zzPGXNsa3eKKW}Us?DUi$<6q>9mY<_dPkByZ4@_^%5ha@sd%nGL&$t)+z!gr|G1wHX zwW9t)FL>ra@1NgSqxE5L0hjqEc`lG=k37?!3I0AtbiI1${$ASOhxhpDc?Qjk`16e( z?CaIA*7Xu%yLS;ica}B@Yhaj1Iyc<5+KqK2dIv5W?S%Ku z67h|=D%$%*`$x=kvu1U_)|gB0`JHuKoP8AU&++&D@Vz^hUb1=@#zu|l3+JFM=y?O} zH|OsJI>u*@1-}U1nM=c&_Bk<@QKZsF0i*YNt+FY7^jP*8Gwi1(zhvKMO!}bxkybq+ zKb{Q?zVjvcVSZBgKv-w%4||y7b=6;7%+bcG^SM8!b@MKaqqO(KN;*E1_cJb#N^o)h};e84DXkWOfm$aMbh27jaQhZB;^zjweR4+Dyhd+JF(SG)+ zVbSkr4vV&w3Frp4yN8*@OIaKL>jP={{1EAJ+QW zX!Ox~*E7KkS94q{_J3A6@ZA6p{z?nh-K|f2d8-Tccxtt;*U$9bPpx+K`f*)~>rz|~ zgA8h)Hr9RV9fRErewXC⪙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 SJiCYw6+L;$+J$2Qu zk&0T>JSRwrSEI0;pkbRFrE!Cl7^);*trR(p@~S?h)TC0?(tcZnAz)sLX;O*Xp^ zg3ULpY52X(52%lg{$%qSrDCJG_y^R6ue^Q1`5>&@^1B<;m(=b!^HKG!H$PtTEz?2` zXVdV%wp_D$M@ip~<(nJMUV-g)KX%OhpDW33#LwTu&)+Lq4}Y^I5q$%za>Yj*elWM@ zime`Y&%^M-md~p{f%~q0Ox-d1&ecC&7yKP2){0>jVp3`U&5EXG{^{u4b!RTYCVaN; zZnX;%+kLff^rr1!P^uCpZ@focG8*jofLdGr){1^=bWiUMZ%&z&j>AG&MD#;e~jLC>tI z`1Zt~tFr~ndlO{u`nb9jUcYO{wP#hPWp}8vBPjbNeE4o(y$YYa`)XAf z{o>tEu7{?3`k~>WOW^5`T?S7)RF0oZVc}zC;pfP`X_&t!uBTHfQuli+SZ(WA!GkUp z%YOgA;iIK3Cl#dctsd>W_m8d~Ri9lc!G2Xeo78tk<2~~w>Kv>)^d9x8(f1wtL`3D` zi-&har%Q~(r?4nN@8=+Q*bnxV8)^9(Q~s1`E2uB|K@2;VjxkQ=Rs2l0(~v}Z0Ou+l z!|eGSekNK88Kj+8h0u#Iy#jp@JqTH(!@<7Kq8}ZCqQ$E3TKctXW>@d=9rXx&`jCMTy*qW`6 zU{#d2jvag60Dl6O%XPd2w!n>vzYfLg&#U9o8Xn(dd3-br?~14z82s8cRUFNI?V6I{ zbe+)=-Rg+vy&Hp`gXq_NRRPz2eH)JKkA3~I5;Xv42ezqpxOVUlRTX@3a9fbyWsJE` zy-k-H<7LPV`X!|e@SlU%2NNlyRL3K&@w`&<8{1SjWbk|%vfuE7I$Y)HXb8`q_b_XA z!X(lYOskm=Fr9^^Z}@6?blo>Ku4^!O>|xai$;bVmNd_Vtd=FbDiUXnrGLLVpEcJ@m zEOcOv!{bLGFZH}N@W|u8uU>)NKY`eH8%O`(yDzKYK6Xt7jYm2*VtL=_eJ4I13Gx+2RE<@kgAgT^AI*)Q zQMY75p*bDoZY334-pz8FWtXGs1eSCh0`;W-$deJ6da_&{hUAkz)IJ$WiCQD89kJY! zxybt+w?)=J3YjOL4O9&-43 zZzyRBCHoa?tikoYHDPQoVh!e!H@F=$3w!;~U^+Olng9;ADjQv2W>IDg<0h%{~4+I`v% zb4a@#+c;Yvg6K(H0xjFmo%ic`MKssi54nOjo9f!e_zB)-d>J;Qq zbK3I5D@_y z_WT-#9MTg^CFcTWN5=%HDL**LRB9?SYYLK6K5dBbT!0K}p0+fp-@7^gdB`GNbZ8g? zPs=cgv@~k2Wk!f?1eTCiI8qM0Ca~Kk+eqNIc_1(=(B%)Jz@|aU4H` zyCuu(1D4liD;G*bcCba3lQ&x)ff0;Tz&M+bP=CkS8$LWegL_4O&~#g{2BQBD=RQ*z z;k{h*21p^@>(D-?c=tit$&}jVn;eshLokT6mnr3IkHUG#AzfhlUZz!8(h&hQ;|FE< zYKjim7I%P1_pL(lK?i9sQ_AW~#!Yy}UEhrVU>{R=ojk#EYKIK!%fs3j%c*T``NS&v zCs)xwW#n+pv(aGIvZa=3<7m6_}D_HF<=kRG$BJ-&uu5b1F%?x(D{3t^^< zlpC(K>Un&*z?w22YB@>-l1R(A$=!K`uRNajq3`(%^C-f0RgguyI<|9bRu7ZU`}kb8 zgy&&82NSGGEi`0hIs=KkuS#JA&y~=e_k%8cMM?*0e#d+a&lAv-_hC4HA(v{-Wh%6u z4bQk%qK|p@;f~=VL|?!=3qLtiga@n$wUBzjhxQjPL=adH9Y_X{xbwUL2GQdo_UN`l zFXWJpF_n2P<9i&`Pw~0+r;(^jmWc$h_n7!HGU~a$*egh@nNlr|OQKlTLl)^yrfxh{k`$RI6$uQ8CUS~#l;$iC>~TcEk0 z(`=c<&vA(Uf_6Yl__+>xP~HNGpJNZR2iJcqG^5U;P`{V-gJIUBI{vMd=Sdj(Ij(a* z|LxguisD20FYxWli{)yDG6)u|jHwT3C81*xQb^BPG3>U8LkH5@O-5H{K`qq^HB9BcD)Z(*NZVJT_)I+K2YIIMiiLNcIoiMF{+;%3 zBdA#sH-TkrNE$dQkj9x(hV~s{Cq)0<5B4*4M@1S^NZXl8KS=(a(1CPl72D&XZNZ8= z>RmYSPK24`od|1zJBXKX2azz;t?99l4y{6GA@h=-TwqGIvwO$eVtl&wDuw8O&@0W! zmuS{BpQd~G66R3D`m&mLal(y|K%J≥?@wY1X7Rx$i=?yjJKzdSDgW9@0Lhl6Nlvx=Q2` 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