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

#define STDIN_NAME "<stdin>"
#define STDOUT_NAME "<stdout>"

/* these are the predicted errors that could occur */
enum error_type{
	FILE_ACCESS,
	FILE_CLOSE,
	FILE_WRITE
};

/* this is an error function that will print to standard error the error that
 * occurred in the program and exit */
void
error(enum error_type type, char *argv0, char *file_name){
	switch(type){
	case FILE_ACCESS:
		fprintf(stderr, "%s: %s: cannot open file\n", argv0, file_name);
		break;
	case FILE_CLOSE:
		fprintf(stderr, "%s: %s: cannot close file\n", argv0, file_name);
		break;
	case FILE_WRITE:
		fprintf(stderr, "%s: %s: cannot write to file\n", argv0, file_name);
		break;
	}
	exit(1);
}

/* print input to output, returns 0 if successful and 1 if unsuccessful */
int
file_copy(FILE *input, FILE *output){
	char c;
	while((c = getc(input)) != EOF)
		if(putc(c, output) == EOF)
			return 1;
	return 0;
}

int
main(int argc, char *argv[]){
	/* the name of the file being printed (for diagnostics) */
	char *file_name;

	/* allocate this ahead of time */
	char *stdin_file_name = STDIN_NAME;

	/* the file pointer of the file being printed */
	FILE *input;

	/* this will always be stdout */
	FILE *output = stdout;

	int i;

	/* whether or not options are being parsed */
	int parsing_opts = 1;

	/* usage with 0 arguments - print standard input to standard output */
	if(argc == 1 && file_copy(stdin, stdout))
		error(FILE_WRITE, argv[0], STDOUT_NAME);
	else if(argc == 1)
		return 0;

	for(i = 1; i < argc; ++i){
		/* parsing options */

		/* after `--`, interpret `--`, `-`, and `-u` as literal
		 * filenames */
		if(parsing_opts && !strcmp(argv[i], "--")){
			parsing_opts = 0;
			continue;

		/* ignore `-u` if still parsing options */
		}else if(parsing_opts && !strcmp(argv[i], "-u"))
			continue;

		/* take `-` to mean standard input if still parsing options */
		else if(parsing_opts && !strcmp(argv[i], "-")){
			file_name = stdin_file_name;
			input = stdin;

		/* non-option; open the file and make sure file_name points to
		 * the right string */
		}else{
			file_name = argv[i];
			input = fopen(file_name, "r");
			if(input == NULL)
				error(FILE_ACCESS, argv[0], file_name);
		}

		/* print input to output */
		if(file_copy(input, output))
			error(FILE_WRITE, argv[0], STDOUT_NAME);

		/* close input file if it's not stdin */
		if(input != stdin && fclose(input))
			error(FILE_CLOSE, argv[0], file_name);
	}

	/* exit successfully */
	return 0;
}
