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