view uip/picksbr.c @ 13:3c5835cca094

fix
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sat, 21 Apr 2012 15:40:28 +0900
parents 441a2190cfae
children
line wrap: on
line source

/* picksbr.c - routines to help pick along... */
#ifndef	lint
static char ident[] = "@(#)$Id: picksbr.c,v 1.1.1.1 2005/04/18 14:46:07 kono Exp $";
#endif	/* lint */

#include "../h/mh.h"
#include "../zotnet/tws.h"
#include <stdio.h>

/*  */

static struct swit parswit[] = {
#define	PRAND	0
    "and", 0,
#define	PROR	1
    "or", 0,
#define	PRNOT	2
    "not", 0,
#define	PRLBR	3
    "lbrace", 0,
#define	PRRBR	4
    "rbrace", 0,

#define	PRCC	5
    "cc  pattern", 0,
#define	PRDATE	6
    "date  pattern", 0,
#define	PRFROM	7
    "from  pattern", 0,
#define	PRSRCH	8
    "search  pattern", 0,
#define	PRSUBJ	9
    "subject  pattern", 0,
#define	PRTO	10
    "to  pattern", 0,
#define	PROTHR	11
    "-othercomponent  pattern", 15,

#define	PRAFTR	12
    "after date", 0,
#define	PRBEFR	13
    "before date", 0,
#define	PRDATF	14
    "datefield field", 5,

    NULL, 0
};

/*    DEFINITIONS FOR PATTERN MATCHING */

/* We really should be using re_comp() and re_exec() here.  Unfortunately,
   pick advertises that lowercase characters matches characters of both
   cases.  Since re_exec() doesn't exhibit this behavior, we are stuck
   with this version.  Furthermore, we need to be able to save and restore
   the state of the pattern matcher in order to do things "efficiently".

   The matching power of this algorithm isn't as powerful as the re_xxx()
   routines (no \(xxx\) and \n constructs).  Such is life.
 */


#define	CCHR	2
#define	CDOT	4
#define	CCL	6
#define	NCCL	8
#define	CDOL	10
#define	CEOF	11

#define	STAR	01

#define LBSIZE  1024
#define	ESIZE	256


static char	linebuf[LBSIZE + 1];

static char cc[] = {		/* the magic array for case-independence */
	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,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,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,
};

/*    DEFINITIONS FOR DATE MATCHING */

static struct tws *tws_parse (), *tws_special ();


time_t time ();

/*    DEFINITIONS FOR NEXUS */

#define	nxtarg()	(*argp ? *argp++ : NULL)
#define	prvarg()	argp--


#define	padvise		if (!talked++) advise


struct nexus {
    int     (*n_action) ();

    union {
	struct {		/* for {OR,AND,NOT}action */
	    struct nexus   *un_L_child;
	    struct nexus   *un_R_child;
	}       st1;
#define	n_L_child	un.st1.un_L_child
#define	n_R_child	un.st1.un_R_child

	struct {		/* for GREPaction */
	    int     un_header;
	    int     un_circf;
	    char    un_expbuf[ESIZE];
	    char   *un_patbuf;
	}       st2;
#define	n_header	un.st2.un_header
#define	n_circf		un.st2.un_circf
#define	n_expbuf	un.st2.un_expbuf
#define	n_patbuf	un.st2.un_patbuf

	struct {		/* for TWSaction */
	    char   *un_datef;
	    int     un_after;
	    struct tws un_tws;
	}	st3;
#define	n_datef		un.st3.un_datef
#define	n_after		un.st3.un_after
#define	n_tws		un.st3.un_tws

    }	un;
};

static	int   talked;
static	int   pdebug = 0;

static  char *datesw;
static  char **argp;

static  struct nexus *head;

static void	PRaction();
static int	gcompile(), advance(), cclass(), tcompile();

static struct	nexus *parse (), *exp1 (), *exp20 (), *exp3 (), *newnexus ();

static int	ORaction (), ANDaction (), NOTaction (), GREPaction (),
		TWSaction ();

