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