toybox/toys/posix/uniq.c
<<
>>
Prefs
   1/* uniq.c - report or filter out repeated lines in a file
   2 *
   3 * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org>
   4 *
   5 * See http://opengroup.org/onlinepubs/9699919799/utilities/uniq.html
   6
   7USE_UNIQ(NEWTOY(uniq, "f#s#w#zicdu", TOYFLAG_USR|TOYFLAG_BIN))
   8
   9config UNIQ
  10  bool "uniq"
  11  default y
  12  help
  13    usage: uniq [-cduiz] [-w MAXCHARS] [-f FIELDS] [-s CHAR] [INFILE [OUTFILE]]
  14
  15    Report or filter out repeated lines in a file
  16
  17    -c  Show counts before each line
  18    -d  Show only lines that are repeated
  19    -u  Show only lines that are unique
  20    -i  Ignore case when comparing lines
  21    -z  Lines end with \0 not \n
  22    -w  Compare maximum X chars per line
  23    -f  Ignore first X fields
  24    -s  Ignore first X chars
  25*/
  26
  27#define FOR_uniq
  28#include "toys.h"
  29
  30GLOBALS(
  31  long w, s, f;
  32
  33  long repeats;
  34)
  35
  36static char *skip(char *str)
  37{
  38  long nchars = TT.s, nfields = TT.f;
  39
  40  // Skip fields first
  41  while (nfields--) {
  42    while (*str && isspace(*str)) str++;
  43    while (*str && !isspace(*str)) str++;
  44  }
  45  // Skip chars
  46  while (*str && nchars--) str++;
  47
  48  return str;
  49}
  50
  51static void print_line(FILE *f, char *line)
  52{
  53  if (TT.repeats ? FLAG(u) : FLAG(d)) return;
  54  if (FLAG(c)) fprintf(f, "%7lu ", TT.repeats + 1);
  55  fputs(line, f);
  56  if (FLAG(z)) fputc(0, f);
  57}
  58
  59void uniq_main(void)
  60{
  61  FILE *infile = stdin, *outfile = stdout;
  62  char *thisline = 0, *prevline = 0, *tmpline, eol = '\n';
  63  size_t thissize, prevsize = 0, tmpsize;
  64
  65  if (toys.optc >= 1) infile = xfopen(toys.optargs[0], "r");
  66  if (toys.optc >= 2) outfile = xfopen(toys.optargs[1], "w");
  67
  68  if (FLAG(z)) eol = 0;
  69
  70  // If first line can't be read
  71  if (getdelim(&prevline, &prevsize, eol, infile) < 0) return;
  72
  73  while (getdelim(&thisline, &thissize, eol, infile) > 0) {
  74    int diff;
  75    char *t1, *t2;
  76
  77    // If requested get the chosen fields + character offsets.
  78    if (TT.f || TT.s) {
  79      t1 = skip(thisline);
  80      t2 = skip(prevline);
  81    } else {
  82      t1 = thisline;
  83      t2 = prevline;
  84    }
  85
  86    if (!TT.w)
  87      diff = !FLAG(i) ? strcmp(t1, t2) : strcasecmp(t1, t2);
  88    else diff = !FLAG(i) ? strncmp(t1, t2, TT.w) : strncasecmp(t1, t2, TT.w);
  89
  90    if (!diff) TT.repeats++;
  91    else {
  92      print_line(outfile, prevline);
  93
  94      TT.repeats = 0;
  95
  96      tmpline = prevline;
  97      prevline = thisline;
  98      thisline = tmpline;
  99
 100      tmpsize = prevsize;
 101      prevsize = thissize;
 102      thissize = tmpsize;
 103    }
 104  }
 105
 106  print_line(outfile, prevline);
 107
 108  if (CFG_TOYBOX_FREE) {
 109    if (outfile != stdout) fclose(outfile);
 110    if (infile != stdin) fclose(infile);
 111    free(prevline);
 112    free(thisline);
 113  }
 114}
 115