diff options
author | Ron Yorston <rmy@pobox.com> | 2021-08-30 08:44:58 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2021-08-30 09:16:01 +0100 |
commit | 420afde92eb83c8c19b856f45491568cfa04a625 (patch) | |
tree | eec8392147bc79ac58d0341be5b23ce97d4f5a21 /editors/vi.c | |
parent | a9fc40467450f5afa9b220bb7c0fa9cade71c7a5 (diff) | |
download | busybox-w32-420afde92eb83c8c19b856f45491568cfa04a625.tar.gz busybox-w32-420afde92eb83c8c19b856f45491568cfa04a625.tar.bz2 busybox-w32-420afde92eb83c8c19b856f45491568cfa04a625.zip |
vi: add fileformats option
Add a limited version of the 'fileformats' option. Only the
'dos,unix' and 'unix,dos' settings are allowed with the former
as default.
When a file is read for editing its format is detected. If it
only has LF line endings it's treated as being of type 'unix'
otherwise its type is 'dos'.
When an empty edit buffer is created it's given the first file
type listed in 'fileformats'.
The file type is stored in the read-only option 'fileformat'
and is used to select the appropriate line endings when the
file is written.
See GitHub issue #220. Adds 168 bytes to the binary.
Diffstat (limited to 'editors/vi.c')
-rw-r--r-- | editors/vi.c | 100 |
1 files changed, 97 insertions, 3 deletions
diff --git a/editors/vi.c b/editors/vi.c index 2c1048a4c..b973cc056 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -112,6 +112,15 @@ | |||
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. Enable the 'fileformats' option. | ||
123 | //config: | ||
115 | //config:config FEATURE_VI_SET | 124 | //config:config FEATURE_VI_SET |
116 | //config: bool "Support :set" | 125 | //config: bool "Support :set" |
117 | //config: default y | 126 | //config: default y |
@@ -297,6 +306,7 @@ struct globals { | |||
297 | 306 | ||
298 | // the rest | 307 | // the rest |
299 | #if ENABLE_FEATURE_VI_SETOPTS | 308 | #if ENABLE_FEATURE_VI_SETOPTS |
309 | #if !ENABLE_FEATURE_VI_FILE_FORMAT | ||
300 | smallint vi_setops; // set by setops() | 310 | smallint vi_setops; // set by setops() |
301 | #define VI_AUTOINDENT (1 << 0) | 311 | #define VI_AUTOINDENT (1 << 0) |
302 | #define VI_EXPANDTAB (1 << 1) | 312 | #define VI_EXPANDTAB (1 << 1) |
@@ -304,6 +314,17 @@ struct globals { | |||
304 | #define VI_IGNORECASE (1 << 3) | 314 | #define VI_IGNORECASE (1 << 3) |
305 | #define VI_SHOWMATCH (1 << 4) | 315 | #define VI_SHOWMATCH (1 << 4) |
306 | #define VI_TABSTOP (1 << 5) | 316 | #define VI_TABSTOP (1 << 5) |
317 | #else | ||
318 | smalluint vi_setops; // set by setops() | ||
319 | #define VI_AUTOINDENT (1 << 0) | ||
320 | #define VI_EXPANDTAB (1 << 1) | ||
321 | #define VI_FILEFORMAT (1 << 2) | ||
322 | #define VI_FILEFORMATS (1 << 3) | ||
323 | #define VI_ERR_METHOD (1 << 4) | ||
324 | #define VI_IGNORECASE (1 << 5) | ||
325 | #define VI_SHOWMATCH (1 << 6) | ||
326 | #define VI_TABSTOP (1 << 7) | ||
327 | #endif | ||
307 | #define autoindent (vi_setops & VI_AUTOINDENT) | 328 | #define autoindent (vi_setops & VI_AUTOINDENT) |
308 | #define expandtab (vi_setops & VI_EXPANDTAB ) | 329 | #define expandtab (vi_setops & VI_EXPANDTAB ) |
309 | #define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash | 330 | #define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash |
@@ -313,10 +334,18 @@ struct globals { | |||
313 | #define OPTS_STR \ | 334 | #define OPTS_STR \ |
314 | "ai\0""autoindent\0" \ | 335 | "ai\0""autoindent\0" \ |
315 | "et\0""expandtab\0" \ | 336 | "et\0""expandtab\0" \ |
337 | IF_FEATURE_VI_FILE_FORMAT("ff\0""fileformat\0") \ | ||
338 | IF_FEATURE_VI_FILE_FORMAT("ffs\0""fileformats\0") \ | ||
316 | "fl\0""flash\0" \ | 339 | "fl\0""flash\0" \ |
317 | "ic\0""ignorecase\0" \ | 340 | "ic\0""ignorecase\0" \ |
318 | "sm\0""showmatch\0" \ | 341 | "sm\0""showmatch\0" \ |
319 | "ts\0""tabstop\0" | 342 | "ts\0""tabstop\0" |
343 | |||
344 | #define FF_DOS_UNIX 0 | ||
345 | #define FF_UNIX_DOS 1 | ||
346 | #define FORMATS_STR \ | ||
347 | "dos,unix\0" \ | ||
348 | "unix,dos\0" | ||
320 | #else | 349 | #else |
321 | #define autoindent (0) | 350 | #define autoindent (0) |
322 | #define expandtab (0) | 351 | #define expandtab (0) |
@@ -380,6 +409,10 @@ struct globals { | |||
380 | #if ENABLE_FEATURE_VI_SETOPTS | 409 | #if ENABLE_FEATURE_VI_SETOPTS |
381 | int indentcol; // column of recently autoindent, 0 or -1 | 410 | int indentcol; // column of recently autoindent, 0 or -1 |
382 | #endif | 411 | #endif |
412 | #if ENABLE_FEATURE_VI_FILE_FORMAT | ||
413 | smallint fileformat; | ||
414 | smallint fileformats; | ||
415 | #endif | ||
383 | smallint cmd_error; | 416 | smallint cmd_error; |
384 | 417 | ||
385 | // former statics | 418 | // former statics |
@@ -507,6 +540,8 @@ struct globals { | |||
507 | #define dotcnt (G.dotcnt ) | 540 | #define dotcnt (G.dotcnt ) |
508 | #define last_search_pattern (G.last_search_pattern) | 541 | #define last_search_pattern (G.last_search_pattern) |
509 | #define indentcol (G.indentcol ) | 542 | #define indentcol (G.indentcol ) |
543 | #define fileformat (G.fileformat ) | ||
544 | #define fileformats (G.fileformats ) | ||
510 | #define cmd_error (G.cmd_error ) | 545 | #define cmd_error (G.cmd_error ) |
511 | 546 | ||
512 | #define edit_file__cur_line (G.edit_file__cur_line) | 547 | #define edit_file__cur_line (G.edit_file__cur_line) |
@@ -2066,6 +2101,10 @@ static int file_insert(const char *fn, char *p, int initial) | |||
2066 | undo_push_insert(p, size, ALLOW_UNDO); | 2101 | undo_push_insert(p, size, ALLOW_UNDO); |
2067 | } | 2102 | } |
2068 | # endif | 2103 | # endif |
2104 | #if ENABLE_FEATURE_VI_FILE_FORMAT | ||
2105 | if (initial && cnt > 0) | ||
2106 | fileformat = cnt == size ? FF_UNIX_DOS : FF_DOS_UNIX; | ||
2107 | #endif | ||
2069 | fi: | 2108 | fi: |
2070 | close(fd); | 2109 | close(fd); |
2071 | 2110 | ||
@@ -2342,6 +2381,9 @@ static int init_text_buffer(char *fn) | |||
2342 | free(text); | 2381 | free(text); |
2343 | text_size = 10240; | 2382 | text_size = 10240; |
2344 | screenbegin = dot = end = text = xzalloc(text_size); | 2383 | screenbegin = dot = end = text = xzalloc(text_size); |
2384 | #if ENABLE_FEATURE_VI_FILE_FORMAT | ||
2385 | fileformat = fileformats; | ||
2386 | #endif | ||
2345 | 2387 | ||
2346 | update_filename(fn); | 2388 | update_filename(fn); |
2347 | rc = file_insert(fn, text, 1); | 2389 | rc = file_insert(fn, text, 1); |
@@ -2387,6 +2429,13 @@ static uintptr_t string_insert(char *p, const char *s, int undo) // insert the s | |||
2387 | static int file_write(char *fn, char *first, char *last) | 2429 | static int file_write(char *fn, char *first, char *last) |
2388 | { | 2430 | { |
2389 | int fd, cnt, charcnt; | 2431 | int fd, cnt, charcnt; |
2432 | #if ENABLE_PLATFORM_MINGW32 | ||
2433 | # if ENABLE_FEATURE_VI_FILE_FORMAT | ||
2434 | # define dos (fileformat == FF_DOS_UNIX) | ||
2435 | # else | ||
2436 | # define dos (1) | ||
2437 | # endif | ||
2438 | #endif | ||
2390 | 2439 | ||
2391 | if (fn == 0) { | 2440 | if (fn == 0) { |
2392 | status_line_bold("No current filename"); | 2441 | status_line_bold("No current filename"); |
@@ -2398,7 +2447,7 @@ static int file_write(char *fn, char *first, char *last) | |||
2398 | #if !ENABLE_PLATFORM_MINGW32 | 2447 | #if !ENABLE_PLATFORM_MINGW32 |
2399 | fd = open(fn, (O_WRONLY | O_CREAT), 0666); | 2448 | fd = open(fn, (O_WRONLY | O_CREAT), 0666); |
2400 | #else | 2449 | #else |
2401 | fd = open(fn, (O_WRONLY | O_CREAT | _O_TEXT), 0666); | 2450 | fd = open(fn, (O_WRONLY | O_CREAT | (dos ? _O_TEXT : 0)), 0666); |
2402 | #endif | 2451 | #endif |
2403 | if (fd < 0) | 2452 | if (fd < 0) |
2404 | return -1; | 2453 | return -1; |
@@ -2407,9 +2456,9 @@ static int file_write(char *fn, char *first, char *last) | |||
2407 | #if !ENABLE_PLATFORM_MINGW32 | 2456 | #if !ENABLE_PLATFORM_MINGW32 |
2408 | ftruncate(fd, charcnt); | 2457 | ftruncate(fd, charcnt); |
2409 | #else | 2458 | #else |
2410 | // File was written in text mode; this makes it bigger so adjust | 2459 | // If file was written in text mode it will be bigger so adjust |
2411 | // the truncation to match. | 2460 | // the truncation to match. |
2412 | ftruncate(fd, charcnt + count_cr(first, cnt)); | 2461 | ftruncate(fd, charcnt + (dos ? count_cr(first, cnt) : 0)); |
2413 | #endif | 2462 | #endif |
2414 | if (charcnt == cnt) { | 2463 | if (charcnt == cnt) { |
2415 | // good write | 2464 | // good write |
@@ -2699,6 +2748,7 @@ static void setops(char *args, int flg_no) | |||
2699 | 2748 | ||
2700 | index = 1 << (index >> 1); // convert to VI_bit | 2749 | index = 1 << (index >> 1); // convert to VI_bit |
2701 | 2750 | ||
2751 | #if !ENABLE_FEATURE_VI_FILE_FORMAT | ||
2702 | if (index & VI_TABSTOP) { | 2752 | if (index & VI_TABSTOP) { |
2703 | int t; | 2753 | int t; |
2704 | if (!eq || flg_no) // no "=NNN" or it is "notabstop"? | 2754 | if (!eq || flg_no) // no "=NNN" or it is "notabstop"? |
@@ -2709,6 +2759,27 @@ static void setops(char *args, int flg_no) | |||
2709 | tabstop = t; | 2759 | tabstop = t; |
2710 | return; | 2760 | return; |
2711 | } | 2761 | } |
2762 | #else | ||
2763 | if (index & VI_FILEFORMAT) | ||
2764 | goto bad; | ||
2765 | if (index & (VI_TABSTOP | VI_FILEFORMATS)) { | ||
2766 | if (!eq || flg_no) // no "=NNN" or it is "notabstop"? | ||
2767 | goto bad; | ||
2768 | if (index & VI_TABSTOP) { | ||
2769 | int t = bb_strtou(eq + 1, NULL, 10); | ||
2770 | if (t <= 0 || t > MAX_TABSTOP) | ||
2771 | goto bad; | ||
2772 | tabstop = t; | ||
2773 | return; | ||
2774 | } else { // VI_FILEFORMATS | ||
2775 | int t = index_in_strings(FORMATS_STR, eq + 1); | ||
2776 | if (t < 0) | ||
2777 | goto bad; | ||
2778 | fileformats = t; | ||
2779 | return; | ||
2780 | } | ||
2781 | } | ||
2782 | #endif | ||
2712 | if (eq) goto bad; // boolean option has "="? | 2783 | if (eq) goto bad; // boolean option has "="? |
2713 | if (flg_no) { | 2784 | if (flg_no) { |
2714 | vi_setops &= ~index; | 2785 | vi_setops &= ~index; |
@@ -3205,6 +3276,7 @@ static void colon(char *buf) | |||
3205 | if (!args[0] || strcmp(args, "all") == 0) { | 3276 | if (!args[0] || strcmp(args, "all") == 0) { |
3206 | // print out values of all options | 3277 | // print out values of all options |
3207 | # if ENABLE_FEATURE_VI_SETOPTS | 3278 | # if ENABLE_FEATURE_VI_SETOPTS |
3279 | # if !ENABLE_FEATURE_VI_FILE_FORMAT | ||
3208 | status_line_bold( | 3280 | status_line_bold( |
3209 | "%sautoindent " | 3281 | "%sautoindent " |
3210 | "%sexpandtab " | 3282 | "%sexpandtab " |
@@ -3219,6 +3291,28 @@ static void colon(char *buf) | |||
3219 | showmatch ? "" : "no", | 3291 | showmatch ? "" : "no", |
3220 | tabstop | 3292 | tabstop |
3221 | ); | 3293 | ); |
3294 | # else // ENABLE_FEATURE_VI_FILE_FORMAT | ||
3295 | unsigned int mask = 1, j = 0; | ||
3296 | go_bottom_and_clear_to_eol(); | ||
3297 | for (;;) { | ||
3298 | const char *name = nth_string(OPTS_STR, 2 * j + 1); | ||
3299 | if (!name[0]) | ||
3300 | break; | ||
3301 | if (mask == VI_FILEFORMAT) | ||
3302 | printf("%s=%s ", name, nth_string("dos\0unix\0", fileformat)); | ||
3303 | else if (mask == VI_FILEFORMATS) | ||
3304 | printf("%s=%s ", name, nth_string(FORMATS_STR, fileformats)); | ||
3305 | else if (mask == VI_TABSTOP) | ||
3306 | printf("%s=%u ", name, tabstop); | ||
3307 | else | ||
3308 | printf("%s%s ", vi_setops & mask ? "" : "no", name); | ||
3309 | if (j++ == 4) | ||
3310 | bb_putchar('\n'); | ||
3311 | mask <<= 1; | ||
3312 | } | ||
3313 | bb_putchar('\n'); | ||
3314 | Hit_Return(); | ||
3315 | # endif | ||
3222 | # endif | 3316 | # endif |
3223 | goto ret; | 3317 | goto ret; |
3224 | } | 3318 | } |