home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume33 / problem1.1 / part03 / display.C next >
Encoding:
C/C++ Source or Header  |  1992-11-13  |  17.2 KB  |  677 lines

  1. /*
  2. ** Routines controlling the physical display
  3. **
  4. ** display.C display.C 1.23   Delta\'d: 10:57:09 10/28/92   Mike Lijewski, CNSF
  5. **
  6. ** Copyright \(c\) 1991, 1992 Cornell University
  7. ** All rights reserved.
  8. **
  9. ** Redistribution and use in source and binary forms are permitted
  10. ** provided that: \(1\) source distributions retain this entire copyright
  11. ** notice and comment, and \(2\) distributions including binaries display
  12. ** the following acknowledgement:  ``This product includes software
  13. ** developed by Cornell University\'\' in the documentation or other
  14. ** materials provided with the distribution and in all advertising
  15. ** materials mentioning features or use of this software. Neither the
  16. ** name of the University nor the names of its contributors may be used
  17. ** to endorse or promote products derived from this software without
  18. ** specific prior written permission.
  19. **
  20. ** THIS SOFTWARE IS PROVIDED ``AS IS\'\' AND WITHOUT ANY EXPRESS OR
  21. ** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  22. ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  23. */
  24.  
  25. #ifndef _IBMR2
  26. #include <libc.h>
  27. #endif /*_IBMR2*/
  28.  
  29. #include <osfcn.h>
  30. #include <signal.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <sys/ioctl.h>
  35.  
  36. #ifdef M_UNIX
  37. #include <sys/unistd.h>
  38. #include <sys/stream.h>
  39. #include <sys/ptem.h>
  40. #endif /*M_UNIX*/
  41.  
  42. #ifdef TERMIOS
  43. #include <termios.h>
  44. #include <unistd.h>
  45. #elif  TERMIO
  46. #include <termio.h>
  47. #if defined(ISC) || defined(ESIX)
  48. #include <sys/stream.h>
  49. #include <sys/ptem.h>
  50. #endif /*ISC||ESIX*/
  51. #else
  52. #include <sgtty.h>
  53. #endif
  54.  
  55. #include "utilities.h"
  56. #include "display.h"
  57.  
  58. #ifndef EXIT_FAILURE
  59. #define EXIT_FAILURE 1
  60. #endif
  61.  
  62. /*
  63. ** The definition of ospeed -- needed by the termcap routines.
  64. */
  65.  
  66. short ospeed;
  67.  
  68. //
  69. // termcap capabilities we use
  70. //
  71. char *AL;               // insert blank line before cursor
  72. char *ALN;              // insert N blank lines at cursor
  73. int   AM;               // automatic margins?
  74. char *BC;               // backspace, if not BS
  75. int   BS;               // ASCII backspace works
  76. char *CD;               // clear to end of display
  77. char *CE;               // clear to end of line
  78. char *CL;               // clear screen
  79. int   CO;               // number of columns
  80. char *CM;               // cursor motion
  81. char *CR;               // cursor beginning of line
  82. char *CS;               // set scroll region
  83. int   DA;               // backing store off top?
  84. int   DB;               // backing store off bottom?
  85. char *DC;               // delete character at cursor
  86. char *DL;               // delete line cursor is on
  87. char *DLN;              // delete N lines from cursor
  88. char *DM;               // string to enter delete mode
  89. char *DO;               // cursor down
  90. char *ED;               // string to end delete mode
  91. int   HC;               // hardcopy terminal?
  92. char *IS;               // initialize terminal
  93. char *HO;               // cursor home
  94. char *KD;               // down arrow key
  95. char *KE;               // de-initialize keypad
  96. char *KS;               // initialize keypad -- for arrow keys
  97. char *KU;               // up arrrow key
  98. char *LE;               // cursor back one column
  99. int   LI;               // number of rows
  100. char *LL;               // cursor to lower left
  101. int   OS;               // terminal overstrikes?
  102. #ifndef APOLLO
  103. char  PC;               // pad character
  104. #endif
  105. char *PCstr;            // pad string
  106. char *SE;               // end standout mode
  107. char *SF;               // scroll screen up one line
  108. char *SO;               // enter standout mode
  109. char *SR;               // scroll screen down one line
  110. char *TE;               // end cursor addressing mode
  111. char *TI;               // enter cursor addressing mode
  112. char *UP;               // cursor up
  113. char *VE;               // end visual mode
  114. char *VS;               // enter visual mode
  115. char *XN;               // strange wrap behaviour
  116.  
  117. /*
  118. ** termcap - reads termcap file setting all the terminal capabilities
  119. **           which we will use.
  120. */
  121.  
  122. void termcap(const char *term_type)
  123. {
  124.     static char capability_buffer[512];
  125.     char* bp = capability_buffer;
  126.     char termcap_buffer[2048];
  127.     
  128.     switch (tgetent(termcap_buffer, term_type))
  129.     {
  130.       case -1:
  131.         (void)fputs("couldn't open termcap database\n", stderr);
  132.         exit(1);
  133.       case 0:
  134.         (void)fprintf(stderr, "invalid terminal type: `%s'\n", term_type);
  135.         exit(1);
  136.       default: break;
  137.     }
  138.     
  139.     AL = tgetstr("al", &bp);
  140.     ALN = tgetstr("AL", &bp);
  141.     AM = tgetflag("am");
  142.     BC = tgetstr("bc", &bp);
  143.     BS = tgetflag("bs");
  144.     CD = tgetstr("cd", &bp);
  145.     CE = tgetstr("ce", &bp);
  146.     CL = tgetstr("cl", &bp);
  147.     CM = tgetstr("cm", &bp);
  148.     CR = tgetstr("cr", &bp);
  149.     CS = tgetstr("cs", &bp);
  150.     DA = tgetflag("da");
  151.     DB = tgetflag("db");
  152.     DC = tgetstr("dc", &bp);
  153.     DL = tgetstr("dl", &bp);
  154.     DLN = tgetstr("DL", &bp);
  155.     DM = tgetstr("dm", &bp);
  156.     DO = tgetstr("do", &bp);
  157.     ED = tgetstr("ed", &bp);
  158.     HC = tgetflag("hc");
  159.     HO = tgetstr("ho", &bp);
  160.     IS = tgetstr("is", &bp);
  161.     KD = tgetstr("kd", &bp);
  162.     KE = tgetstr("ke", &bp);
  163.     KS = tgetstr("ks", &bp);
  164.     KU = tgetstr("ku", &bp);
  165.     LE = tgetstr("le", &bp);
  166.     LL = tgetstr("ll", &bp);
  167.     OS = tgetflag("os");
  168.     PCstr = tgetstr("pc", &bp);
  169.     SE = tgetstr("se", &bp);
  170.     SF = tgetstr("sf", &bp);
  171.     SO = tgetstr("so", &bp);
  172.     SR = tgetstr("sr", &bp);
  173.     TE = tgetstr("te", &bp);
  174.     TI = tgetstr("ti", &bp);
  175.     UP = tgetstr("up", &bp);
  176.     VE = tgetstr("ve", &bp);
  177.     VS = tgetstr("vs", &bp);
  178.     XN = tgetstr("xn", &bp);
  179.     
  180.     PC = PCstr ? PCstr[0] :  0;
  181.     
  182.     if (!BC && !LE && !BS)
  183.     {
  184.         (void)fputs("terminal can't backspace - unusable\n", stderr);
  185.         exit(1);
  186.     }
  187.     if (!BC) BC = LE ? LE : "\b";
  188.     if (!CR) CR = "\r";
  189.     if (!DO) DO = SF ? SF : "\n";
  190.     
  191.     const char *tmp = getenv("LINES");
  192.     if (tmp) LI = atoi(tmp);
  193.     tmp = getenv("COLUMNS");
  194.     if (tmp) CO = atoi(tmp);
  195.     
  196. #ifdef TIOCGWINSZ
  197.     struct winsize win;
  198.     if (ioctl(fileno(stdout), TIOCGWINSZ, (char *)&win) == 0)
  199.     {
  200.         if (LI == 0 && win.ws_row > 0) LI = win.ws_row;
  201.         if (CO == 0 && win.ws_col > 0) CO = win.ws_col;
  202.     }
  203. #endif
  204.     
  205.     if (CO == 0) CO = tgetnum("co");
  206.     if (LI == 0) LI = tgetnum("li");
  207.     
  208.     if (LI == -1 || CO == -1 || HC || !CM || !CE)
  209.     {
  210.         (void)fputs("terminal too dumb to be useful\n", stderr);
  211.         exit(1);
  212.     }
  213.     if (LI < 5)
  214.     {
  215.         (void)fputs("too few rows to be useful\n", stderr);
  216.         exit(1);
  217.     }
  218. }
  219.  
  220. /*
  221. ** setraw - puts terminal into raw mode.  Cbreak mode actually, but
  222. **          why be pedantic.  Flow control is disabled as well as BREAK keys.
  223. **          Echoing is turned off as well as signal generation.  Hence
  224. **          keyboard generated signals must be simulated.  Also sets
  225. **          ospeed.
  226. */
  227.  
  228. #ifdef TERMIOS
  229. static struct termios tty_mode;    /* save tty mode here */
  230. #elif  TERMIO
  231. static struct termio tty_mode;    /* save tty mode here */
  232. #else
  233. static struct sgttyb  oarg;      /* save tty stuff here */
  234. static struct tchars  otarg;
  235. static struct ltchars oltarg;
  236. #endif
  237.  
  238. void setraw()
  239. {
  240. #ifdef TERMIOS
  241.     struct termios temp_mode;
  242.  
  243.     if (tcgetattr(STDIN_FILENO, &temp_mode) < 0)
  244.     {
  245.         perror("tcgetattr");
  246.         exit(EXIT_FAILURE);
  247.     }
  248.  
  249.     tty_mode = temp_mode;  /* save for latter restoration */
  250.  
  251.     temp_mode.c_iflag &= ~(IGNBRK|ICRNL|INLCR);
  252.     temp_mode.c_lflag &= ~(ICANON|ECHO|IEXTEN);
  253.     temp_mode.c_oflag &= ~OPOST;
  254.     temp_mode.c_cc[VQUIT] = 28; // C-\ is QUIT
  255.     temp_mode.c_cc[VMIN]  = 1;    // min #chars to satisfy read
  256.     temp_mode.c_cc[VTIME] = 0;    // read returns immediately
  257.  
  258.     if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &temp_mode) < 0)
  259.     {
  260.         perror("tcsetattr");
  261.         exit(EXIT_FAILURE);
  262.     }
  263.  
  264.     ospeed = cfgetospeed(&temp_mode);
  265. #elif TERMIO
  266.     struct termio temp_mode;
  267.     
  268.     if (ioctl(fileno(stdin), TCGETA, (char *)&temp_mode) < 0)
  269.     {
  270.         perror("ioctl - TCGETA");
  271.         exit(EXIT_FAILURE);
  272.     }
  273.  
  274.     tty_mode = temp_mode;  /* save for latter restoration */
  275.  
  276.     temp_mode.c_iflag &= ~(IGNBRK|ICRNL|INLCR);
  277.     temp_mode.c_lflag &= ~(ICANON|ECHO);
  278.     temp_mode.c_oflag &= ~OPOST;
  279.     temp_mode.c_cc[VQUIT] = 28; // C-\ is QUIT
  280.     temp_mode.c_cc[VMIN]  = 1;    // min #chars to satisfy read
  281.     temp_mode.c_cc[VTIME] = 0;    // read returns immediately
  282.  
  283.     if (ioctl(fileno(stdin), TCSETA, (char *)&temp_mode) < 0)
  284.     {
  285.         perror("ioctl - TCSETA");
  286.         exit(EXIT_FAILURE);
  287.     }
  288.  
  289.     ospeed = temp_mode.c_cflag & CBAUD;
  290. #else
  291.     struct sgttyb arg;
  292.     struct tchars targ;
  293.     struct ltchars ltarg;
  294.  
  295.     if (ioctl(fileno(stdin), TIOCGETP, (char *)&arg) < 0)
  296.     {
  297.         perror("ioctl - TIOCGETP");
  298.         exit(EXIT_FAILURE);
  299.     }
  300.     if (ioctl(fileno(stdin), TIOCGETC, (char *)&targ) < 0)
  301.     {
  302.         perror("ioctl - TIOCGETC");
  303.         exit(EXIT_FAILURE);
  304.     }
  305.     if (ioctl(fileno(stdin), TIOCGLTC, (char *)<arg) < 0)
  306.     {
  307.         perror("ioctl - TIOCGLTC");
  308.         exit(EXIT_FAILURE);
  309.     }
  310.  
  311.     oarg   = arg;
  312.     otarg  = targ;
  313.     oltarg = ltarg;
  314.  
  315.     arg.sg_flags=((arg.sg_flags&~(ECHO|CRMOD))|CBREAK) ;
  316.     targ.t_eofc    = -1;  // turn off end-of-file character
  317.     targ.t_brkc    = -1;  // turn off break delimiter
  318.     ltarg.t_dsuspc = -1;  // turn off delayed suspend character
  319.     ltarg.t_rprntc = -1;  // turn off reprint line character
  320.     ltarg.t_flushc = -1;  // turn off flush character
  321.     ltarg.t_werasc = -1;  // turn off erase work character
  322.     ltarg.t_lnextc = -1;  // turn off literal next char
  323.  
  324.     if (ioctl(fileno(stdin), TIOCSETN, (char *)&arg) < 0)
  325.     {
  326.         perror("ioctl - TIOCSETN");
  327.         exit(EXIT_FAILURE);
  328.     }
  329.     if (ioctl(fileno(stdin), TIOCSETC, (char *)&targ) < 0)
  330.     {
  331.         perror("ioctl - TIOCSETC");
  332.         exit(EXIT_FAILURE);
  333.     }
  334.     if (ioctl(fileno(stdin), TIOCSLTC, (char *)<arg) < 0)
  335.     {
  336.         perror("ioctl - TIOCSLTC");
  337.         exit(EXIT_FAILURE);
  338.     }
  339.  
  340.     ospeed = arg.sg_ospeed;
  341. #endif
  342. }
  343.  
  344. /*
  345. ** unsetraw - Restore the terminal mode to whatever it was on the most
  346. **            recent call to the setraw function above.
  347. **            Exits with rc==1 on failure.
  348. */
  349.  
  350. void unsetraw()
  351. {
  352. #ifdef TERMIOS
  353.     if (tcsetattr(0, TCSAFLUSH, &tty_mode) < 0)
  354.     {
  355.         perror("tcsetattr");
  356.         exit(EXIT_FAILURE);
  357.     }
  358. #elif TERMIO
  359.     if (ioctl(fileno(stdin), TCSETA, (char *)&tty_mode) < 0)
  360.     {
  361.         perror("ioctl - TCSETA");
  362.         exit(EXIT_FAILURE);
  363.     }
  364. #else
  365.     if (ioctl(fileno(stdin), TIOCSETN, (char *)&oarg) < 0)
  366.     {
  367.         perror("ioctl - TIOSETN");
  368.         exit(EXIT_FAILURE);
  369.     }
  370.     if (ioctl(fileno(stdin), TIOCSETC, (char *)&otarg) < 0)
  371.     {
  372.         perror("ioctl - TIOSETC");
  373.         exit(EXIT_FAILURE);
  374.     }
  375.     if (ioctl(fileno(stdin), TIOCSLTC, (char *)&oltarg) < 0) {
  376.         perror("ioctl - TIOSLTC");
  377.         exit(EXIT_FAILURE);
  378.     }
  379. #endif
  380. }
  381.  
  382. /*
  383. ** outputch - a function to output a single character.
  384. **            Termcap routines NEED a function.
  385. */
  386.  
  387. int outputch(int ch) { return putchar(ch); }
  388.  
  389. /*
  390. ** init_screen_and_kbdr - initialize screen and keyboard
  391. */
  392.  
  393. void init_screen_and_kbdr()
  394. {
  395.     setraw();
  396.     enter_cursor_addressing_mode();
  397.     enter_visual_mode();
  398.     enable_keypad();
  399.     synch_display();
  400. }
  401.  
  402. /*
  403. ** initialize - get ready to do some real work.
  404. */
  405.  
  406. void initialize()
  407. {
  408.     setvbuf(stdout, 0, _IOFBF, 0);  // fully buffer stdout
  409.     setvbuf(stdin , 0, _IONBF, 0);  // no buffering on stdin
  410.  
  411.     const char *term = getenv("TERM");
  412.     if (term == 0 || *term == 0)
  413.     {
  414.         (void)fputs("please set your TERM variable appropriately\n", stderr);
  415.         exit(1);
  416.     }
  417.  
  418.     termcap(term);
  419.     init_screen_and_kbdr();
  420. }
  421.  
  422. /*
  423. ** deinit_screen_and_kbdr
  424. */
  425.  
  426. void deinit_screen_and_kbdr()
  427. {
  428.     move_to_message_line();
  429.     clear_to_end_of_line();
  430.     disable_keypad();
  431.     end_visual_mode();
  432.     end_cursor_addressing_mode();
  433.     synch_display();
  434.     unsetraw();
  435. }
  436.  
  437. //
  438. // Have we just been continued after being suspended?
  439. // Should be a sig_atomic_t.
  440. //
  441. int resumingAfterSuspension;
  442.  
  443. /*
  444. ** scroll_listing_up_N - scrolls the listing window up n lines.
  445. **                       The cursor is left in column 0 of the first
  446. **                       line to scroll into the window.
  447. **                       Must have CS capability.
  448. */
  449.  
  450. void scroll_listing_up_N(int n)
  451. {
  452.     output_string_capability(tgoto(CS, rows()-3, 0));
  453.     move_cursor(rows()-3, 0);
  454.     for (int i = 0; i < n; i++) cursor_down();
  455.     output_string_capability(tgoto(CS, rows()-1, 0));
  456.     move_cursor(rows()-2-n, 0);
  457. }
  458.  
  459. /*
  460. ** scroll_listing_down_N - half_down - scrolls the listing window
  461. **                         \(line 0 - rows-3\) down \(rows-2\)/2 lines.
  462. **                         The cursor is left in HOME position.
  463. **                         Must have CS capability.
  464. */
  465.  
  466. void scroll_listing_down_N(int n)
  467. {
  468.     output_string_capability(tgoto(CS, rows()-3, 0));
  469.     move_cursor(0, 0);
  470.     for (int i = 0; i < n; i++) output_string_capability(SR, rows()-2);
  471.     output_string_capability(tgoto(CS, rows()-1, 0));
  472.     cursor_home();
  473. }
  474.  
  475. /*
  476. ** scroll_listing_up_one - scrolls the listing window \(line 0 - rows-3\)
  477. **                         up one row. The cursor is left in column
  478. **                         0 of rows-3 row.  Assumes CS capability.
  479. */
  480.  
  481. void scroll_listing_up_one()
  482. {
  483.     output_string_capability(tgoto(CS, rows()-3, 0));
  484.     move_cursor(rows()-3, 0);
  485.     cursor_down();
  486.     output_string_capability(tgoto(CS, rows()-1, 0));
  487.     move_cursor(rows()-3, 0);
  488. }
  489.  
  490. /*
  491. ** scroll_listing_down_one - scrolls the listing window \(line 0 - rows-3\)
  492. **                           down one row. The cursor is left at HOME.
  493. **                           Assumes CS capability.
  494. */
  495.  
  496. void scroll_listing_down_one()
  497. {
  498.     output_string_capability(tgoto(CS, rows()-3, 0));
  499.     cursor_home();
  500.     output_string_capability(SR, rows()-2);
  501.     output_string_capability(tgoto(CS, rows()-1, 0));
  502.     cursor_home();
  503. }
  504.  
  505. /*
  506. ** termstop - caught a SIGTSTP.  We are relying on the signal to
  507. **            interrupt read.
  508. */
  509.  
  510. #ifdef SIGTSTP
  511. void termstop(int)
  512. {
  513.     (void)signal(SIGTSTP,  SIG_IGN);
  514. #ifdef SIGWINCH
  515.     (void)signal(SIGWINCH, SIG_IGN);
  516. #endif
  517.     deinit_screen_and_kbdr();
  518.     (void)kill(getpid(), SIGSTOP);
  519.     init_screen_and_kbdr();
  520.     (void)signal(SIGTSTP,  termstop);
  521. #ifdef SIGWINCH
  522.     (void)signal(SIGWINCH, winch);
  523. #endif
  524.  
  525.     //
  526.     // window size may have changed
  527.     //
  528. #ifdef TIOCGWINSZ
  529.     int oCO = columns(), oLI = rows();
  530.     struct winsize w;
  531.     if (ioctl(fileno(stdout), TIOCGWINSZ, (char *)&w) == 0 && w.ws_row > 0)
  532.         LI = w.ws_row;
  533.     if (ioctl(fileno(stdout), TIOCGWINSZ, (char *)&w) == 0 && w.ws_col > 0)
  534.         CO = w.ws_col;
  535.     if (oCO != columns() || oLI != rows()) windowSizeChanged = 1;
  536. #endif
  537.     resumingAfterSuspension = 1;
  538. }
  539. #endif /*SIGTSTP*/
  540.  
  541. /*
  542. ** clear_display_area - clears all except the last two lines.  Leaves
  543. **                      the cursor at home.
  544. */
  545.  
  546. void clear_display_area()
  547. {
  548.     cursor_home();
  549.     for (int i = 0; i < rows() - 2; i++)
  550.     {
  551.         clear_to_end_of_line();
  552.         cursor_down();
  553.     }
  554.     cursor_home();
  555. }
  556.  
  557. /*
  558. ** scroll_screen_up_one - must have DL or SF
  559. */
  560.  
  561. void scroll_screen_up_one()
  562. {
  563.     if (DL)
  564.     {
  565.         cursor_home();
  566.         output_string_capability(DL, rows());
  567.     }
  568.     else
  569.     {
  570.         move_cursor(rows()-1, 0);
  571.         output_string_capability(SF, rows());
  572.     }
  573.     if (DB) clear_message_line();
  574. }
  575.  
  576. /*
  577. ** scroll_screen_down_one - must have AL or SR
  578. */
  579.  
  580. void scroll_screen_down_one()
  581. {
  582.     cursor_home();
  583.  
  584.     if (AL)
  585.         output_string_capability(AL, rows());
  586.     else
  587.         output_string_capability(SR, rows());
  588.     if (DA) clear_to_end_of_line();
  589. }
  590.  
  591. /*
  592. ** scroll_screen_up_N - must have DLN, DL or SF.
  593. **         
  594. */
  595.  
  596. void scroll_screen_up_N(int n)
  597. {
  598.     if (DLN)
  599.     {
  600.         cursor_home();
  601.         output_string_capability(tgoto(DLN, 0, n), rows());
  602.     }
  603.     else if (DL)
  604.     {
  605.         cursor_home();
  606.         for (int i = 0; i < n; i++)
  607.             output_string_capability(DL, rows());
  608.     }
  609.     else
  610.     {
  611.         move_cursor(rows()-1, 0);
  612.         for (int i = 0; i < n; i++) output_string_capability(SF, rows());
  613.     }
  614.     if (DB) clear_to_end_of_screen(rows()-n);
  615. }
  616.  
  617. /*
  618. ** scroll_screen_down_N - must have ALN, AL or SR.
  619. */
  620.  
  621. void scroll_screen_down_N(int n)
  622. {
  623.     cursor_home();
  624.     int i;
  625.     if (ALN)
  626.         output_string_capability(tgoto(ALN, 0, n), rows());
  627.     else if (AL)
  628.         for (i = 0; i < n; i++) output_string_capability(AL, rows());
  629.     else
  630.         for (i = 0; i < n; i++) output_string_capability(SR, rows());
  631.     if (DA)
  632.     {
  633.         for (i = 0; i < n; i++)
  634.         {
  635.             clear_to_end_of_line();
  636.             cursor_down();
  637.         }
  638.         cursor_home();
  639.     }
  640. }
  641.  
  642. /*
  643. ** clear_to_end_of_screen - clears screen from line y to the bottom
  644. */
  645.  
  646. void clear_to_end_of_screen(int y)
  647. {
  648.     move_cursor(y, 0);
  649.     if (CD)
  650.         output_string_capability(DL, rows()-y);
  651.     else
  652.         for (int i = 0; i < rows()-y; i++)
  653.         {
  654.             clear_to_end_of_line();
  655.             putchar('\n');
  656.         }
  657. }
  658.  
  659. /*
  660. ** delete_listing_line - deletes line at line y, scrolling the lines below
  661. **                       y up.  We only call this routine when we KNOW that
  662. **                       there is at least one line in need of being scrolled
  663. **                       up. Must have CS capability.
  664. */
  665.  
  666. void delete_listing_line(int y)
  667. {
  668.     move_cursor(y, 0);
  669.     clear_to_end_of_line();
  670.     output_string_capability(tgoto(CS, rows()-3, y));
  671.     move_cursor(rows()-3, 0);
  672.     cursor_down();
  673.     output_string_capability(tgoto(CS, rows()-1, 0));
  674. }
  675.  
  676.  
  677.