paste.c - sbase - suckless unix tools | |
git clone git://git.suckless.org/sbase | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
paste.c (2734B) | |
--- | |
1 /* See LICENSE file for copyright and license details. */ | |
2 #include <stdlib.h> | |
3 #include <string.h> | |
4 | |
5 #include "utf.h" | |
6 #include "util.h" | |
7 | |
8 struct fdescr { | |
9 FILE *fp; | |
10 const char *name; | |
11 }; | |
12 | |
13 static void | |
14 sequential(struct fdescr *dsc, int fdescrlen, Rune *delim, size_t deliml… | |
15 { | |
16 Rune c, last; | |
17 size_t i, d; | |
18 | |
19 for (i = 0; i < fdescrlen; i++) { | |
20 d = 0; | |
21 last = 0; | |
22 | |
23 while (efgetrune(&c, dsc[i].fp, dsc[i].name)) { | |
24 if (last == '\n') { | |
25 if (delim[d] != '\0') | |
26 efputrune(&delim[d], stdout, "<s… | |
27 d = (d + 1) % delimlen; | |
28 } | |
29 | |
30 if (c != '\n') | |
31 efputrune(&c, stdout, "<stdout>"); | |
32 last = c; | |
33 } | |
34 | |
35 if (last == '\n') | |
36 efputrune(&last, stdout, "<stdout>"); | |
37 } | |
38 } | |
39 | |
40 static void | |
41 parallel(struct fdescr *dsc, int fdescrlen, Rune *delim, size_t delimlen) | |
42 { | |
43 Rune c, d; | |
44 size_t i, m; | |
45 ssize_t last; | |
46 | |
47 nextline: | |
48 last = -1; | |
49 | |
50 for (i = 0; i < fdescrlen; i++) { | |
51 d = delim[i % delimlen]; | |
52 c = 0; | |
53 | |
54 while (efgetrune(&c, dsc[i].fp, dsc[i].name)) { | |
55 for (m = last + 1; m < i; m++) { | |
56 if (delim[m % delimlen] != '\0') | |
57 efputrune(&delim[m % delimlen], … | |
58 } | |
59 last = i; | |
60 if (c == '\n') { | |
61 if (i != fdescrlen - 1) | |
62 c = d; | |
63 efputrune(&c, stdout, "<stdout>"); | |
64 break; | |
65 } | |
66 efputrune(&c, stdout, "<stdout>"); | |
67 } | |
68 | |
69 if (c == 0 && last != -1) { | |
70 if (i == fdescrlen - 1) | |
71 putchar('\n'); | |
72 else if (d != '\0') | |
73 efputrune(&d, stdout, "<stdout>"); | |
74 last++; | |
75 } | |
76 } | |
77 if (last != -1) | |
78 goto nextline; | |
79 } | |
80 | |
81 static void | |
82 usage(void) | |
83 { | |
84 eprintf("usage: %s [-s] [-d list] file ...\n", argv0); | |
85 } | |
86 | |
87 int | |
88 main(int argc, char *argv[]) | |
89 { | |
90 struct fdescr *dsc; | |
91 Rune *delim_rune = NULL; | |
92 size_t delim_runelen, i, delim_bytelen = 1; | |
93 int seq = 0, ret = 0; | |
94 char *delim = "\t"; | |
95 | |
96 ARGBEGIN { | |
97 case 's': | |
98 seq = 1; | |
99 break; | |
100 case 'd': | |
101 delim = EARGF(usage()); | |
102 delim_bytelen = unescape(delim); | |
103 break; | |
104 default: | |
105 usage(); | |
106 } ARGEND | |
107 | |
108 if (!argc) | |
109 usage(); | |
110 | |
111 /* populate delimiters */ | |
112 delim_rune = ereallocarray(NULL, | |
113 utfmemlen(delim, delim_bytelen) + 1, sizeof(*delim_rune)… | |
114 if (!(delim_runelen = utfntorunestr(delim, delim_bytelen, delim_… | |
115 usage(); | |
116 } | |
117 | |
118 /* populate file list */ | |
119 dsc = ereallocarray(NULL, argc, sizeof(*dsc)); | |
120 | |
121 for (i = 0; i < argc; i++) { | |
122 if (!strcmp(argv[i], "-")) { | |
123 argv[i] = "<stdin>"; | |
124 dsc[i].fp = stdin; | |
125 } else if (!(dsc[i].fp = fopen(argv[i], "r"))) { | |
126 eprintf("fopen %s:", argv[i]); | |
127 } | |
128 dsc[i].name = argv[i]; | |
129 } | |
130 | |
131 if (seq) { | |
132 sequential(dsc, argc, delim_rune, delim_runelen); | |
133 } else { | |
134 parallel(dsc, argc, delim_rune, delim_runelen); | |
135 } | |
136 | |
137 for (i = 0; i < argc; i++) | |
138 if (dsc[i].fp != stdin && fshut(dsc[i].fp, argv[i])) | |
139 ret |= fshut(dsc[i].fp, argv[i]); | |
140 | |
141 ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"); | |
142 | |
143 return ret; | |
144 } |