vinyl-cache/lib/libvinyl/vtim.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2011 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 *
30
 * Semi-trivial functions to handle HTTP header timestamps according to
31
 * RFC 2616 section 3.3.
32
 *
33
 * We must parse four different formats:
34
 *       000000000011111111112222222222
35
 *       012345678901234567890123456789
36
 *       ------------------------------
37
 *      "Sun, 06 Nov 1994 08:49:37 GMT"         RFC822 & RFC1123
38
 *      "Sunday, 06-Nov-94 08:49:37 GMT"        RFC850
39
 *      "Sun Nov  6 08:49:37 1994"              ANSI-C asctime()
40
 *      "1994-11-06T08:49:37"                   ISO 8601
41
 *
42
 * And always output the RFC1123 format.
43
 *
44
 * So why are these functions hand-built ?
45
 *
46
 * Because the people behind POSIX were short-sighted morons who didn't think
47
 * anybody would ever need to deal with timestamps in multiple different
48
 * timezones at the same time -- for that matter, convert timestamps to
49
 * broken down UTC/GMT time.
50
 *
51
 * We could, and used to, get by by smashing our TZ variable to "UTC" but
52
 * that ruins the LOCALE for VMODs.
53
 *
54
 */
55
56
#include "config.h"
57
58
#include <time.h>
59
#include <sys/time.h>
60
61
#include <math.h>
62
#include <stdint.h>
63
#include <stdio.h>
64
#include <stdlib.h>
65
#include <string.h>
66
#ifdef __MACH__
67
#include <mach/mach_time.h>
68
#endif
69
70
#include "vdef.h"
71
72
#include "vas.h"
73
#include "vct.h"
74
#include "vtim.h"
75
76
/* relax vtim parsing */
77
unsigned VTIM_postel = 0;
78
79
static const char * const weekday_name[] = {
80
        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
81
};
82
83
static const char * const more_weekday[] = {
84
        "day", "day", "sday", "nesday", "rsday", "day", "urday"
85
};
86
87
static const char * const month_name[] = {
88
        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
89
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
90
};
91
92
static const int days_in_month[] = {
93
        31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
94
};
95
96
static const int days_before_month[] = {
97
        0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
98
};
99
100
#ifdef __MACH__
101
// http://stackoverflow.com/a/21352348
102
static uint64_t mt_base;
103
static double   mt_scale;
104
105
static void
106
mach_time_init(void)
107
{
108
        mach_timebase_info_data_t timebase;
109
110
        mt_base = mach_absolute_time();
111
112
        AZ(mach_timebase_info(&timebase));
113
        mt_scale = (double)timebase.numer / (double)timebase.denom * 1e-9;
114
}
115
116
static __attribute__((constructor)) void
117
init(void)
118
{
119
        mach_time_init();
120
}
121
#endif
122
123
/*
124
 * On older Solaris-incarnations, gethrtime() was faster than
125
 * clock_gettime(CLOCK_MONOTONIC). Our configure script prefers
126
 * clock_gettime if it is consistently at least twice as fast as
127
 * gethrtime(), which is the case on modern Solaris descendents.
128
 */
