[BACK]Return to option.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / vim

File: [local] / src / usr.bin / vim / Attic / option.c (download)

Revision 1.1.1.1 (vendor branch), Sat Sep 7 21:40:25 1996 UTC (27 years, 9 months ago) by downsj
Branch: VIM
CVS Tags: VIM42
Changes since 1.1: +0 -0 lines

Initial import of vim 4.2.

This is meant to replace nvi in the tree.  Vim, in general, works better,
provides more features, and does not suffer from the license problems
being imposed upon nvi.

On the other hand, vim lacks a non-visual ex mode, in addition to open mode.

This includes the GUI (X11) code, but doesn't try to compile it.


/*	$OpenBSD: option.c,v 1.1.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;
}