1 /*======================================================================*\
2 |*		Editor mined						*|
3 |*		part 1							*|
4 \*======================================================================*/
5 
6 #include "mined.h"
7 #include "version.h"
8 
9 #ifndef VAXC
10 #include <sys/stat.h>	/* umask () */
11 #endif
12 
13 #include "textfile.h"
14 #include "charprop.h"
15 #include "encoding.h"
16 #include "io.h"
17 #include "termprop.h"
18 
19 
20 #if defined (vms) || defined (__TURBOC__)
21 #ifndef VAXC
22 #define wildcard_expansion
23 #endif
24 #endif
25 
26 #define dont_debug_wildcard_expansion
27 #ifdef debug_wildcard_expansion
28 #define wildcard_expansion
29 #endif
30 
31 #ifdef wildcard_expansion
32 #include <dirent.h>
33 #endif
34 
35 
36 #include <errno.h>	/* EEXIST */
37 
38 #ifdef __CYGWIN__
39 #include <cygwin/version.h>	/* check CYGWIN_VERSION_DLL_MAJOR >= 1007 ? */
40 #include <locale.h>
41 #if CYGWIN_VERSION_DLL_MAJOR >= 1007
42 #include <langinfo.h>	/* available #if CYGWIN_VERSION_DLL_MAJOR >= 1005 */
43 #endif
44 #include <sys/utsname.h>
45 #endif
46 
47 
48 /**
49    How to deal with non-matching tty and terminal sizes.
50    Method 1: adjust_terminal_height
51    	accept the tty size assumption and try to resize the terminal to it
52    	- not needed anymore (see method 3)
53    Method 2: adjust_to_actual_termsize
54    	request the terminal size, process the reponse asynchronously
55    	- what a weird idea, never fully implemented ...
56    Method 3: checkwinsize ()
57    	detect the terminal size: set the cursor way out the area,
58    	request cursor position
59    	(or use specific size request as in method 1 but synchronously)
60  */
61 #define dont_adjust_terminal_height
62 #define dont_adjust_to_actual_termsize	/* not fully implemented */
63 
64 
65 /*======================================================================*\
66 |*		Local function declarations and FLAGs			*|
67 \*======================================================================*/
68 
69 static void flush_keyboard _((void));
70 static char * get_terminal_report_string _((char * s));
71 
72 static void check_cjk_width _((void));
73 static void config_markers _((void));
74 
75 
76 /*======================================================================*\
77 |*		Data section						*|
78 \*======================================================================*/
79 
80 char * debug_mined = NIL_PTR;
81 
82 LINE * header;			/* Head of line list */
83 LINE * tail;			/* Last line in line list */
84 LINE * cur_line;		/* Current line in use */
85 LINE * top_line;		/* First line of screen */
86 LINE * bot_line;		/* Last line of screen */
87 char * cur_text;		/* Current char on current line in use */
88 int last_y;			/* Last y of screen. Usually SCREENMAX */
89 int x = 0;			/* screen column of current text position */
90 int y = 0;			/* screen row of current text position */
91 int line_number;		/* current line # determined by file_status */
92 int total_lines = 0;		/* Number of lines in file */
93 long total_chars = 0L;		/* Number of characters in file */
94 
95 int lines_per_page = 00;	/* assumption for file_status */
96 
97 FLAG loading = True;		/* Loading a file? Init True for error handling */
98 static FLAG utf8_auto_detected = False;
99 
100 int hop_flag = 0;		/* Counter flag for the HOP function */
101 int hop_flag_displayed = 0;
102 
103 FLAG quit = False;		/* Set on SIGQUIT or quit character typed */
104 FLAG winchg = False;		/* Set when window size has changed */
105 FLAG interrupted = False;	/* Set when a signal interrupts */
106 FLAG isscreenmode = False;	/* Set when screen mode is on */
107 FLAG stat_visible;		/* Set if status line is visible */
108 FLAG top_line_dirty = False;	/* Was menu line cleared? */
109 FLAG text_screen_dirty = False;	/* Was text display position affected? */
110 
111 FLAG waitingforinput = False;	/* Set while waiting for the next command key */
112 FLAG reading_pipe = False;	/* Set if file should be read from stdin */
113 FLAG writing_pipe = False;	/* Set if file should be written to stdout */
114 
115 char * minedprog;		/* store argv [0] for help invocation */
116 character quit_char = '\034';	/* ^\/^G character to cancel command */
117 
118 int YMAX, XMAX;
119 
120 long chars_saved;		/* # of chars in paste buffer */
121 long bytes_saved;		/* # of bytes in paste buffer */
122 int lines_saved;		/* # of lines in paste buffer */
123 
124 char text_buffer [maxLINElen];	/* for get_line, modifications, get_tagline, build_string */
125 
126 /**
127    Yank variables
128  */
129 char yank_file [maxFILENAMElen];
130 char yankie_file [maxFILENAMElen];
131 char spool_file [maxFILENAMElen];
132 char html_file [maxFILENAMElen];	/* temp. buffer for HTML embedding */
133 char panic_file [maxFILENAMElen];
134 
135 /**
136    Terminal properties
137  */
138 static char * TERM;
139 static int terminal_type = -1;
140 static int terminal_version = 0;
141 static char * glyphs = NIL_PTR;
142 static FLAG combining_screen_selected = False;	/* explicitly selected ? */
143 static FLAG term_encoding_selected = False;	/* explicitly selected ? */
144 static FLAG text_encoding_selected = False;	/* explicitly selected ? */
145 static FLAG limited_marker_font = False;	/* -F to limit font usage? */
146 static FLAG very_limited_marker_font = False;	/* -FF to limit font usage? */
147 static FLAG explicit_selection_style = False;	/* -QQ or -Qq? */
148 FLAG suppress_unknown_cjk = True;	/* on CJK terminal if no Unicode mapping */
149 FLAG suppress_invalid_cjk = True;	/* on CJK terminal if invalid CJK code */
150 FLAG suppress_extended_cjk = False;	/* on CJK terminal if in extended code range */
151 FLAG suppress_surrogates = True;	/* suppress display of single Unicode surrogates */
152 FLAG suppress_non_BMP = False;		/* suppress display of non-BMP range */
153 FLAG suppress_EF = True;		/* suppress display of 0x*FFFE/F codes */
154 FLAG suppress_non_Unicode = True;	/* suppress display of non-Unicode codes */
155 FLAG utf_cjk_wide_padding = False; /* always display CJK on UTF double-width ? */
156 #ifdef pc_term
157 FLAG dark_term = True;		/* PC terminal */
158 #else
159 FLAG dark_term = False;		/* dark colour terminal ? */
160 #endif
161 FLAG darkness_detected = False;	/* could background colour be queried ? */
162 FLAG fg_yellowish = False;	/* foreground colour near yellow ? */
163 FLAG bright_term = False;	/* need to improved contrast ? */
164 FLAG bw_term = False;		/* black/white terminal ? */
165 FLAG suppress_colour = False;	/* don't use ANSI color settings */
166 static FLAG cygwin_console = False;
167 static FLAG can_report_props = True;
168 
169 FLAG configure_xterm_keyboard = False;	/* deleteIsDEL, metaSendsEscape */
170 
171 FLAG combining_mode = False;	/* UTF-8 combining character display support ? */
172 FLAG separate_isolated_combinings = True;	/* separated display of comb. at line beg./after TAB ? */
173 
174 static unsigned long dec_features = 1 << 4;	/* assume SIXEL for mlterm */
175 
176 #if defined (unix) || defined (ANSI)
177 /* window headline and icon text setting */
178 char * title_string_pattern = "";
179 char * mined_modf = " (*)";
180 #endif
181 
182 FLAG apply_joining = True;	/* apply LAM/ALEF joining ? */
183 
184 
185 /*======================================================================*\
186 |*		File-related properties					*|
187 \*======================================================================*/
188 
189 lineend_type default_lineend = lineend_LF;
190 #ifdef msdos
191 lineend_type newfile_lineend = lineend_CRLF;
192 #else
193 lineend_type newfile_lineend = lineend_LF;
194 #endif
195 FLAG writable;			/* Set if file cannot be written */
196 FLAG file_is_dir;		/* Tried to open a directory as file? */
197 FLAG file_is_dev;		/* Tried to open a char/block device file? */
198 FLAG file_is_fifo;		/* Read from a named pipe? */
199 
200 FLAG cjk_text = False;		/* text in CJK encoding ? */
201 FLAG utf8_text = False;		/* text in UTF-8 representation ? */
202 FLAG utf16_file = False;	/* file encoded in UTF-16 ? */
203 FLAG utf16_little_endian = False;	/* UTF-16 file encoded little endian ? */
204 FLAG mapped_text = False;	/* text in 8 bit, non-Latin-1 representation ? */
205 FLAG ebcdic_text = False;
206 FLAG ebcdic_file = False;
207 FLAG utf8_lineends = True;	/* detect UTF-8 LS and PS line ends ? */
208 FLAG poormansbidi = True;	/* poor man's bidirectional support ? */
209 
210 char file_name [maxFILENAMElen];	/* Name of file in use */
211 
212 PROT fprot0 = 0644;	/* default prot. mode for new files */
213 PROT fprot1 = 0;	/* prot. mode for new file being edited */
214 PROT bufprot = 0600;	/* prot. mode for paste buffer file */
215 static PROT exeprot = 0111;	/* default prot. mask for executables */
216 PROT xprot = 0;		/* actual prot. mask representing +x option */
217 
218 
219 /*======================================================================*\
220 |*		Modes and options					*|
221 \*======================================================================*/
222 
223 static FLAG cmdline_selected = False;
224 
225 short MENU = 1;
226 FLAG use_file_tabs = True;
227 static int splash_level = 2;	/* Show no/text/SIXEL splash_logo? */
228 
229 FLAG flags_changed = False;	/* Should flag menu area be redrawn? */
230 static FLAG quickmenu = True;	/* Right mouse button pops up menu */
231 static int wheel_scroll = 3;	/* Number of lines scrolled by mouse wheel */
232 FLAG modified = False;		/* Set when file is modified */
233 FLAG viewonly_mode = False;	/* Set when view only mode is selected */
234 FLAG viewonly_locked = False;	/* Enforced view only status */
235 FLAG viewonly_err = False;	/* Error view only status */
236 FLAG restricted = False;	/* Set when edited file shall not be switched */
237 
238 /* emulation and keyboard assignment flags */
239 char emulation = 'm';		/* 'e'macs, 'p'ico, 'w'indows, word's'tar */
240 char keypad_mode = 'm';		/* 'm'ined, 'S'hift-select, 'w'indows */
241 FLAG shift_selection = False;	/* selection highlighting on shift-cursor */
242 FLAG mined_keypad = True;	/* Apply mined keypad assignments */
243 FLAG home_selection = False;	/* numeric keypad Home/End forced to Mark/Copy */
244 FLAG small_home_selection = False;	/* small keypad Home/End: Mark/Copy */
245 FLAG emacs_buffer = False;	/* enable emacs buffer fct for ^K/^T */
246 FLAG paste_stay_left = False;	/* cursor stays before pasted region */
247 FLAG tab_left = False;	/* Set if moving up/down on TAB should go left */
248 FLAG tab_right = False;	/* Set if moving up/down on TAB should go left */
249 FLAG plain_BS = False;	/* prefer BS to perform plain rather than smart? */
250 
251 FLAG append_flag = False;	/* Set when buffer should be appended to */
252 FLAG pastebuf_utf8 = False;	/* Paste buffer always treated as UTF-8? */
253 FLAG rectangular_paste_flag = False;	/* Copy/Paste rectangular area? */
254 FLAG visselect_key = False;	/* Visual selection on unmodified cursor key? */
255 FLAG visselect_anymouse = False;	/* Visual selection on any mouse move? */
256 FLAG visselect_keeponsearch = False;	/* Keep visual selection on search ? */
257 FLAG visselect_setonfind = False;	/* Select search result? */
258 FLAG visselect_autocopy = True;		/* Auto-copy selection? */
259 FLAG visselect_copydeselect = True;	/* Deselect on copy? */
260 FLAG visselect_autodelete = False;	/* Delete selection on insert? */
261 
262 FLAG insert_mode = True;	/* insert or overwrite */
263 
264 int JUSlevel = 0;		/* Keep justified while typing? */
265 int JUSmode = 0;		/* 1: paragraphs end at empty line */
266 FLAG autoindent = True;		/* Auto indent on input of Enter? */
267 FLAG autonumber = True;		/* Auto numbering on input of Enter? */
268 FLAG backnumber = True;		/* Auto-undent numbering on input of BS? */
269 FLAG backincrem = False;	/* Auto-increment numbering on input of BS? */
270 FLAG lowcapstrop = False;	/* capitalize letter symbols on input? */
271 FLAG dispunstrop = False;	/* display stropped letters in bold? */
272 FLAG strop_selected = False;	/* was stropping explictly selected? */
273 char strop_style = ' ';		/* bold/underline? */
274 FLAG mark_HTML = UNSURE;	/* Display HTML marked ? */
275 FLAG mark_JSP = True;		/* Display JSP marked ? */
276 
277 char backup_mode = 'a';		/* none ('\0'), simple, e/v/numbered, auto */
278 char * backup_directory = NIL_PTR;	/* directory name for backup files */
279 char * recover_directory = NIL_PTR;	/* directory name for recovery files */
280 static FLAG homedir_selected = False;	/* option -~ given? */
281 static char * inisearch = NIL_PTR;	/* Optional startup search string */
282 
283 FLAG only_detect_text_encoding = False;
284 static FLAG only_detect_terminal_encoding = False;
285 
286 FLAG wordnonblank = False;	/* Handle all non-blank sequences as words */
287 FLAG proportional = False;	/* Enable support for proportional fonts? */
288 FLAG hide_passwords = UNSURE;	/* Hide passwords in display */
289 FLAG filtering_read = False;	/* Use filter for reading file ? */
290 char * filter_read = NIL_PTR;	/* Filter for reading file */
291 FLAG filtering_write = False;	/* Use filter for writing file ? */
292 char * filter_write = NIL_PTR;	/* Filter for writing file */
293 FLAG show_vt100_graph = False;	/* Display letters as VT100 block graphics ? */
294 FLAG auto_detect = True;	/* Auto detect character encoding from file ? */
295 char * detect_encodings;	/* List of encodings to detect */
296 char language_tag = 0;
297 FLAG translate_output = False;	/* Transform output diacritics to strings */
298 int translen;			/* length of " */
299 char * transout;		/* Output transformation table */
300 int tabsize = 8;		/* Width of tab positions, 2 or 4 or 8 */
301 FLAG tabsize_selected = False;	/* Tab width selected by explicit option? */
302 FLAG expand_tabs = False;	/* Expand TABs to Spaces? */
303 FLAG controlQS = False;		/* must respect ^Q/^S handshake ? */
304 character erase_char = '\010';	/* effective (configured) char for erase left */
305 
306 FLAG prefer_comspec = False;	/* for ESC ! command (cygwin) */
307 FLAG smart_quotes = True;	/* replace " with typographic quote ? */
308 static char * ext_status = NIL_PTR;	/* status line per option -_ */
309 
310 FLAG disp_scrollbar = True;	/* shall scrollbar be displayed ? */
311 FLAG fine_scrollbar = True;	/* fine-grained UTF-8 scrollbar ? */
312 FLAG old_scrollbar_clickmode = False;	/* old left/right click semantics ? */
313 int scrollbar_width = 1;
314 FLAG update_scrollbar_lazy = True;	/* partial scrollbar refresh as needed ? */
315 static FLAG use_window_title = True;	/* filename display in window title? */
316 static FLAG use_window_title_query = True;	/* query old title / detect title encoding? */
317 
318 static FLAG combining_mode_disabled = False;	/* combining mode explicitly disabled ? */
319 static FLAG U_mode_set = False;
320 
321 FLAG detect_esc_alt = True;	/* Enable detection of Alt key by ESC prefix? */
322 
323 char selection_space = SPACE_NEXT;	/* space behaviour in keyboard mapping menu */
324 FLAG enforce_keymap = True;	/* enable keyboard mapping even on non-suitable terminal */
325 
326 FLAG page_scroll = False;	/* use scroll for page up/down */
327 FLAG page_stay = False;		/* stay at edge of screen after page up/down */
328 int display_delay = 3;		/* delay between display lines */
329 
330 FLAG paradisp = False;		/* Shall paragraph end be distinguished? */
331 
332 /**
333    Line indicators
334  */
335 static char TABdefault = '�';		/* default TAB indicator */
336 static char RETdefault = '�';		/* indicates line end */
337 static char PARAdefault = '�';		/* indicates end of paragraph */
338 char UNI_marker = '�';		/* Char to be shown in place of Unicode char */
339 char TAB_marker = ' ';		/* Char to be shown in place of tab chars */
340 char TAB0_marker = '\0';	/* Char to be shown at start of tab chars */
341 char TAB2_marker = '\0';	/* Char to be shown at end of tab chars */
342 char TABmid_marker = '\0';	/* Char to be shown in middle of tab chars */
343 unsigned long CJK_TAB_marker = 0x2026;	/* to be shown in place of tab */
344 char RET_marker = '\0';		/* Char indicating end of line (LF) */
345 char DOSRET_marker = '\0';	/* Char indicating DOS end of line (CRLF) */
346 char MACRET_marker = '\0';	/* Char indicating Mac end of line (CR) */
347 char PARA_marker = '\0';	/* Char indicating end of paragraph */
348 char RETfill_marker = '\0';	/* Char to fill the end of line with */
349 char RETfini_marker = '\0';	/* Char to fill last position of line with */
350 char SHIFT_marker = '�';	/* Char indicating that line continues */
351 char SHIFT_BEG_marker = '�';	/* Char indicating that line continues left */
352 char MENU_marker = '�';		/* Char to mark selected item */
353 char * UTF_TAB_marker = NIL_PTR;	/* Char to be shown in place of tab chars */
354 char * UTF_TAB0_marker = NIL_PTR;	/* Char to be shown at start of tab chars */
355 char * UTF_TAB2_marker = NIL_PTR;	/* Char to be shown at end of tab chars */
356 char * UTF_TABmid_marker = NIL_PTR;	/* Char to be shown in middle of tab chars */
357 char * UTF_RET_marker = NIL_PTR;	/* Char indicating end of line */
358 char * UTF_DOSRET_marker = NIL_PTR;	/* Char indicating DOS end of line */
359 char * UTF_MACRET_marker = NIL_PTR;	/* Char indicating Mac end of line */
360 char * UTF_PARA_marker = NIL_PTR;	/* Char indicating end of paragraph */
361 char * UTF_RETfill_marker = NIL_PTR;	/* Char to fill the end of line with */
362 char * UTF_RETfini_marker = NIL_PTR;	/* Char to fill last position of line with */
363 char * UTF_SHIFT_marker = NIL_PTR;	/* Char indicating that line continues */
364 char * UTF_SHIFT_BEG_marker = NIL_PTR;	/* Char indicating that line continues left */
365 char * UTF_MENU_marker = "✓";		/* Char to mark selected item */
366 static char * UTF_MENU_marker_fancy = "☛";
367 static char * UTF_MENU_marker_alt = "►";
368 char * submenu_marker = "▶";
369 static char * submenu_marker_alt = "►";
370 char * menu_cont_marker = "┆";
371 char * menu_cont_fatmarker = "┇";
372 
373 /**
374    Information display preferences
375  */
376 FLAG always_disp_fstat = True;	/* Permanent file status display on status line? */
377 FLAG always_disp_help = False;	/* Permanent F2... help display on status line? */
378 FLAG always_disp_code = False;	/* Permanent char code display on status line? */
379 FLAG disp_scriptname = True;	/* display Unicode script range? */
380 FLAG disp_charname = True;	/* display Unicode character name? */
381 FLAG disp_charseqname = True;	/* display Unicode named sequences? */
382 FLAG disp_decomposition = False;	/* display Unicode character decomposition? */
383 FLAG disp_mnemos = False;	/* display mined input mnemos? */
384 
385 FLAG always_disp_Han = False;	/* Permanent Han character description display on status line? */
386 FLAG disp_Han_Mandarin = False;	/* display this Han pronunciation ? */
387 FLAG disp_Han_Cantonese = False;	/* display this Han pronunciation ? */
388 FLAG disp_Han_Japanese = False;	/* display this Han pronunciation ? */
389 FLAG disp_Han_Sino_Japanese = False;	/* display this Han pronunciation ? */
390 FLAG disp_Han_Hangul = False;	/* display this Han pronunciation ? */
391 FLAG disp_Han_Korean = False;	/* display this Han pronunciation ? */
392 FLAG disp_Han_Vietnamese = False;	/* display this Han pronunciation ? */
393 FLAG disp_Han_HanyuPinlu = False;	/* display this Han pronunciation ? */
394 FLAG disp_Han_HanyuPinyin = False;	/* display this Han pronunciation ? */
395 FLAG disp_Han_XHCHanyuPinyin = False;	/* display this Han pronunciation ? */
396 FLAG disp_Han_Tang = False;	/* display this Han pronunciation ? */
397 FLAG disp_Han_description = True;	/* display Han description ? */
398 FLAG disp_Han_full = True;	/* display full popup Han description ? */
399 
400 
401 /*======================================================================*\
402 |*		Mouse and other terminal interaction			*|
403 \*======================================================================*/
404 
405 static FLAG in_selection_mouse_mode = False;
406 
407 static
408 void
selection_mouse_mode(selecting)409 selection_mouse_mode (selecting)
410   FLAG selecting;
411 {
412   if (use_mouse_release) {
413 	in_selection_mouse_mode = selecting;
414 	menu_mouse_mode (selecting);
415   }
416 }
417 
418 static
419 void
mouse_scroll(S,P)420 mouse_scroll (S, P)
421   voidfunc S;
422   voidfunc P;
423 {
424   if (in_selection_mouse_mode == True) {
425 	in_selection_mouse_mode = VALID;
426 	setMARK (True);
427   }
428 
429   if (mouse_shift & shift_button) {
430 	(* P) ();
431   } else if (mouse_shift & control_button) {
432 	(* S) ();
433   } else if (disp_scrollbar && mouse_xpos == XMAX) {
434 	hop_flag = 1;
435 	(* S) ();
436   } else {
437 	int l;
438 	for (l = 0; quit == False && l < wheel_scroll && l < YMAX; l ++) {
439 		if (l > 0 && disp_scrollbar) {
440 			(void) display_scrollbar (True);
441 		}
442 		(* S) ();
443 	}
444   }
445 
446   if (in_selection_mouse_mode) {
447 	move_to (mouse_xpos, mouse_ypos);
448   }
449 }
450 
451 mousebutton_type last_mouse_event = movebutton;
452 static mousebutton_type prev_mouse_event = movebutton;
453 static int prev_x = -1;
454 static int prev_y = -1;
455 
456 #define dont_debug_mouse
457 
458 /*
459  * MOUSEfunction () is invoked after a mouse escape sequence with
460    coordinates and button info already stored in
461    mouse_xpos, mouse_ypos, and mouse_button.
462    Then it performs a menu or other mouse controlled function.
463  * FOCUSout and FOCUSin are special cases of mouse report for
464    the window losing or gaining focus.
465  * AMBIGnarrow and AMBIGwide are mintty reports of changed ambiguous
466    character width (corresponding to xterm option -cjk_width).
467  */
468 /*
469    MOUSEfunction is most often called after checking parameter from
470    _readchar, as follows:
471 	(_readchar:)
472 	DIRECTxtermgetxy ('M');
473 	keyproc = MOUSEfunction;
474 
475    MOUSEfunction may also be called after reading and arranging the
476    parameters, as follows:
477    DIRECTxterm ()
478    {
479      DIRECTxtermgetxy ('M');
480      MOUSEfunction ();
481    }
482  */
483 void
MOUSEfunction()484 MOUSEfunction ()
485 {
486   if (! window_focus) {
487 	return;
488   }
489   prev_mouse_event = last_mouse_event;
490   last_mouse_event = mouse_button;
491 
492   trace_mouse ("MOUSEfunction");
493 
494   if (mouse_ypos < -1) {
495 	/* click in filename tab label area */
496 	if (use_file_tabs) {
497 		char * fn = filelist_search (mouse_ypos + MENU, mouse_xpos);
498 		if (fn) {
499 			if (! streq (fn, file_name)) {
500 				save_text_load_file (fn);
501 			}
502 		} else {
503 			/* "No specific file selected" - clicked on gap */
504 		}
505 	}
506   } else if (mouse_ypos == -1
507 	&& ! in_selection_mouse_mode
508 	/* double-check whether movebutton enabled for buggy Haiku Terminal */
509 	&& (mouse_button != movebutton || use_mouse_anymove_always)
510 	) {
511 	openmenuat (mouse_xpos);
512   } else if (mouse_button == wheelup) {
513 	mouse_scroll (SU, MOVPU);
514   } else if (mouse_button == wheeldown) {
515 	mouse_scroll (SD, MOVPD);
516   } else if (disp_scrollbar && mouse_xpos == XMAX) {
517 	static int last_dir = 1;
518 	if (mouse_button == leftbutton) {
519 		if (old_scrollbar_clickmode) {
520 			MOVPD ();
521 		} else {
522 			int cmp = check_scrollbar_pos ();
523 			if (cmp < 0) {
524 				MOVPU ();
525 				last_dir = -1;
526 			} else if (cmp > 0) {
527 				MOVPD ();
528 				last_dir = 1;
529 			}
530 		}
531 	} else if (mouse_button == rightbutton) {
532 		if (old_scrollbar_clickmode) {
533 			MOVPU ();
534 		} else {
535 			int cmp = check_scrollbar_pos ();
536 			if (cmp < 0) {
537 				MOVPD ();
538 			} else if (cmp > 0) {
539 				MOVPU ();
540 			} else if (last_dir > 0) {
541 				MOVPU ();
542 			} else {
543 				MOVPD ();
544 			}
545 		}
546 	} else if (mouse_button == middlebutton
547 		   || (mouse_button == releasebutton
548 		       && mouse_prevbutton == middlebutton)
549 		   || (mouse_button == movebutton
550 		       /* double-check for the sake of buggy Haiku Terminal */
551 		       && mouse_buttons_pressed > 0
552 		      )
553 		  ) {
554 		int proz = (mouse_ypos + 1) * 100 / YMAX;
555 		if (proz > 100) {
556 			goproz (100);
557 		} else {
558 			goproz ((mouse_ypos + 1) * 100 / YMAX);
559 		}
560 	}
561 #if defined (unix) || defined (vms)
562 	/* enable scrollbar dragging */
563 	if (mouse_button != releasebutton) {
564 		mouse_button_event_mode (True);
565 	}
566 #endif
567   } else if (mouse_button == movebutton) {
568 	/* keep drag-and-copy enabled */
569 	report_release = True;
570 #ifdef debug_mouse
571 	printf ("MOUSEfunction: report_release = True\n");
572 #endif
573 
574 	/* workaround for rxvt-unicode quirk:
575 		urxvt focus-in sends 3 mouse event codes: click, move, release
576 	 */
577 	if (mouse_prevbutton == leftbutton
578 	    && mouse_xpos == mouse_prevxpos && mouse_ypos == mouse_prevypos
579 	   ) {
580 		if (rxvt_version > 0) {
581 			FOCUSin ();
582 			last_mouse_event = mouse_button;
583 		}
584 	} else if (in_selection_mouse_mode) {
585 		/* initiate visual selection */
586 		if (in_selection_mouse_mode == True) {
587 			in_selection_mouse_mode = VALID;
588 			setMARK (True);
589 		}
590 		/* extend visual selection */
591 		if (mouse_ypos == -1) {
592 			mouse_scroll (SU, MOVPU);
593 			move_to (mouse_xpos, 0);
594 		} else if (mouse_ypos == YMAX) {
595 			mouse_scroll (SD, MOVPD);
596 			move_to (mouse_xpos, YMAX - 1);
597 		} else {
598 			FLAG alt_mouse = mouse_shift & alt_button
599 					? True
600 					: False;
601 			adjust_rectangular_mode (alt_mouse);
602 			move_to (mouse_xpos, mouse_ypos);
603 		}
604 	} else if (use_mouse_anymove_always) {
605 		/* click-free mouse interface (alpha, experimental) */
606 		if (! char_ready_within (350, "mouse")) {
607 			if (mouse_ypos == -1) {	/* menu stuff */
608 				openmenuat (mouse_xpos);
609 			}
610 		}
611 	}
612   } else if (mouse_ypos == YMAX
613 	     /* ensure that release on bottom line terminates selection */
614 	     && mouse_button != releasebutton) {
615 	if (mouse_button == leftbutton) {
616 		MOVPD ();
617 	} else if (mouse_button == middlebutton) {
618 		if (always_disp_fstat) {
619 			display_code ();
620 		} else {
621 			FS ();
622 		}
623 	} else if (mouse_button == rightbutton) {
624 		MOVPU ();
625 	}
626   } else if (quickmenu) {
627 	if (mouse_ypos > last_y) {
628 		mouse_ypos = last_y;
629 	}
630 
631 	if (mouse_button == leftbutton) {
632 		char * prev_text = cur_text;
633 		prev_x = x;
634 		prev_y = y;
635 		move_to (mouse_xpos, mouse_ypos);
636 
637 		if (x == prev_x && y == prev_y
638 		    && cur_text == prev_text	/* unless moved or shifted */
639 		    && last_delta_readchar < 500	/* unless too slow */
640 		   ) {
641 			/* word selection on double click */
642 			MNW ();
643 			setMARK (True);
644 			MPW ();
645 		} else {
646 			if (! visselect_autocopy && ! mouse_shift) {
647 				clear_highlight_selection ();
648 				/* setMARK (True); */
649 			}
650 			if (shift_selection && (mouse_shift & shift_button)) {
651 				continue_highlight_selection (mouse_xpos);
652 			}
653 		}
654 
655 		/* enable drag-and-copy */
656 		report_release = True;
657 #ifdef debug_mouse
658 		printf ("MOUSEfunction: report_release = True\n");
659 #endif
660 
661 		/* enable visual selection */
662 		selection_mouse_mode (True);
663 	} else if (mouse_button == middlebutton) {
664 		if (always_disp_fstat) {
665 			display_code ();
666 		} else {
667 			FS ();
668 		}
669 	} else if (mouse_button == rightbutton) {
670 		if (! shift_selection) {
671 			move_to (mouse_xpos, mouse_ypos);
672 		}
673 		display_flush ();
674 		QUICKMENU ();
675 	} else if (mouse_button == releasebutton
676 			&& mouse_prevbutton == leftbutton
677 			&& (mouse_xpos != mouse_prevxpos
678 			    || mouse_ypos != mouse_prevypos)) {
679 		/* mouse-drag selection in terminal without move reports */
680 		if (in_selection_mouse_mode != VALID) {
681 			setMARK (True);
682 		}
683 		move_to (mouse_xpos, mouse_ypos);
684 		if (visselect_autocopy) {
685 			COPY ();
686 		}
687 		if (in_selection_mouse_mode) {
688 			selection_mouse_mode (False);
689 		}
690 	} else if (mouse_button == releasebutton && in_selection_mouse_mode
691 			&& (mouse_xpos != mouse_prevxpos
692 			    || mouse_ypos != mouse_prevypos)) {
693 		/* mouse-drag selection in terminal with mouse move reports */
694 		move_to (mouse_xpos, mouse_ypos);
695 		if (visselect_autocopy) {
696 			COPY ();
697 		}
698 		selection_mouse_mode (False);
699 	} else if (mouse_button == releasebutton
700 		   && prev_mouse_event == focusin
701 		   && rxvt_version > 0
702 		  ) {
703 			/* try to revert previous click-positioning? */
704 			move_to (prev_x, prev_y);
705 	} else {
706 		/* catch short click/release to not keep up selection */
707 		if (in_selection_mouse_mode) {
708 			selection_mouse_mode (False);
709 		}
710 	}
711   } else {
712 	prev_x = x;
713 	prev_y = y;
714 
715 	if (mouse_ypos > last_y) {
716 		mouse_ypos = last_y;
717 	}
718 	move_to (mouse_xpos, mouse_ypos);
719 
720 	if (mouse_button == leftbutton) {
721 		if (x == prev_x && y == prev_y) {
722 			MNW ();
723 			setMARK (True);
724 			MPW ();
725 		} else {
726 			setMARK (True);
727 		}
728 	} else if (mouse_button == middlebutton) {
729 		PASTE ();
730 	} else if (mouse_button == rightbutton) {
731 		COPY ();
732 	}
733   }
734 }
735 
736 void
FOCUSout()737 FOCUSout ()
738 {
739 #ifdef debug_mouse
740   printf ("mouse focus out\n");
741 #endif
742   window_focus = False;
743   mouse_button = focusout;
744 }
745 
746 void
FOCUSin()747 FOCUSin ()
748 {
749 #ifdef debug_mouse
750   printf ("mouse focus in\n");
751 #endif
752   window_focus = True;
753   mouse_button = focusin;
754 }
755 
756 void
AMBIGnarrow()757 AMBIGnarrow ()
758 {
759   /*check_cjk_width ();*/
760 
761   width_data_version = cjk_width_data_version;
762   cjk_width_data_version = 0;
763   config_markers ();
764 
765   RDwin ();
766 }
767 
768 void
AMBIGwide()769 AMBIGwide ()
770 {
771   /*check_cjk_width ();*/
772   cjk_width_data_version = width_data_version;
773 
774   fine_scrollbar = False;
775   limited_marker_font = True;
776   if (! explicit_border_style) {
777 	use_stylish_menu_selection = False;
778   }
779   config_markers ();
780 
781   RDwin ();
782 }
783 
784 
785 /*======================================================================*\
786 |*		Screen size handling					*|
787 \*======================================================================*/
788 
789 #ifdef msdos
790 #ifdef __TURBOC__
791 #define msdos_screenfunctions
792 #endif
793 #endif
794 
795 
796 #define dont_debug_checkwinsize
797 
798 #ifdef debug_checkwinsize
799 #define trace_checkwinsize(params)	printf params
800 #else
801 #define trace_checkwinsize(params)
802 #endif
803 
804 static
805 void
change_screen_size(sb,keep_columns)806 change_screen_size (sb, keep_columns)
807   FLAG sb;
808   FLAG keep_columns;
809 {
810   trace_checkwinsize (("change_screen_size (HOP %d) SML/BIG %d keep_col %d\n", hop_flag, sb, keep_columns));
811 /* Experimental area: */
812 /*	set_screen_mode (mode1);	any available mode number */
813 /*	set_video_lines (mode1);	0/1/2: 200/350/400 lines */
814 	/* does not seem to have any effect */
815 /*	set_textmode_height (mode1);	0/1/2: font height 8/14/16 */
816 /*	set_grafmode_height (mode1, mode2);
817 		0/1/2: font height 8/14/16 1/2/3/n: 14/25/43/n lines */
818 /*	set_fontbank (f);		0..7 */
819 /**/
820   if (hop_flag > 0) {
821     int index;
822     int mode1;
823 
824 #ifdef msdos_screenfunctions
825     int mode2;
826 
827     if (keep_columns) {
828       if (sb == BIGGER) {
829 	index = get_number ("Switch to font bank (0..7) ", '\0', & mode1);
830 	if (index == ERRORS) {
831 		return;
832 	}
833 	set_fontbank (mode1);
834       } else {
835 	index = get_number ("Set character height (<= 32 pixels) ", '\0', & mode1);
836 	if (index == ERRORS) {
837 		return;
838 	}
839 	set_font_height (mode1);
840       }
841     } else {
842       if (sb == BIGGER) {
843 #endif
844 	index = get_number ("Select video mode ", '\0', & mode1);
845 	if (index == ERRORS) {
846 		return;
847 	}
848 	set_screen_mode (mode1);
849 #ifdef msdos_screenfunctions
850       } else {
851 	index = get_number ("Select graf font (0/1/2: font height 8/14/16) ", '\0', & mode1);
852 	if (index == ERRORS) {
853 		return;
854 	}
855 	index = get_number ("Select line number (1/2/3/n: 14/25/43/n) ", '\0', & mode2);
856 	if (index == ERRORS) {
857 		return;
858 	}
859 	set_grafmode_height (mode1, mode2);	/* 0/1/2: font height 8/14/16 */
860 					/* 1/2/3/n: 14/25/43/n lines */
861       }
862     }
863 #endif
864   } else {
865 	resize_the_screen (sb, keep_columns);
866   }
867   RDwin ();
868 }
869 
870 static
871 void
change_font_size(inc)872 change_font_size (inc)
873   int inc;
874 {
875   resize_font (inc);
876   RDwin ();
877 }
878 
879 void
screenmorelines()880 screenmorelines ()
881 {
882   change_screen_size (BIGGER, True);
883 }
884 
885 void
screenlesslines()886 screenlesslines ()
887 {
888   change_screen_size (SMALLER, True);
889 }
890 
891 void
screenmorecols()892 screenmorecols ()
893 {
894   change_screen_size (BIGGER, NOT_VALID);
895 }
896 
897 void
screenlesscols()898 screenlesscols ()
899 {
900   change_screen_size (SMALLER, NOT_VALID);
901 }
902 
903 void
screenbigger()904 screenbigger ()
905 {
906   change_screen_size (BIGGER, False);
907 }
908 
909 void
screensmaller()910 screensmaller ()
911 {
912   change_screen_size (SMALLER, False);
913 }
914 
915 void
fontbigger()916 fontbigger ()
917 {
918   change_font_size (1);
919 }
920 
921 void
fontsmaller()922 fontsmaller ()
923 {
924   change_font_size (-1);
925 }
926 
927 void
fontdefault()928 fontdefault ()
929 {
930   change_font_size (0);
931 }
932 
933 void
LNCI()934 LNCI ()
935 {
936   switch_textmode_height (True);
937   RDwin ();
938 }
939 
940 void
LNSW()941 LNSW ()
942 {
943   if (hop_flag > 0) {
944 	hop_flag = 0;
945 	LNCI ();
946   } else {
947 	switch_textmode_height (False);
948 	RDwin ();
949   }
950 }
951 
952 
953 /*======================================================================*\
954 |*		Restriction handling					*|
955 \*======================================================================*/
956 
957 /*
958  * viewonlyerr () outputs an error message with a beep
959  */
960 void
viewonlyerr()961 viewonlyerr ()
962 {
963   ring_bell ();
964   error ("View only mode");
965 }
966 
967 /*
968  * restrictederr () outputs an error message with a beep
969  */
970 void
restrictederr()971 restrictederr ()
972 {
973   ring_bell ();
974   error2 ("Restricted mode", " - function not allowed");
975 }
976 
977 
978 /*
979  * Set the modified flag
980  */
981 void
set_modified()982 set_modified ()
983 {
984   if (modified == False) {
985 	modified = True;
986 #ifdef unix
987 	RD_window_title ();
988 #endif
989   }
990   clear_highlight_selection ();
991 }
992 
993 
994 /*======================================================================*\
995 |*		Keyboard macros						*|
996 \*======================================================================*/
997 
998 #define dont_enable_key_macros
999 
1000 #ifdef enable_key_macros
1001 # define debug_key_macros
1002 #endif
1003 
1004 #ifdef debug_key_macros
1005 #define trace_key_macros(params)	printf params
1006 #else
1007 #define trace_key_macros(params)
1008 #endif
1009 
1010 static FLAG key_recording = False;
1011 static FLAG key_replaying = False;
1012 
1013 #ifndef enable_key_macros
1014 void
KEYREC()1015 KEYREC ()
1016 {
1017 }
1018 static
1019 void
KEYrecord(key)1020 KEYrecord (key)
1021   unsigned long key;
1022 {
1023 }
1024 static
1025 unsigned long
KEYreplay()1026 KEYreplay ()
1027 {
1028   return 0;
1029 }
1030 #else
1031 
1032 /**
1033    first experimental attempt: one static limited buffer
1034    plan: multiple unlimited buffers, assignable to keys
1035  */
1036 static struct {
1037 	unsigned long key;
1038 	unsigned char shift;
1039 	voidfunc proc;
1040 } keyrec [] = {
1041 	{0, 0, I},
1042 	{0, 0, I},
1043 	{0, 0, I},
1044 	{0, 0, I},
1045 	{0, 0, I},
1046 	{0, 0, I},
1047 	{0, 0, I},
1048 	{0, 0, I},
1049 	{0, 0, I},
1050 	{0, 0, I},
1051 	{0, 0, I},
1052 };
1053 #define maxkeyreclen arrlen (keyrec)
1054 
1055 static int keyreci = 0;
1056 static int keyreclen = 0;
1057 
1058 void
KEYREC()1059 KEYREC ()
1060 {
1061   if (keyshift & shift_mask) {
1062 	/* Record keyboard macro */
1063 	if (key_replaying) {
1064 		/* display notice that key replaying is aborted? */
1065 		key_replaying = False;
1066 	}
1067 
1068 	if (key_recording) {
1069 		/* Stop keyboard macro recording */
1070 		key_recording = False;
1071 		keyreclen --;	/* fix KEYREC already inserted */
1072 	} else {
1073 		/* Start keyboard macro recording */
1074 		key_recording = True;
1075 		keyreci = 0;
1076 	}
1077   } else {
1078 	/* Replay keyboard macro */
1079 	if (key_recording) {
1080 		/* display notice that key recording is aborted? */
1081 		key_recording = False;
1082 	}
1083 
1084 	if (key_replaying) {
1085 		/* abort invalid recursive macro replaying */
1086 		key_replaying = False;
1087 		ring_bell ();
1088 	} else if (keyreclen > 0) {
1089 		/* Start keyboard macro replaying */
1090 		keyreci = 0;
1091 		key_replaying = True;
1092 	} else {
1093 		/* display notice that key replaying is not available? */
1094 		ring_bell ();
1095 	}
1096   }
1097 }
1098 
1099 static
1100 void
KEYrecord(key)1101 KEYrecord (key)
1102   unsigned long key;
1103 {
1104   if (keyreci >= maxkeyreclen) {
1105 	key_recording = False;
1106 	trace_key_macros (("KEYrecord buf\n"));
1107 	ring_bell ();
1108   } else {
1109 	keyrec [keyreci].key = key;
1110 	keyrec [keyreci].shift = keyshift;
1111 	keyrec [keyreci].proc = keyproc;
1112 	trace_key_macros (("KEYrecord [%d] %02lX\n", keyreci, key));
1113 	keyreci ++;
1114 	keyreclen = keyreci;
1115   }
1116 }
1117 
1118 static
1119 unsigned long
KEYreplay()1120 KEYreplay ()
1121 {
1122   unsigned long key = keyrec [keyreci].key;
1123   keyshift = keyrec [keyreci].shift;
1124   keyproc = keyrec [keyreci].proc;
1125   trace_key_macros (("KEYreplay [%d (%d)] %02lX\n", keyreci, keyreclen, key));
1126   keyreci ++;
1127   if (keyreci >= keyreclen) {
1128 	key_replaying = False;
1129   }
1130   return key;
1131 }
1132 
1133 #endif
1134 
1135 
1136 /*======================================================================*\
1137 |*		Setup display preferences				*|
1138 \*======================================================================*/
1139 
1140 /**
1141    Configure line and display markers.
1142    Width data detection must be settled for the case of UTF-8.
1143  */
1144 static
1145 void
config_markers()1146 config_markers ()
1147 {
1148   char * Mark;
1149 
1150   Mark = envvar ("MINEDSHIFT");
1151   if (Mark != NIL_PTR) {
1152 	SHIFT_BEG_marker = Mark [0];
1153 	if (SHIFT_BEG_marker == ' ') {
1154 		SHIFT_BEG_marker = '\0';
1155 	}
1156 	if (Mark [0] && Mark [1]) {
1157 		SHIFT_marker = Mark [1];
1158 	}
1159   }
1160 
1161   Mark = envvar ("MINEDTAB");
1162   if (Mark != NIL_PTR) {
1163 	if (Mark [0] == '\0') {
1164 		TAB_marker = TABdefault;
1165 	} else {
1166 		TAB_marker = Mark [0];
1167 		if (Mark [1]) {
1168 			if (Mark [2]) {
1169 				TAB0_marker = Mark [0];
1170 				TAB_marker = Mark [1];
1171 				TAB2_marker = Mark [2];
1172 			} else {
1173 				TABmid_marker = Mark [1];
1174 			}
1175 		}
1176 		if (TAB_marker >= ' ' && TAB_marker != '\\' && TAB_marker < '~') {
1177 			CJK_TAB_marker = TAB_marker;
1178 		}
1179 	}
1180   } else {
1181 	TAB_marker = TABdefault;
1182   }
1183 
1184   Mark = envvar ("MINEDRET");
1185   if (Mark != NIL_PTR) {
1186 	RET_marker = Mark [0];
1187 	if (RET_marker != '\0') {
1188 		RETfill_marker = Mark [1];
1189 	}
1190 	if (RETfill_marker != '\0') {
1191 		RETfini_marker = Mark [2];
1192 	}
1193   } else {
1194 	RET_marker = RETdefault;
1195   }
1196   Mark = envvar ("MINEDDOSRET");
1197   if (Mark && * Mark) {
1198 	DOSRET_marker = Mark [0];
1199   } else {
1200 	if (bw_term) {
1201 		DOSRET_marker = '�';
1202 	} else {
1203 		DOSRET_marker = RET_marker;
1204 	}
1205   }
1206   Mark = envvar ("MINEDMACRET");
1207   if (Mark && * Mark) {
1208 	MACRET_marker = Mark [0];
1209   } else {
1210 	if (bw_term) {
1211 		MACRET_marker = '@';
1212 	} else {
1213 		MACRET_marker = RET_marker;
1214 	}
1215   }
1216   Mark = envvar ("MINEDPARA");
1217   if (Mark && * Mark) {
1218 	PARA_marker = Mark [0];
1219   } else {
1220 	PARA_marker = PARAdefault;
1221   }
1222   Mark = envvar ("MINEDMENUMARKER");
1223   if (Mark) {
1224 	if (* Mark) {
1225 		MENU_marker = Mark [0];
1226 	} else {
1227 		/*MENU_marker = '`';*/
1228 		MENU_marker = '*';
1229 	}
1230   }
1231 
1232   if (cjk_width_data_version) {
1233 	submenu_marker = submenu_marker_alt;
1234   }
1235 
1236   if (! limited_marker_font) {
1237 	/* unlimited font settings */
1238 	UTF_SHIFT_BEG_marker = envvar ("MINEDUTFSHIFT");
1239 	if (UTF_SHIFT_BEG_marker && * UTF_SHIFT_BEG_marker) {
1240 		UTF_SHIFT_marker = UTF_SHIFT_BEG_marker;
1241 		advance_utf8 (& UTF_SHIFT_marker);
1242 		if (* UTF_SHIFT_BEG_marker == ' ') {
1243 			UTF_SHIFT_BEG_marker = "";
1244 		}
1245 	}
1246 	UTF_TAB_marker = envvar ("MINEDUTFTAB");
1247 	if (UTF_TAB_marker != NIL_PTR) {
1248 		char * markpoi = UTF_TAB_marker;
1249 		if (* markpoi) {
1250 			advance_utf8 (& markpoi);
1251 			if (* markpoi) {
1252 				UTF_TAB0_marker = UTF_TAB_marker;
1253 				UTF_TAB_marker = markpoi;
1254 				advance_utf8 (& markpoi);
1255 				if (* markpoi) {
1256 					UTF_TAB2_marker = markpoi;
1257 				} else {
1258 					UTF_TABmid_marker = UTF_TAB_marker;
1259 					UTF_TAB_marker = UTF_TAB0_marker;
1260 					UTF_TAB0_marker = NIL_PTR;
1261 				}
1262 			}
1263 		}
1264 	}
1265 	UTF_RET_marker = envvar ("MINEDUTFRET");
1266 	if (UTF_RET_marker != NIL_PTR) {
1267 		UTF_RETfill_marker = UTF_RET_marker;
1268 		if (* UTF_RETfill_marker != '\0') {
1269 			advance_utf8 (& UTF_RETfill_marker);
1270 		}
1271 		UTF_RETfini_marker = UTF_RETfill_marker;
1272 		if (* UTF_RETfini_marker != '\0') {
1273 			advance_utf8 (& UTF_RETfini_marker);
1274 		}
1275 	}
1276 	UTF_DOSRET_marker = envvar ("MINEDUTFDOSRET");
1277 	if (UTF_DOSRET_marker == NIL_PTR) {
1278 		if (bw_term) {
1279 			UTF_DOSRET_marker = "µ";
1280 		} else {
1281 			UTF_DOSRET_marker = UTF_RET_marker;
1282 		}
1283 	}
1284 	UTF_MACRET_marker = envvar ("MINEDUTFMACRET");
1285 	if (UTF_MACRET_marker == NIL_PTR) {
1286 		if (bw_term) {
1287 			UTF_MACRET_marker = "@";
1288 		} else {
1289 			UTF_MACRET_marker = UTF_RET_marker;
1290 		}
1291 	}
1292 	UTF_PARA_marker = envvar ("MINEDUTFPARA");
1293 	Mark = envvar ("MINEDUTFMENUMARKER");
1294 	if (Mark) {
1295 		if (* Mark) {
1296 			int len;
1297 			unsigned long unichar;
1298 			utf8_info (Mark, & len, & unichar);
1299 			if (len > 1 && ! iswide (unichar) && ! iscombining (unichar)) {
1300 				UTF_MENU_marker = Mark;
1301 			}
1302 		} else {
1303 			UTF_MENU_marker = UTF_MENU_marker_fancy;
1304 		}
1305 	}
1306   } else if (! very_limited_marker_font) {
1307 	/* limited font settings */
1308 	UTF_MENU_marker = UTF_MENU_marker_alt;
1309 	submenu_marker = submenu_marker_alt;
1310   } else {
1311 	/* very limited font settings */
1312 	UTF_MENU_marker = "»";
1313 	submenu_marker = "»";
1314   }
1315 }
1316 
1317 #ifdef unix
1318 
1319 static float dimfactor = 0.6;	/* MUST be >= 0 AND <= 1 ! */
1320 static float bgdimfactor = 0.15;	/* MUST be >= 0 AND <= 1 ! */
1321 
1322 static
1323 char *
get_terminal_rgb(s)1324 get_terminal_rgb (s)
1325   char * s;
1326 {
1327   char * report = get_terminal_report_string (s);
1328   if (report) {
1329 	return strstr (report, "rgb:");
1330   } else {
1331 	return NIL_PTR;
1332   }
1333 }
1334 
1335 static
1336 int
sscanrgb(s,__r,__g,__b)1337 sscanrgb (s, __r, __g, __b)
1338   char * s;
1339   unsigned int * __r;
1340   unsigned int * __g;
1341   unsigned int * __b;
1342 {
1343   char * rgb = strstr (s, "rgb:");
1344   if (rgb) {
1345 	if (sscanf (rgb, "rgb:%04X/%04X/%04X", __r, __g, __b) == 3) {
1346 		return 3;
1347 	}
1348   }
1349   return 0;
1350 }
1351 
1352 /**
1353    Determine a suitable dim mode for marker display
1354    	(TAB, line end indicators).
1355    Also check whether terminal background is dark (to adjust highlighting).
1356    * Retrieve color values of text and background colors.
1357    * Calculate a value between them.
1358    * Retrieve color value of ANSI color 7 (for later restoring).
1359    * Redefine ANSI color 7 to calculated color for use as dim attribute.
1360    Works in xterm, should work in rxvt (but doesn't...).
1361    The feature is activated if the environment variable MINEDDIM is
1362    set to an empty value.
1363    The feature is not applied if the terminal provides a native dim mode.
1364  */
1365 static
1366 FLAG
determine_dim_mode(darkcheck_only)1367 determine_dim_mode (darkcheck_only)
1368   FLAG darkcheck_only;
1369 {
1370   char * color_report;
1371   int ret;
1372   int r, g, b, _r, _g, _b, r_, g_, b_, r3, g3, b3;	/* signed! */
1373 
1374 #define dont_debug_dim_mode
1375 
1376   if (tmux_version > 0) {
1377 	return False;
1378   }
1379 
1380   /* check whether terminal can report ANSI colours */
1381   if (! (xterm_version > 2 || mintty_version >= 404 || rxvt_version >= 300 || gnome_terminal_version)) {
1382 	return False;
1383   }
1384 
1385   /* query current ANSI color 3 to fix misconfigured yellow */
1386   color_report = get_terminal_rgb ("\033]4;3;?\033\\");
1387   if (! color_report) {
1388 	return False;
1389   }
1390   /* only redefine yellow if it's grossly misconfigured */
1391   ret = sscanrgb (color_report, & r3, & g3, & b3);
1392 #ifdef debug_dim_mode
1393   printf ("ANSI color 3 (yellow) %s -> %d: %04X %04X %04X\n", color_report, ret, r3, g3, b3);
1394 #endif
1395   if (ret < 3) {
1396 	return False;
1397   }
1398   /* build escape string to restore ANSI color 3 */
1399   build_string (restore_ansi3, "\033]4;3;%s\033\\", color_report);
1400   /* check whether yellow is too dark (e.g. actually more brown) */
1401   r = (r3 - 0xC000) >> 8;
1402   g = (g3 - 0xC000) >> 8;
1403   b = b3 >> 8;
1404   if (r * r + g * g + b * b > 12000) {
1405 	redefined_ansi3 = True;
1406 	/* build escape string to define ANSI color 3 as yellow */
1407 	build_string (set_ansi3, "\033]4;3;rgb:C000/C000/0000\033\\");
1408 #ifdef debug_dim_mode
1409 	printf (" redefining yellow %s\n", set_ansi3 + 6);
1410 #endif
1411 	/* redefine ANSI color 3 as yellow */
1412 	putescape (set_ansi3);
1413   }
1414 
1415   /* check whether terminal can report background colours */
1416   if (! (xterm_version > 0 || mintty_version >= 404 || rxvt_version >= 300)) {
1417 	return False;
1418   }
1419 
1420   /* query terminal background color */
1421   color_report = get_terminal_rgb ("\033]11;?\033\\");
1422   if (! color_report) {
1423 	return False;
1424   }
1425   /* analyse query result */
1426   ret = sscanrgb (color_report, & _r, & _g, & _b);
1427 #ifdef debug_dim_mode
1428   printf ("background color %s -> %d: %04X %04X %04X\n", color_report, ret, _r, _g, _b);
1429 #endif
1430   if (ret < 3) {
1431 	return False;
1432   }
1433 
1434   darkness_detected = True;
1435 
1436   /* check dark background */
1437   if (_r + _g + _b < 99000) {	/* range is 0...65535 * 3 */
1438 	dark_term = True;
1439 #ifdef debug_dim_mode
1440 	printf (" -> dark_term\n");
1441 #endif
1442   }
1443 
1444   /* query color 48, the one with the largest difference between
1445      256 color mode and 88 color mode
1446    */
1447   color_report = get_terminal_rgb ("\033]4;48;?\033\\");
1448 	if (color_report) {
1449 	/* analyse query result */
1450 	ret = sscanrgb (color_report, & r, & g, & b);
1451 #ifdef debug_dim_mode
1452 	printf ("color 48 %s -> %d: %04X %04X %04X\n", color_report, ret, r, g, b);
1453 #endif
1454 	/* check whether it's nearer to color 48 of
1455 	   256 color mode or 88 color mode
1456 	 */
1457 	if (ret == 3) {
1458 		/* difference to 88 color mode color 48 */
1459 		int _r = r - 170;
1460 		int _g = g - 0;
1461 		int _b = b - 0;
1462 		/* difference to 256 color mode color 48 */
1463 		int r_ = r - 0;
1464 		int g_ = g - 255;
1465 		int b_ = b - 102;
1466 		if (_r * _r + _g * _g + _b * _b < r_ * r_ + g_ * g_ + b_ * b_) {
1467 			colours_88 = True;
1468 			colours_256 = False;
1469 		} else {
1470 			colours_256 = True;
1471 			colours_88 = False;
1472 		}
1473 #ifdef debug_dim_mode
1474 		printf (" detected %d color mode\n", colours_256 ? 256 : 88);
1475 #endif
1476 	}
1477   }
1478 
1479 #ifdef dont_use_dimmed_menu_bg
1480   if (darkcheck_only) {
1481 	return dark_term;
1482   }
1483   /* check whether we need to dim ourselves */
1484   if (can_dim) {
1485 #ifdef debug_dim_mode
1486 	printf ("terminal has native dim attribute, not redefining colours\n");
1487 #endif
1488 	return False;
1489   }
1490 #endif
1491 
1492   /* query terminal text color */
1493   color_report = get_terminal_rgb ("\033]10;?\033\\");
1494   if (! color_report) {
1495 	return darkcheck_only ? dark_term : False;
1496   }
1497   /* analyse query result */
1498   ret = sscanrgb (color_report, & r, & g, & b);
1499 #ifdef debug_dim_mode
1500   printf ("foreground color %s -> %d: %04X %04X %04X\n", color_report, ret, r, g, b);
1501 #endif
1502   if (ret < 3) {
1503 	return darkcheck_only ? dark_term : False;
1504   }
1505 
1506   if (! mlterm_version) {
1507     /* query terminal cursor color */
1508     color_report = get_terminal_rgb ("\033]12;?\033\\");
1509     if (color_report) {
1510 	/* analyse query result */
1511 	ret = sscanrgb (color_report, & r_, & g_, & b_);
1512 #ifdef debug_dim_mode
1513 	printf ("cursor color %s -> %d: %04X %04X %04X\n", color_report, ret, r_, g_, b_);
1514 #endif
1515 	if (ret == 3) {
1516 	    if ((r_ == r && g_ == g && b_ == b) || (r_ == _r && g_ == _g && b_ == _b)) {
1517 		redefined_curscolr = True;
1518 		/* build escape string to restore cursor color */
1519 		build_string (restore_curscolr, "\033]12;%s\033\\", color_report);
1520 		/* ensure cursor contrast */
1521 		/* calculate cursor color, between foreground and background */
1522 		r_ = _r + (r - _r) / 2;
1523 		g_ = _g + (g - _g) / 2;
1524 		b_ = _b + (b - _b) / 2;
1525 		/* build escape string to define cursor color */
1526 		build_string (set_curscolr, "\033]12;rgb:%04X/%04X/%04X\033\\", r_, g_, b_);
1527 #ifdef debug_dim_mode
1528 		printf (" using cursor color %s\n", set_curscolr + 6);
1529 #endif
1530 		/* redefine cursor color */
1531 		putescape (set_curscolr);
1532 	    }
1533 	}
1534     }
1535   }
1536 
1537   /* check whether text color is near yellow */
1538   r3 = (0xC000 - r) >> 8;
1539   g3 = (0xC000 - g) >> 8;
1540   b3 = (0x0000 - b) >> 8;
1541   /* use blue (for flags) rather than yellow */
1542   if (r3 * r3 + g3 * g3 + b3 * b3 < 12000) {
1543 	fg_yellowish = True;
1544   }
1545 
1546   /* query current ANSI color 2 */
1547   color_report = get_terminal_rgb ("\033]4;2;?\033\\");
1548   if (! color_report) {
1549 	return darkcheck_only ? dark_term : False;
1550   }
1551   /* build escape string to restore ANSI color 2 */
1552   build_string (restore_ansi2, "\033]4;2;%s\033\\", color_report);
1553   redefined_ansi2 = True;
1554   /* calculate menu bg color, dimmed from background */
1555   if (r + g + b > _r + _g + _b) {
1556 	r_ = _r + (65535 - _r) * bgdimfactor;
1557 	g_ = _g + (65535 - _g) * bgdimfactor;
1558 	b_ = _b + (65535 - _b) * bgdimfactor;
1559 #ifdef debug_dim_mode
1560 	printf (" %d,%d,%d > %d,%d,%d -> %d,%d,%d\n", r, g, b, _r, _g, _b, r_, g_, b_);
1561 #endif
1562   } else {
1563 	r_ = _r + (0 - _r) * bgdimfactor;
1564 	g_ = _g + (0 - _g) * bgdimfactor;
1565 	b_ = _b + (0 - _b) * bgdimfactor;
1566 #ifdef debug_dim_mode
1567 	printf (" %d,%d,%d < %d,%d,%d -> %d,%d,%d\n", r, g, b, _r, _g, _b, r_, g_, b_);
1568 #endif
1569   }
1570   /* build escape string to define ANSI color 2 as menu bg color */
1571   build_string (set_ansi2, "\033]4;2;rgb:%04X/%04X/%04X\033\\", r_, g_, b_);
1572 #ifdef debug_dim_mode
1573   printf (" using menu bg color %s\n", set_ansi2 + 6);
1574 #endif
1575   /* redefine ANSI color 2 as menu bg color */
1576   putescape (set_ansi2);
1577 
1578   if (darkcheck_only) {
1579 #ifdef debug_dim_mode
1580 	printf ("darkcheck only\n");
1581 #endif
1582 	return dark_term;
1583   }
1584   /* check whether we need to dim ourselves */
1585   if (can_dim) {
1586 #ifdef debug_dim_mode
1587 	printf ("terminal has native dim attribute, not redefining colours\n");
1588 #endif
1589 	return False;
1590   }
1591 
1592   /* query current ANSI color 7 */
1593   color_report = get_terminal_rgb ("\033]4;7;?\033\\");
1594   if (! color_report) {
1595 	return False;
1596   }
1597   /* build escape string to restore ANSI color 7 */
1598   build_string (restore_ansi7, "\033]4;7;%s\033\\", color_report);
1599   redefined_ansi7 = True;
1600   /* calculate dim color, between foreground and background */
1601   r_ = _r + (r - _r) * dimfactor;
1602   g_ = _g + (g - _g) * dimfactor;
1603   b_ = _b + (b - _b) * dimfactor;
1604   /* mix in some red */
1605   r_ += (65535 - r_) / 2;
1606   /* build escape string to define ANSI color 7 as dim color */
1607   build_string (set_ansi7, "\033]4;7;rgb:%04X/%04X/%04X\033\\", r_, g_, b_);
1608 #ifdef debug_dim_mode
1609   printf (" using dim color %s\n", set_ansi7 + 6);
1610 #endif
1611   /* redefine ANSI color 7 as dim color */
1612   putescape (set_ansi7);
1613 
1614   return True;
1615 }
1616 
1617 #else
1618 
1619 static
1620 FLAG
determine_dim_mode(darkcheck_only)1621 determine_dim_mode (darkcheck_only)
1622   FLAG darkcheck_only;
1623 {
1624   return False;
1625 }
1626 
1627 #endif
1628 
1629 /**
1630    Setup configured display attributes for certain items
1631  */
1632 static
1633 void
get_ansi_modes()1634 get_ansi_modes ()
1635 {
1636   markansi = envvar ("MINEDDIM");
1637   if (markansi != NIL_PTR) {
1638 #ifdef unix
1639 	/* check if MINEDDIM is a percentage value */
1640 	int dim_percent;
1641 	char c;
1642 	int res = sscanf (markansi, "%d%c", & dim_percent, & c);
1643 	if (res == 2 && c == '%' && dim_percent > 0 && dim_percent < 100) {
1644 		dimfactor = dim_percent / 100.0;
1645 		markansi = "";	/* trigger procedure below */
1646 	}
1647 #endif
1648   }
1649   if (markansi == NIL_PTR || * markansi == '\0') {
1650 	if (determine_dim_mode (False)) {
1651 		markansi = "37";	/* use redefined ANSI color 7 */
1652 	} else {
1653 		markansi = "31";	/* use red */
1654 	}
1655   } else {
1656 	(void) determine_dim_mode (True);
1657   }
1658 
1659   emphansi = envvar ("MINEDEMPH");
1660   if (emphansi == NIL_PTR) {
1661 	emphansi = "31";	/* use red */
1662   }
1663 
1664   borderansi = envvar ("MINEDBORDER");
1665   if (borderansi == NIL_PTR) {
1666 	borderansi = "31";
1667   }
1668 
1669   selansi = envvar ("MINEDSEL");
1670   selfgansi = envvar ("MINEDSELFG");
1671   if (selfgansi == NIL_PTR) {
1672 	selfgansi = "43";
1673   }
1674   if (selansi == NIL_PTR) {
1675 	if (dark_term) {
1676 		selansi = "34;1";
1677 	} else {
1678 		selansi = "34";
1679 	}
1680   }
1681 
1682   uniansi = envvar ("MINEDUNI");
1683   if (uniansi == NIL_PTR) {
1684 	if (cjk_term) {
1685 		/* needed for hanterm */
1686 		uniansi = "36;7;40";
1687 	} else {
1688 		uniansi = "40;36;7";
1689 	}
1690   } else if ((character) * uniansi > '9') {
1691 	UNI_marker = * uniansi;
1692 	do {
1693 		uniansi ++;
1694 	} while (* uniansi == ' ');
1695   }
1696   specialansi = envvar ("MINEDSPECIAL");
1697   if (specialansi == NIL_PTR) {
1698 	specialansi = "36;1";
1699   }
1700   combiningansi = envvar ("MINEDCOMBINING");
1701   if (combiningansi == NIL_PTR) {
1702 	combiningansi = "46;30";
1703   }
1704 
1705   ctrlansi = envvar ("MINEDCTRL");
1706   if (ctrlansi == NIL_PTR) {
1707 	ctrlansi = "";
1708   }
1709   menuansi = envvar ("MINEDMENU");
1710   if (menuansi == NIL_PTR) {
1711 	menuansi = "";
1712   }
1713   HTMLansi = envvar ("MINEDHTML");
1714   if (HTMLansi == NIL_PTR) {
1715 	if (dark_term) {
1716 		HTMLansi = "36";	/* conflicts with JSP */
1717 		HTMLansi = "1;34";	/* not sufficient with dark blue */
1718 		HTMLansi = "34;42";
1719 		HTMLansi = "34;46";
1720 #ifdef special_case_for_very_dark
1721 		if (streq ("cygwin", TERM)) {
1722 			HTMLansi = "1;36";
1723 		}
1724 #endif
1725 	} else {
1726 		HTMLansi = "34";
1727 	}
1728   }
1729   XMLattribansi = envvar ("MINEDXMLATTRIB");
1730   if (XMLattribansi == NIL_PTR) {
1731 	if (dark_term) {
1732 		XMLattribansi = "31;46";
1733 	} else {
1734 		XMLattribansi = "31";
1735 	}
1736   }
1737   XMLvalueansi = envvar ("MINEDXMLVALUE");
1738   if (XMLvalueansi == NIL_PTR) {
1739 	if (dark_term) {
1740 		XMLvalueansi = "35;1;46";
1741 	} else {
1742 		XMLvalueansi = "35;1";
1743 	}
1744   }
1745   diagansi = envstr ("MINEDDIAG");
1746 
1747   scrollbgansi = envvar ("MINEDSCROLLBG");
1748   if (scrollbgansi == NIL_PTR) {
1749 	if (colours_256 || colours_88) {
1750 		/*scrollbgansi = "34;48;5;45";*/
1751 		scrollbgansi = "46;34;48;5;45";
1752 	} else {
1753 		scrollbgansi = "46;34";
1754 	}
1755   }
1756   scrollfgansi = envvar ("MINEDSCROLLFG");
1757   if (scrollfgansi == NIL_PTR) {
1758 	scrollfgansi = "";
1759 	if (colours_256 || colours_88) {
1760 		/*scrollfgansi = "44;38;5;45";*/
1761 		/*scrollfgansi = "44;36;38;5;45";*/
1762 	} else if (cjk_term && (text_encoding_tag == 'K' || text_encoding_tag == 'H')
1763 		  && strisprefix ("xterm", TERM)
1764 	    ) {
1765 		/* probably hanterm; attributes will all be reverse
1766 		   and could not be distinguished to build the scrollbar
1767 		 */
1768 		/*scrollfgansi = "0";*/
1769 		scrollfgansi = "44;36";
1770 	} else {
1771 		/*scrollfgansi = "44;36";*/
1772 	}
1773   }
1774 }
1775 
1776 
1777 /*======================================================================*\
1778 |*		Terminal report, window resize handling			*|
1779 \*======================================================================*/
1780 
1781 #define dont_debug_queries
1782 
1783 #define dont_debug_ansiseq
1784 #define dont_debug_expect
1785 
1786 #ifdef debug_expect
1787 #warning extra debug read will provoke hanging
1788 # define debug_queries
1789 #define trace_expect(params)	printf ("[%lu] ", gettime ()); printf params
1790 static
1791 unsigned long
gettime()1792 gettime ()
1793 {
1794   struct timeval now;
1795   gettimeofday (& now, 0);
1796   return ((long) now.tv_sec) * 1000000 + now.tv_usec;
1797 }
1798 #else
1799 #define trace_expect(params)
1800 #endif
1801 
1802 #ifdef debug_queries
1803 # define debug_ansiseq
1804 #define trace_query(params)	printf params
1805 #else
1806 #define trace_query(params)
1807 #endif
1808 
1809 
1810 /* For the initial terminal report request, balance the delay time
1811    (to accept a response) so that reponses via slow remote
1812    terminal lines can be acquired but the user delay on a
1813    terminal that doesn't respond at all remains acceptable.
1814  */
1815 static int escape_delay = 0;		/* wait to detect escape sequence */
1816 #ifdef vms
1817 static int default_escape_delay = 2000;	/* overridden by $ESCDELAY */
1818 #else
1819 static int default_escape_delay = 450;	/* overridden by $ESCDELAY */
1820 #endif
1821 
1822 static
1823 void
adjust_escdelay()1824 adjust_escdelay ()
1825 {
1826   if (escape_delay == 0) {
1827 	char * env = envvar ("ESCDELAY");
1828 	if (env) {
1829 		(void) scan_int (env, & escape_delay);
1830 	}
1831 
1832 	/**
1833 	   The default escape waiting delay (or minimum, see below)
1834 	   is a trade-off between terminals that do not respond to
1835 	   certain requests and supporting slow remote connections
1836 	   on which extended delay is needed before timeout.
1837 	 */
1838 	if (strisprefix ("rxvt", TERM)) {
1839 		/* accept slow rxvt DA report */
1840 		default_escape_delay = 25555;
1841 	} else if (strisprefix ("xterm", TERM)
1842 		|| strisprefix ("screen", TERM)
1843 		|| (strisprefix ("vt", TERM) && TERM [2] >= '2' && TERM [2] < '5')
1844 		) {
1845 		/* support slower remote connections */
1846 		default_escape_delay = 3333;
1847 	}
1848 
1849 	/* if unset (== 0) or too small (e.g. ESCDELAY=200), set to default */
1850 	if (escape_delay < default_escape_delay) {
1851 		escape_delay = default_escape_delay;
1852 	}
1853   }
1854 }
1855 
1856 static
1857 character
expect1byte(timeout,debug_tag)1858 expect1byte (timeout, debug_tag)
1859   FLAG timeout;
1860   char * debug_tag;
1861 {
1862   character c;
1863   FLAG awaiting = True;
1864   int delay = escape_delay;
1865   if (timeout == UNSURE) {
1866 	/* timeout, but not too long, in case response is disabled */
1867 	delay = 555;
1868   }
1869 
1870   if (xterm_version > 0 || mintty_version > 0 || rxvt_version > 0) {
1871 	/* if we know the terminal should respond, don't timeout
1872 	   in order to avoid garbage from late responses
1873 	 */
1874   }
1875 
1876   trace_expect (("expect1byte [%s] (%d) escdel %d/%d\n", unnull (debug_tag), timeout, escape_delay, delay));
1877   if (char_ready_within (delay, "expect")) {
1878 	awaiting = False;
1879   }
1880 
1881   if (timeout && awaiting) {
1882 	trace_expect (("expect1byte [%s] timeout\n", unnull (debug_tag)));
1883 #ifdef debug_expect
1884 	c = read1byte ();
1885 	trace_expect (("expect1byte [%s] read after timeout %02X\n", unnull (debug_tag), c));
1886 #endif
1887 	return 0;
1888   }
1889 
1890   if (awaiting) {
1891 	status_uni ("... awaiting slow terminal response ...");
1892   }
1893 
1894   if (timeout && streq (debug_tag, "acquire") && strisprefix ("rxvt", TERM)) {
1895 	status_uni ("... waiting for rxvt to report device attributes ...");
1896   }
1897 
1898   c = read1byte ();
1899   trace_expect (("expect1byte [%s] read %02X\n", unnull (debug_tag), c));
1900 
1901   if (awaiting) {
1902 	clear_status ();
1903   }
1904   return c;
1905 }
1906 
1907 
1908 static
1909 FLAG
receiving_response(c,debug_tag)1910 receiving_response (c, debug_tag)
1911   character c;
1912   char * debug_tag;
1913 {
1914   if (c == '\033') {
1915 	return True;
1916   }
1917 #ifdef debug_queries
1918   printf ("not receiving response [%s] (esc_delay %d) (%02X)\n", unnull (debug_tag), escape_delay, c);
1919 #endif
1920   flush_keyboard ();
1921   return False;
1922 }
1923 
1924 /**
1925    Check ANSI escape sequence (which has already been read)
1926  */
1927 void
ANSIseq()1928 ANSIseq ()
1929 {
1930 #ifdef debug_ansiseq
1931   printf ("ANSIseq %d:", ansi_params);
1932   {	int i;
1933 	for (i = 0; i < ansi_params; i ++) {
1934 		printf (" %d", ansi_param [i]);
1935 	}
1936 	printf (" %c\n", ansi_fini);
1937   }
1938 #endif
1939 
1940   if (ansi_fini == 'R') {
1941 	/* could also be modified F3, though, not to arrive here */
1942 	status_line ("Late screen mode response ",
1943 		"- set ESCDELAY=2000 or higher for proper detection");
1944   } else if (ansi_fini == 't') {
1945 	if (ansi_params == 3 && ansi_param [0] == 8) {
1946 # ifdef debug_terminal_resize
1947 		printf ("received terminal size report %dx%d\n", ansi_param [1], ansi_param [2]);
1948 # endif
1949 #ifdef adjust_to_actual_termsize
1950 		/* adjust to actual screen size reported by terminal */
1951 		if (YMAX != ansi_param [1] - 1 - MENU || XMAX != ansi_param [2] - 1) {
1952 			YMAX = ansi_param [1] - 1 - MENU;
1953 			XMAX = ansi_param [2] - 1;
1954 			RD ();
1955 			... see RDwin
1956 			flush ();
1957 		}
1958 #endif
1959 	} else {
1960 		error ("Unknown terminal status report");
1961 	}
1962   } else if (ansi_fini == 'c') {
1963 	if (strisprefix ("rxvt", TERM)) {
1964 		error ("Late device attribute report - restart mined for proper screen detection");
1965 	} else {
1966 		error ("Unexpected (delayed) device attribute report");
1967 	}
1968   } else {
1969 	error ("Unknown keyboard control sequence");
1970   }
1971 }
1972 
1973 
1974 static
1975 FLAG
get_CPR(rowpoi,colpoi)1976 get_CPR (rowpoi, colpoi)
1977   int * rowpoi;
1978   int * colpoi;
1979 {
1980   character c;
1981   /* apply timeout to cursor position report? */
1982   static FLAG timeout_CPR = True;
1983   trace_checkwinsize (("get_CPR\n"));
1984 
1985   if (cygwin_console) {
1986 	trace_query (("-> skipped on cygwin console\n"));
1987 	return False;
1988   }
1989 
1990   adjust_escdelay ();
1991   trace_query (("query CPR\n"));
1992 
1993   c = expect1byte (timeout_CPR, "CPR");	/* ESC */
1994   if (receiving_response (c, "CPR")) {
1995 	int row, col;
1996 	timeout_CPR = False;
1997 	c = expect1byte (False, "CPR.");	/* '[' */
1998 	c = get_digits (& row);
1999 	if (c == ';') {
2000 		c = get_digits (& col);
2001 		* rowpoi = row;
2002 		* colpoi = col;
2003 
2004 		trace_checkwinsize (("get_CPR %d %d\n", row, col));
2005 		trace_query (("-> %d %d\n", row, col));
2006 		return True;
2007 	}
2008   }
2009 
2010   trace_checkwinsize (("get_CPR failed\n"));
2011   trace_query (("-> failed\n"));
2012   return False;
2013 }
2014 
2015 static
2016 FLAG
get_TSZ(rowpoi,colpoi)2017 get_TSZ (rowpoi, colpoi)
2018   int * rowpoi;
2019   int * colpoi;
2020 {
2021   character c;
2022   /* apply timeout to cursor position report? */
2023   static FLAG timeout_CPR = True;
2024   trace_query (("query TSZ\n"));
2025 
2026   if (! can_report_props || xterm_version == 2) {
2027 	trace_query (("-> skipped\n"));
2028 	return False;
2029   }
2030 
2031   adjust_escdelay ();
2032 
2033   c = expect1byte (timeout_CPR, "TSZ");	/* ESC */
2034   if (receiving_response (c, "TSZ")) {
2035 	int dum, row, col;
2036 	timeout_CPR = False;
2037 	c = expect1byte (False, "TSZ.");	/* '[' */
2038 	c = get_digits (& dum);			/* '8' */
2039 	c = get_digits (& row);
2040 	if (c == ';') {
2041 		c = get_digits (& col);
2042 		* rowpoi = row;
2043 		* colpoi = col;
2044 
2045 		trace_query (("-> %d %d\n", row, col));
2046 		return True;
2047 	}
2048   }
2049 
2050   trace_query (("-> failed\n"));
2051   return False;
2052 }
2053 
2054 static FLAG can_get_winsize = True;
2055 
2056 static
2057 void
checkwinsize()2058 checkwinsize ()
2059 {
2060   static int checking_winsize = 0;
2061   trace_checkwinsize (("checkwinsize\n"));
2062   if (can_get_winsize) {
2063 	/* try to get screen size from terminal device driver (ioctl/BIOS) */
2064 	getwinsize ();
2065 	trace_checkwinsize (("using getwinsize: %d %d\n", YMAX + 1 + MENU, XMAX + 1));
2066   }
2067 #ifndef msdos
2068   if (checking_winsize) {
2069 	/* this doesn't need to be atomic with checking_winsize = 1 below
2070 	   because there is no parallel or asynchronous processing here;
2071 	   RDwinchg is not called from catchwinch anymore;
2072 	   the recursive invocation can only occur from further down
2073 	   in the execution tree below
2074 	   (calling RDwinchg from readchar/__readchar)
2075 	 */
2076 	trace_checkwinsize (("skip checking winsize\n"));
2077 	return;
2078   }
2079   if (ansi_esc) {
2080 	int row, col;
2081 	checking_winsize = 1;
2082 	/* scrolling region is cleared during screen initialization */
2083 	set_cursor (2222, 2222);
2084 	trace_checkwinsize (("trying ^[[6n\n"));
2085 	flush_keyboard ();
2086 	putescape ("\033[6n");
2087 	/* could probably use putescape ("\033[18t") rightaway (see below);
2088 	   however, let's prefer the method used by the 'resize' tool
2089 	 */
2090 	flush ();
2091 	trace_checkwinsize (("... waiting ...\n"));
2092 	if (get_CPR (& row, & col) && row > 1 && col > 1) {
2093 		row = row - 1 - MENU;
2094 		col = col - 1;
2095 		if (YMAX != row || XMAX != col) {
2096 			YMAX = row;
2097 			XMAX = col;
2098 			can_get_winsize = False;
2099 		}
2100 		trace_checkwinsize (("using ^[[6n: %d %d\n", row + 1 + MENU, col + 1));
2101 		checking_winsize = 0;
2102 		return;
2103 	}
2104 
2105 	/* the cursor-beyond-limits method failed (maybe with curses...) */
2106 	trace_checkwinsize (("trying ^[[18t\n"));
2107 	flush_keyboard ();
2108 	putescape ("\033[18t");	/* long timeout if response disabled? */
2109 	flush ();
2110 	trace_checkwinsize (("... waiting ...\n"));
2111 	if (get_TSZ (& row, & col)) {
2112 		row = row - 1 - MENU;
2113 		col = col - 1;
2114 		if (YMAX != row || XMAX != col) {
2115 			YMAX = row;
2116 			XMAX = col;
2117 			can_get_winsize = False;
2118 		}
2119 		trace_checkwinsize (("using ^[[18t: %d %d\n", row + 1 + MENU, col + 1));
2120 		checking_winsize = 0;
2121 		return;
2122 	}
2123 	trace_checkwinsize (("terminal size detection failed\n"));
2124   }
2125   checking_winsize = 0;
2126 #endif
2127 }
2128 
2129 
2130 /*======================================================================*\
2131 |*		Screen redraw and Window title handling			*|
2132 \*======================================================================*/
2133 
2134 #ifdef unix
2135 
2136 #define dont_debug_window_title
2137 
2138 /*
2139  * Set window headline and icon text
2140  */
2141 static
2142 void
build_window_title(ws,title,icon)2143 build_window_title (ws, title, icon)
2144   char * ws;
2145   char * title;
2146   char * icon;
2147 {
2148   if (strcontains (title_string_pattern, "%d")) {
2149 	/* hpterm */
2150 	int lent = strlen (title);
2151 	int leni = strlen (icon);
2152 	build_string (ws, title_string_pattern, lent, title, leni, icon);
2153   } else {
2154 	build_string (ws, title_string_pattern, title, icon);
2155   }
2156 }
2157 
2158 static char old_window_title [maxXMAX + 9];
2159 static char old_icon_title [maxXMAX + 9];
2160 static FLAG saved_old_window_title = False;
2161 
2162 static
2163 void
save_old_window_title()2164 save_old_window_title ()
2165 {
2166   if (xterm_version >= 251 || mintty_version >= 10003) {
2167 	putescape ("\033[22t");
2168 	saved_old_window_title = True;
2169   } else if (use_window_title_query && ansi_esc && xterm_version > 2 && ! mlterm_version) {
2170 	/* title query can be disabled since xterm 174 (allowWindowOps)
2171 	   the default is false since xterm 249 (security concerns);
2172 	   to mitigate this, get_terminal_report_string enforces a
2173 	   shorter timeout (since 2014.24)
2174 	 */
2175 	char * t = get_terminal_report_string ("\033[21t");
2176 	if (t && * t) {
2177 		t ++;
2178 		strcpy (old_window_title, t);
2179 		saved_old_window_title = True;
2180 		t = get_terminal_report_string ("\033[20t");
2181 		if (t && * t) {
2182 			t ++;
2183 			strcpy (old_icon_title, t);
2184 		}
2185 	} else {
2186 		use_window_title_query = False;
2187 	}
2188   }
2189 }
2190 
2191 static
2192 void
restore_old_window_title()2193 restore_old_window_title ()
2194 {
2195   if (saved_old_window_title) {
2196 	if (xterm_version >= 251 || mintty_version >= 10003) {
2197 		putescape ("\033[23t");
2198 	} else if (* old_window_title) {
2199 		char window_string [2 * maxXMAX + 18];
2200 		build_window_title (window_string, old_window_title, old_icon_title);
2201 		putescape (window_string);
2202 	}
2203   }
2204 }
2205 
2206 void
clear_window_title()2207 clear_window_title ()
2208 {
2209   char window_string [2 * maxXMAX + 18];
2210 
2211   if (! use_window_title) {
2212 	return;
2213   }
2214 
2215   if (! saved_old_window_title) {
2216 	save_old_window_title ();
2217   }
2218 
2219   build_window_title (window_string, " ", " ");
2220   putescape (window_string);
2221 
2222   restore_old_window_title ();
2223 }
2224 
2225 static char title_encoding = ' ';
2226 static FLAG title_encoding_xterm_to_be_checked = False;
2227 
2228 static
2229 void
check_title_encoding()2230 check_title_encoding ()
2231 {
2232   if (title_encoding == ' ') {
2233 	title_encoding_xterm_to_be_checked = False;
2234 	if (konsole_version > 0) {
2235 		/* locale dependent */
2236 		title_encoding = 'T';	/* terminal encoding */
2237 	} else if (gnome_terminal_version > 0) {
2238 		/* probably gnome-terminal */
2239 		/* locale dependent */
2240 		title_encoding = 'T';	/* terminal encoding */
2241 	} else if (mintty_version > 136) {
2242 		/* mintty: locale dependent since 0.3.9 */
2243 		title_encoding = 'T';	/* terminal encoding */
2244 	} else if (mintty_version == 136) {
2245 		/* PuTTY: Windows Western */
2246 		title_encoding = 'W';
2247 	} else if (xterm_version >= 210) {
2248 		/* title string controlled by utf8Title since xterm 210 */
2249 		if (utf8_screen) {
2250 			if (use_window_title_query) {
2251 				title_encoding_xterm_to_be_checked = True;
2252 				/* fall-back assumption */
2253 				title_encoding = 'U';	/* UTF-8 */
2254 			} else {
2255 				title_encoding = 'A';	/* ASCII */
2256 			}
2257 		} else {
2258 			title_encoding = 'L';	/* ISO Latin-1 */
2259 		}
2260 	} else if (xterm_version >= 201) {
2261 		title_encoding = 'L';	/* ISO Latin-1 */
2262 	} else if (xterm_version > 0 && utf8_screen) {
2263 		title_encoding = 'A';	/* ASCII */
2264 	} else if (rxvt_version > 0) {
2265 #ifdef incapable_X_windows
2266 		/* how to detect this? */
2267 		if (utf8_screen) {
2268 			title_encoding = 'A';	/* workaround rxvt bug? */
2269 		} else {
2270 			title_encoding = 'L';	/* ISO Latin-1 */
2271 		}
2272 #else
2273 		title_encoding = 'T';	/* terminal encoding */
2274 #endif
2275 	} else if (streq (TERM, "cygwin")) {
2276 		if (term_encoding_tag == 'W') {
2277 			/* assume cygwin 1.5 */
2278 # ifdef __CYGWIN__
2279 			/* drop this assumption unless verified locally */
2280 			if (CYGWIN_VERSION_DLL_MAJOR < 1007) {
2281 				title_encoding = 'P';	/* PC-Latin-1 (CP850) */
2282 			} else {
2283 				title_encoding = 'T';	/* terminal encoding */
2284 			}
2285 # endif
2286 		} else {
2287 			/* cygwin 1.5 codepage:oem or cygwin 1.7.0-49 */
2288 			title_encoding = 'T';	/* terminal encoding */
2289 		}
2290 	} else {
2291 #ifdef msdos
2292 		title_encoding = 'P';	/* PC-Latin-1 (CP850) */
2293 #endif
2294 	}
2295 	if (title_encoding == ' ') {
2296 		if (utf8_screen) {
2297 			title_encoding = 'U';	/* UTF-8 */
2298 		} else {
2299 			title_encoding = 'L';	/* ISO Latin-1 */
2300 		}
2301 	}
2302   }
2303 
2304   if (title_encoding_xterm_to_be_checked) {	/* => xterm_version >= 210 */
2305 	/* first check if we can skip the check (ASCII-only file name) */
2306 	char * filename_poi = file_name;
2307 	FLAG check_xterm = False;
2308 	while (* filename_poi != '\0') {
2309 		if (* filename_poi ++ & 0x80) {
2310 			check_xterm = True;
2311 			break;
2312 		}
2313 	}
2314 
2315 	if (check_xterm) {
2316 	    if (xterm_version >= 252 && utf8_screen) {
2317 		/* assume that it's reasonable to just set utf8Title mode */
2318 #ifdef debug_window_title
2319 		printf ("setting xterm window title encoding to UTF-8");
2320 		putescape ("\033[>2t");
2321 		title_encoding = 'U';	/* UTF-8 */
2322 #endif
2323 	    } else {
2324 #ifdef debug_window_title
2325 		printf ("checking xterm window title encoding");
2326 #endif
2327 		/* title string controlled by utf8Title since xterm 210 */
2328 		char * r = get_terminal_report_string ("\033]2;x�x\033[21t");
2329 		title_encoding_xterm_to_be_checked = False;
2330 		if (! r || ! r [0]) {
2331 			/* no response, resource 'allowWindowOps' disabled
2332 			   or non-xterm */
2333 			use_window_title_query = False;
2334 			title_encoding = 'A';	/* ASCII */
2335 		} else if (r [2] == '�') {
2336 			/* only with utf8Title: false */
2337 			title_encoding = 'L';	/* ISO Latin-1 */
2338 		} else {
2339 			/* only with utf8Title: true */
2340 			title_encoding = 'U';	/* UTF-8 */
2341 		}
2342 #ifdef debug_window_title
2343 		printf ("window title:");
2344 		while (* r) {
2345 			printf (" %02X%c", (character) * r, * r);
2346 			r ++;
2347 		}
2348 		printf ("\n");
2349 #endif
2350 	    }
2351 	}
2352   }
2353 }
2354 
2355 void
RD_window_title()2356 RD_window_title ()
2357 {
2358   char window_string [2 * (maxFILENAMElen + maxXMAX) + 18];
2359   char filename_ok [maxFILENAMElen];
2360   char * filename_dispoi;
2361   char * filename_poi;
2362   char * save_term_encoding = NIL_PTR;
2363 
2364   if (! use_window_title) {
2365 	return;
2366   }
2367 
2368   if (! saved_old_window_title) {
2369 	save_old_window_title ();
2370   }
2371 
2372   check_title_encoding ();
2373 
2374   if (title_encoding == 'P' || title_encoding == 'W') {
2375 	save_term_encoding = get_term_encoding ();
2376 	if (title_encoding == 'P') {
2377 		(void) set_term_encoding ("CP850", 'P');
2378 	} else {
2379 		(void) set_term_encoding ("CP1252", 'W');
2380 	}
2381   }
2382 
2383   filename_poi = file_name;
2384   filename_dispoi = filename_ok;
2385   while (* filename_poi != '\0') {
2386 	unsigned long c = unicodevalue (filename_poi);
2387 	if (no_unichar (c) || c < (character) ' ' || (c >= 0x80 && c < 0xA0)) {
2388 		* filename_dispoi ++ = '?';
2389 	} else if (title_encoding == 'L') {
2390 		if (c >= 0x100) {
2391 			* filename_dispoi ++ = '?';
2392 		} else {
2393 			* filename_dispoi ++ = (character) c;
2394 		}
2395 	} else if (title_encoding == 'A' && c >= 0x80) {
2396 		* filename_dispoi ++ = '?';
2397 	} else if (title_encoding == 'U') {
2398 #ifdef incapable_X_windows
2399 		/* how to detect this? */
2400 		if (c >= 0x100) {
2401 			/* only a few selected non-Latin-1 chars are displayed */
2402 			* filename_dispoi ++ = '?';
2403 		} else {
2404 			filename_dispoi += utfencode (c, filename_dispoi);
2405 		}
2406 #else
2407 		filename_dispoi += utfencode (c, filename_dispoi);
2408 #endif
2409 	} else { /* assume title encoding is same as screen encoding */
2410 		if (utf8_screen) {
2411 			filename_dispoi += utfencode (c, filename_dispoi);
2412 		} else if (cjk_term || mapped_term) {
2413 			unsigned long tc = mappedtermchar (c);
2414 			if (no_char (tc)) {
2415 				* filename_dispoi ++ = '?';
2416 			} else if (cjk_term) {
2417 				filename_dispoi += cjkencode_char (True, mappedtermchar (c), filename_dispoi);
2418 			} else {
2419 				* filename_dispoi ++ = tc;
2420 			}
2421 		} else { /* also fall-back for ASCII chars in all cases */
2422 			* filename_dispoi ++ = (character) c;
2423 		}
2424 	}
2425 	advance_char (& filename_poi);
2426   }
2427   * filename_dispoi = '\0';
2428 
2429   if (save_term_encoding != NIL_PTR) {
2430 	(void) set_term_encoding (save_term_encoding, ' ');
2431   }
2432 
2433 #ifdef __CYGWIN__
2434 #define mined_name " - MinEd"
2435 #else
2436 #define mined_name ""
2437 #endif
2438 
2439   if (loading == False) {
2440 	char title_text [maxFILENAMElen + maxXMAX];
2441 	char icon_text [maxFILENAMElen + maxXMAX];
2442 	build_string (title_text, "%s%s%s",
2443 			file_name [0] == '\0' ? "[no file]" : filename_ok,
2444 			modified ? mined_modf: "",
2445 			mined_name);
2446 	build_string (icon_text, "%s%s",
2447 			modified ? mined_modf: "",
2448 			file_name [0] == '\0' ? "[no file]" : getbasename (filename_ok));
2449 	build_window_title (window_string, title_text, icon_text);
2450 	putescape (window_string);
2451   }
2452 }
2453 
2454 #endif
2455 
2456 
2457 /*
2458  * Redraw the screen
2459  */
2460 static
2461 void
RD_nobot()2462 RD_nobot ()
2463 {
2464   reverse_off ();
2465   clearscreen ();
2466 
2467 #ifdef use_logo
2468   if (xterm_version > 0 || mintty_version > 0 || decterm_version > 0) {
2469 	/* double line logo - would waste 2 lines */
2470 	/* show accent conditionally, see splash_logo () */
2471 	set_cursor (XMAX - 10, 1);
2472 	putescape ("\033#3ḿ   MinEd");
2473 	set_cursor (XMAX - 10, 2);
2474 	putescape ("\033#4ḿ   MinEd");
2475   }
2476 #endif
2477 
2478 /* display page */
2479   display (0, top_line, last_y, y);
2480 
2481 /* redraw scroll bar */
2482   if (disp_scrollbar && ! winchg) {
2483 	(void) display_scrollbar (False);
2484   }
2485 
2486 /* clear/redraw last line */
2487   set_cursor (0, YMAX);
2488   clear_lastline ();
2489   move_address (cur_text, find_y_w_o_RD (cur_line));
2490 
2491 #ifdef unix
2492   RD_window_title ();
2493 #endif
2494 }
2495 
2496 void
RD()2497 RD ()
2498 {
2499   RD_nobot ();
2500   if (stat_visible) {
2501 	rd_bottom_line ();
2502   }
2503 }
2504 
2505 void
RD_y(y_pos)2506 RD_y (y_pos)
2507   int y_pos;
2508 {
2509   reverse_off ();
2510   clearscreen ();
2511 
2512 /* display page */
2513   display (0, top_line, last_y, y_pos);
2514 
2515 /* clear/redraw last line */
2516   set_cursor (0, YMAX);
2517   clear_lastline ();
2518   if (stat_visible) {
2519 	rd_bottom_line ();
2520   }
2521 }
2522 
2523 /*
2524  * Adjust current window size after WINCH signal
2525  */
2526 static
2527 void
RDwin_menu(rd_menu,after_winchg)2528 RDwin_menu (rd_menu, after_winchg)
2529   FLAG rd_menu;
2530   FLAG after_winchg;
2531 {
2532   screen_buffer (True);
2533 
2534 #ifdef debug_terminal_resize
2535   printf ("RDwin %dx%d", YMAX + 1 + MENU, XMAX + 1);
2536 #endif
2537   winchg = False;
2538   checkwinsize ();
2539 #ifdef debug_terminal_resize
2540   printf (" -> %dx%d\n", YMAX + 1 + MENU, XMAX + 1);
2541 #endif
2542 
2543 #ifdef adjust_to_actual_termsize	/* incomplete & obsolete */
2544   flush_keyboard ();
2545   putescape ("\033[18t");	/* long timeout if response disabled? */
2546   flush ();
2547   if (char_ready_within (...)) { /*  c = expect1byte (True, NIL_PTR); if (receiving_response (c, NIL_PTR)) { */
2548 	c = readcharacter ();...
2549 	if (command (c) == ANSIseq) {
2550 		ANSIseq ();
2551 		... but without RD which is actually done here ...
2552 		in both cases, reset the variables below, however ...
2553 	}
2554   }
2555 #endif
2556 
2557   if (loading == False) {
2558 	LINE * current_line = cur_line;
2559 	reset (top_line, y);
2560 	/* move_y (find_y_w_o_RD (current_line)); */
2561 	move_address (cur_text, find_y_w_o_RD (current_line));
2562 
2563 	RD_nobot ();
2564 	if (MENU && ! winchg) {
2565 		displaymenuline (True);
2566 		if (rd_menu) {
2567 			redrawmenu ();
2568 		}
2569 	}
2570   }
2571 
2572   display_flush ();
2573 
2574   if (after_winchg && ! winchg) {
2575 	(void) display_scrollbar (True);
2576   }
2577 
2578   set_cursor_xy ();
2579 
2580   if (stat_visible && ! winchg) {
2581 	rd_bottom_line ();
2582 	/* could call redraw_prompt () instead, but:
2583 	   - menu header missing
2584 	   - with empty text: line marker not restored?
2585 	*/
2586   }
2587 
2588   if (winchg) {
2589 	trace_checkwinsize (("recursive RDwin_menu after winchg\n"));
2590 	RDwin_menu (rd_menu, after_winchg);
2591   }
2592 
2593   flush ();
2594 }
2595 
2596 void
RDwin()2597 RDwin ()
2598 {
2599   RDwin_menu (True, False);
2600 }
2601 
2602 void
RDcenter()2603 RDcenter ()
2604 {
2605   LINE * l = cur_line;
2606   int targy = YMAX / 2 - 1;
2607   int li = 0;
2608   while (l->prev != header && li < targy) {
2609 	l = l->prev;
2610 	li ++;
2611   }
2612   reset (l, li);
2613 
2614   RDwin ();
2615 }
2616 
2617 void
RDwinchg()2618 RDwinchg ()
2619 {
2620   trace_checkwinsize (("RDwinchg\n"));
2621   if (loading) {
2622 #ifdef debug_terminal_resize
2623 	printf ("RDwin (skip/loading) %dx%d\n", YMAX + 1 + MENU, XMAX + 1);
2624 #endif
2625 	/* cannot use text buffer for refresh */
2626 	return;
2627   }
2628   RDwin_menu (True, True);
2629 }
2630 
2631 void
RDwin_nomenu()2632 RDwin_nomenu ()
2633 {
2634   RDwin_menu (False, False);
2635 }
2636 
2637 
2638 /*======================================================================*\
2639 |*		Terminal mode debugging					*|
2640 \*======================================================================*/
2641 
2642 #define dont_debug_encoding
2643 
2644 
2645 #define dont_debug_test_screen_width
2646 
2647 #define dont_debug_screenmode
2648 #define dont_debug_width_data_version
2649 
2650 #define dont_debug_graphics
2651 
2652 
2653 #ifdef debug_test_screen_width
2654 # define debug_encoding
2655 #endif
2656 
2657 
2658 #ifdef debug_encoding
2659 
2660 static
2661 FLAG
do_set_term_encoding(function,line,charmap,tag)2662 do_set_term_encoding (function, line, charmap, tag)
2663   char * function;
2664   unsigned int line;
2665   char * charmap;
2666   char tag;
2667 {
2668   FLAG ret = set_term_encoding (charmap, tag);
2669   printf ("set_term_encoding [%s:%d] %s '%c' -> %d %s\n", function, line, charmap, tag, ret, get_term_encoding ());
2670   return ret;
2671 }
2672 
2673 #define set_term_encoding(charmap, tag)	do_set_term_encoding (__FUNCTION__, __LINE__, charmap, tag)
2674 
2675 #define trace_encoding(tag)	\
2676  printf ("[%s]  	TERM <%s> '%c' utf8 %d cjk %d map %d comb/bidi %d/%d\n		TEXT <%s> '%c' (auto %d) utf8 %d utf16 %d cjk %d map %d\n", \
2677  tag, \
2678  get_term_encoding (), term_encoding_tag, utf8_screen, cjk_term, mapped_term, combining_screen, bidi_screen, \
2679  get_text_encoding (), text_encoding_tag, auto_detect, utf8_text, utf16_file, cjk_text, mapped_text)
2680 
2681 #else
2682 
2683 #define trace_encoding(tag)
2684 
2685 #endif
2686 
2687 
2688 #ifdef debug_width_data_version
2689 
2690 #define trace_width_data_version(tag)	\
2691  printf ("[%s] width_data_version %d (CJK %d) nonbmp %X combining_data_version %d (Jamo %d)\n", \
2692  tag, \
2693  width_data_version, cjk_width_data_version, nonbmp_width_data, \
2694  combining_data_version, hangul_jamo_extended)
2695 
2696 #else
2697 
2698 #define trace_width_data_version(tag)
2699 
2700 #endif
2701 
2702 
2703 /*======================================================================*\
2704 |*		TTY setup						*|
2705 \*======================================================================*/
2706 
2707 /* workaround for cygwin console delaying some escape sequences */
2708 #ifdef __CYGWIN__
2709 static
2710 void
install_console_pipe()2711 install_console_pipe ()
2712 {
2713   if ((streq ("cygwin", TERM) && ! screen_version && ! tmux_version)) {
2714 	struct utsname uts;
2715 	int pfds [2];
2716 	int pid;
2717 	int cygwin_version_major = CYGWIN_VERSION_DLL_MAJOR;
2718 	int cygwin_version_minor = CYGWIN_VERSION_DLL_MINOR;
2719 
2720 	if (uname (& uts) == 0) {
2721 		int mil, maj, min;
2722 		int ret = sscanf (uts.release, "%d.%d.%d", & mil, & maj, & min);
2723 		if (ret == 3) {
2724 			cygwin_version_major = mil * 1000 + maj;
2725 			cygwin_version_minor = min;
2726 		}
2727 	}
2728 
2729 	if (cygwin_version_major < 1007 || cygwin_version_minor < 10) {
2730 		/* no bug yet */
2731 	} else if (pipe (pfds) < 0) {
2732 		/* don't fork, accept deficiencies */
2733 	} else {
2734 		pid = fork ();
2735 		if (pid < 0) {	/* fork error */
2736 			/* ignore, accept deficiencies */
2737 		} else if (pid == 0) {	/* child */
2738 			int n;
2739 			(void) close (pfds [0]);
2740 			sleep (1);
2741 			/* copy input_fd to pipe */
2742 			do {
2743 				character c;
2744 				n = read (input_fd, & c, 1);
2745 				if (n > 0) {
2746 					n = write (pfds [1], & c, 1);
2747 				}
2748 			} while (n >= 0);
2749 			_exit (127);
2750 		} else {	/* parent */
2751 			(void) close (pfds [1]);
2752 			/* redirect input from pipe */
2753 			input_fd = pfds [0];
2754 			/* proceed with editing */
2755 		}
2756 	}
2757   }
2758 }
2759 #else
2760 #define install_console_pipe()
2761 #endif
2762 
2763 
2764 /*======================================================================*\
2765 |*		Terminal setup						*|
2766 \*======================================================================*/
2767 
2768 /**
2769    Request the terminal (VT100-like, xterm and derivatives) to send
2770    Device Attributes report containing terminal type and version.
2771  */
2772 static
2773 void
acquire_device_attributes(again)2774 acquire_device_attributes (again)
2775   FLAG again;
2776 {
2777 #ifndef msdos
2778   character c;
2779 
2780   trace_query (("query ^[[>c\n"));
2781 
2782   terminal_type = -1;
2783   terminal_version = 0;
2784 
2785   flush_keyboard ();
2786   putescape ("\033[>c");
2787   flush ();
2788 
2789   adjust_escdelay ();
2790 
2791   c = expect1byte (True, "acquire");	/* ESC */
2792   if (receiving_response (c, "acquire")) {
2793 	c = expect1byte (False, "acquire.");	/* '[' */
2794 	c = expect1byte (False, "acquire..");
2795 		/* '>' (secondary DA) or '?' (CJK terminals) */
2796 	c = get_digits (& terminal_type);
2797 	if (c == ';') {
2798 		c = get_digits (& terminal_version);
2799 	}
2800 	while (c == '.') {
2801 		int dummy;
2802 		/* mrxvt sends sub-version 0.4.1 */
2803 		c = get_digits (& dummy);
2804 		terminal_version = terminal_version * 100 + dummy;
2805 	}
2806 	while (c == ';') {
2807 		int dummy;
2808 		c = get_digits (& dummy);
2809 	}
2810   }
2811 
2812   trace_query (("-> %d %d\n", terminal_type, terminal_version));
2813 #endif
2814 }
2815 
2816 static
2817 void
acquire_primary_device_attributes()2818 acquire_primary_device_attributes ()
2819 {
2820 #ifndef msdos
2821   character c;
2822 
2823   trace_query (("query ^[[c\n"));
2824 
2825   flush_keyboard ();
2826   putescape ("\033[c");
2827   flush ();
2828 
2829   adjust_escdelay ();
2830 
2831   c = expect1byte (True, "acquirep");	/* ESC */
2832   if (receiving_response (c, "acquirep")) {
2833 	c = expect1byte (False, "acquirep.");	/* '[' */
2834 	c = expect1byte (False, "acquirep..");	/* '?' */
2835 	dec_features = 0;
2836 	do {
2837 		int feature;
2838 		c = get_digits (& feature);
2839 		trace_query (("terminal feature %d\n", feature));
2840 		dec_features |= 1 << feature;
2841 	} while (c == ';');
2842 	trace_query (("terminal features %08lX\n", dec_features));
2843   }
2844 #endif
2845 }
2846 
2847 
2848 /**
2849    Swallow keyboard input.
2850    For use before enquiring all kinds of terminal reports.
2851  */
2852 static
2853 void
flush_keyboard()2854 flush_keyboard ()
2855 {
2856   /* swallow either
2857 	- key typed in by user while requesting terminal
2858 	- delayed response to a previous request
2859 	  which could not be handled in time
2860   */
2861 #ifndef vms_slow_lookahead
2862   while (char_ready_within (30, "swallow")) {
2863 #ifdef debug_expect
2864 	unsigned long swallowed = _readchar_nokeymap ();
2865 	printf ("swallowed %04lX\n", swallowed);
2866 	(void) swallowed;
2867 #else
2868 	(void) _readchar_nokeymap ();
2869 #endif
2870   }
2871 #endif
2872 }
2873 
2874 /**
2875    Retrieve terminal response to various enquiry escape sequences.
2876    Used for:
2877 	color report
2878 	window title report (not with newer xterm/mintty)
2879 	glyph availability report (with newer mintty)
2880  */
2881 static
2882 char *
get_terminal_report_string(s)2883 get_terminal_report_string (s)
2884   char * s;
2885 {
2886 #ifndef msdos
2887   character c;
2888   static char sbuf [maxMSGlen];
2889   char * spoi = sbuf;
2890 
2891   trace_query (("query [%d] ^[%s\n", escape_delay, s + 1));
2892 
2893   flush_keyboard ();
2894   putescape (s);
2895   flush ();
2896 
2897   /* UNSURE: enforce shorter timeout to mitigate delay
2898      if xterm resource allowWindowOps is false
2899    */
2900   c = expect1byte (UNSURE, "report");	/* ESC */
2901   if (receiving_response (c, s + 1)) {
2902 	c = expect1byte (False, "report.");	/* ']' */
2903 	while ((c = expect1byte (False, "report..")) != '\033' && c != '\007' && c != 0x9C) {
2904 		if (spoi < & sbuf [maxMSGlen - 1]) {
2905 			* spoi ++ = c;
2906 		}
2907 	}
2908 	if (c == '\033' && rxvt_version < 300) {
2909 		/* rxvt-unicode fails to send the final \ */
2910 		c = expect1byte (False, "report...");	/* '\\' */
2911 	}
2912   }
2913   * spoi = '\0';
2914 
2915   if (debug_mined) {
2916 	debuglog ("report", s + 1, sbuf);
2917   }
2918   trace_query (("-> ^[%s\n", sbuf));
2919   return sbuf;
2920 #else
2921   return "";
2922 #endif
2923 }
2924 
2925 static
2926 void
get_width_report(s,wpoi)2927 get_width_report (s, wpoi)
2928   char * s;
2929   int * wpoi;
2930 {
2931   int row, col;
2932   if (get_CPR (& row, & col)) {
2933 #ifdef debug_test_screen_width
2934 	printf ("width <%s> -> %d\n", s, col - 1);
2935 #endif
2936 	* wpoi = col - 1;
2937   }
2938 }
2939 
2940 static
2941 int
test_screen_width(s)2942 test_screen_width (s)
2943   char * s;
2944 {
2945   int col = -1;
2946 
2947 #ifndef msdos
2948 
2949   if (! ansi_esc) {
2950 	return -1;
2951   }
2952 
2953   /* if (xterm_version >= 201) {
2954 	suppress visible effect by setting invisible character mode
2955 	- this would need intensive regression testing, so leave it
2956      }
2957   */
2958   putescape ("\r");
2959   flush_keyboard ();
2960   debuglog ("6n", "", screen_version ? "s" : "");
2961   putstring (s);	/* don't use putescape here for 'screen' 4.0 */
2962   putescape ("\033[6n");	/* maybe termcap u7 but not really defined */
2963   putescape ("\r");
2964   clear_eol ();	/* reduce visible effect */
2965   flush ();
2966   debuglog ("6n", "", "flush");
2967 
2968   get_width_report (s, & col);
2969   debuglog ("CPR", "", "");
2970 #endif
2971 
2972   return col;
2973 }
2974 
2975 typedef struct {
2976 	char * test;
2977 	int width;
2978 	} screen_width;
2979 
2980 static screen_width utf8_widths [] = {
2981 	/* detecting combining mode: */
2982 	{"a̡"},
2983 
2984 	/* detecting width data version: */
2985 	{"《》〚〛⦅⦆"},
2986 	{"︐"},
2987 	{"ꥠ"},
2988 	{"����"},	/* non-BMP characters cannot reliably be used for detection */
2989 
2990 	/* detecting combining_data_version: */
2991 	{"a܏"},
2992 	{"aͣ"},
2993 	{".͐.឴.᠎"},
2994 	{".͘.͙"},
2995 	{".᷄.᷅"},
2996 	{".҇.᷌"},	/* U510 */
2997 	{".ࠖ.ऀ"},	/* U520 */
2998 	{".ٟ.ऺ"},	/* U600 */
2999 	{".؄.ꙴ"},	/* U620 */
3000 	{".؜.؜"},	/* U630 */
3001 	{".᪰.ᷮ"},	/* U700 */
3002 	{"ᄀힰᄀퟋ"},	/* Hangul Jamo Extended-B */
3003 
3004 	/* detecting xterm -cjk_width: */
3005 	{"‘’“”…―­"},
3006 #ifdef single_width_check
3007 	{"…―…"},
3008 #endif
3009 
3010 	/* detecting non-BMP width properties: */
3011 	{"��������a��a��a��"},
3012 	{"������"},
3013 	/* detecting unassigned character width properties: */
3014 	{"㄀ㄯ㄰㆏꒎꓏﫿﹯＀"},
3015 
3016 	/* detecting Yijing Hexagram widths and printable bidi markers: */
3017 	{"䷀䷀‎"},
3018 #ifdef poderosa_detect_string
3019 	{"¡×"},
3020 #endif
3021 
3022 #ifdef oldmlterm_wideboldborderbug_workaround
3023 	{"╭"},
3024 #endif
3025 };
3026 
3027 static screen_width cjk_widths [] = {
3028 	{"�0�2"},
3029 	{"����ꥦ�ޡ"},
3030 	{"����"},
3031 	{"���x"},
3032 	{"��"},
3033 	{"��"},
3034 };
3035 
3036 static
3037 int
get_screen_width(s,sw,len)3038 get_screen_width (s, sw, len)
3039   char * s;
3040   screen_width * sw;
3041   int len;
3042 {
3043   int i;
3044   for (i = 0; i < len; i ++) {
3045 	/* if screen width has been acquired for this test string, return */
3046 	if (streq (s, sw [i].test) && sw [i].width) {
3047 #ifdef debug_test_screen_width
3048 		printf ("get <%s> -> %d\n", s, sw [i].width);
3049 #endif
3050 		return sw [i].width;
3051 	}
3052   }
3053   return test_screen_width (s);
3054 }
3055 
3056 static
3057 void
acquire_screen_widths(sw,len)3058 acquire_screen_widths (sw, len)
3059   screen_width * sw;
3060   int len;
3061 {
3062 #ifdef vms
3063   /* VMS cannot buffer more than 80 characters,
3064      so it would hang on trying to read the responses...
3065      Even the response read-ahead trick below doesn't seem to work.
3066    */
3067 #else
3068 #ifndef msdos
3069   int i;
3070   int k = 0;
3071 
3072   /*
3073     if (xterm_version >= 201) {
3074 	suppress visible effect by setting invisible character mode
3075 	(invisible mode double width bug fixed in xterm 201)
3076 	- this would need intensive regression testing, so leave it
3077     }
3078   */
3079 #ifdef debug_test_screen_width
3080   printf ("acquire_screen_widths\n");
3081 #endif
3082   debuglog ("6n", "**", screen_version ? "s" : "");
3083   flush_keyboard ();
3084   putescape ("\r");
3085   for (i = 0; i < len; i ++) {
3086 	/*debuglog ("6n", "*", screen_version ? "s" : "");*/
3087 	putstring (sw [i].test);	/* don't use putescape here for 'screen' 4.0 */
3088 	putescape ("\033[6n");	/* maybe termcap u7 but not really defined */
3089 	putescape ("\r");
3090 #ifdef vms
3091 	clear_eol ();
3092 	flush ();
3093 	while (k <= i && char_ready_within (35, NIL_PTR)) {
3094 		get_width_report (sw [k].test, & sw [k].width);
3095 		/*debuglog ("CPR", "!", "");*/
3096 		k ++;
3097 	}
3098 #endif
3099   }
3100 #ifndef vms
3101   clear_eol ();	/* reduce visible effect */
3102   flush ();
3103 #endif
3104   debuglog ("6n", "**", "flush");
3105 
3106   for (; k < len; k ++) {
3107 	get_width_report (sw [k].test, & sw [k].width);
3108 	/*debuglog ("CPR", "*", "");*/
3109   }
3110   debuglog ("CPR", "**", "");
3111 #endif
3112 #endif
3113 }
3114 
3115 static
3116 void
check_cjk_width()3117 check_cjk_width ()
3118 {
3119   static FLAG init = True;
3120 
3121   cjk_width_data_version = 0;
3122 
3123   if (utf8_screen) {
3124 	if (width_data_version >= U320) {
3125 		int swidth;
3126 		if (init) {
3127 			swidth = get_screen_width ("‘’“”…―­", utf8_widths, arrlen (utf8_widths));
3128 			init = False;
3129 		} else {
3130 			swidth = test_screen_width ("‘’“”…―­");
3131 		}
3132 		if (swidth > 8) {
3133 			/* xterm -cjk_width (since xterm 168) */
3134 #ifdef consider_wide_block_slices
3135 			/* not useful since block chars used for
3136 			   fine scrollbar have ambiguous width
3137 			 */
3138 			if (! explicit_scrollbar_style) {
3139 				fine_scrollbar = False;
3140 			}
3141 #else
3142 			fine_scrollbar = False;
3143 #endif
3144 			if (! explicit_border_style) {
3145 				use_stylish_menu_selection = False;
3146 			}
3147 			if (swidth & 1) {
3148 				/* soft hyphen is narrow, Unicode 4.0 */
3149 				cjk_width_data_version = U400;
3150 				/* ?
3151 				if (width_data_version < U400) {
3152 					width_data_version = U400;
3153 				}
3154 				*/
3155 			} else {
3156 				/* soft hyphen is wide (ambiguous), Unicode 3.0/3.2 */
3157 				cjk_width_data_version = U320beta;
3158 			}
3159 			trace_width_data_version ("cjk");
3160 		}
3161 #ifdef single_width_check
3162 		swidth = get_screen_width ("…―…", utf8_widths, arrlen (utf8_widths));
3163 		if ((swidth & 1) == 0) {
3164 			/* ― is wide */
3165 		}
3166 		if (swidth >= 5) {
3167 			/* … is wide */
3168 		}
3169 #endif
3170 	}
3171   }
3172 }
3173 
3174 static
3175 int
isglyph_code(glyph)3176 isglyph_code (glyph)
3177   char * glyph;
3178 {
3179   char * match;
3180   if (! glyphs || ! * glyphs) {
3181 	return 0;	/* no info -> reject */
3182   }
3183   match = strcontains (glyphs, glyph);
3184   if (match) {
3185 	char * post = match + strlen (glyph);
3186 	if (* (match - 1) == ';'
3187 	    && (* post < '0' || * post > '9')) {
3188 		return 1;
3189 	}
3190   }
3191   return 0;
3192 }
3193 
3194 int
isglyph_uni(u)3195 isglyph_uni (u)
3196   unsigned long u;
3197 {
3198   if (u == 0) {
3199 	/* detect whether glyph info available */
3200 	return glyphs != NIL_PTR;
3201   }
3202 
3203   if (u < 255) {
3204 	return 1;
3205   } else {
3206 	char glyphcode [20];
3207 	build_string (glyphcode, "%ld", u);
3208 	return isglyph_code (glyphcode);
3209   }
3210 }
3211 
3212 static
3213 int
isglyph_utf(c)3214 isglyph_utf (c)
3215   char * c;
3216 {
3217   if (! c || ! * c) {
3218 	return 0;
3219   } else {
3220 	return isglyph_uni (utf8value (c));
3221   }
3222 }
3223 
3224 /**
3225    Request terminal type and version from terminal.
3226  */
3227 static
3228 void
detect_terminal_type()3229 detect_terminal_type ()
3230 {
3231   trace_query (("detect_terminal_type @ %s\n", TERM));
3232   if ((strisprefix ("xterm", TERM)
3233 	|| strisprefix ("rxvt", TERM)
3234 	|| strisprefix ("gnome", TERM)
3235 	|| strisprefix ("konsole", TERM)
3236 	|| strisprefix ("screen", TERM)
3237 	|| (strisprefix ("vt", TERM)
3238 	    && ! streq ("vt52", TERM)
3239 	    && ! strisprefix ("vt50", TERM)
3240 	   )
3241       )
3242 #ifdef indulge_mlterm
3243 	/* mlterm does not respond to secondary device attribute request;
3244 	   to avoid the timeout, we could suppress the request but only
3245 	   if we detected mlterm by its joining property first;
3246 	   also, be sure about possible other joining terminals...
3247 	   (note: mintty is only "half-joining" - it joins the glyphs
3248 	   but not the two character cells, and leaves a dummy space)
3249 	   - OBSOLETE in newer mlterm, 3.1.2 at least
3250 	 */
3251 	&& ! joining_screen
3252 #endif
3253      ) {
3254 	acquire_device_attributes (False);
3255 	if (terminal_type == 'S') {	/* screen */
3256 		screen_version = terminal_version / 100;
3257 	} else if (strisprefix ("screen", TERM)) {
3258 		screen_version = 1;
3259 	}
3260 	if (screen_version > 0) {
3261 #ifdef __CYGWIN__
3262 	    if (strcontains (envstr ("STY"), ".cons")) {
3263 		/* suppress host terminal attribute enquiry
3264 		   (pass-through) in screen in cygwin console;
3265 		   workaround for not capturing the response then
3266 		   (which would later be inserted as garbage)
3267 		 */
3268 		terminal_type = 'C';
3269 		terminal_version = CYGWIN_VERSION_DLL_MAJOR * 100 + CYGWIN_VERSION_DLL_MINOR;
3270 	    } else {
3271 		acquire_device_attributes (True);
3272 	    }
3273 #else
3274 		/* check host terminal;
3275 		   with screen_version set, terminal requests will
3276 		   apply the pass-through escape sequence of 'screen'
3277 		   (for host terminal detection here
3278 		   and width auto-detection below)
3279 		 */
3280 		acquire_device_attributes (True);
3281 #endif
3282 	}
3283 
3284 #ifdef test_DEC_features
3285 	if (strisprefix ("vt", TERM)) {
3286 		decterm_version = terminal_version;
3287 	}
3288 #endif
3289 	if (terminal_type == 0 && terminal_version == 95 && getenv ("TMUX")) {
3290 		tmux_version = 1;
3291 	} else if (terminal_type == 'T') {	/* tmux 2.0 */
3292 		tmux_version = 2;
3293 	} else if (terminal_type == 0 && terminal_version == 115) {
3294 		konsole_version = terminal_version;
3295 		set_fkeymap ("xterm");
3296 	} else if ((terminal_type | 1) == 1 && konsole_version <= 0) {
3297 		if (terminal_version >= 1115) {
3298 			/* probably gnome-terminal */
3299 			gnome_terminal_version = terminal_version;
3300 		} else if (terminal_version == 136) {
3301 			/* MinTTY 0.3, PuTTY */
3302 			mintty_version = terminal_version;
3303 		} else if (terminal_version == 115) {
3304 			/* KDE konsole */
3305 			konsole_version = terminal_version;
3306 		} else if (terminal_version == 10) {	/* VT220 */
3307 			decterm_version = 220;
3308 		} else if (terminal_version == 2) {	/* Openwin xterm */
3309 			xterm_version = terminal_version;
3310 		} else if (terminal_version <= 20) {	/* ? */
3311 			decterm_version = terminal_version;
3312 #ifdef test_DEC_locator_on_xterm
3313 		} else if (strisprefix ("vt", TERM)) {
3314 			decterm_version = terminal_version;
3315 #endif
3316 		} else {
3317 			xterm_version = terminal_version;
3318 		}
3319 		set_fkeymap ("xterm");
3320 	} else if (terminal_type == 'M') {	/* mintty */
3321 		mintty_version = terminal_version;
3322 		set_fkeymap ("xterm");
3323 	} else if (terminal_type == 'R') {	/* old rxvt */
3324 		rxvt_version = terminal_version / 100;
3325 		TERM = "rxvt";
3326 	} else if (terminal_type == 'U') {	/* rxvt-unicode */
3327 		rxvt_version = terminal_version * 10;
3328 		TERM = "rxvt";
3329 	} else if (terminal_type == 6) {	/* Haiku Terminal */
3330 		fine_scrollbar = False;
3331 		use_stylish_menu_selection = False;
3332 	} else if (terminal_type == 2) {	/* VT240 */
3333 		decterm_version = 240;
3334 	} else if (terminal_type == 18) {	/* VT330 */
3335 		decterm_version = 330;
3336 	} else if (terminal_type == 19) {	/* VT340 */
3337 		decterm_version = 340;
3338 	} else if (terminal_type == 24) {	/* VT320 */
3339 		decterm_version = 320;
3340 	} else if (terminal_type == 28) {	/* DECterm window */
3341 		decterm_version = 1;
3342 	} else if (terminal_type == 41) {	/* VT420 */
3343 		decterm_version = 420;
3344 	} else if (terminal_type == 61) {	/* VT510 */
3345 		decterm_version = 510;
3346 	} else if (terminal_type == 64) {	/* VT520 */
3347 		decterm_version = 520;
3348 	} else if (terminal_type == 65) {	/* VT525 */
3349 		decterm_version = 525;
3350 	} else if (terminal_type < 64) {	/* ? */
3351 		decterm_version = terminal_type;
3352 	}
3353 	if (decterm_version > 1 && terminal_version >= 280) {
3354 		xterm_version = terminal_version;
3355 	}
3356   }
3357 
3358 /* try to detect KDE konsole */
3359   if (! konsole_version &&
3360 	(strisprefix ("konsole", TERM)
3361 #ifdef heuristic_konsole_detection
3362 	|| envvar ("KONSOLE_DCOP") || envvar ("KONSOLE_DBUS_SESSION")
3363 #endif
3364 	)
3365      ) {
3366 	konsole_version = 1;
3367 	/*xterm_version = 0;*/
3368   }
3369 
3370 /* check whether xterm supports SIXEL graphics */
3371   if (xterm_version >= 298) {
3372 	acquire_primary_device_attributes ();
3373   }
3374 
3375 /* try to detect gnome-terminal */
3376   if (strisprefix ("gnome-terminal", envstr ("COLORTERM")) && gnome_terminal_version <= 0) {
3377 	gnome_terminal_version = 1;
3378   }
3379 
3380 /* try to identify mlterm */
3381   if (bidi_screen && ! mintty_version) { /* probably mlterm */
3382 	mlterm_version = 1;
3383   } else if (strisprefix ("mlterm", TERM)) {
3384 	mlterm_version = 1;
3385   } else if (streq ("xterm", TERM) && envvar ("MLTERM")) {
3386 	mlterm_version = 1;
3387   }
3388   if (mlterm_version) {
3389 	char * mlterm= envvar ("MLTERM");
3390 	int v1, v2, v3;
3391 	int ret = sscanf (mlterm, "%d.%d.%d", & v1, & v2, & v3);
3392 	if (ret == 3) {
3393 		mlterm_version = 100 * v1 + 10 * v2 + v3;
3394 	}
3395   }
3396 }
3397 
3398 static
3399 void
check_glyphs()3400 check_glyphs ()
3401 {
3402   if (mintty_version >= 909) {
3403 #ifdef vms
3404 	/* real VMS limits the glyph detection response
3405 	   by its 80 characters input buffer,
3406 	   so check only the most essential markers:
3407 	   ╭9581;▁9601;▶9654;►9658;⏎9166;‣8227;⇾8702;→8594
3408 	 */
3409 	glyphs = get_terminal_report_string ("\033]7771;?;9581;9601;9654;9658;9166;8227;8702;8594");
3410 #else
3411 	glyphs = get_terminal_report_string ("\033]7771;?;9472;9581;9484;9601;9613;9654;9658;10003;8231;8702;8594;8227;9166;8629;8626;10007;8623;8226;9755;9758;8228;8229;8230;9655;9656;9657;9659;9664;9665;9666;9667;9668;9669;9670;9830;9672;11032;11033;11030;11031;9478;9479;8364;699;769;8472");
3412 #endif
3413 	if (glyphs) {
3414 		glyphs = strchr (glyphs, '!');
3415 		if (glyphs) {
3416 			glyphs = dupstr (glyphs);
3417 			/* update ḿ */
3418 			/* used to call splash_logo () here */
3419 		}
3420 	}
3421   }
3422 }
3423 
3424 
3425 #define use_splash_logo
3426 #define use_sixel_splash
3427 
3428 #ifdef use_sixel_splash
3429 static char * sixelsplash = "P0;0;8q\"1;1\
3430 #0;2;0;0;0#1;2;0;18;0#2;2;0;32;0#3;2;0;45;0#4;2;0;57;0#5;2;0;69;0#6;2;0;80;0\
3431 #0!105@$\
3432 #0!105A$\
3433 #0!105C$\
3434 #0!105G$\
3435 #0!105O$\
3436 #0!105_$\
3437 -\
3438 #0!105@$\
3439 #0!105A$\
3440 #0!105C$\
3441 #0!105G$\
3442 #0!105O$\
3443 #0!105_$\
3444 -\
3445 #0!105@$\
3446 #0!105A$\
3447 #0!105C$\
3448 #0!105G$\
3449 #0!105O$\
3450 #0!105_$\
3451 -\
3452 #0!59@#2@#6!9@#0!36@$\
3453 #0!58A#5A#6!11A#0!35A$\
3454 #0!57C#3C#6!11C#3C#0!35C$\
3455 #0!57G#6!11G#4G#0!36G$\
3456 #0!56O#4O#6!10O#5O#0!37O$\
3457 #0!55_#2_#6!11_#0!38_$\
3458 -\
3459 #0!55@#6!11@#1@#0!38@$\
3460 #0!54A#3A#6!10A#2A#0!39A$\
3461 #0!53C#1C#6!10C#3C#0!40C$\
3462 #0!53G#5G#6!9G#4G#0!41G$\
3463 #0!52O#3O#6!9O#5O#0!42O$\
3464 #0!52_#6!10_#0!43_$\
3465 -\
3466 #0!51@#4@#6!9@#1@#0!43@$\
3467 #0!50A#1A#6!9A#2A#0!44A$\
3468 #0!51C#5C#6!7C#0!46C$\
3469 #0!105G$\
3470 #0!105O$\
3471 #0!105_$\
3472 -\
3473 #0!105@$\
3474 #0!105A$\
3475 #0!40C#4C#6!7C#3C#0!18C#2C#6!8C#0!29C$\
3476 #0!20G#1G#6!8G#1G#0!7G#2G#6!13G#2G#0!13G#6!13G#4G#0!26G$\
3477 #0!20O#6!10O#0!5O#1O#6!17O#0!10O#5O#6!16O#2O#0!24O$\
3478 #0!20_#6!10_#0!4_#3_#6!19_#1_#0!6_#1_#6!19_#4_#0!23_$\
3479 -\
3480 #0!20@#6!10@#0!3@#5@#6!21@#1@#0!4@#3@#6!21@#3@#0!22@$\
3481 #0!20A#6!10A#0!2A#5A#6!22A#5A#0!3A#4A#6!23A#2A#0!21A$\
3482 #0!20C#6!10C#0C#6!25C#3C#0C#4C#6!25C#0!21C$\
3483 #0!20G#6!10G#5G#6!26G#4G#6!26G#3G#0!20G$\
3484 #0!20O#6!64O#5O#0!20O$\
3485 #0!20_#6!65_#2_#0!19_$\
3486 -\
3487 #0!20@#6!18@#2@#0!4@#4@#6!21@#4@#0!4@#3@#6!14@#3@#0!19@$\
3488 #0!20A#6!16A#3A#0!7A#1A#6!18A#5A#0!8A#6!13A#5A#0!19A$\
3489 #0!20C#6!15C#2C#0!9C#2C#6!16C#4C#0!10C#6!13C#0!19C$\
3490 #0!20G#6!14G#2G#0!11G#5G#6!14G#4G#0!11G#3G#6!12G#1G#0!18G$\
3491 #0!20O#6!13O#2O#0!12O#3O#6!13O#4O#0!12O#1O#6!12O#1O#0!18O$\
3492 #0!20_#6!12_#3_#0!13_#1_#6!12_#5_#0!14_#5_#6!11_#2_#0!18_$\
3493 -\
3494 #0!20@#6!11@#4@#0!15@#6!12@#0!15@#4@#6!11@#2@#0!18@$\
3495 #0!20A#6!11A#4A#0!15A#5A#6!11A#0!15A#3A#6!11A#2A#0!18A$\
3496 #0!20C#6!11C#4C#0!15C#5C#6!11C#0!15C#2C#6!11C#2C#0!18C$\
3497 #0!20G#6!11G#4G#0!15G#4G#6!11G#0!15G#2G#6!11G#2G#0!18G$\
3498 #0!20O#6!11O#4O#0!15O#4O#6!11O#0!15O#2O#6!11O#2O#0!18O$\
3499 #0!20_#6!11_#4_#0!15_#4_#6!11_#0!15_#2_#6!11_#2_#0!18_$\
3500 -\
3501 #0!20@#6!11@#4@#0!15@#4@#6!11@#0!15@#2@#6!11@#2@#0!18@$\
3502 #0!20A#6!11A#4A#0!15A#4A#6!11A#0!15A#2A#6!11A#2A#0!18A$\
3503 #0!20C#6!11C#4C#0!15C#4C#6!11C#0!15C#2C#6!11C#2C#0!18C$\
3504 #0!20G#6!11G#4G#0!15G#4G#6!11G#0!15G#2G#6!11G#2G#0!18G$\
3505 #0!20O#6!11O#4O#0!15O#4O#6!11O#0!15O#2O#6!11O#2O#0!18O$\
3506 #0!20_#6!11_#4_#0!15_#4_#6!11_#0!15_#2_#6!11_#2_#0!18_$\
3507 -\
3508 #0!20@#6!11@#4@#0!15@#4@#6!11@#0!15@#2@#6!11@#2@#0!18@$\
3509 #0!20A#6!11A#4A#0!15A#4A#6!11A#0!15A#2A#6!11A#2A#0!18A$\
3510 #0!20C#6!11C#4C#0!15C#4C#6!11C#0!15C#2C#6!11C#2C#0!18C$\
3511 #0!20G#6!11G#4G#0!15G#4G#6!11G#0!15G#2G#6!11G#2G#0!18G$\
3512 #0!20O#6!11O#4O#0!15O#4O#6!11O#0!15O#2O#6!11O#2O#0!18O$\
3513 #0!20_#6!11_#4_#0!15_#4_#6!11_#0!15_#2_#6!11_#2_#0!18_$\
3514 -\
3515 #0!20@#6!11@#4@#0!15@#4@#6!11@#0!15@#2@#6!11@#2@#0!18@$\
3516 #0!20A#6!11A#4A#0!15A#4A#6!11A#0!15A#2A#6!11A#2A#0!18A$\
3517 #0!20C#6!11C#4C#0!15C#4C#6!11C#0!15C#2C#6!11C#2C#0!18C$\
3518 #0!20G#6!11G#4G#0!15G#4G#6!11G#0!15G#2G#6!11G#2G#0!18G$\
3519 #0!20O#6!11O#4O#0!15O#4O#6!11O#0!15O#2O#6!11O#2O#0!18O$\
3520 #0!20_#6!11_#4_#0!15_#4_#6!11_#0!15_#2_#6!11_#2_#0!18_$\
3521 -\
3522 #0!20@#6!11@#4@#0!15@#4@#6!11@#0!15@#2@#6!11@#2@#0!18@$\
3523 #0!20A#6!11A#4A#0!15A#4A#6!11A#0!15A#2A#6!11A#2A#0!18A$\
3524 #0!20C#6!11C#4C#0!15C#4C#6!11C#0!15C#2C#6!11C#2C#0!18C$\
3525 #0!20G#6!11G#4G#0!15G#4G#6!11G#0!15G#2G#6!11G#2G#0!18G$\
3526 #0!20O#6!11O#4O#0!15O#4O#6!11O#0!15O#2O#6!11O#2O#0!18O$\
3527 #0!21_#6!9_#3_#0!17_#3_#6!8_#5_#0!17_#2_#6!9_#1_#0!19_$\
3528 -\
3529 #0!105@$\
3530 #0!105A$\
3531 #0!105C$\
3532 #0!105G$\
3533 #0!105O$\
3534 #0!105_$\
3535 -\
3536 #0!105@$\
3537 #0!105A$\
3538 #0!105C$\
3539 #0!105G$\
3540 #0!105O$\
3541 #0!105_$\
3542 -\
3543 #0!105@$\
3544 #0!105A$\
3545 #0!105C$\
3546 #0!105G$\
3547 #0!105O$\
3548 #0!105_$\
3549 -\
3550 #0!105@$\
3551 #0!105A$\
3552 #0!105C$\
3553 #0!105G$\
3554 \\";
3555 #endif
3556 
3557 void
splash_logo()3558 splash_logo ()
3559 {
3560 #ifdef use_splash_logo
3561   static FLAG splash_init_done = False;
3562   int splashpos = YMAX / 3;
3563 
3564   if (splash_level == 0) {
3565 	return;
3566   }
3567 
3568   clear_screen ();
3569   if ((xterm_version > 2 && ! mlterm_version)
3570       || mintty_version > 0 || decterm_version > 0) {
3571 	/* cjk_width_data_version not yet determined @ first invocation! */
3572 	char * logo1 = (mapped_term || cjk_term
3573 			|| cjk_width_data_version || ! mintty_version)
3574 			? "`   MinEd " VERSION
3575 			: utf8_screen
3576 				? "´   MinEd " VERSION
3577 				: "�   MinEd " VERSION;
3578 	char * logo2 = "m   MinEd " VERSION;
3579 	int xpos;
3580 
3581 	if (utf8_screen &&
3582 	    (combining_screen || mintty_version > 0 || xterm_version > 141)) {
3583 		if (! screen_version && mintty_version > 0 && isglyph_code ("769")) {
3584 			/* double-height combining works in mintty */
3585 			logo1 = "ḿ   MinEd " VERSION;
3586 			logo2 = logo1;
3587 		}
3588 	}
3589 	xpos = XMAX / 4 - strlen ("m   MinEd " VERSION) / 2 + 1;
3590 	if (! mlterm_version) {
3591 		set_cursor (xpos, YMAX / 3);
3592 		putescape ("\033#3"); putescape (logo1);
3593 		set_cursor (xpos, YMAX / 3 + 1);
3594 		putescape ("\033#4"); putescape (logo2);
3595 		putstring ("\n");
3596 		splashpos = YMAX / 3 + 3;
3597 	}
3598   }
3599 #ifdef use_sixel_splash
3600   if (splash_level > 1 &&
3601       ((xterm_version >= 298 && dec_features & (1 << 4))
3602        || mlterm_version >= 319 /* actually since 3.1.9 */
3603       )
3604      ) {
3605 	set_cursor (XMAX / 2 - 5, splashpos);
3606 	putescape (sixelsplash);
3607 	putstring ("\n");
3608 	flush ();
3609 
3610 	if (splash_init_done || filelist_count () == 0) {
3611 		/* don't sleep (1); */
3612 	}
3613 	splash_init_done = True;
3614   }
3615 #endif
3616   flush ();
3617 #endif
3618 }
3619 
3620 void
switchAltScreen()3621 switchAltScreen ()
3622 {
3623   status_msg ("Trying to switch to command line view (normal screen)");
3624   screen_buffer (False);
3625   flush ();
3626   (void) readcharacter ();
3627   RDwin ();
3628   status_msg ("Returned to editing view (alternate screen)");
3629 }
3630 
3631 static
3632 void
print_terminal_info()3633 print_terminal_info ()
3634 {
3635 	printf ("Terminal size %d x %d\n", YMAX + 1 + MENU, XMAX + 1);
3636 	printf ("Terminal encoding %s\n", get_term_encoding ());
3637 	printf ("- combining %d, bidi %d, joining %d, halfjoining %d\n",
3638 			combining_screen, bidi_screen,
3639 			joining_screen, halfjoining_screen);
3640 	if (utf8_auto_detected) {
3641 		printf ("- UTF-8 auto-detected\n");
3642 	}
3643 	printf ("- width data version %d - %s\n",
3644 			width_data_version,
3645 			term_Unicode_version_name (width_data_version));
3646 	if (cjk_term) {
3647 		printf ("- CJK terminal%s%s\n",
3648 			cjk_uni_term ? " - Unicode based" : "",
3649 			gb18030_term ? " - GB18030" : "");
3650 	}
3651 	if (cjk_width_data_version) {
3652 		printf ("- CJK width data version %d - %s\n",
3653 			cjk_width_data_version,
3654 			term_Unicode_version_name (cjk_width_data_version));
3655 	}
3656 	if (combining_screen) {
3657 		printf ("- combining data version %d - %s (Hangul Jamo extended %d)\n",
3658 			combining_data_version,
3659 			term_Unicode_version_name (combining_data_version),
3660 			hangul_jamo_extended);
3661 	}
3662 	printf ("- non-BMP width data mode %02X: plane_2_double %d plane_1_comb %d plane_14_comb %d\n",
3663 			nonbmp_width_data, plane_2_double_width,
3664 			plane_1_combining, plane_14_combining);
3665 
3666 	if (terminal_type > ' ') {
3667 		printf ("- terminal type %d ('%c') version %d\n",
3668 			terminal_type, terminal_type, terminal_version);
3669 	} else if (terminal_type >= 0) {
3670 		printf ("- terminal type %d version %d\n",
3671 			terminal_type, terminal_version);
3672 	}
3673 	if (screen_version > 0) {
3674 		printf ("- 'screen' version %d\n", screen_version);
3675 	}
3676 	if (tmux_version > 0) {
3677 		printf ("- 'tmux' version %d\n", tmux_version);
3678 	}
3679 	if (xterm_version > 0) {
3680 		printf ("- 'xterm' version %d\n", xterm_version);
3681 	}
3682 	if (decterm_version > 0) {
3683 		printf ("- 'DEC terminal' version %d\n", decterm_version);
3684 	}
3685 	if (rxvt_version > 0) {
3686 		if (terminal_type == 'U') {
3687 			printf ("- 'rxvt-unicode' version %d\n", rxvt_version);
3688 		} else {
3689 			printf ("- 'rxvt' version %d\n", rxvt_version);
3690 		}
3691 	}
3692 	if (gnome_terminal_version > 0) {
3693 		printf ("- 'gnome terminal' version %d\n", gnome_terminal_version);
3694 	}
3695 	if (konsole_version > 0) {
3696 		printf ("- 'KDE konsole' version %d\n", konsole_version);
3697 	}
3698 	if (mintty_version > 0) {
3699 		printf ("- 'mintty' version %d\n", mintty_version);
3700 	}
3701 	if (mlterm_version > 1) {
3702 		printf ("- 'mlterm' version %d\n", mlterm_version);
3703 	} else if (mlterm_version > 0) {
3704 		printf ("- 'mlterm'\n");
3705 	}
3706 	if (colours_256) {
3707 		printf ("- assuming 256%s color mode\n", colours_88 ? " (maybe 88)" : "");
3708 	} else if (colours_88) {
3709 		printf ("- assuming 88 color mode\n");
3710 	}
3711 	/* check #ifdef debug_screenmode for further information */
3712 
3713 	/*printf ("- window title encoding <%c>\n", title_encoding);*/
3714 
3715 	printf ("Menu border characters: ~ %s\n",
3716 		use_ascii_graphics ? "ASCII" :
3717 			use_vga_block_graphics ? "VGA" :
3718 				use_pc_block_graphics ? "PC-compatible":
3719 					use_vt100_block_graphics ? "VT100 block graphics":
3720 						utf8_screen ? "Unicode":
3721 							"VT100 block graphics"
3722 		);
3723 
3724 	if (dark_term) {
3725 		printf ("- dark terminal background\n");
3726 	}
3727 	printf ("- dim mode: ");
3728 	if (can_dim) {
3729 		printf ("native\n");
3730 #ifdef unix
3731 	} else if (redefined_ansi7) {
3732 		printf ("redefining ansi mode\n");
3733 #endif
3734 	} else {
3735 		printf ("none\n");
3736 	}
3737 }
3738 
3739 /**
3740    Perform terminal detection, encoding auto-detection, determine features,
3741    setup terminal.
3742  */
3743 static
3744 void
terminal_configure_init()3745 terminal_configure_init ()
3746 {
3747   int swidth;
3748 
3749 /* terminal mode initialisation */
3750   /* Note: this must be called before any screen interaction,
3751 	e.g. test_screen_width, acquire_screen_widths, get_screen_width
3752      but after pipe handling (I/O redirection)
3753    */
3754   get_term (TERM);
3755 
3756   /* Set tty to appropriate mode; don't rely on checkwinsize() yet! */
3757   raw_mode (True);
3758   if (erase_char != '\0') {
3759 	key_map [erase_char] = DPC;
3760   }
3761 #ifdef vms
3762   /* detection of terminal setting fails, so in case DEL is on Backarrow: */
3763   key_map ['\177'] = DPC;
3764 #endif
3765 
3766 
3767   checkwinsize ();
3768   if (XMAX < 39 || YMAX < 1) {
3769 	panic ("Min. 3x40 size needed for terminal", "too small");
3770   }
3771 
3772 
3773 /* ensure feedback after start-up when terminal is slow on queries */
3774   if (strisprefix ("rxvt", TERM)) {
3775 	get_ansi_modes ();
3776 	clearscreen ();
3777 	status_msg ("Auto-detecting terminal properties - waiting for rxvt to report");
3778 	set_cursor (0, 0);
3779 	flush ();
3780 
3781 	/* Make sure output is flushed in rxvt (was apparently needed): */
3782 	(void) char_ready_within (30, NIL_PTR);
3783   }
3784 
3785 
3786 /* request terminal type and version from terminal */
3787   detect_terminal_type ();
3788 
3789 #ifdef debug_graphics
3790   printf ("(ty) ascii %d, vga %d, vt100 %d\n", use_ascii_graphics, use_vga_block_graphics, use_vt100_block_graphics);
3791 #endif
3792 
3793 
3794 /* detect screen encoding and calibrate screen properties */
3795 
3796 /* detect kterm encodings */
3797 #define sjis_3bytes	"x�a"
3798 /*#define sjis_3bytes	"���"*/
3799   if (streq ("kterm", TERM)) {
3800 	if (test_screen_width (sjis_3bytes) == 3) {
3801 		(void) set_term_encoding ("Shift-JIS", 'S');
3802 		if (! text_encoding_selected) {
3803 			(void) set_text_encoding ("Shift-JIS", 'S', "TERM=kterm");
3804 		}
3805 	} else {
3806 		(void) set_term_encoding ("EUC-JP", 'J');
3807 		if (! text_encoding_selected) {
3808 			(void) set_text_encoding ("EUC-JP", 'J', "TERM=kterm");
3809 		}
3810 	}
3811 	auto_detect = False;
3812 	trace_encoding ("kterm");
3813   }
3814 
3815 
3816 /* detect UTF-8 and CJK screen encodings */
3817   trace_encoding ("init");
3818 
3819   swidth = test_screen_width ("åلاษษ刈墢");
3820 #ifdef debug_screenmode
3821   printf ("test_screen_width -> %d\n", swidth);
3822 #endif
3823 
3824   if (screen_version > 0 && swidth == 3) {
3825 	/* workaround for problem to get LAM through 'screen' */
3826 	swidth = test_screen_width ("ålษษ刈墢");
3827 #ifdef debug_screenmode
3828 	printf ("test_screen_width -> %d\n", swidth);
3829 #endif
3830   }
3831 
3832   if (swidth > 0) {
3833 	/**
3834 	 check cursor column after test string, determine screen mode
3835 	  6	-> UTF-8, no double-width, with LAM/ALEF ligature joining
3836 	  7	-> UTF-8, no double-width, no LAM/ALEF ligature joining
3837 	  8	-> UTF-8, double-width, with LAM/ALEF ligature joining
3838 	  9	-> UTF-8, double-width, no LAM/ALEF ligature joining
3839 	 11,16	-> CJK terminal (with luit)
3840 	 10,15	-> 8 bit terminal or CJK terminal
3841 	 13	-> Poderosa terminal emulator, UTF-8, or TIS620 terminal
3842 	 14,17	-> CJK terminal
3843 	 16	-> Poderosa, ISO Latin-1
3844 	 (17)	-> Poderosa, (JIS)
3845 	 18	-> CJK terminal (or 8 bit terminal, e.g. Linux console)
3846 	*/
3847 
3848 	if (swidth == 13) {
3849 		/* TIS620 terminal or Poderosa UTF-8 mode */
3850 		if (test_screen_width ("å") == 1) {
3851 			poderosa_version = 1;
3852 			swidth = 9;	/* continue with UTF-8 checks */
3853 		} else {
3854 			set_term_encoding ("TIS", 'T');
3855 		}
3856 	} else if (swidth == 16) {
3857 		poderosa_version = 1;
3858 	}
3859 
3860 	if (swidth > 0 && swidth <= 9) {
3861 	    int xwidth;
3862 	    FLAG do_width_checks = True;
3863 
3864 	    utf8_screen = True;
3865 	    utf8_auto_detected = True;
3866 	    utf8_input = True;
3867 	    cjk_term = False;
3868 	    mapped_term = False;
3869 
3870 	    check_glyphs ();
3871 	    splash_logo ();
3872 
3873 #ifdef vms
3874 	    if (rxvt_version > 0
3875 		|| mintty_version > 0
3876 	       ) {
3877 		/* checks are too slow... */
3878 		do_width_checks = False;
3879 	    }
3880 #endif
3881 
3882 	    if (do_width_checks) {
3883 		acquire_screen_widths (utf8_widths, arrlen (utf8_widths));
3884 	    }
3885 
3886 	    if (get_screen_width ("a̡", utf8_widths, arrlen (utf8_widths)) == 1) {
3887 			combining_screen = True;
3888 			if (! combining_mode_disabled) {
3889 				combining_mode = True;
3890 			}
3891 	    } else {
3892 			combining_screen = False;
3893 			combining_mode = False;
3894 	    }
3895 	    if ((swidth & 1) == 0) {
3896 			/* ligature joining detected, must also be bidi */
3897 			joining_screen = True;
3898 			bidi_screen = True;
3899 			poormansbidi = False;
3900 			/* disable scrollbar to prevent interference */
3901 			if (! explicit_scrollbar_style) {
3902 				disp_scrollbar = False;
3903 				scrollbar_width = 0;
3904 			}
3905 	    }
3906 
3907 	    /* used to call splash_logo () here */
3908 
3909 	    if (swidth < 8) {
3910 			/* no wide character support */
3911 			width_data_version = 0;
3912 			trace_width_data_version ("0");
3913 	    } else if (do_width_checks) {
3914 		if (get_screen_width ("����", utf8_widths, arrlen (utf8_widths)) == 3) {
3915 			width_data_version = U600;
3916 			trace_width_data_version ("600");
3917 		} else if (get_screen_width ("ꥠ", utf8_widths, arrlen (utf8_widths)) >= 2) {
3918 			width_data_version = U520;
3919 			trace_width_data_version ("520");
3920 		} else if (get_screen_width ("︐", utf8_widths, arrlen (utf8_widths)) >= 2) {
3921 			width_data_version = U410;
3922 			trace_width_data_version ("410");
3923 		} else if (get_screen_width ("《》〚〛⦅⦆", utf8_widths, arrlen (utf8_widths)) < 9) {
3924 			/* older width data (before xterm 167) */
3925 			width_data_version = U300;
3926 			trace_width_data_version ("300");
3927 		}
3928 	    }
3929 
3930 	    if (do_width_checks) {
3931 		/* determine combining data version */
3932 
3933 		/* Add new test strings to array utf8_widths
3934 		   (section detecting combining_data_version) */
3935 		if (get_screen_width (".᪰.ᷮ", utf8_widths, arrlen (utf8_widths)) == 2) {
3936 			combining_data_version = U700;
3937 		} else if (get_screen_width (".؜.؜", utf8_widths, arrlen (utf8_widths)) == 2) {
3938 			combining_data_version = U630;
3939 		} else if (get_screen_width (".؄.ꙴ", utf8_widths, arrlen (utf8_widths)) == 2) {
3940 			combining_data_version = U620;
3941 		} else if (get_screen_width (".ٟ.ऺ", utf8_widths, arrlen (utf8_widths)) == 2) {
3942 			combining_data_version = U600;
3943 		} else if (get_screen_width (".ࠖ.ऀ", utf8_widths, arrlen (utf8_widths)) == 2) {
3944 			combining_data_version = U520;
3945 		} else if (get_screen_width (".҇.᷌", utf8_widths, arrlen (utf8_widths)) == 2) {
3946 			combining_data_version = U510;
3947 		} else if (get_screen_width (".᷄.᷅", utf8_widths, arrlen (utf8_widths)) == 2) {
3948 			combining_data_version = U500;
3949 		} else if (get_screen_width (".͘.͙", utf8_widths, arrlen (utf8_widths)) == 2) {
3950 			combining_data_version = U410;
3951 		} else if (get_screen_width (".͐.឴.᠎", utf8_widths, arrlen (utf8_widths)) == 4) {
3952 			combining_data_version = U400;
3953 		} else if (get_screen_width ("aͣ", utf8_widths, arrlen (utf8_widths)) == 1) {
3954 			combining_data_version = U320;
3955 		} else if (get_screen_width ("a܏", utf8_widths, arrlen (utf8_widths)) == 1) {
3956 			combining_data_version = U300;
3957 		} else {
3958 			combining_data_version = U300beta;
3959 		}
3960 		if (combining_data_version >= U520) {
3961 			if (get_screen_width ("ᄀힰᄀퟋ", utf8_widths, arrlen (utf8_widths)) == 4) {
3962 				hangul_jamo_extended = True;
3963 			}
3964 		}
3965 		trace_width_data_version ("comb");
3966 
3967 		check_cjk_width ();
3968 
3969 		/* check non-BMP width properties */
3970 		nonbmp_width_data = get_screen_width ("��������a��a��a��", utf8_widths, arrlen (utf8_widths)) - 7;
3971 		if (nonbmp_width_data > 7) {
3972 			/* non-BMP combining characters are wide;
3973 			   xterm -cjk_width ?
3974 			 */
3975 			nonbmp_width_data -= 3;
3976 		}
3977 		if (get_screen_width ("������", utf8_widths, arrlen (utf8_widths)) > 3 && suppress_non_BMP == False) {
3978 			/* e.g. KDE konsole */
3979 			suppress_non_BMP = True;
3980 		}
3981 		/* check unassigned character width properties;
3982 		   they are sometimes displayed single-width by rxvt
3983 		   or xterm +mk_width (the default)
3984 		 */
3985 		xwidth = get_screen_width ("㄀ㄯ㄰㆏꒎꓏﫿﹯＀", utf8_widths, arrlen (utf8_widths));
3986 		if (xwidth < 18) {
3987 			unassigned_single_width = True;
3988 		}
3989 
3990 		xwidth = get_screen_width ("䷀䷀‎", utf8_widths, arrlen (utf8_widths));
3991 		/* check Yijing Hexagram width (wcwidth glitch) */
3992 		if (xwidth < 4) {
3993 			wide_Yijing_hexagrams = False;
3994 		}
3995 		/* check bidi markers printable width (since xterm 230) */
3996 		if (xwidth & 1) {
3997 			printable_bidi_controls = True;
3998 		}
3999 	    }
4000 	} else {
4001 		utf8_screen = False;
4002 		utf8_input = False;
4003 
4004 		splash_logo ();
4005 
4006 		if (! combining_screen_selected) {
4007 			combining_screen = False;
4008 			combining_mode = False;
4009 		}
4010 		acquire_screen_widths (cjk_widths, arrlen (cjk_widths));
4011 		if (swidth > 13) {
4012 			int cwidth = get_screen_width ("�0�2", cjk_widths, arrlen (cjk_widths));
4013 			if (cwidth > 2) {
4014 				/* quite safe detection */
4015 				gb18030_term = False;
4016 				suppress_extended_cjk = True;
4017 			} else if (cwidth >= 0) {
4018 				cjk_term = True;
4019 				if (cwidth == 1) {
4020 					cjk_uni_term = True;
4021 				}
4022 			}
4023 			/* if any of the following characters is smaller
4024 			   than 2 character cells,
4025 			   it's not a native CJK terminal
4026 			 */
4027 			cwidth = get_screen_width ("����ꥦ�ޡ���", cjk_widths, arrlen (cjk_widths));
4028 			if (cwidth < 14) {
4029 				cjk_uni_term = True;
4030 			}
4031 			cwidth = get_screen_width ("����", cjk_widths, arrlen (cjk_widths));
4032 			if (cwidth > 2) {
4033 				/* quite safe detection */
4034 				euc4_term = False;
4035 				suppress_extended_cjk = True;
4036 			} else if (cwidth >= 0 && swidth != 15 /* mlterm */) {
4037 				if (! mapped_term) {
4038 					cjk_term = True;
4039 				}
4040 			}
4041 			if (euc3_term && get_screen_width ("���x", cjk_widths, arrlen (cjk_widths)) > 3) {
4042 				/* unsafe detection */
4043 				euc3_term = False;
4044 				suppress_extended_cjk = True;
4045 			}
4046 			if (get_screen_width ("��", cjk_widths, arrlen (cjk_widths)) < 2) {
4047 				cjklow_term = False;
4048 			}
4049 		}
4050 		if ((swidth > 10 && swidth != 13 && swidth != 15 && swidth < 18) || cjk_term) {
4051 			/* if the test string width did not comply
4052 			   with 8 bit behaviour, or a
4053 			   GB18030 or EUC 4 byte (EUC-TW) terminal
4054 			   was asserted, assume CJK terminal;
4055 			   a EUC 3 byte (EUC-JP) terminal cannot
4056 			   be asserted but can just be assumed as
4057 			   an 8 bit terminal might respond with
4058 			   the same width behaviour
4059 			 */
4060 			utf8_screen = False;
4061 			utf8_input = False;
4062 			if (! combining_screen_selected) {
4063 				combining_screen = False;
4064 				combining_mode = False;
4065 			}
4066 			/* assume CJK terminal with unspecific encoding */
4067 			if (! mapped_term) {
4068 				cjk_term = True;
4069 			}
4070 
4071 		}
4072 	}
4073 	trace_encoding ("detected");
4074   } else {
4075 #ifdef __ANDROID__
4076 	swidth = 0;	/* no CPR */
4077 #endif
4078 	if (swidth == 0) {	/* e.g. Better Terminal on Android */
4079 		(void) set_term_encoding ("ASCII", ' ');
4080 		use_ascii_graphics = True;
4081 		menu_border_style = 'r';
4082 	}
4083 
4084 	splash_logo ();
4085   }
4086 
4087 /* detect and adjust Poderosa terminal emulator (narrow ¡ and wide ×) */
4088   if (poderosa_version > 0) {
4089 	if (utf8_screen
4090 #ifdef poderosa_detect_string
4091 	 && get_screen_width ("¡×", utf8_widths, arrlen (utf8_widths)) == 3
4092 #endif
4093 	   ) {
4094 	/* Poderosa utf-8 (or undetected euc-jp/shift-jis) */
4095 		limited_marker_font = True;
4096 	} else if (! cjk_term
4097 #ifdef poderosa_detect_string
4098 	 && ! utf8_screen && get_screen_width ("��", cjk_widths, arrlen (cjk_widths)) == 3
4099 #endif
4100 	   ) {
4101 	/* Poderosa iso-8859-1 */
4102 		(void) set_term_encoding ("ISO-8859-1", ' ');
4103 	} else {
4104 		poderosa_version = 0;
4105 	}
4106 	if (poderosa_version > 0) {
4107 		cjk_width_data_version = U300beta;
4108 		use_vt100_block_graphics = False;
4109 		use_ascii_graphics = True;
4110 		menu_border_style = 'r';
4111 		use_vga_block_graphics = False;
4112 		use_mouse = False;
4113 		use_appl_keypad = False;
4114 		colours_256 = False;
4115 		colours_88 = False;
4116 	}
4117   }
4118 
4119 #ifdef debug_graphics
4120   printf ("(tw) ascii %d, vga %d, vt100 %d\n", use_ascii_graphics, use_vga_block_graphics, use_vt100_block_graphics);
4121 #endif
4122 
4123 
4124 /* determine combining character support on non-Unicode terminal */
4125   if (cjk_term) {
4126 	unsigned long cjk_combining = mappedtermchar (0x0300);
4127 	if (no_char (cjk_combining)) {
4128 		combining_screen = False;
4129 	} else {
4130 		char cjk_check [9];
4131 		char * check = cjk_check;
4132 		* check ++ = 'a';
4133 		check += cjkencode_char (True, cjk_combining, check);
4134 		* check = '\0';
4135 		if (test_screen_width (cjk_check) == 1) {
4136 			combining_screen = True;
4137 			if (! combining_mode_disabled) {
4138 				combining_mode = True;
4139 			}
4140 #ifdef debug_screenmode
4141 			printf ("cjk combining screen %d (disabled %d) mode %d\n", combining_screen, combining_mode_disabled, combining_mode);
4142 #endif
4143 		}
4144 	}
4145   } else if (mapped_term) {
4146 	character c;
4147 	combining_screen = False;
4148 	for (c = 0x80; ; c ++) {
4149 		unsigned long u = lookup_mappedtermchar (c);
4150 		if (! no_unichar (u) && iscombining (u)) {
4151 			char comb_check [3];
4152 			comb_check [0] = 'a';
4153 			comb_check [1] = c;
4154 			comb_check [2] = '\0';
4155 			if (test_screen_width (comb_check) == 1) {
4156 				combining_screen = True;
4157 				if (! combining_mode_disabled) {
4158 					combining_mode = True;
4159 				}
4160 			}
4161 			break;
4162 		}
4163 		if (c == 0xFF) {
4164 			break;
4165 		}
4166 	}
4167   }
4168 
4169 /* determine joining character support on non-Unicode terminal */
4170   if (cjk_term || mapped_term) {
4171 	unsigned long lam = mappedtermchar (0x0644);
4172 	if (! no_char (lam)) {
4173 		unsigned long alef = mappedtermchar (0x0627);
4174 		char join_check [9];
4175 		char * check = join_check;
4176 		* check ++ = 'a';
4177 		if (cjk_term) {
4178 			check += cjkencode_char (True, lam, check);
4179 			check += cjkencode_char (True, alef, check);
4180 		} else {
4181 			* check ++ = lam;
4182 			* check ++ = alef;
4183 		}
4184 		* check = '\0';
4185 		if (test_screen_width (join_check) == 2) {
4186 			/* ligature joining detected, must also be bidi */
4187 			joining_screen = True;
4188 			bidi_screen = True;
4189 			poormansbidi = False;
4190 			/* disable scrollbar to prevent interference */
4191 			if (! explicit_scrollbar_style) {
4192 				disp_scrollbar = False;
4193 				scrollbar_width = 0;
4194 			}
4195 			/* bold does not work */
4196 			use_bold = False;
4197 #ifdef debug_screenmode
4198 			printf ("bidi screen\n");
4199 #endif
4200 		}
4201 	}
4202   }
4203 
4204 /* determine terminal restrictions relevant for marker configuration */
4205 
4206   if (strisprefix ("terminator", TERM)) {
4207 	limited_marker_font = True;
4208   }
4209 
4210 
4211 /* adjust CJK width properties */
4212 /* adjust CJK line markers */
4213   if (cjk_term) {
4214 	/* determine size of line markers in CJK terminal encoding */
4215 	int cjk_ellipsis_width;
4216 	unsigned long cjk_degree = mappedtermchar (0x00B0);	/* ° */
4217 	unsigned long cjk_lineend = mappedtermchar (0x300A);	/* 《 */
4218 	unsigned long cjk_ellipsis = mappedtermchar (0x2026);	/* … */
4219 	unsigned long cjk_uni = mappedtermchar (0x00A2);	/* ¢ */
4220 	unsigned long cjk_dot = mappedtermchar (0x00B7);	/* · */
4221 	unsigned long cjk_lat = mappedtermchar (0x00F8);	/* ø */
4222 	unsigned long cjk_shy = mappedtermchar (0x00AD);	/* ­ */
4223 	unsigned long cjk_ten = mappedtermchar (0x3248);	/* ㉈ */
4224 
4225 	char cjk_check [29];
4226 	char * check = cjk_check;
4227 	int cjkwidth;
4228 	cjk_currency_width = 1;
4229 	check += cjkencode_char (True, cjk_ellipsis, check);
4230 	check += cjkencode_char (True, cjk_lineend, check);
4231 	check += cjkencode_char (True, cjk_lineend, check);
4232 	if (no_char (cjk_uni)) {
4233 		cjk_currency_width = 0;
4234 		cjk_uni = cjk_shy;
4235 		if (no_char (cjk_uni)) {
4236 			cjk_uni = mappedtermchar (0x00AF);	/* ¯ */
4237 		}
4238 	}
4239 	if (! no_char (cjk_uni)) {
4240 		check += cjkencode_char (True, cjk_uni, check);
4241 		check += cjkencode_char (True, cjk_uni, check);
4242 		check += cjkencode_char (True, cjk_uni, check);
4243 		check += cjkencode_char (True, cjk_uni, check);
4244 	}
4245 	* check = '\0';
4246 	cjkwidth = test_screen_width (cjk_check);
4247 	cjkwidth --;
4248 	cjk_ellipsis_width = 1 + (cjkwidth & 1);
4249 	cjkwidth = (cjkwidth >> 1) - 1;
4250 	cjk_lineend_width = 1 + (cjkwidth & 1);
4251 	cjkwidth = (cjkwidth >> 1) - 1;
4252 	if (cjk_currency_width && cjkwidth == 1) {
4253 		cjk_currency_width = 2;
4254 	}
4255 	if (! no_char (cjk_uni) && (cjkwidth & 1) == 0) {
4256 		cjk_uni_term = True;
4257 	}
4258 
4259 	if (cjk_uni_term) {
4260 		if (! no_char (cjk_degree)) {
4261 			check = cjk_check;
4262 			check += cjkencode_char (True, cjk_degree, check);
4263 			* check = '\0';
4264 			if (test_screen_width (cjk_check) == 2) {
4265 				cjk_width_data_version = U320beta;
4266 			}
4267 		}
4268 
4269 		if (cjk_lineend_width == 1) {
4270 			if (width_data_version > 0) {
4271 				width_data_version = U300;
4272 			}
4273 		} else if (cjk_ellipsis_width == 2) {
4274 			cjk_width_data_version = U400;
4275 			/* ?
4276 			if (width_data_version < U400) {
4277 				if (width_data_version > 0) {
4278 					width_data_version = U400;
4279 				}
4280 			}
4281 			*/
4282 
4283 			if (! no_char (cjk_ten)) {
4284 				check = cjk_check;
4285 				check += cjkencode_char (True, cjk_ten, check);
4286 				* check = '\0';
4287 				if (test_screen_width (cjk_check) == 2) {
4288 					cjk_width_data_version = U520;
4289 				}
4290 			}
4291 
4292 			if (cjk_width_data_version < U520 && ! no_char (cjk_shy)) {
4293 				check = cjk_check;
4294 				check += cjkencode_char (True, cjk_shy, check);
4295 				* check = '\0';
4296 				if (test_screen_width (cjk_check) == 2) {
4297 					cjk_width_data_version = U320beta;
4298 				}
4299 			}
4300 
4301 			if (! no_char (cjk_lat)) {
4302 				check = cjk_check;
4303 				check += cjkencode_char (True, cjk_lat, check);
4304 				* check = '\0';
4305 				if (test_screen_width (cjk_check) == 2) {
4306 					cjk_wide_latin1 = True;
4307 				} else {
4308 					cjk_wide_latin1 = False;
4309 				}
4310 			}
4311 		} else if (rxvt_version > 0 && ! no_char (cjk_dot)) {
4312 			check = cjk_check;
4313 			check += cjkencode_char (True, cjk_dot, check);
4314 			* check = '\0';
4315 			if (test_screen_width (cjk_check) == 1) {
4316 				/* fix this as a workaround for buggy rxvt */
4317 				if (width_data_version > 0) {
4318 					width_data_version = U320;
4319 				}
4320 			}
4321 		}
4322 		trace_width_data_version ("cjk_uni_term");
4323 #ifdef debug_screenmode
4324 		printf ("cjk_uni_term (width_data_version %d CJK %d) ", width_data_version, cjk_width_data_version);
4325 #endif
4326 	}
4327 #ifdef debug_screenmode
4328 	printf ("CJK %c\n", text_encoding_tag);
4329 	printf ("euc3 %d, euc4 %d, low cjk %d\n", euc3_term, euc4_term, cjklow_term);
4330 #endif
4331 
4332 	if (CJK_TAB_marker >= 0x80) {
4333 #ifdef CJKTAB_MIDDLE_DOT
4334 		/* not available in all CJK encodings and terminals */
4335 		CJK_TAB_marker = 0x00B7;
4336 		cjk_tab_width = cjk_dot_width;
4337 #else
4338 		cjk_tab_width = cjk_ellipsis_width;
4339 #endif
4340 		if (term_encoding_tag == 'H') {
4341 			/* workaround for buggy hanterm */
4342 			CJK_TAB_marker = '.';
4343 		}
4344 		if (limited_marker_font) {
4345 			CJK_TAB_marker = '.';
4346 		}
4347 	}
4348 	if (CJK_TAB_marker < 0x80) {
4349 		cjk_tab_width = 1;
4350 	}
4351 
4352 	/* ensure further markers work for CJK */
4353 	SHIFT_marker = ' ';
4354 	MENU_marker = '>';
4355   }
4356 
4357 
4358 #ifdef debug_screenmode
4359 	printf ("width_data_version %d (CJK %d), combining_data_version %d\n", width_data_version, cjk_width_data_version, combining_data_version);
4360 #else
4361 	trace_width_data_version ("final");
4362 #endif
4363 
4364 
4365 /* request terminal type and version from terminal */
4366 /*  detect_terminal_type ();	moved above */
4367 
4368 
4369 /* 'screen' tweaks */
4370   if (screen_version > 0) {
4371 	if (! explicit_scrollbar_style) {
4372 		fine_scrollbar = False;
4373 	}
4374 	if (! explicit_border_style) {
4375 		use_stylish_menu_selection = False;
4376 		use_vt100_block_graphics = True;
4377 	}
4378 	if (limited_marker_font) {
4379 		very_limited_marker_font = True;
4380 	} else {
4381 		limited_marker_font = True;
4382 	}
4383 	use_mouse_anymove_inmenu = True;
4384   }
4385 
4386 /* 'tmux' tweaks */
4387   if (tmux_version > 0) {
4388 	if (limited_marker_font) {
4389 		very_limited_marker_font = True;
4390 	} else {
4391 		limited_marker_font = True;
4392 	}
4393 	if (! explicit_border_style) {
4394 		use_stylish_menu_selection = False;
4395 	}
4396 	bold_border = False;	/* could be in mintty using DejaVu fonts */
4397   }
4398 
4399 /* mlterm tweaks */
4400   /* since mlterm does not identify itself, try to reveal it: */
4401   if (! mlterm_version) {
4402 	if (streq ("mlterm", TERM)) {
4403 		mlterm_version = 1;
4404 	} else if (bidi_screen && ! mintty_version) { /* probably mlterm */
4405 		mlterm_version = 1;
4406 	}
4407   }
4408   if (mlterm_version > 0) {
4409 	use_appl_keypad = True;
4410 	apply_joining = False;	/* use native LAM/ALEF joining of mlterm */
4411 	unassigned_single_width = True;
4412 	spacing_combining = True;
4413 	/* bold would use weird font */
4414 	use_bold = False;
4415 	if (xterm_version >= 96) {	/* mlterm 3.1.0 */
4416 		use_mouse_1015 = True;	/* mlterm 3.1.2 supports 1015 and 1006 */
4417 	}
4418 	/* enforce some observed font limitations of cygwin mlterm */
4419 	if (limited_marker_font) {
4420 		very_limited_marker_font = True;
4421 	} else {
4422 		limited_marker_font = True;
4423 	}
4424 	if (! explicit_border_style) {
4425 		use_stylish_menu_selection = False;
4426 	}
4427 	if (! explicit_scrollbar_style) {
4428 		disp_scrollbar = False;
4429 		scrollbar_width = 0;
4430 	}
4431 	fine_scrollbar = False;
4432   }
4433 
4434 /* workaround for buggy mlterm bold/width chaos */
4435 #ifdef oldmlterm_wideboldborderbug_workaround
4436   if (! explicit_border_style && ! cjk_width_data_version) {
4437 	bold_on ();
4438 	/* check width of upper left rounded corner */
4439 	if (get_screen_width ("╭", utf8_widths, arrlen (utf8_widths)) > 1) {
4440 		use_vt100_block_graphics = True;
4441 	}
4442 	bold_off ();
4443   }
4444 #endif
4445 
4446 /* tweaks for KDE konsole; disable use of some features */
4447   if (konsole_version > 0) {
4448 	colours_256 = False;
4449 	if (! utf8_screen) {
4450 		/* VT100 block graphics work now with workaround for
4451 		   missing eA capability (see io.c) */
4452 		/* disable use of VT100 block graphics for
4453 		   konsole instances that do not support them */
4454 		if (strcontains (TERM, "linux")) {
4455 			use_ascii_graphics = True;
4456 			menu_border_style = 'r';
4457 			use_vga_block_graphics = False;
4458 		}
4459 	}
4460 	/* disable use of Unicode fine-grained block graphics */
4461 	if (! explicit_border_style) {
4462 		use_stylish_menu_selection = False;
4463 		if (! use_ascii_graphics) {
4464 			menu_border_style = 's';
4465 		}
4466 	}
4467 	/* make menu selections more visible ? */
4468 	/*dark_term = True;*/	/* fatal if not actually dark */
4469 
4470 	/* workaround for buggy behaviour on systems that report
4471 	   wrong window size (SCO Unixware Caldera Linux) */
4472 	if (! can_get_winsize) {
4473 		can_delete_line = False;
4474 	}
4475   }
4476 
4477 /* handle mintty/PuTTY */
4478   if (mintty_version > 0) {
4479 	display_delay = 0;
4480 
4481 	if (utf8_screen && mintty_version >= 909) {
4482 		/* used to check_glyphs () here */
4483 		if (! glyphs) {
4484 			limited_marker_font = True;
4485 		}
4486 	} else {
4487 		if (limited_marker_font) {
4488 			very_limited_marker_font = True;
4489 		} else {
4490 			limited_marker_font = True;
4491 		}
4492 	}
4493 
4494 	spacing_combining = False;
4495 	if (mintty_version < 500 && suppress_non_BMP == False) {
4496 		suppress_non_BMP = True;
4497 	}
4498 	bidi_screen = True;
4499 	halfjoining_screen = True;
4500 	apply_joining = True;
4501 	poormansbidi = False;
4502 	/* disable scrollbar to prevent interference */
4503 	if (! explicit_scrollbar_style) {
4504 		/*disp_scrollbar = False;*/
4505 		/*scrollbar_width = 0;*/
4506 	}
4507 
4508 	/* mintty display adjustment */
4509 	if (! explicit_scrollbar_style) {
4510 		if (! isglyph_code ("9601")) { /* LOWER ONE EIGHTH BLOCK */
4511 			fine_scrollbar = False;
4512 		}
4513 	}
4514 	if (! explicit_selection_style) {
4515 #ifdef assume_proper_vertical_blocks
4516 		if (! isglyph_code ("9613")) { /* LEFT THREE EIGHTHS BLOCK */
4517 			use_stylish_menu_selection = False;
4518 		}
4519 #else
4520 		/* defensively disable use of crap vertical blocks */
4521 		use_stylish_menu_selection = False;
4522 #endif
4523 	}
4524 	if (! explicit_border_style) {
4525 		if (mintty_version >= 400) {
4526 			if (isglyph_code ("9581")) { /* BOX DRAWINGS ARC */
4527 				menu_border_style = 'r';
4528 			} else if (isglyph_code ("9484")) { /* BOX DRAW. CORNER */
4529 				menu_border_style = 's';
4530 			} else {
4531 				use_vt100_block_graphics = True;
4532 				/*use_ascii_graphics = True;*/
4533 				menu_border_style = 'r';
4534 			}
4535 		} else {
4536 			menu_border_style = 'd';
4537 		}
4538 	}
4539 	/* for the sake of DejaVu fonts */
4540 	bold_border = False;
4541 
4542 	can_dim = True;		/* ? some shading problems... */
4543 #ifdef avoid_light_pseudo_bold
4544 	dark_term = False;
4545 #endif
4546 
4547 	if (mintty_version >= 400) {
4548 		use_modifyOtherKeys = True;
4549 		use_appl_cursor = False;
4550 		use_appl_keypad = True;
4551 	}
4552 	if (mintty_version >= 10004) {
4553 		/* numeric encoding of mouse coordinates */
4554 		use_mouse_1015 = True;
4555 	} else {
4556 		use_mouse_1015 = False;	/* buggy in 1.0.3 */
4557 		if (mintty_version >= 900) {
4558 			/* UTF-8 encoding of mouse coordinates */
4559 			use_mouse_extended = True;
4560 		}
4561 	}
4562 	/* enable mouse move reporting without button pressed (for menus) */
4563 	use_mouse_anymove_inmenu = True;
4564 	/* limit terminal to ASCII in POSIX locale */
4565 	(void) locale_terminal_encoding ();
4566   }
4567 
4568   if (strisprefix ("xterm", TERM) && xterm_version != 2) {
4569 	colours_256 = True;
4570   }
4571 
4572 /* disable VT100 graphics for openwin xterm (but not for cxterm etc) */
4573   if (xterm_version == 2 && ! cjk_term) {
4574 	use_ascii_graphics = True;
4575 	use_vt100_block_graphics = False;
4576 	menu_border_style = 'r';
4577   }
4578 
4579 /* disable erase characters for older xterm */
4580   if (xterm_version < 154 && mlterm_version == 0) {
4581 	can_erase_chars = False;
4582   }
4583 
4584 /* indicate enabling of special terminal modes */
4585   if (xterm_version >= 216) {
4586 	use_modifyOtherKeys = True;
4587 	/*use_appl_keypad = True;*/
4588   }
4589   if (xterm_version > 0) {
4590 	/* enable mouse move reporting without button pressed (for menus) */
4591 	use_mouse_anymove_inmenu = True;
4592   }
4593   if (xterm_version >= 277) {
4594 	/* numeric encoding of mouse coordinates */
4595 	use_mouse_1015 = True;
4596   } else if (xterm_version >= 262) {
4597 	/* UTF-8 encoding of mouse coordinates */
4598 	use_mouse_extended = True;
4599   }
4600   if (xterm_version > 305) {
4601 	can_dim = True;
4602   }
4603   if (xterm_version > 0 /* && xterm_version < ?? */) {
4604 	suppress_non_BMP = True;
4605   }
4606 
4607 #ifdef use_mouse_hilite_tracking
4608 /* suppress mouse highlight tracking when it would lock xterm */
4609   if (xterm_version == 224) {
4610 	/* xterm bug broke hilite mode abort sequence */
4611 	use_mouse_hilite_tracking = False;
4612   }
4613 #endif
4614 
4615 /* suppress fancy graphic characters in gnome-terminal, fix keyboard mapping */
4616   if (gnome_terminal_version > 0) {
4617 	/* give built-in keydefs precedence over buggy termcap */
4618 	set_fkeymap (NIL_PTR);
4619 	/* workaround for unusual keypad assignments */
4620 	if (mined_keypad) {
4621 		mined_keypad = False;
4622 	} else {	/* in case option -k reversed it already */
4623 		mined_keypad = True;
4624 	}
4625 
4626 	/* probably gnome-terminal */
4627 	if (! use_ascii_graphics) {
4628 		menu_border_style = 's';
4629 	}
4630 	use_stylish_menu_selection = False;
4631 	fine_scrollbar = False;
4632 
4633 	/* make menu selections more visible ? */
4634 	/*dark_term = True;*/	/* fatal if not actually dark */
4635 
4636 	/* suppress attempts to display invalid Unicode characters */
4637 	suppress_EF = True;
4638 
4639 	/* enable mouse move reporting without button pressed (for menus) */
4640 	use_mouse_anymove_inmenu = True;
4641 
4642 	if (gnome_terminal_version >= 2000 && gnome_terminal_version < 2800) {
4643 		/* for the sake of sakura */
4644 		use_vt100_block_graphics = True;
4645 		limited_marker_font = True;
4646 		very_limited_marker_font = True;
4647 	}
4648 
4649 	cursor_style = 0;
4650    }
4651 
4652 /* special cases of terminal capabilities handling (esp. block graphics) */
4653 
4654   if (strcontains (TERM, "vt220")
4655      || strcontains (TERM, "vt320")
4656      || strcontains (TERM, "vt340")
4657      || strcontains (TERM, "vt400")
4658      || strcontains (TERM, "vt420")
4659      || strcontains (TERM, "vt510")
4660      || strcontains (TERM, "vt520")
4661      || strcontains (TERM, "vt525")
4662      || strisprefix ("pcvt", TERM)
4663      || strisprefix ("ncsa", TERM)
4664      || strisprefix ("ti916", TERM)
4665      || strisprefix ("bq300", TERM)
4666      || strisprefix ("z340", TERM)
4667      || strisprefix ("ncr160vt300", TERM)
4668      || strisprefix ("ncr260vt300", TERM)
4669      || streq ("emu-220", TERM)
4670      || streq ("crt", TERM)
4671      ) {
4672 	use_appl_keypad = True;
4673   }
4674   if (strcontains (TERM, "linux")) {
4675 	set_fkeymap ("linux");
4676 	fine_scrollbar = False;
4677 	use_stylish_menu_selection = False;
4678 	UTF_MENU_marker = "»";
4679 	submenu_marker = "»";
4680 	dark_term = True;
4681 	bold_border = False;	/* needed e.g. for Debian VGA console */
4682 	use_appl_keypad = True;
4683 	if (! explicit_border_style) {
4684 		if (utf8_screen) {
4685 			/*use_ascii_graphics = True;*/
4686 			if (! use_ascii_graphics) {
4687 				/* 's' or 'd' work */
4688 				menu_border_style = 's';
4689 			}
4690 		} else if (use_vt100_block_graphics == False) {
4691 			use_vga_block_graphics = True;
4692 		}
4693 	}
4694   }
4695   if (! can_alt_cset && ! use_pc_block_graphics && ! use_vga_block_graphics && ! utf8_screen ) {
4696 	use_ascii_graphics = True;
4697 	menu_border_style = 'r';
4698   }
4699   if (cjk_term) {
4700 	/* make sure lineend marker will always fit: */
4701 	scrollbar_width = 1;
4702 
4703 	/*use_bgcolor = False;*/
4704 
4705 	if (strisprefix ("rxvt", TERM)) {
4706 		/* seems to work now */
4707 	} else if (xterm_version == 2) {
4708 		/* cxterm would blink instead of setting 256 color mode */
4709 		colours_256 = False;
4710 		colours_88 = False;
4711 	}
4712   }
4713 #ifdef debug_graphics
4714   printf ("(tt) ascii %d, vga %d, vt100 %d\n", use_ascii_graphics, use_vga_block_graphics, use_vt100_block_graphics);
4715 #endif
4716 
4717 /* derive further terminal restrictions */
4718   if (standout_glitch) {
4719 	use_bold = False;
4720   }
4721 
4722 
4723 /* some terminal-specific properties */
4724   if (strisprefix ("vt1", TERM)) {
4725 	use_appl_keypad = True;
4726   }
4727   if (rxvt_version > 0 || strisprefix ("rxvt", TERM)) {
4728 	use_appl_keypad = True;
4729 
4730 	if (rxvt_version < 909 && rxvt_version >= 380) {
4731 		colours_256 = False;
4732 		colours_88 = True;
4733 		/* ?? colour mode doesn't work with older buggy rxvt after configure --enable-text-blink --disable-256-color */
4734 	}
4735 
4736 #ifdef check_unassigned_single_width_here
4737 	/* rxvt-unicode sometimes displays all unassigned Unicode chars
4738 	   in single width;
4739 	   According to change log, this could have been fixed in:
4740 		   4.4: rewrote handling of default-char width
4741 		   8.0: fixed urxvt::strwidth to calculate width in the same way as screen.C
4742 		   8.1: rewrote handling of default-char width
4743 	   It does not happen with cygwin rxvt-unicode
4744 	   (which is not locale-driven).
4745 	   Check should not be limited to certain versions (e.g. < 810):
4746 	   - inconsistent behaviour (e.g. cygwin, see above)
4747 	   - unreliable version detection, e.g. rxvt 7.7 reports to be 9.4
4748 	 */
4749 	/* issue also sometimes occurs with xterm +mk_width,
4750 	   so the check was moved out (see above)
4751 	 */
4752 	if (rxvt_version > 0) {
4753 		if (test_screen_width ("㄀ㄯ㄰㆏꒎꓏﫿﹯＀") < 18) {
4754 			unassigned_single_width = True;
4755 		}
4756 	}
4757 #endif
4758 
4759 	/* rxvt sends ESC prefix for Alt-modified escape sequences */
4760 	detect_esc_alt = True;
4761 	/* disable use of VT100 block graphics on rxvt which does not support them */
4762 	if (! utf8_screen) {
4763 		/* VT100 block graphics work now with workaround for
4764 		   missing eA capability (see io.c) */
4765 		if (rxvt_version < 300) {	/* old (non-Unicode) rxvt */
4766 			/* VT100 block graphics depend on font capabilities */
4767 			use_ascii_graphics = True;
4768 			menu_border_style = 'r';
4769 		}
4770 	}
4771 
4772 	if (rxvt_version >= 840) {
4773 		use_mouse_anymove_inmenu = True;
4774 	}
4775 	/* numeric encoding of mouse coordinates since rxvt-unicode 9.10 */
4776 	use_mouse_1015 = True;
4777   }
4778 
4779 #ifdef debug_graphics
4780   printf ("(tx) ascii %d, vga %d, vt100 %d\n", use_ascii_graphics, use_vga_block_graphics, use_vt100_block_graphics);
4781 #endif
4782 
4783 
4784 /* disable graphics on some CJK terminals */
4785   if (cjk_term && ! use_vt100_block_graphics && ! can_alt_cset) {
4786 	use_ascii_graphics = True;
4787 	menu_border_style = 'r';
4788   }
4789 #ifdef debug_graphics
4790   printf ("(ct) ascii %d, vga %d, vt100 %d\n", use_ascii_graphics, use_vga_block_graphics, use_vt100_block_graphics);
4791 #endif
4792 
4793 
4794 /* configure line markers */
4795   config_markers ();
4796 
4797 /* adjust wide line markers */
4798   if (cjk_width_data_version) {
4799 	if (UTF_TAB_marker && iswide (utf8value (UTF_TAB_marker))) {
4800 		UTF_TAB_marker = NIL_PTR;
4801 	}
4802 	if (UTF_TAB0_marker && iswide (utf8value (UTF_TAB0_marker))) {
4803 		UTF_TAB0_marker = NIL_PTR;
4804 	}
4805 	if (UTF_TAB2_marker && iswide (utf8value (UTF_TAB2_marker))) {
4806 		UTF_TAB2_marker = NIL_PTR;
4807 	}
4808 	if (UTF_TABmid_marker && iswide (utf8value (UTF_TABmid_marker))) {
4809 		UTF_TABmid_marker = NIL_PTR;
4810 	}
4811   }
4812 
4813 /* adjust to glyph detection */
4814   if (glyphs && * glyphs) {	/* utf8_screen && mintty_version >= 909 */
4815     /*
4816     the check covers misc. configurable alternatives and char. substitutes:
4817     border styles:
4818 	border	┌ ┆/╎/┊
4819 	- rnd	╭
4820 	- fat	┏ ╏/┇/┋
4821 	- dbl	╔
4822 	- cont	◆ ♦ ◈ ⬘ ⬙
4823 	- yet unchecked: 9487┏;9556╔;9550╎;9482┊;9551╏;9483┋
4824     markers (additional):
4825 	menu	• ☛ ☞
4826 	tab	․ ‥ … ▷ ▸ ▹ ▻
4827 	ret	◀ ◁ ◂ ◃ ◄ ◅
4828 	shift	tab/ret ⬖ ⬗
4829     special characters:
4830 	char	✓ ✗ ↯
4831     */
4832 	/* Usage of TAB markers:
4833 		TAB0 TAB TAB TAB TAB TAB TAB (TAB2)
4834 		TAB TAB TAB TAB TABmid TAB TAB TAB
4835 	*/
4836 	if (! isglyph_utf (UTF_TAB_marker)) {
4837 		if (isglyph_code ("8231")) {
4838 			UTF_TAB_marker = "‧";
4839 		} else {
4840 			UTF_TAB_marker = "·";
4841 		}
4842 	}
4843 	if (! isglyph_utf (UTF_TABmid_marker)) {
4844 		if (isglyph_code ("8227")) {
4845 			UTF_TABmid_marker = "‣";
4846 		} else if (isglyph_code ("8702")) {
4847 			UTF_TABmid_marker = "⇾";
4848 		} else if (isglyph_code ("8594")) {
4849 			UTF_TABmid_marker = "→";
4850 		} else {
4851 			UTF_TABmid_marker = UTF_TAB_marker;
4852 		}
4853 	}
4854 	if (! isglyph_utf (UTF_TAB0_marker)) {
4855 		if (UTF_TAB2_marker != NIL_PTR) {
4856 			UTF_TAB0_marker = UTF_TAB_marker;
4857 		} else {
4858 			UTF_TAB0_marker = NIL_PTR;
4859 		}
4860 	}
4861 	if (! isglyph_utf (UTF_TAB2_marker)) {
4862 		UTF_TAB2_marker = NIL_PTR;
4863 	}
4864 
4865 	if (! isglyph_utf (UTF_RET_marker)) {
4866 		if (isglyph_code ("9166")) {
4867 			UTF_RET_marker = "⏎";
4868 		} else if (isglyph_code ("8629")) {
4869 			UTF_RET_marker = "↵";
4870 		} else if (isglyph_code ("8626")) {
4871 			UTF_RET_marker = "↲";
4872 		} else {
4873 			UTF_RET_marker = "«";
4874 		}
4875 	}
4876 	if (! isglyph_utf (UTF_RETfill_marker)) {
4877 		UTF_RETfill_marker = "";
4878 	}
4879 	if (! isglyph_utf (UTF_RETfini_marker)) {
4880 		UTF_RETfini_marker = "";
4881 	}
4882 	if (! isglyph_utf (UTF_DOSRET_marker)) {
4883 		UTF_DOSRET_marker = UTF_RET_marker;
4884 	}
4885 	if (! isglyph_utf (UTF_MACRET_marker)) {
4886 		UTF_MACRET_marker = UTF_RET_marker;
4887 	}
4888 	if (UTF_PARA_marker && ! isglyph_utf (UTF_PARA_marker)) {
4889 		UTF_PARA_marker = NIL_PTR;
4890 	}
4891 
4892 	if (! isglyph_utf (UTF_SHIFT_marker)) {
4893 		UTF_SHIFT_marker = "»";
4894 	}
4895 	if (! isglyph_utf (UTF_SHIFT_BEG_marker)) {
4896 		UTF_SHIFT_BEG_marker = "«";
4897 	}
4898 
4899 	if (! isglyph_utf (UTF_MENU_marker)) {
4900 		if (isglyph_code ("10003")) {
4901 			UTF_MENU_marker = "✓";
4902 		} else if (isglyph_utf (UTF_MENU_marker_alt)) {
4903 			UTF_MENU_marker = UTF_MENU_marker_alt;
4904 		} else {
4905 			UTF_MENU_marker = "»";
4906 		}
4907 	}
4908 	if (! isglyph_utf (submenu_marker)) {
4909 		submenu_marker = submenu_marker_alt;
4910 		if (! isglyph_utf (submenu_marker)) {
4911 			submenu_marker = "»";
4912 		}
4913 	}
4914 
4915 	/* menu scrolling indications */
4916 	if (! isglyph_utf (menu_cont_marker)) {
4917 		if (isglyph_code ("9830")) {
4918 			menu_cont_marker = "♦";
4919 		} else {
4920 			menu_cont_marker = "│";
4921 		}
4922 	}
4923 	if (! isglyph_utf (menu_cont_fatmarker)) {
4924 		if (isglyph_code ("9830")) {
4925 			menu_cont_fatmarker = "♦";
4926 		} else {
4927 			menu_cont_fatmarker = "┃";
4928 		}
4929 	}
4930   } else if (very_limited_marker_font) {
4931 	glyphs = "";	/* pretend all checked glyphs unavailable */
4932   }
4933 
4934 
4935 /* setup terminal modes */
4936   /* call raw_mode again (was already called for initial tty configuration) */
4937   raw_mode (True);
4938 
4939 
4940 /* terminal height adjustment / detection
4941    - deprecated section, see checkwinsize ()
4942 	terminal control codes useful here:
4943 	ESC[<n>t	(n>=24)	resize to n lines
4944 	ESC[18t		report size of text area as ESC[8;<height>;<width>t
4945 	ESC[8;<height>;<width>t	resize text area
4946   */
4947   if (ansi_esc) {
4948 #ifdef adjust_terminal_height	/* obsolete */
4949 	if (strisprefix ("xterm", TERM) && konsole_version <= 0) {
4950 		/* try to adjust the window to the size the tty assumes;
4951 		   workaround for buggy Cygwin/X xterm tty size assumption,
4952 		   also workaround for various rlogin/telnet size confusions;
4953 		   also workaround for false explicit stty rows settings
4954 		 */
4955 		char resizebuf [19];
4956 		int height = YMAX + 1 + MENU;
4957 #ifdef adjust_lines_only
4958 		if (height >= 24 && rxvt_version <= 0) {
4959 			/* this short form doesn't work with rxvt
4960 			   (which would become extra large)
4961 			 */
4962 			build_string (resizebuf, "\033[%dt", height);
4963 # ifdef debug_terminal_resize
4964 			printf ("setting terminal to %d lines\n", height);
4965 # endif
4966 		} else {
4967 			build_string (resizebuf, "\033[8;%d;%dt", height, XMAX + 1);
4968 # ifdef debug_terminal_resize
4969 			printf ("setting terminal to %dx%d\n", height, XMAX + 1);
4970 # endif
4971 		}
4972 #else
4973 		build_string (resizebuf, "\033[8;%d;%dt", height, XMAX + 1);
4974 # ifdef debug_terminal_resize
4975 		printf ("setting terminal to %dx%d\n", height, XMAX + 1);
4976 # endif
4977 #endif
4978 		putescape (resizebuf);
4979 	}
4980 #else
4981 #ifdef adjust_to_actual_termsize
4982 	unsigned long c;
4983 	/* response will be handled by ANSIseq */
4984 	putescape ("\033[18t");	/* long timeout if response disabled? */
4985 # ifdef debug_terminal_resize
4986 	printf ("requesting terminal size\n");
4987 # endif
4988 	flush ();
4989 #endif
4990 #endif
4991   }
4992 }
4993 
4994 
4995 /*======================================================================*\
4996 |*		Setup misc stuff					*|
4997 \*======================================================================*/
4998 
4999 /**
5000    generate names of paste, spool, panic files
5001  */
5002 static
5003 void
setup_temp_filenames()5004 setup_temp_filenames ()
5005 {
5006   char * temp_dir;
5007   char temp_dn [maxFILENAMElen];
5008   char * minedtemp_dir;
5009   char * username = envvar ("MINEDUSER");
5010   if (! username) {
5011 	username = getusername ();
5012   }
5013 
5014 #ifdef unix
5015   temp_dir = envvar ("TMPDIR");
5016   if (temp_dir == NIL_PTR || temp_dir [0] == '\0' || access (temp_dir, W_OK | X_OK) < 0) {
5017 	temp_dir = envvar ("TMP");
5018   }
5019   if (temp_dir == NIL_PTR || temp_dir [0] == '\0' || access (temp_dir, W_OK | X_OK) < 0) {
5020 	temp_dir = envvar ("TEMP");
5021   }
5022   if (temp_dir == NIL_PTR || temp_dir [0] == '\0' || access (temp_dir, W_OK | X_OK) < 0) {
5023 	/* the less volatile traditional tmp dir (often link to /var/tmp) */
5024 	temp_dir = "/usr/tmp";
5025   }
5026   if (access (temp_dir, W_OK | X_OK) < 0) {
5027 	temp_dir = "/tmp";
5028   }
5029   if (access (temp_dir, W_OK | X_OK) < 0) {
5030 	/* in case there is no $TMP, no /tmp etc (e.g. Android): */
5031 	temp_dir = gethomedir ();
5032   }
5033 
5034   strcpy (temp_dn, temp_dir);
5035   strip_trailingslash (temp_dn);
5036   temp_dir = temp_dn;
5037 
5038   /* prefer $MINEDTMP for buffer and spool files (but not for panic files) */
5039   minedtemp_dir = envvar ("MINEDTMP");
5040   if (minedtemp_dir == NIL_PTR || minedtemp_dir [0] == '\0' || access (minedtemp_dir, W_OK | X_OK) < 0) {
5041 	minedtemp_dir = temp_dir;
5042   }
5043 
5044   build_string (panic_file, "%s/minedrecover.%s.%d", temp_dir, username, (int) getpid ());
5045   build_string (yankie_file, "%s/mined.%s", minedtemp_dir, username);
5046   build_string (spool_file, "%s/minedprint.%s.%d", minedtemp_dir, username, (int) getpid ());
5047 #endif
5048 #ifdef vms
5049   if (envvar ("SYS$SCRATCH")) {
5050 	temp_dir = "SYS$SCRATCH";
5051   } else {
5052 	temp_dir = "SYS$LOGIN";
5053   }
5054 
5055   /* prefer $MINEDTMP for buffer and spool files (but not for panic files) */
5056   if (envvar ("SYS$MINEDTMP")) {
5057 	minedtemp_dir = "SYS$MINEDTMP";
5058   } else {
5059 	minedtemp_dir = temp_dir;
5060   }
5061 
5062   build_string (panic_file, "%s:$MINEDRECOVER$%s$%d", temp_dir, username, getpid ());
5063   build_string (yankie_file, "%s:$MINED$%s", minedtemp_dir, username);
5064   build_string (spool_file, "%s:$MINEDPRINT$%s$%d", minedtemp_dir, username, getpid ());
5065 #endif
5066 #ifdef msdos
5067   temp_dir = envvar ("TEMP");
5068   if (temp_dir == NIL_PTR || temp_dir [0] == '\0') {
5069 	temp_dir = envvar ("TMP");
5070   }
5071   if (temp_dir == NIL_PTR || temp_dir [0] == '\0') {
5072 	temp_dir = "\\";
5073   }
5074 
5075   /* prefer %MINEDTMP% for buffer and spool files (but not for panic files) */
5076   minedtemp_dir = envvar ("MINEDTMP");
5077   if (minedtemp_dir == NIL_PTR || minedtemp_dir [0] == '\0') {
5078 	minedtemp_dir = temp_dir;
5079   }
5080 
5081   build_string (panic_file, "%s\\$minedsv_%s", temp_dir, username);
5082   build_string (yankie_file, "%s\\$minedbf_%s", minedtemp_dir, username);
5083   build_string (spool_file, "%s\\$minedpr_%s", minedtemp_dir, username);
5084 #endif
5085 }
5086 
5087 
5088 /*======================================================================*\
5089 |*		Main							*|
5090 \*======================================================================*/
5091 
5092 void
emul_mined()5093 emul_mined ()
5094 {
5095   int i;
5096 
5097   for (i = 0; i < 32; i ++) {
5098 	key_map [i] = mined_key_map [i];
5099   }
5100   key_map [erase_char] = DPC;
5101   quit_char = '\034';
5102 
5103   emulation = 'm';
5104   shift_selection = False;
5105   visselect_autocopy = True;
5106   visselect_copydeselect = True;
5107   visselect_autodelete = False;
5108 
5109   emacs_buffer = False;
5110   paste_stay_left = False;
5111   JUSmode = 0;
5112 }
5113 
5114 void
emul_emacs()5115 emul_emacs ()
5116 {
5117   int i;
5118 
5119   for (i = 0; i < 32; i ++) {
5120 	key_map [i] = emacs_key_map [i];
5121   }
5122   key_map [erase_char] = DPC;
5123   quit_char = '\007';		/* ^G */
5124 
5125   emulation = 'e';
5126   shift_selection = False;
5127   visselect_autocopy = True;
5128   visselect_copydeselect = True;
5129   visselect_autodelete = False;
5130 
5131   emacs_buffer = True;
5132   paste_stay_left = False;
5133   JUSmode = 1;
5134 }
5135 
5136 void
emul_WordStar()5137 emul_WordStar ()
5138 {
5139   int i;
5140 
5141   for (i = 0; i < 32; i ++) {
5142 	key_map [i] = ws_key_map [i];
5143   }
5144   key_map [erase_char] = DPC;
5145   quit_char = '\034';
5146 
5147   emulation = 's';
5148   shift_selection = True;
5149   visselect_autocopy = False;
5150   visselect_copydeselect = False;
5151   visselect_autodelete = True;
5152 
5153   emacs_buffer = False;
5154   paste_stay_left = True;
5155   JUSmode = 0;
5156 }
5157 
5158 void
emul_Windows()5159 emul_Windows ()
5160 {
5161   int i;
5162 
5163   for (i = 0; i < 32; i ++) {
5164 	key_map [i] = windows_key_map [i];
5165   }
5166   key_map [erase_char] = DPC;
5167   quit_char = '\034';
5168 
5169   emulation = 'w';
5170   shift_selection = True;
5171   visselect_autocopy = False;
5172   visselect_copydeselect = False;
5173   visselect_autodelete = True;
5174 
5175   emacs_buffer = False;
5176   paste_stay_left = False;
5177   JUSmode = 0;
5178 }
5179 
5180 void
emul_pico()5181 emul_pico ()
5182 {
5183   int i;
5184 
5185   for (i = 0; i < 32; i ++) {
5186 	key_map [i] = pico_key_map [i];
5187   }
5188   key_map [erase_char] = DPC;
5189   quit_char = '\034';
5190 
5191   emulation = 'p';
5192   shift_selection = True;
5193   visselect_autocopy = False;
5194   visselect_copydeselect = False;
5195   visselect_autodelete = True;
5196 
5197   emacs_buffer = True;
5198   paste_stay_left = False;
5199   JUSmode = 1;
5200 }
5201 
5202 void
set_keypad_mined()5203 set_keypad_mined ()
5204 {
5205   keypad_mode = 'm';
5206   shift_selection = False;
5207   visselect_autocopy = True;
5208   visselect_copydeselect = True;
5209   visselect_autodelete = False;
5210 }
5211 
5212 void
set_keypad_shift_selection()5213 set_keypad_shift_selection ()
5214 {
5215   keypad_mode = 'S';
5216   shift_selection = UNSURE;
5217   visselect_copydeselect = True;
5218   visselect_autocopy = False;
5219   visselect_autodelete = True;
5220 }
5221 
5222 void
set_keypad_windows()5223 set_keypad_windows ()
5224 {
5225   keypad_mode = 'w';
5226   shift_selection = True;
5227   visselect_copydeselect = False;
5228   visselect_autocopy = False;
5229   visselect_autodelete = True;
5230 }
5231 
5232 
5233 /*
5234    check if string w matches initial words of string s (esp. a locale prefix)
5235    "ti" "ti_ER" -> True
5236    "ti" "tig_ER" -> False
5237    "ti_ER" "ti_ER.UTF-8" -> True
5238    "aa_E*" "aa_ER" -> True
5239  */
5240 static
5241 FLAG
matchwords(w,s)5242 matchwords (w, s)
5243   char * w;
5244   char * s;
5245 {
5246   if (strisprefix (w, s)) {
5247 	char fini = s [strlen (w)];
5248 	if ((fini >= 'A' && fini <= 'Z') || (fini >= 'a' && fini <= 'z')) {
5249 		return False;
5250 	} else {
5251 		return True;
5252 	}
5253   } else if (w [strlen (w) - 1] == '*' && strncmp (s, w, strlen (w) - 1) == 0) {
5254 	return True;
5255   } else {
5256 	return False;
5257   }
5258 }
5259 
5260 static
5261 FLAG
set_charmap_2(term,charmap_term,charmap_text)5262 set_charmap_2 (term, charmap_term, charmap_text)
5263   FLAG term;
5264   char * charmap_term;
5265   char * charmap_text;
5266 {
5267   if (term) {
5268 	return set_term_encoding (charmap_term, ' ');
5269   } else {
5270 	return set_text_encoding (charmap_text, ' ', "set_charmap_2");
5271   }
5272 }
5273 
5274 static
5275 FLAG
set_charmap(term,charmap)5276 set_charmap (term, charmap)
5277   FLAG term;
5278   char * charmap;
5279 {
5280   if (term) {
5281 	return set_term_encoding (charmap, ' ');
5282   } else {
5283 	return set_text_encoding (charmap, ' ', "set_charmap");
5284   }
5285 }
5286 
5287 #ifdef debug_encoding
5288 
5289 static
5290 FLAG
do_set_charmap_2(function,line,term,charmap_term,charmap_text)5291 do_set_charmap_2 (function, line, term, charmap_term, charmap_text)
5292   char * function;
5293   unsigned int line;
5294   FLAG term;
5295   char * charmap_term;
5296   char * charmap_text;
5297 {
5298   if (term) {
5299 	printf ("set_charmap [%s:%d] %s\n", function, line, charmap_term);
5300   }
5301   return set_charmap_2 (term, charmap_term, charmap_text);
5302 }
5303 
5304 #define set_charmap(term, charmap)	do_set_charmap_2 (__FUNCTION__, __LINE__, term, charmap, charmap)
5305 #define set_charmap_2(term, charmap_term, charmap_text)	do_set_charmap_2 (__FUNCTION__, __LINE__, term, charmap_term, charmap_text)
5306 
5307 #endif
5308 
5309 static
5310 struct {
5311 	char * locale;
5312 	char * quotes;
5313 	char * altquotes;
5314 } quotestyles [] = {
5315 #include "quotes.t"
5316 };
5317 
5318 static
5319 void
set_quote_styles(style,altstyle)5320 set_quote_styles (style, altstyle)
5321   char * style;
5322   char * altstyle;
5323 {
5324   set_quote_style (altstyle);
5325   prev_quote_type = quote_type;
5326   set_quote_style (style);
5327 }
5328 
5329 void
handle_locale_quotes(lang,alt)5330 handle_locale_quotes (lang, alt)
5331   char * lang;
5332   FLAG alt;
5333 {
5334   int i;
5335   char * style = "“”";
5336   char * altstyle = NIL_PTR;
5337 
5338   if (! lang) {
5339 	(void) locale_text_encoding ();
5340 	lang = language_code;
5341 	if (alt == UNSURE && language_preference) {
5342 		/* enable smart quotes if using LANGUAGE= or TEXTLANG= */
5343 		smart_quotes = VALID;
5344 		alt = False;
5345 	}
5346   }
5347 
5348   for (i = 0; i < arrlen (quotestyles); i ++) {
5349 	if (matchwords (quotestyles [i].locale, lang)) {
5350 		style = quotestyles [i].quotes;
5351 		altstyle = quotestyles [i].altquotes;
5352 		if (strcontains (quotestyles [i].locale, "_")) {
5353 			break;
5354 		}
5355 	}
5356   }
5357 
5358   if (alt == UNSURE) {
5359 	set_quote_styles ("\"\"", style);
5360   } else if (alt && altstyle != NIL_PTR) {
5361 	set_quote_styles (altstyle, style);
5362   } else if (altstyle != NIL_PTR) {
5363 	set_quote_styles (style, altstyle);
5364   } else {
5365 	set_quote_style (style);
5366   }
5367   default_quote_type = quote_type;
5368 
5369 #ifdef dont_set_spacing_here
5370   if (matchwords ("fr", lang) && ! matchwords ("fr_CH", lang)) {
5371 	spacing_quotes = True;
5372   }
5373 #endif
5374 }
5375 
5376 static
5377 struct {
5378 	char * locale;
5379 	char * charmap;
5380 	char * charmap_text;
5381 } locmaps [] = {
5382 #include "locales.t"
5383 };
5384 
5385 static
5386 FLAG
handle_locale_encoding(term,encoding)5387 handle_locale_encoding (term, encoding)
5388   FLAG term;
5389   char * encoding;
5390 {
5391   /* determine language-specific text handling features */
5392   if (! term) {
5393 	if (matchwords ("de", language_code)) {
5394 		language_tag = 'g';
5395 	} else if (matchwords ("da", language_code)) {
5396 		language_tag = 'd';
5397 	} else if (matchwords ("fr", language_code)) {
5398 		language_tag = 'f';
5399 	} else if (matchwords ("tr", language_code)
5400 		|| matchwords ("az", language_code)
5401 		/* https://bugzilla.mozilla.org/show_bug.cgi?id=231162#c17 */
5402 		|| matchwords ("crh", language_code)
5403 		|| matchwords ("tt", language_code)
5404 		|| matchwords ("ba", language_code)
5405 		) {
5406 		language_tag = 't';
5407 	} else if (matchwords ("lt", language_code)) {
5408 		language_tag = 'l';
5409 	} else if (matchwords ("nl", language_code)) {
5410 		language_tag = 'n';	/* -> cap. IJsselmeer */
5411 	}
5412   }
5413 
5414   /* detect encoding by locale suffix;
5415      if there is no encoding suffix (starting after "."),
5416      as a fallback, try to interpret the country suffix
5417      (starting with '_' as returned by the functions above)
5418    */
5419   if (strisprefix ("GB", encoding)
5420    || strisprefix ("gb", encoding)
5421    || strisprefix ("EUC-CN", encoding)
5422    || strisprefix ("euccn", encoding)
5423    || strisprefix ("eucCN", encoding)
5424      ) {
5425 	return set_charmap (term, "GB");
5426   } else if (strisprefix ("BIG5", encoding)
5427 	 || strisprefix ("Big5", encoding)
5428 	 || strisprefix ("big5", encoding)
5429 	) {
5430 	return set_charmap (term, "Big5");
5431   } else if (strisprefix ("EUC-TW", encoding)
5432 	 || strisprefix ("euctw", encoding)
5433 	 || strisprefix ("eucTW", encoding)
5434 	) {
5435 	return set_charmap (term, "CNS");
5436   } else if (strisprefix ("UHC", encoding)
5437 	 || strisprefix ("EUC-KR", encoding)
5438 	 || strisprefix ("euckr", encoding)
5439 	 || strisprefix ("eucKR", encoding)
5440 	) {
5441 	return set_charmap (term, "UHC");
5442   } else if (strisprefix ("EUC-JP", encoding)
5443 	 || strisprefix ("eucjp", encoding)
5444 	 || strisprefix ("eucJP", encoding)
5445 	 || strisprefix ("ujis", encoding)
5446 	) {
5447 	return set_charmap (term, "EUC-JP");
5448   } else if (strisprefix ("Shift_JIS", encoding)
5449 	 || strisprefix ("shiftjis", encoding)
5450 	 || strisprefix ("sjis", encoding)
5451 	 || strisprefix ("SJIS", encoding)
5452 	) {
5453 	return set_charmap (term, "CP932");
5454   } else if (strisprefix ("JOHAB", encoding)) {
5455 	return set_charmap (term, "Johab");
5456 
5457   } else if (strisprefix ("@euro", encoding)) {
5458 	if (matchwords ("fy_NL", language_code)) {
5459 		return set_charmap (term, "UTF-8");
5460 	} else if (matchwords ("hsb_DE", language_code)) {
5461 		return set_charmap (term, "ISO-8859-2");
5462 	} else {
5463 		return set_charmap (term, "ISO-8859-15");
5464 	}
5465   } else if (strisprefix ("@tradicional", encoding)) {
5466 	return set_charmap (term, "ISO-8859-15");
5467   } else if (strisprefix ("@devanagari", encoding)) {
5468 	return set_charmap (term, "UTF-8");
5469   } else if (strisprefix ("@latin", encoding)) {
5470 	return set_charmap (term, "UTF-8");
5471   } else if (strisprefix ("@cyrillic", encoding)) {
5472 	if (matchwords ("uz_UZ", language_code)) {
5473 		return set_charmap (term, "UTF-8");
5474 	} else {
5475 		return set_charmap (term, "ISO-8859-5");
5476 	}
5477   } else if (strisprefix ("@iqtelif", encoding)) {
5478 	return set_charmap (term, "UTF-8");
5479   } else if (strisprefix ("iso8859", encoding)
5480 	|| strisprefix ("ISO8859", encoding)
5481 	|| strisprefix ("iso-8859", encoding)
5482 	|| strisprefix ("ISO-8859", encoding)
5483 	  ) {
5484 	if (encoding [3] == '-') {
5485 		encoding += 8;
5486 	} else {
5487 		encoding += 7;
5488 	}
5489 	if (* encoding == '-' || * encoding == '_') {
5490 		encoding ++;
5491 	}
5492 	if (streq ("1", encoding)) {
5493 		return set_charmap (term, "ISO-8859-1");
5494 	} else if (streq ("5", encoding)) {
5495 		return set_charmap (term, "ISO-8859-5");
5496 	} else if (streq ("6", encoding)) {
5497 		return set_charmap_2 (term, "ISO-8859-6", "MacArabic");
5498 	} else if (streq ("7", encoding)) {
5499 		return set_charmap (term, "ISO-8859-7");
5500 	} else if (streq ("8", encoding)) {
5501 		return set_charmap_2 (term, "ISO-8859-8", "CP1255");
5502 	} else if (streq ("15", encoding)) {
5503 		return set_charmap (term, "ISO-8859-15");
5504 
5505 	} else if (streq ("2", encoding)) {
5506 		return set_charmap (term, "ISO-8859-2");
5507 	} else if (streq ("3", encoding)) {
5508 		return set_charmap (term, "ISO-8859-3");
5509 	} else if (streq ("4", encoding)) {
5510 		return set_charmap (term, "ISO-8859-4");
5511 	} else if (streq ("9", encoding)) {
5512 		return set_charmap (term, "ISO-8859-9");
5513 	} else if (streq ("10", encoding)) {
5514 		return set_charmap (term, "ISO-8859-10");
5515 	} else if (streq ("13", encoding)) {
5516 		return set_charmap (term, "ISO-8859-13");
5517 	} else if (streq ("14", encoding)) {
5518 		return set_charmap (term, "ISO-8859-14");
5519 	} else if (streq ("16", encoding)) {
5520 		return set_charmap (term, "ISO-8859-16");
5521 	} else if (streq ("11", encoding)) {
5522 		return set_charmap (term, "TIS");
5523 	}
5524   } else if (strisprefix ("koi8t", encoding)) {
5525 	return set_charmap (term, "KOI8-T");
5526   } else if (strisprefix ("KOI8-T", encoding)) {
5527 	return set_charmap (term, "KOI8-T");
5528   } else if (strisprefix ("koi8r", encoding)) {
5529 	return set_charmap_2 (term, "KOI8-R", "KOI8-RU");
5530   } else if (strisprefix ("KOI8-R", encoding)) {
5531 	return set_charmap_2 (term, "KOI8-R", "KOI8-RU");
5532   } else if (strisprefix ("koi8u", encoding)) {
5533 	return set_charmap_2 (term, "KOI8-U", "KOI8-RU");
5534   } else if (strisprefix ("KOI8-U", encoding)) {
5535 	return set_charmap_2 (term, "KOI8-U", "KOI8-RU");
5536   } else if (strisprefix ("koi", encoding)) {
5537 	return set_charmap (term, "KOI8-RU");
5538   } else if (strisprefix ("tcvn", encoding)) {
5539 	return set_charmap (term, "TCVN");
5540   } else if (strisprefix ("viscii", encoding)) {
5541 	return set_charmap (term, "VISCII");
5542   } else if (strisprefix ("tis", encoding)
5543 	|| strisprefix ("TIS", encoding)
5544 	) {
5545 	return set_charmap (term, "TIS");
5546   } else if (strisprefix ("roman", encoding)) {
5547 	return set_charmap (term, "MacRoman");
5548   } else if (strisprefix ("cp1252", encoding)
5549 	|| strisprefix ("CP1252", encoding)
5550 	) {
5551 	return set_charmap (term, "CP1252");
5552   } else if (strisprefix ("cp1251", encoding)
5553 	|| strisprefix ("CP1251", encoding)
5554 	) {
5555 	return set_charmap (term, "CP1251");
5556   } else if (strisprefix ("cp850", encoding)
5557 	|| strisprefix ("CP850", encoding)
5558 	) {
5559 	return set_charmap (term, "CP850");
5560   } else if (strisprefix ("cp1255", encoding)
5561 	|| strisprefix ("CP1255", encoding)
5562 	) {
5563 	return set_charmap (term, "CP1255");
5564   } else if (strisprefix ("cp1131", encoding)
5565 	|| strisprefix ("CP1131", encoding)
5566 	) {
5567 	return set_charmap (term, "CP1131");
5568   } else if (strisprefix ("georgianps", encoding)) {
5569 	return set_charmap (term, "Georgian-PS");
5570   } else if (strisprefix ("pt154", encoding)) {
5571 	return set_charmap (term, "PT154");
5572   } else if (strisprefix ("armscii", encoding)
5573 	|| strisprefix ("ARMSCII", encoding)
5574 	) {
5575 	return set_charmap (term, "ARMSCII");
5576   } else if (strisprefix ("utf8", encoding)
5577 	 || strisprefix ("UTF-8", encoding)
5578 	) {
5579 	return set_charmap (term, "UTF-8");
5580 
5581   } else if (strisprefix ("EBCDIC", encoding)
5582 	|| strisprefix ("cp1047", encoding)
5583 	|| strisprefix ("CP1047", encoding)
5584 	) {
5585 	return set_charmap (term, "CP1047");
5586 
5587   } else if (streq ("EUC", encoding)
5588 	|| strisprefix ("euc", encoding)
5589 	) {
5590 	if (strisprefix ("zh_TW", language_code)) {
5591 		return set_charmap (term, "CNS");
5592 	} else if (strisprefix ("zh", language_code)) {
5593 		return set_charmap (term, "GB");
5594 	} else if (strisprefix ("ja", language_code)) {
5595 		return set_charmap (term, "EUC-JP");
5596 	} else if (strisprefix ("ko", language_code)) {
5597 		return set_charmap (term, "EUC-KR");
5598 	}
5599 
5600   } else if (encoding [0] != '\0' && set_charmap (term, encoding)) {
5601 	/* has been set to other encoding suffix */
5602   } else {
5603     /* handle locale shortcut names that imply an encoding */
5604     int i;
5605     for (i = arrlen (locmaps) - 1; i >= 0; i --) {
5606 	if (matchwords (locmaps [i].locale, language_code)) {
5607 		if (! term && locmaps [i].charmap_text) {
5608 			return set_charmap (False, locmaps [i].charmap_text);
5609 		} else {
5610 			return set_charmap (term, locmaps [i].charmap);
5611 		}
5612 	}
5613     }
5614   }
5615 
5616   return False;
5617 }
5618 
5619 
5620 static
5621 void
eval_options(minedopt,command_line)5622 eval_options (minedopt, command_line)
5623   char * minedopt;
5624   FLAG command_line;
5625 {
5626   FLAG plus_opt = False;	/* set if options start with '+' */
5627   FLAG Cflag = False;	/* -C interacts with -E for compatibility */
5628 
5629   while (* minedopt != '\0') {
5630     switch (* minedopt) {
5631 	case '+':
5632 		plus_opt = True;
5633 		break;
5634 	case '-':
5635 		plus_opt = False;
5636 		minedopt ++;
5637 		if (* minedopt == '-') {
5638 			restricted = True;
5639 		} else {
5640 			minedopt --;
5641 		}
5642 		break;
5643 	case ' ':
5644 		break;
5645 	case 'M':
5646 		if (* (minedopt + 1) == ':') {
5647 			minedopt ++;
5648 			if (plus_opt) {
5649 				MENU = 1;
5650 				use_file_tabs = True;
5651 			} else {
5652 				use_file_tabs = False;
5653 			}
5654 			break;
5655 		}
5656 		if (plus_opt) {
5657 			if (MENU) {
5658 				if (quickmenu) {
5659 					/*MENU ++;*/
5660 					use_file_tabs = True;
5661 				}
5662 				quickmenu = True;
5663 			} else {
5664 				MENU = 1;
5665 			}
5666 		} else {
5667 			if (use_file_tabs) {
5668 				use_file_tabs = False;
5669 			} else if (MENU) {
5670 				MENU = 0;
5671 			} else {
5672 				quickmenu = False;
5673 			}
5674 		}
5675 		break;
5676 	case 'H':
5677 		mark_HTML = plus_opt;
5678 		break;
5679 	case '@':
5680 		if (plus_opt) {
5681 			groom_stat = True;
5682 		} else {
5683 			groom_info_files = False;
5684 			groom_info_file = False;
5685 		}
5686 		break;
5687 	case '*':
5688 		if (plus_opt) {
5689 			if (use_mouse) {
5690 				/* enable mouse move reporting without button pressed
5691 				 (for menus) */
5692 				if (use_mouse_anymove_inmenu) {
5693 					use_mouse_anymove_always = True;
5694 				} else {
5695 					use_mouse_anymove_inmenu = True;
5696 				}
5697 			} else {
5698 				use_mouse = True;
5699 			}
5700 		} else {
5701 			if (use_mouse_anymove_inmenu) {
5702 				/* disable mouse move reporting w/o button */
5703 				use_mouse_anymove_inmenu = False;
5704 			} else {
5705 				/* disable mouse altogether */
5706 				use_mouse = False;
5707 			}
5708 		}
5709 		break;
5710 	case '~':
5711 		minedopt ++;
5712 		if (* minedopt == '=') {
5713 			minedopt ++;
5714 			sethomedir (minedopt);
5715 			homedir_selected = True;
5716 			while (* minedopt) {
5717 				minedopt ++;
5718 			}
5719 		}
5720 		break;
5721 	case 'L':
5722 		minedopt ++;
5723 		minedopt = scan_int (minedopt, & wheel_scroll);
5724 		minedopt --;
5725 		break;
5726 	case 'v':
5727 		viewonly_mode = True;
5728 		break;
5729 	case 'P':
5730 		if (plus_opt) {
5731 			hide_passwords = False;
5732 		} else {
5733 			hide_passwords = True;
5734 		}
5735 		break;
5736 	case 'p':
5737 		if (plus_opt) {
5738 			proportional = True;
5739 		} else {
5740 			paradisp = True;
5741 		}
5742 		break;
5743 	case 'r':
5744 		minedopt ++;
5745 		if (* minedopt == '?') {
5746 			if (plus_opt) {	/* +r?	CRLF for new files */
5747 				newfile_lineend = lineend_CRLF;
5748 			} else {	/* -r?	LF for new files */
5749 				newfile_lineend = lineend_LF;
5750 			}
5751 		} else {
5752 			minedopt --;
5753 			if (plus_opt) {	/* +r	convert LF to CRLF */
5754 				lineends_LFtoCRLF = True;
5755 			} else {	/* -r	convert CRLF to LF */
5756 				lineends_CRLFtoLF = True;
5757 			}
5758 		}
5759 		break;
5760 	case 'R':
5761 		if (plus_opt) {	/* +R	handle CR */
5762 			lineends_detectCR = True;
5763 		} else {	/* -R	convert CR to LF */
5764 			lineends_detectCR = True;
5765 			lineends_CRtoLF = True;
5766 		}
5767 		break;
5768 	case 'Q':
5769 		minedopt ++;
5770 		if (* minedopt >= '0' && * minedopt <= '9') {
5771 			if (plus_opt) {
5772 				splash_level = * minedopt - '0';
5773 			} else {
5774 				menumargin = * minedopt - '0';
5775 			}
5776 		} else if (* minedopt == 'Q') {
5777 			explicit_selection_style = command_line;
5778 			use_stylish_menu_selection = True;
5779 		} else if (* minedopt == 'q') {
5780 			explicit_selection_style = command_line;
5781 			use_stylish_menu_selection = False;
5782 		} else if (* minedopt == 'a') {
5783 			explicit_border_style = command_line;
5784 			use_ascii_graphics = True;
5785 			use_vt100_block_graphics = False;
5786 			menu_border_style = 'r';
5787 		} else if (* minedopt == 'v') {
5788 			explicit_border_style = command_line;
5789 			use_vt100_block_graphics = True;
5790 			use_ascii_graphics = False;
5791 		} else if (* minedopt == 'p' || * minedopt == 'P') {
5792 			menu_border_style = * minedopt;
5793 			explicit_border_style = command_line;
5794 		} else if (* minedopt == 'b') {
5795 			full_menu_bg = False;
5796 		} else if (* minedopt == 'B') {
5797 			full_menu_bg = True;
5798 			if (menu_border_style == '@') {
5799 				menu_border_style = 'p';
5800 			}
5801 		} else {
5802 			menu_border_style = * minedopt;
5803 			if (menu_border_style != 'd') {
5804 				explicit_border_style = command_line;
5805 			}
5806 			if (menu_border_style == '@') {
5807 				full_menu_bg = False;
5808 			}
5809 		}
5810 		break;
5811 	case 'O':
5812 		use_script_colour = plus_opt;
5813 		break;
5814 	case 'f':
5815 		if (menu_border_style == 's') {
5816 			if (use_vt100_block_graphics) {
5817 				use_ascii_graphics = True;
5818 				menu_border_style = 'r';	/* by option */
5819 				use_vt100_block_graphics = False;
5820 			} else {
5821 				use_vt100_block_graphics = True;
5822 			}
5823 		} else {
5824 			menu_border_style = 's';
5825 		}
5826 		use_stylish_menu_selection = False;
5827 		fine_scrollbar = False;
5828 		break;
5829 	case 'F':
5830 		if (plus_opt) {
5831 			if (very_limited_marker_font) {
5832 				very_limited_marker_font = False;
5833 			} else {
5834 				limited_marker_font = False;
5835 			}
5836 		} else {
5837 			if (limited_marker_font) {
5838 				very_limited_marker_font = True;
5839 			} else {
5840 				limited_marker_font = True;
5841 			}
5842 		}
5843 		break;
5844 	case 'o':
5845 		minedopt ++;
5846 		explicit_scrollbar_style = command_line;
5847 		switch (* minedopt) {
5848 		case '0':
5849 			disp_scrollbar = False;
5850 			scrollbar_width = 0;
5851 			break;
5852 		case '1':
5853 			disp_scrollbar = True;
5854 			fine_scrollbar = False;
5855 			scrollbar_width = 1;
5856 			break;
5857 		case '2':
5858 			disp_scrollbar = True;
5859 			fine_scrollbar = True;
5860 			scrollbar_width = 1;
5861 			break;
5862 		case '8':
5863 			update_scrollbar_lazy = False;
5864 			break;
5865 		case '9':
5866 			update_scrollbar_lazy = True;
5867 			break;
5868 		case 'o':
5869 			old_scrollbar_clickmode = True;	/* old left/right click semantics */
5870 			break;
5871 		default:
5872 			minedopt --;
5873 			/* disable/enable scrollbar */
5874 			if (plus_opt) {
5875 				disp_scrollbar = True;
5876 				scrollbar_width = 1;
5877 			} else {
5878 				disp_scrollbar = False;
5879 				scrollbar_width = 0;
5880 			}
5881 		}
5882 		break;
5883 	case 'c':
5884 		if (plus_opt) {
5885 			combining_screen = True;
5886 			combining_mode = True;
5887 			combining_screen_selected = True;
5888 		} else {
5889 			if (combining_mode_disabled) {
5890 				combining_screen = False;
5891 			} else {
5892 				combining_mode = False;
5893 				combining_mode_disabled = True;
5894 			}
5895 		}
5896 		break;
5897 	case 'C':
5898 		if (plus_opt) {
5899 			cjk_term = True;
5900 			/* output CJK encoded characters transparently */
5901 			if (suppress_unknown_cjk) {
5902 				suppress_unknown_cjk = False;
5903 			} else if (suppress_invalid_cjk) {
5904 				suppress_invalid_cjk = False;
5905 			} else {
5906 				suppress_extended_cjk = False;
5907 			}
5908 			/* output non-Unicode codes transparently */
5909 			suppress_non_BMP = NOT_VALID;
5910 			if (suppress_EF) {
5911 				suppress_EF = False;
5912 			} else if (suppress_surrogates) {
5913 				suppress_surrogates = False;
5914 			} else {
5915 				suppress_non_Unicode = False;
5916 			}
5917 		} else {
5918 			Cflag = True;
5919 		}
5920 		break;
5921 	case 'U':
5922 		if (plus_opt) {
5923 			if (U_mode_set) {
5924 				bidi_screen = True;
5925 				joining_screen = True;
5926 				poormansbidi = False;
5927 				/* disable scrollbar to prevent interference */
5928 				disp_scrollbar = False;
5929 				scrollbar_width = 0;
5930 			} else {
5931 				utf8_screen = True;
5932 				utf8_input = True;
5933 				combining_screen = True;
5934 				combining_mode = True;
5935 				U_mode_set = True;
5936 				cjk_term = False;
5937 				mapped_term = False;
5938 			}
5939 		} else if (bidi_screen) {
5940 			joining_screen = False;
5941 		} else if (utf8_input) {
5942 			utf8_screen = False;
5943 			utf8_input = False;
5944 			combining_screen = False;
5945 			combining_mode = False;
5946 		} else {
5947 			utf8_screen = True;
5948 			utf8_input = True;
5949 			combining_screen = True;
5950 			combining_mode = True;
5951 			cjk_term = False;
5952 			mapped_term = False;
5953 		}
5954 		break;
5955 	case 'u':
5956 		auto_detect = False;
5957 		if (plus_opt) {
5958 			(void) set_text_encoding (NIL_PTR, 'L', "+u");
5959 			utf8_lineends = False;
5960 		} else {
5961 			(void) set_text_encoding (NIL_PTR, 'U', "-u");
5962 			text_encoding_selected = True;
5963 		}
5964 		break;
5965 	case 'l':
5966 		auto_detect = False;
5967 		(void) set_text_encoding (NIL_PTR, 'L', "-l");
5968 		text_encoding_selected = True;
5969 		break;
5970 	case 'E':
5971 		minedopt ++;
5972 		if (* minedopt == '?') {
5973 			if (plus_opt) {
5974 				only_detect_terminal_encoding = True;
5975 			} else {
5976 				only_detect_text_encoding = True;
5977 			}
5978 		} else if (* minedopt == 'u') {
5979 			pastebuf_utf8 = True;
5980 		} else if (* minedopt == 'U' || * minedopt == 'L') {
5981 			if (plus_opt) {
5982 				cjk_term = False;
5983 				mapped_term = False;
5984 				if (* minedopt == 'U') {
5985 					utf8_screen = True;
5986 					utf8_input = True;
5987 					combining_screen = True;
5988 					combining_mode = True;
5989 				} else {
5990 					utf8_screen = False;
5991 					utf8_input = False;
5992 					combining_screen = False;
5993 					combining_mode = False;
5994 				}
5995 				cjk_term = False;
5996 				mapped_term = False;
5997 				term_encoding_selected = True;
5998 			} else {
5999 				if (set_text_encoding (NIL_PTR, * minedopt, "-EU/L")) {
6000 					auto_detect = False;
6001 					text_encoding_selected = True;
6002 				}
6003 			}
6004 		} else if (* minedopt == '.') {
6005 			minedopt ++;
6006 			if (handle_locale_encoding (plus_opt, minedopt)) {
6007 				if (plus_opt) {
6008 					term_encoding_selected = True;
6009 				} else {
6010 					auto_detect = False;
6011 					text_encoding_selected = True;
6012 				}
6013 			} else {
6014 				if (plus_opt) {
6015 					errprintf ("Unknown terminal encoding %s\n", minedopt);
6016 				} else {
6017 					errprintf ("Unknown text encoding %s\n", minedopt);
6018 				}
6019 				sleep (1);
6020 
6021 			}
6022 			while (* minedopt) {
6023 				minedopt ++;
6024 			}
6025 		} else if (* minedopt == '=') {
6026 			minedopt ++;
6027 			if (set_charmap (plus_opt, minedopt)) {
6028 				if (plus_opt) {
6029 					term_encoding_selected = True;
6030 				} else {
6031 					auto_detect = False;
6032 					text_encoding_selected = True;
6033 				}
6034 			} else {
6035 				if (plus_opt) {
6036 					errprintf ("Unknown terminal charmap %s\n", minedopt);
6037 				} else {
6038 					errprintf ("Unknown text charmap %s\n", minedopt);
6039 				}
6040 				sleep (1);
6041 			}
6042 			while (* minedopt) {
6043 				minedopt ++;
6044 			}
6045 		} else if (* minedopt == ':') {
6046 			if (set_charmap (plus_opt, minedopt)) {
6047 				if (plus_opt) {
6048 					term_encoding_selected = True;
6049 				} else {
6050 					auto_detect = False;
6051 					text_encoding_selected = True;
6052 				}
6053 			} else {
6054 				if (plus_opt) {
6055 					errprintf ("Unknown terminal encoding flag %s\n", minedopt + 1);
6056 				} else {
6057 					errprintf ("Unknown text encoding flag %s\n", minedopt + 1);
6058 				}
6059 				sleep (1);
6060 			}
6061 			minedopt ++;
6062 			if (* minedopt) {
6063 				minedopt ++;
6064 			}
6065 			if (* minedopt) {
6066 				minedopt ++;
6067 			}
6068 		} else if (* minedopt == '-' || * minedopt == '\0') {
6069 			if (! plus_opt) {
6070 				auto_detect = False;
6071 			}
6072 		} else {
6073 			char enctag = * minedopt;
6074 			switch (enctag) {
6075 			case 'g':	if (plus_opt || Cflag) {
6076 						gb18030_term = False;
6077 						suppress_extended_cjk = True;
6078 					}
6079 					enctag = 'G';
6080 					break;
6081 			case 'j':	if (plus_opt || Cflag) {
6082 						euc3_term = False;
6083 						suppress_extended_cjk = True;
6084 					}
6085 					enctag = 'J';
6086 					break;
6087 			case 'c':	if (plus_opt || Cflag) {
6088 						euc4_term = False;
6089 						suppress_extended_cjk = True;
6090 					}
6091 					enctag = 'C';
6092 					break;
6093 			}
6094 			if (plus_opt || Cflag) {
6095 				if (set_term_encoding (NIL_PTR, enctag)) {
6096 					term_encoding_selected = True;
6097 				} else {
6098 					errprintf ("Unknown terminal encoding tag %c\n", * minedopt);
6099 					sleep (1);
6100 					break;
6101 				}
6102 			}
6103 			if (! plus_opt) {
6104 				if (set_text_encoding (NIL_PTR, enctag, "-E")) {
6105 					auto_detect = False;
6106 					text_encoding_selected = True;
6107 				} else {
6108 					errprintf ("Unknown text encoding tag %c\n", * minedopt);
6109 					sleep (1);
6110 					break;
6111 				}
6112 			}
6113 		}
6114 		break;
6115 	case 'b':
6116 		if (plus_opt) {
6117 			minedopt ++;
6118 			if (* minedopt == '-' || * minedopt == 'o') {
6119 				backup_mode = '\0';
6120 			} else if (* minedopt == '\0') {
6121 				backup_mode = 'a';
6122 			} else if (* minedopt == '=') {
6123 				minedopt ++;
6124 				if (minedopt [0] == '~'
6125 					&& (minedopt [1] == '/' || minedopt [1] == '\0')) {
6126 					char expandedname [maxFILENAMElen];
6127 					strcpy (expandedname, "");
6128 					strappend (expandedname, gethomedir (), maxFILENAMElen);
6129 					minedopt ++;
6130 					strip_trailingslash (expandedname);
6131 					strappend (expandedname, minedopt, maxFILENAMElen);
6132 					backup_directory = dupstr (expandedname);
6133 				} else {
6134 					backup_directory = dupstr (minedopt);
6135 				}
6136 				return;
6137 			} else {
6138 				backup_mode = * minedopt;
6139 			}
6140 		} else {
6141 			if (poormansbidi) {
6142 				poormansbidi = False;
6143 			} else {
6144 				poormansbidi = True;
6145 				bidi_screen = False;
6146 			}
6147 		}
6148 		break;
6149 	case 'z':
6150 		/* file chooser sort options */
6151 		minedopt ++;
6152 		if (* minedopt == 'x') {
6153 			sort_by_extension = plus_opt;
6154 		} else if (* minedopt == 'd') {
6155 			sort_dirs_first = plus_opt;
6156 		}
6157 		break;
6158 	case 'B':
6159 		if (plus_opt) {
6160 			minedopt ++;
6161 			if (* minedopt == 'p') {
6162 				plain_BS = True;
6163 			}
6164 		} else {
6165 			/*
6166 			key_map ['\010'] = DPC;
6167 			key_map ['\177'] = DCC;
6168 			*/
6169 			key_map ['\010'] = LFkey;
6170 			key_map ['\177'] = DPC;
6171 		}
6172 		break;
6173 	case 'K':
6174 		if (plus_opt) {
6175 			/* obsolete since 2000.15 as this is the default */
6176 			enforce_keymap = True;
6177 		} else {
6178 			minedopt ++;
6179 			if (* minedopt == '=') {
6180 				minedopt ++;
6181 				if (setKEYMAP (minedopt)) {
6182 					explicit_keymap = True;
6183 				} else {
6184 					errprintf ("Unknown input method %s\n", minedopt);
6185 					sleep (1);
6186 				}
6187 				return;
6188 			} else {
6189 				selection_space = * minedopt;
6190 			}
6191 		}
6192 		break;
6193 	case '[':
6194 		rectangular_paste_flag = plus_opt;
6195 		break;
6196 	case 'D':
6197 		configure_xterm_keyboard = plus_opt;
6198 		break;
6199 	case 'w':
6200 		if (wordnonblank) {
6201 			wordnonblank = False;
6202 		} else {
6203 			wordnonblank = True;
6204 		}
6205 		break;
6206 	case 'Z':
6207 		minedopt ++;
6208 		switch (* minedopt) {
6209 		case '_':
6210 			strop_style = * minedopt;
6211 			break;
6212 		case 'Z':
6213 			if (plus_opt) {
6214 				lowcapstrop = True;
6215 				dispunstrop = True;
6216 			} else {
6217 				lowcapstrop = False;
6218 				dispunstrop = False;
6219 			}
6220 			strop_selected = True;
6221 			break;
6222 		}
6223 		break;
6224 	case 'q':
6225 		smart_quotes = VALID;
6226 		minedopt ++;
6227 		if (* minedopt == '=' || * minedopt == ':') {
6228 			minedopt ++;
6229 			if (* minedopt >= 'A' && * minedopt <= 'z') {
6230 				handle_locale_quotes (minedopt, plus_opt);
6231 			} else if (* minedopt) {
6232 				set_quote_style (minedopt);
6233 				default_quote_type = quote_type;
6234 			} else {
6235 				handle_locale_quotes (NIL_PTR, plus_opt);
6236 			}
6237 			return;
6238 		} else {
6239 			minedopt --;
6240 			handle_locale_quotes (NIL_PTR, plus_opt);
6241 		}
6242 		break;
6243 	case 'a':
6244 		append_flag = True;
6245 		break;
6246 	case 'j':
6247 		if (plus_opt) {
6248 			minedopt ++;
6249 			if (* minedopt == '=') {
6250 				minedopt ++;
6251 				if (* minedopt >= '0' && * minedopt <= '2') {
6252 					JUSlevel = * minedopt - '0';
6253 				}
6254 			} else {
6255 				minedopt --;
6256 				if (JUSlevel < 2) {
6257 					JUSlevel ++;
6258 				}
6259 			}
6260 		} else if (JUSlevel == 1) {
6261 			JUSlevel = 2;
6262 		} else {
6263 			JUSlevel = 1;
6264 		}
6265 		break;
6266 	case 'J':
6267 		JUSlevel = 2;
6268 		break;
6269 	case 'T':
6270 		if (plus_opt) {
6271 			tab_right = True;
6272 		} else {
6273 			tab_left = True;
6274 		}
6275 		break;
6276 	case 'V':
6277 		minedopt ++;
6278 		if (* minedopt == ':' || * minedopt == '=') {
6279 			minedopt ++;
6280 			if (* minedopt == 'k') {
6281 				visselect_keeponsearch = plus_opt;
6282 			} else if (* minedopt == 'c') {
6283 				visselect_autocopy = plus_opt;
6284 				visselect_copydeselect = plus_opt;
6285 			}
6286 		} else {
6287 			minedopt --;
6288 			if (plus_opt) {
6289 				if (paste_stay_left) {
6290 					paste_stay_left = False;
6291 				} else {
6292 					emacs_buffer = True;
6293 				}
6294 			} else {
6295 				if (! paste_stay_left) {
6296 					paste_stay_left = True;
6297 				} else {
6298 					emacs_buffer = False;
6299 				}
6300 			}
6301 		}
6302 		break;
6303 	case 's':
6304 		page_stay = True;
6305 		break;
6306 	case 'S':
6307 		page_scroll = True;
6308 		break;
6309 	case 'x':
6310 		xprot = exeprot;
6311 		break;
6312 	case 'X':
6313 		use_window_title_query = use_window_title;
6314 		use_window_title = plus_opt;
6315 		break;
6316 	case 'd':
6317 		minedopt ++;
6318 		if (* minedopt == '-') {
6319 			display_delay = -1;
6320 		} else if (* minedopt >= '0' && * minedopt <= '9') {
6321 			display_delay = (int) * minedopt - (int) '0';
6322 		} else {
6323 			minedopt --;
6324 		}
6325 		break;
6326 	case '':
6327 		minedopt ++;
6328 		if (* minedopt >= '0' && * minedopt <= '9') {
6329 			cursor_style = (int) * minedopt - (int) '0';
6330 		} else {
6331 			minedopt --;
6332 		}
6333 		break;
6334 	case '4':
6335 		if (! tabsize_selected) {
6336 			tabsize = 4;
6337 			tabsize_selected = cmdline_selected;
6338 			expand_tabs = plus_opt;
6339 		}
6340 		break;
6341 	case '2':
6342 		if (! tabsize_selected) {
6343 			tabsize = 2;
6344 			tabsize_selected = cmdline_selected;
6345 			expand_tabs = plus_opt;
6346 		}
6347 		break;
6348 	case '8':
6349 		if (! tabsize_selected) {
6350 			tabsize = 8;
6351 			tabsize_selected = cmdline_selected;
6352 			expand_tabs = plus_opt;
6353 		}
6354 		break;
6355 	case '?':
6356 		minedopt ++;
6357 		if (* minedopt == 'c') {	/* enable char info */
6358 			if (plus_opt) {
6359 				always_disp_code = True;
6360 				always_disp_fstat = False;
6361 				if (! disp_Han_full) {
6362 					always_disp_Han = False;
6363 				}
6364 			} else {
6365 				always_disp_code = False;
6366 			}
6367 		} else if (* minedopt == 's') {	/* enable char/script info */
6368 			if (plus_opt) {
6369 				disp_scriptname = True;
6370 				/* also enable char info: */
6371 				always_disp_code = True;
6372 				always_disp_fstat = False;
6373 				if (! disp_Han_full) {
6374 					always_disp_Han = False;
6375 				}
6376 			} else {
6377 				disp_scriptname = False;
6378 			}
6379 		} else if (* minedopt == 'n') {	/* enable char/name info */
6380 			if (plus_opt) {
6381 				disp_charname = True;
6382 				/* also enable char info: */
6383 				always_disp_code = True;
6384 				always_disp_fstat = False;
6385 				if (! disp_Han_full) {
6386 					always_disp_Han = False;
6387 				}
6388 			} else {
6389 				disp_charname = False;
6390 			}
6391 		} else if (* minedopt == 'q') {	/* enable named seq info */
6392 			if (plus_opt) {
6393 				disp_charseqname = True;
6394 				/* also enable char info: */
6395 				always_disp_code = True;
6396 				always_disp_fstat = False;
6397 				if (! disp_Han_full) {
6398 					always_disp_Han = False;
6399 				}
6400 			} else {
6401 				disp_charseqname = False;
6402 			}
6403 		} else if (* minedopt == 'd') {	/* enable char/decomposition info */
6404 			if (plus_opt) {
6405 				disp_decomposition = True;
6406 				disp_charname = False;
6407 				/* also enable char info: */
6408 				always_disp_code = True;
6409 				always_disp_fstat = False;
6410 				if (! disp_Han_full) {
6411 					always_disp_Han = False;
6412 				}
6413 			} else {
6414 				disp_decomposition = False;
6415 			}
6416 		} else if (* minedopt == 'm') {	/* enable char/menmos info */
6417 			if (plus_opt) {
6418 				disp_mnemos = True;
6419 				disp_charname = False;
6420 				/* also enable char info: */
6421 				always_disp_code = True;
6422 				always_disp_fstat = False;
6423 				if (! disp_Han_full) {
6424 					always_disp_Han = False;
6425 				}
6426 			} else {
6427 				disp_mnemos = False;
6428 			}
6429 		} else if (* minedopt == 'f') {	/* enable file info */
6430 			if (plus_opt) {
6431 				always_disp_fstat = True;
6432 				always_disp_code = False;
6433 				if (! disp_Han_full) {
6434 					always_disp_Han = False;
6435 				}
6436 			} else {
6437 				always_disp_fstat = False;
6438 			}
6439 		} else if (* minedopt == 'h') {	/* enable popup Han info */
6440 			if (plus_opt) {
6441 				always_disp_Han = True;
6442 				disp_Han_full = True;
6443 			} else {
6444 				disp_Han_full = False;
6445 			}
6446 		} else if (* minedopt == 'x') {	/* enable short Han info */
6447 			if (plus_opt) {
6448 				always_disp_Han = True;
6449 				disp_Han_full = False;
6450 				always_disp_fstat = False;
6451 				always_disp_code = False;
6452 			} else {
6453 				always_disp_Han = False;
6454 			}
6455 		}
6456 		break;
6457 	case '#':
6458 		dark_term = plus_opt;
6459 		break;
6460 	case 'W':
6461 		emul_WordStar ();
6462 		break;
6463 	case 'e':
6464 		if (plus_opt) {
6465 			minedopt ++;
6466 			switch (* minedopt) {
6467 			case 'e':	emul_emacs (); break;
6468 			case 's':	emul_WordStar (); break;
6469 			case 'p':	emul_pico (); break;
6470 			case 'W':	newfile_lineend = lineend_CRLF;
6471 					prefer_comspec = True;
6472 					/*FALLTHROUGH*/
6473 			case 'w':	emul_Windows (); break;
6474 			case 'm':	emul_mined (); break;
6475 			default:	errprintf ("Unknown emulation mode %c\n", * minedopt);
6476 					sleep (1);
6477 			}
6478 		} else {
6479 			emul_emacs ();
6480 		}
6481 		break;
6482 	case 'k':
6483 		if (plus_opt) {
6484 			use_appl_keypad = True;
6485 		} else {
6486 			minedopt ++;
6487 			switch (* minedopt) {
6488 			case 'c':	small_home_selection = True;
6489 					break;
6490 			case 'C':	home_selection = True;
6491 					break;
6492 			case 'm':	set_keypad_mined ();
6493 					break;
6494 			case 's':
6495 			case 'S':	set_keypad_shift_selection ();
6496 					break;
6497 			case 'w':	set_keypad_windows ();
6498 					break;
6499 			default:	minedopt --;
6500 					if (mined_keypad) {
6501 						mined_keypad = False;
6502 					} else {
6503 						mined_keypad = True;
6504 					}
6505 			}
6506 		}
6507 		break;
6508 	case 't':	/* deprecated; 2012.21 compatibility */
6509 		if (plus_opt) {
6510 			if (shift_selection == True) {
6511 				set_keypad_shift_selection ();
6512 			} else {
6513 				set_keypad_windows ();
6514 			}
6515 		} else {
6516 			set_keypad_mined ();
6517 		}
6518 		break;
6519 	case 'n':
6520 		minedopt ++;
6521 		if (* minedopt == 'c') {
6522 			suppress_colour = True;
6523 			bw_term = True;
6524 		}
6525 		break;
6526 	case '':
6527 		/* viewing mined help file */
6528 		viewing_help = True;	/* also triggers mark_HTML = True */
6529 		viewonly_mode = True;
6530 		restricted = True;
6531 		ext_status = ++ minedopt;
6532 		return;
6533 	case '_':
6534 		ext_status = ++ minedopt;
6535 		return;
6536 	case '/':
6537 		minedopt ++;
6538 		inisearch = minedopt;
6539 		return;
6540 	case '':
6541 		minedopt ++;
6542 		if (* minedopt) {
6543 			filtering_read = plus_opt;
6544 			free_space (filter_read);
6545 			filter_read = dupstr (minedopt);
6546 		}
6547 		return;
6548 	case '':
6549 		minedopt ++;
6550 		if (* minedopt) {
6551 			filtering_write = plus_opt;
6552 			free_space (filter_write);
6553 			filter_write = dupstr (minedopt);
6554 		}
6555 		return;
6556 	default:
6557 		errprintf ("Unknown option %c\n", * minedopt);
6558 		if (command_line) {
6559 			sleep (1);
6560 		}
6561 		break;
6562     }
6563     if (* minedopt != '\0') {
6564 	minedopt ++;
6565     }
6566   }
6567 }
6568 
6569 
6570 static int mined_argc;
6571 static char * * mined_argv;
6572 static int initlini = 0;
6573 
6574 static
6575 int
eval_commandline()6576 eval_commandline ()
6577 {
6578   char * minedopt;
6579   int argi = 1;
6580   FLAG goon = True;
6581 
6582   if (mined_argv [0]) {
6583 	minedprog = mined_argv [0];
6584 	minedopt = strrchr (mined_argv [0], '/');
6585 	if (minedopt) {
6586 		minedopt ++;
6587 	} else {
6588 		minedopt = mined_argv [0];
6589 	}
6590 	if (strisprefix ("r", minedopt)) {
6591 		restricted = True;
6592 		minedopt ++;
6593 	}
6594 	if (strisprefix ("minma", minedopt)) {
6595 		eval_options ("-e", False);
6596 	} else if (strisprefix ("mstar", minedopt)) {
6597 		eval_options ("-W", False);
6598 	} else if (strisprefix ("mpico", minedopt)) {
6599 		emul_pico ();
6600 	}
6601   } else {
6602 	minedprog = "mined";
6603   }
6604 
6605   do {
6606 	if (argi < mined_argc) {
6607 		if (streq (mined_argv [argi], "++")) {
6608 			argi += 1;
6609 			goon = False;
6610 		} else if (* mined_argv [argi] == '+' && mined_argv [argi] [1] >= '0' && mined_argv [argi] [1] <= '9') {
6611 			initlini = argi;
6612 			argi += 1;
6613 		} else if (* mined_argv [argi] == '-'
6614 			      || * mined_argv [argi] == '+'
6615 #ifdef msdos
6616 			      || * mined_argv [argi] == '/'
6617 #endif
6618 			      )
6619 		{
6620 			minedopt = mined_argv [argi];
6621 			eval_options (minedopt, True);
6622 			argi += 1;
6623 		} else {
6624 			goon = False;
6625 		}
6626 	} else {
6627 		goon = False;
6628 	}
6629   } while (goon);
6630 
6631   return argi;
6632 }
6633 
6634 
6635 #ifdef __GNUC__
6636 #define mempoi void *
6637 #else
6638 /* most non-GNU C compilers, following standard C, do not permit
6639    pointer arithmetic on void *
6640  */
6641 #define mempoi char *
6642 #endif
6643 
6644 static mempoi prefbuf = 0;
6645 static mempoi prefpoi;
6646 static int prefsaving;
6647 static int preflen = 200;
6648 
6649 #define dont_debug_preferences
6650 
6651 #ifdef debug_preferences
6652 #define trace_pref(params)	printf params
6653 #else
6654 #define trace_pref(params)
6655 #endif
6656 
6657 static
6658 void
6659 #ifdef debug_preferences
do_prefmov(varpoi,varsize,varname)6660 do_prefmov (varpoi, varsize, varname)
6661   void * varpoi;
6662   int varsize;
6663   char * varname;
6664 #else
6665 do_prefmov (varpoi, varsize)
6666   void * varpoi;
6667   int varsize;
6668 #endif
6669 {
6670   if (prefsaving) {
6671 	if (prefpoi - prefbuf + varsize > preflen) {
6672 #define prefinc 50
6673 		mempoi newbuf = realloc (prefbuf, preflen + prefinc);
6674 		if (newbuf) {
6675 			trace_pref (("realloc %p->%p (%d)\n", prefbuf, newbuf, preflen + prefinc));
6676 			prefpoi = newbuf + (prefpoi - prefbuf);
6677 			prefbuf = newbuf;
6678 			preflen += prefinc;
6679 		} else {
6680 			trace_pref (("realloc failed\n"));
6681 			return;
6682 		}
6683 	}
6684 	memcpy (prefpoi, varpoi, varsize);
6685 	trace_pref (("%p:%04X <- %s (%d)\n", prefpoi, * (unsigned int *) prefpoi, varname, varsize));
6686 	prefpoi += varsize;
6687   } else {
6688 	trace_pref (("%p:%04X -> %s (%d)\n", prefpoi, * (unsigned int *) prefpoi, varname, varsize));
6689 	memcpy (varpoi, prefpoi, varsize);
6690 	prefpoi += varsize;
6691   }
6692 }
6693 
6694 #ifdef debug_preferences
6695 #define prefmov(var)	do_prefmov (& var, sizeof (var), #var)
6696 #else
6697 /* stringification (#var) not supported on various systems (e.g. HPUX) */
6698 #define prefmov(var)	do_prefmov (& var, sizeof (var))
6699 #endif
6700 
6701 static
6702 void
preferences(save_restore)6703 preferences (save_restore)
6704   FLAG save_restore;
6705 {
6706   prefsaving = save_restore != REVERSE;
6707 
6708   if (prefsaving && ! prefbuf) {
6709 	prefbuf = alloc (preflen);
6710   }
6711   if (! prefbuf) {
6712 	return;
6713   }
6714 
6715   prefpoi = prefbuf;
6716 
6717   prefmov (restricted);	/* just to be safe (cannot be toggled) */
6718   prefmov (use_file_tabs);
6719   prefmov (backup_mode);
6720 
6721   prefmov (smart_quotes);
6722   prefmov (quote_type);
6723   prefmov (prev_quote_type);
6724   prefmov (wordnonblank);
6725   prefmov (JUSlevel);
6726   prefmov (JUSmode);
6727   prefmov (mark_HTML);
6728   prefmov (mark_JSP);
6729   prefmov (viewonly_mode);
6730   prefmov (lowcapstrop);
6731   prefmov (dispunstrop);
6732   prefmov (strop_style);
6733   prefmov (autoindent);
6734   prefmov (autonumber);
6735   prefmov (backnumber);
6736   prefmov (backincrem);
6737   prefmov (tabsize);
6738   prefmov (tabsize_selected);
6739   prefmov (expand_tabs);
6740   prefmov (hide_passwords);
6741   prefmov (filtering_read);
6742   prefmov (filtering_write);
6743 
6744   trace_pref (("preferences (saving %d) length %d\n", prefsaving, prefpoi - prefbuf));
6745 }
6746 
6747 static struct {
6748 	char * name;
6749 	char * eval;
6750 } config_options [] = {
6751 	{"tab",		"-%s"},
6752 	{"tabstop",	"-%s"},
6753 	{"tabwidth",	"-%s"},
6754 	{"tabexpand",	"-+%s"},
6755 	{"rectangular",	"+["},
6756 	{"square",	"+["},
6757 	{"emul",	"+e%s"},
6758 	{"keypad_windows",		"-kw"},
6759 	{"keypad_shift_selection",	"-kS"},
6760 	{"keypad_mined",		"-km"},
6761 	{"home_selection",		"-kM"},
6762 	{"small_home_selection",	"-km"},
6763 	{"im_space",	"-K%s"},
6764 	{"im",		"-K=%s"},
6765 	{"strop_bold",		"+ZZ"},
6766 	{"strop_underline",	"+ZZZ_"},
6767 	{"unicode_paste_buffer",	"-Eu"},
6768 	{"separated_display",	"-c"},
6769 	{"backup_mode",		"+b%s"},
6770 	{"backup_directory",	"+b=%s"},
6771 	{"file_chooser",	"+z%s"},
6772 	{"file_tabs",		"+M:"},
6773 	{"tab_snap",		"%sT"},
6774 	{"justify",		"+j=%s"},
6775 	{"display_mac",		"+R"},
6776 	{"display_paragraphs",	"-p"},
6777 	{"page_stay",	"-s"},
6778 	{"paste_stay",	"-V"},
6779 	{"delete_to_buffer",	"+VV"},
6780 	{"no_window_title",	"-X"},
6781 	{"word_skip",	"-w"},
6782 	{"smart_quotes",	"-q=%s"},
6783 	{"highlight_html",	"+H"},
6784 	{"highlight_xml",	"+H"},
6785 	{"cursor_style",	"-%s"},
6786 	{"hide_passwords",	"-P"},
6787 	{"show_passwords",	"+P"},
6788 	{"sel_keep_on_search",	"+V:k"},
6789 	{"sel_auto_copy",	"+V:c"},
6790 	{"display_charinfo",	"+?c"},
6791 	{"no_display_charinfo",	"-?c"},
6792 	{"display_script",	"+?s"},
6793 	{"display_charname",	"+?n"},
6794 	{"display_namedseq",	"+?q"},
6795 	{"display_decomposition",	"+?d"},
6796 	{"display_mnemos",	"+?m"},
6797 	{"display_fileinfo",	"+?f"},
6798 	{"display_haninfo_short",	"+?x"},
6799 	{"display_haninfo_full",	"+?h"},
6800 	{"plain_BS",		"+Bp"},
6801 	{"filter_read",		"+%s"},
6802 	{"filter_write",	"+%s"},
6803 	{"menu_corners_simple",	"-Qs"},
6804 	{"menu_corners_round",	"-Qr"},
6805 	{"menu_borders_fat",	"-Qf"},
6806 	{"menu_borders_double",	"-Qd"},
6807 	{"menu_borders_ascii",	"-Qa"},
6808 	{"menu_borders_vt100",	"-Qv"},
6809 	{"menu_borders_plain",	"-Qp"},
6810 	{"menu_borders_none",	"-QP"},
6811 	{"menu_background",	"-QB"},
6812 	{"menu_selection_fancy",	"-QQ"},
6813 	{"menu_selection_plain",	"-Qq"},
6814 	{"splash_logo",	"+Q%s"},
6815 	{NIL_PTR}
6816 };
6817 
6818 /**
6819    Read and evaluate mined runtime configuration file.
6820    applyall = True: initially evaluate common options
6821               False: apply conditional options only
6822    Preferences management concept:
6823 	initially:
6824 		configure_preferences (True);	... calling eval_options
6825 		... check various environment preferences
6826 		(void) eval_commandline ();	... overriding preset values
6827 		preferences (FORWARD);		... saving preferences
6828 	load_file:
6829 		update_file_name:
6830 			configure_preferences (False); ... restoring initial preferences first
6831 				preferences (REVERSE); ... restore saved preferences
6832 				... read file name specific preferences
6833 		get_open_pos	... override saved file preferences
6834 		set_file_type_flags ()
6835 			... deriving generic file specific preferences
6836 		configure_preferences (OPEN);	... restore command line options
6837 			(void) eval_commandline ();
6838 	However, the latter does not work as long as there are
6839 	cumulative options, i.e. options that have different effect
6840 	if applied multiple times; thus, for now, specific checks
6841 	are still needed (e.g. tabsize_selected).
6842 	This applies to the following options:
6843 		M
6844 		*
6845 		f
6846 		F
6847 		c
6848 		C
6849 		U
6850 		-b
6851 		w
6852 		-j
6853 		V
6854 		+t
6855 		-k (plain)
6856 	and possibly to the following guarding flags:
6857 		tabsize_selected
6858 		strop_selected
6859 		explicit_keymap
6860 		explicit_border_style
6861 		explicit_scrollbar_style
6862 		explicit_selection_style
6863 		default_quote_type
6864 		preselect_quote_style
6865 		default_text_encoding
6866 		text_encoding_selected
6867 		default_lineend
6868 		homedir_selected
6869  */
6870 #define dont_debug_confpref
6871 void
configure_preferences(applycommon)6872 configure_preferences (applycommon)
6873   FLAG applycommon;
6874 {
6875   char rcfn [maxFILENAMElen];
6876   int rc_fd;
6877   FLAG condition = applycommon;
6878   char pref_name [maxFILENAMElen];	/* filename to check */
6879   strcpy (pref_name, file_name);
6880 
6881   /* mark subsequent selections to be preconfigured (e.g. .minedrc) */
6882   cmdline_selected = False;
6883 
6884   if (applycommon == OPEN) {
6885 #ifdef apply_cmdline_options_again
6886 #warning implementation incomplete, some options may cumulate
6887 	/* recover command line options */
6888 	(void) eval_commandline ();
6889 #endif
6890 	return;
6891   } else if (! applycommon) {
6892 	/* restore initial preferences */
6893 	preferences (REVERSE);
6894   }
6895 
6896   strcpy (rcfn, gethomedir ());
6897 #ifdef vms
6898   strappend (rcfn, ".minedrc", maxFILENAMElen);
6899 #else
6900   strip_trailingslash (rcfn);
6901   strappend (rcfn, "/.minedrc", maxFILENAMElen);
6902 #endif
6903   rc_fd = open (rcfn, O_RDONLY | O_BINARY, 0);
6904 
6905   if (rc_fd >= 0) {
6906 	static off_t seek_position = 0;
6907 	int dumlen;
6908 
6909 	if (! applycommon) {
6910 		if (lseek (rc_fd, seek_position, SEEK_SET) < 0) {
6911 			/* ignore, just read from beginning */
6912 		}
6913 	}
6914 
6915 	reset_get_line (False);
6916 	while (line_gotten (get_line (rc_fd, text_buffer, & dumlen, False))) {
6917 		long linelen = strlen (text_buffer);
6918 		if (text_buffer [0] == '[') {
6919 			/* determine condition to apply configuration options */
6920 			char * condopt = strrchr (text_buffer, ']');
6921 			if (condopt) {
6922 				* condopt = '\0';
6923 			}
6924 			condition = False;
6925 			/* check if considering common or specific options */
6926 			if (applycommon) {
6927 				break;
6928 			} else {
6929 				/* check specific preferences filter */
6930 				condopt = & text_buffer [2];
6931 				if (text_buffer [1] == '=') {
6932 					/* filter terminal type */
6933 					if (streq (condopt, TERM)) {
6934 						condition = True;
6935 					}
6936 #ifdef pref_match_only_suffix
6937 				} else if (text_buffer [1] == '.') {
6938 					/* filter filename suffix */
6939 					char * suf = strstr (pref_name, condopt);
6940 					if (suf && strlen (suf) == strlen (condopt)) {
6941 						condition = True;
6942 					}
6943 #endif
6944 				} else if (wildcard (& text_buffer [1], pref_name)) {
6945 					condition = True;
6946 				}
6947 #ifdef debug_confpref
6948 				printf ("conf %d %s\n", condition, text_buffer);
6949 #endif
6950 			}
6951 		} else if (condition && text_buffer [0] > '#') {
6952 			char * option = text_buffer;
6953 			char * negoption = NIL_PTR;
6954 			char * optval;
6955 			character * optpoi;	/* unsigned ! */
6956 			char optvalsep = ' ';
6957 
6958 			if (* option == '-') {
6959 				option ++;
6960 			} else if (strisprefix ("set", option) && option [3] <= ' ') {
6961 				option += 3;
6962 				while (* option == ' ' || * option == '\t') {
6963 					option ++;
6964 				}
6965 			} else if (strisprefix ("unset", option) && option [5] <= ' ') {
6966 				option += 5;
6967 				while (* option == ' ' || * option == '\t') {
6968 					option ++;
6969 				}
6970 				negoption = option;
6971 			}
6972 			/*option [strlen (option) - 1] = '\0';*/
6973 			if (strisprefix ("no_", option)) {
6974 				if (negoption) {
6975 					negoption = NIL_PTR;
6976 					option += 3;
6977 				} else {
6978 					negoption = option + 3;
6979 				}
6980 			}
6981 
6982 			/* skip option name, terminate it with NUL */
6983 			optpoi = option;
6984 			while (* optpoi > ' ' && * optpoi != '=') {
6985 				if (* optpoi == '-') {
6986 					* optpoi = '_';
6987 				}
6988 				optpoi ++;
6989 			}
6990 			while (* optpoi == ' ' || * optpoi == '\t' || * optpoi == '=') {
6991 				* optpoi ++ = '\0';
6992 			}
6993 
6994 			/* check option value delimiter */
6995 			if (* optpoi == '"' || * optpoi == '\'') {
6996 				optvalsep = * optpoi;
6997 				optpoi ++;
6998 			}
6999 
7000 			/* option value starts here */
7001 			optval = optpoi;
7002 
7003 			/* skip option value, terminate it with NUL */
7004 			while (* optpoi >= ' ' && * optpoi != optvalsep) {
7005 				optpoi ++;
7006 			}
7007 			* optpoi = '\0';
7008 
7009 #ifdef debug_confpref
7010 			printf ("conf %s=%s\n", option, optval);
7011 #endif
7012 			if (streq (option, "<<")) {
7013 				strncpy (pref_name, optval, maxFILENAMElen);
7014 				pref_name [maxFILENAMElen - 1] = '\0';
7015 			} else {
7016 			    int opt_i = 0;
7017 			    while (config_options [opt_i].name != NIL_PTR) {
7018 				if (streq (option, config_options [opt_i].name)) {
7019 					char eval [maxCMDlen];
7020 					build_string (eval, config_options [opt_i].eval, optval);
7021 #ifdef debug_confpref
7022 					printf ("     ->%s\n", eval);
7023 #endif
7024 					eval_options (eval, False);
7025 					if (strisprefix ("filter_", option)) {
7026 						char * suf = strrchr (pref_name, '.');
7027 						if (suf) {
7028 							* suf = '\0';
7029 						}
7030 					}
7031 					break;
7032 				} else if (negoption
7033 					&& streq (negoption, config_options [opt_i].name)
7034 					&& config_options [opt_i].eval [0] == '+'
7035 					) {
7036 					char eval [maxCMDlen];
7037 					build_string (eval, config_options [opt_i].eval, optval);
7038 					eval [0] = '-';
7039 #ifdef debug_confpref
7040 					printf ("     ->%s\n", eval);
7041 #endif
7042 					eval_options (eval, False);
7043 					break;
7044 				}
7045 				opt_i ++;
7046 			    }
7047 			}
7048 		}
7049 		if (applycommon) {
7050 			seek_position += linelen;
7051 		}
7052 	}
7053 	(void) close (rc_fd);
7054 	clear_filebuf ();	/* which needs to call clear_get_line too */
7055   }
7056 }
7057 
7058 
7059 /**
7060    configuration and initialisation;
7061    load the file (if any);
7062    main loop of the editor
7063  */
7064 int
main(argc,argv)7065 main (argc, argv)
7066   int argc;
7067   char * argv [];
7068 {
7069   int argi;
7070   unsigned long inputchar;
7071   int initlinenum;
7072   LINE * initline;
7073   char * env;
7074   char * minedopt;
7075 
7076   debug_mined = envvar ("DEBUG_MINED");
7077   TERM = envstr ("TERM");
7078 
7079   mined_argc = argc;
7080   mined_argv = argv;
7081 
7082 /* determine various modes and display options from environment settings */
7083   if (envvar ("NoCtrlSQ") || envvar ("NoControlSQ")) {
7084 	/* ^S and ^Q may come arbitrarily from terminal, so don't use them */
7085 	controlQS = True;
7086 	key_map ['\021'] = I;
7087 	key_map ['\023'] = I;
7088   }
7089 
7090   transout = envstr ("MINEDOUT");
7091   if (* transout != '\0') {
7092 	translen = strlen (transout);
7093 	translate_output = True;
7094 	use_ascii_graphics = True;
7095 	menu_border_style = 'r';
7096   }
7097 #ifdef unix
7098   if (envvar ("MINEDMODF")) {
7099 	mined_modf = envvar ("MINEDMODF");
7100   }
7101 #endif
7102 #ifdef pc_winlowdelay
7103   if (is_Windows ()) {
7104 	display_delay = 0;
7105   }
7106 #endif
7107 
7108 #ifdef debug_graphics
7109   printf ("(mn) ascii %d, vga %d, vt100 %d\n", use_ascii_graphics, use_vga_block_graphics, use_vt100_block_graphics);
7110 #endif
7111 
7112 
7113 /* derive screen mode and default text encoding from environment */
7114 
7115 #ifdef __CYGWIN__
7116 /* check misconfigured cygwin console and ignore $TERM if detected;
7117 	if $WINDIR is in environment rather than $windir,
7118 	there has been an underlying cygwin instance
7119 	before spawning the console and thus the value of $TERM is bogus
7120 	*/
7121   if (strisprefix ("/dev/cons", unnull (ttyname (2))) && envvar ("WINDIR")) {
7122 	TERM = "cygwin";
7123   }
7124 #endif
7125 
7126   if (streq (TERM, "cygwin")) {
7127 	cygwin_console = True;
7128   }
7129 
7130 /* detect PC terminal modes for native PC and for telnet from PC to Unix */
7131 #ifdef pc_term
7132   if (envvar ("USERPROFILE")) {
7133 	(void) set_term_encoding ("CP850", 'P');
7134   } else {
7135 	(void) set_term_encoding ("CP437", 'p');
7136   }
7137 #endif
7138   if (strisprefix ("nansi", TERM)
7139 	|| strisprefix ("ansi.", TERM)
7140 	|| strisprefix ("opennt", TERM)
7141 	|| strcontains (TERM, "-emx")
7142 	|| strisprefix ("interix", TERM)
7143      ) {
7144 #ifdef __CYGWIN__
7145 	TERM = "cygwin";
7146 #else
7147 	dark_term = True;
7148 	(void) set_term_encoding ("CP437", 'p');
7149 	term_encoding_selected = True;
7150 	if (! text_encoding_selected) {
7151 		(void) set_text_encoding ("CP850", 'P', "TERM=nansi");
7152 	}
7153 	use_vga_block_graphics = True;
7154 	use_mouse_button_event_tracking = False;
7155 #endif
7156   } else if (strisprefix ("pcansi", TERM)
7157 		|| strisprefix ("hpansi", TERM)
7158 		|| streq ("ansi", TERM)
7159 		|| streq ("ansi-nt", TERM)
7160      ) {
7161 #ifdef __CYGWIN__
7162 	TERM = "cygwin";
7163 #else
7164 	dark_term = True;
7165 	(void) set_term_encoding ("CP850", 'P');
7166 	term_encoding_selected = True;
7167 	if (! text_encoding_selected) {
7168 		(void) set_text_encoding ("CP850", 'P', "TERM=pcansi");
7169 	}
7170 	use_vga_block_graphics = True;
7171 	use_mouse_button_event_tracking = False;
7172 #endif
7173   }
7174 #ifdef __CYGWIN__
7175   {
7176 	char * path = envstr ("PATH");
7177 	char * p = strstr (path, "WindowsPowerShell");
7178 	if (p) {
7179 		char * sys = strstr (path, "%SystemRoot%");
7180 		if (sys && sys + 22 == path) {
7181 			/* Windows PowerShell */
7182 			TERM = "cygwin";
7183 			dark_term = True;
7184 		}
7185 	}
7186   }
7187 #endif
7188   if (strisprefix ("ansi", TERM)) {
7189 	can_report_props = False;
7190 	use_ascii_graphics = True;
7191 	menu_border_style = 'r';
7192   }
7193   if (strisprefix ("Eterm", TERM)) {
7194 	bright_term = True;
7195   }
7196 
7197 /* check if cygwin console is configured to be in PC character set mode */
7198   if (streq (TERM, "cygwin")) {
7199 	can_report_props = False;
7200 	dark_term = True;
7201 	/* avoid_reverse_colour = True; workaround obsolete */
7202 	use_script_colour = False;
7203 #ifdef msdos
7204 	/* if the djgpp version of mined is called from a cygwin shell,
7205 	   it will still see TERM=cygwin but the cygwin encoding emulation
7206 	   is not applicable (it's done by the cygwin DLL, not the terminal);
7207 	   djgpp mined assumes CP850 terminal "codepage" by default,
7208 	   may be overridden by codepage detection below
7209 	 */
7210 	(void) set_term_encoding ("CP850", 'P');
7211 #else
7212 	if (strcontains (envstr ("CYGWIN"), "codepage:oem")) {
7213 		/* CP850 */
7214 		(void) set_term_encoding ("CP850", 'P');
7215 		term_encoding_selected = True;
7216 	} else if (strcontains (envstr ("CYGWIN"), "codepage:utf8")) {
7217 		(void) set_term_encoding (NIL_PTR, 'U');
7218 		term_encoding_selected = True;
7219 	} else {
7220 		use_pc_block_graphics = True;
7221 # ifdef __CYGWIN__
7222 #  if CYGWIN_VERSION_DLL_MAJOR < 1007	/* avoid langinfo for MSYS */
7223 #   if CYGWIN_VERSION_DLL_MAJOR < 1005	/* MSYS */
7224 			use_ascii_graphics = True;
7225 			menu_border_style = 'r';
7226 #   endif
7227 			if (! set_term_encoding (":cw", ' ')) {
7228 				(void) set_term_encoding ("CP1252", 'W');
7229 			}
7230 #  else
7231 			if (setlocale (LC_CTYPE, "")) {
7232 				(void) set_term_encoding (nl_langinfo (CODESET), ' ');
7233 				term_encoding_selected = True;
7234 			} else {
7235 #   ifdef fallback_builtin
7236 				(void) locale_terminal_encoding ();
7237 				if (streq (language_code, "")) {
7238 					(void) set_term_encoding (NIL_PTR, 'U');
7239 				} else {
7240 					/* leave to handle_locale_encoding below */
7241 				}
7242 #   else
7243 				(void) set_term_encoding (NIL_PTR, 'U');
7244 				term_encoding_selected = True;
7245 #   endif
7246 			}
7247 #  endif
7248 # else
7249 		/* set default terminal encoding assumption
7250 		   for remote login from a cygwin console
7251 		 */
7252 		/* cygwin 1.5: */
7253 		/*(void) set_term_encoding ("CP1252", 'W');*/
7254 		/* cygwin 1.7: */
7255 		/*(void) set_term_encoding (NIL_PTR, 'U');*/
7256 		/* safe common fall-back: */
7257 		(void) set_term_encoding ("ASCII", ' ');
7258 		/* encodings should be indicated properly in environment ...
7259 		 */
7260 # endif
7261 	}
7262 
7263 	/* limit terminal to ASCII in POSIX locale */
7264 	(void) locale_terminal_encoding ();
7265 /* relic of early cygwin 1.7 versions:
7266 	if (streq (language_code, "C") || streq (language_code, "POSIX")) {
7267 		(void) set_term_encoding ("ASCII", ' ');
7268 	}
7269 */
7270 
7271 	/* enable mouse move reporting without button pressed (for menus) */
7272 	use_mouse_anymove_inmenu = True;
7273 	/* adjust Unicode limitations in case UTF-8 is configured later */
7274 	/* (e.g. with LC_... after rlogin) */
7275 	width_data_version = 0;
7276 	utf_cjk_wide_padding = False;
7277 	suppress_non_BMP = True;
7278 	suppress_extended_cjk = True;
7279 	if (limited_marker_font) {
7280 		very_limited_marker_font = True;
7281 	} else {
7282 		limited_marker_font = True;
7283 	}
7284 	if (! explicit_scrollbar_style) {
7285 		fine_scrollbar = False;
7286 	}
7287 	use_vga_block_graphics = True;
7288 
7289 	/* workaround for unusual keypad assignments */
7290 	if (mined_keypad) {
7291 		mined_keypad = False;
7292 	} else {	/* in case option -k reversed it already */
7293 		mined_keypad = True;
7294 	}
7295 #endif
7296 
7297 	if (! text_encoding_selected) {
7298 		/*(void) set_text_encoding ("CP1252", 'W', "TERM=cygwin");*/
7299 		/* align with changed non-locale terminal encoding */
7300 		(void) set_text_encoding ("ISO-8859-1", 'L', "TERM=cygwin");
7301 	}
7302 	trace_encoding ("cygwin");
7303 
7304 	/* numeric encoding of mouse coordinates */
7305 	use_mouse_1015 = True;
7306   }
7307 
7308 /* now derive screen mode and default text encoding from locale environment */
7309   if (! term_encoding_selected) {
7310 #ifdef msdos
7311 	char codepagename [13];
7312 # ifdef debug_encoding
7313 	printf ("codepage %d\n", get_codepage ());
7314 # endif
7315 	build_string (codepagename, "CP%d", get_codepage ());
7316 	if (! set_term_encoding (codepagename, ' ')) {
7317 		(void) set_term_encoding ("ASCII", ' ');
7318 	} else if (! text_encoding_selected) {
7319 		/* transparent editing in current codepage */
7320 		(void) set_text_encoding (codepagename, ' ', "codepage");
7321 	}
7322 	if (lookup_mappedtermchar (0xB2) != 0x2593) {
7323 		/* codepage does not include VGA block graphics */
7324 		use_ascii_graphics = True;
7325 		menu_border_style = 'r';
7326 	}
7327 	trace_encoding ("codepage");
7328 #else
7329 	(void) handle_locale_encoding (True, locale_terminal_encoding ());
7330 	trace_encoding ("term locale");
7331 #endif
7332   }
7333   if (! text_encoding_selected) {
7334 	(void) handle_locale_encoding (False, locale_text_encoding ());
7335 	trace_encoding ("text locale");
7336   }
7337 
7338 
7339 /* fall-back/default config actions */
7340   handle_locale_quotes (NIL_PTR, UNSURE);
7341 
7342 
7343 /* configuration common preferences */
7344   configure_preferences (True);	/* calling eval_options */
7345 
7346 
7347 /* backup and recovery environment settings */
7348   if (envvar ("BACKUP_DIRECTORY")) {
7349 	backup_directory = envvar ("BACKUP_DIRECTORY");
7350   }
7351   if (! backup_directory || backup_directory [0] == '\0') {
7352 	if (envvar ("BACKUPDIR")) {
7353 		backup_directory = envvar ("BACKUPDIR");
7354 	}
7355   }
7356   if (backup_directory && backup_directory [0] == '\0') {
7357 	backup_directory = NIL_PTR;
7358   }
7359   if (backup_directory && is_absolute_path (backup_directory)) {
7360 	if (mkdir (backup_directory, 0700) == 0 || geterrno () == EEXIST) {
7361 		/* backup directory OK */
7362 	} else {
7363 		backup_directory = NIL_PTR;
7364 	}
7365   }
7366   if ((minedopt = envvar ("VERSION_CONTROL")) != NIL_PTR) {
7367 	if (streq ("none", minedopt) || streq ("off", minedopt)) {
7368 		/* never make backups (cp: "even if --backup is given") */
7369 		backup_mode = '\0';
7370 	} else if (streq ("numbered", minedopt) || streq ("t", minedopt)) {
7371 		/* make numbered backups (emacs style) */
7372 		backup_mode = 'e';
7373 	} else if (streq ("existing", minedopt) || streq ("nil", minedopt)) {
7374 		/* numbered if numbered backups exist, simple otherwise */
7375 		backup_mode = 'a';
7376 	} else if (streq ("simple", minedopt) || streq ("never", minedopt)) {
7377 		/* always make simple backups */
7378 		backup_mode = 's';
7379 	}
7380   }
7381   recover_directory = envvar ("AUTO_SAVE_DIRECTORY");
7382   if (! recover_directory || recover_directory [0] == '\0') {
7383 	recover_directory = envvar ("AUTOSAVEDIR");
7384   }
7385   if (recover_directory && recover_directory [0] == '\0') {
7386 	recover_directory = NIL_PTR;
7387   }
7388   if (recover_directory && is_absolute_path (recover_directory)) {
7389 	if (mkdir (recover_directory, 0700) == 0 || geterrno () == EEXIST) {
7390 		/* recovery directory OK */
7391 	} else {
7392 		recover_directory = NIL_PTR;
7393 	}
7394   }
7395   if (! recover_directory || recover_directory [0] == '\0') {
7396 	recover_directory = backup_directory;
7397   }
7398 
7399 
7400 /* process options configured in environment */
7401   minedopt = envvar ("MINEDOPT");
7402   if (minedopt == NIL_PTR) {
7403 #ifdef vms
7404 	minedopt = envvar ("MINED$OPT");
7405 #else
7406 	minedopt = envvar ("MINED");
7407 #endif
7408   }
7409   if (minedopt != NIL_PTR) {
7410 	eval_options (minedopt, False);
7411   }
7412 
7413 
7414 /* set configured keyboard mapping */
7415   (void) setKEYMAP (envvar ("MINEDKEYMAP"));
7416 
7417 
7418 /* mark subsequent selections to be manually selected */
7419   cmdline_selected = True;
7420 
7421 /* evaluate command line options (not file names) */
7422   argi = eval_commandline ();
7423   cmdline_selected = False;
7424 
7425 /* save initial preferences */
7426   preferences (FORWARD);
7427 
7428 
7429 #ifdef debug_graphics
7430   printf ("(op) ascii %d, vga %d, vt100 %d\n", use_ascii_graphics, use_vga_block_graphics, use_vt100_block_graphics);
7431 #endif
7432   trace_encoding ("options");
7433 
7434 #ifdef debug_wildcard_expansion
7435 #define trace_expansion(params)	printf params
7436 #else
7437 #define trace_expansion(params)
7438 #endif
7439 
7440   if (argi < argc) {
7441 	int fi;
7442 	for (fi = argi; fi < argc; fi ++) {
7443 #ifdef wildcard_expansion
7444 	    char * fnami = argv [fi];
7445 	    FLAG match = False;
7446 	    trace_expansion (("expanding %d <%s>\n", fi, fnami));
7447 	    if (strchr (fnami, '*') || strchr (fnami, '?')
7448 #ifdef vms
7449 		|| strchr (fnami, '%')
7450 #else
7451 		|| (strchr (fnami, '[') && strchr (fnami, ']'))
7452 #endif
7453 		) {
7454 		char * bn;
7455 		char dn [maxFILENAMElen];
7456 		DIR * dir;
7457 		* dn = '\0';
7458 		strappend (dn, fnami, maxFILENAMElen);
7459 		bn = getbasename (dn);
7460 		if (bn == dn) {
7461 			strcpy (dn, "");
7462 		} else {
7463 			* bn = '\0';
7464 		}
7465 		bn = getbasename (fnami);
7466 
7467 		trace_expansion (("dir <%s>\n", dn));
7468 		if (* dn) {
7469 			dir = opendir (dn);
7470 		} else {
7471 			dir = opendir (".");
7472 		}
7473 		if (dir) {
7474 #ifdef vms
7475 		    char * prevfn = "";
7476 #endif
7477 		    struct dirent * direntry;
7478 		    while ((direntry = readdir (dir)) != 0) {
7479 			trace_expansion (("matching <%s> in <%s>\n", bn, direntry->d_name));
7480 			if (wildcard (bn, direntry->d_name)) {
7481 				char * fn = alloc (strlen (dn) + strlen (direntry->d_name) + 2);
7482 
7483 				if (! fn) {
7484 					break;
7485 				}
7486 				strcpy (fn, dn);
7487 				strcat (fn, direntry->d_name);
7488 				trace_expansion (("-> <%s>\n", fn));
7489 
7490 				match = True;
7491 
7492 #ifdef vms
7493 				/* does pattern contain version? */
7494 				if (strchr (bn, ';')) {
7495 					/* add match with version */
7496 					trace_expansion ((" -> added with version\n"));
7497 					filelist_add (fn, True);
7498 				} else {
7499 					/* handle []x* -> X.;1 X.;2 */
7500 
7501 					/* strip version from match */
7502 					char * ver = strrchr (fn, ';');
7503 					if (ver) {
7504 						* ver = '\0';
7505 					}
7506 
7507 					if (streq (prevfn, fn)) {
7508 						/* drop duplicate versions */
7509 						trace_expansion ((" -> dropped\n"));
7510 					} else {
7511 						trace_expansion ((" -> added\n"));
7512 						filelist_add (fn, True);
7513 					}
7514 				}
7515 				prevfn = fn;
7516 #else
7517 				filelist_add (fn, True);
7518 #endif
7519 			}
7520 		    }
7521 		    closedir (dir);
7522 		}
7523 		trace_expansion (("match: %d\n", match));
7524 	    }
7525 	    if (! match) {	/* no wildcard or no match */
7526 		filelist_add (fnami, True);
7527 	    }
7528 #else
7529 	    filelist_add (argv [fi], True);
7530 #endif
7531 	}
7532 	argi = 0;
7533   } else {
7534 	argi = -1;	/* indicate "no file" */
7535   }
7536 
7537 
7538 /* handling of input/output redirection */
7539   /* Note: this must be called before terminal mode initialisation
7540 	(get_term)
7541    */
7542   /* Note:
7543      - input redirection does not work with DOS version
7544      - handling of input/output redirection has to be suppressed in
7545        DOSBox or mined cannot start there (probably a DOSBox bug)
7546   */
7547 #ifdef msdos
7548   if (strisprefix ("Z:\\", envstr ("COMSPEC")))
7549   {
7550 	/* DOSBox detected */
7551   }
7552   else
7553 #endif
7554   {
7555 #ifndef __MINGW32__
7556     if (! isatty (STD_IN)) {	/* Reading from pipe */
7557 	if (argi >= 0) {
7558 		panic ("Cannot read both pipe and file", NIL_PTR);
7559 	}
7560 	reading_pipe = True;
7561 
7562 	/* wait for pipe data available in order to prevent screen control
7563 	   interference with previous pipe programs;
7564 	   must be called before changing input_fd
7565 	   and before calling terminal_configure_init ();
7566 	   this enhances pipe robustness slightly; a better solution would
7567 	   read the complete pipe before tackling the screen
7568 	 */
7569 	(void) inputreadyafter (-1);
7570 
7571 	/* set modified flag not to loose buffer */
7572 	set_modified ();
7573 
7574 	/* open terminal tty */
7575 #ifdef msdos
7576 	panic ("Cannot edit after input from pipe", "MSDOS incompatibility");
7577 #else
7578 	if ((input_fd = open ("/dev/tty", O_RDONLY, 0)) < 0) {
7579 		panic ("Cannot open /dev/tty for reading", serror ());
7580 	}
7581 #endif
7582     }
7583 
7584     if (! isatty (STD_OUT)) {
7585 	writing_pipe = True;
7586 	set_modified (); /* Set modified flag not to ignore buffer on exit */
7587 	if ((output_fd = open ("/dev/tty", O_WRONLY, 0)) < 0) {
7588 		panic ("Cannot open /dev/tty for writing", serror ());
7589 	}
7590     }
7591 #endif
7592   }
7593 
7594 
7595 /* setup terminal, auto-detect encoding, fine-tune modes */
7596   /*if (! only_detect_text_encoding)?*/
7597   terminal_configure_init ();
7598 
7599 
7600 /* install workaround for cygwin console delaying some escape sequences */
7601   install_console_pipe ();
7602 
7603 
7604 /* determine terminal-specific escape sequences and restrictions */
7605   if (strisprefix ("vt1", TERM)) {
7606 	set_fkeymap ("vt100");
7607   }
7608   if (strisprefix ("rxvt", TERM) && mintty_version == 0) {
7609 	set_fkeymap ("rxvt");
7610   }
7611   if (strisprefix ("hp", TERM)
7612    || streq ("xterm-hp", TERM)
7613    || strisprefix ("superbee", TERM)
7614    || strisprefix ("sb", TERM)
7615    || strisprefix ("microb", TERM)
7616      ) {
7617 	if (! streq ("hpansi", TERM)) {
7618 		set_fkeymap ("hp");
7619 	}
7620 	use_ascii_graphics = True;
7621 	menu_border_style = 'r';
7622 	use_bold = False;
7623   }
7624   if (strisprefix ("hp", TERM)) {
7625 	bw_term = True;
7626   }
7627   if (streq ("vt52", TERM)
7628    || strcontains (TERM, "-vt52")
7629      ) {
7630 	set_fkeymap ("52");
7631 	(void) set_term_encoding ("ASCII", ' ');
7632 	use_ascii_graphics = True;
7633 	menu_border_style = 'r';
7634 	use_bold = False;
7635   }
7636   if (strisprefix ("scoansi", TERM)
7637    || streq ("xterm-sco", TERM)
7638    || strisprefix ("cons", TERM)	/* FreeBSD console */
7639    || streq ("att605-pc", TERM)
7640    || streq ("ti_ansi", TERM)
7641    || streq ("mgterm", TERM)
7642      ) {
7643 	set_fkeymap ("o");
7644   }
7645   if (strcontains (TERM, "koi")) {
7646 	(void) set_term_encoding ("KOI8-R", ' ');
7647   }
7648   if (strisprefix ("cons", TERM) && strlen (TERM) >= 6) {
7649 	/* FreeBSD console */
7650 	if (strisprefix ("r", TERM + 6)) {
7651 		(void) set_term_encoding ("KOI8-R", ' ');
7652 	} else if (strisprefix ("l1", TERM + 6)) {
7653 		(void) set_term_encoding ("ISO-8859-1", ' ');
7654 	} else {
7655 		(void) set_term_encoding ("CP437", 'p');
7656 	}
7657   }
7658   if (strisprefix ("mac", TERM)) {
7659 	(void) set_term_encoding ("MacRoman", 'M');
7660   }
7661   if (strisprefix ("nsterm", TERM)) {
7662 	if (strcontains (TERM, "7")) {
7663 		(void) set_term_encoding ("ASCII", ' ');
7664 	} else if (streq ("+mac", TERM + 6)
7665 	   || streq ("-m", TERM + 6)
7666 	   || streq ("-m-s", TERM + 6)
7667 	   || streq ("", TERM + 6)
7668 	   || streq ("-c", TERM + 6)
7669 	   || streq ("-s", TERM + 6)
7670 	   || streq ("-c-s", TERM + 6)
7671 	) {
7672 		(void) set_term_encoding ("MacRoman", 'M');
7673 	}
7674   }
7675   if (strisprefix ("9780", TERM)) {
7676 	set_fkeymap ("siemens");
7677 	use_ascii_graphics = True;
7678 	menu_border_style = 'r';
7679   }
7680   if (strisprefix ("interix", TERM)) {
7681 	set_fkeymap ("interix");
7682 	use_mouse = False;
7683   }
7684 #ifdef assume_sco_dtterm_broken_default_font
7685   if (streq ("dtterm", TERM)) {
7686 	TABdefault = '.';
7687 	RETdefault = '<';
7688 	(void) set_term_encoding ("ASCII", ' ');
7689   }
7690 #endif
7691 #ifdef __ANDROID__
7692   if (streq ("screen", TERM)) {
7693 	/* Terminal Emulator (Jack Palevich) */
7694 	suppress_colour = True;
7695   }
7696 #endif
7697 
7698 
7699   if (! use_bold || menu_border_style == 'f' || menu_border_style == 'd') {
7700 	bold_border = False;
7701   }
7702 
7703 
7704 /* get/update ANSI screen mode configuration */
7705   get_ansi_modes ();	/* also calls determine_dim_mode */
7706 
7707 
7708 /* if request with option +E?, only report terminal encoding */
7709   if (only_detect_terminal_encoding) {
7710 	/* display character data version information (for +E? option) */
7711 	raw_mode (False);
7712 	print_terminal_info ();
7713 	exit (0);
7714   }
7715 
7716 
7717 /* remember determined default text encoding for further files */
7718   default_text_encoding = get_text_encoding ();
7719 
7720 /* read filter that defines which CJK encodings may be auto-detected */
7721   detect_encodings = envvar ("MINEDDETECT");
7722   /* if not defined, fallback to default set of auto-detected encodings */
7723   if (! detect_encodings) {
7724 	detect_encodings = "BGC JSXx KH LWP";
7725   }
7726 
7727 
7728 /* get preconfigured smart quotes style */
7729   preselect_quote_style = envvar ("MINEDQUOTES");
7730 
7731 
7732 /* get selection of Han character information to be displayed */
7733   env = envvar ("MINEDHANINFO");
7734   if (env) {
7735 	if (* env) {
7736 		always_disp_Han = True;
7737 		disp_Han_description = False;
7738 		disp_Han_full = False;
7739 	} else {
7740 		always_disp_Han = False;
7741 	}
7742 	if (strchr (env, 'M') != NIL_PTR) {
7743 		disp_Han_Mandarin = True;
7744 	}
7745 	if (strchr (env, 'C') != NIL_PTR) {
7746 		disp_Han_Cantonese = True;
7747 	}
7748 	if (strchr (env, 'J') != NIL_PTR) {
7749 		disp_Han_Japanese = True;
7750 	}
7751 	if (strchr (env, 'S') != NIL_PTR) {
7752 		disp_Han_Sino_Japanese = True;
7753 	}
7754 	if (strchr (env, 'H') != NIL_PTR) {
7755 		disp_Han_Hangul = True;
7756 	}
7757 	if (strchr (env, 'K') != NIL_PTR) {
7758 		disp_Han_Korean = True;
7759 	}
7760 	if (strchr (env, 'V') != NIL_PTR) {
7761 		disp_Han_Vietnamese = True;
7762 	}
7763 	if (strchr (env, 'P') != NIL_PTR) {
7764 		disp_Han_HanyuPinlu = True;
7765 	}
7766 	if (strchr (env, 'Y') != NIL_PTR) {
7767 		disp_Han_HanyuPinyin = True;
7768 	}
7769 	if (strchr (env, 'X') != NIL_PTR) {
7770 		disp_Han_XHCHanyuPinyin = True;
7771 	}
7772 	if (strchr (env, 'T') != NIL_PTR) {
7773 		disp_Han_Tang = True;
7774 	}
7775 	if (strchr (env, 'D') != NIL_PTR) {
7776 		disp_Han_description = True;
7777 	}
7778 	if (strchr (env, 'F') != NIL_PTR) {
7779 		disp_Han_description = True;
7780 		disp_Han_full = True;
7781 	}
7782   }
7783 
7784 
7785   setup_temp_filenames ();
7786 
7787 
7788 /* determine default permission setting for new files */
7789   fprot0 = ~ umask (0) & 0666;
7790 
7791 /* option +@: grooming .@mined */
7792   if (groom_stat) {
7793 	GROOM_INFO ();
7794 	if (argi < 0) {
7795 		raw_mode (False);
7796 		exit (0);
7797 	}
7798   }
7799 
7800 
7801 /* ----------------------------------------------------------------------- */
7802 
7803 /* prepare editing buffer */
7804   header = tail = alloc_header (); /* Make header of list */
7805   if (header == NIL_LINE) {
7806 	panic ("Cannot allocate memory", NIL_PTR);
7807   }
7808   header->text = NIL_PTR;
7809   header->next = tail->prev = header;
7810   header->syntax_mask = syntax_none;
7811   header->sel_begin = NIL_PTR;
7812   header->sel_end = NIL_PTR;
7813 
7814 /* load the file (if any) */
7815   if (argi < 0) {
7816 	if (! only_detect_text_encoding) {
7817 		if (homedir_selected) {
7818 			(void) chdir (gethomedir ());
7819 		}
7820 		load_wild_file (NIL_PTR, reading_pipe, False);
7821 	}
7822   } else {
7823 	load_wild_file (filelist_get (argi), False, False);
7824   }
7825   trace_encoding ("load");
7826 
7827   if (only_detect_text_encoding) {
7828 	raw_mode (False);
7829 	if (argi < 0) {
7830 		printf ("%s\n", get_text_encoding ());
7831 	} else {
7832 		printf ("%s: %s\n", filelist_get (argi), get_text_encoding ());
7833 		viewonly_mode = True;
7834 		while (argi + 1 < filelist_count ()) {
7835 			argi ++;
7836 			raw_mode (True);
7837 			load_wild_file (filelist_get (argi), False, True);
7838 			raw_mode (False);
7839 			printf ("%s: %s\n", filelist_get (argi), get_text_encoding ());
7840 		}
7841 	}
7842 	exit (0);
7843   }
7844 
7845   loading = True;	/* keep loading flag True until entering main loop */
7846 
7847   if (initlini != 0) {
7848      (void) scan_int (argv [initlini] + 1, & initlinenum);
7849      if (initlinenum > 0) {
7850 	if (initlinenum <= 0 || (initline = proceed (header->next, initlinenum - 1)) == tail) {
7851 	   error2 ("Invalid line number: ", dec_out ((long) initlinenum));
7852 	} else {
7853 	   move_to (x, find_y_w_o_RD (initline));
7854 	   fstatus ("Loaded", -1L, -1L);
7855 	}
7856      }
7857   }
7858 
7859   if (inisearch != NIL_PTR) {
7860 	if (search_ini (inisearch, FORWARD, True) == False) {
7861 		sleep (1);	/* show "not found" message */
7862 	}
7863 	if (! viewing_help) {
7864 		fstatus ("Loaded", -1L, -1L);
7865 	}
7866   }
7867 
7868   if (writing_pipe) {
7869 	file_name [0] = '\0'; /* don't let user believe he's editing a file */
7870 	fstatus ("Editing for standard output", -1L, -1L);
7871   } else if (reading_pipe) {
7872 	file_name [0] = '\0'; /* switch from [standard input] to [no file] */
7873   }
7874 
7875   loading = False;
7876   catch_signals ();
7877 
7878 /* display text which was postponed for the sake of +N or +/expr options */
7879   display (0, top_line, last_y, 0);
7880   flush ();
7881 
7882   trace_encoding ("main");
7883 /* main loop of the editor */
7884   for (;;) {
7885 	/* FLAG cursor_somewhere = False; */
7886 	if (last_mouse_event == releasebutton && in_selection_mouse_mode) {
7887 		selection_mouse_mode (False);
7888 	}
7889 	/* update selection highlighting */
7890 	display_flush ();
7891 	/* ... cursor_somewhere = True; */
7892 
7893 	/* display status line contents unless there is a message */
7894 	if (! stat_visible) {
7895 		if (ext_status != NIL_PTR) {
7896 			/* interpret status text in terminal encoding? */
7897 			/*?*/
7898 			/* interpret status text in text file encoding? */
7899 			/*status_fmt2 (ext_status, NIL_PTR);*/
7900 			/* interpret status text in Unicode */
7901 			status_uni (ext_status);
7902 		} else if (always_disp_fstat) {
7903 			FSTATUS ();
7904 		} else if (always_disp_code) {
7905 			display_the_code ();
7906 		} else if (always_disp_Han && ! disp_Han_full) {
7907 			display_Han (cur_text, False);
7908 		} else if (always_disp_help) {
7909 			display_FHELP ();
7910 		}
7911 	}
7912 	if (always_disp_Han && disp_Han_full) {
7913 		display_Han (cur_text, False);
7914 	}
7915 
7916 	if ((hop_flag_displayed && ! hop_flag) || (hop_flag && ! hop_flag_displayed)) {
7917 		/* since hop_flag is often cleared on-the-fly as needed in
7918 		   editing functions, we need extra detection and handling
7919 		 */
7920 		flags_changed = True;
7921 	}
7922 
7923 	/* refresh display items (top line, scrollbar, cursor position) */
7924 	if (MENU && top_line_dirty) {
7925 		displaymenuline (True);
7926 		flags_changed = False;
7927 		/*cursor_somewhere = True;*/
7928 	}
7929 	if (text_screen_dirty) {
7930 		RDwin ();
7931 		text_screen_dirty = False;
7932 	}
7933 	if (MENU && flags_changed) {
7934 		displayflags ();
7935 		/*cursor_somewhere = True;*/
7936 	}
7937 	if (disp_scrollbar) {
7938 		if (display_scrollbar (update_scrollbar_lazy)) {
7939 			/*cursor_somewhere = True;*/
7940 		}
7941 	}
7942 /*
7943 	if (cursor_somewhere) {
7944 		set_cursor_xy ();
7945 	}
7946 */
7947 	set_cursor_xy ();
7948 
7949 	flush ();	/* Flush output (if any) */
7950 	debuglog (0, "flush", 0);
7951 
7952 input:
7953 
7954 	if (key_replaying) {
7955 		inputchar = KEYreplay ();	/* also set keyshift */
7956 	} else {
7957 		do {
7958 			inputchar = readcharacter_unicode_mapped ();
7959 			trace_keytrack ("main", inputchar);
7960 		} while (inputchar == CHAR_UNKNOWN);
7961 	}
7962 	if (key_recording) {
7963 		KEYrecord (inputchar);		/* also log keyshift */
7964 	}
7965 
7966 	if (command (inputchar) != Scharacter
7967 	 && command (inputchar) != Sdash
7968 	 && command (inputchar) != Ssinglequote
7969 	 && command (inputchar) != Sdoublequote
7970 	   ) {
7971 		reset_smart_replacement ();
7972 	}
7973 
7974 	if (command (inputchar) != Scharacter) {
7975 		keyproc = command (inputchar);
7976 		inputchar = FUNcmd;
7977 	} else {
7978 		inputchar = encodedchar (inputchar);
7979 	}
7980 
7981 #ifdef adjust_to_actual_termsize
7982 	if (command (inputchar) == ANSIseq) {
7983 		ANSIseq ();
7984 		goto input;
7985 	}
7986 #endif
7987 
7988 	if (command (inputchar) == FOCUSin) {
7989 #ifdef debug_mouse
7990 		printf ("FOCUSin received\n");
7991 #endif
7992 		check_file_modified ();
7993 		goto input;
7994 	}
7995 
7996 	if (always_disp_Han) {
7997 		clean_menus ();
7998 	}
7999 
8000 	if (stat_visible) {
8001 		clear_status ();
8002 	}
8003 	if (quit == False) {	/* Call the function for the typed key */
8004 		invoke_key_function (inputchar);
8005 		if (hop_flag > 0) {
8006 			hop_flag --;
8007 			flags_changed = True;
8008 		}
8009 		if (buffer_open_flag > 0) {
8010 			buffer_open_flag --;
8011 #ifdef debug_ring_buffer
8012 			if (buffer_open_flag == 0) {
8013 				flags_changed = True;
8014 			}
8015 #endif
8016 		}
8017 	}
8018 	if (quit) {
8019 		if (hop_flag > 0) {
8020 			flags_changed = True;
8021 		}
8022 		CANCEL ();
8023 		quit = False;
8024 	}
8025   }
8026   /* NOTREACHED */
8027 }
8028 
8029 
8030 /*======================================================================*\
8031 |*		End							*|
8032 \*======================================================================*/
8033