blob: 522ab3476d3bdcfd73ff33c3c5daec2fe451d0c9 [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Eric Andersenc98c0622001-12-06 15:16:43 +00002/*
3 * Calendar implementation for busybox
4 *
Eric Andersenc98c0622001-12-06 15:16:43 +00005 * See original copyright at the end of this file
6 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02007 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
"Robert P. J. Day"801ab142006-07-12 07:56:04 +00008 */
Denys Vlasenkoaf3f4202016-11-23 14:46:56 +01009/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
10 *
11 * Major size reduction... over 50% (>1.5k) on i386.
12 */
13//config:config CAL
Denys Vlasenkob097a842018-12-28 03:20:17 +010014//config: bool "cal (5.8 kb)"
Denys Vlasenkoaf3f4202016-11-23 14:46:56 +010015//config: default y
16//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020017//config: cal is used to display a monthly calendar.
Denys Vlasenkoaf3f4202016-11-23 14:46:56 +010018
Denys Vlasenkocbdc37c2018-01-14 14:32:11 +010019//applet:IF_CAL(APPLET_NOEXEC(cal, cal, BB_DIR_USR_BIN, BB_SUID_DROP, cal))
20/* NOEXEC despite rare cases when it can be a "runner" (e.g. cal -n12000 takes you into years 30xx) */
Denys Vlasenkoaf3f4202016-11-23 14:46:56 +010021
22//kbuild:lib-$(CONFIG_CAL) += cal.o
Manuel Novoa III cad53642003-03-19 09:13:01 +000023
24/* BB_AUDIT SUSv3 compliant with -j and -y extensions (from util-linux). */
25/* BB_AUDIT BUG: The output of 'cal -j 1752' is incorrect. The upstream
26 * BB_AUDIT BUG: version in util-linux seems to be broken as well. */
27/* http://www.opengroup.org/onlinepubs/007904975/utilities/cal.html */
28
Pere Orga34425382011-03-31 14:43:25 +020029//usage:#define cal_trivial_usage
Ron Yorston56f0e882021-09-21 08:42:58 +010030//usage: "[-jmy] [[MONTH] YEAR]"
Pere Orga34425382011-03-31 14:43:25 +020031//usage:#define cal_full_usage "\n\n"
32//usage: "Display a calendar\n"
Pere Orga34425382011-03-31 14:43:25 +020033//usage: "\n -j Use julian dates"
Ron Yorston56f0e882021-09-21 08:42:58 +010034//usage: "\n -m Week starts on Monday"
Pere Orga34425382011-03-31 14:43:25 +020035//usage: "\n -y Display the entire year"
36
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000037#include "libbb.h"
Denys Vlasenko9f93d622010-01-24 07:44:03 +010038#include "unicode.h"
Manuel Novoa III b99cb642002-05-29 19:08:41 +000039
Denys Vlasenko10ad6222017-04-17 16:13:32 +020040/* We often use "unsigned" instead of "int", it's easier to div on most CPUs */
Denis Vlasenko661f6fa2007-07-26 11:12:51 +000041
Ron Yorston56f0e882021-09-21 08:42:58 +010042#define SUNDAY 0
43#define MONDAY 1
Eric Andersenc98c0622001-12-06 15:16:43 +000044#define THURSDAY 4 /* for reformation */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000045#define SATURDAY 6 /* 1 Jan 1 was a Saturday */
Eric Andersenc98c0622001-12-06 15:16:43 +000046
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000047#define FIRST_MISSING_DAY 639787 /* 3 Sep 1752 */
48#define NUMBER_MISSING_DAYS 11 /* 11 day correction */
Eric Andersenc98c0622001-12-06 15:16:43 +000049
50#define MAXDAYS 42 /* max slots in a month array */
51#define SPACE -1 /* used in day array */
52
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000053static const unsigned char days_in_month[] ALIGN1 = {
Manuel Novoa III cad53642003-03-19 09:13:01 +000054 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
Eric Andersenc98c0622001-12-06 15:16:43 +000055};
56
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000057static const unsigned char sep1752[] ALIGN1 = {
Denys Vlasenko6830ade2013-01-15 13:58:01 +010058 1, 2, 14, 15, 16,
Eric Andersenc98c0622001-12-06 15:16:43 +000059 17, 18, 19, 20, 21, 22, 23,
Manuel Novoa III cad53642003-03-19 09:13:01 +000060 24, 25, 26, 27, 28, 29, 30
Eric Andersenc98c0622001-12-06 15:16:43 +000061};
62
Denis Vlasenkoa5254032008-07-22 10:10:13 +000063/* Set to 0 or 1 in main */
64#define julian ((unsigned)option_mask32)
Eric Andersenc98c0622001-12-06 15:16:43 +000065
Eric Andersenaff114c2004-04-14 17:51:38 +000066/* leap year -- account for Gregorian reformation in 1752 */
Denis Vlasenko661f6fa2007-07-26 11:12:51 +000067static int leap_year(unsigned yr)
Manuel Novoa III cad53642003-03-19 09:13:01 +000068{
Denis Vlasenko319f8eb2007-08-13 11:09:30 +000069 if (yr <= 1752)
Denis Vlasenko661f6fa2007-07-26 11:12:51 +000070 return !(yr % 4);
71 return (!(yr % 4) && (yr % 100)) || !(yr % 400);
Manuel Novoa III cad53642003-03-19 09:13:01 +000072}
Manuel Novoa III cad53642003-03-19 09:13:01 +000073
Eric Andersenc98c0622001-12-06 15:16:43 +000074/* number of centuries since 1700, not inclusive */
75#define centuries_since_1700(yr) \
76 ((yr) > 1700 ? (yr) / 100 - 17 : 0)
77
78/* number of centuries since 1700 whose modulo of 400 is 0 */
79#define quad_centuries_since_1700(yr) \
80 ((yr) > 1600 ? ((yr) - 1600) / 400 : 0)
81
82/* number of leap years between year 1 and this year, not inclusive */
83#define leap_years_since_year_1(yr) \
84 ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
85
Denis Vlasenko661f6fa2007-07-26 11:12:51 +000086static void center(char *, unsigned, unsigned);
Ron Yorston56f0e882021-09-21 08:42:58 +010087static void day_array(unsigned, unsigned, unsigned, unsigned *);
Denis Vlasenko661f6fa2007-07-26 11:12:51 +000088static void trim_trailing_spaces_and_print(char *);
Manuel Novoa III cad53642003-03-19 09:13:01 +000089
90static void blank_string(char *buf, size_t buflen);
Denis Vlasenko661f6fa2007-07-26 11:12:51 +000091static char *build_row(char *p, unsigned *dp);
Manuel Novoa III cad53642003-03-19 09:13:01 +000092
93#define DAY_LEN 3 /* 3 spaces per day */
94#define J_DAY_LEN (DAY_LEN + 1)
95#define WEEK_LEN 20 /* 7 * 3 - one space at the end */
96#define J_WEEK_LEN (WEEK_LEN + 7)
97#define HEAD_SEP 2 /* spaces between day headings */
Eric Andersenc98c0622001-12-06 15:16:43 +000098
Ron Yorston56f0e882021-09-21 08:42:58 +010099enum {
100 OPT_JULIAN = (1 << 0),
101 OPT_MONDAY = (1 << 1),
102 OPT_YEAR = (1 << 2),
103};
104
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000105int cal_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko2ec91ae2010-01-04 14:15:38 +0100106int cal_main(int argc UNUSED_PARAM, char **argv)
Eric Andersenc98c0622001-12-06 15:16:43 +0000107{
Manuel Novoa III cad53642003-03-19 09:13:01 +0000108 struct tm zero_tm;
Eric Andersenc98c0622001-12-06 15:16:43 +0000109 time_t now;
Ron Yorston56f0e882021-09-21 08:42:58 +0100110 unsigned month, year, flags, i, weekstart;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000111 char *month_names[12];
Denys Vlasenko9f93d622010-01-24 07:44:03 +0100112 /* normal heading: */
113 /* "Su Mo Tu We Th Fr Sa" */
114 /* -j heading: */
115 /* " Su Mo Tu We Th Fr Sa" */
Denys Vlasenko19158a82010-03-26 14:06:56 +0100116 char day_headings[ENABLE_UNICODE_SUPPORT ? 28 * 6 : 28];
117 IF_UNICODE_SUPPORT(char *hp = day_headings;)
Eric Andersenc98c0622001-12-06 15:16:43 +0000118 char buf[40];
119
Denys Vlasenko9f93d622010-01-24 07:44:03 +0100120 init_unicode();
121
Ron Yorston56f0e882021-09-21 08:42:58 +0100122 flags = getopt32(argv, "jmy");
123 /* This sets julian = flags & OPT_JULIAN: */
124 option_mask32 &= OPT_JULIAN;
Eric Andersenc98c0622001-12-06 15:16:43 +0000125 month = 0;
Ron Yorston56f0e882021-09-21 08:42:58 +0100126 weekstart = (flags & OPT_MONDAY) ? MONDAY : SUNDAY;
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000127 argv += optind;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000128
Denys Vlasenko2ec91ae2010-01-04 14:15:38 +0100129 if (!argv[0]) {
Denys Vlasenkodc698bb2010-01-09 19:10:49 +0100130 struct tm *ptm;
131
Eric Andersenc98c0622001-12-06 15:16:43 +0000132 time(&now);
Denys Vlasenkodc698bb2010-01-09 19:10:49 +0100133 ptm = localtime(&now);
134 year = ptm->tm_year + 1900;
Ron Yorston56f0e882021-09-21 08:42:58 +0100135 if (!(flags & OPT_YEAR)) { /* no -y */
Denys Vlasenkodc698bb2010-01-09 19:10:49 +0100136 month = ptm->tm_mon + 1;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000137 }
138 } else {
Denys Vlasenko2ec91ae2010-01-04 14:15:38 +0100139 if (argv[1]) {
140 if (argv[2]) {
141 bb_show_usage();
142 }
Ron Yorston56f0e882021-09-21 08:42:58 +0100143 if (!(flags & OPT_YEAR)) { /* no -y */
Denys Vlasenkoed910c72010-01-31 00:10:18 +0100144 month = xatou_range(*argv, 1, 12);
145 }
146 argv++;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000147 }
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000148 year = xatou_range(*argv, 1, 9999);
Eric Andersenc98c0622001-12-06 15:16:43 +0000149 }
150
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000151 blank_string(day_headings, sizeof(day_headings) - 7 + 7*julian);
Manuel Novoa III cad53642003-03-19 09:13:01 +0000152
153 i = 0;
154 do {
Eric Andersenc98c0622001-12-06 15:16:43 +0000155 zero_tm.tm_mon = i;
Denys Vlasenko86350f82010-01-06 10:18:37 +0100156 /* full month name according to locale */
Eric Andersenc98c0622001-12-06 15:16:43 +0000157 strftime(buf, sizeof(buf), "%B", &zero_tm);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000158 month_names[i] = xstrdup(buf);
Eric Andersenc98c0622001-12-06 15:16:43 +0000159
Manuel Novoa III cad53642003-03-19 09:13:01 +0000160 if (i < 7) {
Ron Yorston56f0e882021-09-21 08:42:58 +0100161 zero_tm.tm_wday = (i + weekstart) % 7;
Denys Vlasenko86350f82010-01-06 10:18:37 +0100162 /* abbreviated weekday name according to locale */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000163 strftime(buf, sizeof(buf), "%a", &zero_tm);
Denys Vlasenko19158a82010-03-26 14:06:56 +0100164#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko9f93d622010-01-24 07:44:03 +0100165 if (julian)
166 *hp++ = ' ';
167 {
Denys Vlasenkodc7e5c42011-01-11 13:08:28 +0100168 char *two_wchars = unicode_conv_to_printable_fixedwidth(/*NULL,*/ buf, 2);
Denys Vlasenko9f93d622010-01-24 07:44:03 +0100169 strcpy(hp, two_wchars);
170 free(two_wchars);
171 }
172 hp += strlen(hp);
173 *hp++ = ' ';
174#else
Manuel Novoa III cad53642003-03-19 09:13:01 +0000175 strncpy(day_headings + i * (3+julian) + julian, buf, 2);
Denys Vlasenko9f93d622010-01-24 07:44:03 +0100176#endif
Manuel Novoa III cad53642003-03-19 09:13:01 +0000177 }
178 } while (++i < 12);
Denys Vlasenko19158a82010-03-26 14:06:56 +0100179 IF_UNICODE_SUPPORT(hp[-1] = '\0';)
Eric Andersenc98c0622001-12-06 15:16:43 +0000180
Manuel Novoa III cad53642003-03-19 09:13:01 +0000181 if (month) {
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000182 unsigned row, len, days[MAXDAYS];
183 unsigned *dp = days;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000184 char lineout[30];
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000185
Ron Yorston56f0e882021-09-21 08:42:58 +0100186 day_array(month, year, weekstart, dp);
Denys Vlasenko327f5502013-11-29 16:45:45 +0100187 len = sprintf(lineout, "%s %u", month_names[month - 1], year);
Denis Vlasenkof0ed3762006-10-26 23:21:47 +0000188 printf("%*s%s\n%s\n",
Denys Vlasenko69675782013-01-14 01:34:48 +0100189 ((7*julian + WEEK_LEN) - len) / 2, "",
190 lineout, day_headings);
Eric Andersenc98c0622001-12-06 15:16:43 +0000191 for (row = 0; row < 6; row++) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000192 build_row(lineout, dp)[0] = '\0';
193 dp += 7;
194 trim_trailing_spaces_and_print(lineout);
195 }
196 } else {
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000197 unsigned row, which_cal, week_len, days[12][MAXDAYS];
198 unsigned *dp;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000199 char lineout[80];
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000200
Denys Vlasenko7bb346f2009-10-06 22:09:50 +0200201 sprintf(lineout, "%u", year);
Manuel Novoa III cad53642003-03-19 09:13:01 +0000202 center(lineout,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +0100203 (WEEK_LEN * 3 + HEAD_SEP * 2)
204 + julian * (J_WEEK_LEN * 2 + HEAD_SEP
Denys Vlasenko6830ade2013-01-15 13:58:01 +0100205 - (WEEK_LEN * 3 + HEAD_SEP * 2)),
Denys Vlasenko60cb48c2013-01-14 15:57:44 +0100206 0
207 );
Manuel Novoa III cad53642003-03-19 09:13:01 +0000208 puts("\n"); /* two \n's */
209 for (i = 0; i < 12; i++) {
Ron Yorston56f0e882021-09-21 08:42:58 +0100210 day_array(i + 1, year, weekstart, days[i]);
Manuel Novoa III cad53642003-03-19 09:13:01 +0000211 }
212 blank_string(lineout, sizeof(lineout));
213 week_len = WEEK_LEN + julian * (J_WEEK_LEN - WEEK_LEN);
214 for (month = 0; month < 12; month += 3-julian) {
215 center(month_names[month], week_len, HEAD_SEP);
216 if (!julian) {
217 center(month_names[month + 1], week_len, HEAD_SEP);
Eric Andersenc98c0622001-12-06 15:16:43 +0000218 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000219 center(month_names[month + 2 - julian], week_len, 0);
Denis Vlasenkof0ed3762006-10-26 23:21:47 +0000220 printf("\n%s%*s%s", day_headings, HEAD_SEP, "", day_headings);
Manuel Novoa III cad53642003-03-19 09:13:01 +0000221 if (!julian) {
Denis Vlasenkof0ed3762006-10-26 23:21:47 +0000222 printf("%*s%s", HEAD_SEP, "", day_headings);
Manuel Novoa III cad53642003-03-19 09:13:01 +0000223 }
Denis Vlasenko4daad902007-09-27 10:20:47 +0000224 bb_putchar('\n');
Manuel Novoa III cad53642003-03-19 09:13:01 +0000225 for (row = 0; row < (6*7); row += 7) {
226 for (which_cal = 0; which_cal < 3-julian; which_cal++) {
227 dp = days[month + which_cal] + row;
228 build_row(lineout + which_cal * (week_len + 2), dp);
229 }
230 /* blank_string took care of nul termination. */
231 trim_trailing_spaces_and_print(lineout);
232 }
Eric Andersenc98c0622001-12-06 15:16:43 +0000233 }
234 }
Eric Andersenc98c0622001-12-06 15:16:43 +0000235
Denys Vlasenko31f45c12022-01-04 23:31:58 +0100236 fflush_stdout_and_exit_SUCCESS();
Eric Andersenc98c0622001-12-06 15:16:43 +0000237}
238
239/*
240 * day_array --
241 * Fill in an array of 42 integers with a calendar. Assume for a moment
242 * that you took the (maximum) 6 rows in a calendar and stretched them
243 * out end to end. You would have 42 numbers or spaces. This routine
244 * builds that array for any month from Jan. 1 through Dec. 9999.
245 */
Ron Yorston56f0e882021-09-21 08:42:58 +0100246static void day_array(unsigned month, unsigned year, unsigned weekstart,
247 unsigned *days)
Eric Andersenc98c0622001-12-06 15:16:43 +0000248{
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000249 unsigned long temp;
250 unsigned i;
251 unsigned day, dw, dm;
Eric Andersenc98c0622001-12-06 15:16:43 +0000252
Manuel Novoa III cad53642003-03-19 09:13:01 +0000253 memset(days, SPACE, MAXDAYS * sizeof(int));
Eric Andersenc98c0622001-12-06 15:16:43 +0000254
Manuel Novoa III cad53642003-03-19 09:13:01 +0000255 if ((month == 9) && (year == 1752)) {
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000256 /* Assumes the Gregorian reformation eliminates
257 * 3 Sep. 1752 through 13 Sep. 1752.
258 */
259 unsigned j_offset = julian * 244;
"Vladimir N. Oleynik"676b15e2006-01-30 13:47:19 +0000260 size_t oday = 0;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000261
Manuel Novoa III cad53642003-03-19 09:13:01 +0000262 do {
Ron Yorston56f0e882021-09-21 08:42:58 +0100263 days[oday+2-weekstart] = sep1752[oday] + j_offset;
"Vladimir N. Oleynik"676b15e2006-01-30 13:47:19 +0000264 } while (++oday < sizeof(sep1752));
Eric Andersenc98c0622001-12-06 15:16:43 +0000265
Eric Andersenc98c0622001-12-06 15:16:43 +0000266 return;
267 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000268
269 /* day_in_year
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000270 * return the 1 based day number within the year
Manuel Novoa III cad53642003-03-19 09:13:01 +0000271 */
272 day = 1;
273 if ((month > 2) && leap_year(year)) {
274 ++day;
Eric Andersenc98c0622001-12-06 15:16:43 +0000275 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000276
277 i = month;
278 while (i) {
279 day += days_in_month[--i];
280 }
281
282 /* day_in_week
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000283 * return the 0 based day number for any date from 1 Jan. 1 to
284 * 31 Dec. 9999. Assumes the Gregorian reformation eliminates
285 * 3 Sep. 1752 through 13 Sep. 1752. Returns Thursday for all
286 * missing days.
Manuel Novoa III cad53642003-03-19 09:13:01 +0000287 */
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000288 temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1) + day;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000289 if (temp < FIRST_MISSING_DAY) {
290 dw = ((temp - 1 + SATURDAY) % 7);
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000291 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000292 dw = (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
293 }
Ron Yorston56f0e882021-09-21 08:42:58 +0100294 dw = (dw - weekstart + 7) % 7;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000295
296 if (!julian) {
297 day = 1;
298 }
299
300 dm = days_in_month[month];
301 if ((month == 2) && leap_year(year)) {
302 ++dm;
303 }
304
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000305 do {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000306 days[dw++] = day++;
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000307 } while (--dm);
Eric Andersenc98c0622001-12-06 15:16:43 +0000308}
309
Manuel Novoa III cad53642003-03-19 09:13:01 +0000310static void trim_trailing_spaces_and_print(char *s)
Eric Andersenc98c0622001-12-06 15:16:43 +0000311{
Manuel Novoa III cad53642003-03-19 09:13:01 +0000312 char *p = s;
Eric Andersenc98c0622001-12-06 15:16:43 +0000313
Manuel Novoa III cad53642003-03-19 09:13:01 +0000314 while (*p) {
Eric Andersenc98c0622001-12-06 15:16:43 +0000315 ++p;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000316 }
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000317 while (p != s) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000318 --p;
Denys Vlasenkoc0dab372009-10-22 22:28:08 +0200319 if (!isspace(*p)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000320 p[1] = '\0';
321 break;
322 }
323 }
324
325 puts(s);
Eric Andersenc98c0622001-12-06 15:16:43 +0000326}
327
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000328static void center(char *str, unsigned len, unsigned separate)
Eric Andersenc98c0622001-12-06 15:16:43 +0000329{
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000330 unsigned n = strlen(str);
Manuel Novoa III cad53642003-03-19 09:13:01 +0000331 len -= n;
Denis Vlasenkof0ed3762006-10-26 23:21:47 +0000332 printf("%*s%*s", (len/2) + n, str, (len/2) + (len % 2) + separate, "");
Eric Andersenc98c0622001-12-06 15:16:43 +0000333}
334
Manuel Novoa III cad53642003-03-19 09:13:01 +0000335static void blank_string(char *buf, size_t buflen)
336{
337 memset(buf, ' ', buflen);
338 buf[buflen-1] = '\0';
339}
340
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000341static char *build_row(char *p, unsigned *dp)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000342{
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000343 unsigned col, val, day;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000344
Manuel Novoa III cad53642003-03-19 09:13:01 +0000345 memset(p, ' ', (julian + DAY_LEN) * 7);
346
347 col = 0;
348 do {
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000349 day = *dp++;
350 if (day != SPACE) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000351 if (julian) {
Manuel Novoa III 5b3c0562003-08-13 12:11:33 +0000352 ++p;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000353 if (day >= 100) {
354 *p = '0';
355 p[-1] = (day / 100) + '0';
356 day %= 100;
357 }
358 }
Denis Vlasenko661f6fa2007-07-26 11:12:51 +0000359 val = day / 10;
360 if (val > 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000361 *p = val + '0';
362 }
363 *++p = day % 10 + '0';
364 p += 2;
365 } else {
366 p += DAY_LEN + julian;
367 }
368 } while (++col < 7);
369
370 return p;
371}
Eric Andersenc98c0622001-12-06 15:16:43 +0000372
373/*
374 * Copyright (c) 1989, 1993, 1994
375 * The Regents of the University of California. All rights reserved.
376 *
377 * This code is derived from software contributed to Berkeley by
378 * Kim Letkeman.
379 *
380 * Redistribution and use in source and binary forms, with or without
381 * modification, are permitted provided that the following conditions
382 * are met:
383 * 1. Redistributions of source code must retain the above copyright
384 * notice, this list of conditions and the following disclaimer.
385 * 2. Redistributions in binary form must reproduce the above copyright
386 * notice, this list of conditions and the following disclaimer in the
387 * documentation and/or other materials provided with the distribution.
Aaron Lehmann69d41782002-06-23 22:25:24 +0000388 * 3. Neither the name of the University nor the names of its contributors
Eric Andersenc98c0622001-12-06 15:16:43 +0000389 * may be used to endorse or promote products derived from this software
390 * without specific prior written permission.
391 *
Denys Vlasenko95f79532017-08-02 14:26:33 +0200392 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
Eric Andersenc98c0622001-12-06 15:16:43 +0000393 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
394 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
395 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
396 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
397 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
398 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
399 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
400 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
401 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
402 * SUCH DAMAGE.
403 */