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 15static const char uniq_opts[] ALIGN1 = "cdu" "f:s:" "cdu\0\1\2\4"; 16 17static FILE *xgetoptfile_uniq_s(char **argv, int read0write2) 18{ 19 const char *n; 20 21 n = *argv; 22 if (n != NULL) { 23 if ((*n != '-') || n[1]) { 24 return xfopen(n, "r\0w" + read0write2); 25 } 26 } 27 return (read0write2) ? stdout : stdin; 28} 29 30int uniq_main(int argc, char **argv); 31int uniq_main(int argc, char **argv) 32{ 33 FILE *in, *out; 34 unsigned long dups, skip_fields, skip_chars, i; 35 const char *s0, *e0, *s1, *e1, *input_filename; 36 unsigned opt; 37 38 enum { 39 OPT_c = 0x1, 40 OPT_d = 0x2, 41 OPT_u = 0x4, 42 OPT_f = 0x8, 43 OPT_s = 0x10, 44 }; 45 46 skip_fields = skip_chars = 0; 47 48 opt = getopt32(argv, "cduf:s:", &s0, &s1); 49 if (opt & OPT_f) 50 skip_fields = xatoul(s0); 51 if (opt & OPT_s) 52 skip_chars = xatoul(s1); 53 argv += optind; 54 55 input_filename = *argv; 56 57 in = xgetoptfile_uniq_s(argv, 0); 58 if (*argv) { 59 ++argv; 60 } 61 out = xgetoptfile_uniq_s(argv, 2); 62 if (*argv && argv[1]) { 63 bb_show_usage(); 64 } 65 66 s1 = e1 = NULL; /* prime the pump */ 67 68 do { 69 s0 = s1; 70 e0 = e1; 71 dups = 0; 72 73 /* gnu uniq ignores newlines */ 74 while ((s1 = xmalloc_getline(in)) != NULL) { 75 e1 = s1; 76 for (i = skip_fields; i; i--) { 77 e1 = skip_whitespace(e1); 78 e1 = skip_non_whitespace(e1); 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 (!(opt & (OPT_d << !!dups))) { /* (if dups, opt & OPT_e) */ 93 fprintf(out, "\0%d " + (opt & 1), dups + 1); 94 fprintf(out, "%s\n", s0); 95 } 96 free((void *)s0); 97 } 98 } while (s1); 99 100 die_if_ferror(in, input_filename); 101 102 fflush_stdout_and_exit(EXIT_SUCCESS); 103} 104