home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #3 / NN_1993_3.iso / spool / comp / bugs / 2bsd / 113 next >
Encoding:
Internet Message Format  |  1993-01-25  |  138.1 KB

  1. Path: sparky!uunet!ogicse!emory!sol.ctr.columbia.edu!howland.reston.ans.net!europa.asd.contel.com!wlbr!sms
  2. From: sms@WLV.IIPO.GTEGSC.COM (Steven M. Schultz)
  3. Newsgroups: comp.bugs.2bsd
  4. Subject: 'less' for 2.11BSD (#101)
  5. Message-ID: <1993Jan25.182911.19307@wlbr.iipo.gtegsc.com>
  6. Date: 25 Jan 93 18:29:11 GMT
  7. Article-I.D.: wlbr.1993Jan25.182911.19307
  8. Sender: news@wlbr.iipo.gtegsc.com (news)
  9. Organization: GTE Government Systems
  10. Lines: 6344
  11. Nntp-Posting-Host: wlv.iipo.gtegsc.com
  12.  
  13. Subject: 'less' for 2.11BSD (#101)
  14. Index:    local/less 2.11BSD
  15.  
  16. Description:
  17.     A new program being installed in the source tree.
  18.  
  19.     Thanks to Paul Taylor (taylor@oswego.oswego.edu) for doing the port.
  20.  
  21. Repeat-By:
  22.     N/A.
  23.  
  24. Fix:
  25.     Cut at the indicated line, unpack the shar file, cd /usr/src/local/less
  26.     and "make all; make install".
  27. ================================cut here=====================================
  28. #! /bin/sh
  29. # This is a shell archive, meaning:
  30. # 1. Remove everything above the #! /bin/sh line.
  31. # 2. Save the resulting text in a file.
  32. # 3. Execute the file with /bin/sh (not csh) to create:
  33. #    /usr/src/local/less
  34. # This archive created: Mon Jan 25 09:27:56 1993
  35. export PATH; PATH=/bin:/usr/bin:$PATH
  36. if test ! -d '/usr/src/local/less'
  37. then
  38.     mkdir '/usr/src/local/less'
  39. fi
  40. cd '/usr/src/local/less'
  41. if test -f 'README'
  42. then
  43.     echo shar: "will not over-write existing file 'README'"
  44. else
  45. sed 's/^X//' << \SHAR_EOF > 'README'
  46. XThis is the distribution of "less", a paginator similar to "more" or "pg".
  47. XThe manual page is in less.man (nroff source in less.nro).
  48. X
  49. XINSTALLATION:
  50. X
  51. X1. Move the distributed source to its own directory and 
  52. X   unpack it by running "sh" on the distribution file,
  53. X   if you have not already done so.
  54. X
  55. X2. Type "install" and answer the questions it asks.
  56. X   This will generate a makefile.
  57. X
  58. X   If you choose not to include some features in your version,
  59. X   you may wish to edit the manual page less.nro and/or less.man
  60. X   to remove the references to the appropriate commands or options.
  61. X
  62. X   (NOTE: there are some pre-generated makefiles for
  63. X    various systems, named makefile.sys5, makefile.bsd41,
  64. X    etc. which may be used if you wish.)
  65. X
  66. X3. It is a good idea to look over the generated makefile 
  67. X   and make sure it looks ok.
  68. X
  69. X4. Type "make" and watch the fun.
  70. X
  71. X5. If the make succeeds, it will generate a program "less"
  72. X   in your current directory.  Test the generated program.
  73. X
  74. X6. When satisfied that it works, if you wish to install it
  75. X   in a public place, type "make install".
  76. X
  77. XIf you have any problems building or running "less", 
  78. Xsuggestions, complaints, etc., you may mail to the 
  79. Xauthor via USENET at:
  80. X    tektronix!nscpdc!convgt!mark
  81. X  or    ihnp4!nsc!nscpdc!convgt!mark
  82. X
  83. XNote to hackers: comments noting possible improvements are enclosed
  84. Xin double curly brackets {{ like this }}.
  85. SHAR_EOF
  86. fi
  87. if test -f 'ch.c'
  88. then
  89.     echo shar: "will not over-write existing file 'ch.c'"
  90. else
  91. sed 's/^X//' << \SHAR_EOF > 'ch.c'
  92. X/*
  93. X * Low level character input from the input file.
  94. X * We use these special purpose routines which optimize moving
  95. X * both forward and backward from the current read pointer.
  96. X */
  97. X
  98. X#include "less.h"
  99. X
  100. Xpublic int file = -1;    /* File descriptor of the input file */
  101. X
  102. X/*
  103. X * Pool of buffers holding the most recently used blocks of the input file.
  104. X */
  105. X#define BUFSIZ    1024
  106. Xstruct buf {
  107. X    struct buf *next, *prev;
  108. X    long block;
  109. X    char data[BUFSIZ];
  110. X};
  111. Xstatic struct buf *bufs = NULL;
  112. Xpublic int nbufs;
  113. X
  114. X/*
  115. X * The buffer pool is kept as a doubly-linked circular list,
  116. X * in order from most- to least-recently used.
  117. X * The circular list is anchored by buf_anchor.
  118. X */
  119. Xstatic struct {
  120. X    struct buf *next, *prev;
  121. X} buf_anchor;
  122. X#define    END_OF_CHAIN    ((struct buf *)&buf_anchor)
  123. X#define    buf_head    buf_anchor.next
  124. X#define    buf_tail    buf_anchor.prev
  125. X
  126. X/*
  127. X * If we fail to allocate enough memory for buffers, we try to limp
  128. X * along with a minimum number of buffers.  
  129. X */
  130. X#define    DEF_NBUFS    2    /* Minimum number of buffers */
  131. X
  132. Xextern int clean_data;
  133. Xextern int ispipe;
  134. Xextern int sigs;
  135. X
  136. X#if LOGFILE
  137. Xextern int logfile;
  138. X#endif
  139. X
  140. X/*
  141. X * Current position in file.
  142. X * Stored as a block number and an offset into the block.
  143. X */
  144. Xstatic long ch_block;
  145. Xstatic int ch_offset;
  146. X
  147. X/* 
  148. X * Length of file, needed if input is a pipe.
  149. X */
  150. Xstatic POSITION ch_fsize;
  151. X
  152. X/*
  153. X * Largest block number read if input is standard input (a pipe).
  154. X */
  155. Xstatic long last_piped_block;
  156. X
  157. X/*
  158. X * Get the character pointed to by the read pointer.
  159. X * ch_get() is a macro which is more efficient to call
  160. X * than fch_get (the function), in the usual case 
  161. X * that the block desired is at the head of the chain.
  162. X */
  163. X#define    ch_get()   ((buf_head->block == ch_block) ? \
  164. X            buf_head->data[ch_offset] : fch_get())
  165. X    static int
  166. Xfch_get()
  167. X{
  168. X    register struct buf *bp;
  169. X    register int n;
  170. X    register int end;
  171. X    POSITION pos;
  172. X
  173. X    /*
  174. X     * Look for a buffer holding the desired block.
  175. X     */
  176. X    for (bp = buf_head;  bp != END_OF_CHAIN;  bp = bp->next)
  177. X        if (bp->block == ch_block)
  178. X            goto found;
  179. X    /*
  180. X     * Block is not in a buffer.  
  181. X     * Take the least recently used buffer 
  182. X     * and read the desired block into it.
  183. X     */
  184. X    bp = buf_tail;
  185. X    bp->block = ch_block;
  186. X    pos = ch_block * BUFSIZ;
  187. X    if (ispipe)
  188. X    {
  189. X        /*
  190. X         * The block requested should be one more than
  191. X         * the last block read.
  192. X         */
  193. X        if (ch_block != ++last_piped_block)
  194. X        {
  195. X            /* This "should not happen". */
  196. X            char message[80];
  197. X            sprintf(message, "Pipe error: last %ld, want %ld\n",
  198. X                (long)last_piped_block-1, (long)ch_block);
  199. X            error(message);
  200. X            quit();
  201. X        }
  202. X    } else
  203. X        lseek(file, pos, 0);
  204. X
  205. X    /*
  206. X     * Read the block.  This may take several reads if the input
  207. X     * is coming from standard input, due to the nature of pipes.
  208. X     */
  209. X    end = 0;
  210. X    while ((n = read(file, &bp->data[end], BUFSIZ-end)) > 0)
  211. X        if ((end += n) >= BUFSIZ)
  212. X            break;
  213. X
  214. X    if (n < 0)
  215. X    {
  216. X        error("read error");
  217. X        quit();
  218. X    }
  219. X
  220. X#if LOGFILE
  221. X    /*
  222. X     * If we have a log file, write this block to it.
  223. X     */
  224. X    if (logfile >= 0 && end > 0)
  225. X        write(logfile, bp->data, end);
  226. X#endif
  227. X
  228. X    /*
  229. X     * Set an EOF marker in the buffered data itself.
  230. X     * Then ensure the data is "clean": there are no 
  231. X     * extra EOF chars in the data and that the "meta"
  232. X     * bit (the 0200 bit) is reset in each char.
  233. X     */
  234. X    if (end < BUFSIZ)
  235. X    {
  236. X        ch_fsize = pos + end;
  237. X        bp->data[end] = EOF;
  238. X    }
  239. X
  240. X    if (!clean_data)
  241. X        while (--end >= 0)
  242. X        {
  243. X            bp->data[end] &= 0177;
  244. X            if (bp->data[end] == EOF)
  245. X                bp->data[end] = '@';
  246. X        }
  247. X
  248. X    found:
  249. X    /* if (buf_head != bp) {this is guaranteed by the ch_get macro} */
  250. X    {
  251. X        /*
  252. X         * Move the buffer to the head of the buffer chain.
  253. X         * This orders the buffer chain, most- to least-recently used.
  254. X         */
  255. X        bp->next->prev = bp->prev;
  256. X        bp->prev->next = bp->next;
  257. X
  258. X        bp->next = buf_head;
  259. X        bp->prev = END_OF_CHAIN;
  260. X        buf_head->prev = bp;
  261. X        buf_head = bp;
  262. X    }
  263. X    return (bp->data[ch_offset]);
  264. X}
  265. X
  266. X#if LOGFILE
  267. X/*
  268. X * Close the logfile.
  269. X * If we haven't read all of standard input into it, do that now.
  270. X */
  271. X    public void
  272. Xend_logfile()
  273. X{
  274. X    static int tried;
  275. X
  276. X    if (logfile < 0)
  277. X        return;
  278. X    if (!tried && ch_fsize == NULL_POSITION)
  279. X    {
  280. X        tried = 1;
  281. X        lower_left();
  282. X        clear_eol();
  283. X        so_enter();
  284. X        puts("finishing logfile... (interrupt to abort)");
  285. X        so_exit();
  286. X        flush();
  287. X        while (sigs == 0 && ch_forw_get() != EOF)
  288. X            ;
  289. X    }
  290. X    close(logfile);
  291. X    logfile = -1;
  292. X}
  293. X#endif
  294. X
  295. X/*
  296. X * Determine if a specific block is currently in one of the buffers.
  297. X */
  298. X    static int
  299. Xbuffered(block)
  300. X    long block;
  301. X{
  302. X    register struct buf *bp;
  303. X
  304. X    for (bp = buf_head;  bp != END_OF_CHAIN;  bp = bp->next)
  305. X        if (bp->block == block)
  306. X            return (1);
  307. X    return (0);
  308. X}
  309. X
  310. X/*
  311. X * Seek to a specified position in the file.
  312. X * Return 0 if successful, non-zero if can't seek there.
  313. X */
  314. X    public int
  315. Xch_seek(pos)
  316. X    register POSITION pos;
  317. X{
  318. X    long new_block;
  319. X
  320. X    new_block = pos / BUFSIZ;
  321. X    if (!ispipe || new_block == last_piped_block + 1 || buffered(new_block))
  322. X    {
  323. X        /*
  324. X         * Set read pointer.
  325. X         */
  326. X        ch_block = new_block;
  327. X        ch_offset = pos % BUFSIZ;
  328. X        return (0);
  329. X    }
  330. X    return (1);
  331. X}
  332. X
  333. X/*
  334. X * Seek to the end of the file.
  335. X */
  336. X    public int
  337. Xch_end_seek()
  338. X{
  339. X    if (ispipe)
  340. X    {
  341. X        /*
  342. X         * Do it the slow way: read till end of data.
  343. X         */
  344. X        while (ch_forw_get() != EOF)
  345. X            ;
  346. X    } else
  347. X    {
  348. X        (void) ch_seek((POSITION)(lseek(file, (off_t)0, 2)));
  349. X    }
  350. X    return (0);
  351. X}
  352. X
  353. X/*
  354. X * Seek to the beginning of the file, or as close to it as we can get.
  355. X * We may not be able to seek there if input is a pipe and the
  356. X * beginning of the pipe is no longer buffered.
  357. X */
  358. X    public int
  359. Xch_beg_seek()
  360. X{
  361. X    register struct buf *bp, *firstbp;
  362. X
  363. X    /*
  364. X     * Try a plain ch_seek first.
  365. X     */
  366. X    if (ch_seek((POSITION)0) == 0)
  367. X        return (0);
  368. X
  369. X    /*
  370. X     * Can't get to position 0.
  371. X     * Look thru the buffers for the one closest to position 0.
  372. X     */
  373. X    firstbp = bp = buf_head;
  374. X    if (bp == END_OF_CHAIN)
  375. X        return (1);
  376. X    while ((bp = bp->next) != END_OF_CHAIN)
  377. X        if (bp->block < firstbp->block)
  378. X            firstbp = bp;
  379. X    ch_block = firstbp->block;
  380. X    ch_offset = 0;
  381. X    return (0);
  382. X}
  383. X
  384. X/*
  385. X * Return the length of the file, if known.
  386. X */
  387. X    public POSITION
  388. Xch_length()
  389. X{
  390. X    if (ispipe)
  391. X        return (ch_fsize);
  392. X    return ((POSITION)(lseek(file, (off_t)0, 2)));
  393. X}
  394. X
  395. X/*
  396. X * Return the current position in the file.
  397. X */
  398. X    public POSITION
  399. Xch_tell()
  400. X{
  401. X    return (ch_block * BUFSIZ + ch_offset);
  402. X}
  403. X
  404. X/*
  405. X * Get the current char and post-increment the read pointer.
  406. X */
  407. X    public int
  408. Xch_forw_get()
  409. X{
  410. X    register int c;
  411. X
  412. X    c = ch_get();
  413. X    if (c != EOF && ++ch_offset >= BUFSIZ)
  414. X    {
  415. X        ch_offset = 0;
  416. X        ch_block ++;
  417. X    }
  418. X    return (c);
  419. X}
  420. X
  421. X/*
  422. X * Pre-decrement the read pointer and get the new current char.
  423. X */
  424. X    public int
  425. Xch_back_get()
  426. X{
  427. X    register int c;
  428. X
  429. X    if (--ch_offset < 0)
  430. X    {
  431. X        if (ch_block <= 0 || (ispipe && !buffered(ch_block-1)))
  432. X        {
  433. X            ch_offset = 0;
  434. X            return (EOF);
  435. X        }
  436. X        ch_offset = BUFSIZ - 1;
  437. X        ch_block--;
  438. X    }
  439. X    c = ch_get();
  440. X    return (c);
  441. X}
  442. X
  443. X/*
  444. X * Initialize the buffer pool to all empty.
  445. X * Caller suggests that we use want_nbufs buffers.
  446. X */
  447. X    public void
  448. Xch_init(want_nbufs)
  449. X    int want_nbufs;
  450. X{
  451. X    register struct buf *bp;
  452. X    char *calloc();
  453. X
  454. X    if (nbufs < want_nbufs)
  455. X    {
  456. X        /*
  457. X         * We don't have enough buffers.  
  458. X         * Free what we have (if any) and allocate some new ones.
  459. X         */
  460. X        if (bufs != NULL)
  461. X            free((char *)bufs);
  462. X        bufs = (struct buf *) calloc(want_nbufs, sizeof(struct buf));
  463. X        nbufs = want_nbufs;
  464. X        if (bufs == NULL)
  465. X        {
  466. X            /*
  467. X             * Couldn't get that many.
  468. X             * Try for a small default number of buffers.
  469. X             */
  470. X            char message[80];
  471. X            sprintf(message,
  472. X              "Cannot allocate %d buffers.  Using %d buffers.", 
  473. X              nbufs, DEF_NBUFS);
  474. X            error(message);
  475. X            bufs = (struct buf *) calloc(DEF_NBUFS, sizeof(struct buf));
  476. X            nbufs = DEF_NBUFS;
  477. X            if (bufs == NULL)
  478. X            {
  479. X                /*
  480. X                 * Couldn't even get the smaller number of bufs.
  481. X                 * Something is wrong here, don't continue.
  482. X                 */
  483. X                sprintf(message, 
  484. X                "Cannot even allocate %d buffers!  Quitting.",
  485. X                  DEF_NBUFS);
  486. X                error(message);
  487. X                quit();
  488. X                /*NOTREACHED*/
  489. X            }
  490. X        }
  491. X    }
  492. X
  493. X    /*
  494. X     * Initialize the buffers to empty.
  495. X     * Set up the circular list.
  496. X     */
  497. X    for (bp = &bufs[0];  bp < &bufs[nbufs];  bp++)
  498. X    {
  499. X        bp->next = bp + 1;
  500. X        bp->prev = bp - 1;
  501. X        bp->block = (long)(-1);
  502. X    }
  503. X    bufs[0].prev = bufs[nbufs-1].next = END_OF_CHAIN;
  504. X    buf_head = &bufs[0];
  505. X    buf_tail = &bufs[nbufs-1];
  506. X    last_piped_block = -1;
  507. X    ch_fsize = NULL_POSITION;
  508. X    (void) ch_seek((POSITION)0);
  509. X}
  510. SHAR_EOF
  511. fi
  512. if test -f 'command.c'
  513. then
  514.     echo shar: "will not over-write existing file 'command.c'"
  515. else
  516. sed 's/^X//' << \SHAR_EOF > 'command.c'
  517. X/*
  518. X * User-level command processor.
  519. X */
  520. X
  521. X#include "less.h"
  522. X#include "position.h"
  523. X#include <setjmp.h>
  524. X
  525. Xextern jmp_buf main_loop;
  526. Xextern int erase_char, kill_char;
  527. Xextern int pr_type;
  528. Xextern int sigs;
  529. Xextern int ispipe;
  530. Xextern int quit_at_eof;
  531. Xextern int hit_eof;
  532. Xextern int sc_width, sc_height;
  533. Xextern int sc_window;
  534. Xextern char *first_cmd;
  535. Xextern char *every_first_cmd;
  536. Xextern char version[];
  537. Xextern char current_file[];
  538. Xextern char *editor;
  539. X
  540. Xstatic char cmdbuf[90];        /* Buffer for holding a multi-char command */
  541. Xstatic char *cp;        /* Pointer into cmdbuf */
  542. Xstatic int cmd_col;        /* Current column of the multi-char command */
  543. Xstatic char mcc;        /* The multi-char command letter (e.g. '/') */
  544. Xstatic char last_mcc;        /* The previous mcc */
  545. Xstatic int screen_trashed;    /* The screen has been overwritten */
  546. X
  547. X/*
  548. X * Reset command buffer (to empty).
  549. X */
  550. Xcmd_reset()
  551. X{
  552. X    cp = cmdbuf;
  553. X}
  554. X
  555. X/*
  556. X * Backspace in command buffer.
  557. X */
  558. X    static int
  559. Xcmd_erase()
  560. X{
  561. X    if (cp == cmdbuf)
  562. X        /*
  563. X         * Backspace past beginning of the string:
  564. X         * this usually means abort the command.
  565. X         */
  566. X        return (1);
  567. X
  568. X    if (control_char(*--cp))
  569. X    {
  570. X        /*
  571. X         * Erase an extra character, for the carat.
  572. X         */
  573. X        backspace();
  574. X        cmd_col--;
  575. X    }
  576. X    backspace();
  577. X    cmd_col--;
  578. X    return (0);
  579. X}
  580. X
  581. X/*
  582. X * Set up the display to start a new multi-character command.
  583. X */
  584. Xstart_mcc(c)
  585. X    int c;
  586. X{
  587. X    mcc = c;
  588. X    lower_left();
  589. X    clear_eol();
  590. X    putc(mcc);
  591. X    cmd_col = 1;
  592. X}
  593. X
  594. X/*
  595. X * Process a single character of a multi-character command, such as
  596. X * a number, or the pattern of a search command.
  597. X */
  598. X    static int
  599. Xcmd_char(c)
  600. X    int c;
  601. X{
  602. X    if (c == erase_char)
  603. X    {
  604. X        if (cmd_erase())
  605. X            return (1);
  606. X    } else if (c == kill_char)
  607. X    {
  608. X        /* {{ Could do this faster, but who cares? }} */
  609. X        while (cmd_erase() == 0)
  610. X            ;
  611. X    } else
  612. X    {
  613. X        /*
  614. X         * Append the character to the string,
  615. X         * if there is room in the buffer and on the screen.
  616. X         */
  617. X        if (cp < &cmdbuf[sizeof(cmdbuf)-1] && cmd_col < sc_width-3)
  618. X        {
  619. X            *cp++ = c;
  620. X            if (control_char(c))
  621. X            {
  622. X                putc('^');
  623. X                cmd_col++;
  624. X                c = carat_char(c);
  625. X            }
  626. X            putc(c);
  627. X            cmd_col++;
  628. X        } else
  629. X            bell();
  630. X    }
  631. X    return (0);
  632. X}
  633. X
  634. X/*
  635. X * Return the number currently in the command buffer.
  636. X */
  637. X    static int
  638. Xcmd_int()
  639. X{
  640. X    *cp = '\0';
  641. X    cp = cmdbuf;
  642. X    return (atoi(cmdbuf));
  643. X}
  644. X
  645. X/*
  646. X * Move the cursor to lower left before executing a command.
  647. X * This looks nicer if the command takes a long time before
  648. X * updating the screen.
  649. X */
  650. X    static void
  651. Xcmd_exec()
  652. X{
  653. X    lower_left();
  654. X    flush();
  655. X}
  656. X
  657. X/*
  658. X * Display the appropriate prompt.
  659. X */
  660. X    static void
  661. Xprompt()
  662. X{
  663. X    register char *p;
  664. X
  665. X    if (first_cmd != NULL && *first_cmd != '\0')
  666. X        /*
  667. X         * No prompt necessary if commands are from first_cmd
  668. X         * rather than from the user.
  669. X         */
  670. X        return;
  671. X
  672. X    /*
  673. X     * If nothing is displayed yet, display starting from line 1.
  674. X     */
  675. X    if (position(TOP) == NULL_POSITION)
  676. X        jump_back(1);
  677. X    else if (screen_trashed)
  678. X        repaint();
  679. X    screen_trashed = 0;
  680. X
  681. X    /*
  682. X     * Select the proper prompt and display it.
  683. X     */
  684. X    lower_left();
  685. X    clear_eol();
  686. X    p = pr_string();
  687. X    if (p == NULL)
  688. X        putc(':');
  689. X    else
  690. X    {
  691. X        so_enter();
  692. X        puts(p);
  693. X        so_exit();
  694. X    }
  695. X}
  696. X
  697. X/*
  698. X * Get command character.
  699. X * The character normally comes from the keyboard,
  700. X * but may come from the "first_cmd" string.
  701. X */
  702. X    static int
  703. Xgetcc()
  704. X{
  705. X    if (first_cmd == NULL)
  706. X        return (getc());
  707. X
  708. X    if (*first_cmd == '\0')
  709. X    {
  710. X        /*
  711. X         * Reached end of first_cmd input.
  712. X         */
  713. X        first_cmd = NULL;
  714. X        if (cp > cmdbuf && position(TOP) == NULL_POSITION)
  715. X        {
  716. X            /*
  717. X             * Command is incomplete, so try to complete it.
  718. X             * There are only two cases:
  719. X             * 1. We have "/string" but no newline.  Add the \n.
  720. X             * 2. We have a number but no command.  Treat as #g.
  721. X             * (This is all pretty hokey.)
  722. X             */
  723. X            if (mcc != ':')
  724. X                /* Not a number; must be search string */
  725. X                return ('\n'); 
  726. X            else
  727. X                /* A number; append a 'g' */
  728. X                return ('g');
  729. X        }
  730. X        return (getc());
  731. X    }
  732. X    return (*first_cmd++);
  733. X}
  734. X
  735. X/*
  736. X * Main command processor.
  737. X * Accept and execute commands until a quit command, then return.
  738. X */
  739. X    public void
  740. Xcommands()
  741. X{
  742. X    register int c;
  743. X    register int n;
  744. X    register int scroll = 10;
  745. X
  746. X    last_mcc = 0;
  747. X    setjmp(main_loop);
  748. X    mcc = 0;
  749. X
  750. X    for (;;)
  751. X    {
  752. X        /*
  753. X         * Display prompt and accept a character.
  754. X         */
  755. X        psignals();    /* See if any signals need processing */
  756. X
  757. X        if (quit_at_eof && hit_eof > 1)
  758. X            /*
  759. X             * After hitting end-of-file for the second time,
  760. X             * automatically advance to the next file.
  761. X             * If there are no more files, quit.
  762. X             */
  763. X            next_file(1);
  764. X
  765. X        cmd_reset();
  766. X        prompt();
  767. X        c = getcc();
  768. X
  769. X    again:
  770. X        if (sigs)
  771. X            continue;
  772. X
  773. X        if (mcc)
  774. X        {
  775. X            /*
  776. X             * We are in a multi-character command.  
  777. X             * All chars until newline go into the command buffer.
  778. X             * (Note that mcc == ':' is a special case that
  779. X             *  means a number is being entered.)
  780. X             */
  781. X            if (mcc != ':' && (c == '\n' || c == '\r'))
  782. X            {
  783. X                char *p;
  784. X                static char fcbuf[100];
  785. X
  786. X                /*
  787. X                 * Execute the command.
  788. X                 */
  789. X                *cp = '\0';
  790. X                cmd_exec();
  791. X                switch (mcc)
  792. X                {
  793. X                case '/': case '?':
  794. X                    search(mcc, cmdbuf, n);
  795. X                    break;
  796. X                case '+':
  797. X                    for (p = cmdbuf;  *p == '+' || *p == ' ';  p++) ;
  798. X                    if (*p == '\0')
  799. X                        every_first_cmd = NULL;
  800. X                    else
  801. X                    {
  802. X                        strtcpy(fcbuf, p, sizeof(fcbuf));
  803. X                        every_first_cmd = fcbuf;
  804. X                    }
  805. X                    break;
  806. X                case 'E':
  807. X                    /*
  808. X                     * Ignore leading spaces 
  809. X                     * in the filename.
  810. X                     */
  811. X                    for (p = cmdbuf;  *p == ' ';  p++) ;
  812. X                    edit(glob(p));
  813. X                    break;
  814. X#if SHELL_ESCAPE
  815. X                case '!':
  816. X                    lsystem(cmdbuf);
  817. X                    screen_trashed = 1;
  818. X                    error("!done");
  819. X                    break;
  820. X#endif
  821. X                }
  822. X                mcc = 0;
  823. X            } else
  824. X            {
  825. X                if (mcc == ':' && (c < '0' || c > '9') &&
  826. X                    c != erase_char && c != kill_char)
  827. X                {
  828. X                    /*
  829. X                     * This is not part of the number
  830. X                     * we were entering.  Process
  831. X                     * it as a regular character.
  832. X                     */
  833. X                    mcc = 0;
  834. X                    goto again;
  835. X                }
  836. X
  837. X                /*
  838. X                 * Append the char to the command buffer.
  839. X                 */
  840. X                if (cmd_char(c))
  841. X                {
  842. X                    /* Abort the multi-char command. */
  843. X                    mcc = 0;
  844. X                    continue;
  845. X                }
  846. X                c = getcc();
  847. X                goto again;
  848. X            }
  849. X        } else switch (c)
  850. X        {
  851. X        case '0': case '1': case '2': case '3': case '4':
  852. X        case '5': case '6': case '7': case '8': case '9':
  853. X            /*
  854. X             * First digit of a number.
  855. X             */
  856. X            start_mcc(':');
  857. X            goto again;
  858. X
  859. X        case 'f':
  860. X        case ' ':
  861. X        case CONTROL('F'):
  862. X            /*
  863. X             * Forward one screen.
  864. X             */
  865. X            n = cmd_int();
  866. X            if (n <= 0)
  867. X                n = sc_window;
  868. X            forward(n, 1);
  869. X            break;
  870. X
  871. X        case 'b':
  872. X        case CONTROL('B'):
  873. X            /*
  874. X             * Backward one screen.
  875. X             */
  876. X            n = cmd_int();
  877. X            if (n <= 0)
  878. X                n = sc_window;
  879. X            backward(n, 1);
  880. X            break;
  881. X
  882. X        case 'e':
  883. X        case 'j':
  884. X        case '\r':
  885. X        case '\n':
  886. X        case CONTROL('E'):
  887. X            /*
  888. X             * Forward N (default 1) line.
  889. X             */
  890. X            n = cmd_int();
  891. X            if (n <= 0)
  892. X                n = 1;
  893. X            forward(n, 0);
  894. X            break;
  895. X
  896. X        case 'y':
  897. X        case 'k':
  898. X        case CONTROL('K'):
  899. X        case CONTROL('Y'):
  900. X            /*
  901. X             * Backward N (default 1) line.
  902. X             */
  903. X            n = cmd_int();
  904. X            if (n <= 0)
  905. X                n = 1;
  906. X            backward(n, 0);
  907. X            break;
  908. X
  909. X        case 'd':
  910. X        case CONTROL('D'):
  911. X            /*
  912. X             * Forward N lines 
  913. X             * (default same as last 'd' or 'u' command).
  914. X             */
  915. X            n = cmd_int();
  916. X            if (n > 0)
  917. X                scroll = n;
  918. X            forward(scroll, 0);
  919. X            break;
  920. X
  921. X        case 'u':
  922. X        case CONTROL('U'):
  923. X            /*
  924. X             * Forward N lines 
  925. X             * (default same as last 'd' or 'u' command).
  926. X             */
  927. X            n = cmd_int();
  928. X            if (n > 0)
  929. X                scroll = n;
  930. X            backward(scroll, 0);
  931. X            break;
  932. X
  933. X        case 'R':
  934. X            /*
  935. X             * Flush buffers, then repaint screen.
  936. X             * Don't flush the buffers on a pipe!
  937. X             */
  938. X            if (!ispipe)
  939. X                ch_init(0);
  940. X            /* Fall thru */
  941. X        case 'r':
  942. X        case CONTROL('R'):
  943. X        case CONTROL('L'):
  944. X            /*
  945. X             * Repaint screen.
  946. X             */
  947. X            repaint();
  948. X            break;
  949. X
  950. X        case 'g':
  951. X            /*
  952. X             * Go to line N, default beginning of file.
  953. X             */
  954. X            n = cmd_int();
  955. X            if (n <= 0)
  956. X                n = 1;
  957. X            cmd_exec();
  958. X            jump_back(n);
  959. X            break;
  960. X
  961. X        case 'p':
  962. X        case '%':
  963. X            /*
  964. X             * Go to a specified percentage into the file.
  965. X             */
  966. X            n = cmd_int();
  967. X            if (n < 0)
  968. X                n = 0;
  969. X            if (n > 100)
  970. X                n = 100;
  971. X            cmd_exec();
  972. X            jump_percent(n);
  973. X            break;
  974. X
  975. X        case 'G':
  976. X            /*
  977. X             * Go to line N, default end of file.
  978. X             */
  979. X            n = cmd_int();
  980. X            cmd_exec();
  981. X            if (n <= 0)
  982. X                jump_forw();
  983. X            else
  984. X                jump_back(n);
  985. X            break;
  986. X
  987. X        case '=':
  988. X        case CONTROL('G'):
  989. X            /*
  990. X             * Print file name, etc.
  991. X             */
  992. X            error(eq_message());
  993. X            break;
  994. X            
  995. X        case 'V':
  996. X            /*
  997. X             * Print version number, without the "@(#)".
  998. X             */
  999. X            error(version+4);
  1000. X            break;
  1001. X
  1002. X        case 'q':
  1003. X            /*
  1004. X             * Exit.
  1005. X             */
  1006. X            /*setjmp(main_loop);*/
  1007. X            quit();
  1008. X
  1009. X        case '/':
  1010. X        case '?':
  1011. X            /*
  1012. X             * Search for a pattern.
  1013. X             * Accept chars of the pattern until \n.
  1014. X             */
  1015. X            n = cmd_int();
  1016. X            if (n <= 0)
  1017. X                n = 1;
  1018. X            start_mcc(c);
  1019. X            last_mcc = c;
  1020. X            c = getcc();
  1021. X            goto again;
  1022. X
  1023. X        case 'n':
  1024. X            /*
  1025. X             * Repeat previous search.
  1026. X             */
  1027. X            n = cmd_int();
  1028. X            if (n <= 0)
  1029. X                n = 1;
  1030. X            start_mcc(last_mcc);
  1031. X            cmd_exec();
  1032. X            search(mcc, (char *)NULL, n);
  1033. X            mcc = 0;
  1034. X            break;
  1035. X
  1036. X        case 'h':
  1037. X            /*
  1038. X             * Help.
  1039. X             */
  1040. X            lower_left();
  1041. X            clear_eol();
  1042. X            puts("help");
  1043. X            cmd_exec();
  1044. X            help();
  1045. X            screen_trashed = 1;
  1046. X            break;
  1047. X
  1048. X        case 'E':
  1049. X            /*
  1050. X             * Edit a new file.  Get the filename.
  1051. X             */
  1052. X            cmd_reset();
  1053. X            start_mcc('E');
  1054. X            puts("xamine: ");    /* This looks nicer */
  1055. X            cmd_col += 8;
  1056. X            c = getcc();
  1057. X            goto again;
  1058. X            
  1059. X        case '!':
  1060. X#if SHELL_ESCAPE
  1061. X            /*
  1062. X             * Shell escape.
  1063. X             */
  1064. X            cmd_reset();
  1065. X            start_mcc('!');
  1066. X            c = getcc();
  1067. X            goto again;
  1068. X#else
  1069. X            error("Command not available");
  1070. X            break;
  1071. X#endif
  1072. X
  1073. X        case 'v':
  1074. X#if EDITOR
  1075. X            if (ispipe)
  1076. X            {
  1077. X                error("Cannot edit standard input");
  1078. X                break;
  1079. X            }
  1080. X            sprintf(cmdbuf, "%s %s", editor, current_file);
  1081. X            lsystem(cmdbuf);
  1082. X            ch_init(0);
  1083. X            screen_trashed = 1;
  1084. X            break;
  1085. X#else
  1086. X            error("Command not available");
  1087. X            break;
  1088. X#endif
  1089. X
  1090. X        case 'N':
  1091. X            /*
  1092. X             * Examine next file.
  1093. X             */
  1094. X            n = cmd_int();
  1095. X            if (n <= 0)
  1096. X                n = 1;
  1097. X            next_file(n);
  1098. X            break;
  1099. X
  1100. X        case 'P':
  1101. X            /*
  1102. X             * Examine previous file.
  1103. X             */
  1104. X            n = cmd_int();
  1105. X            if (n <= 0)
  1106. X                n = 1;
  1107. X            prev_file(n);
  1108. X            break;
  1109. X
  1110. X        case '-':
  1111. X            /*
  1112. X             * Toggle a flag setting.
  1113. X             */
  1114. X            start_mcc('-');
  1115. X            c = getcc();
  1116. X            mcc = 0;
  1117. X            if (c == erase_char || c == kill_char)
  1118. X                break;
  1119. X            toggle_option(c);
  1120. X            break;
  1121. X
  1122. X        case '+':
  1123. X            cmd_reset();
  1124. X            start_mcc('+');
  1125. X            c = getcc();
  1126. X            goto again;
  1127. X
  1128. X        case 'm':
  1129. X            /*
  1130. X             * Set a mark.
  1131. X             */
  1132. X            lower_left();
  1133. X            clear_eol();
  1134. X            puts("mark: ");
  1135. X            c = getcc();
  1136. X            if (c == erase_char || c == kill_char)
  1137. X                break;
  1138. X            setmark(c);
  1139. X            break;
  1140. X
  1141. X        case '\'':
  1142. X            /*
  1143. X             * Go to a mark.
  1144. X             */
  1145. X            lower_left();
  1146. X            clear_eol();
  1147. X            puts("goto mark: ");
  1148. X            c = getcc();
  1149. X            if (c == erase_char || c == kill_char)
  1150. X                break;
  1151. X            gomark(c);
  1152. X            break;
  1153. X
  1154. X        default:
  1155. X            bell();
  1156. X            break;
  1157. X        }
  1158. X    }
  1159. X}
  1160. SHAR_EOF
  1161. fi
  1162. if test -f 'funcs.h'
  1163. then
  1164.     echo shar: "will not over-write existing file 'funcs.h'"
  1165. else
  1166. sed 's/^X//' << \SHAR_EOF > 'funcs.h'
  1167. X    public void edit ();
  1168. X    public void next_file ();
  1169. X    public void prev_file ();
  1170. X    public void quit ();
  1171. X    public void init_option ();
  1172. X    public void toggle_option ();
  1173. X    public void scan_option ();
  1174. X    public void forward ();
  1175. X    public void backward ();
  1176. X    public void repaint ();
  1177. X    public void jump_forw ();
  1178. X    public void jump_back ();
  1179. X    public void jump_percent ();
  1180. X    public void jump_loc ();
  1181. X    public void init_mark ();
  1182. X    public void setmark ();
  1183. X    public void lastmark ();
  1184. X    public void gomark ();
  1185. X    public int get_back_scroll ();
  1186. X    public void search ();
  1187. X    public void end_logfile ();
  1188. X    public int ch_seek ();
  1189. X    public int ch_end_seek ();
  1190. X    public int ch_beg_seek ();
  1191. X    public POSITION ch_length ();
  1192. X    public POSITION ch_tell ();
  1193. X    public int ch_forw_get ();
  1194. X    public int ch_back_get ();
  1195. X    public void ch_init ();
  1196. X    public POSITION position ();
  1197. X    public void add_forw_pos ();
  1198. X    public void add_back_pos ();
  1199. X    public void pos_clear ();
  1200. X    public int onscreen ();
  1201. X    public POSITION forw_line ();
  1202. X    public POSITION back_line ();
  1203. X    public void put_line ();
  1204. X    public int control_char ();
  1205. X    public int carat_char ();
  1206. X    public void flush ();
  1207. X    public void dropout ();
  1208. X    public void putc ();
  1209. X    public void puts ();
  1210. X    public void error ();
  1211. X    public int error_width ();
  1212. X    public void raw_mode ();
  1213. X    public void get_term ();
  1214. X    public void init ();
  1215. X    public void deinit ();
  1216. X    public void home ();
  1217. X    public void add_line ();
  1218. X    public void lower_left ();
  1219. X    public void bell ();
  1220. X    public void vbell ();
  1221. X    public void clear ();
  1222. X    public void clear_eol ();
  1223. X    public void so_enter ();
  1224. X    public void so_exit ();
  1225. X    public void ul_enter ();
  1226. X    public void ul_exit ();
  1227. X    public void bo_enter ();
  1228. X    public void bo_exit ();
  1229. X    public void backspace ();
  1230. X    public void putbs ();
  1231. X    public char * eq_message ();
  1232. X    public char * pr_string ();
  1233. X    public void prewind ();
  1234. X    public int pappend ();
  1235. X    public POSITION forw_raw_line ();
  1236. X    public POSITION back_raw_line ();
  1237. X    public void init_signals ();
  1238. X    public void  psignals ();
  1239. X    public void lsystem ();
  1240. X    public void help ();
  1241. X    public void open_getc ();
  1242. X    public int getc ();
  1243. X    public void commands ();
  1244. SHAR_EOF
  1245. fi
  1246. if test -f 'help.c'
  1247. then
  1248.     echo shar: "will not over-write existing file 'help.c'"
  1249. else
  1250. sed 's/^X//' << \SHAR_EOF > 'help.c'
  1251. X#include  "less.h"
  1252. X
  1253. X/*
  1254. X * Display some help.
  1255. X * Just invoke another "less" to display the help file.
  1256. X *
  1257. X * {{ This makes this function very simple, and makes changing the
  1258. X *    help file very easy, but it may present difficulties on
  1259. X *    (non-Unix) systems which do not supply the "system()" function. }}
  1260. X */
  1261. X
  1262. X    public void
  1263. Xhelp()
  1264. X{
  1265. X    char cmd[200];
  1266. X
  1267. X    sprintf(cmd, 
  1268. X     "-less -m '-Pm<HELP -- Press RETURN for more, or q when done >' %s",
  1269. X     HELPFILE);
  1270. X    lsystem(cmd);
  1271. X    error("End of help");
  1272. X}
  1273. SHAR_EOF
  1274. fi
  1275. if test -f 'input.c'
  1276. then
  1277.     echo shar: "will not over-write existing file 'input.c'"
  1278. else
  1279. sed 's/^X//' << \SHAR_EOF > 'input.c'
  1280. X/*
  1281. X * High level routines dealing with getting lines of input 
  1282. X * from the file being viewed.
  1283. X *
  1284. X * When we speak of "lines" here, we mean PRINTABLE lines;
  1285. X * lines processed with respect to the screen width.
  1286. X * We use the term "raw line" to refer to lines simply
  1287. X * delimited by newlines; not processed with respect to screen width.
  1288. X */
  1289. X
  1290. X#include "less.h"
  1291. X
  1292. Xextern int squeeze;
  1293. Xextern char *line;
  1294. X
  1295. X/*
  1296. X * Get the next line.
  1297. X * A "current" position is passed and a "new" position is returned.
  1298. X * The current position is the position of the first character of
  1299. X * a line.  The new position is the position of the first character
  1300. X * of the NEXT line.  The line obtained is the line starting at curr_pos.
  1301. X */
  1302. X    public POSITION
  1303. Xforw_line(curr_pos)
  1304. X    POSITION curr_pos;
  1305. X{
  1306. X    POSITION new_pos;
  1307. X    register int c;
  1308. X
  1309. X    if (curr_pos == NULL_POSITION || ch_seek(curr_pos))
  1310. X        return (NULL_POSITION);
  1311. X
  1312. X    c = ch_forw_get();
  1313. X    if (c == EOF)
  1314. X        return (NULL_POSITION);
  1315. X
  1316. X    prewind();
  1317. X    for (;;)
  1318. X    {
  1319. X        if (c == '\n' || c == EOF)
  1320. X        {
  1321. X            /*
  1322. X             * End of the line.
  1323. X             */
  1324. X            new_pos = ch_tell();
  1325. X            break;
  1326. X        }
  1327. X
  1328. X        /*
  1329. X         * Append the char to the line and get the next char.
  1330. X         */
  1331. X        if (pappend(c))
  1332. X        {
  1333. X            /*
  1334. X             * The char won't fit in the line; the line
  1335. X             * is too long to print in the screen width.
  1336. X             * End the line here.
  1337. X             */
  1338. X            new_pos = ch_tell() - 1;
  1339. X            break;
  1340. X        }
  1341. X        c = ch_forw_get();
  1342. X    }
  1343. X    (void) pappend('\0');
  1344. X
  1345. X    if (squeeze && *line == '\0')
  1346. X    {
  1347. X        /*
  1348. X         * This line is blank.
  1349. X         * Skip down to the last contiguous blank line
  1350. X         * and pretend it is the one which we are returning.
  1351. X         */
  1352. X        while ((c = ch_forw_get()) == '\n')
  1353. X            ;
  1354. X        if (c != EOF)
  1355. X            (void) ch_back_get();
  1356. X        new_pos = ch_tell();
  1357. X    }
  1358. X
  1359. X    return (new_pos);
  1360. X}
  1361. X
  1362. X/*
  1363. X * Get the previous line.
  1364. X * A "current" position is passed and a "new" position is returned.
  1365. X * The current position is the position of the first character of
  1366. X * a line.  The new position is the position of the first character
  1367. X * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
  1368. X */
  1369. X    public POSITION
  1370. Xback_line(curr_pos)
  1371. X    POSITION curr_pos;
  1372. X{
  1373. X    POSITION new_pos, begin_new_pos;
  1374. X    int c;
  1375. X
  1376. X    if (curr_pos == NULL_POSITION || curr_pos <= (POSITION)0 ||
  1377. X        ch_seek(curr_pos-1))
  1378. X        return (NULL_POSITION);
  1379. X
  1380. X    if (squeeze)
  1381. X    {
  1382. X        /*
  1383. X         * Find out if the "current" line was blank.
  1384. X         */
  1385. X        (void) ch_forw_get();    /* Skip the newline */
  1386. X        c = ch_forw_get();    /* First char of "current" line */
  1387. X        (void) ch_back_get();    /* Restore our position */
  1388. X        (void) ch_back_get();
  1389. X
  1390. X        if (c == '\n')
  1391. X        {
  1392. X            /*
  1393. X             * The "current" line was blank.
  1394. X             * Skip over any preceeding blank lines,
  1395. X             * since we skipped them in forw_line().
  1396. X             */
  1397. X            while ((c = ch_back_get()) == '\n')
  1398. X                ;
  1399. X            if (c == EOF)
  1400. X                return (NULL_POSITION);
  1401. X            (void) ch_forw_get();
  1402. X        }
  1403. X    }
  1404. X
  1405. X    /*
  1406. X     * Scan backwards until we hit the beginning of the line.
  1407. X     */
  1408. X    for (;;)
  1409. X    {
  1410. X        c = ch_back_get();
  1411. X        if (c == '\n')
  1412. X        {
  1413. X            /*
  1414. X             * This is the newline ending the previous line.
  1415. X             * We have hit the beginning of the line.
  1416. X             */
  1417. X            new_pos = ch_tell() + 1;
  1418. X            break;
  1419. X        }
  1420. X        if (c == EOF)
  1421. X        {
  1422. X            /*
  1423. X             * We have hit the beginning of the file.
  1424. X             * This must be the first line in the file.
  1425. X             * This must, of course, be the beginning of the line.
  1426. X             */
  1427. X            new_pos = ch_tell();
  1428. X            break;
  1429. X        }
  1430. X    }
  1431. X
  1432. X    /*
  1433. X     * Now scan forwards from the beginning of this line.
  1434. X     * We keep discarding "printable lines" (based on screen width)
  1435. X     * until we reach the curr_pos.
  1436. X     *
  1437. X     * {{ This algorithm is pretty inefficient if the lines
  1438. X     *    are much longer than the screen width, 
  1439. X     *    but I don't know of any better way. }}
  1440. X     */
  1441. X    if (ch_seek(new_pos))
  1442. X        return (NULL_POSITION);
  1443. X    loop:
  1444. X    begin_new_pos = new_pos;
  1445. X    prewind();
  1446. X
  1447. X    do
  1448. X    {
  1449. X        c = ch_forw_get();
  1450. X        new_pos++;
  1451. X        if (c == '\n')
  1452. X            break;
  1453. X        if (pappend(c))
  1454. X        {
  1455. X            /*
  1456. X             * Got a full printable line, but we haven't
  1457. X             * reached our curr_pos yet.  Discard the line
  1458. X             * and start a new one.
  1459. X             */
  1460. X            (void) pappend('\0');
  1461. X            (void) ch_back_get();
  1462. X            new_pos--;
  1463. X            goto loop;
  1464. X        }
  1465. X    } while (new_pos < curr_pos);
  1466. X
  1467. X    (void) pappend('\0');
  1468. X
  1469. X    return (begin_new_pos);
  1470. X}
  1471. SHAR_EOF
  1472. fi
  1473. if test -f 'install'
  1474. then
  1475.     echo shar: "will not over-write existing file 'install'"
  1476. else
  1477. sed 's/^X//' << \SHAR_EOF > 'install'
  1478. X:
  1479. X# Installation script for less.
  1480. X# This script prompts the operator for various information
  1481. X# and constructs a makefile.
  1482. X
  1483. Xecho "This script will build a makefile for less."
  1484. Xecho "If you already have a file called \"makefile\" it will be overwritten."
  1485. Xecho "Press RETURN to continue."
  1486. Xread ans
  1487. X
  1488. Xecho "I will ask you some questions about your system."
  1489. Xecho "If you do not know the answer to any question,"
  1490. Xecho "just press RETURN and I will choose a default for you."
  1491. Xecho "Press RETURN now."
  1492. Xread ans
  1493. X
  1494. Xecho "Most Unix systems are derived from either System V"
  1495. Xecho "or Berkeley BSD 4.1, 4.2, 4.3, etc."
  1496. Xecho ""
  1497. Xecho "Is your system closest to:"
  1498. Xecho "  1. System V"
  1499. Xecho "  2. BSD 2.11 or later"
  1500. Xecho "  3. BSD 4.1"
  1501. Xecho "  4. BSD 4.2 or later"
  1502. Xecho "  5. Xenix"
  1503. Xecho "Enter a number, or just RETURN if you don't know: \c"
  1504. Xread ans
  1505. Xxenix=0
  1506. Xcase "X$ans" in
  1507. XX1) sys=sys5; sysname="System V" ;;
  1508. XX2) sys=bsd; bsd41=0; bsd2=1; sysname="BSD 2.11" ;;
  1509. XX3) sys=bsd; bsd41=1; bsd2=0; sysname="BSD 4.1" ;;
  1510. XX4) sys=bsd; bsd41=0; bsd2=0; sysname="BSD 4.2" ;;
  1511. XX5) sys=sys5; xenix=1; sysname="Xenix" ;;
  1512. X*) sys=unknown ;;
  1513. Xesac
  1514. Xecho ""
  1515. X
  1516. Xcat >makefile <<"EOF"
  1517. X# Makefile for "less"
  1518. X#
  1519. X# Invoked as:
  1520. X#    make all
  1521. X#   or    make install
  1522. X# Plain "make" is equivalent to "make all".
  1523. X#
  1524. X# If you add or delete functions, remake funcs.h by doing:
  1525. X#    make newfuncs
  1526. X# This depends on the coding convention of function headers looking like:
  1527. X#    " \t public <function-type> \n <function-name> ( ... ) "
  1528. X#
  1529. X# Also provided:
  1530. X#    make lint    # Runs "lint" on all the sources.
  1531. X#    make clean    # Removes "less" and the .o files.
  1532. X#    make clobber    # Pretty much the same as make "clean".
  1533. X
  1534. X
  1535. X##########################################################################
  1536. X# System-specific parameters
  1537. X##########################################################################
  1538. X
  1539. XEOF
  1540. X
  1541. Xcat >>makefile <<EOF
  1542. X# Define XENIX if running under XENIX 3.0
  1543. XXENIX = $xenix
  1544. X
  1545. XEOF
  1546. Xecho ""
  1547. X
  1548. X
  1549. X
  1550. Xif [ "X$sys" = "Xunknown" ]
  1551. Xthen
  1552. X    alldefault=0
  1553. Xelse
  1554. X    def=yes
  1555. X    alldefault=1
  1556. X    echo "Do you want to use ALL the defaults for $sysname?"
  1557. X    echo "  Enter \"yes\" if you have a STANDARD $sysname."
  1558. X    echo "  Enter \"no\" if you want to change any of the defaults. [$def] \c"
  1559. X    read ans
  1560. X    case "X$ans" in
  1561. X    X[yY]*) alldefault=1 ;;
  1562. X    X[nN]*) alldefault=0 ;;
  1563. X    esac
  1564. X    echo ""
  1565. Xfi
  1566. X
  1567. X
  1568. X
  1569. Xdef=yes
  1570. Xx=1
  1571. Xif [ $alldefault = 0 ]
  1572. Xthen
  1573. X    echo "Does your C compiler support the \"void\" type? [$def] \c"
  1574. X    read ans
  1575. X    case "X$ans" in
  1576. X    X[yY]*) x=1 ;;
  1577. X    X[nN]*) x=0 ;;
  1578. X    esac
  1579. X    echo ""
  1580. Xfi
  1581. Xcat >>makefile <<EOF
  1582. X# VOID is 1 if your C compiler supports the "void" type,
  1583. X# 0 if it does not.
  1584. XVOID = $x
  1585. X
  1586. XEOF
  1587. X
  1588. X
  1589. X
  1590. Xdef=long
  1591. Xif [ $alldefault = 0 ]
  1592. Xthen
  1593. X    echo "What type is the \"offset\" argument to lseek? [$def] \c"
  1594. X    read ans
  1595. X    if [ "X$ans" != "X" ]
  1596. X    then
  1597. X        def=$ans
  1598. X    fi
  1599. X    echo ""
  1600. Xfi
  1601. Xcat >>makefile <<EOF
  1602. X# off_t is the type which lseek() returns.
  1603. X# It is also the type of lseek()'s second argument.
  1604. Xoff_t = $def
  1605. X
  1606. XEOF
  1607. X
  1608. X
  1609. X
  1610. X
  1611. Xif [ "$sys" = "bsd" ]
  1612. Xthen
  1613. X    def=no; x=0
  1614. Xelse
  1615. X    def=yes; x=1
  1616. Xfi
  1617. Xif [ $alldefault = 0 ]
  1618. Xthen
  1619. X    echo "Most System V systems have termio.h, while most"
  1620. X    echo "Berkeley-derived systems have sgtty.h."
  1621. X    echo "Does your system have termio.h? [$def] \c"
  1622. X    read ans
  1623. X    case "X$ans" in
  1624. X    X[yY]*) x=1 ;;
  1625. X    X[nN]*) x=0 ;;
  1626. X    esac
  1627. X    echo ""
  1628. Xfi
  1629. Xcat >>makefile <<EOF
  1630. X# TERMIO is 1 if your system has /usr/include/termio.h.
  1631. X# This is normally the case for System 5.
  1632. X# If TERMIO is 0 your system must have /usr/include/sgtty.h.
  1633. X# This is normally the case for BSD.
  1634. XTERMIO = $x
  1635. X
  1636. XEOF
  1637. X
  1638. X
  1639. X
  1640. X
  1641. Xif [ "$sys" = "bsd" -a "$bsd41" = "0" ]
  1642. Xthen
  1643. X    def=yes; x=1
  1644. Xelse
  1645. X    def=no; x=0
  1646. Xfi
  1647. Xif [ $alldefault = 0 ]
  1648. Xthen
  1649. X    echo "Most BSD 4.2 and 4.3 systems have the sigsetmask() call."
  1650. X    echo "Most System V and BSD 4.1 systems do not."
  1651. X    echo "Does your system have sigsetmask()? [$def] \c"
  1652. X    read ans
  1653. X    case "X$ans" in
  1654. X    X[yY]*) x=1 ;;
  1655. X    X[nN]*) x=0 ;;
  1656. X    esac
  1657. X    echo ""
  1658. Xfi
  1659. Xcat >>makefile <<EOF
  1660. X# SIGSETMASK is 1 if your system has the sigsetmask() call.
  1661. X# This is normally the case only for BSD 4.2,
  1662. X# not for BSD 4.1 or System 5.
  1663. XSIGSETMASK = $x
  1664. X
  1665. XEOF
  1666. X
  1667. Xcat >>makefile <<EOF
  1668. X##########################################################################
  1669. X# Optional and semi-optional features
  1670. X##########################################################################
  1671. X
  1672. XEOF
  1673. X
  1674. X
  1675. X
  1676. X
  1677. Xif [ "$sys" = "bsd" ]
  1678. Xthen
  1679. X    def=2; REGCMP=0;RECOMP=1
  1680. Xelse
  1681. X    def=1; REGCMP=1;RECOMP=0
  1682. Xfi
  1683. Xif [ $alldefault = 0 ]
  1684. Xthen
  1685. X    echo "Most System V systems have the regcmp() function."
  1686. X    echo "Most Berkeley-derived systems have the re_comp() function."
  1687. X    echo "Does your system have:"
  1688. X    echo "  1. regcmp"
  1689. X    echo "  2. re_comp"
  1690. X    echo "  3. neither   [$def] \c"
  1691. X    read ans
  1692. X    case "X$ans" in
  1693. X    X1) REGCMP=1;RECOMP=0 ;;
  1694. X    X2) REGCMP=0;RECOMP=1 ;;
  1695. X    X3) REGCMP=0;RECOMP=0 ;;
  1696. X    esac
  1697. X    echo ""
  1698. Xfi
  1699. Xcat >>makefile <<EOF
  1700. X# REGCMP is 1 if your system has the regcmp() function.
  1701. X# This is normally the case for System 5.
  1702. X# RECOMP is 1 if your system has the re_comp() function.
  1703. X# This is normally the case for BSD.
  1704. X# If neither is 1, pattern matching is supported, but without metacharacters.
  1705. XREGCMP = $REGCMP
  1706. XRECOMP = $RECOMP
  1707. X
  1708. XEOF
  1709. X
  1710. X
  1711. X
  1712. X
  1713. Xdef=yes
  1714. Xx=1
  1715. Xif [ $alldefault = 0 ]
  1716. Xthen
  1717. X    echo "Do you wish to allow shell escapes? [$def] \c"
  1718. X    read ans
  1719. X    case "X$ans" in
  1720. X    X[yY]*) x=1 ;;
  1721. X    X[nN]*) x=0 ;;
  1722. X    esac
  1723. X    echo ""
  1724. Xfi
  1725. Xcat >>makefile <<EOF
  1726. X# SHELL_ESCAPE is 1 if you wish to allow shell escapes.
  1727. X# (This is possible only if your system supplies the system() function.)
  1728. XSHELL_ESCAPE = $x
  1729. X
  1730. XEOF
  1731. X
  1732. X
  1733. X
  1734. Xdef=yes
  1735. Xx=1
  1736. Xedname="vi"
  1737. Xif [ $alldefault = 0 ]
  1738. Xthen
  1739. X    echo "Do you wish to allow editor escapes? [$def] \c"
  1740. X    read ans
  1741. X    case "X$ans" in
  1742. X    X[nN]*) x=0; edname="" ;;
  1743. X    X[yY]*) x=1
  1744. X        echo "What is the pathname of the default editor? [$edname] \c"
  1745. X        read ans 
  1746. X        if [ "x$ans" != "x" ]
  1747. X        then
  1748. X            edname=$ans
  1749. X        fi
  1750. X        ;;
  1751. X    esac
  1752. X    echo ""
  1753. Xfi
  1754. Xcat >>makefile <<EOF
  1755. X# EDITOR is 1 if you wish to allow editor invocation (the "v" command).
  1756. X# (This is possible only if your system supplies the system() function.)
  1757. X# EDIT_PGM is the name of the (default) editor to be invoked.
  1758. XEDITOR = $x
  1759. XEDIT_PGM = $edname
  1760. X
  1761. XEOF
  1762. X
  1763. X
  1764. X
  1765. Xdef=yes
  1766. Xx=1
  1767. Xif [ $alldefault = 0 ]
  1768. Xthen
  1769. X    echo "If your system provides the popen() function and"
  1770. X    echo "the \"echo\" shell command, you may allow shell metacharacters" 
  1771. X    echo "to be expanded in filenames."
  1772. X    echo "Do you wish to allow shell metacharacters in filenames? [$def] \c"
  1773. X    read ans
  1774. X    case "X$ans" in
  1775. X    X[yY]*) x=1 ;;
  1776. X    X[nN]*) x=0 ;;
  1777. X    esac
  1778. X    echo ""
  1779. Xfi
  1780. Xcat >>makefile <<EOF
  1781. X# GLOB is 1 if you wish to have shell metacharacters expanded in filenames.
  1782. X# This will generally work if your system provides the "popen" function
  1783. X# and the "echo" shell command.
  1784. XGLOB = $x
  1785. X
  1786. XEOF
  1787. X
  1788. X
  1789. X
  1790. Xdef=yes
  1791. Xx=1
  1792. Xif [ $alldefault = 0 ]
  1793. Xthen
  1794. X    echo "Do you wish to allow log files (-l option)? [$def] \c"
  1795. X    read ans
  1796. X    case "X$ans" in
  1797. X    X[yY]*) x=1 ;;
  1798. X    X[nN]*) x=0 ;;
  1799. X    esac
  1800. X    echo ""
  1801. Xfi
  1802. Xcat >>makefile <<EOF
  1803. X# LOGFILE is 1 if you wish to allow the -l option (to create log files).
  1804. XLOGFILE = $x
  1805. X
  1806. XEOF
  1807. X
  1808. Xcat >>makefile <<EOF
  1809. X# ONLY_RETURN is 1 if you want RETURN to be the only input which
  1810. X# will continue past an error message.
  1811. X# Otherwise, any key will continue past an error message.
  1812. XONLY_RETURN = 0
  1813. X
  1814. X
  1815. X##########################################################################
  1816. X# Compilation environment.
  1817. X##########################################################################
  1818. X
  1819. XEOF
  1820. X
  1821. X
  1822. X
  1823. Xif [ "$xenix" = "1" ]
  1824. Xthen
  1825. X    LIBS="-ltermlib"
  1826. Xelif [ "$sys" = "bsd" ]
  1827. Xthen
  1828. X    LIBS="-ltermcap"
  1829. Xelse
  1830. X    LIBS="-lcurses -ltermcap -lPW"
  1831. Xfi
  1832. Xif [ $alldefault = 0 ]
  1833. Xthen
  1834. X    echo "To build \"less\", you must link with libraries supplied by your system."
  1835. X    echo "(If this needs to be changed later, edit the makefile"
  1836. X    echo "and change the definition of LIBS.)"
  1837. X    echo "What libraries should be used [$LIBS] \c"
  1838. X    read ans
  1839. X    if [ "X$ans" != "X" ]
  1840. X    then
  1841. X        LIBS="$ans"
  1842. X    fi
  1843. X    echo ""
  1844. Xfi
  1845. Xcat >>makefile <<EOF
  1846. X# LIBS is the list of libraries needed.
  1847. XLIBS = $LIBS
  1848. X
  1849. XEOF
  1850. X
  1851. X
  1852. Xif [ "$sys" = "bsd" -a "$bsd2" = "1" ]
  1853. Xthen
  1854. X    INSTALL_LESS="/usr/local/less"
  1855. X    INSTALL_HELP="/usr/local/lib/less.help"
  1856. X    INSTALL_MAN="/usr/local/man/cat1/less.0"
  1857. X    MANUAL="less.nro"
  1858. Xelse
  1859. X    INSTALL_LESS="/usr/local/bin/less"
  1860. X    INSTALL_HELP="/usr/local/bin/less.help"
  1861. X    INSTALL_MAN="/usr/man/man1/less.1"
  1862. X    MANUAL="less.nro"
  1863. Xfi
  1864. X
  1865. Xif [ $alldefault = 0 ]
  1866. Xthen
  1867. X    echo "What is the name of the \"public\" (installed) version of less?"
  1868. X    echo " [$INSTALL_LESS] \c"
  1869. X    read ans
  1870. X    if [ "X$ans" != "X" ]
  1871. X    then
  1872. X        INSTALL_LESS="$ans"
  1873. X    fi
  1874. X    echo "What is the name of the \"public\" (installed) version of the help file?"
  1875. X    echo " [$INSTALL_HELP] \c"
  1876. X    read ans
  1877. X    if [ "X$ans" != "X" ]
  1878. X    then
  1879. X        INSTALL_HELP="$ans"
  1880. X    fi
  1881. X    echo "What is the name of the \"public\" (installed) version of the manual page?"
  1882. X    echo " [$INSTALL_MAN] \c"
  1883. X    read ans
  1884. X    if [ "X$ans" != "X" ]
  1885. X    then
  1886. X        INSTALL_MAN="$ans"
  1887. X    fi
  1888. X    echo ""
  1889. Xfi
  1890. Xcat >>makefile <<EOF
  1891. X# INSTALL_LESS is a list of the public versions of less.
  1892. X# INSTALL_HELP is a list of the public version of the help file.
  1893. X# INSTALL_MAN is a list of the public versions of the manual page.
  1894. XINSTALL_LESS =    $INSTALL_LESS
  1895. XINSTALL_HELP =    $INSTALL_HELP
  1896. XINSTALL_MAN =    $INSTALL_MAN
  1897. XMANUAL =    $MANUAL
  1898. XHELPFILE =    $INSTALL_HELP
  1899. X
  1900. X
  1901. XEOF
  1902. X
  1903. X
  1904. X
  1905. Xif [ "$sys" = "bsd" -a "$bsd2" = "1" ]
  1906. Xthen
  1907. Xcat >>makefile <<"EOF"
  1908. X# OPTIM is passed to the compiler and the loader.
  1909. X# It is normally "-O" but may be, for example, "-g".
  1910. XOPTIM = -O -i
  1911. XEOF
  1912. X
  1913. Xelse
  1914. Xcat >>makefile <<"EOF"
  1915. X# OPTIM is passed to the compiler and the loader.
  1916. X# It is normally "-O" but may be, for example, "-g".
  1917. XOPTIM = -O
  1918. XEOF
  1919. X
  1920. Xfi
  1921. X
  1922. X
  1923. Xcat >>makefile <<"EOF"
  1924. X
  1925. X
  1926. X##########################################################################
  1927. X# Files
  1928. X##########################################################################
  1929. X
  1930. XSRC1 =    main.c option.c prim.c ch.c position.c input.c output.c 
  1931. XSRC2 =    screen.c prompt.c line.c signal.c help.c ttyin.c command.c version.c
  1932. XSRC =    $(SRC1) $(SRC2)
  1933. XOBJ =    main.o option.o prim.o ch.o position.o input.o output.o screen.o \
  1934. X    prompt.o line.o signal.o help.o ttyin.o command.o version.o
  1935. X
  1936. X
  1937. X##########################################################################
  1938. X# Rules
  1939. X##########################################################################
  1940. X
  1941. XDEFS =    "-DTERMIO=$(TERMIO)" \
  1942. X    "-DSIGSETMASK=$(SIGSETMASK)" \
  1943. X    "-Doff_t=$(off_t)" "-DVOID=$(VOID)" \
  1944. X    "-DREGCMP=$(REGCMP)" "-DRECOMP=$(RECOMP)" \
  1945. X    "-DSHELL_ESCAPE=$(SHELL_ESCAPE)" \
  1946. X    "-DEDITOR=$(EDITOR)" "-DEDIT_PGM=\"$(EDIT_PGM)\"" \
  1947. X    "-DHELPFILE=\"$(HELPFILE)\"" \
  1948. X    "-DLOGFILE=$(LOGFILE)" \
  1949. X    "-DONLY_RETURN=$(ONLY_RETURN)" \
  1950. X    "-DGLOB=$(GLOB)" \
  1951. X    "-DXENIX=$(XENIX)"
  1952. X
  1953. XCFLAGS = $(OPTIM) $(DEFS)
  1954. X
  1955. X
  1956. Xall: less
  1957. X
  1958. Xless: $(OBJ)
  1959. X    cc $(OPTIM) -o less $(OBJ) $(LIBS)
  1960. X
  1961. Xinstall: install_man install_less install_help
  1962. X
  1963. Xinstall_less: less
  1964. X    for f in $(INSTALL_LESS); do  rm -f $$f; cp less $$f;  done
  1965. X    touch install_less
  1966. X
  1967. Xinstall_help: less.help
  1968. X    for f in $(INSTALL_HELP); do  rm -f $$f; cp less.help $$f;  done
  1969. X    touch install_help
  1970. X
  1971. XEOF
  1972. X
  1973. Xif [ "$sys" = "bsd" -a "$bsd2" = "1" ]
  1974. Xthen
  1975. Xcat >>makefile <<"EOF"
  1976. Xinstall_man: $(MANUAL)
  1977. X    rm -f $(INSTALL_MAN)
  1978. X    /usr/man/manroff $(MANUAL) > $(INSTALL_MAN)
  1979. X    chmod 444 $(INSTALL_MAN)
  1980. X    chown bin.bin $(INSTALL_MAN)
  1981. X    touch install_man
  1982. X
  1983. XEOF
  1984. X
  1985. Xelse
  1986. Xcat >>makefile <<"EOF"
  1987. Xinstall_man: $(MANUAL)
  1988. X    for f in $(INSTALL_MAN); do  rm -f $$f; cp $(MANUAL) $$f;  done
  1989. X    touch install_man
  1990. X
  1991. XEOF
  1992. Xfi
  1993. X
  1994. Xcat >>makefile <<"EOF"
  1995. X$(OBJ): less.h funcs.h
  1996. X
  1997. X# help.o depends on makefile for the definition of HELPFILE.
  1998. Xhelp.o: makefile
  1999. X
  2000. Xlint:
  2001. X    lint -hp $(DEFS) $(SRC)
  2002. X
  2003. Xnewfuncs:
  2004. X    mv funcs.h funcs.h.OLD
  2005. X    awk -f mkfuncs.awk $(SRC) >funcs.h
  2006. X
  2007. XEOF
  2008. X
  2009. X
  2010. Xif [ "$sys" = "bsd" -a "$bsd2" = "1" ]
  2011. Xthen
  2012. Xcat >>makefile <<"EOF"
  2013. Xclean:
  2014. X    rm -f $(OBJ) less install_help install_less install_man core
  2015. X
  2016. XEOF
  2017. X
  2018. Xelse
  2019. Xcat >>makefile <<"EOF"
  2020. Xclean:
  2021. X    rm -f $(OBJ) less
  2022. X
  2023. XEOF
  2024. Xfi
  2025. X
  2026. Xcat >>makefile <<"EOF"
  2027. Xclobber:
  2028. X    rm -f *.o less install_less install_man
  2029. X
  2030. Xshar:
  2031. X    shar -v README install less.help makefile.* *.h *.awk > less.shar.a
  2032. X    shar -v less.nro $(SRC1) > less.shar.b
  2033. X    shar -v $(SRC2) > less.shar.c
  2034. XEOF
  2035. Xecho ""
  2036. X
  2037. Xecho "The makefile has been built."
  2038. Xecho "You should check it to make sure everything is as you want it to be."
  2039. Xecho "When you are satisfied with the makefile, just type \"make\""
  2040. Xecho "and \"less\" will be built."
  2041. SHAR_EOF
  2042. chmod +x 'install'
  2043. fi
  2044. if test -f 'less.h'
  2045. then
  2046.     echo shar: "will not over-write existing file 'less.h'"
  2047. else
  2048. sed 's/^X//' << \SHAR_EOF > 'less.h'
  2049. X/*
  2050. X * Standard include file for "less".
  2051. X */
  2052. X
  2053. X/*
  2054. X * Language details.
  2055. X */
  2056. X#if !VOID
  2057. X#define    void  int
  2058. X#endif
  2059. X#define    public        /* PUBLIC FUNCTION */
  2060. X
  2061. X/*
  2062. X * Special types and constants.
  2063. X */
  2064. Xtypedef long        POSITION;
  2065. X/*
  2066. X * {{ Warning: if POSITION is changed to other than "long",
  2067. X *    you may have to change some of the printfs which use "%ld"
  2068. X *    to print a variable of type POSITION. }}
  2069. X */
  2070. X
  2071. X#define    NULL_POSITION    ((POSITION)(-1))
  2072. X
  2073. X#define    EOF        (0)
  2074. X#define    NULL        (0)
  2075. X
  2076. X/* How quiet should we be? */
  2077. X#define    NOT_QUIET    0    /* Ring bell at eof and for errors */
  2078. X#define    LITTLE_QUIET    1    /* Ring bell only for errors */
  2079. X#define    VERY_QUIET    2    /* Never ring bell */
  2080. X
  2081. X/* How should we prompt? */
  2082. X#define    PR_SHORT    0    /* Prompt with colon */
  2083. X#define    PR_MEDIUM    1    /* Prompt with message */
  2084. X#define    PR_LONG        2    /* Prompt with longer message */
  2085. X
  2086. X/* How should we handle backspaces? */
  2087. X#define    BS_SPECIAL    0    /* Do special things for underlining and bold */
  2088. X#define    BS_NORMAL    1    /* \b treated as normal char; actually output */
  2089. X#define    BS_CONTROL    2    /* \b treated as control char; prints as ^H */
  2090. X
  2091. X/* Special chars used to tell put_line() to do something special */
  2092. X#define    UL_CHAR        '\201'    /* Enter underline mode */
  2093. X#define    UE_CHAR        '\202'    /* Exit underline mode */
  2094. X#define    BO_CHAR        '\203'    /* Enter boldface mode */
  2095. X#define    BE_CHAR        '\204'    /* Exit boldface mode */
  2096. X
  2097. X#define    CONTROL(c)        ((c)&037)
  2098. X#define    SIGNAL(sig,func)    signal(sig,func)
  2099. X
  2100. X/* Library function declarations */
  2101. Xoff_t lseek();
  2102. X
  2103. X#include "funcs.h"
  2104. SHAR_EOF
  2105. fi
  2106. if test -f 'less.help'
  2107. then
  2108.     echo shar: "will not over-write existing file 'less.help'"
  2109. else
  2110. sed 's/^X//' << \SHAR_EOF > 'less.help'
  2111. X
  2112. X      Commands marked with * may be preceeded by a number, N.
  2113. X
  2114. X  h              Display this help.
  2115. X  q              Exit.
  2116. X
  2117. X  f, SPACE    *  Forward  N lines, default one screen.
  2118. X  b           *  Backward N lines, default one screen.
  2119. X  e, j, CR    *  Forward  N lines, default 1 line.
  2120. X  y, k        *  Backward N lines, default 1 line.
  2121. X  d           *  Forward  N lines, default 10 or last N to d or u command.
  2122. X  u           *  Backward N lines, default 10 or last N to d or u command.
  2123. X  r              Repaint screen.
  2124. X  R              Repaint screen, discarding buffered input.
  2125. X
  2126. X  /pattern    *  Search forward for N-th line containing the pattern.
  2127. X  ?pattern    *  Search backward for N-th line containing the pattern.
  2128. X  n           *  Repeat previous search (for N-th occurence).
  2129. X
  2130. X  g           *  Go to line N, default 1.
  2131. X  G           *  Like g, but default is last line in file.
  2132. X  p, %        *  Position to N percent into the file.
  2133. X  m<letter>      Mark the current position with <letter>.
  2134. X  '<letter>      Return to a previously marked position.
  2135. X  ''             Return to previous position.
  2136. X
  2137. X  E [file]       Examine a new file.
  2138. X  N           *  Examine the next file (from the command line).
  2139. X  P           *  Examine the previous file (from the command line).
  2140. X  =              Print current file name.
  2141. X  V              Print version number of "less".
  2142. X
  2143. X  -<flag>        Toggle a command line flag.
  2144. X  +cmd           Execute the less cmd each time a new file is examined.
  2145. X
  2146. X  !command       Passes the command to a shell to be executed.
  2147. X  v              Edit the current file with $EDITOR.
  2148. SHAR_EOF
  2149. fi
  2150. if test -f 'less.nro'
  2151. then
  2152.     echo shar: "will not over-write existing file 'less.nro'"
  2153. else
  2154. sed 's/^X//' << \SHAR_EOF > 'less.nro'
  2155. X.TH LESS LOCAL
  2156. X.SH NAME
  2157. Xless \- opposite of more
  2158. X.SH SYNOPSIS
  2159. X.B "less [-cdepstwmMqQuU] [-h\fIN\fB] [-b[fp]\fIN\fB] [-x\fIN\fB] [-[z]\fIN\fB]"
  2160. X.br
  2161. X.B "     [-P[mM]\fIstring\fB] [-l\fIlogfile\fB] [+\fIcmd\fB]  [\fIfilename\fB]..."
  2162. X.SH DESCRIPTION
  2163. X.I Less
  2164. Xis a program similar to 
  2165. X.I more
  2166. X(1), but which allows backwards movement
  2167. Xin the file as well as forward movement.
  2168. XAlso,
  2169. X.I less
  2170. Xdoes not have to read the entire input file before starting,
  2171. Xso with large input files it starts up faster than text editors like
  2172. X.I vi
  2173. X(1).
  2174. X.I Less
  2175. Xuses termcap, so it can run on a variety of terminals.
  2176. XThere is even limited support for hardcopy terminals.
  2177. X(On a hardcopy terminal, lines which should be printed at the top
  2178. Xof the screen are prefixed with an up-arrow.)
  2179. X.PP
  2180. XCommands are based on both
  2181. X.I more
  2182. Xand
  2183. X.I vi.
  2184. XCommands may be preceeded by a decimal number, 
  2185. Xcalled N in the descriptions below.
  2186. XThe number is used by some commands, as indicated.
  2187. X
  2188. X.SH COMMANDS
  2189. XIn the following descriptions, ^X means control-X.
  2190. X.IP h
  2191. XHelp: display a summary of these commands.
  2192. XIf you forget all the other commands, remember this one.
  2193. X.PP
  2194. X.IP SPACE
  2195. XScroll forward N lines, default one window (see option \-z below).
  2196. XIf N is more than the screen size, only the final screenful is displayed.
  2197. X.PP
  2198. X.IP "f or ^F"
  2199. XSame as SPACE.
  2200. X.PP
  2201. X.IP "b or ^B"
  2202. XScroll backward N lines, default one window (see option \-z below).
  2203. XIf N is more than the screen size, only the final screenful is displayed.
  2204. X.PP
  2205. X.IP RETURN
  2206. XScroll forward N lines, default 1.
  2207. XThe entire N lines are displayed, even if N is more than the screen size.
  2208. X.PP
  2209. X.IP "e or ^E"
  2210. XSame as RETURN.
  2211. X.PP
  2212. X.IP "j or ^J"
  2213. XAlso the same as RETURN.
  2214. X.PP
  2215. X.IP "y or ^Y"
  2216. XScroll backward N lines, default 1.
  2217. XThe entire N lines are displayed, even if N is more than the screen size.
  2218. X.IP "k or ^K"
  2219. XSame as y.
  2220. X.PP
  2221. X.IP "d or ^D"
  2222. XScroll forward N lines, default 10.
  2223. XIf N is specified, it becomes the new default for 
  2224. Xsubsequent d and u commands.
  2225. X.PP
  2226. X.IP "u or ^U"
  2227. XScroll backward N lines, default 10.
  2228. XIf N is specified, it becomes the new default for 
  2229. Xsubsequent d and u commands.
  2230. X.PP
  2231. X.IP "r or ^R or ^L"
  2232. XRepaint the screen.
  2233. X.PP
  2234. X.IP R
  2235. XRepaint the screen, discarding any buffered input.
  2236. XUseful if the file is changing while it is being viewed.
  2237. X.PP
  2238. X.IP g
  2239. XGo to line N in the file, default 1 (beginning of file).
  2240. X(Warning: this may be slow if N is large.)
  2241. X.PP
  2242. X.IP G
  2243. XGo to line N in the file, default the end of the file.
  2244. X(Warning: this may be slow if standard input, 
  2245. Xrather than a file, is being read.)
  2246. X.PP
  2247. X.IP p
  2248. XGo to a position N percent into the file.
  2249. XN should be between 0 and 100.
  2250. X(This is possible if standard input is being read,
  2251. Xbut only if
  2252. X.I less
  2253. Xhas already read to the end of the file.
  2254. XIt is always fast, but not always useful.)
  2255. X.PP
  2256. X.IP %
  2257. XSame as p.
  2258. X.PP
  2259. X.IP m
  2260. XFollowed by any lowercase letter, 
  2261. Xmarks the current position with that letter.
  2262. X.PP
  2263. X.IP "'"
  2264. X(Single quote.)
  2265. XFollowed by any lowercase letter, returns to the position which
  2266. Xwas previously marked with that letter.
  2267. XFollowed by another single quote, returns to the postion at
  2268. Xwhich the last "large" movement command was executed.
  2269. XAll marks are lost when a new file is examined.
  2270. X.PP
  2271. X.IP /pattern
  2272. XSearch forward in the file for the N-th line containing the pattern.
  2273. XN defaults to 1.
  2274. XThe pattern is a regular expression, as recognized by
  2275. X.I ed.
  2276. XThe search starts at the second line displayed
  2277. X(but see the \-t option, which changes this).
  2278. X.PP
  2279. X.IP ?pattern
  2280. XSearch backward in the file for the N-th line containing the pattern.
  2281. XThe search starts at the line immediately before the top line displayed.
  2282. X.PP
  2283. X.IP n
  2284. XRepeat previous search, for N-th line containing the last pattern.
  2285. X.PP
  2286. X.IP E [filename]
  2287. XExamine a new file.
  2288. XIf the filename is missing, the "current" file (see the N and P commands
  2289. Xbelow) from the list of files in the command line is re-examined.
  2290. X.PP
  2291. X.IP N
  2292. XExamine the next file (from the list of files given in the command line).
  2293. XIf a number N is specified (not to be confused with the command N),
  2294. Xthe N-th next file is examined.
  2295. X.PP
  2296. X.IP P
  2297. XExamine the previous file.
  2298. XIf a number N is specified, the N-th previous file is examined.
  2299. X.PP
  2300. X.IP "= or ^G"
  2301. XPrints some information about the file being viewed,
  2302. Xincluding its name
  2303. Xand the byte offset of the bottom line being displayed.
  2304. XIf possible, it also prints the length of the file
  2305. Xand the percent of the file above the last displayed line.
  2306. X.PP
  2307. X.IP \-
  2308. XFollowed by one of the command line option letters (see below),
  2309. Xthis will toggle the setting of that option
  2310. Xand print a message describing the new setting.
  2311. X.PP
  2312. X.IP +cmd
  2313. XCauses the specified cmd to be executed each time a new file is examined.
  2314. XFor example, +G causes 
  2315. X.I less
  2316. Xto initially display each file starting at the end 
  2317. Xrather than the beginning.
  2318. X.PP
  2319. X.IP V
  2320. XPrints the version number of 
  2321. X.I less 
  2322. Xbeing run.
  2323. X.PP
  2324. X.IP q
  2325. XExits
  2326. X.I less.
  2327. X.PP
  2328. XThe following 
  2329. Xtwo 
  2330. Xcommands may or may not be valid, depending on your particular installation.
  2331. X.PP
  2332. X.IP v
  2333. XInvokes an editor to edit the current file being viewed.
  2334. XThe editor is taken from the environment variable EDITOR,
  2335. Xor defaults to "vi".
  2336. X.PP
  2337. X.IP "! shell-command"
  2338. XInvokes a shell to run the shell-command given.
  2339. X.PP
  2340. X.SH OPTIONS
  2341. XCommand line options are described below.
  2342. XMost options may be changed while
  2343. X.I less 
  2344. Xis running, via the "\-" command.
  2345. X.PP
  2346. XOptions are also taken from the environment variable "LESS".
  2347. XFor example, if you like 
  2348. Xmore-style prompting, to avoid typing "less \-m ..." each time 
  2349. X.I less 
  2350. Xis invoked, you might tell 
  2351. X.I csh:
  2352. X.sp
  2353. Xsetenv LESS m
  2354. X.sp
  2355. Xor if you use 
  2356. X.I sh:
  2357. X.sp
  2358. XLESS=m; export LESS
  2359. X.sp
  2360. XThe environment variable is parsed before the command line,
  2361. Xso command line options override the LESS environment variable.
  2362. XA dollar sign ($) may be used to signal the end of an option string.
  2363. XThis is important only for options like \-P which take a
  2364. Xfollowing string.
  2365. X.IP \-s
  2366. XThe \-s option causes
  2367. Xconsecutive blank lines to be squeezed into a single blank line.
  2368. XThis is useful when viewing
  2369. X.I nroff
  2370. Xoutput.
  2371. X.IP \-t
  2372. XNormally, forward searches start just after
  2373. Xthe top displayed line (that is, at the second displayed line).
  2374. XThus forward searches include the currently displayed screen.
  2375. XThe \-t option causes forward searches to start 
  2376. Xjust after the bottom line displayed,
  2377. Xthus skipping the currently displayed screen.
  2378. X.IP \-m
  2379. XNormally,
  2380. X.I less
  2381. Xprompts with a colon.
  2382. XThe \-m option causes 
  2383. X.I less
  2384. Xto prompt verbosely (like 
  2385. X.I more),
  2386. Xwith the percent into the file.
  2387. X.IP \-M
  2388. XThe \-M option causes 
  2389. X.I less
  2390. Xto prompt even more verbosely than 
  2391. X.I more.
  2392. X.IP \-P
  2393. XThe \-P option provides a way to tailor the three prompt
  2394. Xstyles to your own preference.
  2395. XYou would normally put this option in your LESS environment
  2396. Xvariable, rather than type it in with each less command.
  2397. XSuch an option must either be the last option in the LESS variable,
  2398. Xor be terminated by a dollar sign.
  2399. X\-P followed by a string changes the default (short) prompt to that string.
  2400. X\-Pm changes the medium (\-m) prompt to the string, and
  2401. X\-PM changes the long (\-M) prompt.
  2402. XThe string consists of a sequence of letters which are replaced
  2403. Xwith certain predefined strings, as follows:
  2404. X.br
  2405. X    F    file name
  2406. X.br
  2407. X    f    file name, only once
  2408. X.br
  2409. X    O    file n of n
  2410. X.br
  2411. X    o    file n of n, only once
  2412. X.br
  2413. X    b    byte offset
  2414. X.br
  2415. X    p    percent into file
  2416. X.br
  2417. X    P    percent if known, else byte offset
  2418. X.br
  2419. XAngle brackets, < and >, may be used to surround a
  2420. Xliteral string to be included in the prompt.
  2421. XThe defaults are "fo" for the short prompt,
  2422. X"foP" for the medium prompt, and
  2423. X"Fobp" for the long prompt.
  2424. X.br
  2425. XExample: Setting your LESS variable to "PmFOP$PMFObp"
  2426. Xwould change the medium and long prompts to always 
  2427. Xinclude the file name and "file n of n" message.
  2428. X.br
  2429. XAnother example: Setting your LESS variable to 
  2430. X.br
  2431. X"mPm<--Less-->FoPe"
  2432. Xwould change the medium prompt to the string "--Less--" followed
  2433. Xby the file name and percent into the file.
  2434. XIt also selects the medium
  2435. Xprompt as the default prompt (because of the first "m").
  2436. X.IP \-q
  2437. XNormally, if an attempt is made to scroll past the end of the file
  2438. Xor before the beginning of the file, the terminal bell is rung to
  2439. Xindicate this fact.
  2440. XThe \-q option tells
  2441. X.I less
  2442. Xnot to ring the bell at such times.
  2443. XIf the terminal has a "visual bell", it is used instead.
  2444. X.IP \-Q
  2445. XEven if \-q is given, 
  2446. X.I less 
  2447. Xwill ring the bell on certain other errors,
  2448. Xsuch as typing an invalid character.
  2449. XThe \-Q option tells
  2450. X.I less
  2451. Xto be quiet all the time; that is, never ring the terminal bell.
  2452. XIf the terminal has a "visual bell", it is used instead.
  2453. X.IP \-e
  2454. XNormally the only way to exit less is via the "q" command.
  2455. XThe \-e option tells less to automatically exit
  2456. Xthe second time it reaches end-of-file.
  2457. X.IP \-u
  2458. XIf the \-u option is given, 
  2459. Xbackspaces are treated as printable characters;
  2460. Xthat is, they are sent to the terminal when they appear in the input.
  2461. X.IP \-U
  2462. XIf the \-U option is given,
  2463. Xbackspaces are printed as the two character sequence "^H".
  2464. X.sp
  2465. XIf neither \-u nor \-U is given,
  2466. Xbackspaces which appear adjacent to an underscore character
  2467. Xare treated specially:
  2468. Xthe underlined text is displayed 
  2469. Xusing the terminal's hardware underlining capability.
  2470. XAlso, backspaces which appear between two identical characters
  2471. Xare treated specially: 
  2472. Xthe overstruck text is printed 
  2473. Xusing the terminal's hardware boldface capability.
  2474. XOther backspaces are deleted, along with the preceeding character.
  2475. X.IP \-w
  2476. XNormally,
  2477. X.I less
  2478. Xuses a tilde character to represent lines past the end of the file.
  2479. XThe \-w option causes blank lines to be used instead.
  2480. X.IP \-d
  2481. XNormally,
  2482. X.I less
  2483. Xwill complain if the terminal is dumb; that is, lacks some important capability,
  2484. Xsuch as the ability to clear the screen or scroll backwards.
  2485. XThe \-d option suppresses this complaint 
  2486. X(but does not otherwise change the behavior of the program on a dumb terminal).
  2487. X.IP \-p
  2488. XNormally, 
  2489. X.I less 
  2490. Xwill repaint the screen by scrolling from the bottom of the screen.
  2491. XIf the \-p option is set, when
  2492. X.I less 
  2493. Xneeds to change the entire display, it will clear the screen
  2494. Xand paint from the top line down.
  2495. X.IP \-h
  2496. XNormally,
  2497. X.I less
  2498. Xwill scroll backwards when backwards movement is necessary.
  2499. XThe \-h option specifies a maximum number of lines to scroll backwards.
  2500. XIf it is necessary to move backwards more than this many lines,
  2501. Xthe screen is repainted in a forward direction.
  2502. X(If the terminal does not have the ability to scroll
  2503. Xbackwards, \-h0 is implied.)
  2504. X.IP \-[z]
  2505. XWhen given a backwards or forwards window command,
  2506. X.I less
  2507. Xwill by
  2508. Xdefault scroll backwards or forwards one screenful of lines. 
  2509. XThe \-z\fIn\fR option changes the default scrolling window size 
  2510. Xto \fIn\fR lines.
  2511. XIf \fIn\fR is greater than the screen size, 
  2512. Xthe scrolling window size will be set to one screenful.  
  2513. XNote that the "z" is optional for compatibility with
  2514. X.I more.
  2515. X.IP -x
  2516. XThe -x\fIn\fR option sets tab stops every \fIn\fR positions.
  2517. XThe default for \fIn\fR is 8.
  2518. X.IP -l
  2519. XThe -l option, followed immediately by a filename,
  2520. Xwill cause 
  2521. X.I less
  2522. Xto copy its input to the named file as it is being viewed.
  2523. XThis applies only when the input file is a pipe,
  2524. Xnot an ordinary file.
  2525. X.IP -b
  2526. XThe -b\fIn\fR option tells
  2527. X.I less
  2528. Xto use a non-standard buffer size.
  2529. XThere are two standard (default) buffer sizes,
  2530. Xone is used when a file is being read and the other
  2531. Xwhen a pipe (standard input) is being read.
  2532. XThe current defaults are 5 buffers for files and 12 for pipes.
  2533. X(Buffers are 1024 bytes.)
  2534. XThe number \fIn\fR specifies a different number of buffers to use.
  2535. XThe -b may be followed by "f", in which case only 
  2536. Xthe file default is changed, or by "p" in which case only the 
  2537. Xpipe default is changed.  Otherwise, both are changed.
  2538. X.IP -c
  2539. XNormally, when data is read by
  2540. X.I less,
  2541. Xit is scanned to ensure that bit 7 (the high order bit) is turned off in
  2542. Xeach byte read, and to ensure that there are no null (zero) bytes in
  2543. Xthe data (null bytes are turned into "@" characters).
  2544. XIf the data is known to be "clean",
  2545. Xthe -c option will tell 
  2546. X.I less
  2547. Xto skip this checking, causing an imperceptible speed improvement.
  2548. X(However, if the data is not "clean", unpredicatable results may occur.)
  2549. X.IP +
  2550. XIf a command line option begins with \fB+\fR,
  2551. Xthe remainder of that option is taken to be an initial command to
  2552. X.I less.
  2553. XFor example, +G tells
  2554. X.I less
  2555. Xto start at the end of the file rather than the beginning,
  2556. Xand +/xyz tells it to start at the first occurence of "xyz" in the file.
  2557. XAs a special case, +<number> acts like +<number>g; 
  2558. Xthat is, it starts the display at the specified line number
  2559. X(however, see the caveat under the "g" command above).
  2560. XIf the option starts with \fB++\fR, the initial command applies to
  2561. Xevery file being viewed, not just the first one.
  2562. XThe + command described previously
  2563. Xmay also be used to set (or change) an initial command for every file.
  2564. X
  2565. X.SH BUGS
  2566. XWhen used on standard input (rather than a file), you can move
  2567. Xbackwards only a finite amount, corresponding to that portion
  2568. Xof the file which is still buffered.
  2569. XThe -b option may be used to expand the buffer space.
  2570. SHAR_EOF
  2571. fi
  2572. if test -f 'line.c'
  2573. then
  2574.     echo shar: "will not over-write existing file 'line.c'"
  2575. else
  2576. sed 's/^X//' << \SHAR_EOF > 'line.c'
  2577. X/*
  2578. X * Routines to manipulate the "line buffer".
  2579. X * The line buffer holds a line of output as it is being built
  2580. X * in preparation for output to the screen.
  2581. X * We keep track of the PRINTABLE length of the line as it is being built.
  2582. X */
  2583. X
  2584. X#include "less.h"
  2585. X
  2586. Xstatic char linebuf[1024];    /* Buffer which holds the current output line */
  2587. Xstatic char *curr;        /* Pointer into linebuf */
  2588. Xstatic int column;        /* Printable length, accounting for
  2589. X                   backspaces, etc. */
  2590. X/*
  2591. X * A ridiculously complex state machine takes care of backspaces 
  2592. X * when in BS_SPECIAL mode.  The complexity arises from the attempt
  2593. X * to deal with all cases, especially involving long lines with underlining,
  2594. X * boldfacing or whatever.  There are still some cases which will break it.
  2595. X *
  2596. X * There are four states:
  2597. X *    LN_NORMAL is the normal state (not in underline mode).
  2598. X *    LN_UNDERLINE means we are in underline mode.  We expect to get
  2599. X *        either a sequence like "_\bX" or "X\b_" to continue
  2600. X *        underline mode, or anything else to end underline mode.
  2601. X *    LN_BOLDFACE means we are in boldface mode.  We expect to get sequences
  2602. X *        like "X\bX\b...X\bX" to continue boldface mode, or anything
  2603. X *        else to end boldface mode.
  2604. X *    LN_UL_X means we are one character after LN_UNDERLINE
  2605. X *        (we have gotten the '_' in "_\bX" or the 'X' in "X\b_").
  2606. X *    LN_UL_XB means we are one character after LN_UL_X 
  2607. X *        (we have gotten the backspace in "_\bX" or "X\b_";
  2608. X *        we expect one more ordinary character, 
  2609. X *        which will put us back in state LN_UNDERLINE).
  2610. X *    LN_BO_X means we are one character after LN_BOLDFACE
  2611. X *        (we have gotten the 'X' in "X\bX").
  2612. X *    LN_BO_XB means we are one character after LN_BO_X
  2613. X *        (we have gotten the backspace in "X\bX";
  2614. X *        we expect one more 'X' which will put us back
  2615. X *        in LN_BOLDFACE).
  2616. X */
  2617. Xstatic int ln_state;        /* Currently in normal/underline/bold/etc mode? */
  2618. X#define    LN_NORMAL    0    /* Not in underline, boldface or whatever mode */
  2619. X#define    LN_UNDERLINE    1    /* In underline, need next char */
  2620. X#define    LN_UL_X        2    /* In underline, got char, need \b */
  2621. X#define    LN_UL_XB    3    /* In underline, got char & \b, need one more */
  2622. X#define    LN_BOLDFACE    4    /* In boldface, need next char */
  2623. X#define    LN_BO_X        5    /* In boldface, got char, need \b */
  2624. X#define    LN_BO_XB    6    /* In boldface, got char & \b, need same char */
  2625. X
  2626. Xpublic char *line;        /* Pointer to the current line.
  2627. X                   Usually points to linebuf. */
  2628. X
  2629. Xextern int bs_mode;
  2630. Xextern int tabstop;
  2631. Xextern int bo_width, be_width;
  2632. Xextern int ul_width, ue_width;
  2633. Xextern int sc_width, sc_height;
  2634. X
  2635. X/*
  2636. X * Rewind the line buffer.
  2637. X */
  2638. X    public void
  2639. Xprewind()
  2640. X{
  2641. X    line = curr = linebuf;
  2642. X    ln_state = LN_NORMAL;
  2643. X    column = 0;
  2644. X}
  2645. X
  2646. X/*
  2647. X * Append a character to the line buffer.
  2648. X * Expand tabs into spaces, handle underlining, boldfacing, etc.
  2649. X * Returns 0 if ok, 1 if couldn't fit in buffer.
  2650. X */
  2651. X
  2652. X#define    NEW_COLUMN(newcol)    if ((newcol) + ((ln_state)?ue_width:0) > sc_width) \
  2653. X                    return (1); else column = (newcol)
  2654. X
  2655. X    public int
  2656. Xpappend(c)
  2657. X    int c;
  2658. X{
  2659. X    if (c == '\0')
  2660. X    {
  2661. X        /*
  2662. X         * Terminate any special modes, if necessary.
  2663. X         * Append a '\0' to the end of the line.
  2664. X         */
  2665. X        switch (ln_state)
  2666. X        {
  2667. X        case LN_UL_X:
  2668. X            curr[0] = curr[-1];
  2669. X            curr[-1] = UE_CHAR;
  2670. X            curr++;
  2671. X            break;
  2672. X        case LN_BO_X:
  2673. X            curr[0] = curr[-1];
  2674. X            curr[-1] = BE_CHAR;
  2675. X            curr++;
  2676. X            break;
  2677. X        case LN_UL_XB:
  2678. X        case LN_UNDERLINE:
  2679. X            *curr++ = UE_CHAR;
  2680. X            break;
  2681. X        case LN_BO_XB:
  2682. X        case LN_BOLDFACE:
  2683. X            *curr++ = BE_CHAR;
  2684. X            break;
  2685. X        }
  2686. X        ln_state = LN_NORMAL;
  2687. X        *curr = '\0';
  2688. X        return (0);
  2689. X    }
  2690. X
  2691. X    if (curr > linebuf + sizeof(linebuf) - 12)
  2692. X        /*
  2693. X         * Almost out of room in the line buffer.
  2694. X         * Don't take any chances.
  2695. X         * {{ Linebuf is supposed to be big enough that this
  2696. X         *    will never happen, but may need to be made 
  2697. X         *    bigger for wide screens or lots of backspaces. }}
  2698. X         */
  2699. X        return (1);
  2700. X
  2701. X    if (bs_mode == BS_SPECIAL)
  2702. X    {
  2703. X        /*
  2704. X         * Advance the state machine.
  2705. X         */
  2706. X        switch (ln_state)
  2707. X        {
  2708. X        case LN_NORMAL:
  2709. X            if (curr <= linebuf + 1 || curr[-1] != '\b')
  2710. X                break;
  2711. X
  2712. X            if (c == curr[-2])
  2713. X                goto enter_boldface;
  2714. X            if (c == '_' || curr[-2] == '_')
  2715. X                goto enter_underline;
  2716. X            curr -= 2;
  2717. X            break;
  2718. X
  2719. Xenter_boldface:
  2720. X            /*
  2721. X             * We have "X\bX" (including the current char).
  2722. X             * Switch into boldface mode.
  2723. X             */
  2724. X            if (column + bo_width + be_width + 1 >= sc_width)
  2725. X                /*
  2726. X                 * Not enough room left on the screen to 
  2727. X                 * enter and exit boldface mode.
  2728. X                 */
  2729. X                return (1);
  2730. X
  2731. X            if (bo_width > 0 && 
  2732. X                curr > linebuf + 2 && curr[-3] == ' ')
  2733. X            {
  2734. X                /*
  2735. X                 * Special case for magic cookie terminals:
  2736. X                 * if the previous char was a space, replace 
  2737. X                 * it with the "enter boldface" sequence.
  2738. X                 */
  2739. X                curr[-3] = BO_CHAR;
  2740. X                column += bo_width-1;
  2741. X            } else
  2742. X            {
  2743. X                curr[-1] = curr[-2];
  2744. X                curr[-2] = BO_CHAR;
  2745. X                column += bo_width;
  2746. X                curr++;
  2747. X            }
  2748. X            goto ln_bo_xb_case;
  2749. X
  2750. Xenter_underline:
  2751. X            /*
  2752. X             * We have either "_\bX" or "X\b_" (including
  2753. X             * the current char).  Switch into underline mode.
  2754. X             */
  2755. X            if (column + ul_width + ue_width + 1 >= sc_width)
  2756. X                /*
  2757. X                 * Not enough room left on the screen to 
  2758. X                 * enter and exit underline mode.
  2759. X                 */
  2760. X                return (1);
  2761. X
  2762. X            if (ul_width > 0 && 
  2763. X                curr > linebuf + 2 && curr[-3] == ' ')
  2764. X            {
  2765. X                /*
  2766. X                 * Special case for magic cookie terminals:
  2767. X                 * if the previous char was a space, replace 
  2768. X                 * it with the "enter underline" sequence.
  2769. X                 */
  2770. X                curr[-3] = UL_CHAR;
  2771. X                column += ul_width-1;
  2772. X            } else
  2773. X            {
  2774. X                curr[-1] = curr[-2];
  2775. X                curr[-2] = UL_CHAR;
  2776. X                column += ul_width;
  2777. X                curr++;
  2778. X            }
  2779. X            goto ln_ul_xb_case;
  2780. X            /*NOTREACHED*/
  2781. X        case LN_UL_XB:
  2782. X            /*
  2783. X             * Termination of a sequence "_\bX" or "X\b_".
  2784. X             */
  2785. X            if (c != '_' && curr[-2] != '_' && c == curr[-2])
  2786. X            {
  2787. X                /*
  2788. X                 * We seem to have run on from underlining
  2789. X                 * into boldfacing - this is a nasty fix, but
  2790. X                 * until this whole routine is rewritten as a
  2791. X                 * real DFA, ...  well ...
  2792. X                 */
  2793. X                curr[0] = curr[-2];
  2794. X                curr[-2] = UE_CHAR;
  2795. X                curr[-1] = BO_CHAR;
  2796. X                curr += 2; /* char & non-existent backspace */
  2797. X                ln_state = LN_BO_XB;
  2798. X                goto ln_bo_xb_case;
  2799. X            }
  2800. Xln_ul_xb_case:
  2801. X            if (c == '_')
  2802. X                c = curr[-2];
  2803. X            curr -= 2;
  2804. X            ln_state = LN_UNDERLINE;
  2805. X            break;
  2806. X        case LN_BO_XB:
  2807. X            /*
  2808. X             * Termination of a sequnce "X\bX".
  2809. X             */
  2810. X            if (c != curr[-2] && (c == '_' || curr[-2] == '_'))
  2811. X            {
  2812. X                /*
  2813. X                 * We seem to have run on from
  2814. X                 * boldfacing into underlining.
  2815. X                 */
  2816. X                curr[0] = curr[-2];
  2817. X                curr[-2] = BE_CHAR;
  2818. X                curr[-1] = UL_CHAR;
  2819. X                curr += 2; /* char & non-existent backspace */
  2820. X                ln_state = LN_UL_XB;
  2821. X                goto ln_ul_xb_case;
  2822. X            }
  2823. Xln_bo_xb_case:
  2824. X            curr -= 2;
  2825. X            ln_state = LN_BOLDFACE;
  2826. X            break;
  2827. X        case LN_UNDERLINE:
  2828. X            if (column + ue_width + bo_width + 1 + be_width >= sc_width)
  2829. X                /*
  2830. X                 * We have just barely enough room to 
  2831. X                 * exit underline mode and handle a possible
  2832. X                 * underline/boldface run on mixup.
  2833. X                 */
  2834. X                return (1);
  2835. X            ln_state = LN_UL_X;
  2836. X            break;
  2837. X        case LN_BOLDFACE:
  2838. X            if (c == '\b')
  2839. X            {
  2840. X                ln_state = LN_BO_XB;
  2841. X                break;
  2842. X            }
  2843. X            if (column + be_width + ul_width + 1 + ue_width >= sc_width)
  2844. X                /*
  2845. X                 * We have just barely enough room to 
  2846. X                 * exit underline mode and handle a possible
  2847. X                 * underline/boldface run on mixup.
  2848. X                 */
  2849. X                return (1);
  2850. X            ln_state = LN_BO_X;
  2851. X            break;
  2852. X        case LN_UL_X:
  2853. X            if (c == '\b')
  2854. X                ln_state = LN_UL_XB;
  2855. X            else
  2856. X            {
  2857. X                /*
  2858. X                 * Exit underline mode.
  2859. X                 * We have to shuffle the chars a bit
  2860. X                 * to make this work.
  2861. X                 */
  2862. X                curr[0] = curr[-1];
  2863. X                curr[-1] = UE_CHAR;
  2864. X                column += ue_width;
  2865. X                if (ue_width > 0 && curr[0] == ' ')
  2866. X                    /*
  2867. X                     * Another special case for magic
  2868. X                     * cookie terminals: if the next
  2869. X                     * char is a space, replace it
  2870. X                     * with the "exit underline" sequence.
  2871. X                     */
  2872. X                    column--;
  2873. X                else
  2874. X                    curr++;
  2875. X                ln_state = LN_NORMAL;
  2876. X            } 
  2877. X            break;
  2878. X        case LN_BO_X:
  2879. X            if (c == '\b')
  2880. X                ln_state = LN_BO_XB;
  2881. X            else
  2882. X            {
  2883. X                /*
  2884. X                 * Exit boldface mode.
  2885. X                 * We have to shuffle the chars a bit
  2886. X                 * to make this work.
  2887. X                 */
  2888. X                curr[0] = curr[-1];
  2889. X                curr[-1] = BE_CHAR;
  2890. X                column += be_width;
  2891. X                if (be_width > 0 && curr[0] == ' ')
  2892. X                    /*
  2893. X                     * Another special case for magic
  2894. X                     * cookie terminals: if the next
  2895. X                     * char is a space, replace it
  2896. X                     * with the "exit boldface" sequence.
  2897. X                     */
  2898. X                    column--;
  2899. X                else
  2900. X                    curr++;
  2901. X                ln_state = LN_NORMAL;
  2902. X            } 
  2903. X            break;
  2904. X        }
  2905. X    }
  2906. X    
  2907. X    if (c == '\t') 
  2908. X    {
  2909. X        /*
  2910. X         * Expand a tab into spaces.
  2911. X         */
  2912. X        do
  2913. X        {
  2914. X            NEW_COLUMN(column+1);
  2915. X        } while ((column % tabstop) != 0);
  2916. X        *curr++ = '\t';
  2917. X        return (0);
  2918. X    }
  2919. X
  2920. X    if (c == '\b')
  2921. X    {
  2922. X        if (bs_mode == BS_CONTROL)
  2923. X        {
  2924. X            /*
  2925. X             * Treat backspace as a control char: output "^H".
  2926. X             */
  2927. X            NEW_COLUMN(column+2);
  2928. X            *curr++ = ('H' | 0200);
  2929. X        } else
  2930. X        {
  2931. X            /*
  2932. X             * Output a real backspace.
  2933. X             */
  2934. X            column--;
  2935. X            *curr++ = '\b';
  2936. X        }
  2937. X        return (0);
  2938. X    } 
  2939. X
  2940. X    if (control_char(c))
  2941. X    {
  2942. X        /*
  2943. X         * Put a "^X" into the buffer.
  2944. X         * The 0200 bit is used to tell put_line() to prefix
  2945. X         * the char with a ^.  We don't actually put the ^
  2946. X         * in the buffer because we sometimes need to move
  2947. X         * chars around, and such movement might separate 
  2948. X         * the ^ from its following character.
  2949. X         * {{ This should be redone so that we can use an
  2950. X         *    8 bit (e.g. international) character set. }}
  2951. X         */
  2952. X        NEW_COLUMN(column+2);
  2953. X        *curr++ = (carat_char(c) | 0200);
  2954. X        return (0);
  2955. X    }
  2956. X
  2957. X    /*
  2958. X     * Ordinary character.  Just put it in the buffer.
  2959. X     */
  2960. X    NEW_COLUMN(column+1);
  2961. X    *curr++ = c;
  2962. X    return (0);
  2963. X}
  2964. X
  2965. X/*
  2966. X * Analogous to forw_line(), but deals with "raw lines":
  2967. X * lines which are not split for screen width.
  2968. X * {{ This is supposed to be more efficient than forw_line(). }}
  2969. X */
  2970. X    public POSITION
  2971. Xforw_raw_line(curr_pos)
  2972. X    POSITION curr_pos;
  2973. X{
  2974. X    register char *p;
  2975. X    register int c;
  2976. X    POSITION new_pos;
  2977. X
  2978. X    if (curr_pos == NULL_POSITION || ch_seek(curr_pos) ||
  2979. X        (c = ch_forw_get()) == EOF)
  2980. X        return (NULL_POSITION);
  2981. X
  2982. X    p = linebuf;
  2983. X
  2984. X    for (;;)
  2985. X    {
  2986. X        if (c == '\n' || c == EOF)
  2987. X        {
  2988. X            new_pos = ch_tell();
  2989. X            break;
  2990. X        }
  2991. X        if (p >= &linebuf[sizeof(linebuf)-1])
  2992. X        {
  2993. X            /*
  2994. X             * Overflowed the input buffer.
  2995. X             * Pretend the line ended here.
  2996. X             * {{ The line buffer is supposed to be big
  2997. X             *    enough that this never happens. }}
  2998. X             */
  2999. X            new_pos = ch_tell() - 1;
  3000. X            break;
  3001. X        }
  3002. X        *p++ = c;
  3003. X        c = ch_forw_get();
  3004. X    }
  3005. X    *p = '\0';
  3006. X    line = linebuf;
  3007. X    return (new_pos);
  3008. X}
  3009. X
  3010. X/*
  3011. X * Analogous to back_line(), but deals with "raw lines".
  3012. X * {{ This is supposed to be more efficient than back_line(). }}
  3013. X */
  3014. X    public POSITION
  3015. Xback_raw_line(curr_pos)
  3016. X    POSITION curr_pos;
  3017. X{
  3018. X    register char *p;
  3019. X    register int c;
  3020. X    POSITION new_pos;
  3021. X
  3022. X    if (curr_pos == NULL_POSITION || curr_pos <= (POSITION)0 ||
  3023. X        ch_seek(curr_pos-1))
  3024. X        return (NULL_POSITION);
  3025. X
  3026. X    p = &linebuf[sizeof(linebuf)];
  3027. X    *--p = '\0';
  3028. X
  3029. X    for (;;)
  3030. X    {
  3031. X        c = ch_back_get();
  3032. X        if (c == '\n')
  3033. X        {
  3034. X            /*
  3035. X             * This is the newline ending the previous line.
  3036. X             * We have hit the beginning of the line.
  3037. X             */
  3038. X            new_pos = ch_tell() + 1;
  3039. X            break;
  3040. X        }
  3041. X        if (c == EOF)
  3042. X        {
  3043. X            /*
  3044. X             * We have hit the beginning of the file.
  3045. X             * This must be the first line in the file.
  3046. X             * This must, of course, be the beginning of the line.
  3047. X             */
  3048. X            new_pos = (POSITION)0;
  3049. X            break;
  3050. X        }
  3051. X        if (p <= linebuf)
  3052. X        {
  3053. X            /*
  3054. X             * Overflowed the input buffer.
  3055. X             * Pretend the line ended here.
  3056. X             */
  3057. X            new_pos = ch_tell() + 1;
  3058. X            break;
  3059. X        }
  3060. X        *--p = c;
  3061. X    }
  3062. X    line = p;
  3063. X    return (new_pos);
  3064. X}
  3065. SHAR_EOF
  3066. fi
  3067. if test -f 'main.c'
  3068. then
  3069.     echo shar: "will not over-write existing file 'main.c'"
  3070. else
  3071. sed 's/^X//' << \SHAR_EOF > 'main.c'
  3072. X/*
  3073. X * Entry point, initialization, miscellaneous routines.
  3074. X */
  3075. X
  3076. X#include "less.h"
  3077. X#include "position.h"
  3078. X#include <setjmp.h>
  3079. X
  3080. Xpublic int    ispipe;
  3081. Xpublic jmp_buf    main_loop;
  3082. Xpublic char *    first_cmd;
  3083. Xpublic char *    every_first_cmd;
  3084. Xpublic int    new_file;
  3085. Xpublic int    is_tty;
  3086. Xpublic char     current_file[128];
  3087. Xpublic int    any_display;
  3088. Xpublic int    ac;
  3089. Xpublic char **    av;
  3090. Xpublic int     curr_ac;
  3091. X#if LOGFILE
  3092. Xpublic int    logfile = -1;
  3093. Xpublic char *    namelogfile = NULL;
  3094. X#endif
  3095. X#if EDITOR
  3096. Xpublic char *    editor;
  3097. X#endif
  3098. X
  3099. Xextern int file;
  3100. Xextern int nbufs;
  3101. Xextern int sigs;
  3102. Xextern int quit_at_eof;
  3103. Xextern int p_nbufs, f_nbufs;
  3104. Xextern int back_scroll;
  3105. Xextern int top_scroll;
  3106. Xextern int sc_height;
  3107. Xextern int errmsgs;
  3108. X
  3109. X
  3110. X/*
  3111. X * Edit a new file.
  3112. X * Filename "-" means standard input.
  3113. X * No filename means the "current" file, from the command line.
  3114. X */
  3115. X    public void
  3116. Xedit(filename)
  3117. X    char *filename;
  3118. X{
  3119. X    register int f;
  3120. X    char message[100];
  3121. X    static didpipe;
  3122. X
  3123. X    if (filename == NULL || *filename == '\0')
  3124. X    {
  3125. X        if (curr_ac >= ac)
  3126. X        {
  3127. X            error("No current file");
  3128. X            return;
  3129. X        }
  3130. X        filename = av[curr_ac];
  3131. X    }
  3132. X    if (strcmp(filename, "-") == 0)
  3133. X    {
  3134. X        /* 
  3135. X         * Use standard input.
  3136. X         */
  3137. X        if (didpipe)
  3138. X        {
  3139. X            error("Can view standard input only once");
  3140. X            return;
  3141. X        }
  3142. X        f = 0;
  3143. X    } else if ((f = open(filename, 0)) < 0)
  3144. X    {
  3145. X        static char co[] = "Cannot open ";
  3146. X        strcpy(message, co);
  3147. X        strtcpy(message+sizeof(co)-1, filename, 
  3148. X            sizeof(message)-sizeof(co));
  3149. X        error(message);
  3150. X        return;
  3151. X    }
  3152. X
  3153. X    if (isatty(f))
  3154. X    {
  3155. X        /*
  3156. X         * Not really necessary to call this an error,
  3157. X         * but if the control terminal (for commands)
  3158. X         * and the input file (for data) are the same,
  3159. X         * we get weird results at best.
  3160. X         */
  3161. X        error("Can't take input from a terminal");
  3162. X        if (f > 0)
  3163. X            close(f);
  3164. X        return;
  3165. X    }
  3166. X
  3167. X#if LOGFILE
  3168. X    /*
  3169. X     * If he asked for a log file and we have opened standard input,
  3170. X     * create the log file.  
  3171. X     * We take care not to blindly overwrite an existing file.
  3172. X     */
  3173. X    end_logfile();
  3174. X    if (f == 0 && namelogfile != NULL && is_tty)
  3175. X    {
  3176. X        int exists;
  3177. X        int answer;
  3178. X
  3179. X        /*
  3180. X         * {{ We could use access() here. }}
  3181. X         */
  3182. X        exists = open(namelogfile, 0);
  3183. X        close(exists);
  3184. X        exists = (exists >= 0);
  3185. X
  3186. X        if (exists)
  3187. X        {
  3188. X            static char w[] = "WARNING: log file exists: ";
  3189. X            strcpy(message, w);
  3190. X            strtcpy(message+sizeof(w)-1, namelogfile,
  3191. X                sizeof(message)-sizeof(w));
  3192. X            error(message);
  3193. X            answer = 'X';    /* Ask the user what to do */
  3194. X        } else
  3195. X            answer = 'O';    /* Create the log file */
  3196. X
  3197. X    loop:
  3198. X        switch (answer)
  3199. X        {
  3200. X        case 'O': case 'o':
  3201. X            logfile = creat(namelogfile, 0644);
  3202. X            break;
  3203. X        case 'A': case 'a':
  3204. X            logfile = open(namelogfile, 1);
  3205. X            if (lseek(logfile, (off_t)0, 2) < 0)
  3206. X            {
  3207. X                close(logfile);
  3208. X                logfile = -1;
  3209. X            }
  3210. X            break;
  3211. X        case 'D': case 'd':
  3212. X            answer = 0;    /* Don't print an error message */
  3213. X            break;
  3214. X        case 'q':
  3215. X            quit();
  3216. X        default:
  3217. X            puts("\n  Overwrite, Append, or Don't log? ");
  3218. X            answer = getc();
  3219. X            puts("\n");
  3220. X            flush();
  3221. X            goto loop;
  3222. X        }
  3223. X
  3224. X        if (logfile < 0 && answer != 0)
  3225. X        {
  3226. X            sprintf(message, "Cannot write to \"%s\"", 
  3227. X                namelogfile);
  3228. X            error(message);
  3229. X        }
  3230. X    }
  3231. X#endif
  3232. X
  3233. X    /*
  3234. X     * We are now committed to using the new file.
  3235. X     * Close the current input file and set up to use the new one.
  3236. X     */
  3237. X    if (file > 0)
  3238. X        close(file);
  3239. X    new_file = 1;
  3240. X    strtcpy(current_file, filename, sizeof(current_file));
  3241. X    ispipe = (f == 0);
  3242. X    if (ispipe)
  3243. X        didpipe = 1;
  3244. X    file = f;
  3245. X    ch_init( (ispipe) ? p_nbufs : f_nbufs );
  3246. X    init_mark();
  3247. X
  3248. X    if (every_first_cmd != NULL)
  3249. X        first_cmd = every_first_cmd;
  3250. X
  3251. X    if (is_tty)
  3252. X    {
  3253. X        int no_display = !any_display;
  3254. X        any_display = 1;
  3255. X        if (no_display && errmsgs > 0)
  3256. X        {
  3257. X            /*
  3258. X             * We displayed some messages on error output
  3259. X             * (file descriptor 2; see error() function).
  3260. X             * Before erasing the screen contents,
  3261. X             * display the file name and wait for a keystroke.
  3262. X             */
  3263. X            error(filename);
  3264. X        }
  3265. X        /*
  3266. X         * Indicate there is nothing displayed yet.
  3267. X         */
  3268. X        pos_clear();
  3269. X    }
  3270. X}
  3271. X
  3272. X/*
  3273. X * Edit the next file in the command line list.
  3274. X */
  3275. X    public void
  3276. Xnext_file(n)
  3277. X    int n;
  3278. X{
  3279. X    if (curr_ac + n >= ac)
  3280. X    {
  3281. X        if (quit_at_eof)
  3282. X            quit();
  3283. X        error("No (N-th) next file");
  3284. X    } else
  3285. X        edit(av[curr_ac += n]);
  3286. X}
  3287. X
  3288. X/*
  3289. X * Edit the previous file in the command line list.
  3290. X */
  3291. X    public void
  3292. Xprev_file(n)
  3293. X    int n;
  3294. X{
  3295. X    if (curr_ac - n < 0)
  3296. X        error("No (N-th) previous file");
  3297. X    else
  3298. X        edit(av[curr_ac -= n]);
  3299. X}
  3300. X
  3301. X/*
  3302. X * Copy a file directly to standard output.
  3303. X * Used if standard output is not a tty.
  3304. X */
  3305. X    static void
  3306. Xcat_file()
  3307. X{
  3308. X    register int c;
  3309. X
  3310. X    while ((c = ch_forw_get()) != EOF)
  3311. X        putc(c);
  3312. X    flush();
  3313. X}
  3314. X
  3315. X/*
  3316. X * Entry point.
  3317. X */
  3318. Xmain(argc, argv)
  3319. X    int argc;
  3320. X    char *argv[];
  3321. X{
  3322. X    char *getenv();
  3323. X
  3324. X
  3325. X    /*
  3326. X     * Process command line arguments and LESS environment arguments.
  3327. X     * Command line arguments override environment arguments.
  3328. X     */
  3329. X    init_option();
  3330. X    scan_option(getenv("LESS"));
  3331. X    argv++;
  3332. X    while ( (--argc > 0) && 
  3333. X        (argv[0][0] == '-' || argv[0][0] == '+') && 
  3334. X        argv[0][1] != '\0')
  3335. X        scan_option(*argv++);
  3336. X
  3337. X#if EDITOR
  3338. X    editor = getenv("EDITOR");
  3339. X    if (editor == NULL || *editor == '\0')
  3340. X        editor = EDIT_PGM;
  3341. X#endif
  3342. X
  3343. X    /*
  3344. X     * Set up list of files to be examined.
  3345. X     */
  3346. X    ac = argc;
  3347. X    av = argv;
  3348. X    curr_ac = 0;
  3349. X
  3350. X    /*
  3351. X     * Set up terminal, etc.
  3352. X     */
  3353. X    is_tty = isatty(1);
  3354. X    if (!is_tty)
  3355. X    {
  3356. X        /*
  3357. X         * Output is not a tty.
  3358. X         * Just copy the input file(s) to output.
  3359. X         */
  3360. X        if (ac < 1)
  3361. X        {
  3362. X            edit("-");
  3363. X            cat_file();
  3364. X        } else
  3365. X        {
  3366. X            do
  3367. X            {
  3368. X                edit((char *)NULL);
  3369. X                if (file >= 0)
  3370. X                    cat_file();
  3371. X            } while (++curr_ac < ac);
  3372. X        }
  3373. X        exit(0);
  3374. X    }
  3375. X
  3376. X    raw_mode(1);
  3377. X    get_term();
  3378. X    open_getc();
  3379. X    init();
  3380. X
  3381. X    if (setjmp(main_loop))
  3382. X        quit();
  3383. X    init_signals();
  3384. X
  3385. X    /*
  3386. X     * Select the first file to examine.
  3387. X     */
  3388. X    if (ac < 1)
  3389. X        edit("-");    /* Standard input */
  3390. X    else 
  3391. X    {
  3392. X        /*
  3393. X         * Try all the files named as command arguments.
  3394. X         * We are simply looking for one which can be
  3395. X         * opened without error.
  3396. X         */
  3397. X        do
  3398. X        {
  3399. X            edit((char *)NULL);
  3400. X        } while (file < 0 && ++curr_ac < ac);
  3401. X    }
  3402. X
  3403. X    if (file >= 0)
  3404. X        commands();
  3405. X    quit();
  3406. X}
  3407. X
  3408. X/*
  3409. X * Copy a string, truncating to the specified length if necessary.
  3410. X * Unlike strncpy(), the resulting string is guaranteed to be null-terminated.
  3411. X */
  3412. Xstrtcpy(to, from, len)
  3413. X    char *to;
  3414. X    char *from;
  3415. X    int len;
  3416. X{
  3417. X    strncpy(to, from, len);
  3418. X    to[len-1] = '\0';
  3419. X}
  3420. X
  3421. X/*
  3422. X * Exit the program.
  3423. X */
  3424. X    public void
  3425. Xquit()
  3426. X{
  3427. X    /*
  3428. X     * Put cursor at bottom left corner, clear the line,
  3429. X     * reset the terminal modes, and exit.
  3430. X     */
  3431. X#if LOGFILE
  3432. X    end_logfile();
  3433. X#endif
  3434. X    lower_left();
  3435. X    clear_eol();
  3436. X    deinit();
  3437. X    flush();
  3438. X    raw_mode(0);
  3439. X    exit(0);
  3440. X}
  3441. SHAR_EOF
  3442. fi
  3443. if test -f 'makefile'
  3444. then
  3445.     echo shar: "will not over-write existing file 'makefile'"
  3446. else
  3447. sed 's/^X//' << \SHAR_EOF > 'makefile'
  3448. X# Makefile for "less"
  3449. X#
  3450. X# Invoked as:
  3451. X#    make all
  3452. X#   or    make install
  3453. X# Plain "make" is equivalent to "make all".
  3454. X#
  3455. X# If you add or delete functions, remake funcs.h by doing:
  3456. X#    make newfuncs
  3457. X# This depends on the coding convention of function headers looking like:
  3458. X#    " \t public <function-type> \n <function-name> ( ... ) "
  3459. X#
  3460. X# Also provided:
  3461. X#    make lint    # Runs "lint" on all the sources.
  3462. X#    make clean    # Removes "less" and the .o files.
  3463. X#    make clobber    # Pretty much the same as make "clean".
  3464. X
  3465. X
  3466. X##########################################################################
  3467. X# System-specific parameters
  3468. X##########################################################################
  3469. X
  3470. X# Define XENIX if running under XENIX 3.0
  3471. XXENIX = 0
  3472. X
  3473. X# VOID is 1 if your C compiler supports the "void" type,
  3474. X# 0 if it does not.
  3475. XVOID = 1
  3476. X
  3477. X# off_t is the type which lseek() returns.
  3478. X# It is also the type of lseek()'s second argument.
  3479. Xoff_t = long
  3480. X
  3481. X# TERMIO is 1 if your system has /usr/include/termio.h.
  3482. X# This is normally the case for System 5.
  3483. X# If TERMIO is 0 your system must have /usr/include/sgtty.h.
  3484. X# This is normally the case for BSD.
  3485. XTERMIO = 0
  3486. X
  3487. X# SIGSETMASK is 1 if your system has the sigsetmask() call.
  3488. X# This is normally the case only for BSD 4.2,
  3489. X# not for BSD 4.1 or System 5.
  3490. XSIGSETMASK = 1
  3491. X
  3492. X##########################################################################
  3493. X# Optional and semi-optional features
  3494. X##########################################################################
  3495. X
  3496. X# REGCMP is 1 if your system has the regcmp() function.
  3497. X# This is normally the case for System 5.
  3498. X# RECOMP is 1 if your system has the re_comp() function.
  3499. X# This is normally the case for BSD.
  3500. X# If neither is 1, pattern matching is supported, but without metacharacters.
  3501. XREGCMP = 0
  3502. XRECOMP = 1
  3503. X
  3504. X# SHELL_ESCAPE is 1 if you wish to allow shell escapes.
  3505. X# (This is possible only if your system supplies the system() function.)
  3506. XSHELL_ESCAPE = 1
  3507. X
  3508. X# EDITOR is 1 if you wish to allow editor invocation (the "v" command).
  3509. X# (This is possible only if your system supplies the system() function.)
  3510. X# EDIT_PGM is the name of the (default) editor to be invoked.
  3511. XEDITOR = 1
  3512. XEDIT_PGM = vi
  3513. X
  3514. X# GLOB is 1 if you wish to have shell metacharacters expanded in filenames.
  3515. X# This will generally work if your system provides the "popen" function
  3516. X# and the "echo" shell command.
  3517. XGLOB = 1
  3518. X
  3519. X# LOGFILE is 1 if you wish to allow the -l option (to create log files).
  3520. XLOGFILE = 1
  3521. X
  3522. X# ONLY_RETURN is 1 if you want RETURN to be the only input which
  3523. X# will continue past an error message.
  3524. X# Otherwise, any key will continue past an error message.
  3525. XONLY_RETURN = 0
  3526. X
  3527. X
  3528. X##########################################################################
  3529. X# Compilation environment.
  3530. X##########################################################################
  3531. X
  3532. X# LIBS is the list of libraries needed.
  3533. XLIBS = -ltermcap
  3534. X
  3535. X# INSTALL_LESS is a list of the public versions of less.
  3536. X# INSTALL_HELP is a list of the public version of the help file.
  3537. X# INSTALL_MAN is a list of the public versions of the manual page.
  3538. XINSTALL_LESS =    /usr/local/less
  3539. XINSTALL_HELP =    /usr/local/lib/less.help
  3540. XINSTALL_MAN =    /usr/local/man/cat1/less.0
  3541. XMANUAL =    less.nro
  3542. XHELPFILE =    /usr/local/lib/less.help
  3543. X
  3544. X
  3545. X# OPTIM is passed to the compiler and the loader.
  3546. X# It is normally "-O" but may be, for example, "-g".
  3547. XOPTIM = -O -i
  3548. X
  3549. X
  3550. X##########################################################################
  3551. X# Files
  3552. X##########################################################################
  3553. X
  3554. XSRC1 =    main.c option.c prim.c ch.c position.c input.c output.c 
  3555. XSRC2 =    screen.c prompt.c line.c signal.c help.c ttyin.c command.c version.c
  3556. XSRC =    $(SRC1) $(SRC2)
  3557. XOBJ =    main.o option.o prim.o ch.o position.o input.o output.o screen.o \
  3558. X    prompt.o line.o signal.o help.o ttyin.o command.o version.o
  3559. X
  3560. X
  3561. X##########################################################################
  3562. X# Rules
  3563. X##########################################################################
  3564. X
  3565. XDEFS =    "-DTERMIO=$(TERMIO)" \
  3566. X    "-DSIGSETMASK=$(SIGSETMASK)" \
  3567. X    "-Doff_t=$(off_t)" "-DVOID=$(VOID)" \
  3568. X    "-DREGCMP=$(REGCMP)" "-DRECOMP=$(RECOMP)" \
  3569. X    "-DSHELL_ESCAPE=$(SHELL_ESCAPE)" \
  3570. X    "-DEDITOR=$(EDITOR)" "-DEDIT_PGM=\"$(EDIT_PGM)\"" \
  3571. X    "-DHELPFILE=\"$(HELPFILE)\"" \
  3572. X    "-DLOGFILE=$(LOGFILE)" \
  3573. X    "-DONLY_RETURN=$(ONLY_RETURN)" \
  3574. X    "-DGLOB=$(GLOB)" \
  3575. X    "-DXENIX=$(XENIX)"
  3576. X
  3577. XCFLAGS = $(OPTIM) $(DEFS)
  3578. X
  3579. X
  3580. Xall: less
  3581. X
  3582. Xless: $(OBJ)
  3583. X    cc $(OPTIM) -o less $(OBJ) $(LIBS)
  3584. X
  3585. Xinstall: install_man install_less install_help
  3586. X
  3587. Xinstall_less: less
  3588. X    for f in $(INSTALL_LESS); do  rm -f $$f; cp less $$f;  done
  3589. X    touch install_less
  3590. X
  3591. Xinstall_help: less.help
  3592. X    for f in $(INSTALL_HELP); do  rm -f $$f; cp less.help $$f;  done
  3593. X    touch install_help
  3594. X
  3595. Xinstall_man: $(MANUAL)
  3596. X    rm -f $(INSTALL_MAN)
  3597. X    /usr/man/manroff $(MANUAL) > $(INSTALL_MAN)
  3598. X    chmod 444 $(INSTALL_MAN)
  3599. X    chown bin.bin $(INSTALL_MAN)
  3600. X    touch install_man
  3601. X
  3602. X$(OBJ): less.h funcs.h
  3603. X
  3604. X# help.o depends on makefile for the definition of HELPFILE.
  3605. Xhelp.o: makefile
  3606. X
  3607. Xlint:
  3608. X    lint -hp $(DEFS) $(SRC)
  3609. X
  3610. Xnewfuncs:
  3611. X    mv funcs.h funcs.h.OLD
  3612. X    awk -f mkfuncs.awk $(SRC) >funcs.h
  3613. X
  3614. Xclean:
  3615. X    rm -f $(OBJ) less install_help install_less install_man core
  3616. X
  3617. Xclobber:
  3618. X    rm -f *.o less install_less install_man
  3619. X
  3620. Xshar:
  3621. X    shar -v README install less.man less.help makefile.* *.h *.awk > less.shar.a
  3622. X    shar -v less.nro $(SRC1) > less.shar.b
  3623. X    shar -v $(SRC2) > less.shar.c
  3624. SHAR_EOF
  3625. fi
  3626. if test -f 'mkfuncs.awk'
  3627. then
  3628.     echo shar: "will not over-write existing file 'mkfuncs.awk'"
  3629. else
  3630. sed 's/^X//' << \SHAR_EOF > 'mkfuncs.awk'
  3631. XBEGIN { FS="("; state = 0 }
  3632. X
  3633. X/^    public/ { ftype = $0; state = 1 }
  3634. X
  3635. X{ if (state == 1)
  3636. X    state = 2
  3637. X  else if (state == 2)
  3638. X    { print ftype,$1,"();"; state = 0 }
  3639. X}
  3640. SHAR_EOF
  3641. fi
  3642. if test -f 'option.c'
  3643. then
  3644.     echo shar: "will not over-write existing file 'option.c'"
  3645. else
  3646. sed 's/^X//' << \SHAR_EOF > 'option.c'
  3647. X/*
  3648. X * Process command line options.
  3649. X * Each option is a single letter which controls a program variable.
  3650. X * The options have defaults which may be changed via
  3651. X * the command line option, or toggled via the "-" command.
  3652. X */
  3653. X
  3654. X#include "less.h"
  3655. X
  3656. X#define    toupper(c)    ((c)-'a'+'A')
  3657. X
  3658. X#define    END_OPTION_STRING    ('$')
  3659. X
  3660. X/*
  3661. X * Types of options.
  3662. X */
  3663. X#define    BOOL        01    /* Boolean option: 0 or 1 */
  3664. X#define    TRIPLE        02    /* Triple-valued option: 0, 1 or 2 */
  3665. X#define    NUMBER        04    /* Numeric option */
  3666. X#define    REPAINT        040    /* Repaint screen after toggling option */
  3667. X#define    NO_TOGGLE    0100    /* Option cannot be toggled with "-" cmd */
  3668. X
  3669. X/*
  3670. X * Variables controlled by command line options.
  3671. X */
  3672. Xpublic int p_nbufs, f_nbufs;    /* Number of buffers.  There are two values,
  3673. X                   one used for input from a pipe and 
  3674. X                   the other for input from a file. */
  3675. Xpublic int clean_data;        /* Can we assume the data is "clean"? 
  3676. X                   (That is, free of nulls, etc) */
  3677. Xpublic int quiet;        /* Should we suppress the audible bell? */
  3678. Xpublic int top_search;        /* Should forward searches start at the top 
  3679. X                   of the screen? (alternative is bottom) */
  3680. Xpublic int top_scroll;        /* Repaint screen from top?
  3681. X                   (alternative is scroll from bottom) */
  3682. Xpublic int pr_type;        /* Type of prompt (short, medium, long) */
  3683. Xpublic int bs_mode;        /* How to process backspaces */
  3684. Xpublic int know_dumb;        /* Don't complain about dumb terminals */
  3685. Xpublic int quit_at_eof;        /* Quit after hitting end of file twice */
  3686. Xpublic int squeeze;        /* Squeeze multiple blank lines into one */
  3687. Xpublic int tabstop;        /* Tab settings */
  3688. Xpublic int back_scroll;        /* Repaint screen on backwards movement */
  3689. Xpublic int twiddle;        /* Display "~" for lines after EOF */
  3690. X
  3691. Xextern char *prproto[];
  3692. Xextern int nbufs;
  3693. Xextern int sc_window;
  3694. Xextern char *first_cmd;
  3695. Xextern char *every_first_cmd;
  3696. X#if LOGFILE
  3697. Xextern char *namelogfile;
  3698. X#endif
  3699. X
  3700. X#define    DEF_F_NBUFS    5    /* Default for f_nbufs */
  3701. X#define    DEF_P_NBUFS    12    /* Default for p_nbufs */
  3702. X
  3703. Xstatic struct option
  3704. X{
  3705. X    char oletter;        /* The controlling letter (a-z) */
  3706. X    char otype;        /* Type of the option */
  3707. X    int odefault;        /* Default value */
  3708. X    int *ovar;        /* Pointer to the associated variable */
  3709. X    char *odesc[3];        /* Description of each value */
  3710. X} option[] =
  3711. X{
  3712. X    { 'c', BOOL, 0, &clean_data,
  3713. X        { "Don't assume data is clean",
  3714. X          "Assume data is clean",
  3715. X          NULL
  3716. X        }
  3717. X    },
  3718. X    { 'd', BOOL|NO_TOGGLE, 0, &know_dumb,
  3719. X        { NULL, NULL, NULL}
  3720. X    },
  3721. X    { 'e', BOOL, 0, &quit_at_eof,
  3722. X        { "Don't quit at end-of-file",
  3723. X          "Quit at end-of-file",
  3724. X          NULL
  3725. X        }
  3726. X    },
  3727. X    { 'h', NUMBER, -1, &back_scroll,
  3728. X        { "Backwards scroll limit is %d lines",
  3729. X          NULL, NULL
  3730. X        }
  3731. X    },
  3732. X    { 'p', BOOL, 0, &top_scroll,
  3733. X        { "Repaint by scrolling from bottom of screen",
  3734. X          "Repaint by painting from top of screen",
  3735. X          NULL
  3736. X        }
  3737. X    },
  3738. X    { 'x', NUMBER, 8, &tabstop,
  3739. X        { "Tab stops every %d spaces", 
  3740. X          NULL, NULL 
  3741. X        }
  3742. X    },
  3743. X    { 's', BOOL|REPAINT, 0, &squeeze,
  3744. X        { "Don't squeeze multiple blank lines",
  3745. X          "Squeeze multiple blank lines",
  3746. X          NULL
  3747. X        }
  3748. X    },
  3749. X    { 't', BOOL, 1, &top_search,
  3750. X        { "Forward search starts from bottom of screen",
  3751. X          "Forward search starts from top of screen",
  3752. X          NULL
  3753. X        }
  3754. X    },
  3755. X    { 'w', BOOL|REPAINT, 1, &twiddle,
  3756. X        { "Display nothing for lines after end-of-file",
  3757. X          "Display ~ for lines after end-of-file",
  3758. X          NULL
  3759. X        }
  3760. X    },
  3761. X    { 'm', TRIPLE, 0, &pr_type,
  3762. X        { "Short prompt",
  3763. X          "Medium prompt",
  3764. X          "Long prompt"
  3765. X        }
  3766. X    },
  3767. X    { 'q', TRIPLE, 0, &quiet,
  3768. X        { "Ring the bell for errors AND at eof/bof",
  3769. X          "Ring the bell for errors but not at eof/bof",
  3770. X          "Never ring the bell"
  3771. X        }
  3772. X    },
  3773. X    { 'u', TRIPLE|REPAINT, 0, &bs_mode,
  3774. X        { "Underlined text displayed in underline mode",
  3775. X          "Backspaces cause overstrike",
  3776. X          "Backspaces print as ^H"
  3777. X        }
  3778. X    },
  3779. X    { 'z', NUMBER, 24, &sc_window,
  3780. X        { "Scroll window size is %d lines",
  3781. X          NULL, NULL
  3782. X        }
  3783. X    },
  3784. X    { '\0' }
  3785. X};
  3786. X
  3787. Xpublic char all_options[64];    /* List of all valid options */
  3788. X
  3789. X/*
  3790. X * Initialize each option to its default value.
  3791. X */
  3792. X    public void
  3793. Xinit_option()
  3794. X{
  3795. X    register struct option *o;
  3796. X    register char *p;
  3797. X
  3798. X    /*
  3799. X     * First do special cases, not in option table.
  3800. X     */
  3801. X    first_cmd = every_first_cmd = NULL;
  3802. X    f_nbufs = DEF_F_NBUFS;        /* -bf */
  3803. X    p_nbufs = DEF_P_NBUFS;        /* -bp */
  3804. X
  3805. X    p = all_options;
  3806. X    *p++ = 'b';
  3807. X
  3808. X    for (o = option;  o->oletter != '\0';  o++)
  3809. X    {
  3810. X        /*
  3811. X         * Set each variable to its default.
  3812. X         * Also make a list of all options, in "all_options".
  3813. X         */
  3814. X        *(o->ovar) = o->odefault;
  3815. X        *p++ = o->oletter;
  3816. X        if (o->otype & TRIPLE)
  3817. X            *p++ = toupper(o->oletter);
  3818. X    }
  3819. X    *p = '\0';
  3820. X}
  3821. X
  3822. X/*
  3823. X * Toggle command line flags from within the program.
  3824. X * Used by the "-" command.
  3825. X */
  3826. X    public void
  3827. Xtoggle_option(c)
  3828. X    int c;
  3829. X{
  3830. X    register struct option *o;
  3831. X    char message[100];
  3832. X    char buf[5];
  3833. X
  3834. X    /*
  3835. X     * First check for special cases not handled by the option table.
  3836. X     */
  3837. X    switch (c)
  3838. X    {
  3839. X    case 'b':
  3840. X        sprintf(message, "%d buffers", nbufs);
  3841. X        error(message);
  3842. X        return;
  3843. X    }
  3844. X
  3845. X
  3846. X    for (o = option;  o->oletter != '\0';  o++)
  3847. X    {
  3848. X        if (o->otype & NO_TOGGLE)
  3849. X            continue;
  3850. X        if ((o->otype & BOOL) && (o->oletter == c))
  3851. X        {
  3852. X            /*
  3853. X             * Boolean option: 
  3854. X             * just toggle it.
  3855. X             */
  3856. X            *(o->ovar) = ! *(o->ovar);
  3857. X        } else if ((o->otype & TRIPLE) && (o->oletter == c))
  3858. X        {
  3859. X            /*
  3860. X             * Triple-valued option with lower case letter:
  3861. X             * make it 1 unless already 1, then make it 0.
  3862. X             */
  3863. X            *(o->ovar) = (*(o->ovar) == 1) ? 0 : 1;
  3864. X        } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c))
  3865. X        {
  3866. X            /*
  3867. X             * Triple-valued option with upper case letter:
  3868. X             * make it 2 unless already 2, then make it 0.
  3869. X             */
  3870. X            *(o->ovar) = (*(o->ovar) == 2) ? 0 : 2;
  3871. X        } else if ((o->otype & NUMBER) && (o->oletter == c))
  3872. X        {
  3873. X            sprintf(message, o->odesc[0], 
  3874. X                (o->ovar == &back_scroll) ? 
  3875. X                get_back_scroll() : *(o->ovar));
  3876. X            error(message);
  3877. X            return;
  3878. X        } else
  3879. X            continue;
  3880. X
  3881. X        if (o->otype & REPAINT)
  3882. X            repaint();
  3883. X        error(o->odesc[*(o->ovar)]);
  3884. X        return;
  3885. X    }
  3886. X
  3887. X    if (control_char(c))
  3888. X        sprintf(buf, "^%c", carat_char(c));
  3889. X    else
  3890. X        sprintf(buf, "%c", c);
  3891. X    sprintf(message, "\"-%s\": no such flag.  Use one of \"%s\"", 
  3892. X        buf, all_options);
  3893. X    error(message);
  3894. X}
  3895. X
  3896. X/*
  3897. X * Scan to end of string or to an END_OPTION_STRING character.
  3898. X * In the latter case, replace the char with a null char.
  3899. X * Return a pointer to the remainder of the string, if any.
  3900. X */
  3901. X    static char *
  3902. Xoptstring(s)
  3903. X    char *s;
  3904. X{
  3905. X    register char *p;
  3906. X
  3907. X    for (p = s;  *p != '\0';  p++)
  3908. X        if (*p == END_OPTION_STRING)
  3909. X        {
  3910. X            *p = '\0';
  3911. X            return (p+1);
  3912. X        }
  3913. X    return (p);
  3914. X}
  3915. X
  3916. X/* 
  3917. X * Scan an argument (either from command line or from LESS environment 
  3918. X * variable) and process it.
  3919. X */
  3920. X    public void
  3921. Xscan_option(s)
  3922. X    char *s;
  3923. X{
  3924. X    register struct option *o;
  3925. X    register int c;
  3926. X    char message[80];
  3927. X
  3928. X    if (s == NULL)
  3929. X        return;
  3930. X
  3931. X    next:
  3932. X    if (*s == '\0')
  3933. X        return;
  3934. X    switch (c = *s++)
  3935. X    {
  3936. X    case '-':
  3937. X    case ' ':
  3938. X    case '\t':
  3939. X    case END_OPTION_STRING:
  3940. X        goto next;
  3941. X    case '+':
  3942. X        if (*s == '+')
  3943. X            every_first_cmd = ++s;
  3944. X        first_cmd = s;
  3945. X        s = optstring(s);
  3946. X        goto next;
  3947. X    case 'P':
  3948. X        switch (*s)
  3949. X        {
  3950. X        case 'm':  prproto[PR_MEDIUM] = ++s;  break;
  3951. X        case 'M':  prproto[PR_LONG] = ++s;    break;
  3952. X        default:   prproto[PR_SHORT] = s;     break;
  3953. X        }
  3954. X        s = optstring(s);
  3955. X        goto next;
  3956. X#if LOGFILE
  3957. X    case 'l':
  3958. X        namelogfile = s;
  3959. X        s = optstring(s);
  3960. X        goto next;
  3961. X#endif
  3962. X    case 'b':
  3963. X        switch (*s)
  3964. X        {
  3965. X        case 'f':
  3966. X            s++;
  3967. X            f_nbufs = getnum(&s, 'b');
  3968. X            break;
  3969. X        case 'p':
  3970. X            s++;
  3971. X            p_nbufs = getnum(&s, 'b');
  3972. X            break;
  3973. X        default:
  3974. X            f_nbufs = p_nbufs = getnum(&s, 'b');
  3975. X            break;
  3976. X        }
  3977. X        goto next;
  3978. X    case '0':  case '1':  case '2':  case '3':  case '4':
  3979. X    case '5':  case '6':  case '7':  case '8':  case '9':
  3980. X        {
  3981. X            /*
  3982. X             * Handle special "more" compatibility form "-number"
  3983. X             * to set the scrolling window size.
  3984. X             */
  3985. X            s--;
  3986. X            sc_window = getnum(&s, '-');
  3987. X            goto next;
  3988. X        }
  3989. X    }
  3990. X
  3991. X    for (o = option;  o->oletter != '\0';  o++)
  3992. X    {
  3993. X        if ((o->otype & BOOL) && (o->oletter == c))
  3994. X        {
  3995. X            *(o->ovar) = ! o->odefault;
  3996. X            goto next;
  3997. X        } else if ((o->otype & TRIPLE) && (o->oletter == c))
  3998. X        {
  3999. X            *(o->ovar) = (o->odefault == 1) ? 0 : 1;
  4000. X            goto next;
  4001. X        } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c))
  4002. X        {
  4003. X            *(o->ovar) = (o->odefault == 2) ? 0 : 2;
  4004. X            goto next;
  4005. X        } else if ((o->otype & NUMBER) && (o->oletter == c))
  4006. X        {
  4007. X            *(o->ovar) = getnum(&s, c);
  4008. X            goto next;
  4009. X        }
  4010. X    }
  4011. X
  4012. X    sprintf(message, "\"-%c\": invalid flag", c);
  4013. X    error(message);
  4014. X    exit(1);
  4015. X}
  4016. X
  4017. X/*
  4018. X * Translate a string into a number.
  4019. X * Like atoi(), but takes a pointer to a char *, and updates
  4020. X * the char * to point after the translated number.
  4021. X */
  4022. X    static int
  4023. Xgetnum(sp, c)
  4024. X    char **sp;
  4025. X    int c;
  4026. X{
  4027. X    register char *s;
  4028. X    register int n;
  4029. X    char message[80];
  4030. X
  4031. X    s = *sp;
  4032. X    if (*s < '0' || *s > '9')
  4033. X    {
  4034. X        sprintf(message, "number is required after -%c", c);
  4035. X        error(message);
  4036. X        exit(1);
  4037. X    }
  4038. X
  4039. X    n = 0;
  4040. X    while (*s >= '0' && *s <= '9')
  4041. X        n = 10 * n + *s++ - '0';
  4042. X    *sp = s;
  4043. X    return (n);
  4044. X}
  4045. SHAR_EOF
  4046. fi
  4047. if test -f 'output.c'
  4048. then
  4049.     echo shar: "will not over-write existing file 'output.c'"
  4050. else
  4051. sed 's/^X//' << \SHAR_EOF > 'output.c'
  4052. X/*
  4053. X * High level routines dealing with the output to the screen.
  4054. X */
  4055. X
  4056. X#include "less.h"
  4057. X
  4058. Xpublic int errmsgs;    /* Count of messages displayed by error() */
  4059. X
  4060. Xextern int sigs;
  4061. Xextern int sc_width, sc_height;
  4062. Xextern int ul_width, ue_width;
  4063. Xextern int so_width, se_width;
  4064. Xextern int bo_width, be_width;
  4065. Xextern int tabstop;
  4066. Xextern int twiddle;
  4067. Xextern int any_display;
  4068. Xextern char *line;
  4069. Xextern char *first_cmd;
  4070. X
  4071. X/*
  4072. X * Display the line which is in the line buffer.
  4073. X */
  4074. X    public void
  4075. Xput_line()
  4076. X{
  4077. X    register char *p;
  4078. X    register int c;
  4079. X    register int column;
  4080. X    extern int auto_wrap, ignaw;
  4081. X
  4082. X    if (sigs)
  4083. X        /*
  4084. X         * Don't output if a signal is pending.
  4085. X         */
  4086. X        return;
  4087. X
  4088. X    if (line == NULL)
  4089. X        line = (twiddle) ? "~" : "";
  4090. X
  4091. X    column = 0;
  4092. X    for (p = line;  *p != '\0';  p++)
  4093. X    {
  4094. X        switch (c = *p)
  4095. X        {
  4096. X        case UL_CHAR:
  4097. X            ul_enter();
  4098. X            column += ul_width;
  4099. X            break;
  4100. X        case UE_CHAR:
  4101. X            ul_exit();
  4102. X            column += ue_width;
  4103. X            break;
  4104. X        case BO_CHAR:
  4105. X            bo_enter();
  4106. X            column += bo_width;
  4107. X            break;
  4108. X        case BE_CHAR:
  4109. X            bo_exit();
  4110. X            column += be_width;
  4111. X            break;
  4112. X        case '\t':
  4113. X            do
  4114. X            {
  4115. X                putc(' ');
  4116. X                column++;
  4117. X            } while ((column % tabstop) != 0);
  4118. X            break;
  4119. X        case '\b':
  4120. X            putbs();
  4121. X            column--;
  4122. X            break;
  4123. X        default:
  4124. X            if (c & 0200)
  4125. X            {
  4126. X                putc('^');
  4127. X                putc(c & 0177);
  4128. X                column += 2;
  4129. X            } else
  4130. X            {
  4131. X                putc(c);
  4132. X                column++;
  4133. X            }
  4134. X        }
  4135. X    }
  4136. X    if (column < sc_width || !auto_wrap || ignaw)
  4137. X        putc('\n');
  4138. X}
  4139. X
  4140. X/*
  4141. X * Is a given character a "control" character?
  4142. X * {{ ASCII DEPENDENT }}
  4143. X */
  4144. X    public int
  4145. Xcontrol_char(c)
  4146. X    int c;
  4147. X{
  4148. X    return (c < ' ' || c == '\177');
  4149. X}
  4150. X
  4151. X/*
  4152. X * Return the printable character used to identify a control character
  4153. X * (printed after a carat; e.g. '\3' => "^C").
  4154. X * {{ ASCII DEPENDENT }}
  4155. X */
  4156. X    public int
  4157. Xcarat_char(c)
  4158. X    int c;
  4159. X{
  4160. X    return ((c == '\177') ? '?' : (c | 0100));
  4161. X}
  4162. X
  4163. X
  4164. Xstatic char obuf[1024];
  4165. Xstatic char *ob = obuf;
  4166. X
  4167. X/*
  4168. X * Flush buffered output.
  4169. X */
  4170. X    public void
  4171. Xflush()
  4172. X{
  4173. X    write(1, obuf, ob-obuf);
  4174. X    ob = obuf;
  4175. X}
  4176. X
  4177. X/*
  4178. X * Discard buffered output.
  4179. X */
  4180. X    public void
  4181. Xdropout()
  4182. X{
  4183. X    ob = obuf;
  4184. X}
  4185. X
  4186. X/*
  4187. X * Output a character.
  4188. X */
  4189. X    public void
  4190. Xputc(c)
  4191. X    int c;
  4192. X{
  4193. X    if (ob >= &obuf[sizeof(obuf)])
  4194. X        flush();
  4195. X    *ob++ = c;
  4196. X}
  4197. X
  4198. X/*
  4199. X * Output a string.
  4200. X */
  4201. X    public void
  4202. Xputs(s)
  4203. X    register char *s;
  4204. X{
  4205. X    while (*s != '\0')
  4206. X        putc(*s++);
  4207. X}
  4208. X
  4209. X/*
  4210. X * Output a message in the lower left corner of the screen
  4211. X * and wait for carriage return.
  4212. X */
  4213. X
  4214. Xstatic char return_to_continue[] = "  (press RETURN)";
  4215. X
  4216. X    public void
  4217. Xerror(s)
  4218. X    char *s;
  4219. X{
  4220. X    register int c;
  4221. X    static char buf[2];
  4222. X
  4223. X    errmsgs++;
  4224. X    if (!any_display)
  4225. X    {
  4226. X        /*
  4227. X         * Nothing has been displayed yet.
  4228. X         * Output this message on error output (file
  4229. X         * descriptor 2) and don't wait for a keystroke
  4230. X         * to continue.
  4231. X         *
  4232. X         * This has the desirable effect of producing all
  4233. X         * error messages on error output if standard output
  4234. X         * is directed to a file.  It also does the same if
  4235. X         * we never produce any real output; for example, if
  4236. X         * the input file(s) cannot be opened.  If we do
  4237. X         * eventually produce output, code in edit() makes
  4238. X         * sure these messages can be seen before they are
  4239. X         * overwritten or scrolled away.
  4240. X         */
  4241. X        write(2, s, strlen(s));
  4242. X        write(2, "\n", 1);
  4243. X        return;
  4244. X    }
  4245. X
  4246. X    lower_left();
  4247. X    clear_eol();
  4248. X    so_enter();
  4249. X    puts(s);
  4250. X    puts(return_to_continue);
  4251. X    so_exit();
  4252. X
  4253. X#if ONLY_RETURN
  4254. X    while ((c = getc()) != '\n' && c != '\r')
  4255. X        bell();
  4256. X#else
  4257. X    c = getc();
  4258. X    if (c != '\n' && c != '\r' && c != ' ')
  4259. X    {
  4260. X        buf[0] = c;
  4261. X        first_cmd = buf;
  4262. X    }
  4263. X#endif
  4264. X
  4265. X    if (strlen(s) + sizeof(return_to_continue) + 
  4266. X        so_width + se_width + 1 > sc_width)
  4267. X        /*
  4268. X         * Printing the message has probably scrolled the screen.
  4269. X         * {{ Unless the terminal doesn't have auto margins,
  4270. X         *    in which case we just hammered on the right margin. }}
  4271. X         */
  4272. X        repaint();
  4273. X}
  4274. X
  4275. X#ifdef notdef
  4276. X    public int
  4277. Xerror_width()
  4278. X{
  4279. X    /*
  4280. X     * Don't use the last position, because some terminals
  4281. X     * will scroll if you write in the last char of the last line.
  4282. X     */
  4283. X    return (sc_width - 
  4284. X        (sizeof(return_to_continue) + so_width + se_width + 1));
  4285. X}
  4286. X#endif
  4287. SHAR_EOF
  4288. fi
  4289. if test -f 'position.c'
  4290. then
  4291.     echo shar: "will not over-write existing file 'position.c'"
  4292. else
  4293. sed 's/^X//' << \SHAR_EOF > 'position.c'
  4294. X/*
  4295. X * Routines dealing with the "position" table.
  4296. X * This is a table which tells the position (in the input file) of the
  4297. X * first char on each currently displayed line.
  4298. X *
  4299. X * {{ The position table is scrolled by moving all the entries.
  4300. X *    Would be better to have a circular table 
  4301. X *    and just change a couple of pointers. }}
  4302. X */
  4303. X
  4304. X#include "less.h"
  4305. X#include "position.h"
  4306. X
  4307. X#define    NPOS    100        /* {{ sc_height must be less than NPOS }} */
  4308. Xstatic POSITION table[NPOS];    /* The position table */
  4309. X
  4310. Xextern int sc_width, sc_height;
  4311. X
  4312. X/*
  4313. X * Return the starting file position of a line displayed on the screen.
  4314. X * The line may be specified as a line number relative to the top
  4315. X * of the screen, but is usually one of these special cases:
  4316. X *    the top (first) line on the screen
  4317. X *    the second line on the screen
  4318. X *    the bottom line on the screen
  4319. X *    the line after the bottom line on the screen
  4320. X */
  4321. X    public POSITION
  4322. Xposition(where)
  4323. X    int where;
  4324. X{
  4325. X    switch (where)
  4326. X    {
  4327. X    case BOTTOM:
  4328. X        where = sc_height - 2;
  4329. X        break;
  4330. X    case BOTTOM_PLUS_ONE:
  4331. X        where = sc_height - 1;
  4332. X        break;
  4333. X    }
  4334. X    return (table[where]);
  4335. X}
  4336. X
  4337. X/*
  4338. X * Add a new file position to the bottom of the position table.
  4339. X */
  4340. X    public void
  4341. Xadd_forw_pos(pos)
  4342. X    POSITION pos;
  4343. X{
  4344. X    register int i;
  4345. X
  4346. X    /*
  4347. X     * Scroll the position table up.
  4348. X     */
  4349. X    for (i = 1;  i < sc_height;  i++)
  4350. X        table[i-1] = table[i];
  4351. X    table[sc_height - 1] = pos;
  4352. X}
  4353. X
  4354. X/*
  4355. X * Add a new file position to the top of the position table.
  4356. X */
  4357. X    public void
  4358. Xadd_back_pos(pos)
  4359. X    POSITION pos;
  4360. X{
  4361. X    register int i;
  4362. X
  4363. X    /*
  4364. X     * Scroll the position table down.
  4365. X     */
  4366. X    for (i = sc_height - 1;  i > 0;  i--)
  4367. X        table[i] = table[i-1];
  4368. X    table[0] = pos;
  4369. X}
  4370. X
  4371. X/*
  4372. X * Initialize the position table, done whenever we clear the screen.
  4373. X */
  4374. X    public void
  4375. Xpos_clear()
  4376. X{
  4377. X    register int i;
  4378. X
  4379. X    for (i = 0;  i < sc_height;  i++)
  4380. X        table[i] = NULL_POSITION;
  4381. X}
  4382. X
  4383. X/*
  4384. X * See if the byte at a specified position is currently on the screen.
  4385. X * Check the position table to see if the position falls within its range.
  4386. X * Return the position table entry if found, -1 if not.
  4387. X */
  4388. X    public int
  4389. Xonscreen(pos)
  4390. X    POSITION pos;
  4391. X{
  4392. X    register int i;
  4393. X
  4394. X    if (pos < table[0])
  4395. X        return (-1);
  4396. X    for (i = 1;  i < sc_height;  i++)
  4397. X        if (pos < table[i])
  4398. X            return (i-1);
  4399. X    return (-1);
  4400. X}
  4401. SHAR_EOF
  4402. fi
  4403. if test -f 'position.h'
  4404. then
  4405.     echo shar: "will not over-write existing file 'position.h'"
  4406. else
  4407. sed 's/^X//' << \SHAR_EOF > 'position.h'
  4408. X/*
  4409. X * Include file for interfacing to position.c modules.
  4410. X */
  4411. X#define    TOP        0
  4412. X#define    TOP_PLUS_ONE    1
  4413. X#define    BOTTOM        -1
  4414. X#define    BOTTOM_PLUS_ONE    -2
  4415. SHAR_EOF
  4416. fi
  4417. if test -f 'prim.c'
  4418. then
  4419.     echo shar: "will not over-write existing file 'prim.c'"
  4420. else
  4421. sed 's/^X//' << \SHAR_EOF > 'prim.c'
  4422. X/*
  4423. X * Primitives for displaying the file on the screen.
  4424. X */
  4425. X
  4426. X#include "less.h"
  4427. X#include "position.h"
  4428. X
  4429. Xpublic int hit_eof;    /* Keeps track of how many times we hit end of file */
  4430. X
  4431. Xextern int quiet;
  4432. Xextern int top_search;
  4433. Xextern int top_scroll;
  4434. Xextern int back_scroll;
  4435. Xextern int sc_width, sc_height;
  4436. Xextern int sigs;
  4437. Xextern char *line;
  4438. Xextern char *first_cmd;
  4439. X
  4440. X/*
  4441. X * Sound the bell to indicate he is trying to move past end of file.
  4442. X */
  4443. X    static void
  4444. Xeof_bell()
  4445. X{
  4446. X    if (quiet == NOT_QUIET)
  4447. X        bell();
  4448. X    else
  4449. X        vbell();
  4450. X}
  4451. X
  4452. X/*
  4453. X * Check to see if the end of file is currently "displayed".
  4454. X */
  4455. X    static void
  4456. Xeof_check()
  4457. X{
  4458. X    POSITION pos;
  4459. X
  4460. X    /*
  4461. X     * If the bottom line is empty, we are at EOF.
  4462. X     * If the bottom line ends at the file length,
  4463. X     * we must be just at EOF.
  4464. X     */
  4465. X    pos = position(BOTTOM_PLUS_ONE);
  4466. X    if (pos == NULL_POSITION || pos == ch_length())
  4467. X        hit_eof++;
  4468. X}
  4469. X
  4470. X/*
  4471. X * Display n lines, scrolling forward, 
  4472. X * starting at position pos in the input file.
  4473. X * "force" means display the n lines even if we hit end of file.
  4474. X * "only_last" means display only the last screenful if n > screen size.
  4475. X */
  4476. X    static void
  4477. Xforw(n, pos, force, only_last)
  4478. X    register int n;
  4479. X    POSITION pos;
  4480. X    int force;
  4481. X    int only_last;
  4482. X{
  4483. X    int eof = 0;
  4484. X    int nlines = 0;
  4485. X    int repaint_flag;
  4486. X    static int first_time = 1;
  4487. X
  4488. X    /*
  4489. X     * repaint_flag tells us not to display anything till the end, 
  4490. X     * then just repaint the entire screen.
  4491. X     */
  4492. X    repaint_flag = (only_last && n > sc_height-1);
  4493. X
  4494. X    if (!repaint_flag)
  4495. X    {
  4496. X        if (top_scroll && n >= sc_height - 1)
  4497. X        {
  4498. X            /*
  4499. X             * Start a new screen.
  4500. X             * {{ This is not really desirable if we happen
  4501. X             *    to hit eof in the middle of this screen,
  4502. X             *    but we don't yet know if that will happen. }}
  4503. X             */
  4504. X            clear();
  4505. X            home();
  4506. X            force = 1;
  4507. X        } else
  4508. X        {
  4509. X            lower_left();
  4510. X            clear_eol();
  4511. X        }
  4512. X
  4513. X        if (pos != position(BOTTOM_PLUS_ONE))
  4514. X        {
  4515. X            /*
  4516. X             * This is not contiguous with what is
  4517. X             * currently displayed.  Clear the screen image 
  4518. X             * (position table) and start a new screen.
  4519. X             */
  4520. X            pos_clear();
  4521. X            add_forw_pos(pos);
  4522. X            force = 1;
  4523. X            if (top_scroll)
  4524. X            {
  4525. X                clear();
  4526. X                home();
  4527. X            } else if (!first_time)
  4528. X            {
  4529. X                puts("...skipping...\n");
  4530. X            }
  4531. X        }
  4532. X    }
  4533. X
  4534. X    while (--n >= 0)
  4535. X    {
  4536. X        /*
  4537. X         * Read the next line of input.
  4538. X         */
  4539. X        pos = forw_line(pos);
  4540. X        if (pos == NULL_POSITION)
  4541. X        {
  4542. X            /*
  4543. X             * End of file: stop here unless the top line 
  4544. X             * is still empty, or "force" is true.
  4545. X             */
  4546. X            eof = 1;
  4547. X            if (!force && position(TOP) != NULL_POSITION)
  4548. X                break;
  4549. X            line = NULL;
  4550. X        }
  4551. X        /*
  4552. X         * Add the position of the next line to the position table.
  4553. X         * Display the current line on the screen.
  4554. X         */
  4555. X        add_forw_pos(pos);
  4556. X        nlines++;
  4557. X        if (repaint_flag || 
  4558. X            (first_time && line == NULL && !top_scroll))
  4559. X            continue;
  4560. X        put_line();
  4561. X    }
  4562. X
  4563. X    if (eof)
  4564. X        hit_eof++;
  4565. X    else
  4566. X        eof_check();
  4567. X    if (nlines == 0)
  4568. X        eof_bell();
  4569. X    else if (repaint_flag)
  4570. X        repaint();
  4571. X    first_time = 0;
  4572. X}
  4573. X
  4574. X/*
  4575. X * Display n lines, scrolling backward.
  4576. X */
  4577. X    static void
  4578. Xback(n, pos, force, only_last)
  4579. X    register int n;
  4580. X    POSITION pos;
  4581. X    int force;
  4582. X    int only_last;
  4583. X{
  4584. X    int nlines = 0;
  4585. X    int repaint_flag;
  4586. X
  4587. X    repaint_flag = (n > get_back_scroll() || (only_last && n > sc_height-1));
  4588. X    hit_eof = 0;
  4589. X    while (--n >= 0)
  4590. X    {
  4591. X        /*
  4592. X         * Get the previous line of input.
  4593. X         */
  4594. X        pos = back_line(pos);
  4595. X        if (pos == NULL_POSITION)
  4596. X        {
  4597. X            /*
  4598. X             * Beginning of file: stop here unless "force" is true.
  4599. X             */
  4600. X            if (!force)
  4601. X                break;
  4602. X            line = NULL;
  4603. X        }
  4604. X        /*
  4605. X         * Add the position of the previous line to the position table.
  4606. X         * Display the line on the screen.
  4607. X         */
  4608. X        add_back_pos(pos);
  4609. X        nlines++;
  4610. X        if (!repaint_flag)
  4611. X        {
  4612. X            home();
  4613. X            add_line();
  4614. X            put_line();
  4615. X        }
  4616. X    }
  4617. X
  4618. X    eof_check();
  4619. X    if (nlines == 0)
  4620. X        eof_bell();
  4621. X    else if (repaint_flag)
  4622. X        repaint();
  4623. X}
  4624. X
  4625. X/*
  4626. X * Display n more lines, forward.
  4627. X * Start just after the line currently displayed at the bottom of the screen.
  4628. X */
  4629. X    public void
  4630. Xforward(n, only_last)
  4631. X    int n;
  4632. X    int only_last;
  4633. X{
  4634. X    POSITION pos;
  4635. X
  4636. X    pos = position(BOTTOM_PLUS_ONE);
  4637. X    if (pos == NULL_POSITION)
  4638. X    {
  4639. X        eof_bell();
  4640. X        hit_eof++;
  4641. X        return;
  4642. X    }
  4643. X    forw(n, pos, 0, only_last);
  4644. X}
  4645. X
  4646. X/*
  4647. X * Display n more lines, backward.
  4648. X * Start just before the line currently displayed at the top of the screen.
  4649. X */
  4650. X    public void
  4651. Xbackward(n, only_last)
  4652. X    int n;
  4653. X    int only_last;
  4654. X{
  4655. X    POSITION pos;
  4656. X
  4657. X    pos = position(TOP);
  4658. X    if (pos == NULL_POSITION)
  4659. X    {
  4660. X        /* 
  4661. X         * This will almost never happen,
  4662. X         * because the top line is almost never empty. 
  4663. X         */
  4664. X        eof_bell();
  4665. X        return;   
  4666. X    }
  4667. X    back(n, pos, 0, only_last);
  4668. X}
  4669. X
  4670. X/*
  4671. X * Repaint the screen, starting from a specified position.
  4672. X */
  4673. X    static void
  4674. Xprepaint(pos)    
  4675. X    POSITION pos;
  4676. X{
  4677. X    hit_eof = 0;
  4678. X    forw(sc_height-1, pos, 0, 0);
  4679. X}
  4680. X
  4681. X/*
  4682. X * Repaint the screen.
  4683. X */
  4684. X    public void
  4685. Xrepaint()
  4686. X{
  4687. X    /*
  4688. X     * Start at the line currently at the top of the screen
  4689. X     * and redisplay the screen.
  4690. X     */
  4691. X    prepaint(position(TOP));
  4692. X}
  4693. X
  4694. X/*
  4695. X * Jump to the end of the file.
  4696. X * It is more convenient to paint the screen backward,
  4697. X * from the end of the file toward the beginning.
  4698. X */
  4699. X    public void
  4700. Xjump_forw()
  4701. X{
  4702. X    POSITION pos;
  4703. X
  4704. X    if (ch_end_seek())
  4705. X    {
  4706. X        error("Cannot seek to end of file");
  4707. X        return;
  4708. X    }
  4709. X    lastmark();
  4710. X    pos = ch_tell();
  4711. X    clear();
  4712. X    pos_clear();
  4713. X    add_back_pos(pos);
  4714. X    back(sc_height - 1, pos, 0, 0);
  4715. X}
  4716. X
  4717. X/*
  4718. X * Jump to line n in the file.
  4719. X */
  4720. X    public void
  4721. Xjump_back(n)
  4722. X    register int n;
  4723. X{
  4724. X    register int c;
  4725. X    int nlines;
  4726. X
  4727. X    /*
  4728. X     * This is done the slow way, by starting at the beginning
  4729. X     * of the file and counting newlines.
  4730. X     */
  4731. X    if (ch_seek((POSITION)0))
  4732. X    {
  4733. X        /* 
  4734. X         * Probably a pipe with beginning of file no longer buffered. 
  4735. X         * If he wants to go to line 1, we do the best we can, 
  4736. X         * by going to the first line which is still buffered.
  4737. X         */
  4738. X        if (n <= 1 && ch_beg_seek() == 0)
  4739. X            jump_loc(ch_tell());
  4740. X        error("Cannot get to beginning of file");
  4741. X        return;
  4742. X    }
  4743. X
  4744. X    /*
  4745. X     * Start counting lines.
  4746. X     */
  4747. X    for (nlines = 1;  nlines < n;  nlines++)
  4748. X    {
  4749. X        while ((c = ch_forw_get()) != '\n')
  4750. X            if (c == EOF)
  4751. X            {
  4752. X                char message[40];
  4753. X                sprintf(message, "File has only %d lines", 
  4754. X                    nlines-1);
  4755. X                error(message);
  4756. X                return;
  4757. X            }
  4758. X    }
  4759. X
  4760. X    jump_loc(ch_tell());
  4761. X}
  4762. X
  4763. X/*
  4764. X * Jump to a specified percentage into the file.
  4765. X * This is a poor compensation for not being able to
  4766. X * quickly jump to a specific line number.
  4767. X */
  4768. X    public void
  4769. Xjump_percent(percent)
  4770. X    int percent;
  4771. X{
  4772. X    POSITION pos, len;
  4773. X    register int c;
  4774. X
  4775. X    /*
  4776. X     * Determine the position in the file
  4777. X     * (the specified percentage of the file's length).
  4778. X     */
  4779. X    if ((len = ch_length()) == NULL_POSITION)
  4780. X    {
  4781. X        error("Don't know length of file");
  4782. X        return;
  4783. X    }
  4784. X    pos = (percent * len) / 100;
  4785. X
  4786. X    /*
  4787. X     * Back up to the beginning of the line.
  4788. X     */
  4789. X    if (ch_seek(pos) == 0)
  4790. X    {
  4791. X        while ((c = ch_back_get()) != '\n' && c != EOF)
  4792. X            ;
  4793. X        if (c == '\n')
  4794. X            (void) ch_forw_get();
  4795. X        pos = ch_tell();
  4796. X    }
  4797. X    jump_loc(pos);
  4798. X}
  4799. X
  4800. X/*
  4801. X * Jump to a specified position in the file.
  4802. X */
  4803. X    public void
  4804. Xjump_loc(pos)
  4805. X    POSITION pos;
  4806. X{
  4807. X    register int nline;
  4808. X    POSITION tpos;
  4809. X
  4810. X    /*
  4811. X     * See if the desired line is BEFORE the currently
  4812. X     * displayed screen.  If so, see if it is close enough 
  4813. X     * to scroll backwards to it.
  4814. X     * {{ This can be expensive if he has specified a very
  4815. X     *    large back_scroll count.  Perhaps we should put
  4816. X     *    some sanity limit on the loop count here. }}
  4817. X     */
  4818. X    tpos = position(TOP);
  4819. X    if (tpos != NULL_POSITION && pos < tpos)
  4820. X    {
  4821. X        int bs = get_back_scroll();
  4822. X        for (nline = 1;  nline <= bs;  nline++)
  4823. X        {
  4824. X            tpos = back_line(tpos);
  4825. X            if (tpos == NULL_POSITION)
  4826. X                break;
  4827. X            if (tpos <= pos)
  4828. X            {
  4829. X                back(nline, position(TOP), 1, 0);
  4830. X                return;
  4831. X            }
  4832. X        }
  4833. X    } else if ((nline = onscreen(pos)) >= 0)
  4834. X    {
  4835. X        /*
  4836. X         * The line is currently displayed.  
  4837. X         * Just scroll there.
  4838. X         */
  4839. X        forw(nline, position(BOTTOM_PLUS_ONE), 1, 0);
  4840. X        return;
  4841. X    }
  4842. X
  4843. X    /*
  4844. X     * Line is not on screen.
  4845. X     * Remember where we were; clear and paint the screen.
  4846. X     */
  4847. X    if (ch_seek(pos))
  4848. X    {
  4849. X        error("Cannot seek to that position");
  4850. X        return;
  4851. X    }
  4852. X    lastmark();
  4853. X    prepaint(pos);
  4854. X}
  4855. X
  4856. X/*
  4857. X * The table of marks.
  4858. X * A mark is simply a position in the file.
  4859. X */
  4860. X#define    NMARKS        (27)        /* 26 for a-z plus one for quote */
  4861. X#define    LASTMARK    (NMARKS-1)    /* For quote */
  4862. Xstatic POSITION marks[NMARKS];
  4863. X
  4864. X/*
  4865. X * Initialize the mark table to show no marks are set.
  4866. X */
  4867. X    public void
  4868. Xinit_mark()
  4869. X{
  4870. X    int i;
  4871. X
  4872. X    for (i = 0;  i < NMARKS;  i++)
  4873. X        marks[i] = NULL_POSITION;
  4874. X}
  4875. X
  4876. X/*
  4877. X * See if a mark letter is valid (between a and z).
  4878. X */
  4879. X    static int
  4880. Xbadmark(c)
  4881. X    int c;
  4882. X{
  4883. X    if (c < 'a' || c > 'z')
  4884. X    {
  4885. X        error("Choose a letter between 'a' and 'z'");
  4886. X        return (1);
  4887. X    }
  4888. X    return (0);
  4889. X}
  4890. X
  4891. X/*
  4892. X * Set a mark.
  4893. X */
  4894. X    public void
  4895. Xsetmark(c)
  4896. X    int c;
  4897. X{
  4898. X    if (badmark(c))
  4899. X        return;
  4900. X    marks[c-'a'] = position(TOP);
  4901. X}
  4902. X
  4903. X    public void
  4904. Xlastmark()
  4905. X{
  4906. X    marks[LASTMARK] = position(TOP);
  4907. X}
  4908. X
  4909. X/*
  4910. X * Go to a previously set mark.
  4911. X */
  4912. X    public void
  4913. Xgomark(c)
  4914. X    int c;
  4915. X{
  4916. X    POSITION pos;
  4917. X
  4918. X    if (c == '\'')
  4919. X        pos = marks[LASTMARK];
  4920. X    else if (badmark(c))
  4921. X        return;
  4922. X    else 
  4923. X        pos = marks[c-'a'];
  4924. X
  4925. X    if (pos == NULL_POSITION)
  4926. X        error("mark not set");
  4927. X    else
  4928. X        jump_loc(pos);
  4929. X}
  4930. X
  4931. X/*
  4932. X * Get the backwards scroll limit.
  4933. X * Must call this function instead of just using the value of
  4934. X * back_scroll, because the default case depends on sc_height and
  4935. X * top_scroll, as well as back_scroll.
  4936. X */
  4937. X    public int
  4938. Xget_back_scroll()
  4939. X{
  4940. X    if (back_scroll < 0)
  4941. X        return (sc_height - 1 - top_scroll);
  4942. X    return (back_scroll);
  4943. X}
  4944. X
  4945. X/*
  4946. X * Search for the n-th occurence of a specified pattern, 
  4947. X * either forward (direction == '/'), or backwards (direction == '?').
  4948. X */
  4949. X    public void
  4950. Xsearch(direction, pattern, n)
  4951. X    int direction;
  4952. X    char *pattern;
  4953. X    register int n;
  4954. X{
  4955. X    register int search_forward = (direction == '/');
  4956. X    POSITION pos, linepos;
  4957. X
  4958. X#if RECOMP
  4959. X    char *re_comp();
  4960. X    char *errmsg;
  4961. X
  4962. X    /*
  4963. X     * (re_comp handles a null pattern internally, 
  4964. X     *  so there is no need to check for a null pattern here.)
  4965. X     */
  4966. X    if ((errmsg = re_comp(pattern)) != NULL)
  4967. X    {
  4968. X        error(errmsg);
  4969. X        return;
  4970. X    }
  4971. X#else
  4972. X#if REGCMP
  4973. X    char *regcmp();
  4974. X    static char *cpattern = NULL;
  4975. X
  4976. X    if (pattern == NULL || *pattern == '\0')
  4977. X    {
  4978. X        /*
  4979. X         * A null pattern means use the previous pattern.
  4980. X         * The compiled previous pattern is in cpattern, so just use it.
  4981. X         */
  4982. X        if (cpattern == NULL)
  4983. X        {
  4984. X            error("No previous regular expression");
  4985. X            return;
  4986. X        }
  4987. X    } else
  4988. X    {
  4989. X        /*
  4990. X         * Otherwise compile the given pattern.
  4991. X         */
  4992. X        char *s;
  4993. X        if ((s = regcmp(pattern, 0)) == NULL)
  4994. X        {
  4995. X            error("Invalid pattern");
  4996. X            return;
  4997. X        }
  4998. X        if (cpattern != NULL)
  4999. X            free(cpattern);
  5000. X        cpattern = s;
  5001. X    }
  5002. X#else
  5003. X    static char lpbuf[100];
  5004. X    static char *last_pattern = NULL;
  5005. X
  5006. X    if (pattern == NULL || *pattern == '\0')
  5007. X    {
  5008. X        /*
  5009. X         * Null pattern means use the previous pattern.
  5010. X         */
  5011. X        if (last_pattern == NULL)
  5012. X        {
  5013. X            error("No previous regular expression");
  5014. X            return;
  5015. X        }
  5016. X        pattern = last_pattern;
  5017. X    } else
  5018. X    {
  5019. X        strcpy(lpbuf, pattern);
  5020. X        last_pattern = lpbuf;
  5021. X    }
  5022. X#endif
  5023. X#endif
  5024. X
  5025. X    /*
  5026. X     * Figure out where to start the search.
  5027. X     */
  5028. X
  5029. X    if (position(TOP) == NULL_POSITION)
  5030. X    {
  5031. X        /*
  5032. X         * Nothing is currently displayed.
  5033. X         * Start at the beginning of the file.
  5034. X         * (This case is mainly for first_cmd searches,
  5035. X         * for example, "+/xyz" on the command line.)
  5036. X         */
  5037. X        pos = (POSITION)0;
  5038. X    } else if (!search_forward)
  5039. X    {
  5040. X        /*
  5041. X         * Backward search: start just before the top line
  5042. X         * displayed on the screen.
  5043. X         */
  5044. X        pos = position(TOP);
  5045. X    } else if (top_search)
  5046. X    {
  5047. X        /*
  5048. X         * Forward search and "start from top".
  5049. X         * Start at the second line displayed on the screen.
  5050. X         */
  5051. X        pos = position(TOP_PLUS_ONE);
  5052. X    } else
  5053. X    {
  5054. X        /*
  5055. X         * Forward search but don't "start from top".
  5056. X         * Start just after the bottom line displayed on the screen.
  5057. X         */
  5058. X        pos = position(BOTTOM_PLUS_ONE);
  5059. X    }
  5060. X
  5061. X    if (pos == NULL_POSITION)
  5062. X    {
  5063. X        /*
  5064. X         * Can't find anyplace to start searching from.
  5065. X         */
  5066. X        error("Nothing to search");
  5067. X        return;
  5068. X    }
  5069. X
  5070. X    for (;;)
  5071. X    {
  5072. X        /*
  5073. X         * Get lines until we find a matching one or 
  5074. X         * until we hit end-of-file (or beginning-of-file 
  5075. X         * if we're going backwards).
  5076. X         */
  5077. X        if (sigs)
  5078. X            /*
  5079. X             * A signal aborts the search.
  5080. X             */
  5081. X            return;
  5082. X
  5083. X        if (search_forward)
  5084. X        {
  5085. X            /*
  5086. X             * Read the next line, and save the 
  5087. X             * starting position of that line in linepos.
  5088. X             */
  5089. X            linepos = pos;
  5090. X            pos = forw_raw_line(pos);
  5091. X        } else
  5092. X        {
  5093. X            /*
  5094. X             * Read the previous line and save the
  5095. X             * starting position of that line in linepos.
  5096. X             */
  5097. X            pos = back_raw_line(pos);
  5098. X            linepos = pos;
  5099. X        }
  5100. X
  5101. X        if (pos == NULL_POSITION)
  5102. X        {
  5103. X            /*
  5104. X             * We hit EOF/BOF without a match.
  5105. X             */
  5106. X            error("Pattern not found");
  5107. X            return;
  5108. X        }
  5109. X
  5110. X        /*
  5111. X         * Test the next line to see if we have a match.
  5112. X         * This is done in a variety of ways, depending
  5113. X         * on what pattern matching functions are available.
  5114. X         */
  5115. X#if REGCMP
  5116. X        if ( (regex(cpattern, line) != NULL)
  5117. X#else
  5118. X#if RECOMP
  5119. X        if ( (re_exec(line) == 1)
  5120. X#else
  5121. X        if ( (match(pattern, line))
  5122. X#endif
  5123. X#endif
  5124. X                && (--n <= 0) )
  5125. X            /*
  5126. X             * Found the matching line.
  5127. X             */
  5128. X            break;
  5129. X    }
  5130. X
  5131. X    jump_loc(linepos);
  5132. X}
  5133. X
  5134. X#if (!REGCMP) && (!RECOMP)
  5135. X/*
  5136. X * We have neither regcmp() nor re_comp().
  5137. X * We use this function to do simple pattern matching.
  5138. X * It supports no metacharacters like *, etc.
  5139. X */
  5140. X    static int
  5141. Xmatch(pattern, buf)
  5142. X    char *pattern, *buf;
  5143. X{
  5144. X    register char *pp, *lp;
  5145. X
  5146. X    for ( ;  *buf != '\0';  buf++)
  5147. X    {
  5148. X        for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
  5149. X            if (*pp == '\0' || *lp == '\0')
  5150. X                break;
  5151. X        if (*pp == '\0')
  5152. X            return (1);
  5153. X    }
  5154. X    return (0);
  5155. X}
  5156. X#endif
  5157. SHAR_EOF
  5158. fi
  5159. if test -f 'prompt.c'
  5160. then
  5161.     echo shar: "will not over-write existing file 'prompt.c'"
  5162. else
  5163. sed 's/^X//' << \SHAR_EOF > 'prompt.c'
  5164. X/*
  5165. X * Prompting and other messages.
  5166. X * There are three flavors of prompts, SHORT, MEDIUM and LONG,
  5167. X * selected by the -m/-M options.
  5168. X * A prompt is either a colon or a message composed of various
  5169. X * pieces, such as the name of the file being viewed, the percentage
  5170. X * into the file, etc.
  5171. X */
  5172. X
  5173. X#include "less.h"
  5174. X#include "position.h"
  5175. X
  5176. Xextern int pr_type;
  5177. Xextern int ispipe;
  5178. Xextern int hit_eof;
  5179. Xextern int new_file;
  5180. Xextern int sc_width;
  5181. Xextern char current_file[];
  5182. Xextern int ac;
  5183. Xextern char **av;
  5184. Xextern int curr_ac;
  5185. X
  5186. X/*
  5187. X * Prototypes for the three flavors of prompts.
  5188. X * These strings are expanded by pr_expand().
  5189. X */
  5190. Xchar *prproto[] = { 
  5191. X    "fo",        /* PR_SHORT */
  5192. X    "foP",        /* PR_MEDIUM */
  5193. X    "Fobp"        /* PR_LONG */
  5194. X};
  5195. X
  5196. Xstatic char message[200];
  5197. Xstatic char *mp;
  5198. X
  5199. X    static void
  5200. Xsetmp()
  5201. X{
  5202. X    mp = message + strlen(message);
  5203. X}
  5204. X
  5205. X/*
  5206. X * Append the name of the current file (to the message buffer).
  5207. X */
  5208. X    static void
  5209. Xap_filename()
  5210. X{
  5211. X    if (ispipe)
  5212. X        return;
  5213. X    strtcpy(mp, current_file, &message[sizeof(message)] - mp);
  5214. X    setmp();
  5215. X}
  5216. X
  5217. X/*
  5218. X * Append the "file N of M" message.
  5219. X */
  5220. X    static void
  5221. Xap_of()
  5222. X{
  5223. X    if (ac <= 1)
  5224. X        return;
  5225. X    sprintf(mp, " (file %d of %d)", curr_ac+1, ac);
  5226. X    setmp();
  5227. X}
  5228. X
  5229. X/*
  5230. X * Append the byte offset into the current file.
  5231. X */
  5232. X    static void
  5233. Xap_byte()
  5234. X{
  5235. X    POSITION pos, len;
  5236. X
  5237. X    pos = position(BOTTOM_PLUS_ONE);
  5238. X    if (pos == NULL_POSITION)
  5239. X        pos = ch_length();
  5240. X    if (pos != NULL_POSITION)
  5241. X    {
  5242. X        sprintf(mp, " byte %ld", (long)pos);
  5243. X        setmp();
  5244. X        len = ch_length();
  5245. X        if (len > 0)
  5246. X        {
  5247. X            sprintf(mp, "/%ld", (long)len);
  5248. X            setmp();
  5249. X        }
  5250. X    }
  5251. X}
  5252. X
  5253. X/*
  5254. X * Append the percentage into the current file.
  5255. X * If we cannot find the percentage and must_print is true,
  5256. X * use the byte offset.
  5257. X */
  5258. X    static void
  5259. Xap_percent(must_print)
  5260. X{
  5261. X    POSITION pos,len;
  5262. X
  5263. X    pos = position(BOTTOM_PLUS_ONE);
  5264. X    len = ch_length();
  5265. X    if (len > 0 && pos != NULL_POSITION)
  5266. X    {
  5267. X        sprintf(mp, " (%ld%%)", (100 * (long)pos) / len);
  5268. X        setmp();
  5269. X    } else if (must_print)
  5270. X        ap_byte();
  5271. X}
  5272. X
  5273. X/*
  5274. X * Append the end-of-file message.
  5275. X */
  5276. X    static void
  5277. Xap_eof()
  5278. X{
  5279. X    strcpy(mp, " (END)");
  5280. X    setmp();
  5281. X    if (curr_ac + 1 < ac)
  5282. X    {
  5283. X        sprintf(mp, " - Next: %s", av[curr_ac+1]);
  5284. X        setmp();
  5285. X    }
  5286. X}
  5287. X
  5288. X/*
  5289. X * Construct a message based on a prototype string.
  5290. X */
  5291. X    static char *
  5292. Xpr_expand(proto, maxwidth)
  5293. X    char *proto;
  5294. X    int maxwidth;
  5295. X{
  5296. X    register char *p;
  5297. X
  5298. X    mp = message;
  5299. X
  5300. X    for (p = proto;  *p != '\0';  p++)
  5301. X    {
  5302. X        if (maxwidth > 0 && mp >= message + maxwidth)
  5303. X        {
  5304. X            /*
  5305. X             * Truncate to the screen width.
  5306. X             * {{ This isn't very nice. }}
  5307. X             */
  5308. X            mp = message + maxwidth;
  5309. X            break;
  5310. X        }
  5311. X        switch (*p)
  5312. X        {
  5313. X        case 'f':
  5314. X            if (new_file)
  5315. X                ap_filename();
  5316. X            break;
  5317. X        case 'F':
  5318. X            ap_filename();
  5319. X            break;
  5320. X        case 'o':
  5321. X            if (new_file)
  5322. X                ap_of();
  5323. X            break;
  5324. X        case 'O':
  5325. X            ap_of();
  5326. X            break;
  5327. X        case 'b':
  5328. X            ap_byte();
  5329. X            break;
  5330. X        case 'p':
  5331. X            if (!hit_eof)
  5332. X                ap_percent(0);
  5333. X            break;
  5334. X        case 'P':
  5335. X            if (!hit_eof)
  5336. X                ap_percent(1);
  5337. X            break;
  5338. X        case '<':
  5339. X            while (*++p != '>')
  5340. X            {
  5341. X                if (*p == '\0')
  5342. X                {
  5343. X                    p--;
  5344. X                    break;
  5345. X                }
  5346. X                *mp++ = *p;
  5347. X            }
  5348. X            break;
  5349. X        default:
  5350. X            *mp++ = *p;
  5351. X            break;
  5352. X          }
  5353. X    }
  5354. X    if (hit_eof)
  5355. X        ap_eof();
  5356. X
  5357. X    new_file = 0;
  5358. X    if (mp == message)
  5359. X        return (NULL);
  5360. X    *mp = '\0';
  5361. X    return (message);
  5362. X}
  5363. X
  5364. X/*
  5365. X * Return a message suitable for printing by the "=" command.
  5366. X */
  5367. X    public char *
  5368. Xeq_message()
  5369. X{
  5370. X    return (pr_expand("FObp", 0));
  5371. X}
  5372. X
  5373. X/*
  5374. X * Return a prompt.
  5375. X * This depends on the prompt type (SHORT, MEDIUM, LONG), etc.
  5376. X * If we can't come up with an appropriate prompt, return NULL
  5377. X * and the caller will prompt with a colon.
  5378. X */
  5379. X    public char *
  5380. Xpr_string()
  5381. X{
  5382. X    return (pr_expand(prproto[pr_type], sc_width-2));
  5383. X}
  5384. SHAR_EOF
  5385. fi
  5386. if test -f 'screen.c'
  5387. then
  5388.     echo shar: "will not over-write existing file 'screen.c'"
  5389. else
  5390. sed 's/^X//' << \SHAR_EOF > 'screen.c'
  5391. X/*
  5392. X * Routines which deal with the characteristics of the terminal.
  5393. X * Uses termcap to be as terminal-independent as possible.
  5394. X *
  5395. X * {{ Someday this should be rewritten to use curses. }}
  5396. X */
  5397. X
  5398. X#include "less.h"
  5399. X#if XENIX
  5400. X#include <sys/types.h>
  5401. X#include <sys/ioctl.h>
  5402. X#endif
  5403. X
  5404. X#if TERMIO
  5405. X#include <termio.h>
  5406. X#else
  5407. X#include <sgtty.h>
  5408. X#endif
  5409. X
  5410. X/*
  5411. X * Strings passed to tputs() to do various terminal functions.
  5412. X */
  5413. Xstatic char
  5414. X    *sc_pad,        /* Pad string */
  5415. X    *sc_home,        /* Cursor home */
  5416. X    *sc_addline,        /* Add line, scroll down following lines */
  5417. X    *sc_lower_left,        /* Cursor to last line, first column */
  5418. X    *sc_move,        /* General cursor positioning */
  5419. X    *sc_clear,        /* Clear screen */
  5420. X    *sc_eol_clear,        /* Clear to end of line */
  5421. X    *sc_s_in,        /* Enter standout (highlighted) mode */
  5422. X    *sc_s_out,        /* Exit standout mode */
  5423. X    *sc_u_in,        /* Enter underline mode */
  5424. X    *sc_u_out,        /* Exit underline mode */
  5425. X    *sc_b_in,        /* Enter bold mode */
  5426. X    *sc_b_out,        /* Exit bold mode */
  5427. X    *sc_visual_bell,    /* Visual bell (flash screen) sequence */
  5428. X    *sc_backspace,        /* Backspace cursor */
  5429. X    *sc_init,        /* Startup terminal initialization */
  5430. X    *sc_deinit;        /* Exit terminal de-intialization */
  5431. Xstatic int dumb;
  5432. Xstatic int hard;
  5433. X
  5434. Xpublic int auto_wrap;        /* Terminal does \r\n when write past margin */
  5435. Xpublic int ignaw;        /* Terminal ignores \n immediately after wrap */
  5436. Xpublic int erase_char, kill_char; /* The user's erase and line-kill chars */
  5437. Xpublic int sc_width, sc_height;    /* Height & width of screen */
  5438. Xpublic int sc_window = -1;    /* window size for forward and backward */
  5439. Xpublic int bo_width, be_width;    /* Printing width of boldface sequences */
  5440. Xpublic int ul_width, ue_width;    /* Printing width of underline sequences */
  5441. Xpublic int so_width, se_width;    /* Printing width of standout sequences */
  5442. X
  5443. X/*
  5444. X * These two variables are sometimes defined in,
  5445. X * and needed by, the termcap library.
  5446. X * It may be necessary on some systems to declare them extern here.
  5447. X */
  5448. X/*extern*/ short ospeed;    /* Terminal output baud rate */
  5449. X/*extern*/ char PC;        /* Pad character */
  5450. X
  5451. Xextern int quiet;        /* If VERY_QUIET, use visual bell for bell */
  5452. Xextern int know_dumb;        /* Don't complain about a dumb terminal */
  5453. Xextern int back_scroll;
  5454. Xchar *tgetstr();
  5455. Xchar *tgoto();
  5456. X
  5457. X/*
  5458. X * Change terminal to "raw mode", or restore to "normal" mode.
  5459. X * "Raw mode" means 
  5460. X *    1. An outstanding read will complete on receipt of a single keystroke.
  5461. X *    2. Input is not echoed.  
  5462. X *    3. On output, \n is mapped to \r\n.
  5463. X *    4. \t is NOT expanded into spaces.
  5464. X *    5. Signal-causing characters such as ctrl-C (interrupt),
  5465. X *       etc. are NOT disabled.
  5466. X * It doesn't matter whether an input \n is mapped to \r, or vice versa.
  5467. X */
  5468. X    public void
  5469. Xraw_mode(on)
  5470. X    int on;
  5471. X{
  5472. X#if TERMIO
  5473. X    struct termio s;
  5474. X    static struct termio save_term;
  5475. X
  5476. X    if (on)
  5477. X    {
  5478. X        /*
  5479. X         * Get terminal modes.
  5480. X         */
  5481. X        ioctl(2, TCGETA, &s);
  5482. X
  5483. X        /*
  5484. X         * Save modes and set certain variables dependent on modes.
  5485. X         */
  5486. X        save_term = s;
  5487. X        ospeed = s.c_cflag & CBAUD;
  5488. X        erase_char = s.c_cc[VERASE];
  5489. X        kill_char = s.c_cc[VKILL];
  5490. X
  5491. X        /*
  5492. X         * Set the modes to the way we want them.
  5493. X         */
  5494. X        s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
  5495. X        s.c_oflag |=  (OPOST|ONLCR|TAB3);
  5496. X        s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
  5497. X        s.c_cc[VMIN] = 1;
  5498. X        s.c_cc[VTIME] = 0;
  5499. X    } else
  5500. X    {
  5501. X        /*
  5502. X         * Restore saved modes.
  5503. X         */
  5504. X        s = save_term;
  5505. X    }
  5506. X    ioctl(2, TCSETAW, &s);
  5507. X#else
  5508. X    struct sgttyb s;
  5509. X    static struct sgttyb save_term;
  5510. X
  5511. X    if (on)
  5512. X    {
  5513. X        /*
  5514. X         * Get terminal modes.
  5515. X         */
  5516. X        ioctl(2, TIOCGETP, &s);
  5517. X
  5518. X        /*
  5519. X         * Save modes and set certain variables dependent on modes.
  5520. X         */
  5521. X        save_term = s;
  5522. X        ospeed = s.sg_ospeed;
  5523. X        erase_char = s.sg_erase;
  5524. X        kill_char = s.sg_kill;
  5525. X
  5526. X        /*
  5527. X         * Set the modes to the way we want them.
  5528. X         */
  5529. X        s.sg_flags |= CBREAK;
  5530. X        s.sg_flags &= ~(ECHO|XTABS);
  5531. X    } else
  5532. X    {
  5533. X        /*
  5534. X         * Restore saved modes.
  5535. X         */
  5536. X        s = save_term;
  5537. X    }
  5538. X    ioctl(2, TIOCSETN, &s);
  5539. X#endif
  5540. X}
  5541. X
  5542. X    static void
  5543. Xcannot(s)
  5544. X    char *s;
  5545. X{
  5546. X    char message[100];
  5547. X
  5548. X    if (know_dumb)
  5549. X        /* 
  5550. X         * He knows he has a dumb terminal, so don't tell him. 
  5551. X         */
  5552. X        return;
  5553. X
  5554. X    sprintf(message, "WARNING: terminal cannot \"%s\"", s);
  5555. X    error(message);
  5556. X}
  5557. X
  5558. X/*
  5559. X * Get terminal capabilities via termcap.
  5560. X */
  5561. X    public void
  5562. Xget_term()
  5563. X{
  5564. X    char termbuf[1024];
  5565. X    char *sp;
  5566. X    static char sbuf[150];
  5567. X
  5568. X    char *getenv();
  5569. X
  5570. X    /*
  5571. X     * Find out what kind of terminal this is.
  5572. X     */
  5573. X    if (tgetent(termbuf, getenv("TERM")) <= 0)
  5574. X        dumb = 1;
  5575. X
  5576. X    /*
  5577. X     * Get size of the screen.
  5578. X     */
  5579. X    if (dumb || (sc_height = tgetnum("li")) < 0 || tgetflag("hc"))
  5580. X    {
  5581. X        /* Oh no, this is a hardcopy terminal. */
  5582. X        hard = 1;
  5583. X        sc_height = 24;
  5584. X    }
  5585. X    /*
  5586. X     * This is terrible - the following if "knows" that it is being
  5587. X     * executed *after* command line and environment options have
  5588. X     * already been parsed.  Should it be executed in the main program
  5589. X     * instead?
  5590. X     */
  5591. X    if ((sc_window <= 0) || (sc_window >= sc_height))
  5592. X        sc_window = sc_height-1;
  5593. X    if (dumb || (sc_width = tgetnum("co")) < 0)
  5594. X        sc_width = 80;
  5595. X
  5596. X    auto_wrap = tgetflag("am");
  5597. X    ignaw = tgetflag("xn");
  5598. X
  5599. X    /*
  5600. X     * Assumes termcap variable "sg" is the printing width of
  5601. X     * the standout sequence, the end standout sequence,
  5602. X     * the underline sequence, the end underline sequence,
  5603. X     * the boldface sequence, and the end boldface sequence.
  5604. X     */
  5605. X    if ((so_width = tgetnum("sg")) < 0)
  5606. X        so_width = 0;
  5607. X    be_width = bo_width = ue_width = ul_width = se_width = so_width;
  5608. X
  5609. X    /*
  5610. X     * Get various string-valued capabilities.
  5611. X     */
  5612. X    sp = sbuf;
  5613. X
  5614. X    sc_pad = (dumb) ? NULL : tgetstr("pc", &sp);
  5615. X    if (sc_pad != NULL)
  5616. X        PC = *sc_pad;
  5617. X
  5618. X    sc_init = (dumb) ? NULL : tgetstr("ti", &sp);
  5619. X    if (sc_init == NULL)
  5620. X        sc_init = "";
  5621. X
  5622. X    sc_deinit= (dumb) ? NULL : tgetstr("te", &sp);
  5623. X    if (sc_deinit == NULL)
  5624. X        sc_deinit = "";
  5625. X
  5626. X    sc_eol_clear = (dumb) ? NULL : tgetstr("ce", &sp);
  5627. X    if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
  5628. X    {
  5629. X        cannot("clear to end of line");
  5630. X        sc_eol_clear = "";
  5631. X    }
  5632. X
  5633. X    sc_clear = (dumb) ? NULL : tgetstr("cl", &sp);
  5634. X    if (hard || sc_clear == NULL || *sc_clear == '\0')
  5635. X    {
  5636. X        cannot("clear screen");
  5637. X        sc_clear = "\n\n";
  5638. X    }
  5639. X
  5640. X    sc_move = (dumb) ? NULL : tgetstr("cm", &sp);
  5641. X    if (hard || sc_move == NULL || *sc_move == '\0')
  5642. X    {
  5643. X        /*
  5644. X         * This is not an error here, because we don't 
  5645. X         * always need sc_move.
  5646. X         * We need it only if we don't have home or lower-left.
  5647. X         */
  5648. X        sc_move = "";
  5649. X    }
  5650. X
  5651. X    sc_s_in = (dumb) ? NULL : tgetstr("so", &sp);
  5652. X    if (hard || sc_s_in == NULL)
  5653. X        sc_s_in = "";
  5654. X
  5655. X    sc_s_out = (dumb) ? NULL : tgetstr("se", &sp);
  5656. X    if (hard || sc_s_out == NULL)
  5657. X        sc_s_out = "";
  5658. X
  5659. X    sc_u_in = (dumb) ? NULL : tgetstr("us", &sp);
  5660. X    if (hard || sc_u_in == NULL)
  5661. X        sc_u_in = sc_s_in;
  5662. X
  5663. X    sc_u_out = (dumb) ? NULL : tgetstr("ue", &sp);
  5664. X    if (hard || sc_u_out == NULL)
  5665. X        sc_u_out = sc_s_out;
  5666. X
  5667. X    sc_b_in = (dumb) ? NULL : tgetstr("md", &sp);
  5668. X    if (hard || sc_b_in == NULL)
  5669. X    {
  5670. X        sc_b_in = sc_s_in;
  5671. X        sc_b_out = sc_s_out;
  5672. X    } else
  5673. X    {
  5674. X        sc_b_out = (dumb) ? NULL : tgetstr("me", &sp);
  5675. X        if (hard || sc_b_out == NULL)
  5676. X            sc_b_out = "";
  5677. X    }
  5678. X
  5679. X    sc_visual_bell = (dumb) ? NULL : tgetstr("vb", &sp);
  5680. X    if (hard || sc_visual_bell == NULL)
  5681. X        sc_visual_bell = "";
  5682. X
  5683. X    sc_home = (dumb) ? NULL : tgetstr("ho", &sp);
  5684. X    if (hard || sc_home == NULL || *sc_home == '\0')
  5685. X    {
  5686. X        if (*sc_move == '\0')
  5687. X        {
  5688. X            cannot("home cursor");
  5689. X            /*
  5690. X             * This last resort for sc_home is supposed to
  5691. X             * be an up-arrow suggesting moving to the 
  5692. X             * top of the "virtual screen". (The one in
  5693. X             * your imagination as you try to use this on
  5694. X             * a hard copy terminal.)
  5695. X             */
  5696. X            sc_home = "|\b^";        
  5697. X        } else
  5698. X        {
  5699. X            /* 
  5700. X             * No "home" string,
  5701. X             * but we can use "move(0,0)".
  5702. X             */
  5703. X            strcpy(sp, tgoto(sc_move, 0, 0));
  5704. X            sc_home = sp;
  5705. X            sp += strlen(sp) + 1;
  5706. X        }
  5707. X    }
  5708. X
  5709. X    sc_lower_left = (dumb) ? NULL : tgetstr("ll", &sp);
  5710. X    if (hard || sc_lower_left == NULL || *sc_lower_left == '\0')
  5711. X    {
  5712. X        if (*sc_move == '\0')
  5713. X        {
  5714. X            cannot("move cursor to lower left of screen");
  5715. X            sc_lower_left = "\r";
  5716. X        } else
  5717. X        {
  5718. X            /*
  5719. X             * No "lower-left" string, 
  5720. X             * but we can use "move(0,last-line)".
  5721. X             */
  5722. X            strcpy(sp, tgoto(sc_move, 0, sc_height-1));
  5723. X            sc_lower_left = sp;
  5724. X            sp += strlen(sp) + 1;
  5725. X        }
  5726. X    }
  5727. X
  5728. X    /*
  5729. X     * To add a line at top of screen and scroll the display down,
  5730. X     * we use "al" (add line) or "sr" (scroll reverse).
  5731. X     */
  5732. X    if (dumb)
  5733. X        sc_addline = NULL;
  5734. X    else if ((sc_addline = tgetstr("al", &sp)) == NULL || 
  5735. X         *sc_addline == '\0')
  5736. X        sc_addline = tgetstr("sr", &sp);
  5737. X
  5738. X    if (hard || sc_addline == NULL || *sc_addline == '\0')
  5739. X    {
  5740. X        cannot("scroll backwards");
  5741. X        sc_addline = "";
  5742. X        /* Force repaint on any backward movement */
  5743. X        back_scroll = 0;
  5744. X    }
  5745. X
  5746. X    if (dumb || tgetflag("bs"))
  5747. X        sc_backspace = "\b";
  5748. X    else
  5749. X    {
  5750. X        sc_backspace = tgetstr("bc", &sp);
  5751. X        if (sc_backspace == NULL || *sc_backspace == '\0')
  5752. X            sc_backspace = "\b";
  5753. X    }
  5754. X}
  5755. X
  5756. X
  5757. X/*
  5758. X * Below are the functions which perform all the 
  5759. X * terminal-specific screen manipulation.
  5760. X */
  5761. X
  5762. X
  5763. X/*
  5764. X * Initialize terminal
  5765. X */
  5766. X    public void
  5767. Xinit()
  5768. X{
  5769. X    tputs(sc_init, sc_height, putc);
  5770. X}
  5771. X
  5772. X/*
  5773. X * Deinitialize terminal
  5774. X */
  5775. X    public void
  5776. Xdeinit()
  5777. X{
  5778. X    tputs(sc_deinit, sc_height, putc);
  5779. X}
  5780. X
  5781. X/*
  5782. X * Home cursor (move to upper left corner of screen).
  5783. X */
  5784. X    public void
  5785. Xhome()
  5786. X{
  5787. X    tputs(sc_home, 1, putc);
  5788. X}
  5789. X
  5790. X/*
  5791. X * Add a blank line (called with cursor at home).
  5792. X * Should scroll the display down.
  5793. X */
  5794. X    public void
  5795. Xadd_line()
  5796. X{
  5797. X    tputs(sc_addline, sc_height, putc);
  5798. X}
  5799. X
  5800. X/*
  5801. X * Move cursor to lower left corner of screen.
  5802. X */
  5803. X    public void
  5804. Xlower_left()
  5805. X{
  5806. X    tputs(sc_lower_left, 1, putc);
  5807. X}
  5808. X
  5809. X/*
  5810. X * Ring the terminal bell.
  5811. X */
  5812. X    public void
  5813. Xbell()
  5814. X{
  5815. X    if (quiet == VERY_QUIET)
  5816. X        vbell();
  5817. X    else
  5818. X        putc('\7');
  5819. X}
  5820. X
  5821. X/*
  5822. X * Output the "visual bell", if there is one.
  5823. X */
  5824. X    public void
  5825. Xvbell()
  5826. X{
  5827. X    if (*sc_visual_bell == '\0')
  5828. X        return;
  5829. X    tputs(sc_visual_bell, sc_height, putc);
  5830. X}
  5831. X
  5832. X/*
  5833. X * Clear the screen.
  5834. X */
  5835. X    public void
  5836. Xclear()
  5837. X{
  5838. X    tputs(sc_clear, sc_height, putc);
  5839. X}
  5840. X
  5841. X/*
  5842. X * Clear from the cursor to the end of the cursor's line.
  5843. X * {{ This must not move the cursor. }}
  5844. X */
  5845. X    public void
  5846. Xclear_eol()
  5847. X{
  5848. X    tputs(sc_eol_clear, 1, putc);
  5849. X}
  5850. X
  5851. X/*
  5852. X * Begin "standout" (bold, underline, or whatever).
  5853. X */
  5854. X    public void
  5855. Xso_enter()
  5856. X{
  5857. X    tputs(sc_s_in, 1, putc);
  5858. X}
  5859. X
  5860. X/*
  5861. X * End "standout".
  5862. X */
  5863. X    public void
  5864. Xso_exit()
  5865. X{
  5866. X    tputs(sc_s_out, 1, putc);
  5867. X}
  5868. X
  5869. X/*
  5870. X * Begin "underline" (hopefully real underlining, 
  5871. X * otherwise whatever the terminal provides).
  5872. X */
  5873. X    public void
  5874. Xul_enter()
  5875. X{
  5876. X    tputs(sc_u_in, 1, putc);
  5877. X}
  5878. X
  5879. X/*
  5880. X * End "underline".
  5881. X */
  5882. X    public void
  5883. Xul_exit()
  5884. X{
  5885. X    tputs(sc_u_out, 1, putc);
  5886. X}
  5887. X
  5888. X/*
  5889. X * Begin "bold"
  5890. X */
  5891. X    public void
  5892. Xbo_enter()
  5893. X{
  5894. X    tputs(sc_b_in, 1, putc);
  5895. X}
  5896. X
  5897. X/*
  5898. X * End "bold".
  5899. X */
  5900. X    public void
  5901. Xbo_exit()
  5902. X{
  5903. X    tputs(sc_b_out, 1, putc);
  5904. X}
  5905. X
  5906. X/*
  5907. X * Erase the character to the left of the cursor 
  5908. X * and move the cursor left.
  5909. X */
  5910. X    public void
  5911. Xbackspace()
  5912. X{
  5913. X    /* 
  5914. X     * Try to erase the previous character by overstriking with a space.
  5915. X     */
  5916. X    tputs(sc_backspace, 1, putc);
  5917. X    putc(' ');
  5918. X    tputs(sc_backspace, 1, putc);
  5919. X}
  5920. X
  5921. X/*
  5922. X * Output a plain backspace, without erasing the previous char.
  5923. X */
  5924. X    public void
  5925. Xputbs()
  5926. X{
  5927. X    tputs(sc_backspace, 1, putc);
  5928. X}
  5929. SHAR_EOF
  5930. fi
  5931. if test -f 'signal.c'
  5932. then
  5933.     echo shar: "will not over-write existing file 'signal.c'"
  5934. else
  5935. sed 's/^X//' << \SHAR_EOF > 'signal.c'
  5936. X/*
  5937. X * Routines dealing with signals.
  5938. X *
  5939. X * A signal usually merely causes a bit to be set in the "signals" word.
  5940. X * At some convenient time, the mainline code checks to see if any
  5941. X * signals need processing by calling psignal().
  5942. X * An exception is made if we are reading from the keyboard when the
  5943. X * signal is received.  Some operating systems will simply call the
  5944. X * signal handler and NOT return from the read (with EINTR).
  5945. X * To handle this case, we service the interrupt directly from
  5946. X * the handler if we are reading from the keyboard.
  5947. X */
  5948. X
  5949. X#include "less.h"
  5950. X#include <signal.h>
  5951. X#include <setjmp.h>
  5952. X
  5953. X/*
  5954. X * The type of signal handler functions.
  5955. X * Usually int, although it should be void.
  5956. X */
  5957. Xtypedef    int        HANDLER;
  5958. X
  5959. X/*
  5960. X * "sigs" contains bits indicating signals which need to be processed.
  5961. X */
  5962. Xpublic int sigs;
  5963. X#define    S_INTERRUPT    01
  5964. X#ifdef SIGTSTP
  5965. X#define    S_STOP        02
  5966. X#endif
  5967. X
  5968. Xextern int reading;
  5969. Xextern char *first_cmd;
  5970. Xextern jmp_buf main_loop;
  5971. X
  5972. X/*
  5973. X * Interrupt signal handler.
  5974. X */
  5975. X    static HANDLER
  5976. Xinterrupt()
  5977. X{
  5978. X    SIGNAL(SIGINT, interrupt);
  5979. X    sigs |= S_INTERRUPT;
  5980. X    if (reading)
  5981. X        psignals();
  5982. X}
  5983. X
  5984. X#ifdef SIGTSTP
  5985. X/*
  5986. X * "Stop" (^Z) signal handler.
  5987. X */
  5988. X    static HANDLER
  5989. Xstop()
  5990. X{
  5991. X    SIGNAL(SIGTSTP, stop);
  5992. X    sigs |= S_STOP;
  5993. X    if (reading)
  5994. X        psignals();
  5995. X}
  5996. X#endif
  5997. X
  5998. X/*
  5999. X * Set up the signal handlers.
  6000. X */
  6001. X    public void
  6002. Xinit_signals()
  6003. X{
  6004. X    (void) SIGNAL(SIGINT, interrupt);
  6005. X#ifdef SIGTSTP
  6006. X    (void) SIGNAL(SIGTSTP, stop);
  6007. X#endif
  6008. X}
  6009. X
  6010. X/*
  6011. X * Process any signals we have recieved.
  6012. X * A received signal cause a bit to be set in "sigs".
  6013. X */
  6014. X    public void 
  6015. Xpsignals()
  6016. X{
  6017. X    register int tsignals;
  6018. X
  6019. X    tsignals = sigs;
  6020. X    sigs = 0;
  6021. X    if (tsignals == 0)
  6022. X        return;
  6023. X
  6024. X    dropout();        /* Discard any buffered output */
  6025. X
  6026. X#ifdef SIGTSTP
  6027. X    if (tsignals & S_STOP)
  6028. X    {
  6029. X        /*
  6030. X         * Clean up the terminal.
  6031. X         */
  6032. X#ifdef SIGTTOU
  6033. X        SIGNAL(SIGTTOU, SIG_IGN);
  6034. X#endif
  6035. X        lower_left();
  6036. X        clear_eol();
  6037. X        flush();
  6038. X        raw_mode(0);
  6039. X#ifdef SIGTTOU
  6040. X        SIGNAL(SIGTTOU, SIG_DFL);
  6041. X#endif
  6042. X        SIGNAL(SIGTSTP, SIG_DFL);
  6043. X#if SIGSETMASK
  6044. X        /*
  6045. X         * This system will not allow us to send a 
  6046. X         * stop signal (SIGTSTP) to ourself
  6047. X         * while we are in the signal handler, like maybe now.
  6048. X         * (This can be the case if we are reading; see comment above.)
  6049. X         * So we ask the silly system for permission to do so.
  6050. X         */
  6051. X        sigsetmask(0);
  6052. X#endif
  6053. X        kill(getpid(), SIGTSTP);
  6054. X        /*
  6055. X         * ... Bye bye. ...
  6056. X         * Hopefully we'll be back later and resume here...
  6057. X         * Reset the terminal and arrange to repaint the
  6058. X         * screen when we get back to the main command loop.
  6059. X         */
  6060. X        SIGNAL(SIGTSTP, stop);
  6061. X        raw_mode(1);
  6062. X        first_cmd = "r";
  6063. X        longjmp(main_loop, 1);
  6064. X    }
  6065. X#endif
  6066. X    if (tsignals & S_INTERRUPT)
  6067. X    {
  6068. X        bell();
  6069. X        /*
  6070. X         * {{ You may wish to replace the bell() with 
  6071. X         *    error("Interrupt"); }}
  6072. X         */
  6073. X    }
  6074. X
  6075. X    longjmp(main_loop, 1);
  6076. X}
  6077. X
  6078. X/*
  6079. X * Pass the specified command to a shell to be executed.
  6080. X * Like plain "system()", but handles resetting terminal modes, etc.
  6081. X */
  6082. X    public void
  6083. Xlsystem(cmd)
  6084. X    char *cmd;
  6085. X{
  6086. X    int inp;
  6087. X
  6088. X    /*
  6089. X     * Print the command which is to be executed,
  6090. X     * unless the command starts with a "-".
  6091. X     */
  6092. X    if (cmd[0] == '-')
  6093. X        cmd++;
  6094. X    else
  6095. X    {
  6096. X        lower_left();
  6097. X        clear_eol();
  6098. X        puts("!");
  6099. X        puts(cmd);
  6100. X        puts("\n");
  6101. X    }
  6102. X
  6103. X    /*
  6104. X     * De-initialize the terminal and take out of raw mode.
  6105. X     */
  6106. X    deinit();
  6107. X    flush();
  6108. X    raw_mode(0);
  6109. X
  6110. X    /*
  6111. X     * Restore signals to their defaults.
  6112. X     */
  6113. X    SIGNAL(SIGINT, SIG_DFL);
  6114. X#ifdef SIGTSTP
  6115. X    SIGNAL(SIGTSTP, SIG_DFL);
  6116. X#endif
  6117. X    /*
  6118. X     * Force standard input to be the terminal, "/dev/tty".
  6119. X     */
  6120. X    inp = dup(0);
  6121. X    close(0);
  6122. X    open("/dev/tty", 0);
  6123. X
  6124. X    /*
  6125. X     * Pass the command to the system to be executed.
  6126. X     */
  6127. X    system(cmd);
  6128. X
  6129. X    /*
  6130. X     * Restore standard input, reset signals, raw mode, etc.
  6131. X     */
  6132. X    close(0);
  6133. X    dup(inp);
  6134. X    close(inp);
  6135. X
  6136. X    init_signals();
  6137. X    raw_mode(1);
  6138. X    init();
  6139. X}
  6140. X
  6141. X/*
  6142. X * Expand a filename, substituting any environment variables, etc.
  6143. X * The implementation of this is necessarily very operating system
  6144. X * dependent.  This implementation is unabashedly only for Unix systems.
  6145. X */
  6146. X#if GLOB
  6147. X
  6148. X#include <stdio.h>
  6149. X
  6150. X    char *
  6151. Xglob(filename)
  6152. X    char *filename;
  6153. X{
  6154. X    FILE *f;
  6155. X    char *p;
  6156. X    int ch;
  6157. X    static char filebuf[128];
  6158. X    static char ECHO[] = "echo ";
  6159. X
  6160. X    strcpy(filebuf, ECHO);
  6161. X    strtcpy(filebuf+sizeof(ECHO)-1, filename, sizeof(filebuf)-sizeof(ECHO));
  6162. X    if ((f = popen(filebuf, "r")) == NULL)
  6163. X        return (filename);
  6164. X    for (p = filebuf;  p < &filebuf[sizeof(filebuf)-1];  p++)
  6165. X    {
  6166. X        if ((ch = getc(f)) == '\n' || ch == EOF)
  6167. X            break;
  6168. X        *p = ch;
  6169. X    }
  6170. X    *p = '\0';
  6171. X    pclose(f);
  6172. X    return (filebuf);
  6173. X}
  6174. X
  6175. X#else
  6176. X
  6177. X    char *
  6178. Xglob(filename)
  6179. X    char *filename;
  6180. X{
  6181. X    return (filename);
  6182. X}
  6183. X
  6184. X#endif
  6185. SHAR_EOF
  6186. fi
  6187. if test -f 'ttyin.c'
  6188. then
  6189.     echo shar: "will not over-write existing file 'ttyin.c'"
  6190. else
  6191. sed 's/^X//' << \SHAR_EOF > 'ttyin.c'
  6192. X/*
  6193. X * Routines dealing with getting input from the keyboard (i.e. from the user).
  6194. X */
  6195. X
  6196. X#include "less.h"
  6197. X
  6198. X/*
  6199. X * The boolean "reading" is set true or false according to whether
  6200. X * we are currently reading from the keyboard.
  6201. X * This information is used by the signal handling stuff in signal.c.
  6202. X * {{ There are probably some race conditions here
  6203. X *    involving the variable "reading". }}
  6204. X */
  6205. Xpublic int reading;
  6206. X
  6207. Xstatic int tty;
  6208. X
  6209. X/*
  6210. X * Open keyboard for input.
  6211. X * (Just use file descriptor 2.)
  6212. X */
  6213. X    public void
  6214. Xopen_getc()
  6215. X{
  6216. X    tty = 2;
  6217. X}
  6218. X
  6219. X/*
  6220. X * Get a character from the keyboard.
  6221. X */
  6222. X    public int
  6223. Xgetc()
  6224. X{
  6225. X    char c;
  6226. X    int result;
  6227. X
  6228. X    reading = 1;
  6229. X    do
  6230. X    {
  6231. X        flush();
  6232. X        result = read(tty, &c, 1);
  6233. X    } while (result != 1);
  6234. X    reading = 0;
  6235. X    return (c & 0177);
  6236. X}
  6237. SHAR_EOF
  6238. fi
  6239. if test -f 'version.c'
  6240. then
  6241.     echo shar: "will not over-write existing file 'version.c'"
  6242. else
  6243. sed 's/^X//' << \SHAR_EOF > 'version.c'
  6244. X/*
  6245. X *        less
  6246. X *    Copyright (c) 1984,1985  Mark Nudelman
  6247. X *
  6248. X *    This program may be freely used and/or modified, 
  6249. X *    with the following provisions:
  6250. X *    1. This notice and the above copyright notice must remain intact.
  6251. X *    2. Neither this program, nor any modification of it,
  6252. X *       may be sold for profit without written consent of the author.
  6253. X *
  6254. X *    -----------------------------------------------------------------
  6255. X *
  6256. X *    This program is a paginator similar to "more", 
  6257. X *    but allows you to move both forward and backward in the file.  
  6258. X *    Commands are based on "more" and "vi".
  6259. X *
  6260. X *    ----------------------- CHANGES ---------------------------------
  6261. X *
  6262. X *        Allowed use on standard input        1/29/84   markn
  6263. X *        Added E, N, P commands            2/1/84    markn
  6264. X *        Added '=' command, 'stop' signal handling    4/17/84   markn
  6265. X *        Added line folding                4/20/84   markn
  6266. X *    v2: Fixed '=' command to use BOTTOM_PLUS_ONE, 
  6267. X *        instead of TOP, added 'p' & 'v' commands    4/27/84   markn
  6268. X *    v3: Added -m and -t options, '-' command    5/3/84    markn
  6269. X *    v4: Added LESS environment variable        5/3/84    markn
  6270. X *    v5: New comments, fixed '-' command slightly    5/3/84    markn
  6271. X *    v6: Added -Q, visual bell            5/15/84   markn
  6272. X *    v7: Fixed jump_back(n) bug: n should count real
  6273. X *        lines, not folded lines.  Also allow number
  6274. X *        on G command.                5/24/84   markn
  6275. X *    v8: Re-do -q and -Q commands            5/30/84   markn
  6276. X *    v9: Added "+<cmd>" argument            9/25/84   markn
  6277. X *    v10: Fixed bug in -b<n> argument processing    10/10/84  markn
  6278. X *    v11: Made error() ring bell if \n not entered.    10/18/84  markn
  6279. X *    -----------------------------------------------------------------
  6280. X *    v12: Reorganized signal handling and made
  6281. X *         portable to 4.2bsd.            2/13/85   mark
  6282. X *    v13: Reword error message for '-' command.    2/16/85   mark
  6283. X *    v14: Added -bf and -bp variants of -b.        2/22/85   mark
  6284. X *    v15: Miscellaneous changes.            2/25/85   mark
  6285. X *    v16: Added -u flag for backspace processing.    3/13/85   mark
  6286. X *    v17: Added j and k commands, 
  6287. X *        changed -t default.            4/13/85   mark
  6288. X *    v18: Rewrote signal handling code.        4/20/85   mark
  6289. X *    v19: Got rid of "verbose" eq_message().        5/2/85    mark
  6290. X *         Made search() scroll in some cases.
  6291. X *    v20: Fixed screen.c ioctls for System V.    5/21/85   mark
  6292. X *    v21: Fixed some first_cmd bugs.            5/23/85   mark
  6293. X *    v22: Added support for no RECOMP nor REGCMP.    5/24/85   mark
  6294. X *     v23: Miscellanous changes and prettying up.    5/25/85   mark
  6295. X *        Posted to USENET.
  6296. X *      v24: Added ti,te terminal init & de-init       6/3/85 Mike Kersenbrock
  6297. X *    v25: Added -U flag, standout mode underlining.    6/8/85    mark
  6298. X *    v26: Added -M flag.                6/9/85    mark
  6299. X *         Use underline termcap (us) if it exists.
  6300. X *    v27: Renamed some variables to make unique in    6/15/85   mark
  6301. X *         6 chars.  Minor fix to -m.
  6302. X *    v28: Fixed right margin bug.            6/28/85   mark
  6303. X *    v29: Incorporated M.Rose's changes to signal.c    6/28/85   mark
  6304. X *    v30: Fixed stupid bug in argument processing.    6/29/85   mark
  6305. X *    v31: Added -p flag, changed repaint algorithm.  7/15/85   mark
  6306. X *         Added kludge for magic cookie terminals.
  6307. X *    v32: Added cat_file if output not a tty.    7/16/85   mark
  6308. X *    v33: Added -e flag and EDITOR.            7/23/85   mark
  6309. X *    v34: Added -s flag.                7/26/85   mark
  6310. X *    v35: Rewrote option handling; added option.c.    7/27/85   mark
  6311. X *    v36: Fixed -e flag to work if not last file.    7/29/85   mark
  6312. X *    v37: Added -x flag.                8/10/85   mark
  6313. X *    v38: Changed prompting; created prompt.c.    8/19/85   mark
  6314. X *    v39: (Not -p) does not initially clear screen.    8/24/85   mark
  6315. X *    v40: Added "skipping" indicator in forw().    8/26/85   mark
  6316. X *        Posted to USENET.
  6317. X *    v41: ONLY_RETURN, control char commands,    9/17/85   mark
  6318. X *         faster search, other minor fixes.
  6319. X *    v42: Added ++ command line syntax;        9/25/85   mark
  6320. X *         ch_fsize for pipes.
  6321. X *    v43: Added -h flag, changed prim.c algorithms.    10/15/85  mark
  6322. X *    v44: Made END print in all cases of eof;    10/16/85  mark
  6323. X *         ignore SIGTTOU after receiving SIGTSTP.
  6324. X *    v45: Never print backspaces unless -u.        10/16/85  mark
  6325. X *    v46: Backwards scroll in jump_loc.        10/24/85  mark
  6326. X *    v47: Fixed bug in edit(): *first_cmd==0        10/30/85  mark
  6327. X *    v48: Use TIOCSETN instead of TIOCSETP.        11/16/85  mark
  6328. X *         Added marks (m and ' commands).
  6329. X *        Posted to USENET.
  6330. X *    -----------------------------------------------------------------
  6331. X *    v49: Fixed bug: signal didn't clear mcc.    1/9/86    mark
  6332. X *    v50: Added ' (quote) to gomark.            1/15/86   mark
  6333. X *    v51: Added + cmd, fixed problem if first_cmd
  6334. X *         fails, made g cmd sort of "work" on pipes
  6335. X *         even if bof is no longer buffered.        1/16/86   mark
  6336. X *    v52: Made short files work better.        1/17/86   mark
  6337. X *    v53: Added -P option.                1/20/86   mark
  6338. X *    v54: Changed help to use HELPFILE.        1/20/86   mark
  6339. X *    v55: Messages work better if not tty output.    1/23/86   mark
  6340. X *    v56: Added -l option.                1/24/86   mark
  6341. X *    v57: Fixed -l to get confirmation before
  6342. X *         overwriting an existing file.        1/31/86   mark
  6343. X *    v58: Added filename globbing.            8/28/86   mark
  6344. X *    v59: Fixed some bugs with very long filenames.    9/15/86   mark
  6345. X *    v60: Incorporated changes from Leith (Casey)
  6346. X *         Leedom for boldface and -z option.        9/26/86   mark
  6347. X *    v61: Got rid of annoying repaints after ! cmd.    9/26/86   mark
  6348. X *    -----------------------------------------------------------------
  6349. X */
  6350. X
  6351. Xchar version[] = "@(#) less  version 61";
  6352. SHAR_EOF
  6353. fi
  6354. cd ..
  6355. exit 0
  6356. #    End of shell archive
  6357.