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
28 static const char rcsid[] =
29 "$FreeBSD: src/bin/date/vary.c,v 1.8.2.2 2000/12/08 11:42:53 brian Exp $";
43 static struct trans trans_mon[] = {
44 { 1, "january" }, { 2, "february" }, { 3, "march" }, { 4, "april" },
45 { 5, "may"}, { 6, "june" }, { 7, "july" }, { 8, "august" },
46 { 9, "september" }, { 10, "october" }, { 11, "november" }, { 12, "december" },
50 static struct trans trans_wday[] = {
51 { 0, "sunday" }, { 1, "monday" }, { 2, "tuesday" }, { 3, "wednesday" },
52 { 4, "thursday" }, { 5, "friday" }, { 6, "saturday" },
56 static char digits[] = "0123456789";
57 static int adjhour(struct tm *, char, int, int);
60 domktime(struct tm *t, char type)
64 while ((ret = mktime(t)) == -1 && t->tm_year > 68 && t->tm_year < 138)
65 /* While mktime() fails, adjust by an hour */
66 adjhour(t, type == '-' ? type : '+', 1, 0);
72 trans(const struct trans t[], const char *arg)
76 for (f = 0; t[f].val != -1; f++)
77 if (!strncasecmp(t[f].str, arg, 3) ||
78 !strncasecmp(t[f].str, arg, strlen(t[f].str)))
85 vary_append(struct vary *v, char *arg)
87 struct vary *result, **nextp;
97 if ((*nextp = (struct vary *)malloc(sizeof(struct vary))) == NULL)
100 (*nextp)->next = NULL;
104 static int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
107 daysinmonth(const struct tm *t)
111 year = t->tm_year + 1900;
116 else if (!(year % 100))
118 else if (!(year % 4))
122 else if (t->tm_mon >= 0 && t->tm_mon < 12)
123 return mdays[t->tm_mon];
130 adjyear(struct tm *t, char type, int val, int mk)
142 t->tm_year += 100; /* as per date.c */
143 else if (t->tm_year > 1900)
144 t->tm_year -= 1900; /* struct tm holds years since 1900 */
147 return !mk || domktime(t, type) != -1;
151 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 return !mk || domktime(t, type) != -1;
204 adjday(struct tm *t, char type, int val, int mk)
211 mdays = daysinmonth(t);
212 if (val > mdays - t->tm_mday) {
213 val -= mdays - t->tm_mday + 1;
215 if (!adjmon(t, '+', 1, 0, 0))
225 if (val >= t->tm_mday) {
228 if (!adjmon(t, '-', 1, 0, 0))
230 t->tm_mday = daysinmonth(t);
237 if (val > 0 && val <= daysinmonth(t))
244 return !mk || domktime(t, type) != -1;
248 adjwday(struct tm *t, char type, int val, int istext, int mk)
256 if (val < t->tm_wday)
257 val = 7 - t->tm_wday + val; /* early next week */
259 val -= t->tm_wday; /* later this week */
261 val *= 7; /* "-v+5w" == "5 weeks in the future" */
262 return !val || adjday(t, '+', val, mk);
265 if (val > t->tm_wday)
266 val = 7 - val + t->tm_wday; /* later last week */
268 val = t->tm_wday - val; /* early this week */
270 val *= 7; /* "-v-5w" == "5 weeks ago" */
271 return !val || adjday(t, '-', val, mk);
273 if (val < t->tm_wday)
274 return adjday(t, '-', t->tm_wday - val, mk);
277 else if (val > t->tm_wday)
278 return adjday(t, '+', val - t->tm_wday, mk);
284 adjhour(struct tm *t, char type, int val, int mk)
294 days = (t->tm_hour + val) / 24;
298 if (!adjday(t, '+', days, 0))
309 if (val > t->tm_hour) {
314 if (!adjday(t, '-', days, 0))
325 return !mk || domktime(t, type) != -1;
329 adjmin(struct tm *t, char type, int val, int mk)
337 if (!adjhour(t, '+', (t->tm_min + val) / 60, 0))
348 if (!adjhour(t, '-', val / 60, 0))
351 if (val > t->tm_min) {
352 if (!adjhour(t, '-', 1, 0))
366 return !mk || domktime(t, type) != -1;
370 adjsec(struct tm *t, char type, int val, int mk)
378 if (!adjmin(t, '+', (t->tm_sec + val) / 60, 0))
389 if (!adjmin(t, '-', val / 60, 0))
392 if (val > t->tm_sec) {
393 if (!adjmin(t, '-', 1, 0))
407 return !mk || domktime(t, type) != -1;
411 vary_apply(const struct vary *v, struct tm *t)
419 for (; v; v = v->next) {
422 if (type == '+' || type == '-')
433 if (strspn(arg, digits) != len-1) {
434 val = trans(trans_wday, arg);
436 if (!adjwday(t, type, val, 1, 1))
439 val = trans(trans_mon, arg);
441 if (!adjmon(t, type, val, 1, 1))
452 if (!adjsec(t, type, val, 1))
456 if (!adjmin(t, type, val, 1))
460 if (!adjhour(t, type, val, 1))
465 if (!adjday(t, type, val, 1))
470 if (!adjwday(t, type, val, 0, 1))
475 if (!adjmon(t, type, val, 0, 1))
480 if (!adjyear(t, type, val, 1))
492 vary_destroy(struct vary *v)