blob: b4c3e71535518997677834ec17326b9522c58d29 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersen2ce1edc1999-10-12 15:42:48 +00002/*
3 * Mini date implementation for busybox
4 *
Eric Andersenc4996011999-10-20 22:08:37 +00005 * by Matthew Grant <grantma@anathoth.gen.nz>
Eric Andersen2ce1edc1999-10-12 15:42:48 +00006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21*/
22
Eric Andersencc8ed391999-10-05 16:24:54 +000023#include "internal.h"
Erik Andersenfac10d72000-02-07 05:29:42 +000024#define BB_DECLARE_EXTERN
25#define bb_need_invalid_date
26#define bb_need_memory_exhausted
27#include "messages.c"
Eric Andersencc8ed391999-10-05 16:24:54 +000028#include <stdlib.h>
29#include <errno.h>
30#include <sys/time.h>
31#include <unistd.h>
32#include <time.h>
33#include <stdio.h>
Eric Andersencc8ed391999-10-05 16:24:54 +000034
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
Erik Andersene49d5ec2000-02-08 19:58:47 +000042static const char date_usage[] = "date [OPTION]... [+FORMAT]\n"
43 " or: date [OPTION] [MMDDhhmm[[CC]YY][.ss]]\n\n"
44 "Display the current time in the given FORMAT, or set the system date.\n"
45 "\nOptions:\n\t-R\t\toutput RFC-822 compliant date string\n"
46 "\t-s\t\tset time described by STRING\n"
47
48 "\t-u\t\tprint or set Coordinated Universal Time\n";
Eric Andersencc8ed391999-10-05 16:24:54 +000049
50
51/* Input parsing code is always bulky - used heavy duty libc stuff as
52 much as possible, missed out a lot of bounds checking */
53
54/* Default input handling to save suprising some people */
55
Erik Andersene49d5ec2000-02-08 19:58:47 +000056struct tm *date_conv_time(struct tm *tm_time, const char *t_string)
57{
58 int nr;
Eric Andersencc8ed391999-10-05 16:24:54 +000059
Erik Andersene49d5ec2000-02-08 19:58:47 +000060 nr = sscanf(t_string, "%2d%2d%2d%2d%d",
61 &(tm_time->tm_mon),
62 &(tm_time->tm_mday),
63 &(tm_time->tm_hour),
64 &(tm_time->tm_min), &(tm_time->tm_year));
Eric Andersencc8ed391999-10-05 16:24:54 +000065
Erik Andersene49d5ec2000-02-08 19:58:47 +000066 if (nr < 4 || nr > 5) {
67 fprintf(stderr, invalid_date, "date", t_string);
68 exit(FALSE);
69 }
Eric Andersencc8ed391999-10-05 16:24:54 +000070
Erik Andersene49d5ec2000-02-08 19:58:47 +000071 /* correct for century - minor Y2K problem here? */
72 if (tm_time->tm_year >= 1900)
73 tm_time->tm_year -= 1900;
74 /* adjust date */
75 tm_time->tm_mon -= 1;
76
77 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +000078
79}
80
81
82/* The new stuff for LRP */
83
Erik Andersene49d5ec2000-02-08 19:58:47 +000084struct tm *date_conv_ftime(struct tm *tm_time, const char *t_string)
85{
86 struct tm itm_time, jtm_time, ktm_time, ltm_time, mtm_time, ntm_time;
Eric Andersencc8ed391999-10-05 16:24:54 +000087
Erik Andersene49d5ec2000-02-08 19:58:47 +000088 itm_time = *tm_time;
89 jtm_time = *tm_time;
90 ktm_time = *tm_time;
91 ltm_time = *tm_time;
92 mtm_time = *tm_time;
93 ntm_time = *tm_time;
Eric Andersencc8ed391999-10-05 16:24:54 +000094
Erik Andersene49d5ec2000-02-08 19:58:47 +000095 /* Parse input and assign appropriately to tm_time */
Eric Andersencc8ed391999-10-05 16:24:54 +000096
Erik Andersene49d5ec2000-02-08 19:58:47 +000097 if (sscanf(t_string, "%d:%d:%d",
98 &itm_time.tm_hour, &itm_time.tm_min, &itm_time.tm_sec) == 3) {
Eric Andersencc8ed391999-10-05 16:24:54 +000099
Erik Andersene49d5ec2000-02-08 19:58:47 +0000100 *tm_time = itm_time;
101 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +0000102
Erik Andersene49d5ec2000-02-08 19:58:47 +0000103 } else if (sscanf(t_string, "%d:%d",
104 &jtm_time.tm_hour, &jtm_time.tm_min) == 2) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000105
Erik Andersene49d5ec2000-02-08 19:58:47 +0000106 *tm_time = jtm_time;
107 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +0000108
Erik Andersene49d5ec2000-02-08 19:58:47 +0000109 } else if (sscanf(t_string, "%d.%d-%d:%d:%d",
110 &ktm_time.tm_mon,
111 &ktm_time.tm_mday,
112 &ktm_time.tm_hour,
113 &ktm_time.tm_min, &ktm_time.tm_sec) == 5) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000114
Erik Andersene49d5ec2000-02-08 19:58:47 +0000115 ktm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
116 *tm_time = ktm_time;
117 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +0000118
Erik Andersene49d5ec2000-02-08 19:58:47 +0000119 } else if (sscanf(t_string, "%d.%d-%d:%d",
120 &ltm_time.tm_mon,
121 &ltm_time.tm_mday,
122 &ltm_time.tm_hour, &ltm_time.tm_min) == 4) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000123
Erik Andersene49d5ec2000-02-08 19:58:47 +0000124 ltm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
125 *tm_time = ltm_time;
126 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +0000127
Erik Andersene49d5ec2000-02-08 19:58:47 +0000128 } else if (sscanf(t_string, "%d.%d.%d-%d:%d:%d",
129 &mtm_time.tm_year,
130 &mtm_time.tm_mon,
131 &mtm_time.tm_mday,
132 &mtm_time.tm_hour,
133 &mtm_time.tm_min, &mtm_time.tm_sec) == 6) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000134
Erik Andersene49d5ec2000-02-08 19:58:47 +0000135 mtm_time.tm_year -= 1900; /* Adjust years */
136 mtm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
137 *tm_time = mtm_time;
138 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +0000139
Erik Andersene49d5ec2000-02-08 19:58:47 +0000140 } else if (sscanf(t_string, "%d.%d.%d-%d:%d",
141 &ntm_time.tm_year,
142 &ntm_time.tm_mon,
143 &ntm_time.tm_mday,
144 &ntm_time.tm_hour, &ntm_time.tm_min) == 5) {
145 ntm_time.tm_year -= 1900; /* Adjust years */
146 ntm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
147 *tm_time = ntm_time;
148 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +0000149
Erik Andersene49d5ec2000-02-08 19:58:47 +0000150 }
151
152 fprintf(stderr, invalid_date, "date", t_string);
153
154 exit(FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000155
156}
157
158
Erik Andersene49d5ec2000-02-08 19:58:47 +0000159int date_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000160{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000161 char *date_str = NULL;
162 char *date_fmt = NULL;
163 char *t_buff;
164 int i;
165 int set_time = 0;
166 int rfc822 = 0;
167 int utc = 0;
168 int use_arg = 0;
169 time_t tm;
170 struct tm tm_time;
171
172 /* Interpret command line args */
173 i = --argc;
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000174 argv++;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000175 while (i > 0 && **argv) {
176 if (**argv == '-') {
177 while (i > 0 && *++(*argv))
178 switch (**argv) {
179 case 'R':
180 rfc822 = 1;
181 break;
182 case 's':
183 set_time = 1;
184 if (date_str != NULL)
185 usage(date_usage);
186 date_str = optarg;
187 break;
188 case 'u':
189 utc = 1;
190 if (putenv("TZ=UTC0") != 0) {
191 fprintf(stderr, memory_exhausted, "date");
192 exit(FALSE);
193 }
194 /* Look ma, no break. Don't fix it either. */
195 case 'd':
196 use_arg = 1;
197 if (date_str != NULL)
198 usage(date_usage);
199 date_str = optarg;
200 break;
201 case '-':
202 usage(date_usage);
203 }
204 } else {
205 if ((date_fmt == NULL) && (strcmp(*argv, "+") == 0))
206 date_fmt = *argv;
207 else if (date_str == NULL) {
208 set_time = 1;
209 date_str = *argv;
210 } else {
211 usage(date_usage);
212 }
213 }
214 i--;
215 argv++;
216 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000217
218
Erik Andersene49d5ec2000-02-08 19:58:47 +0000219 /* Now we have parsed all the information except the date format
220 which depends on whether the clock is being set or read */
Eric Andersencc8ed391999-10-05 16:24:54 +0000221
Erik Andersene49d5ec2000-02-08 19:58:47 +0000222 time(&tm);
223 memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
224 /* Zero out fields - take her back to midnight! */
225 if (date_str != NULL) {
226 tm_time.tm_sec = 0;
227 tm_time.tm_min = 0;
228 tm_time.tm_hour = 0;
229 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000230
Erik Andersene49d5ec2000-02-08 19:58:47 +0000231 /* Process any date input to UNIX time since 1 Jan 1970 */
232 if (date_str != NULL) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000233
Erik Andersene49d5ec2000-02-08 19:58:47 +0000234 if (strchr(date_str, ':') != NULL) {
235 date_conv_ftime(&tm_time, date_str);
236 } else {
237 date_conv_time(&tm_time, date_str);
238 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000239
Erik Andersene49d5ec2000-02-08 19:58:47 +0000240 /* Correct any day of week and day of year etc fields */
241 tm = mktime(&tm_time);
242 if (tm < 0) {
243 fprintf(stderr, invalid_date, "date", date_str);
244 exit(FALSE);
245 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000246
Erik Andersene49d5ec2000-02-08 19:58:47 +0000247 /* if setting time, set it */
248 if (set_time) {
249 if (stime(&tm) < 0) {
250 fprintf(stderr, "date: can't set date.\n");
251 exit(FALSE);
252 }
253 }
254 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000255
Erik Andersene49d5ec2000-02-08 19:58:47 +0000256 /* Display output */
Eric Andersencc8ed391999-10-05 16:24:54 +0000257
Erik Andersene49d5ec2000-02-08 19:58:47 +0000258 /* Deal with format string */
259 if (date_fmt == NULL) {
260 date_fmt = (rfc822
261 ? (utc
262 ? "%a, %_d %b %Y %H:%M:%S GMT"
263 : "%a, %_d %b %Y %H:%M:%S %z")
264 : "%a %b %e %H:%M:%S %Z %Y");
Eric Andersencc8ed391999-10-05 16:24:54 +0000265
Erik Andersene49d5ec2000-02-08 19:58:47 +0000266 } else if (*date_fmt == '\0') {
267 /* Imitate what GNU 'date' does with NO format string! */
268 printf("\n");
269 exit(TRUE);
270 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000271
Erik Andersene49d5ec2000-02-08 19:58:47 +0000272 /* Handle special conversions */
Eric Andersencc8ed391999-10-05 16:24:54 +0000273
Erik Andersene49d5ec2000-02-08 19:58:47 +0000274 if (strncmp(date_fmt, "%f", 2) == 0) {
275 date_fmt = "%Y.%m.%d-%H:%M:%S";
276 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000277
Erik Andersene49d5ec2000-02-08 19:58:47 +0000278 /* Print OUTPUT (after ALL that!) */
279 t_buff = malloc(201);
280 strftime(t_buff, 200, date_fmt, &tm_time);
281 printf("%s\n", t_buff);
282
283 exit(TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000284
285}