Bump to tzdata 2016i
[platform/upstream/tzdata.git] / date.c
1 /* Display or set the current time and date.  */
2
3 /* Copyright 1985, 1987, 1988 The Regents of the University of California.
4    All rights reserved.
5
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.
17
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.  */
29
30 #include "private.h"
31 #include "locale.h"
32
33 /*
34 ** The two things date knows about time are. . .
35 */
36
37 #ifndef TM_YEAR_BASE
38 #define TM_YEAR_BASE    1900
39 #endif /* !defined TM_YEAR_BASE */
40
41 #ifndef SECSPERMIN
42 #define SECSPERMIN      60
43 #endif /* !defined SECSPERMIN */
44
45 extern char **          environ;
46
47 #if !HAVE_POSIX_DECLS
48 extern char *           optarg;
49 extern int              optind;
50 extern char *           tzname[];
51 #endif
52
53 static int              retval = EXIT_SUCCESS;
54
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);
60
61 int
62 main(const int argc, char *argv[])
63 {
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;
71
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();
96                         }
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);
108                         }
109                         t = secs;
110                         break;
111                 }
112         }
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();
122                         }
123                 else {
124                   fprintf(stderr, _("date: unknown operand: %s\n"), cp);
125                   usage();
126                 }
127         }
128
129         display(format, t);
130         return retval;
131 }
132
133 static void
134 dogmt(void)
135 {
136         static char **  fakeenv;
137
138         if (fakeenv == NULL) {
139                 register int    from;
140                 register int    to;
141                 register int    n;
142                 static char     tzegmt0[] = "TZ=GMT0";
143
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);
151                 }
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;
159         }
160 }
161
162 static void
163 errensure(void)
164 {
165         if (retval == EXIT_SUCCESS)
166                 retval = EXIT_FAILURE;
167 }
168
169 static void
170 usage(void)
171 {
172         fprintf(stderr,
173                        _("date: usage: date [-u] [-c] [-r seconds]"
174                          " [+format]\n"));
175         errensure();
176         exit(retval);
177 }
178
179 static void
180 display(char const *format, time_t now)
181 {
182         struct tm *tmp;
183
184         tmp = localtime(&now);
185         if (!tmp) {
186                 fprintf(stderr,
187                         _("date: error: time out of range\n"));
188                 errensure();
189                 return;
190         }
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();
199         }
200 }
201
202 #define INCR    1024
203
204 static void
205 timeout(FILE *fp, char const *format, struct tm const *tmp)
206 {
207         char *  cp;
208         size_t  result;
209         size_t  size;
210         struct tm tm;
211
212         if (*format == '\0')
213                 return;
214         if (!tmp) {
215                 fprintf(stderr, _("date: error: time out of range\n"));
216                 errensure();
217                 return;
218         }
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);
229                 }
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);
236         }
237         fwrite(cp, 1, result, fp);
238         free(cp);
239 }