Annotation of src/usr.bin/cal/cal.c, Revision 1.1
1.1 ! deraadt 1: /* $NetBSD: cal.c,v 1.6 1995/03/26 03:10:24 glass Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1989, 1993, 1994
! 5: * The Regents of the University of California. All rights reserved.
! 6: *
! 7: * This code is derived from software contributed to Berkeley by
! 8: * Kim Letkeman.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: * 3. All advertising materials mentioning features or use of this software
! 19: * must display the following acknowledgement:
! 20: * This product includes software developed by the University of
! 21: * California, Berkeley and its contributors.
! 22: * 4. Neither the name of the University nor the names of its contributors
! 23: * may be used to endorse or promote products derived from this software
! 24: * without specific prior written permission.
! 25: *
! 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 36: * SUCH DAMAGE.
! 37: */
! 38:
! 39: #ifndef lint
! 40: static char copyright[] =
! 41: "@(#) Copyright (c) 1989, 1993, 1994\n\
! 42: The Regents of the University of California. All rights reserved.\n";
! 43: #endif /* not lint */
! 44:
! 45: #ifndef lint
! 46: #if 0
! 47: static char sccsid[] = "@(#)cal.c 8.4 (Berkeley) 4/2/94";
! 48: #else
! 49: static char rcsid[] = "$NetBSD: cal.c,v 1.6 1995/03/26 03:10:24 glass Exp $";
! 50: #endif
! 51: #endif /* not lint */
! 52:
! 53: #include <sys/types.h>
! 54:
! 55: #include <ctype.h>
! 56: #include <err.h>
! 57: #include <stdio.h>
! 58: #include <stdlib.h>
! 59: #include <string.h>
! 60: #include <time.h>
! 61: #include <unistd.h>
! 62:
! 63: #define THURSDAY 4 /* for reformation */
! 64: #define SATURDAY 6 /* 1 Jan 1 was a Saturday */
! 65:
! 66: #define FIRST_MISSING_DAY 639799 /* 3 Sep 1752 */
! 67: #define NUMBER_MISSING_DAYS 11 /* 11 day correction */
! 68:
! 69: #define MAXDAYS 42 /* max slots in a month array */
! 70: #define SPACE -1 /* used in day array */
! 71:
! 72: static int days_in_month[2][13] = {
! 73: {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
! 74: {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
! 75: };
! 76:
! 77: int sep1752[MAXDAYS] = {
! 78: SPACE, SPACE, 1, 2, 14, 15, 16,
! 79: 17, 18, 19, 20, 21, 22, 23,
! 80: 24, 25, 26, 27, 28, 29, 30,
! 81: SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
! 82: SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
! 83: SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
! 84: }, j_sep1752[MAXDAYS] = {
! 85: SPACE, SPACE, 245, 246, 258, 259, 260,
! 86: 261, 262, 263, 264, 265, 266, 267,
! 87: 268, 269, 270, 271, 272, 273, 274,
! 88: SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
! 89: SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
! 90: SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
! 91: }, empty[MAXDAYS] = {
! 92: SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
! 93: SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
! 94: SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
! 95: SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
! 96: SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
! 97: SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
! 98: };
! 99:
! 100: char *month_names[12] = {
! 101: "January", "February", "March", "April", "May", "June",
! 102: "July", "August", "September", "October", "November", "December",
! 103: };
! 104:
! 105: char *day_headings = " S M Tu W Th F S";
! 106: char *j_day_headings = " S M Tu W Th F S";
! 107:
! 108: /* leap year -- account for gregorian reformation in 1752 */
! 109: #define leap_year(yr) \
! 110: ((yr) <= 1752 ? !((yr) % 4) : \
! 111: !((yr) % 4) && ((yr) % 100) || !((yr) % 400))
! 112:
! 113: /* number of centuries since 1700, not inclusive */
! 114: #define centuries_since_1700(yr) \
! 115: ((yr) > 1700 ? (yr) / 100 - 17 : 0)
! 116:
! 117: /* number of centuries since 1700 whose modulo of 400 is 0 */
! 118: #define quad_centuries_since_1700(yr) \
! 119: ((yr) > 1600 ? ((yr) - 1600) / 400 : 0)
! 120:
! 121: /* number of leap years between year 1 and this year, not inclusive */
! 122: #define leap_years_since_year_1(yr) \
! 123: ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
! 124:
! 125: int julian;
! 126:
! 127: void ascii_day __P((char *, int));
! 128: void center __P((char *, int, int));
! 129: void day_array __P((int, int, int *));
! 130: int day_in_week __P((int, int, int));
! 131: int day_in_year __P((int, int, int));
! 132: void j_yearly __P((int));
! 133: void monthly __P((int, int));
! 134: void trim_trailing_spaces __P((char *));
! 135: void usage __P((void));
! 136: void yearly __P((int));
! 137:
! 138: int
! 139: main(argc, argv)
! 140: int argc;
! 141: char **argv;
! 142: {
! 143: struct tm *local_time;
! 144: time_t now;
! 145: int ch, month, year, yflag;
! 146:
! 147: yflag = 0;
! 148: while ((ch = getopt(argc, argv, "jy")) != EOF)
! 149: switch(ch) {
! 150: case 'j':
! 151: julian = 1;
! 152: break;
! 153: case 'y':
! 154: yflag = 1;
! 155: break;
! 156: case '?':
! 157: default:
! 158: usage();
! 159: }
! 160: argc -= optind;
! 161: argv += optind;
! 162:
! 163: month = 0;
! 164: switch(argc) {
! 165: case 2:
! 166: if ((month = atoi(*argv++)) < 1 || month > 12)
! 167: errx(1, "illegal month value: use 1-12");
! 168: /* FALLTHROUGH */
! 169: case 1:
! 170: if ((year = atoi(*argv)) < 1 || year > 9999)
! 171: errx(1, "illegal year value: use 1-9999");
! 172: break;
! 173: case 0:
! 174: (void)time(&now);
! 175: local_time = localtime(&now);
! 176: year = local_time->tm_year + 1900;
! 177: if (!yflag)
! 178: month = local_time->tm_mon + 1;
! 179: break;
! 180: default:
! 181: usage();
! 182: }
! 183:
! 184: if (month)
! 185: monthly(month, year);
! 186: else if (julian)
! 187: j_yearly(year);
! 188: else
! 189: yearly(year);
! 190: exit(0);
! 191: }
! 192:
! 193: #define DAY_LEN 3 /* 3 spaces per day */
! 194: #define J_DAY_LEN 4 /* 4 spaces per day */
! 195: #define WEEK_LEN 20 /* 7 * 3 - one space at the end */
! 196: #define J_WEEK_LEN 27 /* 7 * 4 - one space at the end */
! 197: #define HEAD_SEP 2 /* spaces between day headings */
! 198: #define J_HEAD_SEP 2
! 199:
! 200: void
! 201: monthly(month, year)
! 202: int month, year;
! 203: {
! 204: int col, row, len, days[MAXDAYS];
! 205: char *p, lineout[30];
! 206:
! 207: day_array(month, year, days);
! 208: len = sprintf(lineout, "%s %d", month_names[month - 1], year);
! 209: (void)printf("%*s%s\n%s\n",
! 210: ((julian ? J_WEEK_LEN : WEEK_LEN) - len) / 2, "",
! 211: lineout, julian ? j_day_headings : day_headings);
! 212: for (row = 0; row < 6; row++) {
! 213: for (col = 0, p = lineout; col < 7; col++,
! 214: p += julian ? J_DAY_LEN : DAY_LEN)
! 215: ascii_day(p, days[row * 7 + col]);
! 216: *p = '\0';
! 217: trim_trailing_spaces(lineout);
! 218: (void)printf("%s\n", lineout);
! 219: }
! 220: }
! 221:
! 222: void
! 223: j_yearly(year)
! 224: int year;
! 225: {
! 226: int col, *dp, i, month, row, which_cal;
! 227: int days[12][MAXDAYS];
! 228: char *p, lineout[80];
! 229:
! 230: (void)sprintf(lineout, "%d", year);
! 231: center(lineout, J_WEEK_LEN * 2 + J_HEAD_SEP, 0);
! 232: (void)printf("\n\n");
! 233: for (i = 0; i < 12; i++)
! 234: day_array(i + 1, year, days[i]);
! 235: (void)memset(lineout, ' ', sizeof(lineout) - 1);
! 236: lineout[sizeof(lineout) - 1] = '\0';
! 237: for (month = 0; month < 12; month += 2) {
! 238: center(month_names[month], J_WEEK_LEN, J_HEAD_SEP);
! 239: center(month_names[month + 1], J_WEEK_LEN, 0);
! 240: (void)printf("\n%s%*s%s\n", j_day_headings, J_HEAD_SEP, "",
! 241: j_day_headings);
! 242: for (row = 0; row < 6; row++) {
! 243: for (which_cal = 0; which_cal < 2; which_cal++) {
! 244: p = lineout + which_cal * (J_WEEK_LEN + 2);
! 245: dp = &days[month + which_cal][row * 7];
! 246: for (col = 0; col < 7; col++, p += J_DAY_LEN)
! 247: ascii_day(p, *dp++);
! 248: }
! 249: *p = '\0';
! 250: trim_trailing_spaces(lineout);
! 251: (void)printf("%s\n", lineout);
! 252: }
! 253: }
! 254: (void)printf("\n");
! 255: }
! 256:
! 257: void
! 258: yearly(year)
! 259: int year;
! 260: {
! 261: int col, *dp, i, month, row, which_cal;
! 262: int days[12][MAXDAYS];
! 263: char *p, lineout[80];
! 264:
! 265: (void)sprintf(lineout, "%d", year);
! 266: center(lineout, WEEK_LEN * 3 + HEAD_SEP * 2, 0);
! 267: (void)printf("\n\n");
! 268: for (i = 0; i < 12; i++)
! 269: day_array(i + 1, year, days[i]);
! 270: (void)memset(lineout, ' ', sizeof(lineout) - 1);
! 271: lineout[sizeof(lineout) - 1] = '\0';
! 272: for (month = 0; month < 12; month += 3) {
! 273: center(month_names[month], WEEK_LEN, HEAD_SEP);
! 274: center(month_names[month + 1], WEEK_LEN, HEAD_SEP);
! 275: center(month_names[month + 2], WEEK_LEN, 0);
! 276: (void)printf("\n%s%*s%s%*s%s\n", day_headings, HEAD_SEP,
! 277: "", day_headings, HEAD_SEP, "", day_headings);
! 278: for (row = 0; row < 6; row++) {
! 279: for (which_cal = 0; which_cal < 3; which_cal++) {
! 280: p = lineout + which_cal * (WEEK_LEN + 2);
! 281: dp = &days[month + which_cal][row * 7];
! 282: for (col = 0; col < 7; col++, p += DAY_LEN)
! 283: ascii_day(p, *dp++);
! 284: }
! 285: *p = '\0';
! 286: trim_trailing_spaces(lineout);
! 287: (void)printf("%s\n", lineout);
! 288: }
! 289: }
! 290: (void)printf("\n");
! 291: }
! 292:
! 293: /*
! 294: * day_array --
! 295: * Fill in an array of 42 integers with a calendar. Assume for a moment
! 296: * that you took the (maximum) 6 rows in a calendar and stretched them
! 297: * out end to end. You would have 42 numbers or spaces. This routine
! 298: * builds that array for any month from Jan. 1 through Dec. 9999.
! 299: */
! 300: void
! 301: day_array(month, year, days)
! 302: int month, year;
! 303: int *days;
! 304: {
! 305: int day, dw, dm;
! 306:
! 307: if (month == 9 && year == 1752) {
! 308: memmove(days,
! 309: julian ? j_sep1752 : sep1752, MAXDAYS * sizeof(int));
! 310: return;
! 311: }
! 312: memmove(days, empty, MAXDAYS * sizeof(int));
! 313: dm = days_in_month[leap_year(year)][month];
! 314: dw = day_in_week(1, month, year);
! 315: day = julian ? day_in_year(1, month, year) : 1;
! 316: while (dm--)
! 317: days[dw++] = day++;
! 318: }
! 319:
! 320: /*
! 321: * day_in_year --
! 322: * return the 1 based day number within the year
! 323: */
! 324: int
! 325: day_in_year(day, month, year)
! 326: int day, month, year;
! 327: {
! 328: int i, leap;
! 329:
! 330: leap = leap_year(year);
! 331: for (i = 1; i < month; i++)
! 332: day += days_in_month[leap][i];
! 333: return (day);
! 334: }
! 335:
! 336: /*
! 337: * day_in_week
! 338: * return the 0 based day number for any date from 1 Jan. 1 to
! 339: * 31 Dec. 9999. Assumes the Gregorian reformation eliminates
! 340: * 3 Sep. 1752 through 13 Sep. 1752. Returns Thursday for all
! 341: * missing days.
! 342: */
! 343: int
! 344: day_in_week(day, month, year)
! 345: int day, month, year;
! 346: {
! 347: long temp;
! 348:
! 349: temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1)
! 350: + day_in_year(day, month, year);
! 351: if (temp < FIRST_MISSING_DAY)
! 352: return ((temp - 1 + SATURDAY) % 7);
! 353: if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS))
! 354: return (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
! 355: return (THURSDAY);
! 356: }
! 357:
! 358: void
! 359: ascii_day(p, day)
! 360: char *p;
! 361: int day;
! 362: {
! 363: int display, val;
! 364: static char *aday[] = {
! 365: "",
! 366: " 1", " 2", " 3", " 4", " 5", " 6", " 7",
! 367: " 8", " 9", "10", "11", "12", "13", "14",
! 368: "15", "16", "17", "18", "19", "20", "21",
! 369: "22", "23", "24", "25", "26", "27", "28",
! 370: "29", "30", "31",
! 371: };
! 372:
! 373: if (day == SPACE) {
! 374: memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN);
! 375: return;
! 376: }
! 377: if (julian) {
! 378: if (val = day / 100) {
! 379: day %= 100;
! 380: *p++ = val + '0';
! 381: display = 1;
! 382: } else {
! 383: *p++ = ' ';
! 384: display = 0;
! 385: }
! 386: val = day / 10;
! 387: if (val || display)
! 388: *p++ = val + '0';
! 389: else
! 390: *p++ = ' ';
! 391: *p++ = day % 10 + '0';
! 392: } else {
! 393: *p++ = aday[day][0];
! 394: *p++ = aday[day][1];
! 395: }
! 396: *p = ' ';
! 397: }
! 398:
! 399: void
! 400: trim_trailing_spaces(s)
! 401: char *s;
! 402: {
! 403: char *p;
! 404:
! 405: for (p = s; *p; ++p)
! 406: continue;
! 407: while (p > s && isspace(*--p))
! 408: continue;
! 409: if (p > s)
! 410: ++p;
! 411: *p = '\0';
! 412: }
! 413:
! 414: void
! 415: center(str, len, separate)
! 416: char *str;
! 417: int len;
! 418: int separate;
! 419: {
! 420:
! 421: len -= strlen(str);
! 422: (void)printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, "");
! 423: if (separate)
! 424: (void)printf("%*s", separate, "");
! 425: }
! 426:
! 427: void
! 428: usage()
! 429: {
! 430:
! 431: (void)fprintf(stderr, "usage: cal [-jy] [[month] year]\n");
! 432: exit(1);
! 433: }