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