129
130
vtim_mono
131 2406443
VTIM_mono(void)
132
{
133
#if defined(HAVE_GETHRTIME) && defined(USE_GETHRTIME)
134
        return (gethrtime() * 1e-9);
135
#else
136
        struct timespec ts;
137
138 2406443
        AZ(clock_gettime(CLOCK_MONOTONIC, &ts));
139 2406443
        return (ts_vtim(ts));
140
#endif
141
}
142
143
vtim_real
144 955868
VTIM_real(void)
145
{
146
#ifdef HAVE_CLOCK_GETTIME
147
        struct timespec ts;
148
149 955868
        AZ(clock_gettime(CLOCK_REALTIME, &ts));
150 955868
        return (ts_vtim(ts));
151
#else
152
        struct timeval tv;
153
154
        AZ(gettimeofday(&tv, NULL));
155
        return (tv_vtim(tv));
156
#endif
157
}
158
159
void
160 18530588
VTIM_format(vtim_real t, char p[VTIM_FORMAT_SIZE])
161
{
162
        struct tm tm;
163
        time_t tt;
164
165 18530588
        AN(p);
166 18530588
        *p = '\0';
167
168 18530588
        if (t < (vtim_real)INTMAX_MIN || t > (vtim_real)INTMAX_MAX)
169 4
                return;
170
171 18530584
        tt = (time_t)(intmax_t)t;
172 18530584
        if (gmtime_r(&tt, &tm) == NULL)
173 0
                return;
174
175 18530584
        AN(snprintf(p, VTIM_FORMAT_SIZE,
176
            "%s, %02d %s %4d %02d:%02d:%02d GMT",
177
            weekday_name[tm.tm_wday],
178
            tm.tm_mday, month_name[tm.tm_mon], tm.tm_year + 1900,
179
            tm.tm_hour, tm.tm_min, tm.tm_sec));
180 18530588
}
181
182
#ifdef TEST_DRIVER
183
#define FAIL()  \
184
        do { printf("\nFAIL <<%d>>\n", __LINE__); return (0); } while (0)
185
#else
186
#define FAIL()  \
187
        do { return (0); } while (0)
188
#endif
189
190
#define DIGIT(mult, fld)                                        \
191
        do {                                                    \
192
                if (*p < '0' || *p > '9')                       \
193
                        FAIL();                                 \
194
                tm->tm_##fld += (*p - '0') * mult;              \
195
                p++;                                            \
196
        } while(0)
197
198
#define MUSTBE(chr)                                             \
199
        do {                                                    \
200
                if (*p != chr)                                  \
201
                        FAIL();                                 \
202
                p++;                                            \
203
        } while(0)
204
205
#define WEEKDAY()                                               \
206
        do {                                                    \
207
                int i;                                          \
208
                for (i = 0; i < 7; i++) {                       \
209
                        if (!memcmp(p, weekday_name[i], 3)) {   \
210
                                tm->tm_wday = i;                \
211
                                break;                          \
212
                        }                                       \
213
                }                                               \
214
                if (i == 7)                                     \
215
                        FAIL();                                 \
216
                p += 3;                                         \
217
        } while(0)
218
219
220
#define MONTH()                                                 \
221
        do {                                                    \
222
                int i;                                          \
223
                for (i = 0; i < 12; i++) {                      \
224
                        if (!memcmp(p, month_name[i], 3)) {     \
225
                                tm->tm_mon = i + 1;             \
226
                                break;                          \
227
                        }                                       \
228
                }                                               \
229
                if (i == 12)                                    \
230
                        FAIL();                                 \
231
                p += 3;                                         \
232
        } while(0)
233
234
#define TIMESTAMP()                                             \
235
        do {                                                    \
236
                DIGIT(10, hour);                                \
237
                DIGIT(1, hour);                                 \
238
                MUSTBE(':');                                    \
239
                DIGIT(10, min);                                 \
240
                DIGIT(1, min);                                  \
241
                MUSTBE(':');                                    \
242
                DIGIT(10, sec);                                 \
243
                DIGIT(1, sec);                                  \
244
        } while(0)
