#include	"ctype.h"
#include	"stdio.h"
#include	"sys/types.h"
#include	"sys/stat.h"
#include	"sys/dir.h"

extern int	errno;

struct	stat	nstat, pstat;

short sflg, cflg, pflg, ostdi, ostdo, pid, sig2;
char subsec;
char sec;

#define	SECPOS	3
char *man = "manx/xxxxxxxxxxxxxxxxxxx";
#define	NSECPOS	17
char *pman = "/usr4/mantext/manx/xxxxxxxxxxxxxxxxxxx";
char *tfname = "/usr4/mantext/mtmpXXXXXX";
char	lbuf[512];
char	nbuf[64];
FILE *ifp;
int	stop();

char *dcheck[] = {
	"/usr/man/u_man",
	"/usr/man/a_man",
	0
};
main(c, v)
char **v;
{
	register char *s, *f;
	register char **p;

	ostdi = dup(0);
	ostdo = dup(1);
	sig2 = signal(2, 1);
	signal(3, 1);
	if(sig2 != 1)
		signal(2, sig2);

	while(--c){
		v++;
		if(**v != '-'){
			v--;
			c++;
			break;
		}
		switch(*++(*v)){
	case 's':
		sflg++;
		break;

	case 'c':
		cflg++;
		break;

	default:
usage:
		fprintf(stderr, "Usage: man [-c] [-s] [section] title [title ...]\n");
		exit(1);
		break;
		}
	}
	if(c < 2)
		goto usage;

	s = nbuf;
	while(--c){
		strcpy(s, *++v);
		if(isdigit(*s)){
			sec = *s;
			subsec = s[1];
			continue;
		}
		if(strchr(s, '.') || strchr(s, '/'))
			goto usage;
		f = NULL;
		for(p = dcheck; *p && f == NULL; p++){
			if(chdir(*p))continue;
			if(sec)
				f = makename(sec, subsec, s);
			else	f = findname(s);
		}

		if(f == NULL){
			fprintf(stderr, "man: Can't find '%s' in ", s);
			if(sec){
				fprintf(stderr, "section %c", sec);
				if(subsec)
					fprintf(stderr, "%c", subsec);
				fprintf(stderr, " of ");
			}
			fprintf(stderr, "the manual.\n");
			continue;
		}
		doman();
	}
	exit(0);
}

makename(c, sc, f)
char c;
char sc;
char *f;
{
	register char *t, *p;

	if(strlen(f) > 12)
		f[12] = 0;
	t = &man[SECPOS];
	*t++ = c;
	*t = 0;
	if(lookup(c, sc, man, f))
		return(0);
	*t = '/';
	p = f;
	while(*++t = *p++);
	if(stat(man, &nstat))
		return(0);
	t = &pman[NSECPOS];
	*t++ = c;
	p = f;
	while(*++t = *p++);
	if((pflg = stat(pman, &pstat)) == 0)
		pflg = (pstat.st_mtime < nstat.st_mtime);
	return(man);
}

findname(f)
char *f;
{
	register char c, *s, *t;

	s = f;
	for(c = '1'; c <= '8'; c++)
		if((t = makename(c, 0, s)) != NULL)
			return(t);
	return(NULL);
}

doman()
{
	register char *p;
	char seensyn;
	register FILE *ofp;
	short pv[2];

	ofp = NULL;
	seensyn = 0;
	pid = 0;
	if(pflg){
		close(0);
		close(1);
		if(pipe(pv)){
			fprintf(stderr, "man: Pipe create error for nroff\n");
			exit(1);
		}
		if((pid = fork()) == -1){
			fprintf(stderr, "man: Can't fork -- Error %d\n", errno);
			exit(errno);
		}
		if(pid == 0){
			close(0);
			dup(ostdi);
			execlp("nroff", "nroff", "-man", man, 0);
			fprintf(stderr, "man: Can't execute nroff\n");
			exit(-1);
		}
		close(1);
		dup(ostdo);
		if((ifp = fdopen(0, "r")) == NULL){
			fprintf(stderr, "man: Can't open stdin as pipe\n");
			exit(-2);
		}
		if(!sflg){
			mktemp(tfname);
			if(sig2 != 1)
				signal(2, stop);
			unlink(tfname);
			close(creat(tfname, 0644));
			chmod(tfname, 0644);
			chown(tfname, 9, 3);
			ofp = fopen(tfname, "w");
		}
	} else
		if((ifp = fopen(pman, "r")) == NULL){
			fprintf(stderr, "man: Can't open quick file: %s\n", pman);
			exit(-3);
		}
	while(fgets(lbuf, 511, ifp)){
		if(ofp)
			fprintf(ofp, "%s", lbuf);
		if(cflg && strip(lbuf) == 0)
			continue;
		if(sflg){
			strip (lbuf);
			if(seensyn == 0){
				if((p = strchr(lbuf, 'S')) == NULL)
					continue;
				if(strncmp(p, "SYNOPSIS", 8) == 0)
					seensyn++;
				continue;
			} else
				if((p = strchr(lbuf, 'D')) != NULL &&
					strncmp(p, "DESCRIPTION", 11) == 0)
						break;
		}
		fprintf(stdout, "%s", lbuf);
	}
	signal(2, 1);
	fclose(ifp);
	if(pflg && pid > 0)
		kill(pid, 13);
	if(ofp){
		fclose(ofp);
		unlink(pman);
		link(tfname, pman);
		unlink(tfname);
	}
	signal(2, sig2);
	fflush(stdout);
	if(pflg){
		while(wait(0) != -1);
		dup(ostdi);
	}
	return(0);
}

stop()
{
	fclose(ifp);
	if(pid > 0)
		kill(pid, 13);
	unlink(tfname);
	signal(2, sig2);
	while(wait(0) != -1);
	exit(4);
}


strip(b)
register char *b;
{
	register char *s, *t;

	for(s = b; *s == ' ' || *s == '\t'; s++);
	if(*s == '\n')
		return(0);
	while(*s)s++;
	s -= 2;
	while(s > b && (*s == ' ' || *s == '\t'))s--;
	*++s = '\n';
	*++s = 0;
	b++;
	while((s = strchr(b, '\b')) != NULL){
		if(s[-1] == '_' || s[-1] == s[1]){
			t = s-1;
			b = t;
			while(*t++ = *++s);
		}
		else	b = s+1;
	}
	return(1);
}

lookup(c, sc, dir, name)
char c;
char sc;
char *dir;
register char *name;
{
	short fd, r;
	char dbuf[512];
	register struct direct *pd, *pl;
	short n;

	if((fd = open(dir, 0)) == -1)
		return(1);
	n = strlen(name);
	while((r = read(fd, dbuf, 512)) > 0)
		for(pd = dbuf, pl = &dbuf[r]; pd < pl; pd++){
			if(pd->d_ino == 0 ||
				strncmp(pd->d_name, name, n))
					continue;
			if(pd->d_name[n] != '.' ||
				pd->d_name[n+1] != c ||
				(sc && pd->d_name[n+2] != sc))
					continue;
			name += n;
			*name++ = '.';
			*name++ = c;
			*name++ = pd->d_name[n+2]; /* [gmul] */
			*name = 0;
			close(fd);
			return(0);
		}
	close(fd);
	return(1);
}
