summaryrefslogtreecommitdiffstats
path: root/usr.bin/calendar
diff options
context:
space:
mode:
authoredwin <edwin@FreeBSD.org>2010-03-29 06:49:20 +0000
committeredwin <edwin@FreeBSD.org>2010-03-29 06:49:20 +0000
commit914d5a5c2da11a9119f44c4469b7820a3471ddbb (patch)
tree3d2119bf9389f55ad0bcafa6f89a7fa4865924d6 /usr.bin/calendar
parentda13321f0367c93e6227866043622792c016f3a2 (diff)
downloadFreeBSD-src-914d5a5c2da11a9119f44c4469b7820a3471ddbb.zip
FreeBSD-src-914d5a5c2da11a9119f44c4469b7820a3471ddbb.tar.gz
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
Diffstat (limited to 'usr.bin/calendar')
-rw-r--r--usr.bin/calendar/Makefile4
-rw-r--r--usr.bin/calendar/calendar.182
-rw-r--r--usr.bin/calendar/calendar.c106
-rw-r--r--usr.bin/calendar/calendar.h178
-rw-r--r--usr.bin/calendar/dates.c451
-rw-r--r--usr.bin/calendar/day.c412
-rw-r--r--usr.bin/calendar/events.c125
-rw-r--r--usr.bin/calendar/io.c368
-rw-r--r--usr.bin/calendar/locale.c168
-rw-r--r--usr.bin/calendar/ostern.c46
-rw-r--r--usr.bin/calendar/parsedata.c1008
-rw-r--r--usr.bin/calendar/paskha.c43
-rw-r--r--usr.bin/calendar/pathnames.h2
-rw-r--r--usr.bin/calendar/pom.c280
-rw-r--r--usr.bin/calendar/sunpos.c447
15 files changed, 2928 insertions, 792 deletions
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=<locale_name>
in the calendar file as early as possible.
-To handle national Easter
-names in the calendars
-.Dq Easter=<national_name>
-(for Catholic Easter) or
-.Dq Paskha=<national_name>
-(for Orthodox Easter) can be used.
+.Pp
+To handle the local name of sequences, you can specify them as:
+.Dq SEQUENCE=<first> <second> <third> <fourth> <fifth> <last>
+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 <pwd.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <time.h>
#include <unistd.h>
#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 <sys/types.h>
#include <sys/uio.h>
+#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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <err.h>
+#include <time.h>
+
+#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 <m1 .. m2>
+ * - 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-<m1 .. 12]
+ * - Take all days from <y1 .. y2>
+ * - 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <ctype.h>
#include <err.h>
#include <locale.h>
#include <stdio.h>
@@ -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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/time.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/uio.h>
#include <sys/wait.h>
#include <ctype.h>
#include <err.h>
@@ -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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#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 <wosch@FreeBSD.org>. 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+
+#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 <sys/cdefs.h>
+__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 <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <sysexits.h>
+#include <time.h>
+#include <unistd.h>
+
+#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 <sys/cdefs.h>
+__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 <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <math.h>
+#include <string.h>
+#include <time.h>
+#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
OpenPOWER on IntegriCloud