diff options
Diffstat (limited to 'coreutils/uniq.c')
-rw-r--r-- | coreutils/uniq.c | 126 |
1 files changed, 75 insertions, 51 deletions
diff --git a/coreutils/uniq.c b/coreutils/uniq.c index cb63c4277..90686c9af 100644 --- a/coreutils/uniq.c +++ b/coreutils/uniq.c | |||
@@ -1,10 +1,8 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | 1 | /* vi: set sw=4 ts=4: */ |
2 | /* | 2 | /* |
3 | * Mini uniq implementation for busybox | 3 | * uniq implementation for busybox |
4 | * | 4 | * |
5 | * Copyright (C) 1999 by Lineo, inc. and John Beppu | 5 | * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> |
6 | * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org> | ||
7 | * Rewritten by Matt Kraai <kraai@alumni.carnegiemellon.edu> | ||
8 | * | 6 | * |
9 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -22,67 +20,93 @@ | |||
22 | * | 20 | * |
23 | */ | 21 | */ |
24 | 22 | ||
23 | /* BB_AUDIT SUSv3 compliant */ | ||
24 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/uniq.html */ | ||
25 | |||
25 | #include <stdio.h> | 26 | #include <stdio.h> |
26 | #include <string.h> | ||
27 | #include <getopt.h> | ||
28 | #include <errno.h> | ||
29 | #include <stdlib.h> | 27 | #include <stdlib.h> |
28 | #include <string.h> | ||
29 | #include <ctype.h> | ||
30 | #include <unistd.h> | ||
30 | #include "busybox.h" | 31 | #include "busybox.h" |
32 | #include "libcoreutils/coreutils.h" | ||
31 | 33 | ||
32 | static int print_count; | 34 | static const char uniq_opts[] = "f:s:cdu\0\7\3\5\1\2\4"; |
33 | static int print_uniq = 1; | ||
34 | static int print_duplicates = 1; | ||
35 | |||
36 | static void print_line(char *line, int count, FILE *fp) | ||
37 | { | ||
38 | if ((print_duplicates && count > 1) || (print_uniq && count == 1)) { | ||
39 | if (print_count) | ||
40 | fprintf(fp, "%7d\t%s", count, line); | ||
41 | else | ||
42 | fputs(line, fp); | ||
43 | } | ||
44 | } | ||
45 | 35 | ||
46 | int uniq_main(int argc, char **argv) | 36 | int uniq_main(int argc, char **argv) |
47 | { | 37 | { |
48 | FILE *in = stdin, *out = stdout; | 38 | FILE *in, *out; |
49 | char *lastline = NULL, *input; | 39 | /* Note: Ignore the warning about dups and e0 possibly being uninitialized. |
50 | int opt, count = 0; | 40 | * They will be initialized on the fist pass of the loop (since s0 is NULL). */ |
41 | unsigned long dups, skip_fields, skip_chars, i; | ||
42 | const char *s0, *e0, *s1, *e1, *input_filename; | ||
43 | int opt; | ||
44 | int uniq_flags = 6; /* -u */ | ||
51 | 45 | ||
52 | /* parse argv[] */ | 46 | skip_fields = skip_chars = 0; |
53 | while ((opt = getopt(argc, argv, "cdu")) > 0) { | 47 | |
54 | switch (opt) { | 48 | while ((opt = getopt(argc, argv, uniq_opts)) > 0) { |
55 | case 'c': | 49 | if (opt == 'f') { |
56 | print_count = 1; | 50 | skip_fields = bb_xgetularg10(optarg); |
57 | break; | 51 | } else if (opt == 's') { |
58 | case 'd': | 52 | skip_chars = bb_xgetularg10(optarg); |
59 | print_duplicates = 1; | 53 | } else if ((s0 = strchr(uniq_opts, opt)) != NULL) { |
60 | print_uniq = 0; | 54 | uniq_flags &= s0[4]; |
61 | break; | 55 | uniq_flags |= s0[7]; |
62 | case 'u': | 56 | } else { |
63 | print_duplicates = 0; | 57 | bb_show_usage(); |
64 | print_uniq = 1; | ||
65 | break; | ||
66 | } | 58 | } |
67 | } | 59 | } |
68 | 60 | ||
69 | if (argv[optind] != NULL) { | 61 | input_filename = *(argv += optind); |
70 | in = xfopen(argv[optind], "r"); | 62 | |
71 | if (argv[optind+1] != NULL) | 63 | in = xgetoptfile_sort_uniq(argv, "r"); |
72 | out = xfopen(argv[optind+1], "w"); | 64 | if (*argv) { |
65 | ++argv; | ||
73 | } | 66 | } |
67 | out = xgetoptfile_sort_uniq(argv, "w"); | ||
68 | if (*argv && argv[1]) { | ||
69 | bb_show_usage(); | ||
70 | } | ||
71 | |||
72 | s0 = NULL; | ||
74 | 73 | ||
75 | while ((input = get_line_from_file(in)) != NULL) { | 74 | /* gnu uniq ignores newlines */ |
76 | if (lastline == NULL || strcmp(input, lastline) != 0) { | 75 | while ((s1 = bb_get_chomped_line_from_file(in)) != NULL) { |
77 | print_line(lastline, count, out); | 76 | e1 = s1; |
78 | free(lastline); | 77 | for (i=skip_fields ; i ; i--) { |
79 | lastline = input; | 78 | e1 = bb_skip_whitespace(e1); |
80 | count = 0; | 79 | while (*e1 && !isspace(*e1)) { |
80 | ++e1; | ||
81 | } | ||
82 | } | ||
83 | for (i = skip_chars ; *e1 && i ; i--) { | ||
84 | ++e1; | ||
85 | } | ||
86 | if (s0) { | ||
87 | if (strcmp(e0, e1) == 0) { | ||
88 | ++dups; /* Note: Testing for overflow seems excessive. */ | ||
89 | continue; | ||
90 | } | ||
91 | DO_LAST: | ||
92 | if ((dups && (uniq_flags & 2)) || (!dups && (uniq_flags & 4))) { | ||
93 | bb_fprintf(out, "\0%7d\t" + (uniq_flags & 1), dups + 1); | ||
94 | bb_fprintf(out, "%s\n", s0); | ||
95 | } | ||
96 | free((void *)s0); | ||
81 | } | 97 | } |
82 | count++; | 98 | |
99 | s0 = s1; | ||
100 | e0 = e1; | ||
101 | dups = 0; | ||
102 | } | ||
103 | |||
104 | if (s0) { | ||
105 | e1 = NULL; | ||
106 | goto DO_LAST; | ||
83 | } | 107 | } |
84 | print_line(lastline, count, out); | ||
85 | free(lastline); | ||
86 | 108 | ||
87 | return EXIT_SUCCESS; | 109 | bb_xferror(in, input_filename); |
110 | |||
111 | bb_fflush_stdout_and_exit(EXIT_SUCCESS); | ||
88 | } | 112 | } |