ftp.nice.ch/pub/next/unix/calendars/remind.3.0.13.N.bs.tar.gz#/remind-3.0.13/hbcal.c

This is hbcal.c in view mode; [Download] [Up]

/***************************************************************/
/*                                                             */
/*  HBCAL.C                                                    */
/*                                                             */
/*  Support for the Hebrew calendar                            */
/*                                                             */
/*  This file is part of REMIND.                               */
/*  Copyright (C) 1992, 1993, 1994 by David F. Skoll.          */
/*                                                             */
/*  Derived from code written by Amos Shapir in 1978; revised  */
/*  1985.                                                      */
/*                                                             */
/***************************************************************/
#include <stdio.h>  /* For FILE used by protos.h - sigh. */
#include "config.h"
#include "types.h"
#include "protos.h"
#include "globals.h"
#include "err.h"
#define HOUR 1080L
#define DAY  (24L*HOUR)
#define WEEK (7L*DAY)
#define M(h,p) ((long)(h*HOUR+p))
#define MONTH (DAY+M(12,793))

/* Correction to convert base reference to 1990.  NOTE:  If you change
   the value of BASE in config.h, this will NOT WORK!  You'll have to
   add the appropriate number of days to CORRECTION. */

#define CORRECTION 732774L

#define TISHREY 0
#define HESHVAN 1
#define KISLEV  2
#define TEVET   3
#define SHVAT   4
#define ADARA   5
#define ADARB   6
#define NISAN   7
#define IYAR    8
#define SIVAN   9
#define TAMUZ  10
#define AV     11
#define ELUL   12
#define ADAR   13

#define JAHR_NONE     0
#define JAHR_FORWARD  1
#define JAHR_BACKWARD 2

#define ADAR2ADARB 0
#define ADAR2ADARA 1
#define ADAR2BOTH  2

static char *HebMonthNames[] = {
   "Tishrey", "Heshvan", "Kislev", "Tevet", "Shvat", "Adar A", "Adar B",
   "Nisan", "Iyar", "Sivan", "Tamuz", "Av", "Elul", "Adar"};

static char MaxMonLen[] = {
   30, 30, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29, 29};

static char HebIsLeap[] = {0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,1};
  
/***************************************************************/
/*                                                             */
/*  RoshHashana                                                */
/*                                                             */
/*  Return the Julian date for Rosh Hashana of specified       */
/*  Hebrew year.  (ie, 5751, not 1990)                         */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC int RoshHashana(int i)
#else
int RoshHashana(i)
int i;
#endif     
{
    long j;
    j = DaysToHebYear(i-3744) - CORRECTION;
    return (int) j; /* No overflow check... very trusting! */
}
 
/***************************************************************/
/*                                                             */
/*  DaysToHebYear                                              */
/*                                                             */
/*  Return the number of days to RH of specified Hebrew year   */
/*  from new moon before Tishrey 1 5701.                       */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC long DaysToHebYear(int y)
#else
long DaysToHebYear(y)
int y;
#endif
{
	long m, nm, dw, s, l;

	l = y*7+1;	  /* no. of leap months */
	m = y*12+l/19;  /* total no. of months */
	nm = m*MONTH+M(1,779); /* molad at 197 cycles */
	s = m*28+nm/DAY-2;

	nm %= WEEK;
	l %= 19L;
	dw = nm/DAY;
	nm %= DAY;

	/* special cases of Molad Zaken */
	if (nm >= 18*HOUR ||
              (l < 12 && dw==3 && nm>=M(9,204)) ||
	      (l <  7 && dw==2 && nm>=M(15,589)))
		s++,dw++;
	/* ADU */
	if(dw == 1 || dw == 4 || dw == 6)
		s++;
	return s;
}

