diff --git a/cosmo/Dockerfile b/cosmo/Dockerfile index 6fafeaa..761bade 100644 --- a/cosmo/Dockerfile +++ b/cosmo/Dockerfile @@ -1,8 +1,8 @@ # MAIN: https://justine.lol/cosmopolitan/ # REPO: https://github.com/jart/cosmopolitan ARG COSMO_FLAVOR=def -ARG COSMO_COMMIT=d5910e267352319359477d2a533c93ac7d883c95 -ARG COSMO_SHA256=a8cb999cbe7c6c9405c7aa9c51e54eee61177bc46efe8f88ec68393c776d5ceb +ARG COSMO_COMMIT=31dab8a75d928df7a4cd2e9bcf42916b1810d085 +ARG COSMO_SHA256=4acafc98fa38a2429941ed46cbec4ac7c0c313641397d9c1fcda1a8e9115df80 FROM localhost/notwa-util AS downloader ARG COSMO_COMMIT COSMO_SHA256 @@ -20,7 +20,6 @@ WORKDIR /cosmopolitan # tell makefiles to be less noisy, also use /tmp: ENV V=0 COLUMNS=80 TMPDIR=/tmp -COPY unbourne-backports.patch /cosmopolitan/ COPY --chmod=0755 --from=localhost/notwa-util /nu/ /usr/bin/ RUN : \ # allow optimized builds to be more portable, so the container is too. \ @@ -35,20 +34,16 @@ RUN : \ '/\bNET_HTTP\b/i\\tTHIRD_PARTY_LINENOISE\t\t\\' \ # include LoadZipArgs in cosmopolitan.a \ '/\bNET_HTTP\b/i\\tTOOL_ARGS\t\t\\' \ -# include nsync_cv_signal and nsync_cv_wait_with_deadline in cosmopolitan.a \ -'/\bTHIRD_PARTY_NSYNC_MALLOC\b/i\\tTHIRD_PARTY_NSYNC_MEM\t\t\\' \ # add missing includes \ && shed libc/elf/elf.h '/"libc\/elf\/struct\/ehdr.h"/i\\#include "libc/elf/struct/dyn.h"' \ # awk's pledge isn't working for me for whatever reason \ && shed third_party/awk/main.c '/pledge.*{/,/}/d' \ # create a mapping from flavor to mode (possibly an empty string) \ - && { [ "$COSMO_FLAVOR" != def ] && mode="$COSMO_FLAVOR" || mode=; } \ + && { [ "$COSMO_FLAVOR" != def ] && mode="$COSMO_FLAVOR" || mode= ;} \ && printf '%s="%s"\n' >env \ commit "$COSMO_COMMIT" \ flavor "$COSMO_FLAVOR" \ mode "$mode" \ -# apply patches from dash to unbourne shell \ - && /usr/bin/busybox patch -p1 -i unbourne-backports.patch \ # make calling make a little shorter (don't put this in distrib!) \ && printf '%s\n' >makeit '#!/usr/bin/env sh' \ "build/bootstrap/make.com -j2 MODE='$mode'"' "$@"' \ @@ -112,7 +107,6 @@ RUN : \ # install the rest FROM builder AS distrib -COPY --chmod=0755 --from=localhost/notwa-util /nu/dedupe /usr/bin/ RUN --mount=type=tmpfs,target=/tmp : \ && . ./env \ && find o -name '*.sym' -delete \ diff --git a/cosmo/unbourne-backports.patch b/cosmo/unbourne-backports.patch deleted file mode 100644 index ba5c0e2..0000000 --- a/cosmo/unbourne-backports.patch +++ /dev/null @@ -1,1664 +0,0 @@ ---- a/examples/unbourne.c -+++ b/examples/unbourne.c -@@ -59,8 +59,8 @@ - for decades thanks to a spark of brilliance from Ken Thompson. - - git://git.kernel.org/pub/scm/utils/dash/dash.git -- fba95e9e4a5d0f1f1ac9f7d86557e47bc0e2656c -- Tue Jun 19 11:27:37 2018 -0400 -+ 057cd650a4edd5856213d431a974ff35c6594489 -+ Fri Sep 03 15:00:58 2021 +0800 - - The UNBOURNE SHELL pays HOMAGE to the Stewards of House California: - -@@ -68,7 +68,7 @@ - Derived from software contributed to Berkeley by Kenneth Almquist. - - Copyright 1991,1993 The Regents of the University of California -- Copyright 1997-2018 Herbert Xu -+ Copyright 1997-2021 Herbert Xu - Copyright 1997 Christos Zoulas - - Redistribution and use in source and binary forms, with or without -@@ -183,6 +183,7 @@ - /* exceptions */ - #define EXINT 0 - #define EXERROR 1 -+#define EXEND 3 - #define EXEXIT 4 - - /* -@@ -207,7 +208,6 @@ - #define CEOF 11 - #define CCTL 12 - #define CSPCL 13 --#define CIGN 14 - - /* Syntax classes for is_ functions */ - #define ISDIGIT 01 -@@ -216,13 +216,11 @@ - #define ISUNDER 010 - #define ISSPECL 020 - --#define SYNBASE 130 --#define PEOF -130 -+#define SYNBASE 129 -+#define PEOF -129 - - #define EOF_NLEFT -99 - --#define PEOA -129 -- - #define BASESYNTAX (basesyntax + SYNBASE) - #define DQSYNTAX (dqsyntax + SYNBASE) - #define SQSYNTAX (sqsyntax + SYNBASE) -@@ -345,6 +343,7 @@ - #define VSTRIMLEFT 0x8 - #define VSTRIMLEFTMAX 0x9 - #define VSLENGTH 0xa -+/* VSLENGTH must come last. */ - - /* values of checkkwd variable */ - #define CHKALIAS 0x1 -@@ -484,9 +483,10 @@ - #define CUR_STOPPED 0 - - /* mode flags for dowait */ --#define DOWAIT_NORMAL 0 --#define DOWAIT_BLOCK 1 --#define DOWAIT_WAITCMD 2 -+#define DOWAIT_NONBLOCK 0 -+#define DOWAIT_BLOCK 1 -+#define DOWAIT_WAITCMD 2 -+#define DOWAIT_WAITCMD_ALL 4 - - /* _rmescape() flags */ - #define RMESCAPE_ALLOC 0x01 -@@ -570,7 +570,6 @@ - #define CD_PHYSICAL 1 - #define CD_PRINT 2 - --#define REALLY_CLOSED -3 - #define EMPTY -2 - #define CLOSED -1 - #define PIPESIZE 4096 -@@ -711,10 +710,11 @@ - struct strpush *prev; /* preceding string on stack */ - char *prevstring; - int prevnleft; -- struct alias *ap; /* if push was associated with an alias */ -- char *string; /* remember the string since it may change */ -- int lastc[2]; /* Remember last two characters for pungetc. */ -- int unget; /* Number of outstanding calls to pungetc. */ -+ struct alias *ap; /* if push was associated with an alias */ -+ char *string; /* remember the string since it may change */ -+ struct strpush *spfree; /* Delay freeing so we can stop nested aliases. */ -+ int lastc[2]; /* Remember last two characters for pungetc. */ -+ int unget; /* Number of outstanding calls to pungetc. */ - }; - - /* -@@ -731,6 +731,7 @@ - char *buf; /* input buffer */ - struct strpush *strpush; /* for pushing strings at this level */ - struct strpush basestrpush; /* so pushing one is fast */ -+ struct strpush *spfree; /* Delay freeing so we can stop nested aliases. */ - int lastc[2]; /* Remember last two characters for pungetc. */ - int unget; /* Number of outstanding calls to pungetc. */ - }; -@@ -1055,8 +1056,8 @@ - static int funcblocksize; /* size of structures in function */ - static int funcline; /* start line of function, or 0 if not in one */ - static int funcstringsize; /* size of strings in node */ --static int gotsigchld; /* received SIGCHLD */ - static int initialpgrp; /* pgrp of shell on invocation */ -+static int inps4; /* Prevent PS4 nesting. */ - static int job_warning; - static int jobctl; - static int last_token; -@@ -1083,6 +1084,7 @@ - static struct ifsregion *ifslastp; /* last struct in list */ - static struct ifsregion ifsfirst; /* first struct in list of ifs regions */ - static struct jmploc *handler; -+static struct jmploc main_handler; - static struct job *curjob; /* current job */ - static struct job *jobtab; /* array of jobs */ - static struct localvar_list *localvar_stack; -@@ -1099,8 +1101,10 @@ - static struct Var *vartab[VTABSIZE]; - static union node *redirnode; - static union yystype yylval; -+static unsigned closed_redirs; /* Bit map of currently closed file descriptors. */ - static unsigned expdir_max; - static unsigned njobs; /* size of array */ -+static volatile sig_atomic_t gotsigchld; /* received SIGCHLD */ - static volatile sig_atomic_t intpending; - static volatile sig_atomic_t pending_sig; /* last pending signal */ - static struct alias *atab[ATABSIZE]; -@@ -1217,117 +1221,135 @@ - - /* syntax table used when not in quotes */ - static const char basesyntax[] /* clang-format off */ = { -- CEOF, CSPCL, CWORD, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, -- CCTL, CCTL, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CSPCL, CNL, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CSPCL, CWORD, CDQUOTE, CWORD, CVAR, CWORD, CSPCL, CSQUOTE, CSPCL, -- CSPCL, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CSPCL, CSPCL, CWORD, CSPCL, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CBACK, CWORD, CWORD, -- CWORD, CBQUOTE, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CSPCL, CENDVAR, CWORD, CWORD -+ CEOF, CWORD, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, -+ CCTL, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CSPCL, CNL, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CSPCL, -+ CWORD, CDQUOTE, CWORD, CVAR, CWORD, CSPCL, CSQUOTE, CSPCL, CSPCL, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CSPCL, -+ CSPCL, CWORD, CSPCL, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CBACK, CWORD, CWORD, CWORD, -+ CBQUOTE, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CSPCL, CENDVAR, CWORD, CWORD - } /* clang-format on */; - - /* syntax table used when in double quotes */ - static const char dqsyntax[] /* clang-format off */ = { -- CEOF, CIGN, CWORD, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, -- CCTL, CCTL, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CNL, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CCTL, CENDQUOTE, CWORD, CVAR, CWORD, CWORD, CWORD, CWORD, -- CWORD, CCTL, CWORD, CWORD, CCTL, CWORD, CCTL, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CCTL, -- CWORD, CWORD, CCTL, CWORD, CCTL, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CCTL, CBACK, CCTL, CWORD, -- CWORD, CBQUOTE, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CENDVAR, CCTL, CWORD -+ CEOF, CWORD, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, -+ CCTL, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CNL, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CCTL, CENDQUOTE, CWORD, CVAR, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CCTL, CWORD, CWORD, CCTL, CWORD, CCTL, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CCTL, CWORD, -+ CWORD, CCTL, CWORD, CCTL, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CCTL, CBACK, CCTL, CWORD, CWORD, -+ CBQUOTE, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CENDVAR, CCTL, CWORD - } /* clang-format on */; - - /* syntax table used when in single quotes */ --static const char sqsyntax[] = { -- CEOF, CIGN, CWORD, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CNL, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CCTL, CWORD, CWORD, CWORD, CWORD, CWORD, -- CENDQUOTE, CWORD, CWORD, CCTL, CWORD, CWORD, CCTL, CWORD, CCTL, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CCTL, CWORD, CWORD, CCTL, CWORD, CCTL, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CCTL, CCTL, CCTL, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CCTL, CWORD, --}; -+static const char sqsyntax[] /* clang-format off */ = { -+ CEOF, CWORD, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, -+ CCTL, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CNL, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CCTL, CWORD, CWORD, CWORD, CWORD, CWORD, CENDQUOTE, CWORD, CWORD, -+ CCTL, CWORD, CWORD, CCTL, CWORD, CCTL, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CCTL, CWORD, -+ CWORD, CCTL, CWORD, CCTL, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CCTL, CCTL, CCTL, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CCTL, CWORD -+} /* clang-format on */; - - /* syntax table used when in arithmetic */ --static const char arisyntax[] = { -- CEOF, CIGN, CWORD, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CNL, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CVAR, CWORD, CWORD, -- CWORD, CLP, CRP, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CBACK, CWORD, CWORD, CWORD, CBQUOTE, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -- CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CENDVAR, CWORD, CWORD, --}; -+static const char arisyntax[] /* clang-format off */ = { -+ CEOF, CWORD, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, CCTL, -+ CCTL, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CNL, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CVAR, CWORD, CWORD, CWORD, CLP, CRP, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CBACK, CWORD, CWORD, CWORD, -+ CBQUOTE, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, CWORD, -+ CWORD, CWORD, CENDVAR, CWORD, CWORD -+} /* clang-format on */; - - /* character classification table */ - static const char is_type[] /* clang-format off */ = { -@@ -1351,19 +1373,19 @@ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -- 0, 0, 0, ISSPECL, 0, ISSPECL, ISSPECL, 0, -- 0, 0, 0, 0, ISSPECL, 0, 0, ISSPECL, -- 0, 0, ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, -- ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, 0, 0, 0, 0, -- 0, ISSPECL, ISSPECL, ISUPPER, ISUPPER, ISUPPER, ISUPPER, ISUPPER, -+ 0, 0, ISSPECL, 0, ISSPECL, ISSPECL, 0, 0, -+ 0, 0, 0, ISSPECL, 0, 0, ISSPECL, 0, -+ 0, ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, -+ ISDIGIT, ISDIGIT, ISDIGIT, 0, 0, 0, 0, 0, -+ ISSPECL, ISSPECL, ISUPPER, ISUPPER, ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, ISUPPER, ISUPPER, ISUPPER, ISUPPER, -- ISUPPER, ISUPPER, ISUPPER, ISUPPER, ISUPPER, 0, 0, 0, -- 0, ISUNDER, 0, ISLOWER, ISLOWER, ISLOWER, ISLOWER, ISLOWER, -+ ISUPPER, ISUPPER, ISUPPER, ISUPPER, 0, 0, 0, 0, -+ ISUNDER, 0, ISLOWER, ISLOWER, ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, ISLOWER, ISLOWER, ISLOWER, ISLOWER, -- ISLOWER, ISLOWER, ISLOWER, ISLOWER, ISLOWER, 0, 0, 0, -- 0, 0 -+ ISLOWER, ISLOWER, ISLOWER, ISLOWER, 0, 0, 0, 0, -+ 0 - } /* clang-format on */; - - static int aliascmd(); -@@ -2141,9 +2163,7 @@ - static int options(int); - static int padvance_magic(const char **, const char *, int); - static int patmatch(char *, const char *); --static int peektoken(void); - static int pgetc(void); --static int pgetc2(void); - static int pgetc_eatbnl(); - static int pmatch(const char *, const char *); - static int preadbuffer(void); -@@ -2155,6 +2175,7 @@ - static int redirectsafe(union node *, int); - static int savefd(int, int); - static int setinputfile(const char *, int); -+static int sh_open(const char *pathname, int flags, int mayfail); - static int showvars(const char *, int, int); - static int stoppedjobs(void); - static int test_file_access(const char *, int); -@@ -2195,21 +2216,20 @@ - static void addcmdentry(char *, struct cmdentry *); - static void addfname(char *); - static void check_conversion(const char *, const char *); --static void clear_traps(void); - static void clearcmdentry(void); --static void closescript(void); - static void defun(union node *); - static void delete_cmd_entry(void); - static void dotrap(void); - static void dupredirect(union node *, int); - static void exitreset(void); - static void expandarg(union node *arg, struct arglist *arglist, int flag); --static void expandmeta(struct strlist *, int); -+static void expandmeta(struct strlist *); - static void expbackq(union node *, int); - static void expmeta(char *, unsigned, unsigned); - static void expredir(union node *); - static void find_command(char *, struct cmdentry *, int, const char *); - static void fixredir(union node *, const char *, int); -+static void forkreset(void); - static void freeparam(volatile struct shparam *); - static void hashcd(void); - static void ignoresig(int); -@@ -2222,7 +2242,7 @@ - static void parseheredoc(void); - static void popallfiles(void); - static void popfile(void); --static void poplocalvars(int); -+static void poplocalvars(void); - static void popredir(int); - static void popstring(void); - static void prehash(union node *); -@@ -3083,8 +3103,11 @@ - static int evaltree(union node *n, int flags) { - int checkexit = 0; - int (*evalfn)(union node *, int); -+ struct stackmark smark; - unsigned isor; - int status = 0; -+ setstackmark(&smark); -+ if (nflag) goto out; - if (n == NULL) { - TRACE(("evaltree(NULL) called\n")); - goto out; -@@ -3108,7 +3131,7 @@ - case NCMD: - evalfn = evalcommand; - checkexit: -- if (eflag && !(flags & EV_TESTED)) checkexit = ~0; -+ checkexit = ~flags & EV_TESTED; - goto calleval; - case NFOR: - evalfn = evalfor; -@@ -3132,8 +3155,6 @@ - case NSEMI: - isor = n->type - NAND; - status = evaltree(n->nbinary.ch1, (flags | ((isor >> 1) - 1)) & EV_TESTED); -- /* XXX: -Wlogical-not-parentheses: -- if (!status == isor || evalskip) break; */ - if ((!status) == isor || evalskip) break; - n = n->nbinary.ch2; - evaln: -@@ -3160,12 +3181,13 @@ - break; - } - out: -- if (checkexit & status) goto exexit; - dotrap(); -+ if (eflag && checkexit & status) goto exexit; - if (flags & EV_EXIT) { - exexit: -- exraise(EXEXIT); -+ exraise(EXEND); - } -+ popstackmark(&smark); - return exitstatus; - } - -@@ -3261,11 +3283,9 @@ - struct arglist arglist; - union node *argp; - struct strlist *sp; -- struct stackmark smark; - int status; - errlinno = lineno = n->nfor.linno; - if (funcline) lineno -= funcline - 1; -- setstackmark(&smark); - arglist.lastp = &arglist.list; - for (argp = n->nfor.args; argp; argp = argp->narg.next) { - expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); -@@ -3280,7 +3300,6 @@ - if (skiploop() & ~SKIPCONT) break; - } - loopnest--; -- popstackmark(&smark); - return status; - } - -@@ -3304,11 +3323,9 @@ - union node *cp; - union node *patp; - struct arglist arglist; -- struct stackmark smark; - int status = 0; - errlinno = lineno = n->ncase.linno; - if (funcline) lineno -= funcline - 1; -- setstackmark(&smark); - arglist.lastp = &arglist.list; - expandarg(n->ncase.expr, &arglist, EXP_TILDE); - for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) { -@@ -3326,7 +3343,6 @@ - } - } - out: -- popstackmark(&smark); - return status; - } - -@@ -3340,14 +3356,17 @@ - errlinno = lineno = n->nredir.linno; - if (funcline) lineno -= funcline - 1; - expredir(n->nredir.redirect); -- if (!backgnd && flags & EV_EXIT && !have_traps()) goto nofork; - INTOFF; -+ if (!backgnd && flags & EV_EXIT && !have_traps()) { -+ forkreset(); -+ goto nofork; -+ } - jp = makejob(n, 1); - if (forkshell(jp, n, backgnd) == 0) { -- INTON; - flags |= EV_EXIT; - if (backgnd) flags &= ~EV_TESTED; - nofork: -+ INTON; - redirect(n->nredir.redirect, 0); - evaltreenr(n->nredir.n, flags); - /* never returns */ -@@ -3378,7 +3397,7 @@ - case NFROMFD: - case NTOFD: - if (redir->ndup.vname) { -- expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); -+ expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR); - fixredir(redir, fn.list->text, 1); - } - break; -@@ -3527,7 +3546,6 @@ - struct localvar_list *localvar_stop; - struct parsefile *file_stop; - struct redirtab *redir_stop; -- struct stackmark smark; - union node *argp; - struct arglist arglist; - struct arglist varlist; -@@ -3550,7 +3568,6 @@ - if (funcline) lineno -= funcline - 1; - /* First expand the arguments. */ - TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); -- setstackmark(&smark); - file_stop = parsefile; - back_exitstatus = 0; - cmdentry.cmdtype = CMDBUILTIN; -@@ -3624,11 +3641,13 @@ - setvareq((*spp)->text, vflags); - } - /* Print the command if xflag is set. */ -- if (xflag) { -+ if (xflag && !inps4) { - struct output *out; - int sep; - out = &preverrout; -+ inps4 = 1; - outstr(expandstr(ps4val()), out); -+ inps4 = 0; - sep = 0; - sep = eprintlist(out, varlist.list, sep); - eprintlist(out, osp, sep); -@@ -3679,7 +3698,6 @@ - */ - setvar("_", lastarg, 0); - } -- popstackmark(&smark); - return status; - } - -@@ -3702,6 +3720,7 @@ - else - status = (*cmd->builtin)(argc, argv); - flushall(); -+ if (out1->flags) sh_warnx("%s: I/O error", commandname); - status |= out1->flags; - exitstatus = status; - cmddone: -@@ -3893,7 +3912,7 @@ - exerrno = (e == ELOOP || e == ENAMETOOLONG || e == ENOENT || e == ENOTDIR) ? 127 : 126; - exitstatus = exerrno; - TRACE(("shellexec failed for %s, errno %d, suppressint %d\n", argv[0], e, suppressint)); -- exerror(EXEXIT, "%s: %s", argv[0], errmsg(e, E_EXEC)); -+ exerror(EXEND, "%s: %s", argv[0], errmsg(e, E_EXEC)); - } - - static void tryexec(char *cmd, char **argv, char **envp) { -@@ -4498,7 +4517,7 @@ - ifsbreakup(p, -1, &exparg); - *exparg.lastp = NULL; - exparg.lastp = &exparg.list; -- expandmeta(exparg.list, flag); -+ expandmeta(exparg.list); - } else { - sp = (struct strlist *)stalloc(sizeof(struct strlist)); - sp->text = p; -@@ -4560,7 +4579,7 @@ - q = stnputs(p, length, expdest); - q[-1] &= end - 1; - expdest = q - (flag & EXP_WORD ? end : 0); -- newloc = expdest - (char *)stackblock() - end; -+ newloc = q - (char *)stackblock() - end; - if (breakall && !inquotes && newloc > startloc) { - recordregion(startloc, newloc, 0); - } -@@ -4756,7 +4775,7 @@ - INTON; - /* Eat all trailing newlines */ - dest = expdest; -- for (; dest > (char *)stackblock() && dest[-1] == '\n';) { -+ for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';) { - STUNPUTC(dest); - } - expdest = dest; -@@ -4889,6 +4908,7 @@ - int patloc; - int startloc; - long varlen; -+ int discard; - int quoted; - varflags = *p++; - subtype = varflags & VSTYPE; -@@ -4899,31 +4919,32 @@ - again: - varlen = varvalue(var_, varflags, flag, quoted); - if (varflags & VSNUL) varlen--; -+ discard = varlen < 0 ? EXP_DISCARD : 0; - switch (subtype) { - case VSPLUS: -- varlen = -1 - varlen; -+ discard ^= EXP_DISCARD; - /* fall through */ - case 0: - case VSMINUS: -- p = argstr(p, flag | EXP_TILDE | EXP_WORD); -- if (varlen < 0) return p; -+ p = argstr(p, flag | EXP_TILDE | EXP_WORD | (discard ^ EXP_DISCARD)); - goto record; - case VSASSIGN: - case VSQUESTION: -- if (varlen >= 0) goto record; -- p = subevalvar(p, var_, 0, startloc, varflags, flag & ~QUOTES_ESC); -- if (flag & EXP_DISCARD) return p; -+ p = subevalvar(p, var_, 0, startloc, varflags, (flag & ~QUOTES_ESC) | (discard ^ EXP_DISCARD)); -+ if ((flag | ~discard) & EXP_DISCARD) goto record; - varflags &= ~VSNUL; -+ subtype = VSNORMAL; - goto again; - } -- if (varlen < 0 && uflag) varunset(p, var_, 0, 0); -+ if ((discard & ~flag) && uflag) varunset(p, var_, 0, 0); - if (subtype == VSLENGTH) { -+ p++; - if (flag & EXP_DISCARD) return p; - cvtnum(varlen > 0 ? varlen : 0, flag); -- goto record; -+ goto really_record; - } - if (subtype == VSNORMAL) goto record; -- flag |= varlen < 0 ? EXP_DISCARD : 0; -+ flag |= discard; - if (!(flag & EXP_DISCARD)) { - /* - * Terminate the string and start recording the pattern -@@ -4934,7 +4955,8 @@ - patloc = expdest - (char *)stackblock(); - p = subevalvar(p, NULL, patloc, startloc, varflags, flag); - record: -- if (flag & EXP_DISCARD) return p; -+ if ((flag | discard) & EXP_DISCARD) return p; -+really_record: - if (quoted) { - quoted = *var_ == '@' && shellparam.nparam; - if (!quoted) return p; -@@ -5212,7 +5234,7 @@ - * Expand shell metacharacters. At this point, the only control characters - * should be escapes. The results are stored in the list exparg. - */ --static void expandmeta(struct strlist *str, int flag) { -+static void expandmeta(struct strlist *str) { - static const char metachars[] = {'*', '?', '[', 0}; - /* TODO - EXP_REDIR */ - while (str) { -@@ -5595,11 +5617,23 @@ - return memtodest(buf, len, flags); - } - --/* -- * Read a character from the script, returning PEOF on end of file. -- * Nul characters in the input are silently discarded. -- */ --static int pgetc(void) { -+static void freestrings(struct strpush *sp) { -+ INTOFF; -+ do { -+ struct strpush *psp; -+ if (sp->ap) { -+ sp->ap->flag &= ~ALIASINUSE; -+ if (sp->ap->flag & ALIASDEAD) unalias(sp->ap->name); -+ } -+ psp = sp; -+ sp = sp->spfree; -+ if (psp != &(parsefile->basestrpush)) ckfree(psp); -+ } while (sp); -+ parsefile->spfree = NULL; -+ INTON; -+} -+ -+static int pgetc_nofree(void) { - int c; - if (parsefile->unget) return parsefile->lastc[--parsefile->unget]; - if (--parsefile->nleft >= 0) -@@ -5612,14 +5646,13 @@ - } - - /* -- * Same as pgetc(), but ignores PEOA. -+ * Read a character from the script, returning PEOF on end of file. -+ * Nul characters in the input are silently discarded. - */ --static int pgetc2() { -- int c; -- do { -- c = pgetc(); -- } while (c == PEOA); -- return c; -+int pgetc(void) { -+ struct strpush *sp = parsefile->spfree; -+ if (unlikely(sp)) freestrings(sp); -+ return pgetc_nofree(); - } - - static void AddUniqueCompletion(linenoiseCompletions *c, char *s) { -@@ -5774,12 +5807,8 @@ - int more; - char savec; - if (unlikely(parsefile->strpush)) { -- if (parsefile->nleft == -1 && parsefile->strpush->ap && parsefile->nextc[-1] != ' ' && -- parsefile->nextc[-1] != '\t') { -- return PEOA; -- } - popstring(); -- return pgetc(); -+ return pgetc_nofree(); - } - if (unlikely(parsefile->nleft == EOF_NLEFT || parsefile->buf == NULL)) return PEOF; - flushall(); -@@ -5840,7 +5869,7 @@ - len = strlen(s); - INTOFF; - /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ -- if (parsefile->strpush) { -+ if ((unsigned long)parsefile->strpush | (unsigned long)parsefile->spfree) { - sp = ckmalloc(sizeof(struct strpush)); - sp->prev = parsefile->strpush; - parsefile->strpush = sp; -@@ -5849,6 +5878,7 @@ - sp->prevstring = parsefile->nextc; - sp->prevnleft = parsefile->nleft; - sp->unget = parsefile->unget; -+ sp->spfree = parsefile->spfree; - memcpy(sp->lastc, parsefile->lastc, sizeof(sp->lastc)); - sp->ap = (struct alias *)ap; - if (ap) { -@@ -5858,6 +5888,7 @@ - parsefile->nextc = s; - parsefile->nleft = len; - parsefile->unget = 0; -+ parsefile->spfree = NULL; - INTON; - } - -@@ -5871,10 +5902,6 @@ - if (sp->string != sp->ap->val) { - ckfree(sp->string); - } -- sp->ap->flag &= ~ALIASINUSE; -- if (sp->ap->flag & ALIASDEAD) { -- unalias(sp->ap->name); -- } - } - parsefile->nextc = sp->prevstring; - parsefile->nleft = sp->prevnleft; -@@ -5882,7 +5909,7 @@ - memcpy(parsefile->lastc, sp->lastc, sizeof(sp->lastc)); - /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ - parsefile->strpush = sp->prev; -- if (sp != &(parsefile->basestrpush)) ckfree(sp); -+ parsefile->spfree = sp; - INTON; - } - -@@ -5893,11 +5920,8 @@ - static int setinputfile(const char *fname, int flags) { - int fd; - INTOFF; -- if ((fd = open(fname, O_RDONLY, 0)) < 0) { -- if (flags & INPUT_NOFILE_OK) goto out; -- exitstatus = 127; -- exerror(EXERROR, "Can't open %s", fname); -- } -+ fd = sh_open(fname, O_RDONLY, flags & INPUT_NOFILE_OK); -+ if (fd < 0) goto out; - if (fd < 10) fd = savefd(fd, fd); - setinputfd(fd, flags & INPUT_PUSH_FILE); - out: -@@ -5943,6 +5967,7 @@ - pf->prev = parsefile; - pf->fd = -1; - pf->strpush = NULL; -+ pf->spfree = NULL; - pf->basestrpush.prev = NULL; - pf->unget = 0; - parsefile = pf; -@@ -5953,7 +5978,11 @@ - INTOFF; - if (pf->fd >= 0) close(pf->fd); - if (pf->buf) ckfree(pf->buf); -- while (pf->strpush) popstring(); -+ if (parsefile->spfree) freestrings(parsefile->spfree); -+ while (pf->strpush) { -+ popstring(); -+ freestrings(parsefile->spfree); -+ } - parsefile = pf->prev; - ckfree(pf); - INTON; -@@ -5970,18 +5999,6 @@ - unwindfiles(&basepf); - } - --/* -- * Close the file(s) that the shell is reading commands from. Called -- * after a fork is done. -- */ --static void closescript(void) { -- popallfiles(); -- if (parsefile->fd > 0) { -- close(parsefile->fd); -- parsefile->fd = 0; -- } --} -- - static char *commandtext(union node *); - static int dowait(int, struct job *); - static int getstatus(struct job *); -@@ -6052,7 +6069,7 @@ - if (on == jobctl || rootshell == 0) return; - if (on) { - int ofd; -- ofd = fd = open(_PATH_TTY, O_RDWR, 0); -+ ofd = fd = sh_open(_PATH_TTY, O_RDWR, 1); - if (fd < 0) { - fd += 3; - while (!isatty(fd)) -@@ -6322,8 +6339,8 @@ - static void showjobs(struct output *out, int mode) { - struct job *jp; - TRACE(("showjobs(%x) called\n", mode)); -- /* If not even one one job changed, there is nothing to do */ -- dowait(DOWAIT_NORMAL, NULL); -+ /* If not even one job changed, there is nothing to do */ -+ dowait(DOWAIT_NONBLOCK, NULL); - for (jp = curjob; jp; jp = jp->prev_job) { - if (!(mode & SHOW_CHANGED) || jp->changed) showjob(out, jp, mode); - } -@@ -6365,7 +6382,7 @@ - jp->waited = 1; - jp = jp->prev_job; - } -- if (!dowait(DOWAIT_WAITCMD, 0)) goto sigout; -+ if (!dowait(DOWAIT_WAITCMD_ALL, 0)) goto sigout; - } - } - retval = 127; -@@ -6546,8 +6563,7 @@ - lvforked = vforked; - if (!lvforked) { - shlvl++; -- closescript(); -- clear_traps(); -+ forkreset(); - /* do job control only in root shell */ - jobctl = 0; - } -@@ -6567,14 +6583,12 @@ - ignoresig(SIGQUIT); - if (jp->nprocs == 0) { - close(0); -- if (open(_PATH_DEVNULL, O_RDONLY, 0) != 0) sh_error("Can't open %s", _PATH_DEVNULL); -+ sh_open(_PATH_DEVNULL, O_RDONLY, 0); - } - } - if (!oldlvl && iflag) { -- if (mode != FORK_BG) { -- setsignal(SIGINT); -- setsignal(SIGQUIT); -- } -+ setsignal(SIGINT); -+ setsignal(SIGQUIT); - setsignal(SIGTERM); - } - if (lvforked) return; -@@ -6666,7 +6680,7 @@ - static int waitforjob(struct job *jp) { - int st; - TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0)); -- dowait(jp ? DOWAIT_BLOCK : DOWAIT_NORMAL, jp); -+ dowait(jp ? DOWAIT_BLOCK : DOWAIT_NONBLOCK, jp); - if (!jp) return exitstatus; - st = getstatus(jp); - if (jp->jobctl) { -@@ -6750,12 +6764,19 @@ - } - - static int dowait(int block, struct job *jp) { -- int pid = block == DOWAIT_NORMAL ? gotsigchld : 1; -- while (jp ? jp->state == JOBRUNNING : pid > 0) { -- if (!jp) gotsigchld = 0; -+ int gotchld = *(volatile int *)&gotsigchld; -+ int rpid; -+ int pid; -+ if (jp && jp->state != JOBRUNNING) block = DOWAIT_NONBLOCK; -+ if (block == DOWAIT_NONBLOCK && !gotchld) return 1; -+ rpid = 1; -+ do { - pid = waitone(block, jp); -- } -- return pid; -+ rpid &= !!pid; -+ block &= ~DOWAIT_WAITCMD_ALL; -+ if (!pid || (jp && jp->state != JOBRUNNING)) block = DOWAIT_NONBLOCK; -+ } while (pid >= 0); -+ return rpid; - } - - /* -@@ -6778,12 +6799,13 @@ - int err; - if (jobctl) flags |= WUNTRACED; - do { -- err = wait3(status, flags, NULL); -+ gotsigchld = 0; -+ do err = wait3(status, flags, NULL); -+ while (err < 0 && errno == EINTR); - if (err || (err = -!block)) break; - sigblockall(&oldmask); - while (!gotsigchld && !pending_sig) sigsuspend(&oldmask); - sigclearmask(); -- err = 0; - } while (gotsigchld); - return err; - } -@@ -7062,7 +7084,11 @@ - } - - static void xtcsetpgrp(int fd, int pgrp) { -- if (tcsetpgrp(fd, pgrp)) sh_error("Cannot set tty process group (%s)", strerror(errno)); -+ int err; -+ sigblockall(NULL); -+ err = tcsetpgrp(fd, pgrp); -+ sigclearmask(); -+ if (err) sh_error("Cannot set tty process group (%s)", strerror(errno)); - } - - static int getstatus(struct job *job) { -@@ -7458,7 +7484,6 @@ - setinputfile(*xargv, 0); - setarg0: - arg0 = *xargv++; -- commandname = arg0; - } - shellparam.p = xargv; - shellparam.optind = 1; -@@ -7803,22 +7828,27 @@ - } - - static union node *list(int nlflag) { -+ int chknl = nlflag & 1 ? 0 : CHKNL; - union node *n1, *n2, *n3; - int tok; - n1 = NULL; - for (;;) { -- switch (peektoken()) { -+ checkkwd = chknl | CHKKWD | CHKALIAS; -+ tok = readtoken(); -+ switch (tok) { - case TNL: -- if (!(nlflag & 1)) break; - parseheredoc(); - return n1; - case TEOF: -- if (!n1 && (nlflag & 1)) n1 = NEOF; -+ if (!n1 && !chknl) n1 = NEOF; -+ out_eof: - parseheredoc(); -+ tokpushback++; -+ lasttoken = TEOF; - return n1; - } -- checkkwd = CHKNL | CHKKWD | CHKALIAS; -- if (nlflag == 2 && tokendlist[peektoken()]) return n1; -+ tokpushback++; -+ if (nlflag == 2 && tokendlist[tok]) return n1; - nlflag |= 2; - n2 = andor(); - tok = readtoken(); -@@ -7845,15 +7875,16 @@ - n1 = n3; - } - switch (tok) { -- case TNL: - case TEOF: -+ goto out_eof; -+ case TNL: - tokpushback++; - /* fall through */ - case TBACKGND: - case TSEMI: - break; - default: -- if ((nlflag & 1)) synexpect(-1); -+ if (!chknl) synexpect(-1); - tokpushback++; - return n1; - } -@@ -8248,13 +8279,6 @@ - } - } - --static int peektoken(void) { -- int t; -- t = readtoken(); -- tokpushback++; -- return (t); --} -- - static int readtoken(void) { - int t; - int kwd = checkkwd; -@@ -8266,9 +8290,12 @@ - if (kwd & CHKNL) { - while (t == TNL) { - parseheredoc(); -+ checkkwd = 0; - t = xxreadtoken(); - } - } -+ kwd |= checkkwd; -+ checkkwd = 0; - if (t != TWORD || quoteflag) { - goto out; - } -@@ -8284,7 +8311,7 @@ - goto out; - } - } -- if (checkkwd & CHKALIAS) { -+ if (kwd & CHKALIAS) { - struct alias *ap; - if ((ap = lookupalias(wordtext, 1)) != NULL) { - if (*ap->val) { -@@ -8294,7 +8321,6 @@ - } - } - out: -- checkkwd = 0; - return (t); - } - -@@ -8338,7 +8364,6 @@ - switch (c) { - case ' ': - case '\t': -- case PEOA: - continue; - case '#': - while ((c = pgetc()) != '\n' && c != PEOF) -@@ -8376,7 +8401,7 @@ - static int pgetc_eatbnl(void) { - int c; - while ((c = pgetc()) == '\\') { -- if (pgetc2() != '\n') { -+ if (pgetc() != '\n') { - pungetc(); - break; - } -@@ -8481,7 +8506,7 @@ - break; - /* backslash */ - case CBACK: -- c = pgetc2(); -+ c = pgetc(); - if (c == PEOF) { - USTPUTC(CTLESC, out); - USTPUTC('\\', out); -@@ -8568,13 +8593,9 @@ - break; - case CEOF: - goto endword; /* exit outer loop */ -- case CIGN: -- break; - default: - if (synstack->varnest == 0) goto endword; /* exit outer loop */ -- if (c != PEOA) { -- USTPUTC(c, out); -- } -+ USTPUTC(c, out); - } - c = pgetc_top(synstack); - } -@@ -8613,18 +8634,13 @@ - if (realeofmark(eofmark)) { - int markloc; - char *p; -- if (c == PEOA) { -- c = pgetc2(); -- } - if (striptabs) { -- while (c == '\t') { -- c = pgetc2(); -- } -+ while (c == '\t') c = pgetc(); - } - markloc = out - (char *)stackblock(); - for (p = eofmark; STPUTC(c, out), *p; p++) { - if (c != *p) goto more_heredoc; -- c = pgetc2(); -+ c = pgetc(); - } - if (c == '\n' || c == PEOF) { - c = PEOF; -@@ -8717,8 +8733,7 @@ - char *p; - static const char types[] = "}-+?="; - c = pgetc_eatbnl(); -- if ((checkkwd & CHKEOFMARK) || c <= PEOA || -- (c != '(' && c != '{' && !is_name(c) && !is_special(c))) { -+ if ((checkkwd & CHKEOFMARK) || (c != '(' && c != '{' && !is_name(c) && !is_special(c))) { - USTPUTC('$', out); - pungetc(); - } else if (c == '(') { /* $(command) or $((arith)) */ -@@ -8748,7 +8763,7 @@ - do { - STPUTC(c, out); - c = pgetc_eatbnl(); -- } while (is_digit(c)); -+ } while ((subtype <= 0 || subtype >= VSLENGTH) && is_digit(c)); - } else if (c != '}') { - int cc = c; - c = pgetc_eatbnl(); -@@ -8795,6 +8810,7 @@ - break; - } - } else { -+ if (subtype == VSLENGTH && c != '}') subtype = 0; - badsub: - pungetc(); - } -@@ -8850,15 +8866,11 @@ - case '`': - goto done; - case '\\': -- pc = pgetc_eatbnl(); -+ pc = pgetc(); - if (pc != '\\' && pc != '`' && pc != '$' && (!synstack->dblquote || pc != '"')) - STPUTC('\\', pout); -- if (pc > PEOA) { -- break; -- } -- /* fall through */ -+ break; - case PEOF: -- case PEOA: - synerror("EOF in backquote substitution"); - case '\n': - nlnoprompt(); -@@ -8892,8 +8904,8 @@ - else { - if (readtoken() != TRP) synexpect(TRP); - setinputstring(nullstr); -- parseheredoc(); - } -+ parseheredoc(); - heredoclist = saveheredoclist; - (*nlpp)->n = n; - /* Start reading from old file again. */ -@@ -8938,21 +8950,38 @@ - } - - static const char *expandstr(const char *ps) { -- union node n; -+ struct parsefile *file_stop; -+ struct jmploc *volatile savehandler; -+ struct heredoc *saveheredoclist; -+ const char *result; - int saveprompt; -- /* XXX Fix (char *) cast. */ -- setinputstring((char *)ps); -+ struct jmploc jmploc; -+ union node n; -+ int err; -+ file_stop = parsefile; -+ setinputstring((char *)ps); /* XXX Fix (char *) cast. */ -+ saveheredoclist = heredoclist; -+ heredoclist = NULL; - saveprompt = doprompt; - doprompt = 0; -+ result = ps; -+ savehandler = handler; -+ if (unlikely(err = setjmp(jmploc.loc))) goto out; -+ handler = &jmploc; - readtoken1(pgetc_eatbnl(), DQSYNTAX, FAKEEOFMARK, 0); -- doprompt = saveprompt; -- popfile(); - n.narg.type = NARG; - n.narg.next = NULL; - n.narg.text = wordtext; - n.narg.backquote = backquotelist; - expandarg(&n, NULL, EXP_QUOTED); -- return stackblock(); -+ result = stackblock(); -+out: -+ handler = savehandler; -+ if (err && exception != EXERROR) longjmp(handler->loc, 1); -+ doprompt = saveprompt; -+ unwindfiles(file_stop); -+ heredoclist = saveheredoclist; -+ return result; - } - - /* -@@ -8979,6 +9008,16 @@ - return findstring(s, parsekwd, sizeof(parsekwd) / sizeof(const char *)); - } - -+static unsigned update_closed_redirs(int fd, int nfd) { -+ unsigned val = closed_redirs; -+ unsigned bit = 1 << fd; -+ if (nfd >= 0) -+ closed_redirs &= ~bit; -+ else -+ closed_redirs |= bit; -+ return val & bit; -+} -+ - /* - * Process a list of redirection commands. If the REDIR_PUSH flag is set, - * old file descriptors are stashed away so that the redirection can be -@@ -9003,17 +9042,17 @@ - if (newfd < -1) continue; - fd = n->nfile.fd; - if (sv) { -+ int closed; - p = &sv->renamed[fd]; - i = *p; -+ closed = update_closed_redirs(fd, newfd); - if (likely(i == EMPTY)) { - i = CLOSED; -- if (fd != newfd) { -+ if (fd != newfd && !closed) { - i = savefd(fd, fd); - fd = -1; - } - } -- if (i == newfd) /* Can only happen if i == newfd == CLOSED */ -- i = REALLY_CLOSED; - *p = i; - } - if (fd == newfd) continue; -@@ -9023,47 +9062,66 @@ - if (flags & REDIR_SAVEFD2 && sv->renamed[2] >= 0) preverrout.fd = sv->renamed[2]; - } - -+wontreturn static int sh_open_fail(const char *pathname, int flags, int e) { -+ const char *word; -+ int action; -+ word = "open"; -+ action = E_OPEN; -+ if (flags & O_CREAT) { -+ word = "create"; -+ action = E_CREAT; -+ } -+ sh_error("cannot %s %s: %s", word, pathname, errmsg(e, action)); -+} -+ -+static int sh_open(const char *pathname, int flags, int mayfail) { -+ int fd; -+ int e; -+ do { -+ fd = open(pathname, flags, 0666); -+ e = errno; -+ } while (fd < 0 && e == EINTR && !pending_sig); -+ if (mayfail || fd >= 0) return fd; -+ sh_open_fail(pathname, flags, e); -+} -+ - static int openredirect(union node *redir) { - struct stat sb; - char *fname; -+ int flags; - int f; - switch (redir->nfile.type) { - case NFROM: -- fname = redir->nfile.expfname; -- if ((f = open(fname, O_RDONLY, 0)) < 0) goto eopen; -+ flags = O_RDONLY; -+ do_open: -+ f = sh_open(redir->nfile.expfname, flags, 0); - break; - case NFROMTO: -- fname = redir->nfile.expfname; -- if ((f = open(fname, O_RDWR | O_CREAT, 0666)) < 0) goto ecreate; -- break; -+ flags = O_RDWR|O_CREAT; -+ goto do_open; - case NTO: - /* Take care of noclobber mode. */ - if (Cflag) { - fname = redir->nfile.expfname; - if (stat(fname, &sb) < 0) { -- if ((f = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0) goto ecreate; -- } else if (!S_ISREG(sb.st_mode)) { -- if ((f = open(fname, O_WRONLY, 0666)) < 0) goto ecreate; -- if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) { -- close(f); -- errno = EEXIST; -- goto ecreate; -- } -- } else { -- errno = EEXIST; -+ flags = O_WRONLY|O_CREAT|O_EXCL; -+ goto do_open; -+ } -+ if (S_ISREG(sb.st_mode)) goto ecreate; -+ f = sh_open(fname, O_WRONLY, 0); -+ if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) { -+ close(f); - goto ecreate; - } - break; - } - /* FALLTHROUGH */ - case NCLOBBER: -- fname = redir->nfile.expfname; -- if ((f = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) goto ecreate; -- break; -+ flags = O_WRONLY|O_CREAT|O_TRUNC; -+ goto do_open; - case NAPPEND: -- fname = redir->nfile.expfname; -- if ((f = open(fname, O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0) goto ecreate; -- break; -+ flags = O_WRONLY|O_CREAT|O_APPEND; -+ goto do_open; - case NTOFD: - case NFROMFD: - f = redir->ndup.dupfd; -@@ -9078,9 +9136,7 @@ - } - return f; - ecreate: -- sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); --eopen: -- sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); -+ sh_open_fail(fname, O_CREAT, EEXIST); - } - - static void dupredirect(union node *redir, int f) { -@@ -9149,12 +9205,12 @@ - INTOFF; - rp = redirlist; - for (i = 0; i < 10; i++) { -+ int closed; -+ if (rp->renamed[i] == EMPTY) continue; -+ closed = drop ? 1 : update_closed_redirs(i, rp->renamed[i]); - switch (rp->renamed[i]) { - case CLOSED: -- if (!drop) close(i); -- break; -- case EMPTY: -- case REALLY_CLOSED: -+ if (!closed) close(i); - break; - default: - if (!drop) dup2(rp->renamed[i], i); -@@ -9268,23 +9324,6 @@ - return 0; - } - --/* -- * Clear traps on a fork. -- */ --static void clear_traps(void) { -- char **tp; -- INTOFF; -- for (tp = trap; tp < &trap[NSIG]; tp++) { -- if (*tp && **tp) { /* trap not NULL or SIG_IGN */ -- ckfree(*tp); -- *tp = NULL; -- if (tp != &trap[0]) setsignal(tp - trap); -- } -- } -- trapcnt = 0; -- INTON; --} -- - /* - * Set the signal handler for the specified signal. The routine figures - * out what it should be set to. -@@ -9437,15 +9476,17 @@ - trap[0] = NULL; - evalskip = 0; - evalstring(p, 0); -+ evalskip = SKIPFUNCDEF; - } - out: -+ exitreset(); - /* - * Disable job control so that whoever had the foreground before we - * started can get it back. - */ - if (likely(!setjmp(loc.loc))) setjobctl(0); - flushall(); -- _exit(savestatus); -+ _exit(exitstatus); - } - - static int decode_signal(const char *string, int minsig) { -@@ -10104,12 +10145,23 @@ - static int timescmd() { - struct tms buf; - long int clk_tck = sysconf(_SC_CLK_TCK); -+ int mutime, mstime, mcutime, mcstime; -+ double utime, stime, cutime, cstime; - times(&buf); -- Printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", (int)(buf.tms_utime / clk_tck / 60), -- ((double)buf.tms_utime) / clk_tck, (int)(buf.tms_stime / clk_tck / 60), -- ((double)buf.tms_stime) / clk_tck, (int)(buf.tms_cutime / clk_tck / 60), -- ((double)buf.tms_cutime) / clk_tck, (int)(buf.tms_cstime / clk_tck / 60), -- ((double)buf.tms_cstime) / clk_tck); -+ utime = (double)buf.tms_utime / clk_tck; -+ mutime = utime / 60; -+ utime -= mutime * 60.0; -+ stime = (double)buf.tms_stime / clk_tck; -+ mstime = stime / 60; -+ stime -= mstime * 60.0; -+ cutime = (double)buf.tms_cutime / clk_tck; -+ mcutime = cutime / 60; -+ cutime -= mcutime * 60.0; -+ cstime = (double)buf.tms_cstime / clk_tck; -+ mcstime = cstime / 60; -+ cstime -= mcstime * 60.0; -+ Printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", mutime, utime, mstime, stime, -+ mcutime, cutime, mcstime, cstime); - return 0; - } - -@@ -10402,7 +10454,7 @@ - * Called after a function returns. - * Interrupts must be off. - */ --static void poplocalvars(int keep) { -+static void poplocalvars(void) { - struct localvar_list *ll; - struct localvar *lvp, *next; - struct Var *vp; -@@ -10415,18 +10467,7 @@ - next = lvp->next; - vp = lvp->vp; - TRACE(("poplocalvar %s\n", vp ? vp->text : "-")); -- if (keep) { -- int bits = VSTRFIXED; -- if (lvp->flags != VUNSET) { -- if (vp->text == lvp->text) -- bits |= VTEXTFIXED; -- else if (!(lvp->flags & (VTEXTFIXED | VSTACK))) -- ckfree(lvp->text); -- } -- vp->flags &= ~bits; -- vp->flags |= (lvp->flags & bits); -- if ((vp->flags & (VEXPORT | VREADONLY | VSTRFIXED | VUNSET)) == VUNSET) unsetvar(vp->text); -- } else if (vp == NULL) { /* $- saved */ -+ if (vp == NULL) { /* $- saved */ - memcpy(optlist, lvp->text, sizeof(optlist)); - ckfree(lvp->text); - optschanged(); -@@ -10463,7 +10504,7 @@ - } - - static void unwindlocalvars(struct localvar_list *stop) { -- while (localvar_stack != stop) poplocalvars(0); -+ while (localvar_stack != stop) poplocalvars(); - } - - /* -@@ -10506,8 +10547,7 @@ - sigmode[SIGCHLD - 1] = S_DFL; - setsignal(SIGCHLD); - } -- /* from output.c: */ -- {} /* from var.c: */ -+ /* from var.c: */ - { - char **envp; - static char ppid[32] = "PPID="; -@@ -10543,12 +10583,13 @@ - static void exitreset() { - /* from eval.c: */ - { -- evalskip = 0; -- loopnest = 0; - if (savestatus >= 0) { -- exitstatus = savestatus; -+ if (exception == EXEXIT || evalskip == SKIPFUNCDEF) exitstatus = savestatus; - savestatus = -1; - } -+ evalskip = 0; -+ loopnest = 0; -+ inps4 = 0; - } - /* from expand.c: */ - { ifsfree(); } -@@ -10561,6 +10602,42 @@ - } - } - -+/* -+ * This routine is called when we enter a subshell. -+ */ -+static void forkreset() { -+ /* from input.c: */ -+ { -+ popallfiles(); -+ if (parsefile->fd > 0) { -+ close(parsefile->fd); -+ parsefile->fd = 0; -+ } -+ } -+ /* from main.c: */ -+ { -+ handler = &main_handler; -+ } -+ /* from redir.c: */ -+ { -+ redirlist = NULL; -+ } -+ /* from trap.c: */ -+ { -+ char **tp; -+ INTOFF; -+ for (tp = trap ; tp < &trap[NSIG] ; tp++) { -+ if (*tp && **tp) { /* trap not NULL or SIG_IGN */ -+ ckfree(*tp); -+ *tp = NULL; -+ if (tp != &trap[0]) setsignal(tp - trap); -+ } -+ } -+ trapcnt = 0; -+ INTON; -+ } -+} -+ - /* - * This routine is called when an error or an interrupt occurs in an - * interactive shell and control is returned to the main command loop. -@@ -10570,10 +10647,10 @@ - { - /* clear input buffer */ - basepf.lleft = basepf.nleft = 0; -+ basepf.unget = 0; - popallfiles(); - } -- /* from output.c: */ -- {} /* from var.c: */ -+ /* from var.c: */ - { - unwindlocalvars(0); - } -@@ -10815,11 +10892,14 @@ - if (n == NEOF) { - if (!top || numeof >= 50) break; - if (!stoppedjobs()) { -- if (!Iflag) break; -+ if (!Iflag) { -+ if (iflag) outcslow('\n', out2); -+ break; -+ } - outstr("\nUse \"exit\" to leave shell.\n", out2); - } - numeof++; -- } else if (nflag == 0) { -+ } else { - int i; - job_warning = (job_warning == 2) ? 1 : 0; - numeof = 0; -@@ -10899,17 +10979,16 @@ - int main(int argc, char **argv) { - char *shinit; - volatile int state; -- struct jmploc jmploc; - struct stackmark smark; - int login; - state = 0; -- if (unlikely(setjmp(jmploc.loc))) { -+ if (unlikely(setjmp(main_handler.loc))) { - int e; - int s; - exitreset(); - e = exception; - s = state; -- if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) exitshell(); -+ if (e == EXEND || e == EXEXIT || s == 0 || iflag == 0 || shlvl) exitshell(); - reset(); - if (e == EXINT) { - outcslow('\n', out2); -@@ -10926,7 +11005,7 @@ - goto state4; - } - } -- handler = &jmploc; -+ handler = &main_handler; - rootpid = getpid(); - init(); - setstackmark(&smark);