/*% cc -s -O -i -K % -o com
 *
 *	created Tom Duff.
 *
 * com [ -ons ] file ...
 * looks for the sequence `/*%' in a file, and sends the rest of the
 * line off to the shell, after replacing any instances of a `%' character
 * with the filename. Com is mainly useful so that information about
 * how to compile programs can be stored with the program.
 *
 * #"# D. Tilbrook -- Aug 79.
 * added -o and -s flags.
 *	-o turns off echoing of command
 *	-s causes commands to be echoed to standard output
 *
 * #"# D. Tilbrook -- Jan 79.
 *	added -n.
 *	suppresses execution -- used to get commands only.
 *	added check of file's stat and magic number.
 *
 * #"# D. Tilbrook -- Mar 79.
 *	if "/*%" is followed by a `-' then command is not
 *	echoed unless `-n' or `-s' flags are specified.
 *
 * #"# C. Forsberg -- 10-6-80
 *	Modified to use stdio.  N.B.  Uses fork and stat
 */
#define	USAGE "com [ -ons ] file ... "
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

struct	stat inode;
FILE *cbuf;		/* hack mod to use stdio */
char	**files;
char	numfiles;
char	oflag=2;
char	nflag;
main(argc, argv) char *argv[]; 
{
	arginterp(argc, argv);
	do make(*files++); 
	while (--numfiles);
	exit(0);
}
arginterp(argc, argv) int argc; 
char **argv; 
{
	register char *p;
	for (--argc, argv++; **argv == '-'; argc--, argv++) {
		switch (argv[0][1]) {
		case 's':
		case 'o':
		case 'n':
			for (p = &argv[0][1]; *p; ) {
				switch (*p++) {
				case 'o':
					oflag = 0;
					continue;
				case 'n':
					nflag++;
					continue;
				case 's':
					oflag = 1;
					continue;
				default:
					usage("invalid flag", *argv);
				}
			}
			continue;
		default:
			usage("invalid option", *argv);
		}
	}
	if ((numfiles = argc) == 0)
		usage ("Arg count", 0);
	files = argv;
}
usage(m1, m2) char *m1, *m2; 
{
	fprintf(stderr, "%s %s\n%s\n",m1,m2,USAGE);
	exit(1);
}
make(file) char file[]; 
{
	int magic;
	char command[512];
	register char *s, *t;
	register c;
	int putcmmd;
	if ((cbuf=fopen(file, "r"))==NULL) {
		perror(file);
		exit(1);
	}
	if (fstat(fileno(cbuf), &inode) == -1) {
		fprintf(stderr, "%s: can't stat\n", file);
		fclose(cbuf);
	}
	if ((inode.st_mode & S_IFMT) != S_IFREG) {
		fprintf(stderr, "%s: not a file\n", file);
		fclose(cbuf);
		return;
	}
	fread(&magic, sizeof(magic), 1, cbuf);
	switch (magic) {
	case 0407: /* executable */
	case 0410: /* pure executable */
	case 0411: /* separate executable */
	case 043344: /* tips profile */
	case 043345: /* tips template object code */
	case 0145405: /* huffman encoded file */
	case 0177545: /* archive */
	case 0177555: /* old archive */
		fprintf(stderr, "%s: has a magic number 0%o\n", file, magic);
		fclose(cbuf);
		return;
	}
	fseek(cbuf, 0L, 0);
	c= getc(cbuf);
	while (c>=0) {
		if (c=='/') {
			if ((c=getc(cbuf))=='*' && (c=getc(cbuf))=='%') {
				putcmmd = oflag;
				if (peek(cbuf) == '-') {
					putcmmd = (nflag || oflag == 1) ? oflag : 0;
					getc(cbuf);
				}
				s=command;
				do;
				while ((c=getc(cbuf))==' ' || c=='\t');
				while (c>=0 && c!='\n') {
					if (c=='%') {
						t=file;
						while (*t)
							*s++ = *t++;
					}
					else
						*s++=c;
					c=getc(cbuf);
				}
				*s='\0';
				if (putcmmd) 
					fprintf(stdout,"%s: %s\n",file, command);
				if (nflag) {
					fclose(cbuf);
					return;
				}
				switch (fork()) {
				case -1:
					fprintf(stderr, "Try again later\n");
					exit(1);
				case 0:
					execl("/bin/sh", 
					"sh", "-c", command, 0);
					fprintf(stderr, "No shell!\n");
					exit(1);
				default:
					wait(0);
					fclose(cbuf);
					return;
				}
			}
		}
		else
			c=getc(cbuf);
	}
	fprintf(stderr, "%s: no command\n", file);
	fclose(cbuf);
	return;
}
peek(from)
register FILE *from;
{
	register char c;
	c = getc(from);
	ungetc(c, from);
	return(c);
}

