master xplshn/aruu / cmd / posix / date.c
  1/* See LICENSE file for copyright and license details. */
  2
  3#include <ctype.h>
  4#include <stdio.h>
  5#include <stdlib.h>
  6#include <string.h>
  7#include <time.h>
  8
  9#include "util.h"
 10
 11static void
 12usage(void)
 13{
 14  eprintf("usage: %s [-u] [-d time] [+format | mmddHHMM[[CC]yy]]\n", argv0);
 15}
 16
 17static int
 18datefield(const char *s, size_t i)
 19{
 20  if (!isdigit(s[i]) || !isdigit(s[i + 1]))
 21    eprintf("invalid date format: %s\n", s);
 22
 23  return (s[i] - '0') * 10 + (s[i + 1] - '0');
 24}
 25
 26static void
 27setdate(const char *s, struct tm *now)
 28{
 29  struct tm       date;
 30  struct timespec ts;
 31
 32  switch (strlen(s)) {
 33    case 8:
 34      date.tm_year = now->tm_year;
 35      break;
 36    case 10:
 37      date.tm_year = datefield(s, 8);
 38      if (date.tm_year < 69)
 39        date.tm_year += 100;
 40      break;
 41    case 12:
 42      date.tm_year = ((datefield(s, 8) - 19) * 100) + datefield(s, 10);
 43      break;
 44    default:
 45      eprintf("invalid date format: %s\n", s);
 46      break;
 47  }
 48
 49  date.tm_mon   = datefield(s, 0) - 1;
 50  date.tm_mday  = datefield(s, 2);
 51  date.tm_hour  = datefield(s, 4);
 52  date.tm_min   = datefield(s, 6);
 53  date.tm_sec   = 0;
 54  date.tm_isdst = -1;
 55
 56  ts.tv_sec = mktime(&date);
 57  if (ts.tv_sec == -1)
 58    eprintf("mktime:");
 59  ts.tv_nsec = 0;
 60
 61  if (clock_settime(CLOCK_REALTIME, &ts) == -1)
 62    eprintf("clock_settime:");
 63}
 64
 65// ?man date: print or set system date and time
 66// ?man arguments: +format | mmddHHMM[[CC]yy]
 67// ?man display or configure the system date and time
 68int
 69main(int argc, char *argv[])
 70{
 71  struct tm *now;
 72  time_t     t;
 73  char       buf[BUFSIZ], *fmt = "%a %b %e %H:%M:%S %Z %Y";
 74
 75  t = time(NULL);
 76  if (t == -1)
 77    eprintf("time:");
 78
 79  ARGBEGIN
 80  {
 81    // ?man -d:num: specify directory
 82    case 'd':
 83      t = estrtonum(EARGF(usage()), 0, LLONG_MAX);
 84      break;
 85    // ?man -u: unbuffered output
 86    case 'u':
 87      if (setenv("TZ", "UTC0", 1) < 0)
 88        eprintf("setenv:");
 89      break;
 90    default:
 91      usage();
 92  }
 93  ARGEND
 94
 95  if (!(now = localtime(&t)))
 96    eprintf("localtime:");
 97  if (argc) {
 98    if (argc != 1)
 99      usage();
100    if (argv[0][0] != '+') {
101      setdate(argv[0], now);
102      return 0;
103    }
104    fmt = &argv[0][1];
105  }
106
107  strftime(buf, sizeof(buf), fmt, now);
108  puts(buf);
109
110  return fshut(stdout, "<stdout>");
111}