1*4887Schin /*********************************************************************** 2*4887Schin * * 3*4887Schin * This software is part of the ast package * 4*4887Schin * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5*4887Schin * and is licensed under the * 6*4887Schin * Common Public License, Version 1.0 * 7*4887Schin * by AT&T Knowledge Ventures * 8*4887Schin * * 9*4887Schin * A copy of the License is available at * 10*4887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 11*4887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*4887Schin * * 13*4887Schin * Information and Software Systems Research * 14*4887Schin * AT&T Research * 15*4887Schin * Florham Park NJ * 16*4887Schin * * 17*4887Schin * Glenn Fowler <gsf@research.att.com> * 18*4887Schin * David Korn <dgk@research.att.com> * 19*4887Schin * Phong Vo <kpv@research.att.com> * 20*4887Schin * * 21*4887Schin ***********************************************************************/ 22*4887Schin #pragma prototyped 23*4887Schin /* 24*4887Schin * Glenn Fowler 25*4887Schin * AT&T Research 26*4887Schin * 27*4887Schin * Time_t conversion support 28*4887Schin * 29*4887Schin * relative times inspired by Steve Bellovin's netnews getdate(3) 30*4887Schin */ 31*4887Schin 32*4887Schin #include <tmx.h> 33*4887Schin #include <ctype.h> 34*4887Schin 35*4887Schin #define dig1(s,n) ((n)=((*(s)++)-'0')) 36*4887Schin #define dig2(s,n) ((n)=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0') 37*4887Schin #define dig3(s,n) ((n)=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0') 38*4887Schin #define dig4(s,n) ((n)=((*(s)++)-'0')*1000,(n)+=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0') 39*4887Schin 40*4887Schin #define BREAK (1<<0) 41*4887Schin #define CCYYMMDDHHMMSS (1<<1) 42*4887Schin #define CRON (1<<2) 43*4887Schin #define DAY (1<<3) 44*4887Schin #define EXACT (1<<4) 45*4887Schin #define FINAL (1<<5) 46*4887Schin #define HOLD (1<<6) 47*4887Schin #define HOUR (1<<7) 48*4887Schin #define LAST (1<<8) 49*4887Schin #define MDAY (1<<9) 50*4887Schin #define MINUTE (1<<10) 51*4887Schin #define MONTH (1<<11) 52*4887Schin #define NEXT (1<<12) 53*4887Schin #define NSEC (1<<13) 54*4887Schin #define SECOND (1<<14) 55*4887Schin #define THIS (1L<<15) 56*4887Schin #define WDAY (1L<<16) 57*4887Schin #define YEAR (1L<<17) 58*4887Schin #define ZONE (1L<<18) 59*4887Schin 60*4887Schin /* 61*4887Schin * parse cron range into set 62*4887Schin * return: -1:error 0:* 1:some 63*4887Schin */ 64*4887Schin 65*4887Schin static int 66*4887Schin range(register char* s, char** e, char* set, int lo, int hi) 67*4887Schin { 68*4887Schin int n; 69*4887Schin int m; 70*4887Schin int i; 71*4887Schin char* t; 72*4887Schin 73*4887Schin while (isspace(*s) || *s == '_') 74*4887Schin s++; 75*4887Schin if (*s == '*') 76*4887Schin { 77*4887Schin *e = s + 1; 78*4887Schin return 0; 79*4887Schin } 80*4887Schin memset(set, 0, hi + 1); 81*4887Schin for (;;) 82*4887Schin { 83*4887Schin n = strtol(s, &t, 10); 84*4887Schin if (s == t || n < lo || n > hi) 85*4887Schin return -1; 86*4887Schin i = 1; 87*4887Schin if (*(s = t) == '-') 88*4887Schin { 89*4887Schin m = strtol(++s, &t, 10); 90*4887Schin if (s == t || m < n || m > hi) 91*4887Schin return -1; 92*4887Schin if (*(s = t) == '/') 93*4887Schin { 94*4887Schin i = strtol(++s, &t, 10); 95*4887Schin if (s == t || i < 1) 96*4887Schin return -1; 97*4887Schin s = t; 98*4887Schin } 99*4887Schin } 100*4887Schin else 101*4887Schin m = n; 102*4887Schin for (; n <= m; n += i) 103*4887Schin set[n] = 1; 104*4887Schin if (*s != ',') 105*4887Schin break; 106*4887Schin s++; 107*4887Schin } 108*4887Schin *e = s; 109*4887Schin return 1; 110*4887Schin } 111*4887Schin 112*4887Schin /* 113*4887Schin * parse date expression in s and return Time_t value 114*4887Schin * 115*4887Schin * if non-null, e points to the first invalid sequence in s 116*4887Schin * now provides default values 117*4887Schin */ 118*4887Schin 119*4887Schin Time_t 120*4887Schin tmxdate(register const char* s, char** e, Time_t now) 121*4887Schin { 122*4887Schin register Tm_t* tm; 123*4887Schin register long n; 124*4887Schin register int w; 125*4887Schin unsigned long set; 126*4887Schin unsigned long state; 127*4887Schin unsigned long flags; 128*4887Schin Time_t fix; 129*4887Schin char* t; 130*4887Schin char* u; 131*4887Schin const char* x; 132*4887Schin char* last; 133*4887Schin char* type; 134*4887Schin int day; 135*4887Schin int dir; 136*4887Schin int dst; 137*4887Schin int zone; 138*4887Schin int c; 139*4887Schin int f; 140*4887Schin int i; 141*4887Schin int j; 142*4887Schin int k; 143*4887Schin int l; 144*4887Schin long m; 145*4887Schin long p; 146*4887Schin long q; 147*4887Schin Tm_zone_t* zp; 148*4887Schin char skip[UCHAR_MAX + 1]; 149*4887Schin 150*4887Schin /* 151*4887Schin * check DATEMSK first 152*4887Schin */ 153*4887Schin 154*4887Schin fix = tmxscan(s, &last, NiL, &t, now, 0); 155*4887Schin if (t && !*last) 156*4887Schin { 157*4887Schin if (e) 158*4887Schin *e = last; 159*4887Schin return fix; 160*4887Schin } 161*4887Schin 162*4887Schin reset: 163*4887Schin 164*4887Schin /* 165*4887Schin * use now for defaults 166*4887Schin */ 167*4887Schin 168*4887Schin tm = tmxmake(now); 169*4887Schin tm_info.date = tm_info.zone; 170*4887Schin day = -1; 171*4887Schin dst = TM_DST; 172*4887Schin set = state = 0; 173*4887Schin type = 0; 174*4887Schin zone = TM_LOCALZONE; 175*4887Schin skip[0] = 0; 176*4887Schin for (n = 1; n <= UCHAR_MAX; n++) 177*4887Schin skip[n] = isspace(n) || strchr("_,;@=|!^()[]{}", n); 178*4887Schin 179*4887Schin /* 180*4887Schin * get <weekday year month day hour minutes seconds ?[ds]t [ap]m> 181*4887Schin */ 182*4887Schin 183*4887Schin for (;;) 184*4887Schin { 185*4887Schin state &= (state & HOLD) ? ~(HOLD) : ~(EXACT|LAST|NEXT|THIS); 186*4887Schin if ((set|state) & (YEAR|MONTH|DAY)) 187*4887Schin skip['/'] = 1; 188*4887Schin for (;;) 189*4887Schin { 190*4887Schin if (*s == '.' || *s == '-' || *s == '+') 191*4887Schin { 192*4887Schin if (((set|state) & (YEAR|MONTH|HOUR|MINUTE|ZONE)) == (YEAR|MONTH|HOUR|MINUTE) && (i = tmgoff(s, &t, TM_LOCALZONE)) != TM_LOCALZONE) 193*4887Schin { 194*4887Schin zone = i; 195*4887Schin state |= ZONE; 196*4887Schin if (!*(s = t)) 197*4887Schin break; 198*4887Schin } 199*4887Schin else if (*s == '+') 200*4887Schin break; 201*4887Schin } 202*4887Schin else if (!skip[*s]) 203*4887Schin break; 204*4887Schin s++; 205*4887Schin } 206*4887Schin if (!*(last = (char*)s)) 207*4887Schin break; 208*4887Schin if (*s == '#') 209*4887Schin { 210*4887Schin if (isdigit(*++s)) 211*4887Schin { 212*4887Schin now = strtoull(s, &t, 0); 213*4887Schin sns: 214*4887Schin if (*(s = t) == '.') 215*4887Schin { 216*4887Schin fix = 0; 217*4887Schin m = 1000000000; 218*4887Schin while (isdigit(*++s)) 219*4887Schin fix += (*s - '0') * (m /= 10); 220*4887Schin now = tmxsns(now, fix); 221*4887Schin } 222*4887Schin else if (now <= 0x7fffffff) 223*4887Schin now = tmxsns(now, 0); 224*4887Schin goto reset; 225*4887Schin } 226*4887Schin else if (*s++ == '#') 227*4887Schin { 228*4887Schin now = tmxtime(tm, zone); 229*4887Schin goto reset; 230*4887Schin } 231*4887Schin break; 232*4887Schin } 233*4887Schin f = -1; 234*4887Schin if (*s == '+') 235*4887Schin { 236*4887Schin while (isspace(*++s) || *s == '_'); 237*4887Schin n = strtol(s, &t, 0); 238*4887Schin if (w = t - s) 239*4887Schin { 240*4887Schin for (s = t; skip[*s]; s++); 241*4887Schin state |= (f = n) ? NEXT : THIS; 242*4887Schin set &= ~(EXACT|LAST|NEXT|THIS); 243*4887Schin set |= state & (EXACT|LAST|NEXT|THIS); 244*4887Schin } 245*4887Schin else 246*4887Schin s = last; 247*4887Schin } 248*4887Schin if (!(state & CRON)) 249*4887Schin { 250*4887Schin /* 251*4887Schin * check for cron date 252*4887Schin * 253*4887Schin * min hour day-of-month month day-of-week 254*4887Schin * 255*4887Schin * if it's cron then determine the next time 256*4887Schin * that satisfies the specification 257*4887Schin * 258*4887Schin * NOTE: the only spacing is ' '||'_'||';' 259*4887Schin */ 260*4887Schin 261*4887Schin i = 0; 262*4887Schin n = *(t = (char*)s); 263*4887Schin for (;;) 264*4887Schin { 265*4887Schin if (n == '*') 266*4887Schin n = *++s; 267*4887Schin else if (!isdigit(n)) 268*4887Schin break; 269*4887Schin else 270*4887Schin while ((n = *++s) == ',' || n == '-' || n == '/' || isdigit(n)); 271*4887Schin if (n != ' ' && n != '_' && n != ';') 272*4887Schin { 273*4887Schin if (!n) 274*4887Schin i++; 275*4887Schin break; 276*4887Schin } 277*4887Schin i++; 278*4887Schin while ((n = *++s) == ' ' || n == '_'); 279*4887Schin } 280*4887Schin if (i == 5) 281*4887Schin { 282*4887Schin Time_t tt; 283*4887Schin char hit[60]; 284*4887Schin char mon[12]; 285*4887Schin char day[7]; 286*4887Schin 287*4887Schin state |= CRON; 288*4887Schin flags = 0; 289*4887Schin tm->tm_sec = 0; 290*4887Schin tm->tm_min++; 291*4887Schin tmfix(tm); 292*4887Schin 293*4887Schin /* 294*4887Schin * minute 295*4887Schin */ 296*4887Schin 297*4887Schin if ((k = range(t, &t, hit, 0, 59)) < 0) 298*4887Schin break; 299*4887Schin if (k && !hit[i = tm->tm_min]) 300*4887Schin { 301*4887Schin hit[i] = 1; 302*4887Schin do if (++i > 59) 303*4887Schin { 304*4887Schin i = 0; 305*4887Schin if (++tm->tm_hour > 59) 306*4887Schin { 307*4887Schin tm->tm_min = i; 308*4887Schin tmfix(tm); 309*4887Schin } 310*4887Schin } while (!hit[i]); 311*4887Schin tm->tm_min = i; 312*4887Schin } 313*4887Schin 314*4887Schin /* 315*4887Schin * hour 316*4887Schin */ 317*4887Schin 318*4887Schin if ((k = range(t, &t, hit, 0, 23)) < 0) 319*4887Schin break; 320*4887Schin if (k && !hit[i = tm->tm_hour]) 321*4887Schin { 322*4887Schin hit[i] = 1; 323*4887Schin do if (++i > 23) 324*4887Schin { 325*4887Schin i = 0; 326*4887Schin if (++tm->tm_mday > 28) 327*4887Schin { 328*4887Schin tm->tm_hour = i; 329*4887Schin tmfix(tm); 330*4887Schin } 331*4887Schin } while (!hit[i]); 332*4887Schin tm->tm_hour = i; 333*4887Schin } 334*4887Schin 335*4887Schin /* 336*4887Schin * day of month 337*4887Schin */ 338*4887Schin 339*4887Schin if ((k = range(t, &t, hit, 1, 31)) < 0) 340*4887Schin break; 341*4887Schin if (k) 342*4887Schin flags |= DAY|MDAY; 343*4887Schin 344*4887Schin /* 345*4887Schin * month 346*4887Schin */ 347*4887Schin 348*4887Schin if ((k = range(t, &t, mon, 1, 12)) < 0) 349*4887Schin break; 350*4887Schin if (k) 351*4887Schin flags |= MONTH; 352*4887Schin else 353*4887Schin for (i = 1; i <= 12; i++) 354*4887Schin mon[i] = 1; 355*4887Schin 356*4887Schin /* 357*4887Schin * day of week 358*4887Schin */ 359*4887Schin 360*4887Schin if ((k = range(t, &t, day, 0, 6)) < 0) 361*4887Schin break; 362*4887Schin if (k) 363*4887Schin flags |= WDAY; 364*4887Schin s = t; 365*4887Schin if (flags & (MONTH|MDAY|WDAY)) 366*4887Schin { 367*4887Schin fix = tmxtime(tm, zone); 368*4887Schin tm = tmxmake(fix); 369*4887Schin i = tm->tm_mon + 1; 370*4887Schin j = tm->tm_mday; 371*4887Schin k = tm->tm_wday; 372*4887Schin for (;;) 373*4887Schin { 374*4887Schin if (!mon[i]) 375*4887Schin { 376*4887Schin if (++i > 12) 377*4887Schin { 378*4887Schin i = 1; 379*4887Schin tm->tm_year++; 380*4887Schin } 381*4887Schin tm->tm_mon = i - 1; 382*4887Schin tm->tm_mday = 1; 383*4887Schin tt = tmxtime(tm, zone); 384*4887Schin if (tt < fix) 385*4887Schin goto done; 386*4887Schin tm = tmxmake(tt); 387*4887Schin i = tm->tm_mon + 1; 388*4887Schin j = tm->tm_mday; 389*4887Schin k = tm->tm_wday; 390*4887Schin continue; 391*4887Schin } 392*4887Schin if (flags & (MDAY|WDAY)) 393*4887Schin { 394*4887Schin if ((flags & (MDAY|WDAY)) == (MDAY|WDAY)) 395*4887Schin { 396*4887Schin if (hit[j] && day[k]) 397*4887Schin break; 398*4887Schin } 399*4887Schin else if ((flags & MDAY) && hit[j]) 400*4887Schin break; 401*4887Schin else if ((flags & WDAY) && day[k]) 402*4887Schin break; 403*4887Schin if (++j > 28) 404*4887Schin { 405*4887Schin tm->tm_mon = i - 1; 406*4887Schin tm->tm_mday = j; 407*4887Schin tm = tmxmake(tmxtime(tm, zone)); 408*4887Schin i = tm->tm_mon + 1; 409*4887Schin j = tm->tm_mday; 410*4887Schin k = tm->tm_wday; 411*4887Schin } 412*4887Schin else if ((flags & WDAY) && ++k > 6) 413*4887Schin k = 0; 414*4887Schin } 415*4887Schin else if (flags & MONTH) 416*4887Schin break; 417*4887Schin } 418*4887Schin tm->tm_mon = i - 1; 419*4887Schin tm->tm_mday = j; 420*4887Schin tm->tm_wday = k; 421*4887Schin } 422*4887Schin continue; 423*4887Schin } 424*4887Schin s = t; 425*4887Schin } 426*4887Schin n = -1; 427*4887Schin if (isdigit(*s)) 428*4887Schin { 429*4887Schin n = strtol(s, &t, 10); 430*4887Schin if ((w = t - s) && *t == '.' && isdigit(*(t + 1)) && isdigit(*(t + 2)) && isdigit(*(t + 3))) 431*4887Schin { 432*4887Schin now = n; 433*4887Schin goto sns; 434*4887Schin } 435*4887Schin u = t + (*t == '-'); 436*4887Schin if ((w == 2 || w == 4) && (*u == 'W' || *u == 'w') && isdigit(*(u + 1))) 437*4887Schin { 438*4887Schin t = u; 439*4887Schin if (w == 4) 440*4887Schin { 441*4887Schin if ((n -= 1900) < TM_WINDOW) 442*4887Schin break; 443*4887Schin } 444*4887Schin else if (n < TM_WINDOW) 445*4887Schin n += 100; 446*4887Schin m = n; 447*4887Schin n = strtol(s = t + 1, &t, 0); 448*4887Schin if ((i = (t - s)) < 2 || i > 3) 449*4887Schin break; 450*4887Schin if (dig2(s, j) < 0 || j > 53) 451*4887Schin break; 452*4887Schin if (!(t - s) && *t == '-') 453*4887Schin n = strtol(s = t + 1, &t, 0); 454*4887Schin if (!(i = (t - s))) 455*4887Schin k = 1; 456*4887Schin else if (i != 1 || dig1(s, k) < 1 || k > 7) 457*4887Schin break; 458*4887Schin else if (k == 7) 459*4887Schin k = 0; 460*4887Schin tm->tm_year = m; 461*4887Schin tmweek(tm, 2, j, k); 462*4887Schin set |= YEAR|MONTH|DAY; 463*4887Schin continue; 464*4887Schin } 465*4887Schin else if ((w == 6 || w == 8) && (*u == 'T' || *u == 't') && isdigit(*(u + 1))) 466*4887Schin { 467*4887Schin t = u; 468*4887Schin flags = 0; 469*4887Schin if (w == 8) 470*4887Schin { 471*4887Schin dig4(s, m); 472*4887Schin if ((m -= 1900) < TM_WINDOW) 473*4887Schin break; 474*4887Schin } 475*4887Schin else 476*4887Schin { 477*4887Schin dig2(s, m); 478*4887Schin if (m < TM_WINDOW) 479*4887Schin m += 100; 480*4887Schin } 481*4887Schin flags |= YEAR; 482*4887Schin if (dig2(s, l) <= 0 || l > 12) 483*4887Schin break; 484*4887Schin flags |= MONTH; 485*4887Schin if (dig2(s, k) < 1 || k > 31) 486*4887Schin break; 487*4887Schin n = strtol(s = t + 1, &t, 0); 488*4887Schin if ((t - s) < 2) 489*4887Schin break; 490*4887Schin if (dig2(s, j) > 24) 491*4887Schin break; 492*4887Schin if ((t - s) < 2) 493*4887Schin { 494*4887Schin if ((t - s) == 1 || *t++ != '-') 495*4887Schin break; 496*4887Schin n = strtol(s = t, &t, 0); 497*4887Schin if ((t - s) < 2) 498*4887Schin break; 499*4887Schin } 500*4887Schin if (dig2(s, i) > 59) 501*4887Schin break; 502*4887Schin flags |= HOUR|MINUTE; 503*4887Schin if ((t - s) == 2) 504*4887Schin { 505*4887Schin if (dig2(s, n) > (59 + TM_MAXLEAP)) 506*4887Schin break; 507*4887Schin flags |= SECOND; 508*4887Schin } 509*4887Schin else if (t - s) 510*4887Schin break; 511*4887Schin else 512*4887Schin n = 0; 513*4887Schin p = 0; 514*4887Schin if (*t == '.') 515*4887Schin { 516*4887Schin q = 1000000000; 517*4887Schin while (isdigit(*++t)) 518*4887Schin p += (*t - '0') * (q /= 10); 519*4887Schin set |= NSEC; 520*4887Schin } 521*4887Schin if (n > (59 + TM_MAXLEAP)) 522*4887Schin break; 523*4887Schin goto save; 524*4887Schin } 525*4887Schin else if (f == -1 && isalpha(*t) && tmlex(t, &t, tm_info.format + TM_ORDINAL, TM_ORDINALS - TM_ORDINAL, NiL, 0) >= 0) 526*4887Schin { 527*4887Schin ordinal: 528*4887Schin state |= (f = n) ? NEXT : THIS; 529*4887Schin set &= ~(EXACT|LAST|NEXT|THIS); 530*4887Schin set |= state & (EXACT|LAST|NEXT|THIS); 531*4887Schin for (s = t; skip[*s]; s++); 532*4887Schin if (isdigit(*s)) 533*4887Schin { 534*4887Schin n = strtol(s, &t, 10); 535*4887Schin s = t; 536*4887Schin if (*s == '_') 537*4887Schin s++; 538*4887Schin } 539*4887Schin else 540*4887Schin n = -1; 541*4887Schin } 542*4887Schin else 543*4887Schin { 544*4887Schin if (!(state & (LAST|NEXT|THIS)) && ((i = t - s) == 4 && (*t == '.' && isdigit(*(t + 1)) && isdigit(*(t + 2)) && *(t + 3) != '.' || (!*t || isspace(*t) || *t == '_' || isalnum(*t)) && n >= 0 && (n % 100) < 60 && ((m = (n / 100)) < 20 || m < 24 && !((set|state) & (YEAR|MONTH|HOUR|MINUTE)))) || i > 4 && i <= 12)) 545*4887Schin { 546*4887Schin /* 547*4887Schin * various { date(1) touch(1) } formats 548*4887Schin * 549*4887Schin * [[cc]yy[mm]]ddhhmm[.ss[.nn...]] 550*4887Schin * [cc]yyjjj 551*4887Schin * hhmm[.ss[.nn...]] 552*4887Schin */ 553*4887Schin 554*4887Schin flags = 0; 555*4887Schin if (state & CCYYMMDDHHMMSS) 556*4887Schin break; 557*4887Schin state |= CCYYMMDDHHMMSS; 558*4887Schin p = 0; 559*4887Schin if ((i == 7 || i == 5) && !*t) 560*4887Schin { 561*4887Schin if (i == 7) 562*4887Schin { 563*4887Schin dig4(s, m); 564*4887Schin if ((m -= 1900) < TM_WINDOW) 565*4887Schin break; 566*4887Schin } 567*4887Schin else if (dig2(s, m) < TM_WINDOW) 568*4887Schin m += 100; 569*4887Schin dig3(s, k); 570*4887Schin l = 1; 571*4887Schin j = 0; 572*4887Schin i = 0; 573*4887Schin n = 0; 574*4887Schin flags |= MONTH; 575*4887Schin } 576*4887Schin else if (i & 1) 577*4887Schin break; 578*4887Schin else 579*4887Schin { 580*4887Schin u = t; 581*4887Schin if (i == 12) 582*4887Schin { 583*4887Schin x = s; 584*4887Schin dig2(x, m); 585*4887Schin if (m <= 12) 586*4887Schin { 587*4887Schin u -= 4; 588*4887Schin i -= 4; 589*4887Schin x = s + 8; 590*4887Schin dig4(x, m); 591*4887Schin } 592*4887Schin else 593*4887Schin dig4(s, m); 594*4887Schin m -= 1900; 595*4887Schin } 596*4887Schin else if (i == 10) 597*4887Schin { 598*4887Schin x = s; 599*4887Schin if (!dig2(x, m) || m > 12 || !dig2(x, m) || m > 31 || dig2(x, m) > 24 || dig2(x, m) > 60 || dig2(x, m) <= 60 && !(tm_info.flags & TM_DATESTYLE)) 600*4887Schin dig2(s, m); 601*4887Schin else 602*4887Schin { 603*4887Schin u -= 2; 604*4887Schin i -= 2; 605*4887Schin x = s + 8; 606*4887Schin dig2(x, m); 607*4887Schin } 608*4887Schin if (m < TM_WINDOW) 609*4887Schin m += 100; 610*4887Schin } 611*4887Schin else 612*4887Schin m = tm->tm_year; 613*4887Schin if ((u - s) < 8) 614*4887Schin l = tm->tm_mon + 1; 615*4887Schin else if (dig2(s, l) <= 0 || l > 12) 616*4887Schin break; 617*4887Schin else 618*4887Schin flags |= MONTH; 619*4887Schin if ((u - s) < 6) 620*4887Schin k = tm->tm_mday; 621*4887Schin else if (dig2(s, k) < 1 || k > 31) 622*4887Schin break; 623*4887Schin else 624*4887Schin flags |= DAY; 625*4887Schin if ((u - s) < 4) 626*4887Schin break; 627*4887Schin if (dig2(s, j) > 24) 628*4887Schin break; 629*4887Schin if (dig2(s, i) > 59) 630*4887Schin break; 631*4887Schin flags |= HOUR|MINUTE; 632*4887Schin if ((u - s) == 2) 633*4887Schin { 634*4887Schin dig2(s, n); 635*4887Schin flags |= SECOND; 636*4887Schin } 637*4887Schin else if (u - s) 638*4887Schin break; 639*4887Schin else if (*t != '.') 640*4887Schin n = 0; 641*4887Schin else 642*4887Schin { 643*4887Schin n = strtol(t + 1, &t, 10); 644*4887Schin flags |= SECOND; 645*4887Schin if (*t == '.') 646*4887Schin { 647*4887Schin q = 1000000000; 648*4887Schin while (isdigit(*++t)) 649*4887Schin p += (*t - '0') * (q /= 10); 650*4887Schin set |= NSEC; 651*4887Schin } 652*4887Schin } 653*4887Schin if (n > (59 + TM_MAXLEAP)) 654*4887Schin break; 655*4887Schin } 656*4887Schin save: 657*4887Schin tm->tm_year = m; 658*4887Schin tm->tm_mon = l - 1; 659*4887Schin tm->tm_mday = k; 660*4887Schin tm->tm_hour = j; 661*4887Schin tm->tm_min = i; 662*4887Schin tm->tm_sec = n; 663*4887Schin tm->tm_nsec = p; 664*4887Schin s = t; 665*4887Schin set |= flags; 666*4887Schin continue; 667*4887Schin } 668*4887Schin for (s = t; skip[*s]; s++); 669*4887Schin if (*s == ':' || *s == '.' && ((set|state) & (YEAR|MONTH|DAY|HOUR)) == (YEAR|MONTH|DAY)) 670*4887Schin { 671*4887Schin c = *s; 672*4887Schin if ((state & HOUR) || n > 24) 673*4887Schin break; 674*4887Schin while (isspace(*++s) || *s == '_'); 675*4887Schin if (!isdigit(*s)) 676*4887Schin break; 677*4887Schin i = n; 678*4887Schin n = strtol(s, &t, 10); 679*4887Schin for (s = t; isspace(*s) || *s == '_'; s++); 680*4887Schin if (n > 59) 681*4887Schin break; 682*4887Schin j = n; 683*4887Schin m = 0; 684*4887Schin if (*s == c) 685*4887Schin { 686*4887Schin while (isspace(*++s) || *s == '_'); 687*4887Schin if (!isdigit(*s)) 688*4887Schin break; 689*4887Schin n = strtol(s, &t, 10); 690*4887Schin s = t; 691*4887Schin if (n > (59 + TM_MAXLEAP)) 692*4887Schin break; 693*4887Schin set |= SECOND; 694*4887Schin while (isspace(*s)) 695*4887Schin s++; 696*4887Schin if (*s == '.') 697*4887Schin { 698*4887Schin q = 1000000000; 699*4887Schin while (isdigit(*++s)) 700*4887Schin m += (*s - '0') * (q /= 10); 701*4887Schin set |= NSEC; 702*4887Schin } 703*4887Schin } 704*4887Schin else 705*4887Schin n = 0; 706*4887Schin set |= HOUR|MINUTE; 707*4887Schin skip[':'] = 1; 708*4887Schin k = tm->tm_hour; 709*4887Schin tm->tm_hour = i; 710*4887Schin l = tm->tm_min; 711*4887Schin tm->tm_min = j; 712*4887Schin tm->tm_sec = n; 713*4887Schin tm->tm_nsec = m; 714*4887Schin while (isspace(*s)) 715*4887Schin s++; 716*4887Schin switch (tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_MERIDIAN, 2)) 717*4887Schin { 718*4887Schin case TM_MERIDIAN: 719*4887Schin s = t; 720*4887Schin if (i == 12) 721*4887Schin tm->tm_hour = i = 0; 722*4887Schin break; 723*4887Schin case TM_MERIDIAN+1: 724*4887Schin if (i < 12) 725*4887Schin tm->tm_hour = i += 12; 726*4887Schin break; 727*4887Schin } 728*4887Schin if (f >= 0 || (state & (LAST|NEXT))) 729*4887Schin { 730*4887Schin state &= ~HOLD; 731*4887Schin if (f < 0) 732*4887Schin { 733*4887Schin if (state & LAST) 734*4887Schin f = -1; 735*4887Schin else if (state & NEXT) 736*4887Schin f = 1; 737*4887Schin else 738*4887Schin f = 0; 739*4887Schin } 740*4887Schin if (f > 0) 741*4887Schin { 742*4887Schin if (i > k || i == k && j > l) 743*4887Schin f--; 744*4887Schin } 745*4887Schin else if (i < k || i == k && j < l) 746*4887Schin f++; 747*4887Schin if (f > 0) 748*4887Schin { 749*4887Schin tm->tm_hour += f * 24; 750*4887Schin while (tm->tm_hour >= 24) 751*4887Schin { 752*4887Schin tm->tm_hour -= 24; 753*4887Schin tm->tm_mday++; 754*4887Schin } 755*4887Schin } 756*4887Schin else if (f < 0) 757*4887Schin { 758*4887Schin tm->tm_hour += f * 24; 759*4887Schin while (tm->tm_hour < 24) 760*4887Schin { 761*4887Schin tm->tm_hour += 24; 762*4887Schin tm->tm_mday--; 763*4887Schin } 764*4887Schin } 765*4887Schin } 766*4887Schin continue; 767*4887Schin } 768*4887Schin } 769*4887Schin } 770*4887Schin for (;;) 771*4887Schin { 772*4887Schin if (*s == '-' || *s == '+') 773*4887Schin { 774*4887Schin if (((set|state) & (MONTH|DAY|HOUR|MINUTE)) == (MONTH|DAY|HOUR|MINUTE) || *s == '+' && (!isdigit(s[1]) || !isdigit(s[2]) || s[3] != ':' && (s[3] != '.' || ((set|state) & (YEAR|MONTH)) != (YEAR|MONTH)))) 775*4887Schin break; 776*4887Schin s++; 777*4887Schin } 778*4887Schin else if (skip[*s]) 779*4887Schin s++; 780*4887Schin else 781*4887Schin break; 782*4887Schin } 783*4887Schin if (isalpha(*s) && n < 1000) 784*4887Schin { 785*4887Schin if ((j = tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES)) >= 0) 786*4887Schin { 787*4887Schin s = t; 788*4887Schin switch (tm_data.lex[j]) 789*4887Schin { 790*4887Schin case TM_EXACT: 791*4887Schin state |= HOLD|EXACT; 792*4887Schin set &= ~(EXACT|LAST|NEXT|THIS); 793*4887Schin set |= state & (EXACT|LAST|NEXT|THIS); 794*4887Schin continue; 795*4887Schin case TM_LAST: 796*4887Schin state |= HOLD|LAST; 797*4887Schin set &= ~(EXACT|LAST|NEXT|THIS); 798*4887Schin set |= state & (EXACT|LAST|NEXT|THIS); 799*4887Schin continue; 800*4887Schin case TM_THIS: 801*4887Schin state |= HOLD|THIS; 802*4887Schin set &= ~(EXACT|LAST|NEXT|THIS); 803*4887Schin set |= state & (EXACT|LAST|NEXT|THIS); 804*4887Schin n = 0; 805*4887Schin continue; 806*4887Schin case TM_NEXT: 807*4887Schin /* 808*4887Schin * disambiguate english "last ... in" 809*4887Schin */ 810*4887Schin 811*4887Schin if (!((state|set) & LAST)) 812*4887Schin { 813*4887Schin state |= HOLD|NEXT; 814*4887Schin set &= ~(EXACT|LAST|NEXT|THIS); 815*4887Schin set |= state & (EXACT|LAST|NEXT|THIS); 816*4887Schin continue; 817*4887Schin } 818*4887Schin /*FALLTHROUGH*/ 819*4887Schin case TM_FINAL: 820*4887Schin state |= HOLD|THIS|FINAL; 821*4887Schin set &= ~(EXACT|LAST|NEXT|THIS); 822*4887Schin set |= state & (EXACT|LAST|NEXT|THIS|FINAL); 823*4887Schin continue; 824*4887Schin case TM_ORDINAL: 825*4887Schin j += TM_ORDINALS - TM_ORDINAL; 826*4887Schin /*FALLTHROUGH*/ 827*4887Schin case TM_ORDINALS: 828*4887Schin n = j - TM_ORDINALS + 1; 829*4887Schin goto ordinal; 830*4887Schin case TM_MERIDIAN: 831*4887Schin if (f >= 0) 832*4887Schin f++; 833*4887Schin else if (state & LAST) 834*4887Schin f = -1; 835*4887Schin else if (state & THIS) 836*4887Schin f = 1; 837*4887Schin else if (state & NEXT) 838*4887Schin f = 2; 839*4887Schin else 840*4887Schin f = 0; 841*4887Schin if (n > 0) 842*4887Schin { 843*4887Schin if (n > 24) 844*4887Schin goto done; 845*4887Schin tm->tm_hour = n; 846*4887Schin } 847*4887Schin for (k = tm->tm_hour; k < 0; k += 24); 848*4887Schin k %= 24; 849*4887Schin if (j == TM_MERIDIAN) 850*4887Schin { 851*4887Schin if (k == 12) 852*4887Schin tm->tm_hour -= 12; 853*4887Schin } 854*4887Schin else if (k < 12) 855*4887Schin tm->tm_hour += 12; 856*4887Schin if (n > 0) 857*4887Schin goto clear_min; 858*4887Schin continue; 859*4887Schin case TM_DAY_ABBREV: 860*4887Schin j += TM_DAY - TM_DAY_ABBREV; 861*4887Schin /*FALLTHROUGH*/ 862*4887Schin case TM_DAY: 863*4887Schin case TM_PARTS: 864*4887Schin case TM_HOURS: 865*4887Schin state |= set & (EXACT|LAST|NEXT|THIS); 866*4887Schin if (!(state & (LAST|NEXT|THIS))) 867*4887Schin for (;;) 868*4887Schin { 869*4887Schin while (skip[*s]) 870*4887Schin s++; 871*4887Schin if ((k = tmlex(s, &t, tm_info.format + TM_LAST, TM_NOISE - TM_LAST, NiL, 0)) >= 0) 872*4887Schin { 873*4887Schin s = t; 874*4887Schin if (k <= 2) 875*4887Schin state |= LAST; 876*4887Schin else if (k <= 5) 877*4887Schin state |= THIS; 878*4887Schin else if (k <= 8) 879*4887Schin state |= NEXT; 880*4887Schin else 881*4887Schin state |= EXACT; 882*4887Schin } 883*4887Schin else 884*4887Schin { 885*4887Schin state |= (n > 0) ? NEXT : THIS; 886*4887Schin break; 887*4887Schin } 888*4887Schin set &= ~(EXACT|LAST|NEXT|THIS); 889*4887Schin set |= state & (EXACT|LAST|NEXT|THIS); 890*4887Schin } 891*4887Schin /*FALLTHROUGH*/ 892*4887Schin case TM_DAYS: 893*4887Schin if (n == -1) 894*4887Schin { 895*4887Schin /* 896*4887Schin * disambiguate english "second" 897*4887Schin */ 898*4887Schin 899*4887Schin if (j == TM_PARTS && f == -1) 900*4887Schin { 901*4887Schin n = 2; 902*4887Schin goto ordinal; 903*4887Schin } 904*4887Schin n = 1; 905*4887Schin } 906*4887Schin if (state & LAST) 907*4887Schin n = -n; 908*4887Schin else if (!(state & NEXT)) 909*4887Schin n--; 910*4887Schin m = (f > 0) ? f * n : n; 911*4887Schin switch (j) 912*4887Schin { 913*4887Schin case TM_DAYS+0: 914*4887Schin tm->tm_mday--; 915*4887Schin set |= DAY; 916*4887Schin goto clear_hour; 917*4887Schin case TM_DAYS+1: 918*4887Schin set |= DAY; 919*4887Schin goto clear_hour; 920*4887Schin case TM_DAYS+2: 921*4887Schin tm->tm_mday++; 922*4887Schin set |= DAY; 923*4887Schin goto clear_hour; 924*4887Schin case TM_PARTS+0: 925*4887Schin set |= SECOND; 926*4887Schin if ((m < 0 ? -m : m) > (365L*24L*60L*60L)) 927*4887Schin { 928*4887Schin now = tmxtime(tm, zone) + tmxsns(m, 0); 929*4887Schin goto reset; 930*4887Schin } 931*4887Schin tm->tm_sec += m; 932*4887Schin goto clear_nsec; 933*4887Schin case TM_PARTS+1: 934*4887Schin tm->tm_min += m; 935*4887Schin set |= MINUTE; 936*4887Schin goto clear_sec; 937*4887Schin case TM_PARTS+2: 938*4887Schin tm->tm_hour += m; 939*4887Schin set |= MINUTE; 940*4887Schin goto clear_min; 941*4887Schin case TM_PARTS+3: 942*4887Schin tm->tm_mday += m; 943*4887Schin if (!(set & FINAL)) 944*4887Schin set |= HOUR; 945*4887Schin goto clear_hour; 946*4887Schin case TM_PARTS+4: 947*4887Schin tm = tmxmake(tmxtime(tm, zone)); 948*4887Schin tm->tm_mday += 7 * m - tm->tm_wday + 1; 949*4887Schin set |= DAY; 950*4887Schin goto clear_hour; 951*4887Schin case TM_PARTS+5: 952*4887Schin tm->tm_mon += m; 953*4887Schin set |= MONTH; 954*4887Schin goto clear_mday; 955*4887Schin case TM_PARTS+6: 956*4887Schin tm->tm_year += m; 957*4887Schin goto clear_mon; 958*4887Schin case TM_HOURS+0: 959*4887Schin tm->tm_mday += m; 960*4887Schin set |= DAY; 961*4887Schin goto clear_hour; 962*4887Schin case TM_HOURS+1: 963*4887Schin tm->tm_mday += m; 964*4887Schin tm->tm_hour = 6; 965*4887Schin set |= HOUR; 966*4887Schin goto clear_min; 967*4887Schin case TM_HOURS+2: 968*4887Schin tm->tm_mday += m; 969*4887Schin tm->tm_hour = 12; 970*4887Schin set |= HOUR; 971*4887Schin goto clear_min; 972*4887Schin case TM_HOURS+3: 973*4887Schin tm->tm_mday += m; 974*4887Schin tm->tm_hour = 18; 975*4887Schin set |= HOUR; 976*4887Schin goto clear_min; 977*4887Schin } 978*4887Schin tm = tmxmake(tmxtime(tm, zone)); 979*4887Schin day = j -= TM_DAY; 980*4887Schin dir = m; 981*4887Schin j -= tm->tm_wday; 982*4887Schin if (state & (LAST|NEXT|THIS)) 983*4887Schin { 984*4887Schin if (j < 0) 985*4887Schin j += 7; 986*4887Schin } 987*4887Schin else if (j > 0) 988*4887Schin j -= 7; 989*4887Schin tm->tm_mday += j + m * 7; 990*4887Schin set |= DAY; 991*4887Schin if (state & (LAST|NEXT|THIS)) 992*4887Schin goto clear_hour; 993*4887Schin continue; 994*4887Schin case TM_MONTH_ABBREV: 995*4887Schin j += TM_MONTH - TM_MONTH_ABBREV; 996*4887Schin /*FALLTHROUGH*/ 997*4887Schin case TM_MONTH: 998*4887Schin if (state & MONTH) 999*4887Schin goto done; 1000*4887Schin state |= MONTH; 1001*4887Schin i = tm->tm_mon; 1002*4887Schin tm->tm_mon = j - TM_MONTH; 1003*4887Schin if (n < 0) 1004*4887Schin { 1005*4887Schin while (skip[*s]) 1006*4887Schin s++; 1007*4887Schin if (isdigit(*s)) 1008*4887Schin { 1009*4887Schin n = strtol(s, &t, 10); 1010*4887Schin if (n <= 31 && *t != ':') 1011*4887Schin s = t; 1012*4887Schin else 1013*4887Schin n = -1; 1014*4887Schin } 1015*4887Schin } 1016*4887Schin if (n >= 0) 1017*4887Schin { 1018*4887Schin if (n > 31) 1019*4887Schin goto done; 1020*4887Schin state |= DAY|MDAY; 1021*4887Schin tm->tm_mday = n; 1022*4887Schin if (f > 0) 1023*4887Schin tm->tm_year += f; 1024*4887Schin } 1025*4887Schin if (state & (LAST|NEXT|THIS)) 1026*4887Schin { 1027*4887Schin n = i; 1028*4887Schin goto rel_month; 1029*4887Schin } 1030*4887Schin continue; 1031*4887Schin case TM_UT: 1032*4887Schin if (state & ZONE) 1033*4887Schin goto done; 1034*4887Schin state |= ZONE; 1035*4887Schin zone = tmgoff(s, &t, 0); 1036*4887Schin s = t; 1037*4887Schin continue; 1038*4887Schin case TM_DT: 1039*4887Schin if (!dst) 1040*4887Schin goto done; 1041*4887Schin if (!(state & ZONE)) 1042*4887Schin { 1043*4887Schin dst = tm_info.zone->dst; 1044*4887Schin zone = tm_info.zone->west; 1045*4887Schin } 1046*4887Schin zone += tmgoff(s, &t, dst); 1047*4887Schin s = t; 1048*4887Schin dst = 0; 1049*4887Schin state |= ZONE; 1050*4887Schin continue; 1051*4887Schin case TM_NOISE: 1052*4887Schin continue; 1053*4887Schin } 1054*4887Schin } 1055*4887Schin if (!(state & ZONE) && (zp = tmzone(s, &t, type, &dst))) 1056*4887Schin { 1057*4887Schin s = t; 1058*4887Schin zone = zp->west + dst; 1059*4887Schin tm_info.date = zp; 1060*4887Schin state |= ZONE; 1061*4887Schin continue; 1062*4887Schin } 1063*4887Schin if (!type && (zp = tmtype(s, &t))) 1064*4887Schin { 1065*4887Schin s = t; 1066*4887Schin type = zp->type; 1067*4887Schin continue; 1068*4887Schin } 1069*4887Schin state |= BREAK; 1070*4887Schin } 1071*4887Schin else if (*s == '/') 1072*4887Schin { 1073*4887Schin if (!(state & (YEAR|MONTH)) && n >= 1900 && n < 3000 && (i = strtol(s + 1, &t, 10)) > 0 && i <= 12) 1074*4887Schin { 1075*4887Schin state |= YEAR; 1076*4887Schin tm->tm_year = n - 1900; 1077*4887Schin s = t; 1078*4887Schin i--; 1079*4887Schin } 1080*4887Schin else 1081*4887Schin { 1082*4887Schin if ((state & MONTH) || n <= 0 || n > 31) 1083*4887Schin break; 1084*4887Schin if (isalpha(*++s)) 1085*4887Schin { 1086*4887Schin if ((i = tmlex(s, &t, tm_info.format, TM_DAY_ABBREV, NiL, 0)) < 0) 1087*4887Schin break; 1088*4887Schin if (i >= TM_MONTH) 1089*4887Schin i -= TM_MONTH; 1090*4887Schin s = t; 1091*4887Schin } 1092*4887Schin else 1093*4887Schin { 1094*4887Schin i = n - 1; 1095*4887Schin n = strtol(s, &t, 10); 1096*4887Schin s = t; 1097*4887Schin if (n <= 0 || n > 31) 1098*4887Schin break; 1099*4887Schin if (*s == '/' && !isdigit(*(s + 1))) 1100*4887Schin break; 1101*4887Schin } 1102*4887Schin state |= DAY; 1103*4887Schin tm->tm_mday = n; 1104*4887Schin } 1105*4887Schin state |= MONTH; 1106*4887Schin n = tm->tm_mon; 1107*4887Schin tm->tm_mon = i; 1108*4887Schin if (*s == '/') 1109*4887Schin { 1110*4887Schin n = strtol(++s, &t, 10); 1111*4887Schin w = t - s; 1112*4887Schin s = t; 1113*4887Schin if (*s == '/' || *s == ':' || *s == '-' || *s == '_') 1114*4887Schin s++; 1115*4887Schin } 1116*4887Schin else 1117*4887Schin { 1118*4887Schin if (state & (LAST|NEXT|THIS)) 1119*4887Schin { 1120*4887Schin rel_month: 1121*4887Schin if (state & LAST) 1122*4887Schin tm->tm_year -= (tm->tm_mon < n) ? 0 : 1; 1123*4887Schin else 1124*4887Schin tm->tm_year += ((state & NEXT) ? 1 : 0) + ((tm->tm_mon < n) ? 1 : 0); 1125*4887Schin if (state & MDAY) 1126*4887Schin goto clear_hour; 1127*4887Schin goto clear_mday; 1128*4887Schin } 1129*4887Schin continue; 1130*4887Schin } 1131*4887Schin } 1132*4887Schin if (n < 0 || w > 4) 1133*4887Schin break; 1134*4887Schin if (w == 4) 1135*4887Schin { 1136*4887Schin if ((state & YEAR) || n < 1900 || n >= 3000) 1137*4887Schin break; 1138*4887Schin state |= YEAR; 1139*4887Schin tm->tm_year = n - 1900; 1140*4887Schin } 1141*4887Schin else if (w == 3) 1142*4887Schin { 1143*4887Schin if (state & (MONTH|MDAY|WDAY)) 1144*4887Schin break; 1145*4887Schin state |= MONTH|DAY|MDAY; 1146*4887Schin tm->tm_mon = 0; 1147*4887Schin tm->tm_mday = n; 1148*4887Schin } 1149*4887Schin else if (w == 2 && !(state & YEAR)) 1150*4887Schin { 1151*4887Schin state |= YEAR; 1152*4887Schin if (n < TM_WINDOW) 1153*4887Schin n += 100; 1154*4887Schin tm->tm_year = n; 1155*4887Schin } 1156*4887Schin else if (!(state & MONTH) && n >= 1 && n <= 12) 1157*4887Schin { 1158*4887Schin state |= MONTH; 1159*4887Schin tm->tm_mon = n - 1; 1160*4887Schin } 1161*4887Schin else if (!(state & (MDAY|WDAY)) && n >= 1 && n <= 31) 1162*4887Schin { 1163*4887Schin state |= DAY|MDAY|WDAY; 1164*4887Schin tm->tm_mday = n; 1165*4887Schin } 1166*4887Schin else 1167*4887Schin break; 1168*4887Schin if (state & BREAK) 1169*4887Schin { 1170*4887Schin last = t; 1171*4887Schin break; 1172*4887Schin } 1173*4887Schin continue; 1174*4887Schin clear_mon: 1175*4887Schin if ((set|state) & (EXACT|MONTH)) 1176*4887Schin continue; 1177*4887Schin tm->tm_mon = 0; 1178*4887Schin clear_mday: 1179*4887Schin set |= MONTH; 1180*4887Schin if ((set|state) & (EXACT|DAY|HOUR)) 1181*4887Schin continue; 1182*4887Schin tm->tm_mday = 1; 1183*4887Schin clear_hour: 1184*4887Schin set |= DAY; 1185*4887Schin if ((set|state) & (EXACT|HOUR)) 1186*4887Schin continue; 1187*4887Schin tm->tm_hour = 0; 1188*4887Schin clear_min: 1189*4887Schin set |= HOUR; 1190*4887Schin if ((set|state) & (EXACT|MINUTE)) 1191*4887Schin continue; 1192*4887Schin tm->tm_min = 0; 1193*4887Schin clear_sec: 1194*4887Schin set |= MINUTE; 1195*4887Schin if ((set|state) & (EXACT|SECOND)) 1196*4887Schin continue; 1197*4887Schin tm->tm_sec = 0; 1198*4887Schin clear_nsec: 1199*4887Schin set |= SECOND; 1200*4887Schin if ((set|state) & (EXACT|NSEC)) 1201*4887Schin continue; 1202*4887Schin tm->tm_nsec = 0; 1203*4887Schin } 1204*4887Schin done: 1205*4887Schin if (day >= 0 && !(state & (MDAY|WDAY))) 1206*4887Schin { 1207*4887Schin if ((m = dir) > 0) 1208*4887Schin m--; 1209*4887Schin if (state & MONTH) 1210*4887Schin tm->tm_mday = 1; 1211*4887Schin else if (m < 0) 1212*4887Schin m++; 1213*4887Schin tm = tmxmake(tmxtime(tm, zone)); 1214*4887Schin j = day - tm->tm_wday; 1215*4887Schin if (j < 0) 1216*4887Schin j += 7; 1217*4887Schin tm->tm_mday += j + m * 7; 1218*4887Schin if (state & FINAL) 1219*4887Schin for (n = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year)); (tm->tm_mday + 7) <= n; tm->tm_mday += 7); 1220*4887Schin } 1221*4887Schin else if (day < 0 && (state & FINAL) && (set & DAY)) 1222*4887Schin tm->tm_mday = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year)); 1223*4887Schin if (e) 1224*4887Schin *e = last; 1225*4887Schin return tmxtime(tm, zone); 1226*4887Schin } 1227