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