1 /* tdate_parse - parse string dates into internal form, stripped-down version 2 ** 3 ** Copyright � 1995 by Jef Poskanzer <jef@acme.com>. 4 ** All rights reserved. 5 ** 6 ** Redistribution and use in source and binary forms, with or without 7 ** modification, are permitted provided that the following conditions 8 ** are met: 9 ** 1. Redistributions of source code must retain the above copyright 10 ** notice, this list of conditions and the following disclaimer. 11 ** 2. Redistributions in binary form must reproduce the above copyright 12 ** notice, this list of conditions and the following disclaimer in the 13 ** documentation and/or other materials provided with the distribution. 14 ** 15 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 ** SUCH DAMAGE. 26 */ 27 28 /* This is a stripped-down version of date_parse.c, available at 29 ** http://www.acme.com/software/date_parse/ 30 */ 31 32 #include <ctype.h> 33 #ifdef HAVE_MEMORY_H 34 #include <memory.h> 35 #endif 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <time.h> 40 41 /*#include "tdate_parse.h" --Sampo */ 42 43 44 struct strlong { 45 char* s; 46 long l; 47 }; 48 49 50 static void 51 pound_case( char* str ) 52 { 53 for ( ; *str != '\0'; ++str ) 54 { 55 if ( isupper( (int) *str ) ) 56 *str = tolower( (int) *str ); 57 } 58 } 59 60 static int 61 strlong_compare( v1, v2 ) 62 char* v1; 63 char* v2; 64 { 65 return strcmp( ((struct strlong*) v1)->s, ((struct strlong*) v2)->s ); 66 } 67 68 69 static int 70 strlong_search( char* str, struct strlong* tab, int n, long* lP ) 71 { 72 int i, h, l, r; 73 74 l = 0; 75 h = n - 1; 76 for (;;) 77 { 78 i = ( h + l ) / 2; 79 r = strcmp( str, tab[i].s ); 80 if ( r < 0 ) 81 h = i - 1; 82 else if ( r > 0 ) 83 l = i + 1; 84 else 85 { 86 *lP = tab[i].l; 87 return 1; 88 } 89 if ( h < l ) 90 return 0; 91 } 92 } 93 94 95 static int 96 scan_wday( char* str_wday, long* tm_wdayP ) 97 { 98 static struct strlong wday_tab[] = { 99 { "sun", 0 }, { "sunday", 0 }, 100 { "mon", 1 }, { "monday", 1 }, 101 { "tue", 2 }, { "tuesday", 2 }, 102 { "wed", 3 }, { "wednesday", 3 }, 103 { "thu", 4 }, { "thursday", 4 }, 104 { "fri", 5 }, { "friday", 5 }, 105 { "sat", 6 }, { "saturday", 6 }, 106 }; 107 static int sorted = 0; 108 109 if ( ! sorted ) 110 { 111 (void) qsort( 112 wday_tab, sizeof(wday_tab)/sizeof(struct strlong), 113 sizeof(struct strlong), strlong_compare ); 114 sorted = 1; 115 } 116 pound_case( str_wday ); 117 return strlong_search( 118 str_wday, wday_tab, sizeof(wday_tab)/sizeof(struct strlong), tm_wdayP ); 119 } 120 121 122 static int 123 scan_mon( char* str_mon, long* tm_monP ) 124 { 125 static struct strlong mon_tab[] = { 126 { "jan", 0 }, { "january", 0 }, 127 { "feb", 1 }, { "february", 1 }, 128 { "mar", 2 }, { "march", 2 }, 129 { "apr", 3 }, { "april", 3 }, 130 { "may", 4 }, 131 { "jun", 5 }, { "june", 5 }, 132 { "jul", 6 }, { "july", 6 }, 133 { "aug", 7 }, { "august", 7 }, 134 { "sep", 8 }, { "september", 8 }, 135 { "oct", 9 }, { "october", 9 }, 136 { "nov", 10 }, { "november", 10 }, 137 { "dec", 11 }, { "december", 11 }, 138 }; 139 static int sorted = 0; 140 141 if ( ! sorted ) 142 { 143 (void) qsort( 144 mon_tab, sizeof(mon_tab)/sizeof(struct strlong), 145 sizeof(struct strlong), strlong_compare ); 146 sorted = 1; 147 } 148 pound_case( str_mon ); 149 return strlong_search( 150 str_mon, mon_tab, sizeof(mon_tab)/sizeof(struct strlong), tm_monP ); 151 } 152 153 154 static int 155 is_leap( int year ) 156 { 157 return year % 400? ( year % 100 ? ( year % 4 ? 0 : 1 ) : 0 ) : 1; 158 } 159 160 161 /* Basically the same as mktime(). */ 162 static time_t 163 tm_to_time( struct tm* tmP ) 164 { 165 time_t t; 166 static int monthtab[12] = { 167 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; 168 169 /* Years since epoch, converted to days. */ 170 t = ( tmP->tm_year - 70 ) * 365; 171 /* Leap days for previous years. */ 172 t += ( tmP->tm_year - 69 ) / 4; 173 /* Days for the beginning of this month. */ 174 t += monthtab[tmP->tm_mon]; 175 /* Leap day for this year. */ 176 if ( tmP->tm_mon >= 2 && is_leap( tmP->tm_year + 1900 ) ) 177 ++t; 178 /* Days since the beginning of this month. */ 179 t += tmP->tm_mday - 1; /* 1-based field */ 180 /* Hours, minutes, and seconds. */ 181 t = t * 24 + tmP->tm_hour; 182 t = t * 60 + tmP->tm_min; 183 t = t * 60 + tmP->tm_sec; 184 185 return t; 186 } 187 188 189 time_t 190 tdate_parse( char* str ) 191 { 192 struct tm tm; 193 char* cp; 194 char str_mon[500], str_wday[500]; 195 int tm_sec, tm_min, tm_hour, tm_mday, tm_year; 196 long tm_mon, tm_wday; 197 time_t t; 198 199 /* Initialize. */ 200 (void) memset( (char*) &tm, 0, sizeof(struct tm) ); 201 202 /* Skip initial whitespace ourselves - sscanf is clumsy at this. */ 203 for ( cp = str; *cp == ' ' || *cp == '\t'; ++cp ) 204 continue; 205 206 /* And do the sscanfs. WARNING: you can add more formats here, 207 ** but be careful! You can easily screw up the parsing of existing 208 ** formats when you add new ones. The order is important. 209 */ 210 211 /* DD-mth-YY HH:MM:SS GMT */ 212 if ( sscanf( cp, "%d-%400[a-zA-Z]-%d %d:%d:%d GMT", 213 &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, 214 &tm_sec ) == 6 && 215 scan_mon( str_mon, &tm_mon ) ) 216 { 217 tm.tm_mday = tm_mday; 218 tm.tm_mon = tm_mon; 219 tm.tm_year = tm_year; 220 tm.tm_hour = tm_hour; 221 tm.tm_min = tm_min; 222 tm.tm_sec = tm_sec; 223 } 224 225 /* DD mth YY HH:MM:SS GMT */ 226 else if ( sscanf( cp, "%d %400[a-zA-Z] %d %d:%d:%d GMT", 227 &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, 228 &tm_sec) == 6 && 229 scan_mon( str_mon, &tm_mon ) ) 230 { 231 tm.tm_mday = tm_mday; 232 tm.tm_mon = tm_mon; 233 tm.tm_year = tm_year; 234 tm.tm_hour = tm_hour; 235 tm.tm_min = tm_min; 236 tm.tm_sec = tm_sec; 237 } 238 239 /* HH:MM:SS GMT DD-mth-YY */ 240 else if ( sscanf( cp, "%d:%d:%d GMT %d-%400[a-zA-Z]-%d", 241 &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon, 242 &tm_year ) == 6 && 243 scan_mon( str_mon, &tm_mon ) ) 244 { 245 tm.tm_hour = tm_hour; 246 tm.tm_min = tm_min; 247 tm.tm_sec = tm_sec; 248 tm.tm_mday = tm_mday; 249 tm.tm_mon = tm_mon; 250 tm.tm_year = tm_year; 251 } 252 253 /* HH:MM:SS GMT DD mth YY */ 254 else if ( sscanf( cp, "%d:%d:%d GMT %d %400[a-zA-Z] %d", 255 &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon, 256 &tm_year ) == 6 && 257 scan_mon( str_mon, &tm_mon ) ) 258 { 259 tm.tm_hour = tm_hour; 260 tm.tm_min = tm_min; 261 tm.tm_sec = tm_sec; 262 tm.tm_mday = tm_mday; 263 tm.tm_mon = tm_mon; 264 tm.tm_year = tm_year; 265 } 266 267 /* wdy, DD-mth-YY HH:MM:SS GMT */ 268 else if ( sscanf( cp, "%400[a-zA-Z], %d-%400[a-zA-Z]-%d %d:%d:%d GMT", 269 str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, 270 &tm_sec ) == 7 && 271 scan_wday( str_wday, &tm_wday ) && 272 scan_mon( str_mon, &tm_mon ) ) 273 { 274 tm.tm_wday = tm_wday; 275 tm.tm_mday = tm_mday; 276 tm.tm_mon = tm_mon; 277 tm.tm_year = tm_year; 278 tm.tm_hour = tm_hour; 279 tm.tm_min = tm_min; 280 tm.tm_sec = tm_sec; 281 } 282 283 /* wdy, DD mth YY HH:MM:SS GMT */ 284 else if ( sscanf( cp, "%400[a-zA-Z], %d %400[a-zA-Z] %d %d:%d:%d GMT", 285 str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, 286 &tm_sec ) == 7 && 287 scan_wday( str_wday, &tm_wday ) && 288 scan_mon( str_mon, &tm_mon ) ) 289 { 290 tm.tm_wday = tm_wday; 291 tm.tm_mday = tm_mday; 292 tm.tm_mon = tm_mon; 293 tm.tm_year = tm_year; 294 tm.tm_hour = tm_hour; 295 tm.tm_min = tm_min; 296 tm.tm_sec = tm_sec; 297 } 298 299 /* wdy mth DD HH:MM:SS GMT YY */ 300 else if ( sscanf( cp, "%400[a-zA-Z] %400[a-zA-Z] %d %d:%d:%d GMT %d", 301 str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec, 302 &tm_year ) == 7 && 303 scan_wday( str_wday, &tm_wday ) && 304 scan_mon( str_mon, &tm_mon ) ) 305 { 306 tm.tm_wday = tm_wday; 307 tm.tm_mon = tm_mon; 308 tm.tm_mday = tm_mday; 309 tm.tm_hour = tm_hour; 310 tm.tm_min = tm_min; 311 tm.tm_sec = tm_sec; 312 tm.tm_year = tm_year; 313 } 314 else 315 return (time_t) -1; 316 317 if ( tm.tm_year > 1900 ) 318 tm.tm_year -= 1900; 319 else if ( tm.tm_year < 70 ) 320 tm.tm_year += 100; 321 322 t = tm_to_time( &tm ); 323 324 return t; 325 } 326