blob: e0f0f3129cf3bde0b11d5b6f04f7b82cdac20320 [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
Eric Andersencc8ed391999-10-05 16:24:54 +000042/* 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 suprising some people */
46
Erik Andersene49d5ec2000-02-08 19:58:47 +000047struct tm *date_conv_time(struct tm *tm_time, const char *t_string)
48{
49 int nr;
Eric Andersencc8ed391999-10-05 16:24:54 +000050
Erik Andersene49d5ec2000-02-08 19:58:47 +000051 nr = sscanf(t_string, "%2d%2d%2d%2d%d",
52 &(tm_time->tm_mon),
53 &(tm_time->tm_mday),
54 &(tm_time->tm_hour),
55 &(tm_time->tm_min), &(tm_time->tm_year));
Eric Andersencc8ed391999-10-05 16:24:54 +000056
Erik Andersene49d5ec2000-02-08 19:58:47 +000057 if (nr < 4 || nr > 5) {
Matt Kraaibe84cd42000-07-12 17:02:35 +000058 fatalError(invalid_date, t_string);
Erik Andersene49d5ec2000-02-08 19:58:47 +000059 }
Eric Andersencc8ed391999-10-05 16:24:54 +000060
Erik Andersene49d5ec2000-02-08 19:58:47 +000061 /* correct for century - minor Y2K problem here? */
62 if (tm_time->tm_year >= 1900)
63 tm_time->tm_year -= 1900;
64 /* adjust date */
65 tm_time->tm_mon -= 1;
66
67 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +000068
69}
70
71
72/* The new stuff for LRP */
73
Erik Andersene49d5ec2000-02-08 19:58:47 +000074struct tm *date_conv_ftime(struct tm *tm_time, const char *t_string)
75{
76 struct tm itm_time, jtm_time, ktm_time, ltm_time, mtm_time, ntm_time;
Eric Andersencc8ed391999-10-05 16:24:54 +000077
Erik Andersene49d5ec2000-02-08 19:58:47 +000078 itm_time = *tm_time;
79 jtm_time = *tm_time;
80 ktm_time = *tm_time;
81 ltm_time = *tm_time;
82 mtm_time = *tm_time;
83 ntm_time = *tm_time;
Eric Andersencc8ed391999-10-05 16:24:54 +000084
Erik Andersene49d5ec2000-02-08 19:58:47 +000085 /* Parse input and assign appropriately to tm_time */
Eric Andersencc8ed391999-10-05 16:24:54 +000086
Erik Andersene49d5ec2000-02-08 19:58:47 +000087 if (sscanf(t_string, "%d:%d:%d",
88 &itm_time.tm_hour, &itm_time.tm_min, &itm_time.tm_sec) == 3) {
Eric Andersencc8ed391999-10-05 16:24:54 +000089
Erik Andersene49d5ec2000-02-08 19:58:47 +000090 *tm_time = itm_time;
91 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +000092
Erik Andersene49d5ec2000-02-08 19:58:47 +000093 } else if (sscanf(t_string, "%d:%d",
94 &jtm_time.tm_hour, &jtm_time.tm_min) == 2) {
Eric Andersencc8ed391999-10-05 16:24:54 +000095
Erik Andersene49d5ec2000-02-08 19:58:47 +000096 *tm_time = jtm_time;
97 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +000098
Erik Andersene49d5ec2000-02-08 19:58:47 +000099 } else if (sscanf(t_string, "%d.%d-%d:%d:%d",
100 &ktm_time.tm_mon,
101 &ktm_time.tm_mday,
102 &ktm_time.tm_hour,
103 &ktm_time.tm_min, &ktm_time.tm_sec) == 5) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000104
Erik Andersene49d5ec2000-02-08 19:58:47 +0000105 ktm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
106 *tm_time = ktm_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",
110 &ltm_time.tm_mon,
111 &ltm_time.tm_mday,
112 &ltm_time.tm_hour, &ltm_time.tm_min) == 4) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000113
Erik Andersene49d5ec2000-02-08 19:58:47 +0000114 ltm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
115 *tm_time = ltm_time;
116 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +0000117
Erik Andersene49d5ec2000-02-08 19:58:47 +0000118 } else if (sscanf(t_string, "%d.%d.%d-%d:%d:%d",
119 &mtm_time.tm_year,
120 &mtm_time.tm_mon,
121 &mtm_time.tm_mday,
122 &mtm_time.tm_hour,
123 &mtm_time.tm_min, &mtm_time.tm_sec) == 6) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000124
Erik Andersene49d5ec2000-02-08 19:58:47 +0000125 mtm_time.tm_year -= 1900; /* Adjust years */
126 mtm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
127 *tm_time = mtm_time;
128 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +0000129
Erik Andersene49d5ec2000-02-08 19:58:47 +0000130 } else if (sscanf(t_string, "%d.%d.%d-%d:%d",
131 &ntm_time.tm_year,
132 &ntm_time.tm_mon,
133 &ntm_time.tm_mday,
134 &ntm_time.tm_hour, &ntm_time.tm_min) == 5) {
135 ntm_time.tm_year -= 1900; /* Adjust years */
136 ntm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
137 *tm_time = ntm_time;
138 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +0000139
Erik Andersene49d5ec2000-02-08 19:58:47 +0000140 }
141
Matt Kraaibe84cd42000-07-12 17:02:35 +0000142 fatalError(invalid_date, t_string);
Eric Andersencc8ed391999-10-05 16:24:54 +0000143}
144
145
Erik Andersene49d5ec2000-02-08 19:58:47 +0000146int date_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000147{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000148 char *date_str = NULL;
149 char *date_fmt = NULL;
150 char *t_buff;
Pavel Roskin47d49262000-07-17 16:17:19 +0000151 int c;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000152 int set_time = 0;
153 int rfc822 = 0;
154 int utc = 0;
155 int use_arg = 0;
156 time_t tm;
157 struct tm tm_time;
158
159 /* Interpret command line args */
Eric Andersenadd09fd2000-07-14 18:39:08 +0000160 while ((c = getopt(argc, argv, "Rs:ud:")) != EOF) {
161 switch (c) {
162 case 'R':
163 rfc822 = 1;
164 break;
165 case 's':
166 set_time = 1;
167 if ((date_str != NULL) || ((date_str = optarg) == NULL))
Erik Andersene49d5ec2000-02-08 19:58:47 +0000168 usage(date_usage);
Eric Andersenadd09fd2000-07-14 18:39:08 +0000169 break;
170 case 'u':
171 utc = 1;
172 if (putenv("TZ=UTC0") != 0)
173 fatalError(memory_exhausted);
174 break;
175 case 'd':
176 use_arg = 1;
177 if ((date_str != NULL) || ((date_str = optarg) == NULL))
178 usage(date_usage);
179 break;
180 default:
181 usage(date_usage);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000182 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000183 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000184
Eric Andersenadd09fd2000-07-14 18:39:08 +0000185 if ((date_fmt == NULL) && (optind < argc) && (argv[optind][0] == '+'))
186 date_fmt = &argv[optind][1]; /* Skip over the '+' */
187 else if (date_str == NULL) {
188 set_time = 1;
189 date_str = argv[optind];
190 } else {
191 usage(date_usage);
192 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000193
Erik Andersene49d5ec2000-02-08 19:58:47 +0000194 /* Now we have parsed all the information except the date format
195 which depends on whether the clock is being set or read */
Eric Andersencc8ed391999-10-05 16:24:54 +0000196
Erik Andersene49d5ec2000-02-08 19:58:47 +0000197 time(&tm);
198 memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
199 /* Zero out fields - take her back to midnight! */
200 if (date_str != NULL) {
201 tm_time.tm_sec = 0;
202 tm_time.tm_min = 0;
203 tm_time.tm_hour = 0;
204 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000205
Erik Andersene49d5ec2000-02-08 19:58:47 +0000206 /* Process any date input to UNIX time since 1 Jan 1970 */
207 if (date_str != NULL) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000208
Erik Andersene49d5ec2000-02-08 19:58:47 +0000209 if (strchr(date_str, ':') != NULL) {
210 date_conv_ftime(&tm_time, date_str);
211 } else {
212 date_conv_time(&tm_time, date_str);
213 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000214
Erik Andersene49d5ec2000-02-08 19:58:47 +0000215 /* Correct any day of week and day of year etc fields */
216 tm = mktime(&tm_time);
Erik Andersen1ad302a2000-03-24 00:54:46 +0000217 if (tm < 0)
Matt Kraaibe84cd42000-07-12 17:02:35 +0000218 fatalError(invalid_date, date_str);
Eric Andersencc8ed391999-10-05 16:24:54 +0000219
Erik Andersene49d5ec2000-02-08 19:58:47 +0000220 /* if setting time, set it */
221 if (set_time) {
222 if (stime(&tm) < 0) {
Matt Kraaibe84cd42000-07-12 17:02:35 +0000223 fatalError("can't set date.\n");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000224 }
225 }
226 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000227
Erik Andersene49d5ec2000-02-08 19:58:47 +0000228 /* Display output */
Eric Andersencc8ed391999-10-05 16:24:54 +0000229
Erik Andersene49d5ec2000-02-08 19:58:47 +0000230 /* Deal with format string */
231 if (date_fmt == NULL) {
232 date_fmt = (rfc822
233 ? (utc
234 ? "%a, %_d %b %Y %H:%M:%S GMT"
235 : "%a, %_d %b %Y %H:%M:%S %z")
236 : "%a %b %e %H:%M:%S %Z %Y");
Eric Andersencc8ed391999-10-05 16:24:54 +0000237
Erik Andersene49d5ec2000-02-08 19:58:47 +0000238 } else if (*date_fmt == '\0') {
239 /* Imitate what GNU 'date' does with NO format string! */
240 printf("\n");
241 exit(TRUE);
242 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000243
Erik Andersene49d5ec2000-02-08 19:58:47 +0000244 /* Handle special conversions */
Eric Andersencc8ed391999-10-05 16:24:54 +0000245
Erik Andersene49d5ec2000-02-08 19:58:47 +0000246 if (strncmp(date_fmt, "%f", 2) == 0) {
247 date_fmt = "%Y.%m.%d-%H:%M:%S";
248 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000249
Erik Andersene49d5ec2000-02-08 19:58:47 +0000250 /* Print OUTPUT (after ALL that!) */
Erik Andersen0d068a22000-03-21 22:32:57 +0000251 t_buff = xmalloc(201);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000252 strftime(t_buff, 200, date_fmt, &tm_time);
253 printf("%s\n", t_buff);
254
Eric Andersenb6106152000-06-19 17:25:40 +0000255 return(TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000256}