1*3570Smckusick /* Copyright (c) 1979 Regents of the University of California */
2*3570Smckusick 
3*3570Smckusick static char sccsid[] = "@(#)pmerge.c 1.1 04/21/81";
4*3570Smckusick 
5*3570Smckusick #include <ctype.h>
6*3570Smckusick #include <stdio.h>
7*3570Smckusick #include <signal.h>
8*3570Smckusick 
9*3570Smckusick #define PRGFILE 0
10*3570Smckusick #define LABELFILE 1
11*3570Smckusick #define CONSTFILE 2
12*3570Smckusick #define TYPEFILE 3
13*3570Smckusick #define VARFILE 4
14*3570Smckusick #define RTNFILE 5
15*3570Smckusick #define BODYFILE 6
16*3570Smckusick #define NUMFILES 7
17*3570Smckusick 
18*3570Smckusick #define TRUE 1
19*3570Smckusick #define FALSE 0
20*3570Smckusick #define MAXINCL 9
21*3570Smckusick #define MAXNAM 75
22*3570Smckusick #define TMPNAME "/usr/tmp/MGXXXXXX"
23*3570Smckusick 
24*3570Smckusick FILE	*files[NUMFILES];
25*3570Smckusick char	*names[NUMFILES];
26*3570Smckusick FILE	*curfile;		/* current output file */
27*3570Smckusick FILE	*fopen();
28*3570Smckusick char	labelopen = FALSE, constopen = FALSE, typeopen = FALSE, varopen = FALSE;
29*3570Smckusick char	*mktemp();
30*3570Smckusick 
31*3570Smckusick /*
32*3570Smckusick  * Remove temporary files if interrupted
33*3570Smckusick  */
34*3570Smckusick onintr()
35*3570Smckusick {
36*3570Smckusick 	int i;
37*3570Smckusick 
38*3570Smckusick 	for (i = 0; i < NUMFILES; i++)
39*3570Smckusick 		if (files[i] != NULL)
40*3570Smckusick 			unlink(names[i]);
41*3570Smckusick }
42*3570Smckusick 
43*3570Smckusick /*
44*3570Smckusick  * Program to merge separately compiled pascal modules into a
45*3570Smckusick  * single standard Pascal program.
46*3570Smckusick  */
47*3570Smckusick main(argc, argv)
48*3570Smckusick 	long argc;
49*3570Smckusick 	char **argv;
50*3570Smckusick {
51*3570Smckusick 	FILE	*incl[MAXINCL];	/* include stack */
52*3570Smckusick 	long	inclcnt = 0;	/* incl index */
53*3570Smckusick 	char	*name[MAXNAM];	/* include names seen so far */
54*3570Smckusick 	long	namcnt = 0;	/* next name ptr slot available */
55*3570Smckusick 	char	nambuf[BUFSIZ];	/* string table for names */
56*3570Smckusick 	char	line[BUFSIZ];	/* input line buffer */
57*3570Smckusick 	char	*next = nambuf;	/* next name space available */
58*3570Smckusick 	FILE	*input = stdin;	/* current input file */
59*3570Smckusick 	long	ac = 0;		/* argv index */
60*3570Smckusick 	char	**cpp, *cp, *fp;/* char ptrs */
61*3570Smckusick 	int	i;		/* index var */
62*3570Smckusick 
63*3570Smckusick 	signal(SIGINT, onintr);
64*3570Smckusick 	curfile = files[PRGFILE] = fopen(names[PRGFILE] = mktemp(TMPNAME), "w");
65*3570Smckusick 	files[LABELFILE] = fopen(names[LABELFILE] = mktemp(TMPNAME), "w");
66*3570Smckusick 	files[CONSTFILE] = fopen(names[CONSTFILE] = mktemp(TMPNAME), "w");
67*3570Smckusick 	files[TYPEFILE] = fopen(names[TYPEFILE] = mktemp(TMPNAME), "w");
68*3570Smckusick 	files[VARFILE] = fopen(names[VARFILE] = mktemp(TMPNAME), "w");
69*3570Smckusick 	files[RTNFILE] = fopen(names[RTNFILE] = mktemp(TMPNAME), "w");
70*3570Smckusick 	files[BODYFILE] = fopen(names[BODYFILE] = mktemp(TMPNAME), "w");
71*3570Smckusick 	for (i = 0; i < NUMFILES; i++)
72*3570Smckusick 		if (files[i] == NULL)
73*3570Smckusick 			quit(names[i]);
74*3570Smckusick 	name[namcnt] = next;
75*3570Smckusick 	for(;;) {
76*3570Smckusick 		if (inclcnt > 0) {
77*3570Smckusick 			inclcnt--;
78*3570Smckusick 			fclose(input);
79*3570Smckusick 			input = incl[inclcnt];
80*3570Smckusick 		} else if (++ac < argc) {
81*3570Smckusick 			input = freopen(argv[ac], "r", input);
82*3570Smckusick 			if (input == NULL)
83*3570Smckusick 				quit(argv[ac]);
84*3570Smckusick 		} else {
85*3570Smckusick 			printout();
86*3570Smckusick 			onintr();
87*3570Smckusick 			exit(0);
88*3570Smckusick 		}
89*3570Smckusick 		fgets(line, BUFSIZ, input);
90*3570Smckusick 		while (!feof(input)) {
91*3570Smckusick 			if (line[0] != '#') {
92*3570Smckusick 				split(line);
93*3570Smckusick 				fgets(line, BUFSIZ, input);
94*3570Smckusick 				continue;
95*3570Smckusick 			}
96*3570Smckusick 			for (cp = &line[1]; isspace(*cp); cp++)
97*3570Smckusick 				/* void */;
98*3570Smckusick 			if (strcmpn("include", cp, 7))
99*3570Smckusick 				goto bad;
100*3570Smckusick 			for (cp += 7; isspace(*cp); cp++)
101*3570Smckusick 				/* void */;
102*3570Smckusick 			if (*cp != '\'' && *cp != '"')
103*3570Smckusick 				goto bad;
104*3570Smckusick 			for (fp = next, cp++; isalnum(*cp) || *cp == '.';)
105*3570Smckusick 				*fp++ = *cp++;
106*3570Smckusick 			if ((*cp != '\'' || *cp != '"') &&
107*3570Smckusick 			    (fp[-1] != 'i' || fp[-1] != 'h') &&
108*3570Smckusick 			    (fp[-2] != '.'))
109*3570Smckusick 				goto bad;
110*3570Smckusick 			*fp++ = '\0';
111*3570Smckusick 			for (cpp = name; *cpp < next && strcmp(*cpp, next); )
112*3570Smckusick 				cpp++;
113*3570Smckusick 			if (*cpp == next) {
114*3570Smckusick 				if (inclcnt == MAXINCL) {
115*3570Smckusick 					fputs("include table overflow\n",
116*3570Smckusick 						stderr);
117*3570Smckusick 					quit(NULL);
118*3570Smckusick 				}
119*3570Smckusick 				if (namcnt++ == MAXNAM) {
120*3570Smckusick 					fputs("include name table overflow\n",
121*3570Smckusick 						stderr);
122*3570Smckusick 					quit(NULL);
123*3570Smckusick 				}
124*3570Smckusick 				incl[inclcnt] = input;
125*3570Smckusick 				inclcnt++;
126*3570Smckusick 				input = fopen(next, "r");
127*3570Smckusick 				if (input == NULL)
128*3570Smckusick 					quit(next);
129*3570Smckusick 				next = fp;
130*3570Smckusick 				name[namcnt] = next;
131*3570Smckusick 			}
132*3570Smckusick 			fgets(line, BUFSIZ, input);
133*3570Smckusick 		}
134*3570Smckusick 	}
135*3570Smckusick bad:
136*3570Smckusick 	fputs("bad include format:", stderr);
137*3570Smckusick 	fputs(line, stderr);
138*3570Smckusick 	quit(NULL);
139*3570Smckusick }
140*3570Smckusick 
141*3570Smckusick /*
142*3570Smckusick  * Split up output into the approprite files
143*3570Smckusick  */
144*3570Smckusick char incom = FALSE;	/* TRUE => in comment */
145*3570Smckusick char incur = FALSE;	/* TRUE => in (* *) style comment */
146*3570Smckusick char inbrac = FALSE;	/* TRUE => in { } style comment */
147*3570Smckusick char instr = FALSE;	/* TRUE => in quoted string */
148*3570Smckusick char inprog = FALSE;	/* TRUE => program statement has been found */
149*3570Smckusick int  beginnest = 0;	/* routine nesting level */
150*3570Smckusick int  nest = 0;		/* begin block nesting level */
151*3570Smckusick 
152*3570Smckusick split(line)
153*3570Smckusick 	char *line;
154*3570Smckusick {
155*3570Smckusick 	char ch1, *cp;		/* input window */
156*3570Smckusick 	char *word;		/* ptr to current word */
157*3570Smckusick 	int len;		/* length of current word */
158*3570Smckusick 	char prt = TRUE;	/* TRUE => print current word */
159*3570Smckusick 
160*3570Smckusick 	ch1 = ' ';
161*3570Smckusick 	cp = line;
162*3570Smckusick 	while (*cp) {
163*3570Smckusick 		switch(*cp) {
164*3570Smckusick 		case '*':
165*3570Smckusick 			if (!incom && ch1 == '(') {
166*3570Smckusick 				incom = TRUE;
167*3570Smckusick 				incur = TRUE;
168*3570Smckusick 			}
169*3570Smckusick 			break;
170*3570Smckusick 		case ')':
171*3570Smckusick 			if (incur && ch1 == '*') {
172*3570Smckusick 				incom = FALSE;
173*3570Smckusick 				incur = FALSE;
174*3570Smckusick 			}
175*3570Smckusick 			break;
176*3570Smckusick 		case '{':
177*3570Smckusick 			if (!incom) {
178*3570Smckusick 				inbrac = TRUE;
179*3570Smckusick 				incom = TRUE;
180*3570Smckusick 			}
181*3570Smckusick 			break;
182*3570Smckusick 		case '}':
183*3570Smckusick 			if (inbrac) {
184*3570Smckusick 				inbrac = FALSE;
185*3570Smckusick 				incom = FALSE;
186*3570Smckusick 			}
187*3570Smckusick 			break;
188*3570Smckusick 		case '\'':
189*3570Smckusick 			if (!incom) {
190*3570Smckusick 				incom = TRUE;
191*3570Smckusick 				instr = TRUE;
192*3570Smckusick 			} else if (instr) {
193*3570Smckusick 				incom = FALSE;
194*3570Smckusick 				instr = FALSE;
195*3570Smckusick 			}
196*3570Smckusick 			break;
197*3570Smckusick 		}
198*3570Smckusick 		if (incom || !isalpha(*cp)) {
199*3570Smckusick 			fputc(*cp, curfile);
200*3570Smckusick 			ch1 = *cp++;
201*3570Smckusick 			continue;
202*3570Smckusick 		}
203*3570Smckusick 		word = cp;
204*3570Smckusick 		while (isalpha(*cp))
205*3570Smckusick 			cp++;
206*3570Smckusick 		len = cp - word;
207*3570Smckusick 		switch (*word) {
208*3570Smckusick 		case 'b':
209*3570Smckusick 			if (len == 5 && !strcmpn(word, "begin", 5)) {
210*3570Smckusick 				if (nest == 0 && beginnest == 0) {
211*3570Smckusick 					if (inprog != 1) {
212*3570Smckusick 						fprintf(stderr,
213*3570Smckusick 						    "improper program body");
214*3570Smckusick 						quit(NULL);
215*3570Smckusick 					}
216*3570Smckusick 					curfile = files[BODYFILE];
217*3570Smckusick 				} else {
218*3570Smckusick 					beginnest++;
219*3570Smckusick 				}
220*3570Smckusick 			}
221*3570Smckusick 			break;
222*3570Smckusick 		case 'c':
223*3570Smckusick 			if (len == 4 && !strcmpn(word, "case", 4)) {
224*3570Smckusick 				if (beginnest > 0) {
225*3570Smckusick 					beginnest++;
226*3570Smckusick 				}
227*3570Smckusick 				break;
228*3570Smckusick 			}
229*3570Smckusick 			if (len == 5 && !strcmpn(word, "const", 5)) {
230*3570Smckusick 				if (nest == 0) {
231*3570Smckusick 					prt = FALSE;
232*3570Smckusick 					if (!constopen) {
233*3570Smckusick 						constopen = TRUE;
234*3570Smckusick 						prt = TRUE;
235*3570Smckusick 					}
236*3570Smckusick 					curfile = files[CONSTFILE];
237*3570Smckusick 				}
238*3570Smckusick 			}
239*3570Smckusick 			break;
240*3570Smckusick 		case 'e':
241*3570Smckusick 			if (len == 3 && !strcmpn(word, "end", 3)) {
242*3570Smckusick 				if (beginnest == 1) {
243*3570Smckusick 					nest--;
244*3570Smckusick 				}
245*3570Smckusick 				if (beginnest > 0) {
246*3570Smckusick 					beginnest--;
247*3570Smckusick 				}
248*3570Smckusick 				if (nest < 0) {
249*3570Smckusick 					if (inprog == 1) {
250*3570Smckusick 						inprog = 0;
251*3570Smckusick 						nest = 0;
252*3570Smckusick 					} else {
253*3570Smckusick 						fprintf(stderr, "too many end statements");
254*3570Smckusick 						quit(NULL);
255*3570Smckusick 					}
256*3570Smckusick 				}
257*3570Smckusick 				break;
258*3570Smckusick 			}
259*3570Smckusick 			if (len == 8 && !strcmpn(word, "external", 8)) {
260*3570Smckusick 				fputs("forward", curfile);
261*3570Smckusick 				prt = FALSE;
262*3570Smckusick 				nest--;
263*3570Smckusick 			}
264*3570Smckusick 			break;
265*3570Smckusick 		case 'f':
266*3570Smckusick 			if (len == 8 && !strcmpn(word, "function", 8)) {
267*3570Smckusick 				if (nest == 0) {
268*3570Smckusick 					curfile = files[RTNFILE];
269*3570Smckusick 				}
270*3570Smckusick 				nest++;
271*3570Smckusick 				break;
272*3570Smckusick 			}
273*3570Smckusick 			if (len == 7 && !strcmpn(word, "forward", 7)) {
274*3570Smckusick 				nest--;
275*3570Smckusick 			}
276*3570Smckusick 			break;
277*3570Smckusick 		case 'l':
278*3570Smckusick 			if (len == 5 && !strcmpn(word, "label", 5)) {
279*3570Smckusick 				if (nest == 0) {
280*3570Smckusick 					prt = FALSE;
281*3570Smckusick 					if (!labelopen) {
282*3570Smckusick 						labelopen = TRUE;
283*3570Smckusick 						prt = TRUE;
284*3570Smckusick 					}
285*3570Smckusick 					curfile = files[LABELFILE];
286*3570Smckusick 				}
287*3570Smckusick 			}
288*3570Smckusick 			break;
289*3570Smckusick 		case 'p':
290*3570Smckusick 			if (len == 9 && !strcmpn(word, "procedure", 9)) {
291*3570Smckusick 				if (nest == 0) {
292*3570Smckusick 					curfile = files[RTNFILE];
293*3570Smckusick 				}
294*3570Smckusick 				nest++;
295*3570Smckusick 				break;
296*3570Smckusick 			}
297*3570Smckusick 			if (len == 7 && !strcmpn(word, "program", 7)) {
298*3570Smckusick 				if (nest != 0) {
299*3570Smckusick 					fprintf(stderr, "improper program nesting");
300*3570Smckusick 					quit(NULL);
301*3570Smckusick 				}
302*3570Smckusick 				inprog = 1;
303*3570Smckusick 				curfile = files[PRGFILE];
304*3570Smckusick 			}
305*3570Smckusick 			break;
306*3570Smckusick 		case 't':
307*3570Smckusick 			if (len == 4 && !strcmpn(word, "type", 4)) {
308*3570Smckusick 				if (nest == 0) {
309*3570Smckusick 					prt = FALSE;
310*3570Smckusick 					if (!typeopen) {
311*3570Smckusick 						typeopen = TRUE;
312*3570Smckusick 						prt = TRUE;
313*3570Smckusick 					}
314*3570Smckusick 					curfile = files[TYPEFILE];
315*3570Smckusick 				}
316*3570Smckusick 			}
317*3570Smckusick 			break;
318*3570Smckusick 		case 'v':
319*3570Smckusick 			if (len == 3 && !strcmpn(word, "var", 3)) {
320*3570Smckusick 				if (nest == 0) {
321*3570Smckusick 					prt = FALSE;
322*3570Smckusick 					if (!varopen) {
323*3570Smckusick 						varopen = TRUE;
324*3570Smckusick 						prt = TRUE;
325*3570Smckusick 					}
326*3570Smckusick 					curfile = files[VARFILE];
327*3570Smckusick 				}
328*3570Smckusick 			}
329*3570Smckusick 			break;
330*3570Smckusick 		}
331*3570Smckusick 		if (prt)
332*3570Smckusick 			fprintf(curfile, "%.*s", len, word);
333*3570Smckusick 		prt = TRUE;
334*3570Smckusick 		ch1 = ' ';
335*3570Smckusick 	}
336*3570Smckusick }
337*3570Smckusick 
338*3570Smckusick /*
339*3570Smckusick  * Print out the merged result
340*3570Smckusick  */
341*3570Smckusick printout()
342*3570Smckusick {
343*3570Smckusick 	FILE *fp;
344*3570Smckusick 	int i;
345*3570Smckusick 	char ch;
346*3570Smckusick 
347*3570Smckusick 	for(i = 0; i < NUMFILES; i++) {
348*3570Smckusick 		fp = freopen(names[i], "r", files[i]);
349*3570Smckusick 		if (fp == NULL)
350*3570Smckusick 			quit(names[i]);
351*3570Smckusick 		ch = getc(fp);
352*3570Smckusick 		while (!feof(fp)) {
353*3570Smckusick 			putc(ch,stdout);
354*3570Smckusick 			ch = getc(fp);
355*3570Smckusick 		}
356*3570Smckusick 	}
357*3570Smckusick }
358*3570Smckusick 
359*3570Smckusick /*
360*3570Smckusick  * Die gracefully
361*3570Smckusick  */
362*3570Smckusick quit(fp)
363*3570Smckusick 	char *fp;
364*3570Smckusick {
365*3570Smckusick 	if (fp != NULL)
366*3570Smckusick 		perror(fp);
367*3570Smckusick 	onintr();
368*3570Smckusick 	exit(1);
369*3570Smckusick }
370