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