/* vi:ts=4:sw=4
 *
 * VIM - Vi IMitation Japanese extension
 *
 * Code Contributions By:	Atsushi Nakamura		ann@mrit.mei.co.jp
 */

#include "vim.h"
#include "globals.h"
#include "proto.h"
#include "param.h"
#include "ops.h"
#ifdef JP
#include "jp.h"
#include "jptab.h"
# ifdef sony
# define sjis2euc sjis_to_euc
# endif
#endif

static int jisx0201rto0208();

#ifdef GENERAL
# undef free
#endif

#if defined(UNIX) && !defined(GENERAL)
#include "signal.h"

/*
 *	handle core dump by some bugs.
 */
	static void
core_handler(dummy)
	int dummy;
{
	static void abend_handler();
	abend_handler(TRUE);
}

	static void 
hup_handler(dummy)
	int dummy;
{
	static void abend_handler();
	abend_handler(FALSE);
}

	static void
abend_handler(core)
	int core;
{
	char *text;

	settmode(0);
	stoptermcap();
	flushbuf();
	stopscript();					/* remove autoscript file */
#ifdef JPFEP
	fep_freqsave();
#endif

	signal(SIGQUIT, SIG_DFL);
	signal(SIGHUP,  SIG_DFL);
	signal(SIGTERM, SIG_DFL);
	signal(SIGSEGV, SIG_DFL);
#ifdef SIGILL
	signal(SIGILL,  SIG_DFL);
#endif
#ifdef SIGBUS
	signal(SIGBUS,  SIG_DFL);
#endif
#ifdef SIGLOST
	signal(SIGLOST, SIG_DFL);
#endif
#ifdef SIGPWR
	signal(SIGPWR,  SIG_DFL);
#endif

#ifdef JP
	printf("\n%s is killed by some bugs....\n", JpVersion);
#else
	printf("\n%s is killed by some bugs....\n", Version);
#endif
	text = modname(Filename, ".sav");
	if (writeit(text, NULL, (linenr_t)1, line_count, FALSE, FALSE, TRUE))
		printf("\nThe current text is saved into %s.\n", text);
	else
		printf("\nI couldn't save the current text.\n");

	if (core)
		kill(getpid(), SIGQUIT);
	else
		kill(getpid(), SIGKILL);
}

	static void
core_init()
{
	signal(SIGQUIT, core_handler);
	signal(SIGHUP,  hup_handler);
	signal(SIGTERM, hup_handler);
	signal(SIGSEGV, core_handler);
#ifdef SIGILL
	signal(SIGILL,  core_handler);
#endif
#ifdef SIGBUS
	signal(SIGBUS,  core_handler);
#endif
#ifdef SIGLOST
	signal(SIGLOST, hup_handler);
#endif
#ifdef SIGPWR
	signal(SIGPWR,  hup_handler);
#endif
}

#endif /* UNIX && !GENERAL */

#ifdef JP

#ifndef GENERAL
	void
jp_init()
{
	JP_FCODE = JP_NEW;
#if defined(UNIX) && !defined(GENERAL)
	core_init();
#endif
}

#endif /* !GENERAL */

/*
 * convert EUC letter into suitable letter.
 */
	void
kanjito(k1, k2, code)
	u_char	*k1, *k2;
	char	code;
{
	u_char c1, c2;

	switch(code)
	{
	  case JP_NJIS:
	  case JP_JIS:
		*k1 &= 0x7f;
		*k2 &= 0x7f;
		return;

	  case JP_SJIS:
	  	c1 = *k1 & 0x7f;
	  	c2 = *k2 & 0x7f;
	    *k1 = (((int)c1 - 1) >> 1) + ((c1 <= 0x5e) ? 0x71 : 0xb1);
		*k2 = c2 + ((c1 & 1) ? ((c2 < 0x60) ? 0x1f : 0x20) : 0x7e);
	    return;

	  default:
		return;
	}
}

/*
 * return kanji shift-in string
 */
	char *
