xref: /openbsd-src/lib/libcurses/tinfo/lib_setup.c (revision 92dd1ec0a89df25171bc5d61a3d95ea1a68cef0b)
1 /*	$OpenBSD: lib_setup.c,v 1.1 1999/01/18 19:10:19 millert Exp $	*/
2 
3 /****************************************************************************
4  * Copyright (c) 1998 Free Software Foundation, Inc.                        *
5  *                                                                          *
6  * Permission is hereby granted, free of charge, to any person obtaining a  *
7  * copy of this software and associated documentation files (the            *
8  * "Software"), to deal in the Software without restriction, including      *
9  * without limitation the rights to use, copy, modify, merge, publish,      *
10  * distribute, distribute with modifications, sublicense, and/or sell       *
11  * copies of the Software, and to permit persons to whom the Software is    *
12  * furnished to do so, subject to the following conditions:                 *
13  *                                                                          *
14  * The above copyright notice and this permission notice shall be included  *
15  * in all copies or substantial portions of the Software.                   *
16  *                                                                          *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
20  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
23  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
24  *                                                                          *
25  * Except as contained in this notice, the name(s) of the above copyright   *
26  * holders shall not be used in advertising or otherwise to promote the     *
27  * sale, use or other dealings in this Software without prior written       *
28  * authorization.                                                           *
29  ****************************************************************************/
30 
31 /****************************************************************************
32  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
33  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
34  ****************************************************************************/
35 
36 
37 /*
38  * Terminal setup routines common to termcap and terminfo:
39  *
40  *		use_env(bool)
41  *		setupterm(char *, int, int *)
42  */
43 
44 #include <curses.priv.h>
45 #include <tic.h>	/* for MAX_NAME_SIZE */
46 
47 #if defined(SVR4_TERMIO) && !defined(_POSIX_SOURCE)
48 #define _POSIX_SOURCE
49 #endif
50 
51 #include <term.h>	/* lines, columns, cur_term */
52 
53 MODULE_ID("$From: lib_setup.c,v 1.48 1999/01/02 23:11:56 tom Exp $")
54 
55 /****************************************************************************
56  *
57  * Terminal size computation
58  *
59  ****************************************************************************/
60 
61 #if HAVE_SIZECHANGE
62 # if !defined(sun) || !TERMIOS
63 #  if HAVE_SYS_IOCTL_H
64 #   include <sys/ioctl.h>
65 #  endif
66 # endif
67 #endif
68 
69 #if NEED_PTEM_H
70  /* On SCO, they neglected to define struct winsize in termios.h -- it's only
71   * in termio.h and ptem.h (the former conflicts with other definitions).
72   */
73 # include <sys/stream.h>
74 # include <sys/ptem.h>
75 #endif
76 
77 /*
78  * SCO defines TIOCGSIZE and the corresponding struct.  Other systems (SunOS,
79  * Solaris, IRIX) define TIOCGWINSZ and struct winsize.
80  */
81 #ifdef TIOCGSIZE
82 # define IOCTL_WINSIZE TIOCGSIZE
83 # define STRUCT_WINSIZE struct ttysize
84 # define WINSIZE_ROWS(n) (int)n.ts_lines
85 # define WINSIZE_COLS(n) (int)n.ts_cols
86 #else
87 # ifdef TIOCGWINSZ
88 #  define IOCTL_WINSIZE TIOCGWINSZ
89 #  define STRUCT_WINSIZE struct winsize
90 #  define WINSIZE_ROWS(n) (int)n.ws_row
91 #  define WINSIZE_COLS(n) (int)n.ws_col
92 # endif
93 #endif
94 
95 static int _use_env = TRUE;
96 
97 static void do_prototype(void);
98 
99 void use_env(bool f)
100 {
101 	_use_env = f;
102 }
103 
104 int LINES, COLS, TABSIZE;
105 
106 static void _nc_get_screensize(int *linep, int *colp)
107 /* Obtain lines/columns values from the environment and/or terminfo entry */
108 {
109 	/* figure out the size of the screen */
110 	T(("screen size: terminfo lines = %d columns = %d", lines, columns));
111 
112 	if (!_use_env)
113 	{
114 	    *linep = (int)lines;
115 	    *colp  = (int)columns;
116 	}
117 	else	/* usually want to query LINES and COLUMNS from environment */
118 	{
119 	    int value;
120 
121 	    *linep = *colp = 0;
122 
123 	    /* first, look for environment variables */
124 	    if ((value = _nc_getenv_num("LINES")) > 0) {
125 		    *linep = value;
126 	    }
127 	    if ((value = _nc_getenv_num("COLUMNS")) > 0) {
128 		    *colp = value;
129 	    }
130 	    T(("screen size: environment LINES = %d COLUMNS = %d",*linep,*colp));
131 
132 #ifdef __EMX__
133 	    if (*linep <= 0 || *colp <= 0)
134 	    {
135 		int screendata[2];
136 		_scrsize(screendata);
137 		*colp  = screendata[0];
138 		*linep = screendata[1];
139 	    	T(("EMX screen size: environment LINES = %d COLUMNS = %d",*linep,*colp));
140 	    }
141 #endif
142 #if HAVE_SIZECHANGE
143 	    /* if that didn't work, maybe we can try asking the OS */
144 	    if (*linep <= 0 || *colp <= 0)
145 	    {
146 		if (isatty(cur_term->Filedes))
147 		{
148 		    STRUCT_WINSIZE size;
149 
150 		    errno = 0;
151 		    do {
152 			if (ioctl(cur_term->Filedes, IOCTL_WINSIZE, &size) < 0
153 				&& errno != EINTR)
154 			    goto failure;
155 		    } while
156 			(errno == EINTR);
157 
158 		    /*
159 		     * Solaris lets users override either dimension with an
160 		     * environment variable.
161 		     */
162 		    if (*linep <= 0)
163 			*linep = WINSIZE_ROWS(size);
164 		    if (*colp <= 0)
165 			*colp  = WINSIZE_COLS(size);
166 		}
167 		/* FALLTHRU */
168 	    failure:;
169 	    }
170 #endif /* HAVE_SIZECHANGE */
171 
172 	    /* if we can't get dynamic info about the size, use static */
173 	    if (*linep <= 0 || *colp <= 0)
174 		if (lines > 0 && columns > 0)
175 		{
176 		    *linep = (int)lines;
177 		    *colp  = (int)columns;
178 		}
179 
180 	    /* the ultimate fallback, assume fixed 24x80 size */
181 	    if (*linep <= 0 || *colp <= 0)
182 	    {
183 		*linep = 24;
184 		*colp  = 80;
185 	    }
186 
187 	    /*
188 	     * Put the derived values back in the screen-size caps, so
189 	     * tigetnum() and tgetnum() will do the right thing.
190 	     */
191 	    lines   = (short)(*linep);
192 	    columns = (short)(*colp);
193 	}
194 
195 	T(("screen size is %dx%d", *linep, *colp));
196 
197 	if (init_tabs != -1)
198 		TABSIZE = (int)init_tabs;
199 	else
200 		TABSIZE = 8;
201 	T(("TABSIZE = %d", TABSIZE));
202 
203 }
204 
205 #if USE_SIZECHANGE
206 void _nc_update_screensize(void)
207 {
208 	int my_lines, my_cols;
209 
210 	_nc_get_screensize(&my_lines, &my_cols);
211 	if (SP != 0 && SP->_resize != 0)
212 		SP->_resize(my_lines, my_cols);
213 }
214 #endif
215 
216 /****************************************************************************
217  *
218  * Terminal setup
219  *
220  ****************************************************************************/
221 
222 #define ret_error(code, fmt, arg)	if (errret) {\
223 					    *errret = code;\
224 					    returnCode(ERR);\
225 					} else {\
226 					    fprintf(stderr, fmt, arg);\
227 					    exit(EXIT_FAILURE);\
228 					}
229 
230 #define ret_error0(code, msg)		if (errret) {\
231 					    *errret = code;\
232 					    returnCode(ERR);\
233 					} else {\
234 					    fprintf(stderr, msg);\
235 					    exit(EXIT_FAILURE);\
236 					}
237 
238 #if USE_DATABASE
239 static int grab_entry(const char *const tn, TERMTYPE *const tp)
240 /* return 1 if entry found, 0 if not found, -1 if database not accessible */
241 {
242 	char	filename[PATH_MAX];
243 	int	status = 0;
244 	int	_nc_read_bsd_terminfo_entry(const char *, TERMTYPE *); /* XXX */
245 
246 #ifdef __OpenBSD__
247 	status = _nc_read_bsd_terminfo_entry(tn, tp);
248 #endif /* __OpenBSD__ */
249 
250 	if (status != 1 && (status = _nc_read_entry(tn, filename, tp)) != 1) {
251 
252 #ifndef PURE_TERMINFO
253 		/*
254 		 * Try falling back on the termcap file.
255 		 * Note:  allowing this call links the entire terminfo/termcap
256 		 * compiler into the startup code.  It's preferable to build a
257 		 * real terminfo database and use that.
258 		 */
259 		status = _nc_read_termcap_entry(tn, tp);
260 #endif /* PURE_TERMINFO */
261 
262 	}
263 
264 	/*
265 	 * If we have an entry, force all of the cancelled strings to null
266 	 * pointers so we don't have to test them in the rest of the library.
267 	 * (The terminfo compiler bypasses this logic, since it must know if
268 	 * a string is cancelled, for merging entries).
269 	 */
270 	if (status == 1) {
271 		unsigned n;
272 		for (n = 0; n < BOOLCOUNT; n++)
273 			if (!VALID_BOOLEAN(tp->Booleans[n]))
274 				tp->Booleans[n] = FALSE;
275 		for (n = 0; n < STRCOUNT; n++)
276 			if (tp->Strings[n] == CANCELLED_STRING)
277 				tp->Strings[n] = ABSENT_STRING;
278 	}
279 	return(status);
280 }
281 #endif
282 
283 char ttytype[NAMESIZE];
284 
285 /*
286  *	setupterm(termname, Filedes, errret)
287  *
288  *	Find and read the appropriate object file for the terminal
289  *	Make cur_term point to the structure.
290  *
291  */
292 
293 int setupterm(NCURSES_CONST char *tname, int Filedes, int *errret)
294 {
295 struct term	*term_ptr;
296 int status;
297 
298 	T((T_CALLED("setupterm(\"%s\",%d,%p)"), tname, Filedes, errret));
299 
300 	if (tname == 0) {
301 		tname = getenv("TERM");
302 		if (tname == 0 || *tname == '\0') {
303 			ret_error0(-1, "TERM environment variable not set.\n");
304                 }
305 	}
306 	if (strlen(tname) > MAX_NAME_SIZE) {
307 		ret_error(-1, "TERM environment must be <= %d characters.\n",
308 		    MAX_NAME_SIZE);
309 	}
310 
311 	T(("your terminal name is %s", tname));
312 
313 	term_ptr = typeCalloc(TERMINAL, 1);
314 
315 	if (term_ptr == 0) {
316 		ret_error0(-1, "Not enough memory to create terminal structure.\n") ;
317         }
318 #if USE_DATABASE
319 	status = grab_entry(tname, &term_ptr->type);
320 #else
321 	status = 0;
322 #endif
323 
324 	/* try fallback list if entry on disk */
325 	if (status != 1)
326 	{
327 	    const TERMTYPE	*fallback = _nc_fallback(tname);
328 
329 	    if (fallback)
330 	    {
331 		memcpy(&term_ptr->type, fallback, sizeof(TERMTYPE));
332 		status = 1;
333 	    }
334 	}
335 
336 	if (status == -1)
337 	{
338 		ret_error0(-1, "terminals database is inaccessible\n");
339 	}
340 	else if (status == 0)
341 	{
342 		ret_error(0, "'%s': unknown terminal type.\n", tname);
343 	}
344 
345 	set_curterm(term_ptr);
346 
347 	if (command_character  &&  getenv("CC"))
348 		do_prototype();
349 
350 	strlcpy(ttytype, cur_term->type.term_names, NAMESIZE);
351 
352 	/*
353 	 * Allow output redirection.  This is what SVr3 does.
354 	 * If stdout is directed to a file, screen updates go
355 	 * to standard error.
356 	 */
357 	if (Filedes == STDOUT_FILENO && !isatty(Filedes))
358 	    Filedes = STDERR_FILENO;
359 	cur_term->Filedes = Filedes;
360 
361 	_nc_get_screensize(&LINES, &COLS);
362 
363 	if (errret)
364 		*errret = 1;
365 
366 	T((T_CREATE("screen %s %dx%d"), tname, LINES, COLS));
367 
368 	if (generic_type) {
369 		ret_error(0, "'%s': I need something more specific.\n", tname);
370 	}
371 	if (hard_copy) {
372 		ret_error(1, "'%s': I can't handle hardcopy terminals.\n", tname);
373 	}
374 	returnCode(OK);
375 }
376 
377 /*
378 **	do_prototype()
379 **
380 **	Take the real command character out of the CC environment variable
381 **	and substitute it in for the prototype given in 'command_character'.
382 **
383 */
384 
385 static void
386 do_prototype(void)
387 {
388 int	i, j;
389 char	CC;
390 char	proto;
391 char    *tmp;
392 
393 	tmp = getenv("CC");
394 	CC = *tmp;
395 	proto = *command_character;
396 
397 	for (i=0; i < STRCOUNT; i++) {
398 		j = 0;
399 		while (cur_term->type.Strings[i][j]) {
400 			if (cur_term->type.Strings[i][j] == proto)
401 				cur_term->type.Strings[i][j] = CC;
402 			j++;
403 		}
404 	}
405 }
406