aboutsummaryrefslogtreecommitdiff
path: root/sys/etc/pagefiles.x
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /sys/etc/pagefiles.x
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'sys/etc/pagefiles.x')
-rw-r--r--sys/etc/pagefiles.x1140
1 files changed, 1140 insertions, 0 deletions
diff --git a/sys/etc/pagefiles.x b/sys/etc/pagefiles.x
new file mode 100644
index 00000000..22ef4840
--- /dev/null
+++ b/sys/etc/pagefiles.x
@@ -0,0 +1,1140 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ttyset.h>
+include <error.h>
+include <ctype.h>
+include <chars.h>
+include <mach.h>
+include <finfo.h>
+include <fset.h>
+
+# PAGEFILES.X -- Page through a file or set of files. Both backwards and
+# forwards traversals of files and file lists are supported, but not
+# (currently) backwards paging of a pipe.
+#
+# This program is a hack as it was coded starting from the original PAGE
+# program, which was much simpler. TODO: Add upscrolling and the ability
+# to buffer input and scoll backwards on a pipe. The present program is
+# monolithic and should be restructured if these features are added.
+
+define CC_PREFIX '^'
+define MAKE_PRINTABLE ($1+'A'-1)
+define SZ_QUERYMSG 80
+define SZ_KEYSTR 80
+define LNO_MAXLINES 2048
+define SZ_LONGLINE 4096
+define MAX_PAGE 100
+define MAX_PBCMD 100
+define UKEYS "ukey" # CL parameter for keyboard input
+
+# Command keystrokes.
+
+define HELPTXT "[q=quit,e=edit,d=dn,u=up,f|sp=fpg,b=bpg,j|cr=dnln,k=upln,.=bof,N=nfile,P=pfile]"
+
+define HELP '?' # print helptxt
+define QUIT 'q' # return to CL
+define EDIT 'e' # edit current file
+define FWD_SCREEN 'f' # forward one full screen
+define BACK_SCREEN 'b' # back one full screen
+define SCROLL_DOWN 'd' # forward half a screen
+define SCROLL_UP 'u' # back half a screen
+define PREV_LINE 'k' # back one line
+define NEXT_LINE 'j' # forward one line
+define TO_BOF '.' # to beginning of file
+define TO_EOF 'G' # to end of file
+define TO_EOF_ALT 'g' # to end of file
+define SEARCH 'n' # search for next occurrence of pattern
+define REDRAW '\014' # redraw screen
+
+define NEXT_FILE 'N' # goto next file in list
+define PREV_FILE 'P' # goto previous file in list
+define NEXT_FILE_ALT '\016' # <ctrl/n>
+define PREV_FILE_ALT '\020' # <ctrl/p>
+
+define LCMD ':' # colon commands
+define TO_FILE 'F' # ":file filename"
+
+
+# PAGEFILES -- Display a text file or files on the standard output (the user
+# terminal) one screen at a time, pausing after each screen has been filled.
+# The program is keystroke driven in raw mode, and currently recognizes the
+# keystrokes defined above.
+#
+# If map_cc is enabled, all unknown control characters will be converted into
+# printable sequences. The following control character sequences have a
+# special significance in IRAF textfiles: FF=formfeed, SO=set standout mode,
+# SI=clear standout mode. These sequences are mapped into whatever the output
+# device requires upon output by the TTY subroutines.
+
+procedure pagefiles (files)
+
+char files[ARB] # file template
+
+string device "terminal"
+string prompt ""
+int first_page
+int clear_screen
+int map_cc
+
+begin
+ first_page = 1
+ clear_screen = YES
+ map_cc = YES
+
+ call xpagefiles (files, device,
+ prompt, first_page, clear_screen, map_cc)
+end
+
+
+# PAGEFILE -- Page a single file; an alternate entry point to the more general
+# routine. A prompt string different than the filename may be specified and
+# the screen is not cleared when scrolling downward.
+
+procedure pagefile (fname, prompt)
+
+char fname[ARB] # name of file to be paged
+char prompt[ARB] # prompt string, if different than fname
+
+string device "terminal"
+int first_page
+int clear_screen
+int map_cc
+
+begin
+ first_page = 1
+ clear_screen = NO
+ map_cc = YES
+
+ call xpagefiles (fname, device,
+ prompt, first_page, clear_screen, map_cc)
+end
+
+
+# XPAGEFILES -- Generalized file pager.
+
+procedure xpagefiles (files, device, prompt, first_page, clear_screen, map_cc)
+
+char files[ARB] # file template
+char device[ARB] # output device name
+char prompt[ARB] # prompt string (filename if null)
+int first_page # first page to be displayed
+int clear_screen # clear screen between pages
+int map_cc # map control chars on output
+
+bool redirin, useroot
+pointer sp, fname, newfname, tty, lbuf
+int spoolfd, list, nfiles, cmd, i, j, n, o
+
+pointer ttyodes()
+bool ttygetb()
+int strncmp(), strlen()
+int fntopnb(), fntrfnb(), fntlenb(), fnldir()
+int pg_getcmd(), pg_pagefile(), fstati()
+errchk fntopnb, ttyodes, ttygetb, fntrfnb, pg_pagefile, pg_getcmd
+define err_ 91
+
+begin
+ call smark (sp)
+ call salloc (newfname, SZ_FNAME, TY_CHAR)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+
+ list = fntopnb (files, YES)
+ nfiles = fntlenb (list)
+ spoolfd = NULL
+
+ tty = ttyodes (device)
+ redirin = (fstati (STDIN, F_REDIR) == YES)
+
+ # If terminal cannot scroll, set clear_screen to true regardless of the
+ # value given above.
+
+ if (ttygetb (tty, "ns"))
+ clear_screen = YES
+
+ cmd = NEXT_FILE
+ for (i=1; i <= nfiles && cmd != QUIT; i=i+1) {
+ # Get next filename.
+ if (fntrfnb (list, i, Memc[fname], SZ_FNAME) == EOF)
+ break
+
+ # Page the file.
+ cmd = pg_pagefile (tty, Memc[fname], Memc[newfname], prompt,
+ clear_screen, first_page, map_cc, i, nfiles, redirin, spoolfd)
+
+ # Decide what to do next.
+ while (cmd != QUIT) {
+ switch (cmd) {
+ case NEXT_FILE, BLANK, NEXT_LINE, CR, LF:
+ if (i >= nfiles)
+ cmd = pg_getcmd (tty, "no more files", 0,0,0,i,nfiles)
+ else
+ break
+ case PREV_FILE:
+ if (i <= 1)
+ cmd = pg_getcmd (tty, "at first file", 0,0,0,i,nfiles)
+ else {
+ i = i - 2
+ break
+ }
+
+ case TO_FILE:
+ # Position within the file list. If the user specified a
+ # logical directory in the filename, perform the compares
+ # on the raw filenames in the list, otherwise use only the
+ # root filename.
+
+ useroot = (fnldir(Memc[newfname],Memc[fname],SZ_FNAME) <= 0)
+ n = strlen (Memc[newfname])
+
+ for (j=1; j <= nfiles; j=j+1)
+ if (fntrfnb (list, j, Memc[lbuf], SZ_FNAME) > 0) {
+ if (useroot)
+ o = fnldir (Memc[lbuf], Memc[fname], SZ_FNAME)
+ else
+ o = 0
+ if (strncmp (Memc[lbuf+o], Memc[newfname], n) >= 0)
+ break
+ }
+
+ if (j > nfiles)
+ i = nfiles - 1
+ else
+ i = j - 1
+ break
+
+ case LCMD:
+ # Colon escape. Only :file is recognized at this level.
+
+ call pg_getstr (Memc[newfname], SZ_FNAME)
+ cmd = TO_FILE
+
+ case HELP:
+ cmd = pg_getcmd (tty, HELPTXT, 0,0,0,0,0)
+
+ default:
+err_ if (!redirin) {
+ call eprintf ("\07")
+ call flush (STDERR)
+ i = i - 1 # redisplay current file
+ }
+ break
+ }
+ }
+ }
+
+ if (spoolfd != NULL)
+ call close (spoolfd)
+
+ call fntclsb (list)
+ call sfree (sp)
+end
+
+
+# PG_PAGEFILE -- Display the named file on the standard output, page by
+# page, pausing for user response between pages.
+
+int procedure pg_pagefile (tty, fname, newfname, u_prompt, clear_screen,
+ first_page, map_cc, fileno, nfiles, redirin, spoolfd)
+
+pointer tty
+char fname[ARB] # file to be paged
+char newfname[ARB] # next file to be page (ret. by :file)
+char u_prompt[ARB] # prompt string, if not same as filename
+int clear_screen # clear screen between pages?
+int first_page # first page of file to be displayed
+int map_cc # map control characters?
+int fileno # current file number
+int nfiles # number of files to be paged
+bool redirin # reading from the standard input
+int spoolfd # fd if spooling output in a file
+
+char patbuf[SZ_LINE]
+int nlines, ncols, maxlines, maxcols
+long fi[LEN_FINFO], nchars, totchars, loffset
+pointer sp, lbuf, prompt, token, cmdbuf, ip, op, lp
+long pgoff[MAX_PAGE], pgnch[MAX_PAGE], pglno[MAX_PAGE]
+int fd, lineno, linelen, nleft, destline, toklen, lnout, i
+bool ateof, first_call, redirout, pushback, upline, upline_ok
+int o_loffset, o_nchars, o_lineno, o_pageno, junk, pageno, cmd, ch, n
+
+long note()
+pointer lno_open()
+bool streq(), ttygetb()
+int pg_getcmd(), ctoi(), strncmp(), patmake(), patmatch(), pg_peekcmd()
+int open(), finfo(), strlen(), pg_getline(), getci()
+int lno_fetch(), fstati(), ttyctrl()
+data first_call /true/
+
+define err_ 91
+define quit_ 92
+define search_ 93
+define destline_ 94
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LONGLINE, TY_CHAR)
+ call salloc (cmdbuf, SZ_LINE, TY_CHAR)
+ call salloc (prompt, SZ_FNAME, TY_CHAR)
+ call salloc (token, SZ_FNAME, TY_CHAR)
+
+ if (first_call) {
+ # The pattern buffer is retained indefinitely.
+ patbuf[1] = EOS
+ spoolfd = NULL
+ first_call = false
+ }
+
+ call pg_setprompt (Memc[prompt], u_prompt, fname)
+ call xttysize (ncols, nlines)
+ maxlines = nlines - 1
+ maxcols = ncols
+
+ redirout = (fstati (STDOUT, F_REDIR) == YES)
+ upline_ok = (!redirout && ttygetb(tty,"cm") && ttygetb(tty,"al"))
+ call pg_pushcmd (NULL)
+
+ # Get file size for (xx%) info in nomore. If reading from the
+ # standard input, file size is not known.
+
+ nchars = 0
+ if (streq (fname, "STDIN")) {
+ totchars = -1
+ } else if (finfo (fname, fi) == ERR) {
+ call sprintf (Memc[lbuf], SZ_LINE, "Cannot access file `%s'")
+ call pargstr (fname)
+ cmd = pg_getcmd (tty, Memc[lbuf], 0, 0, 0, fileno, nfiles)
+ call sfree (sp)
+ return (cmd)
+ } else
+ totchars = FI_SIZE(fi)
+
+ # If file is empty, return immediately without clearing screen.
+ if (totchars == 0) {
+ call sprintf (Memc[lbuf], SZ_LINE, "Null length file `%s'")
+ call pargstr (fname)
+ cmd = pg_getcmd (tty, Memc[lbuf], 0, 0, 0, fileno, nfiles)
+ call sfree (sp)
+ return (cmd)
+ }
+
+ # Open the file.
+ iferr (fd = open (fname, READ_ONLY, TEXT_FILE)) {
+ call sprintf (Memc[lbuf], SZ_LINE, "Cannot open file `%s'")
+ call pargstr (fname)
+ cmd = pg_getcmd (tty, Memc[lbuf], 0, 0, 0, fileno, nfiles)
+ call sfree (sp)
+ return (cmd)
+ }
+
+ # Open the line offset save/fetch database.
+ lp = lno_open (LNO_MAXLINES)
+
+ # Advance to the first page of the file to be displayed. Pages are
+ # marked by FF chararacters in the text. If the first page is number
+ # one, do nothing. If the first character in the file is FF, do not
+ # count it. This is necessary to count pages correctly whether or not
+ # the first page is preceeded by a FF.
+
+ pageno = 1
+ lineno = 1
+ pgoff[1] = BOF
+ pgnch[1] = nchars
+ pglno[1] = lineno
+
+ if (first_page > 1) {
+ junk = getci (fd, ch)
+ nchars = nchars + 1
+
+ while (pageno < first_page) {
+ while (getci (fd, ch) != '\f') {
+ nchars = nchars + 1
+ if (ch == '\n')
+ lineno = lineno + 1
+ if (ch == EOF) {
+ call close (fd)
+ call lno_close (lp)
+ call sfree (sp)
+ return
+ }
+ }
+ pageno = pageno + 1
+ nchars = nchars + 1
+ pgoff[pageno] = note (fd)
+ pgnch[pageno] = nchars
+ pglno[pageno] = lineno
+ }
+ }
+
+ # Always clear the screen between files; the "clear_screen" param
+ # applies only to the pages of a single file.
+
+ if (!redirout) {
+ call ttyclear (STDERR, tty)
+ call flush (STDERR)
+ }
+
+ # Output lines, mapping control characters if enabled. Pause at the
+ # end of every screen, or when FF is encountered in the text.
+
+ pushback= false
+ ateof = false
+ nleft = maxlines # nlines left to display before prompt
+ lnout = 0
+
+ repeat {
+ # Fetch and display the next line of the file.
+
+ if (pushback)
+ pushback = false
+ else
+ loffset = note (fd)
+
+ if (pg_getline (fd, Memc[lbuf]) == EOF) {
+ if ((nfiles==1 && lineno <= maxlines) || redirin || redirout) {
+ # Simply quit if a single small file or the standard input
+ # is being paged.
+
+ call close (fd)
+ call lno_close (lp)
+ call sfree (sp)
+ return (QUIT)
+
+ } else {
+ nchars = totchars + SZ_LINE
+ ateof = true
+ nleft = 0
+ }
+
+ } else if (Memc[lbuf] == '\f') {
+ # Formfeed encountered; pause for the prompt and print the
+ # remainder of the line on the next screen. If we have not
+ # yet written anything on the screen (nleft=maxlines) don't
+ # bother to prompt again.
+
+ pageno = pageno + 1
+ pgoff[pageno] = loffset
+ pglno[pageno] = lineno
+ pgnch[pageno] = nchars
+ call ungetline (fd, Memc[lbuf+1])
+ pushback = true
+
+ if (nleft == maxlines)
+ next
+ else
+ nleft = 0
+
+ } else {
+ # Output line, processing all escapes as req'd by the device.
+ # Keep track of position in file for %done message in prompt,
+ # and of position on screen so that we know when to prompt.
+
+ call lno_save (lp, lineno, loffset, nchars)
+ linelen = strlen (Memc[lbuf])
+ nchars = nchars + linelen
+ lineno = lineno + 1
+
+ # Count the number of printed columns in the output text.
+ n = 1
+ do i = 1, linelen
+ if (ch >= ' ')
+ n = n + 1
+ else if (ch == '\t') {
+ n = n + 1
+ while (mod (n-1, 8) != 0)
+ n = n + 1
+ }
+
+ # Decrement lines left on screen.
+ nleft = nleft - max (1, ((n + maxcols-1) / maxcols))
+
+ if (spoolfd != NULL)
+ call putline (spoolfd, Memc[lbuf])
+
+ # Cancel upline if line is too long.
+ if (upline && lnout <= 0 && linelen >= maxcols) {
+ call ttyclear (STDERR, tty)
+ call flush (STDERR)
+ upline = false
+ lnout = 0
+ }
+
+ if (!(upline && lnout > 0))
+ call ttyputline (STDOUT, tty, Memc[lbuf], map_cc)
+ lnout = min (maxlines, lnout + 1)
+ }
+
+ if (nleft <= 0) {
+ # Move cursor to query line at end of line insert sequence.
+ if (upline) {
+ # Don't bother if the next command is another insert.
+ if (pg_peekcmd() != PREV_LINE) {
+ call ttygoto (STDOUT, tty, 1, lnout + 1)
+ call ttyclearln (STDOUT, tty)
+ }
+ upline = false
+ }
+
+ # Pause and get next keystroke from the user.
+ cmd = pg_getcmd (tty, Memc[prompt], nchars, totchars, lineno,
+ fileno, nfiles)
+
+ # Allow use of the space bar to advance to the next file,
+ # when at the end of the current file.
+
+ if (ateof && nfiles > 1 && (cmd == BLANK || cmd == FWD_SCREEN))
+ cmd = NEXT_FILE
+
+ repeat {
+ switch (cmd) {
+ case NEXT_FILE:
+ # This really means the next file if multiple files.
+ if (nfiles > 1)
+ goto quit_
+ else if (pushback) {
+ cmd = FWD_SCREEN
+ next
+ }
+
+ # Otherwise we want the next page (formfeed).
+ o_loffset = note (fd)
+ o_nchars = nchars
+ o_lineno = lineno
+
+ repeat {
+ loffset = note (fd)
+ n = pg_getline (fd, Memc[lbuf])
+ if (n == EOF) {
+ if (!redirin) {
+ call seek (fd, o_loffset)
+ pushback = false
+ nchars = o_nchars
+ lineno = o_lineno
+ ateof = false
+ }
+ cmd = pg_getcmd (tty, "No more pages",
+ nchars,totchars, lineno, fileno,nfiles)
+ Memc[lbuf] = EOS
+ break
+ }
+
+ call lno_save (lp, lineno, loffset, nchars)
+
+ if (Memc[lbuf] == '\f') {
+ pageno = min (MAX_PAGE, pageno + 1)
+ pgoff[pageno] = loffset
+ pgnch[pageno] = nchars
+ pglno[pageno] = lineno
+ if (!redirout) {
+ call ttyclear (STDERR, tty)
+ call flush (STDERR)
+ lnout = 0
+ }
+ call ungetline (fd, Memc[lbuf+1])
+ pushback = true
+ nleft = maxlines
+ break
+ }
+
+ nchars = nchars + n
+ lineno = lineno + 1
+ }
+
+ if (n == EOF)
+ next
+ else
+ break
+
+ case PREV_FILE:
+ # If there are multiple files go to previous file,
+ # otherwise, go to previous page (formfeed).
+
+ if (nfiles > 1)
+ goto quit_
+ if (redirin)
+ goto err_
+
+ # Special case - just reached beginning of next
+ # page, but still displaying previous page.
+
+ if (pglno[pageno] == lineno)
+ pageno = max (1, pageno - 1)
+
+ # If the beginning of the current page is not on
+ # the screen, go back to the beginning of the page.
+
+ if (lineno <= pglno[pageno]+maxlines)
+ pageno = max (1, pageno - 1)
+
+ # Go there.
+ call seek (fd, pgoff[pageno])
+ nchars = pgnch[pageno]
+ lineno = pglno[pageno]
+ pushback = false
+
+ if (!redirout) {
+ call ttyclear (STDERR, tty)
+ call flush (STDERR)
+ lnout = 0
+ }
+ if (getci (fd, ch) != '\f')
+ call ungetci (fd, ch)
+ nleft = maxlines
+ break
+
+ case QUIT:
+quit_ call close (fd)
+ call lno_close (lp)
+ call sfree (sp)
+ return (cmd)
+
+ case TO_BOF:
+ if (redirin)
+ goto err_
+
+ call pg_setprompt (Memc[prompt], u_prompt, fname)
+ call seek (fd, BOFL)
+ pushback = false
+ Memc[lbuf] = EOS
+ ateof = false
+ lineno = 1
+ nchars = 0
+ nleft = maxlines
+ pageno = 1
+
+ if (!redirout) {
+ call ttyclear (STDERR, tty)
+ call flush (STDERR)
+ lnout = 0
+ }
+ break
+
+ case FWD_SCREEN, BLANK:
+ if (!ateof && clear_screen == YES && !redirout) {
+ call ttyclear (STDERR, tty)
+ call flush (STDERR)
+ lnout = 0
+ }
+ nleft = maxlines
+ break
+
+ case TO_EOF, TO_EOF_ALT:
+ destline = MAX_INT
+ goto destline_
+ case SCROLL_DOWN:
+ nleft = (maxlines + 1) / 2
+ break
+ case SCROLL_UP:
+ if (redirin)
+ goto err_
+ if (upline_ok) {
+ destline = lineno - 2
+ do i = 1, ((maxlines + 1) / 2 - 1)
+ if (lineno - lnout - i > 1)
+ call pg_pushcmd (PREV_LINE)
+ } else
+ destline = lineno - ((maxlines + 1) / 2) - 1
+ goto destline_
+ case BACK_SCREEN:
+ if (redirin)
+ goto err_
+ destline = lineno - maxlines - 1
+ goto destline_
+ case PREV_LINE:
+ if (redirin)
+ goto err_
+ destline = lineno - 2
+ goto destline_
+ case REDRAW:
+ if (redirin)
+ goto err_
+ destline = lineno
+ goto destline_
+ case NEXT_LINE, CR, LF:
+ nleft = 1
+ break
+ case SEARCH:
+ # Stop at next line containing current pattern.
+ goto search_
+
+ case HELP:
+ cmd = pg_getcmd (tty, HELPTXT, 0, 0, 0, 0, 0)
+ # get another command
+
+ case EDIT:
+ # Edit the file being paged.
+ if (redirin)
+ goto err_
+
+ # Close file and LNO database.
+ call close (fd)
+ call lno_close (lp)
+ call flush (STDOUT)
+ call flush (STDERR)
+
+ # Command the CL to edit the file.
+ call sprintf (Memc[lbuf], SZ_LINE, "edit (\"%s\")")
+ call pargstr (fname)
+ iferr (call clcmdw (Memc[lbuf]))
+ call erract (EA_WARN)
+
+ # Reopen the file and LNO database.
+ iferr (fd = open (fname, READ_ONLY, TEXT_FILE)) {
+ call sfree (sp)
+ return (NEXT_FILE)
+ } else
+ lp = lno_open (LNO_MAXLINES)
+
+ # Redisplay the file at the BOF.
+ if (!redirout) {
+ call ttyclear (STDERR, tty)
+ call flush (STDERR)
+ lnout = 0
+ }
+ Memc[lbuf] = EOS
+ nchars = 0
+ lineno = 1
+ nleft = maxlines
+ break
+
+ case LCMD:
+ # Colon escape.
+ call pg_getstr (Memc[cmdbuf], SZ_LINE)
+ for (ip=cmdbuf; IS_WHITE (Memc[ip]); ip=ip+1)
+ ;
+
+ if (Memc[ip] == '!') {
+ # Send a command to the CL.
+
+ iferr (call clcmdw (Memc[cmdbuf+1]))
+ call erract (EA_WARN)
+ cmd = pg_getcmd (tty, Memc[prompt],
+ nchars, totchars, lineno, fileno, nfiles)
+ Memc[lbuf] = EOS
+ next
+
+ } else if (Memc[ip] == '/') {
+ # Search for a line containing the given pattern.
+
+ if (patmake (Memc[ip+1], patbuf, SZ_LINE) == ERR)
+ goto err_
+search_
+ if (patbuf[1] == EOS) {
+ cmd = pg_getcmd (tty, "No current pattern",
+ 0, 0, 0, fileno, nfiles)
+ Memc[lbuf] = EOS
+ next
+ }
+
+ o_loffset = note (fd)
+ o_nchars = nchars
+ o_lineno = lineno
+ o_pageno = pageno
+
+ repeat {
+ loffset = note (fd)
+ n = pg_getline (fd, Memc[lbuf])
+ if (n == EOF) {
+ if (!redirin) {
+ call seek (fd, o_loffset)
+ pushback = false
+ nchars = o_nchars
+ lineno = o_lineno
+ pageno = o_pageno
+ ateof = false
+ }
+ cmd = pg_getcmd (tty, "Pattern not found",
+ nchars,totchars,lineno,fileno,nfiles)
+ Memc[lbuf] = EOS
+ break
+ }
+
+ call lno_save (lp, lineno, loffset, nchars)
+ if (Memc[lbuf] == '\f') {
+ pageno = pageno + 1
+ pgoff[pageno] = loffset
+ pgnch[pageno] = nchars
+ pglno[pageno] = lineno
+ }
+
+ if (patmatch (Memc[lbuf], patbuf) > 0) {
+ if (redirin) {
+ call ungetline (fd, Memc[lbuf])
+ pushback = true
+ nleft = maxlines
+ break
+ } else {
+ destline = lineno
+ nchars = nchars + n
+ lineno = lineno + 1
+ goto destline_
+ }
+ }
+
+ nchars = nchars + n
+ lineno = lineno + 1
+ }
+
+ if (n == EOF)
+ next
+ else
+ break
+ }
+
+ # Case ":cmd arg".
+ for (op=token; IS_ALPHA (Memc[ip]); ip=ip+1) {
+ Memc[op] = Memc[ip]
+ op = op + 1
+ }
+ for (; IS_WHITE (Memc[ip]); ip=ip+1)
+ ;
+ Memc[op] = EOS
+ toklen = op - token
+
+ # Print help if no : string given.
+ if (toklen <= 0) {
+ call strcpy ("help", Memc[token], SZ_FNAME)
+ toklen = 4
+ }
+
+ if (strncmp (Memc[token], "line", toklen) == 0) {
+ # Move to the destination line, expressed as
+ # ":line N" for an absolute line, or ":line +/-N"
+ # for a relative move.
+
+ destline = lineno
+ if (Memc[ip] == '+') {
+ ip = ip + 1
+ if (ctoi (Memc, ip, n) > 0)
+ destline = lineno + n
+ } else if (Memc[ip] == '-') {
+ ip = ip + 1
+ if (ctoi (Memc, ip, n) > 0)
+ destline = lineno - n
+ } else if (ctoi (Memc, ip, n) > 0)
+ destline = n
+destline_
+ # Upscroll one line?
+ if (upline_ok && destline == lineno-2)
+ upline = true
+
+ # Determine line at top of new screen.
+ nleft = maxlines
+ if (destline < lineno && destline >= lineno-lnout-1)
+ destline = destline - lnout + 1
+ else
+ destline = destline - nleft + 1
+
+ # Don't upscroll off the top of the screen.
+ if (destline < 1) {
+ destline = 1
+ upline = false
+ }
+
+ # Look up the desired line offset in the database
+ # and go directly there if found, otherwise either
+ # advance forward or rewind the file and advance
+ # forward to the indicated line.
+
+ if (lno_fetch(lp,destline,loffset,nchars)==ERR) {
+ if (!redirin && destline < lineno) {
+ call seek (fd, BOFL)
+ pushback = false
+ lineno = 1
+ pageno = 1
+ nchars = 0
+ ateof = false
+ call pg_setprompt (Memc[prompt],
+ u_prompt, fname)
+ }
+
+ while (lineno < destline) {
+ loffset = note (fd)
+ n = pg_getline (fd, Memc[lbuf])
+ if (n == EOF) {
+ destline = lineno - 1 # goto EOF
+ goto destline_
+ }
+ call lno_save (lp, lineno, loffset, nchars)
+ if (Memc[lbuf] == '\f') {
+ pageno = pageno + 1
+ pgoff[pageno] = loffset
+ pgnch[pageno] = nchars
+ pglno[pageno] = lineno
+ }
+ nchars = nchars + n
+ lineno = lineno + 1
+ }
+ } else if (!redirin) {
+ call seek (fd, loffset)
+ pushback = false
+ lineno = destline
+ ateof = false
+
+ # Determine which page we are in.
+ do i = 2, MAX_PAGE
+ if (pglno[i] <= 0) {
+ pageno = i - 1
+ break
+ } else if (pglno[i] >= lineno) {
+ pageno = i
+ break
+ }
+
+ call pg_setprompt (Memc[prompt],u_prompt,fname)
+ }
+
+ # Prepare to draw the screen. Upline mode means
+ # we want to insert a line at the top of the screen
+ # and then skip to the page prompt; otherwise we
+ # clear the screen and output a full page of text.
+
+ if (!redirout) {
+ if (upline) {
+ # Clear screen if backing up over a page.
+ if (destline+1 == pglno[pageno])
+ call ttyclear (STDERR, tty)
+ call ttygoto (STDOUT, tty, 1, 1)
+ junk = ttyctrl (STDOUT, tty, "al", maxlines)
+ lnout = 0
+ } else {
+ call ttyclear (STDERR, tty)
+ upline = false
+ lnout = 0
+ }
+ call flush (STDERR)
+ }
+ Memc[lbuf] = EOS
+ break
+
+ } else if (strncmp (Memc[token], "file", toklen) == 0) {
+ # Position to the named file (must be in file list).
+
+ call strcpy (Memc[ip], newfname, SZ_FNAME)
+ call close (fd)
+ call lno_close (lp)
+ call sfree (sp)
+ return (TO_FILE)
+
+ } else if (strncmp (Memc[token],"spool",toklen) == 0) {
+ # Begin spooling output in a file.
+
+ if (spoolfd != NULL) {
+ call close (spoolfd)
+ spoolfd = NULL
+ }
+
+ if (Memc[ip] == EOS) {
+ ;
+ } else iferr {
+ spoolfd = open (Memc[ip], APPEND, TEXT_FILE)
+ } then {
+ spoolfd = NULL
+ call erract (EA_WARN)
+ }
+
+ # Get next keystroke from the user.
+ cmd = pg_getcmd (tty, Memc[prompt],
+ nchars, totchars, lineno, fileno, nfiles)
+
+ } else {
+ cmd = pg_getcmd (tty,
+ "colon cmds: :!cmd :/pat :line L :file F :spool F",
+ 0, 0, 0, 0, 0)
+ }
+
+ default:
+err_ call eprintf ("\07")
+ call flush (STDERR)
+ cmd = pg_getcmd (tty, Memc[prompt], nchars, totchars,
+ lineno, fileno, nfiles)
+ }
+ }
+ }
+ }
+end
+
+
+# PG_SETPROMPT -- Set the prompt string for the ukey end-of-page query.
+# The name of the file currently being paged is used unless a prompt string
+# is given.
+
+procedure pg_setprompt (prompt, u_prompt, fname)
+
+char prompt[SZ_FNAME] # receives prompt string
+char u_prompt[ARB] # user prompt string
+char fname[ARB] # file being paged
+
+int gstrcpy()
+
+begin
+ if (gstrcpy (u_prompt, prompt, SZ_FNAME) <= 0)
+ call strcpy (fname, prompt, SZ_FNAME)
+end
+
+
+# PG_GETLINE -- Get a line from the input file. Accumulates very long lines
+# (requiring several getline calls to read) into a single string.
+
+int procedure pg_getline (fd, lbuf)
+
+int fd # input file
+char lbuf[SZ_LONGLINE] # output buffer
+
+int nchars, op
+int getline()
+errchk getline
+
+begin
+ for (op=1; op + SZ_LINE < SZ_LONGLINE; op=op+nchars) {
+ nchars = getline (fd, lbuf[op])
+ if (nchars == EOF) {
+ if (op == 1)
+ return (EOF)
+ else
+ return (op - 1)
+ } else if (lbuf[op+nchars-1] == '\n')
+ break
+ }
+
+ return (op + nchars - 1)
+end
+
+
+# PG_GETCMD -- Query the user for a single character command keystroke.
+# A prompt naming the current file and our position in it is printed,
+# we read the single character command keystroke in raw mode, and then
+# the prompt line is cleared and we return.
+
+int procedure pg_getcmd (tty, fname, nchars, totchars, lineno, fileno, nfiles)
+
+pointer tty # tty descriptor
+char fname[ARB] # prefix string
+long nchars # position in file
+long totchars # size of file
+int lineno # current line number
+int fileno # current file number
+int nfiles # nfiles being paged through
+
+char keystr[SZ_KEYSTR]
+int key, pb, pbcmd[MAX_PBCMD]
+common /pgucom/ key, pb, pbcmd, keystr
+int clgkey(), fstati()
+
+begin
+ # If any commands have been pushed, return the next pushed command
+ # without generating a query.
+
+ if (pb > 0) {
+ key = pbcmd[pb]
+ pb = pb - 1
+ return (key)
+ }
+
+ # If the standard output is redirected, skip the query and just go on
+ # to the next page.
+
+ if (fstati (STDOUT, F_REDIR) == YES)
+ return (FWD_SCREEN)
+
+ # Ensure synchronization with the standard output.
+ call flush (STDOUT)
+
+ # Print query in standout mode, preceded by %done info.
+ call ttyso (STDERR, tty, YES)
+ call eprintf ("%s")
+ call pargstr (fname)
+ if (totchars > 0) {
+ if (nchars >= totchars + SZ_LINE)
+ call eprintf ("-(EOF)")
+ else {
+ call eprintf ("-(%02d%%)")
+ call pargi (max(0, min(99, nchars * 100 / totchars)))
+ }
+ }
+ if (lineno > 0) {
+ call eprintf ("-line %d")
+ call pargi (lineno - 1)
+ }
+ if (fileno > 0 && nfiles > 0) {
+ call eprintf ("-file %d of %d")
+ call pargi (fileno)
+ call pargi (nfiles)
+ }
+ call ttyso (STDERR, tty, NO)
+ call flush (STDERR)
+
+ call fseti (STDIN, F_SETREDRAW, REDRAW)
+
+ # Read the user's response, normally a single keystroke.
+ if (clgkey (UKEYS, key, keystr, SZ_KEYSTR) == EOF)
+ key = INTCHAR
+
+ call fseti (STDIN, F_SETREDRAW, 0)
+
+ if (key == INTCHAR)
+ key = QUIT
+ else if (key == NEXT_FILE_ALT)
+ key = NEXT_FILE
+ else if (key == PREV_FILE_ALT)
+ key = PREV_FILE
+
+ # Erase the prompt and return.
+ call eprintf ("\r")
+ call ttyclearln (STDERR, tty)
+ call flush (STDERR)
+
+ return (key)
+end
+
+
+# PG_GETSTR -- Called after receipt of a : key to get the string value.
+
+procedure pg_getstr (strval, maxch)
+
+char strval[maxch] # receives string
+int maxch
+
+char keystr[SZ_KEYSTR]
+int key, pb, pbcmd[MAX_PBCMD]
+common /pgucom/ key, pb, pbcmd, keystr
+
+begin
+ call strcpy (keystr, strval, maxch)
+end
+
+
+# PG_PUSHCMD -- Push back a command keystroke.
+
+procedure pg_pushcmd (cmd)
+
+int cmd #I command to be pushed
+
+char keystr[SZ_KEYSTR]
+int key, pb, pbcmd[MAX_PBCMD]
+common /pgucom/ key, pb, pbcmd, keystr
+
+begin
+ if (cmd <= 0)
+ pb = 0
+ else {
+ pb = min (MAX_PBCMD, pb + 1)
+ pbcmd[pb] = cmd
+ }
+end
+
+
+# PG_PEEKCMD -- Peek at any pushed back command keystroke.
+
+int procedure pg_peekcmd()
+
+char keystr[SZ_KEYSTR]
+int key, pb, pbcmd[MAX_PBCMD]
+common /pgucom/ key, pb, pbcmd, keystr
+
+begin
+ if (pb <= 0)
+ return (ERR)
+ else
+ return (pbcmd[pb])
+end