Logo Search packages:      
Sourcecode: fdclone version File versions  Download package

posixsh.c

/*
 *    posixsh.c
 *
 *    XSH command for POSIX
 */

#ifdef      FD
#include "fd.h"
#else
#include "headers.h"
#include "depend.h"
#include "printf.h"
#include "kctype.h"
#include "string.h"
#include "malloc.h"
#endif

#include "sysemu.h"
#include "unixemu.h"

#if   !MSDOS
#include "time.h"
#endif
#ifdef      DEP_ORIGSHELL
#include "system.h"
#endif
#if   defined (DEP_ORIGSHELL) && !defined (MINIMUMSHELL)
#include "posixsh.h"
#endif
#ifdef      FD
#include "term.h"
#endif
#ifdef      DEP_PTY
#include "termemu.h"
#endif

#define     ALIASDELIMIT            "();&|<>"
#define     getconstvar(s)          (getshellvar(s, strsize(s)))
#define     ER_COMNOFOUND           1
#define     ER_NOTFOUND       2
#define     ER_NOTIDENT       4
#define     ER_BADOPTIONS           13
#define     ER_NUMOUTRANGE          18
#define     ER_NOTALIAS       20
#define     ER_MISSARG        21
#define     ER_NOSUCHJOB            22
#define     ER_TERMINATED           23
#define     ER_UNKNOWNSIG           26

#if   !MSDOS
typedef struct _mailpath_t {
      char *path;
      char *msg;
      time_t mtime;
} mailpath_t;
#endif

#if   defined (DEP_ORIGSHELL) && !defined (MINIMUMSHELL)

extern int setenv2 __P_((CONST char *, CONST char *, int));
#ifdef      DEP_PTY
extern VOID sendparent __P_((int, ...));
#endif

#ifndef     FD
extern int ttyio;
extern XFILE *ttyout;
#endif

#ifndef     NOJOB
static CONST char *NEAR headstree __P_((syntaxtree *));
#endif
#ifndef     NOALIAS
static int NEAR searchalias __P_((CONST char *, int));
static shaliastable *NEAR duplalias __P_((shaliastable *));
static int cmpalias __P_((CONST VOID_P, CONST VOID_P));
#endif
static int NEAR _evalexpression __P_((CONST char *, int, long *));
static int NEAR evalexpression __P_((CONST char *, int, long *, int));
#if   !MSDOS
static VOID NEAR addmailpath __P_((CONST char *, char *, time_t));
#endif
static int NEAR testsub1 __P_((int, CONST char *, int *));
static int NEAR testsub2 __P_((int, char *CONST *, int *));
static int NEAR testsub3 __P_((int, char *CONST *, int *, int));

#ifndef     NOJOB
jobtable *joblist = NULL;
int maxjobs = 0;
#endif
#if   !MSDOS
int mailcheck = 0;
#endif
#ifndef     NOALIAS
shaliastable *shellalias = NULL;
#endif
#ifndef     NOPOSIXUTIL
int posixoptind = 0;
#endif

#if   !MSDOS
static mailpath_t *mailpathlist = NULL;
static int maxmailpath = 0;
#endif


#ifndef     NOJOB
int gettermio(pgrp, job)
p_id_t pgrp;
int job;
{
      int ret;
      sigmask_t mask, omask;

      if (ttypgrp < (p_id_t)0 || pgrp < (p_id_t)0 || pgrp == ttypgrp)
            return(0);
      else if (!job) {
            ttypgrp = pgrp;
            return(0);
      }

      Xsigemptyset(mask);
#ifdef      SIGTSTP
      Xsigaddset(mask, SIGTSTP);
#endif
#ifdef      SIGCHLD
      Xsigaddset(mask, SIGCHLD);
#endif
#ifdef      SIGTTIN
      Xsigaddset(mask, SIGTTIN);
#endif
#ifdef      SIGTTOU
      Xsigaddset(mask, SIGTTOU);
#endif
      Xsigblock(omask, mask);

#ifdef      JOBVERBOSE
      fprintf2(ttyout, "gettermio: %id: %id -> %id", mypid, ttypgrp, pgrp);
      VOID_C fputnl(ttyout);
#endif      /* JOBVERBOSE */
      if ((ret = settcpgrp(ttyio, pgrp)) >= 0) ttypgrp = pgrp;
      Xsigsetmask(omask);

      return(ret);
}

static CONST char *NEAR headstree(trp)
syntaxtree *trp;
{
      int id;

      if (!trp) return(NULL);
      if (trp -> flags & ST_NODE) return("{");
      if (!(trp -> comm)) return(NULL);
      if (!isstatement(trp -> comm)) return((trp -> comm) -> argv[0]);

      id = (trp -> comm) -> id;
      if (id != SM_STATEMENT) return(NULL);
      trp = statementbody(trp);
      if (!trp || !(trp -> comm)) return(NULL);
      id = (trp -> comm) -> id;
      if (id == SM_CHILD || id == SM_STATEMENT) return(NULL);

      return(statementlist[id - 1].ident);
}

VOID dispjob(n, fp)
int n;
XFILE *fp;
{
      int i, sig;

      if (n < 0 || n >= maxjobs || !(joblist[n].pids)) return;
      i = joblist[n].npipe;
      fprintf2(fp, "[%d]%c %id ",
            n + 1, (n == lastjob) ? '+' : ((n == prevjob) ? '-' : ' '),
            joblist[n].pids[i]);
      sig = joblist[n].stats[i];

      if (sig <= 0)
            fprintf2(fp, "%-28.28s", (sig) ? "Done" : "Running");
      else {
            if (sig >= 128) sig -= 128;
            dispsignal(sig, 28, fp);
      }
      if (joblist[n].trp) {
            if (!isopbg(joblist[n].trp) && !isopnown(joblist[n].trp)
            && !isoppipe(joblist[n].trp))
                  joblist[n].trp -> type = OP_NONE;
            printstree(joblist[n].trp, -1, fp);
      }
      VOID_C fputnl(fp);
}

int searchjob(pid, np)
p_id_t pid;
int *np;
{
      int i, j;

      for (i = 0; i < maxjobs; i++) {
            if (!(joblist[i].pids)) continue;
            for (j = 0; j <= joblist[i].npipe; j++) {
                  if (joblist[i].pids[j] != pid) continue;
                  if (np) *np = j;
                  return(i);
            }
      }

      return(-1);
}

