diff options
Diffstat (limited to 'busybox/coreutils/date.c')
-rw-r--r-- | busybox/coreutils/date.c | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/busybox/coreutils/date.c b/busybox/coreutils/date.c new file mode 100644 index 000000000..3608df69f --- /dev/null +++ b/busybox/coreutils/date.c | |||
@@ -0,0 +1,292 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Mini date implementation for busybox | ||
4 | * | ||
5 | * by Matthew Grant <grantma@anathoth.gen.nz> | ||
6 | * | ||
7 | * iso-format handling added by Robert Griebl <griebl@gmx.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <stdlib.h> | ||
26 | #include <errno.h> | ||
27 | #include <sys/time.h> | ||
28 | #include <unistd.h> | ||
29 | #include <time.h> | ||
30 | #include <stdio.h> | ||
31 | #include <string.h> | ||
32 | #include <getopt.h> | ||
33 | #include "busybox.h" | ||
34 | |||
35 | |||
36 | /* This 'date' command supports only 2 time setting formats, | ||
37 | all the GNU strftime stuff (its in libc, lets use it), | ||
38 | setting time using UTC and displaying int, as well as | ||
39 | an RFC 822 complient date output for shell scripting | ||
40 | mail commands */ | ||
41 | |||
42 | /* Input parsing code is always bulky - used heavy duty libc stuff as | ||
43 | much as possible, missed out a lot of bounds checking */ | ||
44 | |||
45 | /* Default input handling to save surprising some people */ | ||
46 | |||
47 | static struct tm *date_conv_time(struct tm *tm_time, const char *t_string) | ||
48 | { | ||
49 | int nr; | ||
50 | char *cp; | ||
51 | |||
52 | nr = sscanf(t_string, "%2d%2d%2d%2d%d", &(tm_time->tm_mon), | ||
53 | &(tm_time->tm_mday), &(tm_time->tm_hour), &(tm_time->tm_min), | ||
54 | &(tm_time->tm_year)); | ||
55 | |||
56 | if (nr < 4 || nr > 5) { | ||
57 | bb_error_msg_and_die(bb_msg_invalid_date, t_string); | ||
58 | } | ||
59 | |||
60 | cp = strchr(t_string, '.'); | ||
61 | if (cp) { | ||
62 | nr = sscanf(cp + 1, "%2d", &(tm_time->tm_sec)); | ||
63 | if (nr != 1) { | ||
64 | bb_error_msg_and_die(bb_msg_invalid_date, t_string); | ||
65 | } | ||
66 | } | ||
67 | |||
68 | /* correct for century - minor Y2K problem here? */ | ||
69 | if (tm_time->tm_year >= 1900) { | ||
70 | tm_time->tm_year -= 1900; | ||
71 | } | ||
72 | /* adjust date */ | ||
73 | tm_time->tm_mon -= 1; | ||
74 | |||
75 | return (tm_time); | ||
76 | |||
77 | } | ||
78 | |||
79 | |||
80 | /* The new stuff for LRP */ | ||
81 | |||
82 | static struct tm *date_conv_ftime(struct tm *tm_time, const char *t_string) | ||
83 | { | ||
84 | struct tm t; | ||
85 | |||
86 | /* Parse input and assign appropriately to tm_time */ | ||
87 | |||
88 | if (t = | ||
89 | *tm_time, sscanf(t_string, "%d:%d:%d", &t.tm_hour, &t.tm_min, | ||
90 | &t.tm_sec) == 3) { | ||
91 | /* no adjustments needed */ | ||
92 | } else if (t = | ||
93 | *tm_time, sscanf(t_string, "%d:%d", &t.tm_hour, | ||
94 | &t.tm_min) == 2) { | ||
95 | /* no adjustments needed */ | ||
96 | } else if (t = | ||
97 | *tm_time, sscanf(t_string, "%d.%d-%d:%d:%d", &t.tm_mon, | ||
98 | &t.tm_mday, &t.tm_hour, &t.tm_min, | ||
99 | &t.tm_sec) == 5) { | ||
100 | /* Adjust dates from 1-12 to 0-11 */ | ||
101 | t.tm_mon -= 1; | ||
102 | } else if (t = | ||
103 | *tm_time, sscanf(t_string, "%d.%d-%d:%d", &t.tm_mon, | ||
104 | &t.tm_mday, &t.tm_hour, &t.tm_min) == 4) { | ||
105 | /* Adjust dates from 1-12 to 0-11 */ | ||
106 | t.tm_mon -= 1; | ||
107 | } else if (t = | ||
108 | *tm_time, sscanf(t_string, "%d.%d.%d-%d:%d:%d", &t.tm_year, | ||
109 | &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, | ||
110 | &t.tm_sec) == 6) { | ||
111 | t.tm_year -= 1900; /* Adjust years */ | ||
112 | t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ | ||
113 | } else if (t = | ||
114 | *tm_time, sscanf(t_string, "%d.%d.%d-%d:%d", &t.tm_year, | ||
115 | &t.tm_mon, &t.tm_mday, &t.tm_hour, | ||
116 | &t.tm_min) == 5) { | ||
117 | t.tm_year -= 1900; /* Adjust years */ | ||
118 | t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ | ||
119 | } else { | ||
120 | bb_error_msg_and_die(bb_msg_invalid_date, t_string); | ||
121 | } | ||
122 | *tm_time = t; | ||
123 | return (tm_time); | ||
124 | } | ||
125 | |||
126 | #define DATE_OPT_RFC2822 0x01 | ||
127 | #define DATE_OPT_SET 0x02 | ||
128 | #define DATE_OPT_UTC 0x04 | ||
129 | #define DATE_OPT_DATE 0x08 | ||
130 | #define DATE_OPT_REFERENCE 0x10 | ||
131 | #ifdef CONFIG_FEATURE_DATE_ISOFMT | ||
132 | # define DATE_OPT_TIMESPEC 0x20 | ||
133 | #endif | ||
134 | |||
135 | int date_main(int argc, char **argv) | ||
136 | { | ||
137 | char *date_str = NULL; | ||
138 | char *date_fmt = NULL; | ||
139 | char *t_buff; | ||
140 | int set_time; | ||
141 | int utc; | ||
142 | int use_arg = 0; | ||
143 | time_t tm; | ||
144 | unsigned long opt; | ||
145 | struct tm tm_time; | ||
146 | char *filename = NULL; | ||
147 | |||
148 | #ifdef CONFIG_FEATURE_DATE_ISOFMT | ||
149 | int ifmt = 0; | ||
150 | char *isofmt_arg; | ||
151 | |||
152 | # define GETOPT_ISOFMT "I::" | ||
153 | #else | ||
154 | # define GETOPT_ISOFMT | ||
155 | #endif | ||
156 | bb_opt_complementaly = "d~ds:s~ds"; | ||
157 | opt = bb_getopt_ulflags(argc, argv, "Rs:ud:r:" GETOPT_ISOFMT, | ||
158 | &date_str, &date_str, &filename | ||
159 | #ifdef CONFIG_FEATURE_DATE_ISOFMT | ||
160 | , &isofmt_arg | ||
161 | #endif | ||
162 | ); | ||
163 | set_time = opt & DATE_OPT_SET; | ||
164 | utc = opt & DATE_OPT_UTC; | ||
165 | if ((utc) && (putenv("TZ=UTC0") != 0)) { | ||
166 | bb_error_msg_and_die(bb_msg_memory_exhausted); | ||
167 | } | ||
168 | use_arg = opt & DATE_OPT_DATE; | ||
169 | if(opt & 0x80000000UL) | ||
170 | bb_show_usage(); | ||
171 | #ifdef CONFIG_FEATURE_DATE_ISOFMT | ||
172 | if(opt & DATE_OPT_TIMESPEC) { | ||
173 | if (!isofmt_arg) { | ||
174 | ifmt = 1; | ||
175 | } else { | ||
176 | int ifmt_len = bb_strlen(isofmt_arg); | ||
177 | |||
178 | if ((ifmt_len <= 4) | ||
179 | && (strncmp(isofmt_arg, "date", ifmt_len) == 0)) { | ||
180 | ifmt = 1; | ||
181 | } else if ((ifmt_len <= 5) | ||
182 | && (strncmp(isofmt_arg, "hours", ifmt_len) == 0)) { | ||
183 | ifmt = 2; | ||
184 | } else if ((ifmt_len <= 7) | ||
185 | && (strncmp(isofmt_arg, "minutes", ifmt_len) == 0)) { | ||
186 | ifmt = 3; | ||
187 | } else if ((ifmt_len <= 7) | ||
188 | && (strncmp(isofmt_arg, "seconds", ifmt_len) == 0)) { | ||
189 | ifmt = 4; | ||
190 | } | ||
191 | } | ||
192 | if (!ifmt) { | ||
193 | bb_show_usage(); | ||
194 | } | ||
195 | } | ||
196 | #endif | ||
197 | |||
198 | if ((date_fmt == NULL) && (optind < argc) && (argv[optind][0] == '+')) { | ||
199 | date_fmt = &argv[optind][1]; /* Skip over the '+' */ | ||
200 | } else if (date_str == NULL) { | ||
201 | set_time = 1; | ||
202 | date_str = argv[optind]; | ||
203 | } | ||
204 | |||
205 | /* Now we have parsed all the information except the date format | ||
206 | which depends on whether the clock is being set or read */ | ||
207 | |||
208 | if(filename) { | ||
209 | struct stat statbuf; | ||
210 | if(stat(filename,&statbuf)) | ||
211 | bb_perror_msg_and_die("File '%s' not found.\n",filename); | ||
212 | tm=statbuf.st_mtime; | ||
213 | } else time(&tm); | ||
214 | memcpy(&tm_time, localtime(&tm), sizeof(tm_time)); | ||
215 | /* Zero out fields - take her back to midnight! */ | ||
216 | if (date_str != NULL) { | ||
217 | tm_time.tm_sec = 0; | ||
218 | tm_time.tm_min = 0; | ||
219 | tm_time.tm_hour = 0; | ||
220 | |||
221 | /* Process any date input to UNIX time since 1 Jan 1970 */ | ||
222 | if (strchr(date_str, ':') != NULL) { | ||
223 | date_conv_ftime(&tm_time, date_str); | ||
224 | } else { | ||
225 | date_conv_time(&tm_time, date_str); | ||
226 | } | ||
227 | |||
228 | /* Correct any day of week and day of year etc. fields */ | ||
229 | tm_time.tm_isdst = -1; /* Be sure to recheck dst. */ | ||
230 | tm = mktime(&tm_time); | ||
231 | if (tm < 0) { | ||
232 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); | ||
233 | } | ||
234 | if (utc && (putenv("TZ=UTC0") != 0)) { | ||
235 | bb_error_msg_and_die(bb_msg_memory_exhausted); | ||
236 | } | ||
237 | |||
238 | /* if setting time, set it */ | ||
239 | if (set_time && (stime(&tm) < 0)) { | ||
240 | bb_perror_msg("cannot set date"); | ||
241 | } | ||
242 | } | ||
243 | |||
244 | /* Display output */ | ||
245 | |||
246 | /* Deal with format string */ | ||
247 | if (date_fmt == NULL) { | ||
248 | #ifdef CONFIG_FEATURE_DATE_ISOFMT | ||
249 | switch (ifmt) { | ||
250 | case 4: | ||
251 | date_fmt = utc ? "%Y-%m-%dT%H:%M:%SZ" : "%Y-%m-%dT%H:%M:%S%z"; | ||
252 | break; | ||
253 | case 3: | ||
254 | date_fmt = utc ? "%Y-%m-%dT%H:%MZ" : "%Y-%m-%dT%H:%M%z"; | ||
255 | break; | ||
256 | case 2: | ||
257 | date_fmt = utc ? "%Y-%m-%dT%HZ" : "%Y-%m-%dT%H%z"; | ||
258 | break; | ||
259 | case 1: | ||
260 | date_fmt = "%Y-%m-%d"; | ||
261 | break; | ||
262 | case 0: | ||
263 | default: | ||
264 | #endif | ||
265 | date_fmt = (opt & DATE_OPT_RFC2822 ? | ||
266 | (utc ? "%a, %d %b %Y %H:%M:%S GMT" : | ||
267 | "%a, %d %b %Y %H:%M:%S %z") : | ||
268 | "%a %b %e %H:%M:%S %Z %Y"); | ||
269 | |||
270 | #ifdef CONFIG_FEATURE_DATE_ISOFMT | ||
271 | break; | ||
272 | } | ||
273 | #endif | ||
274 | } else if (*date_fmt == '\0') { | ||
275 | /* Imitate what GNU 'date' does with NO format string! */ | ||
276 | printf("\n"); | ||
277 | return EXIT_SUCCESS; | ||
278 | } | ||
279 | |||
280 | /* Handle special conversions */ | ||
281 | |||
282 | if (strncmp(date_fmt, "%f", 2) == 0) { | ||
283 | date_fmt = "%Y.%m.%d-%H:%M:%S"; | ||
284 | } | ||
285 | |||
286 | /* Print OUTPUT (after ALL that!) */ | ||
287 | t_buff = xmalloc(201); | ||
288 | strftime(t_buff, 200, date_fmt, &tm_time); | ||
289 | puts(t_buff); | ||
290 | |||
291 | return EXIT_SUCCESS; | ||
292 | } | ||