1 /* $NetBSD: term.c,v 1.15 2003/08/07 11:16:49 agc Exp $ */ 2 3 /*- 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)term.c 8.1 (Berkeley) 6/9/93"; 36 #endif 37 __RCSID("$NetBSD: term.c,v 1.15 2003/08/07 11:16:49 agc Exp $"); 38 #endif /* not lint */ 39 40 #include <sys/types.h> 41 #include <err.h> 42 #include <errno.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <termcap.h> 47 #include <ttyent.h> 48 #include <unistd.h> 49 #include "extern.h" 50 51 char *tbuf; /* Termcap entry. */ 52 53 const char *askuser __P((const char *)); 54 char *ttys __P((char *)); 55 56 /* 57 * Figure out what kind of terminal we're dealing with, and then read in 58 * its termcap entry. 59 */ 60 const char * 61 get_termcap_entry(userarg, tcapbufp, extended) 62 const char *userarg; 63 char **tcapbufp; 64 int extended; 65 { 66 struct ttyent *t; 67 int rval; 68 char *p, *ttypath; 69 const char *ttype; 70 char zz[1024], *zz_ptr; 71 char *ext_tc, *newptr; 72 73 if (userarg) { 74 ttype = userarg; 75 goto found; 76 } 77 78 /* Try the environment. */ 79 if ((ttype = getenv("TERM")) != NULL) 80 goto map; 81 82 /* Try ttyname(3); check for dialup or other mapping. */ 83 if ((ttypath = ttyname(STDERR_FILENO)) != NULL) { 84 if ((p = strrchr(ttypath, '/')) != NULL) 85 ++p; 86 else 87 p = ttypath; 88 if ((t = getttynam(p))) { 89 ttype = t->ty_type; 90 goto map; 91 } 92 } 93 94 /* If still undefined, use "unknown". */ 95 ttype = "unknown"; 96 97 map: ttype = mapped(ttype); 98 99 /* 100 * If not a path, remove TERMCAP from the environment so we get a 101 * real entry from /etc/termcap. This prevents us from being fooled 102 * by out of date stuff in the environment. 103 */ 104 found: if ((p = getenv("TERMCAP")) != NULL && *p != '/') 105 unsetenv("TERMCAP"); 106 107 /* 108 * ttype now contains a pointer to the type of the terminal. 109 * If the first character is '?', ask the user. 110 */ 111 if (ttype[0] == '?') { 112 if (ttype[1] != '\0') 113 ttype = askuser(ttype + 1); 114 else 115 ttype = askuser(NULL); 116 } 117 /* Find the termcap entry. If it doesn't exist, ask the user. */ 118 if ((tbuf = (char *) malloc(1024)) == NULL) { 119 fprintf(stderr, "Could not malloc termcap buffer\n"); 120 exit(1); 121 } 122 123 while ((rval = tgetent(tbuf, ttype)) == 0) { 124 warnx("terminal type %s is unknown", ttype); 125 ttype = askuser(NULL); 126 } 127 if (rval == -1) { 128 if (!errno) 129 errno = ENOENT; 130 err(1, NULL); 131 } 132 133 /* check if we get a truncated termcap entry, fish back the full 134 * one if need be and the user has asked for it. 135 */ 136 zz_ptr = zz; 137 if ((extended == 1) && (tgetstr("ZZ", &zz_ptr) != NULL)) { 138 /* it was, fish back the full termcap */ 139 sscanf(zz, "%p", &ext_tc); 140 if ((newptr = (char *) realloc(tbuf, strlen(ext_tc) + 1)) 141 == NULL) { 142 fprintf(stderr, 143 "reallocate of termcap falied\n"); 144 exit (1); 145 } 146 147 strcpy(newptr, ext_tc); 148 tbuf = newptr; 149 } 150 151 *tcapbufp = tbuf; 152 return (ttype); 153 } 154 155 /* Prompt the user for a terminal type. */ 156 const char * 157 askuser(dflt) 158 const char *dflt; 159 { 160 static char answer[256]; 161 char *p; 162 163 /* We can get recalled; if so, don't continue uselessly. */ 164 if (feof(stdin) || ferror(stdin)) { 165 (void)fprintf(stderr, "\n"); 166 exit(1); 167 } 168 for (;;) { 169 if (dflt) 170 (void)fprintf(stderr, "Terminal type? [%s] ", dflt); 171 else 172 (void)fprintf(stderr, "Terminal type? "); 173 (void)fflush(stderr); 174 175 if (fgets(answer, sizeof(answer), stdin) == NULL) { 176 if (dflt == NULL) { 177 (void)fprintf(stderr, "\n"); 178 exit(1); 179 } 180 return (dflt); 181 } 182 183 if ((p = strchr(answer, '\n')) != NULL) 184 *p = '\0'; 185 if (answer[0]) 186 return (answer); 187 if (dflt != NULL) 188 return (dflt); 189 } 190 } 191