summaryrefslogtreecommitdiff
path: root/src/tai64nfrac.c
blob: d3b1a3172f49af569ead7c78ec5b64b4623da3f4 (plain)
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
88
89
90
91
92
#include <unistd.h>

#include "buffer.h"
#include "exit.h"
#include "fmt.h"
#include "getln.h"
#include "open.h"
#include "scan.h"
#include "stralloc.h"

#define TAI64NLEN 24

/**
  @file tai64nfrac
  @brief Read a TAI64N external format timestamp from stdin and
         write fractional seconds since epoch (TAI, not UTC) to stdout.
         Return the characters after the timestamp.
*/

char outbuf[64];
buffer bo = BUFFER_INIT(write, 1, outbuf, sizeof(outbuf));

static void outs(char *s)
{
  if (buffer_puts(&bo, s) == -1) _exit(1);
  if (buffer_flush(&bo) == -1) _exit(1);
}

static void outi(int i)
{
  char num[FMT_ULONG];

  if (buffer_put(&bo, num, fmt_ulong(num, (unsigned long)i)) == -1) _exit(1);
  if (buffer_flush(&bo) == -1) _exit(1);
}

char inbuf[1024];
buffer bi = BUFFER_INIT(read, 0, inbuf, sizeof(inbuf));

int main(void)
{
  int c;
  int i;
  int match;
  unsigned long u;
  unsigned long seconds;
  unsigned long nanoseconds;
  stralloc line = {0};

  /* Read from stdin */

  buffer_init(&bi, read, 0, inbuf, sizeof(inbuf));

  for (;;) {
    if (getln(&bi, &line, &match, '\n') != 0) _exit(1);
    if (!match) break;
    if (!stralloc_0(&line)) _exit(1);

    seconds = 0;
    nanoseconds = 0;

    if (line.s[0] == '@') { /* tai64 timestamp */
      for (i = 1; i <= TAI64NLEN; i++) {
        c = (int)line.s[i];
        u = c - '0';
        if (u >= 10) {
          u = c - 'a';
          if (u >= 6) break;
          u += 10;
        }
        seconds <<= 4;
        seconds += nanoseconds >> 28;
        nanoseconds &= 0xfffffff;
        nanoseconds <<= 4;
        nanoseconds += u;
      }
      seconds -= 4611686018427387914ULL;
      seconds = seconds > 0 ? seconds : 0;
      outi(seconds);
      outs(".");
      outi(nanoseconds);
      outs(line.s + i);
      outs("\n");
    } else {
      outs("tai64nfrac: fatal: Wrong TAI64N input format.");
      outs("\n");
      _exit(1);
    }
  }

  _exit(0);
}