#define DEBUG /* * Sfirat HaOmer program by Warren Burstein * V1, 17 Nisan 5747. * V2, real Hebrew, 8 Nisan 5751. * * The Hebrew Calendar stuff comes from a program I got from * a friend. It did not contain any copyrights, but mentioned * Mark Chodrow, Aarom Wyner, and Dave Sherman as having worked on it. * * I originally wrote the Sfirah part as a shell script but got tired * of changing it each year to tell it when Pesach was. * * The stuff to count in Hebrew is ugly and should not be used * anywhere you need to count beyond 49. If you can do it better * I would be pleased to incorporate your improvements. * Pronunciation is the way I say it, your actual milage may differ. * * "omer -a" prints all the counts in all languages, it's for testing. * "omer -e" prints in english * "omer -t" prints in transliterated hebrew * "omer -h" prints in hebrew * If the environment variable TERM starts with "vt", it's assumed * that aleph is 0xe0. Otherwise, it's assumed that aleph is 0x80. * * If you run this between MIN_SUNSET and MAX_TZAYT, it prints both * today's and tonight's count. After MAX_TZAYT, it prints tonight's. * These are guesses for New York City. You may have to change them. * * I really need an algorithm to compute sunset based on date and * lat/long. If you have one, please let me know so I can put * it in here. * * /|/-\/-\ * |__/__/_/ * | * / * warren@itex.jct.ac.il */ #define MIN_SUNSET (12+7) #define MAX_TZAYT (12+10) #define omer_during(n) ((n) >= 1 && (n) <= 49) #include #include #define TRUE 1 #define FALSE 0 /* * Bit values for "languages". */ #define ENGLISH 1 #define TRANSLIT 2 #define HEBREW 4 /* * Codes for "language", not an enum because it's used to index arrays. */ #define english 0 #define translit 1 #define hebrew 2 #define translit_vav 3 #ifdef DEBUG # define EMPTY "-foo-" #else # define EMPTY "" #endif #ifdef M_XENIX void exit(); #endif #ifdef BSD # define strchr index #endif struct Gdate { int Gyr; /* year in gregorian calendar */ int Gmo; /* January is zero */ int Gda; /* day in month */ int Gdw; /* day of week */ int Gdy; /* days since Jan 1 */ } Gd; int d_g[2][12] = { /* sep oct mov dec jan feb mar apr may jun jul aug */ { 30, 31, 30, 31, 31, 28, 31, 30, 31, 30, 31, 31 }, { 30, 31, 30, 31, 31, 29, 31, 30, 31, 30, 31, 31 } }; #define JANUARY 4 /* index into d_g for January */ int d_h[6][14] = { /* tis hes kis tev svt adr nis iyr siv tmz av ell */ { 0, 30, 29, 29, 29, 30, 29, 30, 29, 30, 29, 30, 29 }, { 0, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29 }, { 0, 30, 30, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29 }, /* tis hes kis tev svt adr adr nis iyr siv tmz av ell */ { 0, 30, 29, 29, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29 }, { 0, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29 }, { 0, 30, 30, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29 } }; int vt_mode = FALSE; main(argc, argv) char **argv; { int yr, leap, count; int print_all = FALSE, print_one = 0, languages = 0, c; long secs, time(); char *term, *getenv(); struct tm *tbuf, *localtime(); extern char *optarg; if (term = getenv("TERM")) if (strncmp(term, "vt", 2) == 0) vt_mode = TRUE; while ( (c = getopt(argc, argv, "aeth?n:")) != EOF) { switch (c) { case 'n': print_one = atoi(optarg); break; case 'a': print_all = TRUE; break; case 'e': languages |= ENGLISH; break; case 't': languages |= TRANSLIT; break; case 'h': languages |= HEBREW; break; default: usage(argv[0]); } } if (languages == 0) languages = ENGLISH | TRANSLIT; if (print_one) { omer(print_one, languages); exit(0); } if (print_all) { test_counts(languages); exit(0); } secs = time((long *) 0); tbuf = localtime(&secs); yr = tbuf->tm_year + 1900 - 1; leap = rh(yr) > rh(yr + 1) ? 0 : 1; heb_greg(yr + 3761, 7 + leap, 15); count = tbuf->tm_yday - Gd.Gdy; if (tbuf->tm_hour < MIN_SUNSET) omer(count, languages); else if (tbuf->tm_hour >= MIN_SUNSET && tbuf->tm_hour <= MAX_TZAYT) { omer(count, languages); if (omer_during(count) && omer_during(count + 1)) (void) printf("\nor\n\n"); omer(count + 1, languages); } else omer(count + 1, languages); exit(0); #ifdef lint return 0; #endif } usage(argv0) char *argv0; { (void) fprintf(stderr, "usage: %s [-aeth]\n", argv0); (void) fprintf(stderr, "\t-a displays all counts in selected languages\n"); (void) fprintf(stderr, "\t-e requests english\n"); (void) fprintf(stderr, "\t-t requests transliterated Hebrew\n"); (void) fprintf(stderr, "\t-h requests Hebrew (use on 8-bit displays,\n"); (void) fprintf(stderr, "or VT-XXX's if TERM stats with \"vt\"\n"); } heb_greg(hyr, hmo, hdayno) register int hyr, hmo, hdayno; { int isaleap, rhgr0; int type, xx; int day_in_year, month; hyr -= 3760; /* Gregorian year of next RH */ isaleap = ( (hyr % 400 == 0) || ( (hyr % 4 == 0) && (hyr % 100 != 0)) ); /* * Find which type of Hebrew year hyr is * 12 months is 0-2, 13 months is 3-5 */ type = ytyp(rh(hyr) - (rhgr0 = rh(hyr - 1)) + isaleap); while (hmo > 1) hdayno += d_h[type][--hmo]; /* Now count up from RH hdayno days in the Gregorian calandar */ hmo = 0; if (rhgr0 > 30) { hmo = 1; rhgr0 = rhgr0 - 30; /* RH in Oct */ } xx = hdayno - (d_g[isaleap][hmo] - rhgr0 + 1); if (xx > 0) { ++hmo; while (xx > d_g[isaleap][hmo]) xx -= d_g[isaleap][hmo++]; Gd.Gda = xx; } else Gd.Gda = hdayno + rhgr0 - 1 ; /* The Gregorian year is hyr - 1 if hmo < 4 otherwise it is hyr */ if (hmo < 4) --hyr; hmo = hmo != 3 ? (hmo + 9) % 12 : 12; Gd.Gmo = hmo - 1; Gd.Gyr = hyr; /* * Compute days since Jan 1. */ day_in_year = Gd.Gda - 1; for (month = 0; month < Gd.Gmo; month++) day_in_year += d_g[isaleap][month + JANUARY]; Gd.Gdy = day_in_year; } ytyp(magic) register int magic; /* magic < 0 => leap; magic > 0 => common */ { if (magic < -12 || magic > 20 || magic > -10 && magic < 3) return 0; return magic < 0 ? magic + 12 : magic - 15; } rh(yr) int yr; { register int day, xx, n2; int au; float fraction, n1; struct Gdate gdt; au = yr % 19 + 1; /* "golden number" */ n1 = yr / 100 - yr / 400 - 2.0 + (765433.0 / 492480.0) * (12 * au % 19) + (yr % 4) / 4.0 - (313.0 * yr + 89091.0) / 98496.0; n2 = n1; /* this is 'N' in Conway's formula */ gdt.Gyr = yr; gdt.Gmo = 8; /* mmc had '9' instead of '8' */ gdt.Gda = n2; dayofwk(&gdt); day = gdt.Gdw; fraction = n1 - n2; xx = 12 * au % 19; if (day == 1 || day == 4 || day == 6) { n2 = n1 + 1; day += 1; } else if (day == 3 && fraction >= 1367.0 / 2160.0 && xx > 6) { day = 5; n2 += 2; } else if (day == 2 && fraction >= 23269.0 / 25920.0 && xx > 11) { day = 3; n2 += 1; } return n2; } /* * This subroutine computes the day of week of the unadjusted RH * The month is reduced by 2 - ie September is the 7th month */ int d_[] = { 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29 }; dayofwk(pGd) struct Gdate *pGd; { register int dayofyr, yr, mo; int xx; yr = pGd->Gyr; mo = pGd->Gmo - 1; while (yr < 0) yr += 2000; while (yr >= 2000) yr -= 2000; if (mo <= 0) mo += 12; if (mo >= 11) yr -= 1; dayofyr = pGd->Gda; while (mo > 1) dayofyr += d_[--mo]; xx = yr < 0 ? 1 : 0 ; /*adjust for 2000 a leap year*/ /* mo value no longer needed */ mo = (dayofyr + yr - xx + (yr + xx) / 4 - (yr + xx) / 100 + (yr + xx) / 400 + 3) % 7; pGd->Gdw = mo >= 0 ? mo : mo + 7; /* return remainder into [0,6] */ } omer(days, languages) { int weeks, remdays; char buf[100], *s; if ( !omer_during(days)) return; weeks = days / 7; remdays = days % 7; if (languages & ENGLISH) { (void) strcpy(buf, "Today is "); enumerate(buf, days, "day", "days", english); if (weeks) { (void) strcat(buf, " which are "); enumerate(buf, weeks, "week", "weeks", english); if (remdays) { (void) strcat(buf, " and "); enumerate(buf, remdays, "day", "days", english); } } (void) strcat(buf, " in the Omer."); (void) printf("%s\n", buf); } if (languages & TRANSLIT) { (void) strcpy(buf, "Hayom "); enumerate(buf, days, "yom", "yamim", translit); if (weeks) { (void) strcat(buf, " shehaym "); enumerate(buf, weeks, "shavuah", "shavuot", translit); if (remdays) { (void) strcat(buf, " "); enumerate(buf, remdays, "ve-yom", "yamim", translit_vav); } } (void) strcat(buf, " la-omer."); (void) printf("%s\n", buf); } if (languages & HEBREW) { (void) strcpy(buf, " "); enumerate(buf, days, "", "", hebrew); if (weeks) { (void) strcat(buf, " "); enumerate(buf, weeks, "", "", hebrew); if (remdays) { (void) strcat(buf, " "); enumerate(buf, remdays, "", "", hebrew); } } (void) strcat(buf, " "); reverse(buf); if (vt_mode) for (s = buf; *s; s++) if (*s & 0x80) *s += 0x60; (void) printf("%s\n", buf); } } /* * Each of these arrays uses the language for the first index. */ char *tens[4][5] = { {EMPTY, EMPTY, "twenty", "thirty", "fourty"}, {EMPTY, EMPTY, "'esrim", "shloshim", "arba'im"}, {EMPTY, EMPTY, "", "", ""}, {EMPTY, EMPTY, "v-'esrim", "ushloshim", "v-arba'im"} }; /* * Teens are irregular in english, Hebrew are prounounced differently * than units so transliateration needs to have them listed separately, */ char *units[4][20] = { { EMPTY, "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", }, { EMPTY, "echad", "shnayim", "shloshah", "arba'ah", "chamishah", "shishah", "shiv'ah", "shmonah", "tish'ah", "'asarah", "ahad asar", "shnaym asar", "shloshah asar", "arba'ah asar", "chamishah asar", "shishah asar", "shiv'ah asar", "shmonah asar", "tish'ah asar", }, { EMPTY, "", "", "", "", "", "", "", "", "", "", EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, }, { EMPTY, EMPTY, EMPTY, "ushloshah", "ve-arba'ah", "vechamishah", "veshishah", EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, }, }; char *two[4] = {EMPTY, "shnay", "", "ushnay"}; char *teen = ""; enumerate(s, count, singular, plural, language) char *s, *singular, *plural; { static char buf[100]; /* * In Hebrew, above ten, count "yom" instead of "yamim". */ if (language != english && count > 10) plural = singular; if (count == 1) switch (language) { case english: (void) sprintf(buf, "%s %s", units[english][1], singular); break; case translit: case translit_vav: (void) sprintf(buf, "%s %s", singular, units[translit][1]); break; case hebrew: (void) sprintf(buf, "%s %s", singular, units[hebrew][1]); break; } else if (count < 20) if (count == 2 && language != english) (void) sprintf(buf, "%s %s", two[language], plural); else if (count > 10 && language == hebrew) (void) sprintf(buf, "%s %s %s", units[language][count % 10], teen, plural); else (void) sprintf(buf, "%s %s", units[language][count], plural); else if (count % 10) switch (language) { case english: (void) sprintf(buf, "%s-%s %s", tens[english][count / 10], units[english][count % 10], plural); break; case translit: (void) sprintf(buf, "%s %s %s", units[translit][count % 10], tens[translit_vav][count / 10], plural); break; case hebrew: (void) sprintf(buf, "%s %s %s", units[hebrew][count % 10], tens[hebrew][count / 10], plural); break; } else switch (language) { case english: case translit: (void) sprintf(buf, "%s %s", tens[language][count / 10], plural); break; case hebrew: (void) sprintf(buf, "%s %s", tens[language][count / 10], plural); break; } (void) strcat(s, buf); } test_counts(languages) { int day; for (day = 0; day < 51; day++) omer(day, languages); } /* * Reverse the string into itself. */ reverse(s) char *s; { char *p, temp; for (p = s + strlen(s) - 1; p > s; p--, s++) { temp = *p; *p = *s; *s = temp; } } /* * Public-domain getopt. */ #define ERR(s, c) if(opterr){\ (void) fputs(argv[0], stderr);\ (void) fputs(s, stderr);\ (void) fputc(c, stderr);\ (void) fputc('\n', stderr);} int opterr = 1; int optind = 1; char *optarg; char *strchr(); int getopt(argc, argv, opts) char **argv, *opts; { static int sp = 1; char c; char *cp; if (sp == 1) { if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') return EOF; if (strcmp(argv[optind], "--") == 0) { optind++; return EOF; } if (strcmp(argv[optind], "-?") == 0) { optind++; return '?'; } } c = argv[optind][sp]; if (c == ':' || (cp = strchr(opts, c)) == (char *) 0) { ERR(": illegal option -- ", c); if (argv[optind][++sp] == '\0') { optind++; sp = 1; } return '?'; } if (*++cp == ':') { if (argv[optind][2] != '\0') optarg = &argv[optind++][sp+1]; else if (++optind >= argc) { ERR(": option requires an argument -- ", c); sp = 1; return '?'; } else optarg = argv[optind++]; sp = 1; } else if (argv[optind][++sp] == '\0') { sp = 1; optind++; } return c; }