input.c revision 200956
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Kenneth Almquist.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 4. Neither the name of the University nor the names of its contributors
171556Srgrimes *    may be used to endorse or promote products derived from this software
181556Srgrimes *    without specific prior written permission.
191556Srgrimes *
201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301556Srgrimes * SUCH DAMAGE.
311556Srgrimes */
321556Srgrimes
331556Srgrimes#ifndef lint
3436150Scharnier#if 0
3536150Scharnierstatic char sccsid[] = "@(#)input.c	8.3 (Berkeley) 6/9/95";
3636150Scharnier#endif
371556Srgrimes#endif /* not lint */
3899110Sobrien#include <sys/cdefs.h>
3999110Sobrien__FBSDID("$FreeBSD: head/bin/sh/input.c 200956 2009-12-24 18:41:14Z jilles $");
401556Srgrimes
4117987Speter#include <stdio.h>	/* defines BUFSIZ */
4217987Speter#include <fcntl.h>
4317987Speter#include <errno.h>
4417987Speter#include <unistd.h>
4517987Speter#include <stdlib.h>
4617987Speter#include <string.h>
4717987Speter
481556Srgrimes/*
491556Srgrimes * This file implements the input routines used by the parser.
501556Srgrimes */
511556Srgrimes
521556Srgrimes#include "shell.h"
5317987Speter#include "redir.h"
541556Srgrimes#include "syntax.h"
551556Srgrimes#include "input.h"
561556Srgrimes#include "output.h"
571556Srgrimes#include "options.h"
581556Srgrimes#include "memalloc.h"
591556Srgrimes#include "error.h"
601556Srgrimes#include "alias.h"
611556Srgrimes#include "parser.h"
621556Srgrimes#include "myhistedit.h"
63100588Stjr#include "trap.h"
641556Srgrimes
651556Srgrimes#define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
661556Srgrimes
671556SrgrimesMKINIT
681556Srgrimesstruct strpush {
691556Srgrimes	struct strpush *prev;	/* preceding string on stack */
701556Srgrimes	char *prevstring;
711556Srgrimes	int prevnleft;
7212043Speter	int prevlleft;
731556Srgrimes	struct alias *ap;	/* if push was associated with an alias */
741556Srgrimes};
751556Srgrimes
761556Srgrimes/*
771556Srgrimes * The parsefile structure pointed to by the global variable parsefile
781556Srgrimes * contains information about the current file being read.
791556Srgrimes */
801556Srgrimes
811556SrgrimesMKINIT
821556Srgrimesstruct parsefile {
831556Srgrimes	struct parsefile *prev;	/* preceding file on stack */
841556Srgrimes	int linno;		/* current line */
851556Srgrimes	int fd;			/* file descriptor (or -1 if string) */
8620425Ssteve	int nleft;		/* number of chars left in this line */
8720425Ssteve	int lleft;		/* number of lines left in this buffer */
881556Srgrimes	char *nextc;		/* next char in buffer */
891556Srgrimes	char *buf;		/* input buffer */
901556Srgrimes	struct strpush *strpush; /* for pushing strings at this level */
911556Srgrimes	struct strpush basestrpush; /* so pushing one is fast */
921556Srgrimes};
931556Srgrimes
941556Srgrimes
951556Srgrimesint plinno = 1;			/* input line number */
961556SrgrimesMKINIT int parsenleft;		/* copy of parsefile->nleft */
9712043SpeterMKINIT int parselleft;		/* copy of parsefile->lleft */
981556Srgrimeschar *parsenextc;		/* copy of parsefile->nextc */
991556SrgrimesMKINIT struct parsefile basepf;	/* top level input file */
1001556Srgrimeschar basebuf[BUFSIZ];		/* buffer for top level input file */
101117261SddsSTATIC struct parsefile *parsefile = &basepf;	/* current input file */
1021556Srgrimesint init_editline = 0;		/* editline library initialized? */
1031556Srgrimesint whichprompt;		/* 1 == PS1, 2 == PS2 */
1041556Srgrimes
1051556SrgrimesEditLine *el;			/* cookie for editline package */
1061556Srgrimes
10790111SimpSTATIC void pushfile(void);
10890111Simpstatic int preadfd(void);
1091556Srgrimes
1101556Srgrimes#ifdef mkinit
1111556SrgrimesINCLUDE "input.h"
1121556SrgrimesINCLUDE "error.h"
1131556Srgrimes
1141556SrgrimesINIT {
1151556Srgrimes	extern char basebuf[];
1161556Srgrimes
1171556Srgrimes	basepf.nextc = basepf.buf = basebuf;
1181556Srgrimes}
1191556Srgrimes
1201556SrgrimesRESET {
121194406Sjilles	popallfiles();
1221556Srgrimes	if (exception != EXSHELLPROC)
12312043Speter		parselleft = parsenleft = 0;	/* clear input buffer */
1241556Srgrimes}
1251556Srgrimes
1261556SrgrimesSHELLPROC {
1271556Srgrimes	popallfiles();
1281556Srgrimes}
1291556Srgrimes#endif
1301556Srgrimes
1311556Srgrimes
1321556Srgrimes/*
1331556Srgrimes * Read a line from the script.
1341556Srgrimes */
1351556Srgrimes
1361556Srgrimeschar *
13790111Simppfgets(char *line, int len)
13817987Speter{
13925225Ssteve	char *p = line;
1401556Srgrimes	int nleft = len;
1411556Srgrimes	int c;
1421556Srgrimes
1431556Srgrimes	while (--nleft > 0) {
1441556Srgrimes		c = pgetc_macro();
1451556Srgrimes		if (c == PEOF) {
1461556Srgrimes			if (p == line)
1471556Srgrimes				return NULL;
1481556Srgrimes			break;
1491556Srgrimes		}
1501556Srgrimes		*p++ = c;
1511556Srgrimes		if (c == '\n')
1521556Srgrimes			break;
1531556Srgrimes	}
1541556Srgrimes	*p = '\0';
1551556Srgrimes	return line;
1561556Srgrimes}
1571556Srgrimes
1581556Srgrimes
1591556Srgrimes
1601556Srgrimes/*
1611556Srgrimes * Read a character from the script, returning PEOF on end of file.
1621556Srgrimes * Nul characters in the input are silently discarded.
1631556Srgrimes */
1641556Srgrimes
1651556Srgrimesint
16690111Simppgetc(void)
16720425Ssteve{
1681556Srgrimes	return pgetc_macro();
1691556Srgrimes}
1701556Srgrimes
17120425Ssteve
17212043Speterstatic int
17390111Simppreadfd(void)
17412043Speter{
17512043Speter	int nr;
17620425Ssteve	parsenextc = parsefile->buf;
1771556Srgrimes
178100588Stjr#ifndef NO_HISTORY
179100588Stjr	if (el != NULL && gotwinch) {
180100588Stjr		gotwinch = 0;
181100588Stjr		el_resize(el);
182100588Stjr	}
183100588Stjr#endif
18412043Speterretry:
18525225Ssteve#ifndef NO_HISTORY
18612043Speter	if (parsefile->fd == 0 && el) {
187158143Sstefanf		static const char *rl_cp;
188158143Sstefanf		static int el_len;
18912043Speter
19012043Speter		if (rl_cp == NULL)
191158143Sstefanf			rl_cp = el_gets(el, &el_len);
192158143Sstefanf		if (rl_cp == NULL)
19312043Speter			nr = 0;
19412043Speter		else {
195158143Sstefanf			nr = el_len;
196158143Sstefanf			if (nr > BUFSIZ - 1)
197158143Sstefanf				nr = BUFSIZ - 1;
198158143Sstefanf			memcpy(parsenextc, rl_cp, nr);
199158143Sstefanf			if (nr != el_len) {
200158143Sstefanf				el_len -= nr;
201158143Sstefanf				rl_cp += nr;
202158143Sstefanf			} else
203158143Sstefanf				rl_cp = NULL;
20412043Speter		}
20525225Ssteve	} else
20625225Ssteve#endif
20712043Speter		nr = read(parsefile->fd, parsenextc, BUFSIZ - 1);
20812043Speter
20912043Speter	if (nr <= 0) {
21012043Speter                if (nr < 0) {
21112043Speter                        if (errno == EINTR)
21212043Speter                                goto retry;
21312043Speter                        if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
21412043Speter                                int flags = fcntl(0, F_GETFL, 0);
21512043Speter                                if (flags >= 0 && flags & O_NONBLOCK) {
21612043Speter                                        flags &=~ O_NONBLOCK;
21712043Speter                                        if (fcntl(0, F_SETFL, flags) >= 0) {
218199629Sjilles						out2fmt_flush("sh: turning off NDELAY mode\n");
21912043Speter                                                goto retry;
22012043Speter                                        }
22112043Speter                                }
22212043Speter                        }
22312043Speter                }
22420425Ssteve                nr = -1;
22512043Speter	}
22612043Speter	return nr;
22712043Speter}
22812043Speter
2291556Srgrimes/*
2301556Srgrimes * Refill the input buffer and return the next input character:
2311556Srgrimes *
2321556Srgrimes * 1) If a string was pushed back on the input, pop it;
2331556Srgrimes * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
2341556Srgrimes *    from a string so we can't refill the buffer, return EOF.
23520425Ssteve * 3) If there is more in this buffer, use it else call read to fill it.
23620425Ssteve * 4) Process input up to the next newline, deleting nul characters.
2371556Srgrimes */
2381556Srgrimes
2391556Srgrimesint
24090111Simppreadbuffer(void)
24120425Ssteve{
24212043Speter	char *p, *q;
24312043Speter	int more;
24412043Speter	int something;
24512043Speter	char savec;
2461556Srgrimes
2471556Srgrimes	if (parsefile->strpush) {
2481556Srgrimes		popstring();
2491556Srgrimes		if (--parsenleft >= 0)
2501556Srgrimes			return (*parsenextc++);
2511556Srgrimes	}
2521556Srgrimes	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
2531556Srgrimes		return PEOF;
2541556Srgrimes	flushout(&output);
2551556Srgrimes	flushout(&errout);
2561556Srgrimes
25712043Speteragain:
25812043Speter	if (parselleft <= 0) {
25925225Ssteve		if ((parselleft = preadfd()) == -1) {
26012043Speter			parselleft = parsenleft = EOF_NLEFT;
26112043Speter			return PEOF;
2621556Srgrimes		}
2631556Srgrimes	}
2641556Srgrimes
26512043Speter	q = p = parsenextc;
26612043Speter
2671556Srgrimes	/* delete nul characters */
2681556Srgrimes	something = 0;
26912043Speter	for (more = 1; more;) {
27012043Speter		switch (*p) {
27112043Speter		case '\0':
27212043Speter			p++;	/* Skip nul */
27312043Speter			goto check;
27412043Speter
27512043Speter		case '\t':
27612043Speter		case ' ':
2771556Srgrimes			break;
27812043Speter
27912043Speter		case '\n':
28012043Speter			parsenleft = q - parsenextc;
28112043Speter			more = 0; /* Stop processing here */
28212043Speter			break;
28312043Speter
28412043Speter		default:
2851556Srgrimes			something = 1;
28612043Speter			break;
2871556Srgrimes		}
28812043Speter
28912043Speter		*q++ = *p++;
29012043Spetercheck:
29112043Speter		if (--parselleft <= 0) {
29212043Speter			parsenleft = q - parsenextc - 1;
29312043Speter			if (parsenleft < 0)
29412043Speter				goto again;
29512043Speter			*q = '\0';
29612043Speter			more = 0;
29712043Speter		}
2981556Srgrimes	}
29912043Speter
30012043Speter	savec = *q;
3011556Srgrimes	*q = '\0';
3021556Srgrimes
30318018Speter#ifndef NO_HISTORY
3041556Srgrimes	if (parsefile->fd == 0 && hist && something) {
30584261Sobrien		HistEvent he;
3061556Srgrimes		INTOFF;
30784261Sobrien		history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
30884261Sobrien		    parsenextc);
3091556Srgrimes		INTON;
3101556Srgrimes	}
31118018Speter#endif
31212043Speter
3131556Srgrimes	if (vflag) {
31412043Speter		out2str(parsenextc);
3151556Srgrimes		flushout(out2);
3161556Srgrimes	}
31712043Speter
31812043Speter	*q = savec;
31912043Speter
3201556Srgrimes	return *parsenextc++;
3211556Srgrimes}
3221556Srgrimes
3231556Srgrimes/*
324194128Sjilles * Returns if we are certain we are at EOF. Does not cause any more input
325194128Sjilles * to be read from the outside world.
326194128Sjilles */
327194128Sjilles
328194128Sjillesint
329194128Sjillespreadateof(void)
330194128Sjilles{
331194128Sjilles	if (parsenleft > 0)
332194128Sjilles		return 0;
333194128Sjilles	if (parsefile->strpush)
334194128Sjilles		return 0;
335194128Sjilles	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
336194128Sjilles		return 1;
337194128Sjilles	return 0;
338194128Sjilles}
339194128Sjilles
340194128Sjilles/*
3411556Srgrimes * Undo the last call to pgetc.  Only one character may be pushed back.
3421556Srgrimes * PEOF may be pushed back.
3431556Srgrimes */
3441556Srgrimes
3451556Srgrimesvoid
34690111Simppungetc(void)
34790111Simp{
3481556Srgrimes	parsenleft++;
3491556Srgrimes	parsenextc--;
3501556Srgrimes}
3511556Srgrimes
3521556Srgrimes/*
3531556Srgrimes * Push a string back onto the input at this current parsefile level.
3541556Srgrimes * We handle aliases this way.
3551556Srgrimes */
3561556Srgrimesvoid
35790111Simppushstring(char *s, int len, void *ap)
35890111Simp{
3591556Srgrimes	struct strpush *sp;
3601556Srgrimes
3611556Srgrimes	INTOFF;
362199629Sjilles/*out2fmt_flush("*** calling pushstring: %s, %d\n", s, len);*/
3631556Srgrimes	if (parsefile->strpush) {
3641556Srgrimes		sp = ckmalloc(sizeof (struct strpush));
3651556Srgrimes		sp->prev = parsefile->strpush;
3661556Srgrimes		parsefile->strpush = sp;
3671556Srgrimes	} else
3681556Srgrimes		sp = parsefile->strpush = &(parsefile->basestrpush);
3691556Srgrimes	sp->prevstring = parsenextc;
3701556Srgrimes	sp->prevnleft = parsenleft;
37112043Speter	sp->prevlleft = parselleft;
3721556Srgrimes	sp->ap = (struct alias *)ap;
3731556Srgrimes	if (ap)
3741556Srgrimes		((struct alias *)ap)->flag |= ALIASINUSE;
3751556Srgrimes	parsenextc = s;
3761556Srgrimes	parsenleft = len;
3771556Srgrimes	INTON;
3781556Srgrimes}
3791556Srgrimes
38017987Spetervoid
38190111Simppopstring(void)
3821556Srgrimes{
3831556Srgrimes	struct strpush *sp = parsefile->strpush;
3841556Srgrimes
3851556Srgrimes	INTOFF;
3861556Srgrimes	parsenextc = sp->prevstring;
3871556Srgrimes	parsenleft = sp->prevnleft;
38812043Speter	parselleft = sp->prevlleft;
389199629Sjilles/*out2fmt_flush("*** calling popstring: restoring to '%s'\n", parsenextc);*/
3901556Srgrimes	if (sp->ap)
3911556Srgrimes		sp->ap->flag &= ~ALIASINUSE;
3921556Srgrimes	parsefile->strpush = sp->prev;
3931556Srgrimes	if (sp != &(parsefile->basestrpush))
3941556Srgrimes		ckfree(sp);
3951556Srgrimes	INTON;
3961556Srgrimes}
3971556Srgrimes
3981556Srgrimes/*
3991556Srgrimes * Set the input to take input from a file.  If push is set, push the
4001556Srgrimes * old input onto the stack first.
4011556Srgrimes */
4021556Srgrimes
4031556Srgrimesvoid
404200956Sjillessetinputfile(const char *fname, int push)
40517987Speter{
4061556Srgrimes	int fd;
4071556Srgrimes	int fd2;
4081556Srgrimes
4091556Srgrimes	INTOFF;
4101556Srgrimes	if ((fd = open(fname, O_RDONLY)) < 0)
41153891Scracauer		error("Can't open %s: %s", fname, strerror(errno));
4121556Srgrimes	if (fd < 10) {
413124780Sdes		fd2 = fcntl(fd, F_DUPFD, 10);
4141556Srgrimes		close(fd);
4151556Srgrimes		if (fd2 < 0)
4161556Srgrimes			error("Out of file descriptors");
4171556Srgrimes		fd = fd2;
4181556Srgrimes	}
4191556Srgrimes	setinputfd(fd, push);
4201556Srgrimes	INTON;
4211556Srgrimes}
4221556Srgrimes
4231556Srgrimes
4241556Srgrimes/*
4251556Srgrimes * Like setinputfile, but takes an open file descriptor.  Call this with
4261556Srgrimes * interrupts off.
4271556Srgrimes */
4281556Srgrimes
4291556Srgrimesvoid
43090111Simpsetinputfd(int fd, int push)
43117987Speter{
43225225Ssteve	(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
4331556Srgrimes	if (push) {
4341556Srgrimes		pushfile();
4351556Srgrimes		parsefile->buf = ckmalloc(BUFSIZ);
4361556Srgrimes	}
4371556Srgrimes	if (parsefile->fd > 0)
4381556Srgrimes		close(parsefile->fd);
4391556Srgrimes	parsefile->fd = fd;
4401556Srgrimes	if (parsefile->buf == NULL)
4411556Srgrimes		parsefile->buf = ckmalloc(BUFSIZ);
44212043Speter	parselleft = parsenleft = 0;
4431556Srgrimes	plinno = 1;
4441556Srgrimes}
4451556Srgrimes
4461556Srgrimes
4471556Srgrimes/*
4481556Srgrimes * Like setinputfile, but takes input from a string.
4491556Srgrimes */
4501556Srgrimes
4511556Srgrimesvoid
45290111Simpsetinputstring(char *string, int push)
45390111Simp{
4541556Srgrimes	INTOFF;
4551556Srgrimes	if (push)
4561556Srgrimes		pushfile();
4571556Srgrimes	parsenextc = string;
45812043Speter	parselleft = parsenleft = strlen(string);
4591556Srgrimes	parsefile->buf = NULL;
4601556Srgrimes	plinno = 1;
4611556Srgrimes	INTON;
4621556Srgrimes}
4631556Srgrimes
4641556Srgrimes
4651556Srgrimes
4661556Srgrimes/*
4671556Srgrimes * To handle the "." command, a stack of input files is used.  Pushfile
4681556Srgrimes * adds a new entry to the stack and popfile restores the previous level.
4691556Srgrimes */
4701556Srgrimes
4711556SrgrimesSTATIC void
47290111Simppushfile(void)
47390111Simp{
4741556Srgrimes	struct parsefile *pf;
4751556Srgrimes
4761556Srgrimes	parsefile->nleft = parsenleft;
47712043Speter	parsefile->lleft = parselleft;
4781556Srgrimes	parsefile->nextc = parsenextc;
4791556Srgrimes	parsefile->linno = plinno;
4801556Srgrimes	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
4811556Srgrimes	pf->prev = parsefile;
4821556Srgrimes	pf->fd = -1;
4831556Srgrimes	pf->strpush = NULL;
4841556Srgrimes	pf->basestrpush.prev = NULL;
4851556Srgrimes	parsefile = pf;
4861556Srgrimes}
4871556Srgrimes
4881556Srgrimes
4891556Srgrimesvoid
49090111Simppopfile(void)
49190111Simp{
4921556Srgrimes	struct parsefile *pf = parsefile;
4931556Srgrimes
4941556Srgrimes	INTOFF;
4951556Srgrimes	if (pf->fd >= 0)
4961556Srgrimes		close(pf->fd);
4971556Srgrimes	if (pf->buf)
4981556Srgrimes		ckfree(pf->buf);
4991556Srgrimes	while (pf->strpush)
5001556Srgrimes		popstring();
5011556Srgrimes	parsefile = pf->prev;
5021556Srgrimes	ckfree(pf);
5031556Srgrimes	parsenleft = parsefile->nleft;
50412043Speter	parselleft = parsefile->lleft;
5051556Srgrimes	parsenextc = parsefile->nextc;
5061556Srgrimes	plinno = parsefile->linno;
5071556Srgrimes	INTON;
5081556Srgrimes}
5091556Srgrimes
5101556Srgrimes
5111556Srgrimes/*
512199647Sjilles * Return current file (to go back to it later using popfilesupto()).
513199647Sjilles */
514199647Sjilles
515199647Sjillesstruct parsefile *
516199647Sjillesgetcurrentfile(void)
517199647Sjilles{
518199647Sjilles	return parsefile;
519199647Sjilles}
520199647Sjilles
521199647Sjilles
522199647Sjilles/*
523199647Sjilles * Pop files until the given file is on top again. Useful for regular
524199647Sjilles * builtins that read shell commands from files or strings.
525199647Sjilles * If the given file is not an active file, an error is raised.
526199647Sjilles */
527199647Sjilles
528199647Sjillesvoid
529199647Sjillespopfilesupto(struct parsefile *file)
530199647Sjilles{
531199647Sjilles	while (parsefile != file && parsefile != &basepf)
532199647Sjilles		popfile();
533199647Sjilles	if (parsefile != file)
534199647Sjilles		error("popfilesupto() misused");
535199647Sjilles}
536199647Sjilles
537199647Sjilles/*
5381556Srgrimes * Return to top level.
5391556Srgrimes */
5401556Srgrimes
5411556Srgrimesvoid
54290111Simppopallfiles(void)
54390111Simp{
5441556Srgrimes	while (parsefile != &basepf)
5451556Srgrimes		popfile();
5461556Srgrimes}
5471556Srgrimes
5481556Srgrimes
5491556Srgrimes
5501556Srgrimes/*
5511556Srgrimes * Close the file(s) that the shell is reading commands from.  Called
5521556Srgrimes * after a fork is done.
5531556Srgrimes */
5541556Srgrimes
5551556Srgrimesvoid
55690111Simpclosescript(void)
55790111Simp{
5581556Srgrimes	popallfiles();
5591556Srgrimes	if (parsefile->fd > 0) {
5601556Srgrimes		close(parsefile->fd);
5611556Srgrimes		parsefile->fd = 0;
5621556Srgrimes	}
5631556Srgrimes}
564