|
|
Initial revision
/* formatsbr.c - format string interpretation */
#include "../h/mh.h"
#include "../h/addrsbr.h"
#include "../h/formatsbr.h"
#include "../zotnet/tws.h"
#include "../h/fmtcompile.h"
#include <ctype.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#define NFMTS MAXARGS
#define QUOTE '\\'
static char *formats = 0;
extern char *formataddr(); /* hook for custom address formatting */
struct msgs *fmt_current_folder;/* current folder (set by main program) */
int fmt_norm = AD_NAME;
struct mailname fmt_mnull;
static
normalize(cp)
register char *cp;
{
register char *dp;
for (dp = cp; *cp; cp++)
if (*cp != QUOTE)
*dp++ = *cp;
else
switch (*++cp) {
case 'b':
*dp++ = '\b';
break;
case 'f':
*dp++ = '\f';
break;
case 'n':
*dp++ = '\n';
break;
case 'r':
*dp++ = '\r';
break;
case 't':
*dp++ = '\t';
break;
case '\n':
break;
case NULL:
cp--;
/* fall through */
default:
*dp++ = *cp;
break;
}
*dp = NULL;
}
char *
new_fs(form, format, def)
register char *form, *format, *def;
{
struct stat st;
register FILE *fp;
if (formats)
free(formats);
if (form) {
if ((fp = fopen(libpath(form), "r")) == NULL)
adios(form, "unable to open format file");
if (fstat(fileno(fp), &st) == NOTOK)
adios(form, "unable to stat format file");
if ((formats = malloc((unsigned) st.st_size + 1)) == NULLCP)
adios(form, "unable to allocate space for format");
if (read(fileno(fp), formats, st.st_size) != st.st_size)
adios(form, "error reading format file");
formats[st.st_size] = '\0';
(void) fclose(fp);
} else {
formats = getcpy(format ? format : def);
}
normalize(formats);
return formats;
}
/*
* test if string "sub" appears anywhere in string "str"
* (case insensitive).
*/
static int
match(str, sub)
register char *str, *sub;
{
register int c1;
register int c2;
register char *s1;
register char *s2;
while (c1 = *sub) {
while ((c2 = *str++) && (c1 | 040) != (c2 | 040))
;
if (!c2)
return 0;
s1 = sub + 1;
s2 = str;
while ((c1 = *s1++) && (c1 | 040) == (*s2++ | 040))
;
if (!c1)
return 1;
}
return 1;
}
/* macros to format data */
#define PUTDF(cp, num, wid, fill) {\
if (cp + wid < ep) {\
if ((i = (num)) < 0)\
i = -(num);\
if ((c = (wid)) < 0)\
c = -c;\
sp = cp + c;\
do {\
*--sp = (i % 10) + '0';\
i /= 10;\
} while (i > 0 && sp > cp);\
if (i > 0)\
*sp = '?';\
else if ((num) < 0 && sp > cp)\
*--sp = '-';\
while (sp > cp)\
*--sp = fill;\
cp += c;\
}}
#define PUTD(cp, num) {\
if (cp < ep) {\
if ((i = (num)) == 0)\
*cp++ = '0';\
else {\
if ((i = (num)) < 0) \
*cp++ = '-', i = -(num);\
c = 10;\
while (c <= i) \
c *= 10;\
while (cp < ep && c > 1) {\
c /= 10;\
*cp++ = (i / c) + '0';\
i %= c;\
}\
}\
}}
#define PUTSF(cp, str, wid, fill) {\
rjust = 0;\
if ((i = (wid)) < 0) {\
i = -i;\
rjust++;\
}\
if (sp = (str)) {\
if (rjust) {\
c = strlen(sp);\
if (c > i)\
sp += c - i;\
else {\
while (--i >= c && cp < ep)\
*cp++ = fill;\
i++;\
}\
} else {\
while ((c = *sp) && c <= 32)\
sp++;\
}\
while ((c = *sp++) && --i >= 0 && cp < ep)\
if (c > 32) \
*cp++ = c;\
else {\
while ((c = *sp) && c <= 32)\
sp++;\
*cp++ = ' ';\
}\
}\
if (!rjust)\
while (--i >= 0 && cp < ep)\
*cp++ = fill;\
}
#define PUTS(cp, str) {\
if (sp = (str)) {\
while ((c = *sp) && c <= 32)\
sp++;\
while ((c = *sp++) && cp < ep)\
if (c > 32) \
*cp++ = c;\
else {\
while ((c = *sp) && c <= 32)\
sp++;\
*cp++ = ' ';\
}\
}}
static char *lmonth[] = {
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
};
fmtscan(format, scanl, width, dat)
struct format *format;
char *scanl;
int width;
int dat[];
{
register char *cp = scanl;
register char *ep = scanl + width - 1;
register struct format *fmt = format;
register char *str = NULLCP;
register int value = 0;
register char *sp;
register int i;
register int c;
register struct comp *comp;
register struct tws *tws;
register struct mailname *mn;
register int j;
int rjust;
long l;
char *savestr;
char buffer[BUFSIZ];
for (;;) {
switch (fmt->f_type) {
case FT_COMP:
PUTS(cp, fmt->f_comp->c_text);
break;
case FT_COMPF:
PUTSF(cp, fmt->f_comp->c_text, fmt->f_width,
fmt->f_fill);
break;
case FT_LIT_FORCE:
sp = fmt->f_text;
i = strlen(sp);
ep += i; /* forced lits are `invisible' */
while (c = *sp++)
*cp++ = c;
break;
case FT_LIT:
sp = fmt->f_text;
while ((c = *sp++) && cp < ep)
*cp++ = c;
break;
case FT_LITF:
sp = fmt->f_text;
/* By default we left justify */
rjust = 0;
if ((i = fmt->f_width) < 0) {
i = -i;
rjust++;
}
if (rjust) {
j = strlen(sp);
if (j > i)
sp += j - i;
else while (j < i && cp < ep) {
*cp++ = fmt->f_fill;
++j;
}
}
while ((c = *sp++) && --i >= 0 && cp < ep)
*cp++ = c;
while (--i >= 0 && cp < ep)
*cp++ = fmt->f_fill;
break;
case FT_STR:
PUTS(cp, str);
break;
case FT_STRF:
PUTSF(cp, str, fmt->f_width, fmt->f_fill);
break;
case FT_STRFW:
adios(NULLCP, "internal error (FT_STRFW)");
case FT_NUM:
PUTD(cp, value);
break;
case FT_NUMF:
PUTDF(cp, value, fmt->f_width, fmt->f_fill);
break;
case FT_CHAR:
*cp++ = fmt->f_char;
break;
case FT_DONE:
goto finished;
case FT_IF_S:
if (str == NULLCP || *str == NULL) {
fmt += fmt->f_skip;
continue;
}
break;
case FT_IF_S_NULL:
if (str != NULLCP && *str != NULL) {
fmt += fmt->f_skip;
continue;
}
break;
case FT_IF_V_EQ:
if (value != fmt->f_value) {
fmt += fmt->f_skip;
continue;
}
break;
case FT_IF_V_NE:
if (value == fmt->f_value) {
fmt += fmt->f_skip;
continue;
}
break;
case FT_IF_V_GT:
if (value <= fmt->f_value) {
fmt += fmt->f_skip;
continue;
}
break;
case FT_IF_MATCH:
if (!str || !match(str, fmt->f_text)) {
fmt += fmt->f_skip;
continue;
}
break;
case FT_V_MATCH:
if (str)
value = match(str, fmt->f_text);
else
value = 0;
break;
case FT_IF_AMATCH:
if (!str || !uprf(str, fmt->f_text)) {
fmt += fmt->f_skip;
continue;
}
break;
case FT_V_AMATCH:
if (str)
value = uprf(str, fmt->f_text);
else
value = 0;
break;
case FT_S_NONNULL:
value = (str != NULLCP && *str != NULL);
break;
case FT_S_NULL:
value = (str == NULLCP || *str == NULL);
break;
case FT_V_EQ:
value = (fmt->f_value == value);
break;
case FT_V_NE:
value = (fmt->f_value != value);
break;
case FT_V_GT:
value = (fmt->f_value > value);
break;
case FT_GOTO:
fmt += fmt->f_skip;
continue;
case FT_NOP:
break;
case FT_LS_COMP:
str = fmt->f_comp->c_text;
break;
case FT_LS_LIT:
str = fmt->f_text;
break;
case FT_LS_TRIM:
if (str) {
register char *xp;
/* Be careful since str can point into buffer */
bcopy(str, buffer, strlen(str) + 1);
str = buffer;
/* Eat leading whitespace */
while (isspace(*str))
str++;
/* Trim trailing whitespace */
xp = str + strlen(str) - 1;
while (xp > str && isspace(*xp))
*xp-- = '\0';
/* By default we left justify */
rjust = 0;
if ((i = fmt->f_width) < 0) {
i = -i;
rjust++;
}
/* If necessary, limit width and/or justify */
if (i > 0 && (j = strlen(str)) > i) {
if (!rjust)
str[i] = '\0';
else
str += j - i;
}
}
break;
case FT_LV_COMPFLAG:
value = fmt->f_comp->c_flags;
break;
case FT_LV_COMP:
value = (comp = fmt->f_comp)->c_text ?
atoi(comp->c_text) : 0;
break;
case FT_LV_LIT:
value = fmt->f_value;
break;
case FT_LV_DAT:
value = dat[fmt->f_value];
break;
case FT_LV_STRLEN:
value = strlen(str);
break;
case FT_LV_CHAR_LEFT:
value = width - (cp - scanl);
break;
case FT_LV_PLUS_L:
value += fmt->f_value;
break;
case FT_LV_MINUS_L:
value = fmt->f_value - value;
break;
case FT_LV_DIVIDE_L:
if (fmt->f_value)
value = value / fmt->f_value;
else
value = 0;
break;
case FT_SAVESTR:
savestr = str;
break;
case FT_LV_SEC:
value = fmt->f_comp->c_tws->tw_sec;
break;
case FT_LV_MIN:
value = fmt->f_comp->c_tws->tw_min;
break;
case FT_LV_HOUR:
value = fmt->f_comp->c_tws->tw_hour;
break;
case FT_LV_MDAY:
value = fmt->f_comp->c_tws->tw_mday;
break;
case FT_LV_MON:
value = fmt->f_comp->c_tws->tw_mon + 1;
break;
case FT_LS_MONTH:
str = tw_moty[fmt->f_comp->c_tws->tw_mon];
break;
case FT_LS_LMONTH:
str = lmonth[fmt->f_comp->c_tws->tw_mon];
break;
case FT_LS_ZONE:
str = dtwszone(fmt->f_comp->c_tws);
break;
case FT_LV_YEAR:
value = fmt->f_comp->c_tws->tw_year;
break;
case FT_LV_WDAY:
if (!(((tws = fmt->f_comp->c_tws)->tw_flags) &
(TW_SEXP | TW_SIMP)))
set_dotw(tws);
value = tws->tw_wday;
break;
case FT_LS_DAY:
if (!(((tws = fmt->f_comp->c_tws)->tw_flags) &
(TW_SEXP | TW_SIMP)))
set_dotw(tws);
str = tw_dotw[tws->tw_wday];
break;
case FT_LS_WEEKDAY:
if (!(((tws = fmt->f_comp->c_tws)->tw_flags) &
(TW_SEXP | TW_SIMP)))
set_dotw(tws);
str = tw_ldotw[tws->tw_wday];
break;
case FT_LV_YDAY:
value = fmt->f_comp->c_tws->tw_yday;
break;
case FT_LV_ZONE:
value = fmt->f_comp->c_tws->tw_zone;
break;
case FT_LV_CLOCK:
if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
value = twclock(fmt->f_comp->c_tws);
break;
case FT_LV_RCLOCK:
if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
value = twclock(fmt->f_comp->c_tws);
value = time((long *) 0) - value;
break;
case FT_LV_DAYF:
if (!(((tws = fmt->f_comp->c_tws)->tw_flags) &
(TW_SEXP | TW_SIMP)))
set_dotw(tws);
switch (fmt->f_comp->c_tws->tw_flags & TW_SDAY) {
case TW_SEXP:
value = 1;
break;
case TW_SIMP:
value = 0;
break;
default:
value = -1;
break;
}
case FT_LV_ZONEF:
if ((fmt->f_comp->c_tws->tw_flags & TW_SZONE) ==
TW_SZEXP)
value = 1;
else
value = -1;
break;
case FT_LV_DST:
value = fmt->f_comp->c_tws->tw_flags & TW_DST;
break;
case FT_LS_822DATE:
str = dasctime(fmt->f_comp->c_tws, TW_ZONE);
break;
case FT_LS_PRETTY:
str = dasctime(fmt->f_comp->c_tws, TW_NULL);
break;
case FT_LS_PERS:
str = fmt->f_comp->c_mn->m_pers;
break;
case FT_LS_MBOX:
str = fmt->f_comp->c_mn->m_mbox;
break;
case FT_LS_HOST:
str = fmt->f_comp->c_mn->m_host;
break;
case FT_LS_PATH:
str = fmt->f_comp->c_mn->m_path;
break;
case FT_LS_GNAME:
str = fmt->f_comp->c_mn->m_gname;
break;
case FT_LS_NOTE:
str = fmt->f_comp->c_mn->m_note;
break;
case FT_LS_822ADDR:
str = adrformat(fmt->f_comp->c_mn);
break;
case FT_LV_HOSTTYPE:
value = fmt->f_comp->c_mn->m_type;
break;
case FT_LV_INGRPF:
value = fmt->f_comp->c_mn->m_ingrp;
break;
case FT_LV_NOHOSTF:
value = fmt->f_comp->c_mn->m_nohost;
break;
case FT_LS_FRIENDLY:
#ifdef BERK
str = fmt->f_comp->c_mn->m_mbox;
#else
mn = fmt->f_comp->c_mn;
if ((str = mn->m_pers) == NULL)
switch (mn->m_type) {
case LOCALHOST:
str = mn->m_mbox;
break;
case UUCPHOST:
(void) sprintf(buffer, "%s!%s",
mn->m_host, mn->m_mbox);
str = buffer;
break;
default:
if (mn->m_mbox) {
(void) sprintf(buffer, "%s@%s",
mn->m_mbox, mn->m_host);
str = buffer;
} else
str = mn->m_text;
break;
}
#endif BERK
break;
case FT_LOCALDATE:
comp = fmt->f_comp;
if ((l = comp->c_tws->tw_clock) == 0)
l = twclock(comp->c_tws);
tws = dlocaltime(&l);
*comp->c_tws = *tws;
break;
case FT_GMTDATE:
comp = fmt->f_comp;
if ((l = comp->c_tws->tw_clock) == 0)
l = twclock(comp->c_tws);
tws = dgmtime(&l);
*comp->c_tws = *tws;
break;
case FT_PARSEDATE:
comp = fmt->f_comp;
if ((sp = comp->c_text) && (tws = dparsetime(sp))) {
*comp->c_tws = *tws;
comp->c_flags = 0;
} else if (comp->c_flags >= 0) {
bzero((char *)comp->c_tws,
sizeof(*comp->c_tws));
comp->c_flags = 1;
}
break;
case FT_FORMATADDR:
/* custom address list formatting hook */
str = formataddr(savestr, str);
break;
case FT_PUTADDR:
/*
* Output the str register as an address component,
* splitting it into multiple lines if necessary.
* The value reg. contains the max line length. The
* lit. field may contain a string to prepend to the
* result (e.g., "To: ")
*/
{
register char *lp = str;
register int indent;
register int wid = value;
register int len = strlen(str);
register char *lastb;
sp = fmt->f_text;
indent = strlen(sp);
wid -= indent;
while ((c = *sp++) && cp < ep)
*cp++ = c;
while (len > wid) {
/*
* Try to break at a comma; failing
* that, break at a space, failing
* that, just split the line.
*/
lastb = 0;
sp = lp + wid;
while (sp > lp && (c = *--sp) != ',') {
if (!lastb && isspace(c))
lastb = sp - 1;
}
if (sp == lp)
if (!(sp = lastb))
sp = lp + wid - 1;
len -= sp - lp + 1;
while (cp < ep && lp <= sp)
*cp++ = *lp++;
*cp++ = '\n';
for (i = indent; cp < ep && i > 0; i--)
*cp++ = ' ';
while (isspace(*lp))
lp++, len--;
}
PUTS(cp, lp);
}
break;
case FT_PARSEADDR:
comp = fmt->f_comp;
if (comp->c_mn != &fmt_mnull)
mnfree(comp->c_mn);
if ((sp = comp->c_text) && (sp = getname(sp)) &&
(mn = getm(sp, NULLCP, 0, fmt_norm, NULLCP))) {
comp->c_mn = mn;
while (getname(""))
;
} else
comp->c_mn = &fmt_mnull;
break;
case FT_MYMBOX:
/*
* If there's no component, we say true. Otherwise
* we say "true" only if we can parse the address and
* it matches one of our addresses.
*/
comp = fmt->f_comp;
if (comp->c_mn != &fmt_mnull)
mnfree(comp->c_mn);
if ((sp = comp->c_text) && (sp = getname(sp)) &&
(mn = getm(sp, NULLCP, 0, AD_NAME, NULLCP))) {
comp->c_mn = mn;
comp->c_flags = ismymbox(mn);
while (sp = getname(sp))
if (comp->c_flags == 0 &&
(mn = getm(sp, NULLCP, 0,
AD_NAME, NULLCP)))
comp->c_flags |= ismymbox(mn);
} else {
comp->c_flags = (comp->c_text == 0);
comp->c_mn = &fmt_mnull;
}
break;
case FT_ADDTOSEQ:
/*
* If we're working on a folder (as opposed to a
* file), add the current msg to sequence given in
* literal field. Don't disturb string or value
* registers.
*/
if (fmt_current_folder)
(void) m_seqadd(fmt_current_folder,
fmt->f_text, dat[0], -1);
break;
}
fmt++;
}
finished:
if (cp[-1] != '\n')
*cp++ = '\n';
*cp = NULL;
return (value);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.