kanjiin(code)
	char	code;
{
	switch(code)
	{
	  case JP_NJIS:
		return "\033$B";

	  case JP_JIS:
		return "\033$@";

	  default:
		return "";
	}
}

/*
 * return kanji shift-out string
 */
	char *
kanjiout(code)
	char	code;
{
	switch(code)
	{ 
	  case JP_NJIS:
		return "\033(B";

	  case JP_JIS:
		return "\033(J";

	  default:
		return "";
	}
}

/*
 * convert buffer to EUC code
 */
static int jis, euc, njis, sjis;
static int knj_asc;
static int jis0201r;

#define IsJIS0201r(c)	((u_char)(c) >= 0xa0 && (u_char)(c) <= 0xdf)

	void
reset_jcount()
{
	jis = euc = njis = sjis =
	knj_asc =
	jis0201r = 0;
}

#if defined(JPFEP) || defined(FEPCTRL)
	char*
guess_jiauto(ji, th)
	char* ji;
	int th;
{
	if (!th)
		return ji;
	if (knj_asc > th)
		return isupper(*ji) ? "J": "j";
	if (knj_asc < - th)
		return isupper(*ji) ? "A": "a";

	return ji;
}
#endif

	char
judge_jcode(code)
	char code;
{
	if (code == JP_ANY || code == JP_SANY)
	{
		char	judge;

		if (!jis && !euc && !njis && !sjis)
			judge = JP_NONE;
		else if (njis)
			judge = JP_NJIS;
		else if (jis)
			judge = JP_JIS;
		else if (euc >= sjis)
			judge = JP_EUC;
		else
			judge = JP_SJIS;
		return judge;
	}
	else
		return code;
}

	int
num_jis0201r()
{
	return jis0201r;
}

static void sjis2euc(ptr)
	char *ptr;
{
	int i, j;

	i = (u_char) *ptr;
	j = (u_char) *(ptr + 1);

	i = (i * 2) - ((i <= 0x9f)? 0xe1 : 0x161);
	if (j < 0x9f)
		j -= ((j > 0x7f) ? 0x20 : 0x1f);
	else
	{
		i ++;
		j -= 0x7e;
	}
	*ptr++ = i | 0x80;
	*ptr   = j | 0x80;
}

#define CHARSET_ASCII		FALSE /* or JISX0201 Left hand set */
#define CHARSET_JISX0208	1
#define CHARSET_JISX0201R	2

	int				/* return the length of dst */
