lwall@sdcrdcf.UUCP (Larry Wall) (10/13/84)
#! /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