316 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			316 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* cal - print a calendar		Author: Maritn Minow */
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <stdio.h>
 | |
| 
 | |
| #define do3months	domonth
 | |
| #define	IO_SUCCESS	0	/* Unix definitions		 */
 | |
| #define	IO_ERROR	1
 | |
| #define	EOS	0
 | |
| 
 | |
| #define	ENTRY_SIZE	3	/* 3 bytes per value		 */
 | |
| #define DAYS_PER_WEEK	7	/* Sunday, etc.			 */
 | |
| #define	WEEKS_PER_MONTH	6	/* Max. weeks in a month	 */
 | |
| #define	MONTHS_PER_LINE	3	/* Three months across		 */
 | |
| #define	MONTH_SPACE	3	/* Between each month		 */
 | |
| 
 | |
| char *badarg = {"Bad argument\n"};
 | |
| char *how = {"Usage: cal [month] year\n"};
 | |
| 
 | |
| /* Calendar() stuffs data into layout[],
 | |
|  * output() copies from layout[] to outline[], (then trims blanks).
 | |
|  */
 | |
| char layout[MONTHS_PER_LINE][WEEKS_PER_MONTH][DAYS_PER_WEEK][ENTRY_SIZE];
 | |
| char outline[(MONTHS_PER_LINE * DAYS_PER_WEEK * ENTRY_SIZE)
 | |
|        + (MONTHS_PER_LINE * MONTH_SPACE)
 | |
|        + 1];
 | |
| 
 | |
| char *weekday = " S  M Tu  W Th  F  S";
 | |
| char *monthname[] = {
 | |
| 	     "???",		/* No month 0	 */
 | |
| 	     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
 | |
| 	     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
 | |
| };
 | |
| 
 | |
| _PROTOTYPE(int main, (int argc, char **argv));
 | |
| _PROTOTYPE(void doyear, (int year));
 | |
| _PROTOTYPE(void domonth, (int year, int month));
 | |
| _PROTOTYPE(void output, (int nmonths));
 | |
| _PROTOTYPE(void calendar, (int year, int month, int indx));
 | |
| _PROTOTYPE(void usage, (char *s));
 | |
| _PROTOTYPE(int date, (int year, int month, int week, int wday));
 | |
| _PROTOTYPE(void setmonth, (int year, int month));
 | |
| _PROTOTYPE(int getdate, (int week, int wday));
 | |
| _PROTOTYPE(static int Jan1, (int year));
 | |
| 
 | |
| int main(argc, argv)
 | |
| int argc;
 | |
| char *argv[];
 | |
| {
 | |
|   register int year;
 | |
| 
 | |
|   register int arg1val;
 | |
|   int arg1len;
 | |
|   int arg2val;
 | |
| 
 | |
|   if (argc <= 1) {
 | |
| 	usage(how);
 | |
|   } else {
 | |
| 	arg1val = atoi(argv[1]);
 | |
| 	arg1len = strlen(argv[1]);
 | |
| 	if (argc == 2) {
 | |
| 		/* Only one argument, if small, it's a month.  If
 | |
| 		 * large, it's a year.  Note: cal		0082	Year
 | |
| 		 * 0082 cal		82	Year 0082 */
 | |
| 		if (arg1len <= 2 && arg1val <= 12)
 | |
| 			do3months(year, arg1val);
 | |
| 		else
 | |
| 			doyear(arg1val);
 | |
| 	} else {
 | |
| 		/* Two arguments, allow 1980 12 or 12 1980 */
 | |
| 		arg2val = atoi(argv[2]);
 | |
| 		if (arg1len > 2)
 | |
| 			do3months(arg1val, arg2val);
 | |
| 		else
 | |
| 			do3months(arg2val, arg1val);
 | |
| 	}
 | |
|   }
 | |
|   return(IO_SUCCESS);
 | |
| }
 | |
| 
 | |
| void doyear(year)
 | |
| int year;
 | |
| /* Print the calendar for an entire year. */
 | |
| {
 | |
|   register int month;
 | |
| 
 | |
|   if (year < 1 || year > 9999) usage(badarg);
 | |
|   if (year < 100)
 | |
| 	printf("\n\n\n                                 00%2d\n\n", year);
 | |
|   else
 | |
| 	printf("\n\n\n%35d\n\n", year);
 | |
|   for (month = 1; month <= 12; month += MONTHS_PER_LINE) {
 | |
| 	printf("%12s%23s%23s\n",
 | |
| 	       monthname[month],
 | |
| 	       monthname[month + 1],
 | |
| 	       monthname[month + 2]);
 | |
| 	printf("%s   %s   %s\n", weekday, weekday, weekday);
 | |
| 	calendar(year, month + 0, 0);
 | |
| 	calendar(year, month + 1, 1);
 | |
| 	calendar(year, month + 2, 2);
 | |
| 	output(3);
 | |
| #if MONTHS_PER_LINE != 3
 | |
| #error  "the above will not work"
 | |
| #endif
 | |
|   }
 | |
|   printf("\n\n\n");
 | |
| }
 | |
