morpheus-base

morpheus base system
git clone git://git.2f30.org/morpheus-base
Log | Files | Refs

cal.c (4497B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <time.h>
      5 
      6 #include "util.h"
      7 
      8 enum { JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };
      9 enum caltype { JULIAN, GREGORIAN };
     10 enum { TRANS_YEAR = 1752, TRANS_MONTH = SEP, TRANS_DAY = 2 };
     11 
     12 static int
     13 isleap(int year, enum caltype cal)
     14 {
     15 	if (cal == GREGORIAN) {
     16 		if (year % 400 == 0)
     17 			return 1;
     18 		if (year % 100 == 0)
     19 			return 0;
     20 		return (year % 4 == 0);
     21 	}
     22 	else { /* cal == Julian */
     23 		return (year % 4 == 0);
     24 	}
     25 }
     26 
     27 static int
     28 monthlength(int year, int month, enum caltype cal)
     29 {
     30 	int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
     31 
     32 	return (month == FEB && isleap(year,cal)) ? 29 : mdays[month];
     33 }
     34 
     35 /* From http://www.tondering.dk/claus/cal/chrweek.php#calcdow */
     36 static int
     37 dayofweek(int year, int month, int dom, enum caltype cal)
     38 {
     39 	int m, y, a;
     40 
     41 	month += 1;  /*  in this formula, 1 <= month <= 12  */
     42 	a = (14 - month) / 12;
     43 	y = year - a;
     44 	m = month + 12 * a - 2;
     45 
     46 	if (cal == GREGORIAN)
     47 		return (dom + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12) % 7;
     48 	else  /* cal == Julian */
     49 		return (5 + dom + y + y / 4 + (31 * m) / 12) % 7;
     50 }
     51 
     52 static void
     53 printgrid(int year, int month, int fday, int line)
     54 {
     55 	enum caltype cal;
     56 	int trans; /* are we in the transition from Julian to Gregorian? */
     57 	int offset, dom, d = 0;
     58 
     59 	if (year < TRANS_YEAR || (year == TRANS_YEAR && month <= TRANS_MONTH))
     60 		cal = JULIAN;
     61 	else
     62 		cal = GREGORIAN;
     63 	trans = (year == TRANS_YEAR && month == TRANS_MONTH);
     64 	offset = dayofweek(year, month, 1, cal) - fday;
     65 	if (offset < 0)
     66 		offset += 7;
     67 	if (line == 1) {
     68 		for ( ; d < offset; ++d)
     69 			printf("   ");
     70 		dom = 1;
     71 	} else {
     72 		dom = 8 - offset + (line - 2) * 7;
     73 		if (trans && !(line == 2 && fday == 3))
     74 			dom += 11;
     75 	}
     76 	for ( ; d < 7 && dom <= monthlength(year, month, cal); ++d, ++dom) {
     77 		printf("%2d ", dom);
     78 		if (trans && dom==TRANS_DAY)
     79 			dom += 11;
     80 	}
     81 	for ( ; d < 7; ++d)
     82 		printf("   ");
     83 }
     84 
     85 static void
     86 drawcal(int year, int month, int ncols, int nmons, int fday)
     87 {
     88 	char *smon[] = {"  January", " February", "    March", "    April",
     89 	                "      May", "     June", "     July", "   August",
     90 	                "September", "  October", " November", " December" };
     91 	char *days[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", };
     92 	int m, n, col, cur_year, cur_month, line, dow;
     93 
     94 	for (m = 0; m < nmons; ) {
     95 		n = m;
     96 		for (col = 0; m < nmons && col < ncols; ++col, ++m) {
     97 			cur_year = year + m / 12;
     98 			cur_month = month + m % 12;
     99 			if (cur_month > 11) {
    100 				cur_month -= 12;
    101 				cur_year += 1;
    102 			}
    103 			printf("   %s %d    ", smon[cur_month], cur_year);
    104 			printf("  ");
    105 		}
    106 		printf("\n");
    107 		for (col = 0, m = n; m < nmons && col < ncols; ++col, ++m) {
    108 			for (dow = fday; dow < (fday + 7); ++dow)
    109 				printf("%s ", days[dow % 7]);
    110 			printf("  ");
    111 		}
    112 		printf("\n");
    113 		for (line = 1; line <= 6; ++line) {
    114 			for (col = 0, m = n; m < nmons && col < ncols; ++col, ++m) {
    115 				cur_year = year + m / 12;
    116 				cur_month = month + m % 12;
    117 				if (cur_month > 11) {
    118 					cur_month -= 12;
    119 					cur_year += 1;
    120 				}
    121 				printgrid(cur_year, cur_month, fday, line);
    122 				printf("  ");
    123 			}
    124 			printf("\n");
    125 		}
    126 	}
    127 }
    128 
    129 static void
    130 usage(void)
    131 {
    132 	eprintf("usage: %s [-1 | -3 | -y | -n nmonths] "
    133 	        "[-s | -m | -f firstday] [-c columns] [[month] year]\n", argv0);
    134 }
    135 
    136 int
    137 main(int argc, char *argv[])
    138 {
    139 	int year, month, ncols, nmons, fday;
    140 	struct tm *ltime;
    141 	time_t now;
    142 
    143 	now = time(NULL);
    144 	ltime = localtime(&now);
    145 	year = ltime->tm_year + 1900;
    146 	month = ltime->tm_mon + 1;
    147 	fday = 0;
    148 
    149 	ncols = 3;
    150 	nmons = 0;
    151 
    152 	ARGBEGIN {
    153 	case '1':
    154 		nmons = 1;
    155 		break;
    156 	case '3':
    157 		nmons = 3;
    158 		month -= 1;
    159 		if (month == 0) {
    160 			month = 12;
    161 			year--;
    162 		}
    163 		break;
    164 	case 'c':
    165 		ncols = estrtol(EARGF(usage()), 0);
    166 		break;
    167 	case 'f':
    168 		fday = estrtol(EARGF(usage()), 0);
    169 		break;
    170 	case 'm': /* Monday */
    171 		fday = 1;
    172 		break;
    173 	case 'n':
    174 		nmons = estrtol(EARGF(usage()), 0);
    175 		break;
    176 	case 's': /* Sunday */
    177 		fday = 0;
    178 		break;
    179 	case 'y':
    180 		month = 1;
    181 		nmons = 12;
    182 		break;
    183 	default:
    184 		usage();
    185 	} ARGEND;
    186 
    187 	if (nmons == 0) {
    188 		if (argc == 1) {
    189 			month = 1;
    190 			nmons = 12;
    191 		} else {
    192 			nmons = 1;
    193 		}
    194 	}
    195 
    196 	switch (argc) {
    197 	case 2:
    198 		month = estrtol(argv[0], 0);
    199 		argv++;
    200 	case 1:
    201 		year = estrtol(argv[0], 0);
    202 		break;
    203 	case 0:
    204 		break;
    205 	default:
    206 		usage();
    207 	}
    208 
    209 	if (ncols < 0 || month < 1 || month > 12 || nmons < 1 || fday < 0 || fday > 6) {
    210 		usage();
    211 	}
    212 
    213 	drawcal(year, month - 1, ncols, nmons, fday);
    214 
    215 	return 0;
    216 }