v13i021: VN newsreader, 1/88 version, Part03/05

Rich Salz rsalz at bbn.com
Sat Feb 6 02:47:25 AEST 1988


Submitted-by: Bob Mcqueer <amdahl!rtech!rtech!bobm at UUNET.UU.NET>
Posting-number: Volume 13, Issue 21
Archive-name: vn.jan.88/part03

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	envir_set.c
#	getch.c
#	hash.c
#	newdisp.c
#	printex.c
#	reg.c
#	sig_set.c
#	stat.c
#	storage.c
#	strings.c
#	strtok.c
#	svart.c
#	term_set.c
#	tmpnam.c
#	tty_set.c
#	userlist.c
#	vnglob.c
# This archive created: Sat Jan  9 12:40:08 1988
export PATH; PATH=/bin:$PATH
echo shar: extracting "'envir_set.c'" '(2837 characters)'
if test -f 'envir_set.c'
then
	echo shar: will not over-write existing file "'envir_set.c'"
else
cat << \SHAR_EOF > 'envir_set.c'
/*
** vn news reader.
**
** envir_set.c - routine to obtain pertinent environment variable settings
**		and set up file / directory names
**
** see copyright disclaimer / history in vn.c source file
*/

#include <stdio.h>
#include <pwd.h>
#include <sys/param.h>
#include "tune.h"
#include "config.h"
#include "vn.h"

extern char *Editor, *Ps1, *Printer;
extern char *Orgdir, *Savedir, *Ccfile;	/* path names */
extern char Cxitop[], Cxitor[], Cxrtoi[], Cxptoi[];
extern char *Home;
extern int More;

#ifdef SYSV
extern char *getcwd();
#define getwd(a) getcwd(a,sizeof(a))
#define	MAXPATHLEN 240
#else
extern char *getwd();
#endif

/*
	environment variable, original directory string setup.
*/

envir_set ()
{
	char dbuf [MAXPATHLEN], *ccname, *keyxln;
	char *vn_env(), *getcwd(), *str_store();
	struct passwd *ptr, *getpwuid();

	vns_envir();
	More = 0;

	Ps1 = vn_env("PS1",DEF_PS1);
	Editor = vn_env("EDITOR",DEF_ED);
	Printer = vn_env("PRINTER",DEF_PRINT);
	ccname = vn_env("CCFILE",DEF_CCFILE);
	keyxln = vn_env("VNKEY",DEF_KEYXLN);
	Savedir = vn_env("VNSAVE",NULL);
	More = (strcmp(vn_env("MORE",""), "-c") == 0 ? TRUE : FALSE);

	/*
		set original directory strings.
	*/

	if ((ptr = getpwuid(getuid())) == NULL)
		printex("Cannot obtain /etc/passwd entry");
	Home = str_store(ptr->pw_dir);
	if ((Orgdir = getwd(dbuf)) == NULL)
		printex ("cannot stat pwd");
	Orgdir = str_store (Orgdir);
	if (Savedir == NULL)
		Savedir = Orgdir;
	if (*ccname != '/')
	{
		sprintf (dbuf, "%s/%s",Home,ccname);
		Ccfile = str_store (dbuf);
	}
	else
		Ccfile = str_store (ccname);
	sprintf (dbuf, "%s/%s%s",Home,".vn","XXXXXX");

	if (*keyxln != '/')
	{
		sprintf(dbuf, "%s/%s",Home,keyxln);
		set_kxln(dbuf);
	}
	else
		set_kxln(keyxln);
}

char *
vn_env(var,def)
char *var;
char *def;
{
	char pfx[RECLEN];
	char *res;
	char *getenv();

	if (var[0] != 'V' || var[1] != 'N')
	{
		sprintf(pfx,"VN%s",var);
		if ((res = getenv(pfx)) != NULL)
			return(res);
	}

	if ((res = getenv(var)) != NULL)
		return(res);

	return(def);
}

static
set_kxln(fname)
char *fname;
{
	FILE *fp;
	int i;
	char bufr[80];
	char in,out,*ptr;
	char *index(), xln_str();

	for (i=0; i < 128; ++i)
		Cxitop[i] = Cxitor[i] = Cxptoi[i] = Cxrtoi[i] = i;

	if ((fp = fopen(fname,"r")) != NULL)
	{
		while(fgets(bufr,79,fp) != NULL)
		{
			if (strncmp(bufr+1,"==",2) == 0)
				ptr = bufr+2;
			else
				ptr = index(bufr+1,'=');
			if (ptr == NULL)
				continue;
			*ptr = '\0';
			++ptr;
			in = xln_str(bufr+1);
			out = xln_str(ptr);
			switch(bufr[0])
			{
			case 'r':
			case 'R':
				Cxrtoi[out] = in;
				Cxitor[in] = out;
				break;
			case 'p':
			case 'P':
				Cxptoi[out] = in;
				Cxitop[in] = out;
			default:
				break;
			}
		}
		fclose(fp);
	}
}

