diff options
Diffstat (limited to 'usr.bin/vim/option.c')
-rw-r--r-- | usr.bin/vim/option.c | 4165 |
1 files changed, 4165 insertions, 0 deletions
diff --git a/usr.bin/vim/option.c b/usr.bin/vim/option.c new file mode 100644 index 00000000000..437d14ce1cc --- /dev/null +++ b/usr.bin/vim/option.c @@ -0,0 +1,4165 @@ +/* $OpenBSD: option.c,v 1.1 1996/09/07 21:40:25 downsj Exp $ */ +/* vi:set ts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + */ + +/* + * Code to handle user-settable options. This is all pretty much table- + * driven. To add a new option, put it in the options array, and add a + * variable for it in option.h. If it's a numeric option, add any necessary + * bounds checks to do_set(). + */ + +#include "vim.h" +#include "globals.h" +#include "proto.h" +#include "option.h" + +struct option +{ + char *fullname; /* full option name */ + char *shortname; /* permissible abbreviation */ + short flags; /* see below */ + char_u *var; /* pointer to variable */ + char_u *def_val; /* default value for variable (can be the same + as the actual value) */ +}; + +/* + * Flags + * + * Note: P_EXPAND and P_IND can never be used at the same time. + * Note: P_IND cannot be used for a terminal option. + */ +#define P_BOOL 0x01 /* the option is boolean */ +#define P_NUM 0x02 /* the option is numeric */ +#define P_STRING 0x04 /* the option is a string */ +#define P_ALLOCED 0x08 /* the string option is in allocated memory, + must use vim_free() when assigning new + value. Not set if default is the same. */ +#define P_EXPAND 0x10 /* environment expansion */ +#define P_IND 0x20 /* indirect, is in curwin or curbuf */ +#define P_NODEFAULT 0x40 /* has no default value */ +#define P_DEF_ALLOCED 0x80 /* default value is in allocated memory, must + use vim_free() when assigning new value */ +#define P_WAS_SET 0x100 /* option has been set/reset */ +#define P_NO_MKRC 0x200 /* don't include in :mkvimrc output */ + +/* + * The options that are in curwin or curbuf have P_IND set and a var field + * that contains one of the values below. + */ +#define PV_LIST 1 +#define PV_NU 2 +#define PV_SCROLL 3 +#define PV_WRAP 4 +#define PV_LBR 5 + +#define PV_AI 6 +#define PV_BIN 7 +#define PV_CIN 8 +#define PV_CINK 9 +#define PV_CINO 10 +#define PV_CINW 11 +#define PV_COM 12 +#define PV_EOL 13 +#define PV_ET 14 +#define PV_FO 15 +#define PV_LISP 16 +#define PV_ML 17 +#define PV_MOD 18 +#define PV_RO 20 +#define PV_SI 21 +#define PV_SN 22 +#define PV_SW 23 +#define PV_TS 24 +#define PV_TW 25 +#define PV_TX 26 +#define PV_WM 27 +#define PV_ISK 28 +#define PV_INF 29 +#define PV_RL 30 + +/* + * The option structure is initialized here. + * The order of the options should be alphabetic for ":set all". + * The options with a NULL variable are 'hidden': a set command for + * them is ignored and they are not printed. + */ +static struct option options[] = +{ +#ifdef RIGHTLEFT + {"aleph", "al", P_NUM, (char_u *)&p_aleph, +# if defined(MSDOS) || defined(WIN32) || defined(OS2) + (char_u *)128L}, +# else + (char_u *)224L}, +# endif +#endif + {"autoindent", "ai", P_BOOL|P_IND, (char_u *)PV_AI, + (char_u *)FALSE}, + {"autoprint", "ap", P_BOOL, (char_u *)NULL, + (char_u *)FALSE}, + {"autowrite", "aw", P_BOOL, (char_u *)&p_aw, + (char_u *)FALSE}, + {"backspace", "bs", P_NUM, (char_u *)&p_bs, + (char_u *)0L}, + {"backup", "bk", P_BOOL, (char_u *)&p_bk, + (char_u *)FALSE}, + {"backupdir", "bdir", P_STRING|P_EXPAND, + (char_u *)&p_bdir, + (char_u *)DEF_BDIR}, + {"backupext", "bex", P_STRING, (char_u *)&p_bex, +#ifdef VMS + (char_u *)"_"}, +#else + (char_u *)"~"}, +#endif + {"beautify", "bf", P_BOOL, (char_u *)NULL, + (char_u *)FALSE}, + {"binary", "bin", P_BOOL|P_IND, (char_u *)PV_BIN, + (char_u *)FALSE}, + {"bioskey", "biosk",P_BOOL, +#ifdef MSDOS + (char_u *)&p_biosk, +#else + (char_u *)NULL, +#endif + (char_u *)TRUE}, + {"breakat", "brk", P_STRING, (char_u *)&p_breakat, + (char_u *)" \t!@*-+_;:,./?"}, +#ifdef CINDENT + {"cindent", "cin", P_BOOL|P_IND, (char_u *)PV_CIN, + (char_u *)FALSE}, + {"cinkeys", "cink", P_STRING|P_IND|P_ALLOCED, (char_u *)PV_CINK, + (char_u *)"0{,0},:,0#,!^F,o,O,e"}, + {"cinoptions", "cino", P_STRING|P_IND|P_ALLOCED, (char_u *)PV_CINO, + (char_u *)""}, +#endif /* CINDENT */ +#if defined(SMARTINDENT) || defined(CINDENT) + {"cinwords", "cinw", P_STRING|P_IND|P_ALLOCED, (char_u *)PV_CINW, + (char_u *)"if,else,while,do,for,switch"}, +#endif + {"cmdheight", "ch", P_NUM, (char_u *)&p_ch, + (char_u *)1L}, + {"columns", "co", P_NUM|P_NODEFAULT|P_NO_MKRC, (char_u *)&Columns, + (char_u *)80L}, + {"comments", "com", P_STRING|P_IND|P_ALLOCED, (char_u *)PV_COM, + (char_u *)"sr:/*,mb:*,el:*/,://,b:#,:%,:XCOMM,n:>,fb:-"}, + {"compatible", "cp", P_BOOL, (char_u *)&p_cp, + (char_u *)FALSE}, + {"cpoptions", "cpo", P_STRING, (char_u *)&p_cpo, +#ifdef COMPATIBLE + (char_u *)CPO_ALL}, +#else + (char_u *)CPO_DEFAULT}, +#endif + {"define", "def", P_STRING, (char_u *)&p_def, + (char_u *)"^#[ \\t]*define"}, + {"dictionary", "dict", P_STRING|P_EXPAND, (char_u *)&p_dict, + (char_u *)""}, + {"digraph", "dg", P_BOOL, +#ifdef DIGRAPHS + (char_u *)&p_dg, +#else + (char_u *)NULL, +#endif /* DIGRAPHS */ + (char_u *)FALSE}, + {"directory", "dir", P_STRING|P_EXPAND, (char_u *)&p_dir, + (char_u *)DEF_DIR}, + {"edcompatible","ed", P_BOOL, (char_u *)&p_ed, + (char_u *)FALSE}, + {"endofline", "eol", P_BOOL|P_IND|P_NO_MKRC, (char_u *)PV_EOL, + (char_u *)FALSE}, + {"equalalways", "ea", P_BOOL, (char_u *)&p_ea, + (char_u *)TRUE}, + {"equalprg", "ep", P_STRING|P_EXPAND, (char_u *)&p_ep, + (char_u *)""}, + {"errorbells", "eb", P_BOOL, (char_u *)&p_eb, + (char_u *)FALSE}, + {"errorfile", "ef", P_STRING|P_EXPAND, (char_u *)&p_ef, +#ifdef AMIGA + (char_u *)"AztecC.Err"}, +#else + (char_u *)"errors.vim"}, +#endif + {"errorformat", "efm", P_STRING, (char_u *)&p_efm, +#ifdef AMIGA + /* don't use [^0-9] here, Manx C can't handle it */ + (char_u *)"%f>%l:%c:%t:%n:%m,%f:%l: %t%*[^0123456789]%n: %m,%f %l %t%*[^0123456789]%n: %m,%*[^\"]\"%f\"%*[^0123456789]%l: %m,%f:%l:%m"}, +#else +# if defined MSDOS || defined WIN32 + (char_u *)"%*[^\"]\"%f\"%*[^0-9]%l: %m,%f(%l) : %m,%*[^ ] %f %l: %m,%f:%l:%m"}, +# elif defined(__EMX__) /* put most common here (i.e. gcc format) at front */ + (char_u *)"%f:%l:%m,%*[^\"]\"%f\"%*[^0-9]%l: %m,\"%f\"%*[^0-9]%l: %m"}, +# else + (char_u *)"%*[^\"]\"%f\"%*[^0-9]%l: %m,\"%f\"%*[^0-9]%l: %m,%f:%l:%m"}, +# endif +#endif + {"esckeys", "ek", P_BOOL, (char_u *)&p_ek, +#ifdef COMPATIBLE + (char_u *)FALSE}, +#else + (char_u *)TRUE}, +#endif + {"expandtab", "et", P_BOOL|P_IND, (char_u *)PV_ET, + (char_u *)FALSE}, + {"exrc", NULL, P_BOOL, (char_u *)&p_exrc, + (char_u *)FALSE}, + {"flash", "fl", P_BOOL, (char_u *)NULL, + (char_u *)FALSE}, + {"formatoptions","fo", P_STRING|P_IND|P_ALLOCED, (char_u *)PV_FO, +#ifdef COMPATIBLE + (char_u *)FO_DFLT_VI}, +#else + (char_u *)FO_DFLT}, +#endif + {"formatprg", "fp", P_STRING|P_EXPAND, (char_u *)&p_fp, + (char_u *)""}, + {"gdefault", "gd", P_BOOL, (char_u *)&p_gd, + (char_u *)FALSE}, + {"graphic", "gr", P_BOOL, (char_u *)NULL, + (char_u *)FALSE}, + {"guifont", "gfn", P_STRING, +#ifdef USE_GUI + (char_u *)&p_guifont, + (char_u *)""}, +#else + (char_u *)NULL, + (char_u *)NULL}, +#endif + {"guioptions", "go", P_STRING, +#ifdef USE_GUI + (char_u *)&p_guioptions, +# ifdef UNIX + (char_u *)"aAgmr"}, +# else + (char_u *)"Agmr"}, +# endif +#else + (char_u *)NULL, + (char_u *)NULL}, +#endif +#if defined(USE_GUI) + {"guipty", NULL, P_BOOL, (char_u *)&p_guipty, + (char_u *)FALSE}, +#endif + {"hardtabs", "ht", P_NUM, (char_u *)NULL, + (char_u *)0L}, + {"helpfile", "hf", P_STRING|P_EXPAND, (char_u *)&p_hf, + (char_u *)""}, + {"helpheight", "hh", P_NUM, (char_u *)&p_hh, + (char_u *)20L}, + {"hidden", "hid", P_BOOL, (char_u *)&p_hid, + (char_u *)FALSE}, + {"highlight", "hl", P_STRING, (char_u *)&p_hl, + (char_u *)"8b,db,es,hs,mb,Mn,nu,rs,sr,tb,vr,ws"}, + {"history", "hi", P_NUM, (char_u *)&p_hi, +#ifdef COMPATIBLE + (char_u *)0L}, +#else + (char_u *)20L}, +#endif +#ifdef RIGHTLEFT + {"hkmap", "hk", P_BOOL, (char_u *)&p_hkmap, + (char_u *)FALSE}, +#endif + {"icon", NULL, P_BOOL, (char_u *)&p_icon, + (char_u *)FALSE}, + {"ignorecase", "ic", P_BOOL, (char_u *)&p_ic, + (char_u *)FALSE}, + {"include", "inc", P_STRING, (char_u *)&p_inc, + (char_u *)"^#[ \\t]*include"}, + {"incsearch", "is", P_BOOL, (char_u *)&p_is, + (char_u *)FALSE}, + {"infercase", "inf", P_BOOL|P_IND, (char_u *)PV_INF, + (char_u *)FALSE}, + {"insertmode", "im", P_BOOL, (char_u *)&p_im, + (char_u *)FALSE}, + {"isfname", "isf", P_STRING, (char_u *)&p_isf, +#ifdef BACKSLASH_IN_FILENAME + (char_u *)"@,48-57,/,.,-,_,+,,,$,:,\\"}, +#else +# ifdef AMIGA + (char_u *)"@,48-57,/,.,-,_,+,,,$,:"}, +# else /* UNIX */ + (char_u *)"@,48-57,/,.,-,_,+,,,$,:,~"}, +# endif +#endif + {"isident", "isi", P_STRING, (char_u *)&p_isi, +#if defined(MSDOS) || defined(WIN32) || defined(OS2) + (char_u *)"@,48-57,_,128-167,224-235"}, +#else + (char_u *)"@,48-57,_,192-255"}, +#endif + {"iskeyword", "isk", P_STRING|P_IND|P_ALLOCED, (char_u *)PV_ISK, +#ifdef COMPATIBLE + (char_u *)"@,48-57,_"}, +#else +# if defined MSDOS || defined WIN32 + (char_u *)"@,48-57,_,128-167,224-235"}, +# else + (char_u *)"@,48-57,_,192-255"}, +# endif +#endif + {"isprint", "isp", P_STRING, (char_u *)&p_isp, +#if defined MSDOS || defined WIN32 + (char_u *)"@,~-255"}, +#else + (char_u *)"@,161-255"}, +#endif + {"joinspaces", "js", P_BOOL, (char_u *)&p_js, + (char_u *)TRUE}, + {"keywordprg", "kp", P_STRING|P_EXPAND, (char_u *)&p_kp, +#if defined(MSDOS) || defined(WIN32) + (char_u *)""}, +#else + (char_u *)"man"}, +#endif + {"langmap", "lmap", P_STRING, +#ifdef HAVE_LANGMAP + (char_u *)&p_langmap, + (char_u *)""}, +#else + (char_u *)NULL, + (char_u *)NULL}, +#endif + {"laststatus", "ls", P_NUM, (char_u *)&p_ls, + (char_u *)1L}, + {"linebreak", "lbr", P_BOOL|P_IND, (char_u *)PV_LBR, + (char_u *)FALSE}, + {"lines", NULL, P_NUM|P_NODEFAULT|P_NO_MKRC, (char_u *)&Rows, +#if defined MSDOS || defined WIN32 + (char_u *)25L}, +#else + (char_u *)24L}, +#endif + {"lisp", NULL, P_BOOL|P_IND, (char_u *)PV_LISP, + (char_u *)FALSE}, + {"list", NULL, P_BOOL|P_IND, (char_u *)PV_LIST, + (char_u *)FALSE}, + {"magic", NULL, P_BOOL, (char_u *)&p_magic, + (char_u *)TRUE}, + {"makeprg", "mp", P_STRING|P_EXPAND, (char_u *)&p_mp, + (char_u *)"make"}, + {"maxmapdepth", "mmd", P_NUM, (char_u *)&p_mmd, + (char_u *)1000L}, + {"maxmem", "mm", P_NUM, (char_u *)&p_mm, + (char_u *)MAXMEM}, + {"maxmemtot", "mmt", P_NUM, (char_u *)&p_mmt, + (char_u *)MAXMEMTOT}, + {"mesg", NULL, P_BOOL, (char_u *)NULL, + (char_u *)FALSE}, + {"modeline", "ml", P_BOOL|P_IND, (char_u *)PV_ML, +#ifdef COMPATIBLE + (char_u *)FALSE}, +#else + (char_u *)TRUE}, +#endif + {"modelines", "mls", P_NUM, (char_u *)&p_mls, + (char_u *)5L}, + {"modified", "mod", P_BOOL|P_IND|P_NO_MKRC, (char_u *)PV_MOD, + (char_u *)FALSE}, + {"more", NULL, P_BOOL, (char_u *)&p_more, +#ifdef COMPATIBLE + (char_u *)FALSE}, +#else + (char_u *)TRUE}, +#endif + {"mouse", NULL, P_STRING, (char_u *)&p_mouse, +#if defined(MSDOS) || defined(WIN32) + (char_u *)"a"}, +#else + (char_u *)""}, +#endif + {"mousetime", "mouset", P_NUM, (char_u *)&p_mouset, + (char_u *)500L}, + {"novice", NULL, P_BOOL, (char_u *)NULL, + (char_u *)FALSE}, + {"number", "nu", P_BOOL|P_IND, (char_u *)PV_NU, + (char_u *)FALSE}, + {"open", NULL, P_BOOL, (char_u *)NULL, + (char_u *)FALSE}, + {"optimize", "opt", P_BOOL, (char_u *)NULL, + (char_u *)FALSE}, + {"paragraphs", "para", P_STRING, (char_u *)&p_para, + (char_u *)"IPLPPPQPP LIpplpipbp"}, + {"paste", NULL, P_BOOL, (char_u *)&p_paste, + (char_u *)FALSE}, + {"patchmode", "pm", P_STRING, (char_u *)&p_pm, + (char_u *)""}, + {"path", "pa", P_STRING|P_EXPAND, (char_u *)&p_path, +#if defined AMIGA || defined MSDOS || defined WIN32 + (char_u *)".,,"}, +#elif defined(__EMX__) + (char_u *)".,/emx/include,,"}, +#else + (char_u *)".,/usr/include,,"}, +#endif + {"prompt", NULL, P_BOOL, (char_u *)NULL, + (char_u *)FALSE}, + {"readonly", "ro", P_BOOL|P_IND, (char_u *)PV_RO, + (char_u *)FALSE}, + {"redraw", NULL, P_BOOL, (char_u *)NULL, + (char_u *)FALSE}, + {"remap", NULL, P_BOOL, (char_u *)&p_remap, + (char_u *)TRUE}, + {"report", NULL, P_NUM, (char_u *)&p_report, + (char_u *)2L}, +#ifdef WIN32 + {"restorescreen", "rs", P_BOOL, (char_u *)&p_rs, + (char_u *)TRUE}, +#endif +#ifdef RIGHTLEFT + {"revins", "ri", P_BOOL, (char_u *)&p_ri, + (char_u *)FALSE}, + {"rightleft", "rl", P_BOOL|P_IND, (char_u *)PV_RL, + (char_u *)FALSE}, +#endif + {"ruler", "ru", P_BOOL, (char_u *)&p_ru, + (char_u *)FALSE}, + {"scroll", "scr", P_NUM|P_IND|P_NO_MKRC, (char_u *)PV_SCROLL, + (char_u *)12L}, + {"scrolljump", "sj", P_NUM, (char_u *)&p_sj, + (char_u *)1L}, + {"scrolloff", "so", P_NUM, (char_u *)&p_so, + (char_u *)0L}, + {"sections", "sect", P_STRING, (char_u *)&p_sections, + (char_u *)"SHNHH HUnhsh"}, + {"secure", NULL, P_BOOL, (char_u *)&p_secure, + (char_u *)FALSE}, + {"shell", "sh", P_STRING|P_EXPAND, (char_u *)&p_sh, +#if defined(MSDOS) + (char_u *)"command"}, +#elif defined(WIN32) + (char_u *)""}, /* set in set_init_1() */ +#elif defined(__EMX__) + (char_u *)"cmd.exe"}, +#elif defined(ARCHIE) + (char_u *)"gos"}, +#else + (char_u *)"sh"}, +#endif + {"shellpipe", "sp", P_STRING, (char_u *)&p_sp, +#if defined(UNIX) || defined(OS2) +# ifdef ARCHIE + (char_u *)"2>"}, +# else + (char_u *)"| tee"}, +# endif +#else + (char_u *)">"}, +#endif + {"shellredir", "srr", P_STRING, (char_u *)&p_srr, + (char_u *)">"}, + {"shelltype", "st", P_NUM, (char_u *)&p_st, + (char_u *)0L}, + {"shiftround", "sr", P_BOOL, (char_u *)&p_sr, + (char_u *)FALSE}, + {"shiftwidth", "sw", P_NUM|P_IND, (char_u *)PV_SW, + (char_u *)8L}, + {"shortmess", "shm", P_STRING, (char_u *)&p_shm, + (char_u *)""}, + {"shortname", "sn", P_BOOL|P_IND, +#ifdef SHORT_FNAME + (char_u *)NULL, +#else + (char_u *)PV_SN, +#endif + (char_u *)FALSE}, + {"showbreak", "sbr", P_STRING, (char_u *)&p_sbr, + (char_u *)""}, + {"showcmd", "sc", P_BOOL, (char_u *)&p_sc, +#if defined(COMPATIBLE) || defined(UNIX) + (char_u *)FALSE}, +#else + (char_u *)TRUE}, +#endif + {"showmatch", "sm", P_BOOL, (char_u *)&p_sm, + (char_u *)FALSE}, + {"showmode", "smd", P_BOOL, (char_u *)&p_smd, +#if defined(COMPATIBLE) + (char_u *)FALSE}, +#else + (char_u *)TRUE}, +#endif + {"sidescroll", "ss", P_NUM, (char_u *)&p_ss, + (char_u *)0L}, + {"slowopen", "slow", P_BOOL, (char_u *)NULL, + (char_u *)FALSE}, + {"smartcase", "scs", P_BOOL, (char_u *)&p_scs, + (char_u *)FALSE}, +#ifdef SMARTINDENT + {"smartindent", "si", P_BOOL|P_IND, (char_u *)PV_SI, + (char_u *)FALSE}, +#endif + {"smarttab", "sta", P_BOOL, (char_u *)&p_sta, + (char_u *)FALSE}, + {"sourceany", NULL, P_BOOL, (char_u *)NULL, + (char_u *)FALSE}, + {"splitbelow", "sb", P_BOOL, (char_u *)&p_sb, + (char_u *)FALSE}, + {"startofline", "sol", P_BOOL, (char_u *)&p_sol, + (char_u *)TRUE}, + {"suffixes", "su", P_STRING, (char_u *)&p_su, + (char_u *)".bak,~,.o,.h,.info,.swp"}, + {"swapsync", "sws", P_STRING, (char_u *)&p_sws, + (char_u *)"fsync"}, + {"tabstop", "ts", P_NUM|P_IND, (char_u *)PV_TS, + (char_u *)8L}, + {"taglength", "tl", P_NUM, (char_u *)&p_tl, + (char_u *)0L}, + {"tagrelative", "tr", P_BOOL, (char_u *)&p_tr, +#if defined(COMPATIBLE) + (char_u *)FALSE}, +#else + (char_u *)TRUE}, +#endif + {"tags", "tag", P_STRING|P_EXPAND, (char_u *)&p_tags, +#ifdef EMACS_TAGS + (char_u *)"./tags,./TAGS,tags,TAGS"}, +#else + (char_u *)"./tags,tags"}, +#endif + {"tagstack", "tgst", P_BOOL, (char_u *)NULL, + (char_u *)FALSE}, + {"term", NULL, P_STRING|P_EXPAND|P_NODEFAULT|P_NO_MKRC, + (char_u *)&term_strings[KS_NAME], + (char_u *)""}, + {"terse", NULL, P_BOOL, (char_u *)&p_terse, + (char_u *)FALSE}, + {"textauto", "ta", P_BOOL, (char_u *)&p_ta, +#if defined(COMPATIBLE) + (char_u *)FALSE}, +#else + (char_u *)TRUE}, +#endif + {"textmode", "tx", P_BOOL|P_IND, (char_u *)PV_TX, +#ifdef USE_CRNL + (char_u *)TRUE}, +#else + (char_u *)FALSE}, +#endif + {"textwidth", "tw", P_NUM|P_IND, (char_u *)PV_TW, + (char_u *)0L}, + {"tildeop", "top", P_BOOL, (char_u *)&p_to, + (char_u *)FALSE}, + {"timeout", "to", P_BOOL, (char_u *)&p_timeout, + (char_u *)TRUE}, + {"timeoutlen", "tm", P_NUM, (char_u *)&p_tm, + (char_u *)1000L}, + {"title", NULL, P_BOOL, (char_u *)&p_title, + (char_u *)FALSE}, + {"ttimeout", NULL, P_BOOL, (char_u *)&p_ttimeout, + (char_u *)FALSE}, + {"ttimeoutlen", "ttm", P_NUM, (char_u *)&p_ttm, + (char_u *)-1L}, + {"ttybuiltin", "tbi", P_BOOL, (char_u *)&p_tbi, + (char_u *)TRUE}, + {"ttyfast", "tf", P_BOOL|P_NO_MKRC, (char_u *)&p_tf, + (char_u *)FALSE}, + {"ttyscroll", "tsl", P_NUM, (char_u *)&p_ttyscroll, + (char_u *)999L}, + {"ttytype", "tty", P_STRING|P_EXPAND|P_NODEFAULT|P_NO_MKRC, + (char_u *)&term_strings[KS_NAME], + (char_u *)""}, + {"undolevels", "ul", P_NUM, (char_u *)&p_ul, +#ifdef COMPATIBLE + (char_u *)0L}, +#else +# if defined(UNIX) || defined(WIN32) || defined(OS2) + (char_u *)1000L}, +# else + (char_u *)100L}, +# endif +#endif + {"updatecount", "uc", P_NUM, (char_u *)&p_uc, +#ifdef COMPATIBLE + (char_u *)0L}, +#else + (char_u *)200L}, +#endif + {"updatetime", "ut", P_NUM, (char_u *)&p_ut, + (char_u *)4000L}, + {"viminfo", "vi", P_STRING, +#ifdef VIMINFO + (char_u *)&p_viminfo, +#else + (char_u *)NULL, +#endif /* VIMINFO */ + (char_u *)""}, + {"visualbell", "vb", P_BOOL, (char_u *)&p_vb, + (char_u *)FALSE}, + {"w300", NULL, P_NUM, (char_u *)NULL, + (char_u *)0L}, + {"w1200", NULL, P_NUM, (char_u *)NULL, + (char_u *)0L}, + {"w9600", NULL, P_NUM, (char_u *)NULL, + (char_u *)0L}, + {"warn", NULL, P_BOOL, (char_u *)&p_warn, + (char_u *)TRUE}, + {"weirdinvert", "wiv", P_BOOL, (char_u *)&p_wiv, + (char_u *)FALSE}, + {"whichwrap", "ww", P_STRING, (char_u *)&p_ww, +#ifdef COMPATIBLE + (char_u *)""}, +#else + (char_u *)"b,s"}, +#endif + {"wildchar", "wc", P_NUM, (char_u *)&p_wc, +#ifdef COMPATIBLE + (char_u *)(long)Ctrl('E')}, +#else + (char_u *)(long)TAB}, +#endif + {"window", "wi", P_NUM, (char_u *)NULL, + (char_u *)0L}, + {"winheight", "wh", P_NUM, (char_u *)&p_wh, + (char_u *)0L}, + {"wrap", NULL, P_BOOL|P_IND, (char_u *)PV_WRAP, + (char_u *)TRUE}, + {"wrapmargin", "wm", P_NUM|P_IND, (char_u *)PV_WM, + (char_u *)0L}, + {"wrapscan", "ws", P_BOOL, (char_u *)&p_ws, + (char_u *)TRUE}, + {"writeany", "wa", P_BOOL, (char_u *)&p_wa, + (char_u *)FALSE}, + {"writebackup", "wb", P_BOOL, (char_u *)&p_wb, +#if defined(COMPATIBLE) && !defined(WRITEBACKUP) + (char_u *)FALSE}, +#else + (char_u *)TRUE}, +#endif + {"writedelay", "wd", P_NUM, (char_u *)&p_wd, + (char_u *)0L}, + +/* terminal output codes */ + {"t_AL", NULL, P_STRING, (char_u *)&term_strings[KS_CAL], + (char_u *)""}, + {"t_al", NULL, P_STRING, (char_u *)&term_strings[KS_AL], + (char_u *)""}, + {"t_cd", NULL, P_STRING, (char_u *)&term_strings[KS_CD], + (char_u *)""}, + {"t_ce", NULL, P_STRING, (char_u *)&term_strings[KS_CE], + (char_u *)""}, + {"t_cl", NULL, P_STRING, (char_u *)&term_strings[KS_CL], + (char_u *)""}, + {"t_cm", NULL, P_STRING, (char_u *)&term_strings[KS_CM], + (char_u *)""}, + {"t_CS", NULL, P_STRING, (char_u *)&term_strings[KS_CSC], + (char_u *)""}, + {"t_cs", NULL, P_STRING, (char_u *)&term_strings[KS_CS], + (char_u *)""}, + {"t_da", NULL, P_STRING, (char_u *)&term_strings[KS_DA], + (char_u *)""}, + {"t_db", NULL, P_STRING, (char_u *)&term_strings[KS_DB], + (char_u *)""}, + {"t_DL", NULL, P_STRING, (char_u *)&term_strings[KS_CDL], + (char_u *)""}, + {"t_dl", NULL, P_STRING, (char_u *)&term_strings[KS_DL], + (char_u *)""}, + {"t_ke", NULL, P_STRING, (char_u *)&term_strings[KS_KE], + (char_u *)""}, + {"t_ks", NULL, P_STRING, (char_u *)&term_strings[KS_KS], + (char_u *)""}, + {"t_md", NULL, P_STRING, (char_u *)&term_strings[KS_MD], + (char_u *)""}, + {"t_me", NULL, P_STRING, (char_u *)&term_strings[KS_ME], + (char_u *)""}, + {"t_mr", NULL, P_STRING, (char_u *)&term_strings[KS_MR], + (char_u *)""}, + {"t_ms", NULL, P_STRING, (char_u *)&term_strings[KS_MS], + (char_u *)""}, + {"t_RI", NULL, P_STRING, (char_u *)&term_strings[KS_CRI], + (char_u *)""}, + {"t_se", NULL, P_STRING, (char_u *)&term_strings[KS_SE], + (char_u *)""}, + {"t_so", NULL, P_STRING, (char_u *)&term_strings[KS_SO], + (char_u *)""}, + {"t_sr", NULL, P_STRING, (char_u *)&term_strings[KS_SR], + (char_u *)""}, + {"t_te", NULL, P_STRING, (char_u *)&term_strings[KS_TE], + (char_u *)""}, + {"t_ti", NULL, P_STRING, (char_u *)&term_strings[KS_TI], + (char_u *)""}, + {"t_ue", NULL, P_STRING, (char_u *)&term_strings[KS_UE], + (char_u *)""}, + {"t_us", NULL, P_STRING, (char_u *)&term_strings[KS_US], + (char_u *)""}, + {"t_vb", NULL, P_STRING, (char_u *)&term_strings[KS_VB], + (char_u *)""}, + {"t_ve", NULL, P_STRING, (char_u *)&term_strings[KS_VE], + (char_u *)""}, + {"t_vi", NULL, P_STRING, (char_u *)&term_strings[KS_VI], + (char_u *)""}, + {"t_vs", NULL, P_STRING, (char_u *)&term_strings[KS_VS], + (char_u *)""}, + {"t_ZH", NULL, P_STRING, (char_u *)&term_strings[KS_CZH], + (char_u *)""}, + {"t_ZR", NULL, P_STRING, (char_u *)&term_strings[KS_CZR], + (char_u *)""}, + +/* terminal key codes are not here */ + + {NULL, NULL, 0, NULL, NULL} /* end marker */ +}; + +#define PARAM_COUNT (sizeof(options) / sizeof(struct option)) + +#ifdef AUTOCMD +/* + * structures for automatic commands + */ + +typedef struct AutoCmd +{ + char_u *cmd; /* The command to be executed */ + struct AutoCmd *next; /* Next AutoCmd in list */ +} AutoCmd; + +typedef struct AutoPat +{ + char_u *pat; /* pattern as typed */ + char_u *reg_pat; /* pattern converted to regexp */ + int allow_directories; /* Pattern may match whole path */ + AutoCmd *cmds; /* list of commands to do */ + struct AutoPat *next; /* next AutoPat in AutoPat list */ +} AutoPat; + +static struct event_name +{ + char *name; /* event name */ + int event; /* event number */ +} event_names[] = +{ + {"BufEnter", EVENT_BUFENTER}, + {"BufLeave", EVENT_BUFLEAVE}, + {"BufNewFile", EVENT_BUFNEWFILE}, + {"BufReadPost", EVENT_BUFREADPOST}, + {"BufReadPre", EVENT_BUFREADPRE}, + {"BufRead", EVENT_BUFREADPOST}, + {"BufWritePost", EVENT_BUFWRITEPOST}, + {"BufWritePre", EVENT_BUFWRITEPRE}, + {"BufWrite", EVENT_BUFWRITEPRE}, + {"FileAppendPost", EVENT_FILEAPPENDPOST}, + {"FileAppendPre", EVENT_FILEAPPENDPRE}, + {"FileReadPost", EVENT_FILEREADPOST}, + {"FileReadPre", EVENT_FILEREADPRE}, + {"FileWritePost", EVENT_FILEWRITEPOST}, + {"FileWritePre", EVENT_FILEWRITEPRE}, + {"FilterReadPost", EVENT_FILTERREADPOST}, + {"FilterReadPre", EVENT_FILTERREADPRE}, + {"FilterWritePost", EVENT_FILTERWRITEPOST}, + {"FilterWritePre", EVENT_FILTERWRITEPRE}, + {"VimLeave", EVENT_VIMLEAVE}, + {"WinEnter", EVENT_WINENTER}, + {"WinLeave", EVENT_WINLEAVE}, + {NULL, 0} +}; + +static AutoPat *first_autopat[NUM_EVENTS] = +{ + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL +}; +#endif + +static void set_option_default __ARGS((int, int)); +static void illegal_char __ARGS((char_u *, int)); +static char_u *option_expand __ARGS((int)); +static int findoption __ARGS((char_u *)); +static int find_key_option __ARGS((char_u *)); +static void showoptions __ARGS((int)); +static int option_changed __ARGS((struct option *)); +static void showoneopt __ARGS((struct option *)); +static int istermoption __ARGS((struct option *)); +static char_u *get_varp __ARGS((struct option *)); +static void option_value2string __ARGS((struct option *)); +#ifdef HAVE_LANGMAP +static void langmap_init __ARGS((void)); +static void langmap_set __ARGS((void)); +#endif +static void paste_option_changed __ARGS((void)); +static void p_compatible_set __ARGS((void)); +static void fill_breakat_flags __ARGS((void)); + +/* + * Initialize the options, first part. + * + * Called only once from main(), just after creating the first buffer. + */ + void +set_init_1() +{ + char_u *p; + int opt_idx; + long n; + +#ifdef HAVE_LANGMAP + langmap_init(); +#endif + +/* + * Find default value for 'shell' option. + */ + if ((p = vim_getenv((char_u *)"SHELL")) != NULL +#if defined(MSDOS) || defined(WIN32) || defined(OS2) +# ifdef __EMX__ + || (p = vim_getenv((char_u *)"EMXSHELL")) != NULL +# endif + || (p = vim_getenv((char_u *)"COMSPEC")) != NULL +# ifdef WIN32 + || (p = default_shell()) != NULL +# endif +#endif + ) + { + p = strsave(p); + if (p != NULL) /* we don't want a NULL */ + { + opt_idx = findoption((char_u *)"sh"); + options[opt_idx].def_val = p; + options[opt_idx].flags |= P_DEF_ALLOCED; + } + } + +/* + * Set default for 'helpfile' option. This cannot be done at compile time, + * because for Unix it is an external variable. + */ + opt_idx = findoption((char_u *)"hf"); +#if defined(HAVE_CONFIG_H) || defined(OS2) + options[opt_idx].def_val = help_fname; +#else + options[opt_idx].def_val = (char_u *)VIM_HLP; +#endif + +/* + * 'maxmemtot' and 'maxmem' may have to be adjusted for available memory + */ + opt_idx = findoption((char_u *)"maxmemtot"); + if (options[opt_idx].def_val == (char_u *)0L) + { + n = (mch_avail_mem(FALSE) >> 11); + options[opt_idx].def_val = (char_u *)n; + opt_idx = findoption((char_u *)"maxmem"); + if ((long)options[opt_idx].def_val > n || + (long)options[opt_idx].def_val == 0L) + options[opt_idx].def_val = (char_u *)n; + } + +/* + * set all the options (except the terminal options) to their default value + */ + for (opt_idx = 0; !istermoption(&options[opt_idx]); opt_idx++) + if (!(options[opt_idx].flags & P_NODEFAULT)) + set_option_default(opt_idx, FALSE); + + curbuf->b_p_initialized = TRUE; + check_buf_options(curbuf); + check_options(); + + /* + * initialize the table for 'iskeyword' et.al. + * Must be before option_expand(), because that one needs isidchar() + */ + init_chartab(); + + /* + * initialize the table for 'breakat'. + */ + fill_breakat_flags(); + + /* + * Expand environment variables and things like "~" for the defaults. + * If option_expand() returns non-NULL the variable is expanded. This can + * only happen for non-indirect options. + * Also set the default to the expanded value, so ":set" does not list + * them. Don't set the P_ALLOCED flag, because we don't want to free the + * default. + */ + for (opt_idx = 0; !istermoption(&options[opt_idx]); opt_idx++) + { + p = option_expand(opt_idx); + if (p != NULL) + { + *(char_u **)options[opt_idx].var = p; + options[opt_idx].def_val = p; + options[opt_idx].flags |= P_DEF_ALLOCED; + } + } +} + +/* + * Set an option to its default value. + */ + static void +set_option_default(opt_idx, dofree) + int opt_idx; + int dofree; /* TRUE when old value may be freed */ +{ + char_u *varp; /* pointer to variable for current option */ + + varp = get_varp(&(options[opt_idx])); + if (varp != NULL) /* nothing to do for hidden option */ + { + if (options[opt_idx].flags & P_STRING) + { + /* indirect options are always in allocated memory */ + if (options[opt_idx].flags & P_IND) + set_string_option(NULL, opt_idx, + options[opt_idx].def_val, dofree); + else + { + if (dofree && (options[opt_idx].flags & P_ALLOCED)) + free_string_option(*(char_u **)(varp)); + *(char_u **)varp = options[opt_idx].def_val; + options[opt_idx].flags &= ~P_ALLOCED; + } + } + else if (options[opt_idx].flags & P_NUM) + *(long *)varp = (long)options[opt_idx].def_val; + else /* P_BOOL */ + /* the cast to long is required for Manx C */ + *(int *)varp = (int)(long)options[opt_idx].def_val; + } +} + +/* + * Initialize the options, part two: After getting Rows and Columns + */ + void +set_init_2() +{ +/* + * 'scroll' defaults to half the window height. Note that this default is + * wrong when the window height changes. + */ + options[findoption((char_u *)"scroll")].def_val = (char_u *)(Rows >> 1); + + comp_col(); +} + +/* + * Initialize the options, part three: After reading the .vimrc + */ + void +set_init_3() +{ + int idx1; + +#if defined(UNIX) || defined(OS2) +/* + * Set 'shellpipe' and 'shellredir', depending on the 'shell' option. + * This is done after other initializations, where 'shell' might have been + * set, but only if they have not been set before. + */ + char_u *p; + int idx2; + int do_sp; + int do_srr; + + idx1 = findoption((char_u *)"sp"); + idx2 = findoption((char_u *)"srr"); + do_sp = !(options[idx1].flags & P_WAS_SET); + do_srr = !(options[idx2].flags & P_WAS_SET); + + /* + * Default for p_sp is "| tee", for p_srr is ">". + * For known shells it is changed here to include stderr. + */ + p = gettail(p_sh); + if ( fnamecmp(p, "csh") == 0 || + fnamecmp(p, "tcsh") == 0 +# ifdef OS2 /* also check with .exe extension */ + || fnamecmp(p, "csh.exe") == 0 + || fnamecmp(p, "tcsh.exe") == 0 +# endif + ) + { + if (do_sp) + { + p_sp = (char_u *)"|& tee"; + options[idx1].def_val = p_sp; + } + if (do_srr) + { + p_srr = (char_u *)">&"; + options[idx2].def_val = p_srr; + } + } + else +# ifndef OS2 /* Always use bourne shell style redirection if we reach this */ + if ( STRCMP(p, "sh") == 0 || + STRCMP(p, "ksh") == 0 || + STRCMP(p, "zsh") == 0 || + STRCMP(p, "bash") == 0) +# endif + { + if (do_sp) + { + p_sp = (char_u *)"2>&1| tee"; + options[idx1].def_val = p_sp; + } + if (do_srr) + { + p_srr = (char_u *)">%s 2>&1"; + options[idx2].def_val = p_srr; + } + } +#endif + +/* + * 'title' and 'icon' only default to true if they have not been set or reset + * in .vimrc and we can read the old value. + * When 'title' and 'icon' have been reset in .vimrc, we won't even check if + * they can be reset. this reduces startup time when using X on a remote + * machine. + */ + idx1 = findoption((char_u *)"title"); + if (!(options[idx1].flags & P_WAS_SET) && mch_can_restore_title()) + { + options[idx1].def_val = (char_u *)TRUE; + p_title = TRUE; + } + idx1 = findoption((char_u *)"icon"); + if (!(options[idx1].flags & P_WAS_SET) && mch_can_restore_icon()) + { + options[idx1].def_val = (char_u *)TRUE; + p_icon = TRUE; + } +} + +/* + * Parse 'arg' for option settings. + * + * 'arg' may be IObuff, but only when no errors can be present and option + * does not need to be expanded with option_expand(). + * + * return FAIL if errors are detected, OK otherwise + */ + int +do_set(arg) + char_u *arg; /* option string (may be written to!) */ +{ + register int opt_idx; + char_u *errmsg; + char_u errbuf[80]; + char_u *startarg; + int prefix; /* 1: nothing, 0: "no", 2: "inv" in front of name */ + int nextchar; /* next non-white char after option name */ + int afterchar; /* character just after option name */ + int len; + int i; + int key; + int flags; /* flags for current option */ + char_u *varp = NULL; /* pointer to variable for current option */ + char_u *oldval; /* previous value if *varp */ + int errcnt = 0; /* number of errornous entries */ + long oldRows = Rows; /* remember old Rows */ + long oldColumns = Columns; /* remember old Columns */ + int oldbin; /* remember old bin option */ + long oldch = p_ch; /* remember old command line height */ + int oldea = p_ea; /* remember old 'equalalways' */ + long olduc = p_uc; /* remember old 'updatecount' */ + int did_show = FALSE; /* already showed one value */ + WIN *wp; + + if (*arg == NUL) + { + showoptions(0); + return OK; + } + + while (*arg) /* loop to process all options */ + { + errmsg = NULL; + startarg = arg; /* remember for error message */ + + if (STRNCMP(arg, "all", (size_t)3) == 0) + { + showoptions(1); + arg += 3; + } + else if (STRNCMP(arg, "termcap", (size_t)7) == 0) + { + showoptions(2); + show_termcodes(); + arg += 7; + } + else + { + prefix = 1; + if (STRNCMP(arg, "no", (size_t)2) == 0) + { + prefix = 0; + arg += 2; + } + else if (STRNCMP(arg, "inv", (size_t)3) == 0) + { + prefix = 2; + arg += 3; + } + /* find end of name */ + if (*arg == '<') + { + opt_idx = -1; + /* check for <t_>;> */ + if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4]) + len = 5; + else + { + len = 1; + while (arg[len] != NUL && arg[len] != '>') + ++len; + } + if (arg[len] != '>') + { + errmsg = e_invarg; + goto skip; + } + nextchar = arg[len]; + arg[len] = NUL; /* put NUL after name */ + if (arg[1] == 't' && arg[2] == '_') /* could be term code */ + opt_idx = findoption(arg + 1); + key = 0; + if (opt_idx == -1) + key = find_key_option(arg + 1); + arg[len++] = nextchar; /* restore nextchar */ + nextchar = arg[len]; + } + else + { + len = 0; + /* + * The two characters after "t_" may not be alphanumeric. + */ + if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) + { + len = 4; + } + else + { + while (isalnum(arg[len]) || arg[len] == '_') + ++len; + } + nextchar = arg[len]; + arg[len] = NUL; /* put NUL after name */ + opt_idx = findoption(arg); + key = 0; + if (opt_idx == -1) + key = find_key_option(arg); + arg[len] = nextchar; /* restore nextchar */ + } + + if (opt_idx == -1 && key == 0) /* found a mismatch: skip */ + { + errmsg = (char_u *)"Unknown option"; + goto skip; + } + + if (opt_idx >= 0) + { + if (options[opt_idx].var == NULL) /* hidden option: skip */ + goto skip; + + flags = options[opt_idx].flags; + varp = get_varp(&(options[opt_idx])); + } + else + flags = P_STRING; + + /* remember character after option name */ + afterchar = nextchar; + + /* skip white space, allow ":set ai ?" */ + while (vim_iswhite(nextchar)) + nextchar = arg[++len]; + + if (vim_strchr((char_u *)"?=:!&", nextchar) != NULL) + { + arg += len; + len = 0; + } + + /* + * allow '=' and ':' as MSDOS command.com allows only one + * '=' character per "set" command line. grrr. (jw) + */ + if (nextchar == '?' || (prefix == 1 && vim_strchr((char_u *)"=:&", + nextchar) == NULL && !(flags & P_BOOL))) + { /* print value */ + if (did_show) + msg_outchar('\n'); /* cursor below last one */ + else + { + gotocmdline(TRUE); /* cursor at status line */ + did_show = TRUE; /* remember that we did a line */ + } + if (opt_idx >= 0) + showoneopt(&options[opt_idx]); + else + { + char_u name[2]; + char_u *p; + + name[0] = KEY2TERMCAP0(key); + name[1] = KEY2TERMCAP1(key); + p = find_termcode(name); + if (p == NULL) + { + errmsg = (char_u *)"Unknown option"; + goto skip; + } + else + (void)show_one_termcode(name, p, TRUE); + } + if (nextchar != '?' && nextchar != NUL && + !vim_iswhite(afterchar)) + errmsg = e_trailing; + } + else + { + if (flags & P_BOOL) /* boolean */ + { + if (nextchar == '=' || nextchar == ':') + { + errmsg = e_invarg; + goto skip; + } + + /* + * in secure mode, setting of the secure option is not + * allowed + */ + if (secure && (int *)varp == &p_secure) + { + errmsg = (char_u *)"not allowed here"; + goto skip; + } + + oldbin = curbuf->b_p_bin; /* remember old bin option */ + + /* + * ":set opt!" or ":set invopt": invert + * ":set opt&": reset to default value + * ":set opt" or ":set noopt": set or reset + */ + if (prefix == 2 || nextchar == '!') + *(int *)(varp) ^= 1; + else if (nextchar == '&') + /* the cast to long is required for Manx C */ + *(int *)(varp) = (int)(long)options[opt_idx].def_val; + else + *(int *)(varp) = prefix; + + /* handle the setting of the compatible option */ + if ((int *)varp == &p_cp && p_cp) + { + p_compatible_set(); + } + /* when 'readonly' is reset, also reset readonlymode */ + else if ((int *)varp == &curbuf->b_p_ro && !curbuf->b_p_ro) + readonlymode = FALSE; + + /* when 'bin' is set also set some other options */ + else if ((int *)varp == &curbuf->b_p_bin) + { + set_options_bin(oldbin, curbuf->b_p_bin); + } + /* when 'terse' is set change 'shortmess' */ + else if ((int *)varp == &p_terse) + { + char_u *p; + + p = vim_strchr(p_shm, SHM_SEARCH); + + /* insert 's' in p_shm */ + if (p_terse && p == NULL) + { + STRCPY(IObuff, p_shm); + STRCAT(IObuff, "s"); + set_string_option((char_u *)"shm", -1, + IObuff, TRUE); + } + /* remove 's' from p_shm */ + else if (!p_terse && p != NULL) + vim_memmove(p, p + 1, STRLEN(p)); + } + /* when 'paste' is set or reset also change other options */ + else if ((int *)varp == &p_paste) + { + paste_option_changed(); + } + /* + * When 'lisp' option changes include/exclude '-' in + * keyword characters. + */ + else if (varp == (char_u *)&(curbuf->b_p_lisp)) + init_chartab(); /* ignore errors */ + + else if (!starting && ((int *)varp == &p_title || + (int *)varp == &p_icon)) + { + /* + * When setting 'title' or 'icon' on, call maketitle() + * to create and display it. + * When resetting 'title' or 'icon', call maketitle() + * to clear it and call mch_restore_title() to get the + * old value back. + */ + maketitle(); + if (!*(int *)varp) + mch_restore_title((int *)varp == &p_title ? 1 : 2); + } + } + else /* numeric or string */ + { + if (vim_strchr((char_u *)"=:&", nextchar) == NULL || + prefix != 1) + { + errmsg = e_invarg; + goto skip; + } + if (flags & P_NUM) /* numeric */ + { + /* + * Different ways to set a number option: + * & set to default value + * <xx> accept special key codes for 'wildchar' + * c accept any non-digit for 'wildchar' + * 0-9 set number + * other error + */ + arg += len + 1; + if (nextchar == '&') + *(long *)(varp) = (long)options[opt_idx].def_val; + else if ((long *)varp == &p_wc && + (*arg == '<' || *arg == '^' || + ((!arg[1] || vim_iswhite(arg[1])) && + !isdigit(*arg)))) + { + if (*arg == '<') + { + i = get_special_key_code(arg + 1); + if (i == 0) + i = find_key_option(arg + 1); + } + else if (*arg == '^') + i = arg[1] ^ 0x40; + else + i = *arg; + if (i == 0) + { + errmsg = e_invarg; + goto skip; + } + p_wc = i; + } + /* allow negative numbers (for 'undolevels') */ + else if (*arg == '-' || isdigit(*arg)) + { + i = 0; + if (*arg == '-') + i = 1; +#ifdef HAVE_STRTOL + *(long *)(varp) = strtol((char *)arg, NULL, 0); + if (arg[i] == '0' && TO_UPPER(arg[i + 1]) == 'X') + i += 2; +#else + *(long *)(varp) = atol((char *)arg); +#endif + while (isdigit(arg[i])) + ++i; + if (arg[i] != NUL && !vim_iswhite(arg[i])) + { + errmsg = e_invarg; + goto skip; + } + } + else + { + errmsg = (char_u *)"Number required after ="; + goto skip; + } + + /* + * Number options that need some action when changed + */ + if ((long *)varp == &p_wh || (long *)varp == &p_hh) + { + if (p_wh < 0) + { + errmsg = e_positive; + p_wh = 0; + } + if (p_hh < 0) + { + errmsg = e_positive; + p_hh = 0; + } + /* Change window height NOW */ + if (p_wh && lastwin != firstwin) + { + win_equal(curwin, FALSE); + must_redraw = CLEAR; + } + } + /* (re)set last window status line */ + if ((long *)varp == &p_ls) + last_status(); + } + else if (opt_idx >= 0) /* string */ + { + char_u *save_arg = NULL; + char_u *s, *p; + int new_value_alloced; /* new string option + was allocated */ + + /* The old value is kept until we are sure that the new + * value is valid. set_option_default() is therefore + * called with FALSE + */ + oldval = *(char_u **)(varp); + if (nextchar == '&') /* set to default val */ + { + set_option_default(opt_idx, FALSE); + new_value_alloced = + (options[opt_idx].flags & P_ALLOCED); + } + else + { + arg += len + 1; /* jump to after the '=' or ':' */ + + /* + * Convert 'whichwrap' number to string, for + * backwards compatibility with Vim 3.0. + * Misuse errbuf[] for the resulting string. + */ + if (varp == (char_u *)&p_ww && isdigit(*arg)) + { + *errbuf = NUL; + i = getdigits(&arg); + if (i & 1) + STRCAT(errbuf, "b,"); + if (i & 2) + STRCAT(errbuf, "s,"); + if (i & 4) + STRCAT(errbuf, "h,l,"); + if (i & 8) + STRCAT(errbuf, "<,>,"); + if (i & 16) + STRCAT(errbuf, "[,],"); + if (*errbuf != NUL) /* remove trailing , */ + errbuf[STRLEN(errbuf) - 1] = NUL; + save_arg = arg; + arg = errbuf; + } + /* + * Remove '>' before 'dir' and 'bdir', for + * backwards compatibility with version 3.0 + */ + else if (*arg == '>' && (varp == (char_u *)&p_dir || + varp == (char_u *)&p_bdir)) + { + ++arg; + } + + /* + * Copy the new string into allocated memory. + * Can't use set_string_option(), because we need + * to remove the backslashes. + */ + /* get a bit too much */ + s = alloc((unsigned)(STRLEN(arg) + 1)); + if (s == NULL) /* out of memory, don't change */ + break; + *(char_u **)(varp) = s; + + /* + * Copy the string, skip over escaped chars. + * For MS-DOS and WIN32 backslashes before normal + * file name characters are not removed. + */ + while (*arg && !vim_iswhite(*arg)) + { + if (*arg == '\\' && arg[1] != NUL +#ifdef BACKSLASH_IN_FILENAME + && !((flags & P_EXPAND) + && isfilechar(arg[1]) + && arg[1] != '\\') +#endif + ) + ++arg; + *s++ = *arg++; + } + *s = NUL; + if (save_arg != NULL) /* number for 'whichwrap' */ + arg = save_arg; + new_value_alloced = TRUE; + } + + /* expand environment variables and ~ */ + s = option_expand(opt_idx); + if (s != NULL) + { + if (new_value_alloced) + vim_free(*(char_u **)(varp)); + *(char_u **)(varp) = s; + new_value_alloced = TRUE; + } + + /* + * options that need some action + * to perform when changed (jw) + */ + if (varp == (char_u *)&term_strings[KS_NAME]) + { + if (term_strings[KS_NAME][0] == NUL) + errmsg = (char_u *)"Cannot set 'term' to empty string"; +#ifdef USE_GUI + if (gui.in_use) + errmsg = (char_u *)"Cannot change term in GUI"; +#endif + else if (set_termname(term_strings[KS_NAME]) == + FAIL) + errmsg = (char_u *)"Not found in termcap"; + else + { + /* Screen colors may have changed. */ + outstr(T_ME); + updateScreen(CLEAR); + } + } + + else if ((varp == (char_u *)&p_bex || + varp == (char_u *)&p_pm)) + { + if (STRCMP(*p_bex == '.' ? p_bex + 1 : p_bex, + *p_pm == '.' ? p_pm + 1 : p_pm) == 0) + errmsg = (char_u *)"'backupext' and 'patchmode' are equal"; + } + /* + * 'isident', 'iskeyword', 'isprint or 'isfname' + * option: refill chartab[] + * If the new option is invalid, use old value. + * 'lisp' option: refill chartab[] for '-' char + */ + else if (varp == (char_u *)&p_isi || + varp == (char_u *)&(curbuf->b_p_isk) || + varp == (char_u *)&p_isp || + varp == (char_u *)&p_isf) + { + if (init_chartab() == FAIL) + errmsg = e_invarg; /* error in value */ + } + else if (varp == (char_u *)&p_hl) + { + /* Check 'highlight' */ + for (s = p_hl; *s; ) + { + if (vim_strchr((char_u *)"8dehmMnrstvw", + (i = s[0])) == NULL || + vim_strchr((char_u *)"bsnuir", + (i = s[1])) == NULL || + ((i = s[2]) != NUL && i != ',')) + { + illegal_char(errbuf, i); + errmsg = errbuf; + break; + } + if (s[2] == NUL) + break; + s = skipwhite(s + 3); + } + } + else if (varp == (char_u *)&(curbuf->b_p_com)) + { + for (s = curbuf->b_p_com; *s; ) + { + while (*s && *s != ':') + { + if (vim_strchr((char_u *)COM_ALL, *s) == NULL) + { + errmsg = (char_u *)"Illegal flag"; + break; + } + ++s; + } + if (*s++ == NUL) + errmsg = (char_u *)"Missing colon"; + else if (*s == ',') + errmsg = (char_u *)"Zero length string"; + if (errmsg != NULL) + break; + while (*s && *s != ',') + { + if (*s == '\\' && s[1] != NUL) + ++s; + ++s; + } + s = skip_to_option_part(s); + } + } +#ifdef VIMINFO + else if (varp == (char_u *)&(p_viminfo)) + { + for (s = p_viminfo; *s;) + { + /* Check it's a valid character */ + if (vim_strchr((char_u *)"\"'fr:/", *s) == NULL) + { + illegal_char(errbuf, *s); + errmsg = errbuf; + break; + } + if (*s == 'r') + { + while (*++s && *s != ',') + ; + } + else + { + while (isdigit(*++s)) + ; + + /* Must be a number after the character */ + if (!isdigit(*(s - 1))) + { + sprintf((char *)errbuf, + "Missing number after <%s>", + transchar(*(s - 1))); + errmsg = errbuf; + break; + } + } + s = skip_to_option_part(s); + } + if (*p_viminfo && errmsg == NULL + && get_viminfo_parameter('\'') < 0) + errmsg = (char_u *)"Must specify a ' value"; + } +#endif /* VIMINFO */ + else if (istermoption(&options[opt_idx]) && full_screen) + { + ttest(FALSE); + if (varp == (char_u *)&term_strings[KS_ME]) + { + outstr(T_ME); + updateScreen(CLEAR); + } + } + else if (varp == (char_u *)&p_sbr) + { + for (s = p_sbr; *s; ++s) + if (charsize(*s) != 1) + errmsg = (char_u *)"contains unprintable character"; + } +#ifdef USE_GUI + else if (varp == (char_u *)&p_guifont) + { + gui_init_font(); + } +#endif /* USE_GUI */ +#ifdef HAVE_LANGMAP + else if (varp == (char_u *)&p_langmap) + langmap_set(); +#endif + else if (varp == (char_u *)&p_breakat) + fill_breakat_flags(); + else + { + /* + * Check options that are a list of flags. + */ + p = NULL; + if (varp == (char_u *)&p_ww) + p = (char_u *)WW_ALL; + if (varp == (char_u *)&p_shm) + p = (char_u *)SHM_ALL; + else if (varp == (char_u *)&(p_cpo)) + p = (char_u *)CPO_ALL; + else if (varp == (char_u *)&(curbuf->b_p_fo)) + p = (char_u *)FO_ALL; + else if (varp == (char_u *)&p_mouse) + { +#ifdef USE_MOUSE + p = (char_u *)MOUSE_ALL; +#else + if (*p_mouse != NUL) + errmsg = (char_u *)"No mouse support"; +#endif + } +#ifdef USE_GUI + else if (varp == (char_u *)&p_guioptions) + p = (char_u *)GO_ALL; +#endif /* USE_GUI */ + if (p != NULL) + { + for (s = *(char_u **)(varp); *s; ++s) + if (vim_strchr(p, *s) == NULL) + { + illegal_char(errbuf, *s); + errmsg = errbuf; + break; + } + } + } + if (errmsg != NULL) /* error detected */ + { + if (new_value_alloced) + vim_free(*(char_u **)(varp)); + *(char_u **)(varp) = oldval; + (void)init_chartab(); /* back to the old value */ + goto skip; + } + +#ifdef USE_GUI + if (varp == (char_u *)&p_guioptions) + gui_init_which_components(oldval); +#endif /* USE_GUI */ + + /* + * Free string options that are in allocated memory. + */ + if (flags & P_ALLOCED) + free_string_option(oldval); + if (new_value_alloced) + options[opt_idx].flags |= P_ALLOCED; + } + else /* key code option */ + { + char_u name[2]; + char_u *p; + + name[0] = KEY2TERMCAP0(key); + name[1] = KEY2TERMCAP1(key); + if (nextchar == '&') + { + if (add_termcap_entry(name, TRUE) == FAIL) + errmsg = (char_u *)"Not found in termcap"; + } + else + { + arg += len + 1; /* jump to after the '=' or ':' */ + for(p = arg; *p && !vim_iswhite(*p); ++p) + { + if (*p == '\\' && *(p + 1)) + ++p; + } + nextchar = *p; + *p = NUL; + add_termcode(name, arg); + *p = nextchar; + } + if (full_screen) + ttest(FALSE); + } + } + if (opt_idx >= 0) + options[opt_idx].flags |= P_WAS_SET; + } + +skip: + /* + * Check the bounds for numeric options here + */ + if (Rows < min_rows() && full_screen) + { + sprintf((char *)errbuf, "Need at least %d lines", min_rows()); + errmsg = errbuf; + Rows = min_rows(); + } + if (Columns < MIN_COLUMNS && full_screen) + { + sprintf((char *)errbuf, "Need at least %d columns", + MIN_COLUMNS); + errmsg = errbuf; + Columns = MIN_COLUMNS; + } + /* + * If the screenheight has been changed, assume it is the physical + * screenheight. + */ + if ((oldRows != Rows || oldColumns != Columns) && full_screen) + { + mch_set_winsize(); /* try to change the window size */ + check_winsize(); /* in case 'columns' changed */ +#ifdef MSDOS + set_window(); /* active window may have changed */ +#endif + } + + if (curbuf->b_p_ts <= 0) + { + errmsg = e_positive; + curbuf->b_p_ts = 8; + } + if (curbuf->b_p_tw < 0) + { + errmsg = e_positive; + curbuf->b_p_tw = 0; + } + if (p_tm < 0) + { + errmsg = e_positive; + p_tm = 0; + } + if ((curwin->w_p_scroll <= 0 || + curwin->w_p_scroll > curwin->w_height) && full_screen) + { + if (curwin->w_p_scroll != 0) + errmsg = e_scroll; + win_comp_scroll(curwin); + } + if (p_report < 0) + { + errmsg = e_positive; + p_report = 1; + } + if ((p_sj < 0 || p_sj >= Rows) && full_screen) + { + if (Rows != oldRows) /* Rows changed, just adjust p_sj */ + p_sj = Rows / 2; + else + { + errmsg = e_scroll; + p_sj = 1; + } + } + if (p_so < 0 && full_screen) + { + errmsg = e_scroll; + p_so = 0; + } + if (p_uc < 0) + { + errmsg = e_positive; + p_uc = 100; + } + if (p_ch < 1) + { + errmsg = e_positive; + p_ch = 1; + } + if (p_ut < 0) + { + errmsg = e_positive; + p_ut = 2000; + } + if (p_ss < 0) + { + errmsg = e_positive; + p_ss = 0; + } + + /* + * Advance to next argument. + * - skip until a blank found, taking care of backslashes + * - skip blanks + */ + while (*arg != NUL && !vim_iswhite(*arg)) + if (*arg++ == '\\' && *arg != NUL) + ++arg; + } + arg = skipwhite(arg); + + if (errmsg) + { + ++no_wait_return; /* wait_return done below */ +#ifdef SLEEP_IN_EMSG + ++dont_sleep; /* don't wait in emsg() */ +#endif + emsg(errmsg); /* show error highlighted */ +#ifdef SLEEP_IN_EMSG + --dont_sleep; +#endif + MSG_OUTSTR(": "); + /* show argument normal */ + while (startarg < arg) + msg_outstr(transchar(*startarg++)); + msg_end(); /* check for scrolling */ + --no_wait_return; + + ++errcnt; /* count number of errors */ + did_show = TRUE; /* error message counts as show */ + if (sourcing_name != NULL) + break; + } + } + + /* + * when 'updatecount' changes from zero to non-zero, open swap files + */ + if (p_uc && !olduc) + ml_open_files(); + + if (p_ch != oldch) /* p_ch changed value */ + command_height(); +#ifdef USE_MOUSE + if (*p_mouse == NUL) + mch_setmouse(FALSE); /* switch mouse off */ + else + setmouse(); /* in case 'mouse' changed */ +#endif + comp_col(); /* in case 'ruler' or 'showcmd' changed */ + curwin->w_set_curswant = TRUE; /* in case 'list' changed */ + + /* + * Update the screen in case we changed something like "tabstop" or + * "lines" or "list" that will change its appearance. + * Also update the cursor position, in case 'wrap' is changed. + */ + for (wp = firstwin; wp; wp = wp->w_next) + wp->w_redr_status = TRUE; /* mark all status lines dirty */ + if (p_ea && !oldea) + win_equal(curwin, FALSE); + updateScreen(CURSUPD); + return (errcnt == 0 ? OK : FAIL); +} + + static void +illegal_char(errbuf, c) + char_u *errbuf; + int c; +{ + sprintf((char *)errbuf, "Illegal character <%s>", (char *)transchar(c)); +} + +/* + * set_options_bin - called when 'bin' changes value. + */ + void +set_options_bin(oldval, newval) + int oldval; + int newval; +{ + /* + * The option values that are changed when 'bin' changes are + * copied when 'bin is set and restored when 'bin' is reset. + */ + if (newval) + { + if (!oldval) /* switched on */ + { + curbuf->b_p_tw_nobin = curbuf->b_p_tw; + curbuf->b_p_wm_nobin = curbuf->b_p_wm; + curbuf->b_p_tx_nobin = curbuf->b_p_tx; + curbuf->b_p_ta_nobin = p_ta; + curbuf->b_p_ml_nobin = curbuf->b_p_ml; + curbuf->b_p_et_nobin = curbuf->b_p_et; + } + + curbuf->b_p_tw = 0; /* no automatic line wrap */ + curbuf->b_p_wm = 0; /* no automatic line wrap */ + curbuf->b_p_tx = 0; /* no text mode */ + p_ta = 0; /* no text auto */ + curbuf->b_p_ml = 0; /* no modelines */ + curbuf->b_p_et = 0; /* no expandtab */ + } + else if (oldval) /* switched off */ + { + curbuf->b_p_tw = curbuf->b_p_tw_nobin; + curbuf->b_p_wm = curbuf->b_p_wm_nobin; + curbuf->b_p_tx = curbuf->b_p_tx_nobin; + p_ta = curbuf->b_p_ta_nobin; + curbuf->b_p_ml = curbuf->b_p_ml_nobin; + curbuf->b_p_et = curbuf->b_p_et_nobin; + } +} + +#ifdef VIMINFO +/* + * Find the parameter represented by the given character (eg ', :, ", or /), + * and return its associated value in the 'viminfo' string. If the parameter + * is not specified in the string, return -1. + */ + int +get_viminfo_parameter(type) + int type; +{ + char_u *p; + + p = vim_strchr(p_viminfo, type); + if (p != NULL && isdigit(*++p)) + return (int)atol((char *)p); + return -1; +} +#endif + +/* + * Expand environment variables for some string options. + * These string options cannot be indirect! + * Return pointer to allocated memory, or NULL when not expanded. + */ + static char_u * +option_expand(opt_idx) + int opt_idx; +{ + char_u *p; + + /* if option doesn't need expansion or is hidden: nothing to do */ + if (!(options[opt_idx].flags & P_EXPAND) || options[opt_idx].var == NULL) + return NULL; + + p = *(char_u **)(options[opt_idx].var); + + /* + * Expanding this with NameBuff, expand_env() must not be passed IObuff. + */ + expand_env(p, NameBuff, MAXPATHL); + if (STRCMP(NameBuff, p) == 0) /* they are the same */ + return NULL; + + return strsave(NameBuff); +} + +/* + * Check for string options that are NULL (normally only termcap options). + */ + void +check_options() +{ + int opt_idx; + char_u **p; + + for (opt_idx = 0; options[opt_idx].fullname != NULL; opt_idx++) + if ((options[opt_idx].flags & P_STRING) && options[opt_idx].var != NULL) + { + p = (char_u **)get_varp(&(options[opt_idx])); + if (*p == NULL) + *p = empty_option; + } +} + +/* + * Check string options in a buffer for NULL value. + */ + void +check_buf_options(buf) + BUF *buf; +{ + if (buf->b_p_fo == NULL) + buf->b_p_fo = empty_option; + if (buf->b_p_isk == NULL) + buf->b_p_isk = empty_option; + if (buf->b_p_com == NULL) + buf->b_p_com = empty_option; +#ifdef CINDENT + if (buf->b_p_cink == NULL) + buf->b_p_cink = empty_option; + if (buf->b_p_cino == NULL) + buf->b_p_cino = empty_option; +#endif +#if defined(SMARTINDENT) || defined(CINDENT) + if (buf->b_p_cinw == NULL) + buf->b_p_cinw = empty_option; +#endif +} + +/* + * Free the string allocated for an option. + * Checks for the string being empty_option. This may happen if we're out of + * memory, strsave() returned NULL, which was replaced by empty_option by + * check_options(). + * Does NOT check for P_ALLOCED flag! + */ + void +free_string_option(p) + char_u *p; +{ + if (p != empty_option) + vim_free(p); +} + +/* + * Set a string option to a new value. + * The string is copied into allocated memory. + * If 'dofree' is set, the old value may be freed. + * if (opt_idx == -1) name is used, otherwise opt_idx is used. + */ + void +set_string_option(name, opt_idx, val, dofree) + char_u *name; + int opt_idx; + char_u *val; + int dofree; +{ + char_u *s; + char_u **varp; + + if (opt_idx == -1) /* use name */ + { + opt_idx = findoption(name); + if (opt_idx == -1) /* not found (should not happen) */ + return; + } + + if (options[opt_idx].var == NULL) /* don't set hidden option */ + return; + + s = strsave(val); + if (s != NULL) + { + varp = (char_u **)get_varp(&(options[opt_idx])); + if (dofree && (options[opt_idx].flags & P_ALLOCED)) + free_string_option(*varp); + *varp = s; + /* if 'term' option set for the first time: set default value */ + if (varp == &(term_strings[KS_NAME]) && + *(options[opt_idx].def_val) == NUL) + { + options[opt_idx].def_val = s; + options[opt_idx].flags |= P_DEF_ALLOCED; + } + else + options[opt_idx].flags |= P_ALLOCED; + } +} + +/* + * find index for option 'arg' + * return -1 if not found + */ + static int +findoption(arg) + char_u *arg; +{ + int opt_idx; + char *s; + + for (opt_idx = 0; (s = options[opt_idx].fullname) != NULL; opt_idx++) + { + if (STRCMP(arg, s) == 0) /* match full name */ + break; + } + if (s == NULL) + { + for (opt_idx = 0; options[opt_idx].fullname != NULL; opt_idx++) + { + s = options[opt_idx].shortname; + if (s != NULL && STRCMP(arg, s) == 0) /* match short name */ + break; + s = NULL; + } + } + if (s == NULL) + opt_idx = -1; + return opt_idx; +} + + char_u * +get_highlight_default() +{ + int i; + + i = findoption((char_u *)"hl"); + if (i >= 0) + return options[i].def_val; + return (char_u *)NULL; +} + + static int +find_key_option(arg) + char_u *arg; +{ + int key; + int c; + + /* don't use get_special_key_code() for t_xx, we don't want it to call + * add_termcap_entry() */ + if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) + key = TERMCAP2KEY(arg[2], arg[3]); + + /* <S-Tab> is a special case, because TAB isn't a special key */ + else if (vim_strnicmp(arg, (char_u *)"S-Tab", (size_t)5) == 0) + key = K_S_TAB; + else + { + /* Currently only the shift modifier is recognized */ + mod_mask = 0; + if (TO_LOWER(arg[0]) == 's' && arg[1] == '-') + { + mod_mask = MOD_MASK_SHIFT; + arg += 2; + } + c = get_special_key_code(arg); + key = check_shifted_spec_key(c); + if (mod_mask && c == key) /* key can't be shifted */ + key = 0; + } + return key; +} + +/* + * if 'all' == 0: show changed options + * if 'all' == 1: show all normal options + * if 'all' == 2: show all terminal options + */ + static void +showoptions(all) + int all; +{ + struct option *p; + int col; + int isterm; + char_u *varp; + struct option **items; + int item_count; + int run; + int row, rows; + int cols; + int i; + int len; + +#define INC 20 +#define GAP 3 + + items = (struct option **)alloc((unsigned)(sizeof(struct option *) * + PARAM_COUNT)); + if (items == NULL) + return; + + set_highlight('t'); /* Highlight title */ + start_highlight(); + if (all == 2) + MSG_OUTSTR("\n--- Terminal codes ---"); + else + MSG_OUTSTR("\n--- Options ---"); + stop_highlight(); + + /* + * do the loop two times: + * 1. display the short items + * 2. display the long items (only strings and numbers) + */ + for (run = 1; run <= 2 && !got_int; ++run) + { + /* + * collect the items in items[] + */ + item_count = 0; + for (p = &options[0]; p->fullname != NULL; p++) + { + isterm = istermoption(p); + varp = get_varp(p); + if (varp != NULL && ( + (all == 2 && isterm) || + (all == 1 && !isterm) || + (all == 0 && option_changed(p)))) + { + if (p->flags & P_BOOL) + len = 1; /* a toggle option fits always */ + else + { + option_value2string(p); + len = STRLEN(p->fullname) + strsize(NameBuff) + 1; + } + if ((len <= INC - GAP && run == 1) || + (len > INC - GAP && run == 2)) + items[item_count++] = p; + } + } + + /* + * display the items + */ + if (run == 1) + { + cols = (Columns + GAP - 3) / INC; + if (cols == 0) + cols = 1; + rows = (item_count + cols - 1) / cols; + } + else /* run == 2 */ + rows = item_count; + for (row = 0; row < rows && !got_int; ++row) + { + msg_outchar('\n'); /* go to next line */ + if (got_int) /* 'q' typed in more */ + break; + col = 0; + for (i = row; i < item_count; i += rows) + { + msg_pos(-1, col); /* make columns */ + showoneopt(items[i]); + col += INC; + } + flushbuf(); + mch_breakcheck(); + } + } + vim_free(items); +} + +/* + * Return TRUE if option is different from the default value + */ + static int +option_changed(p) + struct option *p; +{ + char_u *varp; + + varp = get_varp(p); + if (varp == NULL) + return FALSE; /* hidden option is never changed */ + + if (p->flags & P_NUM) + return (*(long *)varp != (long)p->def_val); + if (p->flags & P_BOOL) + /* the cast to long is required for Manx C */ + return (*(int *)varp != (int)(long)p->def_val); + /* P_STRING */ + return STRCMP(*(char_u **)varp, p->def_val); +} + +/* + * showoneopt: show the value of one option + * must not be called with a hidden option! + */ + static void +showoneopt(p) + struct option *p; +{ + char_u *varp; + + varp = get_varp(p); + + if ((p->flags & P_BOOL) && !*(int *)varp) + MSG_OUTSTR("no"); + else + MSG_OUTSTR(" "); + MSG_OUTSTR(p->fullname); + if (!(p->flags & P_BOOL)) + { + msg_outchar('='); + option_value2string(p); /* put string of option value in NameBuff */ + msg_outtrans(NameBuff); + } +} + +/* + * Write modified options as set command to a file. + * Return FAIL on error, OK otherwise. + */ + int +makeset(fd) + FILE *fd; +{ + struct option *p; + char_u *s; + int e; + char_u *varp; + + /* + * The options that don't have a default (terminal name, columns, lines) + * are never written. Terminal options are also not written. + */ + for (p = &options[0]; !istermoption(p); p++) + if (!(p->flags & P_NO_MKRC) && !istermoption(p) && + (option_changed(p))) + { + varp = get_varp(p); + if (p->flags & P_BOOL) + fprintf(fd, "set %s%s", *(int *)(varp) ? "" : "no", + p->fullname); + else if (p->flags & P_NUM) + fprintf(fd, "set %s=%ld", p->fullname, *(long *)(varp)); + else /* P_STRING */ + { + fprintf(fd, "set %s=", p->fullname); + s = *(char_u **)(varp); + /* some characters have to be escaped with CTRL-V or + * backslash */ + if (s != NULL && putescstr(fd, s, TRUE) == FAIL) + return FAIL; + } +#ifdef USE_CRNL + putc('\r', fd); +#endif + /* + * Only check error for this putc, should catch at least + * the "disk full" situation. + */ + e = putc('\n', fd); + if (e < 0) + return FAIL; + } + return OK; +} + +/* + * Clear all the terminal options. + * If the option has been allocated, free the memory. + * Terminal options are never hidden or indirect. + */ + void +clear_termoptions() +{ + struct option *p; + + /* + * Reset a few things before clearing the old options. This may cause + * outputting a few things that the terminal doesn't understand, but the + * screen will be cleared later, so this is OK. + */ +#ifdef USE_MOUSE + mch_setmouse(FALSE); /* switch mouse off */ +#endif + mch_restore_title(3); /* restore window titles */ +#ifdef WIN32 + /* + * Check if this is allowed now. + */ + if (can_end_termcap_mode(FALSE) == TRUE) +#endif + stoptermcap(); /* stop termcap mode */ + + for (p = &options[0]; p->fullname != NULL; p++) + if (istermoption(p)) + { + if (p->flags & P_ALLOCED) + free_string_option(*(char_u **)(p->var)); + if (p->flags & P_DEF_ALLOCED) + free_string_option(p->def_val); + *(char_u **)(p->var) = empty_option; + p->def_val = empty_option; + p->flags &= ~(P_ALLOCED|P_DEF_ALLOCED); + } + clear_termcodes(); +} + +/* + * Set the terminal option defaults to the current value. + * Used after setting the terminal name. + */ + void +set_term_defaults() +{ + struct option *p; + + for (p = &options[0]; p->fullname != NULL; p++) + if (istermoption(p) && p->def_val != *(char_u **)(p->var)) + { + if (p->flags & P_DEF_ALLOCED) + { + free_string_option(p->def_val); + p->flags &= ~P_DEF_ALLOCED; + } + p->def_val = *(char_u **)(p->var); + if (p->flags & P_ALLOCED) + { + p->flags |= P_DEF_ALLOCED; + p->flags &= ~P_ALLOCED; /* don't free the value now */ + } + } +} + +/* + * return TRUE if 'p' starts with 't_' + */ + static int +istermoption(p) + struct option *p; +{ + return (p->fullname[0] == 't' && p->fullname[1] == '_'); +} + +/* + * Compute columns for ruler and shown command. 'sc_col' is also used to + * decide what the maximum length of a message on the status line can be. + * If there is a status line for the last window, 'sc_col' is independent + * of 'ru_col'. + */ + +#define COL_RULER 17 /* columns needed by ruler */ + + void +comp_col() +{ + int last_has_status = (p_ls == 2 || (p_ls == 1 && firstwin != lastwin)); + + sc_col = 0; + ru_col = 0; + if (p_ru) + { + ru_col = COL_RULER + 1; + /* no last status line, adjust sc_col */ + if (!last_has_status) + sc_col = ru_col; + } + if (p_sc) + { + sc_col += SHOWCMD_COLS; + if (!p_ru || last_has_status) /* no need for separating space */ + ++sc_col; + } + sc_col = Columns - sc_col; + ru_col = Columns - ru_col; + if (sc_col <= 0) /* screen too narrow, will become a mess */ + sc_col = 1; + if (ru_col <= 0) + ru_col = 1; +} + + static char_u * +get_varp(p) + struct option *p; +{ + if (!(p->flags & P_IND) || p->var == NULL) + return p->var; + + switch ((long)(p->var)) + { + case PV_LIST: return (char_u *)&(curwin->w_p_list); + case PV_NU: return (char_u *)&(curwin->w_p_nu); +#ifdef RIGHTLEFT + case PV_RL: return (char_u *)&(curwin->w_p_rl); +#endif + case PV_SCROLL: return (char_u *)&(curwin->w_p_scroll); + case PV_WRAP: return (char_u *)&(curwin->w_p_wrap); + case PV_LBR: return (char_u *)&(curwin->w_p_lbr); + + case PV_AI: return (char_u *)&(curbuf->b_p_ai); + case PV_BIN: return (char_u *)&(curbuf->b_p_bin); +#ifdef CINDENT + case PV_CIN: return (char_u *)&(curbuf->b_p_cin); + case PV_CINK: return (char_u *)&(curbuf->b_p_cink); + case PV_CINO: return (char_u *)&(curbuf->b_p_cino); +#endif +#if defined(SMARTINDENT) || defined(CINDENT) + case PV_CINW: return (char_u *)&(curbuf->b_p_cinw); +#endif + case PV_COM: return (char_u *)&(curbuf->b_p_com); + case PV_EOL: return (char_u *)&(curbuf->b_p_eol); + case PV_ET: return (char_u *)&(curbuf->b_p_et); + case PV_FO: return (char_u *)&(curbuf->b_p_fo); + case PV_INF: return (char_u *)&(curbuf->b_p_inf); + case PV_ISK: return (char_u *)&(curbuf->b_p_isk); + case PV_LISP: return (char_u *)&(curbuf->b_p_lisp); + case PV_ML: return (char_u *)&(curbuf->b_p_ml); + case PV_MOD: return (char_u *)&(curbuf->b_changed); + case PV_RO: return (char_u *)&(curbuf->b_p_ro); +#ifdef SMARTINDENT + case PV_SI: return (char_u *)&(curbuf->b_p_si); +#endif +#ifndef SHORT_FNAME + case PV_SN: return (char_u *)&(curbuf->b_p_sn); +#endif + case PV_SW: return (char_u *)&(curbuf->b_p_sw); + case PV_TS: return (char_u *)&(curbuf->b_p_ts); + case PV_TW: return (char_u *)&(curbuf->b_p_tw); + case PV_TX: return (char_u *)&(curbuf->b_p_tx); + case PV_WM: return (char_u *)&(curbuf->b_p_wm); + default: EMSG("get_varp ERROR"); + } + /* always return a valid pointer to avoid a crash! */ + return (char_u *)&(curbuf->b_p_wm); +} + +/* + * Copy options from one window to another. + * Used when creating a new window. + * The 'scroll' option is not copied, because it depends on the window height. + */ + void +win_copy_options(wp_from, wp_to) + WIN *wp_from; + WIN *wp_to; +{ + wp_to->w_p_list = wp_from->w_p_list; + wp_to->w_p_nu = wp_from->w_p_nu; +#ifdef RIGHTLEFT + wp_to->w_p_rl = wp_from->w_p_rl; +#endif + wp_to->w_p_wrap = wp_from->w_p_wrap; + wp_to->w_p_lbr = wp_from->w_p_lbr; +} + +/* + * Copy options from one buffer to another. + * Used when creating a new buffer and when entering a buffer. + * Only do this once for a new buffer, otherwise allocated memory for the + * string option will be lost. + * When "entering" is TRUE we will enter the bp_to buffer. + */ + void +buf_copy_options(bp_from, bp_to, entering) + BUF *bp_from; + BUF *bp_to; + int entering; +{ + /* + * Don't copy if one of the pointers is NULL or they are the same. + */ + if (bp_from == NULL || bp_to == NULL || bp_from == bp_to) + return; + + /* + * Always copy when entering and 'cpo' contains 'S'. + * Don't copy when already initialized. + * Don't copy when 'cpo' contains 's' and not entering. + */ + if ((vim_strchr(p_cpo, CPO_BUFOPTGLOB) == NULL || !entering) && + (bp_to->b_p_initialized || + (!entering && vim_strchr(p_cpo, CPO_BUFOPT) != NULL))) + { + check_buf_options(bp_to); /* make sure we don't have NULLs */ + return; + } + + /* + * If already initialized, need to free the allocated strings. + * Copy 'readonly' and 'textmode' only when not initialized. + */ + if (bp_to->b_p_initialized) + { + free_string_option(bp_to->b_p_fo); + free_string_option(bp_to->b_p_isk); + free_string_option(bp_to->b_p_com); +#ifdef CINDENT + free_string_option(bp_to->b_p_cink); + free_string_option(bp_to->b_p_cino); +#endif +#if defined(CINDENT) || defined(SMARTINDENT) + free_string_option(bp_to->b_p_cinw); +#endif + } + else + { + bp_to->b_p_ro = FALSE; /* don't copy readonly */ + bp_to->b_p_tx = bp_from->b_p_tx; + bp_to->b_p_tx_nobin = bp_from->b_p_tx_nobin; + } + + bp_to->b_p_ai = bp_from->b_p_ai; + bp_to->b_p_ai_save = bp_from->b_p_ai_save; + bp_to->b_p_sw = bp_from->b_p_sw; + bp_to->b_p_tw = bp_from->b_p_tw; + bp_to->b_p_tw_save = bp_from->b_p_tw_save; + bp_to->b_p_tw_nobin = bp_from->b_p_tw_nobin; + bp_to->b_p_wm = bp_from->b_p_wm; + bp_to->b_p_wm_save = bp_from->b_p_wm_save; + bp_to->b_p_wm_nobin = bp_from->b_p_wm_nobin; + bp_to->b_p_bin = bp_from->b_p_bin; + bp_to->b_p_et = bp_from->b_p_et; + bp_to->b_p_et_nobin = bp_from->b_p_et_nobin; + bp_to->b_p_ml = bp_from->b_p_ml; + bp_to->b_p_ml_nobin = bp_from->b_p_ml_nobin; + bp_to->b_p_inf = bp_from->b_p_inf; +#ifndef SHORT_FNAME + bp_to->b_p_sn = bp_from->b_p_sn; +#endif + bp_to->b_p_com = strsave(bp_from->b_p_com); + bp_to->b_p_fo = strsave(bp_from->b_p_fo); +#ifdef SMARTINDENT + bp_to->b_p_si = bp_from->b_p_si; + bp_to->b_p_si_save = bp_from->b_p_si_save; +#endif +#ifdef CINDENT + bp_to->b_p_cin = bp_from->b_p_cin; + bp_to->b_p_cin_save = bp_from->b_p_cin_save; + bp_to->b_p_cink = strsave(bp_from->b_p_cink); + bp_to->b_p_cino = strsave(bp_from->b_p_cino); +#endif +#if defined(SMARTINDENT) || defined(CINDENT) + bp_to->b_p_cinw = strsave(bp_from->b_p_cinw); +#endif +#ifdef LISPINDENT + bp_to->b_p_lisp = bp_from->b_p_lisp; + bp_to->b_p_lisp_save = bp_from->b_p_lisp_save; +#endif + bp_to->b_p_ta_nobin = bp_from->b_p_ta_nobin; + + /* + * Don't copy the options set by do_help(), use the saved values + */ + if (!keep_help_flag && bp_from->b_help && help_save_isk != NULL) + { + bp_to->b_p_isk = strsave(help_save_isk); + if (bp_to->b_p_isk != NULL) + init_chartab(); + bp_to->b_p_ts = help_save_ts; + bp_to->b_help = FALSE; + } + else + { + bp_to->b_p_isk = strsave(bp_from->b_p_isk); + vim_memmove(bp_to->b_chartab, bp_from->b_chartab, (size_t)256); + bp_to->b_p_ts = bp_from->b_p_ts; + bp_to->b_help = bp_from->b_help; + } + check_buf_options(bp_to); + + /* + * Set the flag that indicates that the options have been ininitialized. + * Avoids loosing allocated memory. + */ + bp_to->b_p_initialized = TRUE; +} + +static int expand_option_idx = -1; +static char_u expand_option_name[5] = {'t', '_', NUL, NUL, NUL}; + + void +set_context_in_set_cmd(arg) + char_u *arg; +{ + int nextchar; + int flags = 0; /* init for GCC */ + int opt_idx = 0; /* init for GCC */ + char_u *p; + char_u *after_blank = NULL; + int is_term_option = FALSE; + int key; + + expand_context = EXPAND_SETTINGS; + if (*arg == NUL) + { + expand_pattern = arg; + return; + } + p = arg + STRLEN(arg) - 1; + if (*p == ' ' && *(p - 1) != '\\') + { + expand_pattern = p + 1; + return; + } + while (p != arg && (*p != ' ' || *(p - 1) == '\\')) + { + /* remember possible start of file name to expand */ + if ((*p == ' ' || (*p == ',' && *(p - 1) != '\\')) && + after_blank == NULL) + after_blank = p + 1; + p--; + } + if (p != arg) + p++; + if (STRNCMP(p, "no", (size_t) 2) == 0) + { + expand_context = EXPAND_BOOL_SETTINGS; + p += 2; + } + if (STRNCMP(p, "inv", (size_t) 3) == 0) + { + expand_context = EXPAND_BOOL_SETTINGS; + p += 3; + } + expand_pattern = arg = p; + if (*arg == '<') + { + while (*p != '>') + if (*p++ == NUL) /* expand terminal option name */ + return; + key = get_special_key_code(arg + 1); + if (key == 0) /* unknown name */ + { + expand_context = EXPAND_NOTHING; + return; + } + nextchar = *++p; + is_term_option = TRUE; + expand_option_name[2] = KEY2TERMCAP0(key); + expand_option_name[3] = KEY2TERMCAP1(key); + } + else + { + if (p[0] == 't' && p[1] == '_') + { + p += 2; + if (*p != NUL) + ++p; + if (*p == NUL) + return; /* expand option name */ + nextchar = *++p; + is_term_option = TRUE; + expand_option_name[2] = p[-2]; + expand_option_name[3] = p[-1]; + } + else + { + while (isalnum(*p) || *p == '_' || *p == '*') /* Allow * wildcard */ + p++; + if (*p == NUL) + return; + nextchar = *p; + *p = NUL; + opt_idx = findoption(arg); + *p = nextchar; + if (opt_idx == -1 || options[opt_idx].var == NULL) + { + expand_context = EXPAND_NOTHING; + return; + } + flags = options[opt_idx].flags; + if (flags & P_BOOL) + { + expand_context = EXPAND_NOTHING; + return; + } + } + } + if ((nextchar != '=' && nextchar != ':') + || expand_context == EXPAND_BOOL_SETTINGS) + { + expand_context = EXPAND_UNSUCCESSFUL; + return; + } + if (expand_context != EXPAND_BOOL_SETTINGS && p[1] == NUL) + { + expand_context = EXPAND_OLD_SETTING; + if (is_term_option) + expand_option_idx = -1; + else + expand_option_idx = opt_idx; + expand_pattern = p + 1; + return; + } + expand_context = EXPAND_NOTHING; + if (is_term_option || (flags & P_NUM)) + return; + if (after_blank != NULL) + expand_pattern = after_blank; + else + expand_pattern = p + 1; + if (flags & P_EXPAND) + { + p = options[opt_idx].var; + if (p == (char_u *)&p_bdir || p == (char_u *)&p_dir || + p == (char_u *)&p_path) + expand_context = EXPAND_DIRECTORIES; + else + expand_context = EXPAND_FILES; + } + return; +} + + int +ExpandSettings(prog, num_file, file) + regexp *prog; + int *num_file; + char_u ***file; +{ + int num_normal = 0; /* Number of matching non-term-code settings */ + int num_term = 0; /* Number of matching terminal code settings */ + int opt_idx; + int match; + int count = 0; + char_u *str; + int loop; + int is_term_opt; + char_u name_buf[MAX_KEY_NAME_LEN]; + + /* do this loop twice: + * loop == 0: count the number of matching options + * loop == 1: copy the matching options into allocated memory + */ + for (loop = 0; loop <= 1; ++loop) + { + if (expand_context != EXPAND_BOOL_SETTINGS) + { + if (vim_regexec(prog, (char_u *)"all", TRUE)) + { + if (loop == 0) + num_normal++; + else + (*file)[count++] = strsave((char_u *)"all"); + } + if (vim_regexec(prog, (char_u *)"termcap", TRUE)) + { + if (loop == 0) + num_normal++; + else + (*file)[count++] = strsave((char_u *)"termcap"); + } + } + for (opt_idx = 0; (str = (char_u *)options[opt_idx].fullname) != NULL; + opt_idx++) + { + if (options[opt_idx].var == NULL) + continue; + if (expand_context == EXPAND_BOOL_SETTINGS + && !(options[opt_idx].flags & P_BOOL)) + continue; + is_term_opt = istermoption(&options[opt_idx]); + if (is_term_opt && num_normal > 0) + continue; + match = FALSE; + if (vim_regexec(prog, str, TRUE) || + (options[opt_idx].shortname != NULL && + vim_regexec(prog, + (char_u *)options[opt_idx].shortname, TRUE))) + match = TRUE; + else if (is_term_opt) + { + name_buf[0] = '<'; + name_buf[1] = 't'; + name_buf[2] = '_'; + name_buf[3] = str[2]; + name_buf[4] = str[3]; + name_buf[5] = '>'; + name_buf[6] = NUL; + if (vim_regexec(prog, name_buf, TRUE)) + { + match = TRUE; + str = name_buf; + } + } + if (match) + { + if (loop == 0) + { + if (is_term_opt) + num_term++; + else + num_normal++; + } + else + (*file)[count++] = strsave(str); + } + } + /* + * Check terminal key codes, these are not in the option table + */ + if (expand_context != EXPAND_BOOL_SETTINGS && num_normal == 0) + { + for (opt_idx = 0; (str = get_termcode(opt_idx)) != NULL; opt_idx++) + { + if (!isprint(str[0]) || !isprint(str[1])) + continue; + + name_buf[0] = 't'; + name_buf[1] = '_'; + name_buf[2] = str[0]; + name_buf[3] = str[1]; + name_buf[4] = NUL; + + match = FALSE; + if (vim_regexec(prog, name_buf, TRUE)) + match = TRUE; + else + { + name_buf[0] = '<'; + name_buf[1] = 't'; + name_buf[2] = '_'; + name_buf[3] = str[0]; + name_buf[4] = str[1]; + name_buf[5] = '>'; + name_buf[6] = NUL; + + if (vim_regexec(prog, name_buf, TRUE)) + match = TRUE; + } + if (match) + { + if (loop == 0) + num_term++; + else + (*file)[count++] = strsave(name_buf); + } + } + /* + * Check special key names. + */ + for (opt_idx = 0; (str = get_key_name(opt_idx)) != NULL; opt_idx++) + { + name_buf[0] = '<'; + STRCPY(name_buf + 1, str); + STRCAT(name_buf, ">"); + + reg_ic = TRUE; /* ignore case here */ + if (vim_regexec(prog, name_buf, TRUE)) + { + if (loop == 0) + num_term++; + else + (*file)[count++] = strsave(name_buf); + } + } + } + if (loop == 0) + { + if (num_normal > 0) + *num_file = num_normal; + else if (num_term > 0) + *num_file = num_term; + else + return OK; + *file = (char_u **) alloc((unsigned)(*num_file * sizeof(char_u *))); + if (*file == NULL) + { + *file = (char_u **)""; + return FAIL; + } + } + } + return OK; +} + + int +ExpandOldSetting(num_file, file) + int *num_file; + char_u ***file; +{ + char_u *var = NULL; /* init for GCC */ + char_u *buf; + + *num_file = 0; + *file = (char_u **)alloc((unsigned)sizeof(char_u *)); + if (*file == NULL) + return FAIL; + + /* + * For a terminal key code epand_option_idx is < 0. + */ + if (expand_option_idx < 0) + { + var = find_termcode(expand_option_name + 2); + if (var == NULL) + expand_option_idx = findoption(expand_option_name); + } + + if (expand_option_idx >= 0) + { + /* put string of option value in NameBuff */ + option_value2string(&options[expand_option_idx]); + var = NameBuff; + } + else if (var == NULL) + var = (char_u *)""; + + /* A backslash is required before some characters */ + buf = strsave_escaped(var, escape_chars); + + if (buf == NULL) + { + vim_free(*file); + *file = NULL; + return FAIL; + } + + *file[0] = buf; + *num_file = 1; + return OK; +} + +/* + * Get the value for the numeric or string option *op in a nice format into + * NameBuff[]. Must not be called with a hidden option! + */ + static void +option_value2string(op) + struct option *op; +{ + char_u *varp; + + varp = get_varp(op); + if (op->flags & P_NUM) + { + if ((long *)varp == &p_wc) + { + if (IS_SPECIAL(p_wc) || find_special_key_in_table((int)p_wc) >= 0) + STRCPY(NameBuff, get_special_key_name((int)p_wc, 0)); + else + STRCPY(NameBuff, transchar((int)p_wc)); + } + else + sprintf((char *)NameBuff, "%ld", *(long *)varp); + } + else /* P_STRING */ + { + varp = *(char_u **)(varp); + if (varp == NULL) /* just in case */ + NameBuff[0] = NUL; + else if (op->flags & P_EXPAND) + home_replace(NULL, varp, NameBuff, MAXPATHL); + else + STRNCPY(NameBuff, varp, MAXPATHL); + } +} + +/* + * Convert the given pattern "pat" which has shell style wildcards in it, into + * a regular expression, and return the result. If there is a directory path + * separator to be matched, then TRUE is put in allow_directories, otherwise + * FALSE is put there -- webb. + */ + char_u * +file_pat_to_reg_pat(pat, pat_end, allow_directories) + char_u *pat; + char_u *pat_end; /* first char after pattern */ + int *allow_directories; /* Result passed back out in here */ +{ + int size; + char_u *endp; + char_u *reg_pat; + char_u *p; + int i; + int nested = 0; + int add_dollar = TRUE; + + if (allow_directories != NULL) + *allow_directories = FALSE; + + size = 2; /* '^' at start, '$' at end */ + for (p = pat; p < pat_end; p++) + { + switch (*p) + { + case '*': + case '.': + case ',': + case '{': + case '}': + case '~': +#ifdef BACKSLASH_IN_FILENAME + case '\\': +#endif + size += 2; + break; + default: + size++; + break; + } + } + reg_pat = alloc(size + 1); + if (reg_pat == NULL) + return NULL; + i = 0; + if (pat[0] == '*') + while (pat[0] == '*' && pat < pat_end - 1) + pat++; + else + reg_pat[i++] = '^'; + endp = pat_end - 1; + if (*endp == '*') + { + while (endp - pat > 0 && *endp == '*') + endp--; + add_dollar = FALSE; + } + for (p = pat; *p && nested >= 0 && p <= endp; p++) + { + switch (*p) + { + case '*': + reg_pat[i++] = '.'; + reg_pat[i++] = '*'; + break; + case '.': + case '~': + reg_pat[i++] = '\\'; + reg_pat[i++] = *p; + break; + case '?': + reg_pat[i++] = '.'; + break; + case '\\': + if (p[1] == NUL) + break; +#ifdef BACKSLASH_IN_FILENAME + /* translate "\x" to "\\x", "\*" to "\\.*", and "\?" to "\\." */ + if (isfilechar(p[1]) || p[1] == '*' || p[1] == '?') + { + reg_pat[i++] = '\\'; + reg_pat[i++] = '\\'; + if (allow_directories != NULL) + *allow_directories = TRUE; + break; + } + ++p; +#else + if (*++p == '?') + reg_pat[i++] = '?'; + else +#endif + if (*p == ',') + reg_pat[i++] = ','; + else + { + if (allow_directories != NULL && ispathsep(*p)) + *allow_directories = TRUE; + reg_pat[i++] = '\\'; + reg_pat[i++] = *p; + } + break; + case '{': + reg_pat[i++] = '\\'; + reg_pat[i++] = '('; + nested++; + break; + case '}': + reg_pat[i++] = '\\'; + reg_pat[i++] = ')'; + --nested; + break; + case ',': + if (nested) + { + reg_pat[i++] = '\\'; + reg_pat[i++] = '|'; + } + else + reg_pat[i++] = ','; + break; + default: + if (allow_directories != NULL && ispathsep(*p)) + *allow_directories = TRUE; + reg_pat[i++] = *p; + break; + } + } + if (add_dollar) + reg_pat[i++] = '$'; + reg_pat[i] = NUL; + if (nested != 0) + { + if (nested < 0) + EMSG("Missing {."); + else + EMSG("Missing }."); + vim_free(reg_pat); + reg_pat = NULL; + } + return reg_pat; +} + +#ifdef AUTOCMD +/* + * functions for automatic commands + */ + +static void show_autocmd __ARGS((AutoPat *ap, int event)); +static void del_autocmd __ARGS((AutoPat *ap)); +static void del_autocmd_cmds __ARGS((AutoPat *ap)); +static int event_name2nr __ARGS((char_u *start, char_u **end)); +static char *event_nr2name __ARGS((int event)); +static char_u *find_end_event __ARGS((char_u *arg)); +static int do_autocmd_event __ARGS((int event, char_u *pat, + char_u *cmd, int force)); + + static void +show_autocmd(ap, event) + AutoPat *ap; + int event; +{ + AutoCmd *ac; + + if (got_int) /* "q" hit for "--more--" */ + return; + msg_outchar('\n'); + if (got_int) /* "q" hit for "--more--" */ + return; + msg_outchar('\n'); + if (got_int) /* "q" hit for "--more--" */ + return; + MSG_OUTSTR(event_nr2name(event)); + MSG_OUTSTR(" "); + msg_outstr(ap->pat); + for (ac = ap->cmds; ac != NULL; ac = ac->next) + { + MSG_OUTSTR("\n "); + if (got_int) /* hit "q" at "--more--" prompt */ + return; + msg_outtrans(ac->cmd); + } +} + +/* + * Delete an autocommand pattern. + */ + static void +del_autocmd(ap) + AutoPat *ap; +{ + vim_free(ap->pat); + vim_free(ap->reg_pat); + del_autocmd_cmds(ap); + vim_free(ap); +} + +/* + * Delete the commands from a pattern. + */ + static void +del_autocmd_cmds(ap) + AutoPat *ap; +{ + AutoCmd *ac; + + while (ap->cmds != NULL) + { + ac = ap->cmds; + ap->cmds = ac->next; + vim_free(ac->cmd); + vim_free(ac); + } +} + +/* + * Return the event number for event name "start". + * Return -1 if the event name was not found. + * Return a pointer to the next event name in "end". + */ + static int +event_name2nr(start, end) + char_u *start; + char_u **end; +{ + char_u *p; + int i; + int len; + + /* the event name ends with end of line, a blank or a comma */ + for (p = start; *p && !vim_iswhite(*p) && *p != ','; ++p) + ; + for (i = 0; event_names[i].name != NULL; ++i) + { + len = strlen(event_names[i].name); + if (len == p - start && + vim_strnicmp((char_u *)event_names[i].name, (char_u *)start, (size_t)len) == 0) + break; + } + if (*p == ',') + ++p; + *end = p; + if (event_names[i].name == NULL) + return -1; + return event_names[i].event; +} + +/* + * Return the name for event "event". + */ + static char * +event_nr2name(event) + int event; +{ + int i; + + for (i = 0; event_names[i].name != NULL; ++i) + if (event_names[i].event == event) + return event_names[i].name; + return "Unknown"; +} + +/* + * Scan over the events. "*" stands for all events. + */ + static char_u * +find_end_event(arg) + char_u *arg; +{ + char_u *pat; + char_u *p; + + if (*arg == '*') + { + if (arg[1] && !vim_iswhite(arg[1])) + { + EMSG2("Illegal character after *: %s", arg); + return NULL; + } + pat = arg + 1; + } + else + { + for (pat = arg; *pat && !vim_iswhite(*pat); pat = p) + { + if (event_name2nr(pat, &p) < 0) + { + EMSG2("No such event: %s", pat); + return NULL; + } + } + } + return pat; +} + +/* + * do_autocmd() -- implements the :autocmd command. Can be used in the + * following ways: + * + * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that + * will be automatically executed for <event> + * when editing a file matching <pat>. + * :autocmd <event> <pat> Show the auto-commands associated with + * <event> and <pat>. + * :autocmd <event> Show the auto-commands associated with + * <event>. + * :autocmd Show all auto-commands. + * :autocmd! <event> <pat> <cmd> Remove all auto-commands associated with + * <event> and <pat>, and add the command + * <cmd>. + * :autocmd! <event> <pat> Remove all auto-commands associated with + * <event> and <pat>. + * :autocmd! <event> Remove all auto-commands associated with + * <event>. + * :autocmd! Remove ALL auto-commands. + * + * Multiple events and patterns may be given separated by commas. Here are + * some examples: + * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic + * :autocmd bufleave * set tw=79 nosmartindent ic infercase + * + * :autocmd * *.c show all autocommands for *.c files. + */ + void +do_autocmd(arg, force) + char_u *arg; + int force; +{ + char_u *pat; + char_u *cmd; + int event; + + /* + * Don't change autocommands while executing one. + */ + if (autocmd_busy) + return; + + /* + * Scan over the events. + * If we find an illegal name, return here, don't do anything. + */ + pat = find_end_event(arg); + if (pat == NULL) + return; + + /* + * Scan over the pattern. Put a NUL at the end. + */ + pat = skipwhite(pat); + cmd = pat; + while (*cmd && (!vim_iswhite(*cmd) || cmd[-1] == '\\')) + cmd++; + if (*cmd) + *cmd++ = NUL; + + /* + * Find the start of the commands. + */ + cmd = skipwhite(cmd); + + /* + * Print header when showing autocommands. + */ + if (!force && *cmd == NUL) + { + set_highlight('t'); /* Highlight title */ + start_highlight(); + MSG_OUTSTR("\n--- Auto-Commands ---"); + stop_highlight(); + } + + /* + * Loop over the events. + */ + if (*arg == '*' || *arg == NUL) + { + for (event = 0; event < NUM_EVENTS; ++event) + if (do_autocmd_event(event, pat, cmd, force) == FAIL) + break; + } + else + { + while (*arg && !vim_iswhite(*arg)) + if (do_autocmd_event(event_name2nr(arg, &arg), pat, + cmd, force) == FAIL) + break; + } +} + +/* + * do_autocmd() for one event. + * If *pat == NUL do for all patterns. + * If *cmd == NUL show entries. + * If force == TRUE delete entries. + */ + static int +do_autocmd_event(event, pat, cmd, force) + int event; + char_u *pat; + char_u *cmd; + int force; +{ + AutoPat *ap; + AutoPat *ap2; + AutoPat **final_ap; + AutoCmd *ac; + AutoCmd **final_ac; + int nested; + char_u *endpat; + int len; + + /* + * Show or delete all patterns for an event. + */ + if (*pat == NUL) + { + for (ap = first_autopat[event]; ap != NULL; ap = ap2) + { + ap2 = ap->next; + if (force) + del_autocmd(ap); + else + show_autocmd(ap, event); + } + if (force) + first_autopat[event] = NULL; + } + + /* + * Loop through all the specified patterns. + */ + for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat)) + { + /* + * Find end of the pattern. + * Watch out for a comma in braces, like "*.\{obj,o\}". + */ + nested = 0; + for (endpat = pat; + *endpat && (*endpat != ',' || nested || endpat[-1] == '\\'); + ++endpat) + { + if (*endpat == '{') + nested++; + else if (*endpat == '}') + nested--; + } + if (pat == endpat) /* ignore single comma */ + continue; + + /* + * Find entry with same pattern. + */ + final_ap = &first_autopat[event]; + for (ap = first_autopat[event]; ap != NULL; ap = *final_ap) + { + len = STRLEN(ap->pat); + if (len == endpat - pat && STRNCMP(pat, ap->pat, len) == 0) + break; + final_ap = &ap->next; + } + + /* + * Add a new pattern. + * Show and delete are ignored if pattern is not found. + */ + if (ap == NULL) + { + if (*cmd == NUL) + continue; + + /* Add the autocmd at the end of the list */ + ap = (AutoPat *)alloc((unsigned)sizeof(AutoPat)); + if (ap == NULL) + return FAIL; + ap->pat = strnsave(pat, (int)(endpat - pat)); + if (ap->pat == NULL) + { + vim_free(ap); + return FAIL; + } + ap->reg_pat = file_pat_to_reg_pat(pat, endpat, + &ap->allow_directories); + if (ap->reg_pat == NULL) + { + vim_free(ap->pat); + vim_free(ap); + return FAIL; + } + ap->cmds = NULL; + *final_ap = ap; + ap->next = NULL; + } + + /* + * Remove existing autocommands. + * If not adding any new autocmd's for this pattern, delete the + * pattern from the autopat list + */ + else if (force) + { + del_autocmd_cmds(ap); + if (*cmd == NUL) + { + if (ap == first_autopat[event]) + first_autopat[event] = ap->next; + else + { + for (ap2 = first_autopat[event]; + ap2->next != ap; + ap2 = ap2->next) + ; + ap2->next = ap->next; + } + del_autocmd(ap); + } + } + + /* + * Show autocmd's for this autopat + */ + if (*cmd == NUL && !force) + { + show_autocmd(ap, event); + } + + /* + * Add the autocmd at the end if it's not already there. + */ + else if (*cmd != NUL) + { + final_ac = &(ap->cmds); + for (ac = ap->cmds; + ac != NULL && STRCMP(cmd, ac->cmd) != 0; + ac = ac->next) + final_ac = &ac->next; + if (ac == NULL) + { + ac = (AutoCmd *)alloc((unsigned)sizeof(AutoCmd)); + if (ac == NULL) + return FAIL; + ac->cmd = strsave(cmd); + if (ac->cmd == NULL) + { + vim_free(ac); + return FAIL; + } + ac->next = NULL; + *final_ac = ac; + } + } + } + return OK; +} + +/* + * Implementation of ":doautocmd event [fname]". + */ + void +do_doautocmd(arg) + char_u *arg; +{ + char_u *fname; + int nothing_done = TRUE; + + if (*arg == '*') + { + EMSG("Can't execute autocommands for ALL events"); + return; + } + + /* + * Scan over the events. + * If we find an illegal name, return here, don't do anything. + */ + fname = find_end_event(arg); + if (fname == NULL) + return; + + fname = skipwhite(fname); + + /* + * Loop over the events. + */ + while (*arg && !vim_iswhite(*arg)) + if (apply_autocmds(event_name2nr(arg, &arg), fname, NULL)) + nothing_done = FALSE; + + if (nothing_done) + MSG("No matching autocommands"); +} + +/* + * Execute autocommands for "event" and file name "fname". + * Return TRUE if some commands were executed. + */ + int +apply_autocmds(event, fname, fname_io) + int event; + char_u *fname; /* NULL or empty means use actual file name */ + char_u *fname_io; /* fname to use for "^Vf" on cmdline */ +{ + struct regexp *prog; + char_u *tail; + AutoPat *ap; + AutoCmd *ac; + int temp; + int save_changed = curbuf->b_changed; + char_u *save_name; + char_u *full_fname = NULL; + int retval = FALSE; + + if (autocmd_busy) /* no nesting allowed */ + return retval; + + /* Don't redraw while doing auto commands. */ + temp = RedrawingDisabled; + RedrawingDisabled = TRUE; + save_name = sourcing_name; /* may be called from .vimrc */ + autocmd_fname = fname_io; + + /* + * While applying autocmds, we don't want to allow the commands + * :doautocmd or :autocmd. + */ + autocmd_busy = TRUE; + + /* + * When the file name is NULL or empty, use the file name of the current + * buffer. Always use the full path of the file name to match with, in + * case "allow_directories" is set. + */ + if (fname == NULL || *fname == NUL) + { + fname = curbuf->b_filename; + if (fname == NULL) + fname = (char_u *)""; + } + else + { + full_fname = FullName_save(fname); + fname = full_fname; + } + + tail = gettail(fname); + + for (ap = first_autopat[event]; ap != NULL; ap = ap->next) + { +#ifdef CASE_INSENSITIVE_FILENAME + reg_ic = TRUE; /* Always ignore case */ +#else + reg_ic = FALSE; /* Don't ever ignore case */ +#endif + reg_magic = TRUE; /* Always use magic */ + prog = vim_regcomp(ap->reg_pat); + + if (prog != NULL && + ((ap->allow_directories && vim_regexec(prog, fname, TRUE)) || + (!ap->allow_directories && vim_regexec(prog, tail, TRUE)))) + { + sprintf((char *)IObuff, "%s Auto commands for \"%s\"", + event_nr2name(event), (char *)ap->pat); + sourcing_name = strsave(IObuff); + for (ac = ap->cmds; ac != NULL; ac = ac->next) + { + do_cmdline(ac->cmd, TRUE, TRUE); + retval = TRUE; + } + vim_free(sourcing_name); + } + vim_free(prog); + } + RedrawingDisabled = temp; + autocmd_busy = FALSE; + sourcing_name = save_name; + autocmd_fname = NULL; + vim_free(full_fname); + + /* Some events don't set or reset the Changed flag */ + if (event == EVENT_BUFREADPOST || event == EVENT_BUFWRITEPOST || + event == EVENT_FILEAPPENDPOST || event == EVENT_VIMLEAVE) + curbuf->b_changed = save_changed; + + return retval; +} + + char_u * +set_context_in_autocmd(arg, doautocmd) + char_u *arg; + int doautocmd; /* TRUE for :doautocmd, FALSE for :autocmd */ +{ + char_u *p; + + /* skip over event name */ + for (p = arg; *p && !vim_iswhite(*p); ++p) + if (*p == ',') + arg = p + 1; + if (*p == NUL) + { + expand_context = EXPAND_EVENTS; /* expand event name */ + expand_pattern = arg; + return NULL; + } + + /* skip over pattern */ + arg = skipwhite(p); + while (*arg && (!vim_iswhite(*arg) || arg[-1] == '\\')) + arg++; + if (*arg) + return arg; /* expand (next) command */ + + if (doautocmd) + expand_context = EXPAND_FILES; /* expand file names */ + else + expand_context = EXPAND_NOTHING; /* pattern is not expanded */ + return NULL; +} + + int +ExpandEvents(prog, num_file, file) + regexp *prog; + int *num_file; + char_u ***file; +{ + int i; + int count; + int round; + + /* + * round == 1: Count the matches. + * round == 2: Save the matches into the array. + */ + for (round = 1; round <= 2; ++round) + { + count = 0; + for (i = 0; event_names[i].name != NULL; i++) + if (vim_regexec(prog, (char_u *)event_names[i].name, TRUE)) + { + if (round == 1) + count++; + else + (*file)[count++] = strsave((char_u *)event_names[i].name); + } + if (round == 1) + { + *num_file = count; + if (count == 0 || (*file = (char_u **) + alloc((unsigned)(count * sizeof(char_u *)))) == NULL) + return FAIL; + } + } + return OK; +} + +#endif /* AUTOCMD */ + +#ifdef HAVE_LANGMAP +/* + * Any character has an equivalent character. This is used for keyboards that + * have a special language mode that sends characters above 128 (although + * other characters can be translated too). + */ + +/* + * char_u langmap_mapchar[256]; + * Normally maps each of the 128 upper chars to an <128 ascii char; used to + * "translate" native lang chars in normal mode or some cases of + * insert mode without having to tediously switch lang mode back&forth. + */ + + static void +langmap_init() +{ + int i; + + for (i = 0; i < 256; i++) /* we init with a-one-to one map */ + langmap_mapchar[i] = i; +} + +/* + * Called when langmap option is set; the language map can be + * changed at any time! + */ + static void +langmap_set() +{ + char_u *p; + char_u *p2; + int from, to; + + langmap_init(); /* back to one-to-one map first */ + + for (p = p_langmap; p[0]; ) + { + for (p2 = p; p2[0] && p2[0] != ',' && p2[0] != ';'; ++p2) + if (p2[0] == '\\' && p2[1]) + ++p2; + if (p2[0] == ';') + ++p2; /* abcd;ABCD form, p2 points to A */ + else + p2 = NULL; /* aAbBcCdD form, p2 is NULL */ + while (p[0]) + { + if (p[0] == '\\' && p[1]) + ++p; + from = p[0]; + if (p2 == NULL) + { + if (p[1] == '\\') + ++p; + to = p[1]; + } + else + { + if (p2[0] == '\\') + ++p2; + to = p2[0]; + } + if (to == NUL) + { + EMSG2("'langmap': Matching character missing for %s", + transchar(from)); + return; + } + langmap_mapchar[from] = to; + + /* Advance to next pair */ + if (p2 == NULL) + { + p += 2; + if (p[0] == ',') + { + ++p; + break; + } + } + else + { + ++p; + ++p2; + if (*p == ';') + { + p = p2; + if (p[0]) + { + if (p[0] != ',') + { + EMSG2("'langmap': Extra characters after semicolon: %s", p); + return; + } + ++p; + } + break; + } + } + } + } +} +#endif + +/* + * Return TRUE if format option 'x' is in effect. + * Take care of no formatting when 'paste' is set. + */ + int +has_format_option(x) + int x; +{ + if (p_paste) + return FALSE; + return (vim_strchr(curbuf->b_p_fo, x) != NULL); +} + +/* + * Return TRUE if "x" is present in 'shortmess' option, or + * 'shortmess' contains 'a' and "x" is present in SHM_A. + */ + int +shortmess(x) + int x; +{ + return (vim_strchr(p_shm, x) != NULL || (vim_strchr(p_shm, 'a') != NULL && + vim_strchr((char_u *)SHM_A, x) != NULL)); +} + +/* + * set_paste_option() - Called after p_paste was set or reset. + */ + static void +paste_option_changed() +{ + static int old_p_paste = FALSE; + static int save_sm = 0; + static int save_ru = 0; +#ifdef RIGHTLEFT + static int save_ri = 0; + static int save_hkmap = 0; +#endif + BUF *buf; + + if (p_paste) + { + /* + * Paste switched from off to on. + * Save the current values, so they can be restored later. + */ + if (!old_p_paste) + { + /* save options for each buffer */ + for (buf = firstbuf; buf != NULL; buf = buf->b_next) + { + buf->b_p_tw_save = buf->b_p_tw; + buf->b_p_wm_save = buf->b_p_wm; + buf->b_p_ai_save = buf->b_p_ai; +#ifdef SMARTINDENT + buf->b_p_si_save = buf->b_p_si; +#endif +#ifdef CINDENT + buf->b_p_cin_save = buf->b_p_cin; +#endif +#ifdef LISPINDENT + buf->b_p_lisp_save = buf->b_p_lisp; +#endif + } + + /* save global options */ + save_sm = p_sm; + save_ru = p_ru; +#ifdef RIGHTLEFT + save_ri = p_ri; + save_hkmap = p_hkmap; +#endif + } + + /* + * Always set the option values, also when 'paste' is set when it is + * already on. + */ + /* set options for each buffer */ + for (buf = firstbuf; buf != NULL; buf = buf->b_next) + { + buf->b_p_tw = 0; /* textwidth is 0 */ + buf->b_p_wm = 0; /* wrapmargin is 0 */ + buf->b_p_ai = 0; /* no auto-indent */ +#ifdef SMARTINDENT + buf->b_p_si = 0; /* no smart-indent */ +#endif +#ifdef CINDENT + buf->b_p_cin = 0; /* no c indenting */ +#endif +#ifdef LISPINDENT + buf->b_p_lisp = 0; /* no lisp indenting */ +#endif + } + + /* set global options */ + p_sm = 0; /* no showmatch */ + p_ru = 0; /* no ruler */ +#ifdef RIGHTLEFT + p_ri = 0; /* no reverse insert */ + p_hkmap = 0; /* no Hebrew keyboard */ +#endif + } + + /* + * Paste switched from on to off: Restore saved values. + */ + else if (old_p_paste) + { + /* restore options for each buffer */ + for (buf = firstbuf; buf != NULL; buf = buf->b_next) + { + buf->b_p_tw = buf->b_p_tw_save; + buf->b_p_wm = buf->b_p_wm_save; + buf->b_p_ai = buf->b_p_ai_save; +#ifdef SMARTINDENT + buf->b_p_si = buf->b_p_si_save; +#endif +#ifdef CINDENT + buf->b_p_cin = buf->b_p_cin_save; +#endif +#ifdef LISPINDENT + buf->b_p_lisp = buf->b_p_lisp_save; +#endif + } + + /* restore global options */ + p_sm = save_sm; + p_ru = save_ru; +#ifdef RIGHTLEFT + p_ri = save_ri; + p_hkmap = save_hkmap; +#endif + } + + old_p_paste = p_paste; +} + +/* + * p_compatible_set() - Called when p_cp has been set. + */ + static void +p_compatible_set() +{ + p_bs = 0; /* normal backspace */ + /* backspace and space do not wrap */ + set_string_option((char_u *)"ww", -1, (char_u *)"", TRUE); + p_bk = 0; /* no backup file */ + /* Use textwidth for formatting, don't format comments */ + set_string_option((char_u *)"fo", -1, (char_u *)FO_DFLT_VI, TRUE); + /* all compatible flags on */ + set_string_option((char_u *)"cpo", -1, (char_u *)CPO_ALL, TRUE); + set_string_option((char_u *)"isk", -1, (char_u *)"@,48-57,_", TRUE); + /* no short messages */ + set_string_option((char_u *)"shm", -1, (char_u *)"", TRUE); +#ifdef DIGRAPHS + p_dg = 0; /* no digraphs */ +#endif /* DIGRAPHS */ + p_ek = 0; /* no ESC keys in insert mode */ + curbuf->b_p_et = 0; /* no expansion of tabs */ + p_gd = 0; /* /g is not default for :s */ + p_hi = 0; /* no history */ + p_scs = 0; /* no ignore case switch */ + p_im = 0; /* do not start in insert mode */ + p_js = 1; /* insert 2 spaces after period */ + curbuf->b_p_ml = 0; /* no modelines */ + p_more = 0; /* no -- more -- for listings */ + p_ru = 0; /* no ruler */ +#ifdef RIGHTLEFT + p_ri = 0; /* no reverse insert */ + p_hkmap = 0; /* no Hebrew keyboard mapping */ +#endif + p_sj = 1; /* no scrolljump */ + p_so = 0; /* no scrolloff */ + p_sr = 0; /* do not round indent to shiftwidth */ + p_sc = 0; /* no showcommand */ + p_smd = 0; /* no showmode */ +#ifdef SMARTINDENT + curbuf->b_p_si = 0; /* no smartindent */ +#endif +#ifdef CINDENT + curbuf->b_p_cin = 0; /* no C indenting */ +#endif + p_sta = 0; /* no smarttab */ + p_sol = TRUE; /* Move cursor to start-of-line */ + p_ta = 0; /* no automatic textmode detection */ + curbuf->b_p_tw = 0; /* no automatic line wrap */ + p_to = 0; /* no tilde operator */ + p_ttimeout = 0; /* no terminal timeout */ + p_tr = 0; /* tag file names not relative */ + p_ul = 0; /* no multilevel undo */ + p_uc = 0; /* no autoscript file */ + p_wb = 0; /* no backup file */ + if (p_wc == TAB) + p_wc = Ctrl('E'); /* normal use for TAB */ + init_chartab(); /* make b_p_isk take effect */ +} + +/* + * fill_breakat_flags() -- called when 'breakat' changes value. + */ + static void +fill_breakat_flags() +{ + char_u *c; + int i; + + for (i = 0; i < 256; i++) + breakat_flags[i] = FALSE; + + if (p_breakat != NULL) + for (c = p_breakat; *c; c++) + breakat_flags[*c] = TRUE; +} |