home *** CD-ROM | disk | FTP | other *** search
- /* 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);
- }
-