/*****************************************************************************/
/*  		VNTeX.c  --  Vietnamese TeX				     */
/*									     */
/*  		 Thieu Nguyen and Hieu Tran				     */
/*	      nguyen@ics.uci.edu & tran@ics.uci.edu			     */
/*	   Department of Information & Computer Science			     */
/*	        University of California, Irvine			     */
/*  		     Irvine, CA  92717					     */
/*  			Summer 1986					     */
/*****************************************************************************/

#include <stdio.h>
#include <ctype.h>
#include <sys/file.h>
#include <signal.h>

#define FALSE 0
#define TRUE  1

#define space(X)	(!isalpha(X))
#define vowel(X)	((X=='a'||X=='e'||X=='i'||X=='o'||X=='u'||X=='y'|| \
			  X=='A'||X=='E'||X=='I'||X=='O'||X=='U'||X=='Y'))
#define is_hat_breve(X)	(X=='^'||X=='(') /*||X=='a')*/
#define norm_mark(X)	(X=='?'||X=='.'||X=='`'||X=='~'||X=='\'')
#define ismark(X)	(X=='?'||X=='.'||X=='`'||X=='~'||X=='\''|| \
			 X=='^'||X=='(') /*||X=='a')*/
#define is_uo_mark(X)	(X=='?'||X=='.'||X=='`'||X=='~'||X=='\'')
#define is_dD(X,Y)	((X=='d'&&Y=='d') || (X=='D'&&Y=='D'))
#define is_uo(X,Y)	((X=='u'&&Y=='u') || (X=='U'&&Y=='U') || \
			 (X=='o'&&Y=='o') || (X=='O'&&Y=='O'))
#define is_not_oo(X)	((X=='a'||X=='e'||X=='i'||X=='u'||X=='y'|| \
			  X=='A'||X=='E'||X=='I'||X=='U'||X=='Y'))
#define text_command(X,Y,Z) \
			(X=='\\' && Y==Z && \
			(Y=='d'||Y=='D'||Y=='u'||Y=='U'||Y=='o'||Y=='O'))
#define quote(X, Y)	((X==Y) && ((X=='`') || (X=='\'')))
#define end_mark(X)	(Y=='.' || Y=='?')
#define esc_end(X, Y)	(X=='\\' && (Y=='.' || Y=='?' || Y=='\''))

#define MACRO_FILE	"VNTEX-MACRO.tex"

FILE *in_file, *out_file, *macro_file;

int  dealt_uo(), twelvepoint = FALSE, elevenpoint = FALSE,
     flag = FALSE, line = 0;

char out_buf [BUFSIZ], *output,			/* output string in Tex form */
     Hoiup[] = "Hoiup",
     sac[] = "sac", huy[] = "huy", hoi[] = "hoi", nga[] = "nga", nan[] = "nan",
     Sac[] = "Sac", Huy[] = "Huy", Hoi[] = "Hoi", Nga[] = "Nga";


