]> git.saurik.com Git - apple/libc.git/blame - stdtime/getdate.c
Libc-1272.250.1.tar.gz
[apple/libc.git] / stdtime / getdate.c
CommitLineData
59e0d9fe
A
1/*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
59e0d9fe
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <stdio.h>
25#include <time.h>
26#include <stdlib.h>
224c7076 27#include <string.h>
59e0d9fe
A
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <errno.h>
31
32enum {
33 DATEMSK_NOT_DEFINED = 1,
34 CANT_OPEN,
35 CANT_FSTAT,
36 NOT_FILE,
37 IO_ERROR,
38 OUT_OF_MEMORY,
39 NO_MATCH,
40 INVALID_DATE
41};
42
43#define DATEMSK "DATEMSK"
44#define TM_SEC_SET 0x01
45#define TM_MIN_SET 0x02
46#define TM_HOUR_SET 0x04
47#define TM_MDAY_SET 0x01
48#define TM_MON_SET 0x02
49#define TM_YEAR_SET 0x04
50#define UNDEFINED -1
51
224c7076 52static const struct tm tmundef = {
59e0d9fe
A
53 UNDEFINED,
54 UNDEFINED,
55 UNDEFINED,
56 UNDEFINED,
57 UNDEFINED,
58 UNDEFINED,
59 UNDEFINED
60};
61
62int getdate_err;
63
64/*
65 * getdate
66 *
67 * Call strptime() on each line of the DATEMSK file, and manipulate the
68 * resulting tm structure.
69 */
70struct tm *
71getdate(const char *str)
72{
224c7076
A
73 static struct tm tm;
74 struct tm *now, *result = NULL;
59e0d9fe
A
75 time_t t;
76 FILE *fp;
224c7076 77 int bufsiz, offset, len, dateset, timeset, saveerrno, wday_set, save_mon;
59e0d9fe
A
78 char *buf;
79 struct stat st;
80 char *file = getenv(DATEMSK);
81
82 if(!file || !*file) {
83 getdate_err = DATEMSK_NOT_DEFINED;
84 return NULL;
85 }
86 saveerrno = errno;
87 if((fp = fopen(file, "r")) == NULL) {
88 getdate_err = CANT_OPEN;
89 errno = saveerrno;
90 return NULL;
91 }
92 do {
93 if(fstat(fileno(fp), &st) < 0) {
94 getdate_err = CANT_FSTAT;
95 break;
96 }
97 if((st.st_mode & S_IFMT) != S_IFREG) {
98 getdate_err = NOT_FILE;
99 break;
100 }
101 if((buf = malloc(bufsiz = BUFSIZ)) == NULL) {
102 getdate_err = OUT_OF_MEMORY;
103 break;
104 }
105 do {
106 offset = 0;
107 for(;;) {
108 if(fgets(buf + offset, bufsiz - offset, fp) == NULL) {
109 if(ferror(fp)) {
110 getdate_err = IO_ERROR;
111 break;
112 }
113 if(offset == 0) {
114 getdate_err = NO_MATCH;
115 break;
116 }
117 len = strlen(buf);
118 } else if((len = strlen(buf)) == bufsiz - 1
119 && buf[len - 1] != '\n') {
120 char *newptr = realloc(buf, (bufsiz += BUFSIZ));
121 if(newptr == NULL) {
122 getdate_err = OUT_OF_MEMORY;
123 break;
124 }
125 buf = newptr;
126 offset = len;
127 continue;
128 }
129 if(buf[len - 1] == '\n')
130 buf[len - 1] = 0;
131 tm = tmundef;
132 if(strptime(str, buf, &tm) == NULL) {
133 offset = 0;
134 continue;
135 }
136 time(&t);
137 now = localtime(&t);
138 dateset = timeset = 0;
139 if(tm.tm_sec != UNDEFINED)
140 timeset |= TM_SEC_SET;
141 if(tm.tm_min != UNDEFINED)
142 timeset |= TM_MIN_SET;
143 if(tm.tm_hour != UNDEFINED)
144 timeset |= TM_HOUR_SET;
145 if(tm.tm_mday != UNDEFINED)
146 dateset |= TM_MDAY_SET;
147 if(tm.tm_mon != UNDEFINED)
148 dateset |= TM_MON_SET;
149 if(tm.tm_year != UNDEFINED)
150 dateset |= TM_YEAR_SET;
151 wday_set = tm.tm_wday;
152
153 switch(timeset) {
154 case 0:
155 tm.tm_sec = now->tm_sec;
156 tm.tm_min = now->tm_min;
157 tm.tm_hour = now->tm_hour;
158 break;
159
160 case TM_SEC_SET:
161 tm.tm_hour = now->tm_hour;
162 tm.tm_min = now->tm_min;
163 if(tm.tm_sec < now->tm_sec)
164 tm.tm_min++;
165 break;
166
167 case TM_MIN_SET:
168 tm.tm_hour = now->tm_hour;
169 if(tm.tm_min < now->tm_min)
170 tm.tm_hour++;
171 tm.tm_sec = 0;
172 break;
173
174 case TM_MIN_SET | TM_SEC_SET:
175 tm.tm_hour = now->tm_hour;
176 if((60 * tm.tm_min + tm.tm_sec)
177 < (60 * now->tm_min + now->tm_sec))
178 tm.tm_hour++;
179 break;
180
181 case TM_HOUR_SET:
182 tm.tm_min = 0;
183 tm.tm_sec = 0;
184 break;
185
186 case TM_HOUR_SET | TM_SEC_SET:
187 tm.tm_min = 0;
188 break;
189
190 case TM_HOUR_SET | TM_MIN_SET:
191 tm.tm_sec = 0;
192 break;
193 }
194
195 switch(dateset) {
196 case 0:
197 tm.tm_mday = now->tm_mday;
198 if(tm.tm_hour < now->tm_hour)
199 tm.tm_mday++;
200 tm.tm_mon = now->tm_mon;
201 tm.tm_year = now->tm_year;
202 break;
203
204 case TM_MDAY_SET:
205 tm.tm_year = now->tm_year;
206 tm.tm_mon = now->tm_mon;
207 if(tm.tm_mday < now->tm_mday)
208 tm.tm_mon++;
209 break;
210
211 case TM_MON_SET:
212 case TM_MON_SET | TM_MDAY_SET:
213 tm.tm_year = now->tm_year;
214 if(tm.tm_mon < now->tm_mon)
215 tm.tm_year++;
216 if(!(dateset & TM_MDAY_SET))
217 tm.tm_mday = 1;
218 break;
219
220 case TM_YEAR_SET:
221 case TM_YEAR_SET | TM_MON_SET:
222 if(!(dateset & TM_MON_SET))
224c7076 223 tm.tm_mon = 0;
59e0d9fe
A
224 tm.tm_mday = 1;
225 break;
226
227 case TM_YEAR_SET | TM_MDAY_SET:
228 tm.tm_mon = now->tm_mon;
229 if(tm.tm_mday < now->tm_mday)
230 tm.tm_mon++;
231 break;
232 }
233
234 tm.tm_wday = now->tm_wday;
235 tm.tm_gmtoff = now->tm_gmtoff; /* XXX: can't grok timezones */
236 tm.tm_isdst = -1;
224c7076 237 save_mon = tm.tm_mon;
59e0d9fe
A
238 if(mktime(&tm) == (time_t)-1) {
239 getdate_err = INVALID_DATE;
240 break;
224c7076
A
241 } else if ((dateset & TM_MON_SET) && (tm.tm_mon != save_mon)) { /* Did mktime fixup an overflow date? */
242 getdate_err = INVALID_DATE;
243 break;
59e0d9fe 244 }
974e3884
A
245 if(wday_set != UNDEFINED &&
246 (dateset != (TM_YEAR_SET | TM_MON_SET | TM_MDAY_SET))) {
247 /*
248 * We got back a week day, but not enough information to resolve it
249 * to a specific day, so we need to push forward the time to the
250 * correct wday. <rdar://problem/27439823>
251 */
59e0d9fe 252 int delta = wday_set - tm.tm_wday;
974e3884 253 if(delta < 0) {
59e0d9fe 254 delta += 7;
974e3884 255 }
59e0d9fe
A
256 tm.tm_mday += delta;
257 if(mktime(&tm) == (time_t)-1) {
258 getdate_err = INVALID_DATE;
259 break;
260 }
261 }
262 result = &tm;
224c7076 263 break;
59e0d9fe
A
264 }
265 } while(0);
266
267 free(buf);
268 } while(0);
269
270 fclose(fp);
271 errno = saveerrno;
272 return result;
273}