1205821Sedwin/*-
2205872Sedwin * Copyright (c) 1992-2009 Edwin Groothuis <edwin@FreeBSD.org>.
3205872Sedwin * All rights reserved.
4205821Sedwin *
5205821Sedwin * Redistribution and use in source and binary forms, with or without
6205821Sedwin * modification, are permitted provided that the following conditions
7205821Sedwin * are met:
8205821Sedwin * 1. Redistributions of source code must retain the above copyright
9205821Sedwin *    notice, this list of conditions and the following disclaimer.
10205821Sedwin * 2. Redistributions in binary form must reproduce the above copyright
11205821Sedwin *    notice, this list of conditions and the following disclaimer in the
12205821Sedwin *    documentation and/or other materials provided with the distribution.
13227370Sgrog *
14205821Sedwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15205821Sedwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16205821Sedwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17205821Sedwin * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18205821Sedwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19205821Sedwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20205821Sedwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21205821Sedwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22205821Sedwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23205821Sedwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24205821Sedwin * SUCH DAMAGE.
25227370Sgrog *
26205821Sedwin */
27205821Sedwin
28205821Sedwin#include <sys/cdefs.h>
29205821Sedwin__FBSDID("$FreeBSD$");
30205821Sedwin
31205821Sedwin#include <ctype.h>
32205821Sedwin#include <math.h>
33205821Sedwin#include <stdio.h>
34205821Sedwin#include <stdlib.h>
35205821Sedwin#include <string.h>
36205821Sedwin#include <err.h>
37205821Sedwin
38205821Sedwin#include "calendar.h"
39205821Sedwin
40205821Sedwinstatic char *showflags(int flags);
41205821Sedwinstatic int isonlydigits(char *s, int nostar);
42205821Sedwinstatic const char *getmonthname(int i);
43205834Sdesstatic int checkmonth(char *s, size_t *len, size_t *offset, const char **month);
44205821Sedwinstatic const char *getdayofweekname(int i);
45205834Sdesstatic int checkdayofweek(char *s, size_t *len, size_t *offset, const char **dow);
46205821Sedwinstatic int indextooffset(char *s);
47205821Sedwinstatic int parseoffset(char *s);
48205821Sedwinstatic char *floattoday(int year, double f);
49205821Sedwinstatic char *floattotime(double f);
50251647Sgrogstatic int wdayom (int day, int offset, int month, int year);
51205821Sedwin
52205821Sedwin/*
53205821Sedwin * Expected styles:
54205821Sedwin *
55205821Sedwin * Date			::=	Month . ' ' . DayOfMonth |
56205821Sedwin *				Month . ' ' . DayOfWeek . ModifierIndex |
57205821Sedwin *				Month . '/' . DayOfMonth |
58205821Sedwin *				Month . '/' . DayOfWeek . ModifierIndex |
59205821Sedwin *				DayOfMonth . ' ' . Month |
60205821Sedwin *				DayOfMonth . '/' . Month |
61205821Sedwin *				DayOfWeek . ModifierIndex . ' ' .Month |
62205821Sedwin *				DayOfWeek . ModifierIndex . '/' .Month |
63205821Sedwin *				DayOfWeek . ModifierIndex |
64205821Sedwin *				SpecialDay . ModifierOffset
65205821Sedwin *
66205821Sedwin * Month		::=	MonthName | MonthNumber | '*'
67205821Sedwin * MonthNumber		::=	'0' ... '9' | '00' ... '09' | '10' ... '12'
68205821Sedwin * MonthName		::=	MonthNameShort | MonthNameLong
69205821Sedwin * MonthNameLong	::=	'January' ... 'December'
70205821Sedwin * MonthNameShort	::=	'Jan' ... 'Dec' | 'Jan.' ... 'Dec.'
71205821Sedwin *
72205821Sedwin * DayOfWeek		::=	DayOfWeekShort | DayOfWeekLong
73205821Sedwin * DayOfWeekShort	::=	'Mon' .. 'Sun'
74205821Sedwin * DayOfWeekLong	::=	'Monday' .. 'Sunday'
75205821Sedwin * DayOfMonth		::=	'0' ... '9' | '00' ... '09' | '10' ... '29' |
76205821Sedwin *				'30' ... '31' | '*'
77205821Sedwin *
78205821Sedwin * ModifierOffset	::=	'' | '+' . ModifierNumber | '-' . ModifierNumber
79205821Sedwin * ModifierNumber	::=	'0' ... '9' | '00' ... '99' | '000' ... '299' |
80205821Sedwin *				'300' ... '359' | '360' ... '365'
81205821Sedwin * ModifierIndex	::=	'Second' | 'Third' | 'Fourth' | 'Fifth' |
82205821Sedwin *				'First' | 'Last'
83227370Sgrog *
84216697Sosa * SpecialDay		::=	'Easter' | 'Paskha' | 'ChineseNewYear'
85205821Sedwin *
86205821Sedwin */
87205821Sedwinstatic int
88205821Sedwindeterminestyle(char *date, int *flags,
89205821Sedwin    char *month, int *imonth, char *dayofmonth, int *idayofmonth,
90205821Sedwin    char *dayofweek, int *idayofweek, char *modifieroffset,
91212035Sedwin    char *modifierindex, char *specialday, char *year, int *iyear)
92205821Sedwin{
93212035Sedwin	char *p, *p1, *p2, *py;
94205821Sedwin	const char *dow, *pmonth;
95205821Sedwin	char pold;
96205821Sedwin	size_t len, offset;
97205821Sedwin
98205821Sedwin	*flags = F_NONE;
99205821Sedwin	*month = '\0';
100205821Sedwin	*imonth = 0;
101212035Sedwin	*year = '\0';
102212035Sedwin	*iyear = 0;
103205821Sedwin	*dayofmonth = '\0';
104205821Sedwin	*idayofmonth = 0;
105205821Sedwin	*dayofweek = '\0';
106205821Sedwin	*idayofweek = 0;
107205821Sedwin	*modifieroffset = '\0';
108205821Sedwin	*modifierindex = '\0';
109205821Sedwin	*specialday = '\0';
110205821Sedwin
111205821Sedwin#define CHECKSPECIAL(s1, s2, lens2, type)				\
112205821Sedwin	if (s2 != NULL && strncmp(s1, s2, lens2) == 0) {		\
113205821Sedwin		*flags |= F_SPECIALDAY;					\
114205821Sedwin		*flags |= type;						\
115205821Sedwin		*flags |= F_VARIABLE;					\
116205821Sedwin		if (strlen(s1) == lens2) {				\
117205821Sedwin			strcpy(specialday, s1);				\
118205821Sedwin			return (1);					\
119205821Sedwin		}							\
120205821Sedwin		strncpy(specialday, s1, lens2);				\
121205821Sedwin		specialday[lens2] = '\0';				\
122205821Sedwin		strcpy(modifieroffset, s1 + lens2);			\
123205821Sedwin		*flags |= F_MODIFIEROFFSET;				\
124205821Sedwin		return (1);						\
125205821Sedwin	}
126205821Sedwin
127205821Sedwin	if ((p = strchr(date, ' ')) == NULL) {
128205821Sedwin		if ((p = strchr(date, '/')) == NULL) {
129205821Sedwin			CHECKSPECIAL(date, STRING_CNY, strlen(STRING_CNY),
130205821Sedwin			    F_CNY);
131205821Sedwin			CHECKSPECIAL(date, ncny.name, ncny.len, F_CNY);
132205821Sedwin			CHECKSPECIAL(date, STRING_NEWMOON,
133205821Sedwin			    strlen(STRING_NEWMOON), F_NEWMOON);
134205821Sedwin			CHECKSPECIAL(date, nnewmoon.name, nnewmoon.len,
135205821Sedwin			    F_NEWMOON);
136205821Sedwin			CHECKSPECIAL(date, STRING_FULLMOON,
137205821Sedwin			    strlen(STRING_FULLMOON), F_FULLMOON);
138205821Sedwin			CHECKSPECIAL(date, nfullmoon.name, nfullmoon.len,
139205821Sedwin			    F_FULLMOON);
140205821Sedwin			CHECKSPECIAL(date, STRING_PASKHA,
141205821Sedwin			    strlen(STRING_PASKHA), F_PASKHA);
142205821Sedwin			CHECKSPECIAL(date, npaskha.name, npaskha.len, F_PASKHA);
143205821Sedwin			CHECKSPECIAL(date, STRING_EASTER,
144205821Sedwin			    strlen(STRING_EASTER), F_EASTER);
145205821Sedwin			CHECKSPECIAL(date, neaster.name, neaster.len, F_EASTER);
146205821Sedwin			CHECKSPECIAL(date, STRING_MAREQUINOX,
147205821Sedwin			    strlen(STRING_MAREQUINOX), F_MAREQUINOX);
148205821Sedwin			CHECKSPECIAL(date, nmarequinox.name, nmarequinox.len,
149205821Sedwin			    F_SEPEQUINOX);
150205821Sedwin			CHECKSPECIAL(date, STRING_SEPEQUINOX,
151205821Sedwin			    strlen(STRING_SEPEQUINOX), F_SEPEQUINOX);
152205821Sedwin			CHECKSPECIAL(date, nsepequinox.name, nsepequinox.len,
153205821Sedwin			    F_SEPEQUINOX);
154205821Sedwin			CHECKSPECIAL(date, STRING_JUNSOLSTICE,
155205821Sedwin			    strlen(STRING_JUNSOLSTICE), F_JUNSOLSTICE);
156205821Sedwin			CHECKSPECIAL(date, njunsolstice.name, njunsolstice.len,
157205821Sedwin			    F_JUNSOLSTICE);
158205821Sedwin			CHECKSPECIAL(date, STRING_DECSOLSTICE,
159205821Sedwin			    strlen(STRING_DECSOLSTICE), F_DECSOLSTICE);
160205821Sedwin			CHECKSPECIAL(date, ndecsolstice.name, ndecsolstice.len,
161205821Sedwin			    F_DECSOLSTICE);
162205821Sedwin			if (checkdayofweek(date, &len, &offset, &dow) != 0) {
163205821Sedwin				*flags |= F_DAYOFWEEK;
164205821Sedwin				*flags |= F_VARIABLE;
165205821Sedwin				*idayofweek = offset;
166205821Sedwin				if (strlen(date) == len) {
167205821Sedwin					strcpy(dayofweek, date);
168205821Sedwin					return (1);
169205821Sedwin				}
170205821Sedwin				strncpy(dayofweek, date, len);
171205821Sedwin				dayofweek[len] = '\0';
172205821Sedwin				strcpy(modifierindex, date + len);
173205821Sedwin				*flags |= F_MODIFIERINDEX;
174205821Sedwin				return (1);
175205821Sedwin			}
176205821Sedwin			if (isonlydigits(date, 1)) {
177205821Sedwin				/* Assume month number only */
178205821Sedwin				*flags |= F_MONTH;
179205821Sedwin				*imonth = (int)strtol(date, (char **)NULL, 10);
180205821Sedwin				strcpy(month, getmonthname(*imonth));
181205821Sedwin				return(1);
182205821Sedwin			}
183205821Sedwin			return (0);
184205821Sedwin		}
185205821Sedwin	}
186205821Sedwin
187205821Sedwin	/*
188251647Sgrog	 * After this, leave by goto-ing to "allfine" or "fail" to restore the
189205821Sedwin	 * original data in `date'.
190205821Sedwin	 */
191205821Sedwin	pold = *p;
192205821Sedwin	*p = 0;
193205821Sedwin	p1 = date;
194205821Sedwin	p2 = p + 1;
195205821Sedwin	/* Now p2 points to the next field and p1 to the first field */
196205821Sedwin
197212035Sedwin	if ((py = strchr(p2, '/')) != NULL) {
198212035Sedwin		/* We have a year in the string. Now this is getting tricky */
199212035Sedwin		strcpy(year, p1);
200212035Sedwin		*iyear = (int)strtol(year, NULL, 10);
201212035Sedwin		p1 = p2;
202212035Sedwin		p2 = py + 1;
203212035Sedwin		*py = 0;
204212035Sedwin		*flags |= F_YEAR;
205212035Sedwin	}
206212035Sedwin
207205821Sedwin	/* Check if there is a month-string in the date */
208205821Sedwin	if ((checkmonth(p1, &len, &offset, &pmonth) != 0)
209251647Sgrog	    || (checkmonth(p2, &len, &offset, &pmonth) != 0 && (p2 = p1))) {
210205821Sedwin		/* p2 is the non-month part */
211205821Sedwin		*flags |= F_MONTH;
212205821Sedwin		*imonth = offset;
213205821Sedwin
214205821Sedwin		strcpy(month, getmonthname(offset));
215205821Sedwin		if (isonlydigits(p2, 1)) {
216205821Sedwin			strcpy(dayofmonth, p2);
217205821Sedwin			*idayofmonth = (int)strtol(p2, (char **)NULL, 10);
218205821Sedwin			*flags |= F_DAYOFMONTH;
219205821Sedwin			goto allfine;
220205821Sedwin		}
221205821Sedwin		if (strcmp(p2, "*") == 0) {
222205821Sedwin			*flags |= F_ALLDAY;
223205821Sedwin			goto allfine;
224205821Sedwin		}
225205821Sedwin
226205821Sedwin		if (checkdayofweek(p2, &len, &offset, &dow) != 0) {
227205821Sedwin			*flags |= F_DAYOFWEEK;
228205821Sedwin			*flags |= F_VARIABLE;
229205821Sedwin			*idayofweek = offset;
230205821Sedwin			strcpy(dayofweek, getdayofweekname(offset));
231205821Sedwin			if (strlen(p2) == len)
232205821Sedwin				goto allfine;
233205821Sedwin			strcpy(modifierindex, p2 + len);
234205821Sedwin			*flags |= F_MODIFIERINDEX;
235205821Sedwin			goto allfine;
236205821Sedwin		}
237205821Sedwin		goto fail;
238205821Sedwin	}
239205821Sedwin
240205821Sedwin	/* Check if there is an every-day or every-month in the string */
241205821Sedwin	if ((strcmp(p1, "*") == 0 && isonlydigits(p2, 1))
242251647Sgrog	    || (strcmp(p2, "*") == 0 && isonlydigits(p1, 1) && (p2 = p1))) {
243205821Sedwin		int d;
244205821Sedwin
245205821Sedwin		*flags |= F_ALLMONTH;
246205821Sedwin		*flags |= F_DAYOFMONTH;
247205821Sedwin		d = (int)strtol(p2, (char **)NULL, 10);
248205821Sedwin		*idayofmonth = d;
249205821Sedwin		sprintf(dayofmonth, "%d", d);
250205821Sedwin		goto allfine;
251205821Sedwin	}
252205821Sedwin
253205821Sedwin	/* Month as a number, then a weekday */
254205821Sedwin	if (isonlydigits(p1, 1)
255251647Sgrog	    && checkdayofweek(p2, &len, &offset, &dow) != 0) {
256205821Sedwin		int d;
257205821Sedwin
258205821Sedwin		*flags |= F_MONTH;
259205821Sedwin		*flags |= F_DAYOFWEEK;
260205821Sedwin		*flags |= F_VARIABLE;
261205821Sedwin
262205821Sedwin		*idayofweek = offset;
263205821Sedwin		d = (int)strtol(p1, (char **)NULL, 10);
264205821Sedwin		*imonth = d;
265205821Sedwin		strcpy(month, getmonthname(d));
266205821Sedwin
267205821Sedwin		strcpy(dayofweek, getdayofweekname(offset));
268205821Sedwin		if (strlen(p2) == len)
269205821Sedwin			goto allfine;
270205821Sedwin		strcpy(modifierindex, p2 + len);
271205821Sedwin		*flags |= F_MODIFIERINDEX;
272205821Sedwin		goto allfine;
273205821Sedwin	}
274205821Sedwin
275205821Sedwin	/* If both the month and date are specified as numbers */
276205821Sedwin	if (isonlydigits(p1, 1) && isonlydigits(p2, 0)) {
277205821Sedwin		/* Now who wants to be this ambigious? :-( */
278205821Sedwin		int m, d;
279205821Sedwin
280205821Sedwin		if (strchr(p2, '*') != NULL)
281205821Sedwin			*flags |= F_VARIABLE;
282205821Sedwin
283205821Sedwin		m = (int)strtol(p1, (char **)NULL, 10);
284205821Sedwin		d = (int)strtol(p2, (char **)NULL, 10);
285205821Sedwin
286205821Sedwin		*flags |= F_MONTH;
287205821Sedwin		*flags |= F_DAYOFMONTH;
288205821Sedwin
289205821Sedwin		if (m > 12) {
290205821Sedwin			*imonth = d;
291205821Sedwin			*idayofmonth = m;
292205821Sedwin			strcpy(month, getmonthname(d));
293205821Sedwin			sprintf(dayofmonth, "%d", m);
294205821Sedwin		} else {
295205821Sedwin			*imonth = m;
296205821Sedwin			*idayofmonth = d;
297205821Sedwin			strcpy(month, getmonthname(m));
298205821Sedwin			sprintf(dayofmonth, "%d", d);
299205821Sedwin		}
300205821Sedwin		goto allfine;
301205821Sedwin	}
302205821Sedwin
303205821Sedwin	/* FALLTHROUGH */
304205821Sedwinfail:
305205821Sedwin	*p = pold;
306205821Sedwin	return (0);
307205821Sedwinallfine:
308205821Sedwin	*p = pold;
309205821Sedwin	return (1);
310227370Sgrog
311205821Sedwin}
312205821Sedwin
313251647Sgrogvoid
314205821Sedwinremember(int *rememberindex, int *y, int *m, int *d, char **ed, int yy, int mm,
315251647Sgrog    int dd, char *extra);
316251647Sgrogvoid
317251647Sgrogremember(int *rememberindex, int *y, int *m, int *d, char **ed, int yy, int mm,
318205821Sedwin    int dd, char *extra)
319205821Sedwin{
320205821Sedwin	static int warned = 0;
321205821Sedwin
322205821Sedwin	if (*rememberindex >= MAXCOUNT - 1) {
323205821Sedwin		if (warned == 0)
324205821Sedwin			warnx("Index > %d, ignored", MAXCOUNT);
325205821Sedwin		warned++;
326205821Sedwin		return;
327205821Sedwin	}
328205821Sedwin	y[*rememberindex] = yy;
329205821Sedwin	m[*rememberindex] = mm;
330205821Sedwin	d[*rememberindex] = dd;
331205821Sedwin	if (extra != NULL)
332205821Sedwin		strcpy(ed[*rememberindex], extra);
333205821Sedwin	else
334205821Sedwin		ed[*rememberindex][0] = '\0';
335205821Sedwin	*rememberindex += 1;
336205821Sedwin}
337205821Sedwin
338205821Sedwinstatic void
339205821Sedwindebug_determinestyle(int dateonly, char *date, int flags, char *month,
340205821Sedwin    int imonth, char *dayofmonth, int idayofmonth, char *dayofweek,
341212035Sedwin    int idayofweek, char *modifieroffset, char *modifierindex, char *specialday,
342212035Sedwin    char *year, int iyear)
343205821Sedwin{
344205821Sedwin
345205821Sedwin	if (dateonly != 0) {
346205821Sedwin		printf("-------\ndate: |%s|\n", date);
347205821Sedwin		if (dateonly == 1)
348205821Sedwin			return;
349205821Sedwin	}
350205821Sedwin	printf("flags: %x - %s\n", flags, showflags(flags));
351205821Sedwin	if (modifieroffset[0] != '\0')
352205821Sedwin		printf("modifieroffset: |%s|\n", modifieroffset);
353205821Sedwin	if (modifierindex[0] != '\0')
354205821Sedwin		printf("modifierindex: |%s|\n", modifierindex);
355212035Sedwin	if (year[0] != '\0')
356212035Sedwin		printf("year: |%s| (%d)\n", year, iyear);
357205821Sedwin	if (month[0] != '\0')
358205821Sedwin		printf("month: |%s| (%d)\n", month, imonth);
359205821Sedwin	if (dayofmonth[0] != '\0')
360205821Sedwin		printf("dayofmonth: |%s| (%d)\n", dayofmonth, idayofmonth);
361205821Sedwin	if (dayofweek[0] != '\0')
362205821Sedwin		printf("dayofweek: |%s| (%d)\n", dayofweek, idayofweek);
363205821Sedwin	if (specialday[0] != '\0')
364205821Sedwin		printf("specialday: |%s|\n", specialday);
365205821Sedwin}
366205821Sedwin
367251647Sgrogstatic struct yearinfo {
368205821Sedwin	int year;
369205821Sedwin	int ieaster, ipaskha, firstcnyday;
370205821Sedwin	double ffullmoon[MAXMOONS], fnewmoon[MAXMOONS];
371205821Sedwin	double ffullmooncny[MAXMOONS], fnewmooncny[MAXMOONS];
372205821Sedwin	int ichinesemonths[MAXMOONS];
373205821Sedwin	double equinoxdays[2], solsticedays[2];
374251647Sgrog	int *monthdays;
375205821Sedwin	struct yearinfo *next;
376251647Sgrog} *years, *yearinfo;
377251647Sgrog
378205821Sedwin/*
379251647Sgrog * Calculate dates with offset from weekdays, like Thurs-3, Wed+2, etc.
380251647Sgrog * day is the day of the week,
381251647Sgrog * offset the ordinal number of the weekday in the month.
382251647Sgrog */
383251647Sgrogstatic int
384251647Sgrogwdayom (int day, int offset, int month, int year)
385251647Sgrog{
386251647Sgrog/* Weekday of first day in month */
387251647Sgrog	int wday1;                                /* first day of month */
388251647Sgrog/* Weekday of last day in month */
389251647Sgrog	int wdayn;
390251647Sgrog	int d;
391251647Sgrog
392251647Sgrog	wday1 = first_dayofweek_of_month(year, month);
393251647Sgrog	if (wday1 < 0)                          /* not set */
394251647Sgrog		return (wday1);
395251647Sgrog	/*
396251647Sgrog	 * Date of zeroth or first of our weekday in month, depending on the
397251647Sgrog	 * relationship with the first of the month.  The range is -6:6.
398251647Sgrog	 */
399251647Sgrog	d = (day - wday1 + 1) % 7;
400251647Sgrog	/*
401251647Sgrog	 * Which way are we counting?  Offset 0 is invalid, abs (offset) > 5 is
402251647Sgrog	 * meaningless, but that's OK.  Offset 5 may or may not be meaningless,
403251647Sgrog	 * so there's no point in complaining for complaining's sake.
404251647Sgrog	 */
405251647Sgrog	if (offset < 0) {			/* back from end of month */
406251647Sgrog						/* FIXME */
407251647Sgrog		wdayn = d;
408251647Sgrog		while (wdayn <= yearinfo->monthdays[month])
409251647Sgrog			wdayn += 7;
410251647Sgrog		d = offset * 7 + wdayn;
411251647Sgrog	} else if (offset > 0){
412251647Sgrog		if (d > 0)
413251647Sgrog			d += offset * 7 - 7;
414251647Sgrog		else
415251647Sgrog			d += offset * 7;
416251647Sgrog	} else
417251647Sgrog		warnx ("Invalid offset 0");
418251647Sgrog	return (d);
419251647Sgrog}
420251647Sgrog
421251647Sgrog/*
422205821Sedwin * Possible date formats include any combination of:
423205821Sedwin *	3-charmonth			(January, Jan, Jan)
424205821Sedwin *	3-charweekday			(Friday, Monday, mon.)
425205821Sedwin *	numeric month or day		(1, 2, 04)
426205821Sedwin *
427205821Sedwin * Any character may separate them, or they may not be separated.  Any line,
428205821Sedwin * following a line that is matched, that starts with "whitespace", is shown
429205821Sedwin * along with the matched line.
430205821Sedwin */
431205821Sedwinint
432205821Sedwinparsedaymonth(char *date, int *yearp, int *monthp, int *dayp, int *flags,
433205821Sedwin    char **edp)
434205821Sedwin{
435205821Sedwin	char month[100], dayofmonth[100], dayofweek[100], modifieroffset[100];
436212035Sedwin	char syear[100];
437205821Sedwin	char modifierindex[100], specialday[100];
438212035Sedwin	int idayofweek = -1, imonth = -1, idayofmonth = -1, iyear = -1;
439212035Sedwin	int year, remindex;
440205821Sedwin	int d, m, dow, rm, rd, offset;
441205821Sedwin	char *ed;
442205821Sedwin	int retvalsign = 1;
443205821Sedwin
444205821Sedwin	/*
445205821Sedwin	 * CONVENTION
446205821Sedwin	 *
447205821Sedwin	 * Month:     1-12
448205821Sedwin	 * Monthname: Jan .. Dec
449227370Sgrog	 * Day:	      1-31
450205821Sedwin	 * Weekday:   Mon .. Sun
451205821Sedwin	 *
452205821Sedwin	 */
453205821Sedwin
454205821Sedwin	*flags = 0;
455205821Sedwin
456205821Sedwin	if (debug)
457205821Sedwin		debug_determinestyle(1, date, *flags, month, imonth,
458205821Sedwin		    dayofmonth, idayofmonth, dayofweek, idayofweek,
459212035Sedwin		    modifieroffset, modifierindex, specialday, syear, iyear);
460205821Sedwin	if (determinestyle(date, flags, month, &imonth, dayofmonth,
461251647Sgrog		&idayofmonth, dayofweek, &idayofweek, modifieroffset,
462251647Sgrog		modifierindex, specialday, syear, &iyear) == 0) {
463205821Sedwin		if (debug)
464205821Sedwin			printf("Failed!\n");
465205821Sedwin		return (0);
466205821Sedwin	}
467205821Sedwin
468205821Sedwin	if (debug)
469205821Sedwin		debug_determinestyle(0, date, *flags, month, imonth,
470205821Sedwin		    dayofmonth, idayofmonth, dayofweek, idayofweek,
471212035Sedwin		    modifieroffset, modifierindex, specialday, syear, iyear);
472205821Sedwin
473205821Sedwin	remindex = 0;
474205821Sedwin	for (year = year1; year <= year2; year++) {
475212035Sedwin
476212035Sedwin		int lflags = *flags;
477212035Sedwin		/* If the year is specified, only do it if it is this year! */
478212035Sedwin		if ((lflags & F_YEAR) != 0)
479212035Sedwin			if (iyear != year)
480212035Sedwin				continue;
481212035Sedwin		lflags &= ~F_YEAR;
482212035Sedwin
483205821Sedwin		/* Get important dates for this year */
484205821Sedwin		yearinfo = years;
485205821Sedwin		while (yearinfo != NULL) {
486205821Sedwin			if (yearinfo->year == year)
487205821Sedwin				break;
488205821Sedwin			yearinfo = yearinfo -> next;
489205821Sedwin		}
490205821Sedwin		if (yearinfo == NULL) {
491205821Sedwin			yearinfo = (struct yearinfo *)calloc(1,
492205821Sedwin			    sizeof(struct yearinfo));
493205821Sedwin			if (yearinfo == NULL)
494205821Sedwin				errx(1, "Unable to allocate more years");
495205821Sedwin			yearinfo->year = year;
496205821Sedwin			yearinfo->next = years;
497205821Sedwin			years = yearinfo;
498205821Sedwin
499251647Sgrog			yearinfo->monthdays = monthdaytab[isleap(year)];
500205821Sedwin			yearinfo->ieaster = easter(year);
501218471Sosa			yearinfo->ipaskha = paskha(year);
502205821Sedwin			fpom(year, UTCOffset, yearinfo->ffullmoon,
503205821Sedwin			    yearinfo->fnewmoon);
504205821Sedwin			fpom(year, UTCOFFSET_CNY, yearinfo->ffullmooncny,
505205821Sedwin			    yearinfo->fnewmooncny);
506205821Sedwin			fequinoxsolstice(year, UTCOffset,
507205821Sedwin			    yearinfo->equinoxdays, yearinfo->solsticedays);
508205821Sedwin
509205821Sedwin			/*
510205821Sedwin			 * CNY: Match day with sun longitude at 330` with new
511205821Sedwin			 * moon
512205821Sedwin			 */
513205821Sedwin			yearinfo->firstcnyday = calculatesunlongitude30(year,
514205821Sedwin			    UTCOFFSET_CNY, yearinfo->ichinesemonths);
515205821Sedwin			for (m = 0; yearinfo->fnewmooncny[m] >= 0; m++) {
516205821Sedwin				if (yearinfo->fnewmooncny[m] >
517205821Sedwin				    yearinfo->firstcnyday) {
518205821Sedwin					yearinfo->firstcnyday =
519205821Sedwin					    floor(yearinfo->fnewmooncny[m - 1]);
520205821Sedwin					break;
521205821Sedwin				}
522205821Sedwin			}
523205821Sedwin		}
524205821Sedwin
525205821Sedwin		/* Same day every year */
526212035Sedwin		if (lflags == (F_MONTH | F_DAYOFMONTH)) {
527205821Sedwin			if (!remember_ymd(year, imonth, idayofmonth))
528205821Sedwin				continue;
529205821Sedwin			remember(&remindex, yearp, monthp, dayp, edp,
530205821Sedwin			    year, imonth, idayofmonth, NULL);
531205821Sedwin			continue;
532205821Sedwin		}
533205821Sedwin
534205821Sedwin		/* XXX Same day every year, but variable */
535212035Sedwin		if (lflags == (F_MONTH | F_DAYOFMONTH | F_VARIABLE)) {
536205821Sedwin			if (!remember_ymd(year, imonth, idayofmonth))
537205821Sedwin				continue;
538205821Sedwin			remember(&remindex, yearp, monthp, dayp, edp,
539205821Sedwin			    year, imonth, idayofmonth, NULL);
540205821Sedwin			continue;
541205821Sedwin		}
542205821Sedwin
543205821Sedwin		/* Same day every month */
544212035Sedwin		if (lflags == (F_ALLMONTH | F_DAYOFMONTH)) {
545205821Sedwin			for (m = 1; m <= 12; m++) {
546205821Sedwin				if (!remember_ymd(year, m, idayofmonth))
547205821Sedwin					continue;
548205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
549205821Sedwin				    year, m, idayofmonth, NULL);
550205821Sedwin			}
551205821Sedwin			continue;
552205821Sedwin		}
553205821Sedwin
554205821Sedwin		/* Every day of a month */
555212035Sedwin		if (lflags == (F_ALLDAY | F_MONTH)) {
556251647Sgrog			for (d = 1; d <= yearinfo->monthdays[imonth]; d++) {
557205821Sedwin				if (!remember_ymd(year, imonth, d))
558205821Sedwin					continue;
559205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
560205821Sedwin				    year, imonth, d, NULL);
561205821Sedwin			}
562205821Sedwin			continue;
563205821Sedwin		}
564205821Sedwin
565205821Sedwin		/* One day of every month */
566212035Sedwin		if (lflags == (F_ALLMONTH | F_DAYOFWEEK)) {
567205821Sedwin			for (m = 1; m <= 12; m++) {
568205821Sedwin				if (!remember_ymd(year, m, idayofmonth))
569205821Sedwin					continue;
570205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
571205821Sedwin				    year, m, idayofmonth, NULL);
572205821Sedwin			}
573205821Sedwin			continue;
574205821Sedwin		}
575205821Sedwin
576205821Sedwin		/* Every dayofweek of the year */
577212035Sedwin		if (lflags == (F_DAYOFWEEK | F_VARIABLE)) {
578205821Sedwin			dow = first_dayofweek_of_year(year);
579205821Sedwin			d = (idayofweek - dow + 8) % 7;
580205821Sedwin			while (d <= 366) {
581205821Sedwin				if (remember_yd(year, d, &rm, &rd))
582205821Sedwin					remember(&remindex,
583205821Sedwin					    yearp, monthp, dayp, edp,
584205821Sedwin					    year, rm, rd, NULL);
585205821Sedwin				d += 7;
586205821Sedwin			}
587205821Sedwin			continue;
588205821Sedwin		}
589205821Sedwin
590251647Sgrog		/*
591251647Sgrog	         * Every so-manied dayofweek of every month of the year:
592251647Sgrog	         * Thu-3
593251647Sgrog	         */
594223928Sedwin		if (lflags == (F_DAYOFWEEK | F_MODIFIERINDEX | F_VARIABLE)) {
595223928Sedwin			offset = indextooffset(modifierindex);
596223928Sedwin
597251647Sgrog			for (m = 0; m <= 12; m++) {
598251647Sgrog	                        d = wdayom (idayofweek, offset, m, year);
599223928Sedwin				if (remember_ymd(year, m, d)) {
600223928Sedwin					remember(&remindex,
601223928Sedwin					    yearp, monthp, dayp, edp,
602223928Sedwin					    year, m, d, NULL);
603223928Sedwin					continue;
604223928Sedwin				}
605223928Sedwin			}
606223928Sedwin			continue;
607223928Sedwin		}
608223928Sedwin
609251647Sgrog		/*
610251647Sgrog	         * A certain dayofweek of a month
611251647Sgrog	         * Jan/Thu-3
612251647Sgrog	         */
613212035Sedwin		if (lflags ==
614205821Sedwin		    (F_MONTH | F_DAYOFWEEK | F_MODIFIERINDEX | F_VARIABLE)) {
615205821Sedwin			offset = indextooffset(modifierindex);
616205821Sedwin			dow = first_dayofweek_of_month(year, imonth);
617205821Sedwin			d = (idayofweek - dow + 8) % 7;
618205821Sedwin
619205821Sedwin			if (offset > 0) {
620251647Sgrog				while (d <= yearinfo->monthdays[imonth]) {
621205821Sedwin					if (--offset == 0
622251647Sgrog					    && remember_ymd(year, imonth, d)) {
623205821Sedwin						remember(&remindex,
624205821Sedwin						    yearp, monthp, dayp, edp,
625205821Sedwin						    year, imonth, d, NULL);
626205821Sedwin						continue;
627205821Sedwin					}
628205821Sedwin					d += 7;
629205821Sedwin				}
630205821Sedwin				continue;
631205821Sedwin			}
632205821Sedwin			if (offset < 0) {
633251647Sgrog				while (d <= yearinfo->monthdays[imonth])
634205821Sedwin					d += 7;
635205821Sedwin				while (offset != 0) {
636205821Sedwin					offset++;
637205821Sedwin					d -= 7;
638205821Sedwin				}
639205821Sedwin				if (remember_ymd(year, imonth, d))
640205821Sedwin					remember(&remindex,
641205821Sedwin					    yearp, monthp, dayp, edp,
642205821Sedwin					    year, imonth, d, NULL);
643205821Sedwin				continue;
644205821Sedwin			}
645205821Sedwin			continue;
646205821Sedwin		}
647205821Sedwin
648205821Sedwin		/* Every dayofweek of the month */
649212035Sedwin		if (lflags == (F_DAYOFWEEK | F_MONTH | F_VARIABLE)) {
650205821Sedwin			dow = first_dayofweek_of_month(year, imonth);
651205821Sedwin			d = (idayofweek - dow + 8) % 7;
652251647Sgrog			while (d <= yearinfo->monthdays[imonth]) {
653205821Sedwin				if (remember_ymd(year, imonth, d))
654205821Sedwin					remember(&remindex,
655205821Sedwin					    yearp, monthp, dayp, edp,
656205821Sedwin					    year, imonth, d, NULL);
657205821Sedwin				d += 7;
658205821Sedwin			}
659205821Sedwin			continue;
660205821Sedwin		}
661205821Sedwin
662205821Sedwin		/* Easter */
663212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
664205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_EASTER)) {
665205821Sedwin			offset = 0;
666212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
667205821Sedwin				offset = parseoffset(modifieroffset);
668205821Sedwin			if (remember_yd(year, yearinfo->ieaster + offset,
669251647Sgrog	                        &rm, &rd))
670205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
671205821Sedwin				    year, rm, rd, NULL);
672205821Sedwin			continue;
673205821Sedwin		}
674205821Sedwin
675205821Sedwin		/* Paskha */
676212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
677205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_PASKHA)) {
678205821Sedwin			offset = 0;
679212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
680205821Sedwin				offset = parseoffset(modifieroffset);
681205821Sedwin			if (remember_yd(year, yearinfo->ipaskha + offset,
682251647Sgrog	                        &rm, &rd))
683205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
684205821Sedwin				    year, rm, rd, NULL);
685205821Sedwin			continue;
686205821Sedwin		}
687205821Sedwin
688205821Sedwin		/* Chinese New Year */
689212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
690205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_CNY)) {
691205821Sedwin			offset = 0;
692212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
693205821Sedwin				offset = parseoffset(modifieroffset);
694205821Sedwin			if (remember_yd(year, yearinfo->firstcnyday + offset,
695251647Sgrog	                        &rm, &rd))
696205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
697205821Sedwin				    year, rm, rd, NULL);
698205821Sedwin			continue;
699205821Sedwin		}
700205821Sedwin
701205821Sedwin		/* FullMoon */
702212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
703205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_FULLMOON)) {
704205821Sedwin			int i;
705205821Sedwin
706205821Sedwin			offset = 0;
707212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
708205821Sedwin				offset = parseoffset(modifieroffset);
709205821Sedwin			for (i = 0; yearinfo->ffullmoon[i] > 0; i++) {
710205821Sedwin				if (remember_yd(year,
711251647Sgrog	                                floor(yearinfo->ffullmoon[i]) + offset,
712205821Sedwin					&rm, &rd)) {
713205821Sedwin					ed = floattotime(
714205821Sedwin					    yearinfo->ffullmoon[i]);
715205821Sedwin					remember(&remindex,
716205821Sedwin					    yearp, monthp, dayp, edp,
717205821Sedwin					    year, rm, rd, ed);
718205821Sedwin				}
719205821Sedwin			}
720205821Sedwin			continue;
721205821Sedwin		}
722205821Sedwin
723205821Sedwin		/* NewMoon */
724212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
725205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_NEWMOON)) {
726205821Sedwin			int i;
727205821Sedwin
728205821Sedwin			offset = 0;
729212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
730205821Sedwin				offset = parseoffset(modifieroffset);
731205821Sedwin			for (i = 0; yearinfo->ffullmoon[i] > 0; i++) {
732205821Sedwin				if (remember_yd(year,
733251647Sgrog					floor(yearinfo->fnewmoon[i]) + offset,
734251647Sgrog					&rm, &rd)) {
735205821Sedwin					ed = floattotime(yearinfo->fnewmoon[i]);
736205821Sedwin					remember(&remindex,
737205821Sedwin					    yearp, monthp, dayp, edp,
738205821Sedwin					    year, rm, rd, ed);
739205821Sedwin				}
740205821Sedwin			}
741205821Sedwin			continue;
742205821Sedwin		}
743205821Sedwin
744205821Sedwin		/* (Mar|Sep)Equinox */
745212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
746205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_MAREQUINOX)) {
747205821Sedwin			offset = 0;
748212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
749205821Sedwin				offset = parseoffset(modifieroffset);
750205821Sedwin			if (remember_yd(year, yearinfo->equinoxdays[0] + offset,
751251647Sgrog				&rm, &rd)) {
752205821Sedwin				ed = floattotime(yearinfo->equinoxdays[0]);
753205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
754205821Sedwin				    year, rm, rd, ed);
755205821Sedwin			}
756205821Sedwin			continue;
757205821Sedwin		}
758212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
759205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_SEPEQUINOX)) {
760205821Sedwin			offset = 0;
761212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
762205821Sedwin				offset = parseoffset(modifieroffset);
763205821Sedwin			if (remember_yd(year, yearinfo->equinoxdays[1] + offset,
764205821Sedwin			    &rm, &rd)) {
765205821Sedwin				ed = floattotime(yearinfo->equinoxdays[1]);
766205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
767205821Sedwin				    year, rm, rd, ed);
768205821Sedwin			}
769205821Sedwin			continue;
770205821Sedwin		}
771205821Sedwin
772205821Sedwin		/* (Jun|Dec)Solstice */
773212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
774205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_JUNSOLSTICE)) {
775205821Sedwin			offset = 0;
776212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
777205821Sedwin				offset = parseoffset(modifieroffset);
778205821Sedwin			if (remember_yd(year,
779251647Sgrog				yearinfo->solsticedays[0] + offset, &rm, &rd)) {
780205821Sedwin				ed = floattotime(yearinfo->solsticedays[0]);
781205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
782205821Sedwin				    year, rm, rd, ed);
783205821Sedwin			}
784205821Sedwin			continue;
785205821Sedwin		}
786212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
787205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_DECSOLSTICE)) {
788205821Sedwin			offset = 0;
789212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
790205821Sedwin				offset = parseoffset(modifieroffset);
791205821Sedwin			if (remember_yd(year,
792251647Sgrog				yearinfo->solsticedays[1] + offset, &rm, &rd)) {
793205821Sedwin				ed = floattotime(yearinfo->solsticedays[1]);
794205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
795205821Sedwin				    year, rm, rd, ed);
796205821Sedwin			}
797205821Sedwin			continue;
798205821Sedwin		}
799205821Sedwin
800227370Sgrog		if (debug) {
801251647Sgrog			printf("Unprocessed:\n");
802251647Sgrog			debug_determinestyle(2, date, lflags, month, imonth,
803251647Sgrog			    dayofmonth, idayofmonth, dayofweek, idayofweek,
804251647Sgrog			    modifieroffset, modifierindex, specialday, syear,
805251647Sgrog			    iyear);
806227370Sgrog		}
807205821Sedwin		retvalsign = -1;
808205821Sedwin	}
809205821Sedwin
810205821Sedwin	if (retvalsign == -1)
811205821Sedwin		return (-remindex - 1);
812205821Sedwin	else
813205821Sedwin		return (remindex);
814205821Sedwin}
815205821Sedwin
816205821Sedwinstatic char *
817205821Sedwinshowflags(int flags)
818205821Sedwin{
819205821Sedwin	static char s[1000];
820205821Sedwin	s[0] = '\0';
821205821Sedwin
822212035Sedwin	if ((flags & F_YEAR) != 0)
823212035Sedwin		strcat(s, "year ");
824205821Sedwin	if ((flags & F_MONTH) != 0)
825205821Sedwin		strcat(s, "month ");
826205821Sedwin	if ((flags & F_DAYOFWEEK) != 0)
827205821Sedwin		strcat(s, "dayofweek ");
828205821Sedwin	if ((flags & F_DAYOFMONTH) != 0)
829205821Sedwin		strcat(s, "dayofmonth ");
830205821Sedwin	if ((flags & F_MODIFIERINDEX) != 0)
831205821Sedwin		strcat(s, "modifierindex ");
832205821Sedwin	if ((flags & F_MODIFIEROFFSET) != 0)
833205821Sedwin		strcat(s, "modifieroffset ");
834205821Sedwin	if ((flags & F_SPECIALDAY) != 0)
835205821Sedwin		strcat(s, "specialday ");
836205821Sedwin	if ((flags & F_ALLMONTH) != 0)
837205821Sedwin		strcat(s, "allmonth ");
838205821Sedwin	if ((flags & F_ALLDAY) != 0)
839205821Sedwin		strcat(s, "allday ");
840205821Sedwin	if ((flags & F_VARIABLE) != 0)
841205821Sedwin		strcat(s, "variable ");
842205821Sedwin	if ((flags & F_CNY) != 0)
843205821Sedwin		strcat(s, "chinesenewyear ");
844205821Sedwin	if ((flags & F_PASKHA) != 0)
845205821Sedwin		strcat(s, "paskha ");
846205821Sedwin	if ((flags & F_EASTER) != 0)
847205821Sedwin		strcat(s, "easter ");
848205821Sedwin	if ((flags & F_FULLMOON) != 0)
849205821Sedwin		strcat(s, "fullmoon ");
850205821Sedwin	if ((flags & F_NEWMOON) != 0)
851205821Sedwin		strcat(s, "newmoon ");
852205821Sedwin	if ((flags & F_MAREQUINOX) != 0)
853205821Sedwin		strcat(s, "marequinox ");
854205821Sedwin	if ((flags & F_SEPEQUINOX) != 0)
855205821Sedwin		strcat(s, "sepequinox ");
856205821Sedwin	if ((flags & F_JUNSOLSTICE) != 0)
857205821Sedwin		strcat(s, "junsolstice ");
858205821Sedwin	if ((flags & F_DECSOLSTICE) != 0)
859205821Sedwin		strcat(s, "decsolstice ");
860205821Sedwin
861205821Sedwin	return s;
862205821Sedwin}
863205821Sedwin
864205821Sedwinstatic const char *
865205821Sedwingetmonthname(int i)
866205821Sedwin{
867223939Sedwin	if (i <= 0 || i > 12)
868223939Sedwin		return ("");
869205821Sedwin	if (nmonths[i - 1].len != 0 && nmonths[i - 1].name != NULL)
870205821Sedwin		return (nmonths[i - 1].name);
871205821Sedwin	return (months[i - 1]);
872205821Sedwin}
873205821Sedwin
874205821Sedwinstatic int
875205834Sdescheckmonth(char *s, size_t *len, size_t *offset, const char **month)
876205821Sedwin{
877205821Sedwin	struct fixs *n;
878205821Sedwin	int i;
879205821Sedwin
880205821Sedwin	for (i = 0; fnmonths[i].name != NULL; i++) {
881205821Sedwin		n = fnmonths + i;
882205821Sedwin		if (strncasecmp(s, n->name, n->len) == 0) {
883205821Sedwin			*len = n->len;
884205821Sedwin			*month = n->name;
885205821Sedwin			*offset = i + 1;
886205821Sedwin			return (1);
887205821Sedwin		}
888205821Sedwin	}
889205821Sedwin	for (i = 0; nmonths[i].name != NULL; i++) {
890205821Sedwin		n = nmonths + i;
891205821Sedwin		if (strncasecmp(s, n->name, n->len) == 0) {
892205821Sedwin			*len = n->len;
893205821Sedwin			*month = n->name;
894205821Sedwin			*offset = i + 1;
895205821Sedwin			return (1);
896205821Sedwin		}
897205821Sedwin	}
898205821Sedwin	for (i = 0; fmonths[i] != NULL; i++) {
899205821Sedwin		*len = strlen(fmonths[i]);
900205821Sedwin		if (strncasecmp(s, fmonths[i], *len) == 0) {
901205821Sedwin			*month = fmonths[i];
902205821Sedwin			*offset = i + 1;
903205821Sedwin			return (1);
904205821Sedwin		}
905205821Sedwin	}
906205821Sedwin	for (i = 0; months[i] != NULL; i++) {
907205821Sedwin		if (strncasecmp(s, months[i], 3) == 0) {
908205821Sedwin			*len = 3;
909205821Sedwin			*month = months[i];
910205821Sedwin			*offset = i + 1;
911205821Sedwin			return (1);
912205821Sedwin		}
913205821Sedwin	}
914205821Sedwin	return (0);
915205821Sedwin}
916205821Sedwin
917205821Sedwinstatic const char *
918205821Sedwingetdayofweekname(int i)
919205821Sedwin{
920205821Sedwin	if (ndays[i].len != 0 && ndays[i].name != NULL)
921205821Sedwin		return (ndays[i].name);
922205821Sedwin	return (days[i]);
923205821Sedwin}
924205821Sedwin
925205821Sedwinstatic int
926205834Sdescheckdayofweek(char *s, size_t *len, size_t *offset, const char **dow)
927205821Sedwin{
928205821Sedwin	struct fixs *n;
929205821Sedwin	int i;
930205821Sedwin
931205821Sedwin	for (i = 0; fndays[i].name != NULL; i++) {
932205821Sedwin		n = fndays + i;
933205821Sedwin		if (strncasecmp(s, n->name, n->len) == 0) {
934205821Sedwin			*len = n->len;
935205821Sedwin			*dow = n->name;
936205821Sedwin			*offset = i;
937205821Sedwin			return (1);
938205821Sedwin		}
939205821Sedwin	}
940205821Sedwin	for (i = 0; ndays[i].name != NULL; i++) {
941205821Sedwin		n = ndays + i;
942205821Sedwin		if (strncasecmp(s, n->name, n->len) == 0) {
943205821Sedwin			*len = n->len;
944205821Sedwin			*dow = n->name;
945205821Sedwin			*offset = i;
946205821Sedwin			return (1);
947205821Sedwin		}
948205821Sedwin	}
949205821Sedwin	for (i = 0; fdays[i] != NULL; i++) {
950205821Sedwin		*len = strlen(fdays[i]);
951205821Sedwin		if (strncasecmp(s, fdays[i], *len) == 0) {
952205821Sedwin			*dow = fdays[i];
953205821Sedwin			*offset = i;
954205821Sedwin			return (1);
955205821Sedwin		}
956205821Sedwin	}
957205821Sedwin	for (i = 0; days[i] != NULL; i++) {
958205821Sedwin		if (strncasecmp(s, days[i], 3) == 0) {
959205821Sedwin			*len = 3;
960205821Sedwin			*dow = days[i];
961205821Sedwin			*offset = i;
962205821Sedwin			return (1);
963205821Sedwin		}
964205821Sedwin	}
965205821Sedwin	return (0);
966205821Sedwin}
967205821Sedwin
968205821Sedwinstatic int
969205821Sedwinisonlydigits(char *s, int nostar)
970205821Sedwin{
971205821Sedwin	int i;
972205821Sedwin	for (i = 0; s[i] != '\0'; i++) {
973205821Sedwin		if (nostar == 0 && s[i] == '*' && s[i + 1] == '\0')
974205821Sedwin			return 1;
975207703Sache		if (!isdigit((unsigned char)s[i]))
976205821Sedwin			return (0);
977205821Sedwin	}
978205821Sedwin	return (1);
979205821Sedwin}
980205821Sedwin
981205821Sedwinstatic int
982205821Sedwinindextooffset(char *s)
983205821Sedwin{
984205821Sedwin	int i;
985205821Sedwin	struct fixs *n;
986244166Sgrog	char *es;
987205821Sedwin
988223928Sedwin	if (s[0] == '+' || s[0] == '-') {
989244168Sgrog		i = strtol (s, &es, 10);
990244166Sgrog		if (*es != '\0')                      /* trailing junk */
991244166Sgrog			errx (1, "Invalid specifier format: %s\n", s);
992244166Sgrog		return (i);
993223928Sedwin	}
994223928Sedwin
995205821Sedwin	for (i = 0; i < 6; i++) {
996205821Sedwin		if (strcasecmp(s, sequences[i]) == 0) {
997205821Sedwin			if (i == 5)
998205821Sedwin				return (-1);
999205821Sedwin			return (i + 1);
1000205821Sedwin		}
1001205821Sedwin	}
1002205821Sedwin	for (i = 0; i < 6; i++) {
1003205821Sedwin		n = nsequences + i;
1004205821Sedwin		if (n->len == 0)
1005205821Sedwin			continue;
1006205821Sedwin		if (strncasecmp(s, n->name, n->len) == 0) {
1007205821Sedwin			if (i == 5)
1008205821Sedwin				return (-1);
1009205821Sedwin			return (i + 1);
1010205821Sedwin		}
1011205821Sedwin	}
1012205821Sedwin	return (0);
1013205821Sedwin}
1014205821Sedwin
1015205821Sedwinstatic int
1016205821Sedwinparseoffset(char *s)
1017205821Sedwin{
1018205821Sedwin	return strtol(s, NULL, 10);
1019205821Sedwin}
1020205821Sedwin
1021205821Sedwinstatic char *
1022205821Sedwinfloattotime(double f)
1023205821Sedwin{
1024205821Sedwin	static char buf[100];
1025205821Sedwin	int hh, mm, ss, i;
1026205821Sedwin
1027205821Sedwin	f -= floor(f);
1028205821Sedwin	i = f * SECSPERDAY;
1029205821Sedwin
1030205821Sedwin	hh = i / SECSPERHOUR;
1031205821Sedwin	i %= SECSPERHOUR;
1032205821Sedwin	mm = i / SECSPERMINUTE;
1033205821Sedwin	i %= SECSPERMINUTE;
1034205821Sedwin	ss = i;
1035205821Sedwin
1036205821Sedwin	sprintf(buf, "%02d:%02d:%02d", hh, mm, ss);
1037205821Sedwin	return (buf);
1038205821Sedwin}
1039205821Sedwin
1040205821Sedwinstatic char *
1041205821Sedwinfloattoday(int year, double f)
1042205821Sedwin{
1043205821Sedwin	static char buf[100];
1044205821Sedwin	int i, m, d, hh, mm, ss;
1045205821Sedwin	int *cumdays = cumdaytab[isleap(year)];
1046205821Sedwin
1047205821Sedwin	for (i = 0; 1 + cumdays[i] < f; i++)
1048212591Semaste		;
1049205821Sedwin	m = --i;
1050205821Sedwin	d = floor(f - 1 - cumdays[i]);
1051205821Sedwin	f -= floor(f);
1052205821Sedwin	i = f * SECSPERDAY;
1053205821Sedwin
1054205821Sedwin	hh = i / SECSPERHOUR;
1055205821Sedwin	i %= SECSPERHOUR;
1056205821Sedwin	mm = i / SECSPERMINUTE;
1057205821Sedwin	i %= SECSPERMINUTE;
1058205821Sedwin	ss = i;
1059205821Sedwin
1060205821Sedwin	sprintf(buf, "%02d-%02d %02d:%02d:%02d", m, d, hh, mm, ss);
1061205821Sedwin	return (buf);
1062205821Sedwin}
1063205821Sedwin
1064205821Sedwinvoid
1065205821Sedwindodebug(char *what)
1066205821Sedwin{
1067205821Sedwin	int year;
1068205821Sedwin
1069205821Sedwin	printf("UTCOffset: %g\n", UTCOffset);
1070205821Sedwin	printf("eastlongitude: %d\n", EastLongitude);
1071205821Sedwin
1072205821Sedwin	if (strcmp(what, "moon") == 0) {
1073205821Sedwin		double ffullmoon[MAXMOONS], fnewmoon[MAXMOONS];
1074205821Sedwin		int i;
1075205821Sedwin
1076205821Sedwin		for (year = year1; year <= year2; year++) {
1077205821Sedwin			fpom(year, UTCOffset, ffullmoon, fnewmoon);
1078205821Sedwin			printf("Full moon %d:\t", year);
1079205821Sedwin			for (i = 0; ffullmoon[i] >= 0; i++) {
1080205821Sedwin				printf("%g (%s) ", ffullmoon[i],
1081205821Sedwin				    floattoday(year, ffullmoon[i]));
1082205821Sedwin			}
1083205821Sedwin			printf("\nNew moon %d:\t", year);
1084205821Sedwin			for (i = 0; fnewmoon[i] >= 0; i++) {
1085205821Sedwin				printf("%g (%s) ", fnewmoon[i],
1086205821Sedwin				    floattoday(year, fnewmoon[i]));
1087205821Sedwin			}
1088205821Sedwin			printf("\n");
1089205821Sedwin
1090205821Sedwin		}
1091227370Sgrog
1092205821Sedwin		return;
1093205821Sedwin	}
1094205821Sedwin
1095205821Sedwin	if (strcmp(what, "sun") == 0) {
1096205821Sedwin		double equinoxdays[2], solsticedays[2];
1097205821Sedwin		for (year = year1; year <= year2; year++) {
1098205821Sedwin			printf("Sun in %d:\n", year);
1099205821Sedwin			fequinoxsolstice(year, UTCOffset, equinoxdays,
1100205821Sedwin			    solsticedays);
1101205821Sedwin			printf("e[0] - %g (%s)\n",
1102205821Sedwin			    equinoxdays[0],
1103205821Sedwin			    floattoday(year, equinoxdays[0]));
1104205821Sedwin			printf("e[1] - %g (%s)\n",
1105205821Sedwin			    equinoxdays[1],
1106205821Sedwin			    floattoday(year, equinoxdays[1]));
1107205821Sedwin			printf("s[0] - %g (%s)\n",
1108205821Sedwin			    solsticedays[0],
1109205821Sedwin			    floattoday(year, solsticedays[0]));
1110205821Sedwin			printf("s[1] - %g (%s)\n",
1111205821Sedwin			    solsticedays[1],
1112205821Sedwin			    floattoday(year, solsticedays[1]));
1113205821Sedwin		}
1114205821Sedwin		return;
1115205821Sedwin	}
1116205821Sedwin}
1117