Full-page calendar program - (nf)
andrew at inmet.UUCP
andrew at inmet.UUCP
Sun Aug 19 14:59:10 AEST 1984
#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 */
More information about the Comp.sources.unix
mailing list