#include <stdio.h>
#include <string.h>
#include "error.h"
#include "danlib.h"
#include "greg.h"
  /* hebcal.c main module for hebrew calendar program
     By Danny Sadinoff
     (C) 1992
     
     $Date: 93/01/19 10:43:58 $
     $Revision: 1.4 $
     
     */ 
  
  
  int sedrot_sw, hebDates_sw, euroDates_sw, specMonth_sw,specDay_sw,
      weekday_sw, suppressHolidays_sw, suppressGreg_sw, 
      printOmer_sw, omer;

  FILE *inFile;

typedef struct {
  
  char * name;
  int length;
  
  int daysInCheshvan;
  int daysInKislev;
  
  int vayakhelPikudei;	/* double parsha flags */
  int tazriaMetzorah;
  int achreiKedoshim;
  int beharBech;
  int chukatBalak; 
  int matotMasei;
  int nitzavimVayelech;
  
} year_t;


year_t legend[2][8] = {
  {				/* stam years */
    {"1BX",353,29,29,1,1,1,1,0,1,1},	/* BX */
    {"1BS",355,30,30,1,1,1,1,1,1,1},	/* BS */
    {"2GC",354,29,30,1,1,1,1,1,1,1},	/* GC */
    {"4HC",354,29,30,1,1,1,1,0,1,0},	/* HC */ 
    {"0error - HX",354,29,29,1,1,1,1,0,1,0},	/* error! hx */
    {"4HS",355,30,30,0,1,1,1,0,1,0},	/* HS */
    {"6ZX",353,29,29,1,1,1,1,0,1,0},	/* ZX */
    {"6ZS",355,30,30,1,1,1,1,0,1,1},	/* ZS */
  },
  {				/* leap years */
    {"1BX",383,29,29,0,0,0,0,1,1,1},	/* BX */
    {"1BS",385,30,30,0,0,0,0,0,1,0},	/* BS */
    {"2GC",384,29,30,0,0,0,0,0,1,0},	/* GC */
    {"0error - HC",383,29,30,0,0,0,0,0,0,0},	/* error ! hc */
    {"4HX",383,29,29,0,0,0,0,0,0,0},	/* HX */
    {"4HS",385,30,30,0,0,0,0,0,0,1},	/* HS */
    {"6ZX",383,29,29,0,0,0,0,0,1,1},	/* ZX */
    {"6ZS",385,30,30,0,0,0,0,1,1,1},	/* ZS */
  }
};

int leapYears[] = {0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,1};

enum {BX,BS,GC,HC,HX,HS,ZX,ZS};

int luach[][19] = 
{
  {HC,BX,HS,HC,BS,ZX,HC,BS,BX,HS,GC,BS,ZX,GC,BS,ZS,HX,GC,ZS},
  {ZS,HC,BX,ZS,HC,BX,ZS,HS,HC,BX,HS,HC,BS,ZX,HC,BS,ZX,HS,GC},
  {BS,ZX,GC,BS,ZS,HX,GC,ZS,ZS,HC,BX,ZS,HC,BS,BX,HC,BS,BS,ZX},
  {HC,HS,ZX,HC,HS,ZS,ZX,GC,BS,ZS,HX,GC,ZS,HS,HC,BX,HS,HC,BX},
  {ZS,HC,BS,BX,HC,BS,BS,ZX,HC,BS,ZX,HS,GC,ZS,ZS,HC,BX,ZS,HX},
  {GC,ZS,HS,HC,BX,HS,HC,BX,ZS,HC,BS,BX,HS,GC,BS,ZX,GC,BS,ZS},
  {ZX,GC,ZS,ZS,HC,BX,ZS,HX,GC,ZS,HS,HC,BX,HS,HC,BS,ZX,HC,BS},
  {BS,ZX,GC,BS,ZS,HX,GC,ZS,ZX,GC,ZS,ZS,HC,BX,ZS,HC,BS,BX,HS},
  {HC,BS,ZX,HC,BS,ZX,HS,GC,BS,ZX,GC,BS,ZS,HX,GC,ZS,HS,HC,BX},
  {ZS,HC,BX,ZS,HC,BS,BX,HS,HC,BS,ZX,HC,BS,ZX,HS,GC,ZS,ZX,GC},
  {BS,ZS,HX,GC,ZS,HS,HC,BX,ZS,HC,BX,ZS,HC,BS,BX,HS,GC,BS,ZX}, /* 10,11 GX? */
  {HC,BS,ZS,ZX,GC,ZS,ZS,HX,GC,ZS,HX,GC,ZS,HS,HC,BX,HS,HC,BS},
  {BX,HC,BS,BS,ZX,GC,BS,ZX,HS,GC,ZS,ZS,HC,BX,ZS,HC,BX,ZS,HS}
};

