#include "TeXit.h"

#include <ctype.h>

typedef struct {
     char *see;
     int len;
     char *set;
     BOOLEAN nargs;
} ENTRY;

ENTRY list[] = {

/* lower case Greek */

     {"alpha ",5,"[/sy(a)]",FALSE},
     {"beta ",4,"[/sy(b)]",FALSE},
     {"gamma ",5,"[/sy(g)]",FALSE},
     {"delta ",5,"[/sy(d)]",FALSE},
     {"epsilon ",7,"[/sy(e)]",FALSE},
     {"varepsilon ",10,"[/sy(e)]",FALSE},
     {"zeta ",4,"[/sy(z)]",FALSE},
     {"eta ",3,"[/sy(h)]",FALSE},
     {"theta ",5,"[/sy(q)]",FALSE},
     {"vartheta ",8,"[/sy(J)]",FALSE},
     {"iota ",4,"[/sy(i)]",FALSE},
     {"kappa ",5,"[/sy(k)]",FALSE},
     {"lambda ",6,"[/sy(l)]",FALSE},
     {"mu ",2,"[/sy(m)]",FALSE},
     {"nu ",2,"[/sy(n)]",FALSE},
     {"xi ",2,"[/sy(x)]",FALSE},
     {"omicron ",7,"[/sy(o)]",FALSE},
     {"pi ",2,"[/sy(p)]",FALSE},
     {"varpi ",5,"[/sy(v)]",FALSE},
     {"rho ",3,"[/sy(r)]",FALSE},
     {"varrho ",6,"[/sy(r)]",FALSE},
     {"sigma ",5,"[/sy(s)]",FALSE},
     {"varsigma ",8,"[/sy(V)]",FALSE},
     {"tau ",3,"[/sy(t)]",FALSE},
     {"upsilon ",7,"[/sy(u)]",FALSE},
     {"phi ",3,"[/sy(f)]",FALSE},
     {"varphi ",6,"[/sy(j)]",FALSE},
     {"chi ",3,"[/sy(c)]",FALSE},
     {"psi ",3,"[/sy(y)]",FALSE},
     {"omega ",5,"[/sy(w)]",FALSE},

/* capital Greek */

     {"Gamma ",5,"[/sy(G)]",FALSE},
     {"Delta ",5,"[/sy(D)]",FALSE},
     {"Theta ",5,"[/sy(Q)]",FALSE},
     {"Lambda ",6,"[/sy(L)]",FALSE},
     {"Xi ",2,"[/sy(X)]",FALSE},
     {"Pi ",2,"[/sy(P)]",FALSE},
     {"Upsilon ",7,"[/sy(\\241)]",FALSE},
     {"Phi ",3,"[/sy(F)]",FALSE},
     {"Psi ",3,"[/sy(Y)]",FALSE},
     {"Omega ",5,"[/sy(W)]",FALSE},

/* misc */

     {"pm ",2,"[/sy(\\261)]",FALSE},
     {"times ",5,"[/sy(\\264)]",FALSE},
     {"div ",3,"[/sy(\\270)]",FALSE},
     {"ast ",3,"[/sy(*)]",FALSE},
     {"circ ",4,"[/sy(\\260)]",FALSE},
     {"bullet ",6,"[/sy(\\267)]",FALSE},
     {"cdot ",4,"[/sy(\\215)]",FALSE},
     {"cap ",3,"[/sy(\\307)]",FALSE},
     {"cup ",3,"[/sy(\\310)]",FALSE},
     {"vee ",3,"[/sy(\\332)]",FALSE},
     {"wedge ",5,"[/sy(\\331)]",FALSE},
     {"diamond ",7,"[/sy(\\340)]",FALSE},
     {"oplus ",5,"[/sy(\\305)]",FALSE},
     {"otimes ",6,"[/sy(\\304)]",FALSE},
     {"dagger ",6,"[/rm(\\262)]",FALSE},
     {"ddagger ",7,"[/rm(\\263)]",FALSE},

     {"leq ",3,"[/sy(\\243)]",FALSE},
     {"ll ",2,"[/tt(\\253)]",FALSE},
     {"subset ",6,"[/sy(\\314)]",FALSE},
     {"subseteq ",8,"[/sy(\\315)]",FALSE},
     {"in ",2,"[/sy(\\316)]",FALSE},
     {"geq ",3,"[/sy(\\263)]",FALSE},
     {"gg ",2,"[/tt(\\273)]",FALSE},
     {"supset ",6,"[/sy(\\311)]",FALSE},
     {"supseteq ",8,"[/sy(\\312)]",FALSE},
     {"ni ",2,"[/sy(')]",FALSE},
     {"equiv ",5,"[/sy(\\272)]",FALSE},
     {"sim ",3,"[/sy(~)]",FALSE},
     {"approx ",6,"[/sy(\\273)]",FALSE},
     {"cong ",4,"[/sy(@)]",FALSE},
     {"neq ",3,"[/sy(\\271)]",FALSE},
     {"propto ",6,"[/sy(\\265)]",FALSE},
     {"mid ",3,"[/sy(|)]",FALSE},
     {"parallel ",8,"[/sy(\\357\\357)]",FALSE},

     {"leftarrow ",9,"[/sy(\\254)]",FALSE},
     {"longleftarrow ",13,"[/sy(\\254\\276)]",FALSE},
     {"uparrow ",7,"[/sy(\\255)]",FALSE},
     {"Leftarrow ",9,"[/sy(\\334)]",FALSE},
     {"Uparrow ",7,"[/sy(\\335)]",FALSE},
     {"rightarrow ",10,"[/sy(\\256)]",FALSE},
     {"longrightarrow ",14,"[/sy(\\276\\256)]",FALSE},
     {"downarrow ",9,"[/sy(\\257)]",FALSE},
     {"Rightarrow ",10,"[/sy(\\336)]",FALSE},
     {"Downarrow ",9,"[/sy(\\337)]",FALSE},
     {"leftrightarrow ",14,"[/sy(\\253)]",FALSE},
     {"longleftrightarrow ",18,"[/sy(\\254\\276\\256)]",FALSE},
     {"Leftrightarrow ",14,"[/sy(\\333)]",FALSE},

     {"aleph ",5,"[/sy(\\300)]",FALSE},
     {"prime ",5,"[/sy(\\242)]",FALSE},
     {"forall ",6,"[/sy(\")]",FALSE},
     {"infty ",5,"[/sy(\\245)]",FALSE},
     {"emptyset ",8,"[/rm(\\351)]",FALSE},
     {"exists ",6,"[/sy($)]",FALSE},
     {"nabla ",5,"[/sy(\\321)]",FALSE},
     {"neg ",3,"[/sy(\\330)]",FALSE},
     {"surd ",4,"[/sy(\\326)]",FALSE},
     {"clubsuit ",8,"[/sy(\\247)]",FALSE},
     {"wp ",2,"[/sy(\\303)]",FALSE},
     {"diamondsuit ",11,"[/sy(\\250)]",FALSE},
     {"Re ",2,"[/sy(\\302)]",FALSE},
     {"|",1,"[/sy(\\275\\275)]",FALSE},
     {"backslash ",9,"[/rm(\\134)]",FALSE},
     {"heartsuit ",9,"[/sy(\\251)]",FALSE},
     {"Im ",2,"[/sy(\\301)]",FALSE},
     {"angle ",5,"[/sy(\\320)]",FALSE},
     {"partial ",7,"[/sy(\\266)]",FALSE},
     {"spadesuit ",9,"[/sy(\\252)]",FALSE},

     {"sum ",3,"[/sy(\\345)]",FALSE},
     {"prod ",4,"[/sy(P)]",FALSE},
     {"int ",3,"[/sy(\\362)]",FALSE},

     {"sqrt ",4,"[/sy(\\326)]",FALSE},

     {"langle ",6,"[/sy(\\341)]",FALSE},
     {"rangle ",6,"[/sy(\\361)]",FALSE},
     
/* non maths ones */

     {"pounds ",6,"[/rm(\\243)]",FALSE},
     {"ldots ",5,"[/sy(\\274)]",FALSE},

/* fonts */

     {"de ",2,"/de",FALSE},
     {"sy ",2,"/sy",FALSE},
     {"it ",2,"/it",FALSE},
     {"rm ",2,"/rm",FALSE},
     {"bf ",2,"/bf",FALSE},
     {"cal ",3,"/cal",FALSE},
     {"tt ",2,"/tt",FALSE},

/* constructions */

     {"bar ",3,"/bar",1},
     {"overline ",8,"/bar",1},
     {"underline ",9,"/ul",1},
     {"frac ",4,"/frac",2},

/* end of list */

     {NULL, 0, NULL, FALSE}
};

