9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

cal.c (4204B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <bio.h>
      4 
      5 char	dayw[] =
      6 {
      7 	" S  M Tu  W Th  F  S"
      8 };
      9 char	*smon[] =
     10 {
     11 	"January", "February", "March", "April",
     12 	"May", "June", "July", "August",
     13 	"September", "October", "November", "December",
     14 };
     15 char	mon[] =
     16 {
     17 	0,
     18 	31, 29, 31, 30,
     19 	31, 30, 31, 31,
     20 	30, 31, 30, 31,
     21 };
     22 char	string[432];
     23 Biobuf	bout;
     24 
     25 void	main(int argc, char *argv[]);
     26 int	number(char *str);
     27 void	pstr(char *str, int n);
     28 void	cal(int m, int y, char *p, int w);
     29 int	jan1(int yr);
     30 int	curmo(void);
     31 int	curyr(void);
     32 
     33 void
     34 main(int argc, char *argv[])
     35 {
     36 	int y, i, j, m;
     37 
     38 	if(argc > 3) {
     39 		fprint(2, "usage: cal [month] [year]\n");
     40 		exits("usage");
     41 	}
     42 	Binit(&bout, 1, OWRITE);
     43 
     44 /*
     45  * no arg, print current month
     46  */
     47 	if(argc == 1) {
     48 		m = curmo();
     49 		y = curyr();
     50 		goto xshort;
     51 	}
     52 
     53 /*
     54  * one arg
     55  *	if looks like a month, print month
     56  *	else print year
     57  */
     58 	if(argc == 2) {
     59 		y = number(argv[1]);
     60 		if(y < 0)
     61 			y = -y;
     62 		if(y >= 1 && y <= 12) {
     63 			m = y;
     64 			y = curyr();
     65 			goto xshort;
     66 		}
     67 		goto xlong;
     68 	}
     69 
     70 /*
     71  * two arg, month and year
     72  */
     73 	m = number(argv[1]);
     74 	if(m < 0)
     75 		m = -m;
     76 	y = number(argv[2]);
     77 	goto xshort;
     78 
     79 /*
     80  *	print out just month
     81  */
     82 xshort:
     83 	if(m < 1 || m > 12)
     84 		goto badarg;
     85 	if(y < 1 || y > 9999)
     86 		goto badarg;
     87 	Bprint(&bout, "   %s %d\n", smon[m-1], y);
     88 	Bprint(&bout, "%s\n", dayw);
     89 	cal(m, y, string, 24);
     90 	for(i=0; i<6*24; i+=24)
     91 		pstr(string+i, 24);
     92 	exits(0);
     93 
     94 /*
     95  *	print out complete year
     96  */
     97 xlong:
     98 	y = number(argv[1]);
     99 	if(y<1 || y>9999)
    100 		goto badarg;
    101 	Bprint(&bout, "\n\n\n");
    102 	Bprint(&bout, "                                %d\n", y);
    103 	Bprint(&bout, "\n");
    104 	for(i=0; i<12; i+=3) {
    105 		for(j=0; j<6*72; j++)
    106 			string[j] = '\0';
    107 		Bprint(&bout, "         %.3s", smon[i]);
    108 		Bprint(&bout, "                    %.3s", smon[i+1]);
    109 		Bprint(&bout, "                    %.3s\n", smon[i+2]);
    110 		Bprint(&bout, "%s   %s   %s\n", dayw, dayw, dayw);
    111 		cal(i+1, y, string, 72);
    112 		cal(i+2, y, string+23, 72);
    113 		cal(i+3, y, string+46, 72);
    114 		for(j=0; j<6*72; j+=72)
    115 			pstr(string+j, 72);
    116 	}
    117 	Bprint(&bout, "\n\n\n");
    118 	exits(0);
    119 
    120 badarg:
    121 	Bprint(&bout, "cal: bad argument\n");
    122 }
    123 
    124 struct
    125 {
    126 	char*	word;
    127 	int	val;
    128 } dict[] =
    129 {
    130 	"jan",		1,
    131 	"january",	1,
    132 	"feb",		2,
    133 	"february",	2,
    134 	"mar",		3,
    135 	"march",	3,
    136 	"apr",		4,
    137 	"april",	4,
    138 	"may",		5,
    139 	"jun",		6,
    140 	"june",		6,
    141 	"jul",		7,
    142 	"july",		7,
    143 	"aug",		8,
    144 	"august",	8,
    145 	"sep",		9,
    146 	"sept",		9,
    147 	"september",	9,
    148 	"oct",		10,
    149 	"october",	10,
    150 	"nov",		11,
    151 	"november",	11,
    152 	"dec",		12,
    153 	"december",	12,
    154 	0
    155 };
    156 
    157 /*
    158  * convert to a number.
    159  * if its a dictionary word,
    160  * return negative  number
    161  */
    162 int
    163 number(char *str)
    164 {
    165 	int n, c;
    166 	char *s;
    167 
    168 	for(n=0; s=dict[n].word; n++)
    169 		if(strcmp(s, str) == 0)
    170 			return -dict[n].val;
    171 	n = 0;
    172 	s = str;
    173 	while(c = *s++) {
    174 		if(c<'0' || c>'9')
    175 			return 0;
    176 		n = n*10 + c-'0';
    177 	}
    178 	return n;
    179 }
    180 
    181 void
    182 pstr(char *str, int n)
    183 {
    184 	int i;
    185 	char *s;
    186 
    187 	s = str;
    188 	i = n;
    189 	while(i--)
    190 		if(*s++ == '\0')
    191 			s[-1] = ' ';
    192 	i = n+1;
    193 	while(i--)
    194 		if(*--s != ' ')
    195 			break;
    196 	s[1] = '\0';
    197 	Bprint(&bout, "%s\n", str);
    198 }
    199 
    200 void
    201 cal(int m, int y, char *p, int w)
    202 {
    203 	int d, i;
    204 	char *s;
    205 
    206 	s = p;
    207 	d = jan1(y);
    208 	mon[2] = 29;
    209 	mon[9] = 30;
    210 
    211 	switch((jan1(y+1)+7-d)%7) {
    212 
    213 	/*
    214 	 *	non-leap year
    215 	 */
    216 	case 1:
    217 		mon[2] = 28;
    218 		break;
    219 
    220 	/*
    221 	 *	1752
    222 	 */
    223 	default:
    224 		mon[9] = 19;
    225 		break;
    226 
    227 	/*
    228 	 *	leap year
    229 	 */
    230 	case 2:
    231 		;
    232 	}
    233 	for(i=1; i<m; i++)
    234 		d += mon[i];
    235 	d %= 7;
    236 	s += 3*d;
    237 	for(i=1; i<=mon[m]; i++) {
    238 		if(i==3 && mon[m]==19) {
    239 			i += 11;
    240 			mon[m] += 11;
    241 		}
    242 		if(i > 9)
    243 			*s = i/10+'0';
    244 		s++;
    245 		*s++ = i%10+'0';
    246 		s++;
    247 		if(++d == 7) {
    248 			d = 0;
    249 			s = p+w;
    250 			p = s;
    251 		}
    252 	}
    253 }
    254 
    255 /*
    256  *	return day of the week
    257  *	of jan 1 of given year
    258  */
    259 int
    260 jan1(int yr)
    261 {
    262 	int y, d;
    263 
    264 /*
    265  *	normal gregorian calendar
    266  *	one extra day per four years
    267  */
    268 
    269 	y = yr;
    270 	d = 4+y+(y+3)/4;
    271 
    272 /*
    273  *	julian calendar
    274  *	regular gregorian
    275  *	less three days per 400
    276  */
    277 
    278 	if(y > 1800) {
    279 		d -= (y-1701)/100;
    280 		d += (y-1601)/400;
    281 	}
    282 
    283 /*
    284  *	great calendar changeover instant
    285  */
    286 
    287 	if(y > 1752)
    288 		d += 3;
    289 
    290 	return d%7;
    291 }
    292 
    293 /*
    294  * system dependent
    295  * get current month and year
    296  */
    297 int
    298 curmo(void)
    299 {
    300 	Tm *tm;
    301 
    302 	tm = localtime(time(0));
    303 	return tm->mon+1;
    304 }
    305 
    306 int
    307 curyr(void)
    308 {
    309 	Tm *tm;
    310 
    311 	tm = localtime(time(0));
    312 	return tm->year+1900;
    313 }