X-Git-Url: https://git.danieliu.xyz/?a=blobdiff_plain;f=st.c;h=504239ea6ac121ec512a4e738e72b916a828015e;hb=88d8293fb4ba150a5f19d58d133b5db93d9dcfa5;hp=839dc94db7621e4bbc9d29b2792ebfb0515a625f;hpb=dbe8676d7d69651132bde2b6d9ec3787cbbc552a;p=st.git diff --git a/st.c b/st.c index 839dc94..504239e 100644 --- a/st.c +++ b/st.c @@ -21,13 +21,8 @@ #include #include #include -#include #include -/* X11 */ -#include -#include - #include "st.h" #include "win.h" @@ -47,8 +42,8 @@ #define STR_ARG_SIZ ESC_ARG_SIZ /* macros */ +#define IS_SET(flag) ((term.mode & (flag)) != 0) #define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) -#define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) @@ -57,6 +52,17 @@ /* constants */ #define ISO14755CMD "dmenu -w \"$WINDOWID\" -p codepoint: pw_shell[0]) ? pw->pw_shell : shell; - if (opt_cmd) - prog = opt_cmd[0]; + if (args) + prog = args[0]; else if (utmp) prog = utmp; else prog = sh; - args = (opt_cmd) ? opt_cmd : (char *[]) {prog, NULL}; + DEFAULT(args, ((char *[]) {prog, NULL})); unsetenv("COLUMNS"); unsetenv("LINES"); @@ -705,7 +702,7 @@ sigchld(int a) void -stty(void) +stty(char **args) { char cmd[_POSIX_ARG_MAX], **p, *q, *s; size_t n, siz; @@ -715,7 +712,7 @@ stty(void) memcpy(cmd, stty_args, n); q = cmd + n; siz = sizeof(cmd) - n; - for (p = opt_cmd; p && (s = *p); ++p) { + for (p = args; p && (s = *p); ++p) { if ((n = strlen(s)) > siz-1) die("stty parameter length too long\n"); *q++ = ' '; @@ -729,31 +726,30 @@ stty(void) } void -ttynew(void) +ttynew(char *line, char *out, char **args) { int m, s; - struct winsize w = {term.row, term.col, 0, 0}; - if (opt_io) { + if (out) { term.mode |= MODE_PRINT; - iofd = (!strcmp(opt_io, "-")) ? - 1 : open(opt_io, O_WRONLY | O_CREAT, 0666); + iofd = (!strcmp(out, "-")) ? + 1 : open(out, O_WRONLY | O_CREAT, 0666); if (iofd < 0) { fprintf(stderr, "Error opening %s:%s\n", - opt_io, strerror(errno)); + out, strerror(errno)); } } - if (opt_line) { - if ((cmdfd = open(opt_line, O_RDWR)) < 0) + if (line) { + if ((cmdfd = open(line, O_RDWR)) < 0) die("open line failed: %s\n", strerror(errno)); dup2(cmdfd, 0); - stty(); + stty(args); return; } /* seems to work fine on linux, openbsd and freebsd */ - if (openpty(&m, &s, NULL, NULL, &w) < 0) + if (openpty(&m, &s, NULL, NULL, NULL) < 0) die("openpty failed: %s\n", strerror(errno)); switch (pid = fork()) { @@ -770,7 +766,7 @@ ttynew(void) die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); close(s); close(m); - execsh(); + execsh(args); break; default: close(s); @@ -785,44 +781,53 @@ ttyread(void) { static char buf[BUFSIZ]; static int buflen = 0; - char *ptr; - int charsize; /* size of utf8 char in bytes */ - Rune unicodep; + int written; int ret; /* append read bytes to unprocessed bytes */ if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0) die("Couldn't read from shell: %s\n", strerror(errno)); - buflen += ret; - ptr = buf; - for (;;) { - if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) { - /* process a complete utf8 char */ - charsize = utf8decode(ptr, &unicodep, buflen); - if (charsize == 0) - break; - tputc(unicodep); - ptr += charsize; - buflen -= charsize; - - } else { - if (buflen <= 0) - break; - tputc(*ptr++ & 0xFF); - buflen--; - } - } + written = twrite(buf, buflen, 0); + buflen -= written; /* keep any uncomplete utf8 char for the next call */ if (buflen > 0) - memmove(buf, ptr, buflen); + memmove(buf, buf + written, buflen); return ret; } void -ttywrite(const char *s, size_t n) +ttywrite(const char *s, size_t n, int may_echo) +{ + const char *next; + + 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; @@ -878,32 +883,6 @@ write_error: die("write error on tty: %s\n", strerror(errno)); } -void -ttysend(char *s, size_t n) -{ - int len; - char *t, *lim; - Rune u; - - ttywrite(s, n); - if (!IS_SET(MODE_ECHO)) - return; - - lim = &s[n]; - for (t = s; t < lim; t += len) { - if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) { - len = utf8decode(t, &u, n); - } else { - u = *t & 0xFF; - len = 1; - } - if (len <= 0) - break; - techo(u); - n -= len; - } -} - void ttyresize(int tw, int th) { @@ -1012,8 +991,6 @@ tnew(int col, int row) { term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } }; tresize(col, row); - term.numlock = 1; - treset(); } @@ -1449,20 +1426,16 @@ tsetscroll(int t, int b) void tsetmode(int priv, int set, int *args, int narg) { - int *lim, mode; - int alt; + int alt, *lim; for (lim = args + narg; args < lim; ++args) { if (priv) { switch (*args) { case 1: /* DECCKM -- Cursor key */ - MODBIT(term.mode, set, MODE_APPCURSOR); + xsetmode(set, MODE_APPCURSOR); break; case 5: /* DECSCNM -- Reverse video */ - mode = term.mode; - MODBIT(term.mode, set, MODE_REVERSE); - if (mode != term.mode) - redraw(); + xsetmode(set, MODE_REVERSE); break; case 6: /* DECOM -- Origin */ MODBIT(term.c.state, set, CURSOR_ORIGIN); @@ -1482,36 +1455,36 @@ tsetmode(int priv, int set, int *args, int narg) case 12: /* att610 -- Start blinking cursor (IGNORED) */ break; case 25: /* DECTCEM -- Text Cursor Enable Mode */ - MODBIT(term.mode, !set, MODE_HIDE); + xsetmode(!set, MODE_HIDE); break; case 9: /* X10 mouse compatibility mode */ xsetpointermotion(0); - MODBIT(term.mode, 0, MODE_MOUSE); - MODBIT(term.mode, set, MODE_MOUSEX10); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEX10); break; case 1000: /* 1000: report button press */ xsetpointermotion(0); - MODBIT(term.mode, 0, MODE_MOUSE); - MODBIT(term.mode, set, MODE_MOUSEBTN); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEBTN); break; case 1002: /* 1002: report motion on button press */ xsetpointermotion(0); - MODBIT(term.mode, 0, MODE_MOUSE); - MODBIT(term.mode, set, MODE_MOUSEMOTION); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEMOTION); break; case 1003: /* 1003: enable all mouse motions */ xsetpointermotion(set); - MODBIT(term.mode, 0, MODE_MOUSE); - MODBIT(term.mode, set, MODE_MOUSEMANY); + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEMANY); break; case 1004: /* 1004: send focus events to tty */ - MODBIT(term.mode, set, MODE_FOCUS); + xsetmode(set, MODE_FOCUS); break; case 1006: /* 1006: extended reporting mode */ - MODBIT(term.mode, set, MODE_MOUSESGR); + xsetmode(set, MODE_MOUSESGR); break; case 1034: - MODBIT(term.mode, set, MODE_8BIT); + xsetmode(set, MODE_8BIT); break; case 1049: /* swap screen & set/restore cursor as xterm */ if (!allowaltscreen) @@ -1536,7 +1509,7 @@ tsetmode(int priv, int set, int *args, int narg) tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); break; case 2004: /* 2004: bracketed paste mode */ - MODBIT(term.mode, set, MODE_BRCKTPASTE); + xsetmode(set, MODE_BRCKTPASTE); break; /* Not implemented mouse modes. See comments there. */ case 1001: /* mouse highlight mode; can hang the @@ -1557,8 +1530,8 @@ tsetmode(int priv, int set, int *args, int narg) switch (*args) { case 0: /* Error (IGNORED) */ break; - case 2: /* KAM -- keyboard action */ - MODBIT(term.mode, set, MODE_KBDLOCK); + case 2: + xsetmode(set, MODE_KBDLOCK); break; case 4: /* IRM -- Insertion-replacement */ MODBIT(term.mode, set, MODE_INSERT); @@ -1626,7 +1599,7 @@ csihandle(void) break; case 'c': /* DA -- Device Attributes */ if (csiescseq.arg[0] == 0) - ttywrite(vtiden, sizeof(vtiden) - 1); + ttywrite(vtiden, strlen(vtiden), 0); break; case 'C': /* CUF -- Cursor Forward */ case 'a': /* HPR -- Cursor Forward */ @@ -1754,7 +1727,7 @@ csihandle(void) if (csiescseq.arg[0] == 6) { len = snprintf(buf, sizeof(buf),"\033[%i;%iR", term.c.y+1, term.c.x+1); - ttywrite(buf, len); + ttywrite(buf, len, 0); } break; case 'r': /* DECSTBM -- Set Scrolling Region */ @@ -1776,11 +1749,8 @@ csihandle(void) case ' ': switch (csiescseq.mode[1]) { case 'q': /* DECSCUSR -- Set Cursor Style */ - DEFAULT(csiescseq.arg[0], 1); - if (!BETWEEN(csiescseq.arg[0], 0, 6)) { + if (xsetcursor(csiescseq.arg[0])) goto unknown; - } - win.cursor = csiescseq.arg[0]; break; default: goto unknown; @@ -1844,8 +1814,8 @@ strhandle(void) dec = base64dec(strescseq.args[2]); if (dec) { - xsetsel(dec, CurrentTime); - clipcopy(NULL); + xsetsel(dec); + xclipcopy(); } else { fprintf(stderr, "erresc: invalid base64\n"); } @@ -1950,8 +1920,7 @@ void tprinter(char *s, size_t len) { if (iofd != -1 && xwrite(iofd, s, len) < 0) { - fprintf(stderr, "Error writing in %s:%s\n", - opt_io, strerror(errno)); + perror("Error writing to output file"); close(iofd); iofd = -1; } @@ -1976,7 +1945,7 @@ iso14755(const Arg *arg) (*e != '\n' && *e != '\0')) return; - ttysend(uc, utf8encode(utf32, uc)); + ttywrite(uc, utf8encode(utf32, uc), 1); } void @@ -2049,22 +2018,6 @@ tputtab(int n) term.c.x = LIMIT(x, 0, term.col-1); } -void -techo(Rune u) -{ - if (ISCONTROL(u)) { /* control code */ - if (u & 0x80) { - u &= 0x7f; - tputc('^'); - tputc('['); - } else if (u != '\n' && u != '\r' && u != '\t') { - u ^= 0x40; - tputc('^'); - } - } - tputc(u); -} - void tdefutf8(char ascii) { @@ -2205,7 +2158,7 @@ tcontrolcode(uchar ascii) case 0x99: /* TODO: SGCI */ break; case 0x9a: /* DECID -- Identify Terminal */ - ttywrite(vtiden, sizeof(vtiden) - 1); + ttywrite(vtiden, strlen(vtiden), 0); break; case 0x9b: /* TODO: CSI */ case 0x9c: /* TODO: ST */ @@ -2277,7 +2230,7 @@ eschandle(uchar ascii) } break; case 'Z': /* DECID -- Identify Terminal */ - ttywrite(vtiden, sizeof(vtiden) - 1); + ttywrite(vtiden, strlen(vtiden), 0); break; case 'c': /* RIS -- Reset to inital state */ treset(); @@ -2285,10 +2238,10 @@ eschandle(uchar ascii) xloadcols(); break; case '=': /* DECPAM -- Application keypad */ - term.mode |= MODE_APPKEYPAD; + xsetmode(1, MODE_APPKEYPAD); break; case '>': /* DECPNM -- Normal keypad */ - term.mode &= ~MODE_APPKEYPAD; + xsetmode(0, MODE_APPKEYPAD); break; case '7': /* DECSC -- Save Cursor */ tcursor(CURSOR_SAVE); @@ -2455,6 +2408,38 @@ check_control_code: } } +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) && !IS_SET(MODE_SIXEL)) { + /* 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) { @@ -2540,64 +2525,35 @@ tresize(int col, int row) void resettitle(void) { - xsettitle(opt_title ? opt_title : "st"); + xsettitle(NULL); } void -redraw(void) +drawregion(int x1, int y1, int x2, int y2) { - tfulldirt(); - draw(); -} + int y; + for (y = y1; y < y2; y++) { + if (!term.dirty[y]) + continue; -int -match(uint mask, uint state) -{ - return mask == XK_ANY_MOD || mask == (state & ~ignoremod); + term.dirty[y] = 0; + xdrawline(term.line[y], x1, y, x2); + } } void -numlock(const Arg *dummy) +draw(void) { - term.numlock ^= 1; + if (!xstartdraw()) + return; + drawregion(0, 0, term.col, term.row); + xdrawcursor(); + xfinishdraw(); } -char* -kmap(KeySym k, uint state) +void +redraw(void) { - Key *kp; - int i; - - /* Check for mapped keys out of X11 function keys. */ - for (i = 0; i < LEN(mappedkeys); i++) { - if (mappedkeys[i] == k) - break; - } - if (i == LEN(mappedkeys)) { - if ((k & 0xFFFF) < 0xFD00) - return NULL; - } - - for (kp = key; kp < key + LEN(key); kp++) { - if (kp->k != k) - continue; - - if (!match(kp->mask, state)) - continue; - - if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0) - continue; - if (term.numlock && kp->appkey == 2) - continue; - - if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0) - continue; - - if (IS_SET(MODE_CRLF) ? kp->crlf < 0 : kp->crlf > 0) - continue; - - return kp->s; - } - - return NULL; + tfulldirt(); + draw(); }