From 07a6e85322768c7410a3db568d0bd97faeb2c2b2 Mon Sep 17 00:00:00 2001
From: deuce <>
Date: Fri, 12 Jul 2019 04:49:35 +0000
Subject: [PATCH] Add more standard sequences.

CSI Pn b (Repeat previous char)
	Actually mildly useful... repeat any character.
CSI Ps d (Line position absolute)
	Moves to a specific row without changing column.
	Mildly useful.
CSI Pn a (Cursor forward)
	Identical to CSI Pn C
CSI Pn ` (Absolute position in line)
	Identical to CSI Pn G
ESC H (Add Tab Stop)
	ie: Break everything else that uses tabs this session.
CSI Pn g (Clear Tabs)
	ie: Break everything else that uses tabs this session.
CSI 2 $ w (Request Tab Report)
	So, maybe it can be fixed after you break it!  Yay!
ESC M (Reverse Line Feed)
	Basically up one line.  Not really useful since we have cursor up.
CSI Ps e (Line position relative)
	Identical to CSI Pn B
---
 src/conio/cterm.c   | 214 +++++++++++++++++++++++++++++++++-----------
 src/conio/cterm.h   |   2 +
 src/conio/cterm.txt |  84 +++++++++++++++--
 3 files changed, 238 insertions(+), 62 deletions(-)

diff --git a/src/conio/cterm.c b/src/conio/cterm.c
index 024ac00819..9468e3b914 100644
--- a/src/conio/cterm.c
+++ b/src/conio/cterm.c
@@ -209,6 +209,8 @@ struct note_params {
 	#define SETFONT(a,b,c)			cterm->ciolib_setfont(a,b,c)
 #endif
 
+static void ctputs(struct cterminal *cterm, char *buf);
+
 #ifdef CTERM_WITHOUT_CONIO
 /***************************************************************/
 /* These funcions are used when conio is not                   */
@@ -468,10 +470,10 @@ static int ciolib_putch(struct cterminal *cterm,int a)
 		case 7:		/* Bell */
 			break;
 		case '\t':
-			for(i=0;i<(sizeof(cterm_tabs)/sizeof(int));i++) {
-				if(cterm_tabs[i]>BD->x) {
+			for(i = 0; i < cterm->tab_count;i++) {
+				if(cterm->tabs[i] > BD->x) {
 					buf[0]=' ';
-					while(BD->x<cterm_tabs[i]) {
+					while(BD->x < cterm->tabs[i]) {
 						PUTTEXT(BD->x+BD->winleft-1
 								,BD->y+BD->wintop-1
 								,BD->x+BD->winleft-1
@@ -604,6 +606,41 @@ static int ciolib_setfont(struct cterminal *,int font, int force, int font_num)
 }
 #endif
 
+static void
+insert_tabstop(struct cterminal *cterm, int pos)
+{
+	int i;
+	int *new_stops;
+
+	for (i = 0; i < cterm->tab_count && cterm->tabs[i] < pos; i++);
+	if (cterm->tabs[i] == pos)
+		return;
+
+	new_stops = realloc(cterm->tabs, (cterm->tab_count + 1) * sizeof(cterm->tabs[0]));
+	if (new_stops == NULL)
+		return;
+	cterm->tabs = new_stops;
+	if (i < cterm->tab_count)
+		memcpy(&cterm->tabs[i + 1], &cterm->tabs[i], (cterm->tab_count - i) * sizeof(cterm->tabs[0]));
+	cterm->tabs[i] = pos;
+	cterm->tab_count++;
+}
+
+static void
+delete_tabstop(struct cterminal *cterm, int pos)
+{
+	int i;
+
+	for (i = 0; i < cterm->tab_count && cterm->tabs[i] < pos; i++) {
+		if (cterm->tabs[i] == pos) {
+			memcpy(&cterm->tabs[i], &cterm->tabs[i+1], (cterm->tab_count - i - 1) * sizeof(cterm->tabs[0]));
+			cterm->tab_count--;
+			return;
+		}
+	}
+	return;
+}
+
 static void tone_or_beep(double freq, int duration, int device_open)
 {
 	if(device_open)
@@ -1636,7 +1673,7 @@ static void parse_extended_colour(struct esc_seq *seq, int *i, struct cterminal
 }
 
 
-static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *speed)
+static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *speed, char last)
 {
 	char	*p;
 	char	*p2;
@@ -2222,6 +2259,22 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 				 * END OF STANDARD CONTROL FUNCTIONS
 				 * AFTER THIS IS ALL PRIVATE EXTENSIONS
 				 */
+				// Tab report
+				else if (strcmp(seq->ctrl_func, "$w") == 0) {
+					seq_default(seq, 0, 0);
+					if (seq->param_int[0] == 2) {
+						strcpy(tmp, "\x1bP2$u");
+						p2 = strchr(tmp, 0);
+						for (i = 0; i < cterm->tab_count && cterm->tabs[i] <= cterm->width; i++) {
+							if (i != 0)
+								*(p2++) = '/';
+							p2 += sprintf(p2, "%d", cterm->tabs[i]);
+						}
+						strcat(p2, "\x1b\\");
+						if(*tmp && strlen(retbuf) + strlen(tmp) < retsize)
+							strcat(retbuf, tmp);
+					}
+				}
 				// Communication speed
 				else if (strcmp(seq->ctrl_func, "*r") == 0) {
 					/*
@@ -2311,6 +2364,7 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 							i=cterm->top_margin;
 						GOTOXY(WHEREX(),i);
 						break;
+					case 'e':	/* Line Position Forward */
 					case 'B':	/* Cursor Down */
 						seq_default(seq, 0, 1);
 						i=WHEREY()+seq->param_int[0];
@@ -2318,6 +2372,7 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 							i=cterm->bottom_margin;
 						GOTOXY(WHEREX(),i);
 						break;
+					case 'a':	/* Character Position Forward */
 					case 'C':	/* Cursor Right */
 						seq_default(seq, 0, 1);
 						i=WHEREX()+seq->param_int[0];
@@ -2346,6 +2401,7 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 							i=cterm->top_margin;
 						GOTOXY(1,i);
 						break;
+					case '`':
 					case 'G':	/* Cursor Position Absolute */
 						seq_default(seq, 0, 1);
 						col=seq->param_int[0];
