614 lines
13 KiB
C
614 lines
13 KiB
C
/*
|
|
* pass3.c - cawf(1) pass 3 function
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 1991 Purdue University Research Foundation,
|
|
* West Lafayette, Indiana 47907. All rights reserved.
|
|
*
|
|
* Written by Victor A. Abell <abe@mace.cc.purdue.edu>, Purdue
|
|
* University Computing Center. Not derived from licensed software;
|
|
* derived from awf(1) by Henry Spencer of the University of Toronto.
|
|
*
|
|
* Permission is granted to anyone to use this software for any
|
|
* purpose on any computer system, and to alter it and redistribute
|
|
* it freely, subject to the following restrictions:
|
|
*
|
|
* 1. The author is not responsible for any consequences of use of
|
|
* this software, even if they arise from flaws in it.
|
|
*
|
|
* 2. The origin of this software must not be misrepresented, either
|
|
* by explicit claim or by omission. Credits must appear in the
|
|
* documentation.
|
|
*
|
|
* 3. Altered versions must be plainly marked as such, and must not
|
|
* be misrepresented as being the original software. Credits must
|
|
* appear in the documentation.
|
|
*
|
|
* 4. This notice may not be removed or altered.
|
|
*/
|
|
|
|
#include "cawf.h"
|
|
|
|
void
|
|
Pass3(len, word, sarg, narg)
|
|
int len; /* length (negative is special) */
|
|
unsigned char *word; /* word */
|
|
unsigned char *sarg; /* string argument */
|
|
int narg; /* numeric argument */
|
|
{
|
|
int addto; /* spaces to add to all words */
|
|
int i, j, k; /* temporary index */
|
|
unsigned char msg[MAXLINE]; /* message buffer */
|
|
int n; /* temporary number */
|
|
unsigned char *s1; /* temporary string pointer */
|
|
int sp = 0; /* no-break spacing switch */
|
|
int sp_Outll; /* sp-saved Outll */
|
|
char sp_Outln; /* sp-saved Outln[0] */
|
|
int sp_Outlx; /* sp-saved Outlx */
|
|
int sp_Padx; /* sp-saved Padx */
|
|
int sp_Tind; /* sp-saved Tind */
|
|
int wl; /* real word length */
|
|
int xsp; /* extra spaces to add */
|
|
int vsp; /* vertical spacing status */
|
|
|
|
vsp = 0;
|
|
if (word != NULL)
|
|
wl = strlen((char *)word);
|
|
/*
|
|
* If not a special command, process a word.
|
|
*/
|
|
if (len >= 0 && Outll < 0) {
|
|
/*
|
|
* Enter first word.
|
|
*/
|
|
(void) strcpy((char *)Outln, (char *)word);
|
|
Outll = len;
|
|
Outlx = wl;
|
|
Padx = 0;
|
|
} else if (len >= 0
|
|
&& (Outll+Contlen+len+narg) <= (LL-Pgoff-Ind-Tind)) {
|
|
/*
|
|
* The word fits, so enter it.
|
|
*/
|
|
if ((Contlen + len) > 0) {
|
|
line_too_big:
|
|
if ((Outlx + Contlen + wl) >= MAXOLL) {
|
|
Error3(len, (char *)word, (char *)sarg, narg,
|
|
"output line too big");
|
|
return;
|
|
} else {
|
|
if (Contlen > 0 && Cont != NULL) {
|
|
if (Contlen == 1 && *Cont == ' ') {
|
|
Padchar[Padx++] = Outlx;
|
|
Outln[Outlx++] = ' ';
|
|
} else {
|
|
(void) strcpy((char *)&Outln[Outlx],
|
|
(char *)Cont);
|
|
Outlx += Contlen;
|
|
}
|
|
}
|
|
if (len > 0) {
|
|
(void) strcpy((char *)&Outln[Outlx],
|
|
(char *)word);
|
|
Outlx += wl;
|
|
}
|
|
}
|
|
}
|
|
Outll += Contlen + len;
|
|
} else if (len == NOBREAK || len == MESSAGE) {
|
|
/*
|
|
* Do nothing (equivalent to break)
|
|
*/
|
|
} else if (len == DOBREAK && strcmp((char *)word, "need") == 0
|
|
&& (Nxtln + narg) < (Pglen + 1 - Botmarg)) {
|
|
/*
|
|
* Do nothing, because there is room on the page.
|
|
*/
|
|
} else if (len == DOBREAK && strcmp((char *)word, "toindent") == 0
|
|
&& (Ind + Tind + Outll) < Ind) {
|
|
/*
|
|
* Move to indent position with line - there is room.
|
|
*/
|
|
n = Ind - (Ind + Tind +Outll);
|
|
Outll += n;
|
|
if ((Outlx + n) >= MAXOLL)
|
|
goto line_too_big;
|
|
for (i = n; i; i--)
|
|
Outln[Outlx++] = ' ';
|
|
Padx = 0;
|
|
Free(&Cont);
|
|
Contlen = 0;
|
|
} else if (Outll >= 0
|
|
|| (len == DOBREAK && strcmp((char *)word, "need") == 0)) {
|
|
/*
|
|
* A non-empty line or a "need" forces output.
|
|
*/
|
|
vsp = 0;
|
|
|
|
print_line:
|
|
if (Nxtln == 1) {
|
|
/*
|
|
* We're at the top of the page, so issue the header.
|
|
*/
|
|
if (Thispg > 1)
|
|
Charput((int)'\f');
|
|
for (i = (Topmarg - 1)/2; i > 0; i--) {
|
|
Charput((int)'\n');
|
|
Nxtln++;
|
|
}
|
|
/*
|
|
* Print the page header, as required.
|
|
*/
|
|
if (Fph || Thispg > 1) {
|
|
i = LenprtHF(Hdc, Thispg, 0)
|
|
+ LenprtHF(Hdl, Thispg, 0)
|
|
+ LenprtHF(Hdr, Thispg, 0) + 2;
|
|
j = (LL - i - Pgoff) / 2 + 1;
|
|
n = LL - Pgoff - i - j + 2;
|
|
for (k = 0; k < Pgoff; k++)
|
|
Charput((int)' ');
|
|
if (Hdl)
|
|
LenprtHF(Hdl, Thispg, 1);
|
|
while (j-- > 0)
|
|
Charput((int)' ');
|
|
if (Hdc)
|
|
LenprtHF(Hdc, Thispg, 1);
|
|
while (n-- > 0)
|
|
Charput((int)' ');
|
|
if (Hdr)
|
|
LenprtHF(Hdr, Thispg, 1);
|
|
Charput((int)'\n');
|
|
} else
|
|
Charput((int)'\n');
|
|
Nxtln++;
|
|
while(Nxtln <= Topmarg) {
|
|
Charput((int)'\n');
|
|
Nxtln++;
|
|
}
|
|
}
|
|
/*
|
|
* Add a trailing hyphen, if mecessary.
|
|
*/
|
|
if (vsp == 0 && Eollen > 0 && Eol != NULL) {
|
|
i = strlen((char *)Eol);
|
|
if ((Outlx + i) >= MAXOLL)
|
|
goto line_too_big;
|
|
(void) strcpy((char *)&Outln[Outlx], (char *)Eol);
|
|
Outlx += i;
|
|
Outll += Eollen;
|
|
}
|
|
/*
|
|
* Trim trailing spaces from the output line.
|
|
*/
|
|
while (Outlx > 0) {
|
|
if (Outln[Outlx - 1] != ' ')
|
|
break;
|
|
if (Padx > 0 && (Outlx - 1) == Padchar[Padx - 1])
|
|
Padx--;
|
|
Outlx--;
|
|
Outln[Outlx] = '\0';
|
|
Outll--;
|
|
}
|
|
if (Outlx == 0)
|
|
Charput((int)'\n');
|
|
else if (len == DOBREAK && strcmp((char *)word, "center") == 0)
|
|
{
|
|
/*
|
|
* Center the output line.
|
|
*/
|
|
i = (LL - Pgoff - Outll) / 2;
|
|
if (i < 0)
|
|
i = 0;
|
|
for (j = (Pgoff + Ind + Tind + i); j; j--)
|
|
Charput((int)' ');
|
|
Stringput(Outln);
|
|
Charput((int)'\n');
|
|
} else if (Adj == LEFTADJ
|
|
|| (Adj == BOTHADJ && (len < 0 || Padx == 0))) {
|
|
/*
|
|
* No right margin adjustment - disabled, inappropriate
|
|
* (line ended by break) or impossible.
|
|
*/
|
|
for (i = 0; i < (Pgoff + Ind + Tind); i++)
|
|
Charput((int)' ');
|
|
Stringput(Outln);
|
|
Charput((int)'\n');
|
|
} else if (Adj == BOTHADJ) {
|
|
/*
|
|
* Adjust right margin.
|
|
*/
|
|
for (i = 0; i < (Pgoff + Ind + Tind); i++)
|
|
Charput((int)' ');
|
|
i = LL - (Pgoff + Ind + Tind);
|
|
j = i - Outll;
|
|
addto = Padx ? (j / Padx) : 0;
|
|
xsp = j - (Padx * addto);
|
|
for (i = 0, s1 = Outln; i < Padx; i++) {
|
|
while (*s1 && (s1 - Outln) <= Padchar[i])
|
|
Charput((int)*s1++);
|
|
if (*s1 == '\0')
|
|
break;
|
|
j = addto;
|
|
if (Padfrom == PADLEFT) {
|
|
if (i < xsp)
|
|
j++;
|
|
} else if (i >= (Padx - xsp))
|
|
j++;
|
|
while (j-- > 0)
|
|
Charput((int)' ');
|
|
}
|
|
while (*s1)
|
|
Charput((int)*s1++);
|
|
Charput((int)'\n');
|
|
Padfrom = (Padfrom == PADLEFT) ? PADRIGHT : PADLEFT;
|
|
}
|
|
/*
|
|
* End of line housekeeping
|
|
*/
|
|
Nxtln++;
|
|
Outll = -1;
|
|
Outlx = 0;
|
|
Padx = 0;
|
|
Tind = 0;
|
|
Nospmode = 0;
|
|
if (vsp == 0 && len == DOBREAK
|
|
&& strcmp((char *)word, "need") == 0) {
|
|
/*
|
|
* Break caused by "need" - satisfy it.
|
|
*/
|
|
while (Nxtln < (Pglen + 1 - Botmarg)) {
|
|
Charput((int)'\n');
|
|
Nxtln++;
|
|
}
|
|
}
|
|
if (Nxtln >= (Pglen + 1 - Botmarg)) {
|
|
/*
|
|
* Footer required
|
|
*/
|
|
for (i = (Botmarg - 1)/2; i > 0; i--) {
|
|
Charput((int)'\n');
|
|
Nxtln++;
|
|
}
|
|
i = LenprtHF(Ftl, Thispg, 0) + LenprtHF(Ftc, Thispg, 0)
|
|
+ LenprtHF(Ftr, Thispg, 0) + 2;
|
|
j = (LL - i - Pgoff) / 2 + 1;
|
|
n = LL - Pgoff - i - j + 2;
|
|
for (k = 0; k < Pgoff; k++)
|
|
Charput((int)' ');
|
|
if (Ftl)
|
|
LenprtHF(Ftl, Thispg, 1);
|
|
while (j-- > 0)
|
|
Charput((int)' ');
|
|
if (Ftc)
|
|
LenprtHF(Ftc, Thispg, 1);
|
|
while (n-- > 0)
|
|
Charput((int)' ');
|
|
if (Ftr)
|
|
LenprtHF(Ftr, Thispg, 1);
|
|
Charput((int)'\n');
|
|
Nxtln++;
|
|
/*
|
|
* The last blank line on the page is suppressed to assist
|
|
* printers that can't look ahead to the following FF.
|
|
*/
|
|
while (Nxtln < Pglen) {
|
|
Charput((int)'\n');
|
|
Nxtln++;
|
|
}
|
|
Nxtln = 1;
|
|
Thispg++;
|
|
Nospmode = 1;
|
|
Padfrom = PADRIGHT;
|
|
}
|
|
/*
|
|
* Initiate any extra vertical spacing.
|
|
*/
|
|
if (++vsp < Vspace)
|
|
goto print_line;
|
|
/*
|
|
* Save any input word that might have forced output.
|
|
*/
|
|
if (len >= 0) {
|
|
(void) strcpy((char *)Outln, (char *)word);
|
|
Outll = len;
|
|
Outlx = wl;
|
|
Padx = 0;
|
|
}
|
|
}
|
|
/*
|
|
* A break causes padding reversal.
|
|
*/
|
|
if (len == DOBREAK)
|
|
Padfrom = PADRIGHT;
|
|
if (len >= 0 || strcmp((char *)word, "nohyphen") == 0) {
|
|
/*
|
|
* Reset continuation and hyphenation.
|
|
*/
|
|
if (Contlen != 1 || Cont[0] != ' ') {
|
|
Free(&Cont);
|
|
Cont = Newstr((unsigned char *)" ");
|
|
Contlen = 1;
|
|
}
|
|
if (Eollen > 0) {
|
|
Free(&Eol);
|
|
Eollen = 0;
|
|
}
|
|
return;
|
|
}
|
|
/*
|
|
* Now post-process any special commands.
|
|
*/
|
|
if (len == MESSAGE) {
|
|
Error3(len, (char *)word, (char *)sarg, narg, NULL);
|
|
return;
|
|
}
|
|
|
|
switch (*word) {
|
|
|
|
case 'b': /* both */
|
|
/*
|
|
* Adjust on both margins.
|
|
*/
|
|
Adj = BOTHADJ;
|
|
return;
|
|
|
|
case 'c': /* center */
|
|
return;
|
|
|
|
case 'e': /* errsto */
|
|
/*
|
|
* "errsto" comes from awf.
|
|
*/
|
|
return;
|
|
|
|
case 'f': /* flush and fph */
|
|
if (word[1] == 'l')
|
|
return;
|
|
else if (word[1] == 'p') {
|
|
/*
|
|
* First page header status
|
|
*/
|
|
Fph = narg;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case 'g': /* gap */
|
|
/*
|
|
* Increase word gap. (Space is not paddable.)
|
|
*/
|
|
if (Outll >= 0) {
|
|
if ((Outlx + narg - 1) >= MAXOLL)
|
|
goto line_too_big;
|
|
for (i = 0; i < (narg - 1); i++) {
|
|
Outln[Outlx++] = ' ';
|
|
Outll++;
|
|
}
|
|
}
|
|
return;
|
|
|
|
case 'h': /* hyphen */
|
|
/*
|
|
* Set discretionary hyphen.
|
|
*/
|
|
Free(&Cont);
|
|
Contlen = 0;
|
|
Free(&Eol);
|
|
Eol = (sarg != NULL) ? Newstr(sarg) : NULL;
|
|
Eollen = narg;
|
|
return;
|
|
|
|
case 'i': /* indent */
|
|
/*
|
|
* Set indentation.
|
|
*/
|
|
Ind = narg;
|
|
return;
|
|
|
|
case 'l': /* left or linelen */
|
|
if (word[1] == 'e') {
|
|
/*
|
|
* Adjust on left margin.
|
|
*/
|
|
Adj = LEFTADJ;
|
|
return;
|
|
} else if (word[1] == 'i') {
|
|
/*
|
|
* Set line length.
|
|
*/
|
|
LL = narg;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case 'n': /* need or nospace */
|
|
if (word[1] == 'e')
|
|
return; /* need */
|
|
else if (word[1] == 'o') {
|
|
/*
|
|
* Set no space mode.
|
|
*/
|
|
Nospmode = 1;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case 'p': /* pagelen or pageoffset */
|
|
if (strncmp((char *)&word[1], "age", 3) != 0)
|
|
break;
|
|
if (word[4] == 'l') {
|
|
/*
|
|
* Set page length.
|
|
*/
|
|
Pglen = narg;
|
|
return;
|
|
} else if (word[4] == 'o') {
|
|
/*
|
|
* Set page offset.
|
|
*/
|
|
Pgoff = narg;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case 's': /* space */
|
|
if (sp) {
|
|
|
|
/*
|
|
* Restore values after NOBREAK spacing ("^'sp").
|
|
*/
|
|
Outlx = sp_Outlx;
|
|
Outln[0] = sp_Outln;
|
|
Padx = sp_Padx;
|
|
Outll = sp_Outll;
|
|
Tind = sp_Tind;
|
|
return;
|
|
}
|
|
if (Nospmode == 0) {
|
|
if (len == NOBREAK) {
|
|
|
|
/*
|
|
* Set up for NOBREAK spacing.
|
|
*/
|
|
sp_Outlx = Outlx;
|
|
sp_Outln = Outln[0];
|
|
sp_Padx = Padx;
|
|
sp_Outll = Outll;
|
|
sp_Tind = Tind;
|
|
vsp = Vspace + 1;
|
|
sp = 1;
|
|
}
|
|
/*
|
|
* Generate a blank line.
|
|
*/
|
|
Outlx = 0;
|
|
Outln[0] = '\0';
|
|
Padx = 0;
|
|
Outll = LL - 1;
|
|
if (sp)
|
|
goto print_line;
|
|
}
|
|
return;
|
|
|
|
case 't': /* tabto, tempindent, or
|
|
* toindent */
|
|
if (word[1] == 'a') {
|
|
/*
|
|
* Move to TAB stop.
|
|
*/
|
|
if (Outll < 0)
|
|
Outll = 0;
|
|
if ((n = narg - Outll) > 0) {
|
|
if ((Outlx + n) >= MAXOLL)
|
|
goto line_too_big;
|
|
Outll += n;
|
|
for (i = n; i > 0; i--)
|
|
Outln[Outlx++] = ' ';
|
|
Free(&Cont);
|
|
Contlen = 0;
|
|
Padx = 0;
|
|
}
|
|
return;
|
|
} else if (word[1] == 'e') {
|
|
/*
|
|
* Set temporary indentation.
|
|
*/
|
|
if (*sarg == '\0' && narg >= 0)
|
|
Tind = narg - Ind;
|
|
else
|
|
Tind = ((Ind + narg) >= 0) ? narg : -Ind;
|
|
return;
|
|
} else if (word[1] == 'o')
|
|
return; /* toindent */
|
|
break;
|
|
|
|
case 'u': /* userhyphen */
|
|
/*
|
|
* Set line length.
|
|
*/
|
|
Free(&Cont);
|
|
Free(&Eol);
|
|
Contlen = Eollen = narg;
|
|
Cont = (sarg == NULL) ? NULL : Newstr(sarg);
|
|
Eol = (sarg == NULL) ? NULL : Newstr(sarg);
|
|
return;
|
|
|
|
case 'v': /* vspace */
|
|
/*
|
|
* Set vertical spacing.
|
|
*/
|
|
Vspace = (narg == 0) ? 1 : narg;
|
|
return;
|
|
|
|
case 'y': /* yesspace */
|
|
/*
|
|
* Set space mode.
|
|
*/
|
|
Nospmode = 0;
|
|
return;
|
|
} /* end of switch(*word) */
|
|
/*
|
|
* Locate header and footer defintions.
|
|
*/
|
|
if (regexec(Pat[14].pat, word)) {
|
|
if (strcmp((char *)word, "LH") == 0) {
|
|
/*
|
|
* Left header
|
|
*/
|
|
Free(&Hdl);
|
|
if (sarg != NULL)
|
|
Hdl = Newstr(sarg);
|
|
return;
|
|
}
|
|
if (strcmp((char *)word, "CH") == 0) {
|
|
/*
|
|
* Center header
|
|
*/
|
|
Free(&Hdc);
|
|
if (sarg != NULL)
|
|
Hdc = Newstr(sarg);
|
|
return;
|
|
}
|
|
if (strcmp((char *)word, "RH") == 0) {
|
|
/*
|
|
* Right header
|
|
*/
|
|
Free(&Hdr);
|
|
if (sarg != NULL)
|
|
Hdr = Newstr(sarg);
|
|
return;
|
|
}
|
|
if (strcmp((char *)word, "LF") == 0) {
|
|
/*
|
|
* Left footer
|
|
*/
|
|
Free(&Ftl);
|
|
if (sarg != NULL)
|
|
Ftl = Newstr(sarg);
|
|
return;
|
|
}
|
|
if (strcmp((char *)word, "CF") == 0) {
|
|
/*
|
|
* Center footer
|
|
*/
|
|
Free(&Ftc);
|
|
if (sarg != NULL)
|
|
Ftc = Newstr(sarg);
|
|
return;
|
|
}
|
|
if (strcmp((char *)word, "RF") == 0) {
|
|
/*
|
|
* Right footer
|
|
*/
|
|
Free(&Ftr);
|
|
if (sarg != NULL)
|
|
Ftr = Newstr(sarg);
|
|
return;
|
|
}
|
|
}
|
|
/*
|
|
* Error on unknown arguments
|
|
*/
|
|
Error3(len, (char *)word, (char *)sarg, narg, "unknown request");
|
|
}
|