1 /* cal - print a calendar Author: Maritn Minow */
7 #define do3months domonth
8 #define IO_SUCCESS 0 /* Unix definitions */
12 #define ENTRY_SIZE 3 /* 3 bytes per value */
13 #define DAYS_PER_WEEK 7 /* Sunday, etc. */
14 #define WEEKS_PER_MONTH 6 /* Max. weeks in a month */
15 #define MONTHS_PER_LINE 3 /* Three months across */
16 #define MONTH_SPACE 3 /* Between each month */
18 char *badarg
= {"Bad argument\n"};
19 char *how
= {"Usage: cal [month] year\n"};
21 /* Calendar() stuffs data into layout[],
22 * output() copies from layout[] to outline[], (then trims blanks).
24 char layout
[MONTHS_PER_LINE
][WEEKS_PER_MONTH
][DAYS_PER_WEEK
][ENTRY_SIZE
];
25 char outline
[(MONTHS_PER_LINE
* DAYS_PER_WEEK
* ENTRY_SIZE
)
26 + (MONTHS_PER_LINE
* MONTH_SPACE
)
29 char *weekday
= " S M Tu W Th F S";
31 "???", /* No month 0 */
32 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
33 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
36 int main(int argc
, char **argv
);
37 void doyear(int year
);
38 void domonth(int year
, int month
);
39 void output(int nmonths
);
40 void calendar(int year
, int month
, int indx
);
42 int date(int year
, int month
, int week
, int wday
);
43 void setmonth(int year
, int month
);
44 int getdate(int week
, int wday
);
45 static int Jan1(int year
);
60 arg1val
= atoi(argv
[1]);
61 arg1len
= strlen(argv
[1]);
63 /* Only one argument, if small, it's a month. If
64 * large, it's a year. Note: cal 0082 Year
65 * 0082 cal 82 Year 0082 */
66 if (arg1len
<= 2 && arg1val
<= 12)
67 do3months(year
, arg1val
);
71 /* Two arguments, allow 1980 12 or 12 1980 */
72 arg2val
= atoi(argv
[2]);
74 do3months(arg1val
, arg2val
);
76 do3months(arg2val
, arg1val
);
84 /* Print the calendar for an entire year. */
88 if (year
< 1 || year
> 9999) usage(badarg
);
90 printf("\n\n\n 00%2d\n\n", year
);
92 printf("\n\n\n%35d\n\n", year
);
93 for (month
= 1; month
<= 12; month
+= MONTHS_PER_LINE
) {
94 printf("%12s%23s%23s\n",
97 monthname
[month
+ 2]);
98 printf("%s %s %s\n", weekday
, weekday
, weekday
);
99 calendar(year
, month
+ 0, 0);
100 calendar(year
, month
+ 1, 1);
101 calendar(year
, month
+ 2, 2);
103 #if MONTHS_PER_LINE != 3
104 #error "the above will not work"
110 void domonth(year
, month
)
113 /* Do one specific month -- note: no longer used */
115 if (year
< 1 || year
> 9999) usage(badarg
);
116 if (month
<= 0 || month
> 12) usage(badarg
);
117 printf("%9s%5d\n\n%s\n", monthname
[month
], year
, weekday
);
118 calendar(year
, month
, 0);
124 int nmonths
; /* Number of months to do */
125 /* Clean up and output the text. */
133 for (week
= 0; week
< WEEKS_PER_MONTH
; week
++) {
135 for (month
= 0; month
< nmonths
; month
++) {
136 /* The -1 in the following removes the unwanted
137 * leading blank from the entry for Sunday. */
138 p
= &layout
[month
][week
][0][1];
139 for (i
= 0; i
< 20; i
++) tmpbuf
[i
] = *p
++;
141 sprintf(outp
, "%s ", tmpbuf
);
142 outp
+= (DAYS_PER_WEEK
* ENTRY_SIZE
) + MONTH_SPACE
- 1;
144 while (outp
> outline
&& outp
[-1] == ' ') outp
--;
146 printf("%s\n", outline
);
150 void calendar(year
, month
, indx
)
153 int indx
; /* Which of the three months */
154 /* Actually build the calendar for this month. */
161 setmonth(year
, month
);
162 for (week
= 0; week
< WEEKS_PER_MONTH
; week
++) {
163 for (wday
= 0; wday
< DAYS_PER_WEEK
; wday
++) {
164 tp
= &layout
[indx
][week
][wday
][0];
166 today
= getdate(week
, wday
);
170 } else if (today
< 10) {
174 *tp
++ = (today
/ 10) + '0';
175 *tp
= (today
% 10) + '0';
184 /* Fatal parameter error. */
186 fprintf(stderr
, "%s", s
);
190 /* Calendar routines, intended for eventual porting to TeX
192 * date(year, month, week, wday)
193 * Returns the date on this week (0 is first, 5 last possible)
194 * and day of the week (Sunday == 0)
195 * Note: January is month 1.
197 * setmonth(year, month)
198 * Parameters are as above, sets getdate() for this month.
201 * getdate(week, wday)
202 * Parameters are as above, uses the data set by setmonth()
205 /* This structure is used to pass data between setmonth() and getdate().
206 * It needs considerable expansion if the Julian->Gregorian change is
207 * to be extended to other countries.
211 int this_month
; /* month number used in 1752 checking */
212 int feb
; /* Days in February for this month */
213 int sept
; /* Days in September for this month */
214 int days_in_month
; /* Number of days in this month */
215 int dow_first
; /* Day of week of the 1st day in month */
218 static int day_month
[] = { /* 30 days hath September... */
219 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
222 int date(year
, month
, week
, wday
)
223 int year
; /* Calendar date being computed */
224 int month
; /* January == 1 */
225 int week
; /* Week in the month 0..5 inclusive */
226 int wday
; /* Weekday, Sunday == 0 */
227 /* Return the date of the month that fell on this week and weekday.
228 * Return zero if it's out of range.
231 setmonth(year
, month
);
232 return(getdate(week
, wday
));
235 void setmonth(year
, month
)
236 int year
; /* Year to compute */
237 int month
; /* Month, January is month 1 */
238 /* Setup the parameters needed to compute this month
239 * (stored in the info structure).
244 if (month
< 1 || month
> 12) {/* Verify caller's parameters */
245 info
.days_in_month
= 0; /* Garbage flag */
248 info
.this_month
= month
; /* used in 1752 checking */
249 info
.dow_first
= Jan1(year
); /* Day of January 1st for now */
250 info
.feb
= 29; /* Assume leap year */
251 info
.sept
= 30; /* Assume normal year */
252 /* Determine whether it's an ordinary year, a leap year or the
253 * magical calendar switch year of 1752. */
254 switch ((Jan1(year
+ 1) + 7 - info
.dow_first
) % 7) {
255 case 1: /* Not a leap year */
257 case 2: /* Ordinary leap year */
260 default: /* The magical moment arrives */
261 info
.sept
= 19; /* 19 days hath September */
265 (month
== 2) ? info
.feb
266 : (month
== 9) ? info
.sept
268 for (i
= 1; i
< month
; i
++) {
269 switch (i
) { /* Special months? */
270 case 2: /* February */
271 info
.dow_first
+= info
.feb
;
274 case 9: info
.dow_first
+= info
.sept
; break;
277 info
.dow_first
+= day_month
[i
];
281 info
.dow_first
%= 7; /* Now it's Sunday to Saturday */
284 int getdate(week
, wday
)
290 /* Get a first guess at today's date and make sure it's in range. */
291 today
= (week
* 7) + wday
- info
.dow_first
+ 1;
292 if (today
<= 0 || today
> info
.days_in_month
)
294 else if (info
.sept
== 19 && info
.this_month
== 9
295 && today
>= 3) /* The magical month? */
296 return(today
+ 11); /* If so, some dates changed */
297 else /* Otherwise, */
298 return(today
); /* Return the date */
301 static int Jan1(year
)
303 /* Return day of the week for Jan 1 of the specified year. */
307 day
= year
+ 4 + ((year
+ 3) / 4); /* Julian Calendar */
308 if (year
> 1800) { /* If it's recent, do */
309 day
-= ((year
- 1701) / 100); /* Clavian correction */
310 day
+= ((year
- 1601) / 400); /* Gregorian correction */
312 if (year
> 1752) /* Adjust for Gregorian */
313 day
+= 3; /* calendar */