26763: fix problem on failed cd -s to relative path
[zsh.git] / Src / Modules / termcap.c
blob5e4cfa07fecebd75abb8d9a74fa2d6a36a9887a2
1 /*
2 * termcap.c - termcap manipulation through curses
4 * This file is part of zsh, the Z shell.
6 * Copyright (c) 1992-1997 Paul Falstad
7 * All rights reserved.
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and to distribute modified versions of this software for any
12 * purpose, provided that the above copyright notice and the following
13 * two paragraphs appear in all copies of this software.
15 * In no event shall Paul Falstad or the Zsh Development Group be liable
16 * to any party for direct, indirect, special, incidental, or consequential
17 * damages arising out of the use of this software and its documentation,
18 * even if Paul Falstad and the Zsh Development Group have been advised of
19 * the possibility of such damage.
21 * Paul Falstad and the Zsh Development Group specifically disclaim any
22 * warranties, including, but not limited to, the implied warranties of
23 * merchantability and fitness for a particular purpose. The software
24 * provided hereunder is on an "as is" basis, and Paul Falstad and the
25 * Zsh Development Group have no obligation to provide maintenance,
26 * support, updates, enhancements, or modifications.
31 * We need to include the zsh headers later to avoid clashes with
32 * the definitions on some systems, however we need the configuration
33 * file to decide whether we should avoid curses.h, which clashes
34 * with several zsh constants on some systems (e.g. SunOS 4).
36 #include "../../config.h"
38 #ifdef HAVE_TGETENT
39 # if defined(ZSH_HAVE_CURSES_H) && defined(ZSH_HAVE_TERM_H)
40 # define USES_TERM_H 1
41 # else
42 # ifdef HAVE_TERMCAP_H
43 # define USES_TERMCAP_H 1
44 # endif
45 # endif
46 #endif
48 #include "termcap.mdh"
49 #include "termcap.pro"
51 /**/
52 #ifdef HAVE_TGETENT
53 # ifdef USES_TERM_H
54 # ifdef HAVE_TERMIO_H
55 # include <termio.h>
56 # endif
57 # ifdef ZSH_HAVE_CURSES_H
58 # include "../zshcurses.h"
59 # endif
60 # include "../zshterm.h"
61 # else
62 # ifdef USES_TERMCAP_H
63 # include <termcap.h>
64 # endif
65 # endif
67 #ifndef HAVE_BOOLCODES
68 static char *boolcodes[] = {
69 "bw", "am", "ut", "cc", "xs", "YA", "YF", "YB", "xt", "xn", "eo",
70 "gn", "hc", "HC", "km", "YC", "hs", "hl", "in", "YG", "da", "db",
71 "mi", "ms", "nx", "xb", "NP", "ND", "NR", "os", "5i", "YD", "YE",
72 "es", "hz", "ul", "xo", NULL};
73 #endif
75 /**/
76 static int
77 ztgetflag(char *s)
79 char **b;
81 /* ncurses can tell if an existing boolean capability is *
82 * off, but other curses variants can't, so we fudge it. *
83 * This feature of ncurses appears to have gone away as *
84 * of NCURSES_MAJOR_VERSION == 5, so don't rely on it. */
85 switch (tgetflag(s)) {
86 case -1:
87 break;
88 case 0:
89 for (b = (char **)boolcodes; *b; ++b)
90 if (s[0] == (*b)[0] && s[1] == (*b)[1])
91 return 0;
92 break;
93 default:
94 return 1;
96 return -1;
99 /* echotc: output a termcap */
101 /**/
102 static int
103 bin_echotc(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
105 char *s, buf[2048], *t, *u;
106 int num, argct;
108 s = *argv++;
109 if (termflags & TERM_BAD)
110 return 1;
111 if ((termflags & TERM_UNKNOWN) && (isset(INTERACTIVE) || !init_term()))
112 return 1;
113 /* if the specified termcap has a numeric value, display it */
114 if ((num = tgetnum(s)) != -1) {
115 printf("%d\n", num);
116 return 0;
118 /* if the specified termcap is boolean, and set, say so */
119 switch (ztgetflag(s)) {
120 case -1:
121 break;
122 case 0:
123 puts("no");
124 return 0;
125 default:
126 puts("yes");
127 return 0;
129 /* get a string-type capability */
130 u = buf;
131 t = tgetstr(s, &u);
132 if (t == (char *)-1 || !t || !*t) {
133 /* capability doesn't exist, or (if boolean) is off */
134 zwarnnam(name, "no such capability: %s", s);
135 return 1;
137 /* count the number of arguments required */
138 for (argct = 0, u = t; *u; u++)
139 if (*u == '%') {
140 if (u++, (*u == 'd' || *u == '2' || *u == '3' || *u == '.' ||
141 *u == '+'))
142 argct++;
144 /* check that the number of arguments provided is correct */
145 if (arrlen(argv) != argct) {
146 zwarnnam(name, (arrlen(argv) < argct) ? "not enough arguments" :
147 "too many arguments");
148 return 1;
150 /* output string, through the proper termcap functions */
151 if (!argct)
152 tputs(t, 1, putraw);
153 else {
154 /* This assumes arguments of <lines> <columns> for cap 'cm' */
155 num = (argv[1]) ? atoi(argv[1]) : atoi(*argv);
156 tputs(tgoto(t, num, atoi(*argv)), 1, putraw);
158 return 0;
161 static struct builtin bintab[] = {
162 BUILTIN("echotc", 0, bin_echotc, 1, -1, 0, NULL, NULL),
165 /**/
166 static HashNode
167 gettermcap(UNUSED(HashTable ht), const char *name)
169 int len, num;
170 char *tcstr, buf[2048], *u, *nameu;
171 Param pm = NULL;
173 /* This depends on the termcap stuff in init.c */
174 if (termflags & TERM_BAD)
175 return NULL;
176 if ((termflags & TERM_UNKNOWN) && (isset(INTERACTIVE) || !init_term()))
177 return NULL;
180 nameu = dupstring(name);
181 unmetafy(nameu, &len);
183 pm = (Param) hcalloc(sizeof(struct param));
184 pm->node.nam = nameu;
185 pm->node.flags = PM_READONLY;
186 u = buf;
188 /* logic in the following cascade copied from echotc, above */
190 if ((num = tgetnum(nameu)) != -1) {
191 pm->gsu.i = &nullsetinteger_gsu;
192 pm->u.val = num;
193 pm->node.flags |= PM_INTEGER;
194 return &pm->node;
197 pm->gsu.s = &nullsetscalar_gsu;
198 switch (ztgetflag(nameu)) {
199 case -1:
200 break;
201 case 0:
202 pm->u.str = dupstring("no");
203 pm->node.flags |= PM_SCALAR;
204 return &pm->node;
205 default:
206 pm->u.str = dupstring("yes");
207 pm->node.flags |= PM_SCALAR;
208 return &pm->node;
210 if ((tcstr = tgetstr(nameu, &u)) != NULL && tcstr != (char *)-1) {
211 pm->u.str = dupstring(tcstr);
212 pm->node.flags |= PM_SCALAR;
213 } else {
214 /* zwarn("no such capability: %s", name); */
215 pm->u.str = dupstring("");
216 pm->node.flags |= PM_UNSET;
218 return &pm->node;
221 /**/
222 static void
223 scantermcap(UNUSED(HashTable ht), ScanFunc func, int flags)
225 Param pm = NULL;
226 int num;
227 char **capcode, *tcstr, buf[2048], *u;
229 #ifndef HAVE_NUMCODES
230 static char *numcodes[] = {
231 "co", "it", "lh", "lw", "li", "lm", "sg", "ma", "Co", "pa", "MW",
232 "NC", "Nl", "pb", "vt", "ws", "Yo", "Yp", "Ya", "BT", "Yc", "Yb",
233 "Yd", "Ye", "Yf", "Yg", "Yh", "Yi", "Yk", "Yj", "Yl", "Ym", "Yn",
234 NULL};
235 #endif
237 #ifndef HAVE_STRCODES
238 static char *zstrcodes[] = {
239 "ac", "bt", "bl", "cr", "ZA", "ZB", "ZC", "ZD", "cs", "rP", "ct",
240 "MC", "cl", "cb", "ce", "cd", "ch", "CC", "CW", "cm", "do", "ho",
241 "vi", "le", "CM", "ve", "nd", "ll", "up", "vs", "ZE", "dc", "dl",
242 "DI", "ds", "DK", "hd", "eA", "as", "SA", "mb", "md", "ti", "dm",
243 "mh", "ZF", "ZG", "im", "ZH", "ZI", "ZJ", "ZK", "ZL", "mp", "mr",
244 "mk", "ZM", "so", "ZN", "ZO", "us", "ZP", "SX", "ec", "ae", "RA",
245 "me", "te", "ed", "ZQ", "ei", "ZR", "ZS", "ZT", "ZU", "se", "ZV",
246 "ZW", "ue", "ZX", "RX", "PA", "fh", "vb", "ff", "fs", "WG", "HU",
247 "i1", "is", "i3", "if", "iP", "Ic", "Ip", "ic", "al", "ip", "K1",
248 "K3", "K2", "kb", "@1", "kB", "K4", "K5", "@2", "ka", "kC", "@3",
249 "@4", "@5", "@6", "kt", "kD", "kL", "kd", "kM", "@7", "@8", "kE",
250 "kS", "@9", "k0", "k1", "k;", "F1", "F2", "F3", "F4", "F5", "F6",
251 "F7", "F8", "F9", "k2", "FA", "FB", "FC", "FD", "FE", "FF", "FG",
252 "FH", "FI", "FJ", "k3", "FK", "FL", "FM", "FN", "FO", "FP", "FQ",
253 "FR", "FS", "FT", "k4", "FU", "FV", "FW", "FX", "FY", "FZ", "Fa",
254 "Fb", "Fc", "Fd", "k5", "Fe", "Ff", "Fg", "Fh", "Fi", "Fj", "Fk",
255 "Fl", "Fm", "Fn", "k6", "Fo", "Fp", "Fq", "Fr", "k7", "k8", "k9",
256 "@0", "%1", "kh", "kI", "kA", "kl", "kH", "%2", "%3", "%4", "%5",
257 "kN", "%6", "%7", "kP", "%8", "%9", "%0", "&1", "&2", "&3", "&4",
258 "&5", "kr", "&6", "&9", "&0", "*1", "*2", "*3", "*4", "*5", "*6",
259 "*7", "*8", "*9", "kF", "*0", "#1", "#2", "#3", "#4", "%a", "%b",
260 "%c", "%d", "%e", "%f", "kR", "%g", "%h", "%i", "%j", "!1", "!2",
261 "kT", "!3", "&7", "&8", "ku", "ke", "ks", "l0", "l1", "la", "l2",
262 "l3", "l4", "l5", "l6", "l7", "l8", "l9", "Lf", "LF", "LO", "mo",
263 "mm", "ZY", "ZZ", "Za", "Zb", "Zc", "Zd", "nw", "Ze", "oc", "op",
264 "pc", "DC", "DL", "DO", "Zf", "IC", "SF", "AL", "LE", "Zg", "RI",
265 "Zh", "SR", "UP", "Zi", "pk", "pl", "px", "pn", "ps", "pO", "pf",
266 "po", "PU", "QD", "RC", "rp", "RF", "r1", "r2", "r3", "rf", "rc",
267 "cv", "sc", "sf", "sr", "Zj", "sa", "Sb", "Zk", "Zl", "SC", "sp",
268 "Sf", "ML", "Zm", "MR", "Zn", "st", "Zo", "Zp", "wi", "Zq", "Zr",
269 "Zs", "Zt", "Zu", "Zv", "ta", "Zw", "ts", "TO", "uc", "hu", "u0",
270 "u1", "u2", "u3", "u4", "u5", "u6", "u7", "u8", "u9", "WA", "XF",
271 "XN", "Zx", "S8", "Yv", "Zz", "Xy", "Zy", "ci", "Yw", "Yx", "dv",
272 "S1", "Yy", "S2", "S4", "S3", "S5", "Gm", "Km", "Mi", "S6", "xl",
273 "RQ", "S7", "s0", "s1", "s2", "s3", "AB", "AF", "Yz", "ML", "YZ",
274 "MT", "Xh", "Xl", "Xo", "Xr", "Xt", "Xv", "sA", "sL", NULL};
275 #endif
277 pm = (Param) hcalloc(sizeof(struct param));
278 u = buf;
280 pm->node.flags = PM_READONLY | PM_SCALAR;
281 pm->gsu.s = &nullsetscalar_gsu;
283 for (capcode = (char **)boolcodes; *capcode; capcode++) {
284 if ((num = ztgetflag(*capcode)) != -1) {
285 pm->u.str = num ? dupstring("yes") : dupstring("no");
286 pm->node.nam = dupstring(*capcode);
287 func(&pm->node, flags);
291 pm->node.flags = PM_READONLY | PM_INTEGER;
292 pm->gsu.i = &nullsetinteger_gsu;
294 for (capcode = (char **)numcodes; *capcode; capcode++) {
295 if ((num = tgetnum(*capcode)) != -1) {
296 pm->u.val = num;
297 pm->node.nam = dupstring(*capcode);
298 func(&pm->node, flags);
302 pm->node.flags = PM_READONLY | PM_SCALAR;
303 pm->gsu.s = &nullsetscalar_gsu;
305 for (capcode = (char **)
306 #ifdef HAVE_STRCODES
307 strcodes
308 #else
309 zstrcodes
310 #endif
311 ; *capcode; capcode++) {
312 if ((tcstr = (char *)tgetstr(*capcode,&u)) != NULL &&
313 tcstr != (char *)-1) {
314 pm->u.str = dupstring(tcstr);
315 pm->node.nam = dupstring(*capcode);
316 func(&pm->node, flags);
321 struct paramdef partab[] = {
322 SPECIALPMDEF("termcap", PM_READONLY, NULL, gettermcap, scantermcap)
325 /**/
326 #endif /* HAVE_TGETENT */
328 static struct features module_features = {
329 #ifdef HAVE_TGETENT
330 bintab, sizeof(bintab)/sizeof(*bintab),
331 #else
332 NULL, 0,
333 #endif
334 NULL, 0,
335 NULL, 0,
336 #ifdef HAVE_TGETENT
337 partab, sizeof(partab)/sizeof(*partab),
338 #else
339 NULL, 0,
340 #endif
344 /**/
346 setup_(UNUSED(Module m))
348 return 0;
351 /**/
353 features_(Module m, char ***features)
355 *features = featuresarray(m, &module_features);
356 return 0;
359 /**/
361 enables_(Module m, int **enables)
363 return handlefeatures(m, &module_features, enables);
366 /**/
368 boot_(Module m)
370 #ifdef HAVE_TGETENT
371 # ifdef HAVE_SETUPTERM
372 setupterm((char *)0, 1, (int *)0);
373 # endif
374 #endif
375 return 0;
378 /**/
380 cleanup_(Module m)
382 return setfeatureenables(m, &module_features, NULL);
385 /**/
387 finish_(UNUSED(Module m))
389 return 0;