toybox/toys/pending/sh.c
<<
>>
Prefs
   1/* sh.c - toybox shell
   2 *
   3 * Copyright 2006 Rob Landley <rob@landley.net>
   4 *
   5 * The POSIX-2008/SUSv4 spec for this is at:
   6 * http://opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
   7 * and http://opengroup.org/onlinepubs/9699919799/utilities/sh.html
   8 *
   9 * The first link describes the following shell builtins:
  10 *
  11 *   break colon continue dot eval exec exit export readonly return set shift
  12 *   times trap unset
  13 *
  14 * The second link (the utilities directory) also contains specs for the
  15 * following shell builtins:
  16 *
  17 *   alias bg cd command fc fg getopts hash jobs kill read type ulimit
  18 *   umask unalias wait
  19 *
  20 * Things like the bash man page are good to read too.
  21 *
  22 * TODO: "make sh" doesn't work (nofork builtins need to be included)
  23 * TODO: test that $PS1 color changes work without stupid \[ \] hack
  24 * TODO: make fake pty wrapper for test infrastructure
  25 * TODO: // Handle embedded NUL bytes in the command line.
  26 * TODO: var=val command
  27 * existing but considered builtins: false kill pwd true time
  28 * buitins: alias bg command fc fg getopts jobs newgrp read umask unalias wait
  29 * "special" builtins: break continue : . eval exec export readonly return set
  30 *   shift times trap unset
  31 * | & ; < > ( ) $ ` \ " ' <space> <tab> <newline>
  32 * * ? [ # ~ = %
  33 * ! { } case do done elif else esac fi for if in then until while
  34 * [[ ]] function select
  35 * $@ $* $# $? $- $$ $! $0
  36 * ENV HOME IFS LANG LC_ALL LINENO PATH PPID PS1 PS2 PS4 PWD
  37 * label:
  38 * TODO: test exit from "trap EXIT" doesn't recurse
  39 * TODO: ! history expansion
  40 *
  41 * bash man page:
  42 * control operators || & && ; ;; ;& ;;& ( ) | |& <newline>
  43 * reserved words
  44 *   ! case  coproc  do done elif else esac fi for  function  if  in  select
  45 *   then until while { } time [[ ]]
  46
  47
  48
  49USE_SH(NEWTOY(cd, NULL, TOYFLAG_NOFORK))
  50USE_SH(NEWTOY(exit, NULL, TOYFLAG_NOFORK))
  51
  52USE_SH(NEWTOY(sh, "c:i", TOYFLAG_BIN))
  53USE_SH(OLDTOY(toysh, sh, TOYFLAG_BIN))
  54USE_SH(OLDTOY(bash, sh, TOYFLAG_BIN))
  55// Login lies in argv[0], so add some aliases to catch that
  56USE_SH(OLDTOY(-sh, sh, 0))
  57USE_SH(OLDTOY(-toysh, sh, 0))
  58USE_SH(OLDTOY(-bash, sh, 0))
  59
  60config SH
  61  bool "sh (toysh)"
  62  default n
  63  help
  64    usage: sh [-c command] [script]
  65
  66    Command shell.  Runs a shell script, or reads input interactively
  67    and responds to it.
  68
  69    -c  command line to execute
  70    -i  interactive mode (default when STDIN is a tty)
  71
  72# These are here for the help text, they're not selectable and control nothing
  73config CD
  74  bool
  75  default n
  76  depends on SH
  77  help
  78    usage: cd [-PL] [path]
  79
  80    Change current directory.  With no arguments, go $HOME.
  81
  82    -P  Physical path: resolve symlinks in path
  83    -L  Local path: .. trims directories off $PWD (default)
  84
  85config EXIT
  86  bool
  87  default n
  88  depends on SH
  89  help
  90    usage: exit [status]
  91
  92    Exit shell.  If no return value supplied on command line, use value
  93    of most recent command, or 0 if none.
  94*/
  95
  96#define FOR_sh
  97#include "toys.h"
  98
  99GLOBALS(
 100  char *command;
 101
 102  long lineno;
 103
 104  struct double_list functions;
 105  unsigned options;
 106
 107  // Running jobs.
 108  struct sh_job {
 109    struct sh_job *next, *prev;
 110    unsigned jobno;
 111
 112    // Every pipeline has at least one set of arguments or it's Not A Thing
 113    struct sh_arg {
 114      char **v;
 115      int c;
 116    } pipeline;
 117
 118    // null terminated array of running processes in pipeline
 119    struct sh_process {
 120      struct string_list *delete; // expanded strings
 121      int pid, exit;   // status? Stopped? Exited?
 122      struct sh_arg arg;
 123    } *procs, *proc;
 124  } *jobs, *job;
 125  unsigned jobcnt;
 126)
 127
 128#define SH_NOCLOBBER 1   // set -C
 129
 130void cd_main(void)
 131{
 132  char *dest = *toys.optargs ? *toys.optargs : getenv("HOME");
 133
 134// TODO: -LPE@
 135// TODO: cd .. goes up $PWD path we used to get here, not ./..
 136  xchdir(dest ? dest : "/");
 137}
 138
 139void exit_main(void)
 140{
 141  exit(*toys.optargs ? atoi(*toys.optargs) : 0);
 142}
 143
 144// like error_msg() but exit from shell scripts
 145void syntax_err(char *msg, ...)
 146{
 147  va_list va;
 148
 149  va_start(va, msg);
 150  verror_msg(msg, 0, va);
 151  va_end(va);
 152
 153  if (*toys.optargs) xexit();
 154}
 155
 156// Print prompt, parsing escapes
 157static void do_prompt(char *prompt)
 158{
 159  char *s, c, cc;
 160
 161  if (!prompt) prompt = "\\$ ";
 162  while (*prompt) {
 163    c = *(prompt++);
 164
 165    if (c=='!') {
 166      if (*prompt=='!') prompt++;
 167      else {
 168        printf("%ld", TT.lineno);
 169        continue;
 170      }
 171    } else if (c=='\\') {
 172      int i = 0;
 173
 174      cc = *(prompt++);
 175      if (!cc) goto down;
 176
 177      // \nnn \dD{}hHjlstT@AuvVwW!#$
 178      // Ignore bash's "nonprintable" hack; query our cursor position instead.
 179      if (cc=='[' || cc==']') continue;
 180      else if (cc=='$') putchar(getuid() ? '$' : '#');
 181      else if (cc=='h' || cc=='H') {
 182        *toybuf = 0;
 183        gethostname(toybuf, sizeof(toybuf)-1);
 184        if (cc=='h' && (s = strchr(toybuf, '.'))) *s = 0;
 185        fputs(toybuf, stdout);
 186      } else if (cc=='s') fputs(getbasename(*toys.argv), stdout);
 187      else {
 188        if (!(c = unescape(cc))) {
 189          c = '\\';
 190          prompt--;
 191        }
 192        i++;
 193      }
 194      if (!i) continue;
 195    }
 196down:
 197    putchar(c);
 198  }
 199  fflush(stdout);
 200}
 201
 202// quote removal, brace, tilde, parameter/variable, $(command),
 203// $((arithmetic)), split, path 
 204#define NO_PATH  (1<<0)
 205#define NO_SPLIT (1<<1)
 206// TODO: ${name:?error} causes an error/abort here (syntax_err longjmp?)
 207// TODO: $1 $@ $* need args marshalled down here: function+structure?
 208// arg = append to this
 209// new = string to expand
 210// flags = type of expansions (not) to do
 211// delete = append new allocations to this so they can be freed later
 212// TODO: at_args: $1 $2 $3 $* $@
 213static void expand_arg(struct sh_arg *arg, char *new, unsigned flags,
 214  struct string_list **delete)
 215{
 216  if (!(arg->c&32)) arg->v = xrealloc(arg->v, sizeof(void *)*(arg->c+33));
 217
 218  arg->v[arg->c++] = new;
 219  arg->v[arg->c] = 0;
 220
 221/*
 222  char *s = word, *new = 0;
 223
 224  // replacement
 225  while (*s) {
 226    if (*s == '$') {
 227      s++;
 228    } else if (*strchr("*?[{", *s)) {
 229      s++;
 230    } else if (*s == '<' || *s == '>') {
 231      s++;
 232    } else s++;
 233  }
 234
 235  return new;
 236*/
 237}
 238
 239// Assign one variable
 240// s: key=val
 241// type: 0 = whatever it was before, local otherwise
 242#define TAKE_MEM 0x80000000
 243// declare -aAilnrux
 244// ft
 245void setvar(char *s, unsigned type)
 246{
 247  if (type&TAKE_MEM) type ^= TAKE_MEM;
 248  else s = xstrdup(s);
 249
 250  // local, export, readonly, integer...
 251  xsetenv(s, 0);
 252}
 253
 254char *getvar(char *s)
 255{
 256  return getenv(s);
 257}
 258
 259// return length of match found at this point
 260static int anystart(char *s, char **try)
 261{
 262  while (*try) {
 263    if (strstart(&s, *try)) return strlen(*try);
 264    try++;
 265  }
 266
 267  return 0;
 268}
 269
 270static int anystr(char *s, char **try)
 271{
 272  while (*try) if (!strcmp(s, *try++)) return 1;
 273
 274  return 0;
 275}
 276
 277// return length of valid prefix that could go before redirect
 278int redir_prefix(char *word)
 279{
 280  char *s = word;
 281
 282  if (*s == '{') {
 283    for (s++; isalnum(*s) || *s=='_'; s++);
 284    if (*s == '}' && s != word+1) s++;
 285    else s = word;
 286  } else while (isdigit(*s)) s++;
 287
 288  return s-word;
 289}
 290
 291// TODO |&
 292
 293// rd[0] = next, 1 = prev, 2 = len, 3-x = to/from redirection pairs.
 294// Execute the commands in a pipeline segment
 295struct sh_process *run_command(struct sh_arg *arg, int **rdlist)
 296{
 297  struct sh_process *pp = xzalloc(sizeof(struct sh_process));
 298  struct toy_list *tl;
 299  char *s, *ss, *sss;
 300  unsigned envlen, j;
 301  int fd, here = 0, rdcount = 0, *rd = 0, *rr, hfd = 0;
 302
 303  // Grab variable assignments
 304  for (envlen = 0; envlen<arg->c; envlen++) {
 305    s = arg->v[envlen];
 306    for (j=0; s[j] && (s[j]=='_' || !ispunct(s[j])); j++);
 307    if (!j || s[j] != '=') break;
 308  }
 309
 310  // perform assignments locally if there's no command
 311  if (envlen == arg->c) {
 312    for (j = 0; j<envlen; j++) {
 313      struct sh_arg aa;
 314
 315      aa.c = 0;
 316      expand_arg(&aa, arg->v[j], NO_PATH|NO_SPLIT, 0);
 317      setvar(*aa.v, TAKE_MEM);
 318      free(aa.v);
 319    }
 320    free(pp);
 321
 322    return 0;
 323  }
 324
 325  // We vfork() instead of fork to support nommu systems, and do
 326  // redirection setup in the parent process. Open new filehandles
 327  // and move them to temporary values >10. The rd[] array has pairs of
 328  // filehandles: child replaces fd1 with fd2 via dup2() and close() after
 329  // the vfork(). fd2 is <<1, if bottom bit set don't close it (dup instead).
 330  // If fd2 < 0 it's a here document (parent process writes to a pipe later).
 331
 332  // Expand arguments and perform redirections
 333  for (j = envlen; j<arg->c; j++) {
 334
 335    // Is this a redirect?
 336    ss = (s = arg->v[j]) + redir_prefix(arg->v[j]);
 337    if (!anystr(ss, (char *[]){"<<<", "<<-", "<<", "<&", "<>", "<", ">>", ">&",
 338      ">|", ">", "&>>", "&>", 0}))
 339    {
 340      // Nope: save/expand argument and loop
 341      expand_arg(&pp->arg, s, 0, 0);
 342
 343      continue;
 344    }
 345
 346    // Yes. Expand rd[] and find first unused filehandle >10
 347    if (!(rdcount&31)) {
 348      if (rd) dlist_lpop((void *)rdlist);
 349      rd = xrealloc(rd, (2*rdcount+3+2*32)*sizeof(int *));
 350      dlist_add_nomalloc((void *)rdlist, (void *)rd);
 351    }
 352    rr = rd+3+rdcount;
 353    if (!hfd)
 354      for (hfd = 10; hfd<99999; hfd++) if (-1 == fcntl(hfd, F_GETFL)) break;
 355
 356    // error check: premature EOF, target fd too high, or redirect file splits
 357    if (++j == arg->c || (isdigit(*s) && ss-s>5)) goto flush;
 358    fd = pp->arg.c;
 359
 360    // expand arguments for everything but << and <<-
 361    if (strncmp(ss, "<<", 2) || ss[2] == '<') {
 362      expand_arg(&pp->arg, arg->v[j], NO_PATH|(NO_SPLIT*!strcmp(ss, "<<<")), 0);
 363      if (fd+1 != pp->arg.c) goto flush;
 364      sss = pp->arg.v[--pp->arg.c];
 365    } else dlist_add((void *)&pp->delete, sss = xstrdup(arg->v[j]));
 366
 367    // rd[] entries come in pairs: first is which fd gets redirected after
 368    // vfork(), I.E. the [n] part of [n]<word
 369
 370    if (isdigit(*ss)) fd = atoi(ss);
 371    else if (*ss == '{') {
 372      ss++;
 373      // when we close a filehandle, we _read_ from {var}, not write to it
 374      if ((!strcmp(s, "<&") || !strcmp(s, ">&")) && !strcmp(sss, "-")) {
 375        ss = xstrndup(ss, (s-ss)-1);
 376        sss = getvar(ss);
 377        free(ss);
 378        fd = -1;
 379        if (sss) fd = atoi(sss);
 380        if (fd<0) goto flush;
 381        if (fd>2) {
 382          rr[0] = fd;
 383          rr[1] = fd<<1; // close it
 384          rdcount++;
 385        }
 386        continue;
 387      } else setvar(xmprintf("%.*s=%d", (int)(s-ss), ss, hfd),  TAKE_MEM); 
 388    } else fd = *ss != '<';
 389    *rr = fd;
 390
 391    // at this point for [n]<word s = start of [n], ss = start of <, sss = word
 392
 393    // second entry in this rd[] pair is new fd to dup2() after vfork(),
 394    // I.E. for [n]<word the fd if you open("word"). It's stored <<1 and the
 395    // low bit set means don't close(rr[1]) after dup2(rr[1]>>1, rr[0]);
 396
 397    // fd<0 means HERE document. Canned input stored earlier, becomes pipe later
 398    if (!strcmp(s, "<<<") || !strcmp(s, "<<-") || !strcmp(s, "<<")) {
 399      fd = --here<<2;
 400      if (s[2] == '-') fd += 1;          // zap tabs
 401      if (s[strcspn(s, "\"'")]) fd += 2; // it was quoted so no expansion
 402      rr[1] = fd;
 403      rdcount++;
 404
 405      continue;
 406    }
 407
 408    // Handle file descriptor duplication/close (&> &>> <& >& with number or -)
 409    if (strchr(ss, '&') && ss[2] != '>') {
 410      char *dig = sss;
 411
 412      // These redirect existing fd so nothing to open()
 413      while (isdigit(dig)) dig++;
 414      if (dig-sss>5) {
 415        s = sss;
 416        goto flush;
 417      }
 418
 419// TODO can't check if fd is open here, must do it when actual redirects happen
 420      if (!*dig || (*dig=='-' && !dig[1])) {
 421        rr[1] = (((dig==sss) ? *rr : atoi(sss))<<1)+(*dig != '-');
 422        rdcount++;
 423
 424        continue;
 425      }
 426    }
 427
 428    // Permissions to open external file with: < > >> <& >& <> >| &>> &>
 429    if (!strcmp(ss, "<>")) fd = O_CREAT|O_RDWR;
 430    else if (strstr(ss, ">>")) fd = O_CREAT|O_APPEND;
 431    else {
 432      fd = (*ss != '<') ? O_CREAT|O_WRONLY|O_TRUNC : O_RDONLY;
 433      if (!strcmp(ss, ">") && (TT.options&SH_NOCLOBBER)) {
 434        struct stat st;
 435
 436        // Not _just_ O_EXCL: > /dev/null allowed
 437        if (stat(sss, &st) || !S_ISREG(st.st_mode)) fd |= O_EXCL;
 438      }
 439    }
 440
 441    // Open the file
 442// TODO: /dev/fd/# /dev/{stdin,stdout,stderr} /dev/{tcp,udp}/host/port
 443    if (-1 == (fd = xcreate(sss, fd|WARN_ONLY, 777)) || hfd != dup2(fd, hfd)) {
 444      pp->exit = 1;
 445      s = 0;
 446
 447      goto flush;
 448    }
 449    if (fd != hfd) close(fd);
 450    rr[1] = hfd<<1;
 451    rdcount++;
 452
 453    // queue up a 2>&1 ?
 454    if (strchr(ss, '&')) {
 455      if (!(31&++rdcount)) rd = xrealloc(rd, (2*rdcount+66)*sizeof(int *));
 456      rr = rd+3+rdcount;
 457      rr[0] = 2;
 458      rr[1] = 1+(1<<1);
 459      rdcount++;
 460    }
 461  }
 462  if (rd) rd[2] = rdcount;
 463
 464// TODO: ok, now _use_ in_rd[in_rdcount] and rd[rdcount]. :)
 465
 466// TODO: handle ((math)) here
 467
 468// TODO use envlen
 469// TODO: check for functions
 470
 471  // Is this command a builtin that should run in this process?
 472  if ((tl = toy_find(*pp->arg.v))
 473    && (tl->flags & (TOYFLAG_NOFORK|TOYFLAG_MAYFORK)))
 474  {
 475    struct toy_context temp;
 476    sigjmp_buf rebound;
 477
 478    // This fakes lots of what toybox_main() does.
 479    memcpy(&temp, &toys, sizeof(struct toy_context));
 480    memset(&toys, 0, sizeof(struct toy_context));
 481
 482// TODO: redirect stdin/out
 483    if (!sigsetjmp(rebound, 1)) {
 484      toys.rebound = &rebound;
 485// must be null terminated
 486      toy_init(tl, pp->arg.v);
 487      tl->toy_main();
 488    }
 489    pp->exit = toys.exitval;
 490    if (toys.optargs != toys.argv+1) free(toys.optargs);
 491    if (toys.old_umask) umask(toys.old_umask);
 492    memcpy(&toys, &temp, sizeof(struct toy_context));
 493  } else {
 494    int pipe[2];
 495
 496    pipe[0] = 0;
 497    pipe[1] = 1;
 498// TODO: redirect and pipe
 499// TODO: redirecting stderr needs xpopen3() or rethink
 500    if (-1 == (pp->pid = xpopen_both(pp->arg.v, pipe)))
 501      perror_msg("%s: vfork", *pp->arg.v);
 502// TODO: don't close stdin/stdout!
 503    else pp->exit = xpclose_both(pp->pid, 0);
 504  }
 505
 506  s = 0;
 507flush:
 508  if (s) {
 509    syntax_err("bad %s", s);
 510    if (!pp->exit) pp->exit = 1;
 511  }
 512  for (j = 0; j<rdcount; j++) if (rd[4+2*j]>6) close(rd[4+2*j]>>1);
 513  if (rdcount) free(dlist_lpop((void *)rdlist));
 514
 515  return pp;
 516}
 517
 518// parse next word from command line. Returns end, or 0 if need continuation
 519// caller eats leading spaces
 520static char *parse_word(char *start)
 521{
 522  int i, j, quote = 0, q, qc = 0;
 523  char *end = start, *s;
 524
 525  // (( is a special quote at the start of a word
 526  if (strstart(&end, "((")) toybuf[quote++] = 255;
 527
 528  // find end of this word
 529  while (*end) {
 530    i = 0;
 531
 532    // barf if we're near overloading quote stack (nesting ridiculously deep)
 533    if (quote>4000) {
 534      syntax_err("tilt");
 535      return (void *)1;
 536    }
 537
 538    q = quote ? toybuf[quote-1] : 0;
 539    // Handle quote contexts
 540    if (q) {
 541
 542      // when waiting for parentheses, they nest
 543      if ((q == ')' || q == '\xff') && (*end == '(' || *end == ')')) {
 544        if (*end == '(') qc++;
 545        else if (qc) qc--;
 546        else if (q == '\xff') {
 547          // (( can end with )) or retroactively become two (( if we hit one )
 548          if (strstart(&end, "))")) quote--;
 549          else return start+1;
 550        }
 551        end++;
 552
 553      // end quote?
 554      } else if (*end == q) quote--, end++;
 555
 556      // single quote claims everything
 557      else if (q == '\'') end++;
 558      else i++;
 559
 560      // loop if we already handled a symbol
 561      if (!i) continue;
 562    } else {
 563      // Things that only matter when unquoted
 564
 565      if (isspace(*end)) break;
 566
 567      // Things we should only return at the _start_ of a word
 568
 569      // Redirections. 123<<file- parses as 2 args: "123<<" "file-".
 570      // Greedy matching: >&; becomes >& ; not > &;
 571      s = end + redir_prefix(end);
 572      j = anystart(s, (char *[]){"<<<", "<<-", "<<", "<&", "<>", "<", ">>",
 573        ">&", ">|", ">", 0});
 574      if (j) s += j;
 575
 576      // Control characters
 577      else s = end + anystart(end, (char *[]){";;&", ";;", ";&", ";", "||",
 578          "|&", "|", "&&", "&>>", "&>", "&", "(", ")", 0});
 579      if (s != end) return (end == start) ? s : end;
 580      i++;
 581    }
 582
 583    // Things the same unquoted or in most non-single-quote contexts
 584
 585    // start new quote context?
 586    if (strchr("\"'`", *end)) toybuf[quote++] = *end++;
 587    else if (q != '"' && (strstart(&end, "<(") || strstart(&end,">(")))
 588      toybuf[quote++]=')';
 589
 590    // backslash escapes
 591    else if (*end == '\\') {
 592      if (!end[1] || (end[1]=='\n' && !end[2])) return 0;
 593      end += 2;
 594    } else if (*end++ == '$') {
 595      if (-1 != (i = stridx("({[", *end))) {
 596        toybuf[quote++] = ")}]"[i];
 597        end++;
 598      }
 599    }
 600  }
 601
 602  return quote ? 0 : end;
 603}
 604
 605// if then fi for while until select done done case esac break continue return
 606
 607// Allocate more space for arg, and possibly terminator
 608void argxtend(struct sh_arg *arg)
 609{
 610  if (!(arg->c&31)) arg->v = xrealloc(arg->v, (33+arg->c)*sizeof(void *));
 611}
 612
 613// Pipeline segments
 614struct sh_pipeline {
 615  struct sh_pipeline *next, *prev;
 616  int count, here, type;
 617  struct sh_arg arg[1];
 618};
 619
 620// run a series of "command | command && command" with redirects.
 621int run_pipeline(struct sh_pipeline **pl, int *rd)
 622{
 623  struct sh_process *pp;
 624  int rc = 0;
 625
 626  for (;;) {
 627// TODO job control
 628    if (!(pp = run_command((*pl)->arg, &rd))) rc = 0;
 629    else {
 630//wait4(pp);
 631      llist_traverse(pp->delete, free);
 632      rc = pp->exit;
 633      free(pp);
 634    }
 635
 636    if ((*pl)->next && !(*pl)->next->type) *pl = (*pl)->next;
 637    else return rc;
 638  }
 639}
 640
 641
 642
 643// scratch space (state held between calls). Don't want to make it global yet
 644// because this could be reentrant.
 645struct sh_function {
 646  char *name;
 647  struct sh_pipeline *pipeline;
 648  struct double_list *expect;
 649// TODO: lifetime rules for arg? remember "shift" command.
 650  struct sh_arg *arg; // arguments to function call
 651  char *end;
 652};
 653
 654// Free one pipeline segment.
 655void free_pipeline(void *pipeline)
 656{
 657  struct sh_pipeline *pl = pipeline;
 658  int i, j;
 659
 660  if (pl) for (j=0; j<=pl->count; j++) {
 661    for (i = 0; i<=pl->arg->c; i++)  free(pl->arg[j].v[i]);
 662    free(pl->arg[j].v);
 663  }
 664  free(pl);
 665}
 666
 667// Return end of current block, or NULL if we weren't in block and fell off end.
 668struct sh_pipeline *block_end(struct sh_pipeline *pl)
 669{
 670  int i = 0;
 671
 672  while (pl) {
 673    if (pl->type == 1 || pl->type == 'f') i++;
 674    else if (pl->type == 3) if (--i<1) break;
 675    pl = pl->next;
 676  }
 677
 678  return 0;
 679}
 680
 681void free_function(struct sh_function *sp)
 682{
 683  llist_traverse(sp->pipeline, free_pipeline);
 684  llist_traverse(sp->expect, free);
 685  memset(sp, 0, sizeof(struct sh_function));
 686}
 687
 688// TODO this has to add to a namespace context. Functions within functions...
 689struct sh_pipeline *add_function(char *name, struct sh_pipeline *pl)
 690{
 691dprintf(2, "stub add_function");
 692
 693  return block_end(pl->next);
 694}
 695
 696// Add a line of shell script to a shell function. Returns 0 if finished,
 697// 1 to request another line of input (> prompt), -1 for syntax err
 698static int parse_line(char *line, struct sh_function *sp)
 699{
 700  char *start = line, *delete = 0, *end, *last = 0, *s, *ex, done = 0;
 701  struct sh_pipeline *pl = sp->pipeline ? sp->pipeline->prev : 0;
 702  struct sh_arg *arg = 0;
 703  long i;
 704
 705  // Resume appending to last statement?
 706  if (pl) {
 707    arg = pl->arg;
 708
 709    // Extend/resume quoted block
 710    if (arg->c<0) {
 711      delete = start = xmprintf("%s%s", arg->v[arg->c = (-arg->c)-1], start);
 712      free(arg->v[arg->c]);
 713      arg->v[arg->c] = 0;
 714
 715    // is a HERE document in progress?
 716    } else if (pl->count != pl->here) {
 717      arg += 1+pl->here;
 718
 719      argxtend(arg);
 720      if (strcmp(line, arg->v[arg->c])) {
 721        // Add this line
 722        arg->v[arg->c+1] = arg->v[arg->c];
 723        arg->v[arg->c++] = xstrdup(line);
 724      // EOF hit, end HERE document
 725      } else {
 726        arg->v[arg->c] = 0;
 727        pl->here++;
 728      }
 729      start = 0;
 730
 731    // Nope, new segment
 732    } else pl = 0;
 733  }
 734
 735  // Parse words, assemble argv[] pipelines, check flow control and HERE docs
 736  if (start) for (;;) {
 737    ex = sp->expect ? sp->expect->prev->data : 0;
 738
 739    // Look for << HERE redirections in completed pipeline segment
 740    if (pl && pl->count == -1) {
 741      pl->count = 0;
 742      arg = pl->arg;
 743
 744      // find arguments of the form [{n}]<<[-] with another one after it
 745      for (i = 0; i<arg->c; i++) {
 746        s = arg->v[i] + redir_prefix(arg->v[i]);
 747        if (strcmp(s, "<<") && strcmp(s, "<<-") && strcmp(s, "<<<")) continue;
 748        if (i+1 == arg->c) goto flush;
 749
 750        // Add another arg[] to the pipeline segment (removing/readding to list
 751        // because realloc can move pointer)
 752        dlist_lpop(&sp->pipeline);
 753        pl = xrealloc(pl, sizeof(*pl) + ++pl->count*sizeof(struct sh_arg));
 754        dlist_add_nomalloc((void *)&sp->pipeline, (void *)pl);
 755
 756        // queue up HERE EOF so input loop asks for more lines.
 757        arg[pl->count].v = xzalloc(2*sizeof(void *));
 758        *arg[pl->count].v = arg->v[++i];
 759        arg[pl->count].c = -(s[2] == '<'); // note <<< as c = -1
 760      }
 761      pl = 0;
 762    }
 763    if (done) break;
 764    s = 0;
 765
 766    // skip leading whitespace/comment here to know where next word starts
 767    for (;;) {
 768      if (isspace(*start)) ++start;
 769      else if (*start=='#') while (*start && *start != '\n') ++start;
 770      else break;
 771    }
 772
 773    // Parse next word and detect overflow (too many nested quotes).
 774    if ((end = parse_word(start)) == (void *)1)
 775      goto flush;
 776
 777    // Is this a new pipeline segment?
 778    if (!pl) {
 779      pl = xzalloc(sizeof(struct sh_pipeline));
 780      arg = pl->arg;
 781      dlist_add_nomalloc((void *)&sp->pipeline, (void *)pl);
 782    }
 783    argxtend(arg);
 784
 785    // Do we need to request another line to finish word (find ending quote)?
 786    if (!end) {
 787      // Save unparsed bit of this line, we'll need to re-parse it.
 788      arg->v[arg->c] = xstrndup(start, strlen(start));
 789      arg->c = -(arg->c+1);
 790      free(delete);
 791
 792      return 1;
 793    }
 794
 795    // Ok, we have a word. What does it _mean_?
 796
 797    // Did we hit end of line or ) outside a function declaration?
 798    // ) is only saved at start of a statement, ends current statement
 799    if (end == start || (arg->c && *start == ')' && pl->type!='f')) {
 800      arg->v[arg->c] = 0;
 801
 802      if (pl->type == 'f' && arg->c<3) {
 803        s = "function()";
 804        goto flush;
 805      }
 806
 807      // "for" on its own line is an error.
 808      if (arg->c == 1 && ex && !memcmp(ex, "do\0A", 4)) {
 809        s = "newline";
 810        goto flush;
 811      }
 812
 813      // don't save blank pipeline segments
 814      if (!arg->c) free_pipeline(dlist_lpop(&sp->pipeline));
 815
 816      // stop at EOL, else continue with new pipeline segment for )
 817      if (end == start) done++;
 818      pl->count = -1;
 819      last = 0;
 820
 821      continue;
 822    }
 823
 824    // Save argument (strdup) and check for flow control
 825    s = arg->v[arg->c] = xstrndup(start, end-start);
 826    start = end;
 827    if (strchr(";|&", *s)) {
 828
 829      // flow control without a statement is an error
 830      if (!arg->c) goto flush;
 831
 832      // treat ; as newline so we don't have to check both elsewhere.
 833      if (!strcmp(s, ";")) {
 834        arg->v[arg->c] = 0;
 835        free(s);
 836        s = 0;
 837      }
 838      last = s;
 839      pl->count = -1;
 840
 841      continue;
 842    } else arg->v[++arg->c] = 0;
 843
 844    // is a function() in progress?
 845    if (arg->c>1 && !strcmp(s, "(")) pl->type = 'f';
 846    if (pl->type=='f') {
 847      if (arg->c == 2 && strcmp(s, "(")) goto flush;
 848      if (arg->c == 3) {
 849        if (strcmp(s, ")")) goto flush;
 850
 851        // end function segment, expect function body
 852        pl->count = -1;
 853        last = 0;
 854        dlist_add(&sp->expect, "}");
 855        dlist_add(&sp->expect, 0);
 856        dlist_add(&sp->expect, "{");
 857
 858        continue;
 859      }
 860
 861    // a for/select must have at least one additional argument on same line
 862    } else if (ex && !memcmp(ex, "do\0A", 4)) {
 863
 864      // Sanity check and break the segment
 865      if (strncmp(s, "((", 2) && strchr(s, '=')) goto flush;
 866      pl->count = -1;
 867      sp->expect->prev->data = "do\0C";
 868
 869      continue;
 870
 871    // flow control is the first word of a pipeline segment
 872    } else if (arg->c>1) continue;
 873
 874    // Do we expect something that _must_ come next? (no multiple statements)
 875    if (ex) {
 876      // When waiting for { it must be next symbol, but can be on a new line.
 877      if (!strcmp(ex, "{")) {
 878        if (strcmp(s, "{")) goto flush;
 879        free(arg->v[--arg->c]);  // don't save the {, function starts the block
 880        free(dlist_lpop(&sp->expect));
 881
 882        continue;
 883
 884      // The "test" part of for/select loops can have (at most) one "in" line,
 885      // for {((;;))|name [in...]} do
 886      } else if (!memcmp(ex, "do\0C", 4)) {
 887        if (strcmp(s, "do")) {
 888          // can only have one "in" line between for/do, but not with for(())
 889          if (!pl->prev->type) goto flush;
 890          if (!strncmp(pl->prev->arg->v[1], "((", 2)) goto flush;
 891          else if (strcmp(s, "in")) goto flush;
 892
 893          continue;
 894        }
 895      }
 896    }
 897
 898    // start of a new block?
 899
 900    // for/select requires variable name on same line, can't break segment yet
 901    if (!strcmp(s, "for") || !strcmp(s, "select")) {
 902      if (!pl->type) pl->type = 1;
 903      dlist_add(&sp->expect, "do\0A");
 904
 905      continue;
 906    }
 907
 908    end = 0;
 909    if (!strcmp(s, "if")) end = "then";
 910    else if (!strcmp(s, "while") || !strcmp(s, "until")) end = "do\0B";
 911    else if (!strcmp(s, "case")) end = "esac";
 912    else if (!strcmp(s, "{")) end = "}";
 913    else if (!strcmp(s, "[[")) end = "]]";
 914    else if (!strcmp(s, "(")) end = ")";
 915
 916    // Expecting NULL means a statement: I.E. any otherwise unrecognized word
 917    else if (sp->expect && !ex) {
 918      free(dlist_lpop(&sp->expect));
 919      continue;
 920    } else if (!ex) goto check;
 921
 922    // Did we start a new statement?
 923    if (end) {
 924      pl->type = 1;
 925
 926      // Only innermost statement needed in { { { echo ;} ;} ;} and such
 927      if (sp->expect && !sp->expect->prev->data) free(dlist_lpop(&sp->expect));
 928
 929    // If we got here we expect a specific word to end this block: is this it?
 930    } else if (!strcmp(s, ex)) {
 931      // can't "if | then" or "while && do", only ; & or newline works
 932      if (last && (strcmp(ex, "then") || strcmp(last, "&"))) {
 933        s = end;
 934        goto flush;
 935      }
 936
 937      free(dlist_lpop(&sp->expect));
 938      pl->type = anystr(s, (char *[]){"fi", "done", "esac", "}", "]]", ")", 0})
 939        ? 3 : 2;
 940
 941      // if it's a multipart block, what comes next?
 942      if (!strcmp(s, "do")) end = "done";
 943      else if (!strcmp(s, "then")) end = "fi\0A";
 944
 945    // fi could have elif, which queues a then.
 946    } else if (!strcmp(ex, "fi")) {
 947      if (!strcmp(s, "elif")) {
 948        free(dlist_lpop(&sp->expect));
 949        end = "then";
 950      // catch duplicate else while we're here
 951      } else if (!strcmp(s, "else")) {
 952        if (ex[3] != 'A') {
 953          s = "2 else";
 954          goto flush;
 955        }
 956        free(dlist_lpop(&sp->expect));
 957        end = "fi\0B";
 958      }
 959    }
 960
 961    // Do we need to queue up the next thing to expect?
 962    if (end) {
 963      if (!pl->type) pl->type = 2;
 964      dlist_add(&sp->expect, end);
 965      dlist_add(&sp->expect, 0);    // they're all preceded by a statement
 966      pl->count = -1;
 967    }
 968
 969check:
 970    // syntax error check: these can't be the first word in an unexpected place
 971    if (!pl->type && anystr(s, (char *[]){"then", "do", "esac", "}", "]]", ")",
 972        "done", "fi", "elif", "else", 0})) goto flush;
 973  }
 974  free(delete);
 975
 976  // advance past <<< arguments (stored as here documents, but no new input)
 977  pl = sp->pipeline->prev;
 978  while (pl->count<pl->here && pl->arg[pl->count].c<0)
 979    pl->arg[pl->count++].c = 0;
 980
 981  // return if HERE document pending or more flow control needed to complete
 982  if (sp->expect) return 1;
 983  if (sp->pipeline && pl->count != pl->here) return 1;
 984  dlist_terminate(sp->pipeline);
 985
 986  // Don't need more input, can start executing.
 987
 988  return 0;
 989
 990flush:
 991  if (s) syntax_err("bad %s", s);
 992  free_function(sp);
 993
 994  return 0-!!s;
 995}
 996
 997static void dump_state(struct sh_function *sp)
 998{
 999  struct sh_pipeline *pl;
1000  int q = 0;
1001  long i;
1002
1003  if (sp->expect) {
1004    struct double_list *dl;
1005
1006    for (dl = sp->expect; dl; dl = (dl->next == sp->expect) ? 0 : dl->next)
1007      dprintf(2, "expecting %s\n", dl->data);
1008    if (sp->pipeline)
1009      dprintf(2, "pipeline count=%d here=%d\n", sp->pipeline->prev->count,
1010        sp->pipeline->prev->here);
1011  }
1012
1013  for (pl = sp->pipeline; pl ; pl = (pl->next == sp->pipeline) ? 0 : pl->next) {
1014    for (i = 0; i<pl->arg->c; i++)
1015      printf("arg[%d][%ld]=%s\n", q, i, pl->arg->v[i]);
1016    printf("type=%d term[%d]=%s\n", pl->type, q++, pl->arg->v[pl->arg->c]);
1017  }
1018}
1019
1020/* Flow control statements:
1021
1022  if/then/elif/else/fi, for select while until/do/done, case/esac,
1023  {/}, [[/]], (/), function assignment
1024*/
1025
1026
1027
1028// run a shell function, handling flow control statements
1029static void run_function(struct sh_function *sp)
1030{
1031  struct sh_pipeline *pl = sp->pipeline, *end;
1032  struct blockstack {
1033    struct blockstack *next;
1034    struct sh_pipeline *start, *end;
1035    int run, loop, *redir;
1036
1037    struct sh_arg farg;          // for/select arg stack
1038    struct string_list *fdelete; // farg's cleanup list
1039    char *fvar;                  // for/select's iteration variable name
1040  } *blk = 0, *new;
1041  long i;
1042
1043  // iterate through the commands
1044  while (pl) {
1045    char *s = *pl->arg->v, *ss = pl->arg->v[1];
1046//dprintf(2, "s=%s %s %d %s %d\n", s, ss, pl->type, blk ? blk->start->arg->v[0] : "X", blk ? blk->run : 0);
1047    // Normal executable statement?
1048    if (!pl->type) {
1049// TODO: break & is supported? Seriously? Also break > potato
1050// TODO: break multiple aguments
1051      if (!strcmp(s, "break") || !strcmp(s, "continue")) {
1052
1053        // How many layers to peel off?
1054        i = ss ? atol(ss) : 0;
1055        if (i<1) i = 1;
1056        if (!blk || pl->arg->c>2 || ss[strspn(ss, "0123456789")]) {
1057          syntax_err("bad %s", s);
1058          break;
1059        }
1060        i = atol(ss);
1061        if (!i) i++;
1062        while (i && blk) {
1063          if (--i && *s == 'c') {
1064            pl = blk->start;
1065            break;
1066          }
1067          pl = blk->end;
1068          llist_traverse(blk->fdelete, free);
1069          free(llist_pop(&blk));
1070        }
1071        pl = pl->next;
1072
1073        continue;
1074      }
1075
1076// inherit redirects?
1077// returns last statement of pipeline
1078      if (!blk) toys.exitval = run_pipeline(&pl, 0);
1079      else if (blk->run) toys.exitval = run_pipeline(&pl, blk->redir);
1080      else while (pl->next && !pl->next->type) pl = pl->next;
1081
1082    // Starting a new block?
1083    } else if (pl->type == 1) {
1084
1085      // are we entering this block (rather than looping back to it)?
1086      if (!blk || blk->start != pl) {
1087
1088        // If it's a nested block we're not running, skip ahead.
1089        end = block_end(pl->next);
1090        if (blk && !blk->run) {
1091          pl = end;
1092          if (pl) pl = pl->next;
1093          continue;
1094        }
1095
1096        // It's a new block we're running, save context and add it to the stack.
1097        new = xzalloc(sizeof(*blk));
1098        new->next = blk;
1099        blk = new;
1100        blk->start = pl;
1101        blk->end = end;
1102        blk->run = 1;
1103// TODO perform block end redirects to blk->redir
1104      }
1105
1106      // What flow control statement is this?
1107
1108      // if/then/elif/else/fi, while until/do/done - no special handling needed
1109
1110      // for select/do/done
1111      if (!strcmp(s, "for") || !strcmp(s, "select")) {
1112        if (blk->loop);
1113        else if (!strncmp(blk->fvar = ss, "((", 2)) {
1114          blk->loop = 1;
1115dprintf(2, "TODO skipped init for((;;)), need math parser\n");
1116        } else {
1117
1118          // populate blk->farg with expanded arguments
1119          if (!pl->next->type) {
1120            for (i = 1; i<pl->next->arg->c; i++)
1121              expand_arg(&blk->farg, pl->next->arg->v[i], 0, &blk->fdelete);
1122          } else expand_arg(&blk->farg, "\"$@\"", 0, &blk->fdelete);
1123        }
1124        pl = pl->next;
1125      }
1126
1127/* TODO
1128case/esac
1129{/}
1130[[/]]
1131(/)
1132((/))
1133function/}
1134*/
1135
1136    // gearshift from block start to block body
1137    } else if (pl->type == 2) {
1138
1139      // Handle if statement
1140      if (!strcmp(s, "then")) blk->run = blk->run && !toys.exitval;
1141      else if (!strcmp(s, "else") || !strcmp(s, "elif")) blk->run = !blk->run;
1142      else if (!strcmp(s, "do")) {
1143        ss = *blk->start->arg->v;
1144        if (!strcmp(ss, "while")) blk->run = blk->run && !toys.exitval;
1145        else if (!strcmp(ss, "until")) blk->run = blk->run && toys.exitval;
1146        else if (blk->loop >= blk->farg.c) {
1147          blk->run = 0;
1148          pl = block_end(pl);
1149          continue;
1150        } else if (!strncmp(blk->fvar, "((", 2)) {
1151dprintf(2, "TODO skipped running for((;;)), need math parser\n");
1152        } else setvar(xmprintf("%s=%s", blk->fvar, blk->farg.v[blk->loop++]),
1153          TAKE_MEM);
1154      }
1155
1156    // end of block
1157    } else if (pl->type == 3) {
1158
1159      // repeating block?
1160      if (blk->run && !strcmp(s, "done")) {
1161        pl = blk->start;
1162        continue;
1163      }
1164
1165      // if ending a block, pop stack.
1166      llist_traverse(blk->fdelete, free);
1167      free(llist_pop(&blk));
1168
1169// TODO unwind redirects (cleanup blk->redir)
1170
1171    } else if (pl->type == 'f') pl = add_function(s, pl);
1172
1173    pl = pl->next;
1174  }
1175
1176  // Cleanup from syntax_err();
1177  while (blk) {
1178    llist_traverse(blk->fdelete, free);
1179    free(llist_pop(&blk));
1180  }
1181
1182  return;
1183}
1184
1185void subshell_imports(void)
1186{
1187/*
1188  // TODO cull local variables because 'env "()=42" env | grep 42' works.
1189
1190  // vfork() means subshells have to export and then re-import locals/functions
1191  sprintf(toybuf, "(%d#%d)", getpid(), getppid());
1192  if ((s = getenv(toybuf))) {
1193    char *from, *to, *ss;
1194
1195    unsetenv(toybuf);
1196    ss = s;
1197
1198    // Loop through packing \\ until \0
1199    for (from = to = s; *from; from++, to++) {
1200      *to = *from;
1201      if (*from != '\\') continue;
1202      if (from[1] == '\\' || from[1] == '0') from++;
1203      if (from[1] != '0') continue;
1204      *to = 0;
1205
1206      // save chunk
1207      for (ss = s; ss<to; ss++) {
1208        if (*ss == '=') {
1209          // first char of name is variable type ala declare
1210          if (s+1<ss && strchr("aAilnru", *s)) {
1211            setvar(ss, *s);
1212
1213            break;
1214          }
1215        } else if (!strncmp(ss, "(){", 3)) {
1216          FILE *ff = fmemopen(s, to-s, "r");
1217
1218          while ((new = xgetline(ff, 0))) {
1219            if ((prompt = parse_line(new, &scratch))<0) break;
1220            free(new);
1221          }
1222          if (!prompt) {
1223            add_function(s, scratch.pipeline);
1224            free_function(&scratch);
1225            break;
1226          }
1227          fclose(ff);
1228        } else if (!isspace(*s) && !ispunct(*s)) continue;
1229
1230        error_exit("bad locals");
1231      }
1232      s = from+1;
1233    }
1234  }
1235*/
1236}
1237
1238void sh_main(void)
1239{
1240  FILE *f;
1241  char *new;
1242  struct sh_function scratch;
1243  int prompt = 0;
1244
1245  // Set up signal handlers and grab control of this tty.
1246
1247  // Read environment for exports from parent shell
1248  subshell_imports();
1249
1250  memset(&scratch, 0, sizeof(scratch));
1251  if (TT.command) f = fmemopen(TT.command, strlen(TT.command), "r");
1252  else if (*toys.optargs) f = xfopen(*toys.optargs, "r");
1253  else {
1254    f = stdin;
1255    if (isatty(0)) toys.optflags |= FLAG_i;
1256  }
1257
1258  for (;;) {
1259
1260    // Prompt and read line
1261    if (f == stdin) {
1262      char *s = getenv(prompt ? "PS2" : "PS1");
1263
1264      if (!s) s = prompt ? "> " : (getpid() ? "\\$ " : "# ");
1265      do_prompt(s);
1266    } else TT.lineno++;
1267    if (!(new = xgetline(f ? f : stdin, 0))) break;
1268
1269// TODO if (!isspace(*new)) add_to_history(line);
1270
1271    // returns 0 if line consumed, command if it needs more data
1272    prompt = parse_line(new, &scratch);
1273if (0) dump_state(&scratch);
1274    if (prompt != 1) {
1275// TODO: ./blah.sh one two three: put one two three in scratch.arg
1276      if (!prompt) run_function(&scratch);
1277      free_function(&scratch);
1278      prompt = 0;
1279    }
1280    free(new);
1281  }
1282
1283  if (prompt) error_exit("%ld:unfinished line"+4*!TT.lineno, TT.lineno);
1284  toys.exitval = f && ferror(f);
1285}
1286