/* $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) 1986 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.	*/

/*
 ****************************************************************
 *								*
 *	eucset.c						*
 *								*
 *	Assuming the line discipline is an EUC line disc,	*
 *	set the cswidth info which is obtained from character   * 
 *	class table (if one) into the line discipline, if no    *
 *	arguments.  If an arg is given it overrides the cswidth *
 *	of the environment.  If there is one arg and it is      *
 *	"-p", then the current	values of the EUC widths are    *
 *	obtained from the linediscipline and printed.		*
 *	Return values are 0 for successful set/get; 1 for	*
 *	failure of any kind.					*
 *								*
 ****************************************************************
 */

#ident "$Header: eucset.c 1.2 90/06/27 $@(#)/usr/bin/eucset 1.2 1988/01 AT&T-UP"

#include <stdio.h>
#include <termio.h>
#include <euc.h>	/* for EUC width structure */
#include <getwidth.h>	/* for EUC width function */
#include <stropts.h>	/* Streams specific ioctls */
#include <limits.h>
#include <ctype.h>

/*
 * Driver Include File (relative to where we are):
 */
#include <sys/eucioctl.h>

#ifndef TRUE
#define TRUE	1
#define FALSE	0
#endif

#define DEF_CSWIDTH	"1:1,0:0,0:0"
#define CSWIDTH_CHAR	1
#define ANY_CHAR	2

struct eucioc eucw;	/* for EUC_WSET/EUC_WGET to line discipline */
eucwidth_t width;	/* return struct from getwidth() */

char *retval;		/* hold value of environment CSWIDTH */
char *prog;		/* pointer to our name */
char *eucc;		/* for command line arg */

char *getenv();
int __getwidth();

/*
 * MAIN	------------------------------------------------------------
 */

main(argc,argv)
	int argc;
	char **argv;
{
	prog = *argv;
	/*
	 * No arguments?  Look for CSWIDTH in environment...
	 *
	 *	If found in env and not NULL, use it silently.
	 *	If found in env and NULL, use DEF_CSWIDTH and warn user.
	 *	If NOT found in env, use DEF_CSWIDTH (_getwidth does it).
	 */
	if (argc == 1) {
#if 0
		retval = getenv("CSWIDTH");
		if (retval == NULL) {			/* not in env */
			__getwidth(&width, DEF_CSWIDTH);
		}
		else if (*retval == '\0') {		/* NULL in env */
			fprintf(stderr,
			"%s: warning - using default CSWIDTH.\n", prog);
			__getwidth(&width, DEF_CSWIDTH);
		}
		else {					/* in env & OK */
			_getwidth(&width);
		}
#endif
		getwidth(&width);
	}
	/*
	 * One arg?  See if it's "-?" or "-p".  If not, assume it is
	 * supposed to be a CSWIDTH specification.  Call the "real"
	 * getwidth function to split up the string and make eucwidth_t.
	 */
	else if (argc == 2) {
		eucc = *++argv;
		if (strcmp(eucc, "-p") == 0) {
			euclook(&eucw);
			exit(0);
		}
		else if (*eucc == '-') {
			usage(prog);
		}
		if (!__getwidth(&width, eucc))
			usage(prog);
	}
	else {
		usage(prog);
	}
	mk_euc(&eucw, &width);	/* make eucwidth struct for line disc. */
	set_euc(&eucw);		/* send ioctl downstream */
	exit(0);
}

/*
 * usage	Print usage message & go away.
 */

usage(s)
	char *s;
{
	fprintf(stderr, "Usage: %s [ x1:[y1], x2:[y2], x3:[y3] ]\n", s);
	fprintf(stderr, "       %s -p\n", s);
	exit(1);
}

/*
 * mk_euc	Take eucioc pointer and eucwidth_t pointer.
 *		Make eucioc from eucwidth_t.
 */

mk_euc(w, cw)
	struct eucioc *w;
	eucwidth_t *cw;
{
	w->eucw[0] = '\001';
	w->scrw[0] = '\001';

	w->eucw[1] = cw->_eucw1;
	w->scrw[1] = cw->_scrw1;

	w->eucw[2] = cw->_eucw2;
	w->scrw[2] = cw->_scrw2;

	w->eucw[3] = cw->_eucw3;
	w->scrw[3] = cw->_scrw3;
}

