PageRenderTime 62ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/external/bsd/nvi/dist/cl/cl_term.c

https://gitlab.com/storedmirrors/minix
C | 483 lines | 316 code | 40 blank | 127 comment | 113 complexity | d354e22c8a94cb46b51947f923ab096f MD5 | raw file
  1. /* $NetBSD: cl_term.c,v 1.4 2014/01/26 21:43:45 christos Exp $ */
  2. /*-
  3. * Copyright (c) 1993, 1994
  4. * The Regents of the University of California. All rights reserved.
  5. * Copyright (c) 1993, 1994, 1995, 1996
  6. * Keith Bostic. All rights reserved.
  7. *
  8. * See the LICENSE file for redistribution information.
  9. */
  10. #include "config.h"
  11. #include <sys/cdefs.h>
  12. #if 0
  13. #ifndef lint
  14. static const char sccsid[] = "Id: cl_term.c,v 10.31 2001/07/08 13:06:56 skimo Exp (Berkeley) Date: 2001/07/08 13:06:56 ";
  15. #endif /* not lint */
  16. #else
  17. __RCSID("$NetBSD: cl_term.c,v 1.4 2014/01/26 21:43:45 christos Exp $");
  18. #endif
  19. #include <sys/types.h>
  20. #include <sys/ioctl.h>
  21. #include <sys/queue.h>
  22. #include <sys/stat.h>
  23. #include <bitstring.h>
  24. #include <errno.h>
  25. #include <limits.h>
  26. #include <signal.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <termios.h>
  31. #include <unistd.h>
  32. #include "../common/common.h"
  33. #include "cl.h"
  34. static int cl_pfmap __P((SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t));
  35. /*
  36. * XXX
  37. * THIS REQUIRES THAT ALL SCREENS SHARE A TERMINAL TYPE.
  38. */
  39. typedef struct _tklist {
  40. const char *ts; /* Key's termcap string. */
  41. const char *output; /* Corresponding vi command. */
  42. const char *name; /* Name. */
  43. u_char value; /* Special value (for lookup). */
  44. } TKLIST;
  45. #define TKINIT(a, b, c) { a, b, c, 0 }
  46. static TKLIST const c_tklist[] = { /* Command mappings. */
  47. TKINIT("kil1", "O", "insert line"),
  48. TKINIT("kdch1", "x", "delete character"),
  49. TKINIT("kcud1", "j", "cursor down"),
  50. TKINIT("kel", "D", "delete to eol"),
  51. TKINIT("kind", "\004", "scroll down"), /* ^D */
  52. TKINIT("kll", "$", "go to eol"),
  53. TKINIT("kend", "$", "go to eol"),
  54. TKINIT("khome", "^", "go to sol"),
  55. TKINIT("kich1", "i", "insert at cursor"),
  56. TKINIT("kdl1", "dd", "delete line"),
  57. TKINIT("kcub1", "h", "cursor left"),
  58. TKINIT("knp", "\006", "page down"), /* ^F */
  59. TKINIT("kpp", "\002", "page up"), /* ^B */
  60. TKINIT("kri", "\025", "scroll up"), /* ^U */
  61. TKINIT("ked", "dG", "delete to end of screen"),
  62. TKINIT("kcuf1", "l", "cursor right"),
  63. TKINIT("kcuu1", "k", "cursor up"),
  64. TKINIT(NULL, NULL, NULL),
  65. };
  66. static TKLIST const m1_tklist[] = { /* Input mappings (lookup). */
  67. TKINIT(NULL, NULL, NULL),
  68. };
  69. static TKLIST const m2_tklist[] = { /* Input mappings (set or delete). */
  70. TKINIT("kcud1", "\033ja", "cursor down"), /* ^[ja */
  71. TKINIT("kcub1", "\033ha", "cursor left"), /* ^[ha */
  72. TKINIT("kcuu1", "\033ka", "cursor up"), /* ^[ka */
  73. TKINIT("kcuf1", "\033la", "cursor right"), /* ^[la */
  74. TKINIT(NULL, NULL, NULL),
  75. };
  76. /*
  77. * cl_term_init --
  78. * Initialize the special keys defined by the termcap/terminfo entry.
  79. *
  80. * PUBLIC: int cl_term_init __P((SCR *));
  81. */
  82. int
  83. cl_term_init(SCR *sp)
  84. {
  85. KEYLIST *kp;
  86. SEQ *qp;
  87. TKLIST const *tkp;
  88. char *t;
  89. CHAR_T name[60];
  90. CHAR_T output[5];
  91. CHAR_T ts[20];
  92. const CHAR_T *wp;
  93. size_t wlen;
  94. /* Command mappings. */
  95. for (tkp = c_tklist; tkp->name != NULL; ++tkp) {
  96. if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
  97. continue;
  98. CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
  99. MEMCPYW(name, wp, wlen);
  100. CHAR2INT(sp, t, strlen(t), wp, wlen);
  101. MEMCPYW(ts, wp, wlen);
  102. CHAR2INT(sp, tkp->output, strlen(tkp->output), wp, wlen);
  103. MEMCPYW(output, wp, wlen);
  104. if (seq_set(sp, name, strlen(tkp->name), ts, strlen(t),
  105. output, strlen(tkp->output), SEQ_COMMAND,
  106. SEQ_NOOVERWRITE | SEQ_SCREEN))
  107. return (1);
  108. }
  109. /* Input mappings needing to be looked up. */
  110. for (tkp = m1_tklist; tkp->name != NULL; ++tkp) {
  111. if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
  112. continue;
  113. for (kp = keylist;; ++kp)
  114. if (kp->value == tkp->value)
  115. break;
  116. if (kp == NULL)
  117. continue;
  118. CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
  119. MEMCPYW(name, wp, wlen);
  120. CHAR2INT(sp, t, strlen(t), wp, wlen);
  121. MEMCPYW(ts, wp, wlen);
  122. output[0] = (UCHAR_T)kp->ch;
  123. if (seq_set(sp, name, strlen(tkp->name), ts, strlen(t),
  124. output, 1, SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN))
  125. return (1);
  126. }
  127. /* Input mappings that are already set or are text deletions. */
  128. for (tkp = m2_tklist; tkp->name != NULL; ++tkp) {
  129. if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
  130. continue;
  131. /*
  132. * !!!
  133. * Some terminals' <cursor_left> keys send single <backspace>
  134. * characters. This is okay in command mapping, but not okay
  135. * in input mapping. That combination is the only one we'll
  136. * ever see, hopefully, so kluge it here for now.
  137. */
  138. if (!strcmp(t, "\b"))
  139. continue;
  140. if (tkp->output == NULL) {
  141. CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
  142. MEMCPYW(name, wp, wlen);
  143. CHAR2INT(sp, t, strlen(t), wp, wlen);
  144. MEMCPYW(ts, wp, wlen);
  145. if (seq_set(sp, name, strlen(tkp->name),
  146. ts, strlen(t), NULL, 0,
  147. SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN))
  148. return (1);
  149. } else {
  150. CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
  151. MEMCPYW(name, wp, wlen);
  152. CHAR2INT(sp, t, strlen(t), wp, wlen);
  153. MEMCPYW(ts, wp, wlen);
  154. CHAR2INT(sp, tkp->output, strlen(tkp->output), wp, wlen);
  155. MEMCPYW(output, wp, wlen);
  156. if (seq_set(sp, name, strlen(tkp->name),
  157. ts, strlen(t), output, strlen(tkp->output),
  158. SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN))
  159. return (1);
  160. }
  161. }
  162. /*
  163. * Rework any function key mappings that were set before the
  164. * screen was initialized.
  165. */
  166. LIST_FOREACH(qp, &sp->gp->seqq, q)
  167. if (F_ISSET(qp, SEQ_FUNCMAP))
  168. (void)cl_pfmap(sp, qp->stype,
  169. qp->input, qp->ilen, qp->output, qp->olen);
  170. return (0);
  171. }
  172. /*
  173. * cl_term_end --
  174. * End the special keys defined by the termcap/terminfo entry.
  175. *
  176. * PUBLIC: int cl_term_end __P((GS *));
  177. */
  178. int
  179. cl_term_end(GS *gp)
  180. {
  181. SEQ *qp, *nqp;
  182. /* Delete screen specific mappings. */
  183. LIST_FOREACH_SAFE(qp, &gp->seqq, q, nqp)
  184. if (F_ISSET(qp, SEQ_SCREEN))
  185. (void)seq_mdel(qp);
  186. return (0);
  187. }
  188. /*
  189. * cl_fmap --
  190. * Map a function key.
  191. *
  192. * PUBLIC: int cl_fmap __P((SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t));
  193. */
  194. int
  195. cl_fmap(SCR *sp, seq_t stype, CHAR_T *from, size_t flen, CHAR_T *to, size_t tlen)
  196. {
  197. /* Ignore until the screen is running, do the real work then. */
  198. if (F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_SCR_VI))
  199. return (0);
  200. if (F_ISSET(sp, SC_EX) && !F_ISSET(sp, SC_SCR_EX))
  201. return (0);
  202. return (cl_pfmap(sp, stype, from, flen, to, tlen));
  203. }
  204. /*
  205. * cl_pfmap --
  206. * Map a function key (private version).
  207. */
  208. static int
  209. cl_pfmap(SCR *sp, seq_t stype, CHAR_T *from, size_t flen, CHAR_T *to, size_t tlen)
  210. {
  211. size_t nlen;
  212. char *p;
  213. char name[64];
  214. CHAR_T mykeyname[64];
  215. CHAR_T ts[20];
  216. const CHAR_T *wp;
  217. size_t wlen;
  218. (void)snprintf(name, sizeof(name), "kf%d",
  219. (int)STRTOL(from+1,NULL,10));
  220. if ((p = tigetstr(name)) == NULL ||
  221. p == (char *)-1 || strlen(p) == 0)
  222. p = NULL;
  223. if (p == NULL) {
  224. msgq_wstr(sp, M_ERR, from, "233|This terminal has no %s key");
  225. return (1);
  226. }
  227. nlen = SPRINTF(mykeyname,
  228. SIZE(mykeyname), L("function key %d"),
  229. (int)STRTOL(from+1,NULL,10));
  230. CHAR2INT(sp, p, strlen(p), wp, wlen);
  231. MEMCPYW(ts, wp, wlen);
  232. return (seq_set(sp, mykeyname, nlen,
  233. ts, strlen(p), to, tlen, stype, SEQ_NOOVERWRITE | SEQ_SCREEN));
  234. }
  235. /*
  236. * cl_optchange --
  237. * Curses screen specific "option changed" routine.
  238. *
  239. * PUBLIC: int cl_optchange __P((SCR *, int, const char *, u_long *));
  240. */
  241. int
  242. cl_optchange(SCR *sp, int opt, const char *str, u_long *valp)
  243. {
  244. CL_PRIVATE *clp;
  245. clp = CLP(sp);
  246. switch (opt) {
  247. case O_COLUMNS:
  248. case O_LINES:
  249. case O_TERM:
  250. /*
  251. * Changing the columns, lines or terminal require that
  252. * we restart the screen.
  253. */
  254. F_SET(sp->gp, G_SRESTART);
  255. F_CLR(sp, SC_SCR_EX | SC_SCR_VI);
  256. break;
  257. case O_MESG:
  258. (void)cl_omesg(sp, clp, *valp);
  259. break;
  260. case O_WINDOWNAME:
  261. if (*valp) {
  262. F_SET(clp, CL_RENAME_OK);
  263. /*
  264. * If the screen is live, i.e. we're not reading the
  265. * .exrc file, update the window.
  266. */
  267. if (sp->frp != NULL && sp->frp->name != NULL)
  268. (void)cl_rename(sp, sp->frp->name, 1);
  269. } else {
  270. F_CLR(clp, CL_RENAME_OK);
  271. (void)cl_rename(sp, NULL, 0);
  272. }
  273. break;
  274. }
  275. return (0);
  276. }
  277. /*
  278. * cl_omesg --
  279. * Turn the tty write permission on or off.
  280. *
  281. * PUBLIC: int cl_omesg __P((SCR *, CL_PRIVATE *, int));
  282. */
  283. int
  284. cl_omesg(SCR *sp, CL_PRIVATE *clp, int on)
  285. {
  286. struct stat sb;
  287. char *tty;
  288. /* Find the tty, get the current permissions. */
  289. if ((tty = ttyname(STDERR_FILENO)) == NULL) {
  290. if (sp != NULL)
  291. msgq(sp, M_SYSERR, "stderr");
  292. return (1);
  293. }
  294. if (stat(tty, &sb) < 0) {
  295. if (sp != NULL)
  296. msgq(sp, M_SYSERR, "%s", tty);
  297. return (1);
  298. }
  299. /* Save the original status if it's unknown. */
  300. if (clp->tgw == TGW_UNKNOWN)
  301. clp->tgw = sb.st_mode & S_IWGRP ? TGW_SET : TGW_UNSET;
  302. /* Toggle the permissions. */
  303. if (on) {
  304. if (chmod(tty, sb.st_mode | S_IWGRP) < 0) {
  305. if (sp != NULL)
  306. msgq(sp, M_SYSERR,
  307. "046|messages not turned on: %s", tty);
  308. return (1);
  309. }
  310. } else
  311. if (chmod(tty, sb.st_mode & ~S_IWGRP) < 0) {
  312. if (sp != NULL)
  313. msgq(sp, M_SYSERR,
  314. "045|messages not turned off: %s", tty);
  315. return (1);
  316. }
  317. return (0);
  318. }
  319. /*
  320. * cl_ssize --
  321. * Return the terminal size.
  322. *
  323. * PUBLIC: int cl_ssize __P((SCR *, int, size_t *, size_t *, int *));
  324. */
  325. int
  326. cl_ssize(SCR *sp, int sigwinch, size_t *rowp, size_t *colp, int *changedp)
  327. {
  328. #ifdef TIOCGWINSZ
  329. struct winsize win;
  330. #endif
  331. size_t col, row;
  332. int rval;
  333. char *p;
  334. /* Assume it's changed. */
  335. if (changedp != NULL)
  336. *changedp = 1;
  337. /*
  338. * !!!
  339. * sp may be NULL.
  340. *
  341. * Get the screen rows and columns. If the values are wrong, it's
  342. * not a big deal -- as soon as the user sets them explicitly the
  343. * environment will be set and the screen package will use the new
  344. * values.
  345. *
  346. * Try TIOCGWINSZ.
  347. */
  348. row = col = 0;
  349. #ifdef TIOCGWINSZ
  350. if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) != -1) {
  351. row = win.ws_row;
  352. col = win.ws_col;
  353. }
  354. #endif
  355. /* If here because of suspend or a signal, only trust TIOCGWINSZ. */
  356. if (sigwinch) {
  357. /*
  358. * Somebody didn't get TIOCGWINSZ right, or has suspend
  359. * without window resizing support. The user just lost,
  360. * but there's nothing we can do.
  361. */
  362. if (row == 0 || col == 0) {
  363. if (changedp != NULL)
  364. *changedp = 0;
  365. return (0);
  366. }
  367. /*
  368. * SunOS systems deliver SIGWINCH when windows are uncovered
  369. * as well as when they change size. In addition, we call
  370. * here when continuing after being suspended since the window
  371. * may have changed size. Since we don't want to background
  372. * all of the screens just because the window was uncovered,
  373. * ignore the signal if there's no change.
  374. */
  375. if (sp != NULL &&
  376. row == O_VAL(sp, O_LINES) && col == O_VAL(sp, O_COLUMNS)) {
  377. if (changedp != NULL)
  378. *changedp = 0;
  379. return (0);
  380. }
  381. if (rowp != NULL)
  382. *rowp = row;
  383. if (colp != NULL)
  384. *colp = col;
  385. resizeterm(row, col);
  386. return (0);
  387. }
  388. /*
  389. * !!!
  390. * If TIOCGWINSZ failed, or had entries of 0, try termcap. This
  391. * routine is called before any termcap or terminal information
  392. * has been set up. If there's no TERM environmental variable set,
  393. * let it go, at least ex can run.
  394. */
  395. if (row == 0 || col == 0) {
  396. if ((p = getenv("TERM")) == NULL)
  397. goto noterm;
  398. if (row == 0) {
  399. if ((rval = tigetnum("lines")) < 0)
  400. msgq(sp, M_SYSERR, "tigetnum: lines");
  401. else
  402. row = rval;
  403. }
  404. if (col == 0) {
  405. if ((rval = tigetnum("cols")) < 0)
  406. msgq(sp, M_SYSERR, "tigetnum: cols");
  407. else
  408. col = rval;
  409. }
  410. }
  411. /* If nothing else, well, it's probably a VT100. */
  412. noterm: if (row == 0)
  413. row = 24;
  414. if (col == 0)
  415. col = 80;
  416. /*
  417. * !!!
  418. * POSIX 1003.2 requires the environment to override everything.
  419. * Often, people can get nvi to stop messing up their screen by
  420. * deleting the LINES and COLUMNS environment variables from their
  421. * dot-files.
  422. */
  423. if ((p = getenv("LINES")) != NULL)
  424. row = strtol(p, NULL, 10);
  425. if ((p = getenv("COLUMNS")) != NULL)
  426. col = strtol(p, NULL, 10);
  427. if (rowp != NULL)
  428. *rowp = row;
  429. if (colp != NULL)
  430. *colp = col;
  431. return (0);
  432. }
  433. /*
  434. * cl_putchar --
  435. * Function version of putchar, for tputs.
  436. *
  437. * PUBLIC: int cl_putchar __P((int));
  438. */
  439. int
  440. cl_putchar(int ch)
  441. {
  442. return (putchar(ch));
  443. }