X-Git-Url: https://git.xinqibao.xyz/st.git/blobdiff_plain/8dacdfbab1c476063a31bc3b8d7222ac2b70ff66..d84f3f4bd15e7d65fc0334cf7d62913c901bad00:/st.c

diff --git a/st.c b/st.c
index ae93ade..dae7b91 100644
--- a/st.c
+++ b/st.c
@@ -21,20 +21,10 @@
 #include <time.h>
 #include <unistd.h>
 #include <libgen.h>
-#include <fontconfig/fontconfig.h>
 #include <wchar.h>
 
-/* X11 */
-#include <X11/cursorfont.h>
-#include <X11/Xft/Xft.h>
-
-char *argv0;
-
-#define Glyph Glyph_
-#define Font Font_
-
-#include "win.h"
 #include "st.h"
+#include "win.h"
 
 #if   defined(__linux)
  #include <pty.h>
@@ -53,14 +43,13 @@ char *argv0;
 
 /* macros */
 #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))
 #define ISDELIM(u)		(utf8strchr(worddelimiters, u) != NULL)
 
 /* constants */
-#define ISO14755CMD		"dmenu -w %lu -p codepoint: </dev/null"
+#define ISO14755CMD		"dmenu -w \"$WINDOWID\" -p codepoint: </dev/null"
 
 enum cursor_movement {
 	CURSOR_SAVE,
@@ -115,35 +104,9 @@ typedef struct {
 	int narg;              /* nb of args */
 } STREscape;
 
-typedef struct {
-	KeySym k;
-	uint mask;
-	char *s;
-	/* three valued logic variables: 0 indifferent, 1 on, -1 off */
-	signed char appkey;    /* application keypad */
-	signed char appcursor; /* application cursor */
-	signed char crlf;      /* crlf mode          */
-} Key;
-
-/* function definitions used in config.h */
-static void clipcopy(const Arg *);
-static void clippaste(const Arg *);
-static void numlock(const Arg *);
-static void selpaste(const Arg *);
-static void zoom(const Arg *);
-static void zoomabs(const Arg *);
-static void zoomreset(const Arg *);
-static void printsel(const Arg *);
-static void printscreen(const Arg *) ;
-static void iso14755(const Arg *);
-static void toggleprinter(const Arg *);
-static void sendbreak(const Arg *);
-
-/* config.h for applying patches and the configuration. */
-#include "config.h"
-
-static void execsh(void);
-static void stty(void);
+
+static void execsh(char **);
+static void stty(char **);
 static void sigchld(int);
 
 static void csidump(void);
@@ -173,7 +136,6 @@ static void tnewline(int);
 static void tputtab(int);
 static void tputc(Rune);
 static void treset(void);
-static void tresize(int, int);
 static void tscrollup(int, int);
 static void tscrolldown(int, int);
 static void tsetattr(int *, int);
@@ -181,8 +143,8 @@ static void tsetchar(Rune, Glyph *, 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 tfulldirt(void);
-static void techo(Rune);
 static void tcontrolcode(uchar );
 static void tdectest(char );
 static void tdefutf8(char);
@@ -201,43 +163,23 @@ static size_t utf8validate(Rune *, size_t);
 static char *base64dec(const char *);
 
 static ssize_t xwrite(int, const char *, size_t);
-static void *xrealloc(void *, size_t);
 
 /* Globals */
-TermWindow win;
 Term term;
 Selection sel;
 int cmdfd;
 pid_t pid;
-char **opt_cmd  = NULL;
-char *opt_class = NULL;
-char *opt_embed = NULL;
-char *opt_font  = NULL;
-char *opt_io    = NULL;
-char *opt_line  = NULL;
-char *opt_name  = NULL;
-char *opt_title = NULL;
 int oldbutton   = 3; /* button event on startup: 3 = release */
 
 static CSIEscape csiescseq;
 static STREscape strescseq;
 static int iofd = 1;
 
-char *usedfont = NULL;
-double usedfontsize = 0;
-double defaultfontsize = 0;
-
 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};
 
-/* config.h array lengths */
-size_t colornamelen = LEN(colorname);
-size_t mshortcutslen = LEN(mshortcuts);
-size_t shortcutslen = LEN(shortcuts);
-size_t selmaskslen = LEN(selmasks);
-
 ssize_t
 xwrite(int fd, const char *s, size_t len)
 {
@@ -285,7 +227,7 @@ xstrdup(char *s)
 }
 
 size_t
-utf8decode(char *c, Rune *u, size_t clen)
+utf8decode(const char *c, Rune *u, size_t clen)
 {
 	size_t i, j, len, type;
 	Rune udecoded;
@@ -386,6 +328,13 @@ static const char base64_digits[] = {
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
+char
+base64dec_getc(const char **src)
+{
+	while (**src && !isprint(**src)) (*src)++;
+	return *((*src)++);
+}
+
 char *
 base64dec(const char *src)
 {
@@ -393,13 +342,13 @@ base64dec(const char *src)
 	char *result, *dst;
 
 	if (in_len % 4)
-		return NULL;
+		in_len += 4 - (in_len % 4);
 	result = dst = xmalloc(in_len / 4 * 3 + 1);
 	while (*src) {
-		int a = base64_digits[(unsigned char) *src++];
-		int b = base64_digits[(unsigned char) *src++];
-		int c = base64_digits[(unsigned char) *src++];
-		int d = base64_digits[(unsigned char) *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)];
 
 		*dst++ = (a << 2) | ((b & 0x30) >> 4);
 		if (c == -1)
@@ -425,24 +374,6 @@ selinit(void)
 	sel.clipboard = NULL;
 }
 
-int
-x2col(int x)
-{
-	x -= borderpx;
-	x /= win.cw;
-
-	return LIMIT(x, 0, term.col-1);
-}
-
-int
-y2row(int y)
-{
-	y -= borderpx;
-	y /= win.ch;
-
-	return LIMIT(y, 0, term.row-1);
-}
-
 int
 tlinelen(int y)
 {
@@ -627,24 +558,6 @@ getsel(void)
 	return str;
 }
 
-void
-selpaste(const Arg *dummy)
-{
-	xselpaste();
-}
-
-void
-clipcopy(const Arg *dummy)
-{
-	xclipcopy();
-}
-
-void
-clippaste(const Arg *dummy)
-{
-	xclippaste();
-}
-
 void
 selclear(void)
 {
@@ -667,9 +580,9 @@ die(const char *errstr, ...)
 }
 
 void
-execsh(void)
+execsh(char **args)
 {
-	char **args, *sh, *prog;
+	char *sh, *prog;
 	const struct passwd *pw;
 
 	errno = 0;
@@ -683,13 +596,13 @@ execsh(void)
 	if ((sh = getenv("SHELL")) == NULL)
 		sh = (pw->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");
@@ -699,7 +612,6 @@ execsh(void)
 	setenv("SHELL", sh, 1);
 	setenv("HOME", pw->pw_dir, 1);
 	setenv("TERM", termname, 1);
-	xsetenv();
 
 	signal(SIGCHLD, SIG_DFL);
 	signal(SIGHUP, SIG_DFL);
@@ -731,7 +643,7 @@ sigchld(int a)
 
 
 void
-stty(void)
+stty(char **args)
 {
 	char cmd[_POSIX_ARG_MAX], **p, *q, *s;
 	size_t n, siz;
@@ -741,7 +653,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++ = ' ';
@@ -755,31 +667,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()) {
@@ -796,7 +707,7 @@ ttynew(void)
 			die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
 		close(s);
 		close(m);
-		execsh();
+		execsh(args);
 		break;
 	default:
 		close(s);
@@ -811,38 +722,19 @@ 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;
 }
@@ -907,38 +799,20 @@ write_error:
 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;
-	}
+	if (IS_SET(MODE_ECHO))
+		twrite(s, n, 1);
 }
 
 void
-ttyresize(void)
+ttyresize(int tw, int th)
 {
 	struct winsize w;
 
 	w.ws_row = term.row;
 	w.ws_col = term.col;
-	w.ws_xpixel = win.tw;
-	w.ws_ypixel = win.th;
+	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));
 }
@@ -1652,7 +1526,7 @@ csihandle(void)
 		break;
 	case 'c': /* DA -- Device Attributes */
 		if (csiescseq.arg[0] == 0)
-			ttywrite(vtiden, sizeof(vtiden) - 1);
+			ttywrite(vtiden, strlen(vtiden));
 		break;
 	case 'C': /* CUF -- Cursor <n> Forward */
 	case 'a': /* HPR -- Cursor <n> Forward */
@@ -1802,11 +1676,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;
@@ -1870,8 +1741,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");
 				}
