Listing 4 xgetdst.c

/* _Getdst function */
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "xtime.h"

static int getint(const char *s, int n)
       {       /* accumulate digits */
       int value;

       for (value = 0; 0 <= --n && isdigit(*s); ++s)
              value = value * 10 + *s - '0';
       return (0 <= n ? -1 : value);
       }

Dstrule *_Getdst(const char *s)
       {       /* parse DST rules */
       const char delim = *s++;
       Dstrule *pr, *rules;

       if (delim == '\0')
              return (NULL);
       {       /* buy space for rules */
       const char *s1, *s2;
       int i;

       for (s1 = s, i = 2; (s2 = strchr(s1, delim)) != NULL; ++i)
              s1 = s2 + 1;
       if ((rules = (Dstrule *)malloc(sizeof (Dstrule) * i)) == NULL)
              return (NULL);
        }
        {      /* parse rules */
       int year = 0;

       for (pr = rules; ; ++pr, ++s)
              {       /* parse next rule */
              if (*s == '(')
                     {      /* got a year qualifier */
                     year = getint(s + 1, 4) - 1900;
                     if (year < 0 || s[5] != ')')
                           break;   /* invalid year */
                     s += 6;
                     }
              pr->year = year;
              pr->mon = getint(s, 2) - 1; s += 2;
              pr->day = getint(s, 2) - 1; s += 2;
              if (isdigit(*s))
                     { pr->hour = getint(s, 2); s += 2; }
              else
                     pr->hour = 0;
              if (12 <= pr->mon || 99 < pr->day || 99 < pr->hour)
                     break; /* invalid month, day, or hour */
              if (*s != '+' && *s != '-')
                     pr->wday = 0;
              else if (s[1] < '0' || '6' < s[1])
                     break; /* invalid week day */
              else
                     {      /* compute week day field */
                     pr->wday = s[1] == '0' ? 7 : s[1] - '0';
                     if (*s == '+') /* '-': strictly before */
                            pr->wday += 7; /* '+': on or after */
                     s += 2;
                     }
              if (*s == '\0')
                     {       /* done, terminate list */
                     (pr + 1)->wday = (unsigned char)-1;
                     (pr + 1)->year = year;
                     return (rules);
                     }
              else if (*s != delim)
                     break;
              }
       free(rules);
       return (NULL);
        }
       }
/* End of File */