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