home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume6
/
calen
< prev
next >
Wrap
Text File
|
1989-03-25
|
17KB
|
547 lines
Newsgroups: comp.sources.misc
From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
Subject: v06i081: another calendar program
Summary: new, improved
Reply-To: awr@genrad.genrad.COM (Andrew W. Rogers)
Organization:
Posting-number: Volume 6, Issue 81
Submitted-by: awr@genrad.COM (Andrew W. Rogers)
Archive-name: calen
Here's another calendar program which I think is considerably more
useful than pcal. For starters, the calendars really do occupy a full
line-printer page; they also include small calendars for the previous
and subsequent months along with a month/year heading in 5x9
dot-matrix characters, printed with overstrikes (on line printers
capable of handling them). Options are available to select:
1) right- or left- justification of the dates within the boxes
2) mixed- or upper-case names of months and days
3) overstrike sequence used to print month/year heading (useful for
printers which do not support overstrikes, since a single character
can be specified - try "-o@")
4) number of blank lines at top of page (useful to center calendar
vertically when operators are careless about aligning paper)
I wrote this in GE Time-Sharing FORTRAN when I was a teenager and have
continued to tweak it through the years; for many years I used it as
my first post-"Hello, world!" program when learning new languages, and
now use it to test the compilers I write.
Have fun...
--
Andrew W. Rogers {decvax,husc6,mit-eddie}!genrad!teddy!awr
awr@teddy.genrad.com
#! /bin/sh
# This file was wrapped with "dummyshar". "sh" this file to extract.
# Contents: calen.c
echo extracting 'calen.c'
if test -f 'calen.c' -a -z "$1"; then echo Not overwriting 'calen.c'; else
sed 's/^X//' << \EOF > 'calen.c'
X/*
X * Calendar program - one month per page
X *
X * Originally written in FORTRAN-IV for GE Timesharing, 10/65
X * Re-coded in C for UNIX, 3/83
X *
X * Author: AW Rogers
X *
X * Parameters:
X *
X * calen yy generates calendar for year yy
X *
X * calen mm yy [len] generates calendar for len months
X * (default = 1) starting with mm/yy
X *
X * Option flags (must precede params):
X *
X * -l left-justify dates (default)
X * -r right-justify dates
X * -m mixed-case output (default)
X * -u upper-case output
X * -o[seq] use "seq" as overstrike sequence
X * for heading (default: HIX)
X * -bN add N blank lines after form-feed
X *
X * Output is to standard output.
X *
X */
X
X#include <stdio.h>
X#include <ctype.h>
X
X#define FALSE 0
X#define TRUE 1
X
X#define JAN 1 /* significant months/years */
X#define FEB 2
X#define DEC 12
X#define MINYR 1753
X#define MAXYR 9999
X
X#define SOLID 0 /* pseudo-enumeration for line styles */
X#define OPEN 1
X
X#define LEFT 0 /* ... and justification of dates */
X#define RIGHT 1
X
X#define MIXED 0 /* ... and case of output text */
X
X#define UPPER 1
X
X#define OVERSTRIKE "HIX" /* overstrike sequence for month/year */
X#define MAX_OVERSTR 3 /* maximum overstrikes permitted */
X
X#define isLeap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0)) /* leap year macro */
X
Xtypedef struct /* info for a single month */
X {
X int mm;
X int yy;
X char mmname[10];
X char dates[6][7][3];
X } monthRec;
X
Xtypedef monthRec *mptr; /* pointer to above struct */
X
X/* globals corresponding to command-line flags */
X
Xint just = LEFT; /* default justification of dates */
Xint ocase = MIXED; /* default case for output */
Xint nblank = 0; /* default blank lines after FF */
Xchar *seq = OVERSTRIKE; /* default overstrike sequence */
X
X
X/*
X * Main - gets and validates parameters, opens output file, executes
X * loop to fill and print months of calendar, closes output file
X */
Xmain(argc, argv)
X int argc;
X char *argv[];
X {
X int nmonths; /* consecutive months to print */
X int badopt = FALSE; /* flag set if bad option */
X int badpar = FALSE; /* flag set if bad param */
X monthRec mRec[3]; /* space for main and small calendars */
X mptr prev = &mRec[0], /* pointers to calendars (initially) */
X curr = &mRec[1],
X next = &mRec[2],
X temp;
X
X /* Get command line flags */
X
X while (argc > 1 && argv[1][0] == '-')
X {
X switch (argv[1][1])
X {
X case 'b':
X sscanf(&argv[1][2], "%d", &nblank);
X break;
X case 'l':
X just = LEFT;
X break;
X case 'r':
X just = RIGHT;
X break;
X case 'm':
X ocase = MIXED;
X break;
X case 'u':
X ocase = UPPER;
X break;
X case 'o':
X if (argv[1][2] != '\0')
X seq = &argv[1][2];
X break;
X default:
X fprintf(stderr, "Invalid flag: %s\n", argv[1]);
X badopt = TRUE;
X break;
X }
X argv++;
X argc--;
X }
X
X if (badopt)
X fprintf(stderr, "Valid flags are -b -l -m -o -r -u\n");
X
X /* Get and validate parameters */
X
X if (argc == 2) /* only one arg - treat as yy */
X {
X sscanf(argv[1], "%d", &curr->yy);
X curr->mm = JAN;
X nmonths = 12;
X }
X
X else if (argc >= 3) /* two or more - treat as mm yy [len] */
X {
X sscanf(argv[1], "%d", &curr->mm);
X sscanf(argv[2], "%d", &curr->yy);
X if (argc >= 4)
X sscanf(argv[3], "%d", &nmonths);
X }
X
X else /* none specified - get interactively */
X {
X fprintf(stderr, "Enter calendar specs (month year length): ");
X scanf("%d %d %d", &curr->mm, &curr->yy, &nmonths);
X }
X
X if (curr->yy > 0 && curr->yy < 100) /* nn -> 19nn */
X curr->yy += 1900;
X
X if (nmonths < 1) /* default for month count */
X nmonths = 1;
X
X if (curr->mm < JAN || curr->mm > DEC) /* validate month/year */
X {
X fprintf(stderr, "Month %d not in range %d .. %d\n", curr->mm, JAN, DEC);
X badpar = TRUE;
X }
X
X if (curr->yy < MINYR || curr->yy > MAXYR)
X {
X fprintf(stderr, "Year %d not in range %d .. %d\n", curr->yy, MINYR,
X MAXYR);
X badpar = TRUE;
X }
X
X if (badpar) /* quit if month or year invalid */
X exit(1);
X
X /* fill in calendars for previous and current month */
X
X prev->mm = (curr->mm == JAN) ? DEC : curr->mm - 1;
X prev->yy = (curr->mm == JAN) ? curr->yy - 1 : curr->yy;
X fillCalendar(prev);
X
X fillCalendar(curr);
X
X /*
X * Main loop: print each month of the calendar (with small calendars for
X * the preceding and following months in the upper corners). The current
X * and next months' calendars can be reused the following month; only
X * the 'next' calendar need be recalculated each time.
X */
X
X for (; nmonths > 0 && curr->yy <= MAXYR; nmonths--) /* main loop */
X {
X next->mm = (curr->mm == DEC) ? JAN : curr->mm + 1;
X next->yy = (curr->mm == DEC) ? curr->yy + 1 : curr->yy;
X fillCalendar(next); /* fill in following month */
X
X printCalendar(prev, curr, next);
X
X temp = prev; /* swap the three months */
X prev = curr;
X curr = next;
X next = temp;
X }
X
X }
X
X/*
X * Print the calendar for the current month, generating small calendars
X * for the previous and following months in the upper corners and the
X * month/year (in large characters) centered at the top.
X */
XprintCalendar(prev, curr, next)
X mptr prev; /* Previous month (upper-left corner) */
X mptr curr; /* Current month (main calendar) */
X mptr next; /* Next month (upper-right corner) */
X {
X int nchars, i, j;
X static char *mc_wkday[] =
X {
X " Sunday ", " Monday ", " Tuesday ", "Wednesday", "Thursday ",
X " Friday ", "Saturday "
X };
X static char *uc_wkday[] =
X {
X " SUNDAY ", " MONDAY ", " TUESDAY ", "WEDNESDAY", "THURSDAY ",
X " FRIDAY ", "SATURDAY "
X };
X
X char **wkday; /* pointer to one of above */
X char *blanks = " "; /* 21 blanks for centering */
X char *padding; /* Pointer into 'blanks' */
X char monthAndYear[20]; /* Work area */
X char *ovr; /* overstrike sequence */
X
X nchars = strlen(curr->mmname); /* set up month/year heading */
X padding = blanks + (3 * (nchars - 3)); /* and center it */
X sprintf(monthAndYear, "%s%5d", curr->mmname, curr->yy);
X
X printf("\f\n"); /* print month/year in large chars */
X for (i = 0; i < nblank; i++)
X printf("\n");
X
X for (i = 0; i < 9; i++) /* surrounded by small calendars */
X {
X for (ovr = seq; /* overstruck lines first */
X ovr < seq + MAX_OVERSTR - 1 && *(ovr+1);
X ovr++)
X {
X printf("%20s%s", " ", padding);
X printHdr(monthAndYear, i, *ovr);
X printf("\r");
X }
X printSmallCal(prev, i); /* then small calendars, etc. */
X printf("%s", padding);
X printHdr(monthAndYear, i, *ovr);
X printf(" %s", padding);
X printSmallCal(next, i);
X printf("\n");
X }
X
X printf("\n"); /* print the weekday names */
X print_line(1, SOLID);
X print_line(1, OPEN);
X printf(" ");
X wkday = ocase == UPPER ? uc_wkday : mc_wkday;
X for (j = 0; j < 7; j++)
X printf("|%13.9s ", wkday[j]);
X printf("|\n");
X print_line(1, OPEN);
X
X for (i = 0; i < 4; i++) /* print first four rows */
X {
X print_line(1, SOLID);
X print_dates(curr, i, just);
X print_line(7, OPEN);
X }
X
X print_line(1, SOLID); /* print bottom row */
X print_dates(curr, 4, just);
X print_line(2, OPEN);
X print_divider(curr->dates[5]); /* divider for 23/30, 24/31 */
X
X print_line(3, OPEN);
X print_dates(curr, 5, !just); /* print 6th line (30/31) at bottom */
X print_line(1, SOLID);
X }
X
X/*
X * Fill in the month name and date fields of a specified calendar record
X * (assumes mm, yy fields already filled in)
X */
XfillCalendar(month)
X mptr month; /* Pointer to month info record */
X {
X typedef struct /* Local info about months */
X {
X char *name[2]; /* Name of month (mixed/upper-case) */
X int offset[2]; /* Offset of m/1 from 1/1 (non-leap/leap) */
X int length[2]; /* Length (non-leap/leap) */
X } monthInfo;
X
X static monthInfo info[12] = {
X { {"January", "JANUARY"}, {0, 0}, {31, 31} },
X { {"February", "FEBRUARY"}, {3, 3}, {28, 29} },
X { {"March", "MARCH"}, {3, 4}, {31, 31} },
X { {"April", "APRIL"}, {6, 0}, {30, 30} },
X { {"May", "MAY"}, {1, 2}, {31, 31} },
X { {"June", "JUNE"}, {4, 5}, {30, 30} },
X { {"July", "JULY"}, {6, 0}, {31, 31} },
X { {"August", "AUGUST"}, {2, 3}, {31, 31} },
X { {"September", "SEPTEMBER"}, {5, 6}, {30, 30} },
X { {"October", "OCTOBER"}, {0, 1}, {31, 31} },
X { {"November", "NOVEMBER"}, {3, 4}, {30, 30} },
X { {"December", "DECEMBER"}, {5, 6}, {31, 31} }
X };
X
X int i, first, last, date = 0, y = month->yy, m = month->mm-1;
X int leap = isLeap(y);
X
X first = (y + (y-1)/4 - (y-1)/100 + (y-1)/400 + info[m].offset[leap]) % 7;
X last = first + info[m].length[leap] - 1;
X
X for (i = 0; i < 42; i++) /* fill in the dates */
X if (i < first || i > last)
X strcpy(month->dates[i/7][i%7], " ");
X else
X sprintf(month->dates[i/7][i%7], "%2d", ++date);
X
X strcpy(month->mmname, info[m].name[ocase]); /* copy name of month */
X }
X
X/*
X * Print one line of a small calendar (previous and next months in
X * upper left and right corners of output)
X */
XprintSmallCal(month, line)
X mptr month; /* Month info record pointer */
X int line; /* Line to print (see below) */
X {
X int i;
X
X switch (line)
X {
X case 0: /* month/year at top */
X printf(" %-10s%4d ", month->mmname, month->yy);
X break;
X case 1: /* blank line */
X printf("%20s", " ");
X break;
X case 2: /* weekdays */
X printf(ocase == UPPER ? "SU MO TU WE TH FR SA" :
X "Su Mo Tu We Th Fr Sa");
X break;
X default: /* line of calendar */
X for (i = 0; i <= 5; i++)
X printf("%s ", month->dates[line-3][i]);
X printf("%s", month->dates[line-3][6]);
X break;
X }
X }
X
X/*
X * Print n lines in selected style
X */
Xprint_line(n, style)
X int n; /* Number of lines to print (> 0) */
X int style; /* SOLID or OPEN */
X {
X int i;
X char *fmt1 = (style == SOLID) ? "+-----------------" :
X "| " ;
X char *fmt2 = (style == SOLID) ? "+\n" : "|\n" ;
X
X for (; n > 0; n--)
X {
X printf(" ");
X for (i = 0; i < 7; i++)
X printf(fmt1);
X printf(fmt2);
X }
X }
X
X
X
X/*
X * Print line of large calendar (open w/left- or right-justified dates)
X */
Xprint_dates(month, line, just)
X mptr month; /* Month info record pointer */
X int line; /* Line to print (0-5) */
X int just; /* justification (LEFT / RIGHT) */
X {
X int i;
X char *fmt = (just == LEFT) ? "| %-16s" : "|%16s " ;
X
X printf(" ");
X for (i = 0; i < 7; i++)
X printf(fmt, month->dates[line][i]);
X printf("|\n");
X }
X
X/*
X * Print divider between 23/30 and 24/31
X */
Xprint_divider(dates)
X char dates[7][3];
X {
X int j;
X
X printf(" ");
X for (j = 0; j < 7; j++)
X if (strcmp(dates[j], " ") == 0)
X printf("| ");
X else
X printf("|_________________");
X printf("|\n");
X }
X
X
X/*
X * Print LS 6 bits of n (0 = ' '; 1 = selected non-blank)
X */
Xdecode(n, c)
X int n; /* Number to print (0-31) */
X char c;
X {
X int msk = 1 << 5;
X
X for (; msk; msk /= 2)
X printf("%c", (n & msk) ? c : ' ');
X }
X
X
X/*
X * Print one line of string in large characters
X */
XprintHdr(str, line, c)
X char *str; /* string to print */
X int line; /* line to print (0-8; else blanks) */
X char c; /* output character to use */
X {
X
X /* 5x9 dot-matrix representations of A-Z, a-z, 0-9 */
X
X static char uppers[26][9] =
X {
X {14, 17, 17, 31, 17, 17, 17, 0, 0}, {30, 17, 17, 30, 17, 17, 30, 0, 0}, /* AB */
X {14, 17, 16, 16, 16, 17, 14, 0, 0}, {30, 17, 17, 17, 17, 17, 30, 0, 0}, /* CD */
X {31, 16, 16, 30, 16, 16, 31, 0, 0}, {31, 16, 16, 30, 16, 16, 16, 0, 0}, /* EF */
X {14, 17, 16, 23, 17, 17, 14, 0, 0}, {17, 17, 17, 31, 17, 17, 17, 0, 0}, /* GH */
X {31, 4, 4, 4, 4, 4, 31, 0, 0}, { 1, 1, 1, 1, 1, 17, 14, 0, 0}, /* IJ */
X {17, 18, 20, 24, 20, 18, 17, 0, 0}, {16, 16, 16, 16, 16, 16, 31, 0, 0}, /* KL */
X {17, 27, 21, 21, 17, 17, 17, 0, 0}, {17, 17, 25, 21, 19, 17, 17, 0, 0}, /* MN */
X {14, 17, 17, 17, 17, 17, 14, 0, 0}, {30, 17, 17, 30, 16, 16, 16, 0, 0}, /* OP */
X {14, 17, 17, 17, 21, 18, 13, 0, 0}, {30, 17, 17, 30, 20, 18, 17, 0, 0}, /* QR */
X {14, 17, 16, 14, 1, 17, 14, 0, 0}, {31, 4, 4, 4, 4, 4, 4, 0, 0}, /* ST */
X {17, 17, 17, 17, 17, 17, 14, 0, 0}, {17, 17, 17, 17, 17, 10, 4, 0, 0}, /* UV */
X {17, 17, 17, 21, 21, 21, 10, 0, 0}, {17, 17, 10, 4, 10, 17, 17, 0, 0}, /* WX */
X {17, 17, 17, 14, 4, 4, 4, 0, 0}, {31, 1, 2, 4, 8, 16, 31, 0, 0} /* YZ */
X };
X
X static char lowers[26][9] =
X {
X { 0, 0, 14, 1, 15, 17, 15, 0, 0}, {16, 16, 30, 17, 17, 17, 30, 0, 0}, /* ab */
X { 0, 0, 15, 16, 16, 16, 15, 0, 0}, { 1, 1, 15, 17, 17, 17, 15, 0, 0}, /* cd */
X { 0, 0, 14, 17, 31, 16, 14, 0, 0}, { 6, 9, 28, 8, 8, 8, 8, 0, 0}, /* ef */
X { 0, 0, 14, 17, 17, 17, 15, 1, 14}, {16, 16, 30, 17, 17, 17, 17, 0, 0}, /* gh */
X { 4, 0, 12, 4, 4, 4, 31, 0, 0}, { 1, 0, 3, 1, 1, 1, 1, 17, 14}, /* ij */
X {16, 16, 17, 18, 28, 18, 17, 0, 0}, {12, 4, 4, 4, 4, 4, 31, 0, 0}, /* kl */
X { 0, 0, 30, 21, 21, 21, 21, 0, 0}, { 0, 0, 30, 17, 17, 17, 17, 0, 0}, /* mn */
X { 0, 0, 14, 17, 17, 17, 14, 0, 0}, { 0, 0, 30, 17, 17, 17, 30, 16, 16}, /* op */
X { 0, 0, 15, 17, 17, 17, 15, 1, 1}, { 0, 0, 30, 17, 16, 16, 16, 0, 0}, /* qr */
X { 0, 0, 15, 16, 14, 1, 30, 0, 0}, { 8, 8, 30, 8, 8, 9, 6, 0, 0}, /* st */
X { 0, 0, 17, 17, 17, 17, 14, 0, 0}, { 0, 0, 17, 17, 17, 10, 4, 0, 0}, /* uv */
X { 0, 0, 17, 21, 21, 21, 10, 0, 0}, { 0, 0, 17, 10, 4, 10, 17, 0, 0}, /* wx */
X { 0, 0, 17, 17, 17, 17, 15, 1, 14}, { 0, 0, 31, 2, 4, 8, 31, 0, 0} /* yz */
X };
X
X static char digits[10][9] =
X {
X {14, 17, 17, 17, 17, 17, 14, 0, 0}, { 2, 6, 10, 2, 2, 2, 31, 0, 0}, /* 01 */
X {14, 17, 2, 4, 8, 16, 31, 0, 0}, {14, 17, 1, 14, 1, 17, 14, 0, 0}, /* 23 */
X { 2, 6, 10, 31, 2, 2, 2, 0, 0}, {31, 16, 16, 30, 1, 17, 14, 0, 0}, /* 45 */
X {14, 17, 16, 30, 17, 17, 14, 0, 0}, {31, 1, 2, 4, 8, 16, 16, 0, 0}, /* 67 */
X {14, 17, 17, 14, 17, 17, 14, 0, 0}, {14, 17, 17, 15, 1, 17, 14, 0, 0} /* 89 */
X };
X
X char ch;
X
X for ( ; *str; str++)
X {
X ch = (line >= 0 && line <= 8) ? *str : ' ';
X if (isupper(ch))
X decode(uppers[ch-'A'][line], c);
X else if (islower(ch))
X decode(lowers[ch-'a'][line], c);
X else if (isdigit(ch))
X decode(digits[ch-'0'][line], c);
X else
X decode(0, c);
X }
X }
EOF
chars=`wc -c < 'calen.c'`
if test $chars != 15111; then echo 'calen.c' is $chars characters, should be 15111 characters!; fi
fi
exit 0