a5ae899a48
Interface as proposed by cls, but internally rewritten after a few considerations. The code is much shorter and to the point, aligning itself with other standard functions. It should also be much faster, which is not bad.
138 lines
2.3 KiB
C
138 lines
2.3 KiB
C
/* See LICENSE file for copyright and license details. */
|
|
#include <locale.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.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')
|
|
writerune("<stdout>", stdout, &delim[d]);
|
|
d = (d + 1) % delimlen;
|
|
}
|
|
|
|
if (c != '\n')
|
|
writerune("<stdout>", stdout, &c);
|
|
last = c;
|
|
}
|
|
|
|
if (last == '\n')
|
|
writerune("<stdout>", stdout, &last);
|
|
}
|
|
}
|
|
|
|
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++)
|
|
writerune("<stdout>", stdout, &(delim[m % delimlen]));
|
|
last = i;
|
|
if (c == '\n') {
|
|
if (i != fdescrlen - 1)
|
|
c = d;
|
|
writerune("<stdout>", stdout, &c);
|
|
break;
|
|
}
|
|
writerune("<stdout>", stdout, &c);
|
|
}
|
|
|
|
if (c == 0 && last != -1) {
|
|
if (i == fdescrlen - 1)
|
|
putchar('\n');
|
|
else
|
|
writerune("<stdout>", stdout, &d);
|
|
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);
|
|
len = chartorunearr(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;
|
|
}
|