[821] | 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 | }
|
---|