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