/* hexdumper.c Hex File dumper by Adam Rogoyski (apoc@laker.net) Temperance
 * Copyright (C) 1998 Adam Rogoyski
 * Dumps files in Hex and Ascii like Norton Diskedit.  Displays ascii
 * portion in 7 or 8 bit mode depending on if you use the -8 switch.
 * Dumping multible files will concatenate all the files into one
 * continous dump.
 * compile gcc -o hexdumper hexdumper.c
 * --- GNU General Public License Disclamer ---
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

#define  LINELENGTH 16
#define  MAXFILES   32

void usage (char *);

int
main (int argc, char **argv)
{
   unsigned char in = 0;
   char *files[MAXFILES];
   int fd = 0;
   int n = 0;
   int nfiles = 0;
   int checkUpTo = 127;
   int i = 0;
   int j = 0;
   unsigned int offset = 0x0000;
   int txt[LINELENGTH];
   short m1 = LINELENGTH / 4;
   short m2 = LINELENGTH / 2;
   short m3 = LINELENGTH - LINELENGTH / 4;
   if (!isatty(0))
   {
      fd = 0;
      files[0] = NULL;
      nfiles = 1;
   }
   if (argc >= 2)
   {
      i = 1;
      while (*(argv + i) != NULL)
      {
         if (**(argv + i) == '-')
            switch (*(*(argv + i) + 1))
            {
               case '8':
                         checkUpTo = 255;
                         break;
               case 'h':
                         usage (*argv);
                         exit (EXIT_SUCCESS);
                         break;
               case '-':
                         if (!strncmp (*(argv + i), "--help", 6))
                         {
                            usage (*argv);
                            exit (EXIT_SUCCESS);
                         }
                         break;
            }
         else
         {
            files[nfiles] = *(argv + i);
            nfiles++;
         }
         i++;
      }
   }
   if (nfiles == 0)
   {
      usage (*argv);
      return EXIT_SUCCESS;
   }
   memset (txt, 0, LINELENGTH * sizeof (char));
   i = 0;
   for (n = 0; n < nfiles; n++)
   {
      if ((n == 0) && (files[n] == NULL))
         fd = 0;
      else
      {
         close (fd);
         fd = open (files[n], O_RDONLY);
         if (fd == -1)
         {
            perror (files[n]);
            continue;
         }
      }
      while (read (fd, (char *) &in, 1) > 0)
      {
         txt[i] = in;
         if (i == LINELENGTH - 1)
         {
            printf ("%02X ", in);
            for (j = 0; j < LINELENGTH; j++)
            {
               if ((txt[j] > 27) && (txt[j] <= checkUpTo))
                  fputc (txt[j], stdout);
               else
                  fputc ('.', stdout);
            }
            printf ("\n");
            i = 0;
            offset++;
            memset (txt, 0, LINELENGTH * sizeof (char));
         }
         else if (i == 0)
         {
            printf ("%08X  ", offset);
            printf ("%02X ", in);
            i++;
            offset++;
         }
         else
         {
            printf ("%02X ", in);
            i++;
            offset++;
         }
         if (i == m2)
            printf ("  ");
         else if (i == m1)
            printf (" ");
         else if (i == m3)
            printf (" ");
      }
   }

   if (i < m1)
      printf ("    ");
   else if (i < m2)
      printf ("   ");
   else if (i < m3)
      printf (" ");
   
   for (j = i; j < LINELENGTH; j++)
      printf ("   ");
   for (j = 0; j < i; j++)
   {
      if ((txt[j] > 27) && (txt[j] <= checkUpTo))
         fputc (txt[j], stdout);
      else
         fputc ('.', stdout);
   }
   close (fd);
   printf ("\n");
   return EXIT_SUCCESS;
}


void
usage (char *filename)
{
   fprintf (stderr, "hexdumper by Adam Rogoyski (apoc@laker.net)\n");
   fprintf (stderr, "usage: %s [flags] filename [files...]\n", filename);
   fprintf (stderr, "usage: unix commands | %s [flags] [files...]\n", filename);
   fprintf (stderr, "flags: -8      print high bit ascii characters\n");
   fprintf (stderr, "       -h      print this help\n");
   fprintf (stderr, "       --help  print this help\n");
   fprintf (stderr, "hexdumper will concatenate files into on continuos dump\n");
}