struct {
  char * name;
  int length;
}hMonths[][14] = {
  {  
    {"Tishrei",30}, {"Cheshvan",29}, {"Kislev",30},
    {"Tevet",29}, {"Shvat",30}, {"Adar",29},
    {"Nisan",30}, {"Iyyar",29}, {"Sivan",30},
    {"Tamuz",29}, {"Av",30},{"Elul",29},{"Tishrei",30}},
  {
    {"Tishrei",30}, {"Cheshvan",29}, {"Kislev",30},
    {"Tevet",29}, {"Shvat",30}, {"Adar I",29}, {"Adar II",30},
    {"Nisan",30}, {"Iyyar",29}, {"Sivan",30},
    {"Tamuz",29}, {"Av",30},{"Elul",29},{"Tishrei",30}}    
};

enum {TISHREI, CHESHVAN, KISLEV, ADAR_2 = 6};

char * sedrot[] = { 
  
  "Bereshit", "Noach", "Lech Lecha", "Vayera", "Chayei Sara",
  "Toldot", "Vayetzei", "Vayishlach", "Vayeshev", "Miketz", "Vayigash",
  "Vayechi",
  
  "Sh'mot", "Vaera", "Bo", "Beshalach", "Yitro", "Mishpatim",
  "Terumah", "Tetzaveh", "Ki Tisa", "Vayakhel", "Pekudei",
  
  "Vayikra", "Tzav", "Shmini", "Tazria", "Metzora", "Achrei Mot",
  "Kedoshim", "Emor", "Behar", "Bechukosai",
  
  "Bamidbar", "Nasso", "Beha'aloscha", "Sh'lach", "Korach", "Chukat",
  "Balak", "Pinchas", "Matot", "Masei",
  
  "Devarim", "Vaetchanan", "Eikev", "Re'eh", "Shoftim", 
  "Ki Teitzei", "Ki Tavo", "Nitzavim", "Vayeilech", "Ha'Azinu", 
  "V'Zot Habracha"
  };

enum { VAYAKHEL = 21, 
	 TAZRIA = 26, ACHREI = 28,
	 BEHAR = 31,
	 CHUKAT = 38, MATOT= 41, 
	 NITZAVIM = 50
	 };

#define NM_LEN 30

#define OWNSEDRA 1
#define NIDCHE 2
#define MUKDAM 4
#define MUKDAM2 8

typedef struct hnode{
  date_t date;
  char *name;
  int typeMask;
  struct hnode *next;
} holiday_t, *holidayp_t;

holiday_t special[100];

