• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <stdio.h>
33 
34 /*
35 ** The two things date knows about time are. . .
36 */
37 
38 #ifndef TM_YEAR_BASE
39 #define TM_YEAR_BASE	1900
40 #endif /* !defined TM_YEAR_BASE */
41 
42 #ifndef SECSPERMIN
43 #define SECSPERMIN	60
44 #endif /* !defined SECSPERMIN */
45 
46 #if !HAVE_POSIX_DECLS
47 extern char *		optarg;
48 extern int		optind;
49 #endif
50 
51 static int		retval = EXIT_SUCCESS;
52 
53 static void		display(const char *, time_t);
54 static void		dogmt(void);
55 static void		errensure(void);
56 static void		timeout(FILE *, const char *, const struct tm *);
57 static _Noreturn void	usage(void);
58 
59 int
main(const int argc,char * argv[])60 main(const int argc, char *argv[])
61 {
62 	register const char *	format = "+%+";
63 	register int		ch;
64 	register bool		rflag = false;
65 	time_t			t;
66 	intmax_t		secs;
67 	char *			endarg;
68 
69 #ifdef LC_ALL
70 	setlocale(LC_ALL, "");
71 #endif /* defined(LC_ALL) */
72 #if HAVE_GETTEXT
73 #ifdef TZ_DOMAINDIR
74 	bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
75 #endif /* defined(TEXTDOMAINDIR) */
76 	textdomain(TZ_DOMAIN);
77 #endif /* HAVE_GETTEXT */
78 	t = time(NULL);
79 	while ((ch = getopt(argc, argv, "ucr:")) != EOF && ch != -1) {
80 		switch (ch) {
81 		default:
82 			usage();
83 		case 'u':		/* do it in UT */
84 		case 'c':
85 			dogmt();
86 			break;
87 		case 'r':		/* seconds since 1970 */
88 			if (rflag) {
89 				fprintf(stderr,
90 					_("date: error: multiple -r's used"));
91 				usage();
92 			}
93 			rflag = true;
94 			errno = 0;
95 			secs = strtoimax(optarg, &endarg, 0);
96 			if (*endarg || optarg == endarg)
97 				errno = EINVAL;
98 			else if (! (TIME_T_MIN <= secs && secs <= TIME_T_MAX))
99 				errno = ERANGE;
100 			if (errno) {
101 				perror(optarg);
102 				errensure();
103 				exit(retval);
104 			}
105 			t = secs;
106 			break;
107 		}
108 	}
109 	if (optind < argc) {
110 	  if (argc - optind != 1) {
111 	    fprintf(stderr,
112 		    _("date: error: multiple operands in command line\n"));
113 	    usage();
114 	  }
115 	  format = argv[optind];
116 	  if (*format != '+') {
117 	    fprintf(stderr, _("date: unknown operand: %s\n"), format);
118 	    usage();
119 	  }
120 	}
121 
122 	display(format, t);
123 	return retval;
124 }
125 
126 static void
dogmt(void)127 dogmt(void)
128 {
129 	static char **	fakeenv;
130 
131 	if (fakeenv == NULL) {
132 		register int	from;
133 		register int	to;
134 		register int	n;
135 		static char	tzegmt0[] = "TZ=GMT0";
136 
137 		for (n = 0;  environ[n] != NULL;  ++n)
138 			continue;
139 		fakeenv = malloc((n + 2) * sizeof *fakeenv);
140 		if (fakeenv == NULL) {
141 			fprintf(stderr, _("date: Memory exhausted\n"));
142 			errensure();
143 			exit(retval);
144 		}
145 		to = 0;
146 		fakeenv[to++] = tzegmt0;
147 		for (from = 1; environ[from] != NULL; ++from)
148 			if (strncmp(environ[from], "TZ=", 3) != 0)
149 				fakeenv[to++] = environ[from];
150 		fakeenv[to] = NULL;
151 		environ = fakeenv;
152 	}
153 }
154 
155 static void
errensure(void)156 errensure(void)
157 {
158 	if (retval == EXIT_SUCCESS)
159 		retval = EXIT_FAILURE;
160 }
161 
162 static void
usage(void)163 usage(void)
164 {
165 	fprintf(stderr,
166 		       _("date: usage: date [-u] [-c] [-r seconds]"
167 			 " [+format]\n"));
168 	errensure();
169 	exit(retval);
170 }
171 
172 static void
display(char const * format,time_t now)173 display(char const *format, time_t now)
174 {
175 	struct tm *tmp;
176 
177 	tmp = localtime(&now);
178 	if (!tmp) {
179 		fprintf(stderr,
180 			_("date: error: time out of range\n"));
181 		errensure();
182 		return;
183 	}
184 	timeout(stdout, format, tmp);
185 	putchar('\n');
186 	fflush(stdout);
187 	fflush(stderr);
188 	if (ferror(stdout) || ferror(stderr)) {
189 		fprintf(stderr,
190 			_("date: error: couldn't write results\n"));
191 		errensure();
192 	}
193 }
194 
195 #define INCR	1024
196 
197 static void
timeout(FILE * fp,char const * format,struct tm const * tmp)198 timeout(FILE *fp, char const *format, struct tm const *tmp)
199 {
200 	char *	cp;
201 	size_t	result;
202 	size_t	size;
203 	struct tm tm;
204 
205 	if (!tmp) {
206 		fprintf(stderr, _("date: error: time out of range\n"));
207 		errensure();
208 		return;
209 	}
210 	tm = *tmp;
211 	tmp = &tm;
212 	size = INCR;
213 	cp = malloc(size);
214 	for ( ; ; ) {
215 		if (cp == NULL) {
216 			fprintf(stderr,
217 				_("date: error: can't get memory\n"));
218 			errensure();
219 			exit(retval);
220 		}
221 		result = strftime(cp, size, format, tmp);
222 		if (result != 0)
223 			break;
224 		size += INCR;
225 		cp = realloc(cp, size);
226 	}
227 	fwrite(cp + 1, 1, result - 1, fp);
228 	free(cp);
229 }
230