home *** CD-ROM | disk | FTP | other *** search
- /*
- * PARTIME parse date/time string into a TM structure
- *
- * Returns:
- * 0 if parsing failed
- * else time values in specified TM structure and zone (unspecified values
- * set to TMNULL)
- * Notes:
- * This code is quasi-public; it may be used freely in like software.
- * It is not to be sold, nor used in licensed software without
- * permission of the author.
- * For everyone's benefit, please report bugs and improvements!
- * Copyright 1980 by Ken Harrenstien, SRI International.
- * (ARPANET: KLH @ SRI)
- */
-
- /* Hacknotes:
- * If parsing changed so that no backup needed, could perhaps modify
- * to use a FILE input stream. Need terminator, though.
- * Perhaps should return 0 on success, else a non-zero error val?
- */
-
- /* $Log: partime.c,v $
- * Revision 1.1.1.1 91/01/18 12:18:12 berliner
- * For CVS 1.2, contributed by Paul Eggert
- *
- * Revision 1.2 1991/01/18 00:14:49 eggert
- * Make minimal changes to interface to CVS 1.0.
- *
- * Revision 5.4 1990/10/04 06:30:15 eggert
- * Remove date vs time heuristics that fail between 2000 and 2400.
- * Check for overflow when lexing an integer.
- * Parse 'Jan 10 LT' as 'Jan 10, LT', not 'Jan, 10 LT'.
- *
- * Revision 5.3 1990/09/24 18:56:31 eggert
- * Update timezones.
- *
- * Revision 5.2 1990/09/04 08:02:16 eggert
- * Don't parse two-digit years, because it won't work after 1999/12/31.
- * Don't permit 'Aug Aug'.
- *
- * Revision 5.1 1990/08/29 07:13:49 eggert
- * Be able to parse our own date format. Don't assume year<10000.
- *
- * Revision 5.0 1990/08/22 08:12:40 eggert
- * Switch to GMT and fix the bugs exposed thereby. Update timezones.
- * Ansify and Posixate. Fix peekahead and int-size bugs.
- *
- * Revision 1.4 89/05/01 14:48:46 narten
- * fixed #ifdef DEBUG construct
- *
- * Revision 1.3 88/08/28 14:53:40 eggert
- * Remove unportable "#endif XXX"s.
- *
- * Revision 1.2 87/03/27 14:21:53 jenkins
- * Port to suns
- *
- * Revision 1.1 82/05/06 11:38:26 wft
- * Initial revision
- *
- */
-
- /* minimal changes needed to get this file to work for CVS rather than RCS */
- /* #include "rcsbase.h" */
- #include <ctype.h>
- #include <time.h>
- #include "cvs.h"
- #define libId(x,y) static char x[] = y;
- #define P(x) ()
- #if !__STDC__
- # define const
- #endif
- /* see also `RCS' in comment below */
-
- libId(partId, "$Id: partime.c,v 1.1.1.1 91/01/18 12:18:12 berliner Exp $")
-
- #define given(v) (0 <= (v))
- #define TMNULL (-1) /* Items not given are given this value */
- #define TZ_OFFSET (24*60) /* TMNULL < zone_offset - TZ_OFFSET */
-
- struct tmwent {
- const char *went;
- short wval;
- char wflgs;
- char wtype;
- };
- /* wflgs */
- #define TWTIME 02 /* Word is a time value (absence implies date) */
- #define TWDST 04 /* Word is a DST-type timezone */
- /* wtype */
- #define TM_MON 1 /* month name */
- #define TM_WDAY 2 /* weekday name */
- #define TM_ZON 3 /* time zone name */
- #define TM_LT 4 /* local time */
- #define TM_DST 5 /* daylight savings time */
- #define TM_12 6 /* AM, PM, NOON, or MIDNIGHT */
- /* wval (for wtype==TM_12) */
- #define T12_AM 1
- #define T12_PM 2
- #define T12_NOON 12
- #define T12_MIDNIGHT 0
-
- static const struct tmwent tmwords [] = {
- {"january", 0, 0, TM_MON},
- {"february", 1, 0, TM_MON},
- {"march", 2, 0, TM_MON},
- {"april", 3, 0, TM_MON},
- {"may", 4, 0, TM_MON},
- {"june", 5, 0, TM_MON},
- {"july", 6, 0, TM_MON},
- {"august", 7, 0, TM_MON},
- {"september", 8, 0, TM_MON},
- {"october", 9, 0, TM_MON},
- {"november", 10, 0, TM_MON},
- {"december", 11, 0, TM_MON},
-
- {"sunday", 0, 0, TM_WDAY},
- {"monday", 1, 0, TM_WDAY},
- {"tuesday", 2, 0, TM_WDAY},
- {"wednesday", 3, 0, TM_WDAY},
- {"thursday", 4, 0, TM_WDAY},
- {"friday", 5, 0, TM_WDAY},
- {"saturday", 6, 0, TM_WDAY},
-
- {"gmt", 0*60, TWTIME, TM_ZON}, /* Greenwich */
- {"utc", 0*60, TWTIME, TM_ZON},
- {"ut", 0*60, TWTIME, TM_ZON},
-
- {"nzst", -12*60, TWTIME, TM_ZON}, /* New Zealand */
- {"jst", -9*60, TWTIME, TM_ZON}, /* Japan */
- {"kst", -9*60, TWTIME, TM_ZON}, /* Korea */
- {"ist", -5*60-30, TWTIME, TM_ZON},/* India */
- {"eet", -2*60, TWTIME, TM_ZON}, /* Eastern Europe */
- {"cet", -1*60, TWTIME, TM_ZON}, /* Central Europe */
- {"met", -1*60, TWTIME, TM_ZON}, /* Middle Europe */
- {"wet", 0*60, TWTIME, TM_ZON}, /* Western Europe */
- {"nst", 3*60+30, TWTIME, TM_ZON},/* Newfoundland */
- {"ast", 4*60, TWTIME, TM_ZON}, /* Atlantic */
- {"est", 5*60, TWTIME, TM_ZON}, /* Eastern */
- {"cst", 6*60, TWTIME, TM_ZON}, /* Central */
- {"mst", 7*60, TWTIME, TM_ZON}, /* Mountain */
- {"pst", 8*60, TWTIME, TM_ZON}, /* Pacific */
- {"akst", 9*60, TWTIME, TM_ZON}, /* Alaska */
- {"hast", 10*60, TWTIME, TM_ZON}, /* Hawaii-Aleutian */
- {"hst", 10*60, TWTIME, TM_ZON}, /* Hawaii */
- {"sst", 11*60, TWTIME, TM_ZON}, /* Samoa */
-
- {"nzdt", -12*60, TWTIME+TWDST, TM_ZON}, /* New Zealand */
- {"kdt", -9*60, TWTIME+TWDST, TM_ZON}, /* Korea */
- {"bst", 0*60, TWTIME+TWDST, TM_ZON}, /* Britain */
- {"ndt", 2*60+30, TWTIME+TWDST, TM_ZON}, /*Newfoundland (DDST)*/
- {"adt", 4*60, TWTIME+TWDST, TM_ZON}, /* Atlantic */
- {"edt", 5*60, TWTIME+TWDST, TM_ZON}, /* Eastern */
- {"cdt", 6*60, TWTIME+TWDST, TM_ZON}, /* Central */
- {"mdt", 7*60, TWTIME+TWDST, TM_ZON}, /* Mountain */
- {"pdt", 8*60, TWTIME+TWDST, TM_ZON}, /* Pacific */
- {"akdt", 9*60, TWTIME+TWDST, TM_ZON}, /* Alaska */
- {"hadt", 10*60, TWTIME+TWDST, TM_ZON}, /* Hawaii-Aleutian */
-
- #if 0
- /*
- * The following names are duplicates or are not well attested.
- * A standard is needed.
- */
- {"?st", -13*60, TWTIME, TM_ZON}, /* Uelen */
- {"?st", -11*60, TWTIME, TM_ZON}, /* Magadan */
- {"east", -10*60, TWTIME, TM_ZON}, /* Eastern Australia */
- {"cast", -9*60-30, TWTIME, TM_ZON},/* Central Australia */
- {"cst", -8*60, TWTIME, TM_ZON}, /* China */
- {"hkt", -8*60, TWTIME, TM_ZON}, /* Hong Kong */
- {"sst", -8*60, TWTIME, TM_ZON}, /* Singapore */
- {"wast", -8*60, TWTIME, TM_ZON}, /* Western Australia */
- {"?st", -7*60, TWTIME, TM_ZON}, /* Novosibirsk */
- {"jt", -7*60-30, TWTIME, TM_ZON},/* Java */
- {"nst", -6*60-30, TWTIME, TM_ZON},/* North Sumatra */
- {"?st", -6*60, TWTIME, TM_ZON}, /* Tashkent */
- {"?st", -5*60, TWTIME, TM_ZON}, /* Sverdlovsk */
- {"?", -4*60-30, TWTIME, TM_ZON},/* Afghanistan */
- {"?st", -4*60, TWTIME, TM_ZON}, /* Rostov */
- {"it", -3*60-30, TWTIME, TM_ZON},/* Iran */
- {"?st", -3*60, TWTIME, TM_ZON}, /* Moscow */
- {"ist", -2*60, TWTIME, TM_ZON}, /* Israel */
- {"ast", 1*60, TWTIME, TM_ZON}, /* Azores */
- {"fst", 2*60, TWTIME, TM_ZON}, /* Fernando de Noronha */
- {"bst", 3*60, TWTIME, TM_ZON}, /* Brazil */
- {"wst", 4*60, TWTIME, TM_ZON}, /* Western Brazil */
- {"ast", 5*60, TWTIME, TM_ZON}, /* Acre Brazil */
- {"?", 9*60+30, TWTIME, TM_ZON},/* Marquesas */
- {"?st", 12*60, TWTIME, TM_ZON}, /* Kwajalein */
-
- {"?dt", -13*60, TWTIME+TWDST, TM_ZON}, /* Uelen */
- {"?dt", -11*60, TWTIME+TWDST, TM_ZON}, /* Magadan */
- {"eadt", -10*60, TWTIME+TWDST, TM_ZON}, /* Eastern Australia */
- {"cadt", -9*60-30, TWTIME+TWDST, TM_ZON}, /* Central Australia */
- {"cdt", -8*60, TWTIME+TWDST, TM_ZON}, /* China */
- {"wadt", -8*60, TWTIME+TWDST, TM_ZON}, /* Western Australia */
- {"?dt", -7*60, TWTIME+TWDST, TM_ZON}, /* Novosibirsk */
- {"?dt", -6*60, TWTIME+TWDST, TM_ZON}, /* Tashkent */
- {"?dt", -5*60, TWTIME+TWDST, TM_ZON}, /* Sverdlovsk */
- {"?dt", -4*60, TWTIME+TWDST, TM_ZON}, /* Rostov */
- {"?dt", -3*60, TWTIME+TWDST, TM_ZON}, /* Moscow */
- {"idt", -2*60, TWTIME+TWDST, TM_ZON}, /* Israel */
- {"eest", -2*60, TWTIME+TWDST, TM_ZON}, /* Eastern Europe */
- {"cest", -1*60, TWTIME+TWDST, TM_ZON}, /* Central Europe */
- {"mest", -1*60, TWTIME+TWDST, TM_ZON}, /* Middle Europe */
- {"west", 0*60, TWTIME+TWDST, TM_ZON}, /* Western Europe */
- {"adt", 1*60, TWTIME+TWDST, TM_ZON}, /* Azores */
- {"fdt", 2*60, TWTIME+TWDST, TM_ZON}, /* Fernando de Noronha */
- {"edt", 3*60, TWTIME+TWDST, TM_ZON}, /* Eastern Brazil */
- {"wdt", 4*60, TWTIME+TWDST, TM_ZON}, /* Western Brazil */
- {"adt", 5*60, TWTIME+TWDST, TM_ZON}, /* Acre Brazil */
- #endif
-
- {"lt", 0, TWTIME, TM_LT}, /* local time */
- {"dst", 1*60, TWTIME, TM_DST}, /* daylight savings time */
- {"ddst", 2*60, TWTIME, TM_DST}, /* double dst */
-
- {"am", T12_AM, TWTIME, TM_12},
- {"pm", T12_PM, TWTIME, TM_12},
- {"noon", T12_NOON, TWTIME, TM_12},
- {"midnight", T12_MIDNIGHT, TWTIME, TM_12},
-
- {0, 0, 0, 0}, /* Zero entry to terminate searches */
- };
-
- struct token {
- const char *tcp;/* pointer to string */
- int tcnt; /* # chars */
- char tbrk; /* "break" char */
- char tbrkl; /* last break char */
- char tflg; /* 0 = alpha, 1 = numeric */
- union { /* Resulting value; */
- int tnum;/* either a #, or */
- const struct tmwent *ttmw;/* ptr to a tmwent. */
- } tval;
- };
-
- static const struct tmwent*ptmatchstr P((const char*,int,const struct tmwent*));
- static int pt12hack P((struct tm *,int));
- static int ptitoken P((struct token *));
- static int ptstash P((int *,int));
- static int pttoken P((struct token *));
-
- static int
- goodzone(t, offset, am)
- register const struct token *t;
- int offset;
- int *am;
- {
- register int m;
- if (
- t->tflg &&
- t->tcnt == 4+offset &&
- (m = t->tval.tnum) <= 2400 &&
- isdigit(t->tcp[offset]) &&
- (m%=100) < 60
- ) {
- m += t->tval.tnum/100 * 60;
- if (t->tcp[offset-1]=='+')
- m = -m;
- *am = m;
- return 1;
- }
- return 0;
- }
-
- int
- partime(astr, atm, zone)
- const char *astr;
- register struct tm *atm;
- int *zone;
- {
- register int i;
- struct token btoken, atoken;
- int zone_offset; /* minutes west of GMT, plus TZ_OFFSET */
- register const char *cp;
- register char ch;
- int ord, midnoon;
- int *atmfield, dst, m;
- int got1 = 0;
-
- atm->tm_sec = TMNULL;
- atm->tm_min = TMNULL;
- atm->tm_hour = TMNULL;
- atm->tm_mday = TMNULL;
- atm->tm_mon = TMNULL;
- atm->tm_year = TMNULL;
- atm->tm_wday = TMNULL;
- atm->tm_yday = TMNULL;
- midnoon = TMNULL; /* and our own temp stuff */
- zone_offset = TMNULL;
- dst = TMNULL;
- btoken.tcnt = btoken.tbrk = 0;
- btoken.tcp = astr;
-
- for (;; got1=1) {
- if (!ptitoken(&btoken)) /* Get a token */
- { if(btoken.tval.tnum) return(0); /* Read error? */
- if (given(midnoon)) /* EOF, wrap up */
- if (!pt12hack(atm, midnoon))
- return 0;
- if (!given(atm->tm_min))
- atm->tm_min = 0;
- *zone =
- (given(zone_offset) ? zone_offset-TZ_OFFSET : 0)
- - (given(dst) ? dst : 0);
- return got1;
- }
- if(btoken.tflg == 0) /* Alpha? */
- { i = btoken.tval.ttmw->wval;
- switch (btoken.tval.ttmw->wtype) {
- default:
- return 0;
- case TM_MON:
- atmfield = &atm->tm_mon;
- break;
- case TM_WDAY:
- atmfield = &atm->tm_wday;
- break;
- case TM_DST:
- atmfield = &dst;
- break;
- case TM_LT:
- if (ptstash(&dst, 0))
- return 0;
- i = 48*60; /* local time magic number -- see maketime() */
- /* fall into */
- case TM_ZON:
- i += TZ_OFFSET;
- if (btoken.tval.ttmw->wflgs & TWDST)
- if (ptstash(&dst, 60))
- return 0;
- /* Peek ahead for offset immediately afterwards. */
- if (
- (btoken.tbrk=='-' || btoken.tbrk=='+') &&
- (atoken=btoken, ++atoken.tcnt, ptitoken(&atoken)) &&
- goodzone(&atoken, 0, &m)
- ) {
- i += m;
- btoken = atoken;
- }
- atmfield = &zone_offset;
- break;
- case TM_12:
- atmfield = &midnoon;
- }
- if (ptstash(atmfield, i))
- return(0); /* ERR: val already set */
- continue;
- }
-
- /* Token is number. Lots of hairy heuristics. */
- if (!isdigit(*btoken.tcp)) {
- if (!goodzone(&btoken, 1, &m))
- return 0;
- zone_offset = TZ_OFFSET + m;
- continue;
- }
-
- i = btoken.tval.tnum; /* Value now known to be valid; get it. */
- if (btoken.tcnt == 3) /* 3 digits = HMM */
- {
- hhmm4: if (ptstash(&atm->tm_min, i%100))
- return(0); /* ERR: min conflict */
- i /= 100;
- hh2: if (ptstash(&atm->tm_hour, i))
- return(0); /* ERR: hour conflict */
- continue;
- }
-
- if (4 < btoken.tcnt)
- goto year4; /* far in the future */
- if(btoken.tcnt == 4) /* 4 digits = YEAR or HHMM */
- { if (given(atm->tm_year)) goto hhmm4; /* Already got yr? */
- if (given(atm->tm_hour)) goto year4; /* Already got hr? */
- if(btoken.tbrk == ':') /* HHMM:SS ? */
- if ( ptstash(&atm->tm_hour, i/100)
- || ptstash(&atm->tm_min, i%100))
- return(0); /* ERR: hr/min clash */
- else goto coltm2; /* Go handle SS */
- if(btoken.tbrk != ',' && btoken.tbrk != '/'
- && (atoken=btoken, ptitoken(&atoken)) /* Peek */
- && ( atoken.tflg
- ? !isdigit(*atoken.tcp)
- : atoken.tval.ttmw->wflgs & TWTIME)) /* HHMM-ZON */
- goto hhmm4;
- goto year4; /* Give up, assume year. */
- }
-
- /* From this point on, assume tcnt == 1 or 2 */
- /* 2 digits = MM, DD, or HH (MM and SS caught at coltime) */
- if(btoken.tbrk == ':') /* HH:MM[:SS] */
- goto coltime; /* must be part of time. */
- if (31 < i)
- return 0;
-
- /* Check for numerical-format date */
- for (cp = "/-."; ch = *cp++;)
- { ord = (ch == '.' ? 0 : 1); /* n/m = D/M or M/D */
- if(btoken.tbrk == ch) /* "NN-" */
- { if(btoken.tbrkl != ch)
- {
- atoken = btoken;
- atoken.tcnt++;
- if (ptitoken(&atoken)
- && atoken.tflg == 0
- && atoken.tval.ttmw->wtype == TM_MON)
- goto dd2;
- if(ord)goto mm2; else goto dd2; /* "NN-" */
- } /* "-NN-" */
- if (!given(atm->tm_mday)
- && given(atm->tm_year)) /* If "YYYY-NN-" */
- goto mm2; /* then always MM */
- if(ord)goto dd2; else goto mm2;
- }
- if(btoken.tbrkl == ch /* "-NN" */
- && given(ord ? atm->tm_mon : atm->tm_mday))
- if (!given(ord ? atm->tm_mday : atm->tm_mon)) /* MM/DD */
- if(ord)goto dd2; else goto mm2;
- }
-
- /* Now reduced to choice between HH and DD */
- if (given(atm->tm_hour)) goto dd2; /* Have hour? Assume day. */
- if (given(atm->tm_mday)) goto hh2; /* Have day? Assume hour. */
- if (given(atm->tm_mon)) goto dd2; /* Have month? Assume day. */
- if(i > 24) goto dd2; /* Impossible HH means DD */
- atoken = btoken;
- if (!ptitoken(&atoken)) /* Read ahead! */
- if(atoken.tval.tnum) return(0); /* ERR: bad token */
- else goto dd2; /* EOF, assume day. */
- if ( atoken.tflg
- ? !isdigit(*atoken.tcp)
- : atoken.tval.ttmw->wflgs & TWTIME)
- /* If next token is a time spec, assume hour */
- goto hh2; /* e.g. "3 PM", "11-EDT" */
-
- dd2: if (ptstash(&atm->tm_mday, i)) /* Store day (1 based) */
- return(0);
- continue;
-
- mm2: if (ptstash(&atm->tm_mon, i-1)) /* Store month (make zero based) */
- return(0);
- continue;
-
- year4: if ((i-=1900) < 0 || ptstash(&atm->tm_year, i)) /* Store year-1900 */
- return(0); /* ERR: year conflict */
- continue;
-
- /* Hack HH:MM[[:]SS] */
- coltime:
- if (ptstash(&atm->tm_hour, i)) return 0;
- if (!ptitoken(&btoken))
- return(!btoken.tval.tnum);
- if(!btoken.tflg) return(0); /* ERR: HH:<alpha> */
- if(btoken.tcnt == 4) /* MMSS */
- if (ptstash(&atm->tm_min, btoken.tval.tnum/100)
- || ptstash(&atm->tm_sec, btoken.tval.tnum%100))
- return(0);
- else continue;
- if(btoken.tcnt != 2
- || ptstash(&atm->tm_min, btoken.tval.tnum))
- return(0); /* ERR: MM bad */
- if (btoken.tbrk != ':') continue; /* Seconds follow? */
- coltm2: if (!ptitoken(&btoken))
- return(!btoken.tval.tnum);
- if(!btoken.tflg || btoken.tcnt != 2 /* Verify SS */
- || ptstash(&atm->tm_sec, btoken.tval.tnum))
- return(0); /* ERR: SS bad */
- }
- }
-
- /* Store date/time value, return 0 if successful.
- * Fail if entry is already set.
- */
- static int
- ptstash(adr,val)
- int *adr;
- int val;
- { register int *a;
- if (given(*(a=adr)))
- return 1;
- *a = val;
- return(0);
- }
-
- /* This subroutine is invoked for AM, PM, NOON and MIDNIGHT when wrapping up
- * just prior to returning from partime.
- */
- static int
- pt12hack(tm, aval)
- register struct tm *tm;
- register int aval;
- { register int h = tm->tm_hour;
- switch (aval) {
- case T12_AM:
- case T12_PM:
- if (h > 12)
- return 0;
- if (h == 12)
- tm->tm_hour = 0;
- if (aval == T12_PM)
- tm->tm_hour += 12;
- break;
- default:
- if (0 < tm->tm_min || 0 < tm->tm_sec)
- return 0;
- if (!given(h) || h==12)
- tm->tm_hour = aval;
- else if (aval==T12_MIDNIGHT && (h==0 || h==24))
- return 0;
- }
- return 1;
- }
-
- /* Get a token and identify it to some degree.
- * Returns 0 on failure; token.tval will be 0 for normal EOF, otherwise
- * hit error of some sort
- */
-
- static int
- ptitoken(tkp)
- register struct token *tkp;
- {
- register const char *cp;
- register int i, j, k;
-
- if (!pttoken(tkp))
- #ifdef DEBUG
- {
- VOID printf("EOF\n");
- return(0);
- }
- #else
- return(0);
- #endif
- cp = tkp->tcp;
-
- #ifdef DEBUG
- VOID printf("Token: \"%.*s\" ", tkp->tcnt, cp);
- #endif
-
- if (tkp->tflg) {
- i = tkp->tcnt;
- if (*cp == '+' || *cp == '-') {
- cp++;
- i--;
- }
- while (0 <= --i) {
- j = tkp->tval.tnum*10;
- k = j + (*cp++ - '0');
- if (j/10 != tkp->tval.tnum || k < j) {
- /* arithmetic overflow */
- tkp->tval.tnum = 1;
- return 0;
- }
- tkp->tval.tnum = k;
- }
- } else if (!(tkp->tval.ttmw = ptmatchstr(cp, tkp->tcnt, tmwords)))
- {
- #ifdef DEBUG
- VOID printf("Not found!\n");
- #endif
- tkp->tval.tnum = 1;
- return 0;
- }
-
- #ifdef DEBUG
- if(tkp->tflg)
- VOID printf("Val: %d.\n",tkp->tval.tnum);
- else VOID printf("Found: \"%s\", val: %d, type %d\n",
- tkp->tval.ttmw->went,tkp->tval.ttmw->wval,tkp->tval.ttmw->wtype);
- #endif
-
- return(1);
- }
-
- /* Read token from input string into token structure */
- static int
- pttoken(tkp)
- register struct token *tkp;
- {
- register const char *cp;
- register int c;
- const char *astr;
-
- tkp->tcp = astr = cp = tkp->tcp + tkp->tcnt;
- tkp->tbrkl = tkp->tbrk; /* Set "last break" */
- tkp->tcnt = tkp->tbrk = tkp->tflg = 0;
- tkp->tval.tnum = 0;
-
- while(c = *cp++)
- { switch(c)
- { case ' ': case '\t': /* Flush all whitespace */
- case '\r': case '\n':
- case '\v': case '\f':
- if (!tkp->tcnt) { /* If no token yet */
- tkp->tcp = cp; /* ignore the brk */
- continue; /* and go on. */
- }
- /* fall into */
- case '(': case ')': /* Perhaps any non-alphanum */
- case '-': case ',': /* shd qualify as break? */
- case '+':
- case '/': case ':': case '.': /* Break chars */
- if(tkp->tcnt == 0) /* If no token yet */
- { tkp->tcp = cp; /* ignore the brk */
- tkp->tbrkl = c;
- continue; /* and go on. */
- }
- tkp->tbrk = c;
- return(tkp->tcnt);
- }
- if (!tkp->tcnt++) { /* If first char of token, */
- if (isdigit(c)) {
- tkp->tflg = 1;
- if (astr<cp-2 && (cp[-2]=='-'||cp[-2]=='+')) {
- /* timezone is break+sign+digit */
- tkp->tcp--;
- tkp->tcnt++;
- }
- }
- } else if ((isdigit(c)!=0) != tkp->tflg) { /* else check type */
- tkp->tbrk = c;
- return --tkp->tcnt; /* Wrong type, back up */
- }
- }
- return(tkp->tcnt); /* When hit EOF */
- }
-
-
- static const struct tmwent *
- ptmatchstr(astr,cnt,astruc)
- const char *astr;
- int cnt;
- const struct tmwent *astruc;
- {
- register const char *cp, *mp;
- register int c;
- const struct tmwent *lastptr;
- int i;
-
- lastptr = 0;
- for(;mp = astruc->went; astruc += 1)
- { cp = astr;
- for(i = cnt; i > 0; i--)
- {
- switch (*cp++ - (c = *mp++))
- { case 0: continue; /* Exact match */
- case 'A'-'a':
- /* `if (ctab[c]==Letter)' in RCS */
- if (islower(c))
- continue;
- }
- break;
- }
- if(i==0)
- if (!*mp) return astruc; /* Exact match */
- else if(lastptr) return(0); /* Ambiguous */
- else lastptr = astruc; /* 1st ambig */
- }
- return lastptr;
- }
-