/*
 *	field [-tc] [-ic] [n]
 *
 * field utility, originally from Bourne pp.228-9.  Distributed on
 * USENET, July 1985.  Rewritten.
 */


/*)BUILD	$(TKBOPTIONS) = {
			TASK	= ...FLD
		}
*/

#ifdef DOCUMENTATION

title	field	Select Fields or Columns from a File
index		Select fields or columns from a file

synopsis

	field [-tc] [-ic] [ n ] ...

description

	The field command copies selected, delimiter-separated
	fields from the standard input to the standard output.
	Fields are numbered from 1 and a field may be requested more
	than once.

	The default delimiter is a tab. This can be changed to
	character c with the option -tc. If the form -ic is used,
	the delimiter c is used on input, but the output is still
	separated by tabs.  You can also specify both separators,
	but they must be in the order listed above:

	    field -t/ -i=

	sets the output separator to '/' and the input separator
	to '='.

example

	The following command extracts the login names, user and
	group numbers from a Unix password file:

	    field -t: 1 3 4 </etc/passwd

bugs

	The number of input or output fields may not exceed 256 and
	the maximum line length is 4096 characters.

authors

	Taken from "The Unix System" by S. R. Bourne.

	Modifications by William Silvert.

	Rewritten by Martin Minow.

#endif

#include <stdio.h>
#ifdef vms
#include		<ssdef.h>
#include		<stsdef.h>
#define	IO_SUCCESS	(SS$_NORMAL | STS$M_INHIB_MSG)
#define	IO_ERROR	SS$_ABORT
#endif
/*
 * Note: IO_SUCCESS and IO_ERROR are defined in the Decus C stdio.h file
 */
#ifndef	IO_SUCCESS
#define	IO_SUCCESS	0
#endif
#ifndef	IO_ERROR
#define	IO_ERROR	1
#endif

#define MAXF	256
#define MAXL	4096
#define IFS	'\t'	/* Default ffield separator is tab on input	*/
#define OFS	'\t'	/* and on output, too.				*/

int	field[MAXF];	/* Field number to output (for reordering)	*/
int	nfields = 0;	/* field[0 .. nfields - 1] are active		*/
int	linefields;	/* Number of fields on this line		*/
char	*fieldp[MAXF];	/* Points to first byte of this field		*/
char	line[MAXL];
char	insep = IFS;	/* Input field separator			*/
char	outsep = OFS;	/* Output field separator			*/

main(argc,argv)
int		argc;
char		*argv[];
{
	register char	*lp;		/* Curr. pos on input line	*/
	register char	**fp;		/* Current field (->fieldp[i])	*/
	register int	c;
	int		fcount;
	char		opt, fs;

#ifdef vms
	argc = getredirection(argc, argv);
#endif
	while (argc > 1) {
	    if (sscanf(argv[1], "-%c%c", &opt, &fs) == 2) {
		switch (opt) {
		case 't':		/* change both field separators	*/
		    outsep = fs;
		case 'i':		/* change only input separator	*/
		    insep = fs;
		    break;

		default:
		    goto usage;
		}
	    }
	    else if (sscanf(argv[1], "%d", &field[nfields++]) != 1) {
usage:		printf("usage: %s [-tc] [ n ] ...\n", argv[0]);
		exit(IO_ERROR);
	    }
	    argc--;
	    argv++;
	}
	while (!feof(stdin)) {
	    lp = line;
	    fp = fieldp;
	    *fp++ = lp;				/* First field		*/
	    while ((c = getchar()) != '\n' && c != EOF) {
	        if (c == insep) {
		    *fp++ = lp;			/* Start of next field	*/
	        }
	        else {
		    *lp++ = c;			/* Store char in field	*/
	        }
	    }
	    if (lp == line && c == EOF)
		break;
	    *fp = lp;				/* Remember last's end	*/
	    linefields = fp - fieldp;		/* Fields on this line	*/
	    for (fcount = 0; fcount < nfields; fcount++) {
		outputfield(field[fcount] - 1);	/* Output nth field	*/
		if (fcount != (nfields - 1))	/* Maybe separator, too	*/
		    putchar(outsep);
	    }
	    if (c == '\n')
		putchar('\n');
	}
	return (IO_SUCCESS);
}

outputfield(n)
int	n;
/*
 * output field n from current line
 */
{

	register char *lp;
	register char *ep;

	if (n < 0 || n >= linefields)
	    return;
	lp = fieldp[n];
	ep = fieldp[n + 1];
	while (lp < ep)
	    putchar(*lp++);
}
