Annotation of /trunk/mkinitrd-magellan/busybox/coreutils/cal.c
Parent Directory | Revision Log
Revision 984 -
(hide annotations)
(download)
Sun May 30 11:32:42 2010 UTC (13 years, 11 months ago) by niro
File MIME type: text/plain
File size: 9956 byte(s)
Sun May 30 11:32:42 2010 UTC (13 years, 11 months ago) by niro
File MIME type: text/plain
File size: 9956 byte(s)
-updated to busybox-1.16.1 and enabled blkid/uuid support in default config
1 | niro | 532 | /* vi: set sw=4 ts=4: */ |
2 | /* | ||
3 | * Calendar implementation for busybox | ||
4 | * | ||
5 | * See original copyright at the end of this file | ||
6 | * | ||
7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
8 | */ | ||
9 | |||
10 | /* BB_AUDIT SUSv3 compliant with -j and -y extensions (from util-linux). */ | ||
11 | /* BB_AUDIT BUG: The output of 'cal -j 1752' is incorrect. The upstream | ||
12 | * BB_AUDIT BUG: version in util-linux seems to be broken as well. */ | ||
13 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/cal.html */ | ||
14 | |||
15 | /* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) | ||
16 | * | ||
17 | * Major size reduction... over 50% (>1.5k) on i386. | ||
18 | */ | ||
19 | niro | 816 | #include "libbb.h" |
20 | niro | 984 | #include "unicode.h" |
21 | niro | 532 | |
22 | niro | 816 | /* We often use "unsigned" intead of "int", it's easier to div on most CPUs */ |
23 | |||
24 | niro | 532 | #define THURSDAY 4 /* for reformation */ |
25 | #define SATURDAY 6 /* 1 Jan 1 was a Saturday */ | ||
26 | |||
27 | #define FIRST_MISSING_DAY 639787 /* 3 Sep 1752 */ | ||
28 | #define NUMBER_MISSING_DAYS 11 /* 11 day correction */ | ||
29 | |||
30 | #define MAXDAYS 42 /* max slots in a month array */ | ||
31 | #define SPACE -1 /* used in day array */ | ||
32 | |||
33 | niro | 816 | static const unsigned char days_in_month[] ALIGN1 = { |
34 | niro | 532 | 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 |
35 | }; | ||
36 | |||
37 | niro | 816 | static const unsigned char sep1752[] ALIGN1 = { |
38 | niro | 532 | 1, 2, 14, 15, 16, |
39 | 17, 18, 19, 20, 21, 22, 23, | ||
40 | 24, 25, 26, 27, 28, 29, 30 | ||
41 | }; | ||
42 | |||
43 | niro | 816 | /* Set to 0 or 1 in main */ |
44 | #define julian ((unsigned)option_mask32) | ||
45 | niro | 532 | |
46 | /* leap year -- account for Gregorian reformation in 1752 */ | ||
47 | niro | 816 | static int leap_year(unsigned yr) |
48 | niro | 532 | { |
49 | niro | 816 | if (yr <= 1752) |
50 | return !(yr % 4); | ||
51 | return (!(yr % 4) && (yr % 100)) || !(yr % 400); | ||
52 | niro | 532 | } |
53 | |||
54 | /* number of centuries since 1700, not inclusive */ | ||
55 | #define centuries_since_1700(yr) \ | ||
56 | ((yr) > 1700 ? (yr) / 100 - 17 : 0) | ||
57 | |||
58 | /* number of centuries since 1700 whose modulo of 400 is 0 */ | ||
59 | #define quad_centuries_since_1700(yr) \ | ||
60 | ((yr) > 1600 ? ((yr) - 1600) / 400 : 0) | ||
61 | |||
62 | /* number of leap years between year 1 and this year, not inclusive */ | ||
63 | #define leap_years_since_year_1(yr) \ | ||
64 | ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr)) | ||
65 | |||
66 | niro | 816 | static void center(char *, unsigned, unsigned); |
67 | static void day_array(unsigned, unsigned, unsigned *); | ||
68 | static void trim_trailing_spaces_and_print(char *); | ||
69 | niro | 532 | |
70 | static void blank_string(char *buf, size_t buflen); | ||
71 | niro | 816 | static char *build_row(char *p, unsigned *dp); |
72 | niro | 532 | |
73 | #define DAY_LEN 3 /* 3 spaces per day */ | ||
74 | #define J_DAY_LEN (DAY_LEN + 1) | ||
75 | #define WEEK_LEN 20 /* 7 * 3 - one space at the end */ | ||
76 | #define J_WEEK_LEN (WEEK_LEN + 7) | ||
77 | #define HEAD_SEP 2 /* spaces between day headings */ | ||
78 | |||
79 | niro | 816 | int cal_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
80 | niro | 984 | int cal_main(int argc UNUSED_PARAM, char **argv) |
81 | niro | 532 | { |
82 | struct tm zero_tm; | ||
83 | time_t now; | ||
84 | niro | 816 | unsigned month, year, flags, i; |
85 | niro | 532 | char *month_names[12]; |
86 | niro | 984 | /* normal heading: */ |
87 | /* "Su Mo Tu We Th Fr Sa" */ | ||
88 | /* -j heading: */ | ||
89 | /* " Su Mo Tu We Th Fr Sa" */ | ||
90 | char day_headings[ENABLE_FEATURE_ASSUME_UNICODE ? 28 * 6 : 28]; | ||
91 | IF_FEATURE_ASSUME_UNICODE(char *hp = day_headings;) | ||
92 | niro | 532 | char buf[40]; |
93 | |||
94 | niro | 984 | init_unicode(); |
95 | |||
96 | niro | 816 | flags = getopt32(argv, "jy"); |
97 | /* This sets julian = flags & 1: */ | ||
98 | option_mask32 &= 1; | ||
99 | month = 0; | ||
100 | niro | 532 | argv += optind; |
101 | |||
102 | niro | 984 | if (!argv[0]) { |
103 | struct tm *ptm; | ||
104 | niro | 532 | |
105 | time(&now); | ||
106 | niro | 984 | ptm = localtime(&now); |
107 | year = ptm->tm_year + 1900; | ||
108 | niro | 816 | if (!(flags & 2)) { /* no -y */ |
109 | niro | 984 | month = ptm->tm_mon + 1; |
110 | niro | 532 | } |
111 | } else { | ||
112 | niro | 984 | if (argv[1]) { |
113 | if (argv[2]) { | ||
114 | bb_show_usage(); | ||
115 | } | ||
116 | niro | 816 | month = xatou_range(*argv++, 1, 12); |
117 | niro | 532 | } |
118 | niro | 816 | year = xatou_range(*argv, 1, 9999); |
119 | niro | 532 | } |
120 | |||
121 | niro | 816 | blank_string(day_headings, sizeof(day_headings) - 7 + 7*julian); |
122 | niro | 532 | |
123 | i = 0; | ||
124 | do { | ||
125 | zero_tm.tm_mon = i; | ||
126 | niro | 984 | /* full month name according to locale */ |
127 | niro | 532 | strftime(buf, sizeof(buf), "%B", &zero_tm); |
128 | month_names[i] = xstrdup(buf); | ||
129 | |||
130 | if (i < 7) { | ||
131 | zero_tm.tm_wday = i; | ||
132 | niro | 984 | /* abbreviated weekday name according to locale */ |
133 | niro | 532 | strftime(buf, sizeof(buf), "%a", &zero_tm); |
134 | niro | 984 | #if ENABLE_FEATURE_ASSUME_UNICODE |
135 | if (julian) | ||
136 | *hp++ = ' '; | ||
137 | { | ||
138 | char *two_wchars = unicode_cut_nchars(2, buf); | ||
139 | strcpy(hp, two_wchars); | ||
140 | free(two_wchars); | ||
141 | } | ||
142 | hp += strlen(hp); | ||
143 | *hp++ = ' '; | ||
144 | #else | ||
145 | niro | 532 | strncpy(day_headings + i * (3+julian) + julian, buf, 2); |
146 | niro | 984 | #endif |
147 | niro | 532 | } |
148 | } while (++i < 12); | ||
149 | niro | 984 | IF_FEATURE_ASSUME_UNICODE(hp[-1] = '\0';) |
150 | niro | 532 | |
151 | if (month) { | ||
152 | niro | 816 | unsigned row, len, days[MAXDAYS]; |
153 | unsigned *dp = days; | ||
154 | niro | 532 | char lineout[30]; |
155 | |||
156 | day_array(month, year, dp); | ||
157 | len = sprintf(lineout, "%s %d", month_names[month - 1], year); | ||
158 | printf("%*s%s\n%s\n", | ||
159 | ((7*julian + WEEK_LEN) - len) / 2, "", | ||
160 | lineout, day_headings); | ||
161 | for (row = 0; row < 6; row++) { | ||
162 | build_row(lineout, dp)[0] = '\0'; | ||
163 | dp += 7; | ||
164 | trim_trailing_spaces_and_print(lineout); | ||
165 | } | ||
166 | } else { | ||
167 | niro | 816 | unsigned row, which_cal, week_len, days[12][MAXDAYS]; |
168 | unsigned *dp; | ||
169 | niro | 532 | char lineout[80]; |
170 | |||
171 | niro | 984 | sprintf(lineout, "%u", year); |
172 | niro | 532 | center(lineout, |
173 | (WEEK_LEN * 3 + HEAD_SEP * 2) | ||
174 | + julian * (J_WEEK_LEN * 2 + HEAD_SEP | ||
175 | - (WEEK_LEN * 3 + HEAD_SEP * 2)), | ||
176 | 0); | ||
177 | puts("\n"); /* two \n's */ | ||
178 | for (i = 0; i < 12; i++) { | ||
179 | day_array(i + 1, year, days[i]); | ||
180 | } | ||
181 | blank_string(lineout, sizeof(lineout)); | ||
182 | week_len = WEEK_LEN + julian * (J_WEEK_LEN - WEEK_LEN); | ||
183 | for (month = 0; month < 12; month += 3-julian) { | ||
184 | center(month_names[month], week_len, HEAD_SEP); | ||
185 | if (!julian) { | ||
186 | center(month_names[month + 1], week_len, HEAD_SEP); | ||
187 | } | ||
188 | center(month_names[month + 2 - julian], week_len, 0); | ||
189 | printf("\n%s%*s%s", day_headings, HEAD_SEP, "", day_headings); | ||
190 | if (!julian) { | ||
191 | printf("%*s%s", HEAD_SEP, "", day_headings); | ||
192 | } | ||
193 | niro | 816 | bb_putchar('\n'); |
194 | niro | 532 | for (row = 0; row < (6*7); row += 7) { |
195 | for (which_cal = 0; which_cal < 3-julian; which_cal++) { | ||
196 | dp = days[month + which_cal] + row; | ||
197 | build_row(lineout + which_cal * (week_len + 2), dp); | ||
198 | } | ||
199 | /* blank_string took care of nul termination. */ | ||
200 | trim_trailing_spaces_and_print(lineout); | ||
201 | } | ||
202 | } | ||
203 | } | ||
204 | |||
205 | niro | 816 | fflush_stdout_and_exit(EXIT_SUCCESS); |
206 | niro | 532 | } |
207 | |||
208 | /* | ||
209 | * day_array -- | ||
210 | * Fill in an array of 42 integers with a calendar. Assume for a moment | ||
211 | * that you took the (maximum) 6 rows in a calendar and stretched them | ||
212 | * out end to end. You would have 42 numbers or spaces. This routine | ||
213 | * builds that array for any month from Jan. 1 through Dec. 9999. | ||
214 | */ | ||
215 | niro | 816 | static void day_array(unsigned month, unsigned year, unsigned *days) |
216 | niro | 532 | { |
217 | niro | 816 | unsigned long temp; |
218 | unsigned i; | ||
219 | unsigned day, dw, dm; | ||
220 | niro | 532 | |
221 | memset(days, SPACE, MAXDAYS * sizeof(int)); | ||
222 | |||
223 | if ((month == 9) && (year == 1752)) { | ||
224 | niro | 816 | /* Assumes the Gregorian reformation eliminates |
225 | * 3 Sep. 1752 through 13 Sep. 1752. | ||
226 | */ | ||
227 | unsigned j_offset = julian * 244; | ||
228 | niro | 532 | size_t oday = 0; |
229 | |||
230 | do { | ||
231 | days[oday+2] = sep1752[oday] + j_offset; | ||
232 | } while (++oday < sizeof(sep1752)); | ||
233 | |||
234 | return; | ||
235 | } | ||
236 | |||
237 | /* day_in_year | ||
238 | niro | 816 | * return the 1 based day number within the year |
239 | niro | 532 | */ |
240 | day = 1; | ||
241 | if ((month > 2) && leap_year(year)) { | ||
242 | ++day; | ||
243 | } | ||
244 | |||
245 | i = month; | ||
246 | while (i) { | ||
247 | day += days_in_month[--i]; | ||
248 | } | ||
249 | |||
250 | /* day_in_week | ||
251 | niro | 816 | * return the 0 based day number for any date from 1 Jan. 1 to |
252 | * 31 Dec. 9999. Assumes the Gregorian reformation eliminates | ||
253 | * 3 Sep. 1752 through 13 Sep. 1752. Returns Thursday for all | ||
254 | * missing days. | ||
255 | niro | 532 | */ |
256 | niro | 816 | temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1) + day; |
257 | niro | 532 | if (temp < FIRST_MISSING_DAY) { |
258 | dw = ((temp - 1 + SATURDAY) % 7); | ||
259 | niro | 816 | } else { |
260 | niro | 532 | dw = (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7); |
261 | } | ||
262 | |||
263 | if (!julian) { | ||
264 | day = 1; | ||
265 | } | ||
266 | |||
267 | dm = days_in_month[month]; | ||
268 | if ((month == 2) && leap_year(year)) { | ||
269 | ++dm; | ||
270 | } | ||
271 | |||
272 | niro | 816 | do { |
273 | niro | 532 | days[dw++] = day++; |
274 | niro | 816 | } while (--dm); |
275 | niro | 532 | } |
276 | |||
277 | static void trim_trailing_spaces_and_print(char *s) | ||
278 | { | ||
279 | char *p = s; | ||
280 | |||
281 | while (*p) { | ||
282 | ++p; | ||
283 | } | ||
284 | niro | 816 | while (p != s) { |
285 | niro | 532 | --p; |
286 | niro | 984 | if (!isspace(*p)) { |
287 | niro | 532 | p[1] = '\0'; |
288 | break; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | puts(s); | ||
293 | } | ||
294 | |||
295 | niro | 816 | static void center(char *str, unsigned len, unsigned separate) |
296 | niro | 532 | { |
297 | niro | 816 | unsigned n = strlen(str); |
298 | niro | 532 | len -= n; |
299 | printf("%*s%*s", (len/2) + n, str, (len/2) + (len % 2) + separate, ""); | ||
300 | } | ||
301 | |||
302 | static void blank_string(char *buf, size_t buflen) | ||
303 | { | ||
304 | memset(buf, ' ', buflen); | ||
305 | buf[buflen-1] = '\0'; | ||
306 | } | ||
307 | |||
308 | niro | 816 | static char *build_row(char *p, unsigned *dp) |
309 | niro | 532 | { |
310 | niro | 816 | unsigned col, val, day; |
311 | niro | 532 | |
312 | memset(p, ' ', (julian + DAY_LEN) * 7); | ||
313 | |||
314 | col = 0; | ||
315 | do { | ||
316 | niro | 816 | day = *dp++; |
317 | if (day != SPACE) { | ||
318 | niro | 532 | if (julian) { |
319 | ++p; | ||
320 | if (day >= 100) { | ||
321 | *p = '0'; | ||
322 | p[-1] = (day / 100) + '0'; | ||
323 | day %= 100; | ||
324 | } | ||
325 | } | ||
326 | niro | 816 | val = day / 10; |
327 | if (val > 0) { | ||
328 | niro | 532 | *p = val + '0'; |
329 | } | ||
330 | *++p = day % 10 + '0'; | ||
331 | p += 2; | ||
332 | } else { | ||
333 | p += DAY_LEN + julian; | ||
334 | } | ||
335 | } while (++col < 7); | ||
336 | |||
337 | return p; | ||
338 | } | ||
339 | |||
340 | /* | ||
341 | * Copyright (c) 1989, 1993, 1994 | ||
342 | * The Regents of the University of California. All rights reserved. | ||
343 | * | ||
344 | * This code is derived from software contributed to Berkeley by | ||
345 | * Kim Letkeman. | ||
346 | * | ||
347 | * Redistribution and use in source and binary forms, with or without | ||
348 | * modification, are permitted provided that the following conditions | ||
349 | * are met: | ||
350 | * 1. Redistributions of source code must retain the above copyright | ||
351 | * notice, this list of conditions and the following disclaimer. | ||
352 | * 2. Redistributions in binary form must reproduce the above copyright | ||
353 | * notice, this list of conditions and the following disclaimer in the | ||
354 | * documentation and/or other materials provided with the distribution. | ||
355 | * 3. Neither the name of the University nor the names of its contributors | ||
356 | * may be used to endorse or promote products derived from this software | ||
357 | * without specific prior written permission. | ||
358 | * | ||
359 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
360 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
361 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
362 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
363 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
364 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
365 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
366 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
367 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
368 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
369 | * SUCH DAMAGE. | ||
370 | */ |