#define has_compat(x) ( ((CL_##x)&term->compatibility_level) != 0 )
+const char sco2ansicolour[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
#define sel_nl_sz (sizeof(sel_nl)/sizeof(wchar_t))
const wchar_t sel_nl[] = SEL_NL;
*/
oldlen = line[0];
lineattrs = line[oldlen + 1];
- line = srealloc(line, TSIZE * (2 + cols));
+ line = sresize(line, 2 + cols, TTYPE);
line[0] = cols;
for (i = oldlen; i < cols; i++)
line[i + 1] = ERASE_CHAR;
}
/*
+ * Get the number of lines in the scrollback.
+ */
+static int sblines(Terminal *term)
+{
+ int sblines = count234(term->scrollback);
+ if (term->cfg.erase_to_scrollback &&
+ term->alt_which && term->alt_screen) {
+ sblines += term->alt_sblines;
+ }
+ return sblines;
+}
+
+/*
* Retrieve a line of the screen or of the scrollback, according to
* whether the y coordinate is non-negative or negative
* (respectively).
whichtree = term->screen;
treeindex = y;
} else {
- whichtree = term->scrollback;
- treeindex = y + count234(term->scrollback);
+ int altlines = 0;
+ if (term->cfg.erase_to_scrollback &&
+ term->alt_which && term->alt_screen) {
+ altlines = term->alt_sblines;
+ }
+ if (y < -altlines) {
+ whichtree = term->scrollback;
+ treeindex = y + altlines + count234(term->scrollback);
+ } else {
+ whichtree = term->alt_screen;
+ treeindex = y + term->alt_sblines;
+ /* treeindex = y + count234(term->alt_screen); */
+ }
}
line = index234(whichtree, treeindex);
term->in_vbell = FALSE;
term->cursor_on = 1;
term->big_cursor = 0;
- term->save_attr = term->curr_attr = ATTR_DEFAULT;
+ term->default_attr = term->save_attr = term->curr_attr = ATTR_DEFAULT;
term->term_editing = term->term_echoing = FALSE;
term->app_cursor_keys = term->cfg.app_cursor;
term->app_keypad_keys = term->cfg.app_keypad;
term->alt_wrap = term->wrap = term->cfg.wrap_mode;
if (reset_decom)
term->alt_om = term->dec_om = term->cfg.dec_om;
- if (reset_bce)
+ if (reset_bce) {
term->use_bce = term->cfg.bce;
+ if (term->use_bce)
+ term->erase_char = (' ' | ATTR_ASCII |
+ (term->curr_attr &
+ (ATTR_FGMASK | ATTR_BGMASK)));
+ else
+ term->erase_char = ERASE_CHAR;
+ }
if (reset_blink)
term->blink_is_real = term->cfg.blinktext;
if (reset_charclass)
while ((line = delpos234(term->scrollback, 0)) != NULL) {
sfree(line);
}
+ term->tempsblines = 0;
+ term->alt_sblines = 0;
update_sbar(term);
}
* Allocate a new Terminal structure and initialise the fields
* that need it.
*/
- term = smalloc(sizeof(Terminal));
+ term = snew(Terminal);
term->frontend = frontend;
term->ucsdata = ucsdata;
term->cfg = *mycfg; /* STRUCTURE COPY */
term->curstype = 0;
term->screen = term->alt_screen = term->scrollback = NULL;
+ term->tempsblines = 0;
+ term->alt_sblines = 0;
term->disptop = 0;
term->disptext = term->dispcurs = NULL;
term->tabs = NULL;
term->attr_mask = 0xffffffff;
term->resize_fn = NULL;
term->resize_ctx = NULL;
+ term->in_term_out = FALSE;
return term;
}
if (term->rows == -1) {
term->scrollback = newtree234(NULL);
term->screen = newtree234(NULL);
+ term->tempsblines = 0;
term->rows = 0;
}
* will take care of resizing each individual line if
* necessary. So:
*
- * - If the new screen and the old screen differ in length, we
- * must shunt some lines in from the scrollback or out to
- * the scrollback.
- *
- * - If doing that fails to provide us with enough material to
- * fill the new screen (i.e. the number of rows needed in
- * the new screen exceeds the total number in the previous
- * screen+scrollback), we must invent some blank lines to
- * cover the gap.
+ * - If the new screen is longer, we shunt lines in from temporary
+ * scrollback if possible, otherwise we add new blank lines at
+ * the bottom.
+ *
+ * - If the new screen is shorter, we remove any blank lines at
+ * the bottom if possible, otherwise shunt lines above the cursor
+ * to scrollback if possible, otherwise delete lines below the
+ * cursor.
*
* - Then, if the new scrollback length is less than the
* amount of scrollback we actually have, we must throw some
*/
sblen = count234(term->scrollback);
/* Do this loop to expand the screen if newrows > rows */
- for (i = term->rows; i < newrows; i++) {
- if (sblen > 0) {
+ assert(term->rows == count234(term->screen));
+ while (term->rows < newrows) {
+ if (term->tempsblines > 0) {
+ /* Insert a line from the scrollback at the top of the screen. */
+ assert(sblen >= term->tempsblines);
line = delpos234(term->scrollback, --sblen);
+ term->tempsblines -= 1;
+ addpos234(term->screen, line, 0);
+ term->curs.y += 1;
+ term->savecurs.y += 1;
} else {
- line = smalloc(TSIZE * (newcols + 2));
+ /* Add a new blank line at the bottom of the screen. */
+ line = snewn(newcols + 2, TTYPE);
line[0] = newcols;
for (j = 0; j < newcols; j++)
line[j + 1] = ERASE_CHAR;
line[newcols + 1] = LATTR_NORM;
+ addpos234(term->screen, line, count234(term->screen));
}
- addpos234(term->screen, line, 0);
+ term->rows += 1;
}
/* Do this loop to shrink the screen if newrows < rows */
- for (i = newrows; i < term->rows; i++) {
- line = delpos234(term->screen, 0);
- addpos234(term->scrollback, line, sblen++);
+ while (term->rows > newrows) {
+ if (term->curs.y < term->rows - 1) {
+ /* delete bottom row, unless it contains the cursor */
+ sfree(delpos234(term->screen, term->rows - 1));
+ } else {
+ /* push top row to scrollback */
+ line = delpos234(term->screen, 0);
+ addpos234(term->scrollback, line, sblen++);
+ term->tempsblines += 1;
+ term->curs.y -= 1;
+ term->savecurs.y -= 1;
+ }
+ term->rows -= 1;
}
+ assert(term->rows == newrows);
assert(count234(term->screen) == newrows);
+
+ /* Delete any excess lines from the scrollback. */
while (sblen > newsavelines) {
line = delpos234(term->scrollback, 0);
sfree(line);
sblen--;
}
+ if (sblen < term->tempsblines)
+ term->tempsblines = sblen;
assert(count234(term->scrollback) <= newsavelines);
+ assert(count234(term->scrollback) >= term->tempsblines);
term->disptop = 0;
- newdisp = smalloc(newrows * (newcols + 1) * TSIZE);
+ /* Make a new displayed text buffer. */
+ newdisp = snewn(newrows * (newcols + 1), TTYPE);
for (i = 0; i < newrows * (newcols + 1); i++)
newdisp[i] = ATTR_INVALID;
sfree(term->disptext);
term->disptext = newdisp;
term->dispcurs = NULL;
+ /* Make a new alternate screen. */
newalt = newtree234(NULL);
for (i = 0; i < newrows; i++) {
- line = smalloc(TSIZE * (newcols + 2));
+ line = snewn(newcols + 2, TTYPE);
line[0] = newcols;
for (j = 0; j < newcols; j++)
line[j + 1] = term->erase_char;
freetree234(term->alt_screen);
}
term->alt_screen = newalt;
+ term->alt_sblines = 0;
- term->tabs = srealloc(term->tabs, newcols * sizeof(*term->tabs));
+ term->tabs = sresize(term->tabs, newcols, unsigned char);
{
int i;
for (i = (term->cols > 0 ? term->cols : 0); i < newcols; i++)
term->tabs[i] = (i % 8 == 0 ? TRUE : FALSE);
}
- if (term->rows > 0)
- term->curs.y += newrows - term->rows;
+ /* Check that the cursor positions are still valid. */
+ if (term->savecurs.y < 0)
+ term->savecurs.y = 0;
+ if (term->savecurs.y >= newrows)
+ term->savecurs.y = newrows - 1;
if (term->curs.y < 0)
term->curs.y = 0;
if (term->curs.y >= newrows)
resize_fn(resize_ctx, term->cols, term->rows);
}
+/* Find the bottom line on the screen that has any content.
+ * If only the top line has content, returns 0.
+ * If no lines have content, return -1.
+ */
+static int find_last_nonempty_line(Terminal * term, tree234 * screen)
+{
+ int i;
+ for (i = count234(screen) - 1; i >= 0; i--) {
+ unsigned long *line = index234(screen, i);
+ int j;
+ int cols = line[0];
+ for (j = 0; j < cols; j++) {
+ if (line[j + 1] != term->erase_char) break;
+ }
+ if (j != cols) break;
+ }
+ return i;
+}
+
/*
* Swap screens. If `reset' is TRUE and we have been asked to
* switch to the alternate screen, we must bring most of its
ttr = term->alt_screen;
term->alt_screen = term->screen;
term->screen = ttr;
+ term->alt_sblines = find_last_nonempty_line(term, term->alt_screen) + 1;
t = term->curs.x;
if (!reset && !keep_cur_pos)
term->curs.x = term->alt_x;
*/
static void update_sbar(Terminal *term)
{
- int nscroll;
-
- nscroll = count234(term->scrollback);
-
+ int nscroll = sblines(term);
set_sbar(term->frontend, nscroll + term->rows,
nscroll + term->disptop, term->rows);
}
if (term->selstart.y >= topline && term->selstart.y <= botline) {
term->selstart.y++;
if (term->selstart.y > botline) {
- term->selstart.y = botline;
+ term->selstart.y = botline + 1;
term->selstart.x = 0;
}
}
if (term->selend.y >= topline && term->selend.y <= botline) {
term->selend.y++;
if (term->selend.y > botline) {
- term->selend.y = botline;
+ term->selend.y = botline + 1;
term->selend.x = 0;
}
}
if (sblen == term->savelines) {
sblen--, line2 = delpos234(term->scrollback, 0);
} else {
- line2 = smalloc(TSIZE * (term->cols + 2));
+ line2 = snewn(term->cols + 2, TTYPE);
line2[0] = term->cols;
+ term->tempsblines += 1;
}
addpos234(term->scrollback, line, sblen);
line = line2;
*/
seltop = sb ? -term->savelines : topline;
- if (term->selstart.y >= seltop &&
- term->selstart.y <= botline) {
- term->selstart.y--;
- if (term->selstart.y < seltop) {
- term->selstart.y = seltop;
- term->selstart.x = 0;
+ if (term->selstate != NO_SELECTION) {
+ if (term->selstart.y >= seltop &&
+ term->selstart.y <= botline) {
+ term->selstart.y--;
+ if (term->selstart.y < seltop) {
+ term->selstart.y = seltop;
+ term->selstart.x = 0;
+ }
}
- }
- if (term->selend.y >= seltop && term->selend.y <= botline) {
- term->selend.y--;
- if (term->selend.y < seltop) {
- term->selend.y = seltop;
- term->selend.x = 0;
+ if (term->selend.y >= seltop && term->selend.y <= botline) {
+ term->selend.y--;
+ if (term->selend.y < seltop) {
+ term->selend.y = seltop;
+ term->selend.x = 0;
+ }
}
- }
- if (term->selanchor.y >= seltop && term->selanchor.y <= botline) {
- term->selanchor.y--;
- if (term->selanchor.y < seltop) {
- term->selanchor.y = seltop;
- term->selanchor.x = 0;
+ if (term->selanchor.y >= seltop &&
+ term->selanchor.y <= botline) {
+ term->selanchor.y--;
+ if (term->selanchor.y < seltop) {
+ term->selanchor.y = seltop;
+ term->selanchor.x = 0;
+ }
}
}
term->scrolltail->botline == botline) {
term->scrolltail->lines += lines;
} else {
- newscroll = smalloc(sizeof(struct scrollregion));
+ newscroll = snew(struct scrollregion);
newscroll->topline = topline;
newscroll->botline = botline;
newscroll->lines = lines;
{
pos start, end;
int erase_lattr;
- unsigned long *ldata;
+ int erasing_lines_from_top = 0;
if (line_only) {
start.y = term->curs.y;
if (start.y == 0 && start.x == 0 && end.y == term->rows)
term_invalidate(term);
- ldata = lineptr(start.y);
- while (poslt(start, end)) {
- if (start.x == term->cols) {
- if (!erase_lattr)
- ldata[start.x] &= ~(LATTR_WRAPPED | LATTR_WRAPPED2);
- else
- ldata[start.x] = LATTR_NORM;
- } else {
- ldata[start.x] = term->erase_char;
- }
- if (incpos(start) && start.y < term->rows)
- ldata = lineptr(start.y);
+ /* Lines scrolled away shouldn't be brought back on if the terminal
+ * resizes. */
+ if (start.y == 0 && start.x == 0 && end.x == 0 && erase_lattr)
+ erasing_lines_from_top = 1;
+
+ if (term->cfg.erase_to_scrollback && erasing_lines_from_top) {
+ /* If it's a whole number of lines, starting at the top, and
+ * we're fully erasing them, erase by scrolling and keep the
+ * lines in the scrollback. */
+ int scrolllines = end.y;
+ if (end.y == term->rows) {
+ /* Shrink until we find a non-empty row.*/
+ scrolllines = find_last_nonempty_line(term, term->screen) + 1;
+ }
+ if (scrolllines > 0)
+ scroll(term, 0, scrolllines - 1, scrolllines, TRUE);
+ fix_cpos;
+ } else {
+ unsigned long *ldata = lineptr(start.y);
+ while (poslt(start, end)) {
+ if (start.x == term->cols) {
+ if (!erase_lattr)
+ ldata[start.x] &= ~(LATTR_WRAPPED | LATTR_WRAPPED2);
+ else
+ ldata[start.x] = LATTR_NORM;
+ } else {
+ ldata[start.x] = term->erase_char;
+ }
+ if (incpos(start) && start.y < term->rows)
+ ldata = lineptr(start.y);
+ }
}
+
+ /* After an erase of lines from the top of the screen, we shouldn't
+ * bring the lines back again if the terminal enlarges (since the user or
+ * application has explictly thrown them away). */
+ if (erasing_lines_from_top && !(term->alt_which))
+ term->tempsblines = 0;
}
/*
if (query)
switch (mode) {
- case 1: /* application cursor keys */
+ case 1: /* DECCKM: application cursor keys */
term->app_cursor_keys = state;
break;
- case 2: /* VT52 mode */
+ case 2: /* DECANM: VT52 mode */
term->vt52_mode = !state;
if (term->vt52_mode) {
term->blink_is_real = FALSE;
term->blink_is_real = term->cfg.blinktext;
}
break;
- case 3: /* 80/132 columns */
+ case 3: /* DECCOLM: 80/132 columns */
deselect(term);
if (!term->cfg.no_remote_resize)
request_resize(term->frontend, state ? 132 : 80, term->rows);
term->reset_132 = state;
+ term->alt_t = term->marg_t = 0;
+ term->alt_b = term->marg_b = term->rows - 1;
+ move(term, 0, 0, 0);
+ erase_lots(term, FALSE, TRUE, TRUE);
break;
- case 5: /* reverse video */
+ case 5: /* DECSCNM: reverse video */
/*
* Toggle reverse video. If we receive an OFF within the
* visual bell timeout period after an ON, we trigger an
if (state)
term_update(term);
break;
- case 6: /* DEC origin mode */
+ case 6: /* DECOM: DEC origin mode */
term->dec_om = state;
break;
- case 7: /* auto wrap */
+ case 7: /* DECAWM: auto wrap */
term->wrap = state;
break;
- case 8: /* auto key repeat */
+ case 8: /* DECARM: auto key repeat */
term->repeat_off = !state;
break;
- case 10: /* set local edit mode */
+ case 10: /* DECEDM: set local edit mode */
term->term_editing = state;
if (term->ldisc) /* cause ldisc to notice changes */
ldisc_send(term->ldisc, NULL, 0, 0);
break;
- case 25: /* enable/disable cursor */
+ case 25: /* DECTCEM: enable/disable cursor */
compatibility2(OTHER, VT220);
term->cursor_on = state;
term->seen_disp_event = TRUE;
term->disptop = 0;
break;
case 1048: /* save/restore cursor */
- save_cursor(term, state);
+ if (!term->cfg.no_alt_screen)
+ save_cursor(term, state);
if (!state) term->seen_disp_event = TRUE;
break;
case 1049: /* cursor & alternate screen */
- if (state)
+ if (state && !term->cfg.no_alt_screen)
save_cursor(term, state);
if (!state) term->seen_disp_event = TRUE;
compatibility(OTHER);
deselect(term);
swap_screen(term, term->cfg.no_alt_screen ? 0 : state, TRUE, FALSE);
- if (!state)
+ if (!state && !term->cfg.no_alt_screen)
save_cursor(term, state);
term->disptop = 0;
break;
} else
switch (mode) {
- case 4: /* set insert mode */
+ case 4: /* IRM: set insert mode */
compatibility(VT102);
term->insert = state;
break;
- case 12: /* set echo mode */
+ case 12: /* SRM: set echo mode */
term->term_echoing = !state;
if (term->ldisc) /* cause ldisc to notice changes */
ldisc_send(term->ldisc, NULL, 0, 0);
break;
- case 20: /* Return sends ... */
+ case 20: /* LNM: Return sends ... */
term->cr_lf_return = state;
break;
- case 34: /* Make cursor BIG */
+ case 34: /* WYULCURM: Make cursor BIG */
compatibility2(OTHER, VT220);
term->big_cursor = !state;
}
/* Or normal C0 controls. */
if ((c & -32) == 0 && term->termstate < DO_CTRLS) {
switch (c) {
- case '\005': /* terminal type query */
+ case '\005': /* ENQ: terminal type query */
/* Strictly speaking this is VT100 but a VT100 defaults to
* no response. Other terminals respond at their option.
*
abuf, d - abuf, 0);
}
break;
- case '\007':
+ case '\007': /* BEL: Bell */
{
struct beeptime *newbeep;
unsigned long ticks;
ticks = GETTICKCOUNT();
if (!term->beep_overloaded) {
- newbeep = smalloc(sizeof(struct beeptime));
+ newbeep = snew(struct beeptime);
newbeep->ticks = ticks;
newbeep->next = NULL;
if (!term->beephead)
term_update(term);
}
}
- term->disptop = 0;
+ term->seen_disp_event = TRUE;
}
break;
- case '\b':
+ case '\b': /* BS: Back space */
if (term->curs.x == 0 &&
(term->curs.y == 0 || term->wrap == 0))
/* do nothing */ ;
fix_cpos;
term->seen_disp_event = TRUE;
break;
- case '\016':
+ case '\016': /* LS1: Locking-shift one */
compatibility(VT100);
term->cset = 1;
break;
- case '\017':
+ case '\017': /* LS0: Locking-shift zero */
compatibility(VT100);
term->cset = 0;
break;
- case '\033':
+ case '\033': /* ESC: Escape */
if (term->vt52_mode)
term->termstate = VT52_ESC;
else {
term->esc_query = FALSE;
}
break;
- case '\015':
+ case '\015': /* CR: Carriage return */
term->curs.x = 0;
term->wrapnext = FALSE;
fix_cpos;
if (term->logctx)
logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII);
break;
- case '\014':
+ case '\014': /* FF: Form feed */
if (has_compat(SCOANSI)) {
move(term, 0, 0, 0);
erase_lots(term, FALSE, FALSE, TRUE);
term->seen_disp_event = 1;
break;
}
- case '\013':
+ case '\013': /* VT: Line tabulation */
compatibility(VT100);
- case '\012':
+ case '\012': /* LF: Line feed */
if (term->curs.y == term->marg_b)
scroll(term, term->marg_t, term->marg_b, 1, TRUE);
else if (term->curs.y < term->rows - 1)
if (term->logctx)
logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII);
break;
- case '\t':
+ case '\t': /* HT: Character tabulation */
{
pos old_curs = term->curs;
unsigned long *ldata = lineptr(term->curs.y);
}
term->termstate = TOPLEVEL;
switch (ANSI(c, term->esc_query)) {
- case '[': /* enter CSI mode */
+ case '[': /* enter CSI mode */
term->termstate = SEEN_CSI;
term->esc_nargs = 1;
term->esc_args[0] = ARG_DEFAULT;
term->esc_query = FALSE;
break;
- case ']': /* xterm escape sequences */
+ case ']': /* OSC: xterm escape sequences */
/* Compatibility is nasty here, xterm, linux, decterm yuk! */
compatibility(OTHER);
term->termstate = SEEN_OSC;
term->esc_args[0] = 0;
break;
- case '7': /* save cursor */
+ case '7': /* DECSC: save cursor */
compatibility(VT100);
save_cursor(term, TRUE);
break;
- case '8': /* restore cursor */
+ case '8': /* DECRC: restore cursor */
compatibility(VT100);
save_cursor(term, FALSE);
term->seen_disp_event = TRUE;
break;
- case '=':
+ case '=': /* DECKPAM: Keypad application mode */
compatibility(VT100);
term->app_keypad_keys = TRUE;
break;
- case '>':
+ case '>': /* DECKPNM: Keypad numeric mode */
compatibility(VT100);
term->app_keypad_keys = FALSE;
break;
- case 'D': /* exactly equivalent to LF */
+ case 'D': /* IND: exactly equivalent to LF */
compatibility(VT100);
if (term->curs.y == term->marg_b)
scroll(term, term->marg_t, term->marg_b, 1, TRUE);
term->wrapnext = FALSE;
term->seen_disp_event = TRUE;
break;
- case 'E': /* exactly equivalent to CR-LF */
+ case 'E': /* NEL: exactly equivalent to CR-LF */
compatibility(VT100);
term->curs.x = 0;
if (term->curs.y == term->marg_b)
term->wrapnext = FALSE;
term->seen_disp_event = TRUE;
break;
- case 'M': /* reverse index - backwards LF */
+ case 'M': /* RI: reverse index - backwards LF */
compatibility(VT100);
if (term->curs.y == term->marg_t)
scroll(term, term->marg_t, term->marg_b, -1, TRUE);
term->wrapnext = FALSE;
term->seen_disp_event = TRUE;
break;
- case 'Z': /* terminal type query */
+ case 'Z': /* DECID: terminal type query */
compatibility(VT100);
if (term->ldisc)
ldisc_send(term->ldisc, term->id_string,
strlen(term->id_string), 0);
break;
- case 'c': /* restore power-on settings */
+ case 'c': /* RIS: restore power-on settings */
compatibility(VT100);
power_on(term);
if (term->ldisc) /* cause ldisc to notice changes */
term->disptop = 0;
term->seen_disp_event = TRUE;
break;
- case 'H': /* set a tab */
+ case 'H': /* HTS: set a tab */
compatibility(VT100);
term->tabs[term->curs.x] = TRUE;
break;
- case ANSI('8', '#'): /* ESC # 8 fills screen with Es :-) */
+ case ANSI('8', '#'): /* DECALN: fills screen with Es :-) */
compatibility(VT100);
{
unsigned long *ldata;
unsigned long nlattr;
unsigned long *ldata;
switch (ANSI(c, term->esc_query)) {
- case ANSI('3', '#'):
+ case ANSI('3', '#'): /* DECDHL: 2*height, top */
nlattr = LATTR_TOP;
break;
- case ANSI('4', '#'):
+ case ANSI('4', '#'): /* DECDHL: 2*height, bottom */
nlattr = LATTR_BOT;
break;
- case ANSI('5', '#'):
+ case ANSI('5', '#'): /* DECSWL: normal */
nlattr = LATTR_NORM;
break;
- default: /* spiritually case ANSI('6', '#'): */
+ default: /* case ANSI('6', '#'): DECDWL: 2*width */
nlattr = LATTR_WIDE;
break;
}
ldata[term->cols] |= nlattr;
}
break;
-
+ /* GZD4: G0 designate 94-set */
case ANSI('A', '('):
compatibility(VT100);
if (!term->cfg.no_remote_charset)
if (!term->cfg.no_remote_charset)
term->cset_attr[0] = ATTR_SCOACS;
break;
-
+ /* G1D4: G1-designate 94-set */
case ANSI('A', ')'):
compatibility(VT100);
if (!term->cfg.no_remote_charset)
if (!term->cfg.no_remote_charset)
term->cset_attr[1] = ATTR_SCOACS;
break;
-
+ /* DOCS: Designate other coding system */
case ANSI('8', '%'): /* Old Linux code */
case ANSI('G', '%'):
compatibility(OTHER);
term->termstate = SEEN_CSI;
} else
switch (ANSI(c, term->esc_query)) {
- case 'A': /* move up N lines */
+ case 'A': /* CUU: move up N lines */
move(term, term->curs.x,
term->curs.y - def(term->esc_args[0], 1), 1);
term->seen_disp_event = TRUE;
break;
- case 'e': /* move down N lines */
+ case 'e': /* VPR: move down N lines */
compatibility(ANSI);
/* FALLTHROUGH */
- case 'B':
+ case 'B': /* CUD: Cursor down */
move(term, term->curs.x,
term->curs.y + def(term->esc_args[0], 1), 1);
term->seen_disp_event = TRUE;
break;
- case ANSI('c', '>'): /* report xterm version */
+ case ANSI('c', '>'): /* DA: report xterm version */
compatibility(OTHER);
/* this reports xterm version 136 so that VIM can
use the drag messages from the mouse reporting */
if (term->ldisc)
ldisc_send(term->ldisc, "\033[>0;136;0c", 11, 0);
break;
- case 'a': /* move right N cols */
+ case 'a': /* HPR: move right N cols */
compatibility(ANSI);
/* FALLTHROUGH */
- case 'C':
+ case 'C': /* CUF: Cursor right */
move(term, term->curs.x + def(term->esc_args[0], 1),
term->curs.y, 1);
term->seen_disp_event = TRUE;
break;
- case 'D': /* move left N cols */
+ case 'D': /* CUB: move left N cols */
move(term, term->curs.x - def(term->esc_args[0], 1),
term->curs.y, 1);
term->seen_disp_event = TRUE;
break;
- case 'E': /* move down N lines and CR */
+ case 'E': /* CNL: move down N lines and CR */
compatibility(ANSI);
move(term, 0,
term->curs.y + def(term->esc_args[0], 1), 1);
term->seen_disp_event = TRUE;
break;
- case 'F': /* move up N lines and CR */
+ case 'F': /* CPL: move up N lines and CR */
compatibility(ANSI);
move(term, 0,
term->curs.y - def(term->esc_args[0], 1), 1);
term->seen_disp_event = TRUE;
break;
- case 'G':
- case '`': /* set horizontal posn */
+ case 'G': /* CHA */
+ case '`': /* HPA: set horizontal posn */
compatibility(ANSI);
move(term, def(term->esc_args[0], 1) - 1,
term->curs.y, 0);
term->seen_disp_event = TRUE;
break;
- case 'd': /* set vertical posn */
+ case 'd': /* VPA: set vertical posn */
compatibility(ANSI);
move(term, term->curs.x,
((term->dec_om ? term->marg_t : 0) +
(term->dec_om ? 2 : 0));
term->seen_disp_event = TRUE;
break;
- case 'H':
- case 'f': /* set horz and vert posns at once */
+ case 'H': /* CUP */
+ case 'f': /* HVP: set horz and vert posns at once */
if (term->esc_nargs < 2)
term->esc_args[1] = ARG_DEFAULT;
move(term, def(term->esc_args[1], 1) - 1,
(term->dec_om ? 2 : 0));
term->seen_disp_event = TRUE;
break;
- case 'J': /* erase screen or parts of it */
+ case 'J': /* ED: erase screen or parts of it */
{
unsigned int i = def(term->esc_args[0], 0) + 1;
if (i > 3)
term->disptop = 0;
term->seen_disp_event = TRUE;
break;
- case 'K': /* erase line or parts of it */
+ case 'K': /* EL: erase line or parts of it */
{
unsigned int i = def(term->esc_args[0], 0) + 1;
if (i > 3)
}
term->seen_disp_event = TRUE;
break;
- case 'L': /* insert lines */
+ case 'L': /* IL: insert lines */
compatibility(VT102);
if (term->curs.y <= term->marg_b)
scroll(term, term->curs.y, term->marg_b,
fix_cpos;
term->seen_disp_event = TRUE;
break;
- case 'M': /* delete lines */
+ case 'M': /* DL: delete lines */
compatibility(VT102);
if (term->curs.y <= term->marg_b)
scroll(term, term->curs.y, term->marg_b,
fix_cpos;
term->seen_disp_event = TRUE;
break;
- case '@': /* insert chars */
+ case '@': /* ICH: insert chars */
/* XXX VTTEST says this is vt220, vt510 manual says vt102 */
compatibility(VT102);
insch(term, def(term->esc_args[0], 1));
term->seen_disp_event = TRUE;
break;
- case 'P': /* delete chars */
+ case 'P': /* DCH: delete chars */
compatibility(VT102);
insch(term, -def(term->esc_args[0], 1));
term->seen_disp_event = TRUE;
break;
- case 'c': /* terminal type query */
+ case 'c': /* DA: terminal type query */
compatibility(VT100);
/* This is the response for a VT102 */
if (term->ldisc)
ldisc_send(term->ldisc, term->id_string,
strlen(term->id_string), 0);
break;
- case 'n': /* cursor position query */
+ case 'n': /* DSR: cursor position query */
if (term->ldisc) {
if (term->esc_args[0] == 6) {
char buf[32];
}
}
break;
- case 'h': /* toggle modes to high */
+ case 'h': /* SM: toggle modes to high */
case ANSI_QUE('h'):
compatibility(VT100);
{
term->esc_query, TRUE);
}
break;
- case 'i':
+ case 'i': /* MC: Media copy */
case ANSI_QUE('i'):
compatibility(VT100);
{
}
}
break;
- case 'l': /* toggle modes to low */
+ case 'l': /* RM: toggle modes to low */
case ANSI_QUE('l'):
compatibility(VT100);
{
term->esc_query, FALSE);
}
break;
- case 'g': /* clear tabs */
+ case 'g': /* TBC: clear tabs */
compatibility(VT100);
if (term->esc_nargs == 1) {
if (term->esc_args[0] == 0) {
}
}
break;
- case 'r': /* set scroll margins */
+ case 'r': /* DECSTBM: set scroll margins */
compatibility(VT100);
if (term->esc_nargs <= 2) {
int top, bot;
}
}
break;
- case 'm': /* set graphics rendition */
+ case 'm': /* SGR: set graphics rendition */
{
/*
* A VT100 without the AVO only had one
for (i = 0; i < term->esc_nargs; i++) {
switch (def(term->esc_args[i], 0)) {
case 0: /* restore defaults */
- term->curr_attr = ATTR_DEFAULT;
+ term->curr_attr = term->default_attr;
break;
case 1: /* enable bold */
compatibility(VT100AVO);
compatibility(VT100AVO);
term->curr_attr |= ATTR_BLINK;
break;
+ case 6: /* SCO light bkgrd */
+ compatibility(SCOANSI);
+ term->blink_is_real = FALSE;
+ term->curr_attr |= ATTR_BLINK;
+ break;
case 7: /* enable reverse video */
term->curr_attr |= ATTR_REVERSE;
break;
save_cursor(term, FALSE);
term->seen_disp_event = TRUE;
break;
- case 't': /* set page size - ie window height */
+ case 't': /* DECSLPP: set page size - ie window height */
/*
* VT340/VT420 sequence DECSLPP, DEC only allows values
* 24/25/36/48/72/144 other emulators (eg dtterm) use
*/
break;
case 20:
- if (term->ldisc) {
+ if (term->ldisc &&
+ !term->cfg.no_remote_qtitle) {
p = get_window_title(term->frontend, TRUE);
len = strlen(p);
ldisc_send(term->ldisc, "\033]L", 3, 0);
}
break;
case 21:
- if (term->ldisc) {
+ if (term->ldisc &&
+ !term->cfg.no_remote_qtitle) {
p = get_window_title(term->frontend,FALSE);
len = strlen(p);
ldisc_send(term->ldisc, "\033]l", 3, 0);
}
}
break;
- case 'S':
+ case 'S': /* SU: Scroll up */
compatibility(SCOANSI);
scroll(term, term->marg_t, term->marg_b,
def(term->esc_args[0], 1), TRUE);
term->wrapnext = FALSE;
term->seen_disp_event = TRUE;
break;
- case 'T':
+ case 'T': /* SD: Scroll down */
compatibility(SCOANSI);
scroll(term, term->marg_t, term->marg_b,
-def(term->esc_args[0], 1), TRUE);
term->wrapnext = FALSE;
term->seen_disp_event = TRUE;
break;
- case ANSI('|', '*'):
- /* VT420 sequence DECSNLS
+ case ANSI('|', '*'): /* DECSNLS */
+ /*
* Set number of lines on screen
- * VT420 uses VGA like hardware and can support any size in
- * reasonable range (24..49 AIUI) with no default specified.
+ * VT420 uses VGA like hardware and can
+ * support any size in reasonable range
+ * (24..49 AIUI) with no default specified.
*/
compatibility(VT420);
if (term->esc_nargs == 1 && term->esc_args[0] > 0) {
deselect(term);
}
break;
- case ANSI('|', '$'):
- /* VT340/VT420 sequence DECSCPP
+ case ANSI('|', '$'): /* DECSCPP */
+ /*
* Set number of columns per page
- * Docs imply range is only 80 or 132, but I'll allow any.
+ * Docs imply range is only 80 or 132, but
+ * I'll allow any.
*/
compatibility(VT340TEXT);
if (term->esc_nargs <= 1) {
deselect(term);
}
break;
- case 'X': /* write N spaces w/o moving cursor */
- /* XXX VTTEST says this is vt220, vt510 manual says vt100 */
+ case 'X': /* ECH: write N spaces w/o moving cursor */
+ /* XXX VTTEST says this is vt220, vt510 manual
+ * says vt100 */
compatibility(ANSIMIN);
{
int n = def(term->esc_args[0], 1);
term->seen_disp_event = TRUE;
}
break;
- case 'x': /* report terminal characteristics */
+ case 'x': /* DECREQTPARM: report terminal characteristics */
compatibility(VT100);
if (term->ldisc) {
char buf[32];
}
}
break;
- case 'Z': /* BackTab for xterm */
+ case 'Z': /* CBT: BackTab for xterm */
compatibility(OTHER);
{
int i = def(term->esc_args[0], 1);
check_selection(term, old_curs, term->curs);
}
break;
+ case ANSI('c', '='): /* Hide or Show Cursor */
+ compatibility(SCOANSI);
+ switch(term->esc_args[0]) {
+ case 0: /* hide cursor */
+ term->cursor_on = FALSE;
+ break;
+ case 1: /* restore cursor */
+ term->big_cursor = FALSE;
+ term->cursor_on = TRUE;
+ break;
+ case 2: /* block cursor */
+ term->big_cursor = TRUE;
+ term->cursor_on = TRUE;
+ break;
+ }
+ break;
+ case ANSI('C', '='):
+ /*
+ * set cursor start on scanline esc_args[0] and
+ * end on scanline esc_args[1].If you set
+ * the bottom scan line to a value less than
+ * the top scan line, the cursor will disappear.
+ */
+ compatibility(SCOANSI);
+ if (term->esc_nargs >= 2) {
+ if (term->esc_args[0] > term->esc_args[1])
+ term->cursor_on = FALSE;
+ else
+ term->cursor_on = TRUE;
+ }
+ break;
+ case ANSI('D', '='):
+ compatibility(SCOANSI);
+ term->blink_is_real = FALSE;
+ if (term->esc_args[0]>=1)
+ term->curr_attr |= ATTR_BLINK;
+ else
+ term->curr_attr &= ~ATTR_BLINK;
+ break;
+ case ANSI('E', '='):
+ compatibility(SCOANSI);
+ term->blink_is_real = (term->esc_args[0] >= 1);
+ break;
+ case ANSI('F', '='): /* set normal foreground */
+ compatibility(SCOANSI);
+ if (term->esc_args[0] >= 0 && term->esc_args[0] < 16) {
+ long colour =
+ (sco2ansicolour[term->esc_args[0] & 0x7] |
+ ((term->esc_args[0] & 0x8) << 1)) <<
+ ATTR_FGSHIFT;
+ term->curr_attr &= ~ATTR_FGMASK;
+ term->curr_attr |= colour;
+ term->default_attr &= ~ATTR_FGMASK;
+ term->default_attr |= colour;
+ }
+ break;
+ case ANSI('G', '='): /* set normal background */
+ compatibility(SCOANSI);
+ if (term->esc_args[0] >= 0 && term->esc_args[0] < 16) {
+ long colour =
+ (sco2ansicolour[term->esc_args[0] & 0x7] |
+ ((term->esc_args[0] & 0x8) << 1)) <<
+ ATTR_BGSHIFT;
+ term->curr_attr &= ~ATTR_BGMASK;
+ term->curr_attr |= colour;
+ term->default_attr &= ~ATTR_BGMASK;
+ term->default_attr |= colour;
+ }
+ break;
case ANSI('L', '='):
- compatibility(OTHER);
+ compatibility(SCOANSI);
term->use_bce = (term->esc_args[0] <= 0);
term->erase_char = ERASE_CHAR;
if (term->use_bce)
(term->curr_attr &
(ATTR_FGMASK | ATTR_BGMASK)));
break;
- case ANSI('E', '='):
- compatibility(OTHER);
- term->blink_is_real = (term->esc_args[0] >= 1);
- break;
- case ANSI('p', '"'):
+ case ANSI('p', '"'): /* DECSCL: set compat level */
/*
* Allow the host to make this emulator a
* 'perfect' VT102. This first appeared in
*/
void term_scroll(Terminal *term, int rel, int where)
{
- int sbtop = -count234(term->scrollback);
+ int sbtop = -sblines(term);
#ifdef OPTIMISE_SCROLL
int olddisptop = term->disptop;
int shift;
term_update(term);
}
-static void clipme(Terminal *term, pos top, pos bottom, int rect)
+static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel)
{
wchar_t *workbuf;
wchar_t *wbptr; /* where next char goes within workbuf */
int buflen; /* amount of memory allocated to workbuf */
buflen = 5120; /* Default size */
- workbuf = smalloc(buflen * sizeof(wchar_t));
+ workbuf = snewn(buflen, wchar_t);
wbptr = workbuf; /* start filling here */
old_top_x = top.x; /* needed for rect==1 */
for (p = cbuf; *p; p++) {
/* Enough overhead for trailing NL and nul */
if (wblen >= buflen - 16) {
- workbuf =
- srealloc(workbuf,
- sizeof(wchar_t) * (buflen += 100));
+ buflen += 100;
+ workbuf = sresize(workbuf, buflen, wchar_t);
wbptr = workbuf + wblen;
}
wblen++;
wblen++;
*wbptr++ = 0;
#endif
- write_clip(term->frontend, workbuf, wblen, FALSE); /* transfer to clipbd */
+ write_clip(term->frontend, workbuf, wblen, desel); /* transfer to clipbd */
if (buflen > 0) /* indicates we allocated this buffer */
sfree(workbuf);
}
void term_copyall(Terminal *term)
{
pos top;
- top.y = -count234(term->scrollback);
+ top.y = -sblines(term);
top.x = 0;
- clipme(term, top, term->curs, 0);
+ clipme(term, top, term->curs, 0, TRUE);
}
/*
{
unsigned long *ldata;
short wvalue;
- int topy = -count234(term->scrollback);
+ int topy = -sblines(term);
ldata = lineptr(p.y);
if (term->paste_buffer)
sfree(term->paste_buffer);
term->paste_pos = term->paste_hold = term->paste_len = 0;
- term->paste_buffer = smalloc(len * sizeof(wchar_t));
+ term->paste_buffer = snewn(len, wchar_t);
p = q = data;
while (p < data + len) {
* data to the clipboard.
*/
clipme(term, term->selstart, term->selend,
- (term->seltype == RECTANGULAR));
+ (term->seltype == RECTANGULAR), FALSE);
term->selstate = SELECTED;
} else
term->selstate = NO_SELECTION;
case PK_END: xkey = 'E'; break;
case PK_PAGEUP: xkey = 'I'; break;
case PK_PAGEDOWN: xkey = 'G'; break;
- default: break; /* else gcc warns `enum value not used' */
+ default: xkey=0; break; /* else gcc warns `enum value not used'*/
}
p += sprintf((char *) p, "\x1B%c", xkey);
goto done;
case PK_END: code = 4; break;
case PK_PAGEUP: code = 5; break;
case PK_PAGEDOWN: code = 6; break;
- default: break; /* else gcc warns `enum value not used' */
+ default: code = 0; break; /* else gcc warns `enum value not used' */
}
p += sprintf((char *) p, "\x1B[%d~", code);
goto done;
case PK_RIGHT: xkey = 'C'; break;
case PK_LEFT: xkey = 'D'; break;
case PK_REST: xkey = 'G'; break; /* centre key on number pad */
- default: break; /* else gcc warns `enum value not used' */
+ default: xkey = 0; break; /* else gcc warns `enum value not used' */
}
if (term->vt52_mode)
p += sprintf((char *) p, "\x1B%c", xkey);
return FALSE;
}
-/*
- * from_backend(), to get data from the backend for the terminal.
- */
-int from_backend(void *vterm, int is_stderr, char *data, int len)
+int term_data(Terminal *term, int is_stderr, const char *data, int len)
{
- Terminal *term = (Terminal *)vterm;
-
- assert(len > 0);
-
bufchain_add(&term->inbuf, data, len);
+ if (!term->in_term_out) {
+ term->in_term_out = TRUE;
+ term_blink(term, 1);
+ term_out(term);
+ term->in_term_out = FALSE;
+ }
+
/*
* term_out() always completely empties inbuf. Therefore,
* there's no reason at all to return anything other than zero