int getjob(s)
CONST char *s;
{
      CONST char *cp;
      int i, j;

      if (!jobok) return(-1);
      if (!s) i = lastjob;
      else {
            if (s[0] != '%') return(-1);
            if (!s[1] || ((s[1] == '%' || s[1] == '+') && !s[2]))
                  i = lastjob;
            else if (s[1] == '-' && !s[2]) i = prevjob;
            else if ((i = isnumeric(&(s[1]))) >= 0) i--;
            else {
                  j = strlen(&(s[1]));
                  for (i = 0; i < maxjobs; i++) {
                        if (!(joblist[i].pids) || !(joblist[i].trp)
                        || !(cp = headstree(joblist[i].trp)))
                              continue;
                        if (!strnpathcmp(&(s[1]), cp, j)) break;
                  }
            }
      }
      if (i < 0 || i >= maxjobs || !joblist || !(joblist[i].pids))
            return(-1);
      j = joblist[i].npipe;
      if (joblist[i].stats[j] < 0 || joblist[i].stats[j] >= 128) return(-2);

      return(i);
}

int stackjob(pid, sig, trp)
p_id_t pid;
int sig;
syntaxtree *trp;
{
      int i, j, n;

#ifdef      FAKEUNINIT
      j = 0;      /* fake for -Wuninitialized */
#endif
      if (!joblist) {
            joblist = (jobtable *)malloc2(BUFUNIT * sizeof(jobtable));
            maxjobs = BUFUNIT;
            i = 0;
            for (n = 0; n < maxjobs; n++) joblist[n].pids = NULL;
      }
      else {
            n = -1;
            for (i = 0; i < maxjobs; i++) {
                  if (!(joblist[i].pids)) {
                        if (n < 0) n = i;
                        continue;
                  }
                  for (j = 0; j <= joblist[i].npipe; j++)
                        if (joblist[i].pids[j] == pid) break;
                  if (j <= joblist[i].npipe) break;
                  else if (joblist[i].pids[0] == childpgrp) {
                        j = joblist[i].npipe + 1;
                        break;
                  }
            }
            if (i < maxjobs) /*EMPTY*/;
            else if (n >= 0) i = n;
            else {
                  joblist = (jobtable *)realloc2(joblist,
                        (maxjobs + BUFUNIT) * sizeof(jobtable));
                  maxjobs += BUFUNIT;
                  for (n = i; n < maxjobs; n++) joblist[n].pids = NULL;
            }
      }

      if (!(joblist[i].pids)) {
            joblist[i].pids = (p_id_t *)malloc2(BUFUNIT * sizeof(p_id_t));
            joblist[i].stats = (int *)malloc2(BUFUNIT * sizeof(int));
            joblist[i].npipe = 0;
            joblist[i].trp = NULL;
            joblist[i].tty = NULL;
# ifdef     USESGTTY
            joblist[i].ttyflag = NULL;
# endif
            j = 0;
      }
      else if (j > joblist[i].npipe) {
            if (!(j % BUFUNIT)) {
                  joblist[i].pids = (p_id_t *)realloc2(joblist[i].pids,
                        (j + BUFUNIT) * sizeof(p_id_t));
                  joblist[i].stats = (int *)realloc2(joblist[i].stats,
                        (j + BUFUNIT) * sizeof(int));
            }
            joblist[i].npipe = j;
      }

      joblist[i].pids[j] = pid;
      joblist[i].stats[j] = sig;
      if (!j && !(joblist[i].trp) && trp) {
            joblist[i].trp = duplstree(trp, NULL, 0L);
            if (!isoppipe(joblist[i].trp) && joblist[i].trp -> next) {
                  freestree(joblist[i].trp -> next);
                  joblist[i].trp -> next = NULL;
            }
      }

#ifdef      JOBVERBOSE
      fprintf2(ttyout, "stackjob: %id: %id, %d:", mypid, pid, i);
      for (j = 0; j <= joblist[i].npipe; j++)
            fprintf2(ttyout, "%id ", joblist[i].pids[j]);
      VOID_C fputnl(ttyout);
#endif      /* JOBVERBOSE */

      return(i);
}

int stoppedjob(pid)
p_id_t pid;
{
      int i, j, sig;

      if (stopped) return(1);
      if ((i = searchjob(pid, &j)) >= 0) {
            for (; j <= joblist[i].npipe; j++) {
                  sig = joblist[i].stats[j];
                  if (sig > 0 && sig < 128) return(1);
                  else if (!sig) return(0);
            }
      }

      return(-1);
}

VOID checkjob(fp)
XFILE *fp;
{
      int i, j;

      while (waitjob(-1, NULL, WNOHANG | WUNTRACED) > 0);
      if (fp) for (i = 0; i < maxjobs; i++) {
            if (!(joblist[i].pids)) continue;
            j = joblist[i].npipe;
            if (joblist[i].stats[j] >= 0 && joblist[i].stats[j] < 128)
                  continue;

            if (joblist[i].trp
            && (isopbg(joblist[i].trp) || isopnown(joblist[i].trp)))
                  joblist[i].trp -> type = OP_NONE;
            if (jobok && interactive && !nottyout) dispjob(i, fp);
            free2(joblist[i].pids);
            free2(joblist[i].stats);
            if (joblist[i].trp) {
                  freestree(joblist[i].trp);
                  free2(joblist[i].trp);
            }
            free2(joblist[i].tty);
# ifdef     USESGTTY
            free2(joblist[i].ttyflag);
# endif
            joblist[i].pids = NULL;
      }
}

VOID killjob(VOID_A)
{
      int i, j;

      for (i = 0; i < maxjobs; i++) {
            if (!(joblist[i].pids)) continue;
            j = joblist[i].stats[joblist[i].npipe];
            if (j < 0 || j >= 128) continue;
            Xkillpg(joblist[i].pids[0], SIGHUP);
            if (j > 0) Xkillpg(joblist[i].pids[0], SIGCONT);
      }
}
#endif      /* !NOJOB */

#ifndef     NOALIAS
static int NEAR searchalias(ident, len)
CONST char *ident;
int len;
{
      int i;

      if (len < 0) len = strlen(ident);
      for (i = 0; shellalias[i].ident; i++)
            if (!strncommcmp(ident, shellalias[i].ident, len)
            && !(shellalias[i].ident[len]))
                  break;

      return(i);
}

int addalias(ident, comm)
char *ident, *comm;
{
      int i;

      i = searchalias(ident, -1);
      if (shellalias[i].ident) {
            free2(shellalias[i].ident);
            free2(shellalias[i].comm);
      }
      else {
            shellalias = (shaliastable *)realloc2(shellalias,
                  (i + 2) * sizeof(shaliastable));
            shellalias[i + 1].ident = NULL;
      }

      shellalias[i].ident = ident;
      shellalias[i].comm = comm;
# ifdef     DEP_PTY
      sendparent(TE_ADDALIAS, ident, comm);
# endif

      return(0);
}