static BOOLEAN addONE;

static int lcmp(char *text,ENTRY *is)
{
     int i;
     char *tmp,*txt;

     addONE=FALSE;

     for (i=0; is->see; ++i, ++is) {
	  for (tmp=is->see,txt=text; *tmp ; ++txt,++tmp)
	       if (*tmp == ' ') {
		    if (isalnum(*txt))
			 break;
		    else if (isspace(*txt))
			 addONE = TRUE;
	       } else if (*tmp != *txt)
		    break;
	  if (!*tmp)
	       break;
     }

     return (is->see ? i:-1);
}

char *TeXnumb(double f)
{
     int exponent,i;
     double mantisa;
     char dummy[MAXTEX];
     static char sendme[MAXTEX];

     sprintf(dummy,"%g",f);
     for (i=0; dummy[i] && dummy[i] != 'e'; ++i);
     if (dummy[i] == 'e') {
	  exponent = atoi(dummy+i+1);
	  dummy[i] = '\0';
     } else
	  exponent = 0;

     if (atof(dummy) == 1.0 && exponent) {
	  sprintf(sendme,"10^{%d}",exponent);
     } else if (exponent) {
	  sprintf(sendme,"%s\\times 10^{%d}",dummy,exponent);
     } else
	  sprintf(sendme,"%s",dummy);

     return (sendme);
}

