/*===========================================================================
  Copyright (C) 1987-2009 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, 
  MA 02139, USA.
 
  Corresponding concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.TYPE		Module
.IDENTIFICATION tvutil.c
.AUTHOR    	Francois Ochsenbein [ESO-IPG]
.LANGUAGE  	C
.KEYWORDS	Termcap
.ENVIRONMENT	TermWindows
.COMMENTS	This module provides various utilities related to
		TERMCAPabilities or Terminal manipulations.

.VERSION 2.0	12-Jun-1987: Creation. Extracted from full capability version.

.VERSION 2.2	23-Jun-1987: Adapted to UNIX
.VERSION 2.3	02-Dec-1987	Use of external function while waiting for input
.VERSION 2.4	21-Feb-1990	Removed warning 
		
 090831		last modif
----------------------------------------------------------------------------*/

#define		DEBUG		0	/* For debugging only */

#define		PM_LEVEL 	LEVEL_TU

#define	TW_MACROS	0		/* Don't use TermWindows Macros */
#define	TW_import	0	
#define TW_STRUCT	0	/* Do not use window Structures		*/
#include <twset.h>


extern int pm_ed_tr2(), pm_enter(), pm_iexit(), eh_ed_str2(), eh_put1();


MID_EXTERN	TERM *terms;

		/* Macros just to improve readibility	*/

#define		NCAPS			(terms->ns)
#define		CAPLIST			(terms->caplist)
#define		CAPSIZE			(terms->size)
#define		CAPTOP			(terms->captop)


	MONITOR(TVUTIL);


/*==========================================================================
 *			tu_format
 *==========================================================================*/
int tu_format (out, fm, coo)
/*++++++++++++++
.PURPOSE Edits coordinates according to the coded TERMCAP format.
.RETURNS Length of edited string
.REMARKS No test on the length of edited string is performed.
	If the format designates more than 2 arguments, the 3rd is 
	the repetition of the first, etc..
---------------*/
	unsigned char *out; /* OUT: The output buffer, receiving edited coordinates */
	unsigned char *fm;  /* IN: The coded TERMCAP format 		*/
	short int  coo[2];  /* IN: Coordinates to edit			*/
{
 	MID_STATIC short int arg[2] = {0,0};	/* Local copy of coordinates */
	MID_STATIC char digitS[12] = " " ;	/* Edition buffer	*/
	MID_STATIC unsigned char *digit = (unsigned char *)digitS;
	register unsigned char *p, *pf;
	unsigned char *p_end;
	int  j, narg, x, led;

  ENTER("+tu_format");

	/* Local copy of arguments	*/
  arg[0] = coo[0], arg[1] = coo[1]; 
  narg=0;

	/* Scan the format string, performing the substitutions when
		the FORMAT char is found	*/
  p  = out;
  pf = fm + 4;
  p_end = pf + *fm;
 
  while (pf < p_end)
  {	if (*pf != FORMAT) {	*(p++) = *(pf++);
				continue;
			   }
	/* --- Here, only if FORMAT char was found	--- */
	led = 9;		/* Length of argument edition	*/
	switch(*(++pf))
	{ case 'i':		/* Increment all arguments	*/
		arg[0]++, arg[1]++; 
		pf++; break;
	  case 'p':		/* Argument number as %p[1-9]	*/
		arg[narg] = coo[*(++pf) - '1'];
		pf++; break;
	  case 'r':		/* Swap arguments		*/
		x = arg[0]; arg[0] = arg[1]; arg[1] = x; 
		pf++; break;
	  case 'n':		/* Special arguments change	*/
		arg[0] ^= 0140; arg[1] ^= 0140;
		pf++; break;
	  case '>':		/* >xy : if arg>x, add y	*/
		if(arg[narg] > (short int) *(pf+1)) 
			arg[narg] += *(pf+2);
		pf += 3; break;
			
		/* The following effectively edits arguments	*/

	  case '.':		/* Straight transmit		*/
		*(p++) = arg[narg]; 
		narg ^= 1; pf++; break;
 	  case '+':		/* Transmit argument + x	*/
		*(p++) = arg[narg] + *(++pf);
		narg ^= 1; pf++; break;
	  case '0': case '1': 	/* Edit with led chars		*/
		case '2': case '3': case '4':
		led = *pf - '0';
	  case 'd':		/* Identical with '0'		*/
		if (led == 9) led = 0;
		x = arg[narg]; narg ^= 1; j=sizeof(digit);
		while((led>0) || x)	/* Edit the argument	*/
		{	digit[--j] = '0' + x%10;
			x /= 10; led--;
		}
		while (j<sizeof(digit)) *(p++) = digit[j++];
		pf++; break;
	  default: ERR_ED_STR2("Bad TERMCAP format char =>",(char *)pf,1);
		EXIT(0);
	}
  }
  
#if DEBUG
  TRACE_ED_STR2("Output after formatting:",out,p-out);
#endif

  EXIT(p-out);		/* Length of edited string	*/
}

/*==========================================================================
 *			tu_scap
 *==========================================================================*/
