home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume7 / less3 / part03 < prev    next >
Encoding:
Internet Message Format  |  1986-12-04  |  46.8 KB

  1. Subject:  v07i084:  New release of LESS, Part03/03
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: rgb@nscpdc.uucp (Robert Bond)
  6. Mod.sources: Volume 7, Issue 84
  7. Archive-name: less3/Part03
  8.  
  9.  
  10.  
  11.  ---- cut here ---- cut here ---- cut here ---- cut here ---- cut here ----
  12. : This is a shell archive.
  13. : Unpack by running /bin/sh.
  14. echo screen.c
  15. cat >screen.c <<'_SHAR_EOF_'
  16. /*
  17.  * Routines which deal with the characteristics of the terminal.
  18.  * Uses termcap to be as terminal-independent as possible.
  19.  *
  20.  * {{ Someday this should be rewritten to use curses. }}
  21.  */
  22.  
  23. #include "less.h"
  24. #if XENIX
  25. #include <sys/types.h>
  26. #include <sys/ioctl.h>
  27. #endif
  28.  
  29. #if TERMIO
  30. #include <termio.h>
  31. #else
  32. #include <sgtty.h>
  33. #endif
  34.  
  35. /*
  36.  * Strings passed to tputs() to do various terminal functions.
  37.  */
  38. static char
  39.     *sc_pad,        /* Pad string */
  40.     *sc_home,        /* Cursor home */
  41.     *sc_addline,        /* Add line, scroll down following lines */
  42.     *sc_lower_left,        /* Cursor to last line, first column */
  43.     *sc_move,        /* General cursor positioning */
  44.     *sc_clear,        /* Clear screen */
  45.     *sc_eol_clear,        /* Clear to end of line */
  46.     *sc_s_in,        /* Enter standout (highlighted) mode */
  47.     *sc_s_out,        /* Exit standout mode */
  48.     *sc_u_in,        /* Enter underline mode */
  49.     *sc_u_out,        /* Exit underline mode */
  50.     *sc_b_in,        /* Enter bold mode */
  51.     *sc_b_out,        /* Exit bold mode */
  52.     *sc_visual_bell,    /* Visual bell (flash screen) sequence */
  53.     *sc_backspace,        /* Backspace cursor */
  54.     *sc_init,        /* Startup terminal initialization */
  55.     *sc_deinit;        /* Exit terminal de-intialization */
  56. static int dumb;
  57. static int hard;
  58.  
  59. public int auto_wrap;        /* Terminal does \r\n when write past margin */
  60. public int ignaw;        /* Terminal ignores \n immediately after wrap */
  61. public int erase_char, kill_char; /* The user's erase and line-kill chars */
  62. public int sc_width, sc_height;    /* Height & width of screen */
  63. public int sc_window = -1;    /* window size for forward and backward */
  64. public int bo_width, be_width;    /* Printing width of boldface sequences */
  65. public int ul_width, ue_width;    /* Printing width of underline sequences */
  66. public int so_width, se_width;    /* Printing width of standout sequences */
  67.  
  68. /*
  69.  * These two variables are sometimes defined in,
  70.  * and needed by, the termcap library.
  71.  * It may be necessary on some systems to declare them extern here.
  72.  */
  73. /*extern*/ short ospeed;    /* Terminal output baud rate */
  74. /*extern*/ char PC;        /* Pad character */
  75.  
  76. extern int quiet;        /* If VERY_QUIET, use visual bell for bell */
  77. extern int know_dumb;        /* Don't complain about a dumb terminal */
  78. extern int back_scroll;
  79. char *tgetstr();
  80. char *tgoto();
  81.  
  82. /*
  83.  * Change terminal to "raw mode", or restore to "normal" mode.
  84.  * "Raw mode" means 
  85.  *    1. An outstanding read will complete on receipt of a single keystroke.
  86.  *    2. Input is not echoed.  
  87.  *    3. On output, \n is mapped to \r\n.
  88.  *    4. \t is NOT expanded into spaces.
  89.  *    5. Signal-causing characters such as ctrl-C (interrupt),
  90.  *       etc. are NOT disabled.
  91.  * It doesn't matter whether an input \n is mapped to \r, or vice versa.
  92.  */
  93.     public void
  94. raw_mode(on)
  95.     int on;
  96. {
  97. #if TERMIO
  98.     struct termio s;
  99.     static struct termio save_term;
  100.  
  101.     if (on)
  102.     {
  103.         /*
  104.          * Get terminal modes.
  105.          */
  106.         ioctl(2, TCGETA, &s);
  107.  
  108.         /*
  109.          * Save modes and set certain variables dependent on modes.
  110.          */
  111.         save_term = s;
  112.         ospeed = s.c_cflag & CBAUD;
  113.         erase_char = s.c_cc[VERASE];
  114.         kill_char = s.c_cc[VKILL];
  115.  
  116.         /*
  117.          * Set the modes to the way we want them.
  118.          */
  119.         s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
  120.         s.c_oflag |=  (OPOST|ONLCR|TAB3);
  121.         s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
  122.         s.c_cc[VMIN] = 1;
  123.         s.c_cc[VTIME] = 0;
  124.     } else
  125.     {
  126.         /*
  127.          * Restore saved modes.
  128.          */
  129.         s = save_term;
  130.     }
  131.     ioctl(2, TCSETAW, &s);
  132. #else
  133.     struct sgttyb s;
  134.     static struct sgttyb save_term;
  135.  
  136.     if (on)
  137.     {
  138.         /*
  139.          * Get terminal modes.
  140.          */
  141.         ioctl(2, TIOCGETP, &s);
  142.  
  143.         /*
  144.          * Save modes and set certain variables dependent on modes.
  145.          */
  146.         save_term = s;
  147.         ospeed = s.sg_ospeed;
  148.         erase_char = s.sg_erase;
  149.         kill_char = s.sg_kill;
  150.  
  151.         /*
  152.          * Set the modes to the way we want them.
  153.          */
  154.         s.sg_flags |= CBREAK;
  155.         s.sg_flags &= ~(ECHO|XTABS);
  156.     } else
  157.     {
  158.         /*
  159.          * Restore saved modes.
  160.          */
  161.         s = save_term;
  162.     }
  163.     ioctl(2, TIOCSETN, &s);
  164. #endif
  165. }
  166.  
  167.     static void
  168. cannot(s)
  169.     char *s;
  170. {
  171.     char message[100];
  172.  
  173.     if (know_dumb)
  174.         /* 
  175.          * He knows he has a dumb terminal, so don't tell him. 
  176.          */
  177.         return;
  178.  
  179.     sprintf(message, "WARNING: terminal cannot \"%s\"", s);
  180.     error(message);
  181. }
  182.  
  183. /*
  184.  * Get terminal capabilities via termcap.
  185.  */
  186.     public void
  187. get_term()
  188. {
  189.     char termbuf[1024];
  190.     char *sp;
  191.     static char sbuf[150];
  192.  
  193.     char *getenv();
  194.  
  195.     /*
  196.      * Find out what kind of terminal this is.
  197.      */
  198.     if (tgetent(termbuf, getenv("TERM")) <= 0)
  199.         dumb = 1;
  200.  
  201.     /*
  202.      * Get size of the screen.
  203.      */
  204.     if (dumb || (sc_height = tgetnum("li")) < 0 || tgetflag("hc"))
  205.     {
  206.         /* Oh no, this is a hardcopy terminal. */
  207.         hard = 1;
  208.         sc_height = 24;
  209.     }
  210.     /*
  211.      * This is terrible - the following if "knows" that it is being
  212.      * executed *after* command line and environment options have
  213.      * already been parsed.  Should it be executed in the main program
  214.      * instead?
  215.      */
  216.     if ((sc_window <= 0) || (sc_window >= sc_height))
  217.         sc_window = sc_height-1;
  218.     if (dumb || (sc_width = tgetnum("co")) < 0)
  219.         sc_width = 80;
  220.  
  221.     auto_wrap = tgetflag("am");
  222.     ignaw = tgetflag("xn");
  223.  
  224.     /*
  225.      * Assumes termcap variable "sg" is the printing width of
  226.      * the standout sequence, the end standout sequence,
  227.      * the underline sequence, the end underline sequence,
  228.      * the boldface sequence, and the end boldface sequence.
  229.      */
  230.     if ((so_width = tgetnum("sg")) < 0)
  231.         so_width = 0;
  232.     be_width = bo_width = ue_width = ul_width = se_width = so_width;
  233.  
  234.     /*
  235.      * Get various string-valued capabilities.
  236.      */
  237.     sp = sbuf;
  238.  
  239.     sc_pad = (dumb) ? NULL : tgetstr("pc", &sp);
  240.     if (sc_pad != NULL)
  241.         PC = *sc_pad;
  242.  
  243.     sc_init = (dumb) ? NULL : tgetstr("ti", &sp);
  244.     if (sc_init == NULL)
  245.         sc_init = "";
  246.  
  247.     sc_deinit= (dumb) ? NULL : tgetstr("te", &sp);
  248.     if (sc_deinit == NULL)
  249.         sc_deinit = "";
  250.  
  251.     sc_eol_clear = (dumb) ? NULL : tgetstr("ce", &sp);
  252.     if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
  253.     {
  254.         cannot("clear to end of line");
  255.         sc_eol_clear = "";
  256.     }
  257.  
  258.     sc_clear = (dumb) ? NULL : tgetstr("cl", &sp);
  259.     if (hard || sc_clear == NULL || *sc_clear == '\0')
  260.     {
  261.         cannot("clear screen");
  262.         sc_clear = "\n\n";
  263.     }
  264.  
  265.     sc_move = (dumb) ? NULL : tgetstr("cm", &sp);
  266.     if (hard || sc_move == NULL || *sc_move == '\0')
  267.     {
  268.         /*
  269.          * This is not an error here, because we don't 
  270.          * always need sc_move.
  271.          * We need it only if we don't have home or lower-left.
  272.          */
  273.         sc_move = "";
  274.     }
  275.  
  276.     sc_s_in = (dumb) ? NULL : tgetstr("so", &sp);
  277.     if (hard || sc_s_in == NULL)
  278.         sc_s_in = "";
  279.  
  280.     sc_s_out = (dumb) ? NULL : tgetstr("se", &sp);
  281.     if (hard || sc_s_out == NULL)
  282.         sc_s_out = "";
  283.  
  284.     sc_u_in = (dumb) ? NULL : tgetstr("us", &sp);
  285.     if (hard || sc_u_in == NULL)
  286.         sc_u_in = sc_s_in;
  287.  
  288.     sc_u_out = (dumb) ? NULL : tgetstr("ue", &sp);
  289.     if (hard || sc_u_out == NULL)
  290.         sc_u_out = sc_s_out;
  291.  
  292.     sc_b_in = (dumb) ? NULL : tgetstr("md", &sp);
  293.     if (hard || sc_b_in == NULL)
  294.     {
  295.         sc_b_in = sc_s_in;
  296.         sc_b_out = sc_s_out;
  297.     } else
  298.     {
  299.         sc_b_out = (dumb) ? NULL : tgetstr("me", &sp);
  300.         if (hard || sc_b_out == NULL)
  301.             sc_b_out = "";
  302.     }
  303.  
  304.     sc_visual_bell = (dumb) ? NULL : tgetstr("vb", &sp);
  305.     if (hard || sc_visual_bell == NULL)
  306.         sc_visual_bell = "";
  307.  
  308.     sc_home = (dumb) ? NULL : tgetstr("ho", &sp);
  309.     if (hard || sc_home == NULL || *sc_home == '\0')
  310.     {
  311.         if (*sc_move == '\0')
  312.         {
  313.             cannot("home cursor");
  314.             /*
  315.              * This last resort for sc_home is supposed to
  316.              * be an up-arrow suggesting moving to the 
  317.              * top of the "virtual screen". (The one in
  318.              * your imagination as you try to use this on
  319.              * a hard copy terminal.)
  320.              */
  321.             sc_home = "|\b^";        
  322.         } else
  323.         {
  324.             /* 
  325.              * No "home" string,
  326.              * but we can use "move(0,0)".
  327.              */
  328.             strcpy(sp, tgoto(sc_move, 0, 0));
  329.             sc_home = sp;
  330.             sp += strlen(sp) + 1;
  331.         }
  332.     }
  333.  
  334.     sc_lower_left = (dumb) ? NULL : tgetstr("ll", &sp);
  335.     if (hard || sc_lower_left == NULL || *sc_lower_left == '\0')
  336.     {
  337.         if (*sc_move == '\0')
  338.         {
  339.             cannot("move cursor to lower left of screen");
  340.             sc_lower_left = "\r";
  341.         } else
  342.         {
  343.             /*
  344.              * No "lower-left" string, 
  345.              * but we can use "move(0,last-line)".
  346.              */
  347.             strcpy(sp, tgoto(sc_move, 0, sc_height-1));
  348.             sc_lower_left = sp;
  349.             sp += strlen(sp) + 1;
  350.         }
  351.     }
  352.  
  353.     /*
  354.      * To add a line at top of screen and scroll the display down,
  355.      * we use "al" (add line) or "sr" (scroll reverse).
  356.      */
  357.     if (dumb)
  358.         sc_addline = NULL;
  359.     else if ((sc_addline = tgetstr("al", &sp)) == NULL || 
  360.          *sc_addline == '\0')
  361.         sc_addline = tgetstr("sr", &sp);
  362.  
  363.     if (hard || sc_addline == NULL || *sc_addline == '\0')
  364.     {
  365.         cannot("scroll backwards");
  366.         sc_addline = "";
  367.         /* Force repaint on any backward movement */
  368.         back_scroll = 0;
  369.     }
  370.  
  371.     if (dumb || tgetflag("bs"))
  372.         sc_backspace = "\b";
  373.     else
  374.     {
  375.         sc_backspace = tgetstr("bc", &sp);
  376.         if (sc_backspace == NULL || *sc_backspace == '\0')
  377.             sc_backspace = "\b";
  378.     }
  379. }
  380.  
  381.  
  382. /*
  383.  * Below are the functions which perform all the 
  384.  * terminal-specific screen manipulation.
  385.  */
  386.  
  387.  
  388. /*
  389.  * Initialize terminal
  390.  */
  391.     public void
  392. init()
  393. {
  394.     tputs(sc_init, sc_height, putc);
  395. }
  396.  
  397. /*
  398.  * Deinitialize terminal
  399.  */
  400.     public void
  401. deinit()
  402. {
  403.     tputs(sc_deinit, sc_height, putc);
  404. }
  405.  
  406. /*
  407.  * Home cursor (move to upper left corner of screen).
  408.  */
  409.     public void
  410. home()
  411. {
  412.     tputs(sc_home, 1, putc);
  413. }
  414.  
  415. /*
  416.  * Add a blank line (called with cursor at home).
  417.  * Should scroll the display down.
  418.  */
  419.     public void
  420. add_line()
  421. {
  422.     tputs(sc_addline, sc_height, putc);
  423. }
  424.  
  425. /*
  426.  * Move cursor to lower left corner of screen.
  427.  */
  428.     public void
  429. lower_left()
  430. {
  431.     tputs(sc_lower_left, 1, putc);
  432. }
  433.  
  434. /*
  435.  * Ring the terminal bell.
  436.  */
  437.     public void
  438. bell()
  439. {
  440.     if (quiet == VERY_QUIET)
  441.         vbell();
  442.     else
  443.         putc('\7');
  444. }
  445.  
  446. /*
  447.  * Output the "visual bell", if there is one.
  448.  */
  449.     public void
  450. vbell()
  451. {
  452.     if (*sc_visual_bell == '\0')
  453.         return;
  454.     tputs(sc_visual_bell, sc_height, putc);
  455. }
  456.  
  457. /*
  458.  * Clear the screen.
  459.  */
  460.     public void
  461. clear()
  462. {
  463.     tputs(sc_clear, sc_height, putc);
  464. }
  465.  
  466. /*
  467.  * Clear from the cursor to the end of the cursor's line.
  468.  * {{ This must not move the cursor. }}
  469.  */
  470.     public void
  471. clear_eol()
  472. {
  473.     tputs(sc_eol_clear, 1, putc);
  474. }
  475.  
  476. /*
  477.  * Begin "standout" (bold, underline, or whatever).
  478.  */
  479.     public void
  480. so_enter()
  481. {
  482.     tputs(sc_s_in, 1, putc);
  483. }
  484.  
  485. /*
  486.  * End "standout".
  487.  */
  488.     public void
  489. so_exit()
  490. {
  491.     tputs(sc_s_out, 1, putc);
  492. }
  493.  
  494. /*
  495.  * Begin "underline" (hopefully real underlining, 
  496.  * otherwise whatever the terminal provides).
  497.  */
  498.     public void
  499. ul_enter()
  500. {
  501.     tputs(sc_u_in, 1, putc);
  502. }
  503.  
  504. /*
  505.  * End "underline".
  506.  */
  507.     public void
  508. ul_exit()
  509. {
  510.     tputs(sc_u_out, 1, putc);
  511. }
  512.  
  513. /*
  514.  * Begin "bold"
  515.  */
  516.     public void
  517. bo_enter()
  518. {
  519.     tputs(sc_b_in, 1, putc);
  520. }
  521.  
  522. /*
  523.  * End "bold".
  524.  */
  525.     public void
  526. bo_exit()
  527. {
  528.     tputs(sc_b_out, 1, putc);
  529. }
  530.  
  531. /*
  532.  * Erase the character to the left of the cursor 
  533.  * and move the cursor left.
  534.  */
  535.     public void
  536. backspace()
  537. {
  538.     /* 
  539.      * Try to erase the previous character by overstriking with a space.
  540.      */
  541.     tputs(sc_backspace, 1, putc);
  542.     putc(' ');
  543.     tputs(sc_backspace, 1, putc);
  544. }
  545.  
  546. /*
  547.  * Output a plain backspace, without erasing the previous char.
  548.  */
  549.     public void
  550. putbs()
  551. {
  552.     tputs(sc_backspace, 1, putc);
  553. }
  554. _SHAR_EOF_
  555.  
  556. echo prompt.c
  557. cat >prompt.c <<'_SHAR_EOF_'
  558. /*
  559.  * Prompting and other messages.
  560.  * There are three flavors of prompts, SHORT, MEDIUM and LONG,
  561.  * selected by the -m/-M options.
  562.  * A prompt is either a colon or a message composed of various
  563.  * pieces, such as the name of the file being viewed, the percentage
  564.  * into the file, etc.
  565.  */
  566.  
  567. #include "less.h"
  568. #include "position.h"
  569.  
  570. extern int pr_type;
  571. extern int ispipe;
  572. extern int hit_eof;
  573. extern int new_file;
  574. extern int sc_width;
  575. extern char current_file[];
  576. extern int ac;
  577. extern char **av;
  578. extern int curr_ac;
  579.  
  580. /*
  581.  * Prototypes for the three flavors of prompts.
  582.  * These strings are expanded by pr_expand().
  583.  */
  584. char *prproto[] = { 
  585.     "fo",        /* PR_SHORT */
  586.     "foP",        /* PR_MEDIUM */
  587.     "Fobp"        /* PR_LONG */
  588. };
  589.  
  590. static char message[200];
  591. static char *mp;
  592.  
  593.     static void
  594. setmp()
  595. {
  596.     mp = message + strlen(message);
  597. }
  598.  
  599. /*
  600.  * Append the name of the current file (to the message buffer).
  601.  */
  602.     static void
  603. ap_filename()
  604. {
  605.     if (ispipe)
  606.         return;
  607.     strtcpy(mp, current_file, &message[sizeof(message)] - mp);
  608.     setmp();
  609. }
  610.  
  611. /*
  612.  * Append the "file N of M" message.
  613.  */
  614.     static void
  615. ap_of()
  616. {
  617.     if (ac <= 1)
  618.         return;
  619.     sprintf(mp, " (file %d of %d)", curr_ac+1, ac);
  620.     setmp();
  621. }
  622.  
  623. /*
  624.  * Append the byte offset into the current file.
  625.  */
  626.     static void
  627. ap_byte()
  628. {
  629.     POSITION pos, len;
  630.  
  631.     pos = position(BOTTOM_PLUS_ONE);
  632.     if (pos == NULL_POSITION)
  633.         pos = ch_length();
  634.     if (pos != NULL_POSITION)
  635.     {
  636.         sprintf(mp, " byte %ld", (long)pos);
  637.         setmp();
  638.         len = ch_length();
  639.         if (len > 0)
  640.         {
  641.             sprintf(mp, "/%ld", (long)len);
  642.             setmp();
  643.         }
  644.     }
  645. }
  646.  
  647. /*
  648.  * Append the percentage into the current file.
  649.  * If we cannot find the percentage and must_print is true,
  650.  * use the byte offset.
  651.  */
  652.     static void
  653. ap_percent(must_print)
  654. {
  655.     POSITION pos,len;
  656.  
  657.     pos = position(BOTTOM_PLUS_ONE);
  658.     len = ch_length();
  659.     if (len > 0 && pos != NULL_POSITION)
  660.     {
  661.         sprintf(mp, " (%ld%%)", (100 * (long)pos) / len);
  662.         setmp();
  663.     } else if (must_print)
  664.         ap_byte();
  665. }
  666.  
  667. /*
  668.  * Append the end-of-file message.
  669.  */
  670.     static void
  671. ap_eof()
  672. {
  673.     strcpy(mp, " (END)");
  674.     setmp();
  675.     if (curr_ac + 1 < ac)
  676.     {
  677.         sprintf(mp, " - Next: %s", av[curr_ac+1]);
  678.         setmp();
  679.     }
  680. }
  681.  
  682. /*
  683.  * Construct a message based on a prototype string.
  684.  */
  685.     static char *
  686. pr_expand(proto, maxwidth)
  687.     char *proto;
  688.     int maxwidth;
  689. {
  690.     register char *p;
  691.  
  692.     mp = message;
  693.  
  694.     for (p = proto;  *p != '\0';  p++)
  695.     {
  696.         if (maxwidth > 0 && mp >= message + maxwidth)
  697.         {
  698.             /*
  699.              * Truncate to the screen width.
  700.              * {{ This isn't very nice. }}
  701.              */
  702.             mp = message + maxwidth;
  703.             break;
  704.         }
  705.         switch (*p)
  706.         {
  707.         case 'f':
  708.             if (new_file)
  709.                 ap_filename();
  710.             break;
  711.         case 'F':
  712.             ap_filename();
  713.             break;
  714.         case 'o':
  715.             if (new_file)
  716.                 ap_of();
  717.             break;
  718.         case 'O':
  719.             ap_of();
  720.             break;
  721.         case 'b':
  722.             ap_byte();
  723.             break;
  724.         case 'p':
  725.             if (!hit_eof)
  726.                 ap_percent(0);
  727.             break;
  728.         case 'P':
  729.             if (!hit_eof)
  730.                 ap_percent(1);
  731.             break;
  732.         case '<':
  733.             while (*++p != '>')
  734.             {
  735.                 if (*p == '\0')
  736.                 {
  737.                     p--;
  738.                     break;
  739.                 }
  740.                 *mp++ = *p;
  741.             }
  742.             break;
  743.         default:
  744.             *mp++ = *p;
  745.             break;
  746.           }
  747.     }
  748.     if (hit_eof)
  749.         ap_eof();
  750.  
  751.     new_file = 0;
  752.     if (mp == message)
  753.         return (NULL);
  754.     *mp = '\0';
  755.     return (message);
  756. }
  757.  
  758. /*
  759.  * Return a message suitable for printing by the "=" command.
  760.  */
  761.     public char *
  762. eq_message()
  763. {
  764.     return (pr_expand("FObp", 0));
  765. }
  766.  
  767. /*
  768.  * Return a prompt.
  769.  * This depends on the prompt type (SHORT, MEDIUM, LONG), etc.
  770.  * If we can't come up with an appropriate prompt, return NULL
  771.  * and the caller will prompt with a colon.
  772.  */
  773.     public char *
  774. pr_string()
  775. {
  776.     return (pr_expand(prproto[pr_type], sc_width-2));
  777. }
  778. _SHAR_EOF_
  779.  
  780. echo line.c
  781. cat >line.c <<'_SHAR_EOF_'
  782. /*
  783.  * Routines to manipulate the "line buffer".
  784.  * The line buffer holds a line of output as it is being built
  785.  * in preparation for output to the screen.
  786.  * We keep track of the PRINTABLE length of the line as it is being built.
  787.  */
  788.  
  789. #include "less.h"
  790.  
  791. static char linebuf[1024];    /* Buffer which holds the current output line */
  792. static char *curr;        /* Pointer into linebuf */
  793. static int column;        /* Printable length, accounting for
  794.                    backspaces, etc. */
  795. /*
  796.  * A ridiculously complex state machine takes care of backspaces 
  797.  * when in BS_SPECIAL mode.  The complexity arises from the attempt
  798.  * to deal with all cases, especially involving long lines with underlining,
  799.  * boldfacing or whatever.  There are still some cases which will break it.
  800.  *
  801.  * There are four states:
  802.  *    LN_NORMAL is the normal state (not in underline mode).
  803.  *    LN_UNDERLINE means we are in underline mode.  We expect to get
  804.  *        either a sequence like "_\bX" or "X\b_" to continue
  805.  *        underline mode, or anything else to end underline mode.
  806.  *    LN_BOLDFACE means we are in boldface mode.  We expect to get sequences
  807.  *        like "X\bX\b...X\bX" to continue boldface mode, or anything
  808.  *        else to end boldface mode.
  809.  *    LN_UL_X means we are one character after LN_UNDERLINE
  810.  *        (we have gotten the '_' in "_\bX" or the 'X' in "X\b_").
  811.  *    LN_UL_XB means we are one character after LN_UL_X 
  812.  *        (we have gotten the backspace in "_\bX" or "X\b_";
  813.  *        we expect one more ordinary character, 
  814.  *        which will put us back in state LN_UNDERLINE).
  815.  *    LN_BO_X means we are one character after LN_BOLDFACE
  816.  *        (we have gotten the 'X' in "X\bX").
  817.  *    LN_BO_XB means we are one character after LN_BO_X
  818.  *        (we have gotten the backspace in "X\bX";
  819.  *        we expect one more 'X' which will put us back
  820.  *        in LN_BOLDFACE).
  821.  */
  822. static int ln_state;        /* Currently in normal/underline/bold/etc mode? */
  823. #define    LN_NORMAL    0    /* Not in underline, boldface or whatever mode */
  824. #define    LN_UNDERLINE    1    /* In underline, need next char */
  825. #define    LN_UL_X        2    /* In underline, got char, need \b */
  826. #define    LN_UL_XB    3    /* In underline, got char & \b, need one more */
  827. #define    LN_BOLDFACE    4    /* In boldface, need next char */
  828. #define    LN_BO_X        5    /* In boldface, got char, need \b */
  829. #define    LN_BO_XB    6    /* In boldface, got char & \b, need same char */
  830.  
  831. public char *line;        /* Pointer to the current line.
  832.                    Usually points to linebuf. */
  833.  
  834. extern int bs_mode;
  835. extern int tabstop;
  836. extern int bo_width, be_width;
  837. extern int ul_width, ue_width;
  838. extern int sc_width, sc_height;
  839.  
  840. /*
  841.  * Rewind the line buffer.
  842.  */
  843.     public void
  844. prewind()
  845. {
  846.     line = curr = linebuf;
  847.     ln_state = LN_NORMAL;
  848.     column = 0;
  849. }
  850.  
  851. /*
  852.  * Append a character to the line buffer.
  853.  * Expand tabs into spaces, handle underlining, boldfacing, etc.
  854.  * Returns 0 if ok, 1 if couldn't fit in buffer.
  855.  */
  856.  
  857. #define    NEW_COLUMN(newcol)    if ((newcol) + ((ln_state)?ue_width:0) > sc_width) \
  858.                     return (1); else column = (newcol)
  859.  
  860.     public int
  861. pappend(c)
  862.     int c;
  863. {
  864.     if (c == '\0')
  865.     {
  866.         /*
  867.          * Terminate any special modes, if necessary.
  868.          * Append a '\0' to the end of the line.
  869.          */
  870.         switch (ln_state)
  871.         {
  872.         case LN_UL_X:
  873.             curr[0] = curr[-1];
  874.             curr[-1] = UE_CHAR;
  875.             curr++;
  876.             break;
  877.         case LN_BO_X:
  878.             curr[0] = curr[-1];
  879.             curr[-1] = BE_CHAR;
  880.             curr++;
  881.             break;
  882.         case LN_UL_XB:
  883.         case LN_UNDERLINE:
  884.             *curr++ = UE_CHAR;
  885.             break;
  886.         case LN_BO_XB:
  887.         case LN_BOLDFACE:
  888.             *curr++ = BE_CHAR;
  889.             break;
  890.         }
  891.         ln_state = LN_NORMAL;
  892.         *curr = '\0';
  893.         return (0);
  894.     }
  895.  
  896.     if (curr > linebuf + sizeof(linebuf) - 12)
  897.         /*
  898.          * Almost out of room in the line buffer.
  899.          * Don't take any chances.
  900.          * {{ Linebuf is supposed to be big enough that this
  901.          *    will never happen, but may need to be made 
  902.          *    bigger for wide screens or lots of backspaces. }}
  903.          */
  904.         return (1);
  905.  
  906.     if (bs_mode == BS_SPECIAL)
  907.     {
  908.         /*
  909.          * Advance the state machine.
  910.          */
  911.         switch (ln_state)
  912.         {
  913.         case LN_NORMAL:
  914.             if (curr <= linebuf + 1 || curr[-1] != '\b')
  915.                 break;
  916.  
  917.             if (c == curr[-2])
  918.                 goto enter_boldface;
  919.             if (c == '_' || curr[-2] == '_')
  920.                 goto enter_underline;
  921.             curr -= 2;
  922.             break;
  923.  
  924. enter_boldface:
  925.             /*
  926.              * We have "X\bX" (including the current char).
  927.              * Switch into boldface mode.
  928.              */
  929.             if (column + bo_width + be_width + 1 >= sc_width)
  930.                 /*
  931.                  * Not enough room left on the screen to 
  932.                  * enter and exit boldface mode.
  933.                  */
  934.                 return (1);
  935.  
  936.             if (bo_width > 0 && 
  937.                 curr > linebuf + 2 && curr[-3] == ' ')
  938.             {
  939.                 /*
  940.                  * Special case for magic cookie terminals:
  941.                  * if the previous char was a space, replace 
  942.                  * it with the "enter boldface" sequence.
  943.                  */
  944.                 curr[-3] = BO_CHAR;
  945.                 column += bo_width-1;
  946.             } else
  947.             {
  948.                 curr[-1] = curr[-2];
  949.                 curr[-2] = BO_CHAR;
  950.                 column += bo_width;
  951.                 curr++;
  952.             }
  953.             goto ln_bo_xb_case;
  954.  
  955. enter_underline:
  956.             /*
  957.              * We have either "_\bX" or "X\b_" (including
  958.              * the current char).  Switch into underline mode.
  959.              */
  960.             if (column + ul_width + ue_width + 1 >= sc_width)
  961.                 /*
  962.                  * Not enough room left on the screen to 
  963.                  * enter and exit underline mode.
  964.                  */
  965.                 return (1);
  966.  
  967.             if (ul_width > 0 && 
  968.                 curr > linebuf + 2 && curr[-3] == ' ')
  969.             {
  970.                 /*
  971.                  * Special case for magic cookie terminals:
  972.                  * if the previous char was a space, replace 
  973.                  * it with the "enter underline" sequence.
  974.                  */
  975.                 curr[-3] = UL_CHAR;
  976.                 column += ul_width-1;
  977.             } else
  978.             {
  979.                 curr[-1] = curr[-2];
  980.                 curr[-2] = UL_CHAR;
  981.                 column += ul_width;
  982.                 curr++;
  983.             }
  984.             goto ln_ul_xb_case;
  985.             /*NOTREACHED*/
  986.         case LN_UL_XB:
  987.             /*
  988.              * Termination of a sequence "_\bX" or "X\b_".
  989.              */
  990.             if (c != '_' && curr[-2] != '_' && c == curr[-2])
  991.             {
  992.                 /*
  993.                  * We seem to have run on from underlining
  994.                  * into boldfacing - this is a nasty fix, but
  995.                  * until this whole routine is rewritten as a
  996.                  * real DFA, ...  well ...
  997.                  */
  998.                 curr[0] = curr[-2];
  999.                 curr[-2] = UE_CHAR;
  1000.                 curr[-1] = BO_CHAR;
  1001.                 curr += 2; /* char & non-existent backspace */
  1002.                 ln_state = LN_BO_XB;
  1003.                 goto ln_bo_xb_case;
  1004.             }
  1005. ln_ul_xb_case:
  1006.             if (c == '_')
  1007.                 c = curr[-2];
  1008.             curr -= 2;
  1009.             ln_state = LN_UNDERLINE;
  1010.             break;
  1011.         case LN_BO_XB:
  1012.             /*
  1013.              * Termination of a sequnce "X\bX".
  1014.              */
  1015.             if (c != curr[-2] && (c == '_' || curr[-2] == '_'))
  1016.             {
  1017.                 /*
  1018.                  * We seem to have run on from
  1019.                  * boldfacing into underlining.
  1020.                  */
  1021.                 curr[0] = curr[-2];
  1022.                 curr[-2] = BE_CHAR;
  1023.                 curr[-1] = UL_CHAR;
  1024.                 curr += 2; /* char & non-existent backspace */
  1025.                 ln_state = LN_UL_XB;
  1026.                 goto ln_ul_xb_case;
  1027.             }
  1028. ln_bo_xb_case:
  1029.             curr -= 2;
  1030.             ln_state = LN_BOLDFACE;
  1031.             break;
  1032.         case LN_UNDERLINE:
  1033.             if (column + ue_width + bo_width + 1 + be_width >= sc_width)
  1034.                 /*
  1035.                  * We have just barely enough room to 
  1036.                  * exit underline mode and handle a possible
  1037.                  * underline/boldface run on mixup.
  1038.                  */
  1039.                 return (1);
  1040.             ln_state = LN_UL_X;
  1041.             break;
  1042.         case LN_BOLDFACE:
  1043.             if (c == '\b')
  1044.             {
  1045.                 ln_state = LN_BO_XB;
  1046.                 break;
  1047.             }
  1048.             if (column + be_width + ul_width + 1 + ue_width >= sc_width)
  1049.                 /*
  1050.                  * We have just barely enough room to 
  1051.                  * exit underline mode and handle a possible
  1052.                  * underline/boldface run on mixup.
  1053.                  */
  1054.                 return (1);
  1055.             ln_state = LN_BO_X;
  1056.             break;
  1057.         case LN_UL_X:
  1058.             if (c == '\b')
  1059.                 ln_state = LN_UL_XB;
  1060.             else
  1061.             {
  1062.                 /*
  1063.                  * Exit underline mode.
  1064.                  * We have to shuffle the chars a bit
  1065.                  * to make this work.
  1066.                  */
  1067.                 curr[0] = curr[-1];
  1068.                 curr[-1] = UE_CHAR;
  1069.                 column += ue_width;
  1070.                 if (ue_width > 0 && curr[0] == ' ')
  1071.                     /*
  1072.                      * Another special case for magic
  1073.                      * cookie terminals: if the next
  1074.                      * char is a space, replace it
  1075.                      * with the "exit underline" sequence.
  1076.                      */
  1077.                     column--;
  1078.                 else
  1079.                     curr++;
  1080.                 ln_state = LN_NORMAL;
  1081.             } 
  1082.             break;
  1083.         case LN_BO_X:
  1084.             if (c == '\b')
  1085.                 ln_state = LN_BO_XB;
  1086.             else
  1087.             {
  1088.                 /*
  1089.                  * Exit boldface mode.
  1090.                  * We have to shuffle the chars a bit
  1091.                  * to make this work.
  1092.                  */
  1093.                 curr[0] = curr[-1];
  1094.                 curr[-1] = BE_CHAR;
  1095.                 column += be_width;
  1096.                 if (be_width > 0 && curr[0] == ' ')
  1097.                     /*
  1098.                      * Another special case for magic
  1099.                      * cookie terminals: if the next
  1100.                      * char is a space, replace it
  1101.                      * with the "exit boldface" sequence.
  1102.                      */
  1103.                     column--;
  1104.                 else
  1105.                     curr++;
  1106.                 ln_state = LN_NORMAL;
  1107.             } 
  1108.             break;
  1109.         }
  1110.     }
  1111.     
  1112.     if (c == '\t') 
  1113.     {
  1114.         /*
  1115.          * Expand a tab into spaces.
  1116.          */
  1117.         do
  1118.         {
  1119.             NEW_COLUMN(column+1);
  1120.         } while ((column % tabstop) != 0);
  1121.         *curr++ = '\t';
  1122.         return (0);
  1123.     }
  1124.  
  1125.     if (c == '\b')
  1126.     {
  1127.         if (bs_mode == BS_CONTROL)
  1128.         {
  1129.             /*
  1130.              * Treat backspace as a control char: output "^H".
  1131.              */
  1132.             NEW_COLUMN(column+2);
  1133.             *curr++ = ('H' | 0200);
  1134.         } else
  1135.         {
  1136.             /*
  1137.              * Output a real backspace.
  1138.              */
  1139.             column--;
  1140.             *curr++ = '\b';
  1141.         }
  1142.         return (0);
  1143.     } 
  1144.  
  1145.     if (control_char(c))
  1146.     {
  1147.         /*
  1148.          * Put a "^X" into the buffer.
  1149.          * The 0200 bit is used to tell put_line() to prefix
  1150.          * the char with a ^.  We don't actually put the ^
  1151.          * in the buffer because we sometimes need to move
  1152.          * chars around, and such movement might separate 
  1153.          * the ^ from its following character.
  1154.          * {{ This should be redone so that we can use an
  1155.          *    8 bit (e.g. international) character set. }}
  1156.          */
  1157.         NEW_COLUMN(column+2);
  1158.         *curr++ = (carat_char(c) | 0200);
  1159.         return (0);
  1160.     }
  1161.  
  1162.     /*
  1163.      * Ordinary character.  Just put it in the buffer.
  1164.      */
  1165.     NEW_COLUMN(column+1);
  1166.     *curr++ = c;
  1167.     return (0);
  1168. }
  1169.  
  1170. /*
  1171.  * Analogous to forw_line(), but deals with "raw lines":
  1172.  * lines which are not split for screen width.
  1173.  * {{ This is supposed to be more efficient than forw_line(). }}
  1174.  */
  1175.     public POSITION
  1176. forw_raw_line(curr_pos)
  1177.     POSITION curr_pos;
  1178. {
  1179.     register char *p;
  1180.     register int c;
  1181.     POSITION new_pos;
  1182.  
  1183.     if (curr_pos == NULL_POSITION || ch_seek(curr_pos) ||
  1184.         (c = ch_forw_get()) == EOF)
  1185.         return (NULL_POSITION);
  1186.  
  1187.     p = linebuf;
  1188.  
  1189.     for (;;)
  1190.     {
  1191.         if (c == '\n' || c == EOF)
  1192.         {
  1193.             new_pos = ch_tell();
  1194.             break;
  1195.         }
  1196.         if (p >= &linebuf[sizeof(linebuf)-1])
  1197.         {
  1198.             /*
  1199.              * Overflowed the input buffer.
  1200.              * Pretend the line ended here.
  1201.              * {{ The line buffer is supposed to be big
  1202.              *    enough that this never happens. }}
  1203.              */
  1204.             new_pos = ch_tell() - 1;
  1205.             break;
  1206.         }
  1207.         *p++ = c;
  1208.         c = ch_forw_get();
  1209.     }
  1210.     *p = '\0';
  1211.     line = linebuf;
  1212.     return (new_pos);
  1213. }
  1214.  
  1215. /*
  1216.  * Analogous to back_line(), but deals with "raw lines".
  1217.  * {{ This is supposed to be more efficient than back_line(). }}
  1218.  */
  1219.     public POSITION
  1220. back_raw_line(curr_pos)
  1221.     POSITION curr_pos;
  1222. {
  1223.     register char *p;
  1224.     register int c;
  1225.     POSITION new_pos;
  1226.  
  1227.     if (curr_pos == NULL_POSITION || curr_pos <= (POSITION)0 ||
  1228.         ch_seek(curr_pos-1))
  1229.         return (NULL_POSITION);
  1230.  
  1231.     p = &linebuf[sizeof(linebuf)];
  1232.     *--p = '\0';
  1233.  
  1234.     for (;;)
  1235.     {
  1236.         c = ch_back_get();
  1237.         if (c == '\n')
  1238.         {
  1239.             /*
  1240.              * This is the newline ending the previous line.
  1241.              * We have hit the beginning of the line.
  1242.              */
  1243.             new_pos = ch_tell() + 1;
  1244.             break;
  1245.         }
  1246.         if (c == EOF)
  1247.         {
  1248.             /*
  1249.              * We have hit the beginning of the file.
  1250.              * This must be the first line in the file.
  1251.              * This must, of course, be the beginning of the line.
  1252.              */
  1253.             new_pos = (POSITION)0;
  1254.             break;
  1255.         }
  1256.         if (p <= linebuf)
  1257.         {
  1258.             /*
  1259.              * Overflowed the input buffer.
  1260.              * Pretend the line ended here.
  1261.              */
  1262.             new_pos = ch_tell() + 1;
  1263.             break;
  1264.         }
  1265.         *--p = c;
  1266.     }
  1267.     line = p;
  1268.     return (new_pos);
  1269. }
  1270. _SHAR_EOF_
  1271.  
  1272. echo signal.c
  1273. cat >signal.c <<'_SHAR_EOF_'
  1274. /*
  1275.  * Routines dealing with signals.
  1276.  *
  1277.  * A signal usually merely causes a bit to be set in the "signals" word.
  1278.  * At some convenient time, the mainline code checks to see if any
  1279.  * signals need processing by calling psignal().
  1280.  * An exception is made if we are reading from the keyboard when the
  1281.  * signal is received.  Some operating systems will simply call the
  1282.  * signal handler and NOT return from the read (with EINTR).
  1283.  * To handle this case, we service the interrupt directly from
  1284.  * the handler if we are reading from the keyboard.
  1285.  */
  1286.  
  1287. #include "less.h"
  1288. #include <signal.h>
  1289. #include <setjmp.h>
  1290.  
  1291. /*
  1292.  * The type of signal handler functions.
  1293.  * Usually int, although it should be void.
  1294.  */
  1295. typedef    int        HANDLER;
  1296.  
  1297. /*
  1298.  * "sigs" contains bits indicating signals which need to be processed.
  1299.  */
  1300. public int sigs;
  1301. #define    S_INTERRUPT    01
  1302. #ifdef SIGTSTP
  1303. #define    S_STOP        02
  1304. #endif
  1305.  
  1306. extern int reading;
  1307. extern char *first_cmd;
  1308. extern jmp_buf main_loop;
  1309.  
  1310. /*
  1311.  * Interrupt signal handler.
  1312.  */
  1313.     static HANDLER
  1314. interrupt()
  1315. {
  1316.     SIGNAL(SIGINT, interrupt);
  1317.     sigs |= S_INTERRUPT;
  1318.     if (reading)
  1319.         psignals();
  1320. }
  1321.  
  1322. #ifdef SIGTSTP
  1323. /*
  1324.  * "Stop" (^Z) signal handler.
  1325.  */
  1326.     static HANDLER
  1327. stop()
  1328. {
  1329.     SIGNAL(SIGTSTP, stop);
  1330.     sigs |= S_STOP;
  1331.     if (reading)
  1332.         psignals();
  1333. }
  1334. #endif
  1335.  
  1336. /*
  1337.  * Set up the signal handlers.
  1338.  */
  1339.     public void
  1340. init_signals()
  1341. {
  1342.     (void) SIGNAL(SIGINT, interrupt);
  1343. #ifdef SIGTSTP
  1344.     (void) SIGNAL(SIGTSTP, stop);
  1345. #endif
  1346. }
  1347.  
  1348. /*
  1349.  * Process any signals we have recieved.
  1350.  * A received signal cause a bit to be set in "sigs".
  1351.  */
  1352.     public void 
  1353. psignals()
  1354. {
  1355.     register int tsignals;
  1356.  
  1357.     tsignals = sigs;
  1358.     sigs = 0;
  1359.     if (tsignals == 0)
  1360.         return;
  1361.  
  1362.     dropout();        /* Discard any buffered output */
  1363.  
  1364. #ifdef SIGTSTP
  1365.     if (tsignals & S_STOP)
  1366.     {
  1367.         /*
  1368.          * Clean up the terminal.
  1369.          */
  1370. #ifdef SIGTTOU
  1371.         SIGNAL(SIGTTOU, SIG_IGN);
  1372. #endif
  1373.         lower_left();
  1374.         clear_eol();
  1375.         flush();
  1376.         raw_mode(0);
  1377. #ifdef SIGTTOU
  1378.         SIGNAL(SIGTTOU, SIG_DFL);
  1379. #endif
  1380.         SIGNAL(SIGTSTP, SIG_DFL);
  1381. #if SIGSETMASK
  1382.         /*
  1383.          * This system will not allow us to send a 
  1384.          * stop signal (SIGTSTP) to ourself
  1385.          * while we are in the signal handler, like maybe now.
  1386.          * (This can be the case if we are reading; see comment above.)
  1387.          * So we ask the silly system for permission to do so.
  1388.          */
  1389.         sigsetmask(0);
  1390. #endif
  1391.         kill(getpid(), SIGTSTP);
  1392.         /*
  1393.          * ... Bye bye. ...
  1394.          * Hopefully we'll be back later and resume here...
  1395.          * Reset the terminal and arrange to repaint the
  1396.          * screen when we get back to the main command loop.
  1397.          */
  1398.         SIGNAL(SIGTSTP, stop);
  1399.         raw_mode(1);
  1400.         first_cmd = "r";
  1401.         longjmp(main_loop, 1);
  1402.     }
  1403. #endif
  1404.     if (tsignals & S_INTERRUPT)
  1405.     {
  1406.         bell();
  1407.         /*
  1408.          * {{ You may wish to replace the bell() with 
  1409.          *    error("Interrupt"); }}
  1410.          */
  1411.     }
  1412.  
  1413.     longjmp(main_loop, 1);
  1414. }
  1415.  
  1416. /*
  1417.  * Pass the specified command to a shell to be executed.
  1418.  * Like plain "system()", but handles resetting terminal modes, etc.
  1419.  */
  1420.     public void
  1421. lsystem(cmd)
  1422.     char *cmd;
  1423. {
  1424.     int inp;
  1425.  
  1426.     /*
  1427.      * Print the command which is to be executed,
  1428.      * unless the command starts with a "-".
  1429.      */
  1430.     if (cmd[0] == '-')
  1431.         cmd++;
  1432.     else
  1433.     {
  1434.         lower_left();
  1435.         clear_eol();
  1436.         puts("!");
  1437.         puts(cmd);
  1438.         puts("\n");
  1439.     }
  1440.  
  1441.     /*
  1442.      * De-initialize the terminal and take out of raw mode.
  1443.      */
  1444.     deinit();
  1445.     flush();
  1446.     raw_mode(0);
  1447.  
  1448.     /*
  1449.      * Restore signals to their defaults.
  1450.      */
  1451.     SIGNAL(SIGINT, SIG_DFL);
  1452. #ifdef SIGTSTP
  1453.     SIGNAL(SIGTSTP, SIG_DFL);
  1454. #endif
  1455.     /*
  1456.      * Force standard input to be the terminal, "/dev/tty".
  1457.      */
  1458.     inp = dup(0);
  1459.     close(0);
  1460.     open("/dev/tty", 0);
  1461.  
  1462.     /*
  1463.      * Pass the command to the system to be executed.
  1464.      */
  1465.     system(cmd);
  1466.  
  1467.     /*
  1468.      * Restore standard input, reset signals, raw mode, etc.
  1469.      */
  1470.     close(0);
  1471.     dup(inp);
  1472.     close(inp);
  1473.  
  1474.     init_signals();
  1475.     raw_mode(1);
  1476.     init();
  1477. }
  1478.  
  1479. /*
  1480.  * Expand a filename, substituting any environment variables, etc.
  1481.  * The implementation of this is necessarily very operating system
  1482.  * dependent.  This implementation is unabashedly only for Unix systems.
  1483.  */
  1484. #if GLOB
  1485.  
  1486. #include <stdio.h>
  1487.  
  1488.     char *
  1489. glob(filename)
  1490.     char *filename;
  1491. {
  1492.     FILE *f;
  1493.     char *p;
  1494.     int ch;
  1495.     static char filebuf[128];
  1496.     static char ECHO[] = "echo ";
  1497.  
  1498.     strcpy(filebuf, ECHO);
  1499.     strtcpy(filebuf+sizeof(ECHO)-1, filename, sizeof(filebuf)-sizeof(ECHO));
  1500.     if ((f = popen(filebuf, "r")) == NULL)
  1501.         return (filename);
  1502.     for (p = filebuf;  p < &filebuf[sizeof(filebuf)-1];  p++)
  1503.     {
  1504.         if ((ch = getc(f)) == '\n' || ch == EOF)
  1505.             break;
  1506.         *p = ch;
  1507.     }
  1508.     *p = '\0';
  1509.     pclose(f);
  1510.     return (filebuf);
  1511. }
  1512.  
  1513. #else
  1514.  
  1515.     char *
  1516. glob(filename)
  1517.     char *filename;
  1518. {
  1519.     return (filename);
  1520. }
  1521.  
  1522. #endif
  1523. _SHAR_EOF_
  1524.  
  1525. echo help.c
  1526. cat >help.c <<'_SHAR_EOF_'
  1527. #include  "less.h"
  1528.  
  1529. /*
  1530.  * Display some help.
  1531.  * Just invoke another "less" to display the help file.
  1532.  *
  1533.  * {{ This makes this function very simple, and makes changing the
  1534.  *    help file very easy, but it may present difficulties on
  1535.  *    (non-Unix) systems which do not supply the "system()" function. }}
  1536.  */
  1537.  
  1538.     public void
  1539. help()
  1540. {
  1541.     char cmd[200];
  1542.  
  1543.     sprintf(cmd, 
  1544.      "-less -m '-Pm<HELP -- Press RETURN for more, or q when done >' %s",
  1545.      HELPFILE);
  1546.     lsystem(cmd);
  1547.     error("End of help");
  1548. }
  1549. _SHAR_EOF_
  1550.  
  1551. echo ttyin.c
  1552. cat >ttyin.c <<'_SHAR_EOF_'
  1553. /*
  1554.  * Routines dealing with getting input from the keyboard (i.e. from the user).
  1555.  */
  1556.  
  1557. #include "less.h"
  1558.  
  1559. /*
  1560.  * The boolean "reading" is set true or false according to whether
  1561.  * we are currently reading from the keyboard.
  1562.  * This information is used by the signal handling stuff in signal.c.
  1563.  * {{ There are probably some race conditions here
  1564.  *    involving the variable "reading". }}
  1565.  */
  1566. public int reading;
  1567.  
  1568. static int tty;
  1569.  
  1570. /*
  1571.  * Open keyboard for input.
  1572.  * (Just use file descriptor 2.)
  1573.  */
  1574.     public void
  1575. open_getc()
  1576. {
  1577.     tty = 2;
  1578. }
  1579.  
  1580. /*
  1581.  * Get a character from the keyboard.
  1582.  */
  1583.     public int
  1584. getc()
  1585. {
  1586.     char c;
  1587.     int result;
  1588.  
  1589.     reading = 1;
  1590.     do
  1591.     {
  1592.         flush();
  1593.         result = read(tty, &c, 1);
  1594.     } while (result != 1);
  1595.     reading = 0;
  1596.     return (c & 0177);
  1597. }
  1598. _SHAR_EOF_
  1599.  
  1600. echo command.c
  1601. cat >command.c <<'_SHAR_EOF_'
  1602. /*
  1603.  * User-level command processor.
  1604.  */
  1605.  
  1606. #include "less.h"
  1607. #include "position.h"
  1608. #include <setjmp.h>
  1609.  
  1610. extern jmp_buf main_loop;
  1611. extern int erase_char, kill_char;
  1612. extern int pr_type;
  1613. extern int sigs;
  1614. extern int ispipe;
  1615. extern int quit_at_eof;
  1616. extern int hit_eof;
  1617. extern int sc_width, sc_height;
  1618. extern int sc_window;
  1619. extern char *first_cmd;
  1620. extern char *every_first_cmd;
  1621. extern char version[];
  1622. extern char current_file[];
  1623. extern char *editor;
  1624.  
  1625. static char cmdbuf[90];        /* Buffer for holding a multi-char command */
  1626. static char *cp;        /* Pointer into cmdbuf */
  1627. static int cmd_col;        /* Current column of the multi-char command */
  1628. static char mcc;        /* The multi-char command letter (e.g. '/') */
  1629. static char last_mcc;        /* The previous mcc */
  1630. static int screen_trashed;    /* The screen has been overwritten */
  1631.  
  1632. /*
  1633.  * Reset command buffer (to empty).
  1634.  */
  1635. cmd_reset()
  1636. {
  1637.     cp = cmdbuf;
  1638. }
  1639.  
  1640. /*
  1641.  * Backspace in command buffer.
  1642.  */
  1643.     static int
  1644. cmd_erase()
  1645. {
  1646.     if (cp == cmdbuf)
  1647.         /*
  1648.          * Backspace past beginning of the string:
  1649.          * this usually means abort the command.
  1650.          */
  1651.         return (1);
  1652.  
  1653.     if (control_char(*--cp))
  1654.     {
  1655.         /*
  1656.          * Erase an extra character, for the carat.
  1657.          */
  1658.         backspace();
  1659.         cmd_col--;
  1660.     }
  1661.     backspace();
  1662.     cmd_col--;
  1663.     return (0);
  1664. }
  1665.  
  1666. /*
  1667.  * Set up the display to start a new multi-character command.
  1668.  */
  1669. start_mcc(c)
  1670.     int c;
  1671. {
  1672.     mcc = c;
  1673.     lower_left();
  1674.     clear_eol();
  1675.     putc(mcc);
  1676.     cmd_col = 1;
  1677. }
  1678.  
  1679. /*
  1680.  * Process a single character of a multi-character command, such as
  1681.  * a number, or the pattern of a search command.
  1682.  */
  1683.     static int
  1684. cmd_char(c)
  1685.     int c;
  1686. {
  1687.     if (c == erase_char)
  1688.     {
  1689.         if (cmd_erase())
  1690.             return (1);
  1691.     } else if (c == kill_char)
  1692.     {
  1693.         /* {{ Could do this faster, but who cares? }} */
  1694.         while (cmd_erase() == 0)
  1695.             ;
  1696.     } else
  1697.     {
  1698.         /*
  1699.          * Append the character to the string,
  1700.          * if there is room in the buffer and on the screen.
  1701.          */
  1702.         if (cp < &cmdbuf[sizeof(cmdbuf)-1] && cmd_col < sc_width-3)
  1703.         {
  1704.             *cp++ = c;
  1705.             if (control_char(c))
  1706.             {
  1707.                 putc('^');
  1708.                 cmd_col++;
  1709.                 c = carat_char(c);
  1710.             }
  1711.             putc(c);
  1712.             cmd_col++;
  1713.         } else
  1714.             bell();
  1715.     }
  1716.     return (0);
  1717. }
  1718.  
  1719. /*
  1720.  * Return the number currently in the command buffer.
  1721.  */
  1722.     static int
  1723. cmd_int()
  1724. {
  1725.     *cp = '\0';
  1726.     cp = cmdbuf;
  1727.     return (atoi(cmdbuf));
  1728. }
  1729.  
  1730. /*
  1731.  * Move the cursor to lower left before executing a command.
  1732.  * This looks nicer if the command takes a long time before
  1733.  * updating the screen.
  1734.  */
  1735.     static void
  1736. cmd_exec()
  1737. {
  1738.     lower_left();
  1739.     flush();
  1740. }
  1741.  
  1742. /*
  1743.  * Display the appropriate prompt.
  1744.  */
  1745.     static void
  1746. prompt()
  1747. {
  1748.     register char *p;
  1749.  
  1750.     if (first_cmd != NULL && *first_cmd != '\0')
  1751.         /*
  1752.          * No prompt necessary if commands are from first_cmd
  1753.          * rather than from the user.
  1754.          */
  1755.         return;
  1756.  
  1757.     /*
  1758.      * If nothing is displayed yet, display starting from line 1.
  1759.      */
  1760.     if (position(TOP) == NULL_POSITION)
  1761.         jump_back(1);
  1762.     else if (screen_trashed)
  1763.         repaint();
  1764.     screen_trashed = 0;
  1765.  
  1766.     /*
  1767.      * Select the proper prompt and display it.
  1768.      */
  1769.     lower_left();
  1770.     clear_eol();
  1771.     p = pr_string();
  1772.     if (p == NULL)
  1773.         putc(':');
  1774.     else
  1775.     {
  1776.         so_enter();
  1777.         puts(p);
  1778.         so_exit();
  1779.     }
  1780. }
  1781.  
  1782. /*
  1783.  * Get command character.
  1784.  * The character normally comes from the keyboard,
  1785.  * but may come from the "first_cmd" string.
  1786.  */
  1787.     static int
  1788. getcc()
  1789. {
  1790.     if (first_cmd == NULL)
  1791.         return (getc());
  1792.  
  1793.     if (*first_cmd == '\0')
  1794.     {
  1795.         /*
  1796.          * Reached end of first_cmd input.
  1797.          */
  1798.         first_cmd = NULL;
  1799.         if (cp > cmdbuf && position(TOP) == NULL_POSITION)
  1800.         {
  1801.             /*
  1802.              * Command is incomplete, so try to complete it.
  1803.              * There are only two cases:
  1804.              * 1. We have "/string" but no newline.  Add the \n.
  1805.              * 2. We have a number but no command.  Treat as #g.
  1806.              * (This is all pretty hokey.)
  1807.              */
  1808.             if (mcc != ':')
  1809.                 /* Not a number; must be search string */
  1810.                 return ('\n'); 
  1811.             else
  1812.                 /* A number; append a 'g' */
  1813.                 return ('g');
  1814.         }
  1815.         return (getc());
  1816.     }
  1817.     return (*first_cmd++);
  1818. }
  1819.  
  1820. /*
  1821.  * Main command processor.
  1822.  * Accept and execute commands until a quit command, then return.
  1823.  */
  1824.     public void
  1825. commands()
  1826. {
  1827.     register int c;
  1828.     register int n;
  1829.     register int scroll = 10;
  1830.  
  1831.     last_mcc = 0;
  1832.     setjmp(main_loop);
  1833.     mcc = 0;
  1834.  
  1835.     for (;;)
  1836.     {
  1837.         /*
  1838.          * Display prompt and accept a character.
  1839.          */
  1840.         psignals();    /* See if any signals need processing */
  1841.  
  1842.         if (quit_at_eof && hit_eof > 1)
  1843.             /*
  1844.              * After hitting end-of-file for the second time,
  1845.              * automatically advance to the next file.
  1846.              * If there are no more files, quit.
  1847.              */
  1848.             next_file(1);
  1849.  
  1850.         cmd_reset();
  1851.         prompt();
  1852.         c = getcc();
  1853.  
  1854.     again:
  1855.         if (sigs)
  1856.             continue;
  1857.  
  1858.         if (mcc)
  1859.         {
  1860.             /*
  1861.              * We are in a multi-character command.  
  1862.              * All chars until newline go into the command buffer.
  1863.              * (Note that mcc == ':' is a special case that
  1864.              *  means a number is being entered.)
  1865.              */
  1866.             if (mcc != ':' && (c == '\n' || c == '\r'))
  1867.             {
  1868.                 char *p;
  1869.                 static char fcbuf[100];
  1870.  
  1871.                 /*
  1872.                  * Execute the command.
  1873.                  */
  1874.                 *cp = '\0';
  1875.                 cmd_exec();
  1876.                 switch (mcc)
  1877.                 {
  1878.                 case '/': case '?':
  1879.                     search(mcc, cmdbuf, n);
  1880.                     break;
  1881.                 case '+':
  1882.                     for (p = cmdbuf;  *p == '+' || *p == ' ';  p++) ;
  1883.                     if (*p == '\0')
  1884.                         every_first_cmd = NULL;
  1885.                     else
  1886.                     {
  1887.                         strtcpy(fcbuf, p, sizeof(fcbuf));
  1888.                         every_first_cmd = fcbuf;
  1889.                     }
  1890.                     break;
  1891.                 case 'E':
  1892.                     /*
  1893.                      * Ignore leading spaces 
  1894.                      * in the filename.
  1895.                      */
  1896.                     for (p = cmdbuf;  *p == ' ';  p++) ;
  1897.                     edit(glob(p));
  1898.                     break;
  1899. #if SHELL_ESCAPE
  1900.                 case '!':
  1901.                     lsystem(cmdbuf);
  1902.                     screen_trashed = 1;
  1903.                     error("!done");
  1904.                     break;
  1905. #endif
  1906.                 }
  1907.                 mcc = 0;
  1908.             } else
  1909.             {
  1910.                 if (mcc == ':' && (c < '0' || c > '9') &&
  1911.                     c != erase_char && c != kill_char)
  1912.                 {
  1913.                     /*
  1914.                      * This is not part of the number
  1915.                      * we were entering.  Process
  1916.                      * it as a regular character.
  1917.                      */
  1918.                     mcc = 0;
  1919.                     goto again;
  1920.                 }
  1921.  
  1922.                 /*
  1923.                  * Append the char to the command buffer.
  1924.                  */
  1925.                 if (cmd_char(c))
  1926.                 {
  1927.                     /* Abort the multi-char command. */
  1928.                     mcc = 0;
  1929.                     continue;
  1930.                 }
  1931.                 c = getcc();
  1932.                 goto again;
  1933.             }
  1934.         } else switch (c)
  1935.         {
  1936.         case '0': case '1': case '2': case '3': case '4':
  1937.         case '5': case '6': case '7': case '8': case '9':
  1938.             /*
  1939.              * First digit of a number.
  1940.              */
  1941.             start_mcc(':');
  1942.             goto again;
  1943.  
  1944.         case 'f':
  1945.         case ' ':
  1946.         case CONTROL('F'):
  1947.             /*
  1948.              * Forward one screen.
  1949.              */
  1950.             n = cmd_int();
  1951.             if (n <= 0)
  1952.                 n = sc_window;
  1953.             forward(n, 1);
  1954.             break;
  1955.  
  1956.         case 'b':
  1957.         case CONTROL('B'):
  1958.             /*
  1959.              * Backward one screen.
  1960.              */
  1961.             n = cmd_int();
  1962.             if (n <= 0)
  1963.                 n = sc_window;
  1964.             backward(n, 1);
  1965.             break;
  1966.  
  1967.         case 'e':
  1968.         case 'j':
  1969.         case '\r':
  1970.         case '\n':
  1971.         case CONTROL('E'):
  1972.             /*
  1973.              * Forward N (default 1) line.
  1974.              */
  1975.             n = cmd_int();
  1976.             if (n <= 0)
  1977.                 n = 1;
  1978.             forward(n, 0);
  1979.             break;
  1980.  
  1981.         case 'y':
  1982.         case 'k':
  1983.         case CONTROL('K'):
  1984.         case CONTROL('Y'):
  1985.             /*
  1986.              * Backward N (default 1) line.
  1987.              */
  1988.             n = cmd_int();
  1989.             if (n <= 0)
  1990.                 n = 1;
  1991.             backward(n, 0);
  1992.             break;
  1993.  
  1994.         case 'd':
  1995.         case CONTROL('D'):
  1996.             /*
  1997.              * Forward N lines 
  1998.              * (default same as last 'd' or 'u' command).
  1999.              */
  2000.             n = cmd_int();
  2001.             if (n > 0)
  2002.                 scroll = n;
  2003.             forward(scroll, 0);
  2004.             break;
  2005.  
  2006.         case 'u':
  2007.         case CONTROL('U'):
  2008.             /*
  2009.              * Forward N lines 
  2010.              * (default same as last 'd' or 'u' command).
  2011.              */
  2012.             n = cmd_int();
  2013.             if (n > 0)
  2014.                 scroll = n;
  2015.             backward(scroll, 0);
  2016.             break;
  2017.  
  2018.         case 'R':
  2019.             /*
  2020.              * Flush buffers, then repaint screen.
  2021.              * Don't flush the buffers on a pipe!
  2022.              */
  2023.             if (!ispipe)
  2024.                 ch_init(0);
  2025.             /* Fall thru */
  2026.         case 'r':
  2027.         case CONTROL('R'):
  2028.         case CONTROL('L'):
  2029.             /*
  2030.              * Repaint screen.
  2031.              */
  2032.             repaint();
  2033.             break;
  2034.  
  2035.         case 'g':
  2036.             /*
  2037.              * Go to line N, default beginning of file.
  2038.              */
  2039.             n = cmd_int();
  2040.             if (n <= 0)
  2041.                 n = 1;
  2042.             cmd_exec();
  2043.             jump_back(n);
  2044.             break;
  2045.  
  2046.         case 'p':
  2047.         case '%':
  2048.             /*
  2049.              * Go to a specified percentage into the file.
  2050.              */
  2051.             n = cmd_int();
  2052.             if (n < 0)
  2053.                 n = 0;
  2054.             if (n > 100)
  2055.                 n = 100;
  2056.             cmd_exec();
  2057.             jump_percent(n);
  2058.             break;
  2059.  
  2060.         case 'G':
  2061.             /*
  2062.              * Go to line N, default end of file.
  2063.              */
  2064.             n = cmd_int();
  2065.             cmd_exec();
  2066.             if (n <= 0)
  2067.                 jump_forw();
  2068.             else
  2069.                 jump_back(n);
  2070.             break;
  2071.  
  2072.         case '=':
  2073.         case CONTROL('G'):
  2074.             /*
  2075.              * Print file name, etc.
  2076.              */
  2077.             error(eq_message());
  2078.             break;
  2079.             
  2080.         case 'V':
  2081.             /*
  2082.              * Print version number, without the "@(#)".
  2083.              */
  2084.             error(version+4);
  2085.             break;
  2086.  
  2087.         case 'q':
  2088.             /*
  2089.              * Exit.
  2090.              */
  2091.             /*setjmp(main_loop);*/
  2092.             quit();
  2093.  
  2094.         case '/':
  2095.         case '?':
  2096.             /*
  2097.              * Search for a pattern.
  2098.              * Accept chars of the pattern until \n.
  2099.              */
  2100.             n = cmd_int();
  2101.             if (n <= 0)
  2102.                 n = 1;
  2103.             start_mcc(c);
  2104.             last_mcc = c;
  2105.             c = getcc();
  2106.             goto again;
  2107.  
  2108.         case 'n':
  2109.             /*
  2110.              * Repeat previous search.
  2111.              */
  2112.             n = cmd_int();
  2113.             if (n <= 0)
  2114.                 n = 1;
  2115.             start_mcc(last_mcc);
  2116.             cmd_exec();
  2117.             search(mcc, (char *)NULL, n);
  2118.             mcc = 0;
  2119.             break;
  2120.  
  2121.         case 'h':
  2122.             /*
  2123.              * Help.
  2124.              */
  2125.             lower_left();
  2126.             clear_eol();
  2127.             puts("help");
  2128.             cmd_exec();
  2129.             help();
  2130.             screen_trashed = 1;
  2131.             break;
  2132.  
  2133.         case 'E':
  2134.             /*
  2135.              * Edit a new file.  Get the filename.
  2136.              */
  2137.             cmd_reset();
  2138.             start_mcc('E');
  2139.             puts("xamine: ");    /* This looks nicer */
  2140.             cmd_col += 8;
  2141.             c = getcc();
  2142.             goto again;
  2143.             
  2144.         case '!':
  2145. #if SHELL_ESCAPE
  2146.             /*
  2147.              * Shell escape.
  2148.              */
  2149.             cmd_reset();
  2150.             start_mcc('!');
  2151.             c = getcc();
  2152.             goto again;
  2153. #else
  2154.             error("Command not available");
  2155.             break;
  2156. #endif
  2157.  
  2158.         case 'v':
  2159. #if EDITOR
  2160.             if (ispipe)
  2161.             {
  2162.                 error("Cannot edit standard input");
  2163.                 break;
  2164.             }
  2165.             sprintf(cmdbuf, "%s %s", editor, current_file);
  2166.             lsystem(cmdbuf);
  2167.             ch_init(0);
  2168.             screen_trashed = 1;
  2169.             break;
  2170. #else
  2171.             error("Command not available");
  2172.             break;
  2173. #endif
  2174.  
  2175.         case 'N':
  2176.             /*
  2177.              * Examine next file.
  2178.              */
  2179.             n = cmd_int();
  2180.             if (n <= 0)
  2181.                 n = 1;
  2182.             next_file(n);
  2183.             break;
  2184.  
  2185.         case 'P':
  2186.             /*
  2187.              * Examine previous file.
  2188.              */
  2189.             n = cmd_int();
  2190.             if (n <= 0)
  2191.                 n = 1;
  2192.             prev_file(n);
  2193.             break;
  2194.  
  2195.         case '-':
  2196.             /*
  2197.              * Toggle a flag setting.
  2198.              */
  2199.             start_mcc('-');
  2200.             c = getcc();
  2201.             mcc = 0;
  2202.             if (c == erase_char || c == kill_char)
  2203.                 break;
  2204.             toggle_option(c);
  2205.             break;
  2206.  
  2207.         case '+':
  2208.             cmd_reset();
  2209.             start_mcc('+');
  2210.             c = getcc();
  2211.             goto again;
  2212.  
  2213.         case 'm':
  2214.             /*
  2215.              * Set a mark.
  2216.              */
  2217.             lower_left();
  2218.             clear_eol();
  2219.             puts("mark: ");
  2220.             c = getcc();
  2221.             if (c == erase_char || c == kill_char)
  2222.                 break;
  2223.             setmark(c);
  2224.             break;
  2225.  
  2226.         case '\'':
  2227.             /*
  2228.              * Go to a mark.
  2229.              */
  2230.             lower_left();
  2231.             clear_eol();
  2232.             puts("goto mark: ");
  2233.             c = getcc();
  2234.             if (c == erase_char || c == kill_char)
  2235.                 break;
  2236.             gomark(c);
  2237.             break;
  2238.  
  2239.         default:
  2240.             bell();
  2241.             break;
  2242.         }
  2243.     }
  2244. }
  2245. _SHAR_EOF_
  2246.  
  2247. echo version.c
  2248. cat >version.c <<'_SHAR_EOF_'
  2249. /*
  2250.  *        less
  2251.  *    Copyright (c) 1984,1985  Mark Nudelman
  2252.  *
  2253.  *    This program may be freely used and/or modified, 
  2254.  *    with the following provisions:
  2255.  *    1. This notice and the above copyright notice must remain intact.
  2256.  *    2. Neither this program, nor any modification of it,
  2257.  *       may be sold for profit without written consent of the author.
  2258.  *
  2259.  *    -----------------------------------------------------------------
  2260.  *
  2261.  *    This program is a paginator similar to "more", 
  2262.  *    but allows you to move both forward and backward in the file.  
  2263.  *    Commands are based on "more" and "vi".
  2264.  *
  2265.  *    ----------------------- CHANGES ---------------------------------
  2266.  *
  2267.  *        Allowed use on standard input        1/29/84   markn
  2268.  *        Added E, N, P commands            2/1/84    markn
  2269.  *        Added '=' command, 'stop' signal handling    4/17/84   markn
  2270.  *        Added line folding                4/20/84   markn
  2271.  *    v2: Fixed '=' command to use BOTTOM_PLUS_ONE, 
  2272.  *        instead of TOP, added 'p' & 'v' commands    4/27/84   markn
  2273.  *    v3: Added -m and -t options, '-' command    5/3/84    markn
  2274.  *    v4: Added LESS environment variable        5/3/84    markn
  2275.  *    v5: New comments, fixed '-' command slightly    5/3/84    markn
  2276.  *    v6: Added -Q, visual bell            5/15/84   markn
  2277.  *    v7: Fixed jump_back(n) bug: n should count real
  2278.  *        lines, not folded lines.  Also allow number
  2279.  *        on G command.                5/24/84   markn
  2280.  *    v8: Re-do -q and -Q commands            5/30/84   markn
  2281.  *    v9: Added "+<cmd>" argument            9/25/84   markn
  2282.  *    v10: Fixed bug in -b<n> argument processing    10/10/84  markn
  2283.  *    v11: Made error() ring bell if \n not entered.    10/18/84  markn
  2284.  *    -----------------------------------------------------------------
  2285.  *    v12: Reorganized signal handling and made
  2286.  *         portable to 4.2bsd.            2/13/85   mark
  2287.  *    v13: Reword error message for '-' command.    2/16/85   mark
  2288.  *    v14: Added -bf and -bp variants of -b.        2/22/85   mark
  2289.  *    v15: Miscellaneous changes.            2/25/85   mark
  2290.  *    v16: Added -u flag for backspace processing.    3/13/85   mark
  2291.  *    v17: Added j and k commands, 
  2292.  *        changed -t default.            4/13/85   mark
  2293.  *    v18: Rewrote signal handling code.        4/20/85   mark
  2294.  *    v19: Got rid of "verbose" eq_message().        5/2/85    mark
  2295.  *         Made search() scroll in some cases.
  2296.  *    v20: Fixed screen.c ioctls for System V.    5/21/85   mark
  2297.  *    v21: Fixed some first_cmd bugs.            5/23/85   mark
  2298.  *    v22: Added support for no RECOMP nor REGCMP.    5/24/85   mark
  2299.  *     v23: Miscellanous changes and prettying up.    5/25/85   mark
  2300.  *        Posted to USENET.
  2301.  *      v24: Added ti,te terminal init & de-init       6/3/85 Mike Kersenbrock
  2302.  *    v25: Added -U flag, standout mode underlining.    6/8/85    mark
  2303.  *    v26: Added -M flag.                6/9/85    mark
  2304.  *         Use underline termcap (us) if it exists.
  2305.  *    v27: Renamed some variables to make unique in    6/15/85   mark
  2306.  *         6 chars.  Minor fix to -m.
  2307.  *    v28: Fixed right margin bug.            6/28/85   mark
  2308.  *    v29: Incorporated M.Rose's changes to signal.c    6/28/85   mark
  2309.  *    v30: Fixed stupid bug in argument processing.    6/29/85   mark
  2310.  *    v31: Added -p flag, changed repaint algorithm.  7/15/85   mark
  2311.  *         Added kludge for magic cookie terminals.
  2312.  *    v32: Added cat_file if output not a tty.    7/16/85   mark
  2313.  *    v33: Added -e flag and EDITOR.            7/23/85   mark
  2314.  *    v34: Added -s flag.                7/26/85   mark
  2315.  *    v35: Rewrote option handling; added option.c.    7/27/85   mark
  2316.  *    v36: Fixed -e flag to work if not last file.    7/29/85   mark
  2317.  *    v37: Added -x flag.                8/10/85   mark
  2318.  *    v38: Changed prompting; created prompt.c.    8/19/85   mark
  2319.  *    v39: (Not -p) does not initially clear screen.    8/24/85   mark
  2320.  *    v40: Added "skipping" indicator in forw().    8/26/85   mark
  2321.  *        Posted to USENET.
  2322.  *    v41: ONLY_RETURN, control char commands,    9/17/85   mark
  2323.  *         faster search, other minor fixes.
  2324.  *    v42: Added ++ command line syntax;        9/25/85   mark
  2325.  *         ch_fsize for pipes.
  2326.  *    v43: Added -h flag, changed prim.c algorithms.    10/15/85  mark
  2327.  *    v44: Made END print in all cases of eof;    10/16/85  mark
  2328.  *         ignore SIGTTOU after receiving SIGTSTP.
  2329.  *    v45: Never print backspaces unless -u.        10/16/85  mark
  2330.  *    v46: Backwards scroll in jump_loc.        10/24/85  mark
  2331.  *    v47: Fixed bug in edit(): *first_cmd==0        10/30/85  mark
  2332.  *    v48: Use TIOCSETN instead of TIOCSETP.        11/16/85  mark
  2333.  *         Added marks (m and ' commands).
  2334.  *        Posted to USENET.
  2335.  *    -----------------------------------------------------------------
  2336.  *    v49: Fixed bug: signal didn't clear mcc.    1/9/86    mark
  2337.  *    v50: Added ' (quote) to gomark.            1/15/86   mark
  2338.  *    v51: Added + cmd, fixed problem if first_cmd
  2339.  *         fails, made g cmd sort of "work" on pipes
  2340.  *         even if bof is no longer buffered.        1/16/86   mark
  2341.  *    v52: Made short files work better.        1/17/86   mark
  2342.  *    v53: Added -P option.                1/20/86   mark
  2343.  *    v54: Changed help to use HELPFILE.        1/20/86   mark
  2344.  *    v55: Messages work better if not tty output.    1/23/86   mark
  2345.  *    v56: Added -l option.                1/24/86   mark
  2346.  *    v57: Fixed -l to get confirmation before
  2347.  *         overwriting an existing file.        1/31/86   mark
  2348.  *    v58: Added filename globbing.            8/28/86   mark
  2349.  *    v59: Fixed some bugs with very long filenames.    9/15/86   mark
  2350.  *    v60: Incorporated changes from Leith (Casey)
  2351.  *         Leedom for boldface and -z option.        9/26/86   mark
  2352.  *    v61: Got rid of annoying repaints after ! cmd.    9/26/86   mark
  2353.  *    -----------------------------------------------------------------
  2354.  */
  2355.  
  2356. char version[] = "@(#) less  version 61";
  2357. _SHAR_EOF_
  2358.  
  2359.  
  2360.  
  2361.