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