home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / cl / cl_term.c < prev    next >
C/C++ Source or Header  |  1997-06-29  |  13KB  |  568 lines

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