@@ -2522,12 +2578,12 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 					case 'Z':	/* Cursor Backward Tabulation */
 						seq_default(seq, 0, 1);
 						i=strtoul(cterm->escbuf+1,NULL,10);
-						for(j=(sizeof(cterm_tabs)/sizeof(cterm_tabs[0]))-1;j>=0;j--) {
-							if(cterm_tabs[j]<WHEREX()) {
+						for(j=cterm->tab_count-1;j>=0;j--) {
+							if(cterm->tabs[j]<WHEREX()) {
 								k=j-seq->param_int[0]+1;
 								if(k<0)
 									k=0;
-								GOTOXY(cterm_tabs[k],WHEREY());
+								GOTOXY(cterm->tabs[k],WHEREY());
 								break;
 							}
 						}
@@ -2542,11 +2598,22 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 						break;
 					case '_':	/* NOT DEFIFINED IN STANDARD */
 						break;
-					case '`':	/* TODO? Character Position Absolute */
-						break;
-					case 'a':	/* TODO? Character Position Forward */
-						break;
-					case 'b':	/* ToDo? Repeat */
+					// for case '`': see case 'G':
+					// for case 'a': see case 'C':
+					case 'b':	/* Repeat */
+						if (last != 0) {
+							seq_default(seq, 0, 1);
+							i = seq->param_int[0];
+							if (i > 0) {
+								p2 = malloc(i+1);
+								if (p2) {
+									memset(p2, last, i);
+									p2[i] = 0;
+									ctputs(cterm, p2);
+									free(p2);
+								}
+							}
+						}
 						break;
 					case 'c':	/* Device Attributes */
 						seq_default(seq, 0, 0);
@@ -2557,12 +2624,32 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 							}
 						}
 						break;
-					case 'd':	/* TODO? Line Position Absolute */
-						break;
-					case 'e':	/* TODO? Line Position Forward */
+					case 'd':	/* Line Position Absolute */
+						seq_default(seq, 0, 1);
+						max_row = cterm->height;
+						if (cterm->extattr & CTERM_EXTATTR_ORIGINMODE)
+							max_row = cterm->bottom_margin - cterm->top_margin + 1;
+						row = seq->param_int[0];
+						if (row < 1)
+							row = 1;
+						if (row > max_row)
+							row = max_row;
+						if (cterm->extattr & CTERM_EXTATTR_ORIGINMODE)
+							row += cterm->top_margin - 1;
+						GOTOXY(WHEREX(), row);
 						break;
+					// for case 'e': see case 'B':
 					// for case 'f': see case 'H':