static char
xln_str(s)
char *s;
{
	if (*s < '0' || *s > '9')
		return(*s & 0x7f);
	return((char)(atoi(s) & 0x7f));
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'getch.c'" '(1924 characters)'
if test -f 'getch.c'
then
	echo shar: will not over-write existing file "'getch.c'"
else
cat << \SHAR_EOF > 'getch.c'
/*
** vn news reader.
**
** getch.c - character i/o routines
**
** see copyright disclaimer / history in vn.c source file
*/
#include <stdio.h>
#include <setjmp.h>
#include "config.h"
#include "vn.h"

extern char Cxitop[];
extern char *Ku, *Kd, *Kr, *Kl;

/*
	getkey obtains user keystroke with count from leading
	numerics, if any.  Picks up arrow key sequences and maps
	them to other keys.  Also translates character through
	Cxitop array since this routine is only used in session
	loop.  Saves untranslating arrow keys.
*/
getkey (c)
char *c;
{
	int i, j;
	static char	ckseq[32];

	/* Check for leading count */
	for (i = 0; (*c = getchar() & 0x7f) >= '0' && *c <= '9'; i = i * 10 + *c - '0')
		;

	/* @#$!!! flakey front ends that won't map newlines in raw mode */
	if (*c == '\012' || *c == '\015')
		*c = '\n';

	/* @#$!!! flakey terminals which send control sequences for cursors! */
	if( *c == '\033' )
	{
		/*
		** Check if part of cursor key input sequence
		** (pitch unknown escape sequences)
		*/
		j = 0;
		ckseq[j] = *c; ckseq[j+1] = '\0';
		while(*c == Ku[j] || *c == Kd[j] || *c == Kl[j] || *c == Kr[j])
		{
			if( strcmp(ckseq, Ku) == 0 ) { *c = UP; break; }
			if( strcmp(ckseq, Kd) == 0 ) { *c = DOWN; break; }
#ifdef PAGEARROW
			if( strcmp(ckseq, Kl) == 0 ) { *c = BACK; break; }
			if( strcmp(ckseq, Kr) == 0 ) { *c = FORWARD; break; }
#else
			if( strcmp(ckseq, Kl) == 0 ) { *c = UP; break; }
			if( strcmp(ckseq, Kr) == 0 ) { *c = DOWN; break; }
#endif
			*c = (getchar() & 0x7f);
			ckseq[++j] = *c; ckseq[j+1] = '\0';
		}
	}
	else
		*c = Cxitop[*c];

	if (i <= 0)
		i = 1;
	return (i);
}

/*
	get user key ignoring most controls.  Used from reader and other
	non-screen interactions.
*/
getnoctl ()
{
	char c;
	while ((c = getchar() & 0x7f) < ' ' || c == '\177')
	{
		if (c == '\015' || c == '\012')
			c = '\n';
		if (c == '\n' || c == '\b' || c == '\t')
			return (c);
	}
	return ((int) c);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'hash.c'" '(1874 characters)'
if test -f 'hash.c'
then
	echo shar: will not over-write existing file "'hash.c'"
else
cat << \SHAR_EOF > 'hash.c'
/*
** vn news reader.
**
** hash.c - hash table routines
**
** see copyright disclaimer / history in vn.c source file
*/

#include <stdio.h>
#include "config.h"
#include "tune.h"
#include "node.h"

/*
** hash table manipulation routines:
*/

extern int Ncount;
extern NODE **Newsorder;

static NODE *Tab [HASHSIZE];	/* hash Table */

hashinit ()
{
	int i;
	for (i=0; i < HASHSIZE; ++i)
		Tab[i] = NULL;
	Ncount = 0;
}

/*
	enter new node (name s, articles n, low l) in hash Table, 
	initial flags = 0.  Set order to -1.
*/
NODE *hashenter(s,n,l)
char *s;
int n;
int l;
{
	char *str_store();
	NODE *ptr,*node_store();
	NODE *hashfind();
	int i;

	if ((ptr = hashfind(s)) != NULL)
	{
		fgprintf ("Warning: group %s encountered twice",s);
		return (ptr);
	}

	i=hash(s);
	ptr = node_store();
	ptr->next = Tab[i];
	Tab[i] = ptr;
	if (l > n)
		l = n;
	++Ncount;
	ptr->lownum = l;
	ptr->state = 0;
	ptr->data = NULL;
	ptr->flags = 0;
	ptr->highnum = n;
	ptr->nd_name = str_store(s);
	ptr->pgshwn = 0;
	ptr->order = -1;
	return (ptr);
}

NODE *hashfind(s)
char *s;
{
	NODE *ptr;

	for (ptr = Tab[hash(s)]; ptr != NULL && strcmp(ptr->nd_name,s) != 0;
					ptr = ptr->next)
		    ;
	return (ptr);
}

make_newsorder()
{
	char *malloc();
	int i;
	NODE *ptr;

	if ((Newsorder = (NODE **) malloc(Ncount * sizeof(NODE *))) == NULL)
		printex("Memory allocation failure - newsorder array");
	for (i=0; i < Ncount; ++i)
		Newsorder[i] = NULL;
	for (i=0; i < HASHSIZE; ++i)
	{
		for (ptr = Tab[i]; ptr != NULL; ptr = ptr->next)
		{
			if (ptr->order < 0 || ptr->order >= Ncount)
				printex("News order range error");
			Newsorder[ptr->order] = ptr;
		}
	}
	for (i=0; i < Ncount; ++i)
		if (Newsorder[i] == NULL)
			printex("News order duplication error");
}

static hash (s)
char *s;
{
	unsigned rem;
	for (rem=0; *s != '\0'; ++s)
		rem = (rem*128 + (*s&0x7f)) % HASHSIZE;
	return (rem);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'newdisp.c'" '(920 characters)'
if test -f 'newdisp.c'
then
	echo shar: will not over-write existing file "'newdisp.c'"
else
cat << \SHAR_EOF > 'newdisp.c'
/*
** vn news reader.
**
** newgroups.c - display list of new groups since user's last ession.
**
** see copyright disclaimer / history in vn.c source file
*/

#include <stdio.h>
#include "config.h"
#include "tty.h"
#include "node.h"

extern NODE **Newsorder;
extern int Ncount, Lrec, C_allow;

new_groups ()
{
	int i,wrem,w;
	int max;
	char fs[24],c_end;

	max = 0;
	for (i=0; i < Ncount; ++i)
		if (((Newsorder[i])->flags & FLG_NEW) != 0 &&
				(w = strlen((Newsorder[i])->nd_name)) > max)
			max = w;
	sprintf (fs,"%%-%ds%%c",max);

	if (max <= 0)
		return (0);

	term_set (ERASE);
	printf ("New newsgroups:\n");

	wrem = C_allow;
	for (i=0; i < Ncount; ++i)
	{
		if (((Newsorder[i])->flags & FLG_NEW) == 0)
			continue;
		if ((wrem -= max) < max)
		{
			wrem = C_allow;
			c_end = '\n';
		}
		else
			c_end = ' ';
		printf (fs,(Newsorder[i])->nd_name,c_end);
	}
	if (c_end != '\n')
		putchar ('\n');

	return (1);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'printex.c'" '(678 characters)'
if test -f 'printex.c'
then
	echo shar: will not over-write existing file "'printex.c'"
else
cat << \SHAR_EOF > 'printex.c'
/*
** vn news reader.
**
** printex.c - print fatal error message and exit.
**
** see copyright disclaimer / history in vn.c source file
*/
#include <stdio.h>
#include <setjmp.h>
#include "config.h"
#include "tty.h"

extern int errno;	/* unix error number */

/*
	error/abnormal condition cleanup and abort routine
	pass stack to printf
*/
printex (s,a,b,c,d,e,f)
char *s;
long a,b,c,d,e,f;
{
	static int topflag=0;
	if (topflag == 0)
	{
		++topflag;
		term_set (STOP);
		tty_set (COOKED);
		fflush (stdout);
		fprintf (stderr,s,a,b,c,d,e,f);
		fprintf (stderr," (error code %d)\n",errno);
		vns_exit(1);
		stat_end(-1);
		exit (1);
	}
	else
		fprintf (stderr,s,a,b,c,d,e,f);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'reg.c'" '(1656 characters)'
if test -f 'reg.c'
then
	echo shar: will not over-write existing file "'reg.c'"
else
cat << \SHAR_EOF > 'reg.c'
/*
** vn news reader.
**
** reg.c - implementation of regex / regcmp on top of UCB library
**
** see copyright disclaimer / history in vn.c source file
*/

#include <stdio.h>

#define RGBLKSIZE 20

struct _regtab
{
	struct _regtab *link;
	char *regstr;
};

typedef struct _regtab REGTAB;

static REGTAB *Chain = NULL;
static REGTAB *Free = NULL;
static REGTAB *Compiled = NULL;

regfree(s)
char *s;
{
	REGTAB *ptr,*cmp,*old;

	cmp = (REGTAB *) s;
	old = NULL;

	for (ptr = Chain; ptr != NULL; ptr = (old = ptr)->link)
	{
		if (ptr == cmp)
		{
			if (old == NULL)
				Chain = Chain->link;
			else
				old->link = ptr->link;
			ptr->link = Free;
			Free = ptr;
			break;
		}
	}
}

char *regcmp(str)
char *str;
{
	int i;
	char *str_store();
	char *re_comp();

	if (re_comp(str) != NULL)
	{
		Compiled = NULL;	/* make sure we're OK */
		return(NULL);
	}

	if (Free == NULL)
	{
		Free = (REGTAB *) malloc(RGBLKSIZE * sizeof(REGTAB));
		if (Free == NULL)
			printex ("regcmp: memory allocation failure");
		for (i = 0; i < RGBLKSIZE - 1; ++i)
			Free[i].link = Free + i + 1;
		Free[i].link = NULL;
	}

	Compiled = Free;
	Free = Free->link;

	Compiled->link = Chain;
	Chain = Compiled;
	Compiled->regstr = str_store(str);

	return ((char *) Compiled);
}

char *regex(reg,str)
char *reg,*str;
{
	REGTAB *cmp;

	cmp = (REGTAB *) reg;

	if (cmp == Compiled)
	{
		if (re_exec(str))
			return(str);
		return (NULL);
	}

	for (Compiled = Chain; Compiled != NULL; Compiled = Compiled->link)
	{
		if (Compiled == cmp)
			break;
	}

	if (Compiled == NULL)
		printex ("regex: bad pointer");

	re_comp(Compiled->regstr);

	if (re_exec(str))
		return(str);

	return(NULL);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'sig_set.c'" '(4477 characters)'
if test -f 'sig_set.c'
then
	echo shar: will not over-write existing file "'sig_set.c'"
else
cat << \SHAR_EOF > 'sig_set.c'
/*
** vn news reader.
**
** sig_set.c - signal handler
**
** see copyright disclaimer / history in vn.c source file
*/

#include <stdio.h>
#include <sys/signal.h>
#include <sgtty.h>
#include <setjmp.h>
#include "tty.h"
#include "config.h"
#include "brk.h"
#include "tune.h"
#include "node.h"
#include "page.h"

extern int L_allow;
extern char *Version;
extern char *Brk_fmt;
extern char *Vns_version;

static int Sigflag=BRK_INIT;	/* phase of interaction */
static FILE **Fpseek;		/* article reading file pointer pointer */
static int Foreground;
static jmp_buf Jumploc;		/* for BRK_SESS phase */
static int Need_restart = 0;

/*
	interrupt handler - unusual termination (longjmp and printex aborts)
	if not abort, remember to reset signal trap
	CAUTION - the passing of a jump buffer is a little dicey - assumes
	type jump_buf is an array.

	sigcatch and sig_set control a lot of i/o on stderr also, since
	it is so intimately related to signal interaction.  Note that the
	SIGTSTP action causes a "stopped on tty output" if raw terminal
	mode is restored by tty_set(RESTORE).  We don't get it if we were
	already cooked since tty_set avoids calling ioctl if it doesn't
	have to.
*/
static sigcatch (sig)
int sig;
{
	char buf [MAX_C+1];
	int pgrp;

	/* disable signal while processing it */
	signal (sig,SIG_IGN);

	switch (sig)
	{
	case SIGINT:
	case SIGQUIT:
		break;

#ifdef JOBCONTROL
	case SIGTSTP:
		/* ignore SIGTTOU so we don't get stopped if [kc]sh grabs the tty */
		signal(SIGTTOU, SIG_IGN);
		tty_set (SAVEMODE);
		term_set (MOVE,0,L_allow+RECBIAS-1);
		printf ("\n");
		Foreground = 0;
		fflush (stdout);
		fflush (stderr);
		signal(SIGTTOU, SIG_DFL);

		/* Send the TSTP signal to suspend our process group */
		signal(SIGTSTP, SIG_DFL);
		sigsetmask(0);
		kill (0, SIGTSTP);

		/* WE ARE NOW STOPPED */

		/*
				WELCOME BACK!
				if terminals process group is ours, we are foregrounded again
				and can turn newsgroup name printing back on
			*/
		tty_set (RESTORE);

		/*
		** Note concerning RESTART.  If in state BRK_IN, we simply
		** set a flag to do it upon switch to state BRK_SESS - we
		** don't want to send i/o to the terminal when we
		** background during BRK_IN phase ("stopped on tty output")
		*/
		switch (Sigflag)
		{
		case BRK_SESS:
			signal (SIGTSTP,sigcatch);
			term_set (RESTART);
			longjmp (Jumploc,1);
		case BRK_IN:
			Need_restart = 1;
			ioctl (1,TIOCGPGRP,&pgrp);
			if (pgrp == getpgrp(0))
				Foreground = 1;
			break;
		default:
			term_set (RESTART);
			break;
		}
		signal (SIGTSTP,sigcatch);
		return;
#endif
	default:
		printex (Brk_fmt,sig);
	}

	/* QUIT and INTERRUPT signals */
	switch (Sigflag)
	{
	case BRK_SESS:
		/* if in session, ask if really a quit, do longjump if not */
		term_set (ERASE);
		tty_set (RAWMODE);
		user_str (buf, BRK_PR, 1, "");
		if (buf[0] == 'y')
			printex (Brk_fmt,sig);
		signal (sig,sigcatch);
		longjmp (Jumploc,1);
	case BRK_READ:
		/* if reading seek file to end to abort page printing */
		printf ("\n");
		if (*Fpseek == NULL || fseek(*Fpseek,0L,2) < 0)
			putchar ('\07');
		break;
	default:
		printex (Brk_fmt,sig);
	}
	signal (sig,sigcatch);
}

/*
	sig_set controls what will be done with a signal when picked up by
	sigcatch.  fgprintf is included here to keep knowledge
	of TSTP state localized.
*/
/* VARARGS */
sig_set (flag,dat)
int flag, *dat;
{
	int i, *xfer, pgrp;
	if (Sigflag == BRK_INIT)
	{
		signal (SIGINT,sigcatch);
		signal (SIGQUIT,sigcatch);
		signal (SIGTERM,sigcatch);
#ifdef JOBCONTROL
		signal (SIGTSTP,sigcatch);
		ioctl (1,TIOCGPGRP,&pgrp);
		if (pgrp == getpgrp(0))
		{
			Foreground = 1;
			fgprintf ("Visual News, %s(%s), reading:\n",
					Version, Vns_version);
		}
		else
			Foreground = 0;
#else
		Foreground = NOJOB_FG;
#endif
	}
	switch (flag)
	{
	case BRK_IN:
	case BRK_OUT:
		Sigflag = flag;
		break;
	case BRK_READ:
		if (Sigflag != BRK_SESS)
			printex ("unexpected read state, sig_set\n");
		Fpseek = (FILE **) dat;
		Sigflag = BRK_READ;
		break;
	case BRK_SESS:
		if (Need_restart)
			term_set(RESTART);
		xfer = (int *) Jumploc;
		for (i=0; i < sizeof(Jumploc) / sizeof(int); ++i)
			xfer[i] = dat[i];
		Sigflag = BRK_SESS;
		break;
	case BRK_RFIN:
		if (Sigflag != BRK_READ)
			printex ("unexpected finish state, sig_set\n");
		Sigflag = BRK_SESS;
		break;
	default:
		printex ("bad state %d, sig_set\n",flag);
	}
}

fgprintf (fs,a,b,c,d,e)
char *fs;
int a,b,c,d,e;
{
	if (Foreground)
		fprintf (stderr,fs,a,b,c,d,e);
	fflush (stderr);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'stat.c'" '(4226 characters)'
if test -f 'stat.c'
then
	echo shar: will not over-write existing file "'stat.c'"
else
cat << \SHAR_EOF > 'stat.c'
/*
** vn news reader.
**
** stat.c - stat and log file collection
**
** see copyright disclaimer / history in vn.c source file
*/
#include <stdio.h>
#include <sys/types.h>
#ifdef SYSV
#include <fcntl.h>
#endif
#include <sys/file.h>
#include <sys/stat.h>
#include <pwd.h>
#include "config.h"
#include "node.h"

extern NODE *hashfind();
extern char *strtok();
extern int Ncount;
extern NODE **Newsorder;

#ifdef VNLOGFILE
static char Start[80];
#endif

stat_start()
{
#ifdef VNLOGFILE
	char *ctime();
	long now;

	time(&now);
	strcpy(Start,ctime(&now));
#endif
}

/*
** flag = 0, "NO NEWS" type session.
**      = 1, regular session.
**	= -1, aborted session
**
** CAUTION: routine CALLED from within printex() - do NOT
** call printex().  Simply do message to stderr on fail.
*/
stat_end(flag)
int flag;
{
	NODE *nd;
	char *nl,*index();
	char *how;
	struct passwd *ptr, *getpwuid();
	struct stat buf;
	long now;
	char bufr[80];
	char name[60];
	FILE *fp;
	int fd;
	long chk, rd, pg;
	int i;

#ifdef VNLOGFILE
	if (stat(VNLOGFILE,&buf) == 0 && (fp = fopen(VNLOGFILE,"a")) != NULL)
	{
		time(&now);
		strcpy(bufr,ctime(&now));
		if ((nl = index(bufr,'\n')) != NULL)
			*nl = '\0';
		if ((nl = index(Start,'\n')) != NULL)
			*nl = '\0';
		if (flag == 0)
			how = "NO NEWS";
		else
		{
			if (flag > 0)
				how = "OK";
			else
				how = "ABORTED";
		}
		ptr = getpwuid (getuid());
		fprintf(fp, "%s\t%s - %s %s\n", ptr->pw_name, Start, bufr, how);
		fclose (fp);
	}
#endif

#ifdef VNSTATFILE
	/*
	** Stat file is done with a fixed record size, and maintaining the
	** existing record order exactly so that concurrent users will do
	** the least damage.  If two users actually read & update a single
	** record simultaneously, we should just lose one user's counts.
	** Short of implementing a locking scheme, we probably won't do
	** much better.  Disadvantages are that deleted newsgroups never
	** get cleaned out, order is set by the first user whose
	** statistics are collected, it will break if anyone modifies it,
	** and the file is a bit larger than it needs to be.
	**
	** record format:
	**
	** CCCCCC PPPPPP RRRRRR newsgroup name ....  \n
	** ^      ^      ^      ^                    ^
	** 0      7      14     21              char 79
	**
	** CCCCCC - count of sessions searching group
	** PPPPPP - count of sessions actually finding pages for group
	** RRRRRR - count of sessions actually accessing articles in group
	*/
	if ((fd = open(VNSTATFILE,O_RDWR)) > 0)
	{
		bufr[80] = '\0';

		/*
		** read a record, find the newsgroup, update counts.
		** If changed, seek back & overwrite.  By using fixed
		** length records, we should only lose something on
		** concurrent writes of the same record, and by writing
		** the ENTIRE record, we keep it consistent
		*/
		while ((i = read(fd,bufr,80)) == 80 && bufr[79] == '\n')
		{
			chk = atoi(bufr);
			pg = atoi(bufr+7);
			rd = atoi(bufr+14);
			strcpy(name,bufr+21);
			nl = strtok(name," \n");
			if (nl == NULL || (nd = hashfind(nl)) == NULL)
				continue;
			nd->flags |= FLG_STAT;
			if ((nd->flags & (FLG_SEARCH|FLG_ACC|FLG_PAGE)) == 0)
				continue;
			if ((nd->flags & FLG_SEARCH) != 0)
				++chk;
			if ((nd->flags & FLG_PAGE) != 0)
				++pg;
			if ((nd->flags & FLG_ACC) != 0)
				++rd;
			if (chk > 999999L)
				chk = 999999L;
			if (pg > 999999L)
				pg = 999999L;
			if (rd > 999999L)
				rd = 999999L;
			sprintf(bufr,"%6ld",chk);
			bufr[6] = ' ';
			sprintf(bufr+7,"%6ld",pg);
			bufr[13] = ' ';
			sprintf(bufr+14,"%6ld",rd);
			bufr[20] = ' ';
			lseek(fd,-80L,1);
			write(fd,bufr,80);
		}

		/* format screwed up ? */
		if (i != 0)
		{
			lseek(fd,(long) -i,1);
			fprintf(stderr,"bad data in %s\n",VNSTATFILE);
		}

		/* may have aborted during vns_news() */
		if (Newsorder == NULL)
			Ncount = 0;

		/* now append any groups not in file yet */
		for (i = 0; i < Ncount; ++i)
		{
			nd = Newsorder[i];
			if ((nd->flags & FLG_STAT) != 0)
				continue;
			chk = rd = pg = 0;
			if ((nd->flags & FLG_SEARCH) != 0)
				chk = 1;
			if ((nd->flags & FLG_PAGE) != 0)
				pg = 1;
			if ((nd->flags & FLG_ACC) != 0)
				rd = 1;
			sprintf(bufr,"%6ld %6ld %6ld %-58s\n",
					chk, pg, rd, nd->nd_name);
			write(fd,bufr,80);
		}
		close(fd);
	}
#endif
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'storage.c'" '(2261 characters)'
if test -f 'storage.c'
then
	echo shar: will not over-write existing file "'storage.c'"
else
cat << \SHAR_EOF > 'storage.c'
/*
** vn news reader.
**
** storage.c - storage allocation routines
**
** see copyright disclaimer / history in vn.c source file
*/

#include <stdio.h>
#include "tune.h"
#include "node.h"
#include "page.h"

extern char *malloc();

extern int L_allow;

extern PAGE Page;
/*
	Storage allocaters.
*/

char *str_store (s)
char *s;
{
	static unsigned av_len = 0;	/* current storage available */
	static char *avail;
	int len;

	if (s == NULL)
		s = "";

	if ((len = strlen(s)+1) > av_len)
	{
		if (len > STRBLKSIZE)
			av_len = len;
		else
			av_len = STRBLKSIZE;
		if ((avail = malloc(av_len)) == NULL)
			printex ("can't allocate memory for string storage");
	}
	strcpy (avail,s);
	s = avail;
	avail += len;
	av_len -= len;
	return (s);
}

/*
** called after number of terminal lines (L_allow) is known, to set
** up storage for Page.
*/
page_alloc ()
{
	char *body;

	if ((body = malloc(L_allow*sizeof(BODY))) == NULL)
		printex ("can't allocate memory for display storage");

	Page.b = (BODY *) body;
}

NODE
*node_store()
{
	static int nd_avail = 0;
	static NODE *nd;
	NODE *ret;

	if (nd_avail <= 0)
	{
		if ((nd = (NODE *) malloc(sizeof(NODE)*NDBLKSIZE)) == NULL)
			printex ("can't allocate memory for newsgroup table");
		nd_avail = NDBLKSIZE;
	}
	--nd_avail;
	ret = nd;
	++nd;
	return(ret);
}

/*
** temp string storage
*/

typedef struct
{
	int len;
	int idx;
	char **ptr;
} STRINGPOOL;

char *
str_tpool(n)
int n;
{
	int size;
	STRINGPOOL *p;

	size = sizeof(STRINGPOOL) + n * sizeof(char **);

	if ((p = (STRINGPOOL *) malloc(size)) == NULL)
		printex("Cannot allocate temporary string storage");

	p->ptr = (char **)(p+1);
	p->len = n;
	p->idx = 0;

	return((char *) p);
}

char *
str_tstore(cp,s)
char *cp;
char *s;
{
	STRINGPOOL *p;
	int len;

	p = (STRINGPOOL *) cp;
	if (p->idx >= p->len)
		printex("Temporary string storage overflow");
	len = strlen(s)+1;
	if ((cp = malloc(len)) == NULL)
		printex("Cannot allocate copy of string");
	strcpy(cp,s);
	(p->ptr)[p->idx] = cp;
	++(p->idx);

	return(cp);
}

char **
str_taptr(cp)
char *cp;
{
	STRINGPOOL *p;

	p = (STRINGPOOL *) cp;

	return (p->ptr + p->idx);
}

str_tfree(cp)
char *cp;
{
	STRINGPOOL *p;
	int i;

	p = (STRINGPOOL *) cp;
	for (i=0; i < p->idx; ++i)
		free((p->ptr)[i]);
	free (cp);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'strings.c'" '(537 characters)'
if test -f 'strings.c'
then
	echo shar: will not over-write existing file "'strings.c'"
else
cat << \SHAR_EOF > 'strings.c'
/*
** vn news reader.
**
** strings.c - read only character strings
**
** see copyright disclaimer / history in vn.c source file
*/

#include "tune.h"
#include "node.h"
#include "page.h"

char *Version = "1/88";

char *No_msg = "No articles";
char *Hdon_msg = "Headers being printed";
char *Hdoff_msg = "Headers being suppressed";
char *Roton_msg = "ROT 13";
char *Rotoff_msg = "NO ROT";

char *Aformat = AFORMAT;

char *Contstr = "  ******** any key to continue ********";

char *Brk_fmt = "QUIT (signal %d)";

char *List_sep = " \t,";
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'strtok.c'" '(1082 characters)'
if test -f 'strtok.c'
then
	echo shar: will not over-write existing file "'strtok.c'"
else
cat << \SHAR_EOF > 'strtok.c'
/*
** vn news reader.
**
** strtok.c - strtok() and strpbrk() string routines using UCB index().
**
** see copyright disclaimer / history in vn.c source file
*/

#include <stdio.h>

char *strpbrk (s,del)
char *s, *del;
{
	char *ptr,*index();
	if (s == NULL)
		return (NULL);
	for (; *del != '\0'; ++del)
		if ((ptr = index(s,*del)) != NULL)
			return (ptr);
	return (NULL);
}

char *strtok(str,delim)
char *str, *delim;
{
	char *tokstart, *tokend, *first_ch (), *last_ch();
	static char *save=NULL;

	if (str != NULL)
		save = str;

	if (save == NULL)
		return (NULL);

	tokstart = first_ch (save, delim);
	tokend = last_ch (tokstart, delim);
	save = first_ch (tokend, delim);
	*tokend = '\0';

	if (*tokstart == '\0')
		return (NULL);

	return (tokstart);
}

static char *first_ch (str,delim)
char *str,*delim;
{
	char *index ();
	char *f;

	for (f = str; *f != '\0' && index(delim,*f) != NULL; ++f)
		;

	return (f);
}

static char *last_ch (str,delim)
char *str,*delim;
{
	char *index ();
	char *f;

	for (f = str; *f != '\0' && index(delim,*f) == NULL; ++f)
		;

	return (f);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'svart.c'" '(4156 characters)'
if test -f 'svart.c'
then
	echo shar: will not over-write existing file "'svart.c'"
else
cat << \SHAR_EOF > 'svart.c'
/*
** vn news reader.
**
** svart.c - article save routine
**
** see copyright disclaimer / history in vn.c source file
*/
#include <stdio.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "config.h"
#include "tty.h"
#include "tune.h"
#include "node.h"
#include "page.h"

extern PAGE Page;
extern int Digest;
extern char *List_sep;
extern char *Home;
extern char *Savedir;

/*
** save article in file.  Called from reader and session both.
** handles "|" pipe convention.  Caller passes in return message buffer.
*/
save_art(art,idest,msg)
char *art;
char *idest;
char *msg;
{
	char fn[L_tmpnam+1];
	char cmd[RECLEN];
	char *mode;
	char *dest, dstore[RECLEN];
	struct stat sbuf;
	int rstat;
	char *colon;
	char *pcnt;
	char *index();

	/* temporary copy so we don't overwrite saved string */
	strcpy((dest = dstore),idest);

	if (*dest == '|')
	{
		tmpnam(fn);
		if (art_xfer(fn,art,"w") != 0)
		{
			strcpy(msg,"Can't open temporary file");
			return (-1);
		}
		sprintf(cmd,"cat %s %s",fn,dest);
		tty_set (SAVEMODE);
		rstat = system (cmd);
		tty_set (RESTORE);
		sprintf(msg,"Command returns %d",rstat);
		return (rstat);
	}

	if ((colon = index(dest,':')) != NULL)
	{
		mode = dest;
		*colon = '\0';
		dest = colon+1;
	}
	else
		mode = "a";

	if (*dest == '~')
	{
		if (twiddle(dest,msg) < 0)
			return (-1);
	}

	if (*dest == '\0')
		strcpy(dest,"%d");

	if (*dest != '/')
	{
		if (noslash(dest,msg) < 0)
			return (-1);
	}

	if ((pcnt = index(dest,'%')) != NULL && pcnt[1] == 'd')
	{
		if (Digest)
			sprintf(cmd,dest,Digest);
		else
			sprintf(cmd,dest,atoi(art));
		dest = cmd;
	}

	rstat = stat(dest,&sbuf);

	if (art_xfer(dest,art,mode) != 0)
	{
		sprintf(msg,"Can't open %s with mode %s",dest,mode);
		return(-1);
	}

	if (rstat != 0)
	{
		sprintf(msg,"Created %s",dest);
		return(0);
	}

	if (strcmp(mode,"a") == 0)
	{
		sprintf(msg,"Appended %s",dest);
		return(0);
	}

	sprintf(msg,"Wrote (mode %s) %s",mode,dest);
	return(0);
}

static
noslash(dest,msg)
char *dest;
char *msg;
{
	char *pcnt;
	char buf[RECLEN];
	char dir[RECLEN];
	struct stat sbuf;

	strcpy(buf,Page.h.name);
#ifdef SYSV
	buf[14] = '\0';
#endif
	if ((pcnt = index(Savedir,'%')) != NULL && pcnt[1] == 's')
		sprintf(dir,Savedir,buf);
	else
		strcpy(dir,Savedir);
	if (dir[0] == '~')
	{
		if (twiddle(dir,msg) < 0)
			return (-1);
	}
	if (stat(dir,&sbuf) != 0)
	{
#ifdef SYSV
		/*
		** late enough releases of SYSV may have a mkdir() call, but
		** this is an obscure feature anyway.  We'll accept the fork.
		*/
		sprintf(buf,"mkdir %s",dir);
		if (system(buf) != 0)
#else
		if (mkdir(dir,0755) != 0)
#endif
		{
			sprintf(msg,"Cannot make directory %s",dir);
			return (-1);
		}
	}
	sprintf(buf,"%s/%s",dir,dest);
	strcpy(dest,buf);
	return (0);
}

static
twiddle(dest,msg)
char *dest, *msg;
{
	char *tail;
	char *name;
	char tmp;
	char buf[RECLEN];
	struct passwd *ptr, *getpwnam();

	for (tail=name=dest+1; *tail != '/' && *tail != '\0'; ++tail)
		;

	if (*name == '\0' || *name == '/')
		sprintf(buf,"%s%s",Home,tail);
	else
	{
		tmp = *tail;
		*tail = '\0';
		ptr = getpwnam(name);
		*tail = tmp;
		if (ptr == NULL)
		{
			sprintf(msg,"Can't interpret ~%s",name);
			return(-1);
		}
		sprintf(buf,"%s%s",ptr->pw_dir,tail);
	}

	strcpy(dest,buf);
	return (0);
}

/*
** transfer contents of a list of articles to a file.  If Digest, this
** is simply a list of files.  If not, it is a list of articles to be
** saved with vns_asave.  Parses list destructively with
** strtok().  Return 0 for success, -1 for failure to open file.
**
** Called directly to copy a list of articles to a temp. file to
** direct to printer.
*/
art_xfer(fn,list,mode)
char *fn, *list, *mode;
{
	char *p;
	FILE *fout, *fin;
	int count;
	char buf[RECLEN];
	char *strtok();

	if ((fout = fopen(fn,mode)) == NULL)
		return (-1);

	count = 0;
	for (p = strtok(list,List_sep); p != NULL; p = strtok(NULL,List_sep))
	{
		if (Digest)
		{
			fin = fopen(p,"r");
			if (fin == NULL)
				continue;
			while (fgets(buf,RECLEN-1,fin) != NULL)
				fputs(buf,fout);
			fclose(fin);
			continue;
		}
		vns_asave(atoi(p),fout,count,fn,mode);
		++count;
	}
	fclose(fout);
	return(0);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'term_set.c'" '(4953 characters)'
if test -f 'term_set.c'
then
	echo shar: will not over-write existing file "'term_set.c'"
else
cat << \SHAR_EOF > 'term_set.c'
/*
** vn news reader.
**
** term_set.c - terminal control, hides termcap interface
**
** see copyright disclaimer / history in vn.c source file
*/

#include <stdio.h>
#include "tty.h"
#include "config.h"
#include "tune.h"
#include "node.h"
#include "page.h"

extern int L_allow, C_allow;
extern char *Ku, *Kd, *Kl, *Kr;	

static outc (c)
char c;
{
	putchar (c);
}

/*
	term_set controls terminal through termcap
	START sets global parameters related to terminal also,
	as well as allocating display buffer which depends on
	terminal lines, and allocating escape strings.  RESTART
	simply re-issues the initialization - used following system
	calls that could have goofed up the terminal state.
*/

/*
** Escape strings.
*/

static char *Cm,*Cl,*So,*Se,*Te,*Bc,*Ce,*Ti,*Ks,*Ke;
#ifdef USEVS
static char *Vs,*Ve;
#endif

static int Backspace;		/* backspace works */
static int Overstrike;		/* terminal overstrikes */

static t_setup()
{
	char *tgetstr(), *vn_env(), *str_store();
	char *c, tc_buf[2048],optstr[2048];
	char *tvar;

	tvar = vn_env("TERM",DEF_TERM);

	c = optstr;
	if (tgetent(tc_buf,tvar) != 1)
		printex ("%s - unknown terminal",tvar);

	/* get needed capabilities */
	Cm = str_store(tgetstr("cm",&c));
	Cl = str_store(tgetstr("cl",&c));
	So = str_store(tgetstr("so",&c));
	Se = str_store(tgetstr("se",&c));
	Te = str_store(tgetstr("te",&c));
	Ti = str_store(tgetstr("ti",&c));
	Bc = str_store(tgetstr("bc",&c));
	Ce = str_store(tgetstr("ce",&c));
	Kd = str_store(tgetstr("kd",&c));
	Ke = str_store(tgetstr("ke",&c));
	Kl = str_store(tgetstr("kl",&c));
	Kr = str_store(tgetstr("kr",&c));
	Ks = str_store(tgetstr("ks",&c));
	Ku = str_store(tgetstr("ku",&c));
#ifdef USEVS
	Vs = str_store(tgetstr("vs",&c));
	Ve = str_store(tgetstr("ve",&c));
#endif
	Backspace = tgetflag("bs");
	Overstrike = tgetflag("os");

	if ( *Cm == '\0' || *Cl == '\0')
	{
		printex ("cursor control and erase capability needed");
	}

	/*
	** Checks for arrow keys which don't issue something beginning
	** with <ESC>.  This is more paranoid than we need to be, strictly
	** speaking - we could get away with any string which didn't
	** conflict with controls used for commands.  However, that would
	** be a maintenance headache - we will simply reserve <ESC> as the
	** only char not to be used for commands, and punt on terminals
	** which don't send reasonable arrow keys.  It would be confusing
	** to have keys work partially, also.  I know of no terminal with
	** one arrow key beginning with an escape, and another beginning
	** with something else, but let's be safe.  This also insists on
	** definitions for all 4 arrows, which seems reasonable.
	*/

	if ((*Ku != '\0' && *Ku != '\033') || *Kl != *Ku || *Kr != *Ku || *Kd != *Ku)
	{
		fgprintf("WARNING: arrow keys will not work for this terminal");
		Ku = Kd = Kl = Kr = Kd = Ke = "";
	}

	if (Overstrike)
		fgprintf ("WARNING: terminal overstrikes - can't update display without erase\n");

	if ((L_allow = tgetnum("li")) < REQLINES)
	{
		if (L_allow < 0)
			printex ("can't determine number of lines on terminal");
		printex ("too few lines for display - %d needed", REQLINES);
	}

	/*
	** C_allow set so as to not use extreme right column.
	** Avoids "bad wraparound" problems - we're deciding it's best
	** to ALWAYS assume no automargin, and take care of it ourselves
	*/
	if((C_allow = tgetnum("co")) > MAX_C)
		C_allow = MAX_C;
	else
		--C_allow;
	if (C_allow < MIN_C)
	{
		if (C_allow < 0)
			printex("can't determine number of columns on terminal.");
		printex ("too few columns for display - %d needed",MIN_C);
	}

	L_allow -= RECBIAS;
	page_alloc();
	tputs(Ti,1,outc);
	tputs(Ks,1,outc);
#ifdef USEVS
	tputs(Vs,1,outc);
#endif
}

/* VARARGS */
term_set(cmd,x,y)
int cmd,x,y;
{
	char *tgoto();
	int i;
	switch (cmd)
	{
	case MOVE:
		tputs (tgoto(Cm,x,y),1,outc);
		break;
	case ERASE:
		tputs(Cl,1,outc);
		break;
	case ONREVERSE:
		tputs(So,1,outc);
		break;
	case OFFREVERSE:
		tputs(Se,1,outc);
		break;
	case START:
		t_setup();
		break;
	case RESTART:
		tputs(Ti,1,outc);
		tputs(Ks,1,outc);
#ifdef USEVS
		tputs(Vs,1,outc);
#endif
		break;
	case STOP:
		term_set (MOVE,0,L_allow+RECBIAS-1);
		printf ("\n");
		tputs(Ke,1,outc);
		tputs(Te,1,outc);
#ifdef USEVS
		tputs(Ve,1,outc);
#endif
		break;
	case RUBSEQ:
		if (Overstrike)
		{
			/* space overprint is futile */
			if (Backspace)
				putchar('\010');
			else
				tputs(Bc,1,outc);
			break;
		}
		if (Backspace)
			printf("%c %c",'\010','\010');
		else
		{
			tputs(Bc,1,outc);  
			putchar(' ');  
			tputs(Bc,1,outc);
		}
		break;
	case ZAP:
		if (Ce != NULL && *Ce != '\0')
			tputs(Ce,1,outc);
		else
		{
			if (Overstrike)
				break;		/* punt */
			for (i=x; i < y; ++i)
				putchar(' ');
			if (Backspace)
			{
				for (i=x; i < y; ++i)
					putchar('\010');
			}
			else
			{
				for (i=x; i < y; ++i)
					tputs(Bc,1,outc);
			}
		}
		break;
	default:
		printex ("term_set unknown code (%d)",cmd);
		break;
	}
	return (0);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'tmpnam.c'" '(420 characters)'
if test -f 'tmpnam.c'
then
	echo shar: will not over-write existing file "'tmpnam.c'"
else
cat << \SHAR_EOF > 'tmpnam.c'
/*
** vn news reader.
**
** tmpnam.c - tmpnam() replacement for UCB, also uses non-generic name.
**
** see copyright disclaimer / history in vn.c source file
*/

#include <stdio.h>
#include "config.h"

char *tmpnam (buf)
char *buf;
{
	static char *ptr = VNTEMPNAME;

	/* depends on string initialized above */
	sprintf (ptr+TMP_XOFFSET,"XXXXXX");

	mktemp (ptr);

	if (buf != NULL)
		strcpy (buf,ptr);

	return (ptr);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'tty_set.c'" '(2552 characters)'
if test -f 'tty_set.c'
then
	echo shar: will not over-write existing file "'tty_set.c'"
else
cat << \SHAR_EOF > 'tty_set.c'
/*
** vn news reader.
**
** tty_set.c - interface to ioctl (system tty interface)
**
** see copyright disclaimer / history in vn.c source file
*/

#ifdef SYSV
#include <termio.h>
#else
#include <sgtty.h>
#endif

#include "tty.h"

extern char Erasekey,Killkey;

#ifdef SYSV
static struct termio C_tp, O_tp;
#else
static struct sgttyb C_tp;
static unsigned short O_lflag;
#endif

static unsigned S_flag=0;
static int R_ignore=0;		/* up/down counter of reset calls to ignore */

#define IO_GOT 1	/* have polled for original terminal mode */
#define IO_RAW 2	/* in RAW (CBREAK actually) mode */

/*
	tty_set handles ioctl calls.  SAVEMODE, RESTORE are used around
	system calls and interrupts to assure cooked mode, and restore
	raw if raw on SAVEMODE.  The pair results in no calls to ioctl
	if we are cooked already when SAVEMODE is called, and may be nested,
	provided we desire no "restore" of cooked mode after restoring raw.

	When we get the original terminal mode, we also save erase and kill.

	sig_set makes an ioctl call to get process group leader.  Otherwise
	ioctl calls should come through here.
*/
tty_set(cmd)
int cmd;
{
	int rc;
	unsigned mask;

	switch (cmd)
	{
	case BACKSTOP:
#ifdef JOBCONTROL
		if ((rc = ioctl(1,TIOCLGET,&mask)) != 0)
			break;
		mask |= LTOSTOP;
		rc = ioctl(1,TIOCLSET,&mask);
#else
		rc = 0;
#endif
		break;
	case RAWMODE:
		if ((S_flag & IO_RAW) != 0)
		{
			rc = 0;
			break;
		}
		if ((S_flag & IO_GOT) == 0)
		{
			/* Save original modes, get erase / kill */
#ifdef SYSV
			rc = ioctl(0,TCGETA,&C_tp);
			O_tp = C_tp;
			Erasekey = C_tp.c_cc[VERASE];
			Killkey = C_tp.c_cc[VKILL];
#else
			rc = ioctl(0,TIOCGETP,&C_tp);
			O_lflag = C_tp.sg_flags;
			Erasekey = C_tp.sg_erase;
			Killkey = C_tp.sg_kill;
#endif
		}
#ifdef SYSV
		C_tp.c_lflag &= ~(ECHO | ICANON);
		C_tp.c_cc[VMIN] = 1;
		rc = ioctl(0,TCSETAW,&C_tp);
#else
		C_tp.sg_flags |= CBREAK;
		C_tp.sg_flags &= ~ECHO;
		rc = ioctl(0,TIOCSETP,&C_tp);
#endif
		S_flag = IO_GOT|IO_RAW;
		break;
	case COOKED:
		if ((S_flag & IO_RAW) != 0)
		{
#ifdef SYSV
			C_tp = O_tp;
			rc = ioctl(0,TCSETAW,&C_tp);
#else
			C_tp.sg_flags = O_lflag;
			rc = ioctl(0,TIOCSETP,&C_tp);
#endif
			S_flag &= ~IO_RAW;
		}
		else
			rc = 0;
		break;
	case SAVEMODE:
		if ((S_flag & IO_RAW) != 0)
		{
			tty_set(COOKED);
			R_ignore = 0;
		}
		else
			++R_ignore;
		rc = 0;
		break;
	case RESTORE:
		if (R_ignore <= 0)
		{
			tty_set(RAWMODE);
		}
		else
			--R_ignore;
		rc = 0;
		break;
	default:
		rc = -1;
	}
	if (rc < 0)
		printex ("ioctl failure, tty_set: %d",cmd);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'userlist.c'" '(2130 characters)'
if test -f 'userlist.c'
then
	echo shar: will not over-write existing file "'userlist.c'"
else
cat << \SHAR_EOF > 'userlist.c'
/*
** vn news reader.
**
** userlist.c - generate user's list of articles
**
** see copyright disclaimer / history in vn.c source file
*/

#include <stdio.h>
#include "tune.h"
#include "node.h"
#include "page.h"
#include "vn.h"

extern PAGE Page;
extern char *List_sep;

static char Pattern[MAX_C] = "";

/*
	generate user list of articles - either article numbers
	are input directly (numeric list), or input is a search
	string - invoke regular expression library and examine titles
	search string "*" reserved for marked articles.  Strings may
	be prefixed with '!' for negation.
*/
userlist (list)
char *list;
{
	int i,j,anum[RECLEN/2],acount;
	char neg, *s, sbuf[MAX_C+1], *reg, *regex(), *regcmp(), *index(), *strtok();

	user_str (sbuf,"Articles or title search string : ",1,Pattern);
	if (sbuf[0] == '!')
	{
		neg = '!';
		s = sbuf+1;
	}
	else
	{
		neg = '\0';
		s = sbuf;
	}
	for (i=0; s[i] != '\0'; ++i)
	{
		if (index(List_sep,s[i]) == NULL)
		{
			if (s[i] < '0' || s[i] > '9')
				break;
		}
	}
	acount = 0;

	if (s[i] == '\0')
	{
		for (s = strtok(s,List_sep); s != NULL; s = strtok(NULL,List_sep))
		{
			anum[acount] = atoi(s);
			++acount;
		}
	}
	else
	{
		/* we save old input only if NOT a list of article numbers */
		strcpy(Pattern,sbuf);
		if (s[0] == ART_MARK)
		{
			for (i=0; i < Page.h.artnum; ++i)
			{
				if (Page.b[i].art_mark == ART_MARK)
				{
					anum[acount] = Page.b[i].art_id;
					++acount;
				}
			}
		}
		else
		{
			reg = regcmp(s,(char *) 0);
			if (reg != NULL)
			{
				for (i=0; i < Page.h.artnum; ++i)
				{
					if (regex(reg,Page.b[i].art_t) != NULL)
					{
						anum[acount] = Page.b[i].art_id;
						++acount;
					}
				}
				regfree (reg);
			}
			else
				preinfo ("bad regular expression syntax");
		}
	}

	/* algorithm is inefficient, but we're only handling a few numbers */
	*list = '\0';
	for (i=0; i < Page.h.artnum; ++i)
	{
		for (j=0; j < acount && anum[j] != Page.b[i].art_id; ++j)
			;
		if (neg == '!')
		{
			if (j < acount)
				continue;
		}
		else
		{
			if (j >= acount)
				continue;
		}
		sprintf (list,"%d ",Page.b[i].art_id);
		list += strlen(list);
	}
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'vnglob.c'" '(1473 characters)'
if test -f 'vnglob.c'
then
	echo shar: will not over-write existing file "'vnglob.c'"
else
cat << \SHAR_EOF > 'vnglob.c'
/*
** vn news reader.
**
** vnglob.c - global variables - see string.c also
**
** see copyright disclaimer / history in vn.c source file
*/

#include <stdio.h>
#include "config.h"
#include "head.h"
#include "tune.h"
#include "node.h"
#include "page.h"

/*
	global data structure
*/
NODE **Newsorder = NULL;	/* in order of fw_group calls */

char *Editor, *Ps1, *Printer;

int (*Massage)() = NULL;
int (*Headedit)() = NULL;
int (*Postfunc)() = NULL;
int (*Mailfunc)() = NULL;

char Erasekey, Killkey;		/* user keys from stty */
char *Orgdir;			/* .newsrc file, and original pwd */
char *Savefile = DEF_SAVE;	/* file in which to save articles */
char *Savedir;			/* default directory for saved articles */
char *Ccfile;			/* author_copy file, stored /bin/mail fmt */
char *Home;			/* user's home */

int Rot;	/* rotation */
int Headflag;	/* header printing flag */
int Digest;	/* if non-zero, digest article */
int More;	/* if non-zero, clear screen between each page.  Set by */
		/* user's MORE environment variable; if `-c', then set true */

char *Ku, *Kd, *Kl, *Kr;	/* Cursor movement capabilities */

/* character translation arrays for commands */
char Cxitop[128], Cxitor[128], Cxrtoi[128], Cxptoi[128];

/*
	cur_page - current page displayed;
	lrec - last record
	l_allow - lines allowed for article display
	c_allow - columns allowed
	ncount = newsorder index
*/
int Cur_page, Lrec, L_allow, C_allow, Ncount;

int Nounsub, Listfirst;
/*
	current page
*/
PAGE Page;
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0
-- 
For comp.sources.unix stuff, mail to sources at uunet.uu.net.



More information about the Comp.sources.unix mailing list