1 /*-
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#)fancy.c	8.1 (Berkeley) 5/31/93
30  * $FreeBSD: src/games/backgammon/common_source/fancy.c,v 1.7 1999/11/30 03:48:25 billf Exp $
31  */
32 
33 #include <string.h>
34 #include <termcap.h>
35 #include "back.h"
36 
37 static void	bsect(int, int, int, int);
38 static void	fixpos(int, int, int, int, int);
39 static void	fixcol(int, int, int, int, int);
40 static void	newline(void);
41 
42 char	PC;			/* padding character */
43 char	*BC;			/* backspace sequence */
44 char	*CD;			/* clear to end of screen sequence */
45 char	*CE;			/* clear to end of line sequence */
46 char	*CL;			/* clear screen sequence */
47 char	*CM;			/* cursor movement instructions */
48 char	*HO;			/* home cursor sequence */
49 char	*MC;			/* column cursor movement map */
50 char	*ML;			/* row cursor movement map */
51 char	*ND;			/* forward cursor sequence */
52 char	*UP;			/* up cursor sequence */
53 
54 int	lHO;			/* length of HO */
55 int	lBC;			/* length of BC */
56 int	lND;			/* length of ND */
57 int	lUP;			/* length of UP */
58 int	CO;			/* number of columns */
59 int	LI;			/* number of lines */
60 int	*linect;		/* array of lengths of lines on screen
61 				   (the actual screen is not stored) */
62 
63 				/* two letter codes */
64 char	tcap[] = "bccdceclcmhomcmlndup";
65 				/* corresponding strings */
66 char	**tstr[] = { &BC, &CD, &CE, &CL, &CM, &HO, &MC, &ML, &ND, &UP };
67 
68 int	buffnum;		/* pointer to output buffer */
69 
70 char	tbuf[1024];		/* buffer for decoded termcap entries */
71 
72 int	oldb[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
73 
74 int	oldr;
75 int	oldw;
76 /*
77  * "real" cursor positions, so it knows when to reposition. These are -1 if
78  * curr and curc are accurate
79  */
80 int	realr;
81 int	realc;
82 
83 void
84 fboard(void)
85 {
86 	int i, j, l;
87 
88 	curmove(0, 0);		/* do top line */
89 	for (i = 0; i < 53; i++)
90 		fancyc('_');
91 
92 	curmove(15, 0);		/* do bottom line */
93 	for (i = 0; i < 53; i++)
94 		fancyc('_');
95 
96 	l = 1;			/* do vertical lines */
97 	for (i = 52; i > -1; i -= 28) {
98 		curmove((l == 1 ? 1 : 15), i);
99 		fancyc('|');
100 		for (j = 0; j < 14; j++) {
101 			curmove(curr + l, curc - 1);
102 			fancyc('|');
103 		}
104 		if (i == 24)
105 			i += 32;
106 		l = -l;		/* alternate directions */
107 	}
108 
109 	curmove(2, 1);		/* label positions 13-18 */
110 	for (i = 13; i < 18; i++) {
111 		fancyc('1');
112 		fancyc((i % 10) + '0');
113 		curmove(curr, curc + 2);
114 	}
115 	fancyc('1');
116 	fancyc('8');
117 
118 	curmove(2, 29);		/* label positions 19-24 */
119 	fancyc('1');
120 	fancyc('9');
121 	for (i = 20; i < 25; i++) {
122 		curmove(curr, curc + 2);
123 		fancyc('2');
124 		fancyc((i % 10) + '0');
125 	}
126 
127 	curmove(14, 1);		/* label positions 12-7 */
128 	fancyc('1');
129 	fancyc('2');
130 	for (i = 11; i > 6; i--) {
131 		curmove(curr, curc + 2);
132 		fancyc(i > 9 ? '1' : ' ');
133 		fancyc((i % 10) + '0');
134 	}
135 
136 	curmove(14, 30);	/* label positions 6-1 */
137 	fancyc('6');
138 	for (i = 5; i > 0; i--) {
139 		curmove(curr, curc + 3);
140 		fancyc(i + '0');
141 	}
142 
143 	for (i = 12; i > 6; i--)	/* print positions 12-7 */
144 		if (board[i])
145 			bsect(board[i], 13, 1 + 4 * (12 - i), -1);
146 
147 	if (board[0])		/* print red men on bar */
148 		bsect(board[0], 13, 25, -1);
149 
150 	for (i = 6; i > 0; i--)	/* print positions 6-1 */
151 		if (board[i])
152 			bsect(board[i], 13, 29 + 4 * (6 - i), -1);
153 
154 	l = (off[1] < 0 ? off[1] + 15 : off[1]);	/* print white's home */
155 	bsect(l, 3, 54, 1);
156 
157 	curmove(8, 25);		/* print the word BAR */
158 	fancyc('B');
159 	fancyc('A');
160 	fancyc('R');
161 
162 	for (i = 13; i < 19; i++)	/* print positions 13-18 */
163 		if (board[i])
164 			bsect(board[i], 3, 1 + 4 * (i - 13), 1);
165 
166 	if (board[25])		/* print white's men on bar */
167 		bsect(board[25], 3, 25, 1);
168 
169 	for (i = 19; i < 25; i++)	/* print positions 19-24 */
170 		if (board[i])
171 			bsect(board[i], 3, 29 + 4 * (i - 19), 1);
172 
173 	l = (off[0] < 0 ? off[0] + 15 : off[0]);	/* print red's home */
174 	bsect(-l, 13, 54, -1);
175 
176 	for (i = 0; i < 26; i++)	/* save board position
177 					* for refresh later */
178 		oldb[i] = board[i];
179 	oldr = (off[1] < 0 ? off[1] + 15 : off[1]);
180 	oldw = -(off[0] < 0 ? off[0] + 15 : off[0]);
181 }
182 
183 /*
184  * bsect (b,rpos,cpos,cnext)
185  *	Print the contents of a board position.  "b" has the value of the
186  * position, "rpos" is the row to start printing, "cpos" is the column to
187  * start printing, and "cnext" is positive if the position starts at the top
188  * and negative if it starts at the bottom.  The value of "cpos" is checked
189  * to see if the position is a player's home, since those are printed
190  * differently.
191  */
192 static void
193 bsect(int b, int rpos, int cpos, int cnext)
194 {
195 	int j;			/* index */
196 	int n;			/* number of men on position */
197 	int bct;		/* counter */
198 	int k;			/* index */
199 	char pc;		/* color of men on position */
200 
201 	bct = 0;
202 	n = abs(b);			/* initialize n and pc */
203 	pc = (b > 0 ? 'r' : 'w');
204 
205 	if (n < 6 && cpos < 54)		/* position cursor at start */
206 		curmove(rpos, cpos + 1);
207 	else
208 		curmove(rpos, cpos);
209 
210 	for (j = 0; j < 5; j++) {	/* print position row by row */
211 		for (k = 0; k < 15; k += 5)	/* print men */
212 			if (n > j + k)
213 				fancyc(pc);
214 
215 		if (j < 4) {	/* figure how far to back up for next row */
216 			if (n < 6) {		/* stop if none left */
217 				if (j + 1 == n)
218 					break;
219 				bct = 1;	/* single column */
220 			} else {
221 				if (n < 11) {	/* two columns */
222 					if (cpos == 54) {	/* home pos */
223 						if (j + 5 >= n)
224 							bct = 1;
225 						else
226 							bct = 2;
227 					}
228 					if (cpos < 54) {	/* not home */
229 						if (j + 6 >= n)
230 							bct = 1;
231 						else
232 							bct = 2;
233 					}
234 				} else {	/* three columns */
235 					if (j + 10 >= n)
236 						bct = 2;
237 					else
238 						bct = 3;
239 				}
240 			}
241 			/* reposition cursor */
242 			curmove(curr + cnext, curc - bct);
243 		}
244 	}
245 }
246 
247 void
248 refresh(void)
249 {
250 	int i, r, c;
251 
252 	r = curr;			/* save current position */
253 	c = curc;
254 
255 	for (i = 12; i > 6; i--)	/* fix positions 12-7 */
256 		if (board[i] != oldb[i]) {
257 			fixpos(oldb[i], board[i], 13, 1 + (12 - i) * 4, -1);
258 			oldb[i] = board[i];
259 		}
260 	if (board[0] != oldb[0]) {	/* fix red men on bar */
261 		fixpos(oldb[0], board[0], 13, 25, -1);
262 		oldb[0] = board[0];
263 	}
264 	for (i = 6; i > 0; i--)		/* fix positions 6-1 */
265 		if (board[i] != oldb[i]) {
266 			fixpos(oldb[i], board[i], 13, 29 + (6 - i) * 4, -1);
267 			oldb[i] = board[i];
268 		}
269 	i = -(off[0] < 0 ? off[0] + 15 : off[0]);	/* fix white's home */
270 	if (oldw != i) {
271 		fixpos(oldw, i, 13, 54, -1);
272 		oldw = i;
273 	}
274 	for (i = 13; i < 19; i++)	/* fix positions 13-18 */
275 		if (board[i] != oldb[i]) {
276 			fixpos(oldb[i], board[i], 3, 1 + (i - 13) * 4, 1);
277 			oldb[i] = board[i];
278 		}
279 	if (board[25] != oldb[25]) {	/* fix white men on bar */
280 		fixpos(oldb[25], board[25], 3, 25, 1);
281 		oldb[25] = board[25];
282 	}
283 	for (i = 19; i < 25; i++)	/* fix positions 19-24 */
284 		if (board[i] != oldb[i]) {
285 			fixpos(oldb[i], board[i], 3, 29 + (i - 19) * 4, 1);
286 			oldb[i] = board[i];
287 		}
288 	i = (off[1] < 0 ? off[1] + 15 : off[1]);	/* fix red's home */
289 	if (oldr != i) {
290 		fixpos(oldr, i, 3, 54, 1);
291 		oldr = i;
292 	}
293 	curmove(r, c);			/* return to saved position */
294 	newpos();
295 	buflush();
296 }
297 
298 static void
299 fixpos(int cur, int new, int r, int c, int inc)
300 {
301 	int o, n, nv;
302 	int ov, nc;
303 	char col;
304 
305 	nc = 0;
306 	if (cur * new >= 0) {
307 		ov = abs(cur);
308 		nv = abs(new);
309 		col = (cur + new > 0 ? 'r' : 'w');
310 		o = (ov - 1) / 5;
311 		n = (nv - 1) / 5;
312 		if (o == n) {
313 			if (o == 2)
314 				nc = c + 2;
315 			if (o == 1)
316 				nc = c < 54 ? c : c + 1;
317 			if (o == 0)
318 				nc = c < 54 ? c + 1 : c;
319 			if (ov > nv)
320 				fixcol(r + inc * (nv - n * 5), nc,
321 				    abs(ov - nv), ' ', inc);
322 			else
323 				fixcol(r + inc * (ov - o * 5), nc,
324 				    abs(ov - nv), col, inc);
325 			return;
326 		} else {
327 			if (c < 54) {
328 				if (o + n == 1) {
329 					if (n) {
330 						fixcol(r, c, abs(nv - 5), col,
331 						    inc);
332 						if (ov != 5)
333 							fixcol(r + inc * ov,
334 							    c + 1, abs(ov - 5),
335 							    col, inc);
336 					} else {
337 						fixcol(r, c, abs(ov - 5), ' ',
338 						    inc);
339 						if (nv != 5)
340 							fixcol(r + inc * nv,
341 							    c + 1, abs(nv - 5),
342 							    ' ', inc);
343 					}
344 					return;
345 				}
346 				if (n == 2) {
347 					if (ov != 10)
348 						fixcol(r + inc * (ov - 5), c,
349 						    abs(ov - 10), col, inc);
350 					fixcol(r, c + 2, abs(nv - 10), col, inc);
351 				} else {
352 					if (nv != 10)
353 						fixcol(r + inc * (nv - 5), c,
354 						    abs(nv - 10), ' ', inc);
355 					fixcol(r, c + 2, abs(ov - 10), ' ', inc);
356 				}
357 				return;
358 			}
359 			if (n > o) {
360 				fixcol(r + inc * (ov % 5), c + o,
361 				    abs(5 * n - ov), col, inc);
362 				if (nv != 5 * n)
363 					fixcol(r, c + n, abs(5 * n - nv),
364 					    col, inc);
365 			} else {
366 				fixcol(r + inc * (nv % 5), c + n,
367 				    abs(5 * n - nv), ' ', inc);
368 				if (ov != 5 * o)
369 					fixcol(r, c + o, abs(5 * o - ov),
370 					    ' ', inc);
371 			}
372 			return;
373 		}
374 	}
375 	nv = abs(new);
376 	fixcol(r, c + 1, nv, new > 0 ? 'r' : 'w', inc);
377 	if (abs(cur) <= abs(new))
378 		return;
379 	fixcol(r + inc * new, c + 1, abs(cur + new), ' ', inc);
380 }
381 
382 static void
383 fixcol(int r, int c, int l, int ch, int inc)
384 {
385 	int i;
386 
387 	curmove(r, c);
388 	fancyc(ch);
389 	for (i = 1; i < l; i++) {
390 		curmove(curr + inc, curc - 1);
391 		fancyc(ch);
392 	}
393 }
394 
395 void
396 curmove(int r, int c)
397 {
398 	if (curr == r && curc == c)
399 		return;
400 	if (realr == -1) {
401 		realr = curr;
402 		realc = curc;
403 	}
404 	curr = r;
405 	curc = c;
406 }
407 
408 void
409 newpos(void)
410 {
411 	int r;			/* destination row */
412 	int c;			/* destination column */
413 	int mode;		/* mode of movement */
414 
415 	int ccount;		/* character count */
416 	int i;			/* index */
417 	int n;			/* temporary variable */
418 	char *m;		/* string containing CM movement */
419 
420 	mode = -1;
421 	ccount = 1000;
422 	m = NULL;
423 	if (realr == -1)	/* see if already there */
424 		return;
425 
426 	r = curr;		/* set current and dest. positions */
427 	c = curc;
428 	curr = realr;
429 	curc = realc;
430 
431 	/* double check position */
432 	if (curr == r && curc == c) {
433 		realr = realc = -1;
434 		return;
435 	}
436 	if (CM) {		/* try CM to get there */
437 		mode = 0;
438 		m = (char *)tgoto(CM, c, r);
439 		ccount = strlen(m);
440 	}
441 	/* try HO and local movement */
442 	if (HO && (n = r + c * lND + lHO) < ccount) {
443 		mode = 1;
444 		ccount = n;
445 	}
446 	/* try various LF combinations */
447 	if (r >= curr) {
448 		/* CR, LF, and ND */
449 		if ((n = (r - curr) + c * lND + 1) < ccount) {
450 			mode = 2;
451 			ccount = n;
452 		}
453 		/* LF, ND */
454 		if (c >= curc && (n = (r - curr) + (c - curc) * lND) < ccount) {
455 			mode = 3;
456 			ccount = n;
457 		}
458 		/* LF, BS */
459 		if (c < curc && (n = (r - curr) + (curc - c) * lBC) < ccount) {
460 			mode = 4;
461 			ccount = n;
462 		}
463 	}
464 	/* try corresponding UP combinations */
465 	if (r < curr) {
466 		/* CR, UP, and ND */
467 		if ((n = (curr - r) * lUP + c * lND + 1) < ccount) {
468 			mode = 5;
469 			ccount = n;
470 		}
471 		/* UP and ND */
472 		if (c >= curc &&
473 		    (n = (curr - r) * lUP + (c - curc) * lND) < ccount) {
474 			mode = 6;
475 			ccount = n;
476 		}
477 		/* UP and BS */
478 		if (c < curc &&
479 		    (n = (curr - r) * lUP + (curc - c) * lBC) < ccount) {
480 			mode = 7;
481 			ccount = n;
482 		}
483 	}
484 	/* space over */
485 	if (curr == r && c > curc && linect[r] < curc && c - curc < ccount)
486 		mode = 8;
487 
488 	switch (mode) {
489 	case -1:	/* error! */
490 		write(2, "\r\nInternal cursor error.\r\n", 26);
491 		getout(0);
492 
493 	case 0:		/* direct cursor motion */
494 		tputs(m, abs(curr - r), addbuf);
495 		break;
496 
497 	case 1:		/* relative to "home" */
498 		tputs(HO, r, addbuf);
499 		for (i = 0; i < r; i++)
500 			addbuf('\012');
501 		for (i = 0; i < c; i++)
502 			tputs(ND, 1, addbuf);
503 		break;
504 
505 	case 2:		/* CR and down and over */
506 		addbuf('\015');
507 		for (i = 0; i < r - curr; i++)
508 			addbuf('\012');
509 		for (i = 0; i < c; i++)
510 			tputs(ND, 1, addbuf);
511 		break;
512 
513 	case 3:		/* down and over */
514 		for (i = 0; i < r - curr; i++)
515 			addbuf('\012');
516 		for (i = 0; i < c - curc; i++)
517 			tputs(ND, 1, addbuf);
518 		break;
519 
520 	case 4:		/* down and back */
521 		for (i = 0; i < r - curr; i++)
522 			addbuf('\012');
523 		for (i = 0; i < curc - c; i++)
524 			addbuf('\010');
525 		break;
526 
527 	case 5:		/* CR and up and over */
528 		addbuf('\015');
529 		for (i = 0; i < curr - r; i++)
530 			tputs(UP, 1, addbuf);
531 		for (i = 0; i < c; i++)
532 			tputs(ND, 1, addbuf);
533 		break;
534 
535 	case 6:		/* up and over */
536 		for (i = 0; i < curr - r; i++)
537 			tputs(UP, 1, addbuf);
538 		for (i = 0; i < c - curc; i++)
539 			tputs(ND, 1, addbuf);
540 		break;
541 
542 	case 7:		/* up and back */
543 		for (i = 0; i < curr - r; i++)
544 			tputs(UP, 1, addbuf);
545 		for (i = 0; i < curc - c; i++) {
546 			if (BC)
547 				tputs(BC, 1, addbuf);
548 			else
549 				addbuf('\010');
550 		}
551 		break;
552 
553 	case 8:		/* safe space */
554 		for (i = 0; i < c - curc; i++)
555 			addbuf(' ');
556 	}
557 
558 	/* fix positions */
559 	curr = r;
560 	curc = c;
561 	realr = -1;
562 	realc = -1;
563 }
564 
565 void
566 clear(void)
567 {
568 	int i;
569 
570 	/* double space if can't clear */
571 	if (CL == NULL) {
572 		writel("\n\n");
573 		return;
574 	}
575 	curr = curc = 0;		/* fix position markers */
576 	realr = realc = -1;
577 	for (i = 0; i < 24; i++)	/* clear line counts */
578 		linect[i] = -1;
579 	buffnum = -1;			/* ignore leftover buffer contents */
580 	tputs(CL, CO, addbuf);		/* put CL in buffer */
581 }
582 
583 /* input is character to output */
584 void
585 fancyc(char c)
586 {
587 	int sp;			/* counts spaces in a tab */
588 
589 	if (c == '\007') {	/* bells go in blindly */
590 		addbuf(c);
591 		return;
592 	}
593 
594 	/*
595 	 * process tabs, use spaces if the the tab should be erasing things,
596 	 * otherwise use cursor movement routines.  Note this does not use
597 	 * hardware tabs at all.
598 	 */
599 	if (c == '\t') {
600 		sp = (curc + 8) & (~7);		/* compute spaces */
601 		/* check line length */
602 		if (linect[curr] >= curc || sp < 4) {
603 			for (; sp > curc; sp--)
604 				addbuf(' ');
605 			curc = sp;		/* fix curc */
606 		} else
607 			curmove(curr, sp);
608 		return;
609 	}
610 	/* do newline be calling newline */
611 	if (c == '\n') {
612 		newline();
613 		return;
614 	}
615 	/* ignore any other control chars */
616 	if (c < ' ')
617 		return;
618 
619 	/*
620 	 * if an erasing space or non-space, just add it to buffer.  Otherwise
621 	 * use cursor movement routine, so that multiple spaces will be grouped
622 	 * together
623 	 */
624 	if (c > ' ' || linect[curr] >= curc) {
625 		newpos();		/* make sure position correct */
626 		addbuf(c);		/* add character to buffer */
627 		/* fix line length */
628 		if (c == ' ' && linect[curr] == curc)
629 			linect[curr]--;
630 		else
631 			if (linect[curr] < curc)
632 				linect[curr] = curc;
633 		curc++;			/* fix curc */
634 	} else
635 		/* use cursor movement routine */
636 		curmove(curr, curc + 1);
637 }
638 
639 void
640 clend(void)
641 {
642 	int i;
643 
644 	if (CD) {
645 		tputs(CD, CO - curr, addbuf);
646 		for (i = curr; i < LI; i++)
647 			linect[i] = -1;
648 		return;
649 	}
650 	curmove(i = curr, 0);
651 	cline();
652 	while (curr < LI - 1) {
653 		curmove(curr + 1, 0);
654 		if (linect[curr] > -1)
655 			cline();
656 	}
657 	curmove(i, 0);
658 }
659 
660 void
661 cline(void)
662 {
663 	int c;
664 
665 	if (curc > linect[curr])
666 		return;
667 	newpos();
668 	if (CE) {
669 		tputs(CE, 1, addbuf);
670 		linect[curr] = curc - 1;
671 	} else {
672 		c = curc - 1;
673 		while (linect[curr] > c) {
674 			addbuf(' ');
675 			curc++;
676 			linect[curr]--;
677 		}
678 		curmove(curr, c + 1);
679 	}
680 }
681 
682 static void
683 newline(void)
684 {
685 	cline();
686 	if (curr == LI - 1)
687 		curmove(begscr, 0);
688 	else
689 		curmove(curr + 1, 0);
690 }
691 
692 int
693 getcaps(const char *s)
694 {
695 	char   *code;		/* two letter code */
696 	char ***cap;		/* pointer to cap string */
697 	char   *bufp;		/* pointer to cap buffer */
698 	char    tentry[1024];	/* temporary uncoded caps buffer */
699 
700 	tgetent(tentry, s);	/* get uncoded termcap entry */
701 
702 	LI = tgetnum("li");	/* get number of lines */
703 	if (LI == -1)
704 		LI = 12;
705 	CO = tgetnum("co");	/* get number of columns */
706 	if (CO == -1)
707 		CO = 65;
708 
709 	bufp = tbuf;		/* get padding character */
710 	tgetstr("pc", &bufp);
711 	if (bufp != tbuf)
712 		PC = *tbuf;
713 	else
714 		PC = 0;
715 
716 	bufp = tbuf;		/* get string entries */
717 	cap = tstr;
718 	for (code = tcap; *code; code += 2)
719 		**cap++ = (char *)tgetstr(code, &bufp);
720 
721 	/* get pertinent lengths */
722 	if (HO)
723 		lHO = strlen(HO);
724 	if (BC)
725 		lBC = strlen(BC);
726 	else
727 		lBC = 1;
728 	if (UP)
729 		lUP = strlen(UP);
730 	if (ND)
731 		lND = strlen(ND);
732 	if (LI < 24 || CO < 72 || !(CL && UP && ND))
733 		return (0);
734 	linect = calloc(LI + 1, sizeof(int));
735 	return (1);
736 }
737