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
This commit is contained in:
Edwin Groothuis 2010-03-29 06:49:20 +00:00
parent 9ba84a88b8
commit 2b84020d5c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=205821
15 changed files with 2938 additions and 802 deletions

View File

@ -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

View File

@ -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.

View File

@ -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);
}

View File

@ -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
extern int f_dayAfter; /* days after current date */
extern int f_dayBefore; /* days before current date */
extern int Friday; /* day before weekend */
#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"
#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);

451
usr.bin/calendar/dates.c Normal file
View File

@ -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;
}

View File

@ -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)
{
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
settime(time_t now)
settimes(time_t now, int before, int after, int friday, struct tm *tp1, struct tm *tp2)
{
char *oldl, *lbufp;
struct tm tp;
localtime_r(&now, &tp);
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;
if (after == 0 && before == 0 && friday != -1)
after = tp.tm_wday == friday ? 3 : 1;
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;
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);
}

125
usr.bin/calendar/events.c Normal file
View File

@ -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;
}
}
}

View File

@ -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,248 +126,89 @@ 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);
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 (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);
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);
/*
* If the line starts with a tab, the data has to be
* added to the previous line
*/
if (buf[0] == '\t') {
for (i = 0; i < count; i++)
event_continue(events[i], buf);
continue;
}
/* Get rid of leading spaces (non-standard) */
while (isspace(buf[0]))
memcpy(buf, buf + 1, strlen(buf) - 1);
/* No tab in the line, then not a valid line */
if ((pp = strchr(buf, '\t')) == NULL)
continue;
/* Trim spaces in front of the tab */
while (isspace(pp[-1]))
pp--;
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;
}
/* Find the last tab */
while (pp[1] == '\t')
pp++;
if (d_first < 0)
d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
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]);
}
}
event_print_all(fp, events);
event_print_all(fp);
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.
*/
month = 1;
while (month <= 12) {
if (day <= cumdays[month])
break;
month++;
}
month--;
day -= cumdays[month];
#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
*/
for (e = events; e != NULL; e = e_next) {
e_next = e->next;
if (month != e->month || day != e->day)
continue;
(void)fprintf(fp, "%s%c%s\n", e->date,
e->var ? '*' : ' ', e->text);
}
}
}
int
getfield(char *p, char **endp, int *flags)
{
int val, var;
char *start, savech;
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;
/* variable weekday */
if ((var = getdayvar(start)) != 0) {
if (var <= 5 && var >= -4)
val += var * 10;
#ifdef DEBUG
printf("var: %d\n", var);
#endif
}
}
/* 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);
}
FILE *
opencal(void)
{
@ -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]);

168
usr.bin/calendar/locale.c Normal file
View File

@ -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;
}

View File

@ -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);
}

1008
usr.bin/calendar/parsedata.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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));
}

View File

@ -1,4 +1,4 @@
/*
/*-
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*

280
usr.bin/calendar/pom.c Normal file
View File

@ -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;
}

447
usr.bin/calendar/sunpos.c Normal file
View File

@ -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