Annotation of embedaddon/thttpd/tdate_parse.c, revision 1.1.1.1

1.1       misho       1: /* tdate_parse - parse string dates into internal form, stripped-down version
                      2: **
                      3: ** Copyright © 1995 by Jef Poskanzer <jef@mail.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 <sys/types.h>
                     33: 
                     34: #include <ctype.h>
                     35: #ifdef HAVE_MEMORY_H
                     36: #include <memory.h>
                     37: #endif
                     38: #include <stdio.h>
                     39: #include <stdlib.h>
                     40: #include <string.h>
                     41: #include <time.h>
                     42: 
                     43: #include "tdate_parse.h"
                     44: 
                     45: 
                     46: struct strlong {
                     47:     char* s;
                     48:     long l;
                     49:     };
                     50: 
                     51: 
                     52: static void
                     53: pound_case( char* str )
                     54:     {
                     55:     for ( ; *str != '\0'; ++str )
                     56:        {
                     57:        if ( isupper( (int) *str ) )
                     58:            *str = tolower( (int) *str );
                     59:        }
                     60:     }
                     61: 
                     62: static int
                     63: strlong_compare( v1, v2 )
                     64:     char* v1;
                     65:     char* v2;
                     66:     {
                     67:     return strcmp( ((struct strlong*) v1)->s, ((struct strlong*) v2)->s );
                     68:     }
                     69: 
                     70: 
                     71: static int
                     72: strlong_search( char* str, struct strlong* tab, int n, long* lP )
                     73:     {
                     74:     int i, h, l, r;
                     75: 
                     76:     l = 0;
                     77:     h = n - 1;
                     78:     for (;;)
                     79:        {
                     80:        i = ( h + l ) / 2;
                     81:        r = strcmp( str, tab[i].s );
                     82:        if ( r < 0 )
                     83:            h = i - 1;
                     84:        else if ( r > 0 )
                     85:            l = i + 1;
                     86:        else
                     87:            {
                     88:            *lP = tab[i].l;
                     89:            return 1;
                     90:            }
                     91:        if ( h < l )
                     92:            return 0;
                     93:        }
                     94:     }
                     95: 
                     96: 
                     97: static int
                     98: scan_wday( char* str_wday, long* tm_wdayP )
                     99:     {
                    100:     static struct strlong wday_tab[] = {
                    101:        { "sun", 0 }, { "sunday", 0 },
                    102:        { "mon", 1 }, { "monday", 1 },
                    103:        { "tue", 2 }, { "tuesday", 2 },
                    104:        { "wed", 3 }, { "wednesday", 3 },
                    105:        { "thu", 4 }, { "thursday", 4 },
                    106:        { "fri", 5 }, { "friday", 5 },
                    107:        { "sat", 6 }, { "saturday", 6 },
                    108:        };
                    109:     static int sorted = 0;
                    110: 
                    111:     if ( ! sorted )
                    112:        {
                    113:        (void) qsort(
                    114:            wday_tab, sizeof(wday_tab)/sizeof(struct strlong),
                    115:            sizeof(struct strlong), strlong_compare );
                    116:        sorted = 1;
                    117:        }
                    118:     pound_case( str_wday );
                    119:     return strlong_search(
                    120:        str_wday, wday_tab, sizeof(wday_tab)/sizeof(struct strlong), tm_wdayP );
                    121:     }
                    122: 
                    123: 
                    124: static int
                    125: scan_mon( char* str_mon, long* tm_monP )
                    126:     {
                    127:     static struct strlong mon_tab[] = {
                    128:        { "jan", 0 }, { "january", 0 },
                    129:        { "feb", 1 }, { "february", 1 },
                    130:        { "mar", 2 }, { "march", 2 },
                    131:        { "apr", 3 }, { "april", 3 },
                    132:        { "may", 4 },
                    133:        { "jun", 5 }, { "june", 5 },
                    134:        { "jul", 6 }, { "july", 6 },
                    135:        { "aug", 7 }, { "august", 7 },
                    136:        { "sep", 8 }, { "september", 8 },
                    137:        { "oct", 9 }, { "october", 9 },
                    138:        { "nov", 10 }, { "november", 10 },
                    139:        { "dec", 11 }, { "december", 11 },
                    140:        };
                    141:     static int sorted = 0;
                    142: 
                    143:     if ( ! sorted )
                    144:        {
                    145:        (void) qsort(
                    146:            mon_tab, sizeof(mon_tab)/sizeof(struct strlong),
                    147:            sizeof(struct strlong), strlong_compare );
                    148:        sorted = 1;
                    149:        }
                    150:     pound_case( str_mon );
                    151:     return strlong_search(
                    152:        str_mon, mon_tab, sizeof(mon_tab)/sizeof(struct strlong), tm_monP );
                    153:     }
                    154: 
                    155: 
                    156: static int
                    157: is_leap( int year )
                    158:     {
                    159:     return year % 400? ( year % 100 ? ( year % 4 ? 0 : 1 ) : 0 ) : 1;
                    160:     }
                    161: 
                    162: 
                    163: /* Basically the same as mktime(). */
                    164: static time_t
                    165: tm_to_time( struct tm* tmP )
                    166:     {
                    167:     time_t t;
                    168:     static int monthtab[12] = {
                    169:        0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
                    170: 
                    171:     /* Years since epoch, converted to days. */
                    172:     t = ( tmP->tm_year - 70 ) * 365;
                    173:     /* Leap days for previous years. */
                    174:     t += ( tmP->tm_year - 69 ) / 4;
                    175:     /* Days for the beginning of this month. */
                    176:     t += monthtab[tmP->tm_mon];
                    177:     /* Leap day for this year. */
                    178:     if ( tmP->tm_mon >= 2 && is_leap( tmP->tm_year + 1900 ) )
                    179:        ++t;
                    180:     /* Days since the beginning of this month. */
                    181:     t += tmP->tm_mday - 1;     /* 1-based field */
                    182:     /* Hours, minutes, and seconds. */
                    183:     t = t * 24 + tmP->tm_hour;
                    184:     t = t * 60 + tmP->tm_min;
                    185:     t = t * 60 + tmP->tm_sec;
                    186: 
                    187:     return t;
                    188:     }
                    189: 
                    190: 
                    191: time_t
                    192: tdate_parse( char* str )
                    193:     {
                    194:     struct tm tm;
                    195:     char* cp;
                    196:     char str_mon[500], str_wday[500];
                    197:     int tm_sec, tm_min, tm_hour, tm_mday, tm_year;
                    198:     long tm_mon, tm_wday;
                    199:     time_t t;
                    200: 
                    201:     /* Initialize. */
                    202:     (void) memset( (char*) &tm, 0, sizeof(struct tm) );
                    203: 
                    204:     /* Skip initial whitespace ourselves - sscanf is clumsy at this. */
                    205:     for ( cp = str; *cp == ' ' || *cp == '\t'; ++cp )
                    206:        continue;
                    207: 
                    208:     /* And do the sscanfs.  WARNING: you can add more formats here,
                    209:     ** but be careful!  You can easily screw up the parsing of existing
                    210:     ** formats when you add new ones.  The order is important.
                    211:     */
                    212: 
                    213:     /* DD-mth-YY HH:MM:SS GMT */
                    214:     if ( sscanf( cp, "%d-%400[a-zA-Z]-%d %d:%d:%d GMT",
                    215:                &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
                    216:                &tm_sec ) == 6 &&
                    217:            scan_mon( str_mon, &tm_mon ) )
                    218:        {
                    219:        tm.tm_mday = tm_mday;
                    220:        tm.tm_mon = tm_mon;
                    221:        tm.tm_year = tm_year;
                    222:        tm.tm_hour = tm_hour;
                    223:        tm.tm_min = tm_min;
                    224:        tm.tm_sec = tm_sec;
                    225:        }
                    226: 
                    227:     /* DD mth YY HH:MM:SS GMT */
                    228:     else if ( sscanf( cp, "%d %400[a-zA-Z] %d %d:%d:%d GMT",
                    229:                &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
                    230:                &tm_sec) == 6 &&
                    231:            scan_mon( str_mon, &tm_mon ) )
                    232:        {
                    233:        tm.tm_mday = tm_mday;
                    234:        tm.tm_mon = tm_mon;
                    235:        tm.tm_year = tm_year;
                    236:        tm.tm_hour = tm_hour;
                    237:        tm.tm_min = tm_min;
                    238:        tm.tm_sec = tm_sec;
                    239:        }
                    240: 
                    241:     /* HH:MM:SS GMT DD-mth-YY */
                    242:     else if ( sscanf( cp, "%d:%d:%d GMT %d-%400[a-zA-Z]-%d",
                    243:                &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
                    244:                &tm_year ) == 6 &&
                    245:            scan_mon( str_mon, &tm_mon ) )
                    246:        {
                    247:        tm.tm_hour = tm_hour;
                    248:        tm.tm_min = tm_min;
                    249:        tm.tm_sec = tm_sec;
                    250:        tm.tm_mday = tm_mday;
                    251:        tm.tm_mon = tm_mon;
                    252:        tm.tm_year = tm_year;
                    253:        }
                    254: 
                    255:     /* HH:MM:SS GMT DD mth YY */
                    256:     else if ( sscanf( cp, "%d:%d:%d GMT %d %400[a-zA-Z] %d",
                    257:                &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
                    258:                &tm_year ) == 6 &&
                    259:            scan_mon( str_mon, &tm_mon ) )
                    260:        {
                    261:        tm.tm_hour = tm_hour;
                    262:        tm.tm_min = tm_min;
                    263:        tm.tm_sec = tm_sec;
                    264:        tm.tm_mday = tm_mday;
                    265:        tm.tm_mon = tm_mon;
                    266:        tm.tm_year = tm_year;
                    267:        }
                    268: 
                    269:     /* wdy, DD-mth-YY HH:MM:SS GMT */
                    270:     else if ( sscanf( cp, "%400[a-zA-Z], %d-%400[a-zA-Z]-%d %d:%d:%d GMT",
                    271:                str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
                    272:                &tm_sec ) == 7 &&
                    273:            scan_wday( str_wday, &tm_wday ) &&
                    274:            scan_mon( str_mon, &tm_mon ) )
                    275:        {
                    276:        tm.tm_wday = tm_wday;
                    277:        tm.tm_mday = tm_mday;
                    278:        tm.tm_mon = tm_mon;
                    279:        tm.tm_year = tm_year;
                    280:        tm.tm_hour = tm_hour;
                    281:        tm.tm_min = tm_min;
                    282:        tm.tm_sec = tm_sec;
                    283:        }
                    284: 
                    285:     /* wdy, DD mth YY HH:MM:SS GMT */
                    286:     else if ( sscanf( cp, "%400[a-zA-Z], %d %400[a-zA-Z] %d %d:%d:%d GMT",
                    287:                str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
                    288:                &tm_sec ) == 7 &&
                    289:            scan_wday( str_wday, &tm_wday ) &&
                    290:            scan_mon( str_mon, &tm_mon ) )
                    291:        {
                    292:        tm.tm_wday = tm_wday;
                    293:        tm.tm_mday = tm_mday;
                    294:        tm.tm_mon = tm_mon;
                    295:        tm.tm_year = tm_year;
                    296:        tm.tm_hour = tm_hour;
                    297:        tm.tm_min = tm_min;
                    298:        tm.tm_sec = tm_sec;
                    299:        }
                    300: 
                    301:     /* wdy mth DD HH:MM:SS GMT YY */
                    302:     else if ( sscanf( cp, "%400[a-zA-Z] %400[a-zA-Z] %d %d:%d:%d GMT %d",
                    303:                str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec,
                    304:                &tm_year ) == 7 &&
                    305:            scan_wday( str_wday, &tm_wday ) &&
                    306:            scan_mon( str_mon, &tm_mon ) )
                    307:        {
                    308:        tm.tm_wday = tm_wday;
                    309:        tm.tm_mon = tm_mon;
                    310:        tm.tm_mday = tm_mday;
                    311:        tm.tm_hour = tm_hour;
                    312:        tm.tm_min = tm_min;
                    313:        tm.tm_sec = tm_sec;
                    314:        tm.tm_year = tm_year;
                    315:        }
                    316:     else
                    317:        return (time_t) -1;
                    318: 
                    319:     if ( tm.tm_year > 1900 )
                    320:        tm.tm_year -= 1900;
                    321:     else if ( tm.tm_year < 70 )
                    322:        tm.tm_year += 100;
                    323: 
                    324:     t = tm_to_time( &tm );
                    325: 
                    326:     return t;
                    327:     }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>