/***************************************************************/
/*                                                             */
/*  DaysInHebYear                                              */
/*                                                             */
/*  Return the number of days in the Hebrew year.              */
/*                                                             */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC int DaysInHebYear(int y)
#else
int DaysInHebYear(y)
int y;
#endif
{
   long thisyear, nextyear;

   thisyear = DaysToHebYear(y-3744);
   nextyear = DaysToHebYear(y-3743);
   return (int) (nextyear - thisyear);
}

/***************************************************************/
/*                                                             */
/*  DaysInHebMonths                                            */
/*                                                             */
/*  Return a pointer to an array giving lengths of months      */
/*  given the LENGTH of the Hebrew year.                       */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC char *DaysInHebMonths(int ylen)
#else
char *DaysInHebMonths(ylen)
int ylen;
#endif
{
   static char monlen[13] =
      {30, 29, 30, 29, 30, 0, 29, 30, 29, 30, 29, 30, 29};


   if (ylen > 355) {
      monlen[ADARA] = 30;
      ylen -= 30;
   } else monlen[ADARA] = 0;

   if (ylen == 353) monlen[KISLEV] = 29; else monlen[KISLEV] = 30;
   if (ylen == 355) monlen[HESHVAN] = 30; else monlen[HESHVAN] = 29;

   return monlen;
}

/***************************************************************/
/*                                                             */
/*  HebToJul                                                   */
/*                                                             */
/*  Convert a Hebrew date to Julian.                           */
/*  Hebrew months range from 0-12, but Adar A has 0 length in  */
/*  non-leap-years.                                            */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC int HebToJul(int hy, int hm, int hd)
#else
int HebToJul(hy, hm, hd)
int hy, hm, hd;
#endif
{
   int ylen;
   char *monlens;
   int rh;
   int m;

   /* Do some range checking */
   if (hy - 3761 < BASE || hy - 3760 > BASE+YR_RANGE) return -1;

   ylen = DaysInHebYear(hy);
   monlens = DaysInHebMonths(ylen);

   /* Get the Rosh Hashana of the year */
   rh = RoshHashana(hy);

   /* Bump up to the appropriate month */
   for (m=0; m<hm; m++) rh += monlens[m];

   /* Add in appropriate number of days */
   rh += hd - 1;
   return rh;
}

/***************************************************************/
/*                                                             */
/*  JulToHeb                                                   */
/*                                                             */
/*  Convert a Julian date to Hebrew.                           */
/*  Hebrew months range from 0-12, but Adar A has 0 length in  */
/*  non-leap-years.                                            */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC void JulToHeb(int jul, int *hy, int *hm, int *hd)
#else
void JulToHeb(jul, hy, hm, hd)
int jul, *hy, *hm, *hd;
#endif
{
   int y, m, d;
   int rh;
   int ylen;
   char *monlen;
   /* Get the common year */
   FromJulian(jul, &y, &m, &d);
   y += 3763; /* Over-estimate a bit to be on the safe side below... */

   /* Find the RH just before desired date */
   while ((rh=RoshHashana(y))>jul) y--;

   /* Got the year - now find the month */
   jul -= rh;
   ylen = DaysInHebYear(y);
   monlen = DaysInHebMonths(ylen);
   m = 0;
   while((jul >= monlen[m]) || !monlen[m]) {
      jul -= monlen[m];
      m++;
   }

   *hy = y;
   *hm = m;
   *hd = jul+1;
}

/***************************************************************/
/*                                                             */
/*  HebNameToNum                                               */
/*                                                             */
/*  Convert a Hebrew month's name to its number, given the     */
/*  year.                                                      */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC int HebNameToNum(const char *mname)
#else
int HebNameToNum(mname)
char *mname;
#endif
{
   int i;
   int m=-1;

   for (i=0; i<14; i++)
      if (!StrCmpi(mname, HebMonthNames[i])) {
         m = i;
	 break;
      }

   return m;
}   

