blob: 2e99aea19a220d687d0483042aa3ffbbb9b7b651 [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 Andersen3570a342000-09-25 21:45:58 +000023#include "busybox.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 Andersen88f50b62000-08-10 17:59:11 +000034#include <getopt.h>
Eric Andersencc8ed391999-10-05 16:24:54 +000035
36
37/* This 'date' command supports only 2 time setting formats,
38 all the GNU strftime stuff (its in libc, lets use it),
39 setting time using UTC and displaying int, as well as
40 an RFC 822 complient date output for shell scripting
41 mail commands */
42
Eric Andersencc8ed391999-10-05 16:24:54 +000043/* Input parsing code is always bulky - used heavy duty libc stuff as
44 much as possible, missed out a lot of bounds checking */
45
46/* Default input handling to save suprising some people */
47
Erik Andersene49d5ec2000-02-08 19:58:47 +000048struct tm *date_conv_time(struct tm *tm_time, const char *t_string)
49{
50 int nr;
Eric Andersencc8ed391999-10-05 16:24:54 +000051
Erik Andersene49d5ec2000-02-08 19:58:47 +000052 nr = sscanf(t_string, "%2d%2d%2d%2d%d",
53 &(tm_time->tm_mon),
54 &(tm_time->tm_mday),
55 &(tm_time->tm_hour),
56 &(tm_time->tm_min), &(tm_time->tm_year));
Eric Andersencc8ed391999-10-05 16:24:54 +000057
Erik Andersene49d5ec2000-02-08 19:58:47 +000058 if (nr < 4 || nr > 5) {
Matt Kraaibe84cd42000-07-12 17:02:35 +000059 fatalError(invalid_date, t_string);
Erik Andersene49d5ec2000-02-08 19:58:47 +000060 }
Eric Andersencc8ed391999-10-05 16:24:54 +000061
Erik Andersene49d5ec2000-02-08 19:58:47 +000062 /* correct for century - minor Y2K problem here? */
63 if (tm_time->tm_year >= 1900)
64 tm_time->tm_year -= 1900;
65 /* adjust date */
66 tm_time->tm_mon -= 1;
67
68 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +000069
70}
71
72
73/* The new stuff for LRP */
74
Erik Andersene49d5ec2000-02-08 19:58:47 +000075struct tm *date_conv_ftime(struct tm *tm_time, const char *t_string)
76{
77 struct tm itm_time, jtm_time, ktm_time, ltm_time, mtm_time, ntm_time;
Eric Andersencc8ed391999-10-05 16:24:54 +000078
Erik Andersene49d5ec2000-02-08 19:58:47 +000079 itm_time = *tm_time;
80 jtm_time = *tm_time;
81 ktm_time = *tm_time;
82 ltm_time = *tm_time;
83 mtm_time = *tm_time;
84 ntm_time = *tm_time;
Eric Andersencc8ed391999-10-05 16:24:54 +000085
Erik Andersene49d5ec2000-02-08 19:58:47 +000086 /* Parse input and assign appropriately to tm_time */
Eric Andersencc8ed391999-10-05 16:24:54 +000087
Erik Andersene49d5ec2000-02-08 19:58:47 +000088 if (sscanf(t_string, "%d:%d:%d",
89 &itm_time.tm_hour, &itm_time.tm_min, &itm_time.tm_sec) == 3) {
Eric Andersencc8ed391999-10-05 16:24:54 +000090
Erik Andersene49d5ec2000-02-08 19:58:47 +000091 *tm_time = itm_time;
92 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +000093
Erik Andersene49d5ec2000-02-08 19:58:47 +000094 } else if (sscanf(t_string, "%d:%d",
95 &jtm_time.tm_hour, &jtm_time.tm_min) == 2) {
Eric Andersencc8ed391999-10-05 16:24:54 +000096
Erik Andersene49d5ec2000-02-08 19:58:47 +000097 *tm_time = jtm_time;
98 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +000099
Erik Andersene49d5ec2000-02-08 19:58:47 +0000100 } else if (sscanf(t_string, "%d.%d-%d:%d:%d",
101 &ktm_time.tm_mon,
102 &ktm_time.tm_mday,
103 &ktm_time.tm_hour,
104 &ktm_time.tm_min, &ktm_time.tm_sec) == 5) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000105
Erik Andersene49d5ec2000-02-08 19:58:47 +0000106 ktm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
107 *tm_time = ktm_time;
108 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +0000109
Erik Andersene49d5ec2000-02-08 19:58:47 +0000110 } else if (sscanf(t_string, "%d.%d-%d:%d",
111 &ltm_time.tm_mon,
112 &ltm_time.tm_mday,
113 &ltm_time.tm_hour, &ltm_time.tm_min) == 4) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000114
Erik Andersene49d5ec2000-02-08 19:58:47 +0000115 ltm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
116 *tm_time = ltm_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:%d:%d",
120 &mtm_time.tm_year,
121 &mtm_time.tm_mon,
122 &mtm_time.tm_mday,
123 &mtm_time.tm_hour,
124 &mtm_time.tm_min, &mtm_time.tm_sec) == 6) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000125
Erik Andersene49d5ec2000-02-08 19:58:47 +0000126 mtm_time.tm_year -= 1900; /* Adjust years */
127 mtm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
128 *tm_time = mtm_time;
129 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +0000130
Erik Andersene49d5ec2000-02-08 19:58:47 +0000131 } else if (sscanf(t_string, "%d.%d.%d-%d:%d",
132 &ntm_time.tm_year,
133 &ntm_time.tm_mon,
134 &ntm_time.tm_mday,
135 &ntm_time.tm_hour, &ntm_time.tm_min) == 5) {
136 ntm_time.tm_year -= 1900; /* Adjust years */
137 ntm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
138 *tm_time = ntm_time;
139 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +0000140
Erik Andersene49d5ec2000-02-08 19:58:47 +0000141 }
142
Matt Kraaibe84cd42000-07-12 17:02:35 +0000143 fatalError(invalid_date, t_string);
Eric Andersencc8ed391999-10-05 16:24:54 +0000144}
145
146
Erik Andersene49d5ec2000-02-08 19:58:47 +0000147int date_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000148{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000149 char *date_str = NULL;
150 char *date_fmt = NULL;
151 char *t_buff;
Pavel Roskin47d49262000-07-17 16:17:19 +0000152 int c;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000153 int set_time = 0;
154 int rfc822 = 0;
155 int utc = 0;
156 int use_arg = 0;
157 time_t tm;
158 struct tm tm_time;
159
160 /* Interpret command line args */
Eric Andersenadd09fd2000-07-14 18:39:08 +0000161 while ((c = getopt(argc, argv, "Rs:ud:")) != EOF) {
162 switch (c) {
163 case 'R':
164 rfc822 = 1;
165 break;
166 case 's':
167 set_time = 1;
168 if ((date_str != NULL) || ((date_str = optarg) == NULL))
Erik Andersene49d5ec2000-02-08 19:58:47 +0000169 usage(date_usage);
Eric Andersenadd09fd2000-07-14 18:39:08 +0000170 break;
171 case 'u':
172 utc = 1;
173 if (putenv("TZ=UTC0") != 0)
174 fatalError(memory_exhausted);
175 break;
176 case 'd':
177 use_arg = 1;
178 if ((date_str != NULL) || ((date_str = optarg) == NULL))
179 usage(date_usage);
180 break;
181 default:
182 usage(date_usage);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000183 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000184 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000185
Eric Andersenadd09fd2000-07-14 18:39:08 +0000186 if ((date_fmt == NULL) && (optind < argc) && (argv[optind][0] == '+'))
187 date_fmt = &argv[optind][1]; /* Skip over the '+' */
188 else if (date_str == NULL) {
189 set_time = 1;
190 date_str = argv[optind];
191 } else {
192 usage(date_usage);
193 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000194
Erik Andersene49d5ec2000-02-08 19:58:47 +0000195 /* Now we have parsed all the information except the date format
196 which depends on whether the clock is being set or read */
Eric Andersencc8ed391999-10-05 16:24:54 +0000197
Erik Andersene49d5ec2000-02-08 19:58:47 +0000198 time(&tm);
199 memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
200 /* Zero out fields - take her back to midnight! */
201 if (date_str != NULL) {
202 tm_time.tm_sec = 0;
203 tm_time.tm_min = 0;
204 tm_time.tm_hour = 0;
205 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000206
Erik Andersene49d5ec2000-02-08 19:58:47 +0000207 /* Process any date input to UNIX time since 1 Jan 1970 */
208 if (date_str != NULL) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000209
Erik Andersene49d5ec2000-02-08 19:58:47 +0000210 if (strchr(date_str, ':') != NULL) {
211 date_conv_ftime(&tm_time, date_str);
212 } else {
213 date_conv_time(&tm_time, date_str);
214 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000215
Erik Andersene49d5ec2000-02-08 19:58:47 +0000216 /* Correct any day of week and day of year etc fields */
217 tm = mktime(&tm_time);
Erik Andersen1ad302a2000-03-24 00:54:46 +0000218 if (tm < 0)
Matt Kraaibe84cd42000-07-12 17:02:35 +0000219 fatalError(invalid_date, date_str);
Eric Andersencc8ed391999-10-05 16:24:54 +0000220
Erik Andersene49d5ec2000-02-08 19:58:47 +0000221 /* if setting time, set it */
222 if (set_time) {
223 if (stime(&tm) < 0) {
Matt Kraaibe84cd42000-07-12 17:02:35 +0000224 fatalError("can't set date.\n");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000225 }
226 }
227 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000228
Erik Andersene49d5ec2000-02-08 19:58:47 +0000229 /* Display output */
Eric Andersencc8ed391999-10-05 16:24:54 +0000230
Erik Andersene49d5ec2000-02-08 19:58:47 +0000231 /* Deal with format string */
232 if (date_fmt == NULL) {
233 date_fmt = (rfc822
234 ? (utc
235 ? "%a, %_d %b %Y %H:%M:%S GMT"
236 : "%a, %_d %b %Y %H:%M:%S %z")
237 : "%a %b %e %H:%M:%S %Z %Y");
Eric Andersencc8ed391999-10-05 16:24:54 +0000238
Erik Andersene49d5ec2000-02-08 19:58:47 +0000239 } else if (*date_fmt == '\0') {
240 /* Imitate what GNU 'date' does with NO format string! */
241 printf("\n");
242 exit(TRUE);
243 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000244
Erik Andersene49d5ec2000-02-08 19:58:47 +0000245 /* Handle special conversions */
Eric Andersencc8ed391999-10-05 16:24:54 +0000246
Erik Andersene49d5ec2000-02-08 19:58:47 +0000247 if (strncmp(date_fmt, "%f", 2) == 0) {
248 date_fmt = "%Y.%m.%d-%H:%M:%S";
249 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000250
Erik Andersene49d5ec2000-02-08 19:58:47 +0000251 /* Print OUTPUT (after ALL that!) */
Erik Andersen0d068a22000-03-21 22:32:57 +0000252 t_buff = xmalloc(201);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000253 strftime(t_buff, 200, date_fmt, &tm_time);
254 printf("%s\n", t_buff);
255
Eric Andersenb6106152000-06-19 17:25:40 +0000256 return(TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000257}