1 /*
2  * Internals of the Terminal structure, for those other modules
3  * which need to look inside it. It would be nice if this could be
4  * folded back into terminal.c in future, with an abstraction layer
5  * to handle everything that other modules need to know about it;
6  * but for the moment, this will do.
7  */
8 
9 #ifndef PUTTY_TERMINAL_H
10 #define PUTTY_TERMINAL_H
11 
12 #include "tree234.h"
13 
14 struct beeptime {
15     struct beeptime *next;
16     unsigned long ticks;
17 };
18 
19 #define TRUST_SIGIL_WIDTH 3
20 #define TRUST_SIGIL_CHAR 0xDFFE
21 
22 typedef struct {
23     int y, x;
24 } pos;
25 
26 typedef struct termchar termchar;
27 typedef struct termline termline;
28 
29 struct termchar {
30     /*
31      * Any code in terminal.c which definitely needs to be changed
32      * when extra fields are added here is labelled with a comment
33      * saying FULL-TERMCHAR.
34      */
35     unsigned long chr;
36     unsigned long attr;
37     truecolour truecolour;
38 
39     /*
40      * The cc_next field is used to link multiple termchars
41      * together into a list, so as to fit more than one character
42      * into a character cell (Unicode combining characters).
43      *
44      * cc_next is a relative offset into the current array of
45      * termchars. I.e. to advance to the next character in a list,
46      * one does `tc += tc->next'.
47      *
48      * Zero means end of list.
49      */
50     int cc_next;
51 };
52 
53 struct termline {
54     unsigned short lattr;
55     int cols;                          /* number of real columns on the line */
56     int size;                          /* number of allocated termchars
57                                         * (cc-lists may make this > cols) */
58     bool temporary;                    /* true if decompressed from scrollback */
59     int cc_free;                       /* offset to first cc in free list */
60     struct termchar *chars;
61     bool trusted;
62 };
63 
64 struct bidi_cache_entry {
65     int width;
66     bool trusted;
67     struct termchar *chars;
68     int *forward, *backward;           /* the permutations of line positions */
69 };
70 
71 struct term_utf8_decode {
72     int state;                         /* Is there a pending UTF-8 character */
73     int chr;                           /* and what is it so far? */
74     int size;                          /* The size of the UTF character. */
75 };
76 
77 struct terminal_tag {
78 
79     int compatibility_level;
80 
81     tree234 *scrollback;               /* lines scrolled off top of screen */
82     tree234 *screen;                   /* lines on primary screen */
83     tree234 *alt_screen;               /* lines on alternate screen */
84     int disptop;                       /* distance scrolled back (0 or -ve) */
85     int tempsblines;                   /* number of lines of .scrollback that
86                                           can be retrieved onto the terminal
87                                           ("temporary scrollback") */
88 
89     termline **disptext;               /* buffer of text on real screen */
90     int dispcursx, dispcursy;          /* location of cursor on real screen */
91     int curstype;                      /* type of cursor on real screen */
92 
93 #define VBELL_TIMEOUT (TICKSPERSEC/10) /* visual bell lasts 1/10 sec */
94 
95     struct beeptime *beephead, *beeptail;
96     int nbeeps;
97     bool beep_overloaded;
98     long lastbeep;
99 
100 #define TTYPE termchar
101 #define TSIZE (sizeof(TTYPE))
102 
103     int default_attr, curr_attr, save_attr;
104     truecolour curr_truecolour, save_truecolour;
105     termchar basic_erase_char, erase_char;
106 
107     bufchain inbuf;                    /* terminal input buffer */
108 
109     pos curs;                          /* cursor */
110     pos savecurs;                      /* saved cursor position */
111     int marg_t, marg_b;                /* scroll margins */
112     bool dec_om;                       /* DEC origin mode flag */
113     bool wrap, wrapnext;               /* wrap flags */
114     bool insert;                       /* insert-mode flag */
115     int cset;                          /* 0 or 1: which char set */
116     int save_cset, save_csattr;        /* saved with cursor position */
117     bool save_utf, save_wnext;         /* saved with cursor position */
118     bool rvideo;                       /* global reverse video flag */
119     unsigned long rvbell_startpoint;   /* for ESC[?5hESC[?5l vbell */
120     bool cursor_on;                    /* cursor enabled flag */
121     bool reset_132;                    /* Flag ESC c resets to 80 cols */
122     bool use_bce;                      /* Use Background coloured erase */
123     bool cblinker;                     /* When blinking is the cursor on ? */
124     bool tblinker;                     /* When the blinking text is on */
125     bool blink_is_real;                /* Actually blink blinking text */
126     int sco_acs, save_sco_acs;         /* CSI 10,11,12m -> OEM charset */
127     bool vt52_bold;                    /* Force bold on non-bold colours */
128     bool utf;                          /* Are we in toggleable UTF-8 mode? */
129     term_utf8_decode utf8;             /* If so, here's our decoding state */
130     bool printing, only_printing;      /* Are we doing ANSI printing? */
131     int print_state;                   /* state of print-end-sequence scan */
132     bufchain printer_buf;              /* buffered data for printer */
133     printer_job *print_job;
134 
135     /* ESC 7 saved state for the alternate screen */
136     pos alt_savecurs;
137     int alt_save_attr;
138     truecolour alt_save_truecolour;
139     int alt_save_cset, alt_save_csattr;
140     bool alt_save_utf;
141     bool alt_save_wnext;
142     int alt_save_sco_acs;
143 
144     int rows, cols, savelines;
145     bool has_focus;
146     bool in_vbell;
147     long vbell_end;
148     bool app_cursor_keys, app_keypad_keys, vt52_mode;
149     bool repeat_off, srm_echo, cr_lf_return;
150     bool seen_disp_event;
151     bool big_cursor;
152 
153     bool xterm_mouse_forbidden;
154     int xterm_mouse;                   /* send mouse messages to host */
155     bool xterm_extended_mouse;
156     bool urxvt_extended_mouse;
157     int mouse_is_down;                 /* used while tracking mouse buttons */
158 
159     bool bracketed_paste, bracketed_paste_active;
160 
161     int cset_attr[2];
162 
163 /*
164  * Saved settings on the alternate screen.
165  */
166     int alt_x, alt_y;
167     bool alt_wnext, alt_ins;
168     bool alt_om, alt_wrap;
169     int alt_cset, alt_sco_acs;
170     bool alt_utf;
171     int alt_t, alt_b;
172     int alt_which;
173     int alt_sblines; /* # of lines on alternate screen that should be used for scrollback. */
174 
175 #define ARGS_MAX 32                    /* max # of esc sequence arguments */
176 #define ARG_DEFAULT 0                  /* if an arg isn't specified */
177 #define def(a,d) ( (a) == ARG_DEFAULT ? (d) : (a) )
178     unsigned esc_args[ARGS_MAX];
179     int esc_nargs;
180     int esc_query;
181 #define ANSI(x,y)       ((x)+((y)*256))
182 #define ANSI_QUE(x)     ANSI(x,1)
183 
184 #define OSC_STR_MAX 2048
185     int osc_strlen;
186     char osc_string[OSC_STR_MAX + 1];
187     bool osc_w;
188 
189     char id_string[1024];
190 
191     unsigned char *tabs;
192 
193     enum {
194         TOPLEVEL,
195         SEEN_ESC,
196         SEEN_CSI,
197         SEEN_OSC,
198         SEEN_OSC_W,
199 
200         DO_CTRLS,
201 
202         SEEN_OSC_P,
203         OSC_STRING, OSC_MAYBE_ST,
204         VT52_ESC,
205         VT52_Y1,
206         VT52_Y2,
207         VT52_FG,
208         VT52_BG
209     } termstate;
210 
211     enum {
212         NO_SELECTION, ABOUT_TO, DRAGGING, SELECTED
213     } selstate;
214     enum {
215         LEXICOGRAPHIC, RECTANGULAR
216     } seltype;
217     enum {
218         SM_CHAR, SM_WORD, SM_LINE
219     } selmode;
220     pos selstart, selend, selanchor;
221 
222     short wordness[256];
223 
224     /* Mask of attributes to pay attention to when painting. */
225     int attr_mask;
226 
227     wchar_t *paste_buffer;
228     int paste_len, paste_pos;
229 
230     Backend *backend;
231 
232     Ldisc *ldisc;
233 
234     TermWin *win;
235 
236     LogContext *logctx;
237 
238     struct unicode_data *ucsdata;
239 
240     unsigned long last_graphic_char;
241 
242     /*
243      * We maintain a full copy of a Conf here, not merely a pointer
244      * to it. That way, when we're passed a new one for
245      * reconfiguration, we can check the differences and adjust the
246      * _current_ setting of (e.g.) auto wrap mode rather than only
247      * the default.
248      */
249     Conf *conf;
250 
251     /*
252      * GUI implementations of seat_output call term_out, but it can
253      * also be called from the ldisc if the ldisc is called _within_
254      * term_out. So we have to guard against re-entrancy - if
255      * seat_output is called recursively like this, it will simply add
256      * data to the end of the buffer term_out is in the process of
257      * working through.
258      */
259     bool in_term_out;
260 
261     /*
262      * We don't permit window updates too close together, to avoid CPU
263      * churn pointlessly redrawing the window faster than the user can
264      * read. So after an update, we set window_update_cooldown = true
265      * and schedule a timer to reset it to false. In between those
266      * times, window updates are not performed, and instead we set
267      * window_update_pending = true, which will remind us to perform
268      * the deferred redraw when the cooldown period ends and
269      * window_update_cooldown is reset to false.
270      */
271     bool window_update_pending, window_update_cooldown;
272     long window_update_cooldown_end;
273 
274     /*
275      * Track pending blinks and tblinks.
276      */
277     bool tblink_pending, cblink_pending;
278     long next_tblink, next_cblink;
279 
280     /*
281      * These are buffers used by the bidi and Arabic shaping code.
282      */
283     termchar *ltemp;
284     int ltemp_size;
285     bidi_char *wcFrom, *wcTo;
286     int wcFromTo_size;
287     struct bidi_cache_entry *pre_bidi_cache, *post_bidi_cache;
288     size_t bidi_cache_size;
289 
290     /*
291      * Current trust state, used to annotate every line of the
292      * terminal that a graphic character is output to.
293      */
294     bool trusted;
295 
296     /*
297      * We copy a bunch of stuff out of the Conf structure into local
298      * fields in the Terminal structure, to avoid the repeated
299      * tree234 lookups which would be involved in fetching them from
300      * the former every time.
301      */
302     bool ansi_colour;
303     char *answerback;
304     int answerbacklen;
305     bool no_arabicshaping;
306     int beep;
307     bool bellovl;
308     int bellovl_n;
309     int bellovl_s;
310     int bellovl_t;
311     bool no_bidi;
312     bool bksp_is_delete;
313     bool blink_cur;
314     bool blinktext;
315     bool cjk_ambig_wide;
316     int conf_height;
317     int conf_width;
318     bool crhaslf;
319     bool erase_to_scrollback;
320     int funky_type;
321     bool lfhascr;
322     bool logflush;
323     int logtype;
324     bool mouse_override;
325     bool nethack_keypad;
326     bool no_alt_screen;
327     bool no_applic_c;
328     bool no_applic_k;
329     bool no_dbackspace;
330     bool no_mouse_rep;
331     bool no_remote_charset;
332     bool no_remote_resize;
333     bool no_remote_wintitle;
334     bool no_remote_clearscroll;
335     bool rawcnp;
336     bool utf8linedraw;
337     bool rect_select;
338     int remote_qtitle_action;
339     bool rxvt_homeend;
340     bool scroll_on_disp;
341     bool scroll_on_key;
342     bool xterm_256_colour;
343     bool true_colour;
344 
345     wchar_t *last_selected_text;
346     int *last_selected_attr;
347     truecolour *last_selected_tc;
348     size_t last_selected_len;
349     int mouse_select_clipboards[N_CLIPBOARDS];
350     int n_mouse_select_clipboards;
351     int mouse_paste_clipboard;
352 
353     char *window_title, *icon_title;
354     bool minimised;
355 
356     /* Multi-layered colour palette. The colours from Conf (plus the
357      * default xterm-256 ones that don't have Conf ids at all) have
358      * lowest priority, followed by platform overrides if any,
359      * followed by escape-sequence overrides during the session. */
360     struct term_subpalette {
361         rgb values[OSC4_NCOLOURS];
362         bool present[OSC4_NCOLOURS];
363     } subpalettes[3];
364 #define SUBPAL_CONF 0
365 #define SUBPAL_PLATFORM 1
366 #define SUBPAL_SESSION 2
367 
368     /* The composite palette that we make out of the above */
369     rgb palette[OSC4_NCOLOURS];
370 
371     unsigned winpos_x, winpos_y, winpixsize_x, winpixsize_y;
372 
373     /*
374      * Assorted 'pending' flags for ancillary window changes performed
375      * in term_update. Generally, to trigger one of these operations,
376      * you set the pending flag and/or the parameters here, then call
377      * term_schedule_update.
378      */
379     bool win_move_pending;
380     int win_move_pending_x, win_move_pending_y;
381     bool win_resize_pending;
382     int win_resize_pending_w, win_resize_pending_h;
383     bool win_zorder_pending;
384     bool win_zorder_top;
385     bool win_minimise_pending;
386     bool win_minimise_enable;
387     bool win_maximise_pending;
388     bool win_maximise_enable;
389     bool win_title_pending, win_icon_title_pending;
390     bool win_pointer_shape_pending;
391     bool win_pointer_shape_raw;
392     bool win_refresh_pending;
393     bool win_scrollbar_update_pending;
394     bool win_palette_pending;
395     unsigned win_palette_pending_min, win_palette_pending_limit;
396 };
397 
in_utf(Terminal * term)398 static inline bool in_utf(Terminal *term)
399 {
400     return term->utf || term->ucsdata->line_codepage == CP_UTF8;
401 }
402 
403 unsigned long term_translate(
404     Terminal *term, term_utf8_decode *utf8, unsigned char c);
term_char_width(Terminal * term,unsigned int c)405 static inline int term_char_width(Terminal *term, unsigned int c)
406 {
407     return term->cjk_ambig_wide ? mk_wcwidth_cjk(c) : mk_wcwidth(c);
408 }
409 
410 /*
411  * UCSINCOMPLETE is returned from term_translate if it's successfully
412  * absorbed a byte but not emitted a complete character yet.
413  * UCSTRUNCATED indicates a truncated multibyte sequence (so the
414  * caller emits an error character and then calls term_translate again
415  * with the same input byte). UCSINVALID indicates some other invalid
416  * multibyte sequence, such as an overlong synonym, or a standalone
417  * continuation byte, or a completely illegal thing like 0xFE. These
418  * values are not stored in the terminal data structures at all.
419  */
420 #define UCSINCOMPLETE 0x8000003FU    /* '?' */
421 #define UCSTRUNCATED  0x80000021U    /* '!' */
422 #define UCSINVALID    0x8000002AU    /* '*' */
423 
424 /*
425  * Maximum number of combining characters we're willing to store in a
426  * character cell. Our linked-list data representation permits an
427  * unlimited number of these in principle, but if we allowed that in
428  * practice then it would be an easy DoS to just squirt a squillion
429  * identical combining characters to someone's terminal and cause
430  * their PuTTY or pterm to consume lots of memory and CPU pointlessly.
431  *
432  * The precise figure of 32 is more or less arbitrary, but one point
433  * supporting it is UAX #15's comment that 30 combining characters is
434  * "significantly beyond what is required for any linguistic or
435  * technical usage".
436  */
437 #define CC_LIMIT 32
438 
439 /* ----------------------------------------------------------------------
440  * Helper functions for dealing with the small 'pos' structure.
441  */
442 
poslt(pos p1,pos p2)443 static inline bool poslt(pos p1, pos p2)
444 {
445     if (p1.y != p2.y)
446         return p1.y < p2.y;
447     return p1.x < p2.x;
448 }
449 
posle(pos p1,pos p2)450 static inline bool posle(pos p1, pos p2)
451 {
452     if (p1.y != p2.y)
453         return p1.y < p2.y;
454     return p1.x <= p2.x;
455 }
456 
poseq(pos p1,pos p2)457 static inline bool poseq(pos p1, pos p2)
458 {
459     return p1.y == p2.y && p1.x == p2.x;
460 }
461 
posdiff_fn(pos p1,pos p2,int cols)462 static inline int posdiff_fn(pos p1, pos p2, int cols)
463 {
464     return (p1.y - p2.y) * (cols+1) + (p1.x - p2.x);
465 }
466 
467 /* Convenience wrapper on posdiff_fn which uses the 'Terminal *term'
468  * that more or less every function in terminal.c will have in scope.
469  * For safety's sake I include a TYPECHECK that ensures it really is a
470  * structure pointer of the right type. */
471 #define GET_TERM_COLS TYPECHECK(term == (Terminal *)0, term->cols)
472 #define posdiff(p1,p2) posdiff_fn(p1, p2, GET_TERM_COLS)
473 
474 /* Product-order comparisons for rectangular block selection. */
475 
posPle(pos p1,pos p2)476 static inline bool posPle(pos p1, pos p2)
477 {
478     return p1.y <= p2.y && p1.x <= p2.x;
479 }
480 
posPle_left(pos p1,pos p2)481 static inline bool posPle_left(pos p1, pos p2)
482 {
483     /*
484      * This function is used for checking whether a given character
485      * cell of the terminal ought to be highlighted as part of the
486      * selection, by comparing with term->selend. term->selend stores
487      * the location one space to the right of the last highlighted
488      * character. So we want to highlight the characters that are
489      * less-or-equal (in the product order) to the character just left
490      * of p2.
491      *
492      * (Setting up term->selend that way was the easiest way to get
493      * rectangular selection working at all, in a code base that had
494      * done lexicographic selection the way I happened to have done
495      * it.)
496      */
497     return p1.y <= p2.y && p1.x < p2.x;
498 }
499 
incpos_fn(pos * p,int cols)500 static inline bool incpos_fn(pos *p, int cols)
501 {
502     if (p->x == cols) {
503         p->x = 0;
504         p->y++;
505         return true;
506     }
507     p->x++;
508     return false;
509 }
510 
decpos_fn(pos * p,int cols)511 static inline bool decpos_fn(pos *p, int cols)
512 {
513     if (p->x == 0) {
514         p->x = cols;
515         p->y--;
516         return true;
517     }
518     p->x--;
519     return false;
520 }
521 
522 /* Convenience wrappers on incpos and decpos which use term->cols
523  * (similarly to posdiff above), and also (for mild convenience and
524  * mostly historical inertia) let you leave off the & at every call
525  * site. */
526 #define incpos(p) incpos_fn(&(p), GET_TERM_COLS)
527 #define decpos(p) decpos_fn(&(p), GET_TERM_COLS)
528 
529 #endif
530