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