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 3196483
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 3196483
        AZ(clock_gettime(CLOCK_MONOTONIC, &ts));
139 3196483
        return (ts_vtim(ts));
140
#endif
141
}
142
143
vtim_real
144 1274872
VTIM_real(void)
145
{
146
#ifdef HAVE_CLOCK_GETTIME
147
        struct timespec ts;
148
149 1274872
        AZ(clock_gettime(CLOCK_REALTIME, &ts));
150 1274872
        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 24707347
VTIM_format(vtim_real t, char p[VTIM_FORMAT_SIZE])
161
{
162
        struct tm tm;
163
        time_t tt;
164
        int r;
165
166 24707347
        AN(p);
167 24707347
        *p = '\0';
168
169 24707347
        if (t < (vtim_real)INTMAX_MIN || t > (vtim_real)INTMAX_MAX)
170 5
                return;
171
172 24707342
        tt = (time_t)(intmax_t)t;
173 24707342
        if (gmtime_r(&tt, &tm) == NULL)
174 0
                return;
175
176 49414684
        r = snprintf(p, VTIM_FORMAT_SIZE,
177
            "%s, %02d %s %4d %02d:%02d:%02d GMT",
178 24707342
            weekday_name[tm.tm_wday],
179 24707342
            tm.tm_mday, month_name[tm.tm_mon], tm.tm_year + 1900,
180 24707342
            tm.tm_hour, tm.tm_min, tm.tm_sec);
181 24707342
        assert(r == VTIM_FORMAT_SIZE - 1);
182 24707347
}
183
184
#ifdef TEST_DRIVER
185
#define FAIL()  \
186
        do { printf("\nFAIL <<%d>>\n", __LINE__); return (0); } while (0)
187
#else
188
#define FAIL()  \
189
        do { return (0); } while (0)
190
#endif
191
192
#define DIGIT(mult, fld)                                        \
193
        do {                                                    \
194
                if (*p < '0' || *p > '9')                       \
195
                        FAIL();                                 \
196
                tm->tm_##fld += (*p - '0') * mult;              \
197
                p++;                                            \
198
        } while(0)
199
200
#define MUSTBE(chr)                                             \
201
        do {                                                    \
202
                if (*p != chr)                                  \
203
                        FAIL();                                 \
204
                p++;                                            \
205
        } while(0)
206
207
#define WEEKDAY()                                               \
208
        do {                                                    \
209
                int i;                                          \
210
                for (i = 0; i < 7; i++) {                       \
211
                        if (!vstrncmp(p, weekday_name[i], 3)) { \
212
                                tm->tm_wday = i;                \
213
                                break;                          \
214
                        }                                       \
215
                }                                               \
216
                if (i == 7)                                     \
217
                        FAIL();                                 \
218
                p += 3;                                         \
219
        } while(0)
220
221
222
#define MONTH()                                                 \
223
        do {                                                    \
224
                int i;                                          \
225
                for (i = 0; i < 12; i++) {                      \
226
                        if (!vstrncmp(p, month_name[i], 3)) {   \
227
                                tm->tm_mon = i + 1;             \
228
                                break;                          \
229
                        }                                       \
230
                }                                               \
231
                if (i == 12)                                    \
232
                        FAIL();                                 \
233
                p += 3;                                         \
234
        } while(0)
235
236
#define TIMESTAMP()                                             \
237
        do {                                                    \
238
                DIGIT(10, hour);                                \
239
                DIGIT(1, hour);                                 \
240
                MUSTBE(':');                                    \
241
                DIGIT(10, min);                                 \
242
                DIGIT(1, min);                                  \
243
                MUSTBE(':');                                    \
244
                DIGIT(10, sec);                                 \
245
                DIGIT(1, sec);                                  \
246
        } while(0)
247
248
static unsigned
249 77580505
vtim_parse_http(struct tm *tm, const char **pp)
250
{
251
        const char *p;
252
253 77580505
        AN(pp);
254 77580505
        p = *pp;
255 77580505
        if (*p == '\0')
256 4
                FAIL();
257
258 77580501
        if (*p >= '0' && *p <= '9') {
259
                /* ISO8601 -- "1994-11-06T08:49:37" */
260 24684564
                DIGIT(1000, year);
261 24684564
                DIGIT(100, year);
262 24684564
                DIGIT(10, year);
263 24684564
                DIGIT(1, year);
264 24684564
                MUSTBE('-');
265 24684508
                DIGIT(10, mon);
266 24684508
                DIGIT(1, mon);
267 24684508
                MUSTBE('-');
268 24684508
                DIGIT(10, mday);
269 24684508
                DIGIT(1, mday);
270 24684508
                MUSTBE('T');
271 24684508
                TIMESTAMP();
272 24684508
        } else {
273 211560847
                WEEKDAY();
274 52895921
                assert(tm->tm_wday >= 0 && tm->tm_wday <= 6);
275 52895921
                if (*p == ',') {
276
                        /* RFC822 & RFC1123 - "Sun, 06 Nov 1994 08:49:37 GMT" */
277 24695189
                        p++;
278 24695189
                        MUSTBE(' ');
279 24695189
                        if (VTIM_postel && *p && p[1] == ' ')
280 16
                                DIGIT(1, mday);
281
                        else {
282 24695173
                                DIGIT(10, mday);
283 24695173
                                DIGIT(1, mday);
284
                        }
285 24695189
                        MUSTBE(' ');
286 161085032
                        MONTH();
287 24695185
                        MUSTBE(' ');
288 24695185
                        DIGIT(1000, year);
289 24695185
                        DIGIT(100, year);
290 24695185
                        DIGIT(10, year);
291 24695185
                        DIGIT(1, year);
292 24695185
                        MUSTBE(' ');
293 24695185
                        TIMESTAMP();
294 24695185
                        MUSTBE(' ');
295 24695185
                        MUSTBE('G');
296 24695181
                        MUSTBE('M');
297 24695181
                        MUSTBE('T');
298 52895913
                } else if (*p == ' ') {
299
                        /* ANSI-C asctime() -- "Sun Nov  6 08:49:37 1994" */
300 24688900
                        p++;
301 161035592
                        MONTH();
302 24688884
                        MUSTBE(' ');
303 24688884
                        if (*p != ' ')
304 17385128
                                DIGIT(10, mday);
305
                        else
306 7303756
                                p++;
307 24688884
                        DIGIT(1, mday);
308 24688884
                        MUSTBE(' ');
309 24688884
                        TIMESTAMP();
310 24688884
                        MUSTBE(' ');
311 24688884
                        DIGIT(1000, year);
312 24688884
                        DIGIT(100, year);
313 24688884
                        DIGIT(10, year);
314 24688884
                        DIGIT(1, year);
315 28200716
                } else if (!vstrncmp(p, more_weekday[tm->tm_wday],
316
                    vstrlen(more_weekday[tm->tm_wday]))) {
317
                        /* RFC850 -- "Sunday, 06-Nov-94 08:49:37 GMT" */
318 3511816
                        p += vstrlen(more_weekday[tm->tm_wday]);
319 3511816
                        MUSTBE(',');
320 3511816
                        MUSTBE(' ');
321 3511816
                        DIGIT(10, mday);
322 3511816
                        DIGIT(1, mday);
323 3511816
                        MUSTBE('-');
324 22927100
                        MONTH();
325 3511816
                        MUSTBE('-');
326 3511816
                        DIGIT(10, year);
327 3511816
                        DIGIT(1, year);
328 3511816
                        tm->tm_year += 1900;
329 3511816
                        if (tm->tm_year < 1969)
330 2420208
                                tm->tm_year += 100;
331 3511816
                        MUSTBE(' ');
332 3511816
                        TIMESTAMP();
333 3511816
                        MUSTBE(' ');
334 3511816
                        MUSTBE('G');
335 3511816
                        MUSTBE('M');
336 3511816
                        MUSTBE('T');
337 3511816
                } else
338 16
                        FAIL();
339
        }
340
341 77580389
        *pp = p;
342 77580389
        return (1);
343 77580505
}
344
345
static vtim_real
346 77580373
vtim_calc(struct tm *tm)
347
{
348
        vtim_real t;
349
        int d, leap;
350
351 77580373
        if (tm->tm_sec < 0 || tm->tm_sec > 60)  /* Leapseconds! */
352 16
                FAIL();
353 77580357
        if (tm->tm_min < 0 || tm->tm_min > 59)
354 16
                FAIL();
355 77580341
        if (tm->tm_hour < 0 || tm->tm_hour > 23)
356 16
                FAIL();
357 77580325
        if (tm->tm_mon < 1 || tm->tm_mon > 12)
358 16
                FAIL();
359 77580309
        if (tm->tm_mday < 1 || tm->tm_mday > days_in_month[tm->tm_mon - 1])
360 16
                FAIL();
361 77580293
        if (tm->tm_year < 1899)
362 0
                FAIL();
363
364 97014493
        leap = ((tm->tm_year) % 4) == 0 &&
365 19434200
            (((tm->tm_year) % 100) != 0 || ((tm->tm_year) % 400) == 0);
366
367 77580293
        if (tm->tm_mon == 2 && tm->tm_mday > 28 && !leap)
368 16
                FAIL();
369
370 77580277
        if (tm->tm_sec == 60)                   /* Ignore Leapseconds */
371 16
                tm->tm_sec--;
372
373 77580277
        t = ((tm->tm_hour * 60.) + tm->tm_min) * 60. + tm->tm_sec;
374
375 77580277
        d = (tm->tm_mday - 1) + days_before_month[tm->tm_mon - 1];
376
377 77580277
        if (tm->tm_mon > 2 && leap)
378 15720856
                d++;
379
380 77580277
        d += (tm->tm_year % 100) * 365; /* There are 365 days in a year */
381
382 77580277
        if ((tm->tm_year % 100) > 0)    /* And a leap day every four years */
383 76703365
                d += (((tm->tm_year % 100) - 1) / 4);
384
385 77580277
        d += ((tm->tm_year / 100) - 20) *       /* Days relative to y2000 */
386
            (100 * 365 + 24);           /* 24 leapdays per year in a century */
387
388 77580277
        d += ((tm->tm_year - 1) / 400) - 4;     /* One more every 400 years */
389
390
        /*
391
         * Now check weekday, if we have one.
392
         * 6 is because 2000-01-01 was a saturday.
393
         * 10000 is to make sure the modulus argument is always positive
394
         */
395 77580277
        if (tm->tm_wday != -1 && (d + 6 + 7 * 10000) % 7 != tm->tm_wday)
396 32
                FAIL();
397
398 77580245
        t += d * 86400.;
399
400 77580245
        t += 10957. * 86400.;   /* 10957 days frm UNIX epoch to y2000 */
401
402 77580245
        return (t);
403 77580373
}
404
405
vtim_real
406 77580505
VTIM_parse(const char *p)
407
{
408 77580505
        struct tm tm[1] = {{.tm_wday = -1 }};
409
410 77580505
        if (p == NULL)
411 0
                FAIL();
412
413 77580513
        while (vct_isows(*p))
414 8
                p++;
415
416 77580505
        if (!vtim_parse_http(tm, &p))
417 116
                FAIL();
418
419 77580405
        while (vct_isows(*p))
420 16
                p++;
421
422 77580389
        if (*p != '\0')
423 16
                FAIL();
424
425 77580373
        return (vtim_calc(tm));
426 77580505
}
427
428
void
429 569917
VTIM_sleep(vtim_dur t)
430
{
431
        struct timespec ts;
432
433 569917
        ts = VTIM_timespec(t);
434
435 569917
        (void)nanosleep(&ts, NULL);
436 569917
}
437
438
/*
439
 * VTIM_timeval and VTIM_timespec may need variants with different signatures
440
 * when vtim_real / vtim_mono typedefs are changed
441
 */
442
443
struct timeval
444 50589
VTIM_timeval(vtim_dur t)
445
{
446
        struct timeval tv;
447
448 50589
        AZ(isnan(t));
449 50589
        tv.tv_sec = (time_t)trunc(t);
450 50589
        tv.tv_usec = (int)(1e6 * (t - tv.tv_sec));
451 50589
        return (tv);
452
}
453
454
struct timespec
455 662409
VTIM_timespec(vtim_dur t)
456
{
457
        struct timespec tv;
458
459 662409
        AZ(isnan(t));
460 662409
        tv.tv_sec = (time_t)trunc(t);
461 662409
        tv.tv_nsec = (int)(1e9 * (t - tv.tv_sec));
462 662409
        return (tv);
463
}
464
465
struct timeval
466 50589
VTIM_timeval_sock(vtim_dur t)
467
{
468
469 50589
        return (VTIM_timeval(isinf(t) ? 0. : vmax(t, 1e-3)));
470
}
471
472
int
473 232167
VTIM_poll_tmo(vtim_dur tmo)
474
{
475
476 232167
        if (isinf(tmo))
477 12
                return (-1);
478 232155
        assert(!isnan(tmo));
479 232155
        return (vmax_t(int, 0, ((int)(tmo * 1e3))));
480 232167
}
481
482
#ifdef TEST_DRIVER
483
484
#pragma GCC diagnostic ignored "-Wformat-y2k"
485
486
#include <stdint.h>
487
488
static void
489 16
tst(const char *s, time_t good)
490
{
491
        time_t t;
492
        char buf[BUFSIZ];
493
494 16
        t = VTIM_parse(s);
495 16
        VTIM_format(t, buf);
496 16
        printf("%-30s -> %12jd -> %s\n", s, (intmax_t)t, buf);
497 16
        if (t != good) {
498 0
                printf("Parse error! Got: %jd should have %jd diff %jd\n",
499 0
                    (intmax_t)t, (intmax_t)good, (intmax_t)(t - good));
500 0
                exit(4);
501
        }
502 16
}
503
504
/* XXX keep as double for the time being */
505
static int
506 8
tst_delta_check(const char *name, double begin, double end, vtim_dur ref)
507
{
508
#ifdef __MACH__
509
        const double tol_max = 2;
510
#else
511 8
        const double tol_max = 1.1;
512
#endif
513 8
        const double tol_min = 1;
514
515 8
        printf("%s delta for %fs sleep: %f\n", name, ref, (end - begin));
516
517 8
        if ((end - begin) > tol_max * ref) {
518 0
                printf("%s delta above tolerance: ((%f - %f) = %f) > %f\n",
519 0
                    name, end, begin, (end - begin), tol_max);
520 0
                return (1);
521 8
        } else if ((end - begin) < tol_min * ref) {
522 0
                printf("%s delta below tolerance: ((%f - %f) = %f) < %f\n",
523 0
                    name, end, begin, (end - begin), tol_min);
524 0
                return (1);
525
        }
526 8
        return (0);
527 8
}
528
529
static void
530 4
tst_delta(void)
531
{
532
        vtim_mono m_begin, m_end;
533
        vtim_real r_begin, r_end;
534 4
        const vtim_dur ref = 1;
535 4
        int err = 0;
536
537 4
        r_begin = VTIM_real();
538 4
        m_begin = VTIM_mono();
539 4
        VTIM_sleep(ref);
540 4
        r_end = VTIM_real();
541 4
        m_end = VTIM_mono();
542
543 4
        err += tst_delta_check("VTIM_mono", m_begin, m_end, ref);
544 4
        err += tst_delta_check("VTIM_real", r_begin, r_end, ref);
545
546 4
        if (err) {
547 0
                printf("%d time delta test errors\n", err);
548 0
                exit(4);
549
        }
550 4
}
551
552
static void
553 4
bench(void)
554
{
555
        vtim_mono s, e;
556
        vtim_mono t_m;
557
        vtim_real t_r;
558
        unsigned long t_i;
559
        int i;
560
        char buf[64];
561
562 4
        t_m = 0;
563 4
        t_r = 0;
564 4
        s = VTIM_mono();
565 400004
        for (i=0; i<100000; i++)
566 400000
                t_r += VTIM_real();
567 4
        e = VTIM_mono();
568 4
        printf("real: %fs / %d = %fns - tst val %f\n",
569 4
            e - s, i, 1e9 * (e - s) / i, t_r);
570
571 4
        t_i = 0;
572 4
        s = VTIM_mono();
573 400004
        for (i=0; i<100000; i++)
574 400000
                t_m += VTIM_mono();
575 4
        e = VTIM_mono();
576 4
        printf("mono: %fs / %d = %fns - tst val %f\n",
577 4
            e - s, i, 1e9 * (e - s) / i, t_m);
578
579 4
        t_i = 0;
580 4
        s = VTIM_mono();
581 400004
        for (i=0; i<100000; i++) {
582 400000
                snprintf(buf, sizeof(buf), "%.6f", s);
583 400000
                t_i += buf[4];
584 400000
        }
585 4
        e = VTIM_mono();
586 4
        printf("printf %%.6f: %fs / %d = %fns - tst val %lu %s\n",
587 4
            e - s, i, 1e9 * (e - s) / i, t_i, buf);
588
589 4
        t_i = 0;
590 4
        s = VTIM_mono();
591 400004
        for (i=0; i<100000; i++) {
592 800000
                snprintf(buf, sizeof(buf), "%ju.%06ju",
593 400000
                    (uintmax_t)floor(s),
594 400000
                    (uintmax_t)floor((s * 1e6)) % 1000000UL);
595 400000
                t_i += buf[4];
596 400000
        }
597 4
        e = VTIM_mono();
598 4
        printf("printf %%ju.%%06ju: %fs / %d = %fns - tst val %lu %s\n",
599 4
            e - s, i, 1e9 * (e - s) / i, t_i, buf);
600 4
}
601
602
static void
603 77560788
parse_check(time_t t, const char *s)
604
{
605
        vtim_real tt;
606
        char buf[BUFSIZ];
607
608 77560788
        tt = VTIM_parse(s);
609 77560788
        if (tt != t) {
610 0
                VTIM_format(tt, buf);
611 0
                printf("  fm: %12jd <%s>\n", (intmax_t)t, s);
612 0
                printf("  to: %12.0f <%s>\n", tt, buf);
613 0
                exit(2);
614
        }
615 77560788
}
616
617
#define TTEST_MIN (sizeof(time_t) >= 8 ? -2209852800LL : INT32_MIN)
618
#define TTEST_MAX (sizeof(time_t) >= 8 ? 20000000000LL : INT32_MAX)
619
620
int
621 4
main(int argc, char **argv)
622
{
623
        time_t t;
624
        intmax_t iter;
625
        struct tm tm;
626
        char buf[BUFSIZ];
627
        char buf1[BUFSIZ];
628
629 4
        (void)argc;
630 4
        (void)argv;
631
632 4
        AZ(setenv("TZ", "UTC", 1));
633
634 4
        bench();
635
636
        /* Brute force test against libc version */
637 24684476
        for (iter = TTEST_MIN; iter < TTEST_MAX; iter += 3599) {
638 24684472
                t = (time_t)iter;
639 24684472
                gmtime_r(&t, &tm);
640 24684472
                strftime(buf1, sizeof buf1, "%a, %d %b %Y %T GMT", &tm);
641 24684472
                VTIM_format(t, buf);
642 24684472
                if (vstrcmp(buf, buf1)) {
643 0
                        printf("libc: <%s> Vtim <%s> %jd\n",
644 0
                            buf1, buf, (intmax_t)t);
645 0
                        exit(2);
646
                }
647 24684472
                parse_check(t, buf1);
648
649 24684472
                strftime(buf1, sizeof buf1, "%a %b %e %T %Y", &tm);
650 24684472
                parse_check(t, buf1);
651
652 24684472
                strftime(buf1, sizeof buf1, "%Y-%m-%dT%T", &tm);
653 24684472
                parse_check(t, buf1);
654
655 24684472
                if (tm.tm_year >= 69 && tm.tm_year < 169) {
656 3507372
                        strftime(buf1, sizeof buf1, "%A, %d-%b-%y %T GMT", &tm);
657 3507372
                        parse_check(t, buf1);
658 3507372
                }
659 24684472
        }
660
661
        /* Examples from RFC2616 section 3.3.1 */
662 4
        tst("Sun, 06 Nov 1994 08:49:37 GMT", 784111777);
663 4
        tst("Sunday, 06-Nov-94 08:49:37 GMT", 784111777);
664 4
        tst("Sun Nov  6 08:49:37 1994", 784111777);
665
666 4
        tst("1994-11-06T08:49:37", 784111777);
667
668 4
        tst_delta();
669
670 4
        return (0);
671
}
672
673
#endif