svn commit: r205821 - head/usr.bin/calendar

Edwin Groothuis edwin at FreeBSD.org
Mon Mar 29 06:49:20 UTC 2010


Author: edwin
Date: Mon Mar 29 06:49:20 2010
New Revision: 205821
URL: http://svn.freebsd.org/changeset/base/205821

Log:
  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

Added:
  head/usr.bin/calendar/dates.c   (contents, props changed)
  head/usr.bin/calendar/events.c   (contents, props changed)
  head/usr.bin/calendar/locale.c   (contents, props changed)
  head/usr.bin/calendar/parsedata.c   (contents, props changed)
  head/usr.bin/calendar/pom.c   (contents, props changed)
  head/usr.bin/calendar/sunpos.c   (contents, props changed)
Modified:
  head/usr.bin/calendar/Makefile
  head/usr.bin/calendar/calendar.1
  head/usr.bin/calendar/calendar.c
  head/usr.bin/calendar/calendar.h
  head/usr.bin/calendar/day.c
  head/usr.bin/calendar/io.c
  head/usr.bin/calendar/ostern.c
  head/usr.bin/calendar/paskha.c
  head/usr.bin/calendar/pathnames.h

Modified: head/usr.bin/calendar/Makefile
==============================================================================
--- head/usr.bin/calendar/Makefile	Mon Mar 29 06:31:58 2010	(r205820)
+++ head/usr.bin/calendar/Makefile	Mon Mar 29 06:49:20 2010	(r205821)
@@ -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

Modified: head/usr.bin/calendar/calendar.1
==============================================================================
--- head/usr.bin/calendar/calendar.1	Mon Mar 29 06:31:58 2010	(r205820)
+++ head/usr.bin/calendar/calendar.1	Mon Mar 29 06:49:20 2010	(r205821)
@@ -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 num
 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 followe
 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
 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 correctl
 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.

Modified: head/usr.bin/calendar/calendar.c
==============================================================================
--- head/usr.bin/calendar/calendar.c	Mon Mar 29 06:31:58 2010	(r205820)
+++ head/usr.bin/calendar/calendar.c	Mon Mar 29 06:49:20 2010	(r205821)
@@ -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);
 }

Modified: head/usr.bin/calendar/calendar.h
==============================================================================
--- head/usr.bin/calendar/calendar.h	Mon Mar 29 06:31:58 2010	(r205820)
+++ head/usr.bin/calendar/calendar.h	Mon Mar 29 06:49:20 2010	(r205821)
@@ -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 */
-
-extern int	f_dayAfter;	/* days after current date */
-extern int	f_dayBefore;	/* days before current date */
-extern int	Friday;		/* day before weekend */
+/* Flags to determine the returned values by determinestyle() in parsedata.c */
+#define	F_NONE			0x00000
+#define	F_MONTH			0x00001
+#define	F_DAYOFWEEK		0x00002
+#define	F_DAYOFMONTH		0x00004
+#define	F_MODIFIERINDEX		0x00008
+#define	F_MODIFIEROFFSET	0x00010
+#define	F_SPECIALDAY		0x00020
+#define	F_ALLMONTH		0x00040
+#define	F_ALLDAY		0x00080
+#define	F_VARIABLE		0x00100
+#define	F_EASTER		0x00200
+#define	F_CNY			0x00400
+#define	F_PASKHA		0x00800
+#define	F_NEWMOON		0x01000
+#define	F_FULLMOON		0x02000
+#define	F_MAREQUINOX		0x04000
+#define	F_SEPEQUINOX		0x08000
+#define	F_JUNSOLSTICE		0x10000
+#define	F_DECSOLSTICE		0x20000
+
+#define	STRING_EASTER		"Easter"
+#define	STRING_PASKHA		"Paskha"
+#define	STRING_CNY		"ChineseNewYear"
+#define STRING_NEWMOON		"NewMoon"
+#define STRING_FULLMOON		"FullMoon"
+#define STRING_MAREQUINOX	"MarEquinox"
+#define STRING_SEPEQUINOX	"SepEquinox"
+#define STRING_JUNSOLSTICE	"JunSolstice"
+#define STRING_DECSOLSTICE	"DecSolstice"
+
+#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);

Added: head/usr.bin/calendar/dates.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.bin/calendar/dates.c	Mon Mar 29 06:49:20 2010	(r205821)
@@ -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;
+}

Modified: head/usr.bin/calendar/day.c
==============================================================================
--- head/usr.bin/calendar/day.c	Mon Mar 29 06:31:58 2010	(r205820)
+++ head/usr.bin/calendar/day.c	Mon Mar 29 06:49:20 2010	(r205821)
@@ -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];
-
-

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list