xref: /freebsd/contrib/tzcode/date.c (revision bc42155199b5b0b479311e05b07aee7f6f9c5172)
1*bc421551SDag-Erling Smørgrav /* Display or set the current time and date.  */
2*bc421551SDag-Erling Smørgrav 
3*bc421551SDag-Erling Smørgrav /* Copyright 1985, 1987, 1988 The Regents of the University of California.
4*bc421551SDag-Erling Smørgrav    All rights reserved.
5*bc421551SDag-Erling Smørgrav 
6*bc421551SDag-Erling Smørgrav    Redistribution and use in source and binary forms, with or without
7*bc421551SDag-Erling Smørgrav    modification, are permitted provided that the following conditions
8*bc421551SDag-Erling Smørgrav    are met:
9*bc421551SDag-Erling Smørgrav    1. Redistributions of source code must retain the above copyright
10*bc421551SDag-Erling Smørgrav       notice, this list of conditions and the following disclaimer.
11*bc421551SDag-Erling Smørgrav    2. Redistributions in binary form must reproduce the above copyright
12*bc421551SDag-Erling Smørgrav       notice, this list of conditions and the following disclaimer in the
13*bc421551SDag-Erling Smørgrav       documentation and/or other materials provided with the distribution.
14*bc421551SDag-Erling Smørgrav    3. Neither the name of the University nor the names of its contributors
15*bc421551SDag-Erling Smørgrav       may be used to endorse or promote products derived from this software
16*bc421551SDag-Erling Smørgrav       without specific prior written permission.
17*bc421551SDag-Erling Smørgrav 
18*bc421551SDag-Erling Smørgrav    THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
19*bc421551SDag-Erling Smørgrav    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*bc421551SDag-Erling Smørgrav    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*bc421551SDag-Erling Smørgrav    ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22*bc421551SDag-Erling Smørgrav    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*bc421551SDag-Erling Smørgrav    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*bc421551SDag-Erling Smørgrav    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*bc421551SDag-Erling Smørgrav    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*bc421551SDag-Erling Smørgrav    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*bc421551SDag-Erling Smørgrav    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*bc421551SDag-Erling Smørgrav    SUCH DAMAGE.  */
29*bc421551SDag-Erling Smørgrav 
30*bc421551SDag-Erling Smørgrav #include "private.h"
31*bc421551SDag-Erling Smørgrav #include <locale.h>
32*bc421551SDag-Erling Smørgrav #include <stdio.h>
33*bc421551SDag-Erling Smørgrav 
34*bc421551SDag-Erling Smørgrav #if !HAVE_POSIX_DECLS
35*bc421551SDag-Erling Smørgrav extern char *		optarg;
36*bc421551SDag-Erling Smørgrav extern int		optind;
37*bc421551SDag-Erling Smørgrav #endif
38*bc421551SDag-Erling Smørgrav 
39*bc421551SDag-Erling Smørgrav static int		retval = EXIT_SUCCESS;
40*bc421551SDag-Erling Smørgrav 
41*bc421551SDag-Erling Smørgrav static void		display(const char *, time_t);
42*bc421551SDag-Erling Smørgrav static void		dogmt(void);
43*bc421551SDag-Erling Smørgrav static void		errensure(void);
44*bc421551SDag-Erling Smørgrav static void		timeout(FILE *, const char *, const struct tm *);
45*bc421551SDag-Erling Smørgrav static ATTRIBUTE_NORETURN void usage(void);
46*bc421551SDag-Erling Smørgrav 
47*bc421551SDag-Erling Smørgrav int
48*bc421551SDag-Erling Smørgrav main(const int argc, char *argv[])
49*bc421551SDag-Erling Smørgrav {
50*bc421551SDag-Erling Smørgrav 	register const char *	format = "+%+";
51*bc421551SDag-Erling Smørgrav 	register int		ch;
52*bc421551SDag-Erling Smørgrav 	register bool		rflag = false;
53*bc421551SDag-Erling Smørgrav 	time_t			t;
54*bc421551SDag-Erling Smørgrav 	intmax_t		secs;
55*bc421551SDag-Erling Smørgrav 	char *			endarg;
56*bc421551SDag-Erling Smørgrav 
57*bc421551SDag-Erling Smørgrav #ifdef LC_ALL
58*bc421551SDag-Erling Smørgrav 	setlocale(LC_ALL, "");
59*bc421551SDag-Erling Smørgrav #endif /* defined(LC_ALL) */
60*bc421551SDag-Erling Smørgrav #if HAVE_GETTEXT
61*bc421551SDag-Erling Smørgrav # ifdef TZ_DOMAINDIR
62*bc421551SDag-Erling Smørgrav 	bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
63*bc421551SDag-Erling Smørgrav # endif /* defined(TEXTDOMAINDIR) */
64*bc421551SDag-Erling Smørgrav 	textdomain(TZ_DOMAIN);
65*bc421551SDag-Erling Smørgrav #endif /* HAVE_GETTEXT */
66*bc421551SDag-Erling Smørgrav 	t = time(NULL);
67*bc421551SDag-Erling Smørgrav 	while ((ch = getopt(argc, argv, "ucr:")) != EOF && ch != -1) {
68*bc421551SDag-Erling Smørgrav 		switch (ch) {
69*bc421551SDag-Erling Smørgrav 		default:
70*bc421551SDag-Erling Smørgrav 			usage();
71*bc421551SDag-Erling Smørgrav 		case 'u':		/* do it in UT */
72*bc421551SDag-Erling Smørgrav 		case 'c':
73*bc421551SDag-Erling Smørgrav 			dogmt();
74*bc421551SDag-Erling Smørgrav 			break;
75*bc421551SDag-Erling Smørgrav 		case 'r':		/* seconds since 1970 */
76*bc421551SDag-Erling Smørgrav 			if (rflag) {
77*bc421551SDag-Erling Smørgrav 				fprintf(stderr,
78*bc421551SDag-Erling Smørgrav 					_("date: error: multiple -r's used"));
79*bc421551SDag-Erling Smørgrav 				usage();
80*bc421551SDag-Erling Smørgrav 			}
81*bc421551SDag-Erling Smørgrav 			rflag = true;
82*bc421551SDag-Erling Smørgrav 			errno = 0;
83*bc421551SDag-Erling Smørgrav 			secs = strtoimax(optarg, &endarg, 0);
84*bc421551SDag-Erling Smørgrav 			if (*endarg || optarg == endarg)
85*bc421551SDag-Erling Smørgrav 				errno = EINVAL;
86*bc421551SDag-Erling Smørgrav 			else if (! (TIME_T_MIN <= secs && secs <= TIME_T_MAX))
87*bc421551SDag-Erling Smørgrav 				errno = ERANGE;
88*bc421551SDag-Erling Smørgrav 			if (errno) {
89*bc421551SDag-Erling Smørgrav 				perror(optarg);
90*bc421551SDag-Erling Smørgrav 				errensure();
91*bc421551SDag-Erling Smørgrav 				exit(retval);
92*bc421551SDag-Erling Smørgrav 			}
93*bc421551SDag-Erling Smørgrav 			t = secs;
94*bc421551SDag-Erling Smørgrav 			break;
95*bc421551SDag-Erling Smørgrav 		}
96*bc421551SDag-Erling Smørgrav 	}
97*bc421551SDag-Erling Smørgrav 	if (optind < argc) {
98*bc421551SDag-Erling Smørgrav 	  if (argc - optind != 1) {
99*bc421551SDag-Erling Smørgrav 	    fprintf(stderr,
100*bc421551SDag-Erling Smørgrav 		    _("date: error: multiple operands in command line\n"));
101*bc421551SDag-Erling Smørgrav 	    usage();
102*bc421551SDag-Erling Smørgrav 	  }
103*bc421551SDag-Erling Smørgrav 	  format = argv[optind];
104*bc421551SDag-Erling Smørgrav 	  if (*format != '+') {
105*bc421551SDag-Erling Smørgrav 	    fprintf(stderr, _("date: unknown operand: %s\n"), format);
106*bc421551SDag-Erling Smørgrav 	    usage();
107*bc421551SDag-Erling Smørgrav 	  }
108*bc421551SDag-Erling Smørgrav 	}
109*bc421551SDag-Erling Smørgrav 
110*bc421551SDag-Erling Smørgrav 	display(format, t);
111*bc421551SDag-Erling Smørgrav 	return retval;
112*bc421551SDag-Erling Smørgrav }
113*bc421551SDag-Erling Smørgrav 
114*bc421551SDag-Erling Smørgrav static void
115*bc421551SDag-Erling Smørgrav dogmt(void)
116*bc421551SDag-Erling Smørgrav {
117*bc421551SDag-Erling Smørgrav 	static char **	fakeenv;
118*bc421551SDag-Erling Smørgrav 
119*bc421551SDag-Erling Smørgrav 	if (fakeenv == NULL) {
120*bc421551SDag-Erling Smørgrav 		static char	tzeutc0[] = "TZ=UTC0";
121*bc421551SDag-Erling Smørgrav 		ptrdiff_t from, to, n;
122*bc421551SDag-Erling Smørgrav 
123*bc421551SDag-Erling Smørgrav 		for (n = 0;  environ[n] != NULL;  ++n)
124*bc421551SDag-Erling Smørgrav 			continue;
125*bc421551SDag-Erling Smørgrav #if defined ckd_add && defined ckd_mul
126*bc421551SDag-Erling Smørgrav 		if (!ckd_add(&n, n, 2) && !ckd_mul(&n, n, sizeof *fakeenv)
127*bc421551SDag-Erling Smørgrav 		    && n <= SIZE_MAX)
128*bc421551SDag-Erling Smørgrav 		  fakeenv = malloc(n);
129*bc421551SDag-Erling Smørgrav #else
130*bc421551SDag-Erling Smørgrav 		if (n <= min(PTRDIFF_MAX, SIZE_MAX) / sizeof *fakeenv - 2)
131*bc421551SDag-Erling Smørgrav 		  fakeenv = malloc((n + 2) * sizeof *fakeenv);
132*bc421551SDag-Erling Smørgrav #endif
133*bc421551SDag-Erling Smørgrav 		if (fakeenv == NULL) {
134*bc421551SDag-Erling Smørgrav 			fprintf(stderr, _("date: Memory exhausted\n"));
135*bc421551SDag-Erling Smørgrav 			errensure();
136*bc421551SDag-Erling Smørgrav 			exit(retval);
137*bc421551SDag-Erling Smørgrav 		}
138*bc421551SDag-Erling Smørgrav 		to = 0;
139*bc421551SDag-Erling Smørgrav 		fakeenv[to++] = tzeutc0;
140*bc421551SDag-Erling Smørgrav 		for (from = 1; environ[from] != NULL; ++from)
141*bc421551SDag-Erling Smørgrav 			if (strncmp(environ[from], "TZ=", 3) != 0)
142*bc421551SDag-Erling Smørgrav 				fakeenv[to++] = environ[from];
143*bc421551SDag-Erling Smørgrav 		fakeenv[to] = NULL;
144*bc421551SDag-Erling Smørgrav 		environ = fakeenv;
145*bc421551SDag-Erling Smørgrav 	}
146*bc421551SDag-Erling Smørgrav }
147*bc421551SDag-Erling Smørgrav 
148*bc421551SDag-Erling Smørgrav static void
149*bc421551SDag-Erling Smørgrav errensure(void)
150*bc421551SDag-Erling Smørgrav {
151*bc421551SDag-Erling Smørgrav 	if (retval == EXIT_SUCCESS)
152*bc421551SDag-Erling Smørgrav 		retval = EXIT_FAILURE;
153*bc421551SDag-Erling Smørgrav }
154*bc421551SDag-Erling Smørgrav 
155*bc421551SDag-Erling Smørgrav static void
156*bc421551SDag-Erling Smørgrav usage(void)
157*bc421551SDag-Erling Smørgrav {
158*bc421551SDag-Erling Smørgrav 	fprintf(stderr,
159*bc421551SDag-Erling Smørgrav 		       _("date: usage: date [-u] [-c] [-r seconds]"
160*bc421551SDag-Erling Smørgrav 			 " [+format]\n"));
161*bc421551SDag-Erling Smørgrav 	errensure();
162*bc421551SDag-Erling Smørgrav 	exit(retval);
163*bc421551SDag-Erling Smørgrav }
164*bc421551SDag-Erling Smørgrav 
165*bc421551SDag-Erling Smørgrav static void
166*bc421551SDag-Erling Smørgrav display(char const *format, time_t now)
167*bc421551SDag-Erling Smørgrav {
168*bc421551SDag-Erling Smørgrav 	struct tm *tmp;
169*bc421551SDag-Erling Smørgrav 
170*bc421551SDag-Erling Smørgrav 	tmp = localtime(&now);
171*bc421551SDag-Erling Smørgrav 	if (!tmp) {
172*bc421551SDag-Erling Smørgrav 		fprintf(stderr,
173*bc421551SDag-Erling Smørgrav 			_("date: error: time out of range\n"));
174*bc421551SDag-Erling Smørgrav 		errensure();
175*bc421551SDag-Erling Smørgrav 		return;
176*bc421551SDag-Erling Smørgrav 	}
177*bc421551SDag-Erling Smørgrav 	timeout(stdout, format, tmp);
178*bc421551SDag-Erling Smørgrav 	putchar('\n');
179*bc421551SDag-Erling Smørgrav 	fflush(stdout);
180*bc421551SDag-Erling Smørgrav 	fflush(stderr);
181*bc421551SDag-Erling Smørgrav 	if (ferror(stdout) || ferror(stderr)) {
182*bc421551SDag-Erling Smørgrav 		fprintf(stderr,
183*bc421551SDag-Erling Smørgrav 			_("date: error: couldn't write results\n"));
184*bc421551SDag-Erling Smørgrav 		errensure();
185*bc421551SDag-Erling Smørgrav 	}
186*bc421551SDag-Erling Smørgrav }
187*bc421551SDag-Erling Smørgrav 
188*bc421551SDag-Erling Smørgrav static void
189*bc421551SDag-Erling Smørgrav timeout(FILE *fp, char const *format, struct tm const *tmp)
190*bc421551SDag-Erling Smørgrav {
191*bc421551SDag-Erling Smørgrav 	char *cp = NULL;
192*bc421551SDag-Erling Smørgrav 	ptrdiff_t result;
193*bc421551SDag-Erling Smørgrav 	ptrdiff_t size = 1024 / 2;
194*bc421551SDag-Erling Smørgrav 
195*bc421551SDag-Erling Smørgrav 	for ( ; ; ) {
196*bc421551SDag-Erling Smørgrav #ifdef ckd_mul
197*bc421551SDag-Erling Smørgrav 		bool bigger = !ckd_mul(&size, size, 2) && size <= SIZE_MAX;
198*bc421551SDag-Erling Smørgrav #else
199*bc421551SDag-Erling Smørgrav 		bool bigger = (size <= min(PTRDIFF_MAX, SIZE_MAX) / 2
200*bc421551SDag-Erling Smørgrav 			       && (size *= 2, true));
201*bc421551SDag-Erling Smørgrav #endif
202*bc421551SDag-Erling Smørgrav 		char *newcp = bigger ? realloc(cp, size) : NULL;
203*bc421551SDag-Erling Smørgrav 		if (!newcp) {
204*bc421551SDag-Erling Smørgrav 			fprintf(stderr,
205*bc421551SDag-Erling Smørgrav 				_("date: error: can't get memory\n"));
206*bc421551SDag-Erling Smørgrav 			errensure();
207*bc421551SDag-Erling Smørgrav 			exit(retval);
208*bc421551SDag-Erling Smørgrav 		}
209*bc421551SDag-Erling Smørgrav 		cp = newcp;
210*bc421551SDag-Erling Smørgrav 		result = strftime(cp, size, format, tmp);
211*bc421551SDag-Erling Smørgrav 		if (result != 0)
212*bc421551SDag-Erling Smørgrav 			break;
213*bc421551SDag-Erling Smørgrav 	}
214*bc421551SDag-Erling Smørgrav 	fwrite(cp + 1, 1, result - 1, fp);
215*bc421551SDag-Erling Smørgrav 	free(cp);
216*bc421551SDag-Erling Smørgrav }
217