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