1492 lines
40 KiB
Groff
1492 lines
40 KiB
Groff
Path: tut!sunic!mcsun!uunet!munnari.oz.au!basser!ultima!nick
|
||
From: nick@ultima.cs.uts.oz (Nick Andrew)
|
||
Newsgroups: comp.os.minix
|
||
Subject: Vn for Minix, part 1 of 4
|
||
Keywords: vn news usenet
|
||
Message-ID: <16666@ultima.cs.uts.oz>
|
||
Date: 26 Nov 89 11:27:59 GMT
|
||
Organization: Comp Sci, NSWIT, Australia
|
||
Lines: 1481
|
||
|
||
|
||
Since I've been using this Vn under Minix for over 6 months without
|
||
problems, I thought it was time to post it to the net. This is the 4/88
|
||
version of Vn, as modified for Minix.
|
||
|
||
Share and Enjoy ... Nick.
|
||
|
||
|
||
"Zeta Microcomputer Software"
|
||
ACSnet: nick@ultima.cs.uts.oz
|
||
UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick
|
||
Fidonet: Nick Andrew on 3:713/602 (Zeta)
|
||
|
||
#! /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 shell archive."
|
||
# Contents: brk.h config.h config_std.h digest.c envir_set.c getch.c
|
||
# hash.c head.h help.c makefile
|
||
# Wrapped by nick@ultima on Sun Nov 26 22:15:38 1989
|
||
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
|
||
if test -f 'brk.h' -a "${1}" != "-c" ; then
|
||
echo shar: Will not clobber existing file \"'brk.h'\"
|
||
else
|
||
echo shar: Extracting \"'brk.h'\" \(750 characters\)
|
||
sed "s/^X//" >'brk.h' <<'END_OF_FILE'
|
||
X/*
|
||
X** vn news reader.
|
||
X**
|
||
X** brk.h - codes for sig_set routine
|
||
X**
|
||
X** see copyright disclaimer / history in vn.c source file
|
||
X*/
|
||
X
|
||
X/*
|
||
X state flags for handling breaks / values for sig_set calls.
|
||
X BRK_IN, BRK_SESS, BRK_READ and BRK_OUT are the states. All
|
||
X but BRK_INIT are used as calls to sig_set. BRK_RFIN indicates
|
||
X a return from BRK_READ to BRK_SESS (no jump location passed),
|
||
X*/
|
||
X#define BRK_INIT 0 /* initial value, indicating uncaught signals */
|
||
X#define BRK_IN 1 /* in NEWSRC / article scanning phase */
|
||
X#define BRK_SESS 2 /* in page interactive session */
|
||
X#define BRK_READ 3 /* reading articles */
|
||
X#define BRK_RFIN 4 /* finished reading, return to old mode */
|
||
X#define BRK_OUT 5 /* NEWSRC updating phase */
|
||
X
|
||
X#define BRK_PR "really quit ? "
|
||
END_OF_FILE
|
||
if test 750 -ne `wc -c <'brk.h'`; then
|
||
echo shar: \"'brk.h'\" unpacked with wrong size!
|
||
fi
|
||
# end of 'brk.h'
|
||
fi
|
||
if test -f 'config.h' -a "${1}" != "-c" ; then
|
||
echo shar: Will not clobber existing file \"'config.h'\"
|
||
else
|
||
echo shar: Extracting \"'config.h'\" \(4479 characters\)
|
||
sed "s/^X//" >'config.h' <<'END_OF_FILE'
|
||
X/*
|
||
X** vn news reader.
|
||
X**
|
||
X** config.h - system configuration parameters
|
||
X**
|
||
X** see copyright disclaimer / history in vn.c source file
|
||
X*/
|
||
X
|
||
X#define DEF_ED "/bin/mined" /* editor to use if no EDITOR variable */
|
||
X#define DEF_PS1 "$ " /* ! command prompt if no PS1 */
|
||
X#define DEF_SAVE "" /* save file */
|
||
X
|
||
X#define DEF_PRINT "/usr/bin/lpr" /* print command */
|
||
X
|
||
X#define DEF_CCFILE "author_copy"
|
||
X#define DEF_KEYXLN ".vnkey"
|
||
X
|
||
X/*
|
||
X** this is the "pre-typed" string the user will be presented with
|
||
X** in answer to the "update" question following the QUIT command.
|
||
X** Set to "" if you don't like it answering "yes" for you, or "y"
|
||
X** if you only want to have to erase one character to say "no", etc.
|
||
X*/
|
||
X#define QUIT_ANSWER ""
|
||
X
|
||
X/*
|
||
X** default terminal assumed if TERM variable is unset. Since TERM has to
|
||
X** be set for most UNIX tools, you probably want to make this something
|
||
X** which will cause failure, unless EVERYBODY has the same kind of terminal
|
||
X** or you don't really use a standard UNIX environment.
|
||
X*/
|
||
X#define DEF_TERM "minix"
|
||
X
|
||
X/*
|
||
X** foreground flag for messages. applies only if JOBCONTROL undefined
|
||
X** (SYS V). set to 1 to see newsgroup messages, etc. during reading phase,
|
||
X** 0 for "silent" operation - be warned that this may suppress some
|
||
X** non-fatal diagnostic messages - find all references to fgprintf to
|
||
X** see what is suppressed.
|
||
X*/
|
||
X#define NOJOB_FG 1
|
||
X
|
||
X/*
|
||
X** bit mask for interpreting command characters. Set it to 0xff, and
|
||
X** we should be able to handle 8 bit characters for control keys -
|
||
X** leaving it 0x7f protects against possible parity bits in ascii
|
||
X** characters. A lot of the general paranoia about character handling
|
||
X** in raw mode comes from one of the earliest versions which was
|
||
X** run on an amdahl using an IBM series 1 front end - it had a very
|
||
X** brain damaged implementation of ioctl().
|
||
X*/
|
||
X#define CHMASK 0x7f
|
||
X
|
||
X/*
|
||
X** arrow key treatment. If PAGEARROW is defined, right and left arrow
|
||
X** keys will be synonyms for <return> (next-page) and <backspace> (previous).
|
||
X** Otherwise, the right arrow will function as down, and the left as up.
|
||
X** Made configurable because while there is no lateral motion on the screen
|
||
X** to associate with the right and left arrows, you might not like them
|
||
X** changing pages on you.
|
||
X*/
|
||
X#define PAGEARROW
|
||
X
|
||
X/*
|
||
X** if USEVS is defined, terminal initialization / exit for vn will include the
|
||
X** "vs"/"ve" pair as well as "ti"/"te". This doesn't matter on a lot of
|
||
X** terminals, but may make vn display behaviour closer to "vi" since vs/ve
|
||
X** is vi's "visual mode" sequence. For instance, I believe the commonly
|
||
X** used definitions for these strings on multi-page concepts allows the
|
||
X** program to run in the first page of the terminal, preserving the more
|
||
X** recent part of your session on exit
|
||
X**
|
||
X** #define USEVS
|
||
X*/
|
||
X
|
||
X/*
|
||
X** temp file name template for mktemp(). Used in tmpnam.c, does not apply
|
||
X** if you use a system library tmpnam(). BE CAREFUL - VNTEMPNAME MUST
|
||
X** contain a string of 6 X's for mktemp() (actually, a place where 6 X's
|
||
X** are intended to go). TMP_XOFFSET absolutely MUST point to the first of
|
||
X** the X's. Yes, writing into a literal string is sloppy. To the best of
|
||
X** my knowledge, tmpnam.c is the only place you'll find vn code doing it.
|
||
X** We make this configurable in case you want temp files somewhere else.
|
||
X*/
|
||
X#define VNTEMPNAME "/usr/tmp/vnXXXXXX"
|
||
X#define TMP_XOFFSET 11
|
||
X
|
||
X/*
|
||
X** VNLOGFILE and VNSTATFILE. If these files EXIST, the corresponding data
|
||
X** collection will be turned on. If they don't it will be turned off.
|
||
X** To turn it back on again, create the files empty. Garbage in VNLOGFILE
|
||
X** won't hurt collection but VNSTATFILE requires very strict syntax, so
|
||
X** make sure its always an empty file or EXACTLY the right syntax. See stat.c
|
||
X**
|
||
X** VNLOGFILE logs user sessions. VNSTATFILE keeps a running breakdown
|
||
X** of newsgroup activity. I add these with some hesitancy, as I find
|
||
X** use of things like this for Gestapo-like purposes repugnant in the
|
||
X** extreme. However, they can also be useful for system tuning purposes
|
||
X** such as verifying what newsgroups are being read, and when load on
|
||
X** the system due to newsreading is occurring.
|
||
X**
|
||
X** If VNLOGFILE and VNSTATFILE are NOT DEFINED, the code for doing logging
|
||
X** and statistical collection will not be compiled in, saving some overhead,
|
||
X** and avoiding calls to system functions like ctime() and time() which may
|
||
X** have system dependent quirks.
|
||
X**
|
||
X*/
|
||
X#define VNLOGFILE "/usr/tmp/vn.log"
|
||
X#define VNSTATFILE "/usr/tmp/vn.stat"
|
||
END_OF_FILE
|
||
if test 4479 -ne `wc -c <'config.h'`; then
|
||
echo shar: \"'config.h'\" unpacked with wrong size!
|
||
fi
|
||
# end of 'config.h'
|
||
fi
|
||
if test -f 'config_std.h' -a "${1}" != "-c" ; then
|
||
echo shar: Will not clobber existing file \"'config_std.h'\"
|
||
else
|
||
echo shar: Extracting \"'config_std.h'\" \(2802 characters\)
|
||
sed "s/^X//" >'config_std.h' <<'END_OF_FILE'
|
||
X/*
|
||
X** default news poster
|
||
X*/
|
||
X#define DEF_POST "/usr/lib/news/inews -h"
|
||
X
|
||
X/*
|
||
X** default user .newsrc file
|
||
X*/
|
||
X#define DEF_NEWSRC ".newsrc"
|
||
X
|
||
X/*
|
||
X** If INLETTER is defined, the address line will be placed into the
|
||
X** file editted by the user, and the mailer is assumed smart enough
|
||
X** to understand about header lines in the file. Otherwise the
|
||
X** address is part of the mailer's command line.
|
||
X**
|
||
X** if MAILSMART is defined, The From: line will be used for mail replies,
|
||
X** or overridden by a "Reply-to:" line if present - "Path:" will be used
|
||
X** as a last resort. If MAILSMART is not defined, "Path:" will simply be
|
||
X** used.
|
||
X**
|
||
X** if MAILCHOOSE is defined, the user is prompted before edit with all
|
||
X** of the address lines to choose from, or to input a new one. MAILCHOOSE
|
||
X** makes MAILSMART irrelevant, but the two are independent of INLETTER.
|
||
X**
|
||
X*/
|
||
X#define MAILSMART
|
||
X#define INLETTER
|
||
X
|
||
X/*
|
||
X** default mail sender. If INLETTER, will be done as
|
||
X** cat <file> | DEF_MAIL, Otherwise, cat <file> | DEF_MAIL <address>
|
||
X** user's MAILER variable will have to conform, too.
|
||
X*/
|
||
X#ifdef INLETTER
|
||
X#define DEF_MAIL "/usr/lib/sendmail -t"
|
||
X#else
|
||
X#define DEF_MAIL "/bin/mail"
|
||
X#endif
|
||
X
|
||
X/* OLDRC defined for an apparently earlier news version which took unnamed
|
||
X** command line options as synonyms for -n, and did not take ranges in
|
||
X** the .newsrc file. Probably useless, but kept in for historical reasons.
|
||
X**
|
||
X**#define OLDRC
|
||
X*/
|
||
X
|
||
X/*
|
||
X** article spool directory
|
||
X*/
|
||
X#define SPOOLDIR "/usr/spool/news"
|
||
X
|
||
X/*
|
||
X** active file
|
||
X*/
|
||
X#define ACTFILE "/usr/lib/news/active"
|
||
X
|
||
X/*
|
||
X** maximum number of option lines in .newsrc
|
||
X*/
|
||
X#define OPTLINES 20
|
||
X
|
||
X/*
|
||
X** maximum number of filter options
|
||
X*/
|
||
X#define NUMFILTER 30
|
||
X
|
||
X/*
|
||
X** maximum number of file lines to search looking for header lines.
|
||
X*/
|
||
X#define HDR_LINES 36
|
||
X
|
||
X/*
|
||
X** When a newsgroup is scanned, we ignore articles less than <high spool> -
|
||
X** MAXARTRANGE. This is intended to prevent ridiculous numbers of article
|
||
X** opening attempts the first time a user reads a new newsgroup which has a
|
||
X** huge difference between the high and low spool numbers, perhaps due to
|
||
X** some articles not getting expired.
|
||
X*/
|
||
X#define MAXARTRANGE 1600 /* about 2 weeks of soc.singles */
|
||
X
|
||
X/*
|
||
X** If we detect that the user has a higher number in .newsrc than the
|
||
X** high article number, obviously the active file is out of synch with the
|
||
X** .newsrc. We set the user's number back to the low article number in
|
||
X** this case, on the theory that it's better to repeat stuff than miss
|
||
X** articles. On such setbacks, we won't backdate the user by more than
|
||
X** SYN_SETBACK articles, preventing floods of articles on large newsgroups
|
||
X** if you don't define SYN_CHECK, the user's number won't be adjusted in
|
||
X** this case, choosing to lose articles rather than show old ones.
|
||
X*/
|
||
X#define SYN_CHECK
|
||
X#define SYN_SETBACK 60
|
||
END_OF_FILE
|
||
if test 2802 -ne `wc -c <'config_std.h'`; then
|
||
echo shar: \"'config_std.h'\" unpacked with wrong size!
|
||
fi
|
||
# end of 'config_std.h'
|
||
fi
|
||
if test -f 'digest.c' -a "${1}" != "-c" ; then
|
||
echo shar: Will not clobber existing file \"'digest.c'\"
|
||
else
|
||
echo shar: Extracting \"'digest.c'\" \(5681 characters\)
|
||
sed "s/^X//" >'digest.c' <<'END_OF_FILE'
|
||
X/*
|
||
X** vn news reader.
|
||
X**
|
||
X** digest.c - digest unpacking routines
|
||
X**
|
||
X** see copyright disclaimer / history in vn.c source file
|
||
X*/
|
||
X
|
||
X#include <stdio.h>
|
||
X#include "config.h"
|
||
X#include "head.h"
|
||
X#include "tune.h"
|
||
X#include "node.h"
|
||
X#include "page.h"
|
||
X
|
||
Xextern int Digest;
|
||
Xextern int L_allow;
|
||
Xextern int C_allow;
|
||
Xextern PAGE Page;
|
||
X
|
||
Xextern FILE *vns_aopen();
|
||
X
|
||
Xstatic char *Ext_pool = NULL;
|
||
Xstatic char *Show[3];
|
||
X
|
||
Xstatic char *Dhead = "Date: ";
|
||
Xstatic char *Fhead = "From: ";
|
||
Xstatic char *Lhead = "Lines: ";
|
||
Xstatic char *Thead = "Subject: ";
|
||
X
|
||
X#define THDLEN 9
|
||
X#define LHDLEN 7
|
||
X#define FHDLEN 6
|
||
X#define DHDLEN 6
|
||
X
|
||
Xdige_page (idx,skip)
|
||
Xint idx;
|
||
X{
|
||
X char name[24];
|
||
X FILE *fp;
|
||
X int i,len,hl;
|
||
X char subj[RECLEN],date[RECLEN],from[RECLEN],junk[RECLEN],*str_store();
|
||
X long pos;
|
||
X ARTHEADER hdr;
|
||
X
|
||
X Digest = Page.b[idx].art_id;
|
||
X
|
||
X if ((fp = vns_aopen(Digest,&hdr)) == NULL)
|
||
X return (-1);
|
||
X
|
||
X subj[0] = date[0] = from[0] = junk[0] = '\0';
|
||
X
|
||
X /* skip over some articles if requested to */
|
||
X for (i=skip; i > 0; --i)
|
||
X {
|
||
X if (dig_advance(fp,from,subj,date,junk,&pos,&hl) < 0)
|
||
X return (-1);
|
||
X }
|
||
X
|
||
X for (i=0; i < L_allow &&
|
||
X (len = dig_advance(fp,from,subj,date,junk,&pos,&hl)) >= 0; ++i)
|
||
X {
|
||
X Page.b[i].art_id = i+1+skip;
|
||
X Page.b[i].art_mark = ' ';
|
||
X subj [C_allow] = '\0';
|
||
X from [C_allow] = '\0';
|
||
X sprintf (name,"%d",len);
|
||
X form_title (date,subj,name,from,100);
|
||
X strcpy (Page.b[i].art_t,date);
|
||
X }
|
||
X
|
||
X vns_aclose (fp);
|
||
X
|
||
X if (i == 0)
|
||
X return (-1);
|
||
X
|
||
X Page.h.artnum = i;
|
||
X return (i);
|
||
X}
|
||
X
|
||
X/*
|
||
X returns name of file containing "article", NULL for failure
|
||
X*/
|
||
Xchar * dige_extract (s,art,hdr,start)
|
||
Xchar *s;
|
||
Xint art;
|
||
XARTHEADER *hdr;
|
||
Xlong *start;
|
||
X{
|
||
X FILE *fout,*fin;
|
||
X long pos;
|
||
X int lines,hl;
|
||
X char subj[RECLEN],date[RECLEN],from[RECLEN],bufr[RECLEN];
|
||
X char extra[RECLEN];
|
||
X char *index();
|
||
X long ftell();
|
||
X char *str_tpool(), *str_tstore();
|
||
X
|
||
X if (Ext_pool != NULL)
|
||
X str_tfree(Ext_pool);
|
||
X Ext_pool = str_tpool(3);
|
||
X
|
||
X if ((fin = vns_aopen(Digest,hdr)) == NULL)
|
||
X return (NULL);
|
||
X
|
||
X for ( ; art > 0; --art)
|
||
X {
|
||
X from[0] = subj[0] = date[0] = '\0';
|
||
X if ((lines = dig_advance(fin,from,subj,date,extra,&pos,&hl)) < 0)
|
||
X {
|
||
X vns_aclose(fin);
|
||
X return (NULL);
|
||
X }
|
||
X }
|
||
X
|
||
X tmpnam(s);
|
||
X
|
||
X if ((fout = fopen(s,"w")) == NULL)
|
||
X {
|
||
X vns_aclose(fin);
|
||
X unlink (s);
|
||
X return (NULL);
|
||
X }
|
||
X
|
||
X fseek(fin,0L,0);
|
||
X
|
||
X hdr->show_num = 0;
|
||
X hdr->show = Show;
|
||
X hdr->lines = lines;
|
||
X hdr->hlines = hl;
|
||
X if (subj[0] != '\0')
|
||
X {
|
||
X sprintf (bufr,"%s%s",Thead,subj);
|
||
X Show[hdr->show_num] = str_tstore(Ext_pool,bufr);
|
||
X ++(hdr->show_num);
|
||
X }
|
||
X if (from[0] != '\0')
|
||
X {
|
||
X sprintf (bufr,"%s%s",Fhead,from);
|
||
X Show[hdr->show_num] = str_tstore(Ext_pool,bufr);
|
||
X ++(hdr->show_num);
|
||
X }
|
||
X if (date[0] != '\0')
|
||
X {
|
||
X sprintf (bufr,"%s%s",Dhead,date);
|
||
X Show[hdr->show_num] = str_tstore(Ext_pool,bufr);
|
||
X ++(hdr->show_num);
|
||
X }
|
||
X
|
||
X while (fgets(bufr,RECLEN-1,fin) != NULL && bufr[0] != '\n')
|
||
X {
|
||
X if (strncmp(bufr,Fhead,FHDLEN) == 0)
|
||
X {
|
||
X fprintf (fout,"%s%s\n",Fhead,from);
|
||
X continue;
|
||
X }
|
||
X if (strncmp(bufr,Thead,THDLEN) == 0)
|
||
X {
|
||
X fprintf (fout,"%s%s\n",Thead,subj);
|
||
X continue;
|
||
X }
|
||
X if (strncmp(bufr,Dhead,DHDLEN) == 0)
|
||
X {
|
||
X fprintf (fout,"%s%s\n",Dhead,date);
|
||
X continue;
|
||
X }
|
||
X /* defer line count header - it comes last */
|
||
X if (strncmp(bufr,Lhead,LHDLEN) == 0)
|
||
X continue;
|
||
X fprintf (fout,"%s",bufr);
|
||
X }
|
||
X
|
||
X /* toss in extra header lines, line count header, extra newline */
|
||
X fprintf (fout,"%s%s%d\n\n",extra,Lhead,lines);
|
||
X *start = ftell(fout);
|
||
X
|
||
X fseek (fin,pos,0);
|
||
X
|
||
X while (fgets(bufr,RECLEN-1,fin) != NULL && strncmp(bufr,"--------",8) != 0)
|
||
X fprintf(fout,"%s",bufr);
|
||
X
|
||
X vns_aclose (fin);
|
||
X fclose (fout);
|
||
X return (s);
|
||
X}
|
||
X
|
||
Xdig_list (s)
|
||
Xchar *s;
|
||
X{
|
||
X char *ptr,*out,*new,ns[L_tmpnam],tmp[RECLEN],*strtok();
|
||
X ARTHEADER hdr;
|
||
X long pos;
|
||
X int i;
|
||
X
|
||
X prinfo ("Extracting articles .....");
|
||
X strcpy (tmp,s);
|
||
X out = s;
|
||
X
|
||
X for (ptr = strtok(tmp," "); ptr != NULL; ptr = strtok(NULL," "))
|
||
X {
|
||
X i = atoi(ptr);
|
||
X if ((new = dige_extract(ns,i,&hdr,&pos)) != NULL)
|
||
X {
|
||
X sprintf (out,"%s ",new);
|
||
X out += strlen(new) + 1;
|
||
X }
|
||
X }
|
||
X
|
||
X *out = '\0';
|
||
X
|
||
X if (*s == '\0')
|
||
X strcpy (s,"NULLDIGEST");
|
||
X}
|
||
X
|
||
Xdig_ulist (s)
|
||
Xchar *s;
|
||
X{
|
||
X char *strtok();
|
||
X for (s = strtok(s," "); s != NULL; s = strtok(NULL," "))
|
||
X unlink (s);
|
||
X}
|
||
X
|
||
X/*
|
||
X returns # lines in article, -1 for failure
|
||
X scans past article, returns position of start.
|
||
X also returns "extra" header lines encountered, WITH newlines.
|
||
X and counts total header lines.
|
||
X*/
|
||
Xstatic dig_advance (fp,from,subj,date,extra,pos,hcount)
|
||
XFILE *fp;
|
||
Xchar *from,*subj,*date,*extra;
|
||
Xlong *pos;
|
||
Xint *hcount;
|
||
X{
|
||
X char buf[RECLEN];
|
||
X char *ptr, *index();
|
||
X int len,state,lcount;
|
||
X
|
||
X *hcount = lcount = state = 0;
|
||
X *extra = '\0';
|
||
X
|
||
X while (fgets(buf,RECLEN-1,fp) != NULL)
|
||
X {
|
||
X buf[(len = strlen(buf) - 1)] = '\0';
|
||
X for (--len ; len >= 0 && buf[len] == ' ' || buf[len] == '\t'; --len)
|
||
X buf[len] = '\0';
|
||
X ++len;
|
||
X
|
||
X switch(state)
|
||
X {
|
||
X case 0:
|
||
X /* skip blank lines before header */
|
||
X if (len == 0)
|
||
X break;
|
||
X state = 1; /* fall through */
|
||
X case 1:
|
||
X ++(*hcount);
|
||
X if (strncmp(buf,Fhead,FHDLEN) == 0)
|
||
X {
|
||
X strcpy (from,buf+FHDLEN);
|
||
X break;
|
||
X }
|
||
X if (strncmp(buf,Thead,THDLEN) == 0)
|
||
X {
|
||
X strcpy (subj,buf+THDLEN);
|
||
X break;
|
||
X }
|
||
X if (strncmp(buf,Dhead,DHDLEN) == 0)
|
||
X {
|
||
X strcpy (date,buf+DHDLEN);
|
||
X break;
|
||
X }
|
||
X /* put wierd header lines in extra */
|
||
X if ((ptr = index(buf,':')) != NULL)
|
||
X {
|
||
X *ptr = '\0';
|
||
X if (index(buf, ' ') == NULL)
|
||
X {
|
||
X *ptr = ':';
|
||
X sprintf(extra,"%s\n",buf);
|
||
X extra += strlen(extra);
|
||
X break;
|
||
X }
|
||
X *ptr = ':';
|
||
X }
|
||
X state = 2;
|
||
X --(*hcount);
|
||
X
|
||
X /* remember the newline we lopped off */
|
||
X *pos = ftell(fp)-strlen(buf)-1; /* fall through */
|
||
X case 2:
|
||
X ++lcount;
|
||
X if (strncmp("--------",buf,8) == 0)
|
||
X {
|
||
X --lcount;
|
||
X return (lcount);
|
||
X }
|
||
X break;
|
||
X }
|
||
X }
|
||
X
|
||
X return (-1);
|
||
X}
|
||
END_OF_FILE
|
||
if test 5681 -ne `wc -c <'digest.c'`; then
|
||
echo shar: \"'digest.c'\" unpacked with wrong size!
|
||
fi
|
||
# end of 'digest.c'
|
||
fi
|
||
if test -f 'envir_set.c' -a "${1}" != "-c" ; then
|
||
echo shar: Will not clobber existing file \"'envir_set.c'\"
|
||
else
|
||
echo shar: Extracting \"'envir_set.c'\" \(2900 characters\)
|
||
sed "s/^X//" >'envir_set.c' <<'END_OF_FILE'
|
||
X/*
|
||
X** vn news reader.
|
||
X**
|
||
X** envir_set.c - routine to obtain pertinent environment variable settings
|
||
X** and set up file / directory names
|
||
X**
|
||
X** see copyright disclaimer / history in vn.c source file
|
||
X*/
|
||
X
|
||
X#include <stdio.h>
|
||
X#include <pwd.h>
|
||
X
|
||
X#ifndef MINIX
|
||
X/* minix does not have this */
|
||
X#include <sys/param.h>
|
||
X#endif
|
||
X
|
||
X#include "tune.h"
|
||
X#include "config.h"
|
||
X#include "vn.h"
|
||
X
|
||
Xextern char *Editor, *Ps1, *Printer;
|
||
Xextern char *Orgdir, *Savedir, *Ccfile; /* path names */
|
||
Xextern char Cxitop[], Cxitor[], Cxrtoi[], Cxptoi[];
|
||
Xextern char *Home;
|
||
Xextern int More;
|
||
X
|
||
X#ifdef SYSV
|
||
Xextern char *getcwd();
|
||
X#define getwd(a) getcwd(a,sizeof(a))
|
||
X#define MAXPATHLEN 240
|
||
X#else
|
||
Xextern char *getwd();
|
||
X#endif
|
||
X
|
||
X/*
|
||
X environment variable, original directory string setup.
|
||
X*/
|
||
X
|
||
Xenvir_set ()
|
||
X{
|
||
X char dbuf [MAXPATHLEN], *ccname, *keyxln;
|
||
X char *vn_env(), *getcwd(), *str_store();
|
||
X struct passwd *ptr, *getpwuid();
|
||
X
|
||
X vns_envir();
|
||
X More = 0;
|
||
X
|
||
X Ps1 = vn_env("PS1",DEF_PS1);
|
||
X Editor = vn_env("EDITOR",DEF_ED);
|
||
X Printer = vn_env("PRINTER",DEF_PRINT);
|
||
X ccname = vn_env("CCFILE",DEF_CCFILE);
|
||
X keyxln = vn_env("VNKEY",DEF_KEYXLN);
|
||
X Savedir = vn_env("VNSAVE",NULL);
|
||
X More = (strcmp(vn_env("MORE",""), "-c") == 0 ? TRUE : FALSE);
|
||
X
|
||
X /*
|
||
X set original directory strings.
|
||
X */
|
||
X
|
||
X if ((ptr = getpwuid(getuid())) == NULL)
|
||
X printex("Cannot obtain /etc/passwd entry");
|
||
X Home = str_store(ptr->pw_dir);
|
||
X if ((Orgdir = getwd(dbuf)) == NULL)
|
||
X printex ("cannot stat pwd");
|
||
X Orgdir = str_store (Orgdir);
|
||
X if (Savedir == NULL)
|
||
X Savedir = Orgdir;
|
||
X if (*ccname != '/')
|
||
X {
|
||
X sprintf (dbuf, "%s/%s",Home,ccname);
|
||
X Ccfile = str_store (dbuf);
|
||
X }
|
||
X else
|
||
X Ccfile = str_store (ccname);
|
||
X sprintf (dbuf, "%s/%s%s",Home,".vn","XXXXXX");
|
||
X
|
||
X if (*keyxln != '/')
|
||
X {
|
||
X sprintf(dbuf, "%s/%s",Home,keyxln);
|
||
X set_kxln(dbuf);
|
||
X }
|
||
X else
|
||
X set_kxln(keyxln);
|
||
X}
|
||
X
|
||
Xchar *
|
||
Xvn_env(var,def)
|
||
Xchar *var;
|
||
Xchar *def;
|
||
X{
|
||
X char pfx[RECLEN];
|
||
X char *res;
|
||
X char *getenv();
|
||
X
|
||
X if (var[0] != 'V' || var[1] != 'N')
|
||
X {
|
||
X sprintf(pfx,"VN%s",var);
|
||
X if ((res = getenv(pfx)) != NULL)
|
||
X return(res);
|
||
X }
|
||
X
|
||
X if ((res = getenv(var)) != NULL)
|
||
X return(res);
|
||
X
|
||
X return(def);
|
||
X}
|
||
X
|
||
Xstatic
|
||
Xset_kxln(fname)
|
||
Xchar *fname;
|
||
X{
|
||
X FILE *fp;
|
||
X int i;
|
||
X char bufr[80];
|
||
X char in,out,*ptr;
|
||
X char *index(), xln_str();
|
||
X
|
||
X for (i=0; i < CHMASK+1; ++i)
|
||
X Cxitop[i] = Cxitor[i] = Cxptoi[i] = Cxrtoi[i] = i;
|
||
X
|
||
X if ((fp = fopen(fname,"r")) != NULL)
|
||
X {
|
||
X while(fgets(bufr,79,fp) != NULL)
|
||
X {
|
||
X if (strncmp(bufr+1,"==",2) == 0)
|
||
X ptr = bufr+2;
|
||
X else
|
||
X ptr = index(bufr+1,'=');
|
||
X if (ptr == NULL)
|
||
X continue;
|
||
X *ptr = '\0';
|
||
X ++ptr;
|
||
X in = xln_str(bufr+1);
|
||
X out = xln_str(ptr);
|
||
X switch(bufr[0])
|
||
X {
|
||
X case 'r':
|
||
X case 'R':
|
||
X Cxrtoi[out] = in;
|
||
X Cxitor[in] = out;
|
||
X break;
|
||
X case 'p':
|
||
X case 'P':
|
||
X Cxptoi[out] = in;
|
||
X Cxitop[in] = out;
|
||
X default:
|
||
X break;
|
||
X }
|
||
X }
|
||
X fclose(fp);
|
||
X }
|
||
X}
|
||
X
|
||
Xstatic char
|
||
Xxln_str(s)
|
||
Xchar *s;
|
||
X{
|
||
X if (*s < '0' || *s > '9')
|
||
X return(*s & CHMASK);
|
||
X return((char)(atoi(s) & CHMASK));
|
||
X}
|
||
END_OF_FILE
|
||
if test 2900 -ne `wc -c <'envir_set.c'`; then
|
||
echo shar: \"'envir_set.c'\" unpacked with wrong size!
|
||
fi
|
||
# end of 'envir_set.c'
|
||
fi
|
||
if test -f 'getch.c' -a "${1}" != "-c" ; then
|
||
echo shar: Will not clobber existing file \"'getch.c'\"
|
||
else
|
||
echo shar: Extracting \"'getch.c'\" \(2004 characters\)
|
||
sed "s/^X//" >'getch.c' <<'END_OF_FILE'
|
||
X/*
|
||
X** vn news reader.
|
||
X**
|
||
X** getch.c - character i/o routines
|
||
X**
|
||
X** see copyright disclaimer / history in vn.c source file
|
||
X*/
|
||
X#include <stdio.h>
|
||
X#include <setjmp.h>
|
||
X#include <ctype.h>
|
||
X#include "config.h"
|
||
X#include "vn.h"
|
||
X
|
||
Xextern char Cxitop[];
|
||
Xextern char *Ku, *Kd, *Kr, *Kl;
|
||
X
|
||
X/*
|
||
X getkey obtains user keystroke with count from leading
|
||
X numerics, if any. Picks up arrow key sequences and maps
|
||
X them to other keys. Also translates character through
|
||
X Cxitop array since this routine is only used in session
|
||
X loop. Saves untranslating arrow keys.
|
||
X*/
|
||
Xgetkey (c)
|
||
Xchar *c;
|
||
X{
|
||
X int i, j;
|
||
X static char ckseq[32];
|
||
X
|
||
X#ifdef MINIX
|
||
X fflush(stdout);
|
||
X#endif
|
||
X
|
||
X /* Check for leading count */
|
||
X for (i = 0; isdigit(*c = getc(stdin) & CHMASK); i = i * 10 + *c - '0')
|
||
X ;
|
||
X
|
||
X /* @#$!!! flakey front ends that won't map newlines in raw mode */
|
||
X if (*c == '\012' || *c == '\015')
|
||
X *c = '\n';
|
||
X
|
||
X /* @#$!!! flakey terminals which send control sequences for cursors! */
|
||
X if( *c == '\033' )
|
||
X {
|
||
X /*
|
||
X ** Check if part of cursor key input sequence
|
||
X ** (pitch unknown escape sequences)
|
||
X */
|
||
X j = 0;
|
||
X ckseq[j] = *c; ckseq[j+1] = '\0';
|
||
X while(*c == Ku[j] || *c == Kd[j] || *c == Kl[j] || *c == Kr[j])
|
||
X {
|
||
X if( strcmp(ckseq, Ku) == 0 ) { *c = UP; break; }
|
||
X if( strcmp(ckseq, Kd) == 0 ) { *c = DOWN; break; }
|
||
X#ifdef PAGEARROW
|
||
X if( strcmp(ckseq, Kl) == 0 ) { *c = BACK; break; }
|
||
X if( strcmp(ckseq, Kr) == 0 ) { *c = FORWARD; break; }
|
||
X#else
|
||
X if( strcmp(ckseq, Kl) == 0 ) { *c = UP; break; }
|
||
X if( strcmp(ckseq, Kr) == 0 ) { *c = DOWN; break; }
|
||
X#endif
|
||
X *c = (getc(stdin) & CHMASK);
|
||
X ckseq[++j] = *c; ckseq[j+1] = '\0';
|
||
X }
|
||
X }
|
||
X else
|
||
X *c = Cxitop[*c];
|
||
X
|
||
X if (i <= 0)
|
||
X i = 1;
|
||
X return (i);
|
||
X}
|
||
X
|
||
X/*
|
||
X get user key ignoring most controls. Used from reader and other
|
||
X non-screen interactions.
|
||
X*/
|
||
Xgetnoctl ()
|
||
X{
|
||
X char c;
|
||
X
|
||
X#ifdef MINIX
|
||
X fflush(stdout);
|
||
X#endif
|
||
X while (iscntrl(c = getc(stdin) & CHMASK))
|
||
X {
|
||
X if (c == '\015' || c == '\012')
|
||
X c = '\n';
|
||
X if (c == '\n' || c == '\b' || c == '\t')
|
||
X return (c);
|
||
X }
|
||
X return ((int) c);
|
||
X}
|
||
END_OF_FILE
|
||
if test 2004 -ne `wc -c <'getch.c'`; then
|
||
echo shar: \"'getch.c'\" unpacked with wrong size!
|
||
fi
|
||
# end of 'getch.c'
|
||
fi
|
||
if test -f 'hash.c' -a "${1}" != "-c" ; then
|
||
echo shar: Will not clobber existing file \"'hash.c'\"
|
||
else
|
||
echo shar: Extracting \"'hash.c'\" \(1874 characters\)
|
||
sed "s/^X//" >'hash.c' <<'END_OF_FILE'
|
||
X/*
|
||
X** vn news reader.
|
||
X**
|
||
X** hash.c - hash table routines
|
||
X**
|
||
X** see copyright disclaimer / history in vn.c source file
|
||
X*/
|
||
X
|
||
X#include <stdio.h>
|
||
X#include "config.h"
|
||
X#include "tune.h"
|
||
X#include "node.h"
|
||
X
|
||
X/*
|
||
X** hash table manipulation routines:
|
||
X*/
|
||
X
|
||
Xextern int Ncount;
|
||
Xextern NODE **Newsorder;
|
||
X
|
||
Xstatic NODE *Tab [HASHSIZE]; /* hash Table */
|
||
X
|
||
Xhashinit ()
|
||
X{
|
||
X int i;
|
||
X for (i=0; i < HASHSIZE; ++i)
|
||
X Tab[i] = NULL;
|
||
X Ncount = 0;
|
||
X}
|
||
X
|
||
X/*
|
||
X enter new node (name s, articles n, low l) in hash Table,
|
||
X initial flags = 0. Set order to -1.
|
||
X*/
|
||
XNODE *hashenter(s,n,l)
|
||
Xchar *s;
|
||
Xint n;
|
||
Xint l;
|
||
X{
|
||
X char *str_store();
|
||
X NODE *ptr,*node_store();
|
||
X NODE *hashfind();
|
||
X int i;
|
||
X
|
||
X if ((ptr = hashfind(s)) != NULL)
|
||
X {
|
||
X fgprintf ("Warning: group %s encountered twice",s);
|
||
X return (ptr);
|
||
X }
|
||
X
|
||
X i=hash(s);
|
||
X ptr = node_store();
|
||
X ptr->next = Tab[i];
|
||
X Tab[i] = ptr;
|
||
X if (l > n)
|
||
X l = n;
|
||
X ++Ncount;
|
||
X ptr->lownum = l;
|
||
X ptr->state = 0;
|
||
X ptr->data = NULL;
|
||
X ptr->flags = 0;
|
||
X ptr->highnum = n;
|
||
X ptr->nd_name = str_store(s);
|
||
X ptr->pgshwn = 0;
|
||
X ptr->order = -1;
|
||
X return (ptr);
|
||
X}
|
||
X
|
||
XNODE *hashfind(s)
|
||
Xchar *s;
|
||
X{
|
||
X NODE *ptr;
|
||
X
|
||
X for (ptr = Tab[hash(s)]; ptr != NULL && strcmp(ptr->nd_name,s) != 0;
|
||
X ptr = ptr->next)
|
||
X ;
|
||
X return (ptr);
|
||
X}
|
||
X
|
||
Xmake_newsorder()
|
||
X{
|
||
X char *malloc();
|
||
X int i;
|
||
X NODE *ptr;
|
||
X
|
||
X if ((Newsorder = (NODE **) malloc(Ncount * sizeof(NODE *))) == NULL)
|
||
X printex("Memory allocation failure - newsorder array");
|
||
X for (i=0; i < Ncount; ++i)
|
||
X Newsorder[i] = NULL;
|
||
X for (i=0; i < HASHSIZE; ++i)
|
||
X {
|
||
X for (ptr = Tab[i]; ptr != NULL; ptr = ptr->next)
|
||
X {
|
||
X if (ptr->order < 0 || ptr->order >= Ncount)
|
||
X printex("News order range error");
|
||
X Newsorder[ptr->order] = ptr;
|
||
X }
|
||
X }
|
||
X for (i=0; i < Ncount; ++i)
|
||
X if (Newsorder[i] == NULL)
|
||
X printex("News order duplication error");
|
||
X}
|
||
X
|
||
Xstatic hash (s)
|
||
Xchar *s;
|
||
X{
|
||
X unsigned rem;
|
||
X for (rem=0; *s != '\0'; ++s)
|
||
X rem = (rem*128 + (*s&0x7f)) % HASHSIZE;
|
||
X return (rem);
|
||
X}
|
||
END_OF_FILE
|
||
if test 1874 -ne `wc -c <'hash.c'`; then
|
||
echo shar: \"'hash.c'\" unpacked with wrong size!
|
||
fi
|
||
# end of 'hash.c'
|
||
fi
|
||
if test -f 'head.h' -a "${1}" != "-c" ; then
|
||
echo shar: Will not clobber existing file \"'head.h'\"
|
||
else
|
||
echo shar: Extracting \"'head.h'\" \(2530 characters\)
|
||
sed "s/^X//" >'head.h' <<'END_OF_FILE'
|
||
X/*
|
||
X** vn news reader.
|
||
X**
|
||
X** head.h - header line structure
|
||
X**
|
||
X** see copyright disclaimer / history in vn.c source file
|
||
X*/
|
||
X
|
||
X/*
|
||
X** How this thing works:
|
||
X**
|
||
X** this structure is filled in by vns_aopen when opening an article.
|
||
X** lines & hlines items will be used in providing percentage read prompts
|
||
X**
|
||
X** show_num & show are the article information lines presented for the user
|
||
X** when the "show headers" flag is turned off.
|
||
X**
|
||
X** from and artid are used for mail salutations, etc.
|
||
X**
|
||
X** The items used for mail replies, FOLLOWING the call to the mail massager
|
||
X** if there is one, are mailcmd, mail_num, and mail. These are the items
|
||
X** the massager should fill in. If no massager exists, vns_aopen will
|
||
X** fill these in directly. If mail_err is non-null, the user won't be
|
||
X** able to mail a reply to the article, and the item should be an error
|
||
X** message explaining why. If there is a mailer function, the mailcmd
|
||
X** item is not used.
|
||
X**
|
||
X** The priv and priv_num items are for sole use of the server layer in
|
||
X** the mail massager, mailer and poster functions.
|
||
X**
|
||
X** The postcmd, post_num, and post arguments are used in treatment of
|
||
X** followups. If post_err is non-null, followup won't be allowed, for
|
||
X** the reason described therein. If there is a poster function, the
|
||
X** postcmd item isn't used.
|
||
X**
|
||
X** The header lines for inclusion in mail / followup files will open
|
||
X** the file, and will be followed by one blank line. The lines are literal -
|
||
X** all appropriate headers should be prepended, etc.
|
||
X**
|
||
X** postcmd / mailcmd are used as format strings which are assumed to have a
|
||
X** single %s in them some place for the placement of the users editted file.
|
||
X** The result will be spawned as a command.
|
||
X*/
|
||
X
|
||
Xtypedef struct
|
||
X{
|
||
X int lines; /* number of lines in article */
|
||
X int hlines; /* number of header lines in article */
|
||
X char *from; /* authors name */
|
||
X char *artid; /* article id */
|
||
X int show_num; /* number of extra lines for reader display */
|
||
X char **show; /* extra header lines */
|
||
X int priv_num; /* number of private arguments */
|
||
X char **priv; /* private server arguments */
|
||
X char *mail_err; /* mail reply error message */
|
||
X char *mailcmd; /* command line for mailer */
|
||
X int mail_num; /* number of header lines in mail reply file */
|
||
X char **mail; /* mail reply header lines */
|
||
X char *post_err; /* follow-up posting error message */
|
||
X char *postcmd; /* command line for followup poster */
|
||
X int post_num; /* number of header lines for followup file */
|
||
X char **post; /* followup header lines */
|
||
X} ARTHEADER;
|
||
END_OF_FILE
|
||
if test 2530 -ne `wc -c <'head.h'`; then
|
||
echo shar: \"'head.h'\" unpacked with wrong size!
|
||
fi
|
||
# end of 'head.h'
|
||
fi
|
||
if test -f 'help.c' -a "${1}" != "-c" ; then
|
||
echo shar: Will not clobber existing file \"'help.c'\"
|
||
else
|
||
echo shar: Extracting \"'help.c'\" \(6850 characters\)
|
||
sed "s/^X//" >'help.c' <<'END_OF_FILE'
|
||
X/*
|
||
X** vn news reader.
|
||
X**
|
||
X** help.c - print help
|
||
X**
|
||
X** see copyright disclaimer / history in vn.c source file
|
||
X*/
|
||
X#include <stdio.h>
|
||
X#include <setjmp.h>
|
||
X#include "config.h"
|
||
X#include "tty.h"
|
||
X#include "tune.h"
|
||
X#include "node.h"
|
||
X#include "page.h"
|
||
X#include "reader.h"
|
||
X#include "vn.h"
|
||
X
|
||
Xextern int L_allow;
|
||
Xextern int C_allow;
|
||
Xextern int Digest;
|
||
Xextern char *Contstr;
|
||
Xextern char Cxptoi[], Cxrtoi[];
|
||
X
|
||
Xextern int (*Hookfunc)();
|
||
Xextern char *(*Hookhelp)();
|
||
X
|
||
X/*
|
||
X Help message table. Character for command, plus its help
|
||
X message. Table order is order of presentation to user.
|
||
X*/
|
||
Xstatic struct HELPTAB
|
||
X{
|
||
X char cmd, *msg;
|
||
X int dig;
|
||
X char *amsg;
|
||
X}
|
||
XHelptab [] =
|
||
X{
|
||
X { QUIT, "quit", 1, NULL},
|
||
X { UP, "(or up arrow) move up [number of lines]", 1, NULL},
|
||
X { DOWN, "(or down arrow) move down [number of lines]", 1, NULL},
|
||
X#ifdef PAGEARROW
|
||
X { BACK, "(or left arrow) previous page [number of pages]", 1, NULL},
|
||
X { FORWARD, "(or right arrow) next page [number of pages]", 1, NULL},
|
||
X#else
|
||
X { BACK, "previous page [number of pages]", 1, NULL},
|
||
X { FORWARD, "next page [number of pages]", 1, NULL},
|
||
X#endif
|
||
X { GRPBACK, "previous newsgroup [number of newsgroups]", 0, NULL },
|
||
X { GRPFORWARD, "next newsgroup [number of newsgroups]", 0, NULL },
|
||
X { TOPMOVE, "move to top of page", 1, NULL},
|
||
X { BOTMOVE, "move to bottom of page", 1, NULL},
|
||
X { ALTBOTTOM, "move to bottom of page (alternate L)", 1, NULL},
|
||
X { MIDMOVE, "move to middle of page", 1, NULL},
|
||
X { DIGEST, "unpack digest", 1, "exit digest"},
|
||
X { READ, "read article [number of articles]", 1, NULL},
|
||
X { ALTREAD, "read article (alternate 'r')", 1, NULL},
|
||
X { READALL, "read all articles on page", 1, NULL},
|
||
X { READSTRING, "specify articles to read", 1, NULL},
|
||
X { SAVE, "save or pipe article [number of articles]", 1, NULL},
|
||
X { SAVEALL, "save or pipe all articles on page", 1, NULL},
|
||
X { SAVESTRING, "specify articles to save", 1, NULL},
|
||
X { ALTSAVE, "specify articles to save (alternate ctl-s)", 1, NULL},
|
||
X { PRINT, "print article [number of articles]", 1, NULL},
|
||
X { PRINTALL, "print all article on page", 1, NULL},
|
||
X { PRINTSTRING, "specify articles to print", 1, NULL},
|
||
X { UPDATE, "update .newsrc status to cursor", 0, NULL},
|
||
X { UPALL, "update .newsrc status for whole newsgroup", 0, NULL},
|
||
X { UPSEEN, "update .newsrc status for all pages displayed", 0, NULL},
|
||
X { ORGGRP, "recover original .newsrc status for newsgroup", 0, NULL},
|
||
X { ORGSTAT, "recover all original .newsrc status", 0, NULL},
|
||
X { SSTAT, "display count of groups and pages - shown and total", 0, NULL},
|
||
X { GRPLIST, "list newsgroups with new article, updated counts", 0, NULL},
|
||
X { NEWGROUP, "specify newsgroup to display and/or resubscribe to", 1, NULL},
|
||
X { UNSUBSCRIBE, "unsubscribe from group", 0, NULL},
|
||
X { MARK, "mark/unmark article [number of articles]", 1, NULL},
|
||
X { ART_MARK, "mark/unmark article [number of articles]", 1, NULL},
|
||
X { UNMARK, "erase marks on articles", 1, NULL},
|
||
X { MARKSTRING, "specify articles to mark/unmark", 1, NULL},
|
||
X { HEADTOG, "toggle flag for display of headers when reading", 1, NULL},
|
||
X { SETROT, "toggle rotation for reading", 1, NULL},
|
||
X { REDRAW, "redraw screen", 1, NULL},
|
||
X { UNESC, "escape to UNIX to execute a command", 1, NULL},
|
||
X { PRTVERSION, "show vn version", 1, NULL},
|
||
X { HELP, "show this help menu", 1, NULL}
|
||
X};
|
||
X
|
||
X#define HTSIZE (sizeof(Helptab)/sizeof(struct HELPTAB))
|
||
X
|
||
X
|
||
X#define HHLINES 5 /* lines (CRs + 1) contained in HELP_HEAD */
|
||
X/*
|
||
X help from main screen
|
||
X*/
|
||
Xhelp ()
|
||
X{
|
||
X int i,lcount,lim;
|
||
X char *hs;
|
||
X char c;
|
||
X
|
||
X term_set (ERASE);
|
||
X lim = L_allow + RECBIAS - 2;
|
||
X printf("%s\n","[...] = effect of optional number preceding command\n");
|
||
X printf("%s\n","pipes are specified by filenames beginning with |\n");
|
||
X printf("%s\n","articles specified as a list of numbers, title search string, or\n");
|
||
X printf("%s\n"," * to specify marked articles. ! may be used to negate any\n");
|
||
X lcount = HHLINES;
|
||
X for (i=0; i < HTSIZE; ++i)
|
||
X {
|
||
X if (Digest && !(Helptab[i].dig))
|
||
X continue;
|
||
X if (Hookfunc != NULL && (*Hookfunc)(Helptab[i].cmd,0,0) >= 0)
|
||
X continue;
|
||
X ++lcount;
|
||
X if (Digest && Helptab[i].amsg != NULL)
|
||
X h_print (Cxptoi[Helptab[i].cmd],Helptab[i].amsg);
|
||
X else
|
||
X h_print (Cxptoi[Helptab[i].cmd],Helptab[i].msg);
|
||
X if (lcount >= lim)
|
||
X {
|
||
X printf ("\n%s",Contstr);
|
||
X getnoctl ();
|
||
X term_set (MOVE,0,lim+1);
|
||
X term_set (ZAP,0,strlen(Contstr));
|
||
X term_set (MOVE,0,lim-1);
|
||
X putchar ('\n');
|
||
X lcount = 0;
|
||
X }
|
||
X }
|
||
X if (Hookhelp != NULL)
|
||
X {
|
||
X for (hs=(*Hookhelp)(0,1,&c);
|
||
X hs != NULL; hs = (*Hookhelp)(0,0,&c))
|
||
X {
|
||
X ++lcount;
|
||
X h_print (Cxptoi[c],hs);
|
||
X if (lcount >= lim)
|
||
X {
|
||
X printf ("\n%s",Contstr);
|
||
X getnoctl ();
|
||
X term_set (MOVE,0,lim+1);
|
||
X term_set (ZAP,0,strlen(Contstr));
|
||
X term_set (MOVE,0,lim-1);
|
||
X putchar ('\n');
|
||
X lcount = 0;
|
||
X }
|
||
X }
|
||
X }
|
||
X if (lcount > 0)
|
||
X {
|
||
X printf ("\n%s",Contstr);
|
||
X getnoctl ();
|
||
X }
|
||
X}
|
||
X
|
||
X/*
|
||
X help from reader
|
||
X*/
|
||
Xhelp_rd()
|
||
X{
|
||
X char *hs;
|
||
X char c;
|
||
X
|
||
X printf("\n"); /* "confused" tab expansion on first line */
|
||
X
|
||
X hr_print (Cxrtoi[PG_NEXT],HPG_NEXT);
|
||
X hr_print (Cxrtoi[PG_QUIT],HPG_QUIT);
|
||
X hr_print (Cxrtoi[PG_FLIP],HPG_FLIP);
|
||
X hr_print (Cxrtoi[PG_REWIND],HPG_REWIND);
|
||
X hr_print (Cxrtoi[PG_WIND],HPG_WIND);
|
||
X hr_print (Cxrtoi[PG_SEARCH],HPG_SEARCH);
|
||
X hr_print (Cxrtoi[PG_STEP],HPG_STEP);
|
||
X hr_print (Cxrtoi[PG_REPLY],HPG_REPLY);
|
||
X hr_print (Cxrtoi[PG_FOLLOW],HPG_FOLLOW);
|
||
X hr_print (Cxrtoi[SAVE],HPG_SAVE);
|
||
X hr_print (Cxrtoi[PRINT],HPG_PRINT);
|
||
X hr_print (Cxrtoi[SETROT],HPG_ROT);
|
||
X hr_print (Cxrtoi[HEADTOG],HPG_HEAD);
|
||
X hr_print (Cxrtoi[PG_HELP],HPG_HELP);
|
||
X if (Hookhelp != NULL)
|
||
X {
|
||
X for (hs=(*Hookhelp)(1,1,&c);
|
||
X hs != NULL; hs = (*Hookhelp)(1,0,&c))
|
||
X h_print (Cxrtoi[c],hs);
|
||
X }
|
||
X printf ("%s\n",HPG_DEF);
|
||
X}
|
||
X
|
||
Xhr_print(c,msg)
|
||
Xchar c;
|
||
Xchar *msg;
|
||
X{
|
||
X if (Hookfunc == NULL || (*Hookfunc)(c,1,0) < 0)
|
||
X h_print(c,msg);
|
||
X}
|
||
X
|
||
Xsrch_help(c,dig)
|
||
Xchar c;
|
||
Xint *dig;
|
||
X{
|
||
X int i;
|
||
X
|
||
X for (i=0; i < HTSIZE; ++i)
|
||
X if (Helptab[i].cmd == c)
|
||
X break;
|
||
X if (i < HTSIZE)
|
||
X {
|
||
X *dig = Helptab[i].dig;
|
||
X return (0);
|
||
X }
|
||
X return(-1);
|
||
X}
|
||
X
|
||
X/*
|
||
X h_print prints a character and a legend for a help menu.
|
||
X*/
|
||
Xstatic
|
||
Xh_print(c,s)
|
||
Xchar c,*s;
|
||
X{
|
||
X if (strlen(s) > (C_allow - 14))
|
||
X s [C_allow - 14] = '\0';
|
||
X if (c > ' ' && c != '\177')
|
||
X printf (" %c - %s\n",c,s);
|
||
X else
|
||
X {
|
||
X switch (c)
|
||
X {
|
||
X case '\177':
|
||
X printf (" <delete> - %s\n",s);
|
||
X break;
|
||
X case '\040':
|
||
X printf (" <space> - %s\n",s);
|
||
X break;
|
||
X case '\033':
|
||
X printf (" <escape> - %s\n",s);
|
||
X break;
|
||
X case '\n':
|
||
X printf (" <return> - %s\n",s);
|
||
X break;
|
||
X case '\t':
|
||
X printf (" <tab> - %s\n",s);
|
||
X break;
|
||
X case '\b':
|
||
X printf (" <back sp> - %s\n",s);
|
||
X break;
|
||
X case '\f':
|
||
X printf ("<formfeed> - %s\n",s);
|
||
X break;
|
||
X case '\07':
|
||
X printf (" <bell> - %s\n",s);
|
||
X break;
|
||
X case '\0':
|
||
X printf (" <null> - %s\n",s);
|
||
X break;
|
||
X default:
|
||
X if (c < '\033')
|
||
X {
|
||
X c += 'a' - 1;
|
||
X printf(" control-%c - %s\n",c,s);
|
||
X }
|
||
X else
|
||
X printf(" %c0%o - %s\n",'\\',(int) c,s);
|
||
X break;
|
||
X }
|
||
X }
|
||
X}
|
||
END_OF_FILE
|
||
if test 6850 -ne `wc -c <'help.c'`; then
|
||
echo shar: \"'help.c'\" unpacked with wrong size!
|
||
fi
|
||
# end of 'help.c'
|
||
fi
|
||
if test -f 'makefile' -a "${1}" != "-c" ; then
|
||
echo shar: Will not clobber existing file \"'makefile'\"
|
||
else
|
||
echo shar: Extracting \"'makefile'\" \(4377 characters\)
|
||
sed "s/^X//" >'makefile' <<'END_OF_FILE'
|
||
X# CFLAGS:
|
||
X# set -DJOBCONTROL if you have job control (BSD).
|
||
X# set -DSYSV -Dindex=strchr -Drindex=strrchr on Sytem V systems
|
||
X# set -Dregfree=free if you DON'T include reg.s (SYSV + some BSD)
|
||
X#
|
||
X# JOBCONTROL could be done as #ifndef SYSV, I suppose, but this clearly
|
||
X# marks that particular difference.
|
||
X#
|
||
X# LIBS:
|
||
X# should point to any extra libraries needed, such as termcap. You
|
||
X# may want to change this to use the curses termcap cover. If you need
|
||
X# to pull in another library to get regex / regcmp or strtok on non-SYSV
|
||
X# systems, you may want to put that here
|
||
X#
|
||
X# EXTRAOBJS:
|
||
X# may be used to include tmpnam.s, strtok.s, reg.s in the list.
|
||
X#
|
||
X# These objects implement SYSV utilities for BSD machines.
|
||
X#
|
||
X# strtok.s implements strtok() / strpbrk(). reg.s implements regex()/regcmp()
|
||
X# on top of the BSD regular expression library (regex() allows multiple
|
||
X# regular expressions). tmpnam.s implements tmpnam() of course.
|
||
X#
|
||
X# If you have them, use your own regex/regcmp, because:
|
||
X#
|
||
X# i) They should be faster than the reg.c code, which
|
||
X# recompiles the "current" ucb string every time you
|
||
X# switch regular expressions.
|
||
X#
|
||
X# ii) I briefly checked out reg.c once, and it seemed to
|
||
X# work. Our system has the "real" calls available, so I
|
||
X# run with those. reg.c hasn't been used much by me, although
|
||
X# I've had nobody tell me it doesn't work.
|
||
X#
|
||
X# if you DON'T include reg.s, be sure you set -Dregfree=free in CFLAGS.
|
||
X#
|
||
X# As with regex, if you have a system strtok(), it is likely more efficient -
|
||
X# string routines will often be done in assembler on a given machine.
|
||
X#
|
||
X# Even if you have it, you can use tmpnam.s anyhow. This version will tailor
|
||
X# the temp file name to vnXXXXXX, instead of a generic tmpXXXXXX.
|
||
X#
|
||
X# "vanilla" BSD:
|
||
X#LIBS = -ltermcap
|
||
X#EXTRAOBJS = tmpnam.s strtok.s reg.s
|
||
X#CFLAGS = -O -DJOBCONTROL
|
||
X#
|
||
X# "vanilla" SYSV:
|
||
X#LIBS = -ltermcap
|
||
X#EXTRAOBJS = tmpnam.s
|
||
X#CFLAGS = -O -DSYSV -Dregfree=free -Dindex=strchr -Drindex=strrchr
|
||
X#
|
||
X# BSD with strtok() / regex(), such as ULTRIX. These are the rules
|
||
X# used for our installation (rtech is a microvax running ULTRIX):
|
||
X#LIBS = -ltermcap
|
||
X#EXTRAOBJS = tmpnam.s
|
||
X#CFLAGS = -O -DJOBCONTROL -Dregfree=free
|
||
X
|
||
X#
|
||
X# Minix!!!
|
||
X# Regular expressions: Use reg.c to turn regcmp into re_comp
|
||
X# and regex into re_exec. Use regcompat.c to turn re_comp into
|
||
X# regcomp and re_exec into regexec. Wow! What a load of old
|
||
X# cobblers.
|
||
XLIBS =
|
||
X#EXTRAOBJS = tmpnam.s strtok.s reg.s
|
||
XEXTRAOBJS = tmpnam.s reg.s regcompat.s
|
||
XCFLAGS = -F -O -DMINIX -DSYSV
|
||
X
|
||
X# SERVEROBJS defines the object(s) for the vns_xxxx "server" interface.
|
||
X#
|
||
X# std.s is the version for "standard" news, making use of the
|
||
X# users .newsrc file, and resident articles / active file.
|
||
X#
|
||
XSERVEROBJS = std.s
|
||
X
|
||
X# normal vn objects
|
||
X#
|
||
XVNOBJS= hash.s envir_set.s pagefile.s reader.s storage.s sig_set.s \
|
||
Xterm_set.s tty_set.s userlist.s vn.s vnglob.s digest.s strings.s \
|
||
Xsession.s printex.s getch.s help.s newdisp.s stat.s svart.s
|
||
X
|
||
X# This is to force you to read the makefile. Once you have, comment this rule,
|
||
X# and uncomment the "real" rule. At the minimum, you will also have to
|
||
X# uncomment one of the three sets of LIBS / EXTRAOBJS & CFLAGS definitions
|
||
X# above.
|
||
X#
|
||
X#vn:
|
||
X# @echo "PLEASE READ THE MAKEFILE"
|
||
Xvn: $(VNOBJS) $(EXTRAOBJS) $(SERVEROBJS)
|
||
X cc -i -o vn $(VNOBJS) $(EXTRAOBJS) $(SERVEROBJS) $(LIBS)
|
||
X
|
||
Xdigest.s: digest.c config.h head.h node.h page.h tune.h
|
||
Xenvir_set.s: envir_set.c config.h tune.h vn.h
|
||
Xgetch.s: getch.c config.h vn.h
|
||
Xhash.s: hash.c config.h node.h tune.h
|
||
Xhelp.s: help.c config.h node.h page.h reader.h tty.h tune.h vn.h
|
||
Xnewdisp.s: newdisp.c config.h node.h tty.h
|
||
Xpagefile.s: pagefile.c node.h page.h tune.h
|
||
Xprintex.s: printex.c config.h tty.h
|
||
Xreader.s: reader.c config.h brk.h head.h node.h page.h reader.h \
|
||
X tty.h tune.h vn.h
|
||
Xregcompat.s: regcompat.c
|
||
Xsession.s: session.c config.h brk.h head.h node.h page.h tty.h tune.h \
|
||
X vn.h
|
||
Xsig_set.s: sig_set.c config.h node.h page.h tty.h tune.h
|
||
Xstat.s: stat.c config.h node.h
|
||
Xstd.s: std.c config_std.h brk.h head.h server.h std.h
|
||
Xstorage.s: storage.c node.h page.h tune.h
|
||
Xstrings.s: strings.c node.h page.h tune.h
|
||
Xsvart.s: svart.c config.h node.h page.h tty.h tune.h
|
||
Xterm_set.s: term_set.c config.h node.h page.h tty.h tune.h
|
||
Xtty_set.s: tty_set.c tty.h
|
||
Xtmpnam.s: tmpnam.c config.h
|
||
Xuserlist.s: userlist.c node.h page.h tune.h vn.h
|
||
Xvn.s: vn.c node.h tty.h
|
||
Xvnglob.s: vnglob.c config.h brk.h head.h node.h page.h tune.h
|
||
END_OF_FILE
|
||
if test 4377 -ne `wc -c <'makefile'`; then
|
||
echo shar: \"'makefile'\" unpacked with wrong size!
|
||
fi
|
||
# end of 'makefile'
|
||
fi
|
||
echo shar: End of shell archive.
|
||
exit 0
|
||
--
|
||
"Zeta Microcomputer Software"
|
||
ACSnet: nick@nswitgould.cs.uts.oz nick@ultima.cs.uts.oz
|
||
UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick
|
||
Fidonet: Nick Andrew on 3:713/602 (Zeta)
|