From 914d5a5c2da11a9119f44c4469b7820a3471ddbb Mon Sep 17 00:00:00 2001 From: edwin Date: Mon, 29 Mar 2010 06:49:20 +0000 Subject: Long awaited update to the calendar system: - Repeating events which span multiple years (because of -A, -B or just the three days before the end of the year). - Support for lunar events (full moon, new moon) and solar events (equinox and solstice, chinese new year). Because of this, the options -U (UTC offset) and -l (longitude) are available to compensate if reality doesn't match the calculated values. MFC after: 1 month --- usr.bin/calendar/Makefile | 4 +- usr.bin/calendar/calendar.1 | 82 +++- usr.bin/calendar/calendar.c | 106 ++++- usr.bin/calendar/calendar.h | 178 ++++++-- usr.bin/calendar/dates.c | 451 +++++++++++++++++++ usr.bin/calendar/day.c | 412 +---------------- usr.bin/calendar/events.c | 125 ++++++ usr.bin/calendar/io.c | 368 +++++---------- usr.bin/calendar/locale.c | 168 +++++++ usr.bin/calendar/ostern.c | 46 +- usr.bin/calendar/parsedata.c | 1008 ++++++++++++++++++++++++++++++++++++++++++ usr.bin/calendar/paskha.c | 43 +- usr.bin/calendar/pathnames.h | 2 +- usr.bin/calendar/pom.c | 280 ++++++++++++ usr.bin/calendar/sunpos.c | 447 +++++++++++++++++++ 15 files changed, 2928 insertions(+), 792 deletions(-) create mode 100644 usr.bin/calendar/dates.c create mode 100644 usr.bin/calendar/events.c create mode 100644 usr.bin/calendar/locale.c create mode 100644 usr.bin/calendar/parsedata.c create mode 100644 usr.bin/calendar/pom.c create mode 100644 usr.bin/calendar/sunpos.c (limited to 'usr.bin') diff --git a/usr.bin/calendar/Makefile b/usr.bin/calendar/Makefile index 27df8b6..d135805 100644 --- a/usr.bin/calendar/Makefile +++ b/usr.bin/calendar/Makefile @@ -2,7 +2,9 @@ # $FreeBSD$ PROG= calendar -SRCS= calendar.c io.c day.c ostern.c paskha.c +SRCS= calendar.c locale.c events.c dates.c parsedata.c io.c day.c \ + ostern.c paskha.c pom.c sunpos.c +LDADD= -lm INTER= de_AT.ISO_8859-15 de_DE.ISO8859-1 fr_FR.ISO8859-1 \ hr_HR.ISO8859-2 hu_HU.ISO8859-2 ru_RU.KOI8-R uk_UA.KOI8-U DE_LINKS= de_DE.ISO8859-15 diff --git a/usr.bin/calendar/calendar.1 b/usr.bin/calendar/calendar.1 index 404f44c..28c8bbb 100644 --- a/usr.bin/calendar/calendar.1 +++ b/usr.bin/calendar/calendar.1 @@ -54,6 +54,8 @@ .Ek .Oc .Op Fl W Ar num +.Op Fl U Ar UTC-offset +.Op Fl l Ar longitude .Sh DESCRIPTION The .Nm @@ -93,6 +95,12 @@ as the default calendar file. .Sm on .Xc For test purposes only: set date directly to argument values. +.It Fl l Ar longitude , Fl U Ar UTC-offset +Only one is needed: +Perform lunar and solar calculations from this longitude or from +this UTC offset. +If neither is specified, the calculations will be based on the +difference between UTC time and localtime. .It Fl W Ar num Print lines from today and the next .Ar num @@ -103,12 +111,36 @@ Ignore weekends when calculating the number of days. To handle calendars in your national code table you can specify .Dq LANG= in the calendar file as early as possible. -To handle national Easter -names in the calendars -.Dq Easter= -(for Catholic Easter) or -.Dq Paskha= -(for Orthodox Easter) can be used. +.Pp +To handle the local name of sequences, you can specify them as: +.Dq SEQUENCE= +in the calendar file as early as possible. +.Pp +The names of the following special days are recognized: +.Bl -tag -width 123456789012345 -compact +.It Easter +Catholic Easter. +.It Paskha +Orthodox Easter. +.It NewMoon +The lunar New Moon. +.It FullMoon +The lunar Full Moon. +.It MarEquinox +The solar equinox in March. +.It JunSolstice +The solar solstice in June. +.It SepEquinox +The solar equinox in March. +.It DecSolstice +The solar solstice in December. +.It ChineseNewYear +The first day of the Chinese year. +.El +These names may be reassigned to their local names via an assignment +like +.Dq Easter=Pasen +in the calendar file. .Pp Other lines should begin with a month and day. They may be entered in almost any format, either numeric or as character @@ -122,11 +154,11 @@ Two numbers default to the month followed by the day. Lines with leading tabs default to the last entered date, allowing multiple line specifications for a single date. .Pp -``Easter'', is Easter for this year, and may be followed by a positive -or negative integer. -.Pp -``Paskha'', is Orthodox Easter for this year, and may be followed by a -positive or negative integer. +The names of the recognized special days may be followed by a +positive or negative integer, like: +.Dq Easter+3 +or +.Dq Pashka-4 . .Pp Weekdays may be followed by ``-4'' ...\& ``+5'' (aliases for last, first, second, third, fourth) for moving events like @@ -191,7 +223,8 @@ calendar file to use if no calendar file exists in the current directory. do not send mail if this file exists. .El .Pp -The following default calendar files are provided: +The following default calendar files are provided in +.Pa /usr/share/calendars: .Pp .Bl -tag -width calendar.southafrica -compact .It Pa calendar.all @@ -208,6 +241,8 @@ so that roving holidays are set correctly for the current year. Days of special significance to computer people. .It Pa calendar.croatian Calendar of events in Croatia. +.It Pa calendar.dutch +Calendar of events in the Netherlands. .It Pa calendar.freebsd Birthdays of .Fx @@ -259,7 +294,28 @@ A .Nm command appeared in .At v7 . +.Sh NOTES +Chinese New Year is calculated at 120 degrees east of Greenwich, +which roughly corresponds with the east coast of China. +For people west of China, this might result that the start of Chinese +New Year and the day of the related new moon might differ. +.Pp +The phases of the moon and the longitude of the sun are calculated +against the local position which corresponds with 30 degrees times +the time-difference towards Greenwich. +.Pp +The new and full moons are happening on the day indicated: They +might happen in the time period in the early night or in the late +evening. +It doesn't indicate that they are starting in the night on that date. +.Pp +Because of minor differences between the output of the formulas +used and other sources on the Internet, Druids and Werewolves should +double-check the start and end time of solar and lunar events. .Sh BUGS The .Nm -utility does not handle Jewish holidays and moon phases. +utility does not handle Jewish holidays. +.Pp +There is no possibility to properly specify the local position +needed for solar and lunar calculations. diff --git a/usr.bin/calendar/calendar.c b/usr.bin/calendar/calendar.c index 39f2c9c..f5b5e94 100644 --- a/usr.bin/calendar/calendar.c +++ b/usr.bin/calendar/calendar.c @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -52,29 +52,38 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include "calendar.h" +#define UTCOFFSET_NOTSET 100 /* Expected between -24 and +24 */ +#define LONGITUDE_NOTSET 1000 /* Expected between -360 and +360 */ + struct passwd *pw; int doall = 0; +int debug = 0; +char *DEBUG = NULL; time_t f_time = 0; - -int f_dayAfter = 0; /* days after current date */ -int f_dayBefore = 0; /* days before current date */ -int Friday = 5; /* day before weekend */ +double UTCOffset = UTCOFFSET_NOTSET; +int EastLongitude = LONGITUDE_NOTSET; static void usage(void) __dead2; int main(int argc, char *argv[]) { + int f_dayAfter = 0; /* days after current date */ + int f_dayBefore = 0; /* days before current date */ + int Friday = 5; /* day before weekend */ + int ch; + struct tm tp1, tp2; (void)setlocale(LC_ALL, ""); - while ((ch = getopt(argc, argv, "-A:aB:F:f:t:W:")) != -1) + while ((ch = getopt(argc, argv, "-A:aB:dD:F:f:l:t:U:W:")) != -1) switch (ch) { case '-': /* backward contemptible */ case 'a': @@ -89,14 +98,10 @@ main(int argc, char *argv[]) calendarFile = optarg; break; - case 't': /* other date, undocumented, for tests */ - f_time = Mktime(optarg); - break; - case 'W': /* we don't need no steenking Fridays */ Friday = -1; - /* FALLTHROUGH */ + case 'A': /* days after current date */ f_dayAfter = atoi(optarg); break; @@ -105,9 +110,25 @@ main(int argc, char *argv[]) f_dayBefore = atoi(optarg); break; - case 'F': + case 'F': /* Change the time: When does weekend start? */ Friday = atoi(optarg); break; + case 'l': /* Change longitudal position */ + EastLongitude = strtol(optarg, NULL, 10); + break; + case 'U': /* Change UTC offset */ + UTCOffset = strtod(optarg, NULL); + break; + + case 'd': + debug = 1; + break; + case 'D': + DEBUG = optarg; + break; + case 't': /* other date, undocumented, for tests */ + f_time = Mktime(optarg); + break; case '?': default: @@ -124,7 +145,60 @@ main(int argc, char *argv[]) if (f_time <= 0) (void)time(&f_time); - settime(f_time); + /* if not set, determine where I could be */ + { + if (UTCOffset == UTCOFFSET_NOTSET && + EastLongitude == LONGITUDE_NOTSET) { + /* Calculate on difference between here and UTC */ + time_t t; + struct tm tm; + long utcoffset, hh, mm, ss; + double uo; + + time(&t); + localtime_r(&t, &tm); + utcoffset = tm.tm_gmtoff; + /* seconds -> hh:mm:ss */ + hh = utcoffset / SECSPERHOUR; + utcoffset %= SECSPERHOUR; + mm = utcoffset / SECSPERMINUTE; + utcoffset %= SECSPERMINUTE; + ss = utcoffset; + + /* hh:mm:ss -> hh.mmss */ + uo = mm + (100.0 * (ss / 60.0)); + uo /= 60.0 / 100.0; + uo = hh + uo / 100; + + UTCOffset = uo; + EastLongitude = UTCOffset * 15; + } else if (UTCOffset == UTCOFFSET_NOTSET) { + /* Base on information given */ + UTCOffset = EastLongitude / 15; + } else if (EastLongitude == LONGITUDE_NOTSET) { + /* Base on information given */ + EastLongitude = UTCOffset * 15; + } + } + + settimes(f_time, f_dayBefore, f_dayAfter, Friday, &tp1, &tp2); + generatedates(&tp1, &tp2); + + /* + * FROM now on, we are working in UTC. + * This will only affect moon and sun related events anyway. + */ + if (setenv("TZ", "UTC", 1) != 0) + errx(1, "setenv: %s", strerror(errno)); + tzset(); + + if (debug) + dumpdates(); + + if (DEBUG != NULL) { + dodebug(DEBUG); + exit(0); + } if (doall) while ((pw = getpwent()) != NULL) { @@ -145,9 +219,11 @@ static void __dead2 usage(void) { - fprintf(stderr, "%s\n%s\n", + fprintf(stderr, "%s\n%s\n%s\n", "usage: calendar [-a] [-A days] [-B days] [-F friday] " "[-f calendarfile]", - " [-t dd[.mm[.year]]] [-W days]"); + " [-d] [-t dd[.mm[.year]]] [-W days]", + " [-U utcoffset] [-l longitude]" + ); exit(1); } diff --git a/usr.bin/calendar/calendar.h b/usr.bin/calendar/calendar.h index ff67ca6..722c241 100644 --- a/usr.bin/calendar/calendar.h +++ b/usr.bin/calendar/calendar.h @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -36,43 +36,163 @@ #include #include +#define SECSPERDAY (24 * 60 * 60) +#define SECSPERHOUR (60 * 60) +#define SECSPERMINUTE (60) +#define MINSPERHOUR (60) +#define HOURSPERDAY (24) +#define FSECSPERDAY (24.0 * 60.0 * 60.0) +#define FSECSPERHOUR (60.0 * 60.0) +#define FSECSPERMINUTE (60.0) +#define FMINSPERHOUR (60.0) +#define FHOURSPERDAY (24.0) + +#define DAYSPERYEAR 365 +#define DAYSPERLEAPYEAR 366 + +/* Not yet categorized */ + extern struct passwd *pw; extern int doall; -extern struct iovec header[]; -extern struct tm *tp; +extern time_t t1, t2; extern const char *calendarFile; -extern int *cumdays; extern int yrdays; -extern struct fixs neaster, npaskha; - -void cal(void); -void closecal(FILE *); -int getday(char *); -int getdayvar(char *); -int getfield(char *, char **, int *); -int getmonth(char *); -int geteaster(char *, int); -int getpaskha(char *, int); -int easter(int); -int isnow(char *, int *, int *, int *); -FILE *opencal(void); -void settime(time_t); -time_t Mktime(char *); -void setnnames(void); +extern struct fixs neaster, npaskha, ncny, nfullmoon, nnewmoon; +extern struct fixs nmarequinox, nsepequinox, njunsolstice, ndecsolstice; +extern double UTCOffset; +extern int EastLongitude; #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) -/* some flags */ -#define F_ISMONTH 0x01 /* month (January ...) */ -#define F_ISDAY 0x02 /* day of week (Sun, Mon, ...) */ -#define F_ISDAYVAR 0x04 /* variables day of week, like SundayLast */ -#define F_EASTER 0x08 /* Easter or easter depending days */ +/* Flags to determine the returned values by determinestyle() in parsedata.c */ +#define F_NONE 0x00000 +#define F_MONTH 0x00001 +#define F_DAYOFWEEK 0x00002 +#define F_DAYOFMONTH 0x00004 +#define F_MODIFIERINDEX 0x00008 +#define F_MODIFIEROFFSET 0x00010 +#define F_SPECIALDAY 0x00020 +#define F_ALLMONTH 0x00040 +#define F_ALLDAY 0x00080 +#define F_VARIABLE 0x00100 +#define F_EASTER 0x00200 +#define F_CNY 0x00400 +#define F_PASKHA 0x00800 +#define F_NEWMOON 0x01000 +#define F_FULLMOON 0x02000 +#define F_MAREQUINOX 0x04000 +#define F_SEPEQUINOX 0x08000 +#define F_JUNSOLSTICE 0x10000 +#define F_DECSOLSTICE 0x20000 + +#define STRING_EASTER "Easter" +#define STRING_PASKHA "Paskha" +#define STRING_CNY "ChineseNewYear" +#define STRING_NEWMOON "NewMoon" +#define STRING_FULLMOON "FullMoon" +#define STRING_MAREQUINOX "MarEquinox" +#define STRING_SEPEQUINOX "SepEquinox" +#define STRING_JUNSOLSTICE "JunSolstice" +#define STRING_DECSOLSTICE "DecSolstice" -extern int f_dayAfter; /* days after current date */ -extern int f_dayBefore; /* days before current date */ -extern int Friday; /* day before weekend */ +#define MAXCOUNT 125 /* Random number of maximum number of + * repeats of an event. Should be 52 + * (number of weeks per year), if you + * want to show two years then it + * should be 104. If you are seeing + * more than this you are using this + * program wrong. + */ + +/* + * All the astronomical calculations are carried out for the meridian 120 + * degrees east of Greenwich. + */ +#define UTCOFFSET_CNY 8.0 + +extern int debug; /* show parsing of the input */ +extern int year1, year2; + +/* events.c */ +/* + * Event sorting related functions: + * - Use event_add() to create a new event + * - Use event_continue() to add more text to the last added event + * - Use event_print_all() to display them in time chronological order + */ +struct event *event_add(int, int, int, char *, int, char *, char *); +void event_continue(struct event *events, char *txt); +void event_print_all(FILE *fp); +struct event { + int year; + int month; + int day; + int var; + char *date; + char *text; + char *extra; + struct event *next; +}; + +/* locale.c */ struct fixs { char *name; - int len; + size_t len; }; + +extern const char *days[]; +extern const char *fdays[]; +extern const char *fmonths[]; +extern const char *months[]; +extern const char *sequences[]; +extern struct fixs fndays[8]; /* full national days names */ +extern struct fixs fnmonths[13]; /* full national months names */ +extern struct fixs ndays[8]; /* short national days names */ +extern struct fixs nmonths[13]; /* short national month names */ +extern struct fixs nsequences[10]; + +void setnnames(void); +void setnsequences(char *); + +/* day.c */ +extern const struct tm tm0; +extern char dayname[]; +void settimes(time_t,int before, int after, int friday, struct tm *tp1, struct tm *tp2); +time_t Mktime(char *); + +/* parsedata.c */ +int parsedaymonth(char *, int *, int *, int *, int *, char **); +void dodebug(char *type); + +/* io.c */ +void cal(void); +void closecal(FILE *); +FILE *opencal(void); + +/* ostern.c / pashka.c */ +int paskha(int); +int easter(int); + +/* dates.c */ +extern int cumdaytab[][14]; +extern int mondaytab[][14]; +extern int debug_remember; +void generatedates(struct tm *tp1, struct tm *tp2); +void dumpdates(void); +int remember_ymd(int y, int m, int d); +int remember_yd(int y, int d, int *rm, int *rd); +int first_dayofweek_of_year(int y); +int first_dayofweek_of_month(int y, int m); +int walkthrough_dates(struct event **e); +void addtodate(struct event *e, int year, int month, int day); + +/* pom.c */ +#define MAXMOONS 18 +void pom(int year, double UTCoffset, int *fms, int *nms); +void fpom(int year, double utcoffset, double *ffms, double *fnms); + +/* sunpos.c */ +void equinoxsolstice(int year, double UTCoffset, int *equinoxdays, int *solsticedays); +void fequinoxsolstice(int year, double UTCoffset, double *equinoxdays, double *solsticedays); +int calculatesunlongitude30(int year, int degreeGMToffset, int *ichinesemonths); diff --git a/usr.bin/calendar/dates.c b/usr.bin/calendar/dates.c new file mode 100644 index 0000000..69f8514 --- /dev/null +++ b/usr.bin/calendar/dates.c @@ -0,0 +1,451 @@ +/*- + * Copyright (c) 1992-2009 Edwin Groothuis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include "calendar.h" + +struct cal_year { + int year; /* 19xx, 20xx, 21xx */ + int easter; /* Julian day */ + int paskha; /* Julian day */ + int cny; /* Julian day */ + int firstdayofweek; /* 0 .. 6 */ + struct cal_month *months; + struct cal_year *nextyear; +} cal_year; + +struct cal_month { + int month; /* 01 .. 12 */ + int firstdayjulian; /* 000 .. 366 */ + int firstdayofweek; /* 0 .. 6 */ + struct cal_year *year; /* points back */ + struct cal_day *days; + struct cal_month *nextmonth; +} cal_month; + +struct cal_day { + int dayofmonth; /* 01 .. 31 */ + int julianday; /* 000 .. 366 */ + int dayofweek; /* 0 .. 6 */ + struct cal_day *nextday; + struct cal_month *month; /* points back */ + struct cal_year *year; /* points back */ + struct event *events; +} cal_day; + +int debug_remember = 0; +struct cal_year *hyear = NULL; + +/* 1-based month, 0-based days, cumulative */ +int *cumdays; +int cumdaytab[][14] = { + {0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364}, + {0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, +}; +/* 1-based month, individual */ +int *mondays; +int mondaytab[][14] = { + {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30}, + {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 30}, +}; + +static struct cal_day * find_day(int yy, int mm, int dd); + +static void +createdate(int y, int m, int d) +{ + struct cal_year *py, *pyp; + struct cal_month *pm, *pmp; + struct cal_day *pd, *pdp; + int *cumday; + + pyp = NULL; + py = hyear; + while (py != NULL) { + if (py->year == y + 1900) + break; + pyp = py; + py = py->nextyear; + } + + if (py == NULL) { + struct tm td; + time_t t; + py = (struct cal_year *)calloc(1, sizeof(struct cal_year)); + py->year = y + 1900; + py->easter = easter(y); + py->paskha = paskha(y); + + td = tm0; + td.tm_year = y; + td.tm_mday = 1; + t = mktime(&td); + localtime_r(&t, &td); + py->firstdayofweek = td.tm_wday; + + if (pyp != NULL) + pyp->nextyear = py; + } + if (pyp == NULL) { + /* The very very very first one */ + hyear = py; + } + + pmp = NULL; + pm = py->months; + while (pm != NULL) { + if (pm->month == m) + break; + pmp = pm; + pm = pm->nextmonth; + } + + if (pm == NULL) { + pm = (struct cal_month *)calloc(1, sizeof(struct cal_month)); + pm->year = py; + pm->month = m; + cumday = cumdaytab[isleap(y)]; + pm->firstdayjulian = cumday[m] + 2; + pm->firstdayofweek = + (py->firstdayofweek + pm->firstdayjulian -1) % 7; + if (pmp != NULL) + pmp->nextmonth = pm; + } + if (pmp == NULL) + py->months = pm; + + pdp = NULL; + pd = pm->days; + while (pd != NULL) { + pdp = pd; + pd = pd->nextday; + } + + if (pd == NULL) { /* Always true */ + pd = (struct cal_day *)calloc(1, sizeof(struct cal_day)); + pd->month = pm; + pd->year = py; + pd->dayofmonth = d; + pd->julianday = pm->firstdayjulian + d - 1; + pd->dayofweek = (pm->firstdayofweek + d - 1) % 7; + if (pdp != NULL) + pdp->nextday = pd; + } + if (pdp == NULL) + pm->days = pd; +} + +void +generatedates(struct tm *tp1, struct tm *tp2) +{ + int y1, m1, d1; + int y2, m2, d2; + int y, m, d; + + y1 = tp1->tm_year; + m1 = tp1->tm_mon + 1; + d1 = tp1->tm_mday; + y2 = tp2->tm_year; + m2 = tp2->tm_mon + 1; + d2 = tp2->tm_mday; + + if (y1 == y2) { + if (m1 == m2) { + /* Same year, same month. Easy! */ + for (d = d1; d <= d2; d++) + createdate(y1, m1, d); + return; + } + /* + * Same year, different month. + * - Take the leftover days from m1 + * - Take all days from + * - Take the first days from m2 + */ + mondays = mondaytab[isleap(y1)]; + for (d = d1; d <= mondays[m1]; d++) + createdate(y1, m1, d); + for (m = m1 + 1; m < m2; m++) + for (d = 1; d <= mondays[m]; d++) + createdate(y1, m, d); + for (d = 1; d <= d2; d++) + createdate(y1, m2, d); + return; + } + /* + * Different year, different month. + * - Take the leftover days from y1-m1 + * - Take all days from y1- + * - Take all days from y2-[1 .. m2> + * - Take the first days of y2-m2 + */ + mondays = mondaytab[isleap(y1)]; + for (d = d1; d <= mondays[m1]; d++) + createdate(y1, m1, d); + for (m = m1 + 1; m <= 12; m++) + for (d = 1; d <= mondays[m]; d++) + createdate(y1, m, d); + for (y = y1 + 1; y < y2; y++) { + mondays = mondaytab[isleap(y)]; + for (m = 1; m <= 12; m++) + for (d = 1; d <= mondays[m]; d++) + createdate(y, m, d); + } + mondays = mondaytab[isleap(y2)]; + for (m = 1; m < m2; m++) + for (d = 1; d <= mondays[m]; d++) + createdate(y2, m, d); + for (d = 1; d <= d2; d++) + createdate(y2, m2, d); +} + +void +dumpdates(void) +{ + struct cal_year *y; + struct cal_month *m; + struct cal_day *d; + + y = hyear; + while (y != NULL) { + printf("%-5d (wday:%d)\n", y->year, y->firstdayofweek); + m = y->months; + while (m != NULL) { + printf("-- %-5d (julian:%d, dow:%d)\n", m->month, + m->firstdayjulian, m->firstdayofweek); + d = m->days; + while (d != NULL) { + printf(" -- %-5d (julian:%d, dow:%d)\n", + d->dayofmonth, d->julianday, d->dayofweek); + d = d->nextday; + } + m = m->nextmonth; + } + y = y->nextyear; + } +} + +int +remember_ymd(int yy, int mm, int dd) +{ + struct cal_year *y; + struct cal_month *m; + struct cal_day *d; + + if (debug_remember) + printf("remember_ymd: %d - %d - %d\n", yy, mm, dd); + + y = hyear; + while (y != NULL) { + if (y->year != yy) { + y = y->nextyear; + continue; + } + m = y->months; + while (m != NULL) { + if (m->month != mm) { + m = m->nextmonth; + continue; + } + d = m->days; + while (d != NULL) { + if (d->dayofmonth == dd) + return (1); + d = d->nextday; + continue; + } + return (0); + } + return (0); + } + return (0); +} + +int +remember_yd(int yy, int dd, int *rm, int *rd) +{ + struct cal_year *y; + struct cal_month *m; + struct cal_day *d; + + if (debug_remember) + printf("remember_yd: %d - %d\n", yy, dd); + + y = hyear; + while (y != NULL) { + if (y->year != yy) { + y = y->nextyear; + continue; + } + m = y->months; + while (m != NULL) { + d = m->days; + while (d != NULL) { + if (d->julianday == dd) { + *rm = m->month; + *rd = d->dayofmonth; + return (1); + } + d = d->nextday; + } + m = m->nextmonth; + } + return (0); + } + return (0); +} + +int +first_dayofweek_of_year(int yy) +{ + struct cal_year *y; + + y = hyear; + while (y != NULL) { + if (y->year == yy) + return (y->firstdayofweek); + y = y->nextyear; + } + + /* Should not happen */ + return (-1); +} + +int +first_dayofweek_of_month(int yy, int mm) +{ + struct cal_year *y; + struct cal_month *m; + + y = hyear; + while (y != NULL) { + if (y->year != yy) { + y = y->nextyear; + continue; + } + m = y->months; + while (m != NULL) { + if (m->month == mm) + return (m->firstdayofweek); + m = m->nextmonth; + } + /* Should not happen */ + return (-1); + } + + /* Should not happen */ + return (-1); +} + +int +walkthrough_dates(struct event **e) +{ + static struct cal_year *y = NULL; + static struct cal_month *m = NULL; + static struct cal_day *d = NULL; + + if (y == NULL) { + y = hyear; + m = y->months; + d = m->days; + *e = d->events; + return (1); + }; + if (d->nextday != NULL) { + d = d->nextday; + *e = d->events; + return (1); + } + if (m->nextmonth != NULL) { + m = m->nextmonth; + d = m->days; + *e = d->events; + return (1); + } + if (y->nextyear != NULL) { + y = y->nextyear; + m = y->months; + d = m->days; + *e = d->events; + return (1); + } + + return (0); +} + +static struct cal_day * +find_day(int yy, int mm, int dd) +{ + struct cal_year *y; + struct cal_month *m; + struct cal_day *d; + + if (debug_remember) + printf("remember_ymd: %d - %d - %d\n", yy, mm, dd); + + y = hyear; + while (y != NULL) { + if (y->year != yy) { + y = y->nextyear; + continue; + } + m = y->months; + while (m != NULL) { + if (m->month != mm) { + m = m->nextmonth; + continue; + } + d = m->days; + while (d != NULL) { + if (d->dayofmonth == dd) + return (d); + d = d->nextday; + continue; + } + return (NULL); + } + return (NULL); + } + return (NULL); +} + +void +addtodate(struct event *e, int year, int month, int day) +{ + struct cal_day *d; + + d = find_day(year, month, day); + e->next = d->events; + d->events = e; +} diff --git a/usr.bin/calendar/day.c b/usr.bin/calendar/day.c index e40481e..6625290 100644 --- a/usr.bin/calendar/day.c +++ b/usr.bin/calendar/day.c @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -34,9 +34,6 @@ #include __FBSDID("$FreeBSD$"); -#include -#include -#include #include #include #include @@ -46,120 +43,38 @@ __FBSDID("$FreeBSD$"); #include "calendar.h" -struct tm *tp; -static const struct tm tm0; -int *cumdays, yrdays; -char dayname[10]; - - -/* 1-based month, 0-based days, cumulative */ -int daytab[][14] = { - {0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364}, - {0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, -}; - -static char const *days[] = { - "sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL, -}; - -static const char *months[] = { - "jan", "feb", "mar", "apr", "may", "jun", - "jul", "aug", "sep", "oct", "nov", "dec", NULL, -}; - -static struct fixs fndays[8]; /* full national days names */ -static struct fixs ndays[8]; /* short national days names */ - -static struct fixs fnmonths[13]; /* full national months names */ -static struct fixs nmonths[13]; /* short national month names */ +time_t time1, time2; +const struct tm tm0; +char dayname[100]; +int year1, year2; void -setnnames(void) +settimes(time_t now, int before, int after, int friday, struct tm *tp1, struct tm *tp2) { - char buf[80]; - int i, l; - struct tm tm; - - for (i = 0; i < 7; i++) { - tm.tm_wday = i; - strftime(buf, sizeof(buf), "%a", &tm); - for (l = strlen(buf); - l > 0 && isspace((unsigned char)buf[l - 1]); - l--) - ; - buf[l] = '\0'; - if (ndays[i].name != NULL) - free(ndays[i].name); - if ((ndays[i].name = strdup(buf)) == NULL) - errx(1, "cannot allocate memory"); - ndays[i].len = strlen(buf); - - strftime(buf, sizeof(buf), "%A", &tm); - for (l = strlen(buf); - l > 0 && isspace((unsigned char)buf[l - 1]); - l--) - ; - buf[l] = '\0'; - if (fndays[i].name != NULL) - free(fndays[i].name); - if ((fndays[i].name = strdup(buf)) == NULL) - errx(1, "cannot allocate memory"); - fndays[i].len = strlen(buf); - } + char *oldl, *lbufp; + struct tm tp; - for (i = 0; i < 12; i++) { - tm.tm_mon = i; - strftime(buf, sizeof(buf), "%b", &tm); - for (l = strlen(buf); - l > 0 && isspace((unsigned char)buf[l - 1]); - l--) - ; - buf[l] = '\0'; - if (nmonths[i].name != NULL) - free(nmonths[i].name); - if ((nmonths[i].name = strdup(buf)) == NULL) - errx(1, "cannot allocate memory"); - nmonths[i].len = strlen(buf); + localtime_r(&now, &tp); - strftime(buf, sizeof(buf), "%B", &tm); - for (l = strlen(buf); - l > 0 && isspace((unsigned char)buf[l - 1]); - l--) - ; - buf[l] = '\0'; - if (fnmonths[i].name != NULL) - free(fnmonths[i].name); - if ((fnmonths[i].name = strdup(buf)) == NULL) - errx(1, "cannot allocate memory"); - fnmonths[i].len = strlen(buf); - } -} + /* Friday displays Monday's events */ + if (after == 0 && before == 0 && friday != -1) + after = tp.tm_wday == friday ? 3 : 1; -void -settime(time_t now) -{ - char *oldl, *lbufp; + time1 = now - SECSPERDAY * before; + localtime_r(&time1, tp1); + year1 = 1900 + tp1->tm_year; + time2 = now + SECSPERDAY * after; + localtime_r(&time2, tp2); + year2 = 1900 + tp2->tm_year; - tp = localtime(&now); - if (isleap(tp->tm_year + 1900)) { - yrdays = 366; - cumdays = daytab[1]; - } else { - yrdays = 365; - cumdays = daytab[0]; - } - /* Friday displays Monday's events */ - if (f_dayAfter == 0 && f_dayBefore == 0 && Friday != -1) - f_dayAfter = tp->tm_wday == Friday ? 3 : 1; - header[5].iov_base = dayname; + strftime(dayname, sizeof(dayname) - 1, "%A, %d %B %Y", tp1); oldl = NULL; lbufp = setlocale(LC_TIME, NULL); if (lbufp != NULL && (oldl = strdup(lbufp)) == NULL) errx(1, "cannot allocate memory"); (void)setlocale(LC_TIME, "C"); - header[5].iov_len = strftime(dayname, sizeof(dayname), "%A", tp); (void)setlocale(LC_TIME, (oldl != NULL ? oldl : "")); if (oldl != NULL) free(oldl); @@ -175,15 +90,15 @@ Mktime(char *dp) { time_t t; int d, m, y; - struct tm tm; + struct tm tm, tp; (void)time(&t); - tp = localtime(&t); + localtime_r(&t, &tp); tm = tm0; - tm.tm_mday = tp->tm_mday; - tm.tm_mon = tp->tm_mon; - tm.tm_year = tp->tm_year; + tm.tm_mday = tp.tm_mday; + tm.tm_mon = tp.tm_mon; + tm.tm_year = tp.tm_year; switch (sscanf(dp, "%d.%d.%d", &d, &m, &y)) { case 3: @@ -204,282 +119,3 @@ Mktime(char *dp) #endif return (mktime(&tm)); } - -/* - * Possible date formats include any combination of: - * 3-charmonth (January, Jan, Jan) - * 3-charweekday (Friday, Monday, mon.) - * numeric month or day (1, 2, 04) - * - * Any character may separate them, or they may not be separated. Any line, - * following a line that is matched, that starts with "whitespace", is shown - * along with the matched line. - */ -int -isnow(char *endp, int *monthp, int *dayp, int *varp) -{ - int day, flags, month = 0, v1, v2; - - /* - * CONVENTION - * - * Month: 1-12 - * Monthname: Jan .. Dec - * Day: 1-31 - * Weekday: Mon-Sun - * - */ - - flags = 0; - - /* read first field */ - /* didn't recognize anything, skip it */ - if (!(v1 = getfield(endp, &endp, &flags))) - return (0); - - /* Easter or Easter depending days */ - if (flags & F_EASTER) - day = v1 - 1; /* days since January 1 [0-365] */ - - /* - * 1. {Weekday,Day} XYZ ... - * - * where Day is > 12 - */ - else if (flags & F_ISDAY || v1 > 12) { - - /* found a day; day: 1-31 or weekday: 1-7 */ - day = v1; - - /* {Day,Weekday} {Month,Monthname} ... */ - /* if no recognizable month, assume just a day alone - * in other words, find month or use current month */ - if (!(month = getfield(endp, &endp, &flags))) - month = tp->tm_mon + 1; - } - - /* 2. {Monthname} XYZ ... */ - else if (flags & F_ISMONTH) { - month = v1; - - /* Monthname {day,weekday} */ - /* if no recognizable day, assume the first day in month */ - if (!(day = getfield(endp, &endp, &flags))) - day = 1; - } - - /* Hm ... */ - else { - v2 = getfield(endp, &endp, &flags); - - /* - * {Day} {Monthname} ... - * where Day <= 12 - */ - if (flags & F_ISMONTH) { - day = v1; - month = v2; - *varp = 0; - } - - /* {Month} {Weekday,Day} ... */ - else { - /* F_ISDAY set, v2 > 12, or no way to tell */ - month = v1; - /* if no recognizable day, assume the first */ - day = v2 ? v2 : 1; - *varp = 0; - } - } - - /* convert Weekday into *next* Day, - * e.g.: 'Sunday' -> 22 - * 'SundayLast' -> ?? - */ - if (flags & F_ISDAY) { -#ifdef DEBUG - fprintf(stderr, "\nday: %d %s month %d\n", day, endp, month); -#endif - - *varp = 1; - /* variable weekday, SundayLast, MondayFirst ... */ - if (day < 0 || day >= 10) { - - /* negative offset; last, -4 .. -1 */ - if (day < 0) { - v1 = day / 10 - 1; /* offset -4 ... -1 */ - day = 10 + (day % 10); /* day 1 ... 7 */ - - /* day, eg '22nd' */ - v2 = tp->tm_mday + - (((day - 1) - tp->tm_wday + 7) % 7); - - /* (month length - day) / 7 + 1 */ - if (cumdays[month + 1] - cumdays[month] >= v2 - && ((int)((cumdays[month + 1] - - cumdays[month] - v2) / 7) + 1) == -v1) - day = v2; /* bingo ! */ - - /* set to yesterday */ - else { - day = tp->tm_mday - 1; - if (day == 0) - return (0); - } - } - - /* first, second ... +1 ... +5 */ - else { - /* offset: +1 (first Sunday) ... */ - v1 = day / 10; - day = day % 10; - - /* day, eg '22th' */ - v2 = tp->tm_mday + - (((day - 1) - tp->tm_wday + 7) % 7); - - /* Hurrah! matched */ - if (((v2 - 1 + 7) / 7) == v1 ) - day = v2; - - else { - /* set to yesterday */ - day = tp->tm_mday - 1; - if (day == 0) - return (0); - } - } - } else { - /* wired */ - day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7); - *varp = 1; - } - } - - if (!(flags & F_EASTER)) { - if (day + cumdays[month] > cumdays[month + 1]) { - /* off end of month, adjust */ - day -= (cumdays[month + 1] - cumdays[month]); - /* next year */ - if (++month > 12) - month = 1; - } - *monthp = month; - *dayp = day; - day = cumdays[month] + day; - } else { - for (v1 = 0; day > cumdays[v1]; v1++) - ; - *monthp = v1 - 1; - *dayp = day - cumdays[v1 - 1]; - *varp = 1; - } - -#ifdef DEBUG - fprintf(stderr, "day2: day %d(%d-%d) yday %d\n", - *dayp, day, cumdays[month], tp->tm_yday); -#endif - - /* When days before or days after is specified */ - /* no year rollover */ - if (day >= tp->tm_yday - f_dayBefore && - day <= tp->tm_yday + f_dayAfter) - return (1); - - /* next year */ - if (tp->tm_yday + f_dayAfter >= yrdays) { - int end = tp->tm_yday + f_dayAfter - yrdays; - if (day <= end) - return (1); - } - - /* previous year */ - if (tp->tm_yday - f_dayBefore < 0) { - int before = yrdays + (tp->tm_yday - f_dayBefore); - if (day >= before) - return (1); - } - - return (0); -} - - -int -getmonth(char *s) -{ - const char **p; - struct fixs *n; - - for (n = fnmonths; n->name; ++n) - if (!strncasecmp(s, n->name, n->len)) - return ((n - fnmonths) + 1); - for (n = nmonths; n->name; ++n) - if (!strncasecmp(s, n->name, n->len)) - return ((n - nmonths) + 1); - for (p = months; *p; ++p) - if (!strncasecmp(s, *p, 3)) - return ((p - months) + 1); - return (0); -} - - -int -getday(char *s) -{ - const char **p; - struct fixs *n; - - for (n = fndays; n->name; ++n) - if (!strncasecmp(s, n->name, n->len)) - return ((n - fndays) + 1); - for (n = ndays; n->name; ++n) - if (!strncasecmp(s, n->name, n->len)) - return ((n - ndays) + 1); - for (p = days; *p; ++p) - if (!strncasecmp(s, *p, 3)) - return ((p - days) + 1); - return (0); -} - -/* return offset for variable weekdays - * -1 -> last weekday in month - * +1 -> first weekday in month - * ... etc ... - */ -int -getdayvar(char *s) -{ - int offs; - - offs = strlen(s); - - /* Sun+1 or Wednesday-2 - * ^ ^ */ - - /* fprintf(stderr, "x: %s %s %d\n", s, s + offs - 2, offs); */ - switch (*(s + offs - 2)) { - case '-': - return (-(atoi(s + offs - 1))); - case '+': - return (atoi(s + offs - 1)); - } - - /* - * some aliases: last, first, second, third, fourth - */ - - /* last */ - if (offs > 4 && !strcasecmp(s + offs - 4, "last")) - return (-1); - else if (offs > 5 && !strcasecmp(s + offs - 5, "first")) - return (+1); - else if (offs > 6 && !strcasecmp(s + offs - 6, "second")) - return (+2); - else if (offs > 5 && !strcasecmp(s + offs - 5, "third")) - return (+3); - else if (offs > 6 && !strcasecmp(s + offs - 6, "fourth")) - return (+4); - - /* no offset detected */ - return (0); -} diff --git a/usr.bin/calendar/events.c b/usr.bin/calendar/events.c new file mode 100644 index 0000000..2609476 --- /dev/null +++ b/usr.bin/calendar/events.c @@ -0,0 +1,125 @@ +/*- + * Copyright (c) 1992-2009 Edwin Groothuis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include "pathnames.h" +#include "calendar.h" + +struct event * +event_add(int year, int month, int day, char *date, int var, char *txt, + char *extra) +{ + struct event *e; + + /* + * Creating a new event: + * - Create a new event + * - Copy the machine readable day and month + * - Copy the human readable and language specific date + * - Copy the text of the event + */ + e = (struct event *)calloc(1, sizeof(struct event)); + if (e == NULL) + errx(1, "event_add: cannot allocate memory"); + e->month = month; + e->day = day; + e->var = var; + e->date = strdup(date); + if (e->date == NULL) + errx(1, "event_add: cannot allocate memory"); + e->text = strdup(txt); + if (e->text == NULL) + errx(1, "event_add: cannot allocate memory"); + e->extra = NULL; + if (extra != NULL && extra[0] != '\0') + e->extra = strdup(extra); + addtodate(e, year, month, day); + return (e); +} + +void +event_continue(struct event *e, char *txt) +{ + char *text; + + /* + * Adding text to the event: + * - Save a copy of the old text (unknown length, so strdup()) + * - Allocate enough space for old text + \n + new text + 0 + * - Store the old text + \n + new text + * - Destroy the saved copy. + */ + text = strdup(e->text); + if (text == NULL) + errx(1, "event_continue: cannot allocate memory"); + + free(e->text); + e->text = (char *)malloc(strlen(text) + strlen(txt) + 3); + if (e->text == NULL) + errx(1, "event_continue: cannot allocate memory"); + strcpy(e->text, text); + strcat(e->text, "\n"); + strcat(e->text, txt); + free(text); + + return; +} + +void +event_print_all(FILE *fp) +{ + struct event *e; + + while (walkthrough_dates(&e) != 0) { +#ifdef DEBUG + fprintf(stderr, "event_print_allmonth: %d, day: %d\n", + month, day); +#endif + + /* + * Go through all events and print the text of the matching + * dates + */ + while (e != NULL) { + (void)fprintf(fp, "%s%c%s%s%s%s\n", e->date, + e->var ? '*' : ' ', e->text, + e->extra != NULL ? " (" : "", + e->extra != NULL ? e->extra : "", + e->extra != NULL ? ")" : "" + ); + + e = e->next; + } + } +} diff --git a/usr.bin/calendar/io.c b/usr.bin/calendar/io.c index 03f28fe..9973afc 100644 --- a/usr.bin/calendar/io.c +++ b/usr.bin/calendar/io.c @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -46,11 +46,8 @@ static char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94"; #include __FBSDID("$FreeBSD$"); -#include #include #include -#include -#include #include #include #include @@ -66,62 +63,61 @@ __FBSDID("$FreeBSD$"); #include "pathnames.h" #include "calendar.h" -/* - * Event sorting related functions: - * - Use event_add() to create a new event - * - Use event_continue() to add more text to the last added event - * - Use event_print_all() to display them in time chronological order - */ -static struct event *event_add(struct event *, int, int, char *, int, char *); -static void event_continue(struct event *events, char *txt); -static void event_print_all(FILE *fp, struct event *events); -struct event { - int month; - int day; - int var; - char *date; - char *text; - struct event *next; -}; - const char *calendarFile = "calendar"; /* default calendar file */ const char *calendarHomes[] = {".calendar", _PATH_INCLUDE}; /* HOME */ const char *calendarNoMail = "nomail"; /* don't sent mail if this file exist */ char path[MAXPATHLEN]; -struct fixs neaster, npaskha; - -struct iovec header[] = { - {"From: ", 6}, - {NULL, 0}, - {" (Reminder Service)\nTo: ", 24}, - {NULL, 0}, - {"\nSubject: ", 10}, - {NULL, 0}, - {"'s Calendar\nPrecedence: bulk\n\n", 30}, -}; - +struct fixs neaster, npaskha, ncny, nfullmoon, nnewmoon; +struct fixs nmarequinox, nsepequinox, njunsolstice, ndecsolstice; + +#define REPLACE(string, slen, struct_) \ + if (strncasecmp(buf, (string), (slen)) == 0 && buf[(slen)]) { \ + if (struct_.name != NULL) \ + free(struct_.name); \ + if ((struct_.name = strdup(buf + (slen))) == NULL) \ + errx(1, "cannot allocate memory"); \ + struct_.len = strlen(buf + (slen)); \ + continue; \ + } void cal(void) { - int printing; - char *p; + char *pp, p; FILE *fp; int ch, l; - int month; - int day; - int var; + int count, i; + int month[MAXCOUNT]; + int day[MAXCOUNT]; + int year[MAXCOUNT]; + char **extradata; /* strings of 20 length */ + int flags; static int d_first = -1; char buf[2048 + 1]; - struct event *events = NULL; + struct event *events[MAXCOUNT]; + struct tm tm; + char dbuf[80]; + + extradata = (char **)calloc(MAXCOUNT, sizeof(char *)); + for (i = 0; i < MAXCOUNT; i++) { + extradata[i] = (char *)calloc(1, 20); + } + + /* Unused */ + tm.tm_sec = 0; + tm.tm_min = 0; + tm.tm_hour = 0; + tm.tm_wday = 0; + count = 0; if ((fp = opencal()) == NULL) return; - for (printing = 0; fgets(buf, sizeof(buf), stdin) != NULL;) { - if ((p = strchr(buf, '\n')) != NULL) - *p = '\0'; + while (fgets(buf, sizeof(buf), stdin) != NULL) { + if ((pp = strchr(buf, '\n')) != NULL) + *pp = '\0'; else + /* Flush this line */ while ((ch = getchar()) != '\n' && ch != EOF); for (l = strlen(buf); l > 0 && isspace((unsigned char)buf[l - 1]); @@ -130,246 +126,87 @@ cal(void) buf[l] = '\0'; if (buf[0] == '\0') continue; + + /* Parse special definitions: LANG, Easter, Paskha etc */ if (strncmp(buf, "LANG=", 5) == 0) { (void)setlocale(LC_ALL, buf + 5); d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); setnnames(); continue; } - if (strncasecmp(buf, "Easter=", 7) == 0 && buf[7]) { - if (neaster.name != NULL) - free(neaster.name); - if ((neaster.name = strdup(buf + 7)) == NULL) - errx(1, "cannot allocate memory"); - neaster.len = strlen(buf + 7); - continue; - } - if (strncasecmp(buf, "Paskha=", 7) == 0 && buf[7]) { - if (npaskha.name != NULL) - free(npaskha.name); - if ((npaskha.name = strdup(buf + 7)) == NULL) - errx(1, "cannot allocate memory"); - npaskha.len = strlen(buf + 7); + REPLACE("Easter=", 7, neaster); + REPLACE("Paskha=", 7, npaskha); + REPLACE("ChineseNewYear=", 15, ncny); + REPLACE("NewMoon=", 8, nnewmoon); + REPLACE("FullMoon=", 9, nfullmoon); + REPLACE("MarEquinox=", 11, nmarequinox); + REPLACE("SepEquinox=", 11, nsepequinox); + REPLACE("JunSolstice=", 12, njunsolstice); + REPLACE("DecSolstice=", 12, ndecsolstice); + if (strncmp(buf, "SEQUENCE=", 9) == 0) { + setnsequences(buf + 9); continue; } - if (buf[0] != '\t') { - printing = isnow(buf, &month, &day, &var) ? 1 : 0; - if ((p = strchr(buf, '\t')) == NULL) - continue; - if (p > buf && p[-1] == '*') - var = 1; - if (printing) { - struct tm tm; - char dbuf[80]; - - if (d_first < 0) - d_first = - (*nl_langinfo(D_MD_ORDER) == 'd'); - tm.tm_sec = 0; /* unused */ - tm.tm_min = 0; /* unused */ - tm.tm_hour = 0; /* unused */ - tm.tm_wday = 0; /* unused */ - tm.tm_mon = month - 1; - tm.tm_mday = day; - tm.tm_year = tp->tm_year; /* unused */ - (void)strftime(dbuf, sizeof(dbuf), - d_first ? "%e %b" : "%b %e", &tm); - events = event_add(events, month, day, dbuf, - var, p); - } - } else { - if (printing) - event_continue(events, buf); - } - } - - event_print_all(fp, events); - closecal(fp); -} - -static struct event * -event_add(struct event *events, int month, int day, - char *date, int var, char *txt) -{ - struct event *e; - - /* - * Creating a new event: - * - Create a new event - * - Copy the machine readable day and month - * - Copy the human readable and language specific date - * - Copy the text of the event - */ - e = (struct event *)calloc(1, sizeof(struct event)); - if (e == NULL) - errx(1, "event_add: cannot allocate memory"); - e->month = month; - e->day = day; - e->var = var; - e->date = strdup(date); - if (e->date == NULL) - errx(1, "event_add: cannot allocate memory"); - e->text = strdup(txt); - if (e->text == NULL) - errx(1, "event_add: cannot allocate memory"); - e->next = events; - - return e; -} - -static void -event_continue(struct event *e, char *txt) -{ - char *text; - - /* - * Adding text to the event: - * - Save a copy of the old text (unknown length, so strdup()) - * - Allocate enough space for old text + \n + new text + 0 - * - Store the old text + \n + new text - * - Destroy the saved copy. - */ - text = strdup(e->text); - if (text == NULL) - errx(1, "event_continue: cannot allocate memory"); - - free(e->text); - e->text = (char *)malloc(strlen(text) + strlen(txt) + 3); - if (e->text == NULL) - errx(1, "event_continue: cannot allocate memory"); - strcpy(e->text, text); - strcat(e->text, "\n"); - strcat(e->text, txt); - free(text); - - return; -} - -static void -event_print_all(FILE *fp, struct event *events) -{ - struct event *e, *e_next; - int daycounter; - int day, month; - - /* - * Print all events: - * - We know the number of days to be counted (f_dayAfter + f_dayBefore) - * - We know the current day of the year ("now" - f_dayBefore + counter) - * - We know the number of days in the year (yrdays, set in settime()) - * - So we know the date on which the current daycounter is on the - * calendar in days and months. - * - Go through the list of events, and print all matching dates - */ - for (daycounter = 0; daycounter <= f_dayAfter + f_dayBefore; - daycounter++) { - day = tp->tm_yday - f_dayBefore + daycounter; - if (day < 0) - day += yrdays; - if (day >= yrdays) - day -= yrdays; /* - * When we know the day of the year, we can determine the day - * of the month and the month. + * If the line starts with a tab, the data has to be + * added to the previous line */ - month = 1; - while (month <= 12) { - if (day <= cumdays[month]) - break; - month++; + if (buf[0] == '\t') { + for (i = 0; i < count; i++) + event_continue(events[i], buf); + continue; } - month--; - day -= cumdays[month]; -#ifdef DEBUG - fprintf(stderr, "event_print_allmonth: %d, day: %d\n", - month, day); -#endif + /* Get rid of leading spaces (non-standard) */ + while (isspace(buf[0])) + memcpy(buf, buf + 1, strlen(buf) - 1); - /* - * Go through all events and print the text of the matching - * dates - */ - for (e = events; e != NULL; e = e_next) { - e_next = e->next; + /* No tab in the line, then not a valid line */ + if ((pp = strchr(buf, '\t')) == NULL) + continue; - if (month != e->month || day != e->day) - continue; + /* Trim spaces in front of the tab */ + while (isspace(pp[-1])) + pp--; - (void)fprintf(fp, "%s%c%s\n", e->date, - e->var ? '*' : ' ', e->text); + p = *pp; + *pp = '\0'; + if ((count = parsedaymonth(buf, year, month, day, &flags, + extradata)) == 0) + continue; + *pp = p; + if (count < 0) { + /* Show error status based on return value */ + fprintf(stderr, "Ignored: %s\n", buf); + if (count == -1) + continue; + count = -count + 1; } - } -} -int -getfield(char *p, char **endp, int *flags) -{ - int val, var; - char *start, savech; + /* Find the last tab */ + while (pp[1] == '\t') + pp++; - for (; !isdigit((unsigned char)*p) && !isalpha((unsigned char)*p) - && *p != '*'; ++p) - ; - if (*p == '*') { /* `*' is current month */ - *flags |= F_ISMONTH; - *endp = p + 1; - return (tp->tm_mon + 1); - } - if (isdigit((unsigned char)*p)) { - val = strtol(p, &p, 10); /* if 0, it's failure */ - for (; !isdigit((unsigned char)*p) - && !isalpha((unsigned char)*p) && *p != '*'; ++p); - *endp = p; - return (val); - } - for (start = p; isalpha((unsigned char)*++p);); - - /* Sunday-1 */ - if (*p == '+' || *p == '-') - for(; isdigit((unsigned char)*++p);) - ; - - savech = *p; - *p = '\0'; - - /* Month */ - if ((val = getmonth(start)) != 0) - *flags |= F_ISMONTH; - - /* Day */ - else if ((val = getday(start)) != 0) { - *flags |= F_ISDAY; + if (d_first < 0) + d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); - /* variable weekday */ - if ((var = getdayvar(start)) != 0) { - if (var <= 5 && var >= -4) - val += var * 10; -#ifdef DEBUG - printf("var: %d\n", var); -#endif + for (i = 0; i < count; i++) { + tm.tm_mon = month[i] - 1; + tm.tm_mday = day[i]; + tm.tm_year = year[i] - 1900; + (void)strftime(dbuf, sizeof(dbuf), + d_first ? "%e %b" : "%b %e", &tm); + if (debug) + fprintf(stderr, "got %s\n", pp); + events[i] = event_add(year[i], month[i], day[i], dbuf, + ((flags &= F_VARIABLE) != 0) ? 1 : 0, pp, + extradata[i]); } } - /* Easter */ - else if ((val = geteaster(start, tp->tm_year + 1900)) != 0) - *flags |= F_EASTER; - - /* Paskha */ - else if ((val = getpaskha(start, tp->tm_year + 1900)) != 0) - *flags |= F_EASTER; - - /* undefined rest */ - else { - *p = savech; - return (0); - } - for (*p = savech; !isdigit((unsigned char)*p) - && !isalpha((unsigned char)*p) && *p != '*'; ++p) - ; - *endp = p; - return (val); + event_print_all(fp); + closecal(fp); } FILE * @@ -505,9 +342,14 @@ closecal(FILE *fp) /* parent -- write to pipe input */ (void)close(pdes[0]); - header[1].iov_base = header[3].iov_base = pw->pw_name; - header[1].iov_len = header[3].iov_len = strlen(pw->pw_name); - writev(pdes[1], header, 7); + write(pdes[1], "From: \"Reminder Service\" <", 26); + write(pdes[1], pw->pw_name, strlen(pw->pw_name)); + write(pdes[1], ">\nTo: <", 7); + write(pdes[1], pw->pw_name, strlen(pw->pw_name)); + write(pdes[1], ">\nSubject: ", 12); + write(pdes[1], dayname, strlen(dayname)); + write(pdes[1], "'s Calendar\nPrecedence: bulk\n\n", 30); + while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0) (void)write(pdes[1], buf, nread); (void)close(pdes[1]); diff --git a/usr.bin/calendar/locale.c b/usr.bin/calendar/locale.c new file mode 100644 index 0000000..bf6d224 --- /dev/null +++ b/usr.bin/calendar/locale.c @@ -0,0 +1,168 @@ +/*- + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include "calendar.h" + +const char *fdays[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", + "Saturday", NULL, +}; + +const char *days[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL, +}; + +const char *fmonths[] = { + "January", "February", "March", "April", "May", "June", "Juli", + "August", "September", "October", "November", "December", NULL, +}; + +const char *months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL, +}; + +const char *sequences[] = { + "First", "Second", "Third", "Fourth", "Fifth", "Last" +}; + +struct fixs fndays[8]; /* full national days names */ +struct fixs ndays[8]; /* short national days names */ +struct fixs fnmonths[13]; /* full national months names */ +struct fixs nmonths[13]; /* short national month names */ +struct fixs nsequences[10]; /* national sequence names */ + + +void +setnnames(void) +{ + char buf[80]; + int i, l; + struct tm tm; + + for (i = 0; i < 7; i++) { + tm.tm_wday = i; + strftime(buf, sizeof(buf), "%a", &tm); + for (l = strlen(buf); + l > 0 && isspace((unsigned char)buf[l - 1]); + l--) + ; + buf[l] = '\0'; + if (ndays[i].name != NULL) + free(ndays[i].name); + if ((ndays[i].name = strdup(buf)) == NULL) + errx(1, "cannot allocate memory"); + ndays[i].len = strlen(buf); + + strftime(buf, sizeof(buf), "%A", &tm); + for (l = strlen(buf); + l > 0 && isspace((unsigned char)buf[l - 1]); + l--) + ; + buf[l] = '\0'; + if (fndays[i].name != NULL) + free(fndays[i].name); + if ((fndays[i].name = strdup(buf)) == NULL) + errx(1, "cannot allocate memory"); + fndays[i].len = strlen(buf); + } + + for (i = 0; i < 12; i++) { + tm.tm_mon = i; + strftime(buf, sizeof(buf), "%b", &tm); + for (l = strlen(buf); + l > 0 && isspace((unsigned char)buf[l - 1]); + l--) + ; + buf[l] = '\0'; + if (nmonths[i].name != NULL) + free(nmonths[i].name); + if ((nmonths[i].name = strdup(buf)) == NULL) + errx(1, "cannot allocate memory"); + nmonths[i].len = strlen(buf); + + strftime(buf, sizeof(buf), "%B", &tm); + for (l = strlen(buf); + l > 0 && isspace((unsigned char)buf[l - 1]); + l--) + ; + buf[l] = '\0'; + if (fnmonths[i].name != NULL) + free(fnmonths[i].name); + if ((fnmonths[i].name = strdup(buf)) == NULL) + errx(1, "cannot allocate memory"); + fnmonths[i].len = strlen(buf); + } +} + +void +setnsequences(char *seq) +{ + int i; + char *p; + + p = seq; + for (i = 0; i < 5; i++) { + nsequences[i].name = p; + if ((p = strchr(p, ' ')) == NULL) { + for (i = 0; i < 5; i++) { + nsequences[i].name = NULL; + nsequences[i].len = 0; + return; + } + + } + *p = '\0'; + p++; + } + nsequences[i].name = p; + + for (i = 0; i < 5; i++) { + nsequences[i].name = strdup(nsequences[i].name); + nsequences[i].len = nsequences[i + 1].name - nsequences[i].name; + } + nsequences[i].name = strdup(nsequences[i].name); + nsequences[i].len = strlen(nsequences[i].name); + + return; +} diff --git a/usr.bin/calendar/ostern.c b/usr.bin/calendar/ostern.c index 89e7b1c..3cce299 100644 --- a/usr.bin/calendar/ostern.c +++ b/usr.bin/calendar/ostern.c @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1996 Wolfram Schneider . Berlin. * All rights reserved. * @@ -60,50 +60,8 @@ easter(int year) /* 0 ... abcd, NOT since 1900 */ L = I - J; - if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) + if (isleap(year)) return 31 + 29 + 21 + L + 7; else return 31 + 28 + 21 + L + 7; } - -/* return year day for Easter or easter depending days - * Match: Easter([+-][0-9]+)? - * e.g: Easter-2 is Good Friday (2 days before Easter) - */ - -int -geteaster(char *s, int year) -{ - int offset = 0; - -#define EASTER "easter" -#define EASTERNAMELEN (sizeof(EASTER) - 1) - - if (strncasecmp(s, EASTER, EASTERNAMELEN) == 0) - s += EASTERNAMELEN; - else if (neaster.name != NULL - && strncasecmp(s, neaster.name, neaster.len) == 0) - s += neaster.len; - else - return (0); - -#ifdef DEBUG - printf("%s %d %d\n", s, year, EASTERNAMELEN); -#endif - - /* Easter+1 or Easter-2 - * ^ ^ */ - - switch (*s) { - - case '-': - case '+': - offset = atoi(s); - break; - - default: - offset = 0; - } - - return (easter(year) + offset); -} diff --git a/usr.bin/calendar/parsedata.c b/usr.bin/calendar/parsedata.c new file mode 100644 index 0000000..fd6b6b6 --- /dev/null +++ b/usr.bin/calendar/parsedata.c @@ -0,0 +1,1008 @@ +/*- + * Copyright (c) 1992-2009 Edwin Groothuis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include "calendar.h" + +static char *showflags(int flags); +static int isonlydigits(char *s, int nostar); +static const char *getmonthname(int i); +static int checkmonth(char *s, int *len, int *offset, const char **month); +static const char *getdayofweekname(int i); +static int checkdayofweek(char *s, int *len, int *offset, const char **dow); +static int indextooffset(char *s); +static int parseoffset(char *s); +static char *floattoday(int year, double f); +static char *floattotime(double f); + +/* + * Expected styles: + * + * Date ::= Month . ' ' . DayOfMonth | + * Month . ' ' . DayOfWeek . ModifierIndex | + * Month . '/' . DayOfMonth | + * Month . '/' . DayOfWeek . ModifierIndex | + * DayOfMonth . ' ' . Month | + * DayOfMonth . '/' . Month | + * DayOfWeek . ModifierIndex . ' ' .Month | + * DayOfWeek . ModifierIndex . '/' .Month | + * DayOfWeek . ModifierIndex | + * SpecialDay . ModifierOffset + * + * Month ::= MonthName | MonthNumber | '*' + * MonthNumber ::= '0' ... '9' | '00' ... '09' | '10' ... '12' + * MonthName ::= MonthNameShort | MonthNameLong + * MonthNameLong ::= 'January' ... 'December' + * MonthNameShort ::= 'Jan' ... 'Dec' | 'Jan.' ... 'Dec.' + * + * DayOfWeek ::= DayOfWeekShort | DayOfWeekLong + * DayOfWeekShort ::= 'Mon' .. 'Sun' + * DayOfWeekLong ::= 'Monday' .. 'Sunday' + * DayOfMonth ::= '0' ... '9' | '00' ... '09' | '10' ... '29' | + * '30' ... '31' | '*' + * + * ModifierOffset ::= '' | '+' . ModifierNumber | '-' . ModifierNumber + * ModifierNumber ::= '0' ... '9' | '00' ... '99' | '000' ... '299' | + * '300' ... '359' | '360' ... '365' + * ModifierIndex ::= 'Second' | 'Third' | 'Fourth' | 'Fifth' | + * 'First' | 'Last' + * + * SpecialDay ::= 'Easter' | 'Pashka' | 'ChineseNewYear' + * + */ +static int +determinestyle(char *date, int *flags, + char *month, int *imonth, char *dayofmonth, int *idayofmonth, + char *dayofweek, int *idayofweek, char *modifieroffset, + char *modifierindex, char *specialday) +{ + char *p, *p1, *p2; + const char *dow, *pmonth; + char pold; + size_t len, offset; + + *flags = F_NONE; + *month = '\0'; + *imonth = 0; + *dayofmonth = '\0'; + *idayofmonth = 0; + *dayofweek = '\0'; + *idayofweek = 0; + *modifieroffset = '\0'; + *modifierindex = '\0'; + *specialday = '\0'; + +#define CHECKSPECIAL(s1, s2, lens2, type) \ + if (s2 != NULL && strncmp(s1, s2, lens2) == 0) { \ + *flags |= F_SPECIALDAY; \ + *flags |= type; \ + *flags |= F_VARIABLE; \ + if (strlen(s1) == lens2) { \ + strcpy(specialday, s1); \ + return (1); \ + } \ + strncpy(specialday, s1, lens2); \ + specialday[lens2] = '\0'; \ + strcpy(modifieroffset, s1 + lens2); \ + *flags |= F_MODIFIEROFFSET; \ + return (1); \ + } + + if ((p = strchr(date, ' ')) == NULL) { + if ((p = strchr(date, '/')) == NULL) { + CHECKSPECIAL(date, STRING_CNY, strlen(STRING_CNY), + F_CNY); + CHECKSPECIAL(date, ncny.name, ncny.len, F_CNY); + CHECKSPECIAL(date, STRING_NEWMOON, + strlen(STRING_NEWMOON), F_NEWMOON); + CHECKSPECIAL(date, nnewmoon.name, nnewmoon.len, + F_NEWMOON); + CHECKSPECIAL(date, STRING_FULLMOON, + strlen(STRING_FULLMOON), F_FULLMOON); + CHECKSPECIAL(date, nfullmoon.name, nfullmoon.len, + F_FULLMOON); + CHECKSPECIAL(date, STRING_PASKHA, + strlen(STRING_PASKHA), F_PASKHA); + CHECKSPECIAL(date, npaskha.name, npaskha.len, F_PASKHA); + CHECKSPECIAL(date, STRING_EASTER, + strlen(STRING_EASTER), F_EASTER); + CHECKSPECIAL(date, neaster.name, neaster.len, F_EASTER); + CHECKSPECIAL(date, STRING_MAREQUINOX, + strlen(STRING_MAREQUINOX), F_MAREQUINOX); + CHECKSPECIAL(date, nmarequinox.name, nmarequinox.len, + F_SEPEQUINOX); + CHECKSPECIAL(date, STRING_SEPEQUINOX, + strlen(STRING_SEPEQUINOX), F_SEPEQUINOX); + CHECKSPECIAL(date, nsepequinox.name, nsepequinox.len, + F_SEPEQUINOX); + CHECKSPECIAL(date, STRING_JUNSOLSTICE, + strlen(STRING_JUNSOLSTICE), F_JUNSOLSTICE); + CHECKSPECIAL(date, njunsolstice.name, njunsolstice.len, + F_JUNSOLSTICE); + CHECKSPECIAL(date, STRING_DECSOLSTICE, + strlen(STRING_DECSOLSTICE), F_DECSOLSTICE); + CHECKSPECIAL(date, ndecsolstice.name, ndecsolstice.len, + F_DECSOLSTICE); + if (checkdayofweek(date, &len, &offset, &dow) != 0) { + *flags |= F_DAYOFWEEK; + *flags |= F_VARIABLE; + *idayofweek = offset; + if (strlen(date) == len) { + strcpy(dayofweek, date); + return (1); + } + strncpy(dayofweek, date, len); + dayofweek[len] = '\0'; + strcpy(modifierindex, date + len); + *flags |= F_MODIFIERINDEX; + return (1); + } + if (isonlydigits(date, 1)) { + /* Assume month number only */ + *flags |= F_MONTH; + *imonth = (int)strtol(date, (char **)NULL, 10); + strcpy(month, getmonthname(*imonth)); + return(1); + } + return (0); + } + } + + /* + * AFTER this, leave by goto-ing to "allfine" or "fail" to restore the + * original data in `date'. + */ + pold = *p; + *p = 0; + p1 = date; + p2 = p + 1; + /* Now p2 points to the next field and p1 to the first field */ + + /* Check if there is a month-string in the date */ + if ((checkmonth(p1, &len, &offset, &pmonth) != 0) + || (checkmonth(p2, &len, &offset, &pmonth) != 0 && (p2 = p1))) { + /* p2 is the non-month part */ + *flags |= F_MONTH; + *imonth = offset; + + strcpy(month, getmonthname(offset)); + if (isonlydigits(p2, 1)) { + strcpy(dayofmonth, p2); + *idayofmonth = (int)strtol(p2, (char **)NULL, 10); + *flags |= F_DAYOFMONTH; + goto allfine; + } + if (strcmp(p2, "*") == 0) { + *flags |= F_ALLDAY; + goto allfine; + } + + if (checkdayofweek(p2, &len, &offset, &dow) != 0) { + *flags |= F_DAYOFWEEK; + *flags |= F_VARIABLE; + *idayofweek = offset; + strcpy(dayofweek, getdayofweekname(offset)); + if (strlen(p2) == len) + goto allfine; + strcpy(modifierindex, p2 + len); + *flags |= F_MODIFIERINDEX; + goto allfine; + } + + goto fail; + } + + /* Check if there is an every-day or every-month in the string */ + if ((strcmp(p1, "*") == 0 && isonlydigits(p2, 1)) + || (strcmp(p2, "*") == 0 && isonlydigits(p1, 1) && (p2 = p1))) { + int d; + + *flags |= F_ALLMONTH; + *flags |= F_DAYOFMONTH; + d = (int)strtol(p2, (char **)NULL, 10); + *idayofmonth = d; + sprintf(dayofmonth, "%d", d); + goto allfine; + } + + /* Month as a number, then a weekday */ + if (isonlydigits(p1, 1) + && checkdayofweek(p2, &len, &offset, &dow) != 0) { + int d; + + *flags |= F_MONTH; + *flags |= F_DAYOFWEEK; + *flags |= F_VARIABLE; + + *idayofweek = offset; + d = (int)strtol(p1, (char **)NULL, 10); + *imonth = d; + strcpy(month, getmonthname(d)); + + strcpy(dayofweek, getdayofweekname(offset)); + if (strlen(p2) == len) + goto allfine; + strcpy(modifierindex, p2 + len); + *flags |= F_MODIFIERINDEX; + goto allfine; + } + + /* If both the month and date are specified as numbers */ + if (isonlydigits(p1, 1) && isonlydigits(p2, 0)) { + /* Now who wants to be this ambigious? :-( */ + int m, d; + + if (strchr(p2, '*') != NULL) + *flags |= F_VARIABLE; + + m = (int)strtol(p1, (char **)NULL, 10); + d = (int)strtol(p2, (char **)NULL, 10); + + *flags |= F_MONTH; + *flags |= F_DAYOFMONTH; + + if (m > 12) { + *imonth = d; + *idayofmonth = m; + strcpy(month, getmonthname(d)); + sprintf(dayofmonth, "%d", m); + } else { + *imonth = m; + *idayofmonth = d; + strcpy(month, getmonthname(m)); + sprintf(dayofmonth, "%d", d); + } + goto allfine; + } + + /* FALLTHROUGH */ +fail: + *p = pold; + return (0); +allfine: + *p = pold; + return (1); + +} + +static void +remember(int *rememberindex, int *y, int *m, int *d, char **ed, int yy, int mm, + int dd, char *extra) +{ + static int warned = 0; + + if (*rememberindex >= MAXCOUNT - 1) { + if (warned == 0) + warnx("Index > %d, ignored", MAXCOUNT); + warned++; + return; + } + y[*rememberindex] = yy; + m[*rememberindex] = mm; + d[*rememberindex] = dd; + if (extra != NULL) + strcpy(ed[*rememberindex], extra); + else + ed[*rememberindex][0] = '\0'; + *rememberindex += 1; +} + +static void +debug_determinestyle(int dateonly, char *date, int flags, char *month, + int imonth, char *dayofmonth, int idayofmonth, char *dayofweek, + int idayofweek, char *modifieroffset, char *modifierindex, char *specialday) +{ + + if (dateonly != 0) { + printf("-------\ndate: |%s|\n", date); + if (dateonly == 1) + return; + } + printf("flags: %x - %s\n", flags, showflags(flags)); + if (modifieroffset[0] != '\0') + printf("modifieroffset: |%s|\n", modifieroffset); + if (modifierindex[0] != '\0') + printf("modifierindex: |%s|\n", modifierindex); + if (month[0] != '\0') + printf("month: |%s| (%d)\n", month, imonth); + if (dayofmonth[0] != '\0') + printf("dayofmonth: |%s| (%d)\n", dayofmonth, idayofmonth); + if (dayofweek[0] != '\0') + printf("dayofweek: |%s| (%d)\n", dayofweek, idayofweek); + if (specialday[0] != '\0') + printf("specialday: |%s|\n", specialday); +} + +struct yearinfo { + int year; + int ieaster, ipaskha, firstcnyday; + double ffullmoon[MAXMOONS], fnewmoon[MAXMOONS]; + double ffullmooncny[MAXMOONS], fnewmooncny[MAXMOONS]; + int ichinesemonths[MAXMOONS]; + double equinoxdays[2], solsticedays[2]; + int *mondays; + struct yearinfo *next; +}; +/* + * Possible date formats include any combination of: + * 3-charmonth (January, Jan, Jan) + * 3-charweekday (Friday, Monday, mon.) + * numeric month or day (1, 2, 04) + * + * Any character may separate them, or they may not be separated. Any line, + * following a line that is matched, that starts with "whitespace", is shown + * along with the matched line. + */ +int +parsedaymonth(char *date, int *yearp, int *monthp, int *dayp, int *flags, + char **edp) +{ + char month[100], dayofmonth[100], dayofweek[100], modifieroffset[100]; + char modifierindex[100], specialday[100]; + int idayofweek = -1, imonth = -1, idayofmonth = -1, year, remindex; + int d, m, dow, rm, rd, offset; + char *ed; + int retvalsign = 1; + + static struct yearinfo *years, *yearinfo; + + /* + * CONVENTION + * + * Month: 1-12 + * Monthname: Jan .. Dec + * Day: 1-31 + * Weekday: Mon .. Sun + * + */ + + *flags = 0; + + if (debug) + debug_determinestyle(1, date, *flags, month, imonth, + dayofmonth, idayofmonth, dayofweek, idayofweek, + modifieroffset, modifierindex, specialday); + if (determinestyle(date, flags, month, &imonth, dayofmonth, + &idayofmonth, dayofweek, &idayofweek, modifieroffset, + modifierindex, specialday) == 0) { + if (debug) + printf("Failed!\n"); + return (0); + } + + if (debug) + debug_determinestyle(0, date, *flags, month, imonth, + dayofmonth, idayofmonth, dayofweek, idayofweek, + modifieroffset, modifierindex, specialday); + + remindex = 0; + for (year = year1; year <= year2; year++) { + /* Get important dates for this year */ + yearinfo = years; + while (yearinfo != NULL) { + if (yearinfo->year == year) + break; + yearinfo = yearinfo -> next; + } + if (yearinfo == NULL) { + yearinfo = (struct yearinfo *)calloc(1, + sizeof(struct yearinfo)); + if (yearinfo == NULL) + errx(1, "Unable to allocate more years"); + yearinfo->year = year; + yearinfo->next = years; + years = yearinfo; + + yearinfo->mondays = mondaytab[isleap(year)]; + yearinfo->ieaster = easter(year); + fpom(year, UTCOffset, yearinfo->ffullmoon, + yearinfo->fnewmoon); + fpom(year, UTCOFFSET_CNY, yearinfo->ffullmooncny, + yearinfo->fnewmooncny); + fequinoxsolstice(year, UTCOffset, + yearinfo->equinoxdays, yearinfo->solsticedays); + + /* + * CNY: Match day with sun longitude at 330` with new + * moon + */ + yearinfo->firstcnyday = calculatesunlongitude30(year, + UTCOFFSET_CNY, yearinfo->ichinesemonths); + for (m = 0; yearinfo->fnewmooncny[m] >= 0; m++) { + if (yearinfo->fnewmooncny[m] > + yearinfo->firstcnyday) { + yearinfo->firstcnyday = + floor(yearinfo->fnewmooncny[m - 1]); + break; + } + } + } + + /* Same day every year */ + if (*flags == (F_MONTH | F_DAYOFMONTH)) { + if (!remember_ymd(year, imonth, idayofmonth)) + continue; + remember(&remindex, yearp, monthp, dayp, edp, + year, imonth, idayofmonth, NULL); + continue; + } + + /* XXX Same day every year, but variable */ + if (*flags == (F_MONTH | F_DAYOFMONTH | F_VARIABLE)) { + if (!remember_ymd(year, imonth, idayofmonth)) + continue; + remember(&remindex, yearp, monthp, dayp, edp, + year, imonth, idayofmonth, NULL); + continue; + } + + /* Same day every month */ + if (*flags == (F_ALLMONTH | F_DAYOFMONTH)) { + for (m = 1; m <= 12; m++) { + if (!remember_ymd(year, m, idayofmonth)) + continue; + remember(&remindex, yearp, monthp, dayp, edp, + year, m, idayofmonth, NULL); + } + continue; + } + + /* Every day of a month */ + if (*flags == (F_ALLDAY | F_MONTH)) { + for (d = 1; d <= yearinfo->mondays[imonth]; d++) { + if (!remember_ymd(year, imonth, d)) + continue; + remember(&remindex, yearp, monthp, dayp, edp, + year, imonth, d, NULL); + } + continue; + } + + /* One day of every month */ + if (*flags == (F_ALLMONTH | F_DAYOFWEEK)) { + for (m = 1; m <= 12; m++) { + if (!remember_ymd(year, m, idayofmonth)) + continue; + remember(&remindex, yearp, monthp, dayp, edp, + year, m, idayofmonth, NULL); + } + continue; + } + + /* Every dayofweek of the year */ + if (*flags == (F_DAYOFWEEK | F_VARIABLE)) { + dow = first_dayofweek_of_year(year); + d = (idayofweek - dow + 8) % 7; + while (d <= 366) { + if (remember_yd(year, d, &rm, &rd)) + remember(&remindex, + yearp, monthp, dayp, edp, + year, rm, rd, NULL); + d += 7; + } + continue; + } + + /* A certain dayofweek of a month */ + if (*flags == + (F_MONTH | F_DAYOFWEEK | F_MODIFIERINDEX | F_VARIABLE)) { + offset = indextooffset(modifierindex); + dow = first_dayofweek_of_month(year, imonth); + d = (idayofweek - dow + 8) % 7; + + if (offset > 0) { + while (d <= yearinfo->mondays[imonth]) { + if (--offset == 0 + && remember_ymd(year, imonth, d)) { + remember(&remindex, + yearp, monthp, dayp, edp, + year, imonth, d, NULL); + continue; + } + d += 7; + } + continue; + } + if (offset < 0) { + while (d <= yearinfo->mondays[imonth]) + d += 7; + while (offset != 0) { + offset++; + d -= 7; + } + if (remember_ymd(year, imonth, d)) + remember(&remindex, + yearp, monthp, dayp, edp, + year, imonth, d, NULL); + continue; + } + continue; + } + + /* Every dayofweek of the month */ + if (*flags == (F_DAYOFWEEK | F_MONTH | F_VARIABLE)) { + dow = first_dayofweek_of_month(year, imonth); + d = (idayofweek - dow + 8) % 7; + while (d <= yearinfo->mondays[imonth]) { + if (remember_ymd(year, imonth, d)) + remember(&remindex, + yearp, monthp, dayp, edp, + year, imonth, d, NULL); + d += 7; + } + continue; + } + + /* Easter */ + if ((*flags & ~F_MODIFIEROFFSET) == + (F_SPECIALDAY | F_VARIABLE | F_EASTER)) { + offset = 0; + if ((*flags & F_MODIFIEROFFSET) != 0) + offset = parseoffset(modifieroffset); + if (remember_yd(year, yearinfo->ieaster + offset, + &rm, &rd)) + remember(&remindex, yearp, monthp, dayp, edp, + year, rm, rd, NULL); + continue; + } + + /* Paskha */ + if ((*flags & ~F_MODIFIEROFFSET) == + (F_SPECIALDAY | F_VARIABLE | F_PASKHA)) { + offset = 0; + if ((*flags & F_MODIFIEROFFSET) != 0) + offset = parseoffset(modifieroffset); + if (remember_yd(year, yearinfo->ipaskha + offset, + &rm, &rd)) + remember(&remindex, yearp, monthp, dayp, edp, + year, rm, rd, NULL); + continue; + } + + /* Chinese New Year */ + if ((*flags & ~F_MODIFIEROFFSET) == + (F_SPECIALDAY | F_VARIABLE | F_CNY)) { + offset = 0; + if ((*flags & F_MODIFIEROFFSET) != 0) + offset = parseoffset(modifieroffset); + if (remember_yd(year, yearinfo->firstcnyday + offset, + &rm, &rd)) + remember(&remindex, yearp, monthp, dayp, edp, + year, rm, rd, NULL); + continue; + } + + /* FullMoon */ + if ((*flags & ~F_MODIFIEROFFSET) == + (F_SPECIALDAY | F_VARIABLE | F_FULLMOON)) { + int i; + + offset = 0; + if ((*flags & F_MODIFIEROFFSET) != 0) + offset = parseoffset(modifieroffset); + for (i = 0; yearinfo->ffullmoon[i] > 0; i++) { + if (remember_yd(year, + floor(yearinfo->ffullmoon[i]) + offset, + &rm, &rd)) { + ed = floattotime( + yearinfo->ffullmoon[i]); + remember(&remindex, + yearp, monthp, dayp, edp, + year, rm, rd, ed); + } + } + continue; + } + + /* NewMoon */ + if ((*flags & ~F_MODIFIEROFFSET) == + (F_SPECIALDAY | F_VARIABLE | F_NEWMOON)) { + int i; + + offset = 0; + if ((*flags & F_MODIFIEROFFSET) != 0) + offset = parseoffset(modifieroffset); + for (i = 0; yearinfo->ffullmoon[i] > 0; i++) { + if (remember_yd(year, + floor(yearinfo->fnewmoon[i]) + offset, + &rm, &rd)) { + ed = floattotime(yearinfo->fnewmoon[i]); + remember(&remindex, + yearp, monthp, dayp, edp, + year, rm, rd, ed); + } + } + continue; + } + + /* (Mar|Sep)Equinox */ + if ((*flags & ~F_MODIFIEROFFSET) == + (F_SPECIALDAY | F_VARIABLE | F_MAREQUINOX)) { + offset = 0; + if ((*flags & F_MODIFIEROFFSET) != 0) + offset = parseoffset(modifieroffset); + if (remember_yd(year, yearinfo->equinoxdays[0] + offset, + &rm, &rd)) { + ed = floattotime(yearinfo->equinoxdays[0]); + remember(&remindex, yearp, monthp, dayp, edp, + year, rm, rd, ed); + } + continue; + } + if ((*flags & ~F_MODIFIEROFFSET) == + (F_SPECIALDAY | F_VARIABLE | F_SEPEQUINOX)) { + offset = 0; + if ((*flags & F_MODIFIEROFFSET) != 0) + offset = parseoffset(modifieroffset); + if (remember_yd(year, yearinfo->equinoxdays[1] + offset, + &rm, &rd)) { + ed = floattotime(yearinfo->equinoxdays[1]); + remember(&remindex, yearp, monthp, dayp, edp, + year, rm, rd, ed); + } + continue; + } + + /* (Jun|Dec)Solstice */ + if ((*flags & ~F_MODIFIEROFFSET) == + (F_SPECIALDAY | F_VARIABLE | F_JUNSOLSTICE)) { + offset = 0; + if ((*flags & F_MODIFIEROFFSET) != 0) + offset = parseoffset(modifieroffset); + if (remember_yd(year, + yearinfo->solsticedays[0] + offset, &rm, &rd)) { + ed = floattotime(yearinfo->solsticedays[0]); + remember(&remindex, yearp, monthp, dayp, edp, + year, rm, rd, ed); + } + continue; + } + if ((*flags & ~F_MODIFIEROFFSET) == + (F_SPECIALDAY | F_VARIABLE | F_DECSOLSTICE)) { + offset = 0; + if ((*flags & F_MODIFIEROFFSET) != 0) + offset = parseoffset(modifieroffset); + if (remember_yd(year, + yearinfo->solsticedays[1] + offset, &rm, &rd)) { + ed = floattotime(yearinfo->solsticedays[1]); + remember(&remindex, yearp, monthp, dayp, edp, + year, rm, rd, ed); + } + continue; + } + + printf("Unprocessed:\n"); + debug_determinestyle(2, date, *flags, month, imonth, + dayofmonth, idayofmonth, dayofweek, idayofweek, + modifieroffset, modifierindex, specialday); + retvalsign = -1; + } + + if (retvalsign == -1) + return (-remindex - 1); + else + return (remindex); +} + +static char * +showflags(int flags) +{ + static char s[1000]; + s[0] = '\0'; + + if ((flags & F_MONTH) != 0) + strcat(s, "month "); + if ((flags & F_DAYOFWEEK) != 0) + strcat(s, "dayofweek "); + if ((flags & F_DAYOFMONTH) != 0) + strcat(s, "dayofmonth "); + if ((flags & F_MODIFIERINDEX) != 0) + strcat(s, "modifierindex "); + if ((flags & F_MODIFIEROFFSET) != 0) + strcat(s, "modifieroffset "); + if ((flags & F_SPECIALDAY) != 0) + strcat(s, "specialday "); + if ((flags & F_ALLMONTH) != 0) + strcat(s, "allmonth "); + if ((flags & F_ALLDAY) != 0) + strcat(s, "allday "); + if ((flags & F_VARIABLE) != 0) + strcat(s, "variable "); + if ((flags & F_CNY) != 0) + strcat(s, "chinesenewyear "); + if ((flags & F_PASKHA) != 0) + strcat(s, "paskha "); + if ((flags & F_EASTER) != 0) + strcat(s, "easter "); + if ((flags & F_FULLMOON) != 0) + strcat(s, "fullmoon "); + if ((flags & F_NEWMOON) != 0) + strcat(s, "newmoon "); + if ((flags & F_MAREQUINOX) != 0) + strcat(s, "marequinox "); + if ((flags & F_SEPEQUINOX) != 0) + strcat(s, "sepequinox "); + if ((flags & F_JUNSOLSTICE) != 0) + strcat(s, "junsolstice "); + if ((flags & F_DECSOLSTICE) != 0) + strcat(s, "decsolstice "); + + return s; +} + +static const char * +getmonthname(int i) +{ + if (nmonths[i - 1].len != 0 && nmonths[i - 1].name != NULL) + return (nmonths[i - 1].name); + return (months[i - 1]); +} + +static int +checkmonth(char *s, int *len, int *offset, const char **month) +{ + struct fixs *n; + int i; + + for (i = 0; fnmonths[i].name != NULL; i++) { + n = fnmonths + i; + if (strncasecmp(s, n->name, n->len) == 0) { + *len = n->len; + *month = n->name; + *offset = i + 1; + return (1); + } + } + for (i = 0; nmonths[i].name != NULL; i++) { + n = nmonths + i; + if (strncasecmp(s, n->name, n->len) == 0) { + *len = n->len; + *month = n->name; + *offset = i + 1; + return (1); + } + } + for (i = 0; fmonths[i] != NULL; i++) { + *len = strlen(fmonths[i]); + if (strncasecmp(s, fmonths[i], *len) == 0) { + *month = fmonths[i]; + *offset = i + 1; + return (1); + } + } + for (i = 0; months[i] != NULL; i++) { + if (strncasecmp(s, months[i], 3) == 0) { + *len = 3; + *month = months[i]; + *offset = i + 1; + return (1); + } + } + return (0); +} + +static const char * +getdayofweekname(int i) +{ + if (ndays[i].len != 0 && ndays[i].name != NULL) + return (ndays[i].name); + return (days[i]); +} + +static int +checkdayofweek(char *s, int *len, int *offset, const char **dow) +{ + struct fixs *n; + int i; + + for (i = 0; fndays[i].name != NULL; i++) { + n = fndays + i; + if (strncasecmp(s, n->name, n->len) == 0) { + *len = n->len; + *dow = n->name; + *offset = i; + return (1); + } + } + for (i = 0; ndays[i].name != NULL; i++) { + n = ndays + i; + if (strncasecmp(s, n->name, n->len) == 0) { + *len = n->len; + *dow = n->name; + *offset = i; + return (1); + } + } + for (i = 0; fdays[i] != NULL; i++) { + *len = strlen(fdays[i]); + if (strncasecmp(s, fdays[i], *len) == 0) { + *dow = fdays[i]; + *offset = i; + return (1); + } + } + for (i = 0; days[i] != NULL; i++) { + if (strncasecmp(s, days[i], 3) == 0) { + *len = 3; + *dow = days[i]; + *offset = i; + return (1); + } + } + return (0); +} + +static int +isonlydigits(char *s, int nostar) +{ + int i; + for (i = 0; s[i] != '\0'; i++) { + if (nostar == 0 && s[i] == '*' && s[i + 1] == '\0') + return 1; + if (!isdigit(s[i])) + return (0); + } + return (1); +} + +static int +indextooffset(char *s) +{ + int i; + struct fixs *n; + + for (i = 0; i < 6; i++) { + if (strcasecmp(s, sequences[i]) == 0) { + if (i == 5) + return (-1); + return (i + 1); + } + } + for (i = 0; i < 6; i++) { + n = nsequences + i; + if (n->len == 0) + continue; + if (strncasecmp(s, n->name, n->len) == 0) { + if (i == 5) + return (-1); + return (i + 1); + } + } + return (0); +} + +static int +parseoffset(char *s) +{ + + return strtol(s, NULL, 10); +} + +static char * +floattotime(double f) +{ + static char buf[100]; + int hh, mm, ss, i; + + f -= floor(f); + i = f * SECSPERDAY; + + hh = i / SECSPERHOUR; + i %= SECSPERHOUR; + mm = i / SECSPERMINUTE; + i %= SECSPERMINUTE; + ss = i; + + sprintf(buf, "%02d:%02d:%02d", hh, mm, ss); + return (buf); +} + +static char * +floattoday(int year, double f) +{ + static char buf[100]; + int i, m, d, hh, mm, ss; + int *cumdays = cumdaytab[isleap(year)]; + + for (i = 0; 1 + cumdays[i] < f; i++) + ;; + m = --i; + d = floor(f - 1 - cumdays[i]); + f -= floor(f); + i = f * SECSPERDAY; + + hh = i / SECSPERHOUR; + i %= SECSPERHOUR; + mm = i / SECSPERMINUTE; + i %= SECSPERMINUTE; + ss = i; + + sprintf(buf, "%02d-%02d %02d:%02d:%02d", m, d, hh, mm, ss); + return (buf); +} + +void +dodebug(char *what) +{ + int year; + + printf("UTCOffset: %g\n", UTCOffset); + printf("eastlongitude: %d\n", EastLongitude); + + if (strcmp(what, "moon") == 0) { + double ffullmoon[MAXMOONS], fnewmoon[MAXMOONS]; + int i; + + for (year = year1; year <= year2; year++) { + fpom(year, UTCOffset, ffullmoon, fnewmoon); + printf("Full moon %d:\t", year); + for (i = 0; ffullmoon[i] >= 0; i++) { + printf("%g (%s) ", ffullmoon[i], + floattoday(year, ffullmoon[i])); + } + printf("\nNew moon %d:\t", year); + for (i = 0; fnewmoon[i] >= 0; i++) { + printf("%g (%s) ", fnewmoon[i], + floattoday(year, fnewmoon[i])); + } + printf("\n"); + + } + + return; + } + + if (strcmp(what, "sun") == 0) { + double equinoxdays[2], solsticedays[2]; + for (year = year1; year <= year2; year++) { + printf("Sun in %d:\n", year); + fequinoxsolstice(year, UTCOffset, equinoxdays, + solsticedays); + printf("e[0] - %g (%s)\n", + equinoxdays[0], + floattoday(year, equinoxdays[0])); + printf("e[1] - %g (%s)\n", + equinoxdays[1], + floattoday(year, equinoxdays[1])); + printf("s[0] - %g (%s)\n", + solsticedays[0], + floattoday(year, solsticedays[0])); + printf("s[1] - %g (%s)\n", + solsticedays[1], + floattoday(year, solsticedays[1])); + } + return; + } +} diff --git a/usr.bin/calendar/paskha.c b/usr.bin/calendar/paskha.c index e713f5f..373ee5d 100644 --- a/usr.bin/calendar/paskha.c +++ b/usr.bin/calendar/paskha.c @@ -1,4 +1,4 @@ -/* +/*- * Copyright (C) 1993-1996 by Andrey A. Chernov, Moscow, Russia. * All rights reserved. * @@ -36,55 +36,22 @@ __FBSDID("$FreeBSD$"); #define PASKHA "paskha" #define PASKHALEN (sizeof(PASKHA) - 1) -static int paskha(int); - /* return year day for Orthodox Easter using Gauss formula */ /* (old style result) */ -static int +int paskha(int R) /*year*/ { int a, b, c, d, e; static int x = 15; static int y = 6; + int *cumday; a = R % 19; b = R % 4; c = R % 7; d = (19 * a + x) % 30; e = (2 * b + 4 * c + 6 * d + y) % 7; - return (((cumdays[3] + 1) + 22) + (d + e)); -} - -/* return year day for Orthodox Easter depending days */ - -int -getpaskha(char *s, int year) -{ - int offset; - - if (strncasecmp(s, PASKHA, PASKHALEN) == 0) - s += PASKHALEN; - else if (npaskha.name != NULL - && strncasecmp(s, npaskha.name, npaskha.len) == 0) - s += npaskha.len; - else - return 0; - - /* Paskha+1 or Paskha-2 - * ^ ^ */ - - switch (*s) { - - case '-': - case '+': - offset = atoi(s); - break; - - default: - offset = 0; - break; - } - - return (paskha(year) + offset + 13 /* new style */); + cumday = cumdaytab[isleap(R)]; + return (((cumday[3] + 1) + 22) + (d + e)); } diff --git a/usr.bin/calendar/pathnames.h b/usr.bin/calendar/pathnames.h index cacbd25..64173d1 100644 --- a/usr.bin/calendar/pathnames.h +++ b/usr.bin/calendar/pathnames.h @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * diff --git a/usr.bin/calendar/pom.c b/usr.bin/calendar/pom.c new file mode 100644 index 0000000..95399ae --- /dev/null +++ b/usr.bin/calendar/pom.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software posted to USENET. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static const char sccsid[] = "@(#)pom.c 8.1 (Berkeley) 5/31/93"; +#endif /* not lint */ +#endif +#include +__FBSDID("$FreeBSD$"); + +/* + * Phase of the Moon. Calculates the current phase of the moon. + * Based on routines from `Practical Astronomy with Your Calculator', + * by Duffett-Smith. Comments give the section from the book that + * particular piece of code was adapted from. + * + * -- Keith E. Brandt VIII 1984 + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "calendar.h" + +#ifndef PI +#define PI 3.14159265358979323846 +#endif +#define EPOCH 85 +#define EPSILONg 279.611371 /* solar ecliptic long at EPOCH */ +#define RHOg 282.680403 /* solar ecliptic long of perigee at EPOCH */ +#define ECCEN 0.01671542 /* solar orbit eccentricity */ +#define lzero 18.251907 /* lunar mean long at EPOCH */ +#define Pzero 192.917585 /* lunar mean long of perigee at EPOCH */ +#define Nzero 55.204723 /* lunar mean long of node at EPOCH */ +#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) + +static void adj360(double *); +static double dtor(double); +static double potm(double onday); +static double potm_minute(double onday, int olddir); + +void +pom(int year, double utcoffset, int *fms, int *nms) +{ + double ffms[MAXMOONS]; + double fnms[MAXMOONS]; + int i, j; + + fpom(year, utcoffset, ffms, fnms); + + j = 0; + for (i = 0; ffms[i] != 0; i++) + fms[j++] = round(ffms[i]); + fms[i] = -1; + for (i = 0; fnms[i] != 0; i++) + nms[i] = round(fnms[i]); + nms[i] = -1; +} + +void +fpom(int year, double utcoffset, double *ffms, double *fnms) +{ + time_t tt; + struct tm GMT, tmd_today, tmd_tomorrow; + double days_today, days_tomorrow, today, tomorrow; + int cnt, d; + int yeardays; + int olddir, newdir; + double *pfnms, *pffms, t; + + pfnms = fnms; + pffms = ffms; + + /* + * We take the phase of the moon one second before and one second + * after midnight. + */ + memset(&tmd_today, 0, sizeof(tmd_today)); + tmd_today.tm_year = year - 1900; + tmd_today.tm_mon = 0; + tmd_today.tm_mday = -1; /* 31 December */ + tmd_today.tm_hour = 23; + tmd_today.tm_min = 59; + tmd_today.tm_sec = 59; + memset(&tmd_tomorrow, 0, sizeof(tmd_tomorrow)); + tmd_tomorrow.tm_year = year - 1900; + tmd_tomorrow.tm_mon = 0; + tmd_tomorrow.tm_mday = 0; /* 01 January */ + tmd_tomorrow.tm_hour = 0; + tmd_tomorrow.tm_min = 0; + tmd_tomorrow.tm_sec = 1; + + tt = mktime(&tmd_today); + gmtime_r(&tt, &GMT); + yeardays = 0; + for (cnt = EPOCH; cnt < GMT.tm_year; ++cnt) + yeardays += isleap(1900 + cnt) ? DAYSPERLEAPYEAR : DAYSPERYEAR; + days_today = (GMT.tm_yday + 1) + ((GMT.tm_hour + + (GMT.tm_min / FSECSPERMINUTE) + (GMT.tm_sec / FSECSPERHOUR)) / + FHOURSPERDAY); + days_today += yeardays; + + tt = mktime(&tmd_tomorrow); + gmtime_r(&tt, &GMT); + yeardays = 0; + for (cnt = EPOCH; cnt < GMT.tm_year; ++cnt) + yeardays += isleap(1900 + cnt) ? DAYSPERLEAPYEAR : DAYSPERYEAR; + days_tomorrow = (GMT.tm_yday + 1) + ((GMT.tm_hour + + (GMT.tm_min / FSECSPERMINUTE) + (GMT.tm_sec / FSECSPERHOUR)) / + FHOURSPERDAY); + days_tomorrow += yeardays; + + today = potm(days_today); /* 30 December 23:59:59 */ + tomorrow = potm(days_tomorrow); /* 31 December 00:00:01 */ + olddir = today > tomorrow ? -1 : +1; + + yeardays = 1 + isleap(year) ? DAYSPERLEAPYEAR : DAYSPERYEAR; /* reuse */ + for (d = 0; d <= yeardays; d++) { + today = potm(days_today); + tomorrow = potm(days_tomorrow); + newdir = today > tomorrow ? -1 : +1; + if (olddir != newdir) { + t = potm_minute(days_today - 1, olddir) + + utcoffset / FHOURSPERDAY; + if (olddir == -1 && newdir == +1) { + *pfnms = d - 1 + t; + pfnms++; + } else if (olddir == +1 && newdir == -1) { + *pffms = d - 1 + t; + pffms++; + } + } + olddir = newdir; + days_today++; + days_tomorrow++; + } + *pffms = -1; + *pfnms = -1; +} + +static double +potm_minute(double onday, int olddir) { + double period = FSECSPERDAY / 2.0; + double p1, p2; + double before, after; + int newdir; + +// printf("---> days:%g olddir:%d\n", days, olddir); + + p1 = onday + (period / SECSPERDAY); + period /= 2; + + while (period > 30) { /* half a minute */ +// printf("period:%g - p1:%g - ", period, p1); + p2 = p1 + (2.0 / SECSPERDAY); + before = potm(p1); + after = potm(p2); +// printf("before:%10.10g - after:%10.10g\n", before, after); + newdir = before < after ? -1 : +1; + if (olddir != newdir) + p1 += (period / SECSPERDAY); + else + p1 -= (period / SECSPERDAY); + period /= 2; +// printf("newdir:%d - p1:%10.10f - period:%g\n", +// newdir, p1, period); + } + p1 -= floor(p1); + //exit(0); + return (p1); +} + +/* + * potm -- + * return phase of the moon, as a percentage [0 ... 100] + */ +static double +potm(double onday) +{ + double N, Msol, Ec, LambdaSol, l, Mm, Ev, Ac, A3, Mmprime; + double A4, lprime, V, ldprime, D, Nm; + + N = 360 * onday / 365.2422; /* sec 42 #3 */ + adj360(&N); + Msol = N + EPSILONg - RHOg; /* sec 42 #4 */ + adj360(&Msol); + Ec = 360 / PI * ECCEN * sin(dtor(Msol)); /* sec 42 #5 */ + LambdaSol = N + Ec + EPSILONg; /* sec 42 #6 */ + adj360(&LambdaSol); + l = 13.1763966 * onday + lzero; /* sec 61 #4 */ + adj360(&l); + Mm = l - (0.1114041 * onday) - Pzero; /* sec 61 #5 */ + adj360(&Mm); + Nm = Nzero - (0.0529539 * onday); /* sec 61 #6 */ + adj360(&Nm); + Ev = 1.2739 * sin(dtor(2*(l - LambdaSol) - Mm)); /* sec 61 #7 */ + Ac = 0.1858 * sin(dtor(Msol)); /* sec 61 #8 */ + A3 = 0.37 * sin(dtor(Msol)); + Mmprime = Mm + Ev - Ac - A3; /* sec 61 #9 */ + Ec = 6.2886 * sin(dtor(Mmprime)); /* sec 61 #10 */ + A4 = 0.214 * sin(dtor(2 * Mmprime)); /* sec 61 #11 */ + lprime = l + Ev + Ec - Ac + A4; /* sec 61 #12 */ + V = 0.6583 * sin(dtor(2 * (lprime - LambdaSol))); /* sec 61 #13 */ + ldprime = lprime + V; /* sec 61 #14 */ + D = ldprime - LambdaSol; /* sec 63 #2 */ + return(50 * (1 - cos(dtor(D)))); /* sec 63 #3 */ +} + +/* + * dtor -- + * convert degrees to radians + */ +static double +dtor(double deg) +{ + + return(deg * PI / 180); +} + +/* + * adj360 -- + * adjust value so 0 <= deg <= 360 + */ +static void +adj360(double *deg) +{ + + for (;;) + if (*deg < 0) + *deg += 360; + else if (*deg > 360) + *deg -= 360; + else + break; +} diff --git a/usr.bin/calendar/sunpos.c b/usr.bin/calendar/sunpos.c new file mode 100644 index 0000000..1083c3b --- /dev/null +++ b/usr.bin/calendar/sunpos.c @@ -0,0 +1,447 @@ +/*- + * Copyright (c) 2009-2010 Edwin Groothuis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * This code is created to match the formulas available at: + * Formula and examples obtained from "How to Calculate alt/az: SAAO" at + * http://www.saao.ac.za/public-info/sun-moon-stars/sun-index/how-to-calculate-altaz/ + */ + +#include +#include +#include +#include +#include +#include +#include "calendar.h" + +#define D2R(m) ((m) / 180 * M_PI) +#define R2D(m) ((m) * 180 / M_PI) + +#define SIN(x) (sin(D2R(x))) +#define COS(x) (cos(D2R(x))) +#define TAN(x) (tan(D2R(x))) +#define ASIN(x) (R2D(asin(x))) +#define ATAN(x) (R2D(atan(x))) + +#ifdef NOTDEF +static void +comp(char *s, double v, double c) +{ + + printf("%-*s %*g %*g %*g\n", 15, s, 15, v, 15, c, 15, v - c); +} + +int expY; +double expZJ = 30.5; +double expUTHM = 8.5; +double expD = 34743.854; +double expT = 0.9512349; +double expL = 324.885; +double expM = 42.029; +double expepsilon = 23.4396; +double explambda = 326.186; +double expalpha = 328.428; +double expDEC = -12.789; +double expeastlongitude = 17.10; +double explatitude = -22.57; +double expHA = -37.673; +double expALT = 49.822; +double expAZ = 67.49; +#endif + +static double +fixup(double *d) +{ + + if (*d < 0) { + while (*d < 0) + *d += 360; + } else { + while (*d > 360) + *d -= 360; + } + + return (*d); +} + +static double ZJtable[] = { + 0, -0.5, 30.5, 58.5, 89.5, 119.5, 150.5, 180.5, 211.5, 242.5, 272.5, 303.5, 333.5 }; + +static void +sunpos(int inYY, int inMM, int inDD, double UTCOFFSET, int inHOUR, int inMIN, + int inSEC, double eastlongitude, double latitude, double *L, double *DEC) +{ + int Y; + double ZJ, D, T, M, epsilon, lambda, alpha, HA, UTHM; + + ZJ = ZJtable[inMM]; + if (inMM <= 2 && isleap(inYY)) + ZJ -= 1.0; + + UTHM = inHOUR + inMIN / FMINSPERHOUR + inSEC / FSECSPERHOUR - UTCOFFSET; + Y = inYY - 1900; /* 1 */ + D = floor(365.25 * Y) + ZJ + inDD + UTHM / FHOURSPERDAY; /* 3 */ + T = D / 36525.0; /* 4 */ + *L = 279.697 + 36000.769 * T; /* 5 */ + fixup(L); + M = 358.476 + 35999.050 * T; /* 6 */ + fixup(&M); + epsilon = 23.452 - 0.013 * T; /* 7 */ + fixup(&epsilon); + + lambda = *L + (1.919 - 0.005 * T) * SIN(M) + 0.020 * SIN(2 * M);/* 8 */ + fixup(&lambda); + alpha = ATAN(TAN(lambda) * COS(epsilon)); /* 9 */ + + /* Alpha should be in the same quadrant as lamba */ + { + int lssign = sin(D2R(lambda)) < 0 ? -1 : 1; + int lcsign = cos(D2R(lambda)) < 0 ? -1 : 1; + while (((sin(D2R(alpha)) < 0) ? -1 : 1) != lssign + || ((cos(D2R(alpha)) < 0) ? -1 : 1) != lcsign) + alpha += 90.0; + } + fixup(&alpha); + + *DEC = ASIN(SIN(lambda) * SIN(epsilon)); /* 10 */ + fixup(DEC); + fixup(&eastlongitude); + HA = *L - alpha + 180 + 15 * UTHM + eastlongitude; /* 12 */ + fixup(&HA); + fixup(&latitude); +#ifdef NOTDEF + printf("%02d/%02d %02d:%02d:%02d l:%g d:%g h:%g\n", + inMM, inDD, inHOUR, inMIN, inSEC, latitude, *DEC, HA); +#endif + return; + + /* + * The following calculations are not used, so to save time + * they are not calculated. + */ +#ifdef NOTDEF + *ALT = ASIN(SIN(latitude) * SIN(*DEC) + + COS(latitude) * COS(*DEC) * COS(HA)); /* 13 */ + fixup(ALT); + *AZ = ATAN(SIN(HA) / + (COS(HA) * SIN(latitude) - TAN(*DEC) * COS(latitude))); /* 14 */ + + if (*ALT > 180) + *ALT -= 360; + if (*ALT < -180) + *ALT += 360; + printf("a:%g a:%g\n", *ALT, *AZ); +#endif + +#ifdef NOTDEF + printf("Y:\t\t\t %d\t\t %d\t\t %d\n", Y, expY, Y - expY); + comp("ZJ", ZJ, expZJ); + comp("UTHM", UTHM, expUTHM); + comp("D", D, expD); + comp("T", T, expT); + comp("L", L, fixup(&expL)); + comp("M", M, fixup(&expM)); + comp("epsilon", epsilon, fixup(&expepsilon)); + comp("lambda", lambda, fixup(&explambda)); + comp("alpha", alpha, fixup(&expalpha)); + comp("DEC", DEC, fixup(&expDEC)); + comp("eastlongitude", eastlongitude, fixup(&expeastlongitude)); + comp("latitude", latitude, fixup(&explatitude)); + comp("HA", HA, fixup(&expHA)); + comp("ALT", ALT, fixup(&expALT)); + comp("AZ", AZ, fixup(&expAZ)); +#endif +} + + +#define SIGN(a) (((a) > 180) ? -1 : 1) +#define ANGLE(a, b) (((a) < (b)) ? 1 : -1) +#define SHOUR(s) ((s) / 3600) +#define SMIN(s) (((s) % 3600) / 60) +#define SSEC(s) ((s) % 60) +#define HOUR(h) ((h) / 4) +#define MIN(h) (15 * ((h) % 4)) +#define SEC(h) 0 +#define DEBUG1(y, m, d, hh, mm, pdec, dec) \ + printf("%4d-%02d-%02d %02d:%02d:00 - %7.7g -> %7.7g\n", \ + y, m, d, hh, mm, pdec, dec) +#define DEBUG2(y, m, d, hh, mm, pdec, dec, pang, ang) \ + printf("%4d-%02d-%02d %02d:%02d:00 - %7.7g -> %7.7g - %d -> %d\n", \ + y, m, d, hh, mm, pdec, dec, pang, ang) +void +equinoxsolstice(int year, double UTCoffset, int *equinoxdays, int *solsticedays) +{ + double fe[2], fs[2]; + + fequinoxsolstice(year, UTCoffset, fe, fs); + equinoxdays[0] = round(fe[0]); + equinoxdays[1] = round(fe[1]); + solsticedays[0] = round(fs[0]); + solsticedays[1] = round(fs[1]); +} + +void +fequinoxsolstice(int year, double UTCoffset, double *equinoxdays, double *solsticedays) +{ + double dec, prevdec, L; + int h, d, prevangle, angle; + int found = 0; + + double decleft, decright, decmiddle; + int dial, s; + + int *cumdays; + cumdays = cumdaytab[isleap(year)]; + + /* + * Find the first equinox, somewhere in March: + * It happens when the returned value "dec" goes from + * [350 ... 360> -> [0 ... 10] + */ + found = 0; + prevdec = 350; + for (d = 18; d < 31; d++) { +// printf("Comparing day %d to %d.\n", d, d+1); + sunpos(year, 3, d, UTCoffset, 0, 0, 0, 0.0, 0.0, &L, &decleft); + sunpos(year, 3, d + 1, UTCoffset, 0, 0, 0, 0.0, 0.0, + &L, &decright); +// printf("Found %g and %g.\n", decleft, decright); + if (SIGN(decleft) == SIGN(decright)) + continue; + + dial = SECSPERDAY; + s = SECSPERDAY / 2; + while (s > 0) { +// printf("Obtaining %d (%02d:%02d)\n", +// dial, SHOUR(dial), SMIN(dial)); + sunpos(year, 3, d, UTCoffset, + SHOUR(dial), SMIN(dial), SSEC(dial), + 0.0, 0.0, &L, &decmiddle); +// printf("Found %g\n", decmiddle); + if (SIGN(decleft) == SIGN(decmiddle)) { + decleft = decmiddle; + dial += s; + } else { + decright = decmiddle; + dial -= s; + } +// printf("New boundaries: %g - %g\n", decleft, decright); + + s /= 2; + } + equinoxdays[0] = 1 + cumdays[3] + d + (dial / FSECSPERDAY); + break; + } + + /* Find the second equinox, somewhere in September: + * It happens when the returned value "dec" goes from + * [10 ... 0] -> <360 ... 350] + */ + found = 0; + prevdec = 10; + for (d = 18; d < 31; d++) { +// printf("Comparing day %d to %d.\n", d, d+1); + sunpos(year, 9, d, UTCoffset, 0, 0, 0, 0.0, 0.0, &L, &decleft); + sunpos(year, 9, d + 1, UTCoffset, 0, 0, 0, 0.0, 0.0, + &L, &decright); +// printf("Found %g and %g.\n", decleft, decright); + if (SIGN(decleft) == SIGN(decright)) + continue; + + dial = SECSPERDAY; + s = SECSPERDAY / 2; + while (s > 0) { +// printf("Obtaining %d (%02d:%02d)\n", +// dial, SHOUR(dial), SMIN(dial)); + sunpos(year, 9, d, UTCoffset, + SHOUR(dial), SMIN(dial), SSEC(dial), + 0.0, 0.0, &L, &decmiddle); +// printf("Found %g\n", decmiddle); + if (SIGN(decleft) == SIGN(decmiddle)) { + decleft = decmiddle; + dial += s; + } else { + decright = decmiddle; + dial -= s; + } +// printf("New boundaries: %g - %g\n", decleft, decright); + + s /= 2; + } + equinoxdays[1] = 1 + cumdays[9] + d + (dial / FSECSPERDAY); + break; + } + + /* + * Find the first solstice, somewhere in June: + * It happens when the returned value "dec" peaks + * [40 ... 45] -> [45 ... 40] + */ + found = 0; + prevdec = 0; + prevangle = 1; + for (d = 18; d < 31; d++) { + for (h = 0; h < 4 * HOURSPERDAY; h++) { + sunpos(year, 6, d, UTCoffset, HOUR(h), MIN(h), SEC(h), + 0.0, 0.0, &L, &dec); + angle = ANGLE(prevdec, dec); + if (prevangle != angle) { +#ifdef NOTDEF + DEBUG2(year, 6, d, HOUR(h), MIN(h), + prevdec, dec, prevangle, angle); +#endif + solsticedays[0] = 1 + cumdays[6] + d + + ((h / 4.0) / 24.0); + found = 1; + break; + } + prevdec = dec; + prevangle = angle; + } + if (found) + break; + } + + /* + * Find the second solstice, somewhere in December: + * It happens when the returned value "dec" peaks + * [315 ... 310] -> [310 ... 315] + */ + found = 0; + prevdec = 360; + prevangle = -1; + for (d = 18; d < 31; d++) { + for (h = 0; h < 4 * HOURSPERDAY; h++) { + sunpos(year, 12, d, UTCoffset, HOUR(h), MIN(h), SEC(h), + 0.0, 0.0, &L, &dec); + angle = ANGLE(prevdec, dec); + if (prevangle != angle) { +#ifdef NOTDEF + DEBUG2(year, 12, d, HOUR(h), MIN(h), + prevdec, dec, prevangle, angle); +#endif + solsticedays[1] = 1 + cumdays[12] + d + + ((h / 4.0) / 24.0); + found = 1; + break; + } + prevdec = dec; + prevangle = angle; + } + if (found) + break; + } + + return; +} + +int +calculatesunlongitude30(int year, int degreeGMToffset, int *ichinesemonths) +{ + int m, d, h; + double dec; + double curL, prevL; + int *pichinesemonths, *monthdays, *cumdays, i; + int firstmonth330 = -1; + + cumdays = cumdaytab[isleap(year)]; + monthdays = mondaytab[isleap(year)]; + pichinesemonths = ichinesemonths; + + h = 0; + sunpos(year - 1, 12, 31, + -24 * (degreeGMToffset / 360.0), + HOUR(h), MIN(h), SEC(h), 0.0, 0.0, &prevL, &dec); + + for (m = 1; m <= 12; m++) { + for (d = 1; d <= monthdays[m]; d++) { + for (h = 0; h < 4 * HOURSPERDAY; h++) { + sunpos(year, m, d, + -24 * (degreeGMToffset / 360.0), + HOUR(h), MIN(h), SEC(h), + 0.0, 0.0, &curL, &dec); + if (curL < 180 && prevL > 180) { + *pichinesemonths = cumdays[m] + d; +#ifdef DEBUG +printf("%04d-%02d-%02d %02d:%02d - %d %g\n", + year, m, d, HOUR(h), MIN(h), *pichinesemonths, curL); +#endif + pichinesemonths++; + } else { + for (i = 0; i <= 360; i += 30) + if (curL > i && prevL < i) { + *pichinesemonths = + cumdays[m] + d; +#ifdef DEBUG +printf("%04d-%02d-%02d %02d:%02d - %d %g\n", + year, m, d, HOUR(h), MIN(h), *pichinesemonths, curL); +#endif + if (i == 330) + firstmonth330 = *pichinesemonths; + pichinesemonths++; + } + } + prevL = curL; + } + } + } + *pichinesemonths = -1; + return (firstmonth330); +} + +#ifdef NOTDEF +int +main(int argc, char **argv) +{ +/* + year Mar June Sept Dec + day time day time day time day time + 2004 20 06:49 21 00:57 22 16:30 21 12:42 + 2005 20 12:33 21 06:46 22 22:23 21 18:35 + 2006 20 18:26 21 12:26 23 04:03 22 00:22 + 2007 21 00:07 21 18:06 23 09:51 22 06:08 + 2008 20 05:48 20 23:59 22 15:44 21 12:04 + 2009 20 11:44 21 05:45 22 21:18 21 17:47 + 2010 20 17:32 21 11:28 23 03:09 21 23:38 + 2011 20 23:21 21 17:16 23 09:04 22 05:30 + 2012 20 05:14 20 23:09 22 14:49 21 11:11 + 2013 20 11:02 21 05:04 22 20:44 21 17:11 + 2014 20 16:57 21 10:51 23 02:29 21 23:03 + 2015 20 22:45 21 16:38 23 08:20 22 04:48 + 2016 20 04:30 20 22:34 22 14:21 21 10:44 + 2017 20 10:28 21 04:24 22 20:02 21 16:28 +*/ + + int eq[2], sol[2]; + equinoxsolstice(strtol(argv[1], NULL, 10), 0.0, eq, sol); + printf("%d - %d - %d - %d\n", eq[0], sol[0], eq[1], sol[1]); + return(0); +} +#endif -- cgit v1.1