1 | /* vi: set sw=4 ts=4: */
|
---|
2 | /*
|
---|
3 | * uniq implementation for busybox
|
---|
4 | *
|
---|
5 | * Copyright (C) 2005 Manuel Novoa III <mjn3@codepoet.org>
|
---|
6 | *
|
---|
7 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
|
---|
8 | */
|
---|
9 |
|
---|
10 | /* BB_AUDIT SUSv3 compliant */
|
---|
11 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/uniq.html */
|
---|
12 |
|
---|
13 | #include "busybox.h"
|
---|
14 | #include <string.h>
|
---|
15 | #include <ctype.h>
|
---|
16 | #include <unistd.h>
|
---|
17 |
|
---|
18 | static const char uniq_opts[] = "f:s:" "cdu\0\1\2\4";
|
---|
19 |
|
---|
20 | static FILE *xgetoptfile_uniq_s(char **argv, int read0write2)
|
---|
21 | {
|
---|
22 | const char *n;
|
---|
23 |
|
---|
24 | if ((n = *argv) != NULL) {
|
---|
25 | if ((*n != '-') || n[1]) {
|
---|
26 | return bb_xfopen(n, "r\0w" + read0write2);
|
---|
27 | }
|
---|
28 | }
|
---|
29 | return (read0write2) ? stdout : stdin;
|
---|
30 | }
|
---|
31 |
|
---|
32 | int uniq_main(int argc, char **argv)
|
---|
33 | {
|
---|
34 | FILE *in, *out;
|
---|
35 | unsigned long dups, skip_fields, skip_chars, i, uniq_flags;
|
---|
36 | const char *s0, *e0, *s1, *e1, *input_filename;
|
---|
37 | int opt;
|
---|
38 |
|
---|
39 | uniq_flags = skip_fields = skip_chars = 0;
|
---|
40 |
|
---|
41 | while ((opt = getopt(argc, argv, uniq_opts)) > 0) {
|
---|
42 | if ((opt == 'f') || (opt == 's')) {
|
---|
43 | int t = bb_xgetularg10(optarg);
|
---|
44 | if (opt == 'f') {
|
---|
45 | skip_fields = t;
|
---|
46 | } else {
|
---|
47 | skip_chars = t;
|
---|
48 | }
|
---|
49 | } else if ((s0 = strchr(uniq_opts, opt)) != NULL) {
|
---|
50 | uniq_flags |= s0[4];
|
---|
51 | } else {
|
---|
52 | bb_show_usage();
|
---|
53 | }
|
---|
54 | }
|
---|
55 |
|
---|
56 | input_filename = *(argv += optind);
|
---|
57 |
|
---|
58 | in = xgetoptfile_uniq_s(argv, 0);
|
---|
59 | if (*argv) {
|
---|
60 | ++argv;
|
---|
61 | }
|
---|
62 | out = xgetoptfile_uniq_s(argv, 2);
|
---|
63 | if (*argv && argv[1]) {
|
---|
64 | bb_show_usage();
|
---|
65 | }
|
---|
66 |
|
---|
67 | s1 = e1 = NULL; /* prime the pump */
|
---|
68 |
|
---|
69 | do {
|
---|
70 | s0 = s1;
|
---|
71 | e0 = e1;
|
---|
72 | dups = 0;
|
---|
73 |
|
---|
74 | /* gnu uniq ignores newlines */
|
---|
75 | while ((s1 = bb_get_chomped_line_from_file(in)) != NULL) {
|
---|
76 | e1 = s1;
|
---|
77 | for (i=skip_fields ; i ; i--) {
|
---|
78 | e1 = skip_whitespace(e1);
|
---|
79 | while (*e1 && !isspace(*e1)) {
|
---|
80 | ++e1;
|
---|
81 | }
|
---|
82 | }
|
---|
83 | for (i = skip_chars ; *e1 && i ; i--) {
|
---|
84 | ++e1;
|
---|
85 | }
|
---|
86 |
|
---|
87 | if (!s0 || strcmp(e0, e1)) {
|
---|
88 | break;
|
---|
89 | }
|
---|
90 |
|
---|
91 | ++dups; /* Note: Testing for overflow seems excessive. */
|
---|
92 | }
|
---|
93 |
|
---|
94 | if (s0) {
|
---|
95 | if (!(uniq_flags & (2 << !!dups))) {
|
---|
96 | bb_fprintf(out, "\0%d " + (uniq_flags & 1), dups + 1);
|
---|
97 | bb_fprintf(out, "%s\n", s0);
|
---|
98 | }
|
---|
99 | free((void *)s0);
|
---|
100 | }
|
---|
101 | } while (s1);
|
---|
102 |
|
---|
103 | bb_xferror(in, input_filename);
|
---|
104 |
|
---|
105 | bb_fflush_stdout_and_exit(EXIT_SUCCESS);
|
---|
106 | }
|
---|