245
246
static unsigned
247 58185510
vtim_parse_http(struct tm *tm, const char **pp)
248
{
249
        const char *p;
250
251 58185510
        AN(pp);
252 58185510
        p = *pp;
253 58185510
        if (*p == '\0')
254 3
                FAIL();
255
256 58185507
        if (*p >= '0' && *p <= '9') {
257
                /* ISO8601 -- "1994-11-06T08:49:37" */
258 18513423
                DIGIT(1000, year);
259 18513423
                DIGIT(100, year);
260 18513423
                DIGIT(10, year);
261 18513423
                DIGIT(1, year);
262 18513423
                MUSTBE('-');
263 18513381
                DIGIT(10, mon);
264 18513381
                DIGIT(1, mon);
265 18513381
                MUSTBE('-');
266 18513381
                DIGIT(10, mday);
267 18513381
                DIGIT(1, mday);
268 18513381
                MUSTBE('T');
269 18513381
                TIMESTAMP();
270 18513381
        } else {
271 158658783
                WEEKDAY();
272 39672072
                assert(tm->tm_wday >= 0 && tm->tm_wday <= 6);
273 39672072
                if (*p == ',') {
274
                        /* RFC822 & RFC1123 - "Sun, 06 Nov 1994 08:49:37 GMT" */
275 18521547
                        p++;
276 18521547
                        MUSTBE(' ');
277 18521547
                        if (VTIM_postel && *p && p[1] == ' ')
278 12
                                DIGIT(1, mday);
279
                        else {
280 18521535
                                DIGIT(10, mday);
281 18521535
                                DIGIT(1, mday);
282
                        }
283 18521547
                        MUSTBE(' ');
284 120810651
                        MONTH();
285 18521544
                        MUSTBE(' ');
286 18521544
                        DIGIT(1000, year);
287 18521544
                        DIGIT(100, year);
288 18521544
                        DIGIT(10, year);
289 18521544
                        DIGIT(1, year);
290 18521544
                        MUSTBE(' ');
291 18521544
                        TIMESTAMP();
292 18521544
                        MUSTBE(' ');
293 18521544
                        MUSTBE('G');
294 18521541
                        MUSTBE('M');
295 18521541
                        MUSTBE('T');
296 39672066
                } else if (*p == ' ') {
297
                        /* ANSI-C asctime() -- "Sun Nov  6 08:49:37 1994" */
298 18516663
                        p++;
299 120776562
                        MONTH();
300 18516651
                        MUSTBE(' ');
301 18516651
                        if (*p != ' ')
302 13038846
                                DIGIT(10, mday);
303
                        else
304 5477805
                                p++;
305 18516651
                        DIGIT(1, mday);
306 18516651
                        MUSTBE(' ');
307 18516651
                        TIMESTAMP();
308 18516651
                        MUSTBE(' ');
309 18516651
                        DIGIT(1000, year);
310 18516651
                        DIGIT(100, year);
311 18516651
                        DIGIT(10, year);
312 18516651
                        DIGIT(1, year);
313 23784375
                } else if (!memcmp(p, more_weekday[tm->tm_wday],
314 2633862
                    vstrlen(more_weekday[tm->tm_wday]))) {
315
                        /* RFC850 -- "Sunday, 06-Nov-94 08:49:37 GMT" */
316 2633850
                        p += vstrlen(more_weekday[tm->tm_wday]);
317 2633850
                        MUSTBE(',');
318 2633850
                        MUSTBE(' ');
319 2633850
                        DIGIT(10, mday);
320 2633850
                        DIGIT(1, mday);
321 2633850
                        MUSTBE('-');
322 17195193
                        MONTH();
323 2633850
                        MUSTBE('-');
324 2633850
                        DIGIT(10, year);
325 2633850
                        DIGIT(1, year);
326 2633850
                        tm->tm_year += 1900;
327 2633850
                        if (tm->tm_year < 1969)
328 1815156
                                tm->tm_year += 100;
329 2633850
                        MUSTBE(' ');
330 2633850
                        TIMESTAMP();
331 2633850
                        MUSTBE(' ');
332 2633850
                        MUSTBE('G');
333 2633850
                        MUSTBE('M');
334 2633850
                        MUSTBE('T');
335 2633850
                } else
336 12
                        FAIL();
337
        }
338
339 58185423
        *pp = p;
340 58185423
        return (1);
341 58185510
}
342
343
static vtim_real
344 58185411
vtim_calc(struct tm *tm)
345
{
346
        vtim_real t;
347
        int d, leap;
348
349 58185411
        if (tm->tm_sec < 0 || tm->tm_sec > 60)  /* Leapseconds! */
350 12
                FAIL();
351 58185399
        if (tm->tm_min < 0 || tm->tm_min > 59)
352 12
                FAIL();
353 58185387
        if (tm->tm_hour < 0 || tm->tm_hour > 23)
354 12
                FAIL();
355 58185375
        if (tm->tm_mon < 1 || tm->tm_mon > 12)
356 12
                FAIL();
357 58185363
        if (tm->tm_mday < 1 || tm->tm_mday > days_in_month[tm->tm_mon - 1])
358 12
                FAIL();
359 58185351
        if (tm->tm_year < 1899)
360 0
                FAIL();
361
362 72761001
        leap = ((tm->tm_year) % 4) == 0 &&
363 14575650
            (((tm->tm_year) % 100) != 0 || ((tm->tm_year) % 400) == 0);
364
365 58185351
        if (tm->tm_mon == 2 && tm->tm_mday > 28 && !leap)
366 12
                FAIL();
367
368 58185339
        if (tm->tm_sec == 60)                   /* Ignore Leapseconds */
369 12
                tm->tm_sec--;
370
371 58185339
        t = ((tm->tm_hour * 60.) + tm->tm_min) * 60. + tm->tm_sec;
372
373 58185339
        d = (tm->tm_mday - 1) + days_before_month[tm->tm_mon - 1];
374
375 58185339
        if (tm->tm_mon > 2 && leap)
376 11790642
                d++;
377
378 58185339
        d += (tm->tm_year % 100) * 365; /* There are 365 days in a year */
379
380 58185339
        if ((tm->tm_year % 100) > 0)    /* And a leap day every four years */
381 57527655
                d += (((tm->tm_year % 100) - 1) / 4);
382
383 58185339
        d += ((tm->tm_year / 100) - 20) *       /* Days relative to y2000 */
384
            (100 * 365 + 24);           /* 24 leapdays per year in a century */
385
386 58185339
        d += ((tm->tm_year - 1) / 400) - 4;     /* One more every 400 years */
387
388
        /*
389
         * Now check weekday, if we have one.
390
         * 6 is because 2000-01-01 was a saturday.
391
         * 10000 is to make sure the modulus argument is always positive
392
         */
393 58185339
        if (tm->tm_wday != -1 && (d + 6 + 7 * 10000) % 7 != tm->tm_wday)
394 24
                FAIL();
395
396 58185315
        t += d * 86400.;
397
398 58185315
        t += 10957. * 86400.;   /* 10957 days frm UNIX epoch to y2000 */
399
400 58185315
        return (t);
401 58185411
}
402
403
vtim_real
404 58185510
VTIM_parse(const char *p)
405
{
406 58185510
        struct tm tm[1] = {{.tm_wday = -1 }};
407
408 58185510
        if (p == NULL)
409 0
                FAIL();
410
411 58185516
        while (vct_isows(*p))
412 6
                p++;
413
414 58185510
        if (!vtim_parse_http(tm, &p))
415 87
                FAIL();
416
417 58185435
        while (vct_isows(*p))
418 12
                p++;
419
420 58185423
        if (*p != '\0')
421 12
                FAIL();
422
423 58185411
        return (vtim_calc(tm));
424 58185510
}
425
426
void
427 422230
VTIM_sleep(vtim_dur t)
428
{
429
        struct timespec ts;
430
431 422230
        ts = VTIM_timespec(t);
432
433 422230
        (void)nanosleep(&ts, NULL);
434 422230
}
435
436
/*
437
 * VTIM_timeval and VTIM_timespec may need variants with different signatures
438
 * when vtim_real / vtim_mono typedefs are changed
439
 */
