Add lib/w32sock.h as dependency of close module.
[gnulib.git] / lib / posixtm.c
1 /* Parse dates for touch and date.
2
3    Copyright (C) 1989, 1990, 1991, 1998, 2000, 2001, 2002, 2003, 2004,
4    2005, 2006, 2007 Free Software Foundation Inc.
5
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19 /* Yacc-based version written by Jim Kingdon and David MacKenzie.
20    Rewritten by Jim Meyering.  */
21
22 #include <config.h>
23
24 #include "posixtm.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <string.h>
30
31 #if USE_UNLOCKED_IO
32 # include "unlocked-io.h"
33 #endif
34
35 /* ISDIGIT differs from isdigit, as follows:
36    - Its arg may be any int or unsigned int; it need not be an unsigned char
37      or EOF.
38    - It's typically faster.
39    POSIX says that only '0' through '9' are digits.  Prefer ISDIGIT to
40    isdigit unless it's important to use the locale's definition
41    of `digit' even when the host does not conform to POSIX.  */
42 #define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
43
44 time_t mktime ();
45
46 /*
47   POSIX requires:
48
49   touch -t [[CC]YY]mmddhhmm[.ss] FILE...
50     8, 10, or 12 digits, followed by optional .ss
51     (PDS_LEADING_YEAR | PDS_CENTURY | PDS_SECONDS)
52
53   touch mmddhhmm[YY] FILE... (obsoleted by POSIX 1003.1-2001)
54     8 or 10 digits, YY (if present) must be in the range 69-99
55     (PDS_TRAILING_YEAR | PDS_PRE_2000)
56
57   date mmddhhmm[[CC]YY]
58     8, 10, or 12 digits
59     (PDS_TRAILING_YEAR | PDS_CENTURY)
60
61 */
62
63 static int
64 year (struct tm *tm, const int *digit_pair, size_t n, unsigned int syntax_bits)
65 {
66   switch (n)
67     {
68     case 1:
69       tm->tm_year = *digit_pair;
70       /* Deduce the century based on the year.
71          POSIX requires that 00-68 be interpreted as 2000-2068,
72          and that 69-99 be interpreted as 1969-1999.  */
73       if (digit_pair[0] <= 68)
74         {
75           if (syntax_bits & PDS_PRE_2000)
76             return 1;
77           tm->tm_year += 100;
78         }
79       break;
80
81     case 2:
82       if (! (syntax_bits & PDS_CENTURY))
83         return 1;
84       tm->tm_year = digit_pair[0] * 100 + digit_pair[1] - 1900;
85       break;
86
87     case 0:
88       {
89         time_t now;
90         struct tm *tmp;
91
92         /* Use current year.  */
93         time (&now);
94         tmp = localtime (&now);
95         if (! tmp)
96           return 1;
97         tm->tm_year = tmp->tm_year;
98       }
99       break;
100
101     default:
102       abort ();
103     }
104
105   return 0;
106 }
107
108 static int
109 posix_time_parse (struct tm *tm, const char *s, unsigned int syntax_bits)
110 {
111   const char *dot = NULL;
112   int pair[6];
113   int *p;
114   size_t i;
115
116   size_t s_len = strlen (s);
117   size_t len = (((syntax_bits & PDS_SECONDS) && (dot = strchr (s, '.')))
118                 ? (size_t) (dot - s)
119                 : s_len);
120
121   if (len != 8 && len != 10 && len != 12)
122     return 1;
123
124   if (dot)
125     {
126       if (!(syntax_bits & PDS_SECONDS))
127         return 1;
128
129       if (s_len - len != 3)
130         return 1;
131     }
132
133   for (i = 0; i < len; i++)
134     if (!ISDIGIT (s[i]))
135       return 1;
136
137   len /= 2;
138   for (i = 0; i < len; i++)
139     pair[i] = 10 * (s[2*i] - '0') + s[2*i + 1] - '0';
140
141   p = pair;
142   if (syntax_bits & PDS_LEADING_YEAR)
143     {
144       if (year (tm, p, len - 4, syntax_bits))
145         return 1;
146       p += len - 4;
147       len = 4;
148     }
149
150   /* Handle 8 digits worth of `MMDDhhmm'.  */
151   tm->tm_mon = *p++ - 1;
152   tm->tm_mday = *p++;
153   tm->tm_hour = *p++;
154   tm->tm_min = *p++;
155   len -= 4;
156
157   /* Handle any trailing year.  */
158   if (syntax_bits & PDS_TRAILING_YEAR)
159     {
160       if (year (tm, p, len, syntax_bits))
161         return 1;
162     }
163
164   /* Handle seconds.  */
165   if (!dot)
166     {
167       tm->tm_sec = 0;
168     }
169   else
170     {
171       int seconds;
172
173       ++dot;
174       if (!ISDIGIT (dot[0]) || !ISDIGIT (dot[1]))
175         return 1;
176       seconds = 10 * (dot[0] - '0') + dot[1] - '0';
177
178       tm->tm_sec = seconds;
179     }
180
181   return 0;
182 }
183
184 /* Parse a POSIX-style date, returning true if successful.  */
185
186 bool
187 posixtime (time_t *p, const char *s, unsigned int syntax_bits)
188 {
189   struct tm tm0
190 #ifdef lint
191   /* Placate gcc-4's -Wuninitialized.
192      posix_time_parse fails to set all of tm0 only when it returns
193      nonzero (due to year() returning nonzero), and in that case,
194      this code doesn't use the tm0 at all.  */
195     = { 0, }
196 #endif
197     ;
198   struct tm tm1;
199   struct tm const *tm;
200   time_t t;
201
202   if (posix_time_parse (&tm0, s, syntax_bits))
203     return false;
204
205   tm1 = tm0;
206   tm1.tm_isdst = -1;
207   t = mktime (&tm1);
208
209   if (t != (time_t) -1)
210     tm = &tm1;
211   else
212     {
213       /* mktime returns -1 for errors, but -1 is also a valid time_t
214          value.  Check whether an error really occurred.  */
215       tm = localtime (&t);
216       if (! tm)
217         return false;
218     }
219
220   /* Reject dates like "September 31" and times like "25:61".  */
221   if ((tm0.tm_year ^ tm->tm_year)
222       | (tm0.tm_mon ^ tm->tm_mon)
223       | (tm0.tm_mday ^ tm->tm_mday)
224       | (tm0.tm_hour ^ tm->tm_hour)
225       | (tm0.tm_min ^ tm->tm_min)
226       | (tm0.tm_sec ^ tm->tm_sec))
227     return false;
228
229   *p = t;
230   return true;
231 }
232
233 #ifdef TEST_POSIXTIME
234 /*
235     Test mainly with syntax_bits == 13
236     (aka: (PDS_LEADING_YEAR | PDS_CENTURY | PDS_SECONDS))
237
238     This test data assumes Universal Time, e.g., TZ="UTC0".
239
240     This test data also assumes that time_t is signed and is at least
241     39 bits wide, so that it can represent all years from 0000 through
242     9999.  A host with 32-bit signed time_t can represent only time
243     stamps in the range 1901-12-13 20:45:52 through 2038-01-18
244     03:14:07 UTC, assuming POSIX time_t with no leap seconds, so test
245     cases outside this range will not work on such a host.
246
247     Also, the first two lines of test data assume that the current
248     year is 2002.
249
250 BEGIN-DATA
251 12131415.16     13   1039788916 Fri Dec 13 14:15:16 2002
252 12131415.16     13   1039788916 Fri Dec 13 14:15:16 2002
253 000001010000.00 13 -62167132800 Sun Jan  1 00:00:00 0000
254 190112132045.52 13  -2147483648 Fri Dec 13 20:45:52 1901
255 190112132045.53 13  -2147483647 Fri Dec 13 20:45:53 1901
256 190112132046.52 13  -2147483588 Fri Dec 13 20:46:52 1901
257 190112132145.52 13  -2147480048 Fri Dec 13 21:45:52 1901
258 190112142045.52 13  -2147397248 Sat Dec 14 20:45:52 1901
259 190201132045.52 13  -2144805248 Mon Jan 13 20:45:52 1902
260 196912312359.59 13           -1 Wed Dec 31 23:59:59 1969
261 197001010000.00 13            0 Thu Jan  1 00:00:00 1970
262 197001010000.01 13            1 Thu Jan  1 00:00:01 1970
263 197001010001.00 13           60 Thu Jan  1 00:01:00 1970
264 197001010100.00 13         3600 Thu Jan  1 01:00:00 1970
265 197001020000.00 13        86400 Fri Jan  2 00:00:00 1970
266 197002010000.00 13      2678400 Sun Feb  1 00:00:00 1970
267 197101010000.00 13     31536000 Fri Jan  1 00:00:00 1971
268 197001000000.00 13            * *
269 197000010000.00 13            * *
270 197001010000.60 13            * *
271 197001010060.00 13            * *
272 197001012400.00 13            * *
273 197001320000.00 13            * *
274 197013010000.00 13            * *
275 203801190314.06 13   2147483646 Tue Jan 19 03:14:06 2038
276 203801190314.07 13   2147483647 Tue Jan 19 03:14:07 2038
277 203801190314.08 13   2147483648 Tue Jan 19 03:14:08 2038
278 999912312359.59 13 253402300799 Fri Dec 31 23:59:59 9999
279 1112131415      13   1323785700 Tue Dec 13 14:15:00 2011
280 1112131415.16   13   1323785716 Tue Dec 13 14:15:16 2011
281 201112131415.16 13   1323785716 Tue Dec 13 14:15:16 2011
282 191112131415.16 13  -1831974284 Wed Dec 13 14:15:16 1911
283 203712131415.16 13   2144326516 Sun Dec 13 14:15:16 2037
284 3712131415.16   13   2144326516 Sun Dec 13 14:15:16 2037
285 6812131415.16   13   3122633716 Thu Dec 13 14:15:16 2068
286 6912131415.16   13     -1590284 Sat Dec 13 14:15:16 1969
287 7012131415.16   13     29945716 Sun Dec 13 14:15:16 1970
288 1213141599       2    945094500 Mon Dec 13 14:15:00 1999
289 1213141500       2    976716900 Wed Dec 13 14:15:00 2000
290 END-DATA
291
292 */
293
294 # define MAX_BUFF_LEN 1024
295
296 int
297 main (void)
298 {
299   char buff[MAX_BUFF_LEN + 1];
300
301   buff[MAX_BUFF_LEN] = 0;
302   while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0])
303     {
304       char time_str[MAX_BUFF_LEN];
305       unsigned int syntax_bits;
306       time_t t;
307       if (sscanf (buff, "%s %u", time_str, &syntax_bits) != 2)
308         printf ("*\n");
309       else
310         {
311           printf ("%-15s %2u ", time_str, syntax_bits);
312           if (posixtime (&t, time_str, syntax_bits))
313             printf ("%12ld %s", (long int) t, ctime (&t));
314           else
315             printf ("%12s %s", "*", "*\n");
316         }
317     }
318   exit (0);
319
320 }
321 #endif
322 \f
323 /*
324 Local Variables:
325 compile-command: "gcc -DTEST_POSIXTIME -g -O -Wall -W posixtm.c"
326 End:
327 */