File:  [MW Coherent from dump] / coherent / d / bin / nroff / misc.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

/*
 * misc.c
 * Nroff/Troff.
 * Miscellaneous routines.
 */

#include "roff.h"
#include <access.h>
#include <ctype.h>
#include <string.h>

/*
 * Define a macro.
 * 'mp' is a pointer to a macro descriptor which is
 * filled in with the appropriate information and name is the name
 * of the macro upon which the definition ends.
 */
deftext(mp, name) register MAC *mp; char name[2];
{
	static char residue[4];
	register STR *sp;
	register char *bp;
	int nlflag;

	if (mp != NULL) {
		mp->t_div.m_next = NULL;
		mp->t_div.m_type = MTEXT;
		mp->t_div.m_core = NULL;
		mp->t_div.m_seek = tmpseek;
	}
#if	0
	/* Conditionalized out 4/11/91 by steve, seems wrong. */
	infalse = 1;
#endif
	bp = miscbuf;
	for (nlflag = 1;;) {

		/* nlflag indicates if last character was \n. */
		if (bp > miscbuf)
			nlflag = (*(bp-1) == '\n');

		/* Flush if necessary, leaving room for "..\n" or ".XX". */
		if (bp >= &miscbuf[MSCSIZE-3]) {
			if (mp != NULL)
				nwrite(miscbuf, 1, bp-miscbuf);
			bp = miscbuf;
		}

		/* Ignore remainder of line not starting with endmark. */
		if (!nlflag) {
			*bp++ = getf(2);
			continue;
		}

		/* Last character was \n, look for endmark on next line. */
		if (name[0]=='\0') {
			if ((*bp++ = getf(2))!='.' || escflag!=0)
				continue;
			if ((*bp++ = getf(2))!='.' || escflag!=0)
				continue;
			if ((*bp++ = getf(2)) != '\n')
				continue;
			bp -= 3;
			break;
		} else {
			if ((*bp++ = getf(2))!=ccc || escflag!=0)
				continue;
			if ((*bp++ = getf(2))!=name[0] || escflag!=0)
				continue;
			if ((*bp++ = getf(2))!=name[1] || escflag!=0)
				continue;
			bp -= 3;
			residue[0] = bp[0];
			residue[1] = bp[1];
			residue[2] = bp[2];
			residue[3] = '\0';
			sp = allstr(SCORE);
			sp->x3.s_cp = residue;
			sp->x3.s_srel = NULL;
			break;
		}
	}
	*bp++ = '\0';
	if (mp != NULL)
		nwrite(miscbuf, 1, bp-miscbuf);
#if	0
	/* Conditionalized out 4/11/91 by steve, as above. */
	infalse = 0;
#endif
}

/*
 * Define a special character.
 */
spc_def(name, value) char name[2]; char *value;
{
	register SPECIAL **spp;
	register int n;
	int len;
	SPECIAL *sp;
	char *cp;

	len = strlen(value) + 1;
	for (spp = &spc_list; *spp != NULL; spp = &((*spp)->spc_link)) {
		sp = *spp;
		n = strncmp(sp->spc_name, name, 2);
		if (n < 0)
			continue;		/* keep looking */
		else if (n > 0)
			break;			/* not found, add it */
		/* Gotcha, redefine it. */
		nfree(sp->spc_val);		/* free old value */
		sp->spc_val = nalloc(len);	/* allocate new space */
		strcpy(sp->spc_val, value);	/* and copy in value */
		return;
	}
	/* Add new entry. */
	sp = (SPECIAL *)nalloc(sizeof(*sp));	/* allocate new entry */
	cp = nalloc(len);			/* allocate new value space */
	sp->spc_link = *spp;			/* link into SPECIAL list */
	*spp = sp;
	sp->spc_name[0] = name[0];
	sp->spc_name[1] = name[1];
	sp->spc_val = cp;
	strcpy(cp, value);
}

/*
 * Find a special character entry in the special character list.
 * Print error message and return NULL if not found.
 */
SPECIAL *
spc_find(name) char name[2];
{
	register SPECIAL *sp;
	register int n;

	for (sp = spc_list; sp != NULL; sp = sp->spc_link) {
		n = strncmp(sp->spc_name, name, 2);
		if (n < 0)
			continue;
		else if (n > 0)
			break;
		else
			return sp;
	}
	printe("special character %c%c not found", name[0], name[1]);
	return NULL;
}

/*
 * Process requests from a library file if it exists.
 * The flag is 1 if file contains requests, 0 if binary data.
 * Return 1 if it exists, 0 if not.
 */
lib_file(s, flag) char *s; int flag;
{
	register char file[40];

	/* Look file, process it if found. */
	sprintf(file, "%s%s%s", LIBDIR,
		(ntroff == NROFF) ? NRDIR : (pflag) ? TPSDIR : TPCLDIR, s);
	if (access(file, AREAD) != 0)
		return 0;
	if (flag) {
		adsfile(file);
		process();
		return 1;
	}
	return copy_file(file);
}

/*
 * Copy a file verbatim.
 * Return 0 if not found or not readable, 1 on success.
 */
