home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume28
/
yapp
/
part04
/
sep.c
< prev
Wrap
C/C++ Source or Header
|
1994-05-29
|
22KB
|
607 lines
/* SEP.C */
static char sccsid[] = "@(#)sep.c 1.19 93/06/06 Copyright (c)1993 thalerd";
/* This module takes care of most of the fancy output, and allows
* users and administrators to completely customize the output
* of many functions. A "separator" string is passed to confsep
* or itemsep, which break it up and generate output based on the
* codes therein. For more information, do "help separators"
* from within the program.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "config.h"
time_t time PROTO((time_t *tloc));
#include "struct.h"
#include "item.h"
#include "range.h"
#include "globals.h"
#include "sep.h"
#include "change.h" /* to get CF_PUBLIC */
#include "lib.h"
#include "sum.h" /* to get SF_FAST */
#include "macro.h"
#include "xalloc.h"
#include "main.h"
#include "news.h"
#include "stats.h"
static char *lchars="ntvbrface";
static char *rchars="\n\t\v\b\r\f\007\377\033";
static int lastnum=0,show[100],depth = 0,num=0,tabs=1;
static int newline,qfail,once,zero;
static char buff[MAX_LINE_LENGTH];
extern char *cfiles[];
/******************************************************************************/
/* OUTPUT A STRING TO THE DESIRED FORMAT */
/******************************************************************************/
static void /* RETURNS: (nothing) */
string(b,fp) /* ARGUMENTS: */
char *b; /* String to output */
FILE *fp; /* File pointer to output to */
{ /* LOCAL VARIABLES: */
char fmt[MAX_LINE_LENGTH]; /* Format string */
char buff[MAX_LINE_LENGTH]; /* Formatted output */
if (!show[depth]) return;
if (num)
sprintf(fmt,"%%%ds",num);
else
strcpy(fmt,"%s");
sprintf(buff,fmt,b);
wfputs(buff,fp);
}
/******************************************************************************/
/* OUTPUT A NUMBER TO THE DESIRED FORMAT */
/******************************************************************************/
static void /* RETURNS: (nothing) */
number(b,fp) /* ARGUMENTS: */
short b; /* Number to output */
FILE *fp; /* Stream to send to */
{
char fmt[MAX_LINE_LENGTH];
if (!show[depth]) return;
if (num)
sprintf(fmt,"%%%dd",num);
else
strcpy(fmt,"%d");
if (!b && zero)
sprintf(buff,"%co",("nN")[zero-1]);
else
sprintf(buff,fmt,b);
wfputs(buff,fp);
lastnum=b;
}
/******************************************************************************/
/* PROCESS CONDITIONS FOR BOTH ITEM/CONF SEPS */
/******************************************************************************/
static char /* RETURNS: 1 on true, 0 on false */
misccond(spp) /* ARGUMENTS: */
char **spp; /* Separator string */
{
char *sp,ret=0;
sp = *spp;
switch(*(sp++)) {
case 'P': ret=(lastnum!=1); break;
default: ret=0; break; /* don't show */
}
*spp = sp;
return ret;
}
/******************************************************************************/
/* PROCESS SEPS FOR BOTH ITEM/CONF SEPS */
/******************************************************************************/
void /* RETURNS: (nothing) */
miscsep(spp,fp) /* ARGUMENTS: */
char **spp; /* Separator string */
FILE *fp; /* Stream to send to */
{
char *sp;
short i;
sp = *spp;
switch(*(sp++)) {
/* Customization separators */
case '%': string("%",fp); break;
case 'E': if (!depth || show[depth-1]) show[depth]= !show[depth]; break;
case 'c': newline=0; break;
case 'S': if (lastnum!=1) string("s",fp); break;
case 'T': tabs=num; break;
case 'X': for (i=0; i<tabs; i++)
if (show[depth]) wfputc(' ',fp);
break;
case ')':
/*
for (i=0; i<depth; i++) printf(" ");
printf("---\n");
*/
depth--; break;
case 'D': if (show[depth]) wfputs(get_date(time((time_t*)0),num),fp); break;
default: break; /* do nothing */
}
*spp = sp;
}
/******************************************************************************/
/* PROCESS CONDITIONS FOR ITEM SEPS ONLY */
/******************************************************************************/
char /* RETURNS: 1 true, 0 false */
itemcond(spp,fl) /* ARGUMENTS: */
char **spp; /* Separator string */
long fl; /* Sep flags */
{
char *sp,ret=0,not=0;
response_t *cre;
sp = *spp;
cre = &(re[st_glob.r_current]);
if (*sp=='!' || *sp=='~') { not = !not; sp++; }
for (num=0; isdigit(*sp); sp++) num= num*10+(*sp-'0');
switch(*(sp++)) {
case 'T': ret=((fl & OF_FORMFEED)>0); break;
case 'E': ret=(( cre->flags & RF_EXPIRED)>0); break;
case 'V': ret=(( cre->flags & RF_CENSORED)>0); break;
case 'W': ret=(( cre->flags & RF_SCRIBBLED)>0); break;
case 'X': ret=((sum[st_glob.i_current-1].flags & IF_RETIRED)>0);
once &= ~IS_RETIRED;
break;
case 'Y': ret=((sum[st_glob.i_current-1].flags & IF_FORGOTTEN)>0);
once &= ~IS_FORGOTTEN;
break;
case 'Z': ret=((sum[st_glob.i_current-1].flags & IF_FROZEN)>0);
once &= ~IS_FROZEN;
break;
case 'R': ret=((once & (IS_ITEM|IS_RESP))>0);
once&= ~(IS_ITEM|IS_RESP);
/*
ret= ((!part[st_glob.i_current-1].nr && sum[st_glob.i_current-1].nr)
|| (part[st_glob.i_current-1].nr < sum[st_glob.i_current-1].nr));
*/
break;
case 'F': ret=((fl & OF_NUMBERED) || (flags & O_NUMBERED)); break;
case 'D': ret=((once & IS_DATE)>0); break;
case 'U': ret=((once & IS_UID)>0); break;
case 'L': ret=(st_glob.l_current>=0 && cre->text
&& st_glob.l_current<xsizeof(cre->text)
&& cre->text[st_glob.l_current]); break;
case 'I': /* ret= (!part[st_glob.i_current-1].nr && sum[st_glob.i_current-1].nr);
break; fall through into O */
case 'O': ret=((once & IS_ITEM)>0); once&= ~IS_ITEM; break;
case 'B': ret=((once & IS_START)>0); once&= ~IS_START; break;
case 'N': ret=(st_glob.r_current>0);
/* ret= (!(!part[st_glob.i_current-1].nr && sum[st_glob.i_current-1].nr)
&& (part[st_glob.i_current-1].nr < sum[st_glob.i_current-1].nr));
*/
break;
case 'p': once &= ~IS_PARENT;
ret=(cre->parent>0); break;
case 'x': ret= (once & num); /* once &= ~num; */ break;
default: return misccond(spp);
}
*spp = sp;
if (!show[depth]) return 0;
return ret^not;
}
/******************************************************************************/
/* PROCESS SEPS FOR ITEM SEPS ONLY */
/* This works only for the current conference */
/******************************************************************************/
void /* RETURNS: (nothing) */
itemsep2(spp,fl,fp) /* ARGUMENTS: */
char **spp; /* Separator string */
long *fl; /* Flags (see sep.h) */
FILE *fp; /* Stream to output to */
{
char *sp;
char *sub,neg=0;
response_t *cre;
char subbuf[MAX_LINE_LENGTH];
cre = &(re[st_glob.r_current]);
sp = *spp;
buff[0]=0;
num=0;
/* Get number */
zero=0;
if (*sp == 'z') { zero=1; sp++; }
else if (*sp == 'Z') { zero=2; sp++; }
if (*sp == '-') { neg=1; sp++; }
while (isdigit(*sp)) { num= num*10+(*sp-'0'); sp++; }
if (neg) num = -num;
switch(*(sp++)) {
/* Item Function Codes */
case 'a': string(cre->fullname,fp); break;
case 'C': if (confidx>=0) string(compress(conflist[confidx].name),fp); break;
case 'h': string(get_subj(confidx,st_glob.i_current-1,sum),fp); break;
case 'i': number(st_glob.i_current,fp); break;
case 'l': string(cre->login,fp); break;
case 'L': string(cre->text[st_glob.l_current],fp); break;
#ifdef NEWS
case 'm': string(message_id(compress(conflist[confidx].name),
st_glob.i_current,st_glob.r_current,re),fp); break;
#endif
case 'n': number(sum[st_glob.i_current-1].nr - 1,fp); break;
case 'N': number(st_glob.l_current+1,fp); break;
case 'r': number(st_glob.r_current,fp); break;
case 's': number((cre->flags & (RF_SCRIBBLED|RF_EXPIRED))? 0 : xsizeof(cre->text),fp);
break;
case 'k': number((cre->numchars+1023)/1024,fp); break;
case 'q': number(cre->numchars,fp); break;
case 'K': /* KKK */ break;
case 'Q': /* KKK */ break;
case 'u': number((short)cre->uid,fp);
/* *fl &= ~OF_UID; */
once &= ~IS_UID; break;
case 'd': if (show[depth]) wfputs(get_date(cre->date,num?num:1),fp);
/* *fl &= ~OF_DATE; */
once &= ~IS_DATE; break;
case 't': if (show[depth]) wfputs(get_date(cre->date,num),fp);
/* *fl &= ~OF_DATE; */
once &= ~IS_DATE; break;
case 'p': number((short)cre->parent,fp); once&=~IS_PARENT; break;
case '<': for (sub=subbuf; *sp && *sp!='>'; sp++,sub++) *sub = *sp;
sp++;
(*sub)='\0';
itemsep(subbuf,1);
break;
case '{': for (sub=subbuf; *sp && *sp!='}'; sp++,sub++) *sub = *sp;
sp++;
(*sub)='\0';
itemsep(subbuf,1);
break;
case '(': show[depth+1]=itemcond(&sp,*fl);
depth++;
break; /* ) */
default: *spp=sp-1; miscsep(spp,fp);
}
*spp = sp;
}
/******************************************************************************/
/* PROCESS CONDITIONS FOR CONF SEPS ONLY */
/******************************************************************************/
char /* RETURNS: 1 true, 0 false */
confcond(spp,idx,st) /* ARGUMENTS: */
char **spp; /* Separator string */
short idx; /* Conference index */
status_t *st;
{
char buff[MAX_LINE_LENGTH];
struct stat stt;
char *sp,ret=0,not=0;
sp = *spp;
if (*sp=='!' || *sp=='~') { not = !not; sp++; }
for (num=0; isdigit(*sp); sp++) num= num*10+(*sp-'0');
/*
int i;
for (i=0; i<depth; i++) printf(" ");
printf("%1d: %c ",i,*sp);
*/
switch(*(sp++)) {
case 'y': lastnum=st->i_unseen; ret=lastnum; break;
case 'n': lastnum=st->i_brandnew+st->i_newresp; ret= lastnum; break;
case 'b': lastnum=st->i_brandnew; ret= lastnum; break;
case 'r': lastnum=st->i_newresp; ret= lastnum; break;
case 'm': ret= (status & S_MAIL); break;
case 'x': ret= (once & num); /* once &= ~num; */ break;
case 'N': if (num>=0 && num<CF_PUBLIC && idx>=0) {
sprintf(buff,"%s/%s",conflist[idx].location,compress(cfiles[num]));
if (stat(buff,&stt) || stt.st_size<=0) ret=0;
else if (st->c_status & CS_JUSTJOINED) ret=1;
else ret=(stt.st_mtime > st->parttime);
}
break;
case 'F': if (num>=0 && num<CF_PUBLIC && idx>=0) {
sprintf(buff,"%s/%s",conflist[idx].location,compress(cfiles[num]));
ret=!stat(buff,&stt);
}
break;
case 'O': ret= (st->c_status & CS_OTHERCONF)?1:0; break;
case 'C': ret= (idx>=0); break;
case 'i': ret= (st->i_first<=st->i_last); break;
case 's': ret= (st->c_status & CS_FW); break;
case 'f': if (num>=0 && idx>=0) {
sprintf(buff,"%s/sum",conflist[idx].location);
ret = !stat(buff,&stt);
}
break;
case 'j': ret= (st->c_status & CS_JUSTJOINED)?1:0; break;
case 'l': ret= (st->c_status & CS_NORESPONSE); break;
case 'B': ret= (idx == confidx); break;
case 'k': ret= (once & IS_CFIDX); /* once &= ~IS_CFIDX; */ break;
default: return misccond(spp);
}
/*
printf("%d\n",ret);
*/
*spp = sp;
if (!show[depth]) return 0;
return ret^not;
}
/******************************************************************************/
/* PROCESS SEPS FOR CONF SEPS ONLY */
/******************************************************************************/
void
confsep2(spp,idx,st,part,fp) /* ARGUMENTS: */
char **spp; /* Separator string */
partentry_t *part; /* User participation info */
short idx; /* Conference index */
status_t *st;
FILE *fp; /* Stream to output to */
{
char *sp,*sub,*sh,*sh2,neg=0;
char subbuf[MAX_LINE_LENGTH];
time_t t;
char **config;
sp = *spp;
num=0;
/* Get number */
zero=0;
if (*sp == 'z') { zero=1; sp++; }
else if (*sp == 'Z') { zero=2; sp++; }
if (*sp == '-') { neg=1; sp++; }
while (isdigit(*sp)) { num= num*10+(*sp-'0'); sp++; }
if (neg) num = -num;
switch(*(sp++)) {
/* Conference separators */
#ifdef NEWS
case 'A': number(st->c_article, fp); break;
#endif
case 'y': number(st->i_unseen,fp); break;
case 'n': number(st->i_brandnew+st->i_newresp,fp); break;
case 'b': number(st->i_brandnew,fp); break;
case 'r': number(st->i_newresp,fp); break;
case 'k': number(st->count,fp); break;
case 'u': string(st->fullname,fp); break;
case 'v': string(login,fp); break;
case 'w': string(work,fp); break;
case 'f': number(st->i_first,fp); break;
case 'l': number(st->i_last,fp); break;
case 'Q': if (idx<0) { string("Not in a conference!",fp); qfail=1; } break;
case 'i': number(st->i_numitems,fp); break;
case 't': number(st->c_security,fp); break;
case 's': if (idx>=0) string(compress(conflist[idx].name),fp); break;
case 'p': if (config = get_config(idx))
string(config[CF_PARTFILE],fp);
break;
case 'd': if (idx>=0) string(conflist[idx].location,fp); break;
case 'q': if (idx>=0) {
sh=conflist[idx].location;
for (sh2=sh+strlen(sh)-1; sh2>=sh && *sh2!='/'; sh2--);
string(sh2+1,fp);
}
break;
case 'o': if (show[depth]) wfputs(get_date(st->parttime,num),fp); break;
case 'm': /* NEW: lastmod of sum file, if any */
/*
if (idx<0) t=0;
else {
sprintf(buff,"%s/sum",conflist[idx].location);
t= (stat(buff,&stt))? 0 : stt.st_mtime;
}
*/
t = st->sumtime;
if (show[depth]) wfputs(get_date(t,num),fp);
break;
case 'g': if (num>=0 && num<CF_PUBLIC && show[depth] && idx>=0)
cat(conflist[idx].location,compress(cfiles[num]));
break; /* KKK later, redirect cat to fp? */
case '<': for (sub=subbuf; *sp && *sp!='>'; sp++,sub++) *sub = *sp;
sp++;
(*sub)='\0';
confsep(subbuf,idx,st,part,1);
break;
case '{': for (sub=subbuf; *sp && *sp!='}'; sp++,sub++) *sub = *sp;
sp++;
(*sub)='\0';
confsep(subbuf,idx,st,part,1);
break;
case '(': /* Get number */
/* for (num=0; isdigit(*sp); sp++) num= num*10+(*sp-'0'); */
show[depth+1]=confcond(&sp,idx,st); /* for ultrix */
depth++;
break; /* ) */
default: *spp=sp-1; miscsep(spp,fp);
}
*spp = sp;
}
/******************************************************************************/
/* SET "ONCE-ONLY" FLAGS VALUE */
/******************************************************************************/
void /* RETURNS: (nothing) */
sepinit(x) /* ARGUMENTS: */
short x; /* Flags to set */
{
once |= x;
}
/******************************************************************************/
/* PROCESS ITEMSEP STRING */
/* Output to pipe, if one is open, else to stdout */
/******************************************************************************/
void /* RETURNS: (nothing) */
itemsep(sep,fl) /* ARGUMENTS: */
char *sep; /* Separator variable */
int fl; /* Force %c? */
{
char *sp,*tp;
response_t *cre;
FILE *fp;
char *str;
char buff[MAX_LINE_LENGTH];
str = expand(sep,DM_VAR);
if (!str) str = sep;
/* Force %c */
if (fl) {
sprintf(buff,"%s%%c",str);
str = buff;
}
if (status & S_EXECUTE) fp = 0;
else if (status & S_REDIRECT) fp = st_glob.outp;
else fp = stdout;
/* get status without trashing subj's in memory */
cre = &(re[st_glob.r_current]);
show[depth=0]=1;
newline=1;
sp=str;
for(;;) {
switch (*sp) {
case '%': sp++;
itemsep2(&sp,&st_glob.opt_flags,fp);
break;
case '\0': if ((once & IS_UID) && ((st_glob.opt_flags & OF_UID ) || (flags & O_UID )))
fprintf(fp," uid %d",cre->uid);
if ((once & IS_DATE) && ((st_glob.opt_flags & OF_DATE) || (flags & O_DATE)))
fprintf(fp," on %.24s",get_date(cre->date,0));
if ((once & IS_RETIRED)
&& (sum[st_glob.i_current-1].flags & IF_RETIRED))
wfputs("\n <item is retired>",fp);
if ((once & IS_FORGOTTEN)
&& (sum[st_glob.i_current-1].flags & IF_FORGOTTEN))
wfputs("\n <item is forgotten>",fp);
if ((once & IS_FROZEN)
&& (sum[st_glob.i_current-1].flags & IF_FROZEN))
wfputs("\n <item is frozen>",fp);
if ((once & IS_LINKED)
&& (sum[st_glob.i_current-1].flags & IF_PARTY))
wfputs("\n <synchronous (party) item>",fp);
if ((once & IS_LINKED)
&& (sum[st_glob.i_current-1].flags & IF_LINKED))
wfputs("\n <linked item>",fp);
if ((once & IS_PARENT)
&& (cre->parent>0))
fprintf(fp," <response to #%d>",cre->parent-1);
if (once & IS_CENSORED) {
if (cre->flags & RF_EXPIRED)
wfputs(" <expired>",fp);
else if (cre->flags & RF_SCRIBBLED) {
if (cre->numchars>8 && cre->text
&& (flags & O_SCRIBBLER)) {
char buff[MAX_LINE_LENGTH];
short i;
for (i=0; i<8 && ((char*)cre->text)[i]!=' '; i++)
buff[i] = ((char*)cre->text)[i];
buff[i] = '\0';
fprintf(fp," <censored & scribbled by %s>",buff);
} else
wfputs(" <censored & scribbled>",fp);
} else if (cre->flags & RF_CENSORED)
wfputs(" <censored>",fp);
}
if (newline) wfputc('\n',fp);
once=0;
fflush(fp);
return;
case '\\': /* Translate lchar into rchar */
sp++;
tp=strchr(lchars,*sp);
if (tp) { /* if *sp is 0 byte, will insert a 0 byte */
if (show[depth]) wfputc(rchars[tp-lchars],fp);
sp++;
break;
} /* else fall through into default */
default: if (show[depth]) wfputc(*sp++,fp);
else sp++;
}
}
}
/******************************************************************************/
/* PROCESS CONFSEP STRING */
/******************************************************************************/
void /* RETURNS: (nothing) */
confsep(sep,idx,st,part,fl) /* ARGUMENTS: */
char *sep; /* Sep string to process */
partentry_t *part; /* User participation info */
short idx; /* Index of which cf we're processing */
status_t *st;
int fl; /* Force %c? */
{
char *sp,*tp,*str;
FILE *fp;
char buff[MAX_LINE_LENGTH];
str = expand(sep,DM_VAR);
if (!str) str=sep;
/* Compatibility: force "...prompt" to end in \c */
if (fl) {
sprintf(buff,"%s%%c",str);
str = buff;
}
if (status & S_EXECUTE) fp = 0;
else if (status & S_REDIRECT) fp = st_glob.outp;
else fp = stdout;
show[depth=0]=1;
newline=1; qfail=0;
sp=str;
while (!qfail) {
switch (*sp) {
case '%': sp++;
confsep2(&sp,idx,st,part,fp);
break;
case '\0': if (newline) wfputc('\n',fp);
once=0;
fflush(fp);
return;
case '\\': /* Translate lchar into rchar */
sp++;
tp=strchr(lchars,*sp);
if (tp) { /* if *sp is 0 byte, will insert a 0 byte */
if (show[depth]) wfputc(rchars[tp-lchars],fp);
sp++;
break;
} /* else fall through into default */
default: if (show[depth]) wfputc(*sp++,fp);
else sp++;
break;
}
}
if (newline) wfputc('\n',fp);
fflush(fp);
}