kanjiconvsfrom(ptr, ptrlen, dst, dstlen, tail, code, charsetp)
	char	*ptr;
	int		ptrlen;
	char	*dst;
	int		dstlen;
	char	*tail;
	char	code;
	int		*charsetp;
{
	char	*top, *dtop;
	u_char	c;
#ifndef GENERAL
	int		firstchar = FALSE;
#endif
	int		charset;

	charset = charsetp ? *charsetp : CHARSET_ASCII;
	top = ptr;
	dtop = dst;
	if (tail)
		tail[0] = NUL;

	switch(code)
	{
	  case JP_NONE:

		while(ptrlen)
		{
			c = *ptr;
			if (!IsKanji(c) || (c & 0x60))
			{					/* if not Function key */
				c &= 0x7f;
				if (*ptr > ' ')
					knj_asc --;
			}

			ptr ++;
			*dst ++ = c;
			ptrlen --;
			if (dst - dtop >= dstlen)
				return -1;
		}
		return dst - dtop;

	  case JP_EUC:

		while(ptrlen)
		{
			if (dst - dtop >= dstlen)
				return -1;
			ptrlen --;
			if (IsKanji(c = *dst ++ = *ptr ++))
			{
				if (! (c & 0x60))	/* if Function key */
					continue;

				if (c == 0xff)		/* if NT Function key */
					continue;

				if (IsKanji(*ptr))
				{					/* JIS0208 char. */
					knj_asc ++;
					*dst ++ = *ptr ++;
					ptrlen --;
					continue;
				}

				if (tail && ptrlen == 0)
				{					/* not completed  */
					tail[0] = c;
					tail[1] = NUL;
					dst --;
					continue;
				}

				else
				{					/* Illegal char  */
					*(dst - 1) &= 0x7f;
					continue;
				}
			}
			else if (c > ' ')		/* ASCII char */
				knj_asc --;
		}
		return dst - dtop;
	
	  case JP_SJIS:

		while(ptrlen)
		{
			if (dst - dtop >= dstlen)
				return -1;

			ptrlen --;
			c = *dst ++ = *ptr ++;
			if (IsKanji(c))
			{
				if (IsJIS0201r(c))
				{					/* JIS X 0201R 8bit encoding */
					char c1;

					if (jisx0201rto0208(c, ptrlen ? *ptr : NUL, dst - 1, &c1))
					{	/* 2 characters -> double byte character. */
						* dst++ = c1;
						ptr ++;
						ptrlen --;
					}
					else if (c1)
						/* 1 character -> double byte character. */
						* dst++ = c1;
				/*	else
						   1 character -> single byte character. */

					jis0201r ++;
					continue;
				}

				if (ptrlen == 0)
				{					/* not completed */
					if (tail)
					{
						tail[0] = c;
						tail[1] = NUL;
						dst --;
					}
					else
						*(dst - 1) &= 0x7f;
					continue;
				}

				if (c == 0xff)		/* if NT Function key */
					continue;

				else
				{					/* SJIS character */ 
					* dst++ = * ptr++;
					ptrlen --;
					knj_asc ++;

					sjis2euc(dst - 2);
					continue;
				}
			}
			else if (c > ' ')
				knj_asc --;
		}
		return dst - dtop;

	  case JP_NJIS:
	  case JP_JIS:
	  case JP_ANY:
	  case JP_SANY:

		while(ptrlen)
		{
			if (dst - dtop >= dstlen)
				return -1;

			ptrlen --;
			c = *dst ++ = *ptr ++;
			if (IsKanji(c))
			{
#ifndef GENERAL
									/* check Function key */
				if (!p_jse && code != JP_SJIS && code != JP_SANY)
				{
					if (!(c & 0x60))
						continue;
				}
				else
				{
					if (firstchar ++ && !(c & 0x60) && !*ptr)
						continue;
				}

				if (c == 0xff)		/* if NT Function key */
					continue;
#endif

				if (ptrlen == 0)
				{					/* not completed */
					if (tail)
					{
						tail[0] = c;
						tail[1] = NUL;
						dst --;
					}
					else
						*(dst - 1) &= 0x7f;
					continue;
				}

				if ( (code == JP_SANY
				   || code == JP_NJIS
				   || code == JP_JIS) && IsJIS0201r(c))
				{					/* JIS X 0201R 8bit encoding */
					char c1;

					if (jisx0201rto0208(c, ptrlen ? *ptr : NUL, dst - 1, &c1))
					{	/* 2 characters -> double byte character. */
						* dst++ = c1;
						ptr ++;
						ptrlen --;
					}
					else if (c1)
						/* 1 character -> double byte character. */
						* dst++ = c1;
				/*	else
						   1 character -> single byte character. */

					jis0201r ++;
					continue;
				}

				* dst++ = * ptr++;

				switch(code)
				{
					case JP_SANY:
						if (c < 0xa0 || c >= 0xe0)
						{
							sjis ++;
							sjis2euc(dst - 2);
						}
						else
							euc ++;
						goto s_or_e;

					case JP_ANY:
						if (c < 0xa0)
						{
							sjis ++;
							sjis2euc(dst - 2);
						}
						else
							euc ++;
s_or_e:
						ptrlen --;
						knj_asc ++;
						break;
					default:
						dst --;
						ptr --;
						*(dst - 1) &= 0x7f;
				}
				continue;
			}

			if (c == ESC)
			{
				dst --;

				if (ptrlen == 0)
				{
					if (tail)
					{
						tail[0] = c;
						tail[1] = NUL;
					}
					else
						dst++;
					continue;
				}

				if (*ptr == '(')
				{
					ptrlen --;
					ptr ++;

					if (ptrlen == 0)
					{
						if (tail)
						{
							tail[0] = c;
							tail[1] = '(';
							tail[2] = NUL;
						}
						else
						{
							dst ++;
							* dst++ = '(';
						}
						continue;
					}

				 	if (*ptr == 'I')
					{						/* JIS X 0201R ISO2022 encoding */
						charset = CHARSET_JISX0201R;
						ptr ++;
						ptrlen --;
						continue;
					}
				 	else if (*ptr == 'J' || *ptr == 'H' || *ptr == 'B' ||
							    code == JP_ANY) /* ASCII/JIS In */
					{
						charset = CHARSET_ASCII;
						ptr ++;
						ptrlen --;
						continue;
					}
					else
					{
						dst ++;
						* dst++ = '(';
						continue;
					}
				}

				if (*ptr == '$')
				{
					ptrlen --;
					ptr ++;

					if (ptrlen == 0)
					{
						if (tail)
						{
							tail[0] = c;
							tail[1] = '$';
							tail[2] = NUL;
						}
						else
						{
							dst ++;
							* dst++ = '$';
						}
						continue;
					}

				 	if (*ptr == '@' || *ptr == 'B' ||
						code == JP_ANY)		/* Kanji In */
					{
						if      (*ptr == '@') jis++;
						else if (*ptr == 'B') njis++;

						charset = CHARSET_JISX0208;
						ptrlen --;
						ptr ++;
						continue;
					}
					else
					{
						dst ++;
						* dst ++ = '$';
						continue;
					}
				}

				else
					dst++;
			}
				
			switch(charset)
			{
				case CHARSET_ASCII:
					if (c > ' ')
						knj_asc --;
					break;

				case CHARSET_JISX0201R:
					if (IsJIS0201r(c | 0x80))
					{	/* This code is not examined. 	ann */
						char c0, c1;

						c0 = ptrlen ? *ptr : NUL;
						if (! IsJIS0201r(c0 | 0x80))
							c0 |= 0x80;
						if (jisx0201rto0208(c | 0x80, c0, dst - 1, &c1))
						{	/* 2 characters -> double byte character. */
							* dst++ = c1;
							ptr ++;
							ptrlen --;
						}
						else if (c1)
							/* 1 character -> double byte character. */
							* dst++ = c1;
					/*	else
							   1 character -> single byte character. */
						jis0201r ++;
					}
					else if (c == NUL || c =='\n' || c == '\r')
						charset = CHARSET_ASCII;
					break;

				default: /* CHARSET_JISX0208 */
					if (ptrlen == 0)
					{
						if (tail)
						{
							tail[0] = c;
							tail[1] = NUL;
							dst --;
						}
					}
					else if (c > ' ' && *ptr > ' ')
					{
						ptrlen --;
						*(dst - 1) |= 0x80;
						* dst++ = * ptr++ | 0x80;
						knj_asc ++;
					}
					else if (c == NUL || c == '\n' || c == '\r')
						charset = CHARSET_ASCII;
			}
		}
		if (charsetp)
			*charsetp = charset;
		return dst - dtop;
	}
	return dst - dtop;
}

