date.con commit [PATCH] Do date parsing by hand... (ecee9d9)
   1/*
   2 * GIT - The information manager from hell
   3 *
   4 * Copyright (C) Linus Torvalds, 2005
   5 */
   6
   7#include <stdio.h>
   8#include <stdlib.h>
   9#include <string.h>
  10#include <ctype.h>
  11#include <time.h>
  12
  13static time_t my_mktime(struct tm *tm)
  14{
  15        static const int mdays[] = {
  16            0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
  17        };
  18        int year = tm->tm_year - 70;
  19        int month = tm->tm_mon;
  20        int day = tm->tm_mday;
  21
  22        if (year < 0 || year > 129) /* algo only works for 1970-2099 */
  23                return -1;
  24        if (month < 0 || month > 11) /* array bounds */
  25                return -1;
  26        if (month < 2 || (year + 2) % 4)
  27                day--;
  28        return (year * 365 + (year + 1) / 4 + mdays[month] + day) * 24*60*60UL +
  29                tm->tm_hour * 60*60 + tm->tm_min * 60 + tm->tm_sec;
  30}
  31
  32static const char *month_names[] = {
  33        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  34        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  35};
  36
  37static const char *weekday_names[] = {
  38        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  39};
  40
  41
  42static char *skipfws(char *str)
  43{
  44        while (isspace(*str))
  45                str++;
  46        return str;
  47}
  48
  49        
  50/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
  51   (i.e. English) day/month names, and it doesn't work correctly with %z. */
  52void parse_date(char *date, char *result, int maxlen)
  53{
  54        struct tm tm;
  55        char *p, *tz;
  56        int i, offset;
  57        time_t then;
  58
  59        memset(&tm, 0, sizeof(tm));
  60
  61        /* Skip day-name */
  62        p = skipfws(date);
  63        if (!isdigit(*p)) {
  64                for (i=0; i<7; i++) {
  65                        if (!strncmp(p,weekday_names[i],3) && p[3] == ',') {
  66                                p = skipfws(p+4);
  67                                goto day;
  68                        }
  69                }
  70                return;
  71        }                                       
  72
  73        /* day */
  74 day:
  75        tm.tm_mday = strtoul(p, &p, 10);
  76
  77        if (tm.tm_mday < 1 || tm.tm_mday > 31)
  78                return;
  79
  80        if (!isspace(*p))
  81                return;
  82
  83        p = skipfws(p);
  84
  85        /* month */
  86
  87        for (i=0; i<12; i++) {
  88                if (!strncmp(p, month_names[i], 3) && isspace(p[3])) {
  89                        tm.tm_mon = i;
  90                        p = skipfws(p+strlen(month_names[i]));
  91                        goto year;
  92                }
  93        }
  94        return; /* Error -- bad month */
  95
  96        /* year */
  97 year:  
  98        tm.tm_year = strtoul(p, &p, 10);
  99
 100        if (!tm.tm_year && !isspace(*p))
 101                return;
 102
 103        if (tm.tm_year > 1900)
 104                tm.tm_year -= 1900;
 105                
 106        p=skipfws(p);
 107
 108        /* hour */
 109        if (!isdigit(*p))
 110                return;
 111        tm.tm_hour = strtoul(p, &p, 10);
 112        
 113        if (tm.tm_hour > 23)
 114                return;
 115
 116        if (*p != ':')
 117                return; /* Error -- bad time */
 118        p++;
 119
 120        /* minute */
 121        if (!isdigit(*p))
 122                return;
 123        tm.tm_min = strtoul(p, &p, 10);
 124        
 125        if (tm.tm_min > 59)
 126                return;
 127
 128        if (*p != ':')
 129                goto zone;
 130        p++;
 131
 132        /* second */
 133        if (!isdigit(*p))
 134                return;
 135        tm.tm_sec = strtoul(p, &p, 10);
 136        
 137        if (tm.tm_sec > 60)
 138                return;
 139
 140 zone:
 141        if (!isspace(*p))
 142                return;
 143
 144        p = skipfws(p);
 145
 146        if (*p == '-')
 147                offset = -60;
 148        else if (*p == '+')
 149                offset = 60;
 150        else
 151               return;
 152
 153        if (!isdigit(p[1]) || !isdigit(p[2]) || !isdigit(p[3]) || !isdigit(p[4]))
 154                return;
 155
 156        tz = p;
 157        i = strtoul(p+1, NULL, 10);
 158        offset *= ((i % 100) + ((i / 100) * 60));
 159
 160        p = skipfws(p + 5);
 161        if (*p && *p != '(') /* trailing comment like (EDT) is ok */
 162                return;
 163
 164        then = my_mktime(&tm); /* mktime uses local timezone */
 165        if (then == -1)
 166                return;
 167
 168        then -= offset;
 169
 170        snprintf(result, maxlen, "%lu %5.5s", then, tz);
 171}
 172
 173void datestamp(char *buf, int bufsize)
 174{
 175        time_t now;
 176        int offset;
 177
 178        time(&now);
 179
 180        offset = my_mktime(localtime(&now)) - now;
 181        offset /= 60;
 182
 183        snprintf(buf, bufsize, "%lu %+05d", now, offset/60*100 + offset%60);
 184}