File:  [MW Coherent from dump] / coherent / d / bin / nroff / main.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * main.c
 * Nroff/Troff.
 * Main program and initialization.
 */

#include <ctype.h>
#if	MSDOS
#include <types.h>
#include <stat.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include <time.h>
#include <path.h>
#include <string.h>
#include "roff.h"

extern	char	*getenv();
extern	char	*path();
extern	time_t	time();
#ifdef	GEMDOS
extern	char	*tempnam();
#else
extern	char	*mktemp();
#endif

#ifdef	GEMDOS
unsigned long _stksize = 0x8000L;
#endif

static	int	kflag;		/* keep tmp file for debug purposes	*/
static	char	template[sizeof(TMPLATE)+1] = TMPLATE;
static	char	*tempname;	/* temp file name			*/

main(argc, argv) int argc; char *argv[];
{
	register int i, fileflag, iflag;
	register char *libpath, *cp;
	register REG *rp;
	char c, name[2];

	argv0 = (ntroff == NROFF) ? "nroff" : "troff";
	cp = getenv((ntroff == NROFF) ? "NROFF" : "TROFF");
	if (cp != NULL && *cp != '\0')
		addargs(cp, &argc, &argv);
	initialize(argc, argv);

	/*
	 * Process specified input files.
	 * initialize() already handled most options.
	 */
	fileflag = iflag = 0;
	for (i = 1; i < argc; i++) {
		cp = argv[i];
		if (*cp != '-') {
			/* Process non-option argument. */
			fileflag = 1;
			if (adsfile(cp) != 0)
				process();
			continue;
		}

		/* Process '-'-option argument. */
		c = *++cp;			/* argv[i][1] */
		cp++;				/* &argv[i][2] */
		if (c == 'i')
			iflag = 1;		/* process stdin when done */
		else if (c == 'f')
			++i;			/* ignore tempfile arg */
		else if (c == 'm') {
			/* Process "-m" macro package argument. */
			sprintf(miscbuf, TMACFMT, cp);
			libpath = DEFLIBPATH;
			if ((libpath = path(libpath, miscbuf, AREAD)) != NULL)
				strcpy(miscbuf, libpath);
#if	(DDEBUG & DBGFILE)
			printd(DBGFILE, "tmac file = %s\n", miscbuf);
#endif
			adsfile(miscbuf);
			process();
		} else if (c == 'n') {
			/* Reset page number. */
			pno = atoi(cp);
			npn = pno + 1;
		} else if (c == 'r' && *cp != '\0') {
			/* Reset register value. */
			name[0] = *cp++;
			if (isdigit(*cp))
				name[1] = '\0';
			else
				name[1] = *cp++;
			rp = getnreg(name);
			rp->n_reg.r_nval = atoi(cp);
			if (rp == nrpnreg)		/* Page # register */
				npn = pno + 1;		/* Set next page # */
		}
	}
	if (fileflag == 0 || iflag != 0) {
		/* Process standard input. */
		adsunit(stdin);
		process();
	}
	if (iestackx != -1)
		printe(".ie without matching .el");
	leave(0);
}

/*
 * Open temp file, set up registers and general initialization.
 */
