1*cf5a6c84SAndroid Build Coastguard Worker /* uniq.c - report or filter out repeated lines in a file
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2012 Georgi Chorbadzhiyski <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker *
5*cf5a6c84SAndroid Build Coastguard Worker * See http://opengroup.org/onlinepubs/9699919799/utilities/uniq.html
6*cf5a6c84SAndroid Build Coastguard Worker
7*cf5a6c84SAndroid Build Coastguard Worker USE_UNIQ(NEWTOY(uniq, "f#s#w#zicdu", TOYFLAG_USR|TOYFLAG_BIN))
8*cf5a6c84SAndroid Build Coastguard Worker
9*cf5a6c84SAndroid Build Coastguard Worker config UNIQ
10*cf5a6c84SAndroid Build Coastguard Worker bool "uniq"
11*cf5a6c84SAndroid Build Coastguard Worker default y
12*cf5a6c84SAndroid Build Coastguard Worker help
13*cf5a6c84SAndroid Build Coastguard Worker usage: uniq [-cduiz] [-w MAXCHARS] [-f FIELDS] [-s CHAR] [INFILE [OUTFILE]]
14*cf5a6c84SAndroid Build Coastguard Worker
15*cf5a6c84SAndroid Build Coastguard Worker Report or filter out repeated lines in a file
16*cf5a6c84SAndroid Build Coastguard Worker
17*cf5a6c84SAndroid Build Coastguard Worker -c Show counts before each line
18*cf5a6c84SAndroid Build Coastguard Worker -d Show only lines that are repeated
19*cf5a6c84SAndroid Build Coastguard Worker -u Show only lines that are unique
20*cf5a6c84SAndroid Build Coastguard Worker -i Ignore case when comparing lines
21*cf5a6c84SAndroid Build Coastguard Worker -z Lines end with \0 not \n
22*cf5a6c84SAndroid Build Coastguard Worker -w Compare maximum X chars per line
23*cf5a6c84SAndroid Build Coastguard Worker -f Ignore first X fields
24*cf5a6c84SAndroid Build Coastguard Worker -s Ignore first X chars
25*cf5a6c84SAndroid Build Coastguard Worker */
26*cf5a6c84SAndroid Build Coastguard Worker
27*cf5a6c84SAndroid Build Coastguard Worker #define FOR_uniq
28*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
29*cf5a6c84SAndroid Build Coastguard Worker
GLOBALS(long w,s,f;long repeats;)30*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
31*cf5a6c84SAndroid Build Coastguard Worker long w, s, f;
32*cf5a6c84SAndroid Build Coastguard Worker
33*cf5a6c84SAndroid Build Coastguard Worker long repeats;
34*cf5a6c84SAndroid Build Coastguard Worker )
35*cf5a6c84SAndroid Build Coastguard Worker
36*cf5a6c84SAndroid Build Coastguard Worker static char *skip(char *str)
37*cf5a6c84SAndroid Build Coastguard Worker {
38*cf5a6c84SAndroid Build Coastguard Worker long nchars = TT.s, nfields = TT.f;
39*cf5a6c84SAndroid Build Coastguard Worker
40*cf5a6c84SAndroid Build Coastguard Worker // Skip fields first
41*cf5a6c84SAndroid Build Coastguard Worker while (nfields--) {
42*cf5a6c84SAndroid Build Coastguard Worker while (*str && isspace(*str)) str++;
43*cf5a6c84SAndroid Build Coastguard Worker while (*str && !isspace(*str)) str++;
44*cf5a6c84SAndroid Build Coastguard Worker }
45*cf5a6c84SAndroid Build Coastguard Worker // Skip chars
46*cf5a6c84SAndroid Build Coastguard Worker while (*str && nchars--) str++;
47*cf5a6c84SAndroid Build Coastguard Worker
48*cf5a6c84SAndroid Build Coastguard Worker return str;
49*cf5a6c84SAndroid Build Coastguard Worker }
50*cf5a6c84SAndroid Build Coastguard Worker
print_line(FILE * f,char * line)51*cf5a6c84SAndroid Build Coastguard Worker static void print_line(FILE *f, char *line)
52*cf5a6c84SAndroid Build Coastguard Worker {
53*cf5a6c84SAndroid Build Coastguard Worker if (TT.repeats ? FLAG(u) : FLAG(d)) return;
54*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(c)) fprintf(f, "%7lu ", TT.repeats + 1);
55*cf5a6c84SAndroid Build Coastguard Worker fputs(line, f);
56*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(z)) fputc(0, f);
57*cf5a6c84SAndroid Build Coastguard Worker }
58*cf5a6c84SAndroid Build Coastguard Worker
uniq_main(void)59*cf5a6c84SAndroid Build Coastguard Worker void uniq_main(void)
60*cf5a6c84SAndroid Build Coastguard Worker {
61*cf5a6c84SAndroid Build Coastguard Worker FILE *infile = stdin, *outfile = stdout;
62*cf5a6c84SAndroid Build Coastguard Worker char *thisline = 0, *prevline = 0, *tmpline, eol = '\n';
63*cf5a6c84SAndroid Build Coastguard Worker size_t thissize, prevsize = 0, tmpsize;
64*cf5a6c84SAndroid Build Coastguard Worker
65*cf5a6c84SAndroid Build Coastguard Worker if (toys.optc >= 1) infile = xfopen(toys.optargs[0], "r");
66*cf5a6c84SAndroid Build Coastguard Worker if (toys.optc >= 2) outfile = xfopen(toys.optargs[1], "w");
67*cf5a6c84SAndroid Build Coastguard Worker
68*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(z)) eol = 0;
69*cf5a6c84SAndroid Build Coastguard Worker
70*cf5a6c84SAndroid Build Coastguard Worker // If first line can't be read
71*cf5a6c84SAndroid Build Coastguard Worker if (getdelim(&prevline, &prevsize, eol, infile) < 0) return;
72*cf5a6c84SAndroid Build Coastguard Worker
73*cf5a6c84SAndroid Build Coastguard Worker while (getdelim(&thisline, &thissize, eol, infile) > 0) {
74*cf5a6c84SAndroid Build Coastguard Worker int diff;
75*cf5a6c84SAndroid Build Coastguard Worker char *t1, *t2;
76*cf5a6c84SAndroid Build Coastguard Worker
77*cf5a6c84SAndroid Build Coastguard Worker // If requested get the chosen fields + character offsets.
78*cf5a6c84SAndroid Build Coastguard Worker if (TT.f || TT.s) {
79*cf5a6c84SAndroid Build Coastguard Worker t1 = skip(thisline);
80*cf5a6c84SAndroid Build Coastguard Worker t2 = skip(prevline);
81*cf5a6c84SAndroid Build Coastguard Worker } else {
82*cf5a6c84SAndroid Build Coastguard Worker t1 = thisline;
83*cf5a6c84SAndroid Build Coastguard Worker t2 = prevline;
84*cf5a6c84SAndroid Build Coastguard Worker }
85*cf5a6c84SAndroid Build Coastguard Worker
86*cf5a6c84SAndroid Build Coastguard Worker if (!TT.w)
87*cf5a6c84SAndroid Build Coastguard Worker diff = !FLAG(i) ? strcmp(t1, t2) : strcasecmp(t1, t2);
88*cf5a6c84SAndroid Build Coastguard Worker else diff = !FLAG(i) ? strncmp(t1, t2, TT.w) : strncasecmp(t1, t2, TT.w);
89*cf5a6c84SAndroid Build Coastguard Worker
90*cf5a6c84SAndroid Build Coastguard Worker if (!diff) TT.repeats++;
91*cf5a6c84SAndroid Build Coastguard Worker else {
92*cf5a6c84SAndroid Build Coastguard Worker print_line(outfile, prevline);
93*cf5a6c84SAndroid Build Coastguard Worker
94*cf5a6c84SAndroid Build Coastguard Worker TT.repeats = 0;
95*cf5a6c84SAndroid Build Coastguard Worker
96*cf5a6c84SAndroid Build Coastguard Worker tmpline = prevline;
97*cf5a6c84SAndroid Build Coastguard Worker prevline = thisline;
98*cf5a6c84SAndroid Build Coastguard Worker thisline = tmpline;
99*cf5a6c84SAndroid Build Coastguard Worker
100*cf5a6c84SAndroid Build Coastguard Worker tmpsize = prevsize;
101*cf5a6c84SAndroid Build Coastguard Worker prevsize = thissize;
102*cf5a6c84SAndroid Build Coastguard Worker thissize = tmpsize;
103*cf5a6c84SAndroid Build Coastguard Worker }
104*cf5a6c84SAndroid Build Coastguard Worker }
105*cf5a6c84SAndroid Build Coastguard Worker
106*cf5a6c84SAndroid Build Coastguard Worker print_line(outfile, prevline);
107*cf5a6c84SAndroid Build Coastguard Worker
108*cf5a6c84SAndroid Build Coastguard Worker if (CFG_TOYBOX_FREE) {
109*cf5a6c84SAndroid Build Coastguard Worker if (outfile != stdout) fclose(outfile);
110*cf5a6c84SAndroid Build Coastguard Worker if (infile != stdin) fclose(infile);
111*cf5a6c84SAndroid Build Coastguard Worker free(prevline);
112*cf5a6c84SAndroid Build Coastguard Worker free(thisline);
113*cf5a6c84SAndroid Build Coastguard Worker }
114*cf5a6c84SAndroid Build Coastguard Worker }
115