ncurses 4.1
[ncurses.git] / ncurses / lib_setup.c
1
2 /***************************************************************************
3 *                            COPYRIGHT NOTICE                              *
4 ****************************************************************************
5 *                ncurses is copyright (C) 1992-1995                        *
6 *                          Zeyd M. Ben-Halim                               *
7 *                          zmbenhal@netcom.com                             *
8 *                          Eric S. Raymond                                 *
9 *                          esr@snark.thyrsus.com                           *
10 *                                                                          *
11 *        Permission is hereby granted to reproduce and distribute ncurses  *
12 *        by any means and for any fee, whether alone or as part of a       *
13 *        larger distribution, in source or in binary form, PROVIDED        *
14 *        this notice is included with any such distribution, and is not    *
15 *        removed from any of its header files. Mention of ncurses in any   *
16 *        applications linked with it is highly appreciated.                *
17 *                                                                          *
18 *        ncurses comes AS IS with no warranty, implied or expressed.       *
19 *                                                                          *
20 ***************************************************************************/
21
22
23 /*
24  * Terminal setup routines common to termcap and terminfo:
25  *
26  *              use_env(bool)
27  *              setupterm(char *, int, int *)
28  */
29
30 #include <curses.priv.h>
31
32 #ifdef SVR4_TERMIO
33 #define _POSIX_SOURCE
34 #endif
35
36 #include <term.h>       /* lines, columns, cur_term */
37
38 MODULE_ID("$Id: lib_setup.c,v 1.24 1997/03/08 21:25:44 tom Exp $")
39
40 /****************************************************************************
41  *
42  * Terminal size computation
43  *
44  ****************************************************************************/
45
46 #if !defined(sun) || !HAVE_TERMIOS_H
47 #include <sys/ioctl.h>
48 #endif
49
50 static int _use_env = TRUE;
51
52 static void do_prototype(void);
53
54 void use_env(bool f)
55 {
56         _use_env = f;
57 }
58
59 int LINES, COLS, TABSIZE;
60
61 void _nc_get_screensize(void)
62 /* set LINES and COLS from the environment and/or terminfo entry */
63 {
64 char            *rows, *cols;
65
66         /* figure out the size of the screen */
67         T(("screen size: terminfo lines = %d columns = %d", lines, columns));
68
69         if (!_use_env)
70         {
71             LINES = (int)lines;
72             COLS  = (int)columns;
73         }
74         else    /* usually want to query LINES and COLUMNS from environment */
75         {
76             LINES = COLS = 0;
77
78             /* first, look for environment variables */
79             rows = getenv("LINES");
80             if (rows != (char *)NULL)
81                 LINES = atoi(rows);
82             cols = getenv("COLUMNS");
83             if (cols != (char *)NULL)
84                 COLS = atoi(cols);
85             T(("screen size: environment LINES = %d COLUMNS = %d",LINES,COLS));
86
87 #if defined(TIOCGWINSZ) && !BROKEN_TIOCGWINSZ
88             /* if that didn't work, maybe we can try asking the OS */
89             if (LINES <= 0 || COLS <= 0)
90             {
91                 if (isatty(cur_term->Filedes))
92                 {
93                     struct winsize size;
94
95                     errno = 0;
96                     do {
97                         if (ioctl(cur_term->Filedes, TIOCGWINSZ, &size) < 0
98                                 && errno != EINTR)
99                             goto failure;
100                     } while
101                         (errno == EINTR);
102
103                     LINES = (int)size.ws_row;
104                     COLS  = (int)size.ws_col;
105                 }
106                 /* FALLTHRU */
107             failure:;
108             }
109 #endif /* defined(TIOCGWINSZ) && !defined(BROKEN_TIOCGWINSZ) */
110
111             /* if we can't get dynamic info about the size, use static */
112             if (LINES <= 0 || COLS <= 0)
113                 if (lines > 0 && columns > 0)
114                 {
115                     LINES = (int)lines;
116                     COLS  = (int)columns;
117                 }
118
119             /* the ultimate fallback, assume fixed 24x80 size */
120             if (LINES <= 0 || COLS <= 0)
121             {
122                 LINES = 24;
123                 COLS  = 80;
124             }
125
126             /*
127              * Put the derived values back in the screen-size caps, so
128              * tigetnum() and tgetnum() will do the right thing.
129              */
130             lines   = (short)LINES;
131             columns = (short)COLS;
132         }
133
134         T(("screen size is %dx%d", LINES, COLS));
135
136 #ifdef init_tabs
137         if (init_tabs != -1)
138                 TABSIZE = (int)init_tabs;
139         else
140 #endif /* init_tabs */
141                 TABSIZE = 8;
142         T(("TABSIZE = %d", TABSIZE));
143
144 }
145
146 /****************************************************************************
147  *
148  * Terminal setup
149  *
150  ****************************************************************************/
151
152 #define ret_error(code, fmt, arg)       if (errret) {\
153                                             *errret = code;\
154                                             returnCode(ERR);\
155                                         } else {\
156                                             fprintf(stderr, fmt, arg);\
157                                             exit(EXIT_FAILURE);\
158                                         }
159
160 #define ret_error0(code, msg)           if (errret) {\
161                                             *errret = code;\
162                                             returnCode(ERR);\
163                                         } else {\
164                                             fprintf(stderr, msg);\
165                                             exit(EXIT_FAILURE);\
166                                         }
167
168 static int grab_entry(const char *const tn, TERMTYPE *const tp)
169 /* return 1 if entry found, 0 if not found, -1 if database not accessible */
170 {
171         char    filename[PATH_MAX];
172         int     status;
173
174         if ((status = _nc_read_entry(tn, filename, tp)) == 1)
175             return(1);
176
177 #ifndef PURE_TERMINFO
178         /*
179          * Try falling back on the termcap file.  Note: allowing this call
180          * links the entire terminfo/termcap compiler into the startup code.
181          * It's preferable to build a real terminfo database and use that.
182          */
183         status = _nc_read_termcap_entry(tn, tp);
184 #endif /* PURE_TERMINFO */
185
186         return(status);
187 }
188
189 char ttytype[NAMESIZE];
190
191 /*
192  *      setupterm(termname, Filedes, errret)
193  *
194  *      Find and read the appropriate object file for the terminal
195  *      Make cur_term point to the structure.
196  *
197  */
198
199 int setupterm(const char *tname, int Filedes, int *errret)
200 {
201 struct term     *term_ptr;
202 int status;
203
204         T((T_CALLED("setupterm(\"%s\",%d,%p)"), tname, Filedes, errret));
205
206         if (tname == NULL) {
207                 tname = getenv("TERM");
208                 if (tname == NULL)
209                         ret_error0(-1, "TERM environment variable not set.\n");
210         }
211
212         T(("your terminal name is %s", tname));
213
214         term_ptr = typeCalloc(TERMINAL, 1);
215
216         if (term_ptr == NULL)
217                 ret_error0(-1, "Not enough memory to create terminal structure.\n") ;
218         status = grab_entry(tname, &term_ptr->type);
219
220         /* try fallback list if entry on disk */
221         if (status != 1)
222         {
223             const TERMTYPE      *fallback = _nc_fallback(tname);
224
225             if (fallback)
226             {
227                 memcpy(&term_ptr->type, fallback, sizeof(TERMTYPE));
228                 status = 1;
229             }
230         }
231
232         if (status == -1)
233         {
234                 ret_error0(-1, "terminals database is inaccessible\n");
235         }
236         else if (status == 0)
237         {
238                 ret_error(0, "'%s': unknown terminal type.\n", tname);
239         }
240
241         cur_term = term_ptr;
242         if (generic_type)
243                 ret_error(0, "'%s': I need something more specific.\n", tname);
244         if (hard_copy)
245                 ret_error(1, "'%s': I can't handle hardcopy terminals.\n", tname);
246
247         if (command_character  &&  getenv("CC"))
248                 do_prototype();
249
250         strncpy(ttytype, cur_term->type.term_names, NAMESIZE - 1);
251         ttytype[NAMESIZE - 1] = '\0';
252
253         /*
254          * Allow output redirection.  This is what SVr3 does.
255          * If stdout is directed to a file, screen updates go
256          * to standard error.
257          */
258         if (Filedes == STDOUT_FILENO && !isatty(Filedes))
259             Filedes = STDERR_FILENO;
260         cur_term->Filedes = Filedes;
261
262         _nc_get_screensize();
263
264         if (errret)
265                 *errret = 1;
266
267         T((T_CREATE("screen %s %dx%d"), tname, LINES, COLS));
268
269         returnCode(OK);
270 }
271
272 /*
273 **      do_prototype()
274 **
275 **      Take the real command character out of the CC environment variable
276 **      and substitute it in for the prototype given in 'command_character'.
277 **
278 */
279
280 static void
281 do_prototype(void)
282 {
283 int     i, j;
284 char    CC;
285 char    proto;
286 char    *tmp;
287
288         tmp = getenv("CC");
289         CC = *tmp;
290         proto = *command_character;
291
292         for (i=0; i < STRCOUNT; i++) {
293                 j = 0;
294                 while (cur_term->type.Strings[i][j]) {
295                         if (cur_term->type.Strings[i][j] == proto)
296                                 cur_term->type.Strings[i][j] = CC;
297                         j++;
298                 }
299         }
300 }