initialize(argc, argv) int argc; char *argv[];
{
	register REG *rp;
	register REQ *qp;
	register int i;
	int Dflag, tmparg;
	char *s;

	A_reg = ntroff==NROFF;

	/*
	 * Pass over args, process those dealing with global initialization.
	 * main() makes another pass over the arg list to process input files.
	 */
	Dflag = tmparg = 0;
	for (i = 1; i < argc; i++) {
		if (argv[i][0] != '-')
			continue;
		switch (argv[i][1]) {
		case 'a':
			A_reg = 1;
			continue;
		case 'd':
#if	DDEBUG
			if (argv[i][2] != '\0') {
				dbglvl = atoi(&argv[i][2]);
				dbginit();
			} else
#endif
				dflag++;
			continue;
		case 'D':
			Dflag = 1;
			continue;
		case 'f':
			if (i < (argc-1))
				tmparg = ++i;
			else
				panic("-f option requires file argument");
			continue;
		case 'i':
			continue;	/* handled in main() */
		case 'K':
		case 'k':
			kflag++;
			continue;
		case 'l':
			lflag = 1;
			continue;
		case 'm':
			continue;	/* handled in main() */
		case 'n':
			continue;	/* handled in main() */
		case 'p':
			pflag = 1;
			continue;
		case 'r':
			continue;	/* handled in main() */
#ifndef GEMDOS
		case 'T':
			if (ntroff == NROFF)
				T_reg = 1;
			continue;
#endif
		case 'x':
			xflag++;
			continue;
		case 'V':
		case 'v':
			fprintf(stderr, "%s: V%s\n", argv0, VERSION);
			continue;
#if	ZKLUDGE
		case 'Z':
			if (argv[i][2] != '\0')
				Zflag = atoi(&argv[i][2]);
			else
				Zflag = ZPAGES;
			continue;
#endif
		default:
			fprintf(stderr, "%s: illegal option: %s\n", argv0, argv[i]);
			/* fall through... */
		case '?':
			usage();
		}
	}

	/* Initialize tempfile. */
#ifdef	GEMDOS
	tempname = (tmparg) ? argv[tmparg] : tempnam(0L, "nroff");
#else
	tempname = (tmparg) ? argv[tmparg] : mktemp(template);
#endif
	dprint2(DBGFILE, "temp file name = %s\n", tempname);
	if ((tmp=fopen(tempname, "wb")) == NULL)
		panic("cannot create temp file");
	else if (freopen(tempname, "rwb", tmp) == NULL)
		panic("cannot reopen temp file");
	tmpseek = ENVSIZE * sizeof (ENV);
	tmpseek = (tmpseek+DBFSIZE+DBFSIZE-1) & ~(DBFSIZE-1);

#ifdef	GEMDOS
	/*
	 * GEMDOS lseek does not produce sparse files;
	 * this makes it necessary to write the beginning of nroff's work file.
	 */
	memset(diskbuf, '\0', DBFSIZE);
	for (i = 0; i < tmpseek; i += DBFSIZE) {
		dprintd(DBGFILE, "initializing tempfile\n");
		if (write(fileno(tmp), diskbuf, DBFSIZE) != DBFSIZE)
			panic("temp file write error");
	}
#endif
#ifdef	COHERENT
	/*
	 * Unlinking temp file immediately under COHERENT makes it
	 * go away if program is interrupted with <Ctrl-C>;
	 * under GEMDOS it would destroy the file immediately,
	 * so it is done under leave() below.
	 */
	if (kflag == 0)
		unlink(tempname);
#endif

	/* Copy .pre-file if it exists. */
	if (!Dflag) {
		s = (lflag) ? PRE_L : PRE_P;
		if (lib_file(s, 0) == 0 & ntroff == TROFF)
			printe("file \"%s\" not found", s);
	}
	
	/* Initialize globals. */
	dev_init();		/* output writer-specific initialization */
	for (i = 0; i < NWIDTH; i++)
		trantab[i] = i;				/* translation table */
	for (i = 0; i < RHTSIZE; i++)
		regt[i] = NULL;				/* request hash table */
	for (qp = reqtab; qp->q_name[0]; qp++) {	/* built-in requests */
		rp = makereg(qp->q_name, RTEXT);
		rp->t_reg.r_macd.r_div.m_next = NULL;
		rp->t_reg.r_macd.r_div.m_type = MREQS;
		rp->t_reg.r_macd.r_div.m_func = qp->q_func;
	}

	/* Create built in registers. */
	/* UNDONE: "c.", same as ".c" */
	nrpnreg = getnreg("%");
	nrctreg = getnreg("ct");
	nrdlreg = getnreg("dl");
	nrdnreg = getnreg("dn");
	nrdwreg = getnreg("dw");
	nrdyreg = getnreg("dy");
	nrhpreg = getnreg("hp");
	nrlnreg = getnreg("ln");
	nrmoreg = getnreg("mo");
	nrnlreg = getnreg("nl");
	nrsbreg = getnreg("sb");
	nrstreg = getnreg("st");
	nryrreg = getnreg("yr");
	setnreg();

	/* Environment initialization. */
	envset();
	envinit[0] = 1;

	/* Etc. */
	iestackx = -1;
	cdivp = NULL;
	newdivn("\0\0");
	mdivp = cdivp;
#ifdef	GEMDOS
	if (((long)mdivp) & 1L)
		panic("diversion buffer odd alignment");
#endif
	endtrap[0] = '\0';
	strp = NULL;
	pgl = (lflag) ? unit(17*SMINCH, 2*SDINCH) : unit(11*SMINCH, SDINCH);
	pno = 1;
	npn = 2;
	esc = '\\';

	/* Load default fonts for troff, initialize font numbers. */
	i = lib_file("fonts.r", 1);
	if (ntroff == TROFF && i == 0)
		panic("fonts.r not found");
	if (Dflag) {
		font_display();
		exit(0);
	}
	if (setfont("R", 1) == -1)
		leave(1);			/* font R is mandatory */
	tfn = curfont;				/* tab character font */
	if ((ufn = font_num("I")) == -1)	/* underline font number */
		ufn = curfont;

	/* Process special character definitions. */
	lib_file("specials.r", 1);		/* special characters */
#if	(DDEBUG & DBGCHEK)
	printd(DBGFUNC, "initialized...\n");
#endif
}

