home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume10
/
pcmail2
/
part09
< prev
next >
Wrap
Text File
|
1990-01-24
|
48KB
|
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