blob: a8f0d7ced9ae1e30823dd8964a6323dd4d137900 [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) {
Eric Andersena683ee82000-11-17 18:51:45 +0000163 case 'R':
164 rfc822 = 1;
165 break;
166 case 's':
167 set_time = 1;
168 if ((date_str != NULL) || ((date_str = optarg) == NULL)) {
169 usage(date_usage);
170 }
171 break;
172 case 'u':
173 utc = 1;
174 if (putenv("TZ=UTC0") != 0)
175 fatalError(memory_exhausted);
176 break;
177 case 'd':
178 use_arg = 1;
179 if ((date_str != NULL) || ((date_str = optarg) == NULL))
180 usage(date_usage);
181 break;
182 default:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000183 usage(date_usage);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000184 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000185 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000186
Eric Andersenadd09fd2000-07-14 18:39:08 +0000187 if ((date_fmt == NULL) && (optind < argc) && (argv[optind][0] == '+'))
188 date_fmt = &argv[optind][1]; /* Skip over the '+' */
189 else if (date_str == NULL) {
190 set_time = 1;
191 date_str = argv[optind];
Eric Andersena683ee82000-11-17 18:51:45 +0000192 }
193#if 0
194 else {
195 errorMsg("date_str='%s' date_fmt='%s'\n", date_str, date_fmt);
Eric Andersenadd09fd2000-07-14 18:39:08 +0000196 usage(date_usage);
197 }
Eric Andersena683ee82000-11-17 18:51:45 +0000198#endif
Eric Andersencc8ed391999-10-05 16:24:54 +0000199
Erik Andersene49d5ec2000-02-08 19:58:47 +0000200 /* Now we have parsed all the information except the date format
201 which depends on whether the clock is being set or read */
Eric Andersencc8ed391999-10-05 16:24:54 +0000202
Erik Andersene49d5ec2000-02-08 19:58:47 +0000203 time(&tm);
204 memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
205 /* Zero out fields - take her back to midnight! */
206 if (date_str != NULL) {
207 tm_time.tm_sec = 0;
208 tm_time.tm_min = 0;
209 tm_time.tm_hour = 0;
210 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000211
Erik Andersene49d5ec2000-02-08 19:58:47 +0000212 /* Process any date input to UNIX time since 1 Jan 1970 */
213 if (date_str != NULL) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000214
Erik Andersene49d5ec2000-02-08 19:58:47 +0000215 if (strchr(date_str, ':') != NULL) {
216 date_conv_ftime(&tm_time, date_str);
217 } else {
218 date_conv_time(&tm_time, date_str);
219 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000220
Erik Andersene49d5ec2000-02-08 19:58:47 +0000221 /* Correct any day of week and day of year etc fields */
222 tm = mktime(&tm_time);
Erik Andersen1ad302a2000-03-24 00:54:46 +0000223 if (tm < 0)
Matt Kraaibe84cd42000-07-12 17:02:35 +0000224 fatalError(invalid_date, date_str);
Eric Andersena683ee82000-11-17 18:51:45 +0000225 if ( utc ) {
226 if (putenv("TZ=UTC0") != 0)
227 fatalError(memory_exhausted);
228 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000229
Erik Andersene49d5ec2000-02-08 19:58:47 +0000230 /* if setting time, set it */
231 if (set_time) {
232 if (stime(&tm) < 0) {
Eric Andersena683ee82000-11-17 18:51:45 +0000233 perrorMsg("cannot set date");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000234 }
235 }
236 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000237
Erik Andersene49d5ec2000-02-08 19:58:47 +0000238 /* Display output */
Eric Andersencc8ed391999-10-05 16:24:54 +0000239
Erik Andersene49d5ec2000-02-08 19:58:47 +0000240 /* Deal with format string */
241 if (date_fmt == NULL) {
242 date_fmt = (rfc822
243 ? (utc
244 ? "%a, %_d %b %Y %H:%M:%S GMT"
245 : "%a, %_d %b %Y %H:%M:%S %z")
246 : "%a %b %e %H:%M:%S %Z %Y");
Eric Andersencc8ed391999-10-05 16:24:54 +0000247
Erik Andersene49d5ec2000-02-08 19:58:47 +0000248 } else if (*date_fmt == '\0') {
249 /* Imitate what GNU 'date' does with NO format string! */
250 printf("\n");
251 exit(TRUE);
252 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000253
Erik Andersene49d5ec2000-02-08 19:58:47 +0000254 /* Handle special conversions */
Eric Andersencc8ed391999-10-05 16:24:54 +0000255
Erik Andersene49d5ec2000-02-08 19:58:47 +0000256 if (strncmp(date_fmt, "%f", 2) == 0) {
257 date_fmt = "%Y.%m.%d-%H:%M:%S";
258 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000259
Erik Andersene49d5ec2000-02-08 19:58:47 +0000260 /* Print OUTPUT (after ALL that!) */
Erik Andersen0d068a22000-03-21 22:32:57 +0000261 t_buff = xmalloc(201);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000262 strftime(t_buff, 200, date_fmt, &tm_time);
263 printf("%s\n", t_buff);
264
Eric Andersenb6106152000-06-19 17:25:40 +0000265 return(TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000266}