1/*
2 * options.c - shell options
3 *
4 * This file is part of zsh, the Z shell.
5 *
6 * Copyright (c) 1992-1997 Paul Falstad
7 * All rights reserved.
8 *
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and to distribute modified versions of this software for any
12 * purpose, provided that the above copyright notice and the following
13 * two paragraphs appear in all copies of this software.
14 *
15 * In no event shall Paul Falstad or the Zsh Development Group be liable
16 * to any party for direct, indirect, special, incidental, or consequential
17 * damages arising out of the use of this software and its documentation,
18 * even if Paul Falstad and the Zsh Development Group have been advised of
19 * the possibility of such damage.
20 *
21 * Paul Falstad and the Zsh Development Group specifically disclaim any
22 * warranties, including, but not limited to, the implied warranties of
23 * merchantability and fitness for a particular purpose.  The software
24 * provided hereunder is on an "as is" basis, and Paul Falstad and the
25 * Zsh Development Group have no obligation to provide maintenance,
26 * support, updates, enhancements, or modifications.
27 *
28 */
29
30#include "zsh.mdh"
31#include "options.pro"
32
33/* current emulation (used to decide which set of option letters is used) */
34
35/**/
36mod_export int emulation;
37
38/* current sticky emulation:  sticky = NULL means none */
39
40/**/
41mod_export Emulation_options sticky;
42
43/* the options; e.g. if opts[SHGLOB] != 0, SH_GLOB is turned on */
44
45/**/
46mod_export char opts[OPT_SIZE];
47
48/* Option name hash table */
49
50/**/
51mod_export HashTable optiontab;
52
53/* The canonical option name table */
54
55#define OPT_CSH		EMULATE_CSH
56#define OPT_KSH		EMULATE_KSH
57#define OPT_SH		EMULATE_SH
58#define OPT_ZSH		EMULATE_ZSH
59
60#define OPT_ALL		(OPT_CSH|OPT_KSH|OPT_SH|OPT_ZSH)
61#define OPT_BOURNE	(OPT_KSH|OPT_SH)
62#define OPT_BSHELL	(OPT_KSH|OPT_SH|OPT_ZSH)
63#define OPT_NONBOURNE	(OPT_ALL & ~OPT_BOURNE)
64#define OPT_NONZSH	(OPT_ALL & ~OPT_ZSH)
65
66/* option is relevant to emulation */
67#define OPT_EMULATE	(EMULATE_UNUSED)
68/* option should never be set by emulate() */
69#define OPT_SPECIAL	(EMULATE_UNUSED<<1)
70/* option is an alias to an other option */
71#define OPT_ALIAS	(EMULATE_UNUSED<<2)
72
73#define defset(X, my_emulation) (!!((X)->node.flags & my_emulation))
74
75/*
76 * Note that option names should usually be fewer than 20 characters long
77 * to avoid formatting problems.
78 */
79static struct optname optns[] = {
80{{NULL, "aliases",	      OPT_EMULATE|OPT_ALL},	 ALIASESOPT},
81{{NULL, "allexport",	      OPT_EMULATE},		 ALLEXPORT},
82{{NULL, "alwayslastprompt",   OPT_ALL},			 ALWAYSLASTPROMPT},
83{{NULL, "alwaystoend",	      0},			 ALWAYSTOEND},
84{{NULL, "appendhistory",      OPT_ALL},			 APPENDHISTORY},
85{{NULL, "autocd",	      OPT_EMULATE},		 AUTOCD},
86{{NULL, "autocontinue",	      0},			 AUTOCONTINUE},
87{{NULL, "autolist",	      OPT_ALL},			 AUTOLIST},
88{{NULL, "automenu",	      OPT_ALL},			 AUTOMENU},
89{{NULL, "autonamedirs",	      0},			 AUTONAMEDIRS},
90{{NULL, "autoparamkeys",      OPT_ALL},			 AUTOPARAMKEYS},
91{{NULL, "autoparamslash",     OPT_ALL},			 AUTOPARAMSLASH},
92{{NULL, "autopushd",	      0},			 AUTOPUSHD},
93{{NULL, "autoremoveslash",    OPT_ALL},			 AUTOREMOVESLASH},
94{{NULL, "autoresume",	      0},			 AUTORESUME},
95{{NULL, "badpattern",	      OPT_EMULATE|OPT_NONBOURNE},BADPATTERN},
96{{NULL, "banghist",	      OPT_NONBOURNE},		 BANGHIST},
97{{NULL, "bareglobqual",       OPT_EMULATE|OPT_ZSH},      BAREGLOBQUAL},
98{{NULL, "bashautolist",	      0},                        BASHAUTOLIST},
99{{NULL, "bashrematch",	      0},			 BASHREMATCH},
100{{NULL, "beep",		      OPT_ALL},			 BEEP},
101{{NULL, "bgnice",	      OPT_EMULATE|OPT_NONBOURNE},BGNICE},
102{{NULL, "braceccl",	      OPT_EMULATE},		 BRACECCL},
103{{NULL, "bsdecho",	      OPT_EMULATE|OPT_SH},	 BSDECHO},
104{{NULL, "caseglob",	      OPT_ALL},			 CASEGLOB},
105{{NULL, "casematch",	      OPT_ALL},			 CASEMATCH},
106{{NULL, "cbases",	      0},			 CBASES},
107{{NULL, "cprecedences",	      OPT_EMULATE|OPT_NONZSH},	 CPRECEDENCES},
108{{NULL, "cdablevars",	      OPT_EMULATE},		 CDABLEVARS},
109{{NULL, "chasedots",	      OPT_EMULATE},		 CHASEDOTS},
110{{NULL, "chaselinks",	      OPT_EMULATE},		 CHASELINKS},
111{{NULL, "checkjobs",	      OPT_EMULATE|OPT_ZSH},	 CHECKJOBS},
112{{NULL, "clobber",	      OPT_EMULATE|OPT_ALL},	 CLOBBER},
113{{NULL, "combiningchars",     0},			 COMBININGCHARS},
114{{NULL, "completealiases",    0},			 COMPLETEALIASES},
115{{NULL, "completeinword",     0},			 COMPLETEINWORD},
116{{NULL, "continueonerror",    0},                        CONTINUEONERROR},
117{{NULL, "correct",	      0},			 CORRECT},
118{{NULL, "correctall",	      0},			 CORRECTALL},
119{{NULL, "cshjunkiehistory",   OPT_EMULATE|OPT_CSH},	 CSHJUNKIEHISTORY},
120{{NULL, "cshjunkieloops",     OPT_EMULATE|OPT_CSH},	 CSHJUNKIELOOPS},
121{{NULL, "cshjunkiequotes",    OPT_EMULATE|OPT_CSH},	 CSHJUNKIEQUOTES},
122{{NULL, "cshnullcmd",	      OPT_EMULATE|OPT_CSH},	 CSHNULLCMD},
123{{NULL, "cshnullglob",	      OPT_EMULATE|OPT_CSH},	 CSHNULLGLOB},
124{{NULL, "debugbeforecmd",     OPT_ALL},			 DEBUGBEFORECMD},
125{{NULL, "emacs",	      0},			 EMACSMODE},
126{{NULL, "equals",	      OPT_EMULATE|OPT_ZSH},	 EQUALS},
127{{NULL, "errexit",	      OPT_EMULATE},		 ERREXIT},
128{{NULL, "errreturn",	      OPT_EMULATE},		 ERRRETURN},
129{{NULL, "exec",		      OPT_ALL},			 EXECOPT},
130{{NULL, "extendedglob",	      OPT_EMULATE},		 EXTENDEDGLOB},
131{{NULL, "extendedhistory",    OPT_CSH},			 EXTENDEDHISTORY},
132{{NULL, "evallineno",	      OPT_EMULATE|OPT_ZSH},	 EVALLINENO},
133{{NULL, "flowcontrol",	      OPT_ALL},			 FLOWCONTROL},
134{{NULL, "functionargzero",    OPT_EMULATE|OPT_NONBOURNE},FUNCTIONARGZERO},
135{{NULL, "glob",		      OPT_EMULATE|OPT_ALL},	 GLOBOPT},
136{{NULL, "globalexport",       OPT_EMULATE|OPT_ZSH},	 GLOBALEXPORT},
137{{NULL, "globalrcs",          OPT_ALL},			 GLOBALRCS},
138{{NULL, "globassign",	      OPT_EMULATE|OPT_CSH},	 GLOBASSIGN},
139{{NULL, "globcomplete",	      0},			 GLOBCOMPLETE},
140{{NULL, "globdots",	      OPT_EMULATE},		 GLOBDOTS},
141{{NULL, "globsubst",	      OPT_EMULATE|OPT_NONZSH},	 GLOBSUBST},
142{{NULL, "hashcmds",	      OPT_ALL},			 HASHCMDS},
143{{NULL, "hashdirs",	      OPT_ALL},			 HASHDIRS},
144{{NULL, "hashexecutablesonly", 0},                       HASHEXECUTABLESONLY},
145{{NULL, "hashlistall",	      OPT_ALL},			 HASHLISTALL},
146{{NULL, "histallowclobber",   0},			 HISTALLOWCLOBBER},
147{{NULL, "histbeep",	      OPT_ALL},			 HISTBEEP},
148{{NULL, "histexpiredupsfirst",0},			 HISTEXPIREDUPSFIRST},
149{{NULL, "histfcntllock",      0},			 HISTFCNTLLOCK},
150{{NULL, "histfindnodups",     0},			 HISTFINDNODUPS},
151{{NULL, "histignorealldups",  0},			 HISTIGNOREALLDUPS},
152{{NULL, "histignoredups",     0},			 HISTIGNOREDUPS},
153{{NULL, "histignorespace",    0},			 HISTIGNORESPACE},
154{{NULL, "histlexwords",	      0},			 HISTLEXWORDS},
155{{NULL, "histnofunctions",    0},			 HISTNOFUNCTIONS},
156{{NULL, "histnostore",	      0},			 HISTNOSTORE},
157{{NULL, "histsubstpattern",   OPT_EMULATE},              HISTSUBSTPATTERN},
158{{NULL, "histreduceblanks",   0},			 HISTREDUCEBLANKS},
159{{NULL, "histsavebycopy",     OPT_ALL},			 HISTSAVEBYCOPY},
160{{NULL, "histsavenodups",     0},			 HISTSAVENODUPS},
161{{NULL, "histverify",	      0},			 HISTVERIFY},
162{{NULL, "hup",		      OPT_EMULATE|OPT_ZSH},	 HUP},
163{{NULL, "ignorebraces",	      OPT_EMULATE|OPT_SH},	 IGNOREBRACES},
164{{NULL, "ignoreclosebraces",  OPT_EMULATE},		 IGNORECLOSEBRACES},
165{{NULL, "ignoreeof",	      0},			 IGNOREEOF},
166{{NULL, "incappendhistory",   0},			 INCAPPENDHISTORY},
167{{NULL, "interactive",	      OPT_SPECIAL},		 INTERACTIVE},
168{{NULL, "interactivecomments",OPT_BOURNE},		 INTERACTIVECOMMENTS},
169{{NULL, "ksharrays",	      OPT_EMULATE|OPT_BOURNE},	 KSHARRAYS},
170{{NULL, "kshautoload",	      OPT_EMULATE|OPT_BOURNE},	 KSHAUTOLOAD},
171{{NULL, "kshglob",	      OPT_EMULATE|OPT_KSH},	 KSHGLOB},
172{{NULL, "kshoptionprint",     OPT_EMULATE|OPT_KSH},	 KSHOPTIONPRINT},
173{{NULL, "kshtypeset",	      OPT_EMULATE|OPT_KSH},	 KSHTYPESET},
174{{NULL, "kshzerosubscript",   0},			 KSHZEROSUBSCRIPT},
175{{NULL, "listambiguous",      OPT_ALL},			 LISTAMBIGUOUS},
176{{NULL, "listbeep",	      OPT_ALL},			 LISTBEEP},
177{{NULL, "listpacked",	      0},			 LISTPACKED},
178{{NULL, "listrowsfirst",      0},			 LISTROWSFIRST},
179{{NULL, "listtypes",	      OPT_ALL},			 LISTTYPES},
180{{NULL, "localoptions",	      OPT_EMULATE|OPT_KSH},	 LOCALOPTIONS},
181{{NULL, "localtraps",	      OPT_EMULATE|OPT_KSH},	 LOCALTRAPS},
182{{NULL, "login",	      OPT_SPECIAL},		 LOGINSHELL},
183{{NULL, "longlistjobs",	      0},			 LONGLISTJOBS},
184{{NULL, "magicequalsubst",    OPT_EMULATE},		 MAGICEQUALSUBST},
185{{NULL, "mailwarning",	      0},			 MAILWARNING},
186{{NULL, "markdirs",	      0},			 MARKDIRS},
187{{NULL, "menucomplete",	      0},			 MENUCOMPLETE},
188{{NULL, "monitor",	      OPT_SPECIAL},		 MONITOR},
189{{NULL, "multibyte",
190#ifdef MULTIBYTE_SUPPORT
191			      OPT_EMULATE|OPT_ZSH|OPT_CSH|OPT_KSH
192#else
193			      0
194#endif
195			      },			 MULTIBYTE},
196{{NULL, "multifuncdef",	      OPT_EMULATE|OPT_ZSH},	 MULTIFUNCDEF},
197{{NULL, "multios",	      OPT_EMULATE|OPT_ZSH},	 MULTIOS},
198{{NULL, "nomatch",	      OPT_EMULATE|OPT_NONBOURNE},NOMATCH},
199{{NULL, "notify",	      OPT_ZSH},			 NOTIFY},
200{{NULL, "nullglob",	      OPT_EMULATE},		 NULLGLOB},
201{{NULL, "numericglobsort",    OPT_EMULATE},		 NUMERICGLOBSORT},
202{{NULL, "octalzeroes",        OPT_EMULATE|OPT_SH},	 OCTALZEROES},
203{{NULL, "overstrike",	      0},			 OVERSTRIKE},
204{{NULL, "pathdirs",	      OPT_EMULATE},		 PATHDIRS},
205{{NULL, "pathscript",	      OPT_EMULATE|OPT_BOURNE},	 PATHSCRIPT},
206{{NULL, "posixaliases",       OPT_EMULATE|OPT_BOURNE},	 POSIXALIASES},
207{{NULL, "posixbuiltins",      OPT_EMULATE|OPT_BOURNE},	 POSIXBUILTINS},
208{{NULL, "posixcd",            OPT_EMULATE|OPT_BOURNE},	 POSIXCD},
209{{NULL, "posixidentifiers",   OPT_EMULATE|OPT_BOURNE},	 POSIXIDENTIFIERS},
210{{NULL, "posixjobs",          OPT_EMULATE|OPT_BOURNE},	 POSIXJOBS},
211{{NULL, "posixstrings",       OPT_EMULATE|OPT_BOURNE},   POSIXSTRINGS},
212{{NULL, "posixtraps",         OPT_EMULATE|OPT_BOURNE},	 POSIXTRAPS},
213{{NULL, "printeightbit",      0},                        PRINTEIGHTBIT},
214{{NULL, "printexitvalue",     0},			 PRINTEXITVALUE},
215{{NULL, "privileged",	      OPT_SPECIAL},		 PRIVILEGED},
216{{NULL, "promptbang",	      OPT_KSH},			 PROMPTBANG},
217{{NULL, "promptcr",	      OPT_ALL},			 PROMPTCR},
218{{NULL, "promptpercent",      OPT_NONBOURNE},		 PROMPTPERCENT},
219{{NULL, "promptsp",	      OPT_ALL},			 PROMPTSP},
220{{NULL, "promptsubst",	      OPT_BOURNE},		 PROMPTSUBST},
221{{NULL, "pushdignoredups",    OPT_EMULATE},		 PUSHDIGNOREDUPS},
222{{NULL, "pushdminus",	      OPT_EMULATE},		 PUSHDMINUS},
223{{NULL, "pushdsilent",	      0},			 PUSHDSILENT},
224{{NULL, "pushdtohome",	      OPT_EMULATE},		 PUSHDTOHOME},
225{{NULL, "rcexpandparam",      OPT_EMULATE},		 RCEXPANDPARAM},
226{{NULL, "rcquotes",	      OPT_EMULATE},		 RCQUOTES},
227{{NULL, "rcs",		      OPT_ALL},			 RCS},
228{{NULL, "recexact",	      0},			 RECEXACT},
229{{NULL, "rematchpcre",	      0},			 REMATCHPCRE},
230{{NULL, "restricted",	      OPT_SPECIAL},		 RESTRICTED},
231{{NULL, "rmstarsilent",	      OPT_BOURNE},		 RMSTARSILENT},
232{{NULL, "rmstarwait",	      0},			 RMSTARWAIT},
233{{NULL, "sharehistory",	      OPT_KSH},			 SHAREHISTORY},
234{{NULL, "shfileexpansion",    OPT_EMULATE|OPT_BOURNE},	 SHFILEEXPANSION},
235{{NULL, "shglob",	      OPT_EMULATE|OPT_BOURNE},	 SHGLOB},
236{{NULL, "shinstdin",	      OPT_SPECIAL},		 SHINSTDIN},
237{{NULL, "shnullcmd",          OPT_EMULATE|OPT_BOURNE},	 SHNULLCMD},
238{{NULL, "shoptionletters",    OPT_EMULATE|OPT_BOURNE},	 SHOPTIONLETTERS},
239{{NULL, "shortloops",	      OPT_EMULATE|OPT_NONBOURNE},SHORTLOOPS},
240{{NULL, "shwordsplit",	      OPT_EMULATE|OPT_BOURNE},	 SHWORDSPLIT},
241{{NULL, "singlecommand",      OPT_SPECIAL},		 SINGLECOMMAND},
242{{NULL, "singlelinezle",      OPT_KSH},			 SINGLELINEZLE},
243{{NULL, "sourcetrace",        0},			 SOURCETRACE},
244{{NULL, "sunkeyboardhack",    0},			 SUNKEYBOARDHACK},
245{{NULL, "transientrprompt",   0},			 TRANSIENTRPROMPT},
246{{NULL, "trapsasync",	      0},			 TRAPSASYNC},
247{{NULL, "typesetsilent",      OPT_EMULATE|OPT_BOURNE},	 TYPESETSILENT},
248{{NULL, "unset",	      OPT_EMULATE|OPT_BSHELL},	 UNSET},
249{{NULL, "verbose",	      0},			 VERBOSE},
250{{NULL, "vi",		      0},			 VIMODE},
251{{NULL, "warncreateglobal",   0},			 WARNCREATEGLOBAL},
252{{NULL, "xtrace",	      0},			 XTRACE},
253{{NULL, "zle",		      OPT_SPECIAL},		 USEZLE},
254{{NULL, "braceexpand",	      OPT_ALIAS}, /* ksh/bash */ -IGNOREBRACES},
255{{NULL, "dotglob",	      OPT_ALIAS}, /* bash */	 GLOBDOTS},
256{{NULL, "hashall",	      OPT_ALIAS}, /* bash */	 HASHCMDS},
257{{NULL, "histappend",	      OPT_ALIAS}, /* bash */	 APPENDHISTORY},
258{{NULL, "histexpand",	      OPT_ALIAS}, /* bash */	 BANGHIST},
259{{NULL, "log",		      OPT_ALIAS}, /* ksh */	 -HISTNOFUNCTIONS},
260{{NULL, "mailwarn",	      OPT_ALIAS}, /* bash */	 MAILWARNING},
261{{NULL, "onecmd",	      OPT_ALIAS}, /* bash */	 SINGLECOMMAND},
262{{NULL, "physical",	      OPT_ALIAS}, /* ksh/bash */ CHASELINKS},
263{{NULL, "promptvars",	      OPT_ALIAS}, /* bash */	 PROMPTSUBST},
264{{NULL, "stdin",	      OPT_ALIAS}, /* ksh */	 SHINSTDIN},
265{{NULL, "trackall",	      OPT_ALIAS}, /* ksh */	 HASHCMDS},
266{{NULL, "dvorak",	      0},			 DVORAK},
267{{NULL, NULL, 0}, 0}
268};
269
270/* Option letters */
271
272#define optletters (isset(SHOPTIONLETTERS) ? kshletters : zshletters)
273
274#define FIRST_OPT '0'
275#define LAST_OPT 'y'
276
277static short zshletters[LAST_OPT - FIRST_OPT + 1] = {
278    /* 0 */  CORRECT,
279    /* 1 */  PRINTEXITVALUE,
280    /* 2 */ -BADPATTERN,
281    /* 3 */ -NOMATCH,
282    /* 4 */  GLOBDOTS,
283    /* 5 */  NOTIFY,
284    /* 6 */  BGNICE,
285    /* 7 */  IGNOREEOF,
286    /* 8 */  MARKDIRS,
287    /* 9 */  AUTOLIST,
288    /* : */  0,
289    /* ; */  0,
290    /* < */  0,
291    /* = */  0,
292    /* > */  0,
293    /* ? */  0,
294    /* @ */  0,
295    /* A */  0,			/* use with set for arrays */
296    /* B */ -BEEP,
297    /* C */ -CLOBBER,
298    /* D */  PUSHDTOHOME,
299    /* E */  PUSHDSILENT,
300    /* F */ -GLOBOPT,
301    /* G */  NULLGLOB,
302    /* H */  RMSTARSILENT,
303    /* I */  IGNOREBRACES,
304    /* J */  AUTOCD,
305    /* K */ -BANGHIST,
306    /* L */  SUNKEYBOARDHACK,
307    /* M */  SINGLELINEZLE,
308    /* N */  AUTOPUSHD,
309    /* O */  CORRECTALL,
310    /* P */  RCEXPANDPARAM,
311    /* Q */  PATHDIRS,
312    /* R */  LONGLISTJOBS,
313    /* S */  RECEXACT,
314    /* T */  CDABLEVARS,
315    /* U */  MAILWARNING,
316    /* V */ -PROMPTCR,
317    /* W */  AUTORESUME,
318    /* X */  LISTTYPES,
319    /* Y */  MENUCOMPLETE,
320    /* Z */  USEZLE,
321    /* [ */  0,
322    /* \ */  0,
323    /* ] */  0,
324    /* ^ */  0,
325    /* _ */  0,
326    /* ` */  0,
327    /* a */  ALLEXPORT,
328    /* b */  0,			/* in non-Bourne shells, end of options */
329    /* c */  0,			/* command follows */
330    /* d */ -GLOBALRCS,
331    /* e */  ERREXIT,
332    /* f */ -RCS,
333    /* g */  HISTIGNORESPACE,
334    /* h */  HISTIGNOREDUPS,
335    /* i */  INTERACTIVE,
336    /* j */  0,
337    /* k */  INTERACTIVECOMMENTS,
338    /* l */  LOGINSHELL,
339    /* m */  MONITOR,
340    /* n */ -EXECOPT,
341    /* o */  0,			/* long option name follows */
342    /* p */  PRIVILEGED,
343    /* q */  0,
344    /* r */  RESTRICTED,
345    /* s */  SHINSTDIN,
346    /* t */  SINGLECOMMAND,
347    /* u */ -UNSET,
348    /* v */  VERBOSE,
349    /* w */  CHASELINKS,
350    /* x */  XTRACE,
351    /* y */  SHWORDSPLIT,
352};
353
354static short kshletters[LAST_OPT - FIRST_OPT + 1] = {
355    /* 0 */  0,
356    /* 1 */  0,
357    /* 2 */  0,
358    /* 3 */  0,
359    /* 4 */  0,
360    /* 5 */  0,
361    /* 6 */  0,
362    /* 7 */  0,
363    /* 8 */  0,
364    /* 9 */  0,
365    /* : */  0,
366    /* ; */  0,
367    /* < */  0,
368    /* = */  0,
369    /* > */  0,
370    /* ? */  0,
371    /* @ */  0,
372    /* A */  0,
373    /* B */  0,
374    /* C */ -CLOBBER,
375    /* D */  0,
376    /* E */  0,
377    /* F */  0,
378    /* G */  0,
379    /* H */  0,
380    /* I */  0,
381    /* J */  0,
382    /* K */  0,
383    /* L */  0,
384    /* M */  0,
385    /* N */  0,
386    /* O */  0,
387    /* P */  0,
388    /* Q */  0,
389    /* R */  0,
390    /* S */  0,
391    /* T */  TRAPSASYNC,
392    /* U */  0,
393    /* V */  0,
394    /* W */  0,
395    /* X */  MARKDIRS,
396    /* Y */  0,
397    /* Z */  0,
398    /* [ */  0,
399    /* \ */  0,
400    /* ] */  0,
401    /* ^ */  0,
402    /* _ */  0,
403    /* ` */  0,
404    /* a */  ALLEXPORT,
405    /* b */  NOTIFY,
406    /* c */  0,
407    /* d */  0,
408    /* e */  ERREXIT,
409    /* f */ -GLOBOPT,
410    /* g */  0,
411    /* h */  0,
412    /* i */  INTERACTIVE,
413    /* j */  0,
414    /* k */  0,
415    /* l */  LOGINSHELL,
416    /* m */  MONITOR,
417    /* n */ -EXECOPT,
418    /* o */  0,
419    /* p */  PRIVILEGED,
420    /* q */  0,
421    /* r */  RESTRICTED,
422    /* s */  SHINSTDIN,
423    /* t */  SINGLECOMMAND,
424    /* u */ -UNSET,
425    /* v */  VERBOSE,
426    /* w */  0,
427    /* x */  XTRACE,
428    /* y */  0,
429};
430
431/* Initialisation of the option name hash table */
432
433/**/
434static void
435printoptionnode(HashNode hn, int set)
436{
437    Optname on = (Optname) hn;
438    int optno = on->optno;
439
440    if (optno < 0)
441	optno = -optno;
442    if (isset(KSHOPTIONPRINT)) {
443	if (defset(on, emulation))
444	    printf("no%-19s %s\n", on->node.nam, isset(optno) ? "off" : "on");
445	else
446	    printf("%-21s %s\n", on->node.nam, isset(optno) ? "on" : "off");
447    } else if (set == (isset(optno) ^ defset(on, emulation))) {
448	if (set ^ isset(optno))
449	    fputs("no", stdout);
450	puts(on->node.nam);
451    }
452}
453
454/**/
455void
456createoptiontable(void)
457{
458    Optname on;
459
460    optiontab = newhashtable(101, "optiontab", NULL);
461
462    optiontab->hash        = hasher;
463    optiontab->emptytable  = NULL;
464    optiontab->filltable   = NULL;
465    optiontab->cmpnodes    = strcmp;
466    optiontab->addnode     = addhashnode;
467    optiontab->getnode     = gethashnode;
468    optiontab->getnode2    = gethashnode2;
469    optiontab->removenode  = NULL;
470    optiontab->disablenode = disablehashnode;
471    optiontab->enablenode  = enablehashnode;
472    optiontab->freenode    = NULL;
473    optiontab->printnode   = printoptionnode;
474
475    for (on = optns; on->node.nam; on++)
476	optiontab->addnode(optiontab, on->node.nam, on);
477}
478
479/* Emulation appropriate to the setemulate function */
480
481static int setemulate_emulation;
482
483/* Option array manipulated within the setemulate function */
484
485/**/
486static char *setemulate_opts;
487
488/* Setting of default options */
489
490/**/
491static void
492setemulate(HashNode hn, int fully)
493{
494    Optname on = (Optname) hn;
495
496    /* Set options: each non-special option is set according to the *
497     * current emulation mode if either it is considered relevant   *
498     * to emulation or we are doing a full emulation (as indicated  *
499     * by the `fully' parameter).                                   */
500    if (!(on->node.flags & OPT_ALIAS) &&
501	((fully && !(on->node.flags & OPT_SPECIAL)) ||
502	 (on->node.flags & OPT_EMULATE)))
503	setemulate_opts[on->optno] = defset(on, setemulate_emulation);
504}
505
506/**/
507void
508installemulation(int new_emulation, char *new_opts)
509{
510    setemulate_emulation = new_emulation;
511    setemulate_opts = new_opts;
512    scanhashtable(optiontab, 0, 0, 0, setemulate,
513		  !!(new_emulation & EMULATE_FULLY));
514}
515
516/**/
517void
518emulate(const char *zsh_name, int fully, int *new_emulation, char *new_opts)
519{
520    char ch = *zsh_name;
521
522    if (ch == 'r')
523	ch = zsh_name[1];
524
525    /* Work out the new emulation mode */
526    if (ch == 'c')
527	*new_emulation = EMULATE_CSH;
528    else if (ch == 'k')
529	*new_emulation = EMULATE_KSH;
530    else if (ch == 's' || ch == 'b')
531	*new_emulation = EMULATE_SH;
532    else
533	*new_emulation = EMULATE_ZSH;
534
535    if (fully)
536	*new_emulation |= EMULATE_FULLY;
537    installemulation(*new_emulation, new_opts);
538
539    if (funcstack && funcstack->tp == FS_FUNC) {
540	/*
541	 * We are inside a function.  Decide if it's traced.
542	 * Pedantic note: the function in the function table isn't
543	 * guaranteed to be what we're executing, but it's
544	 * close enough.
545	 */
546	Shfunc shf = (Shfunc)shfunctab->getnode(shfunctab, funcstack->name);
547	if (shf && (shf->node.flags & (PM_TAGGED|PM_TAGGED_LOCAL))) {
548	    /* Tracing is on, so set xtrace */
549	    new_opts[XTRACE] = 1;
550	}
551    }
552}
553
554/* setopt, unsetopt */
555
556/**/
557static void
558setoption(HashNode hn, int value)
559{
560    dosetopt(((Optname) hn)->optno, value, 0, opts);
561}
562
563/**/
564int
565bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun)
566{
567    int action, optno, match = 0;
568
569    /* With no arguments or options, display options. */
570    if (!*args) {
571	scanhashtable(optiontab, 1, 0, OPT_ALIAS, optiontab->printnode, !isun);
572	return 0;
573    }
574
575    /* loop through command line options (begins with "-" or "+") */
576    while (*args && (**args == '-' || **args == '+')) {
577	action = (**args == '-') ^ isun;
578	if(!args[0][1])
579	    *args = "--";
580	while (*++*args) {
581	    if(**args == Meta)
582		*++*args ^= 32;
583	    /* The pseudo-option `--' signifies the end of options. */
584	    if (**args == '-') {
585		args++;
586		goto doneoptions;
587	    } else if (**args == 'o') {
588		if (!*++*args)
589		    args++;
590		if (!*args) {
591		    zwarnnam(nam, "string expected after -o");
592		    inittyptab();
593		    return 1;
594		}
595		if(!(optno = optlookup(*args)))
596		    zwarnnam(nam, "no such option: %s", *args);
597		else if(dosetopt(optno, action, 0, opts))
598		    zwarnnam(nam, "can't change option: %s", *args);
599		break;
600	    } else if(**args == 'm') {
601		match = 1;
602	    } else {
603	    	if (!(optno = optlookupc(**args)))
604		    zwarnnam(nam, "bad option: -%c", **args);
605		else if(dosetopt(optno, action, 0, opts))
606		    zwarnnam(nam, "can't change option: -%c", **args);
607	    }
608	}
609	args++;
610    }
611    doneoptions:
612
613    if (!match) {
614	/* Not globbing the arguments -- arguments are simply option names. */
615	while (*args) {
616	    if(!(optno = optlookup(*args++)))
617		zwarnnam(nam, "no such option: %s", args[-1]);
618	    else if(dosetopt(optno, !isun, 0, opts))
619		zwarnnam(nam, "can't change option: %s", args[-1]);
620	}
621    } else {
622	/* Globbing option (-m) set. */
623	while (*args) {
624	    Patprog pprog;
625	    char *s, *t;
626
627	    t = s = dupstring(*args);
628	    while (*t)
629		if (*t == '_')
630		    chuck(t);
631		else {
632		    /* See comment in optlookup() */
633		    if (*t >= 'A' && *t <= 'Z')
634			*t = (*t - 'A') + 'a';
635		    t++;
636		}
637
638	    /* Expand the current arg. */
639	    tokenize(s);
640	    if (!(pprog = patcompile(s, PAT_STATIC, NULL))) {
641		zwarnnam(nam, "bad pattern: %s", *args);
642		continue;
643	    }
644	    /* Loop over expansions. */
645	    scanmatchtable(optiontab, pprog, 0, 0, OPT_ALIAS,
646			   setoption, !isun);
647	    args++;
648	}
649    }
650    inittyptab();
651    return 0;
652}
653
654/* Identify an option name */
655
656/**/
657mod_export int
658optlookup(char const *name)
659{
660    char *s, *t;
661    Optname n;
662
663    s = t = dupstring(name);
664
665    /* exorcise underscores, and change to lowercase */
666    while (*t)
667	if (*t == '_')
668	    chuck(t);
669	else {
670	    /*
671	     * Some locales (in particular tr_TR.UTF-8) may
672	     * have non-standard mappings of ASCII characters,
673	     * so be careful.  Option names must be ASCII so
674	     * we don't need to be too clever.
675	     */
676	    if (*t >= 'A' && *t <= 'Z')
677		*t = (*t - 'A') + 'a';
678	    t++;
679	}
680
681    /* look up name in the table */
682    if (s[0] == 'n' && s[1] == 'o' &&
683	(n = (Optname) optiontab->getnode(optiontab, s + 2))) {
684	return -n->optno;
685    } else if ((n = (Optname) optiontab->getnode(optiontab, s)))
686	return n->optno;
687    else
688	return OPT_INVALID;
689}
690
691/* Identify an option letter */
692
693/**/
694int
695optlookupc(char c)
696{
697    if(c < FIRST_OPT || c > LAST_OPT)
698	return 0;
699
700    return optletters[c - FIRST_OPT];
701}
702
703/**/
704static void
705restrictparam(char *nam)
706{
707    Param pm = (Param) paramtab->getnode(paramtab, nam);
708
709    if (pm) {
710	pm->node.flags |= PM_SPECIAL | PM_RESTRICTED;
711	return;
712    }
713    createparam(nam, PM_SCALAR | PM_UNSET | PM_SPECIAL | PM_RESTRICTED);
714}
715
716/* list of restricted parameters which are not otherwise special */
717static char *rparams[] = {
718    "SHELL", "HISTFILE", "LD_LIBRARY_PATH", "LD_AOUT_LIBRARY_PATH",
719    "LD_PRELOAD", "LD_AOUT_PRELOAD", NULL
720};
721
722/* Set or unset an option, as a result of user request.  The option *
723 * number may be negative, indicating that the sense is reversed    *
724 * from the usual meaning of the option.                            */
725
726/**/
727mod_export int
728dosetopt(int optno, int value, int force, char *new_opts)
729{
730    if(!optno)
731	return -1;
732    if(optno < 0) {
733	optno = -optno;
734	value = !value;
735    }
736    if (optno == RESTRICTED) {
737	if (isset(RESTRICTED))
738	    return value ? 0 : -1;
739	if (value) {
740	    char **s;
741
742	    for (s = rparams; *s; s++)
743		restrictparam(*s);
744	}
745    } else if(!force && optno == EXECOPT && !value && interact) {
746	/* cannot set noexec when interactive */
747	return -1;
748    } else if(!force && (optno == INTERACTIVE || optno == SHINSTDIN ||
749	    optno == SINGLECOMMAND)) {
750	if (new_opts[optno] == value)
751	    return 0;
752	/* it is not permitted to change the value of these options */
753	return -1;
754    } else if(!force && optno == USEZLE && value) {
755	/* we require a terminal in order to use ZLE */
756	if(!interact || SHTTY == -1 || !shout)
757	    return -1;
758    } else if(optno == PRIVILEGED && !value) {
759	/* unsetting PRIVILEGED causes the shell to make itself unprivileged */
760#ifdef HAVE_SETUID
761	setuid(getuid());
762	setgid(getgid());
763#endif /* HAVE_SETUID */
764#ifdef JOB_CONTROL
765    } else if (!force && optno == MONITOR && value) {
766	if (new_opts[optno] == value)
767	    return 0;
768	if (SHTTY != -1) {
769	    origpgrp = GETPGRP();
770	    acquire_pgrp();
771	} else
772	    return -1;
773#else
774    } else if(optno == MONITOR && value) {
775	    return -1;
776#endif /* not JOB_CONTROL */
777#ifdef GETPWNAM_FAKED
778    } else if(optno == CDABLEVARS && value) {
779	    return -1;
780#endif /* GETPWNAM_FAKED */
781    } else if ((optno == EMACSMODE || optno == VIMODE) && value) {
782	if (sticky && sticky->emulation)
783	    return -1;
784	zleentry(ZLE_CMD_SET_KEYMAP, optno);
785	new_opts[(optno == EMACSMODE) ? VIMODE : EMACSMODE] = 0;
786    } else if (optno == SUNKEYBOARDHACK) {
787	/* for backward compatibility */
788	keyboardhackchar = (value ? '`' : '\0');
789    }
790    new_opts[optno] = value;
791    if (optno == BANGHIST || optno == SHINSTDIN)
792	inittyptab();
793    return 0;
794}
795
796/* Function to get value for special parameter `-' */
797
798/**/
799char *
800dashgetfn(UNUSED(Param pm))
801{
802    static char buf[LAST_OPT - FIRST_OPT + 2];
803    char *val = buf;
804    int i;
805
806    for(i = 0; i <= LAST_OPT - FIRST_OPT; i++) {
807	int optno = optletters[i];
808	if(optno && ((optno > 0) ? isset(optno) : unset(-optno)))
809	    *val++ = FIRST_OPT + i;
810    }
811    *val = '\0';
812    return buf;
813}
814
815/* print options for set -o/+o */
816
817/**/
818void
819printoptionstates(int hadplus)
820{
821    scanhashtable(optiontab, 1, 0, OPT_ALIAS, printoptionnodestate, hadplus);
822}
823
824/**/
825static void
826printoptionnodestate(HashNode hn, int hadplus)
827{
828    Optname on = (Optname) hn;
829    int optno = on->optno;
830
831    if (hadplus) {
832        if (defset(on, emulation) != isset(optno))
833	    printf("set -o %s%s\n", defset(on, emulation) ?
834		   "no" : "", on->node.nam);
835    } else {
836	if (defset(on, emulation))
837	    printf("no%-19s %s\n", on->node.nam, isset(optno) ? "off" : "on");
838	else
839	    printf("%-21s %s\n", on->node.nam, isset(optno) ? "on" : "off");
840    }
841}
842
843/* Print option list for --help */
844
845/**/
846void
847printoptionlist(void)
848{
849    short *lp;
850    char c;
851
852    printf("\nNamed options:\n");
853    scanhashtable(optiontab, 1, 0, OPT_ALIAS, printoptionlist_printoption, 0);
854    printf("\nOption aliases:\n");
855    scanhashtable(optiontab, 1, OPT_ALIAS, 0, printoptionlist_printoption, 0);
856    printf("\nOption letters:\n");
857    for(lp = optletters, c = FIRST_OPT; c <= LAST_OPT; lp++, c++) {
858	if(!*lp)
859	    continue;
860	printf("  -%c  ", c);
861	printoptionlist_printequiv(*lp);
862    }
863}
864
865/**/
866static void
867printoptionlist_printoption(HashNode hn, UNUSED(int ignored))
868{
869    Optname on = (Optname) hn;
870
871    if(on->node.flags & OPT_ALIAS) {
872	printf("  --%-19s  ", on->node.nam);
873	printoptionlist_printequiv(on->optno);
874    } else
875	printf("  --%s\n", on->node.nam);
876}
877
878/**/
879static void
880printoptionlist_printequiv(int optno)
881{
882    int isneg = optno < 0;
883
884    optno *= (isneg ? -1 : 1);
885    printf("  equivalent to --%s%s\n", isneg ? "no-" : "", optns[optno-1].node.nam);
886}
887