#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/io.h>

int main(int argc, char *argv[]) {
  if (argc < 2) {
    fprintf(stderr, "Usage: %s <tracefile>\n", argv[0]);
    return 1;
  }

  if (iopl(3)) {
    perror("Unable to enable port access: iopl");
    return 1;
  }

  FILE *f = fopen(argv[1], "r");
  if (!f) {
    perror("Unable to open tracefile");
    return 1;
  }
  FILE *outfile = fopen("dump.bin", "a");
  if (!outfile) {
    perror("Unable to open output file");
    return 1;
  }

  bool run = false;
  unsigned int counter = 1;

  while (!feof(f)) {
    unsigned int count, port, value;
    unsigned char direction, junk[32];
    char buf[32];

    fscanf(f, "%d %s 0x%x %c %x @ %s", &count, junk, &port, &direction, &value, junk);
    if (!run)
      printf("%d: Next IO: count=%d, 0x%x %c 0x%x\n", counter++, count, port, direction, value);

    while (1 && !run) {
      printf("> ");
      fgets(buf, sizeof(buf), stdin);
      switch (buf[0]) {
        case 'g':
        case 's':
        case 0x0A:
          break;
        case 'h':
        case '?':
          printf("Available commands: g(o) h(elp) r(un) s(tep) q(uit)\n");
          break;
        case 'r':
          run = true;
          break;
        case 'q':
          exit(0);
          break;
      }
      if (buf[0] == 's' || buf[0] == 'g' || buf[0] == 0x0A)
        break;
    }
    switch (direction) {
      case '<':
        for (int i = 0; i < count; i++) {
//          printf("read from port 0x%x, expecting data 0x%x\n", port, value);
          char data = inb(port);
//          value = ~data;
          if (port == 0x344)
            fwrite(&data, sizeof(data), 1, outfile);
//          if (data != value)
//            printf("");
//            printf("unexpected data, got 0x%x", data);
        }
        break;
      case '>':
        for (int i = 0; i < count; i++) {
//          printf("write to port 0x%x, data 0x%x\n", port, value);
          outb(value, port);
        }
        break;
      default:
        fprintf(stderr, "Error in trace file\n");
        return 1;
    }
  }

  fclose(f);
  return 0;
}