/*
 * set_euc	Send EUC code widths to line discipline.
 */

set_euc(e)
	struct eucioc *e;
{
	struct strioctl sb;

	sb.ic_cmd = EUC_WSET;
	sb.ic_timout = 0;
	sb.ic_len = sizeof(struct eucioc);
	sb.ic_dp = (char *) e;

	if (ioctl(0, I_STR, &sb) < 0)
		fail();
}

/*
 * euclook	Get current EUC code widths from line discipline.
 */

euclook(e)
	struct eucioc *e;
{
	struct strioctl sb;

	sb.ic_cmd = EUC_WGET;
	sb.ic_timout = 0;
	sb.ic_len = sizeof(struct eucioc);
	sb.ic_dp = (char *) e;
	if (ioctl(0, I_STR, &sb) < 0)
		fail();
	printf("cswidth %d:%d,%d:%d,%d:%d\n",
					e->eucw[1], e->scrw[1],
					e->eucw[2], e->scrw[2],
					e->eucw[3], e->scrw[3]);
}

/*
 * fail		Print a message and go away.
 */

fail()
{
	fprintf(stderr, "%s: EUC_WSET failed.\n", prog);
	exit(1);
}

/*
 * format	print "bad format" message & exit.
 */

format()
{
	fprintf(stderr, "%s: bad cswidth format\n", prog);
	exit(1);
}

/*
 * __getwidth	get cswidth info. from given parameter.
 */

int
__getwidth(wp, s)
	eucwidth_t *wp;
	char 	   s[];
{
	int 		w[3], sw[3];
	register int 	i, iret;
	char		*aret, *getnextsym();

	wp->_eucw1 = wp->_scrw1 = 1;
	wp->_eucw2 = wp->_eucw3 = wp->_scrw2 = wp->_scrw3 = 0;
	wp->_pcw = sizeof(unsigned short);
	wp->_multibyte = 0;

	w[0] = w[1] = w[2] =  sw[0] = sw[1] = sw[2] = 0;
	if(s) {
		for (i = 0; *s != '\0'; ++i) {
			if ((aret = getnextsym(&s, CSWIDTH_CHAR)) == NULL)
				return(0);

			iret = atoi(aret);
			if ((iret < 0) || (iret >= MB_LEN_MAX))
				return(0);

			w[i] = sw[i] = iret;
			if ((aret = getnextsym(&s, ANY_CHAR)) == NULL)
				return(0);
			
			if (*aret == ':') {
				if ((aret = getnextsym(&s, CSWIDTH_CHAR)) == NULL)
					return(0);

				iret = atoi(aret);
				if (iret < 0)
					return(0);

					/*
					 * Only update screen width if byte width 
					 * is non zero.
					 */
				if (w[i] != 0)
					sw[i] = iret;

				if ((aret = getnextsym(&s, ANY_CHAR)) == NULL)
					return(0);
			}

			if ((*aret == '\0') && (i == 2))
				break;

			if (*aret != ',')
				return(0);
		
		}
		wp->_eucw1 = w[0];
		wp->_eucw2 = w[1];
		wp->_eucw3 = w[2];
		if (w[0] > 1  || w[1] || w[2])
			wp->_multibyte = 1;

		if (w[0] > 2  || w[1] > 2 || w[2] > 2 )
			wp->_pcw = sizeof(unsigned long);

		wp->_scrw1 = sw[0];
		wp->_scrw2 = sw[1];
		wp->_scrw3 = sw[2];
	}
	return;
}

char *
getnextsym(s, token)
	char **s;
	int  token;
{
	static char	str[10];
	int		i;

	switch(token) {
		case	CSWIDTH_CHAR:
			while ((**s == ' ') || (**s == '\t')) 
				(*s)++;
			
			if ((**s =='\n') || (**s == '\0')) 
				return (NULL);

			for (i = 0; isdigit(**s); ++i, (*s)++)
				str[i] = **s; 

			str[i] = '\0';
			if (i == 0)
				return (NULL);

			break;

		case	ANY_CHAR:
			while ((**s == ' ') || (**s == '\t')) 
				(*s)++;
			
			if ((**s =='\n') || (**s == '\0')) 
				str[0] = '\0';
			else
				str[0] = **s;

			(*s)++;
			break;

		default:
			return (NULL);
			break;

	}
	return(str);
}
