/* hexdump.c (emx+gcc) */

/* test setmode(), _isterm() */

#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <fcntl.h>
#include <getopt.h>
#include <sys/ioctl.h>

#define FALSE 0
#define TRUE  1

static int opt_binary = FALSE;
static int opt_text = FALSE;
static int opt_verbose = FALSE;
static unsigned char inp_buf[10240];
static char out_buf[100];
static char hex[] = "0123456789ABCDEF";

static void usage (void)
{
  puts ("Usage: hexdump [-btv] [-n<count>] [<input_file>]");
  exit (1);
}

static void flush (void)
{
  if (write (1, out_buf, strlen (out_buf)) != strlen (out_buf))
    {
      perror ("write() failed");
      exit (2);
    }
}


static void talk_about (int fd, const char *name)
{
  int i, fl;

  fprintf (stderr, "%s: isatty:  %d\n", name, isatty (fd));
  fprintf (stderr, "%s: _isterm: %d\n", name, _isterm (fd));
  if (ioctl (fd, FGETHTYPE, &i) < 0)
    perror ("ioctl FGETHTYPE");
  else
    switch (i)
      {
      case HT_FILE:
        fprintf (stderr, "%s is a regular file\n", name);
        break;
      case HT_UPIPE:
        fprintf (stderr, "%s is a unnamed pipe\n", name);
        break;
      case HT_NPIPE:
        fprintf (stderr, "%s is a named pipe\n", name);
        break;
      case HT_DEV_NUL:
        fprintf (stderr, "%s is the null device\n", name);
        break;
      case HT_DEV_CON:
        fprintf (stderr, "%s is the console\n", name);
        break;
      case HT_DEV_CLK:
        fprintf (stderr, "%s is the clock device\n", name);
        break;
      case HT_DEV_OTHER:
        fprintf (stderr, "%s is an unknown device\n", name);
        break;
      default:
        fprintf (stderr, "%s: unknown handle type: %d\n", name, i);
        break;
      }
  if ((fl = fcntl (fd, F_GETFL, 0)) == -1)
    perror ("fcntl F_GETFL");
  else
    {
      fprintf (stderr, "  Flags:");
      if (fl & O_APPEND)
        fprintf (stderr, " O_APPEND");
      if (fl & O_NDELAY)
        fprintf (stderr, " O_NDELAY");
      fprintf (stderr, "\n");
    }
}


int main (int argc, char *argv[])
{
  int i, fd, c, x, m, n, nread;
  char *d, *inp_fname;

  optswchar = "-"; optind = 0;
  nread = sizeof (inp_buf);
  while ((c = getopt (argc, argv, ":bn:tv")) != -1)
    {
      switch (c)
        {
        case 'b':
          opt_binary = TRUE;
          break;
        case 'n':
          nread = atoi (optarg);
          if (nread < 1 || nread > sizeof (inp_buf))
            usage ();
          break;
        case 't':
          opt_text = TRUE;
          break;
        case 'v':
          opt_verbose = TRUE;
          break;
        case ':':
          fprintf (stderr, "No argument for -%c\n", optopt);
          usage ();
        default:
          fprintf (stderr, "Invalid option -%c\n", optopt);
          usage ();
        }
    }
  m = 0;
  if (opt_binary) m |= O_BINARY;
  if (opt_text) m |= O_TEXT;
  if (optind == argc)
    {
      fd = 0;         /* stdin */
      inp_fname = "stdin";
      if (m != 0 && setmode (fd, m) < 0)
        {
          perror ("setmode() failed");
          return 2;
        }
    }
  else if (optind + 1 == argc)
    {
      inp_fname = argv[optind];
      fd = open (argv[optind], O_RDONLY | m);
      if (fd < 0)
        {
          perror ("open() failed");
          return 1;
        }
    }
  else
    usage ();
  if (opt_verbose)
    {
      talk_about (fd, inp_fname);
      talk_about (1, "stdout");
    }
  x = 0; d = out_buf; n = 0; i = 0;
  for (;;)
    {
      if (i >= n)
        {
          i = 0;
          n = read (fd, inp_buf, nread);
          if (n < 0)
            {
              perror ("read() failed");
              return 2;
            }
          if (n == 0)
            break;
        }
      if (x >= 16)
        {
          *d++ = '\n'; *d = 0;
          flush ();
          x = 0; d = out_buf;
        }
      c = inp_buf[i++];
      if (x != 0)
        *d++ = ' ';
      ++x;
      *d++ = hex[(c >> 4) & 0x0f];
      *d++ = hex[c & 0x0f];
    }
  if (out_buf[0] != 0)
    {
      *d++ = '\n'; *d = 0;
      flush ();
    }
  return 0;
}

/*
 * Local variables:
 * compile-command: "make hexdump.exe"
 * end:
 */
