comparison src/option.c @ 31886:b741e5243e58 v9.0.1275

patch 9.0.1275: the code for setting options is too complicated Commit: https://github.com/vim/vim/commit/78012f55faf7444e554c0a97a589d99fa215bea9 Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Thu Feb 2 16:34:11 2023 +0000 patch 9.0.1275: the code for setting options is too complicated Problem: The code for setting options is too complicated. Solution: Refactor the do_set() function. (Yegappan Lakshmanan, Lewis Russell, closes #11932)
author Bram Moolenaar <Bram@vim.org>
date Thu, 02 Feb 2023 17:45:05 +0100
parents aec031683d61
children 1c5ef864fe4c
comparison
equal deleted inserted replaced
31885:cc751d944b7e 31886:b741e5243e58
8 */ 8 */
9 9
10 /* 10 /*
11 * Code to handle user-settable options. This is all pretty much table- 11 * Code to handle user-settable options. This is all pretty much table-
12 * driven. Checklist for adding a new option: 12 * driven. Checklist for adding a new option:
13 * - Put it in the options array below (copy an existing entry). 13 * - Put it in the options array in optiondefs.h (copy an existing entry).
14 * - For a global option: Add a variable for it in option.h. 14 * - For a global option: Add a variable for it in option.h.
15 * - For a buffer or window local option: 15 * - For a buffer or window local option:
16 * - Add a PV_XX entry to the enum below. 16 * - Add a PV_XX macro definition to the optiondefs.h file.
17 * - Add a variable to the window or buffer struct in structs.h. 17 * - Add a variable to the window or buffer struct in structs.h.
18 * - For a window option, add some code to copy_winopt(). 18 * - For a window option, add some code to copy_winopt().
19 * - For a window string option, add code to check_win_options() and
20 * clear_winopt().
19 * - For a buffer option, add some code to buf_copy_options(). 21 * - For a buffer option, add some code to buf_copy_options().
20 * - For a buffer string option, add code to check_buf_options(). 22 * - For a buffer string option, add code to check_buf_options().
21 * - If it's a numeric option, add any necessary bounds checks to do_set(). 23 * - If it's a numeric option, add any necessary bounds checks to
22 * - If it's a list of flags, add some code in do_set(), search for WW_ALL. 24 * set_num_option().
25 * - If it's a list of flags, add some code in did_set_string_option(), search
26 * for WW_ALL.
23 * - When adding an option with expansion (P_EXPAND), but with a different 27 * - When adding an option with expansion (P_EXPAND), but with a different
24 * default for Vi and Vim (no P_VI_DEF), add some code at VIMEXP. 28 * default for Vi and Vim (no P_VI_DEF), add some code at VIMEXP.
25 * - Add documentation! One line in doc/quickref.txt, full description in 29 * - Add documentation! One line in doc/quickref.txt, full description in
26 * options.txt, and any other related places. 30 * options.txt, and any other related places.
27 * - Add an entry in runtime/optwin.vim. 31 * - Add an entry in runtime/optwin.vim.
1631 *argp = arg; 1635 *argp = arg;
1632 return *errmsg == NULL ? OK : FAIL; 1636 return *errmsg == NULL ? OK : FAIL;
1633 } 1637 }
1634 1638
1635 /* 1639 /*
1640 * Set an option to a new value.
1641 * Return NULL if OK, return an untranslated error message when something is
1642 * wrong. "errbuf[errbuflen]" can be used to create the error message.
1643 */
1644 static char *
1645 do_set_option(
1646 int opt_flags,
1647 char_u **argp,
1648 char_u *arg_start,
1649 char_u **startarg,
1650 int *did_show,
1651 int *stopopteval,
1652 char *errbuf,
1653 size_t errbuflen)
1654 {
1655 char *errmsg = NULL;
1656 int prefix; // 1: nothing, 0: "no", 2: "inv" in front of name
1657 int nextchar; // next non-white char after option name
1658 int afterchar; // character just after option name
1659 char_u *arg = *argp;
1660 int key;
1661 int opt_idx;
1662 int len;
1663 set_op_T op = 0;
1664 long_u flags; // flags for current option
1665 char_u *varp = NULL; // pointer to variable for current option
1666 char_u key_name[2];
1667 int cp_val = 0;
1668 varnumber_T value;
1669 int i;
1670
1671 prefix = 1;
1672 if (STRNCMP(arg, "no", 2) == 0 && STRNCMP(arg, "novice", 6) != 0)
1673 {
1674 prefix = 0;
1675 arg += 2;
1676 }
1677 else if (STRNCMP(arg, "inv", 3) == 0)
1678 {
1679 prefix = 2;
1680 arg += 3;
1681 }
1682
1683 // find end of name
1684 key = 0;
1685 if (*arg == '<')
1686 {
1687 opt_idx = -1;
1688 // look out for <t_>;>
1689 if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4])
1690 len = 5;
1691 else
1692 {
1693 len = 1;
1694 while (arg[len] != NUL && arg[len] != '>')
1695 ++len;
1696 }
1697 if (arg[len] != '>')
1698 {
1699 errmsg = e_invalid_argument;
1700 goto skip;
1701 }
1702 arg[len] = NUL; // put NUL after name
1703 if (arg[1] == 't' && arg[2] == '_') // could be term code
1704 opt_idx = findoption(arg + 1);
1705 arg[len++] = '>'; // restore '>'
1706 if (opt_idx == -1)
1707 key = find_key_option(arg + 1, TRUE);
1708 }
1709 else
1710 {
1711 len = 0;
1712 /*
1713 * The two characters after "t_" may not be alphanumeric.
1714 */
1715 if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3])
1716 len = 4;
1717 else
1718 while (ASCII_ISALNUM(arg[len]) || arg[len] == '_')
1719 ++len;
1720 nextchar = arg[len];
1721 arg[len] = NUL; // put NUL after name
1722 opt_idx = findoption(arg);
1723 arg[len] = nextchar; // restore nextchar
1724 if (opt_idx == -1)
1725 key = find_key_option(arg, FALSE);
1726 }
1727
1728 // remember character after option name
1729 afterchar = arg[len];
1730
1731 if (in_vim9script())
1732 {
1733 char_u *p = skipwhite(arg + len);
1734
1735 // disallow white space before =val, +=val, -=val, ^=val
1736 if (p > arg + len && (p[0] == '='
1737 || (vim_strchr((char_u *)"+-^", p[0]) != NULL
1738 && p[1] == '=')))
1739 {
1740 errmsg = e_no_white_space_allowed_between_option_and;
1741 arg = p;
1742 *startarg = p;
1743 goto skip;
1744 }
1745 }
1746 else
1747 // skip white space, allow ":set ai ?", ":set hlsearch !"
1748 while (VIM_ISWHITE(arg[len]))
1749 ++len;
1750
1751 op = OP_NONE;
1752 if (arg[len] != NUL && arg[len + 1] == '=')
1753 {
1754 if (arg[len] == '+')
1755 {
1756 op = OP_ADDING; // "+="
1757 ++len;
1758 }
1759 else if (arg[len] == '^')
1760 {
1761 op = OP_PREPENDING; // "^="
1762 ++len;
1763 }
1764 else if (arg[len] == '-')
1765 {
1766 op = OP_REMOVING; // "-="
1767 ++len;
1768 }
1769 }
1770 nextchar = arg[len];
1771
1772 if (opt_idx == -1 && key == 0) // found a mismatch: skip
1773 {
1774 if (in_vim9script() && arg > arg_start
1775 && vim_strchr((char_u *)"!&<", *arg) != NULL)
1776 errmsg = e_no_white_space_allowed_between_option_and;
1777 else
1778 errmsg = e_unknown_option;
1779 goto skip;
1780 }
1781
1782 if (opt_idx >= 0)
1783 {
1784 if (options[opt_idx].var == NULL) // hidden option: skip
1785 {
1786 // Only give an error message when requesting the value of
1787 // a hidden option, ignore setting it.
1788 if (vim_strchr((char_u *)"=:!&<", nextchar) == NULL
1789 && (!(options[opt_idx].flags & P_BOOL)
1790 || nextchar == '?'))
1791 errmsg = e_option_not_supported;
1792 goto skip;
1793 }
1794
1795 flags = options[opt_idx].flags;
1796 varp = get_varp_scope(&(options[opt_idx]), opt_flags);
1797 }
1798 else
1799 {
1800 flags = P_STRING;
1801 if (key < 0)
1802 {
1803 key_name[0] = KEY2TERMCAP0(key);
1804 key_name[1] = KEY2TERMCAP1(key);
1805 }
1806 else
1807 {
1808 key_name[0] = KS_KEY;
1809 key_name[1] = (key & 0xff);
1810 }
1811 }
1812
1813 // Skip all options that are not window-local (used when showing
1814 // an already loaded buffer in a window).
1815 if ((opt_flags & OPT_WINONLY)
1816 && (opt_idx < 0 || options[opt_idx].var != VAR_WIN))
1817 goto skip;
1818
1819 // Skip all options that are window-local (used for :vimgrep).
1820 if ((opt_flags & OPT_NOWIN) && opt_idx >= 0
1821 && options[opt_idx].var == VAR_WIN)
1822 goto skip;
1823
1824 // Disallow changing some options from modelines.
1825 if (opt_flags & OPT_MODELINE)
1826 {
1827 if (flags & (P_SECURE | P_NO_ML))
1828 {
1829 errmsg = e_not_allowed_in_modeline;
1830 goto skip;
1831 }
1832 if ((flags & P_MLE) && !p_mle)
1833 {
1834 errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off;
1835 goto skip;
1836 }
1837 #ifdef FEAT_DIFF
1838 // In diff mode some options are overruled. This avoids that
1839 // 'foldmethod' becomes "marker" instead of "diff" and that
1840 // "wrap" gets set.
1841 if (curwin->w_p_diff
1842 && opt_idx >= 0 // shut up coverity warning
1843 && (
1844 #ifdef FEAT_FOLDING
1845 options[opt_idx].indir == PV_FDM ||
1846 #endif
1847 options[opt_idx].indir == PV_WRAP))
1848 goto skip;
1849 #endif
1850 }
1851
1852 #ifdef HAVE_SANDBOX
1853 // Disallow changing some options in the sandbox
1854 if (sandbox != 0 && (flags & P_SECURE))
1855 {
1856 errmsg = e_not_allowed_in_sandbox;
1857 goto skip;
1858 }
1859 #endif
1860
1861 if (vim_strchr((char_u *)"?=:!&<", nextchar) != NULL)
1862 {
1863 arg += len;
1864 cp_val = p_cp;
1865 if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i')
1866 {
1867 if (arg[3] == 'm') // "opt&vim": set to Vim default
1868 {
1869 cp_val = FALSE;
1870 arg += 3;
1871 }
1872 else // "opt&vi": set to Vi default
1873 {
1874 cp_val = TRUE;
1875 arg += 2;
1876 }
1877 }
1878 if (vim_strchr((char_u *)"?!&<", nextchar) != NULL
1879 && arg[1] != NUL && !VIM_ISWHITE(arg[1]))
1880 {
1881 errmsg = e_trailing_characters;
1882 goto skip;
1883 }
1884 }
1885
1886 /*
1887 * allow '=' and ':' for historical reasons (MSDOS command.com
1888 * allows only one '=' character per "set" command line. grrr. (jw)
1889 */
1890 if (nextchar == '?'
1891 || (prefix == 1
1892 && vim_strchr((char_u *)"=:&<", nextchar) == NULL
1893 && !(flags & P_BOOL)))
1894 {
1895 /*
1896 * print value
1897 */
1898 if (*did_show)
1899 msg_putchar('\n'); // cursor below last one
1900 else
1901 {
1902 gotocmdline(TRUE); // cursor at status line
1903 *did_show = TRUE; // remember that we did a line
1904 }
1905 if (opt_idx >= 0)
1906 {
1907 showoneopt(&options[opt_idx], opt_flags);
1908 #ifdef FEAT_EVAL
1909 if (p_verbose > 0)
1910 {
1911 // Mention where the option was last set.
1912 if (varp == options[opt_idx].var)
1913 last_set_msg(options[opt_idx].script_ctx);
1914 else if ((int)options[opt_idx].indir & PV_WIN)
1915 last_set_msg(curwin->w_p_script_ctx[
1916 (int)options[opt_idx].indir & PV_MASK]);
1917 else if ((int)options[opt_idx].indir & PV_BUF)
1918 last_set_msg(curbuf->b_p_script_ctx[
1919 (int)options[opt_idx].indir & PV_MASK]);
1920 }
1921 #endif
1922 }
1923 else
1924 {
1925 char_u *p;
1926
1927 p = find_termcode(key_name);
1928 if (p == NULL)
1929 {
1930 errmsg = e_key_code_not_set;
1931 goto skip;
1932 }
1933 else
1934 (void)show_one_termcode(key_name, p, TRUE);
1935 }
1936 if (nextchar != '?'
1937 && nextchar != NUL && !VIM_ISWHITE(afterchar))
1938 errmsg = e_trailing_characters;
1939 }
1940 else
1941 {
1942 int value_checked = FALSE;
1943
1944 if (flags & P_BOOL) // boolean
1945 {
1946 if (nextchar == '=' || nextchar == ':')
1947 {
1948 errmsg = e_invalid_argument;
1949 goto skip;
1950 }
1951
1952 /*
1953 * ":set opt!": invert
1954 * ":set opt&": reset to default value
1955 * ":set opt<": reset to global value
1956 */
1957 if (nextchar == '!')
1958 value = *(int *)(varp) ^ 1;
1959 else if (nextchar == '&')
1960 value = (int)(long)(long_i)options[opt_idx].def_val[
1961 ((flags & P_VI_DEF) || cp_val)
1962 ? VI_DEFAULT : VIM_DEFAULT];
1963 else if (nextchar == '<')
1964 {
1965 // For 'autoread' -1 means to use global value.
1966 if ((int *)varp == &curbuf->b_p_ar
1967 && opt_flags == OPT_LOCAL)
1968 value = -1;
1969 else
1970 value = *(int *)get_varp_scope(&(options[opt_idx]),
1971 OPT_GLOBAL);
1972 }
1973 else
1974 {
1975 /*
1976 * ":set invopt": invert
1977 * ":set opt" or ":set noopt": set or reset
1978 */
1979 if (nextchar != NUL && !VIM_ISWHITE(afterchar))
1980 {
1981 errmsg = e_trailing_characters;
1982 goto skip;
1983 }
1984 if (prefix == 2) // inv
1985 value = *(int *)(varp) ^ 1;
1986 else
1987 value = prefix;
1988 }
1989
1990 errmsg = set_bool_option(opt_idx, varp, (int)value,
1991 opt_flags);
1992 }
1993 else // numeric or string
1994 {
1995 if (vim_strchr((char_u *)"=:&<", nextchar) == NULL
1996 || prefix != 1)
1997 {
1998 errmsg = e_invalid_argument;
1999 goto skip;
2000 }
2001
2002 if (flags & P_NUM) // numeric
2003 {
2004 /*
2005 * Different ways to set a number option:
2006 * & set to default value
2007 * < set to global value
2008 * <xx> accept special key codes for 'wildchar'
2009 * c accept any non-digit for 'wildchar'
2010 * [-]0-9 set number
2011 * other error
2012 */
2013 ++arg;
2014 if (nextchar == '&')
2015 value = (long)(long_i)options[opt_idx].def_val[
2016 ((flags & P_VI_DEF) || cp_val)
2017 ? VI_DEFAULT : VIM_DEFAULT];
2018 else if (nextchar == '<')
2019 {
2020 // For 'undolevels' NO_LOCAL_UNDOLEVEL means to
2021 // use the global value.
2022 if ((long *)varp == &curbuf->b_p_ul
2023 && opt_flags == OPT_LOCAL)
2024 value = NO_LOCAL_UNDOLEVEL;
2025 else
2026 value = *(long *)get_varp_scope(
2027 &(options[opt_idx]), OPT_GLOBAL);
2028 }
2029 else if (((long *)varp == &p_wc
2030 || (long *)varp == &p_wcm)
2031 && (*arg == '<'
2032 || *arg == '^'
2033 || (*arg != NUL
2034 && (!arg[1] || VIM_ISWHITE(arg[1]))
2035 && !VIM_ISDIGIT(*arg))))
2036 {
2037 value = string_to_key(arg, FALSE);
2038 if (value == 0 && (long *)varp != &p_wcm)
2039 {
2040 errmsg = e_invalid_argument;
2041 goto skip;
2042 }
2043 }
2044 else if (*arg == '-' || VIM_ISDIGIT(*arg))
2045 {
2046 // Allow negative (for 'undolevels'), octal and
2047 // hex numbers.
2048 vim_str2nr(arg, NULL, &i, STR2NR_ALL,
2049 &value, NULL, 0, TRUE);
2050 if (i == 0 || (arg[i] != NUL
2051 && !VIM_ISWHITE(arg[i])))
2052 {
2053 errmsg = e_number_required_after_equal;
2054 goto skip;
2055 }
2056 }
2057 else
2058 {
2059 errmsg = e_number_required_after_equal;
2060 goto skip;
2061 }
2062
2063 if (op == OP_ADDING)
2064 value = *(long *)varp + value;
2065 else if (op == OP_PREPENDING)
2066 value = *(long *)varp * value;
2067 else if (op == OP_REMOVING)
2068 value = *(long *)varp - value;
2069 errmsg = set_num_option(opt_idx, varp, value,
2070 errbuf, errbuflen, opt_flags);
2071 }
2072 else if (opt_idx >= 0) // string
2073 {
2074 if (do_set_string(opt_idx, opt_flags, &arg, nextchar,
2075 op, flags, cp_val, varp, errbuf,
2076 &value_checked, &errmsg) == FAIL)
2077 {
2078 if (errmsg != NULL)
2079 goto skip;
2080 *stopopteval = TRUE;
2081 goto skip;
2082 }
2083 }
2084 else // key code option
2085 {
2086 char_u *p;
2087
2088 if (nextchar == '&')
2089 {
2090 if (add_termcap_entry(key_name, TRUE) == FAIL)
2091 errmsg = e_not_found_in_termcap;
2092 }
2093 else
2094 {
2095 ++arg; // jump to after the '=' or ':'
2096 for (p = arg; *p && !VIM_ISWHITE(*p); ++p)
2097 if (*p == '\\' && p[1] != NUL)
2098 ++p;
2099 nextchar = *p;
2100 *p = NUL;
2101 add_termcode(key_name, arg, FALSE);
2102 *p = nextchar;
2103 }
2104 if (full_screen)
2105 ttest(FALSE);
2106 redraw_all_later(UPD_CLEAR);
2107 }
2108 }
2109
2110 if (opt_idx >= 0)
2111 did_set_option(
2112 opt_idx, opt_flags, op == OP_NONE, value_checked);
2113 }
2114
2115 skip:
2116 *argp = arg;
2117 return errmsg;
2118 }
2119
2120 /*
1636 * Parse 'arg' for option settings. 2121 * Parse 'arg' for option settings.
1637 * 2122 *
1638 * 'arg' may be IObuff, but only when no errors can be present and option 2123 * 'arg' may be IObuff, but only when no errors can be present and option
1639 * does not need to be expanded with option_expand(). 2124 * does not need to be expanded with option_expand().
1640 * "opt_flags": 2125 * "opt_flags":
1644 * OPT_MODELINE for a modeline 2129 * OPT_MODELINE for a modeline
1645 * OPT_WINONLY to only set window-local options 2130 * OPT_WINONLY to only set window-local options
1646 * OPT_NOWIN to skip setting window-local options 2131 * OPT_NOWIN to skip setting window-local options
1647 * OPT_ONECOLUMN do not use multiple columns 2132 * OPT_ONECOLUMN do not use multiple columns
1648 * 2133 *
1649 * returns FAIL if an error is detected, OK otherwise 2134 * Returns FAIL if an error is detected, OK otherwise.
1650 */ 2135 */
1651 int 2136 int
1652 do_set( 2137 do_set(
1653 char_u *arg_start, // option string (may be written to!) 2138 char_u *arg_start, // option string (may be written to!)
1654 int opt_flags) 2139 int opt_flags)
1655 { 2140 {
1656 char_u *arg = arg_start; 2141 char_u *arg = arg_start;
1657 int opt_idx;
1658 char *errmsg;
1659 char errbuf[80];
1660 char_u *startarg;
1661 int prefix; // 1: nothing, 0: "no", 2: "inv" in front of name
1662 int nextchar; // next non-white char after option name
1663 int afterchar; // character just after option name
1664 int len;
1665 int i; 2142 int i;
1666 varnumber_T value;
1667 int key;
1668 long_u flags; // flags for current option
1669 char_u *varp = NULL; // pointer to variable for current option
1670 int did_show = FALSE; // already showed one value 2143 int did_show = FALSE; // already showed one value
1671 set_op_T op = 0;
1672 int cp_val = 0;
1673 char_u key_name[2];
1674 2144
1675 if (*arg == NUL) 2145 if (*arg == NUL)
1676 { 2146 {
1677 showoptions(0, opt_flags); 2147 showoptions(0, opt_flags);
1678 did_show = TRUE; 2148 did_show = TRUE;
1679 goto theend; 2149 goto theend;
1680 } 2150 }
1681 2151
1682 while (*arg != NUL) // loop to process all options 2152 while (*arg != NUL) // loop to process all options
1683 { 2153 {
1684 errmsg = NULL;
1685 startarg = arg; // remember for error message
1686
1687 if (STRNCMP(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3]) 2154 if (STRNCMP(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3])
1688 && !(opt_flags & OPT_MODELINE)) 2155 && !(opt_flags & OPT_MODELINE))
1689 { 2156 {
1690 /* 2157 /*
1691 * ":set all" show all options. 2158 * ":set all" show all options.
1714 did_show = TRUE; 2181 did_show = TRUE;
1715 arg += 7; 2182 arg += 7;
1716 } 2183 }
1717 else 2184 else
1718 { 2185 {
1719 prefix = 1; 2186 int stopopteval = FALSE;
1720 if (STRNCMP(arg, "no", 2) == 0 && STRNCMP(arg, "novice", 6) != 0) 2187 char *errmsg = NULL;
1721 { 2188 char errbuf[80];
1722 prefix = 0; 2189 char_u *startarg = arg;
1723 arg += 2; 2190
1724 } 2191 errmsg = do_set_option(opt_flags, &arg, arg_start, &startarg,
1725 else if (STRNCMP(arg, "inv", 3) == 0) 2192 &did_show, &stopopteval, errbuf,
1726 { 2193 sizeof(errbuf));
1727 prefix = 2; 2194 if (stopopteval)
1728 arg += 3; 2195 break;
1729 } 2196
1730
1731 // find end of name
1732 key = 0;
1733 if (*arg == '<')
1734 {
1735 opt_idx = -1;
1736 // look out for <t_>;>
1737 if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4])
1738 len = 5;
1739 else
1740 {
1741 len = 1;
1742 while (arg[len] != NUL && arg[len] != '>')
1743 ++len;
1744 }
1745 if (arg[len] != '>')
1746 {
1747 errmsg = e_invalid_argument;
1748 goto skip;
1749 }
1750 arg[len] = NUL; // put NUL after name
1751 if (arg[1] == 't' && arg[2] == '_') // could be term code
1752 opt_idx = findoption(arg + 1);
1753 arg[len++] = '>'; // restore '>'
1754 if (opt_idx == -1)
1755 key = find_key_option(arg + 1, TRUE);
1756 }
1757 else
1758 {
1759 len = 0;
1760 /*
1761 * The two characters after "t_" may not be alphanumeric.
1762 */
1763 if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3])
1764 len = 4;
1765 else
1766 while (ASCII_ISALNUM(arg[len]) || arg[len] == '_')
1767 ++len;
1768 nextchar = arg[len];
1769 arg[len] = NUL; // put NUL after name
1770 opt_idx = findoption(arg);
1771 arg[len] = nextchar; // restore nextchar
1772 if (opt_idx == -1)
1773 key = find_key_option(arg, FALSE);
1774 }
1775
1776 // remember character after option name
1777 afterchar = arg[len];
1778
1779 if (in_vim9script())
1780 {
1781 char_u *p = skipwhite(arg + len);
1782
1783 // disallow white space before =val, +=val, -=val, ^=val
1784 if (p > arg + len && (p[0] == '='
1785 || (vim_strchr((char_u *)"+-^", p[0]) != NULL
1786 && p[1] == '=')))
1787 {
1788 errmsg = e_no_white_space_allowed_between_option_and;
1789 arg = p;
1790 startarg = p;
1791 goto skip;
1792 }
1793 }
1794 else
1795 // skip white space, allow ":set ai ?", ":set hlsearch !"
1796 while (VIM_ISWHITE(arg[len]))
1797 ++len;
1798
1799 op = OP_NONE;
1800 if (arg[len] != NUL && arg[len + 1] == '=')
1801 {
1802 if (arg[len] == '+')
1803 {
1804 op = OP_ADDING; // "+="
1805 ++len;
1806 }
1807 else if (arg[len] == '^')
1808 {
1809 op = OP_PREPENDING; // "^="
1810 ++len;
1811 }
1812 else if (arg[len] == '-')
1813 {
1814 op = OP_REMOVING; // "-="
1815 ++len;
1816 }
1817 }
1818 nextchar = arg[len];
1819
1820 if (opt_idx == -1 && key == 0) // found a mismatch: skip
1821 {
1822 if (in_vim9script() && arg > arg_start
1823 && vim_strchr((char_u *)"!&<", *arg) != NULL)
1824 errmsg = e_no_white_space_allowed_between_option_and;
1825 else
1826 errmsg = e_unknown_option;
1827 goto skip;
1828 }
1829
1830 if (opt_idx >= 0)
1831 {
1832 if (options[opt_idx].var == NULL) // hidden option: skip
1833 {
1834 // Only give an error message when requesting the value of
1835 // a hidden option, ignore setting it.
1836 if (vim_strchr((char_u *)"=:!&<", nextchar) == NULL
1837 && (!(options[opt_idx].flags & P_BOOL)
1838 || nextchar == '?'))
1839 errmsg = e_option_not_supported;
1840 goto skip;
1841 }
1842
1843 flags = options[opt_idx].flags;
1844 varp = get_varp_scope(&(options[opt_idx]), opt_flags);
1845 }
1846 else
1847 {
1848 flags = P_STRING;
1849 if (key < 0)
1850 {
1851 key_name[0] = KEY2TERMCAP0(key);
1852 key_name[1] = KEY2TERMCAP1(key);
1853 }
1854 else
1855 {
1856 key_name[0] = KS_KEY;
1857 key_name[1] = (key & 0xff);
1858 }
1859 }
1860
1861 // Skip all options that are not window-local (used when showing
1862 // an already loaded buffer in a window).
1863 if ((opt_flags & OPT_WINONLY)
1864 && (opt_idx < 0 || options[opt_idx].var != VAR_WIN))
1865 goto skip;
1866
1867 // Skip all options that are window-local (used for :vimgrep).
1868 if ((opt_flags & OPT_NOWIN) && opt_idx >= 0
1869 && options[opt_idx].var == VAR_WIN)
1870 goto skip;
1871
1872 // Disallow changing some options from modelines.
1873 if (opt_flags & OPT_MODELINE)
1874 {
1875 if (flags & (P_SECURE | P_NO_ML))
1876 {
1877 errmsg = e_not_allowed_in_modeline;
1878 goto skip;
1879 }
1880 if ((flags & P_MLE) && !p_mle)
1881 {
1882 errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off;
1883 goto skip;
1884 }
1885 #ifdef FEAT_DIFF
1886 // In diff mode some options are overruled. This avoids that
1887 // 'foldmethod' becomes "marker" instead of "diff" and that
1888 // "wrap" gets set.
1889 if (curwin->w_p_diff
1890 && opt_idx >= 0 // shut up coverity warning
1891 && (
1892 #ifdef FEAT_FOLDING
1893 options[opt_idx].indir == PV_FDM ||
1894 #endif
1895 options[opt_idx].indir == PV_WRAP))
1896 goto skip;
1897 #endif
1898 }
1899
1900 #ifdef HAVE_SANDBOX
1901 // Disallow changing some options in the sandbox
1902 if (sandbox != 0 && (flags & P_SECURE))
1903 {
1904 errmsg = e_not_allowed_in_sandbox;
1905 goto skip;
1906 }
1907 #endif
1908
1909 if (vim_strchr((char_u *)"?=:!&<", nextchar) != NULL)
1910 {
1911 arg += len;
1912 cp_val = p_cp;
1913 if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i')
1914 {
1915 if (arg[3] == 'm') // "opt&vim": set to Vim default
1916 {
1917 cp_val = FALSE;
1918 arg += 3;
1919 }
1920 else // "opt&vi": set to Vi default
1921 {
1922 cp_val = TRUE;
1923 arg += 2;
1924 }
1925 }
1926 if (vim_strchr((char_u *)"?!&<", nextchar) != NULL
1927 && arg[1] != NUL && !VIM_ISWHITE(arg[1]))
1928 {
1929 errmsg = e_trailing_characters;
1930 goto skip;
1931 }
1932 }
1933
1934 /*
1935 * allow '=' and ':' for historical reasons (MSDOS command.com
1936 * allows only one '=' character per "set" command line. grrr. (jw)
1937 */
1938 if (nextchar == '?'
1939 || (prefix == 1
1940 && vim_strchr((char_u *)"=:&<", nextchar) == NULL
1941 && !(flags & P_BOOL)))
1942 {
1943 /*
1944 * print value
1945 */
1946 if (did_show)
1947 msg_putchar('\n'); // cursor below last one
1948 else
1949 {
1950 gotocmdline(TRUE); // cursor at status line
1951 did_show = TRUE; // remember that we did a line
1952 }
1953 if (opt_idx >= 0)
1954 {
1955 showoneopt(&options[opt_idx], opt_flags);
1956 #ifdef FEAT_EVAL
1957 if (p_verbose > 0)
1958 {
1959 // Mention where the option was last set.
1960 if (varp == options[opt_idx].var)
1961 last_set_msg(options[opt_idx].script_ctx);
1962 else if ((int)options[opt_idx].indir & PV_WIN)
1963 last_set_msg(curwin->w_p_script_ctx[
1964 (int)options[opt_idx].indir & PV_MASK]);
1965 else if ((int)options[opt_idx].indir & PV_BUF)
1966 last_set_msg(curbuf->b_p_script_ctx[
1967 (int)options[opt_idx].indir & PV_MASK]);
1968 }
1969 #endif
1970 }
1971 else
1972 {
1973 char_u *p;
1974
1975 p = find_termcode(key_name);
1976 if (p == NULL)
1977 {
1978 errmsg = e_key_code_not_set;
1979 goto skip;
1980 }
1981 else
1982 (void)show_one_termcode(key_name, p, TRUE);
1983 }
1984 if (nextchar != '?'
1985 && nextchar != NUL && !VIM_ISWHITE(afterchar))
1986 errmsg = e_trailing_characters;
1987 }
1988 else
1989 {
1990 int value_checked = FALSE;
1991
1992 if (flags & P_BOOL) // boolean
1993 {
1994 if (nextchar == '=' || nextchar == ':')
1995 {
1996 errmsg = e_invalid_argument;
1997 goto skip;
1998 }
1999
2000 /*
2001 * ":set opt!": invert
2002 * ":set opt&": reset to default value
2003 * ":set opt<": reset to global value
2004 */
2005 if (nextchar == '!')
2006 value = *(int *)(varp) ^ 1;
2007 else if (nextchar == '&')
2008 value = (int)(long)(long_i)options[opt_idx].def_val[
2009 ((flags & P_VI_DEF) || cp_val)
2010 ? VI_DEFAULT : VIM_DEFAULT];
2011 else if (nextchar == '<')
2012 {
2013 // For 'autoread' -1 means to use global value.
2014 if ((int *)varp == &curbuf->b_p_ar
2015 && opt_flags == OPT_LOCAL)
2016 value = -1;
2017 else
2018 value = *(int *)get_varp_scope(&(options[opt_idx]),
2019 OPT_GLOBAL);
2020 }
2021 else
2022 {
2023 /*
2024 * ":set invopt": invert
2025 * ":set opt" or ":set noopt": set or reset
2026 */
2027 if (nextchar != NUL && !VIM_ISWHITE(afterchar))
2028 {
2029 errmsg = e_trailing_characters;
2030 goto skip;
2031 }
2032 if (prefix == 2) // inv
2033 value = *(int *)(varp) ^ 1;
2034 else
2035 value = prefix;
2036 }
2037
2038 errmsg = set_bool_option(opt_idx, varp, (int)value,
2039 opt_flags);
2040 }
2041 else // numeric or string
2042 {
2043 if (vim_strchr((char_u *)"=:&<", nextchar) == NULL
2044 || prefix != 1)
2045 {
2046 errmsg = e_invalid_argument;
2047 goto skip;
2048 }
2049
2050 if (flags & P_NUM) // numeric
2051 {
2052 /*
2053 * Different ways to set a number option:
2054 * & set to default value
2055 * < set to global value
2056 * <xx> accept special key codes for 'wildchar'
2057 * c accept any non-digit for 'wildchar'
2058 * [-]0-9 set number
2059 * other error
2060 */
2061 ++arg;
2062 if (nextchar == '&')
2063 value = (long)(long_i)options[opt_idx].def_val[
2064 ((flags & P_VI_DEF) || cp_val)
2065 ? VI_DEFAULT : VIM_DEFAULT];
2066 else if (nextchar == '<')
2067 {
2068 // For 'undolevels' NO_LOCAL_UNDOLEVEL means to
2069 // use the global value.
2070 if ((long *)varp == &curbuf->b_p_ul
2071 && opt_flags == OPT_LOCAL)
2072 value = NO_LOCAL_UNDOLEVEL;
2073 else
2074 value = *(long *)get_varp_scope(
2075 &(options[opt_idx]), OPT_GLOBAL);
2076 }
2077 else if (((long *)varp == &p_wc
2078 || (long *)varp == &p_wcm)
2079 && (*arg == '<'
2080 || *arg == '^'
2081 || (*arg != NUL
2082 && (!arg[1] || VIM_ISWHITE(arg[1]))
2083 && !VIM_ISDIGIT(*arg))))
2084 {
2085 value = string_to_key(arg, FALSE);
2086 if (value == 0 && (long *)varp != &p_wcm)
2087 {
2088 errmsg = e_invalid_argument;
2089 goto skip;
2090 }
2091 }
2092 else if (*arg == '-' || VIM_ISDIGIT(*arg))
2093 {
2094 // Allow negative (for 'undolevels'), octal and
2095 // hex numbers.
2096 vim_str2nr(arg, NULL, &i, STR2NR_ALL,
2097 &value, NULL, 0, TRUE);
2098 if (i == 0 || (arg[i] != NUL
2099 && !VIM_ISWHITE(arg[i])))
2100 {
2101 errmsg = e_number_required_after_equal;
2102 goto skip;
2103 }
2104 }
2105 else
2106 {
2107 errmsg = e_number_required_after_equal;
2108 goto skip;
2109 }
2110
2111 if (op == OP_ADDING)
2112 value = *(long *)varp + value;
2113 else if (op == OP_PREPENDING)
2114 value = *(long *)varp * value;
2115 else if (op == OP_REMOVING)
2116 value = *(long *)varp - value;
2117 errmsg = set_num_option(opt_idx, varp, value,
2118 errbuf, sizeof(errbuf), opt_flags);
2119 }
2120 else if (opt_idx >= 0) // string
2121 {
2122 if (do_set_string(opt_idx, opt_flags, &arg, nextchar,
2123 op, flags, cp_val, varp, errbuf,
2124 &value_checked, &errmsg) == FAIL)
2125 {
2126 if (errmsg != NULL)
2127 goto skip;
2128 break;
2129 }
2130 }
2131 else // key code option
2132 {
2133 char_u *p;
2134
2135 if (nextchar == '&')
2136 {
2137 if (add_termcap_entry(key_name, TRUE) == FAIL)
2138 errmsg = e_not_found_in_termcap;
2139 }
2140 else
2141 {
2142 ++arg; // jump to after the '=' or ':'
2143 for (p = arg; *p && !VIM_ISWHITE(*p); ++p)
2144 if (*p == '\\' && p[1] != NUL)
2145 ++p;
2146 nextchar = *p;
2147 *p = NUL;
2148 add_termcode(key_name, arg, FALSE);
2149 *p = nextchar;
2150 }
2151 if (full_screen)
2152 ttest(FALSE);
2153 redraw_all_later(UPD_CLEAR);
2154 }
2155 }
2156
2157 if (opt_idx >= 0)
2158 did_set_option(
2159 opt_idx, opt_flags, op == OP_NONE, value_checked);
2160 }
2161
2162 skip:
2163 /* 2197 /*
2164 * Advance to next argument. 2198 * Advance to next argument.
2165 * - skip until a blank found, taking care of backslashes 2199 * - skip until a blank found, taking care of backslashes
2166 * - skip blanks 2200 * - skip blanks
2167 * - skip one "=val" argument (for hidden options ":set gfn =xx") 2201 * - skip one "=val" argument (for hidden options ":set gfn =xx")
2173 ++arg; 2207 ++arg;
2174 arg = skipwhite(arg); 2208 arg = skipwhite(arg);
2175 if (*arg != '=') 2209 if (*arg != '=')
2176 break; 2210 break;
2177 } 2211 }
2178 } 2212
2179 2213 if (errmsg != NULL)
2180 if (errmsg != NULL) 2214 {
2181 { 2215 vim_strncpy(IObuff, (char_u *)_(errmsg), IOSIZE - 1);
2182 vim_strncpy(IObuff, (char_u *)_(errmsg), IOSIZE - 1); 2216 i = (int)STRLEN(IObuff) + 2;
2183 i = (int)STRLEN(IObuff) + 2; 2217 if (i + (arg - startarg) < IOSIZE)
2184 if (i + (arg - startarg) < IOSIZE) 2218 {
2185 { 2219 // append the argument with the error
2186 // append the argument with the error 2220 STRCAT(IObuff, ": ");
2187 STRCAT(IObuff, ": "); 2221 mch_memmove(IObuff + i, startarg, (arg - startarg));
2188 mch_memmove(IObuff + i, startarg, (arg - startarg)); 2222 IObuff[i + (arg - startarg)] = NUL;
2189 IObuff[i + (arg - startarg)] = NUL; 2223 }
2190 } 2224 // make sure all characters are printable
2191 // make sure all characters are printable 2225 trans_characters(IObuff, IOSIZE);
2192 trans_characters(IObuff, IOSIZE); 2226
2193 2227 ++no_wait_return; // wait_return() done later
2194 ++no_wait_return; // wait_return() done later 2228 emsg((char *)IObuff); // show error highlighted
2195 emsg((char *)IObuff); // show error highlighted 2229 --no_wait_return;
2196 --no_wait_return; 2230
2197 2231 return FAIL;
2198 return FAIL; 2232 }
2199 } 2233 }
2200 2234
2201 arg = skipwhite(arg); 2235 arg = skipwhite(arg);
2202 } 2236 }
2203 2237