cal.c revision 1.15 1 1.15 atatat /* $NetBSD: cal.c,v 1.15 2003/06/05 00:21:20 atatat Exp $ */
2 1.6 glass
3 1.1 cgd /*
4 1.6 glass * Copyright (c) 1989, 1993, 1994
5 1.6 glass * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * This code is derived from software contributed to Berkeley by
8 1.1 cgd * Kim Letkeman.
9 1.1 cgd *
10 1.1 cgd * Redistribution and use in source and binary forms, with or without
11 1.1 cgd * modification, are permitted provided that the following conditions
12 1.1 cgd * are met:
13 1.1 cgd * 1. Redistributions of source code must retain the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer.
15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 cgd * notice, this list of conditions and the following disclaimer in the
17 1.1 cgd * documentation and/or other materials provided with the distribution.
18 1.1 cgd * 3. All advertising materials mentioning features or use of this software
19 1.1 cgd * must display the following acknowledgement:
20 1.1 cgd * This product includes software developed by the University of
21 1.1 cgd * California, Berkeley and its contributors.
22 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
23 1.1 cgd * may be used to endorse or promote products derived from this software
24 1.1 cgd * without specific prior written permission.
25 1.1 cgd *
26 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 1.1 cgd * SUCH DAMAGE.
37 1.1 cgd */
38 1.1 cgd
39 1.7 lukem #include <sys/cdefs.h>
40 1.1 cgd #ifndef lint
41 1.7 lukem __COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\n\
42 1.7 lukem The Regents of the University of California. All rights reserved.\n");
43 1.1 cgd #endif /* not lint */
44 1.1 cgd
45 1.1 cgd #ifndef lint
46 1.6 glass #if 0
47 1.6 glass static char sccsid[] = "@(#)cal.c 8.4 (Berkeley) 4/2/94";
48 1.6 glass #else
49 1.15 atatat __RCSID("$NetBSD: cal.c,v 1.15 2003/06/05 00:21:20 atatat Exp $");
50 1.6 glass #endif
51 1.1 cgd #endif /* not lint */
52 1.1 cgd
53 1.1 cgd #include <sys/types.h>
54 1.6 glass
55 1.6 glass #include <ctype.h>
56 1.6 glass #include <err.h>
57 1.14 yamt #include <errno.h>
58 1.14 yamt #include <limits.h>
59 1.1 cgd #include <stdio.h>
60 1.6 glass #include <stdlib.h>
61 1.4 cgd #include <string.h>
62 1.15 atatat #include <termcap.h>
63 1.6 glass #include <time.h>
64 1.8 christos #include <tzfile.h>
65 1.6 glass #include <unistd.h>
66 1.1 cgd
67 1.1 cgd #define THURSDAY 4 /* for reformation */
68 1.1 cgd #define SATURDAY 6 /* 1 Jan 1 was a Saturday */
69 1.1 cgd
70 1.5 ws #define FIRST_MISSING_DAY 639799 /* 3 Sep 1752 */
71 1.1 cgd #define NUMBER_MISSING_DAYS 11 /* 11 day correction */
72 1.1 cgd
73 1.1 cgd #define MAXDAYS 42 /* max slots in a month array */
74 1.1 cgd #define SPACE -1 /* used in day array */
75 1.1 cgd
76 1.1 cgd static int days_in_month[2][13] = {
77 1.1 cgd {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
78 1.1 cgd {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
79 1.1 cgd };
80 1.1 cgd
81 1.1 cgd int sep1752[MAXDAYS] = {
82 1.1 cgd SPACE, SPACE, 1, 2, 14, 15, 16,
83 1.1 cgd 17, 18, 19, 20, 21, 22, 23,
84 1.1 cgd 24, 25, 26, 27, 28, 29, 30,
85 1.1 cgd SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
86 1.1 cgd SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
87 1.1 cgd SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
88 1.1 cgd }, j_sep1752[MAXDAYS] = {
89 1.1 cgd SPACE, SPACE, 245, 246, 258, 259, 260,
90 1.1 cgd 261, 262, 263, 264, 265, 266, 267,
91 1.1 cgd 268, 269, 270, 271, 272, 273, 274,
92 1.1 cgd SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
93 1.1 cgd SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
94 1.1 cgd SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
95 1.1 cgd }, empty[MAXDAYS] = {
96 1.1 cgd SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
97 1.1 cgd SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
98 1.1 cgd SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
99 1.1 cgd SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
100 1.1 cgd SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
101 1.1 cgd SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
102 1.1 cgd };
103 1.1 cgd
104 1.1 cgd char *month_names[12] = {
105 1.1 cgd "January", "February", "March", "April", "May", "June",
106 1.1 cgd "July", "August", "September", "October", "November", "December",
107 1.1 cgd };
108 1.1 cgd
109 1.1 cgd char *day_headings = " S M Tu W Th F S";
110 1.1 cgd char *j_day_headings = " S M Tu W Th F S";
111 1.1 cgd
112 1.1 cgd /* leap year -- account for gregorian reformation in 1752 */
113 1.1 cgd #define leap_year(yr) \
114 1.1 cgd ((yr) <= 1752 ? !((yr) % 4) : \
115 1.9 ws (!((yr) % 4) && ((yr) % 100)) || !((yr) % 400))
116 1.1 cgd
117 1.1 cgd /* number of centuries since 1700, not inclusive */
118 1.1 cgd #define centuries_since_1700(yr) \
119 1.1 cgd ((yr) > 1700 ? (yr) / 100 - 17 : 0)
120 1.1 cgd
121 1.1 cgd /* number of centuries since 1700 whose modulo of 400 is 0 */
122 1.1 cgd #define quad_centuries_since_1700(yr) \
123 1.1 cgd ((yr) > 1600 ? ((yr) - 1600) / 400 : 0)
124 1.1 cgd
125 1.1 cgd /* number of leap years between year 1 and this year, not inclusive */
126 1.1 cgd #define leap_years_since_year_1(yr) \
127 1.1 cgd ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
128 1.1 cgd
129 1.1 cgd int julian;
130 1.15 atatat int hilite;
131 1.15 atatat char *md, *me;
132 1.1 cgd
133 1.15 atatat void init_hilite(void);
134 1.14 yamt int getnum(const char *);
135 1.15 atatat int ascii_day(char *, int);
136 1.12 perry void center(char *, int, int);
137 1.12 perry void day_array(int, int, int *);
138 1.12 perry int day_in_week(int, int, int);
139 1.12 perry int day_in_year(int, int, int);
140 1.14 yamt void monthrange(int, int, int, int, int);
141 1.12 perry int main(int, char **);
142 1.12 perry void trim_trailing_spaces(char *);
143 1.12 perry void usage(void);
144 1.6 glass
145 1.6 glass int
146 1.12 perry main(int argc, char **argv)
147 1.1 cgd {
148 1.1 cgd struct tm *local_time;
149 1.6 glass time_t now;
150 1.14 yamt int ch, month, year, yflag;
151 1.14 yamt int before, after;
152 1.14 yamt int yearly = 0;
153 1.1 cgd
154 1.14 yamt before = after = 0;
155 1.7 lukem yflag = year = 0;
156 1.15 atatat while ((ch = getopt(argc, argv, "A:B:hjy3")) != -1) {
157 1.12 perry switch (ch) {
158 1.14 yamt case 'A':
159 1.14 yamt after = getnum(optarg);
160 1.14 yamt break;
161 1.14 yamt case 'B':
162 1.14 yamt before = getnum(optarg);
163 1.14 yamt break;
164 1.15 atatat case 'h':
165 1.15 atatat init_hilite();
166 1.15 atatat break;
167 1.1 cgd case 'j':
168 1.1 cgd julian = 1;
169 1.1 cgd break;
170 1.1 cgd case 'y':
171 1.1 cgd yflag = 1;
172 1.1 cgd break;
173 1.13 perry case '3':
174 1.14 yamt before = after = 1;
175 1.13 perry break;
176 1.1 cgd case '?':
177 1.1 cgd default:
178 1.1 cgd usage();
179 1.12 perry /* NOTREACHED */
180 1.1 cgd }
181 1.12 perry }
182 1.13 perry
183 1.1 cgd argc -= optind;
184 1.1 cgd argv += optind;
185 1.1 cgd
186 1.1 cgd month = 0;
187 1.12 perry switch (argc) {
188 1.1 cgd case 2:
189 1.6 glass if ((month = atoi(*argv++)) < 1 || month > 12)
190 1.6 glass errx(1, "illegal month value: use 1-12");
191 1.1 cgd /* FALLTHROUGH */
192 1.1 cgd case 1:
193 1.6 glass if ((year = atoi(*argv)) < 1 || year > 9999)
194 1.6 glass errx(1, "illegal year value: use 1-9999");
195 1.1 cgd break;
196 1.1 cgd case 0:
197 1.1 cgd (void)time(&now);
198 1.1 cgd local_time = localtime(&now);
199 1.8 christos year = local_time->tm_year + TM_YEAR_BASE;
200 1.1 cgd if (!yflag)
201 1.1 cgd month = local_time->tm_mon + 1;
202 1.1 cgd break;
203 1.1 cgd default:
204 1.1 cgd usage();
205 1.1 cgd }
206 1.1 cgd
207 1.14 yamt if (!month) {
208 1.14 yamt /* yearly */
209 1.14 yamt month = 1;
210 1.14 yamt before = 0;
211 1.14 yamt after = 11;
212 1.14 yamt yearly = 1;
213 1.14 yamt }
214 1.14 yamt
215 1.14 yamt monthrange(month, year, before, after, yearly);
216 1.13 perry
217 1.1 cgd exit(0);
218 1.1 cgd }
219 1.1 cgd
220 1.1 cgd #define DAY_LEN 3 /* 3 spaces per day */
221 1.1 cgd #define J_DAY_LEN 4 /* 4 spaces per day */
222 1.1 cgd #define WEEK_LEN 20 /* 7 * 3 - one space at the end */
223 1.1 cgd #define J_WEEK_LEN 27 /* 7 * 4 - one space at the end */
224 1.1 cgd #define HEAD_SEP 2 /* spaces between day headings */
225 1.1 cgd #define J_HEAD_SEP 2
226 1.14 yamt #define MONTH_PER_ROW 3 /* how many monthes in a row */
227 1.14 yamt #define J_MONTH_PER_ROW 2
228 1.1 cgd
229 1.6 glass void
230 1.14 yamt monthrange(int month, int year, int before, int after, int yearly)
231 1.1 cgd {
232 1.14 yamt int startmonth, startyear;
233 1.14 yamt int endmonth, endyear;
234 1.14 yamt int i, row;
235 1.14 yamt int days[3][MAXDAYS];
236 1.15 atatat char lineout[256];
237 1.14 yamt int inayear;
238 1.14 yamt int newyear;
239 1.14 yamt int day_len, week_len, head_sep;
240 1.14 yamt int month_per_row;
241 1.15 atatat int skip, r_off, w_off;
242 1.14 yamt
243 1.14 yamt if (julian) {
244 1.14 yamt day_len = J_DAY_LEN;
245 1.14 yamt week_len = J_WEEK_LEN;
246 1.14 yamt head_sep = J_HEAD_SEP;
247 1.14 yamt month_per_row = J_MONTH_PER_ROW;
248 1.14 yamt }
249 1.14 yamt else {
250 1.14 yamt day_len = DAY_LEN;
251 1.14 yamt week_len = WEEK_LEN;
252 1.14 yamt head_sep = HEAD_SEP;
253 1.14 yamt month_per_row = MONTH_PER_ROW;
254 1.14 yamt }
255 1.14 yamt
256 1.14 yamt month--;
257 1.14 yamt
258 1.14 yamt startyear = year - (before + 12 - 1 - month) / 12;
259 1.14 yamt startmonth = 12 - 1 - ((before + 12 - 1 - month) % 12);
260 1.14 yamt endyear = year + (month + after) / 12;
261 1.14 yamt endmonth = (month + after) % 12;
262 1.1 cgd
263 1.14 yamt if (startyear < 0 || endyear > 9999) {
264 1.14 yamt errx(1, "year should be in 1-9999\n");
265 1.1 cgd }
266 1.1 cgd
267 1.14 yamt year = startyear;
268 1.14 yamt month = startmonth;
269 1.14 yamt inayear = newyear = (year != endyear || yearly);
270 1.14 yamt if (inayear) {
271 1.14 yamt skip = month % month_per_row;
272 1.14 yamt month -= skip;
273 1.14 yamt }
274 1.14 yamt else {
275 1.14 yamt skip = 0;
276 1.14 yamt }
277 1.14 yamt
278 1.14 yamt do {
279 1.14 yamt if (newyear) {
280 1.14 yamt (void)snprintf(lineout, sizeof(lineout), "%d", year);
281 1.14 yamt center(lineout, week_len * month_per_row +
282 1.14 yamt head_sep * (month_per_row - 1), 0);
283 1.14 yamt (void)printf("\n\n");
284 1.14 yamt newyear = 0;
285 1.14 yamt }
286 1.14 yamt
287 1.14 yamt for (i = 0; i < skip; i++)
288 1.14 yamt center("", week_len, head_sep);
289 1.14 yamt
290 1.14 yamt for (; i < month_per_row; i++) {
291 1.14 yamt int sep;
292 1.14 yamt
293 1.14 yamt if (year == endyear && month + i > endmonth)
294 1.14 yamt break;
295 1.14 yamt
296 1.14 yamt sep = (i == month_per_row - 1) ? 0 : head_sep;
297 1.14 yamt day_array(month + i + 1, year, days[i]);
298 1.14 yamt if (inayear) {
299 1.14 yamt center(month_names[month + i], week_len, sep);
300 1.14 yamt }
301 1.14 yamt else {
302 1.14 yamt snprintf(lineout, sizeof(lineout), "%s %d",
303 1.14 yamt month_names[month + i], year);
304 1.14 yamt center(lineout, week_len, sep);
305 1.1 cgd }
306 1.1 cgd }
307 1.14 yamt printf("\n");
308 1.14 yamt
309 1.14 yamt for (i = 0; i < skip; i++)
310 1.14 yamt center("", week_len, head_sep);
311 1.14 yamt
312 1.14 yamt for (; i < month_per_row; i++) {
313 1.14 yamt int sep;
314 1.14 yamt
315 1.14 yamt if (year == endyear && month + i > endmonth)
316 1.14 yamt break;
317 1.14 yamt
318 1.14 yamt sep = (i == month_per_row - 1) ? 0 : head_sep;
319 1.14 yamt printf("%s%*s",
320 1.14 yamt (julian) ? j_day_headings : day_headings, sep, "");
321 1.14 yamt }
322 1.14 yamt printf("\n");
323 1.1 cgd
324 1.14 yamt memset(lineout, ' ', sizeof(lineout));
325 1.1 cgd for (row = 0; row < 6; row++) {
326 1.14 yamt char *p;
327 1.14 yamt for (i = 0; i < skip; i++) {
328 1.15 atatat p = lineout + i * (week_len + 2) + w_off;
329 1.14 yamt memset(p, ' ', week_len);
330 1.14 yamt }
331 1.15 atatat w_off = 0;
332 1.14 yamt for (; i < month_per_row; i++) {
333 1.14 yamt int col, *dp;
334 1.14 yamt
335 1.14 yamt if (year == endyear && month + i > endmonth)
336 1.14 yamt break;
337 1.14 yamt
338 1.15 atatat p = lineout + i * (week_len + 2) + w_off;
339 1.14 yamt dp = &days[i][row * 7];
340 1.15 atatat for (col = 0; col < 7;
341 1.15 atatat col++, p += day_len + r_off) {
342 1.15 atatat r_off = ascii_day(p, *dp++);
343 1.15 atatat w_off += r_off;
344 1.15 atatat }
345 1.1 cgd }
346 1.3 cgd *p = '\0';
347 1.1 cgd trim_trailing_spaces(lineout);
348 1.1 cgd (void)printf("%s\n", lineout);
349 1.1 cgd }
350 1.13 perry
351 1.14 yamt skip = 0;
352 1.14 yamt month += month_per_row;
353 1.14 yamt if (month >= 12) {
354 1.14 yamt month -= 12;
355 1.14 yamt year++;
356 1.14 yamt newyear = 1;
357 1.13 perry }
358 1.14 yamt } while (year < endyear || (year == endyear && month <= endmonth));
359 1.13 perry }
360 1.13 perry
361 1.1 cgd /*
362 1.1 cgd * day_array --
363 1.1 cgd * Fill in an array of 42 integers with a calendar. Assume for a moment
364 1.1 cgd * that you took the (maximum) 6 rows in a calendar and stretched them
365 1.1 cgd * out end to end. You would have 42 numbers or spaces. This routine
366 1.1 cgd * builds that array for any month from Jan. 1 through Dec. 9999.
367 1.1 cgd */
368 1.6 glass void
369 1.12 perry day_array(int month, int year, int *days)
370 1.1 cgd {
371 1.6 glass int day, dw, dm;
372 1.15 atatat time_t t;
373 1.15 atatat struct tm *tm;
374 1.15 atatat
375 1.15 atatat t = time(NULL);
376 1.15 atatat tm = localtime(&t);
377 1.15 atatat tm->tm_year += TM_YEAR_BASE;
378 1.15 atatat tm->tm_mon++;
379 1.15 atatat tm->tm_yday++; /* jan 1 is 1 for us, not 0 */
380 1.1 cgd
381 1.1 cgd if (month == 9 && year == 1752) {
382 1.6 glass memmove(days,
383 1.6 glass julian ? j_sep1752 : sep1752, MAXDAYS * sizeof(int));
384 1.1 cgd return;
385 1.1 cgd }
386 1.6 glass memmove(days, empty, MAXDAYS * sizeof(int));
387 1.1 cgd dm = days_in_month[leap_year(year)][month];
388 1.1 cgd dw = day_in_week(1, month, year);
389 1.1 cgd day = julian ? day_in_year(1, month, year) : 1;
390 1.15 atatat while (dm--) {
391 1.15 atatat if (hilite && year == tm->tm_year &&
392 1.15 atatat (julian ? (day == tm->tm_yday) :
393 1.15 atatat (month == tm->tm_mon && day == tm->tm_mday)))
394 1.15 atatat days[dw++] = -1 - day++;
395 1.15 atatat else
396 1.15 atatat days[dw++] = day++;
397 1.15 atatat }
398 1.1 cgd }
399 1.1 cgd
400 1.1 cgd /*
401 1.1 cgd * day_in_year --
402 1.1 cgd * return the 1 based day number within the year
403 1.1 cgd */
404 1.6 glass int
405 1.12 perry day_in_year(int day, int month, int year)
406 1.1 cgd {
407 1.6 glass int i, leap;
408 1.1 cgd
409 1.1 cgd leap = leap_year(year);
410 1.1 cgd for (i = 1; i < month; i++)
411 1.1 cgd day += days_in_month[leap][i];
412 1.6 glass return (day);
413 1.1 cgd }
414 1.1 cgd
415 1.1 cgd /*
416 1.1 cgd * day_in_week
417 1.1 cgd * return the 0 based day number for any date from 1 Jan. 1 to
418 1.1 cgd * 31 Dec. 9999. Assumes the Gregorian reformation eliminates
419 1.1 cgd * 3 Sep. 1752 through 13 Sep. 1752. Returns Thursday for all
420 1.1 cgd * missing days.
421 1.1 cgd */
422 1.6 glass int
423 1.12 perry day_in_week(int day, int month, int year)
424 1.1 cgd {
425 1.1 cgd long temp;
426 1.1 cgd
427 1.1 cgd temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1)
428 1.1 cgd + day_in_year(day, month, year);
429 1.1 cgd if (temp < FIRST_MISSING_DAY)
430 1.6 glass return ((temp - 1 + SATURDAY) % 7);
431 1.1 cgd if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS))
432 1.6 glass return (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
433 1.6 glass return (THURSDAY);
434 1.1 cgd }
435 1.1 cgd
436 1.15 atatat int
437 1.12 perry ascii_day(char *p, int day)
438 1.1 cgd {
439 1.15 atatat int display, val, rc;
440 1.15 atatat char *b;
441 1.1 cgd static char *aday[] = {
442 1.1 cgd "",
443 1.1 cgd " 1", " 2", " 3", " 4", " 5", " 6", " 7",
444 1.1 cgd " 8", " 9", "10", "11", "12", "13", "14",
445 1.1 cgd "15", "16", "17", "18", "19", "20", "21",
446 1.1 cgd "22", "23", "24", "25", "26", "27", "28",
447 1.1 cgd "29", "30", "31",
448 1.1 cgd };
449 1.1 cgd
450 1.1 cgd if (day == SPACE) {
451 1.1 cgd memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN);
452 1.15 atatat return (0);
453 1.1 cgd }
454 1.15 atatat if (day < 0) {
455 1.15 atatat b = p;
456 1.15 atatat day = -1 - day;
457 1.15 atatat } else
458 1.15 atatat b = NULL;
459 1.1 cgd if (julian) {
460 1.7 lukem if ((val = day / 100) != 0) {
461 1.1 cgd day %= 100;
462 1.1 cgd *p++ = val + '0';
463 1.1 cgd display = 1;
464 1.1 cgd } else {
465 1.1 cgd *p++ = ' ';
466 1.1 cgd display = 0;
467 1.1 cgd }
468 1.1 cgd val = day / 10;
469 1.1 cgd if (val || display)
470 1.1 cgd *p++ = val + '0';
471 1.1 cgd else
472 1.1 cgd *p++ = ' ';
473 1.1 cgd *p++ = day % 10 + '0';
474 1.1 cgd } else {
475 1.1 cgd *p++ = aday[day][0];
476 1.1 cgd *p++ = aday[day][1];
477 1.1 cgd }
478 1.15 atatat
479 1.15 atatat rc = 0;
480 1.15 atatat if (b != NULL) {
481 1.15 atatat char *t, h[64];
482 1.15 atatat int l;
483 1.15 atatat
484 1.15 atatat l = p - b;
485 1.15 atatat memcpy(h, b, l);
486 1.15 atatat p = b;
487 1.15 atatat
488 1.15 atatat if (md != NULL) {
489 1.15 atatat for (t = md; *t; rc++)
490 1.15 atatat *p++ = *t++;
491 1.15 atatat memcpy(p, h, l);
492 1.15 atatat p += l;
493 1.15 atatat for (t = me; *t; rc++)
494 1.15 atatat *p++ = *t++;
495 1.15 atatat } else {
496 1.15 atatat for (t = &h[0]; l--; t++) {
497 1.15 atatat *p++ = *t;
498 1.15 atatat rc++;
499 1.15 atatat *p++ = '\b';
500 1.15 atatat rc++;
501 1.15 atatat *p++ = *t;
502 1.15 atatat }
503 1.15 atatat }
504 1.15 atatat
505 1.15 atatat }
506 1.15 atatat
507 1.1 cgd *p = ' ';
508 1.15 atatat return (rc);
509 1.1 cgd }
510 1.1 cgd
511 1.6 glass void
512 1.12 perry trim_trailing_spaces(char *s)
513 1.1 cgd {
514 1.6 glass char *p;
515 1.1 cgd
516 1.6 glass for (p = s; *p; ++p)
517 1.6 glass continue;
518 1.11 christos while (p > s && isspace((unsigned char)*--p))
519 1.6 glass continue;
520 1.1 cgd if (p > s)
521 1.1 cgd ++p;
522 1.1 cgd *p = '\0';
523 1.1 cgd }
524 1.1 cgd
525 1.6 glass void
526 1.12 perry center(char *str, int len, int separate)
527 1.1 cgd {
528 1.6 glass
529 1.1 cgd len -= strlen(str);
530 1.1 cgd (void)printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, "");
531 1.1 cgd if (separate)
532 1.1 cgd (void)printf("%*s", separate, "");
533 1.1 cgd }
534 1.1 cgd
535 1.14 yamt int
536 1.14 yamt getnum(const char *p)
537 1.14 yamt {
538 1.14 yamt long result;
539 1.14 yamt char *ep;
540 1.14 yamt
541 1.14 yamt errno = 0;
542 1.14 yamt result = strtoul(p, &ep, 10);
543 1.14 yamt if (p[0] == '\0' || *ep != '\0')
544 1.14 yamt goto error;
545 1.14 yamt if (errno == ERANGE && result == ULONG_MAX)
546 1.14 yamt goto error;
547 1.14 yamt if (result > INT_MAX)
548 1.14 yamt goto error;
549 1.14 yamt
550 1.14 yamt return (int)result;
551 1.14 yamt
552 1.14 yamt error:
553 1.14 yamt errx(1, "bad number: %s", p);
554 1.14 yamt /*NOTREACHED*/
555 1.14 yamt }
556 1.14 yamt
557 1.6 glass void
558 1.15 atatat init_hilite(void)
559 1.15 atatat {
560 1.15 atatat static char control[128];
561 1.15 atatat char cap[1024];
562 1.15 atatat char *tc;
563 1.15 atatat
564 1.15 atatat hilite++;
565 1.15 atatat
566 1.15 atatat if (!isatty(fileno(stdout)))
567 1.15 atatat return;
568 1.15 atatat
569 1.15 atatat tc = getenv("TERM");
570 1.15 atatat if (tc == NULL)
571 1.15 atatat tc = "dumb";
572 1.15 atatat if (tgetent(&cap[0], tc) != 1)
573 1.15 atatat return;
574 1.15 atatat
575 1.15 atatat tc = &control[0];
576 1.15 atatat if ((md = tgetstr(hilite > 1 ? "mr" : "md", &tc)))
577 1.15 atatat *tc++ = '\0';
578 1.15 atatat if ((me = tgetstr("me", &tc)))
579 1.15 atatat *tc++ = '\0';
580 1.15 atatat if (me == NULL || md == NULL)
581 1.15 atatat md = me = NULL;
582 1.15 atatat }
583 1.15 atatat
584 1.15 atatat void
585 1.12 perry usage(void)
586 1.1 cgd {
587 1.6 glass
588 1.14 yamt (void)fprintf(stderr,
589 1.15 atatat "usage: cal [-hjy3] [-B before] [-A after] [[month] year]\n");
590 1.1 cgd exit(1);
591 1.1 cgd }
592