/*
 * Copyright (c) 2019 Clementine Computing LLC.
 *
 * This file is part of PopuFare.
 *
 * PopuFare is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * PopuFare 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with PopuFare.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

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

//extern char *optarg;

int g_start_pos = 0;
int g_end_pos = -1;
int g_modulus = 16;
char *g_fn = NULL;

int g_verbose_flag = 0;
int g_cononical_flag = 0;

void print_usage_and_exit(void)
{
  printf("simple utility to look at raw data of files\n");
  printf("usage:\n");
  printf("  -f fn           filename\n");
  printf("  [-s start]      start byte (default start)\n");
  printf("  [-e end]        end byte (default end)\n");
  printf("  [-m mod]        newline every 'mod' entries (default 16)\n");
  printf("  [-C]            'cononical' view.  Print printable ascii next alongsize value\n");
  printf("  [-h]            help\n");
  printf("  [-v]            verbose flag\n");

  exit(0);
}



int main(int argc, char **argv)
{
  int i, k;
  int fd = -1;
  struct stat st;

  int r;

  int read_end = -1;
  char buf[16] = {0};
  int c;

  while ((c = getopt(argc, argv, "hvs:e:m:f:C")) != -1) 
    switch (c)
    {
      case 'f': g_fn = strdup(optarg); break;
      case 'C': g_cononical_flag = 1; break;
      case 'h': print_usage_and_exit(); exit(0); break;
      case 'v': g_verbose_flag = 1; break;
      case 's': g_start_pos = atoi(optarg); break;
      case 'e': g_end_pos = atoi(optarg); break;
      case 'm': g_modulus = atoi(optarg); break;
      default: print_usage_and_exit(); exit(0); break;
    }

  if ( !g_fn )
  {
    printf("provide filename\n");
    print_usage_and_exit();
  }

  if ((g_start_pos < 0) ||
      (g_modulus < 1) )
  {
    printf("start byte must be non-negative and modulus must be greater than 0\n");
    print_usage_and_exit();
  }

  r = stat( g_fn, &st );
  if (r < 0)
  {
    perror(g_fn);
    exit(-1);
  }

  fd = open( g_fn, O_RDONLY );
  if (fd < 0)
  {
    perror(g_fn);
    exit(-1);
  }

  read_end = st.st_size;
  if ( (g_end_pos >= 0) && (g_end_pos < st.st_size) )
    read_end = g_end_pos+1;

  if (g_start_pos>0)
    lseek( fd, g_start_pos, SEEK_SET );

  printf("start %i end %i\n", g_start_pos, read_end);

  printf("#output in hex\n");
  for (k=0, i=g_start_pos; i < read_end ; i++, k++)
  {
    if ((k % g_modulus)==0)
    {
      if (k>0)
        printf("\n");

      if (g_cononical_flag)
      {
        printf("[%4x]", i);
      }
 
    }

    r = read( fd, buf, 1 );
    if (r < 0)
    {
      perror("read error");
      exit(-1);
    }

    printf(" %02x", buf[0] );
    if (g_cononical_flag)
    {
      printf(" %c  ", isprint(buf[0]) ? buf[0] : '.' );
    }
  }

  close(fd);


  printf("\n");

  return 0;

}
