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