/* See LICENSE file for copyright and license details. */
#include <stdlib.h>
#include <string.h>

#include "utf.h"
#include "util.h"

struct fdescr {
	FILE *fp;
	const char *name;
};

static void
sequential(struct fdescr *dsc, int fdescrlen, Rune *delim, size_t delimlen)
{
	Rune c, last;
	size_t i, d;

	for (i = 0; i < fdescrlen; i++) {
		d = 0;
		last = 0;

		while (efgetrune(&c, dsc[i].fp, dsc[i].name)) {
			if (last == '\n') {
				if (delim[d] != '\0')
					efputrune(&delim[d], stdout, "<stdout>");
				d = (d + 1) % delimlen;
			}

			if (c != '\n')
				efputrune(&c, stdout, "<stdout>");
			last = c;
		}

		if (last == '\n')
			efputrune(&last, stdout, "<stdout>");
	}
}

static void
parallel(struct fdescr *dsc, int fdescrlen, Rune *delim, size_t delimlen)
{
	Rune c, d;
	size_t i, m;
	ssize_t last;

nextline:
	last = -1;

	for (i = 0; i < fdescrlen; i++) {
		d = delim[i % delimlen];
		c = 0;

		for (; efgetrune(&c, dsc[i].fp, dsc[i].name) ;) {
			for (m = last + 1; m < i; m++)
				efputrune(&(delim[m % delimlen]), stdout, "<stdout>");
			last = i;
			if (c == '\n') {
				if (i != fdescrlen - 1)
					c = d;
				efputrune(&c, stdout, "<stdout>");
				break;
			}
			efputrune(&c, stdout, "<stdout>");
		}

		if (c == 0 && last != -1) {
			if (i == fdescrlen - 1)
				putchar('\n');
			else
				efputrune(&d, stdout, "<stdout>");
				last++;
		}
	}
	if (last != -1)
		goto nextline;
}

static void
usage(void)
{
	eprintf("usage: %s [-s] [-d list] file ...\n", argv0);
}

int
main(int argc, char *argv[])
{
	struct fdescr *dsc;
	Rune  *delim;
	size_t i, len;
	int    seq = 0;
	char  *adelim = "\t";

	ARGBEGIN {
	case 's':
		seq = 1;
		break;
	case 'd':
		adelim = EARGF(usage());
		break;
	default:
		usage();
	} ARGEND;

	if (argc == 0)
		usage();

	/* populate delimiters */
	unescape(adelim);
	delim = emalloc((utflen(adelim) + 1) * sizeof(*delim));
	len = utftorunestr(adelim, delim);

	/* populate file list */
	dsc = emalloc(argc * sizeof(*dsc));

	for (i = 0; i < argc; i++) {
		if (strcmp(argv[i], "-") == 0)
			dsc[i].fp = stdin;
		else
			dsc[i].fp = fopen(argv[i], "r");
		if (!dsc[i].fp)
			eprintf("fopen %s:", argv[i]);
		dsc[i].name = argv[i];
	}

	if (seq)
		sequential(dsc, argc, delim, len);
	else
		parallel(dsc, argc, delim, len);

	for (i = 0; i < argc; i++)
		fclose(dsc[i].fp);

	return 0;
}