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) )
+/* Product-order comparisons for rectangular block selection. */
+#define posPlt(p1,p2) ( (p1).y <= (p2).y && (p1).x < (p2).x )
+#define posPle(p1,p2) ( (p1).y <= (p2).y && (p1).x <= (p2).x )
+
static bufchain inbuf; /* terminal input buffer */
static pos curs; /* cursor */
static pos savecurs; /* saved cursor position */
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 save_utf, save_wnext; /* 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 utf_state; /* Is there a pending UTF-8 character */
static int utf_char; /* and what is it so far. */
static int utf_size; /* The size of the UTF character. */
+static int printing, only_printing; /* Are we doing ANSI printing? */
+static int print_state; /* state of print-end-sequence scan */
+static bufchain printer_buf; /* buffered data for printer */
+static printer_job *print_job;
static int xterm_mouse; /* send mouse messages to app */
static enum {
NO_SELECTION, ABOUT_TO, DRAGGING, SELECTED
} selstate;
+static enum {
+ LEXICOGRAPHIC, RECTANGULAR
+} seltype;
static enum {
SM_CHAR, SM_WORD, SM_LINE
} selmode;
static void swap_screen(int);
static void update_sbar(void);
static void deselect(void);
-/* 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);
+static void term_print_finish(void);
/*
* Resize a line to make it `cols' columns wide.
blink_is_real = cfg.blinktext;
erase_char = ERASE_CHAR;
alt_which = 0;
+ term_print_finish();
{
int i;
for (i = 0; i < 256; i++)
term_update();
}
+/*
+ * When the user reconfigures us, we need to check the forbidden-
+ * alternate-screen config option, disable raw mouse mode if the
+ * user has disabled mouse reporting, and abandon a print job if
+ * the user has disabled printing.
+ */
+void term_reconfig(void)
+{
+ if (cfg.no_alt_screen)
+ swap_screen(0);
+ if (cfg.no_mouse_rep) {
+ xterm_mouse = 0;
+ set_raw_mouse_mode(0);
+ }
+ if (cfg.no_remote_charset) {
+ cset_attr[0] = cset_attr[1] = ATTR_ASCII;
+ sco_acs = alt_sco_acs = 0;
+ utf = 0;
+ }
+ if (!*cfg.printer) {
+ term_print_finish();
+ }
+}
+
/*
* Clear the scrollback.
*/
* selection), and also selanchor (for one being
* selected as we speak).
*/
- seltop = sb ? -savelines : 0;
+ seltop = sb ? -savelines : topline;
if (selstart.y >= seltop && selstart.y <= botline) {
selstart.y--;
save_attr = curr_attr;
save_cset = cset;
save_utf = utf;
+ save_wnext = wrapnext;
save_csattr = cset_attr[cset];
save_sco_acs = sco_acs;
} else {
curr_attr = save_attr;
cset = save_cset;
utf = save_utf;
+ wrapnext = save_wnext;
+ /*
+ * wrapnext might reset to False if the x position is no
+ * longer at the rightmost edge.
+ */
+ if (wrapnext && curs.x < cols-1)
+ wrapnext = FALSE;
cset_attr[cset] = save_csattr;
sco_acs = save_sco_acs;
fix_cpos;
*/
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);
+ if (!cfg.no_remote_resize)
+ 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;
case 47: /* alternate screen */
compatibility(OTHER);
deselect();
- swap_screen(state);
+ swap_screen(cfg.no_alt_screen ? 0 : state);
disptop = 0;
break;
case 1000: /* xterm mouse 1 */
switch (esc_args[0]) {
case 0:
case 1:
- set_icon(osc_string);
+ if (!cfg.no_remote_wintitle)
+ set_icon(osc_string);
if (esc_args[0] == 1)
break;
/* fall through: parameter 0 means set both */
case 2:
case 21:
- set_title(osc_string);
+ if (!cfg.no_remote_wintitle)
+ set_title(osc_string);
+ break;
+ }
+ }
+}
+
+/*
+ * ANSI printing routines.
+ */
+static void term_print_setup(void)
+{
+ bufchain_clear(&printer_buf);
+ print_job = printer_start_job(cfg.printer);
+}
+static void term_print_flush(void)
+{
+ void *data;
+ int len;
+ int size;
+ while ((size = bufchain_size(&printer_buf)) > 5) {
+ bufchain_prefix(&printer_buf, &data, &len);
+ if (len > size-5)
+ len = size-5;
+ printer_job_data(print_job, data, len);
+ bufchain_consume(&printer_buf, len);
+ }
+}
+static void term_print_finish(void)
+{
+ void *data;
+ int len, size;
+ char c;
+
+ term_print_flush();
+ while ((size = bufchain_size(&printer_buf)) > 0) {
+ bufchain_prefix(&printer_buf, &data, &len);
+ c = *(char *)data;
+ if (c == '\033' || c == '\233') {
+ bufchain_consume(&printer_buf, size);
break;
+ } else {
+ printer_job_data(print_job, &c, 1);
+ bufchain_consume(&printer_buf, 1);
}
}
+ printer_finish_job(print_job);
+ print_job = NULL;
+ printing = only_printing = FALSE;
}
/*
* debugging and possibly also useful for actual logging.
*/
if (cfg.logtype == LGTYP_DEBUG)
- logtraffic((unsigned char) &c, LGTYP_DEBUG);
+ logtraffic((unsigned char) c, LGTYP_DEBUG);
} else {
c = unget;
unget = -1;
* of i18n.
*/
+ /*
+ * If we're printing, add the character to the printer
+ * buffer.
+ */
+ if (printing) {
+ char cc = c;
+ bufchain_add(&printer_buf, &c, 1);
+
+ /*
+ * If we're in print-only mode, we use a much simpler
+ * state machine designed only to recognise the ESC[4i
+ * termination sequence.
+ */
+ if (only_printing) {
+ if (c == '\033')
+ print_state = 1;
+ else if (c == (unsigned char)'\233')
+ print_state = 2;
+ else if (c == '[' && print_state == 1)
+ print_state = 2;
+ else if (c == '4' && print_state == 2)
+ print_state = 3;
+ else if (c == 'i' && print_state == 3)
+ print_state = 4;
+ else
+ print_state = 0;
+ if (print_state == 4) {
+ printing = only_printing = FALSE;
+ term_print_finish();
+ }
+ continue;
+ }
+ }
+
/* First see about all those translations. */
if (termstate == TOPLEVEL) {
if (in_utf)
curs.x--;
wrapnext = FALSE;
fix_cpos;
- *cpos = (' ' | curr_attr | ATTR_ASCII);
+ if (!cfg.no_dbackspace) /* destructive bksp might be disabled */
+ *cpos = (' ' | curr_attr | ATTR_ASCII);
} else
/* Or normal C0 controls. */
if ((c & -32) == 0 && termstate < DO_CTRLS) {
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();
}
}
compatibility(VT100);
power_on();
if (reset_132) {
- request_resize(80, rows);
+ if (!cfg.no_remote_resize)
+ request_resize(80, rows);
reset_132 = 0;
}
fix_cpos;
case ANSI('A', '('):
compatibility(VT100);
- cset_attr[0] = ATTR_GBCHR;
+ if (!cfg.no_remote_charset)
+ cset_attr[0] = ATTR_GBCHR;
break;
case ANSI('B', '('):
compatibility(VT100);
- cset_attr[0] = ATTR_ASCII;
+ if (!cfg.no_remote_charset)
+ cset_attr[0] = ATTR_ASCII;
break;
case ANSI('0', '('):
compatibility(VT100);
- cset_attr[0] = ATTR_LINEDRW;
+ if (!cfg.no_remote_charset)
+ cset_attr[0] = ATTR_LINEDRW;
break;
case ANSI('U', '('):
compatibility(OTHER);
- cset_attr[0] = ATTR_SCOACS;
+ if (!cfg.no_remote_charset)
+ cset_attr[0] = ATTR_SCOACS;
break;
case ANSI('A', ')'):
compatibility(VT100);
- cset_attr[1] = ATTR_GBCHR;
+ if (!cfg.no_remote_charset)
+ cset_attr[1] = ATTR_GBCHR;
break;
case ANSI('B', ')'):
compatibility(VT100);
- cset_attr[1] = ATTR_ASCII;
+ if (!cfg.no_remote_charset)
+ cset_attr[1] = ATTR_ASCII;
break;
case ANSI('0', ')'):
compatibility(VT100);
- cset_attr[1] = ATTR_LINEDRW;
+ if (!cfg.no_remote_charset)
+ cset_attr[1] = ATTR_LINEDRW;
break;
case ANSI('U', ')'):
compatibility(OTHER);
- cset_attr[1] = ATTR_SCOACS;
+ if (!cfg.no_remote_charset)
+ cset_attr[1] = ATTR_SCOACS;
break;
case ANSI('8', '%'): /* Old Linux code */
case ANSI('G', '%'):
compatibility(OTHER);
- utf = 1;
+ if (!cfg.no_remote_charset)
+ utf = 1;
break;
case ANSI('@', '%'):
compatibility(OTHER);
- utf = 0;
+ if (!cfg.no_remote_charset)
+ utf = 0;
break;
}
break;
toggle_mode(esc_args[i], esc_query, TRUE);
}
break;
+ case 'i':
+ case ANSI_QUE('i'):
+ compatibility(VT100);
+ {
+ int i;
+ if (esc_nargs != 1) break;
+ if (esc_args[0] == 5 && *cfg.printer) {
+ printing = TRUE;
+ only_printing = !esc_query;
+ print_state = 0;
+ term_print_setup();
+ } else if (esc_args[0] == 4 && printing) {
+ printing = FALSE;
+ only_printing = FALSE;
+ term_print_finish();
+ }
+ }
+ break;
case 'l': /* toggle modes to low */
case ANSI_QUE('l'):
compatibility(VT100);
break;
case 10: /* SCO acs off */
compatibility(SCOANSI);
+ if (cfg.no_remote_charset) break;
sco_acs = 0; break;
case 11: /* SCO acs on */
compatibility(SCOANSI);
+ if (cfg.no_remote_charset) break;
sco_acs = 1; break;
case 12: /* SCO acs on flipped */
compatibility(SCOANSI);
+ if (cfg.no_remote_charset) break;
sco_acs = 2; break;
case 22: /* disable bold */
compatibility2(OTHER, VT220);
* illegal values (eg first arg 1..9) for window changing
* and reports.
*/
- compatibility(VT340TEXT);
if (esc_nargs <= 1
&& (esc_args[0] < 1 || esc_args[0] >= 24)) {
- request_resize(cols, def(esc_args[0], 24));
+ compatibility(VT340TEXT);
+ if (!cfg.no_remote_resize)
+ request_resize(cols, def(esc_args[0], 24));
deselect();
+ } else if (esc_nargs >= 1 &&
+ esc_args[0] >= 1 &&
+ esc_args[0] < 24) {
+ compatibility(OTHER);
+
+ switch (esc_args[0]) {
+ int x, y, len;
+ char buf[80], *p;
+ case 1:
+ set_iconic(FALSE);
+ break;
+ case 2:
+ set_iconic(TRUE);
+ break;
+ case 3:
+ if (esc_nargs >= 3) {
+ if (!cfg.no_remote_resize)
+ move_window(def(esc_args[1], 0),
+ def(esc_args[2], 0));
+ }
+ break;
+ case 4:
+ /* We should resize the window to a given
+ * size in pixels here, but currently our
+ * resizing code isn't healthy enough to
+ * manage it. */
+ break;
+ case 5:
+ set_zorder(TRUE); /* move to top */
+ break;
+ case 6:
+ set_zorder(FALSE); /* move to bottom */
+ break;
+ case 7:
+ refresh_window();
+ break;
+ case 8:
+ if (esc_nargs >= 3) {
+ if (!cfg.no_remote_resize)
+ request_resize(def(esc_args[2], cfg.width),
+ def(esc_args[1], cfg.height));
+ }
+ break;
+ case 9:
+ if (esc_nargs >= 2)
+ set_zoomed(esc_args[1] ? TRUE : FALSE);
+ break;
+ case 11:
+ ldisc_send(is_iconic() ? "\033[1t" : "\033[2t",
+ 4, 0);
+ break;
+ case 13:
+ get_window_pos(&x, &y);
+ len = sprintf(buf, "\033[3;%d;%dt", x, y);
+ ldisc_send(buf, len, 0);
+ break;
+ case 14:
+ get_window_pixels(&x, &y);
+ len = sprintf(buf, "\033[4;%d;%dt", x, y);
+ ldisc_send(buf, len, 0);
+ break;
+ case 18:
+ len = sprintf(buf, "\033[8;%d;%dt",
+ rows, cols);
+ ldisc_send(buf, len, 0);
+ break;
+ case 19:
+ /*
+ * Hmmm. Strictly speaking we
+ * should return `the size of the
+ * screen in characters', but
+ * that's not easy: (a) window
+ * furniture being what it is it's
+ * hard to compute, and (b) in
+ * resize-font mode maximising the
+ * window wouldn't change the
+ * number of characters. *shrug*. I
+ * think we'll ignore it for the
+ * moment and see if anyone
+ * complains, and then ask them
+ * what they would like it to do.
+ */
+ break;
+ case 20:
+ p = get_window_title(TRUE);
+ len = strlen(p);
+ ldisc_send("\033]L", 3, 0);
+ ldisc_send(p, len, 0);
+ ldisc_send("\033\\", 2, 0);
+ break;
+ case 21:
+ p = get_window_title(FALSE);
+ len = strlen(p);
+ ldisc_send("\033]l", 3, 0);
+ ldisc_send(p, len, 0);
+ ldisc_send("\033\\", 2, 0);
+ break;
+ }
}
break;
case 'S':
*/
compatibility(VT420);
if (esc_nargs == 1 && esc_args[0] > 0) {
- request_resize(cols, def(esc_args[0], cfg.height));
+ if (!cfg.no_remote_resize)
+ 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);
+ if (!cfg.no_remote_resize)
+ request_resize(def(esc_args[0], cfg.width), rows);
deselect();
}
break;
* Well we should do a soft reset at this point ...
*/
if (!has_compat(VT420) && has_compat(VT100)) {
- if (reset_132)
- request_resize(132, 24);
- else
- request_resize(80, 24);
+ if (!cfg.no_remote_resize) {
+ if (reset_132)
+ request_resize(132, 24);
+ else
+ request_resize(80, 24);
+ }
}
#endif
break;
check_selection(curs, cursplus);
}
}
+
+ term_print_flush();
}
#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);
for (i = 0; i < rows; i++) {
unsigned long *ldata;
int lattr;
- int idx, dirty_line, dirty_run;
+ int idx, dirty_line, dirty_run, selected;
unsigned long attr = 0;
int updated_line = 0;
int start = 0;
tattr |= ATTR_WIDE;
/* Video reversing things */
+ if (seltype == LEXICOGRAPHIC)
+ selected = posle(selstart, scrpos) && poslt(scrpos, selend);
+ else
+ selected = posPle(selstart, scrpos) && posPlt(scrpos, selend);
tattr = (tattr ^ rv
- ^ (posle(selstart, scrpos) &&
- poslt(scrpos, selend) ? ATTR_REVERSE : 0));
+ ^ (selected ? ATTR_REVERSE : 0));
/* 'Real' blinking ? */
if (blink_is_real && (tattr & ATTR_BLINK)) {
term_update();
}
-static void clipme(pos top, pos bottom)
+static void clipme(pos top, pos bottom, int rect)
{
wchar_t *workbuf;
wchar_t *wbptr; /* where next char goes within workbuf */
+ int old_top_x;
int wblen = 0; /* workbuf len */
int buflen; /* amount of memory allocated to workbuf */
buflen = 5120; /* Default size */
workbuf = smalloc(buflen * sizeof(wchar_t));
wbptr = workbuf; /* start filling here */
+ old_top_x = top.x; /* needed for rect==1 */
while (poslt(top, bottom)) {
int nl = FALSE;
unsigned long *ldata = lineptr(top.y);
pos nlpos;
+ /*
+ * nlpos will point at the maximum position on this line we
+ * should copy up to. So we start it at the end of the
+ * line...
+ */
nlpos.y = top.y;
nlpos.x = cols;
+ /*
+ * ... move it backwards if there's unused space at the end
+ * of the line (and also set `nl' if this is the case,
+ * because in normal selection mode this means we need a
+ * newline at the end)...
+ */
if (!(ldata[cols] & LATTR_WRAPPED)) {
while (((ldata[nlpos.x - 1] & 0xFF) == 0x20 ||
(DIRECT_CHAR(ldata[nlpos.x - 1]) &&
if (poslt(nlpos, bottom))
nl = TRUE;
}
+
+ /*
+ * ... and then clip it to the terminal x coordinate if
+ * we're doing rectangular selection. (In this case we
+ * still did the above, so that copying e.g. the right-hand
+ * column from a table doesn't fill with spaces on the
+ * right.)
+ */
+ if (rect) {
+ if (nlpos.x > bottom.x)
+ nlpos.x = bottom.x;
+ nl = (top.y < bottom.y);
+ }
+
while (poslt(top, bottom) && poslt(top, nlpos)) {
#if 0
char cbuf[16], *p;
}
}
top.y++;
- top.x = 0;
+ top.x = rect ? old_top_x : 0;
}
wblen++;
*wbptr++ = 0;
pos top;
top.y = -count234(scrollback);
top.x = 0;
- clipme(top, curs);
+ clipme(top, curs, 0);
}
/*
{
unsigned long *ldata;
short wvalue;
+ int topy = -count234(scrollback);
ldata = lineptr(p.y);
*/
wvalue = wordtype(ldata[p.x]);
if (dir == +1) {
- while (p.x < cols && wordtype(ldata[p.x + 1]) == wvalue)
- p.x++;
+ while (1) {
+ if (p.x < cols-1) {
+ if (wordtype(ldata[p.x + 1]) == wvalue)
+ p.x++;
+ else
+ break;
+ } else {
+ if (ldata[cols] & LATTR_WRAPPED) {
+ unsigned long *ldata2;
+ ldata2 = lineptr(p.y+1);
+ if (wordtype(ldata2[0]) == wvalue) {
+ p.x = 0;
+ p.y++;
+ ldata = ldata2;
+ } else
+ break;
+ } else
+ break;
+ }
+ }
} else {
- while (p.x > 0 && wordtype(ldata[p.x - 1]) == wvalue)
- p.x--;
+ while (1) {
+ if (p.x > 0) {
+ if (wordtype(ldata[p.x - 1]) == wvalue)
+ p.x--;
+ else
+ break;
+ } else {
+ unsigned long *ldata2;
+ if (p.y <= topy)
+ break;
+ ldata2 = lineptr(p.y-1);
+ if ((ldata2[cols] & LATTR_WRAPPED) &&
+ wordtype(ldata2[cols-1]) == wvalue) {
+ p.x = cols-1;
+ p.y--;
+ ldata = ldata2;
+ } else
+ break;
+ }
+ }
}
break;
case SM_LINE:
static void sel_spread(void)
{
- selstart = sel_spread_half(selstart, -1);
- decpos(selend);
- selend = sel_spread_half(selend, +1);
- incpos(selend);
+ if (seltype == LEXICOGRAPHIC) {
+ selstart = sel_spread_half(selstart, -1);
+ decpos(selend);
+ selend = sel_spread_half(selend, +1);
+ incpos(selend);
+ }
}
void term_do_paste(void)
}
void term_mouse(Mouse_Button b, Mouse_Action a, int x, int y,
- int shift, int ctrl)
+ int shift, int ctrl, int alt)
{
pos selpoint;
unsigned long *ldata;
- int raw_mouse = xterm_mouse && !(cfg.mouse_override && shift);
+ int raw_mouse = (xterm_mouse &&
+ !cfg.no_mouse_rep &&
+ !(cfg.mouse_override && shift));
+ int default_seltype;
if (y < 0) {
y = 0;
b = translate_button(b);
+ /*
+ * Set the selection type (rectangular or normal) at the start
+ * of a selection attempt, from the state of Alt.
+ */
+ if (!alt ^ !cfg.rect_select)
+ default_seltype = RECTANGULAR;
+ else
+ default_seltype = LEXICOGRAPHIC;
+
+ if (selstate == NO_SELECTION) {
+ seltype = default_seltype;
+ }
+
if (b == MBT_SELECT && a == MA_CLICK) {
deselect();
selstate = ABOUT_TO;
+ seltype = default_seltype;
selanchor = selpoint;
selmode = SM_CHAR;
} else if (b == MBT_SELECT && (a == MA_2CLK || a == MA_3CLK)) {
if (selstate == ABOUT_TO && poseq(selanchor, selpoint))
return;
if (b == MBT_EXTEND && a != MA_DRAG && selstate == SELECTED) {
- if (posdiff(selpoint, selstart) <
- posdiff(selend, selstart) / 2) {
- selanchor = selend;
- decpos(selanchor);
+ if (seltype == LEXICOGRAPHIC) {
+ /*
+ * For normal selection, we extend by moving
+ * whichever end of the current selection is closer
+ * to the mouse.
+ */
+ if (posdiff(selpoint, selstart) <
+ posdiff(selend, selstart) / 2) {
+ selanchor = selend;
+ decpos(selanchor);
+ } else {
+ selanchor = selstart;
+ }
} else {
- selanchor = selstart;
+ /*
+ * For rectangular selection, we have a choice of
+ * _four_ places to put selanchor and selpoint: the
+ * four corners of the selection.
+ */
+ if (2*selpoint.x < selstart.x + selend.x)
+ selanchor.x = selend.x-1;
+ else
+ selanchor.x = selstart.x;
+
+ if (2*selpoint.y < selstart.y + selend.y)
+ selanchor.y = selend.y;
+ else
+ selanchor.y = selstart.y;
}
selstate = DRAGGING;
}
if (selstate != ABOUT_TO && selstate != DRAGGING)
selanchor = selpoint;
selstate = DRAGGING;
- if (poslt(selpoint, selanchor)) {
- selstart = selpoint;
- selend = selanchor;
- incpos(selend);
+ if (seltype == LEXICOGRAPHIC) {
+ /*
+ * For normal selection, we set (selstart,selend) to
+ * (selpoint,selanchor) in some order.
+ */
+ if (poslt(selpoint, selanchor)) {
+ selstart = selpoint;
+ selend = selanchor;
+ incpos(selend);
+ } else {
+ selstart = selanchor;
+ selend = selpoint;
+ incpos(selend);
+ }
} else {
- selstart = selanchor;
- selend = selpoint;
- incpos(selend);
+ /*
+ * For rectangular selection, we may need to
+ * interchange x and y coordinates (if the user has
+ * dragged in the -x and +y directions, or vice versa).
+ */
+ selstart.x = min(selanchor.x, selpoint.x);
+ selend.x = 1+max(selanchor.x, selpoint.x);
+ selstart.y = min(selanchor.y, selpoint.y);
+ selend.y = max(selanchor.y, selpoint.y);
}
sel_spread();
} else if ((b == MBT_SELECT || b == MBT_EXTEND) && a == MA_RELEASE) {
* We've completed a selection. We now transfer the
* data to the clipboard.
*/
- clipme(selstart, selend);
+ clipme(selstart, selend, (seltype == RECTANGULAR));
selstate = SELECTED;
} else
selstate = NO_SELECTION;
*/
int from_backend(int is_stderr, char *data, int len)
{
+ assert(len > 0);
+
bufchain_add(&inbuf, data, len);
/*
*/
return 0;
}
-
-/*
- * Log session traffic.
- */
-void logtraffic(unsigned char c, int logmode)
-{
- if (cfg.logtype > 0) {
- if (cfg.logtype == logmode) {
- /* deferred open file from pgm start? */
- if (!lgfp)
- logfopen();
- if (lgfp)
- fputc(c, lgfp);
- }
- }
-}
-
-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;
- char writemod[4];
-
- if (!cfg.logtype)
- return;
- sprintf(writemod, "wb"); /* default to rewrite */
-
- 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(currlogfilename);
- if (i == 1)
- writemod[0] = 'a'; /* set append mode */
- else if (i == 0) { /* cancelled */
- lgfp = NULL;
- cfg.logtype = 0; /* disable logging */
- return;
- }
- }
-
- 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, currlogfilename, 128);
- buf[strlen(buf)] = '\0';
- logevent(buf);
-
- /* --- write header line into log file */
- fputs("=~=~=~=~=~=~=~=~=~=~=~= PuTTY log ", lgfp);
- strftime(buf, 24, "%Y.%m.%d %H:%M:%S", &tm);
- fputs(buf, lgfp);
- fputs(" =~=~=~=~=~=~=~=~=~=~=~=\r\n", lgfp);
- }
-}
-
-void logfclose(void)
-{
- if (lgfp) {
- fclose(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';
-}