/*
  Copyright (C) 1989      Fung F. Lee
  Copyright (C) 1994      Stephen G. Simpson

  big2hzp: convert a Big5 file into a HZ+ file.

  This program is free for general distribution.  

*/

#include <stdio.h>

#define true 1
#define false 0
#define Big5FirstByte(c)	((c)>=0xA1 && (c)<=0xFE) 
/* is likely to be the first byte of a Big5 character */

int termStyle = false;	/* enforce terminal emulation style if true */
int MAXLEN = 77;	/* default maximum line length in the above style */
int MINLEN = 7;		/* minimum line length in the above style */
char *progname;

main(argc, argv)
     int argc;
     char *argv[];
{
  int i, len;

  progname = argv[0];
  for (i=1; i<argc; i++)
    {
      if (argv[i][0]!='-') warning();
      switch (argv[i][1])
	{
        case 'f':
	    setbuf(stdout,NULL);
            break;
	case 't':
	    termStyle = true;
	    if ((argv[i][2]!='\0') && (sscanf(&argv[i][2], "%d", &len) != 1))
		warning();
	    if (len >= MINLEN) MAXLEN = len;
	    break;
	default:
	    warning();
	    break;
	}
    }
  filter(stdin, stdout);
}

warning()
{
  fprintf(stderr, 
	  "usage: %s [-f] [-t[maximum-line-length]] < foo.big > foo.hzp\n",
	  progname);
  fprintf(stderr, "       -f means do not buffer output\n");
  exit(1);
}

filter(fin, fout)
     FILE *fin, *fout;
{
    int c1, c2, c3, c4;
    int B5mode = false;
    int len = 0;
    int tilde = 0;
    int ascii = 1;
  
    while ((c1=fgetc(fin)) != EOF)
	{
	    if (Big5FirstByte(c1))
		/* assume c1 is the first byte of a Big5 character */
		{
		    if (termStyle)
			{
			    if (B5mode && len>MAXLEN-5)
				{
				    fprintf(fout, "~}~\n");
				    B5mode = false;
				    len = 0;
				    ascii = 1;
				}
			    else if (!B5mode && len>MAXLEN-7)
				{
				    fprintf(fout, "~\n");
				    B5mode = false;
				    len = 0;
				    ascii = 1;
				}
			}
		    c2 = fgetc(fin);
		    if (c1 < 0xC9)
			/* Big5 block 1, see HZ+ specification */
			{
			    if (B5mode != 1)
				{		
				    B5mode = 1;
				    fprintf(fout, "~>");
				    len += 2;
				    ascii = 0;
				    tilde = 0;
				}
			}
		    else 
			/* Big5 block 2, see HZ+ specification */
			{
			    if (B5mode != 2)
				{			
				    B5mode = 2;
				    fprintf(fout, "~<");
				    len += 2;
				    ascii = 0;
				    tilde = 0;
				}
			}
		    big2hzp(c1, c2, &c3, &c4);
		    fputc(c3, fout);
		    fputc(c4, fout);
		    len += 2;
		}
	    else
		/* c1 is not the first byte of a Big5 character */
		/* treat it as ASCII */
		{
		    if (B5mode)
			{
			    fprintf(fout, "~}");
			    len += 2;
			    B5mode = false;
			    ascii = 1;
			}
		    if (termStyle && (len>MAXLEN-2 || len>MAXLEN-3 && c1=='~'))
			{
			    fprintf(fout, "~\n");
			    len = 0;
			    ascii = 1;
			}
		    if (tilde==1)
			{
			    if (c1 == '{' || c1 == '<' || c1 == '>')
				ascii = 0;
			    else if (c1 == '}' || c1 == '\n' || c1 == '~')
				ascii = 1;
			    else if (ascii == 1)
				{
				    fputc('~', fout);
				    len++;
				}
			}
		    fputc(c1, fout);
		    len++;
		    if (c1=='\n') len=0;
		    if (c1== '~' && tilde == 0)
			tilde = 1;
		    else tilde = 0;
		}
	}
    if (B5mode) fprintf(fout, "~}");
}

/*

cns2hzp(b1, b2, a1, a2)
    int b1, b2, *a1, *a2;
{
    *a1 = 0x7F & b1;
    *a2 = 0x7F & b2;
}

big2hzp(b1, b2, a1, a2)
    int b1, b2, *a1, *a2;
{
    unsigned long n;

    n = 157 * ((b1 < 0xC9) ? (b1 - 0xA1) : (b1 - 0xC9)) 
	+ ((b2 < 0xA1) ? (b2 - 0x40) : (b2 - 0xA1 + 63));

    *a1 = 0x21 + (int) (n / 94);

    *a2 = 0x21 + (int) (n % 94);
}

*/

int table1[54] = {0x21, 0x22, 0x24, 0x26, 0x27, 0x29, 0x2B, 0x2C,
0x2E, 0x30, 0x31, 0x33, 0x35, 0x36, 0x38, 0x3A, 0x3B, 0x3D, 0x3F,
0x40, 0x42, 0x44, 0x45, 0x47, 0x49, 0x4A, 0x4C, 0x4E, 0x4F, 0x51,
0x53, 0x54, 0x56, 0x58, 0x59, 0x5B, 0x5D, 0x5E, 0x60, 0x62, 0x63,
0x65, 0x67, 0x68, 0x6A, 0x6C, 0x6D, 0x6F, 0x71, 0x72, 0x74, 0x76,
0x77, 0x79};

int table2[54] = {0x21, 0x60, 0x41, 0x22, 0x61, 0x42, 0x23, 0x62,
0x43, 0x24, 0x63, 0x44, 0x25, 0x64, 0x45, 0x26, 0x65, 0x46, 0x27,
0x66, 0x47, 0x28, 0x67, 0x48, 0x29, 0x68, 0x49, 0x2A, 0x69, 0x4A,
0x2B, 0x6A, 0x4B, 0x2C, 0x6B, 0x4C, 0x2D, 0x6C, 0x4D, 0x2E, 0x6D,
0x4E, 0x2F, 0x6E, 0x4F, 0x30, 0x6F, 0x50, 0x31, 0x70, 0x51, 0x32,
0x71, 0x52};

/*
    for(b = 0; b < 54; b++)
	{
	    table1[b] = 0x21 + (157 * b) / 94;
	    table2[b] = 0x21 + (157 * b) % 94;
	}
*/

big2hzp(b1, b2, a1, a2)
    int b1, b2, *a1, *a2;
{
    int b;

    b = ((b1 < 0xC9) ? (b1 - 0xA1) : (b1 - 0xC9));

    *a1 = table1[b];

    *a2 = table2[b] + ((b2 < 0xA1) ? (b2 - 0x40) : (b2 - 0xA1 + 63));

    if (*a2 > 0x7E) { *a2 = *a2 - 94 ; *a1 = *a1 + 1; }

    if (*a2 > 0x7E) { *a2 = *a2 - 94 ; *a1 = *a1 + 1; }

}