int deletealias(ident)
CONST char *ident;
{
      reg_t *re;
      int i, n, max;

      n = 0;
      re = regexp_init(ident, -1);
      for (max = 0; shellalias[max].ident; max++) /*EMPTY*/;
      for (i = 0; i < max; i++) {
            if (re) {
                  if (!regexp_exec(re, shellalias[i].ident, 0)) continue;
            }
            else if (strcommcmp(ident, shellalias[i].ident)) continue;
            free2(shellalias[i].ident);
            free2(shellalias[i].comm);
            memmove((char *)&(shellalias[i]), (char *)&(shellalias[i + 1]),
                  (max-- - i) * sizeof(shaliastable));
            i--;
            n++;
      }
      regexp_free(re);
      if (!n) return(-1);
# ifdef     DEP_PTY
      sendparent(TE_DELETEALIAS, ident);
# endif

      return(0);
}

static shaliastable *NEAR duplalias(alias)
shaliastable *alias;
{
      shaliastable *dupl;
      int i, n;

      if (!alias) n = 0;
      else for (n = 0; alias[n].ident; n++) /*EMPTY*/;
      dupl = (shaliastable *)malloc2((n + 1) * sizeof(shaliastable));
      for (i = 0; i < n; i++) {
            dupl[i].ident = strdup2(alias[i].ident);
            dupl[i].comm = strdup2(alias[i].comm);
      }
      dupl[i].ident = NULL;

      return(dupl);
}

VOID freealias(alias)
shaliastable *alias;
{
      int i;

      if (alias) {
            for (i = 0; alias[i].ident; i++) {
                  free2(alias[i].ident);
                  free2(alias[i].comm);
            }
            free2(alias);
      }
}

static int cmpalias(vp1, vp2)
CONST VOID_P vp1;
CONST VOID_P vp2;
{
      shaliastable *ap1, *ap2;

      ap1 = (shaliastable *)vp1;
      ap2 = (shaliastable *)vp2;

      return(strpathcmp2(ap1 -> ident, ap2 -> ident));
}

int checkalias(trp, ident, len, delim)
syntaxtree *trp;
char *ident;
int len, delim;
{
      int i;

      if (!trp || (trp -> flags & ST_NODE) || hascomm(trp)
      || !interactive
      || ((i = getstatid(parentstree(trp))) >= 0
      && !(statementlist[i].type & STT_NEEDLIST)))
            return(-1);

      if (delim
      && (!strchr2(IFS_SET, delim) && !strchr2(ALIASDELIMIT, delim)))
            return(-1);
      i = searchalias(ident, len);
      if (!(shellalias[i].ident) || (shellalias[i].flags & AL_USED))
            return(-1);

      *ident = '\0';
      shellalias[i].flags |= AL_USED;

      return(i);
}
#endif      /* NOALIAS */

static int NEAR _evalexpression(s, ptr, resultp)
CONST char *s;
int ptr;
long *resultp;
{
      long n;
      int i, c, base;

      while (s[ptr] && strchr2(IFS_SET, s[ptr])) ptr++;
      if (!s[ptr]) return(-1);

      if (s[ptr] == '+') {
            if ((ptr = _evalexpression(s, ptr + 1, resultp)) < 0)
                  return(-1);
      }
      else if (s[ptr] == '-') {
            if ((ptr = _evalexpression(s, ptr + 1, resultp)) < 0)
                  return(-1);
            *resultp = -(*resultp);
      }
      else if (s[ptr] == '~') {
            if ((ptr = _evalexpression(s, ptr + 1, resultp)) < 0)
                  return(-1);
            *resultp = ~(*resultp);
      }
      else if (s[ptr] == '!' && s[ptr + 1] != '=') {
            if ((ptr = _evalexpression(s, ptr + 1, resultp)) < 0)
                  return(-1);
            *resultp = (*resultp) ? 0L : 1L;
      }
      else if (s[ptr] == '(') {
            if ((ptr = evalexpression(s, ptr + 1, resultp, 9)) < 0)
                  return(-1);
            while (s[ptr] && strchr2(IFS_SET, s[ptr])) ptr++;
            if (s[ptr++] != ')') return(-1);
      }
      else if (isdigit2(s[ptr])) {
            if (s[ptr] != '0') base = 10;
            else if (toupper2(s[++ptr]) != 'X') base = 8;
            else {
                  base = 16;
                  ptr++;
            }

            n = 0;
            for (i = ptr; s[i]; i++) {
                  c = s[i];
                  if (isdigit2(c)) c -= '0';
                  else if (islower2(c)) c -= 'a' - 10;
                  else if (isupper2(c)) c -= 'A' - 10;
                  else c = -1;
                  if (c < 0 || c >= base) break;

                  if (n > MAXTYPE(long) / base
                  || (n == MAXTYPE(long) / base
                  && c > MAXTYPE(long) % base))
                        return(-1);
                  n = n * base + c;
            }
            if (i <= ptr) return(-1);
            ptr = i;
            *resultp = n;
      }
      else return(-1);

      while (s[ptr] && strchr2(IFS_SET, s[ptr])) ptr++;

      return(ptr);
}

