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:
parent
da13321f03
commit
914d5a5c2d
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
451
usr.bin/calendar/dates.c
Normal 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;
|
||||
}
|
@ -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
125
usr.bin/calendar/events.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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
168
usr.bin/calendar/locale.c
Normal 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;
|
||||
}
|
@ -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
1008
usr.bin/calendar/parsedata.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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));
|
||||
}
|
||||
|
@ -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
280
usr.bin/calendar/pom.c
Normal 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
447
usr.bin/calendar/sunpos.c
Normal 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
|
Loading…
Reference in New Issue
Block a user