/*
 * convert buffer from EUC code
 */

#ifdef GENERAL
# define alloc_line(x)	malloc(x)
#endif

#ifndef GENERAL
	void
kanjiconvto(lnum, lend, code)
	linenr_t	lnum, lend;
	char		code;
{
	char	*ptr, *new;

	for(; lnum <= lend; ++lnum)
	{
		ptr = nr2ptr(lnum);
		new = kanjiconvsto(ptr, code);
		if (new != ptr) free_line(replaceline(lnum, new));
	}
}

#endif /* !GENERAL */

	char *
kanjiconvsto(ptr, code)
	char	*ptr;
	char	code;
{
	char	*top, *ptr2;
	char	*kin, *kout, *cp;
	int		kanji, nshift, nchar;

	top = ptr;

	switch(code)
	{
	  case JP_EUC:
	  	return top;
	
	  case JP_NONE:
		top = ptr2 = alloc_line(strlen(ptr));
		while(*ptr)
			 *ptr2 ++ = *ptr ++ & ~0x80;
		*ptr2 = NUL;
		return top;

	  case JP_SJIS:
		top = ptr2 = alloc_line(strlen(ptr));
		while(*ptr)
			if (IsKanji(*ptr2++ = *ptr++))
			{
				*ptr2 ++ = *ptr ++;
				kanjito(ptr2 - 2, ptr2 - 1, code);
			}
		*ptr2 = NUL;
		return top;

	  case JP_NJIS:
	  case JP_JIS:
	  case JP_ANY:

		kin  = kanjiin(code);
		kout = kanjiout(code);

		kanji = 0;
		for(nshift = 0; *ptr; ptr++)
		{
			if (kanji !=  (*ptr & 0x80))
			{
				nshift++;
				kanji ^= 0x80;
			}
		}
		if (kanji) nshift++;
		nchar = ptr - top;

		if (!nshift) return top;

		ptr = top;
		top = ptr2 = alloc_line(nchar + nshift * 3);

		kanji = 0;
		while(*ptr) 
		{
			if (kanji !=  (*ptr & 0x80))
			{
				if (kanji)
					for(cp = kout; *cp;)
						*ptr2++ = *cp++;
				else
					for(cp = kin; *cp;)
						*ptr2++ = *cp++;
				kanji ^= 0x80;
			}
			*ptr2++ = (*ptr++ & 0x7f);
		}
		if (kanji)
			for(cp = kout; *cp;)
				*ptr2++ = *cp++;
		*ptr2 = 0;
		return top;
	}
	return top;
}

