diff options
Diffstat (limited to 'src/nvim/option.c')
-rw-r--r-- | src/nvim/option.c | 1780 |
1 files changed, 809 insertions, 971 deletions
diff --git a/src/nvim/option.c b/src/nvim/option.c index 596bc72cd3..f236392f4a 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -21,14 +21,18 @@ #define IN_OPTION_C #include <assert.h> +#include <ctype.h> #include <inttypes.h> #include <limits.h> #include <stdbool.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> -#include "nvim/arglist.h" +#include "auto/config.h" +#include "nvim/api/private/defs.h" #include "nvim/ascii.h" +#include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/change.h" #include "nvim/charset.h" @@ -36,23 +40,26 @@ #include "nvim/decoration_provider.h" #include "nvim/diff.h" #include "nvim/drawscreen.h" -#include "nvim/edit.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" +#include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" #include "nvim/ex_session.h" -#include "nvim/fileio.h" #include "nvim/fold.h" #include "nvim/garray.h" -#include "nvim/getchar.h" -#include "nvim/hardcopy.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" +#include "nvim/grid_defs.h" #include "nvim/highlight.h" #include "nvim/highlight_group.h" #include "nvim/indent.h" #include "nvim/indent_c.h" +#include "nvim/insexpand.h" #include "nvim/keycodes.h" #include "nvim/locale.h" +#include "nvim/log.h" #include "nvim/macros.h" #include "nvim/mapping.h" #include "nvim/mbyte.h" @@ -65,30 +72,32 @@ #include "nvim/normal.h" #include "nvim/ops.h" #include "nvim/option.h" +#include "nvim/option_defs.h" #include "nvim/optionstr.h" #include "nvim/os/os.h" -#include "nvim/os_unix.h" #include "nvim/path.h" #include "nvim/popupmenu.h" +#include "nvim/pos.h" #include "nvim/regexp.h" +#include "nvim/runtime.h" #include "nvim/screen.h" -#include "nvim/search.h" +#include "nvim/sign_defs.h" #include "nvim/spell.h" #include "nvim/spellfile.h" #include "nvim/spellsuggest.h" #include "nvim/strings.h" -#include "nvim/syntax.h" +#include "nvim/tag.h" +#include "nvim/terminal.h" +#include "nvim/types.h" #include "nvim/ui.h" -#include "nvim/ui_compositor.h" #include "nvim/undo.h" #include "nvim/vim.h" #include "nvim/window.h" -#ifdef WIN32 +#ifdef MSWIN # include "nvim/os/pty_conpty_win.h" #endif #include "nvim/api/extmark.h" #include "nvim/api/private/helpers.h" -#include "nvim/api/vim.h" #include "nvim/lua/executor.h" #include "nvim/os/input.h" #include "nvim/os/lang.h" @@ -106,34 +115,6 @@ static char e_number_required_after_equal[] static char e_preview_window_already_exists[] = N_("E590: A preview window already exists"); -/* - * The options that are local to a window or buffer have "indir" set to one of - * these values. Special values: - * PV_NONE: global option. - * PV_WIN is added: window-local option - * PV_BUF is added: buffer-local option - * PV_BOTH is added: global option which also has a local value. - */ -#define PV_BOTH 0x1000 -#define PV_WIN 0x2000 -#define PV_BUF 0x4000 -#define PV_MASK 0x0fff -#define OPT_WIN(x) (idopt_T)(PV_WIN + (int)(x)) -#define OPT_BUF(x) (idopt_T)(PV_BUF + (int)(x)) -#define OPT_BOTH(x) (idopt_T)(PV_BOTH + (int)(x)) - -// WV_ and BV_ values get typecasted to this for the "indir" field -typedef enum { - PV_NONE = 0, - PV_MAXVAL = 0xffff, // to avoid warnings for value out of range -} idopt_T; - -/* - * Options local to a window have a value local to a buffer and global to all - * buffers. Indicate this by setting "var" to VAR_WIN. - */ -#define VAR_WIN ((char_u *)-1) - static char *p_term = NULL; static char *p_ttytype = NULL; @@ -151,27 +132,12 @@ static long p_tw_nopaste; static long p_wm_nopaste; static char *p_vsts_nopaste; -typedef struct vimoption { - char *fullname; // full option name - char *shortname; // permissible abbreviation - uint32_t flags; // see below - char_u *var; // global option: pointer to variable; - // window-local option: VAR_WIN; - // buffer-local option: global value - idopt_T indir; // global option: PV_NONE; - // local option: indirect option index - char_u *def_val; // default values for variable (neovim!!) - LastSet last_set; // script in which the option was last set -} vimoption_T; - -/* - * options[] is initialized here. - * The order of the options MUST be alphabetic for ":set all" and findoption(). - * All option names MUST start with a lowercase letter (for findoption()). - * Exception: "t_" options are at the end. - * The options with a NULL variable are 'hidden': a set command for them is - * ignored and they are not printed. - */ +// options[] is initialized here. +// The order of the options MUST be alphabetic for ":set all" and findoption(). +// All option names MUST start with a lowercase letter (for findoption()). +// Exception: "t_" options are at the end. +// The options with a NULL variable are 'hidden': a set command for them is +// ignored and they are not printed. #ifdef INCLUDE_GENERATED_DECLARATIONS # include "options.generated.h" @@ -179,10 +145,24 @@ typedef struct vimoption { #define OPTION_COUNT ARRAY_SIZE(options) +typedef enum { + OP_NONE = 0, + OP_ADDING, ///< "opt+=arg" + OP_PREPENDING, ///< "opt^=arg" + OP_REMOVING, ///< "opt-=arg" +} set_op_T; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "option.c.generated.h" #endif +void set_init_tablocal(void) +{ + // susy baka: cmdheight calls itself OPT_GLOBAL but is really tablocal! + int ch_idx = findoption("cmdheight"); + p_ch = (long)options[ch_idx].def_val; +} + /// Initialize the options, first part. /// /// Called only once from main(), just after creating the first buffer. @@ -197,10 +177,8 @@ void set_init_1(bool clean_arg) langmap_init(); - /* - * Find default value for 'shell' option. - * Don't use it if it is empty. - */ + // Find default value for 'shell' option. + // Don't use it if it is empty. { const char *shell = os_getenv("SHELL"); if (shell != NULL) { @@ -215,10 +193,8 @@ void set_init_1(bool clean_arg) } } - /* - * Set the default for 'backupskip' to include environment variables for - * temp files. - */ + // Set the default for 'backupskip' to include environment variables for + // temp files. { #ifdef UNIX static char *(names[4]) = { "", "TMPDIR", "TEMP", "TMP" }; @@ -240,7 +216,7 @@ void set_init_1(bool clean_arg) p = "/tmp"; # endif mustfree = false; - } else + } else // NOLINT(readability/braces) #endif { p = vim_getenv(names[n]); @@ -252,7 +228,7 @@ void set_init_1(bool clean_arg) xstrlcpy(item, p, len); add_pathsep(item); xstrlcat(item, "*", len); - if (find_dup_item(ga.ga_data, (char_u *)item, options[opt_idx].flags) + if (find_dup_item(ga.ga_data, item, options[opt_idx].flags) == NULL) { ga_grow(&ga, (int)len); if (!GA_EMPTY(&ga)) { @@ -275,15 +251,15 @@ void set_init_1(bool clean_arg) } { - char_u *cdpath; - char_u *buf; + char *cdpath; + char *buf; int i; int j; // Initialize the 'cdpath' option's default value. - cdpath = (char_u *)vim_getenv("CDPATH"); + cdpath = vim_getenv("CDPATH"); if (cdpath != NULL) { - buf = xmalloc(2 * STRLEN(cdpath) + 2); + buf = xmalloc(2 * strlen(cdpath) + 2); { buf[0] = ','; // start with ",", current dir first j = 1; @@ -310,28 +286,6 @@ void set_init_1(bool clean_arg) } } -#if defined(MSWIN) || defined(MAC) - // Set print encoding on platforms that don't default to latin1 - set_string_default("printencoding", "hp-roman8", false); -#endif - - // 'printexpr' must be allocated to be able to evaluate it. - set_string_default("printexpr", -#ifdef UNIX - "system(['lpr'] " - "+ (empty(&printdevice)?[]:['-P', &printdevice]) " - "+ [v:fname_in])" - ". delete(v:fname_in)" - "+ v:shell_error", -#elif defined(MSWIN) - "system(['copy', v:fname_in, " - "empty(&printdevice)?'LPT1':&printdevice])" - ". delete(v:fname_in)", -#else - "", -#endif - false); - char *backupdir = stdpaths_user_state_subpath("backup", 2, true); const size_t backupdir_len = strlen(backupdir); backupdir = xrealloc(backupdir, backupdir_len + 3); @@ -354,10 +308,8 @@ void set_init_1(bool clean_arg) rtp = NULL; // ownership taken } - /* - * Set all the options (except the terminal options) to their default - * value. Also set the global value for local options. - */ + // Set all the options (except the terminal options) to their default + // value. Also set the global value for local options. set_options_default(0); curbuf->b_p_initialized = true; @@ -380,15 +332,13 @@ void set_init_1(bool clean_arg) // didset_options() because it only depends on 'encoding'. init_spell_chartab(); - /* - * Expand environment variables and things like "~" for the defaults. - * If option_expand() returns non-NULL the variable is expanded. This can - * only happen for non-indirect options. - * Also set the default to the expanded value, so ":set" does not list - * them. - * Don't set the P_ALLOCED flag, because we don't want to free the - * default. - */ + // Expand environment variables and things like "~" for the defaults. + // If option_expand() returns non-NULL the variable is expanded. This can + // only happen for non-indirect options. + // Also set the default to the expanded value, so ":set" does not list + // them. + // Don't set the P_ALLOCED flag, because we don't want to free the + // default. for (opt_idx = 0; options[opt_idx].fullname; opt_idx++) { if (options[opt_idx].flags & P_NO_DEF_EXP) { continue; @@ -398,7 +348,7 @@ void set_init_1(bool clean_arg) && options[opt_idx].var != NULL) { p = _(*(char **)options[opt_idx].var); } else { - p = (char *)option_expand(opt_idx, NULL); + p = option_expand(opt_idx, NULL); } if (p != NULL) { p = xstrdup(p); @@ -406,7 +356,7 @@ void set_init_1(bool clean_arg) if (options[opt_idx].flags & P_DEF_ALLOCED) { xfree(options[opt_idx].def_val); } - options[opt_idx].def_val = (char_u *)p; + options[opt_idx].def_val = p; options[opt_idx].flags |= P_DEF_ALLOCED; } } @@ -434,7 +384,7 @@ void set_init_1(bool clean_arg) // use utf-8 as 'default' if locale encoding can't be detected. p = (char_u *)xmemdupz(S_LEN("utf-8")); } - fenc_default = p; + fenc_default = (char *)p; #ifdef HAVE_WORKING_LIBINTL // GNU gettext 0.10.37 supports this feature: set the codeset used for @@ -463,12 +413,12 @@ static void set_option_default(int opt_idx, int opt_flags) // freeing and allocating the value. if (options[opt_idx].indir != PV_NONE) { set_string_option_direct(NULL, opt_idx, - (char *)options[opt_idx].def_val, opt_flags, 0); + options[opt_idx].def_val, opt_flags, 0); } else { if ((opt_flags & OPT_FREE) && (flags & P_ALLOCED)) { free_string_option(*(char **)(varp)); } - *(char_u **)varp = options[opt_idx].def_val; + *(char **)varp = options[opt_idx].def_val; options[opt_idx].flags &= ~P_ALLOCED; } } else if (flags & P_NUM) { @@ -547,16 +497,14 @@ static void set_string_default(const char *name, char *val, bool allocated) xfree(options[opt_idx].def_val); } - options[opt_idx].def_val = allocated - ? (char_u *)val - : (char_u *)xstrdup(val); + options[opt_idx].def_val = allocated ? val : xstrdup(val); options[opt_idx].flags |= P_DEF_ALLOCED; } } -// For an option value that contains comma separated items, find "newval" in -// "origval". Return NULL if not found. -static char_u *find_dup_item(char_u *origval, const char_u *newval, uint32_t flags) +/// For an option value that contains comma separated items, find "newval" in +/// "origval". Return NULL if not found. +static char *find_dup_item(char *origval, const char *newval, uint32_t flags) FUNC_ATTR_NONNULL_ARG(2) { int bs = 0; @@ -565,10 +513,10 @@ static char_u *find_dup_item(char_u *origval, const char_u *newval, uint32_t fla return NULL; } - const size_t newlen = STRLEN(newval); - for (char_u *s = origval; *s != NUL; s++) { + const size_t newlen = strlen(newval); + for (char *s = origval; *s != NUL; s++) { if ((!(flags & P_COMMA) || s == origval || (s[-1] == ',' && !(bs & 1))) - && STRNCMP(s, newval, newlen) == 0 + && strncmp(s, newval, newlen) == 0 && (!(flags & P_COMMA) || s[newlen] == ',' || s[newlen] == NUL)) { return s; } @@ -589,11 +537,9 @@ static char_u *find_dup_item(char_u *origval, const char_u *newval, uint32_t fla /// Used for 'lines' and 'columns'. void set_number_default(char *name, long val) { - int opt_idx; - - opt_idx = findoption(name); + int opt_idx = findoption(name); if (opt_idx >= 0) { - options[opt_idx].def_val = (char_u *)(intptr_t)val; + options[opt_idx].def_val = (char *)(intptr_t)val; } } @@ -608,7 +554,7 @@ void free_all_options(void) free_string_option(*(char **)options[i].var); } if (options[i].flags & P_DEF_ALLOCED) { - free_string_option((char *)options[i].def_val); + free_string_option(options[i].def_val); } } else if (options[i].var != VAR_WIN && (options[i].flags & P_STRING)) { // buffer-local option: free global value @@ -616,6 +562,7 @@ void free_all_options(void) } } free_operatorfunc_option(); + free_tagfunc_option(); } #endif @@ -635,15 +582,12 @@ void set_init_2(bool headless) } comp_col(); - /* - * 'window' is only for backwards compatibility with Vi. - * Default is Rows - 1. - */ + // 'window' is only for backwards compatibility with Vi. + // Default is Rows - 1. if (!option_was_set("window")) { p_window = Rows - 1; } set_number_default("window", Rows - 1); - (void)parse_printoptions(); // parse 'printoptions' default value } /// Initialize the options, part three: After reading the .vimrc @@ -664,42 +608,42 @@ void set_init_3(void) : !(options[idx_sp].flags & P_WAS_SET); size_t len = 0; - char_u *p = (char_u *)invocation_path_tail(p_sh, &len); - p = vim_strnsave(p, len); + char *p = (char *)invocation_path_tail(p_sh, &len); + p = xstrnsave(p, len); { // // Default for p_sp is "| tee", for p_srr is ">". // For known shells it is changed here to include stderr. // - if (FNAMECMP(p, "csh") == 0 - || FNAMECMP(p, "tcsh") == 0) { + if (path_fnamecmp(p, "csh") == 0 + || path_fnamecmp(p, "tcsh") == 0) { if (do_sp) { p_sp = "|& tee"; - options[idx_sp].def_val = (char_u *)p_sp; + options[idx_sp].def_val = p_sp; } if (do_srr) { p_srr = ">&"; - options[idx_srr].def_val = (char_u *)p_srr; + options[idx_srr].def_val = p_srr; } - } else if (FNAMECMP(p, "sh") == 0 - || FNAMECMP(p, "ksh") == 0 - || FNAMECMP(p, "mksh") == 0 - || FNAMECMP(p, "pdksh") == 0 - || FNAMECMP(p, "zsh") == 0 - || FNAMECMP(p, "zsh-beta") == 0 - || FNAMECMP(p, "bash") == 0 - || FNAMECMP(p, "fish") == 0 - || FNAMECMP(p, "ash") == 0 - || FNAMECMP(p, "dash") == 0) { + } else if (path_fnamecmp(p, "sh") == 0 + || path_fnamecmp(p, "ksh") == 0 + || path_fnamecmp(p, "mksh") == 0 + || path_fnamecmp(p, "pdksh") == 0 + || path_fnamecmp(p, "zsh") == 0 + || path_fnamecmp(p, "zsh-beta") == 0 + || path_fnamecmp(p, "bash") == 0 + || path_fnamecmp(p, "fish") == 0 + || path_fnamecmp(p, "ash") == 0 + || path_fnamecmp(p, "dash") == 0) { // Always use POSIX shell style redirection if we reach this if (do_sp) { p_sp = "2>&1| tee"; - options[idx_sp].def_val = (char_u *)p_sp; + options[idx_sp].def_val = p_sp; } if (do_srr) { p_srr = ">%s 2>&1"; - options[idx_srr].def_val = (char_u *)p_srr; + options[idx_srr].def_val = p_srr; } } xfree(p); @@ -732,14 +676,14 @@ void set_helplang_default(const char *lang) int idx = findoption("hlg"); if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) { if (options[idx].flags & P_ALLOCED) { - free_string_option((char *)p_hlg); + free_string_option(p_hlg); } - p_hlg = (char_u *)xmemdupz(lang, lang_len); + p_hlg = xmemdupz(lang, lang_len); // zh_CN becomes "cn", zh_TW becomes "tw". - if (STRNICMP(p_hlg, "zh_", 3) == 0 && STRLEN(p_hlg) >= 5) { - p_hlg[0] = (char_u)TOLOWER_ASC(p_hlg[3]); - p_hlg[1] = (char_u)TOLOWER_ASC(p_hlg[4]); - } else if (STRLEN(p_hlg) >= 1 && *p_hlg == 'C') { + if (STRNICMP(p_hlg, "zh_", 3) == 0 && strlen(p_hlg) >= 5) { + p_hlg[0] = (char)TOLOWER_ASC(p_hlg[3]); + p_hlg[1] = (char)TOLOWER_ASC(p_hlg[4]); + } else if (strlen(p_hlg) >= 1 && *p_hlg == 'C') { // any C like setting, such as C.UTF-8, becomes "en" p_hlg[0] = 'e'; p_hlg[1] = 'n'; @@ -756,21 +700,17 @@ void set_helplang_default(const char *lang) /// machine. void set_title_defaults(void) { - int idx1; - - /* - * If GUI is (going to be) used, we can always set the window title and - * icon name. Saves a bit of time, because the X11 display server does - * not need to be contacted. - */ - idx1 = findoption("title"); + // If GUI is (going to be) used, we can always set the window title and + // icon name. Saves a bit of time, because the X11 display server does + // not need to be contacted. + int idx1 = findoption("title"); if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) { - options[idx1].def_val = (char_u *)(intptr_t)0; + options[idx1].def_val = 0; p_title = 0; } idx1 = findoption("icon"); if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) { - options[idx1].def_val = (char_u *)(intptr_t)0; + options[idx1].def_val = 0; p_icon = 0; } } @@ -790,6 +730,347 @@ void ex_set(exarg_T *eap) (void)do_set(eap->arg, flags); } +/// Part of do_set() for string options. +/// @return FAIL on failure, do not process further options. +static int do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, set_op_T op_arg, + uint32_t flags, char *varp_arg, char *errbuf, size_t errbuflen, + int *value_checked, char **errmsg) +{ + char *arg = *argp; + set_op_T op = op_arg; + char *varp = varp_arg; + char *save_arg = NULL; + char *s = NULL; + char *oldval = NULL; // previous value if *varp + char *origval = NULL; + char_u *origval_l = NULL; + char_u *origval_g = NULL; + char *saved_origval = NULL; + char *saved_origval_l = NULL; + char *saved_origval_g = NULL; + char *saved_newval = NULL; + char whichwrap[80]; + + // When using ":set opt=val" for a global option + // with a local value the local value will be + // reset, use the global value here. + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0 + && ((int)options[opt_idx].indir & PV_BOTH)) { + varp = (char *)options[opt_idx].var; + } + + // The old value is kept until we are sure that the new value is valid. + oldval = *(char **)varp; + + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { + origval_l = *(char_u **)get_varp_scope(&(options[opt_idx]), OPT_LOCAL); + origval_g = *(char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); + + // A global-local string option might have an empty option as value to + // indicate that the global value should be used. + if (((int)options[opt_idx].indir & PV_BOTH) && origval_l == (char_u *)empty_option) { + origval_l = origval_g; + } + } + + // When setting the local value of a global option, the old value may be + // the global value. + if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags & OPT_LOCAL)) { + origval = *(char **)get_varp(&options[opt_idx]); + } else { + origval = oldval; + } + + char *newval; + if (nextchar == '&') { // set to default val + newval = options[opt_idx].def_val; + // expand environment variables and ~ since the default value was + // already expanded, only required when an environment variable was set + // later + if (newval == NULL) { + newval = empty_option; + } else if (!(options[opt_idx].flags & P_NO_DEF_EXP)) { + s = option_expand(opt_idx, newval); + if (s == NULL) { + s = newval; + } + newval = xstrdup(s); + } else { + newval = xstrdup(newval); + } + } else if (nextchar == '<') { // set to global val + newval = xstrdup(*(char **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL)); + } else { + arg++; // jump to after the '=' or ':' + + // Set 'keywordprg' to ":help" if an empty + // value was passed to :set by the user. + if (varp == (char *)&p_kp && (*arg == NUL || *arg == ' ')) { + save_arg = arg; + arg = ":help"; + } else if (varp == (char *)&p_bs && ascii_isdigit(**(char_u **)varp)) { + // Convert 'backspace' number to string, for + // adding, prepending and removing string. + int i = getdigits_int((char **)varp, true, 0); + switch (i) { + case 0: + *(char **)varp = empty_option; + break; + case 1: + *(char_u **)varp = (char_u *)xstrdup("indent,eol"); + break; + case 2: + *(char_u **)varp = (char_u *)xstrdup("indent,eol,start"); + break; + case 3: + *(char_u **)varp = (char_u *)xstrdup("indent,eol,nostop"); + break; + } + xfree(oldval); + if (origval == oldval) { + origval = *(char **)varp; + } + if (origval_l == (char_u *)oldval) { + origval_l = *(char_u **)varp; + } + if (origval_g == (char_u *)oldval) { + origval_g = *(char_u **)varp; + } + oldval = *(char **)varp; + } else if (varp == (char *)&p_ww && ascii_isdigit(*arg)) { + // Convert 'whichwrap' number to string, for backwards compatibility + // with Vim 3.0. + *whichwrap = NUL; + int i = getdigits_int(&arg, true, 0); + if (i & 1) { + xstrlcat(whichwrap, "b,", sizeof(whichwrap)); + } + if (i & 2) { + xstrlcat(whichwrap, "s,", sizeof(whichwrap)); + } + if (i & 4) { + xstrlcat(whichwrap, "h,l,", sizeof(whichwrap)); + } + if (i & 8) { + xstrlcat(whichwrap, "<,>,", sizeof(whichwrap)); + } + if (i & 16) { + xstrlcat(whichwrap, "[,],", sizeof(whichwrap)); + } + if (*whichwrap != NUL) { // remove trailing , + whichwrap[strlen(whichwrap) - 1] = NUL; + } + save_arg = arg; + arg = whichwrap; + } else if (*arg == '>' && (varp == (char *)&p_dir || varp == (char *)&p_bdir)) { + // Remove '>' before 'dir' and 'bdir', for backwards compatibility with + // version 3.0 + arg++; + } + + // Copy the new string into allocated memory. + // Can't use set_string_option_direct(), because we need to remove the + // backslashes. + + // get a bit too much + size_t newlen = strlen(arg) + 1; + if (op != OP_NONE) { + newlen += strlen(origval) + 1; + } + newval = xmalloc(newlen); + s = newval; + + // Copy the string, skip over escaped chars. + // For MS-Windows backslashes before normal file name characters + // are not removed, and keep backslash at start, for "\\machine\path", + // but do remove it for "\\\\machine\\path". + // The reverse is found in ExpandOldSetting(). + while (*arg != NUL && !ascii_iswhite(*arg)) { + if (*arg == '\\' && arg[1] != NUL +#ifdef BACKSLASH_IN_FILENAME + && !((flags & P_EXPAND) + && vim_isfilec((uint8_t)arg[1]) + && !ascii_iswhite(arg[1]) + && (arg[1] != '\\' + || (s == newval && arg[2] != '\\'))) +#endif + ) { + arg++; // remove backslash + } + int i = utfc_ptr2len(arg); + if (i > 1) { + // copy multibyte char + memmove(s, arg, (size_t)i); + arg += i; + s += i; + } else { + *s++ = *arg++; + } + } + *s = NUL; + + // Expand environment variables and ~. + // Don't do it when adding without inserting a comma. + if (op == OP_NONE || (flags & P_COMMA)) { + s = option_expand(opt_idx, newval); + if (s != NULL) { + xfree(newval); + newlen = (unsigned)strlen(s) + 1; + if (op != OP_NONE) { + newlen += (unsigned)strlen(origval) + 1; + } + newval = xmalloc(newlen); + STRCPY(newval, s); + } + } + + // locate newval[] in origval[] when removing it + // and when adding to avoid duplicates + int len = 0; + if (op == OP_REMOVING || (flags & P_NODUP)) { + len = (int)strlen(newval); + s = find_dup_item(origval, newval, flags); + + // do not add if already there + if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) { + op = OP_NONE; + STRCPY(newval, origval); + } + + // if no duplicate, move pointer to end of original value + if (s == NULL) { + s = origval + (int)strlen(origval); + } + } + + // concatenate the two strings; add a ',' if needed + if (op == OP_ADDING || op == OP_PREPENDING) { + int comma = ((flags & P_COMMA) && *origval != NUL && *newval != NUL); + if (op == OP_ADDING) { + len = (int)strlen(origval); + // Strip a trailing comma, would get 2. + if (comma && len > 1 + && (flags & P_ONECOMMA) == P_ONECOMMA + && origval[len - 1] == ',' + && origval[len - 2] != '\\') { + len--; + } + memmove(newval + len + comma, newval, strlen(newval) + 1); + memmove(newval, origval, (size_t)len); + } else { + len = (int)strlen(newval); + STRMOVE(newval + len + comma, origval); + } + if (comma) { + newval[len] = ','; + } + } + + // Remove newval[] from origval[]. (Note: "len" has been set above and + // is used here). + if (op == OP_REMOVING) { + STRCPY(newval, origval); + if (*s) { + // may need to remove a comma + if (flags & P_COMMA) { + if (s == origval) { + // include comma after string + if (s[len] == ',') { + len++; + } + } else { + // include comma before string + s--; + len++; + } + } + STRMOVE(newval + (s - origval), s + len); + } + } + + if (flags & P_FLAGLIST) { + // Remove flags that appear twice. + for (s = newval; *s;) { + // if options have P_FLAGLIST and P_ONECOMMA such as + // 'whichwrap' + if (flags & P_ONECOMMA) { + if (*s != ',' && *(s + 1) == ',' + && vim_strchr(s + 2, *s) != NULL) { + // Remove the duplicated value and the next comma. + STRMOVE(s, s + 2); + continue; + } + } else { + if ((!(flags & P_COMMA) || *s != ',') + && vim_strchr(s + 1, *s) != NULL) { + STRMOVE(s, s + 1); + continue; + } + } + s++; + } + } + + if (save_arg != NULL) { + arg = save_arg; // arg was temporarily changed, restore it + } + } + + // Set the new value. + *(char_u **)(varp) = (char_u *)newval; + + // origval may be freed by did_set_string_option(), make a copy. + saved_origval = (origval != NULL) ? xstrdup(origval) : NULL; + saved_origval_l = (origval_l != NULL) ? xstrdup((char *)origval_l) : NULL; + saved_origval_g = (origval_g != NULL) ? xstrdup((char *)origval_g) : NULL; + + // newval (and varp) may become invalid if the buffer is closed by + // autocommands. + saved_newval = (newval != NULL) ? xstrdup(newval) : NULL; + + { + uint32_t *p = insecure_flag(curwin, opt_idx, opt_flags); + const int secure_saved = secure; + + // When an option is set in the sandbox, from a modeline or in secure + // mode, then deal with side effects in secure mode. Also when the + // value was set with the P_INSECURE flag and is not completely + // replaced. + if ((opt_flags & OPT_MODELINE) + || sandbox != 0 + || (op != OP_NONE && (*p & P_INSECURE))) { + secure = 1; + } + + // Handle side effects, and set the global value for ":set" on local + // options. Note: when setting 'syntax' or 'filetype' autocommands may + // be triggered that can cause havoc. + *errmsg = did_set_string_option(opt_idx, (char **)varp, oldval, + errbuf, errbuflen, + opt_flags, value_checked); + + secure = secure_saved; + } + + if (*errmsg == NULL) { + if (!starting) { + trigger_optionset_string(opt_idx, opt_flags, saved_origval, saved_origval_l, + saved_origval_g, saved_newval); + } + if (options[opt_idx].flags & P_UI_OPTION) { + ui_call_option_set(cstr_as_string(options[opt_idx].fullname), + STRING_OBJ(cstr_as_string(saved_newval))); + } + } + xfree(saved_origval); + xfree(saved_origval_l); + xfree(saved_origval_g); + xfree(saved_newval); + + *argp = arg; + return *errmsg == NULL ? OK : FAIL; +} + /// Parse 'arg' for option settings. /// /// 'arg' may be IObuff, but only when no errors can be present and option @@ -807,23 +1088,7 @@ void ex_set(exarg_T *eap) /// @return FAIL if an error is detected, OK otherwise int do_set(char *arg, int opt_flags) { - int opt_idx; - char *errmsg; - char errbuf[80]; - char *startarg; - int prefix; // 1: nothing, 0: "no", 2: "inv" in front of name - char_u nextchar; // next non-white char after option name - int afterchar; // character just after option name - int len; - int i; - varnumber_T value; - int key; - uint32_t flags; // flags for current option - char *varp = NULL; // pointer to variable for current option int did_show = false; // already showed one value - int adding; // "opt+=arg" - int prepending; // "opt^=arg" - int removing; // "opt-=arg" if (*arg == NUL) { showoptions(0, opt_flags); @@ -831,16 +1096,16 @@ int do_set(char *arg, int opt_flags) goto theend; } + char errbuf[80]; + while (*arg != NUL) { // loop to process all options - errmsg = NULL; - startarg = arg; // remember for error message + char *errmsg = NULL; + char *startarg = arg; // remember for error message - if (STRNCMP(arg, "all", 3) == 0 && !isalpha(arg[3]) + if (strncmp(arg, "all", 3) == 0 && !isalpha(arg[3]) && !(opt_flags & OPT_MODELINE)) { - /* - * ":set all" show all options. - * ":set all&" set all options to their default value. - */ + // ":set all" show all options. + // ":set all&" set all options to their default value. arg += 3; if (*arg == '&') { arg++; @@ -855,17 +1120,19 @@ int do_set(char *arg, int opt_flags) did_show = true; } } else { - prefix = 1; - if (STRNCMP(arg, "no", 2) == 0) { + int prefix = 1; // 1: nothing, 0: "no", 2: "inv" in front of name + if (strncmp(arg, "no", 2) == 0) { prefix = 0; arg += 2; - } else if (STRNCMP(arg, "inv", 3) == 0) { + } else if (strncmp(arg, "inv", 3) == 0) { prefix = 2; arg += 3; } // find end of name - key = 0; + int key = 0; + int len; + int opt_idx; if (*arg == '<') { opt_idx = -1; // look out for <t_>;> @@ -886,7 +1153,7 @@ int do_set(char *arg, int opt_flags) } len++; if (opt_idx == -1) { - key = find_key_option((char_u *)arg + 1, true); + key = find_key_option(arg + 1, true); } } else { len = 0; @@ -900,40 +1167,41 @@ int do_set(char *arg, int opt_flags) } opt_idx = findoption_len((const char *)arg, (size_t)len); if (opt_idx == -1) { - key = find_key_option((char_u *)arg, false); + key = find_key_option(arg, false); } } // remember character after option name - afterchar = (uint8_t)arg[len]; + int afterchar = (uint8_t)arg[len]; // skip white space, allow ":set ai ?" while (ascii_iswhite(arg[len])) { len++; } - adding = false; - prepending = false; - removing = false; + set_op_T op = OP_NONE; if (arg[len] != NUL && arg[len + 1] == '=') { if (arg[len] == '+') { - adding = true; // "+=" + op = OP_ADDING; // "+=" len++; } else if (arg[len] == '^') { - prepending = true; // "^=" + op = OP_PREPENDING; // "^=" len++; } else if (arg[len] == '-') { - removing = true; // "-=" + op = OP_REMOVING; // "-=" len++; } } - nextchar = (uint8_t)arg[len]; + char_u nextchar = (uint8_t)arg[len]; // next non-white char after option name if (opt_idx == -1 && key == 0) { // found a mismatch: skip errmsg = e_unknown_option; goto skip; } + uint32_t flags; // flags for current option + char *varp = NULL; // pointer to variable for current option + if (opt_idx >= 0) { if (options[opt_idx].var == NULL) { // hidden option: skip // Only give an error message when requesting the value of @@ -1016,9 +1284,7 @@ int do_set(char *arg, int opt_flags) || (prefix == 1 && vim_strchr("=:&<", nextchar) == NULL && !(flags & P_BOOL))) { - /* - * print value - */ + // print value if (did_show) { msg_putchar('\n'); // cursor below last one } else { @@ -1048,8 +1314,8 @@ int do_set(char *arg, int opt_flags) errmsg = e_trailing; } } else { - int value_is_replaced = !prepending && !adding && !removing; int value_checked = false; + varnumber_T value; if (flags & P_BOOL) { // boolean if (nextchar == '=' || nextchar == ':') { @@ -1057,11 +1323,9 @@ int do_set(char *arg, int opt_flags) goto skip; } - /* - * ":set opt!": invert - * ":set opt&": reset to default value - * ":set opt<": reset to global value - */ + // ":set opt!": invert + // ":set opt&": reset to default value + // ":set opt<": reset to global value if (nextchar == '!') { value = *(int *)(varp) ^ 1; } else if (nextchar == '&') { @@ -1076,10 +1340,8 @@ int do_set(char *arg, int opt_flags) OPT_GLOBAL); } } else { - /* - * ":set invopt": invert - * ":set opt" or ":set noopt": set or reset - */ + // ":set invopt": invert + // ":set opt" or ":set noopt": set or reset if (nextchar != NUL && !ascii_iswhite(afterchar)) { errmsg = e_trailing; goto skip; @@ -1130,8 +1392,9 @@ int do_set(char *arg, int opt_flags) goto skip; } } else if (*arg == '-' || ascii_isdigit(*arg)) { + int i; // Allow negative, octal and hex numbers. - vim_str2nr((char_u *)arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, true); + vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, true); if (i == 0 || (arg[i] != NUL && !ascii_iswhite(arg[i]))) { errmsg = e_number_required_after_equal; goto skip; @@ -1141,373 +1404,26 @@ int do_set(char *arg, int opt_flags) goto skip; } - if (adding) { + if (op == OP_ADDING) { value = *(long *)varp + value; } - if (prepending) { + if (op == OP_PREPENDING) { value = *(long *)varp * value; } - if (removing) { + if (op == OP_REMOVING) { value = *(long *)varp - value; } errmsg = set_num_option(opt_idx, (char_u *)varp, (long)value, errbuf, sizeof(errbuf), opt_flags); } else if (opt_idx >= 0) { // String. - char_u *save_arg = NULL; - char_u *s = NULL; - char_u *oldval = NULL; // previous value if *varp - char_u *newval; - char_u *origval = NULL; - char_u *origval_l = NULL; - char_u *origval_g = NULL; - char *saved_origval = NULL; - char *saved_origval_l = NULL; - char *saved_origval_g = NULL; - char *saved_newval = NULL; - unsigned newlen; - int comma; - - // When using ":set opt=val" for a global option - // with a local value the local value will be - // reset, use the global value here. - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0 - && ((int)options[opt_idx].indir & PV_BOTH)) { - varp = (char *)options[opt_idx].var; - } - - // The old value is kept until we are sure that the - // new value is valid. - oldval = *(char_u **)varp; - - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { - origval_l = *(char_u **)get_varp_scope(&(options[opt_idx]), OPT_LOCAL); - origval_g = *(char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); - - // A global-local string option might have an empty - // option as value to indicate that the global - // value should be used. - if (((int)options[opt_idx].indir & PV_BOTH) && origval_l == (char_u *)empty_option) { - origval_l = origval_g; - } - } - - // When setting the local value of a global - // option, the old value may be the global value. - if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags & OPT_LOCAL)) { - origval = *(char_u **)get_varp(&options[opt_idx]); - } else { - origval = oldval; - } - - if (nextchar == '&') { // set to default val - newval = options[opt_idx].def_val; - // expand environment variables and ~ since the - // default value was already expanded, only - // required when an environment variable was set - // later - if (newval == NULL) { - newval = (char_u *)empty_option; - } else if (!(options[opt_idx].flags & P_NO_DEF_EXP)) { - s = option_expand(opt_idx, newval); - if (s == NULL) { - s = newval; - } - newval = vim_strsave(s); - } else { - newval = (char_u *)xstrdup((char *)newval); - } - } else if (nextchar == '<') { // set to global val - newval = vim_strsave(*(char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL)); - } else { - arg++; // jump to after the '=' or ':' - - // Set 'keywordprg' to ":help" if an empty - // value was passed to :set by the user. - // Misuse errbuf[] for the resulting string. - if (varp == (char *)&p_kp && (*arg == NUL || *arg == ' ')) { - STRCPY(errbuf, ":help"); - save_arg = (char_u *)arg; - arg = errbuf; - } else if (varp == (char *)&p_bs && ascii_isdigit(**(char_u **)varp)) { - // Convert 'backspace' number to string, for - // adding, prepending and removing string. - i = getdigits_int((char **)varp, true, 0); - switch (i) { - case 0: - *(char **)varp = empty_option; - break; - case 1: - *(char_u **)varp = vim_strsave((char_u *)"indent,eol"); - break; - case 2: - *(char_u **)varp = vim_strsave((char_u *)"indent,eol,start"); - break; - case 3: - *(char_u **)varp = vim_strsave((char_u *)"indent,eol,nostop"); - break; - } - xfree(oldval); - if (origval == oldval) { - origval = *(char_u **)varp; - } - if (origval_l == oldval) { - origval_l = *(char_u **)varp; - } - if (origval_g == oldval) { - origval_g = *(char_u **)varp; - } - oldval = *(char_u **)varp; - } else if (varp == (char *)&p_ww && ascii_isdigit(*arg)) { - // Convert 'whichwrap' number to string, for - // backwards compatibility with Vim 3.0. - // Misuse errbuf[] for the resulting string. - *errbuf = NUL; - i = getdigits_int(&arg, true, 0); - if (i & 1) { - STRLCAT(errbuf, "b,", sizeof(errbuf)); - } - if (i & 2) { - STRLCAT(errbuf, "s,", sizeof(errbuf)); - } - if (i & 4) { - STRLCAT(errbuf, "h,l,", sizeof(errbuf)); - } - if (i & 8) { - STRLCAT(errbuf, "<,>,", sizeof(errbuf)); - } - if (i & 16) { - STRLCAT(errbuf, "[,],", sizeof(errbuf)); - } - save_arg = (char_u *)arg; - arg = errbuf; - } else if (*arg == '>' - && (varp == (char *)&p_dir - || varp == (char *)&p_bdir)) { - // Remove '>' before 'dir' and 'bdir', for - // backwards compatibility with version 3.0 - arg++; - } - - /* - * Copy the new string into allocated memory. - * Can't use set_string_option_direct(), because - * we need to remove the backslashes. - */ - // get a bit too much - newlen = (unsigned)STRLEN(arg) + 1; - if (adding || prepending || removing) { - newlen += (unsigned)STRLEN(origval) + 1; - } - newval = xmalloc(newlen); - s = newval; - - /* - * Copy the string, skip over escaped chars. - * For WIN32 backslashes before normal - * file name characters are not removed, and keep - * backslash at start, for "\\machine\path", but - * do remove it for "\\\\machine\\path". - * The reverse is found in ExpandOldSetting(). - */ - while (*arg && !ascii_iswhite(*arg)) { - if (*arg == '\\' && arg[1] != NUL -#ifdef BACKSLASH_IN_FILENAME - && !((flags & P_EXPAND) - && vim_isfilec(arg[1]) - && !ascii_iswhite(arg[1]) - && (arg[1] != '\\' - || (s == newval - && arg[2] != '\\'))) -#endif - ) { - arg++; // remove backslash - } - i = utfc_ptr2len(arg); - if (i > 1) { - // copy multibyte char - memmove(s, arg, (size_t)i); - arg += i; - s += i; - } else { - *s++ = (uint8_t)(*arg++); - } - } - *s = NUL; - - /* - * Expand environment variables and ~. - * Don't do it when adding without inserting a - * comma. - */ - if (!(adding || prepending || removing) - || (flags & P_COMMA)) { - s = option_expand(opt_idx, newval); - if (s != NULL) { - xfree(newval); - newlen = (unsigned)STRLEN(s) + 1; - if (adding || prepending || removing) { - newlen += (unsigned)STRLEN(origval) + 1; - } - newval = xmalloc(newlen); - STRCPY(newval, s); - } - } - - // locate newval[] in origval[] when removing it - // and when adding to avoid duplicates - i = 0; // init for GCC - if (removing || (flags & P_NODUP)) { - i = (int)STRLEN(newval); - s = find_dup_item(origval, newval, flags); - - // do not add if already there - if ((adding || prepending) && s != NULL) { - prepending = false; - adding = false; - STRCPY(newval, origval); - } - - // if no duplicate, move pointer to end of - // original value - if (s == NULL) { - s = origval + (int)STRLEN(origval); - } - } - - // concatenate the two strings; add a ',' if - // needed - if (adding || prepending) { - comma = ((flags & P_COMMA) && *origval != NUL - && *newval != NUL); - if (adding) { - i = (int)STRLEN(origval); - // Strip a trailing comma, would get 2. - if (comma && i > 1 - && (flags & P_ONECOMMA) == P_ONECOMMA - && origval[i - 1] == ',' - && origval[i - 2] != '\\') { - i--; - } - memmove(newval + i + comma, newval, - STRLEN(newval) + 1); - memmove(newval, origval, (size_t)i); - } else { - i = (int)STRLEN(newval); - STRMOVE(newval + i + comma, origval); - } - if (comma) { - newval[i] = ','; - } - } - - // Remove newval[] from origval[]. (Note: "i" has - // been set above and is used here). - if (removing) { - STRCPY(newval, origval); - if (*s) { - // may need to remove a comma - if (flags & P_COMMA) { - if (s == origval) { - // include comma after string - if (s[i] == ',') { - i++; - } - } else { - // include comma before string - s--; - i++; - } - } - STRMOVE(newval + (s - origval), s + i); - } - } - - if (flags & P_FLAGLIST) { - // Remove flags that appear twice. - for (s = newval; *s;) { - // if options have P_FLAGLIST and P_ONECOMMA such as - // 'whichwrap' - if (flags & P_ONECOMMA) { - if (*s != ',' && *(s + 1) == ',' - && vim_strchr((char *)s + 2, *s) != NULL) { - // Remove the duplicated value and the next comma. - STRMOVE(s, s + 2); - continue; - } - } else { - if ((!(flags & P_COMMA) || *s != ',') - && vim_strchr((char *)s + 1, *s) != NULL) { - STRMOVE(s, s + 1); - continue; - } - } - s++; - } - } - - if (save_arg != NULL) { // number for 'whichwrap' - arg = (char *)save_arg; - } - } - - // Set the new value. - *(char_u **)(varp) = newval; - - // origval may be freed by - // did_set_string_option(), make a copy. - saved_origval = (origval != NULL) ? xstrdup((char *)origval) : 0; - saved_origval_l = (origval_l != NULL) ? xstrdup((char *)origval_l) : 0; - saved_origval_g = (origval_g != NULL) ? xstrdup((char *)origval_g) : 0; - - // newval (and varp) may become invalid if the - // buffer is closed by autocommands. - saved_newval = (newval != NULL) ? xstrdup((char *)newval) : 0; - - { - uint32_t *p = insecure_flag(curwin, opt_idx, opt_flags); - const int secure_saved = secure; - - // When an option is set in the sandbox, from a - // modeline or in secure mode, then deal with side - // effects in secure mode. Also when the value was - // set with the P_INSECURE flag and is not - // completely replaced. - if ((opt_flags & OPT_MODELINE) - || sandbox != 0 - || (!value_is_replaced && (*p & P_INSECURE))) { - secure = 1; - } - - // Handle side effects, and set the global value - // for ":set" on local options. Note: when setting - // 'syntax' or 'filetype' autocommands may be - // triggered that can cause havoc. - errmsg = did_set_string_option(opt_idx, (char **)varp, (char *)oldval, - errbuf, sizeof(errbuf), - opt_flags, &value_checked); - - secure = secure_saved; - } - - if (errmsg == NULL) { - if (!starting) { - trigger_optionsset_string(opt_idx, opt_flags, saved_origval, saved_origval_l, - saved_origval_g, saved_newval); - } - if (options[opt_idx].flags & P_UI_OPTION) { - ui_call_option_set(cstr_as_string(options[opt_idx].fullname), - STRING_OBJ(cstr_as_string(saved_newval))); + if (do_set_string(opt_idx, opt_flags, &arg, nextchar, + op, flags, varp, errbuf, sizeof(errbuf), + &value_checked, &errmsg) == FAIL) { + if (errmsg != NULL) { + goto skip; } - } - xfree(saved_origval); - xfree(saved_origval_l); - xfree(saved_origval_g); - xfree(saved_newval); - - // If error detected, print the error message. - if (errmsg != NULL) { - goto skip; + break; } } else { // key code option(FIXME(tarruda): Show a warning or something @@ -1516,18 +1432,16 @@ int do_set(char *arg, int opt_flags) } if (opt_idx >= 0) { - did_set_option(opt_idx, opt_flags, value_is_replaced, value_checked); + did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked); } } skip: - /* - * Advance to next argument. - * - skip until a blank found, taking care of backslashes - * - skip blanks - * - skip one "=val" argument (for hidden options ":set gfn =xx") - */ - for (i = 0; i < 2; i++) { + // Advance to next argument. + // - skip until a blank found, taking care of backslashes + // - skip blanks + // - skip one "=val" argument (for hidden options ":set gfn =xx") + for (int i = 0; i < 2; i++) { while (*arg != NUL && !ascii_iswhite(*arg)) { if (*arg++ == '\\' && *arg != NUL) { arg++; @@ -1541,8 +1455,8 @@ skip: } if (errmsg != NULL) { - STRLCPY(IObuff, _(errmsg), IOSIZE); - i = (int)STRLEN(IObuff) + 2; + xstrlcpy(IObuff, _(errmsg), IOSIZE); + int i = (int)strlen(IObuff) + 2; if (i + (arg - startarg) < IOSIZE) { // append the argument with the error STRCAT(IObuff, ": "); @@ -1551,10 +1465,10 @@ skip: IObuff[i + (arg - startarg)] = NUL; } // make sure all characters are printable - trans_characters((char *)IObuff, IOSIZE); + trans_characters(IObuff, IOSIZE); no_wait_return++; // wait_return() done later - emsg((char *)IObuff); // show error highlighted + emsg(IObuff); // show error highlighted no_wait_return--; return FAIL; @@ -1567,11 +1481,11 @@ theend: if (silent_mode && did_show) { // After displaying option values in silent mode. silent_mode = false; - info_message = true; // use mch_msg(), not mch_errmsg() + info_message = true; // use os_msg(), not os_errmsg() msg_putchar('\n'); ui_flush(); silent_mode = true; - info_message = false; // use mch_msg(), not mch_errmsg() + info_message = false; // use os_msg(), not os_errmsg() } return OK; @@ -1605,7 +1519,7 @@ void did_set_option(int opt_idx, int opt_flags, int new_value, int value_checked int string_to_key(char_u *arg) { if (*arg == '<') { - return find_key_option(arg + 1, true); + return find_key_option((char *)arg + 1, true); } if (*arg == '^') { return CTRL_CHR(arg[1]); @@ -1629,10 +1543,8 @@ void did_set_title(void) /// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL void set_options_bin(int oldval, int newval, int opt_flags) { - /* - * The option values that are changed when 'bin' changes are - * copied when 'bin is set and restored when 'bin' is reset. - */ + // The option values that are changed when 'bin' changes are + // copied when 'bin is set and restored when 'bin' is reset. if (newval) { if (!oldval) { // switched on if (!(opt_flags & OPT_GLOBAL)) { @@ -1685,9 +1597,7 @@ void set_options_bin(int oldval, int newval, int opt_flags) /// number, return -1. int get_shada_parameter(int type) { - char_u *p; - - p = find_shada_parameter(type); + char_u *p = find_shada_parameter(type); if (p != NULL && ascii_isdigit(*p)) { return atoi((char *)p); } @@ -1718,7 +1628,7 @@ char_u *find_shada_parameter(int type) /// These string options cannot be indirect! /// If "val" is NULL expand the current value of the option. /// Return pointer to NameBuff, or NULL when not expanded. -static char_u *option_expand(int opt_idx, char_u *val) +static char *option_expand(int opt_idx, char *val) { // if option doesn't need expansion nothing to do if (!(options[opt_idx].flags & P_EXPAND) || options[opt_idx].var == NULL) { @@ -1726,30 +1636,28 @@ static char_u *option_expand(int opt_idx, char_u *val) } if (val == NULL) { - val = *(char_u **)options[opt_idx].var; + val = *(char **)options[opt_idx].var; } // If val is longer than MAXPATHL no meaningful expansion can be done, // expand_env() would truncate the string. - if (val == NULL || STRLEN(val) > MAXPATHL) { + if (val == NULL || strlen(val) > MAXPATHL) { return NULL; } - /* - * Expanding this with NameBuff, expand_env() must not be passed IObuff. - * Escape spaces when expanding 'tags', they are used to separate file - * names. - * For 'spellsuggest' expand after "file:". - */ - expand_env_esc(val, (char_u *)NameBuff, MAXPATHL, + // Expanding this with NameBuff, expand_env() must not be passed IObuff. + // Escape spaces when expanding 'tags', they are used to separate file + // names. + // For 'spellsuggest' expand after "file:". + expand_env_esc(val, NameBuff, MAXPATHL, (char_u **)options[opt_idx].var == &p_tags, false, - (char_u **)options[opt_idx].var == (char_u **)&p_sps ? (char_u *)"file:" : + (char_u **)options[opt_idx].var == (char_u **)&p_sps ? "file:" : NULL); - if (STRCMP(NameBuff, val) == 0) { // they are the same + if (strcmp(NameBuff, val) == 0) { // they are the same return NULL; } - return (char_u *)NameBuff; + return NameBuff; } /// After setting various option values: recompute variables that depend on @@ -1930,15 +1838,16 @@ void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx) int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; int indir = (int)options[opt_idx].indir; nlua_set_sctx(&script_ctx); - const LastSet last_set = { - .script_ctx = { - script_ctx.sc_sid, - script_ctx.sc_seq, - script_ctx.sc_lnum + SOURCING_LNUM - }, - current_channel_id + LastSet last_set = { + .script_ctx = script_ctx, + .channel_id = current_channel_id, }; + // Modeline already has the line number set. + if (!(opt_flags & OPT_MODELINE)) { + last_set.script_ctx.sc_lnum += SOURCING_LNUM; + } + // Remember where the option was set. For local options need to do that // in the buffer or window structure. if (both || (opt_flags & OPT_GLOBAL) || (indir & (PV_BUF|PV_WIN)) == 0) { @@ -1953,6 +1862,46 @@ void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx) } } +/// Apply the OptionSet autocommand. +static void apply_optionset_autocmd(int opt_idx, long opt_flags, long oldval, long oldval_g, + long newval, const char *errmsg) +{ + // Don't do this while starting up, failure or recursively. + if (starting || errmsg != NULL || *get_vim_var_str(VV_OPTION_TYPE) != NUL) { + return; + } + + char buf_old[12], buf_old_global[12], buf_new[12], buf_type[12]; + + vim_snprintf(buf_old, sizeof(buf_old), "%ld", oldval); + vim_snprintf(buf_old_global, sizeof(buf_old_global), "%ld", oldval_g); + vim_snprintf(buf_new, sizeof(buf_new), "%ld", newval); + vim_snprintf(buf_type, sizeof(buf_type), "%s", + (opt_flags & OPT_LOCAL) ? "local" : "global"); + set_vim_var_string(VV_OPTION_NEW, buf_new, -1); + set_vim_var_string(VV_OPTION_OLD, buf_old, -1); + set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); + if (opt_flags & OPT_LOCAL) { + set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + } + if (opt_flags & OPT_GLOBAL) { + set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old, -1); + } + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { + set_vim_var_string(VV_OPTION_COMMAND, "set", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old_global, -1); + } + if (opt_flags & OPT_MODELINE) { + set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + } + apply_autocmds(EVENT_OPTIONSET, options[opt_idx].fullname, NULL, false, NULL); + reset_v_option_vars(); +} + /// Set the value of a boolean option, taking care of side effects /// /// @param[in] opt_idx Option index in options[] table. @@ -2040,14 +1989,12 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va } else if ((int *)varp == &curbuf->b_p_ma) { // when 'modifiable' is changed, redraw the window title redraw_titles(); - } else if ((int *)varp == &curbuf->b_p_eol) { - // when 'endofline' is changed, redraw the window title - redraw_titles(); - } else if ((int *)varp == &curbuf->b_p_fixeol) { - // when 'fixeol' is changed, redraw the window title - redraw_titles(); - } else if ((int *)varp == &curbuf->b_p_bomb) { - // when 'bomb' is changed, redraw the window title and tab page text + } else if ((int *)varp == &curbuf->b_p_eof + || (int *)varp == &curbuf->b_p_eol + || (int *)varp == &curbuf->b_p_fixeol + || (int *)varp == &curbuf->b_p_bomb) { + // redraw the window title and tab page text when 'endoffile', 'endofline', + // 'fixeol' or 'bomb' is changed redraw_titles(); } else if ((int *)varp == &curbuf->b_p_bin) { // when 'bin' is set also set some other options @@ -2107,10 +2054,9 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va } redraw_titles(); modified_was_set = value; - } #ifdef BACKSLASH_IN_FILENAME - else if ((int *)varp == &p_ssl) { + } else if ((int *)varp == &p_ssl) { if (p_ssl) { psepc = '/'; psepcN = '\\'; @@ -2125,9 +2071,8 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va buflist_slash_adjust(); alist_slash_adjust(); scriptnames_slash_adjust(); - } #endif - else if ((int *)varp == &curwin->w_p_wrap) { + } else if ((int *)varp == &curwin->w_p_wrap) { // If 'wrap' is set, set w_leftcol to zero. if (curwin->w_p_wrap) { curwin->w_leftcol = 0; @@ -2149,13 +2094,14 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va if (curwin->w_p_spell) { errmsg = did_set_spelllang(curwin); } + } else if (((int *)varp == &curwin->w_p_nu || (int *)varp == &curwin->w_p_rnu) + && *curwin->w_p_stc != NUL) { // '(relative)number' + 'statuscolumn' + curwin->w_nrwidth_line_count = 0; } if ((int *)varp == &curwin->w_p_arab) { if (curwin->w_p_arab) { - /* - * 'arabic' is set, handle various sub-settings. - */ + // 'arabic' is set, handle various sub-settings. if (!p_tbidi) { // set rightleft mode if (!curwin->w_p_rl) { @@ -2172,7 +2118,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va // Arabic requires a utf-8 encoding, inform the user if it's not // set. - if (STRCMP(p_enc, "utf-8") != 0) { + if (strcmp(p_enc, "utf-8") != 0) { static char *w_arabic = N_("W17: Arabic requires UTF-8, do ':set encoding=utf-8'"); msg_source(HL_ATTR(HLF_W)); @@ -2186,9 +2132,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va // Force-set the necessary keymap for arabic. errmsg = set_option_value("keymap", 0L, "arabic", OPT_LOCAL); } else { - /* - * 'arabic' is reset, handle various sub-settings. - */ + // 'arabic' is reset, handle various sub-settings. if (!p_tbidi) { // reset rightleft mode if (curwin->w_p_rl) { @@ -2209,48 +2153,16 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va } } - /* - * End of handling side effects for bool options. - */ + // End of handling side effects for bool options. // after handling side effects, call autocommand options[opt_idx].flags |= P_WAS_SET; - // Don't do this while starting up or recursively. - if (!starting && *get_vim_var_str(VV_OPTION_TYPE) == NUL) { - char buf_old[2]; - char buf_old_global[2]; - char buf_new[2]; - char buf_type[7]; - vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%d", old_value ? true : false); - vim_snprintf(buf_old_global, ARRAY_SIZE(buf_old_global), "%d", old_global_value ? true : false); - vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%d", value ? true : false); - vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s", - (opt_flags & OPT_LOCAL) ? "local" : "global"); - set_vim_var_string(VV_OPTION_NEW, buf_new, -1); - set_vim_var_string(VV_OPTION_OLD, buf_old, -1); - set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); - if (opt_flags & OPT_LOCAL) { - set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); - } - if (opt_flags & OPT_GLOBAL) { - set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1); - set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old, -1); - } - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { - set_vim_var_string(VV_OPTION_COMMAND, "set", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); - set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old_global, -1); - } - if (opt_flags & OPT_MODELINE) { - set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); - } - apply_autocmds(EVENT_OPTIONSET, options[opt_idx].fullname, NULL, false, NULL); - reset_v_option_vars(); - } + apply_optionset_autocmd(opt_idx, opt_flags, + (long)(old_value ? true : false), + (long)(old_global_value ? true : false), + (long)(value ? true : false), NULL); if (options[opt_idx].flags & P_UI_OPTION) { ui_call_option_set(cstr_as_string(options[opt_idx].fullname), @@ -2347,6 +2259,8 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, int minval = 0; if (value < minval) { errmsg = e_positive; + } else { + p_ch_was_zero = value == 0; } } else if (pp == &p_tm) { if (value < 0) { @@ -2405,7 +2319,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, } else if (pp == &curwin->w_p_nuw || pp == &curwin->w_allbuf_opt.wo_nuw) { if (value < 1) { errmsg = e_positive; - } else if (value > 20) { + } else if (value > MAX_NUMBERWIDTH) { errmsg = e_invarg; } } else if (pp == &curbuf->b_p_iminsert || pp == &p_iminsert) { @@ -2539,7 +2453,9 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, // if p_ch changed value, change the command line height // Only compute the new window layout when startup has been // completed. Otherwise the frame sizes may be wrong. - if (p_ch != old_value && full_screen) { + if ((p_ch != old_value + || tabline_height() + global_stl_height() + topframe->fr_height != Rows - p_ch) + && full_screen) { command_height(); } } else if (pp == &p_uc) { @@ -2615,9 +2531,10 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, Rows = (int)p_lines; Columns = (int)p_columns; check_screensize(); - if (cmdline_row > Rows - p_ch && Rows > p_ch) { - assert(p_ch >= 0 && Rows - p_ch <= INT_MAX); - cmdline_row = (int)(Rows - p_ch); + int new_row = (int)(Rows - MAX(p_ch, 1)); + if (cmdline_row > new_row && Rows > p_ch) { + assert(p_ch >= 0 && new_row <= INT_MAX); + cmdline_row = new_row; } } if (p_window >= Rows || !option_was_set("window")) { @@ -2657,41 +2574,8 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, options[opt_idx].flags |= P_WAS_SET; - // Don't do this while starting up, failure or recursively. - if (!starting && errmsg == NULL && *get_vim_var_str(VV_OPTION_TYPE) == NUL) { - char buf_old[NUMBUFLEN]; - char buf_old_global[NUMBUFLEN]; - char buf_new[NUMBUFLEN]; - char buf_type[7]; - - vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%ld", old_value); - vim_snprintf(buf_old_global, ARRAY_SIZE(buf_old_global), "%ld", old_global_value); - vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%ld", value); - vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s", - (opt_flags & OPT_LOCAL) ? "local" : "global"); - set_vim_var_string(VV_OPTION_NEW, buf_new, -1); - set_vim_var_string(VV_OPTION_OLD, buf_old, -1); - set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); - if (opt_flags & OPT_LOCAL) { - set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); - } - if (opt_flags & OPT_GLOBAL) { - set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1); - set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old, -1); - } - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { - set_vim_var_string(VV_OPTION_COMMAND, "set", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); - set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old_global, -1); - } - if (opt_flags & OPT_MODELINE) { - set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); - } - apply_autocmds(EVENT_OPTIONSET, options[opt_idx].fullname, NULL, false, NULL); - reset_v_option_vars(); - } + apply_optionset_autocmd(opt_idx, opt_flags, old_value, old_global_value, + value, errmsg); if (errmsg == NULL && options[opt_idx].flags & P_UI_OPTION) { ui_call_option_set(cstr_as_string(options[opt_idx].fullname), @@ -2711,14 +2595,17 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, /// Called after an option changed: check if something needs to be redrawn. void check_redraw(uint32_t flags) { - // Careful: P_RCLR and P_RALL are a combination of other P_ flags - bool doclear = (flags & P_RCLR) == P_RCLR; - bool all = ((flags & P_RALL) == P_RALL || doclear); + // Careful: P_RALL is a combination of other P_ flags + bool all = (flags & P_RALL) == P_RALL; if ((flags & P_RSTAT) || all) { // mark all status lines and window bars dirty status_redraw_all(); } + if ((flags & P_RTABL) || all) { // mark tablines dirty + redraw_tabline = true; + } + if ((flags & P_RBUF) || (flags & P_RWIN) || all) { changed_window_setting(); } @@ -2728,9 +2615,7 @@ void check_redraw(uint32_t flags) if (flags & P_RWINONLY) { redraw_later(curwin, UPD_NOT_VALID); } - if (doclear) { - redraw_all_later(UPD_CLEAR); - } else if (all) { + if (all) { redraw_all_later(UPD_NOT_VALID); } } @@ -2744,15 +2629,14 @@ void check_redraw(uint32_t flags) int findoption_len(const char *const arg, const size_t len) { const char *s; - const char *p; static int quick_tab[27] = { 0, 0 }; // quick access table // For first call: Initialize the quick-access table. // It contains the index for the first option that starts with a certain // letter. There are 26 letters, plus the first "t_" option. if (quick_tab[1] == 0) { - p = options[0].fullname; - for (short int i = 1; (s = options[i].fullname) != NULL; i++) { + const char *p = options[0].fullname; + for (uint16_t i = 1; (s = options[i].fullname) != NULL; i++) { if (s[0] != p[0]) { if (s[0] == 't' && s[1] == '_') { quick_tab[26] = i; @@ -2797,11 +2681,11 @@ int findoption_len(const char *const arg, const size_t len) opt_idx = -1; } else { // Nvim: handle option aliases. - if (STRNCMP(options[opt_idx].fullname, "viminfo", 7) == 0) { - if (STRLEN(options[opt_idx].fullname) == 7) { + if (strncmp(options[opt_idx].fullname, "viminfo", 7) == 0) { + if (strlen(options[opt_idx].fullname) == 7) { return findoption_len("shada", 5); } - assert(STRCMP(options[opt_idx].fullname, "viminfofile") == 0); + assert(strcmp(options[opt_idx].fullname, "viminfofile") == 0); return findoption_len("shadafile", 9); } } @@ -2910,6 +2794,7 @@ int findoption(const char *const arg) /// Gets the value for an option. /// /// @param stringval NULL when only checking existence +/// @param flagsp set to the option flags (P_xxxx) (if not NULL) /// /// @returns: /// Number option: gov_number, *numval gets value. @@ -2919,7 +2804,8 @@ int findoption(const char *const arg) /// Hidden Toggle option: gov_hidden_bool. /// Hidden String option: gov_hidden_string. /// Unknown option: gov_unknown. -getoption_T get_option_value(const char *name, long *numval, char **stringval, int opt_flags) +getoption_T get_option_value(const char *name, long *numval, char **stringval, uint32_t *flagsp, + int scope) { if (get_tty_option(name, stringval)) { return gov_string; @@ -2930,7 +2816,12 @@ getoption_T get_option_value(const char *name, long *numval, char **stringval, i return gov_unknown; } - char_u *varp = (char_u *)get_varp_scope(&(options[opt_idx]), opt_flags); + char_u *varp = (char_u *)get_varp_scope(&(options[opt_idx]), scope); + + if (flagsp != NULL) { + // Return the P_xxxx option flags. + *flagsp = options[opt_idx].flags; + } if (options[opt_idx].flags & P_STRING) { if (varp == NULL) { // hidden option @@ -3021,15 +2912,13 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o if (p->indir & PV_WIN) { if (opt_type == SREQ_BUF) { return 0; // Requested buffer-local, not window-local option - } else { - rv |= SOPT_WIN; } + rv |= SOPT_WIN; } else if (p->indir & PV_BUF) { if (opt_type == SREQ_WIN) { return 0; // Requested window-local, not buffer-local option - } else { - rv |= SOPT_BUF; } + rv |= SOPT_BUF; } } @@ -3040,9 +2929,8 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o if (opt_type == SREQ_GLOBAL) { if (p->var == VAR_WIN) { return 0; - } else { - varp = p->var; } + varp = p->var; } else { if (opt_type == SREQ_BUF) { // Special case: 'modified' is b_changed, but we also want to @@ -3076,7 +2964,7 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o if (varp != NULL) { if (p->flags & P_STRING) { - *stringval = xstrdup(*(char **)(varp)); + *stringval = *(char **)(varp); } else if (p->flags & P_NUM) { *numval = *(long *)varp; } else { @@ -3087,47 +2975,10 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o return rv; } -/// Return the flags for the option at 'opt_idx'. -uint32_t get_option_flags(int opt_idx) +// Return information for option at 'opt_idx' +vimoption_T *get_option(int opt_idx) { - return options[opt_idx].flags; -} - -/// Set a flag for the option at 'opt_idx'. -void set_option_flag(int opt_idx, uint32_t flag) -{ - options[opt_idx].flags |= flag; -} - -/// Clear a flag for the option at 'opt_idx'. -void clear_option_flag(int opt_idx, uint32_t flag) -{ - options[opt_idx].flags &= ~flag; -} - -/// Returns true if the option at 'opt_idx' is a global option -bool is_global_option(int opt_idx) -{ - return options[opt_idx].indir == PV_NONE; -} - -/// Returns true if the option at 'opt_idx' is a global option which also has a -/// local value. -int is_global_local_option(int opt_idx) -{ - return options[opt_idx].indir & PV_BOTH; -} - -/// Returns true if the option at 'opt_idx' is a window-local option -bool is_window_local_option(int opt_idx) -{ - return options[opt_idx].var == VAR_WIN; -} - -/// Returns true if the option at 'opt_idx' is a hidden option -bool is_hidden_option(int opt_idx) -{ - return options[opt_idx].var == NULL; + return &options[opt_idx]; } /// Set the value of an option @@ -3149,10 +3000,7 @@ char *set_option_value(const char *const name, const long number, const char *co return NULL; // Fail silently; many old vimrcs set t_xx options. } - int opt_idx; - char_u *varp; - - opt_idx = findoption(name); + int opt_idx = findoption(name); if (opt_idx < 0) { semsg(_("E355: Unknown option: %s"), name); } else { @@ -3170,7 +3018,7 @@ char *set_option_value(const char *const name, const long number, const char *co return set_string_option(opt_idx, s, opt_flags); } - varp = (char_u *)get_varp_scope(&(options[opt_idx]), opt_flags); + char_u *varp = (char_u *)get_varp_scope(&(options[opt_idx]), opt_flags); if (varp != NULL) { // hidden option is not changed if (number == 0 && string != NULL) { int idx; @@ -3197,14 +3045,13 @@ char *set_option_value(const char *const name, const long number, const char *co numval = -1; } else { char *s = NULL; - (void)get_option_value(name, &numval, &s, OPT_GLOBAL); + (void)get_option_value(name, &numval, &s, NULL, OPT_GLOBAL); } } if (flags & P_NUM) { return set_num_option(opt_idx, varp, numval, NULL, 0, opt_flags); - } else { - return set_bool_option(opt_idx, varp, (int)numval, opt_flags); } + return set_bool_option(opt_idx, varp, (int)numval, opt_flags); } } return NULL; @@ -3222,6 +3069,12 @@ void set_option_value_give_err(const char *name, long number, const char *string } } +bool is_option_allocated(const char *name) +{ + int idx = findoption(name); + return idx >= 0 && (options[idx].flags & P_ALLOCED); +} + /// Return true if "name" is a string option. /// Returns false if option "name" does not exist. bool is_string_option(const char *name) @@ -3236,16 +3089,15 @@ bool is_string_option(const char *name) int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt) { int key = 0; - int modifiers; - const char_u *arg = arg_arg; + const char *arg = (char *)arg_arg; // Don't use get_special_key_code() for t_xx, we don't want it to call // add_termcap_entry(). if (len >= 4 && arg[0] == 't' && arg[1] == '_') { - key = TERMCAP2KEY(arg[2], arg[3]); + key = TERMCAP2KEY((uint8_t)arg[2], (uint8_t)arg[3]); } else if (has_lt) { arg--; // put arg at the '<' - modifiers = 0; + int modifiers = 0; key = find_special_key(&arg, len + 1, &modifiers, FSK_KEYCODE | FSK_KEEP_X_KEY | FSK_SIMPLIFY, NULL); if (modifiers) { // can't handle modifiers here @@ -3255,9 +3107,9 @@ int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt) return key; } -static int find_key_option(const char_u *arg, bool has_lt) +static int find_key_option(const char *arg, bool has_lt) { - return find_key_option_len(arg, STRLEN(arg), has_lt); + return find_key_option_len((char_u *)arg, strlen(arg), has_lt); } /// if 'all' == 0: show changed options @@ -3266,16 +3118,6 @@ static int find_key_option(const char_u *arg, bool has_lt) /// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL static void showoptions(int all, int opt_flags) { - vimoption_T *p; - int col; - char_u *varp; - int item_count; - int run; - int row, rows; - int cols; - int i; - int len; - #define INC 20 #define GAP 3 @@ -3294,16 +3136,16 @@ static void showoptions(int all, int opt_flags) // 1. display the short items // 2. display the long items (only strings and numbers) // When "opt_flags" has OPT_ONECOLUMN do everything in run 2. - for (run = 1; run <= 2 && !got_int; run++) { + for (int run = 1; run <= 2 && !got_int; run++) { // collect the items in items[] - item_count = 0; - for (p = &options[0]; p->fullname != NULL; p++) { + int item_count = 0; + for (vimoption_T *p = &options[0]; p->fullname != NULL; p++) { // apply :filter /pat/ if (message_filtered(p->fullname)) { continue; } - varp = NULL; + char_u *varp = NULL; if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) != 0) { if (p->indir != PV_NONE) { varp = (char_u *)get_varp_scope(p, opt_flags); @@ -3313,13 +3155,14 @@ static void showoptions(int all, int opt_flags) } if (varp != NULL && (all == 1 || (all == 0 && !optval_default(p, varp)))) { + int len; if (opt_flags & OPT_ONECOLUMN) { len = Columns; } else if (p->flags & P_BOOL) { len = 1; // a toggle option fits always } else { option_value2string(p, opt_flags); - len = (int)STRLEN(p->fullname) + vim_strsize((char *)NameBuff) + 1; + len = (int)strlen(p->fullname) + vim_strsize(NameBuff) + 1; } if ((len <= INC - GAP && run == 1) || (len > INC - GAP && run == 2)) { @@ -3328,15 +3171,15 @@ static void showoptions(int all, int opt_flags) } } - /* - * display the items - */ + int rows; + + // display the items if (run == 1) { assert(Columns <= INT_MAX - GAP && Columns + GAP >= INT_MIN + 3 && (Columns + GAP - 3) / INC >= INT_MIN && (Columns + GAP - 3) / INC <= INT_MAX); - cols = (Columns + GAP - 3) / INC; + int cols = (Columns + GAP - 3) / INC; if (cols == 0) { cols = 1; } @@ -3344,18 +3187,17 @@ static void showoptions(int all, int opt_flags) } else { // run == 2 rows = item_count; } - for (row = 0; row < rows && !got_int; row++) { + for (int row = 0; row < rows && !got_int; row++) { msg_putchar('\n'); // go to next line if (got_int) { // 'q' typed in more break; } - col = 0; - for (i = row; i < item_count; i += rows) { + int col = 0; + for (int i = row; i < item_count; i += rows) { msg_col = col; // make columns showoneopt(items[i], opt_flags); col += INC; } - ui_flush(); os_breakcheck(); } } @@ -3363,7 +3205,7 @@ static void showoptions(int all, int opt_flags) } /// Return true if option "p" has its default value. -static int optval_default(vimoption_T *p, char_u *varp) +static int optval_default(vimoption_T *p, const char_u *varp) { if (varp == NULL) { return true; // hidden option is always at default @@ -3375,7 +3217,7 @@ static int optval_default(vimoption_T *p, char_u *varp) return *(int *)varp == (int)(intptr_t)p->def_val; } // P_STRING - return STRCMP(*(char_u **)varp, p->def_val) == 0; + return strcmp(*(char **)varp, p->def_val) == 0; } /// Send update to UIs with values of UI relevant options @@ -3413,7 +3255,7 @@ static void showoneopt(vimoption_T *p, int opt_flags) int save_silent = silent_mode; silent_mode = false; - info_message = true; // use mch_msg(), not mch_errmsg() + info_message = true; // use os_msg(), not os_errmsg() char_u *varp = (char_u *)get_varp_scope(p, opt_flags); @@ -3431,7 +3273,7 @@ static void showoneopt(vimoption_T *p, int opt_flags) msg_putchar('='); // put value string in NameBuff option_value2string(p, opt_flags); - msg_outtrans((char *)NameBuff); + msg_outtrans(NameBuff); } silent_mode = save_silent; @@ -3460,25 +3302,15 @@ static void showoneopt(vimoption_T *p, int opt_flags) /// Return FAIL on error, OK otherwise. int makeset(FILE *fd, int opt_flags, int local_only) { - vimoption_T *p; - char *varp; // currently used value - char_u *varp_fresh; // local value - char_u *varp_local = NULL; // fresh value - char *cmd; - int round; - int pri; - - /* - * Some options are never written: - * - Options that don't have a default (terminal name, columns, lines). - * - Terminal options. - * - Hidden options. - * - * Do the loop over "options[]" twice: once for options with the - * P_PRI_MKRC flag and once without. - */ - for (pri = 1; pri >= 0; pri--) { - for (p = &options[0]; p->fullname; p++) { + // Some options are never written: + // - Options that don't have a default (terminal name, columns, lines). + // - Terminal options. + // - Hidden options. + // + // Do the loop over "options[]" twice: once for options with the + // P_PRI_MKRC flag and once without. + for (int pri = 1; pri >= 0; pri--) { + for (vimoption_T *p = &options[0]; p->fullname; p++) { if (!(p->flags & P_NO_MKRC) && ((pri == 1) == ((p->flags & P_PRI_MKRC) != 0))) { // skip global option when only doing locals @@ -3492,7 +3324,7 @@ int makeset(FILE *fd, int opt_flags, int local_only) continue; } - varp = get_varp_scope(p, opt_flags); + char *varp = get_varp_scope(p, opt_flags); // currently used value // Hidden options are never written. if (!varp) { continue; @@ -3507,7 +3339,8 @@ int makeset(FILE *fd, int opt_flags, int local_only) continue; } - round = 2; + int round = 2; + char_u *varp_local = NULL; // fresh value if (p->indir != PV_NONE) { if (p->var == VAR_WIN) { // skip window-local option when only doing globals @@ -3517,7 +3350,7 @@ int makeset(FILE *fd, int opt_flags, int local_only) // When fresh value of window-local option is not at the // default, need to write it too. if (!(opt_flags & OPT_GLOBAL) && !local_only) { - varp_fresh = (char_u *)get_varp_scope(p, OPT_GLOBAL); + char_u *varp_fresh = (char_u *)get_varp_scope(p, OPT_GLOBAL); // local value if (!optval_default(p, varp_fresh)) { round = 1; varp_local = (char_u *)varp; @@ -3530,6 +3363,7 @@ int makeset(FILE *fd, int opt_flags, int local_only) // Round 1: fresh value for window-local options. // Round 2: other values for (; round <= 2; varp = (char *)varp_local, round++) { + char *cmd; if (round == 1 || (opt_flags & OPT_GLOBAL)) { cmd = "set"; } else { @@ -3593,10 +3427,8 @@ int makefoldset(FILE *fd) static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_t flags) { - char_u *s; char_u *buf = NULL; char_u *part = NULL; - char *p; if (fprintf(fd, "%s %s=", cmd, name) < 0) { return FAIL; @@ -3606,16 +3438,14 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_ // options some characters have to be escaped with // CTRL-V or backslash if (valuep == &p_pt) { - s = (char_u *)(*valuep); + char_u *s = (char_u *)(*valuep); while (*s != NUL) { - if (put_escstr(fd, (char_u *)str2special((const char **)&s, false, - false), 2) - == FAIL) { + if (put_escstr(fd, (char_u *)str2special((const char **)&s, false, false), 2) == FAIL) { return FAIL; } } } else if ((flags & P_EXPAND) != 0) { - size_t size = (size_t)STRLEN(*valuep) + 1; + size_t size = (size_t)strlen(*valuep) + 1; // replace home directory in the whole option value into "buf" buf = xmalloc(size); @@ -3632,7 +3462,7 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char **valuep, uint64_ if (put_eol(fd) == FAIL) { goto fail; } - p = (char *)buf; + char *p = (char *)buf; while (*p != NUL) { // for each comma separated option part, append value to // the option, :set rtp+=value @@ -3713,8 +3543,7 @@ void unset_global_local_option(char *name, void *from) } p = &(options[opt_idx]); - switch ((int)p->indir) - { + switch ((int)p->indir) { // global option with local value: use local value if it's been set case PV_EP: clear_string_option(&buf->b_p_ep); @@ -3804,19 +3633,24 @@ void unset_global_local_option(char *name, void *from) clear_string_option(&((win_T *)from)->w_p_ve); ((win_T *)from)->w_ve_flags = 0; break; + case PV_STC: + clear_string_option(&((win_T *)from)->w_p_stc); + break; } } /// Get pointer to option variable, depending on local or global scope. -static char *get_varp_scope(vimoption_T *p, int opt_flags) +/// +/// @param scope can be OPT_LOCAL, OPT_GLOBAL or a combination. +char *get_varp_scope(vimoption_T *p, int scope) { - if ((opt_flags & OPT_GLOBAL) && p->indir != PV_NONE) { + if ((scope & OPT_GLOBAL) && p->indir != PV_NONE) { if (p->var == VAR_WIN) { return GLOBAL_WO(get_varp(p)); } return (char *)p->var; } - if ((opt_flags & OPT_LOCAL) && ((int)p->indir & PV_BOTH)) { + if ((scope & OPT_LOCAL) && ((int)p->indir & PV_BOTH)) { switch ((int)p->indir) { case PV_FP: return (char *)&(curbuf->b_p_fp); @@ -3880,13 +3714,6 @@ static char *get_varp_scope(vimoption_T *p, int opt_flags) return (char *)get_varp(p); } -/// Get pointer to option variable at 'opt_idx', depending on local or global -/// scope. -char *get_option_varp_scope(int opt_idx, int opt_flags) -{ - return get_varp_scope(&(options[opt_idx]), opt_flags); -} - /// Get pointer to option variable. static char_u *get_varp(vimoption_T *p) { @@ -4095,6 +3922,8 @@ static char_u *get_varp(vimoption_T *p) return (char_u *)&(curbuf->b_p_ofu); case PV_URF: return (char_u *)&(curbuf->b_p_urf); + case PV_EOF: + return (char_u *)&(curbuf->b_p_eof); case PV_EOL: return (char_u *)&(curbuf->b_p_eol); case PV_FIXEOL: @@ -4129,6 +3958,8 @@ static char_u *get_varp(vimoption_T *p) return (char_u *)&(curbuf->b_p_fex); case PV_LISP: return (char_u *)&(curbuf->b_p_lisp); + case PV_LOP: + return (char_u *)&(curbuf->b_p_lop); case PV_ML: return (char_u *)&(curbuf->b_p_ml); case PV_MPS: @@ -4191,6 +4022,8 @@ static char_u *get_varp(vimoption_T *p) return (char_u *)&(curwin->w_p_winhl); case PV_WINBL: return (char_u *)&(curwin->w_p_winbl); + case PV_STC: + return (char_u *)&(curwin->w_p_stc); default: iemsg(_("E356: get_varp ERROR")); } @@ -4198,18 +4031,6 @@ static char_u *get_varp(vimoption_T *p) return (char_u *)&(curbuf->b_p_wm); } -/// Return a pointer to the variable for option at 'opt_idx' -char_u *get_option_var(int opt_idx) -{ - return options[opt_idx].var; -} - -/// Return the full name of the option at 'opt_idx' -char *get_option_fullname(int opt_idx) -{ - return options[opt_idx].fullname; -} - /// Get the value of 'equalprg', either the buffer-local one or the global one. char_u *get_equalprg(void) { @@ -4291,6 +4112,7 @@ void copy_winopt(winopt_T *from, winopt_T *to) to->wo_scl = copy_option_val(from->wo_scl); to->wo_winhl = copy_option_val(from->wo_winhl); to->wo_winbl = from->wo_winbl; + to->wo_stc = copy_option_val(from->wo_stc); // Copy the script context so that we know were the value was last set. memmove(to->wo_script_ctx, from->wo_script_ctx, sizeof(to->wo_script_ctx)); @@ -4328,6 +4150,7 @@ static void check_winopt(winopt_T *wop) check_string_option(&wop->wo_fcs); check_string_option(&wop->wo_ve); check_string_option(&wop->wo_wbr); + check_string_option(&wop->wo_stc); } /// Free the allocated memory inside a winopt_T. @@ -4354,6 +4177,7 @@ void clear_winopt(winopt_T *wop) clear_string_option(&wop->wo_fcs); clear_string_option(&wop->wo_ve); clear_string_option(&wop->wo_wbr); + clear_string_option(&wop->wo_stc); } void didset_window_options(win_T *wp, bool valid_cursor) @@ -4400,13 +4224,10 @@ void buf_copy_options(buf_T *buf, int flags) { int should_copy = true; char_u *save_p_isk = NULL; // init for GCC - int dont_do_help; int did_isk = false; - /* - * Skip this when the option defaults have not been set yet. Happens when - * main() allocates the first buffer. - */ + // Skip this when the option defaults have not been set yet. Happens when + // main() allocates the first buffer. if (p_cpo != NULL) { // // Always copy when entering and 'cpo' contains 'S'. @@ -4433,7 +4254,7 @@ void buf_copy_options(buf_T *buf, int flags) // Don't copy the options specific to a help buffer when // BCO_NOHELP is given or the options were initialized already // (jumping back to a help file with CTRL-T or CTRL-O) - dont_do_help = ((flags & BCO_NOHELP) && buf->b_help) || buf->b_p_initialized; + bool dont_do_help = ((flags & BCO_NOHELP) && buf->b_help) || buf->b_p_initialized; if (dont_do_help) { // don't free b_p_isk save_p_isk = (char_u *)buf->b_p_isk; buf->b_p_isk = NULL; @@ -4503,17 +4324,20 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_cpt = xstrdup(p_cpt); COPY_OPT_SCTX(buf, BV_CPT); #ifdef BACKSLASH_IN_FILENAME - buf->b_p_csl = vim_strsave(p_csl); + buf->b_p_csl = xstrdup(p_csl); COPY_OPT_SCTX(buf, BV_CSL); #endif buf->b_p_cfu = xstrdup(p_cfu); COPY_OPT_SCTX(buf, BV_CFU); + set_buflocal_cfu_callback(buf); buf->b_p_ofu = xstrdup(p_ofu); COPY_OPT_SCTX(buf, BV_OFU); buf->b_p_urf = xstrdup(p_urf); COPY_OPT_SCTX(buf, BV_URF); + set_buflocal_ofu_callback(buf); buf->b_p_tfu = xstrdup(p_tfu); COPY_OPT_SCTX(buf, BV_TFU); + set_buflocal_tfu_callback(buf); buf->b_p_sts = p_sts; COPY_OPT_SCTX(buf, BV_STS); buf->b_p_sts_nopaste = p_sts_nopaste; @@ -4551,6 +4375,8 @@ void buf_copy_options(buf_T *buf, int flags) COPY_OPT_SCTX(buf, BV_CINO); buf->b_p_cinsd = xstrdup(p_cinsd); COPY_OPT_SCTX(buf, BV_CINSD); + buf->b_p_lop = xstrdup(p_lop); + COPY_OPT_SCTX(buf, BV_LOP); // Don't copy 'filetype', it must be detected buf->b_p_ft = empty_option; @@ -4622,12 +4448,10 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_lw = empty_option; buf->b_p_menc = empty_option; - /* - * Don't copy the options set by ex_help(), use the saved values, - * when going from a help buffer to a non-help buffer. - * Don't touch these at all when BCO_NOHELP is used and going from - * or to a help buffer. - */ + // Don't copy the options set by ex_help(), use the saved values, + // when going from a help buffer to a non-help buffer. + // Don't touch these at all when BCO_NOHELP is used and going from + // or to a help buffer. if (dont_do_help) { buf->b_p_isk = (char *)save_p_isk; if (p_vts && p_vts != empty_option && !buf->b_p_vts_array) { @@ -4657,10 +4481,8 @@ void buf_copy_options(buf_T *buf, int flags) } } - /* - * When the options should be copied (ignoring BCO_ALWAYS), set the - * flag that indicates that the options have been initialized. - */ + // When the options should be copied (ignoring BCO_ALWAYS), set the + // flag that indicates that the options have been initialized. if (should_copy) { buf->b_p_initialized = true; } @@ -4702,30 +4524,27 @@ static char_u expand_option_name[5] = { 't', '_', NUL, NUL, NUL }; static int expand_option_flags = 0; /// @param opt_flags OPT_GLOBAL and/or OPT_LOCAL -void set_context_in_set_cmd(expand_T *xp, char_u *arg, int opt_flags) +void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) { - char_u nextchar; uint32_t flags = 0; // init for GCC int opt_idx = 0; // init for GCC - char_u *p; - char_u *s; + char *p; int is_term_option = false; - int key; expand_option_flags = opt_flags; xp->xp_context = EXPAND_SETTINGS; if (*arg == NUL) { - xp->xp_pattern = (char *)arg; + xp->xp_pattern = arg; return; } - p = arg + STRLEN(arg) - 1; + p = arg + strlen(arg) - 1; if (*p == ' ' && *(p - 1) != '\\') { - xp->xp_pattern = (char *)p + 1; + xp->xp_pattern = p + 1; return; } while (p > arg) { - s = p; + char *s = p; // count number of backslashes before ' ' or ',' if (*p == ' ' || *p == ',') { while (s > arg && *(s - 1) == '\\') { @@ -4739,23 +4558,26 @@ void set_context_in_set_cmd(expand_T *xp, char_u *arg, int opt_flags) } p--; } - if (STRNCMP(p, "no", 2) == 0) { + if (strncmp(p, "no", 2) == 0) { xp->xp_context = EXPAND_BOOL_SETTINGS; p += 2; } - if (STRNCMP(p, "inv", 3) == 0) { + if (strncmp(p, "inv", 3) == 0) { xp->xp_context = EXPAND_BOOL_SETTINGS; p += 3; } - xp->xp_pattern = (char *)p; + xp->xp_pattern = p; arg = p; + + char nextchar; + if (*arg == '<') { while (*p != '>') { if (*p++ == NUL) { // expand terminal option name return; } } - key = get_special_key_code(arg + 1); + int key = get_special_key_code((char_u *)arg + 1); if (key == 0) { // unknown name xp->xp_context = EXPAND_NOTHING; return; @@ -4775,8 +4597,8 @@ void set_context_in_set_cmd(expand_T *xp, char_u *arg, int opt_flags) } nextchar = *++p; is_term_option = true; - expand_option_name[2] = p[-2]; - expand_option_name[3] = p[-1]; + expand_option_name[2] = (char_u)p[-2]; + expand_option_name[3] = (char_u)p[-1]; } else { // Allow * wildcard. while (ASCII_ISALNUM(*p) || *p == '_' || *p == '*') { @@ -4815,7 +4637,7 @@ void set_context_in_set_cmd(expand_T *xp, char_u *arg, int opt_flags) } else { expand_option_idx = opt_idx; } - xp->xp_pattern = (char *)p + 1; + xp->xp_pattern = p + 1; return; } xp->xp_context = EXPAND_NOTHING; @@ -4823,30 +4645,29 @@ void set_context_in_set_cmd(expand_T *xp, char_u *arg, int opt_flags) return; } - xp->xp_pattern = (char *)p + 1; + xp->xp_pattern = p + 1; if (flags & P_EXPAND) { - p = options[opt_idx].var; - if (p == (char_u *)&p_bdir - || p == (char_u *)&p_dir - || p == (char_u *)&p_path - || p == (char_u *)&p_pp - || p == (char_u *)&p_rtp - || p == (char_u *)&p_cdpath - || p == (char_u *)&p_vdir) { + p = (char *)options[opt_idx].var; + if (p == (char *)&p_bdir + || p == (char *)&p_dir + || p == (char *)&p_path + || p == (char *)&p_pp + || p == (char *)&p_rtp + || p == (char *)&p_cdpath + || p == (char *)&p_vdir) { xp->xp_context = EXPAND_DIRECTORIES; - if (p == (char_u *)&p_path - || p == (char_u *)&p_cdpath) { + if (p == (char *)&p_path || p == (char *)&p_cdpath) { xp->xp_backslash = XP_BS_THREE; } else { xp->xp_backslash = XP_BS_ONE; } - } else if (p == (char_u *)&p_ft) { + } else if (p == (char *)&p_ft) { xp->xp_context = EXPAND_FILETYPE; } else { xp->xp_context = EXPAND_FILES; // for 'tags' need three backslashes for a space - if (p == (char_u *)&p_tags) { + if (p == (char *)&p_tags) { xp->xp_backslash = XP_BS_THREE; } else { xp->xp_backslash = XP_BS_ONE; @@ -4856,24 +4677,24 @@ void set_context_in_set_cmd(expand_T *xp, char_u *arg, int opt_flags) // For an option that is a list of file names, find the start of the // last file name. - for (p = arg + STRLEN(arg) - 1; p > (char_u *)xp->xp_pattern; p--) { + for (p = arg + strlen(arg) - 1; p > xp->xp_pattern; p--) { // count number of backslashes before ' ' or ',' if (*p == ' ' || *p == ',') { - s = p; - while (s > (char_u *)xp->xp_pattern && *(s - 1) == '\\') { + char *s = p; + while (s > xp->xp_pattern && *(s - 1) == '\\') { s--; } if ((*p == ' ' && (xp->xp_backslash == XP_BS_THREE && (p - s) < 3)) || (*p == ',' && (flags & P_COMMA) && ((p - s) & 1) == 0)) { - xp->xp_pattern = (char *)p + 1; + xp->xp_pattern = p + 1; break; } } // for 'spellsuggest' start at "file:" if (options[opt_idx].var == (char_u *)&p_sps - && STRNCMP(p, "file:", 5) == 0) { - xp->xp_pattern = (char *)p + 5; + && strncmp(p, "file:", 5) == 0) { + xp->xp_pattern = p + 5; break; } } @@ -4882,17 +4703,15 @@ void set_context_in_set_cmd(expand_T *xp, char_u *arg, int opt_flags) int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***file) { int num_normal = 0; // Nr of matching non-term-code settings - int match; int count = 0; - char_u *str; - int loop; static char *(names[]) = { "all" }; int ic = regmatch->rm_ic; // remember the ignore-case flag // do this loop twice: // loop == 0: count the number of matching options // loop == 1: copy the matching options into allocated memory - for (loop = 0; loop <= 1; loop++) { + for (int loop = 0; loop <= 1; loop++) { + int match; regmatch->rm_ic = ic; if (xp->xp_context != EXPAND_BOOL_SETTINGS) { for (match = 0; match < (int)ARRAY_SIZE(names); @@ -4906,7 +4725,8 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***fi } } } - for (size_t opt_idx = 0; (str = (char_u *)options[opt_idx].fullname) != NULL; + char *str; + for (size_t opt_idx = 0; (str = options[opt_idx].fullname) != NULL; opt_idx++) { if (options[opt_idx].var == NULL) { continue; @@ -4916,7 +4736,7 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***fi continue; } match = false; - if (vim_regexec(regmatch, (char *)str, (colnr_T)0) + if (vim_regexec(regmatch, str, (colnr_T)0) || (options[opt_idx].shortname != NULL && vim_regexec(regmatch, options[opt_idx].shortname, @@ -4928,7 +4748,7 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***fi if (loop == 0) { num_normal++; } else { - (*file)[count++] = (char *)vim_strsave(str); + (*file)[count++] = xstrdup(str); } } } @@ -4939,7 +4759,7 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***fi } else { return OK; } - *file = xmalloc((size_t)(*num_file) * sizeof(char_u *)); + *file = xmalloc((size_t)(*num_file) * sizeof(char *)); } } return OK; @@ -4947,14 +4767,12 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***fi void ExpandOldSetting(int *num_file, char ***file) { - char_u *var = NULL; + char *var = NULL; *num_file = 0; *file = xmalloc(sizeof(char_u *)); - /* - * For a terminal key code expand_option_idx is < 0. - */ + // For a terminal key code expand_option_idx is < 0. if (expand_option_idx < 0) { expand_option_idx = findoption((const char *)expand_option_name); } @@ -4962,14 +4780,14 @@ void ExpandOldSetting(int *num_file, char ***file) if (expand_option_idx >= 0) { // Put string of option value in NameBuff. option_value2string(&options[expand_option_idx], expand_option_flags); - var = (char_u *)NameBuff; + var = NameBuff; } else { - var = (char_u *)""; + var = ""; } // A backslash is required before some characters. This is the reverse of // what happens in do_set(). - char_u *buf = vim_strsave_escaped(var, escape_chars); + char_u *buf = (char_u *)vim_strsave_escaped(var, (char *)escape_chars); #ifdef BACKSLASH_IN_FILENAME // For MS-Windows et al. we don't double backslashes at the start and @@ -4978,7 +4796,7 @@ void ExpandOldSetting(int *num_file, char ***file) if (var[0] == '\\' && var[1] == '\\' && expand_option_idx >= 0 && (options[expand_option_idx].flags & P_EXPAND) - && vim_isfilec(var[2]) + && vim_isfilec((uint8_t)var[2]) && (var[2] != '\\' || (var == buf && var[4] != '\\'))) { STRMOVE(var, var + 1); } @@ -4993,34 +4811,34 @@ void ExpandOldSetting(int *num_file, char ***file) /// NameBuff[]. Must not be called with a hidden option! /// /// @param opt_flags OPT_GLOBAL and/or OPT_LOCAL -static void option_value2string(vimoption_T *opp, int opt_flags) +static void option_value2string(vimoption_T *opp, int scope) { - char_u *varp = (char_u *)get_varp_scope(opp, opt_flags); + char *varp = get_varp_scope(opp, scope); if (opp->flags & P_NUM) { long wc = 0; - if (wc_use_keyname(varp, &wc)) { - STRLCPY(NameBuff, get_special_key_name((int)wc, 0), sizeof(NameBuff)); + if (wc_use_keyname((char_u *)varp, &wc)) { + xstrlcpy(NameBuff, (char *)get_special_key_name((int)wc, 0), sizeof(NameBuff)); } else if (wc != 0) { - STRLCPY(NameBuff, transchar((int)wc), sizeof(NameBuff)); + xstrlcpy(NameBuff, (char *)transchar((int)wc), sizeof(NameBuff)); } else { - snprintf((char *)NameBuff, + snprintf(NameBuff, sizeof(NameBuff), "%" PRId64, - (int64_t)*(long *)varp); + (int64_t)(*(long *)varp)); } } else { // P_STRING - varp = *(char_u **)(varp); + varp = *(char **)(varp); if (varp == NULL) { // Just in case. NameBuff[0] = NUL; } else if (opp->flags & P_EXPAND) { - home_replace(NULL, (char *)varp, (char *)NameBuff, MAXPATHL, false); + home_replace(NULL, varp, (char *)NameBuff, MAXPATHL, false); // Translate 'pastetoggle' into special key names. } else if ((char **)opp->var == &p_pt) { - str2specialbuf((const char *)p_pt, (char *)NameBuff, MAXPATHL); + str2specialbuf((const char *)p_pt, NameBuff, MAXPATHL); } else { - STRLCPY(NameBuff, varp, MAXPATHL); + xstrlcpy(NameBuff, varp, MAXPATHL); } } } @@ -5028,7 +4846,7 @@ static void option_value2string(vimoption_T *opp, int opt_flags) /// Return true if "varp" points to 'wildchar' or 'wildcharm' and it can be /// printed as a keyname. /// "*wcp" is set to the value of the option if it's 'wildchar' or 'wildcharm'. -static int wc_use_keyname(char_u *varp, long *wcp) +static int wc_use_keyname(const char_u *varp, long *wcp) { if (((long *)varp == &p_wc) || ((long *)varp == &p_wcm)) { *wcp = *(long *)varp; @@ -5060,10 +4878,8 @@ static void paste_option_changed(void) static int save_hkmap = 0; if (p_paste) { - /* - * Paste switched from off to on. - * Save the current values, so they can be restored later. - */ + // Paste switched from off to on. + // Save the current values, so they can be restored later. if (!old_p_paste) { // save options for each buffer FOR_ALL_BUFFERS(buf) { @@ -5232,15 +5048,12 @@ void reset_option_was_set(const char *name) /// fill_breakat_flags() -- called when 'breakat' changes value. void fill_breakat_flags(void) { - char_u *p; - int i; - - for (i = 0; i < 256; i++) { + for (int i = 0; i < 256; i++) { breakat_flags[i] = false; } if (p_breakat != NULL) { - for (p = (char_u *)p_breakat; *p; p++) { + for (char_u *p = (char_u *)p_breakat; *p; p++) { breakat_flags[*p] = true; } } @@ -5258,16 +5071,16 @@ int fill_culopt_flags(char *val, win_T *wp) p = val; } while (*p != NUL) { - if (STRNCMP(p, "line", 4) == 0) { + if (strncmp(p, "line", 4) == 0) { p += 4; culopt_flags_new |= CULOPT_LINE; - } else if (STRNCMP(p, "both", 4) == 0) { + } else if (strncmp(p, "both", 4) == 0) { p += 4; culopt_flags_new |= CULOPT_LINE | CULOPT_NBR; - } else if (STRNCMP(p, "number", 6) == 0) { + } else if (strncmp(p, "number", 6) == 0) { p += 6; culopt_flags_new |= CULOPT_NBR; - } else if (STRNCMP(p, "screenline", 10) == 0) { + } else if (strncmp(p, "screenline", 10) == 0) { p += 10; culopt_flags_new |= CULOPT_SCRLINE; } @@ -5289,10 +5102,24 @@ int fill_culopt_flags(char *val, win_T *wp) return OK; } +/// Get the value of 'magic' taking "magic_overruled" into account. +bool magic_isset(void) +{ + switch (magic_overruled) { + case OPTION_MAGIC_ON: + return true; + case OPTION_MAGIC_OFF: + return false; + case OPTION_MAGIC_NOT_SET: + break; + } + return p_magic; +} + /// Set the callback function value for an option that accepts a function name, /// lambda, et al. (e.g. 'operatorfunc', 'tagfunc', etc.) /// @return OK if the option is successfully set to a function, otherwise FAIL -int option_set_callback_func(char_u *optval, Callback *optcb) +int option_set_callback_func(char *optval, Callback *optcb) { if (optval == NULL || *optval == NUL) { callback_free(optcb); @@ -5301,10 +5128,10 @@ int option_set_callback_func(char_u *optval, Callback *optcb) typval_T *tv; if (*optval == '{' - || (STRNCMP(optval, "function(", 9) == 0) - || (STRNCMP(optval, "funcref(", 8) == 0)) { + || (strncmp(optval, "function(", 9) == 0) + || (strncmp(optval, "funcref(", 8) == 0)) { // Lambda expression or a funcref - tv = eval_expr((char *)optval); + tv = eval_expr(optval); if (tv == NULL) { return FAIL; } @@ -5312,11 +5139,11 @@ int option_set_callback_func(char_u *optval, Callback *optcb) // treat everything else as a function name string tv = xcalloc(1, sizeof(*tv)); tv->v_type = VAR_STRING; - tv->vval.v_string = (char *)vim_strsave(optval); + tv->vval.v_string = xstrdup(optval); } Callback cb; - if (!callback_from_typval(&cb, tv)) { + if (!callback_from_typval(&cb, tv) || cb.type == kCallbackNone) { tv_free(tv); return FAIL; } @@ -5355,6 +5182,17 @@ unsigned int get_bkc_value(buf_T *buf) return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags; } +/// Get the local or global value of 'formatlistpat'. +/// +/// @param buf The buffer. +char *get_flp_value(buf_T *buf) +{ + if (buf->b_p_flp == NULL || *buf->b_p_flp == NUL) { + return p_flp; + } + return buf->b_p_flp; +} + /// Get the local or global value of the 'virtualedit' flags. unsigned int get_ve_flags(void) { @@ -5371,7 +5209,7 @@ char_u *get_showbreak_value(win_T *const win) if (win->w_p_sbr == NULL || *win->w_p_sbr == NUL) { return (char_u *)p_sbr; } - if (STRCMP(win->w_p_sbr, "NONE") == 0) { + if (strcmp(win->w_p_sbr, "NONE") == 0) { return (char_u *)empty_option; } return (char_u *)win->w_p_sbr; @@ -5517,13 +5355,13 @@ size_t copy_option_part(char **option, char *buf, size_t maxlen, char *sep_chars /// Return true when 'shell' has "csh" in the tail. int csh_like_shell(void) { - return strstr(path_tail((char *)p_sh), "csh") != NULL; + return strstr(path_tail(p_sh), "csh") != NULL; } /// Return true when 'shell' has "fish" in the tail. bool fish_like_shell(void) { - return strstr(path_tail((char *)p_sh), "fish") != NULL; + return strstr(path_tail(p_sh), "fish") != NULL; } /// Return the number of requested sign columns, based on current @@ -5681,7 +5519,7 @@ static Dictionary vimoption2dict(vimoption_T *opt) const char *type; Object def; // TODO(bfredl): do you even nocp? - char_u *def_val = opt->def_val; + char_u *def_val = (char_u *)opt->def_val; if (opt->flags & P_STRING) { type = "string"; def = CSTR_TO_OBJ(def_val ? (char *)def_val : ""); |