1 /* paste.c - Replace newlines
2  *
3  * Copyright 2012 Felix Janda <felix.janda@posteo.de>
4  *
5  * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/paste.html
6  *
7 USE_PASTE(NEWTOY(paste, "d:s", TOYFLAG_BIN))
8 
9 config PASTE
10   bool "paste"
11   default y
12   help
13     usage: paste [-s] [-d list] [file...]
14 
15     Replace newlines in files.
16 
17     -d list    list of delimiters to separate lines
18     -s         process files sequentially instead of in parallel
19 
20     By default print corresponding lines separated by <tab>.
21 */
22 #define FOR_paste
23 #include "toys.h"
24 
GLOBALS(char * delim;)25 GLOBALS(
26   char *delim;
27 )
28 
29 void paste_main(void)
30 {
31   char *p, *buf = toybuf, **args = toys.optargs;
32   size_t ndelim = 0;
33   int i, j, c;
34 
35   // Process delimiter list
36   // TODO: Handle multibyte characters
37   if (!(toys.optflags & FLAG_d)) TT.delim = "\t";
38   for (p = TT.delim; *p; p++, buf++, ndelim++) {
39     if (*p == '\\') {
40       p++;
41       if (-1 == (i = stridx("nt\\0", *p)))
42         error_exit("bad delimiter: \\%c", *p);
43       *buf = "\n\t\\\0"[i];
44     } else *buf = *p;
45   }
46   *buf = 0;
47 
48   if (toys.optflags & FLAG_s) { // Sequential
49     FILE *f;
50 
51     for (; *args; args++) {
52       if ((*args)[0] == '-' && !(*args)[1]) f = stdin;
53       else if (!(f = fopen(*args, "r"))) perror_exit("%s", *args);
54       for (i = 0, c = 0; c != EOF;) {
55         switch(c = getc(f)) {
56         case '\n':
57           putchar(toybuf[i++ % ndelim]);
58         case EOF:
59           break;
60         default:
61           putchar(c);
62         }
63       }
64       if (f != stdin) fclose(f);
65       putchar('\n');
66     }
67   } else { // Parallel
68     // Need to be careful not to print an extra line at the end
69     FILE **files;
70     int anyopen = 1;
71 
72     files = (FILE**)(buf + 1);
73     for (; *args; args++, files++) {
74       if ((*args)[0] == '-' && !(*args)[1]) *files = stdin;
75       else if (!(*files = fopen(*args, "r"))) perror_exit("%s", *args);
76     }
77     while (anyopen) {
78       anyopen = 0;
79       for (i = 0; i < toys.optc; i++) {
80         FILE **f = (FILE**)(buf + 1) + i;
81 
82         if (*f) for (;;) {
83           c = getc(*f);
84           if (c != EOF) {
85             if (!anyopen++) for (j = 0; j < i; j++) putchar(toybuf[j % ndelim]);
86             if (c != '\n') putchar(c);
87             else break;
88           }
89           else {
90             if (*f != stdin) fclose(*f);
91             *f = 0;
92             break;
93           }
94         }
95         if (anyopen) putchar((i + 1 == toys.optc) ? toybuf[i % ndelim] : '\n');
96       }
97     }
98   }
99 }
100