char *tu_scap (cap2)
/*++++++++++++++
.PURPOSE Retrieve a named capability.
.RETURNS Address of the capability field (starting with a :); NULL if not found.
.REMARKS Dichotomic search is performed via the index.
----------------*/
	char cap2[2];		/* IN: The cap_code to look for	*/
{
 	register INDEX *low, *high, *middle;
	INDEX *match;
	char  *p;

  ENTER("*tu_scap");

  TRACE_ED_STR2("... Searching capability =>",cap2,2);

  low  = (INDEX * ) (CAPLIST + terms->index);
  high = low + (NCAPS-1);
  match= NULL_PTR(INDEX);			/* Matching address	*/
  
  while( high >= low)				/* Check first byte	*/
  {	middle = low + ((high-low)/2);
	if ( cap2[0] < middle->cap[0] )
	{	high = middle-1; continue; }
	if ( cap2[0] > middle->cap[0] )
	{	low  = middle+1; continue; }
						/* Check Second byte	*/
	if ( cap2[1] < middle->cap[1] )
	{	high = middle-1; continue; }
	if ( cap2[1] > middle->cap[1] )
	{	low  = middle+1; continue; }
	match = middle; 
	break;
  }

	/* Entries followed by `@' mean "Not such a capability"	*/
  if (match) 
  {	p = match->icap + CAPLIST;
	if (*(p+3) == '@') 	p = NULL_PTR(char);
  }
  else	p = NULL_PTR(char);
  EXITp(p);	
}

/*==========================================================================
 *			tv_ac
 *==========================================================================*/
int tv_ac(source, len, dest)
/*++++++++++++
.PURPOSE Converts Achars to ASCII chars.
.RETURNS Number of Graphic Chars in the source string.
.REMARKS The converted string is NOT terminated with an EOS.
	Graphic Characters are translated to '+', '-', '|', '~'
-------------*/
	ACHAR *source;	/* IN: Source string of Achar's			*/
	int len;	/* IN: Length of strings		*/
	char  *dest;	/* OUT: Converted string		*/
{
	register int l;
	register ACHAR *pa;
	register char  *pc;

  ENTER_("+tv_at");

  status = 0;		/* Number of Graphic Characters	*/

  for (pa = source, l = len, pc = dest; --l >=0; pa++, pc++)
  {	*pc = *pa & 0177;
	if (isGraphic(*pa))
	{	status++;
		switch(*pc)
		{ case RuleChar(_HORIZONTAL_):	*pc = '-';	break;
		  case RuleChar(_VERTICAL_):	*pc = '|';	break;
		  case RubbishChar():		*pc = '~';	break;
		  default:			*pc = '+';	break;
		}
	}
  }
	
  TRACE_ED_STR2("Converted =>", dest, len);
  EXIT(status);
}

/*==========================================================================
 *			tv_aloc
 *==========================================================================*/
int tv_aloc(source, len, achar)
/*++++++++++++
.PURPOSE Locate in source the position of first `ACHAR' having the same
	attribute as `achar'
.RETURNS Index in source of found character, len if none found.
.REMARKS 
-------------*/
	ACHAR *source;	/* IN: Source string of Achar's			*/
	int len;	/* IN: Length of strings			*/
	ACHAR achar;	/* IN: achar which attribute is to find		*/
{
	register int l;
	register ACHAR *pa, ac;

  ENTER_("+tv_aloc");

  for (pa = source, l = len, ac = achar & 0xff00; 
  	(--l >=0) && ((*pa & 0xff00) != ac); pa++) ;

  EXIT(pa-source);
}

/*==========================================================================
 *			tv_askip
 *==========================================================================*/
int tv_askip(source, len, achar)
/*++++++++++++
.PURPOSE Skip in source all `ACHAR's having the same
	attribute as `achar'
.RETURNS Index in source of differing character, len if none found.
.REMARKS 
-------------*/
	ACHAR *source;	/* IN: Source string of Achar's			*/
	int len;	/* IN: Length of strings			*/
	ACHAR achar;	/* IN: achar which attribute is to find		*/
{
	register int l;
	register ACHAR *pa, ac;

  ENTER_("+tv_askip");

  for (pa = source, l = len, ac = achar & 0xff00; 
  	(--l >=0) && ((*pa & 0xff00) == ac); pa++) ;

  EXIT(pa-source);
}

/*==========================================================================
 *			tv_rb
 *==========================================================================*/
int	tv_rb(coo, dimb, limits)
/*+++++++++++++
.PURPOSE Verify and updates the coordinates / dimensions of a box
	defined on the screen.
.RETURNS OK / NOK (dimension too large)
.REMARKS Not traced.
---------------*/
	short int coo[2]; /* MOD: Proposed position of upper left corner \
				(<0 for position from right)	*/
	short int dimb[2]; /* MOD: Proposed dimensions (0 for complete, \
				<0 for Centered)	*/
	short int limits[2];	/* IN: Total size of screen		*/
{	
	register int i;
	
  status = OK;

  for (i = 2; --i >= 0; )
  {	if (dimb[i] < 0)	/* Centered */
  	{	dimb[i] = - dimb[i];
  		coo[i] = (limits[i] - dimb[i] + 1)/2;
  		if (coo[i]< 0)	coo[i] = 0, status = NOK;
  	}

  	if (coo[i] < 0)		/* Position from bottom	*/
  	{	coo[i] += limits[i];
  		if (coo[i] < 0)	coo[i] = 0, status = NOK;
  	}
				/* Compute size if not defined */
  	if (dimb[i] == 0)	dimb[i] = limits[i] - coo[i];
  	if ((dimb[i]+coo[i]) > limits[i])	
  		dimb[i] = limits[i] - coo[i], status = NOK;
	if (dimb[i] < 0)	status = NOK;
  }

  if ( status == NOK)		ERROR("Can't fit Box!");

  return(status);
}
