home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume37 / remind / patch05c < prev    next >
Encoding:
Text File  |  1993-04-27  |  17.8 KB  |  555 lines

  1. Newsgroups: comp.sources.misc
  2. From: <dfs@doe.carleton.ca> (David F. Skoll)
  3. Subject: v37i030:  remind - A replacement for calendar, Patch05c/3
  4. Message-ID: <1993Apr28.025515.3168@sparky.imd.sterling.com>
  5. X-Md4-Signature: 50dd5f233ab093d49f8f8d5e13ef1477
  6. Date: Wed, 28 Apr 1993 02:55:15 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: <dfs@doe.carleton.ca> (David F. Skoll)
  10. Posting-number: Volume 37, Issue 30
  11. Archive-name: remind/patch05c
  12. Environment: UNIX, MS-DOS, OS/2
  13. Patch-To: remind: Volume 33, Issue 58-69
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then feed it
  17. # into a shell via "sh file" or similar.  To overwrite existing files,
  18. # type "sh file -c".
  19. # Contents:  hbcal.c
  20. # Wrapped by kent@sparky on Tue Apr 27 21:38:31 1993
  21. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  22. echo If this archive is complete, you will see the following message:
  23. echo '          "shar: End of archive 3 (of 3)."'
  24. if test -f 'hbcal.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'hbcal.c'\"
  26. else
  27.   echo shar: Extracting \"'hbcal.c'\" \(16053 characters\)
  28.   sed "s/^X//" >'hbcal.c' <<'END_OF_FILE'
  29. X/***************************************************************/
  30. X/*                                                             */
  31. X/*  HBCAL.C                                                    */
  32. X/*                                                             */
  33. X/*  Support for the Hebrew calendar                            */
  34. X/*                                                             */
  35. X/*  This file is part of REMIND.                               */
  36. X/*  Copyright (C) 1992, 1993 by David F. Skoll.                */
  37. X/*                                                             */
  38. X/*  Derived from code written by Amos Shapir in 1978; revised  */
  39. X/*  1985.                                                      */
  40. X/*                                                             */
  41. X/***************************************************************/
  42. X#include <stdio.h>  /* For FILE used by protos.h - sigh. */
  43. X#include "config.h"
  44. X#include "types.h"
  45. X#include "protos.h"
  46. X#include "globals.h"
  47. X#include "err.h"
  48. X#define HOUR 1080L
  49. X#define DAY  (24L*HOUR)
  50. X#define WEEK (7L*DAY)
  51. X#define M(h,p) ((long)(h*HOUR+p))
  52. X#define MONTH (DAY+M(12,793))
  53. X
  54. X/* Correction to convert base reference to 1990.  NOTE:  If you change
  55. X   the value of BASE in config.h, this will NOT WORK!  You'll have to
  56. X   add the appropriate number of days to CORRECTION. */
  57. X
  58. X#define CORRECTION 732774L
  59. X
  60. X#define TISHREY 0
  61. X#define HESHVAN 1
  62. X#define KISLEV  2
  63. X#define TEVET   3
  64. X#define SHVAT   4
  65. X#define ADARA   5
  66. X#define ADARB   6
  67. X#define NISAN   7
  68. X#define IYAR    8
  69. X#define SIVAN   9
  70. X#define TAMUZ  10
  71. X#define AV     11
  72. X#define ELUL   12
  73. X#define ADAR   13
  74. X
  75. X#define JAHR_NONE     0
  76. X#define JAHR_FORWARD  1
  77. X#define JAHR_BACKWARD 2
  78. X
  79. Xstatic char *HebMonthNames[] = {
  80. X   "Tishrey", "Heshvan", "Kislev", "Tevet", "Shvat", "Adar A", "Adar B",
  81. X   "Nisan", "Iyar", "Sivan", "Tamuz", "Av", "Elul", "Adar"};
  82. X
  83. Xstatic char MaxMonLen[] = {
  84. X   30, 30, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29, 29};
  85. X
  86. Xstatic char HebIsLeap[] = {0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,1};
  87. X  
  88. X/***************************************************************/
  89. X/*                                                             */
  90. X/*  RoshHashana                                                */
  91. X/*                                                             */
  92. X/*  Return the Julian date for Rosh Hashana of specified       */
  93. X/*  Hebrew year.  (ie, 5751, not 1990)                         */
  94. X/*                                                             */
  95. X/***************************************************************/
  96. X#ifdef HAVE_PROTOS
  97. XPUBLIC int RoshHashana(int i)
  98. X#else
  99. Xint RoshHashana(i)
  100. Xint i;
  101. X#endif     
  102. X{
  103. X    long j;
  104. X    j = DaysToHebYear(i-3744) - CORRECTION;
  105. X    return (int) j; /* No overflow check... very trusting! */
  106. X}
  107. X/***************************************************************/
  108. X/*                                                             */
  109. X/*  DaysToHebYear                                              */
  110. X/*                                                             */
  111. X/*  Return the number of days to RH of specified Hebrew year   */
  112. X/*  from new moon before Tishrey 1 5701.                       */
  113. X/*                                                             */
  114. X/***************************************************************/
  115. X#ifdef HAVE_PROTOS
  116. XPUBLIC long DaysToHebYear(int y)
  117. X#else
  118. Xlong DaysToHebYear(y)
  119. Xint y;
  120. X#endif
  121. X{
  122. X    long m, nm, dw, s, l;
  123. X
  124. X    l = y*7+1;      /* no. of leap months */
  125. X    m = y*12+l/19;  /* total no. of months */
  126. X    nm = m*MONTH+M(1,779); /* molad at 197 cycles */
  127. X    s = m*28+nm/DAY-2;
  128. X
  129. X    nm %= WEEK;
  130. X    l %= 19L;
  131. X    dw = nm/DAY;
  132. X    nm %= DAY;
  133. X
  134. X    /* special cases of Molad Zaken */
  135. X    if (nm >= 18*HOUR ||
  136. X              (l < 12 && dw==3 && nm>=M(9,204)) ||
  137. X          (l <  7 && dw==2 && nm>=M(15,589)))
  138. X        s++,dw++;
  139. X    /* ADU */
  140. X    if(dw == 1 || dw == 4 || dw == 6)
  141. X        s++;
  142. X    return s;
  143. X}
  144. X
  145. X/***************************************************************/
  146. X/*                                                             */
  147. X/*  DaysInHebYear                                              */
  148. X/*                                                             */
  149. X/*  Return the number of days in the Hebrew year.              */
  150. X/*                                                             */
  151. X/*                                                             */
  152. X/***************************************************************/
  153. X#ifdef HAVE_PROTOS
  154. XPUBLIC int DaysInHebYear(int y)
  155. X#else
  156. Xint DaysInHebYear(y)
  157. Xint y;
  158. X#endif
  159. X{
  160. X   long thisyear, nextyear;
  161. X
  162. X   thisyear = DaysToHebYear(y-3744);
  163. X   nextyear = DaysToHebYear(y-3743);
  164. X   return (int) (nextyear - thisyear);
  165. X}
  166. X
  167. X/***************************************************************/
  168. X/*                                                             */
  169. X/*  DaysInHebMonths                                            */
  170. X/*                                                             */
  171. X/*  Return a pointer to an array giving lengths of months      */
  172. X/*  given the LENGTH of the Hebrew year.                       */
  173. X/*                                                             */
  174. X/***************************************************************/
  175. X#ifdef HAVE_PROTOS
  176. XPUBLIC char *DaysInHebMonths(int ylen)
  177. X#else
  178. Xchar *DaysInHebMonths(ylen)
  179. Xint ylen;
  180. X#endif
  181. X{
  182. X   static char monlen[13] =
  183. X      {30, 29, 30, 29, 30, 0, 29, 30, 29, 30, 29, 30, 29};
  184. X
  185. X
  186. X   if (ylen > 355) {
  187. X      monlen[ADARA] = 30;
  188. X      ylen -= 30;
  189. X   } else monlen[ADARA] = 0;
  190. X
  191. X   if (ylen == 353) monlen[KISLEV] = 29; else monlen[KISLEV] = 30;
  192. X   if (ylen == 355) monlen[HESHVAN] = 30; else monlen[HESHVAN] = 29;
  193. X
  194. X   return monlen;
  195. X}
  196. X
  197. X/***************************************************************/
  198. X/*                                                             */
  199. X/*  HebToJul                                                   */
  200. X/*                                                             */
  201. X/*  Convert a Hebrew date to Julian.                           */
  202. X/*  Hebrew months range from 0-12, but Adar A has 0 length in  */
  203. X/*  non-leap-years.                                            */
  204. X/*                                                             */
  205. X/***************************************************************/
  206. X#ifdef HAVE_PROTOS
  207. XPUBLIC int HebToJul(int hy, int hm, int hd)
  208. X#else
  209. Xint HebToJul(hy, hm, hd)
  210. Xint hy, hm, hd;
  211. X#endif
  212. X{
  213. X   int ylen;
  214. X   char *monlens;
  215. X   int rh;
  216. X   int m;
  217. X
  218. X   /* Do some range checking */
  219. X   if (hy - 3761 < BASE || hy - 3760 > BASE+YR_RANGE) return -1;
  220. X
  221. X   ylen = DaysInHebYear(hy);
  222. X   monlens = DaysInHebMonths(ylen);
  223. X
  224. X   /* Get the Rosh Hashana of the year */
  225. X   rh = RoshHashana(hy);
  226. X
  227. X   /* Bump up to the appropriate month */
  228. X   for (m=0; m<hm; m++) rh += monlens[m];
  229. X
  230. X   /* Add in appropriate number of days */
  231. X   rh += hd - 1;
  232. X   return rh;
  233. X}
  234. X
  235. X/***************************************************************/
  236. X/*                                                             */
  237. X/*  JulToHeb                                                   */
  238. X/*                                                             */
  239. X/*  Convert a Julian date to Hebrew.                           */
  240. X/*  Hebrew months range from 0-12, but Adar A has 0 length in  */
  241. X/*  non-leap-years.                                            */
  242. X/*                                                             */
  243. X/***************************************************************/
  244. X#ifdef HAVE_PROTOS
  245. XPUBLIC void JulToHeb(int jul, int *hy, int *hm, int *hd)
  246. X#else
  247. Xvoid JulToHeb(jul, hy, hm, hd)
  248. Xint jul, *hy, *hm, *hd;
  249. X#endif
  250. X{
  251. X   int y, m, d;
  252. X   int rh;
  253. X   int ylen;
  254. X   char *monlen;
  255. X   /* Get the common year */
  256. X   FromJulian(jul, &y, &m, &d);
  257. X   y += 3763; /* Over-estimate a bit to be on the safe side below... */
  258. X
  259. X   /* Find the RH just before desired date */
  260. X   while ((rh=RoshHashana(y))>jul) y--;
  261. X
  262. X   /* Got the year - now find the month */
  263. X   jul -= rh;
  264. X   ylen = DaysInHebYear(y);
  265. X   monlen = DaysInHebMonths(ylen);
  266. X   m = 0;
  267. X   while((jul > monlen[m]) || !monlen[m]) {
  268. X      jul -= monlen[m];
  269. X      m++;
  270. X   }
  271. X
  272. X   *hy = y;
  273. X   *hm = m;
  274. X   *hd = jul+1;
  275. X}
  276. X
  277. X/***************************************************************/
  278. X/*                                                             */
  279. X/*  HebNameToNum                                               */
  280. X/*                                                             */
  281. X/*  Convert a Hebrew month's name to its number, given the     */
  282. X/*  year.                                                      */
  283. X/*                                                             */
  284. X/***************************************************************/
  285. X#ifdef HAVE_PROTOS
  286. XPUBLIC int HebNameToNum(const char *mname)
  287. X#else
  288. Xint HebNameToNum(mname)
  289. Xchar *mname;
  290. X#endif
  291. X{
  292. X   int i;
  293. X   int m=-1;
  294. X
  295. X   for (i=0; i<14; i++)
  296. X      if (!StrCmpi(mname, HebMonthNames[i])) {
  297. X         m = i;
  298. X     break;
  299. X      }
  300. X
  301. X   return m;
  302. X}   
  303. X
  304. X/***************************************************************/
  305. X/*                                                             */
  306. X/*  HebMonthname                                               */
  307. X/*                                                             */
  308. X/*  Convert a Hebrew month's number to its name, given the     */
  309. X/*  year.                                                      */
  310. X/*                                                             */
  311. X/***************************************************************/
  312. X#ifdef HAVE_PROTOS
  313. XPUBLIC char *HebMonthName(int m, int y)
  314. X#else
  315. Xchar *HebMonthName(m, y)
  316. Xint m, y;
  317. X#endif
  318. X{
  319. X   if (m != ADARA && m != ADARB) return HebMonthNames[m];
  320. X
  321. X   if (!HebIsLeap[(y-1)%19]) return HebMonthNames[ADAR];
  322. X   else return HebMonthNames[m];
  323. X}
  324. X
  325. X/***************************************************************/
  326. X/*                                                             */
  327. X/* GetValidHebDate                                             */
  328. X/*                                                             */
  329. X/* Given the day of a month, a Hebrew month number, and a      */
  330. X/* year, return a valid year number, month number, and day     */
  331. X/* number.  Returns 0 for success, non-0 for failure.          */
  332. X/* If *dout is set to -1, then date is completely invalid.     */
  333. X/* Otherwise, date is only invalid in specified year.          */
  334. X/*                                                             */
  335. X/* Algorithm:                                                  */
  336. X/* - Convert references to Adar to Adar B.                     */
  337. X/* If jahr == 0 then                                           */ 
  338. X/*     - If no such date in current Hebrew year, return        */
  339. X/*       failure.                                              */
  340. X/* else follow jahrzeit rules:                                 */
  341. X/*     - If jahr == 1: Convert 30 Kislev to 1 Tevet and        */
  342. X/*                     30 Heshvan to 1 Kislev if chaser.       */
  343. X/*                     Convert 30 Adar A to 1 Nisan in nonleap */
  344. X/*                     This rule is NOT appropriate for a      */
  345. X/*                     jahrzeit on 30 Adar A.  Use rule 2 for  */
  346. X/*                     that.  However, I believe it is correct */
  347. X/*                     for smachot.                            */
  348. X/*     - If jahr == 2: Convert 30 Kislev to 29 Kislev and      */
  349. X/*                     30 Heshvan to 29 Heshvan if chaser.     */
  350. X/*                     Change 30 Adar A to 30 Shvat in nonleap */
  351. X/*                                                             */
  352. X/***************************************************************/
  353. X#ifdef HAVE_PROTOS
  354. XPUBLIC int GetValidHebDate(int yin, int min, int din,
  355. X                           int *mout, int *dout, int jahr)
  356. X#else
  357. Xint GetValidHebDate(yin, min, din, mout, dout, jahr)
  358. Xint yin, min, din, *mout, *dout, jahr;
  359. X#endif
  360. X{
  361. X   char *monlen;
  362. X   int ylen;
  363. X
  364. X   *mout = min;
  365. X   *dout = din;
  366. X
  367. X   /* Do some error checking */
  368. X   if (din < 1 || din > MaxMonLen[min] || min < 0 || min > 13) {
  369. X      *dout = -1;
  370. X      Eprint("Invalid Hebrew date");
  371. X      return E_BAD_DATE;
  372. X   }
  373. X
  374. X   /* Convert ADAR to ADAR-B */
  375. X   if (min == ADAR) *mout = min = ADARB;
  376. X
  377. X   ylen = DaysInHebYear(yin);
  378. X   monlen = DaysInHebMonths(ylen);
  379. X
  380. X   if (din <= monlen[min]) return OK;
  381. X
  382. X   switch(jahr) {
  383. X      case JAHR_NONE: return E_BAD_DATE;
  384. X
  385. X      case JAHR_FORWARD:
  386. X         if (min == KISLEV) {
  387. X            *mout = TEVET;
  388. X            *dout = 1;
  389. X            return OK;
  390. X         } else if (min == HESHVAN) {
  391. X            *mout = KISLEV;
  392. X            *dout = 1;
  393. X            return OK;
  394. X     } else if (min == ADARA) {
  395. X            if (din > 29) {
  396. X           *dout = 1;
  397. X           *mout = NISAN;
  398. X            } else {
  399. X           *dout = din;
  400. X           *mout = ADARB;
  401. X            }
  402. X        return OK;
  403. X     }
  404. X
  405. X         Eprint("GetValidHebDate: (1) software error! %d", jahr);
  406. X         return E_SWERR;
  407. X
  408. X      case JAHR_BACKWARD:
  409. X         if (min == KISLEV) {
  410. X            *mout = KISLEV;
  411. X            *dout = 29;
  412. X            return OK;
  413. X         } else if (min == HESHVAN) {
  414. X            *mout = HESHVAN;
  415. X            *dout = 29;
  416. X            return OK;
  417. X         } else if (min == ADARA) {
  418. X        if (din > 29) {
  419. X           *dout = 30;
  420. X           *mout = SHVAT;
  421. X            } else {
  422. X               *mout = ADARB;
  423. X           *dout = din;
  424. X            }
  425. X        return OK;
  426. X         }
  427. X
  428. X         Eprint("GetValidHebDate: (2) software error! %d", jahr);
  429. X         return E_SWERR;
  430. X
  431. X      default:
  432. X         Eprint("GetValidHebDate: (3) software error! %d", jahr);
  433. X         return E_SWERR;
  434. X   }
  435. X}
  436. X
  437. X
  438. X/***************************************************************/
  439. X/*                                                             */
  440. X/*  GetNextHebrewDate                                          */
  441. X/*                                                             */
  442. X/*  Get the next Hebrew date on or after specified date.       */
  443. X/*                                                             */
  444. X/*  Returns 0 for success, non-zero for failure.               */
  445. X/*                                                             */
  446. X/***************************************************************/
  447. X#ifdef HAVE_PROTOS
  448. XPUBLIC int GetNextHebrewDate(int julstart, int hm, int hd, int jahr, int *ans)
  449. X#else
  450. Xint GetNextHebrewDate(julstart, hm, hd, jahr, ans)
  451. Xint julstart, hm, hd, jahr, *ans;
  452. X#endif
  453. X{
  454. X   int r, yout, mout, dout, jul;
  455. X
  456. X   JulToHeb(julstart, &yout, &mout, &dout);
  457. X
  458. X   r = 1;
  459. X   while(r) {
  460. X      r = GetValidHebDate(yout, hm, hd, &mout, &dout, jahr);
  461. X      if (dout == -1) return r;
  462. X      if (r) {
  463. X         yout++;
  464. X     continue;
  465. X      }
  466. X      jul = HebToJul(yout, mout, dout);
  467. X      if (jul >= julstart) break;
  468. X      else {
  469. X         yout++;
  470. X         r=1;  /* Force loop to continue */
  471. X      }
  472. X   }
  473. X   *ans = jul;
  474. X   return OK;
  475. X}
  476. X
  477. X/***************************************************************/
  478. X/*                                                             */
  479. X/*  ComputeJahr                                                */
  480. X/*                                                             */
  481. X/*  Given a date of death, compute the value to use for jahr.  */
  482. X/*                                                             */
  483. X/***************************************************************/
  484. X#ifdef HAVE_PROTOS
  485. XPUBLIC int ComputeJahr(int y, int m, int d, int *ans)
  486. X#else
  487. Xint ComputeJahr(y, m, d, ans)
  488. Xint y, m, d, *ans;
  489. X#endif
  490. X{
  491. X   char *monlen;
  492. X   int len;
  493. X
  494. X   *ans = JAHR_NONE;
  495. X
  496. X   len = DaysInHebYear(y);
  497. X   monlen = DaysInHebMonths(len);
  498. X
  499. X/* Check for Adar A */
  500. X   if (m == ADARA && monlen[m] == 0) {
  501. X      Eprint("No Adar A in %d", y);
  502. X      return E_BAD_DATE;
  503. X   }
  504. X
  505. X
  506. X   if (d < 1 || d > MaxMonLen[m] || m < 0 || m > 13) {
  507. X      Eprint("Invalid Hebrew date");
  508. X      return E_BAD_DATE;
  509. X   }
  510. X
  511. X   if (d > monlen[m]) {
  512. X      Eprint("No %d %s %d", d, HebMonthNames[m], y);
  513. X      return E_BAD_DATE;
  514. X   }
  515. X
  516. X/* If the jahrzeit was in Adar A, we always use JAHR_BACKWARD */
  517. X   if (m == ADARA) {
  518. X      *ans = JAHR_BACKWARD;
  519. X      return OK;
  520. X   }
  521. X
  522. X/* Get lengths of months in year following jahrzeit */
  523. X   len = DaysInHebYear(y+1);
  524. X   monlen = DaysInHebMonths(len);
  525. X
  526. X   if (d > monlen[m]) *ans = JAHR_FORWARD;
  527. X   else               *ans = JAHR_BACKWARD;
  528. X
  529. X   return OK;
  530. X}
  531. END_OF_FILE
  532.   if test 16053 -ne `wc -c <'hbcal.c'`; then
  533.     echo shar: \"'hbcal.c'\" unpacked with wrong size!
  534.   fi
  535.   # end of 'hbcal.c'
  536. fi
  537. echo shar: End of archive 3 \(of 3\).
  538. cp /dev/null ark3isdone
  539. MISSING=""
  540. for I in 1 2 3 ; do
  541.     if test ! -f ark${I}isdone ; then
  542.     MISSING="${MISSING} ${I}"
  543.     fi
  544. done
  545. if test "${MISSING}" = "" ; then
  546.     echo You have unpacked all 3 archives.
  547.     rm -f ark[1-9]isdone
  548. else
  549.     echo You still must unpack the following archives:
  550.     echo "        " ${MISSING}
  551. fi
  552. exit 0
  553. exit 0 # Just in case...
  554.