diff -u at-3.1.8-orig/parsetime.l at-3.1.8/parsetime.l --- at-3.1.8-orig/parsetime.l Sun Sep 28 13:26:30 1997 +++ at-3.1.8/parsetime.l Sat Jan 26 14:18:10 2002 @@ -32,7 +32,6 @@ } while(0) %} -WORD [a-z][a-z0-9]+ %% now { COPY_TOK ; return NOW; } @@ -57,6 +56,7 @@ day(s)? { COPY_TOK ; return DAY; } week(s)? { COPY_TOK ; return WEEK; } month(s)? { COPY_TOK ; return MONTH; } +year(s)? { COPY_TOK ; return YEAR; } jan(uary)? { COPY_TOK ; return JAN; } feb(ruary)? { COPY_TOK ; return FEB; } mar(ch)? { COPY_TOK ; return MAR; } @@ -69,9 +69,16 @@ oct(ober)? { COPY_TOK ; return OCT; } nov(ember)? { COPY_TOK ; return NOV; } dec(ember)? { COPY_TOK ; return DEC; } +utc { COPY_TOK ; return UTC; } +[0-9]{1} { COPY_TOK ; COPY_VAL; return INT1DIGIT; } +[0-9]{2} { COPY_TOK ; COPY_VAL; return INT2DIGIT; } +[0-9]{4} { COPY_TOK ; COPY_VAL; return INT4DIGIT; } +[0-9]{5,8} { COPY_TOK ; COPY_VAL; return INT5_8DIGIT; } [0-9]+ { COPY_TOK ; COPY_VAL; return INT; } +[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{2}([0-9]{2})? { COPY_TOK ; COPY_VAL; return DOTTEDDATE; } +[0-9]{2}([0-9]{2})?-[0-9]{1,2}-[0-9]{1,2} { COPY_TOK ; COPY_VAL; return HYPHENDATE; } +[012]?[0-9][:'h,.][0-9]{2} { COPY_TOK ; COPY_VAL; return HOURMIN; } [ \t\n] ; -{WORD} { COPY_TOK ; COPY_VAL; return WORD; } . { COPY_TOK ; return yytext[0]; } %% diff -u at-3.1.8-orig/parsetime.y at-3.1.8/parsetime.y --- at-3.1.8-orig/parsetime.y Thu Jan 17 22:15:27 2002 +++ at-3.1.8/parsetime.y Sat Jan 26 14:25:25 2002 @@ -22,6 +22,13 @@ int intval; } +%token DOTTEDDATE +%token HYPHENDATE +%token HOURMIN +%token INT1DIGIT +%token INT2DIGIT +%token INT4DIGIT +%token INT5_8DIGIT %token INT %token NOW %token AM PM @@ -31,48 +38,61 @@ %token NEXT %token MINUTE HOUR DAY WEEK MONTH YEAR %token JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC -%token WORD +%token UTC -%type inc_period -%type inc_number +%type concatenated_date +%type hr24clock_hr_min +%type int1_2digit +%type int2_or_4digit +%type integer +%type inc_dec_period +%type inc_dec_number %type day_of_week %start timespec %% -timespec : date +timespec : spec_base + | spec_base inc_or_dec + { + time_only = 0; + + } + ; + +spec_base : date | time { time_only = 1; } | time date - | time_or_not inc_or_dec - | time_or_not date inc_or_dec - | nowspec - ; + | NOW + ; -nowspec : now - | now inc_or_dec +time : time_base + | time_base timezone_name ; -now : NOW - | TOMORROW - { - add_date(1, DAY); - } - ; - -time_or_not : time - | +time_base : hr24clock_hr_min + { + exectm.tm_min = -1; + exectm.tm_hour = -1; + sscanf($1, "%2d %2d", &exectm.tm_hour, + &exectm.tm_min); + free($1); -time : hr24clock_hr_min - | hr24clock_hr_min timezone_name - | hr24clock_hour time_sep minute - | hr24clock_hour time_sep minute timezone_name - | hr24clock_hour am_pm - | hr24clock_hour am_pm timezone_name - | hr24clock_hour time_sep minute am_pm - | hr24clock_hour time_sep minute am_pm timezone_name - | NOON + if (exectm.tm_min > 60 || exectm.tm_min < 0) { + yyerror("Problem in minutes specification"); + YYERROR; + } + if (exectm.tm_hour > 24 || exectm.tm_hour < 0) { + yyerror("Problem in hours specification"); + YYERROR; + } + } + | time_hour am_pm + | time_hour_min + | time_hour_min am_pm + | NOON { exectm.tm_hour = 12; exectm.tm_min = 0; @@ -81,128 +101,23 @@ { exectm.tm_hour = 0; exectm.tm_min = 0; - add_date(1, DAY); } | TEATIME { exectm.tm_hour = 16; exectm.tm_min = 0; } - ; - -date : month_name day_number - | month_name day_number year_number - | month_name day_number ',' year_number - | day_of_week - { - add_date ((6 + $1 - exectm.tm_wday) %7 + 1, DAY); - } - | TODAY - | TOMORROW - { - add_date(1, DAY); - } - | year_number '-' month_number '-' day_number - | day_number '.' month_number '.' year_number - | day_number '.' month_number - | day_number month_name - | day_number month_name year_number - | month_number '/' day_number '/' year_number - ; - -inc_or_dec : increment - | decrement - -increment : '+' inc_number inc_period - { - add_date($2, $3); - } - | NEXT inc_period - { - add_date(1, $2); - } - | NEXT day_of_week - { - add_date ((6 + $2 - exectm.tm_wday) %7 +1, DAY); - } - ; - -decrement : '-' inc_number inc_period - { - add_date(-$2, $3); - } ; -inc_period : MINUTE { $$ = MINUTE ; } - | HOUR { $$ = HOUR ; } - | DAY { $$ = DAY ; } - | WEEK { $$ = WEEK ; } - | MONTH { $$ = MONTH ; } - | YEAR { $$ = YEAR ; } - ; +hr24clock_hr_min: INT4DIGIT + ; -hr24clock_hr_min: INT +time_hour : int1_2digit { - if (strlen($1) == 4) { - exectm.tm_min = -1; - exectm.tm_hour = -1; - sscanf($1, "%2d %2d", &exectm.tm_hour, - &exectm.tm_min); - } else if (strlen($1) >= 5 && strlen($1) <= 8) { - /* Ok, this is a kluge. I hate design errors... -Joey */ - char shallot[5]; - char *onion; - - onion=$1; - memset (shallot, 0, sizeof (shallot)); - if (strlen($1) == 5 || strlen($1) == 7) { - strncpy (shallot,onion,1); - onion++; - } else { - strncpy (shallot,onion,2); - onion+=2; - } - sscanf(shallot, "%d", &exectm.tm_mon); - - if (exectm.tm_mon < 1 || exectm.tm_mon > 12) { - yyerror("Error in month number"); - YYERROR; - } - exectm.tm_mon--; - - memset (shallot, 0, sizeof (shallot)); - strncpy (shallot,onion,2); - sscanf(shallot, "%d", &exectm.tm_mday); - if (exectm.tm_mday < 0 || exectm.tm_mday > 31) - { - yyerror("Error in day of month"); - YYERROR; - } - - onion+=2; - memset (shallot, 0, sizeof (shallot)); - strncpy (shallot,onion,4); - if ( sscanf(shallot, "%d", &exectm.tm_year) != 1) { - yyerror("Error in year"); - YYERROR; - } - if (exectm.tm_year < 70) { - exectm.tm_year += 100; - } - else if (exectm.tm_year > 1900) { - exectm.tm_year -= 1900; - } - } - else { - sscanf($1, "%d", &exectm.tm_hour); - exectm.tm_min = 0; - } + sscanf($1, "%d", &exectm.tm_hour); + exectm.tm_min = 0; free($1); - if (exectm.tm_min > 60 || exectm.tm_min < 0) { - yyerror("Problem in minutes specification"); - YYERROR; - } if (exectm.tm_hour > 24 || exectm.tm_hour < 0) { yyerror("Problem in hours specification"); YYERROR; @@ -210,29 +125,22 @@ } ; -timezone_name : WORD +time_hour_min : HOURMIN { - if (strcasecmp($1,"utc") == 0) { - isgmt = 1; - } - else { - yyerror("Only UTC timezone is supported"); - YYERROR; - } + exectm.tm_min = -1; + exectm.tm_hour = -1; + sscanf($1, "%d %*c %d", &exectm.tm_hour, + &exectm.tm_min); free($1); - } - ; - -hr24clock_hour : hr24clock_hr_min - ; -minute : INT - { - if (sscanf($1, "%d", &exectm.tm_min) != 1) { - yyerror("Error in minute"); + if (exectm.tm_min > 60 || exectm.tm_min < 0) { + yyerror("Problem in minutes specification"); + YYERROR; + } + if (exectm.tm_hour > 24 || exectm.tm_hour < 0) { + yyerror("Problem in hours specification"); YYERROR; } - free($1); } ; @@ -258,6 +166,171 @@ } ; +timezone_name : UTC + { + isgmt = 1; + } + ; + +date : month_name day_number + | month_name day_number year_number + | month_name day_number ',' year_number + | day_of_week + { + add_date ((6 + $1 - exectm.tm_wday) %7 + 1, DAY); + } + | TODAY + | TOMORROW + { + add_date(1, DAY); + } + | HYPHENDATE + { + int ynum = -1; + int mnum = -1; + int dnum = -1; + + if (sscanf($1, "%d %*c %d %*c %d", &ynum, &mnum, &dnum) != 3) { + yyerror("Error in hypenated date"); + YYERROR; + } + + if (mnum < 1 || mnum > 12) { + yyerror("Error in month number"); + YYERROR; + } + exectm.tm_mon = mnum -1; + + if (ynum < 70) { + ynum += 100; + } + else if (ynum > 1900) { + ynum -= 1900; + } + exectm.tm_year = ynum ; + + if ( dnum < 0 + || ((mnum == 1 || mnum == 3 || mnum == 5 || + mnum == 7 || mnum == 8 || mnum == 10 || + mnum == 12) && dnum > 31) + || ((mnum == 4 || mnum == 6 || mnum == 9 || + mnum == 11) && dnum > 30) + || (mnum == 2 && dnum > 29 && __isleap(ynum+1900)) + || (mnum == 2 && dnum > 28 && !__isleap(ynum+1900)) + ) + { + yyerror("Error in day of month"); + YYERROR; + } + exectm.tm_mday = dnum; + + free($1); + } + | DOTTEDDATE + { + int ynum = -1; + int mnum = -1; + int dnum = -1; + + if (sscanf($1, "%d %*c %d %*c %d", &dnum, &mnum, &ynum) != 3) { + yyerror("Error in dotted date"); + YYERROR; + } + + if (mnum < 1 || mnum > 12) { + yyerror("Error in month number"); + YYERROR; + } + exectm.tm_mon = mnum -1; + + if (ynum < 70) { + ynum += 100; + } + else if (ynum > 1900) { + ynum -= 1900; + } + exectm.tm_year = ynum ; + + if ( dnum < 0 + || ((mnum == 1 || mnum == 3 || mnum == 5 || + mnum == 7 || mnum == 8 || mnum == 10 || + mnum == 12) && dnum > 31) + || ((mnum == 4 || mnum == 6 || mnum == 9 || + mnum == 11) && dnum > 30) + || (mnum == 2 && dnum > 29 && __isleap(ynum+1900)) + || (mnum == 2 && dnum > 28 && !__isleap(ynum+1900)) + ) + { + yyerror("Error in day of month"); + YYERROR; + } + exectm.tm_mday = dnum; + + free($1); + } + | day_number month_name + | day_number month_name year_number + | month_number '/' day_number '/' year_number + | concatenated_date + { + /* Ok, this is a kluge. I hate design errors... -Joey */ + char shallot[5]; + char *onion; + + onion=$1; + memset (shallot, 0, sizeof (shallot)); + if (strlen($1) == 5 || strlen($1) == 7) { + strncpy (shallot,onion,1); + onion++; + } else { + strncpy (shallot,onion,2); + onion+=2; + } + sscanf(shallot, "%d", &exectm.tm_mon); + + if (exectm.tm_mon < 1 || exectm.tm_mon > 12) { + yyerror("Error in month number"); + YYERROR; + } + exectm.tm_mon--; + + memset (shallot, 0, sizeof (shallot)); + strncpy (shallot,onion,2); + sscanf(shallot, "%d", &exectm.tm_mday); + if (exectm.tm_mday < 0 || exectm.tm_mday > 31) + { + yyerror("Error in day of month"); + YYERROR; + } + + onion+=2; + memset (shallot, 0, sizeof (shallot)); + strncpy (shallot,onion,4); + if ( sscanf(shallot, "%d", &exectm.tm_year) != 1) { + yyerror("Error in year"); + YYERROR; + } + if (exectm.tm_year < 70) { + exectm.tm_year += 100; + } + else if (exectm.tm_year > 1900) { + exectm.tm_year -= 1900; + } + + free ($1); + } + | NEXT inc_dec_period + { + add_date(1, $2); + } + | NEXT day_of_week + { + add_date ((6 + $2 - exectm.tm_wday) %7 +1, DAY); + } + ; + +concatenated_date: INT5_8DIGIT + ; month_name : JAN { exectm.tm_mon = 0; } | FEB { exectm.tm_mon = 1; } @@ -273,7 +346,7 @@ | DEC { exectm.tm_mon =11; } ; -month_number : INT +month_number : int1_2digit { { int mnum = -1; @@ -287,7 +360,9 @@ free($1); } } -day_number : INT + ; + +day_number : int1_2digit { exectm.tm_mday = -1; sscanf($1, "%d", &exectm.tm_mday); @@ -300,7 +375,7 @@ } ; -year_number : INT +year_number : int2_or_4digit { { int ynum; @@ -322,7 +397,6 @@ } ; - day_of_week : SUN { $$ = 0; } | MON { $$ = 1; } | TUE { $$ = 2; } @@ -332,7 +406,23 @@ | SAT { $$ = 6; } ; -inc_number : INT +inc_or_dec : increment + | decrement + ; + +increment : '+' inc_dec_number inc_dec_period + { + add_date($2, $3); + } + ; + +decrement : '-' inc_dec_number inc_dec_period + { + add_date(-$2, $3); + } + ; + +inc_dec_number : integer { if (sscanf($1, "%d", &$$) != 1) { yyerror("Unknown increment"); @@ -342,11 +432,27 @@ } ; -time_sep : ':' - | '\'' - | '.' - | 'h' - | ',' +inc_dec_period : MINUTE { $$ = MINUTE ; } + | HOUR { $$ = HOUR ; } + | DAY { $$ = DAY ; } + | WEEK { $$ = WEEK ; } + | MONTH { $$ = MONTH ; } + | YEAR { $$ = YEAR ; } + ; + +int1_2digit : INT1DIGIT + | INT2DIGIT + ; + +int2_or_4digit : INT2DIGIT + | INT4DIGIT + ; + +integer : INT + | INT1DIGIT + | INT2DIGIT + | INT4DIGIT + | INT5_8DIGIT ; %% @@ -370,10 +476,7 @@ if (exectime == (time_t)-1) return 0; if (isgmt) { - exectime += timezone; - if (daylight) { - exectime -= 3600; - } + exectime -= timezone; } if (time_only && (currtime > exectime)) { exectime += 24*3600; @@ -386,39 +489,29 @@ } #ifdef TEST_PARSER -/* - -Here are some lines to test: - -./parsetest 7AM Mar 24 2000 -./parsetest 7AM Mar 24 00 -./parsetest 7AM 032400 -./parsetest 7AM 03/24/00 -./parsetest 7AM 24.03.00 -./parsetest 7AM Mar 24 - -./parsetest 03242000 -./parsetest noon 03242000 -./parsetest 5:30 -./parsetest 4pm + 3 days -./parsetest 10am Jul 31 - - */ + int main(int argc, char **argv) { + int retval = 1; time_t res; res = parsetime(argc-1, &argv[1]); + if (time_only) { + fprintf(stderr, "time_only = 1\n"); + } if (res > 0) { printf("%s",ctime(&res)); + retval = 0; } else { printf("Ooops...\n"); + retval = 1; } - return 0; + return retval; } #endif + int yyerror(char *s) { if (last_token == NULL) @@ -430,12 +523,36 @@ void add_seconds(struct tm *tm, long numsec) { + struct tm basetm = *tm; time_t timeval; + timeval = mktime(tm); if (timeval == (time_t)-1) timeval = (time_t)0; timeval += numsec; *tm = *localtime(&timeval); + + /* + * Adjust +-1 hour when moving in or out of DST + */ + + if (daylight > 0) /* Only check if DST is used here */ + { + /* Set tm_isdst on &basetm and tm */ + (void) mktime(&basetm); + (void) mktime(tm); + + if (basetm.tm_isdst > 0 && tm->tm_isdst < 1) + { /* DST to no DST */ + timeval += 3600l; + *tm = *localtime(&timeval); + } + else if (basetm.tm_isdst < 1 && tm->tm_isdst > 0) + { /* no DST to DST */ + timeval -= 3600l; + *tm = *localtime(&timeval); + } + } } int @@ -468,6 +585,10 @@ } exectm.tm_mon = newmonth % 12; number += newmonth / 12 ; + + /* Recalculate tm_isdst so we don't get a +-1 hour creep */ + exectm.tm_isdst = -1; + (void) mktime(&exectm); } if (number == 0) { break; @@ -476,6 +597,9 @@ case YEAR: exectm.tm_year += number; + /* Recalculate tm_isdst so we don't get a +-1 hour creep */ + exectm.tm_isdst = -1; + (void) mktime(&exectm); break; default: @@ -483,5 +607,6 @@ fprintf(stderr,"Unexpected case %d\n", period); abort(); } + return 0; } diff -u at-3.1.8-orig/timespec at-3.1.8/timespec --- at-3.1.8-orig/timespec Wed Mar 12 12:11:05 1997 +++ at-3.1.8/timespec Sat Jan 26 14:18:10 2002 @@ -2,6 +2,13 @@ * Abbreviated version of the yacc grammar used by at(1). */ +%token DOTTEDDATE +%token HYPHENDATE +%token HOURMIN +%token INT1DIGIT +%token INT2DIGIT +%token INT4DIGIT +%token INT5_8DIGIT %token INT %token NOW %token AM PM @@ -11,100 +18,115 @@ %token NEXT %token MINUTE HOUR DAY WEEK MONTH YEAR %token JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC -%token WORD +%token UTC -%type inc_period -%type inc_number +%type concatenated_date +%type hr24clock_hr_min +%type int1_2digit +%type int2_or_4digit +%type integer +%type inc_dec_period +%type inc_dec_number %type day_of_week %start timespec %% -timespec : time - | time date - | time increment - | time date increment - | time decrement - | time date decrement - | nowspec - ; - -nowspec : now - | now increment - | now decrement +timespec : spec_base + | spec_base inc_or_dec ; -now : NOW +spec_base : date + | time + | time date + | NOW ; -time : hr24clock_hr_min - | hr24clock_hr_min timezone_name - | hr24clock_hour time_sep minute - | hr24clock_hour time_sep minute timezone_name - | hr24clock_hour am_pm - | hr24clock_hour am_pm timezone_name - | hr24clock_hour time_sep minute am_pm - | hr24clock_hour time_sep minute am_pm timezone_name - | NOON +time : time_base + | time_base timezone_name + ; + +time_base : hr24clock_hr_min + | time_hour am_pm + | time_hour_min + | time_hour_min am_pm + | NOON | MIDNIGHT | TEATIME - ; + ; + +hr24clock_hr_min: INT4DIGIT + ; + +time_hour : int1_2digit + ; + +time_hour_min : HOURMIN + ; + +am_pm : AM + | PM + ; + +timezone_name : UTC + ; date : month_name day_number + | month_name day_number year_number | month_name day_number ',' year_number | day_of_week | TODAY | TOMORROW - | year_number '-' month_number '-' day_number - | day_number '.' month_number '.' year_number - | day_number '.' month_number + | HYPHENDATE + | DOTTEDDATE | day_number month_name | day_number month_name year_number | month_number '/' day_number '/' year_number - ; - -increment : '+' inc_number inc_period - | NEXT inc_period + | concatenated_date + | NEXT inc_dec_period | NEXT day_of_week ; -decrement : '-' inc_number inc_period +concatenated_date: INT5_8DIGIT ; -inc_period : MINUTE | HOUR | DAY | WEEK | MONTH | YEAR +month_name : JAN | FEB | MAR | APR | MAY | JUN + | JUL | AUG | SEP | OCT | NOV | DEC ; -hr24clock_hr_min: INT +month_number : int1_2digit ; -timezone_name : WORD +day_number : int1_2digit ; -hr24clock_hour : hr24clock_hr_min +year_number : int2_or_4digit ; -minute : INT +day_of_week : SUN | MON | TUE | WED | THU | FRI | SAT ; -am_pm : AM | PM +inc_or_dec : increment | decrement ; -month_name : JAN | FEB | MAR | APR | MAY | JUN | JUL - | AUG | SEP | OCT | NOV | DEC - ; +increment : '+' inc_dec_number inc_dec_period + ; -month_number : INT +decrement : '-' inc_dec_number inc_dec_period ; -day_number : INT + +inc_dec_number : integer ; -year_number : INT +inc_dec_period : MINUTE | HOUR | DAY | WEEK | MONTH | YEAR ; -day_of_week : SUN | MON | TUE | WED | THU | FRI | SAT +int1_2digit : INT1DIGIT | INT2DIGIT ; -inc_number : INT +int2_or_4digit : INT2DIGIT | INT4DIGIT ; -time_sep : ':' | '\'' | '.' | 'h' | ',' +integer : INT | INT1DIGIT | INT2DIGIT | INT4DIGIT | INT5_8DIGIT ; + +%%