mkinit.c revision 11113
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 * 3. All advertising materials mentioning features or use of this software
171556Srgrimes *    must display the following acknowledgement:
181556Srgrimes *	This product includes software developed by the University of
191556Srgrimes *	California, Berkeley and its contributors.
201556Srgrimes * 4. Neither the name of the University nor the names of its contributors
211556Srgrimes *    may be used to endorse or promote products derived from this software
221556Srgrimes *    without specific prior written permission.
231556Srgrimes *
241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341556Srgrimes * SUCH DAMAGE.
353044Sdg *
3611113Sjoerg *	$Id: mkinit.c,v 1.4 1995/05/30 00:07:19 rgrimes Exp $
371556Srgrimes */
381556Srgrimes
391556Srgrimes#ifndef lint
401556Srgrimesstatic char copyright[] =
411556Srgrimes"@(#) Copyright (c) 1991, 1993\n\
421556Srgrimes	The Regents of the University of California.  All rights reserved.\n";
431556Srgrimes#endif /* not lint */
441556Srgrimes
451556Srgrimes#ifndef lint
461556Srgrimesstatic char sccsid[] = "@(#)mkinit.c	8.1 (Berkeley) 5/31/93";
471556Srgrimes#endif /* not lint */
481556Srgrimes
491556Srgrimes/*
501556Srgrimes * This program scans all the source files for code to handle various
511556Srgrimes * special events and combines this code into one file.  This (allegedly)
521556Srgrimes * improves the structure of the program since there is no need for
531556Srgrimes * anyone outside of a module to know that that module performs special
541556Srgrimes * operations on particular events.  The command is executed iff init.c
551556Srgrimes * is actually changed.
561556Srgrimes *
571556Srgrimes * Usage:  mkinit command sourcefile...
581556Srgrimes */
591556Srgrimes
601556Srgrimes
611556Srgrimes#include <sys/cdefs.h>
621556Srgrimes#include <sys/types.h>
631556Srgrimes#include <stdio.h>
641556Srgrimes#include <fcntl.h>
651556Srgrimes#include <unistd.h>
661556Srgrimes
671556Srgrimes
681556Srgrimes/*
691556Srgrimes * OUTFILE is the name of the output file.  Output is initially written
701556Srgrimes * to the file OUTTEMP, which is then moved to OUTFILE if OUTTEMP and
711556Srgrimes * OUTFILE are different.
721556Srgrimes */
731556Srgrimes
741556Srgrimes#define OUTFILE "init.c"
751556Srgrimes#define OUTTEMP "init.c.new"
761556Srgrimes#define OUTOBJ "init.o"
771556Srgrimes
781556Srgrimes
791556Srgrimes/*
801556Srgrimes * A text structure is basicly just a string that grows as more characters
811556Srgrimes * are added onto the end of it.  It is implemented as a linked list of
821556Srgrimes * blocks of characters.  The routines addstr and addchar append a string
831556Srgrimes * or a single character, respectively, to a text structure.  Writetext
841556Srgrimes * writes the contents of a text structure to a file.
851556Srgrimes */
861556Srgrimes
871556Srgrimes#define BLOCKSIZE 512
881556Srgrimes
891556Srgrimesstruct text {
901556Srgrimes	char *nextc;
911556Srgrimes	int nleft;
921556Srgrimes	struct block *start;
931556Srgrimes	struct block *last;
948855Srgrimes};
951556Srgrimes
961556Srgrimesstruct block {
971556Srgrimes	struct block *next;
981556Srgrimes	char text[BLOCKSIZE];
991556Srgrimes};
1001556Srgrimes
1011556Srgrimes
1021556Srgrimes/*
1031556Srgrimes * There is one event structure for each event that mkinit handles.
1041556Srgrimes */
1051556Srgrimes
1061556Srgrimesstruct event {
1071556Srgrimes	char *name;		/* name of event (e.g. INIT) */
1081556Srgrimes	char *routine;		/* name of routine called on event */
1091556Srgrimes	char *comment;		/* comment describing routine */
1101556Srgrimes	struct text code;		/* code for handling event */
1111556Srgrimes};
1121556Srgrimes
1131556Srgrimes
1141556Srgrimeschar writer[] = "\
1151556Srgrimes/*\n\
1161556Srgrimes * This file was generated by the mkinit program.\n\
1171556Srgrimes */\n\
1181556Srgrimes\n";
1191556Srgrimes
1201556Srgrimeschar init[] = "\
1211556Srgrimes/*\n\
1221556Srgrimes * Initialization code.\n\
1231556Srgrimes */\n";
1241556Srgrimes
1251556Srgrimeschar reset[] = "\
1261556Srgrimes/*\n\
1271556Srgrimes * This routine is called when an error or an interrupt occurs in an\n\
1281556Srgrimes * interactive shell and control is returned to the main command loop.\n\
1291556Srgrimes */\n";
1301556Srgrimes
1311556Srgrimeschar shellproc[] = "\
1321556Srgrimes/*\n\
1331556Srgrimes * This routine is called to initialize the shell to run a shell procedure.\n\
1341556Srgrimes */\n";
1351556Srgrimes
1361556Srgrimes
1371556Srgrimesstruct event event[] = {
1381556Srgrimes	{"INIT", "init", init},
1391556Srgrimes	{"RESET", "reset", reset},
1401556Srgrimes	{"SHELLPROC", "initshellproc", shellproc},
1411556Srgrimes	{NULL, NULL}
1421556Srgrimes};
1431556Srgrimes
1441556Srgrimes
1451556Srgrimeschar *curfile;				/* current file */
1461556Srgrimesint linno;				/* current line */
1471556Srgrimeschar *header_files[200];		/* list of header files */
1481556Srgrimesstruct text defines;			/* #define statements */
1491556Srgrimesstruct text decls;			/* declarations */
1501556Srgrimesint amiddecls;				/* for formatting */
1511556Srgrimes
1521556Srgrimes
1531556Srgrimesvoid readfile(), doevent(), doinclude(), dodecl(), output();
1541556Srgrimesvoid addstr(), addchar(), writetext();
1551556Srgrimes
1561556Srgrimes#define equal(s1, s2)	(strcmp(s1, s2) == 0)
1571556Srgrimes
1581556SrgrimesFILE *ckfopen();
1591556Srgrimeschar *savestr();
1601556Srgrimesvoid *ckmalloc __P((int));
1611556Srgrimesvoid error();
1621556Srgrimes
1631556Srgrimesmain(argc, argv)
1641556Srgrimes	char **argv;
1651556Srgrimes	{
1661556Srgrimes	char **ap;
1671556Srgrimes	int fd;
1681556Srgrimes	char c;
1691556Srgrimes
1701556Srgrimes	if (argc < 2)
1711556Srgrimes		error("Usage:  mkinit command file...");
1721556Srgrimes	header_files[0] = "\"shell.h\"";
1731556Srgrimes	header_files[1] = "\"mystring.h\"";
1741556Srgrimes	for (ap = argv + 2 ; *ap ; ap++)
1751556Srgrimes		readfile(*ap);
1761556Srgrimes	output();
1771556Srgrimes	if (file_changed()) {
1781556Srgrimes		unlink(OUTFILE);
1791556Srgrimes		link(OUTTEMP, OUTFILE);
1801556Srgrimes		unlink(OUTTEMP);
1811556Srgrimes	} else {
1821556Srgrimes		unlink(OUTTEMP);
1831556Srgrimes		if (touch(OUTOBJ))
1841556Srgrimes			exit(0);		/* no compilation necessary */
1851556Srgrimes	}
1861556Srgrimes	printf("%s\n", argv[1]);
1871556Srgrimes	execl("/bin/sh", "sh", "-c", argv[1], (char *)0);
1881556Srgrimes	error("Can't exec shell");
1891556Srgrimes}
1901556Srgrimes
1911556Srgrimes
1921556Srgrimes/*
1931556Srgrimes * Parse an input file.
1941556Srgrimes */
1951556Srgrimes
1961556Srgrimesvoid
1971556Srgrimesreadfile(fname)
1981556Srgrimes	char *fname;
1991556Srgrimes	{
2001556Srgrimes	FILE *fp;
20111113Sjoerg	char line[1024], line2[1024];
2021556Srgrimes	struct event *ep;
2031556Srgrimes
2041556Srgrimes	fp = ckfopen(fname, "r");
2051556Srgrimes	curfile = fname;
2061556Srgrimes	linno = 0;
2071556Srgrimes	amiddecls = 0;
2081556Srgrimes	while (fgets(line, sizeof line, fp) != NULL) {
2091556Srgrimes		linno++;
2101556Srgrimes		for (ep = event ; ep->name ; ep++) {
2111556Srgrimes			if (line[0] == ep->name[0] && match(ep->name, line)) {
2121556Srgrimes				doevent(ep, fp, fname);
2131556Srgrimes				break;
2141556Srgrimes			}
2151556Srgrimes		}
2161556Srgrimes		if (line[0] == 'I' && match("INCLUDE", line))
2171556Srgrimes			doinclude(line);
2181556Srgrimes		if (line[0] == 'M' && match("MKINIT", line))
2191556Srgrimes			dodecl(line, fp);
22011113Sjoerg		if (line[0] == '#' && gooddefine(line)) {
22111113Sjoerg			char *cp;
22211113Sjoerg
22311113Sjoerg			strcpy(line2, line);
22411113Sjoerg			memcpy(line2, "#undef ", strlen("#undef "));
22511113Sjoerg			cp = line2 + strlen("#undef ");
22611113Sjoerg			while(*cp && (*cp == ' ' || *cp == '\t'))
22711113Sjoerg				cp++;
22811113Sjoerg			while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
22911113Sjoerg				cp++;
23011113Sjoerg			*cp++ = '\n'; *cp = '\0';
23111113Sjoerg			addstr(line2, &defines);
2321556Srgrimes			addstr(line, &defines);
23311113Sjoerg		}
2341556Srgrimes	}
2351556Srgrimes	fclose(fp);
2361556Srgrimes}
2371556Srgrimes
2381556Srgrimes
2391556Srgrimesint
2401556Srgrimesmatch(name, line)
2411556Srgrimes	char *name;
2421556Srgrimes	char *line;
2431556Srgrimes	{
2441556Srgrimes	register char *p, *q;
2451556Srgrimes
2461556Srgrimes	p = name, q = line;
2471556Srgrimes	while (*p) {
2481556Srgrimes		if (*p++ != *q++)
2491556Srgrimes			return 0;
2501556Srgrimes	}
2511556Srgrimes	if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
2521556Srgrimes		return 0;
2531556Srgrimes	return 1;
2541556Srgrimes}
2551556Srgrimes
2561556Srgrimes
2571556Srgrimesint
2581556Srgrimesgooddefine(line)
2591556Srgrimes	char *line;
2601556Srgrimes	{
2611556Srgrimes	register char *p;
2621556Srgrimes
2631556Srgrimes	if (! match("#define", line))
2641556Srgrimes		return 0;			/* not a define */
2651556Srgrimes	p = line + 7;
2661556Srgrimes	while (*p == ' ' || *p == '\t')
2671556Srgrimes		p++;
2681556Srgrimes	while (*p != ' ' && *p != '\t') {
2691556Srgrimes		if (*p == '(')
2701556Srgrimes			return 0;		/* macro definition */
2711556Srgrimes		p++;
2721556Srgrimes	}
2731556Srgrimes	while (*p != '\n' && *p != '\0')
2741556Srgrimes		p++;
2751556Srgrimes	if (p[-1] == '\\')
2761556Srgrimes		return 0;			/* multi-line definition */
2771556Srgrimes	return 1;
2781556Srgrimes}
2791556Srgrimes
2801556Srgrimes
2811556Srgrimesvoid
2821556Srgrimesdoevent(ep, fp, fname)
2831556Srgrimes	register struct event *ep;
2841556Srgrimes	FILE *fp;
2851556Srgrimes	char *fname;
2861556Srgrimes	{
2871556Srgrimes	char line[1024];
2881556Srgrimes	int indent;
2891556Srgrimes	char *p;
2901556Srgrimes
2911556Srgrimes	sprintf(line, "\n      /* from %s: */\n", fname);
2921556Srgrimes	addstr(line, &ep->code);
2931556Srgrimes	addstr("      {\n", &ep->code);
2941556Srgrimes	for (;;) {
2951556Srgrimes		linno++;
2961556Srgrimes		if (fgets(line, sizeof line, fp) == NULL)
2971556Srgrimes			error("Unexpected EOF");
2981556Srgrimes		if (equal(line, "}\n"))
2991556Srgrimes			break;
3001556Srgrimes		indent = 6;
3011556Srgrimes		for (p = line ; *p == '\t' ; p++)
3021556Srgrimes			indent += 8;
3031556Srgrimes		for ( ; *p == ' ' ; p++)
3041556Srgrimes			indent++;
3051556Srgrimes		if (*p == '\n' || *p == '#')
3061556Srgrimes			indent = 0;
3071556Srgrimes		while (indent >= 8) {
3081556Srgrimes			addchar('\t', &ep->code);
3091556Srgrimes			indent -= 8;
3101556Srgrimes		}
3111556Srgrimes		while (indent > 0) {
3121556Srgrimes			addchar(' ', &ep->code);
3131556Srgrimes			indent--;
3141556Srgrimes		}
3151556Srgrimes		addstr(p, &ep->code);
3161556Srgrimes	}
3171556Srgrimes	addstr("      }\n", &ep->code);
3181556Srgrimes}
3191556Srgrimes
3201556Srgrimes
3211556Srgrimesvoid
3221556Srgrimesdoinclude(line)
3231556Srgrimes	char *line;
3241556Srgrimes	{
3251556Srgrimes	register char *p;
3261556Srgrimes	char *name;
3271556Srgrimes	register char **pp;
3281556Srgrimes
3291556Srgrimes	for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
3301556Srgrimes	if (*p == '\0')
3311556Srgrimes		error("Expecting '\"' or '<'");
3321556Srgrimes	name = p;
3331556Srgrimes	while (*p != ' ' && *p != '\t' && *p != '\n')
3341556Srgrimes		p++;
3351556Srgrimes	if (p[-1] != '"' && p[-1] != '>')
3361556Srgrimes		error("Missing terminator");
3371556Srgrimes	*p = '\0';
3381556Srgrimes
3391556Srgrimes	/* name now contains the name of the include file */
3401556Srgrimes	for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
3411556Srgrimes	if (*pp == NULL)
3421556Srgrimes		*pp = savestr(name);
3431556Srgrimes}
3441556Srgrimes
3451556Srgrimes
3461556Srgrimesvoid
3471556Srgrimesdodecl(line1, fp)
3481556Srgrimes	char *line1;
3491556Srgrimes	FILE *fp;
3501556Srgrimes	{
3511556Srgrimes	char line[1024];
3521556Srgrimes	register char *p, *q;
3531556Srgrimes
3541556Srgrimes	if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
3551556Srgrimes		addchar('\n', &decls);
3561556Srgrimes		do {
3571556Srgrimes			linno++;
3581556Srgrimes			if (fgets(line, sizeof line, fp) == NULL)
3591556Srgrimes				error("Unterminated structure declaration");
3601556Srgrimes			addstr(line, &decls);
3611556Srgrimes		} while (line[0] != '}');
3621556Srgrimes		amiddecls = 0;
3631556Srgrimes	} else {
3641556Srgrimes		if (! amiddecls)
3651556Srgrimes			addchar('\n', &decls);
3661556Srgrimes		q = NULL;
3674204Spst		for (p = line1 + 6 ; *p != '=' && *p != '/' && *p != '\n'; p++);
3681556Srgrimes		if (*p == '=') {		/* eliminate initialization */
3691556Srgrimes			for (q = p ; *q && *q != ';' ; q++);
3701556Srgrimes			if (*q == '\0')
3711556Srgrimes				q = NULL;
3721556Srgrimes			else {
3731556Srgrimes				while (p[-1] == ' ')
3741556Srgrimes					p--;
3751556Srgrimes				*p = '\0';
3761556Srgrimes			}
3771556Srgrimes		}
3781556Srgrimes		addstr("extern", &decls);
3791556Srgrimes		addstr(line1 + 6, &decls);
3801556Srgrimes		if (q != NULL)
3811556Srgrimes			addstr(q, &decls);
3821556Srgrimes		amiddecls = 1;
3831556Srgrimes	}
3841556Srgrimes}
3851556Srgrimes
3861556Srgrimes
3871556Srgrimes
3881556Srgrimes/*
3891556Srgrimes * Write the output to the file OUTTEMP.
3901556Srgrimes */
3911556Srgrimes
3921556Srgrimesvoid
3931556Srgrimesoutput() {
3941556Srgrimes	FILE *fp;
3951556Srgrimes	char **pp;
3961556Srgrimes	struct event *ep;
3971556Srgrimes
3981556Srgrimes	fp = ckfopen(OUTTEMP, "w");
3991556Srgrimes	fputs(writer, fp);
4001556Srgrimes	for (pp = header_files ; *pp ; pp++)
4011556Srgrimes		fprintf(fp, "#include %s\n", *pp);
4021556Srgrimes	fputs("\n\n\n", fp);
4031556Srgrimes	writetext(&defines, fp);
4041556Srgrimes	fputs("\n\n", fp);
4051556Srgrimes	writetext(&decls, fp);
4061556Srgrimes	for (ep = event ; ep->name ; ep++) {
4071556Srgrimes		fputs("\n\n\n", fp);
4081556Srgrimes		fputs(ep->comment, fp);
4091556Srgrimes		fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
4101556Srgrimes		writetext(&ep->code, fp);
4111556Srgrimes		fprintf(fp, "}\n");
4121556Srgrimes	}
4131556Srgrimes	fclose(fp);
4141556Srgrimes}
4151556Srgrimes
4161556Srgrimes
4171556Srgrimes/*
4181556Srgrimes * Return true if the new output file is different from the old one.
4191556Srgrimes */
4201556Srgrimes
4211556Srgrimesint
4221556Srgrimesfile_changed() {
4231556Srgrimes	register FILE *f1, *f2;
4241556Srgrimes	register int c;
4251556Srgrimes
4261556Srgrimes	if ((f1 = fopen(OUTFILE, "r")) == NULL
4271556Srgrimes	 || (f2 = fopen(OUTTEMP, "r")) == NULL)
4281556Srgrimes		return 1;
4291556Srgrimes	while ((c = getc(f1)) == getc(f2)) {
4301556Srgrimes		if (c == EOF)
4311556Srgrimes			return 0;
4321556Srgrimes	}
4331556Srgrimes	return 1;
4341556Srgrimes}
4351556Srgrimes
4361556Srgrimes
4371556Srgrimes/*
4381556Srgrimes * Touch a file.  Returns 0 on failure, 1 on success.
4391556Srgrimes */
4401556Srgrimes
4411556Srgrimesint
4421556Srgrimestouch(file)
4431556Srgrimes	char *file;
4441556Srgrimes	{
4451556Srgrimes	int fd;
4461556Srgrimes	char c;
4471556Srgrimes
4481556Srgrimes	if ((fd = open(file, O_RDWR)) < 0)
4491556Srgrimes		return 0;
4501556Srgrimes	if (read(fd, &c, 1) != 1) {
4511556Srgrimes		close(fd);
4521556Srgrimes		return 0;
4531556Srgrimes	}
4541556Srgrimes	lseek(fd, (off_t)0, 0);
4551556Srgrimes	write(fd, &c, 1);
4561556Srgrimes	close(fd);
4571556Srgrimes	return 1;
4581556Srgrimes}
4591556Srgrimes
4601556Srgrimes
4611556Srgrimes
4621556Srgrimes/*
4631556Srgrimes * A text structure is simply a block of text that is kept in memory.
4641556Srgrimes * Addstr appends a string to the text struct, and addchar appends a single
4651556Srgrimes * character.
4661556Srgrimes */
4671556Srgrimes
4681556Srgrimesvoid
4691556Srgrimesaddstr(s, text)
4701556Srgrimes	register char *s;
4711556Srgrimes	register struct text *text;
4721556Srgrimes	{
4731556Srgrimes	while (*s) {
4741556Srgrimes		if (--text->nleft < 0)
4751556Srgrimes			addchar(*s++, text);
4761556Srgrimes		else
4771556Srgrimes			*text->nextc++ = *s++;
4781556Srgrimes	}
4791556Srgrimes}
4801556Srgrimes
4811556Srgrimes
4821556Srgrimesvoid
4831556Srgrimesaddchar(c, text)
4841556Srgrimes	register struct text *text;
4851556Srgrimes	{
4861556Srgrimes	struct block *bp;
4871556Srgrimes
4881556Srgrimes	if (--text->nleft < 0) {
4891556Srgrimes		bp = ckmalloc(sizeof *bp);
4901556Srgrimes		if (text->start == NULL)
4911556Srgrimes			text->start = bp;
4921556Srgrimes		else
4931556Srgrimes			text->last->next = bp;
4941556Srgrimes		text->last = bp;
4951556Srgrimes		text->nextc = bp->text;
4961556Srgrimes		text->nleft = BLOCKSIZE - 1;
4971556Srgrimes	}
4981556Srgrimes	*text->nextc++ = c;
4991556Srgrimes}
5001556Srgrimes
5011556Srgrimes/*
5021556Srgrimes * Write the contents of a text structure to a file.
5031556Srgrimes */
5041556Srgrimesvoid
5051556Srgrimeswritetext(text, fp)
5061556Srgrimes	struct text *text;
5071556Srgrimes	FILE *fp;
5081556Srgrimes	{
5091556Srgrimes	struct block *bp;
5101556Srgrimes
5111556Srgrimes	if (text->start != NULL) {
5121556Srgrimes		for (bp = text->start ; bp != text->last ; bp = bp->next)
5131556Srgrimes			fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
5141556Srgrimes		fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
5151556Srgrimes	}
5161556Srgrimes}
5171556Srgrimes
5181556SrgrimesFILE *
5191556Srgrimesckfopen(file, mode)
5201556Srgrimes	char *file;
5211556Srgrimes	char *mode;
5221556Srgrimes	{
5231556Srgrimes	FILE *fp;
5241556Srgrimes
5251556Srgrimes	if ((fp = fopen(file, mode)) == NULL) {
5261556Srgrimes		fprintf(stderr, "Can't open %s\n", file);
5271556Srgrimes		exit(2);
5281556Srgrimes	}
5291556Srgrimes	return fp;
5301556Srgrimes}
5311556Srgrimes
5321556Srgrimesvoid *
5331556Srgrimesckmalloc(nbytes) {
5341556Srgrimes	register char *p;
5351556Srgrimes	char *malloc();
5361556Srgrimes
5371556Srgrimes	if ((p = malloc(nbytes)) == NULL)
5381556Srgrimes		error("Out of space");
5391556Srgrimes	return p;
5401556Srgrimes}
5411556Srgrimes
5421556Srgrimeschar *
5431556Srgrimessavestr(s)
5441556Srgrimes	char *s;
5451556Srgrimes	{
5461556Srgrimes	register char *p;
5471556Srgrimes
5481556Srgrimes	p = ckmalloc(strlen(s) + 1);
5491556Srgrimes	strcpy(p, s);
5501556Srgrimes	return p;
5511556Srgrimes}
5521556Srgrimes
5531556Srgrimesvoid
5541556Srgrimeserror(msg)
5551556Srgrimes	char *msg;
5561556Srgrimes	{
5571556Srgrimes	if (curfile != NULL)
5581556Srgrimes		fprintf(stderr, "%s:%d: ", curfile, linno);
5591556Srgrimes	fprintf(stderr, "%s\n", msg);
5601556Srgrimes	exit(2);
5611556Srgrimes}
562