1 /*
2 * builtin.c - builtin commands
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 /* this is defined so we get the prototype for open_memstream */
31 #define _GNU_SOURCE 1
32
33 #include "zsh.mdh"
34 #include "builtin.pro"
35
36 #include <math.h>
37
38 /* Builtins in the main executable */
39
40 static struct builtin builtins[] =
41 {
42 BIN_PREFIX("-", BINF_DASH),
43 BIN_PREFIX("builtin", BINF_BUILTIN),
44 BIN_PREFIX("command", BINF_COMMAND),
45 BIN_PREFIX("exec", BINF_EXEC),
46 BIN_PREFIX("noglob", BINF_NOGLOB),
47 BUILTIN("[", BINF_HANDLES_OPTS, bin_test, 0, -1, BIN_BRACKET, NULL, NULL),
48 BUILTIN(".", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL),
49 BUILTIN(":", BINF_PSPECIAL, bin_true, 0, -1, 0, NULL, NULL),
50 BUILTIN("alias", BINF_MAGICEQUALS | BINF_PLUSOPTS, bin_alias, 0, -1, 0, "Lgmrs", NULL),
51 BUILTIN("autoload", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "dmktrRTUwWXz", "u"),
52 BUILTIN("bg", 0, bin_fg, 0, -1, BIN_BG, NULL, NULL),
53 BUILTIN("break", BINF_PSPECIAL, bin_break, 0, 1, BIN_BREAK, NULL, NULL),
54 BUILTIN("bye", 0, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
55 BUILTIN("cd", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 2, BIN_CD, "qsPL", NULL),
56 BUILTIN("chdir", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 2, BIN_CD, "qsPL", NULL),
57 BUILTIN("continue", BINF_PSPECIAL, bin_break, 0, 1, BIN_CONTINUE, NULL, NULL),
58 BUILTIN("declare", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%klmp:%rtuxz", NULL),
59 BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "clpv", NULL),
60 BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmprs", NULL),
61 BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL),
62 BUILTIN("echo", BINF_SKIPINVALID, bin_print, 0, -1, BIN_ECHO, "neE", "-"),
63 BUILTIN("emulate", 0, bin_emulate, 0, -1, 0, "lLR", NULL),
64 BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmprs", NULL),
65 BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL),
66 BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
67 BUILTIN("export", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, BIN_EXPORT, "E:%F:%HL:%R:%TUZ:%afhi:%lp:%rtu", "xg"),
68 BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL),
69 /*
70 * We used to behave as if the argument to -e was optional.
71 * But that's actually not useful, so it's more consistent to
72 * cause an error.
73 */
74 BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "aAdDe:EfiIlLmnpPrRt:W", NULL),
75 BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL),
76 BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%Z:%ghlp:%rtux", "E"),
77 BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "ckmMstTuUWx:z", NULL),
78 BUILTIN("getln", 0, bin_read, 0, -1, 0, "ecnAlE", "zr"),
79 BUILTIN("getopts", 0, bin_getopts, 2, -1, 0, NULL, NULL),
80 BUILTIN("hash", BINF_MAGICEQUALS, bin_hash, 0, -1, 0, "Ldfmrv", NULL),
81
82 #ifdef ZSH_HASH_DEBUG
83 BUILTIN("hashinfo", 0, bin_hashinfo, 0, 0, 0, NULL, NULL),
84 #endif
85
86 BUILTIN("history", 0, bin_fc, 0, -1, BIN_FC, "adDEfiLmnpPrt:", "l"),
87 BUILTIN("integer", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "HL:%R:%Z:%ghi:%lp:%rtux", "i"),
88 BUILTIN("jobs", 0, bin_fg, 0, -1, BIN_JOBS, "dlpZrs", NULL),
89 BUILTIN("kill", BINF_HANDLES_OPTS, bin_kill, 0, -1, 0, NULL, NULL),
90 BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL),
91 BUILTIN("local", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%ahi:%lp:%rtux", NULL),
92 BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL),
93 BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL),
94
95 #if defined(ZSH_MEM) & defined(ZSH_MEM_DEBUG)
96 BUILTIN("mem", 0, bin_mem, 0, 0, 0, "v", NULL),
97 #endif
98
99 #if defined(ZSH_PAT_DEBUG)
100 BUILTIN("patdebug", 0, bin_patdebug, 1, -1, 0, "p", NULL),
101 #endif
102
103 BUILTIN("popd", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 1, BIN_POPD, "q", NULL),
104 BUILTIN("print", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, "abcC:Df:ilmnNoOpPrRsSu:v:x:X:z-", NULL),
105 BUILTIN("printf", BINF_SKIPINVALID | BINF_SKIPDASH, bin_print, 1, -1, BIN_PRINTF, "v:", NULL),
106 BUILTIN("pushd", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 2, BIN_PUSHD, "qsPL", NULL),
107 BUILTIN("pushln", 0, bin_print, 0, -1, BIN_PRINT, NULL, "-nz"),
108 BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL),
109 BUILTIN("r", 0, bin_fc, 0, -1, BIN_R, "IlLnr", NULL),
110 BUILTIN("read", 0, bin_read, 0, -1, 0, "cd:ek:%lnpqrst:%zu:AE", NULL),
111 BUILTIN("readonly", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, BIN_READONLY, "AE:%F:%HL:%R:%TUZ:%afghi:%lptux", "r"),
112 BUILTIN("rehash", 0, bin_hash, 0, 0, 0, "df", "r"),
113 BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL),
114 BUILTIN("set", BINF_PSPECIAL | BINF_HANDLES_OPTS, bin_set, 0, -1, 0, NULL, NULL),
115 BUILTIN("setopt", 0, bin_setopt, 0, -1, BIN_SETOPT, NULL, NULL),
116 BUILTIN("shift", BINF_PSPECIAL, bin_shift, 0, -1, 0, "p", NULL),
117 BUILTIN("source", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL),
118 BUILTIN("suspend", 0, bin_suspend, 0, 0, 0, "f", NULL),
119 BUILTIN("test", BINF_HANDLES_OPTS, bin_test, 0, -1, BIN_TEST, NULL, NULL),
120 BUILTIN("ttyctl", 0, bin_ttyctl, 0, 0, 0, "fu", NULL),
121 BUILTIN("times", BINF_PSPECIAL, bin_times, 0, 0, 0, NULL, NULL),
122 BUILTIN("trap", BINF_PSPECIAL | BINF_HANDLES_OPTS, bin_trap, 0, -1, 0, NULL, NULL),
123 BUILTIN("true", 0, bin_true, 0, -1, 0, NULL, NULL),
124 BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsSw", "v"),
125 BUILTIN("typeset", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%klp:%rtuxmz", NULL),
126 BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL),
127 BUILTIN("unalias", 0, bin_unhash, 0, -1, BIN_UNALIAS, "ams", NULL),
128 BUILTIN("unfunction", 0, bin_unhash, 1, -1, BIN_UNFUNCTION, "m", "f"),
129 BUILTIN("unhash", 0, bin_unhash, 1, -1, BIN_UNHASH, "adfms", NULL),
130 BUILTIN("unset", BINF_PSPECIAL, bin_unset, 1, -1, BIN_UNSET, "fmv", NULL),
131 BUILTIN("unsetopt", 0, bin_setopt, 0, -1, BIN_UNSETOPT, NULL, NULL),
132 BUILTIN("wait", 0, bin_fg, 0, -1, BIN_WAIT, NULL, NULL),
133 BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsSwx:", NULL),
134 BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsSwx:", "ca"),
135 BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsSwx:", "c"),
136 BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "AFRILP:abcfdilmpsue", NULL),
137 BUILTIN("zcompile", 0, bin_zcompile, 0, -1, 0, "tUMRcmzka", NULL),
138 };
139
140 /****************************************/
141 /* Builtin Command Hash Table Functions */
142 /****************************************/
143
144 /* hash table containing builtin commands */
145
146 /**/
147 mod_export HashTable builtintab;
148
149 /**/
150 void
createbuiltintable(void)151 createbuiltintable(void)
152 {
153 builtintab = newhashtable(85, "builtintab", NULL);
154
155 builtintab->hash = hasher;
156 builtintab->emptytable = NULL;
157 builtintab->filltable = NULL;
158 builtintab->cmpnodes = strcmp;
159 builtintab->addnode = addhashnode;
160 builtintab->getnode = gethashnode;
161 builtintab->getnode2 = gethashnode2;
162 builtintab->removenode = removehashnode;
163 builtintab->disablenode = disablehashnode;
164 builtintab->enablenode = enablehashnode;
165 builtintab->freenode = freebuiltinnode;
166 builtintab->printnode = printbuiltinnode;
167
168 (void)addbuiltins("zsh", builtins, sizeof(builtins)/sizeof(*builtins));
169 }
170
171 /* Print a builtin */
172
173 /**/
174 static void
printbuiltinnode(HashNode hn,int printflags)175 printbuiltinnode(HashNode hn, int printflags)
176 {
177 Builtin bn = (Builtin) hn;
178
179 if (printflags & PRINT_WHENCE_WORD) {
180 printf("%s: builtin\n", bn->node.nam);
181 return;
182 }
183
184 if (printflags & PRINT_WHENCE_CSH) {
185 printf("%s: shell built-in command\n", bn->node.nam);
186 return;
187 }
188
189 if (printflags & PRINT_WHENCE_VERBOSE) {
190 printf("%s is a shell builtin\n", bn->node.nam);
191 return;
192 }
193
194 /* default is name only */
195 printf("%s\n", bn->node.nam);
196 }
197
198 /**/
199 static void
freebuiltinnode(HashNode hn)200 freebuiltinnode(HashNode hn)
201 {
202 Builtin bn = (Builtin) hn;
203
204 if(!(bn->node.flags & BINF_ADDED)) {
205 zsfree(bn->node.nam);
206 zsfree(bn->optstr);
207 zfree(bn, sizeof(struct builtin));
208 }
209 }
210
211 /**/
212 void
init_builtins(void)213 init_builtins(void)
214 {
215 if (!EMULATION(EMULATE_ZSH)) {
216 HashNode hn = reswdtab->getnode2(reswdtab, "repeat");
217 if (hn)
218 reswdtab->disablenode(hn, 0);
219 }
220 }
221
222 /* Make sure we have space for a new option and increment. */
223
224 #define OPT_ALLOC_CHUNK 16
225
226 /**/
227 static int
new_optarg(Options ops)228 new_optarg(Options ops)
229 {
230 /* Argument index must be a non-zero 6-bit number. */
231 if (ops->argscount == 63)
232 return 1;
233 if (ops->argsalloc == ops->argscount) {
234 char **newptr =
235 (char **)zhalloc((ops->argsalloc + OPT_ALLOC_CHUNK) *
236 sizeof(char *));
237 if (ops->argsalloc)
238 memcpy(newptr, ops->args, ops->argsalloc * sizeof(char *));
239 ops->args = newptr;
240 ops->argsalloc += OPT_ALLOC_CHUNK;
241 }
242 ops->argscount++;
243 return 0;
244 }
245
246
247 /* execute a builtin handler function after parsing the arguments */
248
249 /**/
250 int
execbuiltin(LinkList args,LinkList assigns,Builtin bn)251 execbuiltin(LinkList args, LinkList assigns, Builtin bn)
252 {
253 char *pp, *name, *optstr;
254 int flags, argc, execop, xtr = isset(XTRACE);
255 struct options ops;
256
257 /* initialise options structure */
258 memset(ops.ind, 0, MAX_OPS*sizeof(unsigned char));
259 ops.args = NULL;
260 ops.argscount = ops.argsalloc = 0;
261
262 /* initialize some local variables */
263 name = (char *) ugetnode(args);
264
265 if (!bn->handlerfunc) {
266 DPUTS(1, "Missing builtin detected too late");
267 deletebuiltin(bn->node.nam);
268 return 1;
269 }
270 /* get some information about the command */
271 flags = bn->node.flags;
272 optstr = bn->optstr;
273
274 /* Set up the argument list. */
275 /* count the arguments */
276 argc = countlinknodes(args);
277
278 {
279 /*
280 * Keep all arguments, including options, in an array.
281 * We don't actually need the option part of the argument
282 * after option processing, but it makes XTRACE output
283 * much simpler.
284 */
285 VARARR(char *, argarr, argc + 1);
286 char **argv;
287
288 /*
289 * Get the actual arguments, into argv. Remember argarr
290 * may be an array declaration, depending on the compiler.
291 */
292 argv = argarr;
293 while ((*argv++ = (char *)ugetnode(args)));
294 argv = argarr;
295
296 /* Sort out the options. */
297 if (optstr) {
298 char *arg = *argv;
299 int sense; /* 1 for -x, 0 for +x */
300 /* while arguments look like options ... */
301 while (arg &&
302 /* Must begin with - or maybe + */
303 ((sense = (*arg == '-')) ||
304 ((flags & BINF_PLUSOPTS) && *arg == '+'))) {
305 /* Digits aren't arguments unless the command says they are. */
306 if (!(flags & BINF_KEEPNUM) && idigit(arg[1]))
307 break;
308 /* For cd and friends, a single dash is not an option. */
309 if ((flags & BINF_SKIPDASH) && !arg[1])
310 break;
311 if ((flags & BINF_DASHDASHVALID) && !strcmp(arg, "--")) {
312 /*
313 * Need to skip this before checking whether this is
314 * really an option.
315 */
316 argv++;
317 break;
318 }
319 /*
320 * Unrecognised options to echo etc. are not really
321 * options.
322 *
323 * Note this flag is not smart enough to handle option
324 * arguments. In fact, ideally it shouldn't be added
325 * to any new builtins, to preserve standard option
326 * handling as much as possible.
327 */
328 if (flags & BINF_SKIPINVALID) {
329 char *p = arg;
330 while (*++p && strchr(optstr, (int) *p));
331 if (*p)
332 break;
333 }
334 /* handle -- or - (ops.ind['-']), and +
335 * (ops.ind['-'] and ops.ind['+']) */
336 if (arg[1] == '-')
337 arg++;
338 if (!arg[1]) {
339 ops.ind['-'] = 1;
340 if (!sense)
341 ops.ind['+'] = 1;
342 }
343 /* save options in ops, as long as they are in bn->optstr */
344 while (*++arg) {
345 char *optptr;
346 if ((optptr = strchr(optstr, execop = (int)*arg))) {
347 ops.ind[(int)*arg] = (sense) ? 1 : 2;
348 if (optptr[1] == ':') {
349 char *argptr = NULL;
350 if (optptr[2] == ':') {
351 if (arg[1])
352 argptr = arg+1;
353 /* Optional argument in same word*/
354 } else if (optptr[2] == '%') {
355 /* Optional numeric argument in same
356 * or next word. */
357 if (arg[1] && idigit(arg[1]))
358 argptr = arg+1;
359 else if (argv[1] && idigit(*argv[1]))
360 argptr = arg = *++argv;
361 } else {
362 /* Mandatory argument */
363 if (arg[1])
364 argptr = arg+1;
365 else if ((arg = *++argv))
366 argptr = arg;
367 else {
368 zwarnnam(name, "argument expected: -%c",
369 execop);
370 return 1;
371 }
372 }
373 if (argptr) {
374 if (new_optarg(&ops)) {
375 zwarnnam(name,
376 "too many option arguments");
377 return 1;
378 }
379 ops.ind[execop] |= ops.argscount << 2;
380 ops.args[ops.argscount-1] = argptr;
381 while (arg[1])
382 arg++;
383 }
384 }
385 } else
386 break;
387 }
388 /* The above loop may have exited on an invalid option. (We *
389 * assume that any option requiring metafication is invalid.) */
390 if (*arg) {
391 if(*arg == Meta)
392 *++arg ^= 32;
393 zwarnnam(name, "bad option: %c%c", "+-"[sense], *arg);
394 return 1;
395 }
396 arg = *++argv;
397 /* for the "print" builtin, the options after -R are treated as
398 options to "echo" */
399 if ((flags & BINF_PRINTOPTS) && ops.ind['R'] &&
400 !ops.ind['f']) {
401 optstr = "ne";
402 flags |= BINF_SKIPINVALID;
403 }
404 /* the option -- indicates the end of the options */
405 if (ops.ind['-'])
406 break;
407 }
408 } else if (!(flags & BINF_HANDLES_OPTS) && *argv &&
409 !strcmp(*argv, "--")) {
410 ops.ind['-'] = 1;
411 argv++;
412 }
413
414 /* handle built-in options, for overloaded handler functions */
415 if ((pp = bn->defopts)) {
416 while (*pp) {
417 /* only if not already set */
418 if (!ops.ind[(int)*pp])
419 ops.ind[(int)*pp] = 1;
420 pp++;
421 }
422 }
423
424 /* Fix the argument count by subtracting option arguments */
425 argc -= argv - argarr;
426
427 if (errflag) {
428 errflag &= ~ERRFLAG_ERROR;
429 return 1;
430 }
431
432 /* check that the argument count lies within the specified bounds */
433 if (argc < bn->minargs || (argc > bn->maxargs && bn->maxargs != -1)) {
434 zwarnnam(name, (argc < bn->minargs)
435 ? "not enough arguments" : "too many arguments");
436 return 1;
437 }
438
439 /* display execution trace information, if required */
440 if (xtr) {
441 /* Use full argument list including options for trace output */
442 char **fullargv = argarr;
443 printprompt4();
444 fprintf(xtrerr, "%s", name);
445 while (*fullargv) {
446 fputc(' ', xtrerr);
447 quotedzputs(*fullargv++, xtrerr);
448 }
449 if (assigns) {
450 LinkNode node;
451 for (node = firstnode(assigns); node; incnode(node)) {
452 Asgment asg = (Asgment)node;
453 fputc(' ', xtrerr);
454 quotedzputs(asg->name, xtrerr);
455 if (asg->flags & ASG_ARRAY) {
456 fprintf(xtrerr, "=(");
457 if (asg->value.array) {
458 if (asg->flags & ASG_KEY_VALUE) {
459 LinkNode keynode, valnode;
460 keynode = firstnode(asg->value.array);
461 for (;;) {
462 if (!keynode)
463 break;
464 valnode = nextnode(keynode);
465 if (!valnode)
466 break;
467 fputc('[', xtrerr);
468 quotedzputs((char *)getdata(keynode),
469 xtrerr);
470 fprintf(stderr, "]=");
471 quotedzputs((char *)getdata(valnode),
472 xtrerr);
473 keynode = nextnode(valnode);
474 }
475 } else {
476 LinkNode arrnode;
477 for (arrnode = firstnode(asg->value.array);
478 arrnode;
479 incnode(arrnode)) {
480 fputc(' ', xtrerr);
481 quotedzputs((char *)getdata(arrnode),
482 xtrerr);
483 }
484 }
485 }
486 fprintf(xtrerr, " )");
487 } else if (asg->value.scalar) {
488 fputc('=', xtrerr);
489 quotedzputs(asg->value.scalar, xtrerr);
490 }
491 }
492 }
493 fputc('\n', xtrerr);
494 fflush(xtrerr);
495 }
496 /* call the handler function, and return its return value */
497 if (flags & BINF_ASSIGN)
498 {
499 /*
500 * Takes two sets of arguments.
501 */
502 HandlerFuncAssign assignfunc = (HandlerFuncAssign)bn->handlerfunc;
503 return (*(assignfunc)) (name, argv, assigns, &ops, bn->funcid);
504 }
505 else
506 {
507 return (*(bn->handlerfunc)) (name, argv, &ops, bn->funcid);
508 }
509 }
510 }
511
512 /* Enable/disable an element in one of the internal hash tables. *
513 * With no arguments, it lists all the currently enabled/disabled *
514 * elements in that particular hash table. */
515
516 /**/
517 int
bin_enable(char * name,char ** argv,Options ops,int func)518 bin_enable(char *name, char **argv, Options ops, int func)
519 {
520 HashTable ht;
521 HashNode hn;
522 ScanFunc scanfunc;
523 Patprog pprog;
524 int flags1 = 0, flags2 = 0;
525 int match = 0, returnval = 0;
526
527 /* Find out which hash table we are working with. */
528 if (OPT_ISSET(ops,'p')) {
529 return pat_enables(name, argv, func == BIN_ENABLE);
530 } else if (OPT_ISSET(ops,'f'))
531 ht = shfunctab;
532 else if (OPT_ISSET(ops,'r'))
533 ht = reswdtab;
534 else if (OPT_ISSET(ops,'s'))
535 ht = sufaliastab;
536 else if (OPT_ISSET(ops,'a'))
537 ht = aliastab;
538 else
539 ht = builtintab;
540
541 /* Do we want to enable or disable? */
542 if (func == BIN_ENABLE) {
543 flags2 = DISABLED;
544 scanfunc = ht->enablenode;
545 } else {
546 flags1 = DISABLED;
547 scanfunc = ht->disablenode;
548 }
549
550 /* Given no arguments, print the names of the enabled/disabled elements *
551 * in this hash table. If func == BIN_ENABLE, then scanhashtable will *
552 * print nodes NOT containing the DISABLED flag, else scanhashtable will *
553 * print nodes containing the DISABLED flag. */
554 if (!*argv) {
555 queue_signals();
556 scanhashtable(ht, 1, flags1, flags2, ht->printnode, 0);
557 unqueue_signals();
558 return 0;
559 }
560
561 /* With -m option, treat arguments as glob patterns. */
562 if (OPT_ISSET(ops,'m')) {
563 for (; *argv; argv++) {
564 queue_signals();
565
566 /* parse pattern */
567 tokenize(*argv);
568 if ((pprog = patcompile(*argv, PAT_STATIC, 0)))
569 match += scanmatchtable(ht, pprog, 0, 0, 0, scanfunc, 0);
570 else {
571 untokenize(*argv);
572 zwarnnam(name, "bad pattern : %s", *argv);
573 returnval = 1;
574 }
575 unqueue_signals();
576 }
577 /* If we didn't match anything, we return 1. */
578 if (!match)
579 returnval = 1;
580 return returnval;
581 }
582
583 /* Take arguments literally -- do not glob */
584 queue_signals();
585 for (; *argv; argv++) {
586 if ((hn = ht->getnode2(ht, *argv))) {
587 scanfunc(hn, 0);
588 } else {
589 zwarnnam(name, "no such hash table element: %s", *argv);
590 returnval = 1;
591 }
592 }
593 unqueue_signals();
594 return returnval;
595 }
596
597 /* set: either set the shell options, or set the shell arguments, *
598 * or declare an array, or show various things */
599
600 /**/
601 int
bin_set(char * nam,char ** args,UNUSED (Options ops),UNUSED (int func))602 bin_set(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
603 {
604 int action, optno, array = 0, hadopt = 0,
605 hadplus = 0, hadend = 0, sort = 0;
606 char **x, *arrayname = NULL;
607
608 /* Obsolescent sh compatibility: set - is the same as set +xv *
609 * and set - args is the same as set +xv -- args */
610 if (!EMULATION(EMULATE_ZSH) && *args && **args == '-' && !args[0][1]) {
611 dosetopt(VERBOSE, 0, 0, opts);
612 dosetopt(XTRACE, 0, 0, opts);
613 if (!args[1])
614 return 0;
615 }
616
617 /* loop through command line options (begins with "-" or "+") */
618 while (*args && (**args == '-' || **args == '+')) {
619 action = (**args == '-');
620 hadplus |= !action;
621 if(!args[0][1])
622 *args = "--";
623 while (*++*args) {
624 if(**args == Meta)
625 *++*args ^= 32;
626 if(**args != '-' || action)
627 hadopt = 1;
628 /* The pseudo-option `--' signifies the end of options. */
629 if (**args == '-') {
630 hadend = 1;
631 args++;
632 goto doneoptions;
633 } else if (**args == 'o') {
634 if (!*++*args)
635 args++;
636 if (!*args) {
637 printoptionstates(hadplus);
638 inittyptab();
639 return 0;
640 }
641 if(!(optno = optlookup(*args)))
642 zerrnam(nam, "no such option: %s", *args);
643 else if(dosetopt(optno, action, 0, opts))
644 zerrnam(nam, "can't change option: %s", *args);
645 break;
646 } else if(**args == 'A') {
647 if(!*++*args)
648 args++;
649 array = action ? 1 : -1;
650 arrayname = *args;
651 if (!arrayname)
652 goto doneoptions;
653 else if (!isset(KSHARRAYS))
654 {
655 args++;
656 goto doneoptions;
657 }
658 break;
659 } else if (**args == 's')
660 sort = action ? 1 : -1;
661 else {
662 if (!(optno = optlookupc(**args)))
663 zerrnam(nam, "bad option: -%c", **args);
664 else if(dosetopt(optno, action, 0, opts))
665 zerrnam(nam, "can't change option: -%c", **args);
666 }
667 }
668 args++;
669 }
670 if (errflag)
671 return 1;
672 doneoptions:
673 inittyptab();
674
675 /* Show the parameters, possibly with values */
676 queue_signals();
677 if (!arrayname)
678 {
679 if (!hadopt && !*args)
680 scanhashtable(paramtab, 1, 0, 0, paramtab->printnode,
681 hadplus ? PRINT_NAMEONLY : 0);
682
683 if (array) {
684 /* display arrays */
685 scanhashtable(paramtab, 1, PM_ARRAY, 0, paramtab->printnode,
686 hadplus ? PRINT_NAMEONLY : 0);
687 }
688 if (!*args && !hadend) {
689 unqueue_signals();
690 return 0;
691 }
692 }
693 if (sort)
694 strmetasort(args, sort < 0 ? SORTIT_BACKWARDS : 0, NULL);
695 if (array) {
696 /* create an array with the specified elements */
697 char **a = NULL, **y;
698 int len = arrlen(args);
699
700 if (array < 0 && (a = getaparam(arrayname)) && arrlen_gt(a, len)) {
701 a += len;
702 len += arrlen(a);
703 }
704 for (x = y = zalloc((len + 1) * sizeof(char *)); len--;) {
705 if (!*args)
706 args = a;
707 *y++ = ztrdup(*args++);
708 }
709 *y++ = NULL;
710 setaparam(arrayname, x);
711 } else {
712 /* set shell arguments */
713 freearray(pparams);
714 pparams = zarrdup(args);
715 }
716 unqueue_signals();
717 return 0;
718 }
719
720 /**** directory-handling builtins ****/
721
722 /**/
723 int doprintdir = 0; /* set in exec.c (for autocd, cdpath, etc.) */
724
725 /* pwd: display the name of the current directory */
726
727 /**/
728 int
bin_pwd(UNUSED (char * name),UNUSED (char ** argv),Options ops,UNUSED (int func))729 bin_pwd(UNUSED(char *name), UNUSED(char **argv), Options ops, UNUSED(int func))
730 {
731 if (OPT_ISSET(ops,'r') || OPT_ISSET(ops,'P') ||
732 (isset(CHASELINKS) && !OPT_ISSET(ops,'L')))
733 printf("%s\n", zgetcwd());
734 else {
735 zputs(pwd, stdout);
736 putchar('\n');
737 }
738 return 0;
739 }
740
741 /* the directory stack */
742
743 /**/
744 mod_export LinkList dirstack;
745
746 /* dirs: list the directory stack, or replace it with a provided list */
747
748 /**/
749 int
bin_dirs(UNUSED (char * name),char ** argv,Options ops,UNUSED (int func))750 bin_dirs(UNUSED(char *name), char **argv, Options ops, UNUSED(int func))
751 {
752 LinkList l;
753
754 queue_signals();
755 /* with -v, -p or no arguments display the directory stack */
756 if (!(*argv || OPT_ISSET(ops,'c')) || OPT_ISSET(ops,'v') ||
757 OPT_ISSET(ops,'p')) {
758 LinkNode node;
759 char *fmt;
760 int pos = 1;
761
762 /* with the -v option, display a numbered list, starting at zero */
763 if (OPT_ISSET(ops,'v')) {
764 printf("0\t");
765 fmt = "\n%d\t";
766 /* with the -p option, display entries one per line */
767 } else if (OPT_ISSET(ops,'p'))
768 fmt = "\n";
769 else
770 fmt = " ";
771 if (OPT_ISSET(ops,'l'))
772 zputs(pwd, stdout);
773 else
774 fprintdir(pwd, stdout);
775 for (node = firstnode(dirstack); node; incnode(node)) {
776 printf(fmt, pos++);
777 if (OPT_ISSET(ops,'l'))
778 zputs(getdata(node), stdout);
779 else
780 fprintdir(getdata(node), stdout);
781
782 }
783 unqueue_signals();
784 putchar('\n');
785 return 0;
786 }
787 /* replace the stack with the specified directories */
788 l = znewlinklist();
789 while (*argv)
790 zaddlinknode(l, ztrdup(*argv++));
791 freelinklist(dirstack, freestr);
792 dirstack = l;
793 unqueue_signals();
794 return 0;
795 }
796
797 /* cd, chdir, pushd, popd */
798
799 /**/
800 void
set_pwd_env(void)801 set_pwd_env(void)
802 {
803 Param pm;
804
805 /* update the PWD and OLDPWD shell parameters */
806
807 pm = (Param) paramtab->getnode(paramtab, "PWD");
808 if (pm && PM_TYPE(pm->node.flags) != PM_SCALAR) {
809 pm->node.flags &= ~PM_READONLY;
810 unsetparam_pm(pm, 0, 1);
811 }
812
813 pm = (Param) paramtab->getnode(paramtab, "OLDPWD");
814 if (pm && PM_TYPE(pm->node.flags) != PM_SCALAR) {
815 pm->node.flags &= ~PM_READONLY;
816 unsetparam_pm(pm, 0, 1);
817 }
818
819 assignsparam("PWD", ztrdup(pwd), 0);
820 assignsparam("OLDPWD", ztrdup(oldpwd), 0);
821
822 pm = (Param) paramtab->getnode(paramtab, "PWD");
823 if (!(pm->node.flags & PM_EXPORTED))
824 addenv(pm, pwd);
825 pm = (Param) paramtab->getnode(paramtab, "OLDPWD");
826 if (!(pm->node.flags & PM_EXPORTED))
827 addenv(pm, oldpwd);
828 }
829
830 /* set if we are resolving links to their true paths */
831 static int chasinglinks;
832
833 /* The main pwd changing function. The real work is done by other *
834 * functions. cd_get_dest() does the initial argument processing; *
835 * cd_do_chdir() actually changes directory, if possible; cd_new_pwd() *
836 * does the ancillary processing associated with actually changing *
837 * directory. */
838
839 /**/
840 int
bin_cd(char * nam,char ** argv,Options ops,int func)841 bin_cd(char *nam, char **argv, Options ops, int func)
842 {
843 LinkNode dir;
844 struct stat st1, st2;
845
846 if (isset(RESTRICTED)) {
847 zwarnnam(nam, "restricted");
848 return 1;
849 }
850 doprintdir = (doprintdir == -1);
851
852 chasinglinks = OPT_ISSET(ops,'P') ||
853 (isset(CHASELINKS) && !OPT_ISSET(ops,'L'));
854 queue_signals();
855 zpushnode(dirstack, ztrdup(pwd));
856 if (!(dir = cd_get_dest(nam, argv, OPT_ISSET(ops,'s'), func))) {
857 zsfree(getlinknode(dirstack));
858 unqueue_signals();
859 return 1;
860 }
861 cd_new_pwd(func, dir, OPT_ISSET(ops, 'q'));
862
863 if (stat(unmeta(pwd), &st1) < 0) {
864 setjobpwd();
865 zsfree(pwd);
866 pwd = NULL;
867 pwd = metafy(zgetcwd(), -1, META_DUP);
868 } else if (stat(".", &st2) < 0) {
869 if (chdir(unmeta(pwd)) < 0)
870 zwarn("unable to chdir(%s): %e", pwd, errno);
871 } else if (st1.st_ino != st2.st_ino || st1.st_dev != st2.st_dev) {
872 if (chasinglinks) {
873 setjobpwd();
874 zsfree(pwd);
875 pwd = NULL;
876 pwd = metafy(zgetcwd(), -1, META_DUP);
877 } else if (chdir(unmeta(pwd)) < 0)
878 zwarn("unable to chdir(%s): %e", pwd, errno);
879 }
880 unqueue_signals();
881 return 0;
882 }
883
884 /* Get directory to chdir to */
885
886 /**/
887 static LinkNode
cd_get_dest(char * nam,char ** argv,int hard,int func)888 cd_get_dest(char *nam, char **argv, int hard, int func)
889 {
890 LinkNode dir = NULL;
891 LinkNode target;
892 char *dest;
893
894 if (!argv[0]) {
895 if (func == BIN_POPD && !nextnode(firstnode(dirstack))) {
896 zwarnnam(nam, "directory stack empty");
897 return NULL;
898 }
899 if (func == BIN_PUSHD && unset(PUSHDTOHOME))
900 dir = nextnode(firstnode(dirstack));
901 if (dir)
902 zinsertlinknode(dirstack, dir, getlinknode(dirstack));
903 else if (func != BIN_POPD) {
904 if (!home) {
905 zwarnnam(nam, "HOME not set");
906 return NULL;
907 }
908 zpushnode(dirstack, ztrdup(home));
909 }
910 } else if (!argv[1]) {
911 int dd;
912 char *end;
913
914 doprintdir++;
915 if (!isset(POSIXCD) && argv[0][1] && (argv[0][0] == '+' || argv[0][0] == '-')
916 && strspn(argv[0]+1, "0123456789") == strlen(argv[0]+1)) {
917 dd = zstrtol(argv[0] + 1, &end, 10);
918 if (*end == '\0') {
919 if ((argv[0][0] == '+') ^ isset(PUSHDMINUS))
920 for (dir = firstnode(dirstack); dir && dd; dd--, incnode(dir));
921 else
922 for (dir = lastnode(dirstack); dir != (LinkNode) dirstack && dd;
923 dd--, dir = prevnode(dir));
924 if (!dir || dir == (LinkNode) dirstack) {
925 zwarnnam(nam, "no such entry in dir stack");
926 return NULL;
927 }
928 }
929 }
930 if (!dir)
931 zpushnode(dirstack, ztrdup(strcmp(argv[0], "-")
932 ? (doprintdir--, argv[0]) : oldpwd));
933 } else {
934 char *u, *d;
935 int len1, len2, len3;
936
937 if (!(u = strstr(pwd, argv[0]))) {
938 zwarnnam(nam, "string not in pwd: %s", argv[0]);
939 return NULL;
940 }
941 len1 = strlen(argv[0]);
942 len2 = strlen(argv[1]);
943 len3 = u - pwd;
944 d = (char *)zalloc(len3 + len2 + strlen(u + len1) + 1);
945 strncpy(d, pwd, len3);
946 strcpy(d + len3, argv[1]);
947 strcat(d, u + len1);
948 zpushnode(dirstack, d);
949 doprintdir++;
950 }
951
952 target = dir;
953 if (func == BIN_POPD) {
954 if (!dir) {
955 target = dir = firstnode(dirstack);
956 } else if (dir != firstnode(dirstack)) {
957 return dir;
958 }
959 dir = nextnode(dir);
960 }
961 if (!dir) {
962 dir = firstnode(dirstack);
963 }
964 if (!dir || !getdata(dir)) {
965 DPUTS(1, "Directory not set, not detected early enough");
966 return NULL;
967 }
968 if (!(dest = cd_do_chdir(nam, getdata(dir), hard))) {
969 if (!target)
970 zsfree(getlinknode(dirstack));
971 if (func == BIN_POPD)
972 zsfree(remnode(dirstack, dir));
973 return NULL;
974 }
975 if (dest != (char *)getdata(dir)) {
976 zsfree(getdata(dir));
977 setdata(dir, dest);
978 }
979 return target ? target : dir;
980 }
981
982 /* Change to given directory, if possible. This function works out *
983 * exactly how the directory should be interpreted, including cdpath *
984 * and CDABLEVARS. For each possible interpretation of the given *
985 * path, this calls cd_try_chdir(), which attempts to chdir to that *
986 * particular path. */
987
988 /**/
989 static char *
cd_do_chdir(char * cnam,char * dest,int hard)990 cd_do_chdir(char *cnam, char *dest, int hard)
991 {
992 char **pp, *ret;
993 int hasdot = 0, eno = ENOENT;
994 /*
995 * nocdpath indicates that cdpath should not be used.
996 * This is the case iff dest is a relative path
997 * whose first segment is . or .., but if the path is
998 * absolute then cdpath won't be used anyway.
999 */
1000 int nocdpath;
1001 #ifdef __CYGWIN__
1002 /*
1003 * Normalize path under Cygwin to avoid messing with
1004 * DOS style names with drives in them
1005 */
1006 static char buf[PATH_MAX+1];
1007 #ifdef HAVE_CYGWIN_CONV_PATH
1008 cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE, dest, buf,
1009 PATH_MAX);
1010 #else
1011 #ifndef _SYS_CYGWIN_H
1012 void cygwin_conv_to_posix_path(const char *, char *);
1013 #endif
1014
1015 cygwin_conv_to_posix_path(dest, buf);
1016 #endif
1017 dest = buf;
1018 #endif
1019 nocdpath = dest[0] == '.' &&
1020 (dest[1] == '/' || !dest[1] || (dest[1] == '.' &&
1021 (dest[2] == '/' || !dest[2])));
1022
1023 /*
1024 * If we have an absolute path, use it as-is only
1025 */
1026 if (*dest == '/') {
1027 if ((ret = cd_try_chdir(NULL, dest, hard)))
1028 return ret;
1029 zwarnnam(cnam, "%e: %s", errno, dest);
1030 return NULL;
1031 }
1032
1033 /*
1034 * If cdpath is being used, check it for ".".
1035 * Don't bother doing this if POSIXCD is set, we don't
1036 * need to know (though it doesn't actually matter).
1037 */
1038 if (!nocdpath && !isset(POSIXCD))
1039 for (pp = cdpath; *pp; pp++)
1040 if (!(*pp)[0] || ((*pp)[0] == '.' && (*pp)[1] == '\0'))
1041 hasdot = 1;
1042 /*
1043 * If
1044 * (- there is no . in cdpath
1045 * - or cdpath is not being used)
1046 * - and the POSIXCD option is not set
1047 * try the directory as-is (i.e. from .)
1048 */
1049 if (!hasdot && !isset(POSIXCD)) {
1050 if ((ret = cd_try_chdir(NULL, dest, hard)))
1051 return ret;
1052 if (errno != ENOENT)
1053 eno = errno;
1054 }
1055 /* if cdpath is being used, try given directory relative to each element in
1056 cdpath in turn */
1057 if (!nocdpath)
1058 for (pp = cdpath; *pp; pp++) {
1059 if ((ret = cd_try_chdir(*pp, dest, hard))) {
1060 if (isset(POSIXCD)) {
1061 /*
1062 * For POSIX we need to print the directory
1063 * any time CDPATH was used, except in the
1064 * special case of an empty segment being
1065 * treated as a ".".
1066 */
1067 if (**pp)
1068 doprintdir++;
1069 } else {
1070 if (strcmp(*pp, ".")) {
1071 doprintdir++;
1072 }
1073 }
1074 return ret;
1075 }
1076 if (errno != ENOENT)
1077 eno = errno;
1078 }
1079 /*
1080 * POSIX requires us to check "." after CDPATH rather than before.
1081 */
1082 if (isset(POSIXCD)) {
1083 if ((ret = cd_try_chdir(NULL, dest, hard)))
1084 return ret;
1085 if (errno != ENOENT)
1086 eno = errno;
1087 }
1088
1089 /* handle the CDABLEVARS option */
1090 if ((ret = cd_able_vars(dest))) {
1091 if ((ret = cd_try_chdir(NULL, ret,hard))) {
1092 doprintdir++;
1093 return ret;
1094 }
1095 if (errno != ENOENT)
1096 eno = errno;
1097 }
1098
1099 /* If we got here, it means that we couldn't chdir to any of the
1100 multitudinous possible paths allowed by zsh. We've run out of options!
1101 Add more here! */
1102 zwarnnam(cnam, "%e: %s", eno, dest);
1103 return NULL;
1104 }
1105
1106 /* If the CDABLEVARS option is set, return the new *
1107 * interpretation of the given path. */
1108
1109 /**/
1110 char *
cd_able_vars(char * s)1111 cd_able_vars(char *s)
1112 {
1113 char *rest, save;
1114
1115 if (isset(CDABLEVARS)) {
1116 for (rest = s; *rest && *rest != '/'; rest++);
1117 save = *rest;
1118 *rest = 0;
1119 s = getnameddir(s);
1120 *rest = save;
1121
1122 if (s && *rest)
1123 s = dyncat(s, rest);
1124
1125 return s;
1126 }
1127 return NULL;
1128 }
1129
1130 /* Attempt to change to a single given directory. The directory, *
1131 * for the convenience of the calling function, may be provided in *
1132 * two parts, which must be concatenated before attempting to chdir. *
1133 * Returns NULL if the chdir fails. If the directory change is *
1134 * possible, it is performed, and a pointer to the new full pathname *
1135 * is returned. */
1136
1137 /**/
1138 static char *
cd_try_chdir(char * pfix,char * dest,int hard)1139 cd_try_chdir(char *pfix, char *dest, int hard)
1140 {
1141 char *buf;
1142 int dlen, dochaselinks = 0;
1143
1144 /* handle directory prefix */
1145 if (pfix && *pfix) {
1146 if (*pfix == '/') {
1147 #ifdef __CYGWIN__
1148 /* NB: Don't turn "/"+"bin" into "//"+"bin" by mistake! "//bin" may *
1149 * not be what user really wants (probably wants "/bin"), but *
1150 * "//bin" could be valid too (see fixdir())! This is primarily for *
1151 * handling CDPATH correctly. Likewise for "//"+"bin" not becoming *
1152 * "///bin" (aka "/bin"). */
1153 int root = pfix[1] == '\0' || (pfix[1] == '/' && pfix[2] == '\0');
1154 buf = tricat(pfix, ( root ? "" : "/" ), dest);
1155 #else
1156 buf = tricat(pfix, "/", dest);
1157 #endif
1158 } else {
1159 int pfl = strlen(pfix);
1160 dlen = strlen(pwd);
1161 if (dlen == 1 && *pwd == '/')
1162 dlen = 0;
1163 buf = zalloc(dlen + pfl + strlen(dest) + 3);
1164 if (dlen)
1165 strcpy(buf, pwd);
1166 buf[dlen] = '/';
1167 strcpy(buf + dlen + 1, pfix);
1168 buf[dlen + 1 + pfl] = '/';
1169 strcpy(buf + dlen + pfl + 2, dest);
1170 }
1171 } else if (*dest == '/')
1172 buf = ztrdup(dest);
1173 else {
1174 dlen = strlen(pwd);
1175 if (pwd[dlen-1] == '/')
1176 --dlen;
1177 buf = zalloc(dlen + strlen(dest) + 2);
1178 strcpy(buf, pwd);
1179 buf[dlen] = '/';
1180 strcpy(buf + dlen + 1, dest);
1181 }
1182
1183 /* Normalise path. See the definition of fixdir() for what this means.
1184 * We do not do this if we are chasing links.
1185 */
1186 if (!chasinglinks)
1187 dochaselinks = fixdir(buf);
1188 else
1189 unmetafy(buf, &dlen);
1190
1191 /* We try the full path first. If that fails, try the
1192 * argument to cd relatively. This is useful if the cwd
1193 * or a parent directory is renamed in the interim.
1194 */
1195 if (lchdir(buf, NULL, hard) &&
1196 (pfix || *dest == '/' || lchdir(unmeta(dest), NULL, hard))) {
1197 free(buf);
1198 return NULL;
1199 }
1200 /* the chdir succeeded, so decide if we should force links to be chased */
1201 if (dochaselinks)
1202 chasinglinks = 1;
1203 return metafy(buf, -1, META_NOALLOC);
1204 }
1205
1206 /* do the extra processing associated with changing directory */
1207
1208 /**/
1209 static void
cd_new_pwd(int func,LinkNode dir,int quiet)1210 cd_new_pwd(int func, LinkNode dir, int quiet)
1211 {
1212 char *new_pwd, *s;
1213 int dirstacksize;
1214
1215 if (func == BIN_PUSHD)
1216 rolllist(dirstack, dir);
1217 new_pwd = remnode(dirstack, dir);
1218
1219 if (func == BIN_POPD && firstnode(dirstack)) {
1220 zsfree(new_pwd);
1221 new_pwd = getlinknode(dirstack);
1222 } else if (func == BIN_CD && unset(AUTOPUSHD))
1223 zsfree(getlinknode(dirstack));
1224
1225 if (chasinglinks) {
1226 s = findpwd(new_pwd);
1227 if (s) {
1228 zsfree(new_pwd);
1229 new_pwd = s;
1230 }
1231 }
1232 if (isset(PUSHDIGNOREDUPS)) {
1233 LinkNode n;
1234 for (n = firstnode(dirstack); n; incnode(n)) {
1235 if (!strcmp(new_pwd, getdata(n))) {
1236 zsfree(remnode(dirstack, n));
1237 break;
1238 }
1239 }
1240 }
1241
1242 /* shift around the pwd variables, to make oldpwd and pwd relate to the
1243 current (i.e. new) pwd */
1244 zsfree(oldpwd);
1245 oldpwd = pwd;
1246 setjobpwd();
1247 pwd = new_pwd;
1248 set_pwd_env();
1249
1250 if (isset(INTERACTIVE) || isset(POSIXCD)) {
1251 if (func != BIN_CD && isset(INTERACTIVE)) {
1252 if (unset(PUSHDSILENT) && !quiet)
1253 printdirstack();
1254 } else if (unset(CDSILENT) && doprintdir) {
1255 fprintdir(pwd, stdout);
1256 putchar('\n');
1257 }
1258 }
1259
1260 /* execute the chpwd function */
1261 fflush(stdout);
1262 fflush(stderr);
1263 if (!quiet)
1264 callhookfunc("chpwd", NULL, 1, NULL);
1265
1266 dirstacksize = getiparam("DIRSTACKSIZE");
1267 /* handle directory stack sizes out of range */
1268 if (dirstacksize > 0) {
1269 int remove = countlinknodes(dirstack) -
1270 (dirstacksize < 2 ? 2 : dirstacksize);
1271 while (remove-- >= 0)
1272 zsfree(remnode(dirstack, lastnode(dirstack)));
1273 }
1274 }
1275
1276 /* Print the directory stack */
1277
1278 /**/
1279 static void
printdirstack(void)1280 printdirstack(void)
1281 {
1282 LinkNode node;
1283
1284 fprintdir(pwd, stdout);
1285 for (node = firstnode(dirstack); node; incnode(node)) {
1286 putchar(' ');
1287 fprintdir(getdata(node), stdout);
1288 }
1289 putchar('\n');
1290 }
1291
1292 /* Normalise a path. Segments consisting of ., and foo/.. *
1293 * combinations, are removed and the path is unmetafied.
1294 * Returns 1 if we found a ../ path which should force links to
1295 * be chased, 0 otherwise.
1296 */
1297
1298 /**/
1299 int
fixdir(char * src)1300 fixdir(char *src)
1301 {
1302 char *dest = src, *d0 = dest;
1303 #ifdef __CYGWIN__
1304 char *s0 = src;
1305 #endif
1306 /* This function is always called with n path containing at
1307 * least one slash, either because one was input by the user or
1308 * because the caller has prepended either pwd or a cdpath dir.
1309 * If asked to make a relative change and pwd is set to ".",
1310 * the current directory has been removed out from under us,
1311 * so force links to be chased.
1312 *
1313 * Ordinarily we can't get here with "../" as the first component
1314 * but handle the silly special case of ".." in cdpath.
1315 *
1316 * Order of comparisons here looks funny, but it short-circuits
1317 * most rapidly in the event of a false condition. Set to 2
1318 * here so we still obey the (lack of) CHASEDOTS option after
1319 * the first "../" is preserved (test chasedots > 1 below).
1320 */
1321 int chasedots = (src[0] == '.' && pwd[0] == '.' && pwd[1] == '\0' &&
1322 (src[1] == '/' || (src[1] == '.' && src[2] == '/'))) * 2;
1323
1324 /*** if have RFS superroot directory ***/
1325 #ifdef HAVE_SUPERROOT
1326 /* allow /.. segments to remain */
1327 while (*src == '/' && src[1] == '.' && src[2] == '.' &&
1328 (!src[3] || src[3] == '/')) {
1329 *dest++ = '/';
1330 *dest++ = '.';
1331 *dest++ = '.';
1332 src += 3;
1333 }
1334 #endif
1335
1336 for (;;) {
1337 /* compress multiple /es into single */
1338 if (*src == '/') {
1339 #ifdef __CYGWIN__
1340 /* allow leading // under cygwin, but /// still becomes / */
1341 if (src == s0 && src[1] == '/' && src[2] != '/')
1342 *dest++ = *src++;
1343 #endif
1344 *dest++ = *src++;
1345 while (*src == '/')
1346 src++;
1347 }
1348 /* if we are at the end of the input path, remove a trailing / (if it
1349 exists), and return ct */
1350 if (!*src) {
1351 while (dest > d0 + 1 && dest[-1] == '/')
1352 dest--;
1353 *dest = '\0';
1354 return chasedots;
1355 }
1356 if (src[0] == '.' && src[1] == '.' &&
1357 (src[2] == '\0' || src[2] == '/')) {
1358 if (isset(CHASEDOTS) || chasedots > 1) {
1359 chasedots = 1;
1360 /* and treat as normal path segment */
1361 } else {
1362 if (dest > d0 + 1) {
1363 /*
1364 * remove a foo/.. combination:
1365 * first check foo exists, else return.
1366 */
1367 struct stat st;
1368 *dest = '\0';
1369 if (stat(d0, &st) < 0 || !S_ISDIR(st.st_mode)) {
1370 char *ptrd, *ptrs;
1371 if (dest == src)
1372 *dest = '.';
1373 for (ptrs = src, ptrd = dest; *ptrs; ptrs++, ptrd++)
1374 *ptrd = (*ptrs == Meta) ? (*++ptrs ^ 32) : *ptrs;
1375 *ptrd = '\0';
1376 return 1;
1377 }
1378 for (dest--; dest > d0 + 1 && dest[-1] != '/'; dest--);
1379 if (dest[-1] != '/')
1380 dest--;
1381 }
1382 src++;
1383 while (*++src == '/');
1384 continue;
1385 }
1386 }
1387 if (src[0] == '.' && (src[1] == '/' || src[1] == '\0')) {
1388 /* skip a . section */
1389 while (*++src == '/');
1390 } else {
1391 /* copy a normal segment into the output */
1392 while (*src != '/' && *src != '\0')
1393 if ((*dest++ = *src++) == Meta)
1394 dest[-1] = *src++ ^ 32;
1395 }
1396 }
1397 /* unreached */
1398 }
1399
1400 /**/
1401 mod_export void
printqt(char * str)1402 printqt(char *str)
1403 {
1404 /* Print str, but turn any single quote into '\'' or ''. */
1405 for (; *str; str++)
1406 if (*str == '\'')
1407 printf(isset(RCQUOTES) ? "''" : "'\\''");
1408 else
1409 putchar(*str);
1410 }
1411
1412 /**/
1413 mod_export void
printif(char * str,int c)1414 printif(char *str, int c)
1415 {
1416 /* If flag c has an argument, print that */
1417 if (str) {
1418 printf(" -%c ", c);
1419 quotedzputs(str, stdout);
1420 }
1421 }
1422
1423 /**** history list functions ****/
1424
1425 /* fc, history, r */
1426
1427 /**/
1428 int
bin_fc(char * nam,char ** argv,Options ops,int func)1429 bin_fc(char *nam, char **argv, Options ops, int func)
1430 {
1431 zlong first = -1, last = -1;
1432 int retval;
1433 char *s;
1434 struct asgment *asgf = NULL, *asgl = NULL;
1435 Patprog pprog = NULL;
1436
1437 /* fc is only permitted in interactive shells */
1438 #ifdef FACIST_INTERACTIVE
1439 if (!interact) {
1440 zwarnnam(nam, "not interactive shell");
1441 return 1;
1442 }
1443 #endif
1444 if (OPT_ISSET(ops,'p')) {
1445 char *hf = "";
1446 zlong hs = DEFAULT_HISTSIZE;
1447 zlong shs = 0;
1448 int level = OPT_ISSET(ops,'a') ? locallevel : -1;
1449 if (*argv) {
1450 hf = *argv++;
1451 if (*argv) {
1452 char *check;
1453 hs = zstrtol(*argv++, &check, 10);
1454 if (*check) {
1455 zwarnnam("fc", "HISTSIZE must be an integer");
1456 return 1;
1457 }
1458 if (*argv) {
1459 shs = zstrtol(*argv++, &check, 10);
1460 if (*check) {
1461 zwarnnam("fc", "SAVEHIST must be an integer");
1462 return 1;
1463 }
1464 } else
1465 shs = hs;
1466 if (*argv) {
1467 zwarnnam("fc", "too many arguments");
1468 return 1;
1469 }
1470 } else {
1471 hs = histsiz;
1472 shs = savehistsiz;
1473 }
1474 }
1475 if (!pushhiststack(hf, hs, shs, level))
1476 return 1;
1477 if (*hf) {
1478 struct stat st;
1479 if (stat(hf, &st) >= 0 || errno != ENOENT)
1480 readhistfile(hf, 1, HFILE_USE_OPTIONS);
1481 }
1482 return 0;
1483 }
1484 if (OPT_ISSET(ops,'P')) {
1485 if (*argv) {
1486 zwarnnam("fc", "too many arguments");
1487 return 1;
1488 }
1489 return !saveandpophiststack(-1, HFILE_USE_OPTIONS);
1490 }
1491 /* with the -m option, the first argument is taken *
1492 * as a pattern that history lines have to match */
1493 if (*argv && OPT_ISSET(ops,'m')) {
1494 tokenize(*argv);
1495 if (!(pprog = patcompile(*argv++, 0, NULL))) {
1496 zwarnnam(nam, "invalid match pattern");
1497 return 1;
1498 }
1499 }
1500 queue_signals();
1501 if (OPT_ISSET(ops,'R')) {
1502 /* read history from a file */
1503 readhistfile(*argv, 1, OPT_ISSET(ops,'I') ? HFILE_SKIPOLD : 0);
1504 unqueue_signals();
1505 return 0;
1506 }
1507 if (OPT_ISSET(ops,'W')) {
1508 /* write history to a file */
1509 savehistfile(*argv, 1, OPT_ISSET(ops,'I') ? HFILE_SKIPOLD : 0);
1510 unqueue_signals();
1511 return 0;
1512 }
1513 if (OPT_ISSET(ops,'A')) {
1514 /* append history to a file */
1515 savehistfile(*argv, 1, HFILE_APPEND |
1516 (OPT_ISSET(ops,'I') ? HFILE_SKIPOLD : 0));
1517 unqueue_signals();
1518 return 0;
1519 }
1520
1521 if (zleactive) {
1522 unqueue_signals();
1523 zwarnnam(nam, "no interactive history within ZLE");
1524 return 1;
1525 }
1526
1527 /* put foo=bar type arguments into the substitution list */
1528 while (*argv && equalsplit(*argv, &s)) {
1529 Asgment a = (Asgment) zhalloc(sizeof *a);
1530
1531 if (!**argv) {
1532 zwarnnam(nam, "invalid replacement pattern: =%s", s);
1533 return 1;
1534 }
1535 if (!asgf)
1536 asgf = asgl = a;
1537 else {
1538 asgl->node.next = &a->node;
1539 asgl = a;
1540 }
1541 a->name = *argv;
1542 a->flags = 0;
1543 a->value.scalar = s;
1544 a->node.next = a->node.prev = NULL;
1545 argv++;
1546 }
1547 /* interpret and check first history line specifier */
1548 if (*argv) {
1549 first = fcgetcomm(*argv);
1550 if (first == -1) {
1551 unqueue_signals();
1552 return 1;
1553 }
1554 argv++;
1555 }
1556 /* interpret and check second history line specifier */
1557 if (*argv) {
1558 last = fcgetcomm(*argv);
1559 if (last == -1) {
1560 unqueue_signals();
1561 return 1;
1562 }
1563 argv++;
1564 }
1565 /* There is a maximum of two history specifiers. At least, there *
1566 * will be as long as the history list is one-dimensional. */
1567 if (*argv) {
1568 unqueue_signals();
1569 zwarnnam("fc", "too many arguments");
1570 return 1;
1571 }
1572 /* default values of first and last, and range checking */
1573 if (last == -1) {
1574 if (OPT_ISSET(ops,'l') && first < curhist) {
1575 /*
1576 * When listing base our calculations on curhist,
1577 * to show anything added since the edited history line.
1578 * Also, in that case curhist will have been modified
1579 * past the current history line; then we want to
1580 * show everything, because the user expects to
1581 * see the result of "print -s". Otherwise, we subtract
1582 * -1 from the line, because the user doesn't usually expect
1583 * to see the command line that caused history to be
1584 * listed.
1585 */
1586 last = (curline.histnum == curhist) ? addhistnum(curhist,-1,0)
1587 : curhist;
1588 if (last < firsthist())
1589 last = firsthist();
1590 }
1591 else
1592 last = first;
1593 }
1594 if (first == -1) {
1595 /*
1596 * When listing, we want to see everything that's been
1597 * added to the history, including by print -s, so use
1598 * curhist.
1599 * When reexecuting, we want to restrict to the last edited
1600 * command line to avoid giving the user a nasty turn
1601 * if some helpful soul ran "print -s 'rm -rf /'".
1602 */
1603 first = OPT_ISSET(ops,'l')? addhistnum(curhist,-16,0)
1604 : addhistnum(curline.histnum,-1,0);
1605 if (first < 1)
1606 first = 1;
1607 if (last < first)
1608 last = first;
1609 }
1610 if (OPT_ISSET(ops,'l')) {
1611 /* list the required part of the history */
1612 retval = fclist(stdout, ops, first, last, asgf, pprog, 0);
1613 unqueue_signals();
1614 }
1615 else {
1616 /* edit history file, and (if successful) use the result as a new command */
1617 int tempfd;
1618 FILE *out;
1619 char *fil;
1620
1621 retval = 1;
1622 if ((tempfd = gettempfile(NULL, 1, &fil)) < 0
1623 || ((out = fdopen(tempfd, "w")) == NULL)) {
1624 unqueue_signals();
1625 zwarnnam("fc", "can't open temp file: %e", errno);
1626 } else {
1627 /*
1628 * Nasty behaviour results if we use the current history
1629 * line here. Treat it as if it doesn't exist, unless
1630 * that gives us an empty range.
1631 */
1632 if (last >= curhist) {
1633 last = curhist - 1;
1634 if (first > last) {
1635 unqueue_signals();
1636 zwarnnam("fc",
1637 "current history line would recurse endlessly, aborted");
1638 fclose(out);
1639 unlink(fil);
1640 return 1;
1641 }
1642 }
1643 ops->ind['n'] = 1; /* No line numbers here. */
1644 if (!fclist(out, ops, first, last, asgf, pprog, 1)) {
1645 char *editor;
1646
1647 if (func == BIN_R)
1648 editor = "-";
1649 else if (OPT_HASARG(ops, 'e'))
1650 editor = OPT_ARG(ops, 'e');
1651 else
1652 editor = getsparam("FCEDIT");
1653 if (!editor)
1654 editor = getsparam("EDITOR");
1655 if (!editor)
1656 editor = DEFAULT_FCEDIT;
1657
1658 unqueue_signals();
1659 if (fcedit(editor, fil)) {
1660 if (stuff(fil))
1661 zwarnnam("fc", "%e: %s", errno, fil);
1662 else {
1663 loop(0,1);
1664 retval = lastval;
1665 }
1666 }
1667 } else
1668 unqueue_signals();
1669 }
1670 unlink(fil);
1671 }
1672 return retval;
1673 }
1674
1675 /* History handling functions: these are called by ZLE, as well as *
1676 * the actual builtins. fcgetcomm() gets a history line, specified *
1677 * either by number or leading string. fcsubs() performs a given *
1678 * set of simple old=new substitutions on a given command line. *
1679 * fclist() outputs a given range of history lines to a text file. */
1680
1681 /* get the history event associated with s */
1682
1683 /**/
1684 static zlong
fcgetcomm(char * s)1685 fcgetcomm(char *s)
1686 {
1687 zlong cmd;
1688
1689 /* First try to match a history number. Negative *
1690 * numbers indicate reversed numbering. */
1691 if ((cmd = atoi(s)) != 0 || *s == '0') {
1692 if (cmd < 0)
1693 cmd = addhistnum(curline.histnum,cmd,HIST_FOREIGN);
1694 if (cmd < 0)
1695 cmd = 0;
1696 return cmd;
1697 }
1698 /* not a number, so search by string */
1699 cmd = hcomsearch(s);
1700 if (cmd == -1)
1701 zwarnnam("fc", "event not found: %s", s);
1702 return cmd;
1703 }
1704
1705 /* Perform old=new substitutions. Uses the asgment structure from zsh.h, *
1706 * which is essentially a linked list of string,replacement pairs. */
1707
1708 /**/
1709 static int
fcsubs(char ** sp,struct asgment * sub)1710 fcsubs(char **sp, struct asgment *sub)
1711 {
1712 char *oldstr, *newstr, *oldpos, *newpos, *newmem, *s = *sp;
1713 int subbed = 0;
1714
1715 /* loop through the linked list */
1716 while (sub) {
1717 oldstr = sub->name;
1718 newstr = sub->value.scalar;
1719 sub = (Asgment)sub->node.next;
1720 oldpos = s;
1721 /* loop over occurrences of oldstr in s, replacing them with newstr */
1722 while ((newpos = (char *)strstr(oldpos, oldstr))) {
1723 newmem = (char *) zhalloc(1 + (newpos - s)
1724 + strlen(newstr) + strlen(newpos + strlen(oldstr)));
1725 ztrncpy(newmem, s, newpos - s);
1726 strcat(newmem, newstr);
1727 oldpos = newmem + strlen(newmem);
1728 strcat(newmem, newpos + strlen(oldstr));
1729 s = newmem;
1730 subbed = 1;
1731 }
1732 }
1733 *sp = s;
1734 return subbed;
1735 }
1736
1737 /* Print a series of history events to a file. The file pointer is *
1738 * given by f, and the required range of events by first and last. *
1739 * subs is an optional list of foo=bar substitutions to perform on the *
1740 * history lines before output. com is an optional comp structure *
1741 * that the history lines are required to match. n, r, D and d are *
1742 * options: n indicates that each line should be numbered. r indicates *
1743 * that the lines should be output in reverse order (newest first). *
1744 * D indicates that the real time taken by each command should be *
1745 * output. d indicates that the time of execution of each command *
1746 * should be output; d>1 means that the date should be output too; d>3 *
1747 * means that mm/dd/yyyy form should be used for the dates, as opposed *
1748 * to dd.mm.yyyy form; d>7 means that yyyy-mm-dd form should be used. */
1749
1750 /**/
1751 static int
fclist(FILE * f,Options ops,zlong first,zlong last,struct asgment * subs,Patprog pprog,int is_command)1752 fclist(FILE *f, Options ops, zlong first, zlong last,
1753 struct asgment *subs, Patprog pprog, int is_command)
1754 {
1755 int fclistdone = 0, xflags = 0;
1756 zlong tmp;
1757 char *s, *tdfmt, *timebuf;
1758 Histent ent;
1759
1760 /* reverse range if required */
1761 if (OPT_ISSET(ops,'r')) {
1762 tmp = last;
1763 last = first;
1764 first = tmp;
1765 }
1766 if (is_command && first > last) {
1767 zwarnnam("fc", "history events can't be executed backwards, aborted");
1768 if (f != stdout)
1769 fclose(f);
1770 return 1;
1771 }
1772
1773 ent = gethistent(first, first < last? GETHIST_DOWNWARD : GETHIST_UPWARD);
1774 if (!ent || (first < last? ent->histnum > last : ent->histnum < last)) {
1775 if (first == last) {
1776 char buf[DIGBUFSIZE];
1777 convbase(buf, first, 10);
1778 zwarnnam("fc", "no such event: %s", buf);
1779 } else
1780 zwarnnam("fc", "no events in that range");
1781 if (f != stdout)
1782 fclose(f);
1783 return 1;
1784 }
1785
1786 if (OPT_ISSET(ops,'d') || OPT_ISSET(ops,'f') ||
1787 OPT_ISSET(ops,'E') || OPT_ISSET(ops,'i') ||
1788 OPT_ISSET(ops,'t')) {
1789 if (OPT_ISSET(ops,'t')) {
1790 tdfmt = OPT_ARG(ops,'t');
1791 } else if (OPT_ISSET(ops,'i')) {
1792 tdfmt = "%Y-%m-%d %H:%M";
1793 } else if (OPT_ISSET(ops,'E')) {
1794 tdfmt = "%f.%-m.%Y %H:%M";
1795 } else if (OPT_ISSET(ops,'f')) {
1796 tdfmt = "%-m/%f/%Y %H:%M";
1797 } else {
1798 tdfmt = "%H:%M";
1799 }
1800 timebuf = zhalloc(256);
1801 } else {
1802 tdfmt = timebuf = NULL;
1803 }
1804
1805 /* xflags exclude events */
1806 if (OPT_ISSET(ops,'L')) {
1807 xflags |= HIST_FOREIGN;
1808 }
1809 if (OPT_ISSET(ops,'I')) {
1810 xflags |= HIST_READ;
1811 }
1812
1813 for (;;) {
1814 if (ent->node.flags & xflags)
1815 s = NULL;
1816 else
1817 s = dupstring(ent->node.nam);
1818 /* this if does the pattern matching, if required */
1819 if (s && (!pprog || pattry(pprog, s))) {
1820 /* perform substitution */
1821 fclistdone |= (subs ? fcsubs(&s, subs) : 1);
1822
1823 /* do numbering */
1824 if (!OPT_ISSET(ops,'n')) {
1825 char buf[DIGBUFSIZE];
1826 convbase(buf, ent->histnum, 10);
1827 fprintf(f, "%5s%c ", buf,
1828 ent->node.flags & HIST_FOREIGN ? '*' : ' ');
1829 }
1830 /* output actual time (and possibly date) of execution of the
1831 command, if required */
1832 if (tdfmt != NULL) {
1833 struct tm *ltm;
1834 int len;
1835 ltm = localtime(&ent->stim);
1836 if ((len = ztrftime(timebuf, 256, tdfmt, ltm, 0L)) >= 0) {
1837 fwrite(timebuf, 1, len, f);
1838 fprintf(f, " ");
1839 }
1840 }
1841 /* display the time taken by the command, if required */
1842 if (OPT_ISSET(ops,'D')) {
1843 long diff;
1844 diff = (ent->ftim) ? ent->ftim - ent->stim : 0;
1845 fprintf(f, "%ld:%02ld ", diff / 60, diff % 60);
1846 }
1847
1848 /* output the command */
1849 if (f == stdout) {
1850 nicezputs(s, f);
1851 putc('\n', f);
1852 } else {
1853 int len;
1854 unmetafy(s, &len);
1855 fwrite(s, 1, len, f);
1856 putc('\n', f);
1857 }
1858 }
1859 /* move on to the next history line, or quit the loop */
1860 if (first < last) {
1861 if (!(ent = down_histent(ent)) || ent->histnum > last)
1862 break;
1863 }
1864 else {
1865 if (!(ent = up_histent(ent)) || ent->histnum < last)
1866 break;
1867 }
1868 }
1869
1870 /* final processing */
1871 if (f != stdout)
1872 fclose(f);
1873 if (!fclistdone) {
1874 if (subs)
1875 zwarnnam("fc", "no substitutions performed");
1876 else if (xflags || pprog)
1877 zwarnnam("fc", "no matching events found");
1878 return 1;
1879 }
1880 return 0;
1881 }
1882
1883 /* edit a history file */
1884
1885 /**/
1886 static int
fcedit(char * ename,char * fn)1887 fcedit(char *ename, char *fn)
1888 {
1889 char *s;
1890
1891 if (!strcmp(ename, "-"))
1892 return 1;
1893
1894 s = tricat(ename, " ", fn);
1895 execstring(s, 1, 0, "fc");
1896 zsfree(s);
1897
1898 return !lastval;
1899 }
1900
1901 /**** parameter builtins ****/
1902
1903 /* Separate an argument into name=value parts, returning them in an *
1904 * asgment structure. Because the asgment structure used is global, *
1905 * only one of these can be active at a time. The string s gets placed *
1906 * in this global structure, so it needs to be in permanent memory. */
1907
1908 /**/
1909 static Asgment
getasg(char *** argvp,LinkList assigns)1910 getasg(char ***argvp, LinkList assigns)
1911 {
1912 char *s = **argvp;
1913 static struct asgment asg;
1914
1915 /* sanity check for valid argument */
1916 if (!s) {
1917 if (assigns) {
1918 Asgment asgp = (Asgment)firstnode(assigns);
1919 if (!asgp)
1920 return NULL;
1921 (void)uremnode(assigns, &asgp->node);
1922 return asgp;
1923 }
1924 return NULL;
1925 }
1926
1927 /* check if name is empty */
1928 if (*s == '=') {
1929 zerr("bad assignment");
1930 return NULL;
1931 }
1932 asg.name = s;
1933 asg.flags = 0;
1934
1935 /* search for `=' */
1936 for (; *s && *s != '='; s++);
1937
1938 /* found `=', so return with a value */
1939 if (*s) {
1940 *s = '\0';
1941 asg.value.scalar = s + 1;
1942 } else {
1943 /* didn't find `=', so we only have a name */
1944 asg.value.scalar = NULL;
1945 }
1946 (*argvp)++;
1947 return &asg;
1948 }
1949
1950 /* for new special parameters */
1951 enum {
1952 NS_NONE,
1953 NS_NORMAL,
1954 NS_SECONDS
1955 };
1956
1957 static const struct gsu_scalar tiedarr_gsu =
1958 { tiedarrgetfn, tiedarrsetfn, tiedarrunsetfn };
1959
1960 /* Install a base if we are turning on a numeric option with an argument */
1961
1962 static int
typeset_setbase(const char * name,Param pm,Options ops,int on,int always)1963 typeset_setbase(const char *name, Param pm, Options ops, int on, int always)
1964 {
1965 char *arg = NULL;
1966
1967 if ((on & PM_INTEGER) && OPT_HASARG(ops,'i'))
1968 arg = OPT_ARG(ops,'i');
1969 else if ((on & PM_EFLOAT) && OPT_HASARG(ops,'E'))
1970 arg = OPT_ARG(ops,'E');
1971 else if ((on & PM_FFLOAT) && OPT_HASARG(ops,'F'))
1972 arg = OPT_ARG(ops,'F');
1973
1974 if (arg) {
1975 char *eptr;
1976 int base = (int)zstrtol(arg, &eptr, 10);
1977 if (*eptr) {
1978 if (on & PM_INTEGER)
1979 zwarnnam(name, "bad base value: %s", arg);
1980 else
1981 zwarnnam(name, "bad precision value: %s", arg);
1982 return 1;
1983 }
1984 if ((on & PM_INTEGER) && (base < 2 || base > 36)) {
1985 zwarnnam(name, "invalid base (must be 2 to 36 inclusive): %d",
1986 base);
1987 return 1;
1988 }
1989 pm->base = base;
1990 } else if (always)
1991 pm->base = 0;
1992
1993 return 0;
1994 }
1995
1996 /* Install a width if we are turning on a padding option with an argument */
1997
1998 static int
typeset_setwidth(const char * name,Param pm,Options ops,int on,int always)1999 typeset_setwidth(const char * name, Param pm, Options ops, int on, int always)
2000 {
2001 char *arg = NULL;
2002
2003 if ((on & PM_LEFT) && OPT_HASARG(ops,'L'))
2004 arg = OPT_ARG(ops,'L');
2005 else if ((on & PM_RIGHT_B) && OPT_HASARG(ops,'R'))
2006 arg = OPT_ARG(ops,'R');
2007 else if ((on & PM_RIGHT_Z) && OPT_HASARG(ops,'Z'))
2008 arg = OPT_ARG(ops,'Z');
2009
2010 if (arg) {
2011 char *eptr;
2012 pm->width = (int)zstrtol(arg, &eptr, 10);
2013 if (*eptr) {
2014 zwarnnam(name, "bad width value: %s", arg);
2015 return 1;
2016 }
2017 } else if (always)
2018 pm->width = 0;
2019
2020 return 0;
2021 }
2022
2023 /* function to set a single parameter */
2024
2025 /**/
2026 static Param
typeset_single(char * cname,char * pname,Param pm,UNUSED (int func),int on,int off,int roff,Asgment asg,Param altpm,Options ops,int joinchar)2027 typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
2028 int on, int off, int roff, Asgment asg, Param altpm,
2029 Options ops, int joinchar)
2030 {
2031 int usepm, tc, keeplocal = 0, newspecial = NS_NONE, readonly, dont_set = 0;
2032 char *subscript;
2033
2034 /*
2035 * Do we use the existing pm? Note that this isn't the end of the
2036 * story, because if we try and create a new pm at the same
2037 * locallevel as an unset one we use the pm struct anyway: that's
2038 * handled in createparam(). Here we just avoid using it for the
2039 * present tests if it's unset.
2040 *
2041 * POSIXBUILTINS horror: we need to retain the 'readonly' or 'export'
2042 * flags of an unset parameter.
2043 */
2044 usepm = pm && (!(pm->node.flags & PM_UNSET) ||
2045 (isset(POSIXBUILTINS) &&
2046 (pm->node.flags & (PM_READONLY|PM_EXPORTED))));
2047
2048 /*
2049 * We need to compare types with an existing pm if special,
2050 * even if that's unset
2051 */
2052 if (!usepm && pm && (pm->node.flags & PM_SPECIAL))
2053 usepm = 2; /* indicate that we preserve the PM_UNSET flag */
2054
2055 /*
2056 * Don't use an existing param if
2057 * - the local level has changed, and
2058 * - we are really locallizing the parameter
2059 */
2060 if (usepm && locallevel != pm->level && (on & PM_LOCAL)) {
2061 /*
2062 * If the original parameter was special and we're creating
2063 * a new one, we need to keep it special.
2064 *
2065 * The -h (hide) flag prevents an existing special being made
2066 * local. It can be applied either to the special or in the
2067 * typeset/local statement for the local variable.
2068 */
2069 if ((pm->node.flags & PM_SPECIAL)
2070 && !(on & PM_HIDE) && !(pm->node.flags & PM_HIDE & ~off))
2071 newspecial = NS_NORMAL;
2072 usepm = 0;
2073 }
2074
2075 /* attempting a type conversion, or making a tied colonarray? */
2076 tc = 0;
2077 if (ASG_ARRAYP(asg) && PM_TYPE(on) == PM_SCALAR &&
2078 !(usepm && (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED))))
2079 on |= PM_ARRAY;
2080 if (usepm && ASG_ARRAYP(asg) && newspecial == NS_NONE &&
2081 PM_TYPE(pm->node.flags) != PM_ARRAY &&
2082 PM_TYPE(pm->node.flags) != PM_HASHED) {
2083 if (on & (PM_EFLOAT|PM_FFLOAT|PM_INTEGER)) {
2084 zerrnam(cname, "%s: can't assign array value to non-array", pname);
2085 return NULL;
2086 }
2087 if (pm->node.flags & PM_SPECIAL) {
2088 zerrnam(cname, "%s: can't assign array value to non-array special", pname);
2089 return NULL;
2090 }
2091 tc = 1;
2092 usepm = 0;
2093 }
2094 else if (usepm || newspecial != NS_NONE) {
2095 int chflags = ((off & pm->node.flags) | (on & ~pm->node.flags)) &
2096 (PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_HASHED|
2097 PM_ARRAY|PM_TIED|PM_AUTOLOAD);
2098 /* keep the parameter if just switching between floating types */
2099 if ((tc = chflags && chflags != (PM_EFLOAT|PM_FFLOAT)))
2100 usepm = 0;
2101 }
2102
2103 /*
2104 * Extra checks if converting the type of a parameter, or if
2105 * trying to remove readonlyness. It's dangerous doing either
2106 * with a special or a parameter which isn't loaded yet (which
2107 * may be special when it is loaded; we can't tell yet).
2108 */
2109 if ((readonly =
2110 ((usepm || newspecial != NS_NONE) &&
2111 (off & pm->node.flags & PM_READONLY))) ||
2112 tc) {
2113 if (pm->node.flags & PM_SPECIAL) {
2114 int err = 1;
2115 if (!readonly && !strcmp(pname, "SECONDS"))
2116 {
2117 /*
2118 * We allow SECONDS to change type between integer
2119 * and floating point. If we are creating a new
2120 * local copy we check the type here and allow
2121 * a new special to be created with that type.
2122 * We then need to make sure the correct type
2123 * for the special is restored at the end of the scope.
2124 * If we are changing the type of an existing
2125 * parameter, we do the whole thing here.
2126 */
2127 if (newspecial != NS_NONE)
2128 {
2129 /*
2130 * The first test allows `typeset' to copy the
2131 * existing type. This is the usual behaviour
2132 * for making special parameters local.
2133 */
2134 if (PM_TYPE(on) == 0 || PM_TYPE(on) == PM_INTEGER ||
2135 PM_TYPE(on) == PM_FFLOAT || PM_TYPE(on) == PM_EFLOAT)
2136 {
2137 newspecial = NS_SECONDS;
2138 err = 0; /* and continue */
2139 tc = 0; /* but don't do a normal conversion */
2140 }
2141 } else if (!setsecondstype(pm, on, off)) {
2142 if (asg->value.scalar &&
2143 !(pm = assignsparam(
2144 pname, ztrdup(asg->value.scalar), 0)))
2145 return NULL;
2146 usepm = 1;
2147 err = 0;
2148 }
2149 }
2150 if (err)
2151 {
2152 zerrnam(cname, "%s: can't change type of a special parameter",
2153 pname);
2154 return NULL;
2155 }
2156 } else if (pm->node.flags & PM_AUTOLOAD) {
2157 zerrnam(cname, "%s: can't change type of autoloaded parameter",
2158 pname);
2159 return NULL;
2160 }
2161 }
2162 else if (newspecial != NS_NONE && strcmp(pname, "SECONDS") == 0)
2163 newspecial = NS_SECONDS;
2164
2165 if (isset(POSIXBUILTINS)) {
2166 /*
2167 * Stricter rules about retaining readonly attribute in this case.
2168 */
2169 if ((on & (PM_READONLY|PM_EXPORTED)) &&
2170 (!usepm || (pm->node.flags & PM_UNSET)) &&
2171 !ASG_VALUEP(asg))
2172 on |= PM_UNSET;
2173 else if (usepm && (pm->node.flags & PM_READONLY) &&
2174 !(on & PM_READONLY) && func != BIN_EXPORT) {
2175 zerr("read-only variable: %s", pm->node.nam);
2176 return NULL;
2177 }
2178 /* This is handled by createparam():
2179 if (usepm && (pm->node.flags & PM_EXPORTED) && !(off & PM_EXPORTED))
2180 on |= PM_EXPORTED;
2181 */
2182 }
2183
2184 /*
2185 * A parameter will be local if
2186 * 1. we are re-using an existing local parameter
2187 * or
2188 * 2. we are not using an existing parameter, but
2189 * i. there is already a parameter, which will be hidden
2190 * or
2191 * ii. we are creating a new local parameter
2192 */
2193 if (usepm) {
2194 if ((asg->flags & ASG_ARRAY) ?
2195 !(PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)) :
2196 (asg->value.scalar && (PM_TYPE(pm->node.flags &
2197 (PM_ARRAY|PM_HASHED))))) {
2198 zerrnam(cname, "%s: inconsistent type for assignment", pname);
2199 return NULL;
2200 }
2201 on &= ~PM_LOCAL;
2202 if (!on && !roff && !ASG_VALUEP(asg)) {
2203 if (OPT_ISSET(ops,'p'))
2204 paramtab->printnode(&pm->node, PRINT_TYPESET);
2205 else if (!OPT_ISSET(ops,'g') &&
2206 (unset(TYPESETSILENT) || OPT_ISSET(ops,'m')))
2207 paramtab->printnode(&pm->node, PRINT_INCLUDEVALUE);
2208 return pm;
2209 }
2210 if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
2211 zerrnam(cname, "%s: restricted", pname);
2212 return pm;
2213 }
2214 if ((on & PM_UNIQUE) && !(pm->node.flags & PM_READONLY & ~off)) {
2215 Param apm;
2216 char **x;
2217 if (PM_TYPE(pm->node.flags) == PM_ARRAY) {
2218 x = (*pm->gsu.a->getfn)(pm);
2219 uniqarray(x);
2220 if (pm->node.flags & PM_SPECIAL) {
2221 if (zheapptr(x))
2222 x = zarrdup(x);
2223 (*pm->gsu.a->setfn)(pm, x);
2224 } else if (pm->ename && x)
2225 arrfixenv(pm->ename, x);
2226 } else if (PM_TYPE(pm->node.flags) == PM_SCALAR && pm->ename &&
2227 (apm =
2228 (Param) paramtab->getnode(paramtab, pm->ename))) {
2229 x = (*apm->gsu.a->getfn)(apm);
2230 uniqarray(x);
2231 if (x)
2232 arrfixenv(pm->node.nam, x);
2233 }
2234 }
2235 if (usepm == 2) /* do not change the PM_UNSET flag */
2236 pm->node.flags = (pm->node.flags | (on & ~PM_READONLY)) & ~off;
2237 else {
2238 /*
2239 * Keep unset if using readonly in POSIX mode.
2240 */
2241 if (!(on & PM_READONLY) || !isset(POSIXBUILTINS))
2242 off |= PM_UNSET;
2243 pm->node.flags = (pm->node.flags |
2244 (on & ~PM_READONLY)) & ~off;
2245 }
2246 if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) {
2247 if (typeset_setwidth(cname, pm, ops, on, 0))
2248 return NULL;
2249 }
2250 if (on & (PM_INTEGER | PM_EFLOAT | PM_FFLOAT)) {
2251 if (typeset_setbase(cname, pm, ops, on, 0))
2252 return NULL;
2253 }
2254 if (!(pm->node.flags & (PM_ARRAY|PM_HASHED))) {
2255 if (pm->node.flags & PM_EXPORTED) {
2256 if (!(pm->node.flags & PM_UNSET) && !pm->env && !ASG_VALUEP(asg))
2257 addenv(pm, getsparam(pname));
2258 } else if (pm->env && !(pm->node.flags & PM_HASHELEM))
2259 delenv(pm);
2260 DPUTS(ASG_ARRAYP(asg), "BUG: typeset got array value where scalar expected");
2261 if (altpm && !(pm->node.flags & PM_SPECIAL)) {
2262 struct tieddata* tdp = (struct tieddata *) pm->u.data;
2263 if (tdp) {
2264 if (tdp->joinchar != joinchar && !asg->value.scalar) {
2265 /*
2266 * Reassign the scalar to itself to do the splitting with
2267 * the new joinchar
2268 */
2269 tdp->joinchar = joinchar;
2270 if (!(pm = assignsparam(pname, ztrdup(getsparam(pname)), 0)))
2271 return NULL;
2272 }
2273 }
2274 else
2275 DPUTS(!tdp, "BUG: no join character to update");
2276 }
2277 if (asg->value.scalar &&
2278 !(pm = assignsparam(pname, ztrdup(asg->value.scalar), 0)))
2279 return NULL;
2280 } else if (asg->flags & ASG_ARRAY) {
2281 int flags = (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0;
2282 if (!(pm = assignaparam(pname, asg->value.array ?
2283 zlinklist2array(asg->value.array) :
2284 mkarray(NULL), flags)))
2285 return NULL;
2286 }
2287 if (errflag)
2288 return NULL;
2289 pm->node.flags |= (on & PM_READONLY);
2290 if (OPT_ISSET(ops,'p'))
2291 paramtab->printnode(&pm->node, PRINT_TYPESET);
2292 return pm;
2293 }
2294
2295 if ((asg->flags & ASG_ARRAY) ?
2296 !(on & (PM_ARRAY|PM_HASHED)) :
2297 (asg->value.scalar && (on & (PM_ARRAY|PM_HASHED)))) {
2298 zerrnam(cname, "%s: inconsistent type for assignment", pname);
2299 return NULL;
2300 }
2301
2302 /*
2303 * We're here either because we're creating a new parameter,
2304 * or we're adding a parameter at a different local level,
2305 * or we're converting the type of a parameter. In the
2306 * last case only, we need to delete the old parameter.
2307 */
2308 if (tc) {
2309 /* Maintain existing readonly/exported status... */
2310 on |= ~off & (PM_READONLY|PM_EXPORTED) & pm->node.flags;
2311 /* ...but turn off existing readonly so we can delete it */
2312 pm->node.flags &= ~PM_READONLY;
2313 /*
2314 * If we're just changing the type, we should keep the
2315 * variable at the current level of localness.
2316 */
2317 keeplocal = pm->level;
2318 /*
2319 * Try to carry over a value, but not when changing from,
2320 * to, or between non-scalar types.
2321 *
2322 * (We can do better now, but it does have user-visible
2323 * implications.)
2324 */
2325 if (!ASG_VALUEP(asg) && !((pm->node.flags|on) & (PM_ARRAY|PM_HASHED))) {
2326 asg->value.scalar = dupstring(getsparam(pname));
2327 asg->flags = 0;
2328 }
2329 /* pname may point to pm->nam which is about to disappear */
2330 pname = dupstring(pname);
2331 unsetparam_pm(pm, 0, 1);
2332 }
2333
2334 if (newspecial != NS_NONE) {
2335 Param tpm, pm2;
2336 if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
2337 zerrnam(cname, "%s: restricted", pname);
2338 return pm;
2339 }
2340 if (pm->node.flags & PM_SINGLE) {
2341 zerrnam(cname, "%s: can only have a single instance", pname);
2342 return pm;
2343 }
2344
2345 on |= pm->node.flags & PM_TIED;
2346
2347 /*
2348 * For specials, we keep the same struct but zero everything.
2349 * Maybe it would be easier to create a new struct but copy
2350 * the get/set methods.
2351 */
2352 tpm = (Param) zshcalloc(sizeof *tpm);
2353
2354 tpm->node.nam = pm->node.nam;
2355 if (pm->ename &&
2356 (pm2 = (Param) paramtab->getnode(paramtab, pm->ename)) &&
2357 pm2->level == locallevel) {
2358 /* This is getting silly, but anyway: if one of a path/PATH
2359 * pair has already been made local at the current level, we
2360 * have to make sure that the other one does not have its value
2361 * saved: since that comes from an internal variable it will
2362 * already reflect the local value, so restoring it on exit
2363 * would be wrong.
2364 *
2365 * This problem is also why we make sure we have a copy
2366 * of the environment entry in tpm->env, rather than relying
2367 * on the restored value to provide it.
2368 */
2369 tpm->node.flags = pm->node.flags | PM_NORESTORE;
2370 } else {
2371 copyparam(tpm, pm, 1);
2372 }
2373 tpm->old = pm->old;
2374 tpm->level = pm->level;
2375 tpm->base = pm->base;
2376 tpm->width = pm->width;
2377 if (pm->env)
2378 delenv(pm);
2379 tpm->env = NULL;
2380
2381 pm->old = tpm;
2382 /*
2383 * The remaining on/off flags should be harmless to use,
2384 * because we've checked for unpleasant surprises above.
2385 */
2386 pm->node.flags = (PM_TYPE(pm->node.flags) | on | PM_SPECIAL) & ~off;
2387 /*
2388 * Readonlyness of special parameters must be preserved.
2389 */
2390 pm->node.flags |= tpm->node.flags & PM_READONLY;
2391 if (newspecial == NS_SECONDS) {
2392 /* We save off the raw internal value of the SECONDS var */
2393 tpm->u.dval = getrawseconds();
2394 setsecondstype(pm, on, off);
2395 }
2396
2397 /*
2398 * Final tweak: if we've turned on one of the flags with
2399 * numbers, we should use the appropriate integer.
2400 */
2401 if (on & (PM_LEFT|PM_RIGHT_B|PM_RIGHT_Z)) {
2402 if (typeset_setwidth(cname, pm, ops, on, 1))
2403 return NULL;
2404 }
2405 if (on & (PM_INTEGER|PM_EFLOAT|PM_FFLOAT)) {
2406 if (typeset_setbase(cname, pm, ops, on, 1))
2407 return NULL;
2408 }
2409 } else if ((subscript = strchr(pname, '['))) {
2410 if (on & PM_READONLY) {
2411 zerrnam(cname,
2412 "%s: can't create readonly array elements", pname);
2413 return NULL;
2414 } else if ((on & PM_LOCAL) && locallevel) {
2415 *subscript = 0;
2416 pm = (Param) (paramtab == realparamtab ?
2417 /* getnode2() to avoid autoloading */
2418 paramtab->getnode2(paramtab, pname) :
2419 paramtab->getnode(paramtab, pname));
2420 *subscript = '[';
2421 if (!pm || pm->level != locallevel) {
2422 zerrnam(cname,
2423 "%s: can't create local array elements", pname);
2424 return NULL;
2425 }
2426 }
2427 if (PM_TYPE(on) == PM_SCALAR && !ASG_ARRAYP(asg)) {
2428 /*
2429 * This will either complain about bad identifiers, or will set
2430 * a hash element or array slice. This once worked by accident,
2431 * creating a stray parameter along the way via createparam(),
2432 * now called below in the isident() branch.
2433 */
2434 if (!(pm = assignsparam(
2435 pname,
2436 ztrdup(asg->value.scalar ? asg->value.scalar : ""), 0)))
2437 return NULL;
2438 dont_set = 1;
2439 asg->flags = 0;
2440 keeplocal = 0;
2441 on = pm->node.flags;
2442 } else if (PM_TYPE(on) == PM_ARRAY && ASG_ARRAYP(asg)) {
2443 int flags = (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0;
2444 if (!(pm = assignaparam(pname, asg->value.array ?
2445 zlinklist2array(asg->value.array) :
2446 mkarray(NULL), flags)))
2447 return NULL;
2448 dont_set = 1;
2449 keeplocal = 0;
2450 on = pm->node.flags;
2451 } else {
2452 zerrnam(cname,
2453 "%s: inconsistent array element or slice assignment", pname);
2454 return NULL;
2455 }
2456 }
2457 /*
2458 * As we can hide existing parameters, we allow a name if
2459 * it's not a normal identifier but is one of the special
2460 * set found in the parameter table. The second test is
2461 * because we can set individual positional parameters;
2462 * however "0" is not a positional parameter and is OK.
2463 *
2464 * It would be neater to extend isident() and be clearer
2465 * about where we allow various parameter types. It's
2466 * not entirely clear to me isident() should reject
2467 * specially named parameters given that it accepts digits.
2468 */
2469 else if ((isident(pname) || paramtab->getnode(paramtab, pname))
2470 && (!idigit(*pname) || !strcmp(pname, "0"))) {
2471 /*
2472 * Create a new node for a parameter with the flags in `on' minus the
2473 * readonly flag
2474 */
2475 pm = createparam(pname, on & ~PM_READONLY);
2476 if (!pm) {
2477 if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z |
2478 PM_INTEGER | PM_EFLOAT | PM_FFLOAT))
2479 zerrnam(cname, "can't change variable attribute: %s", pname);
2480 return NULL;
2481 }
2482 if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) {
2483 if (typeset_setwidth(cname, pm, ops, on, 0))
2484 return NULL;
2485 }
2486 if (on & (PM_INTEGER | PM_EFLOAT | PM_FFLOAT)) {
2487 if (typeset_setbase(cname, pm, ops, on, 0))
2488 return NULL;
2489 }
2490 } else {
2491 if (idigit(*pname))
2492 zerrnam(cname, "not an identifier: %s", pname);
2493 else
2494 zerrnam(cname, "not valid in this context: %s", pname);
2495 return NULL;
2496 }
2497
2498 if (altpm && PM_TYPE(pm->node.flags) == PM_SCALAR && !(pm->node.flags & PM_SPECIAL)) {
2499 /*
2500 * It seems safer to set this here than in createparam(),
2501 * to make sure we only ever use the colonarr functions
2502 * when u.data is correctly set.
2503 */
2504 struct tieddata *tdp = (struct tieddata *)
2505 zalloc(sizeof(struct tieddata));
2506 if (!tdp)
2507 return NULL;
2508 tdp->joinchar = joinchar;
2509 tdp->arrptr = &altpm->u.arr;
2510
2511 pm->gsu.s = &tiedarr_gsu;
2512 pm->u.data = tdp;
2513 }
2514
2515 if (keeplocal)
2516 pm->level = keeplocal;
2517 else if (on & PM_LOCAL)
2518 pm->level = locallevel;
2519 if (ASG_VALUEP(asg) && !dont_set) {
2520 Param ipm = pm;
2521 if (pm->node.flags & (PM_ARRAY|PM_HASHED)) {
2522 char **arrayval;
2523 int flags = (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0;
2524 if (!ASG_ARRAYP(asg)) {
2525 /*
2526 * Attempt to assign a scalar value to an array.
2527 * This can happen if the array is special.
2528 * We'll be lenient and guess what the user meant.
2529 * This is how normal assignment works.
2530 */
2531 if (*asg->value.scalar) {
2532 /* Array with one value */
2533 arrayval = mkarray(ztrdup(asg->value.scalar));
2534 } else {
2535 /* Empty array */
2536 arrayval = mkarray(NULL);
2537 }
2538 } else if (asg->value.array)
2539 arrayval = zlinklist2array(asg->value.array);
2540 else
2541 arrayval = mkarray(NULL);
2542 if (!(pm=assignaparam(pname, arrayval, flags)))
2543 return NULL;
2544 } else {
2545 DPUTS(ASG_ARRAYP(asg), "BUG: inconsistent array value for scalar");
2546 if (!(pm = assignsparam(pname, ztrdup(asg->value.scalar), 0)))
2547 return NULL;
2548 }
2549 if (pm != ipm) {
2550 DPUTS(ipm->node.flags != pm->node.flags,
2551 "BUG: parameter recreated with wrong flags");
2552 unsetparam_pm(ipm, 0, 1);
2553 }
2554 } else if (newspecial != NS_NONE &&
2555 !(pm->old->node.flags & (PM_NORESTORE|PM_READONLY))) {
2556 /*
2557 * We need to use the special setting function to re-initialise
2558 * the special parameter to empty.
2559 */
2560 switch (PM_TYPE(pm->node.flags)) {
2561 case PM_SCALAR:
2562 pm->gsu.s->setfn(pm, ztrdup(""));
2563 break;
2564 case PM_INTEGER:
2565 /*
2566 * Restricted integers are dangerous to initialize to 0,
2567 * so don't do that.
2568 */
2569 if (!(pm->old->node.flags & PM_RESTRICTED))
2570 pm->gsu.i->setfn(pm, 0);
2571 break;
2572 case PM_EFLOAT:
2573 case PM_FFLOAT:
2574 pm->gsu.f->setfn(pm, 0.0);
2575 break;
2576 case PM_ARRAY:
2577 pm->gsu.a->setfn(pm, mkarray(NULL));
2578 break;
2579 case PM_HASHED:
2580 pm->gsu.h->setfn(pm, newparamtable(17, pm->node.nam));
2581 break;
2582 }
2583 }
2584 pm->node.flags |= (on & PM_READONLY);
2585 DPUTS(OPT_ISSET(ops,'p'), "BUG: -p not handled");
2586
2587 return pm;
2588 }
2589
2590 /*
2591 * declare, export, float, integer, local, readonly, typeset
2592 *
2593 * Note the difference in interface from most builtins, covered by the
2594 * BINF_ASSIGN builtin flag. This is only made use of by builtins
2595 * called by reserved word, which only covers declare, local, readonly
2596 * and typeset. Otherwise assigns is NULL.
2597 */
2598
2599 /**/
2600 int
bin_typeset(char * name,char ** argv,LinkList assigns,Options ops,int func)2601 bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
2602 {
2603 Param pm;
2604 Asgment asg;
2605 Patprog pprog;
2606 char *optstr = TYPESET_OPTSTR;
2607 int on = 0, off = 0, roff, bit = PM_ARRAY;
2608 int i;
2609 int returnval = 0, printflags = 0;
2610 int hasargs;
2611
2612 /* hash -f is really the builtin `functions' */
2613 if (OPT_ISSET(ops,'f'))
2614 return bin_functions(name, argv, ops, func);
2615
2616 /* POSIX handles "readonly" specially */
2617 if (func == BIN_READONLY && isset(POSIXBUILTINS) && !OPT_PLUS(ops, 'g'))
2618 ops->ind['g'] = 1;
2619
2620 /* Translate the options into PM_* flags. *
2621 * Unfortunately, this depends on the order *
2622 * these flags are defined in zsh.h */
2623 for (; *optstr; optstr++, bit <<= 1)
2624 {
2625 int optval = STOUC(*optstr);
2626 if (OPT_MINUS(ops,optval))
2627 on |= bit;
2628 else if (OPT_PLUS(ops,optval))
2629 off |= bit;
2630 }
2631 roff = off;
2632
2633 /* Sanity checks on the options. Remove conflicting options. */
2634 if (on & PM_FFLOAT) {
2635 off |= PM_UPPER | PM_ARRAY | PM_HASHED | PM_INTEGER | PM_EFLOAT;
2636 /* Allow `float -F' to work even though float sets -E by default */
2637 on &= ~PM_EFLOAT;
2638 }
2639 if (on & PM_EFLOAT)
2640 off |= PM_UPPER | PM_ARRAY | PM_HASHED | PM_INTEGER | PM_FFLOAT;
2641 if (on & PM_INTEGER)
2642 off |= PM_UPPER | PM_ARRAY | PM_HASHED | PM_EFLOAT | PM_FFLOAT;
2643 /*
2644 * Allowing -Z with -L is a feature: left justify, suppressing
2645 * leading zeroes.
2646 */
2647 if (on & (PM_LEFT|PM_RIGHT_Z))
2648 off |= PM_RIGHT_B;
2649 if (on & PM_RIGHT_B)
2650 off |= PM_LEFT | PM_RIGHT_Z;
2651 if (on & PM_UPPER)
2652 off |= PM_LOWER;
2653 if (on & PM_LOWER)
2654 off |= PM_UPPER;
2655 if (on & PM_HASHED)
2656 off |= PM_ARRAY;
2657 if (on & PM_TIED)
2658 off |= PM_INTEGER | PM_EFLOAT | PM_FFLOAT | PM_ARRAY | PM_HASHED;
2659
2660 on &= ~off;
2661
2662 queue_signals();
2663
2664 /* Given no arguments, list whatever the options specify. */
2665 if (OPT_ISSET(ops,'p')) {
2666
2667 if (isset(POSIXBUILTINS) && SHELL_EMULATION() != EMULATE_KSH) {
2668 if (func == BIN_EXPORT)
2669 printflags |= PRINT_POSIX_EXPORT;
2670 else if (func == BIN_READONLY)
2671 printflags |= PRINT_POSIX_READONLY;
2672 else
2673 printflags |= PRINT_TYPESET;
2674 } else
2675 printflags |= PRINT_TYPESET;
2676
2677 if (OPT_HASARG(ops,'p')) {
2678 char *eptr;
2679 int pflag = (int)zstrtol(OPT_ARG(ops,'p'), &eptr, 10);
2680 if (pflag == 1 && !*eptr)
2681 printflags |= PRINT_LINE;
2682 else if (pflag || *eptr) {
2683 zwarnnam(name, "bad argument to -p: %s", OPT_ARG(ops,'p'));
2684 unqueue_signals();
2685 return 1;
2686 }
2687 /* -p0 treated as -p for consistency */
2688 }
2689 }
2690 hasargs = *argv != NULL || (assigns && firstnode(assigns));
2691 if (!hasargs) {
2692 int exclude = 0;
2693 if (!OPT_ISSET(ops,'p')) {
2694 if (!(on|roff))
2695 printflags |= PRINT_TYPE;
2696 if (roff || OPT_ISSET(ops,'+'))
2697 printflags |= PRINT_NAMEONLY;
2698 } else if (printflags & (PRINT_POSIX_EXPORT|PRINT_POSIX_READONLY)) {
2699 /*
2700 * For POSIX export/readonly, exclude non-scalars unless
2701 * explicitly requested.
2702 */
2703 exclude = (PM_ARRAY|PM_HASHED) & ~(on|roff);
2704 }
2705 scanhashtable(paramtab, 1, on|roff, exclude, paramtab->printnode, printflags);
2706 unqueue_signals();
2707 return 0;
2708 }
2709
2710 if (!(OPT_ISSET(ops,'g') || OPT_ISSET(ops,'x') || OPT_ISSET(ops,'m')) ||
2711 OPT_PLUS(ops,'g') || *name == 'l' ||
2712 (!isset(GLOBALEXPORT) && !OPT_ISSET(ops,'g')))
2713 on |= PM_LOCAL;
2714
2715 if ((on & PM_TIED) && !OPT_ISSET(ops, 'p')) {
2716 Param apm;
2717 struct asgment asg0, asg2;
2718 char *oldval = NULL, *joinstr;
2719 int joinchar, nargs;
2720 int already_tied = 0;
2721
2722 if (OPT_ISSET(ops,'m')) {
2723 zwarnnam(name, "incompatible options for -T");
2724 unqueue_signals();
2725 return 1;
2726 }
2727 on &= ~off;
2728 nargs = arrlen(argv) + (assigns ? countlinknodes(assigns) : 0);
2729 if (nargs < 2) {
2730 zwarnnam(name, "-T requires names of scalar and array");
2731 unqueue_signals();
2732 return 1;
2733 }
2734 if (nargs > 3) {
2735 zwarnnam(name, "too many arguments for -T");
2736 unqueue_signals();
2737 return 1;
2738 }
2739
2740 if (!(asg = getasg(&argv, assigns))) {
2741 unqueue_signals();
2742 return 1;
2743 }
2744 asg0 = *asg;
2745 if (ASG_ARRAYP(&asg0)) {
2746 unqueue_signals();
2747 zwarnnam(name, "first argument of tie must be scalar: %s",
2748 asg0.name);
2749 return 1;
2750 }
2751
2752 if (!(asg = getasg(&argv, assigns))) {
2753 unqueue_signals();
2754 return 1;
2755 }
2756 if (!ASG_ARRAYP(asg) && asg->value.scalar) {
2757 unqueue_signals();
2758 zwarnnam(name, "second argument of tie must be array: %s",
2759 asg->name);
2760 return 1;
2761 }
2762
2763 if (!strcmp(asg0.name, asg->name)) {
2764 unqueue_signals();
2765 zerrnam(name, "can't tie a variable to itself: %s", asg0.name);
2766 return 1;
2767 }
2768 if (strchr(asg0.name, '[') || strchr(asg->name, '[')) {
2769 unqueue_signals();
2770 zerrnam(name, "can't tie array elements: %s", asg0.name);
2771 return 1;
2772 }
2773 if (ASG_VALUEP(asg) && ASG_VALUEP(&asg0)) {
2774 unqueue_signals();
2775 zerrnam(name, "only one tied parameter can have value: %s", asg0.name);
2776 return 1;
2777 }
2778
2779 /*
2780 * Third argument, if given, is character used to join
2781 * the elements of the array in the scalar.
2782 */
2783 if (*argv)
2784 joinstr = *argv;
2785 else if (assigns && firstnode(assigns)) {
2786 Asgment nextasg = (Asgment)firstnode(assigns);
2787 if (ASG_ARRAYP(nextasg) || ASG_VALUEP(nextasg)) {
2788 zwarnnam(name, "third argument of tie must be join character");
2789 unqueue_signals();
2790 return 1;
2791 }
2792 joinstr = nextasg->name;
2793 } else
2794 joinstr = NULL;
2795 if (!joinstr)
2796 joinchar = ':';
2797 else if (!*joinstr)
2798 joinchar = 0;
2799 else if (*joinstr == Meta)
2800 joinchar = joinstr[1] ^ 32;
2801 else
2802 joinchar = *joinstr;
2803
2804 pm = (Param) paramtab->getnode(paramtab, asg0.name);
2805 apm = (Param) paramtab->getnode(paramtab, asg->name);
2806
2807 if (pm && (pm->node.flags & (PM_SPECIAL|PM_TIED)) == (PM_SPECIAL|PM_TIED)) {
2808 /*
2809 * Only allow typeset -T on special tied parameters if the tied
2810 * parameter and join char are the same
2811 */
2812 if (strcmp(pm->ename, asg->name) || !(apm->node.flags & PM_SPECIAL)) {
2813 zwarnnam(name, "%s special parameter can only be tied to special parameter %s", asg0.name, pm->ename);
2814 unqueue_signals();
2815 return 1;
2816 }
2817 if (joinchar != ':') {
2818 zwarnnam(name, "cannot change the join character of special tied parameters");
2819 unqueue_signals();
2820 return 1;
2821 }
2822 already_tied = 1;
2823 } else if (apm && (apm->node.flags & (PM_SPECIAL|PM_TIED)) == (PM_SPECIAL|PM_TIED)) {
2824 /*
2825 * For the array variable, this covers attempts to tie the
2826 * array to a different scalar or to the scalar after it has
2827 * been made non-special
2828 */
2829 zwarnnam(name, "%s special parameter can only be tied to special parameter %s", asg->name, apm->ename);
2830 unqueue_signals();
2831 return 1;
2832 } else if (pm) {
2833 if (!(pm->node.flags & PM_UNSET)
2834 && (locallevel == pm->level || !(on & PM_LOCAL))) {
2835 if (pm->node.flags & PM_TIED) {
2836 if (PM_TYPE(pm->node.flags) != PM_SCALAR) {
2837 zwarnnam(name, "already tied as non-scalar: %s", asg0.name);
2838 unqueue_signals();
2839 return 1;
2840 } else if (!strcmp(asg->name, pm->ename)) {
2841 already_tied = 1;
2842 } else {
2843 zwarnnam(name, "can't tie already tied scalar: %s",
2844 asg0.name);
2845 unqueue_signals();
2846 return 1;
2847 }
2848 } else {
2849 /*
2850 * Variable already exists in the current scope but is not tied.
2851 * We're preserving its value and export attribute but no other
2852 * attributes upon converting to "tied".
2853 */
2854 if (!asg0.value.scalar && !asg->value.array &&
2855 !(PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)))
2856 oldval = ztrdup(getsparam(asg0.name));
2857 on |= (pm->node.flags & ~roff) & PM_EXPORTED;
2858 }
2859 }
2860 }
2861 if (already_tied) {
2862 int ret;
2863 /*
2864 * If already tied, we still need to call typeset_single on
2865 * both the array and colonarray, if only to update the attributes
2866 * of both, and of course to set the new value if one is provided
2867 * for either of them.
2868 */
2869 ret = !(typeset_single(name, asg0.name, pm,
2870 func, on, off, roff, &asg0, apm,
2871 ops, joinchar) &&
2872 typeset_single(name, asg->name, apm,
2873 func, (on | PM_ARRAY) & ~PM_EXPORTED,
2874 off & ~PM_ARRAY, roff, asg, NULL, ops, 0)
2875 );
2876 unqueue_signals();
2877 return ret;
2878 }
2879 /*
2880 * Create the tied array; this is normal except that
2881 * it has the PM_TIED flag set. Do it first because
2882 * we need the address.
2883 *
2884 * Don't attempt to set it yet, it's too early
2885 * to be exported properly.
2886 */
2887 asg2.name = asg->name;
2888 asg2.flags = 0;
2889 asg2.value.array = (LinkList)0;
2890 if (!(apm=typeset_single(name, asg->name,
2891 (Param)paramtab->getnode(paramtab,
2892 asg->name),
2893 func, (on | PM_ARRAY) & ~PM_EXPORTED,
2894 off, roff, &asg2, NULL, ops, 0))) {
2895 if (oldval)
2896 zsfree(oldval);
2897 unqueue_signals();
2898 return 1;
2899 }
2900 /*
2901 * Create the tied colonarray. We make it as a normal scalar
2902 * and fix up the oddities later.
2903 */
2904 if (!(pm=typeset_single(name, asg0.name, pm,
2905 func, on, off, roff, &asg0, apm,
2906 ops, joinchar))) {
2907 if (oldval)
2908 zsfree(oldval);
2909 unsetparam_pm(apm, 1, 1);
2910 unqueue_signals();
2911 return 1;
2912 }
2913
2914 /*
2915 * pm->ename is only deleted when the struct is, so
2916 * we need to free it here if it already exists.
2917 */
2918 if (pm->ename)
2919 zsfree(pm->ename);
2920 pm->ename = ztrdup(asg->name);
2921 if (apm->ename)
2922 zsfree(apm->ename);
2923 apm->ename = ztrdup(asg0.name);
2924 if (asg->value.array) {
2925 int flags = (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0;
2926 assignaparam(asg->name, zlinklist2array(asg->value.array), flags);
2927 } else if (oldval)
2928 assignsparam(asg0.name, oldval, 0);
2929 unqueue_signals();
2930
2931 return 0;
2932 }
2933 if (off & PM_TIED) {
2934 unqueue_signals();
2935 zerrnam(name, "use unset to remove tied variables");
2936 return 1;
2937 }
2938
2939 /* With the -m option, treat arguments as glob patterns */
2940 if (OPT_ISSET(ops,'m')) {
2941 if (!OPT_ISSET(ops,'p')) {
2942 if (!(on|roff))
2943 printflags |= PRINT_TYPE;
2944 if (!on)
2945 printflags |= PRINT_NAMEONLY;
2946 }
2947
2948 while ((asg = getasg(&argv, assigns))) {
2949 LinkList pmlist = newlinklist();
2950 LinkNode pmnode;
2951
2952 tokenize(asg->name); /* expand argument */
2953 if (!(pprog = patcompile(asg->name, 0, NULL))) {
2954 untokenize(asg->name);
2955 zwarnnam(name, "bad pattern : %s", asg->name);
2956 returnval = 1;
2957 continue;
2958 }
2959 if (OPT_PLUS(ops,'m') && !ASG_VALUEP(asg)) {
2960 scanmatchtable(paramtab, pprog, 1, on|roff, 0,
2961 paramtab->printnode, printflags);
2962 continue;
2963 }
2964 /*
2965 * Search through the parameter table and change all parameters
2966 * matching the glob pattern to have these flags and/or value.
2967 * Bad news: if the parameter gets altered, e.g. by
2968 * a type conversion, then paramtab can be shifted around,
2969 * so we need to store the parameters to alter on a separate
2970 * list for later use.
2971 */
2972 for (i = 0; i < paramtab->hsize; i++) {
2973 for (pm = (Param) paramtab->nodes[i]; pm;
2974 pm = (Param) pm->node.next) {
2975 if (((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) ||
2976 (pm->node.flags & PM_UNSET))
2977 continue;
2978 if (pattry(pprog, pm->node.nam))
2979 addlinknode(pmlist, pm);
2980 }
2981 }
2982 for (pmnode = firstnode(pmlist); pmnode; incnode(pmnode)) {
2983 pm = (Param) getdata(pmnode);
2984 if (!typeset_single(name, pm->node.nam, pm, func, on, off, roff,
2985 asg, NULL, ops, 0))
2986 returnval = 1;
2987 }
2988 }
2989 unqueue_signals();
2990 return returnval;
2991 }
2992
2993 /* Take arguments literally. Don't glob */
2994 while ((asg = getasg(&argv, assigns))) {
2995 HashNode hn = (paramtab == realparamtab ?
2996 /* getnode2() to avoid autoloading */
2997 paramtab->getnode2(paramtab, asg->name) :
2998 paramtab->getnode(paramtab, asg->name));
2999 if (OPT_ISSET(ops,'p')) {
3000 if (hn)
3001 paramtab->printnode(hn, printflags);
3002 else {
3003 zwarnnam(name, "no such variable: %s", asg->name);
3004 returnval = 1;
3005 }
3006 continue;
3007 }
3008 if (!typeset_single(name, asg->name, (Param)hn,
3009 func, on, off, roff, asg, NULL,
3010 ops, 0))
3011 returnval = 1;
3012 }
3013 unqueue_signals();
3014 return returnval;
3015 }
3016
3017 /* Helper for bin_functions() when run as "autoload -X" */
3018
3019 /**/
3020 int
eval_autoload(Shfunc shf,char * name,Options ops,int func)3021 eval_autoload(Shfunc shf, char *name, Options ops, int func)
3022 {
3023 if (!(shf->node.flags & PM_UNDEFINED))
3024 return 1;
3025
3026 if (shf->funcdef) {
3027 freeeprog(shf->funcdef);
3028 shf->funcdef = &dummy_eprog;
3029 }
3030 if (OPT_MINUS(ops,'X')) {
3031 char *fargv[3];
3032 fargv[0] = quotestring(name, QT_SINGLE_OPTIONAL);
3033 fargv[1] = "\"$@\"";
3034 fargv[2] = 0;
3035 shf->funcdef = mkautofn(shf);
3036 return bin_eval(name, fargv, ops, func);
3037 }
3038
3039 return !loadautofn(shf, (OPT_ISSET(ops,'k') ? 2 :
3040 (OPT_ISSET(ops,'z') ? 0 : 1)), 1,
3041 OPT_ISSET(ops,'d'));
3042 }
3043
3044 /* Helper for bin_functions() for -X and -r options */
3045
3046 /**/
3047 static int
check_autoload(Shfunc shf,char * name,Options ops,int func)3048 check_autoload(Shfunc shf, char *name, Options ops, int func)
3049 {
3050 if (OPT_ISSET(ops,'X'))
3051 {
3052 return eval_autoload(shf, name, ops, func);
3053 }
3054 if ((OPT_ISSET(ops,'r') || OPT_ISSET(ops,'R')) &&
3055 (shf->node.flags & PM_UNDEFINED))
3056 {
3057 char *dir_path;
3058 if (shf->filename && (shf->node.flags & PM_LOADDIR)) {
3059 char *spec_path[2];
3060 spec_path[0] = shf->filename;
3061 spec_path[1] = NULL;
3062 if (getfpfunc(shf->node.nam, NULL, &dir_path, spec_path, 1)) {
3063 /* shf->filename is already correct. */
3064 return 0;
3065 }
3066 if (!OPT_ISSET(ops,'d')) {
3067 if (OPT_ISSET(ops,'R')) {
3068 zerr("%s: function definition file not found",
3069 shf->node.nam);
3070 return 1;
3071 }
3072 return 0;
3073 }
3074 }
3075 if (getfpfunc(shf->node.nam, NULL, &dir_path, NULL, 1)) {
3076 dircache_set(&shf->filename, NULL);
3077 if (*dir_path != '/') {
3078 dir_path = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP),
3079 "/", dir_path);
3080 dir_path = xsymlink(dir_path, 1);
3081 }
3082 dircache_set(&shf->filename, dir_path);
3083 shf->node.flags |= PM_LOADDIR;
3084 return 0;
3085 }
3086 if (OPT_ISSET(ops,'R')) {
3087 zerr("%s: function definition file not found",
3088 shf->node.nam);
3089 return 1;
3090 }
3091 /* with -r, we don't flag an error, just let it be found later. */
3092 }
3093 return 0;
3094 }
3095
3096 /* List a user-defined math function. */
3097 static void
listusermathfunc(MathFunc p)3098 listusermathfunc(MathFunc p)
3099 {
3100 int showargs;
3101
3102 if (p->module)
3103 showargs = 3;
3104 else if (p->maxargs != (p->minargs ? p->minargs : -1))
3105 showargs = 2;
3106 else if (p->minargs)
3107 showargs = 1;
3108 else
3109 showargs = 0;
3110
3111 printf("functions -M%s %s", (p->flags & MFF_STR) ? "s" : "", p->name);
3112 if (showargs) {
3113 printf(" %d", p->minargs);
3114 showargs--;
3115 }
3116 if (showargs) {
3117 printf(" %d", p->maxargs);
3118 showargs--;
3119 }
3120 if (showargs) {
3121 /*
3122 * function names are not required to consist of ident characters
3123 */
3124 putchar(' ');
3125 quotedzputs(p->module, stdout);
3126 showargs--;
3127 }
3128 putchar('\n');
3129 }
3130
3131
3132 static void
add_autoload_function(Shfunc shf,char * funcname)3133 add_autoload_function(Shfunc shf, char *funcname)
3134 {
3135 char *nam;
3136 if (*funcname == '/' && funcname[1] &&
3137 (nam = strrchr(funcname, '/')) && nam[1] &&
3138 (shf->node.flags & PM_UNDEFINED)) {
3139 char *dir;
3140 nam = strrchr(funcname, '/');
3141 if (nam == funcname) {
3142 dir = "/";
3143 } else {
3144 *nam++ = '\0';
3145 dir = funcname;
3146 }
3147 dircache_set(&shf->filename, NULL);
3148 dircache_set(&shf->filename, dir);
3149 shf->node.flags |= PM_LOADDIR;
3150 shf->node.flags |= PM_ABSPATH_USED;
3151 shfunctab->addnode(shfunctab, ztrdup(nam), shf);
3152 } else {
3153 Shfunc shf2;
3154 Funcstack fs;
3155 const char *calling_f = NULL;
3156 char buf[PATH_MAX+1];
3157
3158 /* Find calling function */
3159 for (fs = funcstack; fs; fs = fs->prev) {
3160 if (fs->tp == FS_FUNC && fs->name && (!shf->node.nam || 0 != strcmp(fs->name,shf->node.nam))) {
3161 calling_f = fs->name;
3162 break;
3163 }
3164 }
3165
3166 /* Get its directory */
3167 if (calling_f) {
3168 /* Should contain load directory, and be loaded via absolute path */
3169 if ((shf2 = (Shfunc) shfunctab->getnode2(shfunctab, calling_f))
3170 && (shf2->node.flags & PM_LOADDIR) && (shf2->node.flags & PM_ABSPATH_USED)
3171 && shf2->filename)
3172 {
3173 if (strlen(shf2->filename) + strlen(funcname) + 1 < PATH_MAX)
3174 {
3175 sprintf(buf, "%s/%s", shf2->filename, funcname);
3176 /* Set containing directory if the function file
3177 * exists (do normal FPATH processing otherwise) */
3178 if (!access(buf, R_OK)) {
3179 dircache_set(&shf->filename, NULL);
3180 dircache_set(&shf->filename, shf2->filename);
3181 shf->node.flags |= PM_LOADDIR;
3182 shf->node.flags |= PM_ABSPATH_USED;
3183 }
3184 }
3185 }
3186 }
3187
3188 shfunctab->addnode(shfunctab, ztrdup(funcname), shf);
3189 }
3190 }
3191
3192 /* Display or change the attributes of shell functions. *
3193 * If called as autoload, it will define a new autoloaded *
3194 * (undefined) shell function. */
3195
3196 /**/
3197 int
bin_functions(char * name,char ** argv,Options ops,int func)3198 bin_functions(char *name, char **argv, Options ops, int func)
3199 {
3200 Patprog pprog;
3201 Shfunc shf;
3202 int i, returnval = 0;
3203 int on = 0, off = 0, pflags = 0, roff, expand = 0;
3204
3205 /* Do we have any flags defined? */
3206 if (OPT_PLUS(ops,'u'))
3207 off |= PM_UNDEFINED;
3208 else if (OPT_MINUS(ops,'u') || OPT_ISSET(ops,'X'))
3209 on |= PM_UNDEFINED;
3210 if (OPT_MINUS(ops,'U'))
3211 on |= PM_UNALIASED|PM_UNDEFINED;
3212 else if (OPT_PLUS(ops,'U'))
3213 off |= PM_UNALIASED;
3214 if (OPT_MINUS(ops,'t'))
3215 on |= PM_TAGGED;
3216 else if (OPT_PLUS(ops,'t'))
3217 off |= PM_TAGGED;
3218 if (OPT_MINUS(ops,'T'))
3219 on |= PM_TAGGED_LOCAL;
3220 else if (OPT_PLUS(ops,'T'))
3221 off |= PM_TAGGED_LOCAL;
3222 if (OPT_MINUS(ops,'W'))
3223 on |= PM_WARNNESTED;
3224 else if (OPT_PLUS(ops,'W'))
3225 off |= PM_WARNNESTED;
3226 roff = off;
3227 if (OPT_MINUS(ops,'z')) {
3228 on |= PM_ZSHSTORED;
3229 off |= PM_KSHSTORED;
3230 } else if (OPT_PLUS(ops,'z')) {
3231 off |= PM_ZSHSTORED;
3232 roff |= PM_ZSHSTORED;
3233 }
3234 if (OPT_MINUS(ops,'k')) {
3235 on |= PM_KSHSTORED;
3236 off |= PM_ZSHSTORED;
3237 } else if (OPT_PLUS(ops,'k')) {
3238 off |= PM_KSHSTORED;
3239 roff |= PM_KSHSTORED;
3240 }
3241 if (OPT_MINUS(ops,'d')) {
3242 on |= PM_CUR_FPATH;
3243 off |= PM_CUR_FPATH;
3244 } else if (OPT_PLUS(ops,'d')) {
3245 off |= PM_CUR_FPATH;
3246 roff |= PM_CUR_FPATH;
3247 }
3248
3249 if ((off & PM_UNDEFINED) || (OPT_ISSET(ops,'k') && OPT_ISSET(ops,'z')) ||
3250 (OPT_ISSET(ops,'x') && !OPT_HASARG(ops,'x')) ||
3251 (OPT_MINUS(ops,'X') && (OPT_ISSET(ops,'m') || !scriptname)) ||
3252 (OPT_ISSET(ops,'c') && (OPT_ISSET(ops,'x') || OPT_ISSET(ops,'X') ||
3253 OPT_ISSET(ops,'m')))) {
3254 zwarnnam(name, "invalid option(s)");
3255 return 1;
3256 }
3257
3258 if (OPT_ISSET(ops,'c')) {
3259 Shfunc newsh;
3260 if (!*argv || !argv[1] || argv[2]) {
3261 zwarnnam(name, "-c: requires two arguments");
3262 return 1;
3263 }
3264 shf = (Shfunc) shfunctab->getnode(shfunctab, *argv);
3265 if (!shf) {
3266 zwarnnam(name, "no such function: %s", *argv);
3267 return 1;
3268 }
3269 if (shf->node.flags & PM_UNDEFINED) {
3270 if (shf->funcdef) {
3271 freeeprog(shf->funcdef);
3272 shf->funcdef = &dummy_eprog;
3273 }
3274 shf = loadautofn(shf, 1, 0, 0);
3275 if (!shf)
3276 return 1;
3277 }
3278 newsh = zalloc(sizeof(*newsh));
3279 memcpy(newsh, shf, sizeof(*newsh));
3280 if (newsh->node.flags & PM_LOADDIR) {
3281 /* Expand original location of autoloaded file */
3282 newsh->node.flags &= ~PM_LOADDIR;
3283 newsh->filename = tricat(shf->filename, "/", shf->node.nam);
3284 } else
3285 newsh->filename = ztrdup(shf->filename);
3286 newsh->funcdef->nref++;
3287 if (newsh->redir)
3288 newsh->redir->nref++;
3289 if (shf->sticky)
3290 newsh->sticky = sticky_emulation_dup(sticky, 0);
3291 shfunctab->addnode(shfunctab, ztrdup(argv[1]), &newsh->node);
3292 return 0;
3293 }
3294
3295 if (OPT_ISSET(ops,'x')) {
3296 char *eptr;
3297 expand = (int)zstrtol(OPT_ARG(ops,'x'), &eptr, 10);
3298 if (*eptr) {
3299 zwarnnam(name, "number expected after -x");
3300 return 1;
3301 }
3302 if (expand == 0) /* no indentation at all */
3303 expand = -1;
3304 }
3305
3306 if (OPT_PLUS(ops,'f') || roff || OPT_ISSET(ops,'+'))
3307 pflags |= PRINT_NAMEONLY;
3308
3309 if (OPT_MINUS(ops,'M') || OPT_PLUS(ops,'M')) {
3310 MathFunc p, q, prev;
3311 /*
3312 * Add/remove/list function as mathematical.
3313 */
3314 if (on || off || pflags || OPT_ISSET(ops,'X') || OPT_ISSET(ops,'u')
3315 || OPT_ISSET(ops,'U') || OPT_ISSET(ops,'w')) {
3316 zwarnnam(name, "invalid option(s)");
3317 return 1;
3318 }
3319 if (!*argv) {
3320 /* List functions. */
3321 queue_signals();
3322 for (p = mathfuncs; p; p = p->next)
3323 if (p->flags & MFF_USERFUNC)
3324 listusermathfunc(p);
3325 unqueue_signals();
3326 } else if (OPT_ISSET(ops,'m')) {
3327 /* List matching functions. */
3328 for (; *argv; argv++) {
3329 queue_signals();
3330 tokenize(*argv);
3331 if ((pprog = patcompile(*argv, PAT_STATIC, 0))) {
3332 for (p = mathfuncs, q = NULL; p; q = p) {
3333 MathFunc next;
3334 do {
3335 next = NULL;
3336 if ((p->flags & MFF_USERFUNC) &&
3337 pattry(pprog, p->name)) {
3338 if (OPT_PLUS(ops,'M')) {
3339 next = p->next;
3340 removemathfunc(q, p);
3341 p = next;
3342 } else
3343 listusermathfunc(p);
3344 }
3345 /* if we deleted one, retry with the new p */
3346 } while (next);
3347 if (p)
3348 p = p->next;
3349 }
3350 } else {
3351 untokenize(*argv);
3352 zwarnnam(name, "bad pattern : %s", *argv);
3353 returnval = 1;
3354 }
3355 unqueue_signals();
3356 }
3357 } else if (OPT_PLUS(ops,'M')) {
3358 /* Delete functions. -m is allowed but is handled above. */
3359 for (; *argv; argv++) {
3360 queue_signals();
3361 for (p = mathfuncs, q = NULL; p; q = p, p = p->next) {
3362 if (!strcmp(p->name, *argv)) {
3363 if (!(p->flags & MFF_USERFUNC)) {
3364 zwarnnam(name, "+M %s: is a library function",
3365 *argv);
3366 returnval = 1;
3367 break;
3368 }
3369 removemathfunc(q, p);
3370 break;
3371 }
3372 }
3373 unqueue_signals();
3374 }
3375 } else {
3376 /* Add a function */
3377 int minargs, maxargs;
3378 char *funcname = *argv++;
3379 char *modname = NULL;
3380 char *ptr;
3381
3382 if (OPT_ISSET(ops,'s')) {
3383 minargs = maxargs = 1;
3384 } else {
3385 minargs = 0;
3386 maxargs = -1;
3387 }
3388
3389 ptr = itype_end(funcname, IIDENT, 0);
3390 if (idigit(*funcname) || funcname == ptr || *ptr) {
3391 zwarnnam(name, "-M %s: bad math function name", funcname);
3392 return 1;
3393 }
3394
3395 if (*argv) {
3396 minargs = (int)zstrtol(*argv, &ptr, 0);
3397 if (minargs < 0 || *ptr) {
3398 zwarnnam(name, "-M: invalid min number of arguments: %s",
3399 *argv);
3400 return 1;
3401 }
3402 if (OPT_ISSET(ops,'s') && minargs != 1) {
3403 zwarnnam(name, "-Ms: must take a single string argument");
3404 return 1;
3405 }
3406 maxargs = minargs;
3407 argv++;
3408 }
3409 if (*argv) {
3410 maxargs = (int)zstrtol(*argv, &ptr, 0);
3411 if (maxargs < -1 ||
3412 (maxargs != -1 && maxargs < minargs) ||
3413 *ptr) {
3414 zwarnnam(name,
3415 "-M: invalid max number of arguments: %s",
3416 *argv);
3417 return 1;
3418 }
3419 if (OPT_ISSET(ops,'s') && maxargs != 1) {
3420 zwarnnam(name, "-Ms: must take a single string argument");
3421 return 1;
3422 }
3423 argv++;
3424 }
3425 if (*argv)
3426 modname = *argv++;
3427 if (*argv) {
3428 zwarnnam(name, "-M: too many arguments");
3429 return 1;
3430 }
3431
3432 p = (MathFunc)zshcalloc(sizeof(struct mathfunc));
3433 p->name = ztrdup(funcname);
3434 p->flags = MFF_USERFUNC;
3435 if (OPT_ISSET(ops,'s'))
3436 p->flags |= MFF_STR;
3437 p->module = modname ? ztrdup(modname) : NULL;
3438 p->minargs = minargs;
3439 p->maxargs = maxargs;
3440
3441 queue_signals();
3442 for (q = mathfuncs, prev = NULL; q; prev = q, q = q->next) {
3443 if (!strcmp(q->name, funcname)) {
3444 removemathfunc(prev, q);
3445 break;
3446 }
3447 }
3448
3449 p->next = mathfuncs;
3450 mathfuncs = p;
3451 unqueue_signals();
3452 }
3453
3454 return returnval;
3455 }
3456
3457 if (OPT_MINUS(ops,'X')) {
3458 Funcstack fs;
3459 char *funcname = NULL;
3460 int ret;
3461 if (*argv && argv[1]) {
3462 zwarnnam(name, "-X: too many arguments");
3463 return 1;
3464 }
3465 queue_signals();
3466 for (fs = funcstack; fs; fs = fs->prev) {
3467 if (fs->tp == FS_FUNC) {
3468 /*
3469 * dupstring here is paranoia but unlikely to be
3470 * problematic
3471 */
3472 funcname = dupstring(fs->name);
3473 break;
3474 }
3475 }
3476 if (!funcname)
3477 {
3478 zerrnam(name, "bad autoload");
3479 ret = 1;
3480 } else {
3481 if ((shf = (Shfunc) shfunctab->getnode(shfunctab, funcname))) {
3482 DPUTS(!shf->funcdef,
3483 "BUG: Calling autoload from empty function");
3484 } else {
3485 shf = (Shfunc) zshcalloc(sizeof *shf);
3486 shfunctab->addnode(shfunctab, ztrdup(funcname), shf);
3487 }
3488 if (*argv) {
3489 dircache_set(&shf->filename, NULL);
3490 dircache_set(&shf->filename, *argv);
3491 on |= PM_LOADDIR;
3492 }
3493 shf->node.flags = on;
3494 ret = eval_autoload(shf, funcname, ops, func);
3495 }
3496 unqueue_signals();
3497 return ret;
3498 } else if (!*argv) {
3499 /* If no arguments given, we will print functions. If flags *
3500 * are given, we will print only functions containing these *
3501 * flags, else we'll print them all. */
3502 int ret = 0;
3503
3504 queue_signals();
3505 if (OPT_ISSET(ops,'U') && !OPT_ISSET(ops,'u'))
3506 on &= ~PM_UNDEFINED;
3507 scanshfunc(1, on|off, DISABLED, shfunctab->printnode,
3508 pflags, expand);
3509 unqueue_signals();
3510 return ret;
3511 }
3512
3513 /* With the -m option, treat arguments as glob patterns */
3514 if (OPT_ISSET(ops,'m')) {
3515 on &= ~PM_UNDEFINED;
3516 for (; *argv; argv++) {
3517 queue_signals();
3518 /* expand argument */
3519 tokenize(*argv);
3520 if ((pprog = patcompile(*argv, PAT_STATIC, 0))) {
3521 /* with no options, just print all functions matching the glob pattern */
3522 if (!(on|off) && !OPT_ISSET(ops,'X')) {
3523 scanmatchshfunc(pprog, 1, 0, DISABLED,
3524 shfunctab->printnode, pflags, expand);
3525 } else {
3526 /* apply the options to all functions matching the glob pattern */
3527 for (i = 0; i < shfunctab->hsize; i++) {
3528 for (shf = (Shfunc) shfunctab->nodes[i]; shf;
3529 shf = (Shfunc) shf->node.next)
3530 if (pattry(pprog, shf->node.nam) &&
3531 !(shf->node.flags & DISABLED)) {
3532 shf->node.flags = (shf->node.flags |
3533 (on & ~PM_UNDEFINED)) & ~off;
3534 if (check_autoload(shf, shf->node.nam,
3535 ops, func)) {
3536 returnval = 1;
3537 }
3538 }
3539 }
3540 }
3541 } else {
3542 untokenize(*argv);
3543 zwarnnam(name, "bad pattern : %s", *argv);
3544 returnval = 1;
3545 }
3546 unqueue_signals();
3547 }
3548 return returnval;
3549 }
3550
3551 /* Take the arguments literally -- do not glob */
3552 queue_signals();
3553 for (; *argv; argv++) {
3554 if (OPT_ISSET(ops,'w'))
3555 returnval = dump_autoload(name, *argv, on, ops, func);
3556 else if ((shf = (Shfunc) shfunctab->getnode(shfunctab, *argv))) {
3557 /* if any flag was given */
3558 if (on|off) {
3559 /* turn on/off the given flags */
3560 shf->node.flags = (shf->node.flags | (on & ~PM_UNDEFINED)) & ~off;
3561 if (check_autoload(shf, shf->node.nam, ops, func))
3562 returnval = 1;
3563 } else
3564 /* no flags, so just print */
3565 printshfuncexpand(&shf->node, pflags, expand);
3566 } else if (on & PM_UNDEFINED) {
3567 int signum = -1, ok = 1;
3568
3569 if (!strncmp(*argv, "TRAP", 4) &&
3570 (signum = getsignum(*argv + 4)) != -1) {
3571 /*
3572 * Because of the possibility of alternative names,
3573 * we must remove the trap explicitly.
3574 */
3575 removetrapnode(signum);
3576 }
3577
3578 if (**argv == '/') {
3579 char *base = strrchr(*argv, '/') + 1;
3580 if (*base &&
3581 (shf = (Shfunc) shfunctab->getnode(shfunctab, base))) {
3582 char *dir;
3583 /* turn on/off the given flags */
3584 shf->node.flags =
3585 (shf->node.flags | (on & ~PM_UNDEFINED)) & ~off;
3586 if (shf->node.flags & PM_UNDEFINED) {
3587 /* update path if not yet loaded */
3588 if (base == *argv + 1)
3589 dir = "/";
3590 else {
3591 dir = *argv;
3592 base[-1] = '\0';
3593 }
3594 dircache_set(&shf->filename, NULL);
3595 dircache_set(&shf->filename, dir);
3596 }
3597 if (check_autoload(shf, shf->node.nam, ops, func))
3598 returnval = 1;
3599 continue;
3600 }
3601 }
3602
3603 /* Add a new undefined (autoloaded) function to the *
3604 * hash table with the corresponding flags set. */
3605 shf = (Shfunc) zshcalloc(sizeof *shf);
3606 shf->node.flags = on;
3607 shf->funcdef = mkautofn(shf);
3608 shfunc_set_sticky(shf);
3609 add_autoload_function(shf, *argv);
3610
3611 if (signum != -1) {
3612 if (settrap(signum, NULL, ZSIG_FUNC)) {
3613 shfunctab->removenode(shfunctab, *argv);
3614 shfunctab->freenode(&shf->node);
3615 returnval = 1;
3616 ok = 0;
3617 }
3618 }
3619
3620 if (ok && check_autoload(shf, shf->node.nam, ops, func))
3621 returnval = 1;
3622 } else
3623 returnval = 1;
3624 }
3625 unqueue_signals();
3626 return returnval;
3627 }
3628
3629 /**/
3630 Eprog
mkautofn(Shfunc shf)3631 mkautofn(Shfunc shf)
3632 {
3633 Eprog p;
3634
3635 p = (Eprog) zalloc(sizeof(*p));
3636 p->len = 5 * sizeof(wordcode);
3637 p->prog = (Wordcode) zalloc(p->len);
3638 p->strs = NULL;
3639 p->shf = shf;
3640 p->npats = 0;
3641 p->nref = 1; /* allocated from permanent storage */
3642 p->pats = (Patprog *) p->prog;
3643 p->flags = EF_REAL;
3644 p->dump = NULL;
3645
3646 p->prog[0] = WCB_LIST((Z_SYNC | Z_END), 0);
3647 p->prog[1] = WCB_SUBLIST(WC_SUBLIST_END, 0, 3);
3648 p->prog[2] = WCB_PIPE(WC_PIPE_END, 0);
3649 p->prog[3] = WCB_AUTOFN();
3650 p->prog[4] = WCB_END();
3651
3652 return p;
3653 }
3654
3655 /* unset: unset parameters */
3656
3657 /**/
3658 int
bin_unset(char * name,char ** argv,Options ops,int func)3659 bin_unset(char *name, char **argv, Options ops, int func)
3660 {
3661 Param pm, next;
3662 Patprog pprog;
3663 char *s;
3664 int match = 0, returnval = 0;
3665 int i;
3666
3667 /* unset -f is the same as unfunction */
3668 if (OPT_ISSET(ops,'f'))
3669 return bin_unhash(name, argv, ops, func);
3670
3671 /* with -m option, treat arguments as glob patterns */
3672 if (OPT_ISSET(ops,'m')) {
3673 while ((s = *argv++)) {
3674 queue_signals();
3675 /* expand */
3676 tokenize(s);
3677 if ((pprog = patcompile(s, PAT_STATIC, NULL))) {
3678 /* Go through the parameter table, and unset any matches */
3679 for (i = 0; i < paramtab->hsize; i++) {
3680 for (pm = (Param) paramtab->nodes[i]; pm; pm = next) {
3681 /* record pointer to next, since we may free this one */
3682 next = (Param) pm->node.next;
3683 if ((!(pm->node.flags & PM_RESTRICTED) ||
3684 unset(RESTRICTED)) &&
3685 pattry(pprog, pm->node.nam)) {
3686 unsetparam_pm(pm, 0, 1);
3687 match++;
3688 }
3689 }
3690 }
3691 } else {
3692 untokenize(s);
3693 zwarnnam(name, "bad pattern : %s", s);
3694 returnval = 1;
3695 }
3696 unqueue_signals();
3697 }
3698 /* If we didn't match anything, we return 1. */
3699 if (!match)
3700 returnval = 1;
3701 return returnval;
3702 }
3703
3704 /* do not glob -- unset the given parameter */
3705 queue_signals();
3706 while ((s = *argv++)) {
3707 char *ss = strchr(s, '['), *subscript = 0;
3708 if (ss) {
3709 char *sse;
3710 *ss = 0;
3711 if ((sse = parse_subscript(ss+1, 1, ']'))) {
3712 *sse = 0;
3713 subscript = dupstring(ss+1);
3714 *sse = ']';
3715 remnulargs(subscript);
3716 untokenize(subscript);
3717 }
3718 }
3719 if ((ss && !subscript) || !isident(s)) {
3720 if (ss)
3721 *ss = '[';
3722 zerrnam(name, "%s: invalid parameter name", s);
3723 returnval = 1;
3724 continue;
3725 }
3726 pm = (Param) (paramtab == realparamtab ?
3727 /* getnode2() to avoid autoloading */
3728 paramtab->getnode2(paramtab, s) :
3729 paramtab->getnode(paramtab, s));
3730 /*
3731 * Unsetting an unset variable is not an error.
3732 * This appears to be reasonably standard behaviour.
3733 */
3734 if (!pm)
3735 continue;
3736 else if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
3737 zerrnam(name, "%s: restricted", pm->node.nam);
3738 returnval = 1;
3739 } else if (ss) {
3740 if (PM_TYPE(pm->node.flags) == PM_HASHED) {
3741 HashTable tht = paramtab;
3742 if ((paramtab = pm->gsu.h->getfn(pm)))
3743 unsetparam(subscript);
3744 paramtab = tht;
3745 } else if (PM_TYPE(pm->node.flags) == PM_SCALAR ||
3746 PM_TYPE(pm->node.flags) == PM_ARRAY) {
3747 struct value vbuf;
3748 vbuf.isarr = (PM_TYPE(pm->node.flags) == PM_ARRAY ?
3749 SCANPM_ARRONLY : 0);
3750 vbuf.pm = pm;
3751 vbuf.flags = 0;
3752 vbuf.start = 0;
3753 vbuf.end = -1;
3754 vbuf.arr = 0;
3755 *ss = '[';
3756 if (getindex(&ss, &vbuf, SCANPM_ASSIGNING) == 0 &&
3757 vbuf.pm && !(vbuf.pm->node.flags & PM_UNSET)) {
3758 if (PM_TYPE(pm->node.flags) == PM_SCALAR) {
3759 setstrvalue(&vbuf, ztrdup(""));
3760 } else {
3761 /* start is after the element for reverse index */
3762 int start = vbuf.start - !!(vbuf.flags & VALFLAG_INV);
3763 if (arrlen_gt(vbuf.pm->u.arr, start)) {
3764 char *arr[2];
3765 arr[0] = "";
3766 arr[1] = 0;
3767 setarrvalue(&vbuf, zarrdup(arr));
3768 }
3769 }
3770 }
3771 returnval = errflag;
3772 errflag &= ~ERRFLAG_ERROR;
3773 } else {
3774 zerrnam(name, "%s: invalid element for unset", s);
3775 returnval = 1;
3776 }
3777 } else {
3778 if (unsetparam_pm(pm, 0, 1))
3779 returnval = 1;
3780 }
3781 if (ss)
3782 *ss = '[';
3783 }
3784 unqueue_signals();
3785 return returnval;
3786 }
3787
3788 /* type, whence, which, command */
3789
3790 static LinkList matchednodes;
3791
3792 static void
fetchcmdnamnode(HashNode hn,UNUSED (int printflags))3793 fetchcmdnamnode(HashNode hn, UNUSED(int printflags))
3794 {
3795 Cmdnam cn = (Cmdnam) hn;
3796 addlinknode(matchednodes, cn->node.nam);
3797 }
3798
3799 /**/
3800 int
bin_whence(char * nam,char ** argv,Options ops,int func)3801 bin_whence(char *nam, char **argv, Options ops, int func)
3802 {
3803 HashNode hn;
3804 Patprog pprog;
3805 int returnval = 0;
3806 int printflags = 0;
3807 int aliasflags;
3808 int csh, all, v, wd;
3809 int informed = 0;
3810 int expand = 0;
3811 char *cnam, **allmatched = 0;
3812
3813 /* Check some option information */
3814 csh = OPT_ISSET(ops,'c');
3815 v = OPT_ISSET(ops,'v');
3816 all = OPT_ISSET(ops,'a');
3817 wd = OPT_ISSET(ops,'w');
3818
3819 if (OPT_ISSET(ops,'x')) {
3820 char *eptr;
3821 expand = (int)zstrtol(OPT_ARG(ops,'x'), &eptr, 10);
3822 if (*eptr) {
3823 zwarnnam(nam, "number expected after -x");
3824 return 1;
3825 }
3826 if (expand == 0) /* no indentation at all */
3827 expand = -1;
3828 }
3829
3830 if (OPT_ISSET(ops,'w'))
3831 printflags |= PRINT_WHENCE_WORD;
3832 else if (OPT_ISSET(ops,'c'))
3833 printflags |= PRINT_WHENCE_CSH;
3834 else if (OPT_ISSET(ops,'v'))
3835 printflags |= PRINT_WHENCE_VERBOSE;
3836 else
3837 printflags |= PRINT_WHENCE_SIMPLE;
3838 if (OPT_ISSET(ops,'f'))
3839 printflags |= PRINT_WHENCE_FUNCDEF;
3840
3841 if (func == BIN_COMMAND)
3842 if (OPT_ISSET(ops,'V')) {
3843 printflags = aliasflags = PRINT_WHENCE_VERBOSE;
3844 v = 1;
3845 } else {
3846 aliasflags = PRINT_LIST;
3847 printflags = PRINT_WHENCE_SIMPLE;
3848 v = 0;
3849 }
3850 else
3851 aliasflags = printflags;
3852
3853 /* With -m option -- treat arguments as a glob patterns */
3854 if (OPT_ISSET(ops,'m')) {
3855 cmdnamtab->filltable(cmdnamtab);
3856 if (all) {
3857 pushheap();
3858 matchednodes = newlinklist();
3859 }
3860 queue_signals();
3861 for (; *argv; argv++) {
3862 /* parse the pattern */
3863 tokenize(*argv);
3864 if (!(pprog = patcompile(*argv, PAT_STATIC, NULL))) {
3865 untokenize(*argv);
3866 zwarnnam(nam, "bad pattern : %s", *argv);
3867 returnval = 1;
3868 continue;
3869 }
3870 if (!OPT_ISSET(ops,'p')) {
3871 /* -p option is for path search only. *
3872 * We're not using it, so search for ... */
3873
3874 /* aliases ... */
3875 informed +=
3876 scanmatchtable(aliastab, pprog, 1, 0, DISABLED,
3877 aliastab->printnode, printflags);
3878
3879 /* and reserved words ... */
3880 informed +=
3881 scanmatchtable(reswdtab, pprog, 1, 0, DISABLED,
3882 reswdtab->printnode, printflags);
3883
3884 /* and shell functions... */
3885 informed +=
3886 scanmatchshfunc(pprog, 1, 0, DISABLED,
3887 shfunctab->printnode, printflags, expand);
3888
3889 /* and builtins. */
3890 informed +=
3891 scanmatchtable(builtintab, pprog, 1, 0, DISABLED,
3892 builtintab->printnode, printflags);
3893 }
3894 /* Done search for `internal' commands, if the -p option *
3895 * was not used. Now search the path. */
3896 informed +=
3897 scanmatchtable(cmdnamtab, pprog, 1, 0, 0,
3898 (all ? fetchcmdnamnode : cmdnamtab->printnode),
3899 printflags);
3900 run_queued_signals();
3901 }
3902 unqueue_signals();
3903 if (all) {
3904 allmatched = argv = zlinklist2array(matchednodes);
3905 matchednodes = NULL;
3906 popheap();
3907 } else
3908 return returnval || !informed;
3909 }
3910
3911 /* Take arguments literally -- do not glob */
3912 queue_signals();
3913 for (; *argv; argv++) {
3914 if (!OPT_ISSET(ops,'p') && !allmatched) {
3915 char *suf;
3916
3917 /* Look for alias */
3918 if ((hn = aliastab->getnode(aliastab, *argv))) {
3919 aliastab->printnode(hn, aliasflags);
3920 informed = 1;
3921 if (!all)
3922 continue;
3923 }
3924 /* Look for suffix alias */
3925 if ((suf = strrchr(*argv, '.')) && suf[1] &&
3926 suf > *argv && suf[-1] != Meta &&
3927 (hn = sufaliastab->getnode(sufaliastab, suf+1))) {
3928 sufaliastab->printnode(hn, printflags);
3929 informed = 1;
3930 if (!all)
3931 continue;
3932 }
3933 /* Look for reserved word */
3934 if ((hn = reswdtab->getnode(reswdtab, *argv))) {
3935 reswdtab->printnode(hn, printflags);
3936 informed = 1;
3937 if (!all)
3938 continue;
3939 }
3940 /* Look for shell function */
3941 if ((hn = shfunctab->getnode(shfunctab, *argv))) {
3942 printshfuncexpand(hn, printflags, expand);
3943 informed = 1;
3944 if (!all)
3945 continue;
3946 }
3947 /* Look for builtin command */
3948 if ((hn = builtintab->getnode(builtintab, *argv))) {
3949 builtintab->printnode(hn, printflags);
3950 informed = 1;
3951 if (!all)
3952 continue;
3953 }
3954 /* Look for commands that have been added to the *
3955 * cmdnamtab with the builtin `hash foo=bar'. */
3956 if ((hn = cmdnamtab->getnode(cmdnamtab, *argv)) && (hn->flags & HASHED)) {
3957 cmdnamtab->printnode(hn, printflags);
3958 informed = 1;
3959 if (!all)
3960 continue;
3961 }
3962 }
3963
3964 /* Option -a is to search the entire path, *
3965 * rather than just looking for one match. */
3966 if (all && **argv != '/') {
3967 char **pp, *buf;
3968
3969 pushheap();
3970 for (pp = path; *pp; pp++) {
3971 if (**pp) {
3972 buf = zhtricat(*pp, "/", *argv);
3973 } else buf = dupstring(*argv);
3974
3975 if (iscom(buf)) {
3976 if (wd) {
3977 printf("%s: command\n", *argv);
3978 } else {
3979 if (v && !csh) {
3980 zputs(*argv, stdout), fputs(" is ", stdout);
3981 quotedzputs(buf, stdout);
3982 } else
3983 zputs(buf, stdout);
3984 if (OPT_ISSET(ops,'s') || OPT_ISSET(ops, 'S'))
3985 print_if_link(buf, OPT_ISSET(ops, 'S'));
3986 fputc('\n', stdout);
3987 }
3988 informed = 1;
3989 }
3990 }
3991 if (!informed && (wd || v || csh)) {
3992 /* this is information and not an error so, as in csh, use stdout */
3993 zputs(*argv, stdout);
3994 puts(wd ? ": none" : " not found");
3995 returnval = 1;
3996 }
3997 popheap();
3998 } else if (func == BIN_COMMAND && OPT_ISSET(ops,'p') &&
3999 (hn = builtintab->getnode(builtintab, *argv))) {
4000 /*
4001 * Special case for "command -p[vV]" which needs to
4002 * show a builtin in preference to an external command.
4003 */
4004 builtintab->printnode(hn, printflags);
4005 informed = 1;
4006 } else if ((cnam = findcmd(*argv, 1,
4007 func == BIN_COMMAND &&
4008 OPT_ISSET(ops,'p')))) {
4009 /* Found external command. */
4010 if (wd) {
4011 printf("%s: command\n", *argv);
4012 } else {
4013 if (v && !csh) {
4014 zputs(*argv, stdout), fputs(" is ", stdout);
4015 quotedzputs(cnam, stdout);
4016 } else
4017 zputs(cnam, stdout);
4018 if (OPT_ISSET(ops,'s') || OPT_ISSET(ops,'S'))
4019 print_if_link(cnam, OPT_ISSET(ops,'S'));
4020 fputc('\n', stdout);
4021 }
4022 informed = 1;
4023 } else {
4024 /* Not found at all. That's not an error as such so this goes to stdout */
4025 if (v || csh || wd)
4026 zputs(*argv, stdout), puts(wd ? ": none" : " not found");
4027 returnval = 1;
4028 }
4029 }
4030 if (allmatched)
4031 freearray(allmatched);
4032
4033 unqueue_signals();
4034 return returnval || !informed;
4035 }
4036
4037 /**** command & named directory hash table builtins ****/
4038
4039 /*****************************************************************
4040 * hash -- explicitly hash a command. *
4041 * 1) Given no arguments, list the hash table. *
4042 * 2) The -m option prints out commands in the hash table that *
4043 * match a given glob pattern. *
4044 * 3) The -f option causes the entire path to be added to the *
4045 * hash table (cannot be combined with any arguments). *
4046 * 4) The -r option causes the entire hash table to be discarded *
4047 * (cannot be combined with any arguments). *
4048 * 5) Given argument of the form foo=bar, add element to command *
4049 * hash table, so that when `foo' is entered, then `bar' is *
4050 * executed. *
4051 * 6) Given arguments not of the previous form, add it to the *
4052 * command hash table as if it were being executed. *
4053 * 7) The -d option causes analogous things to be done using *
4054 * the named directory hash table. *
4055 *****************************************************************/
4056
4057 /**/
4058 int
bin_hash(char * name,char ** argv,Options ops,UNUSED (int func))4059 bin_hash(char *name, char **argv, Options ops, UNUSED(int func))
4060 {
4061 HashTable ht;
4062 Patprog pprog;
4063 Asgment asg;
4064 int returnval = 0;
4065 int printflags = 0;
4066
4067 if (OPT_ISSET(ops,'d'))
4068 ht = nameddirtab;
4069 else
4070 ht = cmdnamtab;
4071
4072 if (OPT_ISSET(ops,'r') || OPT_ISSET(ops,'f')) {
4073 /* -f and -r can't be used with any arguments */
4074 if (*argv) {
4075 zwarnnam("hash", "too many arguments");
4076 return 1;
4077 }
4078
4079 /* empty the hash table */
4080 if (OPT_ISSET(ops,'r'))
4081 ht->emptytable(ht);
4082
4083 /* fill the hash table in a standard way */
4084 if (OPT_ISSET(ops,'f'))
4085 ht->filltable(ht);
4086
4087 return 0;
4088 }
4089
4090 if (OPT_ISSET(ops,'L')) printflags |= PRINT_LIST;
4091
4092 /* Given no arguments, display current hash table. */
4093 if (!*argv) {
4094 queue_signals();
4095 scanhashtable(ht, 1, 0, 0, ht->printnode, printflags);
4096 unqueue_signals();
4097 return 0;
4098 }
4099
4100 queue_signals();
4101 while (*argv) {
4102 void *hn;
4103 if (OPT_ISSET(ops,'m')) {
4104 /* with the -m option, treat the argument as a glob pattern */
4105 tokenize(*argv); /* expand */
4106 if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) {
4107 /* display matching hash table elements */
4108 scanmatchtable(ht, pprog, 1, 0, 0, ht->printnode, printflags);
4109 } else {
4110 untokenize(*argv);
4111 zwarnnam(name, "bad pattern : %s", *argv);
4112 returnval = 1;
4113 }
4114 argv++;
4115 continue;
4116 }
4117 if (!(asg = getasg(&argv, NULL))) {
4118 zwarnnam(name, "bad assignment");
4119 returnval = 1;
4120 break;
4121 } else if (ASG_VALUEP(asg)) {
4122 if(isset(RESTRICTED)) {
4123 zwarnnam(name, "restricted: %s", asg->value.scalar);
4124 returnval = 1;
4125 } else {
4126 /* The argument is of the form foo=bar, *
4127 * so define an entry for the table. */
4128 if(OPT_ISSET(ops,'d')) {
4129 /* shouldn't return NULL if asg->name is not NULL */
4130 if (*itype_end(asg->name, IUSER, 0)) {
4131 zwarnnam(name,
4132 "invalid character in directory name: %s",
4133 asg->name);
4134 returnval = 1;
4135 continue;
4136 } else {
4137 Nameddir nd = hn = zshcalloc(sizeof *nd);
4138 nd->node.flags = 0;
4139 nd->dir = ztrdup(asg->value.scalar);
4140 }
4141 } else {
4142 Cmdnam cn = hn = zshcalloc(sizeof *cn);
4143 cn->node.flags = HASHED;
4144 cn->u.cmd = ztrdup(asg->value.scalar);
4145 }
4146 ht->addnode(ht, ztrdup(asg->name), hn);
4147 if(OPT_ISSET(ops,'v'))
4148 ht->printnode(hn, 0);
4149 }
4150 } else if (!(hn = ht->getnode2(ht, asg->name))) {
4151 /* With no `=value' part to the argument, *
4152 * work out what it ought to be. */
4153 if(OPT_ISSET(ops,'d')) {
4154 if(!getnameddir(asg->name)) {
4155 zwarnnam(name, "no such directory name: %s", asg->name);
4156 returnval = 1;
4157 }
4158 } else {
4159 if (!hashcmd(asg->name, path)) {
4160 zwarnnam(name, "no such command: %s", asg->name);
4161 returnval = 1;
4162 }
4163 }
4164 if(OPT_ISSET(ops,'v') && (hn = ht->getnode2(ht, asg->name)))
4165 ht->printnode(hn, 0);
4166 } else if(OPT_ISSET(ops,'v'))
4167 ht->printnode(hn, 0);
4168 }
4169 unqueue_signals();
4170 return returnval;
4171 }
4172
4173 /* unhash: remove specified elements from a hash table */
4174
4175 /**/
4176 int
bin_unhash(char * name,char ** argv,Options ops,int func)4177 bin_unhash(char *name, char **argv, Options ops, int func)
4178 {
4179 HashTable ht;
4180 HashNode hn, nhn;
4181 Patprog pprog;
4182 int match = 0, returnval = 0, all = 0;
4183 int i;
4184
4185 /* Check which hash table we are working with. */
4186 if (func == BIN_UNALIAS) {
4187 if (OPT_ISSET(ops,'s'))
4188 ht = sufaliastab; /* suffix aliases */
4189 else
4190 ht = aliastab; /* aliases */
4191 if (OPT_ISSET(ops, 'a')) {
4192 if (*argv) {
4193 zwarnnam(name, "-a: too many arguments");
4194 return 1;
4195 }
4196 all = 1;
4197 } else if (!*argv) {
4198 zwarnnam(name, "not enough arguments");
4199 return 1;
4200 }
4201 } else if (OPT_ISSET(ops,'d'))
4202 ht = nameddirtab; /* named directories */
4203 else if (OPT_ISSET(ops,'f'))
4204 ht = shfunctab; /* shell functions */
4205 else if (OPT_ISSET(ops,'s'))
4206 ht = sufaliastab; /* suffix aliases, must precede aliases */
4207 else if (func == BIN_UNHASH && (OPT_ISSET(ops,'a')))
4208 ht = aliastab; /* aliases */
4209 else
4210 ht = cmdnamtab; /* external commands */
4211
4212 if (all) {
4213 queue_signals();
4214 for (i = 0; i < ht->hsize; i++) {
4215 for (hn = ht->nodes[i]; hn; hn = nhn) {
4216 /* record pointer to next, since we may free this one */
4217 nhn = hn->next;
4218 ht->freenode(ht->removenode(ht, hn->nam));
4219 }
4220 }
4221 unqueue_signals();
4222 return 0;
4223 }
4224
4225 /* With -m option, treat arguments as glob patterns. *
4226 * "unhash -m '*'" is legal, but not recommended. */
4227 if (OPT_ISSET(ops,'m')) {
4228 for (; *argv; argv++) {
4229 queue_signals();
4230 /* expand argument */
4231 tokenize(*argv);
4232 if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) {
4233 /* remove all nodes matching glob pattern */
4234 for (i = 0; i < ht->hsize; i++) {
4235 for (hn = ht->nodes[i]; hn; hn = nhn) {
4236 /* record pointer to next, since we may free this one */
4237 nhn = hn->next;
4238 if (pattry(pprog, hn->nam)) {
4239 ht->freenode(ht->removenode(ht, hn->nam));
4240 match++;
4241 }
4242 }
4243 }
4244 } else {
4245 untokenize(*argv);
4246 zwarnnam(name, "bad pattern : %s", *argv);
4247 returnval = 1;
4248 }
4249 unqueue_signals();
4250 }
4251 /* If we didn't match anything, we return 1. */
4252 if (!match)
4253 returnval = 1;
4254 return returnval;
4255 }
4256
4257 /* Take arguments literally -- do not glob */
4258 queue_signals();
4259 for (; *argv; argv++) {
4260 if ((hn = ht->removenode(ht, *argv))) {
4261 ht->freenode(hn);
4262 } else if (func == BIN_UNSET && isset(POSIXBUILTINS)) {
4263 /* POSIX: unset: "Unsetting a variable or function that was *
4264 * not previously set shall not be considered an error." */
4265 returnval = 0;
4266 } else {
4267 zwarnnam(name, "no such hash table element: %s", *argv);
4268 returnval = 1;
4269 }
4270 }
4271 unqueue_signals();
4272 return returnval;
4273 }
4274
4275 /**** alias builtins ****/
4276
4277 /* alias: display or create aliases. */
4278
4279 /**/
4280 int
bin_alias(char * name,char ** argv,Options ops,UNUSED (int func))4281 bin_alias(char *name, char **argv, Options ops, UNUSED(int func))
4282 {
4283 Alias a;
4284 Patprog pprog;
4285 Asgment asg;
4286 int returnval = 0;
4287 int flags1 = 0, flags2 = DISABLED;
4288 int printflags = 0;
4289 int type_opts;
4290 HashTable ht = aliastab;
4291
4292 /* Did we specify the type of alias? */
4293 type_opts = OPT_ISSET(ops, 'r') + OPT_ISSET(ops, 'g') +
4294 OPT_ISSET(ops, 's');
4295 if (type_opts) {
4296 if (type_opts > 1) {
4297 zwarnnam(name, "illegal combination of options");
4298 return 1;
4299 }
4300 if (OPT_ISSET(ops,'g'))
4301 flags1 |= ALIAS_GLOBAL;
4302 else
4303 flags2 |= ALIAS_GLOBAL;
4304 if (OPT_ISSET(ops, 's')) {
4305 /*
4306 * Although we keep suffix aliases in a different table,
4307 * it is useful to be able to distinguish Alias structures
4308 * without reference to the table, so we have a separate
4309 * flag, too.
4310 */
4311 flags1 |= ALIAS_SUFFIX;
4312 ht = sufaliastab;
4313 } else
4314 flags2 |= ALIAS_SUFFIX;
4315 }
4316
4317 if (OPT_ISSET(ops,'L'))
4318 printflags |= PRINT_LIST;
4319 else if (OPT_PLUS(ops,'g') || OPT_PLUS(ops,'r') || OPT_PLUS(ops,'s') ||
4320 OPT_PLUS(ops,'m') || OPT_ISSET(ops,'+'))
4321 printflags |= PRINT_NAMEONLY;
4322
4323 /* In the absence of arguments, list all aliases. If a command *
4324 * line flag is specified, list only those of that type. */
4325 if (!*argv) {
4326 queue_signals();
4327 scanhashtable(ht, 1, flags1, flags2, ht->printnode, printflags);
4328 unqueue_signals();
4329 return 0;
4330 }
4331
4332 /* With the -m option, treat the arguments as *
4333 * glob patterns of aliases to display. */
4334 if (OPT_ISSET(ops,'m')) {
4335 for (; *argv; argv++) {
4336 queue_signals();
4337 tokenize(*argv); /* expand argument */
4338 if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) {
4339 /* display the matching aliases */
4340 scanmatchtable(ht, pprog, 1, flags1, flags2,
4341 ht->printnode, printflags);
4342 } else {
4343 untokenize(*argv);
4344 zwarnnam(name, "bad pattern : %s", *argv);
4345 returnval = 1;
4346 }
4347 unqueue_signals();
4348 }
4349 return returnval;
4350 }
4351
4352 /* Take arguments literally. Don't glob */
4353 queue_signals();
4354 while ((asg = getasg(&argv, NULL))) {
4355 if (asg->value.scalar && !OPT_ISSET(ops,'L')) {
4356 /* The argument is of the form foo=bar and we are not *
4357 * forcing a listing with -L, so define an alias */
4358 ht->addnode(ht, ztrdup(asg->name),
4359 createaliasnode(ztrdup(asg->value.scalar), flags1));
4360 } else if ((a = (Alias) ht->getnode(ht, asg->name))) {
4361 /* display alias if appropriate */
4362 if (!type_opts || ht == sufaliastab ||
4363 (OPT_ISSET(ops,'r') &&
4364 !(a->node.flags & (ALIAS_GLOBAL|ALIAS_SUFFIX))) ||
4365 (OPT_ISSET(ops,'g') && (a->node.flags & ALIAS_GLOBAL)))
4366 ht->printnode(&a->node, printflags);
4367 } else
4368 returnval = 1;
4369 }
4370 unqueue_signals();
4371 return returnval;
4372 }
4373
4374
4375 /**** miscellaneous builtins ****/
4376
4377 /* true, : (colon) */
4378
4379 /**/
4380 int
bin_true(UNUSED (char * name),UNUSED (char ** argv),UNUSED (Options ops),UNUSED (int func))4381 bin_true(UNUSED(char *name), UNUSED(char **argv), UNUSED(Options ops), UNUSED(int func))
4382 {
4383 return 0;
4384 }
4385
4386 /* false builtin */
4387
4388 /**/
4389 int
bin_false(UNUSED (char * name),UNUSED (char ** argv),UNUSED (Options ops),UNUSED (int func))4390 bin_false(UNUSED(char *name), UNUSED(char **argv), UNUSED(Options ops), UNUSED(int func))
4391 {
4392 return 1;
4393 }
4394
4395 /* the zle buffer stack */
4396
4397 /**/
4398 mod_export LinkList bufstack;
4399
4400 /* echo, print, printf, pushln */
4401
4402 #define print_val(VAL) \
4403 if (prec >= 0) \
4404 count += fprintf(fout, spec, width, prec, VAL); \
4405 else \
4406 count += fprintf(fout, spec, width, VAL);
4407
4408 /*
4409 * Because of the use of getkeystring() to interpret the arguments,
4410 * the elements of args spend a large part of the function unmetafied
4411 * with the lengths in len. This may have seemed a good idea once.
4412 * As we are stuck with this for now, we need to be very careful
4413 * deciding what state args is in.
4414 */
4415
4416 /**/
4417 int
bin_print(char * name,char ** args,Options ops,int func)4418 bin_print(char *name, char **args, Options ops, int func)
4419 {
4420 int flen, width, prec, type, argc, n, narg, curlen = 0;
4421 int nnl = 0, fmttrunc = 0, ret = 0, maxarg = 0, nc = 0;
4422 int flags[6], *len, visarr = 0;
4423 char *start, *endptr, *c, *d, *flag, *buf = NULL, spec[14], *fmt = NULL;
4424 char **first, **argp, *curarg, *flagch = "'0+- #", save = '\0', nullstr = '\0';
4425 size_t rcount = 0, count = 0;
4426 size_t *cursplit = 0, *splits = 0;
4427 FILE *fout = stdout;
4428 #ifdef HAVE_OPEN_MEMSTREAM
4429 size_t mcount;
4430 #define ASSIGN_MSTREAM(BUF,FOUT) \
4431 do { \
4432 if ((FOUT = open_memstream(&BUF, &mcount)) == NULL) { \
4433 zwarnnam(name, "open_memstream failed"); \
4434 return 1; \
4435 } \
4436 } while (0)
4437 /*
4438 * Some implementations of open_memstream() have a bug such that,
4439 * if fflush() is followed by fclose(), another NUL byte is written
4440 * to the buffer at the wrong position. Therefore we must fclose()
4441 * before reading.
4442 */
4443 #define READ_MSTREAM(BUF,FOUT) \
4444 ((fclose(FOUT) == 0) ? mcount : (size_t)-1)
4445 #define CLOSE_MSTREAM(FOUT) 0
4446
4447 #else /* simulate HAVE_OPEN_MEMSTREAM */
4448
4449 #define ASSIGN_MSTREAM(BUF,FOUT) \
4450 do { \
4451 int tempfd; \
4452 char *tmpf; \
4453 if ((tempfd = gettempfile(NULL, 1, &tmpf)) < 0) { \
4454 zwarnnam(name, "can't open temp file: %e", errno); \
4455 return 1; \
4456 } \
4457 unlink(tmpf); \
4458 if ((FOUT = fdopen(tempfd, "w+")) == NULL) { \
4459 close(tempfd); \
4460 zwarnnam(name, "can't open temp file: %e", errno); \
4461 return 1; \
4462 } \
4463 } while (0)
4464 #define READ_MSTREAM(BUF,FOUT) \
4465 ((((count = ftell(FOUT)), (BUF = (char *)zalloc(count + 1))) && \
4466 ((fseek(FOUT, 0L, SEEK_SET) == 0) && !(BUF[count] = '\0')) && \
4467 (fread(BUF, 1, count, FOUT) == count)) ? count : (size_t)-1)
4468 #define CLOSE_MSTREAM(FOUT) fclose(FOUT)
4469
4470 #endif
4471
4472 #define IS_MSTREAM(FOUT) \
4473 (FOUT != stdout && \
4474 (OPT_ISSET(ops,'z') || OPT_ISSET(ops,'s') || OPT_ISSET(ops,'v')))
4475
4476 /* Testing EBADF special-cases >&- redirections */
4477 #define CLOSE_CLEANLY(FOUT) \
4478 (IS_MSTREAM(FOUT) ? CLOSE_MSTREAM(FOUT) == 0 : \
4479 ((FOUT == stdout) ? (fflush(FOUT) == 0 || errno == EBADF) : \
4480 (fclose(FOUT) == 0))) /* implies error for -u on a closed fd */
4481
4482 Histent ent;
4483 mnumber mnumval;
4484 double doubleval;
4485 int intval;
4486 zlong zlongval;
4487 zulong zulongval;
4488 char *stringval;
4489
4490 /* Error check option combinations and option arguments */
4491
4492 if (OPT_ISSET(ops, 'z') +
4493 OPT_ISSET(ops, 's') + OPT_ISSET(ops, 'S') +
4494 OPT_ISSET(ops, 'v') > 1) {
4495 zwarnnam(name, "only one of -s, -S, -v, or -z allowed");
4496 return 1;
4497 }
4498 if ((OPT_ISSET(ops, 'z') | OPT_ISSET(ops, 's') | OPT_ISSET(ops, 'S')) +
4499 (OPT_ISSET(ops, 'c') | OPT_ISSET(ops, 'C')) > 1) {
4500 zwarnnam(name, "-c or -C not allowed with -s, -S, or -z");
4501 return 1;
4502 }
4503 if ((OPT_ISSET(ops, 'z') | OPT_ISSET(ops, 'v') |
4504 OPT_ISSET(ops, 's') | OPT_ISSET(ops, 'S')) +
4505 (OPT_ISSET(ops, 'p') | OPT_ISSET(ops, 'u')) > 1) {
4506 zwarnnam(name, "-p or -u not allowed with -s, -S, -v, or -z");
4507 return 1;
4508 }
4509 /*
4510 if (OPT_ISSET(ops, 'f') &&
4511 (OPT_ISSET(ops, 'S') || OPT_ISSET(ops, 'c') || OPT_ISSET(ops, 'C'))) {
4512 zwarnnam(name, "-f not allowed with -c, -C, or -S");
4513 return 1;
4514 }
4515 */
4516
4517 /* -C -- number of columns */
4518 if (!fmt && OPT_ISSET(ops,'C')) {
4519 char *eptr, *argptr = OPT_ARG(ops,'C');
4520 nc = (int)zstrtol(argptr, &eptr, 10);
4521 if (*eptr) {
4522 zwarnnam(name, "number expected after -%c: %s", 'C', argptr);
4523 return 1;
4524 }
4525 if (nc <= 0) {
4526 zwarnnam(name, "invalid number of columns: %s", argptr);
4527 return 1;
4528 }
4529 }
4530
4531 if (func == BIN_PRINTF) {
4532 if (!strcmp(*args, "--") && !*++args) {
4533 zwarnnam(name, "not enough arguments");
4534 return 1;
4535 }
4536 fmt = *args++;
4537 } else if (func == BIN_ECHO && isset(BSDECHO))
4538 ops->ind['E'] = 1;
4539 else if (OPT_HASARG(ops,'f'))
4540 fmt = OPT_ARG(ops,'f');
4541 if (fmt)
4542 fmt = getkeystring(fmt, &flen, OPT_ISSET(ops,'b') ? GETKEYS_BINDKEY :
4543 GETKEYS_PRINTF_FMT, &fmttrunc);
4544
4545 first = args;
4546
4547 /* -m option -- treat the first argument as a pattern and remove
4548 * arguments not matching */
4549 if (OPT_ISSET(ops,'m')) {
4550 Patprog pprog;
4551 char **t, **p;
4552
4553 if (!*args) {
4554 zwarnnam(name, "no pattern specified");
4555 return 1;
4556 }
4557 queue_signals();
4558 tokenize(*args);
4559 if (!(pprog = patcompile(*args, PAT_STATIC, NULL))) {
4560 untokenize(*args);
4561 zwarnnam(name, "bad pattern: %s", *args);
4562 unqueue_signals();
4563 return 1;
4564 }
4565 for (t = p = ++args; *p; p++)
4566 if (pattry(pprog, *p))
4567 *t++ = *p;
4568 *t = NULL;
4569 first = args;
4570 unqueue_signals();
4571 if (fmt && !*args) return 0;
4572 }
4573 /* compute lengths, and interpret according to -P, -D, -e, etc. */
4574 argc = arrlen(args);
4575 len = (int *) hcalloc(argc * sizeof(int));
4576 for (n = 0; n < argc; n++) {
4577 /* first \ sequences */
4578 if (fmt ||
4579 (!OPT_ISSET(ops,'e') &&
4580 (OPT_ISSET(ops,'R') || OPT_ISSET(ops,'r') || OPT_ISSET(ops,'E'))))
4581 unmetafy(args[n], &len[n]);
4582 else {
4583 int escape_how;
4584 if (OPT_ISSET(ops,'b'))
4585 escape_how = GETKEYS_BINDKEY;
4586 else if (func != BIN_ECHO && !OPT_ISSET(ops,'e'))
4587 escape_how = GETKEYS_PRINT;
4588 else
4589 escape_how = GETKEYS_ECHO;
4590 args[n] = getkeystring(args[n], &len[n], escape_how, &nnl);
4591 if (nnl) {
4592 /* If there was a \c escape, make this the last arg. */
4593 argc = n + 1;
4594 args[argc] = NULL;
4595 }
4596 }
4597 /* -P option -- interpret as a prompt sequence */
4598 if (OPT_ISSET(ops,'P')) {
4599 /*
4600 * promptexpand uses permanent storage: to avoid
4601 * messy memory management, stick it on the heap
4602 * instead.
4603 */
4604 char *str = unmetafy(
4605 promptexpand(metafy(args[n], len[n], META_NOALLOC),
4606 0, NULL, NULL, NULL),
4607 &len[n]);
4608 args[n] = dupstrpfx(str, len[n]);
4609 free(str);
4610 }
4611 /* -D option -- interpret as a directory, and use ~ */
4612 if (OPT_ISSET(ops,'D')) {
4613 Nameddir d;
4614
4615 queue_signals();
4616 /* TODO: finddir takes a metafied file */
4617 d = finddir(args[n]);
4618 if (d) {
4619 int dirlen = strlen(d->dir);
4620 char *arg = zhalloc(len[n] - dirlen + strlen(d->node.nam) + 2);
4621 sprintf(arg, "~%s%s", d->node.nam, args[n] + dirlen);
4622 args[n] = arg;
4623 len[n] = strlen(args[n]);
4624 }
4625 unqueue_signals();
4626 }
4627 }
4628
4629 /* -o and -O -- sort the arguments */
4630 if (OPT_ISSET(ops,'o') || OPT_ISSET(ops,'O')) {
4631 int flags;
4632
4633 if (fmt && !*args)
4634 return 0;
4635 flags = OPT_ISSET(ops,'i') ? SORTIT_IGNORING_CASE : 0;
4636 if (OPT_ISSET(ops,'O'))
4637 flags |= SORTIT_BACKWARDS;
4638 strmetasort(args, flags, len);
4639 }
4640
4641 /* -u and -p -- output to other than standard output */
4642 if ((OPT_HASARG(ops,'u') || OPT_ISSET(ops,'p')) &&
4643 /* rule out conflicting options -- historical precedence */
4644 ((!fmt && (OPT_ISSET(ops,'c') || OPT_ISSET(ops,'C'))) ||
4645 !(OPT_ISSET(ops, 'z') || OPT_ISSET(ops, 'v') ||
4646 OPT_ISSET(ops, 's') || OPT_ISSET(ops, 'S')))) {
4647 int fdarg, fd;
4648
4649 if (OPT_ISSET(ops, 'p')) {
4650 fdarg = coprocout;
4651 if (fdarg < 0) {
4652 zwarnnam(name, "-p: no coprocess");
4653 return 1;
4654 }
4655 } else {
4656 char *argptr = OPT_ARG(ops,'u'), *eptr;
4657 /* Handle undocumented feature that -up worked */
4658 if (!strcmp(argptr, "p")) {
4659 fdarg = coprocout;
4660 if (fdarg < 0) {
4661 zwarnnam(name, "-p: no coprocess");
4662 return 1;
4663 }
4664 } else {
4665 fdarg = (int)zstrtol(argptr, &eptr, 10);
4666 if (*eptr) {
4667 zwarnnam(name, "number expected after -u: %s", argptr);
4668 return 1;
4669 }
4670 }
4671 }
4672
4673 if ((fd = dup(fdarg)) < 0) {
4674 zwarnnam(name, "bad file number: %d", fdarg);
4675 return 1;
4676 }
4677 if ((fout = fdopen(fd, "w")) == 0) {
4678 close(fd);
4679 zwarnnam(name, "bad mode on fd %d", fd);
4680 return 1;
4681 }
4682 }
4683
4684 if (OPT_ISSET(ops, 'v') ||
4685 (fmt && (OPT_ISSET(ops,'z') || OPT_ISSET(ops,'s'))))
4686 ASSIGN_MSTREAM(buf,fout);
4687
4688 /* -c -- output in columns */
4689 if (!fmt && (OPT_ISSET(ops,'c') || OPT_ISSET(ops,'C'))) {
4690 int l, nr, sc, n, t, i;
4691 #ifdef MULTIBYTE_SUPPORT
4692 int *widths;
4693
4694 if (isset(MULTIBYTE)) {
4695 int *wptr;
4696
4697 /*
4698 * We need the character widths to align output in
4699 * columns.
4700 */
4701 wptr = widths = (int *) zhalloc(argc * sizeof(int));
4702 for (i = 0; i < argc && args[i]; i++, wptr++) {
4703 int l = len[i], width = 0;
4704 char *aptr = args[i];
4705 mbstate_t mbs;
4706
4707 memset(&mbs, 0, sizeof(mbstate_t));
4708 while (l > 0) {
4709 wchar_t wc;
4710 size_t cnt;
4711 int wcw;
4712
4713 /*
4714 * Prevent misaligned columns due to escape sequences by
4715 * skipping over them. Octals \033 and \233 are the
4716 * possible escape characters recognized by ANSI.
4717 *
4718 * It ought to be possible to do this in the case
4719 * of prompt expansion by propagating the information
4720 * about escape sequences (currently we strip this
4721 * out).
4722 */
4723 if (*aptr == '\033' || *aptr == '\233') {
4724 for (aptr++, l--;
4725 l && !isalpha(STOUC(*aptr));
4726 aptr++, l--)
4727 ;
4728 aptr++;
4729 l--;
4730 continue;
4731 }
4732
4733 cnt = mbrtowc(&wc, aptr, l, &mbs);
4734
4735 if (cnt == MB_INCOMPLETE || cnt == MB_INVALID)
4736 {
4737 /* treat as ordinary string */
4738 width += l;
4739 break;
4740 }
4741 wcw = WCWIDTH(wc);
4742 /* treat unprintable as 0 */
4743 if (wcw > 0)
4744 width += wcw;
4745 /* skip over NUL normally */
4746 if (cnt == 0)
4747 cnt = 1;
4748 aptr += cnt;
4749 l -= cnt;
4750 }
4751 widths[i] = width;
4752 }
4753 }
4754 else
4755 widths = len;
4756 #else
4757 int *widths = len;
4758 #endif
4759
4760 if (OPT_ISSET(ops,'C')) {
4761 /*
4762 * n: number of elements
4763 * nc: number of columns (above)
4764 * nr: number of rows
4765 */
4766 n = arrlen(args);
4767 nr = (n + nc - 1) / nc;
4768
4769 /*
4770 * i: loop counter
4771 * l: maximum length seen
4772 *
4773 * Ignore lengths in last column since they don't affect
4774 * the separation.
4775 */
4776 for (i = l = 0; i < argc; i++) {
4777 if (OPT_ISSET(ops, 'a')) {
4778 if ((i % nc) == nc - 1)
4779 continue;
4780 } else {
4781 if (i >= nr * (nc - 1))
4782 break;
4783 }
4784 if (l < widths[i])
4785 l = widths[i];
4786 }
4787 sc = l + 2;
4788 }
4789 else
4790 {
4791 /*
4792 * n: loop counter
4793 * l: maximum length seen
4794 */
4795 for (n = l = 0; n < argc; n++)
4796 if (l < widths[n])
4797 l = widths[n];
4798
4799 /*
4800 * sc: column width
4801 * nc: number of columns (at least one)
4802 */
4803 sc = l + 2;
4804 nc = (zterm_columns + 1) / sc;
4805 if (!nc)
4806 nc = 1;
4807 nr = (n + nc - 1) / nc;
4808 }
4809
4810 if (OPT_ISSET(ops,'a')) /* print across, i.e. columns first */
4811 n = 0;
4812 for (i = 0; i < nr; i++) {
4813 if (OPT_ISSET(ops,'a'))
4814 {
4815 int ic;
4816 for (ic = 0; ic < nc && n < argc; ic++, n++)
4817 {
4818 fwrite(args[n], len[n], 1, fout);
4819 l = widths[n];
4820 if (n < argc)
4821 for (; l < sc; l++)
4822 fputc(' ', fout);
4823 }
4824 }
4825 else
4826 {
4827 n = i;
4828 do {
4829 fwrite(args[n], len[n], 1, fout);
4830 l = widths[n];
4831 for (t = nr; t && n < argc; t--, n++);
4832 if (n < argc)
4833 for (; l < sc; l++)
4834 fputc(' ', fout);
4835 } while (n < argc);
4836 }
4837 fputc(OPT_ISSET(ops,'N') ? '\0' : '\n', fout);
4838 }
4839 if (IS_MSTREAM(fout) && (rcount = READ_MSTREAM(buf,fout)) == -1)
4840 ret = 1;
4841 if (!CLOSE_CLEANLY(fout) || ret) {
4842 zwarnnam(name, "write error: %e", errno);
4843 ret = 1;
4844 }
4845 if (buf) {
4846 /* assert: we must be doing -v at this point */
4847 queue_signals();
4848 if (ret)
4849 free(buf);
4850 else
4851 setsparam(OPT_ARG(ops, 'v'),
4852 metafy(buf, rcount, META_REALLOC));
4853 unqueue_signals();
4854 }
4855 return ret;
4856 }
4857
4858 /* normal output */
4859 if (!fmt) {
4860 if (OPT_ISSET(ops, 'z') || OPT_ISSET(ops, 'v') ||
4861 OPT_ISSET(ops, 's') || OPT_ISSET(ops, 'S')) {
4862 /*
4863 * We don't want the arguments unmetafied after all.
4864 */
4865 for (n = 0; n < argc; n++)
4866 metafy(args[n], len[n], META_NOALLOC);
4867 }
4868
4869 /* -z option -- push the arguments onto the editing buffer stack */
4870 if (OPT_ISSET(ops,'z')) {
4871 queue_signals();
4872 zpushnode(bufstack, sepjoin(args, NULL, 0));
4873 unqueue_signals();
4874 return 0;
4875 }
4876 /* -s option -- add the arguments to the history list */
4877 if (OPT_ISSET(ops,'s') || OPT_ISSET(ops,'S')) {
4878 int nwords = 0, nlen, iwords;
4879 char **pargs = args;
4880
4881 queue_signals();
4882 while (*pargs++)
4883 nwords++;
4884 if (nwords) {
4885 if (OPT_ISSET(ops,'S')) {
4886 int wordsize;
4887 short *words;
4888 if (nwords > 1) {
4889 zwarnnam(name, "option -S takes a single argument");
4890 unqueue_signals();
4891 return 1;
4892 }
4893 words = NULL;
4894 wordsize = 0;
4895 histsplitwords(*args, &words, &wordsize, &nwords, 1);
4896 ent = prepnexthistent();
4897 ent->words = (short *)zalloc(nwords*sizeof(short));
4898 memcpy(ent->words, words, nwords*sizeof(short));
4899 free(words);
4900 ent->nwords = nwords/2;
4901 } else {
4902 ent = prepnexthistent();
4903 ent->words = (short *)zalloc(nwords*2*sizeof(short));
4904 ent->nwords = nwords;
4905 nlen = iwords = 0;
4906 for (pargs = args; *pargs; pargs++) {
4907 ent->words[iwords++] = nlen;
4908 nlen += strlen(*pargs);
4909 ent->words[iwords++] = nlen;
4910 nlen++;
4911 }
4912 }
4913 } else {
4914 ent = prepnexthistent();
4915 ent->words = (short *)NULL;
4916 }
4917 ent->node.nam = zjoin(args, ' ', 0);
4918 ent->stim = ent->ftim = time(NULL);
4919 ent->node.flags = 0;
4920 addhistnode(histtab, ent->node.nam, ent);
4921 unqueue_signals();
4922 return 0;
4923 }
4924
4925 if (OPT_HASARG(ops, 'x') || OPT_HASARG(ops, 'X')) {
4926 char *eptr;
4927 int expand, startpos = 0;
4928 int all = OPT_HASARG(ops, 'X');
4929 char *xarg = all ? OPT_ARG(ops, 'X') : OPT_ARG(ops, 'x');
4930
4931 expand = (int)zstrtol(xarg, &eptr, 10);
4932 if (*eptr || expand <= 0) {
4933 zwarnnam(name, "positive integer expected after -%c: %s", 'x',
4934 xarg);
4935 return 1;
4936 }
4937 for (; *args; args++, len++) {
4938 startpos = zexpandtabs(*args, *len, expand, startpos, fout,
4939 all);
4940 if (args[1]) {
4941 if (OPT_ISSET(ops, 'l')) {
4942 fputc('\n', fout);
4943 startpos = 0;
4944 } else if (OPT_ISSET(ops,'N')) {
4945 fputc('\0', fout);
4946 } else {
4947 fputc(' ', fout);
4948 startpos++;
4949 }
4950 }
4951 }
4952 } else {
4953 for (; *args; args++, len++) {
4954 fwrite(*args, *len, 1, fout);
4955 if (args[1])
4956 fputc(OPT_ISSET(ops,'l') ? '\n' :
4957 OPT_ISSET(ops,'N') ? '\0' : ' ', fout);
4958 }
4959 }
4960 if (!(OPT_ISSET(ops,'n') || nnl ||
4961 (OPT_ISSET(ops, 'v') && !OPT_ISSET(ops, 'l'))))
4962 fputc(OPT_ISSET(ops,'N') ? '\0' : '\n', fout);
4963 if (IS_MSTREAM(fout) && (rcount = READ_MSTREAM(buf,fout)) == -1)
4964 ret = 1;
4965 if (!CLOSE_CLEANLY(fout) || ret) {
4966 zwarnnam(name, "write error: %e", errno);
4967 ret = 1;
4968 }
4969 if (buf) {
4970 /* assert: we must be doing -v at this point */
4971 queue_signals();
4972 if (ret)
4973 free(buf);
4974 else
4975 setsparam(OPT_ARG(ops, 'v'),
4976 metafy(buf, rcount, META_REALLOC));
4977 unqueue_signals();
4978 }
4979 return ret;
4980 }
4981
4982 /*
4983 * All the remaining code in this function is for printf-style
4984 * output (printf itself, or print -f). We still have to handle
4985 * special cases of printing to a ZLE buffer or the history, however.
4986 */
4987
4988 if (OPT_ISSET(ops,'v')) {
4989 struct value vbuf;
4990 char* s = OPT_ARG(ops,'v');
4991 Value v = getvalue(&vbuf, &s, 0);
4992 visarr = v && PM_TYPE(v->pm->node.flags) == PM_ARRAY;
4993 }
4994 /* printf style output */
4995 *spec = '%';
4996 argp = args;
4997 do {
4998 rcount = count;
4999 if (argp > args && visarr) { /* reusing format string */
5000 if (!splits)
5001 cursplit = splits = (size_t *)zhalloc(sizeof(size_t) *
5002 (arrlen(args) / (argp - args) + 1));
5003 *cursplit++ = count;
5004 }
5005 if (maxarg) {
5006 first += maxarg;
5007 argc -= maxarg;
5008 maxarg = 0;
5009 }
5010 for (c = fmt; c-fmt < flen; c++) {
5011 if (*c != '%') {
5012 putc(*c, fout);
5013 ++count;
5014 continue;
5015 }
5016
5017 start = c++;
5018 if (*c == '%') {
5019 putc('%', fout);
5020 ++count;
5021 continue;
5022 }
5023
5024 type = prec = -1;
5025 width = 0;
5026 curarg = NULL;
5027 d = spec + 1;
5028
5029 if (*c >= '1' && *c <= '9') {
5030 narg = strtoul(c, &endptr, 0);
5031 if (*endptr == '$') {
5032 c = endptr + 1;
5033 if (narg <= 0 || narg > argc) {
5034 zwarnnam(name, "%d: argument specifier out of range",
5035 narg);
5036 if (fout != stdout)
5037 fclose(fout);
5038 #ifdef HAVE_OPEN_MEMSTREAM
5039 if (buf)
5040 free(buf);
5041 #endif
5042 return 1;
5043 } else {
5044 if (narg > maxarg) maxarg = narg;
5045 curarg = *(first + narg - 1);
5046 curlen = len[first - args + narg - 1];
5047 }
5048 }
5049 }
5050
5051 /* copy only one of each flag as spec has finite size */
5052 memset(flags, 0, sizeof(flags));
5053 while (*c && (flag = strchr(flagch, *c))) {
5054 if (!flags[flag - flagch]) {
5055 flags[flag - flagch] = 1;
5056 *d++ = *c;
5057 }
5058 c++;
5059 }
5060
5061 if (idigit(*c)) {
5062 width = strtoul(c, &endptr, 0);
5063 c = endptr;
5064 } else if (*c == '*') {
5065 if (idigit(*++c)) {
5066 narg = strtoul(c, &endptr, 0);
5067 if (*endptr == '$') {
5068 c = endptr + 1;
5069 if (narg > argc || narg <= 0) {
5070 zwarnnam(name,
5071 "%d: argument specifier out of range",
5072 narg);
5073 if (fout != stdout)
5074 fclose(fout);
5075 #ifdef HAVE_OPEN_MEMSTREAM
5076 if (buf)
5077 free(buf);
5078 #endif
5079 return 1;
5080 } else {
5081 if (narg > maxarg) maxarg = narg;
5082 argp = first + narg - 1;
5083 }
5084 }
5085 }
5086 if (*argp) {
5087 width = (int)mathevali(*argp++);
5088 if (errflag) {
5089 errflag &= ~ERRFLAG_ERROR;
5090 ret = 1;
5091 }
5092 }
5093 }
5094 *d++ = '*';
5095
5096 if (*c == '.') {
5097 if (*++c == '*') {
5098 if (idigit(*++c)) {
5099 narg = strtoul(c, &endptr, 0);
5100 if (*endptr == '$') {
5101 c = endptr + 1;
5102 if (narg > argc || narg <= 0) {
5103 zwarnnam(name,
5104 "%d: argument specifier out of range",
5105 narg);
5106 if (fout != stdout)
5107 fclose(fout);
5108 #ifdef HAVE_OPEN_MEMSTREAM
5109 if (buf)
5110 free(buf);
5111 #endif
5112 return 1;
5113 } else {
5114 if (narg > maxarg) maxarg = narg;
5115 argp = first + narg - 1;
5116 }
5117 }
5118 }
5119
5120 if (*argp) {
5121 prec = (int)mathevali(*argp++);
5122 if (errflag) {
5123 errflag &= ~ERRFLAG_ERROR;
5124 ret = 1;
5125 }
5126 }
5127 } else if (idigit(*c)) {
5128 prec = strtoul(c, &endptr, 0);
5129 c = endptr;
5130 } else
5131 prec = 0;
5132 if (prec >= 0) *d++ = '.', *d++ = '*';
5133 }
5134
5135 /* ignore any size modifier */
5136 if (*c == 'l' || *c == 'L' || *c == 'h') c++;
5137
5138 if (!curarg && *argp) {
5139 curarg = *argp;
5140 curlen = len[argp++ - args];
5141 }
5142 d[1] = '\0';
5143 switch (*d = *c) {
5144 case 'c':
5145 if (curarg)
5146 intval = *curarg;
5147 else
5148 intval = 0;
5149 print_val(intval);
5150 break;
5151 case 's':
5152 case 'b':
5153 if (curarg) {
5154 char *b, *ptr;
5155 int lbytes, lchars, lleft;
5156 #ifdef MULTIBYTE_SUPPORT
5157 mbstate_t mbs;
5158 #endif
5159
5160 if (*c == 'b') {
5161 b = getkeystring(metafy(curarg, curlen, META_USEHEAP),
5162 &lbytes,
5163 OPT_ISSET(ops,'b') ? GETKEYS_BINDKEY :
5164 GETKEYS_PRINTF_ARG, &nnl);
5165 } else {
5166 b = curarg;
5167 lbytes = curlen;
5168 }
5169 /*
5170 * Handle width/precision here and use fwrite so that
5171 * nul characters can be output.
5172 *
5173 * First, examine width of string given that it
5174 * may contain multibyte characters. The output
5175 * widths are for characters, so we need to count
5176 * (in lchars). However, if we need to truncate
5177 * the string we need the width in bytes (in lbytes).
5178 */
5179 ptr = b;
5180 #ifdef MULTIBYTE_SUPPORT
5181 memset(&mbs, 0, sizeof(mbs));
5182 #endif
5183
5184 for (lchars = 0, lleft = lbytes; lleft > 0; lchars++) {
5185 int chars;
5186
5187 if (lchars == prec) {
5188 /* Truncate at this point. */
5189 lbytes = ptr - b;
5190 break;
5191 }
5192 #ifdef MULTIBYTE_SUPPORT
5193 if (isset(MULTIBYTE)) {
5194 chars = mbrlen(ptr, lleft, &mbs);
5195 if (chars < 0) {
5196 /*
5197 * Invalid/incomplete character at this
5198 * point. Assume all the rest are a
5199 * single byte. That's about the best we
5200 * can do.
5201 */
5202 lchars += lleft;
5203 lbytes = (ptr - b) + lleft;
5204 break;
5205 } else if (chars == 0) {
5206 /* NUL, handle as real character */
5207 chars = 1;
5208 }
5209 }
5210 else /* use the non-multibyte code below */
5211 #endif
5212 chars = 1; /* compiler can optimise this...*/
5213 lleft -= chars;
5214 ptr += chars;
5215 }
5216 if (width > 0 && flags[3]) width = -width;
5217 if (width > 0 && lchars < width)
5218 count += fprintf(fout, "%*c", width - lchars, ' ');
5219 count += fwrite(b, 1, lbytes, fout);
5220 if (width < 0 && lchars < -width)
5221 count += fprintf(fout, "%*c", -width - lchars, ' ');
5222 if (nnl) {
5223 /* If the %b arg had a \c escape, truncate the fmt. */
5224 flen = c - fmt + 1;
5225 fmttrunc = 1;
5226 }
5227 } else if (width)
5228 count += fprintf(fout, "%*c", width, ' ');
5229 break;
5230 case 'q':
5231 stringval = curarg ?
5232 quotestring(metafy(curarg, curlen, META_USEHEAP),
5233 QT_BACKSLASH_SHOWNULL) : &nullstr;
5234 *d = 's';
5235 print_val(unmetafy(stringval, &curlen));
5236 break;
5237 case 'd':
5238 case 'i':
5239 type=1;
5240 break;
5241 case 'e':
5242 case 'E':
5243 case 'f':
5244 case 'g':
5245 case 'G':
5246 type=2;
5247 break;
5248 case 'o':
5249 case 'u':
5250 case 'x':
5251 case 'X':
5252 type=3;
5253 break;
5254 case 'n':
5255 if (curarg) setiparam(curarg, count - rcount);
5256 break;
5257 default:
5258 if (*c) {
5259 save = c[1];
5260 c[1] = '\0';
5261 }
5262 zwarnnam(name, "%s: invalid directive", start);
5263 if (*c) c[1] = save;
5264 /* Why do we care about a clean close here? */
5265 if (!CLOSE_CLEANLY(fout))
5266 zwarnnam(name, "write error: %e", errno);
5267 #ifdef HAVE_OPEN_MEMSTREAM
5268 if (buf)
5269 free(buf);
5270 #endif
5271 return 1;
5272 }
5273
5274 if (type > 0) {
5275 if (curarg && (*curarg == '\'' || *curarg == '"' )) {
5276 convchar_t cc;
5277 #ifdef MULTIBYTE_SUPPORT
5278 if (isset(MULTIBYTE)) {
5279 mb_charinit();
5280 (void)mb_metacharlenconv(metafy(curarg+1, curlen-1,
5281 META_USEHEAP), &cc);
5282 }
5283 else
5284 cc = WEOF;
5285 if (cc == WEOF)
5286 cc = (curlen > 1) ? STOUC(curarg[1]) : 0;
5287 #else
5288 cc = (curlen > 1) ? STOUC(curarg[1]) : 0;
5289 #endif
5290 if (type == 2) {
5291 doubleval = cc;
5292 print_val(doubleval);
5293 } else {
5294 intval = cc;
5295 print_val(intval);
5296 }
5297 } else {
5298 switch (type) {
5299 case 1:
5300 #ifdef ZSH_64_BIT_TYPE
5301 *d++ = 'l';
5302 #endif
5303 *d++ = 'l', *d++ = *c, *d = '\0';
5304 zlongval = (curarg) ? mathevali(curarg) : 0;
5305 if (errflag) {
5306 zlongval = 0;
5307 errflag &= ~ERRFLAG_ERROR;
5308 ret = 1;
5309 }
5310 print_val(zlongval)
5311 break;
5312 case 2:
5313 if (curarg) {
5314 char *eptr;
5315 /*
5316 * First attempt to parse as a floating
5317 * point constant. If we go through
5318 * a math evaluation, we can lose
5319 * mostly unimportant information
5320 * that people in standards organizations
5321 * worry about.
5322 */
5323 doubleval = strtod(curarg, &eptr);
5324 /*
5325 * If it didn't parse as a constant,
5326 * parse it as an expression.
5327 */
5328 if (*eptr != '\0') {
5329 mnumval = matheval(curarg);
5330 doubleval = (mnumval.type & MN_FLOAT) ?
5331 mnumval.u.d : (double)mnumval.u.l;
5332 }
5333 } else doubleval = 0;
5334 if (errflag) {
5335 doubleval = 0;
5336 errflag &= ~ERRFLAG_ERROR;
5337 ret = 1;
5338 }
5339 /* force consistent form for Inf/NaN output */
5340 if (isnan(doubleval))
5341 count += fputs("nan", fout);
5342 else if (isinf(doubleval))
5343 count += fputs((doubleval < 0.0) ? "-inf" : "inf", fout);
5344 else
5345 print_val(doubleval)
5346 break;
5347 case 3:
5348 #ifdef ZSH_64_BIT_UTYPE
5349 *d++ = 'l';
5350 #endif
5351 *d++ = 'l', *d++ = *c, *d = '\0';
5352 if (!curarg)
5353 zulongval = (zulong)0;
5354 else if (!zstrtoul_underscore(curarg, &zulongval))
5355 zulongval = mathevali(curarg);
5356 if (errflag) {
5357 zulongval = 0;
5358 errflag &= ~ERRFLAG_ERROR;
5359 ret = 1;
5360 }
5361 print_val(zulongval)
5362 }
5363 }
5364 }
5365 if (maxarg && (argp - first > maxarg))
5366 maxarg = argp - first;
5367 }
5368
5369 if (maxarg) argp = first + maxarg;
5370 /* if there are remaining args, reuse format string */
5371 } while (*argp && argp != first && !fmttrunc && !OPT_ISSET(ops,'r'));
5372
5373 if (IS_MSTREAM(fout)) {
5374 queue_signals();
5375 if ((rcount = READ_MSTREAM(buf,fout)) == -1) {
5376 zwarnnam(name, "i/o error: %e", errno);
5377 if (buf)
5378 free(buf);
5379 } else {
5380 if (visarr && splits) {
5381 char **arrayval = zshcalloc((cursplit - splits + 2) * sizeof(char *));
5382 for (;cursplit >= splits; cursplit--) {
5383 int start = cursplit == splits ? 0 : cursplit[-1];
5384 arrayval[cursplit - splits] =
5385 metafy(buf + start, count - start, META_DUP);
5386 count = start;
5387 }
5388 setaparam(OPT_ARG(ops, 'v'), arrayval);
5389 free(buf);
5390 } else {
5391 stringval = metafy(buf, rcount, META_REALLOC);
5392 if (OPT_ISSET(ops,'z')) {
5393 zpushnode(bufstack, stringval);
5394 } else if (OPT_ISSET(ops,'v')) {
5395 setsparam(OPT_ARG(ops, 'v'), stringval);
5396 } else {
5397 ent = prepnexthistent();
5398 ent->node.nam = stringval;
5399 ent->stim = ent->ftim = time(NULL);
5400 ent->node.flags = 0;
5401 ent->words = (short *)NULL;
5402 addhistnode(histtab, ent->node.nam, ent);
5403 }
5404 }
5405 }
5406 unqueue_signals();
5407 }
5408
5409 if (!CLOSE_CLEANLY(fout))
5410 {
5411 zwarnnam(name, "write error: %e", errno);
5412 ret = 1;
5413 }
5414 return ret;
5415 }
5416
5417 /* shift builtin */
5418
5419 /**/
5420 int
bin_shift(char * name,char ** argv,Options ops,UNUSED (int func))5421 bin_shift(char *name, char **argv, Options ops, UNUSED(int func))
5422 {
5423 int num = 1, l, ret = 0;
5424 char **s;
5425
5426 /* optional argument can be either numeric or an array */
5427 queue_signals();
5428 if (*argv && !getaparam(*argv)) {
5429 num = mathevali(*argv++);
5430 if (errflag) {
5431 unqueue_signals();
5432 return 1;
5433 }
5434 }
5435
5436 if (num < 0) {
5437 unqueue_signals();
5438 zwarnnam(name, "argument to shift must be non-negative");
5439 return 1;
5440 }
5441
5442 if (*argv) {
5443 for (; *argv; argv++)
5444 if ((s = getaparam(*argv))) {
5445 if (arrlen_lt(s, num)) {
5446 zwarnnam(name, "shift count must be <= $#");
5447 ret++;
5448 continue;
5449 }
5450 if (OPT_ISSET(ops,'p')) {
5451 char **s2, **src, **dst;
5452 int count;
5453 l = arrlen(s);
5454 src = s;
5455 dst = s2 = (char **)zalloc((l - num + 1) * sizeof(char *));
5456 for (count = l - num; count; count--)
5457 *dst++ = ztrdup(*src++);
5458 *dst = NULL;
5459 s = s2;
5460 } else {
5461 s = zarrdup(s + num);
5462 }
5463 setaparam(*argv, s);
5464 }
5465 } else {
5466 if (num > (l = arrlen(pparams))) {
5467 zwarnnam(name, "shift count must be <= $#");
5468 ret = 1;
5469 } else {
5470 s = zalloc((l - num + 1) * sizeof(char *));
5471 if (OPT_ISSET(ops,'p')) {
5472 memcpy(s, pparams, (l - num) * sizeof(char *));
5473 s[l-num] = NULL;
5474 while (num--)
5475 zsfree(pparams[l-1-num]);
5476 } else {
5477 memcpy(s, pparams + num, (l - num + 1) * sizeof(char *));
5478 while (num--)
5479 zsfree(pparams[num]);
5480 }
5481 zfree(pparams, (l + 1) * sizeof(char *));
5482 pparams = s;
5483 }
5484 }
5485 unqueue_signals();
5486 return ret;
5487 }
5488
5489 /*
5490 * Position of getopts option within OPTIND argument with multiple options.
5491 */
5492
5493 /**/
5494 int optcind;
5495
5496 /* getopts: automagical option handling for shell scripts */
5497
5498 /**/
5499 int
bin_getopts(UNUSED (char * name),char ** argv,UNUSED (Options ops),UNUSED (int func))5500 bin_getopts(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int func))
5501 {
5502 int lenstr, lenoptstr, quiet, lenoptbuf;
5503 char *optstr = unmetafy(*argv++, &lenoptstr), *var = *argv++;
5504 char **args = (*argv) ? argv : pparams;
5505 char *str, optbuf[2] = " ", *p, opch;
5506
5507 /* zoptind keeps count of the current argument number. The *
5508 * user can set it to zero to start a new option parse. */
5509 if (zoptind < 1) {
5510 /* first call */
5511 zoptind = 1;
5512 optcind = 0;
5513 }
5514 if (arrlen_lt(args, zoptind))
5515 /* no more options */
5516 return 1;
5517
5518 /* leading ':' in optstr means don't print an error message */
5519 quiet = *optstr == ':';
5520 optstr += quiet;
5521 lenoptstr -= quiet;
5522
5523 /* find place in relevant argument */
5524 str = unmetafy(dupstring(args[zoptind - 1]), &lenstr);
5525 if (!lenstr) /* Definitely not an option. */
5526 return 1;
5527 if(optcind >= lenstr) {
5528 optcind = 0;
5529 if(!args[zoptind++])
5530 return 1;
5531 str = unmetafy(dupstring(args[zoptind - 1]), &lenstr);
5532 }
5533 if(!optcind) {
5534 if(lenstr < 2 || (*str != '-' && *str != '+'))
5535 return 1;
5536 if(lenstr == 2 && str[0] == '-' && str[1] == '-') {
5537 zoptind++;
5538 return 1;
5539 }
5540 optcind++;
5541 }
5542 opch = str[optcind++];
5543 if(str[0] == '+') {
5544 optbuf[0] = '+';
5545 lenoptbuf = 2;
5546 } else
5547 lenoptbuf = 1;
5548 optbuf[lenoptbuf - 1] = opch;
5549
5550 /* check for legality */
5551 if(opch == ':' || !(p = memchr(optstr, opch, lenoptstr))) {
5552 p = "?";
5553 zsfree(zoptarg);
5554 setsparam(var, ztrdup(p));
5555 if(quiet) {
5556 zoptarg = metafy(optbuf, lenoptbuf, META_DUP);
5557 } else {
5558 zwarn("bad option: %c%c",
5559 "?-+"[lenoptbuf], opch);
5560 zoptarg=ztrdup("");
5561 }
5562 return 0;
5563 }
5564
5565 /* check for required argument */
5566 if(p[1] == ':') {
5567 if(optcind == lenstr) {
5568 if(!args[zoptind]) {
5569 zsfree(zoptarg);
5570 if(quiet) {
5571 setsparam(var, ztrdup(":"));
5572 zoptarg = metafy(optbuf, lenoptbuf, META_DUP);
5573 } else {
5574 setsparam(var, ztrdup("?"));
5575 zoptarg = ztrdup("");
5576 zwarn("argument expected after %c%c option",
5577 "?-+"[lenoptbuf], opch);
5578 }
5579 return 0;
5580 }
5581 p = ztrdup(args[zoptind++]);
5582 } else
5583 p = metafy(str+optcind, lenstr-optcind, META_DUP);
5584 /*
5585 * Careful: I've just changed the following two lines from
5586 * optcind = ztrlen(args[zoptind - 1]);
5587 * and it's a rigorous theorem that every change in getopts breaks
5588 * something. See zsh-workers/9095 for the bug fixed here.
5589 * PWS 2000/05/02
5590 */
5591 optcind = 0;
5592 zoptind++;
5593 zsfree(zoptarg);
5594 zoptarg = p;
5595 } else {
5596 zsfree(zoptarg);
5597 zoptarg = ztrdup("");
5598 }
5599
5600 setsparam(var, metafy(optbuf, lenoptbuf, META_DUP));
5601 return 0;
5602 }
5603
5604 /* Boolean flag that we should exit the shell as soon as all functions return.
5605 *
5606 * Set by the 'exit' builtin.
5607 */
5608
5609 /**/
5610 mod_export int
5611 exit_pending;
5612
5613 /* Shell level at which we exit if exit_pending */
5614 /**/
5615 mod_export int
5616 exit_level;
5617
5618 /* break, bye, continue, exit, logout, return -- most of these take *
5619 * one numeric argument, and the other (logout) is related to return. *
5620 * (return is treated as a logout when in a login shell.) */
5621
5622 /**/
5623 int
bin_break(char * name,char ** argv,UNUSED (Options ops),int func)5624 bin_break(char *name, char **argv, UNUSED(Options ops), int func)
5625 {
5626 int num = lastval, nump = 0, implicit;
5627
5628 /* handle one optional numeric argument */
5629 implicit = !*argv;
5630 if (*argv) {
5631 num = mathevali(*argv++);
5632 nump = 1;
5633 }
5634
5635 if (nump > 0 && (func == BIN_CONTINUE || func == BIN_BREAK) && num <= 0) {
5636 zerrnam(name, "argument is not positive: %d", num);
5637 return 1;
5638 }
5639
5640 switch (func) {
5641 case BIN_CONTINUE:
5642 if (!loops) { /* continue is only permitted in loops */
5643 zerrnam(name, "not in while, until, select, or repeat loop");
5644 return 1;
5645 }
5646 contflag = 1; /* FALLTHROUGH */
5647 case BIN_BREAK:
5648 if (!loops) { /* break is only permitted in loops */
5649 zerrnam(name, "not in while, until, select, or repeat loop");
5650 return 1;
5651 }
5652 breaks = nump ? minimum(num,loops) : 1;
5653 break;
5654 case BIN_RETURN:
5655 if ((isset(INTERACTIVE) && isset(SHINSTDIN))
5656 || locallevel || sourcelevel) {
5657 retflag = 1;
5658 breaks = loops;
5659 lastval = num;
5660 if (trap_state == TRAP_STATE_PRIMED && trap_return == -2
5661 /*
5662 * With POSIX, "return" on its own in a trap doesn't
5663 * update $? --- we keep the status from before the
5664 * trap.
5665 */
5666 && !(isset(POSIXTRAPS) && implicit)) {
5667 trap_state = TRAP_STATE_FORCE_RETURN;
5668 trap_return = lastval;
5669 }
5670 return lastval;
5671 }
5672 zexit(num, ZEXIT_NORMAL); /* else treat return as logout/exit */
5673 break;
5674 case BIN_LOGOUT:
5675 if (unset(LOGINSHELL)) {
5676 zerrnam(name, "not login shell");
5677 return 1;
5678 }
5679 /*FALLTHROUGH*/
5680 case BIN_EXIT:
5681 if (locallevel > forklevel && shell_exiting != -1) {
5682 /*
5683 * We don't exit directly from functions to allow tidying
5684 * up, in particular EXIT traps. We still need to perform
5685 * the usual interactive tests to see if we can exit at
5686 * all, however.
5687 *
5688 * If we are forked, we exit the shell at the function depth
5689 * at which we became a subshell, hence the comparison.
5690 *
5691 * If we are already exiting... give this all up as
5692 * a bad job.
5693 */
5694 if (stopmsg || (zexit(0, ZEXIT_DEFERRED), !stopmsg)) {
5695 retflag = 1;
5696 breaks = loops;
5697 exit_pending = 1;
5698 exit_level = locallevel;
5699 exit_val = num;
5700 }
5701 } else
5702 zexit(num, ZEXIT_NORMAL);
5703 break;
5704 }
5705 return 0;
5706 }
5707
5708 /* we have printed a 'you have stopped (running) jobs.' message */
5709
5710 /**/
5711 mod_export int stopmsg;
5712
5713 /* check to see if user has jobs running/stopped */
5714
5715 /**/
5716 static void
checkjobs(void)5717 checkjobs(void)
5718 {
5719 int i;
5720
5721 for (i = 1; i <= maxjob; i++)
5722 if (i != thisjob && (jobtab[i].stat & STAT_LOCKED) &&
5723 !(jobtab[i].stat & STAT_NOPRINT) &&
5724 (isset(CHECKRUNNINGJOBS) || jobtab[i].stat & STAT_STOPPED))
5725 break;
5726 if (i <= maxjob) {
5727 if (jobtab[i].stat & STAT_STOPPED) {
5728
5729 #ifdef USE_SUSPENDED
5730 zerr("you have suspended jobs.");
5731 #else
5732 zerr("you have stopped jobs.");
5733 #endif
5734
5735 } else
5736 zerr("you have running jobs.");
5737 stopmsg = 1;
5738 }
5739 }
5740
5741 /*
5742 * -1 if the shell is already committed to exit.
5743 * positive if zexit() was already called.
5744 */
5745
5746 /**/
5747 int shell_exiting;
5748
5749 /*
5750 * Exit status if explicitly set by an exit command.
5751 * This is complicated by the fact the exit command may be within
5752 * a function whose state we need to unwind (exit_pending set
5753 * and the exit will happen up the stack), or we may need to execute
5754 * additional code such as a trap after we are committed to exiting
5755 * (shell_exiting and the exit will happen down the stack).
5756 *
5757 * It's lucky this is all so obvious there is no possibility of any
5758 * bugs. (C.f. the entire rest of the shell.)
5759 */
5760 /**/
5761 int exit_val;
5762
5763 /*
5764 * Actually exit the shell, working out the status locally.
5765 * This is exit_val if "exit" has explicitly been called in the shell,
5766 * else lastval.
5767 */
5768
5769 /**/
5770 void
realexit(void)5771 realexit(void)
5772 {
5773 exit((shell_exiting || exit_pending) ? exit_val : lastval);
5774 }
5775
5776 /* As realexit(), but call _exit instead */
5777
5778 /**/
5779 void
_realexit(void)5780 _realexit(void)
5781 {
5782 _exit((shell_exiting || exit_pending) ? exit_val : lastval);
5783 }
5784
5785 /* exit the shell. val is the return value of the shell. *
5786 * from_where is
5787 * ZEXIT_SIGNAL if zexit is called because of a signal
5788 * ZEXIT_DEFERRED if we can't actually exit yet (e.g., functions need
5789 * terminating) but should perform the usual interactive
5790 * tests.
5791 */
5792
5793 /**/
5794 mod_export void
zexit(int val,enum zexit_t from_where)5795 zexit(int val, enum zexit_t from_where)
5796 {
5797 /*
5798 * Don't do anything recursively: see below.
5799 * Do, however, update exit status --- there's no nesting,
5800 * a later value always overrides an earlier.
5801 */
5802 exit_val = val;
5803 if (shell_exiting == -1)
5804 return;
5805
5806 if (isset(MONITOR) && !stopmsg && from_where != ZEXIT_SIGNAL) {
5807 scanjobs(); /* check if jobs need printing */
5808 if (isset(CHECKJOBS))
5809 checkjobs(); /* check if any jobs are running/stopped */
5810 if (stopmsg) {
5811 stopmsg = 2;
5812 return;
5813 }
5814 }
5815 /* Positive shell_exiting means we have been here before */
5816 if (from_where == ZEXIT_DEFERRED ||
5817 (shell_exiting++ && from_where != ZEXIT_NORMAL))
5818 return;
5819
5820 /*
5821 * We're now committed to exiting. Set shell_exiting to -1 to
5822 * indicate we shouldn't do any recursive processing.
5823 */
5824 shell_exiting = -1;
5825 /*
5826 * We want to do all remaining processing regardless of preceding
5827 * errors, even user interrupts.
5828 */
5829 errflag = 0;
5830
5831 if (isset(MONITOR)) {
5832 /* send SIGHUP to any jobs left running */
5833 killrunjobs(from_where == ZEXIT_SIGNAL);
5834 }
5835 if (isset(RCS) && interact) {
5836 if (!nohistsave) {
5837 int writeflags = HFILE_USE_OPTIONS;
5838 if (from_where == ZEXIT_SIGNAL)
5839 writeflags |= HFILE_NO_REWRITE;
5840 saveandpophiststack(1, writeflags);
5841 savehistfile(NULL, 1, writeflags);
5842 }
5843 if (islogin && !subsh) {
5844 sourcehome(".zlogout");
5845 #ifdef GLOBAL_ZLOGOUT
5846 if (isset(RCS) && isset(GLOBALRCS))
5847 source(GLOBAL_ZLOGOUT);
5848 #endif
5849 }
5850 }
5851 lastval = exit_val;
5852 /*
5853 * Now we are committed to exiting any previous state
5854 * is irrelevant. Ensure trap can run.
5855 */
5856 errflag = intrap = 0;
5857 if (sigtrapped[SIGEXIT])
5858 dotrap(SIGEXIT);
5859 callhookfunc("zshexit", NULL, 1, NULL);
5860 runhookdef(EXITHOOK, NULL);
5861 if (opts[MONITOR] && interact && (SHTTY != -1)) {
5862 release_pgrp();
5863 }
5864 if (mypid != getpid())
5865 _exit(exit_val);
5866 else
5867 exit(exit_val);
5868 }
5869
5870 /* . (dot), source */
5871
5872 /**/
5873 int
bin_dot(char * name,char ** argv,UNUSED (Options ops),UNUSED (int func))5874 bin_dot(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
5875 {
5876 char **old, *old0 = NULL;
5877 int diddot = 0, dotdot = 0;
5878 char *s, **t, *enam, *arg0, *buf;
5879 struct stat st;
5880 enum source_return ret;
5881
5882 if (!*argv)
5883 return 0;
5884 old = pparams;
5885 /* get arguments for the script */
5886 if (argv[1])
5887 pparams = zarrdup(argv + 1);
5888
5889 enam = arg0 = ztrdup(*argv);
5890 if (isset(FUNCTIONARGZERO)) {
5891 old0 = argzero;
5892 argzero = ztrdup(arg0);
5893 }
5894 s = unmeta(enam);
5895 errno = ENOENT;
5896 ret = SOURCE_NOT_FOUND;
5897 /* for source only, check in current directory first */
5898 if (*name != '.' && access(s, F_OK) == 0
5899 && stat(s, &st) >= 0 && !S_ISDIR(st.st_mode)) {
5900 diddot = 1;
5901 ret = source(enam);
5902 }
5903 if (ret == SOURCE_NOT_FOUND) {
5904 /* use a path with / in it */
5905 for (s = arg0; *s; s++)
5906 if (*s == '/') {
5907 if (*arg0 == '.') {
5908 if (arg0 + 1 == s)
5909 ++diddot;
5910 else if (arg0[1] == '.' && arg0 + 2 == s)
5911 ++dotdot;
5912 }
5913 ret = source(arg0);
5914 break;
5915 }
5916 if (!*s || (ret == SOURCE_NOT_FOUND &&
5917 isset(PATHDIRS) && diddot < 2 && dotdot == 0)) {
5918 pushheap();
5919 /* search path for script */
5920 for (t = path; *t; t++) {
5921 if (!(*t)[0] || ((*t)[0] == '.' && !(*t)[1])) {
5922 if (diddot)
5923 continue;
5924 diddot = 1;
5925 buf = dupstring(arg0);
5926 } else
5927 buf = zhtricat(*t, "/", arg0);
5928
5929 s = unmeta(buf);
5930 if (access(s, F_OK) == 0 && stat(s, &st) >= 0
5931 && !S_ISDIR(st.st_mode)) {
5932 ret = source(enam = buf);
5933 break;
5934 }
5935 }
5936 popheap();
5937 }
5938 }
5939 /* clean up and return */
5940 if (argv[1]) {
5941 freearray(pparams);
5942 pparams = old;
5943 }
5944 if (ret == SOURCE_NOT_FOUND) {
5945 if (isset(POSIXBUILTINS)) {
5946 /* hard error in POSIX (we'll exit later) */
5947 zerrnam(name, "%e: %s", errno, enam);
5948 } else {
5949 zwarnnam(name, "%e: %s", errno, enam);
5950 }
5951 }
5952 zsfree(arg0);
5953 if (old0) {
5954 zsfree(argzero);
5955 argzero = old0;
5956 }
5957 return ret == SOURCE_OK ? lastval : 128 - ret;
5958 }
5959
5960 /*
5961 * common for bin_emulate and bin_eval
5962 */
5963
5964 static int
eval(char ** argv)5965 eval(char **argv)
5966 {
5967 Eprog prog;
5968 char *oscriptname = scriptname;
5969 int oineval = ineval, fpushed;
5970 struct funcstack fstack;
5971
5972 /*
5973 * If EVALLINENO is not set, we use the line number of the
5974 * environment and must flag this up to exec.c. Otherwise,
5975 * we use a special script name to indicate the special line number.
5976 */
5977 ineval = !isset(EVALLINENO);
5978 if (!ineval) {
5979 scriptname = "(eval)";
5980 fstack.prev = funcstack;
5981 fstack.name = scriptname;
5982 fstack.caller = funcstack ? funcstack->name : dupstring(argzero);
5983 fstack.lineno = lineno;
5984 fstack.tp = FS_EVAL;
5985
5986 /*
5987 * To get file line numbers, we need to know if parent is
5988 * the original script/shell or a sourced file, in which
5989 * case we use the line number raw, or a function or eval,
5990 * in which case we need to deduce where that came from.
5991 *
5992 * This replicates the logic for working out the information
5993 * for $funcfiletrace---eval is similar to an inlined function
5994 * call from a tracing perspective.
5995 */
5996 if (!funcstack || funcstack->tp == FS_SOURCE) {
5997 fstack.flineno = fstack.lineno;
5998 fstack.filename = fstack.caller;
5999 } else {
6000 fstack.flineno = funcstack->flineno + lineno;
6001 /*
6002 * Line numbers in eval start from 1, not zero,
6003 * so offset by one to get line in file.
6004 */
6005 if (funcstack->tp == FS_EVAL)
6006 fstack.flineno--;
6007 fstack.filename = funcstack->filename;
6008 if (!fstack.filename)
6009 fstack.filename = "";
6010 }
6011 funcstack = &fstack;
6012
6013 fpushed = 1;
6014 } else
6015 fpushed = 0;
6016
6017 prog = parse_string(zjoin(argv, ' ', 1), 1);
6018 if (prog) {
6019 if (wc_code(*prog->prog) != WC_LIST) {
6020 /* No code to execute */
6021 lastval = 0;
6022 } else {
6023 execode(prog, 1, 0, "eval");
6024
6025 if (errflag && !lastval)
6026 lastval = errflag;
6027 }
6028 } else {
6029 lastval = 1;
6030 }
6031
6032 if (fpushed)
6033 funcstack = funcstack->prev;
6034
6035 errflag &= ~ERRFLAG_ERROR;
6036 scriptname = oscriptname;
6037 ineval = oineval;
6038
6039 return lastval;
6040 }
6041
6042 /* emulate: set emulation mode and optionally evaluate shell code */
6043
6044 /**/
6045 int
bin_emulate(char * nam,char ** argv,Options ops,UNUSED (int func))6046 bin_emulate(char *nam, char **argv, Options ops, UNUSED(int func))
6047 {
6048 int opt_L = OPT_ISSET(ops, 'L');
6049 int opt_R = OPT_ISSET(ops, 'R');
6050 int opt_l = OPT_ISSET(ops, 'l');
6051 int saveemulation, savehackchar;
6052 int ret = 1, new_emulation;
6053 unsigned int savepatterns;
6054 char saveopts[OPT_SIZE], new_opts[OPT_SIZE];
6055 char *cmd = 0;
6056 const char *shname = *argv;
6057 LinkList optlist;
6058 LinkNode optnode;
6059 Emulation_options save_sticky;
6060 OptIndex *on_ptr, *off_ptr;
6061
6062 /* without arguments just print current emulation */
6063 if (!shname) {
6064 if (opt_L || opt_R) {
6065 zwarnnam(nam, "not enough arguments");
6066 return 1;
6067 }
6068
6069 switch(SHELL_EMULATION()) {
6070 case EMULATE_CSH:
6071 shname = "csh";
6072 break;
6073
6074 case EMULATE_KSH:
6075 shname = "ksh";
6076 break;
6077
6078 case EMULATE_SH:
6079 shname = "sh";
6080 break;
6081
6082 default:
6083 shname = "zsh";
6084 break;
6085 }
6086
6087 printf("%s\n", shname);
6088 return 0;
6089 }
6090
6091 /* with single argument set current emulation */
6092 if (!argv[1]) {
6093 char *cmdopts;
6094 if (opt_l) {
6095 cmdopts = (char *)zhalloc(OPT_SIZE);
6096 memcpy(cmdopts, opts, OPT_SIZE);
6097 } else
6098 cmdopts = opts;
6099 emulate(shname, opt_R, &emulation, cmdopts);
6100 if (opt_L)
6101 cmdopts[LOCALOPTIONS] = cmdopts[LOCALTRAPS] =
6102 cmdopts[LOCALPATTERNS] = 1;
6103 if (opt_l) {
6104 list_emulate_options(cmdopts, opt_R);
6105 return 0;
6106 }
6107 clearpatterndisables();
6108 return 0;
6109 }
6110
6111 if (opt_l) {
6112 zwarnnam(nam, "too many arguments for -l");
6113 return 1;
6114 }
6115
6116 argv++;
6117 memcpy(saveopts, opts, sizeof(opts));
6118 memcpy(new_opts, opts, sizeof(opts));
6119 savehackchar = keyboardhackchar;
6120 emulate(shname, opt_R, &new_emulation, new_opts);
6121 optlist = newlinklist();
6122 if (parseopts(nam, &argv, new_opts, &cmd, optlist, 0)) {
6123 ret = 1;
6124 goto restore;
6125 }
6126
6127 /* parseopts() has consumed anything that looks like an option */
6128 if (*argv) {
6129 zwarnnam(nam, "unknown argument %s", *argv);
6130 goto restore;
6131 }
6132
6133 savepatterns = savepatterndisables();
6134 /*
6135 * All emulations start with an empty set of pattern disables,
6136 * hence no special "sticky" behaviour is required.
6137 */
6138 clearpatterndisables();
6139
6140 saveemulation = emulation;
6141 emulation = new_emulation;
6142 memcpy(opts, new_opts, sizeof(opts));
6143 /* If "-c command" is given, evaluate command using specified
6144 * emulation mode.
6145 */
6146 if (cmd) {
6147 if (opt_L) {
6148 zwarnnam(nam, "option -L incompatible with -c");
6149 goto restore2;
6150 }
6151 *--argv = cmd; /* on stack, never free()d, see execbuiltin() */
6152 } else {
6153 if (opt_L)
6154 opts[LOCALOPTIONS] = opts[LOCALTRAPS] = opts[LOCALPATTERNS] = 1;
6155 return 0;
6156 }
6157
6158 save_sticky = sticky;
6159 sticky = hcalloc(sizeof(*sticky));
6160 sticky->emulation = emulation;
6161 for (optnode = firstnode(optlist); optnode; incnode(optnode)) {
6162 /* Data is index into new_opts */
6163 char *optptr = (char *)getdata(optnode);
6164 if (*optptr)
6165 sticky->n_on_opts++;
6166 else
6167 sticky->n_off_opts++;
6168 }
6169 if (sticky->n_on_opts)
6170 on_ptr = sticky->on_opts =
6171 zhalloc(sticky->n_on_opts * sizeof(*sticky->on_opts));
6172 else
6173 on_ptr = NULL;
6174 if (sticky->n_off_opts)
6175 off_ptr = sticky->off_opts = zhalloc(sticky->n_off_opts *
6176 sizeof(*sticky->off_opts));
6177 else
6178 off_ptr = NULL;
6179 for (optnode = firstnode(optlist); optnode; incnode(optnode)) {
6180 /* Data is index into new_opts */
6181 char *optptr = (char *)getdata(optnode);
6182 int optno = optptr - new_opts;
6183 if (*optptr)
6184 *on_ptr++ = optno;
6185 else
6186 *off_ptr++ = optno;
6187 }
6188 ret = eval(argv);
6189 sticky = save_sticky;
6190 restore2:
6191 emulation = saveemulation;
6192 memcpy(opts, saveopts, sizeof(opts));
6193 restorepatterndisables(savepatterns);
6194 restore:
6195 keyboardhackchar = savehackchar;
6196 inittyptab(); /* restore banghist */
6197 return ret;
6198 }
6199
6200 /* eval: simple evaluation */
6201
6202 /**/
6203 mod_export int ineval;
6204
6205 /**/
6206 int
bin_eval(UNUSED (char * nam),char ** argv,UNUSED (Options ops),UNUSED (int func))6207 bin_eval(UNUSED(char *nam), char **argv, UNUSED(Options ops), UNUSED(int func))
6208 {
6209 return eval(argv);
6210 }
6211
6212 static char *zbuf;
6213 static int readfd;
6214
6215 /* Read a character from readfd, or from the buffer zbuf. Return EOF on end of
6216 file/buffer. */
6217
6218 /* read: get a line of input, or (for compctl functions) return some *
6219 * useful data about the state of the editing line. The -E and -e *
6220 * options mean that the result should be sent to stdout. -e means, *
6221 * in addition, that the result should not actually be assigned to *
6222 * the specified parameters. */
6223
6224 /**/
6225 int
bin_read(char * name,char ** args,Options ops,UNUSED (int func))6226 bin_read(char *name, char **args, Options ops, UNUSED(int func))
6227 {
6228 char *reply, *readpmpt;
6229 int bsiz, c = 0, gotnl = 0, al = 0, first, nchars = 1, bslash, keys = 0;
6230 int haso = 0; /* true if /dev/tty has been opened specially */
6231 int isem = !strcmp(term, "emacs"), izle = zleactive;
6232 char *buf, *bptr, *firstarg, *zbuforig;
6233 LinkList readll = newlinklist();
6234 FILE *oshout = NULL;
6235 int readchar = -1, val, resettty = 0;
6236 struct ttyinfo saveti;
6237 char d;
6238 long izle_timeout = 0;
6239 #ifdef MULTIBYTE_SUPPORT
6240 wchar_t delim = L'\n', wc;
6241 mbstate_t mbs;
6242 char *laststart;
6243 size_t ret;
6244 #else
6245 char delim = '\n';
6246 #endif
6247
6248 if (OPT_HASARG(ops,c='k')) {
6249 char *eptr, *optarg = OPT_ARG(ops,c);
6250 nchars = (int)zstrtol(optarg, &eptr, 10);
6251 if (*eptr) {
6252 zwarnnam(name, "number expected after -%c: %s", c, optarg);
6253 return 1;
6254 }
6255 }
6256 /* This `*args++ : *args' looks a bit weird, but it works around a bug
6257 * in gcc-2.8.1 under DU 4.0. */
6258 firstarg = (*args && **args == '?' ? *args++ : *args);
6259 reply = *args ? *args++ : OPT_ISSET(ops,'A') ? "reply" : "REPLY";
6260
6261 if (OPT_ISSET(ops,'A') && *args) {
6262 zwarnnam(name, "only one array argument allowed");
6263 return 1;
6264 }
6265
6266 /* handle compctl case */
6267 if(OPT_ISSET(ops,'l') || OPT_ISSET(ops,'c'))
6268 return compctlreadptr(name, args, ops, reply);
6269
6270 if ((OPT_ISSET(ops,'k') || OPT_ISSET(ops,'q')) &&
6271 !OPT_ISSET(ops,'u') && !OPT_ISSET(ops,'p')) {
6272 if (!zleactive) {
6273 if (SHTTY == -1) {
6274 /* need to open /dev/tty specially */
6275 if ((SHTTY = open("/dev/tty", O_RDWR|O_NOCTTY)) != -1) {
6276 haso = 1;
6277 oshout = shout;
6278 init_shout();
6279 }
6280 } else if (!shout) {
6281 /* We need an output FILE* on the tty */
6282 init_shout();
6283 }
6284 /* We should have a SHTTY opened by now. */
6285 if (SHTTY == -1) {
6286 /* Unfortunately, we didn't. */
6287 fprintf(stderr, "not interactive and can't open terminal\n");
6288 fflush(stderr);
6289 return 1;
6290 }
6291 if (unset(INTERACTIVE))
6292 gettyinfo(&shttyinfo);
6293 /* attach to the tty */
6294 attachtty(mypgrp);
6295 if (!isem)
6296 setcbreak();
6297 readfd = SHTTY;
6298 }
6299 keys = 1;
6300 } else if (OPT_HASARG(ops,'u') && !OPT_ISSET(ops,'p')) {
6301 /* -u means take input from the specified file descriptor. */
6302 char *eptr, *argptr = OPT_ARG(ops,'u');
6303 /* The old code handled -up, but that was never documented. Still...*/
6304 if (!strcmp(argptr, "p")) {
6305 readfd = coprocin;
6306 if (readfd < 0) {
6307 zwarnnam(name, "-p: no coprocess");
6308 return 1;
6309 }
6310 } else {
6311 readfd = (int)zstrtol(argptr, &eptr, 10);
6312 if (*eptr) {
6313 zwarnnam(name, "number expected after -%c: %s", 'u', argptr);
6314 return 1;
6315 }
6316 }
6317 #if 0
6318 /* This code is left as a warning to future generations --- pws. */
6319 for (readfd = 9; readfd && !OPT_ISSET(ops,readfd + '0'); --readfd);
6320 #endif
6321 izle = 0;
6322 } else if (OPT_ISSET(ops,'p')) {
6323 readfd = coprocin;
6324 if (readfd < 0) {
6325 zwarnnam(name, "-p: no coprocess");
6326 return 1;
6327 }
6328 izle = 0;
6329 } else
6330 readfd = izle = 0;
6331
6332 if (OPT_ISSET(ops,'s') && SHTTY != -1) {
6333 struct ttyinfo ti;
6334 gettyinfo(&ti);
6335 saveti = ti;
6336 resettty = 1;
6337 #ifdef HAS_TIO
6338 ti.tio.c_lflag &= ~ECHO;
6339 #else
6340 ti.sgttyb.sg_flags &= ~ECHO;
6341 #endif
6342 settyinfo(&ti);
6343 }
6344
6345 /* handle prompt */
6346 if (firstarg) {
6347 for (readpmpt = firstarg;
6348 *readpmpt && *readpmpt != '?'; readpmpt++);
6349 if (*readpmpt++) {
6350 if (keys || isatty(0)) {
6351 zputs(readpmpt, (shout ? shout : stderr));
6352 fflush(shout ? shout : stderr);
6353 }
6354 readpmpt[-1] = '\0';
6355 }
6356 }
6357
6358 if (OPT_ISSET(ops,'d')) {
6359 char *delimstr = OPT_ARG(ops,'d');
6360 #ifdef MULTIBYTE_SUPPORT
6361 wint_t wi;
6362
6363 if (isset(MULTIBYTE)) {
6364 mb_charinit();
6365 (void)mb_metacharlenconv(delimstr, &wi);
6366 }
6367 else
6368 wi = WEOF;
6369 if (wi != WEOF)
6370 delim = (wchar_t)wi;
6371 else
6372 delim = (wchar_t)((delimstr[0] == Meta) ?
6373 delimstr[1] ^ 32 : delimstr[0]);
6374 #else
6375 delim = (delimstr[0] == Meta) ? delimstr[1] ^ 32 : delimstr[0];
6376 #endif
6377 if (SHTTY != -1) {
6378 struct ttyinfo ti;
6379 gettyinfo(&ti);
6380 if (! resettty) {
6381 saveti = ti;
6382 resettty = 1;
6383 }
6384 #ifdef HAS_TIO
6385 ti.tio.c_lflag &= ~ICANON;
6386 ti.tio.c_cc[VMIN] = 1;
6387 ti.tio.c_cc[VTIME] = 0;
6388 #else
6389 ti.sgttyb.sg_flags |= CBREAK;
6390 #endif
6391 settyinfo(&ti);
6392 }
6393 }
6394 if (OPT_ISSET(ops,'t')) {
6395 zlong timeout = 0;
6396 if (OPT_HASARG(ops,'t')) {
6397 mnumber mn = zero_mnumber;
6398 mn = matheval(OPT_ARG(ops,'t'));
6399 if (errflag)
6400 return 1;
6401 if (mn.type == MN_FLOAT) {
6402 mn.u.d *= 1e6;
6403 timeout = (zlong)mn.u.d;
6404 } else {
6405 timeout = (zlong)mn.u.l * (zlong)1000000;
6406 }
6407 }
6408 if (izle) {
6409 /*
6410 * Timeout is in 100ths of a second rather than us.
6411 * See calc_timeout() in zle_main for format of this.
6412 */
6413 timeout = -(timeout/(zlong)10000 + 1L);
6414 izle_timeout = (long)timeout;
6415 #ifdef LONG_MAX
6416 /* saturate if range exceeded */
6417 if ((zlong)izle_timeout != timeout)
6418 izle_timeout = LONG_MAX;
6419 #endif
6420 } else {
6421 if (readfd == -1 ||
6422 !read_poll(readfd, &readchar, keys && !zleactive,
6423 timeout)) {
6424 if (keys && !zleactive && !isem)
6425 settyinfo(&shttyinfo);
6426 else if (resettty && SHTTY != -1)
6427 settyinfo(&saveti);
6428 if (haso) {
6429 fclose(shout);
6430 shout = oshout;
6431 SHTTY = -1;
6432 }
6433 return OPT_ISSET(ops,'q') ? 2 : 1;
6434 }
6435 }
6436 }
6437
6438 #ifdef MULTIBYTE_SUPPORT
6439 memset(&mbs, 0, sizeof(mbs));
6440 #endif
6441
6442 /*
6443 * option -k means read only a given number of characters (default 1)
6444 * option -q means get one character, and interpret it as a Y or N
6445 */
6446 if (OPT_ISSET(ops,'k') || OPT_ISSET(ops,'q')) {
6447 int eof = 0;
6448 /* allocate buffer space for result */
6449 #ifdef MULTIBYTE_SUPPORT
6450 bptr = buf = (char *)zalloc(nchars*MB_CUR_MAX+1);
6451 #else
6452 bptr = buf = (char *)zalloc(nchars+1);
6453 #endif
6454
6455 do {
6456 if (izle) {
6457 zleentry(ZLE_CMD_GET_KEY, izle_timeout, NULL, &val);
6458 if (val < 0) {
6459 eof = 1;
6460 break;
6461 }
6462 *bptr = (char) val;
6463 #ifdef MULTIBYTE_SUPPORT
6464 if (isset(MULTIBYTE)) {
6465 ret = mbrlen(bptr++, 1, &mbs);
6466 if (ret == MB_INVALID)
6467 memset(&mbs, 0, sizeof(mbs));
6468 /* treat invalid as single character */
6469 if (ret != MB_INCOMPLETE)
6470 nchars--;
6471 continue;
6472 } else {
6473 bptr++;
6474 nchars--;
6475 }
6476 #else
6477 bptr++;
6478 nchars--;
6479 #endif
6480 } else {
6481 /* If read returns 0, is end of file */
6482 if (readchar >= 0) {
6483 *bptr = readchar;
6484 val = 1;
6485 readchar = -1;
6486 } else {
6487 while ((val = read(readfd, bptr, nchars)) < 0) {
6488 if (errno != EINTR ||
6489 errflag || retflag || breaks || contflag)
6490 break;
6491 }
6492 if (val <= 0) {
6493 eof = 1;
6494 break;
6495 }
6496 }
6497
6498 #ifdef MULTIBYTE_SUPPORT
6499 if (isset(MULTIBYTE)) {
6500 while (val > 0) {
6501 ret = mbrlen(bptr, val, &mbs);
6502 if (ret == MB_INCOMPLETE) {
6503 bptr += val;
6504 break;
6505 } else {
6506 if (ret == MB_INVALID) {
6507 memset(&mbs, 0, sizeof(mbs));
6508 /* treat as single byte */
6509 ret = 1;
6510 }
6511 else if (ret == 0) /* handle null as normal char */
6512 ret = 1;
6513 else if (ret > (size_t)val) {
6514 /* Some mbrlen()s return the full char len */
6515 ret = val;
6516 }
6517 nchars--;
6518 val -= ret;
6519 bptr += ret;
6520 }
6521 }
6522 continue;
6523 }
6524 #endif
6525 /* decrement number of characters read from number required */
6526 nchars -= val;
6527
6528 /* increment pointer past read characters */
6529 bptr += val;
6530 }
6531 } while (nchars > 0);
6532
6533 if (!izle && !OPT_ISSET(ops,'u') && !OPT_ISSET(ops,'p')) {
6534 /* dispose of result appropriately, etc. */
6535 if (isem)
6536 while (val > 0 && read(SHTTY, &d, 1) == 1 && d != '\n');
6537 else {
6538 settyinfo(&shttyinfo);
6539 resettty = 0;
6540 }
6541 if (haso) {
6542 fclose(shout); /* close(SHTTY) */
6543 shout = oshout;
6544 SHTTY = -1;
6545 }
6546 }
6547
6548 if (OPT_ISSET(ops,'q'))
6549 {
6550 /*
6551 * Keep eof as status but status is now whether we read
6552 * 'y' or 'Y'. If we timed out, status is 2.
6553 */
6554 if (eof)
6555 eof = 2;
6556 else
6557 eof = (bptr - buf != 1 || (buf[0] != 'y' && buf[0] != 'Y'));
6558 buf[0] = eof ? 'n' : 'y';
6559 bptr = buf + 1;
6560 }
6561 if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E'))
6562 fwrite(buf, bptr - buf, 1, stdout);
6563 if (!OPT_ISSET(ops,'e'))
6564 setsparam(reply, metafy(buf, bptr - buf, META_REALLOC));
6565 else
6566 zfree(buf, bptr - buf + 1);
6567 if (resettty && SHTTY != -1)
6568 settyinfo(&saveti);
6569 return eof;
6570 }
6571
6572 /* All possible special types of input have been exhausted. Take one line,
6573 and assign words to the parameters until they run out. Leftover words go
6574 onto the last parameter. If an array is specified, all the words become
6575 separate elements of the array. */
6576
6577 zbuforig = zbuf = (!OPT_ISSET(ops,'z')) ? NULL :
6578 (nonempty(bufstack)) ? (char *) getlinknode(bufstack) : ztrdup("");
6579 first = 1;
6580 bslash = 0;
6581 while (*args || (OPT_ISSET(ops,'A') && !gotnl)) {
6582 sigset_t s = child_unblock();
6583 buf = bptr = (char *)zalloc(bsiz = 64);
6584 #ifdef MULTIBYTE_SUPPORT
6585 laststart = buf;
6586 ret = MB_INCOMPLETE;
6587 #endif
6588 /* get input, a character at a time */
6589 while (!gotnl) {
6590 c = zread(izle, &readchar, izle_timeout);
6591 /* \ at the end of a line indicates a continuation *
6592 * line, except in raw mode (-r option) */
6593 #ifdef MULTIBYTE_SUPPORT
6594 if (c == EOF) {
6595 /* not waiting to be completed any more */
6596 ret = 0;
6597 break;
6598 }
6599 *bptr = (char)c;
6600 if (isset(MULTIBYTE)) {
6601 ret = mbrtowc(&wc, bptr, 1, &mbs);
6602 if (!ret) /* NULL */
6603 ret = 1;
6604 } else {
6605 ret = 1;
6606 wc = (wchar_t)c;
6607 }
6608 if (ret != MB_INCOMPLETE) {
6609 if (ret == MB_INVALID) {
6610 memset(&mbs, 0, sizeof(mbs));
6611 /* Treat this as a single character */
6612 wc = (wchar_t)c;
6613 laststart = bptr;
6614 }
6615 if (bslash && wc == delim) {
6616 bslash = 0;
6617 continue;
6618 }
6619 if (wc == delim)
6620 break;
6621 /*
6622 * `first' is non-zero if any separator we encounter is a
6623 * non-whitespace separator, which means that anything
6624 * (even an empty string) between, before or after separators
6625 * is significant. If it is zero, we have a whitespace
6626 * separator, which shouldn't cause extra empty strings to
6627 * be emitted. Hence the test for (*buf || first) when
6628 * we assign the result of reading a word.
6629 */
6630 if (!bslash && wcsitype(wc, ISEP)) {
6631 if (bptr != buf ||
6632 (!(c < 128 && iwsep(c)) && first)) {
6633 first |= !(c < 128 && iwsep(c));
6634 break;
6635 }
6636 first |= !(c < 128 && iwsep(c));
6637 continue;
6638 }
6639 bslash = (wc == L'\\' && !bslash && !OPT_ISSET(ops,'r'));
6640 if (bslash)
6641 continue;
6642 first = 0;
6643 }
6644 if (imeta(STOUC(*bptr))) {
6645 bptr[1] = bptr[0] ^ 32;
6646 bptr[0] = Meta;
6647 bptr += 2;
6648 }
6649 else
6650 bptr++;
6651 if (ret != MB_INCOMPLETE)
6652 laststart = bptr;
6653 #else
6654 if (c == EOF)
6655 break;
6656 if (bslash && c == delim) {
6657 bslash = 0;
6658 continue;
6659 }
6660 if (c == delim)
6661 break;
6662 /*
6663 * `first' is non-zero if any separator we encounter is a
6664 * non-whitespace separator, which means that anything
6665 * (even an empty string) between, before or after separators
6666 * is significant. If it is zero, we have a whitespace
6667 * separator, which shouldn't cause extra empty strings to
6668 * be emitted. Hence the test for (*buf || first) when
6669 * we assign the result of reading a word.
6670 */
6671 if (!bslash && isep(c)) {
6672 if (bptr != buf || (!iwsep(c) && first)) {
6673 first |= !iwsep(c);
6674 break;
6675 }
6676 first |= !iwsep(c);
6677 continue;
6678 }
6679 bslash = c == '\\' && !bslash && !OPT_ISSET(ops,'r');
6680 if (bslash)
6681 continue;
6682 first = 0;
6683 if (imeta(c)) {
6684 *bptr++ = Meta;
6685 *bptr++ = c ^ 32;
6686 } else
6687 *bptr++ = c;
6688 #endif
6689 /* increase the buffer size, if necessary */
6690 if (bptr >= buf + bsiz - 1) {
6691 int blen = bptr - buf;
6692 #ifdef MULTIBYTE_SUPPORT
6693 int llen = laststart - buf;
6694 #endif
6695
6696 buf = realloc(buf, bsiz *= 2);
6697 bptr = buf + blen;
6698 #ifdef MULTIBYTE_SUPPORT
6699 laststart = buf + llen;
6700 #endif
6701 }
6702 }
6703 signal_setmask(s);
6704 #ifdef MULTIBYTE_SUPPORT
6705 if (c == EOF) {
6706 gotnl = 1;
6707 *bptr = '\0'; /* see below */
6708 } else if (ret == MB_INCOMPLETE) {
6709 /*
6710 * We can only get here if there is an EOF in the
6711 * middle of a character... safest to keep the debris,
6712 * I suppose.
6713 */
6714 *bptr = '\0';
6715 } else {
6716 if (wc == delim)
6717 gotnl = 1;
6718 *laststart = '\0';
6719 }
6720 #else
6721 if (c == delim || c == EOF)
6722 gotnl = 1;
6723 *bptr = '\0';
6724 #endif
6725 /* dispose of word appropriately */
6726 if (OPT_ISSET(ops,'e') ||
6727 /*
6728 * When we're doing an array assignment, we'll
6729 * handle echoing at that point. In all other
6730 * cases (including -A with no assignment)
6731 * we'll do it here.
6732 */
6733 (OPT_ISSET(ops,'E') && !OPT_ISSET(ops,'A'))) {
6734 zputs(buf, stdout);
6735 putchar('\n');
6736 }
6737 if (!OPT_ISSET(ops,'e') && (*buf || first || gotnl)) {
6738 if (OPT_ISSET(ops,'A')) {
6739 addlinknode(readll, buf);
6740 al++;
6741 } else
6742 setsparam(reply, buf);
6743 } else
6744 free(buf);
6745 if (!OPT_ISSET(ops,'A'))
6746 reply = *args++;
6747 }
6748 /* handle EOF */
6749 if (c == EOF) {
6750 if (readfd == coprocin) {
6751 close(coprocin);
6752 close(coprocout);
6753 coprocin = coprocout = -1;
6754 }
6755 }
6756 /* final assignment (and display) of array parameter */
6757 if (OPT_ISSET(ops,'A')) {
6758 char **pp, **p = NULL;
6759 LinkNode n;
6760
6761 p = (OPT_ISSET(ops,'e') ? (char **)NULL
6762 : (char **)zalloc((al + 1) * sizeof(char *)));
6763
6764 for (pp = p, n = firstnode(readll); n; incnode(n)) {
6765 if (OPT_ISSET(ops,'E')) {
6766 zputs((char *) getdata(n), stdout);
6767 putchar('\n');
6768 }
6769 if (p)
6770 *pp++ = (char *)getdata(n);
6771 else
6772 zsfree(getdata(n));
6773 }
6774 if (p) {
6775 *pp++ = NULL;
6776 setaparam(reply, p);
6777 }
6778 if (resettty && SHTTY != -1)
6779 settyinfo(&saveti);
6780 return c == EOF;
6781 }
6782 buf = bptr = (char *)zalloc(bsiz = 64);
6783 #ifdef MULTIBYTE_SUPPORT
6784 laststart = buf;
6785 ret = MB_INCOMPLETE;
6786 #endif
6787 /* any remaining part of the line goes into one parameter */
6788 bslash = 0;
6789 if (!gotnl) {
6790 sigset_t s = child_unblock();
6791 for (;;) {
6792 c = zread(izle, &readchar, izle_timeout);
6793 #ifdef MULTIBYTE_SUPPORT
6794 if (c == EOF) {
6795 /* not waiting to be completed any more */
6796 ret = 0;
6797 break;
6798 }
6799 *bptr = (char)c;
6800 if (isset(MULTIBYTE)) {
6801 ret = mbrtowc(&wc, bptr, 1, &mbs);
6802 if (!ret) /* NULL */
6803 ret = 1;
6804 } else {
6805 ret = 1;
6806 wc = (wchar_t)c;
6807 }
6808 if (ret != MB_INCOMPLETE) {
6809 if (ret == MB_INVALID) {
6810 memset(&mbs, 0, sizeof(mbs));
6811 /* Treat this as a single character */
6812 wc = (wchar_t)c;
6813 laststart = bptr;
6814 }
6815 /*
6816 * \ at the end of a line introduces a continuation line,
6817 * except in raw mode (-r option)
6818 */
6819 if (bslash && wc == delim) {
6820 bslash = 0;
6821 continue;
6822 }
6823 if (wc == delim && !zbuf)
6824 break;
6825 if (!bslash && bptr == buf && wcsitype(wc, ISEP)) {
6826 if (c < 128 && iwsep(c))
6827 continue;
6828 else if (!first) {
6829 first = 1;
6830 continue;
6831 }
6832 }
6833 bslash = (wc == L'\\' && !bslash && !OPT_ISSET(ops,'r'));
6834 if (bslash)
6835 continue;
6836 }
6837 if (imeta(STOUC(*bptr))) {
6838 bptr[1] = bptr[0] ^ 32;
6839 bptr[0] = Meta;
6840 bptr += 2;
6841 }
6842 else
6843 bptr++;
6844 if (ret != MB_INCOMPLETE)
6845 laststart = bptr;
6846 #else
6847 /* \ at the end of a line introduces a continuation line, except in
6848 raw mode (-r option) */
6849 if (bslash && c == delim) {
6850 bslash = 0;
6851 continue;
6852 }
6853 if (c == EOF || (c == delim && !zbuf))
6854 break;
6855 if (!bslash && isep(c) && bptr == buf) {
6856 if (iwsep(c))
6857 continue;
6858 else if (!first) {
6859 first = 1;
6860 continue;
6861 }
6862 }
6863 bslash = c == '\\' && !bslash && !OPT_ISSET(ops,'r');
6864 if (bslash)
6865 continue;
6866 if (imeta(c)) {
6867 *bptr++ = Meta;
6868 *bptr++ = c ^ 32;
6869 } else
6870 *bptr++ = c;
6871 #endif
6872 /* increase the buffer size, if necessary */
6873 if (bptr >= buf + bsiz - 1) {
6874 int blen = bptr - buf;
6875 #ifdef MULTIBYTE_SUPPORT
6876 int llen = laststart - buf;
6877 #endif
6878
6879 buf = realloc(buf, bsiz *= 2);
6880 bptr = buf + blen;
6881 #ifdef MULTIBYTE_SUPPORT
6882 laststart = buf + llen;
6883 #endif
6884 }
6885 }
6886 signal_setmask(s);
6887 }
6888 #ifdef MULTIBYTE_SUPPORT
6889 if (ret != MB_INCOMPLETE)
6890 bptr = laststart;
6891 #endif
6892 /*
6893 * Strip trailing IFS whitespace.
6894 * iwsep can only be certain single-byte ASCII bytes, but we
6895 * must check the byte isn't metafied.
6896 */
6897 while (bptr > buf) {
6898 if (bptr > buf + 1 && bptr[-2] == Meta) {
6899 /* non-ASCII, can't be IWSEP */
6900 break;
6901 } else if (iwsep(bptr[-1]))
6902 bptr--;
6903 else
6904 break;
6905 }
6906 *bptr = '\0';
6907 if (resettty && SHTTY != -1)
6908 settyinfo(&saveti);
6909 /* final assignment of reply, etc. */
6910 if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E')) {
6911 zputs(buf, stdout);
6912 putchar('\n');
6913 }
6914 if (!OPT_ISSET(ops,'e'))
6915 setsparam(reply, buf);
6916 else
6917 zsfree(buf);
6918 if (zbuforig) {
6919 char first = *zbuforig;
6920
6921 zsfree(zbuforig);
6922 if (!first)
6923 return 1;
6924 } else if (c == EOF) {
6925 if (readfd == coprocin) {
6926 close(coprocin);
6927 close(coprocout);
6928 coprocin = coprocout = -1;
6929 }
6930 return 1;
6931 }
6932 /*
6933 * The following is to ensure a failure to set the parameter
6934 * causes a non-zero status return. There are arguments for
6935 * turning a non-zero status into errflag more widely.
6936 */
6937 return errflag;
6938 }
6939
6940 /**/
6941 static int
zread(int izle,int * readchar,long izle_timeout)6942 zread(int izle, int *readchar, long izle_timeout)
6943 {
6944 char cc, retry = 0;
6945 int ret;
6946
6947 if (izle) {
6948 int c;
6949 zleentry(ZLE_CMD_GET_KEY, izle_timeout, NULL, &c);
6950
6951 return (c < 0 ? EOF : c);
6952 }
6953 /* use zbuf if possible */
6954 if (zbuf) {
6955 /* If zbuf points to anything, it points to the next character in the
6956 buffer. This may be a null byte to indicate EOF. If reading from the
6957 buffer, move on the buffer pointer. */
6958 if (*zbuf == Meta)
6959 return zbuf++, STOUC(*zbuf++ ^ 32);
6960 else
6961 return (*zbuf) ? STOUC(*zbuf++) : EOF;
6962 }
6963 if (*readchar >= 0) {
6964 cc = *readchar;
6965 *readchar = -1;
6966 return STOUC(cc);
6967 }
6968 for (;;) {
6969 /* read a character from readfd */
6970 ret = read(readfd, &cc, 1);
6971 switch (ret) {
6972 case 1:
6973 /* return the character read */
6974 return STOUC(cc);
6975 case -1:
6976 #if defined(EAGAIN) || defined(EWOULDBLOCK)
6977 if (!retry && readfd == 0 && (
6978 # ifdef EAGAIN
6979 errno == EAGAIN
6980 # ifdef EWOULDBLOCK
6981 ||
6982 # endif /* EWOULDBLOCK */
6983 # endif /* EAGAIN */
6984 # ifdef EWOULDBLOCK
6985 errno == EWOULDBLOCK
6986 # endif /* EWOULDBLOCK */
6987 ) && setblock_stdin()) {
6988 retry = 1;
6989 continue;
6990 } else
6991 #endif /* EAGAIN || EWOULDBLOCK */
6992 if (errno == EINTR && !(errflag || retflag || breaks || contflag))
6993 continue;
6994 break;
6995 }
6996 return EOF;
6997 }
6998 }
6999
7000 /* holds arguments for testlex() */
7001 /**/
7002 char **testargs, **curtestarg;
7003
7004 /* test, [: the old-style general purpose logical expression builtin */
7005
7006 /**/
7007 void
testlex(void)7008 testlex(void)
7009 {
7010 if (tok == LEXERR)
7011 return;
7012
7013 tokstr = *(curtestarg = testargs);
7014 if (!*testargs) {
7015 /* if tok is already zero, reading past the end: error */
7016 tok = tok ? NULLTOK : LEXERR;
7017 return;
7018 } else if (!strcmp(*testargs, "-o"))
7019 tok = DBAR;
7020 else if (!strcmp(*testargs, "-a"))
7021 tok = DAMPER;
7022 else if (!strcmp(*testargs, "!"))
7023 tok = BANG;
7024 else if (!strcmp(*testargs, "("))
7025 tok = INPAR;
7026 else if (!strcmp(*testargs, ")"))
7027 tok = OUTPAR;
7028 else
7029 tok = STRING;
7030 testargs++;
7031 }
7032
7033 /**/
7034 int
bin_test(char * name,char ** argv,UNUSED (Options ops),int func)7035 bin_test(char *name, char **argv, UNUSED(Options ops), int func)
7036 {
7037 char **s;
7038 Eprog prog;
7039 struct estate state;
7040 int nargs, sense = 0, ret;
7041
7042 /* if "test" was invoked as "[", it needs a matching "]" *
7043 * which is subsequently ignored */
7044 if (func == BIN_BRACKET) {
7045 for (s = argv; *s; s++);
7046 if (s == argv || strcmp(s[-1], "]")) {
7047 zwarnnam(name, "']' expected");
7048 return 2;
7049 }
7050 s[-1] = NULL;
7051 }
7052 /* an empty argument list evaluates to false (1) */
7053 if (!*argv)
7054 return 1;
7055
7056 /*
7057 * Implement some XSI extensions to POSIX here.
7058 * See
7059 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html
7060 */
7061 nargs = arrlen(argv);
7062 if (nargs == 3 || nargs == 4)
7063 {
7064 /*
7065 * As parentheses are an extension, we need to be careful ---
7066 * if this is a three-argument expression that could
7067 * be a binary operator, prefer that.
7068 */
7069 if (!strcmp(argv[0], "(") && !strcmp(argv[nargs-1],")") &&
7070 (nargs != 3 || !is_cond_binary_op(argv[1]))) {
7071 argv[nargs-1] = NULL;
7072 argv++;
7073 }
7074 if (nargs == 4 && !strcmp("!", argv[0])) {
7075 sense = 1;
7076 argv++;
7077 }
7078 }
7079
7080 zcontext_save();
7081 testargs = argv;
7082 tok = NULLTOK;
7083 condlex = testlex;
7084 testlex();
7085 prog = parse_cond();
7086 condlex = zshlex;
7087
7088 if (errflag) {
7089 errflag &= ~ERRFLAG_ERROR;
7090 zcontext_restore();
7091 return 2;
7092 }
7093
7094 if (!prog || tok == LEXERR) {
7095 zwarnnam(name, tokstr ? "parse error" : "argument expected");
7096 zcontext_restore();
7097 return 2;
7098 }
7099 zcontext_restore();
7100
7101 if (*curtestarg) {
7102 zwarnnam(name, "too many arguments");
7103 return 2;
7104 }
7105
7106 /* syntax is OK, so evaluate */
7107
7108 state.prog = prog;
7109 state.pc = prog->prog;
7110 state.strs = prog->strs;
7111
7112 ret = evalcond(&state, name);
7113 if (ret < 2 && sense)
7114 ret = ! ret;
7115
7116 return ret;
7117 }
7118
7119 /* display a time, provided in units of 1/60s, as minutes and seconds */
7120 #define pttime(X) printf("%ldm%ld.%02lds",((long) (X))/(60 * clktck),\
7121 ((long) (X))/clktck%clktck,\
7122 ((long) (X))*100/clktck%100)
7123
7124 /* times: display, in a two-line format, the times provided by times(3) */
7125
7126 /**/
7127 int
bin_times(UNUSED (char * name),UNUSED (char ** argv),UNUSED (Options ops),UNUSED (int func))7128 bin_times(UNUSED(char *name), UNUSED(char **argv), UNUSED(Options ops), UNUSED(int func))
7129 {
7130 struct tms buf;
7131 long clktck = get_clktck();
7132
7133 /* get time accounting information */
7134 if (times(&buf) == -1)
7135 return 1;
7136 pttime(buf.tms_utime); /* user time */
7137 putchar(' ');
7138 pttime(buf.tms_stime); /* system time */
7139 putchar('\n');
7140 pttime(buf.tms_cutime); /* user time, children */
7141 putchar(' ');
7142 pttime(buf.tms_cstime); /* system time, children */
7143 putchar('\n');
7144 return 0;
7145 }
7146
7147 /* trap: set/unset signal traps */
7148
7149 /**/
7150 int
bin_trap(char * name,char ** argv,UNUSED (Options ops),UNUSED (int func))7151 bin_trap(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
7152 {
7153 Eprog prog;
7154 char *arg, *s;
7155 int sig;
7156
7157 if (*argv && !strcmp(*argv, "--"))
7158 argv++;
7159
7160 /* If given no arguments, list all currently-set traps */
7161 if (!*argv) {
7162 queue_signals();
7163 for (sig = 0; sig < VSIGCOUNT; sig++) {
7164 if (sigtrapped[sig] & ZSIG_FUNC) {
7165 HashNode hn;
7166
7167 if ((hn = gettrapnode(sig, 0)))
7168 shfunctab->printnode(hn, 0);
7169 DPUTS(!hn, "BUG: I did not find any trap functions!");
7170 } else if (sigtrapped[sig]) {
7171 const char *name = getsigname(sig);
7172 if (!siglists[sig])
7173 printf("trap -- '' %s\n", name);
7174 else {
7175 s = getpermtext(siglists[sig], NULL, 0);
7176 printf("trap -- ");
7177 quotedzputs(s, stdout);
7178 printf(" %s\n", name);
7179 zsfree(s);
7180 }
7181 }
7182 }
7183 unqueue_signals();
7184 return 0;
7185 }
7186
7187 /* If we have a signal number, unset the specified *
7188 * signals. With only -, remove all traps. */
7189 if ((getsignum(*argv) != -1) || (!strcmp(*argv, "-") && argv++)) {
7190 if (!*argv) {
7191 for (sig = 0; sig < VSIGCOUNT; sig++)
7192 unsettrap(sig);
7193 } else {
7194 for (; *argv; argv++) {
7195 sig = getsignum(*argv);
7196 if (sig == -1) {
7197 zwarnnam(name, "undefined signal: %s", *argv);
7198 break;
7199 }
7200 unsettrap(sig);
7201 }
7202 }
7203 return *argv != NULL;
7204 }
7205
7206 /* Sort out the command to execute on trap */
7207 arg = *argv++;
7208 if (!*arg)
7209 prog = &dummy_eprog;
7210 else if (!(prog = parse_string(arg, 1))) {
7211 zwarnnam(name, "couldn't parse trap command");
7212 return 1;
7213 }
7214
7215 /* set traps */
7216 for (; *argv; argv++) {
7217 Eprog t;
7218 int flags;
7219
7220 sig = getsignum(*argv);
7221 if (sig == -1) {
7222 zwarnnam(name, "undefined signal: %s", *argv);
7223 break;
7224 }
7225 if (idigit(**argv) ||
7226 !strcmp(sigs[sig], *argv) ||
7227 (!strncmp("SIG", *argv, 3) && !strcmp(sigs[sig], *argv+3))) {
7228 /* The signal was specified by number or by canonical name (with
7229 * or without SIG prefix).
7230 */
7231 flags = 0;
7232 }
7233 else {
7234 /*
7235 * Record that the signal is used under an assumed name.
7236 * If we ever have more than one alias per signal this
7237 * will need improving.
7238 */
7239 flags = ZSIG_ALIAS;
7240 }
7241 t = dupeprog(prog, 0);
7242 if (settrap(sig, t, flags))
7243 freeeprog(t);
7244 }
7245 return *argv != NULL;
7246 }
7247
7248 /**/
7249 int
bin_ttyctl(UNUSED (char * name),UNUSED (char ** argv),Options ops,UNUSED (int func))7250 bin_ttyctl(UNUSED(char *name), UNUSED(char **argv), Options ops, UNUSED(int func))
7251 {
7252 if (OPT_ISSET(ops,'f'))
7253 ttyfrozen = 1;
7254 else if (OPT_ISSET(ops,'u'))
7255 ttyfrozen = 0;
7256 else
7257 printf("tty is %sfrozen\n", ttyfrozen ? "" : "not ");
7258 return 0;
7259 }
7260
7261 /* let -- mathematical evaluation */
7262
7263 /**/
7264 int
bin_let(UNUSED (char * name),char ** argv,UNUSED (Options ops),UNUSED (int func))7265 bin_let(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int func))
7266 {
7267 mnumber val = zero_mnumber;
7268
7269 while (*argv)
7270 val = matheval(*argv++);
7271 /* Errors in math evaluation in let are non-fatal. */
7272 errflag &= ~ERRFLAG_ERROR;
7273 /* should test for fabs(val.u.d) < epsilon? */
7274 return (val.type == MN_INTEGER) ? val.u.l == 0 : val.u.d == 0.0;
7275 }
7276
7277 /* umask command. umask may be specified as octal digits, or in the *
7278 * symbolic form that chmod(1) uses. Well, a subset of it. Remember *
7279 * that only the bottom nine bits of umask are used, so there's no *
7280 * point allowing the set{u,g}id and sticky bits to be specified. */
7281
7282 /**/
7283 int
bin_umask(char * nam,char ** args,Options ops,UNUSED (int func))7284 bin_umask(char *nam, char **args, Options ops, UNUSED(int func))
7285 {
7286 mode_t um;
7287 char *s = *args;
7288
7289 /* Get the current umask. */
7290 queue_signals();
7291 um = umask(0777);
7292 umask(um);
7293 unqueue_signals();
7294
7295 /* No arguments means to display the current setting. */
7296 if (!s) {
7297 if (OPT_ISSET(ops,'S')) {
7298 char *who = "ugo";
7299
7300 while (*who) {
7301 char *what = "rwx";
7302 printf("%c=", *who++);
7303 while (*what) {
7304 if (!(um & 0400))
7305 putchar(*what);
7306 um <<= 1;
7307 what++;
7308 }
7309 putchar(*who ? ',' : '\n');
7310 }
7311 } else {
7312 if (um & 0700)
7313 putchar('0');
7314 printf("%03o\n", (unsigned)um);
7315 }
7316 return 0;
7317 }
7318
7319 if (idigit(*s)) {
7320 /* Simple digital umask. */
7321 um = zstrtol(s, &s, 8);
7322 if (*s) {
7323 zwarnnam(nam, "bad umask");
7324 return 1;
7325 }
7326 } else {
7327 /* Symbolic notation -- slightly complicated. */
7328 int whomask, umaskop, mask;
7329
7330 /* More than one symbolic argument may be used at once, each separated
7331 by commas. */
7332 for (;;) {
7333 /* First part of the argument -- who does this apply to?
7334 u=owner, g=group, o=other. */
7335 whomask = 0;
7336 while (*s == 'u' || *s == 'g' || *s == 'o' || *s == 'a')
7337 if (*s == 'u')
7338 s++, whomask |= 0700;
7339 else if (*s == 'g')
7340 s++, whomask |= 0070;
7341 else if (*s == 'o')
7342 s++, whomask |= 0007;
7343 else if (*s == 'a')
7344 s++, whomask |= 0777;
7345 /* Default whomask is everyone. */
7346 if (!whomask)
7347 whomask = 0777;
7348 /* Operation may be +, - or =. */
7349 umaskop = (int)*s;
7350 if (!(umaskop == '+' || umaskop == '-' || umaskop == '=')) {
7351 if (umaskop)
7352 zwarnnam(nam, "bad symbolic mode operator: %c", umaskop);
7353 else
7354 zwarnnam(nam, "bad umask");
7355 return 1;
7356 }
7357 /* Permissions mask -- r=read, w=write, x=execute. */
7358 mask = 0;
7359 while (*++s && *s != ',')
7360 if (*s == 'r')
7361 mask |= 0444 & whomask;
7362 else if (*s == 'w')
7363 mask |= 0222 & whomask;
7364 else if (*s == 'x')
7365 mask |= 0111 & whomask;
7366 else {
7367 zwarnnam(nam, "bad symbolic mode permission: %c", *s);
7368 return 1;
7369 }
7370 /* Apply parsed argument to um. */
7371 if (umaskop == '+')
7372 um &= ~mask;
7373 else if (umaskop == '-')
7374 um |= mask;
7375 else /* umaskop == '=' */
7376 um = (um | (whomask)) & ~mask;
7377 if (*s == ',')
7378 s++;
7379 else
7380 break;
7381 }
7382 if (*s) {
7383 zwarnnam(nam, "bad character in symbolic mode: %c", *s);
7384 return 1;
7385 }
7386 }
7387
7388 /* Finally, set the new umask. */
7389 umask(um);
7390 return 0;
7391 }
7392
7393 /* Generic builtin for facilities not available on this OS */
7394
7395 /**/
7396 mod_export int
bin_notavail(char * nam,UNUSED (char ** argv),UNUSED (Options ops),UNUSED (int func))7397 bin_notavail(char *nam, UNUSED(char **argv), UNUSED(Options ops), UNUSED(int func))
7398 {
7399 zwarnnam(nam, "not available on this system");
7400 return 1;
7401 }
7402