main (argc, argv)
    register int argc;
    register char **argv;
{
    char rawfile[ BUFSIZ ], file_tex[ BUFSIZ ];
    register int len, fd, findex;

    init_sigs();			/* catch all errors and exit nicely */

    if (argc <= 1) {
        printf ("Usage: VNTeX [-fontsize] <file>.vnt\n");
	printf ("       -fontsize = 11 or 12 (default 10)\n");
	exit (1);
    }

    if (*argv[1] == '-') {			/* Get point size */
	if (!strcmp(argv[1], "-12"))
	    twelvepoint = TRUE;
	else if	(!strcmp(argv[1], "-11"))
	    elevenpoint = TRUE;
	findex = 2;
    }
    else
	findex = 1;

    strcpy (rawfile, argv[findex]);

/*    printf("This is VNTeX, Version 1.0 for Unix\n");*/
    
    if ( !(acceptable_filename (rawfile)) ) {
      printf("Sorry, file name has to be ended with \".vnt\". Bye!\n");
      exit (1);
    }

    if ((in_file = fopen (rawfile, "r")) == NULL) {
       perror (rawfile);
       exit (1);
    }
   
    /* replace the ".vnt" with the ".tex" */
    strcpy (file_tex, rawfile);
    len = strlen (file_tex);
    file_tex[len-1] = 'x';
    file_tex[len-2] = 'e';
    file_tex[len-3] = 't';

    if ((fd = open( file_tex, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
        perror (file_tex);
       exit (1);
    }
    out_file = fdopen (fd, "w");

    if ((macro_file = fopen (MACRO_FILE, "r")) == NULL) {
	macro_file = fopen (MACRO_FILE, "w");
	write_macro_file ();
    }
    fclose (macro_file);
    process_file ();				/* start the translation */

    if (fclose (in_file) == -1) perror (rawfile);
    if (fclose (out_file) == -1) perror (file_tex);

}

process_file ()
{
    char buf[BUFSIZ];
    register char ch1, ch2, ch3, ch4;
    register int i, len;

    fprintf (out_file, "\\input %s\n\n", MACRO_FILE);
    while ( fgets( buf, BUFSIZ, in_file ) != NULL ) {
      line++;
      i = 0;
      output = out_buf;
      len = strlen( buf );
      while (i < len) {
         ch1 = buf[i];
	 ch2 = buf[i+1];
	 ch3 = buf[i+2];
	 ch4 = buf[i+3];
	 if (is_dD(ch1, ch2)) {			/* see dd or DD -- convert */
	     dealt_dD (ch1);			/* to \dd or \DD, respec.  */
	     i += 2;
	 }
	 else if (is_uo(ch1, ch2)) {		/* see u or o -- handle */
	     i += dealt_uo (ch1, ch3, ch4);	/* special cases.	*/
	 }
         else if (vowel(ch1)) {
	     if (ismark(ch2)) {
		 if (flag) {
		     *output++ = ch1;
		     *output++ = ch2;
		     i += 2;
		 }
		 else {
		     flag = TRUE;
		     if (ismark(ch3)) {
			 if (is_hat_breve(ch2)) {
			     dealt_three (ch1, ch2, ch3);
			     i += 3;
			 }
			 else {
			     dealt_two (ch1, ch2);
			     *output++ = ch3;
			     i += 3;
			 }
		     }
		     else {
			 dealt_two (ch1, ch2);
			 if (esc_end(ch3, ch4)) {	/* skip over '\' */
			     *output++ = ch4;
			     i += 4;
			 }
			 else {
			     i += 2;
			 }
		     }
		 }
	     }
/*
  Need to check for more special cases to distinguish end marks
  with regular marks.
*/
	     else {
		 *output++ = ch1;
		 if (esc_end(ch2, ch3)) {		/* skip over '\' */
		     *output++ = ch3;
		     i += 3;
		 }
		 else i++;
	     }
	 }
	 else if (quote(ch1, ch2)) {		/* see `` or '' - do nothing */
	     *output++ = ch2;
	     *output++ = ch2;
	     i += 2;
	     flag = FALSE;
	 }
	 else if (text_command(ch1, ch2, ch3)) {/* see \dd, \oo or \uu -- */
	     *output++ = ch2;			/* remove '\', e.g. the   */
	     *output++ = ch2;			/* \a\ddtolength command  */
	     i += 3;
	     flag = FALSE;
	 }
	 else if (space(ch1)) {			/* new word, reset flag */
	     flag = FALSE;
	     *output++ = ch1;
	     i++;
	 }
	 else {					/* a consonant */
	     *output++ = ch1;
	     i++;
	 }
      }
      *output = '\0';
      fprintf (out_file, "%s", out_buf );	/* output to file */
   }
}


/*****************************************/
/* Input file must have ".vnt" extension */
/*****************************************/
int acceptable_filename (filename)
   register char *filename;
{
   register int i;
 
   i = strlen (filename);
   if (i < 5) return (FALSE);
   filename = filename + i - 4;
   if (!strcmp (filename, ".vnt"))
      return (TRUE);
   else
      return (FALSE);
}


/****************************************************/
/* To convert a vowel and a da^'u into Tex command. */
/****************************************************/
dealt_two (ch, sign)
    register char ch, sign;
{
    if (isupper(ch))
	ucase_two_marks(sign);
    else
	lcase_two_marks(sign);		/* convert da^'u appropriately */
    *output++ = '{';
    *output++ = ch;  
    *output++ = '}';
}


/************************************************/
/* Convert a vowel and two da^'u into TeX form. */
/************************************************/
dealt_three (ch, sign1, sign2 )
    register char ch, sign1, sign2;
{
    if (isupper(ch))
	ucase_three_marks(sign2);
    else
	lcase_three_marks(sign2);
    *output++ = '{';
    dealt_two (ch, sign1);
    *output++ = '}';
}


/***************************/
/* Convert letter dd or DD */
/***************************/
dealt_dD (ch)
    register char ch;
{
    *output++ = '\\'; *output++ = ch; *output++ = ch; *output++ = ' ';
}


/***************************/
/* Process letter uu or oo */
/***************************/
int dealt_uo (ch, ch2, ch3)
    register char ch, ch2, ch3;
{
    register int advance = 2;

    if (is_uo_mark(ch2)) {
	flag = TRUE;
	advance = 3;
	if (isupper(ch))
	    ucase_three_marks (ch2);
	else lcase_three_marks (ch2);
    }
    else if (is_hat_breve(ch2))
       error ();
    *output++ = '{'; *output++ = '\\'; *output++ = ch;
    *output++ = ch;  *output++ = '}';
    if (is_not_oo(ch2)) {
	*output++ = ch2;
	advance = 3;
	flag = TRUE;
    }
    else if (esc_end(ch2, ch3)) {
	*output++ = ch3;
	advance += 2;
    }
    return advance;
}


/************************************************/
/* A lowercase vowel and 1 da^'u, including the */
/* conversion of da^'u "na(.ng", and "(" to TeX */
/* command: 	.  => \d			*/
/*		(  => \u			*/
/************************************************/
lcase_two_marks (sign)
    register char sign;
{
    *output++ = '\\';
    if (sign == '.')
	*output++ = 'd';
    else if (sign == '(')
	*output++ = 'u';
    else *output++ = sign;
}


/**********************************/
/* An uppercase vowel and 1 da^'u */
/**********************************/
ucase_two_marks (sign)
    register char sign;
{
    register char *mark;

    if (sign == '?') {
	*output++ = '\\';
	mark = Hoiup;
	while (*mark)
	    *output++ = *mark++;
    }
    else
	lcase_two_marks (sign);
}	  


/*********************************/
/* A lowercase vowel and 2 da^'u */
/*********************************/
lcase_three_marks (X)
    register char X;
{
    register char *mark;

    *output++ = '\\';
    switch (X) {
	case '\'' : mark = sac; break;
 	case '`'  : mark = huy; break;
	case '?'  : mark = hoi; break;
	case '~'  : mark = nga; break;
	case '.'  : mark = nan; break;
    }
    while (*mark)
	*output++ = *mark++;
}


/**********************************/
/* An uppercase vowel and 2 da^'u */
/**********************************/
ucase_three_marks (X)
    register char X;
{
    register char *mark;

    *output++ = '\\';
    switch (X) {
	case '\'' : mark = Sac; break;
 	case '`'  : mark = Huy; break;
	case '?'  : mark = Hoi; break;
	case '~'  : mark = Nga; break;
	case '.'  : mark = nan; break;
    }
    while (*mark)
	*output++ = *mark++;
}	  


/***********************************/
/* Write an error message and exit */  
/***********************************/
error ()
{
    *output = '\0';
    fprintf (out_file, "%s", out_buf );			/* dump buffer */
    printf ("*** Typing error in input file at line %d *** \n", line);
    exit (1);						/* exit */
}


/************************************/
/* Catch all errors and exit nicely */
/************************************/
init_sigs()
{
	int exit(), error();

	(void) signal(SIGINT,  exit);
	(void) signal(SIGHUP,  exit);
	(void) signal(SIGQUIT, error);
	(void) signal(SIGSEGV, error);
	(void) signal(SIGBUS,  error);
	(void) signal(SIGILL,  error);
	(void) signal(SIGFPE,  error);
}


/*********************************************/
/* Define TeX commands for diacritical marks */
/*********************************************/
write_macro_file ()
{
    if (twelvepoint)
	fprintf (macro_file, "\\font\\mark=cmr9\n");
    else if (elevenpoint)
	fprintf (macro_file, "\\font\\mark=cmr8\n");
    else
	fprintf (macro_file, "\\font\\mark=cmr8\n");

    fprintf (macro_file,"\\def\\?#1{\\hbox{\\raise.5ex\\hbox{\\kern.2em\\mark\\char39}\\kern-.5em#1}}\n");

    fprintf (macro_file,"\\def\\sac#1{\\hbox{\\raise.5ex\\hbox{\\kern.1em\\char19}\\kern-.6em#1}}\n");
    fprintf (macro_file,"\\def\\huy#1{\\hbox{\\raise.5ex\\hbox{\\kern.1em\\char18}\\kern-.6em#1}}\n");
    fprintf (macro_file,"\\def\\hoi#1{\\hbox{\\raise.8ex\\hbox{\\kern.3em\\mark\\char39}\\kern-.6em#1}}\n");
    fprintf (macro_file,"\\def\\nga#1{\\hbox{\\raise.5ex\\hbox{\\char126}\\kern-.6em#1}}\n");
    fprintf (macro_file,"\\def\\nan#1{\\d{#1}}\n");
    fprintf (macro_file,"\n");

    fprintf (macro_file,"\\def\\Hoiup#1{\\hskip.1pt\\hbox{\\raise1.1ex\\hbox{\\kern1em\\mark\\char39}\\kern-.8em#1}}\n");

    fprintf (macro_file,"\\def\\Sac#1{\\hskip.1pt\\hbox{\\raise1ex\\hbox{\\kern.6em\\char19}\\kern-.9em#1}}\n");
    fprintf (macro_file,"\\def\\Huy#1{\\hskip.1pt\\hbox{\\raise1ex\\hbox{\\kern.6em\\char18}\\kern-.9em#1}}\n");
    fprintf (macro_file,"\\def\\Hoi#1{\\hskip.01pt\\hbox{\\raise1.3ex\\hbox{\\kern.9em\\mark\\char39}\\kern-.8em#1}}\n");
    fprintf (macro_file,"\\def\\Nga#1{\\hskip.1pt\\hbox{\\raise1.1ex\\hbox{\\kern.6em\\char126}\\kern-.9em#1}}\n");
    fprintf (macro_file,"\n");

    fprintf (macro_file,"\\def\\dd{\\kern.1em\\hbox{d\\raise.9ex\\hbox{\\kern-.3em -}}}\n");
    fprintf (macro_file,"\\def\\DD{\\hskip.1pt\\hbox{D\\raise.3ex\\hbox{\\kern-.7em\\char45}\\kern.4em}}\n");
    fprintf (macro_file,"\n");
    fprintf (macro_file,"\\def\\uu{\\hbox{u\\raise.1ex\\hbox{\\kern-.22em\\mark\\char39}}}\n");
    fprintf (macro_file,"\\def\\UU{\\hskip.1pt\\hbox{U\\raise.45ex\\hbox{\\kern-.3em\\char39}}}\n");
    fprintf (macro_file,"\n");
    fprintf (macro_file,"\\def\\oo{\\hbox{o\\hbox{\\kern-.15em\\mark\\char39}}}\n");
    fprintf (macro_file,"\\def\\OO{\\hskip.1pt\\hbox{O\\raise.2ex\\hbox{\\kern-0.28em\\char39}}}\n");
    fprintf (macro_file,"\n");
}
