#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned char uchar;
typedef unsigned int uint;

#define MAX_KEY_SIZE 80

uchar key[MAX_KEY_SIZE], add, t;
uchar state[256];
uint key_length;

#define swap_byte(x,y) t = *(x); *(x) = *(y); *(y) = t

/* ================================================================= */

void initialize_machine(void) {
  short x, y;

  for(x = 0; x < 256; x++)
    state[x] = x;
  for(x = 0; x < 256; x++) {
    y = x % key_length;
    add += state[x] + key[y] + y;
    swap_byte(&state[x], &state[add]);
  }
}

void propagate_machine(uchar x) {

  add = add + state[x];
  swap_byte(&state[x], &state[add]);
  add = state[x] + state[add];
}

/* ================================================================= */

uchar encrypt_char(uchar x) {
  uchar y;

  y = x ^ a;
  propagate_machine(x);
  return y;
}

uchar decrypt_char(uchar y) {
  uchar x;

  x = y ^ xor;
  propagate_machine(x);
  return x;
}

/* ================================================================= */

char help_string[] =
"Usage: zc4 <infile> <key> <outfile> [<flag>]\n"
"The input file is to be encrypted or decrypted.\n"
"The key is any ASCII string. If it includes spaces, enclose it\n"
"    in double quotes. Also, it can't include '<' or '>' or '|'\n"
"    which all have special meanings on the DOS command line.\n"
"The output file is the result.\n"
"The optional flag is any ASCII string; it selects\n"
"    decryption instead of encryption.\n";

void help(void) {
  printf("%s", help_string);
  exit(0);
}

void main(int argc, char *argv[]) {
  int c;
  FILE *f, *g;

  if (argc < 4) help();

  if ((f = fopen(argv[1], "rb")) == NULL) help();

  strcpy(key, argv[2]);
  key_length = strlen(key);

  if ((g = fopen(argv[3], "wb")) == NULL) help();

  initialize_machine();

  while (1) {
    c = fgetc(f);
    if (c == -1 || feof(f)) {
      fclose(f);
      fclose(g);
      return;
    }

    if (argc == 4) c = encrypt_char(c);
    else c = decrypt_char(c);

    fputc(c, g);
  }
}
