blob: 5585170864ff661fdf1640cb5f88bb74709a54d1 [file] [log] [blame]
Eric Andersencc8ed391999-10-05 16:24:54 +00001#include "internal.h"
2#include <stdlib.h>
3#include <errno.h>
4#include <sys/time.h>
5#include <unistd.h>
6#include <time.h>
7#include <stdio.h>
8#include <getopt.h>
9
10
11/* This 'date' command supports only 2 time setting formats,
12 all the GNU strftime stuff (its in libc, lets use it),
13 setting time using UTC and displaying int, as well as
14 an RFC 822 complient date output for shell scripting
15 mail commands */
16
Eric Andersen4bea32a1999-10-06 00:30:51 +000017const char date_usage[] = "date [-uR] [+FORMAT|+%f] [ [-s|-d] MMDDhhmm[[CC]YY]\n"
18"| [[[[CCYY.]MM.DD-]hh:mm[:ss]]]] ]";
19
20//static const char date_usage[] = "Usage: date [OPTION]... [+FORMAT]\n"
21//"or: date [OPTION] [MMDDhhmm[[CC]YY][.ss]]\n"
22//"Display the current time in the given FORMAT, or set the system date.\n";
23
Eric Andersencc8ed391999-10-05 16:24:54 +000024
25static struct option const long_options[] =
26{
27 {"date", required_argument, NULL, 'd'},
28 /* {"rfc-822", no_argument, NULL, 'R'},
29 {"set", required_argument, NULL, 's'},
30 {"uct", no_argument, NULL, 'u'},
31 {"utc", no_argument, NULL, 'u'},
32 {"universal", no_argument, NULL, 'u'}, */
33 {NULL, 0, NULL, 0}
34};
35
36
37
38/* Input parsing code is always bulky - used heavy duty libc stuff as
39 much as possible, missed out a lot of bounds checking */
40
41/* Default input handling to save suprising some people */
42
43struct tm *
44date_conv_time(struct tm *tm_time, const char *t_string) {
45 int nr;
46
47 nr = sscanf(t_string, "%2d%2d%2d%2d%d",
48 &(tm_time->tm_mon),
49 &(tm_time->tm_mday),
50 &(tm_time->tm_hour),
51 &(tm_time->tm_min),
52 &(tm_time->tm_year));
53
54 if(nr < 4 || nr > 5) {
55 fprintf(stderr, "date: invalid date `%s'\n", t_string);
56 exit(1);
57 }
58
59 /* correct for century - minor Y2K problem here? */
60 if(tm_time->tm_year >= 1900)
61 tm_time->tm_year -= 1900;
62 /* adjust date */
63 tm_time->tm_mon -= 1;
64
65 return(tm_time);
66
67}
68
69
70/* The new stuff for LRP */
71
72struct tm *
73date_conv_ftime(struct tm *tm_time, const char *t_string) {
74 struct tm itm_time, jtm_time, ktm_time, \
75 ltm_time, mtm_time, ntm_time;
76
77 itm_time = *tm_time;
78 jtm_time = *tm_time;
79 ktm_time = *tm_time;
80 ltm_time = *tm_time;
81 mtm_time = *tm_time;
82 ntm_time = *tm_time;
83
84 /* Parse input and assign appropriately to tm_time */
85
86 if(sscanf(t_string, "%d:%d:%d",
87 &itm_time.tm_hour,
88 &itm_time.tm_min,
89 &itm_time.tm_sec) == 3 ) {
90
91 *tm_time = itm_time;
92 return(tm_time);
93
94 } else if (sscanf(t_string, "%d:%d",
95 &jtm_time.tm_hour,
96 &jtm_time.tm_min) == 2) {
97
98 *tm_time = jtm_time;
99 return(tm_time);
100
101 } else if (sscanf(t_string, "%d.%d-%d:%d:%d",
102 &ktm_time.tm_mon,
103 &ktm_time.tm_mday,
104 &ktm_time.tm_hour,
105 &ktm_time.tm_min,
106 &ktm_time.tm_sec) == 5) {
107
108 ktm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
109 *tm_time = ktm_time;
110 return(tm_time);
111
112 } else if (sscanf(t_string, "%d.%d-%d:%d",
113 &ltm_time.tm_mon,
114 &ltm_time.tm_mday,
115 &ltm_time.tm_hour,
116 &ltm_time.tm_min) == 4) {
117
118 ltm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
119 *tm_time = ltm_time;
120 return(tm_time);
121
122 } else if (sscanf(t_string, "%d.%d.%d-%d:%d:%d",
123 &mtm_time.tm_year,
124 &mtm_time.tm_mon,
125 &mtm_time.tm_mday,
126 &mtm_time.tm_hour,
127 &mtm_time.tm_min,
128 &mtm_time.tm_sec) == 6) {
129
130 mtm_time.tm_year -= 1900; /* Adjust years */
131 mtm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
132 *tm_time = mtm_time;
133 return(tm_time);
134
135 } else if (sscanf(t_string, "%d.%d.%d-%d:%d",
136 &ntm_time.tm_year,
137 &ntm_time.tm_mon,
138 &ntm_time.tm_mday,
139 &ntm_time.tm_hour,
140 &ntm_time.tm_min) == 5) {
141 ntm_time.tm_year -= 1900; /* Adjust years */
142 ntm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
143 *tm_time = ntm_time;
144 return(tm_time);
145
146 }
147
148 fprintf(stderr, "date: invalid date `%s'\n", t_string);
149
150 exit(1);
151
152}
153
154
155void
156date_err(void) {
157 fprintf(stderr, "date: only one date argument can be given at a time.\n");
158 exit(1);
159}
160
161int
Eric Andersen4bea32a1999-10-06 00:30:51 +0000162date_main(int argc, char * * argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000163{
164 char *date_str = NULL;
165 char *date_fmt = NULL;
166 char *t_buff;
167 int set_time = 0;
168 int rfc822 = 0;
169 int utc = 0;
170 int use_arg = 0;
171 int n_args;
172 time_t tm;
173 struct tm tm_time;
174 char optc;
175
176 /* Interpret command line args */
177
178
179 while ((optc = getopt_long (argc, argv, "d:Rs:u", long_options, NULL))
180 != EOF) {
181 switch (optc) {
182 case 0:
183 break;
184
185 case 'R':
186 rfc822 = 1;
187 break;
188
189 case 's':
190 set_time = 1;
191 if(date_str != NULL) date_err();
192 date_str = optarg;
193 break;
194
195 case 'u':
196 utc = 1;
197 if (putenv ("TZ=UTC0") != 0) {
198 fprintf(stderr,"date: memory exhausted\n");
199 return(1);
200 }
201#if LOCALTIME_CACHE
202 tzset ();
203#endif break;
204
205 case 'd':
206 use_arg = 1;
207 if(date_str != NULL) date_err();
208 date_str = optarg;
209 break;
210
211 default:
Eric Andersen4bea32a1999-10-06 00:30:51 +0000212 fprintf(stderr, "Usage: %s", date_usage);
Eric Andersencc8ed391999-10-05 16:24:54 +0000213 break;
214 }
215 }
216
217
218 n_args = argc - optind;
219
220 while (n_args--){
221 switch(argv[optind][0]) {
222 case '+':
223 /* Date format strings */
224 if(date_fmt != NULL) {
225 fprintf(stderr, "date: only one date format can be given.\n");
226 return(1);
227 }
228 date_fmt = &argv[optind][1];
229 break;
230
231 case '\0':
232 break;
233
234 default:
235 /* Anything left over must be a date string to set the time */
236 set_time = 1;
237 if(date_str != NULL) date_err();
238 date_str = argv[optind];
239 break;
240 }
241 optind++;
242 }
243
244
245 /* Now we have parsed all the information except the date format
246 which depends on whether the clock is being set or read */
247
248 time(&tm);
249 memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
250 /* Zero out fields - take her back to midnight!*/
251 if(date_str != NULL) {
252 tm_time.tm_sec = 0;
253 tm_time.tm_min = 0;
254 tm_time.tm_hour = 0;
255 }
256
257 /* Process any date input to UNIX time since 1 Jan 1970 */
258 if(date_str != NULL) {
259
260 if(strchr(date_str, ':') != NULL) {
261 date_conv_ftime(&tm_time, date_str);
262 } else {
263 date_conv_time(&tm_time, date_str);
264 }
265
266 /* Correct any day of week and day of year etc fields */
267 tm = mktime(&tm_time);
268 if (tm < 0 ) {
269 fprintf(stderr, "date: invalid date `%s'\n", date_str);
270 exit(1);
271 }
272
273 /* if setting time, set it */
274 if(set_time) {
275 if( stime(&tm) < 0) {
276 fprintf(stderr, "date: can't set date.\n");
277 exit(1);
278 }
279 }
280 }
281
282 /* Display output */
283
284 /* Deal with format string */
285 if(date_fmt == NULL) {
286 date_fmt = (rfc822
287 ? (utc
288 ? "%a, %_d %b %Y %H:%M:%S GMT"
289 : "%a, %_d %b %Y %H:%M:%S %z")
290 : "%a %b %e %H:%M:%S %Z %Y");
291
292 } else if ( *date_fmt == '\0' ) {
293 /* Imitate what GNU 'date' does with NO format string! */
294 printf ("\n");
295 return(0);
296 }
297
298 /* Handle special conversions */
299
300 if( strncmp( date_fmt, "%f", 2) == 0 ) {
301 date_fmt = "%Y.%m.%d-%H:%M:%S";
302 }
303
304 /* Print OUTPUT (after ALL that!) */
305 t_buff = malloc(201);
306 strftime(t_buff, 200, date_fmt, &tm_time);
307 printf("%s\n", t_buff);
308
309 return(0);
310
311}