#ifdef JAPAN
#define Get_onechar(c, p) \
{\
    c = *(p) & 0xff;\
    if (ml_ismlptr(p))\
	c = (c << 8) | (*++(p) & 0xff);\
    (p)++;\
}
#endif /* JAPAN */

/*  */

int	pcompile (vec, date)
register char  **vec,
	        *date;
{
    register char  *cp;

    if ((cp = getenv ("MHPDEBUG")) && *cp)
	pdebug++;

    argp = vec;
    if ((datesw = date) == NULL)
	datesw = "date";
    talked = 0;

    if ((head = parse ()) == NULL)
	return (talked ? 0 : 1);

    if (*argp) {
	padvise (NULLCP, "%s unexpected", *argp);
	return 0;
    }

    return 1;
}

/*  */

static struct nexus *parse () {
    register char  *cp;
    register struct nexus  *n,
                           *o;

    if ((n = exp1 ()) == NULL || (cp = nxtarg ()) == NULL)
	return n;

    if (*cp != '-') {
	padvise (NULLCP, "%s unexpected", cp);
	return NULL;
    }

    if (*++cp == '-')
	goto header;
    switch (smatch (cp, parswit)) {
	case AMBIGSW: 
	    ambigsw (cp, parswit);
	    talked++;
	    return NULL;
	case UNKWNSW: 
	    fprintf (stderr, "-%s unknown\n", cp);
	    talked++;
	    return NULL;

	case PROR: 
	    o = newnexus (ORaction);
	    o -> n_L_child = n;
	    if (o -> n_R_child = parse ())
		return o;
	    padvise (NULLCP, "missing disjunctive");
	    return NULL;

header: ;
	default: 
	    prvarg ();
	    return n;
    }
}

/*  */

static struct nexus *exp1 () {
    register char  *cp;
    register struct nexus  *n,
                           *o;

    if ((n = exp20 ()) == NULL || (cp = nxtarg ()) == NULL)
	return n;

    if (*cp != '-') {
	padvise (NULLCP, "%s unexpected", cp);
	return NULL;
    }

    if (*++cp == '-')
	goto header;
    switch (smatch (cp, parswit)) {
	case AMBIGSW: 
	    ambigsw (cp, parswit);
	    talked++;
	    return NULL;
	case UNKWNSW: 
	    fprintf (stderr, "-%s unknown\n", cp);
	    talked++;
	    return NULL;

	case PRAND: 
	    o = newnexus (ANDaction);
	    o -> n_L_child = n;
	    if (o -> n_R_child = exp1 ())
		return o;
	    padvise (NULLCP, "missing conjunctive");
	    return NULL;

header: ;
	default: 
	    prvarg ();
	    return n;
    }
}

/*  */

static struct nexus *exp20 () {
    register char  *cp;
    register struct nexus  *n;

    if ((cp = nxtarg ()) == NULL)
	return NULL;

    if (*cp != '-') {
	prvarg ();
	return exp3 ();
    }

    if (*++cp == '-')
	goto header;
    switch (smatch (cp, parswit)) {
	case AMBIGSW: 
	    ambigsw (cp, parswit);
	    talked++;
	    return NULL;
	case UNKWNSW: 
	    fprintf (stderr, "-%s unknown\n", cp);
	    talked++;
	    return NULL;

	case PRNOT: 
	    n = newnexus (NOTaction);
	    if (n -> n_L_child = exp3 ())
		return n;
	    padvise (NULLCP, "missing negation");
	    return NULL;

header: ;
	default: 
	    prvarg ();
	    return exp3 ();
    }
}

/*  */

static struct nexus *exp3 () {
    int     i;
    register char  *cp,
                   *dp;
    char    buffer[BUFSIZ], temp[64];
    register struct nexus  *n;

    if ((cp = nxtarg ()) == NULL)
	return NULL;

    if (*cp != '-') {
	padvise (NULLCP, "%s unexpected", cp);
	return NULL;
    }

