/*
 * Copyright (C) 2016 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#define COUNT	256

#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *progname;
char *inname0;
char *inname1;

static void
do_work(void)
{
	FILE *fp0;
	FILE *fp1;
	char buf0[1024*1024];
	char line0[COUNT][1024];
	int count0;
	char buf1[1024*1024];
	char line1[COUNT][1024];
	int count1;
	int n0;
	int n1;
	int skip0;
	int skip1;
	int out0;
	int out1;
	char *l0;
	char *l1;
	int i, j;
	int ret;

	/*
	 * Open files.
	 */
	fp0 = fopen(inname0, "r");
	if (! fp0) {
		fprintf(stderr, "%s: ERROR: %s: %s.\n",
				progname, inname0, strerror(errno));
		exit(1);
	}
	setbuffer(fp0, buf0, sizeof(buf0));
	fp1 = fopen(inname1, "r");
	if (! fp1) {
		fprintf(stderr, "%s: ERROR: %s: %s.\n",
				progname, inname1, strerror(errno));
		exit(1);
	}
	setbuffer(fp1, buf1, sizeof(buf1));

	count0 = 0;
	n0 = 1;
	count1 = 0;
	n1 = 1;

	for (;;) {
		/*
		 * Fill buffers.
		 */
		while (count0 < COUNT) {
			l0 = fgets(line0[count0], sizeof(line0[count0]), fp0);
			if (! l0) {
				break;
			}
			count0++;
		}
		while (count1 < COUNT) {
			l1 = fgets(line1[count1], sizeof(line1[count1]), fp1);
			if (! l1) {
				break;
			}
			count1++;
		}
		if (count0 == 0 && count1 == 0) {
			break;

		} else if (count0 == 0) {
			skip0 = 0;
			out0 = 0;
			skip1 = 1;
			out1 = 1;

		} else if (count1 == 0) {
			skip0 = 1;
			out0 = 1;
			skip1 = 0;
			out1 = 0;

		} else {
			if (strcmp(line0[0], line1[0]) == 0) {
				skip0 = 1;
				out0 = 0;
				skip1 = 1;
				out1 = 0;

			} else for (i = 1; ; i++) {
				if (i == COUNT) {
					skip0 = 1;
					out0 = 1;
					skip1 = 1;
					out1 = 1;
					break;
				}
				for (j = 0; j <= i; j++) {
					if (j < count1
					 && i - j < count0
					 && strcmp(line0[i - j], line1[j]) == 0) {
						skip0 = i - j;
						out0 = i - j;
						skip1 = j;
						out1 = j;
						goto found;
					}
				}
			}
		found:	;
		}

		for (i = 0; i < out0; i++) {
			printf("%d: > %s", n0 + i, line0[i]);
		}
		for (i = 0; i < out1; i++) {
			printf("%d: < %s", n1 + i, line1[i]);
		}
		if (out0 || out1) {
			printf("\n");
		}

		if (skip0) {
			for (i = 0; i < COUNT - skip0; i++) {
				strcpy(line0[i], line0[i + skip0]);
			}
			count0 -= skip0;
			n0 += skip0;
		}
		if (skip1) {
			for (i = 0; i < COUNT - skip1; i++) {
				strcpy(line1[i], line1[i + skip1]);
			}
			count1 -= skip1;
			n1 += skip1;
		}
	}

	/*
	 * Close files.
	 */
	ret = fclose(fp1);
	assert(0 <= ret);

	ret = fclose(fp0);
	assert(0 <= ret);
}

static void __attribute__((__noreturn__))
usage(int retval)
{
	fprintf(stderr, "Usage: %s <file0> <file1>\n", progname);
	exit(retval);
}

int
main(int argc, char **argv)
{
	int c;

	progname = *argv;

	while ((c = getopt(argc, argv, "")) != -1) {
		switch (c) {
		default:
			usage(1);
			/*NOTREACHED*/
		}
	}
	argc -= optind;
	argv += optind;

	if (0 < argc) {
		inname0 = *argv;
		argc--;
		argv++;
	} else {
		usage(1);
		/*NOTREACHED*/
	}
	if (0 < argc) {
		inname1 = *argv;
		argc--;
		argv++;
	} else {
		usage(1);
		/*NOTREACHED*/
	}
	if (argc != 0) {
		usage(1);
		/*NOTREACHED*/
	}

	do_work();

	return 0;
}
