paste.c revision 8e9ec867e5753e63778d67c3cb1cce68792f7b24
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 *
7USE_PASTE(NEWTOY(paste, "d:s", TOYFLAG_BIN))
8
9config 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
25GLOBALS(
26  char *delim;
27)
28
29void paste_main(void)
30{
31  char *p, *buf = toybuf;
32  char **args = toys.optargs;
33  size_t ndelim = 0;
34  int i, j, c;
35
36  // Process delimiter list
37  // TODO: Handle multibyte characters
38  if (!(toys.optflags & FLAG_d)) TT.delim = "\t";
39  p = TT.delim;
40  for (; *p; p++, buf++, ndelim++) {
41    if (*p == '\\') {
42      p++;
43      if (-1 == (i = stridx("nt\\0", *p)))
44        error_exit("bad delimiter: \\%c", *p);
45      *buf = "\n\t\\\0"[i];
46    }
47    else *buf = *p;
48  }
49  *buf = 0;
50
51  if (toys.optflags & FLAG_s) { // Sequential
52    FILE *f;
53    for (; *args; args++) {
54      if ((*args)[0] == '-' && !(*args)[1]) f = stdin;
55      else if (!(f = fopen(*args, "r"))) perror_exit("%s", *args);
56      for (i = 0, c = 0; c != EOF;) {
57        switch(c = getc(f)) {
58        case '\n':
59          putchar(toybuf[i++ % ndelim]);
60        case EOF:
61          break;
62        default:
63          putchar(c);
64        }
65      }
66      if (f != stdin) fclose(f);
67      putchar('\n');
68    }
69  }
70  else { // Parallel
71    // Need to be careful not to print an extra line at the end
72    FILE **files;
73    int anyopen = 1;
74    files = (FILE**)(buf + 1);
75    for (; *args; args++, files++) {
76      if ((*args)[0] == '-' && !(*args)[1]) *files = stdin;
77      else if (!(*files = fopen(*args, "r"))) perror_exit("%s", *args);
78    }
79    for (; anyopen;) {
80      anyopen = 0;
81      for (i = 0; i < toys.optc; i++) {
82        FILE **f = (FILE**)(buf + 1) + i;
83        if (*f) for (;;) {
84          c = getc(*f);
85          if (c != EOF) {
86            if (!anyopen++) for (j = 0; j < i; j++) putchar(toybuf[j % ndelim]);
87            if (c != '\n') putchar(c);
88            else break;
89          }
90          else {
91            if (*f != stdin) fclose(*f);
92            *f = 0;
93            break;
94          }
95        }
96        if (anyopen) putchar((i + 1 == toys.optc) ? toybuf[i % ndelim] : '\n');
97      }
98    }
99  }
100}
101