1 /* cal.c - show calendar. 2 * 3 * Copyright 2011 Rob Landley <rob (at) landley.net> 4 * 5 * See http://opengroup.org/onlinepubs/9699919799/utilities/cal.html 6 7 USE_CAL(NEWTOY(cal, ">2", TOYFLAG_USR|TOYFLAG_BIN)) 8 9 config CAL 10 bool "cal" 11 default y 12 help 13 usage: cal [[month] year] 14 15 Print a calendar. 16 17 With one argument, prints all months of the specified year. 18 With two arguments, prints calendar for month and year. 19 */ 20 21 #include "toys.h" 22 23 // Write calendar into buffer: each line is 20 chars wide, end indicated 24 // by empty string. 25 26 static char *calstrings(char *buf, struct tm *tm) 27 { 28 char temp[21]; 29 int wday, mday, start, len, line; 30 31 // header 32 len = strftime(temp, 21, "%B %Y", tm); 33 len += (20-len)/2; 34 buf += sprintf(buf, "%*s%*s ", len, temp, 20-len, ""); 35 buf++; 36 buf += sprintf(buf, "Su Mo Tu We Th Fr Sa "); 37 buf++; 38 39 // What day of the week does this month start on? 40 if (tm->tm_mday>1) 41 start = (36+tm->tm_wday-tm->tm_mday)%7; 42 else start = tm->tm_wday; 43 44 // What day does this month end on? Alas, libc doesn't tell us... 45 len = 31; 46 if (tm->tm_mon == 1) { 47 int year = tm->tm_year; 48 len = 28; 49 if (!(year & 3) && !((year&100) && !(year&400))) len++; 50 } else if ((tm->tm_mon+(tm->tm_mon>6 ? 1 : 0)) & 1) len = 30; 51 52 for (mday=line=0;line<6;line++) { 53 for (wday=0; wday<7; wday++) { 54 char *pat = " "; 55 if (!mday ? wday==start : mday<len) { 56 pat = "%2d "; 57 mday++; 58 } 59 buf += sprintf(buf, pat, mday); 60 } 61 buf++; 62 } 63 64 return buf; 65 } 66 67 // Worst case scenario toybuf usage: sizeof(struct tm) plus 21 bytes/line 68 // plus 8 lines/month plus 12 months, comes to a bit over 2k of our 4k buffer. 69 70 void cal_main(void) 71 { 72 struct tm *tm; 73 char *buf = toybuf; 74 75 if (toys.optc) { 76 // Conveniently starts zeroed 77 tm = (struct tm *)toybuf; 78 buf += sizeof(struct tm); 79 80 // Last argument is year, one before that (if any) is month. 81 tm->tm_year = atolx_range(toys.optargs[--toys.optc], 1, 9999); 82 tm->tm_year -= 1900; 83 tm->tm_mday = 1; 84 tm->tm_hour = 12; // noon to avoid timezone weirdness 85 if (toys.optc) { 86 tm->tm_mon = atolx_range(toys.optargs[--toys.optc], 1, 12); 87 tm->tm_mon--; 88 89 // Print 12 months of the year 90 91 } else { 92 char *bufs[12]; 93 int i, j, k; 94 95 for (i=0; i<12; i++) { 96 tm->tm_mon=i; 97 mktime(tm); 98 buf = calstrings(bufs[i]=buf, tm); 99 } 100 101 // 4 rows, 6 lines each, 3 columns 102 for (i=0; i<4; i++) { 103 for (j=0; j<8; j++) { 104 for(k=0; k<3; k++) { 105 char **b = bufs+(k+i*3); 106 *b += printf("%s ", *b); 107 } 108 puts(""); 109 } 110 } 111 return; 112 } 113 114 // What day of the week does that start on? 115 mktime(tm); 116 117 } else { 118 time_t now; 119 time(&now); 120 tm = localtime(&now); 121 } 122 123 calstrings(buf, tm); 124 while (*buf) buf += printf("%s\n", buf); 125 } 126