copy_file(s) char *s;
{
	register FILE *fp;
	register int c;

	if ((fp = fopen(s, "rb")) == NULL)
		return 0;
	while ((c = fgetc(fp)) != EOF)
		putchar(c);
	fclose(fp);
	return 1;
}

/*
 * Read a block into the buffer 'bp' starting at seek position
 * 'l' in the temp file.
 */
nread(l, bp)
long l;
char *bp;
{
	if (tmpseek-l <= DBFSIZE) {
		copystr(bp, diskbuf, DBFSIZE, 1);
		return;
	}
	lseek(fileno(tmp), (long) l, 0);
	if (read(fileno(tmp), bp, DBFSIZE) != DBFSIZE)
		panic("temporary file read error");
}

/*
 * Write the buffer 'bp' which contains 'n' elements of size 's'
 * onto the end of the temp file.
 */
nwrite(bp, s, n) register char *bp; unsigned s; register unsigned n;
{
	unsigned bno, off;
	register char *dp;

	bno = tmpseek / DBFSIZE;
	off = tmpseek % DBFSIZE;
	if (bno!=0 && off==0) {
		--bno;
		off += DBFSIZE;
	}
	dp = &diskbuf[off];
	s = n *= s;
	while (n--) {
		if (dp >= &diskbuf[DBFSIZE]) {
			lseek(fileno(tmp), (long) bno++*DBFSIZE, 0);
			if (write(fileno(tmp), diskbuf, DBFSIZE) != DBFSIZE)
				panic("temporary file write error");
			dp = &diskbuf[0];
		}
		*dp++ = *bp++;
	}
	tmpseek += s;
}

/*
 * Given a string, return a pointer to a copy of it.
 */
char *
duplstr(s) register char *s;
{
	return strcpy(nalloc(strlen(s) + 1), s);
}

/*
 * Copy the array of 'n' elements containing a structure of size
 * 'size' from 's2' to 's1'.
 */
copystr(s1, s2, size, n) char *s1, *s2; int size; register int n;
{
	if ((n *= size) == 0)
		return;
	memcpy(s1, s2, n);
}

/*
 * Allocate 'n' bytes.
 */
char	*
nalloc(n)
{
	extern char *calloc();
	register char *cp;

	if ((cp = calloc(n, 1)) == NULL)
#if	MSDOS
		panic("out of space");		/* no memok() in MS-DOS libc */
#else
		panic("out of space - memory %s", (memok() ? "good" : "bad"));
#endif
	return cp;
}

/*
 * Release the given storage.
 */
nfree(cp)
char *cp;
{
	free(cp);
}

/*
 * Execute conditional.
 * bp points to the remainder of the line.
 * Called from .el and .ie.
 */
do_cond(cond, bp) int cond; unsigned char *bp;
{
	unsigned char charbuf[CBFSIZE];
	register unsigned char *cp;
	unsigned char c;

	while (isascii(*bp) && isspace(*bp))
		bp++;				/* skip leading space */
	if (cond) {
		/* Execute true branch. */
		cp = charbuf;
		bracelevel = oldbracelevel;	/* restore original brace level */
		if (*bp == EBEG) {
			bp++;			/* ignore \{ */
			bracelevel++;
		}
		while (c = *bp++)
			if (cp < &charbuf[CBFSIZE-2])
				*cp++ = c;
		*cp++ = '\n';
		*cp = '\0';
		cp = duplstr(charbuf);
		adscore(cp);			/* execute remainder */
		strp->x3.s_srel = cp;
	} else {
		/* Skip false branch. */
		if (*bp != EBEG)
			return;			/* one-line conditional */
		for (; *bp; bp++) {
			if (*bp == EBEG)
				++infalse;
			else if (*bp == EEND)
				--infalse;
		}
		if (infalse == 0)
			return;			/* \{ ... \} on one line */
		while (infalse && (c = getf(0))) {
			if (c == EBEG)
				++infalse;
			else if (c == EEND)
				--infalse;	/* scan to matching \} */
		}
		while (getf(0) != '\n')
			;			/* then scan to newline */
	}
}

/*
 * Set a value, saving old value.
 * Called by various requests.
 */
setval(vp, op, arg, mul, div) int *vp, *op; char *arg; long mul, div;
{
	register int val;

	val = *vp;					/* save value */
	*vp = number(arg, mul, div, val, 0, *op);	/* set value */
	*op = val;					/* save old */
}

/*
 * Return the number of the named font.
 * Return -1 if not found.
 */
int
font_num(name) char name[2];
{
	register FTB *p;

	for (p = fontab; p < &fontab[NFNAMES]; p++) {
		if (p->f_name[0] == '\0')
			break;
		else if ((p->f_name[0] == name[0]) && (p->f_name[1] == name[1]))
			return p->f_font;
	}
	return -1;
}

/*
 * Return the number of the named font.
 * Print an error message and return -1 if not found.
 */
int
font_number(name, s) char name[2]; char *s;
{
	register int n;

	if ((n = font_num(name)) == -1)
		printe("%scannot find font %c%c", (s==NULL) ? "" : s, name[0], name[1]);
	return n;
}

