busybox/coreutils/uniq.c
<<
>>
Prefs
   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 "libbb.h"
  14
  15int uniq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  16int uniq_main(int argc UNUSED_PARAM, char **argv)
  17{
  18        const char *input_filename;
  19        unsigned skip_fields, skip_chars, max_chars;
  20        unsigned opt;
  21        char *cur_line;
  22        const char *cur_compare;
  23
  24        enum {
  25                OPT_c = 0x1,
  26                OPT_d = 0x2, /* print only dups */
  27                OPT_u = 0x4, /* print only uniq */
  28                OPT_f = 0x8,
  29                OPT_s = 0x10,
  30                OPT_w = 0x20,
  31        };
  32
  33        skip_fields = skip_chars = 0;
  34        max_chars = INT_MAX;
  35
  36        opt_complementary = "f+:s+:w+";
  37        opt = getopt32(argv, "cduf:s:w:", &skip_fields, &skip_chars, &max_chars);
  38        argv += optind;
  39
  40        input_filename = argv[0];
  41        if (input_filename) {
  42                const char *output;
  43
  44                if (input_filename[0] != '-' || input_filename[1]) {
  45                        close(STDIN_FILENO); /* == 0 */
  46                        xopen(input_filename, O_RDONLY); /* fd will be 0 */
  47                }
  48                output = argv[1];
  49                if (output) {
  50                        if (argv[2])
  51                                bb_show_usage();
  52                        if (output[0] != '-' || output[1]) {
  53                                // Won't work with "uniq - FILE" and closed stdin:
  54                                //close(STDOUT_FILENO);
  55                                //xopen3(output, O_WRONLY | O_CREAT | O_TRUNC, 0666);
  56                                xmove_fd(xopen3(output, O_WRONLY | O_CREAT | O_TRUNC, 0666), STDOUT_FILENO);
  57                        }
  58                }
  59        }
  60
  61        cur_compare = cur_line = NULL; /* prime the pump */
  62
  63        do {
  64                unsigned i;
  65                unsigned long dups;
  66                char *old_line;
  67                const char *old_compare;
  68
  69                old_line = cur_line;
  70                old_compare = cur_compare;
  71                dups = 0;
  72
  73                /* gnu uniq ignores newlines */
  74                while ((cur_line = xmalloc_fgetline(stdin)) != NULL) {
  75                        cur_compare = cur_line;
  76                        for (i = skip_fields; i; i--) {
  77                                cur_compare = skip_whitespace(cur_compare);
  78                                cur_compare = skip_non_whitespace(cur_compare);
  79                        }
  80                        for (i = skip_chars; *cur_compare && i; i--) {
  81                                ++cur_compare;
  82                        }
  83
  84                        if (!old_line || strncmp(old_compare, cur_compare, max_chars)) {
  85                                break;
  86                        }
  87
  88                        free(cur_line);
  89                        ++dups;  /* testing for overflow seems excessive */
  90                }
  91
  92                if (old_line) {
  93                        if (!(opt & (OPT_d << !!dups))) { /* (if dups, opt & OPT_u) */
  94                                if (opt & OPT_c) {
  95                                        /* %7lu matches GNU coreutils 6.9 */
  96                                        printf("%7lu ", dups + 1);
  97                                }
  98                                printf("%s\n", old_line);
  99                        }
 100                        free(old_line);
 101                }
 102        } while (cur_line);
 103
 104        die_if_ferror(stdin, input_filename);
 105
 106        fflush_stdout_and_exit(EXIT_SUCCESS);
 107}
 108