/***************************************************************/
/*                                                             */
/*  HebMonthname                                               */
/*                                                             */
/*  Convert a Hebrew month's number to its name, given the     */
/*  year.                                                      */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC char *HebMonthName(int m, int y)
#else
char *HebMonthName(m, y)
int m, y;
#endif
{
   if (m != ADARA && m != ADARB) return HebMonthNames[m];

   if (!HebIsLeap[(y-1)%19]) return HebMonthNames[ADAR];
   else return HebMonthNames[m];
}

/***************************************************************/
/*                                                             */
/* GetValidHebDate                                             */
/*                                                             */
/* Given the day of a month, a Hebrew month number, and a      */
/* year, return a valid year number, month number, and day     */
/* number.  Returns 0 for success, non-0 for failure.          */
/* If *dout is set to -1, then date is completely invalid.     */
/* Otherwise, date is only invalid in specified year.          */
/*                                                             */
/* Algorithm:                                                  */
/* - Convert references to Adar to Adar B.                     */
/* If jahr == 0 then                                           */ 
/*     - If no such date in current Hebrew year, return        */
/*       failure.                                              */
/* else follow jahrzeit rules:                                 */
/*     - If jahr == 1: Convert 30 Kislev to 1 Tevet and        */
/*                     30 Heshvan to 1 Kislev if chaser.       */
/*                     Convert 30 Adar A to 1 Nisan in nonleap */
/*                     This rule is NOT appropriate for a      */
/*                     jahrzeit on 30 Adar A.  Use rule 2 for  */
/*                     that.  However, I believe it is correct */
/*                     for smachot.                            */
/*     - If jahr == 2: Convert 30 Kislev to 29 Kislev and      */
/*                     30 Heshvan to 29 Heshvan if chaser.     */
/*                     Change 30 Adar A to 30 Shvat in nonleap */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC int GetValidHebDate(int yin, int min, int din, int adarbehave,
                           int *mout, int *dout, int jahr)
#else
int GetValidHebDate(yin, min, din, adarbehave, mout, dout, jahr)
int yin, min, din, adarbehave, *mout, *dout, jahr;
#endif
{
   char *monlen;
   int ylen;

   *mout = min;
   *dout = din;

   /* Do some error checking */
   if (din < 1 || din > MaxMonLen[min] || min < 0 || min > 13) {
      *dout = -1;
      return E_BAD_HEBDATE;
   }

   ylen = DaysInHebYear(yin);
   monlen = DaysInHebMonths(ylen);

   /* Convert ADAR as necessary */
   if (min == ADAR) {
      switch(adarbehave) {
         case ADAR2ADARA: if (monlen[ADARA]) *mout = min = ADARA;
			  else		     *mout = min = ADARB;
			  break;

	 case ADAR2ADARB: *mout = min = ADARB; break;

	 default:
	    Eprint("GetValidHebDate: Bad adarbehave value %d", adarbehave);
	    return E_SWERR;
      }
   }

   if (din <= monlen[min]) return OK;

   switch(jahr) {
      case JAHR_NONE: return E_BAD_DATE;

      case JAHR_FORWARD:
         if (min == KISLEV) {
            *mout = TEVET;
            *dout = 1;
            return OK;
         } else if (min == HESHVAN) {
            *mout = KISLEV;
            *dout = 1;
            return OK;
	 } else if (min == ADARA) {
            if (din > 29) {
	       *dout = 1;
	       *mout = NISAN;
            } else {
	       *dout = din;
	       *mout = ADARB;
            }
	    return OK;
	 }

         Eprint("GetValidHebDate: (1) software error! %d", jahr);
         return E_SWERR;

      case JAHR_BACKWARD:
         if (min == KISLEV) {
            *mout = KISLEV;
            *dout = 29;
            return OK;
         } else if (min == HESHVAN) {
            *mout = HESHVAN;
            *dout = 29;
            return OK;
         } else if (min == ADARA) {
	    if (din > 29) {
	       *dout = 30;
	       *mout = SHVAT;
            } else {
               *mout = ADARB;
	       *dout = din;
            }
	    return OK;
         }

         Eprint("GetValidHebDate: (2) software error! %d", jahr);
         return E_SWERR;

      default:
         Eprint("GetValidHebDate: (3) software error! %d", jahr);
         return E_SWERR;
   }
}


