home *** CD-ROM | disk | FTP | other *** search
- /*++
- /* NAME
- /* pager 3
- /* SUMMARY
- /* pager for text files
- /* PROJECT
- /* pc-mail
- /* PACKAGE
- /* mail
- /* SYNOPSIS
- /* #include "pager.h"
- /*
- /* File *open_pager()
- /*
- /* void close_pager(p)
- /* File *p;
- /*
- /* void set_pager(p)
- /* File *p;
- /*
- /* void app_pager(p,s)
- /* File *p;
- /* char *s;
- /*
- /* void del_pager(p)
- /* File *p;
- /*
- /* void mesg_pager(p,m)
- /* File *p;
- /* char *m[];
- /*
- /* void sort_pager(p,dir)
- /* File *p;
- /*
- /* int cp_pager(path)
- /* char *path;
- /*
- /* int pr_pager()
- /*
- /* int rd_pager(p,path)
- /* File *p;
- /* char *path;
- /*
- /* char *gets_pager();
- /* File *p;
- /*
- /* void puts_pager(s);
- /* char *s;
- /*
- /* int ds_pager()
- /*
- /* int pr_pager()
- /*
- /* int up_pager()
- /*
- /* int dn_pager()
- /*
- /* int pu_pager()
- /*
- /* int pd_pager()
- /* DESCRIPTION
- /* The pager provides acces to a pager file which is displayed
- /* on the screen in the middle window. Some functions operate
- /* on what is called the "current" pager file. All functions
- /* have access to the contents of the middle screen window only.
- /*
- /* open_pager() creates a new (empty) pager file. The return value
- /* should be used in subsequent accesses to the file. Sets the
- /* current file.
- /*
- /* close_pager() releases storage for a pager file. Sets the
- /* current file to none if that is the one being deleted.
- /*
- /* app_pager() appends a new line of text to the end of a pager file.
- /* Sets the current file.
- /*
- /* del_pager() deletes the line at the current cursor position. Sets the
- /* current file.
- /*
- /* mesg_pager() invokes app_pager() to copy a null-terminated array of
- /* strings to a pager file. Since it invokes app_pager(), the current
- /* pager file is set as well. Pager files filled by mesg-pager()
- /* will not be displayed with an '-- end of display --' line at their end.
- /*
- /* ins_pager() inserts a line at the current cursor position. Sets the
- /* current file.
- /*
- /* scan_pager() takes similar arguments as scanf(3), reads from the
- /* line at the current cursor position and returns the number of
- /* successfull conversions done. Does not set the current file.
- /*
- /* sort_pager() sorts a file alphabetically. Sets the current file.
- /* The dir argument selects the direction of sort (FORW_SORT, BACK_SORT).
- /*
- /* set_pager() sets the current file.
- /*
- /* gets_pager() returns a pointer to the current line in the
- /* current file, or a null pointer is there is none.
- /*
- /* puts_pager() replaces the current line in the current file.
- /*
- /* cp_pager() copies the contents of current pager file
- /* to a normal (external) file. It returns a nonzero status if
- /* an error occurred (bad path, write error,...).
- /*
- /* pr_pager() copies the current pager file to the printer.
- /*
- /* rd_pager() appends a permanent file to the current pager file.
- /* It returns a nonzero status if an error occurred. Sets the current file.
- /* rd_pager() reads through the ascf(3) ascii filter, so that it is
- /* suitable for viewing word-processor files.
- /*
- /* up_pager() moves the cursor one line up, if there is one. The
- /* screen is scrolled when the cursor was at the top of the screen.
- /*
- /* dn_pager moves the cursor one line down, if there is one. The
- /* screen is scrolled when the cursor was at the bottom of the screen.
- /*
- /* pu_pager() displays a page of text that precedes the one on the
- /* screen, or as much as there is.
- /*
- /* pd_pager() displays the next page of text, or as much as there is.
- /* FUNCTIONS AND MACROS
- /* printcl(), printat(), beep(), propen(), prclose(),ascopen(),
- /* ascclose(), ascget()
- /* SEE ALSO
- /* path(3), window(3), window(5), asc(3)
- /* DIAGNOSTICS
- /* The buzzer makes noise when attempt is made to move the
- /* cursor beyond the beginning or end of the pager file.
- /* The program aborts with an error message if references are made
- /* to the "current file" or "current line" if there is none.
- /* BUGS
- /* It looks a lot like an editor, but it isn't.
- /*
- /* No optimization. It just overwrites the whole middle window.
- /* AUTHOR(S)
- /* W.Z. Venema
- /* Eindhoven University of Technology
- /* Department of Mathematics and Computer Science
- /* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
- /* CREATION DATE
- /* Fri Apr 3 22:06:00 GMT+1:00 1987
- /* LAST MODIFICATION
- /* 90/01/22 13:02:21
- /* VERSION/RELEASE
- /* 2.1
- /*--*/
-
- #include <stdio.h>
-
- #include "defs.h"
- #include "window.h"
- #include "pager.h"
- #include "path.h"
- #include "ascf.h"
-
- hidden File *curfile = NULL; /* head of the current file */
-
- /* open_pager - create pager file and set current file */
-
- public File *open_pager()
- {
- register File *p = curfile = (File *) myalloc(sizeof(File));
-
- p->top = p->curr = p->head = p->last = NULL;
- p->opts = 0;
- return (p);
- }
-
- /* close_pager - release memory in a pager file */
-
- public void close_pager(p)
- register File *p;
- {
- register Line *q;
-
- if (p) {
- for (q = p->head; q; q = q->next) /* release lines */
- free((char *) q);
- if (curfile == p) /* unset current file */
- curfile = 0;
- free((char *) p); /* release header */
- }
- }
-
- /* app_pager - append line at end of file and set current file */
-
- public app_pager(p, s)
- register File *p;
- char *s;
- {
- register Line *l = (Line *) myalloc(sizeof(Line) + strlen(s));
-
- if (p->head == 0) { /* first line in the file */
- p->head = p->top = p->curr = l;
- } else { /* real append */
- p->last->next = l;
- }
- l->next = NULL; /* since it is last */
- l->prev = p->last; /* since it is last */
- p->last = l; /* since it is last */
-
- strcpy(l->line, s); /* copy the line */
-
- curfile = p; /* set current file */
- }
-
- /* del_pager - delete line at cursor and set current file (untested!) */
-
- public void del_pager(p)
- register File *p;
- {
- register Line *l = p->curr;
-
- if (l) {
- if (l->prev)
- l->prev->next = l->next;
- if (l->next)
- l->next->prev = l->prev;
- if (l == p->head)
- p->curr = p->head = l->next;
- if (l == p->top)
- p->curr = p->top = l->next ? l->next : l->prev;
- if (l == p->last)
- p->curr = p->last = l->prev;
- if (l == p->curr)
- p->curr = l->next;
- free((char *) l);
- }
- curfile = p;
- }
-
- /* set_pager - set the current file; use with care */
-
- public void set_pager(p)
- File *p;
- {
- curfile = p;
- }
-
- /*
- * The following functions provide an easy interface to the keyboard
- * interpreter routines. The keyboard interpreter just associates a key
- * stroke with a function call, does not care what a function does and has
- * almost no facility for passing function arguments. Although the keyboard
- * interpreter manipulates cursor and page coordinates when the some keys
- * are hit, it never knows which keys affect what the user sees on the
- * screen. That explains why the following functions rely on the above ones
- * for setting the "current file". It may also explain why the above
- * routines do not immediately update the terminal screen, whereas the
- * routines below do.
- */
-
- /* ds_pager - display a page of the current pager file */
-
- public int ds_pager()
- {
- static char endline[] = "-- end of display --";
-
- if (curfile && curfile->curr) {
- register Line *p;
- register int k;
-
- for (p = curfile->top, k = 0; p && k < midwin->size; p = p->next)
- k += p->llen = printcl(midwin, p->lineno = k, p->line);
- if (k < midwin->size)
- printcl(midwin, k++, (curfile->opts & PG_NOEND) ? "" : endline);
- while (k < midwin->size)
- printcl(midwin, k++, "");
- printat(midwin, curfile->curr->lineno, "");
- } else {
- register int k;
-
- printcl(midwin, 0, (curfile->opts & PG_NOEND) ? "" : endline);
- for (k = 1; k < midwin->size; k++)
- printcl(midwin, k, "");
- printat(midwin, 0, "");
- }
- return (0); /* screen up-to-date */
- }
-
- /* up_pager - up-arrow key hit. check cursor position */
-
- public int up_pager()
- {
- register Line *p = curfile ? curfile->curr : 0;
-
- if (p == 0 || p->prev == 0) {
- beep();
- } else {
- if (p->lineno == 0)
- pu_pager();
- printat(midwin, (curfile->curr = p->prev)->lineno, "");
- }
- return (0);
- }
-
- /* dn_pager - down-arrow key hit. check cursor position */
-
- public int dn_pager()
- {
- register Line *p = curfile ? curfile->curr : 0;
-
- if (p == 0 || p->next == 0) {
- beep();
- } else {
- if (p->lineno + p->llen >= midwin->size)
- pd_pager();
- printat(midwin, (curfile->curr = p->next)->lineno, "");
- }
- return (0);
- }
-
- /* pu_pager - display preceding page of info */
-
- public int pu_pager()
- {
- register Line *p;
- register int k;
-
- if (curfile && (p = curfile->top) && curfile->top->prev) {
- for (k = 0; k < midwin->size && p; k += p->llen, p = p->prev)
- curfile->top = p;
- curfile->curr = curfile->top;
- ds_pager();
- } else {
- beep();
- }
- return (0);
- }
-
- /* pd_pager - display next page of info */
-
- public int pd_pager()
- {
- register Line *p = curfile ? curfile->top : 0;
- register int k;
- register Line *dummy;
-
- for (k = 0; k < midwin->size && p; k += p->llen, p = p->next)
- dummy = p;
- if (p) {
- curfile->curr = curfile->top = dummy;
- ds_pager();
- } else {
- beep();
- }
- return (0);
- }
-
- /*
- * The following functions copy external files to pager file and vice-versa.
- * There is a limited error detection facility in the form of nonzero return
- * values.
- */
-
- /* cp_pager - copy current pager file to permanent file */
-
- public int cp_pager(path)
- char *path;
- {
- register FILE *fp;
-
- if (curfile && (fp = fopen(path, "w"))) {
- register Line *pp;
- int err;
-
- for (pp = curfile->head; pp; pp = pp->next)
- fputs(pp->line, fp), putc('\n', fp);
- err = (fflush(fp) || ferror(fp));
- fclose(fp);
- return (err);
- } else {
- return (-1);
- }
- }
-
- /* pr_pager - print pager file on default printer */
-
- public int pr_pager()
- {
- register FILE *fp;
-
- if (curfile && (fp = propen())) {
- register Line *pp;
- int err;
-
- for (pp = curfile->head; pp; pp = pp->next)
- fputs(pp->line, fp), putc('\n', fp);
- err = (fflush(fp) || ferror(fp));
- prclose(fp);
- return (err);
- } else {
- return (-1);
- }
- }
-
- /* rd_pager - copy ordinary file via filter to pager file */
-
- public int rd_pager(p, path)
- File *p;
- char *path;
- {
- register FILE *fp;
-
- if (p && (fp = ascopen(path, "r"))) { /* init the filter */
- char buf[BUFSIZ];
- int err;
-
- while (ascgets(buf, sizeof(buf), fp)) /* copy to pager file */
- app_pager(p, buf); /* line by line */
-
- err = ferror(fp); /* check for errors */
- ascclose(fp);
- return (err);
- } else {
- return (-1);
- }
- }
-
- /* fwdcmp, revcmp - compare lexical order of lines */
-
- hidden int fwdcmp(l1, l2)
- Line **l1,
- **l2;
- {
- return (strcmp((*l1)->line, (*l2)->line));
- }
-
- hidden int revcmp(l1, l2)
- Line **l1,
- **l2;
- {
- return (strcmp((*l2)->line, (*l1)->line));
- }
-
- /* sort_pager - sort a pager file */
-
- public void sort_pager(pp, dir)
- File *pp;
- int dir;
- {
- register Line *l;
- register int i;
- int lines;
- Line **lvec;
-
- /* Build a vector with pointers to line structures. */
-
- for (i = 0, l = pp->head; l; l = l->next) /* count nbr of lines */
- i++;
- if (i <= 1) /* no work */
- return;
-
- lvec = (Line **) myalloc((lines = i) * sizeof(*lvec));
-
- for (i = 0, l = pp->head; l; l = l->next) /* fill vector */
- lvec[i++] = l;
-
- /* Sort the vector with pointers to line structures. */
-
- qsort((char *) lvec, lines, sizeof(*lvec),
- dir == FORW_SORT ? fwdcmp : revcmp);
-
- /* Restore links between line structures and destroy the sorted vector */
-
- for (i = 0; i < lines - 1; i++) /* fix forward links */
- lvec[i]->next = lvec[i + 1];
- lvec[i]->next = NULL;
-
- lvec[0]->prev = NULL; /* fix backward links */
- for (i = 1; i < lines; i++)
- lvec[i]->prev = lvec[i - 1];
-
- pp->head = pp->top = pp->curr = lvec[0]; /* fix file header */
- pp->last = lvec[lines - 1];
-
- free((char *) lvec); /* release vector */
-
- curfile = pp; /* set current file */
- }
-
- /* gets_pager - return current line in current file */
-
- public char *gets_pager()
- {
- return (curfile && curfile->curr ? curfile->curr->line : 0);
- }
-
- /* puts_pager - replace line (cleanup this mess) */
-
- public void puts_pager(s)
- char *s;
- {
- if (curfile == 0 || curfile->curr == 0) { /* no-no if there is no line */
- fatal("puts_pager: no current file");
- } else {
- register Line *old = curfile->curr; /* get current line */
- register Line *new = (Line *) myalloc(sizeof(Line) + strlen(s));
-
- new->prev = old->prev; /* fill it in */
- new->next = old->next;
- new->lineno = old->lineno;
- strcpy(new->line, s);
- if (new->next) /* check next line */
- new->next->prev = new;
- if (new->prev) /* check previous line */
- new->prev->next = new;
- if (old == curfile->head) /* check file head */
- curfile->head = new;
- if (old == curfile->top) /* check file display */
- curfile->top = new;
- if (old == curfile->last) /* check file tail */
- curfile->last = new;
- free((char *) curfile->curr); /* release old line */
- curfile->curr = new; /* set current line */
- }
- }
-
- /* mesg_pager - copy null-terminated array of strings to pager file */
-
- public void mesg_pager(pp, msg)
- register File *pp;
- register char **msg;
- {
- pp->opts |= PG_NOEND; /* suppress end marker */
-
- while (*msg)
- app_pager(pp, *msg++);
- }
-