    if (*++cp == '-') {
	dp = ++cp;
	goto header;
    }
    switch (i = smatch (cp, parswit)) {
	case AMBIGSW: 
	    ambigsw (cp, parswit);
	    talked++;
	    return NULL;
	case UNKWNSW: 
	    fprintf (stderr, "-%s unknown\n", cp);
	    talked++;
	    return NULL;

	case PRLBR: 
	    if ((n = parse ()) == NULL) {
		padvise (NULLCP, "missing group");
		return NULL;
	    }
	    if ((cp = nxtarg ()) == NULL) {
		padvise (NULLCP, "missing -rbrace");
		return NULL;
	    }
	    if (*cp++ == '-' && smatch (cp, parswit) == PRRBR)
		return n;
	    padvise (NULLCP, "%s unexpected", --cp);
	    return NULL;

	default: 
	    prvarg ();
	    return NULL;

	case PRCC: 
	case PRDATE: 
	case PRFROM: 
	case PRTO: 
	case PRSUBJ: 
	    strncpy(temp, parswit[i].sw, sizeof(temp));
	    temp[sizeof(temp) - 1] = '\0';
	    dp = *brkstring (temp, " ", NULLCP);
    header: ;
	    if (!(cp = nxtarg ())) {/* allow -xyz arguments */
		padvise (NULLCP, "missing argument to %s", argp[-2]);
		return NULL;
	    }
	    n = newnexus (GREPaction);
	    n -> n_header = 1;
	    (void) sprintf (buffer, "^%s[ \t]*:.*%s", dp, cp);
	    dp = buffer;
	    goto pattern;

	case PRSRCH: 
	    n = newnexus (GREPaction);
	    n -> n_header = 0;
	    if (!(cp = nxtarg ())) {/* allow -xyz arguments */
		padvise (NULLCP, "missing argument to %s", argp[-2]);
		return NULL;
	    }
	    dp = cp;
    pattern: ;
#ifdef JAPAN
#ifdef MHE
	    {
		/* Mule + MH-e have a bug, which output an internal code. */
		int err = 1;
		char *pp, *pi, *po;
		pp = po = getcpy(dp);
		for (pi = pp; *pi; pi++) {
		    if (!(*pi & 0x80))
			*po++ = *pi;
		    else if (*pi == '\222' && ml_ismlptr(pi+1)) {
			*po++ = *++pi;
			*po++ = *++pi;
			err = 0;
		    } else {
			err = 1;
			break;
		    }
		}
		if (err)
		    /* not Mule internal code */
		    (void) ml_conv(dp);
		else {
		    *po = '\0';
		    strcpy(dp, pp);
		}
		free(pp);
	    }
#else /* MHE */
	    (void) ml_conv(dp);
#endif /* MHE */
#endif /* JAPAN */
	    if (!gcompile (n, dp)) {
		padvise (NULLCP, "pattern error in %s %s", argp[-2], cp);
		return NULL;
	    }
	    n -> n_patbuf = getcpy (dp);
	    return n;

	case PROTHR: 
	    padvise (NULLCP, "internal error!");
	    return NULL;

	case PRDATF: 
	    if (!(datesw = nxtarg ()) || *datesw == '-') {
		padvise (NULLCP, "missing argument to %s", argp[-2]);
		return NULL;
	    }
	    return exp3 ();

	case PRAFTR: 
	case PRBEFR: 
	    if (!(cp = nxtarg ())) {/* allow -xyz arguments */
		padvise (NULLCP, "missing argument to %s", argp[-2]);
		return NULL;
	    }
	    n = newnexus (TWSaction);
	    n -> n_datef = datesw;
	    if (!tcompile (cp, &n -> n_tws, n -> n_after = i == PRAFTR)) {
		padvise (NULLCP, "unable to parse %s %s", argp[-2], cp);
		return NULL;
	    }
	    return n;
    }
}

/*  */

static struct nexus *newnexus (action)
register int	(*action) ();
{
    register struct nexus   *p;

    if ((p = (struct nexus *) calloc ((unsigned) 1, sizeof *p)) == NULL)
	adios (NULLCP, "unable to allocate component storage");

    p -> n_action = action;
    return p;
}

/*  */

