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