1// This is an open source non-commercial project. Dear PVS-Studio, please check
2// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
3
4// User-settable options. Checklist for adding a new option:
5// - Put it in options.lua
6// - For a global option: Add a variable for it in option_defs.h.
7// - For a buffer or window local option:
8// - Add a BV_XX or WV_XX entry to option_defs.h
9// - Add a variable to the window or buffer struct in buffer_defs.h.
10// - For a window option, add some code to copy_winopt().
11// - For a window string option, add code to check_winopt()
12// and clear_winopt(). If setting the option needs parsing,
13// add some code to didset_window_options().
14// - For a buffer option, add some code to buf_copy_options().
15// - For a buffer string option, add code to check_buf_options().
16// - If it's a numeric option, add any necessary bounds checks to
17// set_num_option().
18// - If it's a list of flags, add some code in do_set(), search for WW_ALL.
19// - When adding an option with expansion (P_EXPAND), but with a different
20// default for Vi and Vim (no P_VI_DEF), add some code at VIMEXP.
21// - Add documentation! doc/options.txt, and any other related places.
22// - Add an entry in runtime/optwin.vim.
23
24#define IN_OPTION_C
25#include <assert.h>
26#include <inttypes.h>
27#include <stdbool.h>
28#include <string.h>
29#include <stdlib.h>
30#include <limits.h>
31
32#include "nvim/vim.h"
33#include "nvim/macros.h"
34#include "nvim/ascii.h"
35#include "nvim/edit.h"
36#include "nvim/option.h"
37#include "nvim/buffer.h"
38#include "nvim/charset.h"
39#include "nvim/cursor.h"
40#include "nvim/diff.h"
41#include "nvim/digraph.h"
42#include "nvim/eval.h"
43#include "nvim/eval/typval.h"
44#include "nvim/ex_cmds2.h"
45#include "nvim/ex_docmd.h"
46#include "nvim/ex_getln.h"
47#include "nvim/fileio.h"
48#include "nvim/fold.h"
49#include "nvim/getchar.h"
50#include "nvim/hardcopy.h"
51#include "nvim/highlight.h"
52#include "nvim/indent_c.h"
53#include "nvim/mbyte.h"
54#include "nvim/memfile.h"
55#include "nvim/memline.h"
56#include "nvim/memory.h"
57#include "nvim/message.h"
58#include "nvim/misc1.h"
59#include "nvim/keymap.h"
60#include "nvim/garray.h"
61#include "nvim/cursor_shape.h"
62#include "nvim/move.h"
63#include "nvim/mouse.h"
64#include "nvim/normal.h"
65#include "nvim/os_unix.h"
66#include "nvim/path.h"
67#include "nvim/popupmnu.h"
68#include "nvim/regexp.h"
69#include "nvim/screen.h"
70#include "nvim/spell.h"
71#include "nvim/spellfile.h"
72#include "nvim/strings.h"
73#include "nvim/syntax.h"
74#include "nvim/ui.h"
75#include "nvim/ui_compositor.h"
76#include "nvim/undo.h"
77#include "nvim/window.h"
78#include "nvim/os/os.h"
79#include "nvim/api/private/helpers.h"
80#include "nvim/os/input.h"
81#include "nvim/os/lang.h"
82
83/*
84 * The options that are local to a window or buffer have "indir" set to one of
85 * these values. Special values:
86 * PV_NONE: global option.
87 * PV_WIN is added: window-local option
88 * PV_BUF is added: buffer-local option
89 * PV_BOTH is added: global option which also has a local value.
90 */
91#define PV_BOTH 0x1000
92#define PV_WIN 0x2000
93#define PV_BUF 0x4000
94#define PV_MASK 0x0fff
95#define OPT_WIN(x) (idopt_T)(PV_WIN + (int)(x))
96#define OPT_BUF(x) (idopt_T)(PV_BUF + (int)(x))
97#define OPT_BOTH(x) (idopt_T)(PV_BOTH + (int)(x))
98
99
100// WV_ and BV_ values get typecasted to this for the "indir" field
101typedef enum {
102 PV_NONE = 0,
103 PV_MAXVAL = 0xffff // to avoid warnings for value out of range
104} idopt_T;
105
106/*
107 * Options local to a window have a value local to a buffer and global to all
108 * buffers. Indicate this by setting "var" to VAR_WIN.
109 */
110#define VAR_WIN ((char_u *)-1)
111
112static char *p_term = NULL;
113static char *p_ttytype = NULL;
114
115/*
116 * These are the global values for options which are also local to a buffer.
117 * Only to be used in option.c!
118 */
119static int p_ai;
120static int p_bin;
121static int p_bomb;
122static char_u *p_bh;
123static char_u *p_bt;
124static int p_bl;
125static long p_channel;
126static int p_ci;
127static int p_cin;
128static char_u *p_cink;
129static char_u *p_cino;
130static char_u *p_cinw;
131static char_u *p_com;
132static char_u *p_cms;
133static char_u *p_cpt;
134static char_u *p_cfu;
135static char_u *p_ofu;
136static int p_eol;
137static int p_fixeol;
138static int p_et;
139static char_u *p_fenc;
140static char_u *p_ff;
141static char_u *p_fo;
142static char_u *p_flp;
143static char_u *p_ft;
144static long p_iminsert;
145static long p_imsearch;
146static char_u *p_inex;
147static char_u *p_inde;
148static char_u *p_indk;
149static char_u *p_fex;
150static int p_inf;
151static char_u *p_isk;
152static int p_lisp;
153static int p_ml;
154static int p_ma;
155static int p_mod;
156static char_u *p_mps;
157static char_u *p_nf;
158static int p_pi;
159static char_u *p_qe;
160static int p_ro;
161static int p_si;
162static long p_sts;
163static char_u *p_sua;
164static long p_sw;
165static int p_swf;
166static long p_smc;
167static char_u *p_syn;
168static char_u *p_spc;
169static char_u *p_spf;
170static char_u *p_spl;
171static long p_ts;
172static long p_tw;
173static int p_udf;
174static long p_wm;
175static char_u *p_keymap;
176
177// Saved values for when 'bin' is set.
178static int p_et_nobin;
179static int p_ml_nobin;
180static long p_tw_nobin;
181static long p_wm_nobin;
182
183// Saved values for when 'paste' is set.
184static int p_ai_nopaste;
185static int p_et_nopaste;
186static long p_sts_nopaste;
187static long p_tw_nopaste;
188static long p_wm_nopaste;
189
190typedef struct vimoption {
191 char *fullname; // full option name
192 char *shortname; // permissible abbreviation
193 uint32_t flags; // see below
194 char_u *var; // global option: pointer to variable;
195 // window-local option: VAR_WIN;
196 // buffer-local option: global value
197 idopt_T indir; // global option: PV_NONE;
198 // local option: indirect option index
199 char_u *def_val[2]; // default values for variable (vi and vim)
200 LastSet last_set; // script in which the option was last set
201# define SCTX_INIT , { 0, 0, 0 }
202} vimoption_T;
203
204#define VI_DEFAULT 0 // def_val[VI_DEFAULT] is Vi default value
205#define VIM_DEFAULT 1 // def_val[VIM_DEFAULT] is Vim default value
206
207/*
208 * Flags
209 */
210#define P_BOOL 0x01U // the option is boolean
211#define P_NUM 0x02U // the option is numeric
212#define P_STRING 0x04U // the option is a string
213#define P_ALLOCED 0x08U // the string option is in allocated memory,
214 // must use free_string_option() when
215 // assigning new value. Not set if default is
216 // the same.
217#define P_EXPAND 0x10U // environment expansion. NOTE: P_EXPAND can
218 // never be used for local or hidden options
219#define P_NODEFAULT 0x40U // don't set to default value
220#define P_DEF_ALLOCED 0x80U // default value is in allocated memory, must
221 // use free() when assigning new value
222#define P_WAS_SET 0x100U // option has been set/reset
223#define P_NO_MKRC 0x200U // don't include in :mkvimrc output
224#define P_VI_DEF 0x400U // Use Vi default for Vim
225#define P_VIM 0x800U // Vim option
226
227// when option changed, what to display:
228#define P_RSTAT 0x1000U ///< redraw status lines
229#define P_RWIN 0x2000U ///< redraw current window and recompute text
230#define P_RBUF 0x4000U ///< redraw current buffer and recompute text
231#define P_RALL 0x6000U ///< redraw all windows
232#define P_RCLR 0x7000U ///< clear and redraw all
233
234#define P_COMMA 0x8000U ///< comma separated list
235#define P_ONECOMMA 0x18000U ///< P_COMMA and cannot have two consecutive
236 ///< commas
237#define P_NODUP 0x20000U ///< don't allow duplicate strings
238#define P_FLAGLIST 0x40000U ///< list of single-char flags
239
240#define P_SECURE 0x80000U ///< cannot change in modeline or secure mode
241#define P_GETTEXT 0x100000U ///< expand default value with _()
242#define P_NOGLOB 0x200000U ///< do not use local value for global vimrc
243#define P_NFNAME 0x400000U ///< only normal file name chars allowed
244#define P_INSECURE 0x800000U ///< option was set from a modeline
245#define P_PRI_MKRC 0x1000000U ///< priority for :mkvimrc (setting option
246 ///< has side effects)
247#define P_NO_ML 0x2000000U ///< not allowed in modeline
248#define P_CURSWANT 0x4000000U ///< update curswant required; not needed
249 ///< when there is a redraw flag
250#define P_NO_DEF_EXP 0x8000000U ///< Do not expand default value.
251
252#define P_RWINONLY 0x10000000U ///< only redraw current window
253#define P_NDNAME 0x20000000U ///< only normal dir name chars allowed
254#define P_UI_OPTION 0x40000000U ///< send option to remote ui
255#define P_MLE 0x80000000U ///< under control of 'modelineexpr'
256
257#define HIGHLIGHT_INIT \
258 "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \
259 "d:Directory,e:ErrorMsg,i:IncSearch,l:Search,m:MoreMsg,M:ModeMsg,n:LineNr," \
260 "N:CursorLineNr,r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title," \
261 "v:Visual,V:VisualNOS,w:WarningMsg,W:WildMenu,f:Folded,F:FoldColumn," \
262 "A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn,-:Conceal," \
263 "B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel," \
264 "x:PmenuSbar,X:PmenuThumb,*:TabLine,#:TabLineSel,_:TabLineFill," \
265 "!:CursorColumn,.:CursorLine,o:ColorColumn,q:QuickFixLine," \
266 "0:Whitespace,I:NormalNC"
267
268/*
269 * options[] is initialized here.
270 * The order of the options MUST be alphabetic for ":set all" and findoption().
271 * All option names MUST start with a lowercase letter (for findoption()).
272 * Exception: "t_" options are at the end.
273 * The options with a NULL variable are 'hidden': a set command for them is
274 * ignored and they are not printed.
275 */
276
277#ifdef INCLUDE_GENERATED_DECLARATIONS
278# include "options.generated.h"
279#endif
280
281#define PARAM_COUNT ARRAY_SIZE(options)
282
283static char *(p_ambw_values[]) = { "single", "double", NULL };
284static char *(p_bg_values[]) = { "light", "dark", NULL };
285static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha", NULL };
286static char *(p_ff_values[]) = { FF_UNIX, FF_DOS, FF_MAC, NULL };
287static char *(p_wak_values[]) = { "yes", "menu", "no", NULL };
288static char *(p_mousem_values[]) = { "extend", "popup", "popup_setpos",
289 "mac", NULL };
290static char *(p_sel_values[]) = { "inclusive", "exclusive", "old", NULL };
291static char *(p_slm_values[]) = { "mouse", "key", "cmd", NULL };
292static char *(p_km_values[]) = { "startsel", "stopsel", NULL };
293static char *(p_scbopt_values[]) = { "ver", "hor", "jump", NULL };
294static char *(p_debug_values[]) = { "msg", "throw", "beep", NULL };
295static char *(p_ead_values[]) = { "both", "ver", "hor", NULL };
296static char *(p_buftype_values[]) = { "nofile", "nowrite", "quickfix",
297 "help", "acwrite", "terminal", NULL };
298
299static char *(p_bufhidden_values[]) = { "hide", "unload", "delete",
300 "wipe", NULL };
301static char *(p_bs_values[]) = { "indent", "eol", "start", NULL };
302static char *(p_fdm_values[]) = { "manual", "expr", "marker", "indent",
303 "syntax", "diff", NULL };
304static char *(p_fcl_values[]) = { "all", NULL };
305static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview",
306 "noinsert", "noselect", NULL };
307static char *(p_icm_values[]) = { "nosplit", "split", NULL };
308static char *(p_scl_values[]) = { "yes", "no", "auto", "auto:1", "auto:2",
309 "auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8", "auto:9",
310 "yes:1", "yes:2", "yes:3", "yes:4", "yes:5", "yes:6", "yes:7", "yes:8",
311 "yes:9", NULL };
312
313/// All possible flags for 'shm'.
314static char_u SHM_ALL[] = {
315 SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW, SHM_WRI,
316 SHM_ABBREVIATIONS, SHM_WRITE, SHM_TRUNC, SHM_TRUNCALL, SHM_OVER,
317 SHM_OVERALL, SHM_SEARCH, SHM_ATTENTION, SHM_INTRO, SHM_COMPLETIONMENU,
318 SHM_RECORDING, SHM_FILEINFO, SHM_SEARCHCOUNT,
319 0,
320};
321
322#ifdef INCLUDE_GENERATED_DECLARATIONS
323# include "option.c.generated.h"
324#endif
325
326/// Append string with escaped commas
327static char *strcpy_comma_escaped(char *dest, const char *src, const size_t len)
328 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
329{
330 size_t shift = 0;
331 for (size_t i = 0; i < len; i++) {
332 if (src[i] == ',') {
333 dest[i + shift++] = '\\';
334 }
335 dest[i + shift] = src[i];
336 }
337 return &dest[len + shift];
338}
339
340/// Compute length of a colon-separated value, doubled and with some suffixes
341///
342/// @param[in] val Colon-separated array value.
343/// @param[in] common_suf_len Length of the common suffix which is appended to
344/// each item in the array, twice.
345/// @param[in] single_suf_len Length of the suffix which is appended to each
346/// item in the array once.
347///
348/// @return Length of the comma-separated string array that contains each item
349/// in the original array twice with suffixes with given length
350/// (common_suf is present after each new item, single_suf is present
351/// after half of the new items) and with commas after each item, commas
352/// inside the values are escaped.
353static inline size_t compute_double_colon_len(const char *const val,
354 const size_t common_suf_len,
355 const size_t single_suf_len)
356 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
357{
358 if (val == NULL || *val == NUL) {
359 return 0;
360 }
361 size_t ret = 0;
362 const void *iter = NULL;
363 do {
364 size_t dir_len;
365 const char *dir;
366 iter = vim_env_iter(':', val, iter, &dir, &dir_len);
367 if (dir != NULL && dir_len > 0) {
368 ret += ((dir_len + memcnt(dir, ',', dir_len) + common_suf_len
369 + !after_pathsep(dir, dir + dir_len)) * 2
370 + single_suf_len);
371 }
372 } while (iter != NULL);
373 return ret;
374}
375
376#define NVIM_SIZE (sizeof("nvim") - 1)
377
378/// Add directories to a comma-separated array from a colon-separated one
379///
380/// Commas are escaped in process. To each item PATHSEP "nvim" is appended in
381/// addition to suf1 and suf2.
382///
383/// @param[in,out] dest Destination comma-separated array.
384/// @param[in] val Source colon-separated array.
385/// @param[in] suf1 If not NULL, suffix appended to destination. Prior to it
386/// directory separator is appended. Suffix must not contain
387/// commas.
388/// @param[in] len1 Length of the suf1.
389/// @param[in] suf2 If not NULL, another suffix appended to destination. Again
390/// with directory separator behind. Suffix must not contain
391/// commas.
392/// @param[in] len2 Length of the suf2.
393/// @param[in] forward If true, iterate over val in forward direction.
394/// Otherwise in reverse.
395///
396/// @return (dest + appended_characters_length)
397static inline char *add_colon_dirs(char *dest, const char *const val,
398 const char *const suf1, const size_t len1,
399 const char *const suf2, const size_t len2,
400 const bool forward)
401 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1)
402{
403 if (val == NULL || *val == NUL) {
404 return dest;
405 }
406 const void *iter = NULL;
407 do {
408 size_t dir_len;
409 const char *dir;
410 iter = (forward ? vim_env_iter : vim_env_iter_rev)(':', val, iter, &dir,
411 &dir_len);
412 if (dir != NULL && dir_len > 0) {
413 dest = strcpy_comma_escaped(dest, dir, dir_len);
414 if (!after_pathsep(dest - 1, dest)) {
415 *dest++ = PATHSEP;
416 }
417 memmove(dest, "nvim", NVIM_SIZE);
418 dest += NVIM_SIZE;
419 if (suf1 != NULL) {
420 *dest++ = PATHSEP;
421 memmove(dest, suf1, len1);
422 dest += len1;
423 if (suf2 != NULL) {
424 *dest++ = PATHSEP;
425 memmove(dest, suf2, len2);
426 dest += len2;
427 }
428 }
429 *dest++ = ',';
430 }
431 } while (iter != NULL);
432 return dest;
433}
434
435/// Adds directory `dest` to a comma-separated list of directories.
436///
437/// Commas in the added directory are escaped.
438///
439/// Windows: Appends "nvim-data" instead of "nvim" if `type` is kXDGDataHome.
440///
441/// @see get_xdg_home
442///
443/// @param[in,out] dest Destination comma-separated array.
444/// @param[in] dir Directory to append.
445/// @param[in] type Decides whether to append "nvim" (Win: or "nvim-data").
446/// @param[in] suf1 If not NULL, suffix appended to destination. Prior to it
447/// directory separator is appended. Suffix must not contain
448/// commas.
449/// @param[in] len1 Length of the suf1.
450/// @param[in] suf2 If not NULL, another suffix appended to destination. Again
451/// with directory separator behind. Suffix must not contain
452/// commas.
453/// @param[in] len2 Length of the suf2.
454/// @param[in] forward If true, iterate over val in forward direction.
455/// Otherwise in reverse.
456///
457/// @return (dest + appended_characters_length)
458static inline char *add_dir(char *dest, const char *const dir,
459 const size_t dir_len, const XDGVarType type,
460 const char *const suf1, const size_t len1,
461 const char *const suf2, const size_t len2)
462 FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT
463{
464 if (dir == NULL || dir_len == 0) {
465 return dest;
466 }
467 dest = strcpy_comma_escaped(dest, dir, dir_len);
468 bool append_nvim = (type == kXDGDataHome || type == kXDGConfigHome);
469 if (append_nvim) {
470 if (!after_pathsep(dest - 1, dest)) {
471 *dest++ = PATHSEP;
472 }
473#if defined(WIN32)
474 size_t size = (type == kXDGDataHome ? sizeof("nvim-data") - 1 : NVIM_SIZE);
475 memmove(dest, (type == kXDGDataHome ? "nvim-data" : "nvim"), size);
476 dest += size;
477#else
478 memmove(dest, "nvim", NVIM_SIZE);
479 dest += NVIM_SIZE;
480#endif
481 if (suf1 != NULL) {
482 *dest++ = PATHSEP;
483 memmove(dest, suf1, len1);
484 dest += len1;
485 if (suf2 != NULL) {
486 *dest++ = PATHSEP;
487 memmove(dest, suf2, len2);
488 dest += len2;
489 }
490 }
491 }
492 *dest++ = ',';
493 return dest;
494}
495
496/// Sets &runtimepath to default value.
497///
498/// Windows: Uses "…/nvim-data" for kXDGDataHome to avoid storing
499/// configuration and data files in the same path. #4403
500static void set_runtimepath_default(void)
501{
502 size_t rtp_size = 0;
503 char *const data_home = stdpaths_get_xdg_var(kXDGDataHome);
504 char *const config_home = stdpaths_get_xdg_var(kXDGConfigHome);
505 char *const vimruntime = vim_getenv("VIMRUNTIME");
506 char *const data_dirs = stdpaths_get_xdg_var(kXDGDataDirs);
507 char *const config_dirs = stdpaths_get_xdg_var(kXDGConfigDirs);
508#define SITE_SIZE (sizeof("site") - 1)
509#define AFTER_SIZE (sizeof("after") - 1)
510 size_t data_len = 0;
511 size_t config_len = 0;
512 size_t vimruntime_len = 0;
513 if (data_home != NULL) {
514 data_len = strlen(data_home);
515 if (data_len != 0) {
516#if defined(WIN32)
517 size_t nvim_size = (sizeof("nvim-data") - 1);
518#else
519 size_t nvim_size = NVIM_SIZE;
520#endif
521 rtp_size += ((data_len + memcnt(data_home, ',', data_len)
522 + nvim_size + 1 + SITE_SIZE + 1
523 + !after_pathsep(data_home, data_home + data_len)) * 2
524 + AFTER_SIZE + 1);
525 }
526 }
527 if (config_home != NULL) {
528 config_len = strlen(config_home);
529 if (config_len != 0) {
530 rtp_size += ((config_len + memcnt(config_home, ',', config_len)
531 + NVIM_SIZE + 1
532 + !after_pathsep(config_home, config_home + config_len)) * 2
533 + AFTER_SIZE + 1);
534 }
535 }
536 if (vimruntime != NULL) {
537 vimruntime_len = strlen(vimruntime);
538 if (vimruntime_len != 0) {
539 rtp_size += vimruntime_len + memcnt(vimruntime, ',', vimruntime_len) + 1;
540 }
541 }
542 rtp_size += compute_double_colon_len(data_dirs, NVIM_SIZE + 1 + SITE_SIZE + 1,
543 AFTER_SIZE + 1);
544 rtp_size += compute_double_colon_len(config_dirs, NVIM_SIZE + 1,
545 AFTER_SIZE + 1);
546 if (rtp_size == 0) {
547 return;
548 }
549 char *const rtp = xmalloc(rtp_size);
550 char *rtp_cur = rtp;
551 rtp_cur = add_dir(rtp_cur, config_home, config_len, kXDGConfigHome,
552 NULL, 0, NULL, 0);
553 rtp_cur = add_colon_dirs(rtp_cur, config_dirs, NULL, 0, NULL, 0, true);
554 rtp_cur = add_dir(rtp_cur, data_home, data_len, kXDGDataHome,
555 "site", SITE_SIZE, NULL, 0);
556 rtp_cur = add_colon_dirs(rtp_cur, data_dirs, "site", SITE_SIZE, NULL, 0,
557 true);
558 rtp_cur = add_dir(rtp_cur, vimruntime, vimruntime_len, kXDGNone,
559 NULL, 0, NULL, 0);
560 rtp_cur = add_colon_dirs(rtp_cur, data_dirs, "site", SITE_SIZE,
561 "after", AFTER_SIZE, false);
562 rtp_cur = add_dir(rtp_cur, data_home, data_len, kXDGDataHome,
563 "site", SITE_SIZE, "after", AFTER_SIZE);
564 rtp_cur = add_colon_dirs(rtp_cur, config_dirs, "after", AFTER_SIZE, NULL, 0,
565 false);
566 rtp_cur = add_dir(rtp_cur, config_home, config_len, kXDGConfigHome,
567 "after", AFTER_SIZE, NULL, 0);
568 // Strip trailing comma.
569 rtp_cur[-1] = NUL;
570 assert((size_t) (rtp_cur - rtp) == rtp_size);
571#undef SITE_SIZE
572#undef AFTER_SIZE
573 set_string_default("runtimepath", rtp, true);
574 // Make a copy of 'rtp' for 'packpath'
575 set_string_default("packpath", rtp, false);
576 xfree(data_dirs);
577 xfree(config_dirs);
578 xfree(data_home);
579 xfree(config_home);
580 xfree(vimruntime);
581}
582
583#undef NVIM_SIZE
584
585/*
586 * Initialize the options, first part.
587 *
588 * Called only once from main(), just after creating the first buffer.
589 */
590void set_init_1(void)
591{
592 int opt_idx;
593
594 langmap_init();
595
596 // Be nocompatible
597 p_cp = false;
598
599 /*
600 * Find default value for 'shell' option.
601 * Don't use it if it is empty.
602 */
603 {
604 const char *shell = os_getenv("SHELL");
605 if (shell != NULL) {
606 set_string_default("sh", (char *) shell, false);
607 }
608 }
609
610 /*
611 * Set the default for 'backupskip' to include environment variables for
612 * temp files.
613 */
614 {
615# ifdef UNIX
616 static char *(names[4]) = {"", "TMPDIR", "TEMP", "TMP"};
617# else
618 static char *(names[3]) = {"TMPDIR", "TEMP", "TMP"};
619# endif
620 int len;
621 garray_T ga;
622
623 ga_init(&ga, 1, 100);
624 for (size_t n = 0; n < ARRAY_SIZE(names); n++) {
625 bool mustfree = true;
626 char *p;
627# ifdef UNIX
628 if (*names[n] == NUL) {
629# ifdef __APPLE__
630 p = "/private/tmp";
631# else
632 p = "/tmp";
633# endif
634 mustfree = false;
635 } else
636# endif
637 {
638 p = vim_getenv(names[n]);
639 }
640 if (p != NULL && *p != NUL) {
641 // First time count the NUL, otherwise count the ','.
642 len = (int)strlen(p) + 3;
643 ga_grow(&ga, len);
644 if (!GA_EMPTY(&ga)) {
645 STRCAT(ga.ga_data, ",");
646 }
647 STRCAT(ga.ga_data, p);
648 add_pathsep(ga.ga_data);
649 STRCAT(ga.ga_data, "*");
650 ga.ga_len += len;
651 }
652 if(mustfree) {
653 xfree(p);
654 }
655 }
656 if (ga.ga_data != NULL) {
657 set_string_default("bsk", ga.ga_data, true);
658 }
659 }
660
661 {
662 char_u *cdpath;
663 char_u *buf;
664 int i;
665 int j;
666
667 // Initialize the 'cdpath' option's default value.
668 cdpath = (char_u *)vim_getenv("CDPATH");
669 if (cdpath != NULL) {
670 buf = xmalloc(2 * STRLEN(cdpath) + 2);
671 {
672 buf[0] = ','; // start with ",", current dir first
673 j = 1;
674 for (i = 0; cdpath[i] != NUL; i++) {
675 if (vim_ispathlistsep(cdpath[i])) {
676 buf[j++] = ',';
677 } else {
678 if (cdpath[i] == ' ' || cdpath[i] == ',') {
679 buf[j++] = '\\';
680 }
681 buf[j++] = cdpath[i];
682 }
683 }
684 buf[j] = NUL;
685 opt_idx = findoption("cdpath");
686 if (opt_idx >= 0) {
687 options[opt_idx].def_val[VI_DEFAULT] = buf;
688 options[opt_idx].flags |= P_DEF_ALLOCED;
689 } else {
690 xfree(buf); // cannot happen
691 }
692 }
693 xfree(cdpath);
694 }
695 }
696
697#if defined(MSWIN) || defined(MAC)
698 // Set print encoding on platforms that don't default to latin1
699 set_string_default("printencoding", "hp-roman8", false);
700#endif
701
702 // 'printexpr' must be allocated to be able to evaluate it.
703 set_string_default("printexpr",
704#ifdef UNIX
705 "system(['lpr'] "
706 "+ (empty(&printdevice)?[]:['-P', &printdevice]) "
707 "+ [v:fname_in])"
708 ". delete(v:fname_in)"
709 "+ v:shell_error",
710#elif defined(MSWIN)
711 "system(['copy', v:fname_in, "
712 "empty(&printdevice)?'LPT1':&printdevice])"
713 ". delete(v:fname_in)",
714#else
715 "",
716#endif
717 false);
718
719 char *backupdir = stdpaths_user_data_subpath("backup", 0, true);
720 const size_t backupdir_len = strlen(backupdir);
721 backupdir = xrealloc(backupdir, backupdir_len + 3);
722 memmove(backupdir + 2, backupdir, backupdir_len + 1);
723 memmove(backupdir, ".,", 2);
724 set_string_default("viewdir", stdpaths_user_data_subpath("view", 0, true),
725 true);
726 set_string_default("backupdir", backupdir, true);
727 set_string_default("directory", stdpaths_user_data_subpath("swap", 2, true),
728 true);
729 set_string_default("undodir", stdpaths_user_data_subpath("undo", 0, true),
730 true);
731 // Set default for &runtimepath. All necessary expansions are performed in
732 // this function.
733 set_runtimepath_default();
734
735 /*
736 * Set all the options (except the terminal options) to their default
737 * value. Also set the global value for local options.
738 */
739 set_options_default(0);
740
741
742 curbuf->b_p_initialized = true;
743 curbuf->b_p_ar = -1; // no local 'autoread' value
744 curbuf->b_p_ul = NO_LOCAL_UNDOLEVEL;
745 check_buf_options(curbuf);
746 check_win_options(curwin);
747 check_options();
748
749 // Set all options to their Vim default
750 set_options_default(OPT_FREE);
751
752 // set 'laststatus'
753 last_status(false);
754
755 // Must be before option_expand(), because that one needs vim_isIDc()
756 didset_options();
757
758 // Use the current chartab for the generic chartab. This is not in
759 // didset_options() because it only depends on 'encoding'.
760 init_spell_chartab();
761
762 /*
763 * Expand environment variables and things like "~" for the defaults.
764 * If option_expand() returns non-NULL the variable is expanded. This can
765 * only happen for non-indirect options.
766 * Also set the default to the expanded value, so ":set" does not list
767 * them.
768 * Don't set the P_ALLOCED flag, because we don't want to free the
769 * default.
770 */
771 for (opt_idx = 0; options[opt_idx].fullname; opt_idx++) {
772 if (options[opt_idx].flags & P_NO_DEF_EXP) {
773 continue;
774 }
775 char *p;
776 if ((options[opt_idx].flags & P_GETTEXT)
777 && options[opt_idx].var != NULL) {
778 p = _(*(char **)options[opt_idx].var);
779 } else {
780 p = (char *) option_expand(opt_idx, NULL);
781 }
782 if (p != NULL) {
783 p = xstrdup(p);
784 *(char **)options[opt_idx].var = p;
785 /* VIMEXP
786 * Defaults for all expanded options are currently the same for Vi
787 * and Vim. When this changes, add some code here! Also need to
788 * split P_DEF_ALLOCED in two.
789 */
790 if (options[opt_idx].flags & P_DEF_ALLOCED) {
791 xfree(options[opt_idx].def_val[VI_DEFAULT]);
792 }
793 options[opt_idx].def_val[VI_DEFAULT] = (char_u *)p;
794 options[opt_idx].flags |= P_DEF_ALLOCED;
795 }
796 }
797
798 save_file_ff(curbuf); // Buffer is unchanged
799
800 /* Detect use of mlterm.
801 * Mlterm is a terminal emulator akin to xterm that has some special
802 * abilities (bidi namely).
803 * NOTE: mlterm's author is being asked to 'set' a variable
804 * instead of an environment variable due to inheritance.
805 */
806 if (os_env_exists("MLTERM")) {
807 set_option_value("tbidi", 1L, NULL, 0);
808 }
809
810 didset_options2();
811
812 lang_init();
813
814 // enc_locale() will try to find the encoding of the current locale.
815 // This will be used when 'default' is used as encoding specifier
816 // in 'fileencodings'
817 char_u *p = enc_locale();
818 if (p == NULL) {
819 // use utf-8 as 'default' if locale encoding can't be detected.
820 p = (char_u *)xmemdupz(S_LEN("utf-8"));
821 }
822 fenc_default = p;
823
824#ifdef HAVE_WORKING_LIBINTL
825 // GNU gettext 0.10.37 supports this feature: set the codeset used for
826 // translated messages independently from the current locale.
827 (void)bind_textdomain_codeset(PROJECT_NAME, (char *)p_enc);
828#endif
829
830 // Set the default for 'helplang'.
831 set_helplang_default(get_mess_lang());
832}
833
834/*
835 * Set an option to its default value.
836 * This does not take care of side effects!
837 */
838static void
839set_option_default(
840 int opt_idx,
841 int opt_flags, // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
842 int compatible // use Vi default value
843)
844{
845 char_u *varp; // pointer to variable for current option
846 int dvi; // index in def_val[]
847 int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
848
849 varp = get_varp_scope(&(options[opt_idx]), both ? OPT_LOCAL : opt_flags);
850 uint32_t flags = options[opt_idx].flags;
851 if (varp != NULL) { // skip hidden option, nothing to do for it
852 dvi = ((flags & P_VI_DEF) || compatible) ? VI_DEFAULT : VIM_DEFAULT;
853 if (flags & P_STRING) {
854 /* Use set_string_option_direct() for local options to handle
855 * freeing and allocating the value. */
856 if (options[opt_idx].indir != PV_NONE) {
857 set_string_option_direct(NULL, opt_idx,
858 options[opt_idx].def_val[dvi], opt_flags, 0);
859 } else {
860 if ((opt_flags & OPT_FREE) && (flags & P_ALLOCED)) {
861 free_string_option(*(char_u **)(varp));
862 }
863 *(char_u **)varp = options[opt_idx].def_val[dvi];
864 options[opt_idx].flags &= ~P_ALLOCED;
865 }
866 } else if (flags & P_NUM) {
867 if (options[opt_idx].indir == PV_SCROLL) {
868 win_comp_scroll(curwin);
869 } else {
870 *(long *)varp = (long)(intptr_t)options[opt_idx].def_val[dvi];
871 // May also set global value for local option.
872 if (both) {
873 *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) =
874 *(long *)varp;
875 }
876 }
877 } else { // P_BOOL
878 *(int *)varp = (int)(intptr_t)options[opt_idx].def_val[dvi];
879#ifdef UNIX
880 // 'modeline' defaults to off for root
881 if (options[opt_idx].indir == PV_ML && getuid() == ROOT_UID) {
882 *(int *)varp = false;
883 }
884#endif
885 // May also set global value for local option.
886 if (both) {
887 *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) =
888 *(int *)varp;
889 }
890 }
891
892 // The default value is not insecure.
893 uint32_t *flagsp = insecure_flag(opt_idx, opt_flags);
894 *flagsp = *flagsp & ~P_INSECURE;
895 }
896
897 set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
898}
899
900/*
901 * Set all options (except terminal options) to their default value.
902 */
903static void
904set_options_default(
905 int opt_flags // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
906)
907{
908 for (int i = 0; options[i].fullname; i++) {
909 if (!(options[i].flags & P_NODEFAULT)) {
910 set_option_default(i, opt_flags, p_cp);
911 }
912 }
913
914 // The 'scroll' option must be computed for all windows.
915 FOR_ALL_TAB_WINDOWS(tp, wp) {
916 win_comp_scroll(wp);
917 }
918
919 parse_cino(curbuf);
920}
921
922/// Set the Vi-default value of a string option.
923/// Used for 'sh', 'backupskip' and 'term'.
924///
925/// @param name The name of the option
926/// @param val The value of the option
927/// @param allocated If true, do not copy default as it was already allocated.
928static void set_string_default(const char *name, char *val, bool allocated)
929 FUNC_ATTR_NONNULL_ALL
930{
931 int opt_idx = findoption(name);
932 if (opt_idx >= 0) {
933 if (options[opt_idx].flags & P_DEF_ALLOCED) {
934 xfree(options[opt_idx].def_val[VI_DEFAULT]);
935 }
936
937 options[opt_idx].def_val[VI_DEFAULT] = (char_u *) (
938 allocated
939 ? (char_u *) val
940 : (char_u *) xstrdup(val));
941 options[opt_idx].flags |= P_DEF_ALLOCED;
942 }
943}
944
945/*
946 * Set the Vi-default value of a number option.
947 * Used for 'lines' and 'columns'.
948 */
949void set_number_default(char *name, long val)
950{
951 int opt_idx;
952
953 opt_idx = findoption(name);
954 if (opt_idx >= 0) {
955 options[opt_idx].def_val[VI_DEFAULT] = (char_u *)(intptr_t)val;
956 }
957}
958
959#if defined(EXITFREE)
960/// Free all options.
961void free_all_options(void)
962{
963 for (int i = 0; options[i].fullname; i++) {
964 if (options[i].indir == PV_NONE) {
965 // global option: free value and default value.
966 if ((options[i].flags & P_ALLOCED) && options[i].var != NULL) {
967 free_string_option(*(char_u **)options[i].var);
968 }
969 if (options[i].flags & P_DEF_ALLOCED) {
970 free_string_option(options[i].def_val[VI_DEFAULT]);
971 }
972 } else if (options[i].var != VAR_WIN && (options[i].flags & P_STRING)) {
973 // buffer-local option: free global value
974 free_string_option(*(char_u **)options[i].var);
975 }
976 }
977}
978#endif
979
980
981/// Initialize the options, part two: After getting Rows and Columns.
982void set_init_2(bool headless)
983{
984 int idx;
985
986 // 'scroll' defaults to half the window height. The stored default is zero,
987 // which results in the actual value computed from the window height.
988 idx = findoption("scroll");
989 if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) {
990 set_option_default(idx, OPT_LOCAL, p_cp);
991 }
992 comp_col();
993
994 /*
995 * 'window' is only for backwards compatibility with Vi.
996 * Default is Rows - 1.
997 */
998 if (!option_was_set("window")) {
999 p_window = Rows - 1;
1000 }
1001 set_number_default("window", Rows - 1);
1002 (void)parse_printoptions(); // parse 'printoptions' default value
1003}
1004
1005/// Initialize the options, part three: After reading the .vimrc
1006void set_init_3(void)
1007{
1008 parse_shape_opt(SHAPE_CURSOR); // set cursor shapes from 'guicursor'
1009
1010 // Set 'shellpipe' and 'shellredir', depending on the 'shell' option.
1011 // This is done after other initializations, where 'shell' might have been
1012 // set, but only if they have not been set before.
1013 int idx_srr = findoption("srr");
1014 int do_srr = (idx_srr < 0)
1015 ? false
1016 : !(options[idx_srr].flags & P_WAS_SET);
1017 int idx_sp = findoption("sp");
1018 int do_sp = (idx_sp < 0)
1019 ? false
1020 : !(options[idx_sp].flags & P_WAS_SET);
1021
1022 size_t len = 0;
1023 char_u *p = (char_u *)invocation_path_tail(p_sh, &len);
1024 p = vim_strnsave(p, len);
1025
1026 {
1027 //
1028 // Default for p_sp is "| tee", for p_srr is ">".
1029 // For known shells it is changed here to include stderr.
1030 //
1031 if ( fnamecmp(p, "csh") == 0
1032 || fnamecmp(p, "tcsh") == 0
1033 ) {
1034 if (do_sp) {
1035 p_sp = (char_u *)"|& tee";
1036 options[idx_sp].def_val[VI_DEFAULT] = p_sp;
1037 }
1038 if (do_srr) {
1039 p_srr = (char_u *)">&";
1040 options[idx_srr].def_val[VI_DEFAULT] = p_srr;
1041 }
1042 } else if ( fnamecmp(p, "sh") == 0
1043 || fnamecmp(p, "ksh") == 0
1044 || fnamecmp(p, "mksh") == 0
1045 || fnamecmp(p, "pdksh") == 0
1046 || fnamecmp(p, "zsh") == 0
1047 || fnamecmp(p, "zsh-beta") == 0
1048 || fnamecmp(p, "bash") == 0
1049 || fnamecmp(p, "fish") == 0
1050 ) {
1051 if (do_sp) {
1052 p_sp = (char_u *)"2>&1| tee";
1053 options[idx_sp].def_val[VI_DEFAULT] = p_sp;
1054 }
1055 if (do_srr) {
1056 p_srr = (char_u *)">%s 2>&1";
1057 options[idx_srr].def_val[VI_DEFAULT] = p_srr;
1058 }
1059 }
1060 xfree(p);
1061 }
1062
1063 if (BUFEMPTY()) {
1064 int idx_ffs = findoption_len(S_LEN("ffs"));
1065
1066 // Apply the first entry of 'fileformats' to the initial buffer.
1067 if (idx_ffs >= 0 && (options[idx_ffs].flags & P_WAS_SET)) {
1068 set_fileformat(default_fileformat(), OPT_LOCAL);
1069 }
1070 }
1071
1072 set_title_defaults(); // 'title', 'icon'
1073}
1074
1075/*
1076 * When 'helplang' is still at its default value, set it to "lang".
1077 * Only the first two characters of "lang" are used.
1078 */
1079void set_helplang_default(const char *lang)
1080{
1081 if (lang == NULL) {
1082 return;
1083 }
1084
1085 const size_t lang_len = strlen(lang);
1086 if (lang_len < 2) { // safety check
1087 return;
1088 }
1089 int idx = findoption("hlg");
1090 if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) {
1091 if (options[idx].flags & P_ALLOCED) {
1092 free_string_option(p_hlg);
1093 }
1094 p_hlg = (char_u *)xmemdupz(lang, lang_len);
1095 // zh_CN becomes "cn", zh_TW becomes "tw".
1096 if (STRNICMP(p_hlg, "zh_", 3) == 0 && STRLEN(p_hlg) >= 5) {
1097 p_hlg[0] = (char_u)TOLOWER_ASC(p_hlg[3]);
1098 p_hlg[1] = (char_u)TOLOWER_ASC(p_hlg[4]);
1099 } else if (STRLEN(p_hlg) >= 1 && *p_hlg == 'C') {
1100 // any C like setting, such as C.UTF-8, becomes "en"
1101 p_hlg[0] = 'e';
1102 p_hlg[1] = 'n';
1103 }
1104 p_hlg[2] = NUL;
1105 options[idx].flags |= P_ALLOCED;
1106 }
1107}
1108
1109
1110/*
1111 * 'title' and 'icon' only default to true if they have not been set or reset
1112 * in .vimrc and we can read the old value.
1113 * When 'title' and 'icon' have been reset in .vimrc, we won't even check if
1114 * they can be reset. This reduces startup time when using X on a remote
1115 * machine.
1116 */
1117void set_title_defaults(void)
1118{
1119 int idx1;
1120
1121 /*
1122 * If GUI is (going to be) used, we can always set the window title and
1123 * icon name. Saves a bit of time, because the X11 display server does
1124 * not need to be contacted.
1125 */
1126 idx1 = findoption("title");
1127 if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) {
1128 options[idx1].def_val[VI_DEFAULT] = (char_u *)(intptr_t)0;
1129 p_title = 0;
1130 }
1131 idx1 = findoption("icon");
1132 if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) {
1133 options[idx1].def_val[VI_DEFAULT] = (char_u *)(intptr_t)0;
1134 p_icon = 0;
1135 }
1136}
1137
1138// Parse 'arg' for option settings.
1139//
1140// 'arg' may be IObuff, but only when no errors can be present and option
1141// does not need to be expanded with option_expand().
1142// "opt_flags":
1143// 0 for ":set"
1144// OPT_GLOBAL for ":setglobal"
1145// OPT_LOCAL for ":setlocal" and a modeline
1146// OPT_MODELINE for a modeline
1147// OPT_WINONLY to only set window-local options
1148// OPT_NOWIN to skip setting window-local options
1149//
1150// returns FAIL if an error is detected, OK otherwise
1151int do_set(
1152 char_u *arg, // option string (may be written to!)
1153 int opt_flags
1154)
1155{
1156 int opt_idx;
1157 char_u *errmsg;
1158 char_u errbuf[80];
1159 char_u *startarg;
1160 int prefix; // 1: nothing, 0: "no", 2: "inv" in front of name
1161 char_u nextchar; // next non-white char after option name
1162 int afterchar; // character just after option name
1163 int len;
1164 int i;
1165 varnumber_T value;
1166 int key;
1167 uint32_t flags; // flags for current option
1168 char_u *varp = NULL; // pointer to variable for current option
1169 int did_show = false; // already showed one value
1170 int adding; // "opt+=arg"
1171 int prepending; // "opt^=arg"
1172 int removing; // "opt-=arg"
1173 int cp_val = 0;
1174
1175 if (*arg == NUL) {
1176 showoptions(0, opt_flags);
1177 did_show = true;
1178 goto theend;
1179 }
1180
1181 while (*arg != NUL) { // loop to process all options
1182 errmsg = NULL;
1183 startarg = arg; // remember for error message
1184
1185 if (STRNCMP(arg, "all", 3) == 0 && !isalpha(arg[3])
1186 && !(opt_flags & OPT_MODELINE)) {
1187 /*
1188 * ":set all" show all options.
1189 * ":set all&" set all options to their default value.
1190 */
1191 arg += 3;
1192 if (*arg == '&') {
1193 arg++;
1194 // Only for :set command set global value of local options.
1195 set_options_default(OPT_FREE | opt_flags);
1196 didset_options();
1197 didset_options2();
1198 ui_refresh_options();
1199 redraw_all_later(CLEAR);
1200 } else {
1201 showoptions(1, opt_flags);
1202 did_show = true;
1203 }
1204 } else {
1205 prefix = 1;
1206 if (STRNCMP(arg, "no", 2) == 0) {
1207 prefix = 0;
1208 arg += 2;
1209 } else if (STRNCMP(arg, "inv", 3) == 0) {
1210 prefix = 2;
1211 arg += 3;
1212 }
1213
1214 // find end of name
1215 key = 0;
1216 if (*arg == '<') {
1217 opt_idx = -1;
1218 // look out for <t_>;>
1219 if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4]) {
1220 len = 5;
1221 } else {
1222 len = 1;
1223 while (arg[len] != NUL && arg[len] != '>') {
1224 len++;
1225 }
1226 }
1227 if (arg[len] != '>') {
1228 errmsg = e_invarg;
1229 goto skip;
1230 }
1231 if (arg[1] == 't' && arg[2] == '_') { // could be term code
1232 opt_idx = findoption_len((const char *)arg + 1, (size_t)(len - 1));
1233 }
1234 len++;
1235 if (opt_idx == -1) {
1236 key = find_key_option(arg + 1, true);
1237 }
1238 } else {
1239 len = 0;
1240 // The two characters after "t_" may not be alphanumeric.
1241 if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) {
1242 len = 4;
1243 } else {
1244 while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') {
1245 len++;
1246 }
1247 }
1248 opt_idx = findoption_len((const char *)arg, (size_t)len);
1249 if (opt_idx == -1) {
1250 key = find_key_option(arg, false);
1251 }
1252 }
1253
1254 // remember character after option name
1255 afterchar = arg[len];
1256
1257 // skip white space, allow ":set ai ?"
1258 while (ascii_iswhite(arg[len])) {
1259 len++;
1260 }
1261
1262 adding = false;
1263 prepending = false;
1264 removing = false;
1265 if (arg[len] != NUL && arg[len + 1] == '=') {
1266 if (arg[len] == '+') {
1267 adding = true; // "+="
1268 len++;
1269 } else if (arg[len] == '^') {
1270 prepending = true; // "^="
1271 len++;
1272 } else if (arg[len] == '-') {
1273 removing = true; // "-="
1274 len++;
1275 }
1276 }
1277 nextchar = arg[len];
1278
1279 if (opt_idx == -1 && key == 0) { // found a mismatch: skip
1280 errmsg = (char_u *)N_("E518: Unknown option");
1281 goto skip;
1282 }
1283
1284 if (opt_idx >= 0) {
1285 if (options[opt_idx].var == NULL) { // hidden option: skip
1286 // Only give an error message when requesting the value of
1287 // a hidden option, ignore setting it.
1288 if (vim_strchr((char_u *)"=:!&<", nextchar) == NULL
1289 && (!(options[opt_idx].flags & P_BOOL)
1290 || nextchar == '?')) {
1291 errmsg = (char_u *)_(e_unsupportedoption);
1292 }
1293 goto skip;
1294 }
1295
1296 flags = options[opt_idx].flags;
1297 varp = get_varp_scope(&(options[opt_idx]), opt_flags);
1298 } else {
1299 flags = P_STRING;
1300 }
1301
1302 /* Skip all options that are not window-local (used when showing
1303 * an already loaded buffer in a window). */
1304 if ((opt_flags & OPT_WINONLY)
1305 && (opt_idx < 0 || options[opt_idx].var != VAR_WIN))
1306 goto skip;
1307
1308 // Skip all options that are window-local (used for :vimgrep).
1309 if ((opt_flags & OPT_NOWIN) && opt_idx >= 0
1310 && options[opt_idx].var == VAR_WIN) {
1311 goto skip;
1312 }
1313
1314 // Disallow changing some options from modelines.
1315 if (opt_flags & OPT_MODELINE) {
1316 if (flags & (P_SECURE | P_NO_ML)) {
1317 errmsg = (char_u *)_("E520: Not allowed in a modeline");
1318 goto skip;
1319 }
1320 if ((flags & P_MLE) && !p_mle) {
1321 errmsg = (char_u *)_(
1322 "E992: Not allowed in a modeline when 'modelineexpr' is off");
1323 goto skip;
1324 }
1325 // In diff mode some options are overruled. This avoids that
1326 // 'foldmethod' becomes "marker" instead of "diff" and that
1327 // "wrap" gets set.
1328 if (curwin->w_p_diff
1329 && opt_idx >= 0 // shut up coverity warning
1330 && (options[opt_idx].indir == PV_FDM
1331 || options[opt_idx].indir == PV_WRAP)) {
1332 goto skip;
1333 }
1334 }
1335
1336 // Disallow changing some options in the sandbox
1337 if (sandbox != 0 && (flags & P_SECURE)) {
1338 errmsg = (char_u *)_(e_sandbox);
1339 goto skip;
1340 }
1341
1342 if (vim_strchr((char_u *)"?=:!&<", nextchar) != NULL) {
1343 arg += len;
1344 cp_val = p_cp;
1345 if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i') {
1346 if (arg[3] == 'm') { // "opt&vim": set to Vim default
1347 cp_val = false;
1348 arg += 3;
1349 } else { // "opt&vi": set to Vi default
1350 cp_val = true;
1351 arg += 2;
1352 }
1353 }
1354 if (vim_strchr((char_u *)"?!&<", nextchar) != NULL
1355 && arg[1] != NUL && !ascii_iswhite(arg[1])) {
1356 errmsg = e_trailing;
1357 goto skip;
1358 }
1359 }
1360
1361 /*
1362 * allow '=' and ':' as MSDOS command.com allows only one
1363 * '=' character per "set" command line. grrr. (jw)
1364 */
1365 if (nextchar == '?'
1366 || (prefix == 1
1367 && vim_strchr((char_u *)"=:&<", nextchar) == NULL
1368 && !(flags & P_BOOL))) {
1369 /*
1370 * print value
1371 */
1372 if (did_show) {
1373 msg_putchar('\n'); // cursor below last one
1374 } else {
1375 gotocmdline(true); // cursor at status line
1376 did_show = true; // remember that we did a line
1377 }
1378 if (opt_idx >= 0) {
1379 showoneopt(&options[opt_idx], opt_flags);
1380 if (p_verbose > 0) {
1381 // Mention where the option was last set.
1382 if (varp == options[opt_idx].var) {
1383 option_last_set_msg(options[opt_idx].last_set);
1384 } else if ((int)options[opt_idx].indir & PV_WIN) {
1385 option_last_set_msg(curwin->w_p_script_ctx[
1386 (int)options[opt_idx].indir & PV_MASK]);
1387 } else if ((int)options[opt_idx].indir & PV_BUF) {
1388 option_last_set_msg(curbuf->b_p_script_ctx[
1389 (int)options[opt_idx].indir & PV_MASK]);
1390 }
1391 }
1392 } else {
1393 errmsg = (char_u *)N_("E846: Key code not set");
1394 goto skip;
1395 }
1396 if (nextchar != '?'
1397 && nextchar != NUL && !ascii_iswhite(afterchar))
1398 errmsg = e_trailing;
1399 } else {
1400 int value_is_replaced = !prepending && !adding && !removing;
1401 int value_checked = false;
1402
1403 if (flags & P_BOOL) { // boolean
1404 if (nextchar == '=' || nextchar == ':') {
1405 errmsg = e_invarg;
1406 goto skip;
1407 }
1408
1409 /*
1410 * ":set opt!": invert
1411 * ":set opt&": reset to default value
1412 * ":set opt<": reset to global value
1413 */
1414 if (nextchar == '!') {
1415 value = *(int *)(varp) ^ 1;
1416 } else if (nextchar == '&') {
1417 value = (int)(intptr_t)options[opt_idx].def_val[
1418 ((flags & P_VI_DEF) || cp_val)
1419 ? VI_DEFAULT : VIM_DEFAULT];
1420 } else if (nextchar == '<') {
1421 // For 'autoread' -1 means to use global value.
1422 if ((int *)varp == &curbuf->b_p_ar
1423 && opt_flags == OPT_LOCAL) {
1424 value = -1;
1425 } else {
1426 value = *(int *)get_varp_scope(&(options[opt_idx]),
1427 OPT_GLOBAL);
1428 }
1429 } else {
1430 /*
1431 * ":set invopt": invert
1432 * ":set opt" or ":set noopt": set or reset
1433 */
1434 if (nextchar != NUL && !ascii_iswhite(afterchar)) {
1435 errmsg = e_trailing;
1436 goto skip;
1437 }
1438 if (prefix == 2) { // inv
1439 value = *(int *)(varp) ^ 1;
1440 } else {
1441 value = prefix;
1442 }
1443 }
1444
1445 errmsg = (char_u *)set_bool_option(opt_idx, varp, (int)value,
1446 opt_flags);
1447 } else { // Numeric or string.
1448 if (vim_strchr((const char_u *)"=:&<", nextchar) == NULL
1449 || prefix != 1) {
1450 errmsg = e_invarg;
1451 goto skip;
1452 }
1453
1454 if (flags & P_NUM) { // numeric
1455 // Different ways to set a number option:
1456 // & set to default value
1457 // < set to global value
1458 // <xx> accept special key codes for 'wildchar'
1459 // c accept any non-digit for 'wildchar'
1460 // [-]0-9 set number
1461 // other error
1462 arg++;
1463 if (nextchar == '&') {
1464 value = (long)(intptr_t)options[opt_idx].def_val[
1465 ((flags & P_VI_DEF) || cp_val) ? VI_DEFAULT : VIM_DEFAULT];
1466 } else if (nextchar == '<') {
1467 // For 'undolevels' NO_LOCAL_UNDOLEVEL means to
1468 // use the global value.
1469 if ((long *)varp == &curbuf->b_p_ul && opt_flags == OPT_LOCAL) {
1470 value = NO_LOCAL_UNDOLEVEL;
1471 } else {
1472 value = *(long *)get_varp_scope(
1473 &(options[opt_idx]), OPT_GLOBAL);
1474 }
1475 } else if (((long *)varp == &p_wc
1476 || (long *)varp == &p_wcm)
1477 && (*arg == '<'
1478 || *arg == '^'
1479 || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1]))
1480 && !ascii_isdigit(*arg)))) {
1481 value = string_to_key(arg);
1482 if (value == 0 && (long *)varp != &p_wcm) {
1483 errmsg = e_invarg;
1484 goto skip;
1485 }
1486 } else if (*arg == '-' || ascii_isdigit(*arg)) {
1487 // Allow negative, octal and hex numbers.
1488 vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0);
1489 if (arg[i] != NUL && !ascii_iswhite(arg[i])) {
1490 errmsg = e_invarg;
1491 goto skip;
1492 }
1493 } else {
1494 errmsg = (char_u *)N_("E521: Number required after =");
1495 goto skip;
1496 }
1497
1498 if (adding) {
1499 value = *(long *)varp + value;
1500 }
1501 if (prepending) {
1502 value = *(long *)varp * value;
1503 }
1504 if (removing) {
1505 value = *(long *)varp - value;
1506 }
1507 errmsg = (char_u *)set_num_option(opt_idx, varp, (long)value,
1508 errbuf, sizeof(errbuf),
1509 opt_flags);
1510 } else if (opt_idx >= 0) { // String.
1511 char_u *save_arg = NULL;
1512 char_u *s = NULL;
1513 char_u *oldval = NULL; // previous value if *varp
1514 char_u *newval;
1515 char_u *origval = NULL;
1516 char *saved_origval = NULL;
1517 char *saved_newval = NULL;
1518 unsigned newlen;
1519 int comma;
1520 int bs;
1521 int new_value_alloced; /* new string option
1522 was allocated */
1523
1524 /* When using ":set opt=val" for a global option
1525 * with a local value the local value will be
1526 * reset, use the global value here. */
1527 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
1528 && ((int)options[opt_idx].indir & PV_BOTH))
1529 varp = options[opt_idx].var;
1530
1531 /* The old value is kept until we are sure that the
1532 * new value is valid. */
1533 oldval = *(char_u **)varp;
1534
1535 // When setting the local value of a global
1536 // option, the old value may be the global value.
1537 if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags
1538 & OPT_LOCAL)) {
1539 origval = *(char_u **)get_varp(&options[opt_idx]);
1540 } else {
1541 origval = oldval;
1542 }
1543
1544 if (nextchar == '&') { // set to default val
1545 newval = options[opt_idx].def_val[
1546 ((flags & P_VI_DEF) || cp_val)
1547 ? VI_DEFAULT : VIM_DEFAULT];
1548 /* expand environment variables and ~ (since the
1549 * default value was already expanded, only
1550 * required when an environment variable was set
1551 * later */
1552 new_value_alloced = true;
1553 if (newval == NULL) {
1554 newval = empty_option;
1555 } else if (!(options[opt_idx].flags & P_NO_DEF_EXP)) {
1556 s = option_expand(opt_idx, newval);
1557 if (s == NULL) {
1558 s = newval;
1559 }
1560 newval = vim_strsave(s);
1561 } else {
1562 newval = (char_u *)xstrdup((char *)newval);
1563 }
1564 } else if (nextchar == '<') { // set to global val
1565 newval = vim_strsave(*(char_u **)get_varp_scope(
1566 &(options[opt_idx]), OPT_GLOBAL));
1567 new_value_alloced = true;
1568 } else {
1569 arg++; // jump to after the '=' or ':'
1570
1571 /*
1572 * Set 'keywordprg' to ":help" if an empty
1573 * value was passed to :set by the user.
1574 * Misuse errbuf[] for the resulting string.
1575 */
1576 if (varp == (char_u *)&p_kp
1577 && (*arg == NUL || *arg == ' ')) {
1578 STRCPY(errbuf, ":help");
1579 save_arg = arg;
1580 arg = errbuf;
1581 }
1582 /*
1583 * Convert 'backspace' number to string, for
1584 * adding, prepending and removing string.
1585 */
1586 else if (varp == (char_u *)&p_bs
1587 && ascii_isdigit(**(char_u **)varp)) {
1588 i = getdigits_int((char_u **)varp, true, 0);
1589 switch (i) {
1590 case 0:
1591 *(char_u **)varp = empty_option;
1592 break;
1593 case 1:
1594 *(char_u **)varp = vim_strsave(
1595 (char_u *)"indent,eol");
1596 break;
1597 case 2:
1598 *(char_u **)varp = vim_strsave(
1599 (char_u *)"indent,eol,start");
1600 break;
1601 }
1602 xfree(oldval);
1603 if (origval == oldval) {
1604 origval = *(char_u **)varp;
1605 }
1606 oldval = *(char_u **)varp;
1607 }
1608 /*
1609 * Convert 'whichwrap' number to string, for
1610 * backwards compatibility with Vim 3.0.
1611 * Misuse errbuf[] for the resulting string.
1612 */
1613 else if (varp == (char_u *)&p_ww
1614 && ascii_isdigit(*arg)) {
1615 *errbuf = NUL;
1616 i = getdigits_int(&arg, true, 0);
1617 if (i & 1) {
1618 STRCAT(errbuf, "b,");
1619 }
1620 if (i & 2) {
1621 STRCAT(errbuf, "s,");
1622 }
1623 if (i & 4) {
1624 STRCAT(errbuf, "h,l,");
1625 }
1626 if (i & 8) {
1627 STRCAT(errbuf, "<,>,");
1628 }
1629 if (i & 16) {
1630 STRCAT(errbuf, "[,],");
1631 }
1632 if (*errbuf != NUL) { // remove trailing ,
1633 errbuf[STRLEN(errbuf) - 1] = NUL;
1634 }
1635 save_arg = arg;
1636 arg = errbuf;
1637 }
1638 /*
1639 * Remove '>' before 'dir' and 'bdir', for
1640 * backwards compatibility with version 3.0
1641 */
1642 else if ( *arg == '>'
1643 && (varp == (char_u *)&p_dir
1644 || varp == (char_u *)&p_bdir)) {
1645 arg++;
1646 }
1647
1648 /*
1649 * Copy the new string into allocated memory.
1650 * Can't use set_string_option_direct(), because
1651 * we need to remove the backslashes.
1652 */
1653 // get a bit too much
1654 newlen = (unsigned)STRLEN(arg) + 1;
1655 if (adding || prepending || removing) {
1656 newlen += (unsigned)STRLEN(origval) + 1;
1657 }
1658 newval = xmalloc(newlen);
1659 s = newval;
1660
1661 /*
1662 * Copy the string, skip over escaped chars.
1663 * For WIN32 backslashes before normal
1664 * file name characters are not removed, and keep
1665 * backslash at start, for "\\machine\path", but
1666 * do remove it for "\\\\machine\\path".
1667 * The reverse is found in ExpandOldSetting().
1668 */
1669 while (*arg && !ascii_iswhite(*arg)) {
1670 if (*arg == '\\' && arg[1] != NUL
1671#ifdef BACKSLASH_IN_FILENAME
1672 && !((flags & P_EXPAND)
1673 && vim_isfilec(arg[1])
1674 && (arg[1] != '\\'
1675 || (s == newval
1676 && arg[2] != '\\')))
1677#endif
1678 )
1679 arg++; // remove backslash
1680 if (has_mbyte
1681 && (i = (*mb_ptr2len)(arg)) > 1) {
1682 // copy multibyte char
1683 memmove(s, arg, (size_t)i);
1684 arg += i;
1685 s += i;
1686 } else
1687 *s++ = *arg++;
1688 }
1689 *s = NUL;
1690
1691 /*
1692 * Expand environment variables and ~.
1693 * Don't do it when adding without inserting a
1694 * comma.
1695 */
1696 if (!(adding || prepending || removing)
1697 || (flags & P_COMMA)) {
1698 s = option_expand(opt_idx, newval);
1699 if (s != NULL) {
1700 xfree(newval);
1701 newlen = (unsigned)STRLEN(s) + 1;
1702 if (adding || prepending || removing) {
1703 newlen += (unsigned)STRLEN(origval) + 1;
1704 }
1705 newval = xmalloc(newlen);
1706 STRCPY(newval, s);
1707 }
1708 }
1709
1710 /* locate newval[] in origval[] when removing it
1711 * and when adding to avoid duplicates */
1712 i = 0; // init for GCC
1713 if (removing || (flags & P_NODUP)) {
1714 i = (int)STRLEN(newval);
1715 bs = 0;
1716 for (s = origval; *s; s++) {
1717 if ((!(flags & P_COMMA)
1718 || s == origval
1719 || (s[-1] == ',' && !(bs & 1)))
1720 && STRNCMP(s, newval, i) == 0
1721 && (!(flags & P_COMMA)
1722 || s[i] == ','
1723 || s[i] == NUL)) {
1724 break;
1725 }
1726 // Count backslashes. Only a comma with an even number of
1727 // backslashes or a single backslash preceded by a comma
1728 // before it is recognized as a separator
1729 if ((s > origval + 1 && s[-1] == '\\' && s[-2] != ',')
1730 || (s == origval + 1 && s[-1] == '\\')) {
1731 bs++;
1732 } else {
1733 bs = 0;
1734 }
1735 }
1736
1737 // do not add if already there
1738 if ((adding || prepending) && *s) {
1739 prepending = false;
1740 adding = false;
1741 STRCPY(newval, origval);
1742 }
1743 }
1744
1745 /* concatenate the two strings; add a ',' if
1746 * needed */
1747 if (adding || prepending) {
1748 comma = ((flags & P_COMMA) && *origval != NUL
1749 && *newval != NUL);
1750 if (adding) {
1751 i = (int)STRLEN(origval);
1752 // Strip a trailing comma, would get 2.
1753 if (comma && i > 1
1754 && (flags & P_ONECOMMA) == P_ONECOMMA
1755 && origval[i - 1] == ','
1756 && origval[i - 2] != '\\') {
1757 i--;
1758 }
1759 memmove(newval + i + comma, newval,
1760 STRLEN(newval) + 1);
1761 memmove(newval, origval, (size_t)i);
1762 } else {
1763 i = (int)STRLEN(newval);
1764 STRMOVE(newval + i + comma, origval);
1765 }
1766 if (comma) {
1767 newval[i] = ',';
1768 }
1769 }
1770
1771 /* Remove newval[] from origval[]. (Note: "i" has
1772 * been set above and is used here). */
1773 if (removing) {
1774 STRCPY(newval, origval);
1775 if (*s) {
1776 // may need to remove a comma
1777 if (flags & P_COMMA) {
1778 if (s == origval) {
1779 // include comma after string
1780 if (s[i] == ',') {
1781 i++;
1782 }
1783 } else {
1784 // include comma before string
1785 s--;
1786 i++;
1787 }
1788 }
1789 STRMOVE(newval + (s - origval), s + i);
1790 }
1791 }
1792
1793 if (flags & P_FLAGLIST) {
1794 // Remove flags that appear twice.
1795 for (s = newval; *s;) {
1796 // if options have P_FLAGLIST and P_ONECOMMA such as
1797 // 'whichwrap'
1798 if (flags & P_ONECOMMA) {
1799 if (*s != ',' && *(s + 1) == ','
1800 && vim_strchr(s + 2, *s) != NULL) {
1801 // Remove the duplicated value and the next comma.
1802 STRMOVE(s, s + 2);
1803 continue;
1804 }
1805 } else {
1806 if ((!(flags & P_COMMA) || *s != ',')
1807 && vim_strchr(s + 1, *s) != NULL) {
1808 STRMOVE(s, s + 1);
1809 continue;
1810 }
1811 }
1812 s++;
1813 }
1814 }
1815
1816 if (save_arg != NULL) { // number for 'whichwrap'
1817 arg = save_arg;
1818 }
1819 new_value_alloced = true;
1820 }
1821
1822 // Set the new value.
1823 *(char_u **)(varp) = newval;
1824
1825 // origval may be freed by
1826 // did_set_string_option(), make a copy.
1827 saved_origval = (origval != NULL) ? xstrdup((char *)origval) : 0;
1828
1829 // newval (and varp) may become invalid if the
1830 // buffer is closed by autocommands.
1831 saved_newval = (newval != NULL) ? xstrdup((char *)newval) : 0;
1832
1833 {
1834 uint32_t *p = insecure_flag(opt_idx, opt_flags);
1835 const int secure_saved = secure;
1836
1837 // When an option is set in the sandbox, from a
1838 // modeline or in secure mode, then deal with side
1839 // effects in secure mode. Also when the value was
1840 // set with the P_INSECURE flag and is not
1841 // completely replaced.
1842 if ((opt_flags & OPT_MODELINE)
1843 || sandbox != 0
1844 || (!value_is_replaced && (*p & P_INSECURE))) {
1845 secure = 1;
1846 }
1847
1848 // Handle side effects, and set the global value
1849 // for ":set" on local options. Note: when setting
1850 // 'syntax' or 'filetype' autocommands may be
1851 // triggered that can cause havoc.
1852 errmsg = did_set_string_option(opt_idx, (char_u **)varp,
1853 new_value_alloced, oldval,
1854 errbuf, sizeof(errbuf),
1855 opt_flags, &value_checked);
1856
1857 secure = secure_saved;
1858 }
1859
1860 if (errmsg == NULL) {
1861 if (!starting) {
1862 trigger_optionsset_string(opt_idx, opt_flags, saved_origval,
1863 saved_newval);
1864 }
1865 if (options[opt_idx].flags & P_UI_OPTION) {
1866 ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
1867 STRING_OBJ(cstr_as_string(saved_newval)));
1868 }
1869 }
1870 xfree(saved_origval);
1871 xfree(saved_newval);
1872
1873 // If error detected, print the error message.
1874 if (errmsg != NULL) {
1875 goto skip;
1876 }
1877
1878 } else {
1879 // key code option(FIXME(tarruda): Show a warning or something
1880 // similar)
1881 }
1882 }
1883
1884 if (opt_idx >= 0) {
1885 did_set_option(opt_idx, opt_flags, value_is_replaced, value_checked);
1886 }
1887 }
1888
1889skip:
1890 /*
1891 * Advance to next argument.
1892 * - skip until a blank found, taking care of backslashes
1893 * - skip blanks
1894 * - skip one "=val" argument (for hidden options ":set gfn =xx")
1895 */
1896 for (i = 0; i < 2; i++) {
1897 while (*arg != NUL && !ascii_iswhite(*arg)) {
1898 if (*arg++ == '\\' && *arg != NUL) {
1899 arg++;
1900 }
1901 }
1902 arg = skipwhite(arg);
1903 if (*arg != '=') {
1904 break;
1905 }
1906 }
1907 }
1908
1909 if (errmsg != NULL) {
1910 STRLCPY(IObuff, _(errmsg), IOSIZE);
1911 i = (int)STRLEN(IObuff) + 2;
1912 if (i + (arg - startarg) < IOSIZE) {
1913 // append the argument with the error
1914 STRCAT(IObuff, ": ");
1915 assert(arg >= startarg);
1916 memmove(IObuff + i, startarg, (size_t)(arg - startarg));
1917 IObuff[i + (arg - startarg)] = NUL;
1918 }
1919 // make sure all characters are printable
1920 trans_characters(IObuff, IOSIZE);
1921
1922 no_wait_return++; // wait_return done later
1923 emsg(IObuff); // show error highlighted
1924 no_wait_return--;
1925
1926 return FAIL;
1927 }
1928
1929 arg = skipwhite(arg);
1930 }
1931
1932theend:
1933 if (silent_mode && did_show) {
1934 // After displaying option values in silent mode.
1935 silent_mode = false;
1936 info_message = true; // use mch_msg(), not mch_errmsg()
1937 msg_putchar('\n');
1938 ui_flush();
1939 silent_mode = true;
1940 info_message = false; // use mch_msg(), not mch_errmsg()
1941 }
1942
1943 return OK;
1944}
1945
1946// Call this when an option has been given a new value through a user command.
1947// Sets the P_WAS_SET flag and takes care of the P_INSECURE flag.
1948static void did_set_option(
1949 int opt_idx,
1950 int opt_flags, // possibly with OPT_MODELINE
1951 int new_value, // value was replaced completely
1952 int value_checked // value was checked to be safe, no need to
1953 // set P_INSECURE
1954)
1955{
1956 options[opt_idx].flags |= P_WAS_SET;
1957
1958 /* When an option is set in the sandbox, from a modeline or in secure mode
1959 * set the P_INSECURE flag. Otherwise, if a new value is stored reset the
1960 * flag. */
1961 uint32_t *p = insecure_flag(opt_idx, opt_flags);
1962 if (!value_checked && (secure
1963 || sandbox != 0
1964 || (opt_flags & OPT_MODELINE))) {
1965 *p = *p | P_INSECURE;
1966 } else if (new_value) {
1967 *p = *p & ~P_INSECURE;
1968 }
1969}
1970
1971static char_u *illegal_char(char_u *errbuf, size_t errbuflen, int c)
1972{
1973 if (errbuf == NULL) {
1974 return (char_u *)"";
1975 }
1976 vim_snprintf((char *)errbuf, errbuflen, _("E539: Illegal character <%s>"),
1977 (char *)transchar(c));
1978 return errbuf;
1979}
1980
1981/*
1982 * Convert a key name or string into a key value.
1983 * Used for 'wildchar' and 'cedit' options.
1984 */
1985static int string_to_key(char_u *arg)
1986{
1987 if (*arg == '<') {
1988 return find_key_option(arg + 1, true);
1989 }
1990 if (*arg == '^') {
1991 return Ctrl_chr(arg[1]);
1992 }
1993 return *arg;
1994}
1995
1996/*
1997 * Check value of 'cedit' and set cedit_key.
1998 * Returns NULL if value is OK, error message otherwise.
1999 */
2000static char_u *check_cedit(void)
2001{
2002 int n;
2003
2004 if (*p_cedit == NUL) {
2005 cedit_key = -1;
2006 } else {
2007 n = string_to_key(p_cedit);
2008 if (vim_isprintc(n)) {
2009 return e_invarg;
2010 }
2011 cedit_key = n;
2012 }
2013 return NULL;
2014}
2015
2016// When changing 'title', 'titlestring', 'icon' or 'iconstring', call
2017// maketitle() to create and display it.
2018// When switching the title or icon off, call ui_set_{icon,title}(NULL) to get
2019// the old value back.
2020static void did_set_title(
2021 int icon // Did set icon instead of title
2022)
2023{
2024 if (starting != NO_SCREEN) {
2025 maketitle();
2026 resettitle();
2027 }
2028}
2029
2030// set_options_bin - called when 'bin' changes value.
2031void set_options_bin(
2032 int oldval,
2033 int newval,
2034 int opt_flags // OPT_LOCAL and/or OPT_GLOBAL
2035)
2036{
2037 /*
2038 * The option values that are changed when 'bin' changes are
2039 * copied when 'bin is set and restored when 'bin' is reset.
2040 */
2041 if (newval) {
2042 if (!oldval) { // switched on
2043 if (!(opt_flags & OPT_GLOBAL)) {
2044 curbuf->b_p_tw_nobin = curbuf->b_p_tw;
2045 curbuf->b_p_wm_nobin = curbuf->b_p_wm;
2046 curbuf->b_p_ml_nobin = curbuf->b_p_ml;
2047 curbuf->b_p_et_nobin = curbuf->b_p_et;
2048 }
2049 if (!(opt_flags & OPT_LOCAL)) {
2050 p_tw_nobin = p_tw;
2051 p_wm_nobin = p_wm;
2052 p_ml_nobin = p_ml;
2053 p_et_nobin = p_et;
2054 }
2055 }
2056
2057 if (!(opt_flags & OPT_GLOBAL)) {
2058 curbuf->b_p_tw = 0; // no automatic line wrap
2059 curbuf->b_p_wm = 0; // no automatic line wrap
2060 curbuf->b_p_ml = 0; // no modelines
2061 curbuf->b_p_et = 0; // no expandtab
2062 }
2063 if (!(opt_flags & OPT_LOCAL)) {
2064 p_tw = 0;
2065 p_wm = 0;
2066 p_ml = false;
2067 p_et = false;
2068 p_bin = true; // needed when called for the "-b" argument
2069 }
2070 } else if (oldval) { // switched off
2071 if (!(opt_flags & OPT_GLOBAL)) {
2072 curbuf->b_p_tw = curbuf->b_p_tw_nobin;
2073 curbuf->b_p_wm = curbuf->b_p_wm_nobin;
2074 curbuf->b_p_ml = curbuf->b_p_ml_nobin;
2075 curbuf->b_p_et = curbuf->b_p_et_nobin;
2076 }
2077 if (!(opt_flags & OPT_LOCAL)) {
2078 p_tw = p_tw_nobin;
2079 p_wm = p_wm_nobin;
2080 p_ml = p_ml_nobin;
2081 p_et = p_et_nobin;
2082 }
2083 }
2084}
2085
2086/*
2087 * Find the parameter represented by the given character (eg ', :, ", or /),
2088 * and return its associated value in the 'shada' string.
2089 * Only works for number parameters, not for 'r' or 'n'.
2090 * If the parameter is not specified in the string or there is no following
2091 * number, return -1.
2092 */
2093int get_shada_parameter(int type)
2094{
2095 char_u *p;
2096
2097 p = find_shada_parameter(type);
2098 if (p != NULL && ascii_isdigit(*p)) {
2099 return atoi((char *)p);
2100 }
2101 return -1;
2102}
2103
2104/*
2105 * Find the parameter represented by the given character (eg ''', ':', '"', or
2106 * '/') in the 'shada' option and return a pointer to the string after it.
2107 * Return NULL if the parameter is not specified in the string.
2108 */
2109char_u *find_shada_parameter(int type)
2110{
2111 char_u *p;
2112
2113 for (p = p_shada; *p; p++) {
2114 if (*p == type) {
2115 return p + 1;
2116 }
2117 if (*p == 'n') { // 'n' is always the last one
2118 break;
2119 }
2120 p = vim_strchr(p, ','); // skip until next ','
2121 if (p == NULL) { // hit the end without finding parameter
2122 break;
2123 }
2124 }
2125 return NULL;
2126}
2127
2128/*
2129 * Expand environment variables for some string options.
2130 * These string options cannot be indirect!
2131 * If "val" is NULL expand the current value of the option.
2132 * Return pointer to NameBuff, or NULL when not expanded.
2133 */
2134static char_u *option_expand(int opt_idx, char_u *val)
2135{
2136 // if option doesn't need expansion nothing to do
2137 if (!(options[opt_idx].flags & P_EXPAND) || options[opt_idx].var == NULL) {
2138 return NULL;
2139 }
2140
2141 if (val == NULL) {
2142 val = *(char_u **)options[opt_idx].var;
2143 }
2144
2145 // If val is longer than MAXPATHL no meaningful expansion can be done,
2146 // expand_env() would truncate the string.
2147 if (val == NULL || STRLEN(val) > MAXPATHL) {
2148 return NULL;
2149 }
2150
2151 /*
2152 * Expanding this with NameBuff, expand_env() must not be passed IObuff.
2153 * Escape spaces when expanding 'tags', they are used to separate file
2154 * names.
2155 * For 'spellsuggest' expand after "file:".
2156 */
2157 expand_env_esc(val, NameBuff, MAXPATHL,
2158 (char_u **)options[opt_idx].var == &p_tags, false,
2159 (char_u **)options[opt_idx].var == &p_sps ? (char_u *)"file:" :
2160 NULL);
2161 if (STRCMP(NameBuff, val) == 0) { // they are the same
2162 return NULL;
2163 }
2164
2165 return NameBuff;
2166}
2167
2168// After setting various option values: recompute variables that depend on
2169// option values.
2170static void didset_options(void)
2171{
2172 // initialize the table for 'iskeyword' et.al.
2173 (void)init_chartab();
2174
2175 (void)opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true);
2176 (void)opt_strings_flags(p_bkc, p_bkc_values, &bkc_flags, true);
2177 (void)opt_strings_flags(p_bo, p_bo_values, &bo_flags, true);
2178 (void)opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true);
2179 (void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true);
2180 (void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true);
2181 (void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, true);
2182 (void)opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true);
2183 (void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, false);
2184 (void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, true);
2185 (void)opt_strings_flags(p_wop, p_wop_values, &wop_flags, true);
2186 (void)spell_check_msm();
2187 (void)spell_check_sps();
2188 (void)compile_cap_prog(curwin->w_s);
2189 (void)did_set_spell_option(true);
2190 // set cedit_key
2191 (void)check_cedit();
2192 briopt_check(curwin);
2193 // initialize the table for 'breakat'.
2194 fill_breakat_flags();
2195}
2196
2197// More side effects of setting options.
2198static void didset_options2(void)
2199{
2200 // Initialize the highlight_attr[] table.
2201 highlight_changed();
2202
2203 // Parse default for 'clipboard'.
2204 (void)opt_strings_flags(p_cb, p_cb_values, &cb_flags, true);
2205
2206 // Parse default for 'fillchars'.
2207 (void)set_chars_option(curwin, &curwin->w_p_fcs);
2208
2209 // Parse default for 'listchars'.
2210 (void)set_chars_option(curwin, &curwin->w_p_lcs);
2211
2212 // Parse default for 'wildmode'.
2213 check_opt_wim();
2214}
2215
2216/*
2217 * Check for string options that are NULL (normally only termcap options).
2218 */
2219void check_options(void)
2220{
2221 int opt_idx;
2222
2223 for (opt_idx = 0; options[opt_idx].fullname != NULL; opt_idx++) {
2224 if ((options[opt_idx].flags & P_STRING) && options[opt_idx].var != NULL) {
2225 check_string_option((char_u **)get_varp(&(options[opt_idx])));
2226 }
2227 }
2228}
2229
2230/*
2231 * Check string options in a buffer for NULL value.
2232 */
2233void check_buf_options(buf_T *buf)
2234{
2235 check_string_option(&buf->b_p_bh);
2236 check_string_option(&buf->b_p_bt);
2237 check_string_option(&buf->b_p_fenc);
2238 check_string_option(&buf->b_p_ff);
2239 check_string_option(&buf->b_p_def);
2240 check_string_option(&buf->b_p_inc);
2241 check_string_option(&buf->b_p_inex);
2242 check_string_option(&buf->b_p_inde);
2243 check_string_option(&buf->b_p_indk);
2244 check_string_option(&buf->b_p_fp);
2245 check_string_option(&buf->b_p_fex);
2246 check_string_option(&buf->b_p_kp);
2247 check_string_option(&buf->b_p_mps);
2248 check_string_option(&buf->b_p_fo);
2249 check_string_option(&buf->b_p_flp);
2250 check_string_option(&buf->b_p_isk);
2251 check_string_option(&buf->b_p_com);
2252 check_string_option(&buf->b_p_cms);
2253 check_string_option(&buf->b_p_nf);
2254 check_string_option(&buf->b_p_qe);
2255 check_string_option(&buf->b_p_syn);
2256 check_string_option(&buf->b_s.b_syn_isk);
2257 check_string_option(&buf->b_s.b_p_spc);
2258 check_string_option(&buf->b_s.b_p_spf);
2259 check_string_option(&buf->b_s.b_p_spl);
2260 check_string_option(&buf->b_p_sua);
2261 check_string_option(&buf->b_p_cink);
2262 check_string_option(&buf->b_p_cino);
2263 parse_cino(buf);
2264 check_string_option(&buf->b_p_ft);
2265 check_string_option(&buf->b_p_cinw);
2266 check_string_option(&buf->b_p_cpt);
2267 check_string_option(&buf->b_p_cfu);
2268 check_string_option(&buf->b_p_ofu);
2269 check_string_option(&buf->b_p_keymap);
2270 check_string_option(&buf->b_p_gp);
2271 check_string_option(&buf->b_p_mp);
2272 check_string_option(&buf->b_p_efm);
2273 check_string_option(&buf->b_p_ep);
2274 check_string_option(&buf->b_p_path);
2275 check_string_option(&buf->b_p_tags);
2276 check_string_option(&buf->b_p_tc);
2277 check_string_option(&buf->b_p_dict);
2278 check_string_option(&buf->b_p_tsr);
2279 check_string_option(&buf->b_p_lw);
2280 check_string_option(&buf->b_p_bkc);
2281 check_string_option(&buf->b_p_menc);
2282}
2283
2284/*
2285 * Free the string allocated for an option.
2286 * Checks for the string being empty_option. This may happen if we're out of
2287 * memory, vim_strsave() returned NULL, which was replaced by empty_option by
2288 * check_options().
2289 * Does NOT check for P_ALLOCED flag!
2290 */
2291void free_string_option(char_u *p)
2292{
2293 if (p != empty_option) {
2294 xfree(p);
2295 }
2296}
2297
2298void clear_string_option(char_u **pp)
2299{
2300 if (*pp != empty_option) {
2301 xfree(*pp);
2302 }
2303 *pp = empty_option;
2304}
2305
2306static void check_string_option(char_u **pp)
2307{
2308 if (*pp == NULL) {
2309 *pp = empty_option;
2310 }
2311}
2312
2313/// Return true when option "opt" was set from a modeline or in secure mode.
2314/// Return false when it wasn't.
2315/// Return -1 for an unknown option.
2316int was_set_insecurely(char_u *opt, int opt_flags)
2317{
2318 int idx = findoption((const char *)opt);
2319
2320 if (idx >= 0) {
2321 uint32_t *flagp = insecure_flag(idx, opt_flags);
2322 return (*flagp & P_INSECURE) != 0;
2323 }
2324 internal_error("was_set_insecurely()");
2325 return -1;
2326}
2327
2328/*
2329 * Get a pointer to the flags used for the P_INSECURE flag of option
2330 * "opt_idx". For some local options a local flags field is used.
2331 */
2332static uint32_t *insecure_flag(int opt_idx, int opt_flags)
2333{
2334 if (opt_flags & OPT_LOCAL)
2335 switch ((int)options[opt_idx].indir) {
2336 case PV_STL: return &curwin->w_p_stl_flags;
2337 case PV_FDE: return &curwin->w_p_fde_flags;
2338 case PV_FDT: return &curwin->w_p_fdt_flags;
2339 case PV_INDE: return &curbuf->b_p_inde_flags;
2340 case PV_FEX: return &curbuf->b_p_fex_flags;
2341 case PV_INEX: return &curbuf->b_p_inex_flags;
2342 }
2343
2344 // Nothing special, return global flags field.
2345 return &options[opt_idx].flags;
2346}
2347
2348
2349/*
2350 * Redraw the window title and/or tab page text later.
2351 */
2352static void redraw_titles(void)
2353{
2354 need_maketitle = true;
2355 redraw_tabline = true;
2356}
2357
2358static int shada_idx = -1;
2359
2360// Set a string option to a new value (without checking the effect).
2361// The string is copied into allocated memory.
2362// if ("opt_idx" == -1) "name" is used, otherwise "opt_idx" is used.
2363// When "set_sid" is zero set the scriptID to current_sctx.sc_sid. When
2364// "set_sid" is SID_NONE don't set the scriptID. Otherwise set the scriptID to
2365// "set_sid".
2366void
2367set_string_option_direct(
2368 char_u *name,
2369 int opt_idx,
2370 char_u *val,
2371 int opt_flags, // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
2372 int set_sid
2373)
2374{
2375 char_u *s;
2376 char_u **varp;
2377 int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
2378 int idx = opt_idx;
2379
2380 if (idx == -1) { // Use name.
2381 idx = findoption((const char *)name);
2382 if (idx < 0) { // Not found (should not happen).
2383 internal_error("set_string_option_direct()");
2384 IEMSG2(_("For option %s"), name);
2385 return;
2386 }
2387 }
2388
2389 if (options[idx].var == NULL) { // can't set hidden option
2390 return;
2391 }
2392
2393 assert((void *) options[idx].var != (void *) &p_shada);
2394
2395 s = vim_strsave(val);
2396 {
2397 varp = (char_u **)get_varp_scope(&(options[idx]),
2398 both ? OPT_LOCAL : opt_flags);
2399 if ((opt_flags & OPT_FREE) && (options[idx].flags & P_ALLOCED)) {
2400 free_string_option(*varp);
2401 }
2402 *varp = s;
2403
2404 // For buffer/window local option may also set the global value.
2405 if (both) {
2406 set_string_option_global(idx, varp);
2407 }
2408
2409 options[idx].flags |= P_ALLOCED;
2410
2411 /* When setting both values of a global option with a local value,
2412 * make the local value empty, so that the global value is used. */
2413 if (((int)options[idx].indir & PV_BOTH) && both) {
2414 free_string_option(*varp);
2415 *varp = empty_option;
2416 }
2417 if (set_sid != SID_NONE) {
2418 sctx_T script_ctx;
2419
2420 if (set_sid == 0) {
2421 script_ctx = current_sctx;
2422 } else {
2423 script_ctx.sc_sid = set_sid;
2424 script_ctx.sc_seq = 0;
2425 script_ctx.sc_lnum = 0;
2426 }
2427 set_option_sctx_idx(idx, opt_flags, script_ctx);
2428 }
2429 }
2430}
2431
2432/*
2433 * Set global value for string option when it's a local option.
2434 */
2435static void
2436set_string_option_global(
2437 int opt_idx, // option index
2438 char_u **varp // pointer to option variable
2439)
2440{
2441 char_u **p, *s;
2442
2443 // the global value is always allocated
2444 if (options[opt_idx].var == VAR_WIN) {
2445 p = (char_u **)GLOBAL_WO(varp);
2446 } else {
2447 p = (char_u **)options[opt_idx].var;
2448 }
2449 if (options[opt_idx].indir != PV_NONE && p != varp) {
2450 s = vim_strsave(*varp);
2451 free_string_option(*p);
2452 *p = s;
2453 }
2454}
2455
2456/// Set a string option to a new value, handling the effects
2457///
2458/// @param[in] opt_idx Option to set.
2459/// @param[in] value New value.
2460/// @param[in] opt_flags Option flags: expected to contain #OPT_LOCAL and/or
2461/// #OPT_GLOBAL.
2462///
2463/// @return NULL on success, error message on error.
2464static char *set_string_option(const int opt_idx, const char *const value,
2465 const int opt_flags)
2466 FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_WARN_UNUSED_RESULT
2467{
2468 if (options[opt_idx].var == NULL) { // don't set hidden option
2469 return NULL;
2470 }
2471
2472 char *const s = xstrdup(value);
2473 char **const varp = (char **)get_varp_scope(
2474 &(options[opt_idx]),
2475 ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
2476 ? (((int)options[opt_idx].indir & PV_BOTH)
2477 ? OPT_GLOBAL : OPT_LOCAL)
2478 : opt_flags));
2479 char *const oldval = *varp;
2480 *varp = s;
2481
2482 char *const saved_oldval = xstrdup(oldval);
2483 char *const saved_newval = xstrdup(s);
2484
2485 int value_checked = false;
2486 char *const r = (char *)did_set_string_option(
2487 opt_idx, (char_u **)varp, (int)true, (char_u *)oldval,
2488 NULL, 0, opt_flags, &value_checked);
2489 if (r == NULL) {
2490 did_set_option(opt_idx, opt_flags, true, value_checked);
2491 }
2492
2493 // call autocommand after handling side effects
2494 if (r == NULL) {
2495 if (!starting) {
2496 trigger_optionsset_string(opt_idx, opt_flags, saved_oldval, saved_newval);
2497 }
2498 if (options[opt_idx].flags & P_UI_OPTION) {
2499 ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
2500 STRING_OBJ(cstr_as_string(saved_newval)));
2501 }
2502 }
2503 xfree(saved_oldval);
2504 xfree(saved_newval);
2505
2506 return r;
2507}
2508
2509/// Return true if "val" is a valid 'filetype' name.
2510/// Also used for 'syntax' and 'keymap'.
2511static bool valid_filetype(char_u *val)
2512{
2513 for (char_u *s = val; *s != NUL; s++) {
2514 if (!ASCII_ISALNUM(*s) && vim_strchr((char_u *)".-_", *s) == NULL) {
2515 return false;
2516 }
2517 }
2518 return true;
2519}
2520
2521/// Handle string options that need some action to perform when changed.
2522/// Returns NULL for success, or an error message for an error.
2523static char_u *
2524did_set_string_option(
2525 int opt_idx, // index in options[] table
2526 char_u **varp, // pointer to the option variable
2527 int new_value_alloced, // new value was allocated
2528 char_u *oldval, // previous value of the option
2529 char_u *errbuf, // buffer for errors, or NULL
2530 size_t errbuflen, // length of errors buffer
2531 int opt_flags, // OPT_LOCAL and/or OPT_GLOBAL
2532 int *value_checked // value was checked to be safe, no
2533 // need to set P_INSECURE
2534)
2535{
2536 char_u *errmsg = NULL;
2537 char_u *s, *p;
2538 int did_chartab = false;
2539 char_u **gvarp;
2540 bool free_oldval = (options[opt_idx].flags & P_ALLOCED);
2541 bool value_changed = false;
2542
2543 /* Get the global option to compare with, otherwise we would have to check
2544 * two values for all local options. */
2545 gvarp = (char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
2546
2547 // Disallow changing some options from secure mode
2548 if ((secure || sandbox != 0)
2549 && (options[opt_idx].flags & P_SECURE)) {
2550 errmsg = e_secure;
2551 } else if (((options[opt_idx].flags & P_NFNAME)
2552 && vim_strpbrk(*varp, (char_u *)(secure ? "/\\*?[|;&<>\r\n"
2553 : "/\\*?[<>\r\n")) != NULL)
2554 || ((options[opt_idx].flags & P_NDNAME)
2555 && vim_strpbrk(*varp, (char_u *)"*?[|;&<>\r\n") != NULL)) {
2556 // Check for a "normal" directory or file name in some options. Disallow a
2557 // path separator (slash and/or backslash), wildcards and characters that
2558 // are often illegal in a file name. Be more permissive if "secure" is off.
2559 errmsg = e_invarg;
2560 } else if (gvarp == &p_bkc) { // 'backupcopy'
2561 char_u *bkc = p_bkc;
2562 unsigned int *flags = &bkc_flags;
2563
2564 if (opt_flags & OPT_LOCAL) {
2565 bkc = curbuf->b_p_bkc;
2566 flags = &curbuf->b_bkc_flags;
2567 }
2568
2569 if ((opt_flags & OPT_LOCAL) && *bkc == NUL) {
2570 // make the local value empty: use the global value
2571 *flags = 0;
2572 } else {
2573 if (opt_strings_flags(bkc, p_bkc_values, flags, true) != OK) {
2574 errmsg = e_invarg;
2575 }
2576
2577 if (((*flags & BKC_AUTO) != 0)
2578 + ((*flags & BKC_YES) != 0)
2579 + ((*flags & BKC_NO) != 0) != 1) {
2580 // Must have exactly one of "auto", "yes" and "no".
2581 (void)opt_strings_flags(oldval, p_bkc_values, flags, true);
2582 errmsg = e_invarg;
2583 }
2584 }
2585 } else if (varp == &p_bex || varp == &p_pm) { // 'backupext' and 'patchmode'
2586 if (STRCMP(*p_bex == '.' ? p_bex + 1 : p_bex,
2587 *p_pm == '.' ? p_pm + 1 : p_pm) == 0) {
2588 errmsg = (char_u *)N_("E589: 'backupext' and 'patchmode' are equal");
2589 }
2590 } else if (varp == &curwin->w_p_briopt) { // 'breakindentopt'
2591 if (briopt_check(curwin) == FAIL) {
2592 errmsg = e_invarg;
2593 }
2594 } else if (varp == &p_isi
2595 || varp == &(curbuf->b_p_isk)
2596 || varp == &p_isp
2597 || varp == &p_isf) {
2598 // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[]
2599 // If the new option is invalid, use old value. 'lisp' option: refill
2600 // g_chartab[] for '-' char
2601 if (init_chartab() == FAIL) {
2602 did_chartab = true; // need to restore it below
2603 errmsg = e_invarg; // error in value
2604 }
2605 } else if (varp == &p_hf) { // 'helpfile'
2606 // May compute new values for $VIM and $VIMRUNTIME
2607 if (didset_vim) {
2608 os_setenv("VIM", "", 1);
2609 didset_vim = false;
2610 }
2611 if (didset_vimruntime) {
2612 os_setenv("VIMRUNTIME", "", 1);
2613 didset_vimruntime = false;
2614 }
2615 } else if (varp == &curwin->w_p_cc) { // 'colorcolumn'
2616 errmsg = check_colorcolumn(curwin);
2617 } else if (varp == &p_hlg) { // 'helplang'
2618 // Check for "", "ab", "ab,cd", etc.
2619 for (s = p_hlg; *s != NUL; s += 3) {
2620 if (s[1] == NUL || ((s[2] != ',' || s[3] == NUL) && s[2] != NUL)) {
2621 errmsg = e_invarg;
2622 break;
2623 }
2624 if (s[2] == NUL) {
2625 break;
2626 }
2627 }
2628 } else if (varp == &p_hl) {
2629 // 'highlight'
2630 if (strcmp((char *)(*varp), HIGHLIGHT_INIT) != 0) {
2631 errmsg = e_unsupportedoption;
2632 }
2633 } else if (gvarp == &p_nf) { // 'nrformats'
2634 if (check_opt_strings(*varp, p_nf_values, true) != OK) {
2635 errmsg = e_invarg;
2636 }
2637 } else if (varp == &p_ssop) { // 'sessionoptions'
2638 if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true) != OK) {
2639 errmsg = e_invarg;
2640 }
2641 if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR)) {
2642 // Don't allow both "sesdir" and "curdir".
2643 (void)opt_strings_flags(oldval, p_ssop_values, &ssop_flags, true);
2644 errmsg = e_invarg;
2645 }
2646 } else if (varp == &p_vop) { // 'viewoptions'
2647 if (opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true) != OK) {
2648 errmsg = e_invarg;
2649 }
2650 } else if (varp == &p_rdb) { // 'redrawdebug'
2651 if (opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true) != OK) {
2652 errmsg = e_invarg;
2653 }
2654 } else if (varp == &p_sbo) { // 'scrollopt'
2655 if (check_opt_strings(p_sbo, p_scbopt_values, true) != OK) {
2656 errmsg = e_invarg;
2657 }
2658 } else if (varp == &p_ambw || (int *)varp == &p_emoji) {
2659 // 'ambiwidth'
2660 if (check_opt_strings(p_ambw, p_ambw_values, false) != OK) {
2661 errmsg = e_invarg;
2662 } else {
2663 FOR_ALL_TAB_WINDOWS(tp, wp) {
2664 if (set_chars_option(wp, &wp->w_p_lcs) != NULL) {
2665 errmsg = (char_u *)_("E834: Conflicts with value of 'listchars'");
2666 goto ambw_end;
2667 }
2668 if (set_chars_option(wp, &wp->w_p_fcs) != NULL) {
2669 errmsg = (char_u *)_("E835: Conflicts with value of 'fillchars'");
2670 goto ambw_end;
2671 }
2672 }
2673ambw_end:
2674 {} // clint prefers {} over ; as an empty statement
2675 }
2676 } else if (varp == &p_bg) { // 'background'
2677 if (check_opt_strings(p_bg, p_bg_values, false) == OK) {
2678 int dark = (*p_bg == 'd');
2679
2680 init_highlight(false, false);
2681
2682 if (dark != (*p_bg == 'd') && get_var_value("g:colors_name") != NULL) {
2683 // The color scheme must have set 'background' back to another
2684 // value, that's not what we want here. Disable the color
2685 // scheme and set the colors again.
2686 do_unlet(S_LEN("g:colors_name"), true);
2687 free_string_option(p_bg);
2688 p_bg = vim_strsave((char_u *)(dark ? "dark" : "light"));
2689 check_string_option(&p_bg);
2690 init_highlight(false, false);
2691 }
2692 } else
2693 errmsg = e_invarg;
2694 } else if (varp == &p_wim) { // 'wildmode'
2695 if (check_opt_wim() == FAIL) {
2696 errmsg = e_invarg;
2697 }
2698 // 'wildoptions'
2699 } else if (varp == &p_wop) {
2700 if (opt_strings_flags(p_wop, p_wop_values, &wop_flags, true) != OK) {
2701 errmsg = e_invarg;
2702 }
2703 } else if (varp == &p_wak) { // 'winaltkeys'
2704 if (*p_wak == NUL
2705 || check_opt_strings(p_wak, p_wak_values, false) != OK) {
2706 errmsg = e_invarg;
2707 }
2708 } else if (varp == &p_ei) { // 'eventignore'
2709 if (check_ei() == FAIL) {
2710 errmsg = e_invarg;
2711 }
2712 // 'encoding', 'fileencoding' and 'makeencoding'
2713 } else if (varp == &p_enc || gvarp == &p_fenc || gvarp == &p_menc) {
2714 if (gvarp == &p_fenc) {
2715 if (!MODIFIABLE(curbuf) && opt_flags != OPT_GLOBAL) {
2716 errmsg = e_modifiable;
2717 } else if (vim_strchr(*varp, ',') != NULL) {
2718 // No comma allowed in 'fileencoding'; catches confusing it
2719 // with 'fileencodings'.
2720 errmsg = e_invarg;
2721 } else {
2722 // May show a "+" in the title now.
2723 redraw_titles();
2724 // Add 'fileencoding' to the swap file.
2725 ml_setflags(curbuf);
2726 }
2727 }
2728
2729 if (errmsg == NULL) {
2730 // canonize the value, so that STRCMP() can be used on it
2731 p = enc_canonize(*varp);
2732 xfree(*varp);
2733 *varp = p;
2734 if (varp == &p_enc) {
2735 // only encoding=utf-8 allowed
2736 if (STRCMP(p_enc, "utf-8") != 0) {
2737 errmsg = e_unsupportedoption;
2738 }
2739 }
2740 }
2741 } else if (varp == &p_penc) {
2742 // Canonize printencoding if VIM standard one
2743 p = enc_canonize(p_penc);
2744 xfree(p_penc);
2745 p_penc = p;
2746 } else if (varp == &curbuf->b_p_keymap) {
2747 if (!valid_filetype(*varp)) {
2748 errmsg = e_invarg;
2749 } else {
2750 int secure_save = secure;
2751
2752 // Reset the secure flag, since the value of 'keymap' has
2753 // been checked to be safe.
2754 secure = 0;
2755
2756 // load or unload key mapping tables
2757 errmsg = keymap_init();
2758
2759 secure = secure_save;
2760
2761 // Since we check the value, there is no need to set P_INSECURE,
2762 // even when the value comes from a modeline.
2763 *value_checked = true;
2764 }
2765
2766 if (errmsg == NULL) {
2767 if (*curbuf->b_p_keymap != NUL) {
2768 // Installed a new keymap, switch on using it.
2769 curbuf->b_p_iminsert = B_IMODE_LMAP;
2770 if (curbuf->b_p_imsearch != B_IMODE_USE_INSERT) {
2771 curbuf->b_p_imsearch = B_IMODE_LMAP;
2772 }
2773 } else {
2774 // Cleared the keymap, may reset 'iminsert' and 'imsearch'.
2775 if (curbuf->b_p_iminsert == B_IMODE_LMAP) {
2776 curbuf->b_p_iminsert = B_IMODE_NONE;
2777 }
2778 if (curbuf->b_p_imsearch == B_IMODE_LMAP) {
2779 curbuf->b_p_imsearch = B_IMODE_USE_INSERT;
2780 }
2781 }
2782 if ((opt_flags & OPT_LOCAL) == 0) {
2783 set_iminsert_global();
2784 set_imsearch_global();
2785 }
2786 status_redraw_curbuf();
2787 }
2788 } else if (gvarp == &p_ff) { // 'fileformat'
2789 if (!MODIFIABLE(curbuf) && !(opt_flags & OPT_GLOBAL)) {
2790 errmsg = e_modifiable;
2791 } else if (check_opt_strings(*varp, p_ff_values, false) != OK) {
2792 errmsg = e_invarg;
2793 } else {
2794 redraw_titles();
2795 // update flag in swap file
2796 ml_setflags(curbuf);
2797 /* Redraw needed when switching to/from "mac": a CR in the text
2798 * will be displayed differently. */
2799 if (get_fileformat(curbuf) == EOL_MAC || *oldval == 'm') {
2800 redraw_curbuf_later(NOT_VALID);
2801 }
2802 }
2803 } else if (varp == &p_ffs) { // 'fileformats'
2804 if (check_opt_strings(p_ffs, p_ff_values, true) != OK) {
2805 errmsg = e_invarg;
2806 }
2807 } else if (gvarp == &p_mps) { // 'matchpairs'
2808 if (has_mbyte) {
2809 for (p = *varp; *p != NUL; p++) {
2810 int x2 = -1;
2811 int x3 = -1;
2812
2813 if (*p != NUL) {
2814 p += mb_ptr2len(p);
2815 }
2816 if (*p != NUL) {
2817 x2 = *p++;
2818 }
2819 if (*p != NUL) {
2820 x3 = utf_ptr2char(p);
2821 p += mb_ptr2len(p);
2822 }
2823 if (x2 != ':' || x3 == -1 || (*p != NUL && *p != ',')) {
2824 errmsg = e_invarg;
2825 break;
2826 }
2827 if (*p == NUL) {
2828 break;
2829 }
2830 }
2831 } else {
2832 // Check for "x:y,x:y"
2833 for (p = *varp; *p != NUL; p += 4) {
2834 if (p[1] != ':' || p[2] == NUL || (p[3] != NUL && p[3] != ',')) {
2835 errmsg = e_invarg;
2836 break;
2837 }
2838 if (p[3] == NUL) {
2839 break;
2840 }
2841 }
2842 }
2843 } else if (gvarp == &p_com) { // 'comments'
2844 for (s = *varp; *s; ) {
2845 while (*s && *s != ':') {
2846 if (vim_strchr((char_u *)COM_ALL, *s) == NULL
2847 && !ascii_isdigit(*s) && *s != '-') {
2848 errmsg = illegal_char(errbuf, errbuflen, *s);
2849 break;
2850 }
2851 s++;
2852 }
2853 if (*s++ == NUL) {
2854 errmsg = (char_u *)N_("E524: Missing colon");
2855 } else if (*s == ',' || *s == NUL) {
2856 errmsg = (char_u *)N_("E525: Zero length string");
2857 }
2858 if (errmsg != NULL) {
2859 break;
2860 }
2861 while (*s && *s != ',') {
2862 if (*s == '\\' && s[1] != NUL) {
2863 s++;
2864 }
2865 s++;
2866 }
2867 s = skip_to_option_part(s);
2868 }
2869 } else if (varp == &curwin->w_p_lcs) { // 'listchars'
2870 errmsg = set_chars_option(curwin, varp);
2871 } else if (varp == &curwin->w_p_fcs) { // 'fillchars'
2872 errmsg = set_chars_option(curwin, varp);
2873 } else if (varp == &p_cedit) { // 'cedit'
2874 errmsg = check_cedit();
2875 } else if (varp == &p_vfile) { // 'verbosefile'
2876 verbose_stop();
2877 if (*p_vfile != NUL && verbose_open() == FAIL) {
2878 errmsg = e_invarg;
2879 }
2880 // 'shada'
2881 } else if (varp == &p_shada) {
2882 // TODO(ZyX-I): Remove this code in the future, alongside with &viminfo
2883 // option.
2884 opt_idx = ((options[opt_idx].fullname[0] == 'v')
2885 ? (shada_idx == -1
2886 ? ((shada_idx = findoption("shada")))
2887 : shada_idx)
2888 : opt_idx);
2889 // Update free_oldval now that we have the opt_idx for 'shada', otherwise
2890 // there would be a disconnect between the check for P_ALLOCED at the start
2891 // of the function and the set of P_ALLOCED at the end of the fuction.
2892 free_oldval = (options[opt_idx].flags & P_ALLOCED);
2893 for (s = p_shada; *s; ) {
2894 // Check it's a valid character
2895 if (vim_strchr((char_u *)"!\"%'/:<@cfhnrs", *s) == NULL) {
2896 errmsg = illegal_char(errbuf, errbuflen, *s);
2897 break;
2898 }
2899 if (*s == 'n') { // name is always last one
2900 break;
2901 } else if (*s == 'r') { // skip until next ','
2902 while (*++s && *s != ',') {}
2903 } else if (*s == '%') {
2904 // optional number
2905 while (ascii_isdigit(*++s)) {}
2906 } else if (*s == '!' || *s == 'h' || *s == 'c') {
2907 s++; // no extra chars
2908 } else { // must have a number
2909 while (ascii_isdigit(*++s)) {}
2910
2911 if (!ascii_isdigit(*(s - 1))) {
2912 if (errbuf != NULL) {
2913 vim_snprintf((char *)errbuf, errbuflen,
2914 _("E526: Missing number after <%s>"),
2915 transchar_byte(*(s - 1)));
2916 errmsg = errbuf;
2917 } else
2918 errmsg = (char_u *)"";
2919 break;
2920 }
2921 }
2922 if (*s == ',') {
2923 s++;
2924 } else if (*s) {
2925 if (errbuf != NULL) {
2926 errmsg = (char_u *)N_("E527: Missing comma");
2927 } else {
2928 errmsg = (char_u *)"";
2929 }
2930 break;
2931 }
2932 }
2933 if (*p_shada && errmsg == NULL && get_shada_parameter('\'') < 0) {
2934 errmsg = (char_u *)N_("E528: Must specify a ' value");
2935 }
2936 } else if (varp == &p_sbr) { // 'showbreak'
2937 for (s = p_sbr; *s; ) {
2938 if (ptr2cells(s) != 1) {
2939 errmsg = (char_u *)N_("E595: contains unprintable or wide character");
2940 }
2941 MB_PTR_ADV(s);
2942 }
2943 } else if (varp == &p_guicursor) { // 'guicursor'
2944 errmsg = parse_shape_opt(SHAPE_CURSOR);
2945 } else if (varp == &p_popt) {
2946 errmsg = parse_printoptions();
2947 } else if (varp == &p_pmfn) {
2948 errmsg = parse_printmbfont();
2949 } else if (varp == &p_langmap) { // 'langmap'
2950 langmap_set();
2951 } else if (varp == &p_breakat) { // 'breakat'
2952 fill_breakat_flags();
2953 } else if (varp == &p_titlestring || varp == &p_iconstring) {
2954 // 'titlestring' and 'iconstring'
2955 int flagval = (varp == &p_titlestring) ? STL_IN_TITLE : STL_IN_ICON;
2956
2957 // NULL => statusline syntax
2958 if (vim_strchr(*varp, '%') && check_stl_option(*varp) == NULL) {
2959 stl_syntax |= flagval;
2960 } else {
2961 stl_syntax &= ~flagval;
2962 }
2963 did_set_title(varp == &p_iconstring);
2964
2965 } else if (varp == &p_sel) { // 'selection'
2966 if (*p_sel == NUL
2967 || check_opt_strings(p_sel, p_sel_values, false) != OK) {
2968 errmsg = e_invarg;
2969 }
2970 } else if (varp == &p_slm) { // 'selectmode'
2971 if (check_opt_strings(p_slm, p_slm_values, true) != OK) {
2972 errmsg = e_invarg;
2973 }
2974 } else if (varp == &p_km) { // 'keymodel'
2975 if (check_opt_strings(p_km, p_km_values, true) != OK) {
2976 errmsg = e_invarg;
2977 } else {
2978 km_stopsel = (vim_strchr(p_km, 'o') != NULL);
2979 km_startsel = (vim_strchr(p_km, 'a') != NULL);
2980 }
2981 } else if (varp == &p_mousem) { // 'mousemodel'
2982 if (check_opt_strings(p_mousem, p_mousem_values, false) != OK) {
2983 errmsg = e_invarg;
2984 }
2985 } else if (varp == &p_swb) { // 'switchbuf'
2986 if (opt_strings_flags(p_swb, p_swb_values, &swb_flags, true) != OK) {
2987 errmsg = e_invarg;
2988 }
2989 } else if (varp == &p_debug) { // 'debug'
2990 if (check_opt_strings(p_debug, p_debug_values, true) != OK) {
2991 errmsg = e_invarg;
2992 }
2993 } else if (varp == &p_dy) { // 'display'
2994 if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, true) != OK) {
2995 errmsg = e_invarg;
2996 } else {
2997 (void)init_chartab();
2998 msg_grid_validate();
2999 }
3000 } else if (varp == &p_ead) { // 'eadirection'
3001 if (check_opt_strings(p_ead, p_ead_values, false) != OK) {
3002 errmsg = e_invarg;
3003 }
3004 } else if (varp == &p_cb) { // 'clipboard'
3005 if (opt_strings_flags(p_cb, p_cb_values, &cb_flags, true) != OK) {
3006 errmsg = e_invarg;
3007 }
3008 } else if (varp == &(curwin->w_s->b_p_spl) // 'spell'
3009 || varp == &(curwin->w_s->b_p_spf)) {
3010 // When 'spelllang' or 'spellfile' is set and there is a window for this
3011 // buffer in which 'spell' is set load the wordlists.
3012 errmsg = did_set_spell_option(varp == &(curwin->w_s->b_p_spf));
3013 } else if (varp == &(curwin->w_s->b_p_spc)) {
3014 // When 'spellcapcheck' is set compile the regexp program.
3015 errmsg = compile_cap_prog(curwin->w_s);
3016 } else if (varp == &p_sps) { // 'spellsuggest'
3017 if (spell_check_sps() != OK) {
3018 errmsg = e_invarg;
3019 }
3020 } else if (varp == &p_msm) { // 'mkspellmem'
3021 if (spell_check_msm() != OK) {
3022 errmsg = e_invarg;
3023 }
3024 } else if (gvarp == &p_bh) {
3025 // When 'bufhidden' is set, check for valid value.
3026 if (check_opt_strings(curbuf->b_p_bh, p_bufhidden_values, false) != OK) {
3027 errmsg = e_invarg;
3028 }
3029 } else if (gvarp == &p_bt) {
3030 // When 'buftype' is set, check for valid value.
3031 if ((curbuf->terminal && curbuf->b_p_bt[0] != 't')
3032 || (!curbuf->terminal && curbuf->b_p_bt[0] == 't')
3033 || check_opt_strings(curbuf->b_p_bt, p_buftype_values, false) != OK) {
3034 errmsg = e_invarg;
3035 } else {
3036 if (curwin->w_status_height) {
3037 curwin->w_redr_status = true;
3038 redraw_later(VALID);
3039 }
3040 curbuf->b_help = (curbuf->b_p_bt[0] == 'h');
3041 redraw_titles();
3042 }
3043 } else if (gvarp == &p_stl || varp == &p_ruf) {
3044 // 'statusline' or 'rulerformat'
3045 int wid;
3046
3047 if (varp == &p_ruf) { // reset ru_wid first
3048 ru_wid = 0;
3049 }
3050 s = *varp;
3051 if (varp == &p_ruf && *s == '%') {
3052 // set ru_wid if 'ruf' starts with "%99("
3053 if (*++s == '-') { // ignore a '-'
3054 s++;
3055 }
3056 wid = getdigits_int(&s, true, 0);
3057 if (wid && *s == '(' && (errmsg = check_stl_option(p_ruf)) == NULL) {
3058 ru_wid = wid;
3059 } else {
3060 errmsg = check_stl_option(p_ruf);
3061 }
3062 } else if (varp == &p_ruf || s[0] != '%' || s[1] != '!') {
3063 // check 'statusline' only if it doesn't start with "%!"
3064 errmsg = check_stl_option(s);
3065 }
3066 if (varp == &p_ruf && errmsg == NULL) {
3067 comp_col();
3068 }
3069 } else if (gvarp == &p_cpt) {
3070 // check if it is a valid value for 'complete' -- Acevedo
3071 for (s = *varp; *s; ) {
3072 while (*s == ',' || *s == ' ')
3073 s++;
3074 if (!*s) {
3075 break;
3076 }
3077 if (vim_strchr((char_u *)".wbuksid]tU", *s) == NULL) {
3078 errmsg = illegal_char(errbuf, errbuflen, *s);
3079 break;
3080 }
3081 if (*++s != NUL && *s != ',' && *s != ' ') {
3082 if (s[-1] == 'k' || s[-1] == 's') {
3083 // skip optional filename after 'k' and 's'
3084 while (*s && *s != ',' && *s != ' ') {
3085 if (*s == '\\' && s[1] != NUL) {
3086 s++;
3087 }
3088 s++;
3089 }
3090 } else {
3091 if (errbuf != NULL) {
3092 vim_snprintf((char *)errbuf, errbuflen,
3093 _("E535: Illegal character after <%c>"),
3094 *--s);
3095 errmsg = errbuf;
3096 } else
3097 errmsg = (char_u *)"";
3098 break;
3099 }
3100 }
3101 }
3102 } else if (varp == &p_cot) { // 'completeopt'
3103 if (check_opt_strings(p_cot, p_cot_values, true) != OK) {
3104 errmsg = e_invarg;
3105 } else {
3106 completeopt_was_set();
3107 }
3108 } else if (varp == &curwin->w_p_scl) {
3109 // 'signcolumn'
3110 if (check_opt_strings(*varp, p_scl_values, false) != OK) {
3111 errmsg = e_invarg;
3112 }
3113 } else if (varp == &p_pt) {
3114 // 'pastetoggle': translate key codes like in a mapping
3115 if (*p_pt) {
3116 (void)replace_termcodes(p_pt, STRLEN(p_pt), &p, true, true, true,
3117 CPO_TO_CPO_FLAGS);
3118 if (p != NULL) {
3119 if (new_value_alloced) {
3120 free_string_option(p_pt);
3121 }
3122 p_pt = p;
3123 new_value_alloced = true;
3124 }
3125 }
3126 } else if (varp == &p_bs) { // 'backspace'
3127 if (ascii_isdigit(*p_bs)) {
3128 if (*p_bs >'2' || p_bs[1] != NUL) {
3129 errmsg = e_invarg;
3130 }
3131 } else if (check_opt_strings(p_bs, p_bs_values, true) != OK) {
3132 errmsg = e_invarg;
3133 }
3134 } else if (varp == &p_bo) {
3135 if (opt_strings_flags(p_bo, p_bo_values, &bo_flags, true) != OK) {
3136 errmsg = e_invarg;
3137 }
3138 } else if (gvarp == &p_tc) { // 'tagcase'
3139 unsigned int *flags;
3140
3141 if (opt_flags & OPT_LOCAL) {
3142 p = curbuf->b_p_tc;
3143 flags = &curbuf->b_tc_flags;
3144 } else {
3145 p = p_tc;
3146 flags = &tc_flags;
3147 }
3148
3149 if ((opt_flags & OPT_LOCAL) && *p == NUL) {
3150 // make the local value empty: use the global value
3151 *flags = 0;
3152 } else if (*p == NUL
3153 || opt_strings_flags(p, p_tc_values, flags, false) != OK) {
3154 errmsg = e_invarg;
3155 }
3156 } else if (varp == &p_cmp) { // 'casemap'
3157 if (opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true) != OK) {
3158 errmsg = e_invarg;
3159 }
3160 } else if (varp == &p_dip) { // 'diffopt'
3161 if (diffopt_changed() == FAIL) {
3162 errmsg = e_invarg;
3163 }
3164 } else if (gvarp == &curwin->w_allbuf_opt.wo_fdm) { // 'foldmethod'
3165 if (check_opt_strings(*varp, p_fdm_values, false) != OK
3166 || *curwin->w_p_fdm == NUL) {
3167 errmsg = e_invarg;
3168 } else {
3169 foldUpdateAll(curwin);
3170 if (foldmethodIsDiff(curwin)) {
3171 newFoldLevel();
3172 }
3173 }
3174 } else if (varp == &curwin->w_p_fde) { // 'foldexpr'
3175 if (foldmethodIsExpr(curwin)) {
3176 foldUpdateAll(curwin);
3177 }
3178 } else if (gvarp == &curwin->w_allbuf_opt.wo_fmr) { // 'foldmarker'
3179 p = vim_strchr(*varp, ',');
3180 if (p == NULL) {
3181 errmsg = (char_u *)N_("E536: comma required");
3182 } else if (p == *varp || p[1] == NUL) {
3183 errmsg = e_invarg;
3184 } else if (foldmethodIsMarker(curwin)) {
3185 foldUpdateAll(curwin);
3186 }
3187 } else if (gvarp == &p_cms) { // 'commentstring'
3188 if (**varp != NUL && strstr((char *)(*varp), "%s") == NULL) {
3189 errmsg = (char_u *)N_(
3190 "E537: 'commentstring' must be empty or contain %s");
3191 }
3192 } else if (varp == &p_fdo) { // 'foldopen'
3193 if (opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true) != OK) {
3194 errmsg = e_invarg;
3195 }
3196 } else if (varp == &p_fcl) { // 'foldclose'
3197 if (check_opt_strings(p_fcl, p_fcl_values, true) != OK) {
3198 errmsg = e_invarg;
3199 }
3200 } else if (gvarp == &curwin->w_allbuf_opt.wo_fdi) { // 'foldignore'
3201 if (foldmethodIsIndent(curwin)) {
3202 foldUpdateAll(curwin);
3203 }
3204 } else if (varp == &p_ve) { // 'virtualedit'
3205 if (opt_strings_flags(p_ve, p_ve_values, &ve_flags, true) != OK) {
3206 errmsg = e_invarg;
3207 } else if (STRCMP(p_ve, oldval) != 0) {
3208 // Recompute cursor position in case the new 've' setting
3209 // changes something.
3210 validate_virtcol();
3211 coladvance(curwin->w_virtcol);
3212 }
3213 } else if (varp == &p_csqf) {
3214 if (p_csqf != NULL) {
3215 p = p_csqf;
3216 while (*p != NUL) {
3217 if (vim_strchr((char_u *)CSQF_CMDS, *p) == NULL
3218 || p[1] == NUL
3219 || vim_strchr((char_u *)CSQF_FLAGS, p[1]) == NULL
3220 || (p[2] != NUL && p[2] != ',')) {
3221 errmsg = e_invarg;
3222 break;
3223 } else if (p[2] == NUL) {
3224 break;
3225 } else {
3226 p += 3;
3227 }
3228 }
3229 }
3230 } else if (gvarp == &p_cino) { // 'cinoptions'
3231 // TODO(vim): recognize errors
3232 parse_cino(curbuf);
3233 // inccommand
3234 } else if (varp == &p_icm) {
3235 if (check_opt_strings(p_icm, p_icm_values, false) != OK) {
3236 errmsg = e_invarg;
3237 }
3238 } else if (gvarp == &p_ft) {
3239 if (!valid_filetype(*varp)) {
3240 errmsg = e_invarg;
3241 } else {
3242 value_changed = STRCMP(oldval, *varp) != 0;
3243
3244 // Since we check the value, there is no need to set P_INSECURE,
3245 // even when the value comes from a modeline.
3246 *value_checked = true;
3247 }
3248 } else if (gvarp == &p_syn) {
3249 if (!valid_filetype(*varp)) {
3250 errmsg = e_invarg;
3251 } else {
3252 value_changed = STRCMP(oldval, *varp) != 0;
3253
3254 // Since we check the value, there is no need to set P_INSECURE,
3255 // even when the value comes from a modeline.
3256 *value_checked = true;
3257 }
3258 } else if (varp == &curwin->w_p_winhl) {
3259 if (!parse_winhl_opt(curwin)) {
3260 errmsg = e_invarg;
3261 }
3262 } else {
3263 // Options that are a list of flags.
3264 p = NULL;
3265 if (varp == &p_ww) { // 'whichwrap'
3266 p = (char_u *)WW_ALL;
3267 }
3268 if (varp == &p_shm) { // 'shortmess'
3269 p = (char_u *)SHM_ALL;
3270 } else if (varp == &(p_cpo)) { // 'cpoptions'
3271 p = (char_u *)CPO_VI;
3272 } else if (varp == &(curbuf->b_p_fo)) { // 'formatoptions'
3273 p = (char_u *)FO_ALL;
3274 } else if (varp == &curwin->w_p_cocu) { // 'concealcursor'
3275 p = (char_u *)COCU_ALL;
3276 } else if (varp == &p_mouse) { // 'mouse'
3277 p = (char_u *)MOUSE_ALL;
3278 }
3279 if (p != NULL) {
3280 for (s = *varp; *s; s++) {
3281 if (vim_strchr(p, *s) == NULL) {
3282 errmsg = illegal_char(errbuf, errbuflen, *s);
3283 break;
3284 }
3285 }
3286 }
3287 }
3288
3289 /*
3290 * If error detected, restore the previous value.
3291 */
3292 if (errmsg != NULL) {
3293 if (new_value_alloced) {
3294 free_string_option(*varp);
3295 }
3296 *varp = oldval;
3297 /*
3298 * When resetting some values, need to act on it.
3299 */
3300 if (did_chartab) {
3301 (void)init_chartab();
3302 }
3303 } else {
3304 // Remember where the option was set.
3305 set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
3306 // Free string options that are in allocated memory.
3307 // Use "free_oldval", because recursiveness may change the flags under
3308 // our fingers (esp. init_highlight()).
3309 if (free_oldval) {
3310 free_string_option(oldval);
3311 }
3312 if (new_value_alloced) {
3313 options[opt_idx].flags |= P_ALLOCED;
3314 } else {
3315 options[opt_idx].flags &= ~P_ALLOCED;
3316 }
3317
3318 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
3319 && ((int)options[opt_idx].indir & PV_BOTH)) {
3320 /* global option with local value set to use global value; free
3321 * the local value and make it empty */
3322 p = get_varp_scope(&(options[opt_idx]), OPT_LOCAL);
3323 free_string_option(*(char_u **)p);
3324 *(char_u **)p = empty_option;
3325 } else if (!(opt_flags & OPT_LOCAL) && opt_flags != OPT_GLOBAL) {
3326 // May set global value for local option.
3327 set_string_option_global(opt_idx, varp);
3328 }
3329
3330 /*
3331 * Trigger the autocommand only after setting the flags.
3332 */
3333 // When 'syntax' is set, load the syntax of that name
3334 if (varp == &(curbuf->b_p_syn)) {
3335 static int syn_recursive = 0;
3336
3337 syn_recursive++;
3338 // Only pass true for "force" when the value changed or not used
3339 // recursively, to avoid endless recurrence.
3340 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, curbuf->b_fname,
3341 value_changed || syn_recursive == 1, curbuf);
3342 syn_recursive--;
3343 } else if (varp == &(curbuf->b_p_ft)) {
3344 // 'filetype' is set, trigger the FileType autocommand
3345 // Skip this when called from a modeline and the filetype was
3346 // already set to this value.
3347 if (!(opt_flags & OPT_MODELINE) || value_changed) {
3348 static int ft_recursive = 0;
3349 int secure_save = secure;
3350
3351 // Reset the secure flag, since the value of 'filetype' has
3352 // been checked to be safe.
3353 secure = 0;
3354
3355 ft_recursive++;
3356 did_filetype = true;
3357 // Only pass true for "force" when the value changed or not
3358 // used recursively, to avoid endless recurrence.
3359 apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname,
3360 value_changed || ft_recursive == 1, curbuf);
3361 ft_recursive--;
3362 // Just in case the old "curbuf" is now invalid
3363 if (varp != &(curbuf->b_p_ft)) {
3364 varp = NULL;
3365 }
3366 secure = secure_save;
3367 }
3368 }
3369 if (varp == &(curwin->w_s->b_p_spl)) {
3370 char_u fname[200];
3371 char_u *q = curwin->w_s->b_p_spl;
3372
3373 // Skip the first name if it is "cjk".
3374 if (STRNCMP(q, "cjk,", 4) == 0) {
3375 q += 4;
3376 }
3377
3378 /*
3379 * Source the spell/LANG.vim in 'runtimepath'.
3380 * They could set 'spellcapcheck' depending on the language.
3381 * Use the first name in 'spelllang' up to '_region' or
3382 * '.encoding'.
3383 */
3384 for (p = q; *p != NUL; p++) {
3385 if (!ASCII_ISALNUM(*p) && *p != '-') {
3386 break;
3387 }
3388 }
3389 if (p > q) {
3390 vim_snprintf((char *)fname, sizeof(fname), "spell/%.*s.vim",
3391 (int)(p - q), q);
3392 source_runtime(fname, DIP_ALL);
3393 }
3394 }
3395 }
3396
3397 if (varp == &p_mouse) {
3398 if (*p_mouse == NUL) {
3399 ui_call_mouse_off();
3400 } else {
3401 setmouse(); // in case 'mouse' changed
3402 }
3403 }
3404
3405 if (curwin->w_curswant != MAXCOL
3406 && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0)
3407 curwin->w_set_curswant = true;
3408
3409 check_redraw(options[opt_idx].flags);
3410
3411 return errmsg;
3412} // NOLINT(readability/fn_size)
3413
3414/// Simple int comparison function for use with qsort()
3415static int int_cmp(const void *a, const void *b)
3416{
3417 return *(const int *)a - *(const int *)b;
3418}
3419
3420/// Handle setting 'colorcolumn' or 'textwidth' in window "wp".
3421///
3422/// @return error message, NULL if it's OK.
3423char_u *check_colorcolumn(win_T *wp)
3424{
3425 char_u *s;
3426 int col;
3427 unsigned int count = 0;
3428 int color_cols[256];
3429 int j = 0;
3430
3431 if (wp->w_buffer == NULL) {
3432 return NULL; // buffer was closed
3433 }
3434
3435 for (s = wp->w_p_cc; *s != NUL && count < 255; ) {
3436 if (*s == '-' || *s == '+') {
3437 // -N and +N: add to 'textwidth'
3438 col = (*s == '-') ? -1 : 1;
3439 s++;
3440 if (!ascii_isdigit(*s)) {
3441 return e_invarg;
3442 }
3443 col = col * getdigits_int(&s, true, 0);
3444 if (wp->w_buffer->b_p_tw == 0) {
3445 goto skip; // 'textwidth' not set, skip this item
3446 }
3447 assert((col >= 0
3448 && wp->w_buffer->b_p_tw <= INT_MAX - col
3449 && wp->w_buffer->b_p_tw + col >= INT_MIN)
3450 || (col < 0
3451 && wp->w_buffer->b_p_tw >= INT_MIN - col
3452 && wp->w_buffer->b_p_tw + col <= INT_MAX));
3453 col += (int)wp->w_buffer->b_p_tw;
3454 if (col < 0) {
3455 goto skip;
3456 }
3457 } else if (ascii_isdigit(*s)) {
3458 col = getdigits_int(&s, true, 0);
3459 } else {
3460 return e_invarg;
3461 }
3462 color_cols[count++] = col - 1; // 1-based to 0-based
3463skip:
3464 if (*s == NUL) {
3465 break;
3466 }
3467 if (*s != ',') {
3468 return e_invarg;
3469 }
3470 if (*++s == NUL) {
3471 return e_invarg; // illegal trailing comma as in "set cc=80,"
3472 }
3473 }
3474
3475 xfree(wp->w_p_cc_cols);
3476 if (count == 0) {
3477 wp->w_p_cc_cols = NULL;
3478 } else {
3479 wp->w_p_cc_cols = xmalloc(sizeof(int) * (count + 1));
3480 /* sort the columns for faster usage on screen redraw inside
3481 * win_line() */
3482 qsort(color_cols, count, sizeof(int), int_cmp);
3483
3484 for (unsigned int i = 0; i < count; i++) {
3485 // skip duplicates
3486 if (j == 0 || wp->w_p_cc_cols[j - 1] != color_cols[i]) {
3487 wp->w_p_cc_cols[j++] = color_cols[i];
3488 }
3489 }
3490 wp->w_p_cc_cols[j] = -1; // end marker
3491 }
3492
3493 return NULL; // no error
3494}
3495
3496
3497/// Handle setting 'listchars' or 'fillchars'.
3498/// Assume monocell characters
3499///
3500/// @param varp either &curwin->w_p_lcs or &curwin->w_p_fcs
3501/// @return error message, NULL if it's OK.
3502static char_u *set_chars_option(win_T *wp, char_u **varp)
3503{
3504 int round, i, len, entries;
3505 char_u *p, *s;
3506 int c1;
3507 int c2 = 0;
3508 int c3 = 0;
3509
3510 struct chars_tab {
3511 int *cp; ///< char value
3512 char *name; ///< char id
3513 int def; ///< default value
3514 };
3515 struct chars_tab *tab;
3516
3517 struct chars_tab fcs_tab[] = {
3518 { &wp->w_p_fcs_chars.stl, "stl", ' ' },
3519 { &wp->w_p_fcs_chars.stlnc, "stlnc", ' ' },
3520 { &wp->w_p_fcs_chars.vert, "vert", 9474 }, // │
3521 { &wp->w_p_fcs_chars.fold, "fold", 183 }, // ·
3522 { &wp->w_p_fcs_chars.diff, "diff", '-' },
3523 { &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' },
3524 { &wp->w_p_fcs_chars.eob, "eob", '~' },
3525 };
3526 struct chars_tab lcs_tab[] = {
3527 { &wp->w_p_lcs_chars.eol, "eol", NUL },
3528 { &wp->w_p_lcs_chars.ext, "extends", NUL },
3529 { &wp->w_p_lcs_chars.nbsp, "nbsp", NUL },
3530 { &wp->w_p_lcs_chars.prec, "precedes", NUL },
3531 { &wp->w_p_lcs_chars.space, "space", NUL },
3532 { &wp->w_p_lcs_chars.tab2, "tab", NUL },
3533 { &wp->w_p_lcs_chars.trail, "trail", NUL },
3534 { &wp->w_p_lcs_chars.conceal, "conceal", NUL },
3535 };
3536
3537 if (varp == &wp->w_p_lcs) {
3538 tab = lcs_tab;
3539 entries = ARRAY_SIZE(lcs_tab);
3540 } else {
3541 tab = fcs_tab;
3542 entries = ARRAY_SIZE(fcs_tab);
3543 if (*p_ambw == 'd') {
3544 // XXX: If ambiwidth=double then "|" and "·" take 2 columns, which is
3545 // forbidden (TUI limitation?). Set old defaults.
3546 fcs_tab[2].def = '|';
3547 fcs_tab[3].def = '-';
3548 } else {
3549 fcs_tab[2].def = 9474; // │
3550 fcs_tab[3].def = 183; // ·
3551 }
3552 }
3553
3554 // first round: check for valid value, second round: assign values
3555 for (round = 0; round <= 1; round++) {
3556 if (round > 0) {
3557 // After checking that the value is valid: set defaults
3558 for (i = 0; i < entries; i++) {
3559 if (tab[i].cp != NULL) {
3560 *(tab[i].cp) = tab[i].def;
3561 }
3562 }
3563 if (varp == &wp->w_p_lcs) {
3564 wp->w_p_lcs_chars.tab1 = NUL;
3565 wp->w_p_lcs_chars.tab3 = NUL;
3566 }
3567 }
3568 p = *varp;
3569 while (*p) {
3570 for (i = 0; i < entries; i++) {
3571 len = (int)STRLEN(tab[i].name);
3572 if (STRNCMP(p, tab[i].name, len) == 0
3573 && p[len] == ':'
3574 && p[len + 1] != NUL) {
3575 c2 = c3 = 0;
3576 s = p + len + 1;
3577
3578 // TODO(bfredl): use schar_T representation and utfc_ptr2len
3579 int c1len = utf_ptr2len(s);
3580 c1 = mb_cptr2char_adv((const char_u **)&s);
3581 if (mb_char2cells(c1) > 1 || (c1len == 1 && c1 > 127)) {
3582 continue;
3583 }
3584 if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
3585 if (*s == NUL) {
3586 continue;
3587 }
3588 int c2len = utf_ptr2len(s);
3589 c2 = mb_cptr2char_adv((const char_u **)&s);
3590 if (mb_char2cells(c2) > 1 || (c2len == 1 && c2 > 127)) {
3591 continue;
3592 }
3593 if (!(*s == ',' || *s == NUL)) {
3594 int c3len = utf_ptr2len(s);
3595 c3 = mb_cptr2char_adv((const char_u **)&s);
3596 if (mb_char2cells(c3) > 1 || (c3len == 1 && c3 > 127)) {
3597 continue;
3598 }
3599 }
3600 }
3601 if (*s == ',' || *s == NUL) {
3602 if (round) {
3603 if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
3604 wp->w_p_lcs_chars.tab1 = c1;
3605 wp->w_p_lcs_chars.tab2 = c2;
3606 wp->w_p_lcs_chars.tab3 = c3;
3607 } else if (tab[i].cp != NULL) {
3608 *(tab[i].cp) = c1;
3609 }
3610 }
3611 p = s;
3612 break;
3613 }
3614 }
3615 }
3616
3617 if (i == entries) {
3618 return e_invarg;
3619 }
3620 if (*p == ',') {
3621 p++;
3622 }
3623 }
3624 }
3625
3626 return NULL; // no error
3627}
3628
3629/*
3630 * Check validity of options with the 'statusline' format.
3631 * Return error message or NULL.
3632 */
3633char_u *check_stl_option(char_u *s)
3634{
3635 int itemcnt = 0;
3636 int groupdepth = 0;
3637 static char_u errbuf[80];
3638
3639 while (*s && itemcnt < STL_MAX_ITEM) {
3640 // Check for valid keys after % sequences
3641 while (*s && *s != '%') {
3642 s++;
3643 }
3644 if (!*s) {
3645 break;
3646 }
3647 s++;
3648 if (*s != '%' && *s != ')') {
3649 itemcnt++;
3650 }
3651 if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_SEPARATE) {
3652 s++;
3653 continue;
3654 }
3655 if (*s == ')') {
3656 s++;
3657 if (--groupdepth < 0) {
3658 break;
3659 }
3660 continue;
3661 }
3662 if (*s == '-') {
3663 s++;
3664 }
3665 while (ascii_isdigit(*s)) {
3666 s++;
3667 }
3668 if (*s == STL_USER_HL) {
3669 continue;
3670 }
3671 if (*s == '.') {
3672 s++;
3673 while (*s && ascii_isdigit(*s))
3674 s++;
3675 }
3676 if (*s == '(') {
3677 groupdepth++;
3678 continue;
3679 }
3680 if (vim_strchr(STL_ALL, *s) == NULL) {
3681 return illegal_char(errbuf, sizeof(errbuf), *s);
3682 }
3683 if (*s == '{') {
3684 s++;
3685 while (*s != '}' && *s)
3686 s++;
3687 if (*s != '}') {
3688 return (char_u *)N_("E540: Unclosed expression sequence");
3689 }
3690 }
3691 }
3692 if (itemcnt >= STL_MAX_ITEM) {
3693 return (char_u *)N_("E541: too many items");
3694 }
3695 if (groupdepth != 0) {
3696 return (char_u *)N_("E542: unbalanced groups");
3697 }
3698 return NULL;
3699}
3700
3701static char_u *did_set_spell_option(bool is_spellfile)
3702{
3703 char_u *errmsg = NULL;
3704
3705 if (is_spellfile) {
3706 int l = (int)STRLEN(curwin->w_s->b_p_spf);
3707 if (l > 0
3708 && (l < 4 || STRCMP(curwin->w_s->b_p_spf + l - 4, ".add") != 0)) {
3709 errmsg = e_invarg;
3710 }
3711 }
3712
3713 if (errmsg == NULL) {
3714 FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
3715 if (wp->w_buffer == curbuf && wp->w_p_spell) {
3716 errmsg = did_set_spelllang(wp);
3717 break;
3718 }
3719 }
3720 }
3721
3722 return errmsg;
3723}
3724
3725/*
3726 * Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'.
3727 * Return error message when failed, NULL when OK.
3728 */
3729static char_u *compile_cap_prog(synblock_T *synblock)
3730{
3731 regprog_T *rp = synblock->b_cap_prog;
3732 char_u *re;
3733
3734 if (*synblock->b_p_spc == NUL) {
3735 synblock->b_cap_prog = NULL;
3736 } else {
3737 // Prepend a ^ so that we only match at one column
3738 re = concat_str((char_u *)"^", synblock->b_p_spc);
3739 synblock->b_cap_prog = vim_regcomp(re, RE_MAGIC);
3740 xfree(re);
3741 if (synblock->b_cap_prog == NULL) {
3742 synblock->b_cap_prog = rp; // restore the previous program
3743 return e_invarg;
3744 }
3745 }
3746
3747 vim_regfree(rp);
3748 return NULL;
3749}
3750
3751/// Handle setting `winhighlight' in window "wp"
3752static bool parse_winhl_opt(win_T *wp)
3753{
3754 int w_hl_id_normal = 0;
3755 int w_hl_ids[HLF_COUNT] = { 0 };
3756 int hlf;
3757
3758 const char *p = (const char *)wp->w_p_winhl;
3759 while (*p) {
3760 char *colon = strchr(p, ':');
3761 if (!colon) {
3762 return false;
3763 }
3764 size_t nlen = (size_t)(colon-p);
3765 char *hi = colon+1;
3766 char *commap = xstrchrnul(hi, ',');
3767 int len = (int)(commap-hi);
3768 int hl_id = len ? syn_check_group((char_u *)hi, len) : -1;
3769
3770 if (strncmp("Normal", p, nlen) == 0) {
3771 w_hl_id_normal = hl_id;
3772 } else {
3773 for (hlf = 0; hlf < (int)HLF_COUNT; hlf++) {
3774 if (strncmp(hlf_names[hlf], p, nlen) == 0) {
3775 w_hl_ids[hlf] = hl_id;
3776 break;
3777 }
3778 }
3779 if (hlf == HLF_COUNT) {
3780 return false;
3781 }
3782 }
3783
3784 p = *commap ? commap+1 : "";
3785 }
3786
3787 wp->w_hl_id_normal = w_hl_id_normal;
3788 memcpy(wp->w_hl_ids, w_hl_ids, sizeof(w_hl_ids));
3789 wp->w_hl_needs_update = true;
3790 return true;
3791}
3792
3793// Set the script_ctx for an option, taking care of setting the buffer- or
3794// window-local value.
3795static void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx)
3796{
3797 int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
3798 int indir = (int)options[opt_idx].indir;
3799 const LastSet last_set = { .script_ctx =
3800 { script_ctx.sc_sid, script_ctx.sc_seq,
3801 script_ctx.sc_lnum + sourcing_lnum },
3802 current_channel_id };
3803
3804 // Remember where the option was set. For local options need to do that
3805 // in the buffer or window structure.
3806 if (both || (opt_flags & OPT_GLOBAL) || (indir & (PV_BUF|PV_WIN)) == 0) {
3807 options[opt_idx].last_set = last_set;
3808 }
3809 if (both || (opt_flags & OPT_LOCAL)) {
3810 if (indir & PV_BUF) {
3811 curbuf->b_p_script_ctx[indir & PV_MASK] = last_set;
3812 } else if (indir & PV_WIN) {
3813 curwin->w_p_script_ctx[indir & PV_MASK] = last_set;
3814 }
3815 }
3816}
3817
3818/// Set the value of a boolean option, taking care of side effects
3819///
3820/// @param[in] opt_idx Option index in options[] table.
3821/// @param[out] varp Pointer to the option variable.
3822/// @param[in] value New value.
3823/// @param[in] opt_flags OPT_LOCAL and/or OPT_GLOBAL.
3824///
3825/// @return NULL on success, error message on error.
3826static char *set_bool_option(const int opt_idx, char_u *const varp,
3827 const int value,
3828 const int opt_flags)
3829{
3830 int old_value = *(int *)varp;
3831
3832 // Disallow changing some options from secure mode
3833 if ((secure || sandbox != 0)
3834 && (options[opt_idx].flags & P_SECURE)) {
3835 return (char *)e_secure;
3836 }
3837
3838 *(int *)varp = value; // set the new value
3839 // Remember where the option was set.
3840 set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
3841
3842
3843 // May set global value for local option.
3844 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
3845 *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = value;
3846 }
3847
3848 // Ensure that options set to p_force_on cannot be disabled.
3849 if ((int *)varp == &p_force_on && p_force_on == false) {
3850 p_force_on = true;
3851 return (char *)e_unsupportedoption;
3852 // Ensure that options set to p_force_off cannot be enabled.
3853 } else if ((int *)varp == &p_force_off && p_force_off == true) {
3854 p_force_off = false;
3855 return (char *)e_unsupportedoption;
3856 } else if ((int *)varp == &p_lrm) {
3857 // 'langremap' -> !'langnoremap'
3858 p_lnr = !p_lrm;
3859 } else if ((int *)varp == &p_lnr) {
3860 // 'langnoremap' -> !'langremap'
3861 p_lrm = !p_lnr;
3862 } else if ((int *)varp == &curwin->w_p_cul && !value && old_value) {
3863 // 'cursorline'
3864 reset_cursorline();
3865 // 'undofile'
3866 } else if ((int *)varp == &curbuf->b_p_udf || (int *)varp == &p_udf) {
3867 // Only take action when the option was set. When reset we do not
3868 // delete the undo file, the option may be set again without making
3869 // any changes in between.
3870 if (curbuf->b_p_udf || p_udf) {
3871 char_u hash[UNDO_HASH_SIZE];
3872 buf_T *save_curbuf = curbuf;
3873
3874 FOR_ALL_BUFFERS(bp) {
3875 curbuf = bp;
3876 // When 'undofile' is set globally: for every buffer, otherwise
3877 // only for the current buffer: Try to read in the undofile,
3878 // if one exists, the buffer wasn't changed and the buffer was
3879 // loaded
3880 if ((curbuf == save_curbuf
3881 || (opt_flags & OPT_GLOBAL) || opt_flags == 0)
3882 && !curbufIsChanged() && curbuf->b_ml.ml_mfp != NULL) {
3883 u_compute_hash(hash);
3884 u_read_undo(NULL, hash, curbuf->b_fname);
3885 }
3886 }
3887 curbuf = save_curbuf;
3888 }
3889 } else if ((int *)varp == &curbuf->b_p_ro) {
3890 // when 'readonly' is reset globally, also reset readonlymode
3891 if (!curbuf->b_p_ro && (opt_flags & OPT_LOCAL) == 0) {
3892 readonlymode = false;
3893 }
3894
3895 // when 'readonly' is set may give W10 again
3896 if (curbuf->b_p_ro) {
3897 curbuf->b_did_warn = false;
3898 }
3899
3900 redraw_titles();
3901 } else if ((int *)varp == &curbuf->b_p_ma) {
3902 // when 'modifiable' is changed, redraw the window title
3903 redraw_titles();
3904 } else if ((int *)varp == &curbuf->b_p_eol) {
3905 // when 'endofline' is changed, redraw the window title
3906 redraw_titles();
3907 } else if ((int *)varp == &curbuf->b_p_fixeol) {
3908 // when 'fixeol' is changed, redraw the window title
3909 redraw_titles();
3910 } else if ((int *)varp == &curbuf->b_p_bomb) {
3911 // when 'bomb' is changed, redraw the window title and tab page text
3912 redraw_titles();
3913 } else if ((int *)varp == &curbuf->b_p_bin) {
3914 // when 'bin' is set also set some other options
3915 set_options_bin(old_value, curbuf->b_p_bin, opt_flags);
3916 redraw_titles();
3917 } else if ((int *)varp == &curbuf->b_p_bl && old_value != curbuf->b_p_bl) {
3918 // when 'buflisted' changes, trigger autocommands
3919 apply_autocmds(curbuf->b_p_bl ? EVENT_BUFADD : EVENT_BUFDELETE,
3920 NULL, NULL, true, curbuf);
3921 } else if ((int *)varp == (int *)&curbuf->b_p_swf) {
3922 // when 'swf' is set, create swapfile, when reset remove swapfile
3923 if (curbuf->b_p_swf && p_uc) {
3924 ml_open_file(curbuf); // create the swap file
3925 } else {
3926 // no need to reset curbuf->b_may_swap, ml_open_file() will check
3927 // buf->b_p_swf
3928 mf_close_file(curbuf, true); // remove the swap file
3929 }
3930 } else if ((int *)varp == &p_terse) {
3931 // when 'terse' is set change 'shortmess'
3932 char_u *p;
3933
3934 p = vim_strchr(p_shm, SHM_SEARCH);
3935
3936 // insert 's' in p_shm
3937 if (p_terse && p == NULL) {
3938 STRCPY(IObuff, p_shm);
3939 STRCAT(IObuff, "s");
3940 set_string_option_direct((char_u *)"shm", -1, IObuff, OPT_FREE, 0);
3941 } else if (!p_terse && p != NULL) { // remove 's' from p_shm
3942 STRMOVE(p, p + 1);
3943 }
3944 } else if ((int *)varp == &p_paste) {
3945 // when 'paste' is set or reset also change other options
3946 paste_option_changed();
3947 } else if ((int *)varp == &p_im) {
3948 // when 'insertmode' is set from an autocommand need to do work here
3949 if (p_im) {
3950 if ((State & INSERT) == 0) {
3951 need_start_insertmode = true;
3952 }
3953 stop_insert_mode = false;
3954 } else if (old_value) { // only reset if it was set previously
3955 need_start_insertmode = false;
3956 stop_insert_mode = true;
3957 if (restart_edit != 0 && mode_displayed) {
3958 clear_cmdline = true; // remove "(insert)"
3959 }
3960 restart_edit = 0;
3961 }
3962 } else if ((int *)varp == &p_ic && p_hls) {
3963 // when 'ignorecase' is set or reset and 'hlsearch' is set, redraw
3964 redraw_all_later(SOME_VALID);
3965 } else if ((int *)varp == &p_hls) {
3966 // when 'hlsearch' is set or reset: reset no_hlsearch
3967 set_no_hlsearch(false);
3968 } else if ((int *)varp == &curwin->w_p_scb) {
3969 // when 'scrollbind' is set: snapshot the current position to avoid a jump
3970 // at the end of normal_cmd()
3971 if (curwin->w_p_scb) {
3972 do_check_scrollbind(false);
3973 curwin->w_scbind_pos = curwin->w_topline;
3974 }
3975 } else if ((int *)varp == &curwin->w_p_pvw) {
3976 // There can be only one window with 'previewwindow' set.
3977 if (curwin->w_p_pvw) {
3978 FOR_ALL_WINDOWS_IN_TAB(win, curtab) {
3979 if (win->w_p_pvw && win != curwin) {
3980 curwin->w_p_pvw = false;
3981 return N_("E590: A preview window already exists");
3982 }
3983 }
3984 }
3985 } else if (varp == (char_u *)&(curbuf->b_p_lisp)) {
3986 // When 'lisp' option changes include/exclude '-' in
3987 // keyword characters.
3988 (void)buf_init_chartab(curbuf, false); // ignore errors
3989 } else if ((int *)varp == &p_title) {
3990 // when 'title' changed, may need to change the title; same for 'icon'
3991 did_set_title(false);
3992 } else if ((int *)varp == &p_icon) {
3993 did_set_title(true);
3994 } else if ((int *)varp == &curbuf->b_changed) {
3995 if (!value) {
3996 save_file_ff(curbuf); // Buffer is unchanged
3997 }
3998 redraw_titles();
3999 modified_was_set = value;
4000 }
4001
4002#ifdef BACKSLASH_IN_FILENAME
4003 else if ((int *)varp == &p_ssl) {
4004 if (p_ssl) {
4005 psepc = '/';
4006 psepcN = '\\';
4007 pseps[0] = '/';
4008 } else {
4009 psepc = '\\';
4010 psepcN = '/';
4011 pseps[0] = '\\';
4012 }
4013
4014 // need to adjust the file name arguments and buffer names.
4015 buflist_slash_adjust();
4016 alist_slash_adjust();
4017 scriptnames_slash_adjust();
4018 }
4019#endif
4020 else if ((int *)varp == &curwin->w_p_wrap) {
4021 // If 'wrap' is set, set w_leftcol to zero.
4022 if (curwin->w_p_wrap) {
4023 curwin->w_leftcol = 0;
4024 }
4025 } else if ((int *)varp == &p_ea) {
4026 if (p_ea && !old_value) {
4027 win_equal(curwin, false, 0);
4028 }
4029 } else if ((int *)varp == &p_acd) {
4030 // Change directories when the 'acd' option is set now.
4031 do_autochdir();
4032 } else if ((int *)varp == &curwin->w_p_diff) { // 'diff'
4033 // May add or remove the buffer from the list of diff buffers.
4034 diff_buf_adjust(curwin);
4035 if (foldmethodIsDiff(curwin)) {
4036 foldUpdateAll(curwin);
4037 }
4038 } else if ((int *)varp == &curwin->w_p_spell) { // 'spell'
4039 if (curwin->w_p_spell) {
4040 char_u *errmsg = did_set_spelllang(curwin);
4041 if (errmsg != NULL) {
4042 EMSG(_(errmsg));
4043 }
4044 }
4045 }
4046
4047 if ((int *)varp == &curwin->w_p_arab) {
4048 if (curwin->w_p_arab) {
4049 /*
4050 * 'arabic' is set, handle various sub-settings.
4051 */
4052 if (!p_tbidi) {
4053 // set rightleft mode
4054 if (!curwin->w_p_rl) {
4055 curwin->w_p_rl = true;
4056 changed_window_setting();
4057 }
4058
4059 // Enable Arabic shaping (major part of what Arabic requires)
4060 if (!p_arshape) {
4061 p_arshape = true;
4062 redraw_all_later(NOT_VALID);
4063 }
4064 }
4065
4066 /* Arabic requires a utf-8 encoding, inform the user if its not
4067 * set. */
4068 if (STRCMP(p_enc, "utf-8") != 0) {
4069 static char *w_arabic = N_(
4070 "W17: Arabic requires UTF-8, do ':set encoding=utf-8'");
4071
4072 msg_source(HL_ATTR(HLF_W));
4073 msg_attr(_(w_arabic), HL_ATTR(HLF_W));
4074 set_vim_var_string(VV_WARNINGMSG, _(w_arabic), -1);
4075 }
4076
4077 // set 'delcombine'
4078 p_deco = true;
4079
4080 // Force-set the necessary keymap for arabic.
4081 set_option_value("keymap", 0L, "arabic", OPT_LOCAL);
4082 } else {
4083 /*
4084 * 'arabic' is reset, handle various sub-settings.
4085 */
4086 if (!p_tbidi) {
4087 // reset rightleft mode
4088 if (curwin->w_p_rl) {
4089 curwin->w_p_rl = false;
4090 changed_window_setting();
4091 }
4092
4093 /* 'arabicshape' isn't reset, it is a global option and
4094 * another window may still need it "on". */
4095 }
4096
4097 /* 'delcombine' isn't reset, it is a global option and another
4098 * window may still want it "on". */
4099
4100 // Revert to the default keymap
4101 curbuf->b_p_iminsert = B_IMODE_NONE;
4102 curbuf->b_p_imsearch = B_IMODE_USE_INSERT;
4103 }
4104 }
4105
4106
4107 /*
4108 * End of handling side effects for bool options.
4109 */
4110
4111 // after handling side effects, call autocommand
4112
4113 options[opt_idx].flags |= P_WAS_SET;
4114
4115 // Don't do this while starting up or recursively.
4116 if (!starting && *get_vim_var_str(VV_OPTION_TYPE) == NUL) {
4117 char buf_old[2];
4118 char buf_new[2];
4119 char buf_type[7];
4120 vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%d",
4121 old_value ? true: false);
4122 vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%d",
4123 value ? true: false);
4124 vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
4125 (opt_flags & OPT_LOCAL) ? "local" : "global");
4126 set_vim_var_string(VV_OPTION_NEW, buf_new, -1);
4127 set_vim_var_string(VV_OPTION_OLD, buf_old, -1);
4128 set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
4129 apply_autocmds(EVENT_OPTIONSET,
4130 (char_u *) options[opt_idx].fullname,
4131 NULL, false, NULL);
4132 reset_v_option_vars();
4133 }
4134
4135 if (options[opt_idx].flags & P_UI_OPTION) {
4136 ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
4137 BOOLEAN_OBJ(value));
4138 }
4139
4140 comp_col(); // in case 'ruler' or 'showcmd' changed
4141 if (curwin->w_curswant != MAXCOL
4142 && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0) {
4143 curwin->w_set_curswant = true;
4144 }
4145 check_redraw(options[opt_idx].flags);
4146
4147 return NULL;
4148}
4149
4150/// Set the value of a number option, taking care of side effects
4151///
4152/// @param[in] opt_idx Option index in options[] table.
4153/// @param[out] varp Pointer to the option variable.
4154/// @param[in] value New value.
4155/// @param errbuf Buffer for error messages.
4156/// @param[in] errbuflen Length of `errbuf`.
4157/// @param[in] opt_flags OPT_LOCAL, OPT_GLOBAL or OPT_MODELINE.
4158///
4159/// @return NULL on success, error message on error.
4160static char *set_num_option(int opt_idx, char_u *varp, long value,
4161 char_u *errbuf, size_t errbuflen, int opt_flags)
4162{
4163 char_u *errmsg = NULL;
4164 long old_value = *(long *)varp;
4165 long old_Rows = Rows; // remember old Rows
4166 long *pp = (long *)varp;
4167
4168 // Disallow changing some options from secure mode.
4169 if ((secure || sandbox != 0)
4170 && (options[opt_idx].flags & P_SECURE)) {
4171 return (char *)e_secure;
4172 }
4173
4174 // Many number options assume their value is in the signed int range.
4175 if (value < INT_MIN || value > INT_MAX) {
4176 return (char *)e_invarg;
4177 }
4178
4179 // Options that need some validation.
4180 if (pp == &p_wh) {
4181 if (value < 1) {
4182 errmsg = e_positive;
4183 } else if (p_wmh > value) {
4184 errmsg = e_winheight;
4185 }
4186 } else if (pp == &p_hh) {
4187 if (value < 0) {
4188 errmsg = e_positive;
4189 }
4190 } else if (pp == &p_wmh) {
4191 if (value < 0) {
4192 errmsg = e_positive;
4193 } else if (value > p_wh) {
4194 errmsg = e_winheight;
4195 }
4196 } else if (pp == &p_wiw) {
4197 if (value < 1) {
4198 errmsg = e_positive;
4199 } else if (p_wmw > value) {
4200 errmsg = e_winwidth;
4201 }
4202 } else if (pp == &p_wmw) {
4203 if (value < 0) {
4204 errmsg = e_positive;
4205 } else if (value > p_wiw) {
4206 errmsg = e_winwidth;
4207 }
4208 } else if (pp == &p_mco) {
4209 value = MAX_MCO;
4210 } else if (pp == &p_titlelen) {
4211 if (value < 0) {
4212 errmsg = e_positive;
4213 }
4214 } else if (pp == &p_uc) {
4215 if (value < 0) {
4216 errmsg = e_positive;
4217 }
4218 } else if (pp == &p_ch) {
4219 int minval = ui_has(kUIMessages) ? 0 : 1;
4220 if (value < minval) {
4221 errmsg = e_positive;
4222 }
4223 } else if (pp == &p_tm) {
4224 if (value < 0) {
4225 errmsg = e_positive;
4226 }
4227 } else if (pp == &p_hi) {
4228 if (value < 0) {
4229 errmsg = e_positive;
4230 } else if (value > 10000) {
4231 errmsg = e_invarg;
4232 }
4233 } else if (pp == &p_re) {
4234 if (value < 0 || value > 2) {
4235 errmsg = e_invarg;
4236 }
4237 } else if (pp == &p_report) {
4238 if (value < 0) {
4239 errmsg = e_positive;
4240 }
4241 } else if (pp == &p_so) {
4242 if (value < 0 && full_screen) {
4243 errmsg = e_scroll;
4244 }
4245 } else if (pp == &p_siso) {
4246 if (value < 0 && full_screen) {
4247 errmsg = e_positive;
4248 }
4249 } else if (pp == &p_cwh) {
4250 if (value < 1) {
4251 errmsg = e_positive;
4252 }
4253 } else if (pp == &p_ut) {
4254 if (value < 0) {
4255 errmsg = e_positive;
4256 }
4257 } else if (pp == &p_ss) {
4258 if (value < 0) {
4259 errmsg = e_positive;
4260 }
4261 } else if (pp == &curwin->w_p_fdl || pp == &curwin->w_allbuf_opt.wo_fdl) {
4262 if (value < 0) {
4263 errmsg = e_positive;
4264 }
4265 } else if (pp == &curwin->w_p_fdc || pp == &curwin->w_allbuf_opt.wo_fdc) {
4266 if (value < 0) {
4267 errmsg = e_positive;
4268 } else if (value > 12) {
4269 errmsg = e_invarg;
4270 }
4271 } else if (pp == &curwin->w_p_cole || pp == &curwin->w_allbuf_opt.wo_cole) {
4272 if (value < 0) {
4273 errmsg = e_positive;
4274 } else if (value > 3) {
4275 errmsg = e_invarg;
4276 }
4277 } else if (pp == &curwin->w_p_nuw || pp == &curwin->w_allbuf_opt.wo_nuw) {
4278 if (value < 1) {
4279 errmsg = e_positive;
4280 } else if (value > 20) {
4281 errmsg = e_invarg;
4282 }
4283 } else if (pp == &curbuf->b_p_iminsert || pp == &p_iminsert) {
4284 if (value < 0 || value > B_IMODE_LAST) {
4285 errmsg = e_invarg;
4286 }
4287 } else if (pp == &curbuf->b_p_imsearch || pp == &p_imsearch) {
4288 if (value < -1 || value > B_IMODE_LAST) {
4289 errmsg = e_invarg;
4290 }
4291 } else if (pp == &curbuf->b_p_channel || pp == &p_channel) {
4292 errmsg = e_invarg;
4293 } else if (pp == &curbuf->b_p_scbk || pp == &p_scbk) {
4294 if (value < -1 || value > SB_MAX) {
4295 errmsg = e_invarg;
4296 }
4297 } else if (pp == &curbuf->b_p_sw || pp == &p_sw) {
4298 if (value < 0) {
4299 errmsg = e_positive;
4300 }
4301 } else if (pp == &curbuf->b_p_ts || pp == &p_ts) {
4302 if (value < 1) {
4303 errmsg = e_positive;
4304 }
4305 } else if (pp == &curbuf->b_p_tw || pp == &p_tw) {
4306 if (value < 0) {
4307 errmsg = e_positive;
4308 }
4309 }
4310
4311 // Don't change the value and return early if validation failed.
4312 if (errmsg != NULL) {
4313 return (char *)errmsg;
4314 }
4315
4316 *pp = value;
4317 // Remember where the option was set.
4318 set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
4319
4320 // For these options we want to fix some invalid values.
4321 if (pp == &p_window) {
4322 if (p_window < 1) {
4323 p_window = Rows - 1;
4324 } else if (p_window >= Rows) {
4325 p_window = Rows - 1;
4326 }
4327 } else if (pp == &p_ch) {
4328 if (ui_has(kUIMessages)) {
4329 p_ch = 0;
4330 }
4331 if (p_ch > Rows - min_rows() + 1) {
4332 p_ch = Rows - min_rows() + 1;
4333 }
4334 }
4335
4336 // Number options that need some action when changed
4337 if (pp == &p_wh) {
4338 // 'winheight'
4339 if (!ONE_WINDOW && curwin->w_height < p_wh) {
4340 win_setheight((int)p_wh);
4341 }
4342 } else if (pp == &p_hh) {
4343 // 'helpheight'
4344 if (!ONE_WINDOW && curbuf->b_help && curwin->w_height < p_hh) {
4345 win_setheight((int)p_hh);
4346 }
4347 } else if (pp == &p_wmh) {
4348 // 'winminheight'
4349 win_setminheight();
4350 } else if (pp == &p_wiw) {
4351 // 'winwidth'
4352 if (!ONE_WINDOW && curwin->w_width < p_wiw) {
4353 win_setwidth((int)p_wiw);
4354 }
4355 } else if (pp == &p_wmw) {
4356 // 'winminwidth'
4357 win_setminwidth();
4358 } else if (pp == &p_ls) {
4359 last_status(false); // (re)set last window status line.
4360 } else if (pp == &p_stal) {
4361 // (re)set tab page line
4362 shell_new_rows(); // recompute window positions and heights
4363 } else if (pp == &curwin->w_p_fdl) {
4364 newFoldLevel();
4365 } else if (pp == &curwin->w_p_fml) {
4366 foldUpdateAll(curwin);
4367 } else if (pp == &curwin->w_p_fdn) {
4368 if (foldmethodIsSyntax(curwin) || foldmethodIsIndent(curwin)) {
4369 foldUpdateAll(curwin);
4370 }
4371 } else if (pp == &curbuf->b_p_sw || pp == &curbuf->b_p_ts) {
4372 // 'shiftwidth' or 'tabstop'
4373 if (foldmethodIsIndent(curwin)) {
4374 foldUpdateAll(curwin);
4375 }
4376 // When 'shiftwidth' changes, or it's zero and 'tabstop' changes:
4377 // parse 'cinoptions'.
4378 if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0) {
4379 parse_cino(curbuf);
4380 }
4381 } else if (pp == &curbuf->b_p_iminsert) {
4382 showmode();
4383 // Show/unshow value of 'keymap' in status lines.
4384 status_redraw_curbuf();
4385 } else if (pp == &p_titlelen) {
4386 // if 'titlelen' has changed, redraw the title
4387 if (starting != NO_SCREEN && old_value != p_titlelen) {
4388 need_maketitle = true;
4389 }
4390 } else if (pp == &p_ch) {
4391 // if p_ch changed value, change the command line height
4392 // Only compute the new window layout when startup has been
4393 // completed. Otherwise the frame sizes may be wrong.
4394 if (p_ch != old_value && full_screen) {
4395 command_height();
4396 }
4397 } else if (pp == &p_uc) {
4398 // when 'updatecount' changes from zero to non-zero, open swap files
4399 if (p_uc && !old_value) {
4400 ml_open_files();
4401 }
4402 } else if (pp == &p_pb) {
4403 p_pb = MAX(MIN(p_pb, 100), 0);
4404 hl_invalidate_blends();
4405 pum_grid.blending = (p_pb > 0);
4406 if (pum_drawn()) {
4407 pum_redraw();
4408 }
4409 } else if (pp == &p_pyx) {
4410 if (p_pyx != 0 && p_pyx != 2 && p_pyx != 3) {
4411 errmsg = e_invarg;
4412 }
4413 } else if (pp == &p_ul || pp == &curbuf->b_p_ul) {
4414 // sync undo before 'undolevels' changes
4415 // use the old value, otherwise u_sync() may not work properly
4416 *pp = old_value;
4417 u_sync(true);
4418 *pp = value;
4419 } else if (pp == &curbuf->b_p_tw) {
4420 FOR_ALL_TAB_WINDOWS(tp, wp) {
4421 check_colorcolumn(wp);
4422 }
4423 } else if (pp == &curbuf->b_p_scbk || pp == &p_scbk) {
4424 if (curbuf->terminal) {
4425 // Force the scrollback to take effect.
4426 terminal_check_size(curbuf->terminal);
4427 }
4428 } else if (pp == &curwin->w_p_nuw) {
4429 curwin->w_nrwidth_line_count = 0;
4430 } else if (pp == &curwin->w_p_winbl && value != old_value) {
4431 // 'floatblend'
4432 curwin->w_p_winbl = MAX(MIN(curwin->w_p_winbl, 100), 0);
4433 curwin->w_hl_needs_update = true;
4434 curwin->w_grid.blending = curwin->w_p_winbl > 0;
4435 }
4436
4437
4438 // Check the (new) bounds for Rows and Columns here.
4439 if (p_lines < min_rows() && full_screen) {
4440 if (errbuf != NULL) {
4441 vim_snprintf((char *)errbuf, errbuflen,
4442 _("E593: Need at least %d lines"), min_rows());
4443 errmsg = errbuf;
4444 }
4445 p_lines = min_rows();
4446 }
4447 if (p_columns < MIN_COLUMNS && full_screen) {
4448 if (errbuf != NULL) {
4449 vim_snprintf((char *)errbuf, errbuflen,
4450 _("E594: Need at least %d columns"), MIN_COLUMNS);
4451 errmsg = errbuf;
4452 }
4453 p_columns = MIN_COLUMNS;
4454 }
4455
4456 // True max size is defined by check_shellsize()
4457 p_lines = MIN(p_lines, INT_MAX);
4458 p_columns = MIN(p_columns, INT_MAX);
4459
4460 // If the screen (shell) height has been changed, assume it is the
4461 // physical screenheight.
4462 if (p_lines != Rows || p_columns != Columns) {
4463 // Changing the screen size is not allowed while updating the screen.
4464 if (updating_screen) {
4465 *pp = old_value;
4466 } else if (full_screen) {
4467 screen_resize((int)p_columns, (int)p_lines);
4468 } else {
4469 // TODO(bfredl): is this branch ever needed?
4470 // Postpone the resizing; check the size and cmdline position for
4471 // messages.
4472 Rows = (int)p_lines;
4473 Columns = (int)p_columns;
4474 check_shellsize();
4475 if (cmdline_row > Rows - p_ch && Rows > p_ch) {
4476 assert(p_ch >= 0 && Rows - p_ch <= INT_MAX);
4477 cmdline_row = (int)(Rows - p_ch);
4478 }
4479 }
4480 if (p_window >= Rows || !option_was_set("window")) {
4481 p_window = Rows - 1;
4482 }
4483 }
4484
4485 if ((curwin->w_p_scr <= 0
4486 || (curwin->w_p_scr > curwin->w_height
4487 && curwin->w_height > 0))
4488 && full_screen) {
4489 if (pp == &(curwin->w_p_scr)) {
4490 if (curwin->w_p_scr != 0) {
4491 errmsg = e_scroll;
4492 }
4493 win_comp_scroll(curwin);
4494 } else if (curwin->w_p_scr <= 0) {
4495 // If 'scroll' became invalid because of a side effect silently adjust it.
4496 curwin->w_p_scr = 1;
4497 } else { // curwin->w_p_scr > curwin->w_height
4498 curwin->w_p_scr = curwin->w_height;
4499 }
4500 }
4501 if ((p_sj < -100 || p_sj >= Rows) && full_screen) {
4502 if (Rows != old_Rows) { // Rows changed, just adjust p_sj
4503 p_sj = Rows / 2;
4504 } else {
4505 errmsg = e_scroll;
4506 p_sj = 1;
4507 }
4508 }
4509
4510 // May set global value for local option.
4511 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
4512 *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = *pp;
4513 }
4514
4515 options[opt_idx].flags |= P_WAS_SET;
4516
4517 // Don't do this while starting up, failure or recursively.
4518 if (!starting && errmsg == NULL && *get_vim_var_str(VV_OPTION_TYPE) == NUL) {
4519 char buf_old[NUMBUFLEN];
4520 char buf_new[NUMBUFLEN];
4521 char buf_type[7];
4522 vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%ld", old_value);
4523 vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%ld", value);
4524 vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
4525 (opt_flags & OPT_LOCAL) ? "local" : "global");
4526 set_vim_var_string(VV_OPTION_NEW, buf_new, -1);
4527 set_vim_var_string(VV_OPTION_OLD, buf_old, -1);
4528 set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
4529 apply_autocmds(EVENT_OPTIONSET,
4530 (char_u *) options[opt_idx].fullname,
4531 NULL, false, NULL);
4532 reset_v_option_vars();
4533 }
4534
4535 if (errmsg == NULL && options[opt_idx].flags & P_UI_OPTION) {
4536 ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
4537 INTEGER_OBJ(value));
4538 }
4539
4540 comp_col(); // in case 'columns' or 'ls' changed
4541 if (curwin->w_curswant != MAXCOL
4542 && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0) {
4543 curwin->w_set_curswant = true;
4544 }
4545 check_redraw(options[opt_idx].flags);
4546
4547 return (char *)errmsg;
4548}
4549
4550static void trigger_optionsset_string(int opt_idx, int opt_flags,
4551 char *oldval, char *newval)
4552{
4553 // Don't do this recursively.
4554 if (oldval != NULL
4555 && newval != NULL
4556 && *get_vim_var_str(VV_OPTION_TYPE) == NUL) {
4557 char buf_type[7];
4558
4559 vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
4560 (opt_flags & OPT_LOCAL) ? "local" : "global");
4561 set_vim_var_string(VV_OPTION_OLD, oldval, -1);
4562 set_vim_var_string(VV_OPTION_NEW, newval, -1);
4563 set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
4564 apply_autocmds(EVENT_OPTIONSET,
4565 (char_u *)options[opt_idx].fullname, NULL, false, NULL);
4566 reset_v_option_vars();
4567 }
4568}
4569
4570/*
4571 * Called after an option changed: check if something needs to be redrawn.
4572 */
4573static void check_redraw(uint32_t flags)
4574{
4575 // Careful: P_RCLR and P_RALL are a combination of other P_ flags
4576 bool doclear = (flags & P_RCLR) == P_RCLR;
4577 bool all = ((flags & P_RALL) == P_RALL || doclear);
4578
4579 if ((flags & P_RSTAT) || all) { // mark all status lines dirty
4580 status_redraw_all();
4581 }
4582
4583 if ((flags & P_RBUF) || (flags & P_RWIN) || all) {
4584 changed_window_setting();
4585 }
4586 if (flags & P_RBUF) {
4587 redraw_curbuf_later(NOT_VALID);
4588 }
4589 if (flags & P_RWINONLY) {
4590 redraw_later(NOT_VALID);
4591 }
4592 if (doclear) {
4593 redraw_all_later(CLEAR);
4594 } else if (all) {
4595 redraw_all_later(NOT_VALID);
4596 }
4597}
4598
4599/// Find index for named option
4600///
4601/// @param[in] arg Option to find index for.
4602/// @param[in] len Length of the option.
4603///
4604/// @return Index of the option or -1 if option was not found.
4605int findoption_len(const char *const arg, const size_t len)
4606{
4607 const char *s;
4608 const char *p;
4609 static int quick_tab[27] = { 0, 0 }; // quick access table
4610
4611 // For first call: Initialize the quick-access table.
4612 // It contains the index for the first option that starts with a certain
4613 // letter. There are 26 letters, plus the first "t_" option.
4614 if (quick_tab[1] == 0) {
4615 p = options[0].fullname;
4616 for (short int i = 1; (s = options[i].fullname) != NULL; i++) {
4617 if (s[0] != p[0]) {
4618 if (s[0] == 't' && s[1] == '_') {
4619 quick_tab[26] = i;
4620 } else {
4621 quick_tab[CharOrdLow(s[0])] = i;
4622 }
4623 }
4624 p = s;
4625 }
4626 }
4627
4628 // Check for name starting with an illegal character.
4629 if (len == 0 || arg[0] < 'a' || arg[0] > 'z') {
4630 return -1;
4631 }
4632
4633 int opt_idx;
4634 const bool is_term_opt = (len > 2 && arg[0] == 't' && arg[1] == '_');
4635 if (is_term_opt) {
4636 opt_idx = quick_tab[26];
4637 } else {
4638 opt_idx = quick_tab[CharOrdLow(arg[0])];
4639 }
4640 // Match full name
4641 for (; (s = options[opt_idx].fullname) != NULL; opt_idx++) {
4642 if (strncmp(arg, s, len) == 0 && s[len] == NUL) {
4643 break;
4644 }
4645 }
4646 if (s == NULL && !is_term_opt) {
4647 opt_idx = quick_tab[CharOrdLow(arg[0])];
4648 // Match short name
4649 for (; options[opt_idx].fullname != NULL; opt_idx++) {
4650 s = options[opt_idx].shortname;
4651 if (s != NULL && strncmp(arg, s, len) == 0 && s[len] == NUL) {
4652 break;
4653 }
4654 s = NULL;
4655 }
4656 }
4657 if (s == NULL) {
4658 opt_idx = -1;
4659 } else {
4660 // Nvim: handle option aliases.
4661 if (STRNCMP(options[opt_idx].fullname, "viminfo", 7) == 0) {
4662 if (STRLEN(options[opt_idx].fullname) == 7) {
4663 return findoption_len("shada", 5);
4664 }
4665 assert(STRCMP(options[opt_idx].fullname, "viminfofile") == 0);
4666 return findoption_len("shadafile", 9);
4667 }
4668 }
4669 return opt_idx;
4670}
4671
4672bool is_tty_option(const char *name)
4673 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
4674{
4675 return (name[0] == 't' && name[1] == '_')
4676 || strequal(name, "term")
4677 || strequal(name, "ttytype");
4678}
4679
4680#define TCO_BUFFER_SIZE 8
4681/// @param name TUI-related option
4682/// @param[out,allocated] value option string value
4683bool get_tty_option(char *name, char **value)
4684{
4685 if (strequal(name, "t_Co")) {
4686 if (value) {
4687 if (t_colors <= 1) {
4688 *value = xstrdup("");
4689 } else {
4690 *value = xmalloc(TCO_BUFFER_SIZE);
4691 snprintf(*value, TCO_BUFFER_SIZE, "%d", t_colors);
4692 }
4693 }
4694 return true;
4695 }
4696
4697 if (strequal(name, "term")) {
4698 if (value) {
4699 *value = p_term ? xstrdup(p_term) : xstrdup("nvim");
4700 }
4701 return true;
4702 }
4703
4704 if (strequal(name, "ttytype")) {
4705 if (value) {
4706 *value = p_ttytype ? xstrdup(p_ttytype) : xstrdup("nvim");
4707 }
4708 return true;
4709 }
4710
4711 if (is_tty_option(name)) {
4712 if (value) {
4713 // XXX: All other t_* options were removed in 3baba1e7.
4714 *value = xstrdup("");
4715 }
4716 return true;
4717 }
4718
4719 return false;
4720}
4721
4722bool set_tty_option(const char *name, char *value)
4723{
4724 if (strequal(name, "term")) {
4725 if (p_term) {
4726 xfree(p_term);
4727 }
4728 p_term = value;
4729 return true;
4730 }
4731
4732 if (strequal(name, "ttytype")) {
4733 if (p_ttytype) {
4734 xfree(p_ttytype);
4735 }
4736 p_ttytype = value;
4737 return true;
4738 }
4739
4740 return false;
4741}
4742
4743/// Find index for an option
4744///
4745/// @param[in] arg Option name.
4746///
4747/// @return Option index or -1 if option was not found.
4748static int findoption(const char *const arg)
4749{
4750 return findoption_len(arg, strlen(arg));
4751}
4752
4753/// Gets the value for an option.
4754///
4755/// @returns:
4756/// Number or Toggle option: 1, *numval gets value.
4757/// String option: 0, *stringval gets allocated string.
4758/// Hidden Number or Toggle option: -1.
4759/// hidden String option: -2.
4760/// unknown option: -3.
4761int get_option_value(
4762 char_u *name,
4763 long *numval,
4764 char_u **stringval, ///< NULL when only checking existence
4765 int opt_flags
4766)
4767{
4768 if (get_tty_option((char *)name, (char **)stringval)) {
4769 return 0;
4770 }
4771
4772 int opt_idx = findoption((const char *)name);
4773 if (opt_idx < 0) { // Unknown option.
4774 return -3;
4775 }
4776
4777 char_u *varp = get_varp_scope(&(options[opt_idx]), opt_flags);
4778
4779 if (options[opt_idx].flags & P_STRING) {
4780 if (varp == NULL) { // hidden option
4781 return -2;
4782 }
4783 if (stringval != NULL) {
4784 *stringval = vim_strsave(*(char_u **)(varp));
4785 }
4786 return 0;
4787 }
4788
4789 if (varp == NULL) { // hidden option
4790 return -1;
4791 }
4792 if (options[opt_idx].flags & P_NUM) {
4793 *numval = *(long *)varp;
4794 } else {
4795 // Special case: 'modified' is b_changed, but we also want to consider
4796 // it set when 'ff' or 'fenc' changed.
4797 if ((int *)varp == &curbuf->b_changed) {
4798 *numval = curbufIsChanged();
4799 } else {
4800 *numval = (long) *(int *)varp; // NOLINT(whitespace/cast)
4801 }
4802 }
4803 return 1;
4804}
4805
4806// Returns the option attributes and its value. Unlike the above function it
4807// will return either global value or local value of the option depending on
4808// what was requested, but it will never return global value if it was
4809// requested to return local one and vice versa. Neither it will return
4810// buffer-local value if it was requested to return window-local one.
4811//
4812// Pretends that option is absent if it is not present in the requested scope
4813// (i.e. has no global, window-local or buffer-local value depending on
4814// opt_type).
4815//
4816// Returned flags:
4817// 0 hidden or unknown option, also option that does not have requested
4818// type (see SREQ_* in option_defs.h)
4819// see SOPT_* in option_defs.h for other flags
4820//
4821// Possible opt_type values: see SREQ_* in option_defs.h
4822int get_option_value_strict(char *name,
4823 int64_t *numval,
4824 char **stringval,
4825 int opt_type,
4826 void *from)
4827{
4828 if (get_tty_option(name, stringval)) {
4829 return SOPT_STRING | SOPT_GLOBAL;
4830 }
4831
4832 char_u *varp = NULL;
4833 int rv = 0;
4834 int opt_idx = findoption(name);
4835 if (opt_idx < 0) {
4836 return 0;
4837 }
4838
4839 vimoption_T *p = &options[opt_idx];
4840
4841 // Hidden option
4842 if (p->var == NULL) {
4843 return 0;
4844 }
4845
4846 if (p->flags & P_BOOL) {
4847 rv |= SOPT_BOOL;
4848 } else if (p->flags & P_NUM) {
4849 rv |= SOPT_NUM;
4850 } else if (p->flags & P_STRING) {
4851 rv |= SOPT_STRING;
4852 }
4853
4854 if (p->indir == PV_NONE) {
4855 if (opt_type == SREQ_GLOBAL) {
4856 rv |= SOPT_GLOBAL;
4857 } else {
4858 return 0; // Did not request global-only option
4859 }
4860 } else {
4861 if (p->indir & PV_BOTH) {
4862 rv |= SOPT_GLOBAL;
4863 }
4864
4865 if (p->indir & PV_WIN) {
4866 if (opt_type == SREQ_BUF) {
4867 return 0; // Requested buffer-local, not window-local option
4868 } else {
4869 rv |= SOPT_WIN;
4870 }
4871 } else if (p->indir & PV_BUF) {
4872 if (opt_type == SREQ_WIN) {
4873 return 0; // Requested window-local, not buffer-local option
4874 } else {
4875 rv |= SOPT_BUF;
4876 }
4877 }
4878 }
4879
4880 if (stringval == NULL) {
4881 return rv;
4882 }
4883
4884 if (opt_type == SREQ_GLOBAL) {
4885 if (p->var == VAR_WIN) {
4886 return 0;
4887 } else {
4888 varp = p->var;
4889 }
4890 } else {
4891 if (opt_type == SREQ_BUF) {
4892 // Special case: 'modified' is b_changed, but we also want to
4893 // consider it set when 'ff' or 'fenc' changed.
4894 if (p->indir == PV_MOD) {
4895 *numval = bufIsChanged((buf_T *)from);
4896 varp = NULL;
4897 } else {
4898 buf_T *save_curbuf = curbuf;
4899
4900 // only getting a pointer, no need to use aucmd_prepbuf()
4901 curbuf = (buf_T *)from;
4902 curwin->w_buffer = curbuf;
4903 varp = get_varp(p);
4904 curbuf = save_curbuf;
4905 curwin->w_buffer = curbuf;
4906 }
4907 } else if (opt_type == SREQ_WIN) {
4908 win_T *save_curwin = curwin;
4909 curwin = (win_T *)from;
4910 curbuf = curwin->w_buffer;
4911 varp = get_varp(p);
4912 curwin = save_curwin;
4913 curbuf = curwin->w_buffer;
4914 }
4915
4916 if (varp == p->var) {
4917 return (rv | SOPT_UNSET);
4918 }
4919 }
4920
4921 if (varp != NULL) {
4922 if (p->flags & P_STRING) {
4923 *stringval = xstrdup(*(char **)(varp));
4924 } else if (p->flags & P_NUM) {
4925 *numval = *(long *) varp;
4926 } else {
4927 *numval = *(int *)varp;
4928 }
4929 }
4930
4931 return rv;
4932}
4933
4934/// Set the value of an option
4935///
4936/// @param[in] name Option name.
4937/// @param[in] number New value for the number or boolean option.
4938/// @param[in] string New value for string option.
4939/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both).
4940///
4941/// @return NULL on success, error message on error.
4942char *set_option_value(const char *const name, const long number,
4943 const char *const string, const int opt_flags)
4944 FUNC_ATTR_NONNULL_ARG(1)
4945{
4946 if (is_tty_option(name)) {
4947 return NULL; // Fail silently; many old vimrcs set t_xx options.
4948 }
4949
4950 int opt_idx;
4951 char_u *varp;
4952
4953 opt_idx = findoption(name);
4954 if (opt_idx < 0) {
4955 EMSG2(_("E355: Unknown option: %s"), name);
4956 } else {
4957 uint32_t flags = options[opt_idx].flags;
4958 // Disallow changing some options in the sandbox
4959 if (sandbox > 0 && (flags & P_SECURE)) {
4960 EMSG(_(e_sandbox));
4961 return NULL;
4962 }
4963 if (flags & P_STRING) {
4964 const char *s = string;
4965 if (s == NULL) {
4966 s = "";
4967 }
4968 return set_string_option(opt_idx, s, opt_flags);
4969 } else {
4970 varp = get_varp_scope(&(options[opt_idx]), opt_flags);
4971 if (varp != NULL) { // hidden option is not changed
4972 if (number == 0 && string != NULL) {
4973 int idx;
4974
4975 // Either we are given a string or we are setting option
4976 // to zero.
4977 for (idx = 0; string[idx] == '0'; idx++) {}
4978 if (string[idx] != NUL || idx == 0) {
4979 // There's another character after zeros or the string
4980 // is empty. In both cases, we are trying to set a
4981 // num option using a string.
4982 EMSG3(_("E521: Number required: &%s = '%s'"),
4983 name, string);
4984 return NULL; // do nothing as we hit an error
4985 }
4986 }
4987 if (flags & P_NUM) {
4988 return set_num_option(opt_idx, varp, number, NULL, 0, opt_flags);
4989 } else {
4990 return set_bool_option(opt_idx, varp, (int)number, opt_flags);
4991 }
4992 }
4993 }
4994 }
4995 return NULL;
4996}
4997
4998// Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number.
4999// When "has_lt" is true there is a '<' before "*arg_arg".
5000// Returns 0 when the key is not recognized.
5001int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt)
5002{
5003 int key = 0;
5004 int modifiers;
5005 const char_u *arg = arg_arg;
5006
5007 // Don't use get_special_key_code() for t_xx, we don't want it to call
5008 // add_termcap_entry().
5009 if (len >= 4 && arg[0] == 't' && arg[1] == '_') {
5010 key = TERMCAP2KEY(arg[2], arg[3]);
5011 } else if (has_lt) {
5012 arg--; // put arg at the '<'
5013 modifiers = 0;
5014 key = find_special_key(&arg, len + 1, &modifiers, true, true, false);
5015 if (modifiers) { // can't handle modifiers here
5016 key = 0;
5017 }
5018 }
5019 return key;
5020}
5021
5022static int find_key_option(const char_u *arg, bool has_lt)
5023{
5024 return find_key_option_len(arg, STRLEN(arg), has_lt);
5025}
5026
5027/*
5028 * if 'all' == 0: show changed options
5029 * if 'all' == 1: show all normal options
5030 */
5031static void
5032showoptions(
5033 int all,
5034 int opt_flags // OPT_LOCAL and/or OPT_GLOBAL
5035)
5036{
5037 vimoption_T *p;
5038 int col;
5039 char_u *varp;
5040 int item_count;
5041 int run;
5042 int row, rows;
5043 int cols;
5044 int i;
5045 int len;
5046
5047#define INC 20
5048#define GAP 3
5049
5050 vimoption_T **items = xmalloc(sizeof(vimoption_T *) * PARAM_COUNT);
5051
5052 // Highlight title
5053 if (opt_flags & OPT_GLOBAL) {
5054 MSG_PUTS_TITLE(_("\n--- Global option values ---"));
5055 } else if (opt_flags & OPT_LOCAL) {
5056 MSG_PUTS_TITLE(_("\n--- Local option values ---"));
5057 } else {
5058 MSG_PUTS_TITLE(_("\n--- Options ---"));
5059 }
5060
5061 // Do the loop two times:
5062 // 1. display the short items
5063 // 2. display the long items (only strings and numbers)
5064 for (run = 1; run <= 2 && !got_int; run++) {
5065 // collect the items in items[]
5066 item_count = 0;
5067 for (p = &options[0]; p->fullname != NULL; p++) {
5068 // apply :filter /pat/
5069 if (message_filtered((char_u *)p->fullname)) {
5070 continue;
5071 }
5072
5073 varp = NULL;
5074 if (opt_flags != 0) {
5075 if (p->indir != PV_NONE) {
5076 varp = get_varp_scope(p, opt_flags);
5077 }
5078 } else {
5079 varp = get_varp(p);
5080 }
5081 if (varp != NULL
5082 && (all == 1 || (all == 0 && !optval_default(p, varp)))) {
5083 if (p->flags & P_BOOL) {
5084 len = 1; // a toggle option fits always
5085 } else {
5086 option_value2string(p, opt_flags);
5087 len = (int)STRLEN(p->fullname) + vim_strsize(NameBuff) + 1;
5088 }
5089 if ((len <= INC - GAP && run == 1)
5090 || (len > INC - GAP && run == 2)) {
5091 items[item_count++] = p;
5092 }
5093 }
5094 }
5095
5096 /*
5097 * display the items
5098 */
5099 if (run == 1) {
5100 assert(Columns <= INT_MAX - GAP
5101 && Columns + GAP >= INT_MIN + 3
5102 && (Columns + GAP - 3) / INC >= INT_MIN
5103 && (Columns + GAP - 3) / INC <= INT_MAX);
5104 cols = (int)((Columns + GAP - 3) / INC);
5105 if (cols == 0) {
5106 cols = 1;
5107 }
5108 rows = (item_count + cols - 1) / cols;
5109 } else { // run == 2
5110 rows = item_count;
5111 }
5112 for (row = 0; row < rows && !got_int; row++) {
5113 msg_putchar('\n'); // go to next line
5114 if (got_int) { // 'q' typed in more
5115 break;
5116 }
5117 col = 0;
5118 for (i = row; i < item_count; i += rows) {
5119 msg_col = col; // make columns
5120 showoneopt(items[i], opt_flags);
5121 col += INC;
5122 }
5123 ui_flush();
5124 os_breakcheck();
5125 }
5126 }
5127 xfree(items);
5128}
5129
5130/// Return true if option "p" has its default value.
5131static int optval_default(vimoption_T *p, char_u *varp)
5132{
5133 int dvi;
5134
5135 if (varp == NULL) {
5136 return true; // hidden option is always at default
5137 }
5138 dvi = ((p->flags & P_VI_DEF) || p_cp) ? VI_DEFAULT : VIM_DEFAULT;
5139 if (p->flags & P_NUM) {
5140 return *(long *)varp == (long)(intptr_t)p->def_val[dvi];
5141 }
5142 if (p->flags & P_BOOL) {
5143 return *(int *)varp == (int)(intptr_t)p->def_val[dvi];
5144 }
5145 // P_STRING
5146 return STRCMP(*(char_u **)varp, p->def_val[dvi]) == 0;
5147}
5148
5149/// Send update to UIs with values of UI relevant options
5150void ui_refresh_options(void)
5151{
5152 for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) {
5153 uint32_t flags = options[opt_idx].flags;
5154 if (!(flags & P_UI_OPTION)) {
5155 continue;
5156 }
5157 String name = cstr_as_string(options[opt_idx].fullname);
5158 void *varp = options[opt_idx].var;
5159 Object value = OBJECT_INIT;
5160 if (flags & P_BOOL) {
5161 value = BOOLEAN_OBJ(*(int *)varp);
5162 } else if (flags & P_NUM) {
5163 value = INTEGER_OBJ(*(long *)varp);
5164 } else if (flags & P_STRING) {
5165 // cstr_as_string handles NULL string
5166 value = STRING_OBJ(cstr_as_string(*(char **)varp));
5167 }
5168 ui_call_option_set(name, value);
5169 }
5170}
5171
5172/*
5173 * showoneopt: show the value of one option
5174 * must not be called with a hidden option!
5175 */
5176static void
5177showoneopt(
5178 vimoption_T *p,
5179 int opt_flags // OPT_LOCAL or OPT_GLOBAL
5180)
5181{
5182 char_u *varp;
5183 int save_silent = silent_mode;
5184
5185 silent_mode = false;
5186 info_message = true; // use mch_msg(), not mch_errmsg()
5187
5188 varp = get_varp_scope(p, opt_flags);
5189
5190 // for 'modified' we also need to check if 'ff' or 'fenc' changed.
5191 if ((p->flags & P_BOOL) && ((int *)varp == &curbuf->b_changed
5192 ? !curbufIsChanged() : !*(int *)varp)) {
5193 MSG_PUTS("no");
5194 } else if ((p->flags & P_BOOL) && *(int *)varp < 0) {
5195 MSG_PUTS("--");
5196 } else {
5197 MSG_PUTS(" ");
5198 }
5199 MSG_PUTS(p->fullname);
5200 if (!(p->flags & P_BOOL)) {
5201 msg_putchar('=');
5202 // put value string in NameBuff
5203 option_value2string(p, opt_flags);
5204 msg_outtrans(NameBuff);
5205 }
5206
5207 silent_mode = save_silent;
5208 info_message = false;
5209}
5210
5211/*
5212 * Write modified options as ":set" commands to a file.
5213 *
5214 * There are three values for "opt_flags":
5215 * OPT_GLOBAL: Write global option values and fresh values of
5216 * buffer-local options (used for start of a session
5217 * file).
5218 * OPT_GLOBAL + OPT_LOCAL: Idem, add fresh values of window-local options for
5219 * curwin (used for a vimrc file).
5220 * OPT_LOCAL: Write buffer-local option values for curbuf, fresh
5221 * and local values for window-local options of
5222 * curwin. Local values are also written when at the
5223 * default value, because a modeline or autocommand
5224 * may have set them when doing ":edit file" and the
5225 * user has set them back at the default or fresh
5226 * value.
5227 * When "local_only" is true, don't write fresh
5228 * values, only local values (for ":mkview").
5229 * (fresh value = value used for a new buffer or window for a local option).
5230 *
5231 * Return FAIL on error, OK otherwise.
5232 */
5233int makeset(FILE *fd, int opt_flags, int local_only)
5234{
5235 vimoption_T *p;
5236 char_u *varp; // currently used value
5237 char_u *varp_fresh; // local value
5238 char_u *varp_local = NULL; // fresh value
5239 char *cmd;
5240 int round;
5241 int pri;
5242
5243 /*
5244 * Some options are never written:
5245 * - Options that don't have a default (terminal name, columns, lines).
5246 * - Terminal options.
5247 * - Hidden options.
5248 *
5249 * Do the loop over "options[]" twice: once for options with the
5250 * P_PRI_MKRC flag and once without.
5251 */
5252 for (pri = 1; pri >= 0; pri--) {
5253 for (p = &options[0]; p->fullname; p++) {
5254 if (!(p->flags & P_NO_MKRC)
5255 && ((pri == 1) == ((p->flags & P_PRI_MKRC) != 0))) {
5256 // skip global option when only doing locals
5257 if (p->indir == PV_NONE && !(opt_flags & OPT_GLOBAL)) {
5258 continue;
5259 }
5260
5261 /* Do not store options like 'bufhidden' and 'syntax' in a vimrc
5262 * file, they are always buffer-specific. */
5263 if ((opt_flags & OPT_GLOBAL) && (p->flags & P_NOGLOB)) {
5264 continue;
5265 }
5266
5267 varp = get_varp_scope(p, opt_flags);
5268 // Hidden options are never written.
5269 if (!varp) {
5270 continue;
5271 }
5272 // Global values are only written when not at the default value.
5273 if ((opt_flags & OPT_GLOBAL) && optval_default(p, varp)) {
5274 continue;
5275 }
5276
5277 round = 2;
5278 if (p->indir != PV_NONE) {
5279 if (p->var == VAR_WIN) {
5280 // skip window-local option when only doing globals
5281 if (!(opt_flags & OPT_LOCAL)) {
5282 continue;
5283 }
5284 // When fresh value of window-local option is not at the
5285 // default, need to write it too.
5286 if (!(opt_flags & OPT_GLOBAL) && !local_only) {
5287 varp_fresh = get_varp_scope(p, OPT_GLOBAL);
5288 if (!optval_default(p, varp_fresh)) {
5289 round = 1;
5290 varp_local = varp;
5291 varp = varp_fresh;
5292 }
5293 }
5294 }
5295 }
5296
5297 /* Round 1: fresh value for window-local options.
5298 * Round 2: other values */
5299 for (; round <= 2; varp = varp_local, round++) {
5300 if (round == 1 || (opt_flags & OPT_GLOBAL)) {
5301 cmd = "set";
5302 } else {
5303 cmd = "setlocal";
5304 }
5305
5306 if (p->flags & P_BOOL) {
5307 if (put_setbool(fd, cmd, p->fullname, *(int *)varp) == FAIL) {
5308 return FAIL;
5309 }
5310 } else if (p->flags & P_NUM) {
5311 if (put_setnum(fd, cmd, p->fullname, (long *)varp) == FAIL) {
5312 return FAIL;
5313 }
5314 } else { // P_STRING
5315 int do_endif = false;
5316
5317 // Don't set 'syntax' and 'filetype' again if the value is
5318 // already right, avoids reloading the syntax file.
5319 if (p->indir == PV_SYN || p->indir == PV_FT) {
5320 if (fprintf(fd, "if &%s != '%s'", p->fullname,
5321 *(char_u **)(varp)) < 0
5322 || put_eol(fd) < 0) {
5323 return FAIL;
5324 }
5325 do_endif = true;
5326 }
5327 if (put_setstring(fd, cmd, p->fullname, (char_u **)varp,
5328 (p->flags & P_EXPAND) != 0) == FAIL)
5329 return FAIL;
5330 if (do_endif) {
5331 if (put_line(fd, "endif") == FAIL) {
5332 return FAIL;
5333 }
5334 }
5335 }
5336 }
5337 }
5338 }
5339 }
5340 return OK;
5341}
5342
5343/*
5344 * Generate set commands for the local fold options only. Used when
5345 * 'sessionoptions' or 'viewoptions' contains "folds" but not "options".
5346 */
5347int makefoldset(FILE *fd)
5348{
5349 if (put_setstring(fd, "setlocal", "fdm", &curwin->w_p_fdm, false) == FAIL
5350 || put_setstring(fd, "setlocal", "fde", &curwin->w_p_fde, false)
5351 == FAIL
5352 || put_setstring(fd, "setlocal", "fmr", &curwin->w_p_fmr, false)
5353 == FAIL
5354 || put_setstring(fd, "setlocal", "fdi", &curwin->w_p_fdi, false)
5355 == FAIL
5356 || put_setnum(fd, "setlocal", "fdl", &curwin->w_p_fdl) == FAIL
5357 || put_setnum(fd, "setlocal", "fml", &curwin->w_p_fml) == FAIL
5358 || put_setnum(fd, "setlocal", "fdn", &curwin->w_p_fdn) == FAIL
5359 || put_setbool(fd, "setlocal", "fen", curwin->w_p_fen) == FAIL
5360 ) {
5361 return FAIL;
5362 }
5363
5364 return OK;
5365}
5366
5367static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, int expand)
5368{
5369 char_u *s;
5370 char_u *buf;
5371
5372 if (fprintf(fd, "%s %s=", cmd, name) < 0) {
5373 return FAIL;
5374 }
5375 if (*valuep != NULL) {
5376 /* Output 'pastetoggle' as key names. For other
5377 * options some characters have to be escaped with
5378 * CTRL-V or backslash */
5379 if (valuep == &p_pt) {
5380 s = *valuep;
5381 while (*s != NUL) {
5382 if (put_escstr(fd, (char_u *)str2special((const char **)&s, false,
5383 false), 2)
5384 == FAIL) {
5385 return FAIL;
5386 }
5387 }
5388 } else if (expand) {
5389 buf = xmalloc(MAXPATHL);
5390 home_replace(NULL, *valuep, buf, MAXPATHL, false);
5391 if (put_escstr(fd, buf, 2) == FAIL) {
5392 xfree(buf);
5393 return FAIL;
5394 }
5395 xfree(buf);
5396 } else if (put_escstr(fd, *valuep, 2) == FAIL) {
5397 return FAIL;
5398 }
5399 }
5400 if (put_eol(fd) < 0) {
5401 return FAIL;
5402 }
5403 return OK;
5404}
5405
5406static int put_setnum(FILE *fd, char *cmd, char *name, long *valuep)
5407{
5408 long wc;
5409
5410 if (fprintf(fd, "%s %s=", cmd, name) < 0) {
5411 return FAIL;
5412 }
5413 if (wc_use_keyname((char_u *)valuep, &wc)) {
5414 // print 'wildchar' and 'wildcharm' as a key name
5415 if (fputs((char *)get_special_key_name((int)wc, 0), fd) < 0) {
5416 return FAIL;
5417 }
5418 } else if (fprintf(fd, "%" PRId64, (int64_t)(*valuep)) < 0) {
5419 return FAIL;
5420 }
5421 if (put_eol(fd) < 0) {
5422 return FAIL;
5423 }
5424 return OK;
5425}
5426
5427static int put_setbool(FILE *fd, char *cmd, char *name, int value)
5428{
5429 if (value < 0) { // global/local option using global value
5430 return OK;
5431 }
5432 if (fprintf(fd, "%s %s%s", cmd, value ? "" : "no", name) < 0
5433 || put_eol(fd) < 0) {
5434 return FAIL;
5435 }
5436 return OK;
5437}
5438
5439/*
5440 * Compute columns for ruler and shown command. 'sc_col' is also used to
5441 * decide what the maximum length of a message on the status line can be.
5442 * If there is a status line for the last window, 'sc_col' is independent
5443 * of 'ru_col'.
5444 */
5445
5446#define COL_RULER 17 // columns needed by standard ruler
5447
5448void comp_col(void)
5449{
5450 int last_has_status = (p_ls == 2 || (p_ls == 1 && !ONE_WINDOW));
5451
5452 sc_col = 0;
5453 ru_col = 0;
5454 if (p_ru) {
5455 ru_col = (ru_wid ? ru_wid : COL_RULER) + 1;
5456 // no last status line, adjust sc_col
5457 if (!last_has_status) {
5458 sc_col = ru_col;
5459 }
5460 }
5461 if (p_sc) {
5462 sc_col += SHOWCMD_COLS;
5463 if (!p_ru || last_has_status) { // no need for separating space
5464 sc_col++;
5465 }
5466 }
5467 assert(sc_col >= 0
5468 && INT_MIN + sc_col <= Columns
5469 && Columns - sc_col <= INT_MAX);
5470 sc_col = (int)(Columns - sc_col);
5471 assert(ru_col >= 0
5472 && INT_MIN + ru_col <= Columns
5473 && Columns - ru_col <= INT_MAX);
5474 ru_col = (int)(Columns - ru_col);
5475 if (sc_col <= 0) { // screen too narrow, will become a mess
5476 sc_col = 1;
5477 }
5478 if (ru_col <= 0) {
5479 ru_col = 1;
5480 }
5481 set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
5482}
5483
5484// Unset local option value, similar to ":set opt<".
5485void unset_global_local_option(char *name, void *from)
5486{
5487 vimoption_T *p;
5488 buf_T *buf = (buf_T *)from;
5489
5490 int opt_idx = findoption(name);
5491 if (opt_idx < 0) {
5492 EMSG2(_("E355: Unknown option: %s"), name);
5493 return;
5494 }
5495 p = &(options[opt_idx]);
5496
5497 switch ((int)p->indir)
5498 {
5499 // global option with local value: use local value if it's been set
5500 case PV_EP:
5501 clear_string_option(&buf->b_p_ep);
5502 break;
5503 case PV_KP:
5504 clear_string_option(&buf->b_p_kp);
5505 break;
5506 case PV_PATH:
5507 clear_string_option(&buf->b_p_path);
5508 break;
5509 case PV_AR:
5510 buf->b_p_ar = -1;
5511 break;
5512 case PV_BKC:
5513 clear_string_option(&buf->b_p_bkc);
5514 buf->b_bkc_flags = 0;
5515 break;
5516 case PV_TAGS:
5517 clear_string_option(&buf->b_p_tags);
5518 break;
5519 case PV_TC:
5520 clear_string_option(&buf->b_p_tc);
5521 buf->b_tc_flags = 0;
5522 break;
5523 case PV_DEF:
5524 clear_string_option(&buf->b_p_def);
5525 break;
5526 case PV_INC:
5527 clear_string_option(&buf->b_p_inc);
5528 break;
5529 case PV_DICT:
5530 clear_string_option(&buf->b_p_dict);
5531 break;
5532 case PV_TSR:
5533 clear_string_option(&buf->b_p_tsr);
5534 break;
5535 case PV_FP:
5536 clear_string_option(&buf->b_p_fp);
5537 break;
5538 case PV_EFM:
5539 clear_string_option(&buf->b_p_efm);
5540 break;
5541 case PV_GP:
5542 clear_string_option(&buf->b_p_gp);
5543 break;
5544 case PV_MP:
5545 clear_string_option(&buf->b_p_mp);
5546 break;
5547 case PV_STL:
5548 clear_string_option(&((win_T *)from)->w_p_stl);
5549 break;
5550 case PV_UL:
5551 buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
5552 break;
5553 case PV_LW:
5554 clear_string_option(&buf->b_p_lw);
5555 break;
5556 case PV_MENC:
5557 clear_string_option(&buf->b_p_menc);
5558 break;
5559 }
5560}
5561
5562/*
5563 * Get pointer to option variable, depending on local or global scope.
5564 */
5565static char_u *get_varp_scope(vimoption_T *p, int opt_flags)
5566{
5567 if ((opt_flags & OPT_GLOBAL) && p->indir != PV_NONE) {
5568 if (p->var == VAR_WIN) {
5569 return (char_u *)GLOBAL_WO(get_varp(p));
5570 }
5571 return p->var;
5572 }
5573 if ((opt_flags & OPT_LOCAL) && ((int)p->indir & PV_BOTH)) {
5574 switch ((int)p->indir) {
5575 case PV_FP: return (char_u *)&(curbuf->b_p_fp);
5576 case PV_EFM: return (char_u *)&(curbuf->b_p_efm);
5577 case PV_GP: return (char_u *)&(curbuf->b_p_gp);
5578 case PV_MP: return (char_u *)&(curbuf->b_p_mp);
5579 case PV_EP: return (char_u *)&(curbuf->b_p_ep);
5580 case PV_KP: return (char_u *)&(curbuf->b_p_kp);
5581 case PV_PATH: return (char_u *)&(curbuf->b_p_path);
5582 case PV_AR: return (char_u *)&(curbuf->b_p_ar);
5583 case PV_TAGS: return (char_u *)&(curbuf->b_p_tags);
5584 case PV_TC: return (char_u *)&(curbuf->b_p_tc);
5585 case PV_DEF: return (char_u *)&(curbuf->b_p_def);
5586 case PV_INC: return (char_u *)&(curbuf->b_p_inc);
5587 case PV_DICT: return (char_u *)&(curbuf->b_p_dict);
5588 case PV_TSR: return (char_u *)&(curbuf->b_p_tsr);
5589 case PV_STL: return (char_u *)&(curwin->w_p_stl);
5590 case PV_UL: return (char_u *)&(curbuf->b_p_ul);
5591 case PV_LW: return (char_u *)&(curbuf->b_p_lw);
5592 case PV_BKC: return (char_u *)&(curbuf->b_p_bkc);
5593 case PV_MENC: return (char_u *)&(curbuf->b_p_menc);
5594 }
5595 return NULL; // "cannot happen"
5596 }
5597 return get_varp(p);
5598}
5599
5600/*
5601 * Get pointer to option variable.
5602 */
5603static char_u *get_varp(vimoption_T *p)
5604{
5605 // hidden option, always return NULL
5606 if (p->var == NULL) {
5607 return NULL;
5608 }
5609
5610 switch ((int)p->indir) {
5611 case PV_NONE: return p->var;
5612
5613 // global option with local value: use local value if it's been set
5614 case PV_EP: return *curbuf->b_p_ep != NUL
5615 ? (char_u *)&curbuf->b_p_ep : p->var;
5616 case PV_KP: return *curbuf->b_p_kp != NUL
5617 ? (char_u *)&curbuf->b_p_kp : p->var;
5618 case PV_PATH: return *curbuf->b_p_path != NUL
5619 ? (char_u *)&(curbuf->b_p_path) : p->var;
5620 case PV_AR: return curbuf->b_p_ar >= 0
5621 ? (char_u *)&(curbuf->b_p_ar) : p->var;
5622 case PV_TAGS: return *curbuf->b_p_tags != NUL
5623 ? (char_u *)&(curbuf->b_p_tags) : p->var;
5624 case PV_TC: return *curbuf->b_p_tc != NUL
5625 ? (char_u *)&(curbuf->b_p_tc) : p->var;
5626 case PV_BKC: return *curbuf->b_p_bkc != NUL
5627 ? (char_u *)&(curbuf->b_p_bkc) : p->var;
5628 case PV_DEF: return *curbuf->b_p_def != NUL
5629 ? (char_u *)&(curbuf->b_p_def) : p->var;
5630 case PV_INC: return *curbuf->b_p_inc != NUL
5631 ? (char_u *)&(curbuf->b_p_inc) : p->var;
5632 case PV_DICT: return *curbuf->b_p_dict != NUL
5633 ? (char_u *)&(curbuf->b_p_dict) : p->var;
5634 case PV_TSR: return *curbuf->b_p_tsr != NUL
5635 ? (char_u *)&(curbuf->b_p_tsr) : p->var;
5636 case PV_FP: return *curbuf->b_p_fp != NUL
5637 ? (char_u *)&(curbuf->b_p_fp) : p->var;
5638 case PV_EFM: return *curbuf->b_p_efm != NUL
5639 ? (char_u *)&(curbuf->b_p_efm) : p->var;
5640 case PV_GP: return *curbuf->b_p_gp != NUL
5641 ? (char_u *)&(curbuf->b_p_gp) : p->var;
5642 case PV_MP: return *curbuf->b_p_mp != NUL
5643 ? (char_u *)&(curbuf->b_p_mp) : p->var;
5644 case PV_STL: return *curwin->w_p_stl != NUL
5645 ? (char_u *)&(curwin->w_p_stl) : p->var;
5646 case PV_UL: return curbuf->b_p_ul != NO_LOCAL_UNDOLEVEL
5647 ? (char_u *)&(curbuf->b_p_ul) : p->var;
5648 case PV_LW: return *curbuf->b_p_lw != NUL
5649 ? (char_u *)&(curbuf->b_p_lw) : p->var;
5650 case PV_MENC: return *curbuf->b_p_menc != NUL
5651 ? (char_u *)&(curbuf->b_p_menc) : p->var;
5652
5653 case PV_ARAB: return (char_u *)&(curwin->w_p_arab);
5654 case PV_LIST: return (char_u *)&(curwin->w_p_list);
5655 case PV_SPELL: return (char_u *)&(curwin->w_p_spell);
5656 case PV_CUC: return (char_u *)&(curwin->w_p_cuc);
5657 case PV_CUL: return (char_u *)&(curwin->w_p_cul);
5658 case PV_CC: return (char_u *)&(curwin->w_p_cc);
5659 case PV_DIFF: return (char_u *)&(curwin->w_p_diff);
5660 case PV_FDC: return (char_u *)&(curwin->w_p_fdc);
5661 case PV_FEN: return (char_u *)&(curwin->w_p_fen);
5662 case PV_FDI: return (char_u *)&(curwin->w_p_fdi);
5663 case PV_FDL: return (char_u *)&(curwin->w_p_fdl);
5664 case PV_FDM: return (char_u *)&(curwin->w_p_fdm);
5665 case PV_FML: return (char_u *)&(curwin->w_p_fml);
5666 case PV_FDN: return (char_u *)&(curwin->w_p_fdn);
5667 case PV_FDE: return (char_u *)&(curwin->w_p_fde);
5668 case PV_FDT: return (char_u *)&(curwin->w_p_fdt);
5669 case PV_FMR: return (char_u *)&(curwin->w_p_fmr);
5670 case PV_NU: return (char_u *)&(curwin->w_p_nu);
5671 case PV_RNU: return (char_u *)&(curwin->w_p_rnu);
5672 case PV_NUW: return (char_u *)&(curwin->w_p_nuw);
5673 case PV_WFH: return (char_u *)&(curwin->w_p_wfh);
5674 case PV_WFW: return (char_u *)&(curwin->w_p_wfw);
5675 case PV_PVW: return (char_u *)&(curwin->w_p_pvw);
5676 case PV_RL: return (char_u *)&(curwin->w_p_rl);
5677 case PV_RLC: return (char_u *)&(curwin->w_p_rlc);
5678 case PV_SCROLL: return (char_u *)&(curwin->w_p_scr);
5679 case PV_WRAP: return (char_u *)&(curwin->w_p_wrap);
5680 case PV_LBR: return (char_u *)&(curwin->w_p_lbr);
5681 case PV_BRI: return (char_u *)&(curwin->w_p_bri);
5682 case PV_BRIOPT: return (char_u *)&(curwin->w_p_briopt);
5683 case PV_SCBIND: return (char_u *)&(curwin->w_p_scb);
5684 case PV_CRBIND: return (char_u *)&(curwin->w_p_crb);
5685 case PV_COCU: return (char_u *)&(curwin->w_p_cocu);
5686 case PV_COLE: return (char_u *)&(curwin->w_p_cole);
5687
5688 case PV_AI: return (char_u *)&(curbuf->b_p_ai);
5689 case PV_BIN: return (char_u *)&(curbuf->b_p_bin);
5690 case PV_BOMB: return (char_u *)&(curbuf->b_p_bomb);
5691 case PV_BH: return (char_u *)&(curbuf->b_p_bh);
5692 case PV_BT: return (char_u *)&(curbuf->b_p_bt);
5693 case PV_BL: return (char_u *)&(curbuf->b_p_bl);
5694 case PV_CHANNEL:return (char_u *)&(curbuf->b_p_channel);
5695 case PV_CI: return (char_u *)&(curbuf->b_p_ci);
5696 case PV_CIN: return (char_u *)&(curbuf->b_p_cin);
5697 case PV_CINK: return (char_u *)&(curbuf->b_p_cink);
5698 case PV_CINO: return (char_u *)&(curbuf->b_p_cino);
5699 case PV_CINW: return (char_u *)&(curbuf->b_p_cinw);
5700 case PV_COM: return (char_u *)&(curbuf->b_p_com);
5701 case PV_CMS: return (char_u *)&(curbuf->b_p_cms);
5702 case PV_CPT: return (char_u *)&(curbuf->b_p_cpt);
5703 case PV_CFU: return (char_u *)&(curbuf->b_p_cfu);
5704 case PV_OFU: return (char_u *)&(curbuf->b_p_ofu);
5705 case PV_EOL: return (char_u *)&(curbuf->b_p_eol);
5706 case PV_FIXEOL: return (char_u *)&(curbuf->b_p_fixeol);
5707 case PV_ET: return (char_u *)&(curbuf->b_p_et);
5708 case PV_FENC: return (char_u *)&(curbuf->b_p_fenc);
5709 case PV_FF: return (char_u *)&(curbuf->b_p_ff);
5710 case PV_FT: return (char_u *)&(curbuf->b_p_ft);
5711 case PV_FO: return (char_u *)&(curbuf->b_p_fo);
5712 case PV_FLP: return (char_u *)&(curbuf->b_p_flp);
5713 case PV_IMI: return (char_u *)&(curbuf->b_p_iminsert);
5714 case PV_IMS: return (char_u *)&(curbuf->b_p_imsearch);
5715 case PV_INF: return (char_u *)&(curbuf->b_p_inf);
5716 case PV_ISK: return (char_u *)&(curbuf->b_p_isk);
5717 case PV_INEX: return (char_u *)&(curbuf->b_p_inex);
5718 case PV_INDE: return (char_u *)&(curbuf->b_p_inde);
5719 case PV_INDK: return (char_u *)&(curbuf->b_p_indk);
5720 case PV_FEX: return (char_u *)&(curbuf->b_p_fex);
5721 case PV_LISP: return (char_u *)&(curbuf->b_p_lisp);
5722 case PV_ML: return (char_u *)&(curbuf->b_p_ml);
5723 case PV_MPS: return (char_u *)&(curbuf->b_p_mps);
5724 case PV_MA: return (char_u *)&(curbuf->b_p_ma);
5725 case PV_MOD: return (char_u *)&(curbuf->b_changed);
5726 case PV_NF: return (char_u *)&(curbuf->b_p_nf);
5727 case PV_PI: return (char_u *)&(curbuf->b_p_pi);
5728 case PV_QE: return (char_u *)&(curbuf->b_p_qe);
5729 case PV_RO: return (char_u *)&(curbuf->b_p_ro);
5730 case PV_SCBK: return (char_u *)&(curbuf->b_p_scbk);
5731 case PV_SI: return (char_u *)&(curbuf->b_p_si);
5732 case PV_STS: return (char_u *)&(curbuf->b_p_sts);
5733 case PV_SUA: return (char_u *)&(curbuf->b_p_sua);
5734 case PV_SWF: return (char_u *)&(curbuf->b_p_swf);
5735 case PV_SMC: return (char_u *)&(curbuf->b_p_smc);
5736 case PV_SYN: return (char_u *)&(curbuf->b_p_syn);
5737 case PV_SPC: return (char_u *)&(curwin->w_s->b_p_spc);
5738 case PV_SPF: return (char_u *)&(curwin->w_s->b_p_spf);
5739 case PV_SPL: return (char_u *)&(curwin->w_s->b_p_spl);
5740 case PV_SW: return (char_u *)&(curbuf->b_p_sw);
5741 case PV_TS: return (char_u *)&(curbuf->b_p_ts);
5742 case PV_TW: return (char_u *)&(curbuf->b_p_tw);
5743 case PV_UDF: return (char_u *)&(curbuf->b_p_udf);
5744 case PV_WM: return (char_u *)&(curbuf->b_p_wm);
5745 case PV_KMAP: return (char_u *)&(curbuf->b_p_keymap);
5746 case PV_SCL: return (char_u *)&(curwin->w_p_scl);
5747 case PV_WINHL: return (char_u *)&(curwin->w_p_winhl);
5748 case PV_FCS: return (char_u *)&(curwin->w_p_fcs);
5749 case PV_LCS: return (char_u *)&(curwin->w_p_lcs);
5750 case PV_WINBL: return (char_u *)&(curwin->w_p_winbl);
5751 default: IEMSG(_("E356: get_varp ERROR"));
5752 }
5753 // always return a valid pointer to avoid a crash!
5754 return (char_u *)&(curbuf->b_p_wm);
5755}
5756
5757/*
5758 * Get the value of 'equalprg', either the buffer-local one or the global one.
5759 */
5760char_u *get_equalprg(void)
5761{
5762 if (*curbuf->b_p_ep == NUL) {
5763 return p_ep;
5764 }
5765 return curbuf->b_p_ep;
5766}
5767
5768/*
5769 * Copy options from one window to another.
5770 * Used when splitting a window.
5771 */
5772void win_copy_options(win_T *wp_from, win_T *wp_to)
5773{
5774 copy_winopt(&wp_from->w_onebuf_opt, &wp_to->w_onebuf_opt);
5775 copy_winopt(&wp_from->w_allbuf_opt, &wp_to->w_allbuf_opt);
5776}
5777
5778/*
5779 * Copy the options from one winopt_T to another.
5780 * Doesn't free the old option values in "to", use clear_winopt() for that.
5781 * The 'scroll' option is not copied, because it depends on the window height.
5782 * The 'previewwindow' option is reset, there can be only one preview window.
5783 */
5784void copy_winopt(winopt_T *from, winopt_T *to)
5785{
5786 to->wo_arab = from->wo_arab;
5787 to->wo_list = from->wo_list;
5788 to->wo_nu = from->wo_nu;
5789 to->wo_rnu = from->wo_rnu;
5790 to->wo_nuw = from->wo_nuw;
5791 to->wo_rl = from->wo_rl;
5792 to->wo_rlc = vim_strsave(from->wo_rlc);
5793 to->wo_stl = vim_strsave(from->wo_stl);
5794 to->wo_wrap = from->wo_wrap;
5795 to->wo_wrap_save = from->wo_wrap_save;
5796 to->wo_lbr = from->wo_lbr;
5797 to->wo_bri = from->wo_bri;
5798 to->wo_briopt = vim_strsave(from->wo_briopt);
5799 to->wo_scb = from->wo_scb;
5800 to->wo_scb_save = from->wo_scb_save;
5801 to->wo_crb = from->wo_crb;
5802 to->wo_crb_save = from->wo_crb_save;
5803 to->wo_spell = from->wo_spell;
5804 to->wo_cuc = from->wo_cuc;
5805 to->wo_cul = from->wo_cul;
5806 to->wo_cc = vim_strsave(from->wo_cc);
5807 to->wo_diff = from->wo_diff;
5808 to->wo_diff_saved = from->wo_diff_saved;
5809 to->wo_cocu = vim_strsave(from->wo_cocu);
5810 to->wo_cole = from->wo_cole;
5811 to->wo_fdc = from->wo_fdc;
5812 to->wo_fdc_save = from->wo_fdc_save;
5813 to->wo_fen = from->wo_fen;
5814 to->wo_fen_save = from->wo_fen_save;
5815 to->wo_fdi = vim_strsave(from->wo_fdi);
5816 to->wo_fml = from->wo_fml;
5817 to->wo_fdl = from->wo_fdl;
5818 to->wo_fdl_save = from->wo_fdl_save;
5819 to->wo_fdm = vim_strsave(from->wo_fdm);
5820 to->wo_fdm_save = from->wo_diff_saved
5821 ? vim_strsave(from->wo_fdm_save) : empty_option;
5822 to->wo_fdn = from->wo_fdn;
5823 to->wo_fde = vim_strsave(from->wo_fde);
5824 to->wo_fdt = vim_strsave(from->wo_fdt);
5825 to->wo_fmr = vim_strsave(from->wo_fmr);
5826 to->wo_scl = vim_strsave(from->wo_scl);
5827 to->wo_winhl = vim_strsave(from->wo_winhl);
5828 to->wo_fcs = vim_strsave(from->wo_fcs);
5829 to->wo_lcs = vim_strsave(from->wo_lcs);
5830 to->wo_winbl = from->wo_winbl;
5831 check_winopt(to); // don't want NULL pointers
5832}
5833
5834/*
5835 * Check string options in a window for a NULL value.
5836 */
5837void check_win_options(win_T *win)
5838{
5839 check_winopt(&win->w_onebuf_opt);
5840 check_winopt(&win->w_allbuf_opt);
5841}
5842
5843/*
5844 * Check for NULL pointers in a winopt_T and replace them with empty_option.
5845 */
5846static void check_winopt(winopt_T *wop)
5847{
5848 check_string_option(&wop->wo_fdi);
5849 check_string_option(&wop->wo_fdm);
5850 check_string_option(&wop->wo_fdm_save);
5851 check_string_option(&wop->wo_fde);
5852 check_string_option(&wop->wo_fdt);
5853 check_string_option(&wop->wo_fmr);
5854 check_string_option(&wop->wo_scl);
5855 check_string_option(&wop->wo_rlc);
5856 check_string_option(&wop->wo_stl);
5857 check_string_option(&wop->wo_cc);
5858 check_string_option(&wop->wo_cocu);
5859 check_string_option(&wop->wo_briopt);
5860 check_string_option(&wop->wo_winhl);
5861 check_string_option(&wop->wo_fcs);
5862 check_string_option(&wop->wo_lcs);
5863}
5864
5865/*
5866 * Free the allocated memory inside a winopt_T.
5867 */
5868void clear_winopt(winopt_T *wop)
5869{
5870 clear_string_option(&wop->wo_fdi);
5871 clear_string_option(&wop->wo_fdm);
5872 clear_string_option(&wop->wo_fdm_save);
5873 clear_string_option(&wop->wo_fde);
5874 clear_string_option(&wop->wo_fdt);
5875 clear_string_option(&wop->wo_fmr);
5876 clear_string_option(&wop->wo_scl);
5877 clear_string_option(&wop->wo_rlc);
5878 clear_string_option(&wop->wo_stl);
5879 clear_string_option(&wop->wo_cc);
5880 clear_string_option(&wop->wo_cocu);
5881 clear_string_option(&wop->wo_briopt);
5882 clear_string_option(&wop->wo_winhl);
5883 clear_string_option(&wop->wo_fcs);
5884 clear_string_option(&wop->wo_lcs);
5885}
5886
5887void didset_window_options(win_T *wp)
5888{
5889 check_colorcolumn(wp);
5890 briopt_check(wp);
5891 set_chars_option(wp, &wp->w_p_fcs);
5892 set_chars_option(wp, &wp->w_p_lcs);
5893 parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl
5894 wp->w_grid.blending = wp->w_p_winbl > 0;
5895}
5896
5897
5898/*
5899 * Copy global option values to local options for one buffer.
5900 * Used when creating a new buffer and sometimes when entering a buffer.
5901 * flags:
5902 * BCO_ENTER We will enter the buf buffer.
5903 * BCO_ALWAYS Always copy the options, but only set b_p_initialized when
5904 * appropriate.
5905 * BCO_NOHELP Don't copy the values to a help buffer.
5906 */
5907void buf_copy_options(buf_T *buf, int flags)
5908{
5909 int should_copy = true;
5910 char_u *save_p_isk = NULL; // init for GCC
5911 int dont_do_help;
5912 int did_isk = false;
5913
5914 /*
5915 * Skip this when the option defaults have not been set yet. Happens when
5916 * main() allocates the first buffer.
5917 */
5918 if (p_cpo != NULL) {
5919 //
5920 // Always copy when entering and 'cpo' contains 'S'.
5921 // Don't copy when already initialized.
5922 // Don't copy when 'cpo' contains 's' and not entering.
5923 // 'S' BCO_ENTER initialized 's' should_copy
5924 // yes yes X X true
5925 // yes no yes X false
5926 // no X yes X false
5927 // X no no yes false
5928 // X no no no true
5929 // no yes no X true
5930 ///
5931 if ((vim_strchr(p_cpo, CPO_BUFOPTGLOB) == NULL || !(flags & BCO_ENTER))
5932 && (buf->b_p_initialized
5933 || (!(flags & BCO_ENTER)
5934 && vim_strchr(p_cpo, CPO_BUFOPT) != NULL))) {
5935 should_copy = false;
5936 }
5937
5938 if (should_copy || (flags & BCO_ALWAYS)) {
5939 /* Don't copy the options specific to a help buffer when
5940 * BCO_NOHELP is given or the options were initialized already
5941 * (jumping back to a help file with CTRL-T or CTRL-O) */
5942 dont_do_help = ((flags & BCO_NOHELP) && buf->b_help)
5943 || buf->b_p_initialized;
5944 if (dont_do_help) { // don't free b_p_isk
5945 save_p_isk = buf->b_p_isk;
5946 buf->b_p_isk = NULL;
5947 }
5948 /*
5949 * Always free the allocated strings.
5950 * If not already initialized, set 'readonly' and copy 'fileformat'.
5951 */
5952 if (!buf->b_p_initialized) {
5953 free_buf_options(buf, true);
5954 buf->b_p_ro = false; // don't copy readonly
5955 buf->b_p_fenc = vim_strsave(p_fenc);
5956 switch (*p_ffs) {
5957 case 'm': {
5958 buf->b_p_ff = vim_strsave((char_u *)FF_MAC);
5959 break;
5960 }
5961 case 'd': {
5962 buf->b_p_ff = vim_strsave((char_u *)FF_DOS);
5963 break;
5964 }
5965 case 'u': {
5966 buf->b_p_ff = vim_strsave((char_u *)FF_UNIX);
5967 break;
5968 }
5969 default: {
5970 buf->b_p_ff = vim_strsave(p_ff);
5971 break;
5972 }
5973 }
5974 buf->b_p_bh = empty_option;
5975 buf->b_p_bt = empty_option;
5976 } else {
5977 free_buf_options(buf, false);
5978 }
5979
5980 buf->b_p_ai = p_ai;
5981 buf->b_p_ai_nopaste = p_ai_nopaste;
5982 buf->b_p_sw = p_sw;
5983 buf->b_p_scbk = p_scbk;
5984 buf->b_p_tw = p_tw;
5985 buf->b_p_tw_nopaste = p_tw_nopaste;
5986 buf->b_p_tw_nobin = p_tw_nobin;
5987 buf->b_p_wm = p_wm;
5988 buf->b_p_wm_nopaste = p_wm_nopaste;
5989 buf->b_p_wm_nobin = p_wm_nobin;
5990 buf->b_p_bin = p_bin;
5991 buf->b_p_bomb = p_bomb;
5992 buf->b_p_et = p_et;
5993 buf->b_p_fixeol = p_fixeol;
5994 buf->b_p_et_nobin = p_et_nobin;
5995 buf->b_p_et_nopaste = p_et_nopaste;
5996 buf->b_p_ml = p_ml;
5997 buf->b_p_ml_nobin = p_ml_nobin;
5998 buf->b_p_inf = p_inf;
5999 buf->b_p_swf = cmdmod.noswapfile ? false : p_swf;
6000 buf->b_p_cpt = vim_strsave(p_cpt);
6001 buf->b_p_cfu = vim_strsave(p_cfu);
6002 buf->b_p_ofu = vim_strsave(p_ofu);
6003 buf->b_p_sts = p_sts;
6004 buf->b_p_sts_nopaste = p_sts_nopaste;
6005 buf->b_p_com = vim_strsave(p_com);
6006 buf->b_p_cms = vim_strsave(p_cms);
6007 buf->b_p_fo = vim_strsave(p_fo);
6008 buf->b_p_flp = vim_strsave(p_flp);
6009 buf->b_p_nf = vim_strsave(p_nf);
6010 buf->b_p_mps = vim_strsave(p_mps);
6011 buf->b_p_si = p_si;
6012 buf->b_p_channel = 0;
6013 buf->b_p_ci = p_ci;
6014 buf->b_p_cin = p_cin;
6015 buf->b_p_cink = vim_strsave(p_cink);
6016 buf->b_p_cino = vim_strsave(p_cino);
6017 // Don't copy 'filetype', it must be detected
6018 buf->b_p_ft = empty_option;
6019 buf->b_p_pi = p_pi;
6020 buf->b_p_cinw = vim_strsave(p_cinw);
6021 buf->b_p_lisp = p_lisp;
6022 // Don't copy 'syntax', it must be set
6023 buf->b_p_syn = empty_option;
6024 buf->b_p_smc = p_smc;
6025 buf->b_s.b_syn_isk = empty_option;
6026 buf->b_s.b_p_spc = vim_strsave(p_spc);
6027 (void)compile_cap_prog(&buf->b_s);
6028 buf->b_s.b_p_spf = vim_strsave(p_spf);
6029 buf->b_s.b_p_spl = vim_strsave(p_spl);
6030 buf->b_p_inde = vim_strsave(p_inde);
6031 buf->b_p_indk = vim_strsave(p_indk);
6032 buf->b_p_fp = empty_option;
6033 buf->b_p_fex = vim_strsave(p_fex);
6034 buf->b_p_sua = vim_strsave(p_sua);
6035 buf->b_p_keymap = vim_strsave(p_keymap);
6036 buf->b_kmap_state |= KEYMAP_INIT;
6037 /* This isn't really an option, but copying the langmap and IME
6038 * state from the current buffer is better than resetting it. */
6039 buf->b_p_iminsert = p_iminsert;
6040 buf->b_p_imsearch = p_imsearch;
6041
6042 /* options that are normally global but also have a local value
6043 * are not copied, start using the global value */
6044 buf->b_p_ar = -1;
6045 buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
6046 buf->b_p_bkc = empty_option;
6047 buf->b_bkc_flags = 0;
6048 buf->b_p_gp = empty_option;
6049 buf->b_p_mp = empty_option;
6050 buf->b_p_efm = empty_option;
6051 buf->b_p_ep = empty_option;
6052 buf->b_p_kp = empty_option;
6053 buf->b_p_path = empty_option;
6054 buf->b_p_tags = empty_option;
6055 buf->b_p_tc = empty_option;
6056 buf->b_tc_flags = 0;
6057 buf->b_p_def = empty_option;
6058 buf->b_p_inc = empty_option;
6059 buf->b_p_inex = vim_strsave(p_inex);
6060 buf->b_p_dict = empty_option;
6061 buf->b_p_tsr = empty_option;
6062 buf->b_p_qe = vim_strsave(p_qe);
6063 buf->b_p_udf = p_udf;
6064 buf->b_p_lw = empty_option;
6065 buf->b_p_menc = empty_option;
6066
6067 /*
6068 * Don't copy the options set by ex_help(), use the saved values,
6069 * when going from a help buffer to a non-help buffer.
6070 * Don't touch these at all when BCO_NOHELP is used and going from
6071 * or to a help buffer.
6072 */
6073 if (dont_do_help) {
6074 buf->b_p_isk = save_p_isk;
6075 } else {
6076 buf->b_p_isk = vim_strsave(p_isk);
6077 did_isk = true;
6078 buf->b_p_ts = p_ts;
6079 buf->b_help = false;
6080 if (buf->b_p_bt[0] == 'h') {
6081 clear_string_option(&buf->b_p_bt);
6082 }
6083 buf->b_p_ma = p_ma;
6084 }
6085 }
6086
6087 /*
6088 * When the options should be copied (ignoring BCO_ALWAYS), set the
6089 * flag that indicates that the options have been initialized.
6090 */
6091 if (should_copy) {
6092 buf->b_p_initialized = true;
6093 }
6094 }
6095
6096 check_buf_options(buf); // make sure we don't have NULLs
6097 if (did_isk) {
6098 (void)buf_init_chartab(buf, false);
6099 }
6100}
6101
6102/*
6103 * Reset the 'modifiable' option and its default value.
6104 */
6105void reset_modifiable(void)
6106{
6107 int opt_idx;
6108
6109 curbuf->b_p_ma = false;
6110 p_ma = false;
6111 opt_idx = findoption("ma");
6112 if (opt_idx >= 0) {
6113 options[opt_idx].def_val[VI_DEFAULT] = false;
6114 }
6115}
6116
6117/*
6118 * Set the global value for 'iminsert' to the local value.
6119 */
6120void set_iminsert_global(void)
6121{
6122 p_iminsert = curbuf->b_p_iminsert;
6123}
6124
6125/*
6126 * Set the global value for 'imsearch' to the local value.
6127 */
6128void set_imsearch_global(void)
6129{
6130 p_imsearch = curbuf->b_p_imsearch;
6131}
6132
6133static int expand_option_idx = -1;
6134static char_u expand_option_name[5] = {'t', '_', NUL, NUL, NUL};
6135static int expand_option_flags = 0;
6136
6137void
6138set_context_in_set_cmd(
6139 expand_T *xp,
6140 char_u *arg,
6141 int opt_flags // OPT_GLOBAL and/or OPT_LOCAL
6142)
6143{
6144 char_u nextchar;
6145 uint32_t flags = 0; // init for GCC
6146 int opt_idx = 0; // init for GCC
6147 char_u *p;
6148 char_u *s;
6149 int is_term_option = false;
6150 int key;
6151
6152 expand_option_flags = opt_flags;
6153
6154 xp->xp_context = EXPAND_SETTINGS;
6155 if (*arg == NUL) {
6156 xp->xp_pattern = arg;
6157 return;
6158 }
6159 p = arg + STRLEN(arg) - 1;
6160 if (*p == ' ' && *(p - 1) != '\\') {
6161 xp->xp_pattern = p + 1;
6162 return;
6163 }
6164 while (p > arg) {
6165 s = p;
6166 // count number of backslashes before ' ' or ','
6167 if (*p == ' ' || *p == ',') {
6168 while (s > arg && *(s - 1) == '\\') {
6169 s--;
6170 }
6171 }
6172 // break at a space with an even number of backslashes
6173 if (*p == ' ' && ((p - s) & 1) == 0) {
6174 p++;
6175 break;
6176 }
6177 p--;
6178 }
6179 if (STRNCMP(p, "no", 2) == 0) {
6180 xp->xp_context = EXPAND_BOOL_SETTINGS;
6181 p += 2;
6182 }
6183 if (STRNCMP(p, "inv", 3) == 0) {
6184 xp->xp_context = EXPAND_BOOL_SETTINGS;
6185 p += 3;
6186 }
6187 xp->xp_pattern = arg = p;
6188 if (*arg == '<') {
6189 while (*p != '>') {
6190 if (*p++ == NUL) { // expand terminal option name
6191 return;
6192 }
6193 }
6194 key = get_special_key_code(arg + 1);
6195 if (key == 0) { // unknown name
6196 xp->xp_context = EXPAND_NOTHING;
6197 return;
6198 }
6199 nextchar = *++p;
6200 is_term_option = true;
6201 expand_option_name[2] = (char_u)KEY2TERMCAP0(key);
6202 expand_option_name[3] = KEY2TERMCAP1(key);
6203 } else {
6204 if (p[0] == 't' && p[1] == '_') {
6205 p += 2;
6206 if (*p != NUL) {
6207 p++;
6208 }
6209 if (*p == NUL) {
6210 return; // expand option name
6211 }
6212 nextchar = *++p;
6213 is_term_option = true;
6214 expand_option_name[2] = p[-2];
6215 expand_option_name[3] = p[-1];
6216 } else {
6217 // Allow * wildcard.
6218 while (ASCII_ISALNUM(*p) || *p == '_' || *p == '*') {
6219 p++;
6220 }
6221 if (*p == NUL) {
6222 return;
6223 }
6224 nextchar = *p;
6225 opt_idx = findoption_len((const char *)arg, (size_t)(p - arg));
6226 if (opt_idx == -1 || options[opt_idx].var == NULL) {
6227 xp->xp_context = EXPAND_NOTHING;
6228 return;
6229 }
6230 flags = options[opt_idx].flags;
6231 if (flags & P_BOOL) {
6232 xp->xp_context = EXPAND_NOTHING;
6233 return;
6234 }
6235 }
6236 }
6237 // handle "-=" and "+="
6238 if ((nextchar == '-' || nextchar == '+' || nextchar == '^') && p[1] == '=') {
6239 p++;
6240 nextchar = '=';
6241 }
6242 if ((nextchar != '=' && nextchar != ':')
6243 || xp->xp_context == EXPAND_BOOL_SETTINGS) {
6244 xp->xp_context = EXPAND_UNSUCCESSFUL;
6245 return;
6246 }
6247 if (p[1] == NUL) {
6248 xp->xp_context = EXPAND_OLD_SETTING;
6249 if (is_term_option) {
6250 expand_option_idx = -1;
6251 } else {
6252 expand_option_idx = opt_idx;
6253 }
6254 xp->xp_pattern = p + 1;
6255 return;
6256 }
6257 xp->xp_context = EXPAND_NOTHING;
6258 if (is_term_option || (flags & P_NUM)) {
6259 return;
6260 }
6261
6262 xp->xp_pattern = p + 1;
6263
6264 if (flags & P_EXPAND) {
6265 p = options[opt_idx].var;
6266 if (p == (char_u *)&p_bdir
6267 || p == (char_u *)&p_dir
6268 || p == (char_u *)&p_path
6269 || p == (char_u *)&p_pp
6270 || p == (char_u *)&p_rtp
6271 || p == (char_u *)&p_cdpath
6272 || p == (char_u *)&p_vdir
6273 ) {
6274 xp->xp_context = EXPAND_DIRECTORIES;
6275 if (p == (char_u *)&p_path
6276 || p == (char_u *)&p_cdpath
6277 )
6278 xp->xp_backslash = XP_BS_THREE;
6279 else
6280 xp->xp_backslash = XP_BS_ONE;
6281 } else {
6282 xp->xp_context = EXPAND_FILES;
6283 // for 'tags' need three backslashes for a space
6284 if (p == (char_u *)&p_tags) {
6285 xp->xp_backslash = XP_BS_THREE;
6286 } else {
6287 xp->xp_backslash = XP_BS_ONE;
6288 }
6289 }
6290 }
6291
6292 /* For an option that is a list of file names, find the start of the
6293 * last file name. */
6294 for (p = arg + STRLEN(arg) - 1; p > xp->xp_pattern; p--) {
6295 // count number of backslashes before ' ' or ','
6296 if (*p == ' ' || *p == ',') {
6297 s = p;
6298 while (s > xp->xp_pattern && *(s - 1) == '\\') {
6299 s--;
6300 }
6301 if ((*p == ' ' && (xp->xp_backslash == XP_BS_THREE && (p - s) < 3))
6302 || (*p == ',' && (flags & P_COMMA) && ((p - s) & 1) == 0)) {
6303 xp->xp_pattern = p + 1;
6304 break;
6305 }
6306 }
6307
6308 // for 'spellsuggest' start at "file:"
6309 if (options[opt_idx].var == (char_u *)&p_sps
6310 && STRNCMP(p, "file:", 5) == 0) {
6311 xp->xp_pattern = p + 5;
6312 break;
6313 }
6314 }
6315
6316 return;
6317}
6318
6319int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file)
6320{
6321 int num_normal = 0; // Nr of matching non-term-code settings
6322 int match;
6323 int count = 0;
6324 char_u *str;
6325 int loop;
6326 static char *(names[]) = { "all" };
6327 int ic = regmatch->rm_ic; // remember the ignore-case flag
6328
6329 /* do this loop twice:
6330 * loop == 0: count the number of matching options
6331 * loop == 1: copy the matching options into allocated memory
6332 */
6333 for (loop = 0; loop <= 1; loop++) {
6334 regmatch->rm_ic = ic;
6335 if (xp->xp_context != EXPAND_BOOL_SETTINGS) {
6336 for (match = 0; match < (int)ARRAY_SIZE(names);
6337 match++) {
6338 if (vim_regexec(regmatch, (char_u *)names[match], (colnr_T)0)) {
6339 if (loop == 0) {
6340 num_normal++;
6341 } else {
6342 (*file)[count++] = vim_strsave((char_u *)names[match]);
6343 }
6344 }
6345 }
6346 }
6347 for (size_t opt_idx = 0; (str = (char_u *)options[opt_idx].fullname) != NULL;
6348 opt_idx++) {
6349 if (options[opt_idx].var == NULL) {
6350 continue;
6351 }
6352 if (xp->xp_context == EXPAND_BOOL_SETTINGS
6353 && !(options[opt_idx].flags & P_BOOL)) {
6354 continue;
6355 }
6356 match = false;
6357 if (vim_regexec(regmatch, str, (colnr_T)0)
6358 || (options[opt_idx].shortname != NULL
6359 && vim_regexec(regmatch,
6360 (char_u *)options[opt_idx].shortname,
6361 (colnr_T)0))) {
6362 match = true;
6363 }
6364
6365 if (match) {
6366 if (loop == 0) {
6367 num_normal++;
6368 } else
6369 (*file)[count++] = vim_strsave(str);
6370 }
6371 }
6372
6373 if (loop == 0) {
6374 if (num_normal > 0) {
6375 *num_file = num_normal;
6376 } else {
6377 return OK;
6378 }
6379 *file = (char_u **)xmalloc((size_t)(*num_file) * sizeof(char_u *));
6380 }
6381 }
6382 return OK;
6383}
6384
6385void ExpandOldSetting(int *num_file, char_u ***file)
6386{
6387 char_u *var = NULL;
6388
6389 *num_file = 0;
6390 *file = (char_u **)xmalloc(sizeof(char_u *));
6391
6392 /*
6393 * For a terminal key code expand_option_idx is < 0.
6394 */
6395 if (expand_option_idx < 0) {
6396 expand_option_idx = findoption((const char *)expand_option_name);
6397 }
6398
6399 if (expand_option_idx >= 0) {
6400 // Put string of option value in NameBuff.
6401 option_value2string(&options[expand_option_idx], expand_option_flags);
6402 var = NameBuff;
6403 } else {
6404 var = (char_u *)"";
6405 }
6406
6407 // A backslash is required before some characters. This is the reverse of
6408 // what happens in do_set().
6409 char_u *buf = vim_strsave_escaped(var, escape_chars);
6410
6411#ifdef BACKSLASH_IN_FILENAME
6412 /* For MS-Windows et al. we don't double backslashes at the start and
6413 * before a file name character. */
6414 for (var = buf; *var != NUL; MB_PTR_ADV(var)) {
6415 if (var[0] == '\\' && var[1] == '\\'
6416 && expand_option_idx >= 0
6417 && (options[expand_option_idx].flags & P_EXPAND)
6418 && vim_isfilec(var[2])
6419 && (var[2] != '\\' || (var == buf && var[4] != '\\'))) {
6420 STRMOVE(var, var + 1);
6421 }
6422 }
6423#endif
6424
6425 *file[0] = buf;
6426 *num_file = 1;
6427}
6428
6429/*
6430 * Get the value for the numeric or string option *opp in a nice format into
6431 * NameBuff[]. Must not be called with a hidden option!
6432 */
6433static void
6434option_value2string(
6435 vimoption_T *opp,
6436 int opt_flags // OPT_GLOBAL and/or OPT_LOCAL
6437)
6438{
6439 char_u *varp;
6440
6441 varp = get_varp_scope(opp, opt_flags);
6442
6443 if (opp->flags & P_NUM) {
6444 long wc = 0;
6445
6446 if (wc_use_keyname(varp, &wc)) {
6447 STRLCPY(NameBuff, get_special_key_name((int)wc, 0), sizeof(NameBuff));
6448 } else if (wc != 0) {
6449 STRLCPY(NameBuff, transchar((int)wc), sizeof(NameBuff));
6450 } else {
6451 snprintf((char *)NameBuff,
6452 sizeof(NameBuff),
6453 "%" PRId64,
6454 (int64_t)*(long *)varp);
6455 }
6456 } else { // P_STRING
6457 varp = *(char_u **)(varp);
6458 if (varp == NULL) { // Just in case.
6459 NameBuff[0] = NUL;
6460 } else if (opp->flags & P_EXPAND) {
6461 home_replace(NULL, varp, NameBuff, MAXPATHL, false);
6462 // Translate 'pastetoggle' into special key names.
6463 } else if ((char_u **)opp->var == &p_pt) {
6464 str2specialbuf((const char *)p_pt, (char *)NameBuff, MAXPATHL);
6465 } else {
6466 STRLCPY(NameBuff, varp, MAXPATHL);
6467 }
6468 }
6469}
6470
6471/// Return true if "varp" points to 'wildchar' or 'wildcharm' and it can be
6472/// printed as a keyname.
6473/// "*wcp" is set to the value of the option if it's 'wildchar' or 'wildcharm'.
6474static int wc_use_keyname(char_u *varp, long *wcp)
6475{
6476 if (((long *)varp == &p_wc) || ((long *)varp == &p_wcm)) {
6477 *wcp = *(long *)varp;
6478 if (IS_SPECIAL(*wcp) || find_special_key_in_table((int)(*wcp)) >= 0) {
6479 return true;
6480 }
6481 }
6482 return false;
6483}
6484
6485/*
6486 * Any character has an equivalent 'langmap' character. This is used for
6487 * keyboards that have a special language mode that sends characters above
6488 * 128 (although other characters can be translated too). The "to" field is a
6489 * Vim command character. This avoids having to switch the keyboard back to
6490 * ASCII mode when leaving Insert mode.
6491 *
6492 * langmap_mapchar[] maps any of 256 chars to an ASCII char used for Vim
6493 * commands.
6494 * langmap_mapga.ga_data is a sorted table of langmap_entry_T.
6495 * This does the same as langmap_mapchar[] for characters >= 256.
6496 */
6497/*
6498 * With multi-byte support use growarray for 'langmap' chars >= 256
6499 */
6500typedef struct {
6501 int from;
6502 int to;
6503} langmap_entry_T;
6504
6505static garray_T langmap_mapga = GA_EMPTY_INIT_VALUE;
6506
6507/*
6508 * Search for an entry in "langmap_mapga" for "from". If found set the "to"
6509 * field. If not found insert a new entry at the appropriate location.
6510 */
6511static void langmap_set_entry(int from, int to)
6512{
6513 langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data);
6514 unsigned int a = 0;
6515 assert(langmap_mapga.ga_len >= 0);
6516 unsigned int b = (unsigned int)langmap_mapga.ga_len;
6517
6518 // Do a binary search for an existing entry.
6519 while (a != b) {
6520 unsigned int i = (a + b) / 2;
6521 int d = entries[i].from - from;
6522
6523 if (d == 0) {
6524 entries[i].to = to;
6525 return;
6526 }
6527 if (d < 0) {
6528 a = i + 1;
6529 } else {
6530 b = i;
6531 }
6532 }
6533
6534 ga_grow(&langmap_mapga, 1);
6535
6536 // insert new entry at position "a"
6537 entries = (langmap_entry_T *)(langmap_mapga.ga_data) + a;
6538 memmove(entries + 1, entries,
6539 ((unsigned int)langmap_mapga.ga_len - a) * sizeof(langmap_entry_T));
6540 langmap_mapga.ga_len++;
6541 entries[0].from = from;
6542 entries[0].to = to;
6543}
6544
6545/*
6546 * Apply 'langmap' to multi-byte character "c" and return the result.
6547 */
6548int langmap_adjust_mb(int c)
6549{
6550 langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data);
6551 int a = 0;
6552 int b = langmap_mapga.ga_len;
6553
6554 while (a != b) {
6555 int i = (a + b) / 2;
6556 int d = entries[i].from - c;
6557
6558 if (d == 0) {
6559 return entries[i].to; // found matching entry
6560 }
6561 if (d < 0) {
6562 a = i + 1;
6563 } else {
6564 b = i;
6565 }
6566 }
6567 return c; // no entry found, return "c" unmodified
6568}
6569
6570static void langmap_init(void)
6571{
6572 for (int i = 0; i < 256; i++) {
6573 langmap_mapchar[i] = (char_u)i; // we init with a one-to-one map
6574 }
6575 ga_init(&langmap_mapga, sizeof(langmap_entry_T), 8);
6576}
6577
6578/*
6579 * Called when langmap option is set; the language map can be
6580 * changed at any time!
6581 */
6582static void langmap_set(void)
6583{
6584 char_u *p;
6585 char_u *p2;
6586 int from, to;
6587
6588 ga_clear(&langmap_mapga); // clear the previous map first
6589 langmap_init(); // back to one-to-one map
6590
6591 for (p = p_langmap; p[0] != NUL; ) {
6592 for (p2 = p; p2[0] != NUL && p2[0] != ',' && p2[0] != ';';
6593 MB_PTR_ADV(p2)) {
6594 if (p2[0] == '\\' && p2[1] != NUL) {
6595 p2++;
6596 }
6597 }
6598 if (p2[0] == ';') {
6599 p2++; // abcd;ABCD form, p2 points to A
6600 } else {
6601 p2 = NULL; // aAbBcCdD form, p2 is NULL
6602 }
6603 while (p[0]) {
6604 if (p[0] == ',') {
6605 p++;
6606 break;
6607 }
6608 if (p[0] == '\\' && p[1] != NUL) {
6609 p++;
6610 }
6611 from = utf_ptr2char(p);
6612 to = NUL;
6613 if (p2 == NULL) {
6614 MB_PTR_ADV(p);
6615 if (p[0] != ',') {
6616 if (p[0] == '\\') {
6617 p++;
6618 }
6619 to = utf_ptr2char(p);
6620 }
6621 } else {
6622 if (p2[0] != ',') {
6623 if (p2[0] == '\\') {
6624 p2++;
6625 }
6626 to = utf_ptr2char(p2);
6627 }
6628 }
6629 if (to == NUL) {
6630 EMSG2(_("E357: 'langmap': Matching character missing for %s"),
6631 transchar(from));
6632 return;
6633 }
6634
6635 if (from >= 256) {
6636 langmap_set_entry(from, to);
6637 } else {
6638 assert(to <= UCHAR_MAX);
6639 langmap_mapchar[from & 255] = (char_u)to;
6640 }
6641
6642 // Advance to next pair
6643 MB_PTR_ADV(p);
6644 if (p2 != NULL) {
6645 MB_PTR_ADV(p2);
6646 if (*p == ';') {
6647 p = p2;
6648 if (p[0] != NUL) {
6649 if (p[0] != ',') {
6650 EMSG2(_(
6651 "E358: 'langmap': Extra characters after semicolon: %s"),
6652 p);
6653 return;
6654 }
6655 p++;
6656 }
6657 break;
6658 }
6659 }
6660 }
6661 }
6662}
6663
6664/// Return true if format option 'x' is in effect.
6665/// Take care of no formatting when 'paste' is set.
6666int has_format_option(int x)
6667{
6668 if (p_paste) {
6669 return false;
6670 }
6671 return vim_strchr(curbuf->b_p_fo, x) != NULL;
6672}
6673
6674/// @returns true if "x" is present in 'shortmess' option, or
6675/// 'shortmess' contains 'a' and "x" is present in SHM_ALL_ABBREVIATIONS.
6676bool shortmess(int x)
6677{
6678 return (p_shm != NULL
6679 && (vim_strchr(p_shm, x) != NULL
6680 || (vim_strchr(p_shm, 'a') != NULL
6681 && vim_strchr((char_u *)SHM_ALL_ABBREVIATIONS, x) != NULL)));
6682}
6683
6684/*
6685 * paste_option_changed() - Called after p_paste was set or reset.
6686 */
6687static void paste_option_changed(void)
6688{
6689 static int old_p_paste = false;
6690 static int save_sm = 0;
6691 static int save_sta = 0;
6692 static int save_ru = 0;
6693 static int save_ri = 0;
6694 static int save_hkmap = 0;
6695
6696 if (p_paste) {
6697 /*
6698 * Paste switched from off to on.
6699 * Save the current values, so they can be restored later.
6700 */
6701 if (!old_p_paste) {
6702 // save options for each buffer
6703 FOR_ALL_BUFFERS(buf) {
6704 buf->b_p_tw_nopaste = buf->b_p_tw;
6705 buf->b_p_wm_nopaste = buf->b_p_wm;
6706 buf->b_p_sts_nopaste = buf->b_p_sts;
6707 buf->b_p_ai_nopaste = buf->b_p_ai;
6708 buf->b_p_et_nopaste = buf->b_p_et;
6709 }
6710
6711 // save global options
6712 save_sm = p_sm;
6713 save_sta = p_sta;
6714 save_ru = p_ru;
6715 save_ri = p_ri;
6716 save_hkmap = p_hkmap;
6717 // save global values for local buffer options
6718 p_ai_nopaste = p_ai;
6719 p_et_nopaste = p_et;
6720 p_sts_nopaste = p_sts;
6721 p_tw_nopaste = p_tw;
6722 p_wm_nopaste = p_wm;
6723 }
6724
6725 // Always set the option values, also when 'paste' is set when it is
6726 // already on.
6727 // set options for each buffer
6728 FOR_ALL_BUFFERS(buf) {
6729 buf->b_p_tw = 0; // textwidth is 0
6730 buf->b_p_wm = 0; // wrapmargin is 0
6731 buf->b_p_sts = 0; // softtabstop is 0
6732 buf->b_p_ai = 0; // no auto-indent
6733 buf->b_p_et = 0; // no expandtab
6734 }
6735
6736 // set global options
6737 p_sm = 0; // no showmatch
6738 p_sta = 0; // no smarttab
6739 if (p_ru) {
6740 status_redraw_all(); // redraw to remove the ruler
6741 }
6742 p_ru = 0; // no ruler
6743 p_ri = 0; // no reverse insert
6744 p_hkmap = 0; // no Hebrew keyboard
6745 // set global values for local buffer options
6746 p_tw = 0;
6747 p_wm = 0;
6748 p_sts = 0;
6749 p_ai = 0;
6750 } else if (old_p_paste) {
6751 // Paste switched from on to off: Restore saved values.
6752
6753 // restore options for each buffer
6754 FOR_ALL_BUFFERS(buf) {
6755 buf->b_p_tw = buf->b_p_tw_nopaste;
6756 buf->b_p_wm = buf->b_p_wm_nopaste;
6757 buf->b_p_sts = buf->b_p_sts_nopaste;
6758 buf->b_p_ai = buf->b_p_ai_nopaste;
6759 buf->b_p_et = buf->b_p_et_nopaste;
6760 }
6761
6762 // restore global options
6763 p_sm = save_sm;
6764 p_sta = save_sta;
6765 if (p_ru != save_ru) {
6766 status_redraw_all(); // redraw to draw the ruler
6767 }
6768 p_ru = save_ru;
6769 p_ri = save_ri;
6770 p_hkmap = save_hkmap;
6771 // set global values for local buffer options
6772 p_ai = p_ai_nopaste;
6773 p_et = p_et_nopaste;
6774 p_sts = p_sts_nopaste;
6775 p_tw = p_tw_nopaste;
6776 p_wm = p_wm_nopaste;
6777 }
6778
6779 old_p_paste = p_paste;
6780}
6781
6782/// vimrc_found() - Called when a vimrc or "VIMINIT" has been found.
6783///
6784/// Set the values for options that didn't get set yet to the Vim defaults.
6785/// When "fname" is not NULL, use it to set $"envname" when it wasn't set yet.
6786void vimrc_found(char_u *fname, char_u *envname)
6787{
6788 if (fname != NULL && envname != NULL) {
6789 char *p = vim_getenv((char *)envname);
6790 if (p == NULL) {
6791 // Set $MYVIMRC to the first vimrc file found.
6792 p = FullName_save((char *)fname, false);
6793 if (p != NULL) {
6794 os_setenv((char *)envname, p, 1);
6795 xfree(p);
6796 }
6797 } else {
6798 xfree(p);
6799 }
6800 }
6801}
6802
6803/// Check whether global option has been set
6804///
6805/// @param[in] name Option name.
6806///
6807/// @return True if it was set.
6808bool option_was_set(const char *name)
6809{
6810 int idx;
6811
6812 idx = findoption(name);
6813 if (idx < 0) { // Unknown option.
6814 return false;
6815 } else if (options[idx].flags & P_WAS_SET) {
6816 return true;
6817 }
6818 return false;
6819}
6820
6821/// Reset the flag indicating option "name" was set.
6822///
6823/// @param[in] name Option name.
6824void reset_option_was_set(const char *name)
6825{
6826 const int idx = findoption(name);
6827
6828 if (idx >= 0) {
6829 options[idx].flags &= ~P_WAS_SET;
6830 }
6831}
6832
6833/*
6834 * fill_breakat_flags() -- called when 'breakat' changes value.
6835 */
6836static void fill_breakat_flags(void)
6837{
6838 char_u *p;
6839 int i;
6840
6841 for (i = 0; i < 256; i++) {
6842 breakat_flags[i] = false;
6843 }
6844
6845 if (p_breakat != NULL) {
6846 for (p = p_breakat; *p; p++) {
6847 breakat_flags[*p] = true;
6848 }
6849 }
6850}
6851
6852/*
6853 * Check an option that can be a range of string values.
6854 *
6855 * Return OK for correct value, FAIL otherwise.
6856 * Empty is always OK.
6857 */
6858static int check_opt_strings(
6859 char_u *val,
6860 char **values,
6861 int list // when true: accept a list of values
6862)
6863{
6864 return opt_strings_flags(val, values, NULL, list);
6865}
6866
6867/*
6868 * Handle an option that can be a range of string values.
6869 * Set a flag in "*flagp" for each string present.
6870 *
6871 * Return OK for correct value, FAIL otherwise.
6872 * Empty is always OK.
6873 */
6874static int opt_strings_flags(
6875 char_u *val, // new value
6876 char **values, // array of valid string values
6877 unsigned *flagp,
6878 bool list // when true: accept a list of values
6879)
6880{
6881 unsigned int new_flags = 0;
6882
6883 while (*val) {
6884 for (unsigned int i = 0;; i++) {
6885 if (values[i] == NULL) { // val not found in values[]
6886 return FAIL;
6887 }
6888
6889 size_t len = STRLEN(values[i]);
6890 if (STRNCMP(values[i], val, len) == 0
6891 && ((list && val[len] == ',') || val[len] == NUL)) {
6892 val += len + (val[len] == ',');
6893 assert(i < sizeof(1U) * 8);
6894 new_flags |= (1U << i);
6895 break; // check next item in val list
6896 }
6897 }
6898 }
6899 if (flagp != NULL) {
6900 *flagp = new_flags;
6901 }
6902
6903 return OK;
6904}
6905
6906/*
6907 * Read the 'wildmode' option, fill wim_flags[].
6908 */
6909static int check_opt_wim(void)
6910{
6911 char_u new_wim_flags[4];
6912 char_u *p;
6913 int i;
6914 int idx = 0;
6915
6916 for (i = 0; i < 4; i++) {
6917 new_wim_flags[i] = 0;
6918 }
6919
6920 for (p = p_wim; *p; p++) {
6921 for (i = 0; ASCII_ISALPHA(p[i]); i++) {}
6922 if (p[i] != NUL && p[i] != ',' && p[i] != ':') {
6923 return FAIL;
6924 }
6925 if (i == 7 && STRNCMP(p, "longest", 7) == 0) {
6926 new_wim_flags[idx] |= WIM_LONGEST;
6927 } else if (i == 4 && STRNCMP(p, "full", 4) == 0) {
6928 new_wim_flags[idx] |= WIM_FULL;
6929 } else if (i == 4 && STRNCMP(p, "list", 4) == 0) {
6930 new_wim_flags[idx] |= WIM_LIST;
6931 } else {
6932 return FAIL;
6933 }
6934 p += i;
6935 if (*p == NUL) {
6936 break;
6937 }
6938 if (*p == ',') {
6939 if (idx == 3) {
6940 return FAIL;
6941 }
6942 idx++;
6943 }
6944 }
6945
6946 // fill remaining entries with last flag
6947 while (idx < 3) {
6948 new_wim_flags[idx + 1] = new_wim_flags[idx];
6949 idx++;
6950 }
6951
6952 // only when there are no errors, wim_flags[] is changed
6953 for (i = 0; i < 4; i++) {
6954 wim_flags[i] = new_wim_flags[i];
6955 }
6956 return OK;
6957}
6958
6959/*
6960 * Check if backspacing over something is allowed.
6961 * The parameter what is one of the following: whatBS_INDENT, BS_EOL
6962 * or BS_START
6963 */
6964bool can_bs(int what)
6965{
6966 switch (*p_bs) {
6967 case '2': return true;
6968 case '1': return what != BS_START;
6969 case '0': return false;
6970 }
6971 return vim_strchr(p_bs, what) != NULL;
6972}
6973
6974/*
6975 * Save the current values of 'fileformat' and 'fileencoding', so that we know
6976 * the file must be considered changed when the value is different.
6977 */
6978void save_file_ff(buf_T *buf)
6979{
6980 buf->b_start_ffc = *buf->b_p_ff;
6981 buf->b_start_eol = buf->b_p_eol;
6982 buf->b_start_bomb = buf->b_p_bomb;
6983
6984 // Only use free/alloc when necessary, they take time.
6985 if (buf->b_start_fenc == NULL
6986 || STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0) {
6987 xfree(buf->b_start_fenc);
6988 buf->b_start_fenc = vim_strsave(buf->b_p_fenc);
6989 }
6990}
6991
6992/// Return true if 'fileformat' and/or 'fileencoding' has a different value
6993/// from when editing started (save_file_ff() called).
6994/// Also when 'endofline' was changed and 'binary' is set, or when 'bomb' was
6995/// changed and 'binary' is not set.
6996/// Also when 'endofline' was changed and 'fixeol' is not set.
6997/// When "ignore_empty" is true don't consider a new, empty buffer to be
6998/// changed.
6999bool file_ff_differs(buf_T *buf, bool ignore_empty)
7000 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
7001{
7002 // In a buffer that was never loaded the options are not valid.
7003 if (buf->b_flags & BF_NEVERLOADED) {
7004 return false;
7005 }
7006 if (ignore_empty
7007 && (buf->b_flags & BF_NEW)
7008 && buf->b_ml.ml_line_count == 1
7009 && *ml_get_buf(buf, (linenr_T)1, false) == NUL) {
7010 return false;
7011 }
7012 if (buf->b_start_ffc != *buf->b_p_ff) {
7013 return true;
7014 }
7015 if ((buf->b_p_bin || !buf->b_p_fixeol) && buf->b_start_eol != buf->b_p_eol) {
7016 return true;
7017 }
7018 if (!buf->b_p_bin && buf->b_start_bomb != buf->b_p_bomb) {
7019 return true;
7020 }
7021 if (buf->b_start_fenc == NULL) {
7022 return *buf->b_p_fenc != NUL;
7023 }
7024 return STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0;
7025}
7026
7027/*
7028 * return OK if "p" is a valid fileformat name, FAIL otherwise.
7029 */
7030int check_ff_value(char_u *p)
7031{
7032 return check_opt_strings(p, p_ff_values, false);
7033}
7034
7035/*
7036 * Return the effective shiftwidth value for current buffer, using the
7037 * 'tabstop' value when 'shiftwidth' is zero.
7038 */
7039int get_sw_value(buf_T *buf)
7040{
7041 long result = buf->b_p_sw ? buf->b_p_sw : buf->b_p_ts;
7042 assert(result >= 0 && result <= INT_MAX);
7043 return (int)result;
7044}
7045
7046// Return the effective softtabstop value for the current buffer,
7047// using the effective shiftwidth value when 'softtabstop' is negative.
7048int get_sts_value(void)
7049{
7050 long result = curbuf->b_p_sts < 0 ? get_sw_value(curbuf) : curbuf->b_p_sts;
7051 assert(result >= 0 && result <= INT_MAX);
7052 return (int)result;
7053}
7054
7055/*
7056 * Check matchpairs option for "*initc".
7057 * If there is a match set "*initc" to the matching character and "*findc" to
7058 * the opposite character. Set "*backwards" to the direction.
7059 * When "switchit" is true swap the direction.
7060 */
7061void find_mps_values(int *initc, int *findc, int *backwards, int switchit)
7062{
7063 char_u *ptr = curbuf->b_p_mps;
7064
7065 while (*ptr != NUL) {
7066 if (utf_ptr2char(ptr) == *initc) {
7067 if (switchit) {
7068 *findc = *initc;
7069 *initc = utf_ptr2char(ptr + utfc_ptr2len(ptr) + 1);
7070 *backwards = true;
7071 } else {
7072 *findc = utf_ptr2char(ptr + utfc_ptr2len(ptr) + 1);
7073 *backwards = false;
7074 }
7075 return;
7076 }
7077 char_u *prev = ptr;
7078 ptr += utfc_ptr2len(ptr) + 1;
7079 if (utf_ptr2char(ptr) == *initc) {
7080 if (switchit) {
7081 *findc = *initc;
7082 *initc = utf_ptr2char(prev);
7083 *backwards = false;
7084 } else {
7085 *findc = utf_ptr2char(prev);
7086 *backwards = true;
7087 }
7088 return;
7089 }
7090 ptr += utfc_ptr2len(ptr);
7091 if (*ptr == ',') {
7092 ptr++;
7093 }
7094 }
7095}
7096
7097/// This is called when 'breakindentopt' is changed and when a window is
7098/// initialized
7099static bool briopt_check(win_T *wp)
7100{
7101 int bri_shift = 0;
7102 int bri_min = 20;
7103 bool bri_sbr = false;
7104
7105 char_u *p = wp->w_p_briopt;
7106 while (*p != NUL)
7107 {
7108 if (STRNCMP(p, "shift:", 6) == 0
7109 && ((p[6] == '-' && ascii_isdigit(p[7])) || ascii_isdigit(p[6])))
7110 {
7111 p += 6;
7112 bri_shift = getdigits_int(&p, true, 0);
7113 }
7114 else if (STRNCMP(p, "min:", 4) == 0 && ascii_isdigit(p[4]))
7115 {
7116 p += 4;
7117 bri_min = getdigits_int(&p, true, 0);
7118 }
7119 else if (STRNCMP(p, "sbr", 3) == 0)
7120 {
7121 p += 3;
7122 bri_sbr = true;
7123 }
7124 if (*p != ',' && *p != NUL) {
7125 return false;
7126 }
7127 if (*p == ',') {
7128 p++;
7129 }
7130 }
7131
7132 wp->w_p_brishift = bri_shift;
7133 wp->w_p_brimin = bri_min;
7134 wp->w_p_brisbr = bri_sbr;
7135
7136 return true;
7137}
7138
7139/// Get the local or global value of 'backupcopy'.
7140///
7141/// @param buf The buffer.
7142unsigned int get_bkc_value(buf_T *buf)
7143{
7144 return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags;
7145}
7146
7147/// Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC.
7148int get_fileformat(buf_T *buf)
7149{
7150 int c = *buf->b_p_ff;
7151
7152 if (buf->b_p_bin || c == 'u') {
7153 return EOL_UNIX;
7154 }
7155 if (c == 'm') {
7156 return EOL_MAC;
7157 }
7158 return EOL_DOS;
7159}
7160
7161/// Like get_fileformat(), but override 'fileformat' with "p" for "++opt=val"
7162/// argument.
7163///
7164/// @param eap can be NULL!
7165int get_fileformat_force(buf_T *buf, exarg_T *eap)
7166{
7167 int c;
7168
7169 if (eap != NULL && eap->force_ff != 0) {
7170 c = eap->cmd[eap->force_ff];
7171 } else {
7172 if ((eap != NULL && eap->force_bin != 0)
7173 ? (eap->force_bin == FORCE_BIN) : buf->b_p_bin) {
7174 return EOL_UNIX;
7175 }
7176 c = *buf->b_p_ff;
7177 }
7178 if (c == 'u') {
7179 return EOL_UNIX;
7180 }
7181 if (c == 'm') {
7182 return EOL_MAC;
7183 }
7184 return EOL_DOS;
7185}
7186
7187/// Return the default fileformat from 'fileformats'.
7188int default_fileformat(void)
7189{
7190 switch (*p_ffs) {
7191 case 'm': return EOL_MAC;
7192 case 'd': return EOL_DOS;
7193 }
7194 return EOL_UNIX;
7195}
7196
7197/// Set the current end-of-line type to EOL_UNIX, EOL_MAC, or EOL_DOS.
7198///
7199/// Sets 'fileformat'.
7200///
7201/// @param eol_style End-of-line style.
7202/// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL
7203void set_fileformat(int eol_style, int opt_flags)
7204{
7205 char *p = NULL;
7206
7207 switch (eol_style) {
7208 case EOL_UNIX:
7209 p = FF_UNIX;
7210 break;
7211 case EOL_MAC:
7212 p = FF_MAC;
7213 break;
7214 case EOL_DOS:
7215 p = FF_DOS;
7216 break;
7217 }
7218
7219 // p is NULL if "eol_style" is EOL_UNKNOWN.
7220 if (p != NULL) {
7221 set_string_option_direct((char_u *)"ff",
7222 -1,
7223 (char_u *)p,
7224 OPT_FREE | opt_flags,
7225 0);
7226 }
7227
7228 // This may cause the buffer to become (un)modified.
7229 check_status(curbuf);
7230 redraw_tabline = true;
7231 need_maketitle = true; // Set window title later.
7232}
7233
7234/// Skip to next part of an option argument: skip space and comma
7235char_u *skip_to_option_part(const char_u *p)
7236{
7237 if (*p == ',') {
7238 p++;
7239 }
7240 while (*p == ' ') {
7241 p++;
7242 }
7243 return (char_u *)p;
7244}
7245
7246/// Isolate one part of a string option separated by `sep_chars`.
7247///
7248/// @param[in,out] option advanced to the next part
7249/// @param[in,out] buf copy of the isolated part
7250/// @param[in] maxlen length of `buf`
7251/// @param[in] sep_chars chars that separate the option parts
7252///
7253/// @return length of `*option`
7254size_t copy_option_part(char_u **option, char_u *buf, size_t maxlen,
7255 char *sep_chars)
7256{
7257 size_t len = 0;
7258 char_u *p = *option;
7259
7260 // skip '.' at start of option part, for 'suffixes'
7261 if (*p == '.') {
7262 buf[len++] = *p++;
7263 }
7264 while (*p != NUL && vim_strchr((char_u *)sep_chars, *p) == NULL) {
7265 // Skip backslash before a separator character and space.
7266 if (p[0] == '\\' && vim_strchr((char_u *)sep_chars, p[1]) != NULL) {
7267 p++;
7268 }
7269 if (len < maxlen - 1) {
7270 buf[len++] = *p;
7271 }
7272 p++;
7273 }
7274 buf[len] = NUL;
7275
7276 if (*p != NUL && *p != ',') { // skip non-standard separator
7277 p++;
7278 }
7279 p = skip_to_option_part(p); // p points to next file name
7280
7281 *option = p;
7282 return len;
7283}
7284
7285/// Return true when 'shell' has "csh" in the tail.
7286int csh_like_shell(void)
7287{
7288 return strstr((char *)path_tail(p_sh), "csh") != NULL;
7289}
7290
7291/// Return the number of requested sign columns, based on current
7292/// buffer signs and on user configuration.
7293int win_signcol_count(win_T *wp)
7294{
7295 int maximum = 1, needed_signcols;
7296 const char *scl = (const char *)wp->w_p_scl;
7297
7298 if (*scl == 'n') {
7299 return 0;
7300 }
7301 needed_signcols = buf_signcols(wp->w_buffer);
7302
7303 // yes or yes
7304 if (!strncmp(scl, "yes:", 4)) {
7305 // Fixed amount of columns
7306 return scl[4] - '0';
7307 }
7308 if (*scl == 'y') {
7309 return 1;
7310 }
7311
7312 // auto or auto:<NUM>
7313 if (!strncmp(scl, "auto:", 5)) {
7314 // Variable depending on a configuration
7315 maximum = scl[5] - '0';
7316 }
7317
7318 return MIN(maximum, needed_signcols);
7319}
7320
7321/// Get window or buffer local options
7322dict_T *get_winbuf_options(const int bufopt)
7323 FUNC_ATTR_WARN_UNUSED_RESULT
7324{
7325 dict_T *const d = tv_dict_alloc();
7326
7327 for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) {
7328 struct vimoption *opt = &options[opt_idx];
7329
7330 if ((bufopt && (opt->indir & PV_BUF))
7331 || (!bufopt && (opt->indir & PV_WIN))) {
7332 char_u *varp = get_varp(opt);
7333
7334 if (varp != NULL) {
7335 if (opt->flags & P_STRING) {
7336 tv_dict_add_str(d, opt->fullname, strlen(opt->fullname),
7337 *(const char **)varp);
7338 } else if (opt->flags & P_NUM) {
7339 tv_dict_add_nr(d, opt->fullname, strlen(opt->fullname),
7340 *(long *)varp);
7341 } else {
7342 tv_dict_add_nr(d, opt->fullname, strlen(opt->fullname), *(int *)varp);
7343 }
7344 }
7345 }
7346 }
7347
7348 return d;
7349}
7350