/* uniq.c - report or filter out repeated lines in a file * * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org> * * See http://opengroup.org/onlinepubs/9699919799/utilities/uniq.html USE_UNIQ(NEWTOY(uniq, "f#s#w#zicdu", TOYFLAG_USR|TOYFLAG_BIN)) config UNIQ bool "uniq" default y help usage: uniq [-cduiz] [-w maxchars] [-f fields] [-s char] [input_file [output_file]] Report or filter out repeated lines in a file -c Show counts before each line -d Show only lines that are repeated -u Show only lines that are unique -i Ignore case when comparing lines -z Lines end with \0 not \n -w Compare maximum X chars per line -f Ignore first X fields -s Ignore first X chars */ #define FOR_uniq #include "toys.h" GLOBALS( long w, s, f; long repeats; ) static char *skip(char *str) { long nchars = TT.s, nfields = TT.f; // Skip fields first while (nfields--) { while (*str && isspace(*str)) str++; while (*str && !isspace(*str)) str++; } // Skip chars while (*str && nchars--) str++; return str; } static void print_line(FILE *f, char *line) { if (TT.repeats ? FLAG(u) : FLAG(d)) return; if (FLAG(c)) fprintf(f, "%7lu ", TT.repeats + 1); fputs(line, f); if (FLAG(z)) fputc(0, f); } void uniq_main(void) { FILE *infile = stdin, *outfile = stdout; char *thisline = 0, *prevline = 0, *tmpline, eol = '\n'; size_t thissize, prevsize = 0, tmpsize; if (toys.optc >= 1) infile = xfopen(toys.optargs[0], "r"); if (toys.optc >= 2) outfile = xfopen(toys.optargs[1], "w"); if (FLAG(z)) eol = 0; // If first line can't be read if (getdelim(&prevline, &prevsize, eol, infile) < 0) return; while (getdelim(&thisline, &thissize, eol, infile) > 0) { int diff; char *t1, *t2; // If requested get the chosen fields + character offsets. if (TT.f || TT.s) { t1 = skip(thisline); t2 = skip(prevline); } else { t1 = thisline; t2 = prevline; } if (!TT.w) diff = !FLAG(i) ? strcmp(t1, t2) : strcasecmp(t1, t2); else diff = !FLAG(i) ? strncmp(t1, t2, TT.w) : strncasecmp(t1, t2, TT.w); if (!diff) TT.repeats++; else { print_line(outfile, prevline); TT.repeats = 0; tmpline = prevline; prevline = thisline; thisline = tmpline; tmpsize = prevsize; prevsize = thissize; thissize = tmpsize; } } print_line(outfile, prevline); if (CFG_TOYBOX_FREE) { if (outfile != stdout) fclose(outfile); if (infile != stdin) fclose(infile); free(prevline); free(thisline); } }