home *** CD-ROM | disk | FTP | other *** search
- From: rogers@sud509.ed.ray.com (Andrew Rogers)
- Newsgroups: alt.sources
- Subject: Calendar program for non-PostScript sites
- Message-ID: <2587@sud509.ed.ray.com>
- Date: 27 Sep 90 18:25:00 GMT
-
-
- I've gotten a few requests for this from people who do not have PostScript at
- their sites and (consequently) can't use Pcal. This program generates a
- calendar which may be printed on any line printer using standard 132x66
- fan-fold paper. Unfortunately, it lacks Pcal's most important capability -
- to import text from a date file - but it's useful nonetheless. Have fun!
-
- Andrew
-
- -------------------------------- cut here --------------------------------
- /*
- * Calendar program - one month per page
- *
- * Author: AW Rogers
- *
- * Parameters:
- *
- * calen generate calendar for current month/year
- *
- * calen yy generate calendar for entire year yy
- *
- * calen mm yy generate calendar for month mm (1 = January),
- * year yy (19yy if yy < 100)
- *
- * calen mm yy n as above, for n consecutive months
- *
- * Options:
- *
- * -b<N> add N blank lines at top of each page
- *
- * -f<FILE> write output to file FILE (calen.lst if -f alone)
- *
- * -l left-justify dates within boxes (default)
- *
- * -r right-justify dates within boxes
- *
- * -o<STR> use characters in STR as overstrike sequence for
- * printing large month/year (default: HIX)
- *
- * -t print trailing dates (30, 31 in 23/30 and 24/31)
- * in vacant box on first line
- *
- * Output:
- *
- * Full-page calendar for each of the specified months; written to
- * stdout unless -f option used.
- *
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <time.h>
- #include <string.h>
-
- #define FALSE 0
- #define TRUE 1
-
- #define JAN 1 /* significant months/years */
- #define FEB 2
- #define DEC 12
- #define MINYR 1753
- #define MAXYR 9999
-
- #define SOLID 0 /* line styles (cf. box_line()) */
- #define OPEN 1
-
- #define LEFT 0 /* date justification within boxes */
- #define RIGHT 1
- #define DEFAULT_JUST LEFT
-
- #define TOP 0 /* trailing date position */
- #define BOTTOM 1
- #define DEFAULT_TRAIL BOTTOM
-
- #define TOP_ROW 0 /* top and bottom rows of calendar */
- #define BOTTOM_ROW 5
-
- #define OVERSTRIKE "HIX" /* overstrike sequence for heading */
- #define MAX_OVERSTR 3
-
- #define OUTFILE "calen.lst" /* default output file if -f option used */
-
- #define NUM_BLANKS 0 /* default blank lines after <FF> */
- #define NUM_MONTHS 1 /* default number of months */
-
- #define MAXARGS 3 /* maximum non-flag command-line args */
-
-
- #ifdef VMS
- #define EXIT_FAILURE 3
- #define END_PATH ']'
- #else
- #define EXIT_FAILURE 1
- #define END_PATH '/'
- #endif
-
- #define is_leap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
-
- typedef struct /* information about a single month */
- {
- int mm;
- int yy;
- char *mmname;
- char dates[6][7][3];
- } month_rec;
-
- typedef month_rec *p_month; /* pointer to above structure */
-
- /* globals for defaultable command-line parameters, and their defaults */
-
- int just = DEFAULT_JUST; /* justification of dates */
- int trail = DEFAULT_TRAIL; /* format for 23/30, 24/31 */
- int nblank = NUM_BLANKS; /* blank lines after <FF> */
- char *seq = OVERSTRIKE; /* overstrike sequence for heading */
- int nmonths = NUM_MONTHS; /* number of months to print */
-
- char *fname = ""; /* output file name */
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- month_rec mRec[3]; /* space for main and small calendars */
- p_month prev = mRec, curr = mRec+1, next = mRec+2, temp;
-
- /* Get and validate command-line parameters and flags */
-
- get_params(argc, argv, curr);
-
- /* Fill in calendars for previous and current month */
-
- prev->mm = curr->mm == JAN ? DEC : curr->mm - 1;
- prev->yy = curr->mm == JAN ? curr-> yy - 1 : curr->yy;
-
- fill_calendar(prev);
- fill_calendar(curr);
-
- /*
- * Main loop: print each month of the calendar (with small calendars for the
- * previous and next months in the upper corners). The current and next
- * months' calendars can be reused as the previous and current calendars for
- * the following month; only the 'next' calendar need be calculated each
- * time through the loop.
- */
-
- while (nmonths-- > 0 && curr->yy <= MAXYR)
- {
- next->mm = curr->mm == DEC ? JAN : curr->mm + 1;
- next->yy = curr->mm == DEC ? curr->yy + 1 : curr->yy;
- fill_calendar(next); /* fill in following month */
-
- print_calendar(prev, curr, next);
-
- temp = prev; /* swap pointers to months */
- prev = curr;
- curr = next;
- next = temp;
- }
-
- if (*fname) /* report output file name */
- fprintf(stderr, "Output is in file %s\n", fname);
- }
-
-
- /*
- * Get and validate command-line parameters and flags. If month/year not
- * specified on command line, generate calendar for current month/year.
- * Exit program if month or year out of range; forgive illegal flags.
- */
-
- get_params(argc, argv, curr)
- int argc; /* argument count, vector passed in from main() */
- char *argv[];
- p_month curr; /* current month record (fill in month/year) */
- {
- int badopt = FALSE; /* flag set if bad option */
- int badpar = FALSE; /* flag set if bad param */
- int nargs = 0; /* count of non-flag args */
- int numargs[MAXARGS]; /* non-flag (numeric) args */
- char *parg; /* generic argument ptr */
- long tmp; /* temp for system clock */
- struct tm *p_tm; /* ptr to date/time struct */
- char *progname, *p; /* program name (argv[0)) */
- extern int atoi();
-
- /* Isolate root program name (for use in error messages) */
-
- progname = **argv ? *argv : "calen";
- if ((p = strrchr(progname, END_PATH)) != NULL)
- progname = ++p;
- if ((p = strchr(progname, '.')) != NULL)
- *p = '\0';
-
- /* Walk command-line argument list */
-
- while (--argc)
- {
- parg = *++argv;
- if (*parg == '-')
- {
- switch (*++parg)
- {
- case 'b':
- nblank = atoi(++parg);
- break;
- case 'f':
- fname = *++parg ? parg : OUTFILE;
- if (freopen(fname, "w", stdout) == (FILE *) NULL)
- {
- fprintf(stderr, "%s: error opening output file %s\n",
- progname, fname);
- exit (EXIT_FAILURE);
- }
- break;
- case 'l':
- just = LEFT;
- break;
- case 'r':
- just = RIGHT;
- break;
- case 'o':
- if (*++parg)
- seq = parg;
- break;
- case 't':
- trail = TOP;
- break;
- default:
- fprintf(stderr, "%s: invalid flag: %s\n", progname, *argv);
- badopt = TRUE;
- break;
- }
- }
- else /* non-flag argument - add to list */
- {
- if (nargs < MAXARGS)
- numargs[nargs++] = atoi(parg);
- }
- }
-
- /* Get and validate non-flag (numeric) parameters */
-
- switch (nargs)
- {
-
- case 0: /* no arguments - print current month/year */
- time(&tmp);
- p_tm = localtime(&tmp);
- curr->mm = p_tm->tm_mon + 1;
- curr->yy = p_tm->tm_year;
- break;
-
- case 1: /* one argument - print entire year */
- curr->mm = JAN;
- curr->yy = numargs[0];
- nmonths = 12;
- break;
-
- default: /* two or three arguments - print one or more months */
- curr->mm = numargs[0];
- curr->yy = numargs[1];
- nmonths = nargs > 2 ? numargs[2] : NUM_MONTHS;
- break;
- }
-
- if (curr->yy > 0 && curr->yy < 100) /* treat nn as 19nn */
- curr->yy += 1900;
-
- if (nmonths < 1) /* ensure at least one month */
- nmonths = 1;
-
- if (curr->mm < JAN || curr->mm > DEC) /* check range of month and year */
- {
- fprintf(stderr, "%s: month %d not in range %d .. %d\n", progname,
- curr->mm, JAN, DEC);
- badpar = TRUE;
- }
-
- if (curr->yy < MINYR || curr->yy > MAXYR)
- {
- fprintf(stderr, "%s: year %d not in range %d .. %d\n", progname,
- curr->yy, MINYR, MAXYR);
- badpar = TRUE;
- }
-
- if (badpar || badopt)
- usage(progname);
-
- if (badpar)
- exit(EXIT_FAILURE);
- }
-
- /*
- * Print message explaining correct usage of the command-line
- * arguments and flags
- */
-
- usage(prog)
- char *prog;
- {
- fprintf(stderr, "\nUsage:\n\n");
- fprintf(stderr, "\t%s [-bN] [-fFILE] [-l | -r] [-oSTR] [-t]\n", prog);
- fprintf(stderr, "\t\t[ [ [mm] yy ] | [mm yy n] ]\n\n");
- fprintf(stderr, "\nValid flags are:\n\n");
- fprintf(stderr, "\t-bN\t\tadd N blank lines after each <FF> (default: %d)\n\n",
- NUM_BLANKS);
- fprintf(stderr, "\t-fFILE\t\twrite output to file FILE (%s if -f alone)\n\n",
- OUTFILE);
- fprintf(stderr, "\t-l\t\tleft-justify dates within boxes");
- fprintf(stderr, "%s\n\n", DEFAULT_JUST == LEFT ? " (default)" : "");
- fprintf(stderr, "\t-r\t\tright-justify dates within boxes");
- fprintf(stderr, "%s\n\n", DEFAULT_JUST == RIGHT ? " (default)" : "");
- fprintf(stderr, "\t-oSTR\t\tuse characters in STR as overstrike sequence for\n");
- fprintf(stderr, "\t\t\tprinting large month/year (default: %s)\n\n",
- OVERSTRIKE);
- fprintf(stderr, "\t-t\t\tmove trailing 30 and 31 to vacant box on top line\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "\t%s [opts]\t\tgenerate calendar for current month/year\n",
- prog);
- fprintf(stderr, "\n");
- fprintf(stderr, "\t%s [opts] yy\t\tgenerate calendar for entire year yy\n",
- prog);
- fprintf(stderr, "\n");
- fprintf(stderr, "\t%s [opts] mm yy\tgenerate calendar for month mm\n", prog);
- fprintf(stderr, "\t\t\t\t(Jan = 1), year yy (19yy if yy < 100)\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "\t%s [opts] mm yy n\tas above, for n consecutive months\n",
- prog);
- fprintf(stderr, "\n");
- }
-
-
- /*
- * Print the calendar for the current month, generating small calendars
- * for the previous and following months in the upper corners and the
- * month/year (in 5x9 dot-matrix characters) centered at the top.
- */
-
- print_calendar(prev, curr, next)
- p_month prev; /* previous month (upper-left corner) */
- p_month curr; /* current month (main calendar) */
- p_month next; /* following month (upper-right corner) */
- {
- static char *wkday[] =
- {
- " Sunday ", " Monday ", " Tuesday ", "Wednesday", "Thursday",
- " Friday ", "Saturday "
- };
-
- int nchars, line, week, day;
- char *blanks = " "; /* 21 blanks for centering */
- char *padding; /* pointer into 'blanks' */
- char month_and_year[20]; /* work area */
- char *ovr; /* overstrike sequence */
-
- /* Set up month and year heading and appropriate padding to center it */
-
- nchars = strlen(curr->mmname);
- padding = blanks + (3 * (nchars - 3));
- sprintf(month_and_year, "%s%5d", curr->mmname, curr->yy);
-
- /* Print top-of-form and leading blank lines, if any */
-
- printf("\f\n");
- for (line = 0; line < nblank; line++)
- printf("\n");
-
- /* Print month and year in large letters, with small calendars on each side */
-
- for (line = 0; line < 9; line++)
- {
- for (ovr = seq; ovr < seq + MAX_OVERSTR - 1 && *(ovr+1); ovr++)
- {
- printf("%20s%s", " ", padding); /* overstruck lines first */
- header_line(month_and_year, line, *ovr);
- printf(" %s", padding);
- printf("\r");
- }
- small_cal_line(prev, line); /* calendars and non-overstruck line */
- printf("%s", padding);
- header_line(month_and_year, line, *ovr);
- printf(" %s", padding);
- small_cal_line(next, line);
- printf("\n");
- }
-
- printf("\n"); /* print the weekday names */
- box_line(1, SOLID);
- box_line(1, OPEN);
- printf(" ");
- for (day = 0; day < 7; day++)
- printf("|%13.9s ", wkday[day]);
- printf("|\n");
- box_line(1, OPEN);
-
- for (week = TOP_ROW; week < BOTTOM_ROW - 1; week++) /* first four weeks */
- {
- box_line(1, SOLID);
- date_line(curr, week, just);
- box_line(7, OPEN);
- }
-
- box_line(1, SOLID); /* fifth week */
- date_line(curr, BOTTOM_ROW - 1, just);
- box_line(2, OPEN);
-
- divider_line(curr->dates[BOTTOM_ROW]); /* divider for 23/30 and/or 24/31 */
- box_line(3, OPEN);
-
- date_line(curr, BOTTOM_ROW, !just); /* sixth week (trailing 31 or 30 31) */
- box_line(1, SOLID);
-
- }
-
-
-
- /*
- * Fill in the month name and date fields of a calendar record according
- * to its month and year fields.
- */
-
- fill_calendar(month)
- p_month month; /* record to be filled in */
- {
- typedef struct /* local info about months of year */
- {
- char *name; /* month name */
- int offset[2]; /* offset of m/1 from 1/1 (non-leap, leap) */
- int length[2]; /* length of month (non-leap, leap) */
- } month_info;
-
- static month_info info[12] = {
- { "January", {0, 0}, {31, 31} }, { "February", {3, 3}, {28, 29} },
- { "March", {3, 4}, {31, 31} }, { "April", {6, 0}, {30, 30} },
- { "May", {1, 2}, {31, 31} }, { "June", {4, 5}, {30, 30} },
- { "July", {6, 0}, {31, 31} }, { "August", {2, 3}, {31, 31} },
- { "September", {5, 6}, {30, 30} }, { "October", {0, 1}, {31, 31} },
- { "November", {3, 4}, {30, 30} }, { "December", {5, 6}, {31, 31} }
- } ;
-
- int i, first, last, date = 0, y = month->yy, m = month->mm - 1;
- int leap = is_leap(y);
-
- /* Determine when month starts and ends */
-
- first = (y + (y-1)/4 - (y-1)/100 + (y-1)/400 + info[m].offset[leap]) % 7;
- last = first + info[m].length[leap] - 1;
-
- for (i = 0; i < 42; i++) /* fill in 7x6 matrix of dates */
- if (i < first || i > last)
- month->dates[i/7][i%7][0] = '\0';
- else
- sprintf(month->dates[i/7][i%7], "%2d", ++date);
-
- if (trail == TOP) /* move trailing 30/31 to top row if requested */
- for (i = 0; month->dates[BOTTOM_ROW][i][0]; i++)
- {
- strcpy(month->dates[TOP_ROW][i], month->dates[BOTTOM_ROW][i]);
- month->dates[BOTTOM_ROW][i][0] = '\0';
- }
-
- month->mmname = info[m].name; /* fill in month name */
- }
-
-
- /*
- * Print one line of a small calendar (for upper left and right corners);
- * always prints exactly 20 characters.
- */
-
- small_cal_line(month, line)
- p_month month; /* information for month to print */
- int line; /* line to print (0-8; see below) */
- {
- int day;
- char tmp1[10], tmp2[30];
-
- switch (line)
- {
- case 0: /* month and year (centered) */
- strcpy(tmp1, " ");
- tmp1[(15 - strlen(month->mmname)) / 2] = '\0';
- sprintf(tmp2, "%s%s %4d ", tmp1, month->mmname, month->yy);
- printf("%-20.20s", tmp2);
- break;
- case 1: /* blank line */
- printf("%20s", " ");
- break;
- case 2: /* weekdays */
- printf("Su Mo Tu We Th Fr Sa");
- break;
- default: /* line of calendar (3 = first) */
- for (day = 0; day < 6; day++)
- printf("%2s ", month->dates[line-3][day]);
- printf("%2s", month->dates[line-3][day]);
- break;
- }
- }
-
-
- /*
- * Print n calendar box lines in selected style
- */
-
- box_line(n, style)
- int n; /* number of lines to print */
- int style; /* SOLID or OPEN */
- {
- int day;
- char *fmt = style == SOLID ? "+-----------------" :
- "| " ;
-
- for (; n > 0; n--)
- {
- printf(" ");
- for (day = 0; day < 7; day++)
- printf(fmt);
- printf("%c\n", *fmt);
- }
- }
-
-
- /*
- * Print one week of dates, left- or right-justified
- */
-
- date_line(month, week, just)
- p_month month; /* pointer to month data */
- int week; /* week to print (0 = first) */
- int just; /* justification (LEFT or RIGHT) */
- {
- int day;
- char *fmt = just == LEFT ? "| %-16s" : "|%16s " ;
-
- printf(" ");
- for (day = 0; day < 7; day++)
- printf(fmt, month->dates[week][day]);
- printf("|\n");
- }
-
-
- /*
- * Print the divider separating 23/30 and/or 24/31 as needed
- */
-
- divider_line(last_row)
- char last_row[7][3]; /* row containing any trailing 30 and/or 31 */
- {
- int day;
-
- printf(" ");
- for (day = 0; day < 7; day++)
- printf(last_row[day][0] ? "|_________________" : "| ");
- printf("|\n");
- }
-
-
- /*
- * Print least-significant 6 bits of n (0 = ' '; 1 = other char)
- */
-
- decode(n, c)
- int n; /* number to decode (row of 5x9 character) */
- char c; /* character to print for each 1 bit */
- {
- int msk = 1 << 5;
-
- for (; msk; msk >>= 1)
- printf("%c", n & msk ? c : ' ');
- }
-
-
- /*
- * Print one line of string in large (5x9) characters
- */
-
- header_line(str, line, c)
- char *str; /* string to print */
- int line; /* line (0 - 8) */
- char c; /* output character */
- {
-
- /* 5x7 representations of A-Z, 0-9; 5x9 representation of a-z */
-
- static char uppers[26][7] = {
- {14, 17, 17, 31, 17, 17, 17}, {30, 17, 17, 30, 17, 17, 30}, /* AB */
- {14, 17, 16, 16, 16, 17, 14}, {30, 17, 17, 17, 17, 17, 30}, /* CD */
- {31, 16, 16, 30, 16, 16, 31}, {31, 16, 16, 30, 16, 16, 16}, /* EF */
- {14, 17, 16, 23, 17, 17, 14}, {17, 17, 17, 31, 17, 17, 17}, /* GH */
- {31, 4, 4, 4, 4, 4, 31}, { 1, 1, 1, 1, 1, 17, 14}, /* IJ */
- {17, 18, 20, 24, 20, 18, 17}, {16, 16, 16, 16, 16, 16, 31}, /* KL */
- {17, 27, 21, 21, 17, 17, 17}, {17, 17, 25, 21, 19, 17, 17}, /* MN */
- {14, 17, 17, 17, 17, 17, 14}, {30, 17, 17, 30, 16, 16, 16}, /* OP */
- {14, 17, 17, 17, 21, 18, 13}, {30, 17, 17, 30, 20, 18, 17}, /* QR */
- {14, 17, 16, 14, 1, 17, 14}, {31, 4, 4, 4, 4, 4, 4}, /* ST */
- {17, 17, 17, 17, 17, 17, 14}, {17, 17, 17, 17, 17, 10, 4}, /* UV */
- {17, 17, 17, 21, 21, 21, 10}, {17, 17, 10, 4, 10, 17, 17}, /* WX */
- {17, 17, 17, 14, 4, 4, 4}, {31, 1, 2, 4, 8, 16, 31} /* YZ */
- };
-
- static char lowers[26][9] = {
- { 0, 0, 14, 1, 15, 17, 15, 0, 0}, {16, 16, 30, 17, 17, 17, 30, 0, 0}, /* ab */
- { 0, 0, 15, 16, 16, 16, 15, 0, 0}, { 1, 1, 15, 17, 17, 17, 15, 0, 0}, /* cd */
- { 0, 0, 14, 17, 31, 16, 14, 0, 0}, { 6, 9, 28, 8, 8, 8, 8, 0, 0}, /* ef */
- { 0, 0, 14, 17, 17, 17, 15, 1, 14}, {16, 16, 30, 17, 17, 17, 17, 0, 0}, /* gh */
- { 4, 0, 12, 4, 4, 4, 31, 0, 0}, { 1, 0, 3, 1, 1, 1, 1, 17, 14}, /* ij */
- {16, 16, 17, 18, 28, 18, 17, 0, 0}, {12, 4, 4, 4, 4, 4, 31, 0, 0}, /* kl */
- { 0, 0, 30, 21, 21, 21, 21, 0, 0}, { 0, 0, 30, 17, 17, 17, 17, 0, 0}, /* mn */
- { 0, 0, 14, 17, 17, 17, 14, 0, 0}, { 0, 0, 30, 17, 17, 17, 30, 16, 16}, /* op */
- { 0, 0, 15, 17, 17, 17, 15, 1, 1}, { 0, 0, 30, 17, 16, 16, 16, 0, 0}, /* qr */
- { 0, 0, 15, 16, 14, 1, 30, 0, 0}, { 8, 8, 30, 8, 8, 9, 6, 0, 0}, /* st */
- { 0, 0, 17, 17, 17, 17, 15, 0, 0}, { 0, 0, 17, 17, 17, 10, 4, 0, 0}, /* uv */
- { 0, 0, 17, 21, 21, 21, 10, 0, 0}, { 0, 0, 17, 10, 4, 10, 17, 0, 0}, /* wx */
- { 0, 0, 17, 17, 17, 17, 15, 1, 14}, { 0, 0, 31, 2, 4, 8, 31, 0, 0}, /* yz */
- };
-
- static char digits[10][7] = {
- {14, 17, 17, 17, 17, 17, 14}, { 2, 6, 10, 2, 2, 2, 31}, /* 01 */
- {14, 17, 2, 4, 8, 16, 31}, {14, 17, 1, 14, 1, 17, 14}, /* 23 */
- { 2, 6, 10, 31, 2, 2, 2}, {31, 16, 16, 30, 1, 17, 14}, /* 45 */
- {14, 17, 16, 30, 17, 17, 14}, {31, 1, 2, 4, 8, 16, 16}, /* 67 */
- {14, 17, 17, 14, 17, 17, 14}, {14, 17, 17, 15, 1, 17, 14} /* 89 */
- };
-
- char ch;
-
- /* convert each character of str to dot-matrix representation for line */
-
- for ( ; ch = *str; str++)
- {
- if (isupper(ch))
- decode(line < 7 ? uppers[ch-'A'][line] : 0, c);
- else if (islower(ch))
- decode(lowers[ch-'a'][line], c);
- else if (isdigit(ch))
- decode(line < 7 ? digits[ch-'0'][line] : 0, c);
- else
- decode(0, c);
- }
-
- }
-