/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 *
 */

/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident	"$Header: cut.c 1.5 89/11/14 $@(#)cut:cut.c	1.11"
#
/* cut : cut and paste columns of a table (projection of a relation) */
/* Release 1.5; handles single backspaces as produced by nroff    */
# include <stdio.h>	/* make: cc cut.c */
# include <ctype.h>

#ifdef CCS
#include "../../tools/compat.h"
#else
# include <euc.h>
# include <getwidth.h>
#endif

# define MLTDUMB ' '
# define NFIELDS 1024	/* max no of fields or resulting line length */
# define BACKSPACE '\b'

int strcmp(), atoi();
void exit();


main(argc, argv)
int	argc;
char	**argv;
{
	extern int	optind;
	extern char	*optarg;
	static char	usage[] = "Usage: cut [-s] [-d<char>] {-c<list> | -f<list>} file ...";
	static char	cflist[] = "bad list for c/f option";
	register int	c;
	register char	*p1, *rbuf;
	register char	*p, *list;
	char	*del;
	int	num, j, count, poscnt, r, s;
	int	endflag, supflag, cflag, fflag, backflag, filenr;
	static  int	sel[NFIELDS];
	char 	buf[NFIELDS];
	char	*p2, outbuf[NFIELDS];
	FILE	*inptr;
	eucwidth_t wp;
	int eucwc;		/* euc width count */
	int scrwc;		/* screen width count */
	int mltflag = 0;	/* flag of multi byte system */
	int delflag = 0;	/* multibyte delimiter flag */
	int dumb = 0;		/* blank for multi byte system */
	char *pdel;		/* multibyte delimiter */
	int delw = 1;		/* delimiter width */
	int trailflag = 0;	/* trailing delimiter flag */
	int i;

	eucwc = 0;		/* initialize euc code width */
	del = "\t";		/* initialize delimiter */

	getwidth(&wp);
	wp._eucw2++;
	wp._eucw3++;

	supflag = cflag = fflag = r = num = s = 0;


	while((c = getopt(argc, argv, "c:d:f:s")) != EOF)
		switch(c) {
			case 'c':
				if (fflag)
					diag(gettxt("cut:1",usage));
				cflag++;
				list = optarg;
				break;
			case 'd':
				if (ISASCII(*optarg))
					delw = 1;
				else
					delw = ISSET2(*optarg) ? wp._eucw2 :
					       ISSET3(*optarg) ? wp._eucw3 : wp._eucw1 ;
				if (strlen(optarg) > delw)
					diag(gettxt("cut:3", "no delimiter"));
				else
					del = optarg;
				break;
			case 'f':
				if (cflag)
					diag(gettxt("cut:1",usage));
				fflag++;
				list = optarg;
				break;
			case 's':
				supflag++;
				break;
			case '?':
				diag(gettxt("cut:1",usage));
		}

	argv = &argv[optind];
	argc -= optind;

	if (!(cflag || fflag))
		diag(gettxt("cut:2",cflist));

	do {
		p = list;
		switch(*p) {
			case '-':
				if (r)
					diag(gettxt("cut:2",cflist));
				r = 1;
				if (num == 0)
					s = 1;
				else {
					s = num;
					num = 0;
				}
				break;
			case '\0' :
			case ','  :
				if (num >= NFIELDS)
					diag(gettxt("cut:2",cflist));
				if (r) {
					if (num == 0)
						num = NFIELDS - 1;
					if (num < s)
						diag(gettxt("cut:2",cflist));
					for (j = s; j <= num; j++)
						sel[j] = 1;
				} else
					sel[num] = (num > 0 ? 1 : 0);
				s = num = r = 0;
				if (*p == '\0')
					continue;
				break;
			default:
				if (!isdigit(*p))
					diag(gettxt("cut:2",cflist));
				num = atoi(p);
				while (isdigit(*list))
					list++;
				continue;
		}
		list++;
	}while (*p != '\0');
	for (j=0; j < NFIELDS && !sel[j]; j++);
	if (j >= NFIELDS)
		diag(gettxt("cut:4","no fields"));

	filenr = 0;
	do {	/* for all input files */
		if ( argc == 0 || strcmp(argv[filenr],"-") == 0 )
			inptr = stdin;
		else
			if ((inptr = fopen(argv[filenr], "r")) == NULL) {
				fprintf(stderr, gettxt("cut:5","cut: WARNING: cannot open %s\n"), argv[filenr]);
				continue;
			}
		endflag = 0;
		do {	/* for all lines of a file */
			count = poscnt = backflag = 0;
			p1 = &outbuf[0] - 1 ;
			p2 = p1;
			rbuf = buf;
			if ((fgets(buf, NFIELDS, inptr)) == NULL) {
				endflag = 1;
				continue;
			}
			do { 	/* for all char of the line */
				if (rbuf >= &buf[NFIELDS])
					diag(gettxt("cut:6","line too long"));
				delflag = 0;
				pdel = del;
				if (*rbuf != '\n')
					if (ISASCII(*rbuf)) {
						*++p1 = *rbuf;
						if (*rbuf == *pdel)
							delflag = 1;
					} else {
						mltflag = 1;
						if (ISSET2(*rbuf)) {
							eucwc = wp._eucw2;
							scrwc = wp._scrw2;
						} else
						if (ISSET3(*rbuf)) {
							eucwc = wp._eucw3;
							scrwc = wp._scrw3;
						} else {
							eucwc = wp._eucw1;
							scrwc = wp._scrw1;
						}

						do {
							*++p1 = *rbuf;
							if (*rbuf == *pdel)
								delflag++;
							rbuf++;
							pdel++;
						} while (--eucwc);
						if (delflag != delw)
							delflag = 0;
						rbuf--;
						pdel--;
					}
				if (cflag && (*rbuf == BACKSPACE))
					backflag++;
				else if (!backflag)
					poscnt += 1;
				else
					backflag--;
				if ( backflag > 1 )
					diag(gettxt("cut:7","cannot handle multiple adjacent backspaces\n"));
				/* Permits multibyte delimiter */
				if (*rbuf == '\n' && count > 0  || delflag || cflag) {
					count += 1;
					if (fflag)
						poscnt = count;
				/* Consider multiple adjacent EUC code  */

					if (mltflag && cflag) {
						for (i = poscnt; i < (poscnt + scrwc); i++) {
							if (sel[i])
								continue;
							else
								dumb++;
						}
						if (dumb) {
							p1 = p2;
							if (dumb != scrwc) {
								for (i = 0; i < (scrwc - dumb); i++) {
									p1++;
									*p1 = MLTDUMB;
								}
								p2 = p1;
							}
							dumb = 0;
						} else {
							p2 = p1;
							trailflag = delflag? 1 : 0;
						}
						mltflag = 0;
						poscnt += (scrwc - 1);
					} else {
						if (sel[poscnt]) {
							p2 = p1;
							trailflag = delflag ? 1 : 0;
						} else
							p1 = p2;
					}
				}
			} while (*rbuf++ != '\n');
			if ( !endflag && (count > 0 || !supflag)) {
			/* Permits multibyte delimeter */
				if (trailflag && !sel[count]) {
					p1 -= (delw - 1);
					*p1 = '\0'; /*suppress trailing delimiter*/
					trailflag = 0;
				}
				else
					*++p1 = '\0';
				puts(outbuf);
			}
		} while (!endflag);
		fclose(inptr);
	} while (++filenr < argc);
	exit(0);
}


diag(s)
char	*s;
{
	fprintf(stderr, gettxt("cut:8","cut: ERROR: %s\n"), s);
	exit(2);
}