-					case 'g':	/* ToDo?  Tabulation Clear */
+					case 'g':	/* Tabulation Clear */
+						seq_default(seq, 0, 0);
+						switch(seq->param_int[0]) {
+							case 0:
+								delete_tabstop(cterm, WHEREX());
+								break;
+							case 3:
+								cterm->tab_count = 0;
+								break;
+						}
 						break;
 					case 'h':	/* TODO? Set Mode */
 						break;
@@ -2795,11 +2882,11 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 					 * END OF STANDARD CONTROL FUNCTIONS
 					 * AFTER THIS IS ALL PRIVATE EXTENSIONS
 					 */
-					case 'p': /* ToDo?  ANSI keyboard reassignment */
+					case 'p': /* ToDo?  ANSI keyboard reassignment, pointer mode, soft reset */
 						break;
-					case 'q': /* ToDo?  VT100 keyboard lights */
+					case 'q': /* ToDo?  VT100 keyboard lights, cursor style, protection */
 						break;
-					case 'r': /* ToDo?  Scrolling reigon */
+					case 'r': /* Scrolling reigon */
 						seq_default(seq, 0, 1);
 						seq_default(seq, 1, cterm->height);
 						row = seq->param_int[0];
@@ -2809,7 +2896,7 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 							cterm->bottom_margin = max_row;
 						}
 						break;
-					case 's':
+					case 's': /* ToDo?  Also set left/right margins! */
 						cterm->save_xpos=WHEREX();
 						cterm->save_ypos=WHEREY();
 						break;
@@ -2847,20 +2934,20 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 				}
 			}
 			break;
-#if 0
-		case 'D':
-			scrollup(cterm);
+		case 'E':	// Next Line
+			i=WHEREY()+1;
+			if(i > cterm->bottom_margin)
+				i = cterm->bottom_margin;
+			GOTOXY(1,i);
 			break;
-		case 'M':
-			scrolldown(cterm);
+		case 'H':
+			insert_tabstop(cterm, WHEREX());
 			break;
-#endif
-		case '_':	// Application Program Command - APC
-			cterm->string = CTERM_STRING_APC;
-			FREE_AND_NULL(cterm->strbuf);
-			cterm->strbuf = malloc(1024);
-			cterm->strbufsize = 1024;
-			cterm->strbuflen = 0;
+		case 'M':
+			i=WHEREY()-1;
+			if(i < cterm->top_margin)
+				i = cterm->top_margin;
+			GOTOXY(WHEREX(),i);
 			break;
 		case 'P':	// Device Control String - DCS
 			cterm->string = CTERM_STRING_DCS;
@@ -2870,20 +2957,6 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 			cterm->strbufsize = 1024;
 			cterm->strbuflen = 0;
 			break;
-		case ']':	// Operating System Command - OSC
-			cterm->string = CTERM_STRING_OSC;
-			FREE_AND_NULL(cterm->strbuf);
-			cterm->strbuf = malloc(1024);
-			cterm->strbufsize = 1024;
-			cterm->strbuflen = 0;
-			break;
-		case '^':	// Privacy Message - PM
-			cterm->string = CTERM_STRING_PM;
-			FREE_AND_NULL(cterm->strbuf);
-			cterm->strbuf = malloc(1024);
-			cterm->strbufsize = 1024;
-			cterm->strbuflen = 0;
-			break;
 		case 'X':	// Start Of String - SOS
 			cterm->string = CTERM_STRING_SOS;
 			FREE_AND_NULL(cterm->strbuf);
@@ -3126,6 +3199,27 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 			cterm->strbufsize = cterm->strbuflen = 0;
 			cterm->string = 0;
 			break;
+		case ']':	// Operating System Command - OSC
+			cterm->string = CTERM_STRING_OSC;
+			FREE_AND_NULL(cterm->strbuf);
+			cterm->strbuf = malloc(1024);
+			cterm->strbufsize = 1024;
+			cterm->strbuflen = 0;
+			break;
+		case '^':	// Privacy Message - PM
+			cterm->string = CTERM_STRING_PM;
+			FREE_AND_NULL(cterm->strbuf);
+			cterm->strbuf = malloc(1024);
+			cterm->strbufsize = 1024;
+			cterm->strbuflen = 0;
+			break;
+		case '_':	// Application Program Command - APC
+			cterm->string = CTERM_STRING_APC;
+			FREE_AND_NULL(cterm->strbuf);
+			cterm->strbuf = malloc(1024);
+			cterm->strbufsize = 1024;
+			cterm->strbuflen = 0;
+			break;
 		case 'c':
 			/* ToDo: Reset Terminal */
 			break;
