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