rn version 4.1 distribution kit (part 4 of 8)
Larry Wall
lwall at sdcrdcf.UUCP
Tue Sep 25 09:55:26 AEST 1984
#! /bin/sh
# Make a new directory for the rn sources, cd to it, and run kits 1 thru 8
# through sh. When all 8 kits have been run, read README.
echo "This is rn kit 4 (of 8). If kit 4 is complete, the line"
echo '"'"End of kit 4 (of 8)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
echo Extracting intrp.c
cat >intrp.c <<'!STUFFY!FUNK!'
/* $Header: intrp.c,v 4.1 84/09/24 11:57:13 lwall Exp $
*
* $Log: intrp.c,v $
* Revision 4.1 84/09/24 11:57:13 lwall
* Real baseline.
*
* Revision 4.0.1.4 84/09/19 17:08:13 lwall
* Ifdef'ed some stuff that should have been.
*
* Revision 4.0.1.3 84/09/12 17:36:37 lwall
* pwd.h now included by common.h.
*
* Revision 4.0.1.2 84/09/10 15:13:49 lwall
* Delinted.
*
* Revision 4.0.1.1 84/09/04 15:14:39 lwall
* LINKART option for Eunice sites.
*
* Revision 4.0 84/09/04 09:50:48 lwall
* Baseline for netwide release
*
*/
#include "EXTERN.h"
#include "common.h"
#include "util.h"
#include "search.h"
#include "head.h"
#include "rn.h"
#include "artsrch.h"
#include "ng.h"
#include "util.h"
#include "respond.h"
#include "rcstuff.h"
#include "bits.h"
#include "artio.h"
#include "INTERN.h"
#include "intrp.h"
char orgname[] = ORGNAME;
/* name of this site */
#ifdef GETHOSTNAME
char *hostname;
# undef SITENAME
# define SITENAME hostname
#else !GETHOSTNAME
# ifdef DOUNAME
# include <sys/utsname.h>
struct utsname uts;
# undef SITENAME
# define SITENAME uts.sysname
# else !DOUNAME
# ifdef PHOSTNAME
char *hostname;
# undef SITENAME
# define SITENAME hostname
# else !PHOSTNAME
# ifdef WHOAMI
# undef SITENAME
# define SITENAME sysname
# endif WHOAMI
# endif PHOSTNAME
# endif DOUNAME
#endif GETHOSTNAME
#ifdef TILDENAME
static char *tildename = Nullch;
static char *tildedir = Nullch;
#endif
char *realname INIT(Nullch); /* real name of sender from /etc/passwd */
char *dointerp();
char *getrealname();
void
intrp_init(tcbuf)
char *tcbuf;
{
char *getlogin();
lib = savestr(filexp(LIB));
rnlib = savestr(filexp(RNLIB));
spool = savestr(filexp(SPOOL)); /* usually /usr/spool/news */
getwd(tcbuf); /* find working directory name */
origdir = savestr(tcbuf); /* and remember it */
/* get environmental stuff */
/* get home directory */
homedir = getenv("HOME");
if (homedir == Nullch)
homedir = getenv("LOGDIR");
dotdir = getval("DOTDIR",homedir);
/* get the real name of the person (%N) */
strcpy(tcbuf,getrealname(getuid()));
realname = savestr(tcbuf);
/* get login name */
logname = getenv("USER");
if (logname == Nullch)
logname = getenv("LOGNAME");
#ifdef GETLOGIN
if (logname == Nullch)
logname = savestr(getlogin());
#endif
/* name of header file (%h) */
headname = savestr(filexp(HEADNAME));
/* name of this site (%H) */
#ifdef GETHOSTNAME
gethostname(buf,sizeof buf);
hostname = savestr(buf);
#else
#ifdef DOUNAME
/* get sysname */
uname(&uts);
#else
#ifdef PHOSTNAME
{
FILE *popen();
FILE *pipefp = popen(PHOSTNAME,"r");
fgets(buf,sizeof buf,tmpfp);
buf[strlen(buf)-1] = '\0'; /* wipe out newline */
hostname = savestr(buf);
pclose(pipefp);
}
#endif
#endif
#endif
sitename = savestr(SITENAME);
}
/* expand filename via %, ~, and $ interpretation */
/* returns pointer to static area */
/* Note that there is a 1-deep cache of ~name interpretation */
char *
filexp(s)
register char *s;
{
static char filename[MAXFILENAME];
char scrbuf[MAXFILENAME];
register char *d;
#ifdef DEBUGGING
if (debug & DEB_FILEXP)
printf("< %s\n",s);
#endif
interp(filename,s); /* interpret any % escapes */
#ifdef DEBUGGING
if (debug & DEB_FILEXP)
printf("%% %s\n",filename);
#endif
s = filename;
if (*s == '~') { /* does destination start with ~? */
if (!*(++s) || *s == '/') {
sprintf(scrbuf,"%s%s",homedir,s);
/* swap $HOME for it */
#ifdef DEBUGGING
if (debug & DEB_FILEXP)
printf("~ %s\n",scrbuf);
#endif
strcpy(filename,scrbuf);
}
else {
#ifdef TILDENAME
for (d=scrbuf; isalnum(*s); s++,d++)
*d = *s;
*d = '\0';
if (tildedir && strEQ(tildename,scrbuf)) {
strcpy(scrbuf,tildedir);
#ifdef DEBUGGING
if (debug & DEB_FILEXP)
printf("r %s %s\n",tildename,tildedir);
#endif
}
else {
if (tildename) {
free(tildename);
free(tildedir);
tildedir = Nullch;
tildename = savestr(scrbuf);
}
#ifdef GETPWENT /* getpwnam() is not the paragon of efficiency */
{
struct passwd *getpwnam();
struct passwd *pwd = getpwnam(tildename);
sprintf(scrbuf,"%s%s",pwd->pw_dir,s);
tildedir = savestr(pwd->pw_dir);
#ifdef NEWSADMIN
if (strEQ(newsadmin,tildename))
newsuid = atoi(pwd->pw_uid);
#endif
strcpy(filename,scrbuf);
#ifdef GETPWENT
endpwent();
#endif
}
#else /* this will run faster, and is less D space */
{ /* just be sure LOGDIRFIELD is correct */
FILE *pfp = fopen("/etc/passwd","r");
char tmpbuf[512];
int i;
while (fgets(tmpbuf,512,pfp) != Nullch) {
d = cpytill(scrbuf,tmpbuf,':');
#ifdef DEBUGGING
if (debug & DEB_FILEXP)
printf("p %s\n",tmpbuf);
#endif
if (strEQ(scrbuf,tildename)) {
#ifdef NEWSADMIN
if (strEQ(newsadmin,tildename))
newsuid = atoi(index(d,':')+1);
#endif
for (i=LOGDIRFIELD-2; i; i--) {
if (d)
d = index(d+1,':');
}
if (d) {
cpytill(scrbuf,d+1,':');
tildedir = savestr(scrbuf);
strcat(scrbuf,s);
strcpy(filename,scrbuf);
}
break;
}
}
fclose(pfp);
}
#endif
}
#else !TILDENAME
#ifdef VERBOSE
IF(verbose)
fputs("~loginname not implemented.\n",stdout);
ELSE
#endif
#ifdef TERSE
fputs("~login not impl.\n",stdout);
#endif
#endif
}
}
else if (*s == '$') { /* starts with some env variable? */
d = scrbuf;
*d++ = '%';
if (s[1] == '{')
strcpy(d,s+2);
else {
*d++ = '{';
for (s++; isalnum(*s); s++) *d++ = *s;
/* skip over token */
*d++ = '}';
strcpy(d,s);
}
#ifdef DEBUGGING
if (debug & DEB_FILEXP)
printf("$ %s\n",scrbuf);
#endif
interp(filename,scrbuf); /* this might do some extra '%'s but */
/* that is how the Mercedes Benz */
}
#ifdef DEBUGGING
if (debug & DEB_FILEXP)
printf("> %s\n",filename);
#endif
return filename;
}
/* interpret interpolations */
char *
dointerp(dest,pattern,stoppers)
register char *dest;
register char *pattern;
char *stoppers;
{
char *subj_buf = Nullch;
char *ngs_buf = Nullch;
char *refs_buf = Nullch;
char *artid_buf = Nullch;
char *reply_buf = Nullch;
char *from_buf = Nullch;
char *path_buf = Nullch;
char *follow_buf = Nullch;
char *dist_buf = Nullch;
char *line_buf = Nullch;
register char *s, *h;
register int i;
char scrbuf[512];
bool upper = FALSE;
bool lastcomp = FALSE;
while (*pattern && (!stoppers || !index(stoppers,*pattern))) {
if (*pattern == '%') {
upper = FALSE;
lastcomp = FALSE;
for (s=Nullch; !s; ) {
switch (*++pattern) {
case '^':
upper = TRUE;
break;
case '`':
lastcomp = TRUE;
break;
case '/':
#ifdef ARTSRCH
s = scrbuf;
if (!index("/?g",pattern[-2]))
*s++ = '/';
strcpy(s,lastpat);
s += strlen(s);
if (pattern[-2] != 'g') {
if (index("/?",pattern[-2]))
*s++ = pattern[-2];
else
*s++ = '/';
if (art_howmuch == 1)
*s++ = 'h';
else if (art_howmuch == 2)
*s++ = 'a';
if (art_doread)
*s++ = 'r';
}
*s = '\0';
s = scrbuf;
#else
s = nullstr;
#endif
break;
case '{':
pattern = cpytill(scrbuf,pattern+1,'}');
if (s = index(scrbuf,'-'))
*s++ = '\0';
else
s = nullstr;
s = getval(scrbuf,s);
break;
case '[':
pattern = cpytill(scrbuf,pattern+1,']');
i = set_line_type(scrbuf,scrbuf+strlen(scrbuf));
if (line_buf)
free(line_buf);
s = line_buf = fetchlines(art,i);
break;
#ifdef CONDSUB
case '(': {
COMPEX *oldbra_compex = bra_compex;
COMPEX cond_compex;
char rch;
bool matched;
init_compex(&cond_compex);
pattern = dointerp(dest,pattern+1,"!=");
rch = *pattern;
if (rch == '!')
pattern++;
if (*pattern != '=')
goto getout;
pattern = cpytill(scrbuf,pattern+1,'?');
if (!*pattern)
goto getout;
if (s = compile(&cond_compex,scrbuf,TRUE,TRUE)) {
printf("%s: %s\n",scrbuf,s);
pattern += strlen(pattern);
goto getout;
}
matched = (execute(&cond_compex,dest) != Nullch);
if (cond_compex.nbra) /* were there brackets? */
bra_compex = &cond_compex;
if (matched==(rch == '=')) {
pattern = dointerp(dest,pattern+1,":)");
if (*pattern == ':')
pattern = dointerp(scrbuf,pattern+1,")");
}
else {
pattern = dointerp(scrbuf,pattern+1,":)");
if (*pattern == ':')
pattern++;
pattern = dointerp(dest,pattern,")");
}
s = dest;
bra_compex = oldbra_compex;
free_compex(&cond_compex);
break;
}
#endif
case '~':
s = homedir;
break;
case '.':
s = dotdir;
break;
case '$':
s = scrbuf;
sprintf(s,"%d",getpid());
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
#ifdef CONDSUB
s = getbracket(bra_compex,*pattern - '0');
#else
s = nullstr;
#endif
break;
case 'a':
s = scrbuf;
sprintf(s,"%ld",(long)art);
break;
case 'A':
#ifdef LINKART
s = linkartname; /* so Eunice people get right file */
#else
s = scrbuf;
sprintf(s,"%s/%s/%ld",spool,ngdir,(long)art);
#endif
break;
case 'b':
s = savedest;
break;
case 'B':
s = scrbuf;
sprintf(s,"%ld",(long)savefrom);
break;
case 'c':
s = ngdir;
break;
case 'C':
s = ngname;
break;
case 'd':
s = scrbuf;
sprintf(s,"%s/%s",spool,ngdir);
break;
case 'D':
s = dist_buf = fetchlines(art,DIST_LINE);
break;
case 'f': /* from line */
#ifdef ASYNC_PARSE
parse_maybe(art);
#endif
if (htype[REPLY_LINE].ht_minpos >= 0) {
/* was there a reply line? */
if (!(s=reply_buf))
s = reply_buf = fetchlines(art,REPLY_LINE);
}
else if (!(s = from_buf))
s = from_buf = fetchlines(art,FROM_LINE);
break;
case 'F':
#ifdef ASYNC_PARSE
parse_maybe(art);
#endif
if (htype[FOLLOW_LINE].ht_minpos >= 0)
/* is there a Followup-To line? */
s = follow_buf = fetchlines(art,FOLLOW_LINE);
else {
int off;
s = ngs_buf = fetchlines(art,NGS_LINE);
if (h = instr(s,"net.general")) {
off = h-s;
strncpy(scrbuf,s,off+4);
strcpy(scrbuf+off+4,"followup");
safecpy(scrbuf+off+12,h+11,sizeof(scrbuf));
s = scrbuf;
}
}
break;
case 'h': /* header file name */
s = headname;
break;
case 'H': /* host name */
s = sitename;
break;
case 'i':
if (!(s=artid_buf))
s = artid_buf = fetchlines(art,ARTID_LINE);
if (*s != '<') {
sprintf(scrbuf,"<%s>",artid_buf);
s = scrbuf;
}
break;
case 'l': /* rn library */
#ifdef NEWSADMIN
s = newsadmin;
#else
s = "???";
#endif
break;
case 'L': /* login id */
s = logname;
break;
case 'M':
#ifdef DELAYMARK
sprintf(scrbuf,"%ld",(long)dmcount);
s = scrbuf;
#else
s = nullstr;
#endif
break;
case 'n': /* newsgroups */
s = ngs_buf = fetchlines(art,NGS_LINE);
break;
case 'N': /* full name */
s = getval("NAME",realname);
break;
case 'o': /* organization */
s = getval("ORGANIZATION",orgname);
#ifdef ORGFILE
if (*s == '/') {
FILE *ofp = fopen(s,"r");
if (ofp) {
fgets(scrbuf,sizeof scrbuf,ofp);
fclose(ofp);
s = scrbuf;
s[strlen(s)-1] = '\0';
}
}
#endif
break;
case 'O':
s = origdir;
break;
case 'p':
s = cwd;
break;
case 'P':
s = spool;
break;
case 'r':
#ifdef ASYNC_PARSE
parse_maybe(art);
#endif
if (htype[REFS_LINE].ht_minpos >= 0) {
refs_buf = fetchlines(art,REFS_LINE);
refscpy(scrbuf,refs_buf);
}
else
*scrbuf = '\0';
s = rindex(scrbuf,'<');
break;
case 'R':
#ifdef ASYNC_PARSE
parse_maybe(art);
#endif
if (htype[REFS_LINE].ht_minpos >= 0) {
refs_buf = fetchlines(art,REFS_LINE);
refscpy(scrbuf,refs_buf);
}
else
*scrbuf = '\0';
if (!artid_buf)
artid_buf = fetchlines(art,ARTID_LINE);
if (artid_buf[0] == '<')
safecat(scrbuf,artid_buf,sizeof(scrbuf));
else {
char tmpbuf[64];
sprintf(tmpbuf,"<%s>",artid_buf);
safecat(scrbuf,tmpbuf,sizeof(scrbuf));
}
s = scrbuf;
break;
case 's':
if (!(s=subj_buf))
s = subj_buf = fetchsubj(art,TRUE,TRUE);
/* get subject handy */
while ((*s=='R'||*s=='r')&&(s[1]=='E'||s[1]=='e')&&s[2]==':') {
/* skip extra Re: */
s += 3;
if (*s == ' ')
s++;
}
if (h = instr(s,"- (nf"))
*h = '\0';
break;
case 'S':
if (!(s=subj_buf))
s = subj_buf = fetchsubj(art,TRUE,TRUE);
/* get subject handy */
if ((*s=='R'||*s=='r')&&(s[1]=='E'||s[1]=='e')&&s[2]==':') {
/* skip extra Re: */
s += 3;
if (*s == ' ')
s++;
}
break;
case 't':
case 'T':
#ifdef ASYNC_PARSE
parse_maybe(art);
#endif
if (htype[REPLY_LINE].ht_minpos >= 0) {
/* was there a reply line? */
if (!(s=reply_buf))
s = reply_buf = fetchlines(art,REPLY_LINE);
}
else if (!(s = from_buf))
s = from_buf = fetchlines(art,FROM_LINE);
if (*pattern == 'T') {
if (htype[PATH_LINE].ht_minpos >= 0) {
/* should we substitute path? */
s = path_buf = fetchlines(art,PATH_LINE);
}
i = strlen(sitename);
if (strnEQ(sitename,s,i) && s[i] == '!')
s += i + 1;
}
if ((h=index(s,'(')) != Nullch)
/* strip garbage from end */
*(h-1) = '\0';
else if ((h=index(s,'<')) != Nullch) {
/* or perhaps from beginning */
s = h+1;
if ((h=index(s,'>')) != Nullch)
*h = '\0';
}
break;
case 'u':
sprintf(scrbuf,"%ld",(long)toread[ng]);
s = scrbuf;
break;
case 'U':
sprintf(scrbuf,"%ld",
(long)(((ART_NUM)toread[ng]) - 1 + was_read(art)));
s = scrbuf;
break;
case 'x': /* rn library */
s = lib;
break;
case 'X': /* rn library */
s = rnlib;
break;
default:
*dest++ = *pattern;
s = nullstr;
break;
}
}
if (!s)
s = nullstr;
pattern++;
if (upper || lastcomp) {
char *t;
if (s != scrbuf) {
strcpy(scrbuf,s);
s = scrbuf;
}
if (upper || !(t=rindex(s,'/')))
t = s;
while (*t && !isalpha(*t))
t++;
if (islower(*t))
*t = toupper(*t);
}
if (s == dest) {
while (*dest)
dest++;
}
else {
while (*s)
*dest++ = *s++;
}
}
else if (*pattern == '\\') {
++pattern; /* skip backslash */
i = *pattern; /* get char into a register */
/* this used to be a switch but the if may save space */
if (i >= '0' && i <= '7') {
i = 1;
while (i < 01000 && *pattern >= '0' && *pattern <= '7') {
i <<= 3;
i += *pattern++ - '0';
}
*dest++ = i & 0377;
--pattern;
}
else if (i == 'b')
*dest++ = '\b';
else if (i == 'f')
*dest++ = '\f';
else if (i == 'n')
*dest++ = '\n';
else if (i == 'r')
*dest++ = '\r';
else if (i == 't')
*dest++ = '\t';
else
*dest++ = *pattern;
pattern++;
}
else
*dest++ = *pattern++;
}
*dest = '\0';
getout:
if (subj_buf != Nullch) /* return any checked out storage */
free(subj_buf);
if (ngs_buf != Nullch)
free(ngs_buf);
if (refs_buf != Nullch)
free(refs_buf);
if (artid_buf != Nullch)
free(artid_buf);
if (reply_buf != Nullch)
free(reply_buf);
if (from_buf != Nullch)
free(from_buf);
if (path_buf != Nullch)
free(path_buf);
if (follow_buf != Nullch)
free(follow_buf);
if (dist_buf != Nullch)
free(dist_buf);
if (line_buf != Nullch)
free(line_buf);
return pattern; /* where we left off */
}
void
interp(dest,pattern)
char *dest;
char *pattern;
{
dointerp(dest,pattern,Nullch);
}
/* copy a references line, normalizing as we go */
void
refscpy(dest,src)
register char *dest, *src;
{
register char *dot, *at, *beg;
char tmpbuf[64];
while (*src) {
if (*src != '<') {
*dest++ = '<';
at = dot = Nullch;
beg = src;
while (*src && *src != ' ' && *src != ',') {
if (*src == '.')
dot = src;
else if (*src == '@')
at = src;
*dest++ = *src++;
}
if (dot && !at) {
*dest = *dot++ = '\0';
sprintf(tmpbuf,"%s@%s.UUCP",dot,beg);
strcpy(dest,tmpbuf);
dest = dest + strlen(dest);
}
*dest++ = '>';
}
else {
while (*src && (*dest++ = *src++) != '>') ;
}
while (*src == ' ' || *src == ',') src++;
if (*src)
*dest++ = ' ';
}
*dest = '\0';
}
/* get the person's real name from /etc/passwd */
/* (string is overwritten, so it must be copied) */
char *
getrealname(uid)
int uid;
{
char *s, *c;
#ifdef PASSNAMES
#ifdef GETPWENT
struct passwd *pwd = getpwuid(uid);
s = pwd->pw_gcos;
#else
char tmpbuf[512];
int i;
getpw(uid, tmpbuf);
for (s=tmpbuf, i=GCOSFIELD-1; i; i--) {
if (s)
s = index(s,':')+1;
}
if (!s)
return nullstr;
cpytill(tmpbuf,s,':');
s = tmpbuf;
#endif
#ifdef BERKNAMES
#ifdef BERKJUNK
while (*s && !isalnum(*s) && *s != '&') s++;
#endif
if ((c = index(s, ',')) != Nullch)
*c = '\0';
if ((c = index(s, ';')) != Nullch)
*c = '\0';
s = cpytill(buf,s,'&');
if (*s == '&') { /* whoever thought this one up was */
strcat(buf,logname); /* in the middle of the night */
strcat(buf,s+1); /* before the morning after */
if (islower(*buf))
*buf = toupper(*buf); /* gack and double gack */
}
#else
if ((c = index(s, '(')) != Nullch)
*c = '\0';
if ((c = index(s, '-')) != Nullch)
s = c;
strcpy(buf,tmpbuf);
#endif
#ifdef GETPWENT
endpwent();
#endif
return buf; /* return something static */
#else
if ((tmpfp=fopen(filexp(FULLNAMEFILE),"r")) != Nullfp) {
fgets(buf,sizeof buf,tmpfp);
fclose(tmpfp);
buf[strlen(buf)-1] = '\0';
return buf;
}
return "PUT YOUR NAME HERE";
#endif
}
!STUFFY!FUNK!
echo Extracting search.c
cat >search.c <<'!STUFFY!FUNK!'
/* $Header: search.c,v 4.1 84/09/24 12:09:45 lwall Exp $
*
* $Log: search.c,v $
* Revision 4.1 84/09/24 12:09:45 lwall
* Real baseline.
*
* Revision 4.0.1.3 84/09/12 17:34:48 lwall
* Moved some includes to common.h.
*
* Revision 4.0.1.2 84/09/10 15:29:52 lwall
* Delinted.
*
* Revision 4.0.1.1 84/09/05 10:38:46 lwall
* Changed CEOF to CEND to avoid conflict with ttychars.h.
*
* Revision 4.0 84/09/04 09:52:33 lwall
* Baseline for netwide release
*
*/
/* string search routines */
/* Copyright (c) 1981,1980 James Gosling */
/* Modified Aug. 12, 1981 by Tom London to include regular expressions
as in ed. RE stuff hacked over by jag to correct a few major problems,
mainly dealing with searching within the buffer rather than copying
each line to a separate array. Newlines can now appear in RE's */
/* Ripped to shreds and glued back together to make a search package,
* July 6, 1984, by Larry Wall. (If it doesn't work, it's probably my fault.)
* Changes include:
* Buffer, window, and mlisp stuff gone.
* Translation tables reduced to 1 table.
* Expression buffer is now dynamically allocated.
* Character classes now implemented with a bitmap.
*/
#include "EXTERN.h"
#include "common.h"
#include "util.h"
#include "INTERN.h"
#include "search.h"
#ifndef BITSPERBYTE
#define BITSPERBYTE 8
#endif
#define BMAPSIZ (127 / BITSPERBYTE + 1)
/* meta characters in the "compiled" form of a regular expression */
#define CBRA 2 /* \( -- begin bracket */
#define CCHR 4 /* a vanilla character */
#define CDOT 6 /* . -- match anything except a newline */
#define CCL 8 /* [...] -- character class */
#define NCCL 10 /* [^...] -- negated character class */
#define CDOL 12 /* $ -- matches the end of a line */
#define CEND 14 /* The end of the pattern */
#define CKET 16 /* \) -- close bracket */
#define CBACK 18 /* \N -- backreference to the Nth bracketed
string */
#define CIRC 20 /* ^ matches the beginning of a line */
#define WORD 32 /* matches word character \w */
#define NWORD 34 /* matches non-word characer \W */
#define WBOUND 36 /* matches word boundary \b */
#define NWBOUND 38 /* matches non-(word boundary) \B */
#define STAR 01 /* * -- Kleene star, repeats the previous
REas many times as possible; the value
ORs with the other operator types */
#define ASCSIZ 0200
typedef char TRANSTABLE[ASCSIZ];
static TRANSTABLE trans = {
0000,0001,0002,0003,0004,0005,0006,0007,
0010,0011,0012,0013,0014,0015,0016,0017,
0020,0021,0022,0023,0024,0025,0026,0027,
0030,0031,0032,0033,0034,0035,0036,0037,
0040,0041,0042,0043,0044,0045,0046,0047,
0050,0051,0052,0053,0054,0055,0056,0057,
0060,0061,0062,0063,0064,0065,0066,0067,
0070,0071,0072,0073,0074,0075,0076,0077,
0100,0101,0102,0103,0104,0105,0106,0107,
0110,0111,0112,0113,0114,0115,0116,0117,
0120,0121,0122,0123,0124,0125,0126,0127,
0130,0131,0132,0133,0134,0135,0136,0137,
0140,0141,0142,0143,0144,0145,0146,0147,
0150,0151,0152,0153,0154,0155,0156,0157,
0160,0161,0162,0163,0164,0165,0166,0167,
0170,0171,0172,0173,0174,0175,0176,0177,
};
static bool folding = FALSE;
static int err;
static char *FirstCharacter;
void
search_init()
{
#ifdef UNDEF
register int i;
for (i = 0; i < ASCSIZ; i++)
trans[i] = i;
#else
;
#endif
}
void
init_compex(compex)
register COMPEX *compex;
{
/* the following must start off zeroed */
compex->eblen = 0;
compex->brastr = Nullch;
}
void
free_compex(compex)
register COMPEX *compex;
{
if (compex->eblen) {
free(compex->expbuf);
compex->eblen = 0;
}
if (compex->brastr) {
free(compex->brastr);
compex->brastr = Nullch;
}
}
static char *gbr_str = Nullch;
static int gbr_siz = 0;
char *
getbracket(compex,n)
register COMPEX *compex;
int n;
{
int length = compex->braelist[n] - compex->braslist[n];
if (!compex->nbra || n > compex->nbra || !compex->braelist[n] || length<0)
return nullstr;
growstr(&gbr_str, &gbr_siz, length+1);
safecpy(gbr_str, compex->braslist[n], length+1);
return gbr_str;
}
void
case_fold(which)
int which;
{
register int i;
if (which != folding) {
if (which) {
for (i = 'A'; i <= 'Z'; i++)
trans[i] = tolower(i);
}
else {
for (i = 'A'; i <= 'Z'; i++)
trans[i] = i;
}
folding = which;
}
}
/* Compile the given regular expression into a [secret] internal format */
char *
compile (compex, strp, RE, fold)
register COMPEX *compex;
register char *strp;
int RE;
int fold;
{
register int c;
register char *ep;
char *lastep;
char bracket[NBRA],
*bracketp;
char **alt = compex->alternatives;
char *retmes = "Badly formed search string";
case_fold(compex->do_folding = fold);
if (!compex->eblen) {
compex->expbuf = safemalloc(84);
compex->eblen = 80;
}
ep = compex->expbuf; /* point at expression buffer */
*alt++ = ep; /* first alternative starts here */
bracketp = bracket; /* first bracket goes here */
if (*strp == 0) { /* nothing to compile? */
if (*ep == 0) /* nothing there yet? */
return "Null search string";
return Nullch; /* just keep old expression */
}
compex->nbra = 0; /* no brackets yet */
lastep = 0;
for (;;) {
if (ep - compex->expbuf >= compex->eblen)
grow_eb(compex);
c = *strp++; /* fetch next char of pattern */
if (c == 0) { /* end of pattern? */
if (bracketp != bracket) { /* balanced brackets? */
#ifdef VERBOSE
retmes = "Unbalanced parens";
#endif
goto cerror;
}
*ep++ = CEND; /* terminate expression */
*alt++ = 0; /* terminal alternative list */
/*
compex->eblen = ep - compex->expbuf + 1;
compex->expbuf = saferealloc(compex->expbuf,compex->eblen+4); */
return Nullch; /* return success */
}
if (c != '*')
lastep = ep;
if (!RE) { /* just a normal search string? */
*ep++ = CCHR; /* everything is a normal char */
*ep++ = c;
}
else /* it is a regular expression */
switch (c) {
case '\\': /* meta something */
switch (c = *strp++) {
case '(':
if (compex->nbra >= NBRA) {
#ifdef VERBOSE
retmes = "Too many parens";
#endif
goto cerror;
}
*bracketp++ = ++compex->nbra;
*ep++ = CBRA;
*ep++ = compex->nbra;
break;
case '|':
if (bracketp>bracket) {
#ifdef VERBOSE
retmes = "No \\| in parens"; /* Alas! */
#endif
goto cerror;
}
*ep++ = CEND;
*alt++ = ep;
break;
case ')':
if (bracketp <= bracket) {
#ifdef VERBOSE
retmes = "Unmatched right paren";
#endif
goto cerror;
}
*ep++ = CKET;
*ep++ = *--bracketp;
break;
case 'w':
*ep++ = WORD;
break;
case 'W':
*ep++ = NWORD;
break;
case 'b':
*ep++ = WBOUND;
break;
case 'B':
*ep++ = NWBOUND;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
*ep++ = CBACK;
*ep++ = c - '0';
break;
default:
*ep++ = CCHR;
if (c == '\0')
goto cerror;
*ep++ = c;
break;
}
break;
case '.':
*ep++ = CDOT;
continue;
case '*':
if (lastep == 0 || *lastep == CBRA || *lastep == CKET
|| *lastep == CIRC
|| (*lastep&STAR)|| *lastep>NWORD)
goto defchar;
*lastep |= STAR;
continue;
case '^':
if (ep != compex->expbuf && ep[-1] != CEND)
goto defchar;
*ep++ = CIRC;
continue;
case '$':
if (*strp != 0 && (*strp != '\\' || strp[1] != '|'))
goto defchar;
*ep++ = CDOL;
continue;
case '[': { /* character class */
register int i;
if (ep - compex->expbuf >= compex->eblen - BMAPSIZ)
grow_eb(compex); /* reserve bitmap */
for (i = BMAPSIZ; i; --i)
ep[i] = 0;
if ((c = *strp++) == '^') {
c = *strp++;
*ep++ = NCCL; /* negated */
}
else
*ep++ = CCL; /* normal */
i = 0; /* remember oldchar */
do {
if (c == '\0') {
#ifdef VERBOSE
retmes = "Missing ]";
#endif
goto cerror;
}
if (*strp == '-' && *(++strp))
i = *strp++;
else
i = c;
while (c <= i) {
ep[c / BITSPERBYTE] |= 1 << (c % BITSPERBYTE);
if (fold && isalpha(c))
ep[(c ^ 32) / BITSPERBYTE] |=
1 << ((c ^ 32) % BITSPERBYTE);
/* set the other bit too */
c++;
}
} while ((c = *strp++) != ']');
ep += BMAPSIZ;
continue;
}
defchar:
default:
*ep++ = CCHR;
*ep++ = c;
}
}
cerror:
compex->expbuf[0] = 0;
compex->nbra = 0;
return retmes;
}
void
grow_eb(compex)
register COMPEX *compex;
{
compex->eblen += 80;
compex->expbuf = saferealloc(compex->expbuf, (MEM_SIZE)compex->eblen + 4);
}
char *
execute (compex, addr)
register COMPEX *compex;
char *addr;
{
register char *p1 = addr;
register char *trt = trans;
register int c;
if (addr == Nullch)
return Nullch;
if (compex->nbra) { /* any brackets? */
for (c = 0; c <= compex->nbra; c++)
compex->braslist[c] = compex->braelist[c] = Nullch;
if (compex->brastr)
free(compex->brastr);
compex->brastr = savestr(p1); /* in case p1 is not static */
p1 = compex->brastr; /* ! */
}
case_fold(compex->do_folding); /* make sure table is correct */
FirstCharacter = p1; /* for ^ tests */
if (compex->expbuf[0] == CCHR && !compex->alternatives[1]) {
c = trt[compex->expbuf[1]]; /* fast check for first character */
do {
if (trt[*p1] == c && advance (compex, p1, compex->expbuf))
return p1;
p1++;
} while (*p1 && !err);
return Nullch;
}
else { /* regular algorithm */
do {
register char **alt = compex->alternatives;
while (*alt) {
if (advance (compex, p1, *alt++))
return p1;
}
p1++;
} while (*p1 && !err);
return Nullch;
}
}
/* advance the match of the regular expression starting at ep along the
string lp, simulates an NDFSA */
bool
advance (compex, lp, ep)
register COMPEX *compex;
register char *ep;
register char *lp;
{
register char *curlp;
register char *trt = trans;
register int i;
while ((*ep & STAR) || *lp || *ep == CIRC || *ep == CKET)
switch (*ep++) {
case CCHR:
if (trt[*ep++] != trt[*lp]) return FALSE;
lp++;
continue;
case CDOT:
if (*lp == '\n') return FALSE;
lp++;
continue;
case CDOL:
if (!*lp || *lp == '\n')
continue;
return FALSE;
case CIRC:
if (lp == FirstCharacter || lp[-1]=='\n')
continue;
return FALSE;
case WORD:
if (isalnum(*lp)) {
lp++;
continue;
}
return FALSE;
case NWORD:
if (!isalnum(*lp)) {
lp++;
continue;
}
return FALSE;
case WBOUND:
if ((lp == FirstCharacter || !isalnum(lp[-1])) !=
(!*lp || !isalnum(*lp)) )
continue;
return FALSE;
case NWBOUND:
if ((lp == FirstCharacter || !isalnum(lp[-1])) ==
(!*lp || !isalnum(*lp)))
continue;
return FALSE;
case CEND:
return TRUE;
case CCL:
if (cclass (ep, *lp, 1)) {
ep += BMAPSIZ;
lp++;
continue;
}
return FALSE;
case NCCL:
if (cclass (ep, *lp, 0)) {
ep += BMAPSIZ;
lp++;
continue;
}
return FALSE;
case CBRA:
compex->braslist[*ep++] = lp;
continue;
case CKET:
i = *ep++;
compex->braelist[i] = lp;
compex->braelist[0] = lp;
compex->braslist[0] = compex->braslist[i];
continue;
case CBACK:
if (compex->braelist[i = *ep++] == 0) {
fputs("bad braces\n",stdout);
err = TRUE;
return FALSE;
}
if (backref (compex, i, lp)) {
lp += compex->braelist[i] - compex->braslist[i];
continue;
}
return FALSE;
case CBACK | STAR:
if (compex->braelist[i = *ep++] == 0) {
fputs("bad braces\n",stdout);
err = TRUE;
return FALSE;
}
curlp = lp;
while (backref (compex, i, lp)) {
lp += compex->braelist[i] - compex->braslist[i];
}
while (lp >= curlp) {
if (advance (compex, lp, ep))
return TRUE;
lp -= compex->braelist[i] - compex->braslist[i];
}
continue;
case CDOT | STAR:
curlp = lp;
while (*lp++ && lp[-1] != '\n');
goto star;
case WORD | STAR:
curlp = lp;
while (*lp++ && isalnum(lp[-1]));
goto star;
case NWORD | STAR:
curlp = lp;
while (*lp++ && !isalnum(lp[-1]));
goto star;
case CCHR | STAR:
curlp = lp;
while (*lp++ && trt[lp[-1]] == trt[*ep]);
ep++;
goto star;
case CCL | STAR:
case NCCL | STAR:
curlp = lp;
while (*lp++ && cclass (ep, lp[-1], ep[-1] == (CCL | STAR)));
ep += BMAPSIZ;
goto star;
star:
do {
lp--;
if (advance (compex, lp, ep))
return TRUE;
} while (lp > curlp);
return FALSE;
default:
fputs("Badly compiled pattern\n",stdout);
err = TRUE;
return -1;
}
if (*ep == CEND || *ep == CDOL) {
return TRUE;
}
return FALSE;
}
bool
backref (compex, i, lp)
register COMPEX *compex;
register int i;
register char *lp;
{
register char *bp;
bp = compex->braslist[i];
while (*lp && *bp == *lp) {
bp++;
lp++;
if (bp >= compex->braelist[i])
return TRUE;
}
return FALSE;
}
bool
cclass (set, c, af)
register char *set;
register int c;
{
c &= 0177;
#if BITSPERBYTE == 8
if (set[c >> 3] & 1 << (c & 7))
#else
if (set[c / BITSPERBYTE] & 1 << (c % BITSPERBYTE))
#endif
return af;
return !af;
}
!STUFFY!FUNK!
echo Extracting term.c
cat >term.c <<'!STUFFY!FUNK!'
/* $Header: term.c,v 4.1 84/09/24 12:10:42 lwall Exp $
*
* $Log: term.c,v $
* Revision 4.1 84/09/24 12:10:42 lwall
* Real baseline.
*
* Revision 4.0.1.4 84/09/24 10:27:07 lwall
* print_lines() did not do fireworks suppression right.
*
* Revision 4.0.1.3 84/09/19 17:12:36 lwall
* Ifdef'ed some stuff that should have been.
*
* Revision 4.0.1.2 84/09/12 17:22:14 lwall
* ifdef usg -> ifdef TERMIO.
*
* Revision 4.0.1.1 84/09/10 15:33:08 lwall
* Delinted.
*
* Revision 4.0 84/09/04 09:52:51 lwall
* Baseline for netwide release
*
*/
#include "EXTERN.h"
#include "common.h"
#include "util.h"
#include "final.h"
#include "help.h"
#include "cheat.h"
#include "intrp.h"
#include "INTERN.h"
#include "term.h"
char ERASECH; /* rubout character */
char KILLCH; /* line delete character */
char tcarea[TCSIZE]; /* area for "compiled" termcap strings */
/* terminal initialization */
void
term_init(tcbuf)
char *tcbuf; /* temp area for "uncompiled" termcap entry */
{
char *tmpaddr;
int status;
#ifndef read_tty
/* do no delay reads on something that always gets closed on exit */
devtty = open("/dev/tty",0);
fcntl(devtty,F_SETFL,O_NDELAY);
#endif
savetty(); /* remember current tty state */
#ifdef TERMIO
ospeed = _tty.c_cflag & CBAUD; /* for tputs() */
ERASECH = _tty.c_cc[VERASE]; /* for finish_command() */
KILLCH = _tty.c_cc[VKILL]; /* for finish_command() */
#else
ospeed = _tty.sg_ospeed; /* for tputs() */
ERASECH = _tty.sg_erase; /* for finish_command() */
KILLCH = _tty.sg_kill; /* for finish_command() */
#endif
noecho(); /* turn off echo */
crmode(); /* enter cbreak mode */
/* get all that good termcap stuff */
#ifdef HAVETERMLIB
status = tgetent(tcbuf,getenv("TERM")); /* get termcap entry */
if (status < 1) {
#ifdef VERBOSE
printf("No termcap %s found.\n", status ? "file" : "entry");
#else
fputs("Termcap botch\n",stdout)
#endif
finalize(1);
}
tmpaddr = tcarea; /* set up strange tgetstr pointer */
tgetstr("pc",&tmpaddr); /* get pad character */
PC = *tcarea; /* get it where tputs wants it */
if (!tgetflag("bs")) { /* is backspace not used? */
BC = tmpaddr; /* find out what is */
tgetstr("bc",&tmpaddr);
}
else
BC = "\010"; /* make a backspace handy */
UP = tmpaddr; /* move up a line */
tgetstr("up",&tmpaddr);
if (!*UP) /* no UP string? */
marking = 0; /* disable any marking */
if (muck_up_clear) /* this is for weird HPs */
CL = "\n\n\n\n";
else {
CL = tmpaddr; /* get clear string */
tgetstr("cl",&tmpaddr);
}
CE = tmpaddr; /* clear to end of line string */
tgetstr("ce",&tmpaddr);
SO = tmpaddr; /* begin standout */
tgetstr("so",&tmpaddr);
SE = tmpaddr; /* end standout */
tgetstr("se",&tmpaddr);
if ((SG = tgetnum("sg"))<0)
SG = 0; /* blanks left by SG, SE */
US = tmpaddr; /* start underline */
tgetstr("us",&tmpaddr);
UE = tmpaddr; /* end underline */
tgetstr("ue",&tmpaddr);
if ((UG = tgetnum("ug"))<0)
UG = 0; /* blanks left by US, UE */
if (*US)
UC = nullstr; /* UC must not be NULL */
else {
UC = tmpaddr; /* underline a character */
tgetstr("uc",&tmpaddr);
}
if (!*US && !*UC) { /* no underline mode? */
US = SO; /* substitute standout mode */
UE = SE;
UG = SG;
}
LINES = tgetnum("li"); /* lines per page */
COLS = tgetnum("co"); /* columns on page */
AM = tgetflag("am"); /* terminal wraps automatically? */
XN = tgetflag("xn"); /* then eats next newline? */
#else
?????? /* Roll your own... */
#endif
if (LINES > 0) { /* is this a crt? */
if (!initlines) /* no -i? */
if (ospeed >= B9600) /* whole page at >= 9600 baud */
initlines = LINES;
else if (ospeed >= B4800) /* 16 lines at 4800 */
initlines = 16;
else /* otherwise just header */
initlines = 8;
}
else { /* not a crt */
LINES = 30000; /* so don't page */
CL = "\n\n"; /* put a couple of lines between */
if (!initlines) /* make initlines reasonable */
initlines = 8;
}
if (COLS <= 0)
COLS = 80;
just_a_sec = /* 1 second of padding */
ospeed >= B300 ? (
ospeed >= B9600 ? 960 :
ospeed == B4800 ? 480 :
ospeed == B2400 ? 240 :
ospeed == B1800 ? 180 :
ospeed == B1200 ? 120 :
ospeed == B600 ? 60 :
/* ospeed == B300*/ 30
) : ( /* avoid 'expression overflow' grrr */
ospeed == B200 ? 20 :
ospeed == B150 ? 15 : /* do I really have to type the */
ospeed == B134 ? 13 : /* rest of this? */
ospeed == B110 ? 11 :
ospeed == B75 ? 8 :
ospeed == B50 ? 5 :
/* ospeed == B0 */ 960 /* if we are running detached I */
); /* don't want to know about it! */
}
/* routine to pass to tputs */
char
putchr(ch)
register char ch;
{
putchar(ch);
}
/* input the 2nd and succeeding characters of a multi-character command */
/* returns TRUE if command finished, FALSE if they rubbed out first character */
bool
finish_command(donewline)
int donewline;
{
register char *s;
s = buf;
if (s[1] != FINISHCMD) /* someone faking up a command? */
return TRUE;
do {
top:
if (*s < ' ') {
putchar('^');
putchar(*s | 64);
}
else
putchar(*s); /* echo previous character */
s++;
re_read:
fflush(stdout);
getcmd(s);
if (errno || *s == Ctl('l')) {
*s = Ctl('r'); /* force rewrite on CONT */
}
if (*s == '\033') { /* substitution desired? */
#ifdef ESCSUBS
char tmpbuf[4], *cpybuf;
tmpbuf[0] = '%';
read_tty(&tmpbuf[1],1);
#ifdef RAWONLY
tmpbuf[1] &= 0177;
#endif
tmpbuf[2] = '\0';
if (tmpbuf[1] == 'h') {
help_subs();
*s = '\0';
reprint();
goto re_read;
}
else if (tmpbuf[1] == '\033') {
*s = '\0';
cpybuf = savestr(buf);
interp(buf,cpybuf);
free(cpybuf);
s = buf + strlen(buf);
reprint();
goto re_read;
}
else {
interp(s,tmpbuf);
fputs(s,stdout);
s += strlen(s);
}
goto re_read;
#else
notincl("^[");
*s = '\0';
reprint();
goto re_read;
#endif
}
else if (*s == ERASECH) { /* they want to rubout a char? */
rubout();
s--; /* discount the char rubbed out */
if (*s < ' ')
rubout();
if (s == buf) { /* entire string gone? */
fflush(stdout); /* return to single char command mode */
return FALSE;
}
else
goto re_read;
}
else if (*s == KILLCH) { /* wipe out the whole line? */
while (s-- != buf) { /* emulate that many ERASEs */
rubout();
if (*s < ' ')
rubout();
}
fflush(stdout);
return FALSE; /* return to single char mode */
}
#ifdef WORDERASE
else if (*s == Ctl('w')) { /* wipe out one word? */
*s-- = ' ';
while (!isspace(*s) || isspace(s[1])) {
rubout();
if (s-- == buf) {
fflush(stdout);
return FALSE; /* return to single char mode */
}
if (*s < ' ')
rubout();
}
s++;
goto re_read;
}
#endif
else if (*s == Ctl('r')) {
*s = '\0';
reprint();
goto re_read;
}
else if (*s == Ctl('v')) {
putchar('^');
backspace();
getcmd(s);
goto top;
}
} while (*s != '\n'); /* till a newline (not echoed) */
*s = '\0'; /* terminate the string nicely */
if (donewline)
putchar('\n');
return TRUE; /* say we succeeded */
}
/* discard any characters typed ahead */
void
eat_typeahead()
{
/*NOSTRICT*/
if (!typeahead) {
#ifdef PENDING
while (input_pending())
read_tty(buf,sizeof(buf));
#else /* this is probably v7 */
ioctl(_tty_ch,TIOCSETP,&_tty);
#endif
}
}
#ifndef read_tty
/* read a character from the terminal, with hacks for O_NDELAY reads */
int
read_tty(addr,size)
char *addr;
int size;
{
if (is_input) {
*addr = pending_ch;
is_input = FALSE;
return 1;
}
else
return read(0,addr,size);
}
#endif
/* print an underlined string, one way or another */
void
underprint(s)
register char *s;
{
assert(UC);
if (*UC) { /* char by char underline? */
while (*s) {
if (*s < ' ') {
putchar('^');
backspace();/* back up over it */
underchar();/* and do the underline */
putchar(*s+64);
backspace();/* back up over it */
underchar();/* and do the underline */
}
else {
putchar(*s);
backspace();/* back up over it */
underchar();/* and do the underline */
}
s++;
}
}
else { /* start and stop underline */
underline(); /* start underlining */
while (*s) {
if (*s < ' ') {
putchar('^');
putchar(*s+64);
}
else
putchar(*s);
s++;
}
un_underline(); /* stop underlining */
}
}
/* keep screen from flashing strangely on magic cookie terminals */
#ifdef NOFIREWORKS
void
no_sofire()
{
if (*UP && *SE) { /* should we disable fireworks? */
putchar('\n');
un_standout();
up_line();
putchar('\r');
}
}
void
no_ulfire()
{
if (*UP && *US) { /* should we disable fireworks? */
putchar('\n');
un_underline();
up_line();
putchar('\r');
}
}
#endif
/* get a character into a buffer */
void
getcmd(whatbuf)
register char *whatbuf;
{
int_count = 0;
errno = 0;
if (read_tty(whatbuf,1) < 0 && !errno)
errno = EINTR;
if (errno && errno != EINTR) {
perror(readerr);
sig_catcher(0);
}
#ifdef RAWONLY
*whatbuf &= 0177;
#endif
if (whatbuf == buf)
whatbuf[1] = FINISHCMD; /* tell finish_command to work */
}
int
get_anything()
{
char tmpbuf[2];
reask_anything:
standout();
#ifdef VERBOSE
IF(verbose)
fputs("[Type space to continue] ",stdout);
ELSE
#endif
#ifdef TERSE
fputs("[MORE] ",stdout);
#endif
un_standout();
fflush(stdout);
eat_typeahead();
if (int_count) {
return -1;
}
collect_subjects(); /* loads subject cache until */
/* input is pending */
getcmd(tmpbuf);
if (errno || *tmpbuf == '\f') {
putchar('\n'); /* if return from stop signal */
goto reask_anything; /* give them a prompt again */
}
if (*tmpbuf == 'h') {
#ifdef VERBOSE
IF(verbose)
fputs("\nType q to quit or space to continue.\n",stdout);
ELSE
#endif
#ifdef TERSE
fputs("\nq to quit, space to continue.\n",stdout);
#endif
goto reask_anything;
}
else if (*tmpbuf != ' ') {
putchar('\r'); /* put cursor at beginning of line */
erase_eol(); /* and erase the prompt */
return *tmpbuf;
}
if (erase_screen) /* -e? */
clear(); /* clear screen */
else {
putchar('\r'); /* put cursor at beginning of line */
erase_eol(); /* and erase the prompt */
}
return 0;
}
void
in_char(prompt)
char *prompt;
{
reask_in_char:
fputs(prompt,stdout);
fflush(stdout);
eat_typeahead();
getcmd(buf);
if (errno || *buf == '\f') {
putchar('\n'); /* if return from stop signal */
goto reask_in_char; /* give them a prompt again */
}
}
int
print_lines(what_to_print,hilite)
char *what_to_print;
int hilite;
{
register char *s;
register int i;
if (page_line < 0) /* they do not want to see this? */
return -1;
for (s=what_to_print; *s; ) {
if (page_line >= LINES || int_count) {
if (int_count || get_anything()) {
page_line = -1; /* disable further print_lines */
return -1;
}
page_line = 2;
}
else
page_line++;
if (hilite == STANDOUT) {
#ifdef NOFIREWORKS
if (erase_screen)
no_sofire();
#endif
standout();
}
else if (hilite == UNDERLINE) {
#ifdef NOFIREWORKS
if (erase_screen)
no_ulfire();
#endif
underline();
}
for (i=0; i<COLS; i++) {
if (!*s)
break;
if (*s >= ' ')
putchar(*s);
else if (*s == '\t') {
putchar(*s);
i = ((i+8) & ~7) - 1;
}
else if (*s == '\n') {
i = 32000;
}
else {
i++;
putchar('^');
putchar(*s + 64);
}
s++;
}
if (i) {
if (hilite == STANDOUT)
un_standout();
else if (hilite == UNDERLINE)
un_underline();
if (AM && i == COLS)
fflush(stdout);
else
putchar('\n');
}
}
return 0;
}
void
pad(num)
int num;
{
register int i;
for (i = num; i; --i)
putchar(PC);
fflush(stdout);
}
/* echo the command just typed */
#ifdef VERIFY
void
printcmd()
{
if (verify && buf[1] == FINISHCMD) {
if (*buf < ' ') {
putchar('^');
putchar(*buf | 64);
backspace();
backspace();
}
else {
putchar(*buf);
backspace();
}
fflush(stdout);
}
}
#endif
void
rubout()
{
backspace(); /* do the old backspace, */
putchar(' '); /* space, */
backspace(); /* backspace trick */
}
void
reprint()
{
register char *s;
fputs("^R\n",stdout);
for (s = buf; *s; s++) {
if (*s < ' ') {
putchar('^');
putchar(*s | 64);
}
else
putchar(*s);
}
}
!STUFFY!FUNK!
echo Extracting rcln.c
cat >rcln.c <<'!STUFFY!FUNK!'
/* $Header: rcln.c,v 4.1 84/09/24 12:04:36 lwall Exp $
*
* $Log: rcln.c,v $
* Revision 4.1 84/09/24 12:04:36 lwall
* Real baseline.
*
* Revision 4.0.1.3 84/09/18 16:09:18 lwall
* Fixed previous fix.
*
* Revision 4.0.1.2 84/09/13 11:16:43 lwall
* Check for out-of-bounds Xreffing.
*
* Revision 4.0.1.1 84/09/10 15:23:02 lwall
* Delinted.
*
* Revision 4.0 84/09/04 09:52:01 lwall
* Baseline for netwide release
*
*/
#include "EXTERN.h"
#include "common.h"
#include "util.h"
#include "rcstuff.h"
#include "ngdata.h"
#include "INTERN.h"
#include "rcln.h"
void
rcln_init()
{
;
}
#ifdef CATCHUP
void
catch_up(ngx)
NG_NUM ngx;
{
char tmpbuf[128];
#ifdef VERBOSE
IF(verbose)
printf("\nMarking %s as all read.\n",rcline[ngx]);
ELSE
#endif
#ifdef TERSE
fputs("\nMarked read\n",stdout);
#endif
sprintf(tmpbuf,"%s: 1-%ld", rcline[ngx],(long)getngsize(ngx));
free(rcline[ngx]);
rcline[ngx] = savestr(tmpbuf);
*(rcline[ngx] + rcnums[ngx] - 1) = '\0';
write_rc();
}
#endif
/* add an article number to a newsgroup, if it isn't already read */
int
addartnum(artnum,ngnam)
ART_NUM artnum;
char *ngnam;
{
register NG_NUM ngnum = find_ng(ngnam);
register char *s, *t, *maxt = Nullch;
ART_NUM min = 0, max = -1, lastnum = 0;
char *mbuf;
bool morenum;
if (!artnum)
return 0;
if (ngnum == nextrcline || !rcnums[ngnum])
/* not found in newsrc? */
return 0;
#ifdef CACHEFIRST
if (!abs1st[ngnum])
#else
if (!toread[ngnum])
#endif
/* now is a good time to trim down */
set_toread(ngnum); /* the list due to expires if we */
/* have not yet. */
#ifdef DEBUGGING
if (artnum > ngmax[ngnum] + 10 /* allow for incoming articles */
) {
printf("\nCorrupt Xref line!!! %ld --> %s(1..%ld)\n",
artnum,ngnam,
ngmax[ngnum]);
paranoid = TRUE; /* paranoia reigns supreme */
return -1; /* hope this was the first newsgroup */
}
#endif
if (toread[ngnum] == TR_BOGUS)
return 0;
#ifdef DEBUGGING
if (debug & DEB_XREF_MARKER) {
printf("%ld->\n%s%c%s\n",(long)artnum,rcline[ngnum],rcchar[ngnum],
rcline[ngnum] + rcnums[ngnum]);
}
#endif
s = rcline[ngnum] + rcnums[ngnum];
while (*s == ' ') s++; /* skip spaces */
t = s;
while (isdigit(*s) && artnum >= (min = atol(s))) {
/* while it might have been read */
for (t = s; isdigit(*t); t++) ; /* skip number */
if (*t == '-') { /* is it a range? */
t++; /* skip to next number */
if (artnum <= (max = atol(t)))
return 0; /* it is in range => already read */
lastnum = max; /* remember it */
maxt = t; /* remember position in case we */
/* want to overwrite the max */
while (isdigit(*t)) t++; /* skip second number */
}
else {
if (artnum == min) /* explicitly a read article? */
return 0;
lastnum = min; /* remember what the number was */
maxt = Nullch; /* last one was not a range */
}
while (*t && !isdigit(*t)) t++; /* skip comma and any spaces */
s = t;
}
/* we have not read it, so insert the article number before s */
morenum = isdigit(*s); /* will it need a comma after? */
*(rcline[ngnum] + rcnums[ngnum] - 1) = rcchar[ngnum];
mbuf = safemalloc((MEM_SIZE)(strlen(s) + (s-rcline[ngnum]) + 8));
strcpy(mbuf,rcline[ngnum]); /* make new rc line */
if (maxt && lastnum && artnum == lastnum+1)
/* can we just extend last range? */
t = mbuf + (maxt-rcline[ngnum]);/* then overwrite previous max */
else {
t = mbuf + (t-rcline[ngnum]); /* point t into new line instead */
if (lastnum) { /* have we parsed any line? */
if (!morenum) /* are we adding to the tail? */
*t++ = ','; /* supply comma before */
if (!maxt && artnum == lastnum+1 && *(t-1) == ',')
/* adjacent singletons? */
*(t-1) = '-'; /* turn them into a range */
}
}
if (morenum) { /* is there more to life? */
if (min == artnum+1) { /* can we consolidate further? */
bool range_before = (*(t-1) == '-');
bool range_after;
char *nextmax;
for (nextmax = s; isdigit(*nextmax); nextmax++) ;
range_after = *nextmax++ == '-';
if (range_before)
*t = '\0'; /* artnum is redundant */
else
sprintf(t,"%ld-",(long)artnum);/* artnum will be new min */
if (range_after)
s = nextmax; /* *s is redundant */
/* else
s = s */ /* *s is new max */
}
else
sprintf(t,"%ld,",(long)artnum); /* put the number and comma */
}
else
sprintf(t,"%ld",(long)artnum); /* put the number there (wherever) */
strcat(t,s); /* copy remainder of line */
#ifdef DEBUGGING
if (debug & DEB_XREF_MARKER) {
printf("%s\n",mbuf);
}
#endif
free(rcline[ngnum]);
rcline[ngnum] = mbuf; /* pull the switcheroo */
*(rcline[ngnum] + rcnums[ngnum] - 1) = '\0';
/* wipe out : or ! */
if (toread[ngnum] > TR_NONE) /* lest we turn unsub into bogus */
--toread[ngnum];
return 0;
}
#ifdef MCHASE
/* delete an article number from a newsgroup, if it is there */
void
subartnum(artnum,ngnam)
register ART_NUM artnum;
char *ngnam;
{
register NG_NUM ngnum = find_ng(ngnam);
register char *s, *t;
register ART_NUM min, max;
char *mbuf;
int curlen;
if (!artnum)
return;
if (ngnum == nextrcline || !rcnums[ngnum])
return; /* not found in newsrc? */
#ifdef DEBUGGING
if (debug & DEB_XREF_MARKER) {
printf("%ld<-\n%s%c%s\n",(long)artnum,rcline[ngnum],rcchar[ngnum],
rcline[ngnum] + rcnums[ngnum]);
}
#endif
s = rcline[ngnum] + rcnums[ngnum];
while (*s == ' ') s++; /* skip spaces */
/* a little optimization, since it is almost always the last number */
for (t=s; *t; t++) ; /* find end of string */
curlen = t-rcline[ngnum];
for (t--; isdigit(*t); t--) ; /* find previous delim */
if (*t == ',' && atol(t+1) == artnum) {
*t = '\0';
if (toread[ngnum] >= TR_NONE)
++toread[ngnum];
#ifdef DEBUGGING
if (debug & DEB_XREF_MARKER)
printf("%s%c %s\n",rcline[ngnum],rcchar[ngnum],s);
#endif
return;
}
/* not the last number, oh well, we may need the length anyway */
while (isdigit(*s) && artnum >= (min = atol(s))) {
/* while it might have been read */
for (t = s; isdigit(*t); t++) ; /* skip number */
if (*t == '-') { /* is it a range? */
t++; /* skip to next number */
max = atol(t);
while (isdigit(*t)) t++; /* skip second number */
if (artnum <= max) {
/* it is in range => already read */
if (artnum == min) {
min++;
artnum = 0;
}
else if (artnum == max) {
max--;
artnum = 0;
}
*(rcline[ngnum] + rcnums[ngnum] - 1) = rcchar[ngnum];
mbuf = safemalloc((MEM_SIZE)(curlen + (artnum?15:2)));
*s = '\0';
strcpy(mbuf,rcline[ngnum]); /* make new rc line */
s = mbuf + (s-rcline[ngnum]);
/* point s into mbuf now */
if (artnum) { /* split into two ranges? */
prange(s,min,artnum-1);
s += strlen(s);
*s++ = ',';
prange(s,artnum+1,max);
}
else /* only one range */
prange(s,min,max);
s += strlen(s);
strcpy(s,t); /* copy remainder over */
#ifdef DEBUGGING
if (debug & DEB_XREF_MARKER) {
printf("%s\n",mbuf);
}
#endif
free(rcline[ngnum]);
rcline[ngnum] = mbuf; /* pull the switcheroo */
*(rcline[ngnum] + rcnums[ngnum] - 1) = '\0';
/* wipe out : or ! */
if (toread[ngnum] >= TR_NONE)
++toread[ngnum];
return;
}
}
else {
if (artnum == min) { /* explicitly a read article? */
if (*t == ',') /* pick a comma, any comma */
t++;
else if (s[-1] == ',')
s--;
else if (s[-2] == ',') /* (in case of space) */
s -= 2;
strcpy(s,t); /* no need to realloc */
if (toread[ngnum] >= TR_NONE)
++toread[ngnum];
#ifdef DEBUGGING
if (debug & DEB_XREF_MARKER) {
printf("%s%c%s\n",rcline[ngnum],rcchar[ngnum],
rcline[ngnum] + rcnums[ngnum]);
}
#endif
return;
}
}
while (*t && !isdigit(*t)) t++; /* skip comma and any spaces */
s = t;
}
}
void
prange(where,min,max)
char *where;
ART_NUM min,max;
{
if (min == max)
sprintf(where,"%ld",(long)min);
else
sprintf(where,"%ld-%ld",(long)min,(long)max);
}
#endif
/* calculate the number of unread articles for a newsgroup */
void
set_toread(ngnum)
register NG_NUM ngnum;
{
register char *s, *c, *h;
char tmpbuf[64], *mybuf = tmpbuf;
char *nums;
int length;
ART_NUM ngsize = getngsize(ngnum);
ART_NUM unread = ngsize;
ART_NUM newmax;
#ifdef DEBUGGING
ngmax[ngnum] = ngsize; /* for checking out-of-range Xrefs */
#endif
if (ngsize == TR_BOGUS) {
printf("Warning! Bogus newsgroup: %s\n",rcline[ngnum]);
paranoid = TRUE;
toread[ngnum] = TR_BOGUS;
return;
}
#ifdef CACHEFIRST
if (!abs1st[ngnum])
#else
if (!toread[ngnum])
#endif
{
sprintf(tmpbuf," 1-%ld",(long)ngsize);
if (strNE(tmpbuf,rcline[ngnum]+rcnums[ngnum]))
checkexpired(ngnum,ngsize); /* this might realloc rcline */
}
nums = rcline[ngnum]+rcnums[ngnum];
length = strlen(nums);
if (length >= 60)
mybuf = safemalloc((MEM_SIZE)(length+5));
strcpy(mybuf,nums);
mybuf[length++] = ',';
mybuf[length] = '\0';
for (s = mybuf; isspace(*s); s++)
;
for ( ; (c = index(s,',')) != Nullch ; s = ++c) {
/* for each range */
*c = '\0'; /* keep index from running off */
if ((h = index(s,'-')) != Nullch) /* find - in range, if any */
unread -= (newmax = atol(h+1)) - atol(s) + 1;
else if (newmax = atol(s))
unread--; /* recalculate length */
if (newmax > ngsize) { /* paranoia check */
unread = -1;
break;
}
}
if (unread >= 0) /* reasonable number? */
toread[ngnum] = (ART_UNREAD)unread;
/* remember how many are left */
else { /* SOMEONE RESET THE NEWSGROUP!!! */
toread[ngnum] = (ART_UNREAD)ngsize;
/* assume nothing carried over */
printf("Warning! Somebody reset %s--assuming nothing read.\n",
rcline[ngnum]);
*(rcline[ngnum] + rcnums[ngnum]) = '\0';
paranoid = TRUE; /* enough to make a guy paranoid */
}
if (mybuf != tmpbuf)
free(mybuf);
if (rcchar[ngnum] == NEGCHAR)
toread[ngnum] = TR_UNSUB;
}
/* make sure expired articles are marked as read */
void
checkexpired(ngnum,ngsize)
register NG_NUM ngnum;
ART_NUM ngsize;
{
register ART_NUM a1st = getabsfirst(ngnum,ngsize);
register char *s, *t;
register ART_NUM num, lastnum = 0;
char *mbuf, *newnum;
if (a1st<=1)
return;
#ifdef DEBUGGING
if (debug & DEB_XREF_MARKER) {
printf("1-%ld->\n%s%c%s\n",(long)(a1st-1),rcline[ngnum],rcchar[ngnum],
rcline[ngnum] + rcnums[ngnum]);
}
#endif
for (s = rcline[ngnum] + rcnums[ngnum]; isspace(*s); s++);
while (*s && (num = atol(s)) <= a1st) {
while (isdigit(*s)) s++;
while (*s && !isdigit(*s)) s++;
lastnum = num;
}
if (*s) {
if (s[-1] == '-') { /* landed in a range? */
if (lastnum != 1)
sprintf(rcline[ngnum]+rcnums[ngnum]," 1-%s",s);
goto ret;
}
}
/* s now points to what should follow first range */
if (s - rcline[ngnum] > rcnums[ngnum] + 10)
mbuf = rcline[ngnum];
else {
mbuf = safemalloc((MEM_SIZE)(rcnums[ngnum] + strlen(s) + 10));
strcpy(mbuf,rcline[ngnum]);
}
newnum = t = mbuf+rcnums[ngnum];
sprintf(t," 1-%ld",(long)(a1st - (lastnum != a1st)));
if (*s) {
t += strlen(t);
*t++ = ',';
strcpy(t,s);
}
if (mbuf == rcline[ngnum]) {
rcline[ngnum] = saferealloc(rcline[ngnum],
(MEM_SIZE)(rcnums[ngnum] + strlen(newnum) + 1));
}
else {
free(rcline[ngnum]);
rcline[ngnum] = mbuf;
}
ret:
#ifdef DEBUGGING
if (debug & DEB_XREF_MARKER) {
printf("%s%c%s\n",rcline[ngnum],rcchar[ngnum],
rcline[ngnum] + rcnums[ngnum]);
}
#endif
}
!STUFFY!FUNK!
echo Extracting MANIFEST
cat >MANIFEST <<'!STUFFY!FUNK!'
After all the rn kits are run you should have the following files:
Filename Kit Description
-------- --- -----------
Configure 2 A shell script that installs everything system dependent.
EXTERN.h 8 When included, makes other includes not belong to me.
HACKERSGUIDE 6 A brief guide to the contorted innards of rn.
INTERN.h 8 When included, makes other includes belong to me.
MANIFEST 4 This list of files.
Makefile.SH 6 The makefile.
Pnews.SH 5 A news posting shell script that knows about -h.
Pnews.man 7 Manual page for Pnews.
README 6 Installation instructions.
Rnmail.SH 6 A mailer that knows about -h.
Rnmail.man 7 Manual page for Rnmail.
Wishlist 8 What the next version wants in it.
addng.c 7 Routines for scanning the active file for new newsgroups.
addng.h 8 Public info regarding addng.c.
art.c 3 Routines to display an article.
art.h 8 Public info regarding art.c.
art.help.SH 3 Shell script for help at the article level.
artio.c 7 Reserved for the article abstract type, someday.
artio.h 8 Public info regarding artio.c.
artsrch.c 6 Routines for searching among articles.
artsrch.h 8 Public info regarding artsrch.c.
artstate.h 8 Info on the current state of the article.
backpage.c 5 Routines for paging backwards in articles.
backpage.h 8 Public info regarding backpage.c.
bits.c 1 Bitmap management functions.
bits.h 7 Public info regarding bits.c.
cheat.c 7 Routines to do lookahead of several types.
cheat.h 8 Public info regarding cheat.c.
common.h 3 Global info.
final.c 7 Finalization (exit) routines.
final.h 8 Public info regarding final.c.
head.c 6 Header parsing routines.
head.h 7 Public info regarding head.c.
header.c.pat 7 DOXREFS patch for header.c.
header.h.pat 8 DOXREFS patch for header.h.
help.c 6 Help routines.
help.h 8 Public info regarding help.c.
inews.c.1.pat 2 DOXREFS and LINKART patches for 2.10.1 news.
inews.c.2.pat 5 DOXREFS and LINKART patches for 2.10.2 news.
init.c 6 Initialization (startup) routines.
init.h 8 Public info regarding init.c.
intrp.c 4 Filename expansion and % interpretation routines.
intrp.h 8 Public info regarding intrp.c.
kfile.c 6 KILL file routines.
kfile.h 8 Public info regarding kfile.c.
kitleader 8 Shell script to produce front of kit.
kitlists.c 7 Knapsack packer.
kittrailer 8 Shell script to produce end of kit.
last.c 7 Routines for handling the .rnlast file.
last.h 8 Public info regarding last.c.
makedepend.SH 7 Shell script to generate make dependencies.
makedir.SH 7 Shell script to make nested subdirectories.
makedist 1 Shell script to make a distribution kit.
makekit 8 Shell script to make a kit file.
manifake 8 Shell script to make MANIFEST.new file.
manimake 8 Shell script to make MANIFEST file.
mbox.saver.SH 8 Shell script to save an article to a mailbox.
ndir.c 7 4.2 directory routine emulation.
ndir.h 7 Public info regarding ndir.c.
newsetup.SH 7 Shell script to create a .newsrc file.
newsetup.man 7 Manual page for newsetup.
newsgroups.SH 7 Shell script to list unsubscribed newsgroups.
newsgroups.man 7 Manual page for newsgroups.
newsnews.SH 7 A motd-like file that rn may print at startup.
ng.c 2 Routines to display a newsgroup.
ng.h 8 Public info regarding ng.c.
ng.help.SH 7 Shell script to do newsgroup selection help.
ngdata.c 7 General data fetching routines for a newsgroup.
ngdata.h 8 Public info regarding ngdata.c.
ngsrch.c 7 Routines to search among newsgroups.
ngsrch.h 8 Public info regarding ngsrch.c.
ngstuff.c 6 Support routines for ng.c.
ngstuff.h 8 Public info regarding ng.c.
norm.saver.SH 8 Shell script to save an article to a normal file.
only.c 7 Routines to perform newsgroup restriction.
only.h 2 Public info regarding only.c.
pager.help.SH 7 Shell script for help at the pager level.
rcln.c 4 Routines to mung a .newsrc line.
rcln.h 8 Public info regarding rcln.c.
rcstuff.c 3 Routines to mung the .newsrc file.
rcstuff.h 7 Public info regarding rcstuff.c.
respond.c 5 Various routines for doing things with articles.
respond.h 8 Public info regarding respond.c.
rn.c 5 Main program.
rn.h 8 Public info regarding rn.c.
rn.man 1 Manual pages for rn. PLEASE READ.
search.c 4 Regular expression processing ala emacs.
search.h 7 Public info regarding search.c.
subs.help.SH 7 Shell script for help for escape substitutions.
sw.c 5 Switch processing routines.
sw.h 8 Public info regarding switch.c.
term.c 4 Terminal interface routines.
term.h 6 Public info regarding term.c.
util.c 5 Utility routines.
util.h 8 Public info regarding util.c.
!STUFFY!FUNK!
echo ""
echo "End of kit 4 (of 8)"
cat /dev/null >kit4isdone
config=true
for iskit in 1 2 3 4 5 6 7 8; do
if test -f kit${iskit}isdone; then
echo "You have run kit ${iskit}."
else
echo "You still need to run kit ${iskit}."
config=false
fi
done
case $config in
true)
echo "You have run all your kits. Please read README and then type Configure."
chmod 755 Configure
;;
esac
: I do not append .signature, but someone might mail this.
exit
More information about the Comp.sources.unix
mailing list