home *** CD-ROM | disk | FTP | other *** search
- /*++
- /* NAME
- /* pager 3
- /* SUMMARY
- /* pager for text files
- /* PROJECT
- /* pc-mail
- /* PACKAGE
- /* mailsh
- /* 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[];
- /*
- /* int scan_pager(p,fmt[,args])
- /* File *p;
- /*
- /* 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();
- /*
- /* 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
- /* Mon Apr 4 23:46:06 MET 1988
- /* VERSION/RELEASE
- /* 1.3
- /*--*/
-
- #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;
- }
-
- /* scan_pager - read from line at cursor and set current file */
-
- /* VARARGS2 */
-
- public int scan_pager(p,fmt,a1,a2,a3,a4)
- File *p;
- char *fmt;
- long a1,a2,a3,a4;
- {
- return(p && p->curr ? sscanf(p->curr->line,fmt,a1,a2,a3,a4) : 0);
- }
-
- /* 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 driver 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 < wsize[MID]; p = p->next)
- k += p->llen = printcl(MID,p->lineno = k,p->line);
- if (k < wsize[MID])
- printcl(MID,k++,(curfile->opts & PG_NOEND) ? "" : endline);
- while (k < wsize[MID])
- printcl(MID,k++,"");
- printat(MID,curfile->curr->lineno,"");
- } else {
- register int k;
-
- printcl(MID,0,(curfile->opts & PG_NOEND) ? "" : endline);
- for (k = 1; k < wsize[MID]; k++)
- printcl(MID,k,"");
- printat(MID,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(MID,(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 >= wsize[MID])
- pd_pager();
- printat(MID,(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 < wsize[MID] && 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 < wsize[MID] && 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 permanent 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 = 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 = 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];
- char *cp = buf;
- register int c;
- int err;
-
- while ((c = ascget(fp)) != EOF) { /* copy to pager file */
- if (c == '\n' || cp == buf+BUFSIZ-1) {
- *cp = 0;
- app_pager(p,cp = buf); /* line by line */
- } else {
- *cp++ = c;
- }
- }
- if (cp > buf) { /* anything left? */
- *cp = '\0';
- app_pager(p,buf);
- }
- 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, a boring thing */
-
- public void sort_pager(pp,dir)
- File *pp;
- int dir;
- {
- register Line *l;
- register int i;
- int lines;
- Line **lvec;
-
- 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));/* allocate vector */
-
- for (i = 0,l = pp->head; l; l = l->next) /* fill vector */
- lvec[i++] = l;
-
- qsort((char *) lvec,lines,sizeof(*lvec),dir == FORW_SORT ? fwdcmp : revcmp);
-
- 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++);
- }
-