Since rangecoder is just a bunch of C functions, move it into the one user
[oweals/busybox.git] / coreutils / uniq.c
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 }