#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

#define NRKANA 250*2   /*  size of the romaji to kana tables*/
#define TRUE 1
#define FALSE 0

unsigned char KANATAB[NRKANA*2][7];
unsigned char c1,c2,instr[256],outstr[256],kstr[256],outstr2[256];
int omode='e',ForceEUC=FALSE,Konly,Paren=FALSE,OkActive=FALSE;
unsigned char ok_mark = '.';
unsigned char ControlFile[100]={"kanarom.cnv"};

void GetEUC(unsigned char *eucline,unsigned char *Instr);
void FixSJIS(unsigned char *jline);
void sjis2jis   (int *p1,int *p2);   /* Ken Lunde's routine  */

void LoadKana()
{
	int i,ih,ik,mode;
	FILE *fp,*fopen();
	unsigned char kiadir[50],LKin[80],LKinraw[80],*ptr;

	for (i = 0; i < NRKANA*2; i++) strcpy(KANATAB[i]," ");
	fp=fopen(ControlFile,"r");
	if (fp == NULL)
	{
		printf("Unable to open: %s\n",ControlFile);
		exit(1);
	}
	mode = 0;
	while (1)
	{
		fgets(LKinraw,79,fp);
		if (feof(fp))break;
		LKin[strlen(LKinraw)-1] = '\0';
		GetEUC(LKin,LKinraw);
		if(LKin[0] == '#')continue;
		if((LKin[0] == '$')&&((LKin[1]|0x20) == 'h'))
		{
			mode = 0;
			ih = 0;
			continue;
		}
		if((LKin[0] == '$')&&((LKin[1]|0x20) == 'k'))
		{
			mode = 1;
			ih = 0;
			continue;
		}
		ptr = (unsigned char *)strtok(LKin," \t");
		strcpy(KANATAB[mode*NRKANA+ih*2+1],ptr);
		ptr = (unsigned char *)strtok(NULL," \t\r\n");
		strcpy(KANATAB[mode*NRKANA+ih*2],ptr);
		ih++;
		if(ih == NRKANA) printf("Too many romaji table entries!\n");
	}
	fclose(fp);
}

void addch(unsigned char *targ, unsigned char ch)
{
	unsigned char ctemp[2];

	ctemp[0] = ch;
	ctemp[1] = 0;
	strcat(targ,ctemp);
}

void process_kana()
{
	int hit,i,k;
	unsigned char roma[256];

	if (strlen(kstr) == 0) return;

	roma[0] = 0;
	for (i = 0; i < strlen(kstr); )
	{
		hit = FALSE;
		for (k = 0; k < NRKANA; k++)
		{
			if(strncmp(kstr+i,KANATAB[k*2+1],strlen(KANATAB[k*2+1])) == 0)
			{
				strcat(roma,KANATAB[k*2]);
				i = i+strlen(KANATAB[k*2+1]);
				hit = TRUE;
				break;
			}
		}
		if (!hit)
		{
			strcat(roma,"#");
			i++;
		}
	}
	if (roma[strlen(roma)-1] == '*') /* fix up trailing small tsu   */
	{
		i = strlen(roma)-1;
		roma[i++] = 't';
		roma[i++] = '-';
		roma[i] = 0;
	}
	if (kstr[0] == 0xa5)
	{
		for (i = 0; i < strlen(roma); i++)
		{
			if ((roma[i] >= 'a') && (roma[i] <= 'z')) roma[i] = roma[i] & 0x5f;
		}
	}
	for (i = 0; i < strlen(roma); i++)
	{
		if (roma[i] == '*') roma[i] = roma[i+1];
	}
	strcat(outstr,roma);
	kstr[0] = 0;
}

/*======jis2sjis  (from Ken Lunde) =====================================*/
void jis2sjis(unsigned char *p1,unsigned char *p2) /* courtesy of Ken Lunde */
{
    register unsigned char c1 = *p1;
    register unsigned char c2 = *p2;
    register int rowOffset = c1 < 95 ? 112 : 176;
    register int cellOffset = c1 % 2 ? 31 + (c2 > 95) : 126;

    *p1 = ((c1 + 1) >> 1) + rowOffset;
    *p2 = c2 + cellOffset;
}

