home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / nn.tar / nn-6.5.1 / term.c < prev    next >
C/C++ Source or Header  |  1996-08-12  |  45KB  |  2,378 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Terminal interface.
  5.  */
  6. #define raw __curses__raw__
  7. #include <signal.h>
  8. #include <errno.h>
  9. #include "config.h"
  10. #include "keymap.h"
  11. #include "regexp.h"
  12. #include "nn_term.h"
  13.  
  14. #ifdef RESIZING
  15. #include <sys/ioctl.h>            /* for TIOCGWINSZ */
  16.  
  17. #ifdef SYSV_RESIZING
  18. #include <sys/stream.h>
  19. #include <sys/ptem.h>
  20. #endif    /* SYSV_RESIZING */
  21.  
  22. extern int s_resized;
  23. #endif    /* RESIZING */
  24.  
  25. #ifdef FAKE_INTERRUPT
  26. #include <setjmp.h>
  27. #endif
  28.  
  29. #ifdef HAVE_TERMIOS_H
  30. #include <termios.h>
  31. #endif
  32.  
  33. #ifdef USE_TERMINFO
  34. # include <curses.h>
  35. # ifndef VINTR
  36. #  include <termio.h>    /* some systems don't include this in curses.h */
  37. # endif /* VINTR */
  38. # ifndef auto_left_margin
  39. #  include <term.h>
  40. # endif    /* !auto_left_margin */
  41. #else
  42. #define USE_TERMCAP
  43. #endif
  44.  
  45. #ifdef HAVE_TERMIO_H
  46. # ifdef USE_TERMCAP
  47. #  include <termio.h>
  48. # endif    /* USE_TERMCAP */
  49. #else
  50. # include <sgtty.h>
  51. #endif
  52.  
  53. /* SYSV curses.h clash */
  54. #undef raw
  55.  
  56. /* AIX term.h clash */
  57. #ifdef _AIX
  58. #undef Lines
  59. #undef Columns
  60. #endif    /* _AIX */
  61.  
  62. /* term.c */
  63.  
  64. #ifdef __STDC__
  65. #ifdef APOLLO_DOMAIN_OS
  66. static int outc __APROTO((int c));
  67. #else
  68. static int outc __APROTO((char c));
  69. #endif    /* APOLLO_DOMAIN_OS */
  70. #else
  71. static int outc __APROTO(());
  72. #endif    /* __STDC__ */
  73. static void set_term_speed __APROTO((register unsigned long sp));
  74. static void raw_not_ok_error __APROTO((void));
  75. static sig_type rd_timeout __APROTO((int n));
  76. static int read_char_kbd __APROTO((int tmo));
  77. static void unread_char __APROTO((int c));
  78.  
  79. static sig_type catch_winch();
  80.  
  81. void visual_on();
  82. void xterm_mouse_on();
  83. void xterm_mouse_off();
  84.  
  85. import int data_bits;
  86. import int batch_mode;
  87. import char *help_directory;
  88.  
  89. extern void ding();
  90. extern void clrmsg();
  91. extern void gotoxy();
  92.  
  93. struct msg_list {
  94.     char *buf;
  95.     struct msg_list *prev;
  96. };
  97. static struct msg_list *msg_stack = NULL, *msg_ptr = NULL;
  98.  
  99. export int  message_history = 15;
  100. export char *term_name = NULL;
  101. export int  show_current_time = 1;
  102. export int  conf_dont_sleep = 0;
  103. export int  prompt_length;
  104. export int  terminal_speed = 0;
  105. export int  slow_speed = 1200;
  106. export int  any_message = 0;
  107. export int  flow_control = 1;
  108. export int  use_visible_bell = 1; /* if supported by terminal */
  109. export int  ignore_xon_xoff = 1;
  110. export int  multi_key_guard_time = 2; /* tenths of a second */
  111. export int  guard_double_slash = 0; /* need /// or //+ to clear line */
  112. export char *shade_on_attr = NULL;
  113. export char *shade_off_attr = NULL;
  114. export int  mouse_state; /* if xterm is in mouse state */
  115. export int  mouse_usage;  /* 0 don't set mouse, 1 only if xterm,
  116.                 2 set mouse */
  117.  
  118. export key_type help_key = '?';
  119. export key_type comp1_key = SP;
  120. export key_type comp2_key = TAB;
  121. export key_type erase_key, kill_key;
  122. export key_type delword_key = CONTROL_('W');
  123.  
  124. static char bell_str[256] = "\007";
  125. static appl_keypad_mode = 0;
  126.  
  127. #ifdef USE_TERMINFO
  128.  
  129. #define HAS_CAP(str) (str && *str)
  130.  
  131. extern char *tgoto();        /* some systems don't have this in term.h */
  132.  
  133. #else
  134.  
  135. char *tgoto();
  136. char PC;
  137. char *BC, *UP;
  138. short ospeed;
  139.  
  140. static char XBC[64], XUP[64];
  141. static char enter_ca_mode[64], exit_ca_mode[64];
  142. static char cursor_home[64];
  143. static char cursor_address[128];
  144. static char clear_screen[64];
  145. static char clr_eol[64];
  146. static char clr_eos[64];
  147. static char enter_standout_mode[64], exit_standout_mode[64];
  148. static char enter_underline_mode[64], exit_underline_mode[64];
  149. static char key_down[64], key_up[64], key_right[64], key_left[64];
  150. static char keypad_local[64], keypad_xmit[64];
  151.  
  152. int  magic_cookie_glitch;    /* magic cookie size */
  153. int  ceol_standout_glitch;    /* hp brain damage! */
  154. int  auto_right_margin;        /* automatic right margin */
  155. int  eat_newline_glitch;    /* newline ignored at right margin */
  156.  
  157. #define putp(str)    tputs(str, 1, outc)
  158.  
  159. #define HAS_CAP(str)    (*str)
  160.  
  161. #endif    /* USE_TERMCAP */
  162.  
  163. static char key_mouse_d1[64] = "\33[M ";
  164. static char key_mouse_d2[64] = "\33[M!";
  165. static char key_mouse_d3[64] = "\33[M\"";
  166. static char key_mouse_u1[64] = "\33[M#";
  167.  
  168. /*
  169.  * Compute the greatest multiple of p not greater than x.
  170.  * p must be a power of 2.
  171.  * x must be nonnegative, for portability to non-2's-complement hosts.
  172.  */    
  173. #define DISCARD_REMAINDER(x,p) ((x) & ~((p)-1))
  174.  
  175. #ifdef __STDC__
  176. static int
  177. #ifdef APOLLO_DOMAIN_OS
  178. outc(int c)
  179. #else
  180. outc(char c)
  181. #endif    /* APOLLO_DOMAIN_OS */
  182. #else
  183. static int
  184. outc(c) char c;
  185. #endif    /* __STDC__ */
  186. {
  187.     putchar(c);
  188.     return 0;            /* XXX What is it supposed to return? */
  189. }
  190.  
  191.  
  192. #ifdef BROKEN_TPUTS
  193. /* tputs is broken on UNISYS I've been told */
  194. #define putpc(str, cnt)    tputs(str, 0, outc)
  195. #else
  196. #define putpc(str, cnt)    tputs(str, cnt, outc)
  197. #endif
  198.  
  199. #undef standout
  200.  
  201. int  Lines, Columns;    /* screen size */
  202. int  cookie_size;    /* size of magic cookie */
  203. int  two_cookies;    /* space needed to enter&exit standout mode */
  204. int  STANDOUT;        /* terminal got standout mode */
  205.  
  206. static int curxy_c = 0, curxy_l = -1, savxy_c = 0, savxy_l = -1;
  207. static int just_sent_cr = 0;    /* just sent \r to avoid 'xn' term attribute */
  208.  
  209. static int *nonsp;    /* number of non-space characters on line */
  210.  
  211. #ifdef TERM_DEBUG
  212. static char *term_debug = NULL;
  213. extern char *getenv();
  214. #define curxy_nonsp    (curxy_l < 0 ? -1 : nonsp[curxy_l])
  215. #endif
  216.  
  217. #ifdef FAKE_INTERRUPT
  218.  
  219. extern jmp_buf fake_keyb_sig;
  220. extern int arm_fake_keyb_sig;
  221. extern char fake_keyb_siglist[];
  222. #endif    /* FAKE_INTERRUPT */
  223.  
  224. #if defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)
  225.  
  226. /* This used to be 50, but there are some rather complex bugs in the SYSV */
  227. /* TERMIO driver... */
  228. #define KEY_BURST 2    /* read bursts of 1 char (or timeout after 100 ms) */
  229.  
  230. #undef CBREAK
  231.  
  232. #ifdef HAVE_TERMIOS_H
  233. static struct termios norm_tty, raw_tty;
  234. #else
  235. static struct termio norm_tty, raw_tty;
  236. #endif
  237.  
  238. #define    IntrC    ((key_type) norm_tty.c_cc[VINTR])
  239. #define    EraseC    ((key_type) norm_tty.c_cc[VERASE])
  240. #define KillC    ((key_type) norm_tty.c_cc[VKILL])
  241. #ifdef HAVE_TERMIOS_H
  242. #define SuspC   ((key_type) norm_tty.c_cc[VSUSP])
  243. #else
  244. #define SuspC    ((key_type) CONTROL_('Z'))    /* norm_tty.c_cc[SWTCH] */
  245. #endif
  246.  
  247. #else    /* V7/BSD TTY DRIVER */
  248.  
  249. static struct sgttyb norm_tty, raw_tty;
  250. static struct tchars norm_chars;
  251.  
  252. #define    IntrC    ((key_type) norm_chars.t_intrc)
  253. #define    EraseC    ((key_type) norm_tty.sg_erase)
  254. #define KillC    ((key_type) norm_tty.sg_kill)
  255.  
  256. #ifdef TIOCGLTC
  257. static struct     ltchars spec_chars;
  258. #define SuspC    ((key_type) spec_chars.t_suspc)
  259. #else
  260. #define    SuspC    ((key_type) CONTROL_('Z'))
  261. #endif
  262.  
  263. #endif
  264.  
  265. #ifdef USE_TERMCAP
  266.  
  267. opt_cap(cap, buf)
  268. char *cap, *buf;
  269. {
  270.     char *tgetstr();
  271.  
  272.     *buf = NUL;
  273.     return tgetstr(cap, &buf) != NULL;
  274. }
  275.  
  276. get_cap(cap, buf)
  277. char *cap, *buf;
  278. {
  279.     if (!opt_cap(cap, buf))
  280.     nn_exitmsg(1, "TERMCAP entry for %s has no '%s' capability",
  281.            term_name, cap);
  282. }
  283.  
  284. #endif  /* USE_TERMCAP */
  285.  
  286. /*
  287.  * timeout in n/10 seconds via SIGALRM
  288.  */
  289.  
  290. void micro_alarm(n)
  291. int n;
  292. {
  293. #ifdef HAVE_UALARM
  294.     ualarm(n<=1 ? 100000 : n*100000, 0); /* 4.3 BSD ualarm() */
  295. #else
  296. #ifdef MICRO_ALARM
  297.     if (n <= 0) n = 1;
  298.     MICRO_ALARM(n);            /* System specific timeout */
  299. #else
  300.     alarm(n <= 10 ? 1 : (n+9)/10);    /* Standard alarm() call */
  301. #endif    /* MICRO_ALARM */
  302. #endif    /* HAVE_UALARM */
  303. }
  304.  
  305. static int multi_keys = 0;
  306.  
  307. static struct multi_key {
  308.     key_type *cur_key;
  309.     key_type *keys;
  310.     key_type code;
  311. } multi_key_list[MULTI_KEYS];
  312.  
  313. void enter_multi_key(code, keys)
  314. int code;
  315. key_type *keys;
  316. {
  317.     register i;
  318.  
  319.     if (strlen((char *)keys) == 1)
  320.     /* will ignore arrow keys overlaying these keys */
  321.     if (*keys == NL || *keys == CR ||
  322.         *keys == erase_key || *keys == kill_key ||
  323.         *keys == IntrC) return;
  324.  
  325.     /* lookup code to see if it is already defined... */
  326.     for (i = 0; i < multi_keys; i++)
  327.     if (multi_key_list[i].code == (key_type)code)
  328.         goto replace_key;
  329.  
  330.     i = multi_keys++;
  331.  
  332.     /* now i points to matching or empty slot */
  333.     if (i >= MULTI_KEYS) {
  334.     /* should never happen */
  335.     log_entry('E', "too many multi keys");
  336.     return;
  337.     }
  338.  
  339.  replace_key:
  340.  
  341.     multi_key_list[i].keys = keys;
  342.     multi_key_list[i].code = code;
  343. }
  344.  
  345. void dump_multi_keys()
  346. {
  347.     register i;
  348.     register key_type *cp;
  349.  
  350.     clrdisp();
  351.     pg_init(0, 1);
  352.  
  353.     for (i = 0; i < multi_keys; i++) {
  354.     if (pg_next() < 0) break;
  355.     tprintf("%d\t%s\t", i, key_name(multi_key_list[i].code));
  356.     for (cp = multi_key_list[i].keys; *cp; cp++)
  357.         tprintf(" %s", key_name(*cp));
  358.     }
  359.  
  360.     pg_end();
  361. }
  362.  
  363.  
  364. #ifdef RESIZING
  365.  
  366. static sig_type catch_winch(n)
  367. int n;
  368. {
  369.     struct winsize winsize;
  370.     int i;
  371.  
  372.     (void) signal(SIGWINCH, catch_winch);
  373.     if (ioctl(0, TIOCGWINSZ, &winsize) >= 0
  374.     && (winsize.ws_row != Lines || winsize.ws_col != Columns)) {
  375.     nonsp = resizeobj(nonsp, int, winsize.ws_row);
  376.     if ((int)winsize.ws_row > Lines)
  377.         for (i = Lines; i < (int)winsize.ws_row; i++) nonsp[i] = winsize.ws_col;
  378.     if ((int)winsize.ws_col < Columns)
  379.         for (i = 0; i < (int)winsize.ws_row; i++)
  380.         if (nonsp[i] > (int)winsize.ws_col) nonsp[i] = winsize.ws_col;
  381.     Lines = winsize.ws_row;
  382.     Columns = winsize.ws_col;
  383.     curxy_l = -1;
  384.     s_redraw = 1;
  385.     s_resized = 1;
  386.     }
  387. #ifdef FAKE_INTERRUPT
  388.     if (fake_keyb_siglist[n] && arm_fake_keyb_sig)
  389.     longjmp(fake_keyb_sig, 1);
  390. #endif    /* FAKE_INTERRUPT */
  391. }
  392. #endif /* RESIZING */
  393.  
  394. #ifdef SV_INTERRUPT
  395. #ifdef NO_SIGINTERRUPT
  396. static siginterrupt(signo, on)
  397. {
  398.   struct sigvec sv;
  399.   sv.sv_handler = signal (signo, SIG_DFL);
  400.   sv.sv_mask = 0;
  401.   sv.sv_flags = on ? SV_INTERRUPT : 0;
  402.   sigvec (signo, &sv, 0);
  403. }
  404. #endif    /* NO_SIGINTERRUPT */
  405. #endif    /* SV_INTERRUPT */
  406.  
  407. #ifdef FAKE_INTERRUPT
  408. #define SV_INTERRUPT
  409. static siginterrupt (signo, on)
  410. {
  411.     fake_keyb_siglist[signo] = on;
  412. }
  413. #endif    /* FAKE_INTERRUPT */
  414.  
  415. static unsigned sp_table[] = {
  416.     B9600, 960,
  417. #ifdef B19200
  418.     B19200, 1920,
  419. #else
  420. #ifdef EXTA
  421.     EXTA, 1920,
  422. #endif    /* EXTA */
  423. #endif    /* B19200 */
  424. #ifdef B38400
  425.     B38400, 3840,
  426. #else
  427. #ifdef EXTB
  428.     EXTB, 3840,
  429. #endif    /* EXTB */
  430. #endif    /* B38400 */
  431.     B1200, 120,
  432.     B2400, 240,
  433.     B4800, 480,
  434.     B300,   30,
  435.     0,    0
  436. };
  437.  
  438. static  void set_term_speed(sp)
  439. register unsigned long sp;
  440. {
  441.     register unsigned *tp;
  442.  
  443.     for (tp = sp_table; *tp; tp += 2)
  444.     if (*tp == sp) {
  445.         terminal_speed = tp[1];
  446.         return;
  447.     }
  448.  
  449.     terminal_speed = 30;
  450. }
  451.  
  452. static void raw_not_ok_error()
  453. {
  454.     if (batch_mode) return;
  455.     nn_exitmsg(1, "Not prepared for terminal i/o");
  456.     /*NOTREACHED*/
  457. }
  458.  
  459.  
  460. #define    RAW_CHECK    if (terminal_speed == 0) {raw_not_ok_error(); return 0;}
  461. #define    RAW_CHECK_V    if (terminal_speed == 0) {raw_not_ok_error(); return;}
  462. #define BATCH_CHECK    if (terminal_speed == 0) return 0
  463. #define BATCH_CHECK_V    if (terminal_speed == 0) return
  464.  
  465. void init_term(full)
  466. int full;
  467. {
  468. #ifdef USE_TERMCAP
  469.     char tbuf[1024];
  470. #endif
  471.     int i;
  472.  
  473. #ifdef TERM_DEBUG
  474.     term_debug = getenv("TERM_DEBUG");
  475.     if (term_debug) fprintf (stderr, "init_term(%d)\n", full);
  476. #endif
  477.  
  478.     if (batch_mode) {
  479.     term_name = "batch";
  480.     close(0);
  481.     open("/dev/null", 0);
  482.     STANDOUT = 0;
  483.     cookie_size = 1;
  484.     return;
  485.     }
  486.  
  487.     if ((term_name = getenv("TERM")) == NULL) {
  488.     if (full)
  489.         nn_exitmsg(1, "No TERM variable in environment");
  490.     else
  491.         term_name = "unknown";
  492.     }
  493.  
  494.     if (!full) return;
  495.  
  496. #ifdef HAVE_TERMIO_H
  497.     ioctl(0, TCGETA, &norm_tty);
  498. #else
  499. #ifdef HAVE_TERMIOS_H
  500.     tcgetattr(0, &norm_tty);
  501. #else
  502.     ioctl(0, TIOCGETP, &norm_tty);
  503. #endif /* HAVE_TERMIOS_H */
  504. #endif /* HAVE_TERMIO_H */
  505.  
  506. #ifdef USE_TERMINFO
  507.     setupterm((char *)NULL, 1, (int *)NULL);
  508.     Columns = columns;
  509.     Lines = lines;
  510.     if (use_visible_bell && HAS_CAP(flash_screen))
  511.     strcpy(bell_str, flash_screen);
  512.     else if (HAS_CAP(bell))
  513.     strcpy(bell_str, bell);
  514.     if (! HAS_CAP(cursor_home))
  515.     cursor_home = copy_str(tgoto(cursor_address, 0, 0));
  516. #else
  517.  
  518.     if (tgetent(tbuf, term_name) <= 0)
  519.     nn_exitmsg(1, "Unknown terminal type: %s", term_name);
  520.  
  521.     if (opt_cap("bc", XBC)) BC = XBC;
  522.     if (opt_cap("up", XUP)) UP = XUP;
  523.     opt_cap("pc", cursor_address);    /* temp. usage */
  524.     PC = cursor_address[0];
  525.  
  526.     get_cap("cm", cursor_address);
  527.     if (!opt_cap("ho", cursor_home))
  528.     strcpy(cursor_home, tgoto(cursor_address, 0, 0));
  529.  
  530.     get_cap("cl", clear_screen);
  531.     opt_cap("ce", clr_eol);
  532.     opt_cap("cd", clr_eos);
  533.  
  534.     Lines = tgetnum("li");
  535.     Columns = tgetnum("co");
  536.  
  537.     opt_cap("so", enter_standout_mode);
  538.     opt_cap("se", exit_standout_mode);
  539.  
  540.     opt_cap("us", enter_underline_mode);
  541.     opt_cap("ue", exit_underline_mode);
  542.  
  543.     opt_cap("kd", key_down);
  544.     opt_cap("ku", key_up);
  545.     opt_cap("kr", key_right);
  546.     opt_cap("kl", key_left);
  547.  
  548.     magic_cookie_glitch = tgetnum("sg");
  549.  
  550.     ceol_standout_glitch = tgetflag("xs");
  551.     auto_right_margin = tgetflag("am");
  552.     eat_newline_glitch = tgetflag("xn");
  553.  
  554.     opt_cap("ti", enter_ca_mode);
  555.     opt_cap("te", exit_ca_mode);
  556.     opt_cap("ks", keypad_xmit);        /* used to turn "application cursor */
  557.     opt_cap("ke", keypad_local);    /* key" mode on and off (sometimes) */
  558.  
  559.     if (!use_visible_bell || !opt_cap("vb", bell_str))
  560.     if (!opt_cap("bl", bell_str))
  561.         strcpy(bell_str, "\007");
  562.  
  563. #endif /* USE_TERMINFO */
  564.  
  565. #ifdef RESIZING
  566.     {
  567.     struct winsize winsize;
  568.  
  569.     if (ioctl(0, TIOCGWINSZ, &winsize) >= 0
  570.         && winsize.ws_row != 0 && winsize.ws_col != 0) {
  571.         Lines = winsize.ws_row;
  572.         Columns = winsize.ws_col;
  573.         (void) signal(SIGWINCH, catch_winch);
  574. #ifdef SV_INTERRUPT
  575.         siginterrupt(SIGWINCH, 1);    /* make read from tty interruptable */
  576. #endif /* SV_INTERRUPT */
  577.     }
  578.     }
  579. #endif /* RESIZING */
  580.  
  581.     /* Stop NN from blowing up if on a *really* dumb terminal, like "dumb" */
  582.     if (Lines < 1)
  583.       Lines = 24;
  584.     if (Columns < 1)
  585.       Columns = 80;
  586.  
  587.     nonsp = newobj(int, Lines);
  588.     for (i = 0; i < Lines; i++) nonsp[i] = Columns;
  589.     
  590.     STANDOUT = HAS_CAP(enter_standout_mode);
  591.     cookie_size = magic_cookie_glitch;
  592.     if (STANDOUT) {
  593.     if (cookie_size < 0) cookie_size = 0;
  594.     two_cookies = 2 * cookie_size;
  595.     } else
  596.     cookie_size = two_cookies = 0;
  597.  
  598.     raw_tty = norm_tty;
  599.  
  600. #ifdef HAVE_TERMIO_H
  601.     raw_tty.c_iflag &= ~(BRKINT|INLCR|ICRNL|IGNCR|ISTRIP);
  602.     raw_tty.c_iflag |= IGNBRK|IGNPAR;
  603.     raw_tty.c_oflag &= ~OPOST;
  604.     raw_tty.c_lflag &= ~(ISIG|ICANON|XCASE|ECHO|NOFLSH);
  605.  
  606.     /* read a maximum of 10 characters in one burst; timeout in 1-200 ms */
  607.     raw_tty.c_cc[VMIN] = KEY_BURST;
  608.     raw_tty.c_cc[VTIME] = ((int)(raw_tty.c_cflag & CBAUD) > B1200) ? 1 : 2;
  609.     set_term_speed((unsigned long)(raw_tty.c_cflag & CBAUD));
  610. #else
  611. #ifdef HAVE_TERMIOS_H
  612.     cfmakeraw(&raw_tty);
  613.     /* read a maximum of 10 characters in one burst; timeout in 1-200 ms */
  614.     raw_tty.c_cc[VMIN] = KEY_BURST;
  615. #if 0
  616.     raw_tty.c_cc[VTIME] = (cfgetispeed(&raw_tty) > B1200) ? 1 : 2;
  617. #else
  618.     raw_tty.c_cc[VTIME] = 1;
  619. #endif /* 0 */
  620.     set_term_speed((unsigned long)cfgetospeed(&raw_tty));
  621. #ifdef SV_INTERRUPT
  622.     siginterrupt(SIGTSTP, 1);
  623.     siginterrupt(SIGALRM, 1);
  624. #endif /* SV_INTERRUPT */
  625. #else
  626.     ioctl(0, TIOCGETC, &norm_chars);
  627.  
  628. #ifdef TIOCGLTC
  629.     ioctl(0, TIOCGLTC, &spec_chars);
  630. #endif    /* TIOCGLTC */
  631.  
  632.     ospeed = norm_tty.sg_ospeed;
  633.     set_term_speed((unsigned long)ospeed);
  634.  
  635.     raw_tty.sg_flags &= ~(ECHO | CRMOD);
  636. #ifdef CBREAK
  637. #ifdef SV_INTERRUPT            /* make read from tty interruptable */
  638.     siginterrupt(SIGTSTP, 1);        /* this is necessary to redraw screen */
  639. #endif    /* SV_INTERRUPT */
  640.     raw_tty.sg_flags |= CBREAK;
  641. #else
  642.     raw_tty.sg_flags |= RAW;
  643. #endif    /* CBREAK */
  644.  
  645. #ifdef SV_INTERRUPT
  646.     siginterrupt(SIGALRM, 1);        /* make read from tty interruptable */
  647. #endif    /* SV_INTERRUPT */
  648. #endif  /* HAVE_TERMIOS_H */
  649. #endif    /* HAVE_TERMIO_H */
  650.  
  651.     erase_key = EraseC;
  652.     kill_key  = KillC;
  653.  
  654.     if (HAS_CAP(key_down))
  655.     enter_multi_key(K_down_arrow, (key_type *)key_down);
  656.     if (HAS_CAP(key_up))
  657.     enter_multi_key(K_up_arrow, (key_type *)key_up);
  658.     if (HAS_CAP(key_right))
  659.     enter_multi_key(K_right_arrow, (key_type *)key_right);
  660.     if (HAS_CAP(key_left))
  661.     enter_multi_key(K_left_arrow, (key_type *)key_left);
  662.  
  663.     enter_multi_key(K_m_d1, (key_type *)key_mouse_d1);
  664.     enter_multi_key(K_m_d2, (key_type *)key_mouse_d2);
  665.     enter_multi_key(K_m_d3, (key_type *)key_mouse_d3);
  666.     enter_multi_key(K_m_u1, (key_type *)key_mouse_u1);
  667.  
  668.     appl_keypad_mode = (HAS_CAP(keypad_xmit) && HAS_CAP(keypad_local));
  669.     if (!HAS_CAP(key_up)) appl_keypad_mode = 0;    /* no cursor keys */
  670.     if (appl_keypad_mode) {
  671.     /* Use of ks/ke isn't consistent, so we must guess what to do. */
  672.     /* If termcap expects keys to send ESC [, don't switch */
  673.     appl_keypad_mode = (key_up[0] != '\033' || key_up[1] != '[');
  674.     }
  675.     if ((mouse_usage == 2) || ((mouse_usage == 1) 
  676.                     && !strncmp("xterm",term_name,5))) {
  677.     mouse_state = 1;
  678.     flow_control = 0;
  679.     } else {
  680.     mouse_state = 0;
  681.     }
  682.     visual_on();
  683. }
  684.  
  685. void
  686. home()
  687. {
  688.     BATCH_CHECK_V;
  689.  
  690. #ifdef TERM_DEBUG
  691.     if (term_debug) fprintf(stderr, "home\n");
  692. #endif
  693.  
  694.     putp(cursor_home);
  695.     curxy_c = curxy_l = 0;
  696. }
  697.  
  698. void
  699. save_xy()
  700. {
  701.     savxy_c = curxy_c; savxy_l = curxy_l;
  702. }
  703.  
  704. void
  705. restore_xy()
  706. {
  707.     if (savxy_l < 0) return;
  708.     gotoxy(savxy_c, savxy_l); fl;
  709. }
  710.  
  711. void 
  712. gotoxy(c, l)
  713. int c, l;
  714. {
  715.     BATCH_CHECK_V;
  716.  
  717. #ifdef TERM_DEBUG
  718.     if (term_debug)
  719.     fprintf(stderr, "gotoxy %d %d -> %d %d\n", curxy_c, curxy_l, c, l);
  720. #endif
  721.  
  722.     if (Columns <= (unsigned)c || Lines <= (unsigned)l)
  723.     return;
  724.  
  725.     if (!(c | l))
  726.     putp(cursor_home);
  727.     else
  728.         putp(tgoto(cursor_address, c, l));
  729.     curxy_c = c; curxy_l = l;
  730. }
  731.  
  732. void
  733. clrdisp()
  734. {
  735.     int i;
  736.  
  737.     BATCH_CHECK_V;
  738.  
  739. #ifdef TERM_DEBUG
  740.     if (term_debug) fprintf(stderr, "clrdisp\n");
  741. #endif
  742.  
  743.     putpc(clear_screen, Lines);
  744.     curxy_c = curxy_l = 0;
  745.     savxy_l = -1;
  746.     for (i = 0; i < Lines; i++) nonsp[i] = 0;
  747.     msg_ptr = msg_stack;
  748. }
  749.  
  750. void     clrline_noflush();
  751.  
  752. void
  753. clrline()
  754. {
  755.     BATCH_CHECK_V;
  756.  
  757.     /* If we moved the cursor left to avoid weird effects, don't clear. */
  758.     if (just_sent_cr)
  759.     return;
  760.  
  761.     clrline_noflush();
  762.     fl;
  763. }
  764.  
  765. void
  766. clrline_noflush()
  767. {
  768.     int oldxy_c, oldxy_l, spcnt;
  769.  
  770.     BATCH_CHECK_V;
  771.  
  772. #ifdef TERM_DEBUG
  773.     if (term_debug)
  774.     fprintf(stderr, "clrline %d %d [%d]",curxy_c, curxy_l, curxy_nonsp);
  775. #endif
  776.  
  777.     if (curxy_l < 0)
  778.     return;
  779.  
  780.     /* remainder of line already blank? */
  781.  
  782.     if (curxy_c >= nonsp[curxy_l]) {
  783. #ifdef TERM_DEBUG
  784.     if (term_debug) fprintf(stderr, " ignored\n");
  785. #endif
  786.         return;
  787.     }
  788.  
  789.     if (HAS_CAP(clr_eol)) {
  790. #ifdef TERM_DEBUG
  791.         if (term_debug) fprintf(stderr, "\n");
  792. #endif
  793.         putp(clr_eol);
  794.     } else {
  795.     oldxy_c = curxy_c; oldxy_l = curxy_l;
  796.  
  797.     spcnt = nonsp[curxy_l] - curxy_c;
  798.  
  799.     /* guard against scroll */
  800.  
  801.     if (auto_right_margin && curxy_l == Lines-1 && curxy_c+spcnt == Columns)
  802.         spcnt--;
  803.  
  804. #ifdef TERM_DEBUG
  805.     if (term_debug) fprintf(stderr," %d\n", spcnt);
  806. #endif /* TERM_DEBUG */
  807.  
  808. #ifdef TERM_DEBUG
  809.     if (term_debug && *term_debug) {
  810.         while (spcnt--) tputc(*term_debug);
  811.           spcnt = 0;
  812.     }
  813. #endif
  814.     /* clear out line */
  815.  
  816.     while (spcnt--) tputc(SP);
  817.  
  818.     if (curxy_c != oldxy_c || curxy_l != oldxy_l)
  819.         gotoxy(oldxy_c, oldxy_l);
  820.     }
  821.     nonsp[curxy_l] = curxy_c;
  822. }
  823.  
  824. void
  825. clrpage()
  826. {
  827.     int oldxy_c, oldxy_l, i;
  828.  
  829.     BATCH_CHECK_V;
  830.  
  831. #ifdef TERM_DEBUG
  832.     if (term_debug)
  833.     fprintf(stderr, "clrpage %d %d [%d]\n", curxy_c, curxy_l, curxy_nonsp);
  834. #endif
  835.  
  836.     if (curxy_l < 0)
  837.     return;
  838.  
  839.     oldxy_c = curxy_c; oldxy_l = curxy_l;
  840.  
  841.     /* code below only handles curxy_c == 0 */
  842.  
  843.     if (curxy_c != 0) {
  844.     clrline();
  845.     if (curxy_l < Lines-1) gotoxy(0, curxy_l+1);
  846.     }
  847.  
  848.     /* clear to end of screen */
  849.  
  850.     if (curxy_c == 0) {
  851.         if (HAS_CAP(clr_eos)) {
  852.         putpc(clr_eos, Lines - curxy_l);
  853.         for (i = curxy_l; i < Lines; i++) nonsp[i] = 0;
  854.         } else if (curxy_l == 0) {
  855.         putpc(clear_screen, Lines);
  856.         for (i = 0; i < Lines; i++) nonsp[i] = 0;
  857.         } else {
  858.         for (i = curxy_l; i < Lines; i++) {
  859.         if (nonsp[i] != 0) {
  860.             gotoxy(0, i);
  861.                     clrline_noflush();
  862.         }
  863.         }
  864.     }
  865.     }
  866.  
  867.     if (curxy_c != oldxy_c || curxy_l != oldxy_l)
  868.     gotoxy(oldxy_c, oldxy_l);
  869.  
  870.     fl;
  871.     msg_ptr = msg_stack;
  872. }
  873.  
  874. static char buf[512];
  875.  
  876. /*VARARGS*/
  877. void tprintf(va_alist)
  878. va_dcl
  879. {
  880.     use_vararg;
  881.  
  882.     start_vararg;
  883.     tvprintf(va_args1toN);
  884.     end_vararg;
  885. }
  886.  
  887. void tvprintf(va_tail)
  888. va_tdcl
  889. {
  890.     char *fmt, *str;
  891.  
  892.     fmt = va_arg1(char *);
  893.     vsprintf(buf, fmt, va_args2toN);
  894.  
  895.     for (str = buf; *str; str++)
  896.         tputc(*str);
  897. }
  898.  
  899. void tputc(c)
  900. int c;
  901. {
  902.     int i;
  903.  
  904. #ifdef TERM_DEBUG
  905.     if (term_debug) {
  906.     fprintf (stderr, "tputc %d %d [%d] ", curxy_c, curxy_l, curxy_nonsp);
  907.     if (c < ' ' || c > '~')
  908.     else
  909.         fprintf(stderr, "'%c'", c);
  910.     }
  911. #endif
  912.  
  913.     just_sent_cr = 0;
  914.  
  915.     putchar(c);
  916.  
  917.     switch (c) {
  918.  
  919.     case '\n':
  920.     curxy_c = 0;
  921.     if (curxy_l >= 0) curxy_l++;
  922.     break;
  923.  
  924.     case '\r':
  925.     curxy_c = 0;
  926.         break;
  927.  
  928.     case '\t':
  929.     curxy_c = DISCARD_REMAINDER(curxy_c + 8, 8);
  930.      break;
  931.  
  932.     case '\b':
  933.     curxy_c--;
  934.     break;
  935.  
  936.     case ' ':
  937.     curxy_c++;
  938.     if (curxy_l >= 0 && nonsp[curxy_l] == curxy_c)
  939.         nonsp[curxy_l]--;
  940.     break;
  941.  
  942.     default:
  943.     curxy_c++;
  944.     if (curxy_l >= 0 && nonsp[curxy_l] < curxy_c)
  945.          nonsp[curxy_l] = curxy_c;
  946.     break;
  947.        
  948.     }
  949.  
  950. #ifdef TERM_DEBUG
  951.     if (term_debug)
  952.     fprintf(stderr, " -> %d %d [%d]",curxy_c,curxy_l,curxy_nonsp);
  953. #endif
  954.  
  955.     /* account for right margin */
  956.  
  957.     if (curxy_c == Columns) {
  958. #ifdef TERM_DEBUG
  959.     if (term_debug) fprintf(stderr, " margin");
  960. #endif
  961.     if (auto_right_margin) {
  962.         if (eat_newline_glitch) {
  963.         putchar(CR);
  964.                 just_sent_cr = 1;
  965.         curxy_c = 0;
  966.         } else {
  967.         curxy_c = 0;
  968.         if (curxy_l >= 0) curxy_l++;
  969.         }
  970.     } else
  971.         curxy_c--;
  972.     }
  973.  
  974.     /* account for vertical scroll */
  975.  
  976.     if (curxy_l == Lines) {
  977. #ifdef TERM_DEBUG
  978.     if (term_debug) fprintf(stderr, " scroll");
  979. #endif
  980.     for (i = 1; i < Lines; i++)
  981.         nonsp[i-1] = nonsp[i];
  982.     nonsp[--curxy_l] = 0;
  983.     }
  984.  
  985. #ifdef TERM_DEBUG
  986.     if (term_debug) fprintf(stderr, "\n");
  987. #endif
  988. }
  989.  
  990. static char so_buf[512], *so_p;
  991. static int so_c, so_l, so_b, so_active = 0;
  992.  
  993. int so_gotoxy(c, l, blank)
  994. int c, l, blank;
  995. {
  996.     if (!STANDOUT && c >= 0) {
  997.     if (c>= 0 && l >= 0) gotoxy(c, l);
  998.     return 0;
  999.     }
  1000.  
  1001.     so_active++;
  1002.     so_c = c;
  1003.     so_l = l;
  1004.     so_b = blank;
  1005.     so_p = so_buf;
  1006.     *so_p = NUL;
  1007.  
  1008.     return 1;    /* not really true if not standout & c < 0 */
  1009. }
  1010.  
  1011. /*VARARGS*/
  1012. void so_printf(va_alist)
  1013. va_dcl
  1014. {
  1015.     use_vararg;
  1016.  
  1017.     start_vararg;
  1018.     so_vprintf(va_args1toN);
  1019.     end_vararg;
  1020. }
  1021.  
  1022. void so_vprintf(va_tail)
  1023. va_tdcl
  1024. {
  1025.     char *fmt;
  1026.  
  1027.     if (!so_active) {
  1028.     if (ceol_standout_glitch) highlight(0); /* xxx why? */
  1029.     tvprintf(va_args1toN);
  1030.     return;
  1031.     }
  1032.  
  1033.     fmt = va_arg1(char *);
  1034.     vsprintf(so_p, fmt, va_args2toN);
  1035.     while (*so_p) so_p++;
  1036. }
  1037.  
  1038. void so_end()
  1039. {
  1040.     int len;
  1041.  
  1042.     if (!so_active) return;
  1043.  
  1044.     if (so_l >= 0) {
  1045.  
  1046.     len = so_p - so_buf + two_cookies;
  1047.  
  1048.     if (so_c < 0)
  1049.         so_c = Columns - len - 2;
  1050.     if (so_c < 0) so_c = 0;
  1051.  
  1052.     if (len + so_c >= Columns) {
  1053.         len = Columns - so_c - two_cookies;
  1054.         so_buf[len] = NUL;
  1055.     }
  1056.  
  1057.     if (cookie_size) {
  1058.         gotoxy(so_c + len - cookie_size, so_l);
  1059.         standout(0);
  1060.     }
  1061.  
  1062.     gotoxy(so_c, so_l);
  1063.  
  1064.     }
  1065.  
  1066.     if ((so_b & 1) && (!STANDOUT || !cookie_size)) tputc(SP);
  1067.  
  1068.     if (STANDOUT) {
  1069.     if (ceol_standout_glitch) clrline();
  1070.     standout(1);
  1071.     }
  1072.  
  1073.     tprintf("%s", so_buf);
  1074.  
  1075.     if (STANDOUT) standout(0);
  1076.  
  1077.     if ((so_b & 2) && (!STANDOUT || !cookie_size)) tputc(SP);
  1078.  
  1079.     so_active = 0;
  1080. }
  1081.  
  1082.  
  1083. /*VARARGS*/
  1084. void so_printxy(va_alist)
  1085. va_dcl
  1086. {
  1087.     int c, l;
  1088.     use_vararg;
  1089.  
  1090.     start_vararg;
  1091.  
  1092.     c = va_arg1(int);
  1093.     l = va_arg2(int);
  1094.  
  1095.     so_gotoxy(c, l, 0);
  1096.     so_vprintf(va_args3toN);
  1097.     so_end();
  1098.  
  1099.     end_vararg;
  1100. }
  1101.  
  1102.     
  1103. int underline(on)
  1104. int on;
  1105. {
  1106.     if (cookie_size) return 0;
  1107. #ifdef TERM_DEBUG
  1108.     if (term_debug)
  1109.     fprintf(stderr, "underline %d %d [%d] %d", curxy_c, curxy_l, curxy_nonsp, on);
  1110. #endif
  1111.     if (! HAS_CAP(enter_underline_mode)) return 0;
  1112.     putp(on ? enter_underline_mode : exit_underline_mode);
  1113.     return 1;
  1114. }
  1115.  
  1116. int highlight(on)
  1117. int on;
  1118. {
  1119.     if (cookie_size) return 0;
  1120. #ifdef TERM_DEBUG
  1121.     if (term_debug)
  1122.     fprintf(stderr, "highlight %d %d [%d] %d", curxy_c, curxy_l, curxy_nonsp, on);
  1123. #endif
  1124.     if (! HAS_CAP(enter_standout_mode)) return 0;
  1125.     putp(on ? enter_standout_mode : exit_standout_mode);
  1126.     return 1;
  1127. }
  1128.  
  1129. int shadeline(on)
  1130. int on;
  1131. {
  1132.     if (cookie_size) return 0;
  1133. #ifdef TERM_DEBUG
  1134.     if (term_debug)
  1135.     fprintf(stderr, "shadeline %d %d [%d] %d", curxy_c, curxy_l, curxy_nonsp, on);
  1136. #endif
  1137.     if (shade_on_attr && shade_off_attr) {
  1138.     putp(on ? shade_on_attr : shade_off_attr);
  1139.     return 1;
  1140.     } else
  1141.     return underline(1);
  1142. }
  1143.     
  1144. int standout(on)
  1145. int on;
  1146. {
  1147. #ifdef TERM_DEBUG
  1148.     if (term_debug)
  1149.     fprintf(stderr, "standout %d %d [%d] %d", curxy_c, curxy_l, curxy_nonsp, on);
  1150. #endif
  1151.     if (! HAS_CAP(enter_standout_mode)) return 0;
  1152.     putp(on ? enter_standout_mode : exit_standout_mode);
  1153.     curxy_c += cookie_size;
  1154.     if (curxy_l >= 0 && curxy_c > nonsp[curxy_l])
  1155.     nonsp[curxy_l] = curxy_c;
  1156. #ifdef TERM_DEBUG
  1157.     if (term_debug)
  1158.     fprintf(stderr, " -> %d %d [%d]\n", curxy_c, curxy_l, curxy_nonsp);
  1159. #endif
  1160.     return 1;
  1161. }
  1162.  
  1163. static int is_visual = 0;
  1164. static int is_raw = 0;
  1165.  
  1166. #ifdef HAVE_TERMIO_H
  1167. #define RAW_MODE_ON    ioctl(0, TCSETAW, &raw_tty)
  1168. #define RAW_MODE_OFF   ioctl(0, TCSETAW, &norm_tty)
  1169. #else
  1170. #ifdef HAVE_TERMIOS_H
  1171. #define RAW_MODE_ON    tcsetattr(0, TCSADRAIN, &raw_tty)
  1172. #define RAW_MODE_OFF   tcsetattr(0, TCSADRAIN, &norm_tty)
  1173. #else
  1174. #define RAW_MODE_ON    ioctl(0, TIOCSETP, &raw_tty)
  1175. #define RAW_MODE_OFF   ioctl(0, TIOCSETP, &norm_tty)
  1176. #endif    /* HAVE_TERMIOS_H */
  1177. #endif    /* HAVE_TERMIO_H */
  1178.  
  1179. void
  1180. xterm_mouse_on()
  1181. {
  1182.     putp("\33[?1000h"); 
  1183. }
  1184.  
  1185. void
  1186. xterm_mouse_off()
  1187. {
  1188.     putp("\33[?1000l"); 
  1189. }
  1190.  
  1191. void
  1192. visual_on()
  1193. {
  1194.     BATCH_CHECK_V;
  1195.  
  1196.     if (terminal_speed == 0) return;
  1197.  
  1198. #ifdef TERM_DEBUG
  1199.     if (term_debug) fprintf(stderr, "visual_on\n");
  1200. #endif
  1201.  
  1202.     if (!is_visual) {
  1203.     if (HAS_CAP(enter_ca_mode)) putp(enter_ca_mode);
  1204.     if (appl_keypad_mode) putp(keypad_xmit);
  1205.     if (mouse_state)
  1206.         xterm_mouse_on();
  1207.     fl;
  1208.     }
  1209.     is_visual = 1;
  1210. }
  1211.  
  1212. int visual_off()
  1213. {
  1214.     int was_raw = is_raw;
  1215.  
  1216.     if (terminal_speed == 0) return 0;
  1217.  
  1218. #ifdef TERM_DEBUG
  1219.     if (term_debug) fprintf(stderr, "visual_off\n");
  1220. #endif
  1221.  
  1222.     if (is_visual) {
  1223.     if (appl_keypad_mode) putp(keypad_local);
  1224.     if (HAS_CAP(exit_ca_mode)) putp(exit_ca_mode);
  1225.     if (mouse_state)
  1226.         xterm_mouse_off();
  1227.     fl;
  1228.     }
  1229.     is_visual = 0;
  1230.  
  1231.     is_raw = 1;
  1232.     unset_raw();
  1233.  
  1234.     return was_raw;
  1235. }
  1236.  
  1237.  
  1238. #ifdef CBREAK
  1239. void
  1240. nn_raw()
  1241. {
  1242.     RAW_CHECK_V;
  1243.  
  1244.     if (is_raw == 1)
  1245.     return;
  1246.     is_raw = 1;
  1247.     RAW_MODE_ON;
  1248. }
  1249.  
  1250. int
  1251. no_raw()
  1252. {
  1253.     return 0;
  1254. }
  1255.  
  1256. int
  1257. unset_raw()
  1258. {
  1259.     if (is_raw == 0)
  1260.     return 0;
  1261.     RAW_CHECK;
  1262.     RAW_MODE_OFF;
  1263.     is_raw = 0;
  1264.     return 1;
  1265. }
  1266.  
  1267. #else /* not CBREAK */
  1268. static int must_set_raw = 1;
  1269.  
  1270. #undef raw
  1271. void
  1272. nn_raw()
  1273. {
  1274.     RAW_CHECK_V;
  1275.  
  1276.     if (!flow_control) {
  1277.     if (!must_set_raw) return;
  1278.     must_set_raw = 0;
  1279.     }
  1280.  
  1281.     if (is_raw) return;
  1282.  
  1283.     RAW_MODE_ON;
  1284.     is_raw++;
  1285. }
  1286.  
  1287. int no_raw()
  1288. {
  1289.     if (!flow_control) return 0;
  1290.  
  1291.     if (!is_raw) return 0;
  1292.  
  1293.     RAW_CHECK;
  1294.  
  1295.     RAW_MODE_OFF;
  1296.  
  1297.     is_raw = 0;
  1298.  
  1299.     return 1;
  1300. }
  1301.  
  1302. int unset_raw()
  1303. {
  1304.     int was_raw = is_raw;
  1305.  
  1306.     if (is_raw) {
  1307.     RAW_CHECK;
  1308.     RAW_MODE_OFF;
  1309.     is_raw = 0;
  1310.     }
  1311.  
  1312.     if (!flow_control)
  1313.     must_set_raw = 1;
  1314.     return was_raw;
  1315. }
  1316.  
  1317. #endif /* CBREAK */
  1318.  
  1319. #ifndef KEY_BURST
  1320. #define KEY_BURST 32
  1321. #endif    /* KEY_BURST */
  1322. #define RD_PUSHBACK 10
  1323. static char rd_buffer[KEY_BURST+RD_PUSHBACK];    /* Holds stuff from read */
  1324. static char *rd_ptr;
  1325. static int rd_count = 0, rd_alarm = 0;
  1326. #ifdef FAKE_INTERRUPT
  1327. static jmp_buf fake_alarm_sig;
  1328. #endif    /* FAKE_INTERRUPT */
  1329.  
  1330. static sig_type rd_timeout(n)
  1331. int n;
  1332. {
  1333.     rd_alarm = 1;
  1334. #ifdef FAKE_INTERRUPT
  1335.     longjmp(fake_alarm_sig, 1);
  1336. #endif    /* FAKE_INTERRUPT */
  1337. }
  1338.  
  1339. #define RD_TIMEOUT    0x1000
  1340. #define RD_INTERRUPT    0x1001
  1341.  
  1342. static int read_char_kbd(tmo)
  1343. int tmo;    /* timeout if no input arrives */
  1344. {
  1345.     if (rd_count <= 0) {
  1346.     if (tmo) {
  1347. #ifdef FAKE_INTERRUPT
  1348.         if (setjmp(fake_alarm_sig)) goto tmout;
  1349. #endif    /* FAKE_INTERRUPT */
  1350.         rd_alarm = 0;
  1351.         signal(SIGALRM, rd_timeout);
  1352.         micro_alarm(multi_key_guard_time);
  1353.     }
  1354.     rd_ptr = rd_buffer + RD_PUSHBACK;
  1355.     rd_count = read(0, rd_ptr, KEY_BURST);
  1356.     if (tmo) {
  1357.         if (rd_alarm) goto tmout;
  1358.         alarm(0);
  1359.     }
  1360.     if (rd_count < 0) {
  1361.         if (errno != EINTR) s_hangup++;
  1362.         return RD_INTERRUPT;
  1363.     }
  1364.     }
  1365.     --rd_count;
  1366.     return *rd_ptr++;
  1367.     
  1368.  tmout:
  1369.     rd_count = 0;
  1370.     return RD_TIMEOUT;
  1371. }
  1372.  
  1373. static void unread_char(c)
  1374. int c;
  1375. {
  1376.     if (rd_ptr == rd_buffer) return;
  1377.     rd_count++;
  1378.     *--rd_ptr = c;
  1379. }
  1380.  
  1381. void
  1382. flush_input()
  1383. {
  1384. #ifndef HAVE_TERMIO_H
  1385. #ifdef FREAD
  1386.     int arg;
  1387. #endif
  1388. #endif
  1389.  
  1390.     BATCH_CHECK_V;
  1391.  
  1392. #ifdef HAVE_TERMIO_H
  1393.     ioctl(0, TCFLSH, 0);
  1394. #else
  1395. #ifdef HAVE_TERMIOS_H
  1396.     ioctl(0, TCIFLUSH);
  1397. #else
  1398. #ifdef FREAD
  1399.     arg = FREAD;
  1400.     ioctl(0, TIOCFLUSH, &arg);
  1401. #else
  1402.     ioctl(0, TIOCFLUSH, 0);
  1403. #endif    /* FREAD */
  1404. #endif  /* HAVE_TERMIOS_H */
  1405. #endif    /* HAVE_TERMIO_H */
  1406.     rd_count = 0;
  1407. }
  1408.  
  1409. int enable_stop = 1;
  1410.  
  1411. static int do_macro_processing = 1;
  1412. export int mouse_x,mouse_y = -1;
  1413. static int mouse_last = 0;
  1414. int get_c()
  1415. {
  1416.     key_type c, first_key;
  1417.     int key_cnt, mc, n;
  1418.     register struct multi_key *mk, *multi_match;
  1419.     register int i;
  1420.  
  1421.     multi_match = NULL;
  1422.     first_key = 0;
  1423.     mouse_y = -1;
  1424.  
  1425.  next_key:
  1426.     if (s_hangup) return K_interrupt;
  1427.  
  1428.     if (do_macro_processing)
  1429.     switch (m_getc(&mc)) {
  1430.      case 0: break;
  1431.      case 1: return mc;
  1432.      case 2: return K_interrupt;
  1433.     }
  1434.  
  1435. #ifdef RESIZING
  1436.     if (s_resized) goto redraw;
  1437. #endif    /* RESIZING */
  1438.  
  1439.     if (batch_mode)
  1440.     nn_exitmsg(1, "Attempt to read keyboard input in batch mode");
  1441.  
  1442.     for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++)
  1443.     mk->cur_key = mk->keys;
  1444.     key_cnt = 0;
  1445.  
  1446. #ifdef FAKE_INTERRUPT
  1447.     if (setjmp(fake_keyb_sig)) goto intr;
  1448.     arm_fake_keyb_sig = 1;
  1449. #endif    /* FAKE_INTERRUPT */
  1450.  
  1451.  multi:
  1452.     switch (n = read_char_kbd(key_cnt)) {
  1453.  
  1454.      case RD_INTERRUPT:
  1455. #ifdef CBREAK
  1456.     if (s_redraw) goto redraw;
  1457. #endif    /* CBREAK */
  1458. #ifdef RESIZING
  1459.     if (s_resized) goto redraw;
  1460. #endif    /* RESIZING */
  1461.     goto intr;
  1462.  
  1463.      case RD_TIMEOUT:
  1464.     while (--key_cnt > 0) unread_char(multi_match->keys[key_cnt]);
  1465.     c = first_key;
  1466.     goto got_char;
  1467.     
  1468.      default:
  1469.     c = (key_type)n;
  1470.     if (data_bits < 8) c &= 0x7f;
  1471.     if (ignore_xon_xoff)
  1472.         if (c == CONTROL_('Q') || c == CONTROL_('S')) goto multi;
  1473.     break;
  1474.     }
  1475.  
  1476.     multi_match = NULL;
  1477.     for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++) {
  1478.     if (mk->cur_key == NUL) continue;
  1479.     if (*(mk->cur_key)++ != c) {
  1480.         mk->cur_key = NUL;
  1481.         continue;
  1482.     }
  1483.     if (*(mk->cur_key) == NUL) {
  1484.         c = mk->code;
  1485.  
  1486.             /* xterm mouse specific code, translate cursor position
  1487.            into static variables, synthesize key up events */
  1488.         if ((c >= K_m_d1) && (c <= K_m_u1)) {
  1489.         mouse_x = read_char_kbd(key_cnt) - '!';
  1490.         mouse_y = read_char_kbd(key_cnt) - '!';
  1491.         if (c == K_m_u1) {
  1492.             if (mouse_last == K_m_d2) {
  1493.             c = K_m_u2;
  1494.             } else if (mouse_last == K_m_d3) {
  1495.             c = K_m_u3;
  1496.             }
  1497.         }
  1498.         mouse_last = c;
  1499.         }
  1500.         goto got_char;
  1501.     }
  1502.     multi_match = mk;
  1503.     }
  1504.  
  1505.     if (multi_match) {
  1506.     if (key_cnt == 0) first_key = c;
  1507.     key_cnt++;
  1508.     goto multi;
  1509.     }
  1510.     if (key_cnt) {
  1511.     if (key_cnt == 1 && first_key == 033) {
  1512.         unread_char(c);
  1513.         c = 033;
  1514.         goto got_char;
  1515.     }
  1516.     ding();
  1517.     flush_input();
  1518.     goto next_key;
  1519.     }
  1520.  
  1521.  got_char:
  1522. #ifdef FAKE_INTERRUPT
  1523.     arm_fake_keyb_sig = 0;
  1524. #endif    /* FAKE_INTERRUPT */
  1525.     c = global_key_map[c];
  1526.  
  1527. #ifndef CBREAK
  1528.     if (c == IntrC) return K_interrupt;    /* don't flush */
  1529.     if (c == SuspC) {
  1530.     if (enable_stop && suspend_nn()) goto redraw;
  1531.     goto next_key;
  1532.     }
  1533. #endif    /* CBREAK */
  1534.     return (int)c;
  1535.  
  1536.  intr:
  1537. #ifdef FAKE_INTERRUPT
  1538.     arm_fake_keyb_sig = 0;
  1539. #endif    /* FAKE_INTERRUPT */
  1540.     rd_count = 0;
  1541.     return K_interrupt;
  1542.  
  1543.  redraw:
  1544. #ifdef RESIZING
  1545.     s_resized = 0;
  1546. #endif    /* RESIZING */
  1547.     s_redraw = 0;
  1548.     return GETC_COMMAND | K_REDRAW;
  1549. }
  1550.  
  1551.  
  1552. /*
  1553.  * read string with completion, pre-filling, and break on first char
  1554.  *
  1555.  *    dflt        is a string that will be use as default value if the
  1556.  *            space bar is hit as the first character.
  1557.  *
  1558.  *    prefill        pre-fill the buffer with .... and print it
  1559.  *
  1560.  *    break_chars    return immediately if one of these characters
  1561.  *            is entered as the first character.
  1562.  *
  1563.  *    completion     is a function that will fill the buffer with a value
  1564.  *            see the group_completion and file_completion routines
  1565.  *            for examples.
  1566.  */
  1567.  
  1568. char *get_s(dflt, prefill, break_chars, completion)
  1569. char *dflt, *prefill, *break_chars;
  1570. fct_type completion;
  1571. {
  1572.     static key_type lbuf[GET_S_BUFFER];
  1573.     register char *cp;
  1574.     register int i, c, lastc;
  1575.     char *ret_val = (char *)lbuf;
  1576.     int comp_used, comp_len;
  1577.     int ostop, max, did_help;
  1578.     int hit_count;
  1579.  
  1580.     switch (m_gets((char *)lbuf)) {
  1581.      case 0:
  1582.     break;
  1583.      case 1:
  1584.     return (char *)lbuf;
  1585.      case 2:
  1586.     return NULL;
  1587.     }
  1588.  
  1589.     ostop = enable_stop;
  1590.     enable_stop = 0;
  1591.     do_macro_processing = 0;
  1592.     hit_count = 0;
  1593.  
  1594.     max = Columns - prompt_length;
  1595.  
  1596.     if (max >= FILENAME) max = FILENAME-1;
  1597.  
  1598.     i = comp_len = comp_used = did_help = 0;
  1599.  
  1600.     if (prefill && prefill[0]) {
  1601.     while ((c = *prefill++)) {
  1602.         if (i == max) break;
  1603.  
  1604.         tputc(c);
  1605.         lbuf[i] = c;
  1606.         i++;
  1607.     }
  1608.     fl;
  1609.     }
  1610.  
  1611.     if (dflt && *dflt == NUL)
  1612.     dflt = NULL;
  1613.  
  1614.     if (break_chars && *break_chars == NUL)
  1615.     break_chars = NULL;
  1616.  
  1617.     c = NUL;
  1618.     for(;;) {
  1619.     lastc = c;
  1620.     c = get_c();
  1621.     if (c & GETC_COMMAND) continue;
  1622.  
  1623.      kill_prefill_hack:
  1624.  
  1625.     hit_count++;
  1626.  
  1627.     if (i == 0) {
  1628.         if (c == comp1_key && dflt) {
  1629.         while ((c = *dflt++) != NUL && i < max) {
  1630.             tputc(c);
  1631.             lbuf[i] = c;
  1632.             i++;
  1633.         }
  1634.         fl;
  1635.         dflt = NULL;
  1636.         continue;
  1637.         }
  1638.         if ((cp = break_chars)) { /* Stupid ^@$# GCC!!! */
  1639.         while (*cp)
  1640.             if (*cp++ == c) {
  1641.             lbuf[0] = c;
  1642.             lbuf[1] = NUL;
  1643.             goto out;
  1644.             }
  1645.         }
  1646.     }
  1647.  
  1648.     if (completion != NULL_FCT) {
  1649.         if (comp_used && c == erase_key) {
  1650.         if (comp_len) {
  1651.             i -= comp_len;
  1652.             while (--comp_len >= 0) tputc(BS);
  1653.             clrline();
  1654.         }
  1655.         if (!CALL(completion)(lbuf, -(i+1)) && did_help)
  1656.             clrmsg(i);
  1657.         did_help = 0;
  1658.         comp_len = comp_used = 0;
  1659.         if (lastc == help_key) goto no_completion;
  1660.         continue;
  1661.         }
  1662.  
  1663.         if (c == comp1_key || c == comp2_key || c == help_key) {
  1664.         if (!comp_used || c == comp2_key ||
  1665.             (c == help_key && lastc != c)) {
  1666.             lbuf[i] = NUL;
  1667.             if ((comp_used = CALL(completion)(lbuf, i)) == 0) {
  1668.             ding();
  1669.             continue;
  1670.             }
  1671.             if (comp_used < 0) {
  1672.             comp_used = 0;
  1673.             goto no_completion;
  1674.             }
  1675.             comp_len = 0;
  1676.         }
  1677.         if (c == help_key) {
  1678.             if (CALL(completion)((char *)NULL, 1)) {
  1679.             gotoxy(prompt_length+i, prompt_line); fl;
  1680.             did_help = 1;
  1681.             }
  1682.             continue;
  1683.         }
  1684.  
  1685.         if (comp_len) {
  1686.             i -= comp_len;
  1687.             while (--comp_len >= 0) tputc(BS);
  1688.             clrline();
  1689.             comp_len = 0;
  1690.         }
  1691.  
  1692.         switch ( CALL(completion)((char *)NULL, 0) ) {
  1693.  
  1694.          case 0:    /* no possible completion */
  1695.             comp_used = 0;
  1696.             ding();
  1697.             continue;
  1698.  
  1699.          case 2:    /* whole new alternative */
  1700.             while (--i >= 0) tputc(BS);
  1701.             clrline();
  1702.  
  1703.             /*FALLTHRU*/
  1704.          case 1:    /* completion */
  1705.             comp_len = i;
  1706.             while ((c = lbuf[i])) {
  1707.             if (i == max) break;
  1708.             tputc(c);
  1709.             i++;
  1710.             }
  1711.             fl;
  1712.             comp_len = i - comp_len;
  1713.             continue;
  1714.         }
  1715.         }
  1716.  
  1717.         if (comp_used) {
  1718.         if (!CALL(completion)(lbuf, -(i+1)) && did_help)
  1719.             clrmsg(i);
  1720.         did_help = 0;
  1721.         comp_len = comp_used = 0;
  1722.         }
  1723.     }
  1724.  
  1725.      no_completion:
  1726.  
  1727.     if (c == CR || c == NL) {
  1728.         lbuf[i] = NUL;
  1729.         break;
  1730.     }
  1731.  
  1732.     if (c == erase_key) {
  1733.         if (i <= 0) continue;
  1734.         i--;
  1735.         tputc(BS);
  1736.         tputc(' ');
  1737.         tputc(BS);
  1738.         fl;
  1739.         continue;
  1740.     }
  1741.  
  1742.     if (c == delword_key) {
  1743.         if (i <= 0) continue;
  1744.         lbuf[i-1] = 'X';
  1745.         while (i > 0 && isalnum(lbuf[i-1])) { tputc(BS); i--; }
  1746.         clrline();
  1747.         continue;
  1748.     }
  1749.  
  1750.     if (c == kill_key) {
  1751.         while (i > 0) { tputc(BS); i--; }
  1752.         clrline();
  1753.         if (hit_count == 1 && dflt) {
  1754.         c = comp1_key;
  1755.         goto kill_prefill_hack;
  1756.         }
  1757.         continue;
  1758.     }
  1759.  
  1760.     if (c == K_interrupt) {
  1761.         ret_val = NULL;
  1762.         break;
  1763.     }
  1764.  
  1765.     if (data_bits == 8) {
  1766.         if (!iso8859(c)) continue;
  1767.     } else
  1768.     if (!isascii(c) || !isprint(c)) continue;
  1769.  
  1770.     if (i == max) continue;
  1771.  
  1772.     if (i > 0 && lbuf[i-1] == '/' && (c == '/' || c == '+')) {
  1773.         if (c != '/' || !guard_double_slash || (i > 1 && lbuf[i-2] == '/')) {
  1774.         if (completion == file_completion) {
  1775.             while (i > 0) { tputc(BS); i--; }
  1776.             clrline();
  1777.         }
  1778.         }
  1779.     }
  1780.  
  1781.     tputc(c);
  1782.     fl;
  1783.  
  1784.     lbuf[i] = c;
  1785.     i++;
  1786.     }
  1787.  out:
  1788.     enable_stop = ostop;
  1789.     do_macro_processing = 1;
  1790.     return ret_val;
  1791. }
  1792.  
  1793. export int list_offset = 0;
  1794.  
  1795. int list_completion(str)
  1796. char *str;
  1797. {
  1798.     static int cols, line;
  1799.  
  1800.     if (str == NULL) {
  1801.     cols = Columns;
  1802.     line = prompt_line + 1;
  1803.     if (line == Lines - 1) cols--;
  1804.  
  1805.     gotoxy(0, line);
  1806.     clrpage();
  1807.     return 1;
  1808.     }
  1809.  
  1810.     str += list_offset;
  1811.  
  1812.     for (;;) {
  1813.     cols -= strlen(str);
  1814.     if (cols >= 0) {
  1815.         tprintf("%s%s", str, cols > 0 ? " " : "");
  1816.         cols--;
  1817.         return 1;
  1818.     }
  1819.     if (line >= Lines - 1) return 0;
  1820.     line++;
  1821.     cols = Columns;
  1822.     gotoxy(0, line);
  1823.     if (line == Lines - 1) cols--;
  1824.     }
  1825. }
  1826.  
  1827. int yes(must_answer)
  1828. int must_answer;
  1829. {
  1830.     int c, help = 1, in_macro = 0;
  1831.  
  1832.     switch (m_yes()) {
  1833.      case 0:
  1834.     break;
  1835.      case 1:
  1836.     return 0;
  1837.      case 2:
  1838.     return 1;
  1839.      case 3:
  1840.     do_macro_processing = 0;
  1841.         in_macro++;
  1842.     break;
  1843.     }
  1844.     fl;
  1845.  
  1846.     for (;;) {
  1847.     if (!is_raw) {
  1848.         nn_raw();
  1849.         c = get_c();
  1850.         unset_raw();
  1851.     } else
  1852.         c = get_c();
  1853.  
  1854.     if (c == 'y' || c == 'Y') {
  1855.         c = 1;
  1856.         break;
  1857.     }
  1858.  
  1859.     if (must_answer == 0 && (c == SP || c == CR || c == NL)) {
  1860.         c = 1;
  1861.         break;
  1862.     }
  1863.  
  1864.     if (c == 'n' || c == 'N') {
  1865.         c = 0;
  1866.         break;
  1867.     }
  1868.     if (c == K_interrupt) {
  1869.         c = -1;
  1870.         break;
  1871.     }
  1872.     if (help) {
  1873.         tprintf(" y=YES n=NO"); fl;
  1874.         prompt_length += 11;
  1875.         help = 0;
  1876.     }
  1877.     }
  1878.  
  1879.     if (in_macro) {
  1880.     if (c < 0) m_break();
  1881.     do_macro_processing = 1;
  1882.     }
  1883.  
  1884.     return c;
  1885. }
  1886.  
  1887. void 
  1888. ding()
  1889. {
  1890.     BATCH_CHECK_V;
  1891.  
  1892.     putp(bell_str);
  1893.     fl;
  1894. }
  1895.  
  1896.  
  1897. void display_file(name, modes)
  1898. char *name;
  1899. int modes;
  1900. {
  1901.     FILE *f;
  1902.     register c, stand_on;
  1903.     int linecnt, headln_cnt, hdline, no_conf;
  1904.     char headline[128];
  1905.  
  1906.     headline[0] = 0;
  1907.     hdline = 0;
  1908.     no_conf = 0;
  1909.  
  1910.     headln_cnt = -1;
  1911.  
  1912.     if (modes & CLEAR_DISPLAY) {
  1913.     gotoxy(0,0);
  1914.     clrdisp();
  1915.     }
  1916.  
  1917.     linecnt = Lines - 1;
  1918.  
  1919. chain:
  1920.  
  1921.     if (*name != '/') name = relative(help_directory, name);
  1922.     f = open_file(name, OPEN_READ);
  1923.     if (f == NULL)
  1924.     tprintf("\r\n\nFile %s is not available\n\n", name);
  1925.     else {
  1926.     stand_on = 0;
  1927.  
  1928.     while ((c = getc(f)) != EOF) {
  1929. #ifdef HAVE_JOBCONTROL
  1930.         if (s_redraw) {
  1931.         no_conf = 1;
  1932.         break;
  1933.         }
  1934. #endif    /* HAVE_JOBCONTROL */
  1935.         no_conf = 0;
  1936.         if (c == '\1') {
  1937.         if (STANDOUT) {
  1938.             putp(stand_on ? exit_standout_mode : enter_standout_mode);
  1939.             curxy_c += cookie_size;
  1940.             stand_on = !stand_on;
  1941.         }
  1942.         continue;
  1943.         }
  1944.         if (c == '\2') {
  1945.         headln_cnt = 0;
  1946.         continue;
  1947.         }
  1948.         if (c == '\3') {
  1949.         headln_cnt = 0;
  1950.         while ((c = getc(f)) != EOF && c != NL)
  1951.             headline[headln_cnt++] = c;
  1952.         headline[headln_cnt++] = NUL;
  1953.         name = headline;
  1954.         fclose(f);
  1955.         goto chain;
  1956.         }
  1957.         if (c == '\4') {
  1958.         tprintf("%s", version_id);
  1959.         continue;
  1960.         }
  1961.  
  1962.         if (headln_cnt >= 0)
  1963.         headline[headln_cnt++] = c;
  1964.  
  1965.         if (hdline) {
  1966.         tprintf("%s\r", headline);
  1967.         hdline = 0;
  1968.         linecnt--;
  1969.         }
  1970.  
  1971.         tputc(c);
  1972.         if (c == NL) {
  1973.         tputc(CR);
  1974.         if (headln_cnt >= 0) {
  1975.             headline[--headln_cnt] = 0;
  1976.             headln_cnt = -1;
  1977.         }
  1978.         if (--linecnt == 0) {
  1979.             no_conf = 1;
  1980.             if (any_key(0) == K_interrupt)
  1981.             break;
  1982.             linecnt = Lines - 1;
  1983.             if (modes & CLEAR_DISPLAY) {
  1984.             gotoxy(0,0);
  1985.             clrdisp();
  1986.             }
  1987.             hdline = headline[0];
  1988.         }
  1989.         }
  1990.     }
  1991.  
  1992.     if (stand_on) {
  1993.         putp(exit_standout_mode);
  1994.         curxy_c += cookie_size;
  1995.     }
  1996.     fclose(f);
  1997.     }
  1998.  
  1999.     prompt_line = Lines-1;    /* move prompt to last line */
  2000.  
  2001.     if (!no_conf && (modes & CONFIRMATION))
  2002.     any_key(prompt_line);
  2003. }
  2004.  
  2005.  
  2006. /*VARARGS*/
  2007. void nn_exitmsg(va_alist)
  2008. va_dcl
  2009. {
  2010.     char *fmt;
  2011.     int n;
  2012.     use_vararg;
  2013.  
  2014.     if (terminal_speed != 0) {
  2015.     clrdisp();
  2016.     visual_off();
  2017.     }
  2018.  
  2019.     start_vararg;
  2020.     n = va_arg1(int);
  2021.     fmt = va_arg2(char *);
  2022.     vprintf(fmt, va_args3toN);
  2023.     putchar(NL);
  2024.     end_vararg;
  2025.  
  2026.     nn_exit(n);
  2027.     /*NOTREACHED*/
  2028. }
  2029.  
  2030. /*VARARGS*/
  2031. void msg(va_alist)
  2032. va_dcl
  2033. {
  2034.     use_vararg;
  2035.  
  2036.     start_vararg;
  2037.     vmsg(va_args1toN);
  2038.     end_vararg;
  2039. }
  2040.  
  2041. void push_msg(str)
  2042. char *str;
  2043. {
  2044.     register struct msg_list *mp, *newmsg;
  2045.     static int slots = 0;
  2046.     
  2047.     if (str != NULL) {
  2048.     if (slots > message_history) {
  2049.         for (mp = newmsg = msg_stack; mp->prev != NULL; mp = mp->prev)
  2050.         newmsg = mp;
  2051.         if (newmsg == mp)
  2052.         msg_stack = NULL;
  2053.         else {
  2054.         newmsg->prev = NULL;
  2055.         newmsg = mp;
  2056.         }
  2057.         freeobj(newmsg->buf);
  2058.     } else {
  2059.         slots++;
  2060.         newmsg = newobj(struct msg_list, 1);
  2061.     }
  2062.     newmsg->buf = copy_str(str);
  2063.     newmsg->prev = msg_stack;
  2064.     msg_stack = newmsg;
  2065.     }
  2066.     msg_ptr = msg_stack;
  2067. }
  2068.     
  2069. void vmsg(va_tail)
  2070. va_tdcl
  2071. {
  2072.     char *errmsg, *fmt;
  2073.     
  2074.     fmt = va_arg1(char *);
  2075.  
  2076.     if (fmt) {
  2077.     char lbuf[512];
  2078.     
  2079.     vsprintf(lbuf, fmt, va_args2toN);
  2080.     push_msg(lbuf);
  2081.     }
  2082.     
  2083.     if (msg_ptr) {
  2084.     errmsg = msg_ptr->buf;
  2085.     msg_ptr = msg_ptr->prev;
  2086.     } else {
  2087.     errmsg = "(no more messages)";
  2088.     msg_ptr = msg_stack;
  2089.     }
  2090.  
  2091.     if (terminal_speed == 0) {
  2092.     tprintf("%s\n", errmsg);
  2093.     fl;
  2094.     return;
  2095.     }
  2096.     
  2097.     gotoxy(0, Lines-1);
  2098.     tprintf("%s", errmsg);
  2099.     clrline();
  2100.     any_message = 1;
  2101.  
  2102.     if (prompt_line != Lines-1)
  2103.         gotoxy(prompt_length, prompt_line);
  2104.     fl;
  2105. }
  2106.  
  2107. void
  2108. clrmsg(col)
  2109. int col;
  2110. {
  2111.     BATCH_CHECK_V;
  2112.  
  2113.     gotoxy(0, prompt_line + 1);
  2114.     clrpage();
  2115.     if (col >= 0)
  2116.     gotoxy(prompt_length + col, prompt_line);
  2117.     fl;
  2118.     any_message = 0;
  2119. }
  2120.  
  2121.  
  2122. /*VARARGS*/
  2123. void
  2124. prompt(va_alist)
  2125. va_dcl
  2126. {
  2127.     register char *cp;
  2128.     int stand_on;
  2129.     char *fmt;
  2130.     static char cur_p[FILENAME];
  2131.     static char saved_p[FILENAME];
  2132.     use_vararg;
  2133.  
  2134.     BATCH_CHECK_V;
  2135.  
  2136.     start_vararg;
  2137.  
  2138.     fmt = va_arg1(char *);
  2139.  
  2140.     if (fmt == P_VERSION) {
  2141.     gotoxy(0, prompt_line + 1);
  2142.     tprintf("Release %s ", version_id);
  2143.     clrline();
  2144.     any_message++;
  2145.  
  2146.     if (prompt_line >= 0)
  2147.         gotoxy(prompt_length, prompt_line);
  2148.     goto out;
  2149.     }
  2150.  
  2151.     if (fmt == P_SAVE) {
  2152.     strcpy(saved_p, cur_p);
  2153.     goto out;
  2154.     }
  2155.  
  2156.     if (fmt == P_RESTORE)
  2157.     strcpy(cur_p, saved_p);
  2158.  
  2159.     if (prompt_line >= 0)
  2160.     gotoxy(0, prompt_line);
  2161.  
  2162.     if (fmt == P_MOVE) {
  2163.     clrline();
  2164.     goto out;
  2165.     }
  2166.  
  2167.     if (fmt != P_REDRAW && fmt != P_RESTORE)
  2168.     vsprintf(cur_p, fmt, va_args2toN);
  2169.  
  2170.     tputc(CR);
  2171.  
  2172.     for (cp = cur_p, stand_on = 0, prompt_length = 0; *cp; cp++) {
  2173.     if (*cp == '\1') {
  2174.         if (cp[1] != '\1') {
  2175.         if (STANDOUT) {
  2176.             stand_on = !stand_on;
  2177.             standout(stand_on);
  2178.             prompt_length += cookie_size;
  2179.         }
  2180.         continue;
  2181.         }
  2182.         cp++;
  2183.     } else
  2184.     if (*cp == '\2') {
  2185.         time_t t;
  2186.         char   *timestr;
  2187.  
  2188.         t = tick_usage();
  2189.  
  2190.         if (show_current_time) {
  2191.         timestr = ctime(&t) + 11;
  2192.         timestr[5] = NUL;
  2193.  
  2194.         tprintf("-- %s ", timestr);
  2195.         prompt_length += 9;
  2196.         }
  2197.  
  2198.         if (unread_mail(t)) {
  2199.         tprintf("Mail ");
  2200.         prompt_length += 5;
  2201.         }
  2202.  
  2203.         continue;
  2204.     }
  2205.  
  2206.     tputc(*cp);
  2207.     prompt_length ++;
  2208.     }
  2209.     if (stand_on) {
  2210.     standout(0);
  2211.     prompt_length += cookie_size;
  2212.     }
  2213.  
  2214.     clrline();
  2215.  
  2216.     if (fmt == P_RESTORE)
  2217.     restore_xy();
  2218. #if notdef
  2219.     else
  2220.     curxy_c = -1;
  2221. #endif
  2222.  
  2223.  out:
  2224.     end_vararg;
  2225. }
  2226.  
  2227.  
  2228. int any_key(line)
  2229. int line;
  2230. {
  2231.     int was_raw, c, dmp;
  2232.  
  2233.     BATCH_CHECK;
  2234.  
  2235.     was_raw = is_raw;
  2236.     if (!is_raw) nn_raw();
  2237.     if (line == 0)
  2238.     line = -1;
  2239.     else
  2240.     if (line < 0)
  2241.         line = Lines + line;
  2242.  
  2243.     if (line != 10000)
  2244.     so_printxy(0, line, "Hit any key to continue");
  2245.  
  2246.     clrline();
  2247.  
  2248.     dmp = do_macro_processing;
  2249.     do_macro_processing = 0;
  2250.     c = get_c();
  2251.     if (c == 'q' || c == 'Q') c = K_interrupt;
  2252.     do_macro_processing = dmp;
  2253.  
  2254.     if (!was_raw) unset_raw();
  2255.  
  2256.     return c;
  2257. }
  2258.  
  2259.  
  2260. static pg_fline, pg_width, pg_maxw, pg_line, pg_col, pg_quit;
  2261. export regexp *pg_regexp = NULL;
  2262. export int pg_new_regexp = 0;
  2263.  
  2264. void pg_init(first_line, cols)
  2265. int first_line, cols;
  2266. {
  2267.     if (pg_regexp) {
  2268.     freeobj(pg_regexp);
  2269.     pg_regexp = NULL;
  2270.     }
  2271.     pg_new_regexp = 0;
  2272.  
  2273.     pg_fline = first_line;
  2274.     pg_line = pg_fline - 1;
  2275.     pg_quit = pg_col = 0;
  2276.     pg_width = Columns / cols;
  2277.     pg_maxw = pg_width * (cols - 1);
  2278. }
  2279.  
  2280. int pg_scroll(n)
  2281. int n;
  2282. {
  2283.     pg_line += n;
  2284.     if (pg_line >= (Lines - 1)) {
  2285.     pg_line = 0;
  2286.     if (any_key(0) == K_interrupt)
  2287.         return 1;
  2288.     tputc(CR);
  2289.     clrline();
  2290.     }
  2291.     return 0;
  2292. }
  2293.  
  2294. int pg_next()
  2295. {
  2296.     int c;
  2297.  
  2298.     if (batch_mode) {
  2299.     putchar(NL);
  2300.     return 0;
  2301.     }
  2302.  
  2303.     pg_line++;
  2304.     if (pg_line < Lines) {
  2305.     gotoxy(pg_col, pg_line);
  2306.     if (pg_line == Lines - 1 && pg_col == pg_maxw) {
  2307.         c = any_key(0);
  2308.         if (c == '/') {
  2309.         char *expr;
  2310.         tputc(CR);
  2311.         tputc('/');
  2312.         clrline();
  2313.         expr = get_s((char *)NULL, (char *)NULL, (char *)NULL, NULL_FCT);
  2314.         if (expr != NULL && *expr != NUL) {
  2315.             freeobj(pg_regexp);
  2316.             pg_regexp = regcomp(expr);
  2317.             pg_new_regexp = 1;
  2318.         }
  2319.         }
  2320.         gotoxy(0, pg_fline);
  2321.         clrpage();
  2322.         pg_col = 0;
  2323.         pg_line = pg_fline;
  2324.         if (c == K_interrupt) {
  2325.         pg_quit = 1;
  2326.         return -1;
  2327.         }
  2328.         return 1;
  2329.     }
  2330.     } else {
  2331.     pg_line = pg_fline;
  2332.     pg_col += pg_width;
  2333.     gotoxy(pg_col, pg_line);
  2334.     }
  2335.     return 0;
  2336. }
  2337. void
  2338. pg_indent(pos)
  2339. int pos;
  2340. {
  2341.     BATCH_CHECK_V;
  2342.  
  2343.     gotoxy(pg_col + pos, pg_line);
  2344. }
  2345.  
  2346. int pg_end()
  2347. {
  2348.     int c;
  2349.  
  2350.     if (pg_quit == 0 && pg_next() == 0)
  2351.     c = any_key(0);
  2352.     else
  2353.     c = K_interrupt;
  2354.  
  2355.     if (pg_regexp) {
  2356.     freeobj(pg_regexp);
  2357.     pg_regexp = NULL;
  2358.     }
  2359.  
  2360.     return c == K_interrupt ? -1 : 0;
  2361. }
  2362.  
  2363. void
  2364. user_delay(ticks)
  2365. int ticks;
  2366. {
  2367.     BATCH_CHECK_V;
  2368.  
  2369.     if (ticks <= 0 || conf_dont_sleep) {
  2370.     tprintf(" <>");
  2371.     any_key(10000);
  2372.     } else {
  2373.     fl;
  2374.     sleep((unsigned)ticks);
  2375.     }
  2376. }
  2377.  
  2378.