ex_docmd.c
资源名称:vim53src.zip [点击查看]
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:169k
源码类别:
编辑器/阅读器
开发平台:
DOS
- /* vi:set ts=8 sts=4 sw=4:
- *
- * VIM - Vi IMproved by Bram Moolenaar
- *
- * Do ":help uganda" in Vim to read copying and usage conditions.
- * Do ":help credits" in Vim to see a list of people who contributed.
- */
- /*
- * ex_docmd.c: functions for executing an Ex command line.
- */
- #include "vim.h"
- #define DO_DECLARE_EXCMD
- #include "ex_cmds.h" /* Declare the cmdnames struct. */
- #ifdef HAVE_FCNTL_H
- # include <fcntl.h> /* for chdir() */
- #endif
- static int quitmore = 0;
- static int ex_pressedreturn = FALSE;
- #ifdef WANT_EVAL
- /*
- * For conditional commands a stack is kept of nested conditionals.
- * When cs_idx < 0, there is no conditional command.
- */
- #define CSTACK_LEN 50
- struct condstack
- {
- char cs_flags[CSTACK_LEN]; /* CSF_ flags */
- int cs_line[CSTACK_LEN]; /* line number of ":while" line */
- int cs_idx; /* current entry, or -1 if none */
- int cs_whilelevel; /* number of nested ":while"s */
- char cs_had_while; /* just found ":while" */
- char cs_had_continue; /* just found ":continue" */
- char cs_had_endwhile; /* just found ":endwhile" */
- };
- #define CSF_TRUE 1 /* condition was TRUE */
- #define CSF_ACTIVE 2 /* current state is active */
- #define CSF_WHILE 4 /* is a ":while" */
- #endif
- #ifdef USER_COMMANDS
- typedef struct ucmd
- {
- char_u *uc_name; /* The command name */
- long uc_argt; /* The argument type */
- char_u *uc_rep; /* The command's replacement string */
- long uc_def; /* The default value for a range/count */
- int uc_compl; /* completion type */
- } UCMD;
- struct growarray ucmds = { 0, 0, sizeof(UCMD), 4, NULL };
- #define USER_CMD(i) (&((UCMD *)(ucmds.ga_data))[i])
- #endif
- #ifdef WANT_EVAL
- static void free_cmdlines __ARGS((struct growarray *gap));
- static char_u *do_one_cmd __ARGS((char_u **, int, struct condstack *, char_u *(*getline)(int, void *, int), void *cookie));
- #else
- static char_u *do_one_cmd __ARGS((char_u **, int, char_u *(*getline)(int, void *, int), void *cookie));
- #endif
- static int buf_write_all __ARGS((BUF *));
- static int do_write __ARGS((EXARG *eap));
- static char_u *getargcmd __ARGS((char_u **));
- static char_u *skip_cmd_arg __ARGS((char_u *p));
- #ifdef QUICKFIX
- static void do_make __ARGS((char_u *, char_u *));
- static char_u *get_mef_name __ARGS((int newname));
- static void do_cfile __ARGS((EXARG *eap));
- #endif
- static int do_arglist __ARGS((char_u *));
- static int rem_backslash __ARGS((char_u *str));
- static int check_readonly __ARGS((int *forceit));
- static int check_changed __ARGS((BUF *, int, int, int, int));
- #if defined(GUI_DIALOG) || defined(CON_DIALOG)
- static void dialog_changed __ARGS((BUF *buf, int checkall));
- #endif
- #if defined(USE_BROWSE) && (defined(GUI_DIALOG) || defined(CON_DIALOG))
- static void browse_save_fname __ARGS((BUF *buf));
- #endif
- static int check_more __ARGS((int, int));
- static linenr_t get_address __ARGS((char_u **, int skip));
- static char_u * invalid_range __ARGS((EXARG *eap));
- static void correct_range __ARGS((EXARG *eap));
- static void do_quit __ARGS((EXARG *eap));
- static void do_quit_all __ARGS((int forceit));
- static void do_close __ARGS((EXARG *eap));
- static void do_suspend __ARGS((int forceit));
- static void do_exit __ARGS((EXARG *eap));
- static void do_wqall __ARGS((EXARG *eap));
- static void do_print __ARGS((EXARG *eap));
- static void do_argfile __ARGS((EXARG *eap, int argn));
- static void do_next __ARGS((EXARG *eap));
- static void do_recover __ARGS((EXARG *eap));
- static void do_args __ARGS((EXARG *eap));
- static void do_wnext __ARGS((EXARG *eap));
- static void do_resize __ARGS((EXARG *eap));
- static void do_splitview __ARGS((EXARG *eap));
- static void do_exedit __ARGS((EXARG *eap, WIN *old_curwin));
- #ifdef USE_GUI
- static void do_gui __ARGS((EXARG *eap));
- #endif
- static void do_swapname __ARGS((void));
- static void do_read __ARGS((EXARG *eap));
- static void do_cd __ARGS((EXARG *eap));
- static void do_pwd __ARGS((void));
- static void do_sleep __ARGS((EXARG *eap));
- static void do_exmap __ARGS((EXARG *eap, int isabbrev));
- static void do_winsize __ARGS((char_u *arg));
- static void do_exops __ARGS((EXARG *eap));
- static void do_copymove __ARGS((EXARG *eap));
- static void do_exjoin __ARGS((EXARG *eap));
- static void do_exat __ARGS((EXARG *eap));
- static void do_redir __ARGS((EXARG *eap));
- static void close_redir __ARGS((void));
- static void do_mkrc __ARGS((EXARG *eap, char_u *defname));
- static FILE *open_exfile __ARGS((EXARG *eap, char *mode));
- static void do_setmark __ARGS((EXARG *eap));
- #ifdef EX_EXTRA
- static void do_normal __ARGS((EXARG *eap));
- #endif
- #ifdef FIND_IN_PATH
- static char_u *do_findpat __ARGS((EXARG *eap, int action));
- #endif
- static void do_ex_tag __ARGS((EXARG *eap, int dt));
- #ifdef WANT_EVAL
- static char_u *do_if __ARGS((EXARG *eap, struct condstack *cstack));
- static char_u *do_else __ARGS((EXARG *eap, struct condstack *cstack));
- static char_u *do_while __ARGS((EXARG *eap, struct condstack *cstack));
- static char_u *do_continue __ARGS((struct condstack *cstack));
- static char_u *do_break __ARGS((struct condstack *cstack));
- static char_u *do_endwhile __ARGS((struct condstack *cstack));
- static int has_while_cmd __ARGS((char_u *p));
- static int did_endif = FALSE; /* just had ":endif" */
- #endif
- static int makeopens __ARGS((FILE *fd));
- static int put_eol __ARGS((FILE *fd));
- static void cmd_source __ARGS((char_u *fname, int forceit));
- #ifdef USER_COMMANDS
- static int uc_add_command __ARGS((char_u *name, size_t name_len, char_u *rep, long argt, long def, int compl, int force));
- static void uc_list __ARGS((char_u *name, size_t name_len));
- static int uc_scan_attr __ARGS((char_u *attr, size_t len, long *argt, long *def, int *compl));
- static void do_command __ARGS((EXARG *eap));
- static void do_comclear __ARGS((void));
- static void do_delcommand __ARGS((EXARG *eap));
- static char_u *uc_split_args __ARGS((char_u *arg, size_t *lenp));
- static size_t uc_check_code __ARGS((char_u *code, size_t len, char_u *buf, UCMD *cmd, EXARG *eap, char_u **split_buf, size_t *split_len));
- static void do_ucmd __ARGS((UCMD *cmd, EXARG *eap));
- #endif
- #if defined(GUI_DIALOG) || defined(CON_DIALOG)
- static void dialog_msg __ARGS((char_u *buff, char *format, char_u *fname));
- #endif
- static void ex_behave __ARGS((char_u *arg));
- /*
- * Table used to quickly search for a command, based on its first character.
- */
- CMDIDX cmdidxs[27] =
- {
- CMD_append,
- CMD_buffer,
- CMD_change,
- CMD_delete,
- CMD_edit,
- CMD_file,
- CMD_global,
- CMD_help,
- CMD_insert,
- CMD_join,
- CMD_k,
- CMD_list,
- CMD_move,
- CMD_next,
- CMD_open,
- CMD_print,
- CMD_quit,
- CMD_read,
- CMD_substitute,
- CMD_t,
- CMD_undo,
- CMD_vglobal,
- CMD_write,
- CMD_xit,
- CMD_yank,
- CMD_z,
- CMD_Next
- };
- /*
- * do_exmode(): Repeatedly get commands for the "Ex" mode, until the ":vi"
- * command is given.
- */
- void
- do_exmode()
- {
- int save_msg_scroll;
- int prev_msg_row;
- linenr_t prev_line;
- save_msg_scroll = msg_scroll;
- ++RedrawingDisabled; /* don't redisplay the window */
- ++no_wait_return; /* don't wait for return */
- settmode(TMODE_COOK);
- State = NORMAL;
- exmode_active = TRUE;
- #ifdef USE_SNIFF
- want_sniff_request = 0; /* No K_SNIFF wanted */
- #endif
- MSG("Entering Ex mode. Type "visual" to get out.");
- while (exmode_active)
- {
- msg_scroll = TRUE;
- need_wait_return = FALSE;
- ex_pressedreturn = FALSE;
- ex_no_reprint = FALSE;
- prev_msg_row = msg_row;
- prev_line = curwin->w_cursor.lnum;
- #ifdef USE_SNIFF
- ProcessSniffRequests();
- #endif
- do_cmdline(NULL, getexmodeline, NULL, DOCMD_NOWAIT);
- lines_left = Rows - 1;
- if (prev_line != curwin->w_cursor.lnum && !ex_no_reprint)
- {
- if (ex_pressedreturn)
- {
- /* go up one line, to overwrite the ":<CR>" line, so the
- * output doensn't contain empty lines. */
- msg_row = prev_msg_row;
- if (prev_msg_row == Rows - 1)
- msg_row--;
- }
- msg_col = 0;
- print_line_no_prefix(curwin->w_cursor.lnum, FALSE);
- msg_clr_eos();
- }
- else if (ex_pressedreturn) /* must be at EOF */
- EMSG("At end-of-file");
- }
- settmode(TMODE_RAW);
- --RedrawingDisabled;
- --no_wait_return;
- update_screen(CLEAR);
- need_wait_return = FALSE;
- msg_scroll = save_msg_scroll;
- }
- /*
- * do_cmdline(): execute one Ex command line
- *
- * 1. Execute "cmdline" when it is not NULL.
- * If "cmdline" is NULL, or more lines are needed, getline() is used.
- * 2. Split up in parts separated with '|'.
- *
- * This function can be called recursively!
- *
- * flags:
- * DOCMD_VERBOSE - The command will be included in the error message.
- * DOCMD_NOWAIT - Don't call wait_return() and friends.
- * DOCMD_REPEAT - Repeat execution until getline() returns NULL.
- *
- * return FAIL if cmdline could not be executed, OK otherwise
- */
- int
- do_cmdline(cmdline, getline, cookie, flags)
- char_u *cmdline;
- char_u *(*getline) __ARGS((int, void *, int));
- void *cookie; /* argument for getline() */
- int flags;
- {
- char_u *next_cmdline; /* next cmd to execute */
- char_u *cmdline_copy = NULL; /* copy of cmd line */
- static int recursive = 0; /* recursive depth */
- int msg_didout_before_start = 0;
- int count = 0; /* line number count */
- int did_inc = FALSE; /* incremented RedrawingDisabled */
- int retval = OK;
- #ifdef USE_BROWSE
- int save_browse = browse;
- #endif
- #if defined(GUI_DIALOG) || defined(CON_DIALOG)
- int save_confirm = confirm;
- #endif
- #ifdef WANT_EVAL
- struct condstack cstack; /* conditional stack */
- struct growarray lines_ga; /* keep lines for ":while" */
- int current_line = 0; /* active line in lines_ga */
- #endif
- #ifdef WANT_EVAL
- cstack.cs_idx = -1;
- cstack.cs_whilelevel = 0;
- cstack.cs_had_while = FALSE;
- cstack.cs_had_endwhile = FALSE;
- cstack.cs_had_continue = FALSE;
- ga_init2(&lines_ga, (int)sizeof(char_u *), 10);
- #endif
- /*
- * Reset browse and confirm. They are restored when returning, for
- * recursive calls.
- */
- #ifdef USE_BROWSE
- browse = FALSE;
- #endif
- #if defined(GUI_DIALOG) || defined(CON_DIALOG)
- confirm = FALSE;
- #endif
- /*
- * "did_emsg" will be set to TRUE when emsg() is used, in which case we
- * cancel the whole command line, and any if/endif while/endwhile loop.
- */
- did_emsg = FALSE;
- /*
- * KeyTyped is only set when calling vgetc(). Reset it here when not
- * calling vgetc() (sourced command lines).
- */
- if (getline != getexline)
- KeyTyped = FALSE;
- /*
- * Continue executing command lines:
- * - when inside an ":if" or ":while"
- * - for multiple commands on one line, separated with '|'
- * - when repeating until there are no more lines (for ":source")
- */
- next_cmdline = cmdline;
- do
- {
- /* stop skipping cmds for an error msg after all endifs and endwhiles */
- if (next_cmdline == NULL
- #ifdef WANT_EVAL
- && cstack.cs_idx < 0
- #endif
- )
- did_emsg = FALSE;
- /*
- * 1. If repeating a line with ":while", get a line from lines_ga.
- * 2. If no line given: Get an allocated line with getline().
- * 3. If a line is given: Make a copy, so we can mess with it.
- */
- #ifdef WANT_EVAL
- /* 1. If repeating, get a previous line from lines_ga. */
- if (cstack.cs_whilelevel && current_line < lines_ga.ga_len)
- {
- /* Each '|' separated command is stored separately in lines_ga, to
- * be able to jump to it. Don't use next_cmdline now. */
- vim_free(cmdline_copy);
- cmdline_copy = NULL;
- /* Check if a function has returned or aborted */
- if (getline == get_func_line && func_has_ended(cookie))
- {
- retval = FAIL;
- break;
- }
- next_cmdline = ((char_u **)(lines_ga.ga_data))[current_line];
- }
- #endif
- /* 2. If no line given, get an allocated line with getline(). */
- if (next_cmdline == NULL)
- {
- /*
- * Need to set msg_didout for the first line after an ":if",
- * otherwise the ":if" will be overwritten.
- */
- if (count == 1 && getline == getexline)
- msg_didout = TRUE;
- if (getline == NULL || (next_cmdline = getline(':', cookie,
- #ifdef WANT_EVAL
- cstack.cs_idx < 0 ? 0 : (cstack.cs_idx + 1) * 2
- #else
- 0
- #endif
- )) == NULL)
- {
- /* don't call wait_return for aborted command line */
- if (KeyTyped)
- need_wait_return = FALSE;
- retval = FAIL;
- break;
- }
- }
- /* 3. Make a copy of the command so we can mess with it. */
- else if (cmdline_copy == NULL)
- {
- next_cmdline = vim_strsave(next_cmdline);
- if (next_cmdline == NULL)
- {
- retval = FAIL;
- break;
- }
- }
- cmdline_copy = next_cmdline;
- #ifdef WANT_EVAL
- /*
- * Save the current line when inside a ":while", and when the command
- * looks like a ":while", because we may need it later.
- * When there is a '|' and another command, it is stored separately,
- * because we need to be able to jump back to it from an :endwhile.
- */
- if ( current_line == lines_ga.ga_len
- && (cstack.cs_whilelevel || has_while_cmd(next_cmdline))
- && ga_grow(&lines_ga, 1) == OK)
- {
- ((char_u **)(lines_ga.ga_data))[current_line] =
- vim_strsave(next_cmdline);
- ++lines_ga.ga_len;
- --lines_ga.ga_room;
- }
- did_endif = FALSE;
- #endif
- if (count++ == 0)
- {
- /*
- * All output from the commands is put below each other, without
- * waiting for a return. Don't do this when executing commands
- * from a script or when being called recursive (e.g. for ":e
- * +command file").
- */
- if (!(flags & DOCMD_NOWAIT) && !recursive)
- {
- msg_didout_before_start = msg_didout;
- msg_didany = FALSE; /* no output yet */
- msg_start();
- msg_scroll = TRUE; /* put messages below each other */
- ++no_wait_return; /* dont wait for return until finished */
- ++RedrawingDisabled;
- did_inc = TRUE;
- }
- }
- /*
- * 2. Execute one '|' separated command.
- * do_one_cmd() will return NULL if there is no trailing '|'.
- * "cmdline_copy" can change, e.g. for '%' and '#' expansion.
- */
- ++recursive;
- next_cmdline = do_one_cmd(&cmdline_copy, flags & DOCMD_VERBOSE,
- #ifdef WANT_EVAL
- &cstack,
- #endif
- getline, cookie);
- --recursive;
- if (next_cmdline == NULL)
- {
- vim_free(cmdline_copy);
- cmdline_copy = NULL;
- /*
- * If the command was typed, remember it for the ':' register.
- * Do this AFTER executing the command to make :@: work.
- */
- if (getline == getexline && new_last_cmdline != NULL)
- {
- vim_free(last_cmdline);
- last_cmdline = new_last_cmdline;
- new_last_cmdline = NULL;
- }
- }
- else
- {
- /* need to copy the command after the '|' to cmdline_copy, for the
- * next do_one_cmd() */
- mch_memmove(cmdline_copy, next_cmdline, STRLEN(next_cmdline) + 1);
- next_cmdline = cmdline_copy;
- }
- #ifdef WANT_EVAL
- /* reset did_emsg for a function that is not aborted by an error */
- if (did_emsg && getline == get_func_line && !func_has_abort(cookie))
- did_emsg = FALSE;
- if (cstack.cs_whilelevel)
- {
- ++current_line;
- /*
- * An ":endwhile" and ":continue" is handled here.
- * If we were executing commands, jump back to the ":while".
- * If we were not executing commands, decrement whilelevel.
- */
- if (cstack.cs_had_endwhile || cstack.cs_had_continue)
- {
- if (cstack.cs_had_endwhile)
- cstack.cs_had_endwhile = FALSE;
- else
- cstack.cs_had_continue = FALSE;
- /* jump back to the matching ":while"? */
- if (!did_emsg && cstack.cs_idx >= 0
- && (cstack.cs_flags[cstack.cs_idx] & CSF_ACTIVE))
- {
- current_line = cstack.cs_line[cstack.cs_idx];
- cstack.cs_had_while = TRUE; /* note we jumped there */
- line_breakcheck(); /* check if CTRL-C typed */
- }
- else /* can only get here with ":endwhile" */
- {
- --cstack.cs_whilelevel;
- if (cstack.cs_idx >= 0)
- --cstack.cs_idx;
- }
- }
- /*
- * For a ":while" we need to remember the line number.
- */
- else if (cstack.cs_had_while)
- {
- cstack.cs_had_while = FALSE;
- cstack.cs_line[cstack.cs_idx] = current_line - 1;
- }
- }
- /*
- * When not inside a ":while", clear remembered lines.
- */
- if (!cstack.cs_whilelevel)
- {
- free_cmdlines(&lines_ga);
- current_line = 0;
- }
- #endif /* WANT_EVAL */
- }
- /*
- * Continue executing command lines when:
- * - no CTRL-C typed
- * - didn't get an error message or lines are not typed
- * - there is a command after '|', inside a :if or :while, or looping for
- * ":source" command.
- */
- while (!got_int
- && !(did_emsg && (getline == getexmodeline || getline == getexline))
- && (next_cmdline != NULL
- #ifdef WANT_EVAL
- || cstack.cs_idx >= 0
- #endif
- || (flags & DOCMD_REPEAT)));
- vim_free(cmdline_copy);
- #ifdef WANT_EVAL
- free_cmdlines(&lines_ga);
- ga_clear(&lines_ga);
- #endif
- /*
- * If there was too much output to fit on the command line, ask the user to
- * hit return before redrawing the screen. With the ":global" command we do
- * this only once after the command is finished.
- */
- if (did_inc)
- {
- --RedrawingDisabled;
- --no_wait_return;
- msg_scroll = FALSE;
- /*
- * When just finished an ":if"-":else" which was typed, no need to
- * wait for hit-return. Also for an error situation.
- */
- if (retval == FAIL
- #ifdef WANT_EVAL
- || (did_endif && KeyTyped && !did_emsg)
- #endif
- )
- {
- need_wait_return = FALSE;
- msg_didany = FALSE; /* don't wait when restarting edit */
- redraw_later(NOT_VALID);
- }
- else if ((need_wait_return || (msg_check() && !dont_wait_return)))
- {
- /*
- * The msg_start() above clears msg_didout. The wait_return we do
- * here should not overwrite the command that may be shown before
- * doing that.
- */
- msg_didout = msg_didout_before_start;
- wait_return(FALSE);
- }
- }
- #ifdef USE_BROWSE
- browse = save_browse;
- #endif
- #if defined(GUI_DIALOG) || defined(CON_DIALOG)
- confirm = save_confirm;
- #endif
- return retval;
- }
- #ifdef WANT_EVAL
- static void
- free_cmdlines(gap)
- struct growarray *gap;
- {
- while (gap->ga_len)
- {
- vim_free(((char_u **)(gap->ga_data))[gap->ga_len - 1]);
- --gap->ga_len;
- ++gap->ga_room;
- }
- }
- #endif
- /*
- * Execute one Ex command.
- *
- * If 'sourcing' is TRUE, the command will be included in the error message.
- *
- * 2. skip comment lines and leading space
- * 3. parse range
- * 4. parse command
- * 5. parse arguments
- * 6. switch on command name
- *
- * Note: "getline" can be NULL.
- *
- * This function may be called recursively!
- */
- static char_u *
- do_one_cmd(cmdlinep, sourcing,
- #ifdef WANT_EVAL
- cstack,
- #endif
- getline, cookie)
- char_u **cmdlinep;
- int sourcing;
- #ifdef WANT_EVAL
- struct condstack *cstack;
- #endif
- char_u *(*getline) __ARGS((int, void *, int));
- void *cookie; /* argument for getline() */
- {
- char_u *p;
- int i;
- linenr_t lnum;
- long n;
- char_u *errormsg = NULL; /* error message */
- EXARG ea; /* Ex command arguments */
- vim_memset(&ea, 0, sizeof(ea));
- ea.line1 = 1;
- ea.line2 = 1;
- /* when not editing the last file :q has to be typed twice */
- if (quitmore)
- --quitmore;
- /*
- * 2. skip comment lines and leading space and colons
- */
- for (ea.cmd = *cmdlinep; *ea.cmd == ' ' || *ea.cmd == 't'
- || *ea.cmd == ':'; ea.cmd++)
- ;
- /* in ex mode, an empty line works like :+ */
- if (*ea.cmd == NUL && exmode_active && getline == getexmodeline)
- {
- ea.cmd = (char_u *)"+";
- ex_pressedreturn = TRUE;
- }
- if (*ea.cmd == '"' || *ea.cmd == NUL) /* ignore comment and empty lines */
- goto doend;
- #ifdef WANT_EVAL
- ea.skip = did_emsg || (cstack->cs_idx >= 0
- && !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE));
- #else
- ea.skip = FALSE;
- #endif
- /*
- * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
- *
- * where 'addr' is:
- *
- * % (entire file)
- * $ [+-NUM]
- * 'x [+-NUM] (where x denotes a currently defined mark)
- * . [+-NUM]
- * [+-NUM]..
- * NUM
- *
- * The ea.cmd pointer is updated to point to the first character following the
- * range spec. If an initial address is found, but no second, the upper bound
- * is equal to the lower.
- */
- /* repeat for all ',' or ';' separated addresses */
- for (;;)
- {
- ea.line1 = ea.line2;
- ea.line2 = curwin->w_cursor.lnum; /* default is current line number */
- ea.cmd = skipwhite(ea.cmd);
- lnum = get_address(&ea.cmd, ea.skip);
- if (ea.cmd == NULL) /* error detected */
- goto doend;
- if (lnum == MAXLNUM)
- {
- if (*ea.cmd == '%') /* '%' - all lines */
- {
- ++ea.cmd;
- ea.line1 = 1;
- ea.line2 = curbuf->b_ml.ml_line_count;
- ++ea.addr_count;
- }
- /* '*' - visual area */
- else if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL)
- {
- FPOS *fp;
- ++ea.cmd;
- #ifdef WANT_EVAL
- if (!ea.skip)
- #endif
- {
- fp = getmark('<', FALSE);
- if (check_mark(fp) == FAIL)
- goto doend;
- ea.line1 = fp->lnum;
- fp = getmark('>', FALSE);
- if (check_mark(fp) == FAIL)
- goto doend;
- ea.line2 = fp->lnum;
- ++ea.addr_count;
- }
- }
- }
- else
- ea.line2 = lnum;
- ea.addr_count++;
- if (*ea.cmd == ';')
- {
- #ifdef WANT_EVAL
- if (!ea.skip)
- #endif
- curwin->w_cursor.lnum = ea.line2;
- }
- else if (*ea.cmd != ',')
- break;
- ++ea.cmd;
- }
- /* One address given: set start and end lines */
- if (ea.addr_count == 1)
- {
- ea.line1 = ea.line2;
- /* ... but only implicit: really no address given */
- if (lnum == MAXLNUM)
- ea.addr_count = 0;
- }
- /* Don't leave the cursor on an illegal line (caused by ';') */
- check_cursor_lnum();
- /*
- * 4. parse command
- */
- /*
- * Skip ':' and any white space
- */
- ea.cmd = skipwhite(ea.cmd);
- while (*ea.cmd == ':')
- ea.cmd = skipwhite(ea.cmd + 1);
- /*
- * If we got a line, but no command, then go to the line.
- * If we find a '|' or 'n' we set ea.nextcmd.
- */
- if (*ea.cmd == NUL || *ea.cmd == '"' ||
- (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL)
- {
- /*
- * strange vi behaviour:
- * ":3" jumps to line 3
- * ":3|..." prints line 3
- * ":|" prints current line
- */
- #ifdef WANT_EVAL
- if (ea.skip) /* skip this if inside :if */
- goto doend;
- #endif
- if (*ea.cmd == '|')
- {
- ea.cmdidx = CMD_print;
- ea.argt = RANGE+COUNT+TRLBAR;
- if ((errormsg = invalid_range(&ea)) == NULL)
- {
- correct_range(&ea);
- do_print(&ea);
- }
- }
- else if (ea.addr_count != 0)
- {
- if (ea.line2 == 0)
- curwin->w_cursor.lnum = 1;
- else if (ea.line2 > curbuf->b_ml.ml_line_count)
- curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
- else
- curwin->w_cursor.lnum = ea.line2;
- beginline(BL_SOL | BL_FIX);
- }
- goto doend;
- }
- /*
- * Isolate the command and search for it in the command table.
- * Exeptions:
- * - the 'k' command can directly be followed by any character.
- * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
- * but :sre[wind] is another command, as is :sim[alt].
- */
- if (*ea.cmd == 'k')
- {
- ea.cmdidx = CMD_k;
- p = ea.cmd + 1;
- }
- else if (ea.cmd[0] == 's'
- && (ea.cmd[1] == 'c'
- || ea.cmd[1] == 'g'
- || (ea.cmd[1] == 'i' && ea.cmd[2] != 'm')
- || ea.cmd[1] == 'I'
- || (ea.cmd[1] == 'r' && ea.cmd[2] != 'e')))
- {
- ea.cmdidx = CMD_substitute;
- p = ea.cmd + 1;
- }
- else
- {
- p = ea.cmd;
- while (isalpha(*p))
- ++p;
- /* check for non-alpha command */
- if (p == ea.cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL)
- ++p;
- i = (int)(p - ea.cmd);
- if (*ea.cmd >= 'a' && *ea.cmd <= 'z')
- ea.cmdidx = cmdidxs[*ea.cmd - 'a'];
- else
- ea.cmdidx = cmdidxs[26];
- for ( ; (int)ea.cmdidx < (int)CMD_SIZE;
- ea.cmdidx = (CMDIDX)((int)ea.cmdidx + 1))
- if (STRNCMP(cmdnames[(int)ea.cmdidx].cmd_name, (char *)ea.cmd,
- (size_t)i) == 0)
- break;
- #ifdef USER_COMMANDS
- /* Look for a user defined command as a last resort */
- if (ea.cmdidx == CMD_SIZE)
- {
- UCMD *cmd = USER_CMD(0);
- int j;
- int found = FALSE;
- for (j = 0; j < ucmds.ga_len; ++j, ++cmd)
- {
- if (STRNCMP(cmd->uc_name, (char *)ea.cmd, (size_t)i) == 0)
- {
- if (found)
- {
- errormsg = (char_u *)"Ambiguous use of user-defined command";
- goto doend;
- }
- found = TRUE;
- ea.cmdidx = CMD_USER;
- ea.argt = cmd->uc_argt;
- ea.useridx = j;
- /* Do not search for further abbreviations
- * if this is an exact match
- */
- if ((size_t)i == STRLEN(cmd->uc_name))
- break;
- }
- }
- }
- #endif
- if (i == 0 || ea.cmdidx == CMD_SIZE)
- {
- #ifdef WANT_EVAL
- if (!ea.skip)
- #endif
- {
- STRCPY(IObuff, "Not an editor command");
- if (!sourcing)
- {
- STRCAT(IObuff, ": ");
- STRNCAT(IObuff, *cmdlinep, 40);
- }
- errormsg = IObuff;
- }
- goto doend;
- }
- }
- if (*p == '!' && ea.cmdidx != CMD_substitute) /* forced commands */
- {
- ++p;
- ea.forceit = TRUE;
- }
- else
- ea.forceit = FALSE;
- /*
- * 5. parse arguments
- */
- #ifdef USER_COMMANDS
- if (ea.cmdidx != CMD_USER)
- #endif
- ea.argt = cmdnames[(int)ea.cmdidx].cmd_argt;
- if (!(ea.argt & RANGE) && ea.addr_count) /* no range allowed */
- {
- errormsg = e_norange;
- goto doend;
- }
- if (!(ea.argt & BANG) && ea.forceit) /* no <!> allowed */
- {
- errormsg = e_nobang;
- if (ea.cmdidx == CMD_help)
- errormsg = (char_u *)"Don't panic!";
- goto doend;
- }
- /*
- * If the range is backwards, ask for confirmation and, if given, swap
- * ea.line1 & ea.line2 so it's forwards again.
- * When global command is busy, don't ask, will fail below.
- */
- if (!global_busy && ea.line1 > ea.line2)
- {
- if (sourcing)
- {
- errormsg = (char_u *)"Backwards range given";
- goto doend;
- }
- else if (ask_yesno((char_u *)
- "Backwards range given, OK to swap", FALSE) != 'y')
- goto doend;
- lnum = ea.line1;
- ea.line1 = ea.line2;
- ea.line2 = lnum;
- }
- /*
- * don't complain about the range if it is not used
- * (could happen if line_count is accidently set to 0)
- */
- if (!ea.skip && (errormsg = invalid_range(&ea)) != NULL)
- goto doend;
- if ((ea.argt & NOTADR) && ea.addr_count == 0) /* default is 1, not cursor */
- ea.line2 = 1;
- correct_range(&ea);
- #ifdef QUICKFIX
- /*
- * For the :make command we insert the 'makeprg' option here,
- * so things like % get expanded.
- */
- if (ea.cmdidx == CMD_make || ea.cmdidx == CMD_grep)
- {
- char_u *new_cmdline;
- char_u *program;
- program = (ea.cmdidx == CMD_grep) ? p_gp : p_mp;
- new_cmdline = alloc((int)(STRLEN(program) + STRLEN(p) + 2));
- if (new_cmdline == NULL)
- goto doend; /* out of memory */
- STRCPY(new_cmdline, program);
- STRCAT(new_cmdline, " ");
- STRCAT(new_cmdline, p);
- msg_make(p);
- /* 'ea.cmd' is not set here, because it is not used at CMD_make */
- vim_free(*cmdlinep);
- *cmdlinep = new_cmdline;
- p = new_cmdline;
- }
- #endif
- /*
- * Skip to start of argument.
- * Don't do this for the ":!" command, because ":!! -l" needs the space.
- */
- if (ea.cmdidx == CMD_bang)
- ea.arg = p;
- else
- ea.arg = skipwhite(p);
- if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update)
- {
- if (*ea.arg == '>') /* append */
- {
- if (*++ea.arg != '>') /* typed wrong */
- {
- errormsg = (char_u *)"Use w or w>>";
- goto doend;
- }
- ea.arg = skipwhite(ea.arg + 1);
- ea.append = TRUE;
- }
- else if (*ea.arg == '!' && ea.cmdidx == CMD_write) /* :w !filter */
- {
- ++ea.arg;
- ea.usefilter = TRUE;
- }
- }
- if (ea.cmdidx == CMD_read)
- {
- if (ea.forceit)
- {
- ea.usefilter = TRUE; /* :r! filter if ea.forceit */
- ea.forceit = FALSE;
- }
- else if (*ea.arg == '!') /* :r !filter */
- {
- ++ea.arg;
- ea.usefilter = TRUE;
- }
- }
- if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift)
- {
- ea.amount = 1;
- while (*ea.arg == *ea.cmd) /* count number of '>' or '<' */
- {
- ++ea.arg;
- ++ea.amount;
- }
- ea.arg = skipwhite(ea.arg);
- }
- /*
- * Check for "+command" argument, before checking for next command.
- * Don't do this for ":read !cmd" and ":write !cmd".
- */
- if ((ea.argt & EDITCMD) && !ea.usefilter)
- ea.do_ecmd_cmd = getargcmd(&ea.arg);
- /*
- * Check for '|' to separate commands and '"' to start comments.
- * Don't do this for ":read !cmd" and ":write !cmd".
- */
- if ((ea.argt & TRLBAR) && !ea.usefilter)
- separate_nextcmd(&ea);
- /*
- * Check for <newline> to end a shell command.
- * Also do this for ":read !cmd" and ":write !cmd".
- */
- else if (ea.cmdidx == CMD_bang || ea.usefilter)
- {
- for (p = ea.arg; *p; ++p)
- {
- if (*p == '\' && p[1])
- ++p;
- else if (*p == 'n')
- {
- ea.nextcmd = p + 1;
- *p = NUL;
- break;
- }
- }
- }
- if ((ea.argt & DFLALL) && ea.addr_count == 0)
- {
- ea.line1 = 1;
- ea.line2 = curbuf->b_ml.ml_line_count;
- }
- /* accept numbered register only when no count allowed (:put) */
- if ( (ea.argt & REGSTR)
- && *ea.arg != NUL
- #ifdef USER_COMMANDS
- && valid_yank_reg(*ea.arg, (ea.cmdidx != CMD_put
- && ea.cmdidx != CMD_USER))
- /* Do not allow register = for user commands */
- && (ea.cmdidx != CMD_USER || *ea.arg != '=')
- #else
- && valid_yank_reg(*ea.arg, ea.cmdidx != CMD_put)
- #endif
- && !((ea.argt & COUNT) && isdigit(*ea.arg)))
- {
- ea.regname = *ea.arg++;
- #ifdef WANT_EVAL
- /* for '=' register: accept the rest of the line as an expression */
- if (ea.arg[-1] == '=' && ea.arg[0] != NUL)
- {
- set_expr_line(vim_strsave(ea.arg));
- ea.arg += STRLEN(ea.arg);
- }
- #endif
- ea.arg = skipwhite(ea.arg);
- }
- /*
- * Check for a count. When accepting a BUFNAME, don't use "123foo" as a
- * count, it's a buffer name.
- */
- if ((ea.argt & COUNT) && isdigit(*ea.arg)
- && (!(ea.argt & BUFNAME) || *(p = skipdigits(ea.arg)) == NUL
- || vim_iswhite(*p)))
- {
- n = getdigits(&ea.arg);
- ea.arg = skipwhite(ea.arg);
- if (n <= 0)
- {
- errormsg = e_zerocount;
- goto doend;
- }
- if (ea.argt & NOTADR) /* e.g. :buffer 2, :sleep 3 */
- {
- ea.line2 = n;
- if (ea.addr_count == 0)
- ea.addr_count = 1;
- }
- else
- {
- ea.line1 = ea.line2;
- ea.line2 += n - 1;
- ++ea.addr_count;
- /*
- * Be vi compatible: no error message for out of range.
- */
- if (ea.line2 > curbuf->b_ml.ml_line_count)
- ea.line2 = curbuf->b_ml.ml_line_count;
- }
- }
- /* no arguments allowed */
- if (!(ea.argt & EXTRA) && *ea.arg != NUL &&
- vim_strchr((char_u *)"|"", *ea.arg) == NULL)
- {
- errormsg = e_trailing;
- goto doend;
- }
- if ((ea.argt & NEEDARG) && *ea.arg == NUL)
- {
- errormsg = e_argreq;
- goto doend;
- }
- if (ea.argt & XFILE)
- {
- if (expand_filename(&ea, cmdlinep, &errormsg) == FAIL)
- goto doend;
- }
- #ifdef WANT_EVAL
- /*
- * Skip the command when it's not going to be executed.
- * The commands like :if, :endif, etc. always need to be executed.
- * Also make an exception for commands that handle a trailing command
- * themselves.
- */
- if (ea.skip)
- {
- switch (ea.cmdidx)
- {
- /* commands that need evaluation */
- case CMD_while:
- case CMD_endwhile:
- case CMD_if:
- case CMD_elseif:
- case CMD_else:
- case CMD_endif:
- case CMD_function:
- break;
- /* commands that handle '|' themselves */
- case CMD_call:
- case CMD_djump:
- case CMD_dlist:
- case CMD_dsearch:
- case CMD_dsplit:
- case CMD_echo:
- case CMD_echon:
- case CMD_execute:
- case CMD_help:
- case CMD_ijump:
- case CMD_ilist:
- case CMD_isearch:
- case CMD_isplit:
- case CMD_let:
- case CMD_return:
- case CMD_substitute:
- case CMD_smagic:
- case CMD_snomagic:
- case CMD_syntax:
- case CMD_and:
- case CMD_tilde:
- break;
- default: goto doend;
- }
- }
- #endif
- /*
- * Accept buffer name. Cannot be used at the same time with a buffer
- * number.
- */
- if ((ea.argt & BUFNAME) && *ea.arg && ea.addr_count == 0)
- {
- /*
- * :bdelete and :bunload take several arguments, separated by spaces:
- * find next space (skipping over escaped characters).
- * The others take one argument: ignore trailing spaces.
- */
- if (ea.cmdidx == CMD_bdelete || ea.cmdidx == CMD_bunload)
- p = skiptowhite_esc(ea.arg);
- else
- {
- p = ea.arg + STRLEN(ea.arg);
- while (p > ea.arg && vim_iswhite(p[-1]))
- --p;
- }
- ea.line2 = buflist_findpat(ea.arg, p);
- if (ea.line2 < 0) /* failed */
- goto doend;
- ea.addr_count = 1;
- ea.arg = skipwhite(p);
- }
- /*
- * 6. switch on command name
- *
- * The "ea" structure holds the arguments that can be used.
- */
- switch (ea.cmdidx)
- {
- case CMD_quit:
- do_quit(&ea);
- break;
- case CMD_qall:
- do_quit_all(ea.forceit);
- break;
- case CMD_close:
- do_close(&ea);
- break;
- case CMD_hide:
- #ifdef USE_GUI
- need_mouse_correct = TRUE;
- #endif
- close_window(curwin, FALSE); /* don't free buffer */
- break;
- case CMD_only:
- #ifdef USE_GUI
- need_mouse_correct = TRUE;
- #endif
- close_others(TRUE, ea.forceit);
- break;
- case CMD_stop:
- case CMD_suspend:
- do_suspend(ea.forceit);
- break;
- case CMD_exit:
- case CMD_xit:
- case CMD_wq:
- do_exit(&ea);
- break;
- case CMD_xall:
- case CMD_wqall:
- exiting = TRUE;
- /* FALLTHROUGH */
- case CMD_wall:
- do_wqall(&ea);
- break;
- case CMD_preserve:
- ml_preserve(curbuf, TRUE);
- break;
- case CMD_recover:
- do_recover(&ea);
- break;
- case CMD_args:
- do_args(&ea);
- break;
- case CMD_wnext:
- case CMD_wNext:
- case CMD_wprevious:
- do_wnext(&ea);
- break;
- case CMD_next:
- case CMD_snext:
- do_next(&ea);
- break;
- case CMD_previous:
- case CMD_sprevious:
- case CMD_Next:
- case CMD_sNext:
- do_argfile(&ea, curwin->w_arg_idx - (int)ea.line2);
- break;
- case CMD_rewind:
- case CMD_srewind:
- do_argfile(&ea, 0);
- break;
- case CMD_last:
- case CMD_slast:
- do_argfile(&ea, arg_file_count - 1);
- break;
- case CMD_argument:
- case CMD_sargument:
- if (ea.addr_count)
- i = ea.line2 - 1;
- else
- i = curwin->w_arg_idx;
- do_argfile(&ea, i);
- break;
- case CMD_all:
- case CMD_sall:
- if (ea.addr_count == 0)
- ea.line2 = 9999;
- do_arg_all((int)ea.line2, ea.forceit);
- break;
- case CMD_buffer: /* :[N]buffer [N] to buffer N */
- case CMD_sbuffer: /* :[N]sbuffer [N] to buffer N */
- if (*ea.arg)
- errormsg = e_trailing;
- else
- {
- if (ea.addr_count == 0) /* default is current buffer */
- (void)do_buffer(*ea.cmd == 's' ? DOBUF_SPLIT
- : DOBUF_GOTO,
- DOBUF_CURRENT, FORWARD, 0, ea.forceit);
- else
- (void)do_buffer(*ea.cmd == 's' ? DOBUF_SPLIT
- : DOBUF_GOTO,
- DOBUF_FIRST, FORWARD, (int)ea.line2, ea.forceit);
- }
- break;
- case CMD_bmodified: /* :[N]bmod [N] to next mod. buffer */
- case CMD_sbmodified: /* :[N]sbmod [N] to next mod. buffer */
- (void)do_buffer(*ea.cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
- DOBUF_MOD, FORWARD, (int)ea.line2, ea.forceit);
- break;
- case CMD_bnext: /* :[N]bnext [N] to next buffer */
- case CMD_sbnext: /* :[N]sbnext [N] to next buffer */
- (void)do_buffer(*ea.cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
- DOBUF_CURRENT, FORWARD, (int)ea.line2, ea.forceit);
- break;
- case CMD_bNext: /* :[N]bNext [N] to previous buffer */
- case CMD_bprevious: /* :[N]bprevious [N] to previous buffer */
- case CMD_sbNext: /* :[N]sbNext [N] to previous buffer */
- case CMD_sbprevious: /* :[N]sbprevious [N] to previous buffer */
- (void)do_buffer(*ea.cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
- DOBUF_CURRENT, BACKWARD, (int)ea.line2, ea.forceit);
- break;
- case CMD_brewind: /* :brewind to first buffer */
- case CMD_sbrewind: /* :sbrewind to first buffer */
- (void)do_buffer(*ea.cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
- DOBUF_FIRST, FORWARD, 0, ea.forceit);
- break;
- case CMD_blast: /* :blast to last buffer */
- case CMD_sblast: /* :sblast to last buffer */
- (void)do_buffer(*ea.cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
- DOBUF_LAST, FORWARD, 0, ea.forceit);
- break;
- case CMD_bunload: /* :[N]bunload[!] [N] [bufname] unload buffer */
- case CMD_bdelete: /* :[N]bdelete[!] [N] [bufname] delete buffer */
- errormsg = do_bufdel(ea.cmdidx == CMD_bdelete ? DOBUF_DEL
- : DOBUF_UNLOAD,
- ea.arg, ea.addr_count, (int)ea.line1,
- (int)ea.line2, ea.forceit);
- break;
- case CMD_unhide:
- case CMD_sunhide:
- if (ea.addr_count == 0)
- ea.line2 = 9999;
- (void)do_buffer_all((int)ea.line2, FALSE);
- break;
- case CMD_ball:
- case CMD_sball:
- if (ea.addr_count == 0)
- ea.line2 = 9999;
- (void)do_buffer_all((int)ea.line2, TRUE);
- break;
- case CMD_buffers:
- case CMD_files:
- case CMD_ls:
- buflist_list();
- break;
- case CMD_update:
- if (curbuf_changed())
- (void)do_write(&ea);
- break;
- case CMD_write:
- if (ea.usefilter) /* input lines to shell command */
- do_bang(1, ea.line1, ea.line2, FALSE, ea.arg, TRUE, FALSE);
- else
- (void)do_write(&ea);
- break;
- /*
- * set screen mode
- * if no argument given, just get the screen size and redraw
- */
- case CMD_mode:
- if (*ea.arg == NUL || mch_screenmode(ea.arg) != FAIL)
- set_winsize(0, 0, FALSE);
- break;
- case CMD_resize:
- do_resize(&ea);
- break;
- case CMD_sview:
- case CMD_split:
- case CMD_new:
- do_splitview(&ea);
- break;
- case CMD_edit:
- case CMD_ex:
- case CMD_visual:
- case CMD_view:
- case CMD_badd:
- do_exedit(&ea, NULL);
- break;
- #ifdef USE_GUI
- /*
- * Change from the terminal version to the GUI version. File names
- * may be given to redefine the args list -- webb
- */
- case CMD_gvim:
- case CMD_gui:
- do_gui(&ea);
- break;
- #endif
- #ifdef USE_GUI_WIN32
- case CMD_tearoff:
- gui_make_tearoff(ea.arg);
- break;
- #endif
- case CMD_behave:
- ex_behave(ea.arg);
- break;
- case CMD_browse:
- #ifdef USE_BROWSE
- /* don't browse in an xterm! */
- if (gui.in_use)
- browse = TRUE;
- #endif
- ea.nextcmd = ea.arg;
- break;
- #ifdef USE_GUI_WIN32
- case CMD_simalt:
- gui_simulate_alt_key(ea.arg);
- break;
- case CMD_promptfind:
- gui_mch_find_dialog(ea.arg);
- break;
- case CMD_promptrepl:
- gui_mch_replace_dialog(ea.arg);
- break;
- #endif
- case CMD_confirm:
- #if defined(GUI_DIALOG) || defined(CON_DIALOG)
- confirm = TRUE;
- #endif
- ea.nextcmd = ea.arg;
- break;
- case CMD_file:
- do_file(ea.arg, ea.forceit);
- break;
- case CMD_swapname:
- do_swapname();
- break;
- case CMD_read:
- do_read(&ea);
- break;
- case CMD_cd:
- case CMD_chdir:
- do_cd(&ea);
- break;
- case CMD_pwd:
- do_pwd();
- break;
- case CMD_equal:
- smsg((char_u *)"line %ld", (long)ea.line2);
- break;
- case CMD_list:
- i = curwin->w_p_list;
- curwin->w_p_list = 1;
- do_print(&ea);
- curwin->w_p_list = i;
- break;
- case CMD_number:
- case CMD_pound: /* :# */
- case CMD_print:
- case CMD_Print: /* ":Print" does as ":print" */
- do_print(&ea);
- break;
- case CMD_shell:
- do_shell(NULL, 0);
- break;
- case CMD_sleep:
- do_sleep(&ea);
- break;
- case CMD_stag:
- postponed_split = -1;
- /*FALLTHROUGH*/
- case CMD_tag:
- #ifdef USE_CSCOPE
- if (p_cst)
- do_cstag(&ea);
- else
- #endif
- do_tag(ea.arg, DT_TAG,
- ea.addr_count ? (int)ea.line2 : 1, ea.forceit, TRUE);
- break;
- case CMD_stselect:
- postponed_split = -1;
- /*FALLTHROUGH*/
- case CMD_tselect:
- do_tag(ea.arg, DT_SELECT, 0, ea.forceit, TRUE);
- break;
- case CMD_stjump:
- postponed_split = -1;
- /*FALLTHROUGH*/
- case CMD_tjump:
- do_tag(ea.arg, DT_JUMP, 0, ea.forceit, TRUE);
- break;
- case CMD_pop: do_ex_tag(&ea, DT_POP); break;
- case CMD_tnext: do_ex_tag(&ea, DT_NEXT); break;
- case CMD_tNext:
- case CMD_tprevious: do_ex_tag(&ea, DT_PREV); break;
- case CMD_trewind: do_ex_tag(&ea, DT_FIRST); break;
- case CMD_tlast: do_ex_tag(&ea, DT_LAST); break;
- case CMD_tags:
- do_tags();
- break;
- #ifdef USE_CSCOPE
- case CMD_cscope:
- do_cscope(&ea);
- break;
- case CMD_cstag:
- do_cstag(&ea);
- break;
- #endif
- case CMD_marks:
- do_marks(ea.arg);
- break;
- case CMD_jumps:
- do_jumps();
- break;
- case CMD_ascii:
- do_ascii();
- break;
- #ifdef FIND_IN_PATH
- case CMD_checkpath:
- find_pattern_in_path(NULL, 0, 0, FALSE, FALSE, CHECK_PATH, 1L,
- ea.forceit ? ACTION_SHOW_ALL : ACTION_SHOW,
- (linenr_t)1, (linenr_t)MAXLNUM);
- break;
- #endif
- case CMD_digraphs:
- #ifdef DIGRAPHS
- if (*ea.arg)
- putdigraph(ea.arg);
- else
- listdigraphs();
- #else
- EMSG("No digraphs in this version");
- #endif
- break;
- case CMD_set:
- (void)do_set(ea.arg);
- break;
- case CMD_fixdel:
- do_fixdel();
- break;
- #ifdef AUTOCMD
- case CMD_augroup:
- case CMD_autocmd:
- /*
- * Disallow auto commands from .exrc and .vimrc in current
- * directory for security reasons.
- */
- if (secure)
- {
- secure = 2;
- errormsg = e_curdir;
- }
- else if (ea.cmdidx == CMD_autocmd)
- do_autocmd(ea.arg, ea.forceit);
- else
- do_augroup(ea.arg);
- break;
- /*
- * Apply the automatic commands to all loaded buffers.
- */
- case CMD_doautoall:
- do_autoall(ea.arg);
- break;
- /*
- * Apply the automatic commands to the current buffer.
- */
- case CMD_doautocmd:
- (void)do_doautocmd(ea.arg, TRUE);
- do_modelines();
- break;
- #endif
- case CMD_abbreviate:
- case CMD_noreabbrev:
- case CMD_unabbreviate:
- case CMD_cabbrev:
- case CMD_cnoreabbrev:
- case CMD_cunabbrev:
- case CMD_iabbrev:
- case CMD_inoreabbrev:
- case CMD_iunabbrev:
- do_exmap(&ea, TRUE); /* almost the same as mapping */
- break;
- case CMD_map:
- case CMD_nmap:
- case CMD_vmap:
- case CMD_omap:
- case CMD_cmap:
- case CMD_imap:
- case CMD_noremap:
- case CMD_nnoremap:
- case CMD_vnoremap:
- case CMD_onoremap:
- case CMD_cnoremap:
- case CMD_inoremap:
- /*
- * If we are sourcing .exrc or .vimrc in current directory we
- * print the mappings for security reasons.
- */
- if (secure)
- {
- secure = 2;
- msg_outtrans(ea.cmd);
- msg_putchar('n');
- }
- case CMD_unmap:
- case CMD_nunmap:
- case CMD_vunmap:
- case CMD_ounmap:
- case CMD_cunmap:
- case CMD_iunmap:
- do_exmap(&ea, FALSE);
- break;
- case CMD_mapclear:
- case CMD_nmapclear:
- case CMD_vmapclear:
- case CMD_omapclear:
- case CMD_cmapclear:
- case CMD_imapclear:
- map_clear(ea.cmd, ea.forceit, FALSE);
- break;
- case CMD_abclear:
- case CMD_iabclear:
- case CMD_cabclear:
- map_clear(ea.cmd, TRUE, TRUE);
- break;
- #ifdef USE_GUI
- case CMD_menu: case CMD_noremenu: case CMD_unmenu:
- case CMD_amenu: case CMD_anoremenu: case CMD_aunmenu:
- case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu:
- case CMD_vmenu: case CMD_vnoremenu: case CMD_vunmenu:
- case CMD_omenu: case CMD_onoremenu: case CMD_ounmenu:
- case CMD_imenu: case CMD_inoremenu: case CMD_iunmenu:
- case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu:
- case CMD_tmenu: case CMD_tunmenu:
- do_menu(&ea);
- break;
- #endif
- case CMD_display:
- case CMD_registers:
- do_dis(ea.arg);
- break;
- case CMD_help:
- do_help(&ea);
- break;
- case CMD_version:
- do_version(ea.arg);
- break;
- case CMD_winsize:
- do_winsize(ea.arg);
- break;
- case CMD_delete:
- case CMD_yank:
- case CMD_rshift:
- case CMD_lshift:
- do_exops(&ea);
- break;
- case CMD_put:
- /* ":0put" works like ":1put!". */
- if (ea.line2 == 0)
- {
- ea.line2 = 1;
- ea.forceit = TRUE;
- }
- curwin->w_cursor.lnum = ea.line2;
- do_put(ea.regname, ea.forceit ? BACKWARD : FORWARD, -1L, 0);
- break;
- case CMD_t:
- case CMD_copy:
- case CMD_move:
- do_copymove(&ea);
- break;
- case CMD_and: /* :& */
- case CMD_tilde: /* :~ */
- case CMD_substitute: /* :s */
- do_sub(&ea);
- break;
- case CMD_smagic:
- i = p_magic;
- p_magic = TRUE;
- do_sub(&ea);
- p_magic = i;
- break;
- case CMD_snomagic:
- i = p_magic;
- p_magic = FALSE;
- do_sub(&ea);
- p_magic = i;
- break;
- case CMD_join:
- do_exjoin(&ea);
- break;
- case CMD_global:
- if (ea.forceit)
- *ea.cmd = 'v';
- case CMD_vglobal:
- do_glob(&ea);
- break;
- case CMD_star: /* :[addr]*r */
- case CMD_at: /* :[addr]@r */
- do_exat(&ea);
- break;
- case CMD_bang:
- do_bang(ea.addr_count, ea.line1, ea.line2,
- ea.forceit, ea.arg, TRUE, TRUE);
- break;
- case CMD_undo:
- u_undo(1);
- break;
- case CMD_redo:
- u_redo(1);
- break;
- case CMD_source:
- #ifdef USE_BROWSE
- if (browse)
- {
- char_u *fname = NULL;
- fname = do_browse(FALSE, (char_u *)"Run Macro",
- NULL, NULL, ea.arg, BROWSE_FILTER_MACROS, curbuf);
- if (fname != NULL)
- {
- cmd_source(fname, ea.forceit);
- vim_free(fname);
- }
- break;
- }
- #endif /* USE_BROWSE */
- if (*ea.arg == NUL)
- emsg(e_argreq);
- else
- cmd_source(ea.arg, ea.forceit);
- break;
- #ifdef VIMINFO
- case CMD_rviminfo:
- p = p_viminfo;
- if (*p_viminfo == NUL)
- p_viminfo = (char_u *)"'100";
- if (read_viminfo(ea.arg, TRUE, TRUE, ea.forceit) == FAIL)
- EMSG("Cannot open viminfo file for reading");
- p_viminfo = p;
- break;
- case CMD_wviminfo:
- p = p_viminfo;
- if (*p_viminfo == NUL)
- p_viminfo = (char_u *)"'100";
- write_viminfo(ea.arg, ea.forceit);
- p_viminfo = p;
- break;
- #endif /* VIMINFO */
- case CMD_redir:
- do_redir(&ea);
- break;
- case CMD_mksession:
- do_mkrc(&ea, (char_u *)SESSION_FILE);
- break;
- case CMD_mkvimrc:
- do_mkrc(&ea, (char_u *)VIMRC_FILE);
- break;
- case CMD_mkexrc:
- do_mkrc(&ea, (char_u *)EXRC_FILE);
- break;
- #ifdef QUICKFIX
- case CMD_cc:
- qf_jump(0, ea.addr_count ? (int)ea.line2 : 0, ea.forceit);
- break;
- case CMD_cfile:
- do_cfile(&ea);
- break;
- case CMD_clist:
- qf_list(ea.forceit);
- break;
- case CMD_crewind:
- qf_jump(0, ea.addr_count ? (int)ea.line2 : 1, ea.forceit);
- break;
- case CMD_clast:
- qf_jump(0, ea.addr_count ? (int)ea.line2 : 32767, ea.forceit);
- break;
- case CMD_cnext:
- qf_jump(FORWARD, ea.addr_count ? (int)ea.line2 : 1, ea.forceit);
- break;
- case CMD_colder:
- qf_older(ea.addr_count ? (int)ea.line2 : 1);
- break;
- case CMD_cnewer:
- qf_newer(ea.addr_count ? (int)ea.line2 : 1);
- break;
- case CMD_cNext:
- case CMD_cprevious:
- qf_jump(BACKWARD, ea.addr_count ? (int)ea.line2 : 1,
- ea.forceit);
- break;
- #endif
- #ifdef USER_COMMANDS
- case CMD_USER:
- do_ucmd(USER_CMD(ea.useridx), &ea);
- break;
- case CMD_command:
- do_command(&ea);
- break;
- case CMD_comclear:
- do_comclear();
- break;
- case CMD_delcommand:
- do_delcommand(&ea);
- break;
- #endif
- case CMD_cquit:
- getout(1); /* this does not always pass on the exit
- code to the Manx compiler. why? */
- case CMD_mark:
- case CMD_k:
- do_setmark(&ea);
- break;
- #ifdef EX_EXTRA
- case CMD_center:
- case CMD_right:
- case CMD_left:
- do_align(&ea);
- break;
- case CMD_retab:
- do_retab(&ea);
- break;
- case CMD_normal:
- do_normal(&ea);
- break;
- #endif
- #ifdef QUICKFIX
- case CMD_grep:
- do_make(ea.arg, p_gefm);
- break;
- case CMD_make:
- do_make(ea.arg, p_efm);
- break;
- #endif
- #ifdef FIND_IN_PATH
- case CMD_isearch:
- case CMD_dsearch:
- errormsg = do_findpat(&ea, ACTION_SHOW);
- break;
- case CMD_ilist:
- case CMD_dlist:
- errormsg = do_findpat(&ea, ACTION_SHOW_ALL);
- break;
- case CMD_ijump:
- case CMD_djump:
- errormsg = do_findpat(&ea, ACTION_GOTO);
- break;
- case CMD_isplit:
- case CMD_dsplit:
- errormsg = do_findpat(&ea, ACTION_SPLIT);
- break;
- #endif
- #ifdef SYNTAX_HL
- case CMD_syntax:
- do_syntax(&ea, cmdlinep);
- break;
- #endif
- case CMD_highlight:
- do_highlight(ea.arg, ea.forceit, FALSE);
- break;
- #ifdef WANT_EVAL
- case CMD_echo:
- case CMD_echon:
- do_echo(&ea, ea.cmdidx == CMD_echo);
- break;
- case CMD_echohl:
- do_echohl(ea.arg);
- break;
- case CMD_execute:
- do_execute(&ea, getline, cookie);
- break;
- case CMD_call:
- do_call(&ea);
- break;
- case CMD_if:
- errormsg = do_if(&ea, cstack);
- break;
- case CMD_elseif:
- case CMD_else:
- errormsg = do_else(&ea, cstack);
- break;
- case CMD_endif:
- did_endif = TRUE;
- if (cstack->cs_idx < 0
- || (cstack->cs_flags[cstack->cs_idx] & CSF_WHILE))
- errormsg = (char_u *)":endif without :if";
- else
- --cstack->cs_idx;
- break;
- case CMD_while:
- errormsg = do_while(&ea, cstack);
- break;
- case CMD_continue:
- errormsg = do_continue(cstack);
- break;
- case CMD_break:
- errormsg = do_break(cstack);
- break;
- case CMD_endwhile:
- errormsg = do_endwhile(cstack);
- break;
- case CMD_let:
- do_let(&ea);
- break;
- case CMD_unlet:
- do_unlet(ea.arg, ea.forceit);
- break;
- case CMD_function:
- do_function(&ea, getline, cookie);
- break;
- case CMD_delfunction:
- do_delfunction(ea.arg);
- break;
- case CMD_return:
- do_return(&ea);
- break;
- case CMD_endfunction:
- EMSG(":endfunction not inside a function");
- break;
- #endif /* WANT_EVAL */
- case CMD_insert:
- do_append(ea.line2 - 1, getline, cookie);
- ex_no_reprint = TRUE;
- break;
- case CMD_append:
- do_append(ea.line2, getline, cookie);
- ex_no_reprint = TRUE;
- break;
- case CMD_change:
- do_change(ea.line1, ea.line2, getline, cookie);
- ex_no_reprint = TRUE;
- break;
- case CMD_z:
- do_z(ea.line2, ea.arg);
- ex_no_reprint = TRUE;
- break;
- case CMD_intro:
- do_intro();
- break;
- #ifdef HAVE_PERL_INTERP
- case CMD_perl:
- do_perl(&ea);
- break;
- case CMD_perldo:
- do_perldo(&ea);
- break;
- #endif
- #ifdef HAVE_PYTHON
- case CMD_python:
- do_python(&ea);
- break;
- case CMD_pyfile:
- do_pyfile(&ea);
- break;
- #endif
- #ifdef HAVE_TCL
- case CMD_tcl:
- do_tcl(&ea);
- break;
- case CMD_tcldo:
- do_tcldo(&ea);
- break;
- case CMD_tclfile:
- do_tclfile(&ea);
- break;
- #endif
- #ifdef USE_SNIFF
- case CMD_sniff:
- do_sniff(ea.arg);
- break;
- #endif
- case CMD_nohlsearch:
- #ifdef EXTRA_SEARCH
- no_hlsearch = TRUE;
- redraw_all_later(NOT_VALID);
- #endif
- break;
- default:
- /* Illegal commands have already been handled */
- errormsg = (char_u *)"Sorry, this command is not implemented";
- }
- doend:
- if (curwin->w_cursor.lnum == 0) /* can happen with zero line number */
- curwin->w_cursor.lnum = 1;
- if (errormsg != NULL && *errormsg != NUL && !did_emsg)
- {
- emsg(errormsg);
- if (sourcing)
- {
- MSG_PUTS(": ");
- msg_outtrans(*cmdlinep);
- }
- }
- if (ea.nextcmd && *ea.nextcmd == NUL) /* not really a next command */
- ea.nextcmd = NULL;
- return ea.nextcmd;
- }
- /*
- * This is all pretty much copied from do_one_cmd(), with all the extra stuff
- * we don't need/want deleted. Maybe this could be done better if we didn't
- * repeat all this stuff. The only problem is that they may not stay perfectly
- * compatible with each other, but then the command line syntax probably won't
- * change that much -- webb.
- */
- char_u *
- set_one_cmd_context(buff)
- char_u *buff; /* buffer for command string */
- {
- char_u *p;
- char_u *cmd, *arg;
- int i = 0;
- CMDIDX cmdidx;
- long argt = 0;
- #ifdef USER_COMMANDS
- int compl = EXPAND_NOTHING;
- #endif
- char_u delim;
- int forceit = FALSE;
- int usefilter = FALSE; /* filter instead of file name */
- expand_pattern = buff;
- expand_context = EXPAND_COMMANDS; /* Default until we get past command */
- expand_set_path = FALSE;
- /*
- * 2. skip comment lines and leading space, colons or bars
- */
- for (cmd = buff; vim_strchr((char_u *)" t:|", *cmd) != NULL; cmd++)
- ;
- expand_pattern = cmd;
- if (*cmd == NUL)
- return NULL;
- if (*cmd == '"') /* ignore comment lines */
- {
- expand_context = EXPAND_NOTHING;
- return NULL;
- }
- /*
- * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
- */
- /*
- * Backslashed delimiters after / or ? will be skipped, and commands will
- * not be expanded between /'s and ?'s or after "'". -- webb
- */
- while (*cmd != NUL && (vim_isspace(*cmd) || isdigit(*cmd) ||
- vim_strchr((char_u *)".$%'/?-+,;", *cmd) != NULL))
- {
- if (*cmd == ''')
- {
- if (*++cmd == NUL)
- expand_context = EXPAND_NOTHING;
- }
- else if (*cmd == '/' || *cmd == '?')
- {
- delim = *cmd++;
- while (*cmd != NUL && *cmd != delim)
- if (*cmd++ == '\' && *cmd != NUL)
- ++cmd;
- if (*cmd == NUL)
- expand_context = EXPAND_NOTHING;
- }
- if (*cmd != NUL)
- ++cmd;
- }
- /*
- * 4. parse command
- */
- cmd = skipwhite(cmd);
- expand_pattern = cmd;
- if (*cmd == NUL)
- return NULL;
- if (*cmd == '"')
- {
- expand_context = EXPAND_NOTHING;
- return NULL;
- }
- if (*cmd == '|' || *cmd == 'n')
- return cmd + 1; /* There's another command */
- /*
- * Isolate the command and search for it in the command table.
- * Exceptions:
- * - the 'k' command can directly be followed by any character.
- * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
- */
- if (*cmd == 'k')
- {
- cmdidx = CMD_k;
- p = cmd + 1;
- }
- else
- {
- p = cmd;
- while (isalpha(*p) || *p == '*') /* Allow * wild card */
- ++p;
- /* check for non-alpha command */
- if (p == cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL)
- ++p;
- i = (int)(p - cmd);
- if (i == 0)
- {
- expand_context = EXPAND_UNSUCCESSFUL;
- return NULL;
- }
- for (cmdidx = (CMDIDX)0; (int)cmdidx < (int)CMD_SIZE;
- cmdidx = (CMDIDX)((int)cmdidx + 1))
- if (STRNCMP(cmdnames[(int)cmdidx].cmd_name, cmd, (size_t)i) == 0)
- break;
- }
- /*
- * If the cursor is touching the command, and it ends in an alphabetic
- * character, complete the command name.
- */
- if (*p == NUL && isalpha(p[-1]))
- return NULL;
- if (cmdidx == CMD_SIZE)
- {
- if (*cmd == 's' && vim_strchr((char_u *)"cgriI", cmd[1]) != NULL)
- {
- cmdidx = CMD_substitute;
- p = cmd + 1;
- }
- else
- {
- #ifdef USER_COMMANDS
- /* Look for a user defined command as a last resort */
- UCMD *c = USER_CMD(0);
- int j;
- int found = FALSE;
- for (j = 0; j < ucmds.ga_len; ++j, ++c)
- {
- if (STRNCMP(c->uc_name, cmd, (size_t)i) == 0)
- {
- if (found)
- {
- /* Ambiguous abbreviation */
- expand_context = EXPAND_UNSUCCESSFUL;
- return NULL;
- }
- found = TRUE;
- cmdidx = CMD_USER;
- argt = c->uc_argt;
- compl = c->uc_compl;
- /* Do not search for further abbreviations
- * if this is an exact match
- */
- if ((size_t)i == STRLEN(c->uc_name))
- break;
- }
- }
- if (!found)
- #endif
- {
- /* Not still touching the command and it was an illegal one */
- expand_context = EXPAND_UNSUCCESSFUL;
- return NULL;
- }
- }
- }
- expand_context = EXPAND_NOTHING; /* Default now that we're past command */
- if (*p == '!') /* forced commands */
- {
- forceit = TRUE;
- ++p;
- }
- /*
- * 5. parse arguments
- */
- #ifdef USER_COMMANDS
- if (cmdidx != CMD_USER)
- #endif
- argt = cmdnames[(int)cmdidx].cmd_argt;
- arg = skipwhite(p);
- if (cmdidx == CMD_write || cmdidx == CMD_update)
- {
- if (*arg == '>') /* append */
- {
- if (*++arg == '>')
- ++arg;
- arg = skipwhite(arg);
- }
- else if (*arg == '!' && cmdidx == CMD_write) /* :w !filter */
- {
- ++arg;
- usefilter = TRUE;
- }
- }
- if (cmdidx == CMD_read)
- {
- usefilter = forceit; /* :r! filter if forced */
- if (*arg == '!') /* :r !filter */
- {
- ++arg;
- usefilter = TRUE;
- }
- }
- if (cmdidx == CMD_lshift || cmdidx == CMD_rshift)
- {
- while (*arg == *cmd) /* allow any number of '>' or '<' */
- ++arg;
- arg = skipwhite(arg);
- }
- /* Does command allow "+command"? */
- if ((argt & EDITCMD) && !usefilter && *arg == '+')
- {
- /* Check if we're in the +command */
- p = arg + 1;
- arg = skip_cmd_arg(arg);
- /* Still touching the command after '+'? */
- if (*arg == NUL)
- return p;
- /* Skip space(s) after +command to get to the real argument */
- arg = skipwhite(arg);
- }
- /*
- * Check for '|' to separate commands and '"' to start comments.
- * Don't do this for ":read !cmd" and ":write !cmd".
- */
- if ((argt & TRLBAR) && !usefilter)
- {
- p = arg;
- while (*p)
- {
- if (*p == Ctrl('V'))
- {
- if (p[1] != NUL)
- ++p;
- }
- else if ( (*p == '"' && !(argt & NOTRLCOM))
- || *p == '|' || *p == 'n')
- {
- if (*(p - 1) != '\')
- {
- if (*p == '|' || *p == 'n')
- return p + 1;
- return NULL; /* It's a comment */
- }
- }
- ++p;
- }
- }
- /* no arguments allowed */
- if (!(argt & EXTRA) && *arg != NUL &&
- vim_strchr((char_u *)"|"", *arg) == NULL)
- return NULL;
- /* Find start of last argument (argument just before cursor): */
- p = buff + STRLEN(buff);
- while (p != arg && *p != ' ' && *p != TAB)
- p--;
- if (*p == ' ' || *p == TAB)
- p++;
- expand_pattern = p;
- if (argt & XFILE)
- {
- int in_quote = FALSE;
- char_u *bow = NULL; /* Beginning of word */
- /*
- * Allow spaces within back-quotes to count as part of the argument
- * being expanded.
- */
- expand_pattern = skipwhite(arg);
- for (p = expand_pattern; *p; ++p)
- {
- if (*p == '\' && p[1])
- ++p;
- #ifdef SPACE_IN_FILENAME
- else if (vim_iswhite(*p) && (!(argt & NOSPC) || usefilter))
- #else
- else if (vim_iswhite(*p))
- #endif
- {
- p = skipwhite(p);
- if (in_quote)
- bow = p;
- else
- expand_pattern = p;
- --p;
- }
- else if (*p == '`')
- {
- if (!in_quote)
- {
- expand_pattern = p;
- bow = p + 1;
- }
- in_quote = !in_quote;
- }
- }
- /*
- * If we are still inside the quotes, and we passed a space, just
- * expand from there.
- */
- if (bow != NULL && in_quote)
- expand_pattern = bow;
- expand_context = EXPAND_FILES;
- }
- /*
- * 6. switch on command name
- */
- switch (cmdidx)
- {
- case CMD_cd:
- case CMD_chdir:
- expand_context = EXPAND_DIRECTORIES;
- break;
- #ifdef USE_BROWSE
- case CMD_browse:
- #endif
- case CMD_confirm:
- return arg;
- case CMD_global:
- case CMD_vglobal:
- delim = *arg; /* get the delimiter */
- if (delim)
- ++arg; /* skip delimiter if there is one */
- while (arg[0] != NUL && arg[0] != delim)
- {
- if (arg[0] == '\' && arg[1] != NUL)
- ++arg;
- ++arg;
- }
- if (arg[0] != NUL)
- return arg + 1;
- break;
- case CMD_and:
- case CMD_substitute:
- delim = *arg;
- if (delim)
- ++arg;
- for (i = 0; i < 2; i++)
- {
- while (arg[0] != NUL && arg[0] != delim)
- {
- if (arg[0] == '\' && arg[1] != NUL)
- ++arg;
- ++arg;
- }
- if (arg[0] != NUL) /* skip delimiter */
- ++arg;
- }
- while (arg[0] && vim_strchr((char_u *)"|"#", arg[0]) == NULL)
- ++arg;
- if (arg[0] != NUL)
- return arg;
- break;
- case CMD_isearch:
- case CMD_dsearch:
- case CMD_ilist:
- case CMD_dlist:
- case CMD_ijump:
- case CMD_djump:
- case CMD_isplit:
- case CMD_dsplit:
- arg = skipwhite(skipdigits(arg)); /* skip count */
- if (*arg == '/') /* Match regexp, not just whole words */
- {
- for (++arg; *arg && *arg != '/'; arg++)
- if (*arg == '\' && arg[1] != NUL)
- arg++;
- if (*arg)
- {
- arg = skipwhite(arg + 1);
- /* Check for trailing illegal characters */
- if (*arg && vim_strchr((char_u *)"|"n", *arg) == NULL)
- expand_context = EXPAND_NOTHING;
- else
- return arg;
- }
- }
- break;
- #ifdef AUTOCMD
- case CMD_autocmd:
- return set_context_in_autocmd(arg, FALSE);
- case CMD_doautocmd:
- return set_context_in_autocmd(arg, TRUE);
- #endif
- case CMD_set:
- set_context_in_set_cmd(arg);
- break;
- case CMD_tag:
- case CMD_stag:
- case CMD_tselect:
- case CMD_stselect:
- case CMD_tjump:
- case CMD_stjump:
- expand_context = EXPAND_TAGS;
- expand_pattern = arg;
- break;
- case CMD_help:
- expand_context = EXPAND_HELP;
- expand_pattern = arg;
- break;
- case CMD_augroup:
- expand_context = EXPAND_AUGROUP;
- expand_pattern = arg;
- break;
- #ifdef SYNTAX_HL
- case CMD_syntax:
- set_context_in_syntax_cmd(arg);
- break;
- #endif
- #ifdef WANT_EVAL
- case CMD_unlet:
- while ((expand_pattern = vim_strchr(arg, ' ')) != NULL)
- arg = expand_pattern + 1;
- expand_context = EXPAND_USER_VARS;
- expand_pattern = arg;
- break;
- case CMD_echohl:
- expand_context = EXPAND_HIGHLIGHT;
- expand_pattern = arg;
- break;
- #endif
- case CMD_highlight:
- set_context_in_highlight_cmd(arg);
- break;
- case CMD_bdelete:
- case CMD_bunload:
- while ((expand_pattern = vim_strchr(arg, ' ')) != NULL)
- arg = expand_pattern + 1;
- case CMD_buffer:
- case CMD_sbuffer:
- expand_context = EXPAND_BUFFERS;
- expand_pattern = arg;
- break;
- #ifdef USER_COMMANDS
- case CMD_USER:
- if (compl != EXPAND_NOTHING)
- {
- #ifdef USE_GUI
- if (compl == EXPAND_MENUS)
- return gui_set_context_in_menu_cmd(cmd, arg, forceit);
- #endif
- if (compl == EXPAND_COMMANDS)
- return arg;
- while ((expand_pattern = vim_strchr(arg, ' ')) != NULL)
- arg = expand_pattern + 1;
- expand_context = compl;
- expand_pattern = arg;
- }
- break;
- #endif
- #ifdef USE_GUI
- case CMD_menu: case CMD_noremenu: case CMD_unmenu:
- case CMD_amenu: case CMD_anoremenu: case CMD_aunmenu:
- case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu:
- case CMD_vmenu: case CMD_vnoremenu: case CMD_vunmenu:
- case CMD_omenu: case CMD_onoremenu: case CMD_ounmenu:
- case CMD_imenu: case CMD_inoremenu: case CMD_iunmenu:
- case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu:
- case CMD_tmenu: case CMD_tunmenu:
- case CMD_tearoff:
- return gui_set_context_in_menu_cmd(cmd, arg, forceit);
- #endif
- default:
- break;
- }
- return NULL;
- }
- /*
- * get a single EX address
- *
- * Set ptr to the next character after the part that was interpreted.
- * Set ptr to NULL when an error is encountered.
- *
- * Return MAXLNUM when no Ex address was found.
- */
- static linenr_t
- get_address(ptr, skip)
- char_u **ptr;
- int skip; /* only skip the address, don't use it */
- {
- int c;
- int i;
- long n;
- char_u *cmd;
- FPOS pos;
- FPOS *fp;
- linenr_t lnum;
- cmd = skipwhite(*ptr);
- lnum = MAXLNUM;
- do
- {
- switch (*cmd)
- {
- case '.': /* '.' - Cursor position */
- ++cmd;
- lnum = curwin->w_cursor.lnum;
- break;
- case '$': /* '$' - last line */
- ++cmd;
- lnum = curbuf->b_ml.ml_line_count;
- break;
- case ''': /* ''' - mark */
- if (*++cmd == NUL)
- {
- cmd = NULL;
- goto error;
- }
- if (!skip)
- {
- fp = getmark(*cmd, FALSE);
- ++cmd;
- if (check_mark(fp) == FAIL)
- {
- cmd = NULL;
- goto error;
- }
- lnum = fp->lnum;
- }
- break;
- case '/':
- case '?': /* '/' or '?' - search */
- c = *cmd++;
- if (skip) /* skip "/pat/" */
- {
- cmd = skip_regexp(cmd, c, (int)p_magic);
- if (*cmd == c)
- ++cmd;
- }
- else
- {
- pos = curwin->w_cursor; /* save curwin->w_cursor */
- /*
- * When '/' or '?' follows another address, start
- * from there.
- */
- if (lnum != MAXLNUM)
- curwin->w_cursor.lnum = lnum;
- /*
- * Start a forward search at the end of the line.
- * Start a backward search at the start of the line.
- * This makes sure we never match in the current
- * line, and can match anywhere in the
- * next/previous line.
- */
- if (c == '/')
- curwin->w_cursor.col = MAXCOL;
- else
- curwin->w_cursor.col = 0;
- searchcmdlen = 0;
- if (!do_search(NULL, c, cmd, 1L,
- SEARCH_HIS + SEARCH_MSG + SEARCH_START))
- {
- curwin->w_cursor = pos;
- cmd = NULL;
- goto error;
- }
- lnum = curwin->w_cursor.lnum;
- curwin->w_cursor = pos;
- /* adjust command string pointer */
- cmd += searchcmdlen;
- }
- break;
- case '\': /* "?", "/" or "&", repeat search */
- ++cmd;
- if (*cmd == '&')
- i = RE_SUBST;
- else if (*cmd == '?' || *cmd == '/')
- i = RE_SEARCH;
- else
- {
- emsg(e_backslash);
- cmd = NULL;
- goto error;
- }
- if (!skip)
- {
- /*
- * When search follows another address, start from
- * there.
- */
- if (lnum != MAXLNUM)
- pos.lnum = lnum;
- else
- pos.lnum = curwin->w_cursor.lnum;
- /*
- * Start the search just like for the above
- * do_search().
- */
- if (*cmd != '?')
- pos.col = MAXCOL;
- else
- pos.col = 0;
- if (searchit(curbuf, &pos,
- *cmd == '?' ? BACKWARD : FORWARD,
- (char_u *)"", 1L,
- SEARCH_MSG + SEARCH_START, i) == OK)
- lnum = pos.lnum;
- else
- {
- cmd = NULL;
- goto error;
- }
- }
- ++cmd;
- break;
- default:
- if (isdigit(*cmd)) /* absolute line number */
- lnum = getdigits(&cmd);
- }
- for (;;)
- {
- cmd = skipwhite(cmd);
- if (*cmd != '-' && *cmd != '+' && !isdigit(*cmd))
- break;
- if (lnum == MAXLNUM)
- lnum = curwin->w_cursor.lnum; /* "+1" is same as ".+1" */
- if (isdigit(*cmd))
- i = '+'; /* "number" is same as "+number" */
- else
- i = *cmd++;
- if (!isdigit(*cmd)) /* '+' is '+1', but '+0' is not '+1' */
- n = 1;
- else
- n = getdigits(&cmd);
- if (i == '-')
- lnum -= n;
- else
- lnum += n;
- }
- } while (*cmd == '/' || *cmd == '?');
- error:
- *ptr = cmd;
- return lnum;
- }
- /*
- * Check range in Ex command for validity.
- * Return NULL when valid, error message when invalid.
- */
- static char_u *
- invalid_range(eap)
- EXARG *eap;
- {
- if ( eap->line1 < 0
- || eap->line2 < 0
- || eap->line1 > eap->line2
- || ((eap->argt & RANGE)
- && !(eap->argt & NOTADR)
- && eap->line2 > curbuf->b_ml.ml_line_count))
- return e_invrange;
- return NULL;
- }
- /*
- * Corect the range for zero line number, if required.
- */
- static void
- correct_range(eap)
- EXARG *eap;
- {
- if (!(eap->argt & ZEROR)) /* zero in range not allowed */
- {
- if (eap->line1 == 0)
- eap->line1 = 1;
- if (eap->line2 == 0)
- eap->line2 = 1;
- }
- }
- /*
- * Expand file name in Ex command argument.
- * Return FAIL for failure, OK otherwise.
- */
- int
- expand_filename(eap, cmdlinep, errormsgp)
- EXARG *eap;
- char_u **cmdlinep;
- char_u **errormsgp;
- {
- int has_wildcards; /* need to expand wildcards */
- char_u *repl;
- int srclen;
- char_u *p;
- char_u *new_cmdline;
- int len;
- int i;
- int n;
- /*
- * Decide to expand wildcards *before* replacing '%', '#', etc. If
- * the file name contains a wildcard it should not cause expanding.
- * (it will be expanded anyway if there is a wildcard before replacing).
- */
- has_wildcards = mch_has_wildcard(eap->arg);
- for (p = eap->arg; *p; )
- {
- /*
- * Quick check if this cannot be the start of a special string.
- */
- if (vim_strchr((char_u *)"%#<", *p) == NULL)
- {
- ++p;
- continue;
- }
- /*
- * Try to find a match at this position.
- */
- repl = eval_vars(p, &srclen, &(eap->do_ecmd_lnum), errormsgp, eap->arg);
- if (*errormsgp != NULL) /* error detected */
- return FAIL;
- if (repl == NULL) /* no match found */
- {
- p += srclen;
- continue;
- }
- /*
- * The new command line is build in new_cmdline[].
- * First allocate it.
- */
- len = STRLEN(repl);
- i = STRLEN(*cmdlinep) + len + 3;
- if (eap->nextcmd)
- i += STRLEN(eap->nextcmd); /* add space for next command */
- if ((new_cmdline = alloc(i)) == NULL)
- {
- vim_free(repl);
- return FAIL; /* out of memory! */
- }
- /*
- * Copy the stuff before the expanded part.
- * Copy the expanded stuff.
- * Copy what came after the expanded part.
- * Copy the next commands, if there are any.
- */
- i = p - *cmdlinep; /* length of part before match */
- mch_memmove(new_cmdline, *cmdlinep, (size_t)i);
- mch_memmove(new_cmdline + i, repl, (size_t)len);
- vim_free(repl);
- i += len; /* remember the end of the string */
- STRCPY(new_cmdline + i, p + srclen);
- p = new_cmdline + i; /* remember where to continue */
- if (eap->nextcmd) /* append next command */
- {
- i = STRLEN(new_cmdline) + 1;
- STRCPY(new_cmdline + i, eap->nextcmd);
- eap->nextcmd = new_cmdline + i;
- }
- eap->cmd = new_cmdline + (eap->cmd - *cmdlinep);
- eap->arg = new_cmdline + (eap->arg - *cmdlinep);
- if (eap->do_ecmd_cmd != NULL)
- eap->do_ecmd_cmd = new_cmdline + (eap->do_ecmd_cmd - *cmdlinep);
- vim_free(*cmdlinep);
- *cmdlinep = new_cmdline;
- }
- /*
- * One file argument: Expand wildcards.
- * Don't do this with ":r !command" or ":w !command".
- */
- if ((eap->argt & NOSPC) && !eap->usefilter)
- {
- /*
- * May do this twice:
- * 1. Replace environment variables.
- * 2. Replace any other wildcards, remove backslashes.
- */
- for (n = 1; n <= 2; ++n)
- {
- if (n == 2)
- {
- #if defined(UNIX)
- /*
- * Only for Unix we check for more than one file name.
- * For other systems spaces are considered to be part
- * of the file name.
- * Only check here if there is no wildcard, otherwise
- * ExpandOne will check for errors. This allows
- * ":e `ls ve*.c`" on Unix.
- */
- if (!has_wildcards)
- for (p = eap->arg; *p; ++p)
- {
- /* skip escaped characters */
- if (p[1] && (*p == '\' || *p == Ctrl('V')))
- ++p;
- else if (vim_iswhite(*p))
- {
- *errormsgp = (char_u *)"Only one file name allowed";
- return FAIL;
- }
- }
- #endif
- /*
- * halve the number of backslashes (this is Vi compatible)
- */
- backslash_halve(eap->arg, has_wildcards);
- #ifdef macintosh
- /*
- * translate unix-like path components
- */
- slash_n_colon_adjust (eap->arg);
- #endif
- }
- if (has_wildcards)
- {
- if (n == 1)
- {
- /*
- * First loop: May expand environment variables. This
- * can be done much faster with expand_env() than with
- * something else (e.g., calling a shell).
- * After expanding environment variables, check again
- * if there are still wildcards present.
- */
- if (vim_strchr(eap->arg, '$') || vim_strchr(eap->arg, '~'))
- {
- expand_env(eap->arg, NameBuff, MAXPATHL);
- has_wildcards = mch_has_wildcard(NameBuff);
- p = NameBuff;
- }
- else
- p = NULL;
- }
- else /* n == 2 */
- {
- if ((p = ExpandOne(eap->arg, NULL, WILD_LIST_NOTFOUND,
- WILD_EXPAND_FREE)) == NULL)
- return FAIL;
- }
- if (p != NULL)
- {
- /*
- * The tricky bit here is to replace the argument,
- * while keeping the "eap->cmd" and "eap->nextcmd" the
- * pointers correct.
- */
- len = eap->arg - *cmdlinep;
- i = STRLEN(p) + len;
- if (eap->nextcmd)
- i += STRLEN(eap->nextcmd);
- if ((new_cmdline = alloc((unsigned)i + 2)) != NULL)
- {
- STRNCPY(new_cmdline, *cmdlinep, len);
- STRCPY(new_cmdline + len, p);
- if (eap->nextcmd) /* append next command */
- {
- i = STRLEN(new_cmdline) + 1;
- STRCPY(new_cmdline + i, eap->nextcmd);
- eap->nextcmd = new_cmdline + i;
- }
- eap->cmd = new_cmdline + (eap->cmd - *cmdlinep);
- eap->arg = new_cmdline + len;
- vim_free(*cmdlinep);
- *cmdlinep = new_cmdline;
- }
- if (n == 2) /* p came from ExpandOne() */
- vim_free(p);
- }
- }
- }
- }
- return OK;
- }
- /*
- * Check for '|' to separate commands and '"' to start comments.
- */
- void
- separate_nextcmd(eap)
- EXARG *eap;
- {
- char_u *p;
- for (p = eap->arg; *p; ++p)
- {
- if (*p == Ctrl('V'))
- {
- if (eap->argt & (USECTRLV | XFILE))
- ++p; /* skip CTRL-V and next char */
- else
- STRCPY(p, p + 1); /* remove CTRL-V and skip next char */
- if (*p == NUL) /* stop at NUL after CTRL-V */
- break;
- }
- else if ((*p == '"' && !(eap->argt & NOTRLCOM))
- || *p == '|' || *p == 'n')
- {
- /*
- * We remove the '' before the '|', unless USECTRLV is used
- * AND 'b' is present in 'cpoptions'.
- */
- if ((vim_strchr(p_cpo, CPO_BAR) == NULL
- || !(eap->argt & USECTRLV)) && *(p - 1) == '\')
- {
- mch_memmove(p - 1, p, STRLEN(p) + 1); /* remove the '' */
- --p;
- }
- else
- {
- eap->nextcmd = check_nextcmd(p);
- *p = NUL;
- break;
- }
- }
- }
- if (!(eap->argt & NOTRLCOM)) /* remove trailing spaces */
- del_trailing_spaces(eap->arg);
- }
- /*
- * If 'autowrite' option set, try to write the file.
- *
- * return FAIL for failure, OK otherwise
- */
- int
- autowrite(buf, forceit)
- BUF *buf;
- int forceit;
- {
- if (!p_aw || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
- return FAIL;
- return buf_write_all(buf);
- }
- /*
- * flush all buffers, except the ones that are readonly
- */
- void
- autowrite_all()
- {
- BUF *buf;
- if (!p_aw)
- return;
- for (buf = firstbuf; buf; buf = buf->b_next)
- if (buf_changed(buf) && !buf->b_p_ro)
- {
- (void)buf_write_all(buf);
- #ifdef AUTOCMD
- /* an autocommand may have deleted the buffer */
- if (!buf_valid(buf))
- buf = firstbuf;
- #endif
- }
- }
- static int
- check_readonly(forceit)
- int *forceit;
- {
- if (!*forceit && curbuf->b_p_ro)
- {
- #if defined(GUI_DIALOG) || defined(CON_DIALOG)
- if ((p_confirm || confirm) && curbuf->b_fname != NULL)
- {
- char_u buff[IOSIZE];
- dialog_msg(buff, "'readonly' option is set for "%.*s".nDo you wish to override it?",
- curbuf->b_fname);
- if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 0) == VIM_YES)
- {
- /* Set forceit, to force the writing of a readonly file */
- *forceit = TRUE;
- return FALSE;
- }
- else
- return TRUE;
- }
- else
- #endif
- emsg(e_readonly);
- return TRUE;
- }
- return FALSE;
- }
- /*
- * return TRUE if buffer was changed and cannot be abandoned.
- */
- static int
- check_changed(buf, checkaw, mult_win, forceit, allbuf)
- BUF *buf;
- int checkaw; /* do autowrite if buffer was changed */
- int mult_win; /* check also when several wins for the buf */
- int forceit;
- int allbuf; /* may write all buffers */
- {
- if ( !forceit
- && buf_changed(buf)
- && (mult_win || buf->b_nwindows <= 1)
- && (!checkaw || autowrite(buf, forceit) == FAIL))
- {
- #if defined(GUI_DIALOG) || defined(CON_DIALOG)
- if (p_confirm || confirm)
- {
- BUF *buf2;
- int count = 0;
- if (allbuf)
- for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
- if (buf_changed(buf2)
- && (buf2->b_ffname != NULL
- # ifdef USE_BROWSE
- || browse
- # endif
- ))
- ++count;
- dialog_changed(buf, count > 1);
- return buf_changed(buf);
- }
- #endif
- emsg(e_nowrtmsg);
- return TRUE;
- }
- return FALSE;
- }
- #if defined(GUI_DIALOG) || defined(CON_DIALOG)
- /*
- * Ask the user what to do when abondoning a changed buffer.
- */
- static void
- dialog_changed(buf, checkall)
- BUF *buf;
- int checkall; /* may abandon all changed buffers */
- {
- char_u buff[IOSIZE];
- int ret;
- BUF *buf2;
- dialog_msg(buff, "Save changes to "%.*s"?",
- (buf->b_fname != NULL) ?
- buf->b_fname : (char_u *)"Untitled");
- if (checkall)
- ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
- else
- ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
- if (ret == VIM_YES)
- {
- #ifdef USE_BROWSE
- /* May get file name, when there is none */
- browse_save_fname(buf);
- #endif
- if (buf->b_fname != NULL) /* didn't hit Cancel */
- (void)buf_write_all(buf);
- }
- else if (ret == VIM_NO)
- {
- unchanged(buf, TRUE);
- }
- else if (ret == VIM_ALL)
- {
- /*
- * Write all modified files that can be written.
- * Skip readonly buffers, these need to be confirmed
- * individually.
- */
- for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
- {
- if (buf_changed(buf2)
- && (buf2->b_ffname != NULL
- #ifdef USE_BROWSE
- || browse
- #endif
- )
- && !buf2->b_p_ro)
- {
- #ifdef USE_BROWSE
- /* May get file name, when there is none */
- browse_save_fname(buf2);
- #endif
- if (buf2->b_fname != NULL) /* didn't hit Cancel */
- (void)buf_write_all(buf2);
- #ifdef AUTOCMD
- /* an autocommand may have deleted the buffer */
- if (!buf_valid(buf2))
- buf2 = firstbuf;
- #endif
- }
- }
- }
- else if (ret == VIM_DISCARDALL)
- {
- /*
- * mark all buffers as unchanged
- */
- for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
- unchanged(buf2, TRUE);
- }
- }
- #endif
- #if defined(USE_BROWSE) && (defined(GUI_DIALOG) || defined(CON_DIALOG))
- /*
- * When wanting to write a file without a file name, ask the user for a name.
- */
- static void
- browse_save_fname(buf)
- BUF *buf;
- {
- if (buf->b_fname == NULL)
- {
- char_u *fname;
- fname = do_browse(TRUE, (char_u *)"Save As", NULL, NULL, NULL,
- NULL, buf);
- if (fname != NULL)
- {
- setfname(fname, NULL, TRUE);
- vim_free(fname);
- }
- }
- }
- #endif
- /*
- * Return TRUE if the buffer "buf" can be abandoned, either by making it
- * hidden, autowriting it or unloading it.
- */
- int
- can_abandon(buf, forceit)
- BUF *buf;
- int forceit;
- {
- return ( p_hid
- || !buf_changed(buf)
- || buf->b_nwindows > 1
- || autowrite(buf, forceit) == OK
- || forceit);
- }
- /*
- * Return TRUE if any buffer was changed and cannot be abandoned.
- * That changed buffer becomes the current buffer.
- */
- int
- check_changed_any(hidden)
- int hidden; /* Only check hidden buffers */
- {
- BUF *buf;
- int save;
- #if defined(GUI_DIALOG) || defined(CON_DIALOG)
- for (;;)
- {
- #endif
- /* check curbuf first: if it was changed we can't abandon it */
- if (!hidden && buf_changed(curbuf))
- buf = curbuf;
- else
- {
- for (buf = firstbuf; buf != NULL; buf = buf->b_next)
- if ((!hidden || buf->b_nwindows == 0) && buf_changed(buf))
- break;
- }
- if (buf == NULL) /* No buffers changed */
- return FALSE;
- #if defined(GUI_DIALOG) || defined(CON_DIALOG)
- if (p_confirm || confirm)
- {
- if (check_changed(buf, FALSE, TRUE, FALSE, TRUE))
- break; /* didn't save - still changes */
- }
- else
- break; /* confirm not active - has changes */
- }
- #endif
- exiting = FALSE;
- #if defined(GUI_DIALOG) || defined(CON_DIALOG)
- /*
- * When ":confirm" used, don't give an error message.
- */
- if (!(p_confirm || confirm))
- #endif
- {
- /* There must be a wait_return for this message, do_buffer()
- * may cause a redraw. But wait_return() is a no-op when vgetc()
- * is busy (Quit used from window menu), then make sure we don't
- * cause a scroll up. */
- if (vgetc_busy)
- {
- msg_row = cmdline_row;
- msg_col = 0;
- msg_didout = FALSE;
- }
- if (EMSG2("No write since last change for buffer "%s"",
- buf->b_fname == NULL ? (char_u *)"No File" :
- buf->b_fname))
- {
- save = no_wait_return;
- no_wait_return = FALSE;
- wait_return(FALSE);
- no_wait_return = save;
- }
- }
- (void)do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, buf->b_fnum, 0);
- return TRUE;
- }
- /*
- * return FAIL if there is no file name, OK if there is one
- * give error message for FAIL
- */
- int
- check_fname()
- {
- if (curbuf->b_ffname == NULL)
- {
- emsg(e_noname);
- return FAIL;
- }
- return OK;
- }
- /*
- * flush the contents of a buffer, unless it has no file name
- *
- * return FAIL for failure, OK otherwise
- */
- static int
- buf_write_all(buf)
- BUF *buf;
- {
- int retval;
- #ifdef AUTOCMD
- BUF *old_curbuf = curbuf;
- #endif
- retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
- (linenr_t)1, buf->b_ml.ml_line_count,
- FALSE, FALSE, TRUE, FALSE));
- #ifdef AUTOCMD
- if (curbuf != old_curbuf)
- MSG("Warning: Entered other buffer unexpectedly (check autocommands)");
- #endif
- return retval;
- }
- /*
- * get + command from ex argument
- */
- static char_u *
- getargcmd(argp)
- char_u **argp;
- {
- char_u *arg = *argp;
- char_u *command = NULL;
- if (*arg == '+') /* +[command] */
- {
- ++arg;
- if (vim_isspace(*arg))
- command = (char_u *)"$";
- else
- {
- command = arg;
- arg = skip_cmd_arg(command);
- if (*arg)
- *arg++ = NUL; /* terminate command with NUL */
- }
- arg = skipwhite(arg); /* skip over spaces */
- *argp = arg;
- }
- return command;
- }
- /*
- * Find end of "+command" argument. Skip over " " and "\".
- */
- static char_u *
- skip_cmd_arg(p)
- char_u *p;
- {
- while (*p && !vim_isspace(*p))
- {
- if (*p == '\' && p[1] != NUL)
- ++p;
- ++p;
- }
- return p;
- }
- /*
- * Return TRUE if "str" starts with a backslash that should be removed.
- * For MS-DOS, WIN32 and OS/2 this is only done when the character after the
- * backslash is not a normal file name character.
- * Although '$' is a valid file name character, we remove the backslash before
- * it, to be able to disginguish between a file name that starts with '$' and
- * the name of an environment variable.
- * Make sure that "\mchfile" isn't translated into "mchfile".
- */
- static int
- rem_backslash(str)
- char_u *str;
- {
- #ifdef BACKSLASH_IN_FILENAME
- return (str[0] == '\'
- && (str[1] == '$'
- || (str[1] != NUL
- && str[1] != '*'
- && str[1] != '?'
- && !vim_isfilec(str[1]))));
- #else
- return (str[0] == '\' && str[1] != NUL);
- #endif
- }
- /*
- * Halve the number of backslashes in a file name argument.
- * For MS-DOS we only do this if the character after the backslash
- * is not a normal file character.
- * For Unix, when wildcards are going to be expanded, don't remove
- * backslashes before special characters.
- */
- void
- backslash_halve(p, has_wildcards)
- char_u *p;
- int has_wildcards; /* going to expand wildcards later */
- {
- for ( ; *p; ++p)
- if (rem_backslash(p)
- #if defined(UNIX) || defined(OS2)
- && !(has_wildcards &&
- vim_strchr((char_u *)" *?[{`'~$\", p[1]) != NULL)
- #endif
- )
- STRCPY(p, p + 1);
- }
- /*
- * write current buffer to file 'eap->arg'
- * if 'eap->append' is TRUE, append to the file
- *
- * if *eap->arg == NUL write to current file
- * if b_notedited is TRUE, check for overwriting current file
- *
- * return FAIL for failure, OK otherwise
- */
- static int
- do_write(eap)
- EXARG *eap;
- {
- int other;
- char_u *fname = NULL; /* init to shut up gcc */
- char_u *ffname;
- int retval = FAIL;
- char_u *free_fname = NULL;
- #ifdef USE_BROWSE
- char_u *browse_file = NULL;
- #endif
- ffname = eap->arg;
- #ifdef USE_BROWSE
- if (browse)
- {
- browse_file = do_browse(TRUE, (char_u *)"Save As", NULL,
- NULL, ffname, NULL, curbuf);
- if (browse_file == NULL)
- goto theend;
- ffname = browse_file;
- }
- #endif
- if (*ffname == NUL)
- other = FALSE;
- else
- {
- fname = ffname;
- free_fname = fix_fname(ffname);
- /*
- * When out-of-memory, keep unexpanded file name, because we MUST be
- * able to write the file in this situation.
- */
- if (free_fname != NULL)
- ffname = free_fname;
- other = otherfile(ffname);
- }
- /*
- * If we have a new file, name put it in the list of alternate file names.
- */
- if (other && vim_strchr(p_cpo, CPO_ALTWRITE) != NULL)
- setaltfname(ffname, fname, (linenr_t)1);
- /*
- * writing to the current file is not allowed in readonly mode
- * and need a file name
- */
- if (!other && (check_readonly(&eap->forceit) || check_fname() == FAIL))
- goto theend;
- if (!other)
- {
- ffname = curbuf->b_ffname;
- fname = curbuf->b_fname;
- /*
- * Not writing the whole file is only allowed with '!'.
- */
- if ( (eap->line1 != 1
- || eap->line2 != curbuf->b_ml.ml_line_count)
- && !eap->forceit
- && !eap->append
- && !p_wa)
- {
- #if defined(GUI_DIALOG) || defined(CON_DIALOG)
- if (p_confirm || confirm)
- {
- if (vim_dialog_yesno(VIM_QUESTION, NULL,
- (char_u *)"Write partial file?", 2) != VIM_YES)
- goto theend;
- eap->forceit = TRUE;
- dont_wait_return = FALSE; /* show write message */
- }
- else
- #endif
- {
- EMSG("Use ! to write partial buffer");
- goto theend;
- }
- }
- }
- /*
- * write to other file or b_notedited set or not writing the whole file:
- * overwriting only allowed with '!'
- */
- if ( (other
- || curbuf->b_notedited)
- && !eap->forceit
- && !eap->append
- && !p_wa
- && vim_fexists(ffname))
- {
- #ifdef UNIX
- /* with UNIX it is possible to open a directory */
- if (mch_isdir(ffname))
- {
- EMSG2(""%s" is a directory", ffname);
- goto theend;
- }
- else
- #endif
- #if defined(GUI_DIALOG) || defined(CON_DIALOG)
- if (p_confirm || confirm)
- {
- char_u buff[IOSIZE];
- dialog_msg(buff, "Overwrite existing file "%.*s"?", fname);
- if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) != VIM_YES)
- goto theend;
- eap->forceit = TRUE;
- dont_wait_return = FALSE; /* show write message */
- }
- else
- #endif
- {
- emsg(e_exists);
- goto theend;
- }
- }
- retval = (buf_write(curbuf, ffname, fname, eap->line1, eap->line2,
- eap->append, eap->forceit, TRUE, FALSE));
- theend:
- #ifdef USE_BROWSE
- vim_free(browse_file);
- #endif
- vim_free(free_fname);
- return retval;
- }
- /*
- * try to abandon current file and edit a new or existing file
- * 'fnum' is the number of the file, if zero use ffname/sfname
- *
- * return 1 for "normal" error, 2 for "not written" error, 0 for success
- * -1 for succesfully opening another file
- * 'lnum' is the line number for the cursor in the new file (if non-zero).
- */
- int
- getfile(fnum, ffname, sfname, setpm, lnum, forceit)
- int fnum;
- char_u *ffname;
- char_u *sfname;
- int setpm;
- linenr_t lnum;
- int forceit;
- {
- int other;
- int retval;
- char_u *free_me = NULL;
- if (fnum == 0)
- {
- fname_expand(&ffname, &sfname); /* make ffname full path, set sfname */
- other = otherfile(ffname);
- free_me = ffname; /* has been allocated, free() later */
- }
- else
- other = (fnum != curbuf->b_fnum);
- if (other)
- ++no_wait_return; /* don't wait for autowrite message */
- if (other && !forceit && curbuf->b_nwindows == 1 && !p_hid
- && curbuf_changed() && autowrite(curbuf, forceit) == FAIL)
- {
- if (other)
- --no_wait_return;
- emsg(e_nowrtmsg);
- retval = 2; /* file has been changed */
- goto theend;
- }
- if (other)
- --no_wait_return;
- if (setpm)
- setpcmark();
- if (!other)
- {
- if (lnum != 0)
- curwin->w_cursor.lnum = lnum;
- check_cursor_lnum();
- beginline(BL_SOL | BL_FIX);
- retval = 0; /* it's in the same file */
- }
- else if (do_ecmd(fnum, ffname, sfname, NULL, lnum,
- (p_hid ? ECMD_HIDE : 0) + (forceit ? ECMD_FORCEIT : 0)) == OK)
- retval = -1; /* opened another file */
- else
- retval = 1; /* error encountered */
- theend:
- vim_free(free_me);
- return retval;
- }