/*=====KOut===output kana/kanji according to selected mode===========*/
void KOut(unsigned char *sout,unsigned char *oline)
{
	int i,op,JISin;
	unsigned char c1,c2;

	op = 0;
	JISin = FALSE;
	for (i = 0; i < strlen(sout); i++)
	{
		c1 = sout[i]; c2 = sout[i+1];
		if (c1 < 127)
		{
			if (JISin)
			{
				oline[op++] = 0x1b;
				oline[op++] = '(';
				oline[op++] = 'B';
				JISin = FALSE;
				oline[op] = 0;
			}
			oline[op] = c1; oline[op+1] = 0;
			op++;
			continue;
		}
		switch(omode)
		{
		case 'j' :  /* JIS (default)  */
			if (c1 == 0x8f)
			{
				if (JISin)
				{
					oline[op++] = 0x1b;
					oline[op++] = '(';
					oline[op++] = 'B';
					JISin = FALSE;
					oline[op] = 0;
				}
				oline[op++] = 0x1b;
				oline[op++] = '$';
				oline[op++] = '(';
				oline[op++] = 'D';
				oline[op++] = c2&0x7f;
				oline[op++] = sout[i+2]&0x7f;
				oline[op++] = 0x1b;
				oline[op++] = '(';
				oline[op++] = 'B';
				oline[op] = 0;
				i+=2;
				break;
			}
			if (JISin)
			{
				oline[op++] = c1&0x7f;
				oline[op++] = c2&0x7f;
			}
			else
			{
				oline[op++] = 0x1b;
				oline[op++] = '$';
				oline[op++] = 'B';
				oline[op++] = c1&0x7f;
				oline[op++] = c2&0x7f;
				JISin = TRUE;
			}
			i++;
			break;

		case 'e' : /* EUC (internal format) */
			if (c1 == 0x8f)
			{
				oline[op++] = c1;
				oline[op++] = c2;
				oline[op++] = sout[i+2];
				oline[op] = 0;
				i+=2;
				break;
			}
			oline[op++] = c1;
			oline[op++] = c2;
			oline[op] = 0;
			i++;
			break;

		case 's' : /* Shift-JIS */
			if (c1 == 0x8f)
			{
				c1 = 0xa2; c2 = 0xa1;	/* a star in SJIS as there's no JIS212*/
				i++;
			}
			c1 -= 128; c2 -= 128;
			jis2sjis(&c1,&c2);
			oline[op++] = c1;
			oline[op++] = c2;
			oline[op] = 0;
			i++;
			break;
		}
	}
	if (JISin)
	{
		oline[op++] = 0x1b;
		oline[op++] = '(';
		oline[op++] = 'B';
		oline[op] = 0;
		JISin = FALSE;
	}
}

/*====GetEUC - ensures that any JIS in the string is EUC ============*/
/*      Based on the GetEUC in JREADER, this routine examines
	the string "Instr" and converts any JIS or SJIS to EUC.
	The result is placed in the specified string.        */

void GetEUC(unsigned char *eucline,unsigned char *Instr)
{
	int i,j,SI,J212,J212sw;

	J212 = FALSE;
	eucline[0] = '\0';
	SI = FALSE;
	j = 0;
	for (i = 0; i < strlen(Instr); i++)
	{
		if((Instr[i]==0x1b)&&(Instr[i+1]=='$')&&(Instr[i+2]=='(')&&(Instr[i+3]=='D'))
		{
			SI = TRUE;
			J212 = TRUE;
			J212sw = 0;
			i+=3;
			continue;
		}
		if((Instr[i]==0x1b)&&(Instr[i+1]=='$')&&(Instr[i+2]=='B'))
		{
			SI = TRUE;
			J212 = FALSE;
			i+=2;
			continue;
		}
		if((Instr[i]==0x1b)&&(Instr[i+1]=='$')&&(Instr[i+2]=='@'))
		{
			SI = TRUE;
			J212 = FALSE;
			i+=2;
			continue;
		}
		if((Instr[i]==0x1b)&&(Instr[i+1]=='(')&&(Instr[i+2]=='J'))
		{
			SI = FALSE;
			J212 = FALSE;
			i+=2;
			continue;
		}
		if((Instr[i]==0x1b)&&(Instr[i+1]=='(')&&(Instr[i+2]=='B'))
		{
			SI = FALSE;
			J212 = FALSE;
			i+=2;
			continue;
		}
		if (Instr[i] == '\0')break;
		if (SI)
		{
			if (J212 && (J212sw == 0)) eucline[j++] = 0x8f;
			eucline[j] = Instr[i] | 0x80;
			J212sw = (J212sw+1) % 2;
		}
		else
		{
			eucline[j] = Instr[i];
		}
		j++;
		eucline[j] = '\0';
	}
/*  fix up SHIFT-JIS, if present  */
	if (!ForceEUC) FixSJIS(eucline);
}

/*====FixSJIS=== convert any SJIS to EUC in a string==================*/
void FixSJIS(unsigned char *jline)
{
	int i,p1,p2,ShiftJIS;

	ShiftJIS = FALSE;
	for (i = 0; i < strlen(jline); i++)
	{
		p1 = jline[i];
		if (p1 < 127)continue;
		p2 = jline[i+1];
        	if ((p1 >= 129) && (p1 <= 159)) ShiftJIS = TRUE;
		if (((p1 >= 224) && (p1 <= 239))&& ((p2 >= 64) && (p2 <= 158))) ShiftJIS = TRUE;
		if (ShiftJIS)
		{
            		sjis2jis   (&p1,&p2);
            		p1 += 128;
            		p2 += 128;
			jline[i] = p1;
			jline[i+1] = p2;
		
		}
		i++;
	}
}

/*===sjis2jis    - convert ShiftJIS to JIS ===========================*/

