File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / thttpd / tdate_parse.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:21:13 2012 UTC (12 years, 3 months ago) by misho
Branches: thttpd, MAIN
CVS tags: v2_25b, HEAD
thttpd

    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>