source: trunk/minix/commands/simple/cal.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 8.1 KB
Line 
1/* cal - print a calendar Author: Maritn Minow */
2
3#include <stdlib.h>
4#include <string.h>
5#include <stdio.h>
6
7#define do3months domonth
8#define IO_SUCCESS 0 /* Unix definitions */
9#define IO_ERROR 1
10#define EOS 0
11
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 */
17
18char *badarg = {"Bad argument\n"};
19char *how = {"Usage: cal [month] year\n"};
20
21/* Calendar() stuffs data into layout[],
22 * output() copies from layout[] to outline[], (then trims blanks).
23 */
24char layout[MONTHS_PER_LINE][WEEKS_PER_MONTH][DAYS_PER_WEEK][ENTRY_SIZE];
25char outline[(MONTHS_PER_LINE * DAYS_PER_WEEK * ENTRY_SIZE)
26 + (MONTHS_PER_LINE * MONTH_SPACE)
27 + 1];
28
29char *weekday = " S M Tu W Th F S";
30char *monthname[] = {
31 "???", /* No month 0 */
32 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
33 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
34};
35
36_PROTOTYPE(int main, (int argc, char **argv));
37_PROTOTYPE(void doyear, (int year));
38_PROTOTYPE(void domonth, (int year, int month));
39_PROTOTYPE(void output, (int nmonths));
40_PROTOTYPE(void calendar, (int year, int month, int indx));
41_PROTOTYPE(void usage, (char *s));
42_PROTOTYPE(int date, (int year, int month, int week, int wday));
43_PROTOTYPE(void setmonth, (int year, int month));
44_PROTOTYPE(int getdate, (int week, int wday));
45_PROTOTYPE(static int Jan1, (int year));
46
47int main(argc, argv)
48int argc;
49char *argv[];
50{
51 register int year;
52
53 register int arg1val;
54 int arg1len;
55 int arg2val;
56
57 if (argc <= 1) {
58 usage(how);
59 } else {
60 arg1val = atoi(argv[1]);
61 arg1len = strlen(argv[1]);
62 if (argc == 2) {
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);
68 else
69 doyear(arg1val);
70 } else {
71 /* Two arguments, allow 1980 12 or 12 1980 */
72 arg2val = atoi(argv[2]);
73 if (arg1len > 2)
74 do3months(arg1val, arg2val);
75 else
76 do3months(arg2val, arg1val);
77 }
78 }
79 return(IO_SUCCESS);
80}
81
82void doyear(year)
83int year;
84/* Print the calendar for an entire year. */
85{
86 register int month;
87
88 if (year < 1 || year > 9999) usage(badarg);
89 if (year < 100)
90 printf("\n\n\n 00%2d\n\n", year);
91 else
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",
95 monthname[month],
96 monthname[month + 1],
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);
102 output(3);
103#if MONTHS_PER_LINE != 3
104#error "the above will not work"
105#endif
106 }
107 printf("\n\n\n");
108}
109
110void domonth(year, month)
111int year;
112int month;
113/* Do one specific month -- note: no longer used */
114{
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);
119 output(1);
120 printf("\n\n");
121}
122
123void output(nmonths)
124int nmonths; /* Number of months to do */
125/* Clean up and output the text. */
126{
127 register int week;
128 register int month;
129 register char *outp;
130 int i;
131 char tmpbuf[21], *p;
132
133 for (week = 0; week < WEEKS_PER_MONTH; week++) {
134 outp = outline;
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++;
140 tmpbuf[20] = 0;
141 sprintf(outp, "%s ", tmpbuf);
142 outp += (DAYS_PER_WEEK * ENTRY_SIZE) + MONTH_SPACE - 1;
143 }
144 while (outp > outline && outp[-1] == ' ') outp--;
145 *outp = EOS;
146 printf("%s\n", outline);
147 }
148}
149
150void calendar(year, month, indx)
151int year;
152int month;
153int indx; /* Which of the three months */
154/* Actually build the calendar for this month. */
155{
156 register char *tp;
157 int week;
158 register int wday;
159 register int today;
160
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];
165 *tp++ = ' ';
166 today = getdate(week, wday);
167 if (today <= 0) {
168 *tp++ = ' ';
169 *tp++ = ' ';
170 } else if (today < 10) {
171 *tp++ = ' ';
172 *tp = (today + '0');
173 } else {
174 *tp++ = (today / 10) + '0';
175 *tp = (today % 10) + '0';
176 }
177 }
178 }
179}
180
181void usage(s)
182char *s;
183{
184/* Fatal parameter error. */
185
186 fprintf(stderr, "%s", s);
187 exit(IO_ERROR);
188}
189
190/* Calendar routines, intended for eventual porting to TeX
191 *
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.
196 *
197 * setmonth(year, month)
198 * Parameters are as above, sets getdate() for this month.
199 *
200 * int
201 * getdate(week, wday)
202 * Parameters are as above, uses the data set by setmonth()
203 */
204
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.
208 */
209
210static struct {
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 */
216} info;
217
218static int day_month[] = { /* 30 days hath September... */
219 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
220};
221
222int date(year, month, week, wday)
223int year; /* Calendar date being computed */
224int month; /* January == 1 */
225int week; /* Week in the month 0..5 inclusive */
226int 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.
229 */
230{
231 setmonth(year, month);
232 return(getdate(week, wday));
233}
234
235void setmonth(year, month)
236int year; /* Year to compute */
237int month; /* Month, January is month 1 */
238/* Setup the parameters needed to compute this month
239 * (stored in the info structure).
240 */
241{
242 register int i;
243
244 if (month < 1 || month > 12) {/* Verify caller's parameters */
245 info.days_in_month = 0; /* Garbage flag */
246 return;
247 }
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 */
256 info.feb = 28;
257 case 2: /* Ordinary leap year */
258 break;
259
260 default: /* The magical moment arrives */
261 info.sept = 19; /* 19 days hath September */
262 break;
263 }
264 info.days_in_month =
265 (month == 2) ? info.feb
266 : (month == 9) ? info.sept
267 : day_month[month];
268 for (i = 1; i < month; i++) {
269 switch (i) { /* Special months? */
270 case 2: /* February */
271 info.dow_first += info.feb;
272 break;
273
274 case 9: info.dow_first += info.sept; break;
275
276 default:
277 info.dow_first += day_month[i];
278 break;
279 }
280 }
281 info.dow_first %= 7; /* Now it's Sunday to Saturday */
282}
283
284int getdate(week, wday)
285int week;
286int wday;
287{
288 register int today;
289
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)
293 return(0);
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 */
299}
300
301static int Jan1(year)
302int year;
303/* Return day of the week for Jan 1 of the specified year. */
304{
305 register int day;
306
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 */
311 }
312 if (year > 1752) /* Adjust for Gregorian */
313 day += 3; /* calendar */
314 return(day % 7);
315}
Note: See TracBrowser for help on using the repository browser.