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 /**/
36 mod_export int emulation;
37
38 /* current sticky emulation: sticky = NULL means none */
39
40 /**/
41 mod_export Emulation_options sticky;
42
43 /* the options; e.g. if opts[SHGLOB] != 0, SH_GLOB is turned on */
44
45 /**/
46 mod_export char opts[OPT_SIZE];
47
48 /* Option name hash table */
49
50 /**/
51 mod_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 */
79 static struct optname optns[] = {
80 {{NULL, "aliases", OPT_EMULATE|OPT_ALL}, ALIASESOPT},
81 {{NULL, "aliasfuncdef", OPT_EMULATE|OPT_BOURNE}, ALIASFUNCDEF},
82 {{NULL, "allexport", OPT_EMULATE}, ALLEXPORT},
83 {{NULL, "alwayslastprompt", OPT_ALL}, ALWAYSLASTPROMPT},
84 {{NULL, "alwaystoend", 0}, ALWAYSTOEND},
85 {{NULL, "appendcreate", OPT_EMULATE|OPT_BOURNE}, APPENDCREATE},
86 {{NULL, "appendhistory", OPT_ALL}, APPENDHISTORY},
87 {{NULL, "autocd", OPT_EMULATE}, AUTOCD},
88 {{NULL, "autocontinue", 0}, AUTOCONTINUE},
89 {{NULL, "autolist", OPT_ALL}, AUTOLIST},
90 {{NULL, "automenu", OPT_ALL}, AUTOMENU},
91 {{NULL, "autonamedirs", 0}, AUTONAMEDIRS},
92 {{NULL, "autoparamkeys", OPT_ALL}, AUTOPARAMKEYS},
93 {{NULL, "autoparamslash", OPT_ALL}, AUTOPARAMSLASH},
94 {{NULL, "autopushd", 0}, AUTOPUSHD},
95 {{NULL, "autoremoveslash", OPT_ALL}, AUTOREMOVESLASH},
96 {{NULL, "autoresume", 0}, AUTORESUME},
97 {{NULL, "badpattern", OPT_EMULATE|OPT_NONBOURNE},BADPATTERN},
98 {{NULL, "banghist", OPT_NONBOURNE}, BANGHIST},
99 {{NULL, "bareglobqual", OPT_EMULATE|OPT_ZSH}, BAREGLOBQUAL},
100 {{NULL, "bashautolist", 0}, BASHAUTOLIST},
101 {{NULL, "bashrematch", 0}, BASHREMATCH},
102 {{NULL, "beep", OPT_ALL}, BEEP},
103 {{NULL, "bgnice", OPT_EMULATE|OPT_NONBOURNE},BGNICE},
104 {{NULL, "braceccl", OPT_EMULATE}, BRACECCL},
105 {{NULL, "bsdecho", OPT_EMULATE|OPT_SH}, BSDECHO},
106 {{NULL, "caseglob", OPT_ALL}, CASEGLOB},
107 {{NULL, "casematch", OPT_ALL}, CASEMATCH},
108 {{NULL, "cbases", 0}, CBASES},
109 {{NULL, "cprecedences", OPT_EMULATE|OPT_NONZSH}, CPRECEDENCES},
110 {{NULL, "cdablevars", OPT_EMULATE}, CDABLEVARS},
111 {{NULL, "cdsilent", 0}, CDSILENT},
112 {{NULL, "chasedots", OPT_EMULATE}, CHASEDOTS},
113 {{NULL, "chaselinks", OPT_EMULATE}, CHASELINKS},
114 {{NULL, "checkjobs", OPT_EMULATE|OPT_ZSH}, CHECKJOBS},
115 {{NULL, "checkrunningjobs", OPT_EMULATE|OPT_ZSH}, CHECKRUNNINGJOBS},
116 {{NULL, "clobber", OPT_EMULATE|OPT_ALL}, CLOBBER},
117 {{NULL, "combiningchars", 0}, COMBININGCHARS},
118 {{NULL, "completealiases", 0}, COMPLETEALIASES},
119 {{NULL, "completeinword", 0}, COMPLETEINWORD},
120 {{NULL, "continueonerror", 0}, CONTINUEONERROR},
121 {{NULL, "correct", 0}, CORRECT},
122 {{NULL, "correctall", 0}, CORRECTALL},
123 {{NULL, "cshjunkiehistory", OPT_EMULATE|OPT_CSH}, CSHJUNKIEHISTORY},
124 {{NULL, "cshjunkieloops", OPT_EMULATE|OPT_CSH}, CSHJUNKIELOOPS},
125 {{NULL, "cshjunkiequotes", OPT_EMULATE|OPT_CSH}, CSHJUNKIEQUOTES},
126 {{NULL, "cshnullcmd", OPT_EMULATE|OPT_CSH}, CSHNULLCMD},
127 {{NULL, "cshnullglob", OPT_EMULATE|OPT_CSH}, CSHNULLGLOB},
128 {{NULL, "debugbeforecmd", OPT_ALL}, DEBUGBEFORECMD},
129 {{NULL, "emacs", 0}, EMACSMODE},
130 {{NULL, "equals", OPT_EMULATE|OPT_ZSH}, EQUALS},
131 {{NULL, "errexit", OPT_EMULATE}, ERREXIT},
132 {{NULL, "errreturn", OPT_EMULATE}, ERRRETURN},
133 {{NULL, "exec", OPT_ALL}, EXECOPT},
134 {{NULL, "extendedglob", OPT_EMULATE}, EXTENDEDGLOB},
135 {{NULL, "extendedhistory", OPT_CSH}, EXTENDEDHISTORY},
136 {{NULL, "evallineno", OPT_EMULATE|OPT_ZSH}, EVALLINENO},
137 {{NULL, "flowcontrol", OPT_ALL}, FLOWCONTROL},
138 {{NULL, "forcefloat", 0}, FORCEFLOAT},
139 {{NULL, "functionargzero", OPT_EMULATE|OPT_NONBOURNE},FUNCTIONARGZERO},
140 {{NULL, "glob", OPT_EMULATE|OPT_ALL}, GLOBOPT},
141 {{NULL, "globalexport", OPT_EMULATE|OPT_ZSH}, GLOBALEXPORT},
142 {{NULL, "globalrcs", OPT_ALL}, GLOBALRCS},
143 {{NULL, "globassign", OPT_EMULATE|OPT_CSH}, GLOBASSIGN},
144 {{NULL, "globcomplete", 0}, GLOBCOMPLETE},
145 {{NULL, "globdots", OPT_EMULATE}, GLOBDOTS},
146 {{NULL, "globstarshort", OPT_EMULATE}, GLOBSTARSHORT},
147 {{NULL, "globsubst", OPT_EMULATE|OPT_NONZSH}, GLOBSUBST},
148 {{NULL, "hashcmds", OPT_ALL}, HASHCMDS},
149 {{NULL, "hashdirs", OPT_ALL}, HASHDIRS},
150 {{NULL, "hashexecutablesonly", 0}, HASHEXECUTABLESONLY},
151 {{NULL, "hashlistall", OPT_ALL}, HASHLISTALL},
152 {{NULL, "histallowclobber", 0}, HISTALLOWCLOBBER},
153 {{NULL, "histbeep", OPT_ALL}, HISTBEEP},
154 {{NULL, "histexpiredupsfirst",0}, HISTEXPIREDUPSFIRST},
155 {{NULL, "histfcntllock", 0}, HISTFCNTLLOCK},
156 {{NULL, "histfindnodups", 0}, HISTFINDNODUPS},
157 {{NULL, "histignorealldups", 0}, HISTIGNOREALLDUPS},
158 {{NULL, "histignoredups", 0}, HISTIGNOREDUPS},
159 {{NULL, "histignorespace", 0}, HISTIGNORESPACE},
160 {{NULL, "histlexwords", 0}, HISTLEXWORDS},
161 {{NULL, "histnofunctions", 0}, HISTNOFUNCTIONS},
162 {{NULL, "histnostore", 0}, HISTNOSTORE},
163 {{NULL, "histsubstpattern", OPT_EMULATE}, HISTSUBSTPATTERN},
164 {{NULL, "histreduceblanks", 0}, HISTREDUCEBLANKS},
165 {{NULL, "histsavebycopy", OPT_ALL}, HISTSAVEBYCOPY},
166 {{NULL, "histsavenodups", 0}, HISTSAVENODUPS},
167 {{NULL, "histverify", 0}, HISTVERIFY},
168 {{NULL, "hup", OPT_EMULATE|OPT_ZSH}, HUP},
169 {{NULL, "ignorebraces", OPT_EMULATE|OPT_SH}, IGNOREBRACES},
170 {{NULL, "ignoreclosebraces", OPT_EMULATE}, IGNORECLOSEBRACES},
171 {{NULL, "ignoreeof", 0}, IGNOREEOF},
172 {{NULL, "incappendhistory", 0}, INCAPPENDHISTORY},
173 {{NULL, "incappendhistorytime", 0}, INCAPPENDHISTORYTIME},
174 {{NULL, "interactive", OPT_SPECIAL}, INTERACTIVE},
175 {{NULL, "interactivecomments",OPT_BOURNE}, INTERACTIVECOMMENTS},
176 {{NULL, "ksharrays", OPT_EMULATE|OPT_BOURNE}, KSHARRAYS},
177 {{NULL, "kshautoload", OPT_EMULATE|OPT_BOURNE}, KSHAUTOLOAD},
178 {{NULL, "kshglob", OPT_EMULATE|OPT_KSH}, KSHGLOB},
179 {{NULL, "kshoptionprint", OPT_EMULATE|OPT_KSH}, KSHOPTIONPRINT},
180 {{NULL, "kshtypeset", 0}, KSHTYPESET},
181 {{NULL, "kshzerosubscript", 0}, KSHZEROSUBSCRIPT},
182 {{NULL, "listambiguous", OPT_ALL}, LISTAMBIGUOUS},
183 {{NULL, "listbeep", OPT_ALL}, LISTBEEP},
184 {{NULL, "listpacked", 0}, LISTPACKED},
185 {{NULL, "listrowsfirst", 0}, LISTROWSFIRST},
186 {{NULL, "listtypes", OPT_ALL}, LISTTYPES},
187 {{NULL, "localoptions", OPT_EMULATE|OPT_KSH}, LOCALOPTIONS},
188 {{NULL, "localloops", OPT_EMULATE}, LOCALLOOPS},
189 {{NULL, "localpatterns", OPT_EMULATE}, LOCALPATTERNS},
190 {{NULL, "localtraps", OPT_EMULATE|OPT_KSH}, LOCALTRAPS},
191 {{NULL, "login", OPT_SPECIAL}, LOGINSHELL},
192 {{NULL, "longlistjobs", 0}, LONGLISTJOBS},
193 {{NULL, "magicequalsubst", OPT_EMULATE}, MAGICEQUALSUBST},
194 {{NULL, "mailwarning", 0}, MAILWARNING},
195 {{NULL, "markdirs", 0}, MARKDIRS},
196 {{NULL, "menucomplete", 0}, MENUCOMPLETE},
197 {{NULL, "monitor", OPT_SPECIAL}, MONITOR},
198 {{NULL, "multibyte",
199 #ifdef MULTIBYTE_SUPPORT
200 OPT_ALL
201 #else
202 0
203 #endif
204 }, MULTIBYTE},
205 {{NULL, "multifuncdef", OPT_EMULATE|OPT_ZSH}, MULTIFUNCDEF},
206 {{NULL, "multios", OPT_EMULATE|OPT_ZSH}, MULTIOS},
207 {{NULL, "nomatch", OPT_EMULATE|OPT_NONBOURNE},NOMATCH},
208 {{NULL, "notify", OPT_ZSH}, NOTIFY},
209 {{NULL, "nullglob", OPT_EMULATE}, NULLGLOB},
210 {{NULL, "numericglobsort", OPT_EMULATE}, NUMERICGLOBSORT},
211 {{NULL, "octalzeroes", OPT_EMULATE|OPT_SH}, OCTALZEROES},
212 {{NULL, "overstrike", 0}, OVERSTRIKE},
213 {{NULL, "pathdirs", OPT_EMULATE}, PATHDIRS},
214 {{NULL, "pathscript", OPT_EMULATE|OPT_BOURNE}, PATHSCRIPT},
215 {{NULL, "pipefail", OPT_EMULATE}, PIPEFAIL},
216 {{NULL, "posixaliases", OPT_EMULATE|OPT_BOURNE}, POSIXALIASES},
217 {{NULL, "posixargzero", OPT_EMULATE}, POSIXARGZERO},
218 {{NULL, "posixbuiltins", OPT_EMULATE|OPT_BOURNE}, POSIXBUILTINS},
219 {{NULL, "posixcd", OPT_EMULATE|OPT_BOURNE}, POSIXCD},
220 {{NULL, "posixidentifiers", OPT_EMULATE|OPT_BOURNE}, POSIXIDENTIFIERS},
221 {{NULL, "posixjobs", OPT_EMULATE|OPT_BOURNE}, POSIXJOBS},
222 {{NULL, "posixstrings", OPT_EMULATE|OPT_BOURNE}, POSIXSTRINGS},
223 {{NULL, "posixtraps", OPT_EMULATE|OPT_BOURNE}, POSIXTRAPS},
224 {{NULL, "printeightbit", 0}, PRINTEIGHTBIT},
225 {{NULL, "printexitvalue", 0}, PRINTEXITVALUE},
226 {{NULL, "privileged", OPT_SPECIAL}, PRIVILEGED},
227 {{NULL, "promptbang", OPT_KSH}, PROMPTBANG},
228 {{NULL, "promptcr", OPT_ALL}, PROMPTCR},
229 {{NULL, "promptpercent", OPT_NONBOURNE}, PROMPTPERCENT},
230 {{NULL, "promptsp", OPT_ALL}, PROMPTSP},
231 {{NULL, "promptsubst", OPT_BOURNE}, PROMPTSUBST},
232 {{NULL, "pushdignoredups", OPT_EMULATE}, PUSHDIGNOREDUPS},
233 {{NULL, "pushdminus", OPT_EMULATE}, PUSHDMINUS},
234 {{NULL, "pushdsilent", 0}, PUSHDSILENT},
235 {{NULL, "pushdtohome", OPT_EMULATE}, PUSHDTOHOME},
236 {{NULL, "rcexpandparam", OPT_EMULATE}, RCEXPANDPARAM},
237 {{NULL, "rcquotes", OPT_EMULATE}, RCQUOTES},
238 {{NULL, "rcs", OPT_ALL}, RCS},
239 {{NULL, "recexact", 0}, RECEXACT},
240 {{NULL, "rematchpcre", 0}, REMATCHPCRE},
241 {{NULL, "restricted", OPT_SPECIAL}, RESTRICTED},
242 {{NULL, "rmstarsilent", OPT_BOURNE}, RMSTARSILENT},
243 {{NULL, "rmstarwait", 0}, RMSTARWAIT},
244 {{NULL, "sharehistory", OPT_KSH}, SHAREHISTORY},
245 {{NULL, "shfileexpansion", OPT_EMULATE|OPT_BOURNE}, SHFILEEXPANSION},
246 {{NULL, "shglob", OPT_EMULATE|OPT_BOURNE}, SHGLOB},
247 {{NULL, "shinstdin", OPT_SPECIAL}, SHINSTDIN},
248 {{NULL, "shnullcmd", OPT_EMULATE|OPT_BOURNE}, SHNULLCMD},
249 {{NULL, "shoptionletters", OPT_EMULATE|OPT_BOURNE}, SHOPTIONLETTERS},
250 {{NULL, "shortloops", OPT_EMULATE|OPT_NONBOURNE},SHORTLOOPS},
251 {{NULL, "shwordsplit", OPT_EMULATE|OPT_BOURNE}, SHWORDSPLIT},
252 {{NULL, "singlecommand", OPT_SPECIAL}, SINGLECOMMAND},
253 {{NULL, "singlelinezle", OPT_KSH}, SINGLELINEZLE},
254 {{NULL, "sourcetrace", 0}, SOURCETRACE},
255 {{NULL, "sunkeyboardhack", 0}, SUNKEYBOARDHACK},
256 {{NULL, "transientrprompt", 0}, TRANSIENTRPROMPT},
257 {{NULL, "trapsasync", 0}, TRAPSASYNC},
258 {{NULL, "typesetsilent", OPT_EMULATE|OPT_BOURNE}, TYPESETSILENT},
259 {{NULL, "unset", OPT_EMULATE|OPT_BSHELL}, UNSET},
260 {{NULL, "verbose", 0}, VERBOSE},
261 {{NULL, "vi", 0}, VIMODE},
262 {{NULL, "warncreateglobal", OPT_EMULATE}, WARNCREATEGLOBAL},
263 {{NULL, "warnnestedvar", OPT_EMULATE}, WARNNESTEDVAR},
264 {{NULL, "xtrace", 0}, XTRACE},
265 {{NULL, "zle", OPT_SPECIAL}, USEZLE},
266 {{NULL, "braceexpand", OPT_ALIAS}, /* ksh/bash */ -IGNOREBRACES},
267 {{NULL, "dotglob", OPT_ALIAS}, /* bash */ GLOBDOTS},
268 {{NULL, "hashall", OPT_ALIAS}, /* bash */ HASHCMDS},
269 {{NULL, "histappend", OPT_ALIAS}, /* bash */ APPENDHISTORY},
270 {{NULL, "histexpand", OPT_ALIAS}, /* bash */ BANGHIST},
271 {{NULL, "log", OPT_ALIAS}, /* ksh */ -HISTNOFUNCTIONS},
272 {{NULL, "mailwarn", OPT_ALIAS}, /* bash */ MAILWARNING},
273 {{NULL, "onecmd", OPT_ALIAS}, /* bash */ SINGLECOMMAND},
274 {{NULL, "physical", OPT_ALIAS}, /* ksh/bash */ CHASELINKS},
275 {{NULL, "promptvars", OPT_ALIAS}, /* bash */ PROMPTSUBST},
276 {{NULL, "stdin", OPT_ALIAS}, /* ksh */ SHINSTDIN},
277 {{NULL, "trackall", OPT_ALIAS}, /* ksh */ HASHCMDS},
278 {{NULL, "dvorak", 0}, DVORAK},
279 {{NULL, NULL, 0}, 0}
280 };
281
282 /* Option letters */
283
284 #define optletters (isset(SHOPTIONLETTERS) ? kshletters : zshletters)
285
286 #define FIRST_OPT '0'
287 #define LAST_OPT 'y'
288
289 static short zshletters[LAST_OPT - FIRST_OPT + 1] = {
290 /* 0 */ CORRECT,
291 /* 1 */ PRINTEXITVALUE,
292 /* 2 */ -BADPATTERN,
293 /* 3 */ -NOMATCH,
294 /* 4 */ GLOBDOTS,
295 /* 5 */ NOTIFY,
296 /* 6 */ BGNICE,
297 /* 7 */ IGNOREEOF,
298 /* 8 */ MARKDIRS,
299 /* 9 */ AUTOLIST,
300 /* : */ 0,
301 /* ; */ 0,
302 /* < */ 0,
303 /* = */ 0,
304 /* > */ 0,
305 /* ? */ 0,
306 /* @ */ 0,
307 /* A */ 0, /* use with set for arrays */
308 /* B */ -BEEP,
309 /* C */ -CLOBBER,
310 /* D */ PUSHDTOHOME,
311 /* E */ PUSHDSILENT,
312 /* F */ -GLOBOPT,
313 /* G */ NULLGLOB,
314 /* H */ RMSTARSILENT,
315 /* I */ IGNOREBRACES,
316 /* J */ AUTOCD,
317 /* K */ -BANGHIST,
318 /* L */ SUNKEYBOARDHACK,
319 /* M */ SINGLELINEZLE,
320 /* N */ AUTOPUSHD,
321 /* O */ CORRECTALL,
322 /* P */ RCEXPANDPARAM,
323 /* Q */ PATHDIRS,
324 /* R */ LONGLISTJOBS,
325 /* S */ RECEXACT,
326 /* T */ CDABLEVARS,
327 /* U */ MAILWARNING,
328 /* V */ -PROMPTCR,
329 /* W */ AUTORESUME,
330 /* X */ LISTTYPES,
331 /* Y */ MENUCOMPLETE,
332 /* Z */ USEZLE,
333 /* [ */ 0,
334 /* \ */ 0,
335 /* ] */ 0,
336 /* ^ */ 0,
337 /* _ */ 0,
338 /* ` */ 0,
339 /* a */ ALLEXPORT,
340 /* b */ 0, /* in non-Bourne shells, end of options */
341 /* c */ 0, /* command follows */
342 /* d */ -GLOBALRCS,
343 /* e */ ERREXIT,
344 /* f */ -RCS,
345 /* g */ HISTIGNORESPACE,
346 /* h */ HISTIGNOREDUPS,
347 /* i */ INTERACTIVE,
348 /* j */ 0,
349 /* k */ INTERACTIVECOMMENTS,
350 /* l */ LOGINSHELL,
351 /* m */ MONITOR,
352 /* n */ -EXECOPT,
353 /* o */ 0, /* long option name follows */
354 /* p */ PRIVILEGED,
355 /* q */ 0,
356 /* r */ RESTRICTED,
357 /* s */ SHINSTDIN,
358 /* t */ SINGLECOMMAND,
359 /* u */ -UNSET,
360 /* v */ VERBOSE,
361 /* w */ CHASELINKS,
362 /* x */ XTRACE,
363 /* y */ SHWORDSPLIT,
364 };
365
366 static short kshletters[LAST_OPT - FIRST_OPT + 1] = {
367 /* 0 */ 0,
368 /* 1 */ 0,
369 /* 2 */ 0,
370 /* 3 */ 0,
371 /* 4 */ 0,
372 /* 5 */ 0,
373 /* 6 */ 0,
374 /* 7 */ 0,
375 /* 8 */ 0,
376 /* 9 */ 0,
377 /* : */ 0,
378 /* ; */ 0,
379 /* < */ 0,
380 /* = */ 0,
381 /* > */ 0,
382 /* ? */ 0,
383 /* @ */ 0,
384 /* A */ 0,
385 /* B */ 0,
386 /* C */ -CLOBBER,
387 /* D */ 0,
388 /* E */ 0,
389 /* F */ 0,
390 /* G */ 0,
391 /* H */ 0,
392 /* I */ 0,
393 /* J */ 0,
394 /* K */ 0,
395 /* L */ 0,
396 /* M */ 0,
397 /* N */ 0,
398 /* O */ 0,
399 /* P */ 0,
400 /* Q */ 0,
401 /* R */ 0,
402 /* S */ 0,
403 /* T */ TRAPSASYNC,
404 /* U */ 0,
405 /* V */ 0,
406 /* W */ 0,
407 /* X */ MARKDIRS,
408 /* Y */ 0,
409 /* Z */ 0,
410 /* [ */ 0,
411 /* \ */ 0,
412 /* ] */ 0,
413 /* ^ */ 0,
414 /* _ */ 0,
415 /* ` */ 0,
416 /* a */ ALLEXPORT,
417 /* b */ NOTIFY,
418 /* c */ 0,
419 /* d */ 0,
420 /* e */ ERREXIT,
421 /* f */ -GLOBOPT,
422 /* g */ 0,
423 /* h */ 0,
424 /* i */ INTERACTIVE,
425 /* j */ 0,
426 /* k */ 0,
427 /* l */ LOGINSHELL,
428 /* m */ MONITOR,
429 /* n */ -EXECOPT,
430 /* o */ 0,
431 /* p */ PRIVILEGED,
432 /* q */ 0,
433 /* r */ RESTRICTED,
434 /* s */ SHINSTDIN,
435 /* t */ SINGLECOMMAND,
436 /* u */ -UNSET,
437 /* v */ VERBOSE,
438 /* w */ 0,
439 /* x */ XTRACE,
440 /* y */ 0,
441 };
442
443 /* Initialisation of the option name hash table */
444
445 /**/
446 static void
printoptionnode(HashNode hn,int set)447 printoptionnode(HashNode hn, int set)
448 {
449 Optname on = (Optname) hn;
450 int optno = on->optno;
451
452 if (optno < 0)
453 optno = -optno;
454 if (isset(KSHOPTIONPRINT)) {
455 if (defset(on, emulation))
456 printf("no%-19s %s\n", on->node.nam, isset(optno) ? "off" : "on");
457 else
458 printf("%-21s %s\n", on->node.nam, isset(optno) ? "on" : "off");
459 } else if (set == (isset(optno) ^ defset(on, emulation))) {
460 if (set ^ isset(optno))
461 fputs("no", stdout);
462 puts(on->node.nam);
463 }
464 }
465
466 /**/
467 void
createoptiontable(void)468 createoptiontable(void)
469 {
470 Optname on;
471
472 optiontab = newhashtable(101, "optiontab", NULL);
473
474 optiontab->hash = hasher;
475 optiontab->emptytable = NULL;
476 optiontab->filltable = NULL;
477 optiontab->cmpnodes = strcmp;
478 optiontab->addnode = addhashnode;
479 optiontab->getnode = gethashnode;
480 optiontab->getnode2 = gethashnode2;
481 optiontab->removenode = NULL;
482 optiontab->disablenode = disablehashnode;
483 optiontab->enablenode = enablehashnode;
484 optiontab->freenode = NULL;
485 optiontab->printnode = printoptionnode;
486
487 for (on = optns; on->node.nam; on++)
488 optiontab->addnode(optiontab, on->node.nam, on);
489 }
490
491 /* Emulation appropriate to the setemulate function */
492
493 static int setemulate_emulation;
494
495 /* Option array manipulated within the setemulate function */
496
497 /**/
498 static char *setemulate_opts;
499
500 /* Setting of default options */
501
502 /**/
503 static void
setemulate(HashNode hn,int fully)504 setemulate(HashNode hn, int fully)
505 {
506 Optname on = (Optname) hn;
507
508 /* Set options: each non-special option is set according to the *
509 * current emulation mode if either it is considered relevant *
510 * to emulation or we are doing a full emulation (as indicated *
511 * by the `fully' parameter). */
512 if (!(on->node.flags & OPT_ALIAS) &&
513 ((fully && !(on->node.flags & OPT_SPECIAL)) ||
514 (on->node.flags & OPT_EMULATE)))
515 setemulate_opts[on->optno] = defset(on, setemulate_emulation);
516 }
517
518 /**/
519 void
installemulation(int new_emulation,char * new_opts)520 installemulation(int new_emulation, char *new_opts)
521 {
522 setemulate_emulation = new_emulation;
523 setemulate_opts = new_opts;
524 scanhashtable(optiontab, 0, 0, 0, setemulate,
525 !!(new_emulation & EMULATE_FULLY));
526 }
527
528 /**/
529 void
emulate(const char * zsh_name,int fully,int * new_emulation,char * new_opts)530 emulate(const char *zsh_name, int fully, int *new_emulation, char *new_opts)
531 {
532 char ch = *zsh_name;
533
534 if (ch == 'r')
535 ch = zsh_name[1];
536
537 /* Work out the new emulation mode */
538 if (ch == 'c')
539 *new_emulation = EMULATE_CSH;
540 else if (ch == 'k')
541 *new_emulation = EMULATE_KSH;
542 else if (ch == 's' || ch == 'b')
543 *new_emulation = EMULATE_SH;
544 else
545 *new_emulation = EMULATE_ZSH;
546
547 if (fully)
548 *new_emulation |= EMULATE_FULLY;
549 installemulation(*new_emulation, new_opts);
550
551 if (funcstack && funcstack->tp == FS_FUNC) {
552 /*
553 * We are inside a function. Decide if it's traced.
554 * Pedantic note: the function in the function table isn't
555 * guaranteed to be what we're executing, but it's
556 * close enough.
557 */
558 Shfunc shf = (Shfunc)shfunctab->getnode(shfunctab, funcstack->name);
559 if (shf && (shf->node.flags & (PM_TAGGED|PM_TAGGED_LOCAL))) {
560 /* Tracing is on, so set xtrace */
561 new_opts[XTRACE] = 1;
562 }
563 }
564 }
565
566 /* setopt, unsetopt */
567
568 /**/
569 static void
setoption(HashNode hn,int value)570 setoption(HashNode hn, int value)
571 {
572 dosetopt(((Optname) hn)->optno, value, 0, opts);
573 }
574
575 /**/
576 int
bin_setopt(char * nam,char ** args,UNUSED (Options ops),int isun)577 bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun)
578 {
579 int action, optno, match = 0;
580 int retval = 0;
581
582 /* With no arguments or options, display options. */
583 if (!*args) {
584 scanhashtable(optiontab, 1, 0, OPT_ALIAS, optiontab->printnode, !isun);
585 return 0;
586 }
587
588 /* loop through command line options (begins with "-" or "+") */
589 while (*args && (**args == '-' || **args == '+')) {
590 action = (**args == '-') ^ isun;
591 if(!args[0][1])
592 *args = "--";
593 while (*++*args) {
594 if(**args == Meta)
595 *++*args ^= 32;
596 /* The pseudo-option `--' signifies the end of options. */
597 if (**args == '-') {
598 args++;
599 goto doneoptions;
600 } else if (**args == 'o') {
601 if (!*++*args)
602 args++;
603 if (!*args) {
604 zwarnnam(nam, "string expected after -o");
605 inittyptab();
606 return 1;
607 }
608 if(!(optno = optlookup(*args))) {
609 zwarnnam(nam, "no such option: %s", *args);
610 retval |= 1;
611 } else if (dosetopt(optno, action, 0, opts)) {
612 zwarnnam(nam, "can't change option: %s", *args);
613 retval |= 1;
614 }
615 break;
616 } else if(**args == 'm') {
617 match = 1;
618 } else {
619 if (!(optno = optlookupc(**args))) {
620 zwarnnam(nam, "bad option: -%c", **args);
621 retval |= 1;
622 } else if (dosetopt(optno, action, 0, opts)) {
623 zwarnnam(nam, "can't change option: -%c", **args);
624 retval |= 1;
625 }
626 }
627 }
628 args++;
629 }
630 doneoptions:
631
632 if (!match) {
633 /* Not globbing the arguments -- arguments are simply option names. */
634 while (*args) {
635 if(!(optno = optlookup(*args++))) {
636 zwarnnam(nam, "no such option: %s", args[-1]);
637 retval |= 1;
638 } else if (dosetopt(optno, !isun, 0, opts)) {
639 zwarnnam(nam, "can't change option: %s", args[-1]);
640 retval |= 1;
641 }
642 }
643 } else {
644 /* Globbing option (-m) set. */
645 while (*args) {
646 Patprog pprog;
647 char *s, *t;
648
649 t = s = dupstring(*args);
650 while (*t)
651 if (*t == '_')
652 chuck(t);
653 else {
654 /* See comment in optlookup() */
655 if (*t >= 'A' && *t <= 'Z')
656 *t = (*t - 'A') + 'a';
657 t++;
658 }
659
660 /* Expand the current arg. */
661 tokenize(s);
662 if (!(pprog = patcompile(s, PAT_HEAPDUP, NULL))) {
663 zwarnnam(nam, "bad pattern: %s", *args);
664 retval |= 1;
665 break;
666 }
667 /* Loop over expansions. */
668 scanmatchtable(optiontab, pprog, 0, 0, OPT_ALIAS,
669 setoption, !isun);
670 args++;
671 }
672 }
673 inittyptab();
674 return retval;
675 }
676
677 /* Identify an option name */
678
679 /**/
680 mod_export int
optlookup(char const * name)681 optlookup(char const *name)
682 {
683 char *s, *t;
684 Optname n;
685
686 s = t = dupstring(name);
687
688 /* exorcise underscores, and change to lowercase */
689 while (*t)
690 if (*t == '_')
691 chuck(t);
692 else {
693 /*
694 * Some locales (in particular tr_TR.UTF-8) may
695 * have non-standard mappings of ASCII characters,
696 * so be careful. Option names must be ASCII so
697 * we don't need to be too clever.
698 */
699 if (*t >= 'A' && *t <= 'Z')
700 *t = (*t - 'A') + 'a';
701 t++;
702 }
703
704 /* look up name in the table */
705 if (s[0] == 'n' && s[1] == 'o' &&
706 (n = (Optname) optiontab->getnode(optiontab, s + 2))) {
707 return -n->optno;
708 } else if ((n = (Optname) optiontab->getnode(optiontab, s)))
709 return n->optno;
710 else
711 return OPT_INVALID;
712 }
713
714 /* Identify an option letter */
715
716 /**/
717 int
optlookupc(char c)718 optlookupc(char c)
719 {
720 if(c < FIRST_OPT || c > LAST_OPT)
721 return 0;
722
723 return optletters[c - FIRST_OPT];
724 }
725
726 /**/
727 static void
restrictparam(char * nam)728 restrictparam(char *nam)
729 {
730 Param pm = (Param) paramtab->getnode(paramtab, nam);
731
732 if (pm) {
733 pm->node.flags |= PM_SPECIAL | PM_RESTRICTED;
734 return;
735 }
736 createparam(nam, PM_SCALAR | PM_UNSET | PM_SPECIAL | PM_RESTRICTED);
737 }
738
739 /* list of restricted parameters which are not otherwise special */
740 static char *rparams[] = {
741 "SHELL", "HISTFILE", "LD_LIBRARY_PATH", "LD_AOUT_LIBRARY_PATH",
742 "LD_PRELOAD", "LD_AOUT_PRELOAD", NULL
743 };
744
745 /* Set or unset an option, as a result of user request. The option *
746 * number may be negative, indicating that the sense is reversed *
747 * from the usual meaning of the option. */
748
749 /**/
750 mod_export int
dosetopt(int optno,int value,int force,char * new_opts)751 dosetopt(int optno, int value, int force, char *new_opts)
752 {
753 if(!optno)
754 return -1;
755 if(optno < 0) {
756 optno = -optno;
757 value = !value;
758 }
759 if (optno == RESTRICTED) {
760 if (isset(RESTRICTED))
761 return value ? 0 : -1;
762 if (value) {
763 char **s;
764
765 for (s = rparams; *s; s++)
766 restrictparam(*s);
767 }
768 } else if(!force && optno == EXECOPT && !value && interact) {
769 /* cannot set noexec when interactive */
770 return -1;
771 } else if(!force && (optno == INTERACTIVE || optno == SHINSTDIN ||
772 optno == SINGLECOMMAND)) {
773 if (new_opts[optno] == value)
774 return 0;
775 /* it is not permitted to change the value of these options */
776 return -1;
777 } else if(!force && optno == USEZLE && value) {
778 /* we require a terminal in order to use ZLE */
779 if(!interact || SHTTY == -1 || !shout)
780 return -1;
781 } else if(optno == PRIVILEGED && !value) {
782 /* unsetting PRIVILEGED causes the shell to make itself unprivileged */
783
784 /* For simplicity's sake, require both setresgid() and setresuid() up-front. */
785 #if !defined(HAVE_SETRESGID)
786 zwarnnam("unsetopt",
787 "PRIVILEGED: can't drop privileges; setresgid() and friends not available");
788 return -1;
789 #elif !defined(HAVE_SETRESUID)
790 zwarnnam("unsetopt",
791 "PRIVILEGED: can't drop privileges; setresuid() and friends not available");
792 return -1;
793 #else
794 /* If set, return -1 so lastval will be non-zero. */
795 int failed = 0;
796 const int orig_euid = geteuid();
797 const int orig_egid = getegid();
798
799 /*
800 * Set the GID first as if we set the UID to non-privileged it
801 * might be impossible to restore the GID.
802 */
803 if (setresgid(getgid(), getgid(), getgid())) {
804 zwarnnam("unsetopt",
805 "PRIVILEGED: can't drop privileges; failed to change group ID: %e",
806 errno);
807 return -1;
808 }
809
810 # ifdef HAVE_INITGROUPS
811 /* Set the supplementary groups list.
812 *
813 * Note that on macOS, FreeBSD, and possibly some other platforms,
814 * initgroups() resets the EGID to its second argument (see setgroups(2) for
815 * details). This has the potential to leave the EGID in an unexpected
816 * state. However, it seems common in other projects that do this dance to
817 * simply re-use the same GID that's going to become the EGID anyway, in
818 * which case it doesn't matter. That's what we do here. It's therefore
819 * possible, in some probably uncommon cases, that the shell ends up not
820 * having the privileges of the RUID user's primary/passwd group. */
821 if (geteuid() == 0) {
822 struct passwd *pw = getpwuid(getuid());
823 if (pw == NULL) {
824 zwarnnam("unsetopt",
825 "can't drop privileges; failed to get user information for uid %L: %e",
826 (long)getuid(), errno);
827 failed = 1;
828 /* This may behave strangely in the unlikely event that the same user
829 * name appears with multiple UIDs in the passwd database */
830 } else if (initgroups(pw->pw_name, getgid())) {
831 zwarnnam("unsetopt",
832 "can't drop privileges; failed to set supplementary group list: %e",
833 errno);
834 return -1;
835 }
836 } else if (getuid() != 0 &&
837 (geteuid() != getuid() || orig_egid != getegid())) {
838 zwarnnam("unsetopt",
839 "PRIVILEGED: supplementary group list not changed due to lack of permissions: EUID=%L",
840 (long)geteuid());
841 failed = 1;
842 }
843 # else
844 /* initgroups() isn't in POSIX. If it's not available on the system,
845 * we silently skip it. */
846 # endif
847
848 /* Set the UID second. */
849 if (setresuid(getuid(), getuid(), getuid())) {
850 zwarnnam("unsetopt",
851 "PRIVILEGED: can't drop privileges; failed to change user ID: %e",
852 errno);
853 return -1;
854 }
855
856 if (getuid() != 0 && orig_egid != getegid() &&
857 (setgid(orig_egid) != -1 || setegid(orig_egid) != -1)) {
858 zwarnnam("unsetopt",
859 "PRIVILEGED: can't drop privileges; was able to restore the egid");
860 return -1;
861 }
862
863 if (getuid() != 0 && orig_euid != geteuid() &&
864 (setuid(orig_euid) != -1 || seteuid(orig_euid) != -1)) {
865 zwarnnam("unsetopt",
866 "PRIVILEGED: can't drop privileges; was able to restore the euid");
867 return -1;
868 }
869
870 if (failed) {
871 /* A warning message has been printed. */
872 return -1;
873 }
874 #endif /* HAVE_SETRESGID && HAVE_SETRESUID */
875
876 #ifdef JOB_CONTROL
877 } else if (!force && optno == MONITOR && value) {
878 if (new_opts[optno] == value)
879 return 0;
880 if (SHTTY != -1) {
881 origpgrp = GETPGRP();
882 acquire_pgrp();
883 } else
884 return -1;
885 #else
886 } else if(optno == MONITOR && value) {
887 return -1;
888 #endif /* not JOB_CONTROL */
889 #ifdef GETPWNAM_FAKED
890 } else if(optno == CDABLEVARS && value) {
891 return -1;
892 #endif /* GETPWNAM_FAKED */
893 } else if ((optno == EMACSMODE || optno == VIMODE) && value) {
894 if (sticky && sticky->emulation)
895 return -1;
896 zleentry(ZLE_CMD_SET_KEYMAP, optno);
897 new_opts[(optno == EMACSMODE) ? VIMODE : EMACSMODE] = 0;
898 } else if (optno == SUNKEYBOARDHACK) {
899 /* for backward compatibility */
900 keyboardhackchar = (value ? '`' : '\0');
901 }
902 new_opts[optno] = value;
903 if (optno == BANGHIST || optno == SHINSTDIN)
904 inittyptab();
905 return 0;
906 }
907
908 /* Function to get value for special parameter `-' */
909
910 /**/
911 char *
dashgetfn(UNUSED (Param pm))912 dashgetfn(UNUSED(Param pm))
913 {
914 static char buf[LAST_OPT - FIRST_OPT + 2];
915 char *val = buf;
916 int i;
917
918 for(i = 0; i <= LAST_OPT - FIRST_OPT; i++) {
919 int optno = optletters[i];
920 if(optno && ((optno > 0) ? isset(optno) : unset(-optno)))
921 *val++ = FIRST_OPT + i;
922 }
923 *val = '\0';
924 return buf;
925 }
926
927 /* print options for set -o/+o */
928
929 /**/
930 void
printoptionstates(int hadplus)931 printoptionstates(int hadplus)
932 {
933 scanhashtable(optiontab, 1, 0, OPT_ALIAS, printoptionnodestate, hadplus);
934 }
935
936 /**/
937 static void
printoptionnodestate(HashNode hn,int hadplus)938 printoptionnodestate(HashNode hn, int hadplus)
939 {
940 Optname on = (Optname) hn;
941 int optno = on->optno;
942
943 if (hadplus) {
944 printf("set %co %s%s\n",
945 defset(on, emulation) != isset(optno) ? '-' : '+',
946 defset(on, emulation) ? "no" : "",
947 on->node.nam);
948 } else {
949 if (defset(on, emulation))
950 printf("no%-19s %s\n", on->node.nam, isset(optno) ? "off" : "on");
951 else
952 printf("%-21s %s\n", on->node.nam, isset(optno) ? "on" : "off");
953 }
954 }
955
956 /* Print option list for --help */
957
958 /**/
959 void
printoptionlist(void)960 printoptionlist(void)
961 {
962 short *lp;
963 char c;
964
965 printf("\nNamed options:\n");
966 scanhashtable(optiontab, 1, 0, OPT_ALIAS, printoptionlist_printoption, 0);
967 printf("\nOption aliases:\n");
968 scanhashtable(optiontab, 1, OPT_ALIAS, 0, printoptionlist_printoption, 0);
969 printf("\nOption letters:\n");
970 for(lp = optletters, c = FIRST_OPT; c <= LAST_OPT; lp++, c++) {
971 if(!*lp)
972 continue;
973 printf(" -%c ", c);
974 printoptionlist_printequiv(*lp);
975 }
976 }
977
978 /**/
979 static void
printoptionlist_printoption(HashNode hn,UNUSED (int ignored))980 printoptionlist_printoption(HashNode hn, UNUSED(int ignored))
981 {
982 Optname on = (Optname) hn;
983
984 if(on->node.flags & OPT_ALIAS) {
985 printf(" --%-19s ", on->node.nam);
986 printoptionlist_printequiv(on->optno);
987 } else
988 printf(" --%s\n", on->node.nam);
989 }
990
991 /**/
992 static void
printoptionlist_printequiv(int optno)993 printoptionlist_printequiv(int optno)
994 {
995 int isneg = optno < 0;
996
997 optno *= (isneg ? -1 : 1);
998 printf(" equivalent to --%s%s\n", isneg ? "no-" : "", optns[optno-1].node.nam);
999 }
1000
1001 /**/
1002 static char *print_emulate_opts;
1003
1004 /**/
1005 static void
print_emulate_option(HashNode hn,int fully)1006 print_emulate_option(HashNode hn, int fully)
1007 {
1008 Optname on = (Optname) hn;
1009
1010 if (!(on->node.flags & OPT_ALIAS) &&
1011 ((fully && !(on->node.flags & OPT_SPECIAL)) ||
1012 (on->node.flags & OPT_EMULATE)))
1013 {
1014 if (!print_emulate_opts[on->optno])
1015 fputs("no", stdout);
1016 puts(on->node.nam);
1017 }
1018 }
1019
1020 /*
1021 * List the settings of options associated with an emulation
1022 */
1023
1024 /**/
list_emulate_options(char * cmdopts,int fully)1025 void list_emulate_options(char *cmdopts, int fully)
1026 {
1027 print_emulate_opts = cmdopts;
1028 scanhashtable(optiontab, 1, 0, 0, print_emulate_option, fully);
1029 }
1030