1 /* 2 * pass3.c - cawf(1) pass 3 function 3 */ 4 5 /* 6 * Copyright (c) 1991 Purdue University Research Foundation, 7 * West Lafayette, Indiana 47907. All rights reserved. 8 * 9 * Written by Victor A. Abell <abe@mace.cc.purdue.edu>, Purdue 10 * University Computing Center. Not derived from licensed software; 11 * derived from awf(1) by Henry Spencer of the University of Toronto. 12 * 13 * Permission is granted to anyone to use this software for any 14 * purpose on any computer system, and to alter it and redistribute 15 * it freely, subject to the following restrictions: 16 * 17 * 1. The author is not responsible for any consequences of use of 18 * this software, even if they arise from flaws in it. 19 * 20 * 2. The origin of this software must not be misrepresented, either 21 * by explicit claim or by omission. Credits must appear in the 22 * documentation. 23 * 24 * 3. Altered versions must be plainly marked as such, and must not 25 * be misrepresented as being the original software. Credits must 26 * appear in the documentation. 27 * 28 * 4. This notice may not be removed or altered. 29 */ 30 31 #include "cawf.h" 32 33 void 34 Pass3(len, word, sarg, narg) 35 int len; /* length (negative is special) */ 36 unsigned char *word; /* word */ 37 unsigned char *sarg; /* string argument */ 38 int narg; /* numeric argument */ 39 { 40 int addto; /* spaces to add to all words */ 41 int i, j, k; /* temporary index */ 42 unsigned char msg[MAXLINE]; /* message buffer */ 43 int n; /* temporary number */ 44 unsigned char *s1; /* temporary string pointer */ 45 int sp = 0; /* no-break spacing switch */ 46 int sp_Outll; /* sp-saved Outll */ 47 char sp_Outln; /* sp-saved Outln[0] */ 48 int sp_Outlx; /* sp-saved Outlx */ 49 int sp_Padx; /* sp-saved Padx */ 50 int sp_Tind; /* sp-saved Tind */ 51 int wl; /* real word length */ 52 int xsp; /* extra spaces to add */ 53 int vsp; /* vertical spacing status */ 54 55 vsp = 0; 56 if (word != NULL) 57 wl = strlen((char *)word); 58 /* 59 * If not a special command, process a word. 60 */ 61 if (len >= 0 && Outll < 0) { 62 /* 63 * Enter first word. 64 */ 65 (void) strcpy((char *)Outln, (char *)word); 66 Outll = len; 67 Outlx = wl; 68 Padx = 0; 69 } else if (len >= 0 70 && (Outll+Contlen+len+narg) <= (LL-Pgoff-Ind-Tind)) { 71 /* 72 * The word fits, so enter it. 73 */ 74 if ((Contlen + len) > 0) { 75 line_too_big: 76 if ((Outlx + Contlen + wl) >= MAXOLL) { 77 Error3(len, (char *)word, (char *)sarg, narg, 78 "output line too big"); 79 return; 80 } else { 81 if (Contlen > 0 && Cont != NULL) { 82 if (Contlen == 1 && *Cont == ' ') { 83 Padchar[Padx++] = Outlx; 84 Outln[Outlx++] = ' '; 85 } else { 86 (void) strcpy((char *)&Outln[Outlx], 87 (char *)Cont); 88 Outlx += Contlen; 89 } 90 } 91 if (len > 0) { 92 (void) strcpy((char *)&Outln[Outlx], 93 (char *)word); 94 Outlx += wl; 95 } 96 } 97 } 98 Outll += Contlen + len; 99 } else if (len == NOBREAK || len == MESSAGE) { 100 /* 101 * Do nothing (equivalent to break) 102 */ 103 } else if (len == DOBREAK && strcmp((char *)word, "need") == 0 104 && (Nxtln + narg) < (Pglen + 1 - Botmarg)) { 105 /* 106 * Do nothing, because there is room on the page. 107 */ 108 } else if (len == DOBREAK && strcmp((char *)word, "toindent") == 0 109 && (Ind + Tind + Outll) < Ind) { 110 /* 111 * Move to indent position with line - there is room. 112 */ 113 n = Ind - (Ind + Tind +Outll); 114 Outll += n; 115 if ((Outlx + n) >= MAXOLL) 116 goto line_too_big; 117 for (i = n; i; i--) 118 Outln[Outlx++] = ' '; 119 Padx = 0; 120 Free(&Cont); 121 Contlen = 0; 122 } else if (Outll >= 0 123 || (len == DOBREAK && strcmp((char *)word, "need") == 0)) { 124 /* 125 * A non-empty line or a "need" forces output. 126 */ 127 vsp = 0; 128 129 print_line: 130 if (Nxtln == 1) { 131 /* 132 * We're at the top of the page, so issue the header. 133 */ 134 if (Thispg > 1) 135 Charput((int)'\f'); 136 for (i = (Topmarg - 1)/2; i > 0; i--) { 137 Charput((int)'\n'); 138 Nxtln++; 139 } 140 /* 141 * Print the page header, as required. 142 */ 143 if (Fph || Thispg > 1) { 144 i = LenprtHF(Hdc, Thispg, 0) 145 + LenprtHF(Hdl, Thispg, 0) 146 + LenprtHF(Hdr, Thispg, 0) + 2; 147 j = (LL - i - Pgoff) / 2 + 1; 148 n = LL - Pgoff - i - j + 2; 149 for (k = 0; k < Pgoff; k++) 150 Charput((int)' '); 151 if (Hdl) 152 LenprtHF(Hdl, Thispg, 1); 153 while (j-- > 0) 154 Charput((int)' '); 155 if (Hdc) 156 LenprtHF(Hdc, Thispg, 1); 157 while (n-- > 0) 158 Charput((int)' '); 159 if (Hdr) 160 LenprtHF(Hdr, Thispg, 1); 161 Charput((int)'\n'); 162 } else 163 Charput((int)'\n'); 164 Nxtln++; 165 while(Nxtln <= Topmarg) { 166 Charput((int)'\n'); 167 Nxtln++; 168 } 169 } 170 /* 171 * Add a trailing hyphen, if mecessary. 172 */ 173 if (vsp == 0 && Eollen > 0 && Eol != NULL) { 174 i = strlen((char *)Eol); 175 if ((Outlx + i) >= MAXOLL) 176 goto line_too_big; 177 (void) strcpy((char *)&Outln[Outlx], (char *)Eol); 178 Outlx += i; 179 Outll += Eollen; 180 } 181 /* 182 * Trim trailing spaces from the output line. 183 */ 184 while (Outlx > 0) { 185 if (Outln[Outlx - 1] != ' ') 186 break; 187 if (Padx > 0 && (Outlx - 1) == Padchar[Padx - 1]) 188 Padx--; 189 Outlx--; 190 Outln[Outlx] = '\0'; 191 Outll--; 192 } 193 if (Outlx == 0) 194 Charput((int)'\n'); 195 else if (len == DOBREAK && strcmp((char *)word, "center") == 0) 196 { 197 /* 198 * Center the output line. 199 */ 200 i = (LL - Pgoff - Outll) / 2; 201 if (i < 0) 202 i = 0; 203 for (j = (Pgoff + Ind + Tind + i); j; j--) 204 Charput((int)' '); 205 Stringput(Outln); 206 Charput((int)'\n'); 207 } else if (Adj == LEFTADJ 208 || (Adj == BOTHADJ && (len < 0 || Padx == 0))) { 209 /* 210 * No right margin adjustment - disabled, inappropriate 211 * (line ended by break) or impossible. 212 */ 213 for (i = 0; i < (Pgoff + Ind + Tind); i++) 214 Charput((int)' '); 215 Stringput(Outln); 216 Charput((int)'\n'); 217 } else if (Adj == BOTHADJ) { 218 /* 219 * Adjust right margin. 220 */ 221 for (i = 0; i < (Pgoff + Ind + Tind); i++) 222 Charput((int)' '); 223 i = LL - (Pgoff + Ind + Tind); 224 j = i - Outll; 225 addto = Padx ? (j / Padx) : 0; 226 xsp = j - (Padx * addto); 227 for (i = 0, s1 = Outln; i < Padx; i++) { 228 while (*s1 && (s1 - Outln) <= Padchar[i]) 229 Charput((int)*s1++); 230 if (*s1 == '\0') 231 break; 232 j = addto; 233 if (Padfrom == PADLEFT) { 234 if (i < xsp) 235 j++; 236 } else if (i >= (Padx - xsp)) 237 j++; 238 while (j-- > 0) 239 Charput((int)' '); 240 } 241 while (*s1) 242 Charput((int)*s1++); 243 Charput((int)'\n'); 244 Padfrom = (Padfrom == PADLEFT) ? PADRIGHT : PADLEFT; 245 } 246 /* 247 * End of line housekeeping 248 */ 249 Nxtln++; 250 Outll = -1; 251 Outlx = 0; 252 Padx = 0; 253 Tind = 0; 254 Nospmode = 0; 255 if (vsp == 0 && len == DOBREAK 256 && strcmp((char *)word, "need") == 0) { 257 /* 258 * Break caused by "need" - satisfy it. 259 */ 260 while (Nxtln < (Pglen + 1 - Botmarg)) { 261 Charput((int)'\n'); 262 Nxtln++; 263 } 264 } 265 if (Nxtln >= (Pglen + 1 - Botmarg)) { 266 /* 267 * Footer required 268 */ 269 for (i = (Botmarg - 1)/2; i > 0; i--) { 270 Charput((int)'\n'); 271 Nxtln++; 272 } 273 i = LenprtHF(Ftl, Thispg, 0) + LenprtHF(Ftc, Thispg, 0) 274 + LenprtHF(Ftr, Thispg, 0) + 2; 275 j = (LL - i - Pgoff) / 2 + 1; 276 n = LL - Pgoff - i - j + 2; 277 for (k = 0; k < Pgoff; k++) 278 Charput((int)' '); 279 if (Ftl) 280 LenprtHF(Ftl, Thispg, 1); 281 while (j-- > 0) 282 Charput((int)' '); 283 if (Ftc) 284 LenprtHF(Ftc, Thispg, 1); 285 while (n-- > 0) 286 Charput((int)' '); 287 if (Ftr) 288 LenprtHF(Ftr, Thispg, 1); 289 Charput((int)'\n'); 290 Nxtln++; 291 /* 292 * The last blank line on the page is suppressed to assist 293 * printers that can't look ahead to the following FF. 294 */ 295 while (Nxtln < Pglen) { 296 Charput((int)'\n'); 297 Nxtln++; 298 } 299 Nxtln = 1; 300 Thispg++; 301 Nospmode = 1; 302 Padfrom = PADRIGHT; 303 } 304 /* 305 * Initiate any extra vertical spacing. 306 */ 307 if (++vsp < Vspace) 308 goto print_line; 309 /* 310 * Save any input word that might have forced output. 311 */ 312 if (len >= 0) { 313 (void) strcpy((char *)Outln, (char *)word); 314 Outll = len; 315 Outlx = wl; 316 Padx = 0; 317 } 318 } 319 /* 320 * A break causes padding reversal. 321 */ 322 if (len == DOBREAK) 323 Padfrom = PADRIGHT; 324 if (len >= 0 || strcmp((char *)word, "nohyphen") == 0) { 325 /* 326 * Reset continuation and hyphenation. 327 */ 328 if (Contlen != 1 || Cont[0] != ' ') { 329 Free(&Cont); 330 Cont = Newstr((unsigned char *)" "); 331 Contlen = 1; 332 } 333 if (Eollen > 0) { 334 Free(&Eol); 335 Eollen = 0; 336 } 337 return; 338 } 339 /* 340 * Now post-process any special commands. 341 */ 342 if (len == MESSAGE) { 343 Error3(len, (char *)word, (char *)sarg, narg, NULL); 344 return; 345 } 346 347 switch (*word) { 348 349 case 'b': /* both */ 350 /* 351 * Adjust on both margins. 352 */ 353 Adj = BOTHADJ; 354 return; 355 356 case 'c': /* center */ 357 return; 358 359 case 'e': /* errsto */ 360 /* 361 * "errsto" comes from awf. 362 */ 363 return; 364 365 case 'f': /* flush and fph */ 366 if (word[1] == 'l') 367 return; 368 else if (word[1] == 'p') { 369 /* 370 * First page header status 371 */ 372 Fph = narg; 373 return; 374 } 375 break; 376 377 case 'g': /* gap */ 378 /* 379 * Increase word gap. (Space is not paddable.) 380 */ 381 if (Outll >= 0) { 382 if ((Outlx + narg - 1) >= MAXOLL) 383 goto line_too_big; 384 for (i = 0; i < (narg - 1); i++) { 385 Outln[Outlx++] = ' '; 386 Outll++; 387 } 388 } 389 return; 390 391 case 'h': /* hyphen */ 392 /* 393 * Set discretionary hyphen. 394 */ 395 Free(&Cont); 396 Contlen = 0; 397 Free(&Eol); 398 Eol = (sarg != NULL) ? Newstr(sarg) : NULL; 399 Eollen = narg; 400 return; 401 402 case 'i': /* indent */ 403 /* 404 * Set indentation. 405 */ 406 Ind = narg; 407 return; 408 409 case 'l': /* left or linelen */ 410 if (word[1] == 'e') { 411 /* 412 * Adjust on left margin. 413 */ 414 Adj = LEFTADJ; 415 return; 416 } else if (word[1] == 'i') { 417 /* 418 * Set line length. 419 */ 420 LL = narg; 421 return; 422 } 423 break; 424 425 case 'n': /* need or nospace */ 426 if (word[1] == 'e') 427 return; /* need */ 428 else if (word[1] == 'o') { 429 /* 430 * Set no space mode. 431 */ 432 Nospmode = 1; 433 return; 434 } 435 break; 436 437 case 'p': /* pagelen or pageoffset */ 438 if (strncmp((char *)&word[1], "age", 3) != 0) 439 break; 440 if (word[4] == 'l') { 441 /* 442 * Set page length. 443 */ 444 Pglen = narg; 445 return; 446 } else if (word[4] == 'o') { 447 /* 448 * Set page offset. 449 */ 450 Pgoff = narg; 451 return; 452 } 453 break; 454 455 case 's': /* space */ 456 if (sp) { 457 458 /* 459 * Restore values after NOBREAK spacing ("^'sp"). 460 */ 461 Outlx = sp_Outlx; 462 Outln[0] = sp_Outln; 463 Padx = sp_Padx; 464 Outll = sp_Outll; 465 Tind = sp_Tind; 466 return; 467 } 468 if (Nospmode == 0) { 469 if (len == NOBREAK) { 470 471 /* 472 * Set up for NOBREAK spacing. 473 */ 474 sp_Outlx = Outlx; 475 sp_Outln = Outln[0]; 476 sp_Padx = Padx; 477 sp_Outll = Outll; 478 sp_Tind = Tind; 479 vsp = Vspace + 1; 480 sp = 1; 481 } 482 /* 483 * Generate a blank line. 484 */ 485 Outlx = 0; 486 Outln[0] = '\0'; 487 Padx = 0; 488 Outll = LL - 1; 489 if (sp) 490 goto print_line; 491 } 492 return; 493 494 case 't': /* tabto, tempindent, or 495 * toindent */ 496 if (word[1] == 'a') { 497 /* 498 * Move to TAB stop. 499 */ 500 if (Outll < 0) 501 Outll = 0; 502 if ((n = narg - Outll) > 0) { 503 if ((Outlx + n) >= MAXOLL) 504 goto line_too_big; 505 Outll += n; 506 for (i = n; i > 0; i--) 507 Outln[Outlx++] = ' '; 508 Free(&Cont); 509 Contlen = 0; 510 Padx = 0; 511 } 512 return; 513 } else if (word[1] == 'e') { 514 /* 515 * Set temporary indentation. 516 */ 517 if (*sarg == '\0' && narg >= 0) 518 Tind = narg - Ind; 519 else 520 Tind = ((Ind + narg) >= 0) ? narg : -Ind; 521 return; 522 } else if (word[1] == 'o') 523 return; /* toindent */ 524 break; 525 526 case 'u': /* userhyphen */ 527 /* 528 * Set line length. 529 */ 530 Free(&Cont); 531 Free(&Eol); 532 Contlen = Eollen = narg; 533 Cont = (sarg == NULL) ? NULL : Newstr(sarg); 534 Eol = (sarg == NULL) ? NULL : Newstr(sarg); 535 return; 536 537 case 'v': /* vspace */ 538 /* 539 * Set vertical spacing. 540 */ 541 Vspace = (narg == 0) ? 1 : narg; 542 return; 543 544 case 'y': /* yesspace */ 545 /* 546 * Set space mode. 547 */ 548 Nospmode = 0; 549 return; 550 } /* end of switch(*word) */ 551 /* 552 * Locate header and footer defintions. 553 */ 554 if (regexec(Pat[14].pat, word)) { 555 if (strcmp((char *)word, "LH") == 0) { 556 /* 557 * Left header 558 */ 559 Free(&Hdl); 560 if (sarg != NULL) 561 Hdl = Newstr(sarg); 562 return; 563 } 564 if (strcmp((char *)word, "CH") == 0) { 565 /* 566 * Center header 567 */ 568 Free(&Hdc); 569 if (sarg != NULL) 570 Hdc = Newstr(sarg); 571 return; 572 } 573 if (strcmp((char *)word, "RH") == 0) { 574 /* 575 * Right header 576 */ 577 Free(&Hdr); 578 if (sarg != NULL) 579 Hdr = Newstr(sarg); 580 return; 581 } 582 if (strcmp((char *)word, "LF") == 0) { 583 /* 584 * Left footer 585 */ 586 Free(&Ftl); 587 if (sarg != NULL) 588 Ftl = Newstr(sarg); 589 return; 590 } 591 if (strcmp((char *)word, "CF") == 0) { 592 /* 593 * Center footer 594 */ 595 Free(&Ftc); 596 if (sarg != NULL) 597 Ftc = Newstr(sarg); 598 return; 599 } 600 if (strcmp((char *)word, "RF") == 0) { 601 /* 602 * Right footer 603 */ 604 Free(&Ftr); 605 if (sarg != NULL) 606 Ftr = Newstr(sarg); 607 return; 608 } 609 } 610 /* 611 * Error on unknown arguments 612 */ 613 Error3(len, (char *)word, (char *)sarg, narg, "unknown request"); 614 } 615