aboutsummaryrefslogtreecommitdiff
path: root/editors/vi.c
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-08-22 09:17:10 +0100
committerRon Yorston <rmy@pobox.com>2021-08-22 09:17:10 +0100
commit46c5767e7e39d1e173e382bda86ab88b4cad354d (patch)
treed22c7f2376527aebd556eec36e115f037f8a467e /editors/vi.c
parentf13defb1c8f892ecf3e8dd5dbe486cc2b53e6f03 (diff)
parent74c4f356aee9c64978a881e5760055d0e3510a6a (diff)
downloadbusybox-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.c192
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
4771static 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
4777static void edit_file(char *fn) 4785static 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
4925enum {
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
4928int vi_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 4938int vi_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
4929int vi_main(int argc, char **argv) 4939int 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