aboutsummaryrefslogtreecommitdiff
path: root/editors/vi.c
diff options
context:
space:
mode:
Diffstat (limited to 'editors/vi.c')
-rw-r--r--editors/vi.c193
1 files changed, 192 insertions, 1 deletions
diff --git a/editors/vi.c b/editors/vi.c
index 34932f60c..e59083ddb 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -112,6 +112,19 @@
112//config: help 112//config: help
113//config: Enable the editor to set some (ai, ic, showmatch) options. 113//config: Enable the editor to set some (ai, ic, showmatch) options.
114//config: 114//config:
115//config:config FEATURE_VI_FILE_FORMAT
116//config: bool "Enable detection of file format"
117//config: default y
118//config: depends on VI && FEATURE_VI_SETOPTS && PLATFORM_MINGW32
119//config: help
120//config: Enable the editor to detect the format of files it reads
121//config: so they can be written out with the appropriate line
122//config: endings. Also allow files to be edited in binary mode.
123//config:
124//config: This enables the 'fileformat', 'fileformats' and 'binary'
125//config: options and the '-b' command line flag.
126//config:
127//config:
115//config:config FEATURE_VI_SET 128//config:config FEATURE_VI_SET
116//config: bool "Support :set" 129//config: bool "Support :set"
117//config: default y 130//config: default y
@@ -181,9 +194,12 @@
181//kbuild:lib-$(CONFIG_VI) += vi.o 194//kbuild:lib-$(CONFIG_VI) += vi.o
182 195
183//usage:#define vi_trivial_usage 196//usage:#define vi_trivial_usage
184//usage: IF_FEATURE_VI_COLON("[-c CMD] ")IF_FEATURE_VI_READONLY("[-R] ")"[-H] [FILE]..." 197//usage: IF_FEATURE_VI_FILE_FORMAT("[-b] ")IF_FEATURE_VI_COLON("[-c CMD] ")IF_FEATURE_VI_READONLY("[-R] ")"[-H] [FILE]..."
185//usage:#define vi_full_usage "\n\n" 198//usage:#define vi_full_usage "\n\n"
186//usage: "Edit FILE\n" 199//usage: "Edit FILE\n"
200//usage: IF_FEATURE_VI_FILE_FORMAT(
201//usage: "\n -b Edit file in binary mode"
202//usage: )
187//usage: IF_FEATURE_VI_COLON( 203//usage: IF_FEATURE_VI_COLON(
188//usage: "\n -c CMD Initial command to run ($EXINIT and ~/.exrc also available)" 204//usage: "\n -c CMD Initial command to run ($EXINIT and ~/.exrc also available)"
189//usage: ) 205//usage: )
@@ -198,6 +214,9 @@
198#if ENABLE_FEATURE_VI_REGEX_SEARCH 214#if ENABLE_FEATURE_VI_REGEX_SEARCH
199# include <regex.h> 215# include <regex.h>
200#endif 216#endif
217#if ENABLE_PLATFORM_MINGW32
218# include "BB_VER.h"
219#endif
201 220
202// the CRASHME code is unmaintained, and doesn't currently build 221// the CRASHME code is unmaintained, and doesn't currently build
203#define ENABLE_FEATURE_VI_CRASHME 0 222#define ENABLE_FEATURE_VI_CRASHME 0
@@ -224,7 +243,11 @@
224 243
225#endif 244#endif
226 245
246#if !ENABLE_PLATFORM_MINGW32
227#define isbackspace(c) ((c) == term_orig.c_cc[VERASE] || (c) == 8 || (c) == 127) 247#define isbackspace(c) ((c) == term_orig.c_cc[VERASE] || (c) == 8 || (c) == 127)
248#else
249#define isbackspace(c) ((c) == 8 || (c) == 127)
250#endif
228 251
229enum { 252enum {
230 MAX_TABSTOP = 32, // sanity limit 253 MAX_TABSTOP = 32, // sanity limit
@@ -298,6 +321,7 @@ struct globals {
298 321
299 // the rest 322 // the rest
300#if ENABLE_FEATURE_VI_SETOPTS 323#if ENABLE_FEATURE_VI_SETOPTS
324#if !ENABLE_FEATURE_VI_FILE_FORMAT
301 smallint vi_setops; // set by setops() 325 smallint vi_setops; // set by setops()
302#define VI_AUTOINDENT (1 << 0) 326#define VI_AUTOINDENT (1 << 0)
303#define VI_EXPANDTAB (1 << 1) 327#define VI_EXPANDTAB (1 << 1)
@@ -305,6 +329,19 @@ struct globals {
305#define VI_IGNORECASE (1 << 3) 329#define VI_IGNORECASE (1 << 3)
306#define VI_SHOWMATCH (1 << 4) 330#define VI_SHOWMATCH (1 << 4)
307#define VI_TABSTOP (1 << 5) 331#define VI_TABSTOP (1 << 5)
332#else
333 int vi_setops; // set by setops()
334#define VI_AUTOINDENT (1 << 0)
335#define VI_BINARY (1 << 1)
336#define VI_EXPANDTAB (1 << 2)
337#define VI_FILEFORMAT (1 << 3)
338#define VI_FILEFORMATS (1 << 4)
339#define VI_ERR_METHOD (1 << 5)
340#define VI_IGNORECASE (1 << 6)
341#define VI_SHOWMATCH (1 << 7)
342#define VI_TABSTOP (1 << 8)
343#define binary (vi_setops & VI_BINARY )
344#endif
308#define autoindent (vi_setops & VI_AUTOINDENT) 345#define autoindent (vi_setops & VI_AUTOINDENT)
309#define expandtab (vi_setops & VI_EXPANDTAB ) 346#define expandtab (vi_setops & VI_EXPANDTAB )
310#define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash 347#define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash
@@ -313,11 +350,25 @@ struct globals {
313// order of constants and strings must match 350// order of constants and strings must match
314#define OPTS_STR \ 351#define OPTS_STR \
315 "ai\0""autoindent\0" \ 352 "ai\0""autoindent\0" \
353 IF_FEATURE_VI_FILE_FORMAT("bin\0""binary\0") \
316 "et\0""expandtab\0" \ 354 "et\0""expandtab\0" \
355 IF_FEATURE_VI_FILE_FORMAT("ff\0""fileformat\0") \
356 IF_FEATURE_VI_FILE_FORMAT("ffs\0""fileformats\0") \
317 "fl\0""flash\0" \ 357 "fl\0""flash\0" \
318 "ic\0""ignorecase\0" \ 358 "ic\0""ignorecase\0" \
319 "sm\0""showmatch\0" \ 359 "sm\0""showmatch\0" \
320 "ts\0""tabstop\0" 360 "ts\0""tabstop\0"
361
362#define FF_DOS 0
363#define FF_UNIX 1
364
365#define FF_STR \
366 "dos\0" \
367 "unix\0"
368
369#define FFS_STR \
370 "dos,unix\0" \
371 "unix,dos\0"
321#else 372#else
322#define autoindent (0) 373#define autoindent (0)
323#define expandtab (0) 374#define expandtab (0)
@@ -384,6 +435,10 @@ struct globals {
384 int newindent; // autoindent value for 'O'/'cc' commands 435 int newindent; // autoindent value for 'O'/'cc' commands
385 // or -1 to use indent from previous line 436 // or -1 to use indent from previous line
386#endif 437#endif
438#if ENABLE_FEATURE_VI_FILE_FORMAT
439 smallint fileformat;
440 smallint fileformats;
441#endif
387 smallint cmd_error; 442 smallint cmd_error;
388 443
389 // former statics 444 // former statics
@@ -511,6 +566,8 @@ struct globals {
511#define last_search_pattern (G.last_search_pattern) 566#define last_search_pattern (G.last_search_pattern)
512#define char_insert__indentcol (G.char_insert__indentcol) 567#define char_insert__indentcol (G.char_insert__indentcol)
513#define newindent (G.newindent ) 568#define newindent (G.newindent )
569#define fileformat (G.fileformat )
570#define fileformats (G.fileformats )
514#define cmd_error (G.cmd_error ) 571#define cmd_error (G.cmd_error )
515 572
516#define edit_file__cur_line (G.edit_file__cur_line) 573#define edit_file__cur_line (G.edit_file__cur_line)
@@ -615,6 +672,23 @@ static ALWAYS_INLINE int query_screen_dimensions(void)
615// sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready) 672// sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready)
616static int mysleep(int hund) 673static int mysleep(int hund)
617{ 674{
675#if ENABLE_PLATFORM_MINGW32
676 HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
677 DWORD ret;
678
679 if (hund == 0) {
680 // Allow two events in the queue. Otherwise pasted test isn't
681 // displayed because there's still a key release event waiting
682 // after the last character is processed.
683 DWORD nevent_out;
684
685 ret = GetNumberOfConsoleInputEvents(h, &nevent_out);
686 return ret != 0 ? (nevent_out > 2) : 0;
687 }
688 fflush_all();
689 ret = WaitForSingleObject(h, hund*10);
690 return ret != WAIT_TIMEOUT;
691#else
618 struct pollfd pfd[1]; 692 struct pollfd pfd[1];
619 693
620 if (hund != 0) 694 if (hund != 0)
@@ -623,6 +697,7 @@ static int mysleep(int hund)
623 pfd[0].fd = STDIN_FILENO; 697 pfd[0].fd = STDIN_FILENO;
624 pfd[0].events = POLLIN; 698 pfd[0].events = POLLIN;
625 return safe_poll(pfd, 1, hund*10) > 0; 699 return safe_poll(pfd, 1, hund*10) > 0;
700#endif
626} 701}
627 702
628//----- Set terminal attributes -------------------------------- 703//----- Set terminal attributes --------------------------------
@@ -1978,6 +2053,18 @@ static char *yank_delete(char *start, char *stop, int buftype, int yf, int undo)
1978 return p; 2053 return p;
1979} 2054}
1980 2055
2056#if ENABLE_PLATFORM_MINGW32
2057static int count_cr(char *p, int len)
2058{
2059 int i, cnt;
2060
2061 for (i = cnt = 0; i < len; ++i)
2062 if (p[i] == '\n')
2063 ++cnt;
2064 return cnt;
2065}
2066#endif
2067
1981// might reallocate text[]! 2068// might reallocate text[]!
1982static int file_insert(const char *fn, char *p, int initial) 2069static int file_insert(const char *fn, char *p, int initial)
1983{ 2070{
@@ -1990,7 +2077,13 @@ static int file_insert(const char *fn, char *p, int initial)
1990 if (p > end) 2077 if (p > end)
1991 p = end; 2078 p = end;
1992 2079
2080#if !ENABLE_PLATFORM_MINGW32
1993 fd = open(fn, O_RDONLY); 2081 fd = open(fn, O_RDONLY);
2082#elif ENABLE_FEATURE_VI_FILE_FORMAT
2083 fd = open(fn, O_RDONLY | (!binary ? _O_TEXT : 0));
2084#else
2085 fd = open(fn, O_RDONLY | _O_TEXT);
2086#endif
1994 if (fd < 0) { 2087 if (fd < 0) {
1995 if (!initial) 2088 if (!initial)
1996 status_line_bold_errno(fn); 2089 status_line_bold_errno(fn);
@@ -2013,8 +2106,15 @@ static int file_insert(const char *fn, char *p, int initial)
2013 status_line_bold_errno(fn); 2106 status_line_bold_errno(fn);
2014 p = text_hole_delete(p, p + size - 1, NO_UNDO); // un-do buffer insert 2107 p = text_hole_delete(p, p + size - 1, NO_UNDO); // un-do buffer insert
2015 } else if (cnt < size) { 2108 } else if (cnt < size) {
2109#if ENABLE_PLATFORM_MINGW32
2110 // On WIN32 a partial read might just mean CRs have been removed
2111 int cnt_cr = cnt + count_cr(p, cnt);
2112#endif
2016 // There was a partial read, shrink unused space 2113 // There was a partial read, shrink unused space
2017 p = text_hole_delete(p + cnt, p + size - 1, NO_UNDO); 2114 p = text_hole_delete(p + cnt, p + size - 1, NO_UNDO);
2115#if ENABLE_PLATFORM_MINGW32
2116 if (cnt_cr < size)
2117#endif
2018 status_line_bold("can't read '%s'", fn); 2118 status_line_bold("can't read '%s'", fn);
2019 } 2119 }
2020# if ENABLE_FEATURE_VI_UNDO 2120# if ENABLE_FEATURE_VI_UNDO
@@ -2022,6 +2122,10 @@ static int file_insert(const char *fn, char *p, int initial)
2022 undo_push_insert(p, size, ALLOW_UNDO); 2122 undo_push_insert(p, size, ALLOW_UNDO);
2023 } 2123 }
2024# endif 2124# endif
2125#if ENABLE_FEATURE_VI_FILE_FORMAT
2126 if (initial && cnt > 0)
2127 fileformat = cnt == size ? FF_UNIX : FF_DOS;
2128#endif
2025 fi: 2129 fi:
2026 close(fd); 2130 close(fd);
2027 2131
@@ -2312,6 +2416,9 @@ static int init_text_buffer(char *fn)
2312 free(text); 2416 free(text);
2313 text_size = 10240; 2417 text_size = 10240;
2314 screenbegin = dot = end = text = xzalloc(text_size); 2418 screenbegin = dot = end = text = xzalloc(text_size);
2419#if ENABLE_FEATURE_VI_FILE_FORMAT
2420 fileformat = fileformats;
2421#endif
2315 2422
2316 update_filename(fn); 2423 update_filename(fn);
2317 rc = file_insert(fn, text, 1); 2424 rc = file_insert(fn, text, 1);
@@ -2358,6 +2465,13 @@ static uintptr_t string_insert(char *p, const char *s, int undo) // insert the s
2358static int file_write(char *fn, char *first, char *last) 2465static int file_write(char *fn, char *first, char *last)
2359{ 2466{
2360 int fd, cnt, charcnt; 2467 int fd, cnt, charcnt;
2468#if ENABLE_PLATFORM_MINGW32
2469# if ENABLE_FEATURE_VI_FILE_FORMAT
2470# define dos (!binary && fileformat == FF_DOS)
2471# else
2472# define dos (1)
2473# endif
2474#endif
2361 2475
2362 if (fn == 0) { 2476 if (fn == 0) {
2363 status_line_bold("No current filename"); 2477 status_line_bold("No current filename");
@@ -2366,12 +2480,22 @@ static int file_write(char *fn, char *first, char *last)
2366 // By popular request we do not open file with O_TRUNC, 2480 // By popular request we do not open file with O_TRUNC,
2367 // but instead ftruncate() it _after_ successful write. 2481 // but instead ftruncate() it _after_ successful write.
2368 // Might reduce amount of data lost on power fail etc. 2482 // Might reduce amount of data lost on power fail etc.
2483#if !ENABLE_PLATFORM_MINGW32
2369 fd = open(fn, (O_WRONLY | O_CREAT), 0666); 2484 fd = open(fn, (O_WRONLY | O_CREAT), 0666);
2485#else
2486 fd = open(fn, (O_WRONLY | O_CREAT | (dos ? _O_TEXT : 0)), 0666);
2487#endif
2370 if (fd < 0) 2488 if (fd < 0)
2371 return -1; 2489 return -1;
2372 cnt = last - first + 1; 2490 cnt = last - first + 1;
2373 charcnt = full_write(fd, first, cnt); 2491 charcnt = full_write(fd, first, cnt);
2492#if !ENABLE_PLATFORM_MINGW32
2374 ftruncate(fd, charcnt); 2493 ftruncate(fd, charcnt);
2494#else
2495 // If file was written in text mode it will be bigger so adjust
2496 // the truncation to match.
2497 ftruncate(fd, charcnt + (dos ? count_cr(first, cnt) : 0));
2498#endif
2375 if (charcnt == cnt) { 2499 if (charcnt == cnt) {
2376 // good write 2500 // good write
2377 //modified_count = FALSE; 2501 //modified_count = FALSE;
@@ -2660,6 +2784,7 @@ static void setops(char *args, int flg_no)
2660 2784
2661 index = 1 << (index >> 1); // convert to VI_bit 2785 index = 1 << (index >> 1); // convert to VI_bit
2662 2786
2787#if !ENABLE_FEATURE_VI_FILE_FORMAT
2663 if (index & VI_TABSTOP) { 2788 if (index & VI_TABSTOP) {
2664 int t; 2789 int t;
2665 if (!eq || flg_no) // no "=NNN" or it is "notabstop"? 2790 if (!eq || flg_no) // no "=NNN" or it is "notabstop"?
@@ -2670,11 +2795,43 @@ static void setops(char *args, int flg_no)
2670 tabstop = t; 2795 tabstop = t;
2671 return; 2796 return;
2672 } 2797 }
2798#else
2799 if (index & (VI_TABSTOP | VI_FILEFORMAT | VI_FILEFORMATS)) {
2800 if (!eq || flg_no) // no "=NNN" or it is "notabstop"?
2801 goto bad;
2802 if (index & VI_TABSTOP) {
2803 int t = bb_strtou(eq + 1, NULL, 10);
2804 if (t <= 0 || t > MAX_TABSTOP)
2805 goto bad;
2806 tabstop = t;
2807 return;
2808 } else if (index & VI_FILEFORMAT) {
2809 int t = index_in_strings(FF_STR, eq + 1);
2810 if (t < 0)
2811 goto bad;
2812 if (fileformat != t)
2813 modified_count++;
2814 fileformat = t;
2815 return;
2816 } else { // VI_FILEFORMATS
2817 int t = index_in_strings(FFS_STR, eq + 1);
2818 if (t < 0)
2819 goto bad;
2820 fileformats = t;
2821 return;
2822 }
2823 }
2824#endif
2673 if (eq) goto bad; // boolean option has "="? 2825 if (eq) goto bad; // boolean option has "="?
2674 if (flg_no) { 2826 if (flg_no) {
2675 vi_setops &= ~index; 2827 vi_setops &= ~index;
2676 } else { 2828 } else {
2677 vi_setops |= index; 2829 vi_setops |= index;
2830#if ENABLE_FEATURE_VI_FILE_FORMAT
2831 if (index == VI_BINARY) {
2832 vi_setops &= ~VI_EXPANDTAB;
2833 }
2834#endif
2678 } 2835 }
2679} 2836}
2680# endif 2837# endif
@@ -3166,6 +3323,7 @@ static void colon(char *buf)
3166 if (!args[0] || strcmp(args, "all") == 0) { 3323 if (!args[0] || strcmp(args, "all") == 0) {
3167 // print out values of all options 3324 // print out values of all options
3168# if ENABLE_FEATURE_VI_SETOPTS 3325# if ENABLE_FEATURE_VI_SETOPTS
3326# if !ENABLE_FEATURE_VI_FILE_FORMAT
3169 status_line_bold( 3327 status_line_bold(
3170 "%sautoindent " 3328 "%sautoindent "
3171 "%sexpandtab " 3329 "%sexpandtab "
@@ -3180,6 +3338,28 @@ static void colon(char *buf)
3180 showmatch ? "" : "no", 3338 showmatch ? "" : "no",
3181 tabstop 3339 tabstop
3182 ); 3340 );
3341# else // ENABLE_FEATURE_VI_FILE_FORMAT
3342 unsigned int mask = 1, j = 0;
3343 go_bottom_and_clear_to_eol();
3344 for (;;) {
3345 const char *name = nth_string(OPTS_STR, 2 * j + 1);
3346 if (!name[0])
3347 break;
3348 if (mask == VI_FILEFORMAT)
3349 printf("%s=%s ", name, nth_string(FF_STR, fileformat));
3350 else if (mask == VI_FILEFORMATS)
3351 printf("%s=%s ", name, nth_string(FFS_STR, fileformats));
3352 else if (mask == VI_TABSTOP)
3353 printf("%s=%u ", name, tabstop);
3354 else
3355 printf("%s%s ", vi_setops & mask ? "" : "no", name);
3356 if (j++ == 4)
3357 bb_putchar('\n');
3358 mask <<= 1;
3359 }
3360 bb_putchar('\n');
3361 Hit_Return();
3362# endif
3183# endif 3363# endif
3184 goto ret; 3364 goto ret;
3185 } 3365 }
@@ -4934,17 +5114,20 @@ static void edit_file(char *fn)
4934} 5114}
4935 5115
4936#define VI_OPTSTR \ 5116#define VI_OPTSTR \
5117 IF_FEATURE_VI_FILE_FORMAT("b") \
4937 IF_FEATURE_VI_CRASHME("C") \ 5118 IF_FEATURE_VI_CRASHME("C") \
4938 IF_FEATURE_VI_COLON("c:*") \ 5119 IF_FEATURE_VI_COLON("c:*") \
4939 "Hh" \ 5120 "Hh" \
4940 IF_FEATURE_VI_READONLY("R") 5121 IF_FEATURE_VI_READONLY("R")
4941 5122
4942enum { 5123enum {
5124 IF_FEATURE_VI_FILE_FORMAT(OPTBIT_b,)
4943 IF_FEATURE_VI_CRASHME(OPTBIT_C,) 5125 IF_FEATURE_VI_CRASHME(OPTBIT_C,)
4944 IF_FEATURE_VI_COLON(OPTBIT_c,) 5126 IF_FEATURE_VI_COLON(OPTBIT_c,)
4945 OPTBIT_H, 5127 OPTBIT_H,
4946 OPTBIT_h, 5128 OPTBIT_h,
4947 IF_FEATURE_VI_READONLY(OPTBIT_R,) 5129 IF_FEATURE_VI_READONLY(OPTBIT_R,)
5130 OPT_b = IF_FEATURE_VI_FILE_FORMAT( (1 << OPTBIT_b)) + 0,
4948 OPT_C = IF_FEATURE_VI_CRASHME( (1 << OPTBIT_C)) + 0, 5131 OPT_C = IF_FEATURE_VI_CRASHME( (1 << OPTBIT_C)) + 0,
4949 OPT_c = IF_FEATURE_VI_COLON( (1 << OPTBIT_c)) + 0, 5132 OPT_c = IF_FEATURE_VI_COLON( (1 << OPTBIT_c)) + 0,
4950 OPT_H = 1 << OPTBIT_H, 5133 OPT_H = 1 << OPTBIT_H,
@@ -4981,6 +5164,10 @@ int vi_main(int argc, char **argv)
4981 //vi_setops = 0; 5164 //vi_setops = 0;
4982 opts = getopt32(argv, VI_OPTSTR IF_FEATURE_VI_COLON(, &initial_cmds)); 5165 opts = getopt32(argv, VI_OPTSTR IF_FEATURE_VI_COLON(, &initial_cmds));
4983 5166
5167#if ENABLE_FEATURE_VI_FILE_FORMAT
5168 if (opts & OPT_b)
5169 vi_setops |= VI_BINARY;
5170#endif
4984#if ENABLE_FEATURE_VI_CRASHME 5171#if ENABLE_FEATURE_VI_CRASHME
4985 if (opts & OPT_C) 5172 if (opts & OPT_C)
4986 crashme = 1; 5173 crashme = 1;
@@ -5016,7 +5203,11 @@ int vi_main(int argc, char **argv)
5016 5203
5017 // .exrc must belong to and only be writable by user 5204 // .exrc must belong to and only be writable by user
5018 if (stat(exrc, &st) == 0) { 5205 if (stat(exrc, &st) == 0) {
5206# if !ENABLE_PLATFORM_MINGW32
5019 if ((st.st_mode & (S_IWGRP|S_IWOTH)) == 0 5207 if ((st.st_mode & (S_IWGRP|S_IWOTH)) == 0
5208# else
5209 if (1
5210# endif
5020 && st.st_uid == getuid() 5211 && st.st_uid == getuid()
5021 ) { 5212 ) {
5022 cmds = xmalloc_open_read_close(exrc, NULL); 5213 cmds = xmalloc_open_read_close(exrc, NULL);