sbase/paste.c
FRIGN ec8246bbc6 Un-boolify sbase
It actually makes the binaries smaller, the code easier to read
(gems like "val == true", "val == false" are gone) and actually
predictable in the sense of that we actually know what we're
working with (one bitwise operator was quite adventurous and
should now be fixed).

This is also more consistent with the other suckless projects
around which don't use boolean types.
2014-11-14 10:54:20 +00:00

228 lines
3.5 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 <wchar.h>
#include "util.h"
typedef struct {
FILE *fp;
const char *name;
} Fdescr;
static size_t unescape(wchar_t *);
static wint_t in(Fdescr *);
static void out(wchar_t);
static void sequential(Fdescr *, int, const wchar_t *, size_t);
static void parallel(Fdescr *, int, const wchar_t *, size_t);
static void
usage(void)
{
eprintf("usage: %s [-s] [-d list] file...\n", argv0);
}
int
main(int argc, char *argv[])
{
const char *adelim = NULL;
int seq = 0;
wchar_t *delim = NULL;
size_t len;
Fdescr *dsc = NULL;
int i;
setlocale(LC_CTYPE, "");
ARGBEGIN {
case 's':
seq = 1;
break;
case 'd':
adelim = EARGF(usage());
break;
default:
usage();
} ARGEND;
if (argc == 0)
usage();
/* populate delimeters */
if (!adelim)
adelim = "\t";
len = mbstowcs(NULL, adelim, 0);
if (len == (size_t) - 1)
eprintf("invalid delimiter\n");
if (!(delim = malloc((len + 1) * sizeof(*delim))))
eprintf("out of memory\n");
mbstowcs(delim, adelim, len);
len = unescape(delim);
if (len == 0)
eprintf("no delimiters specified\n");
/* populate file list */
if (!(dsc = malloc(argc * sizeof(*dsc))))
eprintf("out of memory\n");
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("can't open '%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++) {
if (dsc[i].fp != stdin)
(void)fclose(dsc[i].fp);
}
free(delim);
free(dsc);
return 0;
}
static size_t
unescape(wchar_t *delim)
{
wchar_t c;
size_t i;
size_t len;
for (i = 0, len = 0; (c = delim[i++]) != '\0'; len++) {
if (c == '\\') {
switch (delim[i++]) {
case 'n':
delim[len] = '\n';
break;
case 't':
delim[len] = '\t';
break;
case '0':
delim[len] = '\0';
break;
case '\\':
delim[len] = '\\';
break;
case '\0':
default:
/* POSIX: unspecified results */
return len;
}
} else
delim[len] = c;
}
return len;
}
static wint_t
in(Fdescr *f)
{
wint_t c = fgetwc(f->fp);
if (c == WEOF && ferror(f->fp))
eprintf("'%s' read error:", f->name);
return c;
}
static void
out(wchar_t c)
{
putwchar(c);
if (ferror(stdout))
eprintf("write error:");
}
static void
sequential(Fdescr *dsc, int len, const wchar_t *delim, size_t cnt)
{
int i;
size_t d;
wint_t c, last;
for (i = 0; i < len; i++) {
d = 0;
last = WEOF;
while ((c = in(&dsc[i])) != WEOF) {
if (last == '\n') {
if (delim[d] != '\0')
out(delim[d]);
d++;
d %= cnt;
}
if (c != '\n')
out((wchar_t)c);
last = c;
}
if (last == '\n')
out((wchar_t)last);
}
}
static void
parallel(Fdescr *dsc, int len, const wchar_t *delim, size_t cnt)
{
int last, i;
wint_t c, o;
wchar_t d;
do {
last = 0;
for (i = 0; i < len; i++) {
d = delim[i % cnt];
do {
o = in(&dsc[i]);
c = o;
switch (c) {
case WEOF:
if (last == 0)
break;
o = '\n';
/* fallthrough */
case '\n':
if (i != len - 1)
o = d;
break;
default:
break;
}
if (o != WEOF) {
/* pad with delimiters up to this point */
while (++last < i) {
if (d != '\0')
out(d);
}
out((wchar_t)o);
}
} while (c != '\n' && c != WEOF);
}
} while (last > 0);
}