uniq.c - sbase - suckless unix tools | |
git clone git://git.suckless.org/sbase | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
uniq.c (2526B) | |
--- | |
1 /* See LICENSE file for copyright and license details. */ | |
2 #include <ctype.h> | |
3 #include <stdio.h> | |
4 #include <stdlib.h> | |
5 #include <string.h> | |
6 | |
7 #include "text.h" | |
8 #include "util.h" | |
9 | |
10 static const char *countfmt = ""; | |
11 static int dflag = 0; | |
12 static int uflag = 0; | |
13 static int fskip = 0; | |
14 static int sskip = 0; | |
15 | |
16 static struct line prevl; | |
17 static ssize_t prevoff = -1; | |
18 static long prevlinecount = 0; | |
19 | |
20 static size_t | |
21 uniqskip(struct line *l) | |
22 { | |
23 size_t i; | |
24 int f = fskip, s = sskip; | |
25 | |
26 for (i = 0; i < l->len && f; --f) { | |
27 while (isblank(l->data[i])) | |
28 i++; | |
29 while (i < l->len && !isblank(l->data[i])) | |
30 i++; | |
31 } | |
32 for (; s && i < l->len && l->data[i] != '\n'; --s, i++) | |
33 ; | |
34 | |
35 return i; | |
36 } | |
37 | |
38 static void | |
39 uniqline(FILE *ofp, struct line *l) | |
40 { | |
41 size_t loff; | |
42 | |
43 if (l) { | |
44 loff = uniqskip(l); | |
45 | |
46 if (prevoff >= 0 && (l->len - loff) == (prevl.len - prev… | |
47 !memcmp(l->data + loff, prevl.data + prevoff, l->len… | |
48 ++prevlinecount; | |
49 return; | |
50 } | |
51 } | |
52 | |
53 if (prevoff >= 0) { | |
54 if ((prevlinecount == 1 && !dflag) || | |
55 (prevlinecount != 1 && !uflag)) { | |
56 if (*countfmt) | |
57 fprintf(ofp, countfmt, prevlinecount); | |
58 fwrite(prevl.data, 1, prevl.len, ofp); | |
59 } | |
60 prevoff = -1; | |
61 } | |
62 | |
63 if (l) { | |
64 if (!prevl.data || l->len >= prevl.len) { | |
65 prevl.data = erealloc(prevl.data, l->len); | |
66 } | |
67 prevl.len = l->len; | |
68 memcpy(prevl.data, l->data, prevl.len); | |
69 prevoff = loff; | |
70 } | |
71 prevlinecount = 1; | |
72 } | |
73 | |
74 static void | |
75 uniq(FILE *fp, FILE *ofp) | |
76 { | |
77 static struct line line; | |
78 static size_t size; | |
79 ssize_t len; | |
80 | |
81 while ((len = getline(&line.data, &size, fp)) > 0) { | |
82 line.len = len; | |
83 uniqline(ofp, &line); | |
84 } | |
85 } | |
86 | |
87 static void | |
88 uniqfinish(FILE *ofp) | |
89 { | |
90 uniqline(ofp, NULL); | |
91 } | |
92 | |
93 static void | |
94 usage(void) | |
95 { | |
96 eprintf("usage: %s [-c] [-d | -u] [-f fields] [-s chars]" | |
97 " [input [output]]\n", argv0); | |
98 } | |
99 | |
100 int | |
101 main(int argc, char *argv[]) | |
102 { | |
103 FILE *fp[2] = { stdin, stdout }; | |
104 int ret = 0, i; | |
105 char *fname[2] = { "<stdin>", "<stdout>" }; | |
106 | |
107 ARGBEGIN { | |
108 case 'c': | |
109 countfmt = "%7ld "; | |
110 break; | |
111 case 'd': | |
112 dflag = 1; | |
113 break; | |
114 case 'u': | |
115 uflag = 1; | |
116 break; | |
117 case 'f': | |
118 fskip = estrtonum(EARGF(usage()), 0, INT_MAX); | |
119 break; | |
120 case 's': | |
121 sskip = estrtonum(EARGF(usage()), 0, INT_MAX); | |
122 break; | |
123 default: | |
124 usage(); | |
125 } ARGEND | |
126 | |
127 if (argc > 2) | |
128 usage(); | |
129 | |
130 for (i = 0; i < argc; i++) { | |
131 if (strcmp(argv[i], "-")) { | |
132 fname[i] = argv[i]; | |
133 if (!(fp[i] = fopen(argv[i], (i == 0) ? "r" : "w… | |
134 eprintf("fopen %s:", argv[i]); | |
135 } | |
136 } | |
137 | |
138 uniq(fp[0], fp[1]); | |
139 uniqfinish(fp[1]); | |
140 | |
141 ret |= fshut(fp[0], fname[0]) | fshut(fp[1], fname[1]); | |
142 | |
143 return ret; | |
144 } |