aboutsummaryrefslogtreecommitdiff
path: root/toys/posix/paste.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/posix/paste.c')
-rw-r--r--toys/posix/paste.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/toys/posix/paste.c b/toys/posix/paste.c
new file mode 100644
index 00000000..92a52534
--- /dev/null
+++ b/toys/posix/paste.c
@@ -0,0 +1,100 @@
+/* paste.c - Replace newlines
+ *
+ * Copyright 2012 Felix Janda <felix.janda@posteo.de>
+ *
+ * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/paste.html
+ *
+USE_PASTE(NEWTOY(paste, "d:s", TOYFLAG_BIN))
+
+config PASTE
+ bool "paste"
+ default y
+ help
+ usage: paste [-s] [-d list] [file...]
+
+ Replace newlines in files.
+
+ -d list list of delimiters to separate lines
+ -s process files sequentially instead of in parallel
+
+ By default print corresponding lines separated by <tab>.
+*/
+#define FOR_paste
+#include "toys.h"
+
+GLOBALS(
+ char *delim;
+)
+
+void paste_main(void)
+{
+ char *p, *buf = toybuf;
+ char **args = toys.optargs;
+ size_t ndelim = 0;
+ int i, j, c;
+
+ // Process delimiter list
+ // TODO: Handle multibyte characters
+ if (!(toys.optflags & FLAG_d)) TT.delim = "\t";
+ p = TT.delim;
+ for (; *p; p++, buf++, ndelim++) {
+ if (*p == '\\') {
+ p++;
+ if (-1 == (i = stridx("nt\\0", *p)))
+ error_exit("bad delimiter: \\%c", *p);
+ *buf = "\n\t\\\0"[i];
+ }
+ else *buf = *p;
+ }
+ *buf = 0;
+
+ if (toys.optflags & FLAG_s) { // Sequential
+ FILE *f;
+ for (; *args; args++) {
+ if ((*args)[0] == '-' && !(*args)[1]) f = stdin;
+ else if (!(f = fopen(*args, "r"))) perror_exit("%s", *args);
+ for (i = 0, c = 0; c != EOF;) {
+ switch(c = getc(f)) {
+ case '\n':
+ putchar(toybuf[i++ % ndelim]);
+ case EOF:
+ break;
+ default:
+ putchar(c);
+ }
+ }
+ if (f != stdin) fclose(f);
+ putchar('\n');
+ }
+ }
+ else { // Parallel
+ // Need to be careful not to print an extra line at the end
+ FILE **files;
+ int anyopen = 1;
+ files = (FILE**)(buf + 1);
+ for (; *args; args++, files++) {
+ if ((*args)[0] == '-' && !(*args)[1]) *files = stdin;
+ else if (!(*files = fopen(*args, "r"))) perror_exit("%s", *args);
+ }
+ for (; anyopen;) {
+ anyopen = 0;
+ for (i = 0; i < toys.optc; i++) {
+ FILE **f = (FILE**)(buf + 1) + i;
+ if (*f) for (;;) {
+ c = getc(*f);
+ if (c != EOF) {
+ if (!anyopen++) for (j = 0; j < i; j++) putchar(toybuf[j % ndelim]);
+ if (c != '\n') putchar(c);
+ else break;
+ }
+ else {
+ if (*f != stdin) fclose(*f);
+ *f = 0;
+ break;
+ }
+ }
+ if (anyopen) putchar((i + 1 == toys.optc) ? toybuf[i % ndelim] : '\n');
+ }
+ }
+ }
+}