void sjis2jis   (int *p1,int *p2)   /* Ken Lunde's routine  */
{
    register unsigned char c1 = *p1;
    register unsigned char c2 = *p2;
    register int adjust = c2 < 159;
    register int rowOffset = c1 < 160 ? 112 : 176;
    register int cellOffset = adjust ? (31 + (c2 > 127)) : 126;

    *p1 = ((c1 - rowOffset) << 1) - adjust;
    *p2 -= cellOffset;
}
void print_ins()
{
	printf("usage: kana2rom -options fni fno\n ");
	printf("  options:   -E force EUC input mode (input has JIS212)\n");
	printf("             -os output in Shift-JIS\n");
	printf("             -oj output in JIS\n");
	printf("             -ccontrol-file\n");
	printf("             -h force okurigana to hyphen\n");
	printf("             -p force okurigana to parentheses\n");
	printf("             -H these instructions\n");
}
main(argc,argv)
int argc;
unsigned char **argv;
{
	FILE *fi,*fo,*fopen();
	int hit,k,i,j,l;
	int argk,c,state,ip;
	register char **p;
	unsigned char tempstr[20];
	unsigned char instr_raw[256];

  argk = argc;
  while (TRUE)
  {
    if (argk < 3)
	{
		print_ins();
	  	exit(0);
	}
	else
	{
		printf("KANA2ROM: kana to romaji conversion program, J.W. Breen, 1996\n\n");
	  p=argv;
	  p++;
	  --argk;
		strcpy(tempstr,*p);
		while (tempstr[0] == '-')
		{
			if (tempstr[1] == 'H') 
			{
				print_ins();
				exit(0);
			}
			if (tempstr[1] == 'o') 
			{
				if ((tempstr[2] == 'j') || (tempstr[2] == 's'))
				{
					omode = tempstr[2];
					p++;
					--argk;
					strcpy(tempstr,*p);
					continue;
				}
				else
				{
					printf("Illegal output mode!\n");
					exit(1);
				}
			}
			if (tempstr[1] == 'E') 
			{
				ForceEUC = TRUE;
				p++;
				--argk;
				strcpy(tempstr,*p);
				continue;
			}
			if (tempstr[1] == 'h') 
			{
				ok_mark = '-';
				p++;
				--argk;
				strcpy(tempstr,*p);
				continue;
			}
			if (tempstr[1] == 'p') 
			{
				ok_mark = '(';
				Paren = TRUE;
				p++;
				--argk;
				strcpy(tempstr,*p);
				continue;
			}
			if (tempstr[1] == 'c') 
			{
				strcpy(ControlFile,tempstr+2);
				printf("Using user-specified control file: %s\n",ControlFile);
				p++;
				--argk;
				strcpy(tempstr,*p);
				continue;
			}
			printf("Illegal option\n");
			print_ins();
			exit(1);
		}

	}
	printf("Input File: %s\n",*p);
	if (fi= fopen(*p,"r")) break;
	printf("\nCannot open %s\n",*p);
  }
  p++;
	printf("Output File: %s\n",*p);
  fo = fopen(*p,"w");
	if (fo == NULL)
	{
		printf("\nCannot open %s\n",*p);
		exit(1);
	}
	LoadKana();
	while (!feof(fi))
	{
		fgets(instr_raw,255,fi);
		if(feof(fi))break;
		instr_raw[strlen(instr_raw)-1] = '\0';
		GetEUC(instr,instr_raw);
		kstr[0] = 0;
		outstr[0] = 0;
		for (j = 0; j < strlen(instr); j++)
		{
			if (instr[j] < 128)
			{
				process_kana();
				if ((instr[j] == '.') &&(outstr[strlen(outstr)-1] == '-'))
				{
					outstr[strlen(outstr)-1] = 0;
				}
				if (instr[j] == '.') 
				{
					instr[j] = ok_mark;
					OkActive = TRUE;
				}
				else
				{
					if (OkActive && Paren) addch(outstr,')');
					OkActive = FALSE;
				}
				addch(outstr,instr[j]);
				continue;
			}
			if ((instr[j] == 0xa1) && (instr[j+1] == 0xbc))
			{
				addch(kstr,instr[j]);
				addch(kstr,instr[j+1]);
				j++;
				continue;
			}
			if (instr[j] == 0x8f)
			{
				process_kana();
				if (OkActive && Paren) addch(outstr,')');
				OkActive = FALSE;
				addch(outstr,instr[j]);
				addch(outstr,instr[j+1]);
				addch(outstr,instr[j+2]);
				j+=2;
				continue;
			}
			if ((instr[j] < 0xa4) || (instr[j] > 0xa5))
			{
				process_kana();
				if (OkActive && Paren) addch(outstr,')');
				OkActive = FALSE;
				addch(outstr,instr[j]);
				addch(outstr,instr[j+1]);
				j++;
				continue;
			}
			addch(kstr,instr[j]);
			addch(kstr,instr[j+1]);
			j++;
			continue;
		}
		process_kana();
		if (OkActive && Paren) addch(outstr,')');
		OkActive = FALSE;
		KOut(outstr,outstr2);
		fprintf(fo,"%s\n",outstr2);
		kstr[0] = 0;
	}
	fclose(fi);
	fclose(fo);
}
