1/*
2 * terminfo.c - parameter interface to terminfo via curses
3 *
4 * This file is part of zsh, the Z shell.
5 *
6 * Copyright (c) 2000 Sven Wishnowsky, Clint Adams
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 Sven Wishnowsky, Clint Adams or the Zsh Development Group
16 * be liable to any party for direct, indirect, special, incidental, or
17 * consequential damages arising out of the use of this software and its
18 * documentation, even if Sven Wishnowsky, Clint Adams and the Zsh
19 * Development Group have been advised of the possibility of such damage.
20 *
21 * Sven Wishnowsky, Clint Adams and the Zsh Development Group specifically
22 * disclaim any warranties, including, but not limited to, the implied
23 * warranties of merchantability and fitness for a particular purpose.
24 * The software provided hereunder is on an "as is" basis, and Sven
25 * Wishnowsky, Clint Adams and the Zsh Development Group have no obligation
26 * to provide maintenance, support, updates, enhancements, or modifications.
27 *
28 */
29
30#define USES_TERM_H 1
31#include "terminfo.mdh"
32
33#if defined(HAVE_TIGETFLAG) && defined(ZSH_HAVE_CURSES_H)
34# define USE_TERMINFO_MODULE 1
35#else
36# undef USE_TERMINFO_MODULE
37#endif
38
39#include "terminfo.pro"
40
41/**/
42#ifdef USE_TERMINFO_MODULE
43
44/* The following two undefs are needed for Solaris 2.6 */
45# ifdef VINTR
46#  undef VINTR
47# endif
48# ifdef offsetof
49#  undef offsetof
50# endif
51
52#ifdef ZSH_HAVE_CURSES_H
53# include "../zshcurses.h"
54#endif
55
56# ifdef ZSH_HAVE_TERM_H
57#  include "../zshterm.h"
58# endif
59
60/* echoti: output a terminfo capability */
61
62/**/
63static int
64bin_echoti(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
65{
66    char *s, *t, **u;
67    int arg, num, strarg = 0;
68    long pars[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
69    char *strcap[] = { "pfkey", "pfloc", "pfx", "pln", "pfxl", NULL };
70
71    s = *argv++;
72    /* This depends on the termcap stuff in init.c */
73    if (termflags & TERM_BAD)
74	return 1;
75    if ((termflags & TERM_UNKNOWN) && (isset(INTERACTIVE) || !init_term()))
76	return 1;
77    /* if the specified capability has a numeric value, display it */
78    if (((num = tigetnum(s)) != -1) && (num != -2)) {
79	printf("%d\n", num);
80	return 0;
81    }
82
83    switch (tigetflag(s)) {
84    case -1:
85	break;
86    case 0:
87	puts("no");
88	return 0;
89    default:
90	puts("yes");
91	return 0;
92    }
93
94/* get a string-type capability */
95    t = (char *)tigetstr(s);
96    if (!t || t == (char *)-1 || !*t) {
97	/* capability doesn't exist, or (if boolean) is off */
98	zwarnnam(name, "no such terminfo capability: %s", s);
99	return 1;
100    }
101    /* check that the number of arguments provided is not too high */
102    if (arrlen(argv) > 9) {
103        zwarnnam(name, "too many arguments");
104        return 1;
105    }
106
107    /* check if we have a capability taking non-integers for parameters */
108    for (u = strcap; *u && !strarg; u++)
109      strarg = !strcmp(s, *u);
110
111    /* get the arguments */
112    for (arg=0; argv[arg]; arg++) {
113	if (strarg && arg > 0)
114            pars[arg] = (long) argv[arg];
115	else
116            pars[arg] = atoi(argv[arg]);
117    }
118
119    /* output string, through the proper termcap functions */
120    if (!arg)
121        putp(t);
122    else {
123        putp(tparm(t, pars[0], pars[1], pars[2], pars[3], pars[4],
124	              pars[5], pars[6], pars[7], pars[8]));
125    }
126    return 0;
127}
128
129static struct builtin bintab[] = {
130    BUILTIN("echoti", 0, bin_echoti, 1, -1, 0, NULL, NULL),
131};
132
133/**/
134static HashNode
135getterminfo(UNUSED(HashTable ht), const char *name)
136{
137    int len, num;
138    char *tistr, *nameu;
139    Param pm = NULL;
140
141    /* This depends on the termcap stuff in init.c */
142    if (termflags & TERM_BAD)
143	return NULL;
144    if ((termflags & TERM_UNKNOWN) && (isset(INTERACTIVE) || !init_term()))
145	return NULL;
146
147    nameu = dupstring(name);
148    unmetafy(nameu, &len);
149
150    pm = (Param) hcalloc(sizeof(struct param));
151    pm->node.nam = nameu;
152    pm->node.flags = PM_READONLY;
153
154    if (((num = tigetnum(nameu)) != -1) && (num != -2)) {
155	pm->u.val = num;
156	pm->node.flags |= PM_INTEGER;
157	pm->gsu.i = &nullsetinteger_gsu;
158    } else if ((num = tigetflag(nameu)) != -1) {
159	pm->u.str = num ? dupstring("yes") : dupstring("no");
160	pm->node.flags |= PM_SCALAR;
161	pm->gsu.s = &nullsetscalar_gsu;
162    } else if ((tistr = (char *)tigetstr(nameu)) != NULL && tistr != (char *)-1) {
163	pm->u.str = dupstring(tistr);
164	pm->node.flags |= PM_SCALAR;
165	pm->gsu.s = &nullsetscalar_gsu;
166    } else {
167	/* zwarn("no such capability: %s", name); */
168	pm->u.str = dupstring("");
169	pm->node.flags |= PM_UNSET;
170	pm->gsu.s = &nullsetscalar_gsu;
171    }
172    return &pm->node;
173}
174
175/**/
176static void
177scanterminfo(UNUSED(HashTable ht), ScanFunc func, int flags)
178{
179    Param pm = NULL;
180    int num;
181    char **capname, *tistr;
182
183#ifndef HAVE_BOOLNAMES
184    static char *boolnames[] = {
185	"bw", "am", "bce", "ccc", "xhp", "xhpa", "cpix", "crxm", "xt", "xenl",
186	"eo", "gn", "hc", "chts", "km", "daisy", "hs", "hls", "in", "lpix",
187	"da", "db", "mir", "msgr", "nxon", "xsb", "npc", "ndscr", "nrrmc",
188	"os", "mc5i", "xvpa", "sam", "eslok", "hz", "ul", "xon", NULL};
189#endif
190
191#ifndef HAVE_NUMNAMES
192    static char *numnames[] = {
193	"cols", "it", "lh", "lw", "lines", "lm", "xmc", "ma", "colors",
194	"pairs", "wnum", "ncv", "nlab", "pb", "vt", "wsl", "bitwin",
195	"bitype", "bufsz", "btns", "spinh", "spinv", "maddr", "mjump",
196	"mcs", "mls", "npins", "orc", "orhi", "orl", "orvi", "cps", "widcs",
197	NULL};
198#endif
199
200#ifndef HAVE_STRNAMES
201    static char *strnames[] = {
202	"acsc", "cbt", "bel", "cr", "cpi", "lpi", "chr", "cvr", "csr", "rmp",
203	"tbc", "mgc", "clear", "el1", "el", "ed", "hpa", "cmdch", "cwin",
204	"cup", "cud1", "home", "civis", "cub1", "mrcup", "cnorm", "cuf1",
205	"ll", "cuu1", "cvvis", "defc", "dch1", "dl1", "dial", "dsl", "dclk",
206	"hd", "enacs", "smacs", "smam", "blink", "bold", "smcup", "smdc",
207	"dim", "swidm", "sdrfq", "smir", "sitm", "slm", "smicm", "snlq",
208	"snrmq", "prot", "rev", "invis", "sshm", "smso", "ssubm", "ssupm",
209	"smul", "sum", "smxon", "ech", "rmacs", "rmam", "sgr0", "rmcup",
210	"rmdc", "rwidm", "rmir", "ritm", "rlm", "rmicm", "rshm", "rmso",
211	"rsubm", "rsupm", "rmul", "rum", "rmxon", "pause", "hook", "flash",
212	"ff", "fsl", "wingo", "hup", "is1", "is2", "is3", "if", "iprog",
213	"initc", "initp", "ich1", "il1", "ip", "ka1", "ka3", "kb2", "kbs",
214	"kbeg", "kcbt", "kc1", "kc3", "kcan", "ktbc", "kclr", "kclo", "kcmd",
215	"kcpy", "kcrt", "kctab", "kdch1", "kdl1", "kcud1", "krmir", "kend",
216	"kent", "kel", "ked", "kext", "kf0", "kf1", "kf10", "kf11", "kf12",
217	"kf13", "kf14", "kf15", "kf16", "kf17", "kf18", "kf19", "kf2",
218	"kf20", "kf21", "kf22", "kf23", "kf24", "kf25", "kf26", "kf27",
219	"kf28", "kf29", "kf3", "kf30", "kf31", "kf32", "kf33", "kf34",
220	"kf35", "kf36", "kf37", "kf38", "kf39", "kf4", "kf40", "kf41",
221	"kf42", "kf43", "kf44", "kf45", "kf46", "kf47", "kf48", "kf49",
222	"kf5", "kf50", "kf51", "kf52", "kf53", "kf54", "kf55", "kf56",
223	"kf57", "kf58", "kf59", "kf6", "kf60", "kf61", "kf62", "kf63",
224	"kf7", "kf8", "kf9", "kfnd", "khlp", "khome", "kich1", "kil1",
225	"kcub1", "kll", "kmrk", "kmsg", "kmov", "knxt", "knp", "kopn",
226	"kopt", "kpp", "kprv", "kprt", "krdo", "kref", "krfr", "krpl",
227	"krst", "kres", "kcuf1", "ksav", "kBEG", "kCAN", "kCMD", "kCPY",
228	"kCRT", "kDC", "kDL", "kslt", "kEND", "kEOL", "kEXT", "kind",
229	"kFND", "kHLP", "kHOM", "kIC", "kLFT", "kMSG", "kMOV", "kNXT",
230	"kOPT", "kPRV", "kPRT", "kri", "kRDO", "kRPL", "kRIT", "kRES",
231	"kSAV", "kSPD", "khts", "kUND", "kspd", "kund", "kcuu1", "rmkx",
232	"smkx", "lf0", "lf1", "lf10", "lf2", "lf3", "lf4", "lf5", "lf6",
233	"lf7", "lf8", "lf9", "fln", "rmln", "smln", "rmm", "smm", "mhpa",
234	"mcud1", "mcub1", "mcuf1", "mvpa", "mcuu1", "nel", "porder", "oc",
235	"op", "pad", "dch", "dl", "cud", "mcud", "ich", "indn", "il", "cub",
236	"mcub", "cuf", "mcuf", "rin", "cuu", "mcuu", "pfkey", "pfloc",
237	"pfx", "pln", "mc0", "mc5p", "mc4", "mc5", "pulse", "qdial",
238	"rmclk", "rep", "rfi", "rs1", "rs2", "rs3", "rf", "rc", "vpa",
239	"sc", "ind", "ri", "scs", "sgr", "setb", "smgb", "smgbp", "sclk",
240	"scp", "setf", "smgl", "smglp", "smgr", "smgrp", "hts", "smgt",
241	"smgtp", "wind", "sbim", "scsd", "rbim", "rcsd", "subcs",
242	"supcs", "ht", "docr", "tsl", "tone", "uc", "hu", "u0", "u1",
243	"u2", "u3", "u4", "u5", "u6", "u7", "u8", "u9", "wait", "xoffc",
244	"xonc", "zerom", "scesa", "bicr", "binel", "birep", "csnm",
245	"csin", "colornm", "defbi", "devt", "dispc", "endbi", "smpch",
246	"smsc", "rmpch", "rmsc", "getm", "kmous", "minfo", "pctrm",
247	"pfxl", "reqmp", "scesc", "s0ds", "s1ds", "s2ds", "s3ds",
248	"setab", "setaf", "setcolor", "smglr", "slines", "smgtb",
249	"ehhlm", "elhlm", "elohlm", "erhlm", "ethlm", "evhlm", "sgr1",
250	"slength", NULL};
251#endif
252
253    pm = (Param) hcalloc(sizeof(struct param));
254
255    pm->node.flags = PM_READONLY | PM_SCALAR;
256    pm->gsu.s = &nullsetscalar_gsu;
257
258    for (capname = (char **)boolnames; *capname; capname++) {
259	if ((num = tigetflag(*capname)) != -1) {
260	    pm->u.str = num ? dupstring("yes") : dupstring("no");
261	    pm->node.nam = dupstring(*capname);
262	    func(&pm->node, flags);
263	}
264    }
265
266    pm->node.flags = PM_READONLY | PM_INTEGER;
267    pm->gsu.i = &nullsetinteger_gsu;
268
269    for (capname = (char **)numnames; *capname; capname++) {
270	if (((num = tigetnum(*capname)) != -1) && (num != -2)) {
271	    pm->u.val = num;
272	    pm->node.nam = dupstring(*capname);
273	    func(&pm->node, flags);
274	}
275    }
276
277    pm->node.flags = PM_READONLY | PM_SCALAR;
278    pm->gsu.s = &nullsetscalar_gsu;
279
280    for (capname = (char **)strnames; *capname; capname++) {
281	if ((tistr = (char *)tigetstr(*capname)) != NULL &&
282	    tistr != (char *)-1) {
283	    pm->u.str = dupstring(tistr);
284	    pm->node.nam = dupstring(*capname);
285	    func(&pm->node, flags);
286	}
287    }
288}
289
290static struct paramdef partab[] = {
291    SPECIALPMDEF("terminfo", PM_READONLY, NULL,
292		 getterminfo, scanterminfo)
293};
294
295/**/
296#endif /* USE_TERMINFO_MODULE */
297
298static struct features module_features = {
299#ifdef USE_TERMINFO_MODULE
300    bintab, sizeof(bintab)/sizeof(*bintab),
301#else
302    NULL, 0,
303#endif
304    NULL, 0,
305    NULL, 0,
306#ifdef USE_TERMINFO_MODULE
307    partab, sizeof(partab)/sizeof(*partab),
308#else
309    NULL, 0,
310#endif
311    0
312};
313
314/**/
315int
316setup_(UNUSED(Module m))
317{
318    return 0;
319}
320
321/**/
322int
323features_(Module m, char ***features)
324{
325    *features = featuresarray(m, &module_features);
326    return 0;
327}
328
329/**/
330int
331enables_(Module m, int **enables)
332{
333    return handlefeatures(m, &module_features, enables);
334}
335
336/**/
337int
338boot_(Module m)
339{
340#ifdef USE_TERMINFO_MODULE
341# ifdef HAVE_SETUPTERM
342    int errret;
343
344    /*
345     * Just because we can't set up the terminal doesn't
346     * mean the modules hasn't booted---TERM may change,
347     * and it should be handled dynamically---so ignore errors here.
348     */
349    (void)setupterm((char *)0, 1, &errret);
350# endif
351#endif
352
353    return 0;
354}
355
356/**/
357int
358cleanup_(Module m)
359{
360    return setfeatureenables(m, &module_features, NULL);
361}
362
363/**/
364int
365finish_(UNUSED(Module m))
366{
367    return 0;
368}
369