cal.c 3.5 KB

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