static int NEAR evalexpression(s, ptr, resultp, lvl)
CONST char *s;
int ptr;
long *resultp;
int lvl;
{
      long n;

      if (lvl < 1) {
            if ((ptr = _evalexpression(s, ptr, resultp)) < 0) return(-1);
      }
      else {
            if ((ptr = evalexpression(s, ptr, resultp, lvl - 1)) < 0)
                  return(-1);
      }

      while (s[ptr]) {
            if (lvl < 1) {
                  if (s[ptr] == '*') {
                        ptr = _evalexpression(s, ptr + 1, &n);
                        if (ptr < 0) return(-1);
                        *resultp *= n;
                  }
                  else if (s[ptr] == '/') {
                        ptr = _evalexpression(s, ptr + 1, &n);
                        if (ptr < 0 || !n) return(-1);
                        *resultp /= n;
                  }
                  else if (s[ptr] == '%') {
                        ptr = _evalexpression(s, ptr + 1, &n);
                        if (ptr < 0 || !n) return(-1);
                        *resultp %= n;
                  }
                  else break;
            }
            else if (lvl < 2) {
                  if (s[ptr] == '+') {
                        ptr = evalexpression(s, ptr + 1, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp += n;
                  }
                  else if (s[ptr] == '-') {
                        ptr = evalexpression(s, ptr + 1, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp -= n;
                  }
                  else break;
            }
            else if (lvl < 3) {
                  if (s[ptr] == '<' && s[ptr + 1] == '<') {
                        ptr = evalexpression(s, ptr + 2, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp <<= n;
                  }
                  else if (s[ptr] == '>' && s[ptr + 1] == '>') {
                        ptr = evalexpression(s, ptr + 2, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp >>= n;
                  }
                  else break;
            }
            else if (lvl < 4) {
                  if ((s[ptr] == '<' && s[ptr + 1] == '=')
                  || (s[ptr] == '=' && s[ptr + 1] == '<')) {
                        ptr = evalexpression(s, ptr + 2, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp = (long)(*resultp <= n);
                  }
                  else if ((s[ptr] == '>' && s[ptr + 1] == '=')
                  || (s[ptr] == '=' && s[ptr + 1] == '>')) {
                        ptr = evalexpression(s, ptr + 2, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp = (long)(*resultp >= n);
                  }
                  else if (s[ptr] == '>') {
                        ptr = evalexpression(s, ptr + 1, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp = (long)(*resultp > n);
                  }
                  else if (s[ptr] == '<') {
                        ptr = evalexpression(s, ptr + 1, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp = (long)(*resultp < n);
                  }
                  else break;
            }
            else if (lvl < 5) {
                  if (s[ptr] == '=' && s[ptr + 1] == '=') {
                        ptr = evalexpression(s, ptr + 2, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp = (long)(*resultp == n);
                  }
                  else if (s[ptr] == '!' && s[ptr + 1] == '=') {
                        ptr = evalexpression(s, ptr + 2, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp = (long)(*resultp != n);
                  }
                  else break;
            }
            else if (lvl < 6) {
                  if (s[ptr] == '&' && s[ptr + 1] != '&') {
                        ptr = evalexpression(s, ptr + 1, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp = (*resultp & n);
                  }
                  else break;
            }
            else if (lvl < 7) {
                  if (s[ptr] == '^') {
                        ptr = evalexpression(s, ptr + 1, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp = (*resultp ^ n);
                  }
                  else break;
            }
            else if (lvl < 8) {
                  if (s[ptr] == '|' && s[ptr + 1] != '|') {
                        ptr = evalexpression(s, ptr + 1, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp = (*resultp | n);
                  }
                  else break;
            }
            else if (lvl < 9) {
                  if (s[ptr] == '&' && s[ptr + 1] == '&') {
                        ptr = evalexpression(s, ptr + 2, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp = (long)(*resultp && n);
                  }
                  else break;
            }
            else {
                  if (s[ptr] == '|' && s[ptr + 1] == '|') {
                        ptr = evalexpression(s, ptr + 2, &n, lvl - 1);
                        if (ptr < 0) return(-1);
                        *resultp = (long)(*resultp || n);
                  }
                  else break;
            }
      }

      return(ptr);
}

char *evalposixsubst(s, ptrp)
CONST char *s;
int *ptrp;
{
#ifndef     BASHBUG
      syntaxtree *trp, *stree;
      redirectlist red;
#endif
      char *cp, *new;
      long n;
      int i, len;

      i = 1;
      if (s[i] == '(') i++;

      s += i;
      len = *ptrp - i * 2;
      s = new = strndup2(s, len);
      if (i <= 1) {
#ifndef     BASHBUG
      /* bash cannot include 'case' statement within $() */
            red.fd = red.type = red.new = 0;
            red.filename = vnullstr;
            i = len = 0;
            stree = newstree(NULL);
            trp = startvar(stree, &red, nullstr, &i, &len, 0);
            trp -> cont = CN_COMM;
            trp = analyze(s, trp, -1);
            if (trp && (trp -> cont & CN_SBST) != CN_CASE) trp = NULL;
            freestree(stree);
            free2(stree);
            if (trp) cp = NULL;
            else
#endif      /* !BASHBUG */
            if (!(cp = evalbackquote(s))) *ptrp = -1;
      }
      else {
            n = 0L;
            cp = evalvararg(new,
                  EA_STRIPESCAPE
                  | EA_NOEVALQ | EA_NOEVALDQ | EA_BACKQ, 0);
            if (!cp) *ptrp = -1;
            else {
                  for (i = 0; cp[i]; i++)
                        if (!strchr2(IFS_SET, cp[i])) break;
                  if (cp[i]) {
                        i = evalexpression(cp, i, &n, 9);
                        if (i < 0 || cp[i]) *ptrp = -1;
                  }
                  free2(cp);
            }

            cp = (*ptrp < 0) ? NULL : asprintf3("%ld", n);
      }
      free2(new);

      return(cp);
}

#if   !MSDOS
static VOID NEAR addmailpath(path, msg, mtime)
CONST char *path;
char *msg;
time_t mtime;
{
      int i;

      for (i = 0; i < maxmailpath; i++)
            if (!strpathcmp(path, mailpathlist[i].path)) break;
      if (i < maxmailpath) free2(mailpathlist[i].msg);
      else {
            mailpathlist = (mailpath_t *)realloc2(mailpathlist,
                  (i + 1) * sizeof(mailpath_t));
            maxmailpath = i + 1;
            mailpathlist[i].path = strdup2(path);
      }
      mailpathlist[i].msg = msg;
      mailpathlist[i].mtime = mtime;
}

VOID replacemailpath(s, multi)
CONST char *s;
int multi;
{
      mailpath_t *mailpath;
      time_t mtime;
      CONST char *cp;
      char *msg, path[MAXPATHLEN];
      int i, max, len;

      mailpath = mailpathlist;
      max = maxmailpath;
      mailpathlist = NULL;
      maxmailpath = 0;

      if (!multi) {
            for (i = 0; i < max; i++)
                  if (!strpathcmp(s, mailpath[i].path)) break;
            mtime = (i < max) ? mailpath[i].mtime : 0;
            addmailpath(s, NULL, mtime);
      }
      else while (*s) {
            if ((cp = strchr2(s, ':'))) len = (cp++) - s;
            else {
                  len = strlen(s);
                  cp = &(s[len]);
            }
            if ((msg = strchr2(s, '%'))) {
                  if (msg > s + len) msg = NULL;
                  else {
                        i = s + len - (msg + 1);
                        len = msg - s;
                        msg = strndup2(&(s[len + 1]), i);
                  }
            }
            strncpy2(path, s, len);
            s = cp;
            for (i = 0; i < max; i++)
                  if (!strpathcmp(path, mailpath[i].path)) break;
            mtime = (i < max) ? mailpath[i].mtime : 0;
            addmailpath(path, msg, mtime);
      }

      for (i = 0; i < max; i++) {
            free2(mailpath[i].path);
            free2(mailpath[i].msg);
      }
      free2(mailpath);
}

VOID checkmail(reset)
int reset;
{
      static time_t lastchecked = 0;
      time_t now;
      int i;

      if (reset) {
            for (i = 0; i < maxmailpath; i++) {
                  free2(mailpathlist[i].path);
                  free2(mailpathlist[i].msg);
            }
            free2(mailpathlist);
            mailpathlist = NULL;
            maxmailpath = 0;
            return;
      }

      if (mailcheck > 0) {
            now = time2();
            if (now < lastchecked + mailcheck) return;
            lastchecked = now;
      }

      for (i = 0; i < maxmailpath; i++)
            cmpmail(mailpathlist[i].path,
                  mailpathlist[i].msg, &(mailpathlist[i].mtime));
}
#endif      /* !MSDOS */

#ifndef     NOJOB
/*ARGSUSED*/
int posixjobs(trp)
syntaxtree *trp;
{
      int i, j;

      if (mypid != orgpgrp) return(RET_SUCCESS);
      checkjob(NULL);
      for (i = 0; i < maxjobs; i++) {
            if (!(joblist[i].pids)) continue;
            j = joblist[i].npipe;

            if (joblist[i].stats[j] >= 0 && joblist[i].stats[j] < 128)
                  dispjob(i, Xstdout);
            else {
                  if (isopbg(joblist[i].trp) || isopnown(joblist[i].trp))
                        joblist[i].trp -> type = OP_NONE;
                  dispjob(i, Xstdout);
                  free2(joblist[i].pids);
                  free2(joblist[i].stats);
                  if (joblist[i].trp) {
                        freestree(joblist[i].trp);
                        free2(joblist[i].trp);
                  }
                  joblist[i].pids = NULL;
            }
      }

      return(RET_SUCCESS);
}

/*ARGSUSED*/
int posixfg(trp)
syntaxtree *trp;
{
      termioctl_t tty;
      char *s;
      int i, j, n, ret;

      s = ((trp -> comm) -> argc > 1) ? (trp -> comm) -> argv[1] : NULL;
      checkjob(NULL);
      if ((i = getjob(s)) < 0) {
            execerror((trp -> comm) -> argv,
                  (trp -> comm) -> argv[1],
                  (i < -1) ? ER_TERMINATED : ER_NOSUCHJOB, 2);
            return(RET_FAIL);
      }
      n = joblist[i].npipe;
      if (tioctl(ttyio, REQGETP, &tty) < 0) {
            doperror((trp -> comm) -> argv[0], "fatal error");
            prepareexit(-1);
            Xexit(RET_FATALERR);
      }
      fprintf2(Xstderr, "[%d] %id", i + 1, joblist[i].pids[n]);
      VOID_C fputnl(Xstderr);
      if (joblist[i].tty) tioctl(ttyio, REQSETP, joblist[i].tty);
# ifdef     USESGTTY
      if (joblist[i].ttyflag) ioctl(ttyio, TIOCLSET, joblist[i].ttyflag);
# endif
      gettermio(joblist[i].pids[0], jobok);
      if ((j = joblist[i].stats[n]) > 0 && j < 128) {
            Xkillpg(joblist[i].pids[0], SIGCONT);
            for (j = 0; j <= n; j++) joblist[i].stats[j] = 0;
      }
      if (isopbg(joblist[i].trp) || isopnown(joblist[i].trp))
            joblist[i].trp -> type = OP_NONE;
      ret = waitchild(joblist[i].pids[n], NULL);
      gettermio(orgpgrp, jobok);
      if (tioctl(ttyio, REQSETP, &tty) < 0) {
            doperror((trp -> comm) -> argv[0], "fatal error");
            prepareexit(-1);
            Xexit(RET_FATALERR);
      }

      return(ret);
}

/*ARGSUSED*/
int posixbg(trp)
syntaxtree *trp;
{
      char *s;
      int i, j, n;

      s = ((trp -> comm) -> argc > 1) ? (trp -> comm) -> argv[1] : NULL;
      checkjob(NULL);
      if ((i = getjob(s)) < 0) {
            execerror((trp -> comm) -> argv,
                  (trp -> comm) -> argv[1],
                  (i < -1) ? ER_TERMINATED : ER_NOSUCHJOB, 2);
            return(RET_FAIL);
      }
      n = joblist[i].npipe;
      if ((j = joblist[i].stats[n]) > 0 && j < 128) {
            Xkillpg(joblist[i].pids[0], SIGCONT);
            for (j = 0; j <= n; j++) joblist[i].stats[j] = 0;
      }
      if (!isopbg(joblist[i].trp) || !isopnown(joblist[i].trp))
            joblist[i].trp -> type = OP_BG;
      if (interactive && !nottyout) dispjob(i, Xstderr);
      prevjob = lastjob;
      lastjob = i;

      return(RET_SUCCESS);
}
#endif      /* !NOJOB */

#ifndef     NOALIAS
int posixalias(trp)
syntaxtree *trp;
{
      shaliastable *alias;
      char **argv;
      int i, n, len, set, ret;

      argv = (trp -> comm) -> argv;
      if ((trp -> comm) -> argc <= 1) {
            alias = duplalias(shellalias);
            for (i = 0; alias[i].ident; i++) /*EMPTY*/;
            if (i > 1) qsort(alias, i, sizeof(shaliastable), cmpalias);
            for (i = 0; alias[i].ident; i++) {
                  fprintf2(Xstdout, "alias %k='%k'",
                        alias[i].ident, alias[i].comm);
                  VOID_C fputnl(Xstdout);
            }
            freealias(alias);
            return(RET_SUCCESS);
      }

      ret = RET_SUCCESS;
      for (n = 1; n < (trp -> comm) -> argc; n++) {
            set = 0;
            for (len = 0; argv[n][len]; len++) if (argv[n][len] == '=') {
                  set = 1;
                  break;
            }

            if (set) VOID_C addalias(strndup2(argv[n], len),
                  strdup2(&(argv[n][len + 1])));
            else {
                  i = searchalias(argv[n], len);
                  if (!(shellalias[i].ident)) {
                        if (interactive) {
                              Xfputs("alias: ", Xstderr);
                              execerror(argv,
                                    argv[n], ER_NOTFOUND, 2);
                        }
                        ret = RET_FAIL;
                        ERRBREAK;
                  }
                  fprintf2(Xstdout, "alias %k='%k'",
                        shellalias[i].ident, shellalias[i].comm);
                  VOID_C fputnl(Xstdout);
            }
      }

      return(ret);
}

int posixunalias(trp)
syntaxtree *trp;
{
      char **argv;
      int n, ret;

      argv = (trp -> comm) -> argv;
      ret = RET_SUCCESS;
      for (n = 1; n < (trp -> comm) -> argc; n++) {
            if (deletealias(argv[n]) < 0) {
                  if (interactive) {
                        Xfputs("alias: ", Xstderr);
                        execerror(argv, argv[n], ER_NOTALIAS, 2);
                  }
                  ret = RET_FAIL;
                  ERRBREAK;
            }
      }

      return(ret);
}
#endif      /* NOALIAS */

int posixkill(trp)
syntaxtree *trp;
{
      char *s;
      p_id_t pid;
      int i, n, sig;

      if ((trp -> comm) -> argc <= 1) {
            Xfputs("usage: kill [ -sig ] pid ...\n", Xstderr);
            Xfputs("for a list of signals: kill -l", Xstderr);
            VOID_C fputnl(Xstderr);
            return(RET_SYNTAXERR);
      }
#ifdef      SIGTERM
      sig = SIGTERM;
#else
      sig = 0;
#endif
      s = (trp -> comm) -> argv[1];
      if (s[0] != '-') i = 1;
      else {
            if (s[1] == 'l') {
                  for (sig = n = 0; sig < NSIG; sig++) {
                        for (i = 0; signallist[i].sig >= 0; i++)
                              if (sig == signallist[i].sig) break;
                        if (signallist[i].sig < 0) continue;
                        fprintf2(Xstdout, "%s%c",
                              signallist[i].ident,
                              (++n % 16) ? ' ' : '\n');
                  }
                  if (n % 16) VOID_C fputnl(Xstdout);
                  Xfflush(Xstdout);
                  return(RET_SUCCESS);
            }
            if ((sig = isnumeric(&(s[1]))) < 0) {
                  for (i = 0; signallist[i].sig >= 0; i++)
                        if (!strcmp(&(s[1]), signallist[i].ident))
                              break;
                  if (signallist[i].sig < 0) {
                        execerror((trp -> comm) -> argv,
                              &(s[1]), ER_UNKNOWNSIG, 1);
                        return(RET_FAIL);
                  }
                  sig = signallist[i].sig;
            }
            if (sig < 0 || sig >= NSIG) {
                  execerror((trp -> comm) -> argv, s, ER_NUMOUTRANGE, 1);
                  return(RET_FAIL);
            }
            i = 2;
      }

#ifndef     NOJOB
      checkjob(NULL);
#endif
      for (; i < (trp -> comm) -> argc; i++) {
            s = (trp -> comm) -> argv[i];
#ifndef     NOJOB
            if (*s == '%') {
                  if ((n = getjob(s)) < 0) {
                        execerror((trp -> comm) -> argv,
                              s,
                              (n < -1)
                              ? ER_TERMINATED : ER_NOSUCHJOB, 2);
                        return(RET_FAIL);
                  }
                  n = Xkillpg(joblist[n].pids[0], sig);
            }
            else
#endif      /* !NOJOB */
            if ((pid = isnumeric(s)) < (p_id_t)0) {
                  Xfputs("usage: kill [ -sig ] pid ...\n", Xstderr);
                  Xfputs("for a list of signals: kill -l", Xstderr);
                  VOID_C fputnl(Xstderr);
                  return(RET_SYNTAXERR);
            }
#if   MSDOS
            else if (pid && pid != mypid) n = seterrno(EPERM);
#endif
            else n = kill(pid, sig);

            if (n < 0) {
                  doperror((trp -> comm) -> argv[0], s);
                  return(RET_FAIL);
            }
      }

      return(RET_SUCCESS);
}

static int NEAR testsub1(c, s, ptrp)
int c;
CONST char *s;
int *ptrp;
{
      struct stat st;
      int ret;

      ret = -1;
      switch (c) {
            case 'r':
                  if (s) ret = (Xaccess(s, R_OK) >= 0)
                        ? RET_SUCCESS : RET_FAIL;
                  break;
            case 'w':
                  if (s) ret = (Xaccess(s, W_OK) >= 0)
                        ? RET_SUCCESS : RET_FAIL;
                  break;
            case 'x':
                  if (s) ret = (Xaccess(s, X_OK) >= 0)
                        ? RET_SUCCESS : RET_FAIL;
                  break;
            case 'f':
#if   defined (BASHSTYLE) || defined (STRICTPOSIX)
      /* "test" on bash & POSIX regards -f as checking if regular file. */
                  if (s) ret = (*s && Xstat(s, &st) >= 0
                  && (st.st_mode & S_IFMT) == S_IFREG)
#else
                  if (s) ret = (*s && Xstat(s, &st) >= 0
                  && (st.st_mode & S_IFMT) != S_IFDIR)
#endif
                        ? RET_SUCCESS : RET_FAIL;
                  break;
            case 'd':
                  if (s) ret = (*s && Xstat(s, &st) >= 0
                  && (st.st_mode & S_IFMT) == S_IFDIR)
                        ? RET_SUCCESS : RET_FAIL;
                  break;
            case 'c':
                  if (s) ret = (*s && Xstat(s, &st) >= 0
                  && (st.st_mode & S_IFMT) == S_IFCHR)
                        ? RET_SUCCESS : RET_FAIL;
                  break;
            case 'b':
                  if (s) ret = (*s && Xstat(s, &st) >= 0
                  && (st.st_mode & S_IFMT) == S_IFBLK)
                        ? RET_SUCCESS : RET_FAIL;
                  break;
            case 'p':
                  if (s) ret = (*s && Xstat(s, &st) >= 0
                  && (st.st_mode & S_IFMT) == S_IFIFO)
                        ? RET_SUCCESS : RET_FAIL;
                  break;
            case 'u':
                  if (s) ret = (*s && Xstat(s, &st) >= 0
                  && st.st_mode & S_ISUID)
                        ? RET_SUCCESS : RET_FAIL;
                  break;
            case 'g':
                  if (s) ret = (*s && Xstat(s, &st) >= 0
                  && st.st_mode & S_ISGID)
                        ? RET_SUCCESS : RET_FAIL;
                  break;
            case 'k':
                  if (s) ret = (*s && Xstat(s, &st) >= 0
                  && st.st_mode & S_ISVTX)
                        ? RET_SUCCESS : RET_FAIL;
                  break;
#if   defined (BASHSTYLE) || defined (STRICTPOSIX)
      /* "test" on bash & POSIX has -e & -L option */
            case 'e':
                  if (s) ret = (*s && Xlstat(s, &st) >= 0)
                        ? RET_SUCCESS : RET_FAIL;
                  break;
            case 'L':
#endif
            case 'h':
                  if (s) ret = (*s && Xlstat(s, &st) >= 0
                  && (st.st_mode & S_IFMT) == S_IFLNK)
                        ? RET_SUCCESS : RET_FAIL;
                  break;
            case 's':
                  if (s) ret = (*s && Xstat(s, &st) >= 0
                  && st.st_size > 0)
                        ? RET_SUCCESS : RET_FAIL;
                  break;
            case 't':
                  if (s) {
#ifdef      BASHBUG
      /* Maybe bash's bug. */
                        if ((ret = isnumeric(s)) < 0) ret = 1;
#else
                        if ((ret = isnumeric(s)) < 0) ret = 0;
#endif
                        ret = (isatty(ret)) ? RET_SUCCESS : RET_FAIL;
                  }
                  else {
                        (*ptrp)++;
#ifdef      BASHBUG
      /* Maybe bash's bug. */
                        ret = 0;
#else
                        ret = 1;
#endif
                        return((isatty(ret)) ? RET_SUCCESS : RET_FAIL);
                  }
                  break;
            case 'z':
                  if (s) ret = (!*s) ? RET_SUCCESS : RET_FAIL;
                  break;
            case 'n':
                  if (s) ret = (*s) ? RET_SUCCESS : RET_FAIL;
                  break;
            default:
                  ret = -2;
                  break;
      }
      if (ret >= 0) *ptrp += 2;

      return(ret);
}

static int NEAR testsub2(argc, argv, ptrp)
int argc;
char *CONST *argv;
int *ptrp;
{
      CONST char *s, *a1, *a2;
      int ret, v1, v2;

      if (*ptrp >= argc) return(-1);
      if (argv[*ptrp][0] == '(' && !argv[*ptrp][1]) {
            (*ptrp)++;
            if ((ret = testsub3(argc, argv, ptrp, 0)) < 0)
                  return(ret);
            if (*ptrp >= argc
            || argv[*ptrp][0] != ')' || argv[*ptrp][1])
                  return(-1);
            (*ptrp)++;
            return(ret);
      }
      if (*ptrp + 2 < argc) {
            s = argv[*ptrp + 1];
            a1 = argv[*ptrp];
            a2 = argv[*ptrp + 2];
            ret = -1;

            if (s[0] == '!' && s[1] == '=' && !s[2])
                  ret = (strcmp(a1, a2)) ? RET_SUCCESS : RET_FAIL;
#ifdef      BASHSTYLE
      /* bash's "test" allows "==" as same as "=" */
            else if (s[0] == '=' && s[1] == '=' && !s[2])
                  ret = (!strcmp(a1, a2)) ? RET_SUCCESS : RET_FAIL;
#endif
            else if (s[0] == '=' && !s[1])
                  ret = (!strcmp(a1, a2)) ? RET_SUCCESS : RET_FAIL;
            else if (s[0] == '-') {
                  if ((v1 = isnumeric(a1)) < 0) {
#ifdef      BASHSTYLE
      /* bash's "test" does not allow arithmetic comparison with strings */
                        return(-3);
#else
                        v1 = 0;
#endif
                  }
                  if ((v2 = isnumeric(a2)) < 0) {
#ifdef      BASHSTYLE
      /* bash's "test" does not allow arithmetic comparison with strings */
                        *ptrp += 2;
                        return(-3);
#else
                        v2 = 0;
#endif
                  }
                  if (s[1] == 'e' && s[2] == 'q' && !s[3])
                        ret = (v1 == v2) ? RET_SUCCESS : RET_FAIL;
                  else if (s[1] == 'n' && s[2] == 'e' && !s[3])
                        ret = (v1 != v2) ? RET_SUCCESS : RET_FAIL;
                  else if (s[1] == 'g' && s[2] == 't' && !s[3])
                        ret = (v1 > v2) ? RET_SUCCESS : RET_FAIL;
                  else if (s[1] == 'g' && s[2] == 'e' && !s[3])
                        ret = (v1 >= v2) ? RET_SUCCESS : RET_FAIL;
                  else if (s[1] == 'l' && s[2] == 't' && !s[3])
                        ret = (v1 < v2) ? RET_SUCCESS : RET_FAIL;
                  else if (s[1] == 'l' && s[2] == 'e' && !s[3])
                        ret = (v1 <= v2) ? RET_SUCCESS : RET_FAIL;
                  else {
                        (*ptrp)++;
                        return(-2);
                  }
            }
            if (ret >= 0) {
                  *ptrp += 3;
                  return(ret);
            }
      }
      if (argv[*ptrp][0] == '-' && !argv[*ptrp][2]) {
            a1 = (*ptrp + 1 < argc) ? argv[*ptrp + 1] : NULL;
            ret = testsub1(argv[*ptrp][1], a1, ptrp);
            if (ret >= -1) return(ret);
      }
      ret = (argv[*ptrp][0]) ? RET_SUCCESS : RET_FAIL;
      (*ptrp)++;

      return(ret);
}

static int NEAR testsub3(argc, argv, ptrp, lvl)
int argc;
char *CONST *argv;
int *ptrp, lvl;
{
      int ret1, ret2;

      if (lvl > 2) {
            if (*ptrp >= argc) return(-1);
            if (argv[*ptrp][0] == '!' && !argv[*ptrp][1]) {
                  (*ptrp)++;
                  if ((ret1 = testsub2(argc, argv, ptrp)) < 0)
                        return(ret1);
                  return(1 - ret1);
            }
            return(testsub2(argc, argv, ptrp));
      }
      if ((ret1 = testsub3(argc, argv, ptrp, lvl + 1)) < 0) return(ret1);
      if (*ptrp >= argc || argv[*ptrp][0] != '-'
      || argv[*ptrp][1] != ((lvl) ? 'a' : 'o') || argv[*ptrp][2])
            return(ret1);

      (*ptrp)++;
      if ((ret2 = testsub3(argc, argv, ptrp, lvl)) < 0) return(ret2);
      ret1 = ((lvl)
            ? (ret1 != RET_FAIL && ret2 != RET_FAIL)
            : (ret1 != RET_FAIL || ret2 != RET_FAIL))
                  ? RET_SUCCESS : RET_FAIL;

      return(ret1);
}

int posixtest(trp)
syntaxtree *trp;
{
      char *CONST *argv;
      int ret, ptr, argc;

      argc = (trp -> comm) -> argc;
      argv = (trp -> comm) -> argv;

      if (argc <= 0) return(RET_FAIL);
      if (argv[0][0] == '[' && !argv[0][1]
      && (--argc <= 0 || argv[argc][0] != ']' || argv[argc][1])) {
            Xfputs("] missing", Xstderr);
            VOID_C fputnl(Xstderr);
            return(RET_NOTICE);
      }
      if (argc <= 1) return(RET_FAIL);
      ptr = 1;
      ret = testsub3(argc, argv, &ptr, 0);
      if (!ret && ptr < argc) ret = -1;
      if (ret < 0) {
            switch (ret) {
                  case -1:
                        Xfputs("argument expected", Xstderr);
                        break;
                  case -2:
                        fprintf2(Xstderr, "unknown operator %k",
                              argv[ptr]);
                        break;
                  default:
                        Xfputs("syntax error", Xstderr);
                        break;
            }
            VOID_C fputnl(Xstderr);
            return(RET_NOTICE);
      }

      return(ret);
}

#ifndef     NOPOSIXUTIL
int posixcommand(trp)
syntaxtree *trp;
{
      hashlist *hp;
      char *cp, **argv, *path;
      int i, n, flag, ret, id, type, argc;

      argc = (trp -> comm) -> argc;
      argv = (trp -> comm) -> argv;

      if ((flag = tinygetopt(trp, "pvV", &n)) < 0) return(RET_FAIL);

      if (interrupted) return(RET_INTR);
      if (argc <= n) return(ret_status);

# ifdef     BASHSTYLE
      ret = RET_FAIL;
# else
      ret = RET_SUCCESS;
# endif
      if (flag == 'V') {
            for (i = n; i < argc; i++) {
                  if (typeone(argv[i], Xstdout) >= 0) {
# ifdef     BASHSTYLE
                        ret = RET_SUCCESS;
# endif
                  }
            }
            return(ret);
      }
      else if (flag == 'v') {
            for (i = n; i < argc; i++) {
#ifdef      NOALIAS
                  type = checktype(argv[i], &id, 0);
#else
                  type = checktype(argv[i], &id, 0, 0);
#endif

                  cp = argv[i];
                  if (type == CT_COMMAND) {
                        type = searchhash(&hp, cp, NULL);
# ifdef     _NOUSEHASH
                        if (!(type & CM_FULLPATH)) cp = (char *)hp;
# else
                        if (type & CM_HASH) cp = hp -> path;
# endif
                        if ((type & CM_NOTFOUND)
                        || Xaccess(cp, X_OK) < 0) {
                              execerror(argv, cp, ER_COMNOFOUND, 1);
                              cp = NULL;
                        }
                  }

                  if (cp) {
                        kanjifputs(cp, Xstdout);
                        VOID_C fputnl(Xstdout);
# ifdef     BASHSTYLE
                        ret = RET_SUCCESS;
# endif
                  }
            }
            return(ret);
      }

#ifdef      NOALIAS
      type = checktype(argv[n], &id, 0);
#else
      type = checktype(argv[n], &id, 0, 0);
#endif
      if (verboseexec) {
            fprintf2(Xstderr, "+ %k", argv[n]);
            for (i = n + 1; i < argc; i++)
                  fprintf2(Xstderr, " %k", argv[i]);
            VOID_C fputnl(Xstderr);
      }

      (trp -> comm) -> argc -= n;
      (trp -> comm) -> argv += n;
      if (flag != 'p')
#if   MSDOS
            ret = exec_simplecom(trp, type, id);
#else
            ret = exec_simplecom(trp, type, id, 0);
#endif
      else {
            path = strdup2(getconstvar(ENVPATH));
            setenv2(ENVPATH, DEFPATH, 1);
#if   MSDOS
            ret = exec_simplecom(trp, type, id);
#else
            ret = exec_simplecom(trp, type, id, 0);
#endif
            setenv2(ENVPATH, path, 1);
            free2(path);
      }
      (trp -> comm) -> argc = argc;
      (trp -> comm) -> argv = argv;

      return(ret);
}

int posixgetopts(trp)
syntaxtree *trp;
{
      static int ptr = 0;
      char *cp, *optstr, *posixoptarg, *name, **argv, buf[MAXLONGWIDTH + 1];
      int n, ret, quiet, argc;

      argc = (trp -> comm) -> argc;
      argv = (trp -> comm) -> argv;

      if (argc <= 2) {
            execerror(argv, NULL, ER_MISSARG, 1);
            return(RET_FAIL);
      }
      if (identcheck(argv[2], '\0') <= 0) {
            execerror(argv, argv[2], ER_NOTIDENT, 0);
            return(RET_FAIL);
      }

      optstr = argv[1];
      name = argv[2];
      quiet = 0;
      if (*optstr == ':') {
            quiet = 1;
            optstr++;
      }

      if (argc > 3) {
            argv = &(argv[2]);
            argc -= 2;
      }
      else {
            argv = argvar;
            argc = countvar(argv);
      }

      if (posixoptind <= 0) {
            ptr = 0;
            posixoptind = 1;
      }

      ret = RET_SUCCESS;
      posixoptarg = NULL;
      if (posixoptind >= argc || !argv[posixoptind]) ret = RET_FAIL;
      else if (ptr >= strlen(argv[posixoptind])) {
            if (++posixoptind < argc && argv[posixoptind]) ptr = 0;
            else ret = RET_FAIL;
      }

      if (ret == RET_SUCCESS && !ptr) {
            if (argv[posixoptind][0] != '-') ret = RET_FAIL;
            else if (argv[posixoptind][1] == '-'
            && !(argv[posixoptind][2])) {
                  posixoptind++;
                  ret = RET_FAIL;
            }
            else if (!(argv[posixoptind][ptr + 1])) ret = RET_FAIL;
            else ptr++;
      }

      if (ret != RET_SUCCESS) n = '?';
      else {
            n = argv[posixoptind][ptr++];
            if (n == ':' || ismsb(n) || !(cp = strchr2(optstr, n))) {
                  buf[0] = n;
                  buf[1] = '\0';
                  n = '?';
                  if (quiet) posixoptarg = buf;
                  else execerror((trp -> comm) -> argv,
                        buf, ER_BADOPTIONS, 2);
            }
            else if (*(cp + 1) == ':') {
                  if (argv[posixoptind][ptr])
                        posixoptarg = &(argv[posixoptind++][ptr]);
                  else if (++posixoptind < argc && argv[posixoptind])
                        posixoptarg = argv[posixoptind++];
                  else {
                        buf[0] = n;
                        buf[1] = '\0';
                        if (quiet) {
                              n = ':';
                              posixoptarg = buf;
                        }
                        else {
                              n = '?';
                              execerror((trp -> comm) -> argv,
                                    buf, ER_MISSARG, 2);
                        }
                  }
                  ptr = 0;
            }
      }

      if (posixoptarg) setenv2(ENVOPTARG, posixoptarg, 0);
      else if (ret == RET_SUCCESS) unset(ENVOPTARG, strsize(ENVOPTARG));

      buf[0] = n;
      buf[1] = '\0';
      setenv2(name, buf, 0);

      n = posixoptind;
      snprintf2(buf, sizeof(buf), "%d", n);
      setenv2(ENVOPTIND, buf, 0);
      posixoptind = n;

      return(ret);
}
#endif      /* NOPOSIXUTIL */
#endif      /* DEP_ORIGSHELL && !MINIMUMSHELL */

Generated by  Doxygen 1.6.0   Back to index