#ifndef GENERAL
	void
kanji_align()
{
	int col;
	char *line;

	line = nr2ptr(Curpos.lnum);

	for(col = 0; col < Curpos.col; line++, col++)
		if (IsKanji(*line))
		{
			line ++;
			col  ++;
		}
	Curpos.col = col;
}
#endif /* !GENERAL */


/*
 *	Japanese Character class;
 *					Make sure this routine is consistent with search.c:cls().
 *
 * 	for Japanese
 * 3 - alphabet, digits
 * 4 - japanese hiragana
 * 5 - japanese katakana
 * 6 - symbols
 * 7 - other multi-char letter
 */

	int
jpcls(c, k)
	char c, k;
{
	if (c == ' ' || c == '\t' || c == NUL)
		return 0;

	if (IsKanji(c))
	{
		int		ret;
		return (ret = jptab[c & 0x7f].cls1) == JPC_KIGOU
				?	jptab[k & 0x7f].cls2
				:	ret;
	}

#ifdef GENERAL
# ifdef __STDC__
	if (isalnum(c) || c == '_')
# else
	if (isalpha(c) || isdigit(c) || c == '_')
# endif
#else
	if (isidchar(c))
#endif
		return 1;

	return -1;
}

/* 
 *	isjppunc(c, k) returns whether a kanji character ck necessary KINSOKU
 *	processing or not.
 */
	int
isjppunc(c, k, type)
	char c, k;
	int type;
{
	k &= 0x7f;
	switch(jptab[(int)c & 0x7f].cls1)
	{
	case JPC_KIGOU:
		return type ? jptab[(int)k].punccsym : jptab[(int)k].puncosym;

	case JPC_HIRA:
	case JPC_KATA:
		return type ? jptab[(int)k].puncckana : FALSE;

	default:
		return FALSE;
	}
}
/* 
 *	isaspunc(c, type) returns whether an ascii character ck necessary KINSOKU
 *	processing or not.
 */
	int
isaspunc(c, type)
	char c;
	int type;
{
	return(type ? jptab[(int)c].punccasc: jptab[(int)c].puncoasc);
}

