394
|
1 /* vi: set sw=4 ts=4:
|
|
2 *
|
|
3 * cal.c - show calendar.
|
|
4 *
|
|
5 * Copyright 2011 Rob Landley <rob@landley.net>
|
|
6 *
|
|
7 * See http://opengroup.org/onlinepubs/9699919799/utilities/cal.html
|
|
8
|
|
9 USE_CAL(NEWTOY(cal, ">2", TOYFLAG_USR|TOYFLAG_BIN))
|
|
10
|
|
11 config CAL
|
|
12 bool "cal"
|
|
13 default y
|
|
14 help
|
|
15 usage: cal [[month] year]
|
|
16 Print a calendar.
|
|
17
|
|
18 With one argument, prints all months of the specified year.
|
|
19 With two arguments, prints calendar for month and year.
|
|
20 */
|
|
21
|
|
22 #include "toys.h"
|
|
23
|
|
24 // Write calendar into buffer: each line is 20 chars wide, end indicated
|
|
25 // by empty string.
|
|
26
|
|
27 static char *calstrings(char *buf, struct tm *tm)
|
|
28 {
|
|
29 char temp[21];
|
|
30 int wday, mday, start, len, line;
|
|
31
|
|
32 // header
|
|
33 len = strftime(temp, 21, "%B %Y", tm);
|
|
34 len += (20-len)/2;
|
|
35 buf += sprintf(buf, "%*s%*s ", len, temp, 20-len, "");
|
|
36 buf++;
|
|
37 buf += sprintf(buf, "Su Mo Tu We Th Fr Sa ");
|
|
38 buf++;
|
|
39
|
|
40 // What day of the week does this month start on?
|
|
41 if (tm->tm_mday>1)
|
|
42 start = (36+tm->tm_wday-tm->tm_mday)%7;
|
|
43 else start = tm->tm_wday;
|
|
44
|
|
45 // What day does this month end on? Alas, libc doesn't tell us...
|
|
46 len = 31;
|
|
47 if (tm->tm_mon == 1) {
|
|
48 int year = tm->tm_year;
|
|
49 len = 28;
|
|
50 if (!(year & 3) && !((year&100) && !(year&400))) len++;
|
|
51 } else if ((tm->tm_mon+(tm->tm_mon>6 ? 1 : 0)) & 1) len = 30;
|
|
52
|
|
53 for (mday=line=0;line<6;line++) {
|
|
54 for (wday=0; wday<7; wday++) {
|
|
55 char *pat = " ";
|
|
56 if (!mday ? wday==start : mday<len) {
|
|
57 pat = "%2d ";
|
|
58 mday++;
|
|
59 }
|
|
60 buf += sprintf(buf, pat, mday);
|
|
61 }
|
|
62 buf++;
|
|
63 }
|
|
64
|
|
65 return buf;
|
|
66 }
|
|
67
|
|
68 void xcheckrange(long val, long low, long high)
|
|
69 {
|
|
70 char *err = "%ld %s than %ld";
|
|
71
|
|
72 if (val < low) error_exit(err, val, "less", low);
|
|
73 if (val > high) error_exit(err, val, "greater", high);
|
|
74 }
|
|
75
|
|
76 // Worst case scenario toybuf usage: sizeof(struct tm) plus 21 bytes/line
|
|
77 // plus 8 lines/month plus 12 months, comes to a bit over 2k of our 4k buffer.
|
|
78
|
|
79 void cal_main(void)
|
|
80 {
|
|
81 struct tm *tm;
|
|
82 char *buf = toybuf;
|
|
83
|
|
84 if (toys.optc) {
|
|
85 // Conveniently starts zeroed
|
|
86 tm = (struct tm *)toybuf;
|
|
87 buf += sizeof(struct tm);
|
|
88
|
|
89 // Last argument is year, one before that (if any) is month.
|
|
90 xcheckrange(tm->tm_year = atol(toys.optargs[--toys.optc]),1,9999);
|
|
91 tm->tm_year -= 1900;
|
|
92 tm->tm_mday = 1;
|
|
93 tm->tm_hour = 12; // noon to avoid timezone weirdness
|
|
94 if (toys.optc) {
|
|
95 xcheckrange(tm->tm_mon = atol(toys.optargs[--toys.optc]),1,12);
|
|
96 tm->tm_mon--;
|
|
97
|
|
98 // Print 12 months of the year
|
|
99
|
|
100 } else {
|
|
101 char *bufs[12];
|
|
102 int i, j, k;
|
|
103
|
|
104 for (i=0; i<12; i++) {
|
|
105 tm->tm_mon=i;
|
|
106 mktime(tm);
|
|
107 buf = calstrings(bufs[i]=buf, tm);
|
|
108 }
|
|
109
|
|
110 // 4 rows, 6 lines each, 3 columns
|
|
111 for (i=0; i<4; i++) {
|
|
112 for (j=0; j<8; j++) {
|
|
113 for(k=0; k<3; k++) {
|
|
114 char **b = bufs+(k+i*3);
|
|
115 *b += printf("%s ", *b);
|
|
116 }
|
|
117 puts("");
|
|
118 }
|
|
119 }
|
|
120 return;
|
|
121 }
|
|
122
|
|
123 // What day of the week does that start on?
|
|
124 mktime(tm);
|
|
125
|
|
126 } else {
|
|
127 time_t now;
|
|
128 time(&now);
|
|
129 tm = localtime(&now);
|
|
130 }
|
|
131
|
|
132 calstrings(buf, tm);
|
|
133 while (*buf) buf += printf("%s\n", buf);
|
|
134 }
|