@@ -3178,6 +3272,13 @@ struct cterminal* CIOLIBCALL cterm_init(int height, int width, int xpos, int ypo
 	cterm->extattr = CTERM_EXTATTR_AUTOWRAP | CTERM_EXTATTR_SXSCROLL;
 	cterm->fg_color = UINT32_MAX;
 	cterm->bg_color = UINT32_MAX;
+	cterm->tabs = malloc(sizeof(cterm_tabs));
+	if (cterm->tabs == NULL) {
+		free(cterm->tabs);
+		return NULL;
+	}
+	memcpy(cterm->tabs, cterm_tabs, sizeof(cterm_tabs));
+	cterm->tab_count = sizeof(cterm_tabs) / sizeof(cterm_tabs[0]);
 	if(cterm->scrollback!=NULL)
 		memset(cterm->scrollback,0,cterm->width*2*cterm->backlines);
 	strcpy(cterm->DA,"\x1b[=67;84;101;114;109;");
@@ -3203,8 +3304,8 @@ struct cterminal* CIOLIBCALL cterm_init(int height, int width, int xpos, int ypo
 
 	/* Set up tabs for ATASCII */
 	if(cterm->emulation == CTERM_EMULATION_ATASCII) {
-		for(i=0; i<(sizeof(cterm_tabs)/sizeof(cterm_tabs[0])); i++)
-			cterm->escbuf[cterm_tabs[i]]=1;
+		for(i=0; i<cterm->tab_count; i++)
+			cterm->escbuf[cterm->tabs[i]]=1;
 	}
 
 	/* Set up a shadow palette */
@@ -3262,7 +3363,8 @@ void CIOLIBCALL cterm_start(struct cterminal *cterm)
 	}
 }
 
