summaryrefslogtreecommitdiffstats
path: root/meta/recipes-extended/at/at/posixtm.c
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-extended/at/at/posixtm.c')
-rw-r--r--meta/recipes-extended/at/at/posixtm.c328
1 files changed, 328 insertions, 0 deletions
diff --git a/meta/recipes-extended/at/at/posixtm.c b/meta/recipes-extended/at/at/posixtm.c
new file mode 100644
index 0000000000..5514ba4fe2
--- /dev/null
+++ b/meta/recipes-extended/at/at/posixtm.c
@@ -0,0 +1,328 @@
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 2, or (at your option)
9 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, write to the Free Software Foundation,
18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19
20/* Yacc-based version written by Jim Kingdon and David MacKenzie.
21 Rewritten by Jim Meyering. */
22
23#include <config.h>
24
25#include "posixtm.h"
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <sys/types.h>
30#include <string.h>
31
32#if USE_UNLOCKED_IO
33# include "unlocked-io.h"
34#endif
35
36/* ISDIGIT differs from isdigit, as follows:
37 - Its arg may be any int or unsigned int; it need not be an unsigned char
38 or EOF.
39 - It's typically faster.
40 POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
41 isdigit unless it's important to use the locale's definition
42 of `digit' even when the host does not conform to POSIX. */
43#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
44
45time_t mktime ();
46
47/*
48 POSIX requires:
49
50 touch -t [[CC]YY]mmddhhmm[.ss] FILE...
51 8, 10, or 12 digits, followed by optional .ss
52 (PDS_LEADING_YEAR | PDS_CENTURY | PDS_SECONDS)
53
54 touch mmddhhmm[YY] FILE... (obsoleted by POSIX 1003.1-2001)
55 8 or 10 digits, YY (if present) must be in the range 69-99
56 (PDS_TRAILING_YEAR | PDS_PRE_2000)
57
58 date mmddhhmm[[CC]YY]
59 8, 10, or 12 digits
60 (PDS_TRAILING_YEAR | PDS_CENTURY)
61
62*/
63
64static int
65year (struct tm *tm, const int *digit_pair, size_t n, unsigned int syntax_bits)
66{
67 switch (n)
68 {
69 case 1:
70 tm->tm_year = *digit_pair;
71 /* Deduce the century based on the year.
72 POSIX requires that 00-68 be interpreted as 2000-2068,
73 and that 69-99 be interpreted as 1969-1999. */
74 if (digit_pair[0] <= 68)
75 {
76 if (syntax_bits & PDS_PRE_2000)
77 return 1;
78 tm->tm_year += 100;
79 }
80 break;
81
82 case 2:
83 if (! (syntax_bits & PDS_CENTURY))
84 return 1;
85 tm->tm_year = digit_pair[0] * 100 + digit_pair[1] - 1900;
86 break;
87
88 case 0:
89 {
90 time_t now;
91 struct tm *tmp;
92
93 /* Use current year. */
94 time (&now);
95 tmp = localtime (&now);
96 if (! tmp)
97 return 1;
98 tm->tm_year = tmp->tm_year;
99 }
100 break;
101
102 default:
103 abort ();
104 }
105
106 return 0;
107}
108
109static int
110posix_time_parse (struct tm *tm, const char *s, unsigned int syntax_bits)
111{
112 const char *dot = NULL;
113 int pair[6];
114 int *p;
115 size_t i;
116
117 size_t s_len = strlen (s);
118 size_t len = (((syntax_bits & PDS_SECONDS) && (dot = strchr (s, '.')))
119 ? (size_t) (dot - s)
120 : s_len);
121
122 if (len != 8 && len != 10 && len != 12)
123 return 1;
124
125 if (dot)
126 {
127 if (!(syntax_bits & PDS_SECONDS))
128 return 1;
129
130 if (s_len - len != 3)
131 return 1;
132 }
133
134 for (i = 0; i < len; i++)
135 if (!ISDIGIT (s[i]))
136 return 1;
137
138 len /= 2;
139 for (i = 0; i < len; i++)
140 pair[i] = 10 * (s[2*i] - '0') + s[2*i + 1] - '0';
141
142 p = pair;
143 if (syntax_bits & PDS_LEADING_YEAR)
144 {
145 if (year (tm, p, len - 4, syntax_bits))
146 return 1;
147 p += len - 4;
148 len = 4;
149 }
150
151 /* Handle 8 digits worth of `MMDDhhmm'. */
152 tm->tm_mon = *p++ - 1;
153 tm->tm_mday = *p++;
154 tm->tm_hour = *p++;
155 tm->tm_min = *p++;
156 len -= 4;
157
158 /* Handle any trailing year. */
159 if (syntax_bits & PDS_TRAILING_YEAR)
160 {
161 if (year (tm, p, len, syntax_bits))
162 return 1;
163 }
164
165 /* Handle seconds. */
166 if (!dot)
167 {
168 tm->tm_sec = 0;
169 }
170 else
171 {
172 int seconds;
173
174 ++dot;
175 if (!ISDIGIT (dot[0]) || !ISDIGIT (dot[1]))
176 return 1;
177 seconds = 10 * (dot[0] - '0') + dot[1] - '0';
178
179 tm->tm_sec = seconds;
180 }
181
182 return 0;
183}
184
185/* Parse a POSIX-style date, returning true if successful. */
186
187bool
188posixtime (time_t *p, const char *s, unsigned int syntax_bits)
189{
190 struct tm tm0
191#ifdef lint
192 /* Placate gcc-4's -Wuninitialized.
193 posix_time_parse fails to set all of tm0 only when it returns
194 nonzero (due to year() returning nonzero), and in that case,
195 this code doesn't use the tm0 at all. */
196 = { 0, }
197#endif
198 ;
199 struct tm tm1;
200 struct tm const *tm;
201 time_t t;
202
203 if (posix_time_parse (&tm0, s, syntax_bits))
204 return false;
205
206 tm1 = tm0;
207 tm1.tm_isdst = -1;
208 t = mktime (&tm1);
209
210 if (t != (time_t) -1)
211 tm = &tm1;
212 else
213 {
214 /* mktime returns -1 for errors, but -1 is also a valid time_t
215 value. Check whether an error really occurred. */
216 tm = localtime (&t);
217 if (! tm)
218 return false;
219 }
220
221 /* Reject dates like "September 31" and times like "25:61". */
222 if ((tm0.tm_year ^ tm->tm_year)
223 | (tm0.tm_mon ^ tm->tm_mon)
224 | (tm0.tm_mday ^ tm->tm_mday)
225 | (tm0.tm_hour ^ tm->tm_hour)
226 | (tm0.tm_min ^ tm->tm_min)
227 | (tm0.tm_sec ^ tm->tm_sec))
228 return false;
229
230 *p = t;
231 return true;
232}
233
234#ifdef TEST_POSIXTIME
235/*
236 Test mainly with syntax_bits == 13
237 (aka: (PDS_LEADING_YEAR | PDS_CENTURY | PDS_SECONDS))
238
239 This test data assumes Universal Time, e.g., TZ="UTC0".
240
241 This test data also assumes that time_t is signed and is at least
242 39 bits wide, so that it can represent all years from 0000 through
243 9999. A host with 32-bit signed time_t can represent only time
244 stamps in the range 1901-12-13 20:45:52 through 2038-01-18
245 03:14:07 UTC, assuming POSIX time_t with no leap seconds, so test
246 cases outside this range will not work on such a host.
247
248 Also, the first two lines of test data assume that the current
249 year is 2002.
250
251BEGIN-DATA
25212131415.16 13 1039788916 Fri Dec 13 14:15:16 2002
25312131415.16 13 1039788916 Fri Dec 13 14:15:16 2002
254000001010000.00 13 -62167132800 Sun Jan 1 00:00:00 0000
255190112132045.52 13 -2147483648 Fri Dec 13 20:45:52 1901
256190112132045.53 13 -2147483647 Fri Dec 13 20:45:53 1901
257190112132046.52 13 -2147483588 Fri Dec 13 20:46:52 1901
258190112132145.52 13 -2147480048 Fri Dec 13 21:45:52 1901
259190112142045.52 13 -2147397248 Sat Dec 14 20:45:52 1901
260190201132045.52 13 -2144805248 Mon Jan 13 20:45:52 1902
261196912312359.59 13 -1 Wed Dec 31 23:59:59 1969
262197001010000.00 13 0 Thu Jan 1 00:00:00 1970
263197001010000.01 13 1 Thu Jan 1 00:00:01 1970
264197001010001.00 13 60 Thu Jan 1 00:01:00 1970
265197001010100.00 13 3600 Thu Jan 1 01:00:00 1970
266197001020000.00 13 86400 Fri Jan 2 00:00:00 1970
267197002010000.00 13 2678400 Sun Feb 1 00:00:00 1970
268197101010000.00 13 31536000 Fri Jan 1 00:00:00 1971
269197001000000.00 13 * *
270197000010000.00 13 * *
271197001010000.60 13 * *
272197001010060.00 13 * *
273197001012400.00 13 * *
274197001320000.00 13 * *
275197013010000.00 13 * *
276203801190314.06 13 2147483646 Tue Jan 19 03:14:06 2038
277203801190314.07 13 2147483647 Tue Jan 19 03:14:07 2038
278203801190314.08 13 2147483648 Tue Jan 19 03:14:08 2038
279999912312359.59 13 253402300799 Fri Dec 31 23:59:59 9999
2801112131415 13 1323785700 Tue Dec 13 14:15:00 2011
2811112131415.16 13 1323785716 Tue Dec 13 14:15:16 2011
282201112131415.16 13 1323785716 Tue Dec 13 14:15:16 2011
283191112131415.16 13 -1831974284 Wed Dec 13 14:15:16 1911
284203712131415.16 13 2144326516 Sun Dec 13 14:15:16 2037
2853712131415.16 13 2144326516 Sun Dec 13 14:15:16 2037
2866812131415.16 13 3122633716 Thu Dec 13 14:15:16 2068
2876912131415.16 13 -1590284 Sat Dec 13 14:15:16 1969
2887012131415.16 13 29945716 Sun Dec 13 14:15:16 1970
2891213141599 2 945094500 Mon Dec 13 14:15:00 1999
2901213141500 2 976716900 Wed Dec 13 14:15:00 2000
291END-DATA
292
293*/
294
295# define MAX_BUFF_LEN 1024
296
297int
298main (void)
299{
300 char buff[MAX_BUFF_LEN + 1];
301
302 buff[MAX_BUFF_LEN] = 0;
303 while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0])
304 {
305 char time_str[MAX_BUFF_LEN];
306 unsigned int syntax_bits;
307 time_t t;
308 if (sscanf (buff, "%s %u", time_str, &syntax_bits) != 2)
309 printf ("*\n");
310 else
311 {
312 printf ("%-15s %2u ", time_str, syntax_bits);
313 if (posixtime (&t, time_str, syntax_bits))
314 printf ("%12ld %s", (long int) t, ctime (&t));
315 else
316 printf ("%12s %s", "*", "*\n");
317 }
318 }
319 exit (0);
320
321}
322#endif
323
324/*
325Local Variables:
326compile-command: "gcc -DTEST_POSIXTIME -g -O -Wall -W posixtm.c"
327End:
328*/