| 
 | |
| void domonth(year, month)
 | |
| int year;
 | |
| int month;
 | |
| /* Do one specific month -- note: no longer used */
 | |
| {
 | |
|   if (year < 1 || year > 9999) usage(badarg);
 | |
|   if (month <= 0 || month > 12) usage(badarg);
 | |
|   printf("%9s%5d\n\n%s\n", monthname[month], year, weekday);
 | |
|   calendar(year, month, 0);
 | |
|   output(1);
 | |
|   printf("\n\n");
 | |
| }
 | |
| 
 | |
| void output(nmonths)
 | |
| int nmonths;			/* Number of months to do	 */
 | |
| /* Clean up and output the text. */
 | |
| {
 | |
|   register int week;
 | |
|   register int month;
 | |
|   register char *outp;
 | |
|   int i;
 | |
|   char tmpbuf[21], *p;
 | |
| 
 | |
|   for (week = 0; week < WEEKS_PER_MONTH; week++) {
 | |
| 	outp = outline;
 | |
| 	for (month = 0; month < nmonths; month++) {
 | |
| 		/* The -1 in the following removes the unwanted
 | |
| 		 * leading blank from the entry for Sunday. */
 | |
| 		p = &layout[month][week][0][1];
 | |
| 		for (i = 0; i < 20; i++) tmpbuf[i] = *p++;
 | |
| 		tmpbuf[20] = 0;
 | |
| 		sprintf(outp, "%s   ", tmpbuf);
 | |
| 		outp += (DAYS_PER_WEEK * ENTRY_SIZE) + MONTH_SPACE - 1;
 | |
| 	}
 | |
| 	while (outp > outline && outp[-1] == ' ') outp--;
 | |
| 	*outp = EOS;
 | |
| 	printf("%s\n", outline);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void calendar(year, month, indx)
 | |
| int year;
 | |
| int month;
 | |
| int indx;			/* Which of the three months		 */
 | |
| /* Actually build the calendar for this month. */
 | |
| {
 | |
|   register char *tp;
 | |
|   int week;
 | |
|   register int wday;
 | |
|   register int today;
 | |
| 
 | |
|   setmonth(year, month);
 | |
|   for (week = 0; week < WEEKS_PER_MONTH; week++) {
 | |
| 	for (wday = 0; wday < DAYS_PER_WEEK; wday++) {
 | |
| 		tp = &layout[indx][week][wday][0];
 | |
| 		*tp++ = ' ';
 | |
| 		today = getdate(week, wday);
 | |
| 		if (today <= 0) {
 | |
| 			*tp++ = ' ';
 | |
| 			*tp++ = ' ';
 | |
| 		} else if (today < 10) {
 | |
| 			*tp++ = ' ';
 | |
| 			*tp = (today + '0');
 | |
| 		} else {
 | |
| 			*tp++ = (today / 10) + '0';
 | |
| 			*tp = (today % 10) + '0';
 | |
| 		}
 | |
| 	}
 | |
|   }
 | |
| }
 | |
| 
 | |
| void usage(s)
 | |
| char *s;
 | |
| {
 | |
| /* Fatal parameter error. */
 | |
| 
 | |
|   fprintf(stderr, "%s", s);
 | |
|   exit(IO_ERROR);
 | |
| }
 | |
| 
 | |
| /* Calendar routines, intended for eventual porting to TeX
 | |
|  *
 | |
|  * date(year, month, week, wday)
 | |
|  *	Returns the date on this week (0 is first, 5 last possible)
 | |
|  *	and day of the week (Sunday == 0)
 | |
|  *	Note: January is month 1.
 | |
|  *
 | |
|  * setmonth(year, month)
 | |
|  *	Parameters are as above, sets getdate() for this month.
 | |
|  *
 | |
|  * int
 | |
|  * getdate(week, wday)
 | |
|  *	Parameters are as above, uses the data set by setmonth()
 | |
|  */
 | |
| 
 | |
| /* This structure is used to pass data between setmonth() and getdate().
 | |
|  * It needs considerable expansion if the Julian->Gregorian change is
 | |
|  * to be extended to other countries.
 | |
|  */
 | |
| 
 | |
| static struct {
 | |
|   int this_month;		/* month number used in 1752 checking	 */
 | |
|   int feb;			/* Days in February for this month	 */
 | |
|   int sept;			/* Days in September for this month	 */
 | |
|   int days_in_month;		/* Number of days in this month		 */
 | |
|   int dow_first;		/* Day of week of the 1st day in month	 */
 | |
| } info;
 | |
| 
 | |
| static int day_month[] = {	/* 30 days hath September...		 */
 | |
| 		  0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
 | |
| };
 | |
| 
 | |
| int date(year, month, week, wday)
 | |
| int year;			/* Calendar date being computed		 */
 | |
| int month;			/* January == 1				 */
 | |
| int week;			/* Week in the month 0..5 inclusive	 */
 | |
| int wday;			/* Weekday, Sunday == 0			 */
 | |
| /* Return the date of the month that fell on this week and weekday.
 | |
|  * Return zero if it's out of range.
 | |
|  */
 | |
| {
 | |
|   setmonth(year, month);
 | |
|   return(getdate(week, wday));
 | |
| }
 | |
| 
 | |
| void setmonth(year, month)
 | |
| int year;			/* Year to compute		 */
 | |
| int month;			/* Month, January is month 1	 */
 | |
| /* Setup the parameters needed to compute this month
 | |
|  * (stored in the info structure).
 | |
|  */
 | |
| {
 | |
|   register int i;
 | |
| 
 | |
|   if (month < 1 || month > 12) {/* Verify caller's parameters	 */
 | |
| 	info.days_in_month = 0;	/* Garbage flag			 */
 | |
| 	return;
 | |
|   }
 | |
|   info.this_month = month;	/* used in 1752	checking	 */
 | |
|   info.dow_first = Jan1(year);	/* Day of January 1st for now	 */
 | |
|   info.feb = 29;		/* Assume leap year		 */
 | |
|   info.sept = 30;		/* Assume normal year		 */
 | |
|   /* Determine whether it's an ordinary year, a leap year or the
 | |
|    * magical calendar switch year of 1752. */
 | |
|   switch ((Jan1(year + 1) + 7 - info.dow_first) % 7) {
 | |
|       case 1:			/* Not a leap year		 */
 | |
| 	info.feb = 28;
 | |
|       case 2:			/* Ordinary leap year		 */
 | |
| 	break;
 | |
| 
 | |
|       default:			/* The magical moment arrives	 */
 | |
| 	info.sept = 19;		/* 19 days hath September	 */
 | |
| 	break;
 | |
|   }
 | |
|   info.days_in_month =
 | |
| 	(month == 2) ? info.feb
 | |
| 	: (month == 9) ? info.sept
 | |
| 	: day_month[month];
 | |
|   for (i = 1; i < month; i++) {
 | |
| 	switch (i) {		/* Special months?		 */
 | |
| 	    case 2:		/* February			 */
 | |
| 		info.dow_first += info.feb;
 | |
| 		break;
 | |
| 
 | |
| 	    case 9:	info.dow_first += info.sept;	break;
 | |
| 
 | |
| 	    default:
 | |
| 		info.dow_first += day_month[i];
 | |
| 		break;
 | |
| 	}
 | |
|   }
 | |
|   info.dow_first %= 7;		/* Now it's Sunday to Saturday	 */
 | |
| }
 | |
| 
 | |
| int getdate(week, wday)
 | |
| int week;
 | |
| int wday;
 | |
| {
 | |
|   register int today;
 | |
| 
 | |
|   /* Get a first guess at today's date and make sure it's in range. */
 | |
|   today = (week * 7) + wday - info.dow_first + 1;
 | |
|   if (today <= 0 || today > info.days_in_month)
 | |
| 	return(0);
 | |
|   else if (info.sept == 19 && info.this_month == 9
 | |
| 	 && today >= 3)		/* The magical month?	 */
 | |
| 	return(today + 11);	/* If so, some dates changed	 */
 | |
|   else				/* Otherwise,			 */
 | |
| 	return(today);		/* Return the date		 */
 | |
| }
 | |
| 
 | |
| static int Jan1(year)
 | |
| int year;
 | |
| /* Return day of the week for Jan 1 of the specified year. */
 | |
| {
 | |
|   register int day;
 | |
| 
 | |
|   day = year + 4 + ((year + 3) / 4);	/* Julian Calendar	 */
 | |
|   if (year > 1800) {		/* If it's recent, do	 */
 | |
| 	day -= ((year - 1701) / 100);	/* Clavian correction	 */
 | |
| 	day += ((year - 1601) / 400);	/* Gregorian correction	 */
 | |
|   }
 | |
|   if (year > 1752)		/* Adjust for Gregorian	 */
 | |
| 	day += 3;		/* calendar		 */
 | |
|   return(day % 7);
 | |
| }
 | 
