OSDN Git Service

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