openenvutils/commandshell/shell/src/exec.c
changeset 0 2e3d3ce01487
child 4 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // exec.c - command execution
       
     2 //
       
     3 // © Portions Copyright (c) Symbian Software Ltd 2007 - 2008. All rights reserved.
       
     4 //
       
     5 /*
       
     6  * This file is part of zsh, the Z shell.
       
     7  *
       
     8  * Copyright (c) 1992-1997 Paul Falstad
       
     9  * All rights reserved.
       
    10  *
       
    11  * Permission is hereby granted, without written agreement and without
       
    12  * license or royalty fees, to use, copy, modify, and distribute this
       
    13  * software and to distribute modified versions of this software for any
       
    14  * purpose, provided that the above copyright notice and the following
       
    15  * two paragraphs appear in all copies of this software.
       
    16  *
       
    17  * In no event shall Paul Falstad or the Zsh Development Group be liable
       
    18  * to any party for direct, indirect, special, incidental, or consequential
       
    19  * damages arising out of the use of this software and its documentation,
       
    20  * even if Paul Falstad and the Zsh Development Group have been advised of
       
    21  * the possibility of such damage.
       
    22  *
       
    23  * Paul Falstad and the Zsh Development Group specifically disclaim any
       
    24  * warranties, including, but not limited to, the implied warranties of
       
    25  * merchantability and fitness for a particular purpose.  The software
       
    26  * provided hereunder is on an "as is" basis, and Paul Falstad and the
       
    27  * Zsh Development Group have no obligation to provide maintenance,
       
    28  * support, updates, enhancements, or modifications.
       
    29  *
       
    30  */
       
    31 
       
    32 #include "zsh.mdh"
       
    33 #include "exec.pro"
       
    34 
       
    35 #ifdef __SYMBIAN32__
       
    36 #ifdef __WINSCW__
       
    37 #pragma warn_unusedarg off
       
    38 #pragma warn_possunwant off
       
    39 #endif//__WINSCW__
       
    40 #endif//__SYMBIAN32__
       
    41 
       
    42 #ifdef __SYMBIAN32__
       
    43 #include <pthread.h>
       
    44 #include <sys/param.h>
       
    45 #include <sys/select.h>
       
    46 #include <sys/stat.h>
       
    47 #include <stdlib.h>
       
    48 #include "dummy.h"
       
    49 #endif //__SYMBIAN32__
       
    50 
       
    51 #ifdef __SYMBIAN32__
       
    52 typedef struct
       
    53 	{
       
    54 	Eprog p;
       
    55 	int dont_change_job;
       
    56 	int exiting;	
       
    57 	} st_exec;	
       
    58 #endif //	__SYMBIAN32__
       
    59 
       
    60 /* used to suppress ERREXIT and trapping of SIGZERR, SIGEXIT. */
       
    61 
       
    62 /**/
       
    63 int noerrexit;
       
    64 
       
    65 /* suppress error messages */
       
    66  
       
    67 /**/
       
    68 mod_export int noerrs;
       
    69  
       
    70 /* do not save history on exec and exit */
       
    71 
       
    72 /**/
       
    73 int nohistsave;
       
    74  
       
    75 /* error/break flag */
       
    76  
       
    77 /**/
       
    78 mod_export int errflag;
       
    79  
       
    80 /* Status of return from a trap */
       
    81  
       
    82 /**/
       
    83 int trapreturn;
       
    84  
       
    85 /* != 0 if this is a subshell */
       
    86  
       
    87 /**/
       
    88 int subsh;
       
    89  
       
    90 /* != 0 if we have a return pending */
       
    91  
       
    92 /**/
       
    93 mod_export int retflag;
       
    94 
       
    95 /**/
       
    96 long lastval2;
       
    97  
       
    98 /* The table of file descriptors.  A table element is zero if the  *
       
    99  * corresponding fd is not used by the shell.  It is greater than  *
       
   100  * 1 if the fd is used by a <(...) or >(...) substitution and 1 if *
       
   101  * it is an internal file descriptor which must be closed before   *
       
   102  * executing an external command.  The first ten elements of the   *
       
   103  * table is not used.  A table element is set by movefd and cleard *
       
   104  * by zclose.                                                      */
       
   105 
       
   106 /**/
       
   107 char *fdtable;
       
   108 
       
   109 /* The allocated size of fdtable */
       
   110 
       
   111 /**/
       
   112 int fdtable_size;
       
   113 
       
   114 /* The highest fd that marked with nonzero in fdtable */
       
   115 
       
   116 /**/
       
   117 int max_zsh_fd;
       
   118 
       
   119 /* input fd from the coprocess */
       
   120 
       
   121 /**/
       
   122 mod_export int coprocin;
       
   123 
       
   124 /* output fd from the coprocess */
       
   125 
       
   126 /**/
       
   127 mod_export int coprocout;
       
   128 
       
   129 /* != 0 if the line editor is active */
       
   130 
       
   131 /**/
       
   132 mod_export int zleactive;
       
   133 
       
   134 /* pid of process undergoing 'process substitution' */
       
   135  
       
   136 /**/
       
   137 pid_t cmdoutpid;
       
   138  
       
   139 /* exit status of process undergoing 'process substitution' */
       
   140  
       
   141 /**/
       
   142 int cmdoutval;
       
   143 
       
   144 /* The context in which a shell function is called, see SFC_* in zsh.h. */ 
       
   145 
       
   146 /**/
       
   147 mod_export int sfcontext;
       
   148 
       
   149 /* Stack to save some variables before executing a signal handler function */
       
   150 
       
   151 /**/
       
   152 struct execstack *exstack;
       
   153 
       
   154 /* Stack with names of functions currently active. */
       
   155 
       
   156 /**/
       
   157 mod_export Funcstack funcstack;
       
   158 
       
   159 #define execerr() if (!forked) { lastval = 1; goto done; } else _exit(1)
       
   160 
       
   161 static LinkList args;
       
   162 static int doneps4;
       
   163 static char *STTYval;
       
   164 
       
   165 /* Execution functions. */
       
   166 
       
   167 static int (*execfuncs[WC_COUNT-WC_CURSH]) _((Estate, int)) = {
       
   168     execcursh, exectime, execfuncdef, execfor, execselect,
       
   169     execwhile, execrepeat, execcase, execif, execcond,
       
   170     execarith, execautofn, exectry
       
   171 };
       
   172 
       
   173 /* structure for command builtin for when it is used with -v or -V */
       
   174 static struct builtin commandbn =
       
   175     BUILTIN(0, 0, bin_whence, 0, -1, BIN_COMMAND, "vV", NULL);
       
   176 
       
   177 
       
   178 /* parse string into a list */
       
   179 
       
   180 /**/
       
   181 mod_export Eprog
       
   182 parse_string(char *s)
       
   183 {
       
   184     Eprog p;
       
   185     int oldlineno = lineno;
       
   186 
       
   187     lexsave();
       
   188     inpush(s, INP_LINENO, NULL);
       
   189     strinbeg(0);
       
   190     lineno = 1;
       
   191     p = parse_list();
       
   192     lineno = oldlineno;
       
   193     if (tok == LEXERR && !lastval)
       
   194 	lastval = 1;
       
   195     strinend();
       
   196     inpop();
       
   197     lexrestore();
       
   198     return p;
       
   199 }
       
   200 
       
   201 /**/
       
   202 #ifdef HAVE_GETRLIMIT
       
   203 
       
   204 /* the resource limits for the shell and its children */
       
   205 
       
   206 /**/
       
   207 mod_export struct rlimit current_limits[RLIM_NLIMITS], limits[RLIM_NLIMITS];
       
   208  
       
   209 /**/
       
   210 mod_export int
       
   211 zsetlimit(int limnum, char *nam)
       
   212 {
       
   213     if (limits[limnum].rlim_max != current_limits[limnum].rlim_max ||
       
   214 	limits[limnum].rlim_cur != current_limits[limnum].rlim_cur) {
       
   215 	if (setrlimit(limnum, limits + limnum)) {
       
   216 	    if (nam)
       
   217 		zwarnnam(nam, "setrlimit failed: %e", NULL, errno);
       
   218 	    return -1;
       
   219 	}
       
   220 	current_limits[limnum] = limits[limnum];
       
   221     }
       
   222     return 0;
       
   223 }
       
   224 
       
   225 /**/
       
   226 mod_export int
       
   227 setlimits(char *nam)
       
   228 {
       
   229     int limnum;
       
   230     int ret = 0;
       
   231 
       
   232     for (limnum = 0; limnum < RLIM_NLIMITS; limnum++)
       
   233 	if (zsetlimit(limnum, nam))
       
   234 	    ret++;
       
   235     return ret;
       
   236 }
       
   237 
       
   238 /**/
       
   239 #endif /* HAVE_GETRLIMIT */
       
   240 
       
   241 /* fork and set limits */
       
   242 
       
   243 /**/
       
   244 #ifndef __SYMBIAN32__
       
   245 static pid_t
       
   246 zfork(struct timeval *tv)
       
   247 {
       
   248     pid_t pid;
       
   249     struct timezone dummy_tz;
       
   250 
       
   251     /*
       
   252      * Is anybody willing to explain this test?
       
   253      */
       
   254     if (thisjob != -1 && thisjob >= jobtabsize - 1 && !expandjobtab()) {
       
   255 	zerr("job table full", NULL, 0);
       
   256 	return -1;
       
   257     }
       
   258     if (tv)
       
   259 	gettimeofday(tv, &dummy_tz);
       
   260     pid = fork();
       
   261     if (pid == -1) {
       
   262 	zerr("fork failed: %e", NULL, errno);
       
   263 	return -1;
       
   264     }
       
   265 #ifdef HAVE_GETRLIMIT
       
   266     if (!pid)
       
   267 	/* set resource limits for the child process */
       
   268 	setlimits(NULL);
       
   269 #endif
       
   270     return pid;
       
   271 }
       
   272 #endif //__SYMBIAN32__
       
   273 
       
   274 /*
       
   275  *   Allen Edeln gebiet ich Andacht,
       
   276  *   Hohen und Niedern von Heimdalls Geschlecht;
       
   277  *   Ich will list_pipe's Wirken kuenden
       
   278  *   Die aeltesten Sagen, der ich mich entsinne...
       
   279  *
       
   280  * In most shells, if you do something like:
       
   281  *
       
   282  *   cat foo | while read a; do grep $a bar; done
       
   283  *
       
   284  * the shell forks and executes the loop in the sub-shell thus created.
       
   285  * In zsh this traditionally executes the loop in the current shell, which
       
   286  * is nice to have if the loop does something to change the shell, like
       
   287  * setting parameters or calling builtins.
       
   288  * Putting the loop in a sub-shell makes life easy, because the shell only
       
   289  * has to put it into the job-structure and then treats it as a normal
       
   290  * process. Suspending and interrupting is no problem then.
       
   291  * Some years ago, zsh either couldn't suspend such things at all, or
       
   292  * it got really messed up when users tried to do it. As a solution, we
       
   293  * implemented the list_pipe-stuff, which has since then become a reason
       
   294  * for many nightmares.
       
   295  * Pipelines like the one above are executed by the functions in this file
       
   296  * which call each other (and sometimes recursively). The one above, for
       
   297  * example would lead to a function call stack roughly like:
       
   298  *
       
   299  *  execlist->execpline->execcmd->execwhile->execlist->execpline
       
   300  *
       
   301  * (when waiting for the grep, ignoring execpline2 for now). At this time,
       
   302  * zsh has built two job-table entries for it: one for the cat and one for
       
   303  * the grep. If the user hits ^Z at this point (and jobbing is used), the 
       
   304  * shell is notified that the grep was suspended. The list_pipe flag is
       
   305  * used to tell the execpline where it was waiting that it was in a pipeline
       
   306  * with a shell construct at the end (which may also be a shell function or
       
   307  * several other things). When zsh sees the suspended grep, it forks to let
       
   308  * the sub-shell execute the rest of the while loop. The parent shell walks
       
   309  * up in the function call stack to the first execpline. There it has to find
       
   310  * out that it has just forked and then has to add information about the sub-
       
   311  * shell (its pid and the text for it) in the job entry of the cat. The pid
       
   312  * is passed down in the list_pipe_pid variable.
       
   313  * But there is a problem: the suspended grep is a child of the parent shell
       
   314  * and can't be adopted by the sub-shell. So the parent shell also has to 
       
   315  * keep the information about this process (more precisely: this pipeline)
       
   316  * by keeping the job table entry it created for it. The fact that there
       
   317  * are two jobs which have to be treated together is remembered by setting
       
   318  * the STAT_SUPERJOB flag in the entry for the cat-job (which now also
       
   319  * contains a process-entry for the whole loop -- the sub-shell) and by
       
   320  * setting STAT_SUBJOB in the job of the grep-job. With that we can keep
       
   321  * sub-jobs from being displayed and we can handle an fg/bg on the super-
       
   322  * job correctly. When the super-job is continued, the shell also wakes up
       
   323  * the sub-job. But then, the grep will exit sometime. Now the parent shell
       
   324  * has to remember not to try to wake it up again (in case of another ^Z).
       
   325  * It also has to wake up the sub-shell (which suspended itself immediately
       
   326  * after creation), so that the rest of the loop is executed by it.
       
   327  * But there is more: when the sub-shell is created, the cat may already
       
   328  * have exited, so we can't put the sub-shell in the process group of it.
       
   329  * In this case, we put the sub-shell in the process group of the parent
       
   330  * shell and in any case, the sub-shell has to put all commands executed
       
   331  * by it into its own process group, because only this way the parent
       
   332  * shell can control them since it only knows the process group of the sub-
       
   333  * shell. Of course, this information is also important when putting a job
       
   334  * in the foreground, where we have to attach its process group to the
       
   335  * controlling tty.
       
   336  * All this is made more difficult because we have to handle return values
       
   337  * correctly. If the grep is signaled, its exit status has to be propagated
       
   338  * back to the parent shell which needs it to set the exit status of the
       
   339  * super-job. And of course, when the grep is signaled (including ^C), the
       
   340  * loop has to be stopped, etc.
       
   341  * The code for all this is distributed over three files (exec.c, jobs.c,
       
   342  * and signals.c) and none of them is a simple one. So, all in all, there
       
   343  * may still be bugs, but considering the complexity (with race conditions,
       
   344  * signal handling, and all that), this should probably be expected.
       
   345  */
       
   346 
       
   347 /**/
       
   348 int list_pipe = 0, simple_pline = 0;
       
   349 
       
   350 static pid_t list_pipe_pid;
       
   351 static struct timeval list_pipe_start;
       
   352 static int nowait, pline_level = 0;
       
   353 static int list_pipe_child = 0, list_pipe_job;
       
   354 static char list_pipe_text[JOBTEXTSIZE];
       
   355 
       
   356 /* execute a current shell command */
       
   357 
       
   358 /**/
       
   359 static int
       
   360 execcursh(Estate state, int do_exec)
       
   361 {
       
   362     Wordcode end = state->pc + WC_CURSH_SKIP(state->pc[-1]);
       
   363 
       
   364     /* Skip word only used for try/always */
       
   365     state->pc++;
       
   366 
       
   367     if (!list_pipe && thisjob != list_pipe_job && !hasprocs(thisjob))
       
   368 	deletejob(jobtab + thisjob);
       
   369     cmdpush(CS_CURSH);
       
   370     execlist(state, 1, do_exec);
       
   371     cmdpop();
       
   372 
       
   373     state->pc = end;
       
   374 
       
   375     return lastval;
       
   376 }
       
   377 
       
   378 /* execve after handling $_ and #! */
       
   379 
       
   380 #define POUNDBANGLIMIT 64
       
   381 
       
   382 /**/
       
   383 static int
       
   384 zexecve(char *pth, char **argv)
       
   385 {
       
   386     int eno =0;
       
   387 #ifndef __SYMBIAN32__
       
   388     static char buf[PATH_MAX * 2];
       
   389     char **eep;
       
   390 
       
   391     unmetafy(pth, NULL);
       
   392     for (eep = argv; *eep; eep++)
       
   393 	if (*eep != pth)
       
   394 	    unmetafy(*eep, NULL);
       
   395     buf[0] = '_';
       
   396     buf[1] = '=';
       
   397     if (*pth == '/')
       
   398 	strcpy(buf + 2, pth);
       
   399     else
       
   400 	sprintf(buf + 2, "%s/%s", pwd, pth);
       
   401     zputenv(buf);
       
   402     closedumps();
       
   403     execve(pth, argv, environ);
       
   404 
       
   405     /* If the execve returns (which in general shouldn't happen),   *
       
   406      * then check for an errno equal to ENOEXEC.  This errno is set *
       
   407      * if the process file has the appropriate access permission,   *
       
   408      * but has an invalid magic number in its header.               */
       
   409     if ((eno = errno) == ENOEXEC) {
       
   410 	char execvebuf[POUNDBANGLIMIT + 1], *ptr, *ptr2, *argv0;
       
   411 	int fd, ct, t0;
       
   412 
       
   413 	if ((fd = open(pth, O_RDONLY|O_NOCTTY)) >= 0) {
       
   414 	    argv0 = *argv;
       
   415 	    *argv = pth;
       
   416 	    ct = read(fd, execvebuf, POUNDBANGLIMIT);
       
   417 	    close(fd);
       
   418 	    if (ct > 0) {
       
   419 		if (execvebuf[0] == '#') {
       
   420 		    if (execvebuf[1] == '!') {
       
   421 			for (t0 = 0; t0 != ct; t0++)
       
   422 			    if (execvebuf[t0] == '\n')
       
   423 				break;
       
   424 			while (inblank(execvebuf[t0]))
       
   425 			    execvebuf[t0--] = '\0';
       
   426 			execvebuf[POUNDBANGLIMIT] = '\0';
       
   427 			for (ptr = execvebuf + 2; *ptr && *ptr == ' '; ptr++);
       
   428 			for (ptr2 = ptr; *ptr && *ptr != ' '; ptr++);
       
   429 			if (*ptr) {
       
   430 			    *ptr = '\0';
       
   431 			    argv[-2] = ptr2;
       
   432 			    argv[-1] = ptr + 1;
       
   433 			    execve(ptr2, argv - 2, environ);
       
   434 			} else {
       
   435 			    argv[-1] = ptr2;
       
   436 			    execve(ptr2, argv - 1, environ);
       
   437 			}
       
   438 		    } else {
       
   439 			argv[-1] = "sh";
       
   440 			execve("/bin/sh", argv - 1, environ);
       
   441 		    }
       
   442 		} else {
       
   443 		    for (t0 = 0; t0 != ct; t0++)
       
   444 			if (!execvebuf[t0])
       
   445 			    break;
       
   446 		    if (t0 == ct) {
       
   447 			argv[-1] = "sh";
       
   448 			execve("/bin/sh", argv - 1, environ);
       
   449 		    }
       
   450 		}
       
   451 	    } else
       
   452 		eno = errno;
       
   453 	    *argv = argv0;
       
   454 	} else
       
   455 	    eno = errno;
       
   456     }
       
   457     /* restore the original arguments and path but do not bother with *
       
   458      * null characters as these cannot be passed to external commands *
       
   459      * anyway.  So the result is truncated at the first null char.    */
       
   460     pth = metafy(pth, -1, META_NOALLOC);
       
   461     for (eep = argv; *eep; eep++)
       
   462 	if (*eep != pth)
       
   463 	    (void) metafy(*eep, -1, META_NOALLOC);
       
   464 #endif//__SYMBIAN32__
       
   465 	
       
   466     return eno;
       
   467 }
       
   468 
       
   469 #define MAXCMDLEN (PATH_MAX*4)
       
   470 
       
   471 /* test whether we really want to believe the error number */
       
   472 
       
   473 /**/
       
   474 static int
       
   475 isgooderr(int e, char *dir)
       
   476 {
       
   477     /*
       
   478      * Maybe the directory was unreadable, or maybe it wasn't
       
   479      * even a directory. 
       
   480      */
       
   481     return ((e != EACCES || !access(dir, X_OK)) &&
       
   482 	    e != ENOENT && e != ENOTDIR); 
       
   483 }
       
   484 
       
   485 /* execute an external command */
       
   486 
       
   487 /**/
       
   488 void
       
   489 execute(UNUSED(Cmdnam cmdname), int dash, int defpath)
       
   490 {
       
   491     Cmdnam cn;
       
   492     char buf[MAXCMDLEN], buf2[MAXCMDLEN];
       
   493     char *s, *z, *arg0;
       
   494     char **argv, **pp;
       
   495     int eno = 0, ee;
       
   496 
       
   497     arg0 = (char *) peekfirst(args);
       
   498     if (isset(RESTRICTED) && (strchr(arg0, '/') || defpath)) {
       
   499 	zerr("%s: restricted", arg0, 0);
       
   500 	_exit(1);
       
   501     }
       
   502 
       
   503     /* If the parameter STTY is set in the command's environment, *
       
   504      * we first run the stty command with the value of this       *
       
   505      * parameter as it arguments.                                 */
       
   506     if ((s = STTYval) && isatty(0) && (GETPGRP() == getpid())) {
       
   507 	LinkList exargs = args;
       
   508 	char *t = tricat("stty", " ", s);
       
   509 
       
   510 	STTYval = 0;	/* this prevents infinite recursion */
       
   511 	zsfree(s);
       
   512 	args = NULL;
       
   513 	execstring(t, 1, 0);
       
   514 	zsfree(t);
       
   515 	args = exargs;
       
   516     } else if (s) {
       
   517 	STTYval = 0;
       
   518 	zsfree(s);
       
   519     }
       
   520 
       
   521     /* If ARGV0 is in the commands environment, we use *
       
   522      * that as argv[0] for this external command       */
       
   523     if (unset(RESTRICTED) && (z = zgetenv("ARGV0"))) {
       
   524 	setdata(firstnode(args), (void *) ztrdup(z));
       
   525 	delenvvalue(z - 6);
       
   526     } else if (dash) {
       
   527     /* Else if the pre-command `-' was given, we add `-' *
       
   528      * to the front of argv[0] for this command.         */
       
   529 	sprintf(buf2, "-%s", arg0);
       
   530 	setdata(firstnode(args), (void *) ztrdup(buf2));
       
   531     }
       
   532 
       
   533     argv = makecline(args);
       
   534     closem(3);
       
   535     child_unblock();
       
   536     if ((int) strlen(arg0) >= PATH_MAX) {
       
   537 	zerr("command too long: %s", arg0, 0);
       
   538 	_exit(1);
       
   539     }
       
   540     for (s = arg0; *s; s++)
       
   541 	if (*s == '/') {
       
   542 	    errno = zexecve(arg0, argv);
       
   543 	    if (arg0 == s || unset(PATHDIRS) ||
       
   544 		(arg0[0] == '.' && (arg0 + 1 == s ||
       
   545 				    (arg0[1] == '.' && arg0 + 2 == s)))) {
       
   546 		zerr("%e: %s", arg0, errno);
       
   547 		_exit((errno == EACCES || errno == ENOEXEC) ? 126 : 127);
       
   548 	    }
       
   549 	    break;
       
   550 	}
       
   551 
       
   552     /* for command -p, search the default path */ 
       
   553     if (defpath) {
       
   554 	char *s, pbuf[PATH_MAX];
       
   555 	char *dptr, *pe, *ps = DEFAULT_PATH;
       
   556 
       
   557 	for(;ps;ps = pe ? pe+1 : NULL) {
       
   558 	    pe = strchr(ps, ':');
       
   559 	    if (*ps == '/') {
       
   560 		s = pbuf;
       
   561 		if (pe)
       
   562 		    struncpy(&s, ps, pe-ps);
       
   563 		else
       
   564 		    strucpy(&s, ps);
       
   565 		*s++ = '/';
       
   566 		if ((s - pbuf) + strlen(arg0) >= PATH_MAX)
       
   567 		    continue;
       
   568 		strucpy(&s, arg0);
       
   569 		if (iscom(pbuf))
       
   570 		    break;
       
   571 	    }
       
   572 	}
       
   573 
       
   574 	if (!ps) {
       
   575 	    zerr("command not found: %s", arg0, 0);
       
   576 	    _exit(127);
       
   577 	}
       
   578 
       
   579 	ee = zexecve(pbuf, argv);
       
   580 
       
   581 	if ((dptr = strrchr(pbuf, '/')))
       
   582 	    *dptr = '\0';
       
   583 	if (isgooderr(ee, *pbuf ? pbuf : "/"))
       
   584 	    eno = ee;
       
   585 
       
   586     } else {
       
   587    
       
   588 	if ((cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0))) {
       
   589 	    char nn[PATH_MAX], *dptr;
       
   590 
       
   591 	    if (cn->flags & HASHED)
       
   592 		strcpy(nn, cn->u.cmd);
       
   593 	    else {
       
   594 		for (pp = path; pp < cn->u.name; pp++)
       
   595 		    if (!**pp || (**pp == '.' && (*pp)[1] == '\0')) {
       
   596 			ee = zexecve(arg0, argv);
       
   597 			if (isgooderr(ee, *pp))
       
   598 			    eno = ee;
       
   599 		    } else if (**pp != '/') {
       
   600 			z = buf;
       
   601 			strucpy(&z, *pp);
       
   602 			*z++ = '/';
       
   603 			strcpy(z, arg0);
       
   604 			ee = zexecve(buf, argv);
       
   605 			if (isgooderr(ee, *pp))
       
   606 			    eno = ee;
       
   607 		    }
       
   608 		strcpy(nn, cn->u.name ? *(cn->u.name) : "");
       
   609 		strcat(nn, "/");
       
   610 		strcat(nn, cn->nam);
       
   611 	    }
       
   612 	    ee = zexecve(nn, argv);
       
   613 
       
   614 	    if ((dptr = strrchr(nn, '/')))
       
   615 		*dptr = '\0';
       
   616 	    if (isgooderr(ee, *nn ? nn : "/"))
       
   617 		eno = ee;
       
   618 	}
       
   619 	for (pp = path; *pp; pp++)
       
   620 	    if (!(*pp)[0] || ((*pp)[0] == '.' && !(*pp)[1])) {
       
   621 		ee = zexecve(arg0, argv);
       
   622 		if (isgooderr(ee, *pp))
       
   623 		    eno = ee;
       
   624 	    } else {
       
   625 		z = buf;
       
   626 		strucpy(&z, *pp);
       
   627 		*z++ = '/';
       
   628 		strcpy(z, arg0);
       
   629 		ee = zexecve(buf, argv);
       
   630 		if (isgooderr(ee, *pp))
       
   631 		    eno = ee;
       
   632 	    }
       
   633     }
       
   634 
       
   635     if (eno)
       
   636 	zerr("%e: %s", arg0, eno);
       
   637     else
       
   638 	zerr("command not found: %s", arg0, 0);
       
   639     _exit((eno == EACCES || eno == ENOEXEC) ? 126 : 127);
       
   640 }
       
   641 
       
   642 #define RET_IF_COM(X) { if (iscom(X)) return docopy ? dupstring(X) : arg0; }
       
   643 
       
   644 /*
       
   645  * Get the full pathname of an external command.
       
   646  * If the second argument is zero, return the first argument if found;
       
   647  * if non-zero, return the path using heap memory.  (RET_IF_COM(X), above).
       
   648  */
       
   649 
       
   650 /**/
       
   651 mod_export char *
       
   652 findcmd(char *arg0, int docopy)
       
   653 {
       
   654     char **pp;
       
   655     char *z, *s, buf[MAXCMDLEN];
       
   656     Cmdnam cn;
       
   657 
       
   658     cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0);
       
   659     if (!cn && isset(HASHCMDS))
       
   660 	cn = hashcmd(arg0, path);
       
   661     if ((int) strlen(arg0) > PATH_MAX)
       
   662 	return NULL;
       
   663     for (s = arg0; *s; s++)
       
   664 	if (*s == '/') {
       
   665 	    RET_IF_COM(arg0);
       
   666 	    if (arg0 == s || unset(PATHDIRS)) {
       
   667 		return NULL;
       
   668 	    }
       
   669 	    break;
       
   670 	}
       
   671     if (cn) {
       
   672 	char nn[PATH_MAX];
       
   673 
       
   674 	if (cn->flags & HASHED)
       
   675 	    strcpy(nn, cn->u.cmd);
       
   676 	else {
       
   677 	    for (pp = path; pp < cn->u.name; pp++)
       
   678 		if (**pp != '/') {
       
   679 		    z = buf;
       
   680 		    if (**pp) {
       
   681 			strucpy(&z, *pp);
       
   682 			*z++ = '/';
       
   683 		    }
       
   684 		    strcpy(z, arg0);
       
   685 		    RET_IF_COM(buf);
       
   686 		}
       
   687 	    strcpy(nn, cn->u.name ? *(cn->u.name) : "");
       
   688 	    strcat(nn, "/");
       
   689 	    strcat(nn, cn->nam);
       
   690 	}
       
   691 	RET_IF_COM(nn);
       
   692     }
       
   693     for (pp = path; *pp; pp++) {
       
   694 	z = buf;
       
   695 	if (**pp) {
       
   696 	    strucpy(&z, *pp);
       
   697 	    *z++ = '/';
       
   698 	}
       
   699 	strcpy(z, arg0);
       
   700 	RET_IF_COM(buf);
       
   701     }
       
   702     return NULL;
       
   703 }
       
   704 
       
   705 /**/
       
   706 int
       
   707 iscom(char *s)
       
   708 {
       
   709     struct stat statbuf;
       
   710     char *us = unmeta(s);
       
   711 
       
   712     return (access(us, X_OK) == 0 && stat(us, &statbuf) >= 0 &&
       
   713 	    S_ISREG(statbuf.st_mode));
       
   714 }
       
   715 
       
   716 /**/
       
   717 int
       
   718 isreallycom(Cmdnam cn)
       
   719 {
       
   720     char fullnam[MAXCMDLEN];
       
   721 
       
   722     if (cn->flags & HASHED)
       
   723 	strcpy(fullnam, cn->u.cmd);
       
   724     else if (!cn->u.name)
       
   725 	return 0;
       
   726     else {
       
   727 	strcpy(fullnam, *(cn->u.name));
       
   728 	strcat(fullnam, "/");
       
   729 	strcat(fullnam, cn->nam);
       
   730     }
       
   731     return iscom(fullnam);
       
   732 }
       
   733 
       
   734 /**/
       
   735 int
       
   736 isrelative(char *s)
       
   737 {
       
   738     if (*s != '/')
       
   739 	return 1;
       
   740     for (; *s; s++)
       
   741 	if (*s == '.' && s[-1] == '/' &&
       
   742 	    (s[1] == '/' || s[1] == '\0' ||
       
   743 	     (s[1] == '.' && (s[2] == '/' || s[2] == '\0'))))
       
   744 	    return 1;
       
   745     return 0;
       
   746 }
       
   747 
       
   748 /**/
       
   749 mod_export Cmdnam
       
   750 hashcmd(char *arg0, char **pp)
       
   751 {
       
   752     Cmdnam cn;
       
   753     char *s, buf[PATH_MAX];
       
   754     char **pq;
       
   755 
       
   756     for (; *pp; pp++)
       
   757 	if (**pp == '/') {
       
   758 	    s = buf;
       
   759 	    strucpy(&s, *pp);
       
   760 	    *s++ = '/';
       
   761 	    if ((s - buf) + strlen(arg0) >= PATH_MAX)
       
   762 		continue;
       
   763 	    strcpy(s, arg0);
       
   764 	    if (iscom(buf))
       
   765 		break;
       
   766 	}
       
   767 
       
   768     if (!*pp)
       
   769 	return NULL;
       
   770 
       
   771     cn = (Cmdnam) zshcalloc(sizeof *cn);
       
   772     cn->flags = 0;
       
   773     cn->u.name = pp;
       
   774     cmdnamtab->addnode(cmdnamtab, ztrdup(arg0), cn);
       
   775 
       
   776     if (isset(HASHDIRS)) {
       
   777 	for (pq = pathchecked; pq <= pp; pq++)
       
   778 	    hashdir(pq);
       
   779 	pathchecked = pp + 1;
       
   780     }
       
   781 
       
   782     return cn;
       
   783 }
       
   784 
       
   785 /* execute a string */
       
   786 
       
   787 /**/
       
   788 mod_export void
       
   789 execstring(char *s, int dont_change_job, int exiting)
       
   790 {
       
   791     Eprog prog;
       
   792 
       
   793     pushheap();
       
   794     if ((prog = parse_string(s)))
       
   795 	execode(prog, dont_change_job, exiting);
       
   796     popheap();
       
   797 }
       
   798 
       
   799 
       
   800 #ifdef __SYMBIAN32__	
       
   801 mod_export
       
   802 void* execode_wrap(void* any)
       
   803 	{
       
   804 		st_exec *st=(st_exec*)any;
       
   805 		if(st)
       
   806 			execode(st->p, st->dont_change_job, st->exiting);
       
   807 		return NULL;
       
   808 	}
       
   809 #endif //__SYMBIAN32__	
       
   810 	
       
   811 /**/
       
   812 mod_export void
       
   813 execode(Eprog p, int dont_change_job, int exiting)
       
   814 {
       
   815     struct estate s;
       
   816 
       
   817     s.prog = p;
       
   818     s.pc = p->prog;
       
   819     s.strs = p->strs;
       
   820     useeprog(p);		/* Mark as in use */
       
   821 
       
   822     execlist(&s, dont_change_job, exiting);
       
   823 
       
   824     freeeprog(p);		/* Free if now unused */
       
   825 }
       
   826 
       
   827 /* Execute a simplified command. This is used to execute things that
       
   828  * will run completely in the shell, so that we can by-pass all that
       
   829  * nasty job-handling and redirection stuff in execpline and execcmd. */
       
   830 
       
   831 /**/
       
   832 static int
       
   833 execsimple(Estate state)
       
   834 {
       
   835     wordcode code = *state->pc++;
       
   836     int lv;
       
   837 
       
   838     if (errflag)
       
   839 	return (lastval = 1);
       
   840 
       
   841     /* In evaluated traps, don't modify the line number. */
       
   842     if ((!intrap || trapisfunc) && !ineval && code)
       
   843 	lineno = code - 1;
       
   844 
       
   845     code = wc_code(*state->pc++);
       
   846 
       
   847     if (code == WC_ASSIGN) {
       
   848 	cmdoutval = 0;
       
   849 	addvars(state, state->pc - 1, 0);
       
   850 	if (isset(XTRACE)) {
       
   851 	    fputc('\n', xtrerr);
       
   852 	    fflush(xtrerr);
       
   853 	}
       
   854 	lv = (lastval ? lastval : cmdoutval);
       
   855     } else
       
   856 	lv = (execfuncs[code - WC_CURSH])(state, 0);
       
   857     	
       
   858     return lastval = lv;
       
   859 }
       
   860 
       
   861 /* Main routine for executing a list.                                *
       
   862  * exiting means that the (sub)shell we are in is a definite goner   *
       
   863  * after the current list is finished, so we may be able to exec the *
       
   864  * last command directly instead of forking.  If dont_change_job is  *
       
   865  * nonzero, then restore the current job number after executing the  *
       
   866  * list.                                                             */
       
   867 
       
   868 /**/
       
   869 void
       
   870 execlist(Estate state, int dont_change_job, int exiting)
       
   871 {
       
   872     static int donetrap;
       
   873     Wordcode next;
       
   874     wordcode code;
       
   875     int ret, cj, csp, ltype;
       
   876     int old_pline_level, old_list_pipe, oldlineno;
       
   877     /*
       
   878      * ERREXIT only forces the shell to exit if the last command in a &&
       
   879      * or || fails.  This is the case even if an earlier command is a
       
   880      * shell function or other current shell structure, so we have to set
       
   881      * noerrexit here if the sublist is not of type END.
       
   882      */
       
   883     int oldnoerrexit = noerrexit;
       
   884 
       
   885     cj = thisjob;
       
   886     old_pline_level = pline_level;
       
   887     old_list_pipe = list_pipe;
       
   888     oldlineno = lineno;
       
   889 
       
   890     if (sourcelevel && unset(SHINSTDIN))
       
   891 	pline_level = list_pipe = 0;
       
   892 
       
   893     /* Loop over all sets of comands separated by newline, *
       
   894      * semi-colon or ampersand (`sublists').               */
       
   895     code = *state->pc++;
       
   896     while (wc_code(code) == WC_LIST && !breaks && !retflag) {
       
   897 	ltype = WC_LIST_TYPE(code);
       
   898 	csp = cmdsp;
       
   899 
       
   900 	if (ltype & Z_SIMPLE) {
       
   901 	    next = state->pc + WC_LIST_SKIP(code);
       
   902 	    execsimple(state);
       
   903 	    state->pc = next;
       
   904 	    goto sublist_done;
       
   905 	}
       
   906 	/* Reset donetrap:  this ensures that a trap is only *
       
   907 	 * called once for each sublist that fails.          */
       
   908 	donetrap = 0;
       
   909 
       
   910 	/* Loop through code followed by &&, ||, or end of sublist. */
       
   911 	code = *state->pc++;
       
   912 	while (wc_code(code) == WC_SUBLIST) {
       
   913 	    next = state->pc + WC_SUBLIST_SKIP(code);
       
   914 	    if (!oldnoerrexit)
       
   915 		noerrexit = (WC_SUBLIST_TYPE(code) != WC_SUBLIST_END);
       
   916 	    switch (WC_SUBLIST_TYPE(code)) {
       
   917 	    case WC_SUBLIST_END:
       
   918 		/* End of sublist; just execute, ignoring status. */
       
   919 		if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE)
       
   920 		    execsimple(state);
       
   921 		else
       
   922 		    execpline(state, code, ltype, (ltype & Z_END) && exiting);
       
   923 		state->pc = next;
       
   924 		goto sublist_done;
       
   925 		break;
       
   926 	    case WC_SUBLIST_AND:
       
   927 		/* If the return code is non-zero, we skip pipelines until *
       
   928 		 * we find a sublist followed by ORNEXT.                   */
       
   929 		if ((ret = ((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) ?
       
   930 			    execsimple(state) :
       
   931 			    execpline(state, code, Z_SYNC, 0)))) {
       
   932 		    state->pc = next;
       
   933 		    code = *state->pc++;
       
   934 		    next = state->pc + WC_SUBLIST_SKIP(code);
       
   935 		    while (wc_code(code) == WC_SUBLIST &&
       
   936 			   WC_SUBLIST_TYPE(code) == WC_SUBLIST_AND) {
       
   937 			state->pc = next;
       
   938 			code = *state->pc++;
       
   939 			next = state->pc + WC_SUBLIST_SKIP(code);
       
   940 		    }
       
   941 		    if (wc_code(code) != WC_SUBLIST) {
       
   942 			/* We've skipped to the end of the list, not executing *
       
   943 			 * the final pipeline, so don't perform error handling *
       
   944 			 * for this sublist.                                   */
       
   945 			donetrap = 1;
       
   946 			goto sublist_done;
       
   947 		    } else if (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END) {
       
   948 			donetrap = 1;
       
   949 			/*
       
   950 			 * Treat this in the same way as if we reached
       
   951 			 * the end of the sublist normally.
       
   952 			 */
       
   953 			state->pc = next;
       
   954 			goto sublist_done;
       
   955 		    }
       
   956 		}
       
   957 		cmdpush(CS_CMDAND);
       
   958 		break;
       
   959 	    case WC_SUBLIST_OR:
       
   960 		/* If the return code is zero, we skip pipelines until *
       
   961 		 * we find a sublist followed by ANDNEXT.              */
       
   962 		if (!(ret = ((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) ?
       
   963 			     execsimple(state) :
       
   964 			     execpline(state, code, Z_SYNC, 0)))) {
       
   965 		    state->pc = next;
       
   966 		    code = *state->pc++;
       
   967 		    next = state->pc + WC_SUBLIST_SKIP(code);
       
   968 		    while (wc_code(code) == WC_SUBLIST &&
       
   969 			   WC_SUBLIST_TYPE(code) == WC_SUBLIST_OR) {
       
   970 			state->pc = next;
       
   971 			code = *state->pc++;
       
   972 			next = state->pc + WC_SUBLIST_SKIP(code);
       
   973 		    }
       
   974 		    if (wc_code(code) != WC_SUBLIST) {
       
   975 			/* We've skipped to the end of the list, not executing *
       
   976 			 * the final pipeline, so don't perform error handling *
       
   977 			 * for this sublist.                                   */
       
   978 			donetrap = 1;
       
   979 			goto sublist_done;
       
   980 		    } else if (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END) {
       
   981 			donetrap = 1;
       
   982 			/*
       
   983 			 * Treat this in the same way as if we reached
       
   984 			 * the end of the sublist normally.
       
   985 			 */
       
   986 			state->pc = next;
       
   987 			goto sublist_done;
       
   988 		    }
       
   989 		}
       
   990 		cmdpush(CS_CMDOR);
       
   991 		break;
       
   992 	    }
       
   993 	    state->pc = next;
       
   994 	    code = *state->pc++;
       
   995 	}
       
   996 	state->pc--;
       
   997 sublist_done:
       
   998 
       
   999 	noerrexit = oldnoerrexit;
       
  1000 
       
  1001 	if (sigtrapped[SIGDEBUG]) {
       
  1002 	    exiting = donetrap;
       
  1003 	    ret = lastval;
       
  1004 	    dotrap(SIGDEBUG);
       
  1005 	    lastval = ret;
       
  1006 	    donetrap = exiting;
       
  1007 	    noerrexit = oldnoerrexit;
       
  1008 	}
       
  1009 
       
  1010 	cmdsp = csp;
       
  1011 
       
  1012 	/* Check whether we are suppressing traps/errexit *
       
  1013 	 * (typically in init scripts) and if we haven't  *
       
  1014 	 * already performed them for this sublist.       */
       
  1015 	if (!noerrexit && !donetrap) {
       
  1016 	    if (sigtrapped[SIGZERR] && lastval) {
       
  1017 		dotrap(SIGZERR);
       
  1018 		donetrap = 1;
       
  1019 	    }
       
  1020 	    if (lastval) {
       
  1021 		int errreturn = isset(ERRRETURN) && 
       
  1022 		    (isset(INTERACTIVE) || locallevel || sourcelevel);
       
  1023 		int errexit = isset(ERREXIT) || 
       
  1024 		    (isset(ERRRETURN) && !errreturn);
       
  1025 		if (errexit) {
       
  1026 		    if (sigtrapped[SIGEXIT])
       
  1027 			dotrap(SIGEXIT);
       
  1028 		    if (mypid != getpid())
       
  1029 			_exit(lastval);
       
  1030 		    else
       
  1031 			exit(lastval);
       
  1032 		}
       
  1033 		if (errreturn) {
       
  1034 		    retflag = 1;
       
  1035 		    breaks = loops;
       
  1036 		}
       
  1037 	    }
       
  1038 	}
       
  1039 	if (ltype & Z_END)
       
  1040 	    break;
       
  1041 	code = *state->pc++;
       
  1042     }
       
  1043     pline_level = old_pline_level;
       
  1044     list_pipe = old_list_pipe;
       
  1045     lineno = oldlineno;
       
  1046     if (dont_change_job)
       
  1047 	thisjob = cj;
       
  1048 }
       
  1049 
       
  1050 /* Execute a pipeline.                                                *
       
  1051  * last1 is a flag that this command is the last command in a shell   *
       
  1052  * that is about to exit, so we can exec instead of forking.  It gets *
       
  1053  * passed all the way down to execcmd() which actually makes the      *
       
  1054  * decision.  A 0 is always passed if the command is not the last in  *
       
  1055  * the pipeline.  This function assumes that the sublist is not NULL. *
       
  1056  * If last1 is zero but the command is at the end of a pipeline, we   *
       
  1057  * pass 2 down to execcmd().                                          *
       
  1058  */
       
  1059 
       
  1060 /**/
       
  1061 static int
       
  1062 execpline(Estate state, wordcode slcode, int how, int last1)
       
  1063 {
       
  1064     int ipipe[2], opipe[2];
       
  1065     int pj, newjob;
       
  1066     int old_simple_pline = simple_pline;
       
  1067     int slflags = WC_SUBLIST_FLAGS(slcode);
       
  1068     wordcode code = *state->pc++;
       
  1069     static int lastwj, lpforked;
       
  1070 
       
  1071     if (wc_code(code) != WC_PIPE)
       
  1072 	return lastval = (slflags & WC_SUBLIST_NOT) != 0;
       
  1073     else if (slflags & WC_SUBLIST_NOT)
       
  1074 	last1 = 0;
       
  1075 
       
  1076     pj = thisjob;
       
  1077     ipipe[0] = ipipe[1] = opipe[0] = opipe[1] = 0;
       
  1078     child_block();
       
  1079 
       
  1080     /*
       
  1081      * Get free entry in job table and initialize it.
       
  1082      * This is currently the only call to initjob(), so this
       
  1083      * is also the only place where we can expand the job table
       
  1084      * under us.
       
  1085      */
       
  1086     if ((thisjob = newjob = initjob()) == -1) {
       
  1087 	child_unblock();
       
  1088 	return 1;
       
  1089     }
       
  1090     if (how & Z_TIMED)
       
  1091 	jobtab[thisjob].stat |= STAT_TIMED;
       
  1092 
       
  1093     if (slflags & WC_SUBLIST_COPROC) {
       
  1094 	how = Z_ASYNC;
       
  1095 	if (coprocin >= 0) {
       
  1096 	    zclose(coprocin);
       
  1097 	    zclose(coprocout);
       
  1098 	}
       
  1099 	mpipe(ipipe);
       
  1100 	mpipe(opipe);
       
  1101 	coprocin = ipipe[0];
       
  1102 	coprocout = opipe[1];
       
  1103 	fdtable[coprocin] = fdtable[coprocout] = 0;
       
  1104     }
       
  1105     /* This used to set list_pipe_pid=0 unconditionally, but in things
       
  1106      * like `ls|if true; then sleep 20; cat; fi' where the sleep was
       
  1107      * stopped, the top-level execpline() didn't get the pid for the
       
  1108      * sub-shell because it was overwritten. */
       
  1109     if (!pline_level++) {
       
  1110         list_pipe_pid = 0;
       
  1111 	nowait = 0;
       
  1112 	simple_pline = (WC_PIPE_TYPE(code) == WC_PIPE_END);
       
  1113 	list_pipe_job = newjob;
       
  1114     }
       
  1115     lastwj = lpforked = 0;
       
  1116     execpline2(state, code, how, opipe[0], ipipe[1], last1);
       
  1117     pline_level--;
       
  1118     if (how & Z_ASYNC) {
       
  1119 	lastwj = newjob;
       
  1120 
       
  1121         if (thisjob == list_pipe_job)
       
  1122             list_pipe_job = 0;
       
  1123 	jobtab[thisjob].stat |= STAT_NOSTTY;
       
  1124 	if (slflags & WC_SUBLIST_COPROC) {
       
  1125 	    zclose(ipipe[1]);
       
  1126 	    zclose(opipe[0]);
       
  1127 	}
       
  1128 	if (how & Z_DISOWN) {
       
  1129 	    deletejob(jobtab + thisjob);
       
  1130 	    thisjob = -1;
       
  1131 	}
       
  1132 	else
       
  1133 	    spawnjob();
       
  1134 	child_unblock();
       
  1135 	return 0;
       
  1136     } else {
       
  1137 	if (newjob != lastwj) {
       
  1138 	    Job jn = jobtab + newjob;
       
  1139 	    int updated;
       
  1140 
       
  1141 	    if (newjob == list_pipe_job && list_pipe_child)
       
  1142 		_exit(0);
       
  1143 
       
  1144 	    lastwj = thisjob = newjob;
       
  1145 
       
  1146 	    if (list_pipe || (pline_level && !(how & Z_TIMED)))
       
  1147 		jn->stat |= STAT_NOPRINT;
       
  1148 
       
  1149 	    if (nowait) {
       
  1150 		if(!pline_level) {
       
  1151 		    struct process *pn, *qn;
       
  1152 
       
  1153 		    curjob = newjob;
       
  1154 		    DPUTS(!list_pipe_pid, "invalid list_pipe_pid");
       
  1155 		    addproc(list_pipe_pid, list_pipe_text, 0,
       
  1156 			    &list_pipe_start);
       
  1157 
       
  1158 		    /* If the super-job contains only the sub-shell, the
       
  1159 		       sub-shell is the group leader. */
       
  1160 		    if (!jn->procs->next || lpforked == 2) {
       
  1161 			jn->gleader = list_pipe_pid;
       
  1162 			jn->stat |= STAT_SUBLEADER;
       
  1163 		    }
       
  1164 		    for (pn = jobtab[jn->other].procs; pn; pn = pn->next)
       
  1165 			if (WIFSTOPPED(pn->status))
       
  1166 			    break;
       
  1167 
       
  1168 		    if (pn) {
       
  1169 			for (qn = jn->procs; qn->next; qn = qn->next);
       
  1170 			qn->status = pn->status;
       
  1171 		    }
       
  1172 
       
  1173 		    jn->stat &= ~(STAT_DONE | STAT_NOPRINT);
       
  1174 		    jn->stat |= STAT_STOPPED | STAT_CHANGED | STAT_LOCKED;
       
  1175 		    printjob(jn, !!isset(LONGLISTJOBS), 1);
       
  1176 		}
       
  1177 		else if (newjob != list_pipe_job)
       
  1178 		    deletejob(jn);
       
  1179 		else
       
  1180 		    lastwj = -1;
       
  1181 	    }
       
  1182 
       
  1183 	    errbrk_saved = 0;
       
  1184 	    for (; !nowait;) {
       
  1185 		if (list_pipe_child) {
       
  1186 		    jn->stat |= STAT_NOPRINT;
       
  1187 		    makerunning(jn);
       
  1188 		}
       
  1189 		if (!(jn->stat & STAT_LOCKED)) {
       
  1190 		    updated = hasprocs(thisjob);
       
  1191 		    waitjobs();
       
  1192 		    child_block();
       
  1193 		} else
       
  1194 		    updated = 0;
       
  1195 		if (!updated &&
       
  1196 		    list_pipe_job && hasprocs(list_pipe_job) &&
       
  1197 		    !(jobtab[list_pipe_job].stat & STAT_STOPPED)) {
       
  1198 		    child_unblock();
       
  1199 		    child_block();
       
  1200 		}
       
  1201 		if (list_pipe_child &&
       
  1202 		    jn->stat & STAT_DONE &&
       
  1203 		    lastval2 & 0200)
       
  1204 		    killpg(mypgrp, lastval2 & ~0200);
       
  1205 		if (!list_pipe_child && !lpforked && !subsh && jobbing &&
       
  1206 		    (list_pipe || last1 || pline_level) &&
       
  1207 		    ((jn->stat & STAT_STOPPED) ||
       
  1208 		     (list_pipe_job && pline_level &&
       
  1209 		      (jobtab[list_pipe_job].stat & STAT_STOPPED)))) {
       
  1210 #ifndef	 __SYMBIAN32__	      
       
  1211 		    pid_t pid;
       
  1212 		    int synch[2];
       
  1213 		    struct timeval bgtime;
       
  1214 
       
  1215 		    pipe(synch);
       
  1216 
       
  1217 		    if ((pid = zfork(&bgtime)) == -1) {
       
  1218 			trashzle();
       
  1219 			close(synch[0]);
       
  1220 			close(synch[1]);
       
  1221 			fprintf(stderr, "zsh: job can't be suspended\n");
       
  1222 			fflush(stderr);
       
  1223 			makerunning(jn);
       
  1224 			killjb(jn, SIGCONT);
       
  1225 			thisjob = newjob;
       
  1226 		    }
       
  1227 		    else if (pid) {
       
  1228 			char dummy;
       
  1229 
       
  1230 			lpforked = 
       
  1231 			    (killpg(jobtab[list_pipe_job].gleader, 0) == -1 ? 2 : 1);
       
  1232 			list_pipe_pid = pid;
       
  1233 			list_pipe_start = bgtime;
       
  1234 			nowait = errflag = 1;
       
  1235 			breaks = loops;
       
  1236 			close(synch[1]);
       
  1237 			read(synch[0], &dummy, 1);
       
  1238 			close(synch[0]);
       
  1239 			/* If this job has finished, we leave it as a
       
  1240 			 * normal (non-super-) job. */
       
  1241 			if (!(jn->stat & STAT_DONE)) {
       
  1242 			    jobtab[list_pipe_job].other = newjob;
       
  1243 			    jobtab[list_pipe_job].stat |= STAT_SUPERJOB;
       
  1244 			    jn->stat |= STAT_SUBJOB | STAT_NOPRINT;
       
  1245 			    jn->other = pid;
       
  1246 			}
       
  1247 			if ((list_pipe || last1) && hasprocs(list_pipe_job))
       
  1248 			    killpg(jobtab[list_pipe_job].gleader, SIGSTOP);
       
  1249 			break;
       
  1250 		    }
       
  1251 		    else {
       
  1252 			close(synch[0]);
       
  1253 			entersubsh(Z_ASYNC, 0, 0, 0);
       
  1254 			if (jobtab[list_pipe_job].procs) {
       
  1255 			    if (setpgrp(0L, mypgrp = jobtab[list_pipe_job].gleader)
       
  1256 				== -1) {
       
  1257 				setpgrp(0L, mypgrp = getpid());
       
  1258 			    }
       
  1259 			} else
       
  1260 			    setpgrp(0L, mypgrp = getpid());
       
  1261 			close(synch[1]);
       
  1262 			kill(getpid(), SIGSTOP);
       
  1263 			list_pipe = 0;
       
  1264 			list_pipe_child = 1;
       
  1265 			opts[INTERACTIVE] = 0;
       
  1266 			if (errbrk_saved) {
       
  1267 			    errflag = prev_errflag;
       
  1268 			    breaks = prev_breaks;
       
  1269 			}
       
  1270 			break;
       
  1271 		    }
       
  1272 #else
       
  1273 			if ((list_pipe || last1) && hasprocs(list_pipe_job))
       
  1274 			    killpg(jobtab[list_pipe_job].gleader, SIGSTOP);
       
  1275 			break;			    
       
  1276 #endif 	 //   __SYMBIAN32__
       
  1277 		}
       
  1278 		else if (subsh && jn->stat & STAT_STOPPED)
       
  1279 		    thisjob = newjob;
       
  1280 		else
       
  1281 		    break;
       
  1282 	    }
       
  1283 	    child_unblock();
       
  1284 
       
  1285 	    if (list_pipe && (lastval & 0200) && pj >= 0 &&
       
  1286 		(!(jn->stat & STAT_INUSE) || (jn->stat & STAT_DONE))) {
       
  1287 		deletejob(jn);
       
  1288 		jn = jobtab + pj;
       
  1289 		if (jn->gleader)
       
  1290 		    killjb(jn, lastval & ~0200);
       
  1291 	    }
       
  1292 	    if (list_pipe_child ||
       
  1293 		((jn->stat & STAT_DONE) &&
       
  1294 		 (list_pipe || (pline_level && !(jn->stat & STAT_SUBJOB)))))
       
  1295 		deletejob(jn);
       
  1296 	    thisjob = pj;
       
  1297 
       
  1298 	}
       
  1299 	if (slflags & WC_SUBLIST_NOT)
       
  1300 	    lastval = !lastval;
       
  1301     }
       
  1302     if (!pline_level)
       
  1303 	simple_pline = old_simple_pline;
       
  1304     return lastval;
       
  1305 }
       
  1306 
       
  1307 static int subsh_close = -1;
       
  1308 
       
  1309 /* execute pipeline.  This function assumes the `pline' is not NULL. */
       
  1310 
       
  1311 /**/
       
  1312 static void
       
  1313 execpline2(Estate state, wordcode pcode,
       
  1314 	   int how, int input, int output, int last1)
       
  1315 {
       
  1316 	int pipes[2];
       
  1317     if (breaks || retflag)
       
  1318 	return;
       
  1319 
       
  1320     /* In evaluated traps, don't modify the line number. */
       
  1321     if ((!intrap || trapisfunc) && !ineval && WC_PIPE_LINENO(pcode))
       
  1322 	lineno = WC_PIPE_LINENO(pcode) - 1;
       
  1323 
       
  1324     if (pline_level == 1) {
       
  1325 	if ((how & Z_ASYNC) || (!sfcontext && !sourcelevel))
       
  1326 	    strcpy(list_pipe_text,
       
  1327 		   getjobtext(state->prog,
       
  1328 			      state->pc + (WC_PIPE_TYPE(pcode) == WC_PIPE_END ?
       
  1329 					   0 : 1)));
       
  1330 	else
       
  1331 	    list_pipe_text[0] = '\0';
       
  1332     }
       
  1333     if (WC_PIPE_TYPE(pcode) == WC_PIPE_END)
       
  1334 
       
  1335 #ifndef __SYMBIAN32__    
       
  1336 	execcmd(state, input, output, how, last1 ? 1 : 2);
       
  1337 #else
       
  1338 	execcmd(state, input, 0, how, last1 ? 1 : 2);	
       
  1339 #endif	
       
  1340     else {
       
  1341 	int old_list_pipe = list_pipe;
       
  1342 	Wordcode next = state->pc + (*state->pc), pc;
       
  1343 	wordcode code;
       
  1344 
       
  1345 	state->pc++;
       
  1346 	for (pc = state->pc; wc_code(code = *pc) == WC_REDIR; pc += 3);
       
  1347 
       
  1348 	mpipe(pipes);
       
  1349 	/* if we are doing "foo | bar" where foo is a current *
       
  1350 	 * shell command, do foo in a subshell and do the     *
       
  1351 	 * rest of the pipeline in the current shell.         */
       
  1352 	if (wc_code(code) >= WC_CURSH && (how & Z_SYNC)) {
       
  1353 #ifndef __SYMBIAN32__	
       
  1354 
       
  1355 	    int synch[2];
       
  1356 	    pid_t pid;	    
       
  1357 	    struct timeval bgtime;
       
  1358 
       
  1359 	    pipe(synch);
       
  1360 	    if ((pid = zfork(&bgtime)) == -1) {
       
  1361 		close(synch[0]);
       
  1362 		close(synch[1]);
       
  1363 	    } else if (pid) {
       
  1364 		char dummy, *text;
       
  1365 
       
  1366 		text = getjobtext(state->prog, state->pc);
       
  1367 		addproc(pid, text, 0, &bgtime);
       
  1368 		close(synch[1]);
       
  1369 		read(synch[0], &dummy, 1);
       
  1370 		close(synch[0]);
       
  1371 	    } else {
       
  1372 		zclose(pipes[0]);
       
  1373 		close(synch[0]);
       
  1374 		entersubsh(how, 2, 0, 0);
       
  1375 		close(synch[1]);
       
  1376 		execcmd(state, input, pipes[1], how, 0);
       
  1377 		_exit(lastval);
       
  1378 	    }
       
  1379 #else	    
       
  1380 		execcmd(state, input, pipes[1], how, 0);	
       
  1381 #endif//__SYMBIAN32__	    
       
  1382 	} else {
       
  1383 	    /* otherwise just do the pipeline normally. */
       
  1384 #ifndef __SYMBIAN32__	    
       
  1385 	    subsh_close = pipes[0];
       
  1386 	    execcmd(state, input, pipes[1], how, 0);
       
  1387 #else
       
  1388 		execcmd(state, 1, 1, how, 0);
       
  1389 #endif
       
  1390 	}
       
  1391 #ifndef __SYMBIAN32__		
       
  1392 	zclose(pipes[1]);
       
  1393 #endif	
       
  1394 	state->pc = next;
       
  1395 
       
  1396 	/* if another execpline() is invoked because the command is *
       
  1397 	 * a list it must know that we're already in a pipeline     */
       
  1398 	cmdpush(CS_PIPE);
       
  1399 	list_pipe = 1;
       
  1400 #ifndef __SYMBIAN32__	
       
  1401 	execpline2(state, *state->pc++, how, pipes[0], output, last1);
       
  1402 #else
       
  1403 	execpline2(state, *state->pc++, how, 1, output, last1);
       
  1404 #endif	
       
  1405 	list_pipe = old_list_pipe;
       
  1406 	cmdpop();
       
  1407 #ifndef __SYMBIAN32__	
       
  1408 	zclose(pipes[0]);
       
  1409 #endif	
       
  1410 	subsh_close = -1;
       
  1411     }
       
  1412 }
       
  1413 
       
  1414 /* make the argv array */
       
  1415 
       
  1416 /**/
       
  1417 static char **
       
  1418 makecline(LinkList list)
       
  1419 {
       
  1420     LinkNode node;
       
  1421     char **argv, **ptr;
       
  1422 
       
  1423     /* A bigger argv is necessary for executing scripts */
       
  1424     ptr = argv = 2 + (char **) hcalloc((countlinknodes(list) + 4) *
       
  1425 				       sizeof(char *));
       
  1426 
       
  1427     if (isset(XTRACE)) {
       
  1428 	if (!doneps4)
       
  1429 	    printprompt4();
       
  1430 
       
  1431 	for (node = firstnode(list); node; incnode(node)) {
       
  1432 	    *ptr++ = (char *)getdata(node);
       
  1433 	    quotedzputs(getdata(node), xtrerr);
       
  1434 	    if (nextnode(node))
       
  1435 		fputc(' ', xtrerr);
       
  1436 	}
       
  1437 	fputc('\n', xtrerr);
       
  1438 	fflush(xtrerr);
       
  1439     } else {
       
  1440 	for (node = firstnode(list); node; incnode(node))
       
  1441 	    *ptr++ = (char *)getdata(node);
       
  1442     }
       
  1443     *ptr = NULL;
       
  1444     return (argv);
       
  1445 }
       
  1446 
       
  1447 /**/
       
  1448 mod_export void
       
  1449 untokenize(char *s)
       
  1450 {
       
  1451     if (*s) {
       
  1452 	int c;
       
  1453 
       
  1454 	while ((c = *s++))
       
  1455 	    if (itok(c)) {
       
  1456 		char *p = s - 1;
       
  1457 
       
  1458 		if (c != Nularg)
       
  1459 		    *p++ = ztokens[c - Pound];
       
  1460 
       
  1461 		while ((c = *s++)) {
       
  1462 		    if (itok(c)) {
       
  1463 			if (c != Nularg)
       
  1464 			    *p++ = ztokens[c - Pound];
       
  1465 		    } else
       
  1466 			*p++ = c;
       
  1467 		}
       
  1468 		*p = '\0';
       
  1469 		break;
       
  1470 	    }
       
  1471     }
       
  1472 }
       
  1473 
       
  1474 /* Open a file for writing redirection */
       
  1475 
       
  1476 /**/
       
  1477 static int
       
  1478 clobber_open(struct redir *f)
       
  1479 {
       
  1480     struct stat buf;
       
  1481     int fd, oerrno;
       
  1482 
       
  1483     /* If clobbering, just open. */
       
  1484     if (isset(CLOBBER) || IS_CLOBBER_REDIR(f->type))
       
  1485 	return open(unmeta(f->name),
       
  1486 		O_WRONLY | O_CREAT | O_TRUNC | O_NOCTTY, 0666);
       
  1487 
       
  1488     /* If not clobbering, attempt to create file exclusively. */
       
  1489     if ((fd = open(unmeta(f->name),
       
  1490 		   O_WRONLY | O_CREAT | O_EXCL | O_NOCTTY, 0666)) >= 0)
       
  1491 	return fd;
       
  1492 
       
  1493     /* If that fails, we are still allowed to open non-regular files. *
       
  1494      * Try opening, and if it's a regular file then close it again    *
       
  1495      * because we weren't supposed to open it.                        */
       
  1496     oerrno = errno;
       
  1497     if ((fd = open(unmeta(f->name), O_WRONLY | O_NOCTTY)) != -1) {
       
  1498 	if(!fstat(fd, &buf) && !S_ISREG(buf.st_mode))
       
  1499 	    return fd;
       
  1500 	close(fd);
       
  1501     }
       
  1502     errno = oerrno;
       
  1503     return -1;
       
  1504 }
       
  1505 
       
  1506 /* size of buffer for tee and cat processes */
       
  1507 #define TCBUFSIZE 4092
       
  1508 
       
  1509 /* close an multio (success) */
       
  1510 
       
  1511 /**/
       
  1512 static void
       
  1513 closemn(struct multio **mfds, int fd)
       
  1514 {
       
  1515     if (fd >= 0 && mfds[fd] && mfds[fd]->ct >= 2) {
       
  1516 	struct multio *mn = mfds[fd];
       
  1517     int i;
       
  1518 
       
  1519 #ifndef __SYMBIAN32__
       
  1520 	char buf[TCBUFSIZE];
       
  1521 	pid_t pid;
       
  1522 	int len;
       
  1523 	struct timeval bgtime;	
       
  1524 	
       
  1525 	if ((pid = zfork(&bgtime))) {
       
  1526 	    for (i = 0; i < mn->ct; i++)
       
  1527 		zclose(mn->fds[i]);
       
  1528 	    zclose(mn->pipe);
       
  1529 	    if (pid == -1) { 
       
  1530 		mfds[fd] = NULL;
       
  1531 		return;
       
  1532 	    }
       
  1533 	    mn->ct = 1;
       
  1534 	    mn->fds[0] = fd;
       
  1535 	    addproc(pid, NULL, 1, &bgtime);
       
  1536 	    return;
       
  1537 	}
       
  1538 	/* pid == 0 */
       
  1539 	closeallelse(mn);
       
  1540 	if (mn->rflag) {
       
  1541 	    /* tee process */
       
  1542 	    while ((len = read(mn->pipe, buf, TCBUFSIZE)) != 0) {
       
  1543 		if (len < 0) {
       
  1544 		    if (errno == EINTR)
       
  1545 			continue;
       
  1546 		    else
       
  1547 			break;
       
  1548 		}
       
  1549 		for (i = 0; i < mn->ct; i++)
       
  1550 		    write(mn->fds[i], buf, len);
       
  1551 	    }
       
  1552 	} else {
       
  1553 	    /* cat process */
       
  1554 	    for (i = 0; i < mn->ct; i++)
       
  1555 		while ((len = read(mn->fds[i], buf, TCBUFSIZE)) != 0) {
       
  1556 		    if (len < 0) {
       
  1557 			if (errno == EINTR)
       
  1558 			    continue;
       
  1559 			else
       
  1560 			    break;
       
  1561 		    }
       
  1562 		    write(mn->pipe, buf, len);
       
  1563 		}
       
  1564 	}
       
  1565 	_exit(0);
       
  1566 #else
       
  1567 	for (i = 0; i < mn->ct; i++)
       
  1568 		zclose(mn->fds[i]);
       
  1569 			
       
  1570 	zclose(mn->pipe);
       
  1571 	mn->ct = 1;
       
  1572 	mn->fds[0] = fd;
       
  1573 	return;	    	    		
       
  1574 #endif	
       
  1575     } else if (fd >= 0)
       
  1576 	mfds[fd] = NULL;
       
  1577 }
       
  1578 
       
  1579 /* close all the mnodes (failure) */
       
  1580 
       
  1581 /**/
       
  1582 static void
       
  1583 closemnodes(struct multio **mfds)
       
  1584 {
       
  1585     int i, j;
       
  1586 
       
  1587     for (i = 0; i < 10; i++)
       
  1588 	if (mfds[i]) {
       
  1589 	    for (j = 0; j < mfds[i]->ct; j++)
       
  1590 		zclose(mfds[i]->fds[j]);
       
  1591 	    mfds[i] = NULL;
       
  1592 	}
       
  1593 }
       
  1594 
       
  1595 /**/
       
  1596 static void
       
  1597 closeallelse(struct multio *mn)
       
  1598 {
       
  1599     int i, j;
       
  1600     long openmax;
       
  1601 
       
  1602     openmax = zopenmax();
       
  1603 
       
  1604     for (i = 0; i < openmax; i++)
       
  1605 	if (mn->pipe != i) {
       
  1606 	    for (j = 0; j < mn->ct; j++)
       
  1607 		if (mn->fds[j] == i)
       
  1608 		    break;
       
  1609 	    if (j == mn->ct)
       
  1610 		zclose(i);
       
  1611 	}
       
  1612 }
       
  1613 
       
  1614 /* A multio is a list of fds associated with a certain fd.       *
       
  1615  * Thus if you do "foo >bar >ble", the multio for fd 1 will have *
       
  1616  * two fds, the result of open("bar",...), and the result of     *
       
  1617  * open("ble",....).                                             */
       
  1618 
       
  1619 /* Add a fd to an multio.  fd1 must be < 10, and may be in any state. *
       
  1620  * fd2 must be open, and is `consumed' by this function.  Note that   *
       
  1621  * fd1 == fd2 is possible, and indicates that fd1 was really closed.  *
       
  1622  * We effectively do `fd2 = movefd(fd2)' at the beginning of this     *
       
  1623  * function, but in most cases we can avoid an extra dup by delaying  *
       
  1624  * the movefd: we only >need< to move it if we're actually doing a    *
       
  1625  * multiple redirection.                                              */
       
  1626 
       
  1627 /**/
       
  1628 static void
       
  1629 addfd(int forked, int *save, struct multio **mfds, int fd1, int fd2, int rflag)
       
  1630 {
       
  1631     int pipes[2];
       
  1632     if (!mfds[fd1] || unset(MULTIOS)) {
       
  1633 	if(!mfds[fd1]) {		/* starting a new multio */
       
  1634 	    mfds[fd1] = (struct multio *) zhalloc(sizeof(struct multio));
       
  1635 	    if (!forked && save[fd1] == -2)
       
  1636 		save[fd1] = (fd1 == fd2) ? -1 : movefd(fd1);
       
  1637 	}
       
  1638 	redup(fd2, fd1);
       
  1639 	mfds[fd1]->ct = 1;
       
  1640 	mfds[fd1]->fds[0] = fd1;
       
  1641 	mfds[fd1]->rflag = rflag;
       
  1642     } else {
       
  1643 	if (mfds[fd1]->rflag != rflag) {
       
  1644 	    zerr("file mode mismatch on fd %d", NULL, fd1);
       
  1645 	    return;
       
  1646 	}
       
  1647 	if (mfds[fd1]->ct == 1) {	/* split the stream */
       
  1648 	    mfds[fd1]->fds[0] = movefd(fd1);
       
  1649 	    mfds[fd1]->fds[1] = movefd(fd2);
       
  1650 	    mpipe(pipes);
       
  1651 	    mfds[fd1]->pipe = pipes[1 - rflag];
       
  1652 	    redup(pipes[rflag], fd1);
       
  1653 	    mfds[fd1]->ct = 2;
       
  1654 	} else {		/* add another fd to an already split stream */
       
  1655 	    if(!(mfds[fd1]->ct % MULTIOUNIT)) {
       
  1656 		int new = sizeof(struct multio) + sizeof(int) * mfds[fd1]->ct;
       
  1657 		int old = new - sizeof(int) * MULTIOUNIT;
       
  1658 		mfds[fd1] = hrealloc((char *)mfds[fd1], old, new);
       
  1659 	    }
       
  1660 	    mfds[fd1]->fds[mfds[fd1]->ct++] = movefd(fd2);
       
  1661 	}
       
  1662     }
       
  1663     if (subsh_close >= 0 && !fdtable[subsh_close])
       
  1664 	subsh_close = -1;
       
  1665 }
       
  1666 
       
  1667 /**/
       
  1668 static void
       
  1669 addvars(Estate state, Wordcode pc, int export)
       
  1670 {
       
  1671     LinkList vl;
       
  1672     int xtr, isstr, htok = 0;
       
  1673     char **arr, **ptr, *name;
       
  1674     Wordcode opc = state->pc;
       
  1675     wordcode ac;
       
  1676     local_list1(svl);
       
  1677 
       
  1678     xtr = isset(XTRACE);
       
  1679     if (xtr) {
       
  1680 	printprompt4();
       
  1681 	doneps4 = 1;
       
  1682     }
       
  1683     state->pc = pc;
       
  1684     while (wc_code(ac = *state->pc++) == WC_ASSIGN) {
       
  1685 	name = ecgetstr(state, EC_DUPTOK, &htok);
       
  1686 	if (htok)
       
  1687 	    untokenize(name);
       
  1688 	if (xtr)
       
  1689 	    fprintf(xtrerr,
       
  1690 	    	WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC ? "%s+=" : "%s=", name);
       
  1691 	if ((isstr = (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR))) {
       
  1692 	    init_list1(svl, ecgetstr(state, EC_DUPTOK, &htok));
       
  1693 	    vl = &svl;
       
  1694 	} else
       
  1695 	    vl = ecgetlist(state, WC_ASSIGN_NUM(ac), EC_DUPTOK, &htok);
       
  1696 
       
  1697 	if (vl && htok) {
       
  1698 	    prefork(vl, (isstr ? (PF_SINGLE|PF_ASSIGN) :
       
  1699 			 PF_ASSIGN));
       
  1700 	    if (errflag) {
       
  1701 		state->pc = opc;
       
  1702 		return;
       
  1703 	    }
       
  1704 	    if (isset(GLOBASSIGN) || !isstr)
       
  1705 		globlist(vl, 0);
       
  1706 	    if (errflag) {
       
  1707 		state->pc = opc;
       
  1708 		return;
       
  1709 	    }
       
  1710 	}
       
  1711 	if (isstr && (empty(vl) || !nextnode(firstnode(vl)))) {
       
  1712 	    Param pm;
       
  1713 	    char *val;
       
  1714 	    int allexp;
       
  1715 
       
  1716 	    if (empty(vl))
       
  1717 		val = ztrdup("");
       
  1718 	    else {
       
  1719 		untokenize(peekfirst(vl));
       
  1720 		val = ztrdup(ugetnode(vl));
       
  1721 	    }
       
  1722 	    if (xtr) {
       
  1723 		quotedzputs(val, xtrerr);
       
  1724 		fputc(' ', xtrerr);
       
  1725 	    }
       
  1726 	    if (export && !strchr(name, '[')) {
       
  1727 		if (export < 0 && isset(RESTRICTED) &&
       
  1728 		    (pm = (Param) paramtab->removenode(paramtab, name)) &&
       
  1729 		    (pm->flags & PM_RESTRICTED)) {
       
  1730 		    zerr("%s: restricted", pm->nam, 0);
       
  1731 		    zsfree(val);
       
  1732 		    state->pc = opc;
       
  1733 		    return;
       
  1734 		}
       
  1735 		if (strcmp(name, "STTY") == 0) {
       
  1736 		    zsfree(STTYval);
       
  1737 		    STTYval = ztrdup(val);
       
  1738 		}
       
  1739 		allexp = opts[ALLEXPORT];
       
  1740 		opts[ALLEXPORT] = 1;
       
  1741 	    	pm = assignsparam(name, val,
       
  1742 		    WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC);
       
  1743 		opts[ALLEXPORT] = allexp;
       
  1744 	    } else
       
  1745 	    	pm = assignsparam(name, val,
       
  1746 		    WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC);
       
  1747 	    if (errflag) {
       
  1748 		state->pc = opc;
       
  1749 		return;
       
  1750 	    }
       
  1751 	    continue;
       
  1752 	}
       
  1753 	if (vl) {
       
  1754 	    ptr = arr = (char **) zalloc(sizeof(char **) *
       
  1755 					 (countlinknodes(vl) + 1));
       
  1756 
       
  1757 	    while (nonempty(vl))
       
  1758 		*ptr++ = ztrdup((char *) ugetnode(vl));
       
  1759 	} else
       
  1760 	    ptr = arr = (char **) zalloc(sizeof(char **));
       
  1761 
       
  1762 	*ptr = NULL;
       
  1763 	if (xtr) {
       
  1764 	    fprintf(xtrerr, "( ");
       
  1765 	    for (ptr = arr; *ptr; ptr++) {
       
  1766 		quotedzputs(*ptr, xtrerr);
       
  1767 		fputc(' ', xtrerr);
       
  1768 	    }
       
  1769 	    fprintf(xtrerr, ") ");
       
  1770 	}
       
  1771 	assignaparam(name, arr, WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC);
       
  1772 	if (errflag) {
       
  1773 	    state->pc = opc;
       
  1774 	    return;
       
  1775 	}
       
  1776     }
       
  1777     state->pc = opc;
       
  1778 }
       
  1779 
       
  1780 /**/
       
  1781 void
       
  1782 setunderscore(char *str)
       
  1783 {
       
  1784     if (str && *str) {
       
  1785 	int l = strlen(str) + 1, nl = (l + 31) & ~31;
       
  1786 
       
  1787 	if (nl > underscorelen || (underscorelen - nl) > 64) {
       
  1788 	    zfree(underscore, underscorelen);
       
  1789 	    underscore = (char *) zalloc(underscorelen = nl);
       
  1790 	}
       
  1791 	strcpy(underscore, str);
       
  1792 	underscoreused = l;
       
  1793     } else {
       
  1794 	if (underscorelen > 128) {
       
  1795 	    zfree(underscore, underscorelen);
       
  1796 	    underscore = (char *) zalloc(underscorelen = 32);
       
  1797 	}
       
  1798 	*underscore = '\0';
       
  1799 	underscoreused = 1;
       
  1800     }
       
  1801 }
       
  1802 
       
  1803 /* These describe the type of expansions that need to be done on the words
       
  1804  * used in the thing we are about to execute. They are set in execcmd() and
       
  1805  * used in execsubst() which might be called from one of the functions
       
  1806  * called from execcmd() (like execfor() and so on). */
       
  1807 
       
  1808 static int esprefork, esglob = 1;
       
  1809 
       
  1810 /**/
       
  1811 void
       
  1812 execsubst(LinkList strs)
       
  1813 {
       
  1814     if (strs) {
       
  1815 	prefork(strs, esprefork);
       
  1816 	if (esglob) {
       
  1817 	    LinkList ostrs = strs;
       
  1818 	    globlist(strs, 0);
       
  1819 	    strs = ostrs;
       
  1820 	}
       
  1821     }
       
  1822 }
       
  1823 #ifdef __SYMBIAN32__
       
  1824 extern int handlePipeCmds(char*, pid_t, int fds[3], int);
       
  1825 extern void clearfds(void);
       
  1826 #endif
       
  1827 
       
  1828 /**/
       
  1829 static void
       
  1830 execcmd(Estate state, int input, int output, int how, int last1)
       
  1831 {
       
  1832     HashNode hn = NULL;
       
  1833     LinkNode node;
       
  1834     Redir fn;
       
  1835     struct multio *mfds[10];
       
  1836     char *text;
       
  1837     int save[10];
       
  1838     int fil, dfil, is_cursh, type, do_exec = 0, i, htok = 0;
       
  1839     int nullexec = 0, assign = 0, forked = 0;
       
  1840     int is_shfunc = 0, is_builtin = 0, is_exec = 0, use_defpath = 0;
       
  1841     /* Various flags to the command. */
       
  1842     int cflags = 0, checked = 0, oautocont = opts[AUTOCONTINUE];
       
  1843     LinkList redir;
       
  1844     wordcode code;
       
  1845     Wordcode beg = state->pc, varspc;
       
  1846     FILE *oxtrerr = xtrerr;
       
  1847 	static int op_fd=-1;
       
  1848 	int thread_created=0;
       
  1849 		
       
  1850     doneps4 = 0;
       
  1851     redir = (wc_code(*state->pc) == WC_REDIR ? ecgetredirs(state) : NULL);
       
  1852     if (wc_code(*state->pc) == WC_ASSIGN) {
       
  1853 	varspc = state->pc;
       
  1854 	while (wc_code((code = *state->pc)) == WC_ASSIGN)
       
  1855 	    state->pc += (WC_ASSIGN_TYPE(code) == WC_ASSIGN_SCALAR ?
       
  1856 			  3 : WC_ASSIGN_NUM(code) + 2);
       
  1857     } else
       
  1858 	varspc = NULL;
       
  1859 
       
  1860     code = *state->pc++;
       
  1861 
       
  1862     type = wc_code(code);
       
  1863 
       
  1864     /* It would be nice if we could use EC_DUPTOK instead of EC_DUP here.
       
  1865      * But for that we would need to check/change all builtins so that
       
  1866      * they don't modify their argument strings. */
       
  1867     args = (type == WC_SIMPLE ?
       
  1868 	    ecgetlist(state, WC_SIMPLE_ARGC(code), EC_DUP, &htok) : NULL);
       
  1869 
       
  1870     for (i = 0; i < 10; i++) {
       
  1871 	save[i] = -2;
       
  1872 	mfds[i] = NULL;
       
  1873     }
       
  1874 
       
  1875     /* If the command begins with `%', then assume it is a *
       
  1876      * reference to a job in the job table.                */
       
  1877     if (type == WC_SIMPLE && args && nonempty(args) &&
       
  1878 	*(char *)peekfirst(args) == '%') {
       
  1879         if (how & Z_DISOWN)
       
  1880             opts[AUTOCONTINUE] = 1;
       
  1881 	pushnode(args, dupstring((how & Z_DISOWN)
       
  1882 				 ? "disown" : (how & Z_ASYNC) ? "bg" : "fg"));
       
  1883 	how = Z_SYNC;
       
  1884     }
       
  1885 
       
  1886     /* If AUTORESUME is set, the command is SIMPLE, and doesn't have *
       
  1887      * any redirections, then check if it matches as a prefix of a   *
       
  1888      * job currently in the job table.  If it does, then we treat it *
       
  1889      * as a command to resume this job.                              */
       
  1890     if (isset(AUTORESUME) && type == WC_SIMPLE && (how & Z_SYNC) &&
       
  1891 	args && nonempty(args) && (!redir || empty(redir)) && !input &&
       
  1892 	!nextnode(firstnode(args))) {
       
  1893 	if (unset(NOTIFY))
       
  1894 	    scanjobs();
       
  1895 	if (findjobnam(peekfirst(args)) != -1)
       
  1896 	    pushnode(args, dupstring("fg"));
       
  1897     }
       
  1898 
       
  1899     /* Check if it's a builtin needing automatic MAGIC_EQUALS_SUBST      *
       
  1900      * handling.  Things like typeset need this.  We can't detect the    *
       
  1901      * command if it contains some tokens (e.g. x=ex; ${x}port), so this *
       
  1902      * only works in simple cases.  has_token() is called to make sure   *
       
  1903      * this really is a simple case.                                     */
       
  1904     if (type == WC_SIMPLE) {
       
  1905 	while (args && nonempty(args)) {
       
  1906 	   	char*	cmdarg= (char *) peekfirst(args);
       
  1907 	    checked = !has_token(cmdarg);
       
  1908 	    if (!checked)
       
  1909 		break;
       
  1910 	    if (!(cflags & (BINF_BUILTIN | BINF_COMMAND)) &&
       
  1911 		(hn = shfunctab->getnode(shfunctab, cmdarg))) {
       
  1912 		is_shfunc = 1;
       
  1913 		break;
       
  1914 	    }
       
  1915 	    if (!(hn = builtintab->getnode(builtintab, cmdarg))) {
       
  1916 		checked = !(cflags & BINF_BUILTIN);
       
  1917 		break;
       
  1918 	    }
       
  1919 	    if (!(hn->flags & BINF_PREFIX)) {
       
  1920 		is_builtin = 1;
       
  1921 
       
  1922 		/* autoload the builtin if necessary */
       
  1923 		if (!((Builtin) hn)->handlerfunc) {
       
  1924 		    load_module(((Builtin) hn)->optstr);
       
  1925 		    hn = builtintab->getnode(builtintab, cmdarg);
       
  1926 		}
       
  1927 		assign = (hn && (hn->flags & BINF_MAGICEQUALS));
       
  1928 		break;
       
  1929 	    }
       
  1930 	    cflags &= ~BINF_BUILTIN & ~BINF_COMMAND;
       
  1931 	    cflags |= hn->flags;
       
  1932 	    checked = 0;
       
  1933 	    if (cflags & BINF_COMMAND && nextnode(firstnode(args))) {
       
  1934 		/* check for options to command builtin */
       
  1935 		char *next = (char *) getdata(nextnode(firstnode(args)));
       
  1936 		char *cmdopt;
       
  1937 		if (next && *next == '-' && strlen(next) == 2 &&
       
  1938 		        (cmdopt = strchr("pvV", next[1])))
       
  1939 		{
       
  1940 		    if (*cmdopt == 'p') {
       
  1941 			uremnode(args, firstnode(args));
       
  1942 			use_defpath = 1;
       
  1943 			if (nextnode(firstnode(args)))
       
  1944 			    next = (char *) getdata(nextnode(firstnode(args)));
       
  1945 		    } else {
       
  1946 			hn = (HashNode)&commandbn;
       
  1947 			is_builtin = 1;
       
  1948 			break;
       
  1949 		    }
       
  1950 		}
       
  1951 		if (!strcmp(next, "--"))
       
  1952 		     uremnode(args, firstnode(args));   
       
  1953 	    }
       
  1954 	    uremnode(args, firstnode(args));
       
  1955 	    hn = NULL;
       
  1956 	    if ((cflags & BINF_COMMAND) && unset(POSIXBUILTINS))
       
  1957 		break;
       
  1958 	}
       
  1959     }
       
  1960 
       
  1961     /* Do prefork substitutions */
       
  1962     esprefork = (assign || isset(MAGICEQUALSUBST)) ? PF_TYPESET : 0;
       
  1963     if (args && htok)
       
  1964 	prefork(args, esprefork);
       
  1965 
       
  1966     if (type == WC_SIMPLE) {
       
  1967 	int unglobbed = 0;
       
  1968 
       
  1969 	for (;;) {
       
  1970 	    char *cmdarg;
       
  1971 
       
  1972 	    if (!(cflags & BINF_NOGLOB))
       
  1973 		while (!checked && !errflag && args && nonempty(args) &&
       
  1974 		       has_token((char *) peekfirst(args)))
       
  1975 		    zglob(args, firstnode(args), 0);
       
  1976 	    else if (!unglobbed) {
       
  1977 		for (node = firstnode(args); node; incnode(node))
       
  1978 		    untokenize((char *) getdata(node));
       
  1979 		unglobbed = 1;
       
  1980 	    }
       
  1981 
       
  1982 	    /* Current shell should not fork unless the *
       
  1983 	     * exec occurs at the end of a pipeline.    */
       
  1984 	    if ((cflags & BINF_EXEC) && last1)
       
  1985 		do_exec = 1;
       
  1986 
       
  1987 	    /* Empty command */
       
  1988 	    if (!args || empty(args)) {
       
  1989 		if (redir && nonempty(redir)) {
       
  1990 		    if (do_exec) {
       
  1991 			/* Was this "exec < foobar"? */
       
  1992 			nullexec = 1;
       
  1993 			break;
       
  1994 		    } else if (varspc) {
       
  1995 			nullexec = 2;
       
  1996 			break;
       
  1997 		    } else if (!nullcmd || !*nullcmd || opts[CSHNULLCMD] ||
       
  1998 			       (cflags & BINF_PREFIX)) {
       
  1999 			zerr("redirection with no command", NULL, 0);
       
  2000 			errflag = lastval = 1;
       
  2001 			return;
       
  2002 		    } else if (!nullcmd || !*nullcmd || opts[SHNULLCMD]) {
       
  2003 			if (!args)
       
  2004 			    args = newlinklist();
       
  2005 			addlinknode(args, dupstring(":"));
       
  2006 		    } else if (readnullcmd && *readnullcmd &&
       
  2007 			       ((Redir) peekfirst(redir))->type == REDIR_READ &&
       
  2008 			       !nextnode(firstnode(redir))) {
       
  2009 			if (!args)
       
  2010 			    args = newlinklist();
       
  2011 			addlinknode(args, dupstring(readnullcmd));
       
  2012 		    } else {
       
  2013 			if (!args)
       
  2014 			    args = newlinklist();
       
  2015 			addlinknode(args, dupstring(nullcmd));
       
  2016 		    }
       
  2017 		} else if ((cflags & BINF_PREFIX) && (cflags & BINF_COMMAND)) {
       
  2018 		    lastval = 0;
       
  2019 		    return;
       
  2020 		} else {
       
  2021 		    cmdoutval = 0;
       
  2022 		    if (varspc)
       
  2023 			addvars(state, varspc, 0);
       
  2024 		    if (errflag)
       
  2025 			lastval = errflag;
       
  2026 		    else
       
  2027 			lastval = cmdoutval;
       
  2028 		    if (isset(XTRACE)) {
       
  2029 			fputc('\n', xtrerr);
       
  2030 			fflush(xtrerr);
       
  2031 		    }
       
  2032 		    return;
       
  2033 		}
       
  2034 	    } else if (isset(RESTRICTED) && (cflags & BINF_EXEC) && do_exec) {
       
  2035 		zerrnam("exec", "%s: restricted",
       
  2036 			(char *) getdata(firstnode(args)), 0);
       
  2037 		lastval = 1;
       
  2038 		return;
       
  2039 	    }
       
  2040 
       
  2041 	    /*
       
  2042 	     * Quit looking for a command if:
       
  2043 	     * - there was an error; or
       
  2044 	     * - we checked the simple cases needing MAGIC_EQUAL_SUBST; or
       
  2045 	     * - we know we already found a builtin (because either:
       
  2046 	     *   - we loaded a builtin from a module, or
       
  2047 	     *   - we have determined there are options which would
       
  2048 	     *     require us to use the "command" builtin); or
       
  2049 	     * - we aren't using POSIX and so BINF_COMMAND indicates a zsh
       
  2050 	     *   precommand modifier is being used in place of the builtin
       
  2051 	     */
       
  2052 	    if (errflag || checked || is_builtin ||
       
  2053 		(unset(POSIXBUILTINS) && (cflags & BINF_COMMAND)))
       
  2054 		break;
       
  2055 
       
  2056 	    cmdarg = (char *) peekfirst(args);
       
  2057 	    if (!(cflags & (BINF_BUILTIN | BINF_COMMAND)) &&
       
  2058 		(hn = shfunctab->getnode(shfunctab, cmdarg))) {
       
  2059 		is_shfunc = 1;
       
  2060 		break;
       
  2061 	    }
       
  2062 	    if (!(hn = builtintab->getnode(builtintab, cmdarg))) {
       
  2063 		if (cflags & BINF_BUILTIN) {
       
  2064 		    zwarn("no such builtin: %s", cmdarg, 0);
       
  2065 		    lastval = 1;
       
  2066                     opts[AUTOCONTINUE] = oautocont;
       
  2067 		    return;
       
  2068 		}
       
  2069 		break;
       
  2070 	    }
       
  2071 	    if (!(hn->flags & BINF_PREFIX)) {
       
  2072 		is_builtin = 1;
       
  2073 
       
  2074 		/* autoload the builtin if necessary */
       
  2075 		if (!((Builtin) hn)->handlerfunc) {
       
  2076 		    load_module(((Builtin) hn)->optstr);
       
  2077 		    hn = builtintab->getnode(builtintab, cmdarg);
       
  2078 		}
       
  2079 		break;
       
  2080 	    }
       
  2081 	    cflags &= ~BINF_BUILTIN & ~BINF_COMMAND;
       
  2082 	    cflags |= hn->flags;
       
  2083 	    uremnode(args, firstnode(args));
       
  2084 	    hn = NULL;
       
  2085 	}
       
  2086     }
       
  2087 
       
  2088     if (errflag) {
       
  2089 	lastval = 1;
       
  2090         opts[AUTOCONTINUE] = oautocont;
       
  2091 	return;
       
  2092     }
       
  2093 
       
  2094     /* Get the text associated with this command. */
       
  2095     if ((how & Z_ASYNC) ||
       
  2096 	(!sfcontext && !sourcelevel && (jobbing || (how & Z_TIMED))))
       
  2097 	text = getjobtext(state->prog, beg);
       
  2098     else
       
  2099 	text = NULL;
       
  2100 
       
  2101     /* Set up special parameter $_ */
       
  2102 
       
  2103     setunderscore((args && nonempty(args)) ? ((char *) getdata(lastnode(args))) : "");
       
  2104 
       
  2105     /* Warn about "rm *" */
       
  2106     if (type == WC_SIMPLE && interact && unset(RMSTARSILENT) &&
       
  2107 	isset(SHINSTDIN) && args && nonempty(args) &&
       
  2108 	nextnode(firstnode(args)) && !strcmp(peekfirst(args), "rm")) {
       
  2109 	LinkNode node, next;
       
  2110 
       
  2111 	for (node = nextnode(firstnode(args)); node && !errflag; node = next) {
       
  2112 	    char *s = (char *) getdata(node);
       
  2113 	    int l = strlen(s);
       
  2114 
       
  2115 	    next = nextnode(node);
       
  2116 	    if (s[0] == Star && !s[1]) {
       
  2117 		if (!checkrmall(pwd))
       
  2118 		    uremnode(args, node);
       
  2119 	    } else if (l > 2 && s[l - 2] == '/' && s[l - 1] == Star) {
       
  2120 		char t = s[l - 2];
       
  2121 
       
  2122 		s[l - 2] = 0;
       
  2123 		if (!checkrmall(s))
       
  2124 		    uremnode(args, node);
       
  2125 		s[l - 2] = t;
       
  2126 	    }
       
  2127 	}
       
  2128 	if (!nextnode(firstnode(args)))
       
  2129 	    errflag = 1;
       
  2130     }
       
  2131 
       
  2132     if (errflag) {
       
  2133 	lastval = 1;
       
  2134         opts[AUTOCONTINUE] = oautocont;
       
  2135 	return;
       
  2136     }
       
  2137 
       
  2138     if (type == WC_SIMPLE && !nullexec) {
       
  2139 	char *s;
       
  2140 	char trycd = (isset(AUTOCD) && isset(SHINSTDIN) &&
       
  2141 		      (!redir || empty(redir)) && args && !empty(args) &&
       
  2142 		      !nextnode(firstnode(args)) && *(char *)peekfirst(args));
       
  2143 
       
  2144 	DPUTS((!args || empty(args)), "BUG: empty(args) in exec.c");
       
  2145 #ifndef __SYMBIAN32__	
       
  2146 	if (!hn) {
       
  2147 	    /* Resolve external commands */
       
  2148 	    char *cmdarg = (char *) peekfirst(args);
       
  2149 	    char **checkpath = pathchecked;
       
  2150 	    int dohashcmd = isset(HASHCMDS);
       
  2151 
       
  2152 	    hn = cmdnamtab->getnode(cmdnamtab, cmdarg);
       
  2153 	    if (hn && trycd && !isreallycom((Cmdnam)hn)) {
       
  2154 		if (!(((Cmdnam)hn)->flags & HASHED)) {
       
  2155 		    checkpath = path;
       
  2156 		    dohashcmd = 1;
       
  2157 		}
       
  2158 		cmdnamtab->removenode(cmdnamtab, cmdarg);
       
  2159 		cmdnamtab->freenode(hn);
       
  2160 		hn = NULL;
       
  2161 	    }
       
  2162 	    if (!hn && dohashcmd && strcmp(cmdarg, "..")) {
       
  2163 		for (s = cmdarg; *s && *s != '/'; s++);
       
  2164 		if (!*s)
       
  2165 		    hn = (HashNode) hashcmd(cmdarg, checkpath);
       
  2166 	    }
       
  2167 	}
       
  2168 #endif //__SYMBIAN32__
       
  2169 	/* If no command found yet, see if it  *
       
  2170 	 * is a directory we should AUTOCD to. */
       
  2171 	if (!hn && trycd && (s = cancd(peekfirst(args)))) {
       
  2172 	    peekfirst(args) = (void *) s;
       
  2173 	    pushnode(args, dupstring("cd"));
       
  2174 	    if ((hn = builtintab->getnode(builtintab, "cd")))
       
  2175 		is_builtin = 1;
       
  2176 	}
       
  2177     }
       
  2178 
       
  2179     /* This is nonzero if the command is a current shell procedure? */
       
  2180     is_cursh = (is_builtin || is_shfunc || nullexec || type >= WC_CURSH);
       
  2181 
       
  2182     /**************************************************************************
       
  2183      * Do we need to fork?  We need to fork if:                               *
       
  2184      * 1) The command is supposed to run in the background. (or)              *
       
  2185      * 2) There is no `exec' flag, and either:                                *
       
  2186      *    a) This is a builtin or shell function with output piped somewhere. *
       
  2187      *    b) This is an external command and we can't do a `fake exec'.       *
       
  2188      *                                                                        *
       
  2189      * A `fake exec' is possible if we have all the following conditions:     *
       
  2190      * 1) last1 flag is 1.  This indicates that the current shell will not    *
       
  2191      *    be needed after the current command.  This is typically the case    *
       
  2192      *    when when the command is the last stage in a subshell, or is the    *
       
  2193      *    last command after the option `-c'.                                 *
       
  2194      * 2) We don't have any traps set.                                        *
       
  2195      * 3) We don't have any files to delete.                                  *
       
  2196      *                                                                        *
       
  2197      * The condition above for a `fake exec' will also work for a current     *
       
  2198      * shell command such as a builtin, but doesn't really buy us anything    *
       
  2199      * (doesn't save us a process), since it is already running in the        *
       
  2200      * current shell.                                                         *
       
  2201      **************************************************************************/
       
  2202 
       
  2203     if ((how & Z_ASYNC) ||
       
  2204 	(!do_exec &&
       
  2205 	 (((is_builtin || is_shfunc) && output) ||
       
  2206 	  (!is_cursh && (last1 != 1 || nsigtrapped || havefiles()))))) {
       
  2207 
       
  2208 //	forked = 1;
       
  2209 	
       
  2210 	
       
  2211 	if (sigtrapped[SIGINT] & ZSIG_IGNORED)
       
  2212 	    holdintr();
       
  2213 #ifdef HAVE_NICE
       
  2214 	/* Check if we should run background jobs at a lower priority. */
       
  2215 	if ((how & Z_ASYNC) && isset(BGNICE))
       
  2216 	    nice(5);
       
  2217 #endif /* HAVE_NICE */
       
  2218 	
       
  2219     } else if (is_cursh) {
       
  2220 	/* This is a current shell procedure that didn't need to fork.    *
       
  2221 	 * This includes current shell procedures that are being exec'ed, *
       
  2222 	 * as well as null execs.                                         */
       
  2223 	jobtab[thisjob].stat |= STAT_CURSH;
       
  2224     } else {
       
  2225 	/* This is an exec (real or fake) for an external command.    *
       
  2226 	 * Note that any form of exec means that the subshell is fake *
       
  2227 	 * (but we may be in a subshell already).                     */
       
  2228 	is_exec = 1;
       
  2229     }
       
  2230     
       
  2231      
       
  2232   if ((esglob = !(cflags & BINF_NOGLOB)) && args && htok) {
       
  2233 	LinkList oargs = args;
       
  2234 	globlist(args, 0);
       
  2235 	args = oargs;
       
  2236     }
       
  2237     if (errflag) {
       
  2238 	lastval = 1;
       
  2239 	goto err;
       
  2240     }
       
  2241 
       
  2242     /* Make a copy of stderr for xtrace output before redirecting */
       
  2243     fflush(xtrerr);
       
  2244     if (isset(XTRACE) && xtrerr == stderr &&
       
  2245 	(type < WC_SUBSH || type == WC_TIMED)) {
       
  2246 	if (!(xtrerr = fdopen(movefd(dup(fileno(stderr))), "w")))
       
  2247 	    xtrerr = stderr;
       
  2248 	else
       
  2249 	    fdtable[fileno(xtrerr)] = 3;
       
  2250     }
       
  2251 
       
  2252     /* Add pipeline input/output to mnodes */
       
  2253 #ifndef __SYMBIAN32__
       
  2254     if (input)
       
  2255    		{
       
  2256     	addfd(forked, save, mfds, 0, input, 0);	
       
  2257    		}
       
  2258 	
       
  2259     if (output)
       
  2260 		{
       
  2261 		addfd(forked, save, mfds, 1, output, 1);    
       
  2262 	  	}
       
  2263 #endif
       
  2264     /* Do process substitutions */
       
  2265     if (redir)
       
  2266 	spawnpipes(redir, nullexec);
       
  2267 
       
  2268     /* Do io redirections */
       
  2269     while (redir && nonempty(redir)) {
       
  2270 	fn = (Redir) ugetnode(redir);
       
  2271 	DPUTS(fn->type == REDIR_HEREDOC || fn->type == REDIR_HEREDOCDASH,
       
  2272 	      "BUG: unexpanded here document");
       
  2273 	if (fn->type == REDIR_INPIPE) {
       
  2274 	    if (fn->fd2 == -1) {
       
  2275 		closemnodes(mfds);
       
  2276 		fixfds(save);
       
  2277 		execerr();
       
  2278 	    }
       
  2279 	    addfd(forked, save, mfds, fn->fd1, fn->fd2, 0);
       
  2280 	} else if (fn->type == REDIR_OUTPIPE) {
       
  2281 	    if (fn->fd2 == -1) {
       
  2282 		closemnodes(mfds);
       
  2283 		fixfds(save);
       
  2284 		execerr();
       
  2285 	    }
       
  2286 	    addfd(forked, save, mfds, fn->fd1, fn->fd2, 1);
       
  2287 	} else {
       
  2288 	    if (fn->type != REDIR_HERESTR && xpandredir(fn, redir))
       
  2289 		continue;
       
  2290 	    if (errflag) {
       
  2291 		closemnodes(mfds);
       
  2292 		fixfds(save);
       
  2293 		execerr();
       
  2294 	    }
       
  2295 	    if (isset(RESTRICTED) && IS_WRITE_FILE(fn->type)) {
       
  2296 		zwarn("writing redirection not allowed in restricted mode", NULL, 0);
       
  2297 		execerr();
       
  2298 	    }
       
  2299 	    if (unset(EXECOPT))
       
  2300 		continue;
       
  2301 	    switch(fn->type) {
       
  2302 	    case REDIR_HERESTR:
       
  2303 		fil = getherestr(fn);
       
  2304 		if (fil == -1) {
       
  2305 		    closemnodes(mfds);
       
  2306 		    fixfds(save);
       
  2307 		    if (errno != EINTR)
       
  2308 			zwarn("%e", NULL, errno);
       
  2309 		    execerr();
       
  2310 		}
       
  2311 		addfd(forked, save, mfds, fn->fd1, fil, 0);
       
  2312 		break;
       
  2313 	    case REDIR_READ:
       
  2314 	    case REDIR_READWRITE:
       
  2315 		if (fn->type == REDIR_READ)
       
  2316 		    fil = open(unmeta(fn->name), O_RDONLY | O_NOCTTY);
       
  2317 		else
       
  2318 		    fil = open(unmeta(fn->name),
       
  2319 			       O_RDWR | O_CREAT | O_NOCTTY, 0666);
       
  2320 		if (fil == -1) {
       
  2321 		    closemnodes(mfds);
       
  2322 		    fixfds(save);
       
  2323 		    if (errno != EINTR)
       
  2324 			zwarn("%e: %s", fn->name, errno);
       
  2325 		    execerr();
       
  2326 		}
       
  2327 		addfd(forked, save, mfds, fn->fd1, fil, 0);
       
  2328 		/* If this is 'exec < file', read from stdin, *
       
  2329 		 * not terminal, unless `file' is a terminal. */
       
  2330 		if (nullexec == 1 && fn->fd1 == 0 &&
       
  2331 		    isset(SHINSTDIN) && interact && !zleactive)
       
  2332 		    init_io();
       
  2333 		break;
       
  2334 	    case REDIR_CLOSE:
       
  2335 		if (!forked && fn->fd1 < 10 && save[fn->fd1] == -2)
       
  2336 		    save[fn->fd1] = movefd(fn->fd1);
       
  2337 		closemn(mfds, fn->fd1);
       
  2338 		zclose(fn->fd1);
       
  2339 		break;
       
  2340 	    case REDIR_MERGEIN:
       
  2341 	    case REDIR_MERGEOUT:
       
  2342 		if (fn->fd2 < 10)
       
  2343 		    closemn(mfds, fn->fd2);
       
  2344 		if (fn->fd2 > 9 &&
       
  2345 		    (fdtable[fn->fd2] ||
       
  2346 		     fn->fd2 == coprocin ||
       
  2347 		     fn->fd2 == coprocout)) {
       
  2348 		    fil = -1;
       
  2349 		    errno = EBADF;
       
  2350 		} else {
       
  2351 		    int fd = fn->fd2;
       
  2352 		    if(fd == -2)
       
  2353 			fd = (fn->type == REDIR_MERGEOUT) ? coprocout : coprocin;
       
  2354 		    fil = dup(fd);
       
  2355 		}
       
  2356 		if (fil == -1) {
       
  2357 		    char fdstr[4];
       
  2358 
       
  2359 		    closemnodes(mfds);
       
  2360 		    fixfds(save);
       
  2361 		    if (fn->fd2 != -2)
       
  2362 		    	sprintf(fdstr, "%d", fn->fd2);
       
  2363 		    zwarn("%s: %e", fn->fd2 == -2 ? "coprocess" : fdstr, errno);
       
  2364 		    execerr();
       
  2365 		}
       
  2366 		addfd(forked, save, mfds, fn->fd1, fil, fn->type == REDIR_MERGEOUT);
       
  2367 		break;
       
  2368 	    default:
       
  2369 		if (IS_APPEND_REDIR(fn->type))
       
  2370 		    fil = open(unmeta(fn->name),
       
  2371 			       (unset(CLOBBER) && !IS_CLOBBER_REDIR(fn->type)) ?
       
  2372 			       O_WRONLY | O_APPEND | O_NOCTTY :
       
  2373 			       O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY, 0666);
       
  2374 		else
       
  2375 		    fil = clobber_open(fn);
       
  2376 		if(fil != -1 && IS_ERROR_REDIR(fn->type))
       
  2377 		    dfil = dup(fil);
       
  2378 		else
       
  2379 		    dfil = 0;
       
  2380 		if (fil == -1 || dfil == -1) {
       
  2381 		    if(fil != -1)
       
  2382 			close(fil);
       
  2383 		    closemnodes(mfds);
       
  2384 		    fixfds(save);
       
  2385 		    if (errno != EINTR)
       
  2386 			zwarn("%e: %s", fn->name, errno);
       
  2387 		    execerr();
       
  2388 		}
       
  2389 		addfd(forked, save, mfds, fn->fd1, fil, 1);
       
  2390 		if(IS_ERROR_REDIR(fn->type))
       
  2391 		    addfd(forked, save, mfds, 2, dfil, 1);
       
  2392 		break;
       
  2393 	    }
       
  2394 	}
       
  2395     }
       
  2396 
       
  2397     /* We are done with redirection.  close the mnodes, *
       
  2398      * spawning tee/cat processes as necessary.         */
       
  2399     for (i = 0; i < 10; i++)
       
  2400 	if (mfds[i] && mfds[i]->ct >= 2)
       
  2401 	    closemn(mfds, i);
       
  2402 	
       
  2403     if (nullexec) {
       
  2404 	if (nullexec == 1) {
       
  2405 	    /*
       
  2406 	     * If nullexec is 1 we specifically *don't* restore the original
       
  2407 	     * fd's before returning.
       
  2408 	     */
       
  2409 	    for (i = 0; i < 10; i++)
       
  2410 		if (save[i] != -2)
       
  2411 		    zclose(save[i]);
       
  2412 	    goto done;
       
  2413 	}
       
  2414 	/*
       
  2415 	 * If nullexec is 2, we have variables to add with the redirections
       
  2416 	 * in place.
       
  2417 	 */
       
  2418 	if (varspc)
       
  2419 	    addvars(state, varspc, 0);
       
  2420 	lastval = errflag ? errflag : cmdoutval;
       
  2421 	if (isset(XTRACE)) {
       
  2422 	    fputc('\n', xtrerr);
       
  2423 	    fflush(xtrerr);
       
  2424 	}
       
  2425     } else if (isset(EXECOPT) && !errflag) {
       
  2426 	/*
       
  2427 	 * We delay the entersubsh() to here when we are exec'ing
       
  2428 	 * the current shell (including a fake exec to run a builtin then
       
  2429 	 * exit) in case there is an error return.
       
  2430 	 */
       
  2431 	if (is_exec)
       
  2432 	    entersubsh(how, (type != WC_SUBSH) ? 2 : 1, 1,
       
  2433 		       (do_exec || (type >= WC_CURSH && last1 == 1)) 
       
  2434 		       && !forked);
       
  2435 	if (type >= WC_CURSH) {
       
  2436 	    if (last1 == 1)
       
  2437 		do_exec = 1;
       
  2438 	    lastval = (execfuncs[type - WC_CURSH])(state, do_exec);
       
  2439 	} else if (is_builtin || is_shfunc) {
       
  2440 	    LinkList restorelist = 0, removelist = 0;
       
  2441 	    /* builtin or shell function */
       
  2442 
       
  2443 	    if (!forked && ((cflags & BINF_COMMAND) ||
       
  2444 			    (unset(POSIXBUILTINS) && !assign) ||
       
  2445 			    (isset(POSIXBUILTINS) && !is_shfunc &&
       
  2446 			     !(hn->flags & BINF_PSPECIAL)))) {
       
  2447 		if (varspc)
       
  2448 		    save_params(state, varspc, &restorelist, &removelist);
       
  2449 		else
       
  2450 		    restorelist = removelist = NULL;
       
  2451 	    }
       
  2452 	    if (varspc) {
       
  2453 		/* Export this if the command is a shell function,
       
  2454 		 * but not if it's a builtin.
       
  2455 		 */
       
  2456 		addvars(state, varspc, is_shfunc);
       
  2457 		if (errflag) {
       
  2458 		    if (restorelist)
       
  2459 			restore_params(restorelist, removelist);
       
  2460 		    lastval = 1;
       
  2461 		    fixfds(save);
       
  2462 		    goto done;
       
  2463 		}
       
  2464 	    }
       
  2465 
       
  2466 	    if (is_shfunc) {
       
  2467 		/* It's a shell function */
       
  2468 
       
  2469 #ifdef PATH_DEV_FD
       
  2470 		int i;
       
  2471 
       
  2472 		for (i = 10; i <= max_zsh_fd; i++)
       
  2473 		    if (fdtable[i] > 1)
       
  2474 			fdtable[i]++;
       
  2475 #endif
       
  2476 		if (subsh_close >= 0)
       
  2477 		    zclose(subsh_close);
       
  2478 		subsh_close = -1;
       
  2479 
       
  2480 		execshfunc((Shfunc) hn, args);
       
  2481 #ifdef PATH_DEV_FD
       
  2482 		for (i = 10; i <= max_zsh_fd; i++)
       
  2483 		    if (fdtable[i] > 1)
       
  2484 			if (--(fdtable[i]) <= 2)
       
  2485 			    zclose(i);
       
  2486 #endif
       
  2487 	    } else {
       
  2488 		/* It's a builtin */
       
  2489 		if (forked)
       
  2490 		    closem(1);		
       
  2491 		
       
  2492 		lastval = execbuiltin(args, (Builtin) hn, input, output);
       
  2493 		
       
  2494 #ifdef PATH_DEV_FD
       
  2495 		closem(2);
       
  2496 #endif
       
  2497 		fflush(stdout);
       
  2498 #ifdef __SYMBIAN32__		
       
  2499 		fflush(stderr);
       
  2500 #endif		
       
  2501 		if (save[1] == -2) {		
       
  2502 		    if (ferror(stdout)) {
       
  2503 			zwarn("write error: %e", NULL, errno);
       
  2504 			clearerr(stdout);			
       
  2505 		    }
       
  2506 		} else
       
  2507 		    clearerr(stdout);
       
  2508 	    }
       
  2509 	    if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) &&
       
  2510 		lastval && !subsh) {
       
  2511 		fprintf(stderr, "zsh: exit %ld\n", (long)lastval);
       
  2512 	    }
       
  2513 
       
  2514 	    if (do_exec) {
       
  2515 		if (subsh)
       
  2516 		    _exit(lastval);
       
  2517 
       
  2518 		/* If we are exec'ing a command, and we are not in a subshell, *
       
  2519 		 * then check if we should save the history file.              */
       
  2520 		if (isset(RCS) && interact && !nohistsave)
       
  2521 		    savehistfile(NULL, 1, HFILE_USE_OPTIONS);
       
  2522 		exit(lastval);
       
  2523 	    }
       
  2524 	    if (restorelist)
       
  2525 		restore_params(restorelist, removelist);
       
  2526 
       
  2527 	} else {
       
  2528 		pid_t pid;
       
  2529 		int fds[3];	
       
  2530 		struct timeval bgtime;
       
  2531     	struct timezone dummy_tz;
       
  2532 		char*  arg0 = (char *) peekfirst(args);
       
  2533 		
       
  2534 		gettimeofday(&bgtime, &dummy_tz);
       
  2535 			
       
  2536 	    if (!forked)
       
  2537 		setiparam("SHLVL", --shlvl);
       
  2538 	    if (do_exec) {
       
  2539 		/* If we are exec'ing a command, and we are not *
       
  2540 		 * in a subshell, then save the history file.   */
       
  2541 		if (!subsh && isset(RCS) && interact && !nohistsave)
       
  2542 		    savehistfile(NULL, 1, HFILE_USE_OPTIONS);
       
  2543 	    }
       
  2544 		if (varspc) {
       
  2545 		    addvars(state, varspc, -1);
       
  2546 		    if (errflag)
       
  2547 			_exit(1);
       
  2548 		}
       
  2549 		closem(1);
       
  2550 		if (coprocin)
       
  2551 		    zclose(coprocin);
       
  2552 		if (coprocout)
       
  2553 		    zclose(coprocout);
       
  2554 #ifdef HAVE_GETRLIMIT
       
  2555 		if (!forked)
       
  2556 		    setlimits(NULL);
       
  2557 #endif
       
  2558 		if (how & Z_ASYNC) {
       
  2559 		    zsfree(STTYval);
       
  2560 		    STTYval = 0;
       
  2561 		}
       
  2562 		
       
  2563 #ifdef __SYMBIAN32__
       
  2564 		{
       
  2565 		//find and execute the external command
       
  2566 		const int data_size=512;		
       
  2567 		char data[data_size];
       
  2568 		int read_cnt=0;
       
  2569 		char** argv;
       
  2570 	    fd_set readfds;		
       
  2571 	    int status=-1;
       
  2572 	    size_t oldcmdlen=0, newcmdlen=0;
       
  2573     	struct timeval tv;
       
  2574     	char *pcmd=NULL;
       
  2575     	char* pfile=NULL;
       
  2576     	
       
  2577 	    //generate full path
       
  2578 		argv=makecline(args);			
       
  2579 		pfile=argv[0];
       
  2580 		
       
  2581 		//generate commands		
       
  2582 		while(++argv && *argv)
       
  2583 			{	
       
  2584 			newcmdlen=strlen(*argv)+newcmdlen+1;			
       
  2585 			if(!pcmd)
       
  2586 				pcmd=(char*)calloc(newcmdlen+1, sizeof(char));
       
  2587 			else
       
  2588 				pcmd=(char*)realloc(pcmd, newcmdlen+1);			
       
  2589 			
       
  2590 			sprintf(pcmd+oldcmdlen, "%s ", *argv);												
       
  2591 			oldcmdlen=newcmdlen;			
       
  2592 			}
       
  2593 
       
  2594 		//execute the external command
       
  2595 		if ( (pid=popen3(pfile, pcmd, environ, fds)) == -1) 
       
  2596 			{ 
       
  2597 		    zerr("command not found: %s", arg0, 0);							
       
  2598 			opts[AUTOCONTINUE] = oautocont;
       
  2599 			clearfds();
       
  2600 			free(pcmd);
       
  2601 			lastval=127;
       
  2602 		    return;		
       
  2603 			}			
       
  2604 		free(pcmd);
       
  2605 
       
  2606 		if(input || output)
       
  2607 			{
       
  2608 			handlePipeCmds(pfile, pid, fds, output);	
       
  2609 			}
       
  2610 		else
       
  2611 			{
       
  2612 			//read the output from the executed command
       
  2613 		    for(;;)
       
  2614 			    {				        
       
  2615 			    int wait_pid=waitpid(pid, &status, WNOHANG);
       
  2616 			    if(pid == wait_pid || wait_pid == -1) //dont wait for the child to terminate
       
  2617 				    {
       
  2618 				    int max= MAX(fds[1], fds[2]);
       
  2619 				    
       
  2620 				    FD_ZERO(&readfds);	    
       
  2621 				    FD_SET(fds[1], &readfds); 					    
       
  2622 					FD_SET(fds[2], &readfds);
       
  2623 						    
       
  2624 				    //read available data, if child is terminated already.
       
  2625 				    for(;;)	
       
  2626 				    	{	
       
  2627 					    tv.tv_sec = 1;
       
  2628 					    tv.tv_usec = 0;    	    
       
  2629 							    				    	
       
  2630 				        if(select(max+1, &readfds, NULL, NULL, &tv) <=0)		       
       
  2631 				    		break;	 			    	
       
  2632 				        else
       
  2633 				        	{		
       
  2634 				   		    if(FD_ISSET(fds[1], &readfds))
       
  2635 								{
       
  2636 								memset(&data[0], 0, 512);				
       
  2637 								read_cnt=read(fds[1], &data[0], 512);	
       
  2638 								if(read_cnt>0)
       
  2639 									write(1, data, read_cnt);							
       
  2640 								}							
       
  2641 			
       
  2642 							if(FD_ISSET(fds[2], &readfds))
       
  2643 								{
       
  2644 								memset(&data[0], 0, 512);				
       
  2645 								read_cnt=read(fds[2], &data[0], 512);	
       
  2646 								if(read_cnt>0)
       
  2647 									write(2, data, read_cnt);							
       
  2648 								}	    			        		
       
  2649 				        	}			          			    		
       
  2650 				    	}
       
  2651 				    //Updating the Error status.
       
  2652 				    if(WIFEXITED(status))
       
  2653 				    	lastval = WEXITSTATUS(status);
       
  2654 				    else if(WIFTERMINATED(status))
       
  2655 				    	lastval = WTERMINATESTATUS(status);
       
  2656 				    else if(WIFPANICED(status))
       
  2657 				    	lastval = WPANICCODE(status);							
       
  2658 				    break;	
       
  2659 				    }
       
  2660 				else
       
  2661 					{				
       
  2662 					int max= MAX(0, MAX(fds[1], fds[2]));
       
  2663 									
       
  2664 				    FD_ZERO(&readfds);						    						
       
  2665 				    FD_SET(fds[1], &readfds); 						    						
       
  2666 					FD_SET(fds[2], &readfds);  	
       
  2667 					FD_SET(0, &readfds);  	
       
  2668 			
       
  2669 					tv.tv_sec = 1;
       
  2670 					tv.tv_usec = 0;   
       
  2671 					    			
       
  2672 				    if(select(max+1, &readfds, NULL, NULL, &tv) < 0)
       
  2673 				    	break;
       
  2674 				    		
       
  2675 				    else
       
  2676 				        {
       
  2677 				        if(FD_ISSET(fds[1], &readfds))
       
  2678 							{
       
  2679 							memset(&data[0], 0, 512);				
       
  2680 							read_cnt=read(fds[1], &data[0], 512);	
       
  2681 							if(read_cnt>0)
       
  2682 								write(1, data, read_cnt);							
       
  2683 							}
       
  2684 			
       
  2685 						if(FD_ISSET(fds[2], &readfds))
       
  2686 							{
       
  2687 							memset(&data[0], 0, 512);				
       
  2688 							read_cnt=read(fds[2], &data[0], 512);	
       
  2689 							if(read_cnt>0)
       
  2690 								write(2, data, read_cnt);							
       
  2691 							}
       
  2692 									
       
  2693 						if(FD_ISSET(0, &readfds))
       
  2694 							{
       
  2695 							memset(&data[0], 0, 512);				
       
  2696 							read_cnt=read(0, &data[0], 512);	
       
  2697 							if(read_cnt>0)
       
  2698 								write(fds[0], data, read_cnt);							
       
  2699 							}							    			        		
       
  2700 				        }//else			          			    		
       
  2701 		    					
       
  2702 					}  //else
       
  2703 			    }//for (;;)				
       
  2704 			close(fds[0]);
       
  2705 			close(fds[1]);
       
  2706 			close(fds[2]);
       
  2707 			}	
       
  2708 		}
       
  2709 #endif		
       
  2710    		if (how & Z_ASYNC) {
       
  2711 			lastpid = (zlong) pid;
       
  2712     	} else if (!jobtab[thisjob].stty_in_env && varspc) {
       
  2713 		/* search for STTY=... */
       
  2714 		Wordcode p = varspc;
       
  2715 		wordcode ac;
       
  2716 
       
  2717 		while (wc_code(ac = *p) == WC_ASSIGN) {
       
  2718 		    if (!strcmp(ecrawstr(state->prog, p + 1, NULL), "STTY")) {
       
  2719 			jobtab[thisjob].stty_in_env = 1;
       
  2720 			break;
       
  2721 	    	}
       
  2722 	    	p += (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR ?
       
  2723 		  	3 : WC_ASSIGN_NUM(ac) + 2);
       
  2724 	   }
       
  2725 	   }
       
  2726 	   opts[AUTOCONTINUE] = oautocont;	   
       
  2727 	   fixfds(save);
       
  2728        return;
       
  2729     }
       
  2730     }
       
  2731 
       
  2732   err:
       
  2733     if (forked)
       
  2734 	_exit(lastval);
       
  2735     fixfds(save);
       
  2736 
       
  2737  done:
       
  2738     if (xtrerr != oxtrerr) {
       
  2739 	fil = fileno(xtrerr);
       
  2740 	fclose(xtrerr);
       
  2741 	xtrerr = oxtrerr;
       
  2742 	zclose(fil);
       
  2743     }
       
  2744 
       
  2745     zsfree(STTYval);
       
  2746     STTYval = 0;
       
  2747     opts[AUTOCONTINUE] = oautocont;
       
  2748   
       
  2749 }
       
  2750 
       
  2751 /* Arrange to have variables restored. */
       
  2752 
       
  2753 /**/
       
  2754 static void
       
  2755 save_params(Estate state, Wordcode pc, LinkList *restore_p, LinkList *remove_p)
       
  2756 {
       
  2757     Param pm;
       
  2758     char *s;
       
  2759     wordcode ac;
       
  2760 
       
  2761     *restore_p = newlinklist();
       
  2762     *remove_p = newlinklist();
       
  2763 
       
  2764     while (wc_code(ac = *pc) == WC_ASSIGN) {
       
  2765 	s = ecrawstr(state->prog, pc + 1, NULL);
       
  2766 	if ((pm = (Param) paramtab->getnode(paramtab, s))) {
       
  2767 	    if (pm->env)
       
  2768 		delenv(pm);
       
  2769 	    if (!(pm->flags & PM_SPECIAL)) {
       
  2770 		paramtab->removenode(paramtab, s);
       
  2771 	    } else if (!(pm->flags & PM_READONLY) &&
       
  2772 		       (unset(RESTRICTED) || !(pm->flags & PM_RESTRICTED))) {
       
  2773 		Param tpm = (Param) hcalloc(sizeof *tpm);
       
  2774 		tpm->nam = pm->nam;
       
  2775 		copyparam(tpm, pm, 1);
       
  2776 		pm = tpm;
       
  2777 	    }
       
  2778 	    addlinknode(*remove_p, dupstring(s));
       
  2779 	    addlinknode(*restore_p, pm);
       
  2780 	} else
       
  2781 	    addlinknode(*remove_p, dupstring(s));
       
  2782 
       
  2783 	pc += (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR ?
       
  2784 	       3 : WC_ASSIGN_NUM(ac) + 2);
       
  2785     }
       
  2786 }
       
  2787 
       
  2788 /* Restore saved parameters after executing a shfunc or builtin */
       
  2789 
       
  2790 /**/
       
  2791 static void
       
  2792 restore_params(LinkList restorelist, LinkList removelist)
       
  2793 {
       
  2794     Param pm;
       
  2795     char *s;
       
  2796 
       
  2797     /* remove temporary parameters */
       
  2798     while ((s = (char *) ugetnode(removelist))) {
       
  2799 	if ((pm = (Param) paramtab->getnode(paramtab, s)) &&
       
  2800 	    !(pm->flags & PM_SPECIAL)) {
       
  2801 	    pm->flags &= ~PM_READONLY;
       
  2802 	    unsetparam_pm(pm, 0, 0);
       
  2803 	}
       
  2804     }
       
  2805 
       
  2806     if (restorelist) {
       
  2807 	/* restore saved parameters */
       
  2808 	while ((pm = (Param) ugetnode(restorelist))) {
       
  2809 	    if (pm->flags & PM_SPECIAL) {
       
  2810 		Param tpm = (Param) paramtab->getnode(paramtab, pm->nam);
       
  2811 
       
  2812 		DPUTS(!tpm || PM_TYPE(pm->flags) != PM_TYPE(tpm->flags) ||
       
  2813 		      !(pm->flags & PM_SPECIAL),
       
  2814 		      "BUG: in restoring special parameters");
       
  2815 		tpm->flags = pm->flags;
       
  2816 		switch (PM_TYPE(pm->flags)) {
       
  2817 		case PM_SCALAR:
       
  2818 		    tpm->gsu.s->setfn(tpm, pm->u.str);
       
  2819 		    break;
       
  2820 		case PM_INTEGER:
       
  2821 		    tpm->gsu.i->setfn(tpm, pm->u.val);
       
  2822 		    break;
       
  2823 		case PM_EFLOAT:
       
  2824 		case PM_FFLOAT:
       
  2825 		    tpm->gsu.f->setfn(tpm, pm->u.dval);
       
  2826 		    break;
       
  2827 		case PM_ARRAY:
       
  2828 		    tpm->gsu.a->setfn(tpm, pm->u.arr);
       
  2829 		    break;
       
  2830 		case PM_HASHED:
       
  2831 		    tpm->gsu.h->setfn(tpm, pm->u.hash);
       
  2832 		    break;
       
  2833 		}
       
  2834 		pm = tpm;
       
  2835 	    } else
       
  2836 		paramtab->addnode(paramtab, pm->nam, pm);
       
  2837 	    if ((pm->flags & PM_EXPORTED) && ((s = getsparam(pm->nam))))
       
  2838 		addenv(pm, s);
       
  2839 	}
       
  2840     }
       
  2841 }
       
  2842 
       
  2843 /* restore fds after redirecting a builtin */
       
  2844 
       
  2845 /**/
       
  2846 static void
       
  2847 fixfds(int *save)
       
  2848 {
       
  2849     int old_errno = errno;
       
  2850     int i;
       
  2851 
       
  2852     for (i = 0; i != 10; i++)
       
  2853 	if (save[i] != -2)
       
  2854 	    redup(save[i], i);
       
  2855     errno = old_errno;
       
  2856 }
       
  2857 
       
  2858 /**/
       
  2859 int
       
  2860 forklevel;
       
  2861 
       
  2862 /**/
       
  2863 static void
       
  2864 entersubsh(int how, int cl, int fake, int revertpgrp)
       
  2865 {
       
  2866     int sig, monitor;
       
  2867 
       
  2868     if (cl != 2)
       
  2869 	for (sig = 0; sig < VSIGCOUNT; sig++)
       
  2870 	    if (!(sigtrapped[sig] & ZSIG_FUNC))
       
  2871 		unsettrap(sig);
       
  2872     if (!(monitor = isset(MONITOR))) {
       
  2873 	if (how & Z_ASYNC) {
       
  2874 	    settrap(SIGINT, NULL);
       
  2875 	    settrap(SIGQUIT, NULL);
       
  2876 	    if (isatty(0)) {
       
  2877 		close(0);
       
  2878 		if (open("/dev/null", O_RDWR | O_NOCTTY)) {
       
  2879 		    zerr("can't open /dev/null: %e", NULL, errno);
       
  2880 		    _exit(1);
       
  2881 		}
       
  2882 	    }
       
  2883 	}
       
  2884     } else if (thisjob != -1 && cl) {
       
  2885 	if (jobtab[list_pipe_job].gleader && (list_pipe || list_pipe_child)) {
       
  2886 	    if (setpgrp(0L, jobtab[list_pipe_job].gleader) == -1 ||
       
  2887 		killpg(jobtab[list_pipe_job].gleader, 0) == -1) {
       
  2888 		jobtab[list_pipe_job].gleader =
       
  2889 		    jobtab[thisjob].gleader = (list_pipe_child ? mypgrp : getpid());
       
  2890 		setpgrp(0L, jobtab[list_pipe_job].gleader);
       
  2891 		if (how & Z_SYNC)
       
  2892 		    attachtty(jobtab[thisjob].gleader);
       
  2893 	    }
       
  2894 	}
       
  2895 	else if (!jobtab[thisjob].gleader ||
       
  2896 		 setpgrp(0L, jobtab[thisjob].gleader) == -1) {
       
  2897 	    jobtab[thisjob].gleader = getpid();
       
  2898 	    if (list_pipe_job != thisjob &&
       
  2899 		!jobtab[list_pipe_job].gleader)
       
  2900 		jobtab[list_pipe_job].gleader = jobtab[thisjob].gleader;
       
  2901 	    setpgrp(0L, jobtab[thisjob].gleader);
       
  2902 	    if (how & Z_SYNC)
       
  2903 		attachtty(jobtab[thisjob].gleader);
       
  2904 	}
       
  2905     }
       
  2906     if (!fake)
       
  2907 	subsh = 1;
       
  2908     if (revertpgrp && getpid() == mypgrp)
       
  2909 	release_pgrp();
       
  2910     if (SHTTY != -1) {
       
  2911 	shout = NULL;
       
  2912 	zclose(SHTTY);
       
  2913 	SHTTY = -1;
       
  2914     }
       
  2915     if (isset(MONITOR)) {
       
  2916 	signal_default(SIGTTOU);
       
  2917 	signal_default(SIGTTIN);
       
  2918 	signal_default(SIGTSTP);
       
  2919     }
       
  2920     if (interact) {
       
  2921 	signal_default(SIGTERM);
       
  2922 	if (!(sigtrapped[SIGINT] & ZSIG_IGNORED))
       
  2923 	    signal_default(SIGINT);
       
  2924     }
       
  2925     if (!(sigtrapped[SIGQUIT] & ZSIG_IGNORED))
       
  2926 	signal_default(SIGQUIT);
       
  2927     opts[MONITOR] = opts[USEZLE] = 0;
       
  2928     zleactive = 0;
       
  2929     if (cl)
       
  2930 	clearjobtab(monitor);
       
  2931     get_usage();
       
  2932     forklevel = locallevel;
       
  2933 }
       
  2934 
       
  2935 /* close internal shell fds */
       
  2936 
       
  2937 /**/
       
  2938 mod_export void
       
  2939 closem(int how)
       
  2940 {
       
  2941     int i;
       
  2942 
       
  2943     for (i = 10; i <= max_zsh_fd; i++)
       
  2944 	if (fdtable[i] && (!how || fdtable[i] == how))
       
  2945 	    zclose(i);
       
  2946 }
       
  2947 
       
  2948 /* convert here document into a here string */
       
  2949 
       
  2950 /**/
       
  2951 char *
       
  2952 gethere(char *str, int typ)
       
  2953 {
       
  2954     char *buf;
       
  2955     int bsiz, qt = 0, strip = 0;
       
  2956     char *s, *t, *bptr, c;
       
  2957 
       
  2958     for (s = str; *s; s++)
       
  2959 	if (INULL(*s)) {
       
  2960 	    qt = 1;
       
  2961 	    break;
       
  2962 	}
       
  2963     quotesubst(str);
       
  2964     untokenize(str);
       
  2965     if (typ == REDIR_HEREDOCDASH) {
       
  2966 	strip = 1;
       
  2967 	while (*str == '\t')
       
  2968 	    str++;
       
  2969     }
       
  2970     bptr = buf = zalloc(bsiz = 256);
       
  2971     for (;;) {
       
  2972 	t = bptr;
       
  2973 
       
  2974 	while ((c = hgetc()) == '\t' && strip)
       
  2975 	    ;
       
  2976 	for (;;) {
       
  2977 	    if (bptr == buf + bsiz) {
       
  2978 		buf = realloc(buf, 2 * bsiz);
       
  2979 		t = buf + bsiz - (bptr - t);
       
  2980 		bptr = buf + bsiz;
       
  2981 		bsiz *= 2;
       
  2982 	    }
       
  2983 	    if (lexstop || c == '\n')
       
  2984 		break;
       
  2985 	    *bptr++ = c;
       
  2986 	    c = hgetc();
       
  2987 	}
       
  2988 	*bptr = '\0';
       
  2989 	if (!strcmp(t, str))
       
  2990 	    break;
       
  2991 	if (lexstop) {
       
  2992 	    t = bptr;
       
  2993 	    break;
       
  2994 	}
       
  2995 	*bptr++ = '\n';
       
  2996     }
       
  2997     if (t > buf && t[-1] == '\n')
       
  2998 	t--;
       
  2999     *t = '\0';
       
  3000     if (!qt) {
       
  3001 	int ef = errflag;
       
  3002 
       
  3003 	parsestr(buf);
       
  3004 
       
  3005 	if (!errflag)
       
  3006 	    errflag = ef;
       
  3007     }
       
  3008     s = dupstring(buf);
       
  3009     zfree(buf, bsiz);
       
  3010     return s;
       
  3011 }
       
  3012 
       
  3013 /* open here string fd */
       
  3014 
       
  3015 /**/
       
  3016 static int
       
  3017 getherestr(struct redir *fn)
       
  3018 {
       
  3019     char *s, *t;
       
  3020     int fd, len;
       
  3021 
       
  3022     t = fn->name;
       
  3023     singsub(&t);
       
  3024     untokenize(t);
       
  3025     unmetafy(t, &len);
       
  3026     t[len++] = '\n';
       
  3027     if ((fd = gettempfile(NULL, 1, &s)) < 0)
       
  3028 	return -1;
       
  3029     write(fd, t, len);
       
  3030     close(fd);
       
  3031     fd = open(s, O_RDONLY | O_NOCTTY);
       
  3032     unlink(s);
       
  3033     return fd;
       
  3034 }
       
  3035 
       
  3036 /* $(...) */
       
  3037 
       
  3038 /**/
       
  3039 LinkList
       
  3040 getoutput(char *cmd, int qt)
       
  3041 {
       
  3042     Eprog prog;
       
  3043     int pipes[2];
       
  3044 	
       
  3045 #ifndef __SYMBIAN32__    
       
  3046     pid_t pid;    
       
  3047 #endif    
       
  3048     Wordcode pc;
       
  3049     int fd;
       
  3050 	LinkList retval;
       
  3051     if (!(prog = parse_string(cmd)))
       
  3052 	return NULL;
       
  3053 
       
  3054     pc = prog->prog;
       
  3055     if (prog != &dummy_eprog &&
       
  3056 	wc_code(pc[0]) == WC_LIST && (WC_LIST_TYPE(pc[0]) & Z_END) &&
       
  3057 	wc_code(pc[1]) == WC_SUBLIST && !WC_SUBLIST_FLAGS(pc[1]) &&
       
  3058 	WC_SUBLIST_TYPE(pc[1]) == WC_SUBLIST_END &&
       
  3059 	wc_code(pc[2]) == WC_PIPE && WC_PIPE_TYPE(pc[2]) == WC_PIPE_END &&
       
  3060 	wc_code(pc[3]) == WC_REDIR && WC_REDIR_TYPE(pc[3]) == REDIR_READ && 
       
  3061 	!pc[4] &&
       
  3062 	wc_code(pc[6]) == WC_SIMPLE && !WC_SIMPLE_ARGC(pc[6])) {
       
  3063 	/* $(< word) */
       
  3064 	int stream;
       
  3065 	char *s = dupstring(ecrawstr(prog, pc + 5, NULL));
       
  3066 
       
  3067 	singsub(&s);
       
  3068 	if (errflag)
       
  3069 	    return NULL;
       
  3070 	untokenize(s);
       
  3071 	if ((stream = open(unmeta(s), O_RDONLY | O_NOCTTY)) == -1) {
       
  3072 	    zerr("%e: %s", s, errno);
       
  3073 	    return NULL;
       
  3074 	}
       
  3075 	return readoutput(stream, qt);
       
  3076     }
       
  3077 #ifndef __SYMBIAN32__
       
  3078     mpipe(pipes);
       
  3079     child_block();
       
  3080     cmdoutval = 0;
       
  3081     if ((cmdoutpid = pid = zfork(NULL)) == -1) {
       
  3082 	/* fork error */
       
  3083 	zclose(pipes[0]);
       
  3084 	zclose(pipes[1]);
       
  3085 	errflag = 1;
       
  3086 	cmdoutpid = 0;
       
  3087 	child_unblock();
       
  3088 	return NULL;
       
  3089     } else if (pid) {
       
  3090 	LinkList retval;
       
  3091 
       
  3092 	zclose(pipes[1]);
       
  3093 	retval = readoutput(pipes[0], qt);
       
  3094 	fdtable[pipes[0]] = 0;
       
  3095 	waitforpid(pid);		/* unblocks */
       
  3096 	lastval = cmdoutval;
       
  3097 	return retval;
       
  3098     }
       
  3099     /* pid == 0 */
       
  3100     child_unblock();
       
  3101     zclose(pipes[0]);
       
  3102     redup(pipes[1], 1);
       
  3103     opts[MONITOR] = 0;
       
  3104     entersubsh(Z_SYNC, 1, 0, 0);
       
  3105     cmdpush(CS_CMDSUBST);
       
  3106 
       
  3107     cmdpop();
       
  3108     close(1);
       
  3109     _exit(lastval);
       
  3110     zerr("exit returned in child!!", NULL, 0);
       
  3111     kill(getpid(), SIGKILL);
       
  3112 #endif  // __SYMBIAN32__
       
  3113 
       
  3114 	//execute the command within the same process space
       
  3115     mpipe(pipes); 
       
  3116 	fd = dup(1);		/* Preserve stdout */
       
  3117 	fcntl(fd, F_SETFD, FD_CLOEXEC);
       
  3118 					    
       
  3119     redup(pipes[1], 1);            
       
  3120     execode(prog, 0, 1);       
       
  3121 
       
  3122 	retval=readoutput(pipes[0], qt);   					
       
  3123 	redup(fd, 1);
       
  3124 	zclose(pipes[0]);
       
  3125 	zclose(pipes[1]);
       
  3126 	close(fd);
       
  3127 			
       
  3128 	return retval;	
       
  3129 }
       
  3130 
       
  3131 /* read output of command substitution */
       
  3132 
       
  3133 /**/
       
  3134 mod_export LinkList
       
  3135 readoutput(int in, int qt)
       
  3136 {
       
  3137     LinkList ret;
       
  3138     char *buf, *ptr;
       
  3139     int bsiz, cnt = 0;
       
  3140     char c;
       
  3141     FILE *fin;
       
  3142 #ifdef __SYMBIAN32__    
       
  3143     struct timeval tv;	        
       
  3144     fd_set readfds;	        
       
  3145     
       
  3146 	FD_ZERO(&readfds);
       
  3147 	FD_SET(in, &readfds); 
       
  3148 	  
       
  3149 	tv.tv_sec = 0;
       
  3150 	tv.tv_usec = 1;    	    						    				    	
       
  3151 	
       
  3152     fin = fdopen(in, "r");
       
  3153     ret = newlinklist();
       
  3154     ptr = buf = (char *) hcalloc(bsiz = 64);
       
  3155 	if(select(in+1, &readfds, NULL, NULL, &tv)==0)	    
       
  3156 		{
       
  3157 		goto dont_read;	
       
  3158 		}				
       
  3159 #endif //__SYMBIAN32__
       
  3160 
       
  3161     while ((read(in, &c, 1) >0) || errno == EINTR) {    
       
  3162 #ifndef __SYMBIAN32__    
       
  3163 	if (c == EOF) {
       
  3164 	    errno = 0;
       
  3165 	    clearerr(fin);
       
  3166 	    continue;
       
  3167 	}
       
  3168 #endif	
       
  3169 	if (imeta(c)) {
       
  3170 	    *ptr++ = Meta;
       
  3171 	    c ^= 32;
       
  3172 	    cnt++;
       
  3173 	}
       
  3174 	if (++cnt >= bsiz) {
       
  3175 	    char *pp = (char *) hcalloc(bsiz *= 2);
       
  3176 
       
  3177 	    memcpy(pp, buf, cnt - 1);
       
  3178 	    ptr = (buf = pp) + cnt - 1;
       
  3179 	}
       
  3180 	*ptr++ = c;
       
  3181 #ifndef __SYMBIAN32__
       
  3182 	if (ptr[-1]=='\n')
       
  3183 		{
       
  3184 		break;
       
  3185 		}
       
  3186 #else
       
  3187 	FD_ZERO(&readfds);
       
  3188 	FD_SET(in, &readfds); 
       
  3189 	if(select(in+1, &readfds, NULL, NULL, &tv)==0)
       
  3190 		{
       
  3191 		break;	
       
  3192 		}
       
  3193 #endif		
       
  3194     }
       
  3195 
       
  3196 dont_read:   
       
  3197     fclose(fin);
       
  3198     while (cnt && ptr[-1] == '\n')
       
  3199 	ptr--, cnt--;
       
  3200     *ptr = '\0';
       
  3201     if (qt) {
       
  3202 	if (!cnt) {
       
  3203 	    *ptr++ = Nularg;
       
  3204 	    *ptr = '\0';
       
  3205 	}
       
  3206 	addlinknode(ret, buf);
       
  3207     } else {
       
  3208 	char **words = spacesplit(buf, 0, 1, 0);
       
  3209 
       
  3210 	while (*words) {
       
  3211 	    if (isset(GLOBSUBST))
       
  3212 		shtokenize(*words);
       
  3213 	    addlinknode(ret, *words++);
       
  3214 	}
       
  3215     }
       
  3216     return ret;
       
  3217 }
       
  3218 
       
  3219 /**/
       
  3220 static Eprog
       
  3221 parsecmd(char *cmd)
       
  3222 {
       
  3223     char *str;
       
  3224     Eprog prog;
       
  3225 
       
  3226     for (str = cmd + 2; *str && *str != Outpar; str++);
       
  3227     if (!*str || cmd[1] != Inpar) {
       
  3228 	zerr("oops.", NULL, 0);
       
  3229 	return NULL;
       
  3230     }
       
  3231     *str = '\0';
       
  3232     if (str[1] || !(prog = parse_string(cmd + 2))) {
       
  3233 	zerr("parse error in process substitution", NULL, 0);
       
  3234 	return NULL;
       
  3235     }
       
  3236     return prog;
       
  3237 }
       
  3238 
       
  3239 /* =(...) */
       
  3240 
       
  3241 /**/
       
  3242 char *
       
  3243 getoutputfile(char *cmd)
       
  3244 {
       
  3245     Eprog prog;
       
  3246 
       
  3247 #ifndef __SYMBIAN32__
       
  3248     pid_t pid;
       
  3249     char *nam;
       
  3250     int fd;
       
  3251            
       
  3252     if (thisjob == -1)
       
  3253 	return NULL;
       
  3254     if (!(prog = parsecmd(cmd)))
       
  3255 	return NULL;
       
  3256     if (!(nam = gettempname(NULL, 0)))
       
  3257 	return NULL;
       
  3258 
       
  3259     if (!jobtab[thisjob].filelist)
       
  3260 	jobtab[thisjob].filelist = znewlinklist();
       
  3261     zaddlinknode(jobtab[thisjob].filelist, nam);
       
  3262 
       
  3263     child_block();
       
  3264     fd = open(nam, O_WRONLY | O_CREAT | O_EXCL | O_NOCTTY, 0600);
       
  3265 
       
  3266     if (fd < 0 || (cmdoutpid = pid = zfork(NULL)) == -1) {
       
  3267 	/* fork or open error */
       
  3268 	child_unblock();
       
  3269 	return nam;
       
  3270     } else if (pid) {
       
  3271 	int os;
       
  3272 
       
  3273 	close(fd);
       
  3274 	os = jobtab[thisjob].stat;
       
  3275 	waitforpid(pid);
       
  3276 	cmdoutval = 0;
       
  3277 	jobtab[thisjob].stat = os;
       
  3278 	return nam;
       
  3279     }
       
  3280 
       
  3281     /* pid == 0 */
       
  3282     redup(fd, 1);
       
  3283     opts[MONITOR] = 0;
       
  3284     entersubsh(Z_SYNC, 1, 0, 0);
       
  3285     cmdpush(CS_CMDSUBST);
       
  3286     execode(prog, 0, 1);
       
  3287     cmdpop();
       
  3288     close(1);
       
  3289     _exit(lastval);
       
  3290     zerr("exit returned in child!!", NULL, 0);
       
  3291     kill(getpid(), SIGKILL);
       
  3292     return NULL;
       
  3293 #else
       
  3294 	st_exec stexec;
       
  3295 	pthread_t testThread;
       
  3296 		
       
  3297     if (!(prog = parsecmd(cmd)))
       
  3298 	  return NULL;   
       
  3299     	
       
  3300 	stexec.dont_change_job=0;
       
  3301 	stexec.exiting=1;
       
  3302 	stexec.p=prog;
       
  3303 	
       
  3304 	pthread_create(&testThread, NULL, &execode_wrap, (void*)&stexec);
       
  3305 	return NULL;
       
  3306 #endif    
       
  3307 }
       
  3308 
       
  3309 #if !defined(PATH_DEV_FD) && defined(HAVE_FIFOS)
       
  3310 /* get a temporary named pipe */
       
  3311 
       
  3312 static char *
       
  3313 namedpipe(void)
       
  3314 {
       
  3315     char *tnam = gettempname(NULL, 1);
       
  3316 
       
  3317 # ifdef HAVE_MKFIFO
       
  3318     if (mkfifo(tnam, 0600) < 0)
       
  3319 # else
       
  3320     if (mknod(tnam, 0010600, 0) < 0)
       
  3321 # endif
       
  3322 	return NULL;
       
  3323     return tnam;
       
  3324 }
       
  3325 #endif /* ! PATH_DEV_FD && HAVE_FIFOS */
       
  3326 
       
  3327 /* <(...) or >(...) */
       
  3328 
       
  3329 /**/
       
  3330 char *
       
  3331 getproc(char *cmd)
       
  3332 {
       
  3333 #if !defined(HAVE_FIFOS) && !defined(PATH_DEV_FD)
       
  3334     zerr("doesn't look like your system supports FIFOs.", NULL, 0);
       
  3335     return NULL;
       
  3336 #else
       
  3337     Eprog prog;
       
  3338     int out = *cmd == Inang;
       
  3339 
       
  3340 #ifndef __SYMBIAN32__
       
  3341     char *pnam;
       
  3342     pid_t pid;
       
  3343     struct timeval bgtime;
       
  3344     
       
  3345 #ifndef PATH_DEV_FD
       
  3346     int fd;
       
  3347     if (thisjob == -1)
       
  3348 	return NULL;
       
  3349     if (!(pnam = namedpipe()))
       
  3350 	return NULL;
       
  3351     if (!(prog = parsecmd(cmd)))
       
  3352 	return NULL;
       
  3353     if (!jobtab[thisjob].filelist)
       
  3354 	jobtab[thisjob].filelist = znewlinklist();
       
  3355     zaddlinknode(jobtab[thisjob].filelist, ztrdup(pnam));
       
  3356     
       
  3357     if ((pid = zfork(&bgtime))) {
       
  3358 	if (pid == -1)
       
  3359 	    return NULL;
       
  3360 	if (!out)
       
  3361 	    addproc(pid, NULL, 1, &bgtime);
       
  3362 	return pnam;
       
  3363     }
       
  3364     closem(0);
       
  3365     fd = open(pnam, out ? O_WRONLY | O_NOCTTY : O_RDONLY | O_NOCTTY);
       
  3366     if (fd == -1) {
       
  3367 	zerr("can't open %s: %e", pnam, errno);
       
  3368 	_exit(1);
       
  3369     }
       
  3370     entersubsh(Z_ASYNC, 1, 0, 0);
       
  3371     redup(fd, out);
       
  3372 #else /* PATH_DEV_FD */    
       
  3373     int pipes[2];
       
  3374 
       
  3375     if (thisjob == -1)
       
  3376 	return NULL;
       
  3377     pnam = hcalloc(strlen(PATH_DEV_FD) + 6);
       
  3378     if (!(prog = parsecmd(cmd)))
       
  3379 	return NULL;
       
  3380     mpipe(pipes);
       
  3381     if ((pid = zfork(&bgtime))) {
       
  3382 	sprintf(pnam, "%s/%d", PATH_DEV_FD, pipes[!out]);
       
  3383 	zclose(pipes[out]);
       
  3384 	if (pid == -1)
       
  3385 	{
       
  3386 	    zclose(pipes[!out]);
       
  3387 	    return NULL;
       
  3388 	}
       
  3389 	fdtable[pipes[!out]] = 2;
       
  3390 	if (!out)
       
  3391 	{
       
  3392 	    addproc(pid, NULL, 1, &bgtime);
       
  3393 	}
       
  3394 	return pnam;
       
  3395     }
       
  3396     entersubsh(Z_ASYNC, 1, 0, 0);
       
  3397     redup(pipes[out], out);
       
  3398     closem(0);   /* this closes pipes[!out] as well */
       
  3399 
       
  3400 #endif /* PATH_DEV_FD */
       
  3401 
       
  3402     cmdpush(CS_CMDSUBST);
       
  3403     execode(prog, 0, 1);
       
  3404     cmdpop();
       
  3405     zclose(out);
       
  3406     _exit(lastval);
       
  3407     return NULL;
       
  3408 #else /*__SYMBIAN32__*/
       
  3409 	st_exec stexec;
       
  3410 	pthread_t testThread;
       
  3411 		
       
  3412     if (!(prog = parsecmd(cmd)))
       
  3413 	  return NULL;   
       
  3414     	
       
  3415 	stexec.dont_change_job=0;
       
  3416 	stexec.exiting=1;
       
  3417 	stexec.p=prog;
       
  3418 	
       
  3419 	pthread_create(&testThread, NULL, &execode_wrap, (void*)&stexec);
       
  3420 	return NULL;
       
  3421 #endif // __SYMBIAN32__  
       
  3422 #endif   /* HAVE_FIFOS and PATH_DEV_FD not defined */
       
  3423 }
       
  3424 
       
  3425 /*
       
  3426  * > >(...) or < <(...) (does not use named pipes)
       
  3427  *
       
  3428  * If the second argument is 1, this is part of
       
  3429  * an "exec < <(...)" or "exec > >(...)" and we shouldn't
       
  3430  * wait for the job to finish before continuing.
       
  3431  */
       
  3432 
       
  3433 /**/
       
  3434 static int
       
  3435 getpipe(char *cmd, int nullexec)
       
  3436 {
       
  3437     Eprog prog;
       
  3438     int out = *cmd == Inang;
       
  3439 
       
  3440 
       
  3441 #ifndef __SYMBIAN32__    
       
  3442     pid_t pid;
       
  3443     struct timeval bgtime;
       
  3444     int pipes[2]; 
       
  3445     
       
  3446     if (!(prog = parsecmd(cmd)))
       
  3447 	return -1;
       
  3448 
       
  3449     mpipe(pipes);
       
  3450     if ((pid = zfork(&bgtime))) {
       
  3451 	zclose(pipes[out]);
       
  3452 	if (pid == -1) {
       
  3453 	    zclose(pipes[!out]);
       
  3454 	    return -1;
       
  3455 	}
       
  3456 	if (!nullexec)
       
  3457 	    addproc(pid, NULL, 1, &bgtime);
       
  3458 	return pipes[!out];
       
  3459     }
       
  3460     entersubsh(Z_ASYNC, 1, 0, 0);
       
  3461     redup(pipes[out], out);
       
  3462     closem(0);	/* this closes pipes[!out] as well */
       
  3463     cmdpush(CS_CMDSUBST);
       
  3464     execode(prog, 0, 1);
       
  3465     cmdpop();
       
  3466     _exit(lastval);
       
  3467 #else
       
  3468 	st_exec stexec;
       
  3469 	pthread_t testThread;
       
  3470 	
       
  3471     if (!(prog = parsecmd(cmd)))
       
  3472 	return -1;
       
  3473 
       
  3474 	stexec.dont_change_job=0;
       
  3475 	stexec.exiting=1;
       
  3476 	stexec.p=prog;
       
  3477 	
       
  3478 	pthread_create(&testThread, NULL, &execode_wrap, (void*)&stexec);	
       
  3479 #endif   //__SYMBIAN32__ 
       
  3480     return 0;
       
  3481 }
       
  3482 
       
  3483 /* open pipes with fds >= 10 */
       
  3484 
       
  3485 /**/
       
  3486 static void
       
  3487 mpipe(int *pp)
       
  3488 {
       
  3489     pipe(pp);
       
  3490     pp[0] = movefd(pp[0]);
       
  3491     pp[1] = movefd(pp[1]);
       
  3492 }
       
  3493 
       
  3494 /*
       
  3495  * Do process substitution with redirection
       
  3496  *
       
  3497  * If the second argument is 1, this is part of
       
  3498  * an "exec < <(...)" or "exec > >(...)" and we shouldn't
       
  3499  * wait for the job to finish before continuing.
       
  3500  */
       
  3501 
       
  3502 /**/
       
  3503 static void
       
  3504 spawnpipes(LinkList l, int nullexec)
       
  3505 {
       
  3506     LinkNode n;
       
  3507     Redir f;
       
  3508     char *str;
       
  3509 
       
  3510     n = firstnode(l);
       
  3511     for (; n; incnode(n)) {
       
  3512 	f = (Redir) getdata(n);
       
  3513 	if (f->type == REDIR_OUTPIPE || f->type == REDIR_INPIPE) {
       
  3514 	    str = f->name;
       
  3515 	    f->fd2 = getpipe(str, nullexec);
       
  3516 	}
       
  3517     }
       
  3518 }
       
  3519 
       
  3520 extern int tracingcond;
       
  3521 
       
  3522 /* evaluate a [[ ... ]] */
       
  3523 
       
  3524 /**/
       
  3525 static int
       
  3526 execcond(Estate state, UNUSED(int do_exec))
       
  3527 {
       
  3528     int stat;
       
  3529 
       
  3530     state->pc--;
       
  3531     if (isset(XTRACE)) {
       
  3532 	printprompt4();
       
  3533 	fprintf(xtrerr, "[[");
       
  3534 	tracingcond++;
       
  3535     }
       
  3536     cmdpush(CS_COND);
       
  3537     stat = evalcond(state, NULL);
       
  3538     /*
       
  3539      * 2 indicates a syntax error.  For compatibility, turn this
       
  3540      * into a shell error.
       
  3541      */
       
  3542     if (stat == 2)
       
  3543 	errflag = 1;
       
  3544     cmdpop();
       
  3545     if (isset(XTRACE)) {
       
  3546 	fprintf(xtrerr, " ]]\n");
       
  3547 	fflush(xtrerr);
       
  3548 	tracingcond--;
       
  3549     }
       
  3550     return stat;
       
  3551 }
       
  3552 
       
  3553 /* evaluate a ((...)) arithmetic command */
       
  3554 
       
  3555 /**/
       
  3556 static int
       
  3557 execarith(Estate state, UNUSED(int do_exec))
       
  3558 {
       
  3559     char *e;
       
  3560     mnumber val = zero_mnumber;
       
  3561     int htok = 0;
       
  3562 
       
  3563     if (isset(XTRACE)) {
       
  3564 	printprompt4();
       
  3565 	fprintf(xtrerr, "((");
       
  3566     }
       
  3567     cmdpush(CS_MATH);
       
  3568     e = ecgetstr(state, EC_DUPTOK, &htok);
       
  3569     if (htok)
       
  3570 	singsub(&e);
       
  3571     if (isset(XTRACE))
       
  3572 	fprintf(xtrerr, " %s", e);
       
  3573 
       
  3574     val = matheval(e);
       
  3575 
       
  3576     cmdpop();
       
  3577 
       
  3578     if (isset(XTRACE)) {
       
  3579 	fprintf(xtrerr, " ))\n");
       
  3580 	fflush(xtrerr);
       
  3581     }
       
  3582     errflag = 0;
       
  3583     /* should test for fabs(val.u.d) < epsilon? */
       
  3584     return (val.type == MN_INTEGER) ? val.u.l == 0 : val.u.d == 0.0;
       
  3585 }
       
  3586 
       
  3587 /* perform time ... command */
       
  3588 
       
  3589 /**/
       
  3590 static int
       
  3591 exectime(Estate state, UNUSED(int do_exec))
       
  3592 {
       
  3593     int jb;
       
  3594 
       
  3595     jb = thisjob;
       
  3596     if (WC_TIMED_TYPE(state->pc[-1]) == WC_TIMED_EMPTY) {
       
  3597 	shelltime();
       
  3598 	return 0;
       
  3599     }
       
  3600     execpline(state, *state->pc++, Z_TIMED|Z_SYNC, 0);
       
  3601     thisjob = jb;
       
  3602     return lastval;
       
  3603 }
       
  3604 
       
  3605 /* Define a shell function */
       
  3606 
       
  3607 /**/
       
  3608 static int
       
  3609 execfuncdef(Estate state, UNUSED(int do_exec))
       
  3610 {
       
  3611     Shfunc shf;
       
  3612     char *s;
       
  3613     int signum, nprg, sbeg, nstrs, npats, len, plen, i, htok = 0;
       
  3614     Wordcode beg = state->pc, end;
       
  3615     Eprog prog;
       
  3616     Patprog *pp;
       
  3617     LinkList names;
       
  3618 
       
  3619     end = beg + WC_FUNCDEF_SKIP(state->pc[-1]);
       
  3620     if (!(names = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) {
       
  3621 	state->pc = end;
       
  3622 	return 0;
       
  3623     }
       
  3624     nprg = end - beg;
       
  3625     sbeg = *state->pc++;
       
  3626     nstrs = *state->pc++;
       
  3627     npats = *state->pc++;
       
  3628 
       
  3629     nprg = (end - state->pc);
       
  3630     plen = nprg * sizeof(wordcode);
       
  3631     len = plen + (npats * sizeof(Patprog)) + nstrs;
       
  3632 
       
  3633     if (htok)
       
  3634 	execsubst(names);
       
  3635 
       
  3636     while ((s = (char *) ugetnode(names))) {
       
  3637 	prog = (Eprog) zalloc(sizeof(*prog));
       
  3638 	prog->npats = npats;
       
  3639 	prog->nref = 1; /* allocated from permanent storage */
       
  3640 	prog->len = len;
       
  3641 	if (state->prog->dump) {
       
  3642 	    prog->flags = EF_MAP;
       
  3643 	    incrdumpcount(state->prog->dump);
       
  3644 	    prog->pats = pp = (Patprog *) zalloc(npats * sizeof(Patprog));
       
  3645 	    prog->prog = state->pc;
       
  3646 	    prog->strs = state->strs + sbeg;
       
  3647 	    prog->dump = state->prog->dump;
       
  3648 	} else {
       
  3649 	    prog->flags = EF_REAL;
       
  3650 	    prog->pats = pp = (Patprog *) zalloc(len);
       
  3651 	    prog->prog = (Wordcode) (prog->pats + npats);
       
  3652 	    prog->strs = (char *) (prog->prog + nprg);
       
  3653 	    prog->dump = NULL;
       
  3654 	    memcpy(prog->prog, state->pc, plen);
       
  3655 	    memcpy(prog->strs, state->strs + sbeg, nstrs);
       
  3656 	}
       
  3657 	for (i = npats; i--; pp++)
       
  3658 	    *pp = dummy_patprog1;
       
  3659 	prog->shf = NULL;
       
  3660 
       
  3661 	shf = (Shfunc) zalloc(sizeof(*shf));
       
  3662 	shf->funcdef = prog;
       
  3663 	shf->flags = 0;
       
  3664 
       
  3665 	/* is this shell function a signal trap? */
       
  3666 	if (!strncmp(s, "TRAP", 4) &&
       
  3667 	    (signum = getsignum(s + 4)) != -1) {
       
  3668 	    if (settrap(signum, shf->funcdef)) {
       
  3669 		freeeprog(shf->funcdef);
       
  3670 		zfree(shf, sizeof(*shf));
       
  3671 		state->pc = end;
       
  3672 		return 1;
       
  3673 	    }
       
  3674 	    sigtrapped[signum] |= ZSIG_FUNC;
       
  3675 
       
  3676 	    /*
       
  3677 	     * Remove the old node explicitly in case it has
       
  3678 	     * an alternative name
       
  3679 	     */
       
  3680 	    removetrapnode(signum);
       
  3681 	}
       
  3682 	shfunctab->addnode(shfunctab, ztrdup(s), shf);
       
  3683     }
       
  3684     state->pc = end;
       
  3685     return 0;
       
  3686 }
       
  3687 
       
  3688 /* Main entry point to execute a shell function. */
       
  3689 
       
  3690 /**/
       
  3691 static void
       
  3692 execshfunc(Shfunc shf, LinkList args)
       
  3693 {
       
  3694     LinkList last_file_list = NULL;
       
  3695     unsigned char *ocs;
       
  3696     int ocsp, osfc;
       
  3697 
       
  3698     if (errflag)
       
  3699 	return;
       
  3700 
       
  3701     if (!list_pipe && thisjob != list_pipe_job && !hasprocs(thisjob)) {
       
  3702 	/* Without this deletejob the process table *
       
  3703 	 * would be filled by a recursive function. */
       
  3704 	last_file_list = jobtab[thisjob].filelist;
       
  3705 	jobtab[thisjob].filelist = NULL;
       
  3706 	deletejob(jobtab + thisjob);
       
  3707     }
       
  3708 
       
  3709     if (isset(XTRACE)) {
       
  3710 	LinkNode lptr;
       
  3711 	printprompt4();
       
  3712 	if (args)
       
  3713 	    for (lptr = firstnode(args); lptr; incnode(lptr)) {
       
  3714 		if (lptr != firstnode(args))
       
  3715 		    fputc(' ', xtrerr);
       
  3716 		quotedzputs((char *)getdata(lptr), xtrerr);
       
  3717 	    }
       
  3718 	fputc('\n', xtrerr);
       
  3719 	fflush(xtrerr);
       
  3720     }
       
  3721     ocs = cmdstack;
       
  3722     ocsp = cmdsp;
       
  3723     cmdstack = (unsigned char *) zalloc(CMDSTACKSZ);
       
  3724     cmdsp = 0;
       
  3725     if ((osfc = sfcontext) == SFC_NONE)
       
  3726 	sfcontext = SFC_DIRECT;
       
  3727     doshfunc(shf->nam, shf->funcdef, args, shf->flags, 0);
       
  3728     sfcontext = osfc;
       
  3729     free(cmdstack);
       
  3730     cmdstack = ocs;
       
  3731     cmdsp = ocsp;
       
  3732 
       
  3733     if (!list_pipe)
       
  3734 	deletefilelist(last_file_list);
       
  3735 }
       
  3736 
       
  3737 /* Function to execute the special type of command that represents an *
       
  3738  * autoloaded shell function.  The command structure tells us which   *
       
  3739  * function it is.  This function is actually called as part of the   *
       
  3740  * execution of the autoloaded function itself, so when the function  *
       
  3741  * has been autoloaded, its list is just run with no frills.          */
       
  3742 
       
  3743 /**/
       
  3744 static int
       
  3745 execautofn(Estate state, UNUSED(int do_exec))
       
  3746 {
       
  3747     Shfunc shf;
       
  3748     char *oldscriptname;
       
  3749 
       
  3750     if (!(shf = loadautofn(state->prog->shf, 1, 0)))
       
  3751 	return 1;
       
  3752 
       
  3753     oldscriptname = scriptname;
       
  3754     scriptname = dupstring(shf->nam);
       
  3755     execode(shf->funcdef, 1, 0);
       
  3756     scriptname = oldscriptname;
       
  3757 
       
  3758     return lastval;
       
  3759 }
       
  3760 
       
  3761 /**/
       
  3762 Shfunc
       
  3763 loadautofn(Shfunc shf, int fksh, int autol)
       
  3764 {
       
  3765     int noalias = noaliases, ksh = 1;
       
  3766     Eprog prog;
       
  3767 
       
  3768     pushheap();
       
  3769 
       
  3770     noaliases = (shf->flags & PM_UNALIASED);
       
  3771     prog = getfpfunc(shf->nam, &ksh);
       
  3772     noaliases = noalias;
       
  3773 
       
  3774     if (ksh == 1) {
       
  3775 	ksh = fksh;
       
  3776 	if (ksh == 1)
       
  3777 	    ksh = (shf->flags & PM_KSHSTORED) ? 2 :
       
  3778 		  (shf->flags & PM_ZSHSTORED) ? 0 : 1;
       
  3779     }
       
  3780 
       
  3781     if (prog == &dummy_eprog) {
       
  3782 	/* We're not actually in the function; decrement locallevel */
       
  3783 	locallevel--;
       
  3784 	zwarn("%s: function definition file not found", shf->nam, 0);
       
  3785 	locallevel++;
       
  3786 	popheap();
       
  3787 	return NULL;
       
  3788     }
       
  3789     if (!prog)
       
  3790 	return NULL;
       
  3791     if (ksh == 2 || (ksh == 1 && isset(KSHAUTOLOAD))) {
       
  3792 	if (autol) {
       
  3793 	    prog->flags |= EF_RUN;
       
  3794 
       
  3795 	    freeeprog(shf->funcdef);
       
  3796 	    if (prog->flags & EF_MAP)
       
  3797 		shf->funcdef = prog;
       
  3798 	    else
       
  3799 		shf->funcdef = dupeprog(prog, 0);
       
  3800 	    shf->flags &= ~PM_UNDEFINED;
       
  3801 	} else {
       
  3802 	    VARARR(char, n, strlen(shf->nam) + 1);
       
  3803 	    strcpy(n, shf->nam);
       
  3804 	    execode(prog, 1, 0);
       
  3805 	    shf = (Shfunc) shfunctab->getnode(shfunctab, n);
       
  3806 	    if (!shf || (shf->flags & PM_UNDEFINED)) {
       
  3807 		/* We're not actually in the function; decrement locallevel */
       
  3808 		locallevel--;
       
  3809 		zwarn("%s: function not defined by file", n, 0);
       
  3810 		locallevel++;
       
  3811 		popheap();
       
  3812 		return NULL;
       
  3813 	    }
       
  3814 	}
       
  3815     } else {
       
  3816 	freeeprog(shf->funcdef);
       
  3817 	if (prog->flags & EF_MAP)
       
  3818 	    shf->funcdef = stripkshdef(prog, shf->nam);
       
  3819 	else
       
  3820 	    shf->funcdef = dupeprog(stripkshdef(prog, shf->nam), 0);
       
  3821 	shf->flags &= ~PM_UNDEFINED;
       
  3822     }
       
  3823     popheap();
       
  3824 
       
  3825     return shf;
       
  3826 }
       
  3827 
       
  3828 /*
       
  3829  * execute a shell function
       
  3830  *
       
  3831  * If noreturnval is nonzero, then reset the current return
       
  3832  * value (lastval) to its value before the shell function
       
  3833  * was executed.  However, in any case return the status value
       
  3834  * from the function (i.e. if noreturnval is not set, this
       
  3835  * will be the same as lastval).
       
  3836  */
       
  3837 
       
  3838 /**/
       
  3839 mod_export int
       
  3840 doshfunc(char *name, Eprog prog, LinkList doshargs, int flags, int noreturnval)
       
  3841 {
       
  3842     char **tab, **x, *oargv0;
       
  3843     int oldzoptind, oldlastval, oldoptcind, oldnumpipestats, ret;
       
  3844     int *oldpipestats = NULL;
       
  3845     char saveopts[OPT_SIZE], *oldscriptname = scriptname, *fname = dupstring(name);
       
  3846     int obreaks;
       
  3847     struct funcstack fstack;
       
  3848 #ifdef MAX_FUNCTION_DEPTH
       
  3849     static int funcdepth;
       
  3850 #endif
       
  3851 
       
  3852     pushheap();
       
  3853 
       
  3854     oargv0 = NULL;
       
  3855     obreaks = breaks;;
       
  3856     if (trapreturn < 0)
       
  3857 	trapreturn--;
       
  3858     oldlastval = lastval;
       
  3859     oldnumpipestats = numpipestats;
       
  3860     if (noreturnval) {
       
  3861 	/*
       
  3862 	 * Easiest to use the heap here since we're bracketed
       
  3863 	 * immediately by a pushheap/popheap pair.
       
  3864 	 */
       
  3865 	size_t bytes = sizeof(int)*numpipestats;
       
  3866 	oldpipestats = (int *)zhalloc(bytes);
       
  3867 	memcpy(oldpipestats, pipestats, bytes);
       
  3868     }
       
  3869 
       
  3870     starttrapscope();
       
  3871 
       
  3872     tab = pparams;
       
  3873     if (!(flags & PM_UNDEFINED))
       
  3874 	scriptname = dupstring(name);
       
  3875     oldzoptind = zoptind;
       
  3876     zoptind = 1;
       
  3877     oldoptcind = optcind;
       
  3878     optcind = 0;
       
  3879 
       
  3880     /* We need to save the current options even if LOCALOPTIONS is *
       
  3881      * not currently set.  That's because if it gets set in the    *
       
  3882      * function we need to restore the original options on exit.   */
       
  3883     memcpy(saveopts, opts, sizeof(opts));
       
  3884 
       
  3885     if (flags & PM_TAGGED)
       
  3886 	opts[XTRACE] = 1;
       
  3887     opts[PRINTEXITVALUE] = 0;
       
  3888     if (doshargs) {
       
  3889 	LinkNode node;
       
  3890 
       
  3891 	node = doshargs->first;
       
  3892 	pparams = x = (char **) zshcalloc(((sizeof *x) *
       
  3893 					 (1 + countlinknodes(doshargs))));
       
  3894 	if (isset(FUNCTIONARGZERO)) {
       
  3895 	    oargv0 = argzero;
       
  3896 	    argzero = ztrdup((char *) node->dat);
       
  3897 	}
       
  3898 	node = node->next;
       
  3899 	for (; node; node = node->next, x++)
       
  3900 	    *x = ztrdup((char *) node->dat);
       
  3901     } else {
       
  3902 	pparams = (char **) zshcalloc(sizeof *pparams);
       
  3903 	if (isset(FUNCTIONARGZERO)) {
       
  3904 	    oargv0 = argzero;
       
  3905 	    argzero = ztrdup(argzero);
       
  3906 	}
       
  3907     }
       
  3908 #ifdef MAX_FUNCTION_DEPTH
       
  3909     if(++funcdepth > MAX_FUNCTION_DEPTH)
       
  3910     {
       
  3911         zerr("maximum nested function level reached", NULL, 0);
       
  3912 	goto undoshfunc;
       
  3913     }
       
  3914 #endif
       
  3915     fstack.name = dupstring(name);
       
  3916     fstack.prev = funcstack;
       
  3917     funcstack = &fstack;
       
  3918 
       
  3919     if (prog->flags & EF_RUN) {
       
  3920 	Shfunc shf;
       
  3921 
       
  3922 	prog->flags &= ~EF_RUN;
       
  3923 
       
  3924 	runshfunc(prog, NULL, fstack.name);
       
  3925 
       
  3926 	if (!(shf = (Shfunc) shfunctab->getnode(shfunctab,
       
  3927 						(name = fname)))) {
       
  3928 	    zwarn("%s: function not defined by file", name, 0);
       
  3929 	    if (noreturnval)
       
  3930 		errflag = 1;
       
  3931 	    else
       
  3932 		lastval = 1;
       
  3933 	    goto doneshfunc;
       
  3934 	}
       
  3935 	prog = shf->funcdef;
       
  3936     }
       
  3937     runshfunc(prog, wrappers, fstack.name);
       
  3938  doneshfunc:
       
  3939     funcstack = fstack.prev;
       
  3940 #ifdef MAX_FUNCTION_DEPTH
       
  3941  undoshfunc:
       
  3942     --funcdepth;
       
  3943 #endif
       
  3944     if (retflag) {
       
  3945 	retflag = 0;
       
  3946 	breaks = obreaks;
       
  3947     }
       
  3948     freearray(pparams);
       
  3949     if (oargv0) {
       
  3950 	zsfree(argzero);
       
  3951 	argzero = oargv0;
       
  3952     }
       
  3953     pparams = tab;
       
  3954     optcind = oldoptcind;
       
  3955     zoptind = oldzoptind;
       
  3956     scriptname = oldscriptname;
       
  3957 
       
  3958     if (isset(LOCALOPTIONS)) {
       
  3959 	/* restore all shell options except PRIVILEGED and RESTRICTED */
       
  3960 	saveopts[PRIVILEGED] = opts[PRIVILEGED];
       
  3961 	saveopts[RESTRICTED] = opts[RESTRICTED];
       
  3962 	memcpy(opts, saveopts, sizeof(opts));
       
  3963     } else {
       
  3964 	/* just restore a couple. */
       
  3965 	opts[XTRACE] = saveopts[XTRACE];
       
  3966 	opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
       
  3967 	opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
       
  3968     }
       
  3969 
       
  3970     endtrapscope();
       
  3971 
       
  3972     if (trapreturn < -1)
       
  3973 	trapreturn++;
       
  3974     ret = lastval;
       
  3975     if (noreturnval) {
       
  3976 	lastval = oldlastval;
       
  3977 	numpipestats = oldnumpipestats;
       
  3978 	memcpy(pipestats, oldpipestats, sizeof(int)*numpipestats);
       
  3979     }
       
  3980     popheap();
       
  3981 
       
  3982     if (exit_pending) {
       
  3983 	if (locallevel) {
       
  3984 	    /* Still functions to return: force them to do so. */
       
  3985 	    retflag = 1;
       
  3986 	    breaks = loops;
       
  3987 	} else {
       
  3988 	    /*
       
  3989 	     * All functions finished: time to exit the shell.
       
  3990 	     * We already did the `stopmsg' test when the
       
  3991 	     * exit command was handled.
       
  3992 	     */
       
  3993 	    stopmsg = 1;
       
  3994 	    zexit(exit_pending >> 1, 0);
       
  3995 	}
       
  3996     }
       
  3997 
       
  3998     return ret;
       
  3999 }
       
  4000 
       
  4001 /* This finally executes a shell function and any function wrappers     *
       
  4002  * defined by modules. This works by calling the wrapper function which *
       
  4003  * in turn has to call back this function with the arguments it gets.   */
       
  4004 
       
  4005 /**/
       
  4006 mod_export void
       
  4007 runshfunc(Eprog prog, FuncWrap wrap, char *name)
       
  4008 {
       
  4009     int cont;
       
  4010     VARARR(char, ou, underscoreused);
       
  4011 
       
  4012     memcpy(ou, underscore, underscoreused);
       
  4013 
       
  4014     while (wrap) {
       
  4015 	wrap->module->wrapper++;
       
  4016 	cont = wrap->handler(prog, wrap->next, name);
       
  4017 	wrap->module->wrapper--;
       
  4018 
       
  4019 	if (!wrap->module->wrapper &&
       
  4020 	    (wrap->module->flags & MOD_UNLOAD))
       
  4021 	    unload_module(wrap->module, NULL);
       
  4022 
       
  4023 	if (!cont)
       
  4024 	    return;
       
  4025 	wrap = wrap->next;
       
  4026     }
       
  4027     startparamscope();
       
  4028     execode(prog, 1, 0);
       
  4029     setunderscore(ou);
       
  4030     endparamscope();
       
  4031 }
       
  4032 
       
  4033 /* Search fpath for an undefined function.  Finds the file, and returns the *
       
  4034  * list of its contents.                                                    */
       
  4035 
       
  4036 /**/
       
  4037 Eprog
       
  4038 getfpfunc(char *s, int *ksh)
       
  4039 {
       
  4040     char **pp, buf[PATH_MAX];
       
  4041     off_t len;
       
  4042     off_t rlen;
       
  4043     char *d;
       
  4044     Eprog r;
       
  4045     int fd;
       
  4046 
       
  4047     pp = fpath;
       
  4048     for (; *pp; pp++) {
       
  4049 	if (strlen(*pp) + strlen(s) + 1 >= PATH_MAX)
       
  4050 	    continue;
       
  4051 	if (**pp)
       
  4052 	    sprintf(buf, "%s/%s", *pp, s);
       
  4053 	else
       
  4054 	    strcpy(buf, s);
       
  4055 	if ((r = try_dump_file(*pp, s, buf, ksh)))
       
  4056 	    return r;
       
  4057 	unmetafy(buf, NULL);
       
  4058 	if (!access(buf, R_OK) && (fd = open(buf, O_RDONLY | O_NOCTTY)) != -1) {
       
  4059 	    if ((len = lseek(fd, 0, 2)) != -1) {
       
  4060 		d = (char *) zalloc(len + 1);
       
  4061 		lseek(fd, 0, 0);
       
  4062 		if ((rlen = read(fd, d, len)) >= 0) {
       
  4063 		    char *oldscriptname = scriptname;
       
  4064 
       
  4065 		    close(fd);
       
  4066 		    d[rlen] = '\0';
       
  4067 		    d = metafy(d, rlen, META_REALLOC);
       
  4068 
       
  4069 		    scriptname = dupstring(s);
       
  4070 		    r = parse_string(d);
       
  4071 		    scriptname = oldscriptname;
       
  4072 
       
  4073 		    zfree(d, len + 1);
       
  4074 
       
  4075 		    return r;
       
  4076 		} else
       
  4077 		    close(fd);
       
  4078 
       
  4079 		zfree(d, len + 1);
       
  4080 	    } else
       
  4081 		close(fd);
       
  4082 	}
       
  4083     }
       
  4084     return &dummy_eprog;
       
  4085 }
       
  4086 
       
  4087 /* Handle the most common type of ksh-style autoloading, when doing a      *
       
  4088  * zsh-style autoload.  Given the list read from an autoload file, and the *
       
  4089  * name of the function being defined, check to see if the file consists   *
       
  4090  * entirely of a single definition for that function.  If so, use the      *
       
  4091  * contents of that definition.  Otherwise, use the entire file.           */
       
  4092 
       
  4093 /**/
       
  4094 Eprog
       
  4095 stripkshdef(Eprog prog, char *name)
       
  4096 {
       
  4097     Wordcode pc = prog->prog;
       
  4098     wordcode code;
       
  4099 
       
  4100     if (!prog)
       
  4101 	return NULL;
       
  4102     code = *pc++;
       
  4103     if (wc_code(code) != WC_LIST ||
       
  4104 	(WC_LIST_TYPE(code) & (Z_SYNC|Z_END|Z_SIMPLE)) != (Z_SYNC|Z_END|Z_SIMPLE))
       
  4105 	return prog;
       
  4106     pc++;
       
  4107     code = *pc++;
       
  4108     if (wc_code(code) != WC_FUNCDEF ||
       
  4109 	*pc != 1 || strcmp(name, ecrawstr(prog, pc + 1, NULL)))
       
  4110 	return prog;
       
  4111 
       
  4112     {
       
  4113 	Eprog ret;
       
  4114 	Wordcode end = pc + WC_FUNCDEF_SKIP(code);
       
  4115 	int sbeg = pc[2], nstrs = pc[3], nprg, npats = pc[4], plen, len, i;
       
  4116 	Patprog *pp;
       
  4117 
       
  4118 	pc += 5;
       
  4119 
       
  4120 	nprg = end - pc;
       
  4121 	plen = nprg * sizeof(wordcode);
       
  4122 	len = plen + (npats * sizeof(Patprog)) + nstrs;
       
  4123 
       
  4124 	if (prog->flags & EF_MAP) {
       
  4125 	    ret = prog;
       
  4126 	    free(prog->pats);
       
  4127 	    ret->pats = pp = (Patprog *) zalloc(npats * sizeof(Patprog));
       
  4128 	    ret->prog = pc;
       
  4129 	    ret->strs = prog->strs + sbeg;
       
  4130 	} else {
       
  4131 	    ret = (Eprog) zhalloc(sizeof(*ret));
       
  4132 	    ret->flags = EF_HEAP;
       
  4133 	    ret->pats = pp = (Patprog *) zhalloc(len);
       
  4134 	    ret->prog = (Wordcode) (ret->pats + npats);
       
  4135 	    ret->strs = (char *) (ret->prog + nprg);
       
  4136 	    memcpy(ret->prog, pc, plen);
       
  4137 	    memcpy(ret->strs, prog->strs + sbeg, nstrs);
       
  4138 	    ret->dump = NULL;
       
  4139 	}
       
  4140 	ret->len = len;
       
  4141 	ret->npats = npats;
       
  4142 	for (i = npats; i--; pp++)
       
  4143 	    *pp = dummy_patprog1;
       
  4144 	ret->shf = NULL;
       
  4145 
       
  4146 	return ret;
       
  4147     }
       
  4148 }
       
  4149 
       
  4150 /* check to see if AUTOCD applies here */
       
  4151 
       
  4152 /**/
       
  4153 static char *
       
  4154 cancd(char *s)
       
  4155 {
       
  4156     int nocdpath = s[0] == '.' &&
       
  4157     (s[1] == '/' || !s[1] || (s[1] == '.' && (s[2] == '/' || !s[1])));
       
  4158     char *t;
       
  4159 
       
  4160     if (*s != '/') {
       
  4161 	char sbuf[PATH_MAX], **cp;
       
  4162 
       
  4163 	if (cancd2(s))
       
  4164 	    return s;
       
  4165 	if (access(unmeta(s), X_OK) == 0)
       
  4166 	    return NULL;
       
  4167 	if (!nocdpath)
       
  4168 	    for (cp = cdpath; *cp; cp++) {
       
  4169 		if (strlen(*cp) + strlen(s) + 1 >= PATH_MAX)
       
  4170 		    continue;
       
  4171 		if (**cp)
       
  4172 		    sprintf(sbuf, "%s/%s", *cp, s);
       
  4173 		else
       
  4174 		    strcpy(sbuf, s);
       
  4175 		if (cancd2(sbuf)) {
       
  4176 		    doprintdir = -1;
       
  4177 		    return dupstring(sbuf);
       
  4178 		}
       
  4179 	    }
       
  4180 	if ((t = cd_able_vars(s))) {
       
  4181 	    if (cancd2(t)) {
       
  4182 		doprintdir = -1;
       
  4183 		return t;
       
  4184 	    }
       
  4185 	}
       
  4186 	return NULL;
       
  4187     }
       
  4188     return cancd2(s) ? s : NULL;
       
  4189 }
       
  4190 
       
  4191 /**/
       
  4192 static int
       
  4193 cancd2(char *s)
       
  4194 {
       
  4195     struct stat buf;
       
  4196     char *us, *us2 = NULL;
       
  4197     int ret;
       
  4198 
       
  4199     /*
       
  4200      * If CHASEDOTS and CHASELINKS are not set, we want to rationalize the
       
  4201      * path by removing foo/.. combinations in the logical rather than
       
  4202      * the physical path.  If either is set, we test the physical path.
       
  4203      */
       
  4204     if (!isset(CHASEDOTS) && !isset(CHASELINKS)) {
       
  4205 	if (*s != '/')
       
  4206 	    us = tricat(pwd[1] ? pwd : "", "/", s);
       
  4207 	else
       
  4208 	    us = ztrdup(s);
       
  4209 	fixdir(us2 = us);
       
  4210     } else
       
  4211 	us = unmeta(s);
       
  4212     ret = !(access(us, X_OK) || stat(us, &buf) || !S_ISDIR(buf.st_mode));
       
  4213     if (us2)
       
  4214 	free(us2);
       
  4215     return ret;
       
  4216 }
       
  4217 
       
  4218 /**/
       
  4219 void
       
  4220 execsave(void)
       
  4221 {
       
  4222     struct execstack *es;
       
  4223 
       
  4224     es = (struct execstack *) malloc(sizeof(struct execstack));
       
  4225     es->args = args;
       
  4226     es->list_pipe_pid = list_pipe_pid;
       
  4227     es->nowait = nowait;
       
  4228     es->pline_level = pline_level;
       
  4229     es->list_pipe_child = list_pipe_child;
       
  4230     es->list_pipe_job = list_pipe_job;
       
  4231     strcpy(es->list_pipe_text, list_pipe_text);
       
  4232     es->lastval = lastval;
       
  4233     es->noeval = noeval;
       
  4234     es->badcshglob = badcshglob;
       
  4235     es->cmdoutpid = cmdoutpid;
       
  4236     es->cmdoutval = cmdoutval;
       
  4237     es->trapreturn = trapreturn;
       
  4238     es->noerrs = noerrs;
       
  4239     es->subsh_close = subsh_close;
       
  4240     es->underscore = ztrdup(underscore);
       
  4241     es->next = exstack;
       
  4242     exstack = es;
       
  4243     noerrs = cmdoutpid = 0;
       
  4244 }
       
  4245 
       
  4246 /**/
       
  4247 void
       
  4248 execrestore(void)
       
  4249 {
       
  4250     struct execstack *en;
       
  4251 
       
  4252     DPUTS(!exstack, "BUG: execrestore() without execsave()");
       
  4253     args = exstack->args;
       
  4254     list_pipe_pid = exstack->list_pipe_pid;
       
  4255     nowait = exstack->nowait;
       
  4256     pline_level = exstack->pline_level;
       
  4257     list_pipe_child = exstack->list_pipe_child;
       
  4258     list_pipe_job = exstack->list_pipe_job;
       
  4259     strcpy(list_pipe_text, exstack->list_pipe_text);
       
  4260     lastval = exstack->lastval;
       
  4261     noeval = exstack->noeval;
       
  4262     badcshglob = exstack->badcshglob;
       
  4263     cmdoutpid = exstack->cmdoutpid;
       
  4264     cmdoutval = exstack->cmdoutval;
       
  4265     trapreturn = exstack->trapreturn;
       
  4266     noerrs = exstack->noerrs;
       
  4267     subsh_close = exstack->subsh_close;
       
  4268     setunderscore(exstack->underscore);
       
  4269     zsfree(exstack->underscore);
       
  4270     en = exstack->next;
       
  4271     free(exstack);
       
  4272     exstack = en;
       
  4273 }