|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - downloadIndex: ┃ T n ┃
Length: 11576 (0x2d38) Types: TextFile Names: »newsrc.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─ ⟦this⟧ »EUUGD11/euug-87hel/sec1/vn/newsrc.c«
/* ** vn news reader. ** ** newsrc.c - routines to deal with the newsrc file ** ** see copyright disclaimer / history in vn.c source file */ #include <stdio.h> #include <ctype.h> #include "config.h" #include "tty.h" #include "vn.h" extern NODE **Newsorder; extern char *Onews, *Newsrc; extern int Ncount, Lrec, C_allow; extern int Ntopt, Nntopt, Nwopt, Nnwopt; extern char *Topt[], *Negtopt[], *Wopt[], *Negwopt[]; extern int Nounsub, Listfirst; /* global flags signifying options set */ #define GF_ALL 1 /* -x option - scan everything */ #define GF_SPEC 2 /* -n option(s) - user specified groups */ #define GF_OVER 4 /* command line specification - overide marks */ static char *Options[OPTLINES]; static int New_idx, Max_name, Optlines; static unsigned Gflags = 0; /* routines for dealing with the .newsrc file and options */ /* command name argument is already omitted from argv argc in this routine. Only the option arguments are present. We process options before we scan the rest of .newsrc, which redoes Newsorder, ie. we don't clobber Ncount until options are processed. */ scan_newsrc (argc,argv) int argc; char **argv; { FILE *fp, *fopen(); static char marks[] = { NEWS_ON, NEWS_OFF, '\0' }; char *str_store (); int line, len, num; char buf [RECLEN], trail, optpflag, submark, *fret, *ptr, *strpbrk(), *strtok(); /* initialize hash table, open temp file, fill table with active articles */ hashinit (); fill_active (); temp_open(); if (argc > 0) { Gflags |= GF_OVER; arg_opt(argc,argv); optpflag = 'y'; } else optpflag = 'n'; if ((fp = fopen (Newsrc,"r")) == NULL) printex ("can't open %s for reading",Newsrc); Optlines = 0; for (line = 1; (fret = fgets(buf,RECLEN-1,fp)) != NULL && emptyline(buf) == 1; ++line) ; if (fret != NULL && strncmp (buf,"options",7) == 0) { Options[0] = str_store(buf); Optlines = 1; trail = buf [strlen(buf)-2]; for ( ; (fret = fgets(buf,RECLEN-1,fp)) != NULL; ++line) { if (trail != '\\' && buf[0] != ' ' && buf[0] != '\t') break; if (Optlines >= OPTLINES) printex ("%s - too many option lines (%d allowed)",Newsrc,OPTLINES); Options[Optlines] = str_store(buf); ++Optlines; if ((len = strlen(buf)) >= 2 && buf[len-2] != '\\') trail = buf[len-2]; else trail = '\0'; } } /* do the options from the newsrc file if there weren't command line args */ if (Optlines > 0 && optpflag == 'n') newsrc_opt (); Ncount = 0; for ( ; fret != NULL; ++line, fret = fgets(buf,RECLEN-1,fp)) { if (emptyline(buf) == 1) continue; if ((ptr = strpbrk(buf,marks)) == NULL) { fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n", line,Newsrc,buf); continue; } submark = *ptr; *ptr = '\0'; ++ptr; num = 0; for (ptr = strtok(ptr," ,-\n"); ptr != NULL; ptr = strtok(NULL," ,-\n")) { len = atoi (ptr); for ( ; *ptr >= '0' && *ptr <= '9'; ++ptr) ; if (*ptr != '\0' || len < num) { num = -1; fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n", line,Newsrc,buf); break; } num = len; } if (num < 0) continue; chkgroup (buf,submark,num); } fclose (fp); /* now take care of groups not specified in .newsrc */ art_active(); /* free up the option string storage */ for (num=0; num < Ntopt; ++num) regfree (Topt[num]); for (num=0; num < Nwopt; ++num) regfree (Wopt[num]); for (num=0; num < Nntopt; ++num) regfree (Negtopt[num]); for (num=0; num < Nnwopt; ++num) regfree (Negwopt[num]); Ntopt = Nwopt = Nntopt = Nnwopt = 0; } static emptyline(s) char *s; { while (isspace(*s)) ++s; if (*s == '\0') return (1); return (0); } \f /* fill hash table from active news group list temporarily makes "Newsorder" active list order. This is needed to be able to process options before scanning user order. */ static fill_active () { FILE *f,*fopen (); char *nread, act_rec[RECLEN], *strtok(); int num,lownum; Max_name = 0; if ((f = fopen (ACTFILE,"r")) == NULL) printex ("couldn't open %s\n",ACTFILE); while (fgets(act_rec, RECLEN-1, f) != NULL) { if (strtok (act_rec," \n") == NULL) continue; nread = strtok (NULL, " \n"); if (nread != NULL) num = atoi(nread); else num = 0; nread = strtok (NULL, " \n"); if (nread != NULL) lownum = atoi(nread); else lownum = 0; if (lownum > 0) --lownum; if (strlen(act_rec) > Max_name) Max_name = strlen(act_rec); hashenter (act_rec, num, lownum); } /* construct initial Newsorder */ entry_order(); fclose (f); } \f /* check active newsgroups not mentioned in NEWSRC file (FLG_SCAN not set) */ static art_active () { char act_rec[RECLEN], *strtok(); NODE *ptr,*hashfind(); FILE *f,*fopen(); if ((f = fopen (ACTFILE,"r")) == NULL) printex ("couldn't open %s\n",ACTFILE); New_idx = Ncount; while (fgets(act_rec, RECLEN-1, f) != NULL) { if (strtok (act_rec," \n") == NULL) continue; if ((ptr = hashfind (act_rec)) == NULL) printex("%s - unexpected hash table failure",act_rec); if ((ptr->state & FLG_SCAN) == 0) chkgroup (ptr->nd_name, NEWS_ON, 0); } } \f /* check group for new articles: s - group c - subscription indicator from NEWSRC n - number read */ static chkgroup (s,c,n) char *s,c; int n; { NODE *ptr, *hashfind(); int lold,lowart; lold = Lrec; if ((ptr = hashfind(s)) != NULL && (ptr->state & FLG_SCAN) == 0) { Newsorder [Ncount] = ptr; ++Ncount; ptr->pages = 0; ptr->state |= FLG_SCAN; if (c == NEWS_ON) ptr->state |= FLG_SUB; /* if "read" more than exist reset to zero */ if (n > ptr->art) n = 0; lowart = ptr->rdnum; if (n < ptr->rdnum) n = ptr->rdnum; ptr->orgrd = ptr->pgrd = ptr->rdnum = n; ptr->pgshwn = 0L; /* ** scan decision is rather complex, since GF_ALL setting ** overides "n" value, GF_SPEC indicates FLG_SPEC flag used. ** if GF_OVER set, FLG_SPEC overides subscription mark, else ** FLG_SPEC AND subscribed is neccesary. */ if ((Gflags & GF_SPEC) != 0) { if ((ptr->state & FLG_SPEC) == 0) c = NEWS_OFF; else { if ((Gflags & GF_OVER) != 0) c = NEWS_ON; } } if ((Gflags & GF_ALL) != 0) n = lowart; if (c == NEWS_ON && ptr->art > n) { outgroup (s,n,ptr->art); if (lold != Lrec) { ptr->pnum = lold+1; ptr->pages = Lrec - lold; ptr->state |= FLG_PAGE; } } } } \f /* wr_newsrc writes the .newsrc file */ wr_newsrc () { FILE *fp,*fopen(); NODE *p; char c; int i,rc; if (link(Newsrc,Onews) < 0) printex ("can't backup %s to %s before writing",Newsrc,Onews); if (unlink(Newsrc) < 0 || (fp = fopen(Newsrc,"w")) == NULL) printex ("can't open %s for writing (backed up in %s)",Newsrc,Onews); else { clearerr(fp); for (i=0; (rc = ferror(fp)) == 0 && i < Optlines; ++i) fprintf (fp,"%s",Options[i]); for (i=0; rc == 0 && i < Ncount; ++i) { p = Newsorder[i]; if ((p->state & FLG_SUB) == 0) c = NEWS_OFF; else c = NEWS_ON; #ifdef OLDRC fprintf (fp,"%s%c %d\n",p->nd_name,c,p->rdnum); #else if (p->rdnum > 0) fprintf (fp,"%s%c 1-%d\n",p->nd_name,c,p->rdnum); else fprintf (fp,"%s%c 0\n",p->nd_name,c); #endif rc = ferror(fp); } fclose (fp); if (rc != 0) printex ("write of %s failed, old copy stored in %s",Newsrc,Onews); else unlink (Onews); } } \f new_groups () { int i,wrem,w; char fs[24],c_end; if (New_idx >= Ncount || C_allow < (w = Max_name+1)) return (0); term_set (ERASE); printf (NEWGFORM,Newsrc); sprintf (fs,"%%-%ds%%c",Max_name); wrem = C_allow; for (i=New_idx; i < Ncount; ++i) { if ((wrem -= w) < w) { wrem = C_allow; c_end = '\n'; } else c_end = ' '; printf (fs,(Newsorder[i])->nd_name,c_end); } if ((++wrem) < C_allow) putchar ('\n'); return (i-New_idx); } \f /* arg_opt must be called prior to option scanning, since it uses the options array. This is a bit of a kludge, but it saves a bunch of work. NOTE - no command name argument */ static arg_opt (argc,argv) int argc; char **argv; { if (argc > OPTLINES) printex ("too many command line options (%d allowed)\n",OPTLINES); for (Optlines=0; Optlines < argc; ++Optlines) { Options[Optlines] = *argv; ++argv; } newsrc_opt(); } \f /* option setting routine: sets global flags: GF_ALL for -x option GF_SPEC for -n. sets up filter array for article scanning */ static newsrc_opt() { int i; char curopt,tmp[RECLEN],*tok,*strtok(),*index(); Nounsub = Listfirst = 0; Ntopt = Nwopt = Nnwopt = Nntopt = 0; curopt = '\0'; for (i=0; i < Optlines; ++i) { strcpy(tmp,Options[i]); for (tok = strtok(tmp,",\\ \t\n"); tok != NULL; tok = strtok(NULL,",\\ \t\n")) { if (*tok != '-') do_opt (curopt,tok); else { for (++tok; index("nwt",*tok) == NULL; ++tok) { /* options with no strings */ switch(*tok) { case 'S': Gflags &= ~GF_OVER; break; case '%': Listfirst = 1; break; case 'U': Nounsub = 1; break; #ifdef OLDRC case 'i': /* Treat "-i" as synonym for "-x" */ #endif case 'x': Gflags |= GF_ALL; default: break; } } curopt = *tok; if (*(++tok) != '\0') do_opt (curopt,tok); } } } } /* do_opt is for options with strings attached */ static do_opt (opt,str) char opt, *str; { switch (opt) { case 'n': Gflags |= GF_SPEC; specmark(str); break; case 'w': specfilter (FIL_AUTHOR,str); break; case 't': specfilter (FIL_TITLE,str); break; default: #ifdef OLDRC Gflags |= GF_SPEC; /* Assume anything else is newsgroup */ specmark(str); #endif break; } } static specfilter (comp,str) char comp,*str; { char *regcmp(); int *count; char **rex; /* ** we may set rex one past end of array. we will error before ** referencing it if that's the case, however. */ if (*str == '!') { if (comp == FIL_TITLE) { count = &Nntopt; rex = Negtopt + *count; } else { count = &Nnwopt; rex = Negwopt + *count; } ++str; } else { if (comp == FIL_TITLE) { count = &Ntopt; rex = Topt + *count; } else { count = &Nwopt; rex = Wopt + *count; } } if (*count >= NUMFILTER) printex ("too many %c options, %d allowed",comp,NUMFILTER); if ((*rex = regcmp(str,(char *) 0)) == NULL) printex ("%c option regular expression syntax: %s",comp,str); ++(*count); } /* handle the newsgroup specification string. ("all" convention - braack!!!) */ static specmark (s) char *s; { unsigned ormask,andmask; int i,len; char *ptr,*re,pattern[RECLEN],*regex(),*regcmp(); if (*s == '!') { ++s; ormask = 0; andmask = ~FLG_SPEC; if (*s == '\0') return; } else { ormask = FLG_SPEC; andmask = 0xffff; } /* convert "all" not bounded by alphanumerics to ".*". ".all" becomes ".*" */ for (ptr = s; (len = findall(ptr)) >= 0; ptr += len+1) { if (len > 0 && isalnum (s[len-1])) continue; if (isalnum (s[len+3])) continue; if (len > 0 && s[len-1] == '.') { --len; strcpy (s+len,s+len+1); } s[len] = '.'; s[len+1] = '*'; strcpy (s+len+2,s+len+3); } /* now use regular expressions */ sprintf (pattern,"^%s$",s); if ((re = regcmp(pattern,(char *) 0)) == NULL) printex ("n option regular expression syntax: %s",s); for (i=0; i < Ncount; ++i) { if (regex(re,(Newsorder[i])->nd_name) != NULL) { (Newsorder[i])->state |= ormask; (Newsorder[i])->state &= andmask; } } regfree (re); } \f static findall (s) char *s; { int len; for (len=0; *s != '\0'; ++s,++len) { if (*s == 'a' && strncmp(s,"all",3) == 0) return (len); } return (-1); }