[net.sources] 'cut' reposted

benjamin@uhmanoa.UUCP (03/12/87)

	The cut source distributed by John Weald did not
seem to work right on our 4.3BSD.  I've made some modifications
and allowed combination of range (-) and specifics (,) in the
argument list.  If you have problems with the original posting,
replace with this below:

benjamin@uhmanoa.ICS.HAWAII.EDU
----------------------------- cut cut ----------------------------------  
#! /bin/sh
#
# This is John Weald's 'cut' program which did not seem to
# work correctly. So I've made some modifications, seems okay
# right now, these are legal: 
#  
#	cut -f3 -d' '  and   cut -f1,3,2,4-6  
#
#   
#		   SHAR AND ENJOY !!!!!
#
PATH=/bin:/usr/bin:/usr/ucb; export PATH
echo shar: 'extracting "'cut.c'" '
if test -f 'cut.c' ; then 
  echo shar: will not over-write existing file "'cut.c'"
else
sed 's/^X//' >cut.c <<'@//E*O*F cut.c//'
X/*
X *  This acts the same as SV cut(1), except that the list of numbers
X *  does not have to be assending.
X *
X *  John Weald
X */
X#include <stdio.h>
X#include <ctype.h>
X
X#define MAXLINE	1024		/* The max. length of a line		*/
X#define DEBUG	0
X
Xextern void exit();
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	extern char *optarg;
X	extern int optind;
X
X	static int fields[MAXLINE];/* The field markers. True if this field */
X				   /* is to be cut, False otherwise	*/
X	FILE *fp;		   /* All the input files or stdin	*/
X	char buf[MAXLINE];	   /* The input buffer			*/
X	int c;			   /* The command line option		*/
X	int err = 0;		   /* True if error in command line	*/
X	int fflag = 0;		   /* True if -f on command line	*/
X	int cflag = 0;		   /* True if -c on command line	*/
X	int suppress = 0;	   /* Suppress lines with no delimitor	*/
X	char fs = '\t';		   /* The field separator		*/
X
X
X	while ((c = getopt(argc, argv, "f:d:c:s")) != EOF)
X	{
X		switch (c)
X		{
X		   case 'f':
X			/* By Field */
X			list(fields, optarg);
X			fflag++;
X			if (cflag)
X				err++;
X			break;
X
X		   case 'c':
X			/* By character */
X			list(fields, optarg);
X			/* Implied suppress */
X			suppress++;
X			cflag++;
X			if (fflag)
X				err++;
X			break;
X
X		   case 'd':
X			/* A new field spererator */
X			fs = *optarg;
X			break;
X
X		   case 's':
X			suppress++;
X			break;
X
X		   default:
X			prusage();
X		}
X	}
X
X	if (!cflag && !fflag)
X	{
X		fprintf(stderr, "Must have one of -f or -c\n");
X		err++;
X	}
X	if (err)
X		prusage();
X
X
X	/*
X	 * Loop on all the files.
X	 */
X	do {
X		if (optind == argc)
X			fp = stdin;
X		else if ((fp = fopen(argv[optind], "r")) == (FILE *)NULL)
X		{
X			fprintf(stderr, "Failed to open file %s\n", 
X					argv[optind]);
X			exit(1);
X		}
X
X		/*
X		 * Loop on all lines in the file.
X		 */
X		while (fgets(buf, sizeof(buf), fp) != (char *)NULL)
X		{
X			cut(buf, fields, fs, suppress, cflag);
X		}
X		(void)fclose(fp);
X	} while (++optind < argc);
X
X	exit(0);
X/* NOTREACHED */
X}
X
X/*
X * Cut the line. This handles both character and field cutting.
X * For character cutting the f array gives character positions, for
X * fields it gives the field number. It must be indexed by either the
X * character number or the field number.
X */
Xcut(in, f, fs, sup, c_or_f)
Xregister char *in;		/* The input line			*/
Xint f[];			/* The field cutting flags		*/
Xchar fs;			/* The field seperator			*/
Xint sup;			/* Suppress lines with no-delimitor?	*/
Xint c_or_f;			/* Cut by char. (true), or field (false)*/
X{
X	char obuf[MAXLINE];	/* Output buffer			*/
X	register char *optr = obuf;
X	register int i;		/* Character count			*/
X	register int fld;	/* The field count			*/
X	char *instart = in;	/* To print lines with no delimiters	*/
X
X 	if (DEBUG)	printf("c_or_f=%d\n",c_or_f);	
X	for (fld = 0, i = 0; i < MAXLINE; i++)
X	{
X		if (*in == '\n')
X		{
X			/* End of the line */
X
X			*optr = '\0';
X			/* Any thing to cut? */
X			if (optr != obuf)
X			{
X				/* Get ride of trailing seperator */
X				if (*(optr - 1) == fs)
X					*(optr - 1) = '\0';
X				puts(obuf);
X			}
X			else if (!sup)
X				printf(instart);
X			return;
X		}
X		if (DEBUG)   printf("%d",f[c_or_f ? i : fld]);
X		if (f[c_or_f ? i : fld])
X		{
X			*optr++ = *in;
X		}
X
X		/* End of field? */
X		if (*in++ == fs)
X			fld++;
X	}
X
X	fprintf(stderr, "Line too long, maximum length is %d\n", MAXLINE);
X	exit(1);
X}
X
X/*
X * Parse the list argument. The format is:
X *	n,n
X * where n is either a number or a range of numbers in the format
X *	m-l
X * m or l  may be absent, indicating the start or end of the lines respectivly.
X * Numbers must be in increasing order for m-l format, but not for n,n.
X * Field numbers start at 1, but index into fields array starts at 0.
X * 
X */
Xlist(f, l)
Xint f[];		/* The fields				*/
Xchar *l;		/* The list				*/
X{
X	int range = 0;	/* True if m-l format			 */
X	int low, high;	/* the low and high numbers in a m-l pair*/
X	int noop,i;
X
X	low = high = 0; noop = 1;
X
X	while (1)
X	{
X		switch(*l)
X		{
X		   case '\0':
X			if (low > 0 && noop) f[low-1]++;
X			return;
X
X		   case ',':
X			if (noop) noop--;
X			l++;
X		       	if (!range) f[low-1]++;
X			else {
X				if (isdigit( (int)*l ))
X				{
X					f[ (low=atoi(l))-1 ]++;
X					while(isdigit( (int)*l ) ) l++;
X				}
X			}
X			range = 0;
X			low = 1;
X			break;
X
X		   case '-':
X			l++;
X			if (noop) noop--;
X			range++;
X			/* Is it m-<nothing> */
X			if (isdigit((int)*l))
X			{
X				high = atoi(l);
X				/* Skip the digits */
X				while (isdigit((int) *l))
X					l++;
X			}
X			else
X				high = MAXLINE;
X
X			/* Is the range the correct way around? */
X			if (low > high)
X			{
X				fprintf(stderr, "Bad c/f list: %d > %d\n", 
X							low, high);
X				exit(1);
X			}
X			/* Set the field flags for the range */
X			for(i = low - 1; i < high; i++)
X				f[i]++;
X			break;
X
X		    default:
X			/* either a number or an error */
X			if (!isdigit((int) *l))
X			{
X				fprintf(stderr, "Bad c/f list at %s\n", l);
X				exit(1);
X			}
X			low = atoi(l);
X			if (low == 0)
X			{
X				fprintf(stderr, "Fields start at 1 not 0\n");
X				exit(1);
X			}
X			/* Skip the digits */
X			while (isdigit((int) *l))
X				l++;
X			break;
X		}
X	}
X}
X
Xprusage()
X{
X	fprintf(stderr, "cut [-d<delimitor>] [-s] -c<list>|-f<list> [files]\n");
X	exit(1);
X}
@//E*O*F cut.c//
echo "end of shar"
fi
exit 0