mkinit.c revision 8855
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 * 368855Srgrimes * $Id: mkinit.c,v 1.3 1994/11/06 06:27:04 pst 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; 2011556Srgrimes char line[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); 2201556Srgrimes if (line[0] == '#' && gooddefine(line)) 2211556Srgrimes addstr(line, &defines); 2221556Srgrimes } 2231556Srgrimes fclose(fp); 2241556Srgrimes} 2251556Srgrimes 2261556Srgrimes 2271556Srgrimesint 2281556Srgrimesmatch(name, line) 2291556Srgrimes char *name; 2301556Srgrimes char *line; 2311556Srgrimes { 2321556Srgrimes register char *p, *q; 2331556Srgrimes 2341556Srgrimes p = name, q = line; 2351556Srgrimes while (*p) { 2361556Srgrimes if (*p++ != *q++) 2371556Srgrimes return 0; 2381556Srgrimes } 2391556Srgrimes if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n') 2401556Srgrimes return 0; 2411556Srgrimes return 1; 2421556Srgrimes} 2431556Srgrimes 2441556Srgrimes 2451556Srgrimesint 2461556Srgrimesgooddefine(line) 2471556Srgrimes char *line; 2481556Srgrimes { 2491556Srgrimes register char *p; 2501556Srgrimes 2511556Srgrimes if (! match("#define", line)) 2521556Srgrimes return 0; /* not a define */ 2531556Srgrimes p = line + 7; 2541556Srgrimes while (*p == ' ' || *p == '\t') 2551556Srgrimes p++; 2561556Srgrimes while (*p != ' ' && *p != '\t') { 2571556Srgrimes if (*p == '(') 2581556Srgrimes return 0; /* macro definition */ 2591556Srgrimes p++; 2601556Srgrimes } 2611556Srgrimes while (*p != '\n' && *p != '\0') 2621556Srgrimes p++; 2631556Srgrimes if (p[-1] == '\\') 2641556Srgrimes return 0; /* multi-line definition */ 2651556Srgrimes return 1; 2661556Srgrimes} 2671556Srgrimes 2681556Srgrimes 2691556Srgrimesvoid 2701556Srgrimesdoevent(ep, fp, fname) 2711556Srgrimes register struct event *ep; 2721556Srgrimes FILE *fp; 2731556Srgrimes char *fname; 2741556Srgrimes { 2751556Srgrimes char line[1024]; 2761556Srgrimes int indent; 2771556Srgrimes char *p; 2781556Srgrimes 2791556Srgrimes sprintf(line, "\n /* from %s: */\n", fname); 2801556Srgrimes addstr(line, &ep->code); 2811556Srgrimes addstr(" {\n", &ep->code); 2821556Srgrimes for (;;) { 2831556Srgrimes linno++; 2841556Srgrimes if (fgets(line, sizeof line, fp) == NULL) 2851556Srgrimes error("Unexpected EOF"); 2861556Srgrimes if (equal(line, "}\n")) 2871556Srgrimes break; 2881556Srgrimes indent = 6; 2891556Srgrimes for (p = line ; *p == '\t' ; p++) 2901556Srgrimes indent += 8; 2911556Srgrimes for ( ; *p == ' ' ; p++) 2921556Srgrimes indent++; 2931556Srgrimes if (*p == '\n' || *p == '#') 2941556Srgrimes indent = 0; 2951556Srgrimes while (indent >= 8) { 2961556Srgrimes addchar('\t', &ep->code); 2971556Srgrimes indent -= 8; 2981556Srgrimes } 2991556Srgrimes while (indent > 0) { 3001556Srgrimes addchar(' ', &ep->code); 3011556Srgrimes indent--; 3021556Srgrimes } 3031556Srgrimes addstr(p, &ep->code); 3041556Srgrimes } 3051556Srgrimes addstr(" }\n", &ep->code); 3061556Srgrimes} 3071556Srgrimes 3081556Srgrimes 3091556Srgrimesvoid 3101556Srgrimesdoinclude(line) 3111556Srgrimes char *line; 3121556Srgrimes { 3131556Srgrimes register char *p; 3141556Srgrimes char *name; 3151556Srgrimes register char **pp; 3161556Srgrimes 3171556Srgrimes for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++); 3181556Srgrimes if (*p == '\0') 3191556Srgrimes error("Expecting '\"' or '<'"); 3201556Srgrimes name = p; 3211556Srgrimes while (*p != ' ' && *p != '\t' && *p != '\n') 3221556Srgrimes p++; 3231556Srgrimes if (p[-1] != '"' && p[-1] != '>') 3241556Srgrimes error("Missing terminator"); 3251556Srgrimes *p = '\0'; 3261556Srgrimes 3271556Srgrimes /* name now contains the name of the include file */ 3281556Srgrimes for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++); 3291556Srgrimes if (*pp == NULL) 3301556Srgrimes *pp = savestr(name); 3311556Srgrimes} 3321556Srgrimes 3331556Srgrimes 3341556Srgrimesvoid 3351556Srgrimesdodecl(line1, fp) 3361556Srgrimes char *line1; 3371556Srgrimes FILE *fp; 3381556Srgrimes { 3391556Srgrimes char line[1024]; 3401556Srgrimes register char *p, *q; 3411556Srgrimes 3421556Srgrimes if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */ 3431556Srgrimes addchar('\n', &decls); 3441556Srgrimes do { 3451556Srgrimes linno++; 3461556Srgrimes if (fgets(line, sizeof line, fp) == NULL) 3471556Srgrimes error("Unterminated structure declaration"); 3481556Srgrimes addstr(line, &decls); 3491556Srgrimes } while (line[0] != '}'); 3501556Srgrimes amiddecls = 0; 3511556Srgrimes } else { 3521556Srgrimes if (! amiddecls) 3531556Srgrimes addchar('\n', &decls); 3541556Srgrimes q = NULL; 3554204Spst for (p = line1 + 6 ; *p != '=' && *p != '/' && *p != '\n'; p++); 3561556Srgrimes if (*p == '=') { /* eliminate initialization */ 3571556Srgrimes for (q = p ; *q && *q != ';' ; q++); 3581556Srgrimes if (*q == '\0') 3591556Srgrimes q = NULL; 3601556Srgrimes else { 3611556Srgrimes while (p[-1] == ' ') 3621556Srgrimes p--; 3631556Srgrimes *p = '\0'; 3641556Srgrimes } 3651556Srgrimes } 3661556Srgrimes addstr("extern", &decls); 3671556Srgrimes addstr(line1 + 6, &decls); 3681556Srgrimes if (q != NULL) 3691556Srgrimes addstr(q, &decls); 3701556Srgrimes amiddecls = 1; 3711556Srgrimes } 3721556Srgrimes} 3731556Srgrimes 3741556Srgrimes 3751556Srgrimes 3761556Srgrimes/* 3771556Srgrimes * Write the output to the file OUTTEMP. 3781556Srgrimes */ 3791556Srgrimes 3801556Srgrimesvoid 3811556Srgrimesoutput() { 3821556Srgrimes FILE *fp; 3831556Srgrimes char **pp; 3841556Srgrimes struct event *ep; 3851556Srgrimes 3861556Srgrimes fp = ckfopen(OUTTEMP, "w"); 3871556Srgrimes fputs(writer, fp); 3881556Srgrimes for (pp = header_files ; *pp ; pp++) 3891556Srgrimes fprintf(fp, "#include %s\n", *pp); 3901556Srgrimes fputs("\n\n\n", fp); 3911556Srgrimes writetext(&defines, fp); 3921556Srgrimes fputs("\n\n", fp); 3931556Srgrimes writetext(&decls, fp); 3941556Srgrimes for (ep = event ; ep->name ; ep++) { 3951556Srgrimes fputs("\n\n\n", fp); 3961556Srgrimes fputs(ep->comment, fp); 3971556Srgrimes fprintf(fp, "\nvoid\n%s() {\n", ep->routine); 3981556Srgrimes writetext(&ep->code, fp); 3991556Srgrimes fprintf(fp, "}\n"); 4001556Srgrimes } 4011556Srgrimes fclose(fp); 4021556Srgrimes} 4031556Srgrimes 4041556Srgrimes 4051556Srgrimes/* 4061556Srgrimes * Return true if the new output file is different from the old one. 4071556Srgrimes */ 4081556Srgrimes 4091556Srgrimesint 4101556Srgrimesfile_changed() { 4111556Srgrimes register FILE *f1, *f2; 4121556Srgrimes register int c; 4131556Srgrimes 4141556Srgrimes if ((f1 = fopen(OUTFILE, "r")) == NULL 4151556Srgrimes || (f2 = fopen(OUTTEMP, "r")) == NULL) 4161556Srgrimes return 1; 4171556Srgrimes while ((c = getc(f1)) == getc(f2)) { 4181556Srgrimes if (c == EOF) 4191556Srgrimes return 0; 4201556Srgrimes } 4211556Srgrimes return 1; 4221556Srgrimes} 4231556Srgrimes 4241556Srgrimes 4251556Srgrimes/* 4261556Srgrimes * Touch a file. Returns 0 on failure, 1 on success. 4271556Srgrimes */ 4281556Srgrimes 4291556Srgrimesint 4301556Srgrimestouch(file) 4311556Srgrimes char *file; 4321556Srgrimes { 4331556Srgrimes int fd; 4341556Srgrimes char c; 4351556Srgrimes 4361556Srgrimes if ((fd = open(file, O_RDWR)) < 0) 4371556Srgrimes return 0; 4381556Srgrimes if (read(fd, &c, 1) != 1) { 4391556Srgrimes close(fd); 4401556Srgrimes return 0; 4411556Srgrimes } 4421556Srgrimes lseek(fd, (off_t)0, 0); 4431556Srgrimes write(fd, &c, 1); 4441556Srgrimes close(fd); 4451556Srgrimes return 1; 4461556Srgrimes} 4471556Srgrimes 4481556Srgrimes 4491556Srgrimes 4501556Srgrimes/* 4511556Srgrimes * A text structure is simply a block of text that is kept in memory. 4521556Srgrimes * Addstr appends a string to the text struct, and addchar appends a single 4531556Srgrimes * character. 4541556Srgrimes */ 4551556Srgrimes 4561556Srgrimesvoid 4571556Srgrimesaddstr(s, text) 4581556Srgrimes register char *s; 4591556Srgrimes register struct text *text; 4601556Srgrimes { 4611556Srgrimes while (*s) { 4621556Srgrimes if (--text->nleft < 0) 4631556Srgrimes addchar(*s++, text); 4641556Srgrimes else 4651556Srgrimes *text->nextc++ = *s++; 4661556Srgrimes } 4671556Srgrimes} 4681556Srgrimes 4691556Srgrimes 4701556Srgrimesvoid 4711556Srgrimesaddchar(c, text) 4721556Srgrimes register struct text *text; 4731556Srgrimes { 4741556Srgrimes struct block *bp; 4751556Srgrimes 4761556Srgrimes if (--text->nleft < 0) { 4771556Srgrimes bp = ckmalloc(sizeof *bp); 4781556Srgrimes if (text->start == NULL) 4791556Srgrimes text->start = bp; 4801556Srgrimes else 4811556Srgrimes text->last->next = bp; 4821556Srgrimes text->last = bp; 4831556Srgrimes text->nextc = bp->text; 4841556Srgrimes text->nleft = BLOCKSIZE - 1; 4851556Srgrimes } 4861556Srgrimes *text->nextc++ = c; 4871556Srgrimes} 4881556Srgrimes 4891556Srgrimes/* 4901556Srgrimes * Write the contents of a text structure to a file. 4911556Srgrimes */ 4921556Srgrimesvoid 4931556Srgrimeswritetext(text, fp) 4941556Srgrimes struct text *text; 4951556Srgrimes FILE *fp; 4961556Srgrimes { 4971556Srgrimes struct block *bp; 4981556Srgrimes 4991556Srgrimes if (text->start != NULL) { 5001556Srgrimes for (bp = text->start ; bp != text->last ; bp = bp->next) 5011556Srgrimes fwrite(bp->text, sizeof (char), BLOCKSIZE, fp); 5021556Srgrimes fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp); 5031556Srgrimes } 5041556Srgrimes} 5051556Srgrimes 5061556SrgrimesFILE * 5071556Srgrimesckfopen(file, mode) 5081556Srgrimes char *file; 5091556Srgrimes char *mode; 5101556Srgrimes { 5111556Srgrimes FILE *fp; 5121556Srgrimes 5131556Srgrimes if ((fp = fopen(file, mode)) == NULL) { 5141556Srgrimes fprintf(stderr, "Can't open %s\n", file); 5151556Srgrimes exit(2); 5161556Srgrimes } 5171556Srgrimes return fp; 5181556Srgrimes} 5191556Srgrimes 5201556Srgrimesvoid * 5211556Srgrimesckmalloc(nbytes) { 5221556Srgrimes register char *p; 5231556Srgrimes char *malloc(); 5241556Srgrimes 5251556Srgrimes if ((p = malloc(nbytes)) == NULL) 5261556Srgrimes error("Out of space"); 5271556Srgrimes return p; 5281556Srgrimes} 5291556Srgrimes 5301556Srgrimeschar * 5311556Srgrimessavestr(s) 5321556Srgrimes char *s; 5331556Srgrimes { 5341556Srgrimes register char *p; 5351556Srgrimes 5361556Srgrimes p = ckmalloc(strlen(s) + 1); 5371556Srgrimes strcpy(p, s); 5381556Srgrimes return p; 5391556Srgrimes} 5401556Srgrimes 5411556Srgrimesvoid 5421556Srgrimeserror(msg) 5431556Srgrimes char *msg; 5441556Srgrimes { 5451556Srgrimes if (curfile != NULL) 5461556Srgrimes fprintf(stderr, "%s:%d: ", curfile, linno); 5471556Srgrimes fprintf(stderr, "%s\n", msg); 5481556Srgrimes exit(2); 5491556Srgrimes} 550