holiday_t holidays[] = {	/* 5 = Adar I */
  /* 6 = Adar = Adar II */
  {{0,1},"Rosh Hashana I",OWNSEDRA},{{0,2},"Rosh Hashana II",OWNSEDRA},
  {{0,3},"Tzom Gedalia",NIDCHE},
  {{0,9},"Erev Yom Kippur"},
  {{0,10},"Yom Kippur",OWNSEDRA},
  
  {{0,15},"Sukkot I",OWNSEDRA},{{0,16},"Sukkot II",OWNSEDRA},
  {{0,17},"Sukkot III (CH\"M)",OWNSEDRA},{{0,18},"Sukkot IV (CH\"M)",OWNSEDRA},
  {{0,19},"Sukkot V (CH\"M)",OWNSEDRA},{{0,20},"Sukkot VI (CH\"M)",OWNSEDRA},
  {{0,21},"Sukkot VII (Hoshana Raba)",OWNSEDRA},
  {{0,22},"Shmini Atzeret",OWNSEDRA},{{0,23},"Simchat Torah",OWNSEDRA},
  
  {{2,25},"Chanukah I"},
  {{2,26},"Chanukah II"},{{2,27},"Chanukah III"},{{2,28},"Chanukah IV"},
  {{3,10},"Asara B'Tevet",NIDCHE},

  {{4,15},"Tu B'Shevat"}  /*NIDCHE?*/,
  
  {{5,15},"Purim katan"},
  {{6,13},"Ta'anit Esther",MUKDAM},{{6,14},"Purim"},
  {{6,15},"Shushan Purim"}, 
  
  {{7,14},"Erev Pesach - Taanit B'chorot",0},
#define PESACH2_STR "Pesach II"
  {{7,15},"Pesach I",OWNSEDRA},{{7,16},PESACH2_STR,OWNSEDRA},
  {{7,17},"Pesach III (CH\"M)",OWNSEDRA},{{7,18},"Pesach IV (CH\"M)",OWNSEDRA},
  {{7,19},"Pesach V (CH\"M)",OWNSEDRA},{{7,20},"Pesach VI (CH\"M)",OWNSEDRA},
  {{7,21},"Pesach VII",OWNSEDRA},
  {{7,22},"Pesach VIII",OWNSEDRA},
  
  {{7,27},"Yom HaShoah"},
  {{8,4},"Yom HaZikaron",MUKDAM2},
  {{8,5},"Yom Ha'atzmaut",MUKDAM},
  {{8,28},"Yom Yerushalayim",MUKDAM},  /* not certain about mukdam status  of the yoms */
#define SHAVUOT_STR "Shavuot I"
  {{9,6},SHAVUOT_STR,OWNSEDRA},{{9,7},"Shavuot II",OWNSEDRA},
  {{10,17},"Shiva Assar B'Tamuz",NIDCHE},
  {{11,9},"Tish'a B'Av",NIDCHE},
  {{12,29},"Erev Rosh Hashana"}
};

holiday_t chanukah_arr[5] =
{
  {{0,0},""},
  {{0,0},"Chanukah V"},
  {{0,0},"Chanukah VI"},
  {{0,0},"Chanukah VII"},
  {{0,0},"Chanukah VIII"}
};

enum {SIMCHAT_DAY = 23};
/* = {
   {{0,0},"Shabbat Shekalim"},
   {{0,0},"Shabbat Zachor"},
   {{0,0},"Parshat HaChodesh"},
   {{0,0},"Parshat Parah"},

   };*/


#define LEAP_YR_HEB(x) (leapYears[((x) -1) % 19])
#define MONTHS_IN_HEB(x) (LEAP_YR_HEB(x) ? 13 :12)

year_t yearData(yr)
     int yr;
{
  return legend[LEAP_YR_HEB(yr)][luach[((yr-1)/19+7)%13][(yr-1) %19]];
}

#define LAST_INDEX(x) (sizeof x / sizeof x[0])

int daysInHebMonth(month, year) 
     int month, year;
{
  year_t theYear;
  
  theYear = yearData(year);
  if (month == CHESHVAN) 
    return theYear.daysInCheshvan;
  else if (month == KISLEV)
    return theYear.daysInKislev;
  else return hMonths[LEAP_YR_HEB(year)][month].length;
}

date_t nextHebDate (dth) 
     date_t dth;
{
  dth.dd++;
  if (dth.dd > daysInHebMonth(dth.mm,dth.yy))
    if (dth.mm ==  MONTHS_IN_HEB(dth.yy)-1){
      dth.yy++;
      dth.mm =0;
      dth.dd =1;
    }
    else {
      dth.mm++;
      dth.dd =1;
    }
  return dth;
}

date_t prevHebDate (dth) 
     date_t dth;
{
  dth.dd--;
  if (dth.dd == 0)
    if (dth.mm == 0) {
      dth.yy--;
      dth.mm = MONTHS_IN_HEB(dth.yy) -1 ;
      dth.dd = daysInHebMonth(dth.mm,dth.yy);
    }
    else {
      dth.mm--;
      dth.dd = daysInHebMonth(dth.mm,dth.yy);
    }
  return dth;
}