#define	args(a)	a, fp, msgnum, start, stop
#define	params	args (n)
#define	plist	\
	    register struct nexus  *n; \
	    register FILE *fp; \
	    int	msgnum; \
	    long    start, \
		    stop;

int	pmatches (fp, msgnum, start, stop)
register FILE *fp;
int	msgnum;
long	start,
	stop;
{
    if (!head)
	return 1;

    if (!talked++ && pdebug)
	PRaction (head, 0);

    return (*head -> n_action) (args (head));
}

/*  */

static	void PRaction (n, level)
register struct nexus *n;
register int	level;
{
    register int    i;

    for (i = 0; i < level; i++)
	fprintf (stderr, "| ");

    if (n -> n_action == ORaction) {
	fprintf (stderr, "OR\n");
	PRaction (n -> n_L_child, level + 1);
	PRaction (n -> n_R_child, level + 1);
	return;
    }
    if (n -> n_action == ANDaction) {
	fprintf (stderr, "AND\n");
	PRaction (n -> n_L_child, level + 1);
	PRaction (n -> n_R_child, level + 1);
	return;
    }
    if (n -> n_action == NOTaction) {
	fprintf (stderr, "NOT\n");
	PRaction (n -> n_L_child, level + 1);
	return;
    }
    if (n -> n_action == GREPaction) {
	fprintf (stderr, "PATTERN(%s) %s\n",
		n -> n_header ? "header" : "body", n -> n_patbuf);
	return;
    }
    if (n -> n_action == TWSaction) {
	fprintf (stderr, "TEMPORAL(%s) %s: %s\n",
		n -> n_after ? "after" : "before", n -> n_datef,
		dasctime (&n -> n_tws, TW_NULL));
	return;
    }
    fprintf (stderr, "UNKNOWN(0x%lx)\n", (long)(*n -> n_action));
}

/*  */

static int  ORaction (params)
plist
{
    if ((*n -> n_L_child -> n_action) (args (n -> n_L_child)))
	return 1;
    return (*n -> n_R_child -> n_action) (args (n -> n_R_child));
}


static int  ANDaction (params)
plist
{
    if (!(*n -> n_L_child -> n_action) (args (n -> n_L_child)))
	return 0;
    return (*n -> n_R_child -> n_action) (args (n -> n_R_child));
}


static int  NOTaction (params)
plist
{
    return (!(*n -> n_L_child -> n_action) (args (n -> n_L_child)));
}

/*  */

static	int gcompile (n, astr)
register struct nexus *n;
register char *astr;
{
    register int    c;
    int     cclcnt;
    register char  *ep,
		   *dp,
                   *sp,
                   *lastep;

    dp = (ep = n -> n_expbuf) + sizeof n -> n_expbuf;
    sp = astr;
    lastep = NULL;
    if (*sp == '^') {
	n -> n_circf = 1;
	sp++;
    }
    else
	n -> n_circf = 0;
    for (;;) {
	if (ep >= dp)
	    goto cerror;
	if ((c = *sp++) != '*')
	    lastep = ep;
	switch (c) {
	    case '\0': 
		*ep++ = CEOF;
		return 1;

	    case '.': 
		*ep++ = CDOT;
		continue;

	    case '*': 
		if (lastep == 0)
		    goto defchar;
		*lastep |= STAR;
		continue;

	    case '$': 
		if (*sp != '\0')
		    goto defchar;
		*ep++ = CDOL;
		continue;

	    case '[': 
		*ep++ = CCL;
		*ep++ = 0;
		cclcnt = 1;
		if ((c = *sp++) == '^') {
		    c = *sp++;
		    ep[-2] = NCCL;
		}
		do {
		    *ep++ = c;
		    cclcnt++;
		    if (c == '\0' || ep >= dp)
			goto cerror;
		} while ((c = *sp++) != ']');
		lastep[1] = cclcnt;
		continue;

	    case '\\': 
		if ((c = *sp++) == '\0')
		    goto cerror;
	defchar: 
	    default: 
		*ep++ = CCHR;
		*ep++ = c;
#ifdef JAPAN
		if (ml_ismlptr(sp - 1) && ep < dp)
		    *ep++ = *sp++;
#endif /* JAPAN */
	}
    }

cerror: ;
    return 0;
}