/* 
 *	isjsend(*cp) returns whether a JIS character *cp separates
 *	sentences or not.
 */
	int
isjsend(cp)
	u_char *cp;
{
	return *cp == (0x80 | '!') && jptab[*(cp + 1) & 0x7f].stcend;
}

/* 
 *	jptocase(&c, &k, tocase)
 *		modify c & k to case tocase
 *			tocase == UPPER : to upper
 *			tocase == LOWER : to lower
 *			tocase == others : swap case
 */
	void
jptocase(cp, kp, tocase)
	u_char *cp, *kp;
	int tocase;
{
	u_char k;

	k = *kp & 0x7f;
	switch(jptab[*cp & 0x7f].cls1)
	{
	case JPC_ALNUM:
		if (tocase != LOWER && islower(k))
			*kp = TO_UPPER(k) | 0x80;
		if (tocase != UPPER && isupper(k))
			*kp = TO_LOWER(k) | 0x80;
		return;

	case JPC_KIGOU:
		if (  (tocase != LOWER && jptab[k].scase == JLOS)
		   || (tocase != UPPER && jptab[k].scase == JUPS)
		   )
			*kp = jptab[k].swap;
		return;

	case JPC_KATA:
		if (tocase != -1)
			*cp = JP1_HIRA | 0x80;
		return;

	case JPC_HIRA:
		if (tocase != 1)
			*cp = JP1_KATA | 0x80;
		return;

	default:
		return;
	}
}


/*
 * JIS X 0201 Right hand set(hankaku kana) <-> JIS X 0208(zenkaku)
 *
 */
	static int
jisx0201rto0208(src0, src1, dst0, dst1)
	char src0, src1, *dst0, *dst1;
{
	u_char	c, y;
	u_char	*x0201p, z;
	int		conv;

	c = (u_char) src0;
	x0201p = (u_char*)jisx0201r + 2 * (c - 0xa0);

	if (! IsKanji(y = *x0201p))
	{
		*dst0 = y;
		*dst1 = NUL;
		return 0;
	}

	z = *(x0201p + 1);
	conv = FALSE;
	if		((u_char)src1 == 0xdf &&		/* maru */
				(c >= 0xca && c <= 0xce))	/* ha - ho */
	{
		z += 2;
		conv = TRUE;
	}
	else if ((u_char)src1 == 0xde)			/* dakuten */
	{
		conv = TRUE;
		if (   (c >= 0xb6 && c <= 0xc4)		/* ka - to */
			|| (c >= 0xca && c <= 0xce) )	/* ha - ho */
			z ++;
		else if (c == 0xb3)					/* u -> vu*/
			z = 0xf4;
		else
			conv = FALSE;
	}

	*dst0 = y;
	*dst1 = z;

	return conv ? 1 : 0;
}

#endif /* JP */


#ifdef GENERAL
/*
 *	The following codes are copied from alloc.c for jcat.c and jfold.c
 */

# ifdef BSD_UNIX
	char *
bsdmemset(ptr, c, size)
	char	*ptr;
	int		c;
	long	size;
{
	register char *p = ptr;

	while (size-- > 0)
		*p++ = c;
	return ptr;
}
# endif

# ifdef MEMMOVE
/*
 * Version of memmove that handles overlapping source and destination.
 * For systems that don't have a function that is guaranteed to do that (SYSV).
 */
	void *
memmove(desti, source, len)
	void	*source, *desti;
#ifdef __sgi
	size_t	len;
#else
	int		len;
#endif
{
	char *src = (char *)source;
	char *dst = (char *)desti;

	if (dst > src && dst < src + len)	/* overlap, copy backwards */
	{
		src +=len;
		dst +=len;
		while (len--)
			*--dst = *--src;
	}
	else								/* copy forwards */
		while (len--)
			*dst++ = *src++;
	return desti;
}
# endif

#endif


syntax highlighted by Code2HTML, v. 0.9.1