[comp.sources.misc] v06i074: calendar program, 1 month per page

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (03/22/89)

Posting-number: Volume 6, Issue 74
Submitted-by: THE MASTER <evh@vax1.acs.udel.edu>
Archive-name: pcal

#! /bin/sh
# To extract, remove mail header lines and type "sh filename"
echo x - README
sed -e 's/^X//' > README << '!FaR!OuT!'
XTo compile:
X-----------
X
X  cc -o pcal pcal.c
X
X
X
X
X
XInfo on usage etc:
X------------------
X
XI wrote this because I was interested in writing a routine to figure
Xout the day of the week for a specific date(as it ended up, I couldn't
Xget my hands on any algorithm so I got ripped some code from some one's
Xprogram in the archives). Any how I ended up writing this calendar program.
X
X
XI call this program 'pcal' because it it prints out one month per page.
XEach month is separated by control-L type form feed character.
XFor testing, I picked random years and verified them.
XEach month is made up of a grid of 7(width) by 5(height) squares. Any
Xmonth that requires over 5 squares high wil have the the appropriate
Xdays split in half.
X
X
XA typical month looks like.
X
X
X                                      1989
X
X                                     April
X
X    |   SUN   |   MON   |   TUE   |   WED   |   THU   |   FRI   |   SAT   |
X    -----------------------------------------------------------------------
X    |         |         |         |         |         |         | 1|      |
X    |         |         |         |         |         |         |---      |
X    |         |         |         |         |         |         |         |
X    |         |         |         |         |         |         |         |
X    |         |         |         |         |         |         |         |
X    -----------------------------------------------------------------------
X    | 2|      | 3|      | 4|      | 5|      | 6|      | 7|      | 8|      |
X    |---      |---      |---      |---      |---      |---      |---      |
X    |         |         |         |         |         |         |         |
X    |         |         |         |         |         |         |         |
X    |         |         |         |         |         |         |         |
X    -----------------------------------------------------------------------
X    | 9|      |10|      |11|      |12|      |13|      |14|      |15|      |
X    |---      |---      |---      |---      |---      |---      |---      |
X    |         |         |         |         |         |         |         |
X    |         |         |         |         |         |         |         |
X    |         |         |         |         |         |         |         |
X    -----------------------------------------------------------------------
X    |16|      |17|      |18|      |19|      |20|      |21|      |22|      |
X    |---      |---      |---      |---      |---      |---      |---      |
X    |         |         |         |         |         |         |         |
X    |         |         |         |         |         |         |         |
X    |         |         |         |         |         |         |         |
X    -----------------------------------------------------------------------
X    |23|    _/|24|      |25|      |26|      |27|      |28|      |29|      |
X    |---  _/  |---      |---      |---      |---      |---      |---      |
X    |   _/    |         |         |         |         |         |         |
X    | _/   ---|         |         |         |         |         |         |
X    |/     |30|         |         |         |         |         |         |
X    -----------------------------------------------------------------------
X       
X
X
X
XUsage: pcal [-l] [-m startmonth]
X            [-n nummonths] [-u] [-y startyear]
X       startmonth:day of month to start on(1=jan...12=dec)
X       startyear :year to start on(1989=1989, 89=0089)
X                  default startday=1, startmonth=1,
X                  startyear=current year
X       nummonths :#of months to print out(default is 12)
X       -l        :suppress printing of ^L's after each month
X                  default is to print them
X       -u        :print this synopsis
X
X
X
XExamples:
X   Say todays date is March 17, 1989.
X
X
X   pcal   -> print out a 12 month calendar for the year 1989.
X             Each month is printed on a separate page.
X
X   pcal -n 3     ->print out Jan,Feb,March of 1989, each on a separate
X                   page.
X
X   pcal -n 3 -l  ->print out Jan,Feb,March of 1989. Each month is printed
X                   one after another.
X
X   pcal -m 4 -n 1 -> prints out the month of April, 1989 and a form feed.
X
X   pcal -m 4 -y 1992 -n 24 ->prints out months from April, 1992 to 
X                             April, 1994. Each month separated by a control-L.
X
X
XFeel free to make any changes to the code, but leave my name at the top
Xof the code file(s).
X
!FaR!OuT!
echo x - pcal.c
sed -e 's/^X//' > pcal.c << '!FaR!OuT!'
X/*pcal.c                                    Sun Feb 26 23:08:25 EST 1989*/
X
X
X
X/*
X *Contents: One page per month calendar program.
X *
X *Author  : Troy Saville(evh@vax1.acs.udel.edu)
X *
X *Compiling: cc -o pcal pcal.c
X *
X *byebye     - make a clean exit from the program
X *getmmddyy  - get month,day,year of todays date(from the system)
X *isleapyear - determine if year is a leap year
X *jan1       - get day of week for 1st day of a year
X *dayofweek  - get day of week for any day of any year
X *genweek    - driver to print out one week of a month
X *genmonth   - driver to print out a complete month
X *main       - the pcal program
X *
X */
X
X
X
X
X
X
X/*generate a calender, 1 month per page*/
X
X
X#include <stdio.h>
X#include <strings.h>
X#include <time.h>
X
X
X
X/*width of calendar, not including margin*/
X#define NUMWIDTH 71
X/*#of spaces to indent calendar*/
X#define NUMINDENT 4
X
X#define INDENT() printf("%-*.*s",NUMINDENT,NUMINDENT,spaces)
X
X/*check for split sqaure on calendar*/
X#define THESPLIT (weeknum == 5) && (endday < numdays) && (week[i]+7 <= numdays)
X
X
Xstatic char *spaces = "                                                   ";
Xstatic char *dashes = "-------------------------------------------------------------------------------";
X
Xstatic int daysinmonth[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
X
Xchar *monthnames[] = {"January", "February", "March", "April", "May", "June",
X                      "July", "August", "September", "October", "November",
X                      "December"};
X
Xchar *daynames[] = {"Sun" ,"Mon" ,"Tue" ,"Wed" ,"Thu" ,"Fri" ,"Sat" };
X
X
X/*day of week that first day starts on*/
X#define DAYSTART 0
X
X/*first month to print out*/
X#define MONSTART 0
X
X
X/*exit the program cleanly - display error message*/
Xvoid byebye(fmt,a1,a2,a3,a4,a5,a6,a7)
X   char *fmt;
X   int a1,a2,a3,a4,a5,a6,a7;
X   {
X   if (fmt != NULL)
X      {
X      char tmp[80];
X      sprintf(tmp,fmt,a1,a2,a3,a4,a5,a6,a7);
X      printf(tmp);
X      }
X  
X   printf("\n");
X   printf("Usage: pcal [-l] [-m startmonth]\n");
X   printf("            [-n nummonths] [-u] [-y startyear]\n");
X   printf("       startmonth:day of month to start on(1=jan...12=dec)\n");
X   printf("       startyear :year to start on(1989=1989, 89=0089)\n");
X   printf("                  default startday=1, startmonth=1,\n");
X   printf("                  startyear=current year\n");
X   printf("       nummonths :#of months to print out(default is 12)\n");
X   printf("       -l        :suppress printing of ^L's after each month\n");
X   printf("                  default is to print them\n");
X   printf("       -u        :print this synopsis\n");
X
X   exit(0);
X   }
X
X
X
X/*get month,day,year of today date, year=89(mean actual year is 1989*/
Xvoid getmmddyy(month,day,year)
X   int *month, *day, *year;
X   {
X   long clockval,time();
X   struct tm *dateinfo,*localtime();
X
X   clockval = time((long *) 0);
X
X   dateinfo = localtime(&clockval);
X   if (month)
X     *month = dateinfo->tm_mon+1;
X   if (day)
X      *day = dateinfo->tm_mday;
X   if (year)
X      *year = dateinfo->tm_year;
X   }
X
X
X
X
X/******************************************************************************
X *isleapyear                                     Tue Oct 25, 1988 -> 21:42:56
X *
X *returns 1 if 'year' is a leap year else returns 0.
X *1988 should be passed as 1988 and not 88.
X */
Xint isleapyear(year)
X   int year;
X   {
X   return((!(year % 4)) && (year % 100) ? 1 : 0);
X   }
X
X
X/*Return day of the week for Jan 1 of the specified year.*/
X/*0=sunday....6=saturday*/
X/*I ripped this out of someone elses program*/
X/*author unknown*/
Xint jan1(year)
X   int year;
X   {
X   int day;
X
X   day = year + 4 + ((year + 3) / 4);     /* Julian Calendar      */
X   if (year > 1800)                       /* If it's recent, do   */
X      {
X      day -= ((year - 1701) / 100);       /* Clavian correction   */
X      day += ((year - 1601) / 400);       /* Gregorian correction */
X      }
X    if (year > 1752)                      /* Adjust for Gregorian */
X      day += 3;                           /* calendar             */
X
X   return (day % 7);
X   }
X
X
X
X
X/*return day of the week for the date passed in*/
X/*month = 0-11, day is 1 based, year is assumed to be 4 digits*/
X/*RETURN:0= sunday.....6=saturday*/
Xint dayofweek(month,day,year)
X   int month,day,year;
X   {
X   int i;
X   int dow = (-1);
X
X   dow += day + jan1(year);
X
X   for(i=0;i < month;i++)
X      dow += daysinmonth[i] + ((i == 1) * isleapyear(year));
X
X   return(dow % 7);
X   }
X
X
X/************************************************************************
X *genweek                                    Mon Feb 27 00:46:16 EST 1989
X * - generate calander for 1 week
X */
Xvoid genweek(week,weeknum,startday,daysinweek,numdays)
X   int week[];     /*#of each day of week to be generated*/
X   int weeknum;    /*week # for current month*/
X   int startday;   /*starting day 
X   int daysinweek; /*last day to be generated*/
X   int numdays;    /*#days in month*/
X   {
X   int i;
X   int row;
X   int endday;
X
X   if (weeknum > 5)
X      return;
X
X   endday = startday + daysinweek - 1;
X
X
X   for(row=0;row < 5;row++)
X      {
X      INDENT();
X      printf("|");
X
X      for(i=0;i< 7;i++)
X         {
X         /*see if day of the week contains a day for this month*/
X         if (week[i])
X            switch(row)
X               {
X               case 0:
X                  printf("%2d|    %s",week[i],
X                         (THESPLIT) ? "_/" : "  ");
X                  break;
X
X               case 1:
X                  printf("---  %s  ",(THESPLIT) ? "_/" : "  ");
X                  break;
X
X               case 2:
X                  printf("   %s    ",(THESPLIT) ? "_/" : "  ");
X                  break;
X
X               case 3:
X                  printf(" %s",(THESPLIT) ? "_/   ---" : "        ");
X                  break;
X
X               case 4:
X                  if (THESPLIT)
X                     printf("/     |%2d",week[i]+7);
X                  else
X                     printf("         ");
X                  break;
X               }
X         else /*this day of the week is in last month or next month*/
X            printf("%-9.9s",spaces);
X         printf("|");
X         }
X
X      printf("\n");
X      }
X
X   INDENT();
X   printf("%-*.*s\n", NUMWIDTH, NUMWIDTH,dashes);
X   }
X
X
X
X/************************************************************************
X *genmonth                                   Sun Feb 26 23:21:30 EST 1989
X * - generate calander for 1 month
X */
Xvoid genmonth(month,year)
X   int month;
X   int year;
X   {
X   int i,j,k;
X   int startday; /*day of week 1st day starts on*/
X   int numdays;  /*#days in month*/
X   int dow;      /*dat of week*/
X   int weeknum = 1; /*# of the current week to print*/
X   int week[7];
X
X   i = (80 - strlen(monthnames[month])) / 2;
X
X   printf("%-*.*s%-s\n\n",i,i,spaces,monthnames[month]);
X
X   numdays = daysinmonth[month] + ((month==1) * isleapyear(year));
X
X   startday = dayofweek(month,1,year);
X
X   INDENT();
X   printf("|   SUN   |   MON   |   TUE   |   WED   |   THU   |   FRI   |   SAT   |\n");
X   INDENT();
X   printf("%-*.*s\n", NUMWIDTH, NUMWIDTH,dashes);
X
X   /*figure out first row*/
X   /*first row of calander*/
X   for(i=0,j=0;i < 7;i++)
X      if (i >= startday)
X         week[i] = ++j;
X      else
X         week[i] = 0;
X
X   /*generate row for one week of calendar*/
X   i = 7 - startday;
X   genweek(week,weeknum,1,i,numdays);
X
X   /*rest of calendar*/
X   for(k=0; i < numdays;i += k,k=0)
X      {
X      for(j=0;j < 7;j++)
X         if ((i+k) < numdays)
X            week[j] = ++k + i;
X         else
X            week[j] = 0;
X      if (k)
X         genweek(week,++weeknum,i+1,k,numdays);
X      }
X   }
X
X
X
X/**************************************************************************
X *main 
X * - main program
X *
X */
Xmain(argc,argv)
X   int argc;
X   char *argv[];
X   {
X   int i,j;
X   int curmonth = 1;   /*current month of year*/
X   int curyear;        /*current year*/
X   int numday;         /*#of the day of the week*/
X   int nummonths = 12; /*#of months to print out*/
X   int controll = 0;   /*suppress printing of control L's 0=no, 1=yes*/
X
X
X   /*set defaults*/
X   getmmddyy(0,0,&curyear);
X   curyear += 1900;
X
X   /*parse command line args*/
X   for(i=1;i<argc;i++)
X      {
X      if (argv[i][0] == '-')
X         switch(argv[i][1])
X            {
X            case 'm': /*day # of the week to start calander on*/
X               if (++i == argc)
X                  byebye("-m requires integer arguement");
X               else if ( (sscanf(argv[i],"%d", &curmonth) != 1) ||
X                         (curmonth < 1) || (curmonth > 12) )
X                  byebye("Bad arg '%s' for -m flag\n", argv[i]);
X               break;
X
X            case 'n': /*#of months to print*/
X               if (++i == argc)
X                  byebye("-n requires integer arguement");
X               else if ( (sscanf(argv[i],"%d", &nummonths) != 1) ||
X                         (nummonths < 1) )
X                  byebye("Bad arg '%s' for -n flag\n", argv[i]);
X               break;
X
X            case 'y': /*day # of the week to start calander on*/
X               if (++i == argc)
X                  byebye("-y requires integer arguement");
X               else if (sscanf(argv[i],"%d", &curyear) != 1)
X                  byebye("Bad arg '%s' for -y flag\n", argv[i]);
X               break;
X
X            case 'l': /*suppress ^L's*/
X               controll = 1;
X               break;
X
X            case 'u': /*usage*/
X               byebye(0);
X               break;
X
X            default: 
X               byebye("Bad command line arguement: %s",argv[i]);
X               break;
X            }
X      else
X         byebye("Bad command line arguement: %s",argv[i]);
X      }
X
X   curmonth--;
X
X
X   /*loop through months*/
X   for(;nummonths > 0;nummonths--, curmonth++)
X      {
X      if (curmonth == 12)
X         {
X         curmonth = 0;
X         curyear++;
X         }
X
X      printf("\n\n\n%-*.*s%-4d\n\n",38,38,spaces,curyear);
X
X      genmonth(curmonth,curyear);
X
X      if (!controll)
X         printf("       \n"); /*form feed to next page*/
X      }
X
X
X   }
X
X
X
X
X
X
X
!FaR!OuT!
exit