/*======================================================================*\ |* Editor mined *| |* part 1 *| \*======================================================================*/ #include "mined.h" #include "textfile.h" #include "io.h" #include "encoding.h" #include "termprop.h" #include "version.h" /*======================================================================*\ |* Definitions specific for mined1.c *| \*======================================================================*/ /* system-specific command to print a UTF-8 file used as a last resort for printing */ # ifdef unix # ifdef sysV # ifdef __CYGWIN__ # define print_command "LC_ALL=en_US.UTF-8 lpr %s" # else # define print_command "LC_ALL=en_US.UTF-8 lp %s" # endif # else # define print_command "LC_ALL=en_US.UTF-8 lpr %s" # endif # endif # ifdef vms # define print_command "print %s" # endif # ifdef msdos # define print_command "copy %s prn: > nul:" # endif #ifdef msdos #ifdef __TURBOC__ #define msdos_screenfunctions #endif #endif /** How to deal with non-matching tty and terminal sizes. */ #define adjust_terminal_height #define dont_adjust_to_actual_termsize /* not fully implemented */ /*======================================================================*\ |* Local function declarations and FLAGs *| \*======================================================================*/ static char * get_terminal_report_string _((char * s)); static void CSI _((void)); static void OSC _((void)); static void CMD _((void)); /*======================================================================*\ |* Data section *| \*======================================================================*/ LINE * header; /* Head of line list */ LINE * tail; /* Last line in line list */ LINE * cur_line; /* Current line in use */ LINE * top_line; /* First line of screen */ LINE * bot_line; /* Last line of screen */ char * cur_text; /* Current char on current line in use */ int last_y; /* Last y of screen. Usually SCREENMAX */ int x = 0; /* screen column of current text position */ int y = 0; /* screen row of current text position */ int line_number; /* current line # determined by file_status */ int lines_per_page = 0; /* assumption for file_status */ int YMAX, XMAX; short MENU = 1; mousebutton_type mouse_button, mouse_lastbutton, mouse_prevbutton; FLAG window_focus = True; /* does the window have mouse/keyboard focus? */ FLAG report_release = False; int mouse_shift = 0; int mouse_xpos, mouse_ypos, mouse_lastxpos, mouse_lastypos; FLAG flags_changed = False; /* Should flag menu area be redrawn? */ FLAG quickmenu = True; /* Right mouse button pops up menu */ static int wheel_scroll = 3; /* Number of lines scrolled by mouse wheel */ int total_lines = 0; /* Number of lines in file */ long total_chars = -1L; /* Number of characters in file */ FLAG modified = False; /* Set when file is modified */ FLAG viewonly = False; /* Set when view only mode is selected */ FLAG append_flag = False; /* Set when buffer should be appended to */ FLAG pastebuf_utf8 = False; /* Paste buffer always treated as UTF-8? */ FLAG restricted = False; /* Set when edited file shall not be switched */ /* file-related properties */ lineend_type default_lineend = lineend_LF; /* used for some inserts */ FLAG writable; /* Set if file cannot be written */ FLAG file_is_dir; /* Tried to open a directory as file? */ int JUSlevel = 0; /* Keep justified while typing? */ int JUSmode = 0; /* 1: paragraphs end at empty line */ FLAG autoindent = True; /* Auto indent on input of Enter? */ FLAG dim_HTML = True; /* Display HTML dimmed ? */ FLAG loading = True; /* Loading a file? Init True for error handling */ static FLAG only_detect_text_encoding = False; static FLAG only_detect_terminal_encoding = False; FLAG quit = False; /* Set when quit character is typed */ FLAG intr_char = False; /* Set when intr character is typed */ FLAG winchg = False; /* Set when window size has changed */ FLAG interrupted = False; /* Set when a signal interrupts */ FLAG isscreenmode = False; /* Set when screen mode is on */ FLAG stat_visible; /* Set if status line is visible */ FLAG top_line_scrolled = False; /* Was menu line scrolled away? */ FLAG always_disp_fstat = False; /* Permanent file status display on status line? */ FLAG always_disp_help = False; /* Permanent F2... help display on status line? */ FLAG always_disp_code = False; /* Permanent char code display on status line? */ FLAG always_disp_Han = False; /* Permanent Han character description display on status line? */ FLAG disp_Han_Mandarin = False; /* display this Han pronunciation ? */ FLAG disp_Han_Cantonese = False; /* display this Han pronunciation ? */ FLAG disp_Han_Japanese = False; /* display this Han pronunciation ? */ FLAG disp_Han_Sino_Japanese = False; /* display this Han pronunciation ? */ FLAG disp_Han_Hangul = False; /* display this Han pronunciation ? */ FLAG disp_Han_Korean = False; /* display this Han pronunciation ? */ FLAG disp_Han_Vietnamese = False; /* display this Han pronunciation ? */ FLAG disp_Han_HanyuPinlu = False; /* display this Han pronunciation ? */ FLAG disp_Han_Tang = False; /* display this Han pronunciation ? */ FLAG disp_Han_description = True; /* display Han description ? */ FLAG disp_Han_full = True; /* display full Han description ? */ FLAG waitingforinput = False; /* Set while waiting for the next command key */ FLAG reading_pipe = False; /* Set if file should be read from stdin */ FLAG writing_pipe = False; /* Set if file should be written to stdout */ FLAG wordnonblank = False; /* Handle all non-blank sequences as words */ FLAG proportional = False; /* Enable support for proportional fonts? */ int hide_password_mode = 1; /* Hide / Hide in dot files / Show */ FLAG hide_password = False; /* Hide passwords in display */ FLAG auto_detect = True; /* Auto detect character encoding from file ? */ char * detect_encodings; /* List of encodings to detect */ static char language_tag = 0; FLAG translate_output = False; /* Transform output diacritics to strings */ int translen; /* length of " */ char * transout; /* Output transformation table */ int tabsize = 8; /* Width of tab positions, 4 or 8 */ FLAG expand_tabs = False; /* Expand TABs to Spaces? */ FLAG controlQS = False; /* must respect ^Q/^S handshake ? */ FLAG insert_mode = True; /* insert or overwrite */ character erase_char = '\010'; /* effective (configured) char for erase left */ char emulation = ' '; /* 'w' for WordStar, 'e' for emacs */ FLAG emacs_buffer = False; /* enable emacs buffer fct for ^K/^T */ FLAG paste_stay_left = False; /* cursor stays before pasted region */ character quit_char = '\034'; /* ^\/^G character to cancel command */ FLAG Turkish = False; /* use Turkish case toggle specials ? */ FLAG Lithuanian = False; /* use Lithuanian case toggle specials ? */ FLAG smart_quotes = True; /* replace " with typographic quote ? */ static FLAG combining_screen_selected = False; /* explicitly selected ? */ static FLAG term_encoding_selected = False; /* explicitly selected ? */ static FLAG text_encoding_selected = False; /* explicitly selected ? */ static FLAG limited_marker_font = False; /* -F to limit font usage? */ static FLAG very_limited_marker_font = False; /* -FF to limit font usage? */ FLAG suppress_unknown_cjk = True; /* on CJK terminal if no Unicode mapping */ FLAG suppress_extended_cjk = True; /* on CJK terminal if in extended code range */ FLAG suppress_invalid_cjk = True; /* on CJK terminal if invalid CJK code */ FLAG suppress_surrogates = True; /* suppress display of single Unicode surrogates */ FLAG suppress_EF = True; /* suppress display of 0x*FFFE/F codes */ FLAG suppress_non_Unicode = True; /* suppress display of non-Unicode codes */ FLAG utf_cjk_wide_padding = False; /* always display CJK on UTF double-width ? */ #ifdef pc_term FLAG dark_term = True; /* PC terminal */ #else FLAG dark_term = False; /* dark colour terminal ? */ #endif FLAG bw_term = False; /* black/white terminal ? */ static int terminal_type = -9; static int terminal_version = -9; FLAG configure_xterm_keyboard = False; /* deleteIsDEL, metaSendsEscape */ int hop_flag = 0; /* Counter flag for the HOP function */ FLAG cjk_text = False; /* text in CJK encoding ? */ FLAG utf8_text = False; /* text in UTF-8 representation ? */ FLAG utf16_file = False; /* file encoded in UTF-16 ? */ FLAG utf16_little_endian = False; /* UTF-16 file encoded little endian ? */ FLAG mapped_text = False; /* text in 8 bit, non-Latin-1 representation ? */ FLAG utf8_lineends = True; /* detect UTF-8 LS and PS line ends ? */ FLAG poormansbidi = True; /* poor man's bidirectional support ? */ FLAG combining_mode = False; /* UTF-8 combining character display support ? */ FLAG separate_isolated_combinings = True; /* separated display of comb. at line beg./after TAB ? */ FLAG disp_scrollbar = True; /* shall scrollbar be displayed ? */ FLAG fine_scrollbar = True; /* fine-grained UTF-8 scrollbar ? */ int scrollbar_width = 1; FLAG update_scrollbar_lazy = True; /* partial scrollbar refresh as needed ? */ FLAG no_window_title = False; /* suppress filename display in window title? */ static FLAG combining_mode_disabled = False; /* combining mode explicitly disabled ? */ static FLAG U_mode_set = False; FLAG mined_keypad = True; /* Apply mined keypad assignments */ FLAG detect_esc_alt = True; /* Enable detection of Alt key by ESC prefix? */ char selection_space = SPACE_NEXT; /* space behaviour in keyboard mapping menu */ FLAG enforce_keymap = False; /* enable keyboard mapping even on non-suitable terminal */ FLAG page_scroll = False; /* use scroll for page up/down */ FLAG page_stay = False; /* stay at edge of screen after page up/down */ int display_delay = 3; /* delay between display lines */ FLAG paradisp = False; /* Shall paragraph end be distinguished? */ long chars_saved; /* # of chars in paste buffer */ long bytes_saved; /* # of bytes in paste buffer */ int lines_saved; /* # of lines in paste buffer */ int input_fd = STD_IN; /* File descriptors for terminal dialog */ #ifdef __EMX__ int output_fd = STD_OUT; #else int output_fd = STD_ERR; #endif char text_buffer [MAX_CHARS]; /* for get_line, modifications, build_string */ char file_name [maxLINE_LEN]; /* Name of file in use */ #ifdef vms unsigned int fprot0 = 0; /* default prot. mode for new files */ unsigned int fprot1 = 0; /* prot. mode for new file being edited */ unsigned int bufprot = 0; /* prot. mode for paste buffer file */ static unsigned int exeprot = 0; /* default prot. mask for executables */ #else PROT fprot0 = 0644; /* default prot. mode for new files */ PROT fprot1 = 0; /* prot. mode for new file being edited */ PROT bufprot = 0600; /* prot. mode for paste buffer file */ static PROT exeprot = 0111; /* default prot. mask for executables */ #endif PROT xprot = 0; /* actual prot. mask representing +x option */ char * inisearch = NIL_PTR; /* Optional startup search string */ #ifdef unix /* window headline and icon text setting */ char * window_string_code = ""; char * mined_modf = " (*)"; #endif /** Yank variables */ char * temp_dir; char yank_file [maxLINE_LEN]; char yankie_file [maxLINE_LEN]; char html_file [maxLINE_LEN]; /* temp. file for HTML embedding buffer */ char panic_file [maxLINE_LEN]; /** Line indicators */ static char TABdefault = ''; /* default TAB indicator */ static char RETdefault = ''; /* indicates line end */ static char PARAdefault = ''; /* indicates end of paragraph */ char UNI_marker = ''; /* Char to be shown in place of Unicode char */ char TAB_marker = ' '; /* Char to be shown in place of tab chars */ char TAB0_marker = '\0'; /* Char to be shown at start of tab chars */ char TAB2_marker = '\0'; /* Char to be shown at end of tab chars */ char TABmid_marker = '\0'; /* Char to be shown in middle of tab chars */ unsigned long CJK_TAB_marker = 0x2026; /* to be shown in place of tab */ char RET_marker = '\0'; /* Char indicating end of line (LF) */ char DOSRET_marker = '\0'; /* Char indicating DOS end of line (CRLF) */ char MACRET_marker = '\0'; /* Char indicating Mac end of line (CR) */ char PARA_marker = '\0'; /* Char indicating end of paragraph */ char RETfill_marker = '\0'; /* Char to fill the end of line with */ char RETfini_marker = '\0'; /* Char to fill last position of line with */ char SHIFT_marker = ''; /* Char indicating that line continues */ char SHIFT_BEG_marker = ''; /* Char indicating that line continues left */ char MENU_marker = '*'; /* Char to mark selected item */ char * UTF_TAB_marker = NIL_PTR; /* Char to be shown in place of tab chars */ char * UTF_TAB0_marker = NIL_PTR; /* Char to be shown at start of tab chars */ char * UTF_TAB2_marker = NIL_PTR; /* Char to be shown at end of tab chars */ char * UTF_TABmid_marker = NIL_PTR; /* Char to be shown in middle of tab chars */ char * UTF_RET_marker = NIL_PTR; /* Char indicating end of line */ char * UTF_DOSRET_marker = NIL_PTR; /* Char indicating DOS end of line */ char * UTF_MACRET_marker = NIL_PTR; /* Char indicating Mac end of line */ char * UTF_PARA_marker = NIL_PTR; /* Char indicating end of paragraph */ char * UTF_RETfill_marker = NIL_PTR; /* Char to fill the end of line with */ char * UTF_RETfini_marker = NIL_PTR; /* Char to fill last position of line with */ char * UTF_SHIFT_marker = NIL_PTR; /* Char indicating that line continues */ char * UTF_SHIFT_BEG_marker = NIL_PTR; /* Char indicating that line continues left */ char * UTF_MENU_marker = "✓"; /* Char to mark selected item */ static char * UTF_MENU_marker_fancy = "☛"; static char * UTF_MENU_marker_alt = "►"; /*======================================================================*\ |* Text string routines *| \*======================================================================*/ int UTF8_len (c) char c; { if ((c & 0x80) == 0x00) { return 1; } else if ((c & 0xE0) == 0xC0) { return 2; } else if ((c & 0xF0) == 0xE0) { return 3; } else if ((c & 0xF8) == 0xF0) { return 4; } else if ((c & 0xFC) == 0xF8) { return 5; } else if ((c & 0xFE) == 0xFC) { return 6; } else { /* illegal UTF-8 code */ return 1; } } int CJK_len (text) character * text; { if (multichar (* text)) { if (text_encoding_tag == 'C' && * text == 0x8E) { return 4; } else if (text_encoding_tag == 'J' && * text == 0x8F) { return 3; } else if (text_encoding_tag == 'G' && * (text + 1) <= '9' && * (text + 1) >= '0') { return 4; } else { return 2; } } else { return 1; } } /* * char_count () returns the number of characters in the string * excluding the '\0'. */ int char_count (string) char * string; { int count = 0; if (string != NIL_PTR) { while (* string != '\0') { advance_char (& string); count ++; } } return count; } /* * col_count () returns the number of screen columns in the string */ int col_count (string) char * string; { int count = 0; char * start = string; if (string != NIL_PTR) { while (* string != '\0') { advance_char_scr (& string, & count, start); } } return count; } /** determine Unicode information from UTF-8 character return parameters: length: the number of UTF-8 bytes in the character ucs: its Unicode value */ void utf8_info (u, length, ucs) char * u; int * length; unsigned long * ucs; { char * textpoi = u; character c = * textpoi; int utfcount; unsigned long unichar; if ((c & 0x80) == 0x00) { utfcount = 1; unichar = c; } else if ((c & 0xE0) == 0xC0) { utfcount = 2; unichar = c & 0x1F; } else if ((c & 0xF0) == 0xE0) { utfcount = 3; unichar = c & 0x0F; } else if ((c & 0xF8) == 0xF0) { utfcount = 4; unichar = c & 0x07; } else if ((c & 0xFC) == 0xF8) { utfcount = 5; unichar = c & 0x03; } else if ((c & 0xFE) == 0xFC) { utfcount = 6; unichar = c & 0x01; } else if (c == 0xFE) { /* illegal UTF-8 code */ utfcount = 1; unichar = '4'; } else if (c == 0xFF) { /* illegal UTF-8 code */ utfcount = 1; unichar = '5'; } else { /* illegal UTF-8 sequence character */ utfcount = 1; unichar = '8'; } * length = utfcount; utfcount --; textpoi ++; while (utfcount > 0 && (* textpoi & 0xC0) == 0x80) { unichar = (unichar << 6) | (* textpoi & 0x3F); utfcount --; textpoi ++; } if (utfcount > 0) { /* too short UTF-8 sequence */ unichar = (character) ''; * length -= utfcount; } * ucs = unichar; } /** Determine if a Unicode character is joined to a ligature with the previous character in the string or line (which may be in any encoding). */ int isjoined (unichar, charpos, linebegin) unsigned long unichar; char * charpos; char * linebegin; { unsigned long prev_unichar; if (bidi_screen && encoding_has_combining ()) { if (unichar == 0x0622 || unichar == 0x0623 || unichar == 0x0625 || unichar == 0x0627) { /* ALEF may be joined to a ligature with preceding LAM */ precede_char (& charpos, linebegin); prev_unichar = unicodevalue (charpos); if (prev_unichar == 0x0644) { /* LAM joins to a ligature with any of the above */ return 1; } } } return 0; } /** Determine if a Unicode character is effectively of zero width, i.e. if it combines with the previous character in the string or line (which may be in any encoding). */ int iscombined (unichar, charpos, linebegin) unsigned long unichar; char * charpos; char * linebegin; { if (mapped_term && no_char (mappedtermchar (unichar))) { return False; } return isjoined (unichar, charpos, linebegin) || iscombining (unichar); } int iscombining (ucs) unsigned long ucs; { if (mapped_term && no_char (mappedtermchar (ucs))) { return False; } else { return term_iscombining (ucs); } } int iswide (ucs) unsigned long ucs; { if (ucs & 0x80000000) { /* special encoding of 2 Unicode chars, mapped from 1 CJK character */ if ((ucs & 0xFFF3) == 0x02E1) { /* 0x02E9 0x02E5 or 0x02E5 0x02E9 */ return 1; } else { /* strip accent indication for width lookup */ ucs &= 0xFFFF; } } return term_iswide (ucs); } /** Determine the effective screen width of a Unicode character. */ int uniscrwidth (unichar, charpos, linebegin) unsigned long unichar; char * charpos; char * linebegin; { if (combining_mode && iscombined (unichar, charpos, linebegin)) { if (separate_isolated_combinings) { if (charpos == linebegin || * (charpos - 1) == '\t') { if (iswide (unichar)) { return 2; } else { return 1; } } } return 0; } if (mapped_term || (cjk_term && ! cjk_uni_term)) { unsigned long cjktermchar = mappedtermchar (unichar); if (! no_char (cjktermchar)) { if (cjktermchar < 0x100) { return 1; } else if (term_encoding_tag == 'J' && (cjktermchar >> 8) == 0x8E) { return 1; } else { return 2; } } } if (iswide (unichar)) { return 2; } else { return 1; } } /** Determine the effective screen width of a CJK character. */ int cjkscrwidth (cjkchar, charpos, linebegin) unsigned long cjkchar; char * charpos; char * linebegin; { char encoding_tag; if (! cjk_term || cjk_uni_term) { unsigned long unichar = lookup_encodedchar (cjkchar); if (no_unichar (unichar) && ! valid_cjk (cjkchar, NIL_PTR)) { return 1; } else if (combining_mode && iscombined (unichar, charpos, linebegin)) { if (separate_isolated_combinings) { if (charpos == linebegin || * (charpos - 1) == '\t') { if (utf_cjk_wide_padding || iswide (unichar)) { return 2; } else { return 1; } } } return 0; } else if (utf_cjk_wide_padding || iswide (unichar)) { return 2; } else if (no_unichar (unichar) && cjk_term) { return 2; } else { return 1; } } encoding_tag = text_encoding_tag; if (mapped_term || (cjk_term && remap_chars ())) { unsigned long unichar = lookup_encodedchar (cjkchar); if (! no_unichar (unichar)) { unsigned long cjktermchar = mappedtermchar (unichar); if (! no_char (cjktermchar)) { cjkchar = cjktermchar; encoding_tag = term_encoding_tag; } } } if (cjkchar < 0x100) { return 1; } else if (encoding_tag == 'J' && (cjkchar >> 8) == 0x8E) { return 1; } else { return 2; } } /* * Advance only character pointer to next character. * UTF-8 mode. */ void advance_utf8 (poipoi) char * * poipoi; { int follow = UTF8_len (* * poipoi) - 1; (* poipoi) ++; while (follow > 0 && (* * poipoi & 0xC0) == 0x80) { (* poipoi) ++; follow --; } } /* * Advance only character pointer to next character. * CJK mode. */ static void advance_cjk (poipoi) char * * poipoi; { int len = CJK_len (* poipoi); (* poipoi) ++; len --; while (len > 0 && * * poipoi != '\0' && * * poipoi != '\n') { (* poipoi) ++; len --; } } /* * Advance only character pointer to next character. * Handle tab characters and different character encodings correctly. */ void advance_char (poipoi) char * * poipoi; { if (utf8_text) { advance_utf8 (poipoi); } else if (cjk_text) { advance_cjk (poipoi); } else { (* poipoi) ++; } } /* charbegin () determines the first byte of the character pointed to in the given line */ char * charbegin (line, s) char * line; char * s; { char * char_search; char * char_prev; if (utf8_text || cjk_text) { char_search = line; char_prev = char_search; while (char_search < s) { char_prev = char_search; advance_char (& char_search); } if (char_search > s) { return char_prev; } else { return s; } } return s; } /* * precede_char () moves the character pointer within line "begin_line" * left by 1 character */ void precede_char (poipoi, begin_line) char * * poipoi; char * begin_line; { if (utf8_text) { char * char_search = * poipoi; int l = 0; while (char_search != begin_line && l < 6) { char_search --; l ++; if ((* char_search & 0xC0) != 0x80) { break; } } if (l > 0 && l > UTF8_len (* char_search)) { (* poipoi) --; } else { * poipoi = char_search; } } else if (cjk_text) { char * char_search = begin_line; char * char_prev = char_search; while (char_search < * poipoi) { char_prev = char_search; advance_cjk (& char_search); } * poipoi = char_prev; } else if (* poipoi != begin_line) { (* poipoi) --; } } /* * utf8value () determines the value of the UTF-8 character pointed to */ unsigned long utf8value (poi) character * poi; { int len; unsigned long unichar; utf8_info (poi, & len, & unichar); return unichar; } /* * charvalue () determines the value of the character pointed to */ unsigned long charvalue (poi) character * poi; { int len; if (utf8_text) { unsigned long unichar; utf8_info (poi, & len, & unichar); return unichar; } else if (cjk_text && multichar (* poi)) { unsigned long cjkchar; len = CJK_len (poi); cjkchar = * poi ++; len --; while (len > 0 && * poi != '\0' && * poi != '\n') { cjkchar = (cjkchar << 8) | * poi ++; len --; } if (len > 0) { return CHAR_INVALID; } else { return cjkchar; } } else { return * poi; } } /** unicode () returns the Unicode value of the character code */ unsigned long unicode (code) unsigned long code; { if (cjk_text || mapped_text) { return lookup_encodedchar (code); } else { return code; } } /** unicodevalue () determines the Unicode value of the character pointed to */ unsigned long unicodevalue (poi) character * poi; { return unicode (charvalue (poi)); } /* * precedingchar () determines the preceding character value */ unsigned long precedingchar (curpoi, begin_line) char * curpoi; char * begin_line; { char * poi; if (curpoi == begin_line) { return '\n'; } else { poi = curpoi; precede_char (& poi, begin_line); return charvalue (poi); } } /* * Advance character pointer and screen column counter to next character. * UTF-8 mode. */ void advance_utf8_scr (poipoi, colpoi, linebegin) char * * poipoi; int * colpoi; char * linebegin; { unsigned long unichar; int follow; utf8_info (* poipoi, & follow, & unichar); (* colpoi) += uniscrwidth (unichar, * poipoi, linebegin); follow --; (* poipoi) ++; while (follow > 0 && (* * poipoi & 0xC0) == 0x80) { (* poipoi) ++; follow --; } } /* * Advance character pointer and screen column counter to next character. * Handle tab characters and different character encodings correctly. */ void advance_char_scr (poipoi, colpoi, linebegin) char * * poipoi; int * colpoi; char * linebegin; { int len; unsigned long unichar; if (is_tab (* * poipoi)) { * colpoi = tab (* colpoi); (* poipoi) ++; } else if (utf8_text) { advance_utf8_scr (poipoi, colpoi, linebegin); } else if (cjk_text) { len = CJK_len (* poipoi); (* colpoi) += cjkscrwidth (charvalue (* poipoi), * poipoi, linebegin); /* make sure pointer is incremented at least once in case it's \n */ (* poipoi) ++; len --; while (len > 0 && * * poipoi != '\0' && * * poipoi != '\n') { (* poipoi) ++; len --; } } else if (mapped_text) { unichar = lookup_encodedchar ((character) * * poipoi); if (combining_mode && iscombined (unichar, * poipoi, linebegin)) { if (separate_isolated_combinings) { if (* poipoi == linebegin || * (* poipoi - 1) == '\t') { if (iswide (unichar)) { (* colpoi) += 2; } else { (* colpoi) ++; } } } else { /* * colpoi stays where it is */ } } else if (cjk_term || cjk_width_data_version) { (* colpoi) += uniscrwidth (unichar, * poipoi, linebegin); } else { (* colpoi) ++; } (* poipoi) ++; } else if (cjk_term || cjk_width_data_version) { (* colpoi) += uniscrwidth ((character) * * poipoi, * poipoi, linebegin); (* poipoi) ++; } else { (* colpoi) ++; (* poipoi) ++; } } /*======================================================================*\ |* Web marker insertion *| \*======================================================================*/ /* Strip string from first blank. */ static void strip (s) char * s; { while (* s != '\0' && * s != ' ') { s ++; } * s = '\0'; } /* Turn string single-line (replace line-ends with space). */ static void unwrap (s) char * s; { while (* s != '\0') { if (* s == '\n') { * s = ' '; } s ++; } } /* Insert string buffer. */ static void Sbuf (s) char * s; { while (* s) { S0 (* s ++); } } static void embed_HTML () { char marker [maxLINE_LEN]; char tag [maxLINE_LEN]; if (viewonly) { viewonlyerr (); return; } if (get_string_nokeymap ("Embed text in HTML marker:", marker, True, "") != FINE) { return; } unwrap (marker); yank_HTML (DELETE); S0 ('<'); if ((marker [0] == 'A' || marker [0] == 'a') && marker [1] == '\0') { S0 (marker [0]); Sbuf (" href="); } else { Sbuf (marker); } S0 ('>'); paste_HTML (); S0 ('<'); S0 ('/'); strcpy (tag, marker); strip (tag); Sbuf (tag); S0 ('>'); } static char HTMLmarker [maxLINE_LEN]; static FLAG HTMLmarking = False; void HTML () { if (viewonly) { viewonlyerr (); return; } if (hop_flag > 0) { hop_flag = 0; embed_HTML (); } else { keyshift = 0; if (HTMLmarking == False) { if (FINE != get_string_nokeymap ("Begin HTML marker:", HTMLmarker, True, "")) { return; } unwrap (HTMLmarker); clear_status (); S0 ('<'); Sbuf (HTMLmarker); S0 ('>'); HTMLmarking = True; } else { S0 ('<'); S0 ('/'); strip (HTMLmarker); Sbuf (HTMLmarker); S0 ('>'); HTMLmarking = False; } } } /*======================================================================*\ |* Window resize and title handling *| \*======================================================================*/ #ifdef unix /* * Set window headline and icon text */ static void build_header (ws, fn, modf) char * ws; char * fn; char * modf; { if (strcontains (window_string_code, "%d")) { /* hpterm */ int len = strlen (fn) + strlen (modf); build_string (ws, window_string_code, len, fn, modf, len, fn, modf); } else { build_string (ws, window_string_code, fn, modf, fn, modf); } } void RD_window_title () { char window_string [MAX_CHARS]; char filename_ok [maxLINE_LEN]; char * filename_dispoi; char * filename_poi; static char title_encoding = ' '; #define dont_debug_window_title if (title_encoding == ' ') { if (konsole_version > 0) { /* locale dependent */ title_encoding = 'T'; /* terminal encoding */ } else if (gnome_terminal_version > 0) { /* probably gnome-terminal */ /* locale dependent */ title_encoding = 'T'; /* terminal encoding */ } else if (xterm_version >= 213) { if (utf8_screen) { char * r = get_terminal_report_string ("\033]2;xx\033[21t"); if (! r [0]) { /* no response, assume non-xterm */ title_encoding = 'U'; /* UTF-8 */ } else if (r [2] == '') { /* only with utf8Title: false */ title_encoding = 'L'; /* Latin-1 */ } else { /* only with utf8Title: true */ title_encoding = 'U'; /* UTF-8 */ } #ifdef debug_window_title printf ("window title:"); while (* r) { printf (" %02X%c", (character) * r, * r); r ++; } printf ("\n"); #endif } else { title_encoding = 'L'; /* Latin-1 */ } } else if (xterm_version >= 201) { title_encoding = 'L'; /* Latin-1 */ } else if (xterm_version > 0 && utf8_screen) { title_encoding = 'A'; /* ASCII */ } else if (rxvt_version > 0) { /* locale dependent ? */ title_encoding = 'L'; /* Latin-1 */ } else { title_encoding = 'L'; /* Latin-1 */ } if (title_encoding == ' ') { if (utf8_screen) { title_encoding = 'U'; /* UTF-8 */ } else { title_encoding = 'L'; /* Latin-1 */ } } } filename_poi = file_name; filename_dispoi = filename_ok; while (* filename_poi != '\0') { unsigned long c = unicodevalue (filename_poi); if (no_unichar (c) || c < (character) ' ' || (c >= 0x80 && c < 0xA0)) { * filename_dispoi ++ = '?'; } else if (title_encoding == 'L' && c >= 0x100) { * filename_dispoi ++ = '?'; } else if (title_encoding == 'A' && c >= 0x80) { * filename_dispoi ++ = '?'; } else if (title_encoding == 'U') { filename_dispoi += utfencode (c, filename_dispoi); } else { if (utf8_screen) { filename_dispoi += utfencode (c, filename_dispoi); } else if (cjk_term) { filename_dispoi += cjkencode_char (True, charvalue (filename_poi), filename_dispoi); } else { * filename_dispoi ++ = (character) c; } } advance_char (& filename_poi); } * filename_dispoi = '\0'; if (loading == False) { build_header (window_string, file_name [0] == '\0' ? empty_buffer_name : filename_ok, modified ? mined_modf : ""); /* putescape (window_string); */ /* Mind! As long as screen buffer shared with file buffer: */ write (output_fd, window_string, (unsigned int) length_of (window_string)); } } void clear_window_title () { char window_string [MAX_CHARS]; build_header (window_string, " ", " "); /* putescape (window_string); */ /* Mind! As long as screen buffer shared with file buffer: */ write (output_fd, window_string, (unsigned int) length_of (window_string)); } #endif /* * Redraw the screen */ static void RD_nobot () { reverse_off (); clearscreen (); /* display page */ display (0, top_line, last_y, y); /* redraw scroll bar */ if (disp_scrollbar && ! winchg) { (void) display_scrollbar (False); } /* clear/redraw last line */ set_cursor (0, YMAX); clear_lastline (); move_address (cur_text, find_y_w_o_RD (cur_line)); #ifdef unix RD_window_title (); #endif } void RD () { RD_nobot (); if (stat_visible) { rd_bottom_line (); } } void RD_y (y_pos) int y_pos; { reverse_off (); clearscreen (); /* display page */ display (0, top_line, last_y, y_pos); /* clear/redraw last line */ set_cursor (0, YMAX); clear_lastline (); if (stat_visible) { rd_bottom_line (); } } /* * Adjust current window size after WINCH signal */ static void RDwin_menu (rd_menu) FLAG rd_menu; { winchg = False; getwinsize (); #ifdef adjust_to_actual_termsize putescape ("\033[18t"); flush (); if (char_ready_within (...)) { c = readcharacter ();... if (command (c) == ANSIseq) { ANSIseq (); ... but without RD which is actually done here ... in both cases, reset the variables below, however ... } } #endif if (loading == False) { LINE * current_line = cur_line; reset (top_line, y); /* move_y (find_y_w_o_RD (current_line)); */ move_address (cur_text, find_y_w_o_RD (current_line)); RD_nobot (); if (MENU && ! winchg) { displaymenuline (); set_cursor_xy (); if (rd_menu) { redrawmenu (); } } } if (stat_visible && ! winchg) { rd_bottom_line (); } if (winchg) { RDwin (); } flush (); } void RDwin () { RDwin_menu (True); } void RDwin_nomenu () { RDwin_menu (False); } /*======================================================================*\ |* Screen size handling *| \*======================================================================*/ static void change_screen_size (sb, keep_columns) FLAG sb; FLAG keep_columns; { int index; int mode1; #ifdef msdos_screenfunctions int mode2; #endif /* Experimental area: */ /* set_screen_mode (mode1); any available mode number */ /* set_video_lines (mode1); 0/1/2: 200/350/400 lines */ /* does not seem to have any effect */ /* set_textmode_height (mode1); 0/1/2: font height 8/14/16 */ /* set_grafmode_height (mode1, mode2); 0/1/2: font height 8/14/16 1/2/3/n: 14/25/43/n lines */ /* set_fontbank (f); 0..7 */ /**/ if (hop_flag > 0) { #ifdef msdos_screenfunctions if (keep_columns) { if (sb == BIGGER) { index = get_number ("Switch to font bank (0..7) ", '\0', & mode1); if (index == ERRORS) { return; } set_fontbank (mode1); } else { index = get_number ("Set character height (<= 32 pixels) ", '\0', & mode1); if (index == ERRORS) { return; } set_font_height (mode1); } } else { if (sb == BIGGER) { #endif index = get_number ("Select video mode ", '\0', & mode1); if (index == ERRORS) { return; } set_screen_mode (mode1); #ifdef msdos_screenfunctions } else { index = get_number ("Select graf font (0/1/2: font height 8/14/16) ", '\0', & mode1); if (index == ERRORS) { return; } index = get_number ("Select line number (1/2/3/n: 14/25/43/n) ", '\0', & mode2); if (index == ERRORS) { return; } set_grafmode_height (mode1, mode2); /* 0/1/2: font height 8/14/16 */ /* 1/2/3/n: 14/25/43/n lines */ } } #endif } else { resize_the_screen (sb, keep_columns); } RDwin (); } void screenmorelines () { change_screen_size (BIGGER, True); } void screenlesslines () { change_screen_size (SMALLER, True); } void screenbigger () { change_screen_size (BIGGER, False); } void screensmaller () { change_screen_size (SMALLER, False); } void LNCI () { switch_textmode_height (True); RDwin (); } void LNSW () { if (hop_flag > 0) { hop_flag = 0; LNCI (); } else { switch_textmode_height (False); RDwin (); } } /*======================================================================*\ |* Generic command processing functions *| \*======================================================================*/ /* * return the mined command associated with the key value */ voidfunc command (c) unsigned long c; { if (c == FUNcmd) { return keyproc; } else if (c < arrlen (key_map)) { return key_map [c]; } else { return Scharacter; } } /** Invoke function associated with the key. */ void invoke_key_function (key) unsigned long key; { (command (key)) (key); } /* * BAD complains about unknown command characters. */ static void BAD (c, tag) unsigned long c; char * tag; { char cmdbuf [34]; char * cbuf = cmdbuf; strcpy (cmdbuf, "Unknown command: "); if (tag) { strcat (cmdbuf, tag); } while (* cbuf) { cbuf ++; } if (no_char (c)) { strcpy (cbuf, ""); } else if (c < ' ') { cbuf [0] = '^'; cbuf [1] = c + '@'; cbuf [2] = '\0'; } else { (void) utfencode (c, cbuf); } ring_bell (); status_uni (cmdbuf); } void BADch (c) unsigned long c; { BAD (c, ""); } /* * Ignore this keystroke. */ void I () { } /* * Fortifying 'HOP' key. */ void HOP () { hop_flag = 2; if (MENU) { displayflags (); set_cursor_xy (); flush (); } if (! char_ready_within (500)) { status_msg ("HOP: type command (to fortify) ..."); } } /* * Cancel prefix function. */ void CANCEL () { hop_flag = 0; clear_status (); } /* * Toggle insert/overwrite mode. */ void TOGINS () { if (insert_mode) { insert_mode = False; } else { insert_mode = True; } } #define cmd_char(c) (c < '\040' ? c + '\100' : (c >= '\140' ? c - '\040' : c)) /* * Interpret control-Q commands. Most can be implemented with the Hop function. */ void ctrlQ () { unsigned long c; voidfunc func; if (! char_ready_within (500)) { status_msg ("^Q: blockBegin Find replAce gotomark HOP..."); } if (quit) { return; } c = readcharacter_unicode (); if (quit) { return; } clear_status (); if ('0' <= c && c <= '9') { GOMAn ((int) c - (int) '0'); return; } if (c == '\033' || c == quit_char) { CANCEL (); return; } switch (cmd_char (c)) { case 'B' : {GOMA () ; return;} case 'K' : { ; return;} /* not exactly WS function */ case 'P' : { ; return;} /* not exactly WS function */ case 'V' : { ; return;} /* not exactly WS function */ case 'W' : /* not exactly WS function */ case 'Z' : /* not exactly WS function */ case 'Y' : case '\177' : { func = command (c); hop_flag = 1; (* func) (c); return; } case 'F' : {if (hop_flag > 0) { SRV (); } else { SFW (); } return; } case 'A' : {if (hop_flag > 0) { REPL (); } else { GR (); } return; } case 'Q' : {REPT (' '); return;} /* not exactly WS function */ case 'L' : /* not exactly WS function */ /* ^Q: B/K top/bottom block P last position W/Z continuous scroll V last find or block Y/DEL delete line right/left 0-9 marker F find A replace Q repeat next key/command L find misspelling */ default : { func = command (c); if (func != Scharacter) { hop_flag = 1; keyshift |= alt_mask; (* func) (c); } else { BAD (c, "^Q "); } return; } } } /* * Interpret control-K commands. */ void ctrlK () { unsigned long c; if (! char_ready_within (500)) { status_msg ("^K: Save Done eXit Quit Read Log mark / block: B/K mark Cop Ydel moV Wr..."); } if (quit) { return; } c = readcharacter_unicode (); if (quit) { return; } clear_status (); if ('0' <= c && c <= '9') { MARKn ((int) c - (int) '0'); return; } if (c == '\033' || c == quit_char) { CANCEL (); return; } switch (cmd_char (c)) { case 'S' : {WTU (); return;} case 'D' : {EXFILE (); return;} case 'X' : {EXMINED (); return;} case 'Q' : {QUED (); return;} case 'B' : {MARK () ; return;} case 'K' : {COPY () ; return;} /* not exactly WS function */ case 'H' : { ; return;} /* not exactly WS function */ case 'C' : {PASTE () ; return;} /* not exactly WS function */ case 'Y' : {CUT () ; return;} /* not exactly WS function */ case 'V' : {PASTE (); return;} /* not exactly WS function */ case 'W' : {WB (); return;} /* not exactly WS function */ case 'N' : { ; return;} /* not exactly WS function */ case 'R' : {INSFILE (); return;} case 'L' : {CHDI (); return;} /* ^K 0-9 set/hide marker B/K block begin/end H block hide C/Y/V/W block copy/delete/move/write N column block */ default : { BAD (c, "^K "); return; } } } /* * Interpret control-O commands. */ void ctrlO () { unsigned long c; if (! char_ready_within (500)) { status_msg ("^O: L/R left/right margins..."); } if (quit) { return; } c = readcharacter_unicode (); if (quit) { return; } clear_status (); if ('0' <= c && c <= '9') { return; } if (c == '\033' || c == quit_char) { CANCEL (); return; } switch (cmd_char (c)) { case 'L' : {ADJLM (); return;} case 'R' : {ADJRM (); return;} case 'G' : {ADJFLM () /* actually paragraph tab */; return;} /* ^O L/R/M set left/right margin /release I/N set/clear tab F ruler from line C center line S set line spacing W toggle word wrap T toggle ruler line J toggle justify V vari-tabs H hyph-help E soft hyph D print display P page break */ default : { BAD (c, "^O "); return; } } } /* * Set marker / go to marker. */ void MARKER () { unsigned long c; status_msg ("0..9: set marker / , or blank: default marker"); c = readcharacter_unicode (); if (quit) { return; } clear_status (); if (c == '\033' || c == quit_char) { CANCEL (); } else if ('0' <= c && c <= '9') { MARKn ((int) c - (int) '0'); } else if (c == ',' || c == '\'' || c == ' ' || c == ']' || c == '\035') { MARK (); } else { BAD (c, "mark "); } } void GOMARKER () { unsigned long c; status_msg ("0..9: go marker / blank: default marker"); c = readcharacter_unicode (); if (quit) { return; } clear_status (); if (c == '\033' || c == quit_char) { CANCEL (); } else if ('0' <= c && c <= '9') { GOMAn ((int) c - (int) '0'); } else if (c == ',' || c == '.' || c == 'g' || c == 'G' || c == '\'' || c == ' ' || c == ']' || c == '\035') { GOMA (); } else { BAD (c, "go mark "); } } /* Toggle TAB width. */ void toggle_tabsize () { if (hop_flag > 0) { toggle_tab_expansion (); return; } if (tabsize == 4) { tabsize = 8; } else { tabsize = 4; } RDwin (); } /* Toggle TAB expansion. */ void toggle_tab_expansion () { expand_tabs = ! expand_tabs; } void UNDO () { error ("Undo not implemented"); } void SPELL () { error ("Spell checking not implemented"); } /* * Interpret Escape commands. */ void ESCAPE () { unsigned long c; voidfunc func; if (! char_ready_within (500)) { /* status_uni ("ESC:exit Space:menu q:uit /:search \\:backw (:match r:eplace g:oto h:elp ..."); */ status_uni ("ESCexit SPACEmenu quit /search \\backw (match replace goto justify =rept help ..."); } if (quit) { return; } c = readcharacter_unicode (); if (quit) { return; } clear_status (); if ('0' <= c && c <= '9') { REPT (c); return; } switch (c) { case '\033' : {EXED (); return;} case '\r' : case '\n' : {Popmark (); return;} case 'q' : {QUED (); return;} case '/' : {SFW (); return;} case '\\' : {SRV (); return;} case 'R' : {LR (); return;} case 'r' : {REPL (); return;} case 'w' : {WT (); return;} case 'W' : {WTU (); return;} case 'v' : {VIEW (); return;} case 'V' : {toggle_VIEWmode (); return;} case 'g' : {GOTO (); return;} case 'h' : {HELP (); return;} case '?' : {FS (); return;} case '.' : {RDwin (); return;} case 'm' : {MARKER (); return;} case '\'' : { if (keyshift & alt_mask) { break; } else { GOMARKER (); return; } } case 'i' : {INSFILE (); return;} case 'b' : {WB (); return;} case '=' : {REPT (' '); return;} case 'z' : {SUSP (); return;} case 'd' : {CHDI (); return;} case '!' : {SH (); return;} case '@' : case '^' : {MARK (); return;} case '[' : {CSI (); return;} case ']' : {OSC (); return;} case 'n' : {NN (); return;} case 'c' : {CMD (); return;} case 'u' : {display_code (); return;} case 'U' : {changeuni (); return;} case 'X' : {changehex (); return;} case 'A' : {changeoct (); return;} case 'D' : {changedec (); return;} case '+' : {NXTFILE (); return;} case '-' : {PRVFILE (); return;} case '#' : {NTHFILE (); return;} case '%' : {screensmaller (); return;} case '&' : {screenbigger (); return;} case 'l' : {screenlesslines (); return;} case 'L' : {screenmorelines (); return;} case 'J' : {JUS (); return;} case 'j' : {JUSclever (); return;} case '<' : {ADJLM (); return;} case ';' : {ADJFLM (); return;} case ':' : {ADJNLM (); return;} case '>' : {ADJRM (); return;} case 'P' : {ADJPAGELEN (); return;} case 'T' : {toggle_tabsize (); return;} case 'H' : {HTML (); return;} case 'x' : {AltX (); return;} case '_' : {UML (language_tag); return;} case (character) '' : case (character) '' : case (character) '' : case (character) '' : {UML ('g'); return;} case (character) '' : case (character) '' : case (character) '' : case (character) '' : case (character) '' : {UML ('f'); return;} case (character) '' : case (character) '' : case (character) '' : {UML ('d'); return;} case 'C' : {LOWCAP (); return;} case '(' : case '{' : {SCORR (REVERSE); return;} case ')' : case '}' : {SCORR (FORWARD); return;} case 't' : {Stag (); return;} case 'a' : {toggle_append (); return;} case 'k' : {toggleKEYMAP (); return;} case 'I' : case 'K' : {setupKEYMAP (); return;} case 'Q' : if (smart_quotes) { if (hop_flag > 0) { quote_type_up (); } else { handleQuotemenu (); } displayflags (); } else { error ("Smart quotes not enabled"); } return; case 'E' : if (hop_flag > 0) { toggle_encoding (); } else { handleEncodingmenu (); } return; case ' ' : {QUICKMENU (); return;} case 'f' : {FILEMENU (); return;} case 'e' : {EDITMENU (); return;} case 's' : {SEARCHMENU (); return;} case 'p' : {PARAMENU (); return;} case 'o' : {OPTIONSMENU (); return;} case ',' : {GR (); return;} /* case 'e' : {EDIT (); return;} case 's' : {GR (); return;} case 'p' : {PRINT (); return;} */ } /* fallback */ if (c == quit_char) { CANCEL (); return; } func = command (c); if (func != Scharacter) { hop_flag = 1; keyshift |= alt_mask; (* func) (c); } else { BAD (c, "ESC/Alt-"); } return; } /* * Interpret emacs meta commands. */ void META () { unsigned long c; voidfunc func; if (! char_ready_within (500)) { status_uni ("Meta ESC(exit) TAB,blank(menu) /,\\(search) (match ..."); } if (quit) { return; } c = readcharacter_unicode (); if (quit) { return; } clear_status (); if ('0' <= c && c <= '9') { REPT (c); return; } switch (c) { /* emacs meta commands */ case 'v' : {PU (); return;} case 'f' : {MNW (); return;} case 'b' : {MPW (); return;} case 'a' : {BSEN (); return;} case 'e' : {ESEN (); return;} case '<' : {BFILE (); return;} case '>' : {EFILE (); return;} case 'd' : {DNW (); return;} case 'k' : {MARK (); ESEN (); CUT (); return;} case 'w' : {COPY (); return;} case 'y' : {YANKRING (); return;} case 'z' : {SUSP (); return;} case '%' : {REPL (); return;} case 'u' : {hop_flag = 1; UPPER (); return;} case 'l' : {hop_flag = 1; LOWER (); return;} case 'c' : {CAPWORD (); return;} case '.' : {Stag (); return;} case 'x' : {ESCAPE (); return;} case '\033' : {ESCAPE (); return;} default : { if (c == quit_char) { CANCEL (); return; } func = command (c); if (func != Scharacter) { hop_flag = 1; keyshift |= alt_mask; (* func) (c); } else { BAD (c, "Meta-"); } return; } } } /* * Interpret emacs ^X commands. */ void EMAX () { unsigned long c; if (! char_ready_within (500)) { status_msg ("^X ..."); } if (quit) { return; } c = readcharacter_unicode (); if (quit) { return; } clear_status (); if (command (c) == MARK) { Popmark (); return; } switch (c) { case 'u' : {UNDO (); return;} case '' : {QUED (); return;} case '' : {WT (); return;} case '' : {SAVEAS (); return;} case '' : {PRVFILE (); return;} case '' : {EDIT (); return;} case '\032' : {SUSP (); return;} case '\033' : {REPT (' '); return;} case 'i' : {INSFILE (); return;} case 's' : {WT (); return;} case 'k' : {EDIT (); return;} case '=' : {FS (); return;} case '[' : {PU (); return;} case ']' : {PD (); return;} default : { if (c == quit_char) { CANCEL (); return; } BAD (c, "^X "); } } } /* * MOUSEescape () is invoked after a mouse escape sequence with coordinates and button info already stored in mouse_xpos, mouse_ypos, and mouse_button. Then it performs a menu or other mouse controlled function. * FOCUSout and FOCUSin are special cases of mouse report for the window losing or gaining focus. */ void MOUSEescape () { int proz; if (! window_focus) { return; } if (mouse_ypos == -1) { /* menu stuff */ openmenuat (mouse_xpos); } else if (mouse_button == wheelup) { if (mouse_shift & shift_button) { PU (); } else if (mouse_shift & control_button) { SU (); } else { for (proz = 0; quit == False && proz < wheel_scroll && proz < YMAX; proz ++) { if (proz > 0 && disp_scrollbar) { (void) display_scrollbar (True); } SU (); } } } else if (mouse_button == wheeldown) { if (mouse_shift & shift_button) { PD (); } else if (mouse_shift & control_button) { SD (); } else { for (proz = 0; quit == False && proz < wheel_scroll && proz < YMAX; proz ++) { if (proz > 0 && disp_scrollbar) { (void) display_scrollbar (True); } SD (); } } } else if (disp_scrollbar && mouse_xpos == XMAX) { if (mouse_button == leftbutton) { PD (); } else if (mouse_button == rightbutton) { PU (); } else if (mouse_button == middlebutton || (mouse_button == releasebutton && mouse_lastbutton == middlebutton) || mouse_button == movebutton ) { proz = (mouse_ypos + 1) * 100 / YMAX; if (proz > 100) { goproz (100); } else { goproz ((mouse_ypos + 1) * 100 / YMAX); } } } else if (mouse_button == movebutton) { /* ignore */ } else if (mouse_ypos == YMAX) { if (mouse_button == leftbutton) { PD (); } else if (mouse_button == middlebutton) { FS (); } else if (mouse_button == rightbutton) { PU (); } } else if (quickmenu) { if (mouse_ypos > last_y) { mouse_ypos = last_y; } if (mouse_button == leftbutton) { move_to (mouse_xpos, mouse_ypos); report_release = True; } else if (mouse_button == middlebutton) { FS (); } else if (mouse_button == rightbutton) { move_to (mouse_xpos, mouse_ypos); QUICKMENU (); } else if (mouse_button == releasebutton && mouse_lastbutton == leftbutton && (mouse_xpos != mouse_lastxpos || mouse_ypos != mouse_lastypos)) { MARK (); move_to (mouse_xpos, mouse_ypos); COPY (); } } else { if (mouse_ypos > last_y) { mouse_ypos = last_y; } move_to (mouse_xpos, mouse_ypos); if (mouse_button == leftbutton) { MARK (); } else if (mouse_button == middlebutton) { PASTE (); } else if (mouse_button == rightbutton) { COPY (); } } } void FOCUSout () { window_focus = False; mouse_button = focusout; } void FOCUSin () { window_focus = True; mouse_button = focusin; } /* * REPT () prompts for a count and wants a command after that. It repeats the * command count times. If a ^\ is given during repeating, stop looping and * return to main loop. */ void REPT (firstdigit) char firstdigit; { int count; voidfunc func; unsigned long cmd; int number; hop_flag = 0; if (firstdigit >= '0' && firstdigit <= '9') { cmd = get_number ("Please continue repeat count...", firstdigit, & number); if (firstdigit != '0' && number < 10) { error ("Invalid repeat count after ESC "); return; } } else { cmd = get_number ("Please enter repeat count...", '\0', & number); } if (cmd == ERRORS) { return; } func = command (cmd); if (func == I) { /* Function assigned? */ clear_status (); return; } count = number; while (count -- > 0 && quit == False) { char save_keyshift = keyshift; if (stat_visible) { clear_status (); } reset_smart_replacement (); (* func) (cmd); keyshift = save_keyshift; flush (); } reset_smart_replacement (); if (quit) { /* Abort has been given */ error ("Repeat aborted"); } else { clear_status (); } } /*======================================================================*\ |* Specific error messages and flag setting *| \*======================================================================*/ /* * viewonlyerr () outputs an error message with a beep */ void viewonlyerr () { ring_bell (); error ("View only mode"); } /* * restrictederr () outputs an error message with a beep */ void restrictederr () { ring_bell (); error2 ("Restricted mode", " - function not allowed"); } /* * Called if an operation is not implemented on this system */ static void notavailable () { error ("Command not available"); } /* * Set the modified flag */ void set_modified () { if (modified == False) { modified = True; #ifdef unix RD_window_title (); #endif } } /*======================================================================*\ |* System-related command functions *| \*======================================================================*/ /* * Change current directory. */ void CHDI () { char new_dir [maxLINE_LEN]; /* Buffer to hold new dir. name */ if (restricted) { restrictederr (); return; } #ifdef pc build_string (text_buffer, "Drive/Directory: %s, change to:", unnull (getcwd (new_dir, maxLINE_LEN))); #else build_string (text_buffer, "Directory: %s, change to:", unnull (getcwd (new_dir, maxLINE_LEN))); #endif if (get_filename (text_buffer, new_dir) != FINE) { return; } #ifdef msdos if (new_dir [0] != '\0' && new_dir [1] == ':') if (new_dir [2] == '\0') { new_dir [2] = '.'; /* change to current dir. of drive */ new_dir [3] = '\0'; } #endif if (chdir (new_dir) == 0) { #ifdef msdos if (new_dir [0] != '\0' && new_dir [1] == ':') setdisk (((int) new_dir [0] & (int) '\137') - (int) 'A'); RD (); /* disk error dialog may be on screen after chdir */ #endif clear_status (); overwriteOK = False; /* Same file base name ... */ writable = True; set_modified (); /* would mean different file now */ } else { #ifdef msdos RD (); /* disk error dialog may be on screen */ #endif error2 ("Cannot change current directory: ", serror ()); } } /* * Print file status. */ void FSTAT () { fstatus (file_name [0] ? "" : empty_buffer_name, -1L, -1L); } void FS () { if (hop_flag > 0) { if (always_disp_fstat) { always_disp_fstat = False; } else { always_disp_fstat = True; } } else { FSTAT (); } } static void show_help (topic) char * topic; { #ifndef pc char syscommand [maxLINE_LEN]; /* Buffer for full system command */ int sysres; #endif char * helpfile; char hfbuf [maxLINE_LEN]; int hf = -1; if (hf == -1) { if (getenv ("MINEDDIR")) { strcpy (hfbuf, getenv ("MINEDDIR")); strcat (hfbuf, "/help/mined.hlp"); helpfile = hfbuf; hf = open (helpfile, O_RDONLY); } } if (hf == -1) { /* deprecated */ helpfile = envvar ("MINEDHELPFILE"); if (* helpfile != '\0') { hf = open (helpfile, O_RDONLY); } } if (hf == -1) { /* look in program directory, esp. for MSDOS */ strcpy (hfbuf, fnamv [0]); helpfile = & hfbuf [strlen (hfbuf)]; while (helpfile >= hfbuf && * helpfile != '/') { helpfile --; } helpfile ++; strcpy (helpfile, "mined.hlp"); helpfile = hfbuf; hf = open (helpfile, O_RDONLY); } #ifndef msdos if (hf == -1) { strcpy (hfbuf, RUNDIR); strcat (hfbuf, "/help/mined.hlp"); helpfile = hfbuf; hf = open (helpfile, O_RDONLY); } if (hf == -1) { strcpy (hfbuf, LRUNDIR); strcat (hfbuf, "/help/mined.hlp"); helpfile = hfbuf; hf = open (helpfile, O_RDONLY); } #endif if (hf == -1) { helpfile = "/usr/share/mined/help/mined.hlp"; hf = open (helpfile, O_RDONLY); } if (hf == -1) { helpfile = "/usr/local/share/mined/help/mined.hlp"; hf = open (helpfile, O_RDONLY); } if (hf == -1) { helpfile = "/usr/share/lib/mined/help/mined.hlp"; hf = open (helpfile, O_RDONLY); } if (hf == -1) { helpfile = "/opt/mined/share/help/mined.hlp"; hf = open (helpfile, O_RDONLY); } if (hf == -1) { helpfile = "/usr/share/doc/packages/mined/help/mined.hlp"; hf = open (helpfile, O_RDONLY); } if (hf == -1) { status_msg ("Help file not found; configure $MINEDDIR in environment!"); return; #ifndef pc } else if (! (hop_flag > 0 || viewing_help)) { (void) close (hf); build_string (syscommand, "less '-QMPMMined help?e (end):?pb (%%pb\\%%).. - type '\\''h for help topic \"%s\", q to return to mined '" " +\"/mined help topic '%s'\nkmhG'h\" %s", topic, topic, helpfile); clear_status (); set_cursor (0, YMAX); #ifdef unix clear_window_title (); #endif raw_mode (False); sysres = system (syscommand); raw_mode (True); RDwin (); if (sysres != 0) { error ("Help topic not found in help file"); } #endif } else { (void) close (hf); view_help (helpfile, topic); } } /* * Show About mined information */ void ABOUT () { char about [99]; strcpy (about, "Mined "); strcat (about, VERSION); #ifdef __GNUC__ strcat (about, " (gcc)"); #endif #ifdef __CYGWIN__ strcat (about, " (cygwin)"); #else #ifdef __TURBOC__ strcat (about, " (turboc)"); #else #ifdef __EMX__ strcat (about, " (emx)"); #else #ifdef pc strcat (about, " (dj)"); #endif #endif #endif #endif strcat (about, " - http://mined.sourceforge.net/"); status_uni (about); } static void dispatch_HELP (topics, Fn) FLAG topics; FLAG Fn; { unsigned long c; /* status_msg ("...F1 / Help on: i(ntroduction k(eyboard f(unction-keys c(ommands m(enu"); */ if (topics && Fn) { status_uni ("(C/S/A)F1 / Help on: about introduction keyboard function-keys commands menu"); } else if (topics) { status_uni ("Help on: about introduction keyboard function-keys commands menu"); } else { status_uni ("Show help bar for: (Ctrl-/Shift-/Alt-/Ctrl-Shift-/Alt-Shift-)Fn / Ctrl-/Alt-/Alt-Ctrl-1 / Ctrl-."); } if (quit) return; c = readcharacter_unicode (); if (quit) return; clear_status (); if (command (c) == F1) { FHELP (F1); } else if (c == '1' || command (c) == key_1) { FHELP (key_1); } else if (command (c) == COMPOSE) { FHELP (COMPOSE); } else if (topics) switch (c) { case '\033': return; case 'a': ABOUT (); return; case 'i': show_help ("introduction"); return; case 'k': show_help ("keyboard"); return; case 'f': show_help ("function-keys"); return; case 'c': show_help ("commands"); return; case 'm': show_help ("menu"); return; default: { if (c == quit_char) { return; } status_msg ("No such help available"); return; } } } /* * View Help topics / display function key help lines */ void HELP () { dispatch_HELP (True, True); } void select_FHELP () { dispatch_HELP (False, True); } void HELP_topics () { dispatch_HELP (True, False); } static char print_file [maxLINE_LEN]; /* temp. file for printing */ static FLAG print_status = NOT_VALID; /* status of print_file */ /** Copy text into temporary file for printing; convert to Unicode. */ static int write_unitext (fd) int fd; { long chars_written = 0L; /* chars written to buffer this time */ int lines_written = 0; /* lines written to buffer this time */ LINE * line = header->next; char * textp = line->text; int count = 0; chars_written = char_count (textp) - 1; while (textp != tail->text) { if (* textp == '\n') { /* handle different line ends */ if (line->return_type != lineend_NONE) { int ret = writechar (fd, '\n'); if (ret == ERRORS) { (void) close (fd); return ERRORS; } lines_written ++; chars_written ++; count = 0; } /* move to the next line */ line = line->next; textp = line->text; chars_written += char_count (textp) - 1; } else { unsigned long unichar = charvalue (textp); if (cjk_text || mapped_text) { unichar = lookup_encodedchar (unichar); if (no_unichar (unichar)) { unichar = 0x00A4; /* ¤ */ } } if (unichar == '\t') { int tab_count = tab (count); while (count < tab_count) { if (writechar (fd, ' ') == ERRORS) { (void) close (fd); return ERRORS; } count ++; } } else { character unibuf [13]; char * up = (char *) unibuf; if (unichar >= 0x80000000) { /* special encoding of 2 Unicode chars, mapped from 1 CJK character */ up += utfencode (unichar & 0xFFFF, up); if (iswide_unichar (unichar)) { count += 2; } else { count ++; } unichar = (unichar >> 16) & 0x7FFF; } (void) utfencode (unichar, up); /* ... iscombined (unichar, textp, line->text) ? */ if (! iscombining_unichar (unichar)) { if (iswide_unichar (unichar)) { count += 2; } else { count ++; } } /* don't use write_line which might write UTF-16 ! */ up = (char *) unibuf; while (* up != '\0') { if (writechar (fd, * up) == ERRORS) { (void) close (fd); return ERRORS; } up ++; } } advance_char (& textp); } } /* Flush the I/O buffer and close file */ if (flush_filebuf (fd) == ERRORS) { (void) close (fd); return ERRORS; } if (close (fd) < 0) { return ERRORS; } return FINE; } /* * Print buffer */ void PRINT () { char cmd [MAX_CHARS]; /* Buffer for print command */ int sysres; char * msg; char fn [maxLINE_LEN]; int fd; if (file_name [0] == '\0') { build_string (fn, "print"); } else { build_string (fn, "print.%s", basename (file_name)); } fd = scratchfile (WRITE, False, print_file, fn, & print_status); if (fd == ERRORS) { error ("Cannot create spool file"); return; } if (write_unitext (fd) == ERRORS) { error ("Cannot write spool file"); return; } clear_status (); set_cursor (0, YMAX); flush (); raw_mode (False); /* try printing with $MINEDPRINT */ if (getenv ("MINEDPRINT")) { build_string (cmd, getenv ("MINEDPRINT"), print_file); sysres = system (cmd); if (sysres == 0) { msg = getenv ("MINEDPRINT"); } else { raw_mode (True); error ("Printing with $MINEDPRINT failed, trying uprint"); sleep (1); raw_mode (False); } } else { sysres = -99; } /* try printing with uprint */ if (sysres != 0) { #ifdef unix build_string (cmd, "PATH=${MINEDDIR:-/dev/null}/bin:%s/bin:%s/bin:%s:%s:%s:%s:%s:$PATH uprint -r %s", RUNDIR, LRUNDIR, "/usr/share/mined/bin", "/usr/local/share/mined/bin", "/usr/share/lib/mined/bin", "/opt/mined/share/bin", "/usr/share/doc/packages/mined/bin", print_file); #else build_string (cmd, "uprint -r %s", print_file); #endif sysres = system (cmd); if (sysres == 0) { msg = "uprint"; } else { raw_mode (True); error ("Printing with uprint failed, trying $LPR/lp/lpr"); sleep (1); raw_mode (False); } } /* try printing with $LPR */ if (sysres != 0 && getenv ("LPR")) { build_string (cmd, "LC_ALL=en_US.UTF-8 %s %s", getenv ("LPR"), print_file); sysres = system (cmd); if (sysres == 0) { msg = getenv ("LPR"); } else { raw_mode (True); error ("Printing with $LPR failed, trying lp/lpr"); sleep (1); raw_mode (False); } } /* try print with system-specific print_command */ if (sysres != 0) { build_string (cmd, print_command, print_file); sysres = system (cmd); if (sysres == 0) { msg = "system print command"; } } sleep (1); raw_mode (True); RDwin (); if (sysres == 0) { status_line ("Printed with ", msg); } else { error ("Printing failed"); } } /* * Pipe buffer */ static void CMD () { int fd; char cmd [maxLINE_LEN]; /* Buffer for command */ char command [maxLINE_LEN]; /* Buffer for full command */ if (restricted) { restrictederr (); return; } if ((fd = yankfile (READ, False)) == ERRORS) { error ("Buffer is empty"); return; } (void) close (fd); if (get_string ("Command with buffer as input:", cmd, True, "") != FINE) { return; } build_string (command, "%s < %s", cmd, yank_file); clear_status (); set_cursor (0, YMAX); #ifdef unix clear_window_title (); #endif raw_mode (False); (void) system (command); sleep (1); raw_mode (True); RDwin (); } /* * Suspend editor after writing back the file. */ void SUSP () { if (restricted) { restrictederr (); return; } if (cansuspendmyself) { if (hop_flag == 0 && modified) { if (write_text (False) == ERRORS) { return; } } set_cursor (0, YMAX); #ifdef unix clear_window_title (); #endif raw_mode (False); suspendmyself (); raw_mode (True); clear_status (); RDwin (); } else { notavailable (); } } #ifndef __CYGWIN__ #define spawn_shell #endif #ifdef spawn_shell #ifdef __CYGWIN__ #error does not work with cygwin: tty mode will not be reset (reason unknown) #endif /* * Call an interactive shell. */ static void spawnSHELL () { #ifdef msdos #define SHimplemented char old_dir [maxLINE_LEN]; /* Buffer to hold dir. name */ (void) getcwd (old_dir, maxLINE_LEN); set_cursor (0, YMAX); raw_mode (False); (void) system (getenv ("COMSPEC")); raw_mode (True); clear_status (); RDwin (); if (chdir (old_dir) == 0) { if (old_dir [0] != '\0' && old_dir [1] == ':') setdisk (((int) old_dir [0] & (int) '\137') - (int) 'A'); RD (); /* disk error dialog may be on screen after chdir */ } else { overwriteOK = False; /* Same file base name ... */ writable = True; set_modified (); /* would mean different file now */ RD (); /* disk error dialog may be on screen */ error2 ("Cannot reset to previous directory: ", serror ()); } #else /* msdos */ #ifdef unix #define SHimplemented register int w; int pid; int status; int waiterr; #ifdef FORK switch (pid = fork ()) { #else switch (pid = vfork ()) { #endif case -1: /* Error */ error2 ("Cannot fork command shell: ", serror ()); return; case 0: /* This is the child */ set_cursor (0, YMAX); putchar ('\n'); clear_window_title (); raw_mode (False); if (reading_pipe) { /* Fix stdin */ if (close (STD_IN) < 0) { /*_exit (126);*/ } if (open ("/dev/tty", O_RDONLY, 0) < 0) { _exit (126); } } execl (getenv ("SHELL"), getenv ("SHELL"), NIL_PTR); _exit (127); /* Exit with 127 */ /* NOTREACHED */ default: /* This is the parent */ do { w = wait (& status); } while (w != -1 && w != pid); waiterr = geterrno (); } raw_mode (True); RDwin (); if (w == -1) { error2 ("Shell termination error: ", serrorof (waiterr)); if (((status >> 8) == 127) || ((status >> 8) == 126)) sleep (2); } if ((status >> 8) == 127) { /* Child died with 127 */ error2 (envvar ("SHELL"), ": error invoking ${SHELL} (not found / not enough memory ?)"); } else if ((status >> 8) == 126) { error ("Cannot open /dev/tty as fd #0"); } #else /* unix */ #ifdef vms #define SHimplemented /* Who can tell me why this hangs the process after return from the CLI ? set_cursor (0, YMAX); raw_mode (False); (void) system ("SPAWN"); raw_mode (True); clear_status (); RDwin (); */ notavailable (); #endif #endif #endif #ifndef SHimplemented notavailable (); #endif } #else /* * Call interactive shell */ static void SHELL () { if (restricted) { restrictederr (); return; } clear_status (); set_cursor (0, YMAX); #ifdef unix clear_window_title (); #endif raw_mode (False); (void) system ("${SHELL-/bin/sh}"); sleep (1); raw_mode (True); RDwin (); } #endif void SH () { if (hop_flag > 0) { hop_flag = 0; CMD (); return; } if (restricted) { restrictederr (); return; } #ifdef spawn_shell spawnSHELL (); #else SHELL (); #endif } /*======================================================================*\ |* Setup display preferences *| \*======================================================================*/ /** Configure line and display markers. Width data detection must be settled for the case of UTF-8. */ static void config_markers () { char * Mark; Mark = getenv ("MINEDSHIFT"); if (Mark != NIL_PTR) { SHIFT_BEG_marker = Mark [0]; if (SHIFT_BEG_marker == ' ') { SHIFT_BEG_marker = '\0'; } if (Mark [0] && Mark [1]) { SHIFT_marker = Mark [1]; } } Mark = getenv ("MINEDTAB"); if (Mark != NIL_PTR) { if (Mark [0] == '\0') { TAB_marker = TABdefault; } else { TAB_marker = Mark [0]; if (Mark [1]) { if (Mark [2]) { TAB0_marker = Mark [0]; TAB_marker = Mark [1]; TAB2_marker = Mark [2]; } else { TABmid_marker = Mark [1]; } } if (TAB_marker >= ' ' && TAB_marker != '\\' && TAB_marker < '~') { CJK_TAB_marker = TAB_marker; } } } else { TAB_marker = TABdefault; } Mark = getenv ("MINEDRET"); if (Mark != NIL_PTR) { RET_marker = Mark [0]; if (RET_marker != '\0') { RETfill_marker = Mark [1]; } if (RETfill_marker != '\0') { RETfini_marker = Mark [2]; } } else { RET_marker = RETdefault; } Mark = getenv ("MINEDDOSRET"); if (Mark && * Mark) { DOSRET_marker = Mark [0]; } else { if (bw_term) { DOSRET_marker = ''; } else { DOSRET_marker = RET_marker; } } Mark = getenv ("MINEDMACRET"); if (Mark && * Mark) { MACRET_marker = Mark [0]; } else { if (bw_term) { MACRET_marker = '@'; } else { MACRET_marker = RET_marker; } } Mark = getenv ("MINEDPARA"); if (Mark && * Mark) { PARA_marker = Mark [0]; } else { PARA_marker = PARAdefault; } Mark = getenv ("MINEDMENUMARKER"); if (Mark) { if (* Mark) { MENU_marker = Mark [0]; } else { MENU_marker = '`'; } } if (! limited_marker_font) { /* unlimited font settings */ UTF_SHIFT_BEG_marker = getenv ("MINEDUTFSHIFT"); if (UTF_SHIFT_BEG_marker && * UTF_SHIFT_BEG_marker) { UTF_SHIFT_marker = UTF_SHIFT_BEG_marker; advance_utf8 (& UTF_SHIFT_marker); if (* UTF_SHIFT_BEG_marker == ' ') { UTF_SHIFT_BEG_marker = ""; } } UTF_TAB_marker = getenv ("MINEDUTFTAB"); if (UTF_TAB_marker != NIL_PTR) { char * markpoi = UTF_TAB_marker; if (* markpoi) { advance_utf8 (& markpoi); if (* markpoi) { UTF_TAB0_marker = UTF_TAB_marker; UTF_TAB_marker = markpoi; advance_utf8 (& markpoi); if (* markpoi) { UTF_TAB2_marker = markpoi; } else { UTF_TABmid_marker = UTF_TAB_marker; UTF_TAB_marker = UTF_TAB0_marker; UTF_TAB0_marker = NIL_PTR; } } } } UTF_RET_marker = getenv ("MINEDUTFRET"); if (UTF_RET_marker != NIL_PTR) { UTF_RETfill_marker = UTF_RET_marker; if (* UTF_RETfill_marker != '\0') { advance_utf8 (& UTF_RETfill_marker); } UTF_RETfini_marker = UTF_RETfill_marker; if (* UTF_RETfini_marker != '\0') { advance_utf8 (& UTF_RETfini_marker); } } UTF_DOSRET_marker = getenv ("MINEDUTFDOSRET"); if (UTF_DOSRET_marker == NIL_PTR) { UTF_DOSRET_marker = UTF_RET_marker; } UTF_MACRET_marker = getenv ("MINEDUTFMACRET"); if (UTF_MACRET_marker == NIL_PTR) { UTF_MACRET_marker = UTF_RET_marker; } UTF_PARA_marker = getenv ("MINEDUTFPARA"); Mark = getenv ("MINEDUTFMENUMARKER"); if (Mark) { if (* Mark) { int len; unsigned long unichar; utf8_info (Mark, & len, & unichar); if (len > 1 && ! iswide (unichar) && ! iscombining (unichar)) { UTF_MENU_marker = Mark; } } else { UTF_MENU_marker = UTF_MENU_marker_fancy; } } } else if (! very_limited_marker_font) { /* limited font settings */ UTF_MENU_marker = UTF_MENU_marker_alt; } else { /* very limited font settings */ UTF_MENU_marker = "»"; } } /** Setup configured display attributes for certain items */ static void get_ansi_modes () { dimansi = getenv ("MINEDDIM"); if (dimansi == NIL_PTR) { if (dark_term) { dimansi = "1;31"; } else { dimansi = "2;31"; } } selansi = getenv ("MINEDSEL"); selfgansi = getenv ("MINEDSELFG"); if (selfgansi == NIL_PTR) { selfgansi = "43"; } if (selansi == NIL_PTR) { if (dark_term) { selansi = "34;1"; } else { selansi = "34"; } } uniansi = getenv ("MINEDUNI"); if (uniansi == NIL_PTR) { if (cjk_term) { uniansi = "36;7;40"; } else { uniansi = "40;36;7"; } } else if ((character) * uniansi > '9') { UNI_marker = * uniansi; do { uniansi ++; } while (* uniansi == ' '); } unimarkansi = getenv ("MINEDUNIMARK"); if (unimarkansi == NIL_PTR) { unimarkansi = "36;1"; } combiningansi = getenv ("MINEDCOMBINING"); if (combiningansi == NIL_PTR) { combiningansi = "46;30"; } ctrlansi = getenv ("MINEDCTRL"); if (ctrlansi == NIL_PTR) { ctrlansi = ""; } menuansi = getenv ("MINEDMENU"); if (menuansi == NIL_PTR) { menuansi = ""; } HTMLansi = getenv ("MINEDHTML"); if (HTMLansi == NIL_PTR) { if (streq ("cygwin", envvar ("TERM"))) { HTMLansi = "1;34"; } else { HTMLansi = "34"; } } diagansi = envvar ("MINEDDIAG"); scrollbgansi = getenv ("MINEDSCROLLBG"); if (scrollbgansi == NIL_PTR) { if (colours_256 || colours_88) { /*scrollbgansi = "34;48;5;45";*/ scrollbgansi = "46;34;48;5;45"; } else { scrollbgansi = "46;34"; } } scrollfgansi = getenv ("MINEDSCROLLFG"); if (scrollfgansi == NIL_PTR) { scrollfgansi = ""; if (colours_256 || colours_88) { /*scrollfgansi = "44;38;5;45";*/ /*scrollfgansi = "44;36;38;5;45";*/ } else if (cjk_term && (text_encoding_tag == 'K' || text_encoding_tag == 'H') && strisprefix ("xterm", envvar ("TERM")) ) { /* probably hanterm; attributes will all be reverse and could not be distinguished to build the scrollbar */ /*scrollfgansi = "0";*/ scrollfgansi = "44;36"; } else { /*scrollfgansi = "44;36";*/ } } } /*======================================================================*\ |* Terminal mode debugging *| \*======================================================================*/ #define dont_debug_test_screen_width #define dont_debug_encoding #define dont_debug_screenmode #define dont_debug_width_data_version #define dont_debug_graphics #ifdef debug_test_screen_width # define debug_encoding #endif #ifdef debug_encoding #define trace_encoding(tag) \ printf ("[%s] TERM %c utf8 %d cjk %d map %d comb/bidi %d/%d - TEXT %c (auto %d) utf8 %d cjk %d map %d\n", \ tag, \ term_encoding_tag, utf8_screen, cjk_term, mapped_term, combining_screen, bidi_screen, \ text_encoding_tag, auto_detect, utf8_text, cjk_text, mapped_text) #else #define trace_encoding(tag) #endif #ifdef debug_width_data_version #define trace_width_data_version(tag) \ printf ("[%s] width_data_version %d (CJK %d) nonbmp %X combining_data_version %d\n", tag, width_data_version, cjk_width_data_version, nonbmp_width_data, combining_data_version) #else #define trace_width_data_version(tag) #endif /*======================================================================*\ |* Terminal setup *| \*======================================================================*/ /* For the initial cursor position request, balance the delay time (to accept a response) so that reponses via slow remote terminal lines can be acquired but the user delay on a terminal that doesn't respond at all remains acceptable. */ static int response_delay = 700; /* initial value */ static int response_delay_plus = 0; /* additional value */ static int response_delay_more = 800; /* for subsequent responses */ static int escape_delay = 0; /* wait to detect escape sequence */ static int default_escape_delay = 450; /* overridden by $ESCDELAY */ static void adjust_delays () { if (escape_delay == 0) { char * env = getenv ("ESCDELAY"); if (env) { (void) scan_int (env, & escape_delay); } else if (strisprefix ("rxvt", envvar ("TERM"))) { escape_delay = 6666; /* slow rxvt font loading */ } if (escape_delay == 0) { escape_delay = default_escape_delay; } else { response_delay += escape_delay - default_escape_delay; } } } /** Request the terminal (VT100-like, xterm and derivatives) to send Device Attributes report containing terminal type and version. */ static void acquire_device_attributes () { #ifndef msdos character c; int dummy; terminal_type = -1; terminal_version = -1; putescape ("\033[>c"); flush (); adjust_delays (); if (char_ready_within (response_delay + response_delay_plus)) { c = read1byte (); if (c == '\033' && char_ready_within (escape_delay)) { c = read1byte (); if (c == '[' && char_ready_within (escape_delay)) { c = read1byte (); /* accept '>' (secondary DA) or '?' (CJK terminals) */ if ((c == '>' || c == '?') && char_ready_within (escape_delay)) { c = get_digits (& terminal_type); if (c == ';') { c = get_digits (& terminal_version); } while (c == '.') { /* mrxvt sends sub-version 0.4.1 */ c = get_digits (& dummy); terminal_version = terminal_version * 100 + dummy; } while (c == ';') { c = get_digits (& dummy); } } } } } #endif } static char * get_terminal_report_string (s) char * s; { #ifndef msdos character c; static char sbuf [MAX_CHARS]; char * spoi = sbuf; putescape (s); flush (); if (char_ready_within (escape_delay)) { c = read1byte (); if (c == '\033' && char_ready_within (escape_delay)) { c = read1byte (); if (c == ']') { character c; while (char_ready_within (escape_delay) && (c = read1byte ()) >= ' ') { if (spoi < & sbuf [MAX_CHARS - 1]) { * spoi ++ = c; } } if (c == '\033') { if (char_ready_within (escape_delay)) { read1byte (); } } } } } * spoi = '\0'; return sbuf; #else return ""; #endif } static int test_screen_width (s) char * s; { #ifndef msdos character c; int row, col; if (! ansi_esc) { return 0; } putstring ("\r"); /* if (xterm_version >= 201) { suppress visible effect by setting invisible character mode - this would need intensive regression testing, so leave it } */ putstring (s); putescape ("\033[6n"); /* maybe termcap u7 but not really defined */ putescape ("\r\033[K"); /* reduce visible effect */ flush (); adjust_delays (); if (char_ready_within (response_delay + response_delay_plus)) { /* for subsequent position requests, increase delay time for the sake of mlterm which needs a longer time to react, probably for font loading */ response_delay_plus = response_delay_more; c = read1byte (); if (c == '\033' && char_ready_within (escape_delay)) { c = read1byte (); if (c == '[' && char_ready_within (escape_delay)) { c = get_digits (& row); if (c == ';') { c = get_digits (& col); #ifdef debug_test_screen_width printf ("test %s -> %d\n", s, col - 1); #endif return col - 1; } } } } #endif return -1; } typedef struct { char * test; int width; } screen_width; static screen_width utf8_widths [] = { {"a̡"}, {"《》〚〛⦅⦆"}, {"︐"}, {"a܏"}, {"aͣ"}, {".឴.឵.᠎"}, {"‘’“”…―­"}, {"…―…"}, {"𠀀𠀀𠀀𠀀a𝆪a𝆪a󠀠"}, {"䷀"}, #ifdef oldmlterm_wideboldborderbug_workaround {"╭"}, #endif }; static screen_width cjk_widths [] = { {"02"}, {"ꥦޡ"}, {""}, {"x"}, {""}, }; static int get_screen_width (s, sw, len) char * s; screen_width * sw; int len; { int i; for (i = 0; i < len; i ++) { /* if screen width has been acquired for this test string, return */ if (streq (s, sw [i].test) && sw [i].width) { #ifdef debug_test_screen_width printf ("get %s -> %d\n", s, sw [i].width); #endif return sw [i].width; } } return test_screen_width (s); } static void acquire_screen_widths (sw, len) screen_width * sw; int len; { #ifndef msdos int i; character c; int row, col; for (i = 0; i < len; i ++) { putstring ("\r"); /* if (xterm_version >= 201) { suppress visible effect by setting invisible character mode - this would need intensive regression testing, so leave it } */ putstring (sw [i].test); putescape ("\033[6n"); /* maybe termcap u7 but not really defined */ } putescape ("\r\033[K"); /* reduce visible effect */ flush (); adjust_delays (); for (i = 0; i < len; i ++) { if (char_ready_within (response_delay + response_delay_plus)) { /* for subsequent position requests, increase delay time for the sake of mlterm which needs a longer time to react, probably for font loading */ response_delay_plus = response_delay_more; c = read1byte (); if (c == '\033' && char_ready_within (escape_delay)) { c = read1byte (); if (c == '[' && char_ready_within (escape_delay)) { c = get_digits (& row); if (c == ';') { c = get_digits (& col); sw [i].width = col - 1; #ifdef debug_test_screen_width printf ("acquire %s -> %d\n", sw [i].test, col - 1); #endif } } } } } #endif } /** Perform terminal detection, encoding auto-detection, determine features, setup terminal. */ static void terminal_configure_init () { int swidth; int cwidth; /* terminal mode initialisation */ /* Note: this must be called before any screen interaction, e.g. test_screen_width, acquire_screen_widths, get_screen_width but after pipe handling (I/O redirection) */ get_term (); raw_mode (True); /* Set tty to appropriate mode */ if (erase_char != '\0') { key_map [erase_char] = DPC; } getwinsize (); if (XMAX < 39 || YMAX < 1) { panic ("Terminal size too small", "minimum: 3 * 40"); } /* ensure feedback after start-up when terminal is slow on loading fonts */ if (strisprefix ("rxvt", envvar ("TERM"))) { get_ansi_modes (); clearscreen (); status_msg ("Auto-detecting terminal properties - wait for rxvt loading fonts"); set_cursor (0, 0); flush (); (void) char_ready_within (30); /* apparently needed to flush output */ } /* detect screen encoding and calibrate screen properties */ /* detect kterm encodings */ #define sjis_3bytes "xa" /*#define sjis_3bytes ""*/ if (streq ("kterm", envvar ("TERM"))) { if (get_screen_width (sjis_3bytes, NIL_PTR, 0) == 3) { (void) set_term_encoding ("Shift-JIS", 'S'); if (! text_encoding_selected) { (void) set_text_encoding ("Shift-JIS", 'S', "TERM=kterm"); } } else { (void) set_term_encoding ("EUC-JP", 'J'); if (! text_encoding_selected) { (void) set_text_encoding ("EUC-JP", 'J', "TERM=kterm"); } } auto_detect = False; trace_encoding ("kterm"); } /* detect UTF-8 and CJK screen encodings */ trace_encoding ("init"); swidth = test_screen_width ("åلاษษ刈墢"); #ifdef debug_screenmode printf ("test_screen_width -> %d\n", swidth); #endif if (swidth > 0) { /** check cursor column after test string, determine screen mode 6 -> UTF-8, no double-width, with LAM/ALEF ligature joining 7 -> UTF-8, no double-width, no LAM/ALEF ligature joining 8 -> UTF-8, double-width, with LAM/ALEF ligature joining 9 -> UTF-8, double-width, no LAM/ALEF ligature joining 11,16 -> CJK terminal (with luit) 10,15 -> 8 bit terminal or CJK terminal 14,17 -> CJK terminal 18 -> CJK terminal (or 8 bit terminal, e.g. Linux console) */ if (swidth > 0 && swidth <= 9) { utf8_screen = True; utf8_input = True; cjk_term = False; mapped_term = False; acquire_screen_widths (utf8_widths, arrlen (utf8_widths)); if (get_screen_width ("a̡", utf8_widths, arrlen (utf8_widths)) == 1) { combining_screen = True; if (! combining_mode_disabled) { combining_mode = True; } } else { combining_screen = False; combining_mode = False; } if ((swidth & 1) == 0) { /* ligature joining detected, must also be bidi */ bidi_screen = True; poormansbidi = False; /* disable scrollbar to prevent interference */ disp_scrollbar = False; scrollbar_width = 0; } if (swidth < 8) { /* no wide character support */ width_data_version = 0; trace_width_data_version ("0"); } else if (get_screen_width ("《》〚〛⦅⦆", utf8_widths, arrlen (utf8_widths)) < 9) { /* older width data (before xterm 167) */ width_data_version = U300; trace_width_data_version ("300"); } else if (get_screen_width ("︐", utf8_widths, arrlen (utf8_widths)) >= 2) { width_data_version = U410; trace_width_data_version ("410"); } /* determine combining data version */ if (get_screen_width (".᷄.᷅", utf8_widths, arrlen (utf8_widths)) == 2) { combining_data_version = U500; } else if (get_screen_width (".͘.͙", utf8_widths, arrlen (utf8_widths)) == 2) { combining_data_version = U410; } else if (get_screen_width (".͐.឴.᠎", utf8_widths, arrlen (utf8_widths)) == 4) { combining_data_version = U400; } else if (get_screen_width ("aͣ", utf8_widths, arrlen (utf8_widths)) == 1) { combining_data_version = U320; } else if (get_screen_width ("a܏", utf8_widths, arrlen (utf8_widths)) == 1) { combining_data_version = U300; } else { combining_data_version = U300beta; } trace_width_data_version ("comb"); if (width_data_version >= U320) { swidth = get_screen_width ("‘’“”…―­", utf8_widths, arrlen (utf8_widths)); if (swidth > 8) { /* xterm -cjk_width (since xterm 168) */ #ifdef consider_wide_block_slices /* not useful since block chars used for fine scrollbar have ambiguous width */ if (! explicit_scrollbar_style) { fine_scrollbar = False; } #else fine_scrollbar = False; #endif if (! explicit_border_style) { use_stylish_menu_selection = False; } if (swidth & 1) { /* soft hyphen is narrow, Unicode 4.0 */ cjk_width_data_version = U400; /* ? if (width_data_version < U400) { width_data_version = U400; } */ } else { /* soft hyphen is wide (ambiguous), Unicode 3.0/3.2 */ cjk_width_data_version = U320beta; } trace_width_data_version ("cjk"); } #ifdef single_width_check swidth = get_screen_width ("…―…", utf8_widths, arrlen (utf8_widths)); if ((swidth & 1) == 0) { /* ― is wide */ } if (swidth >= 5) { /* … is wide */ } #endif } /* check non-BMP width properties */ nonbmp_width_data = get_screen_width ("𠀀𠀀𠀀𠀀a𝆪a𝆪a󠀠", utf8_widths, arrlen (utf8_widths)) - 7; if (nonbmp_width_data > 7) { /* non-BMP combining characters are wide; xterm -cjk_width ? */ nonbmp_width_data -= 3; } /* check Yijing Hexagram width (wcwidth glitch) */ if (get_screen_width ("䷀", utf8_widths, arrlen (utf8_widths)) == 1) { wide_Yijing_hexagrams = False; } } else { utf8_screen = False; utf8_input = False; if (! combining_screen_selected) { combining_screen = False; combining_mode = False; } acquire_screen_widths (cjk_widths, arrlen (cjk_widths)); if (swidth > 13) { cwidth = get_screen_width ("02", cjk_widths, arrlen (cjk_widths)); if (cwidth > 2) { /* quite safe detection */ gb18030_term = False; } else if (cwidth >= 0) { cjk_term = True; if (cwidth == 1) { cjk_uni_term = True; } } /* if any of the following characters is smaller than 2 character cells, it's not a native CJK terminal */ cwidth = get_screen_width ("ꥦޡ", cjk_widths, arrlen (cjk_widths)); if (cwidth < 10) { cjk_uni_term = True; } cwidth = get_screen_width ("", cjk_widths, arrlen (cjk_widths)); if (cwidth > 2) { /* quite safe detection */ euc4_term = False; } else if (cwidth >= 0) { if (! mapped_term) { cjk_term = True; } } if (euc3_term && get_screen_width ("x", cjk_widths, arrlen (cjk_widths)) > 3) { /* unsafe detection */ euc3_term = False; } if (get_screen_width ("", cjk_widths, arrlen (cjk_widths)) < 2) { cjklow_term = False; } } if ((swidth > 10 && swidth != 13 && swidth != 15 && swidth < 18) || cjk_term) { /* if the test string width did not comply with 8 bit behaviour, or a GB18030 or EUC 4 byte (EUC-TW) terminal was asserted, assume CJK terminal; a EUC 3 byte (EUC-JP) terminal cannot be asserted but can just be assumed as an 8 bit terminal might respond with the same width behaviour */ utf8_screen = False; utf8_input = False; if (! combining_screen_selected) { combining_screen = False; combining_mode = False; } /* assume CJK terminal with unspecific encoding */ if (! mapped_term) { cjk_term = True; } } } trace_encoding ("detected"); } /* determine combining character support on non-Unicode terminal */ if (cjk_term) { unsigned long cjk_combining = mappedtermchar (0x0300); if (no_char (cjk_combining)) { combining_screen = False; } else { char cjk_check [9]; char * check = cjk_check; * check ++ = 'a'; check += cjkencode_char (True, cjk_combining, check); * check = '\0'; if (get_screen_width (cjk_check, NIL_PTR, 0) == 1) { combining_screen = True; if (! combining_mode_disabled) { combining_mode = True; } #ifdef debug_screenmode printf ("cjk combining screen %d (disabled %d) mode %d\n", combining_screen, combining_mode_disabled, combining_mode); #endif } } } else if (mapped_term) { character c; combining_screen = False; for (c = 0x80; ; c ++) { unsigned long u = lookup_mappedtermchar (c); if (! no_unichar (u) && iscombining (u)) { char comb_check [3]; comb_check [0] = 'a'; comb_check [1] = c; comb_check [2] = '\0'; if (get_screen_width (comb_check, NIL_PTR, 0) == 1) { combining_screen = True; if (! combining_mode_disabled) { combining_mode = True; } } break; } if (c == 0xFF) { break; } } } /* determine joining character support on non-Unicode terminal */ if (cjk_term || mapped_term) { unsigned long lam = mappedtermchar (0x0644); if (! no_char (lam)) { unsigned long alef = mappedtermchar (0x0627); char join_check [9]; char * check = join_check; * check ++ = 'a'; if (cjk_term) { check += cjkencode_char (True, lam, check); check += cjkencode_char (True, alef, check); } else { * check ++ = lam; * check ++ = alef; } * check = '\0'; if (get_screen_width (join_check, NIL_PTR, 0) == 2) { /* ligature joining detected, must also be bidi */ bidi_screen = True; poormansbidi = False; /* disable scrollbar to prevent interference */ disp_scrollbar = False; scrollbar_width = 0; /* bold does not work */ use_bold = False; /* mouse hilite tracking does not work */ mouse_hilite_tracking = False; #ifdef debug_screenmode printf ("bidi screen\n"); #endif } } } /* configure line markers */ config_markers (); /* adjust CJK width properties */ /* adjust CJK line markers */ if (cjk_term) { /* determine size of line markers in CJK terminal encoding */ int cjk_tab3_width; int cjk_tab1_width; unsigned long cjk_lineend = mappedtermchar (0x300A); /* 《 */ unsigned long cjk_tab = mappedtermchar (0x00B7); /* · */ unsigned long cjk_tab3 = mappedtermchar (0x2026); /* … */ char cjk_check [29]; char * check = cjk_check; int cjkwidth; check += cjkencode_char (True, cjk_lineend, check); check += cjkencode_char (True, cjk_lineend, check); check += cjkencode_char (True, cjk_lineend, check); check += cjkencode_char (True, cjk_lineend, check); check += cjkencode_char (True, cjk_tab, check); check += cjkencode_char (True, cjk_tab, check); check += cjkencode_char (True, cjk_tab3, check); * check = '\0'; cjkwidth = get_screen_width (cjk_check, NIL_PTR, 0); cjkwidth --; cjk_tab3_width = 1 + (cjkwidth & 1); cjkwidth = (cjkwidth >> 1) - 1; cjk_tab1_width = 1 + (cjkwidth & 1); cjkwidth = (cjkwidth >> 1) - 1; cjk_lineend_width = 1 + (cjkwidth & 1); if (cjk_uni_term) { unsigned long cjk_char; if (cjk_lineend_width == 1) { width_data_version = U300; } else if (cjk_tab3_width == 2) { cjk_width_data_version = U400; /* ? if (width_data_version < U400) { width_data_version = U400; } */ check = cjk_check; cjk_char = mappedtermchar (0x00F8); /* ø */ check += cjkencode_char (True, cjk_char, check); check += cjkencode_char (True, cjk_char, check); cjk_char = mappedtermchar (0x00AD); /* SOFT HYPHEN */ if (! no_char (cjk_char)) { check += cjkencode_char (True, cjk_char, check); cjkwidth = 0; } else { cjkwidth = 2; } * check = '\0'; cjkwidth += get_screen_width (cjk_check, NIL_PTR, 0); if ((cjkwidth & 1) == 0) { cjk_width_data_version = U320beta; } if (cjkwidth > 4) { cjk_wide_latin1 = True; } else { cjk_wide_latin1 = False; } } else if (cjk_tab1_width == 1) { /* fix this as a work-around for buggy rxvt */ width_data_version = U320; } trace_width_data_version ("cjk_uni_term"); #ifdef debug_screenmode printf ("cjk_uni_term (width_data_version %d CJK %d) ", width_data_version, cjk_width_data_version); #endif } #ifdef debug_screenmode printf ("CJK %c\n", text_encoding_tag); printf ("euc3 %d, euc4 %d, low cjk %d\n", euc3_term, euc4_term, cjklow_term); #endif if (CJK_TAB_marker >= 0x80) { #ifdef CJKTAB_MIDDLE_DOT /* does not work with JIS and Johab fonts */ CJK_TAB_marker = 0x00B7; cjk_tab_width = cjk_tab1_width; #else cjk_tab_width = cjk_tab3_width; #endif if (term_encoding_tag == 'H') { /* work-around for buggy hanterm */ CJK_TAB_marker = '.'; } if (limited_marker_font) { CJK_TAB_marker = '.'; } } if (CJK_TAB_marker < 0x80) { cjk_tab_width = 1; } /* ensure further markers work for CJK */ SHIFT_marker = ' '; } /* adjust wide line markers */ if (cjk_width_data_version) { if (UTF_TAB_marker && iswide (utf8value (UTF_TAB_marker))) { UTF_TAB_marker = NIL_PTR; } if (UTF_TAB0_marker && iswide (utf8value (UTF_TAB0_marker))) { UTF_TAB0_marker = NIL_PTR; } if (UTF_TAB2_marker && iswide (utf8value (UTF_TAB2_marker))) { UTF_TAB2_marker = NIL_PTR; } if (UTF_TABmid_marker && iswide (utf8value (UTF_TABmid_marker))) { UTF_TABmid_marker = NIL_PTR; } } #ifdef debug_screenmode printf ("width_data_version %d (CJK %d), combining_data_version %d\n", width_data_version, cjk_width_data_version, combining_data_version); #else trace_width_data_version ("final"); #endif /* request terminal type and version from terminal */ if ((strisprefix ("xterm", envvar ("TERM")) || strisprefix ("rxvt", envvar ("TERM"))) && ! bidi_screen) { /* suppress for mlterm */ acquire_device_attributes (); if ((terminal_type | 1) == 1 && ! getenv ("KONSOLE_DCOP")) { xterm_version = terminal_version; } else if (terminal_type == 82) { rxvt_version = terminal_version / 100; } else if (terminal_type == 85) { rxvt_version = terminal_version * 10; } } /* try to detect gnome-terminal */ if (strisprefix ("gnome-terminal", envvar ("COLORTERM"))) { gnome_terminal_version = 1; } if (xterm_version >= 1115) { /* probably gnome-terminal */ gnome_terminal_version = xterm_version; } /* indicate enabling of special terminal modes */ if (xterm_version >= 216) { use_modifyOtherKeys = True; /*use_appl_keypad = True;*/ } /* suppress mouse highlight tracking when it would lock xterm */ if (xterm_version == 224) { /* xterm bug broke hilite mode abort sequence */ mouse_hilite_tracking = False; } /* suppress fancy graphic characters in gnome-terminal */ if (gnome_terminal_version > 0) { /* probably gnome-terminal */ menu_border_style = 's'; use_stylish_menu_selection = False; fine_scrollbar = False; /* make menu selections more visible */ dark_term = True; } /* special cases of terminal capabilities handling (esp. block graphics) */ if (strcontains (envvar ("TERM"), "vt220") || strcontains (envvar ("TERM"), "vt320") || strcontains (envvar ("TERM"), "vt340") || strcontains (envvar ("TERM"), "vt400") || strcontains (envvar ("TERM"), "vt420") || strcontains (envvar ("TERM"), "vt510") || strcontains (envvar ("TERM"), "vt520") || strcontains (envvar ("TERM"), "vt525") || strisprefix ("pcvt", envvar ("TERM")) || strisprefix ("ncsa", envvar ("TERM")) || strisprefix ("ti916", envvar ("TERM")) || strisprefix ("bq300", envvar ("TERM")) || strisprefix ("z340", envvar ("TERM")) || strisprefix ("ncr160vt300", envvar ("TERM")) || strisprefix ("ncr260vt300", envvar ("TERM")) || streq ("emu-220", envvar ("TERM")) || streq ("crt", envvar ("TERM")) ) { use_appl_keypad = True; } if (strcontains (envvar ("TERM"), "linux")) { fine_scrollbar = False; use_stylish_menu_selection = False; dark_term = True; use_appl_keypad = True; if (explicit_border_style == False) { if (utf8_screen) { /*use_ascii_graphics = True;*/ if (! explicit_border_style) { if (! use_ascii_graphics) { menu_border_style = 's'; } } } else if (use_vt100_block_graphics == False) { use_vga_block_graphics = True; } } } if (! can_alt_cset && ! use_pc_block_graphics && ! utf8_screen ) { use_ascii_graphics = True; } if (cjk_term) { /* make sure lineend marker will always fit: */ scrollbar_width = 1; /*use_bgcolor = False;*/ if (strisprefix ("rxvt", envvar ("TERM"))) { /* seems to work now */ } else { /* cxterm would blink instead of setting 256 color mode */ colours_256 = False; colours_88 = False; } } #ifdef debug_graphics printf ("ascii %d, vga %d, vt100 %d\n", use_ascii_graphics, use_vga_block_graphics, use_vt100_block_graphics); #endif /* derive further terminal restrictions */ if (standout_glitch) { use_bold = False; } /* set configured keyboard mapping */ #ifndef msdos setKEYMAP (getenv ("MINEDKEYMAP")); #endif /* rxvt-specific properties */ if (strisprefix ("rxvt", envvar ("TERM"))) { /* rxvt-unicode sometimes displays all unassigned Unicode chars in single width; According to change log, this could have been fixed in: 4.4: rewrote handling of default-char width 8.0: fixed urxvt::strwidth to calculate width in the same way as screen.C 8.1: rewrote handling of default-char width It does not happen with cygwin rxvt-unicode (which is not locale-driven) */ if (rxvt_version > 0) { if (get_screen_width ("㄀ㄯ㄰㆏꒎꓏﫿﹯＀", NIL_PTR, 0) < 18) { unassigned_single_width = True; } } /* rxvt does not modify escape sequences for Alt etc */ detect_esc_alt = True; /* disable use of VT100 block graphics on rxvt which does not support them */ if (! utf8_screen) { /* VT100 block graphics work now with workaround for missing eA capability (see io.c) */ if (rxvt_version < 300) { /* VT100 block graphics depend on font capabilities */ use_ascii_graphics = True; } } } /* mlterm-specific properties */ if (bidi_screen) { /* probably mlterm */ unassigned_single_width = True; spacing_combining = True; } /* workaround for mlterm deficiencies */ if (bidi_screen) { /* probably mlterm */ /* bold does not work */ use_bold = False; /* mouse hilite tracking does not work */ mouse_hilite_tracking = False; } /* workaround for buggy mlterm bold/width chaos */ #ifdef oldmlterm_wideboldborderbug_workaround if (! explicit_border_style && ! cjk_width_data_version) { bold_on (); /* check width of upper left rounded corner */ if (get_screen_width ("╭", utf8_widths, arrlen (utf8_widths)) > 1) { use_vt100_block_graphics = True; } bold_off (); } #endif /* disable use of some features on kde konsole */ if (getenv ("KONSOLE_DCOP")) { konsole_version = 1; colours_256 = False; mouse_hilite_tracking = False; if (! utf8_screen) { /* VT100 block graphics work now with workaround for missing eA capability (see io.c) */ /* disable use of VT100 block graphics for konsole instances that do not support them */ if (strcontains (envvar ("TERM"), "linux")) { use_ascii_graphics = True; use_vga_block_graphics = False; } } /* disable use of Unicode fine-grained block graphics */ if (! explicit_border_style) { use_stylish_menu_selection = False; if (! use_ascii_graphics) { menu_border_style = 's'; } } /* make menu selections more visible */ dark_term = True; } #ifdef debug_graphics printf ("ascii %d, vga %d, vt100 %d\n", use_ascii_graphics, use_vga_block_graphics, use_vt100_block_graphics); #endif /* disable graphics on some CJK terminals */ if (cjk_term && ! use_vt100_block_graphics && ! can_alt_cset) { use_ascii_graphics = True; } #ifdef debug_graphics printf ("ascii %d, vga %d, vt100 %d\n", use_ascii_graphics, use_vga_block_graphics, use_vt100_block_graphics); #endif /* setup terminal modes */ /* call raw_mode again (was already called for initial tty configuration) */ raw_mode (True); /* terminal height adjustment / detection */ /* xterm control codes useful here: ESC[t (n>=24) resize to n lines ESC[18t report size of text area as ESC[8;;t ESC[8;;t resize text area */ if (ansi_esc) { #ifdef adjust_terminal_height if (strisprefix ("xterm", envvar ("TERM"))) { /* try to adjust the window to the size the tty assumes; esp. for buggy Cygwin/X xterm tty size assumption, also work-around for various rlogin/telnet size confusions */ char resizebuf [19]; int height = YMAX + 1 + MENU; #ifdef adjust_lines_only if (height >= 24) { /* this short form doesn't work with rxvt (which would become extra large) */ build_string (resizebuf, "\033[%dt", height); } else { #endif build_string (resizebuf, "\033[8;%d;%dt", height, XMAX + 1); #ifdef adjust_lines_only } #endif putescape (resizebuf); } #else #ifdef adjust_to_actual_termsize unsigned long c; /* response will be handled by ANSIseq */ putescape ("\033[18t"); flush (); #endif #endif } } /*======================================================================*\ |* Main *| \*======================================================================*/ #define dont_debug_ansiseq /** Check ANSI escape sequence (which has already been read) */ void ANSIseq () { #ifdef debug_ansiseq printf ("ANSIseq %d:", ansi_params); { int i; for (i = 0; i < ansi_params; i ++) { printf (" %d", ansi_param [i]); } printf (" %c\n", ansi_fini); } #endif if (ansi_fini == 'R') { status_line ("Late screen mode response ", "- set ESCDELAY=2000 or higher for proper detection"); } else if (ansi_fini == 't') { if (ansi_params == 3 && ansi_param [0] == 8) { #ifdef adjust_to_actual_termsize /* adjust to actual screen size reported by terminal */ if (YMAX != ansi_param [1] - 1 - MENU || XMAX != ansi_param [2] - 1) { YMAX = ansi_param [1] - 1 - MENU; XMAX = ansi_param [2] - 1; RD (); ... see RDwin flush (); } #endif } else { error ("Unknown terminal status report"); } } else if (ansi_fini == 'c') { error ("Unexpected device attribute report"); } else { error ("Unknown keyboard control sequence"); } } /** Read ANSI escape sequence that has been started with ESC [ (but too slowly to be recognised on keyboard input level); swallow [, 0-9, and ; characters plus final letter, @ or ~ */ static void CSI () { character c; if (in_status_line) { ring_bell (); } else { error ("... absorbing slow terminal escape sequence ..."); } flush (); while (char_ready_within (escape_delay) && ((c = read1byte ()) == '[' || c == ';' || (c >= '0' && c <= '9') ) ) { } if (! in_status_line) { error ("... discarded slow terminal escape sequence; re-enter function key"); } } /** Read terminal report string which has been started with ESC ] */ static void OSC () { character c; if (in_status_line) { ring_bell (); } else { error ("... absorbing slow terminal report string ..."); } flush (); while (char_ready_within (escape_delay) && (c = read1byte ()) >= ' ') { } if (c == '\033') { if (char_ready_within (escape_delay)) { read1byte (); } } if (! in_status_line) { clear_status (); } } static void WordStar_keys () { int i; for (i = 0; i < 32; i ++) { key_map [i] = ws_key_map [i]; } emulation = 'w'; emacs_buffer = False; paste_stay_left = True; } static void pico_keys () { int i; for (i = 0; i < 32; i ++) { key_map [i] = pico_key_map [i]; } emulation = 'p'; emacs_buffer = True; paste_stay_left = False; JUSmode = 1; } static void set_emacs_mode () { int i; for (i = 0; i < 32; i ++) { key_map [i] = emacs_key_map [i]; } /* key_map ['\177'] = DPC; */ /* rather automatically adapt to stty */ quit_char = '\007'; /* ^G */ emulation = 'e'; emacs_buffer = True; paste_stay_left = False; JUSmode = 1; } /* check if string w matches initial words of string s (esp. a locale prefix) "ti" "ti_ER" -> True "ti" "tig_ER" -> False "ti_ER" "ti_ER.UTF-8" -> True "aa_E*" "aa_ER" -> True */ static FLAG matchwords (w, s) char * w; char * s; { if (strisprefix (w, s)) { char fini = s [strlen (w)]; if ((fini >= 'A' && fini <= 'Z') || (fini >= 'a' && fini <= 'z')) { return False; } else { return True; } } else if (w [strlen (w) - 1] == '*' && strncmp (s, w, strlen (w) - 1) == 0) { return True; } else { return False; } } static FLAG set_charmap_2 (term, charmap_term, charmap_text) FLAG term; char * charmap_term; char * charmap_text; { if (term) { return set_term_encoding (charmap_term, ' '); } else { return set_text_encoding (charmap_text, ' ', "set_charmap_2"); } } static FLAG set_charmap (term, charmap) FLAG term; char * charmap; { if (term) { return set_term_encoding (charmap, ' '); } else { return set_text_encoding (charmap, ' ', "set_charmap"); } } static struct { char * locale; char * charmap; char * charmap_text; } locmaps [] = { #include "locales.t" }; static FLAG handle_locale (term, encoding) FLAG term; char * encoding; { /* determine language-specific text handling features */ if (! term) { if (matchwords ("de", language_code)) { language_tag = 'g'; } else if (matchwords ("da", language_code)) { language_tag = 'd'; } else if (matchwords ("fr", language_code)) { language_tag = 'f'; } else if (matchwords ("tr", language_code) || matchwords ("az", language_code)) { language_tag = 't'; Turkish = True; } else if (matchwords ("lt", language_code)) { language_tag = 'l'; Lithuanian = True; } } /* detect CJK encodings by locale suffixes; if there is no encoding suffix (starting after "."), as a fallback, try to interpret the country suffix (starting with '_' as returned by the functions above) */ if (strisprefix ("GB", encoding) || strisprefix ("gb", encoding) || strisprefix ("EUC-CN", encoding) || strisprefix ("euccn", encoding) || strisprefix ("eucCN", encoding) ) { return set_charmap (term, "GB"); } else if (strisprefix ("BIG5", encoding) || strisprefix ("Big5", encoding) || strisprefix ("big5", encoding) ) { return set_charmap (term, "Big5"); } else if (strisprefix ("EUC-TW", encoding) || strisprefix ("euctw", encoding) || strisprefix ("eucTW", encoding) ) { return set_charmap (term, "CNS"); } else if (strisprefix ("UHC", encoding) || strisprefix ("EUC-KR", encoding) || strisprefix ("euckr", encoding) || strisprefix ("eucKR", encoding) ) { return set_charmap (term, "UHC"); } else if (strisprefix ("EUC-JP", encoding) || strisprefix ("eucjp", encoding) || strisprefix ("eucJP", encoding) || strisprefix ("ujis", encoding) ) { return set_charmap (term, "EUC-JP"); } else if (strisprefix ("Shift_JIS", encoding) || strisprefix ("shiftjis", encoding) || strisprefix ("sjis", encoding) || strisprefix ("SJIS", encoding) ) { return set_charmap (term, "Shift-JIS"); } else if (strisprefix ("JOHAB", encoding)) { return set_charmap (term, "Johab"); } else if (strisprefix ("@euro", encoding)) { return set_charmap (term, "ISO-8859-15"); } else if (strisprefix ("@cyrillic", encoding)) { if (matchwords ("uz_UZ", language_code)) { return set_charmap (term, "UTF-8"); } else { return set_charmap (term, "ISO-8859-5"); } } else if (strisprefix ("iso8859", encoding) || strisprefix ("ISO8859", encoding)) { encoding += 7; if (* encoding == '-' || * encoding == '_') { encoding ++; } if (streq ("1", encoding)) { return set_charmap (term, "ISO-8859-1"); } else if (streq ("5", encoding)) { return set_charmap (term, "ISO-8859-5"); } else if (streq ("6", encoding)) { return set_charmap_2 (term, "ISO-8859-6", "MacArabic"); } else if (streq ("7", encoding)) { return set_charmap (term, "ISO-8859-7"); } else if (streq ("8", encoding)) { return set_charmap_2 (term, "ISO-8859-8", "CP1255"); } else if (streq ("15", encoding)) { return set_charmap (term, "ISO-8859-15"); } else if (streq ("2", encoding)) { return set_charmap (term, "ISO-8859-2"); } else if (streq ("3", encoding)) { return set_charmap (term, "ISO-8859-3"); } else if (streq ("4", encoding)) { return set_charmap (term, "ISO-8859-4"); } else if (streq ("9", encoding)) { return set_charmap (term, "ISO-8859-9"); } else if (streq ("10", encoding)) { return set_charmap (term, "ISO-8859-10"); } else if (streq ("13", encoding)) { return set_charmap (term, "ISO-8859-13"); } else if (streq ("14", encoding)) { return set_charmap (term, "ISO-8859-14"); } else if (streq ("16", encoding)) { return set_charmap (term, "ISO-8859-16"); } else if (streq ("11", encoding)) { return set_charmap (term, "TIS"); } } else if (strisprefix ("koi8t", encoding)) { return set_charmap (term, "KOI8-T"); } else if (strisprefix ("koi8r", encoding)) { return set_charmap_2 (term, "KOI8-R", "KOI8-RU"); } else if (strisprefix ("koi8u", encoding)) { return set_charmap_2 (term, "KOI8-U", "KOI8-RU"); } else if (strisprefix ("koi", encoding)) { return set_charmap (term, "KOI8-RU"); } else if (strisprefix ("tcvn", encoding)) { return set_charmap (term, "TCVN"); } else if (strisprefix ("viscii", encoding)) { return set_charmap (term, "VISCII"); } else if (strisprefix ("tis", encoding) || strisprefix ("TIS", encoding) ) { return set_charmap (term, "TIS"); } else if (strisprefix ("roman", encoding)) { return set_charmap (term, "MacRoman"); } else if (strisprefix ("cp1252", encoding)) { return set_charmap (term, "CP1252"); } else if (strisprefix ("cp1251", encoding)) { return set_charmap (term, "CP1251"); } else if (strisprefix ("cp850", encoding)) { return set_charmap (term, "CP850"); } else if (strisprefix ("cp1255", encoding)) { return set_charmap (term, "CP1255"); } else if (strisprefix ("georgianps", encoding)) { return set_charmap (term, "Georgian-PS"); } else if (strisprefix ("pt154", encoding)) { return set_charmap (term, "PT154"); } else if (strisprefix ("utf8", encoding) || strisprefix ("UTF-8", encoding) ) { return set_charmap (term, "UTF-8"); } else { int i; for (i = arrlen (locmaps) - 1; i >= 0; i --) { if (matchwords (locmaps [i].locale, language_code)) { if (! term && locmaps [i].charmap_text) { return set_charmap (False, locmaps [i].charmap_text); } else { return set_charmap (term, locmaps [i].charmap); } } } } return False; } static void eval_options (minedopt, command_line) char * minedopt; FLAG command_line; { FLAG plus_opt = False; /* set if options start with '+' */ FLAG Cflag = False; /* -C interacts with -E for compatibility */ while (* minedopt != '\0') { switch (* minedopt) { case '+': plus_opt = True; break; case '-': plus_opt = False; minedopt ++; if (* minedopt == '-') { restricted = True; } else { minedopt --; } break; case ' ': break; case 'M': MENU = 1 - MENU; break; case '*': use_mouse = False; break; case 'L': minedopt ++; minedopt = scan_int (minedopt, & wheel_scroll); minedopt --; break; case 'v': init_viewonly = True; viewonly = True; break; case 'P': if (plus_opt) { hide_password = False; hide_password_mode = 2; } else { hide_password = True; hide_password_mode = 0; } break; case 'p': if (plus_opt) { proportional = True; } else { paradisp = True; } break; case 'r': if (RET_opt == 'r') { RET_opt = ' '; } else { RET_opt = 'r'; } break; case 'R': if (plus_opt) { RET_opt = 'M'; } else { RET_opt = 'R'; } break; case 'Q': minedopt ++; explicit_border_style = command_line; if (* minedopt >= '0' && * minedopt <= '9') { menumargin = * minedopt - '0'; } else if (* minedopt == 'Q') { use_stylish_menu_selection = True; } else if (* minedopt == 'q') { use_stylish_menu_selection = False; } else if (* minedopt == 'a') { use_ascii_graphics = True; } else if (* minedopt == 'v') { use_vt100_block_graphics = True; } else { menu_border_style = * minedopt; } break; case 'f': if (menu_border_style == 's') { if (use_vt100_block_graphics) { use_ascii_graphics = True; menu_border_style = 'r'; use_vt100_block_graphics = False; } else { use_vt100_block_graphics = True; } } else { menu_border_style = 's'; } use_stylish_menu_selection = False; fine_scrollbar = False; break; case 'F': if (limited_marker_font) { very_limited_marker_font = True; } else { limited_marker_font = True; } break; case 'o': minedopt ++; explicit_scrollbar_style = command_line; switch (* minedopt) { case '0': disp_scrollbar = False; scrollbar_width = 0; break; case '1': disp_scrollbar = True; fine_scrollbar = False; scrollbar_width = 1; break; case '2': disp_scrollbar = True; fine_scrollbar = True; scrollbar_width = 1; break; case '8': update_scrollbar_lazy = False; break; case '9': update_scrollbar_lazy = True; break; default: minedopt --; /* compatibility */ if (disp_scrollbar) { disp_scrollbar = False; scrollbar_width = 0; /* compatibility with 2000.6 beta */ if (utf8_screen) { bidi_screen = True; poormansbidi = False; } } else if (bidi_screen == False) { disp_scrollbar = True; scrollbar_width = 1; } } break; case 'c': if (plus_opt == False) { if (combining_mode_disabled) { combining_screen = False; } else { combining_mode = False; combining_mode_disabled = True; } } else { combining_screen = True; combining_mode = True; combining_screen_selected = True; } break; case 'C': if (plus_opt) { cjk_term = True; /* output CJK encoded characters transparently */ if (suppress_unknown_cjk) { suppress_unknown_cjk = False; } else if (suppress_invalid_cjk) { suppress_invalid_cjk = False; } else { suppress_extended_cjk = False; } /* output non-Unicode codes transparently */ if (suppress_EF) { suppress_EF = False; } else if (suppress_surrogates) { suppress_surrogates = False; } else { suppress_non_Unicode = False; } } else { Cflag = True; } break; case 'U': if (plus_opt) { if (U_mode_set) { bidi_screen = True; poormansbidi = False; /* disable scrollbar to prevent interference */ disp_scrollbar = False; scrollbar_width = 0; } else { utf8_screen = True; utf8_input = True; combining_screen = True; combining_mode = True; U_mode_set = True; cjk_term = False; } } else if (utf8_input) { utf8_screen = False; utf8_input = False; combining_screen = False; combining_mode = False; } else { utf8_screen = True; utf8_input = True; combining_screen = True; combining_mode = True; cjk_term = False; } break; case 'u': auto_detect = False; if (plus_opt) { (void) set_text_encoding (NIL_PTR, 'L', "+u"); utf8_lineends = False; } else { (void) set_text_encoding (NIL_PTR, 'U', "-u"); text_encoding_selected = True; } break; case 'l': auto_detect = False; (void) set_text_encoding (NIL_PTR, 'L', "-l"); text_encoding_selected = True; break; case 'E': minedopt ++; if (* minedopt == '?') { if (plus_opt) { only_detect_terminal_encoding = True; } else { only_detect_text_encoding = True; } } else if (* minedopt == 'u') { pastebuf_utf8 = True; } else if (* minedopt == 'U' || * minedopt == 'L') { if (plus_opt) { cjk_term = False; mapped_term = False; if (* minedopt == 'U') { utf8_screen = True; utf8_input = True; combining_screen = True; combining_mode = True; } else { utf8_screen = False; utf8_input = False; combining_screen = False; combining_mode = False; } term_encoding_selected = True; } else { auto_detect = False; (void) set_text_encoding (NIL_PTR, * minedopt, "-EU/L"); text_encoding_selected = True; } } else if (* minedopt == '.') { minedopt ++; if (handle_locale (plus_opt, minedopt)) { if (plus_opt) { term_encoding_selected = True; } else { auto_detect = False; text_encoding_selected = True; } } else { fprintf (stderr, "Unknown encoding suffix %s\n", minedopt); sleep (1); } while (* minedopt) { minedopt ++; } } else if (* minedopt == '=') { minedopt ++; if (set_charmap (plus_opt, minedopt)) { if (plus_opt) { term_encoding_selected = True; } else { auto_detect = False; text_encoding_selected = True; } } else { fprintf (stderr, "Unknown charmap %s\n", minedopt); sleep (1); } while (* minedopt) { minedopt ++; } } else if (* minedopt == ':') { if (set_charmap (plus_opt, minedopt)) { if (plus_opt) { term_encoding_selected = True; } else { auto_detect = False; text_encoding_selected = True; } } else { fprintf (stderr, "Unknown encoding flag %s\n", minedopt + 1); sleep (1); } minedopt ++; if (* minedopt) { minedopt ++; } if (* minedopt) { minedopt ++; } } else if (* minedopt != '\0') { char enctag = * minedopt; switch (enctag) { case 'g': if (plus_opt || Cflag) { gb18030_term = False; } enctag = 'G'; break; case 'j': if (plus_opt || Cflag) { euc3_term = False; } enctag = 'J'; break; case 'c': if (plus_opt || Cflag) { euc4_term = False; } enctag = 'C'; break; } if (plus_opt || Cflag) { if (set_term_encoding (NIL_PTR, enctag)) { term_encoding_selected = True; } else { fprintf (stderr, "Unknown encoding tag %c\n", * minedopt); sleep (1); break; } } if (! plus_opt) { if (set_text_encoding (NIL_PTR, enctag, "-E")) { auto_detect = False; text_encoding_selected = True; } else { fprintf (stderr, "Unknown encoding tag %c\n", * minedopt); sleep (1); break; } } } break; case 'b': if (poormansbidi) { poormansbidi = False; } else { poormansbidi = True; bidi_screen = False; } break; case 'K': if (plus_opt) { enforce_keymap = True; } else { minedopt ++; selection_space = * minedopt; } break; case 'D': configure_xterm_keyboard = plus_opt; break; case 'w': if (wordnonblank) { wordnonblank = False; } else { wordnonblank = True; } break; case 'a': append_flag = True; break; case 'j': if (plus_opt) { if (JUSlevel < 2) { JUSlevel ++; } } else if (JUSlevel == 1) { JUSlevel = 2; } else { JUSlevel = 1; } break; case 'J': JUSlevel = 2; break; case 'k': mined_keypad = False; break; case 'B': if (plus_opt) { blink_cursor = True; } else { /* key_map ['\010'] = DPC; key_map ['\177'] = DCC; */ key_map ['\010'] = MLF; key_map ['\177'] = DPC; } break; case 'T': tab_left = False; break; case 'W': WordStar_keys (); break; case 'e': set_emacs_mode (); break; case 'V': if (plus_opt) { if (paste_stay_left) { paste_stay_left = False; } else { emacs_buffer = True; } } else { if (! paste_stay_left) { paste_stay_left = True; } else { emacs_buffer = False; } } break; case 's': page_stay = True; break; case 'S': page_scroll = True; break; case 'x': xprot = exeprot; break; case 'X': no_window_title = True; break; case 't': minedopt ++; if (* minedopt == '\0') { TAB_marker = TABdefault; } else { TAB_marker = * minedopt; } break; case 'd': minedopt ++; if (* minedopt == '-') { display_delay = -1; } else if (* minedopt >= '0' && * minedopt <= '9') { display_delay = (int) * minedopt - (int) '0'; } else { minedopt --; } break; case '4': tabsize = 4; expand_tabs = plus_opt; break; case '8': tabsize = 8; expand_tabs = plus_opt; break; case '/': minedopt ++; inisearch = minedopt; return; default: fprintf (stderr, "Unknown option %c\n", * minedopt); if (command_line) { sleep (1); } break; } if (* minedopt != '\0') { minedopt ++; } } } /** configuration and initialisation; load the file (if any); main loop of the editor */ int main (argc, argv) int argc; char * argv []; { unsigned long inputchar; int initlinenum; int initlini = 0; LINE * initline; FLAG goon; FLAG cursor_somewhere = False; char * env; char * minedopt; /* determine various modes and display options from environment settings */ if (getenv ("NoCtrlSQ") || getenv ("NoControlSQ")) { /* ^S and ^Q may come arbitrarily from terminal, so don't use them */ controlQS = True; key_map ['\021'] = I; key_map ['\023'] = I; } transout = envvar ("MINEDOUT"); if (* transout != '\0') { translen = strlen (transout); translate_output = True; use_ascii_graphics = True; } #ifdef unix if (getenv ("MINEDMODF")) { mined_modf = getenv ("MINEDMODF"); } #endif #ifdef pc_winlowdelay if (getenv ("windir")) { display_delay = 0; } #endif #ifdef debug_graphics printf ("ascii %d, vga %d, vt100 %d\n", use_ascii_graphics, use_vga_block_graphics, use_vt100_block_graphics); #endif /* process options configured in environment */ if ((minedopt = getenv ("MINED")) != NIL_PTR) { eval_options (minedopt, False); } /* derive screen mode and default text encoding from environment */ /* detect PC terminal modes for native PC and for telnet from PC to Unix */ #ifdef pc_term (void) set_term_encoding ("CP850", 'P'); #endif if (getenv ("TERM") && (strisprefix ("nansi", getenv ("TERM")) || strisprefix ("ansi.", getenv ("TERM")) || strisprefix ("opennt", getenv ("TERM")) || strcontains (getenv ("TERM"), "-emx") ) ) { dark_term = True; (void) set_term_encoding ("CP437", 'p'); term_encoding_selected = True; if (! text_encoding_selected) { (void) set_text_encoding ("CP850", 'P', "TERM=nansi"); } use_vga_block_graphics = True; mouse_button_event_tracking = False; } else if (getenv ("TERM") && (strisprefix ("pcansi", getenv ("TERM")) || strisprefix ("hpansi", getenv ("TERM")) || streq ("ansi", getenv ("TERM")) || streq ("ansi-nt", getenv ("TERM")) || strisprefix ("interix", getenv ("TERM")) ) ) { dark_term = True; (void) set_term_encoding ("CP850", 'P'); term_encoding_selected = True; if (! text_encoding_selected) { (void) set_text_encoding ("CP850", 'P', "TERM=pcansi"); } use_vga_block_graphics = True; mouse_button_event_tracking = False; } if (strisprefix ("ansi", envvar ("TERM"))) { use_ascii_graphics = True; } /* check if cygwin DOS box is configured to be in PC character set mode */ if (streq (envvar ("TERM"), "cygwin")) { dark_term = True; #ifdef msdos /* CP850; the cygwin emulation of CP1252 is not applied by the cygwin console but by the cygwin dll so it depends on the application running */ (void) set_term_encoding ("CP850", 'P'); #else if (strcontains (envvar ("CYGWIN"), "codepage:oem")) { /* CP850 */ (void) set_term_encoding ("CP850", 'P'); } else { if (! set_term_encoding (":cw", ' ')) { (void) set_term_encoding ("CP1252", 'W'); } use_pc_block_graphics = True; } term_encoding_selected = True; #endif if (! text_encoding_selected) { (void) set_text_encoding ("CP1252", 'W', "TERM=cygwin"); } } /* now derive screen mode and default text encoding from locale environment */ if (! term_encoding_selected) { (void) handle_locale (True, locale_terminal_encoding ()); trace_encoding ("term locale"); } if (! text_encoding_selected) { (void) handle_locale (False, locale_text_encoding ()); trace_encoding ("text locale"); } /* evaluate command line options (not file names) */ if (argv [0]) { minedopt = strrchr (argv [0], '/'); if (minedopt) { minedopt ++; } else { minedopt = argv [0]; } if (strisprefix ("r", minedopt)) { restricted = True; minedopt ++; } if (strisprefix ("minma", minedopt)) { eval_options ("-e", False); } else if (strisprefix ("mstar", minedopt)) { eval_options ("-W", False); } else if (strisprefix ("mpico", minedopt)) { pico_keys (); } } fnami = 1; goon = True; do { if (fnami < argc) { if (streq (argv [fnami], "++")) { fnami += 1; goon = False; } else if (* argv [fnami] == '+' && argv [fnami] [1] >= '0' && argv [fnami] [1] <= '9') { initlini = fnami; fnami += 1; } else if (* argv [fnami] == '-' || * argv [fnami] == '+' #ifdef msdos || * argv [fnami] == '/' #endif ) { minedopt = argv [fnami]; eval_options (minedopt, True); fnami += 1; } else { goon = False; } } else { goon = False; } } while (goon); #ifdef debug_graphics printf ("ascii %d, vga %d, vt100 %d\n", use_ascii_graphics, use_vga_block_graphics, use_vt100_block_graphics); #endif trace_encoding ("options"); fnami_min = fnami; fnami_max = argc - 1; /*fnami_cnt = argc - fnami_min;*/ fnamv = argv; if (! (fnami < argc)) { fnami = 0; } /* handling of input/output redirection */ /* Note: this must be called before terminal mode initialisation (get_term) */ /* Note: - input redirection does not work with DOS version - handling of input/output redirection has to be suppressed in DOSBox or mined cannot start there (probably a DOSBox bug) */ #ifdef msdos if (strisprefix ("Z:\\", envvar ("COMSPEC"))) { /* DOSBox detected */ } else #endif { if (! isatty (STD_IN)) { /* Reading from pipe */ if (fnami != 0) { panic ("Cannot read both pipe and file", NIL_PTR); } reading_pipe = True; set_modified (); /* Set modified flag not to loose buffer */ #ifdef msdos panic ("Cannot edit after input from pipe", "MSDOS incompatibility"); #else if ((input_fd = open ("/dev/tty", O_RDONLY, 0)) < 0) { panic ("Cannot open /dev/tty for read", serror ()); } #endif } if (! isatty (STD_OUT)) { writing_pipe = True; set_modified (); /* Set modified flag not to ignore buffer on exit */ if ((output_fd = open ("/dev/tty", O_WRONLY, 0)) < 0) { panic ("Cannot open /dev/tty for write", serror ()); } } } /* determine terminal-specific escape sequences and restrictions */ if (strisprefix ("vt100", envvar ("TERM"))) { set_fkeymap ("vt100"); } if (strisprefix ("rxvt", envvar ("TERM"))) { set_fkeymap ("rxvt"); } if (strisprefix ("hp", envvar ("TERM")) || streq ("xterm-hp", envvar ("TERM")) || strisprefix ("superbee", envvar ("TERM")) || strisprefix ("sb", envvar ("TERM")) || strisprefix ("microb", envvar ("TERM")) ) { if (! streq ("hpansi", envvar ("TERM"))) { set_fkeymap ("hp"); } use_ascii_graphics = True; use_bold = False; } if (streq ("vt52", envvar ("TERM")) || strcontains (envvar ("TERM"), "-vt52") ) { set_fkeymap ("52"); (void) set_term_encoding ("ASCII", ' '); use_bold = False; } if (strisprefix ("scoansi", envvar ("TERM")) || streq ("xterm-sco", envvar ("TERM")) || strisprefix ("cons", envvar ("TERM")) || streq ("att605-pc", envvar ("TERM")) || streq ("ti_ansi", envvar ("TERM")) || streq ("mgterm", envvar ("TERM")) ) { set_fkeymap ("o"); } if (strcontains (envvar ("TERM"), "koi")) { (void) set_term_encoding ("KOI8-R", ' '); } if (strisprefix ("cons", envvar ("TERM")) && strlen (envvar ("TERM")) >= 6) { if (strisprefix ("r", envvar ("TERM") + 6)) { (void) set_term_encoding ("KOI8-R", ' '); } else if (strisprefix ("l1", envvar ("TERM") + 6)) { (void) set_term_encoding ("ISO-8859-1", ' '); } else { (void) set_term_encoding ("CP437", 'p'); } } if (strisprefix ("mac", envvar ("TERM"))) { (void) set_term_encoding ("MacRoman", 'M'); } if (strisprefix ("nsterm", envvar ("TERM"))) { if (strcontains (envvar ("TERM"), "7")) { (void) set_term_encoding ("ASCII", ' '); } else if (streq ("+mac", envvar ("TERM") + 6) || streq ("-m", envvar ("TERM") + 6) || streq ("-m-s", envvar ("TERM") + 6) || streq ("", envvar ("TERM") + 6) || streq ("-c", envvar ("TERM") + 6) || streq ("-s", envvar ("TERM") + 6) || streq ("-c-s", envvar ("TERM") + 6) ) { (void) set_term_encoding ("MacRoman", 'M'); } } if (strisprefix ("9780", envvar ("TERM"))) { set_fkeymap ("siemens"); use_ascii_graphics = True; } if (strisprefix ("interix", getenv ("TERM"))) { set_fkeymap ("interix"); use_mouse = False; } /* setup terminal, auto-detect encoding, fine-tune modes */ /*if (! only_detect_text_encoding)*/ terminal_configure_init (); if (only_detect_terminal_encoding) { /* display character data version information (for +E? option) */ raw_mode (False); printf ("Terminal encoding %s, combining %d, bidi %d\n", get_term_encoding (), combining_screen, bidi_screen); printf ("- width data version %d - %s\n", width_data_version, term_encoding_version_name (width_data_version)); if (cjk_width_data_version) { printf ("- CJK width data version %d - %s\n", cjk_width_data_version, term_encoding_version_name (cjk_width_data_version)); } if (combining_screen) { printf ("- combining data version %d - %s\n", combining_data_version, term_encoding_version_name (combining_data_version)); } printf ("- non-BMP width data mode %X - plane_2_double %d plane_1_comb %d plane_14_comb %d\n", nonbmp_width_data, plane_2_double_width, plane_1_combining, plane_14_combining); if (xterm_version >= 0) { printf ("- xterm version %d\n", xterm_version); } if (rxvt_version >= 0) { printf ("- rxvt version %d\n", rxvt_version); } /* check #ifdef debug_screenmode for further information */ printf ("Menu border characters: ~ %s\n", use_ascii_graphics ? "ASCII" : use_vga_block_graphics ? "VGA" : use_pc_block_graphics ? "PC-compatible": use_vt100_block_graphics ? "VT100 block graphics": utf8_screen ? "Unicode": "VT100 block graphics" ); exit (0); } /* get/update ANSI screen mode configuration */ get_ansi_modes (); /* remember determined default text encoding for further files */ default_text_encoding = get_text_encoding (); /* read filter that defines which CJK encodings may be auto-detected */ detect_encodings = getenv ("MINEDDETECT"); /* if not defined, fallback to default set of auto-detected encodings */ if (! detect_encodings) { detect_encodings = "BGC JS KH LWP"; } /* get preconfigured smart quotes style */ preselect_quote_style = getenv ("MINEDQUOTES"); /* get selection of Han character information to be displayed */ env = getenv ("MINEDHANINFO"); if (env) { if (* env) { always_disp_Han = True; disp_Han_description = False; disp_Han_full = False; } else { always_disp_Han = False; } if (strchr (env, 'M') != NIL_PTR) { disp_Han_Mandarin = True; } if (strchr (env, 'C') != NIL_PTR) { disp_Han_Cantonese = True; } if (strchr (env, 'J') != NIL_PTR) { disp_Han_Japanese = True; } if (strchr (env, 'S') != NIL_PTR) { disp_Han_Sino_Japanese = True; } if (strchr (env, 'H') != NIL_PTR) { disp_Han_Hangul = True; } if (strchr (env, 'K') != NIL_PTR) { disp_Han_Korean = True; } if (strchr (env, 'V') != NIL_PTR) { disp_Han_Vietnamese = True; } if (strchr (env, 'P') != NIL_PTR) { disp_Han_HanyuPinlu = True; } if (strchr (env, 'T') != NIL_PTR) { disp_Han_Tang = True; } if (strchr (env, 'D') != NIL_PTR) { disp_Han_description = True; } if (strchr (env, 'F') != NIL_PTR) { disp_Han_description = True; disp_Han_full = True; } } /* generate names of paste files and of panic-file */ #ifdef unix temp_dir = getenv ("MINEDTMP"); if (temp_dir == NIL_PTR || temp_dir [0] == '\0' || access (temp_dir, W_OK | X_OK) < 0) { temp_dir = getenv ("TMPDIR"); } if (temp_dir == NIL_PTR || temp_dir [0] == '\0' || access (temp_dir, W_OK | X_OK) < 0) { temp_dir = getenv ("TMP"); } if (temp_dir == NIL_PTR || temp_dir [0] == '\0' || access (temp_dir, W_OK | X_OK) < 0) { temp_dir = getenv ("TEMP"); } if (temp_dir == NIL_PTR || temp_dir [0] == '\0' || access (temp_dir, W_OK | X_OK) < 0) { temp_dir = "/usr/tmp"; } if (access (temp_dir, W_OK | X_OK) < 0) { temp_dir = "/tmp"; } if (getenv ("MINEDUSER")) { build_string (yankie_file, "%s/mined.%s", temp_dir, getenv ("MINEDUSER")); build_string (panic_file, "%s/minedpanic.%s.%d", temp_dir, getenv ("MINEDUSER"), getpid ()); } else if (getenv ("USER")) { build_string (yankie_file, "%s/mined.%s", temp_dir, getenv ("USER")); build_string (panic_file, "%s/minedpanic.%s.%d", temp_dir, getenv ("USER"), getpid ()); } else { build_string (yankie_file, "%s/mined.%d", temp_dir, geteuid ()); build_string (panic_file, "%s/minedpanic.%d.%d", temp_dir, geteuid (), getpid ()); } #endif #ifdef vms if (getenv ("SYS$MINEDTMP")) { temp_dir = "SYS$MINEDTMP"; } else if (getenv ("SYS$SCRATCH")) { temp_dir = "SYS$SCRATCH"; } else { temp_dir = "SYS$LOGIN"; } if (getenv ("MINEDUSER")) { build_string (yankie_file, "%s:$MINED$%s", temp_dir, getenv ("MINEDUSER")); build_string (panic_file, "%s:$MINEDPANIC$%s.%d", temp_dir, getenv ("MINEDUSER"), getpid ()); } else if (getenv ("USER")) { build_string (yankie_file, "%s:$MINED$%s", temp_dir, getenv ("USER")); build_string (panic_file, "%s:$MINEDPANIC$%s.%d", temp_dir, getenv ("USER"), getpid ()); } else { build_string (yankie_file, "%s:$MINED$%d", temp_dir, geteuid ()); build_string (panic_file, "%s:$MINEDPANIC$%d.%d", temp_dir, geteuid (), getpid ()); } #endif #ifdef msdos temp_dir = getenv ("MINEDTMP"); if (temp_dir == NIL_PTR || temp_dir [0] == '\0') { temp_dir = getenv ("TEMP"); } if (temp_dir == NIL_PTR || temp_dir [0] == '\0') { temp_dir = getenv ("TMP"); } if (temp_dir == NIL_PTR || temp_dir [0] == '\0') { temp_dir = "\\"; } if (getenv ("MINEDUSER")) { build_string (yankie_file, "%s\\mined-%s", temp_dir, getenv ("MINEDUSER")); build_string (panic_file, "%s\\minedpan.%s", temp_dir, getenv ("MINEDUSER")); } else { build_string (yankie_file, "%s\\mined", temp_dir); build_string (panic_file, "%s\\mined-pa.nic", temp_dir); } #endif /* determine default permission setting for new files */ fprot0 = ~ umask (0) & 0666; /* ----------------------------------------------------------------------- */ /* prepare editing buffer */ clearscreen (); header = tail = alloc_header (); /* Make header of list */ if (header == NIL_LINE) { panic ("Cannot allocate memory", NIL_PTR); } header->text = NIL_PTR; header->next = tail->prev = header; header->syntax_marker = syntax_none; /* load the file (if any) */ if (fnami == 0) { load_file (NIL_PTR, False); } else { /* This should be applied to all file names, or better, not at all: if (length_of (argv [fnami]) > maxLINE_LEN) { argv [fnami] [maxLINE_LEN] = '\0'; } */ load_wild_file (argv [fnami], False); } trace_encoding ("load"); if (only_detect_text_encoding) { raw_mode (False); if (fnami >= fnami_max || fnami == 0) { printf ("%s\n", get_text_encoding ()); } else { printf ("%s: %s\n", fnamv [fnami], get_text_encoding ()); viewonly = True; while (fnami < fnami_max) { raw_mode (True); nextfile (True); raw_mode (False); printf ("%s: %s\n", fnamv [fnami], get_text_encoding ()); } } exit (0); } loading = True; /* keep loading flag True until entering main loop */ if (initlini != 0) { (void) scan_int (argv [initlini] + 1, & initlinenum); if (initlinenum > 0) { if (initlinenum <= 0 || (initline = proceed (header->next, initlinenum - 1)) == tail) { error2 ("Invalid line number: ", dec_out ((long) initlinenum)); } else { move_to (x, find_y_w_o_RD (initline)); fstatus ("Read", -1L, -1L); } } } if (inisearch != NIL_PTR) { search_for (inisearch, FORWARD, True); fstatus ("Read", -1L, -1L); } if (writing_pipe) { file_name [0] = '\0'; /* don't let user believe he's editing a file */ fstatus ("Editing for standard output", -1L, -1L); } RD (); flush (); catch_signals ((signalfunc) catch_interrupt); loading = False; trace_encoding ("main"); /* main loop of the editor */ for (;;) { /* display status line contents unless there is a message */ if (! stat_visible) { if (always_disp_fstat) { FSTAT (); } else if (always_disp_code) { display_the_code (); } else if (always_disp_Han && ! disp_Han_full) { display_Han (cur_text, False); } else if (always_disp_help) { display_FHELP (); } } if (always_disp_Han && disp_Han_full) { display_Han (cur_text, False); } /* refresh display items (top line, scrollbar, cursor position) */ if (MENU && top_line_scrolled) { displaymenuline (); flags_changed = False; cursor_somewhere = True; } if (MENU && flags_changed) { displayflags (); cursor_somewhere = True; } if (disp_scrollbar) { if (display_scrollbar (update_scrollbar_lazy)) { cursor_somewhere = True; } } if (cursor_somewhere) { set_cursor_xy (); } flush (); /* Flush output (if any) */ #ifdef adjust_to_actual_termsize input: #endif inputchar = readcharacter_mapped (); #ifdef adjust_to_actual_termsize if (command (inputchar) == ANSIseq) { ANSIseq (); goto input; } #endif if (always_disp_Han) { clean_menus (); } if (stat_visible) { clear_status (); } if (quit == False) { /* Call the function for the typed key */ invoke_key_function (inputchar); if (hop_flag > 0) { hop_flag --; flags_changed = True; } if (buffer_open_flag > 0) { buffer_open_flag --; #ifdef debug_ring_buffer if (buffer_open_flag == 0) { flags_changed = True; } #endif } } if (quit) { if (hop_flag > 0) { flags_changed = True; } CANCEL (); quit = False; } } /* NOTREACHED */ } /*======================================================================*\ |* End *| \*======================================================================*/