bb_get_[chomped]line_from_file wasn't descriptive enough.
[platform/upstream/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
15 static const char uniq_opts[] = "f:s:" "cdu\0\1\2\4";
16
17 static FILE *xgetoptfile_uniq_s(char **argv, int read0write2)
18 {
19         const char *n;
20
21         if ((n = *argv) != NULL) {
22                 if ((*n != '-') || n[1]) {
23                         return xfopen(n, "r\0w" + read0write2);
24                 }
25         }
26         return (read0write2) ? stdout : stdin;
27 }
28
29 int uniq_main(int argc, char **argv)
30 {
31         FILE *in, *out;
32         unsigned long dups, skip_fields, skip_chars, i, uniq_flags;
33         const char *s0, *e0, *s1, *e1, *input_filename;
34         int opt;
35
36         uniq_flags = skip_fields = skip_chars = 0;
37
38         while ((opt = getopt(argc, argv, uniq_opts)) > 0) {
39                 if ((opt == 'f') || (opt == 's')) {
40                         int t = xatoul(optarg);
41                         if (opt == 'f') {
42                                 skip_fields = t;
43                         } else {
44                                 skip_chars = t;
45                         }
46                 } else if ((s0 = strchr(uniq_opts, opt)) != NULL) {
47                         uniq_flags |= s0[4];
48                 } else {
49                         bb_show_usage();
50                 }
51         }
52
53         input_filename = *(argv += optind);
54
55         in = xgetoptfile_uniq_s(argv, 0);
56         if (*argv) {
57                 ++argv;
58         }
59         out = xgetoptfile_uniq_s(argv, 2);
60         if (*argv && argv[1]) {
61                 bb_show_usage();
62         }
63
64         s1 = e1 = NULL;                         /* prime the pump */
65
66         do {
67                 s0 = s1;
68                 e0 = e1;
69                 dups = 0;
70
71                 /* gnu uniq ignores newlines */
72                 while ((s1 = xmalloc_getline(in)) != NULL) {
73                         e1 = s1;
74                         for (i=skip_fields ; i ; i--) {
75                                 e1 = skip_whitespace(e1);
76                                 while (*e1 && !isspace(*e1)) {
77                                         ++e1;
78                                 }
79                         }
80                         for (i = skip_chars ; *e1 && i ; i--) {
81                                 ++e1;
82                         }
83
84                         if (!s0 || strcmp(e0, e1)) {
85                                 break;
86                         }
87
88                         ++dups;          /* Note: Testing for overflow seems excessive. */
89                 }
90
91                 if (s0) {
92                         if (!(uniq_flags & (2 << !!dups))) {
93                                 bb_fprintf(out, "\0%d " + (uniq_flags & 1), dups + 1);
94                                 bb_fprintf(out, "%s\n", s0);
95                         }
96                         free((void *)s0);
97                 }
98         } while (s1);
99
100         xferror(in, input_filename);
101
102         bb_fflush_stdout_and_exit(EXIT_SUCCESS);
103 }