diff options
author | Ron Yorston <rmy@pobox.com> | 2021-08-22 09:17:10 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2021-08-22 09:17:10 +0100 |
commit | 46c5767e7e39d1e173e382bda86ab88b4cad354d (patch) | |
tree | d22c7f2376527aebd556eec36e115f037f8a467e /editors/vi.c | |
parent | f13defb1c8f892ecf3e8dd5dbe486cc2b53e6f03 (diff) | |
parent | 74c4f356aee9c64978a881e5760055d0e3510a6a (diff) | |
download | busybox-w32-46c5767e7e39d1e173e382bda86ab88b4cad354d.tar.gz busybox-w32-46c5767e7e39d1e173e382bda86ab88b4cad354d.tar.bz2 busybox-w32-46c5767e7e39d1e173e382bda86ab88b4cad354d.zip |
Merge branch 'busybox' into merge
Diffstat (limited to 'editors/vi.c')
-rw-r--r-- | editors/vi.c | 192 |
1 files changed, 107 insertions, 85 deletions
diff --git a/editors/vi.c b/editors/vi.c index c5dff3fee..c791a32e1 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -7,7 +7,7 @@ | |||
7 | */ | 7 | */ |
8 | // | 8 | // |
9 | //Things To Do: | 9 | //Things To Do: |
10 | // $HOME/.exrc and ./.exrc | 10 | // ./.exrc |
11 | // add magic to search /foo.*bar | 11 | // add magic to search /foo.*bar |
12 | // add :help command | 12 | // add :help command |
13 | // :map macros | 13 | // :map macros |
@@ -185,7 +185,7 @@ | |||
185 | //usage:#define vi_full_usage "\n\n" | 185 | //usage:#define vi_full_usage "\n\n" |
186 | //usage: "Edit FILE\n" | 186 | //usage: "Edit FILE\n" |
187 | //usage: IF_FEATURE_VI_COLON( | 187 | //usage: IF_FEATURE_VI_COLON( |
188 | //usage: "\n -c CMD Initial command to run ($EXINIT also available)" | 188 | //usage: "\n -c CMD Initial command to run ($EXINIT and ~/.exrc also available)" |
189 | //usage: ) | 189 | //usage: ) |
190 | //usage: IF_FEATURE_VI_READONLY( | 190 | //usage: IF_FEATURE_VI_READONLY( |
191 | //usage: "\n -R Read-only" | 191 | //usage: "\n -R Read-only" |
@@ -201,6 +201,7 @@ | |||
201 | 201 | ||
202 | // the CRASHME code is unmaintained, and doesn't currently build | 202 | // the CRASHME code is unmaintained, and doesn't currently build |
203 | #define ENABLE_FEATURE_VI_CRASHME 0 | 203 | #define ENABLE_FEATURE_VI_CRASHME 0 |
204 | #define IF_FEATURE_VI_CRASHME(...) | ||
204 | 205 | ||
205 | 206 | ||
206 | #if ENABLE_LOCALE_SUPPORT | 207 | #if ENABLE_LOCALE_SUPPORT |
@@ -405,7 +406,7 @@ struct globals { | |||
405 | int cindex; // saved character index for up/down motion | 406 | int cindex; // saved character index for up/down motion |
406 | smallint keep_index; // retain saved character index | 407 | smallint keep_index; // retain saved character index |
407 | #if ENABLE_FEATURE_VI_COLON | 408 | #if ENABLE_FEATURE_VI_COLON |
408 | char *initial_cmds[3]; // currently 2 entries, NULL terminated | 409 | llist_t *initial_cmds; |
409 | #endif | 410 | #endif |
410 | // Should be just enough to hold a key sequence, | 411 | // Should be just enough to hold a key sequence, |
411 | // but CRASHME mode uses it as generated command buffer too | 412 | // but CRASHME mode uses it as generated command buffer too |
@@ -1405,21 +1406,14 @@ static void print_literal(char *buf, const char *s) | |||
1405 | char *d; | 1406 | char *d; |
1406 | unsigned char c; | 1407 | unsigned char c; |
1407 | 1408 | ||
1408 | buf[0] = '\0'; | ||
1409 | if (!s[0]) | 1409 | if (!s[0]) |
1410 | s = "(NULL)"; | 1410 | s = "(NULL)"; |
1411 | 1411 | ||
1412 | d = buf; | 1412 | d = buf; |
1413 | for (; *s; s++) { | 1413 | for (; *s; s++) { |
1414 | int c_is_no_print; | ||
1415 | |||
1416 | c = *s; | 1414 | c = *s; |
1417 | c_is_no_print = (c & 0x80) && !Isprint(c); | 1415 | if ((c & 0x80) && !Isprint(c)) |
1418 | if (c_is_no_print) { | 1416 | c = '?'; |
1419 | strcpy(d, ESC_NORM_TEXT); | ||
1420 | d += sizeof(ESC_NORM_TEXT)-1; | ||
1421 | c = '.'; | ||
1422 | } | ||
1423 | if (c < ' ' || c == 0x7f) { | 1417 | if (c < ' ' || c == 0x7f) { |
1424 | *d++ = '^'; | 1418 | *d++ = '^'; |
1425 | c |= '@'; // 0x40 | 1419 | c |= '@'; // 0x40 |
@@ -1428,14 +1422,6 @@ static void print_literal(char *buf, const char *s) | |||
1428 | } | 1422 | } |
1429 | *d++ = c; | 1423 | *d++ = c; |
1430 | *d = '\0'; | 1424 | *d = '\0'; |
1431 | if (c_is_no_print) { | ||
1432 | strcpy(d, ESC_BOLD_TEXT); | ||
1433 | d += sizeof(ESC_BOLD_TEXT)-1; | ||
1434 | } | ||
1435 | if (*s == '\n') { | ||
1436 | *d++ = '$'; | ||
1437 | *d = '\0'; | ||
1438 | } | ||
1439 | if (d - buf > MAX_INPUT_LEN - 10) // paranoia | 1425 | if (d - buf > MAX_INPUT_LEN - 10) // paranoia |
1440 | break; | 1426 | break; |
1441 | } | 1427 | } |
@@ -2592,8 +2578,13 @@ static char *get_one_address(char *p, int *result) // get colon addr, if present | |||
2592 | dir = ((unsigned)BACK << 1) | FULL; | 2578 | dir = ((unsigned)BACK << 1) | FULL; |
2593 | } | 2579 | } |
2594 | q = char_search(q, last_search_pattern + 1, dir); | 2580 | q = char_search(q, last_search_pattern + 1, dir); |
2595 | if (q == NULL) | 2581 | if (q == NULL) { |
2596 | return NULL; | 2582 | // no match, continue from other end of file |
2583 | q = char_search(dir > 0 ? text : end - 1, | ||
2584 | last_search_pattern + 1, dir); | ||
2585 | if (q == NULL) | ||
2586 | return NULL; | ||
2587 | } | ||
2597 | new_addr = count_lines(text, q); | 2588 | new_addr = count_lines(text, q); |
2598 | } | 2589 | } |
2599 | # endif | 2590 | # endif |
@@ -2894,10 +2885,12 @@ static void colon(char *buf) | |||
2894 | // :!<cmd> // run <cmd> then return | 2885 | // :!<cmd> // run <cmd> then return |
2895 | // | 2886 | // |
2896 | 2887 | ||
2897 | if (!buf[0]) | 2888 | while (*buf == ':') |
2898 | goto ret; | 2889 | buf++; // move past leading colons |
2899 | if (*buf == ':') | 2890 | while (isblank(*buf)) |
2900 | buf++; // move past the ':' | 2891 | buf++; // move past leading blanks |
2892 | if (!buf[0] || buf[0] == '"') | ||
2893 | goto ret; // ignore empty lines or those starting with '"' | ||
2901 | 2894 | ||
2902 | li = i = 0; | 2895 | li = i = 0; |
2903 | b = e = -1; | 2896 | b = e = -1; |
@@ -4155,8 +4148,8 @@ static void do_cmd(int c) | |||
4155 | #endif | 4148 | #endif |
4156 | } | 4149 | } |
4157 | } | 4150 | } |
4158 | } else /* if (c == '>') */ { | 4151 | } else if (/* c == '>' && */ p != end_line(p)) { |
4159 | // shift right -- add tab or tabstop spaces | 4152 | // shift right -- add tab or tabstop spaces on non-empty lines |
4160 | char_insert(p, '\t', allow_undo); | 4153 | char_insert(p, '\t', allow_undo); |
4161 | } | 4154 | } |
4162 | #if ENABLE_FEATURE_VI_UNDO | 4155 | #if ENABLE_FEATURE_VI_UNDO |
@@ -4774,6 +4767,21 @@ static void crash_test() | |||
4774 | } | 4767 | } |
4775 | #endif | 4768 | #endif |
4776 | 4769 | ||
4770 | #if ENABLE_FEATURE_VI_COLON | ||
4771 | static void run_cmds(char *p) | ||
4772 | { | ||
4773 | while (p) { | ||
4774 | char *q = p; | ||
4775 | p = strchr(q, '\n'); | ||
4776 | if (p) | ||
4777 | while (*p == '\n') | ||
4778 | *p++ = '\0'; | ||
4779 | if (strlen(q) < MAX_INPUT_LEN) | ||
4780 | colon(q); | ||
4781 | } | ||
4782 | } | ||
4783 | #endif | ||
4784 | |||
4777 | static void edit_file(char *fn) | 4785 | static void edit_file(char *fn) |
4778 | { | 4786 | { |
4779 | #if ENABLE_FEATURE_VI_YANKMARK | 4787 | #if ENABLE_FEATURE_VI_YANKMARK |
@@ -4844,25 +4852,8 @@ static void edit_file(char *fn) | |||
4844 | #endif | 4852 | #endif |
4845 | 4853 | ||
4846 | #if ENABLE_FEATURE_VI_COLON | 4854 | #if ENABLE_FEATURE_VI_COLON |
4847 | { | 4855 | while (initial_cmds) |
4848 | char *p, *q; | 4856 | run_cmds((char *)llist_pop(&initial_cmds)); |
4849 | int n = 0; | ||
4850 | |||
4851 | while ((p = initial_cmds[n]) != NULL) { | ||
4852 | do { | ||
4853 | q = p; | ||
4854 | p = strchr(q, '\n'); | ||
4855 | if (p) | ||
4856 | while (*p == '\n') | ||
4857 | *p++ = '\0'; | ||
4858 | if (*q) | ||
4859 | colon(q); | ||
4860 | } while (p); | ||
4861 | free(initial_cmds[n]); | ||
4862 | initial_cmds[n] = NULL; | ||
4863 | n++; | ||
4864 | } | ||
4865 | } | ||
4866 | #endif | 4857 | #endif |
4867 | redraw(FALSE); // dont force every col re-draw | 4858 | redraw(FALSE); // dont force every col re-draw |
4868 | //------This is the main Vi cmd handling loop ----------------------- | 4859 | //------This is the main Vi cmd handling loop ----------------------- |
@@ -4925,10 +4916,29 @@ static void edit_file(char *fn) | |||
4925 | #undef cur_line | 4916 | #undef cur_line |
4926 | } | 4917 | } |
4927 | 4918 | ||
4919 | #define VI_OPTSTR \ | ||
4920 | IF_FEATURE_VI_CRASHME("C") \ | ||
4921 | IF_FEATURE_VI_COLON("c:*") \ | ||
4922 | "Hh" \ | ||
4923 | IF_FEATURE_VI_READONLY("R") | ||
4924 | |||
4925 | enum { | ||
4926 | IF_FEATURE_VI_CRASHME(OPTBIT_C,) | ||
4927 | IF_FEATURE_VI_COLON(OPTBIT_c,) | ||
4928 | OPTBIT_H, | ||
4929 | OPTBIT_h, | ||
4930 | IF_FEATURE_VI_READONLY(OPTBIT_R,) | ||
4931 | OPT_C = IF_FEATURE_VI_CRASHME( (1 << OPTBIT_C)) + 0, | ||
4932 | OPT_c = IF_FEATURE_VI_COLON( (1 << OPTBIT_c)) + 0, | ||
4933 | OPT_H = 1 << OPTBIT_H, | ||
4934 | OPT_h = 1 << OPTBIT_h, | ||
4935 | OPT_R = IF_FEATURE_VI_READONLY( (1 << OPTBIT_R)) + 0, | ||
4936 | }; | ||
4937 | |||
4928 | int vi_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 4938 | int vi_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
4929 | int vi_main(int argc, char **argv) | 4939 | int vi_main(int argc, char **argv) |
4930 | { | 4940 | { |
4931 | int c; | 4941 | int opts; |
4932 | 4942 | ||
4933 | INIT_G(); | 4943 | INIT_G(); |
4934 | 4944 | ||
@@ -4952,50 +4962,62 @@ int vi_main(int argc, char **argv) | |||
4952 | 4962 | ||
4953 | // 0: all of our options are disabled by default in vim | 4963 | // 0: all of our options are disabled by default in vim |
4954 | //vi_setops = 0; | 4964 | //vi_setops = 0; |
4955 | // 1- process EXINIT variable from environment | 4965 | opts = getopt32(argv, VI_OPTSTR IF_FEATURE_VI_COLON(, &initial_cmds)); |
4956 | // 2- if EXINIT is unset process $HOME/.exrc file (not inplemented yet) | 4966 | |
4957 | // 3- process command line args | ||
4958 | #if ENABLE_FEATURE_VI_COLON | ||
4959 | { | ||
4960 | char *p = getenv("EXINIT"); | ||
4961 | if (p && *p) | ||
4962 | initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN); | ||
4963 | } | ||
4964 | #endif | ||
4965 | while ((c = getopt(argc, argv, | ||
4966 | #if ENABLE_FEATURE_VI_CRASHME | ||
4967 | "C" | ||
4968 | #endif | ||
4969 | "RHh" IF_FEATURE_VI_COLON("c:"))) != -1) { | ||
4970 | switch (c) { | ||
4971 | #if ENABLE_FEATURE_VI_CRASHME | 4967 | #if ENABLE_FEATURE_VI_CRASHME |
4972 | case 'C': | 4968 | if (opts & OPT_C) |
4973 | crashme = 1; | 4969 | crashme = 1; |
4974 | break; | ||
4975 | #endif | ||
4976 | #if ENABLE_FEATURE_VI_READONLY | ||
4977 | case 'R': // Read-only flag | ||
4978 | SET_READONLY_MODE(readonly_mode); | ||
4979 | break; | ||
4980 | #endif | ||
4981 | #if ENABLE_FEATURE_VI_COLON | ||
4982 | case 'c': // cmd line vi command | ||
4983 | if (*optarg) | ||
4984 | initial_cmds[initial_cmds[0] != NULL] = xstrndup(optarg, MAX_INPUT_LEN); | ||
4985 | break; | ||
4986 | #endif | 4970 | #endif |
4987 | case 'H': | 4971 | if (opts & OPT_R) |
4988 | show_help(); | 4972 | SET_READONLY_MODE(readonly_mode); |
4989 | // fall through | 4973 | if (opts & OPT_H) |
4990 | default: | 4974 | show_help(); |
4991 | bb_show_usage(); | 4975 | if (opts & (OPT_H | OPT_h)) { |
4992 | return 1; | 4976 | bb_show_usage(); |
4993 | } | 4977 | return 1; |
4994 | } | 4978 | } |
4995 | 4979 | ||
4996 | argv += optind; | 4980 | argv += optind; |
4997 | cmdline_filecnt = argc - optind; | 4981 | cmdline_filecnt = argc - optind; |
4998 | 4982 | ||
4983 | // 1- process EXINIT variable from environment | ||
4984 | // 2- if EXINIT is unset process $HOME/.exrc file | ||
4985 | // 3- process command line args | ||
4986 | #if ENABLE_FEATURE_VI_COLON | ||
4987 | { | ||
4988 | const char *exinit = getenv("EXINIT"); | ||
4989 | char *cmds = NULL; | ||
4990 | |||
4991 | if (exinit) { | ||
4992 | cmds = xstrdup(exinit); | ||
4993 | } else { | ||
4994 | const char *home = getenv("HOME"); | ||
4995 | |||
4996 | if (home && *home) { | ||
4997 | char *exrc = concat_path_file(home, ".exrc"); | ||
4998 | struct stat st; | ||
4999 | |||
5000 | // .exrc must belong to and only be writable by user | ||
5001 | if (stat(exrc, &st) == 0) { | ||
5002 | if ((st.st_mode & (S_IWGRP|S_IWOTH)) == 0 | ||
5003 | && st.st_uid == getuid() | ||
5004 | ) { | ||
5005 | cmds = xmalloc_open_read_close(exrc, NULL); | ||
5006 | } else { | ||
5007 | status_line_bold(".exrc: permission denied"); | ||
5008 | } | ||
5009 | } | ||
5010 | free(exrc); | ||
5011 | } | ||
5012 | } | ||
5013 | |||
5014 | if (cmds) { | ||
5015 | init_text_buffer(NULL); | ||
5016 | run_cmds(cmds); | ||
5017 | free(cmds); | ||
5018 | } | ||
5019 | } | ||
5020 | #endif | ||
4999 | // "Save cursor, use alternate screen buffer, clear screen" | 5021 | // "Save cursor, use alternate screen buffer, clear screen" |
5000 | write1(ESC"[?1049h"); | 5022 | write1(ESC"[?1049h"); |
5001 | // This is the main file handling loop | 5023 | // This is the main file handling loop |