/*======================================================================*\ |* Editor mined *| |* file handling functions *| \*======================================================================*/ #include "mined.h" #include "textfile.h" #include "termprop.h" /* utf8_screen */ #include #include /*======================================================================*\ |* Data section *| \*======================================================================*/ #define mark_file "@mined.mar" #define new_mark_file "@mined.$$$" static int open_linum; /* line # to re-position to */ static int open_col; /* line column to re-position to */ static int open_pos; /* character index to re-position to */ int fnami; /* Parameter index of current file name */ int fnami_min, fnami_max; char * * fnamv; /* Copy of argv, points to program params */ FLAG overwriteOK = False; /* Set if current file is OK for overwrite */ char * default_text_encoding = ""; static FLAG save_viewonly; static FLAG save_restricted; static char save_file_name [maxLINE_LEN]; static int save_cur_pos; static int save_cur_line; FLAG viewing_help = False; /* options */ static FLAG multiexit = True; /* Should exit command go to next file? */ FLAG init_viewonly = False; /* Set with option v */ char * preselect_quote_style = NIL_PTR; #ifdef msdos_with_auto_crlf char RET_opt = 'r'; #else char RET_opt = ' '; /* recognise/convert line ends: handle CR */ #endif /*======================================================================*\ |* File loading performance debugging *| \*======================================================================*/ #define dont_debug_timing #ifdef debug_timing #include static long gettime () { struct timeval now; gettimeofday (& now, 0); return ((long) now.tv_sec) * 1000000 + now.tv_usec; } #define mark_time(timer) timer -= gettime () #define elapsed_time(timer) timer += gettime () #define elapsed_mark_time(timer1, timer2) {long t = gettime (); timer1 += t; timer2 -= t;} #else #define mark_time(timer) #define elapsed_time(timer) #define elapsed_mark_time(timer1, timer2) #endif /*======================================================================*\ |* UTF-8 character statistics and quote style detection *| \*======================================================================*/ /** determine if current position (if quote mark) is opening */ static FLAG isopeningquote (s, beg) char * s; char * beg; { unsigned int prevchar = precedingchar (s, beg); /* for now, follow simplified approach; don't consider quotes after quotes, or CJK embedded quotes */ switch (prevchar) { case '(': case '\n': case '\t': case ' ': case '[': case '{': return True; } return False; } /** language-specific quotation mark counters */ static unsigned long count_plain = 0; static unsigned long count_English = 0; static unsigned long count_German = 0; static unsigned long count_French = 0; static unsigned long count_inwards = 0; static unsigned long count_Dutch = 0; static unsigned long count_Swedish_q = 0; static unsigned long count_Swedish_g = 0; static unsigned long count_Greek = 0; static unsigned long count_Chinese = 0; static unsigned long count_Japanese = 0; static void reset_quote_statistics () { count_plain = 0; count_English = 0; count_German = 0; count_French = 0; count_inwards = 0; count_Dutch = 0; count_Swedish_q = 0; count_Swedish_g = 0; count_Greek = 0; count_Chinese = 0; count_Japanese = 0; } static unsigned long count_quotes; static void check_quote_style (c, s) unsigned long c; char * s; { /*printf ("%4d %s\n", c, s);*/ if (c > count_quotes) { count_quotes = c; set_quote_style (s); } } static void determine_quote_style () { count_quotes = 0; check_quote_style (count_plain, "\"\""); check_quote_style (count_English, "“”"); check_quote_style (count_inwards, "»«"); check_quote_style (count_German, "„“"); check_quote_style (count_French, "«» ‹›"); check_quote_style (count_Dutch, "„”"); check_quote_style (count_Swedish_q, "””"); check_quote_style (count_Swedish_g, "»»"); check_quote_style (count_Greek, "«» ‟”"); check_quote_style (count_Chinese, "《》"); check_quote_style (count_Japanese, "『』"); } /* * utf8_count () returns the number of UTF-8 characters in the string (like char_count) and also detects quotation marks and updates their statistics. */ static int utf8_count (string) char * string; { char * start = string; int count = 0; unsigned long unichar; int utflen; if (string != NIL_PTR) { while (* string != '\0') { /* Detect quotation marks. The UTF-8 codes of all quotation marks are either C2AB or C2BB or start with either E280 or E380. This may help for efficient detection during file loading. */ if ((((character) * string) <= 0x27 && (* string == '\'' || * string == '"') ) || ((* string & 0xDE) == 0xC2 && (((character) * string) == 0xC2 || ((character) * (string + 1)) == 0x80) ) ) { utf8_info (string, & utflen, & unichar); switch ((unsigned int) unichar) { case (character) '"': case (character) '\'': count_plain ++; break; case 0x201C: /* “ LEFT DOUBLE QUOTATION MARK; DOUBLE TURNED COMMA QUOTATION MARK */ case 0x2018: /* ‘ LEFT SINGLE QUOTATION MARK; SINGLE TURNED COMMA QUOTATION MARK */ /* left English, Spanish, Turkish */ /* right German, Danish, Polish, Russian, Romanian, Slovak, Slovenian, Czech, Hungarian */ if (isopeningquote (string, start)) { count_English ++; } else { count_German ++; } break; case 0x201D: /* ” RIGHT DOUBLE QUOTATION MARK; DOUBLE COMMA QUOTATION MARK */ count_Greek ++; case 0x2019: /* ’ RIGHT SINGLE QUOTATION MARK; SINGLE COMMA QUOTATION MARK */ /* right English, Spanish, Turkish */ /* right Dutch, Hungarian */ /* left/right Swedish, Finnish */ /* ” right nested traditional Greek */ count_Swedish_q ++; if (! isopeningquote (string, start)) { count_English ++; count_Dutch ++; } break; case 0x201E: /* „ DOUBLE LOW-9 QUOTATION MARK; LOW DOUBLE COMMA QUOTATION MARK */ case 0x201A: /* ‚ SINGLE LOW-9 QUOTATION MARK; LOW SINGLE COMMA QUOTATION MARK */ /* left German, Danish, Polish, Russian, Romanian, Slovak, Sloven, Czech, Hungarian */ /* left Dutch, Hungarian */ if (isopeningquote (string, start)) { count_German ++; count_Dutch ++; } break; case 0x201F: /* ‟ DOUBLE HIGH-REVERSED-9 QUOTATION MARK; DOUBLE REVERSED COMMA QUOTATION MARK */ count_Greek ++; case 0x201B: /* ‛ SINGLE HIGH-REVERSED-9 QUOTATION MARK; SINGLE REVERSED COMMA QUOTATION MARK */ /* ‟ left nested traditional Greek */ break; case 0x00AB: /* « LEFT-POINTING DOUBLE ANGLE QUOTATION MARK; LEFT POINTING GUILLEMET */ case 0x2039: /* ‹ SINGLE LEFT-POINTING ANGLE QUOTATION MARK; LEFT POINTING SINGLE GUILLEMET */ /* left French, Italian, Norwegian, Portuguese, Russian, Slovenian, Turkish */ /* right German, Polish, Slovak, Czech, Serbian, Croatian */ /* left Greek */ if (isopeningquote (string, start)) { count_French ++; count_Greek ++; } else { count_German ++; count_inwards ++; } break; case 0x00BB: /* » RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK; RIGHT POINTING GUILLEMET */ case 0x203A: /* › SINGLE RIGHT-POINTING ANGLE QUOTATION MARK; RIGHT POINTING SINGLE GUILLEMET */ /* right French, Italian, Norwegian, Portuguese, Russian, Slovenian, Turkish */ /* left German, Polish, Slovak, Czech, Serbian, Croatian */ /* left/right Swedish, Finnish */ /* right Greek */ count_Swedish_g ++; if (isopeningquote (string, start)) { count_German ++; count_inwards ++; } else { count_French ++; count_Greek ++; } break; case 0x300A: /* 《 LEFT DOUBLE ANGLE BRACKET; OPENING DOUBLE ANGLE BRACKET */ case 0x3008: /* 〈 LEFT ANGLE BRACKET; OPENING ANGLE BRACKET */ /* left Chinese? */ /* 〈 left Chinese?? */ if (isopeningquote (string, start)) { count_Chinese ++; } break; case 0x300B: /* 》 RIGHT DOUBLE ANGLE BRACKET; CLOSING DOUBLE ANGLE BRACKET */ case 0x3009: /* 〉 RIGHT ANGLE BRACKET; CLOSING ANGLE BRACKET */ /* right Chinese? */ /* 〉 right Chinese?? */ if (! isopeningquote (string, start)) { count_Chinese ++; } break; case 0x300C: /* 「 LEFT CORNER BRACKET; OPENING CORNER BRACKET */ case 0x300E: /* 『 LEFT WHITE CORNER BRACKET; OPENING WHITE CORNER BRACKET */ /* left Japanese */ /* 『 left Japanese? */ if (isopeningquote (string, start)) { count_Japanese ++; } break; case 0x300D: /* 」 RIGHT CORNER BRACKET; CLOSING CORNER BRACKET */ case 0x300F: /* 』 RIGHT WHITE CORNER BRACKET; CLOSING WHITE CORNER BRACKET */ /* right Japanese */ /* 』 right Japanese? */ if (! isopeningquote (string, start)) { count_Japanese ++; } break; } } /* Advance and count */ advance_utf8 (& string); count ++; } } return count; } /*======================================================================*\ |* File I/O buffer *| \*======================================================================*/ #define filebuflen (10 * 1024) static char filebuf [filebuflen + 1]; static unsigned int filebuf_count = 0; void clear_filebuf () { filebuf_count = 0; } /*======================================================================*\ |* File position handling *| \*======================================================================*/ /* * get_open_pos and save_open_pos look up and save the current file position in @mined.mar For save_open_pos, line_number must be up-to-date */ static void get_open_pos (fn) char * fn; { int mark_fd = open (mark_file, O_RDONLY | O_BINARY, 0); if (mark_fd >= 0) { FLAG modif = modified; FLAG get_quote_type = quote_type == 0; int dumlen; int fnlen = strlen (fn); reset_get_line (False); open_linum = 0; open_col = 0; open_pos = 0; while ((get_line (mark_fd, text_buffer, & dumlen, False)) != ERRORS) { if (strncmp (fn, text_buffer, fnlen) == 0) { char * spoi = text_buffer + fnlen; if (* spoi == ' ') { int v4, v5, v6 = -1; lines_per_page = 0; spoi = scan_int (spoi, & open_linum); spoi = scan_int (spoi, & open_col); if (open_col < 0) { /* indicates new character index semantics */ open_pos = - open_col; } spoi = scan_int (spoi, & lines_per_page); spoi = scan_int (spoi, & v4); if (v4 >= 0) { JUSlevel = 1; spoi = scan_int (spoi, & v5); spoi = scan_int (spoi, & v6); if (v6 > 0) { first_left_margin = v4; next_left_margin = v5; right_margin = v6; } } else { JUSlevel = 0; } if (get_quote_type) { int vq = -1; spoi = scan_int (spoi, & vq); if (vq >= 0) { /* legacy int entries */ if (vq == 1) { set_quote_style ("“” ‘’"); } else if (vq == 2) { set_quote_style ("„“ ‚‘"); } else if (vq == 3) { set_quote_style ("«» ‹›"); } else if (vq == 4) { set_quote_style ("»« ›‹"); } else if (vq == 5) { set_quote_style ("„” ‚’"); } else if (vq == 6) { set_quote_style ("”” ’’"); } else if (vq == 7) { set_quote_style ("»» ››"); } else if (vq == 8) { set_quote_style ("『』 「」"); } else { set_quote_type (0); } } else { char * npoi; /* string entries */ while (* spoi == ' ') { spoi ++; } npoi = strchr (spoi, '\n'); if (npoi != NIL_PTR) { * npoi = '\0'; } set_quote_style (spoi); } } } } } (void) close (mark_fd); clear_filebuf (); /* prevent affecting the modified flag when loading the line number file */ modified = modif; } } /** Write file position and other information to mined marker file. Return False if writing to the file fails. */ static FLAG write_open_pos (fd, fn) int fd; char * fn; { int cur_pos = get_cur_pos (); char marktext [maxLINE_LEN]; if (JUSlevel > 0) { build_string (marktext, "%s %d %d %d %d %d %d %s\n", fn, line_number, - cur_pos, lines_per_page, first_left_margin, next_left_margin, right_margin, quote_mark (quote_type, 0)); } else { build_string (marktext, "%s %d %d %d -3 %s\n", fn, line_number, - cur_pos, lines_per_page, quote_mark (quote_type, 0)); } if (write (fd, marktext, strlen (marktext)) <= 0) { return False; } else { return True; } } #ifdef pc #define append_minedmar #endif #ifdef append_minedmar /** Append file position and other information to mined marker file. Return False if saving to the file fails. */ static FLAG append_open_pos (fn, force) char * fn; int force; { int mark_fd; if (force > 0) { mark_fd = open (mark_file, O_WRONLY | O_APPEND | O_CREAT, fprot0); } else { mark_fd = open (mark_file, O_WRONLY | O_APPEND, fprot0); } if (mark_fd >= 0) { FLAG ret = write_open_pos (mark_fd, fn); if (close (mark_fd) < 0) { ret = False; } return ret; } else { return False; } } #else #ifdef update_in_place #define file_pos(fd) lseek (fd, 0, SEEK_CUR) /** Update file position and other information in mined marker file, doing the modification in place, using two opened file handles to the same file; - This does not work on djgpp and is not used thus. Housekeeping: clean up older entries for same file. Return False if saving to the file fails. */ static FLAG update_open_pos (fn, force) char * fn; int force; { int mark_in; int mark_out; FLAG ret = True; mark_in = open (mark_file, O_RDONLY); if (mark_in < 0 && ! force) { return False; } mark_out = open (mark_file, O_WRONLY | O_CREAT, fprot0); if (mark_out < 0) { return False; } if (mark_in >= 0) { /* scan mark file for old entries for same file and skip them; copy other entries to output stream (to same file) */ int dumlen; int fnlen = strlen (fn); while ((get_line (mark_in, text_buffer, & dumlen, False)) != ERRORS) { if (strncmp (fn, text_buffer, fnlen) == 0 && text_buffer [fnlen] == ' ') { /* skip entry for this filename */ } else { if (write (mark_out, text_buffer, strlen (text_buffer)) <= 0) { /* ignore error */ } } } (void) close (mark_in); clear_filebuf (); } ret = write_open_pos (mark_out, fn); ftruncate (mark_out, file_pos (mark_out)); if (close (mark_out) < 0) { ret = False; } return ret; } #else /** Update file position and other information in mined marker file, using two files and finally moving the new one to the old one. Housekeeping: clean up older entries for same file. Return False if saving to the file fails. */ static FLAG update_open_pos (fn, force) char * fn; int force; { int mark_in; int mark_out; FLAG ret = True; mark_in = open (mark_file, O_RDONLY); if (mark_in < 0 && ! force) { return False; } mark_out = open (new_mark_file, O_WRONLY | O_TRUNC | O_BINARY | O_CREAT, fprot0); if (mark_out < 0) { return False; } if (mark_in >= 0) { /* scan mark file for old entries for same file and skip them; copy other entries to output file */ int dumlen; int fnlen = strlen (fn); while ((get_line (mark_in, text_buffer, & dumlen, False)) != ERRORS) { if (strncmp (fn, text_buffer, fnlen) == 0 && text_buffer [fnlen] == ' ') { /* skip entry for this filename */ } else { if (write (mark_out, text_buffer, strlen (text_buffer)) <= 0) { /* ignore error */ } } } (void) close (mark_in); clear_filebuf (); } ret = write_open_pos (mark_out, fn); if (close (mark_out) < 0) { ret = False; } else { if (rename (new_mark_file, mark_file) < 0) { /* This yields ENOMEM with djgpp */ ret = False; } } return ret; } #endif #endif /** Save file position and other information in mined marker file. Return False if saving to the file fails. */ static FLAG save_open_pos (fn, force) char * fn; int force; { if (fn [0] != '\0') { #ifdef append_minedmar return append_open_pos (fn, force); #else return update_open_pos (fn, force); #endif } else { return True; } } /*======================================================================*\ |* Auxiliary functions *| \*======================================================================*/ static int strcaseeq (s1, s2) char * s1; char * s2; { char c1, c2; do { if (! * s1 && ! * s2) { return True; } c1 = * s1; if (c1 >= 'a' && c1 <= 'z') { c1 = c1 - 'a' + 'A'; } c2 = * s2; if (c2 >= 'a' && c2 <= 'z') { c2 = c2 - 'a' + 'A'; } if (c1 != c2) { return False; } s1 ++; s2 ++; } while (True); } /* Set flags depending on file type. */ static void set_file_type_flags () { char * suffix = strrchr (file_name, '.'); if (suffix != NIL_PTR) { suffix ++; } else { suffix = ""; } if ( strcaseeq (suffix, "html") || strcaseeq (suffix, "htm") || strcaseeq (suffix, "xhtml") || strcaseeq (suffix, "shtml") || strcaseeq (suffix, "sgml") || strcaseeq (suffix, "xml") || strcaseeq (suffix, "jsp") || strcaseeq (suffix, "wsdl") || strcaseeq (suffix, "dtd") || strcaseeq (suffix, "xsl") || strcaseeq (suffix, "xslt") ) { dim_HTML = True; } else { dim_HTML = False; } } /* * Initialize is called when a another file is edited. It free's the allocated * space and sets modified back to False and fixes the header/tail pointer. */ static void initialize () { register LINE * line; register LINE * next_line; /* Delete the whole list */ for (line = header->next; line != tail; line = next_line) { next_line = line->next; free_space (line->text); free_header (line); } /* header and tail should point to itself */ line->next = line->prev = line; x = y = 0; reading_pipe = modified = False; } char * basename (s) char * s; { char * b = strrchr (s, '/'); if (b == NIL_PTR) { return s; } else { b ++; return b; } } /*======================================================================*\ |* File operations *| \*======================================================================*/ /* * Get_line reads one line from filedescriptor fd. If EOF is reached on fd, * get_line () returns ERRORS, else it returns the length of the string. */ static char * get_l_err_u1; static char * get_l_err1; static character last_byte = '\0'; static long count_good_utf; /* count good UTF-8 sequences */ static long count_bad_utf; /* count bad UTF-8 sequences */ static long count_utf_bytes; /* count UTF-8 sequence bytes */ static long count_good_iso; /* count good ISO-8859 bytes */ static long count_good_cp1252; /* count good CP1252 (Windows Western) bytes */ static long count_good_cp850; /* count good CP850 (DOS) bytes */ static long count_good_mac; /* count good MacRoman bytes */ static long count_good_viscii; /* count good VISCII bytes */ static long count_good_tcvn; /* count good TCVN bytes */ static long count_1read_op; /* count 1st read operation by get_line */ static long count_lineend_LF; /* count Unix lines */ static long count_lineend_CRLF; /* count MSDOS lines */ static long count_lineend_CR; /* count Mac lines */ static FLAG BOM; /* BOM found at beginning of file? */ static FLAG consider_utf16; /* consider UTF-16 when reading file? */ /* CJK character encoding auto-detection */ static character last_cjkbyte = '\0'; static character last2_cjkbyte = '\0'; static long count_good_cjk; /* count good CJK codes */ static long count_weak_cjk; /* count weak (unsure) CJK codes */ static long count_bad_cjk; /* count bad CJK codes */ static long count_big5; /* count Big5 codes */ static long count_gb; /* count GB (GB2312, GBK, GB18030) codes */ static int detect_gb18030 = 0; /* observe GB18030 byte state */ static long count_uhc; /* count UHC (KS C 5601/KS X 1001) codes */ static long count_jp; /* count JIS (EUC-JP) codes */ static long count_sjis; /* count Shift-JIS codes */ static long count_sjis1; /* count Shift-JIS single-byte codes */ static long count_johab; /* count Johab codes */ static long count_cns; /* count CNS codes */ #define dont_debug_auto_detect #define dont_debug_read void reset_get_line (from_text_file) FLAG from_text_file; /* consider UTF-16 ? */ { get_l_err1 = NIL_PTR; get_l_err_u1 = NIL_PTR; count_good_utf = 0; count_bad_utf = 0; count_utf_bytes = 0; count_good_cjk = 0; count_weak_cjk = 0; count_bad_cjk = 0; last_byte = '\0'; last_cjkbyte = '\0'; last2_cjkbyte = '\0'; count_good_iso = 0; count_good_viscii = 0; count_good_tcvn = 0; count_good_cp1252 = 0; count_good_cp850 = 0; count_good_mac = 0; count_big5 = 0; count_gb = 0; count_uhc = 0; count_jp = 0; count_sjis = 0; count_sjis1 = 0; count_johab = 0; count_cns = 0; count_lineend_LF = 0; count_lineend_CRLF = 0; count_lineend_CR = 0; count_1read_op = 0; reset_quote_statistics (); BOM = False; consider_utf16 = from_text_file; utf16_file = False; /* make sure set_text_encoding (default_text_encoding) is called after this ! */ } static void show_get_l_error (get_l_err) char * get_l_err; { if (get_l_err != NIL_PTR) { ring_bell (); error2 (get_l_err, " -- type a blank"); while (readcharacter () != ' ' && quit == False) { ring_bell (); flush (); } } } void show_get_l_errors () { show_get_l_error (get_l_err1); show_get_l_error (get_l_err_u1); clear_status (); } static unsigned int surrogate = 0; /* Transform UTF-16 input into UTF-8. */ static int UTF16_transform (UTF8buf, maxbufl, next_byte_poi, fini_byte) char * UTF8buf; int maxbufl; character * * next_byte_poi; character * fini_byte; { register char * ptr = UTF8buf; int read_chars = 0; unsigned long unichar; while (read_chars + 4 < maxbufl && * next_byte_poi < fini_byte) { unichar = * * next_byte_poi; (* next_byte_poi) ++; if (* next_byte_poi < fini_byte) { if (utf16_little_endian) { unichar |= (* * next_byte_poi) << 8; } else { unichar = (unichar << 8) | (* * next_byte_poi); } (* next_byte_poi) ++; } else if (utf16_little_endian == False) { unichar = 0; } if ((unichar & 0xFC00) == 0xD800) { /* high surrogates */ surrogate = (unichar - 0xD7C0) << 10; } else if ((unichar & 0xFC00) == 0xDC00) { /* low surrogates */ unichar = surrogate | (unichar & 0x03FF); surrogate = 0; * ptr ++ = 0xF0 | (unichar >> 18); * ptr ++ = 0x80 | ((unichar >> 12) & 0x3F); * ptr ++ = 0x80 | ((unichar >> 6) & 0x3F); * ptr ++ = 0x80 | (unichar & 0x3F); read_chars += 4; } else if (unichar < 0x80) { * ptr ++ = unichar; read_chars ++; } else if (unichar < 0x800) { * ptr ++ = 0xC0 | (unichar >> 6); * ptr ++ = 0x80 | (unichar & 0x3F); read_chars += 2; } else { * ptr ++ = 0xE0 | (unichar >> 12); * ptr ++ = 0x80 | ((unichar >> 6) & 0x3F); * ptr ++ = 0x80 | (unichar & 0x3F); read_chars += 3; } } return read_chars; } #ifdef debug_read #define trace_read(params) printf params #else #define trace_read(params) #endif static char * last = NIL_PTR; static char * current = NIL_PTR; static char * UTF16buf = NIL_PTR; static char * fini_byte = NIL_PTR; static char * next_byte = NIL_PTR; static long read_bytes; static long read_chars; static void clear_get_line () { last = NIL_PTR; current = NIL_PTR; } static FLAG alloc_UTF16buf () { if (UTF16buf == NIL_PTR) { UTF16buf = alloc (filebuflen); if (UTF16buf == NIL_PTR) { get_l_err_u1 = "Cannot allocate memory for UTF-16 buffer"; viewonly = True; modified = False; return ERRORS; } } return FINE; } /** Tables supporting auto-detection of some 8-bit character encodings; for each character >= 0x80 they indicate whether the character is a letter (cl), a valid character (cv), or invalid (nc). */ #define cl 2 /* count weight of letter */ #define cc 1 /* count weight of non-letter */ #define nc -3 /* count weight of invalid character */ static char good_iso [0x80] = { /*80*/ nc, nc, nc, nc, nc, nc, nc, nc, nc, nc, nc, nc, nc, nc, nc, nc, /*90*/ nc, nc, nc, nc, nc, nc, nc, nc, nc, nc, nc, nc, nc, nc, nc, nc, /*A0*/ cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, /*B0*/ cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, /*C0*/ cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, /*D0*/ cl, cl, cl, cl, cl, cl, cl, cc, cl, cl, cl, cl, cl, cl, cl, cl, /*E0*/ cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, /*F0*/ cl, cl, cl, cl, cl, cl, cl, cc, cl, cl, cl, cl, cl, cl, cl, cl, }; static char good_cp1252 [0x80] = { /*80*/ cc, nc, cc, cc, cc, cc, cc, cc, cc, cc, cl, cc, cl, nc, cl, nc, /*90*/ nc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cl, cc, cl, nc, cl, cl, /*A0*/ cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, /*B0*/ cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, /*C0*/ cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, /*D0*/ cl, cl, cl, cl, cl, cl, cl, cc, cl, cl, cl, cl, cl, cl, cl, cl, /*E0*/ cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, /*F0*/ cl, cl, cl, cl, cl, cl, cl, cc, cl, cl, cl, cl, cl, cl, cl, cl, }; static char good_cp850 [0x80] = { /*80*/ cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, /*90*/ cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cc, cl, cc, cc, /*A0*/ cl, cl, cl, cl, cl, cl, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, /*B0*/ cc, cc, cc, cc, cc, cl, cl, cl, cc, cc, cc, cc, cc, cc, cc, cc, /*C0*/ cc, cc, cc, cc, cc, cc, cl, cl, cc, cc, cc, cc, cc, cc, cc, cc, /*D0*/ cl, cl, cl, cl, cl, cl, cl, cl, cl, cc, cc, cc, cc, cc, cl, cc, /*E0*/ cl, cl, cl, cl, cl, cl, cc, cl, cl, cl, cl, cl, cl, cl, cc, cc, /*F0*/ cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, }; static char good_mac [0x80] = { /*80*/ cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, /*90*/ cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, /*A0*/ cc, cc, cc, cc, cc, cc, cc, cl, cc, cc, cc, cc, cc, cc, cl, cl, /*B0*/ cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cl, cl, /*C0*/ cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, cl, cl, cl, cl, cl, /*D0*/ cc, cc, cc, cc, cc, cc, cc, cc, cl, cl, cc, cc, cc, cc, cc, cc, /*E0*/ cc, cc, cc, cc, cc, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, cl, /*F0*/ nc, cl, cl, cl, cl, cl, cc, cc, cc, cc, cc, cc, cc, cc, cc, cc, }; int get_line (fd, buffer, len, do_auto_detect) int fd; register char buffer [MAX_CHARS]; int * len; FLAG do_auto_detect; { register char * cur_pos = current; char * begin = buffer; char * fini = (char *) (buffer + MAX_CHARS - 2) /* leave space for '\n\0' */; register FLAG ignore1char; int ret = 0; char char_copied; int Ulineend_state = 0; character curbyte; #define dont_debug_overlong #ifdef debug_overlong fini = (char *) (buffer + 20) /* debug overlong line input */; #endif /* read one line */ do { /* read one char */ do { /* read one effective (not to be filtered out) char */ ignore1char = False; if (cur_pos == last) { if (utf16_file && consider_utf16) { if (next_byte >= fini_byte) { do { interrupted = False; if (alloc_UTF16buf () == ERRORS) { return ERRORS; } read_bytes = read (fd, UTF16buf, filebuflen); trace_read (("read utf16 (%d, %X, %d) %d\n", fd, UTF16buf, filebuflen, read_bytes)); } while (interrupted || (read_bytes == -1 && geterrno () == EINTR)); if (read_bytes <= 0) { read_chars = read_bytes; break; } next_byte = UTF16buf; fini_byte = & UTF16buf [read_bytes]; } read_chars = UTF16_transform (filebuf, filebuflen, & next_byte, fini_byte); if (count_1read_op == 0) { if (strncmp (filebuf, "", 3) == 0) { /* already transformed UTF-8 BOM */ BOM = True; } count_1read_op = 1; } } else { do { interrupted = False; read_chars = read (fd, filebuf, filebuflen); trace_read (("read (%d, %X, %d) %d\n", fd, filebuf, filebuflen, read_chars)); } while (interrupted || (read_chars == -1 && geterrno () == EINTR)); if (read_chars <= 0) { break; } } last = & filebuf [read_chars]; cur_pos = filebuf; if (count_1read_op == 0 && consider_utf16) { if (! (utf8_text && utf16_file) && strncmp (filebuf, "", 3) == 0) { /* UTF-8 BOM */ BOM = True; } else if (strncmp (filebuf, "\376\377", 2) == 0 && do_auto_detect) { /* big endian UTF-16 BOM */ (void) set_text_encoding (":16", ' ', "BOM 16"); BOM = True; /* strip converted UTF-8 BOM from text */ cur_pos += 3; } else if (strncmp (filebuf, "\377\376", 2) == 0 && do_auto_detect) { /* little-endian UTF-16 BOM */ (void) set_text_encoding (":61", ' ', "BOM 61"); BOM = True; /* strip converted UTF-8 BOM from text */ cur_pos += 3; } else if (utf8_text && utf16_file) { /* UTF-16 pre-selection */ } else if (do_auto_detect) { /* UTF-16 auto-detection */ char * sp = filebuf; int even_0 = 0; int odd_0 = 0; FLAG odd = False; while (sp < last) { if (* sp ++ == '\0') { if (odd) { odd_0 ++; } else { even_0 ++; } } odd = ! odd; } if (even_0 > read_chars / 133 && even_0 > 2 * (odd_0 + 1)) { /* big endian UTF-16 */ (void) set_text_encoding (":16", ' ', "detect 16"); } else if (odd_0 > read_chars / 133 && odd_0 > 2 * (even_0 + 1)) { /* little-endian UTF-16 */ (void) set_text_encoding (":61", ' ', "detect 61"); } } if (utf16_file) { /* do_auto_detect = False; */ /* move UTF-16 input to UTF-16 buffer */ if (alloc_UTF16buf () == ERRORS) { return ERRORS; } memcpy (UTF16buf, filebuf, (unsigned int) read_chars); read_bytes = read_chars; next_byte = UTF16buf; fini_byte = & UTF16buf [read_bytes]; /* transform to UTF-8 */ read_chars = UTF16_transform (filebuf, filebuflen, & next_byte, fini_byte); last = & filebuf [read_chars]; } count_1read_op = 1; } } curbyte = * cur_pos; /* begin character encoding auto-detection */ /* UTF-8 auto-detection */ #define dont_debug_utf_detect #ifdef debug_utf_detect printf ("count_utf_bytes %d cur %02X\n", count_utf_bytes, curbyte); #endif if (count_utf_bytes == 0) { if ((curbyte & 0xC0) == 0x80) { count_bad_utf ++; } else { count_utf_bytes = UTF8_len (curbyte) - 1; } } else if ((curbyte & 0xC0) == 0x80) { count_utf_bytes --; if (count_utf_bytes == 0) { count_good_utf ++; } } else { count_utf_bytes = 0; count_bad_utf ++; } /* VISCII and ISO-8859 auto-detection */ if (curbyte >= 0x80) { if (do_auto_detect) { count_good_viscii += cl; count_good_tcvn += cl; count_good_iso += good_iso [curbyte - 0x80]; count_good_cp1252 += good_cp1252 [curbyte - 0x80]; count_good_cp850 += good_cp850 [curbyte - 0x80]; count_good_mac += good_mac [curbyte - 0x80]; #ifdef debug_auto_detect printf ("%02X -> iso %d viscii %d\n", curbyte, count_good_iso, count_good_viscii); #endif } else { /* Defending ISO-8859 vs. CJK auto-detection */ count_good_iso += good_iso [curbyte - 0x80]; } } else if (do_auto_detect) { switch (curbyte) { case '': case '': case '': case '': count_good_viscii += 2 * cl; count_good_tcvn += 2 * cl; break; case '': case '': count_good_viscii += 2 * cl; count_good_tcvn += nc; break; case '': case '': case '': case '': case '': case '': case '': case '': count_good_viscii += nc; count_good_tcvn += 2 * cl; break; case '\000': case '': case '': case '': case ' ': case ' ': case '': case '': case '': case '': case 0x1A: case '': case '': case '': case '': count_good_viscii += nc; count_good_tcvn += nc; break; } } /* CJK/Han encoding auto-detection */ /* maintain GB18030 detection state */ if (detect_gb18030 != 0) { detect_gb18030 --; } /* perform detection on bytes after non-ASCII bytes */ if (last_cjkbyte >= 0x80) { if (curbyte >= 0x80) { count_good_cjk += cl; } else if (curbyte < 0x30) { count_bad_cjk += cl; } else if (curbyte <= 0x39) { if (detect_gb18030 == 1) { count_good_cjk += cl; } } else { count_weak_cjk ++; } /* detect specific CJK encoding */ if (do_auto_detect && ! utf16_file) { /* CJK character set ranges Big5 Big5-HKSCS 87-FE 40-7E, A1-FE GB GBK 81-FE 40-7E, 80-FE GB18030 81-FE 30-39 81-FE 30-39 UHC UHC 81-FE 41-5A, 61-7A, 81-FE JIS EUC-JP 8E A1-DF A1-FE A1-FE 8F A1-FE A1-FE JIS Shift-JIS A1-DF 81-9F, E0-EF 40-7E, 80-FC CNS EUC-TW A1-FE A1-FE 8E A1-A7 A1-FE A1-FE */ if (last_cjkbyte >= 0x81 && last_cjkbyte <= 0xFE) { /* Big5 Big5-HKSCS 87-FE 40-7E, A1-FE */ if (last_cjkbyte >= 0x87 /* && last_cjkbyte <= 0xFE */ && ((curbyte >= 0x40 && curbyte <= 0x7E) || (curbyte >= 0xA1 && curbyte <= 0xFE))) { count_big5 ++; } /* GB GBK 81-FE 40-7E, 80-FE GB18030 81-FE 30-39 81-FE 30-39 UHC UHC 81-FE 41-5A, 61-7A, 81-FE */ /* if (last_cjkbyte >= 0x81 && last_cjkbyte <= 0xFE) { */ if ((curbyte >= 0x40 && curbyte <= 0x7E) || (curbyte >= 0x80 && curbyte <= 0xFE)) { count_gb ++; if ((curbyte >= 0x41 && curbyte <= 0x5A) || (curbyte >= 0x61 && curbyte <= 0x7A) || (curbyte >= 0x81 /* && curbyte <= 0xFE */)) { count_uhc ++; } } else if (curbyte >= 0x30 && curbyte <= 0x39) { if (detect_gb18030 == 1) { count_gb += 5; } else { detect_gb18030 = 3; } } /* } */ /* JIS EUC-JP A1-FE A1-FE 8F A1-FE A1-FE 8E A1-DF */ if ((last_cjkbyte >= 0xA1 && last_cjkbyte <= 0xFE) && curbyte >= 0xA1 && curbyte <= 0xFE) { if (last2_cjkbyte == 0x8F) { count_jp += 3; } else { count_jp ++; } } if (last_cjkbyte == 0x8E && curbyte >= 0xA1 && curbyte <= 0xFE) { count_jp += 3; } /* JIS Shift-JIS A1-DF 81-9F, E0-EF 40-7E, 80-FC */ if (last_cjkbyte >= 0xA1 && last_cjkbyte <= 0xDF) { if (curbyte >= 0xA1 && curbyte <= 0xDF) { /* two consecutive single-byte SJIS characters */ count_sjis += 1; count_sjis1 ++; } } else { if (curbyte >= 0x40 && curbyte <= 0xFC && curbyte != 0x7F) { count_sjis ++; } } /* Johab Johab 84-DE, E0-F9 31-7E, 81-FE */ if (((last_cjkbyte >= 0x84 && last_cjkbyte <= 0xDE) || (last_cjkbyte >= 0xE0 && last_cjkbyte <= 0xF9)) && ((curbyte >= 0x31 && curbyte <= 0x7E) || (curbyte >= 0x81 && curbyte <= 0xFE))) { count_johab ++; } } /* if (last_cjkbyte >= 0x81 && last_cjkbyte <= 0xFE) */ else { if (curbyte >= 0x40 && curbyte <= 0xFC && curbyte != 0x7F) { count_sjis ++; } } } /* if do_auto_detect */ } /* shift CJK byte state */ last2_cjkbyte = last_cjkbyte; last_cjkbyte = curbyte; /* end character encoding auto-detection */ #ifdef msdos_with_auto_crlf if (curbyte == '\n' && last_byte != '\r') { set_modified (); } #endif /* line-end transformation */ if (RET_opt == 'R' && curbyte == '\n' && last_byte == '\r') { /* handling DOS line-ends in Mac mode */ last_byte = curbyte; cur_pos ++; ignore1char = True; set_modified (); } else { last_byte = curbyte; } if (* cur_pos == '\r' ) { if (RET_opt == 'R') { /* convert Mac line-ends */ * cur_pos = '\n'; set_modified (); } else if (RET_opt == 'r') { /* convert DOS line-ends */ cur_pos ++; if (* cur_pos == '\n') { ignore1char = True; #ifndef msdos set_modified (); #endif } else { cur_pos --; /* leave '^M' within line */ } } } /* NUL character handling */ if (* cur_pos == '\0') { * cur_pos = '\n'; ret = NUL_LINE; } } while (ignore1char); /* detect if no more lines available */ if (cur_pos == last) { break; } /* handle if line buffer full */ * buffer = * cur_pos; if (buffer > fini - 6 && * cur_pos != '\n') { /* try not to split within a UTF-8 sequence */ if (buffer == fini || /* last chance to split! */ (cjk_text && ! do_auto_detect ? charbegin (begin, buffer) == buffer : (* cur_pos & 0xC0) != 0x80 )) { get_l_err1 = "Line(s) too long - split"; * buffer ++ = '\n'; ret = SPLIT_LINE; break; } } /* copy char from input buffer into line buffer */ char_copied = * buffer ++ = * cur_pos ++; if (utf8_lineends) { if (Ulineend_state == 0 && char_copied == '') { Ulineend_state = 1; } else if (Ulineend_state > 0) { if (Ulineend_state == 1 && char_copied == '') { Ulineend_state = 2; } else if (Ulineend_state == 2 && char_copied == '') { Ulineend_state = 3; /* LS 
 detected */ char_copied = '\n'; } else if (Ulineend_state == 2 && char_copied == '') { Ulineend_state = 3; /* PS 
 detected */ char_copied = '\n'; } else { Ulineend_state = 0; } } } } while (char_copied != '\n' && (char_copied != '\r' || RET_opt != 'M') ); current = cur_pos; if (read_chars <= 0) { if (buffer == begin) { return ERRORS; } if (* (buffer - 1) != '\n' && (* (buffer - 1) != '\r' || RET_opt != 'M') ) { if (loading) { /* Add '\n' to last line of file, for internal handling */ * buffer ++ = '\n'; } * buffer = '\0'; ret = NO_LINE; /* consider incomplete UTF-8 sequence for auto-detection */ if (count_utf_bytes > 0) { count_bad_utf ++; } } } * buffer = '\0'; * len = (int) (buffer - begin); return ret; } /* * extract_lineend_type extracts the type of line end from the string, * removes it from the string and returns it */ lineend_type extract_lineend_type (text, length) char * text; int length; { register char * end = text + length - 1; if (* end == '\n') { end --; if (length > 1 && * end == '\r') { * end = * (end + 1); * (end + 1) = '\0'; count_lineend_CRLF ++; /* count MSDOS lines */ return lineend_CRLF; } else { count_lineend_LF ++; /* count Unix lines */ return lineend_LF; } } else if (* end == '\r') { * end = '\n'; count_lineend_CR ++; /* count Mac lines */ return lineend_CR; } else if (utf8_lineends && length >= 3 && strncmp (end - 2, "
", 3) == 0) { end --; end --; * end ++ = '\n'; * end = '\0'; return lineend_LS; /* Unicode line separator 2028 */ } else if (utf8_lineends && length >= 3 && strncmp (end - 2, "
", 3) == 0) { end --; end --; * end ++ = '\n'; * end = '\0'; return lineend_PS; /* Unicode paragraph separator 2029 */ } else { return lineend_NONE; } } static void update_file_name (newname, update) char * newname; FLAG update; { char * b = basename (newname); copy_string (file_name, newname); /* Save file name */ if (hide_password_mode == 1) { FLAG old_hide_password = hide_password; hide_password = * b == '.'; if (update && hide_password != old_hide_password) { RDwin (); } } } /* * Load_file loads the file with given name or the input pipe into memory. * If the file couldn't be opened, just an empty line is installed. * Buffer pointers are initialized. * The current position is set to the last saved position. * * Load_file_position loads and positions as follows: if open_linum > 0, the given position is used if open_linum == 0, the last saved position is used if open_linum < 0, no position is set (stays at beginning) */ static void load_file_position (file, with_display, to_open_linum, to_open_pos) char * file; FLAG with_display; int to_open_linum; int to_open_pos; { register LINE * line = header; int len; int ret; long nr_of_bytes = 0L; long nr_of_chars = 0L; long nr_of_utfchars = 0L; long nr_of_cjkchars = 0L; int fd = -1; /* Filedescriptor for file */ FLAG locked = False; /* lockf performed ? */ lineend_type new_return_type; FLAG save_utf8_text; /* save state of utf8_text */ FLAG save_cjk_text; /* save state of cjk_text */ FLAG save_mapped_text; /* save state of mapped_text */ FLAG do_auto_detect = auto_detect; char prev_encoding_tag; FLAG empty = False; char * prev_text_encoding = get_text_encoding (); total_lines = 0; /* Zero lines to start with */ open_linum = to_open_linum; open_pos = to_open_pos; open_col = -1; clearscreen (); flush (); overwriteOK = False; writable = True; file_is_dir = False; set_quote_type (0); if (preselect_quote_style != NIL_PTR) { set_quote_style (preselect_quote_style); } if (file == NIL_PTR) { if (reading_pipe == False) { status_msg ("No file"); empty = True; } else { fd = 0; file = "standard input"; } file_name [0] = '\0'; } else { update_file_name (file, False); status_line ("Accessing ", file); if (access (file, 0 /* F_OK */) < 0) { /* Cannot access file */ status_line ("New file ", file); overwriteOK = False; empty = True; } else if ((fd = open (file, O_RDWR | O_BINARY, 0)) >= 0) { overwriteOK = True; writable = True; /* if (lockf (fd, F_LOCK, 0) < 0) { status_line ("No lock for ", file); } else { locked = True; } */ if (open_linum == 0) { get_open_pos (file_name); } } else if ((fd = open (file, O_RDONLY | O_BINARY, 0)) >= 0) { overwriteOK = True; writable = False; if (open_linum == 0) { get_open_pos (file_name); } } else { error2 ("Cannot open: " /*, file */, serror ()); empty = True; } } set_file_type_flags (); /* initiate reading file */ loading = True; /* Loading file, so set flag */ reset_get_line (True); /* must be called after get_open_pos ! */ /* restore determined default text encoding */ /* must be set after reset_get_line ! */ (void) set_text_encoding (default_text_encoding, ' ', "load: def"); if (fd >= 0) { /* Determine file protection in case text is saved to other file */ struct stat fstat_buf; if (fstat (fd, & fstat_buf) == 0) { fprot1 = fstat_buf.st_mode; #ifdef S_ISDIR if (S_ISDIR (fstat_buf.st_mode)) { file_is_dir = True; } #else #ifdef S_IFDIR if (fstat_buf.st_mode & S_IFDIR) { file_is_dir = True; } #endif #endif } else { fprot1 = fprot0; } status_line ("Reading ", file); save_utf8_text = utf8_text; save_cjk_text = cjk_text; save_mapped_text = mapped_text; if (do_auto_detect) { utf8_text = False; cjk_text = False; } #ifdef debug_timing long time_get = 0; long time_check = 0; long time_line = 0; long time_count = 0; #endif mark_time (time_get); while (line != NIL_LINE && (ret = get_line (fd, text_buffer, & len, do_auto_detect)) != ERRORS) { elapsed_mark_time (time_get, time_check); if (ret == NO_LINE || ret == SPLIT_LINE) { new_return_type = lineend_NONE; } else if (ret == NUL_LINE) { new_return_type = lineend_NUL; } else { new_return_type = extract_lineend_type (text_buffer, len); } elapsed_mark_time (time_check, time_line); line = line_insert (line, text_buffer, len, new_return_type); elapsed_time (time_line); /* if editing buffer cannot be filled (out of memory), assure that file is not accidentally overwritten with truncated buffer version */ if (line == NIL_LINE) { * file_name = '\0'; } mark_time (time_count); nr_of_bytes += (long) len; if (do_auto_detect) { nr_of_chars += char_count (text_buffer); nr_of_utfchars += utf8_count (text_buffer); cjk_text = True; nr_of_cjkchars += char_count (text_buffer); cjk_text = False; } else if (utf8_text) { nr_of_chars += utf8_count (text_buffer); } else { nr_of_chars += char_count (text_buffer); } if (new_return_type == lineend_NONE) { nr_of_chars --; nr_of_utfchars --; nr_of_cjkchars --; nr_of_bytes --; } elapsed_mark_time (time_count, time_get); } elapsed_time (time_get); utf8_text = save_utf8_text; cjk_text = save_cjk_text; mapped_text = save_mapped_text; #ifdef debug_timing printf ("get %ld, check %ld, line_insert %ld, count %ld\n", time_get, time_check, time_line, time_count); #endif if (total_lines == 0 && line != NIL_LINE) { /* The file was empty */ line = line_insert (line, "\n", 1, lineend_NONE); } clear_filebuf (); cur_line = header->next; line_number = 0; if (locked == False) { (void) close (fd); } if (count_lineend_CRLF > count_lineend_LF) { default_lineend = lineend_CRLF; } } else { /* Determine file protection in case text is saved to file */ fprot1 = fprot0; /* Just install an empty line */ line = line_insert (line, "\n", 1, default_lineend); } /* auto-detection stuff */ #define dont_debug_auto_detect #ifdef debug_auto_detect printf ("good CJK %d, weak CJK %d, bad CJK %d, good UTF %d, bad UTF %d\n", count_good_cjk, count_weak_cjk, count_bad_cjk, count_good_utf, count_bad_utf); printf ("iso %d, cp1252 %d, cp850 %d, mac %d, viscii %d, tcvn %d\n", count_good_iso, count_good_cp1252, count_good_cp850, count_good_mac, count_good_viscii, count_good_tcvn); printf ("big5 %d, gb %d, jp %d, sjis %d, uhc %d, johab %d\n", count_big5, count_gb, count_jp, count_sjis, count_uhc, count_johab); #endif /* consider line-end types */ count_good_cp1252 += 5 * count_lineend_CRLF; count_good_cp850 += 5 * count_lineend_CRLF; count_good_mac += 5 * count_lineend_CR; count_good_iso += count_lineend_LF; count_sjis += 12 * count_lineend_CRLF; /* heuristic adjustments */ /* count_big5 *= 2; count_uhc *= 2; count_jp *= 3; count_sjis *= 1.5; count_good_viscii *= 0.9; */ count_sjis += count_sjis1 / 2; #ifdef debug_auto_detect printf ("-> iso %d, cp1252 %d, cp850 %d, mac %d, viscii %d, tcvn %d\n", count_good_iso, count_good_cp1252, count_good_cp850, count_good_mac, count_good_viscii, count_good_tcvn); printf ("-> big5 %d, gb %d, jp %d, sjis %d, uhc %d, johab %d\n", count_big5, count_gb, count_jp, count_sjis, count_uhc, count_johab); #endif /* remember text encoding before auto-detection (for CJK char counting) */ prev_encoding_tag = text_encoding_tag; /* filter out encodings that shall not be auto-detected */ if (detect_encodings != NIL_PTR && * detect_encodings != '\0') { if (strchr (detect_encodings, 'G') == NIL_PTR) { count_gb = 0; } if (strchr (detect_encodings, 'B') == NIL_PTR) { count_big5 = 0; } if (strchr (detect_encodings, 'K') == NIL_PTR) { count_uhc = 0; } if (strchr (detect_encodings, 'J') == NIL_PTR) { count_jp = 0; } if (strchr (detect_encodings, 'S') == NIL_PTR) { count_sjis = 0; count_sjis1 = 0; } if (strchr (detect_encodings, 'C') == NIL_PTR) { count_cns = 0; } if (strchr (detect_encodings, 'H') == NIL_PTR) { count_johab = 0; } if (strpbrk (detect_encodings, "V8") == NIL_PTR) { count_good_viscii = 0; } if (strpbrk (detect_encodings, "N8") == NIL_PTR) { count_good_tcvn = 0; } if (strpbrk (detect_encodings, "L8") == NIL_PTR) { count_good_iso = 0; } if (strpbrk (detect_encodings, "W8") == NIL_PTR) { count_good_cp1252 = 0; } if (strpbrk (detect_encodings, "P8") == NIL_PTR) { count_good_cp850 = 0; } if (strpbrk (detect_encodings, "M8") == NIL_PTR) { count_good_mac = 0; } } /* Unicode encoding detection */ if (! empty && do_auto_detect && ! utf16_file) { if (BOM || #ifdef utf_preference_in_utf_term utf8_screen ? count_good_utf >= count_bad_utf : count_good_utf > count_bad_utf #else count_good_utf >= count_bad_utf #endif ) { nr_of_chars = nr_of_utfchars; (void) set_text_encoding (NIL_PTR, 'U', "load: U"); } else { if (strisprefix ("UTF", get_text_encoding ())) { (void) set_text_encoding (NIL_PTR, 'L', "load: L"); } else { /* allow fallback to default encoding set on function entry */ } if (count_good_cjk > count_bad_cjk * 2 + count_weak_cjk / 5 /* count_bad_cjk * 2 + count_weak_cjk * 5 / nr_of_cjkchars */ /* && count_good_cjk > count_good_iso */ && (/* at least one CJK encoding is enabled for auto-detection */ count_gb > 0 || count_big5 > 0 || count_uhc > 0 || count_jp > 0 || count_sjis > 0 ) ) { /* setting cjk_text = True; */ (void) set_text_encoding (":??", ' ', "load: CJK"); nr_of_chars = nr_of_cjkchars; } else if ( /* count_good_viscii / 2 > count_good_cjk + count_weak_cjk && */ /* count_good_viscii / 3 > count_good_cjk + count_weak_cjk - count_bad_cjk && */ count_good_viscii > count_good_iso && count_good_viscii > count_good_cp1252 && count_good_viscii > count_good_cp850 && count_good_viscii > count_good_mac ) { (void) set_text_encoding ("VISCII", 'V', "detect"); } else if (count_good_cp1252 > count_good_iso && count_good_cp1252 > count_good_cp850 && count_good_cp1252 > count_good_mac) { (void) set_text_encoding ("CP1252", 'W', "detect"); } else if (count_good_cp850 > count_good_iso && count_good_cp850 > count_good_mac) { (void) set_text_encoding ("CP850", 'P', "detect"); } else if (count_good_mac > count_good_iso) { (void) set_text_encoding ("MacRoman", 'M', "detect"); } else { /* leave default/fallback encoding */ } } } /* detect CJK encoding based on count_big5 count_gb count_uhc count_jp */ if (! empty && cjk_text && do_auto_detect && ! (utf8_text && utf16_file)) { if (count_gb > count_big5 && count_gb > count_uhc && count_gb > count_jp && count_gb > count_sjis) { (void) set_text_encoding ("GB", 'G', "detect CJK"); } else if (count_uhc > count_big5 && count_uhc > count_jp && count_uhc > count_sjis) { (void) set_text_encoding ("UHC", 'K', "detect CJK"); } else if (count_big5 > count_uhc && count_big5 > count_jp && count_big5 > count_sjis) { (void) set_text_encoding ("Big5", 'B', "detect CJK"); } else if (count_jp > count_sjis) { (void) set_text_encoding ("EUC-JP", 'J', "detect CJK"); } else if (count_sjis > 0) { (void) set_text_encoding ("Shift-JIS", 'S', "detect CJK"); } } /* detect style of quotation marks */ if (quote_type == 0) { determine_quote_style (); } /* if text encoding changed, reset previous one, then toggle */ if (! streq (prev_text_encoding, get_text_encoding ())) { char * new_text_encoding = get_text_encoding (); (void) set_text_encoding (prev_text_encoding, ' ', "load: prev"); change_encoding (new_text_encoding); /* -> ... set_text_encoding (new_text_encoding, ' ', "men: change_encoding"); */ } /* end auto-detection stuff */ if (fd >= 0) { if (line != NIL_LINE) { show_get_l_errors (); fstatus ("Read", nr_of_bytes, nr_of_chars); } } if (line == NIL_LINE) { sleep (2) /* give time to read allocation error msg */; viewonly = True; modified = False; } reset (header->next, 0); /* Initialize pointers */ move_to (0, 0); loading = False; /* Stop loading, reset flag */ if (open_linum > 0) { LINE * open_line = proceed (header->next, open_linum - 1); char * cpoi; int cur_column = 0; move_to (0, find_y_w_o_RD (open_line)); /* re-position within line */ cpoi = cur_line->text; if (open_col >= 0) { char * prev_cpoi = cpoi; while (* cpoi != '\n' && cur_column <= open_col) { prev_cpoi = cpoi; advance_char_scr (& cpoi, & cur_column, cur_line->text); } if (cur_column <= open_col) { prev_cpoi = cpoi; } move_address (prev_cpoi, y); } else { while (* cpoi != '\n' && open_pos > 0) { advance_char (& cpoi); open_pos --; } move_address (cpoi, y); } if (with_display) { display (0, top_line, last_y, 0); } if (! cjk_text || prev_encoding_tag == text_encoding_tag) { fstatus ("Read", nr_of_bytes, nr_of_chars); } else { fstatus ("Read", nr_of_bytes, -1L); } Markn (0); } else if (with_display) { display (0, top_line, last_y, 0); move_to (0, 0); } #ifdef unix RD_window_title (); #endif } void load_file (file, with_display) char * file; FLAG with_display; { load_file_position (file, with_display, 0, 0); } #ifdef msdos # ifdef __TURBOC__ #include "turbodir.h" # else #include # endif struct ffblk ffblock; FLAG ffblockvalid = False; char wildfile [maxLINE_LEN]; char drive [9], dir [maxLINE_LEN], name [13], ext [5]; #endif void load_wild_file (file, with_display) char * file; FLAG with_display; { #ifdef msdos char dumdrive [9]; char dumdir [maxLINE_LEN]; #endif #ifdef msdos ffblockvalid = False; #endif if (file == NIL_PTR) { load_file (file, with_display); } else { #ifdef msdos /* (void) fnsplit (fnamv [fnami], drive, dir, name, ext); if (findfirst (fnamv [fnami], & ffblock, 0) == 0) { */ (void) fnsplit (file, drive, dir, name, ext); if (findfirst (file, & ffblock, 0) == 0) { ffblockvalid = True; (void) fnsplit (ffblock.ff_name, dumdrive, dumdir, name, ext); fnmerge (wildfile, drive, dir, name, ext); load_file (wildfile, with_display); } else #endif load_file (file, with_display); } } /* * Ask user if named file should be overwritten. */ FLAG checkoverwrite (name) char * name; { character c; status_line ("Checking ", name); if (access (name, 0 /* F_OK */) < 0) { /* Cannot access file */ return True; /* thus no danger of unwanted damage */ } status_line (name [0] ? name : empty_buffer_name, ": OK to overwrite? (y/n)"); c = promptyn (); clear_status (); if (c == 'y') { return True; } else if (c == 'n') { return False; } else { /* quit = False; abort character has been given */ return False; } } /* * Attach new file name to buffer */ void NN () { char file [maxLINE_LEN]; /* Buffer for new file name */ if (restricted) { restrictederr (); return; } if (get_filename ("Enter new file name:", file) == ERRORS) { return; } overwriteOK = False; writable = True; update_file_name (file, True); #ifdef unix if (modified) { RD_window_title (); } #endif set_modified (); /* cf. CHDI command */ clear_status (); } /*======================================================================*\ |* File I/O basics *| \*======================================================================*/ /* * Flush the I/O buffer on filedescriptor fd. */ int flush_filebuf (fd) int fd; { if (filebuf_count <= 0) { /* There is nothing to flush */ return FINE; } else { char * writepoi = filebuf; int written = 0; int none_count = 0; /* int less_count = 0; */ while (filebuf_count > 0) { written = write (fd, writepoi, filebuf_count); if (written == -1) { if (geterrno () == EINTR && winchg) { /* try again */ } else { bad_write (fd); return ERRORS; } } else if (written == 0) { none_count ++; if (none_count > 20) { bad_write (fd); return ERRORS; } } else { filebuf_count -= written; writepoi += written; } } } filebuf_count = 0; return FINE; } /* * writechar does a buffered output to file. */ int writechar (fd, c) int fd; char c; { filebuf [filebuf_count ++] = c; if (filebuf_count == filebuflen) { return flush_filebuf (fd); } return FINE; } /* * writeucs writes a UCS Unicode code in UTF-16 * Return # words written or ERRORS. */ static int writeucs (fd, c) int fd; unsigned long c; { int err = FINE; if (c > (unsigned long) 0x10FFFF) { return writeucs (fd, 0xFFFD); } else if (c > (unsigned long) 0xFFFF) { err = 2; c -= 0x10000; err |= writeucs (fd, 0xD800 | (c >> 10)); err |= writeucs (fd, 0xDC00 | (c & 0x03FF)); } else { err = 1; if (utf16_little_endian) { err |= writechar (fd, c & 0xFF); err |= writechar (fd, c >> 8); } else { err |= writechar (fd, c >> 8); err |= writechar (fd, c & 0xFF); } } return err; } /* * writelechar writes a line-end character to file Only called by write_lineend. */ static int writelechar (fd, c, handle_utf16) int fd; char c; FLAG handle_utf16; { if (utf8_text && utf16_file && handle_utf16) { return writeucs (fd, (character) c); } else { return writechar (fd, c); } } /* * write_lineend writes a line-end in the respective form to file Called by write_line, yank_text. */ int write_lineend (fd, return_type, handle_utf16) register int fd; lineend_type return_type; FLAG handle_utf16; { switch (return_type) { case lineend_NONE: return 0; case lineend_NUL: if (writelechar (fd, '\0', handle_utf16) == ERRORS) { return ERRORS; } return 1; case lineend_LF: if (writelechar (fd, '\n', handle_utf16) == ERRORS) { return ERRORS; } return 1; case lineend_CRLF: if (writelechar (fd, '\r', handle_utf16) == ERRORS) { return ERRORS; } if (writelechar (fd, '\n', handle_utf16) == ERRORS) { return ERRORS; } return 2; case lineend_CR: if (writelechar (fd, '\r', handle_utf16) == ERRORS) { return ERRORS; } return 1; case lineend_LS: /* Unicode line separator 2028: 
 */ if (utf8_text && utf16_file && handle_utf16) { if (writeucs (fd, 0x2028) == ERRORS) { return ERRORS; } return 1; } else { if (writelechar (fd, '\342', handle_utf16) == ERRORS) { return ERRORS; } if (writelechar (fd, '\200', handle_utf16) == ERRORS) { return ERRORS; } if (writelechar (fd, '\250', handle_utf16) == ERRORS) { return ERRORS; } return 3; } case lineend_PS: /* Unicode paragraph separator 2029: 
 */ if (utf8_text && utf16_file && handle_utf16) { if (writeucs (fd, 0x2029) == ERRORS) { return ERRORS; } return 1; } else { if (writelechar (fd, '\342', handle_utf16) == ERRORS) { return ERRORS; } if (writelechar (fd, '\200', handle_utf16) == ERRORS) { return ERRORS; } if (writelechar (fd, '\251', handle_utf16) == ERRORS) { return ERRORS; } return 3; } default: if (writelechar (fd, '\n', handle_utf16) == ERRORS) { return ERRORS; } return 1; } } /* * Writestring writes the given string on the given filedescriptor. * (buffered via writechar via misused screen buffer!) * Return # bytes written or ERRORS. Only called by write_file, so handle_utf16 is always True. */ static int write_line (fd, text, return_type, handle_utf16) int fd; char * text; lineend_type return_type; FLAG handle_utf16; { int len; int ccount = 0; while (* text != '\0') { if (* text == '\n') { /* handle different line ends */ len = write_lineend (fd, return_type, handle_utf16); if (len == ERRORS) { return ERRORS; } text ++; ccount += len; } else { if (utf8_text && utf16_file && handle_utf16) { unsigned long unichar; int utflen; utf8_info (text, & utflen, & unichar); if (UTF8_len (* text) == utflen) { len = writeucs (fd, unichar); } else { len = writeucs (fd, 0xFFFD); } if (len == ERRORS) { return ERRORS; } advance_utf8 (& text); ccount += len; } else { if (writechar (fd, * text) == ERRORS) { return ERRORS; } text ++; ccount ++; } } } if (utf8_text && utf16_file && handle_utf16) { return ccount * 2; } else { return ccount; } } /* Call graph for writing functions: panic --\------> panicwrite --------------------------\ > QUED ----------\ \ ESC q --/ > ask_save --\ > write_file ESC e ---> EDIT --> edit_file -/ \ / ESC v ---> VIEW -/ \ / ESC w -------------------> WT -------------> write_text ESC W -------------------> WTU -----------/ ESC z -------------------> SUSP ---------/ ESC ESC -> EXED ---------> EXFILE ------/ \--------> EXMINED ----/ ESC t -------------------> Stag ------/ */ long write_count; /* number of bytes written */ long chars_written; /* number of chars written */ /* * Write text in memory to file. */ static void write_file (fd) int fd; { register LINE * line; int ret = FINE; static FLAG handle_utf16 = True; write_count = 0L; chars_written = 0L; clear_filebuf (); if (utf8_text && utf16_file && handle_utf16) { /* prepend BOM if there was one */ if (BOM && strncmp (header->next->text, "", 3) != 0) { ret = write_line (fd, "", lineend_NONE, handle_utf16); if (ret == ERRORS) { error2 ("Write failed (File incomplete): ", serror ()); write_count = -1L; chars_written = -1L; } else { ret = FINE; write_count = 2; chars_written = 1; } } } if (ret == FINE) { for (line = header->next; line != tail; line = line->next) { ret = write_line (fd, line->text, line->return_type, handle_utf16); if (ret == ERRORS) { error2 ("Write failed (File incomplete): ", serror ()); write_count = -1L; chars_written = -1L; break; } write_count += (long) ret; chars_written += (long) char_count (line->text); if (line->return_type == lineend_NONE) { chars_written --; } } } if (write_count > 0L && flush_filebuf (fd) == ERRORS) { if (ret != ERRORS) { error2 ("Write failed (File incomplete): ", serror ()); ret = ERRORS; } write_count = -1L; chars_written = -1L; } if (close (fd) == -1) { if (ret != ERRORS) { error2 ("Write failed (File incomplete): ", serror ()); } write_count = -1L; chars_written = -1L; } } int panicwrite () { int fd; /* fd = creat (panic_file, bufprot); */ fd = open (panic_file, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, bufprot); write_file (fd); if (write_count == -1L) { return ERRORS; } else { return FINE; } } /** Write text to its associated file. */ int write_text (forceflag) FLAG forceflag; { char file [maxLINE_LEN]; /* Buffer for new file name */ int fd; /* Filedescriptor of file */ int ret; if (writing_pipe) { fd = STD_OUT; status_line ("Writing ", "to standard output"); writing_pipe = False; /* no further write to same stream possible */ } else { if (forceflag == False && modified == False) { if (file_name [0] != '\0') { fstatus ("(Write not necessary)", -1L, -1L); (void) save_open_pos (file_name, hop_flag); } else { status_msg ("Write not necessary."); } return FINE; } /* Check if file_name is valid and if file can be written */ if (file_name [0] == '\0' || writable == False) { overwriteOK = False; if ((ret = get_filename ("Saving edited text - enter file name:", file)) != FINE) { return ret; } update_file_name (file, True); #ifdef unix RD_window_title (); #endif } if (overwriteOK == False) { if (checkoverwrite (file_name)) { overwriteOK = True; } else { if (quit == False) { writable = False; } return ERRORS; } } status_line ("Opening ", file_name); /* fd = creat (file_name, fprot1 | ((fprot1 >> 2) & xprot)); */ fd = open (file_name, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, fprot1 | ((fprot1 >> 2) & xprot)); if (fd < 0) { /* Empty file */ error2 ("Cannot create or write: " /*, file_name */, serror ()); writable = False; return ERRORS; } else { writable = True; } status_line ("Writing ", file_name); } write_file (fd); if (write_count == -1L) { return ERRORS; } modified = False; #ifdef unix RD_window_title (); #endif reading_pipe = False; /* File name is now assigned */ /* Display how many chars (and lines) were written */ fstatus ("Wrote", write_count, chars_written); /* fstatus ("Wrote", -1L); */ (void) save_open_pos (file_name, hop_flag); return FINE; } /*======================================================================*\ |* File commands *| \*======================================================================*/ FLAG save_text_load_file (fn) char * fn; { if (modified) { if (write_text (False) == ERRORS) { return ERRORS; } } /* Free old linked list, initialize global variables and load new file */ initialize (); clearscreen (); load_file (fn, True); return FINE; } void SAVEAS () { if (restricted) { restrictederr (); return; } NN (); WT (); } void WT () { (void) write_text (False); } void WTU () { if (restricted && viewonly) { restrictederr (); return; } (void) write_text (True); } /* * Save current file pos */ void SAVPOS () { if (file_name [0] != '\0') { fstatus ("Remembering file position", -1L, -1L); if (save_open_pos (file_name, 1) == False) { error2 ("Error when saving file position to ", mark_file); } } } /* * Ask the user if he wants to save the file or not. */ static int ask_save () { register character c; status_line (file_name [0] ? file_name : empty_buffer_name, " has been modified. Save? (y/n)"); c = promptyn (); clear_status (); if (c == 'y') { return write_text (False); } else if (c == 'n') { return FINE; } else { quit = False; /* abort character has been given */ return ERRORS; } } /* * Edit/view another file. If the current file has been modified, * ask whether the user wants to save it. * (We could allow to switch between edit and view mode without changing * the file, but we would have to consider carefully the relationship * between viewonly and modified.) */ static void edit_file (prompt, vomode) char * prompt; FLAG vomode; { char new_file [maxLINE_LEN]; /* Buffer to hold new file name */ if (modified && viewonly == False && ask_save () != FINE) { return; } /* Get new file name */ if (get_filename (prompt, new_file) == ERRORS) { return; } viewonly = vomode; /* Free old linked list, initialize global variables and load new file */ initialize (); clearscreen (); load_wild_file (new_file [0] == '\0' ? NIL_PTR : new_file, True); } #ifdef not_used static void edit_this_file (new_file, vomode) char * new_file; FLAG vomode; { if (modified && viewonly == False && ask_save () != FINE) { return; } viewonly = vomode; /* Free old linked list, initialize global variables and load new file */ initialize (); clearscreen (); load_wild_file (new_file [0] == '\0' ? NIL_PTR : new_file, True); } #endif void EDIT () { if (restricted) { restrictederr (); return; } edit_file ("Edit file:", False); } void VIEW () { if (restricted) { restrictederr (); return; } edit_file ("View file:", True); } void EDITmode () { if (restricted) { restrictederr (); return; } viewonly = False; FSTAT (); flags_changed = True; } void VIEWmode () { if (modified == False) { viewonly = True; FSTAT (); flags_changed = True; } else { error ("Cannot view only - already modified"); } } void toggle_VIEWmode () { if (viewonly) { EDITmode (); } else { VIEWmode (); } } void view_help (helpfile, item) char * helpfile; char * item; { char searchstring [maxLINE_LEN]; /* unless already viewing help, save edited text */ if (viewing_help == False) { if (modified) { if (write_text (False) != FINE) { return; } } /* save current position */ save_cur_line = line_number; save_cur_pos = get_cur_pos (); /* save editing mode and file name */ save_viewonly = viewonly; save_restricted = restricted; copy_string (save_file_name, file_name); /* set mode appropriate for viewing online help */ viewonly = True; restricted = True; viewing_help = True; /* load online help file */ initialize (); clearscreen (); load_file_position (helpfile, True, -1, 0); } /* position to selected help topic */ BFILE (); build_string (searchstring, "mined help topic '%s'", item); search_for (searchstring, FORWARD, True); } static void end_view_help () { viewonly = save_viewonly; restricted = save_restricted; viewing_help = False; initialize (); clearscreen (); load_file_position (save_file_name, True, save_cur_line, save_cur_pos); } static void quit_mined () { if (viewing_help) { end_view_help (); return; } delete_yank_files (); clear_status (); set_cursor (0, YMAX); putchar ('\n'); #ifdef unix clear_window_title (); #endif flush (); raw_mode (False); exit (0); } void edit_nth_file (n) int n; { int number; int index; if (modified && viewonly == False && ask_save () != FINE) { return; } if (n == -1) { status_msg ("Edit which file (enter number) or # to reload current file"); index = readcharacter (); if (quit) { return; } if (index == '#') { n = fnami; } else { index = get_number ("Edit which file (enter number) ...", index, & number); if (index == ERRORS) { return; } n = number - 1 + fnami_min; } } if (n < fnami_min) { n = fnami_min; } if (n > fnami_max) { n = fnami_max; } /* Now proceed to load nth file */ viewonly = init_viewonly; /* Free old linked list, initialize global variables and load new file */ initialize (); clearscreen (); fnami = n; if (fnami < fnami_min) { load_wild_file (NIL_PTR, True); } else { load_wild_file (fnamv [fnami], True); } } void nextfile (exitiflast) FLAG exitiflast; { #ifdef msdos char dumdrive [9]; char dumdir [maxLINE_LEN]; #endif if (hop_flag > 0) { edit_nth_file (fnami_max); } else { #ifdef msdos if (modified && viewonly == False && ask_save () != FINE) { return; } if (ffblockvalid && findnext (& ffblock) == 0) { /* Discard edit buffer, initialize and load new file */ initialize (); clearscreen (); (void) fnsplit (ffblock.ff_name, dumdrive, dumdir, name, ext); fnmerge (wildfile, drive, dir, name, ext); load_file (wildfile, True); return; } ffblockvalid = False; #endif if (fnami >= fnami_max || fnami == 0) { if (exitiflast) { quit_mined (); } else { error ("Already at last file"); } } else { edit_nth_file (fnami + 1); } } } void NXTFILE () { Pushmark (); nextfile (False); } void PRVFILE () { Pushmark (); if (hop_flag > 0) { edit_nth_file (fnami_min); } else if (fnami <= fnami_min) { #ifdef msdos error ("Already at first file name"); #else error ("Already at first file"); #endif return; } else { edit_nth_file (fnami - 1); } } void NTHFILE () { edit_nth_file (-1); } /*======================================================================*\ |* Tag search with file change *| \*======================================================================*/ static int get_tagline (idf, filename, search) char * idf; char * filename; char * search; { int tags_fd = open ("tags", O_RDONLY | O_BINARY, 0); FLAG modif = modified; unsigned int len = strlen (idf); int dumlen; char * poi; char * outpoi; char lastpat = '\0'; FLAG found; flush (); /* clear the shared screen/get_line buffer! */ reset_get_line (False); if (tags_fd >= 0) { found = False; while (found == False && (get_line (tags_fd, text_buffer, & dumlen, False)) != ERRORS) { if (strncmp (idf, text_buffer, len) == 0 && text_buffer [len] == '\t') { found = True; poi = text_buffer + len + 1; outpoi = filename; while (* poi != '\0' && * poi != '\t') { * outpoi ++ = * poi ++; } * outpoi = '\0'; outpoi = search; poi ++; if (* poi == '/') { poi ++; } while (* poi != '\0' && (* poi != '/' || lastpat == '\\')) { if (* poi == '[' || * poi == ']' || * poi == '*') { * outpoi ++ = '\\'; } lastpat = * poi ++; * outpoi ++ = lastpat; } * outpoi = '\0'; } } (void) close (tags_fd); clear_filebuf (); clear_get_line (); modified = modif; /* don't let the tags file affect the modified flag */ if (found == False) { error ("Identifier not found in tags file"); return ERRORS; } else { return FINE; } } else { error ("No tags file present; apply the ctags command to your source files"); return ERRORS; } } /* * Stag () opens file and moves to idf, using tags file */ void Stag () { char idf_buf [MAX_CHARS]; /* identifier to search for */ char new_file [maxLINE_LEN]; /* Buffer to hold new file name */ char search [MAX_CHARS]; /* search expression */ int lineno; if (hop_flag > 0) { if (get_string ("Enter identifier (to locate definition):", idf_buf, True, "") != FINE) { return; } } else { if (get_idf (idf_buf, cur_text, cur_line->text) == ERRORS) { return; } } if (get_tagline (idf_buf, new_file, search) == ERRORS) { return; } Pushmark (); if (! streq (new_file, file_name)) { if (save_text_load_file (new_file) == ERRORS) { return; } } if (* search >= '0' && * search <= '9') { (void) scan_int (search, & lineno); goline (lineno); } else { search_for (search, FORWARD, False); } } /*======================================================================*\ |* Checkin/out *| \*======================================================================*/ /* * Checkout (from version managing system). */ void checkout () { int save_cur_pos; int save_cur_line; char syscommand [maxLINE_LEN]; /* Buffer for full system command */ int sysres; if (modified) { if (write_text (False) != FINE) { return; } } /* save current position */ save_cur_line = line_number; save_cur_pos = get_cur_pos (); /* try to check out */ raw_mode (False); build_string (syscommand, "co %s", file_name); sysres = system (syscommand); sleep (1); raw_mode (True); RDwin (); if (sysres != 0) { error ("Checkout failed"); } /* reload file */ initialize (); clearscreen (); load_file_position (file_name, True, save_cur_line, save_cur_pos); } /* * Checkin (to version managing system). */ void checkin () { char syscommand [maxLINE_LEN]; /* Buffer for full system command */ int sysres; if (modified) { if (write_text (False) != FINE) { return; } } /* try to check in */ raw_mode (False); build_string (syscommand, "ci %s", file_name); sysres = system (syscommand); sleep (1); raw_mode (True); RDwin (); if (sysres != 0) { error ("Checkin failed"); } } /*======================================================================*\ |* Exiting *| \*======================================================================*/ /* * Leave editor. If the file has changed, ask if the user wants to save it. */ void QUED () { if (modified && viewonly == False && ask_save () != FINE) { return; } quit_mined (); } /* * Exit editing current file. If the file has changed, save it. * Edit next file if there is one. */ void EXFILE () { if (modified) { if (write_text (False) != FINE) { return; } } if (hop_flag == 0) { nextfile (True); } else { quit_mined (); } } /* * Exit editor. If the file has changed, save it. */ void EXMINED () { if (modified) { if (write_text (False) != FINE) { return; } } quit_mined (); } /* * Exit editing current file. Exit editor if multiexit flag set. */ void EXED () { if (multiexit) { EXFILE (); } else { EXMINED (); } } /*======================================================================*\ |* End *| \*======================================================================*/