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