/*
 * CDE - Common Desktop Environment
 *
 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these libraries and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
 */
/* $XConsortium: uniq.c /main/3 1995/11/01 19:08:52 rswiston $ */
/***************************************************************
*                                                              *
*                      AT&T - PROPRIETARY                      *
*                                                              *
*         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
*                          AT&T CORP.                          *
*                                                              *
*                Copyright (c) 1995 AT&T Corp.                 *
*                     All Rights Reserved                      *
*                                                              *
*           This software is licensed by AT&T Corp.            *
*       under the terms and conditions of the license in       *
*       http://www.research.att.com/orgs/ssr/book/reuse        *
*                                                              *
*               This software was created by the               *
*           Software Engineering Research Department           *
*                    AT&T Bell Laboratories                    *
*                                                              *
*               For further information contact                *
*                     gsf@research.att.com                     *
*                                                              *
***************************************************************/

/* : : generated by proto : : */

#if !defined(__PROTO__)
#if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
#if defined(__cplusplus)
#define __MANGLE__	"C"
#else
#define __MANGLE__
#endif
#define __STDARG__
#define __PROTO__(x)	x
#define __OTORP__(x)
#define __PARAM__(n,o)	n
#if !defined(__STDC__) && !defined(__cplusplus)
#if !defined(c_plusplus)
#define const
#endif
#define signed
#define void		int
#define volatile
#define __V_		char
#else
#define __V_		void
#endif
#else
#define __PROTO__(x)	()
#define __OTORP__(x)	x
#define __PARAM__(n,o)	o
#define __MANGLE__
#define __V_		char
#define const
#define signed
#define void		int
#define volatile
#endif
#if defined(__cplusplus) || defined(c_plusplus)
#define __VARARG__	...
#else
#define __VARARG__
#endif
#if defined(__STDARG__)
#define __VA_START__(p,a)	va_start(p,a)
#else
#define __VA_START__(p,a)	va_start(p)
#endif
#endif
static const char id[] = "\n@(#)uniq (AT&T Bell Laboratories) 04/01/93\0\n";

#include <cmdlib.h>

#define C_FLAG	1
#define D_FLAG	2
#define U_FLAG	4
#define CWIDTH	4
#define MAXCNT	9999

/*
 * return a pointer to a side buffer
 */
static char *sidebuff __PARAM__((int size), (size)) __OTORP__(int size;){
	static int maxbuff;
	static char *buff;
	register char *cp=0;
	if(size)
	{
		if(size <= maxbuff)
			return(buff);
		buff = newof(buff, char, size, 0);
	}
	else
	{
		free(buff);
		buff = 0;
	}
	maxbuff = size;
	return(buff);
}

static int uniq __PARAM__((Sfio_t *fdin, Sfio_t *fdout, int fields, int chars, int mode), (fdin, fdout, fields, chars, mode)) __OTORP__(Sfio_t *fdin; Sfio_t *fdout; int fields; int chars; int mode;){
	register int n, outsize=0;
	register char *cp, *bufp, *outp;
	char *orecp, *sbufp=0, *outbuff;
	int reclen,oreclen= -1,count=0, cwidth=0;
	if(mode&C_FLAG)
		cwidth = CWIDTH+1;
	while(1)
	{
		if(cp = bufp = sfgetr(fdin,'\n',0))
		{
			if(n=fields)
			{
				while(*cp!='\n') /* skip over fields */
				{
					while(*cp==' ' || *cp=='\t')
						cp++;
					if(n-- <=0)
						break;
					while(*cp!=' ' && *cp!='\t' && *cp!='\n')
						cp++;
				}
			}
			if(chars)
				cp += chars;
			n = sfslen();
			if((reclen = n - (cp-bufp)) <=0)
			{
				reclen = 1;
				cp = bufp + sfslen()-1;
			}
		}
		else
			reclen=0;
		if(reclen==oreclen && memcmp(cp,orecp,reclen)==0)
		{
			count++;
			continue;
		}
		/* no match */
		if(outsize>0)
		{
			if(((mode&D_FLAG)&&count==0) || ((mode&U_FLAG)&&count))
			{
				if(outp!=sbufp)
					sfwrite(fdout,outp,0);
			}
			else
			{
				if(cwidth)
				{
					outp[CWIDTH] = ' ';
					if(count<MAXCNT)
					{
						sfsprintf(outp,cwidth,"%*d",CWIDTH,count+1);
						outp[CWIDTH] = ' ';
					}
					else
					{
						outsize -= (CWIDTH+1);
						if(outp!=sbufp)
						{
							if(!(sbufp=sidebuff(outsize)))
								return(1);
							memcpy(sbufp,outp+CWIDTH+1,outsize);
							sfwrite(fdout,outp,0);
							outp = sbufp;
						}
						else
							outp += CWIDTH+1;
						sfprintf(fdout,"%4d ",count+1);
					}
				}
				if(sfwrite(fdout,outp,outsize) < 0)
					return(1);
			}
		}
		if(reclen==0)
			break;
		count = 0;
		/* save current record */
		if (!(outbuff = sfreserve(fdout, 0, 0)) || (outsize = sfslen()) < 0)
			return(1);
		outp = outbuff;
		if(outsize < n+cwidth)
		{
			/* no room in outp, clear lock and use side buffer */
			sfwrite(fdout,outp,0);
			if(!(sbufp = outp=sidebuff(outsize=n+cwidth)))
				return(1);
		}
		else
			outsize = n+cwidth;
		memcpy(outp+cwidth,bufp,n);
		oreclen = reclen;
		orecp = outp+cwidth + (cp-bufp);
	}
	sidebuff(0);
	return(0);
}

int
b_uniq __PARAM__((int argc, char** argv), (argc, argv)) __OTORP__(int argc; char** argv;){
	register int n, mode=0;
	register char *cp;
	int fields=0, chars=0;
	Sfio_t *fpin, *fpout;

	NoP(id[0]);
	NoP(argc);
	cmdinit(argv);
	while (n = optget(argv, "cduf#[fields]s#[chars] [infile [outfile]]")) switch (n)
	{
	    case 'c':
		mode |= C_FLAG;
		break;
	    case 'd':
		mode |= D_FLAG;
		break;
	    case 'u':
		mode |= U_FLAG;
		break;
	    case 'f':
		if(*opt_info.option=='-')
			fields = opt_info.num;
		else
			chars = opt_info.num;
		break;
	    case 's':
		chars = opt_info.num;
		break;
	    case ':':
		error(2, opt_info.arg);
		break;
	    case '?':
		error(ERROR_usage(2), opt_info.arg);
		break;
	}
	argv += opt_info.index;
	if(error_info.errors)
		error(ERROR_usage(2),optusage(NiL));
	if((cp = *argv) && (argv++,!streq(cp,"-")))
	{
		if(!(fpin = sfopen(NiL,cp,"r")))
			error(ERROR_system(1),"%s: cannot open",cp);
	}
	else
		fpin = sfstdin;
	if(cp = *argv)
	{
		argv++;
		if(!(fpout = sfopen(NiL,cp,"w")))
			error(ERROR_system(1),"%s: cannot create",cp);
	}
	else
		fpout = sfstdout;
	if(*argv)
	{
		error(2, "too many arguments");
		error(ERROR_usage(2),optusage(NiL));
	}
	error_info.errors = uniq(fpin,fpout,fields,chars,mode);
	if(fpin!=sfstdin)
		sfclose(fpin);
	if(fpout!=sfstdout)
		sfclose(fpout);
	return(error_info.errors);
}
