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