-static void ctputs(struct cterminal *cterm, char *buf)
+static void
+ctputs(struct cterminal *cterm, char *buf)
 {
 	char *outp;
 	char *p;
@@ -3307,9 +3409,9 @@ static void ctputs(struct cterminal *cterm, char *buf)
 				*p=0;
 				CPUTS(outp);
 				outp=p+1;
-				for(i=0;i<sizeof(cterm_tabs)/sizeof(cterm_tabs[0]);i++) {
-					if(cterm_tabs[i]>cx) {
-						cx=cterm_tabs[i];
+				for(i=0;cterm->tab_count;i++) {
+					if(cterm->tabs[i]>cx) {
+						cx=cterm->tabs[i];
 						break;
 					}
 				}
@@ -3471,6 +3573,7 @@ CIOLIBEXPORT char* CIOLIBCALL cterm_write(struct cterminal * cterm, const void *
 	int mpalette;
 	struct vmem_cell tmpvc[1];
 	int orig_fonts[4];
+	char lastch = 0;
 
 	if(!cterm->started)
 		cterm_start(cterm);
@@ -3663,7 +3766,8 @@ CIOLIBEXPORT char* CIOLIBCALL cterm_write(struct cterminal * cterm, const void *
 						case SEQ_INCOMPLETE:
 							break;
 						case SEQ_COMPLETE:
-							do_ansi(cterm, retbuf, retsize, speed);
+							do_ansi(cterm, retbuf, retsize, speed, lastch);
+							lastch = 0;
 							break;
 					}
 				}
@@ -4214,10 +4318,12 @@ CIOLIBEXPORT char* CIOLIBCALL cterm_write(struct cterminal * cterm, const void *
 						else {
 							switch(buf[j]) {
 								case 0:
+									lastch = 0;
 									if(cterm->doorway_mode)
 										cterm->doorway_char=1;
 									break;
 								case 7:			/* Beep */
+									lastch = 0;
 									uctputs(cterm, prn);
 									prn[0]=0;
 									if(cterm->log==CTERM_LOG_ASCII && cterm->logfile != NULL)
@@ -4231,6 +4337,7 @@ CIOLIBEXPORT char* CIOLIBCALL cterm_write(struct cterminal * cterm, const void *
 									}
 									break;
 								case 12:		/* ^L - Clear screen */
+									lastch = 0;
 									uctputs(cterm, prn);
 									prn[0]=0;
 									if(cterm->log==CTERM_LOG_ASCII && cterm->logfile != NULL)
@@ -4247,6 +4354,7 @@ CIOLIBEXPORT char* CIOLIBCALL cterm_write(struct cterminal * cterm, const void *
 									cterm->sequence=1;
 									break;
 								default:
+									lastch = ch[0];
 									ustrcat(prn,ch);
 							}
 						}
diff --git a/src/conio/cterm.h b/src/conio/cterm.h
index c22613e959..cdd6d157a9 100644
--- a/src/conio/cterm.h
+++ b/src/conio/cterm.h
@@ -146,6 +146,8 @@ struct cterminal {
 	int					cursor;			// Current cursor mode (Normal or None)
 	char				*fg_tc_str;
 	char				*bg_tc_str;
+	int					*tabs;
+	int					tab_count;
 
 	/* Sixel state */
 	int					sixel;			// Sixel status
diff --git a/src/conio/cterm.txt b/src/conio/cterm.txt
index e363e14033..ad3fc1c89e 100644
--- a/src/conio/cterm.txt
+++ b/src/conio/cterm.txt
@@ -53,15 +53,15 @@ ESC {SPACE to '/'}{'0' (ZERO) to '~'}
 
 	Legal combinations which are not handled are silently dropped.
 
-ESC D	(Disabled in current code)
-	Scrolls window up one line filling the bottom line with the
-	current attribute.
-	SOURCE: BANSI.TXT
+ESC H	Set Tab
+	Sets a tab stop at the current column
 
-ESC M	(Disabled in current code)
-	Scrolls window down one line filling the top line with the
-	current attribute
-	SOURCE: BANSI.TXT
+	SOURCE: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
+
+ESC M	Reverse Line Feed
+	Move up one line
+
+	SOURCE: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
 
 ESC _	Application Program String
 	Begins a string consisting of the characters 0x08 - 0x0d and
@@ -388,7 +388,6 @@ CSI Pn G
 	SOURCE: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
 
 CSI Pn1 ; Pn2 H
-CSI Pn1 ; Pn2 f
 	Cursor Position
 	Defaults: Pn1 = 1  Pn2 = 1
 	Moves the cursor to the Pn2th column of the Pn1th line.
@@ -519,6 +518,31 @@ CSI Pn Z
 
 	SOURCE: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
 
+CSI Pn `
+	Character Position Absolute
+	Defaults: Pn = 1
+	Move the cursor to the specified position on the current row.
+	Will not go past the end of the line.
+
+	SOURCE: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
+
+CSI Pn a
+	Cursor Position Forward
+	Defaults: Pn = 1
+	Moves the cursor position forward Pn columns from the current position.
+	Attempting to move past the screen boundaries stops the cursor
+	at the screen boundary.
+
+	SOURCE: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
+
+CSI Pn b
+	Repeat
+	Defaults: Pn = 1
+	Repeats the previous graphic character Pn times.  Will not repeat
+	escape sequences.
+
+	SOURCE: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
+
 CSI Ps c
 	Device Attributes
 	Defaults: Ps = 0
@@ -549,6 +573,37 @@ CSI < Ps c
 	5 - More than the standard 16 colours may by configured via
 	    Operating System Command strings
 
+CSI Ps d
+	Line Position Absolute
+	Defaults: Ps = 1
+	Moves to row specified by Ps.
+
+	SOURCE: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
+
+CSI Ps e
+	Line Position Relative
+	Defaults: Ps = 1
+	Moves forward Ps rows.
+
+	SOURCE: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
+
+CSI Pn1 ; Pn2 f
+	Cursor Position
+	Defaults: Pn1 = 1  Pn2 = 1
+	Moves the cursor to the Pn2th column of the Pn1th line.
+
+	SOURCE: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
+
+CSI Pn g
+	Clear Tab(s)
+	Defaults: Pn = 0
+	Deletes tab stpos according to the values of P1:
+	0 - Deletes tab stop at current position.
+	3 - Deletes all tab stops.
+	5 - Deletes all tab stops.
+
+	SOURCE: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
+
 CSI = 255 h
 	NON-STANDARD EXTENSION
 	Enable DoorWay Mode
@@ -859,6 +914,17 @@ CSI u
 
 	SOURCE: ANSI.SYS
 
+CSI 2 $ w
+	Request Tab Stop Report
+	Requests a list of tab stops.
+	The list is in the form:
+	
+	DCS 2 $ u Pt ST
+	
+	The string Pt is a list of tab stops separated by /s.
+	
+	SOURCE: VT320
+
 CSI = Ps1 ; Ps2 {
 	NON-STANDARD EXTENSION (Deprecated)
 	Defaults:  Ps1 = 255  Ps2 = 0
-- 
GitLab