vi: rearrange functions, no logic changes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2019-04-01 13:55:27 +02:00
parent c319310404
commit 24bd350aaa

View File

@ -483,7 +483,6 @@ struct globals {
} while (0) } while (0)
static void edit_file(char *); // edit one file
static void do_cmd(int); // execute a command static void do_cmd(int); // execute a command
static int next_tabstop(int); static int next_tabstop(int);
static void sync_cursor(char *, int *, int *); // synchronize the screen cursor to dot static void sync_cursor(char *, int *, int *); // synchronize the screen cursor to dot
@ -527,7 +526,6 @@ static uintptr_t text_hole_make(char *, int); // at "p", make a 'size' byte hole
#define yank_delete(a,b,c,d,e) yank_delete(a,b,c,d) #define yank_delete(a,b,c,d,e) yank_delete(a,b,c,d)
#endif #endif
static char *yank_delete(char *, char *, int, int, int); // yank text[] into register then delete 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 rawmode(void); // set "raw" mode on tty
static void cookmode(void); // return to "cooked" 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) // sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready)
@ -610,96 +608,44 @@ static void crash_test();
static int crashme = 0; static int crashme = 0;
#endif #endif
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"
#endif
);
}
static void write1(const char *out) static void write1(const char *out)
{ {
fputs(out, stdout); fputs(out, stdout);
} }
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;
}
/* read text from file or create an empty buf */ /* read text from file or create an empty buf */
/* will also update current_filename */ /* will also update current_filename */
static int init_text_buffer(char *fn) static int init_text_buffer(char *fn)
@ -748,153 +694,6 @@ static ALWAYS_INLINE int query_screen_dimensions(void)
} }
#endif #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 ------------------------------------- //----- The Colon commands -------------------------------------
#if ENABLE_FEATURE_VI_COLON #if ENABLE_FEATURE_VI_COLON
static char *get_one_address(char *p, int *addr) // get colon addr, if present static char *get_one_address(char *p, int *addr) // get colon addr, if present
@ -2589,39 +2388,6 @@ static char *yank_delete(char *start, char *stop, int dist, int yf, int undo)
return p; 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"
#endif
);
}
#if ENABLE_FEATURE_VI_DOT_CMD #if ENABLE_FEATURE_VI_DOT_CMD
static void start_new_cmd_q(char c) static void start_new_cmd_q(char c)
{ {
@ -4495,3 +4261,235 @@ static void crash_test()
} }
} }
#endif #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;
}