1 /* $OpenBSD: termcap.c,v 1.8 2003/06/02 20:18:42 millert Exp $ */
2 /* $NetBSD: termcap.c,v 1.7 1995/06/05 19:45:52 pk Exp $ */
3
4 /*
5 * Copyright (c) 1980, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)termcap.c 8.1 (Berkeley) 6/4/93";
36 #else
37 static char rcsid[] = "$OpenBSD: termcap.c,v 1.8 2003/06/02 20:18:42 millert Exp $";
38 #endif
39 #endif /* not lint */
40
41 #define PBUFSIZ 512 /* max length of filename path */
42 #define PVECSIZ 32 /* max number of names in path */
43
44 #include <sys/param.h>
45 #include <stdio.h>
46 #include <ctype.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include <curses.h>
51 #include "pathnames.h"
52
53 /*
54 * termcap - routines for dealing with the terminal capability data base
55 *
56 * BUG: Should use a "last" pointer in tbuf, so that searching
57 * for capabilities alphabetically would not be a n**2/2
58 * process when large numbers of capabilities are given.
59 * Note: If we add a last pointer now we will screw up the
60 * tc capability. We really should compile termcap.
61 *
62 * Essentially all the work here is scanning and decoding escapes
63 * in string capabilities. We don't use stdio because the editor
64 * doesn't, and because living w/o it is not hard.
65 */
66
67 static char *tbuf; /* termcap buffer */
68
69 /*
70 * Get an entry for terminal name in buffer bp from the termcap file.
71 */
72 int
tgetent(bp,name)73 tgetent(bp, name)
74 char *bp, *name;
75 {
76 register char *p;
77 register char *cp;
78 char *dummy;
79 char **fname;
80 char *home;
81 int i;
82 char pathbuf[MAXPATHLEN]; /* holds raw path of filenames */
83 char *pathvec[PVECSIZ]; /* to point to names in pathbuf */
84 char **pvec; /* holds usable tail of path vector */
85 char *termpath;
86
87 fname = pathvec;
88 pvec = pathvec;
89 tbuf = bp;
90
91 cp = issetugid() ? NULL : getenv("TERMCAP");
92 /*
93 * TERMCAP can have one of two things in it. It can be the name
94 * of a file to use instead of /usr/share/misc/termcap. In this
95 * case it better start with a "/". Or it can be an entry to use
96 * so we don't have to read the file. In this case it has to
97 * already have the newlines crunched out. If TERMCAP does not
98 * hold a file name then a path of names is searched instead.
99 * The path is found in the TERMPATH variable, or becomes
100 * "$HOME/.termcap /usr/share/misc/termcap" if no TERMPATH exists.
101 */
102 if (cp == NULL) {
103 strlcpy(pathbuf, _PATH_TERMCAP, sizeof(pathbuf));
104 } else if (!cp || *cp != '/') { /* TERMCAP holds an entry */
105 if ((termpath = getenv("TERMPATH")) != NULL)
106 strlcpy(pathbuf, termpath, sizeof(pathbuf));
107 else if ((home = getenv("HOME")) == NULL || *home == '\0' ||
108 snprintf(pathbuf, sizeof(pathbuf), "%s/%s", home,
109 _PATH_DEF) >= sizeof(pathbuf))
110 strlcpy(pathbuf, _PATH_DEF, sizeof(pathbuf));
111 } else { /* user-defined path in TERMCAP */
112 /* still can be tokenized */
113 strlcpy(pathbuf, cp, sizeof(pathbuf));
114 }
115 *fname++ = pathbuf; /* tokenize path into vector of names */
116
117 /* split pathbuf into a vector of paths */
118 p = pathbuf;
119 while (*++p)
120 if (*p == ' ' || *p == ':') {
121 *p = '\0';
122 while (*++p)
123 if (*p != ' ' && *p != ':')
124 break;
125 if (*p == '\0')
126 break;
127 *fname++ = p;
128 if (fname >= pathvec + PVECSIZ) {
129 fname--;
130 break;
131 }
132 }
133 *fname = (char *) 0; /* mark end of vector */
134 if (cp && *cp && *cp != '/')
135 if (cgetset(cp) < 0)
136 return (-2);
137
138 dummy = NULL;
139 i = cgetent(&dummy, pathvec, name);
140
141 if (i == 0 && bp != NULL) {
142 strlcpy(bp, dummy, 1024);
143 if ((cp = strrchr(bp, ':')) != NULL)
144 if (cp[1] != '\0')
145 cp[1] = '\0';
146 }
147 else if (i == 0 && bp == NULL)
148 tbuf = dummy;
149 else if (dummy != NULL)
150 free(dummy);
151
152 /* no tc reference loop return code in libterm XXX */
153 if (i == -3)
154 return (-1);
155 return (i + 1);
156 }
157
158 /*
159 * Return the (numeric) option id.
160 * Numeric options look like
161 * li#80
162 * i.e. the option string is separated from the numeric value by
163 * a # character. If the option is not found we return -1.
164 * Note that we handle octal numbers beginning with 0.
165 */
166 int
tgetnum(id)167 tgetnum(id)
168 char *id;
169 {
170 long num;
171
172 if (cgetnum(tbuf, id, &num) == 0)
173 return (num);
174 else
175 return (-1);
176 }
177
178 /*
179 * Handle a flag option.
180 * Flag options are given "naked", i.e. followed by a : or the end
181 * of the buffer. Return 1 if we find the option, or 0 if it is
182 * not given.
183 */
184 int
tgetflag(id)185 tgetflag(id)
186 char *id;
187 {
188 return (cgetcap(tbuf, id, ':') != NULL);
189 }
190
191 /*
192 * Get a string valued option.
193 * These are given as
194 * cl=^Z
195 * Much decoding is done on the strings, and the strings are
196 * placed in area, which is a ref parameter which is updated.
197 * No checking on area overflow.
198 */
199 char *
tgetstr(id,area)200 tgetstr(id, area)
201 char *id, **area;
202 {
203 char ids[3];
204 char *s;
205 int i;
206
207 /*
208 * XXX
209 * This is for all the boneheaded programs that relied on tgetstr
210 * to look only at the first 2 characters of the string passed...
211 */
212 *ids = *id;
213 ids[1] = id[1];
214 ids[2] = '\0';
215
216 if ((i = cgetstr(tbuf, ids, &s)) < 0)
217 return NULL;
218
219 strlcpy(*area, s, 1024);
220 *area += i + 1;
221 return (s);
222 }
223