2 * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
41 static struct trans trans_mon
[] = {
42 { 1, "january" }, { 2, "february" }, { 3, "march" }, { 4, "april" },
43 { 5, "may"}, { 6, "june" }, { 7, "july" }, { 8, "august" },
44 { 9, "september" }, { 10, "october" }, { 11, "november" }, { 12, "december" },
48 static struct trans trans_wday
[] = {
49 { 0, "sunday" }, { 1, "monday" }, { 2, "tuesday" }, { 3, "wednesday" },
50 { 4, "thursday" }, { 5, "friday" }, { 6, "saturday" },
54 static char digits
[] = "0123456789";
55 static int adjhour(struct tm
*, char, int, int);
58 domktime(struct tm
*t
, char type
)
62 while ((ret
= mktime(t
)) == -1 && t
->tm_year
> 68 && t
->tm_year
< 138)
63 /* While mktime() fails, adjust by an hour */
64 adjhour(t
, type
== '-' ? type
: '+', 1, 0);
70 trans(const struct trans t
[], const char *arg
)
74 for (f
= 0; t
[f
].val
!= -1; f
++)
75 if (!strncasecmp(t
[f
].str
, arg
, 3) ||
76 !strncasecmp(t
[f
].str
, arg
, strlen(t
[f
].str
)))
83 vary_append(struct vary
*v
, char *arg
)
85 struct vary
*result
, **nextp
;
95 if ((*nextp
= (struct vary
*)malloc(sizeof(struct vary
))) == NULL
)
98 (*nextp
)->next
= NULL
;
102 static int mdays
[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
105 daysinmonth(const struct tm
*t
)
109 year
= t
->tm_year
+ 1900;
114 else if (!(year
% 100))
116 else if (!(year
% 4))
120 else if (t
->tm_mon
>= 0 && t
->tm_mon
< 12)
121 return mdays
[t
->tm_mon
];
128 adjyear(struct tm
*t
, char type
, int val
, int mk
)
140 t
->tm_year
+= 100; /* as per date.c */
141 else if (t
->tm_year
> 1900)
142 t
->tm_year
-= 1900; /* struct tm holds years since 1900 */
145 return !mk
|| domktime(t
, type
) != -1;
149 adjmon(struct tm
*t
, char type
, int val
, int istext
, int mk
)
159 if (val
<= t
->tm_mon
)
160 val
+= 11 - t
->tm_mon
; /* early next year */
162 val
-= t
->tm_mon
+ 1; /* later this year */
165 if (!adjyear(t
, '+', (t
->tm_mon
+ val
) / 12, 0))
176 if (val
-1 > t
->tm_mon
)
177 val
= 13 - val
+ t
->tm_mon
; /* later last year */
179 val
= t
->tm_mon
- val
+ 1; /* early this year */
182 if (!adjyear(t
, '-', val
/ 12, 0))
185 if (val
> t
->tm_mon
) {
186 if (!adjyear(t
, '-', 1, 0))
195 if (val
> 12 || val
< 1)
200 /* e.g., -v-1m on March, 31 is the last day of February in common sense */
201 lmdays
= daysinmonth(t
);
202 if (t
->tm_mday
> lmdays
)
205 return !mk
|| domktime(t
, type
) != -1;
209 adjday(struct tm
*t
, char type
, int val
, int mk
)
216 lmdays
= daysinmonth(t
);
217 if (val
> lmdays
- t
->tm_mday
) {
218 val
-= lmdays
- t
->tm_mday
+ 1;
220 if (!adjmon(t
, '+', 1, 0, 0))
230 if (val
>= t
->tm_mday
) {
233 if (!adjmon(t
, '-', 1, 0, 0))
235 t
->tm_mday
= daysinmonth(t
);
242 if (val
> 0 && val
<= daysinmonth(t
))
249 return !mk
|| domktime(t
, type
) != -1;
253 adjwday(struct tm
*t
, char type
, int val
, int istext
, int mk
)
261 if (val
< t
->tm_wday
)
262 val
= 7 - t
->tm_wday
+ val
; /* early next week */
264 val
-= t
->tm_wday
; /* later this week */
266 val
*= 7; /* "-v+5w" == "5 weeks in the future" */
267 return !val
|| adjday(t
, '+', val
, mk
);
270 if (val
> t
->tm_wday
)
271 val
= 7 - val
+ t
->tm_wday
; /* later last week */
273 val
= t
->tm_wday
- val
; /* early this week */
275 val
*= 7; /* "-v-5w" == "5 weeks ago" */
276 return !val
|| adjday(t
, '-', val
, mk
);
278 if (val
< t
->tm_wday
)
279 return adjday(t
, '-', t
->tm_wday
- val
, mk
);
282 else if (val
> t
->tm_wday
)
283 return adjday(t
, '+', val
- t
->tm_wday
, mk
);
289 adjhour(struct tm
*t
, char type
, int val
, int mk
)
299 days
= (t
->tm_hour
+ val
) / 24;
303 if (!adjday(t
, '+', days
, 0))
314 if (val
> t
->tm_hour
) {
319 if (!adjday(t
, '-', days
, 0))
330 return !mk
|| domktime(t
, type
) != -1;
334 adjmin(struct tm
*t
, char type
, int val
, int mk
)
342 if (!adjhour(t
, '+', (t
->tm_min
+ val
) / 60, 0))
353 if (!adjhour(t
, '-', val
/ 60, 0))
356 if (val
> t
->tm_min
) {
357 if (!adjhour(t
, '-', 1, 0))
371 return !mk
|| domktime(t
, type
) != -1;
375 adjsec(struct tm
*t
, char type
, int val
, int mk
)
383 if (!adjmin(t
, '+', (t
->tm_sec
+ val
) / 60, 0))
394 if (!adjmin(t
, '-', val
/ 60, 0))
397 if (val
> t
->tm_sec
) {
398 if (!adjmin(t
, '-', 1, 0))
412 return !mk
|| domktime(t
, type
) != -1;
416 vary_apply(const struct vary
*v
, struct tm
*t
)
424 for (; v
; v
= v
->next
) {
427 if (type
== '+' || type
== '-')
438 if (strspn(arg
, digits
) != len
-1) {
439 val
= trans(trans_wday
, arg
);
441 if (!adjwday(t
, type
, val
, 1, 1))
444 val
= trans(trans_mon
, arg
);
446 if (!adjmon(t
, type
, val
, 1, 1))
457 if (!adjsec(t
, type
, val
, 1))
461 if (!adjmin(t
, type
, val
, 1))
465 if (!adjhour(t
, type
, val
, 1))
470 if (!adjday(t
, type
, val
, 1))
475 if (!adjwday(t
, type
, val
, 0, 1))
480 if (!adjmon(t
, type
, val
, 0, 1))
485 if (!adjyear(t
, type
, val
, 1))
497 vary_destroy(struct vary
*v
)