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