Article View: comp.text
Article #2445Re: Is there a tbl checker?
From: Bill "Bill" Tuthill
Date: Thu, 31 Jan 1991 00:41
Date: Thu, 31 Jan 1991 00:41
222 lines
5595 bytes
5595 bytes
mcbride@rust.zso.dec.com (Melinda McBride) writes:
> I know that DWB has eqncheck, but does anybody know of a tbl check?
Here's something I wrote years ago. We don't use troff any more at Sun,
so this program has no commercial value to my company. It checks many
common mistakes, but is a bit Prussian about upper/lower case letters,
mostly to make tbl source easier to read. Good luck!
----------------------- cut here -----------------------
#include <stdio.h> /* checkts.c */
#include <ctype.h>
#define isfmtltr(f) \
(f=='l'||f=='r'||f=='c'||f=='n'||f=='a'||f=='s'||f=='^'||f=='_'||f=='=')
#define isfmtarg(a) \
(a=='|'||a=='t'||a=='f'||a=='I'||a=='B'||a=='L'||a=='p'||a=='+'||a=='-'||\
a=='v'||a=='w'||a=='('||a=='i'||a==')'||a=='e'||a==' '||a=='.'||isdigit(a))
long lno = 1; /* current line number of input file */
main(argc, argv) /* check validity of tbl input files */
int argc;
char *argv[];
{
FILE *fp, *fopen();
char s[BUFSIZ];
int i;
if (argc == 1) { /* no filenames given */
while (fgets(s, BUFSIZ, stdin)) {
checkts(s);
lno++;
}
exit(0);
}
for (i = 1; i < argc; i++) {
if ((fp = fopen(argv[i],"r")) == NULL) {
fprintf(stderr, "checkts: ");
perror(argv[i]);
continue;
}
printf("%s:\n", argv[i]);
while (fgets(s, BUFSIZ, fp)) {
checkts(s);
lno++;
}
fclose(fp);
lno = 1;
}
exit(0);
}
int n_txtblks = 0; /* total number of text blocks in file */
checkts(s) /* read a line at a time, checking syntax */
char *s;
{
static int fields = 0, prevfld;
static char check = 0, period;
static char justTS, tab, txtblk = 0;
char msg[64], lastchar(), *sprintf();
int n;
if (strncmp(s, ".TS", 3) == 0) {
check = 2;
period = 0;
prevfld = 0;
justTS = 1;
tab = '\t';
return;
}
if (strncmp(s, ".T&", 3) == 0) {
check = 2;
period = 0;
prevfld = 0;
return;
}
if (strncmp(s, ".TE", 3) == 0) {
check = 0;
if (txtblk)
error("unmatched T{ - missing T} above");
if (!period)
error("NO PERIOD at end of format specification!!");
n_txtblks = 0;
return;
}
if (strncmp(s, ".TH", 3) == 0)
return;
if (check == 1) { /* check data fields */
if ((n = count(tab, s)) >= fields) {
sprintf(msg, "more than %d fields of data (%d)",
fields, n+1);
error(msg);
}
if ((n = strfind("T}", s)) >= 0) {
if (!txtblk)
error("unmatched T} - missing T{ above");
if (n != 0)
error("T} must be at beginning of line");
if (s[n+2] != '\n' && s[n+2] != tab)
error("T} must be followed by tab");
txtblk = 0;
}
if ((n = strfind("T{", s)) >= 0) {
if (txtblk)
error("unmatched T{ - missing T} above");
if (++n_txtblks > 80)
error("too many text blocks - limit is 80");
if (s[n+2] != '\n')
error("T{ must be at end of line");
if (n > 0 && s[n-1] != tab)
error("T{ must be preceded by tab");
txtblk = 1;
}
if (strlen(s) > 132)
error("line probably too long");
}
if (check == 2) { /* check format specs */
if (lastchar(s) == ';')
rd_options(s, &tab, justTS);
else {
fields = rd_format(s);
if (!prevfld)
prevfld = fields;
else if (fields != prevfld)
error("unequal number of columns in format");
if (fields > 20)
error("too many columns - limit about 20");
if (lastchar(s) == '.') {
check = 1;
period = 1;
}
}
}
justTS = 0;
return;
}
rd_options(s, tab, justTS) /* read tbl option specifications */
char s[], *tab, justTS;
{
int i;
if (!justTS)
error("option specifications must follow .TS line");
if (strfind("center", s) >= 0 && strfind("expand", s) >= 0)
error("center and expand are incompatible options");
if ((i = strfind("tab(", s)) >= 0) {
*tab = s[i+4];
if (*tab == '#')
error("dangerous to use # as tab character");
}
else if ((i = strfind("tab (", s)) >= 0) {
*tab = s[i+5];
if (*tab == '#')
error("dangerous to use # as tab character");
}
}
rd_format(s) /* read tbl format specifications */
char *s;
{
int flds = 0;
char msg[64];
for (; *s != '\n'; s++) {
if (isfmtltr(*s))
flds++;
else if (isfmtarg(*s))
;
else {
sprintf(msg, "illegal character in format (%c)", *s);
error(msg);
}
}
return(flds);
}
count(c, s) /* count instances of char c in string s */
char c, *s;
{
int n = 0;
for (; *s != '\n'; s++)
if (*s == c)
n++;
return(n);
}
char
lastchar(str) /* return last non-blank character in str */
char *str;
{
int n;
n = strlen(str);
while (n && !isspace(str[--n]))
;
return(str[n-1]);
}
strfind(pat, str) /* return position of pattern in string */
char pat[], str[];
{
register int i, j, k;
for (i = 0; str[i]; i++) {
for (j = i, k = 0; pat[k] && str[j] == pat[k]; j++, k++)
;
if (pat[k] == NULL)
return(i);
}
return(-1);
}
error(str) /* print linenumber and error message string */
char *str;
{
printf("\t%ld: %s\n", lno, str);
fflush(stdout);
}
Technical Details
Message-ID:
<7034@exodus.Eng.Sun.COM>Path:
arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!bonnie.concordia.ca!thunder.mcrcim.mcgill.edu!snorkelwacker.mit.edu!think.com!samsung!sdd.hp.com!elroy.jpl.nasa.gov!lll-winken!sun-barr!newstop!exodus!cairo.Eng.Sun.COM!tutReferences:
<1393@rust.zso.dec.com>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!bonnie.concordia.ca!thunder.mcrcim.mcgill.edu!snorkelwacker.mit.edu!think.com!samsung!sdd.hp.com!elroy.jpl.nasa.gov!lll-winken!sun-barr!newstop!exodus!cairo.Eng.Sun.COM!tut From: tut@cairo.Eng.Sun.COM (Bill "Bill" Tuthill) Newsgroups: comp.text Subject: Re: Is there a tbl checker? Keywords: tbl troff Message-ID: <7034@exodus.Eng.Sun.COM> Date: 31 Jan 91 00:41:16 GMT References: <1393@rust.zso.dec.com> Sender: news@exodus.Eng.Sun.COM Lines: 222