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