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, ">2", TOYFLAG_USR|TOYFLAG_BIN))
   8
   9config 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
  26static 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
  70void 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