@@ -1976,8 +1847,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;
 	}
@@ -1986,14 +1856,11 @@ tprinter(char *s, size_t len)
 void
 iso14755(const Arg *arg)
 {
-	unsigned long id = xwinid();
-	char cmd[sizeof(ISO14755CMD) + NUMMAXLEN(id)];
 	FILE *p;
 	char *us, *e, codepoint[9], uc[UTF_SIZ];
 	unsigned long utf32;
 
-	snprintf(cmd, sizeof(cmd), ISO14755CMD, id);
-	if (!(p = popen(cmd, "r")))
+	if (!(p = popen(ISO14755CMD, "r")))
 		return;
 
 	us = fgets(codepoint, sizeof(codepoint), p);
@@ -2078,22 +1945,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)
 {
@@ -2178,10 +2029,7 @@ tcontrolcode(uchar ascii)
 			/* backwards compatibility to xterm */
 			strhandle();
 		} else {
-			if (!(win.state & WIN_FOCUSED))
-				xseturgency(1);
-			if (bellvolume)
-				xbell(bellvolume);
+			xbell();
 		}
 		break;
 	case '\033': /* ESC */
@@ -2237,7 +2085,7 @@ tcontrolcode(uchar ascii)
 	case 0x99:   /* TODO: SGCI */
 		break;
 	case 0x9a:   /* DECID -- Identify Terminal */
