ncurses 5.4
[ncurses.git] / ncurses / tinfo / lib_termcap.c
1 /****************************************************************************
2  * Copyright (c) 1998-2002,2003 Free Software Foundation, Inc.              *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28
29 /****************************************************************************
30  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
31  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32  *                                                                          *
33  * some of the code in here was contributed by:                             *
34  * Magnus Bengtsson, d6mbeng@dtek.chalmers.se (Nov'93)                      *
35  ****************************************************************************/
36
37 #define __INTERNAL_CAPS_VISIBLE
38 #include <curses.priv.h>
39
40 #include <termcap.h>
41 #include <tic.h>
42 #include <ctype.h>
43
44 #include <term_entry.h>
45
46 MODULE_ID("$Id: lib_termcap.c,v 1.44 2003/05/24 21:10:28 tom Exp $")
47
48 #define CSI       233
49 #define ESC       033           /* ^[ */
50 #define L_BRACK   '['
51 #define SHIFT_OUT 017           /* ^N */
52
53 NCURSES_EXPORT_VAR(char *) UP = 0;
54 NCURSES_EXPORT_VAR(char *) BC = 0;
55
56 static char *fix_me = 0;
57
58 static char *
59 set_attribute_9(int flag)
60 {
61     const char *result;
62
63     if ((result = tparm(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, flag)) == 0)
64         result = "";
65     return strdup(result);
66 }
67
68 static int
69 is_csi(char *s)
70 {
71     if (UChar(s[0]) == CSI)
72         return 1;
73     else if (s[0] == ESC && s[1] == L_BRACK)
74         return 2;
75     return 0;
76 }
77
78 static char *
79 skip_zero(char *s)
80 {
81     if (s[0] == '0') {
82         if (s[1] == ';')
83             s += 2;
84         else if (isalpha(UChar(s[1])))
85             s += 1;
86     }
87     return s;
88 }
89
90 static bool
91 similar_sgr(char *a, char *b)
92 {
93     int csi_a = is_csi(a);
94     int csi_b = is_csi(b);
95
96     if (csi_a != 0 && csi_b != 0 && csi_a == csi_b) {
97         a += csi_a;
98         b += csi_b;
99         if (*a != *b) {
100             a = skip_zero(a);
101             b = skip_zero(b);
102         }
103     }
104     return strcmp(a, b) == 0;
105 }
106
107 /***************************************************************************
108  *
109  * tgetent(bufp, term)
110  *
111  * In termcap, this function reads in the entry for terminal `term' into the
112  * buffer pointed to by bufp. It must be called before any of the functions
113  * below are called.
114  * In this terminfo emulation, tgetent() simply calls setupterm() (which
115  * does a bit more than tgetent() in termcap does), and returns its return
116  * value (1 if successful, 0 if no terminal with the given name could be
117  * found, or -1 if no terminal descriptions have been installed on the
118  * system).  The bufp argument is ignored.
119  *
120  ***************************************************************************/
121
122 NCURSES_EXPORT(int)
123 tgetent(char *bufp GCC_UNUSED, const char *name)
124 {
125     int errcode;
126
127     T((T_CALLED("tgetent()")));
128
129     setupterm((NCURSES_CONST char *) name, STDOUT_FILENO, &errcode);
130
131     PC = 0;
132     UP = 0;
133     BC = 0;
134     fix_me = 0;
135
136     if (errcode == 1) {
137
138         if (cursor_left)
139             if ((backspaces_with_bs = !strcmp(cursor_left, "\b")) == 0)
140                 backspace_if_not_bs = cursor_left;
141
142         /* we're required to export these */
143         if (pad_char != NULL)
144             PC = pad_char[0];
145         if (cursor_up != NULL)
146             UP = cursor_up;
147         if (backspace_if_not_bs != NULL)
148             BC = backspace_if_not_bs;
149
150         /*
151          * While 'sgr0' is the "same" as termcap 'me', there is a compatibility
152          * issue.  The sgr/sgr0 capabilities include setting/clearing alternate
153          * character set mode.  A termcap application cannot use sgr, so sgr0
154          * strings that reset alternate character set mode will be
155          * misinterpreted.  Here, we remove those from the more common
156          * ISO/ANSI/VT100 entries, which have sgr0 agreeing with sgr.
157          */
158         if (exit_attribute_mode != 0
159             && set_attributes != 0) {
160             char *on = set_attribute_9(1);
161             char *off = set_attribute_9(0);
162             char *tmp;
163             size_t i, j, k;
164
165             if (similar_sgr(off, exit_attribute_mode)
166                 && !similar_sgr(off, on)) {
167                 TR(TRACE_DATABASE, ("adjusting sgr0 : %s", _nc_visbuf(off)));
168                 FreeIfNeeded(fix_me);
169                 fix_me = off;
170                 for (i = 0; off[i] != '\0'; ++i) {
171                     if (on[i] != off[i]) {
172                         j = strlen(off);
173                         k = strlen(on);
174                         while (j != 0
175                                && k != 0
176                                && off[j - 1] == on[k - 1]) {
177                             --j, --k;
178                         }
179                         while (off[j] != '\0') {
180                             off[i++] = off[j++];
181                         }
182                         off[i] = '\0';
183                         break;
184                     }
185                 }
186                 /* SGR 10 would reset to normal font */
187                 if ((i = is_csi(off)) != 0
188                     && off[strlen(off) - 1] == 'm') {
189                     tmp = skip_zero(off + i);
190                     if (tmp[0] == '1'
191                         && skip_zero(tmp + 1) != tmp + 1) {
192                         i = tmp - off;
193                         if (off[i - 1] == ';')
194                             i--;
195                         j = skip_zero(tmp + 1) - off;
196                         while (off[j] != '\0') {
197                             off[i++] = off[j++];
198                         }
199                         off[i] = '\0';
200                     }
201                 }
202                 TR(TRACE_DATABASE, ("...adjusted me : %s", _nc_visbuf(fix_me)));
203                 if (!strcmp(fix_me, exit_attribute_mode)) {
204                     TR(TRACE_DATABASE, ("...same result, discard"));
205                     free(fix_me);
206                     fix_me = 0;
207                 }
208             }
209             free(on);
210         }
211
212         (void) baudrate();      /* sets ospeed as a side-effect */
213
214 /* LINT_PREPRO
215 #if 0*/
216 #include <capdefaults.c>
217 /* LINT_PREPRO
218 #endif*/
219
220     }
221     returnCode(errcode);
222 }
223
224 /***************************************************************************
225  *
226  * tgetflag(str)
227  *
228  * Look up boolean termcap capability str and return its value (TRUE=1 if
229  * present, FALSE=0 if not).
230  *
231  ***************************************************************************/
232
233 NCURSES_EXPORT(int)
234 tgetflag(NCURSES_CONST char *id)
235 {
236     unsigned i;
237
238     T((T_CALLED("tgetflag(%s)"), id));
239     if (cur_term != 0) {
240         TERMTYPE *tp = &(cur_term->type);
241         for_each_boolean(i, tp) {
242             const char *capname = ExtBoolname(tp, i, boolcodes);
243             if (!strncmp(id, capname, 2)) {
244                 /* setupterm forces invalid booleans to false */
245                 returnCode(tp->Booleans[i]);
246             }
247         }
248     }
249     returnCode(0);              /* Solaris does this */
250 }
251
252 /***************************************************************************
253  *
254  * tgetnum(str)
255  *
256  * Look up numeric termcap capability str and return its value, or -1 if
257  * not given.
258  *
259  ***************************************************************************/
260
261 NCURSES_EXPORT(int)
262 tgetnum(NCURSES_CONST char *id)
263 {
264     unsigned i;
265
266     T((T_CALLED("tgetnum(%s)"), id));
267     if (cur_term != 0) {
268         TERMTYPE *tp = &(cur_term->type);
269         for_each_number(i, tp) {
270             const char *capname = ExtNumname(tp, i, numcodes);
271             if (!strncmp(id, capname, 2)) {
272                 if (!VALID_NUMERIC(tp->Numbers[i]))
273                     returnCode(ABSENT_NUMERIC);
274                 returnCode(tp->Numbers[i]);
275             }
276         }
277     }
278     returnCode(ABSENT_NUMERIC);
279 }
280
281 /***************************************************************************
282  *
283  * tgetstr(str, area)
284  *
285  * Look up string termcap capability str and return a pointer to its value,
286  * or NULL if not given.
287  *
288  ***************************************************************************/
289
290 NCURSES_EXPORT(char *)
291 tgetstr(NCURSES_CONST char *id, char **area)
292 {
293     unsigned i;
294     char *result = NULL;
295
296     T((T_CALLED("tgetstr(%s,%p)"), id, area));
297     if (cur_term != 0) {
298         TERMTYPE *tp = &(cur_term->type);
299         for_each_string(i, tp) {
300             const char *capname = ExtStrname(tp, i, strcodes);
301             if (!strncmp(id, capname, 2)) {
302                 result = tp->Strings[i];
303                 TR(TRACE_DATABASE, ("found match : %s", _nc_visbuf(result)));
304                 /* setupterm forces canceled strings to null */
305                 if (VALID_STRING(result)) {
306                     if (result == exit_attribute_mode
307                         && fix_me != 0) {
308                         result = fix_me;
309                         TR(TRACE_DATABASE, ("altered to : %s", _nc_visbuf(result)));
310                     }
311                     if (area != 0
312                         && *area != 0) {
313                         (void) strcpy(*area, result);
314                         *area += strlen(*area) + 1;
315                     }
316                 }
317                 break;
318             }
319         }
320     }
321     returnPtr(result);
322 }