Nroff and SCO Unix

Ronald S H Khoo ronald at robobar.co.uk
Thu Jun 20 06:18:09 AEST 1991


Michael John Staley <staley at lad.med.utas.edu.au> wrote:

> the Text Processing package was the 'thing' for me
> the product is Xenix based.
> Neverthless I was assured that the product did indeed work on a SCO
> Unix platform

It does indeed.  Installing it was a pain, but SCO knows about that one :-)

> I found that the its use was VERY limited in that I could
> not do things like eqn, tbl etc.

I have used the eqn and tbl from the XENIX text processing system under
SCO UNIX with reasonably good results, using psroff 2.0.
Can you explain just why you can't use tbl and eqn?  I can.

> I experienced all sorts of nasty things such as
> ...core dumped... messages when it was used to man my man.LOCAL things.

This is likely due to a bug in the SCO manual page "rmb" program.  Under SCO
XENIX this is is somewhere like /usr/man/bin, under SCO UNIX it's in
/usr/bin.  I rewrote a slightly "improved" (heh) version of rmb, which
I append to the end of this message.  Please tell me if this cures
your problem.  SCO's rmb dumps core if you give it lines with the
nroff underlining and boldfacing overstrike with ^H trick.  Probably
gets with a fixed buffer or something like that. tut tut :-)

> My problems have increased recently as I have imported psroff 3.0 which
> requires a GOOD version of nsroff.

Actually PSROFF wants troff.  The SCO troff is "good enough".
It's a bit buggy, but not seriously so -- I used it for several years,
first with the "thack" postscript driver, then psroff 1.0, then psroff 2.0.
I'm still waiting for Rich Salz to post 3.0... :-)

> Where can I obtain a good version
> of nroff which has all the bits and which will run with SCO Unix and
> my new psroff 3.0.

Well, you can drop the SCO troff and psroff completely, and get GNU troff
instead (you will want to retain the ms and mm macro packages from
the text processing system -- /usr/lib/tmac and /usr/lib/macros)
You can FTP the Xenix binaries which I compiled from unix.secs.oakland.edu.
Yes, I use them regularly on SCO Unix.  (Actually I now use a slightly
newer version, but I did use the old one for months)

You will still need the documentation from the SCO text processing system.

The other thing to do is to get as many SCO customers as you can to
lobby them to license and resell DWB 3.2 which is the latest
version of commercial troff from AT&T.  In fact, AT&T do sell
binaries for System V/386, which should work on SCO Unix, (has anyone
tried?  Please do post !) but no one's going to support your using that
under SCO, so LOBBY SCO.

Anyway, here's my rmb.c.  It's *different* from SCO's, but you should be
able to drop it in.  Heh.

/*
 * rmb -- removes extra blank lines for displaying manual pages online.
 * also removes the page headers and footers in the middle of the manual.
 * a replacement for the one which comes with SCO's manual page package
 * because that one dumps core.   This one also accepts filename args.
 */

static char rcsid[] = "@(#) $Header: /home/ronald/rmb.c,v 1.2 1991/05/10 20:28:16 ronald Exp $";
static char authorinfo[] = "@(#) Ronald Khoo <ronald at ibmpcug.co.uk>";

#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char *prog;
/* No, I don't cope with arbitrarily long input.  The first version of
   this program did, but it spent too much time in malloc/free, so here's
   a few fixed buffers instead.  I know it can be done properly, but it's not
   worth it. */
#define MAXLEN 4096
char line1[MAXLEN], line2[MAXLEN], nukeline[MAXLEN];

/* buffer a line for output, with ability to undo the outputting of
   previous line if handed a NULL.  Always returns an available buffer
   to use, unless there was an output error in which case NULL is returned.
   The argument may only be line1, line2 or NULL.
*/

int before, after, gotone;
#define CLRET(x) { gotone = before = after = 0; return (x); }
	char *
outputline(s)
	char *s;
{
	char *other;

	if (s == 0) 
		{ gotone = after = 0; before = 1; return line1; }

	if (s == line1)
		other = line2;
	else if (s == line2)
		other = line1;
	else
		CLRET(line1)

	if (*s == '\n') {
		after++;
		return;
	}
	if (gotone) {
		for (; before; before--)
			if (putchar('\n') != '\n')
				CLRET(0)
		if (fputs(other, stdout) == EOF)
			CLRET(0)
		before = after; after = 0;
	}
	gotone = 1;
	return other;
}

/* copy t to s, deleting .^H nroff bullshit */
	void
nukebscpy(s, t)
	register char *s, *t;
{
	register char c;
	while (*t && *t == '\b')
		t++;
	while (c = (*s++ = *t++))
		if (c == '\b')
			*(s-=2) = 0;
}

/* return true if s matches foo(n).*foo(n) like manual pages do. */
	int /* boolean */
isheader(s)
	char *s;
{
	int len, found;
	char *p, *q;

	nukebscpy(nukeline, s);
	s = nukeline;
	while (*s && isspace(*s))
		s++;
	if ((p = strchr(s, ')')) == 0 || p[1] == 0)
		return 0;
	found = 0;
	for (q = s; q < p; q++) {
		if (isspace(*q))
			return 0;
		if (*q == '(')
			found = 1;
	}
	if (found == 0)
		return 0;
	/* s -> head of title, p -> ending ')' */
	len = p - s + 1;
	if ((q = strrchr(p+1, ')')) == 0)
		return 0;
	if (q - p < len)
		return 0;
	/* second copy of the header must be at the end of the line */
	if (q[1] != '\n')
		return 0;
	if (strncmp(s, q + 1 - len, len) == 0) {
		return 1;
	}
	return 0;
}

#define MAXBLANKS 1
	void
rmb(fp)
	FILE *fp;
{
	register char *strend;
	int blanks = MAXBLANKS; /* delete blanks at the top too */
	int donehdr = 0;
	char *s = line1;

	while (fgets(s, MAXLEN, fp)) {
		if (strend = strchr(s, '\n')) {
			while (strend > s && isspace(*--strend)) {
					strend[0] = '\n';
					strend[1] = 0;
				}
		}
		if (blanks == MAXBLANKS) {
			if (isheader(s)) {
				if (donehdr) {
					if ((s = outputline((char *)0)) == 0) {
			fprintf(stderr, "%s: write error on output\n", prog);
						s = line1;
					}
					continue;
				}
				donehdr = 1;
			}
		}
		if (*s == '\n') {
			if (blanks == MAXBLANKS) {
				continue;
			} else
				blanks++;
		} else
			blanks = 0;

		donehdr = 1; /* pretend we've already seen a header because
				SCO Unix manuals seem to delete the first
				header sometimes.  Sigh */
		if ((s = outputline(s)) == 0) {
			fprintf(stderr, "%s: write error on output\n", prog);
			s = line1;
		}
	}
	*s = 0;
	if (outputline(s) == 0)
		fprintf(stderr, "%s: write error on output\n", prog);
}

	int
main(argc, argv)
	int argc;
	char **argv;
{
	FILE *fp;

	prog = argc > 0? argv[0]: "rmb";
	if (argc < 2)
		rmb(stdin);
	else {
		if ((fp = fopen(*++argv, "r")) == 0) {
			fprintf(stderr, "%s: cannot open %s\n", prog,
				*argv);
		} else {
			rmb(fp);
			if (fclose(fp) == EOF) {
			fprintf(stderr, "%s: %s: error on fclose\n", prog,
				*argv);
			}
		}
	}
}

-- 
Ronald Khoo <ronald at robobar.co.uk> +44 81 991 1142 (O) +44 71 229 7741 (H)



More information about the Comp.unix.sysv386 mailing list