void addHoliday(theHoliday, holiList)
     holiday_t theHoliday, **holiList;
{
  
  holidayp_t newHol, currHol = *holiList;
  
  if (currHol) 
    while (currHol->next)	/* scan to the end of the list */
      currHol = currHol->next; /* now currhol points to the last */
  
  if (!(newHol = (holiday_t *) malloc(sizeof (holiday_t))))
    die("Mem allocation error in getHebHolidays routine.","");
  
  if (currHol)
    currHol->next = newHol;
  else *holiList = newHol;
  
  *newHol = theHoliday;
  newHol->next = NULL;
}

holidayp_t getHebHolidays (dt,weekday,theYear, holiList) /* returns a linked */
     date_t dt;			/* list of holidays for that date*/ 
     int weekday;		
     year_t theYear;
     holiday_t ** holiList; 
{
  int c, specialCounter=0;
  holidayp_t tmpholip;
  static int chanukah_day;
  
  *holiList = NULL;
  
#define CORRECTION(yy,mm) (LEAP_YR_HEB(yy) ? 0 : (((mm) > 4) ? 1: 0))
#define MATCH(X,Y) ((X.mm == (Y.mm + CORRECTION(Y.yy,Y.mm)) ) && (X.dd == Y.dd))
  
  for (c = 0; c < LAST_INDEX(holidays); c++) 
    {
      if (MATCH(holidays[c].date,dt))
	if (!(weekday == SAT && holidays[c].typeMask & NIDCHE) &&
	    !(holidays[c].typeMask & MUKDAM &&
	      (weekday == FRI || weekday == SAT)) &&
	    !(holidays[c].typeMask & MUKDAM2 &&
	      (weekday == THU || weekday == FRI)))
	  {            /* do normal holidays*/
	    addHoliday(holidays[c],holiList);
	    if (!strcmp((*holiList)->name,PESACH2_STR)) omer++;
	    if (omer && holiList && !strcmp((*holiList)->name,SHAVUOT_STR)) omer=0;
	  }
      
      if (holidays[c].typeMask & NIDCHE &&	/* fast days which are */
	  (MATCH(holidays[c].date,prevHebDate(dt))) && 
	  (weekday ==SUN)){
	char *st;
	
	initStr(&st,NM_LEN);
	strncat(st,holidays[c].name,NM_LEN);
	strncat(st," [nidche]",NM_LEN);
	addHoliday(holidays[c],holiList); 
	(*holiList)->name = st;
      }
				/* if the date actually falls */
				/* on friday or shabbat*/
      if (holidays[c].typeMask & MUKDAM &&        
	  (MATCH(holidays[c].date,nextHebDate(nextHebDate(dt))) ||
	   MATCH(holidays[c].date,nextHebDate(dt))) &&
	  (weekday == THU))	   
	addHoliday(holidays[c],holiList);
      
				/* if the date actually falls */
				/* on thursday or friday*/
      if (holidays[c].typeMask & MUKDAM2 && 
	  (MATCH(holidays[c].date,nextHebDate(nextHebDate(dt))) ||
	   MATCH(holidays[c].date,nextHebDate(dt))) && 
	  (weekday == WED))	   
	addHoliday(holidays[c],holiList);
    }
  
  /* Lag B'Omer Processing */
  if (omer == 33) {
    tmpholip = &special[specialCounter++];
    initStr(&tmpholip->name,NM_LEN); 
    strncpy(tmpholip->name,"Lag B'Omer",NM_LEN);
    addHoliday(*tmpholip,holiList);
  }

  if ((dt.dd == 29) && (dt.mm == 2)) 
    chanukah_day = 1;
  
  if (chanukah_day) {
    addHoliday(chanukah_arr[chanukah_day],holiList);
    if (chanukah_day == 4)
      chanukah_day = 0;
    else chanukah_day++;
  }


  /* rosh Chodesh Processing... */
  if (dt.dd == 1 && dt.mm){	/* every 1st of the month except tishrei */
    tmpholip = &special[specialCounter++];
    initStr(&tmpholip->name,NM_LEN); 
    strcat(tmpholip->name,"Rosh Chodesh ");
    strncat(tmpholip->name,hMonths[LEAP_YR_HEB(dt.yy)][dt.mm].name,NM_LEN);
    addHoliday(*tmpholip,holiList);
  }
  if (dt.dd == 30){
    tmpholip = &special[specialCounter++];
    initStr(&tmpholip->name,NM_LEN);
    strcat(tmpholip->name,"Rosh Chodesh ");
    strncat(tmpholip->name,hMonths[LEAP_YR_HEB(dt.yy)][dt.mm+1].name,NM_LEN);
    addHoliday(*tmpholip,holiList);
  }
  
  
  return *holiList;
}