/*  */

/* ARGSUSED */

static int  GREPaction (params)
plist
{
    int     c,
            body,
            lf;
#ifdef MIME_HEADERS
    int     decode = 1;
#endif /* MIME_HEADERS */
    long    pos = start;
    register char  *p1,
                   *p2,
                   *ebp,
                   *cbp;
    char    ibuf[BUFSIZ];

    static char *linebuf = NULL;
    static int len = 0;
#if defined(JAPAN) || defined(MIME_HEADERS)
    static char *tmpbuf = NULL;
    static int tmplen = 0;
#endif /* JAPAN || MIME_HEADERS */

    if (linebuf == NULL) {
	if ((linebuf = malloc((unsigned) (len = LBSIZE + 1))) == NULL)
		adios (NULLCP, "unable to allocate string storage");
#if defined(JAPAN) || defined(MIME_HEADERS)
	if ((tmpbuf = malloc((unsigned) (tmplen = LBSIZE + 1))) == NULL)
		adios (NULLCP, "unable to allocate string storage");
#endif /* JAPAN || MIME_HEADERS */
    }

    (void) fseek (fp, start, 0);
    body = 0;
    ebp = cbp = ibuf;
    for (;;) {
	if (body && n -> n_header)
	    return 0;
	p1 = linebuf;
	p2 = cbp;
	lf = 0;
	for (;;) {
	    if (p2 >= ebp) {
		if (fgets (ibuf, sizeof ibuf, fp) == NULL
			|| (stop && pos >= stop)) {
		    if (lf)
			break;
		    return 0;
		}
		pos += (long) strlen (ibuf);
		p2 = ibuf;
		ebp = ibuf + strlen (ibuf);
	    }
	    c = *p2++;
	    if (lf && c != '\n')
		if (c != ' ' && c != '\t') {
		    --p2;
		    break;
		}
		else
		    lf = 0;
	    if (c == '\n')
		if (body)
		    break;
		else {
		    if (lf) {
			body++;
			break;
		    }
		    lf++;
		    c = ' ';
		}
	    if (c && p1 < &linebuf[len - 2])
		*p1++ = c;
	    else if (c) { /* buffer overflow */
		if ((linebuf = realloc(linebuf, len + LBSIZE)) == NULL)
		    adios (NULLCP, "unable to allocate string storage");
		p1 = linebuf + len - 2;
		len += LBSIZE;
		*p1++ = c;
	    }
	}

	*p1++ = 0;
	cbp = p2;
	p1 = linebuf;
	p2 = n -> n_expbuf;
#ifdef JAPAN
	(void) ml_conv(p1);
#endif /* JAPAN */
#ifdef MIME_HEADERS
	if (decode) {
	    if (tmplen < len) {
		if ((tmpbuf = realloc(tmpbuf, len)) == NULL)
		    adios (NULLCP, "unable to allocate string storage");
		tmplen = len;
	    }
	    (void) copy(p1, tmpbuf);
	    exthdr_decode(tmpbuf, p1);
	    if (body)
		decode = 0;
	}
#endif /* MIME_HEADERS */

	if (n -> n_circf) {
	    if (advance (p1, p2))
		return 1;
	    continue;
	}

	if (*p2 == CCHR) {
	    c = p2[1];
	    do {
#ifdef JAPAN
		if (*p1 == c || ((*p1 & 0xff) < 0x80 && cc[*p1] == c))
		    if (advance (p1, p2))
			return 1;
		if (ml_ismlptr(p1))
		    p1++;
#else /* JAPAN */
		if (*p1 == c || cc[*p1] == c)
		    if (advance (p1, p2))
			return 1;
#endif /* JAPAN */
	    } while (*p1++);
	    continue;
	}

	do {
	    if (advance (p1, p2))
		return 1;
#ifdef JAPAN
	    if (ml_ismlptr(p1))
		p1++;
#endif /* JAPAN */
	} while (*p1++);
    }
}

