Annotation of /trunk/mkinitrd-magellan/busybox/coreutils/date.c
Parent Directory | Revision Log
Revision 816 -
(hide annotations)
(download)
Fri Apr 24 18:33:46 2009 UTC (15 years, 5 months ago) by niro
File MIME type: text/plain
File size: 6801 byte(s)
Fri Apr 24 18:33:46 2009 UTC (15 years, 5 months ago) by niro
File MIME type: text/plain
File size: 6801 byte(s)
-updated to busybox-1.13.4
1 | niro | 532 | /* 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 | niro | 816 | * bugfixes and cleanup by Bernhard Reutner-Fischer |
9 | niro | 532 | * |
10 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
11 | */ | ||
12 | |||
13 | niro | 816 | #include "libbb.h" |
14 | niro | 532 | |
15 | /* This 'date' command supports only 2 time setting formats, | ||
16 | all the GNU strftime stuff (its in libc, lets use it), | ||
17 | setting time using UTC and displaying it, as well as | ||
18 | an RFC 2822 compliant date output for shell scripting | ||
19 | mail commands */ | ||
20 | |||
21 | /* Input parsing code is always bulky - used heavy duty libc stuff as | ||
22 | much as possible, missed out a lot of bounds checking */ | ||
23 | |||
24 | /* Default input handling to save surprising some people */ | ||
25 | |||
26 | |||
27 | #define DATE_OPT_RFC2822 0x01 | ||
28 | #define DATE_OPT_SET 0x02 | ||
29 | #define DATE_OPT_UTC 0x04 | ||
30 | #define DATE_OPT_DATE 0x08 | ||
31 | #define DATE_OPT_REFERENCE 0x10 | ||
32 | #define DATE_OPT_TIMESPEC 0x20 | ||
33 | #define DATE_OPT_HINT 0x40 | ||
34 | |||
35 | static void maybe_set_utc(int opt) | ||
36 | { | ||
37 | if (opt & DATE_OPT_UTC) | ||
38 | niro | 816 | putenv((char*)"TZ=UTC0"); |
39 | niro | 532 | } |
40 | |||
41 | niro | 816 | int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
42 | int date_main(int argc UNUSED_PARAM, char **argv) | ||
43 | niro | 532 | { |
44 | niro | 816 | struct tm tm_time; |
45 | niro | 532 | time_t tm; |
46 | unsigned opt; | ||
47 | int ifmt = -1; | ||
48 | niro | 816 | char *date_str; |
49 | char *fmt_dt2str; | ||
50 | char *fmt_str2dt; | ||
51 | char *filename; | ||
52 | char *isofmt_arg = NULL; | ||
53 | niro | 532 | |
54 | niro | 816 | opt_complementary = "d--s:s--d" |
55 | niro | 532 | USE_FEATURE_DATE_ISOFMT(":R--I:I--R"); |
56 | niro | 816 | opt = getopt32(argv, "Rs:ud:r:" |
57 | niro | 532 | USE_FEATURE_DATE_ISOFMT("I::D:"), |
58 | &date_str, &date_str, &filename | ||
59 | niro | 816 | USE_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt)); |
60 | argv += optind; | ||
61 | niro | 532 | maybe_set_utc(opt); |
62 | |||
63 | if (ENABLE_FEATURE_DATE_ISOFMT && (opt & DATE_OPT_TIMESPEC)) { | ||
64 | niro | 816 | ifmt = 0; /* default is date */ |
65 | if (isofmt_arg) { | ||
66 | static const char isoformats[] ALIGN1 = | ||
67 | "date\0""hours\0""minutes\0""seconds\0"; | ||
68 | ifmt = index_in_strings(isoformats, isofmt_arg); | ||
69 | if (ifmt < 0) | ||
70 | niro | 532 | bb_show_usage(); |
71 | } | ||
72 | } | ||
73 | |||
74 | niro | 816 | fmt_dt2str = NULL; |
75 | if (argv[0] && argv[0][0] == '+') { | ||
76 | fmt_dt2str = &argv[0][1]; /* Skip over the '+' */ | ||
77 | argv++; | ||
78 | } | ||
79 | if (!(opt & (DATE_OPT_SET | DATE_OPT_DATE))) { | ||
80 | niro | 532 | opt |= DATE_OPT_SET; |
81 | niro | 816 | date_str = argv[0]; /* can be NULL */ |
82 | if (date_str) | ||
83 | argv++; | ||
84 | niro | 532 | } |
85 | niro | 816 | if (*argv) |
86 | bb_show_usage(); | ||
87 | niro | 532 | |
88 | /* Now we have parsed all the information except the date format | ||
89 | which depends on whether the clock is being set or read */ | ||
90 | |||
91 | niro | 816 | if (opt & DATE_OPT_REFERENCE) { |
92 | niro | 532 | struct stat statbuf; |
93 | xstat(filename, &statbuf); | ||
94 | tm = statbuf.st_mtime; | ||
95 | } else | ||
96 | time(&tm); | ||
97 | memcpy(&tm_time, localtime(&tm), sizeof(tm_time)); | ||
98 | niro | 816 | |
99 | /* If date string is given, update tm_time, and maybe set date */ | ||
100 | niro | 532 | if (date_str != NULL) { |
101 | niro | 816 | /* Zero out fields - take her back to midnight! */ |
102 | niro | 532 | tm_time.tm_sec = 0; |
103 | tm_time.tm_min = 0; | ||
104 | tm_time.tm_hour = 0; | ||
105 | |||
106 | /* Process any date input to UNIX time since 1 Jan 1970 */ | ||
107 | if (ENABLE_FEATURE_DATE_ISOFMT && (opt & DATE_OPT_HINT)) { | ||
108 | niro | 816 | if (strptime(date_str, fmt_str2dt, &tm_time) == NULL) |
109 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); | ||
110 | } else { | ||
111 | char end = '\0'; | ||
112 | const char *last_colon = strrchr(date_str, ':'); | ||
113 | niro | 532 | |
114 | niro | 816 | if (last_colon != NULL) { |
115 | /* Parse input and assign appropriately to tm_time */ | ||
116 | |||
117 | if (sscanf(date_str, "%u:%u%c", | ||
118 | &tm_time.tm_hour, | ||
119 | &tm_time.tm_min, | ||
120 | &end) >= 2) { | ||
121 | /* no adjustments needed */ | ||
122 | } else if (sscanf(date_str, "%u.%u-%u:%u%c", | ||
123 | niro | 532 | &tm_time.tm_mon, &tm_time.tm_mday, |
124 | &tm_time.tm_hour, &tm_time.tm_min, | ||
125 | niro | 816 | &end) >= 4) { |
126 | /* Adjust dates from 1-12 to 0-11 */ | ||
127 | tm_time.tm_mon -= 1; | ||
128 | } else if (sscanf(date_str, "%u.%u.%u-%u:%u%c", &tm_time.tm_year, | ||
129 | niro | 532 | &tm_time.tm_mon, &tm_time.tm_mday, |
130 | niro | 816 | &tm_time.tm_hour, &tm_time.tm_min, |
131 | &end) >= 5) { | ||
132 | tm_time.tm_year -= 1900; /* Adjust years */ | ||
133 | tm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ | ||
134 | } else if (sscanf(date_str, "%u-%u-%u %u:%u%c", &tm_time.tm_year, | ||
135 | &tm_time.tm_mon, &tm_time.tm_mday, | ||
136 | &tm_time.tm_hour, &tm_time.tm_min, | ||
137 | &end) >= 5) { | ||
138 | tm_time.tm_year -= 1900; /* Adjust years */ | ||
139 | tm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ | ||
140 | //TODO: coreutils 6.9 also accepts "YYYY-MM-DD HH" (no minutes) | ||
141 | } else { | ||
142 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); | ||
143 | } | ||
144 | if (end == ':') { | ||
145 | if (sscanf(last_colon + 1, "%u%c", &tm_time.tm_sec, &end) == 1) | ||
146 | end = '\0'; | ||
147 | /* else end != NUL and we error out */ | ||
148 | } | ||
149 | niro | 532 | } else { |
150 | niro | 816 | if (sscanf(date_str, "%2u%2u%2u%2u%u%c", &tm_time.tm_mon, |
151 | &tm_time.tm_mday, &tm_time.tm_hour, &tm_time.tm_min, | ||
152 | &tm_time.tm_year, &end) < 4) | ||
153 | niro | 532 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); |
154 | niro | 816 | /* correct for century - minor Y2K problem here? */ |
155 | if (tm_time.tm_year >= 1900) { | ||
156 | tm_time.tm_year -= 1900; | ||
157 | niro | 532 | } |
158 | niro | 816 | /* adjust date */ |
159 | tm_time.tm_mon -= 1; | ||
160 | if (end == '.') { | ||
161 | if (sscanf(strchr(date_str, '.') + 1, "%u%c", | ||
162 | &tm_time.tm_sec, &end) == 1) | ||
163 | end = '\0'; | ||
164 | /* else end != NUL and we error out */ | ||
165 | } | ||
166 | niro | 532 | } |
167 | niro | 816 | if (end != '\0') { |
168 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); | ||
169 | niro | 532 | } |
170 | } | ||
171 | /* Correct any day of week and day of year etc. fields */ | ||
172 | tm_time.tm_isdst = -1; /* Be sure to recheck dst. */ | ||
173 | tm = mktime(&tm_time); | ||
174 | if (tm < 0) { | ||
175 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); | ||
176 | } | ||
177 | maybe_set_utc(opt); | ||
178 | |||
179 | /* if setting time, set it */ | ||
180 | if ((opt & DATE_OPT_SET) && stime(&tm) < 0) { | ||
181 | bb_perror_msg("cannot set date"); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | /* Display output */ | ||
186 | |||
187 | /* Deal with format string */ | ||
188 | niro | 816 | if (fmt_dt2str == NULL) { |
189 | niro | 532 | int i; |
190 | niro | 816 | fmt_dt2str = xzalloc(32); |
191 | niro | 532 | if (ENABLE_FEATURE_DATE_ISOFMT && ifmt >= 0) { |
192 | niro | 816 | strcpy(fmt_dt2str, "%Y-%m-%d"); |
193 | niro | 532 | if (ifmt > 0) { |
194 | i = 8; | ||
195 | niro | 816 | fmt_dt2str[i++] = 'T'; |
196 | fmt_dt2str[i++] = '%'; | ||
197 | fmt_dt2str[i++] = 'H'; | ||
198 | niro | 532 | if (ifmt > 1) { |
199 | niro | 816 | fmt_dt2str[i++] = ':'; |
200 | fmt_dt2str[i++] = '%'; | ||
201 | fmt_dt2str[i++] = 'M'; | ||
202 | if (ifmt > 2) { | ||
203 | fmt_dt2str[i++] = ':'; | ||
204 | fmt_dt2str[i++] = '%'; | ||
205 | fmt_dt2str[i++] = 'S'; | ||
206 | } | ||
207 | niro | 532 | } |
208 | niro | 816 | format_utc: |
209 | fmt_dt2str[i++] = '%'; | ||
210 | fmt_dt2str[i] = (opt & DATE_OPT_UTC) ? 'Z' : 'z'; | ||
211 | niro | 532 | } |
212 | } else if (opt & DATE_OPT_RFC2822) { | ||
213 | /* Undo busybox.c for date -R */ | ||
214 | if (ENABLE_LOCALE_SUPPORT) | ||
215 | setlocale(LC_TIME, "C"); | ||
216 | niro | 816 | strcpy(fmt_dt2str, "%a, %d %b %Y %H:%M:%S "); |
217 | niro | 532 | i = 22; |
218 | goto format_utc; | ||
219 | } else /* default case */ | ||
220 | niro | 816 | fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y"; |
221 | niro | 532 | } |
222 | |||
223 | niro | 816 | #define date_buf bb_common_bufsiz1 |
224 | if (*fmt_dt2str == '\0') { | ||
225 | niro | 532 | /* With no format string, just print a blank line */ |
226 | niro | 816 | date_buf[0] = '\0'; |
227 | niro | 532 | } else { |
228 | /* Handle special conversions */ | ||
229 | niro | 816 | if (strncmp(fmt_dt2str, "%f", 2) == 0) { |
230 | fmt_dt2str = (char*)"%Y.%m.%d-%H:%M:%S"; | ||
231 | niro | 532 | } |
232 | |||
233 | /* Generate output string */ | ||
234 | niro | 816 | strftime(date_buf, sizeof(date_buf), fmt_dt2str, &tm_time); |
235 | niro | 532 | } |
236 | niro | 816 | puts(date_buf); |
237 | niro | 532 | |
238 | return EXIT_SUCCESS; | ||
239 | } |