Introduction
Introduction Statistics Contact Development Disclaimer Help
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 }
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.