home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume11 / less3 / part01 next >
Encoding:
Text File  |  1987-09-01  |  60.4 KB  |  2,915 lines

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