|
|
1.1 ! root 1: /* ! 2: * Print calendar for specified year (and month). ! 3: * Allows month to be numeric or alphabetic. ! 4: */ ! 5: ! 6: #include <stdio.h> ! 7: #include <ctype.h> ! 8: #include <time.h> ! 9: ! 10: #define GREGYEAR 1752 /* Year of start of Gregorian calendar */ ! 11: #define GREGMON SEP /* Month of above */ ! 12: #define GREGDAY 3 /* day of month of changeover */ ! 13: #define GREGADJ 11 /* Adjustment of cal. (days) for Gregorian */ ! 14: /* The calendar skipped 11 days after ! 15: * September 3, 1752 in England. ! 16: * That made the date jump 12 days ! 17: * forward rather than the usual 1. ! 18: * The original Gregorian reform was in ! 19: * 1582, at which time only 10 days were ! 20: * suppressed. France and Russia adopted ! 21: * the Gregorian calendar after 1752. ! 22: * My calculations, which don't make ! 23: * complete sense, suggest that the ! 24: * corrections would be: ! 25: * 12 days after 1800 ! 26: * 13 days after 1900 ! 27: * and 14 days after 2100 ! 28: * because the Gregorian calendar skips ! 29: * leap years which fall on century years ! 30: * unless they are quadracents and not ! 31: * 4000 AD. ! 32: */ ! 33: #define TMYBIAS 1900 /* bias of year field in struct tm */ ! 34: ! 35: char *mnames[] = { ! 36: "January", "February", "March", "April", "May", "June", ! 37: "July", "August", "September", "October", "November", "December" ! 38: }; ! 39: ! 40: /* ! 41: * Days per month array (non-leap). ! 42: * January is at dpm[1]. ! 43: */ ! 44: char dpm[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; ! 45: ! 46: char dayhead[] = " Su Mo Tu We Th Fr Sa"; ! 47: ! 48: #define DAYWIDTH (sizeof dayhead -1) ! 49: #define GAP 5 /* Gap between months */ ! 50: #define CENTRE ((3*DAYWIDTH+2*GAP)/2+2) /* Centred 4 digit year pos. */ ! 51: #define MPL 3 /* Months per line */ ! 52: #define JAN 1 ! 53: #define FEB 2 ! 54: #define MAR 3 ! 55: #define APR 4 ! 56: #define MAY 5 ! 57: #define JUN 6 ! 58: #define JUL 7 ! 59: #define AUG 8 ! 60: #define SEP 9 ! 61: #define OCT 10 ! 62: #define NOV 11 ! 63: #define DEC 12 ! 64: ! 65: ! 66: char caldays[MPL][6][7], /* 3 per line, 6 lines, 7 days */ ! 67: outbuf[BUFSIZ]; /* stdout setbuf */ ! 68: int baseday; /* Weekday of current year's Jan. 1 */ ! 69: ! 70: main(argc, argv) ! 71: register char *argv[]; ! 72: { ! 73: int month; ! 74: unsigned year; ! 75: struct tm *now; ! 76: long intime; ! 77: long time(); ! 78: ! 79: setbuf(stdout, outbuf); ! 80: intime = time(NULL); ! 81: now = localtime(&intime); ! 82: month = 0; ! 83: year = now->tm_year + TMYBIAS; ! 84: ++argv; ! 85: switch (argc) { ! 86: case 1: ! 87: month = now->tm_mon + 1; ! 88: break; ! 89: case 2: ! 90: if (isdigit(**argv)) ! 91: year = atoi(*argv); ! 92: else ! 93: month = getmon(*argv); ! 94: break; ! 95: case 3: ! 96: if (!isdigit(*argv[0])) ! 97: month = getmon(*argv++); ! 98: else if (isdigit(*argv[1])) { ! 99: month = atoi(*argv++); ! 100: if (month == 0) ! 101: month = -1; ! 102: } else ! 103: month = getmon(argv[1]); ! 104: year = atoi(*argv); ! 105: break; ! 106: default: ! 107: usage(); ! 108: } ! 109: if (month < 0 || month > 12 || year <= 0 || year > 9999) ! 110: usage(); ! 111: cal(year, month); ! 112: exit(0); ! 113: } ! 114: ! 115: /* ! 116: * Produce a calendar for the specifed year and month. ! 117: * (If month is zero, then do whole year.) ! 118: * Setup baseday for fillcal to speed it up a lot. ! 119: */ ! 120: cal(yr, mon) ! 121: { ! 122: register xmon, pos; ! 123: register wday; ! 124: ! 125: /* ! 126: * Start at 1 January, 1 which was a Saturday. ! 127: */ ! 128: wday = 6; ! 129: for (pos=1; pos<yr; pos++) { ! 130: if (pos == GREGYEAR) ! 131: wday -= GREGADJ; ! 132: wday = (wday + (isleap(pos) ? 366 : 365)) % 7; ! 133: } ! 134: baseday = wday; ! 135: if (mon != 0) { ! 136: fillcal(0, mon, yr); ! 137: outcal(mon, 1); ! 138: } else { ! 139: printf("\n%*d\n", CENTRE, yr); ! 140: pos = 0; ! 141: for (xmon = 1; xmon <= 12; xmon++) { ! 142: fillcal(pos, xmon, yr); ! 143: if (++pos >= MPL) { ! 144: outcal(xmon-MPL+1, MPL); ! 145: pos = 0; ! 146: } ! 147: } ! 148: } ! 149: } ! 150: ! 151: /* ! 152: * Fill the caldays array element for the particular month ! 153: * and year specified. ! 154: */ ! 155: fillcal(pos, month, year) ! 156: { ! 157: register i, j, day; ! 158: int wday, special, mdays; ! 159: ! 160: for (i=0; i<6; i++) ! 161: for (j=0; j<7; j++) ! 162: caldays[pos][i][j] = 0; ! 163: wday = baseday; ! 164: dpm[FEB] = isleap(year) ? 29 : 28; ! 165: special = (year==GREGYEAR); ! 166: for (i=1; i<month; i++) { ! 167: if (special && i==GREGMON) ! 168: wday -= GREGADJ; ! 169: wday = (wday + dpm[i]) % 7; ! 170: } ! 171: special = (special && month==GREGMON); ! 172: mdays = dpm[month]; ! 173: i = 0; ! 174: j = wday; ! 175: for (day = 1; day <= mdays; day++) { ! 176: caldays[pos][i][j] = day; ! 177: if (special && day==GREGDAY) ! 178: day += GREGADJ; ! 179: if (++j >= 7) { ! 180: j = 0; ! 181: i++; ! 182: } ! 183: } ! 184: } ! 185: ! 186: /* ! 187: * Put out `n' months from caldays, starting at month `mon'. ! 188: */ ! 189: outcal(mon, n) ! 190: { ! 191: register i, j, k; ! 192: int left, cent; ! 193: int val; ! 194: char *name; ! 195: ! 196: mon--; ! 197: lput('\n'); ! 198: for (i=1; i<=n; i++) { ! 199: name = mnames[mon++]; ! 200: cent = strlen(name); ! 201: left = (DAYWIDTH-cent)/2; ! 202: spaceover(left); ! 203: lputs(name); ! 204: spaceover(DAYWIDTH+GAP-left-cent); ! 205: } ! 206: lput('\n'); ! 207: for (i=1; i<=n; i++) { ! 208: lputs(dayhead); ! 209: spaceover(GAP); ! 210: } ! 211: lput('\n'); ! 212: for (j=0; j<6; j++) { ! 213: for (i=0; i<n; i++) { ! 214: for (k=0; k<7; k++) { ! 215: lput(' '); ! 216: val = caldays[i][j][k]; ! 217: lput(val>=10 ? val/10 + '0' : ' '); ! 218: if (val) ! 219: lput(val%10 + '0'); ! 220: else ! 221: lput(' '); ! 222: } ! 223: spaceover(GAP); ! 224: } ! 225: lput('\n'); ! 226: } ! 227: } ! 228: ! 229: /* ! 230: * Put out calendar characters saving them up until a ! 231: * newline so that trailing blanks can be stripped. ! 232: */ ! 233: ! 234: static char lline[100]; ! 235: static char *lp = lline; ! 236: lput(c) ! 237: register c; ! 238: { ! 239: register char *cp; ! 240: ! 241: if (c != '\n') ! 242: *lp++ = c; ! 243: else { ! 244: for (cp = lp; *--cp == ' '; ) ! 245: ; ! 246: *++cp = '\n'; ! 247: *++cp = '\0'; ! 248: printf("%s", lp = lline); ! 249: } ! 250: } ! 251: ! 252: /* ! 253: * Put out a string using `lput'. ! 254: */ ! 255: lputs(s) ! 256: register char *s; ! 257: { ! 258: while (*s != '\0') ! 259: lput(*s++); ! 260: } ! 261: ! 262: spaceover(n) ! 263: register n; ! 264: { ! 265: if (n>0) ! 266: do { ! 267: lput(' '); ! 268: } while (--n); ! 269: } ! 270: ! 271: /* ! 272: * Return 1 on leap years; 0 otherwise. ! 273: */ ! 274: isleap(yr) ! 275: register yr; ! 276: { ! 277: if (yr<=GREGYEAR) ! 278: return (yr%4 == 0); ! 279: if (yr%4000 == 0) ! 280: return (0); ! 281: if (yr%400==0 || (yr%100!=0 && yr%4==0)) ! 282: return (1); ! 283: return (0); ! 284: } ! 285: ! 286: /* ! 287: * Return the month (1-12) from `mname' which is ! 288: * roman numeric, the name in ascii of a month, or wrong. ! 289: * Trailing '.' is accepted as are upper case letters. ! 290: */ ! 291: struct months { ! 292: char *m_name; ! 293: int m_num; ! 294: } months[] = { ! 295: "i", JAN, "jan", JAN, "january", JAN, ! 296: "janvier", JAN, "ii", FEB, "feb", FEB, ! 297: "february", FEB, "fevrier", FEB, "iii", MAR, ! 298: "mar", MAR, "march", MAR, "mars", MAR, ! 299: "iv", APR, "apr", APR, "april", APR, ! 300: "avril", APR, "v", MAY, "may", MAY, ! 301: "mai", MAY, "vi", JUN, "jun", JUN, ! 302: "june", JUN, "juin", JUN, "vii", JUL, ! 303: "jul", JUL, "july", JUL, "juillet", JUL, ! 304: "viii", AUG, "iix", AUG, "aug", AUG, ! 305: "august", AUG, "aout", AUG, "ix", SEP, ! 306: "sep", SEP, "sept", SEP, "september", SEP, ! 307: "septembre", SEP, "x", OCT, "oct", OCT, ! 308: "october", OCT, "octobre", OCT, "xi", NOV, ! 309: "nov", NOV, "november", NOV, "novembre", NOV, ! 310: "xii", DEC, "dec", DEC, "december", DEC, ! 311: "decembre", DEC, NULL ! 312: }; ! 313: ! 314: getmon(mname) ! 315: char *mname; ! 316: { ! 317: register struct months *mp; ! 318: register char *p1, *p2; ! 319: ! 320: for (p1 = mname; *p1 != '\0'; p1 += 1) ! 321: if (isupper(*p1)) ! 322: *p1 = tolower(*p1); ! 323: if (*--p1 == '.') ! 324: *p1 = '\0'; ! 325: for (mp = months; mp->m_name != NULL; mp++) { ! 326: p1 = mname; ! 327: p2 = mp->m_name; ! 328: while (*p1 == *p2 && *p1 != '\0' && *p2 != 0) ! 329: p1 += 1, p2 += 1; ! 330: if (*p1 == *p2) ! 331: return (mp->m_num); ! 332: } ! 333: return (-1); ! 334: } ! 335: ! 336: usage() ! 337: { ! 338: fprintf(stderr, "Usage: cal [month] [year]\n"); ! 339: exit(1); ! 340: } ! 341:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.