/***************************************************************/
/*                                                             */
/*  GetNextHebrewDate                                          */
/*                                                             */
/*  Get the next Hebrew date on or after specified date.       */
/*                                                             */
/*  Returns 0 for success, non-zero for failure.               */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC int GetNextHebrewDate(int julstart, int hm, int hd,
			     int jahr, int adarbehave, int *ans)
#else
int GetNextHebrewDate(julstart, hm, hd, jahr, adarbehave, ans)
int julstart, hm, hd, jahr, adarbehave, *ans;
#endif
{
   int r, yout, mout, dout, jul=1;
   int adarflag = adarbehave;

   /* I initialize jul above to stop gcc from complaining about
      possible use of uninitialized variable.  You can take it
      out if the small inefficiency really bothers you. */

   /* If adarbehave == ADAR2BOTH, set adarflag to ADAR2ADARA for now */
   if (adarbehave == ADAR2BOTH) adarflag = ADAR2ADARA;

   JulToHeb(julstart, &yout, &mout, &dout);

   r = 1;
   while(r) {
      r = GetValidHebDate(yout, hm, hd, adarflag, &mout, &dout, jahr);
      if (dout == -1) return r;
      if (r) {
         if (adarbehave == ADAR2BOTH && hm == ADAR) {
	    if (adarflag == ADAR2ADARA) {
	       adarflag = ADAR2ADARB;
            } else {
	       adarflag = ADAR2ADARA;
	       yout++;
            }
         } else yout++;
	 continue;
      }
      jul = HebToJul(yout, mout, dout);
      if (jul < 0) return E_DATE_OVER;
      if (jul >= julstart) break;
      else {
         if (adarbehave == ADAR2BOTH && hm == ADAR) {
	    if (adarflag == ADAR2ADARA) {
	       adarflag = ADAR2ADARB;
            } else {
	       adarflag = ADAR2ADARA;
	       yout++;
            }
         } else yout++;
         r=1;  /* Force loop to continue */
      }
   }
   *ans = jul;
   return OK;
}

/***************************************************************/
/*                                                             */
/*  ComputeJahr                                                */
/*                                                             */
/*  Given a date of death, compute the value to use for jahr.  */
/*                                                             */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC int ComputeJahr(int y, int m, int d, int *ans)
#else
int ComputeJahr(y, m, d, ans)
int y, m, d, *ans;
#endif
{
   char *monlen;
   int len;

   *ans = JAHR_NONE;

   len = DaysInHebYear(y);
   monlen = DaysInHebMonths(len);

/* Check for Adar A */
   if (m == ADARA && monlen[m] == 0) {
      Eprint("No Adar A in %d", y);
      return E_BAD_HEBDATE;
   }


   if (d < 1 || d > MaxMonLen[m] || m < 0 || m > 13) {
      return E_BAD_HEBDATE;
   }

   if (d > monlen[m]) {
      Eprint("%d %s %d: %s", d, HebMonthNames[m], y, ErrMsg[E_BAD_HEBDATE]);
      return E_BAD_HEBDATE;
   }

/* If the jahrzeit was in Adar A, we always use JAHR_BACKWARD */
   if (m == ADARA) {
      *ans = JAHR_BACKWARD;
      return OK;
   }

/* Get lengths of months in year following jahrzeit */
   len = DaysInHebYear(y+1);
   monlen = DaysInHebMonths(len);

   if (d > monlen[m]) *ans = JAHR_FORWARD;
   else               *ans = JAHR_BACKWARD;

   return OK;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.