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