xref: /aosp_15_r20/external/toybox/toys/posix/cal.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
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