struct beeptime {
struct beeptime *next;
- long ticks;
+ unsigned long ticks;
};
static struct beeptime *beephead, *beeptail;
int nbeeps;
#define incpos(p) ( (p).x == cols ? ((p).x = 0, (p).y++, 1) : ((p).x++, 0) )
#define decpos(p) ( (p).x == 0 ? ((p).x = cols, (p).y--, 1) : ((p).x--, 0) )
+static bufchain inbuf; /* terminal input buffer */
static pos curs; /* cursor */
static pos savecurs; /* saved cursor position */
static int marg_t, marg_b; /* scroll margins */
static int insert; /* insert-mode flag */
static int cset; /* 0 or 1: which char set */
static int save_cset, save_csattr; /* saved with cursor position */
+static int save_utf; /* saved with cursor position */
static int rvideo; /* global reverse video flag */
-static int rvbell_timeout; /* for ESC[?5hESC[?5l vbell */
+static unsigned long rvbell_startpoint;/* for ESC[?5hESC[?5l vbell */
static int cursor_on; /* cursor enabled flag */
static int reset_132; /* Flag ESC c resets to 80 cols */
static int use_bce; /* Use Background coloured erase */
static int blink_is_real; /* Actually blink blinking text */
static int term_echoing; /* Does terminal want local echo? */
static int term_editing; /* Does terminal want local edit? */
+static int sco_acs, save_sco_acs; /* CSI 10,11,12m -> OEM charset */
static int vt52_bold; /* Force bold on non-bold colours */
static int utf_state; /* Is there a pending UTF-8 character */
static int utf_char; /* and what is it so far. */
/*
* Saved settings on the alternate screen.
*/
-static int alt_x, alt_y, alt_om, alt_wrap, alt_wnext, alt_ins, alt_cset;
+static int alt_x, alt_y, alt_om, alt_wrap, alt_wnext, alt_ins, alt_cset, alt_sco_acs, alt_utf;
static int alt_t, alt_b;
static int alt_which;
/* log session to file stuff ... */
static FILE *lgfp = NULL;
static void logtraffic(unsigned char c, int logmode);
+static void xlatlognam(char *d, char *s, char *hostname, struct tm *tm);
/*
* Resize a line to make it `cols' columns wide.
if (newline != line) {
delpos234(whichtree, treeindex);
addpos234(whichtree, newline, treeindex);
+ line = newline;
}
return line + 1;
alt_wnext = wrapnext = alt_ins = insert = FALSE;
alt_wrap = wrap = cfg.wrap_mode;
alt_cset = cset = 0;
+ alt_utf = utf = 0;
+ alt_sco_acs = sco_acs = 0;
cset_attr[0] = cset_attr[1] = ATTR_ASCII;
rvideo = 0;
in_vbell = FALSE;
big_cursor = 0;
save_attr = curr_attr = ATTR_DEFAULT;
term_editing = term_echoing = FALSE;
- ldisc_send(NULL, 0); /* cause ldisc to notice changes */
+ ldisc_send(NULL, 0, 0); /* cause ldisc to notice changes */
app_cursor_keys = cfg.app_cursor;
app_keypad_keys = cfg.app_keypad;
use_bce = cfg.bce;
Context ctx;
ctx = get_ctx();
if (ctx) {
- if (seen_disp_event)
- update_sbar();
+ int need_sbar_update = seen_disp_event;
if ((seen_key_event && (cfg.scroll_on_key)) ||
(seen_disp_event && (cfg.scroll_on_disp))) {
disptop = 0; /* return to main screen */
seen_disp_event = seen_key_event = 0;
+ need_sbar_update = TRUE;
}
+ if (need_sbar_update)
+ update_sbar();
do_paint(ctx, TRUE);
sys_cursor(curs.x, curs.y - disptop);
free_ctx(ctx);
update_sbar();
term_update();
+ back->size();
}
/*
t = cset;
cset = alt_cset;
alt_cset = t;
+ t = utf;
+ utf = alt_utf;
+ alt_utf = t;
+ t = sco_acs;
+ sco_acs = alt_sco_acs;
+ alt_sco_acs = t;
fix_cpos;
}
static void scroll(int topline, int botline, int lines, int sb)
{
unsigned long *line, *line2;
- int i;
+ int i, seltop;
if (topline != 0 || alt_which != 0)
sb = FALSE;
}
addpos234(scrollback, line, sblen);
line = line2;
+
+ /*
+ * If the user is currently looking at part of the
+ * scrollback, and they haven't enabled any options
+ * that are going to reset the scrollback as a
+ * result of this movement, then the chances are
+ * they'd like to keep looking at the same line. So
+ * we move their viewpoint at the same rate as the
+ * scroll, at least until their viewpoint hits the
+ * top end of the scrollback buffer, at which point
+ * we don't have the choice any more.
+ *
+ * Thanks to Jan Holmen Holsten for the idea and
+ * initial implementation.
+ */
+ if (disptop > -savelines && disptop < 0)
+ disptop--;
}
line = resizeline(line, cols);
for (i = 0; i < cols; i++)
line[cols + 1] = 0;
addpos234(screen, line, botline);
- if (selstart.y >= topline && selstart.y <= botline) {
+ /*
+ * If the selection endpoints move into the scrollback,
+ * we keep them moving until they hit the top. However,
+ * of course, if the line _hasn't_ moved into the
+ * scrollback then we don't do this, and cut them off
+ * at the top of the scroll region.
+ *
+ * This applies to selstart and selend (for an existing
+ * selection), and also selanchor (for one being
+ * selected as we speak).
+ */
+ seltop = sb ? -savelines : 0;
+
+ if (selstart.y >= seltop && selstart.y <= botline) {
selstart.y--;
- if (selstart.y < topline) {
- selstart.y = topline;
+ if (selstart.y < seltop) {
+ selstart.y = seltop;
selstart.x = 0;
}
}
- if (selend.y >= topline && selend.y <= botline) {
+ if (selend.y >= seltop && selend.y <= botline) {
selend.y--;
- if (selend.y < topline) {
- selend.y = topline;
+ if (selend.y < seltop) {
+ selend.y = seltop;
selend.x = 0;
}
}
+ if (selanchor.y >= seltop && selanchor.y <= botline) {
+ selanchor.y--;
+ if (selanchor.y < seltop) {
+ selanchor.y = seltop;
+ selanchor.x = 0;
+ }
+ }
lines--;
}
savecurs = curs;
save_attr = curr_attr;
save_cset = cset;
+ save_utf = utf;
save_csattr = cset_attr[cset];
+ save_sco_acs = sco_acs;
} else {
curs = savecurs;
/* Make sure the window hasn't shrunk since the save */
curr_attr = save_attr;
cset = save_cset;
+ utf = save_utf;
cset_attr[cset] = save_csattr;
+ sco_acs = save_sco_acs;
fix_cpos;
if (use_bce)
- erase_char = (' ' | (curr_attr & (ATTR_FGMASK | ATTR_BGMASK)));
+ erase_char = (' ' | ATTR_ASCII |
+ (curr_attr & (ATTR_FGMASK | ATTR_BGMASK)));
}
}
}
if (!to_end) {
end = curs;
+ incpos(end);
}
check_selection(start, end);
ldata = lineptr(start.y);
while (poslt(start, end)) {
- if (start.y == cols && !erase_lattr)
+ if (start.x == cols && !erase_lattr)
ldata[start.x] &= ~LATTR_WRAPPED;
else
ldata[start.x] = erase_char;
*/
static void toggle_mode(int mode, int query, int state)
{
- long ticks;
+ unsigned long ticks;
if (query)
switch (mode) {
break;
case 3: /* 80/132 columns */
deselect();
- request_resize(state ? 132 : 80, rows, 1);
+ request_resize(state ? 132 : 80, rows);
reset_132 = state;
break;
case 5: /* reverse video */
* always be an actually _visible_ visual bell.
*/
ticks = GetTickCount();
- if (rvideo && !state && /* we're turning it off */
- ticks < rvbell_timeout) { /* and it's not long since it was turned on */
+ /* turn off a previous vbell to avoid inconsistencies */
+ if (ticks - vbell_startpoint >= VBELL_TIMEOUT)
+ in_vbell = FALSE;
+ if (rvideo && !state && /* we're turning it off... */
+ (ticks - rvbell_startpoint) < VBELL_TIMEOUT) { /* ...soon */
+ /* If there's no vbell timeout already, or this one lasts
+ * longer, replace vbell_timeout with ours. */
+ if (!in_vbell ||
+ (rvbell_startpoint - vbell_startpoint < VBELL_TIMEOUT))
+ vbell_startpoint = rvbell_startpoint;
in_vbell = TRUE; /* we may clear rvideo but we set in_vbell */
- if (vbell_timeout < rvbell_timeout) /* don't move vbell end forward */
- vbell_timeout = rvbell_timeout; /* vbell end is at least then */
} else if (!rvideo && state) {
/* This is an ON, so we notice the time and save it. */
- rvbell_timeout = ticks + VBELL_TIMEOUT;
+ rvbell_startpoint = ticks;
}
rvideo = state;
seen_disp_event = TRUE;
break;
case 10: /* set local edit mode */
term_editing = state;
- ldisc_send(NULL, 0); /* cause ldisc to notice changes */
+ ldisc_send(NULL, 0, 0); /* cause ldisc to notice changes */
break;
case 25: /* enable/disable cursor */
compatibility2(OTHER, VT220);
break;
case 12: /* set echo mode */
term_echoing = !state;
- ldisc_send(NULL, 0); /* cause ldisc to notice changes */
+ ldisc_send(NULL, 0, 0); /* cause ldisc to notice changes */
break;
case 20: /* Return sends ... */
cr_lf_return = state;
*/
void term_out(void)
{
- int c, inbuf_reap;
-
- for (inbuf_reap = 0; inbuf_reap < inbuf_head; inbuf_reap++) {
- c = inbuf[inbuf_reap];
+ int c, unget;
+ unsigned char localbuf[256], *chars;
+ int nchars = 0;
+
+ unget = -1;
+
+ while (nchars > 0 || bufchain_size(&inbuf) > 0) {
+ if (unget == -1) {
+ if (nchars == 0) {
+ void *ret;
+ bufchain_prefix(&inbuf, &ret, &nchars);
+ if (nchars > sizeof(localbuf))
+ nchars = sizeof(localbuf);
+ memcpy(localbuf, ret, nchars);
+ bufchain_consume(&inbuf, nchars);
+ chars = localbuf;
+ assert(chars != NULL);
+ }
+ c = *chars++;
+ nchars--;
- /*
- * Optionally log the session traffic to a file. Useful for
- * debugging and possibly also useful for actual logging.
- */
- logtraffic((unsigned char) c, LGTYP_DEBUG);
+ /*
+ * Optionally log the session traffic to a file. Useful for
+ * debugging and possibly also useful for actual logging.
+ */
+ if (cfg.logtype == LGTYP_DEBUG)
+ logtraffic((unsigned char) c, LGTYP_DEBUG);
+ } else {
+ c = unget;
+ unget = -1;
+ }
/* Note only VT220+ are 8-bit VT102 is seven bit, it shouldn't even
* be able to display 8-bit characters, but I'll let that go 'cause
/* First see about all those translations. */
if (termstate == TOPLEVEL) {
- if (utf)
+ if (in_utf)
switch (utf_state) {
case 0:
if (c < 0x80) {
- /* I know; gotos are evil. This one is really bad!
- * But before you try removing it follow the path of the
- * sequence "0x5F 0xC0 0x71" with UTF and VTGraphics on.
- */
- /*
- if (cfg.no_vt_graph_with_utf8) break;
- */
- goto evil_jump;
+ /* UTF-8 must be stateless so we ignore iso2022. */
+ if (unitab_ctrl[c] != 0xFF)
+ c = unitab_ctrl[c];
+ else c = ((unsigned char)c) | ATTR_ASCII;
+ break;
} else if ((c & 0xe0) == 0xc0) {
utf_size = utf_state = 1;
utf_char = (c & 0x1f);
case 4:
case 5:
if ((c & 0xC0) != 0x80) {
- inbuf_reap--; /* This causes the faulting character */
- c = UCSERR; /* to be logged twice - not really a */
- utf_state = 0; /* serious problem. */
+ unget = c;
+ c = UCSERR;
+ utf_state = 0;
break;
}
utf_char = (utf_char << 6) | (c & 0x3f);
if (c >= 0x10000)
c = 0xFFFD;
break;
+ }
+ /* Are we in the nasty ACS mode? Note: no sco in utf mode. */
+ else if(sco_acs &&
+ (c!='\033' && c!='\n' && c!='\r' && c!='\b'))
+ {
+ if (sco_acs == 2) c ^= 0x80;
+ c |= ATTR_SCOACS;
} else {
- evil_jump:;
switch (cset_attr[cset]) {
/*
* Linedraw characters are different from 'ESC ( B'
else
c = ((unsigned char) c) | ATTR_ASCII;
break;
+ case ATTR_SCOACS:
+ if (c>=' ') c = ((unsigned char)c) | ATTR_SCOACS;
+ break;
}
}
}
} else
*d++ = *s;
}
- lpage_send(CP_ACP, abuf, d - abuf);
+ lpage_send(CP_ACP, abuf, d - abuf, 0);
}
break;
case '\007':
{
struct beeptime *newbeep;
- long ticks;
+ unsigned long ticks;
ticks = GetTickCount();
}
if (cfg.bellovl && beep_overloaded &&
- ticks - lastbeep >= cfg.bellovl_s) {
+ ticks - lastbeep >= (unsigned)cfg.bellovl_s) {
/*
* If we're currently overloaded and the
* last beep was more than s seconds ago,
beep(cfg.beep);
if (cfg.beep == BELL_VISUAL) {
in_vbell = TRUE;
- vbell_timeout = ticks + VBELL_TIMEOUT;
+ vbell_startpoint = ticks;
term_update();
}
}
width = wcwidth((wchar_t) c);
switch (width) {
case 2:
- if (curs.x + 1 != cols) {
- *cpos++ = c | ATTR_WIDE | curr_attr;
- *cpos++ = UCSWIDE | curr_attr;
- curs.x++;
- break;
+ *cpos++ = c | curr_attr;
+ if (++curs.x == cols) {
+ *cpos |= LATTR_WRAPPED;
+ if (curs.y == marg_b)
+ scroll(marg_t, marg_b, 1, TRUE);
+ else if (curs.y < rows - 1)
+ curs.y++;
+ curs.x = 0;
+ fix_cpos;
}
+ *cpos++ = UCSWIDE | curr_attr;
+ break;
case 1:
*cpos++ = c | curr_attr;
break;
break;
case 'Z': /* terminal type query */
compatibility(VT100);
- ldisc_send(id_string, strlen(id_string));
+ ldisc_send(id_string, strlen(id_string), 0);
break;
case 'c': /* restore power-on settings */
compatibility(VT100);
power_on();
if (reset_132) {
- request_resize(80, rows, 1);
+ request_resize(80, rows);
reset_132 = 0;
}
fix_cpos;
compatibility(VT100);
cset_attr[0] = ATTR_LINEDRW;
break;
+ case ANSI('U', '('):
+ compatibility(OTHER);
+ cset_attr[0] = ATTR_SCOACS;
+ break;
case ANSI('A', ')'):
compatibility(VT100);
compatibility(VT100);
cset_attr[1] = ATTR_LINEDRW;
break;
+ case ANSI('U', ')'):
+ compatibility(OTHER);
+ cset_attr[1] = ATTR_SCOACS;
+ break;
case ANSI('8', '%'): /* Old Linux code */
case ANSI('G', '%'):
break;
case ANSI('@', '%'):
compatibility(OTHER);
- if (line_codepage != CP_UTF8)
- utf = 0;
+ utf = 0;
break;
}
break;
break;
case 'e': /* move down N lines */
compatibility(ANSI);
+ /* FALLTHROUGH */
case 'B':
move(curs.x, curs.y + def(esc_args[0], 1), 1);
seen_disp_event = TRUE;
break;
- case 'a': /* move right N cols */
- compatibility(ANSI);
case ANSI('c', '>'): /* report xterm version */
compatibility(OTHER);
/* this reports xterm version 136 so that VIM can
use the drag messages from the mouse reporting */
- ldisc_send("\033[>0;136;0c", 11);
+ ldisc_send("\033[>0;136;0c", 11, 0);
break;
+ case 'a': /* move right N cols */
+ compatibility(ANSI);
+ /* FALLTHROUGH */
case 'C':
move(curs.x + def(esc_args[0], 1), curs.y, 1);
seen_disp_event = TRUE;
case 'c': /* terminal type query */
compatibility(VT100);
/* This is the response for a VT102 */
- ldisc_send(id_string, strlen(id_string));
+ ldisc_send(id_string, strlen(id_string), 0);
break;
case 'n': /* cursor position query */
if (esc_args[0] == 6) {
char buf[32];
sprintf(buf, "\033[%d;%dR", curs.y + 1,
curs.x + 1);
- ldisc_send(buf, strlen(buf));
+ ldisc_send(buf, strlen(buf), 0);
} else if (esc_args[0] == 5) {
- ldisc_send("\033[0n", 4);
+ ldisc_send("\033[0n", 4, 0);
}
break;
case 'h': /* toggle modes to high */
case 7: /* enable reverse video */
curr_attr |= ATTR_REVERSE;
break;
+ case 10: /* SCO acs off */
+ compatibility(SCOANSI);
+ sco_acs = 0; break;
+ case 11: /* SCO acs on */
+ compatibility(SCOANSI);
+ sco_acs = 1; break;
+ case 12: /* SCO acs on flipped */
+ compatibility(SCOANSI);
+ sco_acs = 2; break;
case 22: /* disable bold */
compatibility2(OTHER, VT220);
curr_attr &= ~ATTR_BOLD;
}
}
if (use_bce)
- erase_char =
- (' ' |
- (curr_attr &
- (ATTR_FGMASK | ATTR_BGMASK |
- ATTR_BLINK)));
+ erase_char = (' ' | ATTR_ASCII |
+ (curr_attr &
+ (ATTR_FGMASK | ATTR_BGMASK)));
}
break;
case 's': /* save cursor */
compatibility(VT340TEXT);
if (esc_nargs <= 1
&& (esc_args[0] < 1 || esc_args[0] >= 24)) {
- request_resize(cols, def(esc_args[0], 24), 0);
+ request_resize(cols, def(esc_args[0], 24));
deselect();
}
break;
*/
compatibility(VT420);
if (esc_nargs == 1 && esc_args[0] > 0) {
- request_resize(cols,
- def(esc_args[0], cfg.height),
- 0);
+ request_resize(cols, def(esc_args[0], cfg.height));
deselect();
}
break;
*/
compatibility(VT340TEXT);
if (esc_nargs <= 1) {
- request_resize(def(esc_args[0], cfg.width),
- rows, 0);
+ request_resize(def(esc_args[0], cfg.width), rows);
deselect();
}
break;
if (i == 0 || i == 1) {
strcpy(buf, "\033[2;1;1;112;112;1;0x");
buf[2] += i;
- ldisc_send(buf, 20);
+ ldisc_send(buf, 20, 0);
+ }
+ }
+ break;
+ case 'Z': /* BackTab for xterm */
+ compatibility(OTHER);
+ {
+ int i = def(esc_args[0], 1);
+ pos old_curs = curs;
+
+ for(;i>0 && curs.x>0; i--) {
+ do {
+ curs.x--;
+ } while (curs.x >0 && !tabs[curs.x]);
}
+ fix_cpos;
+ check_selection(old_curs, curs);
}
break;
case ANSI('L', '='):
use_bce = (esc_args[0] <= 0);
erase_char = ERASE_CHAR;
if (use_bce)
- erase_char =
- (' ' |
- (curr_attr &
- (ATTR_FGMASK | ATTR_BGMASK)));
+ erase_char = (' ' | ATTR_ASCII |
+ (curr_attr &
+ (ATTR_FGMASK | ATTR_BGMASK)));
break;
case ANSI('E', '='):
compatibility(OTHER);
*/
if (!has_compat(VT420) && has_compat(VT100)) {
if (reset_132)
- request_resize(132, 24, 1);
+ request_resize(132, 24);
else
- request_resize(80, 24, 1);
+ request_resize(80, 24);
}
#endif
break;
termstate = VT52_Y1;
break;
case 'Z':
- ldisc_send("\033/Z", 3);
+ ldisc_send("\033/Z", 3, 0);
break;
case '=':
app_keypad_keys = TRUE;
vt52_bold = FALSE;
curr_attr = ATTR_DEFAULT;
if (use_bce)
- erase_char = (' ' |
- (curr_attr &
- (ATTR_FGMASK | ATTR_BGMASK |
- ATTR_BLINK)));
+ erase_char = (' ' | ATTR_ASCII |
+ (curr_attr &
+ (ATTR_FGMASK | ATTR_BGMASK)));
break;
case 'S':
/* compatibility(VI50) */
curr_attr |= ATTR_BOLD;
if (use_bce)
- erase_char = (' ' |
- (curr_attr &
- (ATTR_FGMASK | ATTR_BGMASK |
- ATTR_BLINK)));
+ erase_char = (' ' | ATTR_ASCII |
+ (curr_attr & (ATTR_FGMASK | ATTR_BGMASK)));
break;
case VT52_BG:
termstate = TOPLEVEL;
curr_attr |= ATTR_BLINK;
if (use_bce)
- erase_char = (' ' |
- (curr_attr &
- (ATTR_FGMASK | ATTR_BGMASK |
- ATTR_BLINK)));
+ erase_char = (' ' | ATTR_ASCII |
+ (curr_attr & (ATTR_FGMASK | ATTR_BGMASK)));
break;
#endif
default: break; /* placate gcc warning about enum use */
check_selection(curs, cursplus);
}
}
- inbuf_head = 0;
}
#if 0
pos scrpos;
char ch[1024];
long cursor_background = ERASE_CHAR;
- long ticks;
+ unsigned long ticks;
/*
* Check the visual bell state.
*/
if (in_vbell) {
ticks = GetTickCount();
- if (ticks - vbell_timeout >= 0)
- in_vbell = FALSE;
- }
+ if (ticks - vbell_startpoint >= VBELL_TIMEOUT)
+ in_vbell = FALSE;
+ }
rv = (!rvideo ^ !in_vbell ? ATTR_REVERSE : 0);
if (dispcurs && (curstype != cursor ||
dispcurs !=
disptext + our_curs_y * (cols + 1) + curs.x)) {
- if (dispcurs > disptext && (dispcurs[-1] & ATTR_WIDE))
+ if (dispcurs > disptext &&
+ (*dispcurs & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
dispcurs[-1] |= ATTR_INVALID;
- if ((*dispcurs & ATTR_WIDE))
+ if ( (dispcurs[1] & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
dispcurs[1] |= ATTR_INVALID;
*dispcurs |= ATTR_INVALID;
curstype = 0;
case ATTR_LINEDRW:
tchar = unitab_xterm[tchar & 0xFF];
break;
+ case ATTR_SCOACS:
+ tchar = unitab_scoacs[tchar&0xFF];
+ break;
}
tattr |= (tchar & CSET_MASK);
tchar &= CHAR_MASK;
+ if ((d[1] & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
+ tattr |= ATTR_WIDE;
/* Video reversing things */
tattr = (tattr ^ rv
tattr &= ~ATTR_BLINK;
}
+ /*
+ * Check the font we'll _probably_ be using to see if
+ * the character is wide when we don't want it to be.
+ */
+ if ((tchar | tattr) != (disptext[idx]& ~ATTR_NARROW)) {
+ if ((tattr & ATTR_WIDE) == 0 &&
+ CharWidth(ctx, (tchar | tattr) & 0xFFFF) == 2)
+ tattr |= ATTR_NARROW;
+ } else if (disptext[idx]&ATTR_NARROW)
+ tattr |= ATTR_NARROW;
+
/* Cursor here ? Save the 'background' */
if (i == our_curs_y && j == curs.x) {
cursor_background = tattr | tchar;
/*
* Paint the window in response to a WM_PAINT message.
*/
-void term_paint(Context ctx, int l, int t, int r, int b)
+void term_paint(Context ctx, int left, int top, int right, int bottom)
{
- int i, j, left, top, right, bottom;
+ int i, j;
+ if (left < 0) left = 0;
+ if (top < 0) top = 0;
+ if (right >= cols) right = cols-1;
+ if (bottom >= rows) bottom = rows-1;
- left = l / font_width;
- right = (r - 1) / font_width;
- top = t / font_height;
- bottom = (b - 1) / font_height;
for (i = top; i <= bottom && i < rows; i++) {
if ((disptext[i * (cols + 1) + cols] & LATTR_MODE) == LATTR_NORM)
for (j = left; j <= right && j < cols; j++)
/* This should happen soon enough, also for some reason it sometimes
* fails to actually do anything when re-sizing ... painting the wrong
* window perhaps ?
- do_paint (ctx, FALSE);
*/
+ if (alt_pressed)
+ do_paint (ctx, FALSE);
}
/*
case ATTR_ASCII:
uc = unitab_line[uc & 0xFF];
break;
+ case ATTR_SCOACS:
+ uc = unitab_scoacs[uc&0xFF];
+ break;
}
switch (uc & CSET_MASK) {
case ATTR_ACP:
case ATTR_ASCII:
uc = unitab_line[uc & 0xFF];
break;
+ case ATTR_SCOACS:
+ uc = unitab_scoacs[uc&0xFF];
+ break;
}
switch (uc & CSET_MASK) {
case ATTR_ACP:
break;
}
+ /* For DBCS font's I can't do anything usefull. Even this will sometimes
+ * fail as there's such a thing as a double width space. :-(
+ */
+ if (dbcs_screenfont && font_codepage == line_codepage)
+ return (uc != ' ');
+
if (uc < 0x80)
return wordness[uc];
/* Assume a small paste will be OK in one go. */
if (paste_len < 256) {
- luni_send(paste_buffer, paste_len);
+ luni_send(paste_buffer, paste_len, 0);
if (paste_buffer)
sfree(paste_buffer);
paste_buffer = 0;
{
pos selpoint;
unsigned long *ldata;
+ int raw_mouse = xterm_mouse && !(cfg.mouse_override && shift);
- if (y < 0)
+ if (y < 0) {
y = 0;
- if (y >= rows)
+ if (a == MA_DRAG && !raw_mouse)
+ term_scroll(0, -1);
+ }
+ if (y >= rows) {
y = rows - 1;
+ if (a == MA_DRAG && !raw_mouse)
+ term_scroll(0, +1);
+ }
if (x < 0) {
if (y > 0) {
x = cols - 1;
if ((ldata[cols] & LATTR_MODE) != LATTR_NORM)
selpoint.x /= 2;
- if (xterm_mouse) {
+ if (raw_mouse) {
int encstate = 0, r, c;
char abuf[16];
static int is_down = 0;
c = x + 33;
sprintf(abuf, "\033[M%c%c%c", encstate, c, r);
- ldisc_send(abuf, 6);
+ ldisc_send(abuf, 6, 0);
return;
}
if (paste_buffer[paste_pos + n++] == '\r')
break;
}
- luni_send(paste_buffer + paste_pos, n);
+ luni_send(paste_buffer + paste_pos, n, 0);
paste_pos += n;
if (paste_pos < paste_len) {
/*
* from_backend(), to get data from the backend for the terminal.
*/
-void from_backend(int is_stderr, char *data, int len)
+int from_backend(int is_stderr, char *data, int len)
{
- while (len--) {
- if (inbuf_head >= INBUF_SIZE)
- term_out();
- inbuf[inbuf_head++] = *data++;
- }
+ bufchain_add(&inbuf, data, len);
+
+ /*
+ * term_out() always completely empties inbuf. Therefore,
+ * there's no reason at all to return anything other than zero
+ * from this function, because there _can't_ be a question of
+ * the remote side needing to wait until term_out() has cleared
+ * a backlog.
+ *
+ * This is a slightly suboptimal way to deal with SSH2 - in
+ * principle, the window mechanism would allow us to continue
+ * to accept data on forwarded ports and X connections even
+ * while the terminal processing was going slowly - but we
+ * can't do the 100% right thing without moving the terminal
+ * processing into a separate thread, and that might hurt
+ * portability. So we manage stdout buffering the old SSH1 way:
+ * if the terminal processing goes slowly, the whole SSH
+ * connection stops accepting data until it's ready.
+ *
+ * In practice, I can't imagine this causing serious trouble.
+ */
+ return 0;
}
/*
}
}
+void settimstr(char *ta, int no_sec);
+char *subslfcode(char *dest, char *src, char *dstrt);
+char *stpncpy(char *dst, const char *src, size_t maxlen);
+char timdatbuf[20];
+char currlogfilename[FILENAME_MAX];
+
/* open log file append/overwrite mode */
void logfopen(void)
{
char buf[256];
time_t t;
- struct tm *tm;
+ struct tm tm;
char writemod[4];
if (!cfg.logtype)
return;
sprintf(writemod, "wb"); /* default to rewrite */
- lgfp = fopen(cfg.logfilename, "r"); /* file already present? */
+
+ time(&t);
+ tm = *localtime(&t);
+
+ /* substitute special codes in file name */
+ xlatlognam(currlogfilename,cfg.logfilename,cfg.host, &tm);
+
+ lgfp = fopen(currlogfilename, "r"); /* file already present? */
if (lgfp) {
int i;
fclose(lgfp);
- i = askappend(cfg.logfilename);
+ i = askappend(currlogfilename);
if (i == 1)
writemod[0] = 'a'; /* set append mode */
else if (i == 0) { /* cancelled */
}
}
- lgfp = fopen(cfg.logfilename, writemod);
+ lgfp = fopen(currlogfilename, writemod);
if (lgfp) { /* enter into event log */
sprintf(buf, "%s session log (%s mode) to file : ",
(writemod[0] == 'a') ? "Appending" : "Writing new",
(cfg.logtype == LGTYP_ASCII ? "ASCII" :
cfg.logtype == LGTYP_DEBUG ? "raw" : "<ukwn>"));
/* Make sure we do not exceed the output buffer size */
- strncat(buf, cfg.logfilename, 128);
+ strncat(buf, currlogfilename, 128);
buf[strlen(buf)] = '\0';
logevent(buf);
- /* --- write header line iinto log file */
+ /* --- write header line into log file */
fputs("=~=~=~=~=~=~=~=~=~=~=~= PuTTY log ", lgfp);
- time(&t);
- tm = localtime(&t);
- strftime(buf, 24, "%Y.%m.%d %H:%M:%S", tm);
+ strftime(buf, 24, "%Y.%m.%d %H:%M:%S", &tm);
fputs(buf, lgfp);
fputs(" =~=~=~=~=~=~=~=~=~=~=~=\r\n", lgfp);
}
lgfp = NULL;
}
}
+
+/*
+ * translate format codes into time/date strings
+ * and insert them into log file name
+ *
+ * "&Y":YYYY "&m":MM "&d":DD "&T":hhmm "&h":<hostname> "&&":&
+ */
+static void xlatlognam(char *d, char *s, char *hostname, struct tm *tm) {
+ char buf[10], *bufp;
+ int size;
+ char *ds = d; /* save start pos. */
+ int len = FILENAME_MAX-1;
+
+ while (*s) {
+ /* Let (bufp, len) be the string to append. */
+ bufp = buf; /* don't usually override this */
+ if (*s == '&') {
+ char c;
+ s++;
+ if (*s) switch (c = *s++, tolower(c)) {
+ case 'y':
+ size = strftime(buf, sizeof(buf), "%Y", tm);
+ break;
+ case 'm':
+ size = strftime(buf, sizeof(buf), "%m", tm);
+ break;
+ case 'd':
+ size = strftime(buf, sizeof(buf), "%d", tm);
+ break;
+ case 't':
+ size = strftime(buf, sizeof(buf), "%H%M%S", tm);
+ break;
+ case 'h':
+ bufp = hostname;
+ size = strlen(bufp);
+ break;
+ default:
+ buf[0] = '&';
+ size = 1;
+ if (c != '&')
+ buf[size++] = c;
+ }
+ } else {
+ buf[0] = *s++;
+ size = 1;
+ }
+ if (size > len)
+ size = len;
+ memcpy(d, bufp, size);
+ d += size;
+ len -= size;
+ }
+ *d = '\0';
+}