-		ttywrite(vtiden, sizeof(vtiden) - 1);
+		ttywrite(vtiden, strlen(vtiden));
 		break;
 	case 0x9b:   /* TODO: CSI */
 	case 0x9c:   /* TODO: ST */
@@ -2309,7 +2157,7 @@ eschandle(uchar ascii)
 		}
 		break;
 	case 'Z': /* DECID -- Identify Terminal */
-		ttywrite(vtiden, sizeof(vtiden) - 1);
+		ttywrite(vtiden, strlen(vtiden));
 		break;
 	case 'c': /* RIS -- Reset to inital state */
 		treset();
@@ -2487,6 +2335,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)
 {
@@ -2521,9 +2401,6 @@ tresize(int col, int row)
 		free(term.alt[i]);
 	}
 
-	/* resize to new width */
-	term.specbuf = xrealloc(term.specbuf, col * sizeof(GlyphFontSpec));
-
 	/* resize to new height */
 	term.line = xrealloc(term.line, row * sizeof(Line));
 	term.alt  = xrealloc(term.alt,  row * sizeof(Line));
@@ -2572,41 +2449,10 @@ tresize(int col, int row)
 	term.c = c;
 }
 
-void
-zoom(const Arg *arg)
-{
-	Arg larg;
-
-	larg.f = usedfontsize + arg->f;
-	zoomabs(&larg);
-}
-
-void
-zoomabs(const Arg *arg)
-{
-	xunloadfonts();
-	xloadfonts(usedfont, arg->f);
-	cresize(0, 0);
-	ttyresize();
-	redraw();
-	xhints();
-}
-
-void
-zoomreset(const Arg *arg)
-{
-	Arg larg;
-
-	if (defaultfontsize > 0) {
-		larg.f = defaultfontsize;
-		zoomabs(&larg);
-	}
-}
-
 void
 resettitle(void)
 {
-	xsettitle(opt_title ? opt_title : "st");
+	xsettitle(NULL);
 }
 
 void
@@ -2616,84 +2462,8 @@ redraw(void)
 	draw();
 }
 
-int
-match(uint mask, uint state)
-{
-	return mask == XK_ANY_MOD || mask == (state & ~ignoremod);
-}
-
 void
 numlock(const Arg *dummy)
 {
 	term.numlock ^= 1;
 }
-
-char*
-kmap(KeySym k, uint state)
-{
-	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;
-}
-
-void
-cresize(int width, int height)
-{
-	int col, row;
-
-	if (width != 0)
-		win.w = width;
-	if (height != 0)
-		win.h = height;
-
-	col = (win.w - 2 * borderpx) / win.cw;
-	row = (win.h - 2 * borderpx) / win.ch;
-
-	tresize(col, row);
-	xresize(col, row);
-}
-
-void
-usage(void)
-{
-	die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]"
-	    " [-n name] [-o file]\n"
-	    "          [-T title] [-t title] [-w windowid]"
-	    " [[-e] command [args ...]]\n"
-	    "       %s [-aiv] [-c class] [-f font] [-g geometry]"
-	    " [-n name] [-o file]\n"
-	    "          [-T title] [-t title] [-w windowid] -l line"
-	    " [stty_args ...]\n", argv0, argv0);
-}