#define VERSION "uniq.c -- BDS Version 1.0 -- 6/20/82"
/*
 *	uniq - report repeated lines in a file
 *
 *	Adapted for BDS C by Jeff Martin, from a program by the same
 *	name written to run under the Unix (tm) operating system.
 *
 *	From the manual page for the Unix command:
 *
 *	  "Uniq reads the input file comparing adjacent lines.  In the
 *	  normal case, the second and succeeding copies	of repeated
 *	  lines	are removed; the remainder is written on the output
 *	  file.	 Input and output should always	be different.  Note
 *	  that repeated	lines must be adjacent in order	to be found.
 *	  If the -u flag is used, just the lines that
 *	  are not repeated in the original file	are output.  The -d
 *	  option specifies that	one copy of just the repeated lines is
 *	  to be	written.  The normal mode output is the	union of the
 *	  -u and -d mode outputs.
 *
 *	  "The -c option supersedes -u and -d and generates an output
 *	  report in default style but with each	line preceded by a
 *	  count	of the number of times it occurred.
 *
 *	  "The n arguments specify skipping an initial portion of each
 *	  line in the comparison:
 *
 *	  -n	  The first n fields together with any blanks before
 *		  each are ignored.  A field is	defined	as a string of
 *		  non-space, non-tab characters	separated by tabs and
 *		  spaces from its neighbors.
 *
 *	  ^n	  The first n characters are ignored.  Fields are
 *		  skipped before characters."
 *
 *	To compile: CC1 uniq.c
 *
 *	To link: L2 uniq dio
 *	  or --  CLINK uniq -f dio
 */

#define STDERR 4
#include <a:bdscio.h>
#include <a:dio.h>

	int	fields;
	int	letters;
	int	linec;
	char	mode;
	int	uniq;
	char	*skip();
	char	b1[1000], b2[1000];
	struct _buf	infile;

main(argc, argv)
int argc;
char *argv[];
{
	dioinit(&argc, argv);

	fields = letters = linec = uniq = 0;
	mode = '\0';
	while(argc > 1) {
		if(*argv[1] == '-') {
			if (isdigit(argv[1][1]))
				fields = atoi(&argv[1][1]);
			else mode = tolower(argv[1][1]);
			argc--;
			argv++;
			continue;
		}
		if(*argv[1] == '^') {
			letters = atoi(&argv[1][1]);
			argc--;
			argv++;
			continue;
		}
		if ((argc == 2) && (fopen(argv[1], infile) == ERROR)) {
			fprintf(STDERR,"Cannot open %s\n", argv[1]);
			exit(1);
		}
		break;
	}

	if (argc != 2) {
		usage();
		exit(1);
	}

	if(gline(b1)) {
		dioflush();
		exit(0);
	}
	for(;;) {
		linec++;
		if(gline(b2)) {
			pline(b1);
			dioflush();
			exit(0);
		}
		if(!equal(b1, b2)) {
			pline(b1);
			linec = 0;
			do {
				linec++;
				if(gline(b1)) {
					pline(b2);
					dioflush();
					exit(0);
				}
			} while(equal(b1, b2));
			pline(b2);
			linec = 0;
		}
	}
}

usage()
{
	fprintf(STDERR,"\n%s\n",VERSION);
	fputs("\nUsage: UNIQ [-u][-d][-c] [-n] [^n] input [>output]\n",STDERR);
	fputs("\t-u ==> just output unrepeated lines\n",STDERR);
	fputs("\t-d ==> output one copy of just repeated lines\n",STDERR);
	fputs("\t(default) ==> union of -u and -d options\n\n",STDERR);
	fputs("\t-c ==> prefix each output line with count of occurrences\n\n",STDERR);
	fputs("\t-n ==> skip first n fields in comparison\n",STDERR);
	fputs("\t^n ==> ignore first n characters (fields are skipped first)\n",STDERR);
	exit(1);
}

gline(buf)
char buf[];
{

	if (fgets(buf,infile) == NULL) {
		*buf = 0;
		return(1);
	}
	buf[strlen(buf)-1] = '\0';
	return(0);
}

pline(buf)
char buf[];
{
	switch(mode) {

	case 'u':
		if(uniq) {
			uniq = 0;
			return;
		}
		break;

	case 'd':
		if(uniq)
			break;
		return;

	case 'c':
		printf("%4d ", linec);
	}
	uniq = 0;
	puts(buf);
	putchar('\n');
}

equal(s1, s2)
char s1[], s2[];
{
	char c;

	s1 = skip(s1);
	s2 = skip(s2);
	while((c = *s1++) != 0)
		if(c != *s2++) return(0);
	if(*s2 != 0)
		return(0);
	uniq++;
	return(1);
}

char *
skip(s)
char *s;
{
	int nf, nl;

	nf = nl = 0;
	while(nf++ < fields) {
		while(*s == ' ' || *s == '\t')
			s++;
		while( !(*s == ' ' || *s == '\t' || *s == 0) ) 
			s++;
	}
	while(nl++ < letters && *s != 0) 
			s++;
	return(s);
}

