/*
  Read RR's in getdns wire format and print them in presentation
  format on stdout.
 */

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <getdns/getdns.h>
#include <getdns/getdns_extra.h>

#undef DEBUG

#if defined(DEBUG)
static void
hd(const char *buf, size_t buf_len)
{
  for (size_t n = 0; n < buf_len; n++)
    {
      if (n % 16 == 0)
        {
          if (n != 0)
            fprintf(stderr, "\n");
          fprintf(stderr, "%08x  ", n);
        }
      else if (n % 8 == 0)
        fprintf(stderr, " ");
      fprintf(stderr, "%02hhx ", buf[n]);
    }
  fprintf(stderr, "\n");
}
#else  /* !DEBUG */
#define hd(a,b)
#endif

/* Return value:
   <0 -- error, the return value being -errorcode
    0 -- done
   >0 -- not done yet, call me again
*/
static int
read_rr(const uint8_t **buf, size_t *buf_len, getdns_dict **rr_dict)
{
  getdns_return_t r = getdns_wire2rr_dict_scan(buf, buf_len, rr_dict);

  if (r)
    return -r;
  return *buf_len;
}

#define INBUFLEN 4096

static size_t
read_inbuf(FILE *infp, uint8_t **bufp_out)
{
  size_t nread = 0;
  uint8_t *wirebuf = malloc(INBUFLEN);
  int chunks = 1;

  if (wirebuf == NULL)
    goto out;

  while (1)
    {
      size_t n = fread(wirebuf + nread, 1, INBUFLEN, infp);
      nread += n;
      if (n < INBUFLEN)
        break;                  /* Done. */

      wirebuf = realloc(wirebuf, ++chunks * INBUFLEN);
      if (wirebuf == NULL)
        break;
    }

 out:
  if (bufp_out != NULL)
    *bufp_out = wirebuf;
  return nread;
}

int
main(int argc, char *argv[])
{
  int rrv = 0;
  uint8_t *inbuf = NULL;
  const uint8_t *bufp = NULL;
  size_t inbuf_len = 0;
  getdns_dict *rr_dict = NULL;
  getdns_return_t r = 0;
  FILE *infp = stdin;

  if (argc > 1)
    {
      infp = fopen(argv[1], "r");
      if (infp == NULL)
        {
          perror("fopen(argv[1])");
          return -errno;
        }
    }
  inbuf_len = read_inbuf(infp, &inbuf);
  if (inbuf == NULL)
    {
      perror("read_inbuf");
      return -errno;
    }
  if (infp != stdin)
    if (fclose(infp))
      perror("fclose");
  hd((const char *) wirebuf, n);

  bufp = inbuf;
  while (1)
    {
      char *stringbuf = NULL;

      rrv = read_rr(&bufp, &inbuf_len, &rr_dict);
      if (rrv < 0)
        break;

      r = getdns_rr_dict2str(rr_dict, &stringbuf);
      if (r)
        break;

      getdns_dict_destroy(rr_dict);
      printf("%s", stringbuf);
      free(stringbuf);

      if (rrv == 0)
        break;                  /* Done. */
    }
  free(inbuf);

  if (rrv < 0)
    {
      fprintf(stderr, "parsing input failed: %s\n",
              getdns_get_errorstr_by_id(-rrv));
      return rrv;
    }
  if (r)
    {
      fprintf(stderr, "converting dict to string failed: %s\n",
              getdns_get_errorstr_by_id(r));
      return -r;
    }

  return 0;
}