summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/rcs/lib/partime.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/rcs/lib/partime.c')
-rw-r--r--gnu/usr.bin/rcs/lib/partime.c639
1 files changed, 639 insertions, 0 deletions
diff --git a/gnu/usr.bin/rcs/lib/partime.c b/gnu/usr.bin/rcs/lib/partime.c
new file mode 100644
index 0000000..4751fc5
--- /dev/null
+++ b/gnu/usr.bin/rcs/lib/partime.c
@@ -0,0 +1,639 @@
+/*
+ * 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 5.6 1991/08/19 03:13:55 eggert
+ * Update timezones.
+ *
+ * Revision 5.5 1991/04/21 11:58:18 eggert
+ * Don't put , just before } in initializer.
+ *
+ * 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
+ *
+ */
+
+#include "rcsbase.h"
+
+libId(partId, "$Id: partime.c,v 5.6 1991/08/19 03:13:55 eggert 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 {
+ char const *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 struct tmwent const 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},
+ {"cut", 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", 3*60+30, TWTIME+TWDST, TM_ZON}, /* Newfoundland */
+ {"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.
+ */
+ {"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 */
+ {"?", -6*60-30, TWTIME, TM_ZON},/* Burma */
+ {"?", -4*60-30, TWTIME, TM_ZON},/* Afghanistan */
+ {"it", -3*60-30, TWTIME, TM_ZON},/* Iran */
+ {"ist", -2*60, TWTIME, TM_ZON}, /* Israel */
+ {"mez", -1*60, TWTIME, TM_ZON}, /* Mittel-Europaeische Zeit */
+ {"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 */
+ {"?", 12*60, TWTIME, TM_ZON}, /* Kwajalein */
+
+ {"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 */
+ {"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 */
+ {"mesz", -1*60, TWTIME+TWDST, TM_ZON}, /* Mittel-Europaeische Sommerzeit */
+ {"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 {
+ char const *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 */
+ struct tmwent const *ttmw;/* a ptr to a tmwent. */
+ } tval;
+};
+
+static struct tmwent const*ptmatchstr P((char const*,int,struct tmwent const*));
+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 struct token const *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)
+char const *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 char const *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 char const *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 char const *cp;
+ register int c;
+ char const *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 struct tmwent const *
+ptmatchstr(astr,cnt,astruc)
+ char const *astr;
+ int cnt;
+ struct tmwent const *astruc;
+{
+ register char const *cp, *mp;
+ register int c;
+ struct tmwent const *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)
+ continue;
+ }
+ break;
+ }
+ if(i==0)
+ if (!*mp) return astruc; /* Exact match */
+ else if(lastptr) return(0); /* Ambiguous */
+ else lastptr = astruc; /* 1st ambig */
+ }
+ return lastptr;
+}
OpenPOWER on IntegriCloud