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.
13205821Sedwin *
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.
25205821Sedwin *
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);
50205821Sedwin
51205821Sedwin/*
52205821Sedwin * Expected styles:
53205821Sedwin *
54205821Sedwin * Date			::=	Month . ' ' . DayOfMonth |
55205821Sedwin *				Month . ' ' . DayOfWeek . ModifierIndex |
56205821Sedwin *				Month . '/' . DayOfMonth |
57205821Sedwin *				Month . '/' . DayOfWeek . ModifierIndex |
58205821Sedwin *				DayOfMonth . ' ' . Month |
59205821Sedwin *				DayOfMonth . '/' . Month |
60205821Sedwin *				DayOfWeek . ModifierIndex . ' ' .Month |
61205821Sedwin *				DayOfWeek . ModifierIndex . '/' .Month |
62205821Sedwin *				DayOfWeek . ModifierIndex |
63205821Sedwin *				SpecialDay . ModifierOffset
64205821Sedwin *
65205821Sedwin * Month		::=	MonthName | MonthNumber | '*'
66205821Sedwin * MonthNumber		::=	'0' ... '9' | '00' ... '09' | '10' ... '12'
67205821Sedwin * MonthName		::=	MonthNameShort | MonthNameLong
68205821Sedwin * MonthNameLong	::=	'January' ... 'December'
69205821Sedwin * MonthNameShort	::=	'Jan' ... 'Dec' | 'Jan.' ... 'Dec.'
70205821Sedwin *
71205821Sedwin * DayOfWeek		::=	DayOfWeekShort | DayOfWeekLong
72205821Sedwin * DayOfWeekShort	::=	'Mon' .. 'Sun'
73205821Sedwin * DayOfWeekLong	::=	'Monday' .. 'Sunday'
74205821Sedwin * DayOfMonth		::=	'0' ... '9' | '00' ... '09' | '10' ... '29' |
75205821Sedwin *				'30' ... '31' | '*'
76205821Sedwin *
77205821Sedwin * ModifierOffset	::=	'' | '+' . ModifierNumber | '-' . ModifierNumber
78205821Sedwin * ModifierNumber	::=	'0' ... '9' | '00' ... '99' | '000' ... '299' |
79205821Sedwin *				'300' ... '359' | '360' ... '365'
80205821Sedwin * ModifierIndex	::=	'Second' | 'Third' | 'Fourth' | 'Fifth' |
81205821Sedwin *				'First' | 'Last'
82205821Sedwin *
83216697Sosa * SpecialDay		::=	'Easter' | 'Paskha' | 'ChineseNewYear'
84205821Sedwin *
85205821Sedwin */
86205821Sedwinstatic int
87205821Sedwindeterminestyle(char *date, int *flags,
88205821Sedwin    char *month, int *imonth, char *dayofmonth, int *idayofmonth,
89205821Sedwin    char *dayofweek, int *idayofweek, char *modifieroffset,
90212035Sedwin    char *modifierindex, char *specialday, char *year, int *iyear)
91205821Sedwin{
92212035Sedwin	char *p, *p1, *p2, *py;
93205821Sedwin	const char *dow, *pmonth;
94205821Sedwin	char pold;
95205821Sedwin	size_t len, offset;
96205821Sedwin
97205821Sedwin	*flags = F_NONE;
98205821Sedwin	*month = '\0';
99205821Sedwin	*imonth = 0;
100212035Sedwin	*year = '\0';
101212035Sedwin	*iyear = 0;
102205821Sedwin	*dayofmonth = '\0';
103205821Sedwin	*idayofmonth = 0;
104205821Sedwin	*dayofweek = '\0';
105205821Sedwin	*idayofweek = 0;
106205821Sedwin	*modifieroffset = '\0';
107205821Sedwin	*modifierindex = '\0';
108205821Sedwin	*specialday = '\0';
109205821Sedwin
110205821Sedwin#define CHECKSPECIAL(s1, s2, lens2, type)				\
111205821Sedwin	if (s2 != NULL && strncmp(s1, s2, lens2) == 0) {		\
112205821Sedwin		*flags |= F_SPECIALDAY;					\
113205821Sedwin		*flags |= type;						\
114205821Sedwin		*flags |= F_VARIABLE;					\
115205821Sedwin		if (strlen(s1) == lens2) {				\
116205821Sedwin			strcpy(specialday, s1);				\
117205821Sedwin			return (1);					\
118205821Sedwin		}							\
119205821Sedwin		strncpy(specialday, s1, lens2);				\
120205821Sedwin		specialday[lens2] = '\0';				\
121205821Sedwin		strcpy(modifieroffset, s1 + lens2);			\
122205821Sedwin		*flags |= F_MODIFIEROFFSET;				\
123205821Sedwin		return (1);						\
124205821Sedwin	}
125205821Sedwin
126205821Sedwin	if ((p = strchr(date, ' ')) == NULL) {
127205821Sedwin		if ((p = strchr(date, '/')) == NULL) {
128205821Sedwin			CHECKSPECIAL(date, STRING_CNY, strlen(STRING_CNY),
129205821Sedwin			    F_CNY);
130205821Sedwin			CHECKSPECIAL(date, ncny.name, ncny.len, F_CNY);
131205821Sedwin			CHECKSPECIAL(date, STRING_NEWMOON,
132205821Sedwin			    strlen(STRING_NEWMOON), F_NEWMOON);
133205821Sedwin			CHECKSPECIAL(date, nnewmoon.name, nnewmoon.len,
134205821Sedwin			    F_NEWMOON);
135205821Sedwin			CHECKSPECIAL(date, STRING_FULLMOON,
136205821Sedwin			    strlen(STRING_FULLMOON), F_FULLMOON);
137205821Sedwin			CHECKSPECIAL(date, nfullmoon.name, nfullmoon.len,
138205821Sedwin			    F_FULLMOON);
139205821Sedwin			CHECKSPECIAL(date, STRING_PASKHA,
140205821Sedwin			    strlen(STRING_PASKHA), F_PASKHA);
141205821Sedwin			CHECKSPECIAL(date, npaskha.name, npaskha.len, F_PASKHA);
142205821Sedwin			CHECKSPECIAL(date, STRING_EASTER,
143205821Sedwin			    strlen(STRING_EASTER), F_EASTER);
144205821Sedwin			CHECKSPECIAL(date, neaster.name, neaster.len, F_EASTER);
145205821Sedwin			CHECKSPECIAL(date, STRING_MAREQUINOX,
146205821Sedwin			    strlen(STRING_MAREQUINOX), F_MAREQUINOX);
147205821Sedwin			CHECKSPECIAL(date, nmarequinox.name, nmarequinox.len,
148205821Sedwin			    F_SEPEQUINOX);
149205821Sedwin			CHECKSPECIAL(date, STRING_SEPEQUINOX,
150205821Sedwin			    strlen(STRING_SEPEQUINOX), F_SEPEQUINOX);
151205821Sedwin			CHECKSPECIAL(date, nsepequinox.name, nsepequinox.len,
152205821Sedwin			    F_SEPEQUINOX);
153205821Sedwin			CHECKSPECIAL(date, STRING_JUNSOLSTICE,
154205821Sedwin			    strlen(STRING_JUNSOLSTICE), F_JUNSOLSTICE);
155205821Sedwin			CHECKSPECIAL(date, njunsolstice.name, njunsolstice.len,
156205821Sedwin			    F_JUNSOLSTICE);
157205821Sedwin			CHECKSPECIAL(date, STRING_DECSOLSTICE,
158205821Sedwin			    strlen(STRING_DECSOLSTICE), F_DECSOLSTICE);
159205821Sedwin			CHECKSPECIAL(date, ndecsolstice.name, ndecsolstice.len,
160205821Sedwin			    F_DECSOLSTICE);
161205821Sedwin			if (checkdayofweek(date, &len, &offset, &dow) != 0) {
162205821Sedwin				*flags |= F_DAYOFWEEK;
163205821Sedwin				*flags |= F_VARIABLE;
164205821Sedwin				*idayofweek = offset;
165205821Sedwin				if (strlen(date) == len) {
166205821Sedwin					strcpy(dayofweek, date);
167205821Sedwin					return (1);
168205821Sedwin				}
169205821Sedwin				strncpy(dayofweek, date, len);
170205821Sedwin				dayofweek[len] = '\0';
171205821Sedwin				strcpy(modifierindex, date + len);
172205821Sedwin				*flags |= F_MODIFIERINDEX;
173205821Sedwin				return (1);
174205821Sedwin			}
175205821Sedwin			if (isonlydigits(date, 1)) {
176205821Sedwin				/* Assume month number only */
177205821Sedwin				*flags |= F_MONTH;
178205821Sedwin				*imonth = (int)strtol(date, (char **)NULL, 10);
179205821Sedwin				strcpy(month, getmonthname(*imonth));
180205821Sedwin				return(1);
181205821Sedwin			}
182205821Sedwin			return (0);
183205821Sedwin		}
184205821Sedwin	}
185205821Sedwin
186205821Sedwin	/*
187205821Sedwin	 * AFTER this, leave by goto-ing to "allfine" or "fail" to restore the
188205821Sedwin	 * original data in `date'.
189205821Sedwin	 */
190205821Sedwin	pold = *p;
191205821Sedwin	*p = 0;
192205821Sedwin	p1 = date;
193205821Sedwin	p2 = p + 1;
194205821Sedwin	/* Now p2 points to the next field and p1 to the first field */
195205821Sedwin
196212035Sedwin	if ((py = strchr(p2, '/')) != NULL) {
197212035Sedwin		/* We have a year in the string. Now this is getting tricky */
198212035Sedwin		strcpy(year, p1);
199212035Sedwin		*iyear = (int)strtol(year, NULL, 10);
200212035Sedwin		p1 = p2;
201212035Sedwin		p2 = py + 1;
202212035Sedwin		*py = 0;
203212035Sedwin		*flags |= F_YEAR;
204212035Sedwin	}
205212035Sedwin
206212035Sedwin	/*
207212035Sedwin	printf("p1: %s\n", p1);
208212035Sedwin	printf("p2: %s\n", p2);
209212035Sedwin	printf("year: %s\n", year);
210212035Sedwin	*/
211212035Sedwin
212205821Sedwin	/* Check if there is a month-string in the date */
213205821Sedwin	if ((checkmonth(p1, &len, &offset, &pmonth) != 0)
214205821Sedwin	 || (checkmonth(p2, &len, &offset, &pmonth) != 0 && (p2 = p1))) {
215205821Sedwin		/* p2 is the non-month part */
216205821Sedwin		*flags |= F_MONTH;
217205821Sedwin		*imonth = offset;
218205821Sedwin
219205821Sedwin		strcpy(month, getmonthname(offset));
220205821Sedwin		if (isonlydigits(p2, 1)) {
221205821Sedwin			strcpy(dayofmonth, p2);
222205821Sedwin			*idayofmonth = (int)strtol(p2, (char **)NULL, 10);
223205821Sedwin			*flags |= F_DAYOFMONTH;
224205821Sedwin			goto allfine;
225205821Sedwin		}
226205821Sedwin		if (strcmp(p2, "*") == 0) {
227205821Sedwin			*flags |= F_ALLDAY;
228205821Sedwin			goto allfine;
229205821Sedwin		}
230205821Sedwin
231205821Sedwin		if (checkdayofweek(p2, &len, &offset, &dow) != 0) {
232205821Sedwin			*flags |= F_DAYOFWEEK;
233205821Sedwin			*flags |= F_VARIABLE;
234205821Sedwin			*idayofweek = offset;
235205821Sedwin			strcpy(dayofweek, getdayofweekname(offset));
236205821Sedwin			if (strlen(p2) == len)
237205821Sedwin				goto allfine;
238205821Sedwin			strcpy(modifierindex, p2 + len);
239205821Sedwin			*flags |= F_MODIFIERINDEX;
240205821Sedwin			goto allfine;
241205821Sedwin		}
242205821Sedwin
243205821Sedwin		goto fail;
244205821Sedwin	}
245205821Sedwin
246205821Sedwin	/* Check if there is an every-day or every-month in the string */
247205821Sedwin	if ((strcmp(p1, "*") == 0 && isonlydigits(p2, 1))
248205821Sedwin	 || (strcmp(p2, "*") == 0 && isonlydigits(p1, 1) && (p2 = p1))) {
249205821Sedwin		int d;
250205821Sedwin
251205821Sedwin		*flags |= F_ALLMONTH;
252205821Sedwin		*flags |= F_DAYOFMONTH;
253205821Sedwin		d = (int)strtol(p2, (char **)NULL, 10);
254205821Sedwin		*idayofmonth = d;
255205821Sedwin		sprintf(dayofmonth, "%d", d);
256205821Sedwin		goto allfine;
257205821Sedwin	}
258205821Sedwin
259205821Sedwin	/* Month as a number, then a weekday */
260205821Sedwin	if (isonlydigits(p1, 1)
261205821Sedwin	 && checkdayofweek(p2, &len, &offset, &dow) != 0) {
262205821Sedwin		int d;
263205821Sedwin
264205821Sedwin		*flags |= F_MONTH;
265205821Sedwin		*flags |= F_DAYOFWEEK;
266205821Sedwin		*flags |= F_VARIABLE;
267205821Sedwin
268205821Sedwin		*idayofweek = offset;
269205821Sedwin		d = (int)strtol(p1, (char **)NULL, 10);
270205821Sedwin		*imonth = d;
271205821Sedwin		strcpy(month, getmonthname(d));
272205821Sedwin
273205821Sedwin		strcpy(dayofweek, getdayofweekname(offset));
274205821Sedwin		if (strlen(p2) == len)
275205821Sedwin			goto allfine;
276205821Sedwin		strcpy(modifierindex, p2 + len);
277205821Sedwin		*flags |= F_MODIFIERINDEX;
278205821Sedwin		goto allfine;
279205821Sedwin	}
280205821Sedwin
281205821Sedwin	/* If both the month and date are specified as numbers */
282205821Sedwin	if (isonlydigits(p1, 1) && isonlydigits(p2, 0)) {
283205821Sedwin		/* Now who wants to be this ambigious? :-( */
284205821Sedwin		int m, d;
285205821Sedwin
286205821Sedwin		if (strchr(p2, '*') != NULL)
287205821Sedwin			*flags |= F_VARIABLE;
288205821Sedwin
289205821Sedwin		m = (int)strtol(p1, (char **)NULL, 10);
290205821Sedwin		d = (int)strtol(p2, (char **)NULL, 10);
291205821Sedwin
292205821Sedwin		*flags |= F_MONTH;
293205821Sedwin		*flags |= F_DAYOFMONTH;
294205821Sedwin
295205821Sedwin		if (m > 12) {
296205821Sedwin			*imonth = d;
297205821Sedwin			*idayofmonth = m;
298205821Sedwin			strcpy(month, getmonthname(d));
299205821Sedwin			sprintf(dayofmonth, "%d", m);
300205821Sedwin		} else {
301205821Sedwin			*imonth = m;
302205821Sedwin			*idayofmonth = d;
303205821Sedwin			strcpy(month, getmonthname(m));
304205821Sedwin			sprintf(dayofmonth, "%d", d);
305205821Sedwin		}
306205821Sedwin		goto allfine;
307205821Sedwin	}
308205821Sedwin
309205821Sedwin	/* FALLTHROUGH */
310205821Sedwinfail:
311205821Sedwin	*p = pold;
312205821Sedwin	return (0);
313205821Sedwinallfine:
314205821Sedwin	*p = pold;
315205821Sedwin	return (1);
316205821Sedwin
317205821Sedwin}
318205821Sedwin
319205821Sedwinstatic void
320205821Sedwinremember(int *rememberindex, int *y, int *m, int *d, char **ed, int yy, int mm,
321205821Sedwin    int dd, char *extra)
322205821Sedwin{
323205821Sedwin	static int warned = 0;
324205821Sedwin
325205821Sedwin	if (*rememberindex >= MAXCOUNT - 1) {
326205821Sedwin		if (warned == 0)
327205821Sedwin			warnx("Index > %d, ignored", MAXCOUNT);
328205821Sedwin		warned++;
329205821Sedwin		return;
330205821Sedwin	}
331205821Sedwin	y[*rememberindex] = yy;
332205821Sedwin	m[*rememberindex] = mm;
333205821Sedwin	d[*rememberindex] = dd;
334205821Sedwin	if (extra != NULL)
335205821Sedwin		strcpy(ed[*rememberindex], extra);
336205821Sedwin	else
337205821Sedwin		ed[*rememberindex][0] = '\0';
338205821Sedwin	*rememberindex += 1;
339205821Sedwin}
340205821Sedwin
341205821Sedwinstatic void
342205821Sedwindebug_determinestyle(int dateonly, char *date, int flags, char *month,
343205821Sedwin    int imonth, char *dayofmonth, int idayofmonth, char *dayofweek,
344212035Sedwin    int idayofweek, char *modifieroffset, char *modifierindex, char *specialday,
345212035Sedwin    char *year, int iyear)
346205821Sedwin{
347205821Sedwin
348205821Sedwin	if (dateonly != 0) {
349205821Sedwin		printf("-------\ndate: |%s|\n", date);
350205821Sedwin		if (dateonly == 1)
351205821Sedwin			return;
352205821Sedwin	}
353205821Sedwin	printf("flags: %x - %s\n", flags, showflags(flags));
354205821Sedwin	if (modifieroffset[0] != '\0')
355205821Sedwin		printf("modifieroffset: |%s|\n", modifieroffset);
356205821Sedwin	if (modifierindex[0] != '\0')
357205821Sedwin		printf("modifierindex: |%s|\n", modifierindex);
358212035Sedwin	if (year[0] != '\0')
359212035Sedwin		printf("year: |%s| (%d)\n", year, iyear);
360205821Sedwin	if (month[0] != '\0')
361205821Sedwin		printf("month: |%s| (%d)\n", month, imonth);
362205821Sedwin	if (dayofmonth[0] != '\0')
363205821Sedwin		printf("dayofmonth: |%s| (%d)\n", dayofmonth, idayofmonth);
364205821Sedwin	if (dayofweek[0] != '\0')
365205821Sedwin		printf("dayofweek: |%s| (%d)\n", dayofweek, idayofweek);
366205821Sedwin	if (specialday[0] != '\0')
367205821Sedwin		printf("specialday: |%s|\n", specialday);
368205821Sedwin}
369205821Sedwin
370205821Sedwinstruct yearinfo {
371205821Sedwin	int year;
372205821Sedwin	int ieaster, ipaskha, firstcnyday;
373205821Sedwin	double ffullmoon[MAXMOONS], fnewmoon[MAXMOONS];
374205821Sedwin	double ffullmooncny[MAXMOONS], fnewmooncny[MAXMOONS];
375205821Sedwin	int ichinesemonths[MAXMOONS];
376205821Sedwin	double equinoxdays[2], solsticedays[2];
377205821Sedwin	int *mondays;
378205821Sedwin	struct yearinfo *next;
379205821Sedwin};
380205821Sedwin/*
381205821Sedwin * Possible date formats include any combination of:
382205821Sedwin *	3-charmonth			(January, Jan, Jan)
383205821Sedwin *	3-charweekday			(Friday, Monday, mon.)
384205821Sedwin *	numeric month or day		(1, 2, 04)
385205821Sedwin *
386205821Sedwin * Any character may separate them, or they may not be separated.  Any line,
387205821Sedwin * following a line that is matched, that starts with "whitespace", is shown
388205821Sedwin * along with the matched line.
389205821Sedwin */
390205821Sedwinint
391205821Sedwinparsedaymonth(char *date, int *yearp, int *monthp, int *dayp, int *flags,
392205821Sedwin    char **edp)
393205821Sedwin{
394205821Sedwin	char month[100], dayofmonth[100], dayofweek[100], modifieroffset[100];
395212035Sedwin	char syear[100];
396205821Sedwin	char modifierindex[100], specialday[100];
397212035Sedwin	int idayofweek = -1, imonth = -1, idayofmonth = -1, iyear = -1;
398212035Sedwin	int year, remindex;
399205821Sedwin	int d, m, dow, rm, rd, offset;
400205821Sedwin	char *ed;
401205821Sedwin	int retvalsign = 1;
402205821Sedwin
403205821Sedwin	static struct yearinfo *years, *yearinfo;
404205821Sedwin
405205821Sedwin	/*
406205821Sedwin	 * CONVENTION
407205821Sedwin	 *
408205821Sedwin	 * Month:     1-12
409205821Sedwin	 * Monthname: Jan .. Dec
410205821Sedwin	 * Day:       1-31
411205821Sedwin	 * Weekday:   Mon .. Sun
412205821Sedwin	 *
413205821Sedwin	 */
414205821Sedwin
415205821Sedwin	*flags = 0;
416205821Sedwin
417205821Sedwin	if (debug)
418205821Sedwin		debug_determinestyle(1, date, *flags, month, imonth,
419205821Sedwin		    dayofmonth, idayofmonth, dayofweek, idayofweek,
420212035Sedwin		    modifieroffset, modifierindex, specialday, syear, iyear);
421205821Sedwin	if (determinestyle(date, flags, month, &imonth, dayofmonth,
422205821Sedwin	    &idayofmonth, dayofweek, &idayofweek, modifieroffset,
423212035Sedwin	    modifierindex, specialday, syear, &iyear) == 0) {
424205821Sedwin		if (debug)
425205821Sedwin			printf("Failed!\n");
426205821Sedwin		return (0);
427205821Sedwin	}
428205821Sedwin
429205821Sedwin	if (debug)
430205821Sedwin		debug_determinestyle(0, date, *flags, month, imonth,
431205821Sedwin		    dayofmonth, idayofmonth, dayofweek, idayofweek,
432212035Sedwin		    modifieroffset, modifierindex, specialday, syear, iyear);
433205821Sedwin
434205821Sedwin	remindex = 0;
435205821Sedwin	for (year = year1; year <= year2; year++) {
436212035Sedwin
437212035Sedwin		int lflags = *flags;
438212035Sedwin		/* If the year is specified, only do it if it is this year! */
439212035Sedwin		if ((lflags & F_YEAR) != 0)
440212035Sedwin			if (iyear != year)
441212035Sedwin				continue;
442212035Sedwin		lflags &= ~F_YEAR;
443212035Sedwin
444205821Sedwin		/* Get important dates for this year */
445205821Sedwin		yearinfo = years;
446205821Sedwin		while (yearinfo != NULL) {
447205821Sedwin			if (yearinfo->year == year)
448205821Sedwin				break;
449205821Sedwin			yearinfo = yearinfo -> next;
450205821Sedwin		}
451205821Sedwin		if (yearinfo == NULL) {
452205821Sedwin			yearinfo = (struct yearinfo *)calloc(1,
453205821Sedwin			    sizeof(struct yearinfo));
454205821Sedwin			if (yearinfo == NULL)
455205821Sedwin				errx(1, "Unable to allocate more years");
456205821Sedwin			yearinfo->year = year;
457205821Sedwin			yearinfo->next = years;
458205821Sedwin			years = yearinfo;
459205821Sedwin
460205821Sedwin			yearinfo->mondays = mondaytab[isleap(year)];
461205821Sedwin			yearinfo->ieaster = easter(year);
462218471Sosa			yearinfo->ipaskha = paskha(year);
463205821Sedwin			fpom(year, UTCOffset, yearinfo->ffullmoon,
464205821Sedwin			    yearinfo->fnewmoon);
465205821Sedwin			fpom(year, UTCOFFSET_CNY, yearinfo->ffullmooncny,
466205821Sedwin			    yearinfo->fnewmooncny);
467205821Sedwin			fequinoxsolstice(year, UTCOffset,
468205821Sedwin			    yearinfo->equinoxdays, yearinfo->solsticedays);
469205821Sedwin
470205821Sedwin			/*
471205821Sedwin			 * CNY: Match day with sun longitude at 330` with new
472205821Sedwin			 * moon
473205821Sedwin			 */
474205821Sedwin			yearinfo->firstcnyday = calculatesunlongitude30(year,
475205821Sedwin			    UTCOFFSET_CNY, yearinfo->ichinesemonths);
476205821Sedwin			for (m = 0; yearinfo->fnewmooncny[m] >= 0; m++) {
477205821Sedwin				if (yearinfo->fnewmooncny[m] >
478205821Sedwin				    yearinfo->firstcnyday) {
479205821Sedwin					yearinfo->firstcnyday =
480205821Sedwin					    floor(yearinfo->fnewmooncny[m - 1]);
481205821Sedwin					break;
482205821Sedwin				}
483205821Sedwin			}
484205821Sedwin		}
485205821Sedwin
486205821Sedwin		/* Same day every year */
487212035Sedwin		if (lflags == (F_MONTH | F_DAYOFMONTH)) {
488205821Sedwin			if (!remember_ymd(year, imonth, idayofmonth))
489205821Sedwin				continue;
490205821Sedwin			remember(&remindex, yearp, monthp, dayp, edp,
491205821Sedwin			    year, imonth, idayofmonth, NULL);
492205821Sedwin			continue;
493205821Sedwin		}
494205821Sedwin
495205821Sedwin		/* XXX Same day every year, but variable */
496212035Sedwin		if (lflags == (F_MONTH | F_DAYOFMONTH | F_VARIABLE)) {
497205821Sedwin			if (!remember_ymd(year, imonth, idayofmonth))
498205821Sedwin				continue;
499205821Sedwin			remember(&remindex, yearp, monthp, dayp, edp,
500205821Sedwin			    year, imonth, idayofmonth, NULL);
501205821Sedwin			continue;
502205821Sedwin		}
503205821Sedwin
504205821Sedwin		/* Same day every month */
505212035Sedwin		if (lflags == (F_ALLMONTH | F_DAYOFMONTH)) {
506205821Sedwin			for (m = 1; m <= 12; m++) {
507205821Sedwin				if (!remember_ymd(year, m, idayofmonth))
508205821Sedwin					continue;
509205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
510205821Sedwin				    year, m, idayofmonth, NULL);
511205821Sedwin			}
512205821Sedwin			continue;
513205821Sedwin		}
514205821Sedwin
515205821Sedwin		/* Every day of a month */
516212035Sedwin		if (lflags == (F_ALLDAY | F_MONTH)) {
517205821Sedwin			for (d = 1; d <= yearinfo->mondays[imonth]; d++) {
518205821Sedwin				if (!remember_ymd(year, imonth, d))
519205821Sedwin					continue;
520205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
521205821Sedwin				    year, imonth, d, NULL);
522205821Sedwin			}
523205821Sedwin			continue;
524205821Sedwin		}
525205821Sedwin
526205821Sedwin		/* One day of every month */
527212035Sedwin		if (lflags == (F_ALLMONTH | F_DAYOFWEEK)) {
528205821Sedwin			for (m = 1; m <= 12; m++) {
529205821Sedwin				if (!remember_ymd(year, m, idayofmonth))
530205821Sedwin					continue;
531205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
532205821Sedwin				    year, m, idayofmonth, NULL);
533205821Sedwin			}
534205821Sedwin			continue;
535205821Sedwin		}
536205821Sedwin
537205821Sedwin		/* Every dayofweek of the year */
538212035Sedwin		if (lflags == (F_DAYOFWEEK | F_VARIABLE)) {
539205821Sedwin			dow = first_dayofweek_of_year(year);
540205821Sedwin			d = (idayofweek - dow + 8) % 7;
541205821Sedwin			while (d <= 366) {
542205821Sedwin				if (remember_yd(year, d, &rm, &rd))
543205821Sedwin					remember(&remindex,
544205821Sedwin					    yearp, monthp, dayp, edp,
545205821Sedwin					    year, rm, rd, NULL);
546205821Sedwin				d += 7;
547205821Sedwin			}
548205821Sedwin			continue;
549205821Sedwin		}
550205821Sedwin
551223928Sedwin		/* Every so-manied dayofweek of every month of the year */
552223928Sedwin		if (lflags == (F_DAYOFWEEK | F_MODIFIERINDEX | F_VARIABLE)) {
553223928Sedwin			offset = indextooffset(modifierindex);
554223928Sedwin
555223928Sedwin			for (m = 0; m < 12; m++) {
556223928Sedwin				dow = first_dayofweek_of_month(year, m);
557223928Sedwin				d = (idayofweek - dow + 8) % 7;
558223928Sedwin				d += (offset - 1) * 7;
559223928Sedwin				if (remember_ymd(year, m, d)) {
560223928Sedwin					remember(&remindex,
561223928Sedwin					    yearp, monthp, dayp, edp,
562223928Sedwin					    year, m, d, NULL);
563223928Sedwin					continue;
564223928Sedwin				}
565223928Sedwin			}
566223928Sedwin			continue;
567223928Sedwin		}
568223928Sedwin
569205821Sedwin		/* A certain dayofweek of a month */
570212035Sedwin		if (lflags ==
571205821Sedwin		    (F_MONTH | F_DAYOFWEEK | F_MODIFIERINDEX | F_VARIABLE)) {
572205821Sedwin			offset = indextooffset(modifierindex);
573205821Sedwin			dow = first_dayofweek_of_month(year, imonth);
574205821Sedwin			d = (idayofweek - dow + 8) % 7;
575205821Sedwin
576205821Sedwin			if (offset > 0) {
577205821Sedwin				while (d <= yearinfo->mondays[imonth]) {
578205821Sedwin					if (--offset == 0
579205821Sedwin					 && remember_ymd(year, imonth, d)) {
580205821Sedwin						remember(&remindex,
581205821Sedwin						    yearp, monthp, dayp, edp,
582205821Sedwin						    year, imonth, d, NULL);
583205821Sedwin						continue;
584205821Sedwin					}
585205821Sedwin					d += 7;
586205821Sedwin				}
587205821Sedwin				continue;
588205821Sedwin			}
589205821Sedwin			if (offset < 0) {
590205821Sedwin				while (d <= yearinfo->mondays[imonth])
591205821Sedwin					d += 7;
592205821Sedwin				while (offset != 0) {
593205821Sedwin					offset++;
594205821Sedwin					d -= 7;
595205821Sedwin				}
596205821Sedwin				if (remember_ymd(year, imonth, d))
597205821Sedwin					remember(&remindex,
598205821Sedwin					    yearp, monthp, dayp, edp,
599205821Sedwin					    year, imonth, d, NULL);
600205821Sedwin				continue;
601205821Sedwin			}
602205821Sedwin			continue;
603205821Sedwin		}
604205821Sedwin
605205821Sedwin		/* Every dayofweek of the month */
606212035Sedwin		if (lflags == (F_DAYOFWEEK | F_MONTH | F_VARIABLE)) {
607205821Sedwin			dow = first_dayofweek_of_month(year, imonth);
608205821Sedwin			d = (idayofweek - dow + 8) % 7;
609205821Sedwin			while (d <= yearinfo->mondays[imonth]) {
610205821Sedwin				if (remember_ymd(year, imonth, d))
611205821Sedwin					remember(&remindex,
612205821Sedwin					    yearp, monthp, dayp, edp,
613205821Sedwin					    year, imonth, d, NULL);
614205821Sedwin				d += 7;
615205821Sedwin			}
616205821Sedwin			continue;
617205821Sedwin		}
618205821Sedwin
619205821Sedwin		/* Easter */
620212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
621205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_EASTER)) {
622205821Sedwin			offset = 0;
623212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
624205821Sedwin				offset = parseoffset(modifieroffset);
625205821Sedwin			if (remember_yd(year, yearinfo->ieaster + offset,
626205821Sedwin			    &rm, &rd))
627205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
628205821Sedwin				    year, rm, rd, NULL);
629205821Sedwin			continue;
630205821Sedwin		}
631205821Sedwin
632205821Sedwin		/* Paskha */
633212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
634205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_PASKHA)) {
635205821Sedwin			offset = 0;
636212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
637205821Sedwin				offset = parseoffset(modifieroffset);
638205821Sedwin			if (remember_yd(year, yearinfo->ipaskha + offset,
639205821Sedwin			    &rm, &rd))
640205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
641205821Sedwin				    year, rm, rd, NULL);
642205821Sedwin			continue;
643205821Sedwin		}
644205821Sedwin
645205821Sedwin		/* Chinese New Year */
646212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
647205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_CNY)) {
648205821Sedwin			offset = 0;
649212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
650205821Sedwin				offset = parseoffset(modifieroffset);
651205821Sedwin			if (remember_yd(year, yearinfo->firstcnyday + offset,
652205821Sedwin			    &rm, &rd))
653205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
654205821Sedwin				    year, rm, rd, NULL);
655205821Sedwin			continue;
656205821Sedwin		}
657205821Sedwin
658205821Sedwin		/* FullMoon */
659212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
660205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_FULLMOON)) {
661205821Sedwin			int i;
662205821Sedwin
663205821Sedwin			offset = 0;
664212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
665205821Sedwin				offset = parseoffset(modifieroffset);
666205821Sedwin			for (i = 0; yearinfo->ffullmoon[i] > 0; i++) {
667205821Sedwin				if (remember_yd(year,
668205821Sedwin				    floor(yearinfo->ffullmoon[i]) + offset,
669205821Sedwin					&rm, &rd)) {
670205821Sedwin					ed = floattotime(
671205821Sedwin					    yearinfo->ffullmoon[i]);
672205821Sedwin					remember(&remindex,
673205821Sedwin					    yearp, monthp, dayp, edp,
674205821Sedwin					    year, rm, rd, ed);
675205821Sedwin				}
676205821Sedwin			}
677205821Sedwin			continue;
678205821Sedwin		}
679205821Sedwin
680205821Sedwin		/* NewMoon */
681212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
682205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_NEWMOON)) {
683205821Sedwin			int i;
684205821Sedwin
685205821Sedwin			offset = 0;
686212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
687205821Sedwin				offset = parseoffset(modifieroffset);
688205821Sedwin			for (i = 0; yearinfo->ffullmoon[i] > 0; i++) {
689205821Sedwin				if (remember_yd(year,
690205821Sedwin				    floor(yearinfo->fnewmoon[i]) + offset,
691205821Sedwin				    &rm, &rd)) {
692205821Sedwin					ed = floattotime(yearinfo->fnewmoon[i]);
693205821Sedwin					remember(&remindex,
694205821Sedwin					    yearp, monthp, dayp, edp,
695205821Sedwin					    year, rm, rd, ed);
696205821Sedwin				}
697205821Sedwin			}
698205821Sedwin			continue;
699205821Sedwin		}
700205821Sedwin
701205821Sedwin		/* (Mar|Sep)Equinox */
702212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
703205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_MAREQUINOX)) {
704205821Sedwin			offset = 0;
705212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
706205821Sedwin				offset = parseoffset(modifieroffset);
707205821Sedwin			if (remember_yd(year, yearinfo->equinoxdays[0] + offset,
708205821Sedwin			    &rm, &rd)) {
709205821Sedwin				ed = floattotime(yearinfo->equinoxdays[0]);
710205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
711205821Sedwin				    year, rm, rd, ed);
712205821Sedwin			}
713205821Sedwin			continue;
714205821Sedwin		}
715212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
716205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_SEPEQUINOX)) {
717205821Sedwin			offset = 0;
718212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
719205821Sedwin				offset = parseoffset(modifieroffset);
720205821Sedwin			if (remember_yd(year, yearinfo->equinoxdays[1] + offset,
721205821Sedwin			    &rm, &rd)) {
722205821Sedwin				ed = floattotime(yearinfo->equinoxdays[1]);
723205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
724205821Sedwin				    year, rm, rd, ed);
725205821Sedwin			}
726205821Sedwin			continue;
727205821Sedwin		}
728205821Sedwin
729205821Sedwin		/* (Jun|Dec)Solstice */
730212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
731205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_JUNSOLSTICE)) {
732205821Sedwin			offset = 0;
733212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
734205821Sedwin				offset = parseoffset(modifieroffset);
735205821Sedwin			if (remember_yd(year,
736205821Sedwin			    yearinfo->solsticedays[0] + offset, &rm, &rd)) {
737205821Sedwin				ed = floattotime(yearinfo->solsticedays[0]);
738205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
739205821Sedwin				    year, rm, rd, ed);
740205821Sedwin			}
741205821Sedwin			continue;
742205821Sedwin		}
743212035Sedwin		if ((lflags & ~F_MODIFIEROFFSET) ==
744205821Sedwin		    (F_SPECIALDAY | F_VARIABLE | F_DECSOLSTICE)) {
745205821Sedwin			offset = 0;
746212035Sedwin			if ((lflags & F_MODIFIEROFFSET) != 0)
747205821Sedwin				offset = parseoffset(modifieroffset);
748205821Sedwin			if (remember_yd(year,
749205821Sedwin			    yearinfo->solsticedays[1] + offset, &rm, &rd)) {
750205821Sedwin				ed = floattotime(yearinfo->solsticedays[1]);
751205821Sedwin				remember(&remindex, yearp, monthp, dayp, edp,
752205821Sedwin				    year, rm, rd, ed);
753205821Sedwin			}
754205821Sedwin			continue;
755205821Sedwin		}
756205821Sedwin
757205821Sedwin		printf("Unprocessed:\n");
758212035Sedwin		debug_determinestyle(2, date, lflags, month, imonth,
759205821Sedwin		    dayofmonth, idayofmonth, dayofweek, idayofweek,
760212035Sedwin		    modifieroffset, modifierindex, specialday, syear, iyear);
761205821Sedwin		retvalsign = -1;
762205821Sedwin	}
763205821Sedwin
764205821Sedwin	if (retvalsign == -1)
765205821Sedwin		return (-remindex - 1);
766205821Sedwin	else
767205821Sedwin		return (remindex);
768205821Sedwin}
769205821Sedwin
770205821Sedwinstatic char *
771205821Sedwinshowflags(int flags)
772205821Sedwin{
773205821Sedwin	static char s[1000];
774205821Sedwin	s[0] = '\0';
775205821Sedwin
776212035Sedwin	if ((flags & F_YEAR) != 0)
777212035Sedwin		strcat(s, "year ");
778205821Sedwin	if ((flags & F_MONTH) != 0)
779205821Sedwin		strcat(s, "month ");
780205821Sedwin	if ((flags & F_DAYOFWEEK) != 0)
781205821Sedwin		strcat(s, "dayofweek ");
782205821Sedwin	if ((flags & F_DAYOFMONTH) != 0)
783205821Sedwin		strcat(s, "dayofmonth ");
784205821Sedwin	if ((flags & F_MODIFIERINDEX) != 0)
785205821Sedwin		strcat(s, "modifierindex ");
786205821Sedwin	if ((flags & F_MODIFIEROFFSET) != 0)
787205821Sedwin		strcat(s, "modifieroffset ");
788205821Sedwin	if ((flags & F_SPECIALDAY) != 0)
789205821Sedwin		strcat(s, "specialday ");
790205821Sedwin	if ((flags & F_ALLMONTH) != 0)
791205821Sedwin		strcat(s, "allmonth ");
792205821Sedwin	if ((flags & F_ALLDAY) != 0)
793205821Sedwin		strcat(s, "allday ");
794205821Sedwin	if ((flags & F_VARIABLE) != 0)
795205821Sedwin		strcat(s, "variable ");
796205821Sedwin	if ((flags & F_CNY) != 0)
797205821Sedwin		strcat(s, "chinesenewyear ");
798205821Sedwin	if ((flags & F_PASKHA) != 0)
799205821Sedwin		strcat(s, "paskha ");
800205821Sedwin	if ((flags & F_EASTER) != 0)
801205821Sedwin		strcat(s, "easter ");
802205821Sedwin	if ((flags & F_FULLMOON) != 0)
803205821Sedwin		strcat(s, "fullmoon ");
804205821Sedwin	if ((flags & F_NEWMOON) != 0)
805205821Sedwin		strcat(s, "newmoon ");
806205821Sedwin	if ((flags & F_MAREQUINOX) != 0)
807205821Sedwin		strcat(s, "marequinox ");
808205821Sedwin	if ((flags & F_SEPEQUINOX) != 0)
809205821Sedwin		strcat(s, "sepequinox ");
810205821Sedwin	if ((flags & F_JUNSOLSTICE) != 0)
811205821Sedwin		strcat(s, "junsolstice ");
812205821Sedwin	if ((flags & F_DECSOLSTICE) != 0)
813205821Sedwin		strcat(s, "decsolstice ");
814205821Sedwin
815205821Sedwin	return s;
816205821Sedwin}
817205821Sedwin
818205821Sedwinstatic const char *
819205821Sedwingetmonthname(int i)
820205821Sedwin{
821223939Sedwin	if (i <= 0 || i > 12)
822223939Sedwin		return ("");
823205821Sedwin	if (nmonths[i - 1].len != 0 && nmonths[i - 1].name != NULL)
824205821Sedwin		return (nmonths[i - 1].name);
825205821Sedwin	return (months[i - 1]);
826205821Sedwin}
827205821Sedwin
828205821Sedwinstatic int
829205834Sdescheckmonth(char *s, size_t *len, size_t *offset, const char **month)
830205821Sedwin{
831205821Sedwin	struct fixs *n;
832205821Sedwin	int i;
833205821Sedwin
834205821Sedwin	for (i = 0; fnmonths[i].name != NULL; i++) {
835205821Sedwin		n = fnmonths + i;
836205821Sedwin		if (strncasecmp(s, n->name, n->len) == 0) {
837205821Sedwin			*len = n->len;
838205821Sedwin			*month = n->name;
839205821Sedwin			*offset = i + 1;
840205821Sedwin			return (1);
841205821Sedwin		}
842205821Sedwin	}
843205821Sedwin	for (i = 0; nmonths[i].name != NULL; i++) {
844205821Sedwin		n = nmonths + i;
845205821Sedwin		if (strncasecmp(s, n->name, n->len) == 0) {
846205821Sedwin			*len = n->len;
847205821Sedwin			*month = n->name;
848205821Sedwin			*offset = i + 1;
849205821Sedwin			return (1);
850205821Sedwin		}
851205821Sedwin	}
852205821Sedwin	for (i = 0; fmonths[i] != NULL; i++) {
853205821Sedwin		*len = strlen(fmonths[i]);
854205821Sedwin		if (strncasecmp(s, fmonths[i], *len) == 0) {
855205821Sedwin			*month = fmonths[i];
856205821Sedwin			*offset = i + 1;
857205821Sedwin			return (1);
858205821Sedwin		}
859205821Sedwin	}
860205821Sedwin	for (i = 0; months[i] != NULL; i++) {
861205821Sedwin		if (strncasecmp(s, months[i], 3) == 0) {
862205821Sedwin			*len = 3;
863205821Sedwin			*month = months[i];
864205821Sedwin			*offset = i + 1;
865205821Sedwin			return (1);
866205821Sedwin		}
867205821Sedwin	}
868205821Sedwin	return (0);
869205821Sedwin}
870205821Sedwin
871205821Sedwinstatic const char *
872205821Sedwingetdayofweekname(int i)
873205821Sedwin{
874205821Sedwin	if (ndays[i].len != 0 && ndays[i].name != NULL)
875205821Sedwin		return (ndays[i].name);
876205821Sedwin	return (days[i]);
877205821Sedwin}
878205821Sedwin
879205821Sedwinstatic int
880205834Sdescheckdayofweek(char *s, size_t *len, size_t *offset, const char **dow)
881205821Sedwin{
882205821Sedwin	struct fixs *n;
883205821Sedwin	int i;
884205821Sedwin
885205821Sedwin	for (i = 0; fndays[i].name != NULL; i++) {
886205821Sedwin		n = fndays + i;
887205821Sedwin		if (strncasecmp(s, n->name, n->len) == 0) {
888205821Sedwin			*len = n->len;
889205821Sedwin			*dow = n->name;
890205821Sedwin			*offset = i;
891205821Sedwin			return (1);
892205821Sedwin		}
893205821Sedwin	}
894205821Sedwin	for (i = 0; ndays[i].name != NULL; i++) {
895205821Sedwin		n = ndays + i;
896205821Sedwin		if (strncasecmp(s, n->name, n->len) == 0) {
897205821Sedwin			*len = n->len;
898205821Sedwin			*dow = n->name;
899205821Sedwin			*offset = i;
900205821Sedwin			return (1);
901205821Sedwin		}
902205821Sedwin	}
903205821Sedwin	for (i = 0; fdays[i] != NULL; i++) {
904205821Sedwin		*len = strlen(fdays[i]);
905205821Sedwin		if (strncasecmp(s, fdays[i], *len) == 0) {
906205821Sedwin			*dow = fdays[i];
907205821Sedwin			*offset = i;
908205821Sedwin			return (1);
909205821Sedwin		}
910205821Sedwin	}
911205821Sedwin	for (i = 0; days[i] != NULL; i++) {
912205821Sedwin		if (strncasecmp(s, days[i], 3) == 0) {
913205821Sedwin			*len = 3;
914205821Sedwin			*dow = days[i];
915205821Sedwin			*offset = i;
916205821Sedwin			return (1);
917205821Sedwin		}
918205821Sedwin	}
919205821Sedwin	return (0);
920205821Sedwin}
921205821Sedwin
922205821Sedwinstatic int
923205821Sedwinisonlydigits(char *s, int nostar)
924205821Sedwin{
925205821Sedwin	int i;
926205821Sedwin	for (i = 0; s[i] != '\0'; i++) {
927205821Sedwin		if (nostar == 0 && s[i] == '*' && s[i + 1] == '\0')
928205821Sedwin			return 1;
929207703Sache		if (!isdigit((unsigned char)s[i]))
930205821Sedwin			return (0);
931205821Sedwin	}
932205821Sedwin	return (1);
933205821Sedwin}
934205821Sedwin
935205821Sedwinstatic int
936205821Sedwinindextooffset(char *s)
937205821Sedwin{
938205821Sedwin	int i;
939205821Sedwin	struct fixs *n;
940205821Sedwin
941223928Sedwin	if (s[0] == '+' || s[0] == '-') {
942223928Sedwin		char ss[9];
943223928Sedwin		for (i = -100; i < 100; i++) {
944223928Sedwin			sprintf(ss, "%s%d", (i > 0) ? "+" : "", i);
945223928Sedwin			if (strcmp(ss, s) == 0)
946223928Sedwin				return (i);
947223928Sedwin		}
948223928Sedwin		return (0);
949223928Sedwin	}
950223928Sedwin
951205821Sedwin	for (i = 0; i < 6; i++) {
952205821Sedwin		if (strcasecmp(s, sequences[i]) == 0) {
953205821Sedwin			if (i == 5)
954205821Sedwin				return (-1);
955205821Sedwin			return (i + 1);
956205821Sedwin		}
957205821Sedwin	}
958205821Sedwin	for (i = 0; i < 6; i++) {
959205821Sedwin		n = nsequences + i;
960205821Sedwin		if (n->len == 0)
961205821Sedwin			continue;
962205821Sedwin		if (strncasecmp(s, n->name, n->len) == 0) {
963205821Sedwin			if (i == 5)
964205821Sedwin				return (-1);
965205821Sedwin			return (i + 1);
966205821Sedwin		}
967205821Sedwin	}
968205821Sedwin	return (0);
969205821Sedwin}
970205821Sedwin
971205821Sedwinstatic int
972205821Sedwinparseoffset(char *s)
973205821Sedwin{
974205821Sedwin
975205821Sedwin	return strtol(s, NULL, 10);
976205821Sedwin}
977205821Sedwin
978205821Sedwinstatic char *
979205821Sedwinfloattotime(double f)
980205821Sedwin{
981205821Sedwin	static char buf[100];
982205821Sedwin	int hh, mm, ss, i;
983205821Sedwin
984205821Sedwin	f -= floor(f);
985205821Sedwin	i = f * SECSPERDAY;
986205821Sedwin
987205821Sedwin	hh = i / SECSPERHOUR;
988205821Sedwin	i %= SECSPERHOUR;
989205821Sedwin	mm = i / SECSPERMINUTE;
990205821Sedwin	i %= SECSPERMINUTE;
991205821Sedwin	ss = i;
992205821Sedwin
993205821Sedwin	sprintf(buf, "%02d:%02d:%02d", hh, mm, ss);
994205821Sedwin	return (buf);
995205821Sedwin}
996205821Sedwin
997205821Sedwinstatic char *
998205821Sedwinfloattoday(int year, double f)
999205821Sedwin{
1000205821Sedwin	static char buf[100];
1001205821Sedwin	int i, m, d, hh, mm, ss;
1002205821Sedwin	int *cumdays = cumdaytab[isleap(year)];
1003205821Sedwin
1004205821Sedwin	for (i = 0; 1 + cumdays[i] < f; i++)
1005212591Semaste		;
1006205821Sedwin	m = --i;
1007205821Sedwin	d = floor(f - 1 - cumdays[i]);
1008205821Sedwin	f -= floor(f);
1009205821Sedwin	i = f * SECSPERDAY;
1010205821Sedwin
1011205821Sedwin	hh = i / SECSPERHOUR;
1012205821Sedwin	i %= SECSPERHOUR;
1013205821Sedwin	mm = i / SECSPERMINUTE;
1014205821Sedwin	i %= SECSPERMINUTE;
1015205821Sedwin	ss = i;
1016205821Sedwin
1017205821Sedwin	sprintf(buf, "%02d-%02d %02d:%02d:%02d", m, d, hh, mm, ss);
1018205821Sedwin	return (buf);
1019205821Sedwin}
1020205821Sedwin
1021205821Sedwinvoid
1022205821Sedwindodebug(char *what)
1023205821Sedwin{
1024205821Sedwin	int year;
1025205821Sedwin
1026205821Sedwin	printf("UTCOffset: %g\n", UTCOffset);
1027205821Sedwin	printf("eastlongitude: %d\n", EastLongitude);
1028205821Sedwin
1029205821Sedwin	if (strcmp(what, "moon") == 0) {
1030205821Sedwin		double ffullmoon[MAXMOONS], fnewmoon[MAXMOONS];
1031205821Sedwin		int i;
1032205821Sedwin
1033205821Sedwin		for (year = year1; year <= year2; year++) {
1034205821Sedwin			fpom(year, UTCOffset, ffullmoon, fnewmoon);
1035205821Sedwin			printf("Full moon %d:\t", year);
1036205821Sedwin			for (i = 0; ffullmoon[i] >= 0; i++) {
1037205821Sedwin				printf("%g (%s) ", ffullmoon[i],
1038205821Sedwin				    floattoday(year, ffullmoon[i]));
1039205821Sedwin			}
1040205821Sedwin			printf("\nNew moon %d:\t", year);
1041205821Sedwin			for (i = 0; fnewmoon[i] >= 0; i++) {
1042205821Sedwin				printf("%g (%s) ", fnewmoon[i],
1043205821Sedwin				    floattoday(year, fnewmoon[i]));
1044205821Sedwin			}
1045205821Sedwin			printf("\n");
1046205821Sedwin
1047205821Sedwin		}
1048205821Sedwin
1049205821Sedwin		return;
1050205821Sedwin	}
1051205821Sedwin
1052205821Sedwin	if (strcmp(what, "sun") == 0) {
1053205821Sedwin		double equinoxdays[2], solsticedays[2];
1054205821Sedwin		for (year = year1; year <= year2; year++) {
1055205821Sedwin			printf("Sun in %d:\n", year);
1056205821Sedwin			fequinoxsolstice(year, UTCOffset, equinoxdays,
1057205821Sedwin			    solsticedays);
1058205821Sedwin			printf("e[0] - %g (%s)\n",
1059205821Sedwin			    equinoxdays[0],
1060205821Sedwin			    floattoday(year, equinoxdays[0]));
1061205821Sedwin			printf("e[1] - %g (%s)\n",
1062205821Sedwin			    equinoxdays[1],
1063205821Sedwin			    floattoday(year, equinoxdays[1]));
1064205821Sedwin			printf("s[0] - %g (%s)\n",
1065205821Sedwin			    solsticedays[0],
1066205821Sedwin			    floattoday(year, solsticedays[0]));
1067205821Sedwin			printf("s[1] - %g (%s)\n",
1068205821Sedwin			    solsticedays[1],
1069205821Sedwin			    floattoday(year, solsticedays[1]));
1070205821Sedwin		}
1071205821Sedwin		return;
1072205821Sedwin	}
1073205821Sedwin}
1074