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