home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / tcap.c < prev    next >
C/C++ Source or Header  |  1998-08-26  |  29KB  |  1,187 lines

  1. /*    tcap:    Unix V5, V7 and BS4.2 Termcap video driver
  2.  *        for MicroEMACS
  3.  *
  4.  * $Header: /usr/build/vile/vile/RCS/tcap.c,v 1.111 1998/08/27 01:30:06 tom Exp $
  5.  *
  6.  */
  7.  
  8. #define termdef 1            /* don't define "term" external */
  9.  
  10. #include    "estruct.h"
  11. #include    "edef.h"
  12.  
  13. #if DISP_TERMCAP
  14.  
  15. #define MARGIN    8
  16. #define SCRSIZ    64
  17. #define NPAUSE    10            /* # times thru update to pause */
  18.  
  19. #include    "tcap.h"
  20.  
  21. #undef WINDOW
  22. #define WINDOW vile_WINDOW
  23.  
  24. #if USE_TERMCAP
  25. #  define TCAPSLEN 768
  26.     static    char tcapbuf[TCAPSLEN];
  27. #endif
  28.  
  29. static char *tc_CM, *tc_CE, *tc_CL, *tc_SO, *tc_SE;
  30. static char *tc_TI, *tc_TE, *tc_KS, *tc_KE;
  31. static char *tc_CS, *tc_dl, *tc_al, *tc_DL, *tc_AL, *tc_SF, *tc_SR;
  32.  
  33. #if OPT_VIDEO_ATTRS
  34. static char *tc_US;    /* underline-start */
  35. static char *tc_UE;    /* underline-end */
  36. static char *tc_ME;
  37. static char *tc_MD;
  38. #endif
  39.  
  40. #if OPT_FLASH
  41. static char *vb;    /* visible-bell */
  42. #endif
  43.  
  44. #if OPT_COLOR
  45. /*
  46.  * This implementation is based on the description of SysVr4 curses found in
  47.  * ncurses 1.8.7, which lists the following terminal capabilities:
  48.  *
  49.  * Full name        Terminfo  Type   Termcap Description
  50.  * ---------------- -------   ----   ----    -----------------------------
  51.  * back_color_erase "bce"     bool   "ut"    screen erased with background color
  52.  * max_colors       "colors"  num    "Co"    maximum numbers of colors on screen
  53.  * max_pairs        "pairs"   num    "pa"    maximum number of color-pairs on the screen
  54.  * no_color_video   "ncv"     num    "NC"    video attributes that can't be used with colors
  55.  * orig_pair        "op"      str    "op"
  56.  * orig_colors      "oc"      str    "oc"    set original colors
  57.  * initialize_color "initc"   str    "Ic"
  58.  * initialize_pair  "initp"   str    "Ip"
  59.  * set_color_pair   "scp"     str    "sp"
  60.  * set_a_foreground "setaf"   str    "AF"
  61.  * set_a_background "setab"   str    "AB"
  62.  * color_names      "colornm" str    "Yw"
  63.  *
  64.  * In this version, we don't support color pairs, since the only terminals on
  65.  * which it's been tested are "ANSI".  The color names are hardcoded.  The
  66.  * termcap must have the following capabilities set (or an equivalent
  67.  * terminfo):
  68.  *    Co (limited to 1 .. (NCOLORS-1)
  69.  *    AF (e.g., "\E[%a+c\036%dm")
  70.  *    AB (e.g., "\E[%a+c\050%dm")
  71.  *    oc (e.g., "\E[0m")
  72.  */
  73.  
  74. #define NO_COLOR (-1)
  75. #define    Num2Color(n) ((n >= 0) ? ctrans[(n) & (ncolors-1)] : NO_COLOR)
  76.  
  77. static    char    *AF;
  78. static    char    *AB;
  79. static    char    *Sf;
  80. static    char    *Sb;
  81. static    char    *OrigColors;
  82. static    int    have_bce;
  83.  
  84.     /* ANSI: black, red, green, yellow, blue, magenta, cyan, white   */
  85. static    const char ANSI_palette[] = { "0 1 2 3 4 5 6 7" };
  86. static    const char UNKN_palette[] = { "0 4 2 6 1 5 3 7 8 12 10 14 9 13 11 15" };
  87. /*
  88.  * We don't really _know_ what the default colors are set to, so the initial
  89.  * values of the current_[fb]color are set to an illegal value to force the
  90.  * colors to be set.
  91.  */
  92. static    int    given_fcolor = NO_COLOR;
  93. static    int    given_bcolor = NO_COLOR;
  94.  
  95. static    int    shown_fcolor = NO_COLOR;
  96. static    int    shown_bcolor = NO_COLOR;
  97. #endif /* OPT_COLOR */
  98.  
  99. static const struct {
  100.     char * capname;
  101.     int    code;
  102. } keyseqs[] = {
  103.     /* Arrow keys */
  104.     { CAPNAME("ku","kcuu1"),    KEY_Up },        /* up */
  105.     { CAPNAME("kd","kcud1"),    KEY_Down },        /* down */
  106.     { CAPNAME("kr","kcuf1"),    KEY_Right },        /* right */
  107.     { CAPNAME("kl","kcub1"),    KEY_Left },        /* left */
  108.     /* other cursor-movement */
  109.     { CAPNAME("kh","khome"),    KEY_Home },        /* home */
  110.     { CAPNAME("kH","kll"),    KEY_End },        /* end (variant) */
  111.     { CAPNAME("@7","kend"),    KEY_End },        /* end */
  112.     /* page scroll */
  113.     { CAPNAME("kN","knp"),    KEY_Next },        /* next page */
  114.     { CAPNAME("kP","kpp"),    KEY_Prior },        /* previous page */
  115.     /* editing */
  116.     { CAPNAME("kI","kich1"),    KEY_Insert },        /* Insert */
  117.     { CAPNAME("kD","kdch1"),    KEY_Delete },        /* Delete */
  118.     { CAPNAME("@0","kfnd"),    KEY_Find },        /* Find */
  119.     { CAPNAME("*6","kslt"),    KEY_Select },        /* Select */
  120.     /* command */
  121.     { CAPNAME("%1","khlp"),    KEY_Help },        /* Help */
  122.     /* function keys */
  123.     { CAPNAME("k1","kf1"),    KEY_F1 },        /* F1 */
  124.     { CAPNAME("k2","kf2"),    KEY_F2 },
  125.     { CAPNAME("k3","kf3"),    KEY_F3 },
  126.     { CAPNAME("k4","kf4"),    KEY_F4 },
  127.     { CAPNAME("k5","kf5"),    KEY_F5 },
  128.     { CAPNAME("k6","kf6"),    KEY_F6 },
  129.     { CAPNAME("k7","kf7"),    KEY_F7 },
  130.     { CAPNAME("k8","kf8"),    KEY_F8 },
  131.     { CAPNAME("k9","kf9"),    KEY_F9 },
  132.     { CAPNAME("k;","kf10"),    KEY_F10 },        /* F10 */
  133.     { CAPNAME("F1","kf11"),    KEY_F11 },        /* F11 */
  134.     { CAPNAME("F2","kf12"),    KEY_F12 },        /* F12 */
  135.     { CAPNAME("F3","kf13"),    KEY_F13 },        /* F13 */
  136.     { CAPNAME("F4","kf14"),    KEY_F14 },
  137.     { CAPNAME("F5","kf15"),    KEY_F15 },
  138.     { CAPNAME("F6","kf16"),    KEY_F16 },
  139.     { CAPNAME("F7","kf17"),    KEY_F17 },
  140.     { CAPNAME("F8","kf18"),    KEY_F18 },
  141.     { CAPNAME("F9","kf19"),    KEY_F19 },        /* F19 */
  142.     { CAPNAME("FA","kf20"),    KEY_F20 },        /* F20 */
  143.     { CAPNAME("FB","kf21"),    KEY_F21 },
  144.     { CAPNAME("FC","kf22"),    KEY_F22 },
  145.     { CAPNAME("FD","kf23"),    KEY_F23 },
  146.     { CAPNAME("FE","kf24"),    KEY_F24 },
  147.     { CAPNAME("FF","kf25"),    KEY_F25 },
  148.     { CAPNAME("FG","kf26"),    KEY_F26 },
  149.     { CAPNAME("FH","kf27"),    KEY_F27 },
  150.     { CAPNAME("FI","kf28"),    KEY_F28 },
  151.     { CAPNAME("FJ","kf29"),    KEY_F29 },
  152.     { CAPNAME("FK","kf30"),    KEY_F30 },
  153.     { CAPNAME("FL","kf31"),    KEY_F31 },
  154.     { CAPNAME("FM","kf32"),    KEY_F32 },
  155.     { CAPNAME("FN","kf33"),    KEY_F33 },
  156.     { CAPNAME("FO","kf34"),    KEY_F34 },
  157.     { CAPNAME("FP","kf35"),    KEY_F35 }
  158. };
  159.  
  160. #if SYS_OS2_EMX
  161. #include "os2keys.h"
  162. #endif
  163.  
  164. static int  colors_are_really_ANSI (void);
  165. static int  tcapcres (const char *cres);
  166. static void putnpad(char *str, int n);
  167. static void putpad(char *str);
  168. static void tcapbeep (void);
  169. static void tcapclose (void);
  170. static void tcapeeol (void);
  171. static void tcapeeop (void);
  172. static void tcapkclose (void);
  173. static void tcapkopen (void);
  174. static void tcapmove (int row, int col);
  175. static void tcapopen (void);
  176. static void tcapscroll_delins (int from, int to, int n);
  177. static void tcapscroll_reg (int from, int to, int n);
  178. static void tcapscrollregion (int top, int bot);
  179.  
  180. #if OPT_COLOR
  181. static void tcapfcol ( int color );
  182. static void tcapbcol ( int  color);
  183. static void tcapspal ( const char *s );
  184. #endif
  185.  
  186. #if OPT_VIDEO_ATTRS
  187. static void tcapattr ( UINT attr );
  188. #else
  189. static void tcaprev  ( UINT state );
  190. #endif
  191.  
  192. TERM term = {
  193.     0,    /* these four values are set dynamically at open time */
  194.     0,
  195.     0,
  196.     0,
  197.     MARGIN,
  198.     SCRSIZ,
  199.     NPAUSE,
  200.     tcapopen,
  201.     tcapclose,
  202.     tcapkopen,
  203.     tcapkclose,
  204.     ttgetc,
  205.     ttputc,
  206.     tttypahead,
  207.     ttflush,
  208.     tcapmove,
  209.     tcapeeol,
  210.     tcapeeop,
  211.     tcapbeep,
  212. #if OPT_VIDEO_ATTRS
  213.     tcapattr,
  214. #else
  215.     tcaprev,
  216. #endif
  217.     tcapcres,
  218. #if    OPT_COLOR
  219.     tcapfcol,
  220.     tcapbcol,
  221.     tcapspal,
  222. #else
  223.     null_t_setfor,
  224.     null_t_setback,
  225.     null_t_setpal,
  226. #endif
  227.     null_t_scroll,        /* set dynamically at open time */
  228.     null_t_pflush,
  229.     null_t_icursor,
  230.     null_t_title,
  231.     null_t_watchfd,
  232.     null_t_unwatchfd,
  233. };
  234.  
  235. #define    XtermPos()    ((unsigned)(keystroke() - 040))
  236.  
  237. #if OPT_XTERM >= 3
  238. # define XTERM_ENABLE_TRACKING   "\033[?1001h"    /* mouse hilite tracking */
  239. # define XTERM_DISABLE_TRACKING  "\033[?1001l"
  240. #else
  241. # if OPT_XTERM >= 2
  242. #  define XTERM_ENABLE_TRACKING   "\033[?1000h"    /* normal tracking mode */
  243. #  define XTERM_DISABLE_TRACKING  "\033[?1000l"
  244. # else
  245. #  define XTERM_ENABLE_TRACKING   "\033[?9h"    /* X10 compatibility mode */
  246. #  define XTERM_DISABLE_TRACKING  "\033[?9l"
  247. # endif
  248. #endif
  249.  
  250. static    int    i_am_xterm;
  251. static    int    x_origin = 1,
  252.         y_origin = 1;
  253.  
  254. #if HAVE_TPARM    /* usually terminfo */
  255. #define CALL_TPARM(cap,code) tparm(cap, code)
  256. #define FREE_TPARM(s) /* nothing */
  257. #else
  258. #if HAVE_TPARAM    /* GNU termcap */
  259. #if DOALLOC
  260. #undef free
  261. #endif
  262. #define CALL_TPARM(cap,code) tparam(cap, (char *)0, 0, code)
  263. #define FREE_TPARM(s) free(s)
  264. #else
  265. static char *my_tparm(char *cap GCC_UNUSED, int code GCC_UNUSED)
  266. {
  267.     static char result[10];
  268.     sprintf(result, cap, code);
  269.     return strcmp(result, cap) ? result : 0;
  270. }
  271. #define CALL_TPARM(cap,code) my_tparm(cap, code)
  272. #define FREE_TPARM(s) /* nothing */
  273. #endif
  274. #endif
  275.  
  276. static void
  277. tcapopen(void)
  278. {
  279. #if USE_TERMCAP
  280.     char tcbuf[2048];
  281.     char err_str[72];
  282.     char *t, *p;
  283. #endif
  284.     char *tv_stype;
  285.     SIZE_T i;
  286.     int j;
  287.     static int already_open = 0;
  288.  
  289.     static const struct {
  290.         char *name;
  291.         char **data;
  292.     } tc_strings[] = {
  293.      { CAPNAME("AL","il"),    &tc_AL }    /* add p1 lines above cursor */
  294.     ,{ CAPNAME("DL","dl"),    &tc_DL }    /* delete p1 lines, begin at cursor */
  295.     ,{ CAPNAME("al","il1"),   &tc_al }    /* add line below cursor */
  296.     ,{ CAPNAME("ce","el"),    &tc_CE }    /* clear to end of line */
  297.     ,{ CAPNAME("cl","clear"), &tc_CL }    /* clear screen, cursor to home */
  298.     ,{ CAPNAME("cm","cup"),   &tc_CM }    /* move cursor to row p1, col p2 */
  299.     ,{ CAPNAME("cs","csr"),   &tc_CS }    /* set scrolling to rows p1 .. p2 */
  300.     ,{ CAPNAME("dl","dl1"),   &tc_dl }    /* delete line */
  301.     ,{ CAPNAME("ke","rmkx"),  &tc_KE }    /* end keypad-mode */
  302.     ,{ CAPNAME("ks","smkx"),  &tc_KS }    /* start keypad-mode */
  303.     ,{ CAPNAME("se","rmso"),  &tc_SE }    /* end standout-mode */
  304.     ,{ CAPNAME("sf","ind"),   &tc_SF }    /* scroll forward 1 line */
  305.     ,{ CAPNAME("so","smso"),  &tc_SO }    /* start standout-mode */
  306.     ,{ CAPNAME("sr","ri"),    &tc_SR }    /* scroll reverse 1 line */
  307.     ,{ CAPNAME("te","rmcup"), &tc_TE }    /* end cursor-motion program */
  308.     ,{ CAPNAME("ti","smcup"), &tc_TI }    /* initialize cursor-motion program */
  309. #if    OPT_COLOR
  310.     ,{ CAPNAME("AF","setaf"), &AF }        /* set ANSI foreground-color */
  311.     ,{ CAPNAME("AB","setab"), &AB }        /* set ANSI background-color */
  312.     ,{ CAPNAME("Sf","setf"),  &Sf }        /* set foreground-color */
  313.     ,{ CAPNAME("Sb","setb"),  &Sb }        /* set background-color */
  314.     ,{ CAPNAME("op","op"), &OrigColors }    /* set to original color pair */
  315.     ,{ CAPNAME("oc","oc"), &OrigColors }    /* set to original colors */
  316. #endif
  317. #if    OPT_FLASH
  318.     ,{ CAPNAME("vb","flash"), &vb }        /* visible bell */
  319. #endif
  320. #if    OPT_VIDEO_ATTRS
  321.     ,{ CAPNAME("me","sgr0"),  &tc_ME }    /* turn off all attributes */
  322.     ,{ CAPNAME("md","bold"),  &tc_MD }    /* turn on bold attribute */
  323.     ,{ CAPNAME("us","smul"),  &tc_US }    /* underline-start */
  324.     ,{ CAPNAME("ue","rmul"),  &tc_UE }    /* underline-end */
  325. #endif
  326.     };
  327.  
  328.     if (already_open)
  329.         return;
  330.  
  331.     if ((tv_stype = getenv("TERM")) == NULL)
  332.     {
  333.         puts("Environment variable TERM not defined!");
  334.         ExitProgram(BADEXIT);
  335.     }
  336.  
  337. #if USE_TERMINFO
  338.     setupterm(tv_stype, fileno(stdout), (int *)0);
  339. #else
  340.     if ((tgetent(tcbuf, tv_stype)) != 1)
  341.     {
  342.         (void)lsprintf(err_str, "Unknown terminal type %s!", tv_stype);
  343.         puts(err_str);
  344.         ExitProgram(BADEXIT);
  345.     }
  346. #endif
  347.  
  348.     /* Get screen size from system, or else from termcap.  */
  349.     getscreensize(&term.t_ncol, &term.t_nrow);
  350.  
  351.     if ((term.t_nrow <= 1)
  352.      && (term.t_nrow = TGETNUM(CAPNAME("li","lines"))) < 0) {
  353.         term.t_nrow = 24;
  354.     }
  355.  
  356.     if ((term.t_ncol <= 1)
  357.      && (term.t_ncol = TGETNUM(CAPNAME("co","cols"))) < 0){
  358.         term.t_ncol = 80;
  359.     }
  360.  
  361. #if OPT_COLOR
  362.     if ((j = TGETNUM(CAPNAME("Co","colors"))) > 0)
  363.         set_ncolors(j);
  364. #endif
  365.  
  366.     /* are we probably an xterm?  */
  367.     i_am_xterm = FALSE;
  368.     if (!strncmp(tv_stype, "xterm", sizeof("xterm") - 1)
  369.      || !strcmp(tv_stype, "rxvt")) {
  370.         i_am_xterm = TRUE;
  371.     }
  372. #if USE_TERMCAP
  373.     else {
  374.         p = tcbuf;
  375.         while (*p && *p != ':') {
  376.             if (*p == 'x'
  377.                 && strncmp(p, "xterm", sizeof("xterm") - 1) == 0) {
  378.                 i_am_xterm = TRUE;
  379.                 break;
  380.             }
  381.             p++;
  382.         }
  383.     }
  384. #endif
  385.     if (i_am_xterm) {
  386.         x_origin = 0;
  387.         y_origin = 0;
  388.     }
  389.  
  390.     term.t_mrow =  term.t_nrow;
  391.     term.t_mcol =  term.t_ncol;
  392.  
  393. #if USE_TERMCAP
  394.     p = tcapbuf;
  395. #endif
  396.     for (i = 0; i < TABLESIZE(tc_strings); i++) {
  397.         /* allow aliases */
  398.         if (NO_CAP(*(tc_strings[i].data)))
  399.             *(tc_strings[i].data) = TGETSTR(tc_strings[i].name, &p);
  400.         /* simplify subsequence checks */
  401.         if (NO_CAP(*(tc_strings[i].data)))
  402.             *(tc_strings[i].data) = 0;
  403.     }
  404.  
  405. #if USE_TERMCAP
  406. #  if HAVE_EXTERN_TCAP_PC
  407.     t = TGETSTR("pc", &p);
  408.     if(t)
  409.         PC = *t;
  410. #  endif
  411. #endif
  412.  
  413.     if (tc_SO != NULL)
  414.         revexist = TRUE;
  415.  
  416.     if(tc_CL == NULL || tc_CM == NULL)
  417.     {
  418.         puts("Incomplete termcap entry\n");
  419.         ExitProgram(BADEXIT);
  420.     }
  421.  
  422.     if (tc_CE == NULL)     /* will we be able to use clear to EOL? */
  423.         eolexist = FALSE;
  424.  
  425.     if (!tc_CS || !tc_SR) { /* some xterm's termcap entry is missing entries */
  426.         if (i_am_xterm) {
  427.             if (!tc_CS) tc_CS = "\033[%i%d;%dr";
  428.             if (!tc_SR) tc_SR = "\033M";
  429.         }
  430.     }
  431.  
  432.     if (tc_CS && tc_SR) {
  433.         if (tc_SF == NULL) /* assume '\n' scrolls forward */
  434.             tc_SF = "\n";
  435.         term.t_scroll = tcapscroll_reg;
  436.     } else if ((tc_DL && tc_AL) || (tc_dl && tc_al)) {
  437.         term.t_scroll = tcapscroll_delins;
  438.     } else {
  439.         term.t_scroll = null_t_scroll;
  440.     }
  441. #if    OPT_COLOR
  442.     /*
  443.      * If we've got one of the canonical strings for resetting to the
  444.      * default colors, we don't have to assume the screen is black/white.
  445.      */
  446.     if (OrigColors != 0) {
  447.         set_global_g_val(GVAL_FCOLOR, NO_COLOR); /* foreground color */
  448.         set_global_g_val(GVAL_BCOLOR, NO_COLOR); /* background color */
  449.     }
  450.  
  451.     /* clear with current bcolor */
  452.     have_bce = TGETFLAG(CAPNAME("ut","bce")) > 0;
  453.  
  454. #if    OPT_VIDEO_ATTRS
  455.     if (OrigColors == 0)
  456.         OrigColors = tc_ME;
  457. #endif
  458.     if (ncolors == 8 && AF != 0 && AB != 0) {
  459.         Sf = AF;
  460.         Sb = AB;
  461.         set_palette(ANSI_palette);
  462.     } else if (colors_are_really_ANSI()) {
  463.         set_palette(ANSI_palette);
  464.     } else
  465.         set_palette(UNKN_palette);
  466. #endif
  467. #if OPT_VIDEO_ATTRS
  468.     if (tc_US == 0 && tc_UE == 0) {    /* if we don't have underline, do bold */
  469.         tc_US = tc_MD;
  470.         tc_UE = tc_ME;
  471.     }
  472. #endif
  473.  
  474. #if SYS_OS2_EMX
  475.     for (i = TABLESIZE(VIO_KeyMap); i--; ) {
  476.         addtosysmap(VIO_KeyMap[i].seq, 2, VIO_KeyMap[i].code);
  477.     }
  478. #endif
  479.     for (i = TABLESIZE(keyseqs); i--; ) {
  480.         char *seq = TGETSTR(keyseqs[i].capname, &p);
  481.         if (!NO_CAP(seq)) {
  482.         int len;
  483. #define DONT_MAP_DEL 1
  484. #if DONT_MAP_DEL
  485.         /* NetBSD, FreeBSD, etc. have the kD (delete) function key
  486.             defined as the DEL char.  i don't like this hack, but
  487.             until we (and we may never) have separate system "map"
  488.             and "map!" maps, we can't allow this -- DEL has different
  489.             semantics in insert and command mode, whereas KEY_Delete
  490.             has the same semantics (whatever they may be) in both.
  491.             KEY_Delete is the only non-motion system map, by the
  492.             way -- so the rest are benign in insert or command
  493.             mode.  */
  494.         if (strcmp(seq,"\177") == 0)
  495.             continue;
  496. #endif
  497.         addtosysmap(seq, len = strlen(seq), keyseqs[i].code);
  498.         /*
  499.          * Termcap represents nulls as octal 200, which is ambiguous
  500.          * (ugh).  To avoid losing escape sequences that may contain
  501.          * nulls, check here, and add a mapping for the strings with
  502.          * explicit nulls.
  503.          */
  504. #define TCAP_NULL '\200'
  505.         if (strchr(seq, TCAP_NULL) != 0) {
  506.             char temp[BUFSIZ];
  507.             (void)strcpy(temp, seq);
  508.             for (j = 0; j < len; j++)
  509.             if (char2int(temp[j]) == TCAP_NULL)
  510.                 temp[j] = '\0';
  511.             addtosysmap(temp, len, keyseqs[i].code);
  512.         }
  513.         }
  514.     }
  515. #if OPT_XTERM
  516.     addtosysmap("\033[M", 3, KEY_Mouse);
  517. #if OPT_XTERM >= 3
  518.     addtosysmap("\033[t", 3, KEY_text);
  519.     addtosysmap("\033[T", 3, KEY_textInvalid);
  520. #endif
  521. #endif
  522.  
  523. #if USE_TERMCAP
  524.     if (p >= &tcapbuf[TCAPSLEN])
  525.     {
  526.         puts("Terminal description too big!\n");
  527.         ExitProgram(BADEXIT);
  528.     }
  529. #endif
  530.     ttopen();
  531.     already_open = TRUE;
  532. }
  533.  
  534. static void
  535. tcapclose(void)
  536. {
  537. #if OPT_VIDEO_ATTRS
  538.     if (tc_ME)    /* end special attributes (including color) */
  539.         putpad(tc_ME);
  540. #endif
  541.     TTmove(term.t_nrow-1, 0);    /* cf: dumbterm.c */
  542.     TTeeol();
  543. #if OPT_COLOR
  544.     shown_fcolor = shown_bcolor =
  545.     given_fcolor = given_bcolor = NO_COLOR;
  546. #endif
  547. }
  548.  
  549. /*
  550.  * We open or close the keyboard when either of the following are true:
  551.  *    a) we're changing the xterm-mouse setting
  552.  *    b) we're spawning a subprocess (e.g., shell or pipe command)
  553.  */
  554. static    int    keyboard_open = FALSE;
  555.  
  556. static void
  557. tcapkopen(void)
  558. {
  559. #if OPT_XTERM
  560.     if (i_am_xterm && global_g_val(GMDXTERM_MOUSE))
  561.         putpad(XTERM_ENABLE_TRACKING);
  562. #endif
  563.     if (!keyboard_open) {
  564.         keyboard_open = TRUE;
  565.         if (tc_TI) {
  566.             putnpad(tc_TI, (int)strlen(tc_TI));
  567.             ttrow = ttcol = -1;    /* 'ti' may move the cursor */
  568.         }
  569.         if (tc_KS)
  570.             putpad(tc_KS);
  571.     }
  572.     (void)strcpy(sres, "NORMAL");
  573. }
  574.  
  575. static void
  576. tcapkclose(void)
  577. {
  578. #if OPT_XTERM
  579.     if (i_am_xterm && global_g_val(GMDXTERM_MOUSE))
  580.         putpad(XTERM_DISABLE_TRACKING);
  581. #endif
  582.     if (keyboard_open) {
  583.         keyboard_open = FALSE;
  584.         if (tc_TE)
  585.             putnpad(tc_TE, (int)strlen(tc_TE));
  586.         if (tc_KE)
  587.             putpad(tc_KE);
  588.     }
  589.     TTflush();
  590. }
  591.  
  592. static void
  593. tcapmove(register int row, register int col)
  594. {
  595.     putpad(tgoto(tc_CM, col, row));
  596. }
  597.  
  598. #if    OPT_COLOR
  599. /*
  600.  * Accommodate brain-damaged non-bce terminals by writing a blank to each
  601.  * space that we'll color, return true if we moved the cursor.
  602.  */
  603. static int
  604. clear_non_bce(int row, int col)
  605. {
  606.     int n;
  607.     int last = (row >= term.t_nrow-1) ? (term.t_ncol - 1) : term.t_ncol;
  608.     if (col < last) {
  609.         for (n = col; n < last; n++)
  610.             ttputc(' ');
  611.         return TRUE;
  612.     }
  613.     return FALSE;
  614. }
  615.  
  616. static void
  617. erase_non_bce(int row, int col)
  618. {
  619.     if (clear_non_bce(row, col))
  620.         TTmove(row, col);
  621. }
  622.  
  623. #define NEED_BCE_FIX (!have_bce && shown_bcolor != NO_COLOR)
  624. #define FILL_BCOLOR(row,col) if(NEED_BCE_FIX) erase_non_bce(row, col)
  625. #else
  626. #define FILL_BCOLOR(row,col) /*nothing*/
  627. #endif
  628.  
  629. static void
  630. tcapeeol(void)
  631. {
  632. #if    OPT_COLOR
  633.     if (NEED_BCE_FIX) {
  634.         erase_non_bce(ttrow, ttcol);
  635.     } else
  636. #endif
  637.     putpad(tc_CE);
  638. }
  639.  
  640. static void
  641. tcapeeop(void)
  642. {
  643. #if    OPT_COLOR
  644.     tcapfcol(gfcolor);
  645.     tcapbcol(gbcolor);
  646.  
  647.     if (NEED_BCE_FIX) {
  648.         int row = ttrow;
  649.         if (row < term.t_nrow-1) {
  650.             while (++row < term.t_nrow) {
  651.                 if (ttrow != row || ttcol != 0)
  652.                     TTmove(row, 0);
  653.                 (void) clear_non_bce(row, 0);
  654.             }
  655.             TTmove(ttrow, ttcol);
  656.         }
  657.         erase_non_bce(ttrow, ttcol);
  658.     } else
  659. #endif
  660.     putpad(tc_CL);
  661. }
  662.  
  663. /*ARGSUSED*/
  664. static int
  665. tcapcres(const char *res GCC_UNUSED)    /* change screen resolution */
  666. {
  667.     return(TRUE);
  668. }
  669.  
  670.  
  671. /* move howmany lines starting at from to to */
  672. static void
  673. tcapscroll_reg(int from, int to, int n)
  674. {
  675.     int i;
  676.     if (to == from) return;
  677.     if (to < from) {
  678.         tcapscrollregion(to, from + n - 1);
  679.         tcapmove(from + n - 1, 0);
  680.         for (i = from - to; i > 0; i--) {
  681.             putpad(tc_SF);
  682.             FILL_BCOLOR(from + n - 1, 0);
  683.         }
  684.     } else { /* from < to */
  685.         tcapscrollregion(from, to + n - 1);
  686.         tcapmove(from, 0);
  687.         for (i = to - from; i > 0; i--) {
  688.             putpad(tc_SR);
  689.             FILL_BCOLOR(from, 0);
  690.         }
  691.     }
  692.     tcapscrollregion(0, term.t_nrow-1);
  693. }
  694.  
  695. /*
  696. OPT_PRETTIER_SCROLL is prettier but slower -- it scrolls
  697.         a line at a time instead of all at once.
  698. */
  699.  
  700. /* move howmany lines starting at from to to */
  701. static void
  702. tcapscroll_delins(int from, int to, int n)
  703. {
  704.     int i;
  705.     if (to == from) return;
  706.     if (tc_DL && tc_AL) {
  707.         if (to < from) {
  708.             tcapmove(to, 0);
  709.             putpad(tgoto(tc_DL, 0, from-to));
  710.             tcapmove(to+n, 0);
  711.             putpad(tgoto(tc_AL, 0, from-to));
  712.             FILL_BCOLOR(to+n, 0);
  713.         } else {
  714.             tcapmove(from+n, 0);
  715.             putpad(tgoto(tc_DL, 0, to-from));
  716.             tcapmove(from, 0);
  717.             putpad(tgoto(tc_AL, 0, to-from));
  718.             FILL_BCOLOR(from+n, 0);
  719.         }
  720.     } else { /* must be dl and al */
  721. #if OPT_PRETTIER_SCROLL
  722.         if (absol(from-to) > 1) {
  723.             tcapscroll_delins(from, (from<to) ? to-1:to+1, n);
  724.             if (from < to)
  725.                 from = to-1;
  726.             else
  727.                 from = to+1;
  728.         }
  729. #endif
  730.         if (to < from) {
  731.             tcapmove(to, 0);
  732.             for (i = from - to; i > 0; i--)
  733.                 putpad(tc_dl);
  734.             tcapmove(to+n, 0);
  735.             for (i = from - to; i > 0; i--) {
  736.                 putpad(tc_al);
  737.                 FILL_BCOLOR(to + n, 0);
  738.             }
  739.         } else {
  740.             tcapmove(from+n, 0);
  741.             for (i = to - from; i > 0; i--)
  742.                 putpad(tc_dl);
  743.             tcapmove(from, 0);
  744.             for (i = to - from; i > 0; i--) {
  745.                 putpad(tc_al);
  746.                 FILL_BCOLOR(from, 0);
  747.             }
  748.         }
  749.     }
  750. }
  751.  
  752. /* cs is set up just like cm, so we use tgoto... */
  753. static void
  754. tcapscrollregion(int top, int bot)
  755. {
  756.     putpad(tgoto(tc_CS, bot, top));
  757. }
  758.  
  759. #if    OPT_COLOR
  760. /*
  761.  * This ugly hack is designed to work around an incompatibility built into
  762.  * non BSD-derived systems that implemented color based on a SVr4 manpage.
  763.  */
  764. static int
  765. colors_are_really_ANSI (void)
  766. {
  767.     int ok = FALSE;
  768.     int n;
  769.     char cmp[BUFSIZ], *t;
  770.  
  771.     if (Sf != 0 && Sb != 0 && ncolors == 8) {
  772.         for (n = 0; n < ncolors; n++) {
  773.             (void)lsprintf(cmp, "\033[4%dm", n);
  774.             if ((t = CALL_TPARM(Sb, n)) == 0 || strcmp(t, cmp))
  775.                 break;
  776.             FREE_TPARM(t);
  777.             (void)lsprintf(cmp, "\033[3%dm", n);
  778.             if ((t = CALL_TPARM(Sf, n)) == 0 || strcmp(t, cmp))
  779.                 break;
  780.             FREE_TPARM(t);
  781.         }
  782.         if (n >= ncolors)    /* everything matched */
  783.             ok = TRUE;
  784.     }
  785.     return ok;
  786. }
  787.  
  788. static void
  789. show_ansi_colors (void)
  790. {
  791.     char    *t;
  792.  
  793.     if (shown_fcolor == NO_COLOR
  794.      || shown_bcolor == NO_COLOR) {
  795.         if (OrigColors)
  796.             putpad(OrigColors);
  797.     }
  798.  
  799.     if ((shown_fcolor != NO_COLOR)
  800.      && (t = CALL_TPARM(Sf, shown_fcolor)) != 0) {
  801.         putpad(t);
  802.         FREE_TPARM(t);
  803.     }
  804.     if ((shown_bcolor != NO_COLOR)
  805.      && (t = CALL_TPARM(Sb, shown_bcolor)) != 0) {
  806.         putpad(t);
  807.         FREE_TPARM(t);
  808.     }
  809. }
  810.  
  811. static void
  812. reinitialize_colors (void)
  813. {
  814.     int    saved_fcolor = given_fcolor;
  815.     int    saved_bcolor = given_bcolor;
  816.  
  817.     shown_fcolor = shown_bcolor =
  818.     given_fcolor = given_bcolor = NO_COLOR;
  819.  
  820.     tcapfcol(saved_fcolor);
  821.     tcapbcol(saved_bcolor);
  822. }
  823.  
  824. static void
  825. tcapfcol(int color)
  826. {
  827.     if (color != given_fcolor) {
  828.         given_fcolor = color;
  829.         shown_fcolor = (Sf != 0) ? Num2Color(color) : NO_COLOR;
  830.         show_ansi_colors();
  831.     }
  832. }
  833.  
  834. static void
  835. tcapbcol(int color)
  836. {
  837.     if (color != given_bcolor) {
  838.         given_bcolor = color;
  839.         shown_bcolor = (Sb != 0) ? Num2Color(color) : NO_COLOR;
  840.         show_ansi_colors();
  841.     }
  842. }
  843.  
  844. static void
  845. tcapspal(const char *thePalette)    /* reset the palette registers */
  846. {
  847.     set_ctrans(thePalette);
  848.     reinitialize_colors();
  849. }
  850. #endif /* OPT_COLOR */
  851.  
  852. #if OPT_VIDEO_ATTRS
  853. /*
  854.  * NOTE:
  855.  * On Linux console, the 'me' termcap setting \E[m resets _all_ attributes,
  856.  * including color.  However, if we use 'se' instead, it doesn't clear the
  857.  * boldface.  To compensate, we reset the colors when we put out any "ending"
  858.  * sequence, such as 'me'.
  859.  *
  860.  * In rxvt (2.12), setting _any_ attribute seems to clobber the color settings.
  861.  */
  862. static void
  863. tcapattr(UINT attr)
  864. {
  865. #define VA_SGR (VASEL|VAREV|VAUL|VAITAL|VABOLD)
  866.     static    const    struct    {
  867.         char    **start;
  868.         char    **end;
  869.         UINT    mask;
  870.     } tbl[] = {
  871.         { &tc_SO, &tc_SE, VASEL|VAREV },
  872.         { &tc_US, &tc_UE, VAUL },
  873.         { &tc_US, &tc_UE, VAITAL },
  874.         { &tc_MD, &tc_ME, VABOLD },
  875.     };
  876.     static    UINT last;
  877.  
  878.     attr = VATTRIB(attr);
  879.     if (attr & VASPCOL) {
  880.         attr = VCOLORATTR((attr & (NCOLORS - 1)));
  881.     } else {
  882.         attr &= ~(VAML|VAMLFOC);
  883.     }
  884.  
  885.     if (attr != last) {
  886.         register SIZE_T n;
  887.         register char *s;
  888.         UINT    diff = attr ^ last;
  889.         int    ends = FALSE;
  890.  
  891.         /* turn OFF old attributes */
  892.         for (n = 0; n < TABLESIZE(tbl); n++) {
  893.             if ((tbl[n].mask & diff) != 0
  894.              && (tbl[n].mask & attr) == 0
  895.              && (s = *(tbl[n].end))  != 0) {
  896.                 putpad(s);
  897. #if OPT_COLOR
  898.                 if (!ends)    /* do this once */
  899.                     reinitialize_colors();
  900. #endif
  901.                 ends = TRUE;
  902.                 diff &= ~(tbl[n].mask);
  903.             }
  904.         }
  905.  
  906.         /* turn ON new attributes */
  907.         for (n = 0; n < TABLESIZE(tbl); n++) {
  908.             if ((tbl[n].mask & diff)  != 0
  909.              && (tbl[n].mask & attr)  != 0
  910.              && (s = *(tbl[n].start)) != 0) {
  911.                 putpad(s);
  912.                 diff &= ~(tbl[n].mask);
  913.             }
  914.         }
  915.  
  916.         if (tc_SO != 0 && tc_SE != 0) {
  917.             if (ends && (attr & (VAREV|VASEL))) {
  918.                 putpad(tc_SO);
  919.             } else if (diff & VA_SGR) {  /* we didn't find it */
  920.                 putpad(tc_SE);
  921.             }
  922.         }
  923. #if OPT_COLOR
  924.         if (attr & VACOLOR)
  925.             tcapfcol(VCOLORNUM(attr));
  926.         else if (given_fcolor != gfcolor)
  927.             tcapfcol(gfcolor);
  928. #endif
  929.         last = attr;
  930.     }
  931. }
  932.  
  933. #else    /* highlighting is a minimum attribute */
  934.  
  935. static void
  936. tcaprev(        /* change reverse video status */
  937. UINT state)        /* FALSE = normal video, TRUE = reverse video */
  938. {
  939.     static int revstate = -1;
  940.     if (state == revstate)
  941.         return;
  942.     revstate = state;
  943.     if (state) {
  944.         if (tc_SO != NULL)
  945.             putpad(tc_SO);
  946.     } else {
  947.         if (tc_SE != NULL)
  948.             putpad(tc_SE);
  949.     }
  950. }
  951.  
  952. #endif    /* OPT_VIDEO_ATTRS */
  953.  
  954. static void
  955. tcapbeep(void)
  956. {
  957. #if OPT_FLASH
  958.     if (global_g_val(GMDFLASH)
  959.      && vb != NULL) {
  960.         putpad(vb);
  961.     } else
  962. #endif
  963.     ttputc(BEL);
  964. }
  965.  
  966. static void
  967. putpad(char *str)
  968. {
  969.     tputs(str, 1, ttputc);
  970. }
  971.  
  972. static void
  973. putnpad(char *str, int n)
  974. {
  975.     tputs(str, n, ttputc);
  976. }
  977.  
  978.  
  979.  
  980. #if OPT_XTERM
  981. /* Finish decoding a mouse-click in an xterm, after the ESC and '[' chars.
  982.  *
  983.  * There are 3 mutually-exclusive xterm mouse-modes (selected here by values of
  984.  * OPT_XTERM):
  985.  *    (1) X10-compatibility (not used here)
  986.  *        Button-press events are received.
  987.  *    (2) normal-tracking
  988.  *        Button-press and button-release events are received.
  989.  *        Button-events have modifiers (e.g., shift, control, meta).
  990.  *    (3) hilite-tracking
  991.  *        Button-press and text-location events are received.
  992.  *        Button-events have modifiers (e.g., shift, control, meta).
  993.  *        Dragging with the mouse produces highlighting.
  994.  *        The text-locations are checked by xterm to ensure validity.
  995.  *
  996.  * NOTE:
  997.  *    The hilite-tracking code is here for testing and (later) use.  Because
  998.  *    we cannot guarantee that we always are decoding escape-sequences when
  999.  *    reading from the terminal, there is the potential for the xterm hanging
  1000.  *    when a mouse-dragging operation is begun: it waits for us to specify
  1001.  *    the screen locations that limit the highlighting.
  1002.  *
  1003.  *     While highlighting, the xterm accepts other characters, but the display
  1004.  *    does not appear to be refreshed until highlighting is ended. So (even
  1005.  *    if we always capture the beginning of highlighting) we cannot simply
  1006.  *    loop here waiting for the end of highlighting.
  1007.  *
  1008.  *    1993/aug/6 dickey@software.org
  1009.  */
  1010.  
  1011. static    int    xterm_button (int c);
  1012.  
  1013. /*ARGSUSED*/
  1014. int
  1015. mouse_motion(int f GCC_UNUSED, int n GCC_UNUSED)
  1016. {
  1017.     return xterm_button('M');
  1018. }
  1019.  
  1020. #if OPT_XTERM >= 3
  1021. /*ARGSUSED*/
  1022. int
  1023. xterm_mouse_t(int f, int n)
  1024. {
  1025.     return xterm_button('t');
  1026. }
  1027.  
  1028. /*ARGSUSED*/
  1029. int
  1030. xterm_mouse_T(int f, int n)
  1031. {
  1032.     return xterm_button('T');
  1033. }
  1034. #endif    /* OPT_XTERM >= 3 */
  1035.  
  1036. static int
  1037. xterm_button(int c)
  1038. {
  1039.     int    event;
  1040.     int    button;
  1041.     int    x;
  1042.     int    y;
  1043.     int    status;
  1044. #if OPT_XTERM >= 3
  1045.     WINDOW    *wp;
  1046.     int    save_row = ttrow;
  1047.     int    save_col = ttcol;
  1048.     int    firstrow, lastrow;
  1049.     int    startx, endx, mousex;
  1050.     int    starty, endy, mousey;
  1051.     MARK    save_dot;
  1052.     char    temp[NSTRING];
  1053.     static    const    char    *fmt = "\033[%d;%d;%d;%d;%dT";
  1054. #endif    /* OPT_XTERM >= 3 */
  1055.  
  1056.     if ((status = (global_g_val(GMDXTERM_MOUSE))) != 0) {
  1057.         beginDisplay();
  1058.         switch(c) {
  1059. #if OPT_XTERM < 3
  1060.         /*
  1061.          * If we get a click on a modeline, clear the current selection,
  1062.          * if any.  Allow implied movement of the mouse (distance between
  1063.          * pressing and releasing a mouse button) to drag the modeline.
  1064.          *
  1065.          * Likewise, if we get a click _not_ on a modeline, make that
  1066.          * start/extend a selection.
  1067.          */
  1068.         case 'M':    /* button-event */
  1069.             event    = keystroke();
  1070.             x    = XtermPos() + x_origin - 1;
  1071.             y    = XtermPos() + y_origin - 1;
  1072.             button    = (event & 3) + 1;
  1073.  
  1074.             if (button > 3)
  1075.                 button = 0;
  1076.             TRACE(("MOUSE-button event %d -> btn %d loc %d.%d\n", event, button, y, x))
  1077.             status = on_mouse_click(button, y, x);
  1078.             break;
  1079. #else /* OPT_XTERM >=3, highlighting mode */
  1080.         case 'M':    /* button-event */
  1081.             event    = keystroke();
  1082.             x    = XtermPos() + x_origin;
  1083.             y    = XtermPos() + y_origin;
  1084.  
  1085.             button    = (event & 3) + 1;
  1086.             TRACE(("MOUSE-button event:%d x:%d y:%d\n", event, x, y))
  1087.             if (button > 3) {
  1088.                 endofDisplay();
  1089.                 return TRUE; /* button up */
  1090.             }
  1091.             wp = row2window(y-1);
  1092.             if (insertmode && wp != curwp) {
  1093.                 kbd_alarm();
  1094.                 return ABORT;
  1095.             }
  1096.             /* Tell the xterm how to highlight the selection.
  1097.              * It won't do anything else until we do this.
  1098.              */
  1099.             if (wp != 0) {
  1100.                 firstrow = wp->w_toprow + 1;
  1101.                 lastrow  = mode_row(wp) + 1;
  1102.             } else {        /* from message-line */
  1103.                 firstrow = term.t_nrow ;
  1104.                 lastrow  = term.t_nrow + 1;
  1105.             }
  1106.             if (y >= lastrow)    /* don't select modeline */
  1107.                 y = lastrow - 1;
  1108.             (void)lsprintf(temp, fmt, 1, x, y, firstrow, lastrow);
  1109.             putpad(temp);
  1110.             TTflush();
  1111.             /* Set the dot-location if button 1 was pressed in a
  1112.              * window.
  1113.              */
  1114.             if (wp != 0
  1115.              && button == 1
  1116.              && !reading_msg_line
  1117.              && setcursor(y-1, x-1)) {
  1118.                 (void)update(TRUE);
  1119.                 status = TRUE;
  1120.             } else if (button <= 3) {
  1121.                 /* abort the selection */
  1122.                 (void)lsprintf(temp, fmt, 0, x, y, firstrow, lastrow);
  1123.                 putpad(temp);
  1124.                 TTflush();
  1125.                 status = ABORT;
  1126.             } else {
  1127.                 status = FALSE;
  1128.             }
  1129.             break;
  1130.         case 't':    /* reports valid text-location */
  1131.             x = XtermPos();
  1132.             y = XtermPos();
  1133.  
  1134.             TRACE(("MOUSE-valid: x:%d y:%d\n", x, y))
  1135.             setwmark(y-1, x-1);
  1136.             yankregion();
  1137.  
  1138.             movecursor(save_row, save_col);
  1139.             (void)update(TRUE);
  1140.             break;
  1141.         case 'T':    /* reports invalid text-location */
  1142.             /*
  1143.              * The starting-location returned is not the location
  1144.              * at which the mouse was pressed.  Instead, it is the
  1145.              * top-most location of the selection.  In turn, the
  1146.              * ending-location is the bottom-most location of the
  1147.              * selection.  The mouse-up location is not necessarily
  1148.              * a pointer to valid text.
  1149.              *
  1150.              * This case handles multi-clicking events as well as
  1151.              * selections whose start or end location was not
  1152.              * pointing to text.
  1153.              */
  1154.             save_dot = DOT;
  1155.             startx = XtermPos();    /* starting-location */
  1156.             starty = XtermPos();
  1157.             endx   = XtermPos();    /* ending-location */
  1158.             endy   = XtermPos();
  1159.             mousex = XtermPos();    /* location at mouse-up */
  1160.             mousey = XtermPos();
  1161.  
  1162.             TRACE(("MOUSE-invalid: start(%d,%d) end(%d,%d) mouse(%d,%d)\n",
  1163.                 starty, startx,
  1164.                 endy,   endx,
  1165.                 mousey, mousex))
  1166.             setcursor(starty - 1, startx - 1);
  1167.             setwmark (endy   - 1, endx   - 1);
  1168.             if (MK.o != 0 && !is_at_end_of_line(MK))
  1169.                 MK.o += 1;
  1170.             yankregion();
  1171.  
  1172.             DOT = save_dot;
  1173.             movecursor(save_row, save_col);
  1174.             (void)update(TRUE);
  1175.             break;
  1176. #endif /* OPT_XTERM < 3 */
  1177.         default:
  1178.             status = FALSE;
  1179.         }
  1180.         endofDisplay();
  1181.     }
  1182.     return status;
  1183. }
  1184. #endif    /* OPT_XTERM */
  1185.  
  1186. #endif    /* DISP_TERMCAP */
  1187.