13570Smckusick /* Copyright (c) 1979 Regents of the University of California */
23570Smckusick 
3*9577Sgarrison static char sccsid[] = "@(#)pmerge.c 1.3 12/07/82";
43570Smckusick 
53570Smckusick #include <ctype.h>
63570Smckusick #include <stdio.h>
73570Smckusick #include <signal.h>
83570Smckusick 
93570Smckusick #define PRGFILE 0
103570Smckusick #define LABELFILE 1
113570Smckusick #define CONSTFILE 2
123570Smckusick #define TYPEFILE 3
133570Smckusick #define VARFILE 4
143570Smckusick #define RTNFILE 5
153570Smckusick #define BODYFILE 6
163570Smckusick #define NUMFILES 7
173570Smckusick 
183570Smckusick #define TRUE 1
193570Smckusick #define FALSE 0
203570Smckusick #define MAXINCL 9
213570Smckusick #define MAXNAM 75
223570Smckusick #define TMPNAME "/usr/tmp/MGXXXXXX"
233570Smckusick 
243570Smckusick FILE	*files[NUMFILES];
253570Smckusick char	*names[NUMFILES];
263570Smckusick FILE	*curfile;		/* current output file */
273570Smckusick FILE	*fopen();
283570Smckusick char	labelopen = FALSE, constopen = FALSE, typeopen = FALSE, varopen = FALSE;
293570Smckusick char	*mktemp();
30*9577Sgarrison char	*malloc();
313570Smckusick 
323570Smckusick /*
333570Smckusick  * Remove temporary files if interrupted
343570Smckusick  */
353570Smckusick onintr()
363570Smckusick {
373570Smckusick 	int i;
383570Smckusick 
393570Smckusick 	for (i = 0; i < NUMFILES; i++)
403570Smckusick 		if (files[i] != NULL)
413570Smckusick 			unlink(names[i]);
423570Smckusick }
433570Smckusick 
443570Smckusick /*
453570Smckusick  * Program to merge separately compiled pascal modules into a
463570Smckusick  * single standard Pascal program.
473570Smckusick  */
483570Smckusick main(argc, argv)
493570Smckusick 	long argc;
503570Smckusick 	char **argv;
513570Smckusick {
523570Smckusick 	FILE	*incl[MAXINCL];	/* include stack */
533570Smckusick 	long	inclcnt = 0;	/* incl index */
543570Smckusick 	char	*name[MAXNAM];	/* include names seen so far */
553570Smckusick 	long	namcnt = 0;	/* next name ptr slot available */
56*9577Sgarrison 	char	*nambuf;	/* string table for names */
573570Smckusick 	char	line[BUFSIZ];	/* input line buffer */
58*9577Sgarrison 	char	*next;		/* next name space available */
593570Smckusick 	FILE	*input = stdin;	/* current input file */
603570Smckusick 	long	ac = 0;		/* argv index */
613570Smckusick 	char	**cpp, *cp, *fp;/* char ptrs */
623866Smckusic 	char	quote;		/* include quote character */
633570Smckusick 	int	i;		/* index var */
643570Smckusick 
65*9577Sgarrison 	for (i = 0; i < MAXNAM ; i++)
66*9577Sgarrison 		name[i] = 0;
67*9577Sgarrison 
683570Smckusick 	signal(SIGINT, onintr);
69*9577Sgarrison 
703570Smckusick 	curfile = files[PRGFILE] = fopen(names[PRGFILE] = mktemp(TMPNAME), "w");
713570Smckusick 	files[LABELFILE] = fopen(names[LABELFILE] = mktemp(TMPNAME), "w");
723570Smckusick 	files[CONSTFILE] = fopen(names[CONSTFILE] = mktemp(TMPNAME), "w");
733570Smckusick 	files[TYPEFILE] = fopen(names[TYPEFILE] = mktemp(TMPNAME), "w");
743570Smckusick 	files[VARFILE] = fopen(names[VARFILE] = mktemp(TMPNAME), "w");
753570Smckusick 	files[RTNFILE] = fopen(names[RTNFILE] = mktemp(TMPNAME), "w");
763570Smckusick 	files[BODYFILE] = fopen(names[BODYFILE] = mktemp(TMPNAME), "w");
77*9577Sgarrison 
783570Smckusick 	for (i = 0; i < NUMFILES; i++)
793570Smckusick 		if (files[i] == NULL)
803570Smckusick 			quit(names[i]);
81*9577Sgarrison 	if ((nambuf = malloc(BUFSIZ)) == NULL) {
82*9577Sgarrison 		fputs("no space for string table\n", stderr);
83*9577Sgarrison 		quit(NULL);
84*9577Sgarrison 	}
85*9577Sgarrison 	next = nambuf;
863570Smckusick 	name[namcnt] = next;
873570Smckusick 	for(;;) {
883570Smckusick 		if (inclcnt > 0) {
893570Smckusick 			inclcnt--;
903570Smckusick 			fclose(input);
913570Smckusick 			input = incl[inclcnt];
923570Smckusick 		} else if (++ac < argc) {
933570Smckusick 			input = freopen(argv[ac], "r", input);
943570Smckusick 			if (input == NULL)
953570Smckusick 				quit(argv[ac]);
963570Smckusick 		} else {
973570Smckusick 			printout();
983570Smckusick 			onintr();
993570Smckusick 			exit(0);
1003570Smckusick 		}
1013570Smckusick 		fgets(line, BUFSIZ, input);
1023570Smckusick 		while (!feof(input)) {
1033570Smckusick 			if (line[0] != '#') {
1043570Smckusick 				split(line);
1053570Smckusick 				fgets(line, BUFSIZ, input);
1063570Smckusick 				continue;
1073570Smckusick 			}
1083570Smckusick 			for (cp = &line[1]; isspace(*cp); cp++)
1093570Smckusick 				/* void */;
1103570Smckusick 			if (strcmpn("include", cp, 7))
1113570Smckusick 				goto bad;
1123570Smckusick 			for (cp += 7; isspace(*cp); cp++)
1133570Smckusick 				/* void */;
1143570Smckusick 			if (*cp != '\'' && *cp != '"')
1153570Smckusick 				goto bad;
116*9577Sgarrison 			if (&nambuf[BUFSIZ] < next + strlen(cp)) {
117*9577Sgarrison 				if ((nambuf = malloc(BUFSIZ)) == NULL) {
118*9577Sgarrison 					fputs("no space for string table\n",
119*9577Sgarrison 						stderr);
120*9577Sgarrison 					quit(NULL);
121*9577Sgarrison 				}
122*9577Sgarrison 				next = nambuf;
123*9577Sgarrison 				name[namcnt] = next;
124*9577Sgarrison 			}
1253866Smckusic 			for (fp = next, quote = *cp++;
1263866Smckusic 			     *cp != '\0' && *cp != quote; )
1273570Smckusick 				*fp++ = *cp++;
1283866Smckusic 			if (*cp != quote &&
1293570Smckusick 			    (fp[-1] != 'i' || fp[-1] != 'h') &&
1303570Smckusick 			    (fp[-2] != '.'))
1313570Smckusick 				goto bad;
1323570Smckusick 			*fp++ = '\0';
1333570Smckusick 			for (cpp = name; *cpp < next && strcmp(*cpp, next); )
1343570Smckusick 				cpp++;
1353570Smckusick 			if (*cpp == next) {
1363570Smckusick 				if (inclcnt == MAXINCL) {
1373570Smckusick 					fputs("include table overflow\n",
1383570Smckusick 						stderr);
1393570Smckusick 					quit(NULL);
1403570Smckusick 				}
141*9577Sgarrison 				if (++namcnt == MAXNAM) {
1423570Smckusick 					fputs("include name table overflow\n",
1433570Smckusick 						stderr);
1443570Smckusick 					quit(NULL);
1453570Smckusick 				}
1463570Smckusick 				incl[inclcnt] = input;
1473570Smckusick 				inclcnt++;
1483570Smckusick 				input = fopen(next, "r");
1493570Smckusick 				if (input == NULL)
1503570Smckusick 					quit(next);
1513570Smckusick 				next = fp;
1523570Smckusick 				name[namcnt] = next;
1533570Smckusick 			}
1543570Smckusick 			fgets(line, BUFSIZ, input);
1553570Smckusick 		}
1563570Smckusick 	}
1573570Smckusick bad:
1583570Smckusick 	fputs("bad include format:", stderr);
1593570Smckusick 	fputs(line, stderr);
1603570Smckusick 	quit(NULL);
1613570Smckusick }
1623570Smckusick 
1633570Smckusick /*
1643570Smckusick  * Split up output into the approprite files
1653570Smckusick  */
1663570Smckusick char incom = FALSE;	/* TRUE => in comment */
1673570Smckusick char incur = FALSE;	/* TRUE => in (* *) style comment */
1683570Smckusick char inbrac = FALSE;	/* TRUE => in { } style comment */
1693570Smckusick char instr = FALSE;	/* TRUE => in quoted string */
1703570Smckusick char inprog = FALSE;	/* TRUE => program statement has been found */
1713570Smckusick int  beginnest = 0;	/* routine nesting level */
1723570Smckusick int  nest = 0;		/* begin block nesting level */
173*9577Sgarrison int  paren_level = 0;	/* nesting level of parentheses */
1743570Smckusick 
1753570Smckusick split(line)
1763570Smckusick 	char *line;
1773570Smckusick {
1783570Smckusick 	char ch1, *cp;		/* input window */
1793570Smckusick 	char *word;		/* ptr to current word */
1803570Smckusick 	int len;		/* length of current word */
1813570Smckusick 	char prt = TRUE;	/* TRUE => print current word */
1823570Smckusick 
1833570Smckusick 	ch1 = ' ';
1843570Smckusick 	cp = line;
1853570Smckusick 	while (*cp) {
1863570Smckusick 		switch(*cp) {
187*9577Sgarrison 		case '(':
188*9577Sgarrison 			if (incom)
189*9577Sgarrison 				break;
190*9577Sgarrison 			if (*(cp+1) == '*') {
191*9577Sgarrison 				fputc(*cp, curfile);
192*9577Sgarrison 				cp++;
1933570Smckusick 				incom = TRUE;
1943570Smckusick 				incur = TRUE;
195*9577Sgarrison 			} else {
196*9577Sgarrison 				paren_level++;
1973570Smckusick 			}
1983570Smckusick 			break;
1993570Smckusick 		case ')':
2003570Smckusick 			if (incur && ch1 == '*') {
2013570Smckusick 				incom = FALSE;
2023570Smckusick 				incur = FALSE;
203*9577Sgarrison 			} else if (!incom) {
204*9577Sgarrison 				paren_level--;
2053570Smckusick 			}
2063570Smckusick 			break;
2073570Smckusick 		case '{':
2083570Smckusick 			if (!incom) {
2093570Smckusick 				inbrac = TRUE;
2103570Smckusick 				incom = TRUE;
2113570Smckusick 			}
2123570Smckusick 			break;
2133570Smckusick 		case '}':
2143570Smckusick 			if (inbrac) {
2153570Smckusick 				inbrac = FALSE;
2163570Smckusick 				incom = FALSE;
2173570Smckusick 			}
2183570Smckusick 			break;
2193570Smckusick 		case '\'':
2203570Smckusick 			if (!incom) {
2213570Smckusick 				incom = TRUE;
2223570Smckusick 				instr = TRUE;
2233570Smckusick 			} else if (instr) {
2243570Smckusick 				incom = FALSE;
2253570Smckusick 				instr = FALSE;
2263570Smckusick 			}
2273570Smckusick 			break;
2283570Smckusick 		}
2293570Smckusick 		if (incom || !isalpha(*cp)) {
2303570Smckusick 			fputc(*cp, curfile);
2313570Smckusick 			ch1 = *cp++;
2323570Smckusick 			continue;
2333570Smckusick 		}
2343570Smckusick 		word = cp;
235*9577Sgarrison 		while (isalnum(*cp))
2363570Smckusick 			cp++;
2373570Smckusick 		len = cp - word;
2383570Smckusick 		switch (*word) {
2393570Smckusick 		case 'b':
2403570Smckusick 			if (len == 5 && !strcmpn(word, "begin", 5)) {
2413570Smckusick 				if (nest == 0 && beginnest == 0) {
2423570Smckusick 					if (inprog != 1) {
2433570Smckusick 						fprintf(stderr,
2443570Smckusick 						    "improper program body");
2453570Smckusick 						quit(NULL);
2463570Smckusick 					}
2473570Smckusick 					curfile = files[BODYFILE];
2483570Smckusick 				} else {
2493570Smckusick 					beginnest++;
2503570Smckusick 				}
2513570Smckusick 			}
2523570Smckusick 			break;
2533570Smckusick 		case 'c':
2543570Smckusick 			if (len == 4 && !strcmpn(word, "case", 4)) {
2553570Smckusick 				if (beginnest > 0) {
2563570Smckusick 					beginnest++;
2573570Smckusick 				}
2583570Smckusick 				break;
2593570Smckusick 			}
2603570Smckusick 			if (len == 5 && !strcmpn(word, "const", 5)) {
2613570Smckusick 				if (nest == 0) {
2623570Smckusick 					prt = FALSE;
2633570Smckusick 					if (!constopen) {
2643570Smckusick 						constopen = TRUE;
2653570Smckusick 						prt = TRUE;
2663570Smckusick 					}
2673570Smckusick 					curfile = files[CONSTFILE];
2683570Smckusick 				}
2693570Smckusick 			}
2703570Smckusick 			break;
2713570Smckusick 		case 'e':
2723570Smckusick 			if (len == 3 && !strcmpn(word, "end", 3)) {
2733570Smckusick 				if (beginnest == 1) {
2743570Smckusick 					nest--;
2753570Smckusick 				}
2763570Smckusick 				if (beginnest > 0) {
2773570Smckusick 					beginnest--;
2783570Smckusick 				}
2793570Smckusick 				if (nest < 0) {
2803570Smckusick 					if (inprog == 1) {
2813570Smckusick 						inprog = 0;
2823570Smckusick 						nest = 0;
2833570Smckusick 					} else {
2843570Smckusick 						fprintf(stderr, "too many end statements");
2853570Smckusick 						quit(NULL);
2863570Smckusick 					}
2873570Smckusick 				}
2883570Smckusick 				break;
2893570Smckusick 			}
2903570Smckusick 			if (len == 8 && !strcmpn(word, "external", 8)) {
2913570Smckusick 				fputs("forward", curfile);
2923570Smckusick 				prt = FALSE;
293*9577Sgarrison 				if (paren_level == 0) {
294*9577Sgarrison 					nest--;
295*9577Sgarrison 				}
2963570Smckusick 			}
2973570Smckusick 			break;
2983570Smckusick 		case 'f':
2993570Smckusick 			if (len == 8 && !strcmpn(word, "function", 8)) {
3003570Smckusick 				if (nest == 0) {
3013570Smckusick 					curfile = files[RTNFILE];
3023570Smckusick 				}
303*9577Sgarrison 				if (paren_level == 0) {
304*9577Sgarrison 					nest++;
305*9577Sgarrison 				}
3063570Smckusick 				break;
3073570Smckusick 			}
3083570Smckusick 			if (len == 7 && !strcmpn(word, "forward", 7)) {
309*9577Sgarrison 				if (paren_level == 0) {
310*9577Sgarrison 					nest--;
311*9577Sgarrison 				}
3123570Smckusick 			}
3133570Smckusick 			break;
3143570Smckusick 		case 'l':
3153570Smckusick 			if (len == 5 && !strcmpn(word, "label", 5)) {
3163570Smckusick 				if (nest == 0) {
3173570Smckusick 					prt = FALSE;
3183570Smckusick 					if (!labelopen) {
3193570Smckusick 						labelopen = TRUE;
3203570Smckusick 						prt = TRUE;
3213570Smckusick 					}
3223570Smckusick 					curfile = files[LABELFILE];
3233570Smckusick 				}
3243570Smckusick 			}
3253570Smckusick 			break;
3263570Smckusick 		case 'p':
3273570Smckusick 			if (len == 9 && !strcmpn(word, "procedure", 9)) {
3283570Smckusick 				if (nest == 0) {
3293570Smckusick 					curfile = files[RTNFILE];
3303570Smckusick 				}
331*9577Sgarrison 				if (paren_level == 0) {
332*9577Sgarrison 					nest++;
333*9577Sgarrison 				}
3343570Smckusick 				break;
3353570Smckusick 			}
3363570Smckusick 			if (len == 7 && !strcmpn(word, "program", 7)) {
3373570Smckusick 				if (nest != 0) {
3383570Smckusick 					fprintf(stderr, "improper program nesting");
3393570Smckusick 					quit(NULL);
3403570Smckusick 				}
3413570Smckusick 				inprog = 1;
3423570Smckusick 				curfile = files[PRGFILE];
3433570Smckusick 			}
3443570Smckusick 			break;
3453570Smckusick 		case 't':
3463570Smckusick 			if (len == 4 && !strcmpn(word, "type", 4)) {
3473570Smckusick 				if (nest == 0) {
3483570Smckusick 					prt = FALSE;
3493570Smckusick 					if (!typeopen) {
3503570Smckusick 						typeopen = TRUE;
3513570Smckusick 						prt = TRUE;
3523570Smckusick 					}
3533570Smckusick 					curfile = files[TYPEFILE];
3543570Smckusick 				}
3553570Smckusick 			}
3563570Smckusick 			break;
3573570Smckusick 		case 'v':
3583570Smckusick 			if (len == 3 && !strcmpn(word, "var", 3)) {
3593570Smckusick 				if (nest == 0) {
3603570Smckusick 					prt = FALSE;
3613570Smckusick 					if (!varopen) {
3623570Smckusick 						varopen = TRUE;
3633570Smckusick 						prt = TRUE;
3643570Smckusick 					}
3653570Smckusick 					curfile = files[VARFILE];
3663570Smckusick 				}
3673570Smckusick 			}
3683570Smckusick 			break;
3693570Smckusick 		}
3703570Smckusick 		if (prt)
3713570Smckusick 			fprintf(curfile, "%.*s", len, word);
3723570Smckusick 		prt = TRUE;
3733570Smckusick 		ch1 = ' ';
3743570Smckusick 	}
3753570Smckusick }
3763570Smckusick 
3773570Smckusick /*
3783570Smckusick  * Print out the merged result
3793570Smckusick  */
3803570Smckusick printout()
3813570Smckusick {
3823570Smckusick 	FILE *fp;
3833570Smckusick 	int i;
3843570Smckusick 	char ch;
3853570Smckusick 
3863570Smckusick 	for(i = 0; i < NUMFILES; i++) {
3873570Smckusick 		fp = freopen(names[i], "r", files[i]);
3883570Smckusick 		if (fp == NULL)
3893570Smckusick 			quit(names[i]);
3903570Smckusick 		ch = getc(fp);
3913570Smckusick 		while (!feof(fp)) {
3923570Smckusick 			putc(ch,stdout);
3933570Smckusick 			ch = getc(fp);
3943570Smckusick 		}
3953570Smckusick 	}
3963570Smckusick }
3973570Smckusick 
3983570Smckusick /*
3993570Smckusick  * Die gracefully
4003570Smckusick  */
4013570Smckusick quit(fp)
4023570Smckusick 	char *fp;
4033570Smckusick {
4043570Smckusick 	if (fp != NULL)
4053570Smckusick 		perror(fp);
4063570Smckusick 	onintr();
4073570Smckusick 	exit(1);
4083570Smckusick }
409