From f7398434b8fa949af7bf43472caaefdd97eed0f3 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <roberto.vargas@igrid-td.com>
Date: Wed, 14 Sep 2016 08:27:32 +0200
Subject: [PATCH] Add parsing of DCS q sequences

These sequences are used to operate with sixels, but they are still
str sequences, so they are finished with \a, ST or with a C1 control
code. This patch also disables utf8 handling for the case of sixels.
---
 st.c | 68 ++++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 45 insertions(+), 23 deletions(-)

diff --git a/st.c b/st.c
index ebbd7ca..6c16386 100644
--- a/st.c
+++ b/st.c
@@ -138,6 +138,7 @@ enum term_mode {
 	MODE_BRCKTPASTE  = 1 << 19,
 	MODE_PRINT       = 1 << 20,
 	MODE_UTF8        = 1 << 21,
+	MODE_SIXEL       = 1 << 22,
 	MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
 	                  |MODE_MOUSEMANY,
 };
@@ -155,11 +156,12 @@ enum charset {
 enum escape_state {
 	ESC_START      = 1,
 	ESC_CSI        = 2,
-	ESC_STR        = 4,  /* DCS, OSC, PM, APC */
+	ESC_STR        = 4,  /* 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,
+	ESC_DCS        =128,
 };
 
 enum window_state {
@@ -1485,7 +1487,7 @@ ttyread(void)
 	ptr = buf;
 
 	for (;;) {
-		if (IS_SET(MODE_UTF8)) {
+		if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
 			/* process a complete utf8 char */
 			charsize = utf8decode(ptr, &unicodep, buflen);
 			if (charsize == 0)
@@ -1578,7 +1580,7 @@ ttysend(char *s, size_t n)
 
 	lim = &s[n];
 	for (t = s; t < lim; t += len) {
-		if (IS_SET(MODE_UTF8)) {
+		if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
 			len = utf8decode(t, &u, n);
 		} else {
 			u = *t & 0xFF;
@@ -2548,6 +2550,7 @@ strhandle(void)
 		xsettitle(strescseq.args[0]);
 		return;
 	case 'P': /* DCS -- Device Control String */
+		term.mode |= ESC_DCS;
 	case '_': /* APC -- Application Program Command */
 	case '^': /* PM -- Privacy Message */
 		return;
@@ -2754,9 +2757,12 @@ tdectest(char c)
 void
 tstrsequence(uchar c)
 {
+	strreset();
+
 	switch (c) {
 	case 0x90:   /* DCS -- Device Control String */
 		c = 'P';
+		term.esc |= ESC_DCS;
 		break;
 	case 0x9f:   /* APC -- Application Program Command */
 		c = '_';
@@ -2768,7 +2774,6 @@ tstrsequence(uchar c)
 		c = ']';
 		break;
 	}
-	strreset();
 	strescseq.type = c;
 	term.esc |= ESC_STR;
 }
@@ -2968,7 +2973,7 @@ tputc(Rune u)
 	Glyph *gp;
 
 	control = ISCONTROL(u);
-	if (!IS_SET(MODE_UTF8)) {
+	if (!IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
 		c[0] = u;
 		width = len = 1;
 	} else {
@@ -2991,30 +2996,47 @@ tputc(Rune u)
 	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_START|ESC_STR|ESC_DCS);
+			if (IS_SET(MODE_SIXEL)) {
+				/* TODO: render sixel */;
+				term.mode &= ~MODE_SIXEL;
+				return;
+			}
 			term.esc |= ESC_STR_END;
-		} else if (strescseq.len + len < sizeof(strescseq.buf) - 1) {
-			memmove(&strescseq.buf[strescseq.len], c, len);
-			strescseq.len += len;
+			goto check_control_code;
+		}
+
+
+		if (IS_SET(MODE_SIXEL)) {
+			/* TODO: implement sixel mode */
 			return;
-		} else {
-		/*
-		 * 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 (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q')
+			term.mode |= MODE_SIXEL;
+
+		if (strescseq.len+len >= sizeof(strescseq.buf)-1) {
+			/*
+			 * 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();
+			 */
 			return;
 		}
+
+		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
-- 
2.20.1