]> granicus.if.org Git - vim/blob - src/optionstr.c
patch 9.0.1359: too many "else if" statements in handling options
[vim] / src / optionstr.c
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved    by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9
10 /*
11  * optionstr.c: Functions related to string options
12  */
13
14 #include "vim.h"
15
16 static char_u shm_buf[SHM_LEN];
17 static int set_shm_recursive = 0;
18
19 static char *(p_ambw_values[]) = {"single", "double", NULL};
20 static char *(p_bg_values[]) = {"light", "dark", NULL};
21 static char *(p_bkc_values[]) = {"yes", "auto", "no", "breaksymlink", "breakhardlink", NULL};
22 static char *(p_bo_values[]) = {"all", "backspace", "cursor", "complete",
23                                  "copy", "ctrlg", "error", "esc", "ex",
24                                  "hangul", "insertmode", "lang", "mess",
25                                  "showmatch", "operator", "register", "shell",
26                                  "spell", "term", "wildmode", NULL};
27 static char *(p_nf_values[]) = {"bin", "octal", "hex", "alpha", "unsigned", NULL};
28 static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
29 #ifdef FEAT_CRYPT
30 static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2",
31  # ifdef FEAT_SODIUM
32     "xchacha20",
33  # endif
34     NULL};
35 #endif
36 static char *(p_cmp_values[]) = {"internal", "keepascii", NULL};
37 static char *(p_dy_values[]) = {"lastline", "truncate", "uhex", NULL};
38 #ifdef FEAT_FOLDING
39 static char *(p_fdo_values[]) = {"all", "block", "hor", "mark", "percent",
40                                  "quickfix", "search", "tag", "insert",
41                                  "undo", "jump", NULL};
42 #endif
43 #ifdef FEAT_SESSION
44 // Also used for 'viewoptions'!  Keep in sync with SSOP_ flags.
45 static char *(p_ssop_values[]) = {"buffers", "winpos", "resize", "winsize",
46     "localoptions", "options", "help", "blank", "globals", "slash", "unix",
47     "sesdir", "curdir", "folds", "cursor", "tabpages", "terminal", "skiprtp",
48     NULL};
49 #endif
50 // Keep in sync with SWB_ flags in option.h
51 static char *(p_swb_values[]) = {"useopen", "usetab", "split", "newtab", "vsplit", "uselast", NULL};
52 static char *(p_spk_values[]) = {"cursor", "screen", "topline", NULL};
53 static char *(p_tc_values[]) = {"followic", "ignore", "match", "followscs", "smart", NULL};
54 #if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_MSWIN)
55 static char *(p_toolbar_values[]) = {"text", "icons", "tooltips", "horiz", NULL};
56 #endif
57 #if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_GTK)
58 static char *(p_tbis_values[]) = {"tiny", "small", "medium", "large", "huge", "giant", NULL};
59 #endif
60 #if defined(UNIX) || defined(VMS)
61 static char *(p_ttym_values[]) = {"xterm", "xterm2", "dec", "netterm", "jsbterm", "pterm", "urxvt", "sgr", NULL};
62 #endif
63 static char *(p_ve_values[]) = {"block", "insert", "all", "onemore", "none", "NONE", NULL};
64 static char *(p_wop_values[]) = {"fuzzy", "tagfile", "pum", NULL};
65 #ifdef FEAT_WAK
66 static char *(p_wak_values[]) = {"yes", "menu", "no", NULL};
67 #endif
68 static char *(p_mousem_values[]) = {"extend", "popup", "popup_setpos", "mac", NULL};
69 static char *(p_sel_values[]) = {"inclusive", "exclusive", "old", NULL};
70 static char *(p_slm_values[]) = {"mouse", "key", "cmd", NULL};
71 static char *(p_km_values[]) = {"startsel", "stopsel", NULL};
72 #ifdef FEAT_BROWSE
73 static char *(p_bsdir_values[]) = {"current", "last", "buffer", NULL};
74 #endif
75 static char *(p_scbopt_values[]) = {"ver", "hor", "jump", NULL};
76 static char *(p_debug_values[]) = {"msg", "throw", "beep", NULL};
77 static char *(p_ead_values[]) = {"both", "ver", "hor", NULL};
78 static char *(p_buftype_values[]) = {"nofile", "nowrite", "quickfix", "help", "terminal", "acwrite", "prompt", "popup", NULL};
79 static char *(p_bufhidden_values[]) = {"hide", "unload", "delete", "wipe", NULL};
80 static char *(p_bs_values[]) = {"indent", "eol", "start", "nostop", NULL};
81 #ifdef FEAT_FOLDING
82 static char *(p_fdm_values[]) = {"manual", "expr", "marker", "indent", "syntax",
83 # ifdef FEAT_DIFF
84                                 "diff",
85 # endif
86                                 NULL};
87 static char *(p_fcl_values[]) = {"all", NULL};
88 #endif
89 static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview", "popup", "popuphidden", "noinsert", "noselect", NULL};
90 #ifdef BACKSLASH_IN_FILENAME
91 static char *(p_csl_values[]) = {"slash", "backslash", NULL};
92 #endif
93 #ifdef FEAT_SIGNS
94 static char *(p_scl_values[]) = {"yes", "no", "auto", "number", NULL};
95 #endif
96 #if defined(MSWIN) && defined(FEAT_TERMINAL)
97 static char *(p_twt_values[]) = {"winpty", "conpty", "", NULL};
98 #endif
99 static char *(p_sloc_values[]) = {"last", "statusline", "tabline", NULL};
100 static char *(p_sws_values[]) = {"fsync", "sync", NULL};
101
102 static int check_opt_strings(char_u *val, char **values, int list);
103 static int opt_strings_flags(char_u *val, char **values, unsigned *flagp, int list);
104
105 /*
106  * After setting various option values: recompute variables that depend on
107  * option values.
108  */
109     void
110 didset_string_options(void)
111 {
112     (void)opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, TRUE);
113     (void)opt_strings_flags(p_bkc, p_bkc_values, &bkc_flags, TRUE);
114     (void)opt_strings_flags(p_bo, p_bo_values, &bo_flags, TRUE);
115 #ifdef FEAT_SESSION
116     (void)opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, TRUE);
117     (void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, TRUE);
118 #endif
119 #ifdef FEAT_FOLDING
120     (void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, TRUE);
121 #endif
122     (void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, TRUE);
123     (void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, FALSE);
124     (void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, TRUE);
125 #if defined(UNIX) || defined(VMS)
126     (void)opt_strings_flags(p_ttym, p_ttym_values, &ttym_flags, FALSE);
127 #endif
128 #if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_MSWIN)
129     (void)opt_strings_flags(p_toolbar, p_toolbar_values, &toolbar_flags, TRUE);
130 #endif
131 #if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_GTK)
132     (void)opt_strings_flags(p_tbis, p_tbis_values, &tbis_flags, FALSE);
133 #endif
134     (void)opt_strings_flags(p_swb, p_swb_values, &swb_flags, TRUE);
135 }
136
137 #if defined(FEAT_EVAL)
138 /*
139  * Trigger the OptionSet autocommand.
140  * "opt_idx"    is the index of the option being set.
141  * "opt_flags"  can be OPT_LOCAL etc.
142  * "oldval"     the old value
143  *  "oldval_l"  the old local value (only non-NULL if global and local value
144  *              are set)
145  * "oldval_g"   the old global value (only non-NULL if global and local value
146  *              are set)
147  * "newval"     the new value
148  */
149     void
150 trigger_optionset_string(
151         int     opt_idx,
152         int     opt_flags,
153         char_u  *oldval,
154         char_u  *oldval_l,
155         char_u  *oldval_g,
156         char_u  *newval)
157 {
158     // Don't do this recursively.
159     if (oldval == NULL || newval == NULL
160                                     || *get_vim_var_str(VV_OPTION_TYPE) != NUL)
161         return;
162
163     char_u buf_type[7];
164
165     sprintf((char *)buf_type, "%s",
166             (opt_flags & OPT_LOCAL) ? "local" : "global");
167     set_vim_var_string(VV_OPTION_OLD, oldval, -1);
168     set_vim_var_string(VV_OPTION_NEW, newval, -1);
169     set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
170     if (opt_flags & OPT_LOCAL)
171     {
172         set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setlocal", -1);
173         set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1);
174     }
175     if (opt_flags & OPT_GLOBAL)
176     {
177         set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setglobal", -1);
178         set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval, -1);
179     }
180     if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
181     {
182         set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"set", -1);
183         set_vim_var_string(VV_OPTION_OLDLOCAL, oldval_l, -1);
184         set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval_g, -1);
185     }
186     if (opt_flags & OPT_MODELINE)
187     {
188         set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"modeline", -1);
189         set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1);
190     }
191     apply_autocmds(EVENT_OPTIONSET,
192             get_option_fullname(opt_idx), NULL, FALSE,
193             NULL);
194     reset_v_option_vars();
195 }
196 #endif
197
198     static char *
199 illegal_char(char *errbuf, int c)
200 {
201     if (errbuf == NULL)
202         return "";
203     sprintf((char *)errbuf, _(e_illegal_character_str), (char *)transchar(c));
204     return errbuf;
205 }
206
207 /*
208  * Check string options in a buffer for NULL value.
209  */
210     void
211 check_buf_options(buf_T *buf)
212 {
213     check_string_option(&buf->b_p_bh);
214     check_string_option(&buf->b_p_bt);
215     check_string_option(&buf->b_p_fenc);
216     check_string_option(&buf->b_p_ff);
217 #ifdef FEAT_FIND_ID
218     check_string_option(&buf->b_p_def);
219     check_string_option(&buf->b_p_inc);
220 # ifdef FEAT_EVAL
221     check_string_option(&buf->b_p_inex);
222 # endif
223 #endif
224 #if defined(FEAT_EVAL)
225     check_string_option(&buf->b_p_inde);
226     check_string_option(&buf->b_p_indk);
227 #endif
228 #if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
229     check_string_option(&buf->b_p_bexpr);
230 #endif
231 #if defined(FEAT_CRYPT)
232     check_string_option(&buf->b_p_cm);
233 #endif
234     check_string_option(&buf->b_p_fp);
235 #if defined(FEAT_EVAL)
236     check_string_option(&buf->b_p_fex);
237 #endif
238 #ifdef FEAT_CRYPT
239     check_string_option(&buf->b_p_key);
240 #endif
241     check_string_option(&buf->b_p_kp);
242     check_string_option(&buf->b_p_mps);
243     check_string_option(&buf->b_p_fo);
244     check_string_option(&buf->b_p_flp);
245     check_string_option(&buf->b_p_isk);
246     check_string_option(&buf->b_p_com);
247 #ifdef FEAT_FOLDING
248     check_string_option(&buf->b_p_cms);
249 #endif
250     check_string_option(&buf->b_p_nf);
251     check_string_option(&buf->b_p_qe);
252 #ifdef FEAT_SYN_HL
253     check_string_option(&buf->b_p_syn);
254     check_string_option(&buf->b_s.b_syn_isk);
255 #endif
256 #ifdef FEAT_SPELL
257     check_string_option(&buf->b_s.b_p_spc);
258     check_string_option(&buf->b_s.b_p_spf);
259     check_string_option(&buf->b_s.b_p_spl);
260     check_string_option(&buf->b_s.b_p_spo);
261 #endif
262     check_string_option(&buf->b_p_sua);
263     check_string_option(&buf->b_p_cink);
264     check_string_option(&buf->b_p_cino);
265     check_string_option(&buf->b_p_cinsd);
266     parse_cino(buf);
267     check_string_option(&buf->b_p_lop);
268     check_string_option(&buf->b_p_ft);
269     check_string_option(&buf->b_p_cinw);
270     check_string_option(&buf->b_p_cpt);
271 #ifdef FEAT_COMPL_FUNC
272     check_string_option(&buf->b_p_cfu);
273     check_string_option(&buf->b_p_ofu);
274     check_string_option(&buf->b_p_tsrfu);
275 #endif
276 #ifdef FEAT_EVAL
277     check_string_option(&buf->b_p_tfu);
278 #endif
279 #ifdef FEAT_KEYMAP
280     check_string_option(&buf->b_p_keymap);
281 #endif
282 #ifdef FEAT_QUICKFIX
283     check_string_option(&buf->b_p_gp);
284     check_string_option(&buf->b_p_mp);
285     check_string_option(&buf->b_p_efm);
286 #endif
287     check_string_option(&buf->b_p_ep);
288     check_string_option(&buf->b_p_path);
289     check_string_option(&buf->b_p_tags);
290     check_string_option(&buf->b_p_tc);
291     check_string_option(&buf->b_p_dict);
292     check_string_option(&buf->b_p_tsr);
293     check_string_option(&buf->b_p_lw);
294     check_string_option(&buf->b_p_bkc);
295     check_string_option(&buf->b_p_menc);
296 #ifdef FEAT_VARTABS
297     check_string_option(&buf->b_p_vsts);
298     check_string_option(&buf->b_p_vts);
299 #endif
300 }
301
302 /*
303  * Free the string allocated for an option.
304  * Checks for the string being empty_option. This may happen if we're out of
305  * memory, vim_strsave() returned NULL, which was replaced by empty_option by
306  * check_options().
307  * Does NOT check for P_ALLOCED flag!
308  */
309     void
310 free_string_option(char_u *p)
311 {
312     if (p != empty_option)
313         vim_free(p);
314 }
315
316     void
317 clear_string_option(char_u **pp)
318 {
319     if (*pp != empty_option)
320         vim_free(*pp);
321     *pp = empty_option;
322 }
323
324     void
325 check_string_option(char_u **pp)
326 {
327     if (*pp == NULL)
328         *pp = empty_option;
329 }
330
331 /*
332  * Set global value for string option when it's a local option.
333  */
334     static void
335 set_string_option_global(
336     int         opt_idx,        // option index
337     char_u      **varp)         // pointer to option variable
338 {
339     char_u      **p, *s;
340
341     // the global value is always allocated
342     if (is_window_local_option(opt_idx))
343         p = (char_u **)GLOBAL_WO(varp);
344     else
345         p = (char_u **)get_option_var(opt_idx);
346     if (!is_global_option(opt_idx)
347             && p != varp
348             && (s = vim_strsave(*varp)) != NULL)
349     {
350         free_string_option(*p);
351         *p = s;
352     }
353 }
354
355 /*
356  * Set a string option to a new value (without checking the effect).
357  * The string is copied into allocated memory.
358  * if ("opt_idx" == -1) "name" is used, otherwise "opt_idx" is used.
359  * When "set_sid" is zero set the scriptID to current_sctx.sc_sid.  When
360  * "set_sid" is SID_NONE don't set the scriptID.  Otherwise set the scriptID to
361  * "set_sid".
362  */
363     void
364 set_string_option_direct(
365     char_u      *name,
366     int         opt_idx,
367     char_u      *val,
368     int         opt_flags,      // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
369     int         set_sid UNUSED)
370 {
371     char_u      *s;
372     char_u      **varp;
373     int         both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
374     int         idx = opt_idx;
375
376     if (idx == -1)              // use name
377     {
378         idx = findoption(name);
379         if (idx < 0)    // not found (should not happen)
380         {
381             semsg(_(e_internal_error_str), "set_string_option_direct()");
382             siemsg(_("For option %s"), name);
383             return;
384         }
385     }
386
387     if (is_hidden_option(idx))          // can't set hidden option
388         return;
389
390     s = vim_strsave(val);
391     if (s == NULL)
392         return;
393
394     varp = (char_u **)get_option_varp_scope(idx,
395             both ? OPT_LOCAL : opt_flags);
396     if ((opt_flags & OPT_FREE) && (get_option_flags(idx) & P_ALLOCED))
397         free_string_option(*varp);
398     *varp = s;
399
400     // For buffer/window local option may also set the global value.
401     if (both)
402         set_string_option_global(idx, varp);
403
404     set_option_flag(idx, P_ALLOCED);
405
406     // When setting both values of a global option with a local value,
407     // make the local value empty, so that the global value is used.
408     if (is_global_local_option(idx) && both)
409     {
410         free_string_option(*varp);
411         *varp = empty_option;
412     }
413 # ifdef FEAT_EVAL
414     if (set_sid != SID_NONE)
415     {
416         sctx_T script_ctx;
417
418         if (set_sid == 0)
419             script_ctx = current_sctx;
420         else
421         {
422             script_ctx.sc_sid = set_sid;
423             script_ctx.sc_seq = 0;
424             script_ctx.sc_lnum = 0;
425             script_ctx.sc_version = 1;
426         }
427         set_option_sctx_idx(idx, opt_flags, script_ctx);
428     }
429 # endif
430 }
431
432 /*
433  * Like set_string_option_direct(), but for a window-local option in "wp".
434  * Blocks autocommands to avoid the old curwin becoming invalid.
435  */
436     void
437 set_string_option_direct_in_win(
438         win_T           *wp,
439         char_u          *name,
440         int             opt_idx,
441         char_u          *val,
442         int             opt_flags,
443         int             set_sid)
444 {
445     win_T       *save_curwin = curwin;
446
447     block_autocmds();
448     curwin = wp;
449     curbuf = curwin->w_buffer;
450     set_string_option_direct(name, opt_idx, val, opt_flags, set_sid);
451     curwin = save_curwin;
452     curbuf = curwin->w_buffer;
453     unblock_autocmds();
454 }
455
456 #if defined(FEAT_PROP_POPUP) || defined(PROTO)
457 /*
458  * Like set_string_option_direct(), but for a buffer-local option in "buf".
459  * Blocks autocommands to avoid the old curbuf becoming invalid.
460  */
461     void
462 set_string_option_direct_in_buf(
463         buf_T           *buf,
464         char_u          *name,
465         int             opt_idx,
466         char_u          *val,
467         int             opt_flags,
468         int             set_sid)
469 {
470     buf_T       *save_curbuf = curbuf;
471
472     block_autocmds();
473     curbuf = buf;
474     curwin->w_buffer = curbuf;
475     set_string_option_direct(name, opt_idx, val, opt_flags, set_sid);
476     curbuf = save_curbuf;
477     curwin->w_buffer = curbuf;
478     unblock_autocmds();
479 }
480 #endif
481
482 /*
483  * Set a string option to a new value, and handle the effects.
484  *
485  * Returns NULL on success or an untranslated error message on error.
486  */
487     char *
488 set_string_option(
489     int         opt_idx,
490     char_u      *value,
491     int         opt_flags,      // OPT_LOCAL and/or OPT_GLOBAL
492     char        *errbuf)
493 {
494     char_u      *s;
495     char_u      **varp;
496     char_u      *oldval;
497 #if defined(FEAT_EVAL)
498     char_u      *oldval_l = NULL;
499     char_u      *oldval_g = NULL;
500     char_u      *saved_oldval = NULL;
501     char_u      *saved_oldval_l = NULL;
502     char_u      *saved_oldval_g = NULL;
503     char_u      *saved_newval = NULL;
504 #endif
505     char        *errmsg = NULL;
506     int         value_checked = FALSE;
507
508     if (is_hidden_option(opt_idx))      // don't set hidden option
509         return NULL;
510
511     s = vim_strsave(value == NULL ? (char_u *)"" : value);
512     if (s == NULL)
513         return NULL;
514
515     varp = (char_u **)get_option_varp_scope(opt_idx,
516             (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
517             ? (is_global_local_option(opt_idx)
518                 ? OPT_GLOBAL : OPT_LOCAL)
519             : opt_flags);
520     oldval = *varp;
521 #if defined(FEAT_EVAL)
522     if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
523     {
524         oldval_l = *(char_u **)get_option_varp_scope(opt_idx, OPT_LOCAL);
525         oldval_g = *(char_u **)get_option_varp_scope(opt_idx, OPT_GLOBAL);
526     }
527 #endif
528     *varp = s;
529
530 #if defined(FEAT_EVAL)
531     if (!starting
532 # ifdef FEAT_CRYPT
533             && !is_crypt_key_option(opt_idx)
534 # endif
535        )
536     {
537         if (oldval_l != NULL)
538             saved_oldval_l = vim_strsave(oldval_l);
539         if (oldval_g != NULL)
540             saved_oldval_g = vim_strsave(oldval_g);
541         saved_oldval = vim_strsave(oldval);
542         saved_newval = vim_strsave(s);
543     }
544 #endif
545     if ((errmsg = did_set_string_option(opt_idx, varp, oldval, value, errbuf,
546                     opt_flags, &value_checked)) == NULL)
547         did_set_option(opt_idx, opt_flags, TRUE, value_checked);
548
549 #if defined(FEAT_EVAL)
550     // call autocommand after handling side effects
551     if (errmsg == NULL)
552         trigger_optionset_string(opt_idx, opt_flags,
553                 saved_oldval, saved_oldval_l,
554                 saved_oldval_g, saved_newval);
555     vim_free(saved_oldval);
556     vim_free(saved_oldval_l);
557     vim_free(saved_oldval_g);
558     vim_free(saved_newval);
559 #endif
560     return errmsg;
561 }
562
563 /*
564  * Return TRUE if "val" is a valid 'filetype' name.
565  * Also used for 'syntax' and 'keymap'.
566  */
567     static int
568 valid_filetype(char_u *val)
569 {
570     return valid_name(val, ".-_");
571 }
572
573 #ifdef FEAT_STL_OPT
574 /*
575  * Check validity of options with the 'statusline' format.
576  * Return an untranslated error message or NULL.
577  */
578     static char *
579 check_stl_option(char_u *s)
580 {
581     int         groupdepth = 0;
582     static char errbuf[80];
583
584     while (*s)
585     {
586         // Check for valid keys after % sequences
587         while (*s && *s != '%')
588             s++;
589         if (!*s)
590             break;
591         s++;
592         if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_SEPARATE)
593         {
594             s++;
595             continue;
596         }
597         if (*s == ')')
598         {
599             s++;
600             if (--groupdepth < 0)
601                 break;
602             continue;
603         }
604         if (*s == '-')
605             s++;
606         while (VIM_ISDIGIT(*s))
607             s++;
608         if (*s == STL_USER_HL)
609             continue;
610         if (*s == '.')
611         {
612             s++;
613             while (*s && VIM_ISDIGIT(*s))
614                 s++;
615         }
616         if (*s == '(')
617         {
618             groupdepth++;
619             continue;
620         }
621         if (vim_strchr(STL_ALL, *s) == NULL)
622         {
623             return illegal_char(errbuf, *s);
624         }
625         if (*s == '{')
626         {
627             int reevaluate = (*++s == '%');
628
629             if (reevaluate && *++s == '}')
630                 // "}" is not allowed immediately after "%{%"
631                 return illegal_char(errbuf, '}');
632             while ((*s != '}' || (reevaluate && s[-1] != '%')) && *s)
633                 s++;
634             if (*s != '}')
635                 return e_unclosed_expression_sequence;
636         }
637     }
638     if (groupdepth != 0)
639         return e_unbalanced_groups;
640     return NULL;
641 }
642 #endif
643
644 /*
645  * Check for a "normal" directory or file name in some options.  Disallow a
646  * path separator (slash and/or backslash), wildcards and characters that are
647  * often illegal in a file name. Be more permissive if "secure" is off.
648  */
649     static int
650 check_illegal_path_names(int opt_idx, char_u **varp)
651 {
652     return (((get_option_flags(opt_idx) & P_NFNAME)
653                 && vim_strpbrk(*varp, (char_u *)(secure
654                         ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL)
655             || ((get_option_flags(opt_idx) & P_NDNAME)
656                 && vim_strpbrk(*varp, (char_u *)"*?[|;&<>\r\n") != NULL));
657 }
658
659 /*
660  * The 'term' option is changed.
661  */
662     static char *
663 did_set_term(int *opt_idx, long_u *free_oldval)
664 {
665     char *errmsg = NULL;
666
667     if (T_NAME[0] == NUL)
668         errmsg = e_cannot_set_term_to_empty_string;
669 #ifdef FEAT_GUI
670     else if (gui.in_use)
671         errmsg = e_cannot_change_term_in_GUI;
672     else if (term_is_gui(T_NAME))
673         errmsg = e_use_gui_to_start_GUI;
674 #endif
675     else if (set_termname(T_NAME) == FAIL)
676         errmsg = e_not_found_in_termcap;
677     else
678     {
679         // Screen colors may have changed.
680         redraw_later_clear();
681
682         // Both 'term' and 'ttytype' point to T_NAME, only set the
683         // P_ALLOCED flag on 'term'.
684         *opt_idx = findoption((char_u *)"term");
685         if (*opt_idx >= 0)
686             *free_oldval = (get_option_flags(*opt_idx) & P_ALLOCED);
687     }
688
689     return errmsg;
690 }
691
692 /*
693  * The 'backupcopy' option is changed.
694  */
695     char *
696 did_set_backupcopy(optset_T *args)
697 {
698     char_u              *bkc = p_bkc;
699     unsigned int        *flags = &bkc_flags;
700     char                *errmsg = NULL;
701
702     if (args->os_flags & OPT_LOCAL)
703     {
704         bkc = curbuf->b_p_bkc;
705         flags = &curbuf->b_bkc_flags;
706     }
707
708     if ((args->os_flags & OPT_LOCAL) && *bkc == NUL)
709         // make the local value empty: use the global value
710         *flags = 0;
711     else
712     {
713         if (opt_strings_flags(bkc, p_bkc_values, flags, TRUE) != OK)
714             errmsg = e_invalid_argument;
715         if ((((int)*flags & BKC_AUTO) != 0)
716                 + (((int)*flags & BKC_YES) != 0)
717                 + (((int)*flags & BKC_NO) != 0) != 1)
718         {
719             // Must have exactly one of "auto", "yes"  and "no".
720             (void)opt_strings_flags(args->os_oldval.string, p_bkc_values,
721                                                                   flags, TRUE);
722             errmsg = e_invalid_argument;
723         }
724     }
725
726     return errmsg;
727 }
728
729 /*
730  * The 'backupext' or the 'patchmode' option is changed.
731  */
732     char *
733 did_set_backupext_or_patchmode(optset_T *args UNUSED)
734 {
735     if (STRCMP(*p_bex == '.' ? p_bex + 1 : p_bex,
736                 *p_pm == '.' ? p_pm + 1 : p_pm) == 0)
737         return e_backupext_and_patchmode_are_equal;
738
739     return NULL;
740 }
741
742 #if defined(FEAT_LINEBREAK) || defined(PROTO)
743 /*
744  * The 'breakindentopt' option is changed.
745  */
746     char *
747 did_set_breakindentopt(optset_T *args UNUSED)
748 {
749     char *errmsg = NULL;
750
751     if (briopt_check(curwin) == FAIL)
752         errmsg = e_invalid_argument;
753     // list setting requires a redraw
754     if (curwin->w_briopt_list)
755         redraw_all_later(UPD_NOT_VALID);
756
757     return errmsg;
758 }
759 #endif
760
761 /*
762  * The 'isident' or the 'iskeyword' or the 'isprint' or the 'isfname' option is
763  * changed.
764  */
765     char *
766 did_set_isopt(optset_T *args)
767 {
768     // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[]
769     // If the new option is invalid, use old value.
770     // 'lisp' option: refill g_chartab[] for '-' char.
771     if (init_chartab() == FAIL)
772     {
773         args->os_restore_chartab = TRUE;// need to restore the chartab.
774         return e_invalid_argument;      // error in value
775     }
776
777     return NULL;
778 }
779
780 /*
781  * The 'helpfile' option is changed.
782  */
783     char *
784 did_set_helpfile(optset_T *args UNUSED)
785 {
786     // May compute new values for $VIM and $VIMRUNTIME
787     if (didset_vim)
788         vim_unsetenv_ext((char_u *)"VIM");
789     if (didset_vimruntime)
790         vim_unsetenv_ext((char_u *)"VIMRUNTIME");
791     return NULL;
792 }
793
794 #if defined(FEAT_SYN_HL) || defined(PROTO)
795 /*
796  * The 'colorcolumn' option is changed.
797  */
798     char *
799 did_set_colorcolumn(optset_T *args UNUSED)
800 {
801     return check_colorcolumn(curwin);
802 }
803
804 /*
805  * The 'cursorlineopt' option is changed.
806  */
807     char *
808 did_set_cursorlineopt(optset_T *args)
809 {
810     if (*args->os_varp == NUL
811             || fill_culopt_flags(args->os_varp, curwin) != OK)
812         return e_invalid_argument;
813
814     return NULL;
815 }
816 #endif
817
818 #if defined(FEAT_MULTI_LANG) || defined(PROTO)
819 /*
820  * The 'helplang' option is changed.
821  */
822     char *
823 did_set_helplang(optset_T *args UNUSED)
824 {
825     char *errmsg = NULL;
826
827     // Check for "", "ab", "ab,cd", etc.
828     for (char_u *s = p_hlg; *s != NUL; s += 3)
829     {
830         if (s[1] == NUL || ((s[2] != ',' || s[3] == NUL) && s[2] != NUL))
831         {
832             errmsg = e_invalid_argument;
833             break;
834         }
835         if (s[2] == NUL)
836             break;
837     }
838
839     return errmsg;
840 }
841 #endif
842
843 /*
844  * The 'highlight' option is changed.
845  */
846     char *
847 did_set_highlight(optset_T *args UNUSED)
848 {
849     if (highlight_changed() == FAIL)
850         return e_invalid_argument;      // invalid flags
851
852     return NULL;
853 }
854
855 /*
856  * An option that accepts a list of flags is changed.
857  * e.g. 'viewoptions', 'switchbuf', 'casemap', etc.
858  */
859     static char *
860 did_set_opt_flags(char_u *val, char **values, unsigned *flagp, int list)
861 {
862     if (opt_strings_flags(val, values, flagp, list) == FAIL)
863         return e_invalid_argument;
864
865     return NULL;
866 }
867
868 /*
869  * An option that accepts a list of string values is changed.
870  * e.g. 'nrformats', 'scrollopt', 'wildoptions', etc.
871  */
872     static char *
873 did_set_opt_strings(char_u *val, char **values, int list)
874 {
875     return did_set_opt_flags(val, values, NULL, list);
876 }
877
878 /*
879  * The 'belloff' option is changed.
880  */
881     char *
882 did_set_belloff(optset_T *args UNUSED)
883 {
884     return did_set_opt_flags(p_bo, p_bo_values, &bo_flags, TRUE);
885 }
886
887 /*
888  * The 'casemap' option is changed.
889  */
890     char *
891 did_set_casemap(optset_T *args UNUSED)
892 {
893     return did_set_opt_flags(p_cmp, p_cmp_values, &cmp_flags, TRUE);
894 }
895
896 /*
897  * The 'scrollopt' option is changed.
898  */
899     char *
900 did_set_scrollopt(optset_T *args UNUSED)
901 {
902     return did_set_opt_strings(p_sbo, p_scbopt_values, TRUE);
903 }
904
905 /*
906  * The 'selectmode' option is changed.
907  */
908     char *
909 did_set_selectmode(optset_T *args UNUSED)
910 {
911     return did_set_opt_strings(p_slm, p_slm_values, TRUE);
912 }
913
914 /*
915  * The 'showcmdloc' option is changed.
916  */
917     char *
918 did_set_showcmdloc(optset_T *args UNUSED)
919 {
920     return did_set_opt_strings(p_sloc, p_sloc_values, FALSE);
921 }
922
923 /*
924  * The 'splitkeep' option is changed.
925  */
926     char *
927 did_set_splitkeep(optset_T *args UNUSED)
928 {
929     return did_set_opt_strings(p_spk, p_spk_values, FALSE);
930 }
931
932 /*
933  * The 'swapsync' option is changed.
934  */
935     char *
936 did_set_swapsync(optset_T *args UNUSED)
937 {
938     return did_set_opt_strings(p_sws, p_sws_values, FALSE);
939 }
940
941 /*
942  * The 'switchbuf' option is changed.
943  */
944     char *
945 did_set_switchbuf(optset_T *args UNUSED)
946 {
947     return did_set_opt_flags(p_swb, p_swb_values, &swb_flags, TRUE);
948 }
949
950 #if defined(FEAT_SESSION) || defined(PROTO)
951 /*
952  * The 'sessionoptions' option is changed.
953  */
954     char *
955 did_set_sessionoptions(optset_T *args)
956 {
957     if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, TRUE) != OK)
958         return e_invalid_argument;
959     if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR))
960     {
961         // Don't allow both "sesdir" and "curdir".
962         (void)opt_strings_flags(args->os_oldval.string, p_ssop_values,
963                                                         &ssop_flags, TRUE);
964         return e_invalid_argument;
965     }
966
967     return NULL;
968 }
969
970 /*
971  * The 'viewoptions' option is changed.
972  */
973     char *
974 did_set_viewoptions(optset_T *args UNUSED)
975 {
976     return did_set_opt_flags(p_vop, p_ssop_values, &vop_flags, TRUE);
977 }
978 #endif
979
980 /*
981  * The 'ambiwidth' option is changed.
982  */
983     char *
984 did_set_ambiwidth(optset_T *args UNUSED)
985 {
986     if (check_opt_strings(p_ambw, p_ambw_values, FALSE) != OK)
987         return e_invalid_argument;
988
989     return check_chars_options();
990 }
991
992 /*
993  * The 'background' option is changed.
994  */
995     char *
996 did_set_background(optset_T *args UNUSED)
997 {
998     if (check_opt_strings(p_bg, p_bg_values, FALSE) == FAIL)
999         return e_invalid_argument;
1000
1001 #ifdef FEAT_EVAL
1002     int dark = (*p_bg == 'd');
1003 #endif
1004
1005     init_highlight(FALSE, FALSE);
1006
1007 #ifdef FEAT_EVAL
1008     if (dark != (*p_bg == 'd')
1009             && get_var_value((char_u *)"g:colors_name") != NULL)
1010     {
1011         // The color scheme must have set 'background' back to another
1012         // value, that's not what we want here.  Disable the color
1013         // scheme and set the colors again.
1014         do_unlet((char_u *)"g:colors_name", TRUE);
1015         free_string_option(p_bg);
1016         p_bg = vim_strsave((char_u *)(dark ? "dark" : "light"));
1017         check_string_option(&p_bg);
1018         init_highlight(FALSE, FALSE);
1019     }
1020 #endif
1021 #ifdef FEAT_TERMINAL
1022     term_update_colors_all();
1023 #endif
1024
1025     return NULL;
1026 }
1027
1028 /*
1029  * The 'wildmode' option is changed.
1030  */
1031     char *
1032 did_set_wildmode(optset_T *args UNUSED)
1033 {
1034     if (check_opt_wim() == FAIL)
1035         return e_invalid_argument;
1036     return NULL;
1037 }
1038
1039 /*
1040  * The 'wildoptions' option is changed.
1041  */
1042     char *
1043 did_set_wildoptions(optset_T *args UNUSED)
1044 {
1045     return did_set_opt_strings(p_wop, p_wop_values, TRUE);
1046 }
1047
1048 #if defined(FEAT_WAK) || defined(PROTO)
1049 /*
1050  * The 'winaltkeys' option is changed.
1051  */
1052     char *
1053 did_set_winaltkeys(optset_T *args UNUSED)
1054 {
1055     char *errmsg = NULL;
1056
1057     if (*p_wak == NUL
1058             || check_opt_strings(p_wak, p_wak_values, FALSE) != OK)
1059         errmsg = e_invalid_argument;
1060 # ifdef FEAT_MENU
1061 #  if defined(FEAT_GUI_MOTIF)
1062     else if (gui.in_use)
1063         gui_motif_set_mnemonics(p_wak[0] == 'y' || p_wak[0] == 'm');
1064 #  elif defined(FEAT_GUI_GTK)
1065     else if (gui.in_use)
1066         gui_gtk_set_mnemonics(p_wak[0] == 'y' || p_wak[0] == 'm');
1067 #  endif
1068 # endif
1069     return errmsg;
1070 }
1071 #endif
1072
1073 /*
1074  * The 'wincolor' option is changed.
1075  */
1076     char *
1077 did_set_wincolor(optset_T *args UNUSED)
1078 {
1079 #ifdef FEAT_TERMINAL
1080     term_update_wincolor(curwin);
1081 #endif
1082     return NULL;
1083 }
1084
1085 /*
1086  * The 'eadirection' option is changed.
1087  */
1088     char *
1089 did_set_eadirection(optset_T *args UNUSED)
1090 {
1091     return did_set_opt_strings(p_ead, p_ead_values, FALSE);
1092 }
1093
1094 /*
1095  * The 'eventignore' option is changed.
1096  */
1097     char *
1098 did_set_eventignore(optset_T *args UNUSED)
1099 {
1100     if (check_ei() == FAIL)
1101         return e_invalid_argument;
1102     return NULL;
1103 }
1104
1105 /*
1106  * One of the 'encoding', 'fileencoding', 'termencoding' or 'makeencoding'
1107  * options is changed.
1108  */
1109     static char *
1110 did_set_encoding(char_u **varp, char_u **gvarp, int opt_flags)
1111 {
1112     char        *errmsg = NULL;
1113     char_u      *p;
1114
1115     if (gvarp == &p_fenc)
1116     {
1117         if (!curbuf->b_p_ma && opt_flags != OPT_GLOBAL)
1118             errmsg = e_cannot_make_changes_modifiable_is_off;
1119         else if (vim_strchr(*varp, ',') != NULL)
1120             // No comma allowed in 'fileencoding'; catches confusing it
1121             // with 'fileencodings'.
1122             errmsg = e_invalid_argument;
1123         else
1124         {
1125             // May show a "+" in the title now.
1126             redraw_titles();
1127             // Add 'fileencoding' to the swap file.
1128             ml_setflags(curbuf);
1129         }
1130     }
1131     if (errmsg == NULL)
1132     {
1133         // canonize the value, so that STRCMP() can be used on it
1134         p = enc_canonize(*varp);
1135         if (p != NULL)
1136         {
1137             vim_free(*varp);
1138             *varp = p;
1139         }
1140         if (varp == &p_enc)
1141         {
1142             errmsg = mb_init();
1143             redraw_titles();
1144         }
1145     }
1146
1147 #if defined(FEAT_GUI_GTK)
1148     if (errmsg == NULL && varp == &p_tenc && gui.in_use)
1149     {
1150         // GTK uses only a single encoding, and that is UTF-8.
1151         if (STRCMP(p_tenc, "utf-8") != 0)
1152             errmsg = e_cannot_be_changed_in_gtk_GUI;
1153     }
1154 #endif
1155
1156     if (errmsg == NULL)
1157     {
1158 #ifdef FEAT_KEYMAP
1159         // When 'keymap' is used and 'encoding' changes, reload the keymap
1160         // (with another encoding).
1161         if (varp == &p_enc && *curbuf->b_p_keymap != NUL)
1162             (void)keymap_init();
1163 #endif
1164
1165         // When 'termencoding' is not empty and 'encoding' changes or when
1166         // 'termencoding' changes, need to setup for keyboard input and
1167         // display output conversion.
1168         if (((varp == &p_enc && *p_tenc != NUL) || varp == &p_tenc))
1169         {
1170             if (convert_setup(&input_conv, p_tenc, p_enc) == FAIL
1171                     || convert_setup(&output_conv, p_enc, p_tenc) == FAIL)
1172             {
1173                 semsg(_(e_cannot_convert_between_str_and_str),
1174                         p_tenc, p_enc);
1175                 errmsg = e_invalid_argument;
1176             }
1177         }
1178
1179 #if defined(MSWIN)
1180         // $HOME, $VIM and $VIMRUNTIME may have characters in active code page.
1181         if (varp == &p_enc)
1182         {
1183             init_homedir();
1184             init_vimdir();
1185         }
1186 #endif
1187     }
1188
1189     return errmsg;
1190 }
1191
1192 #if defined(FEAT_POSTSCRIPT) || defined(PROTO)
1193 /*
1194  * The 'printencoding' option is changed.
1195  */
1196     char *
1197 did_set_printencoding(optset_T *args UNUSED)
1198 {
1199     char_u      *s, *p;
1200
1201     // Canonize 'printencoding' if VIM standard one
1202     p = enc_canonize(p_penc);
1203     if (p != NULL)
1204     {
1205         vim_free(p_penc);
1206         p_penc = p;
1207     }
1208     else
1209     {
1210         // Ensure lower case and '-' for '_'
1211         for (s = p_penc; *s != NUL; s++)
1212         {
1213             if (*s == '_')
1214                 *s = '-';
1215             else
1216                 *s = TOLOWER_ASC(*s);
1217         }
1218     }
1219
1220     return NULL;
1221 }
1222 #endif
1223
1224 #if (defined(FEAT_XIM) && defined(FEAT_GUI_GTK)) || defined(PROTO)
1225 /*
1226  * The 'imactivatekey' option is changed.
1227  */
1228     char *
1229 did_set_imactivatekey(optset_T *args UNUSED)
1230 {
1231     if (!im_xim_isvalid_imactivate())
1232         return e_invalid_argument;
1233     return NULL;
1234 }
1235 #endif
1236
1237 #if defined(FEAT_KEYMAP) || defined(PROTO)
1238 /*
1239  * The 'keymap' option is changed.
1240  */
1241     char *
1242 did_set_keymap(optset_T *args)
1243 {
1244     char *errmsg = NULL;
1245
1246     if (!valid_filetype(args->os_varp))
1247         errmsg = e_invalid_argument;
1248     else
1249     {
1250         int         secure_save = secure;
1251
1252         // Reset the secure flag, since the value of 'keymap' has
1253         // been checked to be safe.
1254         secure = 0;
1255
1256         // load or unload key mapping tables
1257         errmsg = keymap_init();
1258
1259         secure = secure_save;
1260
1261         // Since we check the value, there is no need to set P_INSECURE,
1262         // even when the value comes from a modeline.
1263         args->os_value_checked = TRUE;
1264     }
1265
1266     if (errmsg == NULL)
1267     {
1268         if (*curbuf->b_p_keymap != NUL)
1269         {
1270             // Installed a new keymap, switch on using it.
1271             curbuf->b_p_iminsert = B_IMODE_LMAP;
1272             if (curbuf->b_p_imsearch != B_IMODE_USE_INSERT)
1273                 curbuf->b_p_imsearch = B_IMODE_LMAP;
1274         }
1275         else
1276         {
1277             // Cleared the keymap, may reset 'iminsert' and 'imsearch'.
1278             if (curbuf->b_p_iminsert == B_IMODE_LMAP)
1279                 curbuf->b_p_iminsert = B_IMODE_NONE;
1280             if (curbuf->b_p_imsearch == B_IMODE_LMAP)
1281                 curbuf->b_p_imsearch = B_IMODE_USE_INSERT;
1282         }
1283         if ((args->os_flags & OPT_LOCAL) == 0)
1284         {
1285             set_iminsert_global();
1286             set_imsearch_global();
1287         }
1288         status_redraw_curbuf();
1289     }
1290
1291     return errmsg;
1292 }
1293 #endif
1294
1295 /*
1296  * The 'fileformat' option is changed.
1297  */
1298     char *
1299 did_set_fileformat(optset_T *args)
1300 {
1301     if (!curbuf->b_p_ma && !(args->os_flags & OPT_GLOBAL))
1302         return e_cannot_make_changes_modifiable_is_off;
1303     else if (check_opt_strings(args->os_varp, p_ff_values, FALSE) != OK)
1304         return e_invalid_argument;
1305
1306     // may also change 'textmode'
1307     if (get_fileformat(curbuf) == EOL_DOS)
1308         curbuf->b_p_tx = TRUE;
1309     else
1310         curbuf->b_p_tx = FALSE;
1311     redraw_titles();
1312     // update flag in swap file
1313     ml_setflags(curbuf);
1314     // Redraw needed when switching to/from "mac": a CR in the text
1315     // will be displayed differently.
1316     if (get_fileformat(curbuf) == EOL_MAC || *args->os_oldval.string == 'm')
1317         redraw_curbuf_later(UPD_NOT_VALID);
1318
1319     return NULL;
1320 }
1321
1322 /*
1323  * The 'fileformats' option is changed.
1324  */
1325     char *
1326 did_set_fileformats(optset_T *args UNUSED)
1327 {
1328     if (check_opt_strings(p_ffs, p_ff_values, TRUE) != OK)
1329         return e_invalid_argument;
1330
1331     // also change 'textauto'
1332     if (*p_ffs == NUL)
1333         p_ta = FALSE;
1334     else
1335         p_ta = TRUE;
1336
1337     return NULL;
1338 }
1339
1340 #if defined(FEAT_CRYPT) || defined(PROTO)
1341 /*
1342  * The 'cryptkey' option is changed.
1343  */
1344     char *
1345 did_set_cryptkey(optset_T *args)
1346 {
1347     // Make sure the ":set" command doesn't show the new value in the
1348     // history.
1349     remove_key_from_history();
1350
1351     if (STRCMP(curbuf->b_p_key, args->os_oldval.string) != 0)
1352     {
1353         // Need to update the swapfile.
1354         ml_set_crypt_key(curbuf, args->os_oldval.string,
1355                 *curbuf->b_p_cm == NUL ? p_cm : curbuf->b_p_cm);
1356         changed_internal();
1357     }
1358
1359     return NULL;
1360 }
1361
1362 /*
1363  * The 'cryptmethod' option is changed.
1364  */
1365     char *
1366 did_set_cryptmethod(optset_T *args)
1367 {
1368     char_u  *p;
1369     char_u  *s;
1370
1371     if (args->os_flags & OPT_LOCAL)
1372         p = curbuf->b_p_cm;
1373     else
1374         p = p_cm;
1375     if (check_opt_strings(p, p_cm_values, TRUE) != OK)
1376         return e_invalid_argument;
1377     else if (crypt_self_test() == FAIL)
1378         return e_invalid_argument;
1379
1380     // When setting the global value to empty, make it "zip".
1381     if (*p_cm == NUL)
1382     {
1383         free_string_option(p_cm);
1384         p_cm = vim_strsave((char_u *)"zip");
1385     }
1386     // When using ":set cm=name" the local value is going to be empty.
1387     // Do that here, otherwise the crypt functions will still use the
1388     // local value.
1389     if ((args->os_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
1390     {
1391         free_string_option(curbuf->b_p_cm);
1392         curbuf->b_p_cm = empty_option;
1393     }
1394
1395     // Need to update the swapfile when the effective method changed.
1396     // Set "s" to the effective old value, "p" to the effective new
1397     // method and compare.
1398     if ((args->os_flags & OPT_LOCAL) && *args->os_oldval.string == NUL)
1399         s = p_cm;  // was previously using the global value
1400     else
1401         s = args->os_oldval.string;
1402     if (*curbuf->b_p_cm == NUL)
1403         p = p_cm;  // is now using the global value
1404     else
1405         p = curbuf->b_p_cm;
1406     if (STRCMP(s, p) != 0)
1407         ml_set_crypt_key(curbuf, curbuf->b_p_key, s);
1408
1409     // If the global value changes need to update the swapfile for all
1410     // buffers using that value.
1411     if ((args->os_flags & OPT_GLOBAL)
1412             && STRCMP(p_cm, args->os_oldval.string) != 0)
1413     {
1414         buf_T   *buf;
1415
1416         FOR_ALL_BUFFERS(buf)
1417             if (buf != curbuf && *buf->b_p_cm == NUL)
1418                 ml_set_crypt_key(buf, buf->b_p_key, args->os_oldval.string);
1419     }
1420     return NULL;
1421 }
1422 #endif
1423
1424 /*
1425  * The 'matchpairs' option is changed.
1426  */
1427     char *
1428 did_set_matchpairs(optset_T *args)
1429 {
1430     char_u      *p;
1431
1432     if (has_mbyte)
1433     {
1434         for (p = args->os_varp; *p != NUL; ++p)
1435         {
1436             int x2 = -1;
1437             int x3 = -1;
1438
1439             p += mb_ptr2len(p);
1440             if (*p != NUL)
1441                 x2 = *p++;
1442             if (*p != NUL)
1443             {
1444                 x3 = mb_ptr2char(p);
1445                 p += mb_ptr2len(p);
1446             }
1447             if (x2 != ':' || x3 == -1 || (*p != NUL && *p != ','))
1448                 return e_invalid_argument;
1449             if (*p == NUL)
1450                 break;
1451         }
1452     }
1453     else
1454     {
1455         // Check for "x:y,x:y"
1456         for (p = args->os_varp; *p != NUL; p += 4)
1457         {
1458             if (p[1] != ':' || p[2] == NUL || (p[3] != NUL && p[3] != ','))
1459                 return e_invalid_argument;
1460             if (p[3] == NUL)
1461                 break;
1462         }
1463     }
1464
1465     return NULL;
1466 }
1467
1468 /*
1469  * The 'comments' option is changed.
1470  */
1471     char *
1472 did_set_comments(optset_T *args)
1473 {
1474     char_u      *s;
1475     char        *errmsg = NULL;
1476
1477     for (s = args->os_varp; *s; )
1478     {
1479         while (*s && *s != ':')
1480         {
1481             if (vim_strchr((char_u *)COM_ALL, *s) == NULL
1482                     && !VIM_ISDIGIT(*s) && *s != '-')
1483             {
1484                 errmsg = illegal_char(args->os_errbuf, *s);
1485                 break;
1486             }
1487             ++s;
1488         }
1489         if (*s++ == NUL)
1490             errmsg = e_missing_colon;
1491         else if (*s == ',' || *s == NUL)
1492             errmsg = e_zero_length_string;
1493         if (errmsg != NULL)
1494             break;
1495         while (*s && *s != ',')
1496         {
1497             if (*s == '\\' && s[1] != NUL)
1498                 ++s;
1499             ++s;
1500         }
1501         s = skip_to_option_part(s);
1502     }
1503
1504     return errmsg;
1505 }
1506
1507 /*
1508  * The global 'listchars' or 'fillchars' option is changed.
1509  */
1510     static char *
1511 did_set_global_listfillchars(char_u **varp, int opt_flags)
1512 {
1513     char        *errmsg = NULL;
1514     char_u      **local_ptr = varp == &p_lcs
1515         ? &curwin->w_p_lcs : &curwin->w_p_fcs;
1516
1517     // only apply the global value to "curwin" when it does not have a
1518     // local value
1519     errmsg = set_chars_option(curwin, varp,
1520             **local_ptr == NUL || !(opt_flags & OPT_GLOBAL));
1521     if (errmsg != NULL)
1522         return errmsg;
1523
1524     tabpage_T   *tp;
1525     win_T       *wp;
1526
1527     // If the current window is set to use the global
1528     // 'listchars'/'fillchars' value, clear the window-local value.
1529     if (!(opt_flags & OPT_GLOBAL))
1530         clear_string_option(local_ptr);
1531     FOR_ALL_TAB_WINDOWS(tp, wp)
1532     {
1533         // If the current window has a local value need to apply it
1534         // again, it was changed when setting the global value.
1535         // If no error was returned above, we don't expect an error
1536         // here, so ignore the return value.
1537         local_ptr = varp == &p_lcs ? &wp->w_p_lcs : &wp->w_p_fcs;
1538         if (**local_ptr == NUL)
1539             (void)set_chars_option(wp, local_ptr, TRUE);
1540     }
1541
1542     redraw_all_later(UPD_NOT_VALID);
1543
1544     return NULL;
1545 }
1546
1547 /*
1548  * The 'verbosefile' option is changed.
1549  */
1550     char *
1551 did_set_verbosefile(optset_T *args UNUSED)
1552 {
1553     verbose_stop();
1554     if (*p_vfile != NUL && verbose_open() == FAIL)
1555         return e_invalid_argument;
1556
1557     return NULL;
1558 }
1559
1560 #if defined(FEAT_VIMINFO) || defined(PROTO)
1561 /*
1562  * The 'viminfo' option is changed.
1563  */
1564     char *
1565 did_set_viminfo(optset_T *args)
1566 {
1567     char_u      *s;
1568     char        *errmsg = NULL;
1569
1570     for (s = p_viminfo; *s;)
1571     {
1572         // Check it's a valid character
1573         if (vim_strchr((char_u *)"!\"%'/:<@cfhnrs", *s) == NULL)
1574         {
1575             errmsg = illegal_char(args->os_errbuf, *s);
1576             break;
1577         }
1578         if (*s == 'n')  // name is always last one
1579             break;
1580         else if (*s == 'r') // skip until next ','
1581         {
1582             while (*++s && *s != ',')
1583                 ;
1584         }
1585         else if (*s == '%')
1586         {
1587             // optional number
1588             while (vim_isdigit(*++s))
1589                 ;
1590         }
1591         else if (*s == '!' || *s == 'h' || *s == 'c')
1592             ++s;                // no extra chars
1593         else            // must have a number
1594         {
1595             while (vim_isdigit(*++s))
1596                 ;
1597
1598             if (!VIM_ISDIGIT(*(s - 1)))
1599             {
1600                 if (args->os_errbuf != NULL)
1601                 {
1602                     sprintf(args->os_errbuf,
1603                             _(e_missing_number_after_angle_str_angle),
1604                             transchar_byte(*(s - 1)));
1605                     errmsg = args->os_errbuf;
1606                 }
1607                 else
1608                     errmsg = "";
1609                 break;
1610             }
1611         }
1612         if (*s == ',')
1613             ++s;
1614         else if (*s)
1615         {
1616             if (args->os_errbuf != NULL)
1617                 errmsg = e_missing_comma;
1618             else
1619                 errmsg = "";
1620             break;
1621         }
1622     }
1623     if (*p_viminfo && errmsg == NULL && get_viminfo_parameter('\'') < 0)
1624         errmsg = e_must_specify_a_value;
1625
1626     return errmsg;
1627 }
1628 #endif
1629
1630 /*
1631  * Some terminal option (t_xxx) is changed
1632  */
1633     static void
1634 did_set_term_option(char_u **varp, int *did_swaptcap UNUSED)
1635 {
1636     // ":set t_Co=0" and ":set t_Co=1" do ":set t_Co="
1637     if (varp == &T_CCO)
1638     {
1639         int colors = atoi((char *)T_CCO);
1640
1641         // Only reinitialize colors if t_Co value has really changed to
1642         // avoid expensive reload of colorscheme if t_Co is set to the
1643         // same value multiple times.
1644         if (colors != t_colors)
1645         {
1646             t_colors = colors;
1647             if (t_colors <= 1)
1648             {
1649                 vim_free(T_CCO);
1650                 T_CCO = empty_option;
1651             }
1652 #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
1653             if (is_term_win32())
1654             {
1655                 swap_tcap();
1656                 *did_swaptcap = TRUE;
1657             }
1658 #endif
1659             // We now have a different color setup, initialize it again.
1660             init_highlight(TRUE, FALSE);
1661         }
1662     }
1663     ttest(FALSE);
1664     if (varp == &T_ME)
1665     {
1666         out_str(T_ME);
1667         redraw_later(UPD_CLEAR);
1668 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL))
1669         // Since t_me has been set, this probably means that the user
1670         // wants to use this as default colors.  Need to reset default
1671         // background/foreground colors.
1672 # ifdef VIMDLL
1673         if (!gui.in_use && !gui.starting)
1674 # endif
1675             mch_set_normal_colors();
1676 #endif
1677     }
1678     if (varp == &T_BE && termcap_active)
1679     {
1680         MAY_WANT_TO_LOG_THIS;
1681
1682         if (*T_BE == NUL)
1683             // When clearing t_BE we assume the user no longer wants
1684             // bracketed paste, thus disable it by writing t_BD.
1685             out_str(T_BD);
1686         else
1687             out_str(T_BE);
1688     }
1689 }
1690
1691 #if defined(FEAT_LINEBREAK) || defined(PROTO)
1692 /*
1693  * The 'showbreak' option is changed.
1694  */
1695     char *
1696 did_set_showbreak(optset_T *args)
1697 {
1698     char_u      *s;
1699
1700     for (s = args->os_varp; *s; )
1701     {
1702         if (ptr2cells(s) != 1)
1703             return e_showbreak_contains_unprintable_or_wide_character;
1704         MB_PTR_ADV(s);
1705     }
1706
1707     return NULL;
1708 }
1709 #endif
1710
1711 #if defined(CURSOR_SHAPE) || defined(PROTO)
1712 /*
1713  * The 'guicursor' option is changed.
1714  */
1715     char *
1716 did_set_guicursor(optset_T *args UNUSED)
1717 {
1718     return parse_shape_opt(SHAPE_CURSOR);
1719 }
1720 #endif
1721
1722 #if defined(FEAT_GUI) || defined(PROTO)
1723 /*
1724  * The 'guifont' option is changed.
1725  */
1726     char *
1727 did_set_guifont(optset_T *args UNUSED)
1728 {
1729     char_u      *p;
1730     char        *errmsg = NULL;
1731
1732     if (gui.in_use)
1733     {
1734         p = p_guifont;
1735 # if defined(FEAT_GUI_GTK)
1736         // Put up a font dialog and let the user select a new value.
1737         // If this is cancelled go back to the old value but don't
1738         // give an error message.
1739         if (STRCMP(p, "*") == 0)
1740         {
1741             p = gui_mch_font_dialog(args->os_oldval.string);
1742             free_string_option(p_guifont);
1743             p_guifont = (p != NULL) ? p : vim_strsave(args->os_oldval.string);
1744         }
1745 # endif
1746         if (p != NULL && gui_init_font(p_guifont, FALSE) != OK)
1747         {
1748 # if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_PHOTON)
1749             if (STRCMP(p_guifont, "*") == 0)
1750             {
1751                 // Dialog was cancelled: Keep the old value without giving
1752                 // an error message.
1753                 free_string_option(p_guifont);
1754                 p_guifont = vim_strsave(args->os_oldval.string);
1755             }
1756             else
1757 # endif
1758                 errmsg = e_invalid_fonts;
1759         }
1760     }
1761
1762     return errmsg;
1763 }
1764
1765 # if defined(FEAT_XFONTSET) || defined(PROTO)
1766 /*
1767  * The 'guifontset' option is changed.
1768  */
1769     char *
1770 did_set_guifontset(optset_T *args UNUSED)
1771 {
1772     char *errmsg = NULL;
1773
1774     if (STRCMP(p_guifontset, "*") == 0)
1775         errmsg = e_cant_select_fontset;
1776     else if (gui.in_use && gui_init_font(p_guifontset, TRUE) != OK)
1777         errmsg = e_invalid_fontset;
1778
1779     return errmsg;
1780 }
1781 # endif
1782
1783 /*
1784  * The 'guifontwide' option is changed.
1785  */
1786     char *
1787 did_set_guifontwide(optset_T *args UNUSED)
1788 {
1789     char *errmsg = NULL;
1790
1791     if (STRCMP(p_guifontwide, "*") == 0)
1792         errmsg = e_cant_select_wide_font;
1793     else if (gui_get_wide_font() == FAIL)
1794         errmsg = e_invalid_wide_font;
1795
1796     return errmsg;
1797 }
1798 #endif
1799
1800 #if defined(FEAT_GUI_GTK) || defined(PROTO)
1801 /*
1802  * The 'guiligatures' option is changed.
1803  */
1804     char *
1805 did_set_guiligatures(optset_T *args UNUSED)
1806 {
1807     gui_set_ligatures();
1808     return NULL;
1809 }
1810 #endif
1811
1812 #if defined(FEAT_MOUSESHAPE) || defined(PROTO)
1813     char *
1814 did_set_mouseshape(optset_T *args UNUSED)
1815 {
1816     char *errmsg = NULL;
1817
1818     errmsg = parse_shape_opt(SHAPE_MOUSE);
1819     update_mouseshape(-1);
1820
1821     return errmsg;
1822 }
1823 #endif
1824
1825 /*
1826  * The 'titlestring' or the 'iconstring' option is changed.
1827  */
1828     static char *
1829 did_set_titleiconstring(optset_T *args UNUSED, int flagval UNUSED)
1830 {
1831 #ifdef FEAT_STL_OPT
1832     // NULL => statusline syntax
1833     if (vim_strchr(args->os_varp, '%')
1834                                     && check_stl_option(args->os_varp) == NULL)
1835         stl_syntax |= flagval;
1836     else
1837         stl_syntax &= ~flagval;
1838 #endif
1839     did_set_title();
1840
1841     return NULL;
1842 }
1843
1844 /*
1845  * The 'titlestring' option is changed.
1846  */
1847     char *
1848 did_set_titlestring(optset_T *args)
1849 {
1850     int flagval = 0;
1851
1852 #ifdef FEAT_STL_OPT
1853     flagval = STL_IN_TITLE;
1854 #endif
1855     return did_set_titleiconstring(args, flagval);
1856 }
1857
1858 /*
1859  * The 'iconstring' option is changed.
1860  */
1861     char *
1862 did_set_iconstring(optset_T *args)
1863 {
1864     int flagval = 0;
1865
1866 #ifdef FEAT_STL_OPT
1867     flagval = STL_IN_ICON;
1868 #endif
1869
1870     return did_set_titleiconstring(args, flagval);
1871 }
1872
1873 /*
1874  * An option which is a list of flags is set.  Valid values are in 'flags'.
1875  */
1876     static char *
1877 did_set_option_listflag(char_u *varp, char_u *flags, char *errbuf)
1878 {
1879     char_u      *s;
1880
1881     for (s = varp; *s; ++s)
1882         if (vim_strchr(flags, *s) == NULL)
1883             return illegal_char(errbuf, *s);
1884
1885     return NULL;
1886 }
1887
1888 #if defined(FEAT_GUI) || defined(PROTO)
1889 /*
1890  * The 'guioptions' option is changed.
1891  */
1892     char *
1893 did_set_guioptions(optset_T *args)
1894 {
1895     char *errmsg;
1896
1897     errmsg = did_set_option_listflag(args->os_varp, (char_u *)GO_ALL,
1898                                                         args->os_errbuf);
1899     if (errmsg != NULL)
1900         return errmsg;
1901
1902     gui_init_which_components(args->os_oldval.string);
1903     return NULL;
1904 }
1905 #endif
1906
1907 #if defined(FEAT_GUI_TABLINE)
1908 /*
1909  * The 'guitablabel' option is changed.
1910  */
1911     char *
1912 did_set_guitablabel(optset_T *args UNUSED)
1913 {
1914     redraw_tabline = TRUE;
1915     return NULL;
1916 }
1917 #endif
1918
1919 #if defined(UNIX) || defined(VMS) || defined(PROTO)
1920 /*
1921  * The 'ttymouse' option is changed.
1922  */
1923     char *
1924 did_set_ttymouse(optset_T *args UNUSED)
1925 {
1926     char *errmsg = NULL;
1927
1928     // Switch the mouse off before changing the escape sequences used for
1929     // that.
1930     mch_setmouse(FALSE);
1931     if (opt_strings_flags(p_ttym, p_ttym_values, &ttym_flags, FALSE) != OK)
1932         errmsg = e_invalid_argument;
1933     else
1934         check_mouse_termcode();
1935     if (termcap_active)
1936         setmouse();             // may switch it on again
1937
1938     return errmsg;
1939 }
1940 #endif
1941
1942 /*
1943  * The 'selection' option is changed.
1944  */
1945     char *
1946 did_set_selection(optset_T *args UNUSED)
1947 {
1948     if (*p_sel == NUL
1949             || check_opt_strings(p_sel, p_sel_values, FALSE) != OK)
1950         return e_invalid_argument;
1951
1952     return NULL;
1953 }
1954
1955 #if defined(FEAT_BROWSE) || defined(PROTO)
1956 /*
1957  * The 'browsedir' option is changed.
1958  */
1959     char *
1960 did_set_browsedir(optset_T *args UNUSED)
1961 {
1962     if (check_opt_strings(p_bsdir, p_bsdir_values, FALSE) != OK
1963             && !mch_isdir(p_bsdir))
1964         return e_invalid_argument;
1965
1966     return NULL;
1967 }
1968 #endif
1969
1970 /*
1971  * The 'keymodel' option is changed.
1972  */
1973     char *
1974 did_set_keymodel(optset_T *args UNUSED)
1975 {
1976     if (check_opt_strings(p_km, p_km_values, TRUE) != OK)
1977         return e_invalid_argument;
1978
1979     km_stopsel = (vim_strchr(p_km, 'o') != NULL);
1980     km_startsel = (vim_strchr(p_km, 'a') != NULL);
1981     return NULL;
1982 }
1983
1984 /*
1985  * The 'keyprotocol' option is changed.
1986  */
1987     char *
1988 did_set_keyprotocol(optset_T *args UNUSED)
1989 {
1990     if (match_keyprotocol(NULL) == KEYPROTOCOL_FAIL)
1991         return e_invalid_argument;
1992
1993     return NULL;
1994 }
1995
1996 /*
1997  * The 'mousemodel' option is changed.
1998  */
1999     char *
2000 did_set_mousemodel(optset_T *args UNUSED)
2001 {
2002     if (check_opt_strings(p_mousem, p_mousem_values, FALSE) != OK)
2003         return e_invalid_argument;
2004 #if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU) && (XmVersion <= 1002)
2005     else if (*p_mousem != *oldval)
2006         // Changed from "extend" to "popup" or "popup_setpos" or vv: need
2007         // to create or delete the popup menus.
2008         gui_motif_update_mousemodel(root_menu);
2009 #endif
2010
2011     return NULL;
2012 }
2013
2014 /*
2015  * The 'debug' option is changed.
2016  */
2017     char *
2018 did_set_debug(optset_T *args UNUSED)
2019 {
2020     return did_set_opt_strings(p_debug, p_debug_values, TRUE);
2021 }
2022
2023 /*
2024  * The 'display' option is changed.
2025  */
2026     char *
2027 did_set_display(optset_T *args UNUSED)
2028 {
2029     if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, TRUE) != OK)
2030         return e_invalid_argument;
2031
2032     (void)init_chartab();
2033     return NULL;
2034 }
2035
2036 #if defined(FEAT_SPELL) || defined(PROTO)
2037 /*
2038  * The 'spellfile' option is changed.
2039  */
2040     char *
2041 did_set_spellfile(optset_T *args)
2042 {
2043     if (!valid_spellfile(args->os_varp))
2044         return e_invalid_argument;
2045
2046     // If there is a window for this buffer in which 'spell' is set load the
2047     // wordlists.
2048     return did_set_spell_option(TRUE);
2049 }
2050
2051 /*
2052  * The 'spell' option is changed.
2053  */
2054     char *
2055 did_set_spelllang(optset_T *args)
2056 {
2057     if (!valid_spelllang(args->os_varp))
2058         return e_invalid_argument;
2059
2060     // If there is a window for this buffer in which 'spell' is set load the
2061     // wordlists.
2062     return did_set_spell_option(FALSE);
2063 }
2064
2065 /*
2066  * The 'spellcapcheck' option is changed.
2067  */
2068     char *
2069 did_set_spellcapcheck(optset_T *args UNUSED)
2070 {
2071     // compile the regexp program.
2072     return compile_cap_prog(curwin->w_s);
2073 }
2074
2075 /*
2076  * The 'spelloptions' option is changed.
2077  */
2078     char *
2079 did_set_spelloptions(optset_T *args)
2080 {
2081     if (*args->os_varp != NUL && STRCMP("camel", args->os_varp) != 0)
2082         return e_invalid_argument;
2083
2084     return NULL;
2085 }
2086
2087 /*
2088  * The 'spellsuggest' option is changed.
2089  */
2090     char *
2091 did_set_spellsuggest(optset_T *args UNUSED)
2092 {
2093     if (spell_check_sps() != OK)
2094         return e_invalid_argument;
2095
2096     return NULL;
2097 }
2098
2099 /*
2100  * The 'mkspellmem' option is changed.
2101  */
2102     char *
2103 did_set_mkspellmem(optset_T *args UNUSED)
2104 {
2105     if (spell_check_msm() != OK)
2106         return e_invalid_argument;
2107
2108     return NULL;
2109 }
2110 #endif
2111
2112 /*
2113  * The 'nrformats' option is changed.
2114  */
2115     char *
2116 did_set_nrformats(optset_T *args)
2117 {
2118     return did_set_opt_strings(args->os_varp, p_nf_values, TRUE);
2119 }
2120
2121 /*
2122  * The 'buftype' option is changed.
2123  */
2124     char *
2125 did_set_buftype(optset_T *args UNUSED)
2126 {
2127     if (check_opt_strings(curbuf->b_p_bt, p_buftype_values, FALSE) != OK)
2128         return e_invalid_argument;
2129
2130     if (curwin->w_status_height)
2131     {
2132         curwin->w_redr_status = TRUE;
2133         redraw_later(UPD_VALID);
2134     }
2135     curbuf->b_help = (curbuf->b_p_bt[0] == 'h');
2136     redraw_titles();
2137
2138     return NULL;
2139 }
2140
2141 #if defined(FEAT_STL_OPT) || defined(PROTO)
2142 /*
2143  * The 'statusline' or the 'tabline' or the 'rulerformat' option is changed.
2144  * "rulerformat" is TRUE if the 'rulerformat' option is changed.
2145  */
2146     static char *
2147 did_set_statustabline_rulerformat(optset_T *args, int rulerformat)
2148 {
2149     char_u      *s;
2150     char        *errmsg = NULL;
2151     int         wid;
2152
2153     if (rulerformat)    // reset ru_wid first
2154         ru_wid = 0;
2155     s = args->os_varp;
2156     if (rulerformat && *s == '%')
2157     {
2158         // set ru_wid if 'ruf' starts with "%99("
2159         if (*++s == '-')        // ignore a '-'
2160             s++;
2161         wid = getdigits(&s);
2162         if (wid && *s == '(' && (errmsg = check_stl_option(p_ruf)) == NULL)
2163             ru_wid = wid;
2164         else
2165             errmsg = check_stl_option(p_ruf);
2166     }
2167     // check 'statusline' or 'tabline' only if it doesn't start with "%!"
2168     else if (rulerformat || s[0] != '%' || s[1] != '!')
2169         errmsg = check_stl_option(s);
2170     if (rulerformat && errmsg == NULL)
2171         comp_col();
2172
2173     return errmsg;
2174 }
2175
2176 /*
2177  * The 'statusline' option is changed.
2178  */
2179     char *
2180 did_set_statusline(optset_T *args)
2181 {
2182     return did_set_statustabline_rulerformat(args, FALSE);
2183 }
2184
2185 /*
2186  * The 'tabline' option is changed.
2187  */
2188     char *
2189 did_set_tabline(optset_T *args)
2190 {
2191     return did_set_statustabline_rulerformat(args, FALSE);
2192 }
2193
2194
2195 /*
2196  * The 'rulerformat' option is changed.
2197  */
2198     char *
2199 did_set_rulerformat(optset_T *args)
2200 {
2201     return did_set_statustabline_rulerformat(args, TRUE);
2202 }
2203 #endif
2204
2205 /*
2206  * The 'complete' option is changed.
2207  */
2208     char *
2209 did_set_complete(optset_T *args)
2210 {
2211     char_u      *s;
2212
2213     // check if it is a valid value for 'complete' -- Acevedo
2214     for (s = args->os_varp; *s;)
2215     {
2216         while (*s == ',' || *s == ' ')
2217             s++;
2218         if (!*s)
2219             break;
2220         if (vim_strchr((char_u *)".wbuksid]tU", *s) == NULL)
2221             return illegal_char(args->os_errbuf, *s);
2222         if (*++s != NUL && *s != ',' && *s != ' ')
2223         {
2224             if (s[-1] == 'k' || s[-1] == 's')
2225             {
2226                 // skip optional filename after 'k' and 's'
2227                 while (*s && *s != ',' && *s != ' ')
2228                 {
2229                     if (*s == '\\' && s[1] != NUL)
2230                         ++s;
2231                     ++s;
2232                 }
2233             }
2234             else
2235             {
2236                 if (args->os_errbuf != NULL)
2237                 {
2238                     sprintf((char *)args->os_errbuf,
2239                             _(e_illegal_character_after_chr), *--s);
2240                     return args->os_errbuf;
2241                 }
2242                 return "";
2243             }
2244         }
2245     }
2246
2247     return NULL;
2248 }
2249
2250 /*
2251  * The 'completeopt' option is changed.
2252  */
2253     char *
2254 did_set_completeopt(optset_T *args UNUSED)
2255 {
2256     if (check_opt_strings(p_cot, p_cot_values, TRUE) != OK)
2257         return e_invalid_argument;
2258
2259     completeopt_was_set();
2260     return NULL;
2261 }
2262
2263 #if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
2264 /*
2265  * The 'completeslash' option is changed.
2266  */
2267     char *
2268 did_set_completeslash(optset_T *args UNUSED)
2269 {
2270     if (check_opt_strings(p_csl, p_csl_values, FALSE) != OK
2271             || check_opt_strings(curbuf->b_p_csl, p_csl_values, FALSE) != OK)
2272         return e_invalid_argument;
2273
2274     return NULL;
2275 }
2276 #endif
2277
2278 #if defined(FEAT_SIGNS) || defined(PROTO)
2279 /*
2280  * The 'signcolumn' option is changed.
2281  */
2282     char *
2283 did_set_signcolumn(optset_T *args)
2284 {
2285     if (check_opt_strings(args->os_varp, p_scl_values, FALSE) != OK)
2286         return e_invalid_argument;
2287     // When changing the 'signcolumn' to or from 'number', recompute the
2288     // width of the number column if 'number' or 'relativenumber' is set.
2289     if (((*args->os_oldval.string == 'n' && args->os_oldval.string[1] == 'u')
2290                 || (*curwin->w_p_scl == 'n' && *(curwin->w_p_scl + 1) =='u'))
2291             && (curwin->w_p_nu || curwin->w_p_rnu))
2292         curwin->w_nrwidth_line_count = 0;
2293
2294     return NULL;
2295 }
2296 #endif
2297
2298 #if (defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_MSWIN)) || defined(PROTO)
2299 /*
2300  * The 'toolbar' option is changed.
2301  */
2302     char *
2303 did_set_toolbar(optset_T *args UNUSED)
2304 {
2305     if (opt_strings_flags(p_toolbar, p_toolbar_values,
2306                 &toolbar_flags, TRUE) != OK)
2307         return e_invalid_argument;
2308
2309     out_flush();
2310     gui_mch_show_toolbar((toolbar_flags &
2311                 (TOOLBAR_TEXT | TOOLBAR_ICONS)) != 0);
2312     return NULL;
2313 }
2314 #endif
2315
2316 #if (defined(FEAT_TOOLBAR) && defined(FEAT_GUI_GTK)) || defined(PROTO)
2317 /*
2318  * The 'toolbariconsize' option is changed.  GTK+ 2 only.
2319  */
2320     char *
2321 did_set_toolbariconsize(optset_T *args UNUSED)
2322 {
2323     if (opt_strings_flags(p_tbis, p_tbis_values, &tbis_flags, FALSE) != OK)
2324         return e_invalid_argument;
2325
2326     out_flush();
2327     gui_mch_show_toolbar((toolbar_flags &
2328                 (TOOLBAR_TEXT | TOOLBAR_ICONS)) != 0);
2329     return NULL;
2330 }
2331 #endif
2332
2333 /*
2334  * The 'pastetoggle' option is changed.
2335  */
2336     char *
2337 did_set_pastetoggle(optset_T *args UNUSED)
2338 {
2339     char_u      *p;
2340
2341     // translate key codes like in a mapping
2342     if (*p_pt)
2343     {
2344         (void)replace_termcodes(p_pt, &p,
2345                 REPTERM_FROM_PART | REPTERM_DO_LT, NULL);
2346         if (p != NULL)
2347         {
2348             free_string_option(p_pt);
2349             p_pt = p;
2350         }
2351     }
2352
2353     return NULL;
2354 }
2355
2356 /*
2357  * The 'backspace' option is changed.
2358  */
2359     char *
2360 did_set_backspace(optset_T *args UNUSED)
2361 {
2362     if (VIM_ISDIGIT(*p_bs))
2363     {
2364         if (*p_bs > '3' || p_bs[1] != NUL)
2365             return e_invalid_argument;
2366     }
2367     else if (check_opt_strings(p_bs, p_bs_values, TRUE) != OK)
2368         return e_invalid_argument;
2369
2370     return NULL;
2371 }
2372
2373 /*
2374  * The 'bufhidden' option is changed.
2375  */
2376     char *
2377 did_set_bufhidden(optset_T *args UNUSED)
2378 {
2379     return did_set_opt_strings(curbuf->b_p_bh, p_bufhidden_values, FALSE);
2380 }
2381
2382 /*
2383  * The 'tagcase' option is changed.
2384  */
2385     char *
2386 did_set_tagcase(optset_T *args)
2387 {
2388     unsigned int        *flags;
2389     char_u              *p;
2390
2391     if (args->os_flags & OPT_LOCAL)
2392     {
2393         p = curbuf->b_p_tc;
2394         flags = &curbuf->b_tc_flags;
2395     }
2396     else
2397     {
2398         p = p_tc;
2399         flags = &tc_flags;
2400     }
2401
2402     if ((args->os_flags & OPT_LOCAL) && *p == NUL)
2403         // make the local value empty: use the global value
2404         *flags = 0;
2405     else if (*p == NUL
2406             || opt_strings_flags(p, p_tc_values, flags, FALSE) != OK)
2407         return e_invalid_argument;
2408
2409     return NULL;
2410 }
2411
2412 #if defined(FEAT_DIFF) || defined(PROTO)
2413 /*
2414  * The 'diffopt' option is changed.
2415  */
2416     char *
2417 did_set_diffopt(optset_T *args UNUSED)
2418 {
2419     if (diffopt_changed() == FAIL)
2420         return e_invalid_argument;
2421
2422     return NULL;
2423 }
2424 #endif
2425
2426 #if defined(FEAT_FOLDING) || defined(PROTO)
2427 /*
2428  * The 'foldmethod' option is changed.
2429  */
2430     char *
2431 did_set_foldmethod(optset_T *args)
2432 {
2433     if (check_opt_strings(args->os_varp, p_fdm_values, FALSE) != OK
2434             || *curwin->w_p_fdm == NUL)
2435         return e_invalid_argument;
2436
2437     foldUpdateAll(curwin);
2438     if (foldmethodIsDiff(curwin))
2439         newFoldLevel();
2440     return NULL;
2441 }
2442
2443 /*
2444  * The 'foldmarker' option is changed.
2445  */
2446     char *
2447 did_set_foldmarker(optset_T *args)
2448 {
2449     char_u      *p;
2450
2451     p = vim_strchr(args->os_varp, ',');
2452     if (p == NULL)
2453         return e_comma_required;
2454     else if (p == args->os_varp || p[1] == NUL)
2455         return e_invalid_argument;
2456     else if (foldmethodIsMarker(curwin))
2457         foldUpdateAll(curwin);
2458
2459     return NULL;
2460 }
2461
2462 /*
2463  * The 'commentstring' option is changed.
2464  */
2465     char *
2466 did_set_commentstring(optset_T *args)
2467 {
2468     if (*args->os_varp != NUL && strstr((char *)args->os_varp, "%s") == NULL)
2469         return e_commentstring_must_be_empty_or_contain_str;
2470
2471     return NULL;
2472 }
2473
2474 /*
2475  * The 'foldignore' option is changed.
2476  */
2477     char *
2478 did_set_foldignore(optset_T *args UNUSED)
2479 {
2480     if (foldmethodIsIndent(curwin))
2481         foldUpdateAll(curwin);
2482     return NULL;
2483 }
2484
2485 /*
2486  * The 'foldclose' option is changed.
2487  */
2488     char *
2489 did_set_foldclose(optset_T *args UNUSED)
2490 {
2491     return did_set_opt_strings(p_fcl, p_fcl_values, TRUE);
2492 }
2493
2494 /*
2495  * The 'foldopen' option is changed.
2496  */
2497     char *
2498 did_set_foldopen(optset_T *args UNUSED)
2499 {
2500     return did_set_opt_flags(p_fdo, p_fdo_values, &fdo_flags, TRUE);
2501 }
2502 #endif
2503
2504 /*
2505  * The 'virtualedit' option is changed.
2506  */
2507     char *
2508 did_set_virtualedit(optset_T *args)
2509 {
2510     char_u              *ve = p_ve;
2511     unsigned int        *flags = &ve_flags;
2512
2513     if (args->os_flags & OPT_LOCAL)
2514     {
2515         ve = curwin->w_p_ve;
2516         flags = &curwin->w_ve_flags;
2517     }
2518
2519     if ((args->os_flags & OPT_LOCAL) && *ve == NUL)
2520         // make the local value empty: use the global value
2521         *flags = 0;
2522     else
2523     {
2524         if (opt_strings_flags(ve, p_ve_values, flags, TRUE) != OK)
2525             return e_invalid_argument;
2526         else if (STRCMP(ve, args->os_oldval.string) != 0)
2527         {
2528             // Recompute cursor position in case the new 've' setting
2529             // changes something.
2530             validate_virtcol();
2531             coladvance(curwin->w_virtcol);
2532         }
2533     }
2534
2535     return NULL;
2536 }
2537
2538 #if (defined(FEAT_CSCOPE) && defined(FEAT_QUICKFIX)) || defined(PROTO)
2539 /*
2540  * The 'cscopequickfix' option is changed.
2541  */
2542     char *
2543 did_set_cscopequickfix(optset_T *args UNUSED)
2544 {
2545     char_u      *p;
2546
2547     if (p_csqf == NULL)
2548         return NULL;
2549
2550     p = p_csqf;
2551     while (*p != NUL)
2552     {
2553         if (vim_strchr((char_u *)CSQF_CMDS, *p) == NULL
2554                 || p[1] == NUL
2555                 || vim_strchr((char_u *)CSQF_FLAGS, p[1]) == NULL
2556                 || (p[2] != NUL && p[2] != ','))
2557             return e_invalid_argument;
2558         else if (p[2] == NUL)
2559             break;
2560         else
2561             p += 3;
2562     }
2563
2564     return NULL;
2565 }
2566 #endif
2567
2568 /*
2569  * The 'cinoptions' option is changed.
2570  */
2571     char *
2572 did_set_cinoptions(optset_T *args UNUSED)
2573 {
2574     // TODO: recognize errors
2575     parse_cino(curbuf);
2576
2577     return NULL;
2578 }
2579
2580 /*
2581  * The 'lispoptions' option is changed.
2582  */
2583     char *
2584 did_set_lispoptions(optset_T *args)
2585 {
2586     if (*args->os_varp != NUL
2587             && STRCMP(args->os_varp, "expr:0") != 0
2588             && STRCMP(args->os_varp, "expr:1") != 0)
2589         return e_invalid_argument;
2590
2591     return NULL;
2592 }
2593
2594 #if defined(FEAT_RENDER_OPTIONS) || defined(PROTO)
2595 /*
2596  * The 'renderoptions' option is changed.
2597  */
2598     char *
2599 did_set_renderoptions(optset_T *args UNUSED)
2600 {
2601     if (!gui_mch_set_rendering_options(p_rop))
2602         return e_invalid_argument;
2603
2604     return NULL;
2605 }
2606 #endif
2607
2608 #if defined(FEAT_RIGHTLEFT) || defined(PROTO)
2609 /*
2610  * The 'rightleftcmd' option is changed.
2611  */
2612     char *
2613 did_set_rightleftcmd(optset_T *args)
2614 {
2615     // Currently only "search" is a supported value.
2616     if (*args->os_varp != NUL && STRCMP(args->os_varp, "search") != 0)
2617         return e_invalid_argument;
2618
2619     return NULL;
2620 }
2621 #endif
2622
2623 /*
2624  * The 'filetype' or the 'syntax' option is changed.
2625  */
2626     char *
2627 did_set_filetype_or_syntax(optset_T *args)
2628 {
2629     if (!valid_filetype(args->os_varp))
2630         return e_invalid_argument;
2631
2632     args->os_value_changed =
2633                         STRCMP(args->os_oldval.string, args->os_varp) != 0;
2634
2635     // Since we check the value, there is no need to set P_INSECURE,
2636     // even when the value comes from a modeline.
2637     args->os_value_checked = TRUE;
2638
2639     return NULL;
2640 }
2641
2642 #if defined(FEAT_TERMINAL) || defined(PROTO)
2643 /*
2644  * The 'termwinkey' option is changed.
2645  */
2646     char *
2647 did_set_termwinkey(optset_T *args UNUSED)
2648 {
2649     if (*curwin->w_p_twk != NUL
2650             && string_to_key(curwin->w_p_twk, TRUE) == 0)
2651         return e_invalid_argument;
2652
2653     return NULL;
2654 }
2655
2656 /*
2657  * The 'termwinsize' option is changed.
2658  */
2659     char *
2660 did_set_termwinsize(optset_T *args UNUSED)
2661 {
2662     char_u      *p;
2663
2664     if (*curwin->w_p_tws == NUL)
2665         return NULL;
2666
2667     p = skipdigits(curwin->w_p_tws);
2668     if (p == curwin->w_p_tws
2669             || (*p != 'x' && *p != '*')
2670             || *skipdigits(p + 1) != NUL)
2671         return e_invalid_argument;
2672
2673     return NULL;
2674 }
2675
2676 # if defined(MSWIN) || defined(PROTO)
2677 /*
2678  * The 'termwintype' option is changed.
2679  */
2680     char *
2681 did_set_termwintype(optset_T *args UNUSED)
2682 {
2683     return did_set_opt_strings(p_twt, p_twt_values, FALSE);
2684 }
2685 # endif
2686 #endif
2687
2688 #if defined(FEAT_VARTABS) || defined(PROTO)
2689 /*
2690  * The 'varsofttabstop' option is changed.
2691  */
2692     char *
2693 did_set_varsofttabstop(optset_T *args)
2694 {
2695     char_u *cp;
2696
2697     if (!(args->os_varp[0]) || (args->os_varp[0] == '0' && !(args->os_varp[1])))
2698     {
2699         if (curbuf->b_p_vsts_array)
2700         {
2701             vim_free(curbuf->b_p_vsts_array);
2702             curbuf->b_p_vsts_array = 0;
2703         }
2704     }
2705     else
2706     {
2707         for (cp = args->os_varp; *cp; ++cp)
2708         {
2709             if (vim_isdigit(*cp))
2710                 continue;
2711             if (*cp == ',' && cp > args->os_varp && *(cp-1) != ',')
2712                 continue;
2713             return e_invalid_argument;
2714         }
2715
2716         int *oldarray = curbuf->b_p_vsts_array;
2717         if (tabstop_set(args->os_varp, &(curbuf->b_p_vsts_array)) == OK)
2718         {
2719             if (oldarray)
2720                 vim_free(oldarray);
2721         }
2722         else
2723             return e_invalid_argument;
2724     }
2725
2726     return NULL;
2727 }
2728
2729 /*
2730  * The 'vartabstop' option is changed.
2731  */
2732     char *
2733 did_set_vartabstop(optset_T *args)
2734 {
2735     char_u *cp;
2736
2737     if (!(args->os_varp[0]) || (args->os_varp[0] == '0' && !(args->os_varp[1])))
2738     {
2739         if (curbuf->b_p_vts_array)
2740         {
2741             vim_free(curbuf->b_p_vts_array);
2742             curbuf->b_p_vts_array = NULL;
2743         }
2744     }
2745     else
2746     {
2747         for (cp = args->os_varp; *cp; ++cp)
2748         {
2749             if (vim_isdigit(*cp))
2750                 continue;
2751             if (*cp == ',' && cp > args->os_varp && *(cp-1) != ',')
2752                 continue;
2753             return e_invalid_argument;
2754         }
2755
2756         int *oldarray = curbuf->b_p_vts_array;
2757
2758         if (tabstop_set(args->os_varp, &(curbuf->b_p_vts_array)) == OK)
2759         {
2760             vim_free(oldarray);
2761 # ifdef FEAT_FOLDING
2762             if (foldmethodIsIndent(curwin))
2763                 foldUpdateAll(curwin);
2764 # endif
2765         }
2766         else
2767             return e_invalid_argument;
2768     }
2769
2770     return NULL;
2771 }
2772 #endif
2773
2774 #if defined(FEAT_PROP_POPUP) || defined(PROTO)
2775 /*
2776  * The 'previewpopup' option is changed.
2777  */
2778     char *
2779 did_set_previewpopup(optset_T *args UNUSED)
2780 {
2781     if (parse_previewpopup(NULL) == FAIL)
2782         return e_invalid_argument;
2783
2784     return NULL;
2785 }
2786
2787 # if defined(FEAT_QUICKFIX) || defined(PROTO)
2788 /*
2789  * The 'completepopup' option is changed.
2790  */
2791     char *
2792 did_set_completepopup(optset_T *args UNUSED)
2793 {
2794     if (parse_completepopup(NULL) == FAIL)
2795         return e_invalid_argument;
2796
2797     popup_close_info();
2798     return NULL;
2799 }
2800 # endif
2801 #endif
2802
2803 #if defined(FEAT_EVAL) || defined(PROTO)
2804 /*
2805  * Returns TRUE if the option pointed by "varp" or "gvarp" is one of the
2806  * '*expr' options: 'balloonexpr', 'diffexpr', 'foldexpr', 'foldtext',
2807  * 'formatexpr', 'includeexpr', 'indentexpr', 'patchexpr', 'printexpr' or
2808  * 'charconvert'.
2809  */
2810     static int
2811 is_expr_option(char_u **varp, char_u **gvarp)
2812 {
2813     return (
2814 # ifdef FEAT_BEVAL
2815         varp == &p_bexpr ||                     // 'balloonexpr'
2816 # endif
2817 # ifdef FEAT_DIFF
2818         varp == &p_dex ||                       // 'diffexpr'
2819 # endif
2820 # ifdef FEAT_FOLDING
2821         gvarp == &curwin->w_allbuf_opt.wo_fde ||        // 'foldexpr'
2822         gvarp == &curwin->w_allbuf_opt.wo_fdt ||        // 'foldtext'
2823 # endif
2824         gvarp == &p_fex ||                      // 'formatexpr'
2825 # ifdef FEAT_FIND_ID
2826         gvarp == &p_inex ||                     // 'includeexpr'
2827 # endif
2828         gvarp == &p_inde ||                     // 'indentexpr'
2829 # ifdef FEAT_DIFF
2830         varp == &p_pex ||                       // 'patchexpr'
2831 # endif
2832 # ifdef FEAT_POSTSCRIPT
2833         varp == &p_pexpr ||                     // 'printexpr'
2834 # endif
2835         varp == &p_ccv);                        // 'charconvert'
2836 }
2837
2838 /*
2839  * One of the '*expr' options is changed: 'balloonexpr', 'diffexpr',
2840  * 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr', 'indentexpr',
2841  * 'patchexpr', 'printexpr' and 'charconvert'.
2842  *
2843  */
2844     char *
2845 did_set_optexpr(optset_T *args)
2846 {
2847     // If the option value starts with <SID> or s:, then replace that with
2848     // the script identifier.
2849     char_u *name = get_scriptlocal_funcname(args->os_varp);
2850     if (name != NULL)
2851     {
2852         free_string_option(args->os_varp);
2853         args->os_varp = name;
2854     }
2855
2856     return NULL;
2857 }
2858
2859 # if defined(FEAT_FOLDING) || defined(PROTO)
2860 /*
2861  * The 'foldexpr' option is changed.
2862  */
2863     char *
2864 did_set_foldexpr(optset_T *args)
2865 {
2866     (void)did_set_optexpr(args);
2867     if (foldmethodIsExpr(curwin))
2868         foldUpdateAll(curwin);
2869     return NULL;
2870 }
2871 # endif
2872 #endif
2873
2874 #if defined(FEAT_CONCEAL) || defined(PROTO)
2875 /*
2876  * The 'concealcursor' option is changed.
2877  */
2878     char *
2879 did_set_concealcursor(optset_T *args)
2880 {
2881     return did_set_option_listflag(args->os_varp, (char_u *)COCU_ALL,
2882                                                         args->os_errbuf);
2883 }
2884 #endif
2885
2886 /*
2887  * The 'cpoptions' option is changed.
2888  */
2889     char *
2890 did_set_cpoptions(optset_T *args)
2891 {
2892     return did_set_option_listflag(args->os_varp, (char_u *)CPO_ALL,
2893                                                         args->os_errbuf);
2894 }
2895
2896 /*
2897  * The 'formatoptions' option is changed.
2898  */
2899     char *
2900 did_set_formatoptions(optset_T *args)
2901 {
2902     return did_set_option_listflag(args->os_varp, (char_u *)FO_ALL,
2903                                                         args->os_errbuf);
2904 }
2905
2906 /*
2907  * The 'mouse' option is changed.
2908  */
2909     char *
2910 did_set_mouse(optset_T *args)
2911 {
2912     return did_set_option_listflag(args->os_varp, (char_u *)MOUSE_ALL,
2913                                                         args->os_errbuf);
2914 }
2915
2916 /*
2917  * The 'shortmess' option is changed.
2918  */
2919     char *
2920 did_set_shortmess(optset_T *args)
2921 {
2922     return did_set_option_listflag(args->os_varp, (char_u *)SHM_ALL,
2923                                                         args->os_errbuf);
2924 }
2925
2926 /*
2927  * The 'whichwrap' option is changed.
2928  */
2929     char *
2930 did_set_whichwrap(optset_T *args)
2931 {
2932     return did_set_option_listflag(args->os_varp, (char_u *)WW_ALL,
2933                                                         args->os_errbuf);
2934 }
2935
2936 #ifdef FEAT_SYN_HL
2937 /*
2938  * When the 'syntax' option is set, load the syntax of that name.
2939  */
2940     static void
2941 do_syntax_autocmd(int value_changed)
2942 {
2943     static int syn_recursive = 0;
2944
2945     ++syn_recursive;
2946     // Only pass TRUE for "force" when the value changed or not used
2947     // recursively, to avoid endless recurrence.
2948     apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, curbuf->b_fname,
2949             value_changed || syn_recursive == 1, curbuf);
2950     curbuf->b_flags |= BF_SYN_SET;
2951     --syn_recursive;
2952 }
2953 #endif
2954
2955 /*
2956  * When the 'filetype' option is set, trigger the FileType autocommand.
2957  */
2958     static void
2959 do_filetype_autocmd(char_u **varp, int opt_flags, int value_changed)
2960 {
2961     // Skip this when called from a modeline and the filetype was already set
2962     // to this value.
2963     if ((opt_flags & OPT_MODELINE) && !value_changed)
2964         return;
2965
2966     static int  ft_recursive = 0;
2967     int     secure_save = secure;
2968
2969     // Reset the secure flag, since the value of 'filetype' has
2970     // been checked to be safe.
2971     secure = 0;
2972
2973     ++ft_recursive;
2974     did_filetype = TRUE;
2975     // Only pass TRUE for "force" when the value changed or not
2976     // used recursively, to avoid endless recurrence.
2977     apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname,
2978             value_changed || ft_recursive == 1, curbuf);
2979     --ft_recursive;
2980     // Just in case the old "curbuf" is now invalid.
2981     if (varp != &(curbuf->b_p_ft))
2982         varp = NULL;
2983
2984     secure = secure_save;
2985 }
2986
2987 #ifdef FEAT_SPELL
2988 /*
2989  * When the 'spelllang' option is set, source the spell/LANG.vim file in
2990  * 'runtimepath'.
2991  */
2992     static void
2993 do_spelllang_source(void)
2994 {
2995     char_u      fname[200];
2996     char_u      *p;
2997     char_u      *q = curwin->w_s->b_p_spl;
2998
2999     // Skip the first name if it is "cjk".
3000     if (STRNCMP(q, "cjk,", 4) == 0)
3001         q += 4;
3002
3003     // They could set 'spellcapcheck' depending on the language.  Use the first
3004     // name in 'spelllang' up to '_region' or '.encoding'.
3005     for (p = q; *p != NUL; ++p)
3006         if (!ASCII_ISALNUM(*p) && *p != '-')
3007             break;
3008     if (p > q)
3009     {
3010         vim_snprintf((char *)fname, 200, "spell/%.*s.vim",
3011                 (int)(p - q), q);
3012         source_runtime(fname, DIP_ALL);
3013     }
3014 }
3015 #endif
3016
3017 /*
3018  * Handle string options that need some action to perform when changed.
3019  * The new value must be allocated.
3020  * Returns NULL for success, or an untranslated error message for an error.
3021  */
3022     char *
3023 did_set_string_option(
3024     int         opt_idx,                // index in options[] table
3025     char_u      **varp,                 // pointer to the option variable
3026     char_u      *oldval,                // previous value of the option
3027     char_u      *value,                 // new value of the option
3028     char        *errbuf,                // buffer for errors, or NULL
3029     int         opt_flags,              // OPT_LOCAL and/or OPT_GLOBAL
3030     int         *value_checked)         // value was checked to be safe, no
3031                                         // need to set P_INSECURE
3032 {
3033     char        *errmsg = NULL;
3034     int         restore_chartab = FALSE;
3035     char_u      **gvarp;
3036     long_u      free_oldval = (get_option_flags(opt_idx) & P_ALLOCED);
3037     int         value_changed = FALSE;
3038     int         did_swaptcap = FALSE;
3039     opt_did_set_cb_T did_set_cb = get_option_did_set_cb(opt_idx);
3040
3041     // Get the global option to compare with, otherwise we would have to check
3042     // two values for all local options.
3043     gvarp = (char_u **)get_option_varp_scope(opt_idx, OPT_GLOBAL);
3044
3045     // Disallow changing some options from secure mode
3046     if ((secure
3047 #ifdef HAVE_SANDBOX
3048                 || sandbox != 0
3049 #endif
3050                 ) && (get_option_flags(opt_idx) & P_SECURE))
3051         errmsg = e_not_allowed_here;
3052     // Check for a "normal" directory or file name in some options.
3053     else if (check_illegal_path_names(opt_idx, varp))
3054         errmsg = e_invalid_argument;
3055     else if (did_set_cb != NULL)
3056     {
3057         optset_T   args;
3058
3059         args.os_varp = *varp;
3060         args.os_flags = opt_flags;
3061         args.os_oldval.string = oldval;
3062         args.os_newval.string = value;
3063         args.os_value_checked = FALSE;
3064         args.os_value_changed = FALSE;
3065         args.os_restore_chartab = FALSE;
3066         args.os_errbuf = errbuf;
3067         // Invoke the option specific callback function to validate and apply
3068         // the new option value.
3069         errmsg = did_set_cb(&args);
3070
3071 #ifdef FEAT_EVAL
3072         // The '*expr' option (e.g. diffexpr, foldexpr, etc.), callback
3073         // functions may modify '*varp'.
3074         if (errmsg == NULL && is_expr_option(varp, gvarp))
3075             *varp = args.os_varp;
3076 #endif
3077         // The 'filetype' and 'syntax' option callback functions may change
3078         // the os_value_changed field.
3079         value_changed = args.os_value_changed;
3080         // The 'keymap', 'filetype' and 'syntax' option callback functions
3081         // may change the os_value_checked field.
3082         *value_checked = args.os_value_checked;
3083         // The 'isident', 'iskeyword', 'isprint' and 'isfname' options may
3084         // change the character table.  On failure, this needs to be restored.
3085         restore_chartab = args.os_restore_chartab;
3086     }
3087     else if (varp == &T_NAME)                   // 'term'
3088         errmsg = did_set_term(&opt_idx, &free_oldval);
3089     else if (  varp == &p_enc                   // 'encoding'
3090             || gvarp == &p_fenc                 // 'fileencoding'
3091             || varp == &p_tenc                  // 'termencoding'
3092             || gvarp == &p_menc)                // 'makeencoding'
3093         errmsg = did_set_encoding(varp, gvarp, opt_flags);
3094     else if (  varp == &p_lcs                   // global 'listchars'
3095             || varp == &p_fcs)                  // global 'fillchars'
3096         errmsg = did_set_global_listfillchars(varp, opt_flags);
3097     else if (varp == &curwin->w_p_lcs)          // local 'listchars'
3098         errmsg = set_chars_option(curwin, varp, TRUE);
3099     else if (varp == &curwin->w_p_fcs)          // local 'fillchars'
3100         errmsg = set_chars_option(curwin, varp, TRUE);
3101     // terminal options
3102     else if (istermoption_idx(opt_idx) && full_screen)
3103         did_set_term_option(varp, &did_swaptcap);
3104
3105     // If an error is detected, restore the previous value.
3106     if (errmsg != NULL)
3107     {
3108         free_string_option(*varp);
3109         *varp = oldval;
3110         // When resetting some values, need to act on it.
3111         if (restore_chartab)
3112             (void)init_chartab();
3113         if (varp == &p_hl)
3114             (void)highlight_changed();
3115     }
3116     else
3117     {
3118 #ifdef FEAT_EVAL
3119         // Remember where the option was set.
3120         set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
3121 #endif
3122         // Free string options that are in allocated memory.
3123         // Use "free_oldval", because recursiveness may change the flags under
3124         // our fingers (esp. init_highlight()).
3125         if (free_oldval)
3126             free_string_option(oldval);
3127         set_option_flag(opt_idx, P_ALLOCED);
3128
3129         if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
3130                 && is_global_local_option(opt_idx))
3131         {
3132             // global option with local value set to use global value; free
3133             // the local value and make it empty
3134             char_u *p = get_option_varp_scope(opt_idx, OPT_LOCAL);
3135             free_string_option(*(char_u **)p);
3136             *(char_u **)p = empty_option;
3137         }
3138
3139         // May set global value for local option.
3140         else if (!(opt_flags & OPT_LOCAL) && opt_flags != OPT_GLOBAL)
3141             set_string_option_global(opt_idx, varp);
3142
3143         // Trigger the autocommand only after setting the flags.
3144 #ifdef FEAT_SYN_HL
3145         if (varp == &(curbuf->b_p_syn))
3146             do_syntax_autocmd(value_changed);
3147 #endif
3148         else if (varp == &(curbuf->b_p_ft))
3149             do_filetype_autocmd(varp, opt_flags, value_changed);
3150 #ifdef FEAT_SPELL
3151         if (varp == &(curwin->w_s->b_p_spl))
3152             do_spelllang_source();
3153 #endif
3154     }
3155
3156     if (varp == &p_mouse)
3157     {
3158         if (*p_mouse == NUL)
3159             mch_setmouse(FALSE);    // switch mouse off
3160         else
3161             setmouse();             // in case 'mouse' changed
3162     }
3163
3164 #if defined(FEAT_LUA) || defined(PROTO)
3165     if (varp == &p_rtp)
3166         update_package_paths_in_lua();
3167 #endif
3168
3169 #if defined(FEAT_LINEBREAK)
3170     // Changing Formatlistpattern when briopt includes the list setting:
3171     // redraw
3172     if ((varp == &p_flp || varp == &(curbuf->b_p_flp))
3173             && curwin->w_briopt_list)
3174         redraw_all_later(UPD_NOT_VALID);
3175 #endif
3176
3177     if (curwin->w_curswant != MAXCOL
3178                    && (get_option_flags(opt_idx) & (P_CURSWANT | P_RALL)) != 0)
3179         curwin->w_set_curswant = TRUE;
3180
3181     if ((opt_flags & OPT_NO_REDRAW) == 0)
3182     {
3183 #ifdef FEAT_GUI
3184         // set when changing an option that only requires a redraw in the GUI
3185         int     redraw_gui_only = FALSE;
3186
3187         if (varp == &p_go                       // 'guioptions'
3188                 || varp == &p_guifont           // 'guifont'
3189 # ifdef FEAT_GUI_TABLINE
3190                 || varp == &p_gtl               // 'guitablabel'
3191                 || varp == &p_gtt               // 'guitabtooltip'
3192 # endif
3193 # ifdef FEAT_XFONTSET
3194                 || varp == &p_guifontset        // 'guifontset'
3195 # endif
3196                 || varp == &p_guifontwide       // 'guifontwide'
3197 # ifdef FEAT_GUI_GTK
3198                 || varp == &p_guiligatures      // 'guiligatures'
3199 # endif
3200             )
3201             redraw_gui_only = TRUE;
3202
3203         // check redraw when it's not a GUI option or the GUI is active.
3204         if (!redraw_gui_only || gui.in_use)
3205 #endif
3206             check_redraw(get_option_flags(opt_idx));
3207     }
3208
3209 #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
3210     if (did_swaptcap)
3211     {
3212         set_termname((char_u *)"win32");
3213         init_highlight(TRUE, FALSE);
3214     }
3215 #endif
3216
3217     return errmsg;
3218 }
3219
3220 /*
3221  * Check an option that can be a range of string values.
3222  *
3223  * Return OK for correct value, FAIL otherwise.
3224  * Empty is always OK.
3225  */
3226     static int
3227 check_opt_strings(
3228     char_u      *val,
3229     char        **values,
3230     int         list)       // when TRUE: accept a list of values
3231 {
3232     return opt_strings_flags(val, values, NULL, list);
3233 }
3234
3235 /*
3236  * Handle an option that can be a range of string values.
3237  * Set a flag in "*flagp" for each string present.
3238  *
3239  * Return OK for correct value, FAIL otherwise.
3240  * Empty is always OK.
3241  */
3242     static int
3243 opt_strings_flags(
3244     char_u      *val,           // new value
3245     char        **values,       // array of valid string values
3246     unsigned    *flagp,
3247     int         list)           // when TRUE: accept a list of values
3248 {
3249     int         i;
3250     int         len;
3251     unsigned    new_flags = 0;
3252
3253     while (*val)
3254     {
3255         for (i = 0; ; ++i)
3256         {
3257             if (values[i] == NULL)      // val not found in values[]
3258                 return FAIL;
3259
3260             len = (int)STRLEN(values[i]);
3261             if (STRNCMP(values[i], val, len) == 0
3262                     && ((list && val[len] == ',') || val[len] == NUL))
3263             {
3264                 val += len + (val[len] == ',');
3265                 new_flags |= (1 << i);
3266                 break;          // check next item in val list
3267             }
3268         }
3269     }
3270     if (flagp != NULL)
3271         *flagp = new_flags;
3272
3273     return OK;
3274 }
3275
3276 /*
3277  * return OK if "p" is a valid fileformat name, FAIL otherwise.
3278  */
3279     int
3280 check_ff_value(char_u *p)
3281 {
3282     return check_opt_strings(p, p_ff_values, FALSE);
3283 }
3284
3285 /*
3286  * Save the actual shortmess Flags and clear them temporarily to avoid that
3287  * file messages overwrites any output from the following commands.
3288  *
3289  * Caller must make sure to first call save_clear_shm_value() and then
3290  * restore_shm_value() exactly the same number of times.
3291  */
3292     void
3293 save_clear_shm_value(void)
3294 {
3295     if (STRLEN(p_shm) >= SHM_LEN)
3296     {
3297         iemsg(e_internal_error_shortmess_too_long);
3298         return;
3299     }
3300
3301     if (++set_shm_recursive == 1)
3302     {
3303         STRCPY(shm_buf, p_shm);
3304         set_option_value_give_err((char_u *)"shm", 0L, (char_u *)"", 0);
3305     }
3306 }
3307
3308 /*
3309  * Restore the shortmess Flags set from the save_clear_shm_value() function.
3310  */
3311     void
3312 restore_shm_value(void)
3313 {
3314     if (--set_shm_recursive == 0)
3315     {
3316         set_option_value_give_err((char_u *)"shm", 0L, shm_buf, 0);
3317         vim_memset(shm_buf, 0, SHM_LEN);
3318     }
3319 }