440
441
struct timeval
442 38124
VTIM_timeval(vtim_dur t)
443
{
444
        struct timeval tv;
445
446 38124
        AZ(isnan(t));
447 38124
        tv.tv_sec = (time_t)trunc(t);
448 38124
        tv.tv_usec = (int)(1e6 * (t - tv.tv_sec));
449 38124
        return (tv);
450
}
451
452
struct timespec
453 491856
VTIM_timespec(vtim_dur t)
454
{
455
        struct timespec tv;
456
457 491856
        AZ(isnan(t));
458 491856
        tv.tv_sec = (time_t)trunc(t);
459 491856
        tv.tv_nsec = (int)(1e9 * (t - tv.tv_sec));
460 491856
        return (tv);
461
}
462
463
struct timeval
464 38124
VTIM_timeval_sock(vtim_dur t)
465
{
466
467 38124
        return (VTIM_timeval(isinf(t) ? 0. : vmax(t, 1e-3)));
468
}
469
470
int
471 173792
VTIM_poll_tmo(vtim_dur tmo)
472
{
473
474 173792
        if (isinf(tmo))
475 9
                return (-1);
476 173783
        assert(!isnan(tmo));
477 173783
        return (vmax_t(int, 0, ((int)(tmo * 1e3))));
478 173792
}
479
480
#ifdef TEST_DRIVER
481
482
#pragma GCC diagnostic ignored "-Wformat-y2k"
483
484
#include <stdint.h>
485
486
static void
487 12
tst(const char *s, time_t good)
488
{
489
        time_t t;
490
        char buf[BUFSIZ];
491
492 12
        t = VTIM_parse(s);
493 12
        VTIM_format(t, buf);
494 12
        printf("%-30s -> %12jd -> %s\n", s, (intmax_t)t, buf);
495 12
        if (t != good) {
496 0
                printf("Parse error! Got: %jd should have %jd diff %jd\n",
497 0
                    (intmax_t)t, (intmax_t)good, (intmax_t)(t - good));
498 0
                exit(4);
499
        }
500 12
}
501
502
/* XXX keep as double for the time being */
503
static int
504 6
tst_delta_check(const char *name, double begin, double end, vtim_dur ref)
505
{
506
#ifdef __MACH__
507
        const double tol_max = 2;
508
#else
509 6
        const double tol_max = 1.1;
510
#endif
511 6
        const double tol_min = 1;
512
513 6
        printf("%s delta for %fs sleep: %f\n", name, ref, (end - begin));
514
515 6
        if ((end - begin) > tol_max * ref) {
516 0
                printf("%s delta above tolerance: ((%f - %f) = %f) > %f\n",
517 0
                    name, end, begin, (end - begin), tol_max);
518 0
                return (1);
519 6
        } else if ((end - begin) < tol_min * ref) {
520 0
                printf("%s delta below tolerance: ((%f - %f) = %f) < %f\n",
521 0
                    name, end, begin, (end - begin), tol_min);
522 0
                return (1);
523
        }
524 6
        return (0);
525 6
}
526
527
static void
528 3
tst_delta(void)
529
{
530
        vtim_mono m_begin, m_end;
531
        vtim_real r_begin, r_end;
532 3
        const vtim_dur ref = 1;
533 3
        int err = 0;
534
535 3
        r_begin = VTIM_real();
536 3
        m_begin = VTIM_mono();
537 3
        VTIM_sleep(ref);
538 3
        r_end = VTIM_real();
539 3
        m_end = VTIM_mono();
540
541 3
        err += tst_delta_check("VTIM_mono", m_begin, m_end, ref);
542 3
        err += tst_delta_check("VTIM_real", r_begin, r_end, ref);
543
544 3
        if (err) {
545 0
                printf("%d time delta test errors\n", err);
546 0
                exit(4);
547
        }
548 3
}
549
550
static void
551 3
bench(void)
552
{
553
        vtim_mono s, e;
554
        vtim_mono t_m;
555
        vtim_real t_r;
556
        unsigned long t_i;
557
        int i;
558
        char buf[64];
559
560 3
        t_m = 0;
561 3
        t_r = 0;
562 3
        s = VTIM_mono();
563 300003
        for (i=0; i<100000; i++)
564 300000
                t_r += VTIM_real();
565 3
        e = VTIM_mono();
566 3
        printf("real: %fs / %d = %fns - tst val %f\n",
567 3
            e - s, i, 1e9 * (e - s) / i, t_r);
568
569 3
        t_i = 0;
570 3
        s = VTIM_mono();
571 300003
        for (i=0; i<100000; i++)
572 300000
                t_m += VTIM_mono();
573 3
        e = VTIM_mono();
574 3
        printf("mono: %fs / %d = %fns - tst val %f\n",
575 3
            e - s, i, 1e9 * (e - s) / i, t_m);
576
577 3
        t_i = 0;
578 3
        s = VTIM_mono();
579 300003
        for (i=0; i<100000; i++) {
580 300000
                snprintf(buf, sizeof(buf), "%.6f", s);
581 300000
                t_i += buf[4];
582 300000
        }
583 3
        e = VTIM_mono();
584 3
        printf("printf %%.6f: %fs / %d = %fns - tst val %lu %s\n",
585 3
            e - s, i, 1e9 * (e - s) / i, t_i, buf);
586
587 3
        t_i = 0;
588 3
        s = VTIM_mono();
589 300003
        for (i=0; i<100000; i++) {
590 600000
                snprintf(buf, sizeof(buf), "%ju.%06ju",
591 300000
                    (uintmax_t)floor(s),
592 300000
                    (uintmax_t)floor((s * 1e6)) % 1000000UL);
593 300000
                t_i += buf[4];
594 300000
        }
595 3
        e = VTIM_mono();
596 3
        printf("printf %%ju.%%06ju: %fs / %d = %fns - tst val %lu %s\n",
597 3
            e - s, i, 1e9 * (e - s) / i, t_i, buf);
598 3
}
599
600
static void
601 58170591
parse_check(time_t t, const char *s)
602
{
603
        vtim_real tt;
604
        char buf[BUFSIZ];
605
606 58170591
        tt = VTIM_parse(s);
607 58170591
        if (tt != t) {
608 0
                VTIM_format(tt, buf);
609 0
                printf("  fm: %12jd <%s>\n", (intmax_t)t, s);
610 0
                printf("  to: %12.0f <%s>\n", tt, buf);
611 0
                exit(2);
612
        }
613 58170591
}
614
615
#define TTEST_MIN (sizeof(time_t) >= 8 ? -2209852800LL : INT32_MIN)
616
#define TTEST_MAX (sizeof(time_t) >= 8 ? 20000000000LL : INT32_MAX)
617
618
int
619 3
main(int argc, char **argv)
620
{
621
        time_t t;
622
        intmax_t iter;
623
        struct tm tm;
624
        char buf[BUFSIZ];
625
        char buf1[BUFSIZ];
626
627 3
        (void)argc;
628 3
        (void)argv;
629
630 3
        AZ(setenv("TZ", "UTC", 1));
631
632 3
        bench();
633
634
        /* Brute force test against libc version */
635 18513357
        for (iter = TTEST_MIN; iter < TTEST_MAX; iter += 3599) {
636 18513354
                t = (time_t)iter;
637 18513354
                gmtime_r(&t, &tm);
638 18513354
                strftime(buf1, sizeof buf1, "%a, %d %b %Y %T GMT", &tm);
639 18513354
                VTIM_format(t, buf);
640 18513354
                if (vstrcmp(buf, buf1)) {
641 0
                        printf("libc: <%s> Vtim <%s> %jd\n",
642 0
                            buf1, buf, (intmax_t)t);
643 0
                        exit(2);
644
                }
645 18513354
                parse_check(t, buf1);
646
647 18513354
                strftime(buf1, sizeof buf1, "%a %b %e %T %Y", &tm);
648 18513354
                parse_check(t, buf1);
649
650 18513354
                strftime(buf1, sizeof buf1, "%Y-%m-%dT%T", &tm);
651 18513354
                parse_check(t, buf1);
652
653 18513354
                if (tm.tm_year >= 69 && tm.tm_year < 169) {
654 2630529
                        strftime(buf1, sizeof buf1, "%A, %d-%b-%y %T GMT", &tm);
655 2630529
                        parse_check(t, buf1);
656 2630529
                }
657 18513354
        }
658
659
        /* Examples from RFC2616 section 3.3.1 */
660 3
        tst("Sun, 06 Nov 1994 08:49:37 GMT", 784111777);
661 3
        tst("Sunday, 06-Nov-94 08:49:37 GMT", 784111777);
662 3
        tst("Sun Nov  6 08:49:37 1994", 784111777);
663
664 3
        tst("1994-11-06T08:49:37", 784111777);
665
666 3
        tst_delta();
667
668 3
        return (0);
669
}
670
671
#endif