void incHebJulDate(dth,dtj,wkday)
     date_t *dth, *dtj;
     int *wkday;
{
  /* increments both hebrew and julian calendars */
  
  incDate (dtj,1);
  *wkday = dayOfWeek(*dtj);
  *dth = nextHebDate(*dth);
}   

#define JUL2HEB(x) ((x)+ 3760)

void PrintWeekday (dt) 
     date_t dt;{
       printf ("%s, ",ShortDayNames[dayOfWeek(dt)]);
     }
     
     void PrintJulDate (dt) 
     date_t dt;
{
  if (!suppressGreg_sw) 
    if (euroDates_sw)
      printf ("%d.%d.%d ",dt.dd,dt.mm+1,dt.yy);
    else
      printf ("%d/%d/%d ",dt.mm+1,dt.dd,dt.yy);
}


char *DoSedra (sedra, ydat)	/* returns a string "Parshat <parsha>" */
     int *sedra;		/* based on the current parsha number */
     year_t ydat;
{
#define PLENGTH 40
  static char s[PLENGTH+1];
  
  *s = '\0';
  strncat(s,"Parshat ",PLENGTH);
  strncat(s,sedrot[*sedra],PLENGTH);
  switch (*sedra) {
  case VAYAKHEL :
    if (ydat.vayakhelPikudei){
      strncat(s,"-",PLENGTH);
      strncat(s,sedrot[*sedra+1],PLENGTH);
      *sedra += 2;
    }
    else {
      (*sedra)++;
    }
    break;
  case TAZRIA:
    if (ydat.tazriaMetzorah){
      strncat(s,"-",PLENGTH);
      strncat(s,sedrot[*sedra+1],PLENGTH);
      *sedra += 2;
    }
    else (*sedra)++;
    break;
  case ACHREI :
    if (ydat.achreiKedoshim){
      strncat(s,"-",PLENGTH);
      strncat(s,sedrot[*sedra+1],PLENGTH);
      *sedra += 2;
    }
    else (*sedra)++;
    break;
  case BEHAR :
    if (ydat.beharBech){
      strncat(s,"-",PLENGTH);
      strncat(s,sedrot[*sedra+1],PLENGTH);
      *sedra += 2;
    }
    else (*sedra)++;
    break;
  case CHUKAT :
    if (ydat.chukatBalak){
      strncat(s,"-",PLENGTH);
      strncat(s,sedrot[*sedra+1],PLENGTH);
      *sedra += 2;
    }
    else (*sedra)++;
    break;
  case MATOT :
    if (ydat.matotMasei){
      strncat(s,"-",PLENGTH);
      strncat(s,sedrot[*sedra+1],PLENGTH);
      *sedra += 2;
    }
    else (*sedra)++; 
    break;
  case NITZAVIM :
    if (ydat.nitzavimVayelech){
      strncat(s,"-",PLENGTH);
      strncat(s,sedrot[*sedra+1],PLENGTH);
      *sedra += 2;
    }
    else (*sedra)++; 
    break;
  case LAST_INDEX(sedrot)-1:
    *sedra = 0;
    break;
  default:
    (*sedra)++;
  }
  strncat(s,"\n",PLENGTH);
  return s;
}

#define CHAR2NUM(x) ((x) - '0')