/*  */

static	int advance (alp, aep)
register char  *alp,
               *aep;
{
    register char  *lp,
                   *ep,
                   *curlp;
#ifdef JAPAN
    unsigned int c1, c2;
#endif /* JAPAN */

    lp = alp;
    ep = aep;
    for (;;)
	switch (*ep++) {
	    case CCHR: 
#ifdef JAPAN
		Get_onechar(c1, ep);
		Get_onechar(c2, lp);
		if (c1 == c2 || (c2 < 0x80 && c1 == cc[c2]))
#else /* JAPAN */
		if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
#endif /* JAPAN */
		    continue;
		return 0;

	    case CDOT: 
#ifdef JAPAN
		if (ml_ismlptr(lp))
		    lp++;
#endif /* JAPAN */
		if (*lp++)
		    continue;
		return 0;

	    case CDOL: 
		if (*lp == 0)
		    continue;
		return 0;

	    case CEOF: 
		return 1;

	    case CCL: 
#ifdef JAPAN
		Get_onechar(c2, lp);
		if (cclass (ep, c2, 1)) {
#else /* JAPAN */
		if (cclass (ep, *lp++, 1)) {
#endif /* JAPAN */
		    ep += *ep;
		    continue;
		}
		return 0;

	    case NCCL: 
#ifdef JAPAN
		Get_onechar(c2, lp);
		if (cclass (ep, c2, 0)) {
#else /* JAPAN */
		if (cclass (ep, *lp++, 0)) {
#endif /* JAPAN */
		    ep += *ep;
		    continue;
		}
		return 0;

	    case CDOT | STAR: 
		curlp = lp;
		while (*lp++)
		    continue;
		goto star;

	    case CCHR | STAR: 
		curlp = lp;
#ifdef JAPAN
		Get_onechar(c1, ep);
		do {
		    Get_onechar(c2, lp);
		} while (c2 == c1 || (c2 < 0x80 && cc[c2] == c1));
#else /* JAPAN */
		while (*lp++ == *ep || cc[lp[-1]] == *ep)
		    continue;
		ep++;
#endif /* JAPAN */
		goto star;

	    case CCL | STAR: 
	    case NCCL | STAR: 
		curlp = lp;
#ifdef JAPAN
		do {
		    Get_onechar(c2, lp);
		} while (cclass (ep, c2, ep[-1] == (CCL | STAR)));
#else /* JAPAN */
		while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
		    continue;
#endif /* JAPAN */
		ep += *ep;
		goto star;

	star: 
		do {
		    lp--;
#ifdef JAPAN
		    if (lp > curlp && ml_ismlptr(lp - 1))
			lp--;
#endif /* JAPAN */
		    if (advance (lp, ep))
			return (1);
		} while (lp > curlp);
		return 0;

	    default: 
		admonish (NULLCP, "advance() botch -- you lose big");
		return 0;
	}
}

/*  */

static	int cclass (aset, ac, af)
register char   *aset;
{
    register int    n;
    register unsigned int  c;
    register unsigned char *set;

    set = aset;
    if ((c = ac) == 0)
	return (0);

    n = *set++;
#ifdef JAPAN
    while (--n) {
	unsigned int c2 = *set & 0xff;
	if (n > 1 && ml_ismlptr(set)) {
	    c2 = (c2 << 8) | (*++set & 0xff);
	    n--;
	}
	set++;
	if (c2 == c)
	    return (af);
    }
#else /* JAPAN */
    while (--n)
	if (*set++ == c)
	    return (af);
#endif /* JAPAN */

    return (!af);
}

/*  */

static	int tcompile (ap, tb, isafter)
register char   *ap;
register struct tws *tb;
int     isafter;
{
    register struct tws *tw;

    if ((tw = tws_parse (ap, isafter)) == NULL)
	return 0;

    twscopy (tb, tw);
    return 1;
}

/*  */

static struct tws  *tws_parse (ap, isafter)
register char   *ap;
int     isafter;
{
    char    buffer[BUFSIZ];
    register struct tws *tw,
                        *ts;

    if ((tw = tws_special (ap)) != NULL) {
	tw -> tw_sec = tw -> tw_min = isafter ? 59 : 0;
	tw -> tw_hour = isafter ? 23 : 0;
	return tw;
    }
    if ((tw = dparsetime (ap)) != NULL)
	return tw;

    if ((ts = dtwstime ()) == NULL)
	return NULL;

    (void) sprintf (buffer, "%s %s", ap, dtwszone (ts));
    if ((tw = dparsetime (buffer)) != NULL)
	return tw;

    (void) sprintf (buffer, "%s %02d:%02d:%02d %s", ap,
	    ts -> tw_hour, ts -> tw_min, ts -> tw_sec, dtwszone (ts));
    if ((tw = dparsetime (buffer)) != NULL)
	return tw;

    (void) sprintf (buffer, "%02d %s %04d %s",
	    ts -> tw_mday, tw_moty[ts -> tw_mon], ts -> tw_year, ap);
    if ((tw = dparsetime (buffer)) != NULL)
	return tw;

    (void) sprintf (buffer, "%02d %s %04d %s %s",
	    ts -> tw_mday, tw_moty[ts -> tw_mon], ts -> tw_year,
	    ap, dtwszone (ts));
    if ((tw = dparsetime (buffer)) != NULL)
	return tw;

    return NULL;
}

/*  */

static struct tws  *tws_special (ap)
register char   *ap;
{
    int     i;
    time_t  clock;
    register struct tws *tw;

    (void) time (&clock);
    if (uleq (ap, "Today"))
	return dlocaltime (&clock);
    if (uleq (ap, "Yesterday")) {
	clock -= (long) (60 * 60 * 24);
	return dlocaltime (&clock);
    }
    if (uleq (ap, "Tomorrow")) {
	clock += (long) (60 * 60 * 24);
	return dlocaltime (&clock);
    }

    for (i = 0; tw_ldotw[i]; i++)
	if (uleq (ap, tw_ldotw[i]))
	    break;
    if (tw_ldotw[i]) {
	if ((tw = dlocaltime (&clock)) == NULL)
	    return NULL;
	if ((i -= tw -> tw_wday) > 0)
	    i -= 7;
    }
    else
	if (*ap != '-')
	    return NULL;
	else			/* -ddd days ago */
	    i = atoi (ap);	/* we should error check this */

    clock += (long) ((60 * 60 * 24) * i);
    return dlocaltime (&clock);
}

/*  */

/* ARGSUSED */

static int  TWSaction (params)
plist
{
    int     state;
    register char  *bp;
    char    buf[BUFSIZ],
            name[NAMESZ];
    register struct tws *tw;

    (void) fseek (fp, start, 0);
    for (state = FLD, bp = NULL;;) {
	switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
	    case FLD: 
	    case FLDEOF: 
	    case FLDPLUS: 
		if (bp != NULL)
		    free (bp), bp = NULL;
		bp = add (buf, NULLCP);
		while (state == FLDPLUS) {
		    state = m_getfld (state, name, buf, sizeof buf, fp);
		    bp = add (buf, bp);
		}
		if (uleq (name, n -> n_datef))
		    break;
		if (state != FLDEOF)
		    continue;

	    case BODY: 
	    case BODYEOF: 
	    case FILEEOF: 
	    case LENERR: 
	    case FMTERR: 
		if (state == LENERR || state == FMTERR)
		    advise (NULLCP, "format error in message %d", msgnum);
		if (bp != NULL)
		    free (bp);
		return 0;

	    default: 
		adios (NULLCP, "internal error -- you lose");
	}
	break;
    }

/*  */

    if ((tw = dparsetime (bp)) == NULL)
	advise (NULLCP, "unable to parse %s field in message %d, matching...",
		n -> n_datef, msgnum), state = 1;
    else
	state = n -> n_after ? (twsort (tw, &n -> n_tws) > 0)
	    : (twsort (tw, &n -> n_tws) < 0);

    if (bp != NULL)
	free (bp);
    return state;
}