home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume3 / less / part1 next >
Internet Message Format  |  1986-11-30  |  59KB

  1. From: ihnp4!nsc!nsc-pdc!rgb (Robert Bond)
  2. Subject: less part 1 of 2
  3. Newsgroups: mod.sources
  4. Approved: jpn@panda.UUCP
  5.  
  6. Mod.sources:  Volume 3, Issue 120
  7. Submitted by: ihnp4!nsc!nsc-pdc!rgb (Robert Bond)
  8.  
  9.  
  10.  
  11. Here is the last distribution of less made by Mark Nudelman to net.sources
  12. before he left National Semiconductor.  Since it is taking so long for him
  13. to get back on the net, and because lots of folks did not get part 2
  14. of the last distribution, we have decided to submit less to mod.sources.
  15. Mark is still promising to return to the net Real Soon Now.
  16.  
  17. #!/bin/sh-----cut here-----cut here-----cut here-----cut here-----
  18. # shar:    Shell Archiver
  19. #    Run the following text with /bin/sh to create:
  20. #    INSTALLATION
  21. #    less.l
  22. #    makefile.bsd41
  23. #    makefile.bsd42
  24. #    makefile.sys5
  25. #    makefile.xen
  26. #    funcs.h
  27. #    less.h
  28. #    position.h
  29. #    mkfuncs.awk
  30. #    main.c
  31. #    option.c
  32. #    prim.c
  33. echo shar: extracting INSTALLATION
  34. cat - << \SHAR_EOF > INSTALLATION
  35. This is the distribution of "less", a paginator similar to "more" or "pg".
  36. The manual page is in less.l.
  37.  
  38. INSTALLATION:
  39.  
  40. 1. Move the distributed source to its own directory and 
  41.    unpack it by running "sh" on the distribution file,
  42.    if you have not already done so.
  43.  
  44. 2. If your system is System V:
  45.     cp makefile.sys5 makefile
  46.    If your system is Berkeley 4.2bsd:
  47.     cp makefile.bsd42 makefile
  48.    If your system is Berkeley 4.1bsd:
  49.     cp makefile.bsd41 makefile
  50.    If your system is Xenix 3.0:
  51.     cp makefile.xen makefile
  52.    Otherwise, edit the makefile to make the 
  53.    system parameters match your system.
  54.  
  55.    These features are selectable at compile time:
  56.     shell escapes (SHELL_ESCAPE)
  57.     editor invocation (EDITOR)
  58.     alternate error message handling (ONLY_RETURN)
  59.    If you want to have any of these features, 
  60.    edit the makefile appropriately.
  61.    (If you do not include either SHELL_ESCAPE or EDITOR,
  62.     you may wish to edit the manual page "less.l" to remove
  63.     the references to the "!" and/or "v" commands.)
  64.  
  65. 3. Type "make" and watch the fun.
  66.  
  67. 4. If the make succeeds, it will generate a program "less"
  68.    in your current directory.  Test the generated program.
  69.  
  70. 5. When satisfied that it works, if you wish to install it
  71.    in a public place, edit the makefile so that INSTALL_LESS
  72.    and INSTALL_MAN are the proper filenames.
  73.    Then type "make install".
  74.  
  75. If you have any problems building or running "less", 
  76. you may mail to the author via USENET at:
  77.     ...!tektronix!reed!nsc-pdc!mark
  78.   or    ...!ihnp4!nsc!nsc-pdc!mark
  79.  
  80. Note to hackers: comments noting possible improvements are enclosed
  81. in double curly brackets {{ like this }}.
  82. SHAR_EOF
  83. echo shar: extracting less.l
  84. cat - << \SHAR_EOF > less.l
  85. .TH LESS l
  86. .SH NAME
  87. less \- opposite of more
  88. .SH SYNOPSIS
  89. .B "less [-cdepstwmMqQuU] [-h\fIn\fB] [-b[fp]\fIn\fB] [-x\fIn\fB] [+\fIcmd\fB] [\fIname\fB] ..."
  90. .SH DESCRIPTION
  91. .I Less
  92. is a program similar to 
  93. .I more
  94. (1), but which allows backwards movement
  95. in the file as well as forward movement.
  96. Also,
  97. .I less
  98. does not have to read the entire input file before starting,
  99. so with large input files it starts up faster than text editors like
  100. .I vi
  101. (1).
  102. .I Less
  103. uses termcap, so it can run on a variety of terminals.
  104. There is even limited support for hardcopy terminals.
  105. (On a hardcopy terminal, lines which should be printed at the top
  106. of the screen are prefixed with an up-arrow.)
  107. .PP
  108. Commands are based on both
  109. .I more
  110. and
  111. .I vi.
  112. Commands may be preceeded by a decimal number, 
  113. called N in the descriptions below.
  114. The number is used by some commands, as indicated.
  115.  
  116. .SH COMMANDS
  117. .IP h
  118. Help: display a summary of these commands.
  119. If you forget all the other commands, remember this one.
  120. .PP
  121. .IP SPACE
  122. Scroll forward N lines, default one screen.
  123. If N is more than the screen size, only one screenful is displayed.
  124. .PP
  125. .IP f
  126. Same as SPACE.
  127. .PP
  128. .IP b
  129. Scroll backward N lines, default one screen.
  130. If N is more than the screen size, only one screenful is displayed.
  131. .PP
  132. .IP RETURN
  133. Scroll forward N lines, default 1.
  134. If N is more than the screen size, the entire N lines are displayed.
  135. .PP
  136. .IP e
  137. Same as RETURN.
  138. .PP
  139. .IP j
  140. Also the same as RETURN.
  141. .PP
  142. .IP y
  143. Scroll backward N lines, default 1.
  144. If N is more than the screen size, the entire N lines are displayed.
  145. .IP k
  146. Same as y.
  147. .PP
  148. .IP d
  149. Scroll forward N lines, default 10.
  150. If N is specified, it becomes the new default for all d and u commands.
  151. .PP
  152. .IP u
  153. Scroll backward N lines, default 10.
  154. If N is specified, it becomes the new default for all d and u commands.
  155. .PP
  156. .IP r
  157. Repaint the screen.
  158. .PP
  159. .IP R
  160. Repaint the screen, discarding any buffered input.
  161. Useful if the file is changing while it is being viewed.
  162. .PP
  163. .IP g
  164. Go to line N in the file, default 1 (beginning of file).
  165. (Warning: this may be slow if N is large.)
  166. .PP
  167. .IP G
  168. Go to line N in the file, default the end of the file.
  169. (Warning: this may be slow if standard input, 
  170. rather than a file, is being read.)
  171. .PP
  172. .IP p
  173. Go to a position N percent into the file.
  174. N should be between 0 and 100.
  175. (This is possible if standard input is being read,
  176. but only if
  177. .I less
  178. has already read to the end of the file.
  179. It is always fast, but not always useful.)
  180. .PP
  181. .IP %
  182. Same as p.
  183. .PP
  184. .IP m
  185. Followed by any lowercase letter, marks the current position with that letter.
  186. .PP
  187. .IP "'"
  188. Followed by any lowercase letter, returns to the position which
  189. was previously marked with that letter.
  190. All marks are lost when a new file is examined.
  191. .PP
  192. .IP /pattern
  193. Search forward in the file for the N-th occurence of the pattern.
  194. N defaults to 1.
  195. The pattern is a regular expression, as recognized by
  196. .I ed.
  197. The search starts at the second line displayed
  198. (but see the -t option, which changes this).
  199. .PP
  200. .IP ?pattern
  201. Search backward in the file for the N-th occurence of the pattern.
  202. The search starts at the line immediately before the top line displayed.
  203. .PP
  204. .IP n
  205. Repeat previous search, for N-th occurence of the last pattern.
  206. .PP
  207. .IP E [filename]
  208. Examine a new file.
  209. If the filename is missing, the "current" file (see the N and P commands
  210. below) from the list of files in the command line is re-examined.
  211. .PP
  212. .IP N
  213. Examine the next file (from the list of files given in the command line).
  214. If a number N is specified (not to be confused with the command N),
  215. the N-th next file is examined.
  216. .PP
  217. .IP P
  218. Examine the previous file.
  219. If a number N is specified, the N-th previous file is examined.
  220. .PP
  221. .IP =
  222. Prints the name of the file being viewed
  223. and the byte offset of the bottom line being displayed.
  224. If possible, it also prints the length of the file
  225. and the percent of the file above the last displayed line.
  226. .PP
  227. .IP \-
  228. Followed by one of the command line option letters (see below),
  229. this will toggle the setting of that option
  230. and print a message describing the new setting.
  231. .PP
  232. .IP V
  233. Prints the version number of 
  234. .I less 
  235. being run.
  236. .PP
  237. .IP q
  238. Exits
  239. .I less.
  240. .PP
  241. The following 
  242. two 
  243. commands may or may not be valid, depending on your particular installation.
  244. .PP
  245. .IP v
  246. Invokes an editor to edit the current file being viewed.
  247. The editor is taken from the environment variable EDITOR,
  248. or defaults to "vi".
  249. .PP
  250. .IP "! shell-command"
  251. Invokes a shell to run the shell-command given.
  252. .PP
  253. .SH OPTIONS
  254. Command line options are described below.
  255. Options are also taken from the environment variable "LESS".
  256. (The environment variable is parsed before the command line,
  257. so command line options override the LESS environment variable.
  258. Options may be changed while
  259. .I less 
  260. is running via the "\-" command.)
  261. For example, if you like 
  262. more-style prompting, to avoid typing "less -m ..." each time 
  263. .I less 
  264. is invoked, you might tell 
  265. .I csh:
  266. .sp
  267. setenv LESS m
  268. .sp
  269. or if you use 
  270. .I sh:
  271. .sp
  272. LESS=m; export LESS
  273. .IP -s
  274. The -s flag causes
  275. consecutive blank lines to be squeezed into a single blank line.
  276. This is useful when viewing
  277. .I nroff
  278. output.
  279. .IP -t
  280. Normally, forward searches start just after
  281. the top displayed line (that is, at the second displayed line).
  282. Thus forward searches include the currently displayed screen.
  283. The -t command line option causes forward searches to start 
  284. just after the bottom line displayed,
  285. thus skipping the currently displayed screen.
  286. .IP -m
  287. Normally,
  288. .I less
  289. prompts with a colon.
  290. The -m command line option causes 
  291. .I less
  292. to prompt verbosely like 
  293. .I more,
  294. printing the file name and percent into the file.
  295. .IP -M
  296. The -M command line option causes 
  297. .I less
  298. to prompt even more verbosely than 
  299. .I more.
  300. .IP -q
  301. Normally, if an attempt is made to scroll past the end of the file
  302. or before the beginning of the file, the terminal bell is rung to
  303. indicate this fact.
  304. The -q command line option tells
  305. .I less
  306. not to ring the bell at such times.
  307. If the terminal has a "visual bell", it is used instead.
  308. .IP -Q
  309. Even if -q is given, 
  310. .I less 
  311. will ring the bell on certain other errors,
  312. such as typing an invalid character.
  313. The -Q command line option tells
  314. .I less
  315. to be quiet all the time; that is, never ring the terminal bell.
  316. If the terminal has a "visual bell", it is used instead.
  317. .IP -e
  318. Normally the only way to exit less is via the "q" command.
  319. The -e command line option tells less to automatically exit
  320. the second time it reaches end-of-file.
  321. .IP -u
  322. If the -u command line option is given, 
  323. backspaces are treated as printable characters;
  324. that is, they are sent to the terminal when they appear in the input.
  325. .IP -U
  326. If the -U command line option is given,
  327. backspaces are printed as the two character sequence "^H".
  328. If neither -u nor -U is given,
  329. backspaces which appear adjacent to an underscore character
  330. are treated specially:
  331. the underlined text is displayed 
  332. using the terminal's hardware underlining capability.
  333. .IP -w
  334. Normally,
  335. .I less
  336. uses a tilde character to represent lines past the end of the file.
  337. The -w option causes blank lines to be used instead.
  338. .IP -d
  339. Normally,
  340. .I less
  341. will complain if the terminal is dumb; that is, lacks some important capability,
  342. such as the ability to clear the screen or scroll backwards.
  343. The -d flag suppresses this complaint 
  344. (but does not otherwise change the behavior of the program on a dumb terminal).
  345. .IP -p
  346. Normally, 
  347. .I less 
  348. will repaint the screen by scrolling from the bottom of the screen.
  349. If the -p flag is set, when
  350. .I less 
  351. needs to change the entire display, it will clear the screen
  352. and paint from the top line down.
  353. .IP -h
  354. Normally,
  355. .I less
  356. will scroll backwards when backwards movement is necessary.
  357. The -h option specifies a maximum number of lines to scroll backwards.
  358. If it is necessary to move backwards more than this many lines,
  359. the screen is repainted in a forward direction.
  360. (If the terminal does not have the ability to scroll
  361. backwards, -h0 is implied.)
  362. .IP -x
  363. The -x\fIn\fR command line option sets tab stops every \fIn\fR positions.
  364. The default for \fIn\fR is 8.
  365. .IP -b
  366. The -b\fIn\fR command line option tells
  367. .I less
  368. to use a non-standard buffer size.
  369. There are two standard (default) buffer sizes,
  370. one is used when a file is being read and the other
  371. when a pipe (standard input) is being read.
  372. The current defaults are 5 buffers for files and 12 for pipes.
  373. (Buffers are 1024 bytes.)
  374. The number \fIn\fR specifies a different number of buffers to use.
  375. The -b may be followed by "f", in which case only 
  376. the file default is changed, or by "p" in which case only the 
  377. pipe default is changed.  Otherwise, both are changed.
  378. .IP -c
  379. Normally, when data is read by
  380. .I less,
  381. it is scanned to ensure that bit 7 (the high order bit) is turned off in
  382. each byte read, and to ensure that there are no null (zero) bytes in
  383. the data (null bytes are turned into "@" characters).
  384. If the data is known to be "clean",
  385. the -c command line option will tell 
  386. .I less
  387. to skip this checking, causing an imperceptible speed improvement.
  388. (However, if the data is not "clean", unpredicatable results may occur.)
  389. .IP +
  390. If a command line option begins with \fB+\fR,
  391. the remainder of that option is taken to be an initial command to
  392. .I less.
  393. For example, +G tells
  394. .I less
  395. to start at the end of the file rather than the beginning,
  396. and +/xyz tells it to start at the first occurence of "xyz" in the file.
  397. As a special case, +<number> acts like +<number>g; 
  398. that is, it starts the display at the specified line number
  399. (however, see the caveat under the "g" command above).
  400. If the option starts with \fB++\fR, the initial command applies to
  401. every file being viewed, not just the first one.
  402.  
  403. .SH BUGS
  404. When used on standard input (rather than a file), you can move
  405. backwards only a finite amount, corresponding to that portion
  406. of the file which is still buffered.
  407. SHAR_EOF
  408. echo shar: extracting makefile.bsd41
  409. cat - << \SHAR_EOF > makefile.bsd41
  410. # Makefile for "less"
  411. #
  412. # Invoked as:
  413. #    make all
  414. #   or    make install
  415. # Plain "make" is equivalent to "make all".
  416. #
  417. # If you add or delete functions, remake funcs.h by doing:
  418. #    make newfuncs
  419. # This depends on the coding convention of function headers looking like:
  420. #    " \t public <function-type> \n <function-name> ( ... ) "
  421. #
  422. # Also provided:
  423. #    make lint    # Runs "lint" on all the sources.
  424. #    make clean    # Removes "less" and the .o files.
  425. #    make clobber    # Pretty much the same as make "clean".
  426.  
  427.  
  428. ##########################################################################
  429. # System-specific parameters
  430. ##########################################################################
  431.  
  432. # Define XENIX if running under XENIX 3.0
  433. XENIX = 0
  434.  
  435. # VOID is 1 if your C compiler supports the "void" type,
  436. # 0 if it does not.
  437. VOID = 1
  438.  
  439. # off_t is the type which lseek() returns.
  440. # It is also the type of lseek()'s second argument.
  441. off_t = long
  442.  
  443. # TERMIO is 1 if your system has /usr/include/termio.h.
  444. # This is normally the case for System 5.
  445. # If TERMIO is 0 your system must have /usr/include/sgtty.h.
  446. # This is normally the case for BSD.
  447. TERMIO = 0
  448.  
  449. # SIGSETMASK is 1 if your system has the sigsetmask() call.
  450. # This is normally the case only for BSD 4.2,
  451. # not for BSD 4.1 or System 5.
  452. SIGSETMASK = 0
  453.  
  454.  
  455. ##########################################################################
  456. # Optional and semi-optional features
  457. ##########################################################################
  458.  
  459. # REGCMP is 1 if your system has the regcmp() function.
  460. # This is normally the case for System 5.
  461. # RECOMP is 1 if your system has the re_comp() function.
  462. # This is normally the case for BSD.
  463. # If neither is 1, pattern matching is supported, but without metacharacters.
  464. REGCMP = 0
  465. RECOMP = 1
  466.  
  467. # SHELL_ESCAPE is 1 if you wish to allow shell escapes.
  468. # (This is possible only if your system supplies the system() function.)
  469. SHELL_ESCAPE = 0
  470.  
  471. # EDITOR is 1 if you wish to allow editor invocation (the "v" command).
  472. # (This is possible only if your system supplies the system() function.)
  473. # EDIT_PGM is the name of the (default) editor to be invoked.
  474. EDITOR = 0
  475. EDIT_PGM = /usr/ucb/vi
  476.  
  477. # ONLY_RETURN is 1 if you want RETURN to be the only input which
  478. # will continue past an error message.
  479. # Otherwise, any key will continue past an error message.
  480. ONLY_RETURN = 0
  481.  
  482.  
  483. ##########################################################################
  484. # Compilation environment.
  485. ##########################################################################
  486.  
  487. # LIBS is the list of libraries needed.
  488. LIBS = -ltermcap
  489.  
  490. # INSTALL_LESS is a list of the public versions of less.
  491. # INSTALL_MAN is a list of the public versions of the manual page.
  492. INSTALL_LESS =    /usr/local/less
  493. INSTALL_MAN =    /usr/man/manl/less.l
  494.  
  495. # OPTIM is passed to the compiler and the loader.
  496. # It is normally "-O" but may be, for example, "-g".
  497. OPTIM = -O
  498.  
  499.  
  500. ##########################################################################
  501. # Files
  502. ##########################################################################
  503.  
  504. SRC1 =    main.c option.c prim.c 
  505. SRC2 =    ch.c position.c input.c output.c screen.c \
  506.     prompt.c line.c signal.c help.c ttyin.c command.c version.c
  507. SRC =    $(SRC1) $(SRC2)
  508. OBJ =    main.o option.o prim.o ch.o position.o input.o output.o screen.o \
  509.     prompt.o line.o signal.o help.o ttyin.o command.o version.o
  510.  
  511.  
  512. ##########################################################################
  513. # Rules
  514. ##########################################################################
  515.  
  516. DEFS =    "-DTERMIO=$(TERMIO)" \
  517.     "-DSIGSETMASK=$(SIGSETMASK)" \
  518.     "-Doff_t=$(off_t)" "-DVOID=$(VOID)" \
  519.     "-DREGCMP=$(REGCMP)" "-DRECOMP=$(RECOMP)" \
  520.     "-DSHELL_ESCAPE=$(SHELL_ESCAPE)" \
  521.     "-DEDITOR=$(EDITOR)" "-DEDIT_PGM=\"$(EDIT_PGM)\"" \
  522.     "-DONLY_RETURN=$(ONLY_RETURN)" \
  523.     "-DXENIX=$(XENIX)"
  524.  
  525. CFLAGS = $(OPTIM) $(DEFS)
  526.  
  527.  
  528. all: less
  529.  
  530. less: $(OBJ)
  531.     cc $(OPTIM) -o less $(OBJ) $(LIBS)
  532.  
  533. install: install_man install_less
  534.  
  535. install_man: less.l
  536.     for f in $(INSTALL_MAN); do  rm -f $$f; cp less.l $$f;  done
  537.     touch install_man
  538.     
  539. install_less: less
  540.     for f in $(INSTALL_LESS); do  rm -f $$f; cp less $$f;  done
  541.     touch install_less
  542.  
  543. $(OBJ): less.h funcs.h
  544.  
  545. lint:
  546.     lint -hp $(DEFS) $(SRC)
  547.  
  548. newfuncs:
  549.     mv funcs.h funcs.h.OLD
  550.     awk -f mkfuncs.awk $(SRC) >funcs.h
  551.  
  552. clean:
  553.     rm -f $(OBJ) less
  554.  
  555. clobber:
  556.     rm -f *.o less install_less install_man
  557.  
  558. shar:
  559.     shar -v INSTALLATION less.l makefile.* *.h *.awk $(SRC1) > less.shar.a
  560.     shar -v $(SRC2) > less.shar.b
  561. SHAR_EOF
  562. echo shar: extracting makefile.bsd42
  563. cat - << \SHAR_EOF > makefile.bsd42
  564. # Makefile for "less"
  565. #
  566. # Invoked as:
  567. #    make all
  568. #   or    make install
  569. # Plain "make" is equivalent to "make all".
  570. #
  571. # If you add or delete functions, remake funcs.h by doing:
  572. #    make newfuncs
  573. # This depends on the coding convention of function headers looking like:
  574. #    " \t public <function-type> \n <function-name> ( ... ) "
  575. #
  576. # Also provided:
  577. #    make lint    # Runs "lint" on all the sources.
  578. #    make clean    # Removes "less" and the .o files.
  579. #    make clobber    # Pretty much the same as make "clean".
  580.  
  581.  
  582. ##########################################################################
  583. # System-specific parameters
  584. ##########################################################################
  585.  
  586. # Define XENIX if running under XENIX 3.0
  587. XENIX = 0
  588.  
  589. # VOID is 1 if your C compiler supports the "void" type,
  590. # 0 if it does not.
  591. VOID = 1
  592.  
  593. # off_t is the type which lseek() returns.
  594. # It is also the type of lseek()'s second argument.
  595. off_t = long
  596.  
  597. # TERMIO is 1 if your system has /usr/include/termio.h.
  598. # This is normally the case for System 5.
  599. # If TERMIO is 0 your system must have /usr/include/sgtty.h.
  600. # This is normally the case for BSD.
  601. TERMIO = 0
  602.  
  603. # SIGSETMASK is 1 if your system has the sigsetmask() call.
  604. # This is normally the case only for BSD 4.2,
  605. # not for BSD 4.1 or System 5.
  606. SIGSETMASK = 1
  607.  
  608.  
  609. ##########################################################################
  610. # Optional and semi-optional features
  611. ##########################################################################
  612.  
  613. # REGCMP is 1 if your system has the regcmp() function.
  614. # This is normally the case for System 5.
  615. # RECOMP is 1 if your system has the re_comp() function.
  616. # This is normally the case for BSD.
  617. # If neither is 1, pattern matching is supported, but without metacharacters.
  618. REGCMP = 0
  619. RECOMP = 1
  620.  
  621. # SHELL_ESCAPE is 1 if you wish to allow shell escapes.
  622. # (This is possible only if your system supplies the system() function.)
  623. SHELL_ESCAPE = 0
  624.  
  625. # EDITOR is 1 if you wish to allow editor invocation (the "v" command).
  626. # (This is possible only if your system supplies the system() function.)
  627. # EDIT_PGM is the name of the (default) editor to be invoked.
  628. EDITOR = 0
  629. EDIT_PGM = /usr/ucb/vi
  630.  
  631. # ONLY_RETURN is 1 if you want RETURN to be the only input which
  632. # will continue past an error message.
  633. # Otherwise, any key will continue past an error message.
  634. ONLY_RETURN = 0
  635.  
  636.  
  637. ##########################################################################
  638. # Compilation environment.
  639. ##########################################################################
  640.  
  641. # LIBS is the list of libraries needed.
  642. LIBS = -ltermcap
  643.  
  644. # INSTALL_LESS is a list of the public versions of less.
  645. # INSTALL_MAN is a list of the public versions of the manual page.
  646. INSTALL_LESS =    /usr/local/less
  647. INSTALL_MAN =    /usr/man/manl/less.l
  648.  
  649. # OPTIM is passed to the compiler and the loader.
  650. # It is normally "-O" but may be, for example, "-g".
  651. OPTIM = -O
  652.  
  653.  
  654. ##########################################################################
  655. # Files
  656. ##########################################################################
  657.  
  658. SRC1 =    main.c option.c prim.c
  659. SRC2 =    ch.c position.c input.c output.c screen.c \
  660.     prompt.c line.c signal.c help.c ttyin.c command.c version.c
  661. SRC =    $(SRC1) $(SRC2)
  662. OBJ =    main.o option.o prim.o ch.o position.o input.o output.o screen.o \
  663.     prompt.o line.o signal.o help.o ttyin.o command.o version.o
  664.  
  665.  
  666. ##########################################################################
  667. # Rules
  668. ##########################################################################
  669.  
  670. DEFS =    "-DTERMIO=$(TERMIO)" \
  671.     "-DSIGSETMASK=$(SIGSETMASK)" \
  672.     "-Doff_t=$(off_t)" "-DVOID=$(VOID)" \
  673.     "-DREGCMP=$(REGCMP)" "-DRECOMP=$(RECOMP)" \
  674.     "-DSHELL_ESCAPE=$(SHELL_ESCAPE)" \
  675.     "-DEDITOR=$(EDITOR)" "-DEDIT_PGM=\"$(EDIT_PGM)\"" \
  676.     "-DONLY_RETURN=$(ONLY_RETURN)" \
  677.     "-DXENIX=$(XENIX)"
  678.  
  679. CFLAGS = $(OPTIM) $(DEFS)
  680.  
  681.  
  682. all: less
  683.  
  684. less: $(OBJ)
  685.     cc $(OPTIM) -o less $(OBJ) $(LIBS)
  686.  
  687. install: install_man install_less
  688.  
  689. install_man: less.l
  690.     for f in $(INSTALL_MAN); do  rm -f $$f; cp less.l $$f;  done
  691.     touch install_man
  692.     
  693. install_less: less
  694.     for f in $(INSTALL_LESS); do  rm -f $$f; cp less $$f;  done
  695.     touch install_less
  696.  
  697. $(OBJ): less.h funcs.h
  698.  
  699. lint:
  700.     lint -hp $(DEFS) $(SRC)
  701.  
  702. newfuncs:
  703.     mv funcs.h funcs.h.OLD
  704.     awk -f mkfuncs.awk $(SRC) >funcs.h
  705.  
  706. clean:
  707.     rm -f $(OBJ) less
  708.  
  709. clobber:
  710.     rm -f *.o less install_less install_man
  711.  
  712. shar:
  713.     shar -v INSTALLATION less.l makefile.* *.h *.awk $(SRC1) > less.shar.a
  714.     shar -v $(SRC2) > less.shar.b
  715. SHAR_EOF
  716. echo shar: extracting makefile.sys5
  717. cat - << \SHAR_EOF > makefile.sys5
  718. # Makefile for "less"
  719. #
  720. # Invoked as:
  721. #    make all
  722. #   or    make install
  723. # Plain "make" is equivalent to "make all".
  724. #
  725. # If you add or delete functions, remake funcs.h by doing:
  726. #    make newfuncs
  727. # This depends on the coding convention of function headers looking like:
  728. #    " \t public <function-type> \n <function-name> ( ... ) "
  729. #
  730. # Also provided:
  731. #    make lint    # Runs "lint" on all the sources.
  732. #    make clean    # Removes "less" and the .o files.
  733. #    make clobber    # Pretty much the same as make "clean".
  734.  
  735.  
  736. ##########################################################################
  737. # System-specific parameters
  738. ##########################################################################
  739.  
  740. # Define XENIX if running under XENIX 3.0
  741. XENIX = 0
  742.  
  743. # VOID is 1 if your C compiler supports the "void" type,
  744. # 0 if it does not.
  745. VOID = 1
  746.  
  747. # off_t is the type which lseek() returns.
  748. # It is also the type of lseek()'s second argument.
  749. off_t = long
  750.  
  751. # TERMIO is 1 if your system has /usr/include/termio.h.
  752. # This is normally the case for System 5.
  753. # If TERMIO is 0 your system must have /usr/include/sgtty.h.
  754. # This is normally the case for BSD.
  755. TERMIO = 1
  756.  
  757. # SIGSETMASK is 1 if your system has the sigsetmask() call.
  758. # This is normally the case only for BSD 4.2,
  759. # not for BSD 4.1 or System 5.
  760. SIGSETMASK = 0
  761.  
  762.  
  763. ##########################################################################
  764. # Optional and semi-optional features
  765. ##########################################################################
  766.  
  767. # REGCMP is 1 if your system has the regcmp() function.
  768. # This is normally the case for System 5.
  769. # RECOMP is 1 if your system has the re_comp() function.
  770. # This is normally the case for BSD.
  771. # If neither is 1, pattern matching is supported, but without metacharacters.
  772. REGCMP = 1
  773. RECOMP = 0
  774.  
  775. # SHELL_ESCAPE is 1 if you wish to allow shell escapes.
  776. # (This is possible only if your system supplies the system() function.)
  777. SHELL_ESCAPE = 0
  778.  
  779. # EDITOR is 1 if you wish to allow editor invocation (the "v" command).
  780. # (This is possible only if your system supplies the system() function.)
  781. # EDIT_PGM is the name of the (default) editor to be invoked.
  782. EDITOR = 0
  783. EDIT_PGM = /usr/ucb/vi
  784.  
  785. # ONLY_RETURN is 1 if you want RETURN to be the only input which
  786. # will continue past an error message.
  787. # Otherwise, any key will continue past an error message.
  788. ONLY_RETURN = 0
  789.  
  790.  
  791. ##########################################################################
  792. # Compilation environment.
  793. ##########################################################################
  794.  
  795. # LIBS is the list of libraries needed.
  796. LIBS = -lcurses -lPW
  797.  
  798. # INSTALL_LESS is a list of the public versions of less.
  799. # INSTALL_MAN is a list of the public versions of the manual page.
  800. INSTALL_LESS =    /usr/lbin/less
  801. INSTALL_MAN =    /usr/man/manl/less.l
  802.  
  803. # OPTIM is passed to the compiler and the loader.
  804. # It is normally "-O" but may be, for example, "-g".
  805. OPTIM = -O
  806.  
  807.  
  808. ##########################################################################
  809. # Files
  810. ##########################################################################
  811.  
  812. SRC1 =    main.c option.c prim.c 
  813. SRC2 =    ch.c position.c input.c output.c screen.c \
  814.     prompt.c line.c signal.c help.c ttyin.c command.c version.c
  815. SRC =    $(SRC1) $(SRC2)
  816. OBJ =    main.o option.o prim.o ch.o position.o input.o output.o screen.o \
  817.     prompt.o line.o signal.o help.o ttyin.o command.o version.o
  818.  
  819.  
  820. ##########################################################################
  821. # Rules
  822. ##########################################################################
  823.  
  824. DEFS =    "-DTERMIO=$(TERMIO)" \
  825.     "-DSIGSETMASK=$(SIGSETMASK)" \
  826.     "-Doff_t=$(off_t)" "-DVOID=$(VOID)" \
  827.     "-DREGCMP=$(REGCMP)" "-DRECOMP=$(RECOMP)" \
  828.     "-DSHELL_ESCAPE=$(SHELL_ESCAPE)" \
  829.     "-DEDITOR=$(EDITOR)" "-DEDIT_PGM=\"$(EDIT_PGM)\"" \
  830.     "-DONLY_RETURN=$(ONLY_RETURN)" \
  831.     "-DXENIX=$(XENIX)"
  832.  
  833. CFLAGS = $(OPTIM) $(DEFS)
  834.  
  835.  
  836. all: less
  837.  
  838. less: $(OBJ)
  839.     cc $(OPTIM) -o less $(OBJ) $(LIBS)
  840.  
  841. install: install_man install_less
  842.  
  843. install_man: less.l
  844.     for f in $(INSTALL_MAN); do  rm -f $$f; cp less.l $$f;  done
  845.     touch install_man
  846.     
  847. install_less: less
  848.     for f in $(INSTALL_LESS); do  rm -f $$f; cp less $$f;  done
  849.     touch install_less
  850.  
  851. $(OBJ): less.h funcs.h
  852.  
  853. lint:
  854.     lint -hp $(DEFS) $(SRC)
  855.  
  856. newfuncs:
  857.     mv funcs.h funcs.h.OLD
  858.     awk -f mkfuncs.awk $(SRC) >funcs.h
  859.  
  860. clean:
  861.     rm -f $(OBJ) less
  862.  
  863. clobber:
  864.     rm -f *.o less install_less install_man
  865.  
  866. shar:
  867.     shar -v INSTALLATION less.l makefile.* *.h *.awk $(SRC1) > less.shar.a
  868.     shar -v $(SRC2) > less.shar.b
  869. SHAR_EOF
  870. echo shar: extracting makefile.xen
  871. cat - << \SHAR_EOF > makefile.xen
  872. # Makefile for "less"
  873. #
  874. # Invoked as:
  875. #    make all
  876. #   or    make install
  877. # Plain "make" is equivalent to "make all".
  878. #
  879. # If you add or delete functions, remake funcs.h by doing:
  880. #    make newfuncs
  881. # This depends on the coding convention of function headers looking like:
  882. #    " \t public <function-type> \n <function-name> ( ... ) "
  883. #
  884. # Also provided:
  885. #    make lint    # Runs "lint" on all the sources.
  886. #    make clean    # Removes "less" and the .o files.
  887. #    make clobber    # Pretty much the same as make "clean".
  888.  
  889.  
  890. ##########################################################################
  891. # System-specific parameters
  892. ##########################################################################
  893.  
  894. # Define XENIX if running under XENIX 3.0
  895. XENIX = 1
  896.  
  897. # VOID is 1 if your C compiler supports the "void" type,
  898. # 0 if it does not.
  899. VOID = 1
  900.  
  901. # off_t is the type which lseek() returns.
  902. # It is also the type of lseek()'s second argument.
  903. off_t = long
  904.  
  905. # TERMIO is 1 if your system has /usr/include/termio.h.
  906. # This is normally the case for System 5.
  907. # If TERMIO is 0 your system must have /usr/include/sgtty.h.
  908. # This is normally the case for BSD.
  909. TERMIO = 1
  910.  
  911. # SIGSETMASK is 1 if your system has the sigsetmask() call.
  912. # This is normally the case only for BSD 4.2,
  913. # not for BSD 4.1 or System 5.
  914. SIGSETMASK = 0
  915.  
  916.  
  917. ##########################################################################
  918. # Optional and semi-optional features
  919. ##########################################################################
  920.  
  921. # REGCMP is 1 if your system has the regcmp() function.
  922. # This is normally the case for System 5.
  923. # RECOMP is 1 if your system has the re_comp() function.
  924. # This is normally the case for BSD.
  925. # If neither is 1, pattern matching is supported, but without metacharacters.
  926. REGCMP = 1
  927. RECOMP = 0
  928.  
  929. # SHELL_ESCAPE is 1 if you wish to allow shell escapes.
  930. # (This is possible only if your system supplies the system() function.)
  931. SHELL_ESCAPE = 0
  932.  
  933. # EDITOR is 1 if you wish to allow editor invocation (the "v" command).
  934. # (This is possible only if your system supplies the system() function.)
  935. # EDIT_PGM is the name of the (default) editor to be invoked.
  936. EDITOR = 0
  937. EDIT_PGM = /usr/ucb/vi
  938.  
  939. # ONLY_RETURN is 1 if you want RETURN to be the only input which
  940. # will continue past an error message.
  941. # Otherwise, any key will continue past an error message.
  942. ONLY_RETURN = 0
  943.  
  944.  
  945. ##########################################################################
  946. # Compilation environment.
  947. ##########################################################################
  948.  
  949. # LIBS is the list of libraries needed.
  950. LIBS = -lcurses -ltermlib
  951.  
  952. # INSTALL_LESS is a list of the public versions of less.
  953. # INSTALL_MAN is a list of the public versions of the manual page.
  954. INSTALL_LESS =    /usr/lbin/less
  955. INSTALL_MAN =    /usr/man/manl/less.l
  956.  
  957. # OPTIM is passed to the compiler and the loader.
  958. # It is normally "-O" but may be, for example, "-g".
  959. OPTIM = -O
  960.  
  961.  
  962. ##########################################################################
  963. # Files
  964. ##########################################################################
  965.  
  966. SRC1 =    main.c option.c prim.c 
  967. SRC2 =    ch.c position.c input.c output.c screen.c \
  968.     prompt.c line.c signal.c help.c ttyin.c command.c version.c
  969. SRC =    $(SRC1) $(SRC2)
  970. OBJ =    main.o option.o prim.o ch.o position.o input.o output.o screen.o \
  971.     prompt.o line.o signal.o help.o ttyin.o command.o version.o
  972.  
  973.  
  974. ##########################################################################
  975. # Rules
  976. ##########################################################################
  977.  
  978. DEFS =    "-DTERMIO=$(TERMIO)" \
  979.     "-DSIGSETMASK=$(SIGSETMASK)" \
  980.     "-Doff_t=$(off_t)" "-DVOID=$(VOID)" \
  981.     "-DREGCMP=$(REGCMP)" "-DRECOMP=$(RECOMP)" \
  982.     "-DSHELL_ESCAPE=$(SHELL_ESCAPE)" \
  983.     "-DEDITOR=$(EDITOR)" "-DEDIT_PGM=\"$(EDIT_PGM)\"" \
  984.     "-DONLY_RETURN=$(ONLY_RETURN)" \
  985.     "-DXENIX=$(XENIX)"
  986.  
  987. CFLAGS = $(OPTIM) $(DEFS)
  988.  
  989.  
  990. all: less
  991.  
  992. less: $(OBJ)
  993.     cc $(OPTIM) -o less $(OBJ) $(LIBS)
  994.  
  995. install: install_man install_less
  996.  
  997. install_man: less.l
  998.     for f in $(INSTALL_MAN); do  rm -f $$f; cp less.l $$f;  done
  999.     touch install_man
  1000.     
  1001. install_less: less
  1002.     for f in $(INSTALL_LESS); do  rm -f $$f; cp less $$f;  done
  1003.     touch install_less
  1004.  
  1005. $(OBJ): less.h funcs.h
  1006.  
  1007. lint:
  1008.     lint -hp $(DEFS) $(SRC)
  1009.  
  1010. newfuncs:
  1011.     mv funcs.h funcs.h.OLD
  1012.     awk -f mkfuncs.awk $(SRC) >funcs.h
  1013.  
  1014. clean:
  1015.     rm -f $(OBJ) less
  1016.  
  1017. clobber:
  1018.     rm -f *.o less install_less install_man
  1019.  
  1020. shar:
  1021.     shar -v INSTALLATION less.l makefile.* *.h *.awk $(SRC1) > less.shar.a
  1022.     shar -v $(SRC2) > less.shar.b
  1023. SHAR_EOF
  1024. echo shar: extracting funcs.h
  1025. cat - << \SHAR_EOF > funcs.h
  1026.     public void edit ();
  1027.     public void next_file ();
  1028.     public void prev_file ();
  1029.     public void quit ();
  1030.     public void init_option ();
  1031.     public void toggle_option ();
  1032.     public void scan_option ();
  1033.     public void forward ();
  1034.     public void backward ();
  1035.     public void repaint ();
  1036.     public void jump_forw ();
  1037.     public void jump_back ();
  1038.     public void jump_percent ();
  1039.     public void jump_loc ();
  1040.     public void init_mark ();
  1041.     public void setmark ();
  1042.     public void gomark ();
  1043.     public void search ();
  1044.     public int ch_seek ();
  1045.     public int ch_end_seek ();
  1046.     public POSITION ch_length ();
  1047.     public POSITION ch_tell ();
  1048.     public int ch_forw_get ();
  1049.     public int ch_back_get ();
  1050.     public void ch_init ();
  1051.     public POSITION position ();
  1052.     public void add_forw_pos ();
  1053.     public void add_back_pos ();
  1054.     public void pos_clear ();
  1055.     public int onscreen ();
  1056.     public POSITION forw_line ();
  1057.     public POSITION back_line ();
  1058.     public void put_line ();
  1059.     public int control_char ();
  1060.     public int carat_char ();
  1061.     public void flush ();
  1062.     public void dropout ();
  1063.     public void putc ();
  1064.     public void puts ();
  1065.     public void error ();
  1066.     public int error_width ();
  1067.     public void raw_mode ();
  1068.     public void get_term ();
  1069.     public void init ();
  1070.     public void deinit ();
  1071.     public void home ();
  1072.     public void add_line ();
  1073.     public void lower_left ();
  1074.     public void bell ();
  1075.     public void vbell ();
  1076.     public void clear ();
  1077.     public void clear_eol ();
  1078.     public void so_enter ();
  1079.     public void so_exit ();
  1080.     public void ul_enter ();
  1081.     public void ul_exit ();
  1082.     public void backspace ();
  1083.     public void putbs ();
  1084.     public char * eq_message ();
  1085.     public char * pr_string ();
  1086.     public void prewind ();
  1087.     public int pappend ();
  1088.     public POSITION forw_raw_line ();
  1089.     public POSITION back_raw_line ();
  1090.     public void init_signals ();
  1091.     public void  psignals ();
  1092.     public void lsystem ();
  1093.     public void help ();
  1094.     public void open_getc ();
  1095.     public int getc ();
  1096.     public void commands ();
  1097. SHAR_EOF
  1098. echo shar: extracting less.h
  1099. cat - << \SHAR_EOF > less.h
  1100. /*
  1101.  * Standard include file for "less".
  1102.  */
  1103.  
  1104. /*
  1105.  * Language details.
  1106.  */
  1107. #if !VOID
  1108. #define    void  int
  1109. #endif
  1110. #define    public        /* PUBLIC FUNCTION */
  1111.  
  1112. /*
  1113.  * Special types and constants.
  1114.  */
  1115. typedef long        POSITION;
  1116. /*
  1117.  * {{ Warning: if POSITION is changed to other than "long",
  1118.  *    you may have to change some of the printfs which use "%ld"
  1119.  *    to print a variable of type POSITION. }}
  1120.  */
  1121.  
  1122. #define    END_POSITION    ((POSITION)(-2))
  1123. #define    NULL_POSITION    ((POSITION)(-1))
  1124.  
  1125. #define    EOF        (0)
  1126. #define    NULL        (0)
  1127.  
  1128. /* How quiet should we be? */
  1129. #define    NOT_QUIET    0    /* Ring bell at eof and for errors */
  1130. #define    LITTLE_QUIET    1    /* Ring bell only for errors */
  1131. #define    VERY_QUIET    2    /* Never ring bell */
  1132.  
  1133. /* How should we prompt? */
  1134. #define    PR_SHORT    0    /* Prompt with colon */
  1135. #define    PR_MEDIUM    1    /* Prompt with message */
  1136. #define    PR_LONG        2    /* Prompt with longer message */
  1137.  
  1138. /* How should we handle backspaces? */
  1139. #define    BS_UNDERLINE    0    /* Underlining converted to underline mode */
  1140. #define    BS_NORMAL    1    /* \b treated as normal char; actually output */
  1141. #define    BS_CONTROL    2    /* \b treated as control char; prints as ^H */
  1142.  
  1143. /* Flag to eq_message() telling what to put in the message */
  1144. #define    MNAME        001    /* File name */
  1145. #define    MOF        002    /* "file x of y" */
  1146. #define    MBYTE        004    /* "byte x/y" */
  1147. #define    MPCT        010    /* Percentage into the file */
  1148.  
  1149. /* Special chars used to tell put_line() to do something special */
  1150. #define    UL_CHAR        '\201'    /* Enter underline mode */
  1151. #define    UE_CHAR        '\202'    /* Exit underline mode */
  1152.  
  1153. #define    CONTROL(c)        ((c)&037)
  1154. #define    SIGNAL(sig,func)    signal(sig,func)
  1155.  
  1156. off_t lseek();
  1157.  
  1158. #include "funcs.h"
  1159. SHAR_EOF
  1160. echo shar: extracting position.h
  1161. cat - << \SHAR_EOF > position.h
  1162. /*
  1163.  * Include file for interfacing to position.c modules.
  1164.  */
  1165. #define    TOP        0
  1166. #define    TOP_PLUS_ONE    1
  1167. #define    BOTTOM        -1
  1168. #define    BOTTOM_PLUS_ONE    -2
  1169. SHAR_EOF
  1170. echo shar: extracting mkfuncs.awk
  1171. cat - << \SHAR_EOF > mkfuncs.awk
  1172. BEGIN { FS="("; state = 0 }
  1173.  
  1174. /^    public/ { ftype = $0; state = 1 }
  1175.  
  1176. { if (state == 1)
  1177.     state = 2
  1178.   else if (state == 2)
  1179.     { print ftype,$1,"();"; state = 0 }
  1180. }
  1181. SHAR_EOF
  1182. echo shar: extracting main.c
  1183. cat - << \SHAR_EOF > main.c
  1184. /*
  1185.  * Entry point, initialization, miscellaneous routines.
  1186.  */
  1187.  
  1188. #include "less.h"
  1189. #include "position.h"
  1190. #include <setjmp.h>
  1191.  
  1192. public int    ispipe;
  1193. public jmp_buf    main_loop;
  1194. public char *    first_cmd;
  1195. public char *    every_first_cmd;
  1196. public int    new_file;
  1197. public int    is_tty;
  1198. public char     current_file[128];
  1199. public int ac;
  1200. public char **av;
  1201. public int curr_ac;
  1202. #if EDITOR
  1203. public char *    editor;
  1204. #endif
  1205.  
  1206. extern int file;
  1207. extern int nbufs;
  1208. extern int sigs;
  1209. extern int quit_at_eof;
  1210. extern int p_nbufs, f_nbufs;
  1211. extern int back_scroll;
  1212. extern int top_scroll;
  1213. extern int sc_height;
  1214.  
  1215.  
  1216. /*
  1217.  * Edit a new file.
  1218.  * Filename "-" means standard input.
  1219.  * No filename means the "current" file, from the command line.
  1220.  */
  1221.     public void
  1222. edit(filename)
  1223.     char *filename;
  1224. {
  1225.     register int f;
  1226.     char message[100];
  1227.     static int any_edited = 0;
  1228.     static int hold_scroll = 0;
  1229.  
  1230.     if (filename == NULL || *filename == '\0')
  1231.     {
  1232.         if (curr_ac >= ac)
  1233.         {
  1234.             error("No current file");
  1235.             return;
  1236.         }
  1237.         filename = av[curr_ac];
  1238.     }
  1239.     if (strcmp(filename, "-") == 0)
  1240.         f = 0;    /* Standard input */
  1241.     else if ((f = open(filename, 0)) < 0)
  1242.     {
  1243.         sprintf(message, "Cannot open %.*s", 
  1244.             error_width()-13, filename);
  1245.         if (any_edited)
  1246.             error(message);
  1247.         else
  1248.         {
  1249.             puts(message);
  1250.             hold_scroll = 1;
  1251.         }
  1252.         return;
  1253.     }
  1254.  
  1255.     if (isatty(f))
  1256.     {
  1257.         /*
  1258.          * Not really necessary to call this an error,
  1259.          * but if the control terminal (for commands)
  1260.          * and the input file (for data) are the same,
  1261.          * we get weird results at best.
  1262.          */
  1263.         error("Can't take input from a terminal");
  1264.         if (f > 0)
  1265.             close(f);
  1266.         return;
  1267.     }
  1268.  
  1269.     /*
  1270.      * Close the current input file and set up to use the new one.
  1271.      */
  1272.     if (file > 0)
  1273.         close(file);
  1274.     new_file = 1;
  1275.     strcpy(current_file, filename);
  1276.     ispipe = (f == 0);
  1277.     file = f;
  1278.     ch_init( (ispipe) ? p_nbufs : f_nbufs );
  1279.     init_mark();
  1280.     if (every_first_cmd != NULL)
  1281.         first_cmd = every_first_cmd;
  1282.     if (is_tty)
  1283.     {
  1284.         any_edited = 1;
  1285.         if (hold_scroll)
  1286.         {
  1287.             /*
  1288.              * Before erasing the screen contents,
  1289.              * display the file name and ask for a keystroke.
  1290.              */
  1291.             error(filename);
  1292.             hold_scroll = 0;
  1293.         }
  1294.         if (first_cmd == NULL || *first_cmd == '\0')
  1295.         {
  1296.             /* 
  1297.              * Display the first screen. 
  1298.              */
  1299.             jump_back(1);
  1300.         } else
  1301.         {
  1302.             /* 
  1303.              * The first_cmd will hopefully redisplay the
  1304.              * screen, so we need not display anything yet.
  1305.              * Indicate there is nothing yet on the screen. 
  1306.              */
  1307.             pos_clear();
  1308.         }
  1309.     }
  1310. }
  1311.  
  1312. /*
  1313.  * Edit the next file in the command line list.
  1314.  */
  1315.     public void
  1316. next_file(n)
  1317.     int n;
  1318. {
  1319.     if (curr_ac + n >= ac)
  1320.     {
  1321.         if (quit_at_eof)
  1322.             quit();
  1323.         error("No (N-th) next file");
  1324.     } else
  1325.         edit(av[curr_ac += n]);
  1326. }
  1327.  
  1328. /*
  1329.  * Edit the previous file in the command line list.
  1330.  */
  1331.     public void
  1332. prev_file(n)
  1333.     int n;
  1334. {
  1335.     if (curr_ac - n < 0)
  1336.         error("No (N-th) previous file");
  1337.     else
  1338.         edit(av[curr_ac -= n]);
  1339. }
  1340.  
  1341. /*
  1342.  * Copy a file directly to standard output.
  1343.  * Used if standard output is not a tty.
  1344.  */
  1345.     static void
  1346. cat_file()
  1347. {
  1348.     register int c;
  1349.  
  1350.     while ((c = ch_forw_get()) != EOF)
  1351.         putc(c);
  1352.     flush();
  1353. }
  1354.  
  1355. /*
  1356.  * Entry point.
  1357.  */
  1358. main(argc, argv)
  1359.     int argc;
  1360.     char *argv[];
  1361. {
  1362.     char *getenv();
  1363.  
  1364.  
  1365.     /*
  1366.      * Process command line arguments and LESS environment arguments.
  1367.      * Command line arguments override environment arguments.
  1368.      */
  1369.     init_option();
  1370.     scan_option(getenv("LESS"));
  1371.     argv++;
  1372.     while ( (--argc > 0) && 
  1373.         (argv[0][0] == '-' || argv[0][0] == '+') && 
  1374.         argv[0][1] != '\0')
  1375.         scan_option(*argv++);
  1376.  
  1377. #if EDITOR
  1378.     editor = getenv("EDITOR");
  1379.     if (editor == NULL || *editor == '\0')
  1380.         editor = EDIT_PGM;
  1381. #endif
  1382.  
  1383.     /*
  1384.      * Set up list of files to be examined.
  1385.      */
  1386.     ac = argc;
  1387.     av = argv;
  1388.     curr_ac = 0;
  1389.  
  1390.     /*
  1391.      * Set up terminal, etc.
  1392.      */
  1393.     is_tty = isatty(1);
  1394.     if (!is_tty)
  1395.     {
  1396.         /*
  1397.          * Output is not a tty.
  1398.          * Just copy the input file(s) to output.
  1399.          */
  1400.         if (ac < 1)
  1401.         {
  1402.             edit("-");
  1403.             cat_file();
  1404.         } else
  1405.         {
  1406.             do
  1407.             {
  1408.                 edit((char *)NULL);
  1409.                 if (file >= 0)
  1410.                     cat_file();
  1411.             } while (++curr_ac < ac);
  1412.         }
  1413.         exit(0);
  1414.     }
  1415.  
  1416.     raw_mode(1);
  1417.     get_term();
  1418.     open_getc();
  1419.     init();
  1420.  
  1421.     if (back_scroll < 0)
  1422.     {
  1423.         /* {{ KLUDGE }} */
  1424.         back_scroll = sc_height-1;
  1425.         if (top_scroll)
  1426.             back_scroll--;
  1427.     }
  1428.  
  1429.     if (setjmp(main_loop))
  1430.         quit();
  1431.     init_signals();
  1432.  
  1433.     /*
  1434.      * Select the first file to examine.
  1435.      */
  1436.     if (ac < 1)
  1437.         edit("-");    /* Standard input */
  1438.     else 
  1439.     {
  1440.         /*
  1441.          * Try all the files named as command arguments.
  1442.          * We are simply looking for one which can be
  1443.          * opened without error.
  1444.          */
  1445.         do
  1446.         {
  1447.             edit((char *)NULL);
  1448.             if (file >= 0)
  1449.                 /* We can open this file. */
  1450.                 break;
  1451.             putc('\n');  flush();
  1452.         } while (++curr_ac < ac);
  1453.     }
  1454.  
  1455.     if (file >= 0)
  1456.         commands();
  1457.     quit();
  1458. }
  1459.  
  1460. /*
  1461.  * Exit the program.
  1462.  */
  1463.     public void
  1464. quit()
  1465. {
  1466.     /*
  1467.      * Put cursor at bottom left corner, clear the line,
  1468.      * reset the terminal modes, and exit.
  1469.      */
  1470.     lower_left();
  1471.     clear_eol();
  1472.     deinit();
  1473.     flush();
  1474.     raw_mode(0);
  1475.     exit(0);
  1476. }
  1477. SHAR_EOF
  1478. echo shar: extracting option.c
  1479. cat - << \SHAR_EOF > option.c
  1480. /*
  1481.  * Process command line options.
  1482.  * Each option is a single letter which controls a program variable.
  1483.  * The options have defaults which may be changed via
  1484.  * the command line option, or toggled via the "-" command.
  1485.  */
  1486.  
  1487. #include "less.h"
  1488.  
  1489. #define    toupper(c)    ((c)-'a'+'A')
  1490.  
  1491. /*
  1492.  * Types of options.
  1493.  */
  1494. #define    BOOL        01    /* Boolean option: 0 or 1 */
  1495. #define    TRIPLE        02    /* Triple-valued option: 0, 1 or 2 */
  1496. #define    NUMBER        04    /* Numeric option */
  1497. #define    NO_TOGGLE    0100    /* Option cannot be toggled with "-" cmd */
  1498.  
  1499. /*
  1500.  * Variables controlled by command line options.
  1501.  */
  1502. public int p_nbufs, f_nbufs;    /* Number of buffers.  There are two values,
  1503.                    one used for input from a pipe and 
  1504.                    the other for input from a file. */
  1505. public int clean_data;        /* Can we assume the data is "clean"? 
  1506.                    (That is, free of nulls, etc) */
  1507. public int quiet;        /* Should we suppress the audible bell? */
  1508. public int top_search;        /* Should forward searches start at the top 
  1509.                    of the screen? (alternative is bottom) */
  1510. public int top_scroll;        /* Repaint screen from top?
  1511.                    (alternative is scroll from bottom) */
  1512. public int pr_type;        /* Type of prompt (short, medium, long) */
  1513. public int bs_mode;        /* How to process backspaces */
  1514. public int know_dumb;        /* Don't complain about dumb terminals */
  1515. public int quit_at_eof;        /* Quit after hitting end of file twice */
  1516. public int squeeze;        /* Squeeze multiple blank lines into one */
  1517. public int tabstop;        /* Tab settings */
  1518. public int back_scroll;        /* Repaint screen on backwards movement */
  1519. public int twiddle;        /* Display "~" for lines after EOF */
  1520.  
  1521. extern int nbufs;
  1522. extern char *first_cmd;
  1523. extern char *every_first_cmd;
  1524.  
  1525. #define    DEF_F_NBUFS    5    /* Default for f_nbufs */
  1526. #define    DEF_P_NBUFS    12    /* Default for p_nbufs */
  1527.  
  1528. static struct option
  1529. {
  1530.     char oletter;        /* The controlling letter (a-z) */
  1531.     char otype;        /* Type of the option */
  1532.     int odefault;        /* Default value */
  1533.     int *ovar;        /* Pointer to the associated variable */
  1534.     char *odesc[3];        /* Description of each value */
  1535. } option[] =
  1536. {
  1537.     { 'c', BOOL, 0, &clean_data,
  1538.         { "Don't assume data is clean",
  1539.           "Assume data is clean",
  1540.           NULL
  1541.         }
  1542.     },
  1543.     { 'd', BOOL|NO_TOGGLE, 0, &know_dumb,
  1544.         { NULL, NULL, NULL}
  1545.     },
  1546.     { 'e', BOOL, 0, &quit_at_eof,
  1547.         { "Don't quit at end-of-file",
  1548.           "Quit at end-of-file",
  1549.           NULL
  1550.         }
  1551.     },
  1552.     { 'h', NUMBER, -1, &back_scroll,
  1553.         { "Backwards scroll limit is %d lines",
  1554.           NULL, NULL
  1555.         }
  1556.     },
  1557.     { 'p', BOOL, 0, &top_scroll,
  1558.         { "Repaint by scrolling from bottom of screen",
  1559.           "Repaint by painting from top of screen",
  1560.           NULL
  1561.         }
  1562.     },
  1563.     { 'x', NUMBER, 8, &tabstop,
  1564.         { "Tab stops every %d spaces", 
  1565.           NULL, NULL 
  1566.         }
  1567.     },
  1568.     { 's', BOOL, 0, &squeeze,
  1569.         { "Don't squeeze multiple blank lines",
  1570.           "Squeeze multiple blank lines",
  1571.           NULL
  1572.         }
  1573.     },
  1574.     { 't', BOOL, 1, &top_search,
  1575.         { "Forward search starts from bottom of screen",
  1576.           "Forward search starts from top of screen",
  1577.           NULL
  1578.         }
  1579.     },
  1580.     { 'w', BOOL, 1, &twiddle,
  1581.         { "Display nothing for lines after end-of-file",
  1582.           "Display ~ for lines after end-of-file",
  1583.           NULL
  1584.         }
  1585.     },
  1586.     { 'm', TRIPLE, 0, &pr_type,
  1587.         { "Prompt with a colon",
  1588.           "Prompt with a message",
  1589.           "Prompt with a verbose message"
  1590.         }
  1591.     },
  1592.     { 'q', TRIPLE, 0, &quiet,
  1593.         { "Ring the bell for errors AND at eof/bof",
  1594.           "Ring the bell for errors but not at eof/bof",
  1595.           "Never ring the bell"
  1596.         }
  1597.     },
  1598.     { 'u', TRIPLE, 0, &bs_mode,
  1599.         { "Underlined text displayed in underline mode",
  1600.           "All backspaces cause overstrike",
  1601.           "Backspaces print as ^H"
  1602.         }
  1603.     },
  1604.     { '\0' }
  1605. };
  1606.  
  1607. public char all_options[64];    /* List of all valid options */
  1608.  
  1609. /*
  1610.  * Initialize each option to its default value.
  1611.  */
  1612.     public void
  1613. init_option()
  1614. {
  1615.     register struct option *o;
  1616.     register char *p;
  1617.  
  1618.     /*
  1619.      * First do special cases, not in option table.
  1620.      */
  1621.     first_cmd = every_first_cmd = NULL;
  1622.     f_nbufs = DEF_F_NBUFS;        /* -bf */
  1623.     p_nbufs = DEF_P_NBUFS;        /* -bp */
  1624.  
  1625.     p = all_options;
  1626.     *p++ = 'b';
  1627.  
  1628.     for (o = option;  o->oletter != '\0';  o++)
  1629.     {
  1630.         /*
  1631.          * Set each variable to its default.
  1632.          * Also make a list of all options, in "all_options".
  1633.          */
  1634.         *(o->ovar) = o->odefault;
  1635.         *p++ = o->oletter;
  1636.         if (o->otype & TRIPLE)
  1637.             *p++ = toupper(o->oletter);
  1638.     }
  1639.     *p = '\0';
  1640. }
  1641.  
  1642. /*
  1643.  * Toggle command line flags from within the program.
  1644.  * Used by the "-" command.
  1645.  */
  1646.     public void
  1647. toggle_option(c)
  1648.     int c;
  1649. {
  1650.     register struct option *o;
  1651.     char message[100];
  1652.     char buf[5];
  1653.  
  1654.     /*
  1655.      * First check for special cases not handled by the option table.
  1656.      */
  1657.     switch (c)
  1658.     {
  1659.     case 'b':
  1660.         sprintf(message, "%d buffers", nbufs);
  1661.         error(message);
  1662.         return;
  1663.     }
  1664.  
  1665.  
  1666.     for (o = option;  o->oletter != '\0';  o++)
  1667.     {
  1668.         if ((o->otype & BOOL) && (o->oletter == c) &&
  1669.             (o->otype & NO_TOGGLE) == 0)
  1670.         {
  1671.             /*
  1672.              * Boolean option: 
  1673.              * just toggle it.
  1674.              */
  1675.             *(o->ovar) = ! *(o->ovar);
  1676.             error(o->odesc[*(o->ovar)]);
  1677.             return;
  1678.         } else if ((o->otype & TRIPLE) && (o->oletter == c) &&
  1679.             (o->otype & NO_TOGGLE) == 0)
  1680.         {
  1681.             /*
  1682.              * Triple-valued option with lower case letter:
  1683.              * make it 1 unless already 1, then make it 0.
  1684.              */
  1685.             *(o->ovar) = (*(o->ovar) == 1) ? 0 : 1;
  1686.             error(o->odesc[*(o->ovar)]);
  1687.             return;
  1688.         } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c) &&
  1689.             (o->otype & NO_TOGGLE) == 0)
  1690.         {
  1691.             /*
  1692.              * Triple-valued option with upper case letter:
  1693.              * make it 2 unless already 2, then make it 0.
  1694.              */
  1695.             *(o->ovar) = (*(o->ovar) == 2) ? 0 : 2;
  1696.             error(o->odesc[*(o->ovar)]);
  1697.             return;
  1698.         } else if ((o->otype & NUMBER) && (o->oletter == c) &&
  1699.             (o->otype & NO_TOGGLE) == 0)
  1700.         {
  1701.             sprintf(message, o->odesc[0], *(o->ovar));
  1702.             error(message);
  1703.             return;
  1704.         }
  1705.     }
  1706.  
  1707.     if (control_char(c))
  1708.         sprintf(buf, "^%c", carat_char(c));
  1709.     else
  1710.         sprintf(buf, "%c", c);
  1711.     sprintf(message, "\"-%s\": no such flag.  Use one of \"%s\"", 
  1712.         buf, all_options);
  1713.     error(message);
  1714. }
  1715.  
  1716. /*
  1717.  * Scan an argument (either from command line or from LESS environment 
  1718.  * variable) and process it.
  1719.  */
  1720.     public void
  1721. scan_option(s)
  1722.     char *s;
  1723. {
  1724.     register struct option *o;
  1725.     register int c;
  1726.  
  1727.     if (s == NULL)
  1728.         return;
  1729.  
  1730.     next:
  1731.     if (*s == '\0')
  1732.         return;
  1733.     switch (c = *s++)
  1734.     {
  1735.     case '-':
  1736.     case ' ':
  1737.     case '\t':
  1738.         goto next;
  1739.     case '+':
  1740.         if (*s == '+')
  1741.             every_first_cmd = ++s;
  1742.         first_cmd = s;
  1743.         return;
  1744.     case 'b':
  1745.         switch (*s)
  1746.         {
  1747.         case 'f':
  1748.             s++;
  1749.             f_nbufs = getnum(&s, 'b');
  1750.             break;
  1751.         case 'p':
  1752.             s++;
  1753.             p_nbufs = getnum(&s, 'b');
  1754.             break;
  1755.         default:
  1756.             f_nbufs = p_nbufs = getnum(&s, 'b');
  1757.             break;
  1758.         }
  1759.         goto next;
  1760.     }
  1761.  
  1762.     for (o = option;  o->oletter != '\0';  o++)
  1763.     {
  1764.         if ((o->otype & BOOL) && (o->oletter == c))
  1765.         {
  1766.             *(o->ovar) = ! o->odefault;
  1767.             goto next;
  1768.         } else if ((o->otype & TRIPLE) && (o->oletter == c))
  1769.         {
  1770.             *(o->ovar) = (o->odefault == 1) ? 0 : 1;
  1771.             goto next;
  1772.         } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c))
  1773.         {
  1774.             *(o->ovar) = (o->odefault == 2) ? 0 : 2;
  1775.             goto next;
  1776.         } else if ((o->otype & NUMBER) && (o->oletter == c))
  1777.         {
  1778.             *(o->ovar) = getnum(&s, c);
  1779.             goto next;
  1780.         }
  1781.     }
  1782.  
  1783.     printf("\"-%c\": invalid flag\n", c);
  1784.     exit(1);
  1785. }
  1786.  
  1787. /*
  1788.  * Translate a string into a number.
  1789.  * Like atoi(), but takes a pointer to a char *, and updates
  1790.  * the char * to point after the translated number.
  1791.  */
  1792.     static int
  1793. getnum(sp, c)
  1794.     char **sp;
  1795.     int c;
  1796. {
  1797.     register char *s;
  1798.     register int n;
  1799.  
  1800.     s = *sp;
  1801.     if (*s < '0' || *s > '9')
  1802.     {
  1803.         printf("number is required after -%c\n", c);
  1804.         exit(1);
  1805.     }
  1806.  
  1807.     n = 0;
  1808.     while (*s >= '0' && *s <= '9')
  1809.         n = 10 * n + *s++ - '0';
  1810.     *sp = s;
  1811.     return (n);
  1812. }
  1813. SHAR_EOF
  1814. echo shar: extracting prim.c
  1815. cat - << \SHAR_EOF > prim.c
  1816. /*
  1817.  * Primitives for displaying the file on the screen.
  1818.  */
  1819.  
  1820. #include "less.h"
  1821. #include "position.h"
  1822.  
  1823. public int hit_eof;    /* Keeps track of how many times we hit end of file */
  1824.  
  1825. extern int quiet;
  1826. extern int top_search;
  1827. extern int top_scroll;
  1828. extern int back_scroll;
  1829. extern int sc_width, sc_height;
  1830. extern int sigs;
  1831. extern char *line;
  1832. extern char *first_cmd;
  1833.  
  1834. /*
  1835.  * Sound the bell to indicate he is trying to move past end of file.
  1836.  */
  1837.     static void
  1838. eof_bell()
  1839. {
  1840.     if (quiet == NOT_QUIET)
  1841.         bell();
  1842.     else
  1843.         vbell();
  1844. }
  1845.  
  1846. /*
  1847.  * Check to see if the end of file is currently "displayed".
  1848.  */
  1849.     static void
  1850. eof_check()
  1851. {
  1852.     POSITION pos;
  1853.  
  1854.     /*
  1855.      * If the bottom line is empty, we are at EOF.
  1856.      * If the bottom line ends at the file length,
  1857.      * we must be just at EOF.
  1858.      */
  1859.     pos = position(BOTTOM_PLUS_ONE);
  1860.     if (pos == NULL_POSITION || pos == ch_length())
  1861.         hit_eof++;
  1862. }
  1863.  
  1864. /*
  1865.  * Display n lines, scrolling forward, 
  1866.  * starting at position pos in the input file.
  1867.  * "force" means display the n lines even if we hit end of file.
  1868.  * "only_last" means display only the last screenful if n > screen size.
  1869.  */
  1870.     static void
  1871. forw(n, pos, force, only_last)
  1872.     register int n;
  1873.     POSITION pos;
  1874.     int force;
  1875.     int only_last;
  1876. {
  1877.     int eof = 0;
  1878.     int nlines = 0;
  1879.     int repaint_flag;
  1880.  
  1881.     /*
  1882.      * repaint_flag tells us not to display anything till the end, 
  1883.      * then just repaint the entire screen.
  1884.      */
  1885.     repaint_flag = (only_last && n > sc_height-1);
  1886.  
  1887.     if (!repaint_flag)
  1888.     {
  1889.         if (top_scroll && n >= sc_height - 1)
  1890.         {
  1891.             /*
  1892.              * Start a new screen.
  1893.              * {{ This is not really desirable if we happen
  1894.              *    to hit eof in the middle of this screen,
  1895.              *    but we don't know if that will happen now. }}
  1896.              */
  1897.             clear();
  1898.             home();
  1899.             force = 1;
  1900.         } else
  1901.         {
  1902.             lower_left();
  1903.             clear_eol();
  1904.         }
  1905.  
  1906.         if (pos != position(BOTTOM_PLUS_ONE))
  1907.         {
  1908.             /*
  1909.              * This is not contiguous with what is
  1910.              * currently displayed.  Clear the screen image 
  1911.              * (position table) and start a new screen.
  1912.              */
  1913.             pos_clear();
  1914.             add_forw_pos(pos);
  1915.             force = 1;
  1916.             if (top_scroll)
  1917.             {
  1918.                 clear();
  1919.                 home();
  1920.             } else
  1921.             {
  1922.                 puts("...skipping...\n");
  1923.             }
  1924.         }
  1925.     }
  1926.  
  1927.     while (--n >= 0)
  1928.     {
  1929.         /*
  1930.          * Read the next line of input.
  1931.          */
  1932.         pos = forw_line(pos);
  1933.         if (pos == NULL_POSITION)
  1934.         {
  1935.             /*
  1936.              * End of file: stop here unless the top line 
  1937.              * is still empty, or "force" is true.
  1938.              */
  1939.             eof = 1;
  1940.             if (!force && position(TOP) != NULL_POSITION)
  1941.                 break;
  1942.             line = NULL;
  1943.         }
  1944.         /*
  1945.          * Add the position of the next line to the position table.
  1946.          * Display the current line on the screen.
  1947.          */
  1948.         add_forw_pos(pos);
  1949.         nlines++;
  1950.         if (!repaint_flag)
  1951.             put_line();
  1952.     }
  1953.  
  1954.     if (eof)
  1955.         hit_eof++;
  1956.     else
  1957.         eof_check();
  1958.     if (nlines == 0)
  1959.         eof_bell();
  1960.     else if (repaint_flag)
  1961.         repaint();
  1962. }
  1963.  
  1964. /*
  1965.  * Display n lines, scrolling backward.
  1966.  */
  1967.     static void
  1968. back(n, pos, force, only_last)
  1969.     register int n;
  1970.     POSITION pos;
  1971.     int force;
  1972.     int only_last;
  1973. {
  1974.     int nlines = 0;
  1975.     int repaint_flag;
  1976.  
  1977.     repaint_flag = (n > back_scroll || (only_last && n > sc_height-1));
  1978.     hit_eof = 0;
  1979.     while (--n >= 0)
  1980.     {
  1981.         /*
  1982.          * Get the previous line of input.
  1983.          */
  1984.         pos = back_line(pos);
  1985.         if (pos == NULL_POSITION)
  1986.         {
  1987.             /*
  1988.              * Beginning of file: stop here unless "force" is true.
  1989.              */
  1990.             if (!force)
  1991.                 break;
  1992.             line = NULL;
  1993.         }
  1994.         /*
  1995.          * Add the position of the previous line to the position table.
  1996.          * Display the line on the screen.
  1997.          */
  1998.         add_back_pos(pos);
  1999.         nlines++;
  2000.         if (!repaint_flag)
  2001.         {
  2002.             home();
  2003.             add_line();
  2004.             put_line();
  2005.         }
  2006.     }
  2007.  
  2008.     eof_check();
  2009.     if (nlines == 0)
  2010.         eof_bell();
  2011.     else if (repaint_flag)
  2012.         repaint();
  2013. }
  2014.  
  2015. /*
  2016.  * Display n more lines, forward.
  2017.  * Start just after the line currently displayed at the bottom of the screen.
  2018.  */
  2019.     public void
  2020. forward(n, only_last)
  2021.     int n;
  2022.     int only_last;
  2023. {
  2024.     POSITION pos;
  2025.  
  2026.     pos = position(BOTTOM_PLUS_ONE);
  2027.     if (pos == NULL_POSITION)
  2028.     {
  2029.         eof_bell();
  2030.         hit_eof++;
  2031.         return;
  2032.     }
  2033.     forw(n, pos, 0, only_last);
  2034. }
  2035.  
  2036. /*
  2037.  * Display n more lines, backward.
  2038.  * Start just before the line currently displayed at the top of the screen.
  2039.  */
  2040.     public void
  2041. backward(n, only_last)
  2042.     int n;
  2043.     int only_last;
  2044. {
  2045.     POSITION pos;
  2046.  
  2047.     pos = position(TOP);
  2048.     if (pos == NULL_POSITION)
  2049.     {
  2050.         /* 
  2051.          * This will almost never happen,
  2052.          * because the top line is almost never empty. 
  2053.          */
  2054.         eof_bell();
  2055.         return;   
  2056.     }
  2057.     back(n, pos, 0, only_last);
  2058. }
  2059.  
  2060. /*
  2061.  * Repaint the screen, starting from a specified position.
  2062.  */
  2063.     static void
  2064. prepaint(pos)    
  2065.     POSITION pos;
  2066. {
  2067.     hit_eof = 0;
  2068.     forw(sc_height-1, pos, 0, 0);
  2069. }
  2070.  
  2071. /*
  2072.  * Repaint the screen.
  2073.  */
  2074.     public void
  2075. repaint()
  2076. {
  2077.     /*
  2078.      * Start at the line currently at the top of the screen
  2079.      * and redisplay the screen.
  2080.      */
  2081.     prepaint(position(TOP));
  2082. }
  2083.  
  2084. /*
  2085.  * Jump to the end of the file.
  2086.  * It is more convenient to paint the screen backward,
  2087.  * from the end of the file toward the beginning.
  2088.  */
  2089.     public void
  2090. jump_forw()
  2091. {
  2092.     POSITION pos;
  2093.  
  2094.     if (ch_end_seek())
  2095.     {
  2096.         error("Cannot seek to end of file");
  2097.         return;
  2098.     }
  2099.     pos = ch_tell();
  2100.     clear();
  2101.     pos_clear();
  2102.     add_back_pos(pos);
  2103.     back(sc_height - 1, pos, 0, 0);
  2104. }
  2105.  
  2106. /*
  2107.  * Jump to line n in the file.
  2108.  */
  2109.     public void
  2110. jump_back(n)
  2111.     register int n;
  2112. {
  2113.     register int c;
  2114.  
  2115.     /*
  2116.      * This is done the slow way, by starting at the beginning
  2117.      * of the file and counting newlines.
  2118.      */
  2119.     if (ch_seek((POSITION)0))
  2120.     {
  2121.         /* 
  2122.          * Probably a pipe with beginning of file no longer buffered. 
  2123.          */
  2124.         error("Cannot get to beginning of file");
  2125.         return;
  2126.     }
  2127.  
  2128.     /*
  2129.      * Start counting lines.
  2130.      */
  2131.     while (--n > 0)
  2132.     {
  2133.         while ((c = ch_forw_get()) != '\n')
  2134.             if (c == EOF)
  2135.             {
  2136.                 error("File is not that long");
  2137.                 /* {{ Maybe tell him how long it is? }} */
  2138.                 return;
  2139.             }
  2140.     }
  2141.  
  2142.     /*
  2143.      * Finally found the place to start.
  2144.      * Clear and redisplay the screen from there.
  2145.      *
  2146.      * {{ We *could* figure out if the new position is 
  2147.      *    close enough to just scroll there without clearing
  2148.      *    the screen, but it's not worth it. }}
  2149.      */
  2150.     prepaint(ch_tell());
  2151. }
  2152.  
  2153. /*
  2154.  * Jump to a specified percentage into the file.
  2155.  * This is a poor compensation for not being able to
  2156.  * quickly jump to a specific line number.
  2157.  */
  2158.     public void
  2159. jump_percent(percent)
  2160.     int percent;
  2161. {
  2162.     POSITION pos, len;
  2163.  
  2164.     /*
  2165.      * Determine the position in the file
  2166.      * (the specified percentage of the file's length).
  2167.      */
  2168.     if ((len = ch_length()) == NULL_POSITION)
  2169.     {
  2170.         error("Don't know length of file");
  2171.         return;
  2172.     }
  2173.     pos = (percent * len) / 100;
  2174.     jump_loc(pos);
  2175. }
  2176.  
  2177.     public void
  2178. jump_loc(pos)
  2179.     POSITION pos;
  2180. {
  2181.     register int c;
  2182.     register int nline;
  2183.     POSITION tpos;
  2184.  
  2185.     /*
  2186.      * See if the desired line is BEFORE the currently
  2187.      * displayed screen.  If so, see if it is close enough 
  2188.      * to scroll backwards to it.
  2189.      */
  2190.     tpos = position(TOP);
  2191.     if (pos < tpos)
  2192.     {
  2193.         for (nline = 1;  nline <= back_scroll;  nline++)
  2194.         {
  2195.             tpos = back_line(tpos);
  2196.             if (tpos == NULL_POSITION || tpos <= pos)
  2197.             {
  2198.                 back(nline, position(TOP), 1, 0);
  2199.                 return;
  2200.             }
  2201.         }
  2202.     } else if ((nline = onscreen(pos)) >= 0)
  2203.     {
  2204.         /*
  2205.          * The line is currently displayed.  
  2206.          * Just scroll there.
  2207.          */
  2208.         forw(nline, position(BOTTOM_PLUS_ONE), 1, 0);
  2209.         return;
  2210.     }
  2211.  
  2212.     /*
  2213.      * Line is not on screen.
  2214.      * Back up to the beginning of the current line.
  2215.      */
  2216.     if (ch_seek(pos))
  2217.     {
  2218.         error("Cannot seek to that position");
  2219.         return;
  2220.     }
  2221.     while ((c = ch_back_get()) != '\n' && c != EOF)
  2222.         ;
  2223.     if (c == '\n')
  2224.         (void) ch_forw_get();
  2225.  
  2226.     /*
  2227.      * Clear and paint the screen.
  2228.      */
  2229.     prepaint(ch_tell());
  2230. }
  2231.  
  2232. /*
  2233.  * The table of marks.
  2234.  * A mark is simply a position in the file.
  2235.  */
  2236. static POSITION marks[26];
  2237.  
  2238. /*
  2239.  * Initialize the mark table to show no marks are set.
  2240.  */
  2241.     public void
  2242. init_mark()
  2243. {
  2244.     int i;
  2245.  
  2246.     for (i = 0;  i < 26;  i++)
  2247.         marks[i] = NULL_POSITION;
  2248. }
  2249.  
  2250. /*
  2251.  * See if a mark letter is valid (between a and z).
  2252.  */
  2253.     static int
  2254. badmark(c)
  2255.     int c;
  2256. {
  2257.     if (c < 'a' || c > 'z')
  2258.     {
  2259.         error("Choose a letter between 'a' and 'z'");
  2260.         return (1);
  2261.     }
  2262.     return (0);
  2263. }
  2264.  
  2265. /*
  2266.  * Set a mark.
  2267.  */
  2268.     public void
  2269. setmark(c)
  2270.     int c;
  2271. {
  2272.     if (badmark(c))
  2273.         return;
  2274.     marks[c-'a'] = position(TOP);
  2275. }
  2276.  
  2277. /*
  2278.  * Go to a previously set mark.
  2279.  */
  2280.     public void
  2281. gomark(c)
  2282.     int c;
  2283. {
  2284.     POSITION pos;
  2285.  
  2286.     if (badmark(c))
  2287.         return;
  2288.     if ((pos = marks[c-'a']) == NULL_POSITION)
  2289.         error("mark not set");
  2290.     else
  2291.         jump_loc(pos);
  2292. }
  2293.  
  2294. /*
  2295.  * Search for the n-th occurence of a specified pattern, 
  2296.  * either forward (direction == '/'), or backwards (direction == '?').
  2297.  */
  2298.     public void
  2299. search(direction, pattern, n)
  2300.     int direction;
  2301.     char *pattern;
  2302.     register int n;
  2303. {
  2304.     register int search_forward = (direction == '/');
  2305.     POSITION pos, linepos;
  2306.  
  2307. #if RECOMP
  2308.     char *re_comp();
  2309.     char *errmsg;
  2310.  
  2311.     /*
  2312.      * (re_comp handles a null pattern internally, 
  2313.      *  so there is no need to check for a null pattern here.)
  2314.      */
  2315.     if ((errmsg = re_comp(pattern)) != NULL)
  2316.     {
  2317.         error(errmsg);
  2318.         return;
  2319.     }
  2320. #else
  2321. #if REGCMP
  2322.     char *regcmp();
  2323.     static char *cpattern = NULL;
  2324.  
  2325.     if (pattern == NULL || *pattern == '\0')
  2326.     {
  2327.         /*
  2328.          * A null pattern means use the previous pattern.
  2329.          * The compiled previous pattern is in cpattern, so just use it.
  2330.          */
  2331.         if (cpattern == NULL)
  2332.         {
  2333.             error("No previous regular expression");
  2334.             return;
  2335.         }
  2336.     } else
  2337.     {
  2338.         /*
  2339.          * Otherwise compile the given pattern.
  2340.          */
  2341.         char *s;
  2342.         if ((s = regcmp(pattern, 0)) == NULL)
  2343.         {
  2344.             error("Invalid pattern");
  2345.             return;
  2346.         }
  2347.         if (cpattern != NULL)
  2348.             free(cpattern);
  2349.         cpattern = s;
  2350.     }
  2351. #else
  2352.     static char lpbuf[100];
  2353.     static char *last_pattern = NULL;
  2354.  
  2355.     if (pattern == NULL || *pattern == '\0')
  2356.     {
  2357.         /*
  2358.          * Null pattern means use the previous pattern.
  2359.          */
  2360.         if (last_pattern == NULL)
  2361.         {
  2362.             error("No previous regular expression");
  2363.             return;
  2364.         }
  2365.         pattern = last_pattern;
  2366.     } else
  2367.     {
  2368.         strcpy(lpbuf, pattern);
  2369.         last_pattern = lpbuf;
  2370.     }
  2371. #endif
  2372. #endif
  2373.  
  2374.     /*
  2375.      * Figure out where to start the search.
  2376.      */
  2377.  
  2378.     if (position(TOP) == NULL_POSITION)
  2379.     {
  2380.         /*
  2381.          * Nothing is currently displayed.
  2382.          * Start at the beginning of the file.
  2383.          * (This case is mainly for first_cmd searches,
  2384.          * for example, "+/xyz" on the command line.)
  2385.          */
  2386.         pos = (POSITION)0;
  2387.     } else if (!search_forward)
  2388.     {
  2389.         /*
  2390.          * Backward search: start just before the top line
  2391.          * displayed on the screen.
  2392.          */
  2393.         pos = position(TOP);
  2394.     } else if (top_search)
  2395.     {
  2396.         /*
  2397.          * Forward search and "start from top".
  2398.          * Start at the second line displayed on the screen.
  2399.          */
  2400.         pos = position(TOP_PLUS_ONE);
  2401.     } else
  2402.     {
  2403.         /*
  2404.          * Forward search but don't "start from top".
  2405.          * Start just after the bottom line displayed on the screen.
  2406.          */
  2407.         pos = position(BOTTOM_PLUS_ONE);
  2408.     }
  2409.  
  2410.     if (pos == NULL_POSITION)
  2411.     {
  2412.         /*
  2413.          * Can't find anyplace to start searching from.
  2414.          */
  2415.         error("Nothing to search");
  2416.         return;
  2417.     }
  2418.  
  2419.     for (;;)
  2420.     {
  2421.         /*
  2422.          * Get lines until we find a matching one or 
  2423.          * until we hit end-of-file (or beginning-of-file 
  2424.          * if we're going backwards).
  2425.          */
  2426.         if (sigs)
  2427.             /*
  2428.              * A signal aborts the search.
  2429.              */
  2430.             return;
  2431.  
  2432.         if (search_forward)
  2433.         {
  2434.             /*
  2435.              * Read the next line, and save the 
  2436.              * starting position of that line in linepos.
  2437.              */
  2438.             linepos = pos;
  2439.             pos = forw_raw_line(pos);
  2440.         } else
  2441.         {
  2442.             /*
  2443.              * Read the previous line and save the
  2444.              * starting position of that line in linepos.
  2445.              */
  2446.             pos = back_raw_line(pos);
  2447.             linepos = pos;
  2448.         }
  2449.  
  2450.         if (pos == NULL_POSITION)
  2451.         {
  2452.             /*
  2453.              * We hit EOF/BOF without a match.
  2454.              */
  2455.             error("Pattern not found");
  2456.             return;
  2457.         }
  2458.  
  2459.         /*
  2460.          * Test the next line to see if we have a match.
  2461.          * This is done in a variety of ways, depending
  2462.          * on what pattern matching functions are available.
  2463.          */
  2464. #if REGCMP
  2465.         if ( (regex(cpattern, line) != NULL)
  2466. #else
  2467. #if RECOMP
  2468.         if ( (re_exec(line) == 1)
  2469. #else
  2470.         if ( (match(pattern, line))
  2471. #endif
  2472. #endif
  2473.                 && (--n <= 0) )
  2474.             /*
  2475.              * Found the matching line.
  2476.              */
  2477.             break;
  2478.     }
  2479.     jump_loc(linepos);
  2480. }
  2481.  
  2482. #if (!REGCMP) && (!RECOMP)
  2483. /*
  2484.  * We have neither regcmp() nor re_comp().
  2485.  * We use this function to do simple pattern matching.
  2486.  * It supports no metacharacters like *, etc.
  2487.  */
  2488.     static int
  2489. match(pattern, buf)
  2490.     char *pattern, *buf;
  2491. {
  2492.     register char *pp, *lp;
  2493.  
  2494.     for ( ;  *buf != '\0';  buf++)
  2495.     {
  2496.         for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
  2497.             if (*pp == '\0' || *lp == '\0')
  2498.                 break;
  2499.         if (*pp == '\0')
  2500.             return (1);
  2501.     }
  2502.     return (0);
  2503. }
  2504. #endif
  2505. SHAR_EOF
  2506.  
  2507.  
  2508.