cal.c - sbase - suckless unix tools | |
git clone git://git.suckless.org/sbase | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
cal.c (5009B) | |
--- | |
1 /* See LICENSE file for copyright and license details. */ | |
2 #include <limits.h> | |
3 #include <stdint.h> | |
4 #include <stdio.h> | |
5 #include <stdlib.h> | |
6 #include <string.h> | |
7 #include <time.h> | |
8 #include <unistd.h> | |
9 | |
10 #include "util.h" | |
11 | |
12 enum { JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC }; | |
13 enum caltype { JULIAN, GREGORIAN }; | |
14 enum { TRANS_YEAR = 1752, TRANS_MONTH = SEP, TRANS_DAY = 2 }; | |
15 | |
16 static struct tm *ltime; | |
17 | |
18 static int | |
19 isleap(size_t year, enum caltype cal) | |
20 { | |
21 if (cal == GREGORIAN) { | |
22 if (year % 400 == 0) | |
23 return 1; | |
24 if (year % 100 == 0) | |
25 return 0; | |
26 return (year % 4 == 0); | |
27 } | |
28 else { /* cal == Julian */ | |
29 return (year % 4 == 0); | |
30 } | |
31 } | |
32 | |
33 static int | |
34 monthlength(size_t year, int month, enum caltype cal) | |
35 { | |
36 int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | |
37 | |
38 return (month == FEB && isleap(year, cal)) ? 29 : mdays[month]; | |
39 } | |
40 | |
41 /* From http://www.tondering.dk/claus/cal/chrweek.php#calcdow */ | |
42 static int | |
43 dayofweek(size_t year, int month, int dom, enum caltype cal) | |
44 { | |
45 size_t y; | |
46 int m, a; | |
47 | |
48 a = (13 - month) / 12; | |
49 y = year - a; | |
50 m = month + 12 * a - 1; | |
51 | |
52 if (cal == GREGORIAN) | |
53 return (dom + y + y / 4 - y / 100 + y / 400 + (31 * m) /… | |
54 else /* cal == Julian */ | |
55 return (5 + dom + y + y / 4 + (31 * m) / 12) % 7; | |
56 } | |
57 | |
58 static void | |
59 printgrid(size_t year, int month, int fday, int line) | |
60 { | |
61 enum caltype cal; | |
62 int offset, dom, d = 0, trans; /* are we in the transition from … | |
63 int today = 0; | |
64 | |
65 cal = (year < TRANS_YEAR || (year == TRANS_YEAR && month <= TRAN… | |
66 trans = (year == TRANS_YEAR && month == TRANS_MONTH); | |
67 offset = dayofweek(year, month, 1, cal) - fday; | |
68 | |
69 if (offset < 0) | |
70 offset += 7; | |
71 if (line == 1) { | |
72 for (; d < offset; ++d) | |
73 printf(" "); | |
74 dom = 1; | |
75 } else { | |
76 dom = 8 - offset + (line - 2) * 7; | |
77 if (trans && !(line == 2 && fday == 3)) | |
78 dom += 11; | |
79 } | |
80 if (ltime && year == ltime->tm_year + 1900 && month == ltime->tm… | |
81 today = ltime->tm_mday; | |
82 for (; d < 7 && dom <= monthlength(year, month, cal); ++d, ++dom… | |
83 if (dom == today) | |
84 printf("\x1b[7m%2d\x1b[0m ", dom); /* highlight … | |
85 else | |
86 printf("%2d ", dom); | |
87 if (trans && dom == TRANS_DAY) | |
88 dom += 11; | |
89 } | |
90 for (; d < 7; ++d) | |
91 printf(" "); | |
92 } | |
93 | |
94 static void | |
95 drawcal(size_t year, int month, size_t ncols, size_t nmons, int fday) | |
96 { | |
97 char *smon[] = { "January", "February", "March", "April", | |
98 "May", "June", "July", "August", | |
99 "September", "October", "November", "December" … | |
100 char *days[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", }; | |
101 size_t m, n, col, cur_year, cur_month, dow; | |
102 int line, pad; | |
103 char month_year[sizeof("Su Mo Tu We Th Fr Sa")]; | |
104 | |
105 for (m = 0; m < nmons; ) { | |
106 n = m; | |
107 for (col = 0; m < nmons && col < ncols; ++col, ++m) { | |
108 cur_year = year + m / 12; | |
109 cur_month = month + m % 12; | |
110 if (cur_month > 11) { | |
111 cur_month -= 12; | |
112 cur_year += 1; | |
113 } | |
114 snprintf(month_year, sizeof(month_year), "%s %zu… | |
115 pad = sizeof(month_year) - 1 - strlen(month_year… | |
116 printf("%*s%s%*s ", pad / 2 + pad % 2, "", mon… | |
117 } | |
118 putchar('\n'); | |
119 for (col = 0, m = n; m < nmons && col < ncols; ++col, ++… | |
120 for (dow = fday; dow < (fday + 7); ++dow) | |
121 printf("%s ", days[dow % 7]); | |
122 printf(" "); | |
123 } | |
124 putchar('\n'); | |
125 for (line = 1; line <= 6; ++line) { | |
126 for (col = 0, m = n; m < nmons && col < ncols; +… | |
127 cur_year = year + m / 12; | |
128 cur_month = month + m % 12; | |
129 if (cur_month > 11) { | |
130 cur_month -= 12; | |
131 cur_year += 1; | |
132 } | |
133 printgrid(cur_year, cur_month, fday, lin… | |
134 printf(" "); | |
135 } | |
136 putchar('\n'); | |
137 } | |
138 } | |
139 } | |
140 | |
141 static void | |
142 usage(void) | |
143 { | |
144 eprintf("usage: %s [-1 | -3 | -y | -n num] " | |
145 "[-s | -m | -f num] [-c num] [[month] year]\n", argv0); | |
146 } | |
147 | |
148 int | |
149 main(int argc, char *argv[]) | |
150 { | |
151 time_t now; | |
152 size_t year, ncols, nmons; | |
153 int fday, month; | |
154 | |
155 now = time(NULL); | |
156 ltime = localtime(&now); | |
157 year = ltime->tm_year + 1900; | |
158 month = ltime->tm_mon + 1; | |
159 fday = 0; | |
160 | |
161 if (!isatty(STDOUT_FILENO)) | |
162 ltime = NULL; /* don't highlight today's date */ | |
163 | |
164 ncols = 3; | |
165 nmons = 0; | |
166 | |
167 ARGBEGIN { | |
168 case '1': | |
169 nmons = 1; | |
170 break; | |
171 case '3': | |
172 nmons = 3; | |
173 if (--month == 0) { | |
174 month = 12; | |
175 year--; | |
176 } | |
177 break; | |
178 case 'c': | |
179 ncols = estrtonum(EARGF(usage()), 0, MIN(SIZE_MAX, LLONG… | |
180 break; | |
181 case 'f': | |
182 fday = estrtonum(EARGF(usage()), 0, 6); | |
183 break; | |
184 case 'm': /* Monday */ | |
185 fday = 1; | |
186 break; | |
187 case 'n': | |
188 nmons = estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLONG… | |
189 break; | |
190 case 's': /* Sunday */ | |
191 fday = 0; | |
192 break; | |
193 case 'y': | |
194 month = 1; | |
195 nmons = 12; | |
196 break; | |
197 default: | |
198 usage(); | |
199 } ARGEND | |
200 | |
201 if (nmons == 0) { | |
202 if (argc == 1) { | |
203 month = 1; | |
204 nmons = 12; | |
205 } else { | |
206 nmons = 1; | |
207 } | |
208 } | |
209 | |
210 switch (argc) { | |
211 case 2: | |
212 month = estrtonum(argv[0], 1, 12); | |
213 argv++; | |
214 case 1: /* fallthrough */ | |
215 year = estrtonum(argv[0], 0, INT_MAX); | |
216 break; | |
217 case 0: | |
218 break; | |
219 default: | |
220 usage(); | |
221 } | |
222 | |
223 drawcal(year, month - 1, ncols, nmons, fday); | |
224 | |
225 return fshut(stdout, "<stdout>"); | |
226 } |