blob: 73fc705119b34af1e8400daaa2e27f5a3fa8d735 [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) {
Mark Whitleyf57c9442000-12-07 19:56:48 +000059 error_msg_and_die(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{
Eric Andersen7b5d5942000-11-29 22:01:42 +000077 struct tm t;
Eric Andersencc8ed391999-10-05 16:24:54 +000078
Erik Andersene49d5ec2000-02-08 19:58:47 +000079 /* Parse input and assign appropriately to tm_time */
Eric Andersencc8ed391999-10-05 16:24:54 +000080
Eric Andersen7b5d5942000-11-29 22:01:42 +000081 if (t=*tm_time,sscanf(t_string, "%d:%d:%d",
82 &t.tm_hour, &t.tm_min, &t.tm_sec) == 3) {
83 /* no adjustments needed */
Eric Andersencc8ed391999-10-05 16:24:54 +000084
Eric Andersen7b5d5942000-11-29 22:01:42 +000085 } else if (t=*tm_time,sscanf(t_string, "%d:%d",
86 &t.tm_hour, &t.tm_min) == 2) {
87 /* no adjustments needed */
Eric Andersencc8ed391999-10-05 16:24:54 +000088
Eric Andersencc8ed391999-10-05 16:24:54 +000089
Eric Andersen7b5d5942000-11-29 22:01:42 +000090 } else if (t=*tm_time,sscanf(t_string, "%d.%d-%d:%d:%d",
91 &t.tm_mon,
92 &t.tm_mday,
93 &t.tm_hour,
94 &t.tm_min, &t.tm_sec) == 5) {
Eric Andersencc8ed391999-10-05 16:24:54 +000095
Eric Andersen7b5d5942000-11-29 22:01:42 +000096 t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
Eric Andersencc8ed391999-10-05 16:24:54 +000097
Eric Andersen7b5d5942000-11-29 22:01:42 +000098 } else if (t=*tm_time,sscanf(t_string, "%d.%d-%d:%d",
99 &t.tm_mon,
100 &t.tm_mday,
101 &t.tm_hour, &t.tm_min) == 4) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000102
Eric Andersen7b5d5942000-11-29 22:01:42 +0000103 t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
Eric Andersencc8ed391999-10-05 16:24:54 +0000104
Eric Andersen7b5d5942000-11-29 22:01:42 +0000105 } else if (t=*tm_time,sscanf(t_string, "%d.%d.%d-%d:%d:%d",
106 &t.tm_year,
107 &t.tm_mon,
108 &t.tm_mday,
109 &t.tm_hour,
110 &t.tm_min, &t.tm_sec) == 6) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000111
Eric Andersen7b5d5942000-11-29 22:01:42 +0000112 t.tm_year -= 1900; /* Adjust years */
113 t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
Eric Andersencc8ed391999-10-05 16:24:54 +0000114
Eric Andersen7b5d5942000-11-29 22:01:42 +0000115 } else if (t=*tm_time,sscanf(t_string, "%d.%d.%d-%d:%d",
116 &t.tm_year,
117 &t.tm_mon,
118 &t.tm_mday,
119 &t.tm_hour, &t.tm_min) == 5) {
120 t.tm_year -= 1900; /* Adjust years */
121 t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
Eric Andersencc8ed391999-10-05 16:24:54 +0000122
Eric Andersen7b5d5942000-11-29 22:01:42 +0000123 } else {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000124 error_msg_and_die(invalid_date, t_string);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000125 }
Eric Andersen7b5d5942000-11-29 22:01:42 +0000126 *tm_time = t;
127 return (tm_time);
Eric Andersencc8ed391999-10-05 16:24:54 +0000128}
129
130
Erik Andersene49d5ec2000-02-08 19:58:47 +0000131int date_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000132{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000133 char *date_str = NULL;
134 char *date_fmt = NULL;
135 char *t_buff;
Pavel Roskin47d49262000-07-17 16:17:19 +0000136 int c;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000137 int set_time = 0;
138 int rfc822 = 0;
139 int utc = 0;
140 int use_arg = 0;
141 time_t tm;
142 struct tm tm_time;
143
144 /* Interpret command line args */
Eric Andersenadd09fd2000-07-14 18:39:08 +0000145 while ((c = getopt(argc, argv, "Rs:ud:")) != EOF) {
146 switch (c) {
Eric Andersena683ee82000-11-17 18:51:45 +0000147 case 'R':
148 rfc822 = 1;
149 break;
150 case 's':
151 set_time = 1;
152 if ((date_str != NULL) || ((date_str = optarg) == NULL)) {
153 usage(date_usage);
154 }
155 break;
156 case 'u':
157 utc = 1;
158 if (putenv("TZ=UTC0") != 0)
Mark Whitleyf57c9442000-12-07 19:56:48 +0000159 error_msg_and_die(memory_exhausted);
Eric Andersena683ee82000-11-17 18:51:45 +0000160 break;
161 case 'd':
162 use_arg = 1;
163 if ((date_str != NULL) || ((date_str = optarg) == NULL))
164 usage(date_usage);
165 break;
166 default:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000167 usage(date_usage);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000168 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000169 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000170
Eric Andersenadd09fd2000-07-14 18:39:08 +0000171 if ((date_fmt == NULL) && (optind < argc) && (argv[optind][0] == '+'))
172 date_fmt = &argv[optind][1]; /* Skip over the '+' */
173 else if (date_str == NULL) {
174 set_time = 1;
175 date_str = argv[optind];
Eric Andersena683ee82000-11-17 18:51:45 +0000176 }
177#if 0
178 else {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000179 error_msg("date_str='%s' date_fmt='%s'\n", date_str, date_fmt);
Eric Andersenadd09fd2000-07-14 18:39:08 +0000180 usage(date_usage);
181 }
Eric Andersena683ee82000-11-17 18:51:45 +0000182#endif
Eric Andersencc8ed391999-10-05 16:24:54 +0000183
Erik Andersene49d5ec2000-02-08 19:58:47 +0000184 /* Now we have parsed all the information except the date format
185 which depends on whether the clock is being set or read */
Eric Andersencc8ed391999-10-05 16:24:54 +0000186
Erik Andersene49d5ec2000-02-08 19:58:47 +0000187 time(&tm);
188 memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
189 /* Zero out fields - take her back to midnight! */
190 if (date_str != NULL) {
191 tm_time.tm_sec = 0;
192 tm_time.tm_min = 0;
193 tm_time.tm_hour = 0;
194 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000195
Erik Andersene49d5ec2000-02-08 19:58:47 +0000196 /* Process any date input to UNIX time since 1 Jan 1970 */
197 if (date_str != NULL) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000198
Erik Andersene49d5ec2000-02-08 19:58:47 +0000199 if (strchr(date_str, ':') != NULL) {
200 date_conv_ftime(&tm_time, date_str);
201 } else {
202 date_conv_time(&tm_time, date_str);
203 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000204
Erik Andersene49d5ec2000-02-08 19:58:47 +0000205 /* Correct any day of week and day of year etc fields */
206 tm = mktime(&tm_time);
Erik Andersen1ad302a2000-03-24 00:54:46 +0000207 if (tm < 0)
Mark Whitleyf57c9442000-12-07 19:56:48 +0000208 error_msg_and_die(invalid_date, date_str);
Eric Andersena683ee82000-11-17 18:51:45 +0000209 if ( utc ) {
210 if (putenv("TZ=UTC0") != 0)
Mark Whitleyf57c9442000-12-07 19:56:48 +0000211 error_msg_and_die(memory_exhausted);
Eric Andersena683ee82000-11-17 18:51:45 +0000212 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000213
Erik Andersene49d5ec2000-02-08 19:58:47 +0000214 /* if setting time, set it */
215 if (set_time) {
216 if (stime(&tm) < 0) {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000217 perror_msg("cannot set date");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000218 }
219 }
220 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000221
Erik Andersene49d5ec2000-02-08 19:58:47 +0000222 /* Display output */
Eric Andersencc8ed391999-10-05 16:24:54 +0000223
Erik Andersene49d5ec2000-02-08 19:58:47 +0000224 /* Deal with format string */
225 if (date_fmt == NULL) {
226 date_fmt = (rfc822
227 ? (utc
228 ? "%a, %_d %b %Y %H:%M:%S GMT"
229 : "%a, %_d %b %Y %H:%M:%S %z")
230 : "%a %b %e %H:%M:%S %Z %Y");
Eric Andersencc8ed391999-10-05 16:24:54 +0000231
Erik Andersene49d5ec2000-02-08 19:58:47 +0000232 } else if (*date_fmt == '\0') {
233 /* Imitate what GNU 'date' does with NO format string! */
234 printf("\n");
Matt Kraai3e856ce2000-12-01 02:55:13 +0000235 return EXIT_SUCCESS;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000236 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000237
Erik Andersene49d5ec2000-02-08 19:58:47 +0000238 /* Handle special conversions */
Eric Andersencc8ed391999-10-05 16:24:54 +0000239
Erik Andersene49d5ec2000-02-08 19:58:47 +0000240 if (strncmp(date_fmt, "%f", 2) == 0) {
241 date_fmt = "%Y.%m.%d-%H:%M:%S";
242 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000243
Erik Andersene49d5ec2000-02-08 19:58:47 +0000244 /* Print OUTPUT (after ALL that!) */
Erik Andersen0d068a22000-03-21 22:32:57 +0000245 t_buff = xmalloc(201);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000246 strftime(t_buff, 200, date_fmt, &tm_time);
247 printf("%s\n", t_buff);
248
Matt Kraai3e856ce2000-12-01 02:55:13 +0000249 return EXIT_SUCCESS;
Eric Andersencc8ed391999-10-05 16:24:54 +0000250}