/*
 * Initialize pre-defined number registers.
 */
setnreg()
{
	time_t curtime;
	register struct tm *tmp;

	curtime = time((time_t *)0);
	tmp = localtime(&curtime);
	nryrreg->n_reg.r_nval = tmp->tm_year % 100;
	nrmoreg->n_reg.r_nval = tmp->tm_mon + 1;
	nrdyreg->n_reg.r_nval = tmp->tm_mday;
	nrdwreg->n_reg.r_nval = tmp->tm_wday + 1;
}

/*
 * Leave.
 * The passed exit status is:
 *	0	normal
 *	1	fatal error
 *	2	usage error
 */
leave(status) register int status;
{
	char name[2];
	static int depth = 0;

	if (status == 0 && depth++ == 0) {
		if (endtrap[0] != '\0') {
			name[0] = endtrap[0];
			name[1] = endtrap[1];
			endtrap[0] = '\0';
			execute(name);
		}
		setbreak();
		if (xflag == 0) {
			byeflag = 1;
			pspace();
		}
	} else if (status == 1 && depth++ == 0) {
		/* Space to bottom of page if status==1, useful for PS. */
		if (xflag == 0) {
			byeflag = 1;
			pspace();
		}
	}

#ifndef COHERENT
#if	(DDEBUG & DBGFILE)
	{
		struct stat statblk;

		fclose(tmp);			/* Close the temp file.	*/
		stat(tempname, &statblk);	/* so we can stat it.	*/
		printd(DBGFILE, "deleting temporary file %s, size = %ld\n",
			tempname, statblk.st_size);
	}
#endif
	/* Unlink temp file if not COHERENT. */
	if (kflag == 0)
		unlink(tempname);
#endif
	exit(status);
}

/*
 * Print a fatal usage message and die.
 */
usage()
{
	fprintf(stderr, "Usage: %s [ option ... ] [ file ... ]\n",
		ntroff == NROFF ? "nroff" : "troff");
	fprintf(stderr, "Options:\n");
	fprintf(stderr, "\t-d\tDebug: print each request before executing\n");
	if (ntroff == TROFF)
		fprintf(stderr, "\t-D\tDisplay available fonts\n");
	fprintf(stderr, "\t-f name\tWrite temporary file in file name\n");
	fprintf(stderr, "\t-i\tRead stdin after each file has been read\n");
	fprintf(stderr, "\t-k\tKeep temporary file\n");
	if (ntroff == TROFF)
		fprintf(stderr, "\t-l\tLandscape mode\n");
	fprintf(stderr, "\t-mname\tRead macro package /usr/lib/tmac.name\n");
	fprintf(stderr, "\t-nN\tNumber first page of output N (default, 1)\n");
	if (ntroff == TROFF)
		fprintf(stderr, "\t-p\tProduce PostScript output\n");
	fprintf(stderr, "\t-raN\tSet number register a to value N\n");
	fprintf(stderr, "\t-x\tDo not eject to bottom of final page\n");
	leave(2);
}

/*
 * cp contains space-separated environmental args to be added to argv.
 * Change argc/argv accordingly.
 */
addargs(cp, argcp, argvp) char *cp; int *argcp; char ***argvp;
{
	register int n;
	register char *s, **nargv, **np;

	for (s = cp, n = 1; *s != '\0'; s++)
		if (*s == ' ')
			++n;		/* number of added args */
	*argcp += n;			/* bump argc */
	np = nargv = (char **)nalloc((*argcp + 1) * sizeof (char *)); /* allocate */
	*np++ = *(*argvp)++;		/* copy old argv0 */
	for (s = cp; *s != '\0'; ) {
		*np++ = s;		/* store pointer to new arg */
		while (*s != '\0' && *s != ' ')
			s++;		/* scan to NUL or space */
		if (*s == ' ')
			*s++ = '\0';	/* NUL-terminate space-separated args */
	}
	while (**argvp != NULL)
		*np++ = *(*argvp)++;	/* copy old argv */
	*np = NULL;			/* NULL-terminate new argv */
	*argvp = nargv;			/* pass back new argv */
}

/* end of main.c */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.