uniq.c 2.2 KB

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