andrew@inmet.UUCP (08/19/84)
#N:inmet:12900003:000:9639 inmet!andrew Aug 17 11:01:00 1984 The following program generates a calendar for a given month. Lots of programs do that, of course; this one generates a full-page calendar with ample room to scrawl reminders of meetings, appointments, etc. I originally wrote this (in Fortran-IV, on GE Timesharing) as a programming project while a sophomore in high school; to this day, it is usually the first program I write (after "Hello, world") when adapting to a new language. Anyway, here's a C version for netland. You have my permission to do anything you want with it (except sell it); I'd particularly like to see someone adapt it to a laser printer. Andrew W. Rogers TEAR ALONG DOTTED LINE (don't forget to remove any junk at bottom) ---------------------------------------------------------------------------- /* * Calendar program - one page per month (writes to standard output) * * calen [month] year [len] [-o] * * If one of the numeric arguments {month, year, len} is specified, it * is assumed to be the year; calendar generated is for entire year. * (Note: Unlike the UN*X 'cal', nn is treated as 19nn.) * * If two numeric arguments are specified, first is assumed to be the * month (1-12) and second the year; calendar generated is for that * month/year only. * * If all are specified, calendar generated is for 'len' consecutive * months starting at month/year. * * If last argument is '-o' flag, output will contain backspaces and * overstrikes to emphasize month and year. (Not all printers can * handle this; check local conventions before printing. If using * 'lp' on PWB, use its '-o' flag to convert the backspaces to * overstruck lines.) * * Author: AW Rogers * * Originally written in Fortran-IV on GE Timesharing, 10/65 * Converted to C/UN*X, 3/83 */ /* * Constant definitions: */ #define MIN 1753 /* Valid years (1753: start of Gregorian calendar) */ #define MAX 9999 #define JAN 1 /* Significant months and weekdays */ #define DEC 12 #define SUN 0 #define SAT 6 #define SINGLE "*" /* Normal and overstrike (XIH*) character sequences */ #define OVERSTRIKE "X\bI\bH\b*" /* * Macro definitions: */ #define day_of_week(I) ((I) % 7) /* * Global declarations: */ char output_seq[8]; /* either SINGLE or OVERSTRIKE; used in PrintChar */ /* * Main(argc, argv) * * Gets and checks command line arguments; prints desired calendar(s) */ main(argc, argv) int argc; char *argv[]; { int mon, year, len; /* Command line arguments */ /* * Get and verify command line arguments (see above) */ /* Check for -o as last command line argument (ignore erroneous flags) */ if (argv[argc-1][0] == '-' && argv[--argc][1] == 'o') strcpy(output_seq, OVERSTRIKE); else strcpy(output_seq, SINGLE); /* Supply defaults for numeric arguments as described above */ switch (argc) { case 2: /* 1 argument supplied (year) */ sscanf(argv[1], "%d", &year); mon = JAN; len = 12; break; case 3: /* 2-3 arguments supplied (mon year [len]) */ case 4: sscanf(argv[1], "%d", &mon); sscanf(argv[2], "%d", &year); if (argc == 3) len = 1; else sscanf(argv[3], "%d", &len); break; default: printf("usage: %s [month] year [len] [-o]\n", argv[0]); return; } /* end switch */ /* Validate month and year; quit if invalid */ if (year > 0 && year < 100) /* Convert nn to 19nn first */ year += 1900; if (year < MIN || year > MAX || mon < JAN || mon > DEC) { printf("valid months: %d..%d; valid years: %d..%d\n", JAN, DEC, MIN, MAX); return; } /* * Main loop: prints calendar for each requested month */ while (len-- > 0) { PrintCal(mon, year); /* Prepare for next month's calendar */ if (++mon > DEC) { /* Bump month (and year) */ mon = JAN; if (++year > MAX) /* Quit if year too big */ return; } } /* end calendar generation loop */ } /* end main */ /* * PrintCal(mon, year) * * Prints calendar for specified month and year (assumed valid) */ PrintCal(mon, year) int mon, year; { int i, j, k, /* General-purpose loop indices */ start, end, /* Range of calendar boxes containing dates */ date = 0, /* Date to print inside box */ chars; /* Length of current month name */ static char blanks[36] = " "; /* String of blanks for centering heading */ char digits[5], /* Individual digits of year (for printing) */ *padding; /* Pointer to effective start of 'blanks' */ /* * Names and lengths of months (first element is dummy): */ static struct { char *name; /* name of month */ char len[2]; /* number of days (non-leap, leap) */ char first[2]; /* first of month wrt 1/1 (same) */ } month[13] = { {"", {0,0}, {0,0}}, {"JANUARY", {31,31}, {0,0}}, {"FEBRUARY", {28,29}, {3,3}}, {"MARCH", {31,31}, {3,4}}, {"APRIL", {30,30}, {6,0}}, {"MAY", {31,31}, {1,2}}, {"JUNE" , {30,30}, {4,5}}, {"JULY", {31,31}, {6,0}}, {"AUGUST", {31,31}, {2,3}}, {"SEPTEMBER", {30,30}, {5,6}}, {"OCTOBER", {31,31}, {0,1}}, {"NOVEMBER", {30,30}, {3,4}}, {"DECEMBER", {31,31}, {5,6}}}; /* * Names of weekdays, centered (roughly) in 9-character field: */ static char weekday[7][10] = {" SUNDAY ", "MONDAY ", " TUESDAY ", "WEDNESDAY", "THURSDAY ", " FRIDAY ", "SATURDAY "}; /* * 5 x 7 dot-matrix representations of letters A-Z and digits 0-9. * Printed as large characters (using ' ' and '*'); see PrintChar. */ static char large_letters[26][7] = { 14,17,17,31,17,17,17, 30,17,17,30,17,17,30, 14,17,16,16,16,17,14, 30,17,17,17,17,17,30, 31,16,16,30,16,16,31, 31,16,16,30,16,16,16, 14,17,16,23,17,17,14, 17,17,17,31,17,17,17, 31,4,4,4,4,4,31, 1,1,1,1,1,17,14, 17,18,20,24,20,18,17, 16,16,16,16,16,16,31, 17,27,21,21,17,17,17, 17,17,25,21,19,17,17, 14,17,17,17,17,17,14, 30,17,17,30,16,16,16, 14,17,17,17,21,18,13, 30,17,17,30,20,18,17, 14,17,16,14,1,17,14, 31,4,4,4,4,4,4, 17,17,17,17,17,17,14, 17,17,17,17,17,10,4, 17,17,17,17,21,21,10, 17,17,10,4,10,17,17, 17,17,17,14,4,4,4, 31,1,2,4,8,16,31}; static char large_digits[10][7] = { 14,17,17,17,17,17,14, 2,6,10,2,2,2,31, 14,17,2,4,8,16,31, 14,17,1,14,1,17,14, 2,6,10,31,2,2,2, 31,16,16,30,1,17,14, 14,17,16,30,17,17,14, 31,1,2,4,8,16,16, 14,17,17,14,17,17,14, 14,17,17,15,1,17,14}; /* * Initialize starting weekday of first month (first box to contain a * date) and digits in year (for printing in 5x7 format): */ start = year + (year - 1)/4 - (year - 1)/100 + (year - 1)/400; start = day_of_week(start + month[mon].first[IsLeap(year)]); sprintf(digits, "%4d", year); /* * Print heading with month and year in large letters/digits */ printf("\f\n\n\n"); SolidLine(2); BorderLine(2); /* Create a string of blanks for centering month/year */ chars = strlen(month[mon].name); padding = &blanks[3 * (chars - 3)]; /* Print 7 lines containing the month and year in large characters */ for (j = 0; j <= 6; ++j) { printf(" **%s", padding); for (k = 0; k <= chars - 1; ++k) /* Letters in month name */ PrintChar(large_letters[month[mon].name[k] - 'A'][j]); printf("%12s", " "); for (k = 0; k <= 3; ++k) /* Digits in year */ PrintChar(large_digits[digits[k] - '0'][j]); printf(" %s**\n", padding); } /* Print names of weekdays above calendar boxes */ BorderLine(2); SolidLine(2); BoxLine(1); printf(" **"); for (j = SUN; j <= SAT; ++j) printf("%13s%5s", weekday[j], "*"); printf("*\n"); /* * Print body of calendar */ end = start + month[mon].len[IsLeap(year)] - 1; /* Last date to print */ /* Print first 5 weeks of calendar */ for (j = 0; j <= 34; ++j) { if (day_of_week(j) == SUN) { /* Top and left border */ BoxLine(1); SolidLine(1); printf(" **"); } if (j >= start && j <= end) /* Date or blank */ printf("%3d%15s", ++date, "*"); else printf("%18s", "*"); if (day_of_week(j) == SAT) { /* Right border and bottom */ printf("*\n"); BoxLine(5); } } /* Print last line (with 30/31 if needed) and bottom border */ printf(" **"); for (j = 35; j <= 41; ++j) if (j <= end) /* Print date or blank */ printf("%16d%2s", ++date, "*"); else printf("%18s", "*"); printf("*\n"); SolidLine(2); } /* end PrintCal */ /* * IsLeap(y) * * Return 1 if year y is leap; 0 if not */ int IsLeap(y) int y; { return y % 4 == 0 && y % 100 != 0 || y % 400 == 0; } /* end IsLeap */ /* * PrintChar(i) * * Prints least significant 6 bits of i in binary representation, * using ' ' for 0 and '*' for 1. */ PrintChar(i) char i; { int msk = 32; /* Output field width = log2(msk)+1 = 6 */ for (; msk > 0; msk /= 2) if (i & msk) printf(output_seq); /* Globally defined */ else printf(" "); } /* end PrintChar */ /* * BorderLine(n) * * Print n border lines (** 125 spaces **) */ BorderLine(n) int n; { static char c[] = "**"; while (n--) printf(" %2s%127s\n", c, c); } /* end BorderLine */ /* * BoxLine(n) * * Print n box lines (** 17 spaces * 17 spaces .. **) */ BoxLine(n) int n; { static char c[] = "*"; while (n--) printf(" **%18s%18s%18s%18s%18s%18s%18s*\n", c, c, c, c, c, c, c); } /* end BoxLine */ /* * SolidLine(n) * * Print n solid lines (129 *) */ SolidLine(n) int n; { static char c[] = "*******************************************"; while (n--) printf(" %43s%43s%43s\n", c, c, c); } /* end SolidLine */