X-Git-Url: https://git.danieliu.xyz/?p=st.git;a=blobdiff_plain;f=st.c;h=cf8687e519209aebe265bf09c3fbc35df5c97501;hp=3ebf8c6947e69086dfb51541600d5320f8ce7466;hb=e85b6b64660214121164ea97fb098eaa4935f7db;hpb=33201ac65f74e45b4fa60822ba9a538c3cfa9b25 diff --git a/st.c b/st.c index 3ebf8c6..cf8687e 100644 --- a/st.c +++ b/st.c @@ -3,24 +3,18 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include -#include -#include #include #include #include -#include #include -#include #include #include "st.h" @@ -36,20 +30,29 @@ /* 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 /* macros */ -#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) +#define IS_SET(flag) ((term.mode & (flag)) != 0) #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) #define ISDELIM(u) (utf8strchr(worddelimiters, u) != NULL) -/* constants */ -#define ISO14755CMD "dmenu -w \"$WINDOWID\" -p codepoint: ] [;]] []] */ typedef struct { @@ -104,8 +152,7 @@ typedef struct { int narg; /* nb of args */ } STREscape; - -static void execsh(char **); +static void execsh(char *, char **); static void stty(char **); static void sigchld(int); static void ttywriteraw(const char *, size_t); @@ -154,28 +201,31 @@ static int32_t tdefcolor(int *, int *, int); static void tdeftran(char); static void tstrsequence(uchar); +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 char *utf8strchr(char *s, Rune u); +static char *utf8strchr(char *, Rune); 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 */ -Term term; -int cmdfd; -pid_t pid; -int oldbutton = 3; /* button event on startup: 3 = release */ - +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}; @@ -202,10 +252,10 @@ xwrite(int fd, const char *s, size_t len) void * xmalloc(size_t len) { - void *p = malloc(len); + void *p; - if (!p) - die("Out of memory\n"); + if (!(p = malloc(len))) + die("malloc: %s\n", strerror(errno)); return p; } @@ -214,7 +264,7 @@ void * xrealloc(void *p, size_t len) { if ((p = realloc(p, len)) == NULL) - die("Out of memory\n"); + die("realloc: %s\n", strerror(errno)); return p; } @@ -223,7 +273,7 @@ char * xstrdup(char *s) { if ((s = strdup(s)) == NULL) - die("Out of memory\n"); + die("strdup: %s\n", strerror(errno)); return s; } @@ -392,6 +442,7 @@ 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; @@ -407,7 +458,7 @@ selextend(int col, int row, int type, int done) { int oldey, oldex, oldsby, oldsey, oldtype; - if (!sel.mode) + if (sel.mode == SEL_IDLE) return; if (done && sel.mode == SEL_EMPTY) { selclear(); @@ -420,7 +471,6 @@ selextend(int col, int row, int type, int done) oldsey = sel.ne.y; oldtype = sel.type; - sel.alt = IS_SET(MODE_ALTSCREEN); sel.oe.x = col; sel.oe.y = row; selnormalize(); @@ -625,7 +675,7 @@ die(const char *errstr, ...) } void -execsh(char **args) +execsh(char *cmd, char **args) { char *sh, *prog; const struct passwd *pw; @@ -633,13 +683,13 @@ execsh(char **args) errno = 0; if ((pw = getpwuid(getuid())) == NULL) { if (errno) - die("getpwuid:%s\n", strerror(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 : shell; + sh = (pw->pw_shell[0]) ? pw->pw_shell : cmd; if (args) prog = args[0]; @@ -676,17 +726,18 @@ sigchld(int a) pid_t p; if ((p = waitpid(pid, &stat, WNOHANG)) < 0) - die("Waiting for pid %hd failed: %s\n", pid, strerror(errno)); + die("waiting for pid %hd failed: %s\n", pid, strerror(errno)); if (pid != p) return; - if (!WIFEXITED(stat) || WEXITSTATUS(stat)) - die("child finished with error '%d'\n", stat); + 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) { @@ -708,11 +759,11 @@ stty(char **args) } *q = '\0'; if (system(cmd) != 0) - perror("Couldn't call stty"); + perror("Couldn't call stty"); } -void -ttynew(char *line, char *out, char **args) +int +ttynew(char *line, char *cmd, char *out, char **args) { int m, s; @@ -728,10 +779,11 @@ ttynew(char *line, char *out, char **args) if (line) { if ((cmdfd = open(line, O_RDWR)) < 0) - die("open line failed: %s\n", strerror(errno)); + die("open line '%s' failed: %s\n", + line, strerror(errno)); dup2(cmdfd, 0); stty(args); - return; + return cmdfd; } /* seems to work fine on linux, openbsd and freebsd */ @@ -740,7 +792,7 @@ ttynew(char *line, char *out, char **args) switch (pid = fork()) { case -1: - die("fork failed\n"); + die("fork failed: %s\n", strerror(errno)); break; case 0: close(iofd); @@ -752,14 +804,23 @@ ttynew(char *line, char *out, char **args) die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); close(s); close(m); - execsh(args); +#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 @@ -772,7 +833,7 @@ ttyread(void) /* 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)); + die("couldn't read from shell: %s\n", strerror(errno)); buflen += ret; written = twrite(buf, buflen, 0); @@ -882,6 +943,13 @@ ttyresize(int tw, int th) fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno)); } +void +ttyhangup() +{ + /* Send SIGHUP to shell */ + kill(pid, SIGHUP); +} + int tattrset(int attr) { @@ -977,8 +1045,6 @@ tnew(int col, int row) { term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } }; tresize(col, row); - term.numlock = 1; - treset(); } @@ -1388,7 +1454,8 @@ tsetattr(int *attr, int l) } else { fprintf(stderr, "erresc(default): gfx attr %d unknown\n", - attr[i]), csidump(); + attr[i]); + csidump(); } break; } @@ -1414,20 +1481,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); @@ -1447,36 +1510,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) @@ -1501,7 +1564,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 @@ -1522,8 +1585,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); @@ -1638,7 +1701,6 @@ csihandle(void) tputtab(csiescseq.arg[0]); break; case 'J': /* ED -- Clear screen */ - selclear(); switch (csiescseq.arg[0]) { case 0: /* below */ tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); @@ -1918,28 +1980,6 @@ tprinter(char *s, size_t len) } } -void -iso14755(const Arg *arg) -{ - FILE *p; - char *us, *e, codepoint[9], uc[UTF_SIZ]; - unsigned long utf32; - - if (!(p = popen(ISO14755CMD, "r"))) - return; - - us = fgets(codepoint, sizeof(codepoint), p); - pclose(p); - - if (!us || *us == '\0' || *us == '-' || strlen(us) > 7) - return; - if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX || - (*e != '\n' && *e != '\0')) - return; - - ttywrite(uc, utf8encode(utf32, uc), 1); -} - void toggleprinter(const Arg *arg) { @@ -2224,16 +2264,16 @@ eschandle(uchar ascii) case 'Z': /* DECID -- Identify Terminal */ ttywrite(vtiden, strlen(vtiden), 0); break; - case 'c': /* RIS -- Reset to inital state */ + case 'c': /* RIS -- Reset to initial state */ treset(); resettitle(); 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); @@ -2521,14 +2561,45 @@ resettitle(void) } 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; + + term.dirty[y] = 0; + xdrawline(term.line[y], x1, y, x2); + } +} + +void +draw(void) +{ + int cx = term.c.x; + + 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); + 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(); + xximspot(term.ocx, term.ocy); } void -numlock(const Arg *dummy) +redraw(void) { - term.numlock ^= 1; + tfulldirt(); + draw(); }