Goto sanos source index

//
// sh.c
//
// Shell
//
// Copyright (C) 2011 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 
// 1. Redistributions of source code must retain the above copyright 
//    notice, this list of conditions and the following disclaimer.  
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.  
// 3. Neither the name of the project nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
// SUCH DAMAGE.
// 

#include "sh.h"

static int exec_command(struct job *parent, char *cmdline) {
  struct inputfile *source = NULL;
  struct stkmark mark;
  struct parser parser;
  union node *node;

  pushstr(&source, cmdline);
  pushstkmark(NULL, &mark);
  parse_init(&parser, 0, source, &mark);

  while (!parent->shell->done && !(parser.tok & T_EOF)) {
    node = parse(&parser);
    if (!node) {
      if (parent->shell->debug) printf("line %d: tok=%d\n", source->lineno, parser.tok);
      break;
    }
    if (parent->shell->debug) print_node(node, stdout, 0);
    interp(parent, node);
  }
  
  popstkmark(&mark);

  return 0;
}

static void check_terminations(struct shell *shell) {
  struct job *job = shell->jobs;
  while (job) {
    struct job *next = job->next;
    if (job->handle != -1) {
      int rc = waitone(job->handle, 0);
      if (rc >= 0) {
        if (shell->debug) {
          fprintf(stderr, "Process %d terminated with exit code %d\n", job->handle, rc);
        }
        remove_job(job);
      }
    }
    job = next;
  }
}

static int run_shell(struct shell *shell) {
  char curdir[MAXPATH];
  char cmdline[1024];
  char *prompt = get_property(osconfig(), "shell", "prompt", "%s$ ");
  int rc;

  while (!shell->done) {
    check_terminations(shell);
    printf(prompt, getcwd(curdir, sizeof(curdir)));
    fflush(stdout);
    rc = readline(cmdline, sizeof(cmdline));
    if (rc < 0) {
      if (errno != EINTR) break;
    } else {
      fflush(stdout);
      exec_command(shell->top, cmdline);
    }
  }
  return 0;
}

int run_script(struct shell *shell) {
  char *scriptname = shell->top->args.first->value;
  int fin;
  struct inputfile *source = NULL;
  struct stkmark mark;
  struct parser parser;
  union node *node;

  fin = open(scriptname, 0);
  if (fin < 0) {
    perror(scriptname);
    return 1;
  }

  pushfile(&source, fin);
  pushstkmark(NULL, &mark);
  parse_init(&parser, 0, source, &mark);

  while (!shell->done && !(parser.tok & T_EOF)) {
    check_terminations(shell);
    node = parse(&parser);
    if (parser.errors) break;
    if (!node) continue;
    if (shell->debug) print_node(node, stdout, 0);
    interp(shell->top, node);
  }

  popstkmark(&mark);
  popallfiles(&parser.source);

  return 0;
}

int script_invoke(char *argv0) {
  char *cmd = argv0;
  char *p = argv0;
  while (*p) {
    if (*p == PS1 || *p == PS2) cmd = p + 1;
    p++;
  }
  return strcmp(cmd, "sh") != 0 && strcmp(cmd, "sh.exe") != 0;
}

int main(int argc, char *argv[], char *envp[]) {
  struct shell shell;
  int rc;

  init_shell(&shell, argc, argv, envp);

  if (script_invoke(argv[0])) {
    rc = run_script(&shell);
  } else if (argc > 1) {
    char *cmdline = gettib()->proc->cmdline;
    while (*cmdline && *cmdline != ' ') cmdline++;
    rc = exec_command(shell.top, cmdline);
    if (rc == 0) shell.top->exitcode = shell.lastrc;
  } else {
    rc = run_shell(&shell);
  }

  if (rc == 0) rc = shell.top->exitcode;
  clear_shell(&shell);

  return rc;
}