/************************************************************************ * * * * * Filename: uniq.c * * * * uniq - compact repeated lines Author: John Woods * * * * ( looks like UNIX version ) * * * * Written 02/08/86 by John Woods, placed into public domain. Enjoy. * * * * Amiga port by Gary Duncan , Canberra Australia * * * * * *-----------------------------------------------------------------------* * * * * Modification record: *~~~~~~~~~~~~~~~~~~~~ * * Date By whom Change * ---- ------- ------ * * JW Original * 04Jan90 GMD Amiga port : reformatted, headers * added , usage() added. * +/-n option bug fixed * * Function Description * ~~~~~~~~ ~~~~~~~~~~~ *+ main *+ skip *+ equal *+ show *+ uniq *+ usage *+ getline *+ xfopen *+ * * *******************************************************************************/ #include "stdio.h" #include "ctype.h" /* * give a version # ( GMD ) */ #define VERS "1.1" /* If the symbol WRITE_ERROR is defined, uniq will exit(1) if it gets a * write error on the output. This is not (of course) how V7 uniq does it, * so undefine the symbol if you want to lose your output to a full disk */ #define WRITE_ERROR 1 #define GBUF 1024 extern char *MakeDate[] ; FILE *fopen(); FILE *xfopen(); char xbuffer [BUFSIZ]; int xuflag = 1; /* default is union of -d and -u outputs */ int xdflag = 1; /* flags are mutually exclusive */ int xcflag = 0; int xfields = 0; int xchars = 0; char *xcurline ; char *xprevline ; char xbuf1 [GBUF] ; char xbuf2 [GBUF] ; /*************************************************************************** Name : main Purpose: ..every C prog deserves one.. Entry : Returns : ****************************************************************************/ int main(argc,argv) char *argv[]; { char *p; int inf = -1, outf; if (argc == 1 ) { usage() ; exit (1) ; } setbuf(stdout, xbuffer); for (--argc, ++argv; (argc > 0) && (**argv == '-' || **argv == '+'); --argc, ++argv) { if (**argv == '+') xchars = atoi(*argv + 1); else if (isdigit(argv[0][1])) xfields = atoi(*argv + 1); else if (argv[0][1] == '\0') inf = 0; /* - is stdin */ else { for (p = *argv+1; *p; p++) { switch(*p) { case 'd': xdflag = 1; xuflag = 0; break; case 'u': xuflag = 1; xdflag = 0; break; case 'c': xcflag = 1; break; default: usage(); exit(1) ; } } } } /* input file */ if (argc == 0) inf = 0; else if (inf == -1) { /* if - was not given */ fclose(stdin); xfopen(*argv++, "r"); argc--; } if (argc == 0) outf = 1; else { fclose(stdout); xfopen(*argv++, "w"); argc--; } uniq(); fflush(stdout); exit(0); } /*************************************************************************** Name : skip Purpose: +- n options ; skip fields / charas in fields Entry : Returns : ptr to (+nth) chara in (-nth)field or NULL if not found ****************************************************************************/ char *skip(s) char *s; { int n; /* skip xfields */ for (n = xfields; n > 0 ; --n) { /* skip blanks */ while (*s && (*s == ' ' || *s == '\t')) s++; if (!*s) return s; while (*s && (*s != ' ' && *s != '\t')) s++; if (!*s) return s; } /* skip characters */ for (n = xchars; n > 0; --n) { if (!*s) return s; s++; } return s; } /*************************************************************************** Name : equal Purpose: tests 2 strings for equality Entry : Returns : ****************************************************************************/ int equal(s1, s2) char *s1, *s2; { return !strcmp( skip(s1), skip(s2)); } /*************************************************************************** Name : show Purpose: Entry : Returns : ****************************************************************************/ void show(line,count) int count ; char *line; { if (xcflag) printf("%4d %s", count,line); else { if ((xuflag && count == 1) || (xdflag && count != 1)) printf("%s", line); } } /*************************************************************************** Name : uniq Purpose: Entry : Returns : ****************************************************************************/ int uniq() { char *ptr; int seen = 1 ; /* initialise "prev" line ( setup ?? ) */ xprevline = xbuf1; if (getline(xprevline, GBUF) < 0) return(0); xcurline = xbuf2; /* get xcurline and compare * if not equal, dump xprevline and swap pointers * else continue, bumping seen count */ while (getline(xcurline, GBUF) > 0) { if (!equal(xprevline, xcurline)) { show(xprevline, seen); seen = 1; ptr = xcurline; xcurline = xprevline; xprevline = ptr; } else seen += 1; } show(xprevline, seen); return 0; } /*************************************************************************** Name : getline Purpose: Entry : Returns : -1 ; EOF # of charas read ****************************************************************************/ int getline(buf,count) char *buf; int count; { char c; char * cats = buf ; int ct = 0; while (ct++ < count) { c = getc(stdin); if (c <= 0) return(-1); *cats++ = c; if (c == '\n') { *cats++ = 0; /* * read another line if no 'n' compliance */ if ( xchars || xfields ) { if ( *skip(buf) == '\0' ) { ct = 0 ; cats = buf ; } else /* exit */ return (ct) ; } else return (ct) ; } } return(ct); } /*************************************************************************** Name : xfopen Purpose: Entry : Returns : v****************************************************************************/ FILE *xfopen(fn, mode) char *fn, *mode; { FILE *p; extern int errno; extern char *sys_errlist[]; if ((p = fopen(fn,mode)) == NULL) { perror("uniq"); fflush(stdout); exit(1); } return (p); } /*************************************************************************** Name : usage Purpose: Entry : Returns : ****************************************************************************/ int usage() { static char *rats[] = { " - Written by John Woods (Amiga port by Gary Duncan)\n", "usage: uniq [-udc] [+n] [-n] [input [output]]" , " -c ; print lines , count repeated ones", " -d ; print first occurrence of replicated lines only (default)", " -u ; print only unique lines", " +n ; skip n charas from start of field", " -n ; skip n fields from start of line", "" } ; int j = 0 ; char * ptr ; fprintf(stderr, "uniq: Version %s [ %s ]\n" , VERS , MakeDate[0] ) ; while ( *(ptr=rats[j++]) ) fprintf(stderr,"%s\n" , ptr ); }