home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / cnews.tar / libc / dateabstoks.c < prev    next >
C/C++ Source or Header  |  1992-11-06  |  9KB  |  293 lines

  1. /*
  2.  * datetok - date tokenisation
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <string.h>
  8. #include <sys/types.h>        /* for dateconv.h */
  9. #include "dateconv.h"
  10. #include "datetok.h"
  11.  
  12. /* imports */
  13. int dtok_numparsed;
  14.  
  15. /*
  16.  * this table is guaranteed to contain errors; alphabetic time zones
  17.  * are poorly-defined, ambiguous and a stupid idea (e.g. given a
  18.  * typical name, matching [A-Z][DS]T, the last letter is constant and
  19.  * the second letter conveys a whopping 1 bit of information, so all
  20.  * the information has to be crammed into the first letter).
  21.  * Death to alphabetic time zones!
  22.  *
  23.  * to keep this table reasonably small, we compact the lexval for TZ and DTZ
  24.  * entries and truncate the text field at MAXTOKLEN characters.
  25.  * the text field is not guaranteed to be NUL-terminated.
  26.  * ST = Standard Time; DT = Daylight Time.
  27.  */
  28. datetkn dateabstoks[] = {
  29. /*     text        token    lexval */
  30.     "acsst",    DTZ,    PACK(630),    /* Cent. Australia */
  31.     "acst",        TZ,    PACK(570),    /* Cent. Australia */
  32.     "adt",        DTZ,    PACK(-180),    /* Atlantic DT */
  33.     "aesst",    DTZ,    PACK(660),    /* E. Australia */
  34.     "aest",        TZ,    PACK(600),    /* Australia Eastern ST */
  35.     "akdt",        DTZ,    PACK(-480),    /* Alaska DT */
  36.     "akst",        TZ,    PACK(-540),    /* Alaska ST */
  37.     "am",        AMPM,    AM,
  38.     "apr",        MONTH,    4,
  39.     "april",    MONTH,    4,
  40.     "ast",        TZ,    PACK(-240),    /* Atlantic ST (Canada) */
  41.     "at",        IGNORE,    0,        /* "at" (throwaway) */
  42.     "aug",        MONTH,    8,
  43.     "august",    MONTH,    8,
  44.     "awst",        TZ,    PACK(480),    /* W. Australia */
  45.     "bst",        DTZ,    PACK(60),    /* British Summer Time */
  46.     "cadt",        DTZ,    PACK(630),    /* Central Australian DT */
  47.     "cast",        TZ,    PACK(570),    /* Central Australian ST */
  48.     "cct",        TZ,    PACK(480),    /* China Coast */
  49.     "cdt",        DTZ,    PACK(-300),    /* Central DT */
  50.     "cest",        DTZ,    PACK(120),    /* Central Europe Summer Time */
  51.     "cet",        TZ,    PACK(60),    /* Central European Time */
  52.     "cetdst",    DTZ,    PACK(120),    /* Central European DT */
  53.     "cst",        TZ,    PACK(-360),    /* Central ST */
  54.     "dec",        MONTH,    12,
  55.     "decemb",    MONTH,    12,
  56.     "dnt",        TZ,    PACK(60),    /* Dansk Normal Tid */
  57. /*XX*/    "dst",        IGNORE,    0,
  58.     "eadt",        DTZ,    PACK(660),    /* East Australian DT */
  59.     "east",        TZ,    PACK(600),    /* East Australian ST */
  60.     "edt",        DTZ,    PACK(-240),    /* Eastern DT */
  61.     "eest",        DTZ,    PACK(180),    /* Eastern Europe Summer */
  62.     "eet",        TZ,    PACK(120),    /* Eastern Europe */
  63.     "eetdst",    DTZ,    PACK(180),    /* Eastern Europe */
  64.     "est",        TZ,    PACK(-300),    /* Eastern ST */
  65.     "feb",        MONTH,    2,
  66.     "februa",    MONTH,    2,
  67.     "fri",        IGNORE,    5,
  68.     "friday",    IGNORE,    5,
  69.     "fst",        DTZ,    PACK(120),    /* French Summer Time */
  70.     "fwt",        TZ,    PACK(60),    /* French Winter Time  */
  71.     "gmt",        TZ,    PACK(0),    /* Greenwich Mean Time */
  72.     "gst",        TZ,    PACK(600),    /* Guam ST */
  73.     "hadt",        DTZ,    PACK(-540),    /* Hawaii-Aleutian DT */
  74.     "hast",        TZ,    PACK(-600),    /* Hawaii-Aleutian ST */
  75.     "hkt",        TZ,    PACK(480),    /* Hong Kong Time */
  76.     "hst",        TZ,    PACK(-600),    /* Hawaii ST */
  77.     "idle",        TZ,    PACK(720),    /* Intl. Date Line, East */
  78.     "idlw",        TZ,    PACK(-720),    /* Intl. Date Line, West */
  79.     "idt",        DTZ,    PACK(180),    /* Israel DT */
  80.     "ist",        TZ,    PACK(120),    /* Israel */
  81.     "jan",        MONTH,    1,
  82.     "januar",    MONTH,    1,
  83.     "jst",        TZ,    PACK(540),    /* Japan ST */
  84.     "jul",        MONTH,    7,
  85.     "july",        MONTH,    7,
  86.     "jun",        MONTH,    6,
  87.     "june",        MONTH,    6,
  88.     "kdt",        DTZ,    PACK(600),    /* Korea DT */
  89.     "kst",        TZ,    PACK(540),    /* Korea ST */
  90. /*XX*/    "ligt",        TZ,    PACK(600),    /* From Melbourne, Australia */
  91.     "mar",        MONTH,    3,
  92.     "march",    MONTH,    3,
  93.     "may",        MONTH,    5,
  94.     "mdt",        DTZ,    PACK(-360),    /* Mountain DT */
  95.     "mest",        DTZ,    PACK(120),    /* Middle Europe Summer Time */
  96.     "mesz",        DTZ,    PACK(120),    /* Mittel-Europaeische Sommerzeit */
  97.     "met",        TZ,    PACK(60),    /* Middle Europe Time */
  98.     "metdst",    DTZ,    PACK(120),    /* Middle Europe DT */
  99.     "mewt",        TZ,    PACK(60),    /* Middle Europe Winter Time */
  100.     "mez",        TZ,    PACK(60),    /* Mittel-Europaeische Zeit */
  101.     "mon",        IGNORE,    1,
  102.     "monday",    IGNORE,    1,
  103.     "mst",        TZ,    PACK(-420),    /* Mountain ST */
  104.     "ndt",        DTZ,    PACK(-150),    /* Newfoundland DT */
  105. /*XXN*/    "nft",        TZ,    PACK(-210),    /* Newfoundland ST */
  106. /*XX*/    "nor",        TZ,    PACK(60),    /* Norway ST */
  107.     "nov",        MONTH,    11,
  108.     "novemb",    MONTH,    11,
  109.     "nst",        TZ,    PACK(-210),    /* Newfoundland ST */
  110.     "nzdt",        DTZ,    PACK(780),    /* New Zealand DT */
  111.     "nzst",        TZ,    PACK(720),    /* New Zealand ST */
  112.     "nzt",        TZ,    PACK(720),    /* New Zealand Time */
  113.     "oct",        MONTH,    10,
  114.     "octobe",    MONTH,    10,
  115.     "on",        IGNORE,    0,        /* "on" (throwaway) */
  116.     "pdt",        DTZ,    PACK(-420),    /* Pacific DT */
  117.     "pm",        AMPM,    PM,
  118.     "pst",        TZ,    PACK(-480),    /* Pacific ST */
  119.     "sadt",        DTZ,    PACK(630),    /* S. Australian DT */
  120.     "sast",        TZ,    PACK(570),    /* S. Australian ST */
  121.     "sat",        IGNORE,    6,
  122.     "saturd",    IGNORE,    6,
  123.     "sep",        MONTH,    9,
  124.     "sept",        MONTH,    9,
  125.     "septem",    MONTH,    9,
  126.     "sst",        DTZ,    PACK(120),    /* Swedish Summer Time */
  127.     "sun",        IGNORE,    0,
  128.     "sunday",    IGNORE,    0,
  129.     "swt",        TZ,    PACK(60),    /* Swedish Winter Time  */
  130.     "thu",        IGNORE,    4,
  131.     "thur",        IGNORE,    4,
  132.     "thurs",    IGNORE,    4,
  133.     "thursd",    IGNORE,    4,
  134.     "tue",        IGNORE,    2,
  135.     "tues",        IGNORE,    2,
  136.     "tuesda",    IGNORE,    2,
  137.     "ut",        TZ,    PACK(0),
  138.     "utc",        TZ,    PACK(0),
  139.     "wast",        TZ,    PACK(480),    /* West Australian ST */
  140.     "wat",        TZ,    PACK(-60),    /* West Africa Time */
  141.     "wed",        IGNORE,    3,
  142.     "wednes",    IGNORE,    3,
  143.     "weds",        IGNORE,    3,
  144.     "west",        DTZ,    PACK(60),    /* Western Europe Summer */
  145.     "wet",        TZ,    PACK(0),    /* Western Europe */
  146.     "wetdst",    DTZ,    PACK(60),    /* Western Europe */
  147.     "wst",        TZ,    PACK(480),    /* West Australian ST */
  148.     "ydt",        DTZ,    PACK(-480),    /* Yukon DT */
  149.     "yst",        TZ,    PACK(-540),    /* Yukon ST */
  150. };
  151.  
  152. #if    0
  153. /*
  154.  * these time zones are orphans, i.e. the name is also used by a more
  155.  * likely-to-appear time zone
  156.  */
  157.     "adt",        DTZ,    PACK(0),    /* Azores DT */
  158.     "adt",        DTZ,    PACK(-240),    /* Acre DT */
  159.     "ast",        TZ,    PACK(-60),    /* Azores ST */
  160.     "ast",        TZ,    PACK(-300),    /* Acre ST */
  161.     "bst",        TZ,    PACK(-180),    /* Brazil ST */
  162.     "cdt",        DTZ,    PACK(-180),    /* Chile DT */
  163.     "cdt",        DTZ,    PACK(-240),    /* Cuba DT */
  164.     "cdt",        DTZ,    PACK(540),    /* China DT */
  165.     "cst",        TZ,    PACK(-240),    /* Chile ST */
  166.     "cst",        TZ,    PACK(-300),    /* Cuba ST */
  167.     "cst",        TZ,    PACK(480),    /* China ST */
  168.     "edt",        DTZ,    PACK(-300),    /* Easter Island DT */
  169.     "edt",        DTZ,    PACK(-120),    /* East Brazil DT */
  170.     "edt",        DTZ,    PACK(660),    /* Australian Eastern DT */
  171.     "est",        TZ,    PACK(-360),    /* Easter Island ST */
  172.     "est",        TZ,    PACK(-180),    /* East Brazil ST */
  173.     "est",        TZ,    PACK(600),    /* Australian Eastern ST */
  174.     "fdt",        DTZ,    PACK(-60),    /* Fernando de Noronha DT */
  175.     "fst",        TZ,    PACK(-120),    /* Fernando de Noronha ST */
  176.     "ist",        TZ,    PACK(330),    /* Indian ST */
  177.     "sst",        TZ,    PACK(-660),    /* Samoa ST */
  178.     "sst",        TZ,    PACK(480),    /* Singapore ST */
  179.     "wdt",        DTZ,    PACK(-180),    /* Western Brazil DT */
  180.     "wet",        TZ,    PACK(60),    /* Western European Time */
  181.     "wst",        TZ,    PACK(-240),    /* Western Brazil ST */
  182. /* military timezones are deprecated by RFC 1123 section 5.2.14 */
  183.     "a",        TZ,    PACK(60),    /* UTC+1h */
  184.     "b",        TZ,    PACK(120),    /* UTC+2h */
  185.     "c",        TZ,    PACK(180),    /* UTC+3h */
  186.     "d",        TZ,    PACK(240),    /* UTC+4h */
  187.     "e",        TZ,    PACK(300),    /* UTC+5h */
  188.     "f",        TZ,    PACK(360),    /* UTC+6h */
  189.     "g",        TZ,    PACK(420),    /* UTC+7h */
  190.     "h",        TZ,    PACK(480),    /* UTC+8h */
  191.     "i",        TZ,    PACK(540),    /* UTC+9h */
  192.     "k",        TZ,    PACK(600),    /* UTC+10h */
  193.     "l",        TZ,    PACK(660),    /* UTC+11h */
  194.     "m",        TZ,    PACK(720),    /* UTC+12h */
  195.     "n",        TZ,    PACK(-60),    /* UTC-1h */
  196.     "o",        TZ,    PACK(-120),    /* UTC-2h */
  197.     "p",        TZ,    PACK(-180),    /* UTC-3h */
  198.     "q",        TZ,    PACK(-240),    /* UTC-4h */
  199.     "r",        TZ,    PACK(-300),    /* UTC-5h */
  200.     "s",        TZ,    PACK(-360),    /* UTC-6h */
  201.     "t",        TZ,    PACK(-420),    /* UTC-7h */
  202.     "u",        TZ,    PACK(-480),    /* UTC-8h */
  203.     "v",        TZ,    PACK(-540),    /* UTC-9h */
  204.     "w",        TZ,    PACK(-600),    /* UTC-10h */
  205.     "x",        TZ,    PACK(-660),    /* UTC-11h */
  206.     "y",        TZ,    PACK(-720),    /* UTC-12h */
  207.     "z",        TZ,    PACK(0),    /* UTC */
  208. #endif
  209.  
  210. static unsigned szdateabstoks = sizeof dateabstoks / sizeof dateabstoks[0];
  211.  
  212. datetkn *
  213. datetoktype(s, bigvalp)
  214. char *s;
  215. int *bigvalp;
  216. {
  217.     register char *cp = s;
  218.     register char c = *cp;
  219.     static datetkn t;
  220.     register datetkn *tp = &t;
  221.  
  222.     if (isascii(c) && isdigit(c)) {
  223.         register int len = strlen(cp);
  224.  
  225.         if (len > 3 && (cp[1] == ':' || cp[2] == ':'))
  226.             tp->type = TIME;
  227.         else {
  228.             if (bigvalp != NULL)
  229.                 /* won't fit in tp->value */
  230.                 *bigvalp = atoi(cp);
  231.             if (len == 4)
  232.                 tp->type = YEAR;
  233.             else if (++dtok_numparsed == 1)
  234.                 tp->type = DAY;
  235.             else
  236.                 tp->type = YEAR;
  237.         }
  238.     } else if (c == '-' || c == '+') {
  239.         register int val = atoi(cp + 1);
  240.         register int hr =  val / 100;
  241.         register int min = val % 100;
  242.  
  243.         val = hr*60 + min;
  244.         if (c == '-')
  245.             val = -val;
  246.         tp->type = TZ;
  247.         TOVAL(tp, val);
  248.     } else {
  249.         char lowtoken[TOKMAXLEN+1];
  250.         register char *ltp = lowtoken, *endltp = lowtoken+TOKMAXLEN;
  251.  
  252.         /* copy to lowtoken to avoid modifying s */
  253.         while ((c = *cp++) != '\0' && ltp < endltp)
  254.             *ltp++ = (isascii(c) && isupper(c)? tolower(c): c);
  255.         *ltp = '\0';
  256.         tp = datebsearch(lowtoken, dateabstoks, szdateabstoks);
  257.         if (tp == NULL) {
  258.             tp = &t;
  259.             tp->type = IGNORE;
  260.         }
  261.     }
  262.     return tp;
  263. }
  264.  
  265. /*
  266.  * Binary search -- from Knuth (6.2.1) Algorithm B.  Special case like this
  267.  * is WAY faster than the generic bsearch().
  268.  */
  269. datetkn *
  270. datebsearch(key, base, nel)
  271. register char *key;
  272. register datetkn *base;
  273. unsigned int nel;
  274. {
  275.     register datetkn *last = base + nel - 1, *position;
  276.     register int result;
  277.  
  278.     while (last >= base) {
  279.         position = base + ((last - base) >> 1);
  280.         result = key[0] - position->token[0];
  281.         if (result == 0) {
  282.             result = strncmp(key, position->token, TOKMAXLEN);
  283.             if (result == 0)
  284.                 return position;
  285.         }
  286.         if (result < 0)
  287.             last = position - 1;
  288.         else
  289.             base = position + 1;
  290.     }
  291.     return 0;
  292. }
  293.