/*
**	MPP -- Music PreProcessor
**	psl 8/88
*/
#include	<midi.h>
#include	<stdio.h>

#define	MAXRPT	8		/* how deep repeats can nest */
struct	rptstr	{
	int	num;		/* number of repeats total */
	int	rpt;		/* number of current repeat */
	int	wrongr;		/* is current repeat being output? */
	long	addr;		/* where (in file) repeat starts */
} Rpts[MAXRPT];
int	Rdepth	= 0;		/* how many repeats are stacked up */

main(argc, argv)
char	*argv[];
{
	char *infile = (char *) 0, *cp, buf[1024], ifbuf[32];
	int fsect, lsect, i, fh, cflg;
	FILE *ifp;

	cflg = 0;			/* ignore comments (default) */
	infile = (char *) 0;
	for (i = 1; i < argc; i++) {
	    if (argv[i][0] == '-') {
		switch (argv[i][1]) {
		case 'c':		/* don't strip comments */
		    cflg++;
		    break;
		case 's':		/* specify which section(s) */
		    break;		/* (processed later) */
		default:
		    goto syntax;
		}
	    } else if (infile == (char *) 0)
		infile = argv[i];
	    else
		goto syntax;
	}
	if (!infile) {
	    sprintf(infile = ifbuf, "/tmp/mpp%d", getpid());
	    if ((fh = creat(infile, 0644)) < 0) {
		perror(infile);
		exit(1);
	    }
	    while ((i = read(0, buf, sizeof buf)) > 0)
		write(fh, buf, i);
	    close(fh);
	}
	if (!(ifp = fopen(infile, "r"))) {
	    perror(infile);
syntax:
	    fprintf(stderr, "Usage: %s [-c] [-s#] [file or stdin]\n",
	     argv[0]);
	    fprintf(stderr, "   or: %s [-c] -s### file\n", argv[0]);
	    fprintf(stderr, "where # is a single section number");
	    fprintf(stderr, " and ### is a list of section numbers\n");
	    fprintf(stderr, "using ',' to separate numbers");
	    fprintf(stderr, " and '-' for ranges; e.g. -s1,4-6,1\n");
	    exit(2);
	}
	fsect = lsect = -1;
	for (i = 1; i < argc; i++) {
	    if (argv[i][0] != '-' || argv[i][1] != 's')
		continue;
	    for (cp = &argv[i][2]; *cp; ) {
		fsect = lsect = atoi(cp);
		for (; *cp && *cp != ',' && *cp != '-'; cp++);
		if (*cp == '-') {
		    lsect = atoi(++cp);
		    for (; *cp && *cp != ','; cp++);
		}
		if (*cp == ',')
		    cp++;
		else
		    *cp = '\0';
		for (i = fsect; i <= lsect; i++) {
		    fseek(ifp, 0L, 0);
		    proc(ifp, i, cflg);
		}
	    }
	}
	if (fsect == -1)	/* no sections specified */
	    proc(ifp, 1, cflg);
	if (infile == ifbuf)	/* temp file created */
	    unlink(infile);
	exit(0);
}

proc(ifp, sect, cflg)
FILE	*ifp;
{
	char buf[512], a[16][128];
	int skip, wrongs, i, nf, nr;
	FILE *iifp;
	extern long ftell();

	skip = wrongs = 0;
	for (nr = 1; fgets(buf, sizeof buf, ifp) != NULL; nr++) {
	    nf = sscanf(buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
	     a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
	     a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
	    if (nf <= 0 || strcmp(a[0], "#") == 0) {
		if (cflg)
		    fputs(buf, stdout);
		continue;
	    }
	    for (i = 16; --i >= nf; a[i][0] = '\0');
	    if (a[0][0] == '#') {
		if (skip && strcmp(a[0], "#ENDSKIP") != 0)
		    continue;
		if (strcmp(a[0], "#ALLSECTS") == 0) {
		    wrongs = 0;
		    continue;
		}
		if (strcmp(a[0], "#NOTSECT") == 0) {
		    wrongs = 0;
		    for (i = 1; i < nf; i++)
			if (atoi(a[i]) == sect)
			    wrongs = 1;
		    continue;
		}
		if (strcmp(a[0], "#ONLYSECT") == 0) {
		    wrongs = 1;
		    for (i = 1; i < nf; i++)
			if (atoi(a[i]) == sect)
			    wrongs = 0;
		    continue;
		}
		if (wrongs)
		    continue;
		if (strcmp(a[0], "#ENDSKIP") == 0) {
		    skip = 0;
		    continue;
		}
		if (strcmp(a[0], "#SECT") == 0) {
		    sect = atoi(a[1]);
		    continue;
		}
		if (strcmp(a[0], "#SKIP") == 0) {
		    skip++;
		    continue;
		}
		if (strcmp(a[0], "#INCLUDE") == 0) {
		    if (!(iifp = fopen(a[1], "r")))
			perror(a[1]);
		    else {
			proc(iifp, sect, cflg);
			fclose(iifp);
		    }
		    continue;
		}
		if (strcmp(a[0], "#REPEAT") == 0) {
		    if (Rdepth >= MAXRPT) {
			fprintf(stderr, "Max repeat nesting depth is %d\n",
			 MAXRPT);
			exit(1);
		    }
		    Rpts[Rdepth].num = atoi(a[1]);
		    Rpts[Rdepth].rpt = 1;
		    Rpts[Rdepth].wrongr = 0;
		    Rpts[Rdepth++].addr = ftell(ifp);
		    continue;
		}
		if (strcmp(a[0], "#ALLRPTS") == 0) {
		    if (Rdepth > 0)
			Rpts[Rdepth - 1].wrongr = 0;
		    continue;
		}
		if (strcmp(a[0], "#NOTRPT") == 0) {
		    if (Rdepth > 0) {
			Rpts[Rdepth - 1].wrongr = 0;
			for (i = 1; i < nf; i++)
			    if (atoi(a[i]) == Rpts[Rdepth - 1].rpt)
				Rpts[Rdepth - 1].wrongr = 1;
		    }
		    continue;
		}
		if (strcmp(a[0], "#ONLYRPT") == 0) {
		    if (Rdepth > 0) {
			Rpts[Rdepth - 1].wrongr = 1;
			for (i = 1; i < nf; i++)
			    if (atoi(a[i]) == Rpts[Rdepth - 1].rpt)
				Rpts[Rdepth - 1].wrongr = 0;
		    }
		    continue;
		}
		if (strcmp(a[0], "#ENDRPT") == 0) {
		    if (Rdepth > 0) {
			Rpts[Rdepth - 1].wrongr = 0;
			if (Rpts[Rdepth - 1].rpt++ < Rpts[Rdepth - 1].num)
			    fseek(ifp, Rpts[Rdepth - 1].addr, 0);
			else
			    --Rdepth;
		    }
		    continue;
		}
	    }
	    if (!skip && !wrongs && !wrongrpt())
		fputs(buf, stdout);
	}
	if (Rdepth == 1)
	    fprintf(stderr, "Unterminated repeat\n");
	else if (Rdepth > 0)
	    fprintf(stderr, "Unterminated repeats (%d)\n", Rdepth);
}

wrongrpt()
{
	register int i = Rdepth;

	while (--i >= 0)
	    if (Rpts[i].wrongr)
		return(1);
	return(0);
}
