diff options
author | jilles <jilles@FreeBSD.org> | 2013-07-25 15:08:41 +0000 |
---|---|---|
committer | jilles <jilles@FreeBSD.org> | 2013-07-25 15:08:41 +0000 |
commit | 0ad2a46f33944b5fedbda54167af5739c8c5ed84 (patch) | |
tree | 4cdf5ff0108f4909c6111d72ffe6f925dec35704 /bin | |
parent | 34bfb313cd341ffba7e1c34cdc5f2aabc7cd8ec5 (diff) | |
download | FreeBSD-src-0ad2a46f33944b5fedbda54167af5739c8c5ed84.zip FreeBSD-src-0ad2a46f33944b5fedbda54167af5739c8c5ed84.tar.gz |
sh: Remove mkinit.
Replace the RESET blocks with regular functions and a reset() function that
calls them all.
This code generation tool is unusual and does not appear to provide much
benefit. I do not think isolating the knowledge about which modules need to
be reset is worth an almost 500-line build tool and wider scope for
variables used by the reset functions.
Also, relying on reset functions is often wrong: the cleanup should be done
in exception handlers so that no stale state remains after 'command eval'
and the like.
Diffstat (limited to 'bin')
-rw-r--r-- | bin/sh/Makefile | 11 | ||||
-rw-r--r-- | bin/sh/TOUR | 29 | ||||
-rw-r--r-- | bin/sh/eval.c | 9 | ||||
-rw-r--r-- | bin/sh/eval.h | 2 | ||||
-rw-r--r-- | bin/sh/exec.c | 1 | ||||
-rw-r--r-- | bin/sh/init.h | 36 | ||||
-rw-r--r-- | bin/sh/input.c | 9 | ||||
-rw-r--r-- | bin/sh/input.h | 1 | ||||
-rw-r--r-- | bin/sh/main.c | 11 | ||||
-rw-r--r-- | bin/sh/mkinit.c | 480 | ||||
-rw-r--r-- | bin/sh/parser.c | 8 | ||||
-rw-r--r-- | bin/sh/parser.h | 1 | ||||
-rw-r--r-- | bin/sh/redir.c | 9 | ||||
-rw-r--r-- | bin/sh/redir.h | 1 |
14 files changed, 32 insertions, 576 deletions
diff --git a/bin/sh/Makefile b/bin/sh/Makefile index cc04aa4..00d34fa 100644 --- a/bin/sh/Makefile +++ b/bin/sh/Makefile @@ -8,7 +8,7 @@ SHSRCS= alias.c arith_yacc.c arith_yylex.c cd.c echo.c error.c eval.c \ histedit.c input.c jobs.c kill.c mail.c main.c memalloc.c miscbltin.c \ mystring.c options.c output.c parser.c printf.c redir.c show.c \ test.c trap.c var.c -GENSRCS= builtins.c init.c nodes.c syntax.c +GENSRCS= builtins.c nodes.c syntax.c GENHDRS= builtins.h nodes.h syntax.h token.h SRCS= ${SHSRCS} ${GENSRCS} ${GENHDRS} @@ -30,26 +30,21 @@ WFORMAT=0 ${.CURDIR}/../test \ ${.CURDIR}/../../usr.bin/printf -CLEANFILES+= mkinit mkinit.o mknodes mknodes.o \ +CLEANFILES+= mknodes mknodes.o \ mksyntax mksyntax.o CLEANFILES+= ${GENSRCS} ${GENHDRS} -build-tools: mkinit mknodes mksyntax +build-tools: mknodes mksyntax .ORDER: builtins.c builtins.h builtins.c builtins.h: mkbuiltins builtins.def sh ${.CURDIR}/mkbuiltins ${.CURDIR} -init.c: mkinit alias.c eval.c exec.c input.c jobs.c options.c parser.c \ - redir.c trap.c var.c - ./mkinit ${.ALLSRC:S/^mkinit$//} - # XXX this is just to stop the default .c rule being used, so that the # intermediate object has a fixed name. # XXX we have a default .c rule, but no default .o rule. .o: ${CC} ${CFLAGS} ${LDFLAGS} ${.IMPSRC} ${LDLIBS} -o ${.TARGET} -mkinit: mkinit.o mknodes: mknodes.o mksyntax: mksyntax.o diff --git a/bin/sh/TOUR b/bin/sh/TOUR index 13438b5..e9bbe9b 100644 --- a/bin/sh/TOUR +++ b/bin/sh/TOUR @@ -25,38 +25,11 @@ programs is: program input files generates ------- ----------- --------- mkbuiltins builtins builtins.h builtins.c - mkinit *.c init.c mknodes nodetypes nodes.h nodes.c mksyntax - syntax.h syntax.c mktokens - token.h -There are undoubtedly too many of these. Mkinit searches all the -C source files for entries looking like: - - RESET { - x = 2; /* executed when the shell does a longjmp - back to the main command loop */ - } - -It pulls this code out into routines which are when particular -events occur. The intent is to improve modularity by isolating -the information about which modules need to be explicitly -initialized/reset within the modules themselves. - -Mkinit recognizes several constructs for placing declarations in -the init.c file. - INCLUDE "file.h" -includes a file. The storage class MKINIT makes a declaration -available in the init.c file, for example: - MKINIT int funcnest; /* depth of function calls */ -MKINIT alone on a line introduces a structure or union declara- -tion: - MKINIT - struct redirtab { - short renamed[10]; - }; -Preprocessor #define statements are copied to init.c without any -special action to request this. +There are undoubtedly too many of these. EXCEPTIONS: Code for dealing with exceptions appears in exceptions.c. The C language doesn't include exception handling, diff --git a/bin/sh/eval.c b/bin/sh/eval.c index 1a6d5ed..4d0fed7 100644 --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -104,16 +104,13 @@ static void prehash(union node *); * Called to reset things after an exception. */ -#ifdef mkinit -INCLUDE "eval.h" - -RESET { +void +reseteval(void) +{ evalskip = 0; loopnest = 0; funcnest = 0; } -#endif - /* diff --git a/bin/sh/eval.h b/bin/sh/eval.h index 724e157..a6e87b2 100644 --- a/bin/sh/eval.h +++ b/bin/sh/eval.h @@ -46,6 +46,8 @@ struct backcmd { /* result of evalbackcmd */ struct job *jp; /* job structure for command */ }; +void reseteval(void); + /* flags in argument to evaltree/evalstring */ #define EV_EXIT 01 /* exit after evaluating tree */ #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ diff --git a/bin/sh/exec.c b/bin/sh/exec.c index 6c3a6dd..5f78de9 100644 --- a/bin/sh/exec.c +++ b/bin/sh/exec.c @@ -70,7 +70,6 @@ __FBSDID("$FreeBSD$"); #include "syntax.h" #include "memalloc.h" #include "error.h" -#include "init.h" #include "mystring.h" #include "show.h" #include "jobs.h" diff --git a/bin/sh/init.h b/bin/sh/init.h deleted file mode 100644 index 384bb69..0000000 --- a/bin/sh/init.h +++ /dev/null @@ -1,36 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)init.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD$ - */ - -void reset(void); diff --git a/bin/sh/input.c b/bin/sh/input.c index f574f46..c5b1828 100644 --- a/bin/sh/input.c +++ b/bin/sh/input.c @@ -108,15 +108,12 @@ static void pushfile(void); static int preadfd(void); static void popstring(void); -#ifdef mkinit -INCLUDE "input.h" -INCLUDE "error.h" - -RESET { +void +resetinput(void) +{ popallfiles(); parselleft = parsenleft = 0; /* clear input buffer */ } -#endif /* diff --git a/bin/sh/input.h b/bin/sh/input.h index 70f675e..cc54eed 100644 --- a/bin/sh/input.h +++ b/bin/sh/input.h @@ -47,6 +47,7 @@ extern const char *parsenextc; /* next character in input buffer */ struct alias; struct parsefile; +void resetinput(void); char *pfgets(char *, int); int pgetc(void); int preadbuffer(void); diff --git a/bin/sh/main.c b/bin/sh/main.c index 0c496d0..2b99edd 100644 --- a/bin/sh/main.c +++ b/bin/sh/main.c @@ -68,10 +68,10 @@ __FBSDID("$FreeBSD$"); #include "show.h" #include "memalloc.h" #include "error.h" -#include "init.h" #include "mystring.h" #include "exec.h" #include "cd.h" +#include "redir.h" #include "builtins.h" int rootpid; @@ -79,6 +79,7 @@ int rootshell; struct jmploc main_handler; int localeisutf8, initial_localeisutf8; +static void reset(void); static void cmdloop(int); static void read_profile(const char *); static char *find_dot_file(char *); @@ -179,6 +180,14 @@ state4: return 0; } +static void +reset(void) +{ + reseteval(); + resetinput(); + resetparser(); + resetredir(); +} /* * Read and execute commands. "Top" is nonzero for the top level command diff --git a/bin/sh/mkinit.c b/bin/sh/mkinit.c deleted file mode 100644 index d73e0e2..0000000 --- a/bin/sh/mkinit.c +++ /dev/null @@ -1,480 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -static char const copyright[] = -"@(#) Copyright (c) 1991, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)mkinit.c 8.2 (Berkeley) 5/4/95"; -#endif -#endif /* not lint */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/* - * This program scans all the source files for code to handle various - * special events and combines this code into one file. This (allegedly) - * improves the structure of the program since there is no need for - * anyone outside of a module to know that that module performs special - * operations on particular events. - * - * Usage: mkinit sourcefile... - */ - - -#include <sys/types.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> - - -/* - * OUTFILE is the name of the output file. Output is initially written - * to the file OUTTEMP, which is then moved to OUTFILE. - */ - -#define OUTFILE "init.c" -#define OUTTEMP "init.c.new" - - -/* - * A text structure is basically just a string that grows as more characters - * are added onto the end of it. It is implemented as a linked list of - * blocks of characters. The routines addstr and addchar append a string - * or a single character, respectively, to a text structure. Writetext - * writes the contents of a text structure to a file. - */ - -#define BLOCKSIZE 512 - -struct text { - char *nextc; - int nleft; - struct block *start; - struct block *last; -}; - -struct block { - struct block *next; - char text[BLOCKSIZE]; -}; - - -/* - * There is one event structure for each event that mkinit handles. - */ - -struct event { - const char *name; /* name of event (e.g. RESET) */ - const char *routine; /* name of routine called on event */ - const char *comment; /* comment describing routine */ - struct text code; /* code for handling event */ -}; - - -char writer[] = "\ -/*\n\ - * This file was generated by the mkinit program.\n\ - */\n\ -\n"; - -char reset[] = "\ -/*\n\ - * This routine is called when an error or an interrupt occurs in an\n\ - * interactive shell and control is returned to the main command loop.\n\ - */\n"; - - -struct event event[] = { - { "RESET", "reset", reset, { NULL, 0, NULL, NULL } }, - { NULL, NULL, NULL, { NULL, 0, NULL, NULL } } -}; - - -const char *curfile; /* current file */ -int linno; /* current line */ -char *header_files[200]; /* list of header files */ -struct text defines; /* #define statements */ -struct text decls; /* declarations */ -int amiddecls; /* for formatting */ - - -void readfile(const char *); -int match(const char *, const char *); -int gooddefine(const char *); -void doevent(struct event *, FILE *, const char *); -void doinclude(char *); -void dodecl(char *, FILE *); -void output(void); -void addstr(const char *, struct text *); -void addchar(int, struct text *); -void writetext(struct text *, FILE *); -FILE *ckfopen(const char *, const char *); -void *ckmalloc(size_t); -char *savestr(const char *); -void error(const char *); - -#define equal(s1, s2) (strcmp(s1, s2) == 0) - -int -main(int argc __unused, char *argv[]) -{ - char **ap; - - header_files[0] = savestr("\"shell.h\""); - header_files[1] = savestr("\"mystring.h\""); - header_files[2] = savestr("\"init.h\""); - for (ap = argv + 1 ; *ap ; ap++) - readfile(*ap); - output(); - rename(OUTTEMP, OUTFILE); - exit(0); -} - - -/* - * Parse an input file. - */ - -void -readfile(const char *fname) -{ - FILE *fp; - char line[1024]; - struct event *ep; - - fp = ckfopen(fname, "r"); - curfile = fname; - linno = 0; - amiddecls = 0; - while (fgets(line, sizeof line, fp) != NULL) { - linno++; - for (ep = event ; ep->name ; ep++) { - if (line[0] == ep->name[0] && match(ep->name, line)) { - doevent(ep, fp, fname); - break; - } - } - if (line[0] == 'I' && match("INCLUDE", line)) - doinclude(line); - if (line[0] == 'M' && match("MKINIT", line)) - dodecl(line, fp); - if (line[0] == '#' && gooddefine(line)) { - char *cp; - char line2[1024]; - static const char undef[] = "#undef "; - - strcpy(line2, line); - memcpy(line2, undef, sizeof(undef) - 1); - cp = line2 + sizeof(undef) - 1; - while(*cp && (*cp == ' ' || *cp == '\t')) - cp++; - while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n') - cp++; - *cp++ = '\n'; *cp = '\0'; - addstr(line2, &defines); - addstr(line, &defines); - } - } - fclose(fp); -} - - -int -match(const char *name, const char *line) -{ - const char *p, *q; - - p = name, q = line; - while (*p) { - if (*p++ != *q++) - return 0; - } - if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n') - return 0; - return 1; -} - - -int -gooddefine(const char *line) -{ - const char *p; - - if (! match("#define", line)) - return 0; /* not a define */ - p = line + 7; - while (*p == ' ' || *p == '\t') - p++; - while (*p != ' ' && *p != '\t') { - if (*p == '(') - return 0; /* macro definition */ - p++; - } - while (*p != '\n' && *p != '\0') - p++; - if (p[-1] == '\\') - return 0; /* multi-line definition */ - return 1; -} - - -void -doevent(struct event *ep, FILE *fp, const char *fname) -{ - char line[1024]; - int indent; - const char *p; - - sprintf(line, "\n /* from %s: */\n", fname); - addstr(line, &ep->code); - addstr(" {\n", &ep->code); - for (;;) { - linno++; - if (fgets(line, sizeof line, fp) == NULL) - error("Unexpected EOF"); - if (equal(line, "}\n")) - break; - indent = 6; - for (p = line ; *p == '\t' ; p++) - indent += 8; - for ( ; *p == ' ' ; p++) - indent++; - if (*p == '\n' || *p == '#') - indent = 0; - while (indent >= 8) { - addchar('\t', &ep->code); - indent -= 8; - } - while (indent > 0) { - addchar(' ', &ep->code); - indent--; - } - addstr(p, &ep->code); - } - addstr(" }\n", &ep->code); -} - - -void -doinclude(char *line) -{ - char *p; - char *name; - char **pp; - - for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++); - if (*p == '\0') - error("Expecting '\"' or '<'"); - name = p; - while (*p != ' ' && *p != '\t' && *p != '\n') - p++; - if (p[-1] != '"' && p[-1] != '>') - error("Missing terminator"); - *p = '\0'; - - /* name now contains the name of the include file */ - for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++); - if (*pp == NULL) - *pp = savestr(name); -} - - -void -dodecl(char *line1, FILE *fp) -{ - char line[1024]; - char *p, *q; - - if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */ - addchar('\n', &decls); - do { - linno++; - if (fgets(line, sizeof line, fp) == NULL) - error("Unterminated structure declaration"); - addstr(line, &decls); - } while (line[0] != '}'); - amiddecls = 0; - } else { - if (! amiddecls) - addchar('\n', &decls); - q = NULL; - for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++) - continue; - if (*p == '=') { /* eliminate initialization */ - for (q = p ; *q && *q != ';' ; q++); - if (*q == '\0') - q = NULL; - else { - while (p[-1] == ' ') - p--; - *p = '\0'; - } - } - addstr("extern", &decls); - addstr(line1 + 6, &decls); - if (q != NULL) - addstr(q, &decls); - amiddecls = 1; - } -} - - - -/* - * Write the output to the file OUTTEMP. - */ - -void -output(void) -{ - FILE *fp; - char **pp; - struct event *ep; - - fp = ckfopen(OUTTEMP, "w"); - fputs(writer, fp); - for (pp = header_files ; *pp ; pp++) - fprintf(fp, "#include %s\n", *pp); - fputs("\n\n\n", fp); - writetext(&defines, fp); - fputs("\n\n", fp); - writetext(&decls, fp); - for (ep = event ; ep->name ; ep++) { - fputs("\n\n\n", fp); - fputs(ep->comment, fp); - fprintf(fp, "\nvoid\n%s(void)\n{\n", ep->routine); - writetext(&ep->code, fp); - fprintf(fp, "}\n"); - } - fclose(fp); -} - - -/* - * A text structure is simply a block of text that is kept in memory. - * Addstr appends a string to the text struct, and addchar appends a single - * character. - */ - -void -addstr(const char *s, struct text *text) -{ - while (*s) { - if (--text->nleft < 0) - addchar(*s++, text); - else - *text->nextc++ = *s++; - } -} - - -void -addchar(int c, struct text *text) -{ - struct block *bp; - - if (--text->nleft < 0) { - bp = ckmalloc(sizeof *bp); - if (text->start == NULL) - text->start = bp; - else - text->last->next = bp; - text->last = bp; - text->nextc = bp->text; - text->nleft = BLOCKSIZE - 1; - } - *text->nextc++ = c; -} - -/* - * Write the contents of a text structure to a file. - */ -void -writetext(struct text *text, FILE *fp) -{ - struct block *bp; - - if (text->start != NULL) { - for (bp = text->start ; bp != text->last ; bp = bp->next) - fwrite(bp->text, sizeof (char), BLOCKSIZE, fp); - fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp); - } -} - -FILE * -ckfopen(const char *file, const char *mode) -{ - FILE *fp; - - if ((fp = fopen(file, mode)) == NULL) { - fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno)); - exit(2); - } - return fp; -} - -void * -ckmalloc(size_t nbytes) -{ - char *p; - - if ((p = malloc(nbytes)) == NULL) - error("Out of space"); - return p; -} - -char * -savestr(const char *s) -{ - char *p; - - p = ckmalloc(strlen(s) + 1); - strcpy(p, s); - return p; -} - -void -error(const char *msg) -{ - if (curfile != NULL) - fprintf(stderr, "%s:%d: ", curfile, linno); - fprintf(stderr, "%s\n", msg); - exit(2); -} diff --git a/bin/sh/parser.c b/bin/sh/parser.c index 073c2b6..acb59df 100644 --- a/bin/sh/parser.c +++ b/bin/sh/parser.c @@ -1819,13 +1819,13 @@ parsearith: { } /* end of readtoken */ - -#ifdef mkinit -RESET { +void +resetparser(void) +{ tokpushback = 0; checkkwd = 0; } -#endif + /* * Returns true if the text contains nothing to expand (no dollar signs diff --git a/bin/sh/parser.h b/bin/sh/parser.h index b803f76..92b2e37 100644 --- a/bin/sh/parser.h +++ b/bin/sh/parser.h @@ -79,6 +79,7 @@ extern const char *const parsekwd[]; union node *parsecmd(int); void fixredir(union node *, const char *, int); +void resetparser(void); int goodname(const char *); int isassignment(const char *); char *getprompt(void *); diff --git a/bin/sh/redir.c b/bin/sh/redir.c index 855f317..d6d9fb1 100644 --- a/bin/sh/redir.c +++ b/bin/sh/redir.c @@ -324,16 +324,13 @@ popredir(void) * Undo all redirections. Called on error or interrupt. */ -#ifdef mkinit - -INCLUDE "redir.h" - -RESET { +void +resetredir(void) +{ while (redirlist) popredir(); } -#endif /* Return true if fd 0 has already been redirected at least once. */ int diff --git a/bin/sh/redir.h b/bin/sh/redir.h index ad44c4e..d012440 100644 --- a/bin/sh/redir.h +++ b/bin/sh/redir.h @@ -40,6 +40,7 @@ union node; void redirect(union node *, int); void popredir(void); +void resetredir(void); int fd0_redirected_p(void); void clearredir(void); |