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
26 * $FreeBSD: src/bin/date/vary.c,v 1.16 2004/08/09 13:43:39 yar Exp $
27 * $DragonFly: src/bin/date/vary.c,v 1.4 2005/07/20 06:10:51 cpressey Exp $
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
)
158 if (val
<= t
->tm_mon
)
159 val
+= 11 - t
->tm_mon
; /* early next year */
161 val
-= t
->tm_mon
+ 1; /* later this year */
164 if (!adjyear(t
, '+', (t
->tm_mon
+ val
) / 12, 0))
175 if (val
-1 > t
->tm_mon
)
176 val
= 13 - val
+ t
->tm_mon
; /* later last year */
178 val
= t
->tm_mon
- val
+ 1; /* early this year */
181 if (!adjyear(t
, '-', val
/ 12, 0))
184 if (val
> t
->tm_mon
) {
185 if (!adjyear(t
, '-', 1, 0))
194 if (val
> 12 || val
< 1)
199 /* e.g., -v-1m on March, 31 is the last day of February in common sense */
200 lmdays
= daysinmonth(t
);
201 if (t
->tm_mday
> lmdays
)
204 return !mk
|| domktime(t
, type
) != -1;
208 adjday(struct tm
*t
, char type
, int val
, int mk
)
215 daycount
= daysinmonth(t
);
216 if (val
> daycount
- t
->tm_mday
) {
217 val
-= daycount
- t
->tm_mday
+ 1;
219 if (!adjmon(t
, '+', 1, 0, 0))
229 if (val
>= t
->tm_mday
) {
232 if (!adjmon(t
, '-', 1, 0, 0))
234 t
->tm_mday
= daysinmonth(t
);
241 if (val
> 0 && val
<= daysinmonth(t
))
248 return !mk
|| domktime(t
, type
) != -1;
252 adjwday(struct tm
*t
, char type
, int val
, int istext
, int mk
)
260 if (val
< t
->tm_wday
)
261 val
= 7 - t
->tm_wday
+ val
; /* early next week */
263 val
-= t
->tm_wday
; /* later this week */
265 val
*= 7; /* "-v+5w" == "5 weeks in the future" */
266 return !val
|| adjday(t
, '+', val
, mk
);
269 if (val
> t
->tm_wday
)
270 val
= 7 - val
+ t
->tm_wday
; /* later last week */
272 val
= t
->tm_wday
- val
; /* early this week */
274 val
*= 7; /* "-v-5w" == "5 weeks ago" */
275 return !val
|| adjday(t
, '-', val
, mk
);
277 if (val
< t
->tm_wday
)
278 return adjday(t
, '-', t
->tm_wday
- val
, mk
);
281 else if (val
> t
->tm_wday
)
282 return adjday(t
, '+', val
- t
->tm_wday
, mk
);
288 adjhour(struct tm
*t
, char type
, int val
, int mk
)
298 days
= (t
->tm_hour
+ val
) / 24;
302 if (!adjday(t
, '+', days
, 0))
313 if (val
> t
->tm_hour
) {
318 if (!adjday(t
, '-', days
, 0))
329 return !mk
|| domktime(t
, type
) != -1;
333 adjmin(struct tm
*t
, char type
, int val
, int mk
)
341 if (!adjhour(t
, '+', (t
->tm_min
+ val
) / 60, 0))
352 if (!adjhour(t
, '-', val
/ 60, 0))
355 if (val
> t
->tm_min
) {
356 if (!adjhour(t
, '-', 1, 0))
370 return !mk
|| domktime(t
, type
) != -1;
374 adjsec(struct tm
*t
, char type
, int val
, int mk
)
382 if (!adjmin(t
, '+', (t
->tm_sec
+ val
) / 60, 0))
393 if (!adjmin(t
, '-', val
/ 60, 0))
396 if (val
> t
->tm_sec
) {
397 if (!adjmin(t
, '-', 1, 0))
411 return !mk
|| domktime(t
, type
) != -1;
415 vary_apply(const struct vary
*v
, struct tm
*t
)
423 for (; v
; v
= v
->next
) {
426 if (type
== '+' || type
== '-')
437 if (strspn(arg
, digits
) != len
-1) {
438 val
= trans(trans_wday
, arg
);
440 if (!adjwday(t
, type
, val
, 1, 1))
443 val
= trans(trans_mon
, arg
);
445 if (!adjmon(t
, type
, val
, 1, 1))
456 if (!adjsec(t
, type
, val
, 1))
460 if (!adjmin(t
, type
, val
, 1))
464 if (!adjhour(t
, type
, val
, 1))
469 if (!adjday(t
, type
, val
, 1))
474 if (!adjwday(t
, type
, val
, 0, 1))
479 if (!adjmon(t
, type
, val
, 0, 1))
484 if (!adjyear(t
, type
, val
, 1))
496 vary_destroy(struct vary
*v
)