1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38#define FOR_cut
39#include "toys.h"
40
41GLOBALS(
42 char *d;
43 char *O;
44 struct arg_list *select[5];
45
46 int pairs;
47 regex_t reg;
48)
49
50
51
52int unicolumns(char *start, unsigned columns)
53{
54 int i, j = 0;
55 wchar_t wc;
56 char *s = start, *ss = start;
57
58
59 while (j<columns && (i = utf8towc(&wc, s, 4))) {
60 if (i<0) s++;
61 else {
62 s += i;
63 if (0<(i = wcwidth(wc))) {
64 if ((j += i)>columns) break;
65 ss = s;
66 }
67 }
68 }
69
70 return ss-start;
71}
72
73
74
75static void cut_line(char **pline, long len)
76{
77 unsigned *pairs = (void *)toybuf;
78 char *line = *pline;
79 int i, j;
80
81 if (len && line[len-1]=='\n') line[--len] = 0;
82
83
84 for (i=0; i<TT.pairs; i++) {
85 unsigned start = pairs[2*i], end = pairs[(2*i)+1], count;
86 char *s = line, *ss;
87
88
89
90
91 if (start) start--;
92 if (start>=len) continue;
93 if (!end || end>len) end = len;
94 count = end-start;
95
96
97 if (toys.optflags&FLAG_b) s += start;
98 else if (toys.optflags&FLAG_C) {
99
100
101
102
103
104
105
106
107
108
109 s += unicolumns(s, start);
110 count = unicolumns(s, end-start);
111 } else if (toys.optflags&FLAG_c) {
112 wchar_t wc;
113 char *sss;
114
115
116 ss = line+len;
117 while (start && s<ss) {
118 if (0<=(j = utf8towc(&wc, s, len))) start--;
119 s += (j<1) ? 1 : j;
120 }
121 if (s == ss) continue;
122
123
124 end = count;
125 sss = s;
126 while (end && sss<ss) {
127 if (0<=(j = utf8towc(&wc, sss, len))) end--;
128 sss += (j<1) ? 1 : j;
129 }
130 count = sss-s;
131 } else {
132 regmatch_t match;
133
134
135 for (j = 0; j<2; j++) {
136 ss = s;
137 if (j) start = count;
138 else end = start;
139 while (*ss && start) {
140 if (toys.optflags&FLAG_f) {
141 if (!strchr(TT.d, *ss++)) continue;
142 if (!--start && j) ss--;
143 } else {
144 if (regexec(&TT.reg, ss, 1, &match, REG_NOTBOL|REG_NOTEOL)) {
145 ss = line+len;
146 continue;
147 }
148 if (!match.rm_eo) break;
149 ss += (!--start && j) ? match.rm_so : match.rm_eo;
150 }
151 }
152 if (!j && !*(s = ss)) break;
153 }
154
155
156 if (!j && end == start) {
157 if (toys.optflags&FLAG_s) return;
158 fwrite(line, len, 1, stdout);
159 break;
160 } else if (!*s) continue;
161 count = ss-s;
162 }
163 if (i && TT.O) fputs(TT.O, stdout);
164 fwrite(s, count, 1, stdout);
165 }
166 xputc('\n');
167}
168
169static int compar(unsigned *a, unsigned *b)
170{
171 if (*a<*b) return -1;
172 if (*a>*b) return 1;
173 if (a[1]<b[1]) return -1;
174 if (a[1]>b[1]) return 1;
175
176 return 0;
177}
178
179
180static char *get_range(void *data, char *str, int len)
181{
182 char *end = str;
183 unsigned *pairs = (void *)toybuf, i;
184
185
186 if (TT.pairs == sizeof(toybuf)/sizeof(int)) perror_exit("select limit");
187 pairs += 2*TT.pairs++;
188
189 pairs[1] = UINT_MAX;
190 for (i = 0; ;i++) {
191 if (i==2) return end;
192 if (isdigit(*end)) {
193 long long ll = estrtol(end, &end, 10);
194
195 if (ll<1 || ll>UINT_MAX || errno) return end;
196 pairs[i] = ll;
197 }
198 if (*end++ != '-') break;
199 }
200 if (!i) pairs[1] = pairs[0];
201 if ((end-str)<len) return end;
202 if (pairs[0]>pairs[1]) return str;
203
204
205 return 0;
206}
207
208void cut_main(void)
209{
210 int i;
211 char buf[8];
212
213
214 if ((toys.optflags&(FLAG_s|FLAG_f|FLAG_F))==FLAG_s)
215 error_exit("-s needs -Ff");
216 if ((toys.optflags&(FLAG_d|FLAG_f|FLAG_F))==FLAG_d)
217 error_exit("-d needs -Ff");
218 if (!TT.d) TT.d = (toys.optflags&FLAG_F) ? "[[:space:]][[:space:]]*" : "\t";
219 if (toys.optflags&FLAG_F) xregcomp(&TT.reg, TT.d, REG_EXTENDED);
220 if (!TT.O) {
221 if (toys.optflags&FLAG_F) TT.O = " ";
222 else if (toys.optflags&FLAG_f) TT.O = TT.d;
223 }
224
225
226 for (i = 0; i<ARRAY_LEN(TT.select); i++) {
227 sprintf(buf, "bad -%c", "CFfcb"[i]);
228 if (TT.select[i]) comma_args(TT.select[i], 0, buf, get_range);
229 }
230 if (!TT.pairs) error_exit("no selections");
231
232
233 if (!(toys.optflags&FLAG_D)) {
234 int from, to;
235 unsigned *pairs = (void *)toybuf;
236
237 qsort(toybuf, TT.pairs, 8, (void *)compar);
238 for (to = 0, from = 2; from/2 < TT.pairs; from += 2) {
239 if (pairs[from] > pairs[to+1]) {
240 to += 2;
241 memcpy(pairs+to, pairs+from, 2*sizeof(unsigned));
242 } else if (pairs[from+1] > pairs[to+1]) pairs[to+1] = pairs[from+1];
243 }
244 TT.pairs = (to/2)+1;
245 }
246
247
248 loopfiles_lines(toys.optargs, cut_line);
249}
250