]> git.saurik.com Git - apple/libc.git/blob - stdtime/getdate.c
84a7b2803ceca90344dc757176bb23a57315331d
[apple/libc.git] / stdtime / getdate.c
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 #include <stdio.h>
27 #include <time.h>
28 #include <stdlib.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <errno.h>
32
33 enum {
34 DATEMSK_NOT_DEFINED = 1,
35 CANT_OPEN,
36 CANT_FSTAT,
37 NOT_FILE,
38 IO_ERROR,
39 OUT_OF_MEMORY,
40 NO_MATCH,
41 INVALID_DATE
42 };
43
44 #define DATEMSK "DATEMSK"
45 #define TM_SEC_SET 0x01
46 #define TM_MIN_SET 0x02
47 #define TM_HOUR_SET 0x04
48 #define TM_MDAY_SET 0x01
49 #define TM_MON_SET 0x02
50 #define TM_YEAR_SET 0x04
51 #define UNDEFINED -1
52
53 static struct tm tmundef = {
54 UNDEFINED,
55 UNDEFINED,
56 UNDEFINED,
57 UNDEFINED,
58 UNDEFINED,
59 UNDEFINED,
60 UNDEFINED
61 };
62
63 int getdate_err;
64
65 /*
66 * getdate
67 *
68 * Call strptime() on each line of the DATEMSK file, and manipulate the
69 * resulting tm structure.
70 */
71 struct tm *
72 getdate(const char *str)
73 {
74 static struct tm tm, *now, *result = NULL;
75 time_t t;
76 FILE *fp;
77 int bufsiz, offset, len, dateset, timeset, saveerrno, wday_set;
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))
223 tm.tm_mon = 1;
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;
237
238 if(mktime(&tm) == (time_t)-1) {
239 getdate_err = INVALID_DATE;
240 break;
241 }
242 if(wday_set != UNDEFINED) {
243 int delta = wday_set - tm.tm_wday;
244 if(delta && (dateset & TM_MDAY_SET)) {
245 getdate_err = INVALID_DATE;
246 break;
247 }
248 if(delta < 0)
249 delta += 7;
250 tm.tm_mday += delta;
251 if(mktime(&tm) == (time_t)-1) {
252 getdate_err = INVALID_DATE;
253 break;
254 }
255 }
256 result = &tm;
257 }
258 } while(0);
259
260 free(buf);
261 } while(0);
262
263 fclose(fp);
264 errno = saveerrno;
265 return result;
266 }