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