/*======================================================================*\
|*		Editor mined						*|
|*		Character composition					*|
\*======================================================================*/

#include "mined.h"


/*======================================================================*\
|*			Accented composition				*|
\*======================================================================*/

unsigned long
diaeresis (ch)
  unsigned long ch;
{
  unsigned long trychar = compose ('"', ch);
  if (no_unichar (trychar)) {
	return compose (ch, ':');
  } else {
	return trychar;
  }
}

unsigned long
tilde (ch)
  unsigned long ch;
{
  unsigned long trychar = compose ('~', ch);
  if (no_unichar (trychar)) {
	return compose (ch, '?');
  } else {
	return trychar;
  }
}

unsigned long
angstrom (ch)
  unsigned long ch;
{
  unsigned long trychar = compose (UNI_ring, ch);
  if (no_unichar (trychar)) {
	trychar = compose (ch, ',');
  }
  if (no_unichar (trychar)) {
	trychar = compose (ch, '0');
  }
  return trychar;
}

unsigned long
acute (ch)
  unsigned long ch;
{
  unsigned long trychar = compose (UNI_acute, ch);
  if (no_unichar (trychar)) {
	trychar = compose ('\'', ch);
  }
  if (no_unichar (trychar)) {
	trychar = compose (ch, '\'');
  }
  return trychar;
}

unsigned long
grave (ch)
  unsigned long ch;
{
  unsigned long trychar = compose ('`', ch);
  if (no_unichar (trychar)) {
	return compose (ch, '!');
  } else {
	return trychar;
  }
}

unsigned long
circumflex (ch)
  unsigned long ch;
{
  unsigned long trychar = compose ('^', ch);
  if (no_unichar (trychar)) {
	return compose (ch, '>');
  } else {
	return trychar;
  }
}


/*======================================================================*\
|*			Mnemonic composition				*|
\*======================================================================*/

static
struct {
	char * mnemo;
	int uni;
} unimnemo3 [] =
{
#include "mnemos.h"
	{NIL_PTR}
};

/**
   Compose character from mnemomic.
   Param variable_length tweaks preferences for two-letter mnemonic input.
   Return CHAR_UNKNOWN if mnemonic is unknown.
   Return CHAR_INVALID if character found is invalid (CJK conversion).
 */
static
unsigned long
compose_mnemo (mnemo, variable_length)
  char * mnemo;
  FLAG variable_length;
{
  int i = 0;
  int res1 = -1;	/* prio 1 result index */
  int res2 = -1;	/* prio 2 result index */
  char * mnemo2 = & mnemo [1];
  unsigned long ret;

  while (unimnemo3 [i].mnemo != NIL_PTR) {
	if (streq (unimnemo3 [i].mnemo, mnemo)) {
		if (variable_length) {
			res2 = i;
		} else {
			res1 = i;
			break;
		}
	}
	if (variable_length && unimnemo3 [i].mnemo [0] == ' '
	                    && streq (unimnemo3 [i].mnemo + 1, mnemo)) {
		res1 = i;
		break;
	}
	if (mnemo [0] == '&' && streq (unimnemo3 [i].mnemo, mnemo2)) {
		res2 = i;
	}
	i ++;
  }

  if (res1 >= 0) {
	ret = unimnemo3 [res1].uni;
  } else if (res2 >= 0) {
	ret = unimnemo3 [res2].uni;
  } else {
	return CHAR_UNKNOWN;
  }

  if (cjk_text || mapped_text) {
	return encodedchar (ret);
  } else {
	return ret;
  }
}

/**
   Normalize accent shortcuts to usually available keys as used in tables.
 */
static
void
subst_acc (c1p, c2p, acc, sub)
  unsigned long * c1p;
  unsigned long * c2p;
  character acc;
  character sub;
{
  if (* c1p == acc) {
	* c1p = sub;
  }
  if (* c2p == acc) {
	* c2p = sub;
  }
}

/**
   Compose character from two-letter mnemomic.
   Return CHAR_UNKNOWN if mnemonic is unknown.
   Return CHAR_INVALID if character found is invalid (CJK conversion).
 */
unsigned long
compose (c1, c2)
  unsigned long c1;
  unsigned long c2;
{
  character cs [13];
  character * cp = cs;
  unsigned long ret;
  unsigned long ret2;
  unsigned long c1subst = c1;
  unsigned long c2subst = c2;

  if (c2 == FUNcmd) {
	return CHAR_UNKNOWN;
  }

  cp += utfencode (c1, cp);
  (void) utfencode (c2, cp);

  ret = compose_mnemo (cs, False);

  if (no_char (ret)) {
	/* accept double quote for diaeresis */
	subst_acc (& c1subst, & c2subst, (character) '"', ':');
	/* accept real circumflex */
	subst_acc (& c1subst, & c2subst, (character) '^', '>');
	/* accept real grave */
	subst_acc (& c1subst, & c2subst, (character) '`', '!');
	/* accept real tilde */
	subst_acc (& c1subst, & c2subst, (character) '~', '?');
	/* accept real diaeresis */
	subst_acc (& c1subst, & c2subst, (character) '¨', ':');
	/* accept real macron */
	subst_acc (& c1subst, & c2subst, (character) '¯', '-');
	/* accept real acute */
	subst_acc (& c1subst, & c2subst, (character) '´', '\'');
	/* accept real cedilla */
	subst_acc (& c1subst, & c2subst, (character) '¸', ',');
	/* accept degree for ring above */
	subst_acc (& c1subst, & c2subst, (character) '°', '0');

	cp = cs;
	cp += utfencode (c1subst, cp);
	(void) utfencode (c2subst, cp);
	ret2 = compose_mnemo (cs, False);
	if (! no_char (ret2)) {
		ret = ret2;
	}
  }

  /* no mnemo found, try reversing the two composites */
  if (no_char (ret)) {
	cp = cs;
	cp += utfencode (c2, cp);
	(void) utfencode (c1, cp);
	ret2 = compose_mnemo (cs, False);
	if (! no_char (ret2)) {
		ret = ret2;
	}

	if (no_char (ret)) {
		cp = cs;
		cp += utfencode (c2subst, cp);
		(void) utfencode (c1subst, cp);
		ret2 = compose_mnemo (cs, False);
		if (! no_char (ret2)) {
			ret = ret2;
		}
	}
  }

  return ret;
}

/**
   Compose character from mnemomic.
   Return CHAR_UNKNOWN if mnemonic is unknown.
   Return CHAR_INVALID if character found is invalid (CJK conversion).
 */
unsigned long
compose_mnemonic (mnemo)
  char * mnemo;
{
  return compose_mnemo (mnemo, True);
}


/*======================================================================*\
|*				End					*|
\*======================================================================*/
