aboutsummaryrefslogtreecommitdiffstats
path: root/usr/date.c
blob: 57108ab740cb82dfc47e0d13eb816857b216bcdd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "gbos.h"
/* date: print the wall clock, UTC.
 *
 * The kernel hands back unix seconds (SYS_GETTIME); turning that into a date
 * is all bounded subtraction - no long division or shifts, which SDCC would
 * pull out of sm83.lib and link into the $A000 RAM window (see usr/uptime.c
 * and usr/build.sh). ~20k rounds for the day loop is a fraction of a second.
 *
 * Says so plainly when the clock has never been set: run ntpdate first. */

/* No initialized arrays: SDCC puts those in _INITIALIZED at $A000, the RAM
   window, and the image then overflows its bank ("buffer too small" out of
   makebin - see usr/ansi.c and usr/build.sh). String literals live in _CODE,
   so the tables are literals indexed by hand. */
#define MDAYS "\x1f\x1c\x1f\x1e\x1f\x1e\x1f\x1f\x1e\x1f\x1e\x1f"
#define MNAME "JanFebMarAprMayJunJulAugSepOctNovDec"

static void two(unsigned int v) {
    if (v < 10) putc('0');
    putu(v);
}
static unsigned char leap(unsigned int y) {
    if (y & 3) return 0;
    if (y == 2100) return 0; /* good enough until then */
    return 1;
}

void main(void) {
    unsigned char t[4];
    union {
        unsigned long l;
        unsigned char b[4];
    } u;
    unsigned long sec;
    unsigned int days = 0, year = 1970, h, m, i, dim;

    if (!gettime(t)) {
        puts("date: clock not set (run ntpdate)");
        nl();
        sexit(1);
    }
    u.b[0] = t[0];
    u.b[1] = t[1];
    u.b[2] = t[2];
    u.b[3] = t[3];
    sec = u.l;

    while (sec >= 86400UL) {
        sec -= 86400UL;
        days++;
    }
    h = 0;
    while (sec >= 3600UL) {
        sec -= 3600UL;
        h++;
    }
    m = 0;
    while (sec >= 60UL) {
        sec -= 60UL;
        m++;
    }

    for (;;) { /* years, then months */
        unsigned int len = leap(year) ? 366 : 365;
        if (days < len) break;
        days -= len;
        year++;
    }
    for (i = 0; i < 12; i++) {
        dim = (unsigned char)MDAYS[i];
        if (i == 1 && leap(year)) dim = 29;
        if (days < dim) break;
        days -= dim;
    }
    writes(MNAME + i * 3, 3);
    putc(' ');
    putu(days + 1);
    putc(' ');
    two(h);
    putc(':');
    two(m);
    putc(':');
    two((unsigned int)sec);
    puts(" UTC ");
    putu(year);
    nl();
}