parsedata.c revision 256281
133965Sjdp/*-
260484Sobrien * Copyright (c) 1992-2009 Edwin Groothuis <edwin@FreeBSD.org>.
360484Sobrien * All rights reserved.
433965Sjdp *
533965Sjdp * Redistribution and use in source and binary forms, with or without
633965Sjdp * modification, are permitted provided that the following conditions
733965Sjdp * are met:
833965Sjdp * 1. Redistributions of source code must retain the above copyright
933965Sjdp *    notice, this list of conditions and the following disclaimer.
1033965Sjdp * 2. Redistributions in binary form must reproduce the above copyright
1133965Sjdp *    notice, this list of conditions and the following disclaimer in the
1233965Sjdp *    documentation and/or other materials provided with the distribution.
1333965Sjdp *
1433965Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1533965Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1633965Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1733965Sjdp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1833965Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1933965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2033965Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2133965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2233965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2333965Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2433965Sjdp * SUCH DAMAGE.
2533965Sjdp *
2633965Sjdp */
2733965Sjdp
2833965Sjdp#include <sys/cdefs.h>
2933965Sjdp__FBSDID("$FreeBSD: stable/10/usr.bin/calendar/parsedata.c 251647 2013-06-12 07:52:49Z grog $");
3033965Sjdp
3133965Sjdp#include <ctype.h>
3233965Sjdp#include <math.h>
3333965Sjdp#include <stdio.h>
3433965Sjdp#include <stdlib.h>
3561843Sobrien#include <string.h>
3633965Sjdp#include <err.h>
3733965Sjdp
3833965Sjdp#include "calendar.h"
3933965Sjdp
4033965Sjdpstatic char *showflags(int flags);
4133965Sjdpstatic int isonlydigits(char *s, int nostar);
4233965Sjdpstatic const char *getmonthname(int i);
4333965Sjdpstatic int checkmonth(char *s, size_t *len, size_t *offset, const char **month);
4460484Sobrienstatic const char *getdayofweekname(int i);
4560484Sobrienstatic int checkdayofweek(char *s, size_t *len, size_t *offset, const char **dow);
4660484Sobrienstatic int indextooffset(char *s);
4760484Sobrienstatic int parseoffset(char *s);
4860484Sobrienstatic char *floattoday(int year, double f);
4960484Sobrienstatic char *floattotime(double f);
5033965Sjdpstatic int wdayom (int day, int offset, int month, int year);
5133965Sjdp
5233965Sjdp/*
5333965Sjdp * Expected styles:
5433965Sjdp *
5538889Sjdp * Date			::=	Month . ' ' . DayOfMonth |
5633965Sjdp *				Month . ' ' . DayOfWeek . ModifierIndex |
5733965Sjdp *				Month . '/' . DayOfMonth |
5833965Sjdp *				Month . '/' . DayOfWeek . ModifierIndex |
5933965Sjdp *				DayOfMonth . ' ' . Month |
6033965Sjdp *				DayOfMonth . '/' . Month |
6133965Sjdp *				DayOfWeek . ModifierIndex . ' ' .Month |
6233965Sjdp *				DayOfWeek . ModifierIndex . '/' .Month |
6333965Sjdp *				DayOfWeek . ModifierIndex |
6433965Sjdp *				SpecialDay . ModifierOffset
6533965Sjdp *
6633965Sjdp * Month		::=	MonthName | MonthNumber | '*'
6733965Sjdp * MonthNumber		::=	'0' ... '9' | '00' ... '09' | '10' ... '12'
6833965Sjdp * MonthName		::=	MonthNameShort | MonthNameLong
6933965Sjdp * MonthNameLong	::=	'January' ... 'December'
7033965Sjdp * MonthNameShort	::=	'Jan' ... 'Dec' | 'Jan.' ... 'Dec.'
7133965Sjdp *
7233965Sjdp * DayOfWeek		::=	DayOfWeekShort | DayOfWeekLong
7333965Sjdp * DayOfWeekShort	::=	'Mon' .. 'Sun'
7433965Sjdp * DayOfWeekLong	::=	'Monday' .. 'Sunday'
7533965Sjdp * DayOfMonth		::=	'0' ... '9' | '00' ... '09' | '10' ... '29' |
7633965Sjdp *				'30' ... '31' | '*'
7733965Sjdp *
7833965Sjdp * ModifierOffset	::=	'' | '+' . ModifierNumber | '-' . ModifierNumber
7933965Sjdp * ModifierNumber	::=	'0' ... '9' | '00' ... '99' | '000' ... '299' |
8033965Sjdp *				'300' ... '359' | '360' ... '365'
8133965Sjdp * ModifierIndex	::=	'Second' | 'Third' | 'Fourth' | 'Fifth' |
8233965Sjdp *				'First' | 'Last'
8333965Sjdp *
8433965Sjdp * SpecialDay		::=	'Easter' | 'Paskha' | 'ChineseNewYear'
8533965Sjdp *
8633965Sjdp */
8733965Sjdpstatic int
8833965Sjdpdeterminestyle(char *date, int *flags,
8933965Sjdp    char *month, int *imonth, char *dayofmonth, int *idayofmonth,
9033965Sjdp    char *dayofweek, int *idayofweek, char *modifieroffset,
9133965Sjdp    char *modifierindex, char *specialday, char *year, int *iyear)
9233965Sjdp{
9333965Sjdp	char *p, *p1, *p2, *py;
9433965Sjdp	const char *dow, *pmonth;
9533965Sjdp	char pold;
9633965Sjdp	size_t len, offset;
9733965Sjdp
9833965Sjdp	*flags = F_NONE;
9933965Sjdp	*month = '\0';
10033965Sjdp	*imonth = 0;
10133965Sjdp	*year = '\0';
10233965Sjdp	*iyear = 0;
10333965Sjdp	*dayofmonth = '\0';
10433965Sjdp	*idayofmonth = 0;
10533965Sjdp	*dayofweek = '\0';
10633965Sjdp	*idayofweek = 0;
10733965Sjdp	*modifieroffset = '\0';
10833965Sjdp	*modifierindex = '\0';
10933965Sjdp	*specialday = '\0';
11033965Sjdp
11133965Sjdp#define CHECKSPECIAL(s1, s2, lens2, type)				\
11233965Sjdp	if (s2 != NULL && strncmp(s1, s2, lens2) == 0) {		\
11333965Sjdp		*flags |= F_SPECIALDAY;					\
11433965Sjdp		*flags |= type;						\
11533965Sjdp		*flags |= F_VARIABLE;					\
11633965Sjdp		if (strlen(s1) == lens2) {				\
11733965Sjdp			strcpy(specialday, s1);				\
11833965Sjdp			return (1);					\
11933965Sjdp		}							\
12033965Sjdp		strncpy(specialday, s1, lens2);				\
12133965Sjdp		specialday[lens2] = '\0';				\
12233965Sjdp		strcpy(modifieroffset, s1 + lens2);			\
12333965Sjdp		*flags |= F_MODIFIEROFFSET;				\
12433965Sjdp		return (1);						\
12533965Sjdp	}
12633965Sjdp
12733965Sjdp	if ((p = strchr(date, ' ')) == NULL) {
12833965Sjdp		if ((p = strchr(date, '/')) == NULL) {
12933965Sjdp			CHECKSPECIAL(date, STRING_CNY, strlen(STRING_CNY),
13033965Sjdp			    F_CNY);
13133965Sjdp			CHECKSPECIAL(date, ncny.name, ncny.len, F_CNY);
13233965Sjdp			CHECKSPECIAL(date, STRING_NEWMOON,
13333965Sjdp			    strlen(STRING_NEWMOON), F_NEWMOON);
13433965Sjdp			CHECKSPECIAL(date, nnewmoon.name, nnewmoon.len,
13533965Sjdp			    F_NEWMOON);
13633965Sjdp			CHECKSPECIAL(date, STRING_FULLMOON,
13733965Sjdp			    strlen(STRING_FULLMOON), F_FULLMOON);
13833965Sjdp			CHECKSPECIAL(date, nfullmoon.name, nfullmoon.len,
13933965Sjdp			    F_FULLMOON);
14033965Sjdp			CHECKSPECIAL(date, STRING_PASKHA,
14133965Sjdp			    strlen(STRING_PASKHA), F_PASKHA);
14233965Sjdp			CHECKSPECIAL(date, npaskha.name, npaskha.len, F_PASKHA);
14333965Sjdp			CHECKSPECIAL(date, STRING_EASTER,
14433965Sjdp			    strlen(STRING_EASTER), F_EASTER);
14533965Sjdp			CHECKSPECIAL(date, neaster.name, neaster.len, F_EASTER);
14633965Sjdp			CHECKSPECIAL(date, STRING_MAREQUINOX,
14733965Sjdp			    strlen(STRING_MAREQUINOX), F_MAREQUINOX);
14833965Sjdp			CHECKSPECIAL(date, nmarequinox.name, nmarequinox.len,
14938889Sjdp			    F_SEPEQUINOX);
15033965Sjdp			CHECKSPECIAL(date, STRING_SEPEQUINOX,
15160484Sobrien			    strlen(STRING_SEPEQUINOX), F_SEPEQUINOX);
15260484Sobrien			CHECKSPECIAL(date, nsepequinox.name, nsepequinox.len,
15360484Sobrien			    F_SEPEQUINOX);
15460484Sobrien			CHECKSPECIAL(date, STRING_JUNSOLSTICE,
15560484Sobrien			    strlen(STRING_JUNSOLSTICE), F_JUNSOLSTICE);
15633965Sjdp			CHECKSPECIAL(date, njunsolstice.name, njunsolstice.len,
15733965Sjdp			    F_JUNSOLSTICE);
15833965Sjdp			CHECKSPECIAL(date, STRING_DECSOLSTICE,
15960484Sobrien			    strlen(STRING_DECSOLSTICE), F_DECSOLSTICE);
16060484Sobrien			CHECKSPECIAL(date, ndecsolstice.name, ndecsolstice.len,
16160484Sobrien			    F_DECSOLSTICE);
16260484Sobrien			if (checkdayofweek(date, &len, &offset, &dow) != 0) {
16360484Sobrien				*flags |= F_DAYOFWEEK;
16433965Sjdp				*flags |= F_VARIABLE;
16533965Sjdp				*idayofweek = offset;
16633965Sjdp				if (strlen(date) == len) {
16733965Sjdp					strcpy(dayofweek, date);
16833965Sjdp					return (1);
16933965Sjdp				}
17033965Sjdp				strncpy(dayofweek, date, len);
17133965Sjdp				dayofweek[len] = '\0';
17233965Sjdp				strcpy(modifierindex, date + len);
17333965Sjdp				*flags |= F_MODIFIERINDEX;
17433965Sjdp				return (1);
17533965Sjdp			}
17633965Sjdp			if (isonlydigits(date, 1)) {
17733965Sjdp				/* Assume month number only */
17833965Sjdp				*flags |= F_MONTH;
17933965Sjdp				*imonth = (int)strtol(date, (char **)NULL, 10);
18033965Sjdp				strcpy(month, getmonthname(*imonth));
18133965Sjdp				return(1);
18233965Sjdp			}
18333965Sjdp			return (0);
18433965Sjdp		}
18560484Sobrien	}
18633965Sjdp
18733965Sjdp	/*
18833965Sjdp	 * After this, leave by goto-ing to "allfine" or "fail" to restore the
18933965Sjdp	 * original data in `date'.
19033965Sjdp	 */
19133965Sjdp	pold = *p;
19233965Sjdp	*p = 0;
19333965Sjdp	p1 = date;
19433965Sjdp	p2 = p + 1;
19533965Sjdp	/* Now p2 points to the next field and p1 to the first field */
19660484Sobrien
19733965Sjdp	if ((py = strchr(p2, '/')) != NULL) {
19833965Sjdp		/* We have a year in the string. Now this is getting tricky */
19933965Sjdp		strcpy(year, p1);
20033965Sjdp		*iyear = (int)strtol(year, NULL, 10);
20133965Sjdp		p1 = p2;
20233965Sjdp		p2 = py + 1;
20333965Sjdp		*py = 0;
20433965Sjdp		*flags |= F_YEAR;
20533965Sjdp	}
20633965Sjdp
20760484Sobrien	/* Check if there is a month-string in the date */
20833965Sjdp	if ((checkmonth(p1, &len, &offset, &pmonth) != 0)
20933965Sjdp	    || (checkmonth(p2, &len, &offset, &pmonth) != 0 && (p2 = p1))) {
21033965Sjdp		/* p2 is the non-month part */
21133965Sjdp		*flags |= F_MONTH;
21233965Sjdp		*imonth = offset;
21333965Sjdp
21433965Sjdp		strcpy(month, getmonthname(offset));
21533965Sjdp		if (isonlydigits(p2, 1)) {
21633965Sjdp			strcpy(dayofmonth, p2);
21733965Sjdp			*idayofmonth = (int)strtol(p2, (char **)NULL, 10);
21833965Sjdp			*flags |= F_DAYOFMONTH;
21961843Sobrien			goto allfine;
22033965Sjdp		}
22160484Sobrien		if (strcmp(p2, "*") == 0) {
22260484Sobrien			*flags |= F_ALLDAY;
22360484Sobrien			goto allfine;
22460484Sobrien		}
22560484Sobrien
22660484Sobrien		if (checkdayofweek(p2, &len, &offset, &dow) != 0) {
22760484Sobrien			*flags |= F_DAYOFWEEK;
22860484Sobrien			*flags |= F_VARIABLE;
22960484Sobrien			*idayofweek = offset;
23033965Sjdp			strcpy(dayofweek, getdayofweekname(offset));
23133965Sjdp			if (strlen(p2) == len)
23233965Sjdp				goto allfine;
23333965Sjdp			strcpy(modifierindex, p2 + len);
23433965Sjdp			*flags |= F_MODIFIERINDEX;
23560484Sobrien			goto allfine;
23660484Sobrien		}
23733965Sjdp		goto fail;
23833965Sjdp	}
23933965Sjdp
24033965Sjdp	/* Check if there is an every-day or every-month in the string */
24133965Sjdp	if ((strcmp(p1, "*") == 0 && isonlydigits(p2, 1))
24233965Sjdp	    || (strcmp(p2, "*") == 0 && isonlydigits(p1, 1) && (p2 = p1))) {
24333965Sjdp		int d;
24433965Sjdp
24533965Sjdp		*flags |= F_ALLMONTH;
24633965Sjdp		*flags |= F_DAYOFMONTH;
24733965Sjdp		d = (int)strtol(p2, (char **)NULL, 10);
24833965Sjdp		*idayofmonth = d;
24960484Sobrien		sprintf(dayofmonth, "%d", d);
25033965Sjdp		goto allfine;
25160484Sobrien	}
25260484Sobrien
25377298Sobrien	/* Month as a number, then a weekday */
25460484Sobrien	if (isonlydigits(p1, 1)
25560484Sobrien	    && checkdayofweek(p2, &len, &offset, &dow) != 0) {
25660484Sobrien		int d;
25760484Sobrien
25860484Sobrien		*flags |= F_MONTH;
25960484Sobrien		*flags |= F_DAYOFWEEK;
26060484Sobrien		*flags |= F_VARIABLE;
26160484Sobrien
26260484Sobrien		*idayofweek = offset;
26360484Sobrien		d = (int)strtol(p1, (char **)NULL, 10);
26460484Sobrien		*imonth = d;
26560484Sobrien		strcpy(month, getmonthname(d));
26660484Sobrien
26760484Sobrien		strcpy(dayofweek, getdayofweekname(offset));
26860484Sobrien		if (strlen(p2) == len)
26960484Sobrien			goto allfine;
27060484Sobrien		strcpy(modifierindex, p2 + len);
27160484Sobrien		*flags |= F_MODIFIERINDEX;
27260484Sobrien		goto allfine;
27360484Sobrien	}
27460484Sobrien
27560484Sobrien	/* If both the month and date are specified as numbers */
27660484Sobrien	if (isonlydigits(p1, 1) && isonlydigits(p2, 0)) {
27760484Sobrien		/* Now who wants to be this ambigious? :-( */
27860484Sobrien		int m, d;
27977298Sobrien
28060484Sobrien		if (strchr(p2, '*') != NULL)
28133965Sjdp			*flags |= F_VARIABLE;
28260484Sobrien
28360484Sobrien		m = (int)strtol(p1, (char **)NULL, 10);
28433965Sjdp		d = (int)strtol(p2, (char **)NULL, 10);
28533965Sjdp
28633965Sjdp		*flags |= F_MONTH;
28733965Sjdp		*flags |= F_DAYOFMONTH;
28860484Sobrien
28933965Sjdp		if (m > 12) {
29033965Sjdp			*imonth = d;
29133965Sjdp			*idayofmonth = m;
29233965Sjdp			strcpy(month, getmonthname(d));
29333965Sjdp			sprintf(dayofmonth, "%d", m);
29433965Sjdp		} else {
29533965Sjdp			*imonth = m;
29633965Sjdp			*idayofmonth = d;
29733965Sjdp			strcpy(month, getmonthname(m));
29833965Sjdp			sprintf(dayofmonth, "%d", d);
29933965Sjdp		}
30033965Sjdp		goto allfine;
30133965Sjdp	}
30233965Sjdp
30360484Sobrien	/* FALLTHROUGH */
30460484Sobrienfail:
30560484Sobrien	*p = pold;
30633965Sjdp	return (0);
30761843Sobrienallfine:
30861843Sobrien	*p = pold;
30961843Sobrien	return (1);
31061843Sobrien
31177298Sobrien}
31261843Sobrien
31361843Sobrienvoid
31477298Sobrienremember(int *rememberindex, int *y, int *m, int *d, char **ed, int yy, int mm,
31561843Sobrien    int dd, char *extra);
31661843Sobrienvoid
31733965Sjdpremember(int *rememberindex, int *y, int *m, int *d, char **ed, int yy, int mm,
31833965Sjdp    int dd, char *extra)
31933965Sjdp{
32033965Sjdp	static int warned = 0;
32133965Sjdp
32233965Sjdp	if (*rememberindex >= MAXCOUNT - 1) {
32333965Sjdp		if (warned == 0)
32433965Sjdp			warnx("Index > %d, ignored", MAXCOUNT);
32533965Sjdp		warned++;
32633965Sjdp		return;
32733965Sjdp	}
32833965Sjdp	y[*rememberindex] = yy;
32933965Sjdp	m[*rememberindex] = mm;
33033965Sjdp	d[*rememberindex] = dd;
33133965Sjdp	if (extra != NULL)
33233965Sjdp		strcpy(ed[*rememberindex], extra);
33333965Sjdp	else
33433965Sjdp		ed[*rememberindex][0] = '\0';
33533965Sjdp	*rememberindex += 1;
33633965Sjdp}
33733965Sjdp
33833965Sjdpstatic void
33933965Sjdpdebug_determinestyle(int dateonly, char *date, int flags, char *month,
34060484Sobrien    int imonth, char *dayofmonth, int idayofmonth, char *dayofweek,
34133965Sjdp    int idayofweek, char *modifieroffset, char *modifierindex, char *specialday,
34233965Sjdp    char *year, int iyear)
34333965Sjdp{
34433965Sjdp
34533965Sjdp	if (dateonly != 0) {
34633965Sjdp		printf("-------\ndate: |%s|\n", date);
34733965Sjdp		if (dateonly == 1)
34833965Sjdp			return;
34933965Sjdp	}
35033965Sjdp	printf("flags: %x - %s\n", flags, showflags(flags));
35133965Sjdp	if (modifieroffset[0] != '\0')
35233965Sjdp		printf("modifieroffset: |%s|\n", modifieroffset);
35333965Sjdp	if (modifierindex[0] != '\0')
35433965Sjdp		printf("modifierindex: |%s|\n", modifierindex);
35533965Sjdp	if (year[0] != '\0')
35633965Sjdp		printf("year: |%s| (%d)\n", year, iyear);
35733965Sjdp	if (month[0] != '\0')
35833965Sjdp		printf("month: |%s| (%d)\n", month, imonth);
35933965Sjdp	if (dayofmonth[0] != '\0')
36033965Sjdp		printf("dayofmonth: |%s| (%d)\n", dayofmonth, idayofmonth);
36133965Sjdp	if (dayofweek[0] != '\0')
36233965Sjdp		printf("dayofweek: |%s| (%d)\n", dayofweek, idayofweek);
36333965Sjdp	if (specialday[0] != '\0')
36433965Sjdp		printf("specialday: |%s|\n", specialday);
36533965Sjdp}
36633965Sjdp
36733965Sjdpstatic struct yearinfo {
36833965Sjdp	int year;
36933965Sjdp	int ieaster, ipaskha, firstcnyday;
37033965Sjdp	double ffullmoon[MAXMOONS], fnewmoon[MAXMOONS];
37133965Sjdp	double ffullmooncny[MAXMOONS], fnewmooncny[MAXMOONS];
37233965Sjdp	int ichinesemonths[MAXMOONS];
37333965Sjdp	double equinoxdays[2], solsticedays[2];
37460484Sobrien	int *monthdays;
37533965Sjdp	struct yearinfo *next;
37633965Sjdp} *years, *yearinfo;
37733965Sjdp
37860484Sobrien/*
37960484Sobrien * Calculate dates with offset from weekdays, like Thurs-3, Wed+2, etc.
38060484Sobrien * day is the day of the week,
38160484Sobrien * offset the ordinal number of the weekday in the month.
38260484Sobrien */
38360484Sobrienstatic int
38433965Sjdpwdayom (int day, int offset, int month, int year)
38533965Sjdp{
38633965Sjdp/* Weekday of first day in month */
38733965Sjdp	int wday1;                                /* first day of month */
38833965Sjdp/* Weekday of last day in month */
38933965Sjdp	int wdayn;
39033965Sjdp	int d;
39133965Sjdp
39261843Sobrien	wday1 = first_dayofweek_of_month(year, month);
39361843Sobrien	if (wday1 < 0)                          /* not set */
39461843Sobrien		return (wday1);
39561843Sobrien	/*
39677298Sobrien	 * Date of zeroth or first of our weekday in month, depending on the
39761843Sobrien	 * relationship with the first of the month.  The range is -6:6.
39861843Sobrien	 */
39961843Sobrien	d = (day - wday1 + 1) % 7;
40061843Sobrien	/*
40161843Sobrien	 * Which way are we counting?  Offset 0 is invalid, abs (offset) > 5 is
40233965Sjdp	 * meaningless, but that's OK.  Offset 5 may or may not be meaningless,
40333965Sjdp	 * so there's no point in complaining for complaining's sake.
40433965Sjdp	 */
40533965Sjdp	if (offset < 0) {			/* back from end of month */
40633965Sjdp						/* FIXME */
40761843Sobrien		wdayn = d;
40833965Sjdp		while (wdayn <= yearinfo->monthdays[month])
40933965Sjdp			wdayn += 7;
41033965Sjdp		d = offset * 7 + wdayn;
41133965Sjdp	} else if (offset > 0){
41233965Sjdp		if (d > 0)
41333965Sjdp			d += offset * 7 - 7;
41433965Sjdp		else
41533965Sjdp			d += offset * 7;
41633965Sjdp	} else
41733965Sjdp		warnx ("Invalid offset 0");
41833965Sjdp	return (d);
41933965Sjdp}
42033965Sjdp
42133965Sjdp/*
42233965Sjdp * Possible date formats include any combination of:
42333965Sjdp *	3-charmonth			(January, Jan, Jan)
42433965Sjdp *	3-charweekday			(Friday, Monday, mon.)
42533965Sjdp *	numeric month or day		(1, 2, 04)
42633965Sjdp *
42733965Sjdp * Any character may separate them, or they may not be separated.  Any line,
42833965Sjdp * following a line that is matched, that starts with "whitespace", is shown
42933965Sjdp * along with the matched line.
43033965Sjdp */
43133965Sjdpint
43233965Sjdpparsedaymonth(char *date, int *yearp, int *monthp, int *dayp, int *flags,
43333965Sjdp    char **edp)
43433965Sjdp{
43577298Sobrien	char month[100], dayofmonth[100], dayofweek[100], modifieroffset[100];
43677298Sobrien	char syear[100];
43777298Sobrien	char modifierindex[100], specialday[100];
43877298Sobrien	int idayofweek = -1, imonth = -1, idayofmonth = -1, iyear = -1;
43977298Sobrien	int year, remindex;
44077298Sobrien	int d, m, dow, rm, rd, offset;
44177298Sobrien	char *ed;
44277298Sobrien	int retvalsign = 1;
44377298Sobrien
44477298Sobrien	/*
44577298Sobrien	 * CONVENTION
44633965Sjdp	 *
44733965Sjdp	 * Month:     1-12
44833965Sjdp	 * Monthname: Jan .. Dec
44933965Sjdp	 * Day:	      1-31
45033965Sjdp	 * Weekday:   Mon .. Sun
45133965Sjdp	 *
45233965Sjdp	 */
45333965Sjdp
45433965Sjdp	*flags = 0;
45533965Sjdp
45633965Sjdp	if (debug)
45733965Sjdp		debug_determinestyle(1, date, *flags, month, imonth,
45833965Sjdp		    dayofmonth, idayofmonth, dayofweek, idayofweek,
45933965Sjdp		    modifieroffset, modifierindex, specialday, syear, iyear);
46033965Sjdp	if (determinestyle(date, flags, month, &imonth, dayofmonth,
46133965Sjdp		&idayofmonth, dayofweek, &idayofweek, modifieroffset,
46233965Sjdp		modifierindex, specialday, syear, &iyear) == 0) {
46333965Sjdp		if (debug)
46433965Sjdp			printf("Failed!\n");
46533965Sjdp		return (0);
46633965Sjdp	}
46733965Sjdp
46833965Sjdp	if (debug)
46933965Sjdp		debug_determinestyle(0, date, *flags, month, imonth,
47033965Sjdp		    dayofmonth, idayofmonth, dayofweek, idayofweek,
47133965Sjdp		    modifieroffset, modifierindex, specialday, syear, iyear);
47233965Sjdp
47333965Sjdp	remindex = 0;
47433965Sjdp	for (year = year1; year <= year2; year++) {
47533965Sjdp
47633965Sjdp		int lflags = *flags;
47733965Sjdp		/* If the year is specified, only do it if it is this year! */
47833965Sjdp		if ((lflags & F_YEAR) != 0)
47933965Sjdp			if (iyear != year)
48033965Sjdp				continue;
48133965Sjdp		lflags &= ~F_YEAR;
48233965Sjdp
48333965Sjdp		/* Get important dates for this year */
48433965Sjdp		yearinfo = years;
48533965Sjdp		while (yearinfo != NULL) {
48633965Sjdp			if (yearinfo->year == year)
48733965Sjdp				break;
48833965Sjdp			yearinfo = yearinfo -> next;
48933965Sjdp		}
49033965Sjdp		if (yearinfo == NULL) {
49133965Sjdp			yearinfo = (struct yearinfo *)calloc(1,
49233965Sjdp			    sizeof(struct yearinfo));
49333965Sjdp			if (yearinfo == NULL)
49433965Sjdp				errx(1, "Unable to allocate more years");
49533965Sjdp			yearinfo->year = year;
49633965Sjdp			yearinfo->next = years;
49733965Sjdp			years = yearinfo;
49833965Sjdp
49960484Sobrien			yearinfo->monthdays = monthdaytab[isleap(year)];
50033965Sjdp			yearinfo->ieaster = easter(year);
50133965Sjdp			yearinfo->ipaskha = paskha(year);
50233965Sjdp			fpom(year, UTCOffset, yearinfo->ffullmoon,
50333965Sjdp			    yearinfo->fnewmoon);
50433965Sjdp			fpom(year, UTCOFFSET_CNY, yearinfo->ffullmooncny,
50533965Sjdp			    yearinfo->fnewmooncny);
50633965Sjdp			fequinoxsolstice(year, UTCOffset,
50733965Sjdp			    yearinfo->equinoxdays, yearinfo->solsticedays);
50833965Sjdp
50933965Sjdp			/*
51033965Sjdp			 * CNY: Match day with sun longitude at 330` with new
51133965Sjdp			 * moon
51233965Sjdp			 */
51333965Sjdp			yearinfo->firstcnyday = calculatesunlongitude30(year,
51433965Sjdp			    UTCOFFSET_CNY, yearinfo->ichinesemonths);
51533965Sjdp			for (m = 0; yearinfo->fnewmooncny[m] >= 0; m++) {
51633965Sjdp				if (yearinfo->fnewmooncny[m] >
51733965Sjdp				    yearinfo->firstcnyday) {
51833965Sjdp					yearinfo->firstcnyday =
51933965Sjdp					    floor(yearinfo->fnewmooncny[m - 1]);
52033965Sjdp					break;
52133965Sjdp				}
52233965Sjdp			}
52333965Sjdp		}
52433965Sjdp
52533965Sjdp		/* Same day every year */
52633965Sjdp		if (lflags == (F_MONTH | F_DAYOFMONTH)) {
52733965Sjdp			if (!remember_ymd(year, imonth, idayofmonth))
52833965Sjdp				continue;
52933965Sjdp			remember(&remindex, yearp, monthp, dayp, edp,
53033965Sjdp			    year, imonth, idayofmonth, NULL);
53133965Sjdp			continue;
53233965Sjdp		}
53333965Sjdp
53433965Sjdp		/* XXX Same day every year, but variable */
53533965Sjdp		if (lflags == (F_MONTH | F_DAYOFMONTH | F_VARIABLE)) {
53633965Sjdp			if (!remember_ymd(year, imonth, idayofmonth))
53733965Sjdp				continue;
53833965Sjdp			remember(&remindex, yearp, monthp, dayp, edp,
53933965Sjdp			    year, imonth, idayofmonth, NULL);
54033965Sjdp			continue;
54133965Sjdp		}
54238889Sjdp
54338889Sjdp		/* Same day every month */
54438889Sjdp		if (lflags == (F_ALLMONTH | F_DAYOFMONTH)) {
54533965Sjdp			for (m = 1; m <= 12; m++) {
54633965Sjdp				if (!remember_ymd(year, m, idayofmonth))
54733965Sjdp					continue;
54833965Sjdp				remember(&remindex, yearp, monthp, dayp, edp,
54933965Sjdp				    year, m, idayofmonth, NULL);
55033965Sjdp			}
55133965Sjdp			continue;
55233965Sjdp		}
55333965Sjdp
55433965Sjdp		/* Every day of a month */
55533965Sjdp		if (lflags == (F_ALLDAY | F_MONTH)) {
55633965Sjdp			for (d = 1; d <= yearinfo->monthdays[imonth]; d++) {
55733965Sjdp				if (!remember_ymd(year, imonth, d))
55833965Sjdp					continue;
55933965Sjdp				remember(&remindex, yearp, monthp, dayp, edp,
56033965Sjdp				    year, imonth, d, NULL);
56133965Sjdp			}
56233965Sjdp			continue;
56360484Sobrien		}
56460484Sobrien
56560484Sobrien		/* One day of every month */
56633965Sjdp		if (lflags == (F_ALLMONTH | F_DAYOFWEEK)) {
56733965Sjdp			for (m = 1; m <= 12; m++) {
56833965Sjdp				if (!remember_ymd(year, m, idayofmonth))
56960484Sobrien					continue;
57060484Sobrien				remember(&remindex, yearp, monthp, dayp, edp,
57160484Sobrien				    year, m, idayofmonth, NULL);
57233965Sjdp			}
57360484Sobrien			continue;
57460484Sobrien		}
57533965Sjdp
57633965Sjdp		/* Every dayofweek of the year */
57733965Sjdp		if (lflags == (F_DAYOFWEEK | F_VARIABLE)) {
57833965Sjdp			dow = first_dayofweek_of_year(year);
57933965Sjdp			d = (idayofweek - dow + 8) % 7;
58033965Sjdp			while (d <= 366) {
58133965Sjdp				if (remember_yd(year, d, &rm, &rd))
58233965Sjdp					remember(&remindex,
58333965Sjdp					    yearp, monthp, dayp, edp,
58433965Sjdp					    year, rm, rd, NULL);
58533965Sjdp				d += 7;
58633965Sjdp			}
58733965Sjdp			continue;
58833965Sjdp		}
58933965Sjdp
59033965Sjdp		/*
59133965Sjdp	         * Every so-manied dayofweek of every month of the year:
59233965Sjdp	         * Thu-3
59333965Sjdp	         */
59433965Sjdp		if (lflags == (F_DAYOFWEEK | F_MODIFIERINDEX | F_VARIABLE)) {
59533965Sjdp			offset = indextooffset(modifierindex);
59633965Sjdp
59733965Sjdp			for (m = 0; m <= 12; m++) {
59833965Sjdp	                        d = wdayom (idayofweek, offset, m, year);
59933965Sjdp				if (remember_ymd(year, m, d)) {
60033965Sjdp					remember(&remindex,
60133965Sjdp					    yearp, monthp, dayp, edp,
60233965Sjdp					    year, m, d, NULL);
60333965Sjdp					continue;
60433965Sjdp				}
60533965Sjdp			}
60660484Sobrien			continue;
60733965Sjdp		}
60833965Sjdp
60960484Sobrien		/*
61033965Sjdp	         * A certain dayofweek of a month
61133965Sjdp	         * Jan/Thu-3
61233965Sjdp	         */
61333965Sjdp		if (lflags ==
61433965Sjdp		    (F_MONTH | F_DAYOFWEEK | F_MODIFIERINDEX | F_VARIABLE)) {
61533965Sjdp			offset = indextooffset(modifierindex);
61660484Sobrien			dow = first_dayofweek_of_month(year, imonth);
61760484Sobrien			d = (idayofweek - dow + 8) % 7;
61860484Sobrien
61960484Sobrien			if (offset > 0) {
62060484Sobrien				while (d <= yearinfo->monthdays[imonth]) {
62160484Sobrien					if (--offset == 0
62260484Sobrien					    && remember_ymd(year, imonth, d)) {
62360484Sobrien						remember(&remindex,
62460484Sobrien						    yearp, monthp, dayp, edp,
62533965Sjdp						    year, imonth, d, NULL);
62633965Sjdp						continue;
62733965Sjdp					}
62860484Sobrien					d += 7;
62933965Sjdp				}
63033965Sjdp				continue;
63133965Sjdp			}
63233965Sjdp			if (offset < 0) {
63333965Sjdp				while (d <= yearinfo->monthdays[imonth])
63433965Sjdp					d += 7;
63533965Sjdp				while (offset != 0) {
63633965Sjdp					offset++;
63733965Sjdp					d -= 7;
63833965Sjdp				}
63933965Sjdp				if (remember_ymd(year, imonth, d))
64033965Sjdp					remember(&remindex,
64133965Sjdp					    yearp, monthp, dayp, edp,
64233965Sjdp					    year, imonth, d, NULL);
64333965Sjdp				continue;
64433965Sjdp			}
64533965Sjdp			continue;
64633965Sjdp		}
64733965Sjdp
64833965Sjdp		/* Every dayofweek of the month */
64933965Sjdp		if (lflags == (F_DAYOFWEEK | F_MONTH | F_VARIABLE)) {
65033965Sjdp			dow = first_dayofweek_of_month(year, imonth);
65133965Sjdp			d = (idayofweek - dow + 8) % 7;
65233965Sjdp			while (d <= yearinfo->monthdays[imonth]) {
65333965Sjdp				if (remember_ymd(year, imonth, d))
65433965Sjdp					remember(&remindex,
65533965Sjdp					    yearp, monthp, dayp, edp,
65633965Sjdp					    year, imonth, d, NULL);
65733965Sjdp				d += 7;
65833965Sjdp			}
65933965Sjdp			continue;
66033965Sjdp		}
66133965Sjdp
66233965Sjdp		/* Easter */
66333965Sjdp		if ((lflags & ~F_MODIFIEROFFSET) ==
66433965Sjdp		    (F_SPECIALDAY | F_VARIABLE | F_EASTER)) {
66533965Sjdp			offset = 0;
66633965Sjdp			if ((lflags & F_MODIFIEROFFSET) != 0)
66733965Sjdp				offset = parseoffset(modifieroffset);
66833965Sjdp			if (remember_yd(year, yearinfo->ieaster + offset,
66960484Sobrien	                        &rm, &rd))
67033965Sjdp				remember(&remindex, yearp, monthp, dayp, edp,
67133965Sjdp				    year, rm, rd, NULL);
67233965Sjdp			continue;
67360484Sobrien		}
67433965Sjdp
67533965Sjdp		/* Paskha */
67633965Sjdp		if ((lflags & ~F_MODIFIEROFFSET) ==
67760484Sobrien		    (F_SPECIALDAY | F_VARIABLE | F_PASKHA)) {
67833965Sjdp			offset = 0;
67933965Sjdp			if ((lflags & F_MODIFIEROFFSET) != 0)
68033965Sjdp				offset = parseoffset(modifieroffset);
68133965Sjdp			if (remember_yd(year, yearinfo->ipaskha + offset,
68233965Sjdp	                        &rm, &rd))
68360484Sobrien				remember(&remindex, yearp, monthp, dayp, edp,
68460484Sobrien				    year, rm, rd, NULL);
68533965Sjdp			continue;
68633965Sjdp		}
68733965Sjdp
68833965Sjdp		/* Chinese New Year */
68933965Sjdp		if ((lflags & ~F_MODIFIEROFFSET) ==
69060484Sobrien		    (F_SPECIALDAY | F_VARIABLE | F_CNY)) {
69160484Sobrien			offset = 0;
69233965Sjdp			if ((lflags & F_MODIFIEROFFSET) != 0)
69333965Sjdp				offset = parseoffset(modifieroffset);
69433965Sjdp			if (remember_yd(year, yearinfo->firstcnyday + offset,
69533965Sjdp	                        &rm, &rd))
69633965Sjdp				remember(&remindex, yearp, monthp, dayp, edp,
69733965Sjdp				    year, rm, rd, NULL);
69860484Sobrien			continue;
69960484Sobrien		}
70033965Sjdp
70133965Sjdp		/* FullMoon */
70233965Sjdp		if ((lflags & ~F_MODIFIEROFFSET) ==
70333965Sjdp		    (F_SPECIALDAY | F_VARIABLE | F_FULLMOON)) {
70460484Sobrien			int i;
70560484Sobrien
70633965Sjdp			offset = 0;
70733965Sjdp			if ((lflags & F_MODIFIEROFFSET) != 0)
70833965Sjdp				offset = parseoffset(modifieroffset);
70933965Sjdp			for (i = 0; yearinfo->ffullmoon[i] > 0; i++) {
71033965Sjdp				if (remember_yd(year,
71133965Sjdp	                                floor(yearinfo->ffullmoon[i]) + offset,
71233965Sjdp					&rm, &rd)) {
71333965Sjdp					ed = floattotime(
71433965Sjdp					    yearinfo->ffullmoon[i]);
71533965Sjdp					remember(&remindex,
71633965Sjdp					    yearp, monthp, dayp, edp,
71733965Sjdp					    year, rm, rd, ed);
71833965Sjdp				}
71933965Sjdp			}
72033965Sjdp			continue;
72133965Sjdp		}
72233965Sjdp
72333965Sjdp		/* NewMoon */
72433965Sjdp		if ((lflags & ~F_MODIFIEROFFSET) ==
72533965Sjdp		    (F_SPECIALDAY | F_VARIABLE | F_NEWMOON)) {
72633965Sjdp			int i;
72733965Sjdp
72833965Sjdp			offset = 0;
72933965Sjdp			if ((lflags & F_MODIFIEROFFSET) != 0)
73033965Sjdp				offset = parseoffset(modifieroffset);
73133965Sjdp			for (i = 0; yearinfo->ffullmoon[i] > 0; i++) {
73233965Sjdp				if (remember_yd(year,
73361843Sobrien					floor(yearinfo->fnewmoon[i]) + offset,
73433965Sjdp					&rm, &rd)) {
73561843Sobrien					ed = floattotime(yearinfo->fnewmoon[i]);
73661843Sobrien					remember(&remindex,
73761843Sobrien					    yearp, monthp, dayp, edp,
73861843Sobrien					    year, rm, rd, ed);
73961843Sobrien				}
74033965Sjdp			}
74161843Sobrien			continue;
74233965Sjdp		}
74333965Sjdp
74433965Sjdp		/* (Mar|Sep)Equinox */
74533965Sjdp		if ((lflags & ~F_MODIFIEROFFSET) ==
74633965Sjdp		    (F_SPECIALDAY | F_VARIABLE | F_MAREQUINOX)) {
74733965Sjdp			offset = 0;
74833965Sjdp			if ((lflags & F_MODIFIEROFFSET) != 0)
74933965Sjdp				offset = parseoffset(modifieroffset);
75033965Sjdp			if (remember_yd(year, yearinfo->equinoxdays[0] + offset,
75133965Sjdp				&rm, &rd)) {
75233965Sjdp				ed = floattotime(yearinfo->equinoxdays[0]);
75333965Sjdp				remember(&remindex, yearp, monthp, dayp, edp,
75433965Sjdp				    year, rm, rd, ed);
75533965Sjdp			}
75633965Sjdp			continue;
75733965Sjdp		}
75833965Sjdp		if ((lflags & ~F_MODIFIEROFFSET) ==
75933965Sjdp		    (F_SPECIALDAY | F_VARIABLE | F_SEPEQUINOX)) {
76033965Sjdp			offset = 0;
76133965Sjdp			if ((lflags & F_MODIFIEROFFSET) != 0)
76233965Sjdp				offset = parseoffset(modifieroffset);
76333965Sjdp			if (remember_yd(year, yearinfo->equinoxdays[1] + offset,
76433965Sjdp			    &rm, &rd)) {
76533965Sjdp				ed = floattotime(yearinfo->equinoxdays[1]);
76633965Sjdp				remember(&remindex, yearp, monthp, dayp, edp,
76733965Sjdp				    year, rm, rd, ed);
76833965Sjdp			}
76933965Sjdp			continue;
77033965Sjdp		}
77133965Sjdp
77233965Sjdp		/* (Jun|Dec)Solstice */
77333965Sjdp		if ((lflags & ~F_MODIFIEROFFSET) ==
77433965Sjdp		    (F_SPECIALDAY | F_VARIABLE | F_JUNSOLSTICE)) {
77560484Sobrien			offset = 0;
77660484Sobrien			if ((lflags & F_MODIFIEROFFSET) != 0)
77760484Sobrien				offset = parseoffset(modifieroffset);
77833965Sjdp			if (remember_yd(year,
77933965Sjdp				yearinfo->solsticedays[0] + offset, &rm, &rd)) {
78033965Sjdp				ed = floattotime(yearinfo->solsticedays[0]);
78133965Sjdp				remember(&remindex, yearp, monthp, dayp, edp,
78233965Sjdp				    year, rm, rd, ed);
78333965Sjdp			}
78433965Sjdp			continue;
78533965Sjdp		}
78633965Sjdp		if ((lflags & ~F_MODIFIEROFFSET) ==
78733965Sjdp		    (F_SPECIALDAY | F_VARIABLE | F_DECSOLSTICE)) {
78833965Sjdp			offset = 0;
78933965Sjdp			if ((lflags & F_MODIFIEROFFSET) != 0)
79033965Sjdp				offset = parseoffset(modifieroffset);
79133965Sjdp			if (remember_yd(year,
79233965Sjdp				yearinfo->solsticedays[1] + offset, &rm, &rd)) {
79333965Sjdp				ed = floattotime(yearinfo->solsticedays[1]);
79433965Sjdp				remember(&remindex, yearp, monthp, dayp, edp,
79533965Sjdp				    year, rm, rd, ed);
79633965Sjdp			}
79733965Sjdp			continue;
79833965Sjdp		}
79933965Sjdp
80033965Sjdp		if (debug) {
80133965Sjdp			printf("Unprocessed:\n");
80233965Sjdp			debug_determinestyle(2, date, lflags, month, imonth,
80333965Sjdp			    dayofmonth, idayofmonth, dayofweek, idayofweek,
80433965Sjdp			    modifieroffset, modifierindex, specialday, syear,
80533965Sjdp			    iyear);
80633965Sjdp		}
80733965Sjdp		retvalsign = -1;
80833965Sjdp	}
80933965Sjdp
81033965Sjdp	if (retvalsign == -1)
81133965Sjdp		return (-remindex - 1);
81233965Sjdp	else
81333965Sjdp		return (remindex);
81433965Sjdp}
81533965Sjdp
81633965Sjdpstatic char *
81733965Sjdpshowflags(int flags)
81833965Sjdp{
81933965Sjdp	static char s[1000];
82033965Sjdp	s[0] = '\0';
82133965Sjdp
82233965Sjdp	if ((flags & F_YEAR) != 0)
82360484Sobrien		strcat(s, "year ");
82460484Sobrien	if ((flags & F_MONTH) != 0)
82533965Sjdp		strcat(s, "month ");
82633965Sjdp	if ((flags & F_DAYOFWEEK) != 0)
82777298Sobrien		strcat(s, "dayofweek ");
82877298Sobrien	if ((flags & F_DAYOFMONTH) != 0)
82933965Sjdp		strcat(s, "dayofmonth ");
83033965Sjdp	if ((flags & F_MODIFIERINDEX) != 0)
83133965Sjdp		strcat(s, "modifierindex ");
83233965Sjdp	if ((flags & F_MODIFIEROFFSET) != 0)
83333965Sjdp		strcat(s, "modifieroffset ");
83433965Sjdp	if ((flags & F_SPECIALDAY) != 0)
83533965Sjdp		strcat(s, "specialday ");
83633965Sjdp	if ((flags & F_ALLMONTH) != 0)
83733965Sjdp		strcat(s, "allmonth ");
83833965Sjdp	if ((flags & F_ALLDAY) != 0)
83933965Sjdp		strcat(s, "allday ");
84033965Sjdp	if ((flags & F_VARIABLE) != 0)
84133965Sjdp		strcat(s, "variable ");
84233965Sjdp	if ((flags & F_CNY) != 0)
84333965Sjdp		strcat(s, "chinesenewyear ");
84460484Sobrien	if ((flags & F_PASKHA) != 0)
84560484Sobrien		strcat(s, "paskha ");
84633965Sjdp	if ((flags & F_EASTER) != 0)
84733965Sjdp		strcat(s, "easter ");
84833965Sjdp	if ((flags & F_FULLMOON) != 0)
84933965Sjdp		strcat(s, "fullmoon ");
85033965Sjdp	if ((flags & F_NEWMOON) != 0)
85133965Sjdp		strcat(s, "newmoon ");
85233965Sjdp	if ((flags & F_MAREQUINOX) != 0)
85333965Sjdp		strcat(s, "marequinox ");
85433965Sjdp	if ((flags & F_SEPEQUINOX) != 0)
85533965Sjdp		strcat(s, "sepequinox ");
85633965Sjdp	if ((flags & F_JUNSOLSTICE) != 0)
85733965Sjdp		strcat(s, "junsolstice ");
85833965Sjdp	if ((flags & F_DECSOLSTICE) != 0)
85933965Sjdp		strcat(s, "decsolstice ");
86033965Sjdp
86133965Sjdp	return s;
86233965Sjdp}
86333965Sjdp
86433965Sjdpstatic const char *
86533965Sjdpgetmonthname(int i)
86633965Sjdp{
86733965Sjdp	if (i <= 0 || i > 12)
86833965Sjdp		return ("");
86933965Sjdp	if (nmonths[i - 1].len != 0 && nmonths[i - 1].name != NULL)
87060484Sobrien		return (nmonths[i - 1].name);
87133965Sjdp	return (months[i - 1]);
87233965Sjdp}
87360484Sobrien
87433965Sjdpstatic int
87560484Sobriencheckmonth(char *s, size_t *len, size_t *offset, const char **month)
87660484Sobrien{
87733965Sjdp	struct fixs *n;
87833965Sjdp	int i;
87960484Sobrien
88060484Sobrien	for (i = 0; fnmonths[i].name != NULL; i++) {
88160484Sobrien		n = fnmonths + i;
88260484Sobrien		if (strncasecmp(s, n->name, n->len) == 0) {
88333965Sjdp			*len = n->len;
88433965Sjdp			*month = n->name;
88533965Sjdp			*offset = i + 1;
88633965Sjdp			return (1);
88733965Sjdp		}
88860484Sobrien	}
88933965Sjdp	for (i = 0; nmonths[i].name != NULL; i++) {
89033965Sjdp		n = nmonths + i;
89133965Sjdp		if (strncasecmp(s, n->name, n->len) == 0) {
89233965Sjdp			*len = n->len;
89333965Sjdp			*month = n->name;
89433965Sjdp			*offset = i + 1;
89560484Sobrien			return (1);
89633965Sjdp		}
89733965Sjdp	}
89833965Sjdp	for (i = 0; fmonths[i] != NULL; i++) {
89933965Sjdp		*len = strlen(fmonths[i]);
90033965Sjdp		if (strncasecmp(s, fmonths[i], *len) == 0) {
90133965Sjdp			*month = fmonths[i];
90233965Sjdp			*offset = i + 1;
90333965Sjdp			return (1);
90433965Sjdp		}
90533965Sjdp	}
90633965Sjdp	for (i = 0; months[i] != NULL; i++) {
90733965Sjdp		if (strncasecmp(s, months[i], 3) == 0) {
90833965Sjdp			*len = 3;
90933965Sjdp			*month = months[i];
91033965Sjdp			*offset = i + 1;
91133965Sjdp			return (1);
91260484Sobrien		}
91360484Sobrien	}
91433965Sjdp	return (0);
91533965Sjdp}
91633965Sjdp
91760484Sobrienstatic const char *
91833965Sjdpgetdayofweekname(int i)
91933965Sjdp{
92033965Sjdp	if (ndays[i].len != 0 && ndays[i].name != NULL)
92133965Sjdp		return (ndays[i].name);
92233965Sjdp	return (days[i]);
92360484Sobrien}
92433965Sjdp
92533965Sjdpstatic int
92633965Sjdpcheckdayofweek(char *s, size_t *len, size_t *offset, const char **dow)
92733965Sjdp{
92833965Sjdp	struct fixs *n;
92933965Sjdp	int i;
93033965Sjdp
93133965Sjdp	for (i = 0; fndays[i].name != NULL; i++) {
93233965Sjdp		n = fndays + i;
93333965Sjdp		if (strncasecmp(s, n->name, n->len) == 0) {
93433965Sjdp			*len = n->len;
93560484Sobrien			*dow = n->name;
93660484Sobrien			*offset = i;
93733965Sjdp			return (1);
93833965Sjdp		}
93933965Sjdp	}
94033965Sjdp	for (i = 0; ndays[i].name != NULL; i++) {
94133965Sjdp		n = ndays + i;
94233965Sjdp		if (strncasecmp(s, n->name, n->len) == 0) {
94333965Sjdp			*len = n->len;
94460484Sobrien			*dow = n->name;
94560484Sobrien			*offset = i;
94660484Sobrien			return (1);
94733965Sjdp		}
94833965Sjdp	}
94933965Sjdp	for (i = 0; fdays[i] != NULL; i++) {
95033965Sjdp		*len = strlen(fdays[i]);
95133965Sjdp		if (strncasecmp(s, fdays[i], *len) == 0) {
95233965Sjdp			*dow = fdays[i];
95333965Sjdp			*offset = i;
95433965Sjdp			return (1);
95533965Sjdp		}
95633965Sjdp	}
95733965Sjdp	for (i = 0; days[i] != NULL; i++) {
95833965Sjdp		if (strncasecmp(s, days[i], 3) == 0) {
95933965Sjdp			*len = 3;
96033965Sjdp			*dow = days[i];
96133965Sjdp			*offset = i;
96233965Sjdp			return (1);
96333965Sjdp		}
96433965Sjdp	}
96533965Sjdp	return (0);
96633965Sjdp}
96733965Sjdp
96833965Sjdpstatic int
96933965Sjdpisonlydigits(char *s, int nostar)
97033965Sjdp{
97133965Sjdp	int i;
97261843Sobrien	for (i = 0; s[i] != '\0'; i++) {
97333965Sjdp		if (nostar == 0 && s[i] == '*' && s[i + 1] == '\0')
97461843Sobrien			return 1;
97561843Sobrien		if (!isdigit((unsigned char)s[i]))
97661843Sobrien			return (0);
97761843Sobrien	}
97861843Sobrien	return (1);
97961843Sobrien}
98061843Sobrien
98161843Sobrienstatic int
98233965Sjdpindextooffset(char *s)
98361843Sobrien{
98433965Sjdp	int i;
98533965Sjdp	struct fixs *n;
98633965Sjdp	char *es;
98733965Sjdp
98833965Sjdp	if (s[0] == '+' || s[0] == '-') {
98933965Sjdp		i = strtol (s, &es, 10);
99033965Sjdp		if (*es != '\0')                      /* trailing junk */
99133965Sjdp			errx (1, "Invalid specifier format: %s\n", s);
99233965Sjdp		return (i);
99333965Sjdp	}
99433965Sjdp
99533965Sjdp	for (i = 0; i < 6; i++) {
99633965Sjdp		if (strcasecmp(s, sequences[i]) == 0) {
99733965Sjdp			if (i == 5)
99833965Sjdp				return (-1);
99933965Sjdp			return (i + 1);
100033965Sjdp		}
100133965Sjdp	}
100233965Sjdp	for (i = 0; i < 6; i++) {
100333965Sjdp		n = nsequences + i;
100433965Sjdp		if (n->len == 0)
100533965Sjdp			continue;
100633965Sjdp		if (strncasecmp(s, n->name, n->len) == 0) {
100760484Sobrien			if (i == 5)
100860484Sobrien				return (-1);
100933965Sjdp			return (i + 1);
101033965Sjdp		}
101133965Sjdp	}
101233965Sjdp	return (0);
101333965Sjdp}
101460484Sobrien
101560484Sobrienstatic int
101633965Sjdpparseoffset(char *s)
101733965Sjdp{
101833965Sjdp	return strtol(s, NULL, 10);
101933965Sjdp}
102033965Sjdp
102133965Sjdpstatic char *
102233965Sjdpfloattotime(double f)
102333965Sjdp{
102433965Sjdp	static char buf[100];
102533965Sjdp	int hh, mm, ss, i;
102633965Sjdp
102733965Sjdp	f -= floor(f);
102833965Sjdp	i = f * SECSPERDAY;
102933965Sjdp
103033965Sjdp	hh = i / SECSPERHOUR;
103133965Sjdp	i %= SECSPERHOUR;
103233965Sjdp	mm = i / SECSPERMINUTE;
103333965Sjdp	i %= SECSPERMINUTE;
103433965Sjdp	ss = i;
103533965Sjdp
103633965Sjdp	sprintf(buf, "%02d:%02d:%02d", hh, mm, ss);
103733965Sjdp	return (buf);
103833965Sjdp}
103933965Sjdp
104033965Sjdpstatic char *
104133965Sjdpfloattoday(int year, double f)
104233965Sjdp{
104333965Sjdp	static char buf[100];
104433965Sjdp	int i, m, d, hh, mm, ss;
104533965Sjdp	int *cumdays = cumdaytab[isleap(year)];
104633965Sjdp
104733965Sjdp	for (i = 0; 1 + cumdays[i] < f; i++)
104833965Sjdp		;
104933965Sjdp	m = --i;
105033965Sjdp	d = floor(f - 1 - cumdays[i]);
105133965Sjdp	f -= floor(f);
105233965Sjdp	i = f * SECSPERDAY;
105333965Sjdp
105433965Sjdp	hh = i / SECSPERHOUR;
105533965Sjdp	i %= SECSPERHOUR;
105633965Sjdp	mm = i / SECSPERMINUTE;
105733965Sjdp	i %= SECSPERMINUTE;
105833965Sjdp	ss = i;
105933965Sjdp
106033965Sjdp	sprintf(buf, "%02d-%02d %02d:%02d:%02d", m, d, hh, mm, ss);
106133965Sjdp	return (buf);
106233965Sjdp}
106333965Sjdp
106433965Sjdpvoid
106533965Sjdpdodebug(char *what)
106633965Sjdp{
106733965Sjdp	int year;
106833965Sjdp
106933965Sjdp	printf("UTCOffset: %g\n", UTCOffset);
107033965Sjdp	printf("eastlongitude: %d\n", EastLongitude);
107133965Sjdp
107233965Sjdp	if (strcmp(what, "moon") == 0) {
107333965Sjdp		double ffullmoon[MAXMOONS], fnewmoon[MAXMOONS];
107433965Sjdp		int i;
107533965Sjdp
107633965Sjdp		for (year = year1; year <= year2; year++) {
107733965Sjdp			fpom(year, UTCOffset, ffullmoon, fnewmoon);
107833965Sjdp			printf("Full moon %d:\t", year);
107933965Sjdp			for (i = 0; ffullmoon[i] >= 0; i++) {
108033965Sjdp				printf("%g (%s) ", ffullmoon[i],
108133965Sjdp				    floattoday(year, ffullmoon[i]));
108233965Sjdp			}
108333965Sjdp			printf("\nNew moon %d:\t", year);
108433965Sjdp			for (i = 0; fnewmoon[i] >= 0; i++) {
108533965Sjdp				printf("%g (%s) ", fnewmoon[i],
108633965Sjdp				    floattoday(year, fnewmoon[i]));
108733965Sjdp			}
108833965Sjdp			printf("\n");
108933965Sjdp
109033965Sjdp		}
109133965Sjdp
109233965Sjdp		return;
109333965Sjdp	}
109433965Sjdp
109533965Sjdp	if (strcmp(what, "sun") == 0) {
109633965Sjdp		double equinoxdays[2], solsticedays[2];
109733965Sjdp		for (year = year1; year <= year2; year++) {
109833965Sjdp			printf("Sun in %d:\n", year);
109933965Sjdp			fequinoxsolstice(year, UTCOffset, equinoxdays,
110033965Sjdp			    solsticedays);
110133965Sjdp			printf("e[0] - %g (%s)\n",
110233965Sjdp			    equinoxdays[0],
110333965Sjdp			    floattoday(year, equinoxdays[0]));
110433965Sjdp			printf("e[1] - %g (%s)\n",
110533965Sjdp			    equinoxdays[1],
110633965Sjdp			    floattoday(year, equinoxdays[1]));
110733965Sjdp			printf("s[0] - %g (%s)\n",
110833965Sjdp			    solsticedays[0],
110933965Sjdp			    floattoday(year, solsticedays[0]));
111033965Sjdp			printf("s[1] - %g (%s)\n",
111133965Sjdp			    solsticedays[1],
111233965Sjdp			    floattoday(year, solsticedays[1]));
111333965Sjdp		}
111433965Sjdp		return;
111533965Sjdp	}
111660484Sobrien}
111760484Sobrien