home *** CD-ROM | disk | FTP | other *** search
- From decwrl!ucbvax!tut.cis.ohio-state.edu!unmvax!pprg.unm.edu!hc!lll-winken!uunet!allbery Sat Mar 25 19:44:44 PST 1989
- Article 850 of comp.sources.misc:
- Path: decwrl!ucbvax!tut.cis.ohio-state.edu!unmvax!pprg.unm.edu!hc!lll-winken!uunet!allbery
- From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
- Newsgroups: comp.sources.misc
- Subject: v06i081: another calendar program
- Summary: new, improved
- Message-ID: <51486@uunet.UU.NET>
- Date: 25 Mar 89 17:08:38 GMT
- Sender: allbery@uunet.UU.NET
- Reply-To: awr@genrad.genrad.COM (Andrew W. Rogers)
- Lines: 539
- Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- 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
-
-
-