Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libast/tm/tmxdate.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1985-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* David Korn <[email protected]> *
19
* Phong Vo <[email protected]> *
20
* *
21
***********************************************************************/
22
#pragma prototyped
23
/*
24
* Glenn Fowler
25
* AT&T Research
26
*
27
* Time_t conversion support
28
*
29
* relative times inspired by Steve Bellovin's netnews getdate(3)
30
*/
31
32
#include <tmx.h>
33
#include <ctype.h>
34
#include <debug.h>
35
36
#define dig1(s,n) ((n)=((*(s)++)-'0'))
37
#define dig2(s,n) ((n)=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0')
38
#define dig3(s,n) ((n)=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0')
39
#define dig4(s,n) ((n)=((*(s)++)-'0')*1000,(n)+=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0')
40
41
#undef BREAK
42
43
#define BREAK (1<<0)
44
#define CCYYMMDDHHMMSS (1<<1)
45
#define CRON (1<<2)
46
#define DAY (1<<3)
47
#define EXACT (1<<4)
48
#define FINAL (1<<5)
49
#define HOLD (1<<6)
50
#define HOUR (1<<7)
51
#define LAST (1<<8)
52
#define MDAY (1<<9)
53
#define MINUTE (1<<10)
54
#define MONTH (1<<11)
55
#define NEXT (1<<12)
56
#define NSEC (1<<13)
57
#define ORDINAL (1<<14)
58
#define SECOND (1<<15)
59
#define THIS (1L<<16)
60
#define WDAY (1L<<17)
61
#define WORK (1L<<18)
62
#define YEAR (1L<<19)
63
#define ZONE (1L<<20)
64
65
#define FFMT "%s%s%s%s%s%s%s|"
66
#define FLAGS(f) (f&EXACT)?"|EXACT":"",(f&LAST)?"|LAST":"",(f&THIS)?"|THIS":"",(f&NEXT)?"|NEXT":"",(f&ORDINAL)?"|ORDINAL":"",(f&FINAL)?"|FINAL":"",(f&WORK)?"|WORK":""
67
/*
68
* parse cron range into set
69
* return: -1:error 0:* 1:some
70
*/
71
72
static int
73
range(register char* s, char** e, char* set, int lo, int hi)
74
{
75
int n;
76
int m;
77
int i;
78
char* t;
79
80
while (isspace(*s) || *s == '_')
81
s++;
82
if (*s == '*')
83
{
84
*e = s + 1;
85
return 0;
86
}
87
memset(set, 0, hi + 1);
88
for (;;)
89
{
90
n = strtol(s, &t, 10);
91
if (s == t || n < lo || n > hi)
92
return -1;
93
i = 1;
94
if (*(s = t) == '-')
95
{
96
m = strtol(++s, &t, 10);
97
if (s == t || m < n || m > hi)
98
return -1;
99
if (*(s = t) == '/')
100
{
101
i = strtol(++s, &t, 10);
102
if (s == t || i < 1)
103
return -1;
104
s = t;
105
}
106
}
107
else
108
m = n;
109
for (; n <= m; n += i)
110
set[n] = 1;
111
if (*s != ',')
112
break;
113
s++;
114
}
115
*e = s;
116
return 1;
117
}
118
119
/*
120
* normalize <p,q> to power of 10 u in tm
121
*/
122
123
static void
124
powerize(Tm_t* tm, unsigned long p, unsigned long q, unsigned long u)
125
{
126
Time_t t = p;
127
128
while (q > u)
129
{
130
q /= 10;
131
t /= 10;
132
}
133
while (q < u)
134
{
135
q *= 10;
136
t *= 10;
137
}
138
tm->tm_nsec += (int)(t % TMX_RESOLUTION);
139
tm->tm_sec += (int)(t / TMX_RESOLUTION);
140
}
141
142
#define K1(c1) (c1)
143
#define K2(c1,c2) (((c1)<<8)|(c2))
144
#define K3(c1,c2,c3) (((c1)<<16)|((c2)<<8)|(c3))
145
#define K4(c1,c2,c3,c4) (((c1)<<24)|((c2)<<16)|((c3)<<8)|(c4))
146
147
#define P_INIT(n) w = n; p = q = 0; u = (char*)s + 1
148
149
/*
150
* parse date expression in s and return Time_t value
151
*
152
* if non-null, e points to the first invalid sequence in s
153
* now provides default values
154
*/
155
156
Time_t
157
tmxdate(register const char* s, char** e, Time_t now)
158
{
159
register Tm_t* tm;
160
register long n;
161
register int w;
162
unsigned long set;
163
unsigned long state;
164
unsigned long flags;
165
Time_t fix;
166
char* t;
167
char* u;
168
const char* o;
169
const char* x;
170
char* last;
171
char* type;
172
int day;
173
int dir;
174
int dst;
175
int zone;
176
int c;
177
int f;
178
int i;
179
int j;
180
int k;
181
int l;
182
long m;
183
unsigned long p;
184
unsigned long q;
185
Tm_zone_t* zp;
186
Tm_t ts;
187
char skip[UCHAR_MAX + 1];
188
189
/*
190
* check DATEMSK first
191
*/
192
193
debug((error(-1, "AHA tmxdate 2009-03-06")));
194
fix = tmxscan(s, &last, NiL, &t, now, 0);
195
if (t && !*last)
196
{
197
if (e)
198
*e = last;
199
return fix;
200
}
201
o = s;
202
203
reset:
204
205
/*
206
* use now for defaults
207
*/
208
209
tm = tmxtm(&ts, now, NiL);
210
tm_info.date = tm->tm_zone;
211
day = -1;
212
dir = 0;
213
dst = TM_DST;
214
set = state = 0;
215
type = 0;
216
zone = TM_LOCALZONE;
217
skip[0] = 0;
218
for (n = 1; n <= UCHAR_MAX; n++)
219
skip[n] = isspace(n) || strchr("_,;@=|!^()[]{}", n);
220
221
/*
222
* get <weekday year month day hour minutes seconds ?[ds]t [ap]m>
223
*/
224
225
again:
226
for (;;)
227
{
228
state &= (state & HOLD) ? ~(HOLD) : ~(EXACT|LAST|NEXT|THIS);
229
if ((set|state) & (YEAR|MONTH|DAY))
230
skip['/'] = 1;
231
message((-1, "AHA#%d state=" FFMT " set=" FFMT, __LINE__, FLAGS(state), FLAGS(set)));
232
for (;;)
233
{
234
if (*s == '.' || *s == '-' || *s == '+')
235
{
236
if (((set|state) & (YEAR|MONTH|HOUR|MINUTE|ZONE)) == (YEAR|MONTH|HOUR|MINUTE) && (i = tmgoff(s, &t, TM_LOCALZONE)) != TM_LOCALZONE)
237
{
238
zone = i;
239
state |= ZONE;
240
if (!*(s = t))
241
break;
242
}
243
else if (*s == '+')
244
break;
245
}
246
else if (!skip[*s])
247
break;
248
s++;
249
}
250
if (!*(last = (char*)s))
251
break;
252
if (*s == '#')
253
{
254
if (isdigit(*++s))
255
{
256
now = strtoull(s, &t, 0);
257
sns:
258
if (*(s = t) == '.')
259
{
260
fix = 0;
261
m = 1000000000;
262
while (isdigit(*++s))
263
fix += (*s - '0') * (m /= 10);
264
now = tmxsns(now, fix);
265
}
266
else if (now <= 0x7fffffff)
267
now = tmxsns(now, 0);
268
goto reset;
269
}
270
else if (*s++ == '#')
271
{
272
now = tmxtime(tm, zone);
273
goto reset;
274
}
275
break;
276
}
277
if ((*s == 'P' || *s == 'p') && (!isalpha(*(s + 1)) || (*(s + 1) == 'T' || *(s + 1) == 't') && !isalpha(*(s + 2))))
278
{
279
Tm_t otm;
280
281
/*
282
* iso duration
283
*/
284
285
otm = *tm;
286
t = (char*)s;
287
m = 0;
288
P_INIT('Y');
289
do
290
{
291
c = *++s;
292
duration_next:
293
switch (c)
294
{
295
case 0:
296
m++;
297
if ((char*)s > u)
298
{
299
s--;
300
c = '_';
301
goto duration_next;
302
}
303
break;
304
case 'T':
305
case 't':
306
m++;
307
if ((char*)s > u)
308
{
309
s++;
310
c = 'D';
311
goto duration_next;
312
}
313
continue;
314
case 'Y':
315
case 'y':
316
m = 0;
317
if (q > 1)
318
tm->tm_sec += (365L*24L*60L*60L) * p / q;
319
else
320
tm->tm_year += p;
321
P_INIT('M');
322
continue;
323
case 'm':
324
if (!m)
325
m = 1;
326
/*FALLTHROUGH*/
327
case 'M':
328
switch (*(s + 1))
329
{
330
case 'I':
331
case 'i':
332
s++;
333
m = 1;
334
w = 'S';
335
break;
336
case 'O':
337
case 'o':
338
s++;
339
m = 0;
340
w = 'H';
341
break;
342
case 'S':
343
case 's':
344
s++;
345
m = 2;
346
w = 's';
347
break;
348
}
349
switch (m)
350
{
351
case 0:
352
m = 1;
353
if (q > 1)
354
tm->tm_sec += (3042L*24L*60L*60L) * p / q / 100L;
355
else
356
tm->tm_mon += p;
357
break;
358
case 1:
359
m = 2;
360
if (q > 1)
361
tm->tm_sec += (60L) * p / q;
362
else
363
tm->tm_min += p;
364
break;
365
default:
366
if (q > 1)
367
powerize(tm, p, q, 1000UL);
368
else
369
tm->tm_nsec += p * 1000000L;
370
break;
371
}
372
P_INIT(w);
373
continue;
374
case 'W':
375
case 'w':
376
m = 0;
377
if (q > 1)
378
tm->tm_sec += (7L*24L*60L*60L) * p / q;
379
else
380
tm->tm_mday += 7 * p;
381
P_INIT('D');
382
continue;
383
case 'D':
384
case 'd':
385
m = 0;
386
if (q > 1)
387
tm->tm_sec += (24L*60L*60L) * p / q;
388
else
389
tm->tm_mday += p;
390
P_INIT('H');
391
continue;
392
case 'H':
393
case 'h':
394
m = 1;
395
if (q > 1)
396
tm->tm_sec += (60L*60L) * p / q;
397
else
398
tm->tm_hour += p;
399
P_INIT('m');
400
continue;
401
case 'S':
402
case 's':
403
m = 2;
404
/*FALLTHROUGH*/
405
case ' ':
406
case '_':
407
case '\n':
408
case '\r':
409
case '\t':
410
case '\v':
411
if (q > 1)
412
powerize(tm, p, q, 1000000000UL);
413
else
414
tm->tm_sec += p;
415
P_INIT('U');
416
continue;
417
case 'U':
418
case 'u':
419
switch (*(s + 1))
420
{
421
case 'S':
422
case 's':
423
s++;
424
break;
425
}
426
m = 0;
427
if (q > 1)
428
powerize(tm, p, q, 1000000UL);
429
else
430
tm->tm_nsec += p * 1000L;
431
P_INIT('N');
432
continue;
433
case 'N':
434
case 'n':
435
switch (*(s + 1))
436
{
437
case 'S':
438
case 's':
439
s++;
440
break;
441
}
442
m = 0;
443
if (q > 1)
444
powerize(tm, p, q, 1000000000UL);
445
else
446
tm->tm_nsec += p;
447
P_INIT('Y');
448
continue;
449
case '.':
450
if (q)
451
goto exact;
452
q = 1;
453
continue;
454
case '-':
455
c = 'M';
456
u = (char*)s++;
457
while (*++u && *u != ':')
458
if (*u == '-')
459
{
460
c = 'Y';
461
break;
462
}
463
goto duration_next;
464
case ':':
465
c = 'm';
466
u = (char*)s++;
467
while (*++u)
468
if (*u == ':')
469
{
470
c = 'H';
471
break;
472
}
473
goto duration_next;
474
case '0':
475
case '1':
476
case '2':
477
case '3':
478
case '4':
479
case '5':
480
case '6':
481
case '7':
482
case '8':
483
case '9':
484
q *= 10;
485
p = p * 10 + (c - '0');
486
continue;
487
default:
488
exact:
489
*tm = otm;
490
s = (const char*)t + 1;
491
if (*t == 'p')
492
{
493
state |= HOLD|EXACT;
494
set &= ~(EXACT|LAST|NEXT|THIS);
495
set |= state & (EXACT|LAST|NEXT|THIS);
496
}
497
goto again;
498
}
499
break;
500
} while (c);
501
continue;
502
}
503
f = -1;
504
if (*s == '+')
505
{
506
while (isspace(*++s) || *s == '_');
507
n = strtol(s, &t, 0);
508
if (w = t - s)
509
{
510
for (s = t; skip[*s]; s++);
511
state |= (f = n) ? NEXT : THIS;
512
set &= ~(EXACT|LAST|NEXT|THIS);
513
set |= state & (EXACT|LAST|NEXT|THIS);
514
}
515
else
516
s = last;
517
}
518
if (!(state & CRON))
519
{
520
/*
521
* check for cron date
522
*
523
* min hour day-of-month month day-of-week
524
*
525
* if it's cron then determine the next time
526
* that satisfies the specification
527
*
528
* NOTE: the only spacing is ' '||'_'||';'
529
*/
530
531
i = 0;
532
n = *(t = (char*)s);
533
for (;;)
534
{
535
if (n == '*')
536
n = *++s;
537
else if (!isdigit(n))
538
break;
539
else
540
while ((n = *++s) == ',' || n == '-' || n == '/' || isdigit(n));
541
if (n != ' ' && n != '_' && n != ';')
542
{
543
if (!n)
544
i++;
545
break;
546
}
547
i++;
548
while ((n = *++s) == ' ' || n == '_');
549
}
550
if (i == 5)
551
{
552
Time_t tt;
553
char hit[60];
554
char mon[13];
555
char day[7];
556
557
state |= CRON;
558
flags = 0;
559
tm->tm_sec = 0;
560
tm->tm_min++;
561
tmfix(tm);
562
563
/*
564
* minute
565
*/
566
567
if ((k = range(t, &t, hit, 0, 59)) < 0)
568
break;
569
if (k && !hit[i = tm->tm_min])
570
{
571
hit[i] = 1;
572
do if (++i > 59)
573
{
574
i = 0;
575
if (++tm->tm_hour > 59)
576
{
577
tm->tm_min = i;
578
tmfix(tm);
579
}
580
} while (!hit[i]);
581
tm->tm_min = i;
582
}
583
584
/*
585
* hour
586
*/
587
588
if ((k = range(t, &t, hit, 0, 23)) < 0)
589
break;
590
if (k && !hit[i = tm->tm_hour])
591
{
592
hit[i] = 1;
593
do if (++i > 23)
594
{
595
i = 0;
596
if (++tm->tm_mday > 28)
597
{
598
tm->tm_hour = i;
599
tmfix(tm);
600
}
601
} while (!hit[i]);
602
tm->tm_hour = i;
603
}
604
605
/*
606
* day of month
607
*/
608
609
if ((k = range(t, &t, hit, 1, 31)) < 0)
610
break;
611
if (k)
612
flags |= DAY|MDAY;
613
614
/*
615
* month
616
*/
617
618
if ((k = range(t, &t, mon, 1, 12)) < 0)
619
break;
620
if (k)
621
flags |= MONTH;
622
else
623
for (i = 1; i <= 12; i++)
624
mon[i] = 1;
625
626
/*
627
* day of week
628
*/
629
630
if ((k = range(t, &t, day, 0, 6)) < 0)
631
break;
632
if (k)
633
flags |= WDAY;
634
s = t;
635
if (flags & (MONTH|MDAY|WDAY))
636
{
637
fix = tmxtime(tm, zone);
638
tm = tmxtm(tm, fix, tm->tm_zone);
639
i = tm->tm_mon + 1;
640
j = tm->tm_mday;
641
k = tm->tm_wday;
642
for (;;)
643
{
644
if (!mon[i])
645
{
646
if (++i > 12)
647
{
648
i = 1;
649
tm->tm_year++;
650
}
651
tm->tm_mon = i - 1;
652
tm->tm_mday = 1;
653
tt = tmxtime(tm, zone);
654
if (tt < fix)
655
goto done;
656
tm = tmxtm(tm, tt, tm->tm_zone);
657
i = tm->tm_mon + 1;
658
j = tm->tm_mday;
659
k = tm->tm_wday;
660
continue;
661
}
662
if (flags & (MDAY|WDAY))
663
{
664
if ((flags & (MDAY|WDAY)) == (MDAY|WDAY))
665
{
666
if (hit[j] && day[k])
667
break;
668
}
669
else if ((flags & MDAY) && hit[j])
670
break;
671
else if ((flags & WDAY) && day[k])
672
break;
673
if (++j > 28)
674
{
675
tm->tm_mon = i - 1;
676
tm->tm_mday = j;
677
tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone);
678
i = tm->tm_mon + 1;
679
j = tm->tm_mday;
680
k = tm->tm_wday;
681
}
682
else if ((flags & WDAY) && ++k > 6)
683
k = 0;
684
}
685
else if (flags & MONTH)
686
break;
687
}
688
tm->tm_mon = i - 1;
689
tm->tm_mday = j;
690
tm->tm_wday = k;
691
}
692
continue;
693
}
694
s = t;
695
}
696
n = -1;
697
if (isdigit(*s))
698
{
699
n = strtol(s, &t, 10);
700
if ((w = t - s) && *t == '.' && isdigit(*(t + 1)) && isdigit(*(t + 2)) && isdigit(*(t + 3)))
701
{
702
now = n;
703
goto sns;
704
}
705
if ((*t == 'T' || *t == 't') && ((set|state) & (YEAR|MONTH|DAY)) == (YEAR|MONTH) && isdigit(*(t + 1)))
706
t++;
707
u = t + (*t == '-');
708
message((-1, "AHA#%d n=%d w=%d u='%c' f=%d t=\"%s\"", __LINE__, n, w, *u, f, t));
709
if ((w == 2 || w == 4) && (*u == 'W' || *u == 'w') && isdigit(*(u + 1)))
710
{
711
if (w == 4)
712
{
713
if ((n -= 1900) < TM_WINDOW)
714
break;
715
}
716
else if (n < TM_WINDOW)
717
n += 100;
718
m = n;
719
n = strtol(++u, &t, 10);
720
if ((i = (t - u)) < 2 || i > 3)
721
break;
722
if (i == 3)
723
{
724
k = n % 10;
725
n /= 10;
726
}
727
else if (*t != '-')
728
k = 1;
729
else if (*++t && dig1(t, k) < 1 || k > 7)
730
break;
731
if (n < 0 || n > 53)
732
break;
733
if (k == 7)
734
k = 0;
735
tm->tm_year = m;
736
tmweek(tm, 2, n, k);
737
set |= YEAR|MONTH|DAY;
738
s = t;
739
continue;
740
}
741
else if (w == 6 || w == 8 && (n / 1000000) > 12)
742
{
743
t = (char*)s;
744
flags = 0;
745
if (w == 8 || w == 6 && *u != 'T' && *u != 't')
746
{
747
dig4(t, m);
748
if ((m -= 1900) < TM_WINDOW)
749
break;
750
}
751
else
752
{
753
dig2(t, m);
754
if (m < TM_WINDOW)
755
m += 100;
756
}
757
flags |= YEAR;
758
if (dig2(t, l) <= 0 || l > 12)
759
break;
760
flags |= MONTH;
761
if (*t != 'T' && *t != 't' || !isdigit(*++t))
762
{
763
if (w == 6)
764
goto save_yymm;
765
if (dig2(t, k) < 1 || k > 31)
766
break;
767
flags |= DAY;
768
goto save_yymmdd;
769
}
770
n = strtol(s = t, &t, 0);
771
if ((t - s) < 2)
772
break;
773
if (dig2(s, j) > 24)
774
break;
775
if ((t - s) < 2)
776
{
777
if ((t - s) == 1 || *t++ != '-')
778
break;
779
n = strtol(s = t, &t, 0);
780
if ((t - s) < 2)
781
break;
782
}
783
if (dig2(s, i) > 59)
784
break;
785
flags |= HOUR|MINUTE;
786
if ((t - s) == 2)
787
{
788
if (dig2(s, n) > (59 + TM_MAXLEAP))
789
break;
790
flags |= SECOND;
791
}
792
else if (t - s)
793
break;
794
else
795
n = 0;
796
p = 0;
797
if (*t == '.')
798
{
799
q = 1000000000;
800
while (isdigit(*++t))
801
p += (*t - '0') * (q /= 10);
802
set |= NSEC;
803
}
804
if (n > (59 + TM_MAXLEAP))
805
break;
806
goto save;
807
}
808
else if (f == -1 && isalpha(*t) && tmlex(t, &t, tm_info.format + TM_ORDINAL, TM_ORDINALS - TM_ORDINAL, NiL, 0) >= 0)
809
{
810
message((-1, "AHA#%d n=%d", __LINE__, n));
811
ordinal:
812
if (n)
813
n--;
814
message((-1, "AHA#%d n=%d", __LINE__, n));
815
state |= ((f = n) ? NEXT : THIS)|ORDINAL;
816
set &= ~(EXACT|LAST|NEXT|THIS);
817
set |= state & (EXACT|LAST|NEXT|THIS);
818
for (s = t; skip[*s]; s++);
819
if (isdigit(*s))
820
{
821
if (n = strtol(s, &t, 10))
822
n--;
823
s = t;
824
if (*s == '_')
825
s++;
826
}
827
else
828
n = -1;
829
dir = f;
830
message((-1, "AHA#%d f=%d n=%d state=" FFMT, __LINE__, f, n, FLAGS(state)));
831
}
832
else
833
{
834
for (u = t; isspace(*u); u++);
835
message((-1, "AHA#%d n=%d u=\"%s\"", __LINE__, n, u));
836
if ((j = tmlex(u, NiL, tm_info.format, TM_NFORM, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES)) >= 0 && tm_data.lex[j] == TM_PARTS)
837
s = u;
838
else
839
{
840
message((-1, "AHA#%d t=\"%s\"", __LINE__, t));
841
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))
842
{
843
/*
844
* various { date(1) touch(1) } formats
845
*
846
* [[cc]yy[mm]]ddhhmm[.ss[.nn...]]
847
* [cc]yyjjj
848
* hhmm[.ss[.nn...]]
849
*/
850
851
message((-1, "AHA#%d t=\"%s\"", __LINE__, t));
852
flags = 0;
853
if (state & CCYYMMDDHHMMSS)
854
break;
855
state |= CCYYMMDDHHMMSS;
856
p = 0;
857
if ((i == 7 || i == 5) && (!*t || *t == 'Z' || *t == 'z'))
858
{
859
if (i == 7)
860
{
861
dig4(s, m);
862
if ((m -= 1900) < TM_WINDOW)
863
break;
864
}
865
else if (dig2(s, m) < TM_WINDOW)
866
m += 100;
867
dig3(s, k);
868
l = 1;
869
j = 0;
870
i = 0;
871
n = 0;
872
flags |= MONTH;
873
}
874
else if (i & 1)
875
break;
876
else
877
{
878
u = t;
879
if (i == 12)
880
{
881
x = s;
882
dig2(x, m);
883
if (m <= 12)
884
{
885
u -= 4;
886
i -= 4;
887
x = s + 8;
888
dig4(x, m);
889
}
890
else
891
dig4(s, m);
892
if (m < 1969 || m >= 3000)
893
break;
894
m -= 1900;
895
}
896
else if (i == 10)
897
{
898
x = s;
899
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))
900
dig2(s, m);
901
else
902
{
903
u -= 2;
904
i -= 2;
905
x = s + 8;
906
dig2(x, m);
907
}
908
if (m < TM_WINDOW)
909
m += 100;
910
}
911
else
912
m = tm->tm_year;
913
if ((u - s) < 8)
914
l = tm->tm_mon + 1;
915
else if (dig2(s, l) <= 0 || l > 12)
916
break;
917
else
918
flags |= MONTH;
919
if ((u - s) < 6)
920
k = tm->tm_mday;
921
else if (dig2(s, k) < 1 || k > 31)
922
break;
923
else
924
flags |= DAY;
925
if ((u - s) < 4)
926
break;
927
if (dig2(s, j) > 24)
928
break;
929
if (dig2(s, i) > 59)
930
break;
931
flags |= HOUR|MINUTE;
932
if ((u - s) == 2)
933
{
934
dig2(s, n);
935
flags |= SECOND;
936
}
937
else if (u - s)
938
break;
939
else if (*t != '.')
940
n = 0;
941
else
942
{
943
n = strtol(t + 1, &t, 10);
944
flags |= SECOND;
945
if (*t == '.')
946
{
947
q = 1000000000;
948
while (isdigit(*++t))
949
p += (*t - '0') * (q /= 10);
950
set |= NSEC;
951
}
952
}
953
if (n > (59 + TM_MAXLEAP))
954
break;
955
}
956
save:
957
tm->tm_hour = j;
958
tm->tm_min = i;
959
tm->tm_sec = n;
960
tm->tm_nsec = p;
961
save_yymmdd:
962
tm->tm_mday = k;
963
save_yymm:
964
tm->tm_mon = l - 1;
965
tm->tm_year = m;
966
s = t;
967
set |= flags;
968
continue;
969
}
970
for (s = t; skip[*s]; s++);
971
message((-1, "AHA#%d s=\"%s\"", __LINE__, s));
972
if (*s == ':' || *s == '.' && ((set|state) & (YEAR|MONTH|DAY|HOUR)) == (YEAR|MONTH|DAY))
973
{
974
c = *s;
975
if ((state & HOUR) || n > 24)
976
break;
977
while (isspace(*++s) || *s == '_');
978
if (!isdigit(*s))
979
break;
980
i = n;
981
n = strtol(s, &t, 10);
982
for (s = t; isspace(*s) || *s == '_'; s++);
983
if (n > 59)
984
break;
985
j = n;
986
m = 0;
987
if (*s == c)
988
{
989
while (isspace(*++s) || *s == '_');
990
if (!isdigit(*s))
991
break;
992
n = strtol(s, &t, 10);
993
s = t;
994
if (n > (59 + TM_MAXLEAP))
995
break;
996
set |= SECOND;
997
while (isspace(*s))
998
s++;
999
if (*s == '.')
1000
{
1001
q = 1000000000;
1002
while (isdigit(*++s))
1003
m += (*s - '0') * (q /= 10);
1004
set |= NSEC;
1005
}
1006
}
1007
else
1008
n = 0;
1009
set |= HOUR|MINUTE;
1010
skip[':'] = 1;
1011
k = tm->tm_hour;
1012
tm->tm_hour = i;
1013
l = tm->tm_min;
1014
tm->tm_min = j;
1015
tm->tm_sec = n;
1016
tm->tm_nsec = m;
1017
while (isspace(*s))
1018
s++;
1019
switch (tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_MERIDIAN, 2))
1020
{
1021
case TM_MERIDIAN:
1022
s = t;
1023
if (i == 12)
1024
tm->tm_hour = i = 0;
1025
break;
1026
case TM_MERIDIAN+1:
1027
if (i < 12)
1028
tm->tm_hour = i += 12;
1029
break;
1030
}
1031
if (f >= 0 || (state & (LAST|NEXT)))
1032
{
1033
message((-1, "AHA#%d f=%d i=%d j=%d k=%d l=%d", __LINE__, f, i, j, k, l));
1034
state &= ~HOLD;
1035
if (f < 0)
1036
{
1037
if (state & LAST)
1038
f = -1;
1039
else if (state & NEXT)
1040
f = 1;
1041
else
1042
f = 0;
1043
}
1044
if (f > 0)
1045
{
1046
if (i > k || i == k && j > l)
1047
f--;
1048
}
1049
else if (i < k || i == k && j < l)
1050
f++;
1051
if (f > 0)
1052
{
1053
tm->tm_hour += f * 24;
1054
while (tm->tm_hour >= 24)
1055
{
1056
tm->tm_hour -= 24;
1057
tm->tm_mday++;
1058
}
1059
}
1060
else if (f < 0)
1061
{
1062
tm->tm_hour += f * 24;
1063
while (tm->tm_hour < 24)
1064
{
1065
tm->tm_hour += 24;
1066
tm->tm_mday--;
1067
}
1068
}
1069
}
1070
continue;
1071
}
1072
}
1073
}
1074
}
1075
for (;;)
1076
{
1077
message((-1, "AHA#%d s=\"%s\"", __LINE__, s));
1078
if (*s == '-' || *s == '+')
1079
{
1080
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))))
1081
break;
1082
s++;
1083
}
1084
else if (skip[*s])
1085
s++;
1086
else
1087
break;
1088
}
1089
if (isalpha(*s))
1090
{
1091
if (n > 0)
1092
{
1093
x = s;
1094
q = *s++;
1095
message((-1, "AHA#%d n=%d q='%c'", __LINE__, n, q));
1096
if (isalpha(*s))
1097
{
1098
q <<= 8;
1099
q |= *s++;
1100
if (isalpha(*s))
1101
{
1102
if (tmlex(s, &t, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES, NiL, 0) >= 0)
1103
s = t;
1104
if (isalpha(*s))
1105
{
1106
q <<= 8;
1107
q |= *s++;
1108
if (isalpha(*s))
1109
{
1110
q <<= 8;
1111
q |= *s++;
1112
if (isalpha(*s))
1113
q = 0;
1114
}
1115
}
1116
}
1117
}
1118
switch (q)
1119
{
1120
case K1('y'):
1121
case K1('Y'):
1122
case K2('y','r'):
1123
case K2('Y','R'):
1124
tm->tm_year += n;
1125
set |= YEAR;
1126
continue;
1127
case K1('M'):
1128
case K2('m','o'):
1129
case K2('M','O'):
1130
tm->tm_mon += n;
1131
set |= MONTH;
1132
continue;
1133
case K1('w'):
1134
case K1('W'):
1135
case K2('w','k'):
1136
case K2('W','K'):
1137
tm->tm_mday += n * 7;
1138
set |= DAY;
1139
continue;
1140
case K1('d'):
1141
case K1('D'):
1142
case K2('d','a'):
1143
case K2('d','y'):
1144
case K2('D','A'):
1145
case K2('D','Y'):
1146
tm->tm_mday += n;
1147
set |= DAY;
1148
continue;
1149
case K1('h'):
1150
case K1('H'):
1151
case K2('h','r'):
1152
case K2('H','R'):
1153
tm->tm_hour += n;
1154
set |= HOUR;
1155
continue;
1156
case K1('m'):
1157
case K2('m','n'):
1158
case K2('M','N'):
1159
tm->tm_min += n;
1160
set |= MINUTE;
1161
continue;
1162
case K1('s'):
1163
case K2('s','c'):
1164
case K1('S'):
1165
case K2('S','C'):
1166
tm->tm_sec += n;
1167
set |= SECOND;
1168
continue;
1169
case K2('m','s'):
1170
case K3('m','s','c'):
1171
case K4('m','s','e','c'):
1172
case K2('M','S'):
1173
case K3('M','S','C'):
1174
case K4('M','S','E','C'):
1175
tm->tm_nsec += n * 1000000L;
1176
continue;
1177
case K1('u'):
1178
case K2('u','s'):
1179
case K3('u','s','c'):
1180
case K4('u','s','e','c'):
1181
case K1('U'):
1182
case K2('U','S'):
1183
case K3('U','S','C'):
1184
case K4('U','S','E','C'):
1185
tm->tm_nsec += n * 1000L;
1186
continue;
1187
case K2('n','s'):
1188
case K3('n','s','c'):
1189
case K4('n','s','e','c'):
1190
case K2('N','S'):
1191
case K3('N','S','C'):
1192
case K4('N','S','E','C'):
1193
tm->tm_nsec += n;
1194
continue;
1195
}
1196
s = x;
1197
}
1198
if ((j = tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES)) >= 0)
1199
{
1200
if (tm_data.lex[j] == TM_PARTS || n < 1000)
1201
{
1202
s = t;
1203
switch (tm_data.lex[j])
1204
{
1205
case TM_EXACT:
1206
state |= HOLD|EXACT;
1207
set &= ~(EXACT|LAST|NEXT|THIS);
1208
set |= state & (EXACT|LAST|NEXT|THIS);
1209
continue;
1210
case TM_LAST:
1211
state |= HOLD|LAST;
1212
set &= ~(EXACT|LAST|NEXT|THIS);
1213
set |= state & (EXACT|LAST|NEXT|THIS);
1214
continue;
1215
case TM_THIS:
1216
state |= HOLD|THIS;
1217
set &= ~(EXACT|LAST|NEXT|THIS);
1218
set |= state & (EXACT|LAST|NEXT|THIS);
1219
n = 0;
1220
continue;
1221
case TM_NEXT:
1222
/*
1223
* disambiguate english "last ... in"
1224
*/
1225
1226
if (!((state|set) & LAST))
1227
{
1228
state |= HOLD|NEXT;
1229
set &= ~(EXACT|LAST|NEXT|THIS);
1230
set |= state & (EXACT|LAST|NEXT|THIS);
1231
continue;
1232
}
1233
/*FALLTHROUGH*/
1234
case TM_FINAL:
1235
state |= HOLD|THIS|FINAL;
1236
set &= ~(EXACT|LAST|NEXT|THIS);
1237
set |= state & (EXACT|LAST|NEXT|THIS|FINAL);
1238
continue;
1239
case TM_WORK:
1240
message((-1, "AHA#%d WORK", __LINE__));
1241
state |= WORK;
1242
set |= DAY;
1243
if (state & LAST)
1244
{
1245
state &= ~LAST;
1246
set &= ~LAST;
1247
state |= FINAL;
1248
set |= FINAL;
1249
}
1250
goto clear_hour;
1251
case TM_ORDINAL:
1252
j += TM_ORDINALS - TM_ORDINAL;
1253
message((-1, "AHA#%d j=%d", __LINE__, j));
1254
/*FALLTHROUGH*/
1255
case TM_ORDINALS:
1256
n = j - TM_ORDINALS + 1;
1257
message((-1, "AHA#%d n=%d", __LINE__, n));
1258
goto ordinal;
1259
case TM_MERIDIAN:
1260
if (f >= 0)
1261
f++;
1262
else if (state & LAST)
1263
f = -1;
1264
else if (state & THIS)
1265
f = 1;
1266
else if (state & NEXT)
1267
f = 2;
1268
else
1269
f = 0;
1270
if (n > 0)
1271
{
1272
if (n > 24)
1273
goto done;
1274
tm->tm_hour = n;
1275
}
1276
for (k = tm->tm_hour; k < 0; k += 24);
1277
k %= 24;
1278
if (j == TM_MERIDIAN)
1279
{
1280
if (k == 12)
1281
tm->tm_hour -= 12;
1282
}
1283
else if (k < 12)
1284
tm->tm_hour += 12;
1285
if (n > 0)
1286
goto clear_min;
1287
continue;
1288
case TM_DAY_ABBREV:
1289
j += TM_DAY - TM_DAY_ABBREV;
1290
/*FALLTHROUGH*/
1291
case TM_DAY:
1292
case TM_PARTS:
1293
case TM_HOURS:
1294
state |= set & (EXACT|LAST|NEXT|THIS);
1295
if (!(state & (LAST|NEXT|THIS)))
1296
for (;;)
1297
{
1298
while (skip[*s])
1299
s++;
1300
if ((k = tmlex(s, &t, tm_info.format + TM_LAST, TM_NOISE - TM_LAST, NiL, 0)) >= 0)
1301
{
1302
s = t;
1303
if (k <= 2)
1304
state |= LAST;
1305
else if (k <= 5)
1306
state |= THIS;
1307
else if (k <= 8)
1308
state |= NEXT;
1309
else
1310
state |= EXACT;
1311
}
1312
else
1313
{
1314
state |= (n > 0) ? NEXT : THIS;
1315
break;
1316
}
1317
set &= ~(EXACT|LAST|NEXT|THIS);
1318
set |= state & (EXACT|LAST|NEXT|THIS);
1319
}
1320
/*FALLTHROUGH*/
1321
case TM_DAYS:
1322
message((-1, "AHA#%d n=%d j=%d f=%d state=" FFMT, __LINE__, n, j, f, FLAGS(state)));
1323
if (n == -1)
1324
{
1325
/*
1326
* disambiguate english "second"
1327
*/
1328
1329
if (j == TM_PARTS && f == -1)
1330
{
1331
state &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/
1332
n = 2;
1333
goto ordinal;
1334
}
1335
n = 1;
1336
}
1337
1338
/*
1339
* disambiguate "last" vs. { "previous" "final" }
1340
*/
1341
1342
while (isspace(*s))
1343
s++;
1344
message((-1, "AHA#%d disambiguate LAST s='%s'", __LINE__, s));
1345
if ((k = tmlex(s, &t, tm_info.format + TM_NEXT, TM_EXACT - TM_NEXT, NiL, 0)) >= 0 || (k = tmlex(s, &t, tm_info.format + TM_PARTS + 3, 1, NiL, 0)) >= 0)
1346
{
1347
s = t;
1348
if (state & LAST)
1349
{
1350
state &= ~LAST;
1351
set &= ~LAST;
1352
state |= FINAL;
1353
set |= FINAL;
1354
message((-1, "AHA#%d LAST => FINAL", __LINE__));
1355
}
1356
else
1357
state &= ~(THIS|NEXT);
1358
}
1359
message((-1, "AHA#%d disambiguate LAST k=%d", __LINE__, k));
1360
if (state & LAST)
1361
n = -n;
1362
else if (!(state & NEXT))
1363
n--;
1364
m = (f > 0) ? f * n : n;
1365
message((-1, "AHA#%d f=%d n=%d i=%d j=%d k=%d l=%d m=%d state=" FFMT, __LINE__, f, n, i, j, k, l, m, FLAGS(state)));
1366
switch (j)
1367
{
1368
case TM_DAYS+0:
1369
tm->tm_mday--;
1370
set |= DAY;
1371
goto clear_hour;
1372
case TM_DAYS+1:
1373
set |= DAY;
1374
goto clear_hour;
1375
case TM_DAYS+2:
1376
tm->tm_mday++;
1377
set |= DAY;
1378
goto clear_hour;
1379
case TM_PARTS+0:
1380
set |= SECOND;
1381
if ((m < 0 ? -m : m) > (365L*24L*60L*60L))
1382
{
1383
now = tmxtime(tm, zone) + tmxsns(m, 0);
1384
goto reset;
1385
}
1386
tm->tm_sec += m;
1387
goto clear_nsec;
1388
case TM_PARTS+1:
1389
tm->tm_min += m;
1390
set |= MINUTE;
1391
goto clear_sec;
1392
case TM_PARTS+2:
1393
tm->tm_hour += m;
1394
set |= MINUTE;
1395
goto clear_min;
1396
case TM_PARTS+3:
1397
message((-1, "AHA#%d DAY m=%d n=%d%s", __LINE__, m, n, (state & LAST) ? " LAST" : ""));
1398
if ((state & (LAST|NEXT|THIS)) == LAST)
1399
tm->tm_mday = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year));
1400
else if (state & ORDINAL)
1401
tm->tm_mday = m + 1;
1402
else
1403
tm->tm_mday += m;
1404
if (!(set & (FINAL|WORK)))
1405
set |= HOUR;
1406
goto clear_hour;
1407
case TM_PARTS+4:
1408
tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone);
1409
tm->tm_mday += 7 * m - tm->tm_wday + 1;
1410
set |= DAY;
1411
goto clear_hour;
1412
case TM_PARTS+5:
1413
tm->tm_mon += m;
1414
set |= MONTH;
1415
goto clear_mday;
1416
case TM_PARTS+6:
1417
tm->tm_year += m;
1418
goto clear_mon;
1419
case TM_HOURS+0:
1420
tm->tm_mday += m;
1421
set |= DAY;
1422
goto clear_hour;
1423
case TM_HOURS+1:
1424
tm->tm_mday += m;
1425
tm->tm_hour = 6;
1426
set |= HOUR;
1427
goto clear_min;
1428
case TM_HOURS+2:
1429
tm->tm_mday += m;
1430
tm->tm_hour = 12;
1431
set |= HOUR;
1432
goto clear_min;
1433
case TM_HOURS+3:
1434
tm->tm_mday += m;
1435
tm->tm_hour = 18;
1436
set |= HOUR;
1437
goto clear_min;
1438
}
1439
if (m >= 0 && (state & ORDINAL))
1440
tm->tm_mday = 1;
1441
tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone);
1442
day = j -= TM_DAY;
1443
if (!dir)
1444
dir = m;
1445
message((-1, "AHA#%d j=%d m=%d", __LINE__, j, m));
1446
j -= tm->tm_wday;
1447
message((-1, "AHA#%d mday=%d wday=%d day=%d dir=%d f=%d i=%d j=%d l=%d m=%d", __LINE__, tm->tm_mday, tm->tm_wday, day, dir, f, i, j, l, m));
1448
if (state & (LAST|NEXT|THIS))
1449
{
1450
if (state & ORDINAL)
1451
{
1452
while (isspace(*s))
1453
s++;
1454
if (isdigit(*s) || tmlex(s, &t, tm_info.format, TM_DAY_ABBREV, NiL, 0) >= 0)
1455
{
1456
state &= ~(LAST|NEXT|THIS);
1457
goto clear_hour;
1458
}
1459
}
1460
if (j < 0)
1461
j += 7;
1462
}
1463
else if (j > 0)
1464
j -= 7;
1465
message((-1, "AHA#%d day=%d mday=%d f=%d m=%d j=%d state=" FFMT, __LINE__, day, tm->tm_mday, f, m, j, FLAGS(state)));
1466
set |= DAY;
1467
if (set & (FINAL|WORK))
1468
goto clear_hour;
1469
else if (state & (LAST|NEXT|THIS))
1470
{
1471
if (f >= 0)
1472
day = -1;
1473
else if (m > 0 && (state & (NEXT|YEAR|MONTH)) == NEXT && j >= 0)
1474
m--;
1475
tm->tm_mday += j + m * 7;
1476
set &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/
1477
state &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/
1478
if (!(state & EXACT))
1479
goto clear_hour;
1480
}
1481
continue;
1482
case TM_MONTH_ABBREV:
1483
j += TM_MONTH - TM_MONTH_ABBREV;
1484
/*FALLTHROUGH*/
1485
case TM_MONTH:
1486
if (state & MONTH)
1487
goto done;
1488
state |= MONTH;
1489
i = tm->tm_mon;
1490
tm->tm_mon = j - TM_MONTH;
1491
if (n < 0)
1492
{
1493
while (skip[*s])
1494
s++;
1495
if (isdigit(*s))
1496
{
1497
n = strtol(s, &t, 10);
1498
if (n <= 31 && *t != ':')
1499
s = t;
1500
else
1501
n = -1;
1502
}
1503
}
1504
if (n >= 0)
1505
{
1506
if (n > 31)
1507
goto done;
1508
state |= DAY|MDAY;
1509
tm->tm_mday = n;
1510
if (f > 0)
1511
tm->tm_year += f;
1512
}
1513
if (state & (LAST|NEXT|THIS))
1514
{
1515
n = i;
1516
goto rel_month;
1517
}
1518
continue;
1519
case TM_UT:
1520
if (state & ZONE)
1521
goto done;
1522
state |= ZONE;
1523
zone = tmgoff(s, &t, 0);
1524
s = t;
1525
continue;
1526
case TM_DT:
1527
if (!dst)
1528
goto done;
1529
if (!(state & ZONE))
1530
{
1531
dst = tm->tm_zone->dst;
1532
zone = tm->tm_zone->west;
1533
}
1534
zone += tmgoff(s, &t, dst);
1535
s = t;
1536
dst = 0;
1537
state |= ZONE;
1538
continue;
1539
case TM_NOISE:
1540
continue;
1541
}
1542
}
1543
}
1544
if (n < 1000)
1545
{
1546
if (!(state & ZONE) && (zp = tmzone(s, &t, type, &dst)))
1547
{
1548
s = t;
1549
zone = zp->west + dst;
1550
tm_info.date = zp;
1551
state |= ZONE;
1552
if (n < 0)
1553
continue;
1554
}
1555
else if (!type && (zp = tmtype(s, &t)))
1556
{
1557
s = t;
1558
type = zp->type;
1559
if (n < 0)
1560
continue;
1561
}
1562
state |= BREAK;
1563
}
1564
}
1565
else if (*s == '/')
1566
{
1567
if (!(state & (YEAR|MONTH)) && n >= 1969 && n < 3000 && (i = strtol(s + 1, &t, 10)) > 0 && i <= 12)
1568
{
1569
state |= YEAR;
1570
tm->tm_year = n - 1900;
1571
s = t;
1572
i--;
1573
}
1574
else
1575
{
1576
if ((state & MONTH) || n <= 0 || n > 31)
1577
break;
1578
if (isalpha(*++s))
1579
{
1580
if ((i = tmlex(s, &t, tm_info.format, TM_DAY_ABBREV, NiL, 0)) < 0)
1581
break;
1582
if (i >= TM_MONTH)
1583
i -= TM_MONTH;
1584
s = t;
1585
}
1586
else
1587
{
1588
i = n - 1;
1589
n = strtol(s, &t, 10);
1590
s = t;
1591
if (n <= 0 || n > 31)
1592
break;
1593
if (*s == '/' && !isdigit(*(s + 1)))
1594
break;
1595
}
1596
state |= DAY;
1597
tm->tm_mday = n;
1598
}
1599
state |= MONTH;
1600
n = tm->tm_mon;
1601
tm->tm_mon = i;
1602
if (*s == '/')
1603
{
1604
n = strtol(++s, &t, 10);
1605
w = t - s;
1606
s = t;
1607
if (*s == '/' || *s == ':' || *s == '-' || *s == '_')
1608
s++;
1609
}
1610
else
1611
{
1612
if (state & (LAST|NEXT|THIS))
1613
{
1614
rel_month:
1615
if (state & LAST)
1616
tm->tm_year -= (tm->tm_mon < n) ? 0 : 1;
1617
else
1618
tm->tm_year += ((state & NEXT) ? 1 : 0) + ((tm->tm_mon < n) ? 1 : 0);
1619
if (state & MDAY)
1620
goto clear_hour;
1621
set &= ~(LAST|NEXT|THIS); /*AHA*/
1622
state &= ~(LAST|NEXT|THIS); /*AHA*/
1623
goto clear_mday;
1624
}
1625
continue;
1626
}
1627
}
1628
if (n < 0 || w > 4)
1629
break;
1630
if (w == 4)
1631
{
1632
if ((state & YEAR) || n < 1969 || n >= 3000)
1633
break;
1634
state |= YEAR;
1635
tm->tm_year = n - 1900;
1636
}
1637
else if (w == 3)
1638
{
1639
if (state & (MONTH|MDAY|WDAY))
1640
break;
1641
state |= MONTH|DAY|MDAY;
1642
tm->tm_mon = 0;
1643
tm->tm_mday = n;
1644
}
1645
else if (w == 2 && !(state & YEAR))
1646
{
1647
state |= YEAR;
1648
if (n < TM_WINDOW)
1649
n += 100;
1650
tm->tm_year = n;
1651
}
1652
else if (!(state & MONTH) && n >= 1 && n <= 12)
1653
{
1654
state |= MONTH;
1655
tm->tm_mon = n - 1;
1656
}
1657
else if (!(state & (MDAY|WDAY)) && n >= 1 && n <= 31)
1658
{
1659
state |= DAY|MDAY|WDAY;
1660
tm->tm_mday = n;
1661
}
1662
else
1663
break;
1664
if (state & BREAK)
1665
{
1666
last = t;
1667
break;
1668
}
1669
continue;
1670
clear_mon:
1671
if ((set|state) & (EXACT|MONTH))
1672
continue;
1673
tm->tm_mon = 0;
1674
clear_mday:
1675
set |= MONTH;
1676
if ((set|state) & (EXACT|DAY|HOUR))
1677
continue;
1678
tm->tm_mday = 1;
1679
clear_hour:
1680
message((-1, "AHA#%d DAY", __LINE__));
1681
set |= DAY;
1682
if ((set|state) & (EXACT|HOUR))
1683
continue;
1684
tm->tm_hour = 0;
1685
clear_min:
1686
set |= HOUR;
1687
if ((set|state) & (EXACT|MINUTE))
1688
continue;
1689
tm->tm_min = 0;
1690
clear_sec:
1691
set |= MINUTE;
1692
if ((set|state) & (EXACT|SECOND))
1693
continue;
1694
tm->tm_sec = 0;
1695
clear_nsec:
1696
set |= SECOND;
1697
if ((set|state) & (EXACT|NSEC))
1698
continue;
1699
tm->tm_nsec = 0;
1700
}
1701
done:
1702
if (day >= 0 && !(state & (MDAY|WDAY)))
1703
{
1704
message((-1, "AHA#%d day=%d dir=%d state=" FFMT, __LINE__, day, dir, FLAGS(state)));
1705
tmfix(tm);
1706
m = dir;
1707
if (state & MONTH)
1708
tm->tm_mday = 1;
1709
else if (m < 0)
1710
m++;
1711
tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone);
1712
j = day - tm->tm_wday;
1713
if (j < 0)
1714
j += 7;
1715
tm->tm_mday += j + m * 7;
1716
if (state & FINAL)
1717
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);
1718
}
1719
else if (day < 0 && (state & FINAL) && (set & DAY))
1720
{
1721
tmfix(tm);
1722
tm->tm_mday = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year));
1723
}
1724
if (state & WORK)
1725
{
1726
tm->tm_mday = (set & FINAL) ? (tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year))) : 1;
1727
tmfix(tm);
1728
message((-1, "AHA#%d WORK mday=%d wday=%d", __LINE__, tm->tm_mday, tm->tm_wday));
1729
if (tm->tm_wday == 0 && (j = 1) || tm->tm_wday == 6 && (j = 2))
1730
{
1731
if ((tm->tm_mday + j) > (tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year))))
1732
j -= 3;
1733
tm->tm_mday += j;
1734
}
1735
}
1736
now = tmxtime(tm, zone);
1737
if (tm->tm_year <= 70 && tmxsec(now) > 31536000)
1738
{
1739
now = 0;
1740
last = (char*)o;
1741
}
1742
if (e)
1743
*e = last;
1744
return now;
1745
}
1746
1747