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