10 |
/* BB_AUDIT SUSv3 compliant */ |
/* BB_AUDIT SUSv3 compliant */ |
11 |
/* http://www.opengroup.org/onlinepubs/007904975/utilities/uniq.html */ |
/* http://www.opengroup.org/onlinepubs/007904975/utilities/uniq.html */ |
12 |
|
|
13 |
#include "busybox.h" |
#include "libbb.h" |
|
|
|
|
static const char uniq_opts[] = "f:s:" "cdu\0\1\2\4"; |
|
14 |
|
|
15 |
static FILE *xgetoptfile_uniq_s(char **argv, int read0write2) |
static FILE *xgetoptfile_uniq_s(char **argv, int read0write2) |
16 |
{ |
{ |
17 |
const char *n; |
const char *n; |
18 |
|
|
19 |
if ((n = *argv) != NULL) { |
n = *argv; |
20 |
|
if (n != NULL) { |
21 |
if ((*n != '-') || n[1]) { |
if ((*n != '-') || n[1]) { |
22 |
return xfopen(n, "r\0w" + read0write2); |
return xfopen(n, "r\0w" + read0write2); |
23 |
} |
} |
25 |
return (read0write2) ? stdout : stdin; |
return (read0write2) ? stdout : stdin; |
26 |
} |
} |
27 |
|
|
28 |
int uniq_main(int argc, char **argv) |
int uniq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
29 |
|
int uniq_main(int argc UNUSED_PARAM, char **argv) |
30 |
{ |
{ |
31 |
FILE *in, *out; |
FILE *in, *out; |
|
unsigned long dups, skip_fields, skip_chars, i, uniq_flags; |
|
32 |
const char *s0, *e0, *s1, *e1, *input_filename; |
const char *s0, *e0, *s1, *e1, *input_filename; |
33 |
int opt; |
unsigned long dups; |
34 |
|
unsigned skip_fields, skip_chars, max_chars; |
35 |
uniq_flags = skip_fields = skip_chars = 0; |
unsigned opt; |
36 |
|
unsigned i; |
37 |
while ((opt = getopt(argc, argv, uniq_opts)) > 0) { |
|
38 |
if ((opt == 'f') || (opt == 's')) { |
enum { |
39 |
unsigned long t = xatoul(optarg); |
OPT_c = 0x1, |
40 |
if (opt == 'f') { |
OPT_d = 0x2, |
41 |
skip_fields = t; |
OPT_u = 0x4, |
42 |
} else { |
OPT_f = 0x8, |
43 |
skip_chars = t; |
OPT_s = 0x10, |
44 |
} |
OPT_w = 0x20, |
45 |
} else if ((s0 = strchr(uniq_opts, opt)) != NULL) { |
}; |
46 |
uniq_flags |= s0[4]; |
|
47 |
} else { |
skip_fields = skip_chars = 0; |
48 |
bb_show_usage(); |
max_chars = -1; |
49 |
} |
|
50 |
} |
opt_complementary = "f+:s+:w+"; |
51 |
|
opt = getopt32(argv, "cduf:s:w:", &skip_fields, &skip_chars, &max_chars); |
52 |
|
argv += optind; |
53 |
|
|
54 |
input_filename = *(argv += optind); |
input_filename = *argv; |
55 |
|
|
56 |
in = xgetoptfile_uniq_s(argv, 0); |
in = xgetoptfile_uniq_s(argv, 0); |
57 |
if (*argv) { |
if (*argv) { |
62 |
bb_show_usage(); |
bb_show_usage(); |
63 |
} |
} |
64 |
|
|
65 |
s1 = e1 = NULL; /* prime the pump */ |
s1 = e1 = NULL; /* prime the pump */ |
66 |
|
|
67 |
do { |
do { |
68 |
s0 = s1; |
s0 = s1; |
70 |
dups = 0; |
dups = 0; |
71 |
|
|
72 |
/* gnu uniq ignores newlines */ |
/* gnu uniq ignores newlines */ |
73 |
while ((s1 = xmalloc_getline(in)) != NULL) { |
while ((s1 = xmalloc_fgetline(in)) != NULL) { |
74 |
e1 = s1; |
e1 = s1; |
75 |
for (i = skip_fields; i; i--) { |
for (i = skip_fields; i; i--) { |
76 |
e1 = skip_whitespace(e1); |
e1 = skip_whitespace(e1); |
77 |
while (*e1 && !isspace(*e1)) { |
e1 = skip_non_whitespace(e1); |
|
++e1; |
|
|
} |
|
78 |
} |
} |
79 |
for (i = skip_chars; *e1 && i; i--) { |
for (i = skip_chars; *e1 && i; i--) { |
80 |
++e1; |
++e1; |
81 |
} |
} |
82 |
|
|
83 |
if (!s0 || strcmp(e0, e1)) { |
if (!s0 || strncmp(e0, e1, max_chars)) { |
84 |
break; |
break; |
85 |
} |
} |
86 |
|
|
87 |
++dups; /* Note: Testing for overflow seems excessive. */ |
++dups; /* note: testing for overflow seems excessive. */ |
88 |
} |
} |
89 |
|
|
90 |
if (s0) { |
if (s0) { |
91 |
if (!(uniq_flags & (2 << !!dups))) { |
if (!(opt & (OPT_d << !!dups))) { /* (if dups, opt & OPT_e) */ |
92 |
fprintf(out, "\0%d " + (uniq_flags & 1), dups + 1); |
fprintf(out, "\0%ld " + (opt & 1), dups + 1); /* 1 == OPT_c */ |
93 |
fprintf(out, "%s\n", s0); |
fprintf(out, "%s\n", s0); |
94 |
} |
} |
95 |
free((void *)s0); |
free((void *)s0); |