xref: /minix/minix/commands/cawf/pass3.c (revision 83133719)
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