void DoCalendar (roshDt,justMonth,justDay)
     date_t roshDt;	/* rosh Hashana of preceeding year */
     int justMonth,/* print this month  */
       justDay; 
{ /* print this day */
	 
	 
  int sedra,weekday;
	 date_t todayj, todayh;
	 holiday_t *holip;
	 year_t theYear;
	 todayj = roshDt;
	 
	 todayh.mm = 0;
	 todayh.dd = 1;
	 todayh.yy = JUL2HEB(roshDt.yy)+1; /* because it's after R"H */
	 
	 
	 theYear = yearData(todayh.yy);
	 
	 if (CHAR2NUM(theYear.name[0]) != dayOfWeek(roshDt))
	   die ("Bad Day!\n","");  
	 
	 /* first scan forward to simchat Torah, keeping track of dates only. */
	 while (todayh.dd != SIMCHAT_DAY)
	   incHebJulDate(&todayh, &todayj,&weekday);

	 sedra = 0;		/* initialize sedra */
	 
	 /* then continue until january 1st. */
	 do {
	   getHebHolidays(todayj,weekday,theYear,&holip);
	   if ((weekday == SAT) && !(holip && holip->typeMask & OWNSEDRA)) 
	     DoSedra(&sedra,theYear);
	   incHebJulDate(&todayh,&todayj,&weekday);
	 } while (!((todayj.mm==0) && (todayj.dd==1)));
	 
	 /* -------Main Year Loop-------*/
	 do {
	   if (hebDates_sw && 
	       (!specMonth_sw || (justMonth== todayj.mm)) &&
	       (!specDay_sw   || (justDay == todayj.dd))) {
	     PrintJulDate(todayj);
	     if (weekday_sw)
	       PrintWeekday(todayj);
	     printf ("%d%s of %s, %d\n",todayh.dd, /* print the hebrew date */
		     numSuffix(todayh.dd),
		     hMonths[LEAP_YR_HEB(todayh.yy)][todayh.mm].name,
		     todayh.yy);
	   }
	   getHebHolidays(todayh,weekday,theYear,&holip); 
	   
	   if ((todayh.mm == TISHREI) && (todayh.dd == 1))
	     theYear = yearData(todayh.yy); /* if R"H reset YearData */
	   
	   if (sedrot_sw && (weekday == SAT) && 
	       !(holip && holip->typeMask & OWNSEDRA)){
	     if ((!specMonth_sw || (justMonth == todayj.mm)) &&
		 (!specDay_sw   || (justDay == todayj.dd))){
	       PrintJulDate(todayj);	
	       printf("%s",DoSedra(&sedra,theYear));
	     }
	     else DoSedra(&sedra,theYear);
	   }
	   
	   if ((todayh.mm == TISHREI) && /* reset the sedra on simchat torah */
	       (todayh.dd == SIMCHAT_DAY)) sedra =0; 
	   
	   if (!suppressHolidays_sw &&
	       (!specMonth_sw || (justMonth == todayj.mm)) &&
	       (!specDay_sw   || (justDay == todayj.dd))) 
	     for (;holip;holip = holip->next) {
	       PrintJulDate(todayj);
	       if (weekday_sw)
		 PrintWeekday(todayj);
	       printf ("%s\n",holip->name);
	     }
	   
	   /* print the omer if desired */
	   if (omer && printOmer_sw && 
	       (!specMonth_sw || (justMonth == todayj.mm)) &&
	       (!specDay_sw   || (justDay == todayj.dd))) {
	     char *omerStr;
	     initStr(&omerStr,NM_LEN); 
	     strncat(omerStr,itoa(omer),NM_LEN);
	     strncat(omerStr,numSuffix(omer),NM_LEN);
	     strncat(omerStr," day of the Omer",NM_LEN);
	     PrintJulDate(todayj);
	     if (weekday_sw) PrintWeekday(todayj);
	     printf ("%s\n",omerStr);
	   }
	   if (omer) omer++;
	   
	   
	   incHebJulDate(&todayh,&todayj,&weekday);
	 } while (!((todayj.mm==0) && (todayj.dd==1))); /* continue to january 1st */
	 
       }
     
     void RollBack(dtj,target) /* move rosh hashana dtj back until it's */
     date_t *dtj;		  /* in the year before target */
     int target;{
       
       int days,theyear;
       
       for (days = 0,theyear = dtj->yy ;theyear > target -1; theyear--)
	 days +=yearData(JUL2HEB(theyear)).length;
       decDate (dtj,days); 
       
     }
     
     void RollForward(dtj,target)   /* move rosh hashana dtj forward until it's*/
     date_t *dtj;		       /*  in the year before target*/
     int target; {
       int days,theyear;
       
       for (days = 0,theyear = dtj->yy ;theyear < target -1; theyear++)
	 days +=yearData(JUL2HEB(theyear+1)).length;
       incDate (dtj,days); 
       
     }
     
     char * progname;
     
     int main (argc, argv)
     int argc;
     char *argv[];
{
  char *c;
  date_t startDate,tempdt;
  int theYear,theMonth,theDay,yearDirty=0;
  
  char * usage = "usage: hebcal [-dehostTw] [[month [day]] year]\n               hebcal help\n";  
  progname = argv[0];
  
  startDate.dd = 28;
  startDate.mm = SEP; /* any ol' rosh hashana */
  startDate.yy = 1992;
  
  setDate(&tempdt);		/* do this year */
  theYear = tempdt.yy;
  
  for (argv++, argc--; argc; argv++, argc--)
    if (isAllNums(*argv))
      if ((argc-1) && isAllNums(*(argv+1)) && !yearDirty) 
	if ((argc-2) && isAllNums(*(argv+2))) {
	  specMonth_sw =1;
	  specDay_sw =1;
	  theMonth = atoi(*argv) -1; /* year and month specified */
	  theDay = atoi(*++argv); /* print theDay of theMonth */
	  theYear = atoi(*++argv); /* print theMonth of theYear */
	  yearDirty =1;
	  argc -=2;
	}
	else {
	  specMonth_sw =1;
	  theMonth = atoi(*argv) -1; /* year and month specified */
	  theYear = atoi(*++argv); /* print theMonth of theYear */
	  yearDirty =1;
	  argc--;
	}
      else if (!yearDirty) {
	theYear = atoi(*argv);	/* just year specified */
	yearDirty = 1;		/* print whole year */
      }
      else 	die(usage,"");
    else if (**argv == '-')
      for (c = *argv,c++;*c;c++)
	switch (*c) {
	case 'd' :		/* print hebrew dates */
	  hebDates_sw = 1;
	  break;
	case 'e':
	  euroDates_sw =1;
	  break;
	case 'h':
	  suppressHolidays_sw =1;
	  break;
	case 't':		/* do hebcal for today. */
	  specMonth_sw =1;
	  specDay_sw =1;
	  theMonth = tempdt.mm; /* year and month specified */
	  theDay = tempdt.dd; /* print theDay of theMonth */
	  yearDirty =1;
	  break;
	case 'T':		/* do hebcal for today, omit gregorian date. */
	  suppressGreg_sw = 1;
	  specMonth_sw =1;
	  specDay_sw =1;
	  theMonth = tempdt.mm; /* year and month specified */
	  theDay = tempdt.dd; /* print theDay of theMonth */
	  yearDirty =1;
	  printOmer_sw =1;
	  break;
	case 'o':
	  printOmer_sw =1;
	  break;
	case 's' :		/* print sedrot */
	  sedrot_sw = 1;
	  break;
	case 'w' :		/* print days of the week */
	  weekday_sw = 1;
	  break;
	default: die(usage,"");
	}
    else if (!strcmp(*argv,"help")) {
      printf ("Hebcal Version 1.4\n\n");
      printf ("Hebcal prints out hebrew calendars one solar year at a time.\n");
      printf ("Given one numeric argument, it will print out the calendar \n");
      printf ("for that year.  Given two numeric argumetnts mm yyyy, it\n");
      printf ("prints out the calendar for month mm of year yyyy. \n");
      printf (usage);
      printf ("\nOPTIONS:\n   -d : add hebrew dates\n");
      printf ("   -e : use european dates for OUTPUT ONLY (input format the same)\n");
      printf ("   -h : suppress holidays\n");
      printf ("   -o : add days of the omer\n");
      printf ("   -s : add weekly sedrot \n");
      printf ("   -t : only output for today's date\n");
      printf ("   -T : print today's pertinent information, no gregorian date\n");
      printf ("   -w : add day of the week\n\n");
      printf ("       hebcal help --- prints this message\n"); 
      printf ("\nExample: \n");
      printf ("   hebcal -ho\n");
      printf ("will just print out the days of the omer for the current year.\n");
      exit(0);
    }
    else die (usage,"");
  
  if (specDay_sw) hebDates_sw = 1;
  
  if (theYear < startDate.yy +1) /* go to R"H of the year before */
    RollBack(&startDate,theYear);
  else if (theYear > startDate.yy +1) /* start from there */
    RollForward(&startDate,theYear);
  
  DoCalendar(startDate,theMonth,theDay);   
  
  return 0;
}