/*
 * Assign a font number to a name.
 * If there is no font of the given name, add one.
 * Return the previously assigned font number, or -1 if none.
 */
int
assign_font(name, c) char *name; int c;
{
	char a, b;
	register FTB *p;

	a = name[0];
	b = name[1];
	for (p = fontab; p < &fontab[NFNAMES]; p++) {
		if ((p->f_name[0] == a) && (p->f_name[1] == b)) {

			/* Replace existing entry */
			a = p->f_font;
			p->f_font = c;

			/* Watch for current, tab, underline fonts. */
			if (a == curfont)
				dev_font(c);
			if (a == tfn)
				tfn = c;
			if (a == ufn)
				ufn = c;

			return a;
		} else if (p->f_name[0] == '\0') {
			/* Add new entry */
			p->f_name[0] = a;
			p->f_name[1] = b;
			p->f_font    = c;
			return -1;
		}
	}
	printe("no room for new font name %c%c", a, ((b) ? b : ' '));
	return -1;
}

/*
 * Given a font number, change font.
 */
setfontnum(n, setflag) register int n; int setflag;
{
	register FTB *p;

	for (p = fontab; p < &fontab[NFNAMES]; p++) {
		if (p->f_font == n) {
			setfont(p->f_name, setflag);
			return;
		} else if (p->f_name[0] == '\0')
			break;
	}
	printe("cannot find font %d", n);
}

/*
 * Given a font name, change font.
 * Understands \fP and \fn, saves previous font in oldfon.
 * Return the new font number, or -1 if not found.
 * dev_font() does the real work.
 */
int
setfont(name, setflag) char name[2]; int setflag;
{
	register int n;

	if ((name[0] >= '0') && (name[0] <= '9')) {
		n = name[0] - '0';
		name[0] = mapfont[n][0];
		name[1] = mapfont[n][1];
	}
	if (name[0]=='P' && name[1]=='\0') {
		name[0] = oldfon[0];
		name[1] = oldfon[1];
	}
	if ((n = font_number(name, NULL)) < 0) {
		if (setflag) {
			/*
			 * Bogus font change sets oldfon so \fP gets back
			 * from the bogus font to the present font.
			 * The bogus font change is really ignored.
			 */
			oldfon[0] = fon[0];
			oldfon[1] = fon[1];
		}
		return -1;
	}
	dev_font(n);
	if (setflag) {
		oldfon[0] = fon[0];
		oldfon[1] = fon[1];
		fon[0] = name[0];
		fon[1] = name[1];
	}
	return n;
}

/*
 * Print out a warning.
 */
/*VARARGS*/
printe(a1) char *a1;
{
	register STR *sp;

	fprintf(stderr, "%s: ", argv0);
	for (sp=strp; sp; sp=sp->x1.s_next) {
		if (sp->x1.s_type == SFILE) {
			fprintf(stderr, "%s: %d: ", sp->x2.s_fname, sp->x2.s_clnc);
			break;
		}
	}
	fprintf(stderr, "%r\n", &a1);
	if (dflag)
		fprintf(stderr, "Request: %s\n", miscbuf);
}

/*
 * Print an unimplemented warning.
 */
printu(s) char *s;
{
	printe("%s not implemented yet", s);
}

/*
 * An irrecoverable error was found.
 * Print out an error message and leave.
 */
/*VARARGS*/
panic(s)
{
	fprintf(stderr, "%s: %r\n", argv0, &s);
	leave(1);
}

/* Debug stuff follows, used to be in codebug.c. */

#if	(DDEBUG != 0)
#if	(DDEBUG & DBGCODE)

static char *codtab[] = {
	"DNULL",
	"DHMOV (move horizontal)",
	"DVMOV (move vertical)",
	"DFONT (change font)",
	"DPSZE (change pointsize)",
	"DSPAR (space down and return)",
	"DPADC (Paddable character)",
	"DHYPH (Place to hyphenate)",
	"DHYPC (Hyphen character)"
	};

codebug(code, parm1)
{
	if (code <= 0) {
		printd(DBGCODE, "%s %u\n", codtab[-code], parm1);
	} else {
		printd(DBGCODE, "%c (width=%d)\n", code, parm1);
	}
}
#endif

static char *dbgtbl[] = {
	"CHECKpoints",
	"REGisterS",
	"REGister eXecution",
	"output CODEs",
	"DIVeRsions",
	"FILEs",
	"FUNCtions",
	"CHARacters",
	"PROCess trace",
	"MACro eXecution",
	"MISCelaneous",
	"MOVEment",
	"ENViRonment",
	"CALL tracing"
};

printd(lvl, fmt)
int lvl;
char *fmt;
{
	if (lvl & dbglvl)
		fprintf(stderr, "%r", &fmt);
}

void dbginit()
{
	register int t=dbglvl;
	register int j;
	register int m=1;

	if (dbglvl == 0)
		return;
	for (j=0; j<15; j++) {
		if (t & m)
			fprintf(stderr, "debugging %s\n", dbgtbl[j]);
		m <<= 1;
	}
}
#endif

/* end of misc.c */

unix.superglobalmegacorp.com

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