#include <stdio.h>     // for sscanf, fprintf, perror
#include <stdlib.h>    // for malloc, exit, EXIT_SUCCESS, EXIT_FAILURE
#include <stdint.h>    // for int32_t
#include <inttypes.h>  // for SCNd32, PRId32
#include <errno.h>     // for EINTR
#include <fcntl.h>     // for open, O_RDONLY
#include <unistd.h>    // for read, close

// CSE 333 lecture sample program.
// Use POSIX file I/O to read n bytes from a file and print
// them to stdout (using C library printf for output).

// Print out the usage of the program and exit.
void Usage(void);


int main(int argc, char** argv) {
  int32_t fd, n, bytes_left, result;
  char* buf;

  // input checking (# args, 2nd arg is a positive number)
  if ( (argc != 3) || (sscanf(argv[2], "%" SCNd32, &n) != 1) || (n <= 0) )
    Usage();

  // open input file
  fd = open(argv[1], O_RDONLY);
  if (fd == -1) {
    perror("open failed");
    exit(EXIT_FAILURE);
  }

  // allocate buffer for requested number of bytes
  buf = (char*) malloc((n+1)*sizeof(char));
  if (buf == NULL) {
    perror("malloc failed");
    exit(EXIT_FAILURE);
  }

  // attempt to read in n bytes using POSIX read() with error handling
  // note: there are multiple ways of adjusting pointers and keeping
  // track of the offset in the buffer where the next chunk of data
  // should be stored when read.  This is one way to do it, but it is
  // also possible to do arithmetic on the pointer itself to update the
  // "where to store next" location, etc.
  bytes_left = n;
  while (bytes_left > 0) {
    result = read(fd, buf + (n - bytes_left), bytes_left);
    if (result == -1) {
      if (errno != EINTR) {
        perror("read failed");
        exit(EXIT_FAILURE);
      }
      continue;
    } else if (result == 0) {
      fprintf(stderr, "end of file reached: %" PRId32 " bytes read.\n", n - bytes_left);
      break;
    }
    bytes_left -= result;
  }
  buf[n - bytes_left] = '\0';  // null-terminate string
  printf("Read: %s\n", buf);
  free(buf);
  close(fd);
  return EXIT_SUCCESS;
}


void Usage(void) {
  fprintf(stderr, "Usage: ./readn filename n\nn > 0\n");
  exit(EXIT_FAILURE);
}