3
0

uniq.c 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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. /* BB_AUDIT SUSv3 compliant */
  10. /* http://www.opengroup.org/onlinepubs/007904975/utilities/uniq.html */
  11. #include "busybox.h"
  12. static const char uniq_opts[] = "f:s:" "cdu\0\1\2\4";
  13. static FILE *xgetoptfile_uniq_s(char **argv, int read0write2)
  14. {
  15. const char *n;
  16. if ((n = *argv) != NULL) {
  17. if ((*n != '-') || n[1]) {
  18. return xfopen(n, "r\0w" + read0write2);
  19. }
  20. }
  21. return (read0write2) ? stdout : stdin;
  22. }
  23. int uniq_main(int argc, char **argv)
  24. {
  25. FILE *in, *out;
  26. unsigned long dups, skip_fields, skip_chars, i, uniq_flags;
  27. const char *s0, *e0, *s1, *e1, *input_filename;
  28. int opt;
  29. uniq_flags = skip_fields = skip_chars = 0;
  30. while ((opt = getopt(argc, argv, uniq_opts)) > 0) {
  31. if ((opt == 'f') || (opt == 's')) {
  32. unsigned long t = xatoul(optarg);
  33. if (opt == 'f') {
  34. skip_fields = t;
  35. } else {
  36. skip_chars = t;
  37. }
  38. } else if ((s0 = strchr(uniq_opts, opt)) != NULL) {
  39. uniq_flags |= s0[4];
  40. } else {
  41. bb_show_usage();
  42. }
  43. }
  44. input_filename = *(argv += optind);
  45. in = xgetoptfile_uniq_s(argv, 0);
  46. if (*argv) {
  47. ++argv;
  48. }
  49. out = xgetoptfile_uniq_s(argv, 2);
  50. if (*argv && argv[1]) {
  51. bb_show_usage();
  52. }
  53. s1 = e1 = NULL; /* prime the pump */
  54. do {
  55. s0 = s1;
  56. e0 = e1;
  57. dups = 0;
  58. /* gnu uniq ignores newlines */
  59. while ((s1 = xmalloc_getline(in)) != NULL) {
  60. e1 = s1;
  61. for (i = skip_fields; i; i--) {
  62. e1 = skip_whitespace(e1);
  63. while (*e1 && !isspace(*e1)) {
  64. ++e1;
  65. }
  66. }
  67. for (i = skip_chars; *e1 && i; i--) {
  68. ++e1;
  69. }
  70. if (!s0 || strcmp(e0, e1)) {
  71. break;
  72. }
  73. ++dups; /* Note: Testing for overflow seems excessive. */
  74. }
  75. if (s0) {
  76. if (!(uniq_flags & (2 << !!dups))) {
  77. fprintf(out, "\0%d " + (uniq_flags & 1), dups + 1);
  78. fprintf(out, "%s\n", s0);
  79. }
  80. free((void *)s0);
  81. }
  82. } while (s1);
  83. die_if_ferror(in, input_filename);
  84. fflush_stdout_and_exit(EXIT_SUCCESS);
  85. }