196 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* uniq - compact repeated lines		Author: John Woods */
 | |
| /* Uniq [-udc] [-n] [+n] [infile [outfile]]
 | |
|  *
 | |
|  *	Written 02/08/86 by John Woods, placed into public domain.  Enjoy.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| /* 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
 | |
| #include <ctype.h>
 | |
| #include <errno.h>
 | |
| #include <string.h>
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| 
 | |
| char buffer[BUFSIZ];
 | |
| int uflag = 1;			/* default is union of -d and -u outputs */
 | |
| int dflag = 1;			/* flags are mutually exclusive */
 | |
| int cflag = 0;
 | |
| int fields = 0;
 | |
| int chars = 0;
 | |
| 
 | |
| _PROTOTYPE(int main, (int argc, char **argv));
 | |
| _PROTOTYPE(FILE *xfopen, (char *fn, char *mode));
 | |
| _PROTOTYPE(char *skip, (char *s));
 | |
| _PROTOTYPE(int equal, (char *s1, char *s2));
 | |
| _PROTOTYPE(void show, (char *line, int count));
 | |
| _PROTOTYPE(int uniq, (void));
 | |
| _PROTOTYPE(void usage, (void));
 | |
| _PROTOTYPE(int getline, (char *buf, int count));
 | |
| 
 | |
| FILE *xfopen(fn, mode)
 | |
| char *fn, *mode;
 | |
| {
 | |
|   FILE *p;
 | |
| 
 | |
|   if ((p = fopen(fn, mode)) == NULL) {
 | |
| 	perror("uniq");
 | |
| 	fflush(stdout);
 | |
| 	exit(1);
 | |
|   }
 | |
|   return(p);
 | |
| }
 | |
| 
 | |
| int main(argc, argv)
 | |
| int argc;
 | |
| char *argv[];
 | |
| {
 | |
|   char *p;
 | |
|   int inf = -1, outf;
 | |
| 
 | |
|   setbuf(stdout, buffer);
 | |
|   for (--argc, ++argv; argc > 0 && (**argv == '-' || **argv == '+');
 | |
|        --argc, ++argv) {
 | |
| 	if (**argv == '+')
 | |
| 		chars = atoi(*argv + 1);
 | |
| 	else if (isdigit(argv[0][1]))
 | |
| 		fields = atoi(*argv + 1);
 | |
| 	else if (argv[0][1] == '\0')
 | |
| 		inf = 0;	/* - is stdin */
 | |
| 	else
 | |
| 		for (p = *argv + 1; *p; p++) {
 | |
| 			switch (*p) {
 | |
| 			    case 'd':
 | |
| 				dflag = 1;
 | |
| 				uflag = 0;
 | |
| 				break;
 | |
| 			    case 'u':
 | |
| 				uflag = 1;
 | |
| 				dflag = 0;
 | |
| 				break;
 | |
| 			    case 'c':	cflag = 1;	break;
 | |
| 			    default:	usage();
 | |
| 			}
 | |
| 		}
 | |
|   }
 | |
| 
 | |
|   /* 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);
 | |
|   return(0);
 | |
| }
 | |
| 
 | |
| char *skip(s)
 | |
| char *s;
 | |
| {
 | |
|   int n;
 | |
| 
 | |
|   /* Skip fields */
 | |
|   for (n = fields; 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 = chars; n > 0; --n) {
 | |
| 	if (!*s) return s;
 | |
| 	s++;
 | |
|   }
 | |
|   return s;
 | |
| }
 | |
| 
 | |
| int equal(s1, s2)
 | |
| char *s1, *s2;
 | |
| {
 | |
|   return !strcmp(skip(s1), skip(s2));
 | |
| }
 | |
| 
 | |
| void show(line, count)
 | |
| char *line;
 | |
| int count;
 | |
| {
 | |
|   if (cflag)
 | |
| 	printf("%4d %s", count, line);
 | |
|   else {
 | |
| 	if ((uflag && count == 1) || (dflag && count != 1))
 | |
| 		printf("%s", line);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* The meat of the whole affair */
 | |
| char *nowline, *prevline, buf1[1024], buf2[1024];
 | |
| 
 | |
| int uniq()
 | |
| {
 | |
|   char *p;
 | |
|   int seen;
 | |
| 
 | |
|   /* Setup */
 | |
|   prevline = buf1;
 | |
|   if (getline(prevline, 1024) < 0) return(0);
 | |
|   seen = 1;
 | |
|   nowline = buf2;
 | |
| 
 | |
|   /* Get nowline and compare if not equal, dump prevline and swap
 | |
|    * pointers else continue, bumping seen count */
 | |
|   while (getline(nowline, 1024) > 0) {
 | |
| 	if (!equal(prevline, nowline)) {
 | |
| 		show(prevline, seen);
 | |
| 		seen = 1;
 | |
| 		p = nowline;
 | |
| 		nowline = prevline;
 | |
| 		prevline = p;
 | |
| 	} else
 | |
| 		seen += 1;
 | |
|   }
 | |
|   show(prevline, seen);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| void usage()
 | |
| {
 | |
|   fprintf(stderr, "Usage: uniq [-udc] [+n] [-n] [input [output]]\n");
 | |
| }
 | |
| 
 | |
| int getline(buf, count)
 | |
| char *buf;
 | |
| int count;
 | |
| {
 | |
|   int c;
 | |
|   int ct = 0;
 | |
| 
 | |
|   while (ct++ < count) {
 | |
| 	c = getc(stdin);
 | |
| 	if (c < 0) return(-1);
 | |
| 	*buf++ = c;
 | |
| 	if (c == '\n') {
 | |
| 		*buf++ = 0;
 | |
| 		return(ct);
 | |
| 	}
 | |
|   }
 | |
|   return(ct);
 | |
| }
 | 
