diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 18:31:31 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 18:31:31 +0000 |
commit | 9243becbedbb6a1592208051f8fa2b090dcc5e7d (patch) | |
tree | 607c2a862ec3f4399b8766383f6f8e04c4aa43b4 /src/nvim/option.c | |
parent | 9e40b6e9e1bc67f2d856adb837ee64dd0e25b717 (diff) | |
parent | 3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff) | |
download | rneovim-usermarks.tar.gz rneovim-usermarks.tar.bz2 rneovim-usermarks.zip |
Merge remote-tracking branch 'upstream/master' into usermarksusermarks
Diffstat (limited to 'src/nvim/option.c')
-rw-r--r-- | src/nvim/option.c | 3009 |
1 files changed, 1376 insertions, 1633 deletions
diff --git a/src/nvim/option.c b/src/nvim/option.c index 0acfc5c261..1e7cd62d22 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -21,37 +21,46 @@ #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" +#include "nvim/cmdexpand.h" #include "nvim/cursor_shape.h" #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/ex_cmds2.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" @@ -64,60 +73,49 @@ #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" -/* - * 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 e_unknown_option[] + = N_("E518: Unknown option"); +static char e_not_allowed_in_modeline[] + = N_("E520: Not allowed in a modeline"); +static char e_not_allowed_in_modeline_when_modelineexpr_is_off[] + = N_("E992: Not allowed in a modeline when 'modelineexpr' is off"); +static char e_key_code_not_set[] + = N_("E846: Key code not set"); +static char e_number_required_after_equal[] + = N_("E521: Number required after ="); +static char e_preview_window_already_exists[] + = N_("E590: A preview window already exists"); static char *p_term = NULL; static char *p_ttytype = NULL; @@ -134,29 +132,14 @@ static int p_et_nopaste; static long p_sts_nopaste; static long p_tw_nopaste; static long p_wm_nopaste; -static char_u *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. - */ +static char *p_vsts_nopaste; + +// 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" @@ -164,10 +147,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. @@ -178,14 +175,10 @@ typedef struct vimoption { /// editor state initialized here. Do logging in set_init_2 or later. void set_init_1(bool clean_arg) { - int opt_idx; - 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) { @@ -200,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" }; @@ -211,7 +202,7 @@ void set_init_1(bool clean_arg) static char *(names[3]) = { "TMPDIR", "TEMP", "TMP" }; #endif garray_T ga; - opt_idx = findoption("backupskip"); + int opt_idx = findoption("backupskip"); ga_init(&ga, 1, 100); for (size_t n = 0; n < ARRAY_SIZE(names); n++) { @@ -225,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]); @@ -237,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)) { @@ -260,19 +251,14 @@ void set_init_1(bool clean_arg) } { - char_u *cdpath; - char_u *buf; - int i; - int j; - // Initialize the 'cdpath' option's default value. - cdpath = (char_u *)vim_getenv("CDPATH"); + char *cdpath = vim_getenv("CDPATH"); if (cdpath != NULL) { - buf = xmalloc(2 * STRLEN(cdpath) + 2); + char *buf = xmalloc(2 * strlen(cdpath) + 2); { buf[0] = ','; // start with ",", current dir first - j = 1; - for (i = 0; cdpath[i] != NUL; i++) { + int j = 1; + for (int i = 0; cdpath[i] != NUL; i++) { if (vim_ispathlistsep(cdpath[i])) { buf[j++] = ','; } else { @@ -283,7 +269,7 @@ void set_init_1(bool clean_arg) } } buf[j] = NUL; - opt_idx = findoption("cdpath"); + int opt_idx = findoption("cdpath"); if (opt_idx >= 0) { options[opt_idx].def_val = buf; options[opt_idx].flags |= P_DEF_ALLOCED; @@ -295,28 +281,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); @@ -339,10 +303,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; @@ -365,34 +327,32 @@ 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. - */ - for (opt_idx = 0; options[opt_idx].fullname; opt_idx++) { - if (options[opt_idx].flags & P_NO_DEF_EXP) { + // 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 (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) { + vimoption_T *opt = &options[opt_idx]; + if (opt->flags & P_NO_DEF_EXP) { continue; } char *p; - if ((options[opt_idx].flags & P_GETTEXT) - && options[opt_idx].var != NULL) { - p = _(*(char **)options[opt_idx].var); + if ((opt->flags & P_GETTEXT) && opt->var != NULL) { + p = _(*(char **)opt->var); } else { - p = (char *)option_expand(opt_idx, NULL); + p = option_expand(opt_idx, NULL); } if (p != NULL) { p = xstrdup(p); - *(char **)options[opt_idx].var = p; - if (options[opt_idx].flags & P_DEF_ALLOCED) { - xfree(options[opt_idx].def_val); + *(char **)opt->var = p; + if (opt->flags & P_DEF_ALLOCED) { + xfree(opt->def_val); } - options[opt_idx].def_val = (char_u *)p; - options[opt_idx].flags |= P_DEF_ALLOCED; + opt->def_val = p; + opt->flags |= P_DEF_ALLOCED; } } @@ -404,7 +364,7 @@ void set_init_1(bool clean_arg) // NOTE: mlterm's author is being asked to 'set' a variable // instead of an environment variable due to inheritance. if (os_env_exists("MLTERM")) { - set_option_value("tbidi", 1L, NULL, 0); + set_option_value_give_err("tbidi", 1L, NULL, 0); } didset_options2(); @@ -414,17 +374,17 @@ void set_init_1(bool clean_arg) // enc_locale() will try to find the encoding of the current locale. // This will be used when 'default' is used as encoding specifier // in 'fileencodings' - char_u *p = enc_locale(); + char *p = enc_locale(); if (p == NULL) { // use utf-8 as 'default' if locale encoding can't be detected. - p = (char_u *)xmemdupz(S_LEN("utf-8")); + p = xmemdupz(S_LEN("utf-8")); } fenc_default = p; #ifdef HAVE_WORKING_LIBINTL // GNU gettext 0.10.37 supports this feature: set the codeset used for // translated messages independently from the current locale. - (void)bind_textdomain_codeset(PROJECT_NAME, (char *)p_enc); + (void)bind_textdomain_codeset(PROJECT_NAME, p_enc); #endif // Set the default for 'helplang'. @@ -435,32 +395,32 @@ void set_init_1(bool clean_arg) /// This does not take care of side effects! /// /// @param opt_flags OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL -static void set_option_default(int opt_idx, int opt_flags) +static void set_option_default(const int opt_idx, int opt_flags) { - char_u *varp; // pointer to variable for current option int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; - varp = get_varp_scope(&(options[opt_idx]), both ? OPT_LOCAL : opt_flags); - uint32_t flags = options[opt_idx].flags; + // pointer to variable for current option + vimoption_T *opt = &options[opt_idx]; + char_u *varp = (char_u *)get_varp_scope(opt, both ? OPT_LOCAL : opt_flags); + uint32_t flags = opt->flags; if (varp != NULL) { // skip hidden option, nothing to do for it if (flags & P_STRING) { // Use set_string_option_direct() for local options to handle // 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); + if (opt->indir != PV_NONE) { + set_string_option_direct(NULL, opt_idx, opt->def_val, opt_flags, 0); } else { if ((opt_flags & OPT_FREE) && (flags & P_ALLOCED)) { - free_string_option(*(char_u **)(varp)); + free_string_option(*(char **)(varp)); } - *(char_u **)varp = options[opt_idx].def_val; - options[opt_idx].flags &= ~P_ALLOCED; + *(char **)varp = opt->def_val; + opt->flags &= ~P_ALLOCED; } } else if (flags & P_NUM) { - if (options[opt_idx].indir == PV_SCROLL) { + if (opt->indir == PV_SCROLL) { win_comp_scroll(curwin); } else { - long def_val = (long)options[opt_idx].def_val; + long def_val = (long)opt->def_val; if ((long *)varp == &curwin->w_p_so || (long *)varp == &curwin->w_p_siso) { // 'scrolloff' and 'sidescrolloff' local values have a @@ -471,21 +431,21 @@ static void set_option_default(int opt_idx, int opt_flags) } // May also set global value for local option. if (both) { - *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = + *(long *)get_varp_scope(opt, OPT_GLOBAL) = def_val; } } } else { // P_BOOL - *(int *)varp = (int)(intptr_t)options[opt_idx].def_val; + *(int *)varp = (int)(intptr_t)opt->def_val; #ifdef UNIX // 'modeline' defaults to off for root - if (options[opt_idx].indir == PV_ML && getuid() == ROOT_UID) { + if (opt->indir == PV_ML && getuid() == ROOT_UID) { *(int *)varp = false; } #endif // May also set global value for local option. if (both) { - *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = + *(int *)get_varp_scope(opt, OPT_GLOBAL) = *(int *)varp; } } @@ -528,32 +488,31 @@ static void set_string_default(const char *name, char *val, bool allocated) { int opt_idx = findoption(name); if (opt_idx >= 0) { - if (options[opt_idx].flags & P_DEF_ALLOCED) { - xfree(options[opt_idx].def_val); + vimoption_T *opt = &options[opt_idx]; + if (opt->flags & P_DEF_ALLOCED) { + xfree(opt->def_val); } - options[opt_idx].def_val = allocated - ? (char_u *)val - : (char_u *)xstrdup(val); - options[opt_idx].flags |= P_DEF_ALLOCED; + opt->def_val = allocated ? val : xstrdup(val); + opt->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; - if (origval == NULL) { return NULL; } - const size_t newlen = STRLEN(newval); - for (char_u *s = origval; *s != NUL; s++) { + int bs = 0; + + 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; } @@ -574,11 +533,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; } } @@ -590,17 +547,18 @@ void free_all_options(void) if (options[i].indir == PV_NONE) { // global option: free value and default value. if ((options[i].flags & P_ALLOCED) && options[i].var != NULL) { - free_string_option(*(char_u **)options[i].var); + free_string_option(*(char **)options[i].var); } if (options[i].flags & P_DEF_ALLOCED) { 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 - clear_string_option((char_u **)options[i].var); + clear_string_option((char **)options[i].var); } } free_operatorfunc_option(); + free_tagfunc_option(); } #endif @@ -610,25 +568,20 @@ void set_init_2(bool headless) // set in set_init_1 but logging is not allowed there ILOG("startup runtimepath/packpath value: %s", p_rtp); - int idx; - // 'scroll' defaults to half the window height. The stored default is zero, // which results in the actual value computed from the window height. - idx = findoption("scroll"); + int idx = findoption("scroll"); if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) { set_option_default(idx, OPT_LOCAL); } 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 @@ -649,41 +602,41 @@ 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 = (char_u *)"|& tee"; + p_sp = "|& tee"; options[idx_sp].def_val = p_sp; } if (do_srr) { - p_srr = (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 = (char_u *)"2>&1| tee"; + p_sp = "2>&1| tee"; options[idx_sp].def_val = p_sp; } if (do_srr) { - p_srr = (char_u *)">%s 2>&1"; + p_srr = ">%s 2>&1"; options[idx_srr].def_val = p_srr; } } @@ -715,23 +668,25 @@ void set_helplang_default(const char *lang) return; } int idx = findoption("hlg"); - if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) { - if (options[idx].flags & P_ALLOCED) { - free_string_option(p_hlg); - } - p_hlg = (char_u *)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') { - // any C like setting, such as C.UTF-8, becomes "en" - p_hlg[0] = 'e'; - p_hlg[1] = 'n'; - } - p_hlg[2] = NUL; - options[idx].flags |= P_ALLOCED; + if (idx < 0 || (options[idx].flags & P_WAS_SET)) { + return; } + + if (options[idx].flags & P_ALLOCED) { + free_string_option(p_hlg); + } + 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)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'; + } + p_hlg[2] = NUL; + options[idx].flags |= P_ALLOCED; } /// 'title' and 'icon' only default to true if they have not been set or reset @@ -741,21 +696,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; } } @@ -775,6 +726,342 @@ 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_u *origval_l = NULL; + char_u *origval_g = 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. + char *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; + } + } + + char *origval; + // 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, (uint8_t)(*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, (uint8_t)(*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. + char *saved_origval = (origval != NULL) ? xstrdup(origval) : NULL; + char *saved_origval_l = (origval_l != NULL) ? xstrdup((char *)origval_l) : NULL; + char *saved_origval_g = (origval_g != NULL) ? xstrdup((char *)origval_g) : NULL; + + // newval (and varp) may become invalid if the buffer is closed by + // autocommands. + char *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 @@ -792,23 +1079,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_u *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); @@ -816,16 +1087,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 = (char_u *)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 && !ASCII_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++; @@ -834,23 +1105,25 @@ int do_set(char *arg, int opt_flags) didset_options(); didset_options2(); ui_refresh_options(); - redraw_all_later(CLEAR); + redraw_all_later(UPD_CLEAR); } else { showoptions(1, 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_>;> @@ -871,7 +1144,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; @@ -885,54 +1158,55 @@ 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 = N_("E518: Unknown option"); + 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 // a hidden option, ignore setting it. - if (vim_strchr("=:!&<", nextchar) == NULL + if (vim_strchr("=:!&<", (uint8_t)nextchar) == NULL && (!(options[opt_idx].flags & P_BOOL) || nextchar == '?')) { - errmsg = _(e_unsupportedoption); + errmsg = e_unsupportedoption; } goto skip; } flags = options[opt_idx].flags; - varp = (char *)get_varp_scope(&(options[opt_idx]), opt_flags); + varp = get_varp_scope(&(options[opt_idx]), opt_flags); } else { flags = P_STRING; } @@ -953,11 +1227,11 @@ int do_set(char *arg, int opt_flags) // Disallow changing some options from modelines. if (opt_flags & OPT_MODELINE) { if (flags & (P_SECURE | P_NO_ML)) { - errmsg = N_("E520: Not allowed in a modeline"); + errmsg = e_not_allowed_in_modeline; goto skip; } if ((flags & P_MLE) && !p_mle) { - errmsg = N_("E992: Not allowed in a modeline when 'modelineexpr' is off"); + errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off; goto skip; } // In diff mode some options are overruled. This avoids that @@ -977,7 +1251,7 @@ int do_set(char *arg, int opt_flags) goto skip; } - if (vim_strchr("?=:!&<", nextchar) != NULL) { + if (vim_strchr("?=:!&<", (uint8_t)nextchar) != NULL) { arg += len; if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i') { if (arg[3] == 'm') { // "opt&vim": set to Vim default @@ -986,7 +1260,7 @@ int do_set(char *arg, int opt_flags) arg += 2; } } - if (vim_strchr("?!&<", nextchar) != NULL + if (vim_strchr("?!&<", (uint8_t)nextchar) != NULL && arg[1] != NUL && !ascii_iswhite(arg[1])) { errmsg = e_trailing; goto skip; @@ -999,11 +1273,9 @@ int do_set(char *arg, int opt_flags) // if (nextchar == '?' || (prefix == 1 - && vim_strchr("=:&<", nextchar) == NULL + && vim_strchr("=:&<", (uint8_t)nextchar) == NULL && !(flags & P_BOOL))) { - /* - * print value - */ + // print value if (did_show) { msg_putchar('\n'); // cursor below last one } else { @@ -1025,7 +1297,7 @@ int do_set(char *arg, int opt_flags) } } } else { - errmsg = N_("E846: Key code not set"); + errmsg = e_key_code_not_set; goto skip; } if (nextchar != '?' @@ -1033,8 +1305,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 == ':') { @@ -1042,11 +1314,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 == '&') { @@ -1061,10 +1331,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; @@ -1078,7 +1346,7 @@ int do_set(char *arg, int opt_flags) errmsg = set_bool_option(opt_idx, (char_u *)varp, (int)value, opt_flags); } else { // Numeric or string. - if (vim_strchr("=:&<", nextchar) == NULL + if (vim_strchr("=:&<", (uint8_t)nextchar) == NULL || prefix != 1) { errmsg = e_invarg; goto skip; @@ -1109,390 +1377,44 @@ int do_set(char *arg, int opt_flags) || *arg == '^' || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1])) && !ascii_isdigit(*arg)))) { - value = string_to_key((char_u *)arg); + value = string_to_key(arg); if (value == 0 && (long *)varp != &p_wcm) { errmsg = e_invarg; 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 = N_("E521: Number required after ="); + errmsg = e_number_required_after_equal; goto skip; } } else { - errmsg = N_("E521: Number required after ="); + errmsg = e_number_required_after_equal; 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 == 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 = 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_u **)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_u **)varp, 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 @@ -1501,18 +1423,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++; @@ -1526,20 +1446,20 @@ skip: } if (errmsg != NULL) { - STRLCPY(IObuff, _(errmsg), IOSIZE); - i = (int)STRLEN(IObuff) + 2; - if (i + ((char_u *)arg - startarg) < IOSIZE) { + xstrlcpy(IObuff, _(errmsg), IOSIZE); + int i = (int)strlen(IObuff) + 2; + if (i + (arg - startarg) < IOSIZE) { // append the argument with the error STRCAT(IObuff, ": "); - assert((char_u *)arg >= startarg); - memmove(IObuff + i, startarg, (size_t)((char_u *)arg - startarg)); - IObuff[i + ((char_u *)arg - startarg)] = NUL; + assert(arg >= startarg); + memmove(IObuff + i, startarg, (size_t)(arg - startarg)); + 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 + no_wait_return++; // wait_return() done later + emsg(IObuff); // show error highlighted no_wait_return--; return FAIL; @@ -1552,11 +1472,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; @@ -1587,33 +1507,15 @@ void did_set_option(int opt_idx, int opt_flags, int new_value, int value_checked /// Convert a key name or string into a key value. /// Used for 'wildchar' and 'cedit' options. -static int string_to_key(char_u *arg) +int string_to_key(char *arg) { if (*arg == '<') { return find_key_option(arg + 1, true); } if (*arg == '^') { - return CTRL_CHR(arg[1]); - } - return *arg; -} - -/// Check value of 'cedit' and set cedit_key. -/// Returns NULL if value is OK, error message otherwise. -char *check_cedit(void) -{ - int n; - - if (*p_cedit == NUL) { - cedit_key = -1; - } else { - n = string_to_key(p_cedit); - if (vim_isprintc(n)) { - return e_invarg; - } - cedit_key = n; + return CTRL_CHR((uint8_t)arg[1]); } - return NULL; + return (uint8_t)(*arg); } // When changing 'title', 'titlestring', 'icon' or 'iconstring', call @@ -1632,10 +1534,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)) { @@ -1688,11 +1588,9 @@ 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 *p = find_shada_parameter(type); if (p != NULL && ascii_isdigit(*p)) { - return atoi((char *)p); + return atoi(p); } return -1; } @@ -1700,18 +1598,16 @@ int get_shada_parameter(int type) /// Find the parameter represented by the given character (eg ''', ':', '"', or /// '/') in the 'shada' option and return a pointer to the string after it. /// Return NULL if the parameter is not specified in the string. -char_u *find_shada_parameter(int type) +char *find_shada_parameter(int type) { - char_u *p; - - for (p = p_shada; *p; p++) { + for (char *p = p_shada; *p; p++) { if (*p == type) { return p + 1; } if (*p == 'n') { // 'n' is always the last one break; } - p = (char_u *)vim_strchr((char *)p, ','); // skip until next ',' + p = vim_strchr(p, ','); // skip until next ',' if (p == NULL) { // hit the end without finding parameter break; } @@ -1723,7 +1619,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) { @@ -1731,26 +1627,24 @@ 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:". - */ + // 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 == &p_sps ? (char_u *)"file:" : + (char **)options[opt_idx].var == &p_tags, false, + (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; } @@ -1800,11 +1694,9 @@ static void didset_options2(void) /// Check for string options that are NULL (normally only termcap options). void check_options(void) { - int opt_idx; - - for (opt_idx = 0; options[opt_idx].fullname != NULL; opt_idx++) { + for (int opt_idx = 0; options[opt_idx].fullname != NULL; opt_idx++) { if ((options[opt_idx].flags & P_STRING) && options[opt_idx].var != NULL) { - check_string_option((char_u **)get_varp(&(options[opt_idx]))); + check_string_option((char **)get_varp(&(options[opt_idx]))); } } } @@ -1863,12 +1755,12 @@ void redraw_titles(void) /// Return true if "val" is a valid name: only consists of alphanumeric ASCII /// characters or characters in "allowed". -bool valid_name(const char_u *val, const char *allowed) +bool valid_name(const char *val, const char *allowed) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - for (const char_u *s = val; *s != NUL; s++) { + for (const char *s = val; *s != NUL; s++) { if (!ASCII_ISALNUM(*s) - && vim_strchr(allowed, *s) == NULL) { + && vim_strchr(allowed, (uint8_t)(*s)) == NULL) { return false; } } @@ -1935,15 +1827,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) { @@ -1958,6 +1851,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. @@ -1971,6 +1904,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va { int old_value = *(int *)varp; int old_global_value = 0; + char *errmsg = NULL; // Disallow changing some options from secure mode if ((secure || sandbox != 0) @@ -2025,7 +1959,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va || (opt_flags & OPT_GLOBAL) || opt_flags == 0) && !bufIsChanged(bp) && bp->b_ml.ml_mfp != NULL) { u_compute_hash(bp, hash); - u_read_undo(NULL, hash, (char_u *)bp->b_fname); + u_read_undo(NULL, hash, bp->b_fname); } } } @@ -2044,14 +1978,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 @@ -2075,7 +2007,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va paste_option_changed(); } else if ((int *)varp == &p_ic && p_hls) { // when 'ignorecase' is set or reset and 'hlsearch' is set, redraw - redraw_all_later(SOME_VALID); + redraw_all_later(UPD_SOME_VALID); } else if ((int *)varp == &p_hls) { // when 'hlsearch' is set or reset: reset no_hlsearch set_no_hlsearch(false); @@ -2092,7 +2024,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va FOR_ALL_WINDOWS_IN_TAB(win, curtab) { if (win->w_p_pvw && win != curwin) { curwin->w_p_pvw = false; - return N_("E590: A preview window already exists"); + return e_preview_window_already_exists; } } } @@ -2111,10 +2043,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 = '\\'; @@ -2129,9 +2060,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; @@ -2151,18 +2081,16 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va } } else if ((int *)varp == &curwin->w_p_spell) { // 'spell' if (curwin->w_p_spell) { - char *errmsg = did_set_spelllang(curwin); - if (errmsg != NULL) { - emsg(_(errmsg)); - } + 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) { @@ -2173,13 +2101,13 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va // Enable Arabic shaping (major part of what Arabic requires) if (!p_arshape) { p_arshape = true; - redraw_all_later(NOT_VALID); + redraw_all_later(UPD_NOT_VALID); } } // 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)); @@ -2191,11 +2119,9 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va p_deco = true; // Force-set the necessary keymap for arabic. - set_option_value("keymap", 0L, "arabic", OPT_LOCAL); + 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) { @@ -2216,48 +2142,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), @@ -2271,7 +2165,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va } check_redraw(options[opt_idx].flags); - return NULL; + return errmsg; } /// Set the value of a number option, taking care of side effects @@ -2354,6 +2248,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) { @@ -2412,7 +2308,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) { @@ -2546,7 +2442,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) { @@ -2622,9 +2520,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")) { @@ -2664,41 +2563,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), @@ -2716,32 +2582,38 @@ 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) +void check_redraw_for(buf_T *buf, win_T *win, 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(); + changed_window_setting_win(win); } if (flags & P_RBUF) { - redraw_curbuf_later(NOT_VALID); + redraw_buf_later(buf, UPD_NOT_VALID); } if (flags & P_RWINONLY) { - redraw_later(curwin, NOT_VALID); + redraw_later(win, UPD_NOT_VALID); } - if (doclear) { - redraw_all_later(CLEAR); - } else if (all) { - redraw_all_later(NOT_VALID); + if (all) { + redraw_all_later(UPD_NOT_VALID); } } +void check_redraw(uint32_t flags) +{ + check_redraw_for(curbuf, curwin, flags); +} + /// Find index for named option /// /// @param[in] arg Option to find index for. @@ -2751,15 +2623,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; @@ -2804,11 +2675,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); } } @@ -2888,7 +2759,7 @@ bool set_tty_option(const char *name, char *value) void set_tty_background(const char *value) { - if (option_was_set("bg") || strequal((char *)p_bg, value)) { + if (option_was_set("bg") || strequal(p_bg, value)) { // background is already set... ignore return; } @@ -2898,7 +2769,7 @@ void set_tty_background(const char *value) ? "autocmd VimEnter * ++once ++nested set bg=light" : "autocmd VimEnter * ++once ++nested set bg=dark"); } else { - set_option_value("bg", 0L, value, 0); + set_option_value_give_err("bg", 0L, value, 0); reset_option_was_set("bg"); } } @@ -2917,6 +2788,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. @@ -2926,7 +2798,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; @@ -2937,14 +2810,19 @@ getoption_T get_option_value(const char *name, long *numval, char **stringval, i return gov_unknown; } - char_u *varp = 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 return gov_hidden_string; } if (stringval != NULL) { - if ((char_u **)varp == &p_pt) { // 'pastetoggle' + if ((char **)varp == &p_pt) { // 'pastetoggle' *stringval = str2special_save(*(char **)(varp), false, false); } else { *stringval = xstrdup(*(char **)(varp)); @@ -2992,7 +2870,6 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o return SOPT_STRING | SOPT_GLOBAL; } - char_u *varp = NULL; int rv = 0; int opt_idx = findoption(name); if (opt_idx < 0) { @@ -3028,15 +2905,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; } } @@ -3044,12 +2919,13 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o return rv; } + char_u *varp = NULL; + 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 @@ -3063,7 +2939,7 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o // only getting a pointer, no need to use aucmd_prepbuf() curbuf = (buf_T *)from; curwin->w_buffer = curbuf; - varp = get_varp_scope(p, OPT_LOCAL); + varp = (char_u *)get_varp_scope(p, OPT_LOCAL); curbuf = save_curbuf; curwin->w_buffer = curbuf; } @@ -3071,7 +2947,7 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o win_T *save_curwin = curwin; curwin = (win_T *)from; curbuf = curwin->w_buffer; - varp = get_varp_scope(p, OPT_LOCAL); + varp = (char_u *)get_varp_scope(p, OPT_LOCAL); curwin = save_curwin; curbuf = curwin->w_buffer; } @@ -3083,7 +2959,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 { @@ -3094,47 +2970,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 options[opt_idx].flags; -} - -/// Set a flag for the option at 'opt_idx'. -void set_option_flag(int opt_idx, uint32_t flag) +// Return information for option at 'opt_idx' +vimoption_T *get_option(int opt_idx) { - 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 @@ -3147,7 +2986,7 @@ bool is_hidden_option(int opt_idx) /// is cleared (the exact semantics of this depend /// on the option). /// -/// @return NULL on success, error message on error. +/// @return NULL on success, an untranslated error message on error. char *set_option_value(const char *const name, const long number, const char *const string, const int opt_flags) FUNC_ATTR_NONNULL_ARG(1) @@ -3156,65 +2995,83 @@ 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 { - uint32_t flags = options[opt_idx].flags; - // Disallow changing some options in the sandbox - if (sandbox > 0 && (flags & P_SECURE)) { - emsg(_(e_sandbox)); - return NULL; + return NULL; + } + + uint32_t flags = options[opt_idx].flags; + // Disallow changing some options in the sandbox + if (sandbox > 0 && (flags & P_SECURE)) { + emsg(_(e_sandbox)); + return NULL; + } + + if (flags & P_STRING) { + const char *s = string; + if (s == NULL || opt_flags & OPT_CLEAR) { + s = ""; } - if (flags & P_STRING) { - const char *s = string; - if (s == NULL || opt_flags & OPT_CLEAR) { - s = ""; - } - return set_string_option(opt_idx, s, opt_flags); - } - - varp = get_varp_scope(&(options[opt_idx]), opt_flags); - if (varp != NULL) { // hidden option is not changed - if (number == 0 && string != NULL) { - int idx; - - // Either we are given a string or we are setting option - // to zero. - for (idx = 0; string[idx] == '0'; idx++) {} - if (string[idx] != NUL || idx == 0) { - // There's another character after zeros or the string - // is empty. In both cases, we are trying to set a - // num option using a string. - semsg(_("E521: Number required: &%s = '%s'"), - name, string); - return NULL; // do nothing as we hit an error - } - } - long numval = number; - if (opt_flags & OPT_CLEAR) { - if ((int *)varp == &curbuf->b_p_ar) { - numval = -1; - } else if ((long *)varp == &curbuf->b_p_ul) { - numval = NO_LOCAL_UNDOLEVEL; - } else if ((long *)varp == &curwin->w_p_so || (long *)varp == &curwin->w_p_siso) { - numval = -1; - } else { - char *s = NULL; - (void)get_option_value(name, &numval, &s, 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_string_option(opt_idx, s, opt_flags); + } + + char_u *varp = (char_u *)get_varp_scope(&(options[opt_idx]), opt_flags); + if (varp == NULL) { + // hidden option is not changed + return NULL; + } + + if (number == 0 && string != NULL) { + int idx; + + // Either we are given a string or we are setting option + // to zero. + for (idx = 0; string[idx] == '0'; idx++) {} + if (string[idx] != NUL || idx == 0) { + // There's another character after zeros or the string + // is empty. In both cases, we are trying to set a + // num option using a string. + semsg(_("E521: Number required: &%s = '%s'"), + name, string); + return NULL; // do nothing as we hit an error + } + } + long numval = number; + if (opt_flags & OPT_CLEAR) { + if ((int *)varp == &curbuf->b_p_ar) { + numval = -1; + } else if ((long *)varp == &curbuf->b_p_ul) { + numval = NO_LOCAL_UNDOLEVEL; + } else if ((long *)varp == &curwin->w_p_so || (long *)varp == &curwin->w_p_siso) { + numval = -1; + } else { + char *s = NULL; + (void)get_option_value(name, &numval, &s, NULL, OPT_GLOBAL); } } - return NULL; + if (flags & P_NUM) { + return set_num_option(opt_idx, varp, numval, NULL, 0, opt_flags); + } + return set_bool_option(opt_idx, varp, (int)numval, opt_flags); +} + +/// Call set_option_value() and when an error is returned report it. +/// +/// @param opt_flags OPT_LOCAL or 0 (both) +void set_option_value_give_err(const char *name, long number, const char *string, int opt_flags) +{ + char *errmsg = set_option_value(name, number, string, opt_flags); + + if (errmsg != NULL) { + emsg(_(errmsg)); + } +} + +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. @@ -3228,19 +3085,18 @@ bool is_string_option(const char *name) // Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number. // When "has_lt" is true there is a '<' before "*arg_arg". // Returns 0 when the key is not recognized. -int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt) +int find_key_option_len(const char *arg_arg, size_t len, bool has_lt) { int key = 0; - int modifiers; - const char_u *arg = arg_arg; + const char *arg = 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 @@ -3250,9 +3106,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(arg, strlen(arg), has_lt); } /// if 'all' == 0: show changed options @@ -3261,16 +3117,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 @@ -3289,32 +3135,33 @@ 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((char_u *)p->fullname)) { + 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 = get_varp_scope(p, opt_flags); + varp = (char_u *)get_varp_scope(p, opt_flags); } } else { varp = get_varp(p); } 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)) { @@ -3323,15 +3170,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; } @@ -3339,18 +3186,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(); } } @@ -3358,7 +3204,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 @@ -3370,7 +3216,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 @@ -3405,13 +3251,12 @@ void ui_refresh_options(void) /// @param opt_flags OPT_LOCAL or OPT_GLOBAL static void showoneopt(vimoption_T *p, int opt_flags) { - char_u *varp; 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() - varp = get_varp_scope(p, opt_flags); + char_u *varp = (char_u *)get_varp_scope(p, opt_flags); // for 'modified' we also need to check if 'ff' or 'fenc' changed. if ((p->flags & P_BOOL) && ((int *)varp == &curbuf->b_changed @@ -3427,7 +3272,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; @@ -3456,25 +3301,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_u *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 @@ -3488,13 +3323,13 @@ 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; } // Global values are only written when not at the default value. - if ((opt_flags & OPT_GLOBAL) && optval_default(p, varp)) { + if ((opt_flags & OPT_GLOBAL) && optval_default(p, (char_u *)varp)) { continue; } @@ -3503,7 +3338,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 @@ -3513,11 +3349,11 @@ 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 = 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 = varp; - varp = varp_fresh; + varp_local = (char_u *)varp; + varp = (char *)varp_fresh; } } } @@ -3525,7 +3361,8 @@ 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 = varp_local, round++) { + for (; round <= 2; varp = (char *)varp_local, round++) { + char *cmd; if (round == 1 || (opt_flags & OPT_GLOBAL)) { cmd = "set"; } else { @@ -3553,8 +3390,7 @@ int makeset(FILE *fd, int opt_flags, int local_only) } do_endif = true; } - if (put_setstring(fd, cmd, p->fullname, (char_u **)varp, - p->flags) == FAIL) { + if (put_setstring(fd, cmd, p->fullname, (char **)varp, p->flags) == FAIL) { return FAIL; } if (do_endif) { @@ -3575,65 +3411,58 @@ int makeset(FILE *fd, int opt_flags, int local_only) int makefoldset(FILE *fd) { if (put_setstring(fd, "setlocal", "fdm", &curwin->w_p_fdm, 0) == FAIL - || put_setstring(fd, "setlocal", "fde", &curwin->w_p_fde, 0) - == FAIL - || put_setstring(fd, "setlocal", "fmr", &curwin->w_p_fmr, 0) - == FAIL - || put_setstring(fd, "setlocal", "fdi", &curwin->w_p_fdi, 0) - == FAIL + || put_setstring(fd, "setlocal", "fde", &curwin->w_p_fde, 0) == FAIL + || put_setstring(fd, "setlocal", "fmr", &curwin->w_p_fmr, 0) == FAIL + || put_setstring(fd, "setlocal", "fdi", &curwin->w_p_fdi, 0) == FAIL || put_setnum(fd, "setlocal", "fdl", &curwin->w_p_fdl) == FAIL || put_setnum(fd, "setlocal", "fml", &curwin->w_p_fml) == FAIL || put_setnum(fd, "setlocal", "fdn", &curwin->w_p_fdn) == FAIL - || put_setbool(fd, "setlocal", "fen", - curwin->w_p_fen) == FAIL) { + || put_setbool(fd, "setlocal", "fen", curwin->w_p_fen) == FAIL) { return FAIL; } return OK; } -static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, uint64_t flags) +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; } + + char *buf = NULL; + char_u *part = NULL; + if (*valuep != NULL) { // Output 'pastetoggle' as key names. For other // options some characters have to be escaped with // CTRL-V or backslash if (valuep == &p_pt) { - s = *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 *)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); - home_replace(NULL, (char *)(*valuep), (char *)buf, size, false); + home_replace(NULL, *valuep, buf, size, false); // If the option value is longer than MAXPATHL, we need to append // each comma separated part of the option separately, so that it // can be expanded when read back. if (size >= MAXPATHL && (flags & P_COMMA) != 0 - && vim_strchr((char *)(*valuep), ',') != NULL) { + && vim_strchr(*valuep, ',') != NULL) { part = xmalloc(size); // write line break to clear the option, e.g. ':set rtp=' if (put_eol(fd) == FAIL) { goto fail; } - p = (char *)buf; + char *p = buf; while (*p != NUL) { // for each comma separated option part, append value to // the option, :set rtp+=value @@ -3641,7 +3470,7 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, uint6 goto fail; } (void)copy_option_part(&p, (char *)part, size, ","); - if (put_escstr(fd, part, 2) == FAIL || put_eol(fd) == FAIL) { + if (put_escstr(fd, (char *)part, 2) == FAIL || put_eol(fd) == FAIL) { goto fail; } } @@ -3670,11 +3499,10 @@ fail: static int put_setnum(FILE *fd, char *cmd, char *name, long *valuep) { - long wc; - if (fprintf(fd, "%s %s=", cmd, name) < 0) { return FAIL; } + long wc; if (wc_use_keyname((char_u *)valuep, &wc)) { // print 'wildchar' and 'wildcharm' as a key name if (fputs((char *)get_special_key_name((int)wc, 0), fd) < 0) { @@ -3714,8 +3542,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); @@ -3780,7 +3607,7 @@ void unset_global_local_option(char *name, void *from) clear_string_option(&((win_T *)from)->w_p_stl); break; case PV_WBR: - clear_string_option((char_u **)&((win_T *)from)->w_p_wbr); + clear_string_option(&((win_T *)from)->w_p_wbr); break; case PV_UL: buf->b_p_ul = NO_LOCAL_UNDOLEVEL; @@ -3794,102 +3621,104 @@ void unset_global_local_option(char *name, void *from) case PV_LCS: clear_string_option(&((win_T *)from)->w_p_lcs); set_chars_option((win_T *)from, &((win_T *)from)->w_p_lcs, true); - redraw_later((win_T *)from, NOT_VALID); + redraw_later((win_T *)from, UPD_NOT_VALID); break; case PV_FCS: clear_string_option(&((win_T *)from)->w_p_fcs); set_chars_option((win_T *)from, &((win_T *)from)->w_p_fcs, true); - redraw_later((win_T *)from, NOT_VALID); + redraw_later((win_T *)from, UPD_NOT_VALID); break; case PV_VE: 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_u *get_varp_scope(vimoption_T *p, int opt_flags) +char *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win) { - if ((opt_flags & OPT_GLOBAL) && p->indir != PV_NONE) { + if ((scope & OPT_GLOBAL) && p->indir != PV_NONE) { if (p->var == VAR_WIN) { - return (char_u *)GLOBAL_WO(get_varp(p)); + return GLOBAL_WO(get_varp_from(p, buf, win)); } - return p->var; + 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_u *)&(curbuf->b_p_fp); + return (char *)&(buf->b_p_fp); case PV_EFM: - return (char_u *)&(curbuf->b_p_efm); + return (char *)&(buf->b_p_efm); case PV_GP: - return (char_u *)&(curbuf->b_p_gp); + return (char *)&(buf->b_p_gp); case PV_MP: - return (char_u *)&(curbuf->b_p_mp); + return (char *)&(buf->b_p_mp); case PV_EP: - return (char_u *)&(curbuf->b_p_ep); + return (char *)&(buf->b_p_ep); case PV_KP: - return (char_u *)&(curbuf->b_p_kp); + return (char *)&(buf->b_p_kp); case PV_PATH: - return (char_u *)&(curbuf->b_p_path); + return (char *)&(buf->b_p_path); case PV_AR: - return (char_u *)&(curbuf->b_p_ar); + return (char *)&(buf->b_p_ar); case PV_TAGS: - return (char_u *)&(curbuf->b_p_tags); + return (char *)&(buf->b_p_tags); case PV_TC: - return (char_u *)&(curbuf->b_p_tc); + return (char *)&(buf->b_p_tc); case PV_SISO: - return (char_u *)&(curwin->w_p_siso); + return (char *)&(win->w_p_siso); case PV_SO: - return (char_u *)&(curwin->w_p_so); + return (char *)&(win->w_p_so); case PV_DEF: - return (char_u *)&(curbuf->b_p_def); + return (char *)&(buf->b_p_def); case PV_INC: - return (char_u *)&(curbuf->b_p_inc); + return (char *)&(buf->b_p_inc); case PV_DICT: - return (char_u *)&(curbuf->b_p_dict); + return (char *)&(buf->b_p_dict); case PV_TSR: - return (char_u *)&(curbuf->b_p_tsr); + return (char *)&(buf->b_p_tsr); case PV_TSRFU: - return (char_u *)&(curbuf->b_p_tsrfu); + return (char *)&(buf->b_p_tsrfu); case PV_TFU: - return (char_u *)&(curbuf->b_p_tfu); + return (char *)&(buf->b_p_tfu); case PV_SBR: - return (char_u *)&(curwin->w_p_sbr); + return (char *)&(win->w_p_sbr); case PV_STL: - return (char_u *)&(curwin->w_p_stl); + return (char *)&(win->w_p_stl); case PV_WBR: - return (char_u *)&(curwin->w_p_wbr); + return (char *)&(win->w_p_wbr); case PV_UL: - return (char_u *)&(curbuf->b_p_ul); + return (char *)&(buf->b_p_ul); case PV_LW: - return (char_u *)&(curbuf->b_p_lw); + return (char *)&(buf->b_p_lw); case PV_BKC: - return (char_u *)&(curbuf->b_p_bkc); + return (char *)&(buf->b_p_bkc); case PV_MENC: - return (char_u *)&(curbuf->b_p_menc); + return (char *)&(buf->b_p_menc); case PV_FCS: - return (char_u *)&(curwin->w_p_fcs); + return (char *)&(win->w_p_fcs); case PV_LCS: - return (char_u *)&(curwin->w_p_lcs); + return (char *)&(win->w_p_lcs); case PV_VE: - return (char_u *)&(curwin->w_p_ve); + return (char *)&(win->w_p_ve); } return NULL; // "cannot happen" } - return get_varp(p); + return (char *)get_varp_from(p, buf, win); } -/// Get pointer to option variable at 'opt_idx', depending on local or global -/// scope. -char_u *get_option_varp_scope(int opt_idx, int opt_flags) +/// Get pointer to option variable, depending on local or global scope. +/// +/// @param scope can be OPT_LOCAL, OPT_GLOBAL or a combination. +char *get_varp_scope(vimoption_T *p, int scope) { - return get_varp_scope(&(options[opt_idx]), opt_flags); + return get_varp_scope_from(p, scope, curbuf, curwin); } -/// Get pointer to option variable. -static char_u *get_varp(vimoption_T *p) +static char_u *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) { // hidden option, always return NULL if (p->var == NULL) { @@ -3902,317 +3731,317 @@ static char_u *get_varp(vimoption_T *p) // global option with local value: use local value if it's been set case PV_EP: - return *curbuf->b_p_ep != NUL - ? (char_u *)&curbuf->b_p_ep : p->var; + return *buf->b_p_ep != NUL + ? (char_u *)&buf->b_p_ep : p->var; case PV_KP: - return *curbuf->b_p_kp != NUL - ? (char_u *)&curbuf->b_p_kp : p->var; + return *buf->b_p_kp != NUL + ? (char_u *)&buf->b_p_kp : p->var; case PV_PATH: - return *curbuf->b_p_path != NUL - ? (char_u *)&(curbuf->b_p_path) : p->var; + return *buf->b_p_path != NUL + ? (char_u *)&(buf->b_p_path) : p->var; case PV_AR: - return curbuf->b_p_ar >= 0 - ? (char_u *)&(curbuf->b_p_ar) : p->var; + return buf->b_p_ar >= 0 + ? (char_u *)&(buf->b_p_ar) : p->var; case PV_TAGS: - return *curbuf->b_p_tags != NUL - ? (char_u *)&(curbuf->b_p_tags) : p->var; + return *buf->b_p_tags != NUL + ? (char_u *)&(buf->b_p_tags) : p->var; case PV_TC: - return *curbuf->b_p_tc != NUL - ? (char_u *)&(curbuf->b_p_tc) : p->var; + return *buf->b_p_tc != NUL + ? (char_u *)&(buf->b_p_tc) : p->var; case PV_SISO: - return curwin->w_p_siso >= 0 - ? (char_u *)&(curwin->w_p_siso) : p->var; + return win->w_p_siso >= 0 + ? (char_u *)&(win->w_p_siso) : p->var; case PV_SO: - return curwin->w_p_so >= 0 - ? (char_u *)&(curwin->w_p_so) : p->var; + return win->w_p_so >= 0 + ? (char_u *)&(win->w_p_so) : p->var; case PV_BKC: - return *curbuf->b_p_bkc != NUL - ? (char_u *)&(curbuf->b_p_bkc) : p->var; + return *buf->b_p_bkc != NUL + ? (char_u *)&(buf->b_p_bkc) : p->var; case PV_DEF: - return *curbuf->b_p_def != NUL - ? (char_u *)&(curbuf->b_p_def) : p->var; + return *buf->b_p_def != NUL + ? (char_u *)&(buf->b_p_def) : p->var; case PV_INC: - return *curbuf->b_p_inc != NUL - ? (char_u *)&(curbuf->b_p_inc) : p->var; + return *buf->b_p_inc != NUL + ? (char_u *)&(buf->b_p_inc) : p->var; case PV_DICT: - return *curbuf->b_p_dict != NUL - ? (char_u *)&(curbuf->b_p_dict) : p->var; + return *buf->b_p_dict != NUL + ? (char_u *)&(buf->b_p_dict) : p->var; case PV_TSR: - return *curbuf->b_p_tsr != NUL - ? (char_u *)&(curbuf->b_p_tsr) : p->var; + return *buf->b_p_tsr != NUL + ? (char_u *)&(buf->b_p_tsr) : p->var; case PV_TSRFU: - return *curbuf->b_p_tsrfu != NUL - ? (char_u *)&(curbuf->b_p_tsrfu) : p->var; + return *buf->b_p_tsrfu != NUL + ? (char_u *)&(buf->b_p_tsrfu) : p->var; case PV_FP: - return *curbuf->b_p_fp != NUL - ? (char_u *)&(curbuf->b_p_fp) : p->var; + return *buf->b_p_fp != NUL + ? (char_u *)&(buf->b_p_fp) : p->var; case PV_EFM: - return *curbuf->b_p_efm != NUL - ? (char_u *)&(curbuf->b_p_efm) : p->var; + return *buf->b_p_efm != NUL + ? (char_u *)&(buf->b_p_efm) : p->var; case PV_GP: - return *curbuf->b_p_gp != NUL - ? (char_u *)&(curbuf->b_p_gp) : p->var; + return *buf->b_p_gp != NUL + ? (char_u *)&(buf->b_p_gp) : p->var; case PV_MP: - return *curbuf->b_p_mp != NUL - ? (char_u *)&(curbuf->b_p_mp) : p->var; + return *buf->b_p_mp != NUL + ? (char_u *)&(buf->b_p_mp) : p->var; case PV_SBR: - return *curwin->w_p_sbr != NUL - ? (char_u *)&(curwin->w_p_sbr) : p->var; + return *win->w_p_sbr != NUL + ? (char_u *)&(win->w_p_sbr) : p->var; case PV_STL: - return *curwin->w_p_stl != NUL - ? (char_u *)&(curwin->w_p_stl) : p->var; + return *win->w_p_stl != NUL + ? (char_u *)&(win->w_p_stl) : p->var; case PV_WBR: - return *curwin->w_p_wbr != NUL - ? (char_u *)&(curwin->w_p_wbr) : p->var; + return *win->w_p_wbr != NUL + ? (char_u *)&(win->w_p_wbr) : p->var; case PV_UL: - return curbuf->b_p_ul != NO_LOCAL_UNDOLEVEL - ? (char_u *)&(curbuf->b_p_ul) : p->var; + return buf->b_p_ul != NO_LOCAL_UNDOLEVEL + ? (char_u *)&(buf->b_p_ul) : p->var; case PV_LW: - return *curbuf->b_p_lw != NUL - ? (char_u *)&(curbuf->b_p_lw) : p->var; + return *buf->b_p_lw != NUL + ? (char_u *)&(buf->b_p_lw) : p->var; case PV_MENC: - return *curbuf->b_p_menc != NUL - ? (char_u *)&(curbuf->b_p_menc) : p->var; + return *buf->b_p_menc != NUL + ? (char_u *)&(buf->b_p_menc) : p->var; case PV_FCS: - return *curwin->w_p_fcs != NUL - ? (char_u *)&(curwin->w_p_fcs) : p->var; + return *win->w_p_fcs != NUL + ? (char_u *)&(win->w_p_fcs) : p->var; case PV_LCS: - return *curwin->w_p_lcs != NUL - ? (char_u *)&(curwin->w_p_lcs) : p->var; + return *win->w_p_lcs != NUL + ? (char_u *)&(win->w_p_lcs) : p->var; case PV_VE: - return *curwin->w_p_ve != NUL - ? (char_u *)&curwin->w_p_ve : p->var; + return *win->w_p_ve != NUL + ? (char_u *)&win->w_p_ve : p->var; case PV_ARAB: - return (char_u *)&(curwin->w_p_arab); + return (char_u *)&(win->w_p_arab); case PV_LIST: - return (char_u *)&(curwin->w_p_list); + return (char_u *)&(win->w_p_list); case PV_SPELL: - return (char_u *)&(curwin->w_p_spell); + return (char_u *)&(win->w_p_spell); case PV_CUC: - return (char_u *)&(curwin->w_p_cuc); + return (char_u *)&(win->w_p_cuc); case PV_CUL: - return (char_u *)&(curwin->w_p_cul); + return (char_u *)&(win->w_p_cul); case PV_CULOPT: - return (char_u *)&(curwin->w_p_culopt); + return (char_u *)&(win->w_p_culopt); case PV_CC: - return (char_u *)&(curwin->w_p_cc); + return (char_u *)&(win->w_p_cc); case PV_DIFF: - return (char_u *)&(curwin->w_p_diff); + return (char_u *)&(win->w_p_diff); case PV_FDC: - return (char_u *)&(curwin->w_p_fdc); + return (char_u *)&(win->w_p_fdc); case PV_FEN: - return (char_u *)&(curwin->w_p_fen); + return (char_u *)&(win->w_p_fen); case PV_FDI: - return (char_u *)&(curwin->w_p_fdi); + return (char_u *)&(win->w_p_fdi); case PV_FDL: - return (char_u *)&(curwin->w_p_fdl); + return (char_u *)&(win->w_p_fdl); case PV_FDM: - return (char_u *)&(curwin->w_p_fdm); + return (char_u *)&(win->w_p_fdm); case PV_FML: - return (char_u *)&(curwin->w_p_fml); + return (char_u *)&(win->w_p_fml); case PV_FDN: - return (char_u *)&(curwin->w_p_fdn); + return (char_u *)&(win->w_p_fdn); case PV_FDE: - return (char_u *)&(curwin->w_p_fde); + return (char_u *)&(win->w_p_fde); case PV_FDT: - return (char_u *)&(curwin->w_p_fdt); + return (char_u *)&(win->w_p_fdt); case PV_FMR: - return (char_u *)&(curwin->w_p_fmr); + return (char_u *)&(win->w_p_fmr); case PV_NU: - return (char_u *)&(curwin->w_p_nu); + return (char_u *)&(win->w_p_nu); case PV_RNU: - return (char_u *)&(curwin->w_p_rnu); + return (char_u *)&(win->w_p_rnu); case PV_NUW: - return (char_u *)&(curwin->w_p_nuw); + return (char_u *)&(win->w_p_nuw); case PV_WFH: - return (char_u *)&(curwin->w_p_wfh); + return (char_u *)&(win->w_p_wfh); case PV_WFW: - return (char_u *)&(curwin->w_p_wfw); + return (char_u *)&(win->w_p_wfw); case PV_PVW: - return (char_u *)&(curwin->w_p_pvw); + return (char_u *)&(win->w_p_pvw); case PV_RL: - return (char_u *)&(curwin->w_p_rl); + return (char_u *)&(win->w_p_rl); case PV_RLC: - return (char_u *)&(curwin->w_p_rlc); + return (char_u *)&(win->w_p_rlc); case PV_SCROLL: - return (char_u *)&(curwin->w_p_scr); + return (char_u *)&(win->w_p_scr); case PV_WRAP: - return (char_u *)&(curwin->w_p_wrap); + return (char_u *)&(win->w_p_wrap); case PV_LBR: - return (char_u *)&(curwin->w_p_lbr); + return (char_u *)&(win->w_p_lbr); case PV_BRI: - return (char_u *)&(curwin->w_p_bri); + return (char_u *)&(win->w_p_bri); case PV_BRIOPT: - return (char_u *)&(curwin->w_p_briopt); + return (char_u *)&(win->w_p_briopt); case PV_SCBIND: - return (char_u *)&(curwin->w_p_scb); + return (char_u *)&(win->w_p_scb); case PV_CRBIND: - return (char_u *)&(curwin->w_p_crb); + return (char_u *)&(win->w_p_crb); case PV_COCU: - return (char_u *)&(curwin->w_p_cocu); + return (char_u *)&(win->w_p_cocu); case PV_COLE: - return (char_u *)&(curwin->w_p_cole); + return (char_u *)&(win->w_p_cole); case PV_AI: - return (char_u *)&(curbuf->b_p_ai); + return (char_u *)&(buf->b_p_ai); case PV_BIN: - return (char_u *)&(curbuf->b_p_bin); + return (char_u *)&(buf->b_p_bin); case PV_BOMB: - return (char_u *)&(curbuf->b_p_bomb); + return (char_u *)&(buf->b_p_bomb); case PV_BH: - return (char_u *)&(curbuf->b_p_bh); + return (char_u *)&(buf->b_p_bh); case PV_BT: - return (char_u *)&(curbuf->b_p_bt); + return (char_u *)&(buf->b_p_bt); case PV_BL: - return (char_u *)&(curbuf->b_p_bl); + return (char_u *)&(buf->b_p_bl); case PV_CHANNEL: - return (char_u *)&(curbuf->b_p_channel); + return (char_u *)&(buf->b_p_channel); case PV_CI: - return (char_u *)&(curbuf->b_p_ci); + return (char_u *)&(buf->b_p_ci); case PV_CIN: - return (char_u *)&(curbuf->b_p_cin); + return (char_u *)&(buf->b_p_cin); case PV_CINK: - return (char_u *)&(curbuf->b_p_cink); + return (char_u *)&(buf->b_p_cink); case PV_CINO: - return (char_u *)&(curbuf->b_p_cino); + return (char_u *)&(buf->b_p_cino); case PV_CINSD: - return (char_u *)&(curbuf->b_p_cinsd); + return (char_u *)&(buf->b_p_cinsd); case PV_CINW: - return (char_u *)&(curbuf->b_p_cinw); + return (char_u *)&(buf->b_p_cinw); case PV_COM: - return (char_u *)&(curbuf->b_p_com); + return (char_u *)&(buf->b_p_com); case PV_CMS: - return (char_u *)&(curbuf->b_p_cms); + return (char_u *)&(buf->b_p_cms); case PV_CPT: - return (char_u *)&(curbuf->b_p_cpt); + return (char_u *)&(buf->b_p_cpt); #ifdef BACKSLASH_IN_FILENAME case PV_CSL: - return (char_u *)&(curbuf->b_p_csl); + return (char_u *)&(buf->b_p_csl); #endif case PV_CFU: - return (char_u *)&(curbuf->b_p_cfu); + return (char_u *)&(buf->b_p_cfu); case PV_OFU: - return (char_u *)&(curbuf->b_p_ofu); + return (char_u *)&(buf->b_p_ofu); + case PV_EOF: + return (char_u *)&(buf->b_p_eof); case PV_EOL: - return (char_u *)&(curbuf->b_p_eol); + return (char_u *)&(buf->b_p_eol); case PV_FIXEOL: - return (char_u *)&(curbuf->b_p_fixeol); + return (char_u *)&(buf->b_p_fixeol); case PV_ET: - return (char_u *)&(curbuf->b_p_et); + return (char_u *)&(buf->b_p_et); case PV_FENC: - return (char_u *)&(curbuf->b_p_fenc); + return (char_u *)&(buf->b_p_fenc); case PV_FF: - return (char_u *)&(curbuf->b_p_ff); + return (char_u *)&(buf->b_p_ff); case PV_FT: - return (char_u *)&(curbuf->b_p_ft); + return (char_u *)&(buf->b_p_ft); case PV_FO: - return (char_u *)&(curbuf->b_p_fo); + return (char_u *)&(buf->b_p_fo); case PV_FLP: - return (char_u *)&(curbuf->b_p_flp); + return (char_u *)&(buf->b_p_flp); case PV_IMI: - return (char_u *)&(curbuf->b_p_iminsert); + return (char_u *)&(buf->b_p_iminsert); case PV_IMS: - return (char_u *)&(curbuf->b_p_imsearch); + return (char_u *)&(buf->b_p_imsearch); case PV_INF: - return (char_u *)&(curbuf->b_p_inf); + return (char_u *)&(buf->b_p_inf); case PV_ISK: - return (char_u *)&(curbuf->b_p_isk); + return (char_u *)&(buf->b_p_isk); case PV_INEX: - return (char_u *)&(curbuf->b_p_inex); + return (char_u *)&(buf->b_p_inex); case PV_INDE: - return (char_u *)&(curbuf->b_p_inde); + return (char_u *)&(buf->b_p_inde); case PV_INDK: - return (char_u *)&(curbuf->b_p_indk); + return (char_u *)&(buf->b_p_indk); case PV_FEX: - return (char_u *)&(curbuf->b_p_fex); + return (char_u *)&(buf->b_p_fex); case PV_LISP: - return (char_u *)&(curbuf->b_p_lisp); + return (char_u *)&(buf->b_p_lisp); + case PV_LOP: + return (char_u *)&(buf->b_p_lop); case PV_ML: - return (char_u *)&(curbuf->b_p_ml); + return (char_u *)&(buf->b_p_ml); case PV_MPS: - return (char_u *)&(curbuf->b_p_mps); + return (char_u *)&(buf->b_p_mps); case PV_MA: - return (char_u *)&(curbuf->b_p_ma); + return (char_u *)&(buf->b_p_ma); case PV_MOD: - return (char_u *)&(curbuf->b_changed); + return (char_u *)&(buf->b_changed); case PV_NF: - return (char_u *)&(curbuf->b_p_nf); + return (char_u *)&(buf->b_p_nf); case PV_PI: - return (char_u *)&(curbuf->b_p_pi); + return (char_u *)&(buf->b_p_pi); case PV_QE: - return (char_u *)&(curbuf->b_p_qe); + return (char_u *)&(buf->b_p_qe); case PV_RO: - return (char_u *)&(curbuf->b_p_ro); + return (char_u *)&(buf->b_p_ro); case PV_SCBK: - return (char_u *)&(curbuf->b_p_scbk); + return (char_u *)&(buf->b_p_scbk); case PV_SI: - return (char_u *)&(curbuf->b_p_si); + return (char_u *)&(buf->b_p_si); case PV_STS: - return (char_u *)&(curbuf->b_p_sts); + return (char_u *)&(buf->b_p_sts); case PV_SUA: - return (char_u *)&(curbuf->b_p_sua); + return (char_u *)&(buf->b_p_sua); case PV_SWF: - return (char_u *)&(curbuf->b_p_swf); + return (char_u *)&(buf->b_p_swf); case PV_SMC: - return (char_u *)&(curbuf->b_p_smc); + return (char_u *)&(buf->b_p_smc); case PV_SYN: - return (char_u *)&(curbuf->b_p_syn); + return (char_u *)&(buf->b_p_syn); case PV_SPC: - return (char_u *)&(curwin->w_s->b_p_spc); + return (char_u *)&(win->w_s->b_p_spc); case PV_SPF: - return (char_u *)&(curwin->w_s->b_p_spf); + return (char_u *)&(win->w_s->b_p_spf); case PV_SPL: - return (char_u *)&(curwin->w_s->b_p_spl); + return (char_u *)&(win->w_s->b_p_spl); case PV_SPO: - return (char_u *)&(curwin->w_s->b_p_spo); + return (char_u *)&(win->w_s->b_p_spo); case PV_SW: - return (char_u *)&(curbuf->b_p_sw); + return (char_u *)&(buf->b_p_sw); case PV_TFU: - return (char_u *)&(curbuf->b_p_tfu); + return (char_u *)&(buf->b_p_tfu); case PV_UMF: - return (char_u *)&(curbuf->b_p_umf); + return (char_u *)&(buf->b_p_umf); case PV_TS: - return (char_u *)&(curbuf->b_p_ts); + return (char_u *)&(buf->b_p_ts); case PV_TW: - return (char_u *)&(curbuf->b_p_tw); + return (char_u *)&(buf->b_p_tw); case PV_UDF: - return (char_u *)&(curbuf->b_p_udf); + return (char_u *)&(buf->b_p_udf); case PV_WM: - return (char_u *)&(curbuf->b_p_wm); + return (char_u *)&(buf->b_p_wm); case PV_VSTS: - return (char_u *)&(curbuf->b_p_vsts); + return (char_u *)&(buf->b_p_vsts); case PV_VTS: - return (char_u *)&(curbuf->b_p_vts); + return (char_u *)&(buf->b_p_vts); case PV_KMAP: - return (char_u *)&(curbuf->b_p_keymap); + return (char_u *)&(buf->b_p_keymap); case PV_SCL: - return (char_u *)&(curwin->w_p_scl); + return (char_u *)&(win->w_p_scl); case PV_WINHL: - return (char_u *)&(curwin->w_p_winhl); + return (char_u *)&(win->w_p_winhl); case PV_WINBL: - return (char_u *)&(curwin->w_p_winbl); + return (char_u *)&(win->w_p_winbl); + case PV_STC: + return (char_u *)&(win->w_p_stc); default: iemsg(_("E356: get_varp ERROR")); } // always return a valid pointer to avoid a crash! - 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 (char_u *)&(buf->b_p_wm); } -/// Return the full name of the option at 'opt_idx' -char *get_option_fullname(int opt_idx) +/// Get pointer to option variable. +static inline char_u *get_varp(vimoption_T *p) { - return options[opt_idx].fullname; + return get_varp_from(p, curbuf, curwin); } /// Get the value of 'equalprg', either the buffer-local one or the global one. -char_u *get_equalprg(void) +char *get_equalprg(void) { if (*curbuf->b_p_ep == NUL) { return p_ep; @@ -4229,6 +4058,14 @@ void win_copy_options(win_T *wp_from, win_T *wp_to) didset_window_options(wp_to, true); } +static char *copy_option_val(const char *val) +{ + if (val == empty_option) { + return empty_option; // no need to allocate memory + } + return xstrdup(val); +} + /// Copy the options from one winopt_T to another. /// Doesn't free the old option values in "to", use clear_winopt() for that. /// The 'scroll' option is not copied, because it depends on the window height. @@ -4237,21 +4074,23 @@ void copy_winopt(winopt_T *from, winopt_T *to) { to->wo_arab = from->wo_arab; to->wo_list = from->wo_list; + to->wo_lcs = copy_option_val(from->wo_lcs); + to->wo_fcs = copy_option_val(from->wo_fcs); to->wo_nu = from->wo_nu; to->wo_rnu = from->wo_rnu; - to->wo_ve = vim_strsave(from->wo_ve); + to->wo_ve = copy_option_val(from->wo_ve); to->wo_ve_flags = from->wo_ve_flags; to->wo_nuw = from->wo_nuw; to->wo_rl = from->wo_rl; - to->wo_rlc = vim_strsave(from->wo_rlc); - to->wo_sbr = vim_strsave(from->wo_sbr); - to->wo_stl = vim_strsave(from->wo_stl); - to->wo_wbr = xstrdup(from->wo_wbr); + to->wo_rlc = copy_option_val(from->wo_rlc); + to->wo_sbr = copy_option_val(from->wo_sbr); + to->wo_stl = copy_option_val(from->wo_stl); + to->wo_wbr = copy_option_val(from->wo_wbr); to->wo_wrap = from->wo_wrap; to->wo_wrap_save = from->wo_wrap_save; to->wo_lbr = from->wo_lbr; to->wo_bri = from->wo_bri; - to->wo_briopt = vim_strsave(from->wo_briopt); + to->wo_briopt = copy_option_val(from->wo_briopt); to->wo_scb = from->wo_scb; to->wo_scb_save = from->wo_scb_save; to->wo_crb = from->wo_crb; @@ -4259,33 +4098,30 @@ void copy_winopt(winopt_T *from, winopt_T *to) to->wo_spell = from->wo_spell; to->wo_cuc = from->wo_cuc; to->wo_cul = from->wo_cul; - to->wo_culopt = vim_strsave(from->wo_culopt); - to->wo_cc = vim_strsave(from->wo_cc); + to->wo_culopt = copy_option_val(from->wo_culopt); + to->wo_cc = copy_option_val(from->wo_cc); to->wo_diff = from->wo_diff; to->wo_diff_saved = from->wo_diff_saved; - to->wo_cocu = vim_strsave(from->wo_cocu); + to->wo_cocu = copy_option_val(from->wo_cocu); to->wo_cole = from->wo_cole; - to->wo_fdc = vim_strsave(from->wo_fdc); - to->wo_fdc_save = from->wo_diff_saved - ? vim_strsave(from->wo_fdc_save) : empty_option; + to->wo_fdc = copy_option_val(from->wo_fdc); + to->wo_fdc_save = from->wo_diff_saved ? xstrdup(from->wo_fdc_save) : empty_option; to->wo_fen = from->wo_fen; to->wo_fen_save = from->wo_fen_save; - to->wo_fdi = vim_strsave(from->wo_fdi); + to->wo_fdi = copy_option_val(from->wo_fdi); to->wo_fml = from->wo_fml; to->wo_fdl = from->wo_fdl; to->wo_fdl_save = from->wo_fdl_save; - to->wo_fdm = vim_strsave(from->wo_fdm); - to->wo_fdm_save = from->wo_diff_saved - ? vim_strsave(from->wo_fdm_save) : empty_option; + to->wo_fdm = copy_option_val(from->wo_fdm); + to->wo_fdm_save = from->wo_diff_saved ? xstrdup(from->wo_fdm_save) : empty_option; to->wo_fdn = from->wo_fdn; - to->wo_fde = vim_strsave(from->wo_fde); - to->wo_fdt = vim_strsave(from->wo_fdt); - to->wo_fmr = vim_strsave(from->wo_fmr); - to->wo_scl = vim_strsave(from->wo_scl); - to->wo_winhl = vim_strsave(from->wo_winhl); - to->wo_fcs = vim_strsave(from->wo_fcs); - to->wo_lcs = vim_strsave(from->wo_lcs); + to->wo_fde = copy_option_val(from->wo_fde); + to->wo_fdt = copy_option_val(from->wo_fdt); + to->wo_fmr = copy_option_val(from->wo_fmr); + 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)); @@ -4319,10 +4155,11 @@ static void check_winopt(winopt_T *wop) check_string_option(&wop->wo_cocu); check_string_option(&wop->wo_briopt); check_string_option(&wop->wo_winhl); - check_string_option(&wop->wo_fcs); check_string_option(&wop->wo_lcs); + check_string_option(&wop->wo_fcs); check_string_option(&wop->wo_ve); - check_string_option((char_u **)&wop->wo_wbr); + check_string_option(&wop->wo_wbr); + check_string_option(&wop->wo_stc); } /// Free the allocated memory inside a winopt_T. @@ -4345,10 +4182,11 @@ void clear_winopt(winopt_T *wop) clear_string_option(&wop->wo_cocu); clear_string_option(&wop->wo_briopt); clear_string_option(&wop->wo_winhl); - clear_string_option(&wop->wo_fcs); clear_string_option(&wop->wo_lcs); + clear_string_option(&wop->wo_fcs); clear_string_option(&wop->wo_ve); - clear_string_option((char_u **)&wop->wo_wbr); + clear_string_option(&wop->wo_wbr); + clear_string_option(&wop->wo_stc); } void didset_window_options(win_T *wp, bool valid_cursor) @@ -4394,14 +4232,11 @@ static void init_buf_opt_idx(void) 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; + char *save_p_isk = NULL; // init for GCC 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'. @@ -4428,7 +4263,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 = buf->b_p_isk; buf->b_p_isk = NULL; @@ -4438,19 +4273,19 @@ void buf_copy_options(buf_T *buf, int flags) if (!buf->b_p_initialized) { free_buf_options(buf, true); buf->b_p_ro = false; // don't copy readonly - buf->b_p_fenc = vim_strsave(p_fenc); + buf->b_p_fenc = xstrdup(p_fenc); switch (*p_ffs) { case 'm': - buf->b_p_ff = vim_strsave((char_u *)FF_MAC); + buf->b_p_ff = xstrdup(FF_MAC); break; case 'd': - buf->b_p_ff = vim_strsave((char_u *)FF_DOS); + buf->b_p_ff = xstrdup(FF_DOS); break; case 'u': - buf->b_p_ff = vim_strsave((char_u *)FF_UNIX); + buf->b_p_ff = xstrdup(FF_UNIX); break; default: - buf->b_p_ff = vim_strsave(p_ff); + buf->b_p_ff = xstrdup(p_ff); break; } buf->b_p_bh = empty_option; @@ -4495,44 +4330,45 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_swf = p_swf; COPY_OPT_SCTX(buf, BV_SWF); } - buf->b_p_cpt = vim_strsave(p_cpt); + 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 = vim_strsave(p_cfu); + buf->b_p_cfu = xstrdup(p_cfu); COPY_OPT_SCTX(buf, BV_CFU); - buf->b_p_ofu = vim_strsave(p_ofu); + set_buflocal_cfu_callback(buf); + buf->b_p_ofu = xstrdup(p_ofu); COPY_OPT_SCTX(buf, BV_OFU); - buf->b_p_tfu = vim_strsave(p_tfu); + set_buflocal_ofu_callback(buf); + buf->b_p_tfu = xstrdup(p_tfu); COPY_OPT_SCTX(buf, BV_TFU); - buf->b_p_umf = vim_strsave(p_umf); + buf->b_p_umf = xstrdup(p_umf); COPY_OPT_SCTX(buf, BV_UMF); + 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; - buf->b_p_vsts = vim_strsave(p_vsts); + buf->b_p_vsts = xstrdup(p_vsts); COPY_OPT_SCTX(buf, BV_VSTS); if (p_vsts && p_vsts != empty_option) { (void)tabstop_set(p_vsts, &buf->b_p_vsts_array); } else { buf->b_p_vsts_array = NULL; } - buf->b_p_vsts_nopaste = p_vsts_nopaste - ? vim_strsave(p_vsts_nopaste) - : NULL; - buf->b_p_com = vim_strsave(p_com); + buf->b_p_vsts_nopaste = p_vsts_nopaste ? xstrdup(p_vsts_nopaste) : NULL; + buf->b_p_com = xstrdup(p_com); COPY_OPT_SCTX(buf, BV_COM); - buf->b_p_cms = vim_strsave(p_cms); + buf->b_p_cms = xstrdup(p_cms); COPY_OPT_SCTX(buf, BV_CMS); - buf->b_p_fo = vim_strsave(p_fo); + buf->b_p_fo = xstrdup(p_fo); COPY_OPT_SCTX(buf, BV_FO); - buf->b_p_flp = vim_strsave(p_flp); + buf->b_p_flp = xstrdup(p_flp); COPY_OPT_SCTX(buf, BV_FLP); - buf->b_p_nf = vim_strsave(p_nf); + buf->b_p_nf = xstrdup(p_nf); COPY_OPT_SCTX(buf, BV_NF); - buf->b_p_mps = vim_strsave(p_mps); + buf->b_p_mps = xstrdup(p_mps); COPY_OPT_SCTX(buf, BV_MPS); buf->b_p_si = p_si; COPY_OPT_SCTX(buf, BV_SI); @@ -4542,18 +4378,20 @@ void buf_copy_options(buf_T *buf, int flags) COPY_OPT_SCTX(buf, BV_CI); buf->b_p_cin = p_cin; COPY_OPT_SCTX(buf, BV_CIN); - buf->b_p_cink = vim_strsave(p_cink); + buf->b_p_cink = xstrdup(p_cink); COPY_OPT_SCTX(buf, BV_CINK); - buf->b_p_cino = vim_strsave(p_cino); + buf->b_p_cino = xstrdup(p_cino); COPY_OPT_SCTX(buf, BV_CINO); - buf->b_p_cinsd = vim_strsave(p_cinsd); + 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; buf->b_p_pi = p_pi; COPY_OPT_SCTX(buf, BV_PI); - buf->b_p_cinw = vim_strsave(p_cinw); + buf->b_p_cinw = xstrdup(p_cinw); COPY_OPT_SCTX(buf, BV_CINW); buf->b_p_lisp = p_lisp; COPY_OPT_SCTX(buf, BV_LISP); @@ -4562,25 +4400,25 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_smc = p_smc; COPY_OPT_SCTX(buf, BV_SMC); buf->b_s.b_syn_isk = empty_option; - buf->b_s.b_p_spc = vim_strsave(p_spc); + buf->b_s.b_p_spc = xstrdup(p_spc); COPY_OPT_SCTX(buf, BV_SPC); (void)compile_cap_prog(&buf->b_s); - buf->b_s.b_p_spf = vim_strsave(p_spf); + buf->b_s.b_p_spf = xstrdup(p_spf); COPY_OPT_SCTX(buf, BV_SPF); - buf->b_s.b_p_spl = vim_strsave(p_spl); + buf->b_s.b_p_spl = xstrdup(p_spl); COPY_OPT_SCTX(buf, BV_SPL); - buf->b_s.b_p_spo = vim_strsave(p_spo); + buf->b_s.b_p_spo = xstrdup(p_spo); COPY_OPT_SCTX(buf, BV_SPO); - buf->b_p_inde = vim_strsave(p_inde); + buf->b_p_inde = xstrdup(p_inde); COPY_OPT_SCTX(buf, BV_INDE); - buf->b_p_indk = vim_strsave(p_indk); + buf->b_p_indk = xstrdup(p_indk); COPY_OPT_SCTX(buf, BV_INDK); buf->b_p_fp = empty_option; - buf->b_p_fex = vim_strsave(p_fex); + buf->b_p_fex = xstrdup(p_fex); COPY_OPT_SCTX(buf, BV_FEX); - buf->b_p_sua = vim_strsave(p_sua); + buf->b_p_sua = xstrdup(p_sua); COPY_OPT_SCTX(buf, BV_SUA); - buf->b_p_keymap = vim_strsave(p_keymap); + buf->b_p_keymap = xstrdup(p_keymap); COPY_OPT_SCTX(buf, BV_KMAP); buf->b_kmap_state |= KEYMAP_INIT; // This isn't really an option, but copying the langmap and IME @@ -4607,24 +4445,22 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_tc_flags = 0; buf->b_p_def = empty_option; buf->b_p_inc = empty_option; - buf->b_p_inex = vim_strsave(p_inex); + buf->b_p_inex = xstrdup(p_inex); COPY_OPT_SCTX(buf, BV_INEX); buf->b_p_dict = empty_option; buf->b_p_tsr = empty_option; buf->b_p_tsrfu = empty_option; - buf->b_p_qe = vim_strsave(p_qe); + buf->b_p_qe = xstrdup(p_qe); COPY_OPT_SCTX(buf, BV_QE); buf->b_p_udf = p_udf; COPY_OPT_SCTX(buf, BV_UDF); 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 = save_p_isk; if (p_vts && p_vts != empty_option && !buf->b_p_vts_array) { @@ -4633,12 +4469,12 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_vts_array = NULL; } } else { - buf->b_p_isk = vim_strsave(p_isk); + buf->b_p_isk = xstrdup(p_isk); COPY_OPT_SCTX(buf, BV_ISK); did_isk = true; buf->b_p_ts = p_ts; COPY_OPT_SCTX(buf, BV_TS); - buf->b_p_vts = vim_strsave(p_vts); + buf->b_p_vts = xstrdup(p_vts); COPY_OPT_SCTX(buf, BV_VTS); if (p_vts && p_vts != empty_option && !buf->b_p_vts_array) { (void)tabstop_set(p_vts, &buf->b_p_vts_array); @@ -4654,10 +4490,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; } @@ -4683,15 +4517,15 @@ void reset_modifiable(void) } /// Set the global value for 'iminsert' to the local value. -void set_iminsert_global(void) +void set_iminsert_global(buf_T *buf) { - p_iminsert = curbuf->b_p_iminsert; + p_iminsert = buf->b_p_iminsert; } /// Set the global value for 'imsearch' to the local value. -void set_imsearch_global(void) +void set_imsearch_global(buf_T *buf) { - p_imsearch = curbuf->b_p_imsearch; + p_imsearch = buf->b_p_imsearch; } static int expand_option_idx = -1; @@ -4699,30 +4533,22 @@ 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; - 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; + char *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) == '\\') { @@ -4736,23 +4562,29 @@ 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; + uint32_t flags = 0; + int opt_idx = 0; + int is_term_option = false; + 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; @@ -4772,8 +4604,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 == '*') { @@ -4812,7 +4644,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; @@ -4820,30 +4652,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; @@ -4853,57 +4684,100 @@ 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; } } } -int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***file) +/// Returns true if "str" either matches "regmatch" or fuzzy matches "pat". +/// +/// If "test_only" is true and "fuzzy" is false and if "str" matches the regular +/// expression "regmatch", then returns true. Otherwise returns false. +/// +/// If "test_only" is false and "fuzzy" is false and if "str" matches the +/// regular expression "regmatch", then stores the match in matches[idx] and +/// returns true. +/// +/// If "test_only" is true and "fuzzy" is true and if "str" fuzzy matches +/// "fuzzystr", then returns true. Otherwise returns false. +/// +/// If "test_only" is false and "fuzzy" is true and if "str" fuzzy matches +/// "fuzzystr", then stores the match details in fuzmatch[idx] and returns true. +static bool match_str(char *const str, regmatch_T *const regmatch, char **const matches, + const int idx, const bool test_only, const bool fuzzy, + const char *const fuzzystr, fuzmatch_str_T *const fuzmatch) +{ + if (!fuzzy) { + if (vim_regexec(regmatch, str, (colnr_T)0)) { + if (!test_only) { + matches[idx] = xstrdup(str); + } + return true; + } + } else { + const int score = fuzzy_match_str(str, fuzzystr); + if (score != 0) { + if (!test_only) { + fuzmatch[idx].idx = idx; + fuzmatch[idx].str = xstrdup(str); + fuzmatch[idx].score = score; + } + return true; + } + } + return false; +} + +int ExpandSettings(expand_T *xp, regmatch_T *regmatch, char *fuzzystr, int *numMatches, + char ***matches, const bool can_fuzzy) { 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 + fuzmatch_str_T *fuzmatch = NULL; + const bool fuzzy = can_fuzzy && cmdline_fuzzy_complete(fuzzystr); + // 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); match++) { - if (vim_regexec(regmatch, names[match], (colnr_T)0)) { + if (match_str(names[match], regmatch, *matches, + count, (loop == 0), fuzzy, fuzzystr, fuzmatch)) { if (loop == 0) { num_normal++; } else { - (*file)[count++] = xstrdup(names[match]); + count++; } } } } - 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; @@ -4912,46 +4786,56 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***fi && !(options[opt_idx].flags & P_BOOL)) { continue; } - match = false; - if (vim_regexec(regmatch, (char *)str, (colnr_T)0) - || (options[opt_idx].shortname != NULL - && vim_regexec(regmatch, - options[opt_idx].shortname, - (colnr_T)0))) { - match = true; - } - if (match) { + if (match_str(str, regmatch, *matches, count, (loop == 0), + fuzzy, fuzzystr, fuzmatch)) { if (loop == 0) { num_normal++; } else { - (*file)[count++] = (char *)vim_strsave(str); + count++; + } + } else if (!fuzzy && options[opt_idx].shortname != NULL + && vim_regexec(regmatch, options[opt_idx].shortname, (colnr_T)0)) { + // Compare against the abbreviated option name (for regular + // expression match). Fuzzy matching (previous if) already + // matches against both the expanded and abbreviated names. + if (loop == 0) { + num_normal++; + } else { + (*matches)[count++] = xstrdup(str); } } } if (loop == 0) { if (num_normal > 0) { - *num_file = num_normal; + *numMatches = num_normal; } else { return OK; } - *file = xmalloc((size_t)(*num_file) * sizeof(char_u *)); + if (!fuzzy) { + *matches = xmalloc((size_t)(*numMatches) * sizeof(char *)); + } else { + fuzmatch = xmalloc((size_t)(*numMatches) * sizeof(fuzmatch_str_T)); + } } } + + if (fuzzy) { + fuzzymatches_to_strmatches(fuzmatch, matches, count, false); + } + return OK; } 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); } @@ -4961,12 +4845,12 @@ void ExpandOldSetting(int *num_file, char ***file) option_value2string(&options[expand_option_idx], expand_option_flags); 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 *buf = vim_strsave_escaped(var, escape_chars); #ifdef BACKSLASH_IN_FILENAME // For MS-Windows et al. we don't double backslashes at the start and @@ -4975,14 +4859,14 @@ 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); } } #endif - *file[0] = (char *)buf; + *file[0] = buf; *num_file = 1; } @@ -4990,36 +4874,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; - - varp = 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, 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_u **)opp->var == &p_pt) { - str2specialbuf((const char *)p_pt, (char *)NameBuff, MAXPATHL); + } else if ((char **)opp->var == &p_pt) { + str2specialbuf((const char *)p_pt, NameBuff, MAXPATHL); } else { - STRLCPY(NameBuff, varp, MAXPATHL); + xstrlcpy(NameBuff, varp, MAXPATHL); } } } @@ -5027,7 +4909,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; @@ -5038,25 +4920,14 @@ static int wc_use_keyname(char_u *varp, long *wcp) return false; } -/// Return true if format option 'x' is in effect. -/// Take care of no formatting when 'paste' is set. -bool has_format_option(int x) - FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT -{ - if (p_paste) { - return false; - } - return vim_strchr((char *)curbuf->b_p_fo, x) != NULL; -} - /// @returns true if "x" is present in 'shortmess' option, or /// 'shortmess' contains 'a' and "x" is present in SHM_ALL_ABBREVIATIONS. bool shortmess(int x) { return (p_shm != NULL - && (vim_strchr((char *)p_shm, x) != NULL - || (vim_strchr((char *)p_shm, 'a') != NULL - && vim_strchr((char *)SHM_ALL_ABBREVIATIONS, x) != NULL))); + && (vim_strchr(p_shm, x) != NULL + || (vim_strchr(p_shm, 'a') != NULL + && vim_strchr(SHM_ALL_ABBREVIATIONS, x) != NULL))); } /// paste_option_changed() - Called after p_paste was set or reset. @@ -5070,10 +4941,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) { @@ -5086,7 +4955,7 @@ static void paste_option_changed(void) xfree(buf->b_p_vsts_nopaste); } buf->b_p_vsts_nopaste = buf->b_p_vsts && buf->b_p_vsts != empty_option - ? vim_strsave(buf->b_p_vsts) + ? xstrdup(buf->b_p_vsts) : NULL; } @@ -5105,9 +4974,7 @@ static void paste_option_changed(void) if (p_vsts_nopaste) { xfree(p_vsts_nopaste); } - p_vsts_nopaste = p_vsts && p_vsts != empty_option - ? vim_strsave(p_vsts) - : NULL; + p_vsts_nopaste = p_vsts && p_vsts != empty_option ? xstrdup(p_vsts) : NULL; } // Always set the option values, also when 'paste' is set when it is @@ -5157,9 +5024,7 @@ static void paste_option_changed(void) if (buf->b_p_vsts) { free_string_option(buf->b_p_vsts); } - buf->b_p_vsts = buf->b_p_vsts_nopaste - ? vim_strsave(buf->b_p_vsts_nopaste) - : empty_option; + buf->b_p_vsts = buf->b_p_vsts_nopaste ? xstrdup(buf->b_p_vsts_nopaste) : empty_option; xfree(buf->b_p_vsts_array); if (buf->b_p_vsts && buf->b_p_vsts != empty_option) { (void)tabstop_set(buf->b_p_vsts, &buf->b_p_vsts_array); @@ -5186,7 +5051,7 @@ static void paste_option_changed(void) if (p_vsts) { free_string_option(p_vsts); } - p_vsts = p_vsts_nopaste ? vim_strsave(p_vsts_nopaste) : empty_option; + p_vsts = p_vsts_nopaste ? xstrdup(p_vsts_nopaste) : empty_option; } old_p_paste = p_paste; @@ -5237,33 +5102,31 @@ bool option_was_set(const char *name) void reset_option_was_set(const char *name) { const int idx = findoption(name); - - if (idx >= 0) { - options[idx].flags &= ~P_WAS_SET; + if (idx < 0) { + return; } + + options[idx].flags &= ~P_WAS_SET; } /// 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 = p_breakat; *p; p++) { + for (char_u *p = (char_u *)p_breakat; *p; p++) { breakat_flags[*p] = true; } } } /// fill_culopt_flags() -- called when 'culopt' changes value -int fill_culopt_flags(char_u *val, win_T *wp) +int fill_culopt_flags(char *val, win_T *wp) { - char_u *p; + char *p; char_u culopt_flags_new = 0; if (val == NULL) { @@ -5272,16 +5135,16 @@ int fill_culopt_flags(char_u *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; } @@ -5303,10 +5166,24 @@ int fill_culopt_flags(char_u *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); @@ -5315,10 +5192,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; } @@ -5326,11 +5203,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; } @@ -5341,59 +5218,6 @@ int option_set_callback_func(char_u *optval, Callback *optcb) return OK; } -/// Read the 'wildmode' option, fill wim_flags[]. -int check_opt_wim(void) -{ - char_u new_wim_flags[4]; - char_u *p; - int i; - int idx = 0; - - for (i = 0; i < 4; i++) { - new_wim_flags[i] = 0; - } - - for (p = p_wim; *p; p++) { - for (i = 0; ASCII_ISALPHA(p[i]); i++) {} - if (p[i] != NUL && p[i] != ',' && p[i] != ':') { - return FAIL; - } - if (i == 7 && STRNCMP(p, "longest", 7) == 0) { - new_wim_flags[idx] |= WIM_LONGEST; - } else if (i == 4 && STRNCMP(p, "full", 4) == 0) { - new_wim_flags[idx] |= WIM_FULL; - } else if (i == 4 && STRNCMP(p, "list", 4) == 0) { - new_wim_flags[idx] |= WIM_LIST; - } else if (i == 8 && STRNCMP(p, "lastused", 8) == 0) { - new_wim_flags[idx] |= WIM_BUFLASTUSED; - } else { - return FAIL; - } - p += i; - if (*p == NUL) { - break; - } - if (*p == ',') { - if (idx == 3) { - return FAIL; - } - idx++; - } - } - - // fill remaining entries with last flag - while (idx < 3) { - new_wim_flags[idx + 1] = new_wim_flags[idx]; - idx++; - } - - // only when there are no errors, wim_flags[] is changed - for (i = 0; i < 4; i++) { - wim_flags[i] = new_wim_flags[i]; - } - return OK; -} - /// Check if backspacing over something is allowed. /// @param what BS_INDENT, BS_EOL, BS_START, or BS_NOSTOP bool can_bs(int what) @@ -5411,99 +5235,7 @@ bool can_bs(int what) case '0': return false; } - return vim_strchr((char *)p_bs, what) != NULL; -} - -/// Save the current values of 'fileformat' and 'fileencoding', so that we know -/// the file must be considered changed when the value is different. -void save_file_ff(buf_T *buf) -{ - buf->b_start_ffc = *buf->b_p_ff; - buf->b_start_eol = buf->b_p_eol; - buf->b_start_bomb = buf->b_p_bomb; - - // Only use free/alloc when necessary, they take time. - if (buf->b_start_fenc == NULL - || STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0) { - xfree(buf->b_start_fenc); - buf->b_start_fenc = (char *)vim_strsave(buf->b_p_fenc); - } -} - -/// Return true if 'fileformat' and/or 'fileencoding' has a different value -/// from when editing started (save_file_ff() called). -/// Also when 'endofline' was changed and 'binary' is set, or when 'bomb' was -/// changed and 'binary' is not set. -/// Also when 'endofline' was changed and 'fixeol' is not set. -/// When "ignore_empty" is true don't consider a new, empty buffer to be -/// changed. -bool file_ff_differs(buf_T *buf, bool ignore_empty) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - // In a buffer that was never loaded the options are not valid. - if (buf->b_flags & BF_NEVERLOADED) { - return false; - } - if (ignore_empty - && (buf->b_flags & BF_NEW) - && buf->b_ml.ml_line_count == 1 - && *ml_get_buf(buf, (linenr_T)1, false) == NUL) { - return false; - } - if (buf->b_start_ffc != *buf->b_p_ff) { - return true; - } - if ((buf->b_p_bin || !buf->b_p_fixeol) && buf->b_start_eol != buf->b_p_eol) { - return true; - } - if (!buf->b_p_bin && buf->b_start_bomb != buf->b_p_bomb) { - return true; - } - if (buf->b_start_fenc == NULL) { - return *buf->b_p_fenc != NUL; - } - return STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0; -} - -/// This is called when 'breakindentopt' is changed and when a window is -/// initialized -bool briopt_check(win_T *wp) -{ - int bri_shift = 0; - int bri_min = 20; - bool bri_sbr = false; - int bri_list = 0; - - char *p = (char *)wp->w_p_briopt; - while (*p != NUL) { - if (STRNCMP(p, "shift:", 6) == 0 - && ((p[6] == '-' && ascii_isdigit(p[7])) || ascii_isdigit(p[6]))) { - p += 6; - bri_shift = getdigits_int(&p, true, 0); - } else if (STRNCMP(p, "min:", 4) == 0 && ascii_isdigit(p[4])) { - p += 4; - bri_min = getdigits_int(&p, true, 0); - } else if (STRNCMP(p, "sbr", 3) == 0) { - p += 3; - bri_sbr = true; - } else if (STRNCMP(p, "list:", 5) == 0) { - p += 5; - bri_list = (int)getdigits(&p, false, 0); - } - if (*p != ',' && *p != NUL) { - return false; - } - if (*p == ',') { - p++; - } - } - - wp->w_briopt_shift = bri_shift; - wp->w_briopt_min = bri_min; - wp->w_briopt_sbr = bri_sbr; - wp->w_briopt_list = bri_list; - - return true; + return vim_strchr(p_bs, what) != NULL; } /// Get the local or global value of 'backupcopy'. @@ -5514,6 +5246,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) { @@ -5524,13 +5267,13 @@ unsigned int get_ve_flags(void) /// /// @param win If not NULL, the window to get the local option from; global /// otherwise. -char_u *get_showbreak_value(win_T *const win) +char *get_showbreak_value(win_T *const win) FUNC_ATTR_WARN_UNUSED_RESULT { if (win->w_p_sbr == NULL || *win->w_p_sbr == NUL) { return p_sbr; } - if (STRCMP(win->w_p_sbr, "NONE") == 0) { + if (strcmp(win->w_p_sbr, "NONE") == 0) { return empty_option; } return win->w_p_sbr; @@ -5540,7 +5283,7 @@ char_u *get_showbreak_value(win_T *const win) int get_fileformat(const buf_T *buf) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - int c = *buf->b_p_ff; + int c = (unsigned char)(*buf->b_p_ff); if (buf->b_p_bin || c == 'u') { return EOL_UNIX; @@ -5567,7 +5310,7 @@ int get_fileformat_force(const buf_T *buf, const exarg_T *eap) ? (eap->force_bin == FORCE_BIN) : buf->b_p_bin) { return EOL_UNIX; } - c = *buf->b_p_ff; + c = (unsigned char)(*buf->b_p_ff); } if (c == 'u') { return EOL_UNIX; @@ -5624,7 +5367,7 @@ void set_fileformat(int eol_style, int opt_flags) } /// Skip to next part of an option argument: skip space and comma -char_u *skip_to_option_part(const char_u *p) +char *skip_to_option_part(const char *p) { if (*p == ',') { p++; @@ -5632,7 +5375,7 @@ char_u *skip_to_option_part(const char_u *p) while (*p == ' ') { p++; } - return (char_u *)p; + return (char *)p; } /// Isolate one part of a string option separated by `sep_chars`. @@ -5652,9 +5395,9 @@ size_t copy_option_part(char **option, char *buf, size_t maxlen, char *sep_chars if (*p == '.') { buf[len++] = *p++; } - while (*p != NUL && vim_strchr(sep_chars, *p) == NULL) { + while (*p != NUL && vim_strchr(sep_chars, (uint8_t)(*p)) == NULL) { // Skip backslash before a separator character and space. - if (p[0] == '\\' && vim_strchr(sep_chars, p[1]) != NULL) { + if (p[0] == '\\' && vim_strchr(sep_chars, (uint8_t)p[1]) != NULL) { p++; } if (len < maxlen - 1) { @@ -5667,7 +5410,7 @@ size_t copy_option_part(char **option, char *buf, size_t maxlen, char *sep_chars if (*p != NUL && *p != ',') { // skip non-standard separator p++; } - p = (char *)skip_to_option_part((char_u *)p); // p points to next file name + p = skip_to_option_part(p); // p points to next file name *option = p; return len; @@ -5676,13 +5419,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 @@ -5840,7 +5583,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 : ""); |