} while (0)
-static void edit_file(char *); // edit one file
static void do_cmd(int); // execute a command
static int next_tabstop(int);
static void sync_cursor(char *, int *, int *); // synchronize the screen cursor to dot
#define yank_delete(a,b,c,d,e) yank_delete(a,b,c,d)
#endif
static char *yank_delete(char *, char *, int, int, int); // yank text[] into register then delete
-static void show_help(void); // display some help info
static void rawmode(void); // set "raw" mode on tty
static void cookmode(void); // return to "cooked" mode on tty
// sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready)
static int crashme = 0;
#endif
-static void write1(const char *out)
-{
- fputs(out, stdout);
-}
-
-int vi_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int vi_main(int argc, char **argv)
+static void show_help(void)
{
- int c;
-
- INIT_G();
-
-#if ENABLE_FEATURE_VI_UNDO
- /* undo_stack_tail = NULL; - already is */
-#if ENABLE_FEATURE_VI_UNDO_QUEUE
- undo_queue_state = UNDO_EMPTY;
- /* undo_q = 0; - already is */
+ puts("These features are available:"
+#if ENABLE_FEATURE_VI_SEARCH
+ "\n\tPattern searches with / and ?"
#endif
+#if ENABLE_FEATURE_VI_DOT_CMD
+ "\n\tLast command repeat with ."
#endif
-
-#if ENABLE_FEATURE_VI_CRASHME
- srand((long) getpid());
+#if ENABLE_FEATURE_VI_YANKMARK
+ "\n\tLine marking with 'x"
+ "\n\tNamed buffers with \"x"
#endif
-#ifdef NO_SUCH_APPLET_YET
- // if we aren't "vi", we are "view"
- if (ENABLE_FEATURE_VI_READONLY && applet_name[2]) {
- SET_READONLY_MODE(readonly_mode);
- }
+#if ENABLE_FEATURE_VI_READONLY
+ //not implemented: "\n\tReadonly if vi is called as \"view\""
+ //redundant: usage text says this too: "\n\tReadonly with -R command line arg"
#endif
-
- // autoindent is not default in vim 7.3
- vi_setops = /*VI_AUTOINDENT |*/ VI_SHOWMATCH | VI_IGNORECASE;
- // 1- process $HOME/.exrc file (not inplemented yet)
- // 2- process EXINIT variable from environment
- // 3- process command line args
-#if ENABLE_FEATURE_VI_COLON
- {
- char *p = getenv("EXINIT");
- if (p && *p)
- initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN);
- }
+#if ENABLE_FEATURE_VI_SET
+ "\n\tSome colon mode commands with :"
#endif
- while ((c = getopt(argc, argv, "hCRH" IF_FEATURE_VI_COLON("c:"))) != -1) {
- switch (c) {
-#if ENABLE_FEATURE_VI_CRASHME
- case 'C':
- crashme = 1;
- break;
+#if ENABLE_FEATURE_VI_SETOPTS
+ "\n\tSettable options with \":set\""
#endif
-#if ENABLE_FEATURE_VI_READONLY
- case 'R': // Read-only flag
- SET_READONLY_MODE(readonly_mode);
- break;
+#if ENABLE_FEATURE_VI_USE_SIGNALS
+ "\n\tSignal catching- ^C"
+ "\n\tJob suspend and resume with ^Z"
#endif
-#if ENABLE_FEATURE_VI_COLON
- case 'c': // cmd line vi command
- if (*optarg)
- initial_cmds[initial_cmds[0] != NULL] = xstrndup(optarg, MAX_INPUT_LEN);
- break;
+#if ENABLE_FEATURE_VI_WIN_RESIZE
+ "\n\tAdapt to window re-sizes"
#endif
- case 'H':
- show_help();
- // fall through
- default:
- bb_show_usage();
- return 1;
- }
- }
-
- // The argv array can be used by the ":next" and ":rewind" commands
- argv += optind;
- argc -= optind;
-
- //----- This is the main file handling loop --------------
- save_argc = argc;
- optind = 0;
- // "Save cursor, use alternate screen buffer, clear screen"
- write1(ESC"[?1049h");
- while (1) {
- edit_file(argv[optind]); // param might be NULL
- if (++optind >= argc)
- break;
- }
- // "Use normal screen buffer, restore cursor"
- write1(ESC"[?1049l");
- //-----------------------------------------------------------
+ );
+}
- return 0;
+static void write1(const char *out)
+{
+ fputs(out, stdout);
}
/* read text from file or create an empty buf */
}
#endif
-static void edit_file(char *fn)
-{
-#if ENABLE_FEATURE_VI_YANKMARK
-#define cur_line edit_file__cur_line
-#endif
- int c;
-#if ENABLE_FEATURE_VI_USE_SIGNALS
- int sig;
-#endif
-
- editing = 1; // 0 = exit, 1 = one file, 2 = multiple files
- rawmode();
- rows = 24;
- columns = 80;
- IF_FEATURE_VI_ASK_TERMINAL(G.get_rowcol_error =) query_screen_dimensions();
-#if ENABLE_FEATURE_VI_ASK_TERMINAL
- if (G.get_rowcol_error /* TODO? && no input on stdin */) {
- uint64_t k;
- write1(ESC"[999;999H" ESC"[6n");
- fflush_all();
- k = read_key(STDIN_FILENO, readbuffer, /*timeout_ms:*/ 100);
- if ((int32_t)k == KEYCODE_CURSOR_POS) {
- uint32_t rc = (k >> 32);
- columns = (rc & 0x7fff);
- if (columns > MAX_SCR_COLS)
- columns = MAX_SCR_COLS;
- rows = ((rc >> 16) & 0x7fff);
- if (rows > MAX_SCR_ROWS)
- rows = MAX_SCR_ROWS;
- }
- }
-#endif
- new_screen(rows, columns); // get memory for virtual screen
- init_text_buffer(fn);
-
-#if ENABLE_FEATURE_VI_YANKMARK
- YDreg = 26; // default Yank/Delete reg
-// Ureg = 27; - const // hold orig line for "U" cmd
- mark[26] = mark[27] = text; // init "previous context"
-#endif
-
- last_forward_char = last_input_char = '\0';
- crow = 0;
- ccol = 0;
-
-#if ENABLE_FEATURE_VI_USE_SIGNALS
- signal(SIGWINCH, winch_handler);
- signal(SIGTSTP, tstp_handler);
- sig = sigsetjmp(restart, 1);
- if (sig != 0) {
- screenbegin = dot = text;
- }
- // int_handler() can jump to "restart",
- // must install handler *after* initializing "restart"
- signal(SIGINT, int_handler);
-#endif
-
- cmd_mode = 0; // 0=command 1=insert 2='R'eplace
- cmdcnt = 0;
- tabstop = 8;
- offset = 0; // no horizontal offset
- c = '\0';
-#if ENABLE_FEATURE_VI_DOT_CMD
- free(ioq_start);
- ioq = ioq_start = NULL;
- lmc_len = 0;
- adding2q = 0;
-#endif
-
-#if ENABLE_FEATURE_VI_COLON
- {
- char *p, *q;
- int n = 0;
-
- while ((p = initial_cmds[n]) != NULL) {
- do {
- q = p;
- p = strchr(q, '\n');
- if (p)
- while (*p == '\n')
- *p++ = '\0';
- if (*q)
- colon(q);
- } while (p);
- free(initial_cmds[n]);
- initial_cmds[n] = NULL;
- n++;
- }
- }
-#endif
- redraw(FALSE); // dont force every col re-draw
- //------This is the main Vi cmd handling loop -----------------------
- while (editing > 0) {
-#if ENABLE_FEATURE_VI_CRASHME
- if (crashme > 0) {
- if ((end - text) > 1) {
- crash_dummy(); // generate a random command
- } else {
- crashme = 0;
- string_insert(text, "\n\n##### Ran out of text to work on. #####\n\n", NO_UNDO); // insert the string
- dot = text;
- refresh(FALSE);
- }
- }
-#endif
- last_input_char = c = get_one_char(); // get a cmd from user
-#if ENABLE_FEATURE_VI_YANKMARK
- // save a copy of the current line- for the 'U" command
- if (begin_line(dot) != cur_line) {
- cur_line = begin_line(dot);
- text_yank(begin_line(dot), end_line(dot), Ureg);
- }
-#endif
-#if ENABLE_FEATURE_VI_DOT_CMD
- // These are commands that change text[].
- // Remember the input for the "." command
- if (!adding2q && ioq_start == NULL
- && cmd_mode == 0 // command mode
- && c > '\0' // exclude NUL and non-ASCII chars
- && c < 0x7f // (Unicode and such)
- && strchr(modifying_cmds, c)
- ) {
- start_new_cmd_q(c);
- }
-#endif
- do_cmd(c); // execute the user command
-
- // poll to see if there is input already waiting. if we are
- // not able to display output fast enough to keep up, skip
- // the display update until we catch up with input.
- if (!readbuffer[0] && mysleep(0) == 0) {
- // no input pending - so update output
- refresh(FALSE);
- show_status_line();
- }
-#if ENABLE_FEATURE_VI_CRASHME
- if (crashme > 0)
- crash_test(); // test editor variables
-#endif
- }
- //-------------------------------------------------------------------
-
- go_bottom_and_clear_to_eol();
- cookmode();
-#undef cur_line
-}
-
//----- The Colon commands -------------------------------------
#if ENABLE_FEATURE_VI_COLON
static char *get_one_address(char *p, int *addr) // get colon addr, if present
if (start > stop) {
// they are backwards, reverse them
p = start;
- start = stop;
- stop = p;
- }
- if (dist <= 0) {
- // we cannot cross NL boundaries
- p = start;
- if (*p == '\n')
- return p;
- // dont go past a NewLine
- for (; p + 1 <= stop; p++) {
- if (p[1] == '\n') {
- stop = p; // "stop" just before NewLine
- break;
- }
- }
- }
- p = start;
-#if ENABLE_FEATURE_VI_YANKMARK
- text_yank(start, stop, YDreg);
-#endif
- if (yf == YANKDEL) {
- p = text_hole_delete(start, stop, undo);
- } // delete lines
- return p;
-}
-
-static void show_help(void)
-{
- puts("These features are available:"
-#if ENABLE_FEATURE_VI_SEARCH
- "\n\tPattern searches with / and ?"
-#endif
-#if ENABLE_FEATURE_VI_DOT_CMD
- "\n\tLast command repeat with ."
-#endif
-#if ENABLE_FEATURE_VI_YANKMARK
- "\n\tLine marking with 'x"
- "\n\tNamed buffers with \"x"
-#endif
-#if ENABLE_FEATURE_VI_READONLY
- //not implemented: "\n\tReadonly if vi is called as \"view\""
- //redundant: usage text says this too: "\n\tReadonly with -R command line arg"
-#endif
-#if ENABLE_FEATURE_VI_SET
- "\n\tSome colon mode commands with :"
-#endif
-#if ENABLE_FEATURE_VI_SETOPTS
- "\n\tSettable options with \":set\""
-#endif
-#if ENABLE_FEATURE_VI_USE_SIGNALS
- "\n\tSignal catching- ^C"
- "\n\tJob suspend and resume with ^Z"
-#endif
-#if ENABLE_FEATURE_VI_WIN_RESIZE
- "\n\tAdapt to window re-sizes"
+ start = stop;
+ stop = p;
+ }
+ if (dist <= 0) {
+ // we cannot cross NL boundaries
+ p = start;
+ if (*p == '\n')
+ return p;
+ // dont go past a NewLine
+ for (; p + 1 <= stop; p++) {
+ if (p[1] == '\n') {
+ stop = p; // "stop" just before NewLine
+ break;
+ }
+ }
+ }
+ p = start;
+#if ENABLE_FEATURE_VI_YANKMARK
+ text_yank(start, stop, YDreg);
#endif
- );
+ if (yf == YANKDEL) {
+ p = text_hole_delete(start, stop, undo);
+ } // delete lines
+ return p;
}
#if ENABLE_FEATURE_VI_DOT_CMD
}
}
#endif
+
+static void edit_file(char *fn)
+{
+#if ENABLE_FEATURE_VI_YANKMARK
+#define cur_line edit_file__cur_line
+#endif
+ int c;
+#if ENABLE_FEATURE_VI_USE_SIGNALS
+ int sig;
+#endif
+
+ editing = 1; // 0 = exit, 1 = one file, 2 = multiple files
+ rawmode();
+ rows = 24;
+ columns = 80;
+ IF_FEATURE_VI_ASK_TERMINAL(G.get_rowcol_error =) query_screen_dimensions();
+#if ENABLE_FEATURE_VI_ASK_TERMINAL
+ if (G.get_rowcol_error /* TODO? && no input on stdin */) {
+ uint64_t k;
+ write1(ESC"[999;999H" ESC"[6n");
+ fflush_all();
+ k = read_key(STDIN_FILENO, readbuffer, /*timeout_ms:*/ 100);
+ if ((int32_t)k == KEYCODE_CURSOR_POS) {
+ uint32_t rc = (k >> 32);
+ columns = (rc & 0x7fff);
+ if (columns > MAX_SCR_COLS)
+ columns = MAX_SCR_COLS;
+ rows = ((rc >> 16) & 0x7fff);
+ if (rows > MAX_SCR_ROWS)
+ rows = MAX_SCR_ROWS;
+ }
+ }
+#endif
+ new_screen(rows, columns); // get memory for virtual screen
+ init_text_buffer(fn);
+
+#if ENABLE_FEATURE_VI_YANKMARK
+ YDreg = 26; // default Yank/Delete reg
+// Ureg = 27; - const // hold orig line for "U" cmd
+ mark[26] = mark[27] = text; // init "previous context"
+#endif
+
+ last_forward_char = last_input_char = '\0';
+ crow = 0;
+ ccol = 0;
+
+#if ENABLE_FEATURE_VI_USE_SIGNALS
+ signal(SIGWINCH, winch_handler);
+ signal(SIGTSTP, tstp_handler);
+ sig = sigsetjmp(restart, 1);
+ if (sig != 0) {
+ screenbegin = dot = text;
+ }
+ // int_handler() can jump to "restart",
+ // must install handler *after* initializing "restart"
+ signal(SIGINT, int_handler);
+#endif
+
+ cmd_mode = 0; // 0=command 1=insert 2='R'eplace
+ cmdcnt = 0;
+ tabstop = 8;
+ offset = 0; // no horizontal offset
+ c = '\0';
+#if ENABLE_FEATURE_VI_DOT_CMD
+ free(ioq_start);
+ ioq = ioq_start = NULL;
+ lmc_len = 0;
+ adding2q = 0;
+#endif
+
+#if ENABLE_FEATURE_VI_COLON
+ {
+ char *p, *q;
+ int n = 0;
+
+ while ((p = initial_cmds[n]) != NULL) {
+ do {
+ q = p;
+ p = strchr(q, '\n');
+ if (p)
+ while (*p == '\n')
+ *p++ = '\0';
+ if (*q)
+ colon(q);
+ } while (p);
+ free(initial_cmds[n]);
+ initial_cmds[n] = NULL;
+ n++;
+ }
+ }
+#endif
+ redraw(FALSE); // dont force every col re-draw
+ //------This is the main Vi cmd handling loop -----------------------
+ while (editing > 0) {
+#if ENABLE_FEATURE_VI_CRASHME
+ if (crashme > 0) {
+ if ((end - text) > 1) {
+ crash_dummy(); // generate a random command
+ } else {
+ crashme = 0;
+ string_insert(text, "\n\n##### Ran out of text to work on. #####\n\n", NO_UNDO); // insert the string
+ dot = text;
+ refresh(FALSE);
+ }
+ }
+#endif
+ last_input_char = c = get_one_char(); // get a cmd from user
+#if ENABLE_FEATURE_VI_YANKMARK
+ // save a copy of the current line- for the 'U" command
+ if (begin_line(dot) != cur_line) {
+ cur_line = begin_line(dot);
+ text_yank(begin_line(dot), end_line(dot), Ureg);
+ }
+#endif
+#if ENABLE_FEATURE_VI_DOT_CMD
+ // These are commands that change text[].
+ // Remember the input for the "." command
+ if (!adding2q && ioq_start == NULL
+ && cmd_mode == 0 // command mode
+ && c > '\0' // exclude NUL and non-ASCII chars
+ && c < 0x7f // (Unicode and such)
+ && strchr(modifying_cmds, c)
+ ) {
+ start_new_cmd_q(c);
+ }
+#endif
+ do_cmd(c); // execute the user command
+
+ // poll to see if there is input already waiting. if we are
+ // not able to display output fast enough to keep up, skip
+ // the display update until we catch up with input.
+ if (!readbuffer[0] && mysleep(0) == 0) {
+ // no input pending - so update output
+ refresh(FALSE);
+ show_status_line();
+ }
+#if ENABLE_FEATURE_VI_CRASHME
+ if (crashme > 0)
+ crash_test(); // test editor variables
+#endif
+ }
+ //-------------------------------------------------------------------
+
+ go_bottom_and_clear_to_eol();
+ cookmode();
+#undef cur_line
+}
+
+int vi_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int vi_main(int argc, char **argv)
+{
+ int c;
+
+ INIT_G();
+
+#if ENABLE_FEATURE_VI_UNDO
+ /* undo_stack_tail = NULL; - already is */
+#if ENABLE_FEATURE_VI_UNDO_QUEUE
+ undo_queue_state = UNDO_EMPTY;
+ /* undo_q = 0; - already is */
+#endif
+#endif
+
+#if ENABLE_FEATURE_VI_CRASHME
+ srand((long) getpid());
+#endif
+#ifdef NO_SUCH_APPLET_YET
+ // if we aren't "vi", we are "view"
+ if (ENABLE_FEATURE_VI_READONLY && applet_name[2]) {
+ SET_READONLY_MODE(readonly_mode);
+ }
+#endif
+
+ // autoindent is not default in vim 7.3
+ vi_setops = /*VI_AUTOINDENT |*/ VI_SHOWMATCH | VI_IGNORECASE;
+ // 1- process $HOME/.exrc file (not inplemented yet)
+ // 2- process EXINIT variable from environment
+ // 3- process command line args
+#if ENABLE_FEATURE_VI_COLON
+ {
+ char *p = getenv("EXINIT");
+ if (p && *p)
+ initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN);
+ }
+#endif
+ while ((c = getopt(argc, argv, "hCRH" IF_FEATURE_VI_COLON("c:"))) != -1) {
+ switch (c) {
+#if ENABLE_FEATURE_VI_CRASHME
+ case 'C':
+ crashme = 1;
+ break;
+#endif
+#if ENABLE_FEATURE_VI_READONLY
+ case 'R': // Read-only flag
+ SET_READONLY_MODE(readonly_mode);
+ break;
+#endif
+#if ENABLE_FEATURE_VI_COLON
+ case 'c': // cmd line vi command
+ if (*optarg)
+ initial_cmds[initial_cmds[0] != NULL] = xstrndup(optarg, MAX_INPUT_LEN);
+ break;
+#endif
+ case 'H':
+ show_help();
+ // fall through
+ default:
+ bb_show_usage();
+ return 1;
+ }
+ }
+
+ // The argv array can be used by the ":next" and ":rewind" commands
+ argv += optind;
+ argc -= optind;
+
+ //----- This is the main file handling loop --------------
+ save_argc = argc;
+ optind = 0;
+ // "Save cursor, use alternate screen buffer, clear screen"
+ write1(ESC"[?1049h");
+ while (1) {
+ edit_file(argv[optind]); // param might be NULL
+ if (++optind >= argc)
+ break;
+ }
+ // "Use normal screen buffer, restore cursor"
+ write1(ESC"[?1049l");
+ //-----------------------------------------------------------
+
+ return 0;
+}