int TeXit(char *output,char *input,int maxloop)
{
     char sup[MAXTEX],sub[MAXTEX],*tmp;
     int c=1,i=0,j,numb;
     BOOLEAN inTEXT=FALSE,quit=FALSE;

     *output++ = '[';

     while (maxloop-- && c && !quit && (c = input[i++])) {
	  switch (c) {
	  case '{':
	       if (inTEXT) {             /* end open text */
		    inTEXT = FALSE;
		    *output++ = ')';
	       }
	       i += TeXit(sub,input+i,-1);
	       output += sprintf(output,"%s",sub);
	       break;
	  case '}':
	       if (inTEXT) {             /* end open text */
		    inTEXT = FALSE;
		    *output++ = ')';
	       }
	       quit = TRUE;
	       break;
	  case '_':
	       if (inTEXT) {             /* end open text */
		    inTEXT = FALSE;
		    *output++ = ')';
	       }
	       if (!(c = input[i]))
		    break;
	       else if (c == '{')
		    ++i;
	       i += TeXit(sub,input+i,c=='{'? -1:1 );
	       if ((c = input[i]) && c == '^') {
		    if (!(c = input[++i]))
			 break;
		    else if (c == '{')
			 ++i;
		    i += TeXit(sup,input+i,c=='{'? -1:1 );
		    output += sprintf(output,"[/ss%s%s]",sub,sup);
	       } else
		    output += sprintf(output,"[/sub%s]",sub);
	       break;
	  case '^':
	       if (inTEXT) {             /* end open text */
		    inTEXT = FALSE;
		    *output++ = ')';
	       }
	       if (!(c = input[i]))
		    break;
	       else if (c == '{')
		    ++i;
	       i += TeXit(sup,input+i,c=='{'? -1:1 );
	       if ((c = input[i]) && c == '_') {
		    if (!(c = input[++i]))
			 break;
		    else if (c == '{')
			 ++i;
		    i += TeXit(sub,input+i,c=='{'? -1:1 );
		    output += sprintf(output,"[/ss%s%s]",sub,sup);
	       } else
		    output += sprintf(output,"[/sup%s]",sup);
	       break;
	  case '\\':
	       if (!(c = input[i]))
		    break;             /* end of text */
	       else if (c != '\\') {
		    if (isdigit(c)) {  /* decimal number */
			 numb = 0;
			 do {
			      sub[numb++] = input[i++];
			 } while (isdigit(input[i]));
			 sub[numb] = '\0';
			 numb = atoi(sub);
			 if (numb < 256)      /* ascii assumed */
			      output += sprintf(output,"%s\\%o"
						,inTEXT ? "":"("
						,numb);
			 else
			      output += sprintf(output,"%s?",inTEXT ? "":"(");
			 inTEXT = TRUE;
			 break;
		    } else if ((numb = lcmp((char *) (input+i),list)) >= 0) {
			 if (inTEXT) {
			      inTEXT = FALSE;
			      *output++ = ')';
			 }
			 i += list[numb].len + addONE;
			 if (!list[numb].nargs)
			      output += sprintf(output,"%s",list[numb].set);
			 else {
			      for (j=0; j<list[numb].nargs; ) {
				   while ((c = input[i]) && isspace(c))
					++i;
				   if (!c)
					break;
				   else if (c == '{')
					++i;
				   i += TeXit(sub,input+i,c=='{'?-1:1);
				   if (!j)
					output += sprintf(output,"[%s"
							  ,list[numb].set);
				   output += sprintf(output,"%s",sub);
				   if (++j == list[numb].nargs)
					output += sprintf(output,"]");
			      }
			 }
			 break;
		    } else
			 c = input[i++]; /* just put character */
	       } else
		    ++i;   /* it's a \\ and you want to step on */
	  default:
	       if (c == '\\' && input[i] == '\n')     /* just skip */
		    ++i;
	       else {
		    if (!inTEXT) {
			 inTEXT = TRUE;
			 *output++ = '(';
		    }
		    if (c == '(' || c == ')' || c == '\\')
			 *output++ = '\\';
		    if (isspace(c))
			 *output++ = ' ';
		    else
			 *output++ = c;
	       }
	  }
     }
     
     if (inTEXT) {             /* end open text */
	  inTEXT = FALSE;
	  *output++ = ')';
     }

     output += sprintf(output,"]\n");  /* end of module */

     return (i);     /* number of chars taken from input */
}


