xref: /illumos-gate/usr/src/lib/libcurses/screen/print.c (revision bd335c6465ddbafe543900df4b03247bfa288eff)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2001 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1988 AT&T	*/
28 /*	  All Rights Reserved	*/
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/types.h>
45 #include "curses_inc.h"
46 #include "print.h"
47 #include <signal.h>   /* use this file to determine if this is SVR4.0 system */
48 
49 #ifdef SIGSTOP	/* SVR4.0 and beyond */
50 #define	_ULIBTI	"/usr/share/lib/terminfo"
51 #else
52 #define	_ULIBTI	"/usr/lib/terminfo"
53 #endif
54 
55 char *progname;
56 
57 /* global variables */
58 static enum printtypes printing = pr_none;
59 static int onecolumn = 0;		/* print a single column */
60 static int width = 60;			/* width of multi-column printing */
61 static int restrictterm = 1;		/* restrict termcap names */
62 
63 /* local variables */
64 static int printed = 0;
65 static size_t caplen = 0;
66 
67 void
68 pr_init(enum printtypes type)
69 {
70 	printing = type;
71 }
72 
73 void
74 pr_onecolumn(int onoff)
75 {
76 	onecolumn = onoff;
77 }
78 
79 void
80 pr_width(int nwidth)
81 {
82 	if (nwidth > 0)
83 		width = nwidth;
84 }
85 
86 void
87 pr_caprestrict(int onoff)
88 {
89 	restrictterm = onoff;
90 }
91 
92 static char capbools[] =
93 	"ambsbwdadbeoeshchshzinkmmimsncnsosptulxbxnxoxsxt";
94 static int ncapbools = sizeof (capbools) / sizeof (capbools[0]);
95 
96 static char capnums[] =
97 	"codBdCdFdNdTknlipbsgug";
98 static int ncapnums = sizeof (capnums) / sizeof (capnums[0]);
99 
100 static char capstrs[] =
101 	"ALDCDLDOICLERISFSRUPaealasbcbtcdcechclcmcsctcvdcdldmdsedeifshoi1i2i"
102 	    "cifimipisk0k1k2k3k4k5k6k7k8k9kbkdkekhklkokrkskul0l1l2l3l4l5l6l7l"
103 	    "8l9ndnlpcr1r2r3rcrfrpscsesosrsttetitsucueupusvbvevivs";
104 static int ncapstrs = sizeof (capstrs) / sizeof (capstrs[0]);
105 
106 static int
107 findcapname(char *capname, char *caplist, int listsize)
108 {
109 	int low = 0, mid, high = listsize - 2;
110 	while (low <= high) {
111 		mid = (low + high) / 4 * 2;
112 		if (capname[0] == caplist[mid]) {
113 			if (capname[1] == caplist[mid + 1])
114 				return (1);
115 			else if (capname[1] < caplist[mid + 1])
116 				high = mid - 2;
117 			else
118 				low = mid + 2;
119 		} else if (capname[0] < caplist[mid])
120 			high = mid - 2;
121 		else
122 			low = mid + 2;
123 	}
124 	return (0);
125 /*
126  *	for (; *caplist; caplist += 2)
127  *		if (caplist[0] == capname[0] && caplist[1] == capname[1])
128  *			return (1);
129  *	return (0);
130  */
131 }
132 
133 /*
134  *  Print out the first line of an entry.
135  */
136 void
137 pr_heading(char *term, char *synonyms)
138 {
139 	int	do_print = 0;	/* Can we print the path of the file ? */
140 	char	buffer[512];	/* Holds search pathname */
141 	FILE	*work_fp;	/* Used to try and open the files */
142 	char	tail[4];	/* Used for terminfo pathname suffix */
143 	char	*terminfo;	/* The value of $TERMINFO */
144 
145 
146 	/*
147 	 *	Try to obtain $TERMINFO
148 	 */
149 	terminfo = getenv("TERMINFO");
150 
151 	if (term == (char *)0)
152 		term = "";
153 	/*
154 	 *	Build the suffix for this device
155 	 */
156 	tail[0] = '/';
157 	tail[1] = *term;
158 	tail[2] = '/';
159 	tail[3] = '\0';
160 
161 	/*
162 	 *	If we have it - use it, otherwise use /usr/share/lib/terminfo
163 	 *	as base directory
164 	 */
165 	if (terminfo != NULL)
166 		(void) sprintf(buffer, "%s%s%s", terminfo, tail, term);
167 	else
168 		(void) sprintf(buffer, "%s%s%s", _ULIBTI, tail, term);
169 
170 	/*
171 	 *	Attempt to open the file.
172 	 */
173 	if ((work_fp = fopen(buffer, "r")) == NULL) {
174 		/*
175 		 * Open failed. If we were looking in /usr/share/lib/terminfo
176 		 *	we are done, otherwise look there next.
177 		 */
178 		if (strncmp(buffer, _ULIBTI, strlen(_ULIBTI)) == 0) {
179 				/*
180 				 * We are done. Not in /usr/share/lib/terminfo,
181 				 *	and $TERMINFO is not set.
182 				 */
183 				(void) fprintf(stderr, "Error: Term \"%s\" not "
184 				    "found in %s\n", term, _ULIBTI);
185 		} else {
186 			/*
187 			 * Check /usr/share/lib/terminfo last. If this fails,
188 			 * all hope is lost as we know it is not in $TERMINFO.
189 			 */
190 			(void) sprintf(buffer, "%s%s%s", _ULIBTI, tail, term);
191 
192 			if ((work_fp = fopen(buffer, "r")) == NULL) {
193 				/*
194 				 *	All hope is lost
195 				 */
196 				(void) fprintf(stderr, "Error: Term \"%s\" not "
197 				    "found in %s or %s\n", term, _ULIBTI,
198 				    getenv("TERMINFO"));
199 			} else do_print = 1;
200 		}
201 	} else do_print = 1;
202 
203 	/*
204 	 *	If we found it - print the comment(after closing the file)
205 	 */
206 	if (do_print && *term) {
207 		(void) fclose(work_fp);
208 		(void) printf("#	Reconstructed via infocmp from file: "
209 		    "%s\n", buffer);
210 	}
211 
212 	switch ((int)printing) {
213 		case (int)pr_terminfo:
214 			(void) printf("%s,\n", synonyms);
215 			break;
216 		case (int)pr_cap:
217 			(void) printf("%s:\\\n", synonyms);
218 			caplen = strlen(synonyms) + 1;
219 			break;
220 		case (int)pr_longnames:
221 			(void) printf("Terminal type %s\n", term);
222 			(void) printf("  %s\n", synonyms);
223 			break;
224 	}
225 }
226 
227 void
228 pr_bheading(void)
229 {
230 	if (printing == pr_longnames)
231 		(void) printf("flags\n");
232 	printed = 0;
233 }
234 
235 void
236 pr_boolean(char *infoname, char *capname, char *fullname, int value)
237 {
238 	int	vlen;
239 	size_t	nlen;
240 
241 	if (printing == pr_cap && restrictterm &&
242 	    !findcapname(capname, capbools, ncapbools))
243 		return;
244 
245 	if (onecolumn) {
246 		if (value < 0)
247 			switch ((int)printing) {
248 				case (int)pr_terminfo:
249 					(void) printf("\t%s@,\n", infoname);
250 					break;
251 				case (int)pr_cap:
252 					(void) printf("\t:%s@:\\\n", capname);
253 					caplen += 4 + strlen(capname);
254 					break;
255 				case (int)pr_longnames:
256 					(void) printf("  %s@\n", fullname);
257 			}
258 		else
259 			switch ((int)printing) {
260 				case (int)pr_terminfo:
261 					(void) printf("\t%s,\n", infoname);
262 					break;
263 				case (int)pr_cap:
264 					(void) printf("\t:%s:\\\n", capname);
265 					caplen += 3 + strlen(capname);
266 					break;
267 				case (int)pr_longnames:
268 					(void) printf("  %s\n", fullname);
269 			}
270 	} else {
271 		switch ((int)printing) {
272 			case (int)pr_terminfo:	nlen = strlen(infoname);
273 						break;
274 			case (int)pr_cap:	nlen = strlen(capname);
275 						break;
276 			case (int)pr_longnames:
277 						nlen = strlen(fullname);
278 						break;
279 		}
280 		vlen = (value < 0) ? 1 : 0;
281 		if ((printed > 0) && (printed + nlen + vlen + 1 > width)) {
282 			switch ((int)printing) {
283 				case (int)pr_terminfo:
284 				case (int)pr_longnames:
285 						(void) printf("\n");
286 						break;
287 				case (int)pr_cap:
288 						(void) printf(":\\\n");
289 						caplen += 1;
290 			}
291 			printed = 0;
292 		}
293 		if (printed == 0) {
294 			switch ((int)printing) {
295 				case (int)pr_terminfo:
296 					(void) printf("\t");
297 					printed = 8;
298 					break;
299 				case (int)pr_cap:
300 					(void) printf("\t:");
301 					printed = 9;
302 					caplen += 2;
303 					break;
304 				case (int)pr_longnames:
305 					(void) printf("  ");
306 					printed = 2;
307 			}
308 		} else {
309 			switch ((int)printing) {
310 				case (int)pr_terminfo:
311 				case (int)pr_longnames:
312 					(void) printf(" ");
313 					break;
314 				case (int)pr_cap:
315 					(void) printf(":");
316 					caplen += 1;
317 			}
318 			printed++;
319 		}
320 		if (value < 0)
321 			switch ((int)printing) {
322 				case (int)pr_terminfo:
323 					(void) printf("%s@,", infoname);
324 					printed += nlen + 2;
325 					break;
326 				case (int)pr_cap:
327 					(void) printf("%s@", capname);
328 					printed += nlen + 1;
329 					caplen += nlen + 1;
330 					break;
331 				case (int)pr_longnames:
332 					(void) printf("%s@,", fullname);
333 					printed += nlen + 2;
334 			}
335 		else
336 			switch ((int)printing) {
337 				case (int)pr_terminfo:
338 					(void) printf("%s,", infoname);
339 					printed += nlen + 1;
340 					break;
341 				case (int)pr_cap:
342 					(void) printf("%s", capname);
343 					printed += nlen;
344 					caplen += nlen;
345 					break;
346 				case (int)pr_longnames:
347 					(void) printf("%s,", fullname);
348 					printed += nlen + 1;
349 			}
350 	}
351 }
352 
353 void
354 pr_bfooting(void)
355 {
356 	if (!onecolumn && (printed > 0))
357 		switch ((int)printing) {
358 			case (int)pr_terminfo:
359 			case (int)pr_longnames:
360 				(void) printf("\n");
361 				break;
362 			case (int)pr_cap:
363 				(void) printf(":\\\n");
364 			caplen += 1;
365 	    }
366 }
367 
368 void
369 pr_nheading(void)
370 {
371 	if (printing == pr_longnames)
372 		(void) printf("\nnumbers\n");
373 	printed = 0;
374 }
375 
376 /*
377  *  Return the length of the number if it were printed out
378  *  with %d. The number is guaranteed to be in the range
379  *  0..maxshort.
380  */
381 static int
382 digitlen(int value)
383 {
384 	return (value >= 10000 ? 5 :
385 	    value >=  1000 ? 4 :
386 	    value >=   100 ? 3 :
387 	    value >=    10 ? 2 :
388 	    value >=	0 ? 1 : 0);
389 }
390 
391 void
392 pr_number(char *infoname, char *capname, char *fullname, int value)
393 {
394 	int	vlen;
395 	size_t	nlen;
396 
397 	if (printing == pr_cap && restrictterm &&
398 	    !findcapname(capname, capnums, ncapnums))
399 		return;
400 
401 	if (onecolumn) {
402 		if (value < 0)
403 			switch ((int)printing) {
404 				case (int)pr_terminfo:
405 					(void) printf("\t%s@,\n", infoname);
406 					break;
407 				case (int)pr_cap:
408 					(void) printf("\t:%s@:\\\n", capname);
409 					caplen += 4 + strlen(capname);
410 					break;
411 				case (int)pr_longnames:
412 					(void) printf("  %s @\n", fullname);
413 			}
414 		else
415 			switch ((int)printing) {
416 				case (int)pr_terminfo:
417 					(void) printf("\t%s#%d,\n", infoname,
418 					    value);
419 					break;
420 				case (int)pr_cap:
421 					(void) printf("\t:%s#%d:\\\n",
422 					    capname, value);
423 					caplen += 4 + strlen(capname) +
424 					    digitlen(value);
425 					break;
426 				case (int)pr_longnames:
427 					(void) printf("  %s = %d\n", fullname,
428 					    value);
429 			}
430 	} else {
431 		switch ((int)printing) {
432 			case (int)pr_terminfo:
433 					nlen = strlen(infoname);
434 					break;
435 			case (int)pr_cap:
436 					nlen = strlen(capname);
437 					break;
438 			case (int)pr_longnames:
439 					nlen = strlen(fullname);
440 					break;
441 		}
442 		vlen = digitlen(value);
443 		if ((printed > 0) && (printed + nlen + vlen + 2 > width)) {
444 			switch ((int)printing) {
445 				case (int)pr_terminfo:
446 				case (int)pr_longnames:
447 					(void) printf("\n");
448 					break;
449 				case (int)pr_cap:
450 					(void) printf(":\\\n");
451 					caplen += 1;
452 			}
453 			printed = 0;
454 		}
455 		if (printed == 0) {
456 			switch ((int)printing) {
457 				case (int)pr_terminfo:
458 					(void) printf("\t");
459 					printed = 8;
460 					break;
461 				case (int)pr_cap:
462 					(void) printf("\t:");
463 					printed = 9;
464 					caplen += 2;
465 					break;
466 				case (int)pr_longnames:
467 					(void) printf("  ");
468 					printed = 2;
469 			}
470 		} else {
471 			switch ((int)printing) {
472 				case (int)pr_terminfo:
473 				case (int)pr_longnames:
474 					(void) printf(" ");
475 					break;
476 				case (int)pr_cap:
477 					(void) printf(":");
478 					caplen += 1;
479 			}
480 			printed++;
481 		}
482 		if (value < 0) {
483 			switch ((int)printing) {
484 				case (int)pr_terminfo:
485 					(void) printf("%s@,", infoname);
486 					printed += nlen + 2;
487 					break;
488 				case (int)pr_cap:
489 					(void) printf("%s@", capname);
490 					printed += nlen + 1;
491 					caplen += nlen + 1;
492 					break;
493 				case (int)pr_longnames:
494 					(void) printf("%s@,", fullname);
495 					printed += nlen + 2;
496 			}
497 		} else
498 			switch ((int)printing) {
499 				case (int)pr_terminfo:
500 					(void) printf("%s#%d,", infoname,
501 					    value);
502 					printed += nlen + vlen + 2;
503 					break;
504 				case (int)pr_cap:
505 					(void) printf("%s#%d", capname, value);
506 					printed += nlen + vlen + 1;
507 					caplen += nlen + vlen + 1;
508 					break;
509 				case (int)pr_longnames:
510 					(void) printf("%s = %d,", fullname,
511 					    value);
512 					printed += nlen + vlen + 4;
513 			}
514 	}
515 }
516 
517 void
518 pr_nfooting(void)
519 {
520 	if (!onecolumn && (printed > 0))
521 		switch ((int)printing) {
522 			case (int)pr_terminfo:
523 			case (int)pr_longnames:
524 				(void) printf("\n");
525 				break;
526 			case (int)pr_cap:
527 				(void) printf(":\\\n");
528 				caplen += 1;
529 		}
530 }
531 
532 void
533 pr_sheading(void)
534 {
535 	if (printing == pr_longnames)
536 		(void) printf("\nstrings\n");
537 	printed = 0;
538 }
539 
540 void
541 pr_string(char *infoname, char *capname, char *fullname, char *value)
542 {
543 	char *evalue;
544 	int badcapvalue;
545 	size_t nlen, vlen;
546 
547 	if (printing == pr_cap) {
548 		if (restrictterm && !findcapname(capname, capstrs, ncapstrs))
549 			return;
550 		if (value)
551 			value = infotocap(value, &badcapvalue);
552 	}
553 
554 	if (onecolumn) {
555 		if (value == NULL)
556 			switch ((int)printing) {
557 				case (int)pr_terminfo:
558 					(void) printf("\t%s@,\n", infoname);
559 					break;
560 				case (int)pr_cap:
561 					(void) printf("\t:%s@:\\\n", capname);
562 					caplen += 4 + strlen(capname);
563 					break;
564 				case (int)pr_longnames:
565 					(void) printf("  %s@\n", fullname);
566 			}
567 		else
568 			switch ((int)printing) {
569 				case (int)pr_terminfo:
570 					(void) printf("\t%s=", infoname);
571 					tpr(stdout, value);
572 					(void) printf(",\n");
573 					break;
574 				case (int)pr_cap:
575 					(void) printf("\t:%s%s=",
576 					    badcapvalue ? "." : "", capname);
577 					caplen += 3 + strlen(capname) +
578 					    (badcapvalue ? 1 : 0);
579 					caplen += cpr(stdout, value);
580 					(void) printf(":\\\n");
581 					caplen += 1;
582 					break;
583 				case (int)pr_longnames:
584 					(void) printf("  %s = '", fullname);
585 					tpr(stdout, value);
586 					(void) printf("'\n");
587 			}
588 	} else {
589 		switch ((int)printing) {
590 			case (int)pr_terminfo:
591 				nlen = strlen(infoname);
592 				break;
593 			case (int)pr_cap:
594 				nlen = strlen(capname);
595 				if (badcapvalue)
596 					nlen++;
597 				break;
598 			case (int)pr_longnames:
599 				nlen = strlen(fullname);
600 		}
601 		if (value == NULL)
602 			vlen = 1;
603 		else
604 			if (printing == pr_cap)
605 				vlen = strlen(evalue = cexpand(value));
606 			else
607 				vlen = strlen(evalue = iexpand(value));
608 		if ((printed > 0) && (printed + nlen + vlen + 1 > width)) {
609 			switch ((int)printing) {
610 				case (int)pr_terminfo:
611 				case (int)pr_longnames:
612 					(void) printf("\n");
613 					break;
614 				case (int)pr_cap:
615 					(void) printf(":\\\n");
616 					caplen += 1;
617 			}
618 			printed = 0;
619 		}
620 		if (printed == 0) {
621 			switch ((int)printing) {
622 				case (int)pr_terminfo:
623 					(void) printf("\t");
624 					printed = 8;
625 					break;
626 				case (int)pr_cap:
627 					(void) printf("\t:");
628 					printed = 9;
629 					caplen += 2;
630 					break;
631 				case (int)pr_longnames:
632 					(void) printf("  ");
633 					printed = 2;
634 			}
635 		} else {
636 			switch ((int)printing) {
637 				case (int)pr_terminfo:
638 				case (int)pr_longnames:
639 					(void) printf(" ");
640 					break;
641 				case (int)pr_cap:
642 					(void) printf(":");
643 					caplen += 1;
644 			}
645 			printed++;
646 		}
647 		if (value == NULL) {
648 			switch ((int)printing) {
649 				case (int)pr_terminfo:
650 					(void) printf("%s@,", infoname);
651 					printed += nlen + 2;
652 					break;
653 				case (int)pr_cap:
654 					(void) printf("%s@", capname);
655 					printed += nlen + 1;
656 					caplen += nlen + 1;
657 					break;
658 				case (int)pr_longnames:
659 					(void) printf("%s@,", fullname);
660 					printed += nlen + 2;
661 			}
662 		} else
663 			switch ((int)printing) {
664 				case (int)pr_terminfo:
665 					(void) printf("%s=%s,", infoname,
666 					    evalue);
667 					printed += nlen + vlen + 2;
668 					break;
669 				case (int)pr_cap:
670 					if (badcapvalue) {
671 						(void) printf(".");
672 						caplen += 1;
673 					}
674 					(void) printf("%s=%s", capname,
675 					    evalue);
676 					printed += nlen + vlen + 1;
677 					caplen += nlen + vlen + 1;
678 					break;
679 				case (int)pr_longnames:
680 					(void) printf("%s = '%s',", fullname,
681 					    evalue);
682 					printed += nlen + vlen + 6;
683 			}
684 	}
685 }
686 
687 void
688 pr_sfooting(void)
689 {
690 	if (onecolumn) {
691 		if (printing == pr_cap)
692 			(void) printf("\n");
693 	} else {
694 		if (printed > 0)
695 			switch ((int)printing) {
696 				case (int)pr_terminfo:
697 				case (int)pr_longnames:
698 					(void) printf("\n");
699 					break;
700 				case (int)pr_cap:
701 					(void) printf(":\n");
702 					caplen += 1;
703 			}
704 	}
705 	if (caplen >= 1024) {
706 		(void) fprintf(stderr, "%s: WARNING: termcap entry is too "
707 		    "long!\n", progname);
708 	}
709 
710 	if (printing == pr_longnames)
711 		(void) printf("end of strings\n");
712 }
713