home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-01-24 | 46.6 KB | 1,498 lines |
- Newsgroups: comp.sources.misc
- subject: v10i041: PC-MAIL release 2, 9/11
- from: wswietse@lso.win.tue.nl (Wietse Venema)
- Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 10, Issue 41
- Submitted-by: wswietse@lso.win.tue.nl (Wietse Venema)
- Archive-name: pcmail2/part09
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 9 (of 11)."
- # Contents: daemon/pc-maild.c main/hsearch.c main/pager.c
- # Wrapped by wswietse@tuewsa on Mon Jan 22 17:27:21 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f daemon/pc-maild.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"daemon/pc-maild.c\"
- else
- echo shar: Extracting \"daemon/pc-maild.c\" \(14808 characters\)
- sed "s/^X//" >daemon/pc-maild.c <<'END_OF_daemon/pc-maild.c'
- X/*++
- X/* NAME
- X/* pc-maild 8
- X/* SUMMARY
- X/* deliver unsent mail
- X/* PROJECT
- X/* pc-mail
- X/* PACKAGE
- X/* nfs
- X/* SYNOPSIS
- X/* pc-maild [delay]
- X/* DESCRIPTION
- X/* This program should be run on the nfs file server that exports
- X/* mail directories to MS-DOS pc-mail users. It replaces the
- X/* (MS-DOS -> UNIX) transmission function of the MS-DOS \fIcico\fR
- X/* program.
- X/*
- X/* The per-user mail directories (default: /usr/spool/pc-mail/\fIuser\fR)
- X/* are scanned for outgoing mail every \fIdelay\fR seconds (default: 300).
- X/* When outgoing mail is found, it is sent through the UNIX rmail program
- X/* (uucp mail interface) and the corresponding files are removed from the
- X/* user\'s mail directory.
- X/*
- X/* The program should run with root privileges. It will assume
- X/* the (uid, gid) of the sending user before accessing mail files.
- X/* COMMANDS
- X/* rmail(1), uucp mail interface program
- X/* FILES
- X/* /usr/spool/pc-mail/\fIuser\fR/dNNNNN, mail message (unsent mail)
- X/* /usr/spool/pc-mail/\fIuser\fR/xNNNNN, recipients, subject (unsent mail)
- X/* /usr/spool/pc-mail/\fIuser\fR/qNNNNN, mail message (sent mail)
- X/* /usr/spool/pc-mail/\fIuser\fR/rNNNNN, recipients, subject (sent mail)
- X/* (NNNNN is the pc-mail "message id").
- X/* SEE ALSO
- X/* pc-mail(1)
- X/* DIAGNOSTICS
- X/* Errors found during initialization cause the program to
- X/* terminate with a diagnostic on the standard error stream.
- X/* All other errors are considered transient, i.e. if something
- X/* fails, it is tried again at a later time. Where possible,
- X/* diagnostics are logged through the syslog facility.
- X/* BUGS
- X/* Scanning mail directories is an inefficient way to detect
- X/* unsent mail.
- X/* AUTHOR(S)
- X/* W.Z. Venema
- X/* Eindhoven University of Technology
- X/* Department of Mathematics and Computer Science
- X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
- X/* CREATION DATE
- X/* Sun Oct 22 22:12:15 MED 1989
- X/* LAST MODIFICATION
- X/* 1/6/90 19:45:05
- X/* VERSION/RELEASE
- X/* 1.6
- X/*--*/
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#) pc-maild.c 1.6 1/6/90 19:45:05";
- X
- X#endif
- X
- X /*
- X * General return-value conventions:
- X *
- X * int func(): 0 means OK
- X *
- X * stuff *func(): 0 means error
- X *
- X */
- X
- X#include <stdio.h>
- X#include <pwd.h>
- X#include <time.h>
- X#include <signal.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X
- X#ifdef SYSLOG
- X#include <syslog.h>
- X#else
- X#include "syslog.h"
- X#endif
- X
- X#ifdef SYSV
- X#include <sys/utsname.h>
- X#include <ndir.h>
- X#else
- X#include <sys/types.h>
- X#include <sys/dir.h>
- X#include <sgtty.h>
- X#endif
- X
- X#include "dosunix.h"
- X#include "util.h"
- X#include "mtime.h"
- X
- X/* Library functions */
- X
- Xextern char *strtok();
- Xextern char *strncpy();
- Xextern struct passwd *getpwnam();
- Xextern unsigned sleep();
- Xextern void exit();
- Xextern void _exit();
- Xextern struct tm *localtime();
- Xextern char *asctime();
- Xextern long time();
- X
- X/* Local defines, declarations */
- X
- X#ifndef DELAY
- X#define DELAY 300 /* default: scan every 5 minutes */
- X#endif
- X
- X#ifndef MAILDIR
- X#define MAILDIR "/usr/spool/pc-mail" /* default pc-mail directory tree */
- X#endif
- X
- X#define MAXLINE 1024 /* max length of recipients line */
- X
- Xvoid catchsig();
- Xvoid finduser();
- Xchar *getrcpt();
- Xchar *fullname();
- X
- Xint delay = DELAY; /* the default delay */
- Xchar *progname; /* my process name */
- X
- X
- Xint main(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X progname = *argv;
- X
- X /* Sanity checks */
- X
- X#ifndef DEBUG
- X
- X if (geteuid() != 0) {
- X (void) fprintf(stderr, "%s: must be run as root\n", progname);
- X exit(1);
- X }
- X#endif
- X
- X /* Check for command-line delay argument */
- X
- X if (argc > 1 && (delay = atoi(argv[1])) < 1)
- X delay = DELAY;
- X
- X /* Become a daemon process */
- X
- X#ifndef DEBUG
- X disconnect();
- X#endif
- X
- X /* Set up signal handling */
- X
- X catchsig();
- X
- X /* Enable syslogging */
- X
- X (void) openlog(progname, LOG_PID, LOG_MAIL);
- X syslog(LOG_WARNING, "daemon restarted");
- X
- X /* Setup a decent environment */
- X
- X if (putenv("PATH=/bin:/usr/bin:/usr/ucb") || putenv("IFS= \t\n")) {
- X syslog(LOG_WARNING, "initialization failed (insufficient resources)");
- X exit(1);
- X }
- X /* Enter the main loop */
- X
- X finduser();
- X /* NOTREACHED */
- X}
- X
- X/* finduser - repeatedly iterate over all pc-mail user directories */
- X
- Xvoid finduser()
- X{
- X register DIR *maildp;
- X register struct direct *dp;
- X register struct passwd *uinfo;
- X MTIME *dirtime;
- X char userdir[BUFSIZ];
- X struct stat st;
- X
- X /*
- X * Ignore names that start with a period.
- X *
- X * Ignore names that do not correspond to a directory.
- X *
- X * Ignore directories that did not change since the last time they were
- X * known to hold no unsent mail.
- X *
- X * Ignore directories that do not have a name equal to the login name of a
- X * user.
- X */
- X
- X for (;;) {
- X if ((e_chdir(MAILDIR) == 0) && (maildp = e_opendir(MAILDIR))) {
- X while (dp = readdir(maildp)) {
- X if ((dp->d_name[0] != '.')
- X && (stat(dp->d_name, &st) == 0)
- X && ((st.st_mode & S_IFMT) == S_IFDIR)
- X && (st.st_mtime > (dirtime = mtime(dp->d_name))->time)
- X && ((uinfo = getpwnam(dp->d_name)) != 0)) {
- X (void) sprintf(userdir, "%s/%s", MAILDIR, dp->d_name);
- X if (findmail(uinfo, userdir) == 0)
- X dirtime->time = st.st_mtime; /* say it was empty */
- X }
- X }
- X closedir(maildp); /* done with this user */
- X (void) chdir("/"); /* be friendly */
- X }
- X (void) sleep((unsigned) delay); /* try again later */
- X }
- X}
- X/* findmail - enter a user\'s mail directory and scan for unsent mail */
- X
- Xint findmail(uinfo, userdir)
- Xstruct passwd *uinfo;
- Xchar *userdir;
- X{
- X register DIR *dd;
- X register struct direct *p;
- X int seqno;
- X static char xfile[BUFSIZ]; /* file with recipients (unsent mail) */
- X static char rfile[BUFSIZ]; /* same, but with "Sent" status */
- X static char dfile[BUFSIZ]; /* file with message (unsent mail) */
- X static char qfile[BUFSIZ]; /* same, but with "Sent" status */
- X int found = 0; /* no mail found yet */
- X
- X /*
- X * Use the fact that 'x' files (recipient addresses) are created later
- X * than 'd' files (message body) when a pc user generates a message.
- X * Extract the pc-mail message id from the file name and try to pipe the
- X * message through the UNIX rmail command. All knowledge about pc-mail
- X * file names resides in this function. Return zero if no unsent mail was
- X * found.
- X */
- X
- X if ((e_chdir(userdir) == 0) && (dd = e_opendir(userdir))) {
- X while (p = readdir(dd)) {
- X if (*p->d_name == 'x' && sscanf(p->d_name + 1, "%d", &seqno) == 1) {
- X (void) sprintf(xfile, "x%05d", seqno); /* recipients */
- X if (strcmp(p->d_name, xfile) == 0) { /* ignore junk */
- X (void) sprintf(dfile, "d%05d", seqno);
- X (void) sprintf(rfile, "r%05d", seqno);
- X (void) sprintf(qfile, "q%05d", seqno);
- X pickup(uinfo, xfile, dfile, rfile, qfile);
- X found = 1; /* found unsent mail */
- X }
- X }
- X }
- X closedir(dd);
- X (void) chdir(MAILDIR);
- X }
- X return (found);
- X}
- X
- X/* pickup - pick up one message from a user\'s mail directory */
- X
- Xpickup(uinfo, xfile, dfile, rfile, qfile)
- Xstruct passwd *uinfo;
- Xchar *xfile;
- Xchar *dfile;
- Xchar *rfile;
- Xchar *qfile;
- X{
- X
- X /*
- X * Actual delivery must be done with the (uid, gid) of the sender, or the
- X * From: lines will not be correct. Therefore, we do delivery in a child
- X * process. This also avoid all kinds of nasty security problems. All
- X * errors are considered non-fatal.
- X */
- X
- X#ifdef DEBUG
- X sendasuser(uinfo, xfile, dfile, rfile, qfile); /* don't fork */
- X#else
- X switch (e_fork()) {
- X case -1: /* failure */
- X break;
- X case 0: /* child */
- X sendasuser(uinfo, xfile, dfile, rfile, qfile);
- X _exit(0);
- X /* NOTREACHED */
- X default: /* parent */
- X (void) wait((int *) 0);
- X break;
- X }
- X#endif
- X}
- X
- X/* sendasuser - send mail through rmail(1), having (uid, gid) of sender */
- X
- Xsendasuser(uinfo, xfile, dfile, rfile, qfile)
- Xstruct passwd *uinfo;
- Xchar *xfile;
- Xchar *dfile;
- Xchar *rfile;
- Xchar *qfile;
- X{
- X char *dest; /* recipient address(es) */
- X
- X /*
- X * User-specific mail files must be opened AFTER we have assumed the
- X * (uid, gid) of the pc-mail user; this in order to avoid nasty security
- X * holes. When delivery succeeds, we rename the spool files so they
- X * reflect the "Sent" status.
- X */
- X
- X if ((setugid(uinfo) == 0) /* assume proper (uid, gid) */
- X && (dest = getrcpt(uinfo, xfile)) /* extract recipients */
- X && (rmail(uinfo, dfile, dest) == 0)) { /* pipe message through rmail */
- X (void) unlink(rfile); /* just in case */
- X (void) unlink(qfile); /* just in case */
- X (void) u_link(uinfo, xfile, rfile); /* change status to "Sent" */
- X (void) u_link(uinfo, dfile, qfile); /* change status to "Sent" */
- X (void) u_unlink(uinfo, xfile); /* recipients file */
- X (void) u_unlink(uinfo, dfile); /* message body file */
- X }
- X}
- X
- X/* setugid - assume (uid, gid) of user */
- X
- Xint setugid(uinfo)
- Xstruct passwd *uinfo;
- X{
- X if (setgid(uinfo->pw_gid)) {
- X syslog(LOG_WARNING, "setgid(%s) failed: %m", uinfo->pw_name);
- X return (1);
- X }
- X if (setuid(uinfo->pw_uid)) {
- X syslog(LOG_WARNING, "setuid(%s) failed: %m", uinfo->pw_name);
- X return (1);
- X } else {
- X return (0);
- X }
- X}
- X
- X/* getrcpt - extract recipient from user mail file */
- X
- Xchar *getrcpt(uinfo, xfile)
- Xstruct passwd *uinfo;
- Xchar *xfile;
- X{
- X FILE *xfp; /* recipient file pointer */
- X static char dest[MAXLINE]; /* recipient names */
- X register char *ret;
- X
- X if ((xfp = u_fopen(uinfo, xfile, "r")) == 0) {
- X return (0);
- X } else {
- X pc_wait(fileno(xfp)); /* let pc finish writing */
- X ret = dosgets(dest, sizeof(dest), xfp);
- X (void) fclose(xfp);
- X if (ret == 0)
- X syslog(LOG_WARNING, "no recipients specified in %s/%s",
- X uinfo->pw_name, xfile);
- X return (ret);
- X }
- X}
- X
- X/* rmail - pipe a pc mail message through the UNIX rmail program */
- X
- Xint rmail(uinfo, dfile, dest)
- Xstruct passwd *uinfo; /* originator */
- Xchar *dfile; /* message file */
- Xchar *dest; /* recipients */
- X{
- X static char cmd[MAXLINE+20]; /* command + arguments */
- X FILE *dfp; /* source stream */
- X FILE *pfp; /* output stream */
- X int ret; /* return value, 0 if OK */
- X long secs; /* absolute UNIX time */
- X static char hostname[BUFSIZ]; /* our host name */
- X
- X /*
- X * The UNIX rmail command needs a UUCP-style From_ line.
- X *
- X * The To: and From: lines can be added for esthetical porposes.
- X *
- X * Report communication failures with the rmail command. Error returns from
- X * rmail are ignored; they should be handled in sendmail.
- X */
- X
- X if (dfp = u_fopen(uinfo, dfile, "r")) { /* open message file */
- X (void) sprintf(cmd, "rmail %s", dest);
- X if ((pfp = popen(cmd, "w")) == 0) { /* invoke rmail... */
- X syslog(LOG_WARNING, "cannot invoke %.20s...: %m", rmail);
- X ret = 1;
- X } else {
- X secs = time((long *) 0);
- X (void) gethostname(hostname, sizeof(hostname));
- X (void) fprintf(pfp, "From %s %.24s remote from %s\n",
- X uinfo->pw_name,
- X asctime(localtime(&secs)),
- X hostname); /* add UUCP From_ line */
- X#ifdef RFC822
- X rfc822hdr(uinfo, dest, pfp); /* do RFC822 stuff */
- X#endif
- X if (ret = dos2unix(dfp, pfp)) /* append message body */
- X syslog(LOG_WARNING, "write to rmail failed: %m");
- X (void) pclose(pfp);
- X }
- X (void) fclose(dfp);
- X }
- X return (ret);
- X}
- X
- X/* rfc822hdr - generate subset of RFC822 header lines */
- X
- Xrfc822hdr(uinfo, dest, pfp)
- Xregister struct passwd *uinfo;
- Xchar *dest;
- Xregister FILE *pfp;
- X{
- X char *sep = " ,\t\r\n";
- X char *name;
- X int n = 0;
- X
- X /*
- X * There are a few problems with this function. First of all, it destroys
- X * the dest argument. In the second place, putting each recipient on a
- X * separate header line is ugly; fortunately, sendmail will fix this.
- X */
- X
- X (void) fprintf(pfp, "From: %s (%s)\n", uinfo->pw_name,
- X fullname(uinfo)); /* add From: header line */
- X for (name = strtok(dest, sep); name; name = strtok((char *) 0, sep))
- X (void) fprintf(pfp, "%s%s", n == 0 ? "To: " : ",\n ", name);
- X if (n)
- X (void) putc('\n', pfp);
- X}
- X
- X/* fullname - extract full name from gecos field */
- X
- Xchar *fullname(uinfo)
- Xstruct passwd *uinfo;
- X{
- X static char name[BUFSIZ];
- X
- X /* This code assumes BSD-style gecos fields (name,stuff,stuff...) */
- X
- X if (sscanf(uinfo->pw_gecos, "%[^,]", name) == 0)
- X name[0] = '\0';
- X return (name);
- X}
- X
- X/* gotsig - caught a signal; terminate with diagnostic */
- X
- Xvoid gotsig(sig)
- Xint sig;
- X{
- X syslog(LOG_WARNING, "going down on signal %d", sig);
- X closelog();
- X exit(sig);
- X}
- X
- X/* catchsig - catch some signals */
- X
- Xvoid catchsig()
- X{
- X#ifdef DEBUG
- X (void) signal(SIGHUP, gotsig);
- X (void) signal(SIGINT, gotsig);
- X (void) signal(SIGQUIT, gotsig);
- X#else
- X (void) signal(SIGHUP, SIG_IGN);
- X (void) signal(SIGINT, SIG_IGN);
- X (void) signal(SIGQUIT, SIG_IGN);
- X#endif
- X (void) signal(SIGBUS, gotsig);
- X (void) signal(SIGSEGV, gotsig);
- X (void) signal(SIGTERM, gotsig);
- X}
- X
- X/* disconnect - become a daemon process */
- X
- Xdisconnect()
- X{
- X#ifndef SYSV
- X int fd;
- X
- X#endif
- X
- X /* Get rid of the parent process */
- X
- X switch (e_fork()) {
- X case -1: /* failure */
- X exit(1);
- X /* NOTREACHED */
- X default:
- X _exit(0); /* parent */
- X /* NOTREACHED */
- X case 0: /* child */
- X break;
- X }
- X
- X /* Get rid of the controlling terminal */
- X
- X (void) close(0);
- X (void) close(1);
- X (void) close(2);
- X#ifdef SYSV
- X (void) setpgrp();
- X#else
- X if ((fd = open("/dev/tty", 0)) >= 0) {
- X (void) ioctl(fd, TIOCNOTTY, 0);
- X (void) close(fd);
- X }
- X#endif
- X}
- X
- X/* pc_wait - wait till the pc has finished writing a file */
- X
- Xpc_wait(fd)
- Xint fd;
- X{
- X struct stat st;
- X long oldsize = 0;
- X
- X /*
- X * Repeatedly sleep one second until the file size does not change
- X * anymore.
- X *
- X * At first sight, this does not seem to be a very robust algorithm. It is,
- X * however, sufficient. The pc sofware will first create a message file,
- X * then the file with recipient addresses. The pc-maild program, on the
- X * other hand, will read the recipient-address file first. If that file
- X * turns out to be empty, it will try again at a later time. So, the only
- X * time we may produce an incorrect result is under the following
- X * conditions:
- X *
- X * (1) the file with recipient names is longer than the PC/NFS packet size
- X * or the pc\'s stdio buffer size.
- X *
- X * (2) the network connection goes down for > 1 second after part of the
- X * data has arrived in the file with recipient addresses.
- X */
- X
- X while (fstat(fd, &st) == 0 && oldsize != st.st_size) {
- X oldsize = st.st_size;
- X (void) sleep(1);
- X }
- X}
- X
- X#ifdef SYSV
- X
- X/* gethostname - BSD compatibility routine */
- X
- Xgethostname(name, len)
- Xchar *name;
- Xint len;
- X{
- X struct utsname ut;
- X
- X (void) uname(&ut);
- X (void) strncpy(name, ut.nodename, len);
- X return (0);
- X}
- X
- X#endif
- END_OF_daemon/pc-maild.c
- if test 14808 -ne `wc -c <daemon/pc-maild.c`; then
- echo shar: \"daemon/pc-maild.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f main/hsearch.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"main/hsearch.c\"
- else
- echo shar: Extracting \"main/hsearch.c\" \(15461 characters\)
- sed "s/^X//" >main/hsearch.c <<'END_OF_main/hsearch.c'
- X/* Original source written by Arnold Robbins */
- X
- X#include <ctype.h> /* for case-insensitive version */
- X#include "hsearch.h" /* join the parts that were broken up */
- X
- X#define strcmp istrcmp /* for case-insensitive version */
- X
- Xstatic ELEMENT **Table = NULL; /* pointer to dynamicly allocated table */
- Xstatic int Num_elem = -1; /* number of elements */
- X
- Xextern char *calloc();
- X
- Xextern void hdestroy();
- Xextern int hcreate();
- Xextern ENTRY *hsearch();
- X
- Xstatic int hashit();
- X
- X/*
- X * table of first 1900 or so primes, for use in finding the right prime
- X * number to be the table size. this table may be generally useful...
- X */
- X
- Xstatic unsigned short primetab[] = {
- X/*
- X * comment these out, so that table will always have a minimal size...
- X1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
- X*/
- X73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
- X157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
- X239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
- X331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
- X421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
- X509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607,
- X613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
- X709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811,
- X821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
- X919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019,
- X1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097,
- X1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201,
- X1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
- X1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409,
- X1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487,
- X1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579,
- X1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667,
- X1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777,
- X1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877,
- X1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993,
- X1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083,
- X2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179,
- X2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287,
- X2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381,
- X2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473,
- X2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609,
- X2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693,
- X2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789,
- X2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887,
- X2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001,
- X3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119,
- X3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229,
- X3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331,
- X3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457,
- X3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541,
- X3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637,
- X3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739,
- X3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853,
- X3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947,
- X3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073,
- X4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177,
- X4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273,
- X4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409,
- X4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517,
- X4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639,
- X4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733,
- X4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871,
- X4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969,
- X4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077,
- X5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189,
- X5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309,
- X5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431,
- X5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521,
- X5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651,
- X5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743,
- X5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851,
- X5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981,
- X5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091,
- X6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211,
- X6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311,
- X6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397,
- X6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553,
- X6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673,
- X6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781,
- X6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883,
- X6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991,
- X6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121,
- X7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237,
- X7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369,
- X7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507,
- X7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589,
- X7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699,
- X7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829,
- X7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937,
- X7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087,
- X8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209,
- X8219, 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297,
- X8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431,
- X8443, 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573,
- X8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681,
- X8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, 8753, 8761, 8779,
- X8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, 8887,
- X8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011,
- X9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137,
- X9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241,
- X9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371,
- X9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463,
- X9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601,
- X9613, 9619, 9623, 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719,
- X9721, 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817,
- X9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929,
- X9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, 10061, 10067, 10069,
- X10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159,
- X10163, 10169, 10177, 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259,
- X10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, 10331, 10333, 10337,
- X10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459,
- X10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, 10589,
- X10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667,
- X10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, 10753, 10771, 10781,
- X10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889,
- X10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993,
- X11003, 11027, 11047, 11057, 11059, 11069, 11071, 11083, 11087, 11093, 11113,
- X11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173, 11177, 11197, 11213,
- X11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317,
- X11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437,
- X11443, 11447, 11467, 11471, 11483, 11489, 11491, 11497, 11503, 11519, 11527,
- X11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657, 11677,
- X11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, 11779, 11783,
- X11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863, 11867,
- X11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, 11941, 11953, 11959,
- X11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049, 12071,
- X12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161,
- X12163, 12197, 12203, 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269,
- X12277, 12281, 12289, 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379,
- X12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479,
- X12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553,
- X12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, 12637, 12641, 12647,
- X12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739, 12743, 12757,
- X12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, 12841, 12853, 12889,
- X12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953, 12959, 12967,
- X12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, 13037, 13043, 13049,
- X13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151, 13159, 13163,
- X13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267,
- X13291, 13297, 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397,
- X13399, 13411, 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487,
- X13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619,
- X13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, 13709,
- X13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, 13781, 13789, 13799,
- X13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, 13883, 13901, 13903,
- X13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, 13999, 14009, 14011,
- X14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, 14107, 14143, 14149,
- X14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, 14249, 14251, 14281,
- X14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, 14387, 14389, 14401,
- X14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489,
- X14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591,
- X14593, 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699,
- X14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, 14771,
- X14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869,
- X14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, 14951, 14957, 14969,
- X14983, 15013, 15017, 15031, 15053, 15061, 15073, 15077, 15083, 15091, 15101,
- X15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, 15187, 15193, 15199,
- X15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, 15277, 15287, 15289,
- X15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359, 15361, 15373, 15377,
- X15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473,
- X15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601,
- X15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679,
- X15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, 15787,
- X15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, 15887, 15889,
- X15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001,
- X16007, 16033, 16057, 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097,
- X16103, 16111, 16127, 16139, 16141, 16183, 16187, 16189, 16193, 16217, 16223,
- X16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, 16333, 16339, 16349,
- X16361, 16363, 16369, 16381
- X};
- X
- X/* hcreate --- create a hash table at least howmany big */
- X
- Xint hcreate (howmany)
- Xregister unsigned int howmany;
- X{
- X register int i, j;
- X
- X /*
- X * find first prime number >= howmany, and use it for table size
- X */
- X
- X if (Num_elem != -1) /* already a table out there */
- X hdestroy(); /* remove it */
- X
- X j = sizeof (primetab) / sizeof (primetab[0]);
- X for (i = 0; i < j; i++)
- X if (primetab[i] >= howmany)
- X break;
- X
- X if (i >= j) /* howmany bigger than any prime we have, use it */
- X Num_elem = howmany;
- X else
- X Num_elem = primetab[i];
- X
- X if ((Table = (ELEMENT **) calloc (Num_elem, sizeof (ELEMENT *))) == NULL)
- X return (0);
- X else
- X return (1);
- X}
- X
- X/* idestroy --- destroy a single element on a chain */
- X
- Xstatic void idestroy (elem)
- XELEMENT *elem;
- X{
- X if (elem != NULL)
- X {
- X idestroy (elem->next);
- X free ((char *) elem);
- X }
- X}
- X
- X/* hdestroy --- nuke the existing hash table */
- X
- Xvoid hdestroy()
- X{
- X register unsigned int i;
- X
- X if (Table != NULL)
- X {
- X /* free all the chains */
- X for (i = 0; i < Num_elem; i++)
- X idestroy (Table[i]);
- X
- X /* now the table itself */
- X free ((char *) Table);
- X Num_elem = -1;
- X Table = NULL;
- X }
- X}
- X
- X/* hsearch --- lookup or enter an item in the hash table */
- X
- XENTRY *hsearch (entry, action)
- XENTRY entry;
- XACTION action;
- X{
- X ELEMENT e;
- X ELEMENT *ep = NULL;
- X ELEMENT *ep2 = NULL;
- X int index;
- X
- X if (Table == NULL)
- X return (NULL);
- X
- X index = hashit (entry.key);
- X if (Table[index] == NULL) /* nothing there */
- X {
- X if (action == FIND)
- X return (NULL);
- X else
- X {
- X /* add it to the table */
- X e.item = entry;
- X e.next = NULL;
- X if ((Table[index] = (ELEMENT *) calloc (1, sizeof (ELEMENT))) == NULL)
- X return (NULL);
- X *Table[index] = e;
- X return (& Table[index]->item);
- X }
- X }
- X else
- X {
- X /* something in bucket, see if already on chain */
- X for (ep = Table[index]; ep != NULL; ep = ep->next)
- X {
- X if (strcmp (ep->item.key, entry.key) == 0)
- X {
- X if (action == ENTER)
- X ep->item.data = entry.data;
- X /* already there, just change data */
- X /* or action was just find it */
- X return (& ep->item);
- X }
- X else
- X ep2 = ep;
- X }
- X /* at this point, item was not in table */
- X /* ep2 points at last element on the list */
- X if (action == ENTER)
- X {
- X if ((ep2->next = (ELEMENT *) calloc (1, sizeof (ELEMENT))) == NULL)
- X return (NULL);
- X ep2->next->item = entry;
- X ep2->next->next = NULL;
- X return (& ep2->next->item);
- X }
- X else
- X return (NULL);
- X }
- X /*NOTREACHED*/
- X}
- X
- X/* hashit --- do the hashing algorithm */
- X
- X/*
- X * algorithm is sum of string elements, plus string length
- X * mod table size.
- X *
- X * made case insensitive for hyphenation program
- X */
- X
- Xstatic int hashit (text)
- Xregister char *text;
- X{
- X register long int sum = 0;
- X register int i;
- X register int kludge;
- X
- X for (i = 0; (kludge = text[i]) != '\0'; i++)
- X sum += (isupper(kludge) ? tolower(kludge) : kludge);
- X sum += i;
- X
- X return (sum % Num_elem);
- X}
- X
- END_OF_main/hsearch.c
- if test 15461 -ne `wc -c <main/hsearch.c`; then
- echo shar: \"main/hsearch.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f main/pager.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"main/pager.c\"
- else
- echo shar: Extracting \"main/pager.c\" \(13541 characters\)
- sed "s/^X//" >main/pager.c <<'END_OF_main/pager.c'
- X/*++
- X/* NAME
- X/* pager 3
- X/* SUMMARY
- X/* pager for text files
- X/* PROJECT
- X/* pc-mail
- X/* PACKAGE
- X/* mail
- X/* SYNOPSIS
- X/* #include "pager.h"
- X/*
- X/* File *open_pager()
- X/*
- X/* void close_pager(p)
- X/* File *p;
- X/*
- X/* void set_pager(p)
- X/* File *p;
- X/*
- X/* void app_pager(p,s)
- X/* File *p;
- X/* char *s;
- X/*
- X/* void del_pager(p)
- X/* File *p;
- X/*
- X/* void mesg_pager(p,m)
- X/* File *p;
- X/* char *m[];
- X/*
- X/* void sort_pager(p,dir)
- X/* File *p;
- X/*
- X/* int cp_pager(path)
- X/* char *path;
- X/*
- X/* int pr_pager()
- X/*
- X/* int rd_pager(p,path)
- X/* File *p;
- X/* char *path;
- X/*
- X/* char *gets_pager();
- X/* File *p;
- X/*
- X/* void puts_pager(s);
- X/* char *s;
- X/*
- X/* int ds_pager()
- X/*
- X/* int pr_pager()
- X/*
- X/* int up_pager()
- X/*
- X/* int dn_pager()
- X/*
- X/* int pu_pager()
- X/*
- X/* int pd_pager()
- X/* DESCRIPTION
- X/* The pager provides acces to a pager file which is displayed
- X/* on the screen in the middle window. Some functions operate
- X/* on what is called the "current" pager file. All functions
- X/* have access to the contents of the middle screen window only.
- X/*
- X/* open_pager() creates a new (empty) pager file. The return value
- X/* should be used in subsequent accesses to the file. Sets the
- X/* current file.
- X/*
- X/* close_pager() releases storage for a pager file. Sets the
- X/* current file to none if that is the one being deleted.
- X/*
- X/* app_pager() appends a new line of text to the end of a pager file.
- X/* Sets the current file.
- X/*
- X/* del_pager() deletes the line at the current cursor position. Sets the
- X/* current file.
- X/*
- X/* mesg_pager() invokes app_pager() to copy a null-terminated array of
- X/* strings to a pager file. Since it invokes app_pager(), the current
- X/* pager file is set as well. Pager files filled by mesg-pager()
- X/* will not be displayed with an '-- end of display --' line at their end.
- X/*
- X/* ins_pager() inserts a line at the current cursor position. Sets the
- X/* current file.
- X/*
- X/* scan_pager() takes similar arguments as scanf(3), reads from the
- X/* line at the current cursor position and returns the number of
- X/* successfull conversions done. Does not set the current file.
- X/*
- X/* sort_pager() sorts a file alphabetically. Sets the current file.
- X/* The dir argument selects the direction of sort (FORW_SORT, BACK_SORT).
- X/*
- X/* set_pager() sets the current file.
- X/*
- X/* gets_pager() returns a pointer to the current line in the
- X/* current file, or a null pointer is there is none.
- X/*
- X/* puts_pager() replaces the current line in the current file.
- X/*
- X/* cp_pager() copies the contents of current pager file
- X/* to a normal (external) file. It returns a nonzero status if
- X/* an error occurred (bad path, write error,...).
- X/*
- X/* pr_pager() copies the current pager file to the printer.
- X/*
- X/* rd_pager() appends a permanent file to the current pager file.
- X/* It returns a nonzero status if an error occurred. Sets the current file.
- X/* rd_pager() reads through the ascf(3) ascii filter, so that it is
- X/* suitable for viewing word-processor files.
- X/*
- X/* up_pager() moves the cursor one line up, if there is one. The
- X/* screen is scrolled when the cursor was at the top of the screen.
- X/*
- X/* dn_pager moves the cursor one line down, if there is one. The
- X/* screen is scrolled when the cursor was at the bottom of the screen.
- X/*
- X/* pu_pager() displays a page of text that precedes the one on the
- X/* screen, or as much as there is.
- X/*
- X/* pd_pager() displays the next page of text, or as much as there is.
- X/* FUNCTIONS AND MACROS
- X/* printcl(), printat(), beep(), propen(), prclose(),ascopen(),
- X/* ascclose(), ascget()
- X/* SEE ALSO
- X/* path(3), window(3), window(5), asc(3)
- X/* DIAGNOSTICS
- X/* The buzzer makes noise when attempt is made to move the
- X/* cursor beyond the beginning or end of the pager file.
- X/* The program aborts with an error message if references are made
- X/* to the "current file" or "current line" if there is none.
- X/* BUGS
- X/* It looks a lot like an editor, but it isn't.
- X/*
- X/* No optimization. It just overwrites the whole middle window.
- X/* AUTHOR(S)
- X/* W.Z. Venema
- X/* Eindhoven University of Technology
- X/* Department of Mathematics and Computer Science
- X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
- X/* CREATION DATE
- X/* Fri Apr 3 22:06:00 GMT+1:00 1987
- X/* LAST MODIFICATION
- X/* 90/01/22 13:02:21
- X/* VERSION/RELEASE
- X/* 2.1
- X/*--*/
- X
- X#include <stdio.h>
- X
- X#include "defs.h"
- X#include "window.h"
- X#include "pager.h"
- X#include "path.h"
- X#include "ascf.h"
- X
- Xhidden File *curfile = NULL; /* head of the current file */
- X
- X/* open_pager - create pager file and set current file */
- X
- Xpublic File *open_pager()
- X{
- X register File *p = curfile = (File *) myalloc(sizeof(File));
- X
- X p->top = p->curr = p->head = p->last = NULL;
- X p->opts = 0;
- X return (p);
- X}
- X
- X/* close_pager - release memory in a pager file */
- X
- Xpublic void close_pager(p)
- Xregister File *p;
- X{
- X register Line *q;
- X
- X if (p) {
- X for (q = p->head; q; q = q->next) /* release lines */
- X free((char *) q);
- X if (curfile == p) /* unset current file */
- X curfile = 0;
- X free((char *) p); /* release header */
- X }
- X}
- X
- X/* app_pager - append line at end of file and set current file */
- X
- Xpublic app_pager(p, s)
- Xregister File *p;
- Xchar *s;
- X{
- X register Line *l = (Line *) myalloc(sizeof(Line) + strlen(s));
- X
- X if (p->head == 0) { /* first line in the file */
- X p->head = p->top = p->curr = l;
- X } else { /* real append */
- X p->last->next = l;
- X }
- X l->next = NULL; /* since it is last */
- X l->prev = p->last; /* since it is last */
- X p->last = l; /* since it is last */
- X
- X strcpy(l->line, s); /* copy the line */
- X
- X curfile = p; /* set current file */
- X}
- X
- X/* del_pager - delete line at cursor and set current file (untested!) */
- X
- Xpublic void del_pager(p)
- Xregister File *p;
- X{
- X register Line *l = p->curr;
- X
- X if (l) {
- X if (l->prev)
- X l->prev->next = l->next;
- X if (l->next)
- X l->next->prev = l->prev;
- X if (l == p->head)
- X p->curr = p->head = l->next;
- X if (l == p->top)
- X p->curr = p->top = l->next ? l->next : l->prev;
- X if (l == p->last)
- X p->curr = p->last = l->prev;
- X if (l == p->curr)
- X p->curr = l->next;
- X free((char *) l);
- X }
- X curfile = p;
- X}
- X
- X/* set_pager - set the current file; use with care */
- X
- Xpublic void set_pager(p)
- XFile *p;
- X{
- X curfile = p;
- X}
- X
- X /*
- X * The following functions provide an easy interface to the keyboard
- X * interpreter routines. The keyboard interpreter just associates a key
- X * stroke with a function call, does not care what a function does and has
- X * almost no facility for passing function arguments. Although the keyboard
- X * interpreter manipulates cursor and page coordinates when the some keys
- X * are hit, it never knows which keys affect what the user sees on the
- X * screen. That explains why the following functions rely on the above ones
- X * for setting the "current file". It may also explain why the above
- X * routines do not immediately update the terminal screen, whereas the
- X * routines below do.
- X */
- X
- X/* ds_pager - display a page of the current pager file */
- X
- Xpublic int ds_pager()
- X{
- X static char endline[] = "-- end of display --";
- X
- X if (curfile && curfile->curr) {
- X register Line *p;
- X register int k;
- X
- X for (p = curfile->top, k = 0; p && k < midwin->size; p = p->next)
- X k += p->llen = printcl(midwin, p->lineno = k, p->line);
- X if (k < midwin->size)
- X printcl(midwin, k++, (curfile->opts & PG_NOEND) ? "" : endline);
- X while (k < midwin->size)
- X printcl(midwin, k++, "");
- X printat(midwin, curfile->curr->lineno, "");
- X } else {
- X register int k;
- X
- X printcl(midwin, 0, (curfile->opts & PG_NOEND) ? "" : endline);
- X for (k = 1; k < midwin->size; k++)
- X printcl(midwin, k, "");
- X printat(midwin, 0, "");
- X }
- X return (0); /* screen up-to-date */
- X}
- X
- X/* up_pager - up-arrow key hit. check cursor position */
- X
- Xpublic int up_pager()
- X{
- X register Line *p = curfile ? curfile->curr : 0;
- X
- X if (p == 0 || p->prev == 0) {
- X beep();
- X } else {
- X if (p->lineno == 0)
- X pu_pager();
- X printat(midwin, (curfile->curr = p->prev)->lineno, "");
- X }
- X return (0);
- X}
- X
- X/* dn_pager - down-arrow key hit. check cursor position */
- X
- Xpublic int dn_pager()
- X{
- X register Line *p = curfile ? curfile->curr : 0;
- X
- X if (p == 0 || p->next == 0) {
- X beep();
- X } else {
- X if (p->lineno + p->llen >= midwin->size)
- X pd_pager();
- X printat(midwin, (curfile->curr = p->next)->lineno, "");
- X }
- X return (0);
- X}
- X
- X/* pu_pager - display preceding page of info */
- X
- Xpublic int pu_pager()
- X{
- X register Line *p;
- X register int k;
- X
- X if (curfile && (p = curfile->top) && curfile->top->prev) {
- X for (k = 0; k < midwin->size && p; k += p->llen, p = p->prev)
- X curfile->top = p;
- X curfile->curr = curfile->top;
- X ds_pager();
- X } else {
- X beep();
- X }
- X return (0);
- X}
- X
- X/* pd_pager - display next page of info */
- X
- Xpublic int pd_pager()
- X{
- X register Line *p = curfile ? curfile->top : 0;
- X register int k;
- X register Line *dummy;
- X
- X for (k = 0; k < midwin->size && p; k += p->llen, p = p->next)
- X dummy = p;
- X if (p) {
- X curfile->curr = curfile->top = dummy;
- X ds_pager();
- X } else {
- X beep();
- X }
- X return (0);
- X}
- X
- X /*
- X * The following functions copy external files to pager file and vice-versa.
- X * There is a limited error detection facility in the form of nonzero return
- X * values.
- X */
- X
- X/* cp_pager - copy current pager file to permanent file */
- X
- Xpublic int cp_pager(path)
- Xchar *path;
- X{
- X register FILE *fp;
- X
- X if (curfile && (fp = fopen(path, "w"))) {
- X register Line *pp;
- X int err;
- X
- X for (pp = curfile->head; pp; pp = pp->next)
- X fputs(pp->line, fp), putc('\n', fp);
- X err = (fflush(fp) || ferror(fp));
- X fclose(fp);
- X return (err);
- X } else {
- X return (-1);
- X }
- X}
- X
- X/* pr_pager - print pager file on default printer */
- X
- Xpublic int pr_pager()
- X{
- X register FILE *fp;
- X
- X if (curfile && (fp = propen())) {
- X register Line *pp;
- X int err;
- X
- X for (pp = curfile->head; pp; pp = pp->next)
- X fputs(pp->line, fp), putc('\n', fp);
- X err = (fflush(fp) || ferror(fp));
- X prclose(fp);
- X return (err);
- X } else {
- X return (-1);
- X }
- X}
- X
- X/* rd_pager - copy ordinary file via filter to pager file */
- X
- Xpublic int rd_pager(p, path)
- XFile *p;
- Xchar *path;
- X{
- X register FILE *fp;
- X
- X if (p && (fp = ascopen(path, "r"))) { /* init the filter */
- X char buf[BUFSIZ];
- X int err;
- X
- X while (ascgets(buf, sizeof(buf), fp)) /* copy to pager file */
- X app_pager(p, buf); /* line by line */
- X
- X err = ferror(fp); /* check for errors */
- X ascclose(fp);
- X return (err);
- X } else {
- X return (-1);
- X }
- X}
- X
- X/* fwdcmp, revcmp - compare lexical order of lines */
- X
- Xhidden int fwdcmp(l1, l2)
- XLine **l1,
- X **l2;
- X{
- X return (strcmp((*l1)->line, (*l2)->line));
- X}
- X
- Xhidden int revcmp(l1, l2)
- XLine **l1,
- X **l2;
- X{
- X return (strcmp((*l2)->line, (*l1)->line));
- X}
- X
- X/* sort_pager - sort a pager file */
- X
- Xpublic void sort_pager(pp, dir)
- XFile *pp;
- Xint dir;
- X{
- X register Line *l;
- X register int i;
- X int lines;
- X Line **lvec;
- X
- X /* Build a vector with pointers to line structures. */
- X
- X for (i = 0, l = pp->head; l; l = l->next) /* count nbr of lines */
- X i++;
- X if (i <= 1) /* no work */
- X return;
- X
- X lvec = (Line **) myalloc((lines = i) * sizeof(*lvec));
- X
- X for (i = 0, l = pp->head; l; l = l->next) /* fill vector */
- X lvec[i++] = l;
- X
- X /* Sort the vector with pointers to line structures. */
- X
- X qsort((char *) lvec, lines, sizeof(*lvec),
- X dir == FORW_SORT ? fwdcmp : revcmp);
- X
- X /* Restore links between line structures and destroy the sorted vector */
- X
- X for (i = 0; i < lines - 1; i++) /* fix forward links */
- X lvec[i]->next = lvec[i + 1];
- X lvec[i]->next = NULL;
- X
- X lvec[0]->prev = NULL; /* fix backward links */
- X for (i = 1; i < lines; i++)
- X lvec[i]->prev = lvec[i - 1];
- X
- X pp->head = pp->top = pp->curr = lvec[0]; /* fix file header */
- X pp->last = lvec[lines - 1];
- X
- X free((char *) lvec); /* release vector */
- X
- X curfile = pp; /* set current file */
- X}
- X
- X/* gets_pager - return current line in current file */
- X
- Xpublic char *gets_pager()
- X{
- X return (curfile && curfile->curr ? curfile->curr->line : 0);
- X}
- X
- X/* puts_pager - replace line (cleanup this mess) */
- X
- Xpublic void puts_pager(s)
- Xchar *s;
- X{
- X if (curfile == 0 || curfile->curr == 0) { /* no-no if there is no line */
- X fatal("puts_pager: no current file");
- X } else {
- X register Line *old = curfile->curr; /* get current line */
- X register Line *new = (Line *) myalloc(sizeof(Line) + strlen(s));
- X
- X new->prev = old->prev; /* fill it in */
- X new->next = old->next;
- X new->lineno = old->lineno;
- X strcpy(new->line, s);
- X if (new->next) /* check next line */
- X new->next->prev = new;
- X if (new->prev) /* check previous line */
- X new->prev->next = new;
- X if (old == curfile->head) /* check file head */
- X curfile->head = new;
- X if (old == curfile->top) /* check file display */
- X curfile->top = new;
- X if (old == curfile->last) /* check file tail */
- X curfile->last = new;
- X free((char *) curfile->curr); /* release old line */
- X curfile->curr = new; /* set current line */
- X }
- X}
- X
- X/* mesg_pager - copy null-terminated array of strings to pager file */
- X
- Xpublic void mesg_pager(pp, msg)
- Xregister File *pp;
- Xregister char **msg;
- X{
- X pp->opts |= PG_NOEND; /* suppress end marker */
- X
- X while (*msg)
- X app_pager(pp, *msg++);
- X}
- END_OF_main/pager.c
- if test 13541 -ne `wc -c <main/pager.c`; then
- echo shar: \"main/pager.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- echo shar: End of archive 9 \(of 11\).
- cp /dev/null ark9isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 11 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
-