Introduction
Introduction Statistics Contact Development Disclaimer Help
cut.c - sbase - suckless unix tools
git clone git://git.suckless.org/sbase
Log
Files
Refs
README
LICENSE
---
cut.c (4145B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "text.h"
7 #include "utf.h"
8 #include "util.h"
9
10 typedef struct Range {
11 size_t min, max;
12 struct Range *next;
13 } Range;
14
15 static Range *list = NULL;
16 static char mode = 0;
17 static char *delim = "\t";
18 static size_t delimlen = 1;
19 static int nflag = 0;
20 static int sflag = 0;
21
22 static void
23 insert(Range *r)
24 {
25 Range *l, *p, *t;
26
27 for (p = NULL, l = list; l; p = l, l = l->next) {
28 if (r->max && r->max + 1 < l->min) {
29 r->next = l;
30 break;
31 } else if (!l->max || r->min < l->max + 2) {
32 l->min = MIN(r->min, l->min);
33 for (p = l, t = l->next; t; p = t, t = t->next)
34 if (r->max && r->max + 1 < t->min)
35 break;
36 l->max = (p->max && r->max) ? MAX(p->max, r->max…
37 l->next = t;
38 return;
39 }
40 }
41 if (p)
42 p->next = r;
43 else
44 list = r;
45 }
46
47 static void
48 parselist(char *str)
49 {
50 char *s;
51 size_t n = 1;
52 Range *r;
53
54 if (!*str)
55 eprintf("empty list\n");
56 for (s = str; *s; s++) {
57 if (*s == ' ')
58 *s = ',';
59 if (*s == ',')
60 n++;
61 }
62 r = ereallocarray(NULL, n, sizeof(*r));
63 for (s = str; n; n--, s++) {
64 r->min = (*s == '-') ? 1 : strtoul(s, &s, 10);
65 r->max = (*s == '-') ? strtoul(s + 1, &s, 10) : r->min;
66 r->next = NULL;
67 if (!r->min || (r->max && r->max < r->min) || (*s && *s …
68 eprintf("bad list value\n");
69 insert(r++);
70 }
71 }
72
73 static size_t
74 seek(struct line *s, size_t pos, size_t *prev, size_t count)
75 {
76 size_t n = pos - *prev, i, j;
77
78 if (mode == 'b') {
79 if (n >= s->len)
80 return s->len;
81 if (nflag)
82 while (n && !UTF8_POINT(s->data[n]))
83 n--;
84 *prev += n;
85 return n;
86 } else if (mode == 'c') {
87 for (n++, i = 0; i < s->len; i++)
88 if (UTF8_POINT(s->data[i]) && !--n)
89 break;
90 } else {
91 for (i = (count < delimlen + 1) ? 0 : delimlen; n && i <…
92 if ((s->len - i) >= delimlen &&
93 !memcmp(s->data + i, delim, delimlen)) {
94 if (!--n && count)
95 break;
96 i += delimlen;
97 continue;
98 }
99 for (j = 1; j + i <= s->len && !fullrune(s->data…
100 i += j;
101 }
102 }
103 *prev = pos;
104
105 return i;
106 }
107
108 static void
109 cut(FILE *fp, const char *fname)
110 {
111 Range *r;
112 struct line s;
113 static struct line line;
114 static size_t size;
115 size_t i, n, p;
116 ssize_t len;
117
118 while ((len = getline(&line.data, &size, fp)) > 0) {
119 line.len = len;
120 if (line.data[line.len - 1] == '\n')
121 line.data[--line.len] = '\0';
122 if (mode == 'f' && !memmem(line.data, line.len, delim, d…
123 if (!sflag) {
124 fwrite(line.data, 1, line.len, stdout);
125 fputc('\n', stdout);
126 }
127 continue;
128 }
129 for (i = 0, p = 1, s = line, r = list; r; r = r->next) {
130 n = seek(&s, r->min, &p, i);
131 s.data += n;
132 s.len -= n;
133 i += (mode == 'f') ? delimlen : 1;
134 if (!s.len)
135 break;
136 if (!r->max) {
137 fwrite(s.data, 1, s.len, stdout);
138 break;
139 }
140 n = seek(&s, r->max + 1, &p, i);
141 i += (mode == 'f') ? delimlen : 1;
142 if (fwrite(s.data, 1, n, stdout) != n)
143 eprintf("fwrite <stdout>:");
144 s.data += n;
145 s.len -= n;
146 }
147 putchar('\n');
148 }
149 if (ferror(fp))
150 eprintf("getline %s:", fname);
151 }
152
153 static void
154 usage(void)
155 {
156 eprintf("usage: %s -b list [-n] [file ...]\n"
157 " %s -c list [file ...]\n"
158 " %s -f list [-d delim] [-s] [file ...]\n",
159 argv0, argv0, argv0);
160 }
161
162 int
163 main(int argc, char *argv[])
164 {
165 FILE *fp;
166 int ret = 0;
167
168 ARGBEGIN {
169 case 'b':
170 case 'c':
171 case 'f':
172 mode = ARGC();
173 parselist(EARGF(usage()));
174 break;
175 case 'd':
176 delim = EARGF(usage());
177 if (!*delim)
178 eprintf("empty delimiter\n");
179 delimlen = unescape(delim);
180 break;
181 case 'n':
182 nflag = 1;
183 break;
184 case 's':
185 sflag = 1;
186 break;
187 default:
188 usage();
189 } ARGEND
190
191 if (!mode)
192 usage();
193
194 if (!argc)
195 cut(stdin, "<stdin>");
196 else {
197 for (; *argv; argc--, argv++) {
198 if (!strcmp(*argv, "-")) {
199 *argv = "<stdin>";
200 fp = stdin;
201 } else if (!(fp = fopen(*argv, "r"))) {
202 weprintf("fopen %s:", *argv);
203 ret = 1;
204 continue;
205 }
206 cut(fp, *argv);
207 if (fp != stdin && fshut(fp, *argv))
208 ret = 1;
209 }
210 }
211
212 ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
213
214 return ret;
215 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.