1 /*	$OpenBSD: read_bsd_terminfo.c,v 1.14 2003/06/17 21:56:24 millert Exp $	*/
2 
3 /*
4  * Copyright (c) 2006, 2009 Thorsten Glaser <tg@mirbsd.org>
5  * Copyright (c) 1998, 1999, 2000 Todd C. Miller <Todd.Miller@courtesan.com>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  *
19  * The following disclaimer must also be retained in all copies:
20  *
21  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
22  * the utmost extent permitted by applicable law, neither express nor
23  * implied; without malicious intent or gross negligence. In no event
24  * may a licensor, author or contributor be held liable for indirect,
25  * direct, other damage, loss, or other issues arising in any way out
26  * of dealing in the work, even if advised of the possibility of such
27  * damage or existence of a defect, except proven that it results out
28  * of said person's immediate fault when using the work as intended.
29  */
30 
31 #include <curses.priv.h>
32 #include <tic.h>
33 #include <term.h>	/* lines, columns, cur_term */
34 #include <term_entry.h>
35 
36 __RCSID("$MirOS: src/lib/libncurses/src/ncurses/tinfo/read_bsd_terminfo.c,v 1.6 2009/09/06 12:46:46 tg Exp $");
37 
38 #ifndef _PATH_TERMINFO
39 #define _PATH_TERMINFO	"/usr/share/misc/terminfo"
40 #endif /* ! _PATH_TERMINFO */
41 
42 static char _path_terminfo[] = _PATH_TERMINFO;
43 
44 /* Function prototypes for private functions, */
45 static int _nc_lookup_bsd_terminfo_entry(char *, char *, TERMTYPE * const);
46 
47 /*
48  * Look up ``tn'' in the BSD terminfo.db file and fill in ``tp''
49  * with the info we find there.
50  * Returns 1 on success, 0 on failure.
51  */
52 int
_nc_read_bsd_terminfo_entry(const char * const tn_,char * const filename,TERMTYPE * const tp)53 _nc_read_bsd_terminfo_entry(const char * const tn_, char * const filename,
54     TERMTYPE * const tp)
55 {
56     char **fname, *p;
57     char   envterm[PATH_MAX];		/* local copy of $TERMINFO */
58     char   hometerm[PATH_MAX];		/* local copy of $HOME/.terminfo */
59     char  *pathvec[4];			/* list of possible terminfo files */
60     char  *tn;
61     size_t len;
62 
63     if ((tn = strdup(tn_)) == NULL)
64 	return (0);
65 
66     fname = pathvec;
67     /* $TERMINFO may hold a path to a terminfo file */
68     if (use_terminfo_vars() && (p = getenv("TERMINFO")) != NULL) {
69 	len = strlcpy(envterm, p, sizeof(envterm));
70 	if (len < sizeof(envterm))
71 	    *fname++ = envterm;
72     }
73 
74     /* Also check $HOME/.terminfo if it exists */
75     if (use_terminfo_vars() && (p = getenv("HOME")) != NULL && *p != '\0') {
76 	len = snprintf(hometerm, sizeof(hometerm), "%s/.terminfo", p);
77 	if (len > 0 && len < sizeof(hometerm))
78 	    *fname++ = hometerm;
79     }
80 
81     /* Finally we check the system terminfo file */
82     *fname++ = _path_terminfo;
83     *fname = NULL;
84 
85     /*
86      * Lookup ``tn'' in each possible terminfo file until
87      * we find it or reach the end.
88      */
89     for (fname = pathvec; *fname; fname++) {
90 	if (_nc_lookup_bsd_terminfo_entry(tn, *fname, tp) == 1) {
91 	    /* Set copyout parameter and return */
92 	    (void)strlcpy(filename, *fname, PATH_MAX);
93 	    free(tn);
94 	    return (1);
95 	}
96     }
97     free(tn);
98     return (0);
99 }
100 
101 /*
102  * Given a path /path/to/terminfo/X/termname, look up termname
103  * /path/to/terminfo.db and fill in ``tp'' with the info we find there.
104  * Returns 1 on success, 0 on failure.
105  */
106 int
_nc_read_bsd_terminfo_file(const char * const filename,TERMTYPE * const tp)107 _nc_read_bsd_terminfo_file(const char * const filename, TERMTYPE * const tp)
108 {
109     char path[PATH_MAX];		/* path to terminfo.db */
110     char *tname;			/* name of terminal to look up */
111     char *p;
112 
113     (void)strlcpy(path, filename, sizeof(path));
114 
115     /* Split filename into path and term name components. */
116     if ((tname = strrchr(path, '/')) == NULL)
117 	return (0);
118     *tname++ = '\0';
119     if ((p = strrchr(path, '/')) == NULL)
120 	return (0);
121     *p = '\0';
122 
123     return (_nc_lookup_bsd_terminfo_entry(tname, path, tp));
124 }
125 
126 /*
127  * Look up ``tn'' in the BSD terminfo file ``filename'' and fill in
128  * ``tp'' with the info we find there.
129  * Returns 1 on success, 0 on failure.
130  */
131 static int
_nc_lookup_bsd_terminfo_entry(char * tn,char * filename,TERMTYPE * const tp)132 _nc_lookup_bsd_terminfo_entry(char *tn, char *filename, TERMTYPE * const tp)
133 {
134     char  *pathvec[2], *sfn;
135     char  *capbuf, *cptr, *infobuf, *iptr;
136     int    error;
137     size_t len;
138     ENTRY  thisentry;
139 
140     if (asprintf(&sfn, "getcap(%s)", filename) == -1)
141 	sfn = filename;
142 
143     pathvec[0] = filename;
144     pathvec[1] = NULL;
145     capbuf = NULL;
146     infobuf = NULL;
147 
148     _nc_set_source(sfn);		/* For useful error messages */
149 
150     /* Don't prepend any hardcoded entries. */
151     (void) cgetset(NULL);
152 
153     /* Lookup tn in 'filename' */
154     error = cgetent(&capbuf, pathvec, tn);
155     if (error == 0) {
156 	/*
157 	 * To make the terminfo parser happy we need to, as a minimum,
158 	 * 1) convert ':' separators to ','
159 	 * 2) add a newline after the name field
160 	 * 3) add a newline at the end of the entry
161 	 */
162 
163 	/* Add space for 2 extra newlines and the final NUL */
164 	infobuf = malloc(strlen(capbuf) + 3);
165 	if (infobuf == NULL) {
166 	    error = TRUE;
167 	    goto done;
168 	}
169 
170 	/* Copy name and aliases, adding a newline. */
171 	cptr = strchr(capbuf, ':');
172 	if (cptr == NULL) {
173 	    error = TRUE;
174 	    goto done;
175 	}
176 	len = cptr - capbuf;
177 	memcpy(infobuf, capbuf, len);
178 	iptr = infobuf + len;
179 	*iptr++ = ',';
180 	*iptr++ = '\n';
181 
182 	/* Copy the rest of capbuf, converting ':' -> ',' */
183 	for (++cptr; *cptr; ++cptr)
184 		if ((*cptr == '\\') || (*cptr == '^')) {
185 			*iptr++ = *cptr++;
186 			if (!*cptr)
187 				break;
188 			*iptr++ = *cptr;
189 		} else if (*cptr == ':')
190 			*iptr++ = ',';
191 		else
192 			*iptr++ = *cptr;
193 	*iptr++ = '\n';
194 	*iptr = '\0';
195 
196 	_nc_reset_input(NULL, infobuf);
197 	memset(&thisentry, 0, sizeof (thisentry));
198 	if (_nc_parse_entry(&thisentry, FALSE, FALSE) == ERR) {
199 		error = TRUE;
200 		goto done;
201 	}
202 	*tp = thisentry.tterm;
203     }
204 
205 done:
206     if (capbuf)
207 	free(capbuf);
208     if (infobuf)
209 	free(infobuf);
210     cgetclose();
211 
212     _nc_set_source("");
213     if (sfn != filename)
214 	free(sfn);
215 
216     return ((error == 0));
217 }
218