1 /* A helper tool for perl's 2038 support.
2 * See Porting/README.y2038 for details
3 */
4
5 #include <sys/types.h>
6 #include <stdio.h>
7 #include <time.h>
8 #include <errno.h>
9 #include <string.h>
10
11 int opt_v = 0;
12 int i;
13 struct tm *tmp;
14 time_t pt, pt_max, pt_min;
15
16 static char hexbuf[80];
hex(time_t t)17 char *hex (time_t t)
18 {
19 if ((long long)t < 0)
20 sprintf (hexbuf, " -0x%016lx", -t);
21 else
22 sprintf (hexbuf, " 0x%016lx", t);
23 return (hexbuf);
24 } /* hex */
25
gm_check(time_t t,int min_year,int max_year)26 void gm_check (time_t t, int min_year, int max_year)
27 {
28 tmp = gmtime (&t);
29 if ( tmp == NULL ||
30 /* Check tm_year overflow */
31 tmp->tm_year < min_year || tmp->tm_year > max_year) {
32 if (opt_v)
33 fprintf (stderr, "gmtime (%ld) failed with errno %d\n", t, errno);
34 }
35 else {
36 if (opt_v)
37 fprintf (stderr, "%3d:%s: %12ld-%02d-%02d %02d:%02d:%02d\n",
38 i, hex (t),
39 (long)(tmp->tm_year) + 1900, tmp->tm_mon + 1, tmp->tm_mday,
40 tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
41 pt = t;
42 }
43 } /* gm_check */
44
check_gm_max()45 int check_gm_max ()
46 {
47 tmp = NULL;
48 pt = 0;
49 if (tmp == NULL || tmp->tm_year < 0) {
50 for (i = 63; i >= 0; i--) {
51 time_t x = pt | ((time_t)1 << i);
52 if (x < 0 || x < pt) continue;
53 gm_check (x, 69, 0x7fffffff);
54 }
55 }
56 pt_max = pt;
57 return (0);
58 } /* check_gm_max */
59
check_gm_min()60 int check_gm_min ()
61 {
62 tmp = NULL;
63 pt = 0;
64 if (tmp == NULL) {
65 for (i = 36; i >= 0; i--) {
66 time_t x = pt - ((time_t)1 << i);
67 if (x > 0) continue;
68 gm_check (x, -1900, 70);
69 }
70 }
71 pt_min = pt;
72 return (0);
73 } /* check_gm_min */
74
lt_check(time_t t,int min_year,int max_year)75 void lt_check (time_t t, int min_year, int max_year)
76 {
77 if (sizeof (time_t) > 4 && t > 0x7ffffffffffff000LL)
78 tmp = NULL;
79 else
80 tmp = localtime (&t);
81 if ( tmp == NULL ||
82 /* Check tm_year overflow */
83 tmp->tm_year < min_year || tmp->tm_year > max_year) {
84 if (opt_v)
85 fprintf (stderr, "localtime (%ld) failed with errno %d\n", t, errno);
86 }
87 else {
88 if (opt_v)
89 fprintf (stderr, "%3d:%s: %12ld-%02d-%02d %02d:%02d:%02d\n",
90 i, hex (t),
91 (long)(tmp->tm_year) + 1900, tmp->tm_mon + 1, tmp->tm_mday,
92 tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
93 pt = t;
94 }
95 } /* lt_check */
96
check_lt_max()97 int check_lt_max ()
98 {
99 tmp = NULL;
100 pt = 0;
101 if (tmp == NULL || tmp->tm_year < 0) {
102 for (i = 63; i >= 0; i--) {
103 time_t x = pt | ((time_t)1 << i);
104 if (x < 0 || x < pt) continue;
105 lt_check (x, 69, 0x7fffffff);
106 }
107 }
108 pt_max = pt;
109 return (0);
110 } /* check_lt_max */
111
check_lt_min()112 int check_lt_min ()
113 {
114 tmp = NULL;
115 pt = 0;
116 if (tmp == NULL) {
117 for (i = 36; i >= 0; i--) {
118 time_t x = pt - ((time_t)1 << i);
119 if (x > 0) continue;
120 lt_check (x, -1900, 70);
121 }
122 }
123 pt_min = pt;
124 return (0);
125 } /* check_lt_min */
126
main(int argc,char * argv[])127 int main (int argc, char *argv[])
128 {
129 time_t gm_max, gm_min, lt_max, lt_min;
130 if (argc > 1 && strcmp (argv[1], "-v") == 0) opt_v++;
131
132 check_gm_max (); gm_max = pt_max;
133 check_gm_min (); gm_min = pt_min;
134 check_lt_max (); lt_max = pt_max;
135 check_lt_min (); lt_min = pt_min;
136
137 opt_v++;
138 printf ("======================\n");
139 printf ("Sizeof time_t = %d\n", (i = sizeof (time_t)));
140 printf ("gmtime () boundaries:\n");
141 gm_check (gm_max, 69, 0x7fffffff);
142 gm_check (gm_min, -1900, 70);
143 printf ("localtime () boundaries:\n");
144 lt_check (lt_max, 69, 0x7fffffff);
145 lt_check (lt_min, -1900, 70);
146 printf ("Configure variables:\n");
147 printf ("sGMTIME_max='%ld'\n", gm_max);
148 printf ("sGMTIME_min='%ld'\n", gm_min);
149 printf ("sLOCALTIME_max='%ld'\n", lt_max);
150 printf ("sLOCALTIME_min='%ld'\n", lt_min);
151 return (0);
152 } /* main */
153