1 /*  MathType equation to LaTeX converter
2  *
3  *  Ported 2000.04.03 by Steve Swanson, steve@mackichan.com
4  *  Initial implementation by Jack Medd.  Originally part of
5  *  RTF to LaTeX converter in Scientific WorkPlace (http://www.mackichan.com).
6  *
7  *  The MathType equation format were described at
8  *    http://www.mathtype.com/support/tech/MTEF4.htm
9  *    http://www.mathtype.com/support/tech/MTEF5.htm
10  *    http://www.mathtype.com/support/tech/MTEF_storage.htm
11  *    http://www.mathtype.com/support/tech/encodings/mtcode.stm
12  *  Various undocumented details determined by debugging and intuition.
13  *
14  *  Access to these pages is available at
15  *  http://web.archive.org/web/20010304110708/http://mathtype.com/support/tech/MTEF5.htm
16  *  http://web.archive.org/web/20010304110708/http://mathtype.com/support/tech/MTEF4.htm
17  *  http://web.archive.org/web/20010304110708/http://mathtype.com/support/tech/MTEF3.htm
18  *  http://web.archive.org/web/20010304111449/http://mathtype.com/support/tech/MTEF_storage.htm
19  *  http://web.archive.org/web/20021020115826/http://www.mathtype.com/support/tech/encodings/mtcode.stm
20  */
21 
22 # include       <stdint.h>
23 # include       <stdio.h>
24 # include       <string.h>
25 # include       <stdlib.h>
26 # include       <ctype.h>
27 
28 # include       "rtf.h"
29 # include       "rtf2latex2e.h"
30 # include       "eqn.h"
31 # include       "eqn_support.h"
32 
33 # define        DEBUG_PARSING     0
34 # define        DEBUG_TRANSLATION 0
35 # define        DEBUG_TEMPLATE    0
36 # define        DEBUG_FONT        0
37 # define        DEBUG_EMBELLS     0
38 # define        DEBUG_CHAR        0
39 # define        DEBUG_MODE        0
40 # define        DEBUG_SIZE        0
41 # define        DEBUG_JOIN        0
42 # define        DEBUG_LINE        0
43 # define        DEBUG_FUNCTION    0
44 # define        DEBUG_EQUATION    (DEBUG_PARSING || DEBUG_TRANSLATION || DEBUG_TEMPLATE)
45 
46 
47 static MT_OBJLIST *Eqn_GetObjectList(MTEquation * eqn, unsigned char *src, int *src_index, int num_objs);
48 static char *Eqn_TranslateObjects(MTEquation * eqn, MT_OBJLIST * the_list);
49 extern void hexdump (void *ptr, void *zero, uint32_t length, char *msg);
50 
51 # define EQN_MODE_TEXT     0
52 # define EQN_MODE_INLINE   1
53 # define EQN_MODE_DISPLAY  2
54 # define EQN_MODE_EQNARRAY 3
55 
56 /*  Various local data which used to be in rtf2latex.ini.  Initialized at bottom of file. */
57 extern char *Profile_FUNCTIONS[];
58 extern char *Profile_VARIABLES[];
59 extern char *Profile_PILEtranslation[];
60 extern char *Profile_MT_CHARSET_ATTS[];
61 extern char *Profile_CHARTABLE[];
62 extern char *Profile_TEMPLATES[];
63 extern char *Profile_TEMPLATES_5[];
64 extern char *Template_EMBELLS[];
65 
66 char * typeFaceName[NUM_TYPEFACE_SLOTS] =
67 {
68     "ZERO",
69     "TEXT",
70     "FUNCTION",
71     "VARIABLE",
72     "LCGREEK",
73     "UCGREEK",
74     "SYMBOL",
75     "VECTOR",
76     "NUMBER",
77     "USER1",
78     "USER2",
79     "MTEXTRA",
80     "UNKNOWN",
81     "UNKNOWN",
82     "UNKNOWN",
83     "UNKNOWN",
84     "UNKNOWN",
85     "UNKNOWN",
86     "UNKNOWN",
87     "UNKNOWN",
88     "UNKNOWN",
89     "TEXT_FE",
90     "EXPAND",
91     "MARKER",
92     "SPACE",
93     "UNKNOWN",
94     "UNKNOWN",
95     "UNKNOWN",
96     "UNKNOWN",
97     "UNKNOWN",
98     "UNKNOWN",
99     "UNKNOWN"
100 };
101 
102 static
ToBuffer(char * src,char * buffer,uint32_t * off,uint32_t * lim)103 char *ToBuffer(char *src, char *buffer, uint32_t *off, uint32_t *lim)
104 {
105 
106     uint32_t zln = (uint32_t) strlen(src) + 1;
107 
108     if (*off + zln + 256 >= *lim) {
109         char *newbuf;
110         *lim = *off + zln + 1024;
111         newbuf = (char *) malloc(*lim);
112         strcpy(newbuf, buffer);
113         free(buffer);
114         buffer = newbuf;
115     }
116 
117     strcpy(buffer + *off, src);
118     *off += zln - 1;
119     free(src);
120 
121     return buffer;
122 }
123 
SetComment(EQ_STRREC * strs,int lev,char * src)124 static void SetComment(EQ_STRREC * strs, int lev, char *src)
125 {
126     strs[0].log_level = lev;
127     strs[0].do_delete = 1;
128     strs[0].ilk = Z_COMMENT;
129     strs[0].is_line = 0;
130 
131     if (src) {
132         uint32_t zln = (uint32_t) strlen(src) + 1;
133         char *newbuf = (char *) malloc( (size_t) zln);
134         strcpy(newbuf, src);
135         strs[0].data = newbuf;
136     } else
137         strs[0].data = (char *) NULL;
138 }
139 
print_tag(uint8_t tag,int src_index)140 static void print_tag(uint8_t tag, int src_index)
141 {
142     switch (tag) {
143     case 0:
144         RTFMsg("[%03d] %-14s\n", src_index, "END");
145         break;
146     case 1:
147         RTFMsg("[%03d] %-14s\n", src_index, "LINE");
148         break;
149     case 2:
150         RTFMsg("[%03d] %-14s\n", src_index, "CHAR");
151         break;
152     case 3:
153         RTFMsg("[%03d] %-14s\n", src_index, "TMPL");
154         break;
155     case 4:
156         RTFMsg("[%03d] %-14s\n", src_index, "PILE");
157         break;
158     case 5:
159         RTFMsg("[%03d] %-14s\n", src_index, "MATRIX");
160         break;
161     case 6:
162         RTFMsg("[%03d] %-14s\n", src_index, "EMBELL");
163         break;
164     case 7:
165         RTFMsg("[%03d] %-14s\n", src_index, "RULER");
166         break;
167     case 8:
168         RTFMsg("[%03d] %-14s\n", src_index, "FONT_STYLE_DEF");
169         break;
170     case 9:
171         RTFMsg("[%03d] %-14s\n", src_index, "SIZE");
172         break;
173     case 10:
174         RTFMsg("[%03d] %-14s\n", src_index, "FULL");
175         break;
176     case 11:
177         RTFMsg("[%03d] %-14s\n", src_index, "SUB");
178         break;
179     case 12:
180         RTFMsg("[%03d] %-14s\n", src_index, "SUB2");
181         break;
182     case 13:
183         RTFMsg("[%03d] %-14s\n", src_index, "SYM");
184         break;
185     case 14:
186         RTFMsg("[%03d] %-14s\n", src_index, "SUBSYM");
187         break;
188     case 15:
189         RTFMsg("[%03d] %-14s\n", src_index, "COLOR");
190         break;
191     case 16:
192         RTFMsg("[%03d] %-14s\n", src_index, "COLOR_DEF");
193         break;
194     case 17:
195         RTFMsg("[%03d] %-14s\n", src_index, "FONT_DEF");
196         break;
197     case 18:
198         RTFMsg("[%03d] %-14s\n", src_index, "EQN_PREFS");
199         break;
200     case 19:
201         RTFMsg("[%03d] %-14s\n", src_index, "ENCODING_DEF");
202         break;
203     default:
204         RTFMsg("[%03d] %-14s\n", src_index, "FUTURE");
205         break;
206     }
207 }
208 
209 /*
210  * Nibble routines
211  */
HiNibble(unsigned char x)212 static unsigned char HiNibble(unsigned char x)
213 {
214 //    fprintf(stderr, "x=%d, high=%d, shifted=%d\n",x,(x & 0xF0),(x & 0xF0)/16);
215     return (unsigned char) ((x & 0xF0)/16);
216 }
217 
LoNibble(unsigned char x)218 static unsigned char LoNibble(unsigned char x)
219 {
220     return (x & 0x0F);
221 }
222 
PrintNibble(unsigned char n)223 static void PrintNibble(unsigned char n)
224 {
225     if (1)
226         return;
227 
228     if (n <= 9)
229         fprintf(stderr, "%d", n);
230     else if (n == 0x0A)
231         fprintf(stderr, ".");
232     else if (n == 0x0B)
233         fprintf(stderr, "-");
234     else if (n == 0x0F)
235         fprintf(stderr, " ");
236     else
237         RTFPanic("Bad nibble\n");
238 }
239 
PrintNibbleDimension(unsigned char n)240 static void PrintNibbleDimension(unsigned char n)
241 {
242     if (1)
243         return;
244     switch (n) {
245     case 0:
246         fprintf(stderr, "in ");
247         break;
248     case 1:
249         fprintf(stderr, "cm ");
250         break;
251     case 2:
252         fprintf(stderr, "pt ");
253         break;
254     case 3:
255         fprintf(stderr, "pc ");
256         break;
257     case 4:
258         fprintf(stderr, " %% ");
259         break;
260     default:
261         RTFPanic("Bad nibble\n");
262     }
263 }
264 
265 
SkipNibbles(unsigned char * p,int num)266 static int SkipNibbles(unsigned char *p, int num)
267 {
268     unsigned char hi, lo;
269     int nbytes = 0;
270     int count = 1;
271     int new_str = 1;
272 
273     if (0) fprintf(stderr, " #%02d -- ", count);
274     while (count <= num) {
275 
276         hi = HiNibble(*(p + nbytes));
277         lo = LoNibble(*(p + nbytes));
278         nbytes++;
279 
280         if (new_str)
281             PrintNibbleDimension(hi);
282         else
283             PrintNibble(hi);
284 
285         new_str = 0;
286         if (hi == 0x0F) {
287             new_str = 1;
288             count++;
289             if (0) fprintf(stderr, " ---> total of %d bytes\n #%02d -- ", nbytes, count);
290         }
291 
292         if (new_str)
293             PrintNibbleDimension(lo);
294         else
295             PrintNibble(lo);
296 
297         new_str = 0;
298         if (lo == 0x0F) {
299             new_str = 1;
300             count++;
301             if (0) fprintf(stderr, " ---> total of %d bytes\n #%02d -- ", nbytes, count);
302         }
303     }
304     if (0) fprintf(stderr, "\n");
305 
306     return nbytes;
307 }
308 
309 
310 /*  section contains strings of the form */
311 /*     key=data */
312 static
GetProfileStr(char ** section,char * key,char * data,int datalen)313 uint32_t GetProfileStr(char **section, char *key, char *data, int datalen)
314 {
315     char **rover;
316     size_t keylen;
317 
318 	data[0] = '\0';
319     if (key == NULL) return 0;
320     keylen = strlen(key);
321 
322     for (rover = &section[0]; *rover; ++rover) {
323         if (strncmp(*rover, key, keylen) == 0) {
324             strncpy(data, *rover + keylen + 1, (size_t) (datalen - 1));    /*  skip over = (no check for white space */
325             data[datalen - 1] = '\0';      /*  null terminate */
326             return ((uint32_t) strlen(data));
327         }
328     }
329 
330     return 0;
331 }
332 
333 
334 /*  this mangles the contents of strs[].data, so just call once! */
335 static
Eqn_JoinStrings(MTEquation * eqn,EQ_STRREC * strs,int num_strs)336 char *Eqn_JoinStrings(MTEquation * eqn, EQ_STRREC * strs, int num_strs)
337 {
338     char join[8192], buf[128];
339     char *p, *substition_text, *marker, *thetex;
340     char *vars[3];
341     int i, j, id, is_pile;
342 
343     if (DEBUG_JOIN) {
344         for (i=0; i<num_strs; i++)
345             fprintf(stderr,"   is_line=%d, strs[%d].data=%s\n", strs[i].is_line, i, strs[i].data);
346     }
347 
348     *join = '\0';
349 
350     for (i=0; i<num_strs; i++) {
351 
352         if (!strs[i].data) continue;
353 
354         if (strs[i].log_level > eqn->log_level) continue;
355 
356         if (strs[i].ilk != Z_TMPL) {
357             strcat(join, strs[i].data);
358             continue;
359         }
360 
361         /*  the current string is a TMPL and needs to be filled and added */
362         /*  e.g., dat = "\sqrt[#2]{#1}" */
363 
364         p = strs[i].data;
365 
366         while (*p) {
367 
368             marker = strchr(p, '#');
369             if (!marker) {
370                 strcat(join, p);
371                 break;
372             }
373 
374             *marker = '\0';
375             strcat(join, p);
376             p = marker + 1;
377 
378 /*  #1[L][STARTSUB][ENDSUB]  ... substitute text according to byzantine scheme */
379 
380             /* only #1, #2, and #3 are used */
381             id = *p - '1';
382             if (id < 0 || id > 3) break;
383             p++;
384 
385             /* Extract the bracketed items */
386             /* vars[0]="L", vars[1]="STARTSUB", vars[2]="ENDSUB" */
387             /* only vars[1] and vars[2] are used */
388 
389             vars[1] = NULL;
390             vars[2] = NULL;
391             j = 0;
392             while (*p == '[') {
393                 p++;
394                 marker = strchr(p, ']');
395                 if (!marker) break;
396                 *marker = '\0';
397                 vars[j++] = p;
398                 p = marker+1;
399             }
400 
401             /*  This is pretty confusing. All the strs[] have an is_line flag */
402             /*  only strs[] entries that have this flag set may be used for replacement */
403             /*  The replacement text for #1 or #2 or #3 is the first, second, or third */
404             /*  strs[] entry that has its flag set. */
405 
406             thetex = NULL;
407             for (j=i+1; j<num_strs; j++) {
408                 if (strs[j].is_line == 0) continue;
409 
410                 if (id == 0) {
411                     thetex = strs[j].data;
412                     strs[j].log_level = 100; /*  mark this entry as used */
413                     is_pile = (strs[j].is_line == 2) ? 1 : 0;
414                     break;
415                 }
416                 id--;  /*  one string closer to our goal */
417             }
418 
419             /*  this should not happen, but if it does, just go on to the next character */
420             if (!thetex) continue;
421 
422             if (GetProfileStr(Profile_VARIABLES, vars[1], buf, 128)) {
423 
424                 substition_text = buf;
425                 marker = strchr(buf, ',');
426 
427                 if (is_pile)
428                     substition_text = marker + 1;
429                 else
430                     *marker = '\0';
431 
432                 strcat(join, substition_text);
433             }
434 
435             strcat(join, thetex);
436 
437             if (GetProfileStr(Profile_VARIABLES, vars[2], buf, 128)) {
438 
439                 substition_text = buf;
440                 marker = strchr(buf, ',');
441 
442                 if (is_pile)
443                     substition_text = marker + 1;
444                 else
445                     *marker = 0;
446 
447                 strcat(join, substition_text);
448             }
449         }
450     }
451 
452     for (i=0; i<num_strs; i++)
453         if (strs[i].do_delete && strs[i].data) {
454             free(strs[i].data);
455             strs[i].data = NULL;
456         }
457 
458     thetex = (char *) malloc(strlen(join)+1);
459     strcpy(thetex, join);
460     if (DEBUG_JOIN) fprintf(stderr,"final join='%s'\n", thetex);
461     return thetex;
462 }
463 
464 /*  delete routines */
465 
466 
467 
468 static
DeleteTabstops(MT_TABSTOP * the_list)469 void DeleteTabstops(MT_TABSTOP * the_list)
470 {
471     MT_TABSTOP *del_node;
472 
473     while (the_list) {
474         del_node = the_list;
475         the_list = (MT_TABSTOP *) (the_list->next);
476         free(del_node);
477     }
478 }
479 
480 
481 static
DeleteEmbells(MT_EMBELL * the_list)482 void DeleteEmbells(MT_EMBELL * the_list)
483 {
484     MT_EMBELL *del_node;
485     while (the_list) {
486         del_node = the_list;
487         the_list = (MT_EMBELL *) the_list->next;
488         free(del_node);
489     }
490 }
491 
492 
493 static
DeleteObjectList(MT_OBJLIST * the_list)494 void DeleteObjectList(MT_OBJLIST * the_list)
495 {
496     MT_OBJLIST *del_node;
497     MT_LINE *line;
498     MT_CHAR *charptr;
499 
500     while (the_list) {
501 
502         del_node = the_list;
503         the_list = (void *) the_list->next;
504 
505         switch (del_node->tag) {
506 
507         case LINE:{
508                 line = (MT_LINE *) del_node->obj_ptr;
509                 if (line) {
510                     if (line->ruler) {
511                         DeleteTabstops(line->ruler->tabstop_list);
512                         free(line->ruler);
513                     }
514 
515                     if (line->object_list)
516                         DeleteObjectList(line->object_list);
517                     free(line);
518                 }
519             }
520             break;
521 
522         case CHAR:{
523                 charptr = (MT_CHAR *) del_node->obj_ptr;
524                 if (charptr) {
525                     if (charptr->embellishment_list)
526                         DeleteEmbells(charptr->embellishment_list);
527                     free(charptr);
528                 }
529             }
530             break;
531 
532         case TMPL:{
533                 MT_TMPL *tmpl = (MT_TMPL *) del_node->obj_ptr;
534                 if (tmpl) {
535                     if (tmpl->subobject_list)
536                         DeleteObjectList(tmpl->subobject_list);
537                     free(tmpl);
538                 }
539             }
540             break;
541 
542         case PILE:{
543                 MT_PILE *pile = (MT_PILE *) del_node->obj_ptr;
544                 if (pile) {
545                     if (pile->line_list)
546                         DeleteObjectList(pile->line_list);
547                     free(pile);
548                 }
549             }
550             break;
551 
552         case MATRIX:{
553                 MT_MATRIX *matrix = (MT_MATRIX *) del_node->obj_ptr;
554                 if (matrix) {
555                     if (matrix->element_list)
556                         DeleteObjectList(matrix->element_list);
557                     free(matrix);
558                 }
559             }
560             break;
561 
562         case EMBELL:
563             break;
564 
565         case RULER:{
566                 MT_RULER *ruler = (MT_RULER *) del_node->obj_ptr;
567                 if (ruler) {
568                     if (ruler->tabstop_list)
569                         DeleteTabstops(ruler->tabstop_list);
570                     free(ruler);
571                 }
572             }
573             break;
574 
575         case FONT:{
576                 MT_FONT *font = (MT_FONT *) del_node->obj_ptr;
577                 if (font) {
578                     if (font->zname)
579                         free(font->zname);
580                     free(font);
581                 }
582             }
583             break;
584 
585         case SIZE:
586         case FULL:
587         case SUB:
588         case SUB2:
589         case SYM:
590         case SUBSYM:{
591                 MT_SIZE *size = (MT_SIZE *) del_node->obj_ptr;
592                 if (size) {
593                     free(size);
594                 }
595             }
596             break;
597 
598         default:
599             break;
600         }
601 
602         free(del_node);
603     }                           /*   while ( the_list ) */
604 }
605 
Eqn_Destroy(MTEquation * eqn)606 void Eqn_Destroy(MTEquation * eqn)
607 {
608     if (eqn->o_list) {
609         DeleteObjectList(eqn->o_list);
610         eqn->o_list = NULL;
611     }
612     if (eqn->atts_table) {
613         free(eqn->atts_table);
614         eqn->atts_table = NULL;
615     }
616     if (eqn->m_latex_start) {
617         free(eqn->m_latex_start);
618         eqn->m_latex_start = NULL;
619     }
620     if (eqn->m_latex_end) {
621         free(eqn->m_latex_end);
622         eqn->m_latex_end = NULL;
623     }
624     if (eqn->m_latex) {
625         free(eqn->m_latex);
626         eqn->m_latex = NULL;
627     }
628 
629 }
630 
setMathMode(MTEquation * eqn,int mode)631 static void setMathMode(MTEquation * eqn, int mode)
632 {
633     char s[50];
634     if (DEBUG_MODE || g_input_file_type==TYPE_EQN) fprintf(stderr,"old=%d, new=%d\n",eqn->m_mode,mode);
635 
636     switch (mode) {
637     case EQN_MODE_TEXT:
638         switch (eqn->m_mode) {
639         case EQN_MODE_TEXT:
640             break;
641         case EQN_MODE_INLINE:
642             strcpy(s," $");
643             if (eqn->m_latex_end) free(eqn->m_latex_end);
644             eqn->m_latex_end = strdup(s);
645             break;
646         case EQN_MODE_DISPLAY:
647             strcpy(s," $$\n");
648             if (eqn->m_latex_end) free(eqn->m_latex_end);
649             eqn->m_latex_end = strdup(s);
650             break;
651         case EQN_MODE_EQNARRAY:
652             strcpy(s,"\\end{eqnarray}\n");
653             if (eqn->m_latex_end) free(eqn->m_latex_end);
654             eqn->m_latex_end = strdup(s);
655             break;
656         }
657         break;
658 
659     case EQN_MODE_INLINE:
660         switch (eqn->m_mode) {
661         case EQN_MODE_TEXT:
662             if (eqn->m_latex_start) free(eqn->m_latex_start);
663             eqn->m_latex_start = strdup("$");
664             break;
665         case EQN_MODE_INLINE:
666             break;
667         case EQN_MODE_DISPLAY:
668             fprintf(stderr,"Bizarre case of switching from display to inline??\n");
669             break;
670         case EQN_MODE_EQNARRAY:
671             fprintf(stderr,"Bizarre case of switching from eqnarray to inline??\n");
672             break;
673         }
674         break;
675 
676     case EQN_MODE_DISPLAY:
677         switch (eqn->m_mode) {
678         case EQN_MODE_TEXT:
679             if (eqn->m_latex_start) free(eqn->m_latex_start);
680             eqn->m_latex_start = strdup("$$");
681             break;
682         case EQN_MODE_INLINE:
683             fprintf(stderr,"Bizarre case of switching from inline to display??\n");
684             break;
685         case EQN_MODE_DISPLAY:
686             break;
687         case EQN_MODE_EQNARRAY:
688             fprintf(stderr,"Bizarre case of switching from eqnarry to display??\n");
689             break;
690         }
691         break;
692 
693     case EQN_MODE_EQNARRAY:
694         switch (eqn->m_mode) {
695         case EQN_MODE_TEXT:
696             if (eqn->m_latex_start) free(eqn->m_latex_start);
697             eqn->m_latex_start = strdup("\\begin{eqnarray}");
698             break;
699         case EQN_MODE_INLINE:
700             fprintf(stderr,"Bizarre case of switching from inline to eqnarry??\n");
701             break;
702         case EQN_MODE_DISPLAY:
703             fprintf(stderr,"Bizarre case of switching from display to eqnarry??\n");
704             break;
705         case EQN_MODE_EQNARRAY:
706             break;
707         }
708         break;
709     }
710 
711     eqn->m_mode = mode;
712 
713 /*    if (strlen(s))
714     	return strdup(s);
715     else
716     	return NULL;*/
717 }
718 
GetAttribute(MTEquation * eqn,unsigned char * src,uint8_t * attrs)719 static int GetAttribute(MTEquation * eqn, unsigned char *src, uint8_t *attrs)
720 {
721     if (eqn->m_mtef_ver < 5) {
722         *attrs = HiNibble(*src);
723         return 1;
724     }
725 
726     *attrs = *(src + 1);
727     return 2;
728 }
729 
730 static
GetNudge(unsigned char * src,int16_t * x,int16_t * y)731 int GetNudge(unsigned char *src, int16_t *x, int16_t *y)
732 {
733 
734     int nudge_length;
735     int16_t tmp;
736 
737     unsigned char b1 = *src;
738     unsigned char b2 = *(src + 1);
739 
740 
741     if (b1 == 128 && b2 == 128) {
742         tmp  = (int16_t) *(src + 2);
743         tmp |= (int16_t) *(src + 3) << 8;
744         *x = tmp;
745         tmp  = (int16_t) *(src + 4);
746         tmp |= (int16_t) *(src + 5) << 8;
747         *y = tmp;
748         nudge_length = 6;
749     } else {
750         *x = b1;
751         *y = b2;
752         nudge_length = 2;
753     }
754 
755     if (g_input_file_type==TYPE_EQN) fprintf(stderr, "nudge gotten size=%d",nudge_length);
756 
757     return nudge_length;
758 }
759 
Eqn_inputRULER(MTEquation * eqn,unsigned char * src,int * src_index)760 static MT_RULER *Eqn_inputRULER(MTEquation * eqn, unsigned char *src, int *src_index)
761 {
762     MT_RULER *new_ruler;
763     MT_TABSTOP *head, *curr, *new_stop;
764     uint8_t i, num_stops, tag;
765 
766     /* if we arrived here from LINE, then there does not seem to be
767        a proper RULER tag.  Skip the tag only if it is a RULER */
768     tag = *(src + *src_index) & 0x0F;
769     if (tag == 7)
770         (*src_index)++;             /*  step over ruler tag */
771 
772     head = NULL;
773     num_stops = *(src + *src_index);
774     (*src_index)++;
775 
776     for (i=0; i < num_stops; i++) {
777         new_stop = (MT_TABSTOP *) malloc(sizeof(MT_TABSTOP));
778         new_stop->next = NULL;
779         new_stop->type = *(src + *src_index);
780         (*src_index)++;
781 
782         new_stop->offset = *(src + *src_index);
783         (*src_index)++;
784         new_stop->offset |= *(src + *src_index) << 8;
785         (*src_index)++;
786 
787         if (head)
788             curr->next = (struct MT_TABSTOP *) new_stop;
789         else
790             head = new_stop;
791         curr = new_stop;
792     }
793 
794     new_ruler = (MT_RULER *) malloc(sizeof(MT_RULER));
795     new_ruler->n_stops = num_stops;
796     new_ruler->tabstop_list = head;
797 
798     return new_ruler;
799 }
800 
801 
802 /*
803     * record type (1)
804     * options
805     * [nudge] if mtefOPT_NUDGE is set
806     * [line spacing] if mtefOPT_LINE_LSPACE is set (16-bit integer)
807     * [RULER record] if mtefOPT_LP_RULER is set
808     * object list contents of line (a single pile, characters and templates, or nothing)
809 */
810 
Eqn_inputLINE(MTEquation * eqn,unsigned char * src,int * src_index)811 static MT_LINE *Eqn_inputLINE(MTEquation * eqn, unsigned char *src,
812                        int *src_index)
813 {
814     unsigned char attrs;
815     MT_LINE *new_line = (MT_LINE *) malloc(sizeof(MT_LINE));
816     new_line->nudge_x = 0;
817     new_line->nudge_y = 0;
818     new_line->line_spacing = 0;
819     new_line->ruler = NULL;
820     new_line->object_list = NULL;
821 
822     *src_index += GetAttribute(eqn, src+*src_index, &attrs);
823 
824     if (DEBUG_LINE) fprintf(stderr, "LINE options  = 0x%02x\n", attrs);
825 
826     if (attrs & xfLMOVE)
827         *src_index += GetNudge(src + *src_index, &new_line->nudge_x, &new_line->nudge_y);
828 
829     if (attrs & xfLSPACE) {
830         new_line->line_spacing = *(src + *src_index);
831         (*src_index)++;
832     }
833 
834     if (attrs & xfRULER)
835         new_line->ruler = Eqn_inputRULER(eqn, src, src_index);
836 
837     if (!(attrs & xfNULL))
838         new_line->object_list = Eqn_GetObjectList(eqn, src, src_index, 0);
839 
840     return new_line;
841 }
842 
843 
Eqn_inputEMBELL(MTEquation * eqn,unsigned char * src,int * src_index)844 static MT_EMBELL *Eqn_inputEMBELL(MTEquation * eqn, unsigned char *src, int *src_index)
845 {
846     unsigned char attrs, tag;
847     MT_EMBELL *head = NULL;
848     MT_EMBELL *new_embell = NULL;
849     MT_EMBELL *curr = NULL;
850     tag = EMBELL;
851 
852     while (tag == EMBELL) {
853         new_embell = (MT_EMBELL *) malloc(sizeof(MT_EMBELL));
854         new_embell->next = NULL;
855         new_embell->nudge_x = 0;
856         new_embell->nudge_y = 0;
857 
858         *src_index += GetAttribute(eqn, src+*src_index, &attrs);
859 
860         if (attrs & xfLMOVE)
861             *src_index += GetNudge(src + *src_index, &new_embell->nudge_x, &new_embell->nudge_y);
862 
863         new_embell->embell = *(src + *src_index);
864         if (DEBUG_EMBELLS  || g_input_file_type==TYPE_EQN)
865             fprintf(stderr, "[%-3d] EMBELL --- embell=%d\n", *src_index, (int) new_embell->embell);
866         (*src_index)++;
867 
868         if (head)
869             curr->next = (struct MT_EMBELL *) new_embell;
870         else
871             head = new_embell;
872         curr = new_embell;
873 
874         if (eqn->m_mtef_ver == 5)
875             tag = *(src + *src_index);
876         else
877             tag = LoNibble(*(src + *src_index));
878     }
879 
880     (*src_index)++;             /*  advance over end byte */
881 
882     return head;
883 }
884 
885 
886 /*
887     * attributes
888     * [nudge] if xfLMOVE is set
889     * [typeface] typeface value (see FONT below) + 128
890     * [character] 16-bit character value (encoding depends on typeface)
891     * [embellishment list] if xfEMBELL is set (embellishments)
892 */
893 
Eqn_inputCHAR(MTEquation * eqn,unsigned char * src,int * src_index)894 static MT_CHAR *Eqn_inputCHAR(MTEquation * eqn, unsigned char *src, int *src_index)
895 {
896     unsigned char attrs;
897     MT_CHAR *new_char = (MT_CHAR *) malloc(sizeof(MT_CHAR));
898     new_char->nudge_x = 0;
899     new_char->nudge_y = 0;
900     new_char->mtchar = 0;
901     new_char->bits16 = 0;
902     new_char->embellishment_list = (MT_EMBELL *) NULL;
903 
904     *src_index += GetAttribute(eqn, src+*src_index, &attrs);
905     new_char->atts = attrs;
906 
907     if (new_char->atts & CHAR_NUDGE)
908         *src_index += GetNudge(src + *src_index, &new_char->nudge_x, &new_char->nudge_y);
909 
910     new_char->typeface = *(src + *src_index);
911     (*src_index)++;
912 
913     if (eqn->m_mtef_ver < 5) {
914         new_char->character = *(src + *src_index);
915         (*src_index)++;
916         if (eqn->m_platform == PLATFORM_WIN) {
917 			new_char->character |= *(src + *src_index) << 8;
918 			(*src_index)++;
919         }
920 
921     } else {
922 
923         /* nearly always have a 16 bit MT character */
924         if (!(new_char->atts & CHAR_ENC_NO_MTCODE)) {
925             new_char->character = *(src + *src_index);
926             (*src_index)++;
927             new_char->character |= *(src + *src_index) << 8;
928             (*src_index)++;
929         }
930 
931         /*  02 05 84 bc 03 6d 06 00  11 00 02 04 86  */
932         if (new_char->atts & CHAR_ENC_CHAR_8) {
933             new_char->character = *(src + *src_index);
934             (*src_index)++;
935         }
936 
937         if (new_char->atts & CHAR_ENC_CHAR_16) {
938             new_char->bits16 = *(src + *src_index);
939             (*src_index)++;
940             new_char->bits16 |= *(src + *src_index) << 8;
941             (*src_index)++;
942         }
943     }
944 
945     if (g_input_file_type==TYPE_EQN || DEBUG_CHAR) {
946         fprintf(stderr, "          '%c' or 0x%04x,", (int)new_char->character, (unsigned int) new_char->character);
947         fprintf(stderr, " typeface = %d mtchar=%u, 16bit=%u ",
948                   (int) new_char->typeface-128, (unsigned int) new_char->mtchar, (unsigned int) new_char->bits16);
949         fprintf(stderr, " attr = 0x%02x \n", (unsigned int) new_char->atts);
950     }
951 
952     if (eqn->m_mtef_ver == 5) {
953         if (new_char->atts & CHAR_EMBELL)
954             new_char->embellishment_list = Eqn_inputEMBELL(eqn, src, src_index);
955     } else {
956         if (new_char->atts & xfEMBELL)
957             new_char->embellishment_list = Eqn_inputEMBELL(eqn, src, src_index);
958     }
959 
960 
961     return new_char;
962 }
963 
Eqn_inputTMPL(MTEquation * eqn,unsigned char * src,int * src_index)964 static MT_TMPL *Eqn_inputTMPL(MTEquation * eqn, unsigned char *src, int *src_index)
965 {
966     unsigned char attrs;
967     MT_TMPL *new_tmpl = (MT_TMPL *) malloc(sizeof(MT_TMPL));
968     new_tmpl->nudge_x = 0;
969     new_tmpl->nudge_y = 0;
970 
971     *src_index += GetAttribute(eqn, src+*src_index, &attrs);
972 
973     if (attrs & xfLMOVE)
974         *src_index += GetNudge(src + *src_index, &new_tmpl->nudge_x, &new_tmpl->nudge_y);
975 
976     new_tmpl->selector = *(src + *src_index);
977     (*src_index)++;
978 
979     new_tmpl->variation = *(src + *src_index);
980     (*src_index)++;
981 
982     if (eqn->m_mtef_ver == 5 && (new_tmpl->variation & 0x80) ) {
983         new_tmpl->variation &= 0x7F;
984         new_tmpl->variation |=  *(src + *src_index) << 8;
985         (*src_index)++;
986         RTFMsg("Two byte variation!\n");
987     }
988 
989     new_tmpl->options = *(src + *src_index);
990     (*src_index)++;
991 
992 //	if (eqn->m_mtef_ver == 3 && 18 <= new_tmpl->selector && new_tmpl->selector <= 20)
993 	//	new_tmpl->variation = new_tmpl->variation >> 8;
994 
995     if ( (DEBUG_PARSING && DEBUG_TEMPLATE) || g_input_file_type==TYPE_EQN)
996         fprintf(stderr, "TMPL : read sel=%2d var=0x%04x (%d.%d)\n",
997         (int) new_tmpl->selector, (unsigned int) new_tmpl->variation, (int) new_tmpl->selector, (int) new_tmpl->variation);
998 
999     new_tmpl->subobject_list = Eqn_GetObjectList(eqn, src, src_index, 0);
1000 
1001     return new_tmpl;
1002 }
1003 
1004 
Eqn_inputPILE(MTEquation * eqn,unsigned char * src,int * src_index)1005 static MT_PILE *Eqn_inputPILE(MTEquation * eqn, unsigned char *src,
1006                        int *src_index)
1007 {
1008     unsigned char attrs;
1009     MT_PILE *new_pile = (MT_PILE *) malloc(sizeof(MT_PILE));
1010     new_pile->nudge_x = 0;
1011     new_pile->nudge_y = 0;
1012     new_pile->ruler = NULL;
1013 
1014     *src_index += GetAttribute(eqn, src+*src_index, &attrs);
1015 
1016     if (attrs & xfLMOVE)
1017         *src_index += GetNudge(src + *src_index, &new_pile->nudge_x, &new_pile->nudge_y);
1018 
1019     new_pile->halign = *(src + *src_index);
1020     (*src_index)++;
1021 
1022     new_pile->valign = *(src + *src_index);
1023     (*src_index)++;
1024 
1025     if (attrs & xfRULER)
1026         new_pile->ruler = Eqn_inputRULER(eqn, src, src_index);
1027 
1028     new_pile->line_list = Eqn_GetObjectList(eqn, src, src_index, 0);
1029 
1030     return new_pile;
1031 }
1032 
1033 
Eqn_inputMATRIX(MTEquation * eqn,unsigned char * src,int * src_index)1034 static MT_MATRIX *Eqn_inputMATRIX(MTEquation * eqn, unsigned char *src,
1035                            int *src_index)
1036 {
1037     uint8_t attrs, i, bytes;
1038 
1039     MT_MATRIX *new_matrix = (MT_MATRIX *) malloc(sizeof(MT_MATRIX));
1040     new_matrix->nudge_x = 0;
1041     new_matrix->nudge_y = 0;
1042 
1043     *src_index += GetAttribute(eqn, src+*src_index, &attrs);
1044 
1045     if (attrs & xfLMOVE)
1046         *src_index += GetNudge(src + *src_index, &new_matrix->nudge_x, &new_matrix->nudge_y);
1047 
1048     new_matrix->valign = *(src + *src_index);
1049     (*src_index)++;
1050     new_matrix->h_just = *(src + *src_index);
1051     (*src_index)++;
1052     new_matrix->v_just = *(src + *src_index);
1053     (*src_index)++;
1054     new_matrix->rows = *(src + *src_index);
1055     (*src_index)++;
1056     new_matrix->cols = *(src + *src_index);
1057     (*src_index)++;
1058 
1059     /* row partition consists of (rows+1) two-bit values */
1060     bytes = (2 * (new_matrix->rows + 1) + 7) / 8;
1061     for (i=0; i<bytes; i++) {
1062         new_matrix->row_parts[i] = *(src + *src_index);
1063         (*src_index)++;
1064     }
1065 
1066     /* col partition consists of (cols+1) two-bit values */
1067     bytes = (2 * (new_matrix->cols + 1) + 7) / 8;
1068     for (i=0; i<bytes; i++) {
1069         new_matrix->col_parts[i] = *(src + *src_index);
1070         (*src_index)++;
1071     }
1072 
1073     new_matrix->element_list = Eqn_GetObjectList(eqn, src, src_index, 0);
1074 
1075     return new_matrix;
1076 }
1077 
Eqn_inputFONT(MTEquation * eqn,unsigned char * src,int * src_index)1078 static MT_FONT *Eqn_inputFONT(MTEquation * eqn, unsigned char *src,
1079                        int *src_index)
1080 {
1081     uint32_t zln;
1082     MT_FONT *new_font = (MT_FONT *) malloc(sizeof(MT_FONT));
1083 
1084     (*src_index)++;             /*  step over the tag */
1085 
1086     new_font->tface = *(src + *src_index);
1087     (*src_index)++;
1088     new_font->style = *(src + *src_index);
1089     (*src_index)++;
1090 
1091     zln = (uint32_t) strlen((char *) src + *src_index) + 1;
1092     new_font->zname = (char *) malloc(sizeof(char) * zln);
1093     strcpy((char *) new_font->zname, (char *) src + *src_index);
1094     *src_index += zln;
1095 
1096     return new_font;
1097 }
1098 
Eqn_inputSIZE(MTEquation * eqn,unsigned char * src,int * src_index)1099 static MT_SIZE *Eqn_inputSIZE(MTEquation * eqn, unsigned char *src,
1100                        int *src_index)
1101 {
1102     unsigned char tag, option;
1103     MT_SIZE *new_size = (MT_SIZE *) malloc(sizeof(MT_SIZE));
1104     new_size->dsize = 0;
1105 
1106     /* also works in MTEF5 because all supported tags are less than 16 */
1107     tag = *(src + *src_index) & 0x0F;
1108     (*src_index)++;
1109 
1110     /* FULL or SUB or SUB2 or SYM or SUBSYM */
1111     if (tag >= FULL && tag <= SUBSYM) {
1112 //    fprintf(stderr,"tag= %d\n",tag);
1113         new_size->type  = tag;
1114         new_size->lsize = tag - FULL;
1115         return new_size;
1116     }
1117 
1118     option = *(src + *src_index);
1119     (*src_index)++;
1120 
1121     /* large dsize */
1122     if (option == 100) {
1123         new_size->type = option;
1124         new_size->lsize = *(src + *src_index);
1125         (*src_index)++;
1126         new_size->dsize = *(src + *src_index);
1127         (*src_index)++;
1128         new_size->dsize += (*(src + *src_index) << 8);
1129         (*src_index)++;
1130         return new_size;
1131     }
1132 
1133     /* explicit point size */
1134     if (option == 101) {
1135         new_size->type = option;
1136         new_size->lsize = *(src + *src_index);
1137         (*src_index)++;
1138         new_size->lsize += (*(src + *src_index) << 8);
1139         (*src_index)++;
1140         return new_size;
1141     }
1142 
1143     /* -128 < dsize < 128 */
1144     new_size->type = 0;
1145     new_size->lsize = option;
1146     new_size->dsize = *(src + *src_index) - 128;
1147     (*src_index)++;
1148     return new_size;
1149 }
1150 
1151 
1152 /*
1153  * Convert MT equation into internal form
1154  * at each Eqn_inputXXX call, the src_index is set to the XXX tag
1155  * so that the hi nibble can be used to obtain the options in
1156  * versions 1-4 of MTEF
1157 */
Eqn_GetObjectList(MTEquation * eqn,unsigned char * src,int * src_index,int num_objs)1158 static MT_OBJLIST *Eqn_GetObjectList(MTEquation * eqn, unsigned char *src, int *src_index, int num_objs)
1159 {
1160     static int subroutine_depth = 0;
1161     unsigned char c, size, curr_tag;
1162     int i,id;
1163     int tally = 0;
1164     MT_OBJLIST *head = (MT_OBJLIST *) NULL;
1165     MT_OBJLIST *curr;
1166     void *new_obj;
1167 
1168     ++subroutine_depth;
1169     if (eqn->m_mtef_ver == 5)
1170         curr_tag = *(src + *src_index);
1171     else
1172         curr_tag = LoNibble(*(src + *src_index));
1173 
1174     while (curr_tag != 0xFF) {
1175 
1176         new_obj = (void *) NULL;
1177 
1178 if (DEBUG_PARSING || g_input_file_type==TYPE_EQN) {
1179         print_tag(curr_tag, *src_index);
1180         hexdump(src+*src_index, src+*src_index, 16, NULL);
1181 }
1182 
1183         switch (curr_tag) {
1184         case END:
1185             (*src_index)++;
1186             subroutine_depth--;
1187             return head;
1188             break;
1189 
1190         case LINE:
1191             new_obj = (void *) Eqn_inputLINE(eqn, src, src_index);
1192             break;
1193         case CHAR:
1194             new_obj = (void *) Eqn_inputCHAR(eqn, src, src_index);
1195             break;
1196         case TMPL:
1197             new_obj = (void *) Eqn_inputTMPL(eqn, src, src_index);
1198             break;
1199         case PILE:
1200             new_obj = (void *) Eqn_inputPILE(eqn, src, src_index);
1201             break;
1202         case MATRIX:
1203             new_obj = (void *) Eqn_inputMATRIX(eqn, src, src_index);
1204             break;
1205 
1206         case EMBELL:
1207             new_obj = (void *) Eqn_inputEMBELL(eqn, src, src_index);
1208             break;
1209 
1210         case RULER:
1211             new_obj = (void *) Eqn_inputRULER(eqn, src, src_index);
1212             break;
1213         case FONT:
1214             new_obj = (void *) Eqn_inputFONT(eqn, src, src_index);
1215             break;
1216 
1217         case SIZE:
1218         case FULL:
1219         case SUB:
1220         case SUB2:
1221         case SYM:
1222         case SUBSYM:
1223             new_obj = (void *) Eqn_inputSIZE(eqn, src, src_index);
1224             break;
1225 
1226         case COLOR_DEF:
1227             break;
1228 
1229         case FONT_DEF:
1230             (*src_index)++;
1231             id = *(src + *src_index);
1232             (*src_index)++;
1233             if (DEBUG_FONT) fprintf(stderr,"          ");
1234             while ((c = *(src + *src_index))) {
1235                 if (DEBUG_FONT) fprintf(stderr,"%c",c);
1236                 (*src_index)++;
1237             }
1238             if (DEBUG_FONT) fprintf(stderr," ==> %d\n",id);
1239             (*src_index)++;
1240             tally--;
1241             break;
1242 
1243         case EQN_PREFS:
1244             (*src_index)++;     /* skip tag */
1245             (*src_index)++;     /* options */
1246 
1247             size = *(src + *src_index); /* sizes[] */
1248             if (0) fprintf(stderr, " size array has %d entries\n", size);
1249             (*src_index)++;
1250             (*src_index) += SkipNibbles(src + *src_index, size);
1251 
1252             size = *(src + *src_index); /* spaces[] */
1253             (*src_index)++;
1254             (*src_index) += SkipNibbles(src + *src_index, size);
1255 
1256             size = *(src + *src_index); /* styles[] */
1257             (*src_index)++;
1258             if (0) fprintf(stderr, " style array has %d entries\n", size);
1259             for (i = 0; i < size; i++) {
1260                 c = *(src + *src_index);
1261                 (*src_index)++;
1262                 if (c) {
1263                    /* c = *(src + *src_index); */
1264                     (*src_index)++;
1265                 }
1266             }
1267             tally--;
1268             break;
1269 
1270         case ENCODING_DEF:
1271             (*src_index)++;     /* skip tag */
1272             while ((c = *(src + *src_index))) {
1273                 if (0) fprintf(stderr, "%c", c);
1274                 (*src_index)++;
1275             }
1276             if (0) fprintf(stderr, "\n");
1277             (*src_index)++;     /* skip NULL */
1278             tally--;
1279             break;
1280 
1281         default:
1282             (*src_index)++;     /* skip tag */
1283             size = *(src + *src_index);
1284             (*src_index)++;
1285             size |= *(src + *src_index) << 8;
1286 
1287             //Need to include a change to how the *src_index tag is incremented.
1288             //Although the MTEF v.5 documentation says otherwise, it appears the
1289             //index should be incremented by size-1, not size.
1290             (*src_index) += size;
1291 
1292             fprintf(stderr, "Future tag = 0x%02x with size %d\n",curr_tag,size);
1293             fprintf(stderr,"--> ignoring!\n");
1294             tally--;
1295             break;
1296         }
1297 
1298         if (new_obj) {
1299             MT_OBJLIST *new_node =
1300                 (MT_OBJLIST *) malloc(sizeof(MT_OBJLIST));
1301             new_node->next = NULL;
1302             new_node->tag = curr_tag;
1303             new_node->obj_ptr = new_obj;
1304 
1305             if (head)
1306                 curr->next = (void *) new_node;
1307             else
1308                 head = new_node;
1309             curr = new_node;
1310         }
1311 
1312         if (eqn->m_mtef_ver == 5)
1313             curr_tag = *(src + *src_index);
1314         else
1315             curr_tag = LoNibble(*(src + *src_index));
1316 
1317         tally++;
1318 
1319 //        fprintf(stderr,"depth=%d number of objects/total = %d/%d\n", subroutine_depth, tally, num_objs);
1320 
1321         if (tally == num_objs) {
1322     		subroutine_depth--;
1323             return head;
1324         }
1325 
1326     }                           /*  while loop thru MathType Objects */
1327 
1328     (*src_index)++;             /*  step over end byte */
1329 
1330     subroutine_depth--;
1331     return head;
1332 }
1333 
1334 static
Eqn_LoadCharSetAtts(MTEquation * eqn,char ** table)1335 void Eqn_LoadCharSetAtts(MTEquation * eqn, char **table)
1336 {
1337     char key[16];
1338     char buff[16];
1339     uint8_t slot = 1;
1340     uint32_t zln;
1341 
1342     eqn->atts_table = malloc(sizeof(MT_CHARSET_ATTS) * NUM_TYPEFACE_SLOTS);
1343 
1344     while (slot <= NUM_TYPEFACE_SLOTS) {
1345         snprintf(key, 16, "%d", (int) slot + 128);
1346         zln = GetProfileStr(table, key, buff, 16);
1347         if (zln) {
1348             eqn->atts_table[slot - 1].mathattr = buff[0] - '0';
1349             eqn->atts_table[slot - 1].do_lookup = buff[2] - '0';
1350             eqn->atts_table[slot - 1].use_codepoint = buff[4] - '0';
1351         } else {
1352             eqn->atts_table[slot - 1].mathattr = 1;
1353             eqn->atts_table[slot - 1].do_lookup = 0;
1354             eqn->atts_table[slot - 1].use_codepoint = 1;
1355         }
1356 
1357         slot++;
1358     }
1359 }
1360 
1361 /* parse the equation header and fill the fields of eqn */
Eqn_Create(MTEquation * eqn,unsigned char * eqn_stream,int eqn_size)1362 int Eqn_Create(MTEquation * eqn, unsigned char *eqn_stream, int eqn_size)
1363 {
1364     int src_index = 0;
1365 
1366     eqn->indent[0] = '%';
1367     eqn->indent[1] = 0;
1368     eqn->o_list = NULL;
1369     eqn->atts_table = NULL;
1370     eqn->m_mode = EQN_MODE_TEXT;
1371     eqn->m_inline = 0;
1372     eqn->m_latex_start = NULL;
1373     eqn->m_latex_end = NULL;
1374     eqn->m_latex = NULL;
1375     eqn->m_mtef_ver = 0;
1376 
1377 	if (g_input_file_type != TYPE_RAWEQN) {
1378     	eqn->m_mtef_ver = eqn_stream[0];
1379 		src_index++;
1380 	} else {
1381 		fprintf(stderr, "skipping 0x %02X %02X %02X %02X\n", eqn_stream[0], eqn_stream[1], eqn_stream[2], eqn_stream[3]);
1382 		src_index+=4;
1383 	}
1384 
1385     switch (eqn->m_mtef_ver) {
1386     case 0:
1387         eqn->m_mtef_ver = 5;
1388         eqn->m_product = 0;
1389         eqn->m_version = 0;
1390         eqn->m_version_sub = 0;
1391         break;
1392     case 1:
1393     case 101:
1394         eqn->m_platform = (eqn->m_mtef_ver == 101) ? 1 : 0;
1395         eqn->m_product = 0;
1396         eqn->m_version = 1;
1397         eqn->m_version_sub = 0;
1398         break;
1399 
1400     case 2:
1401     case 3:
1402     case 4:
1403         eqn->m_platform = eqn_stream[src_index++];
1404         eqn->m_product = eqn_stream[src_index++];
1405         eqn->m_version = eqn_stream[src_index++];
1406         eqn->m_version_sub = eqn_stream[src_index++];
1407         break;
1408 
1409     case 5:
1410         eqn->m_platform = eqn_stream[src_index++];
1411         eqn->m_product = eqn_stream[src_index++];
1412         eqn->m_version = eqn_stream[src_index++];
1413         eqn->m_version_sub = eqn_stream[src_index++];
1414 
1415         /* the application key is a null terminated string */
1416         while (eqn_stream[src_index]) {
1417 //            fprintf(stderr, "%d", eqn_stream[src_index]);
1418             src_index++;
1419             if (src_index == eqn_size) {
1420                 RTFMsg("The Application Key for the Equation is screwy!");
1421                 return (false);
1422             }
1423         }
1424         /*  fprintf(stderr, "\n"); */
1425         src_index++;
1426 
1427         eqn->m_inline = eqn_stream[src_index++];
1428         break;
1429 
1430     default:
1431         RTFMsg("* Unsupported MathType Equation Binary Format (MTEF=%d)\n",
1432                eqn->m_mtef_ver);
1433         return (false);
1434     }
1435 
1436     if (g_input_file_type==TYPE_EQN || DEBUG_EQUATION) {
1437         fprintf(stderr,"* MTEF ver = %d\n", eqn->m_mtef_ver);
1438         fprintf(stderr,"* Platform = %s\n", (eqn->m_platform == PLATFORM_WIN) ? "Win" : "Mac");
1439         fprintf(stderr,"* Product  = %s\n", (eqn->m_product) ? "MathType" : "EqnEditor");
1440         fprintf(stderr,"* Version  = %d.%d\n", eqn->m_version, eqn->m_version_sub);
1441         fprintf(stderr,"* Type     = %s (ignored because it is unreliable)\n", eqn->m_inline ? "inline" : "display");
1442     }
1443 
1444     eqn->m_atts_table = Profile_MT_CHARSET_ATTS;
1445     Eqn_LoadCharSetAtts(eqn, Profile_MT_CHARSET_ATTS);
1446     eqn->m_char_table = Profile_CHARTABLE;
1447 
1448     /*  We expect a SIZE then a LINE or PILE */
1449     eqn->o_list = Eqn_GetObjectList(eqn, eqn_stream, &src_index, 2);
1450 
1451     return (true);
1452 }
1453 
1454 /*  formatting routines.  convert internal form to LaTeX */
1455 
1456 
1457 
1458 static
Eqn_TranslateRULER(MTEquation * eqn,MT_RULER * ruler)1459 char *Eqn_TranslateRULER(MTEquation * eqn, MT_RULER * ruler)
1460 {
1461     char buf[128];
1462     EQ_STRREC strs[2];
1463     int num_strs = 0;
1464 
1465     if (eqn->log_level >= 2) {
1466         snprintf(buf, 128, "\n%sRULER\n", eqn->indent);
1467         SetComment(strs, 2, buf);
1468         num_strs++;
1469     }
1470 
1471     strcat(eqn->indent, "  ");
1472 
1473     /*  no translation implemented yet */
1474 
1475     eqn->indent[strlen(eqn->indent) - 2] = 0;
1476 
1477     return Eqn_JoinStrings(eqn, strs, num_strs);
1478 }
1479 
1480 static
Eqn_TranslateLINE(MTEquation * eqn,MT_LINE * line)1481 char *Eqn_TranslateLINE(MTEquation * eqn, MT_LINE * line)
1482 {
1483     char buf[128];
1484     char *thetex;
1485     EQ_STRREC strs[3];
1486 
1487     int num_strs = 0;
1488     if (eqn->log_level >= 2) {
1489         snprintf(buf, 128, "\n%sLINE\n", eqn->indent);
1490         SetComment(strs, 2, buf);
1491         num_strs++;
1492     }
1493 
1494     strcat(eqn->indent, "  ");
1495 
1496     if (line->ruler) {
1497 //    fprintf(stderr,"LINE---ruler\n");
1498         strs[num_strs].log_level = 0;
1499         strs[num_strs].do_delete = 1;
1500         strs[num_strs].ilk = Z_TEX;
1501         strs[num_strs].is_line = 0;
1502         strs[num_strs].data = Eqn_TranslateRULER(eqn, line->ruler);
1503         num_strs++;
1504     }
1505 
1506     if (line->object_list) {
1507 //    fprintf(stderr,"LINE---object list\n");
1508         strs[num_strs].log_level = 0;
1509         strs[num_strs].do_delete = 1;
1510         strs[num_strs].ilk = Z_TEX;
1511         strs[num_strs].is_line = 0;
1512         strs[num_strs].data = Eqn_TranslateObjects(eqn, line->object_list);
1513         num_strs++;
1514     }
1515 
1516     eqn->indent[strlen(eqn->indent) - 2] = 0;
1517 
1518     thetex = Eqn_JoinStrings(eqn, strs, num_strs);
1519 
1520     if (g_input_file_type==TYPE_EQN || DEBUG_LINE) fprintf(stderr,"LINE='%s'\n",thetex);
1521     return thetex;
1522 }
1523 
1524 /*  Character translation, MathType to TeX, using inifile data */
1525 
1526 static
Eqn_GetTexChar(MTEquation * eqn,EQ_STRREC * strs,MT_CHAR * thechar,int * math_attr)1527 int Eqn_GetTexChar(MTEquation * eqn, EQ_STRREC * strs, MT_CHAR * thechar, int *math_attr)
1528 {
1529     MT_CHARSET_ATTS set_atts;
1530     MT_EMBELL *embells;
1531     char buff[256];
1532     int num_strs = 0;
1533 
1534     char *ztex = (char *) NULL;
1535     char zch = 0;
1536     char *zdata = (char *) NULL;
1537 
1538     if (DEBUG_CHAR) fprintf(stderr,"in GetTeXChar seeking eqn->atts_table[%d]\n",(int) thechar->typeface - 129);
1539 
1540     strs[0].log_level = 0;
1541     strs[0].do_delete = 1;
1542     strs[0].ilk = Z_TEX;
1543     strs[0].is_line = 0;
1544     strs[0].data = NULL;
1545 
1546     if (thechar->typeface >= 129 && thechar->typeface < 129 + NUM_TYPEFACE_SLOTS) {
1547         set_atts = eqn->atts_table[thechar->typeface - 129];
1548     } else {                    /*  unexpected charset */
1549         char buffer[16];
1550         char key[16];
1551         uint32_t zln;
1552         snprintf(key, 16, "%d", (int) thechar->typeface);
1553         zln = GetProfileStr(eqn->m_atts_table, key, buffer, 16);
1554         if (zln) {
1555             set_atts.mathattr = buffer[0] - '0';
1556             set_atts.do_lookup = buffer[2] - '0';
1557             set_atts.use_codepoint = buffer[4] - '0';
1558         } else {
1559             set_atts.mathattr = 1;
1560             set_atts.do_lookup = 1;
1561             set_atts.use_codepoint = 1;
1562         }
1563     }
1564 
1565     *math_attr = set_atts.mathattr;
1566     if (set_atts.do_lookup) {
1567         uint32_t zln;
1568         char key[16];           /*  132.65m */
1569 
1570         snprintf(key, 16, "%d.%d", (int)thechar->typeface, (int)thechar->character);
1571         if (DEBUG_CHAR) fprintf(stderr, "looking up char in table[%d] as %d.%d\n",
1572         (int)thechar->typeface - 129, (int) thechar->typeface, (int) thechar->character);
1573 
1574         if (*math_attr == 3) {
1575             if (eqn->m_mode == EQN_MODE_TEXT)
1576                 strcat(key, "t");
1577             else
1578                 strcat(key, "m");
1579             *math_attr = 0;
1580         }
1581 
1582         zln = GetProfileStr(eqn->m_char_table, key, buff, 256);
1583         if (zln) {
1584             ztex = (char *) malloc(zln + 1);
1585             strcpy(ztex, buff);
1586         }
1587     }
1588 
1589     if (*math_attr == MA_FORCE_MATH && eqn->m_mode == EQN_MODE_TEXT) {
1590         setMathMode(eqn, eqn->m_inline ? EQN_MODE_INLINE : EQN_MODE_DISPLAY);
1591 
1592     } else if (*math_attr == MA_FORCE_TEXT) {
1593         setMathMode(eqn, EQN_MODE_TEXT);
1594 	}
1595     if (!ztex && set_atts.use_codepoint) {
1596         if (thechar->character >= 32 && thechar->character <= 127) {
1597             zch = (char) thechar->character;
1598             if (thechar->character == 38) {
1599                 snprintf(buff,20,"\\&");
1600                 ztex = (char *) malloc(strlen(buff) + 1);
1601                 strcpy(ztex, buff);
1602             }
1603             if (thechar->typeface == 135) {
1604                 snprintf(buff,20,"\\mathbf{%c}", zch);
1605                 ztex = (char *) malloc(strlen(buff) + 1);
1606                 strcpy(ztex, buff);
1607             }
1608         }
1609     }
1610 
1611     if (ztex) {
1612         zdata = ztex;
1613     } else if (zch) {
1614         zdata = (char *) malloc(2);
1615         zdata[0] = zch;
1616         zdata[1] = 0;
1617     }
1618 
1619     if (!zdata)
1620         return num_strs;
1621 
1622     embells = thechar->embellishment_list;
1623 
1624     while (embells) {
1625         char template[128];
1626         *template = '\0';
1627 
1628         /* template will in the form "math template,text template" */
1629         if (embells->embell>1 && embells->embell<37)
1630             strcpy(template, Template_EMBELLS[embells->embell]);
1631 
1632         if (DEBUG_EMBELLS || g_input_file_type==TYPE_EQN)
1633             fprintf(stderr,"Yikes --- Template_EMBELLS[%d]='%s'!\n", (int) embells->embell,template);
1634 
1635         if (strlen(template)) {     /*  only bother if there is a character */
1636             char *join, *t_ptr, *j_ptr;
1637 
1638             t_ptr = strchr(template, ',');
1639 
1640             if (!t_ptr) {
1641                 RTFPanic("Malformed EMBELL Template!\n");
1642                 exit(1);
1643             }
1644 
1645             /* set string to first or second half of template depending on mode */
1646             if (eqn->m_mode != EQN_MODE_TEXT) {
1647                 *t_ptr = '\0';
1648                 t_ptr = template;
1649             } else
1650                 t_ptr++;
1651 
1652             join = (char *) malloc(strlen(t_ptr) + strlen(zdata) + 16);
1653             j_ptr = join;
1654 
1655             if (DEBUG_EMBELLS || g_input_file_type==TYPE_EQN) fprintf(stderr,"Yikes --- replacement template is '%s'!\n",t_ptr);
1656 
1657             /* replace %1 in template with zdata */
1658             while (*t_ptr) {
1659                 if (*t_ptr == '%') {
1660                     t_ptr+=2;             /* skip over %1 */
1661                     strcpy(j_ptr, zdata);
1662                     j_ptr += strlen(zdata);
1663                 } else {
1664                     *j_ptr = *t_ptr;
1665                     j_ptr++;
1666                     t_ptr++;
1667                 }
1668             }
1669             *j_ptr = '\0';
1670             free(zdata);
1671             zdata = join;
1672         }
1673         if (DEBUG_EMBELLS || g_input_file_type==TYPE_EQN) fprintf(stderr,"Yikes --- after replacement strs[0].data is '%s'!\n",zdata);
1674 
1675         embells = (MT_EMBELL *) embells->next;
1676     }
1677 
1678     strs[0].data = zdata;
1679     num_strs++;
1680     return num_strs;
1681 }
1682 
1683 static
Eqn_TranslateCHAR(MTEquation * eqn,MT_CHAR * thechar)1684 char *Eqn_TranslateCHAR(MTEquation * eqn, MT_CHAR * thechar)
1685 {
1686     EQ_STRREC strs[4];
1687     int num_strs = 0;
1688     int math_attr;
1689 
1690     if (eqn->log_level >= 2) {
1691         char buf[128];
1692         snprintf(buf, 128, "\n%sCHAR : atts=%d,typeface=%d,char=%c,%d\n",
1693                 eqn->indent, (int)thechar->atts, (int)thechar->typeface,
1694                 (char) thechar->character, (int)thechar->character);
1695         SetComment(strs, 2, buf);
1696         num_strs++;
1697     }
1698     if (DEBUG_CHAR || g_input_file_type==TYPE_EQN)
1699         fprintf(stderr, "CHAR : atts=%d,typeface=%3d=%10s, char='%c' = 0x%04x = %d\n",
1700                 (int)thechar->atts, (int)thechar->typeface, typeFaceName[thechar->typeface-128],
1701                 (char) thechar->character, (unsigned int)thechar->character, (int)thechar->character);
1702 /*
1703     SetComment(strs + num_strs, 100, (char *) NULL);
1704     num_strs++;
1705 */
1706     strcat(eqn->indent, "  ");
1707 
1708     num_strs += Eqn_GetTexChar(eqn, strs + num_strs, thechar, &math_attr);
1709 
1710     eqn->indent[strlen(eqn->indent) - 2] = 0;
1711 
1712     return Eqn_JoinStrings(eqn, strs, num_strs);
1713 }
1714 
1715 
1716 static
Eqn_TranslateFUNCTION(MTEquation * eqn,MT_OBJLIST * curr_node,int * advance)1717 char *Eqn_TranslateFUNCTION(MTEquation * eqn, MT_OBJLIST * curr_node,
1718                             int *advance)
1719 {
1720     char nom[16];
1721     char tex_func[128];
1722     EQ_STRREC strs[4];
1723     int num_strs = 0;
1724     uint32_t zlen;
1725     char *zdata;
1726 
1727     /*  step through object list to gather the function name */
1728     *advance = 0;
1729     nom[*advance] = '\0';
1730     while (curr_node && curr_node->tag == CHAR) {
1731         MT_CHAR *charptr = (MT_CHAR *) curr_node->obj_ptr;
1732         if (!charptr || charptr->typeface != 130 || !isalpha((int) charptr->character))
1733             break;
1734 
1735         nom[*advance] = (char) charptr->character;
1736         curr_node = (MT_OBJLIST *) curr_node->next;
1737         (*advance)++;
1738     }
1739     nom[*advance] = '\0';
1740 
1741     if (*advance == 0) return NULL;
1742 
1743     if (g_input_file_type==TYPE_EQN || DEBUG_FUNCTION) fprintf(stderr,"FUNC : name = '%s'\n", nom);
1744 
1745     zlen = GetProfileStr(Profile_FUNCTIONS, nom, tex_func, 128);
1746 
1747     /* no function translation found, just emit these characters */
1748     if (!zlen || !tex_func[0])
1749         snprintf(tex_func,128,"\\mathrm{%s}", nom);
1750 
1751     if (eqn->log_level >= 2) {
1752         char buf[128];
1753         snprintf(buf, 128, "\n%sFUNCTION : %s\n", eqn->indent, nom);
1754         SetComment(strs, 2, buf);
1755         num_strs++;
1756     }
1757 
1758 /*  place_holder for $ if needed
1759     SetComment(strs + num_strs, 100, (char *) NULL);
1760     num_strs++;
1761 */
1762     strs[num_strs].log_level = 0;
1763     strs[num_strs].do_delete = 1;
1764     strs[num_strs].ilk = Z_TEX;
1765     strs[num_strs].is_line = 0;
1766     zdata = (char *) malloc(strlen(tex_func) + 1);
1767     strcpy(zdata, tex_func);
1768     strs[num_strs].data = zdata;
1769     num_strs++;
1770 
1771     return Eqn_JoinStrings(eqn, strs, num_strs);
1772 }
1773 
1774 
1775 static
Eqn_TranslateTEXTRUN(MTEquation * eqn,MT_OBJLIST * curr_node,int * advance)1776 char *Eqn_TranslateTEXTRUN(MTEquation * eqn, MT_OBJLIST * curr_node,
1777                            int *advance)
1778 {
1779     /*  Gather the tex run */
1780 
1781     int di = 0;
1782     char run[256];
1783     EQ_STRREC strs[4];
1784     int num_strs = 0;
1785     char tbuff[256];
1786     uint32_t zlen;
1787     char *zdata;
1788     char *ndl;
1789 
1790     *advance = 0;
1791 
1792     while (curr_node && (curr_node->tag == CHAR || curr_node->tag == SIZE)) {
1793         if (curr_node->tag == CHAR) {
1794             MT_CHAR *charptr = (MT_CHAR *) curr_node->obj_ptr;
1795             if (charptr && charptr->typeface == 129) {
1796                 run[di++] = (char) charptr->character;
1797                 curr_node = (MT_OBJLIST *) curr_node->next;
1798                 (*advance)++;
1799             } else
1800                 break;
1801         } else {
1802             curr_node = (MT_OBJLIST *) curr_node->next;
1803             (*advance)++;
1804         }
1805     }
1806     run[di] = 0;
1807 
1808     if (eqn->log_level >= 2) {
1809         char buf[256];
1810         snprintf(buf, 256, "\n%sTEXTRUN : %s\n", eqn->indent, run);
1811         SetComment(strs, 2, buf);
1812         num_strs++;
1813     }
1814 
1815     strs[num_strs].log_level = 0;
1816     strs[num_strs].do_delete = 1;
1817     strs[num_strs].ilk = Z_TEX;
1818     strs[num_strs].is_line = 0;
1819 
1820     zlen = GetProfileStr(Profile_TEMPLATES, "TextInMath", tbuff, 256);
1821     if (zlen <= 0)
1822         strcpy(tbuff, "\\text{#1}");
1823 
1824     zdata = malloc(di + zlen);
1825 
1826     ndl = strchr(tbuff, '#');
1827     if (ndl) {
1828         *ndl = 0;
1829         strcpy(zdata, tbuff);
1830     } else
1831         *zdata = 0;
1832     strcat(zdata, run);
1833     if (ndl) {
1834         ndl += 2;
1835         strcat(zdata, ndl);
1836     }
1837 
1838     strs[num_strs].data = zdata;
1839     num_strs++;
1840 
1841     return Eqn_JoinStrings(eqn, strs, num_strs);
1842 }
1843 
1844 #if 0
1845 /*  Line positions are stored in a 2-bit pieces in the bits
1846  *  array.  This extracts the right one and returns true if
1847  *  a dashed, dotted, or solid line is present.
1848  */
1849 static
1850 int HasHVLine(int line_num, unsigned char *bits)
1851 {
1852 
1853     int rv = 0;
1854     int byte_num = line_num / 4;
1855     int shift = (line_num % 4) * 2;
1856     int mask = 0x03 << shift;
1857 
1858     if (byte_num < MATR_MAX)
1859         rv = (bits[byte_num] & mask) ? 1 : 0;
1860 
1861     return rv;
1862 }
1863 #endif
1864 
1865 /*  The current implementation ignores the vertical and
1866  *  horizontal lines ... it is not clear if it makes any
1867  *  sense to use the tabular environment to include this
1868  *  feature
1869  */
1870 static
Eqn_TranslateMATRIX(MTEquation * eqn,MT_MATRIX * matrix)1871 char *Eqn_TranslateMATRIX(MTEquation * eqn, MT_MATRIX * matrix)
1872 {
1873     size_t buf_limit = 8192;
1874     char *thetex, *cell;
1875     char *col_align = "c";
1876     uint8_t j,col,row;
1877     MT_OBJLIST *obj_list;
1878 
1879     thetex = malloc(buf_limit);
1880     *thetex = 0;
1881 
1882     if (eqn->log_level >= 2) {
1883         char buf[128];
1884         snprintf(buf, 128, "\n%sStart MATRIX\n", eqn->indent);
1885         strcat(thetex, buf);
1886     }
1887 
1888     strcat(eqn->indent, "  ");
1889 
1890     strcat(thetex, "\n\\begin{array}");
1891 
1892     /*  set the vertical alignment of the matrix */
1893     if (matrix->valign == 0)
1894         strcat(thetex, "[t]");
1895     else if (matrix->valign == 2)
1896         strcat(thetex, "[b]");
1897 
1898     /*  set alignment for all columns */
1899     if (matrix->h_just == MT_LEFT)
1900         col_align = "l";
1901     else if (matrix->h_just == MT_RIGHT)
1902         col_align = "r";
1903 
1904     strcat(thetex, "{");
1905     for (col=0; col<matrix->cols; col++)
1906         strcat(thetex, col_align);
1907     strcat(thetex, "}\n");
1908 
1909     obj_list = matrix->element_list;
1910     for (row = 0; row < matrix->rows; row++) {
1911 
1912         if (row > 0)
1913             strcat(thetex, " \\\\\n");
1914 
1915         for (col=0; col<matrix->cols; col++) {
1916 
1917             if (col>0) strcat(thetex, " & ");
1918 
1919             while (obj_list && obj_list->tag != LINE)
1920                 obj_list = (MT_OBJLIST *) obj_list->next;
1921 
1922             /* no column element found ... finish the line and exit */
1923             if (!obj_list || obj_list->tag != LINE) {
1924                 for (j=col; j<matrix->cols; j++)
1925                     strcat(thetex, " & ");
1926                 break;
1927             }
1928 
1929             cell = Eqn_TranslateLINE(eqn, (MT_LINE *) obj_list->obj_ptr);
1930             strcat(thetex, cell);
1931             free(cell);
1932 
1933             obj_list = (MT_OBJLIST *) obj_list->next;
1934         }
1935     }                           /*  loop down rows */
1936 
1937     strcat(thetex, "\n\\end{array}\n");
1938 
1939     eqn->indent[strlen(eqn->indent) - 2] = 0;
1940 
1941     if (eqn->log_level >= 2) {
1942         char buf[128];
1943         snprintf(buf, 128, "\n%sEnd MATRIX\n", eqn->indent);
1944         strcat(thetex, buf);
1945     }
1946     return thetex;
1947 }
1948 
1949 static
Is_RelOp(MT_CHAR * charptr)1950 int Is_RelOp(MT_CHAR * charptr)
1951 {
1952 
1953     int rv = 0;
1954 
1955     if (charptr->typeface == 134) {
1956 
1957         if (charptr->character == 60 || charptr->character == 62
1958             || charptr->character == 163 || charptr->character == 179
1959             || charptr->character == 185 || charptr->character == 186
1960             || charptr->character == 187 || charptr->character == 64
1961             || charptr->character == 61 || charptr->character == 181)
1962             rv = 1;
1963 
1964     } else if (charptr->typeface == 139) {
1965         if (charptr->character == 112 || charptr->character == 102
1966             || charptr->character == 60 || charptr->character == 62)
1967             rv = 1;
1968     }
1969 
1970     return rv;
1971 }
1972 
1973 
1974 static
Eqn_TranslateEQNARRAY(MTEquation * eqn,MT_PILE * pile)1975 char *Eqn_TranslateEQNARRAY(MTEquation * eqn, MT_PILE * pile)
1976 {
1977 	char *rv;
1978     uint32_t buf_limit = 8192;
1979     MT_OBJLIST *obj_list;
1980     int curr_row = 0;
1981     int right_only = 0;
1982     char *data;
1983     uint32_t b_off;
1984 
1985     rv = malloc(buf_limit);
1986     *rv = 0;
1987 
1988     if (eqn->log_level >= 2) {
1989         char buf[128];
1990         snprintf(buf, 128, "\n%sStart EQNARRAY\n", eqn->indent);
1991         strcat(rv, buf);
1992     }
1993 
1994     strcat(eqn->indent, "  ");
1995 
1996 	setMathMode(eqn, EQN_MODE_EQNARRAY);
1997 
1998     obj_list = pile->line_list;
1999 
2000     while (obj_list) {          /*   loop down lines */
2001 
2002         if (curr_row)
2003             strcat(rv, " \\\\\n");
2004 
2005         while (obj_list && obj_list->tag != LINE) {     /*  could be a SIZE */
2006             obj_list = (MT_OBJLIST *) obj_list->next;
2007         }
2008 
2009         if (obj_list && obj_list->tag == LINE) {
2010 
2011 /*  locate the "relop" in the object_list of the current line */
2012 
2013             MT_OBJLIST *left_node = (MT_OBJLIST *) NULL;
2014             MT_OBJLIST *right_node = (MT_OBJLIST *) NULL;
2015 
2016             MT_LINE *line = (MT_LINE *) obj_list->obj_ptr;
2017             MT_OBJLIST *curr_node = line->object_list;
2018             while (curr_node) {
2019                 if (curr_node->tag == CHAR) {   /*  check for a relop */
2020                     if (Is_RelOp((MT_CHAR *) curr_node->obj_ptr))
2021                         break;
2022                 }
2023                 left_node = curr_node;
2024                 curr_node = (MT_OBJLIST *) curr_node->next;
2025             }
2026 
2027 /*  handle left side */
2028 
2029             if (left_node) {
2030                 if (curr_node) {
2031                     left_node->next = NULL;
2032                     data = Eqn_TranslateLINE(eqn, (MT_LINE *) obj_list->obj_ptr);
2033 
2034                     b_off = (uint32_t) strlen(rv);
2035                     rv = ToBuffer(data, rv, &b_off, &buf_limit);        /*  strcat( rv,data ); */
2036 
2037                     left_node->next = (void *) curr_node;
2038                 } else {
2039                     right_node = left_node;
2040                     right_only = 1;
2041                 }
2042             }
2043             strcat(rv, " & ");
2044 
2045 /*  handle the relop */
2046 
2047             if (curr_node) {
2048                 char *data2 = Eqn_TranslateCHAR(eqn, (MT_CHAR *) curr_node->obj_ptr);
2049                 strcat(rv, data2);
2050                 free(data2);
2051                 right_node = (MT_OBJLIST *) curr_node->next;
2052             }
2053             strcat(rv, " & ");
2054 
2055 /*  handle right side */
2056 
2057             if (right_node) {
2058                 char *data2;
2059                 if (right_only)
2060                     data2 = Eqn_TranslateLINE(eqn, (MT_LINE *) obj_list->obj_ptr);
2061                 else
2062                     data2 = Eqn_TranslateObjects(eqn, right_node);
2063 
2064                 b_off = (uint32_t) strlen(rv);
2065                 rv = ToBuffer(data2, rv, &b_off, &buf_limit);    /*  strcat( rv,data ); */
2066             }
2067 
2068             obj_list = (MT_OBJLIST *) obj_list->next;
2069         } else
2070             break;
2071 
2072         curr_row++;
2073     }                           /*  loop down thru lines */
2074 
2075     eqn->indent[strlen(eqn->indent) - 2] = 0;
2076 
2077     if (eqn->log_level >= 2) {
2078         char buf[128];
2079         snprintf(buf, 128, "%sEnd EQNARRAY\n", eqn->indent);
2080         strcat(rv, buf);
2081     }
2082 
2083     return rv;
2084 }
2085 
2086 
2087 static
Eqn_TranslateTABULAR(MTEquation * eqn,MT_PILE * pile)2088 char *Eqn_TranslateTABULAR(MTEquation * eqn, MT_PILE * pile)
2089 {
2090     MT_OBJLIST *obj_list;
2091     size_t buf_limit = 8192;
2092     uint8_t row;
2093     uint32_t head_len;
2094     char *thetex, *line;
2095 
2096     thetex = (char *) malloc(buf_limit);
2097 
2098     /* fprintf(stderr, "PILE : Translating Tabular PILE\n"); */
2099     *thetex = '\0';
2100 
2101     if (eqn->log_level >= 2) {
2102         char buf[128];
2103         snprintf(buf, 128, "\n%sStart TABULAR\n", eqn->indent);
2104         strcat(thetex, buf);
2105     }
2106 
2107     strcat(eqn->indent, "  ");
2108 
2109     strcat(thetex, "\n\\begin{array}");
2110 
2111     switch (pile->valign) {
2112         case PVA_TOP:
2113             strcat(thetex, "[t]");
2114             break;
2115         case PVA_BOTTOM:
2116             strcat(thetex, "[b]");
2117             break;
2118         case PVA_CENTER:
2119         case PVA_CENTERING:
2120         case PVA_MATH:
2121             break;
2122     }
2123 
2124     switch (pile->halign) {
2125         case MT_PILE_LEFT:
2126             strcat(thetex, "{l}\n");
2127             break;
2128         case MT_PILE_RIGHT:
2129             strcat(thetex, "{r}\n");
2130             break;
2131         case MT_PILE_CENTER:
2132         case MT_PILE_OPERATOR:
2133         case MT_PILE_DECIMAL:
2134             strcat(thetex, "{r}\n");
2135             break;
2136     }
2137 
2138     head_len = (uint32_t) strlen(thetex);
2139 
2140     row = 1;
2141     for (obj_list = pile->line_list; obj_list != NULL; obj_list = (MT_OBJLIST *)obj_list->next) {
2142 
2143         if (obj_list->tag != LINE)
2144             continue;
2145 
2146         line = Eqn_TranslateLINE(eqn, (MT_LINE *) obj_list->obj_ptr);
2147 
2148         if (strlen(line)>0) {
2149             if (row > 1) strcat(thetex, " \\\\\n");  /*  end previous row */
2150             strcat(thetex, line);
2151             row++;
2152         }
2153         free(line);
2154     }
2155 
2156     if (row==2 && strlen(thetex) > head_len)
2157         strcat(thetex, "\n");
2158     strcat(thetex, "\\end{array}\n");
2159 
2160     eqn->indent[strlen(eqn->indent) - 2] = 0;
2161 
2162     if (eqn->log_level >= 2) {
2163         char buf[128];
2164         snprintf(buf, 128, "\n%sEnd TABULAR\n", eqn->indent);
2165         strcat(thetex, buf);
2166     }
2167 
2168     return thetex;
2169 }
2170 
2171 
2172 static
Eqn_TranslatePILEtoTARGET(MTEquation * eqn,MT_PILE * pile,char * targ_nom)2173 char *Eqn_TranslatePILEtoTARGET(MTEquation * eqn, MT_PILE * pile, char *targ_nom)
2174 {
2175     MT_OBJLIST *obj_list;
2176     char ini_line[256];
2177     uint32_t dlen = 0;
2178     /*int forces_math = 1;*/
2179     /*int forces_text = 0;*/
2180     char *head = "";
2181     char *line_sep = " \\\\ ";
2182     char *tail = "";
2183     uint32_t buf_limit = 8192;
2184     int curr_row = 0;
2185 
2186     char *rv = (char *) malloc(buf_limit);
2187     *rv = 0;
2188 
2189     if (targ_nom && *targ_nom)
2190         dlen = GetProfileStr(Profile_PILEtranslation, targ_nom, ini_line, 256);
2191 
2192     /*   ini_line  =  "TextOnly,\begin{env}, \\,\end{env}" */
2193 
2194     if (dlen) {
2195         char *rover = ini_line;
2196         if (*rover == 'T') {
2197            /* forces_math = 0; */
2198            /* forces_text = 1; */
2199         }
2200         rover = strchr(rover, ',');     /*  end math/text force flag */
2201         if (rover && *(rover + 1)) {
2202             rover++;            /*  start of head */
2203             if (*rover != ',')
2204                 head = rover;
2205             rover = strchr(rover, ','); /*  end of head */
2206             if (rover) {
2207                 *rover = 0;
2208                 rover++;        /*  start of line_sep */
2209                 if (*rover && *(rover + 1)) {
2210                     if (*rover != ',')
2211                         line_sep = rover;
2212                     rover = strchr(rover, ','); /*  end of line_sep */
2213                     if (rover) {
2214                         *rover = 0;
2215                         rover++;        /*  start of tail */
2216                         if (*rover)
2217                             if (*rover != ',')
2218                                 tail = rover;
2219                     }
2220                 }
2221             }
2222         }
2223     }
2224 
2225     if (eqn->log_level >= 2) {
2226         char buf[128];
2227         snprintf(buf, 128, "\n%sStart PILE in TMPL field\n", eqn->indent);
2228         strcat(rv, buf);
2229     }
2230 
2231     strcat(eqn->indent, "  ");
2232 
2233     strcat(rv, "\n");
2234     strcat(rv, head);
2235     strcat(rv, "\n");
2236 
2237     obj_list = pile->line_list;
2238 
2239     while (obj_list) {          /*   loop down thru lines */
2240 
2241         if (curr_row) {
2242             strcat(rv, line_sep);
2243             strcat(rv, "\n");
2244         }
2245 
2246         while (obj_list && obj_list->tag != LINE) {     /*  could be a SIZE */
2247             obj_list = (MT_OBJLIST *) obj_list->next;
2248         }
2249 
2250         if (obj_list && obj_list->tag == LINE) {
2251             char *data = Eqn_TranslateLINE(eqn, (MT_LINE *) obj_list->obj_ptr);
2252 
2253             uint32_t b_off = (uint32_t) strlen(rv);
2254             rv = ToBuffer(data, rv, &b_off, &buf_limit);
2255 
2256             obj_list = (MT_OBJLIST *) obj_list->next;
2257         } else
2258             break;
2259 
2260         curr_row++;
2261     }                           /*  loop down thru lines */
2262 
2263     /*  put "\n\\end{array*}\n" */
2264 
2265     strcat(rv, "\n");
2266     strcat(rv, tail);
2267     strcat(rv, "\n");
2268 
2269     eqn->indent[strlen(eqn->indent) - 2] = 0;
2270 
2271     if (eqn->log_level >= 2) {
2272         char buf[128];
2273         snprintf(buf, 128, "\n%sEnd PILE in TMPL field\n", eqn->indent);
2274         strcat(rv, buf);
2275     }
2276 
2277     return rv;
2278 }
2279 
2280 
2281 static
Eqn_TranslateSIZE(MTEquation * eqn,MT_SIZE * size)2282 char *Eqn_TranslateSIZE(MTEquation * eqn, MT_SIZE * size)
2283 {
2284 
2285     EQ_STRREC strs[2];
2286 
2287     int num_strs = 0;
2288     if (eqn->log_level >= 2) {
2289         char buf[128];
2290         snprintf(buf, 128, "\n%sSIZE\n", eqn->indent);
2291         SetComment(strs, 2, buf);
2292         num_strs++;
2293     }
2294     if (DEBUG_SIZE) fprintf(stderr, "\n%sSIZE type=%d, lsize=%d, dsize=%d\n", eqn->indent, size->type, size->lsize, size->dsize);
2295 
2296     strcat(eqn->indent, "  ");
2297 
2298     /*  not translation implemented yet */
2299 
2300     eqn->indent[strlen(eqn->indent) - 2] = 0;
2301 
2302     return Eqn_JoinStrings(eqn, strs, num_strs);
2303 }
2304 
2305 
2306 static
Eqn_TranslateFONT(MTEquation * eqn,MT_FONT * font)2307 char *Eqn_TranslateFONT(MTEquation * eqn, MT_FONT * font)
2308 {
2309 
2310     EQ_STRREC strs[2];
2311     int num_strs = 0;
2312 
2313     if (eqn->log_level >= 2) {
2314         char buf[128];
2315         snprintf(buf, 128,"\n%sFONT\n", eqn->indent);
2316         SetComment(strs, 2, buf);
2317         num_strs++;
2318     }
2319 
2320     strcat(eqn->indent, "  ");
2321 
2322     /*  no translation implemented yet */
2323 
2324     eqn->indent[strlen(eqn->indent) - 2] = 0;
2325 
2326     return Eqn_JoinStrings(eqn, strs, num_strs);
2327 }
2328 
2329 static
GetPileType(char * the_template,int arg_num,char * targ_nom)2330 void GetPileType(char *the_template, int arg_num, char *targ_nom)
2331 {
2332     int di = 0;
2333     char *ptr;
2334     char tok[4];
2335     snprintf(tok, 4, "#%d", arg_num);       /* #2 */
2336 
2337     ptr = strstr(the_template, tok);
2338     if (ptr && *(ptr + 2) == '[') {
2339         ptr += 3;
2340         while (*ptr != ']' && di < 32)
2341             targ_nom[di++] = *ptr++;
2342     }
2343 
2344     targ_nom[di] = 0;
2345 }
2346 
2347 
2348 static
Eqn_GetTmplStr(MTEquation * eqn,uint8_t selector,uint16_t variation,EQ_STRREC * strs)2349 int Eqn_GetTmplStr(MTEquation * eqn, uint8_t selector, uint16_t variation, EQ_STRREC * strs)
2350 {
2351     char key[16];                /*  key = "20.1" */
2352     char ini_line[256];
2353     char *tmpl_ptr;
2354     int result;
2355     int num_strs = 0;           /*  this becomes the return value */
2356 
2357     snprintf(key, 16, "%d.%d", (int)selector, (int)variation);
2358 
2359     if (eqn->m_mtef_ver==5)
2360         result = GetProfileStr(Profile_TEMPLATES_5, key, ini_line, 256);
2361     else
2362         result = GetProfileStr(Profile_TEMPLATES, key, ini_line, 256);
2363 
2364 	if (!result) {
2365 	    fprintf(stderr, "TMPL key='%s' not found in version %d Profile_TEMPLATE\n",key,eqn->m_mtef_ver);
2366         exit(1);
2367 	}
2368 
2369 //	fprintf(stderr,"ini_line='%s'\n", ini_line);
2370     tmpl_ptr = strchr(ini_line, ',');
2371 
2372     if (eqn->log_level >= 2) {
2373         char buf[512];
2374         snprintf(buf, 512, "\n%sTMPL : %s=!%s!\n", eqn->indent, key, ini_line);
2375         SetComment(strs, 2, buf);
2376         num_strs++;
2377     }
2378     if (0) fprintf(stderr, "\n%sTMPL : %s=!%s!\n", eqn->indent, key, ini_line);
2379 
2380     if (tmpl_ptr)
2381         *tmpl_ptr++ = 0;
2382 
2383     if (tmpl_ptr && *tmpl_ptr) {
2384         char *ztmpl;
2385         strs[num_strs].log_level = 0;
2386         strs[num_strs].do_delete = 1;
2387         strs[num_strs].ilk = Z_TMPL;
2388         strs[num_strs].is_line = 0;
2389         ztmpl = (char *) malloc(strlen(tmpl_ptr) + 1);
2390         strcpy(ztmpl, tmpl_ptr);
2391         strs[num_strs].data = ztmpl;
2392         num_strs++;
2393     }
2394 
2395     return num_strs;
2396 }
2397 
2398 
2399 static
Eqn_TranslateTMPL(MTEquation * eqn,MT_TMPL * tmpl)2400 char *Eqn_TranslateTMPL(MTEquation * eqn, MT_TMPL * tmpl)
2401 {
2402     EQ_STRREC strs[10];
2403     char *the_template;
2404     int tally = 1;
2405     int num_strs;
2406     MT_OBJLIST *obj_list;
2407 
2408     if (eqn->m_mode == EQN_MODE_TEXT)
2409         setMathMode(eqn, eqn->m_inline ? EQN_MODE_INLINE : EQN_MODE_DISPLAY);
2410 
2411     if (eqn->m_mtef_ver == 5 && (tmpl->selector != 9))
2412         tmpl->variation &= 0x000f;
2413 
2414     if (DEBUG_TEMPLATE || g_input_file_type==TYPE_EQN)
2415         fprintf(stderr, "TMPL : selector = %d, variation=0x%04x (%d.%d)\n",
2416                (int) tmpl->selector, (unsigned int) tmpl->variation, (int) tmpl->selector, (int) tmpl->variation);
2417 
2418     num_strs = Eqn_GetTmplStr(eqn, tmpl->selector, tmpl->variation, strs);
2419 
2420     the_template = strs[num_strs - 1].data;
2421 
2422     if (DEBUG_TEMPLATE || g_input_file_type==TYPE_EQN)
2423     	fprintf(stderr,"TMPL : num_strs=%d, strs[%d].data='%s'\n",num_strs,num_strs-1,the_template);
2424 
2425     strcat(eqn->indent, "  ");
2426 
2427     obj_list = tmpl->subobject_list;
2428 
2429     if (obj_list && obj_list->tag == CHAR) {
2430 
2431 /*    translateCHAR( (MT_CHAR*)obj_list->obj_ptr ); */
2432 
2433         obj_list = (MT_OBJLIST *) obj_list->next;
2434     }
2435 
2436     if (obj_list && obj_list->tag >= SIZE && obj_list->tag <= SUBSYM) {
2437 
2438         obj_list = (MT_OBJLIST *) obj_list->next;
2439     }
2440 
2441     while (obj_list) {
2442         if (obj_list->tag == LINE) {
2443             if (DEBUG_TEMPLATE || g_input_file_type==TYPE_EQN) fprintf(stderr,"TMPL : LINE object\n");
2444             strs[num_strs].log_level = 0;
2445             strs[num_strs].do_delete = 1;
2446             strs[num_strs].ilk = Z_TEX;
2447             strs[num_strs].is_line = 1;
2448             strs[num_strs].data = Eqn_TranslateLINE(eqn, (MT_LINE *) obj_list->obj_ptr);
2449             if (DEBUG_TEMPLATE || g_input_file_type==TYPE_EQN) fprintf(stderr,"TMPL : strs[%d].data='%s'\n",num_strs,strs[num_strs].data);
2450             num_strs++;
2451             tally++;
2452         } else if (obj_list->tag == PILE) {     /*  This one is DIFFICULT!! */
2453             char targ_nom[32];
2454             if (DEBUG_TEMPLATE || g_input_file_type==TYPE_EQN) fprintf(stderr,"TMPL : PILE object, targ_nom=%s\n",targ_nom);
2455             strs[num_strs].log_level = 0;
2456             strs[num_strs].do_delete = 1;
2457             strs[num_strs].ilk = Z_TEX;
2458             strs[num_strs].is_line = 2;
2459 
2460             GetPileType(the_template, tally, targ_nom);
2461 
2462             strs[num_strs].data = Eqn_TranslatePILEtoTARGET(eqn, (MT_PILE *) obj_list-> obj_ptr, targ_nom);
2463             if (DEBUG_TEMPLATE || g_input_file_type==TYPE_EQN) fprintf(stderr,"PILE : strs[%d].data='%s'\n",num_strs,strs[num_strs].data);
2464 
2465             num_strs++;
2466             tally++;
2467         }
2468 
2469         obj_list = (MT_OBJLIST *) obj_list->next;
2470     }
2471 
2472     /* There may be a SIZE at the end of the list */
2473 
2474     eqn->indent[strlen(eqn->indent) - 2] = 0;
2475 
2476     return Eqn_JoinStrings(eqn, strs, num_strs);
2477 }
2478 
2479 
2480 static
Eqn_TranslatePILE(MTEquation * eqn,MT_PILE * pile)2481 char *Eqn_TranslatePILE(MTEquation * eqn, MT_PILE * pile)
2482 {
2483     EQ_STRREC strs[2];
2484     int num_strs = 0;
2485 
2486 /*  fprintf(stderr, "PILE : Translating PILE\n"); */
2487 
2488     if (eqn->log_level >= 2) {
2489         char buf[128];
2490         snprintf(buf, 128, "\n%sPILE\n", eqn->indent);
2491         SetComment(strs, 2, buf);
2492         num_strs++;
2493     }
2494 
2495     strcat(eqn->indent, "  ");
2496 
2497     strs[num_strs].log_level = 0;
2498     strs[num_strs].do_delete = 1;
2499     strs[num_strs].ilk = Z_TEX;
2500     strs[num_strs].is_line = 0;
2501 
2502     setMathMode(eqn, EQN_MODE_DISPLAY);
2503 
2504     if (pile->halign == MT_PILE_OPERATOR)
2505         strs[num_strs].data = Eqn_TranslateEQNARRAY(eqn, pile);
2506     else
2507         strs[num_strs].data = Eqn_TranslateTABULAR(eqn, pile);
2508     num_strs++;
2509 
2510     eqn->indent[strlen(eqn->indent) - 2] = 0;
2511 
2512     return Eqn_JoinStrings(eqn, strs, num_strs);
2513 }
2514 
2515 static
Eqn_TranslateObjects(MTEquation * eqn,MT_OBJLIST * the_list)2516 char *Eqn_TranslateObjects(MTEquation * eqn, MT_OBJLIST * the_list)
2517 {
2518 
2519     char *zcurr;
2520     char *rv = (char *) malloc(1024);
2521     uint32_t di = 0;
2522     uint32_t lim = 1024;
2523 
2524     MT_OBJLIST *curr_node;
2525     *rv = 0;
2526 
2527     if (DEBUG_TRANSLATION || g_input_file_type==TYPE_EQN) fprintf(stderr,"new object list\n");
2528     while (the_list) {
2529 
2530         curr_node = the_list;
2531         the_list = (void *) the_list->next;
2532 
2533         zcurr = (char *) NULL;
2534 
2535         if (DEBUG_TRANSLATION || g_input_file_type==TYPE_EQN) print_tag(curr_node->tag, 0);
2536 
2537         switch (curr_node->tag) {
2538 
2539         case LINE:{
2540                 MT_LINE *line = (MT_LINE *) curr_node->obj_ptr;
2541                 if (line)
2542                     zcurr = Eqn_TranslateLINE(eqn, line);
2543             }
2544             break;
2545 
2546         case CHAR:{
2547                 int advance = 0;
2548                 MT_CHAR *charptr = (MT_CHAR *) curr_node->obj_ptr;
2549                 if (!charptr) break;
2550 
2551                 if (charptr->typeface == 130) {     /*  auto_recognize functions */
2552                     zcurr = Eqn_TranslateFUNCTION(eqn, curr_node, &advance);
2553                     while (advance > 1) {
2554                         the_list = (MT_OBJLIST *) the_list->next;
2555                         advance--;
2556                     }
2557                 } else if (charptr->typeface == 129 && eqn->m_mode != EQN_MODE_TEXT) {    /*  text in math */
2558                     zcurr = Eqn_TranslateTEXTRUN(eqn, curr_node, &advance);
2559                     while (advance > 1) {
2560                         the_list = (MT_OBJLIST *) the_list->next;
2561                         advance--;
2562                     }
2563                 }
2564                 if (!advance)
2565                     zcurr = Eqn_TranslateCHAR(eqn, charptr);
2566             }
2567             break;
2568 
2569         case TMPL:{
2570                 MT_TMPL *tmpl = (MT_TMPL *) curr_node->obj_ptr;
2571                 if (tmpl)
2572                     zcurr = Eqn_TranslateTMPL(eqn, tmpl);
2573             }
2574             break;
2575 
2576         case PILE:{
2577                 MT_PILE *pile = (MT_PILE *) curr_node->obj_ptr;
2578                 if (pile)
2579                     zcurr = Eqn_TranslatePILE(eqn, pile);
2580             }
2581             break;
2582 
2583         case MATRIX:{
2584                 MT_MATRIX *matrix = (MT_MATRIX *) curr_node->obj_ptr;
2585                 if (matrix)
2586                     zcurr = Eqn_TranslateMATRIX(eqn, matrix);
2587             }
2588             break;
2589 
2590         case EMBELL:
2591             break;
2592 
2593         case RULER:{
2594                 MT_RULER *ruler = (MT_RULER *) curr_node->obj_ptr;
2595                 if (ruler)
2596                     zcurr = Eqn_TranslateRULER(eqn, ruler);
2597             }
2598             break;
2599 
2600         case FONT:{
2601                 MT_FONT *font = (MT_FONT *) curr_node->obj_ptr;
2602                 if (font)
2603                     zcurr = Eqn_TranslateFONT(eqn, font);
2604             }
2605             break;
2606 
2607         case SIZE:
2608         case FULL:
2609         case SUB:
2610         case SUB2:
2611         case SYM:
2612         case SUBSYM:{
2613                 MT_SIZE *size = (MT_SIZE *) curr_node->obj_ptr;
2614                 if (size)
2615                     zcurr = Eqn_TranslateSIZE(eqn, size);
2616             }
2617             break;
2618 
2619         default:
2620             break;
2621         }
2622 
2623         if (zcurr)
2624             rv = ToBuffer(zcurr, rv, &di, &lim);
2625 
2626     }                           /*   while ( the_list ) */
2627 
2628     return rv;
2629 }
2630 
Eqn_TranslateObjectList(MTEquation * eqn,FILE * outfile,int loglevel)2631 void Eqn_TranslateObjectList(MTEquation * eqn, FILE * outfile,
2632                              int loglevel)
2633 {
2634     char *ztex;
2635 
2636     eqn->out_file = outfile;
2637     eqn->log_level = loglevel;
2638 
2639     if (eqn->log_level == 2)
2640         fputs("%Begin Equation\n", eqn->out_file);
2641 
2642     if (DEBUG_TRANSLATION || g_input_file_type==TYPE_EQN) fprintf(stderr,"new equation\n");
2643 
2644     ztex = Eqn_TranslateObjects(eqn, eqn->o_list);
2645 
2646 	if (eqn->m_latex_start && ztex && *ztex) {
2647 		eqn->m_latex = ztex;
2648 		if (!eqn->m_latex_end) setMathMode(eqn, EQN_MODE_TEXT);
2649 		return;
2650 	}
2651 
2652 	if (eqn->m_latex_start) free(eqn->m_latex_start);
2653 	eqn->m_latex_start = NULL;
2654 	if (eqn->m_latex) free(eqn->m_latex);
2655 	eqn->m_latex = NULL;
2656 	if (eqn->m_latex_end) free(eqn->m_latex_end);
2657 	eqn->m_latex_end = NULL;
2658 }
2659 
2660 /* [FUNCTIONS] */
2661 char *Profile_FUNCTIONS[] = {
2662     "Pr=\\Pr ",
2663     "arccos=\\arccos ",
2664     "arcsin=\\arcsin ",
2665     "arctan=\\arctan ",
2666     "arg=\\arg ",
2667     "cos=\\cos ",
2668     "cosh=\\cosh ",
2669     "cot=\\cot ",
2670     "coth=\\coth ",
2671     "csc=\\csc ",
2672     "deg=\\deg ",
2673     "det=\\det ",
2674     "dim=\\dim ",
2675     "exp=\\exp ",
2676     "gcd=\\gcd ",
2677     "hom=\\hom ",
2678     "inf=\\inf ",
2679     "ker=\\ker ",
2680     "lim=\\lim ",
2681     "liminf=\\liminf ",
2682     "limsup=\\limsup ",
2683     "ln=\\ln ",
2684     "log=\\log ",
2685     "max=\\max ",
2686     "min=\\min ",
2687     "sec=\\sec ",
2688     "sin=\\sin ",
2689     "sinh=\\sinh ",
2690     "sup=\\sup ",
2691     "tan=\\tan ",
2692     "tanh=\\tanh ",
2693     "mod=\\mathop{\\rm mod} ",
2694     "glb=\\mathop{\\rm glb} ",
2695     "lub=\\mathop{\\rm lub} ",
2696     "int=\\mathop{\\rm int} ",
2697     "Im=\\mathop{\\rm Im} ",
2698     "Re=\\mathop{\\rm Re} ",
2699     "var=\\mathop{\\rm var} ",
2700     "cov=\\mathop{\\rm cov} ",
2701     0
2702 };
2703 
2704 /* [VARIABLES] */
2705 /* VARIABLE_NAME,MATH_VERSION,TEXT_VERSION */
2706 char *Profile_VARIABLES[] = {
2707     "STARTSUB=_{,\\Sb ",
2708     "ENDSUB=}, \\endSb ",
2709     "STARTSUP=^{,\\Sp ",
2710     "ENDSUP=}, \\endSp ",
2711     0
2712 };
2713 
2714 /* [PILEtranslation] */
2715 char *Profile_PILEtranslation[] = {
2716     "MATHDEFAULT=MathForce,\\begin{array}{l}, \\\\,\\end{array}",
2717     "TEXTDEFAULT=TextOnly,\\begin{tabular}{l}, \\\\,\\end{tabular}",
2718     "L=,, \\ ,",
2719     "M=MathForce,\\begin{array}{l}, \\\\,\\end{array}",
2720     "X=TextForce,\\begin{texttest}, \\\\LINE_END,\\end{texttest}",
2721     "Y=MathForce,\\begin{mathtest}, \\\\LINE_END,\\end{mathtest}",
2722     0
2723 };
2724 
2725 
2726 /* typeface=attributes,do_lookup,use_codepoint */
2727 /* attributes --> 0=MA_NONE, 1=MA_FORCE_MATH, 2=MA_FORCE_TEXT, 3=2 translations */
2728 char *Profile_MT_CHARSET_ATTS[] = {
2729     "129=2,0,1", /* TEXT     */
2730     "130=1,1,1", /* FUNCTION */
2731     "131=1,0,1", /* VARIABLE */
2732     "132=1,1,0", /* LCGREEK  */
2733     "133=1,1,0", /* UCGREEK  */
2734     "134=1,1,1", /* SYMBOL   */
2735     "135=1,0,1", /* VECTOR   */
2736     "136=1,0,1", /* NUMBER   */
2737     "137=1,1,0",
2738     "138=1,1,0",
2739     "139=1,1,1", /* MTEXTRA */
2740     "140=1,1,0",
2741     "141=1,1,0",
2742     "142=1,1,0",
2743     "143=1,1,0",
2744     "144=1,1,0",
2745     "145=1,1,0",
2746     "146=1,1,0",
2747     "147=1,1,0",
2748     "148=1,1,0",
2749     "149=1,1,0",
2750     "150=1,1,0", /* EXPAND */
2751     "151=1,1,0", /* MARKER */
2752     "152=3,1,0", /* SPACE  */
2753     "153=1,1,0",
2754     0
2755 };
2756 
2757 /* [CHARTABLE] */
2758 char *Profile_CHARTABLE[] = {
2759     "130.91=\\lbrack ",
2760     "130.95=\\_ ",        /* needed to properly escape '_' */
2761     "131.95=\\_ ",
2762     "132.74=\\vartheta ", /* encoding for lowercase greek */
2763     "132.86=\\varsigma ",
2764     "132.97=\\alpha ",
2765     "132.98=\\beta ",
2766     "132.99=\\chi ",
2767     "132.100=\\delta ",
2768     "132.101=\\epsilon ",
2769     "132.102=\\phi ",
2770     "132.103=\\gamma ",
2771     "132.104=\\eta ",
2772     "132.105=\\iota ",
2773     "132.106=\\varphi ",
2774     "132.107=\\kappa ",
2775     "132.108=\\lambda ",
2776     "132.109=\\mu ",
2777     "132.110=\\nu ",
2778     "132.111=\\o ",
2779     "132.112=\\pi ",
2780     "132.113=\\theta ",
2781     "132.114=\\rho ",
2782     "132.115=\\sigma ",
2783     "132.116=\\tau ",
2784     "132.117=\\upsilon ",
2785     "132.118=\\varpi ",
2786     "132.119=\\omega ",
2787     "132.120=\\xi ",
2788     "132.121=\\psi ",
2789     "132.122=\\zeta ",
2790     "132.182=\\partial ",
2791     "132.945=\\alpha ",
2792     "132.946=\\beta ",
2793     "132.967=\\chi ",
2794     "132.948=\\delta ",
2795     "132.949=\\epsilon ",
2796     "132.966=\\phi ",
2797     "132.947=\\gamma ",
2798     "132.951=\\eta ",
2799     "132.953=\\iota ",
2800     "132.981=\\varphi ",
2801     "132.954=\\kappa ",
2802     "132.955=\\lambda ",
2803     "132.956=\\mu ",
2804     "132.957=\\nu ",
2805     "132.959=\\o ",
2806     "132.960=\\pi ",
2807     "132.952=\\theta ",
2808     "132.961=\\rho ",
2809     "132.963=\\sigma ",
2810     "132.964=\\tau ",
2811     "132.965=\\upsilon ",
2812     "132.969=\\omega ",
2813     "132.958=\\xi ",
2814     "132.968=\\psi ",
2815     "132.950=\\zeta ",
2816     "132.977=\\vartheta ",
2817     "132.962=\\varsigma ",
2818     "132.982=\\varpi ",
2819     "133.65=A",            /* encoding for upper case greek */
2820     "133.66=B",
2821     "133.67=X",
2822     "133.68=\\Delta ",
2823     "133.69=E",
2824     "133.70=\\Phi ",
2825     "133.71=\\Gamma ",
2826     "133.72=H",
2827     "133.73=I",
2828     "133.75=K",
2829     "133.76=\\Lambda ",
2830     "133.77=M",
2831     "133.78=N",
2832     "133.79=O",
2833     "133.80=\\Pi ",
2834     "133.81=\\Theta ",
2835     "133.82=P",
2836     "133.83=\\Sigma ",
2837     "133.84=T",
2838     "133.85=Y",
2839     "133.87=\\Omega ",
2840     "133.88=\\Xi ",
2841     "133.89=\\Psi ",
2842     "133.90=Z",
2843     "133.913=A",
2844     "133.914=B",
2845     "133.935=X",
2846     "133.916=\\Delta ",
2847     "133.917=E",
2848     "133.934=\\Phi ",
2849     "133.915=\\Gamma ",
2850     "133.919=H",
2851     "133.921=I",
2852     "133.922=K",
2853     "133.923=\\Lambda ",
2854     "133.924=M",
2855     "133.925=N",
2856     "133.927=O",
2857     "133.928=\\Pi ",
2858     "133.920=\\Theta ",
2859     "133.929=P",
2860     "133.931=\\Sigma ",
2861     "133.932=T",
2862     "133.933=Y",
2863     "133.937=\\Omega ",
2864     "133.926=\\Xi ",
2865     "133.936=\\Psi ",
2866     "133.918=Z",
2867     "134.34=\\forall ",    /* symbol font encoding */
2868     "134.36=\\exists ",
2869     "134.39=\\ni ",
2870     "134.42=*",
2871     "134.43=+",
2872     "134.45=-",
2873     "134.61==",
2874     "134.64=\\cong ",
2875     "134.92=\\therefore ",
2876     "134.94=\\bot ",
2877     "134.97=\\alpha ",
2878     "134.98=\\beta ",
2879     "134.99=\\chi ",
2880     "134.100=\\delta ",
2881     "134.101=\\epsilon ",
2882     "134.102=\\phi ",
2883     "134.103=\\gamma ",
2884     "134.104=\\eta ",
2885     "134.105=\\iota ",
2886     "134.106=\\varphi ",
2887     "134.107=\\kappa ",
2888     "134.108=\\lambda ",
2889     "134.109=\\mu ",
2890     "134.110=\\nu ",
2891     "134.112=\\pi ",
2892     "134.113=\\theta ",
2893     "134.114=\\rho ",
2894     "134.115=\\sigma ",
2895     "134.116=\\tau ",
2896     "134.117=\\upsilon ",
2897     "134.118=\\varpi ",
2898     "134.119=\\omega ",
2899     "134.120=\\xi ",
2900     "134.121=\\psi ",
2901     "134.122=\\zeta ",
2902     "134.163=\\leq ",
2903     "134.165=\\infty ",
2904     "134.171=\\leftrightarrow ",
2905     "134.172=\\leftarrow ",
2906     "134.173=\\uparrow ",
2907     "134.174=\\rightarrow ",
2908     "134.175=\\downarrow ",
2909     "134.176=^\\circ ",
2910     "134.177=\\pm ",
2911     "134.179=\\geq ",
2912     "134.180=\\times ",
2913     "134.181=\\propto ",
2914     "134.182=\\partial ",
2915     "134.183=\\bullet ",
2916     "134.184=\\div ",
2917     "134.185=\\neq ",
2918     "134.186=\\equiv ",
2919     "134.187=\\approx ",
2920     "134.191=\\hookleftarrow ",
2921     "134.192=\\aleph ",
2922     "134.193=\\Im ",
2923     "134.194=\\Re ",
2924     "134.195=\\wp ",
2925     "134.196=\\otimes ",
2926     "134.197=\\oplus ",
2927     "134.198=\\emptyset ",
2928     "134.199=\\cap ",
2929     "134.200=\\cup ",
2930     "134.201=\\supset ",
2931     "134.202=\\supseteq ",
2932     "134.203=\\nsubset ",
2933     "134.204=\\subset ",
2934     "134.205=\\subseteq ",
2935     "134.206=\\in ",
2936     "134.207=\\notin ",
2937     "134.208=\\angle ",
2938     "134.209=\\nabla ",
2939     "134.213=\\prod ",
2940     "134.215=\\cdot ",
2941 /*    "134.215=\\times ", */
2942     "134.216=\\neg ",
2943     "134.217=\\wedge ",
2944     "134.218=\\vee ",
2945     "134.219=\\Leftrightarrow ",
2946     "134.220=\\Leftarrow ",
2947     "134.221=\\Uparrow ",
2948     "134.222=\\Rightarrow ",
2949     "134.223=\\Downarrow ",
2950     "134.224=\\Diamond ",
2951     "134.225=\\langle ",
2952     "134.229=\\Sigma ",
2953     "134.241=\\rangle ",
2954     "134.242=\\smallint ",
2955     "134.247=\\div ",
2956     "134.8722=-",
2957     "134.8804=\\leq ",
2958     "134.8805=\\geq ",
2959     "134.8800=\\neq ",
2960     "134.8801=\\equiv ",
2961     "134.8776=\\approx ",
2962     "134.8773=\\cong ",
2963     "134.8733=\\propto ",
2964     "134.8727=\\ast ",
2965     "134.8901=\\cdot ",
2966     "134.8226=\\bullet ",
2967     "134.8855=\\otimes ",
2968     "134.8853=\\oplus ",
2969     "134.9001=\\langle ",
2970     "134.9002=\\rangle ",
2971     "134.8594=\\rightarrow ",
2972     "134.8592=\\leftarrow ",
2973     "134.8596=\\leftrightarrow ",
2974     "134.8593=\\uparrow ",
2975     "134.8595=\\downarrow ",
2976     "134.8658=\\Rightarrow ",
2977     "134.8656=\\Leftarrow ",
2978     "134.8660=\\Leftrightarrow ",
2979     "134.8657=\\Uparrow ",
2980     "134.8659=\\Downarrow ",
2981     "134.8629=\\hookleftarrow ",
2982     "134.8756=\\therefore ",
2983     "134.8717=\\backepsilon ",
2984     "134.8707=\\exists ",
2985     "134.8704=\\forall ",
2986     "134.172=\\neg ",
2987     "134.8743=\\wedge ",
2988     "134.8744=\\vee ",
2989     "134.8712=\\in ",
2990     "134.8713=\\notin ",
2991     "134.8746=\\cup ",
2992     "134.8745=\\cap ",
2993     "134.8834=\\subset ",
2994     "134.8835=\\supset ",
2995     "134.8838=\\subseteq ",
2996     "134.8839=\\supseteq ",
2997     "134.8836=\\not\\subset ",
2998     "134.8709=\\emptyset ",
2999     "134.8706=\\partial ",
3000     "134.8711=\\nabla ",
3001     "134.8465=\\Im ",
3002     "134.8476=\\Re ",
3003     "134.8501=\\aleph ",
3004     "134.8736=\\angle ",
3005     "134.8869=\\bot ",
3006     "134.8900=\\lozenge ",
3007     "134.8734=\\infty ",
3008     "134.8472=\\wp ",
3009     "134.8747=\\smallint",
3010     "134.8721=\\sum ",
3011     "134.8719=\\prod ",
3012     "139.58=\\sim ",              /* MT Extra encoding */
3013     "139.59=\\simeq ",
3014     "139.60=\\vartriangleleft ",
3015     "139.61=\\ll ",
3016     "139.62=\\vartriangleright ",
3017     "139.63=\\gg ",
3018     "139.66=\\doteq ",
3019     "139.67=\\coprod ",
3020     "139.68=\\lambdabar ",
3021     "139.73=\\bigcap ",
3022     "139.75=\\ldots ",
3023     "139.76=\\cdots ",
3024     "139.77=\\vdots ",
3025     "139.78=\\ddots ",
3026     "139.79=\\ddots ",
3027     "139.81=\\because ",
3028     "139.85=\\bigcup ",
3029     "139.97=\\mapsto ",
3030     "139.98=\\updownarrow ",
3031     "139.99=\\Updownarrow ",
3032     "139.102=\\succ ",
3033     "139.104=\\hbar ",
3034     "139.108=\\ell ",
3035     "139.109=\\mp ",
3036     "139.111=\\circ ",
3037     "139.112=\\prec ",
3038     "139.8230=\\ldots ",
3039     "139.8943=\\cdots ",
3040     "139.8942=\\vdots ",
3041     "139.8944=\\ddots ",
3042     "139.8945=\\ddots ",
3043     "139.8826=\\prec ",
3044     "139.8827=\\succ ",
3045     "139.8882=\\vartriangleleft ",
3046     "139.8883=\\vartriangleright ",
3047     "139.8723=\\mp ",
3048     "139.8728=\\circ ",
3049     "139.8614=\\longmapsto ",
3050     "139.8597=\\updownarrow ",
3051     "139.8661=\\Updownarrow ",
3052     "139.4746=\\bigcup ",
3053     "139.4745=\\bigcap ",
3054     "139.8757=\\because ",
3055     "139.8467=\\ell ",
3056     "139.8463=\\hbar ",
3057     "139.411=\\lambdabar ",
3058     "139.8720=\\coprod ",
3059     "151.60160m={}",
3060     "151.60160t={}",
3061     "152.1m={}",
3062     "152.1t={}",
3063     "152.8m=\\/",
3064     "152.8t=\\/",
3065     "152.2m=\\,",
3066     "152.2t=\\thinspace ",
3067     "152.4m=\\;",
3068     "152.4t=\\ ",
3069     "152.5m=\\quad ",
3070     "152.5t=\\quad ",
3071     "152.60161m=\\/",
3072     "152.60161t=\\/",
3073     "152.61168m=@,",
3074     "152.61168t=",
3075     "152.60162m=\\,",
3076     "152.60162t=\\thinspace ",
3077     "152.60164m=\\;",
3078     "152.60164t=\\ ",
3079     "152.60165m=\\quad ",
3080     "152.60165t=\\quad ",
3081     "152.61186m=\\, ",
3082     "152.61186t=\\thinspace ",
3083     0
3084 };
3085 
3086 /* [TEMPLATES] */
3087 char *Profile_TEMPLATES[] = {
3088     "0.0=fence: angle-both,\\left\\langle #1[M]\\right\\rangle ",
3089     "0.1=fence: angle-left only,\\left\\langle #1[M]\\right. ",
3090     "0.2=fence: angle-right only,\\left. #1[M]\\right\\rangle ",
3091     "1.0=fence: paren-both,\\left( #1[M]\\right) ",
3092     "1.1=fence: paren-left only,\\left( #1[M]\\right. ",
3093     "1.2=fence: paren-right only,\\left. #1[M]\\right) ",
3094     "2.0=fence: brace-both,\\left\\{ #1[M]\\right\\} ",
3095     "2.1=fence: brace-left only,\\left\\{ #1[M]\\right. ",
3096     "2.2=fence: brace-right only,\\left. #1[M]\\right\\} ",
3097     "3.0=fence: brack-both,\\left[ #1[M]\\right] ",
3098     "3.1=fence: brack-left only,\\lef]t[ #1[M]\\right. ",
3099     "3.2=fence: brack-right only,\\left. #1[M]\\right] ",
3100     "4.0=fence: bar-both,\\left| #1[M]\\right| ",
3101     "4.1=fence: bar-left only,\\left| #1[M]\\right. ",
3102     "4.2=fence: bar-right only,\\left. #1[M]\\right| ",
3103     "5.0=fence: dbar-both,\\left\\| #1[M]\\right\\| ",
3104     "5.1=fence: dbar-left only,\\left\\| #1[M]\\right. ",
3105     "5.2=fence: dbar-right only,\\left. #1[M]\\right\\| ",
3106     "6.0=fence: floor,\\left\\lfloor #1[M]\\right\\rfloor ",
3107     "7.0=fence: ceiling,\\left\\lceil #1[M]\\right\\rceil ",
3108     "8.0=fence: LBLB,\\left[ #1[M]\\right[ ",
3109     "9.0=fence: RBRB,\\left] #1[M]\\right] ",
3110     "10.0=fence: RBLB,\\left] #1[M]\\right[ ",
3111     "11.0=fence: LBRP,\\left[ #1[M]\\right) ",
3112     "12.0=fence: LPRB,\\left( #1[M]\\right] ",
3113     "13.0=root: sqroot,\\sqrt{#1[M]} ",
3114     "13.1=root: nthroot,\\sqrt[#2[M]]{#1[M]} ",
3115     "14.0=fract: ffract,\\frac{#1[M]}{#2[M]} ",
3116     "14.1=fract: pfract,\\frac{#1[M]}{#2[M]} ",
3117     "15.0=script: super,#1[L][STARTSUP][ENDSUP] ",
3118     "15.1=script: sub,#1[L][STARTSUB][ENDSUB] ",
3119     "15.2=script: subsup,#1[L][STARTSUB][ENDSUB]#2[L][STARTSUP][ENDSUP] ",
3120     "16.0=ubar: subar,\\underline{#1[M]} ",
3121     "16.1=ubar: dubar,\\underline{\\underline{#1[M]}} ",
3122     "17.0=obar: sobar,\\overline{#1[M]} ",
3123     "17.1=obar: dobar,\\overline{\\overline{#1[M]}} ",
3124     "18.0=larrow: box on top,\\stackrel{#1[M]}{\\longleftarrow} ",
3125     "18.1=larrow: box below ,\\stackunder{#1[M]}{\\longleftarrow} ",
3126     "19.0=rarrow: box on top,\\stackrel{#1[M]}{\\longrightarrow} ",
3127     "19.1=rarrow: box below ,\\stackunder{#1[M]}{\\longrightarrow} ",
3128     "20.0=barrow: box on top,\\stackrel{#1[M]}{\\longleftrightarrow} ",
3129     "20.1=barrow: box below ,\\stackunder{#1[M]}{\\longleftrightarrow} ",
3130     "21.0=integrals: single - no limits,\\int #1[M] ",
3131     "21.1=integrals: single - lower only,\\int\\nolimits#2[L][STARTSUB][ENDSUB]#1[M] ",
3132     "21.2=integrals: single - both,\\int\\nolimits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3133     "21.3=integrals: contour - no limits,\\oint #1[M] ",
3134     "21.4=integrals: contour - lower only,\\oint\\nolimits#2[L][STARTSUB][ENDSUB]#1[M] ",
3135     "22.0=integrals: double - no limits ,\\iint #1[M] ",
3136     "22.1=integrals: double - lower only,\\iint\\nolimits#2[L][STARTSUB][ENDSUB]#1[M] ",
3137     "22.2=integrals: area - no limits ,\\iint #1[M] ",
3138     "22.3=integrals: area - lower only,\\iint\\nolimits#2[L][STARTSUB][ENDSUB]#1[M] ",
3139     "23.0=integrals: triple - no limits ,\\iiint #1[M] ",
3140     "23.1=integrals: triple - lower only,\\iiint\\nolimits#2[L][STARTSUB][ENDSUB]#1[M] ",
3141     "23.2=integrals: volume - no limits ,\\iiint #1[M] ",
3142     "23.3=integrals: volume - lower only,\\iiint\\nolimits#2[L][STARTSUB][ENDSUB] #1[M] ",
3143     "24.0=integrals: single - sum style - both,\\int\\limits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3144     "24.1=integrals: single - sum style - lower only,\\int\\limits#2[L][STARTSUB][ENDSUB]#1[M] ",
3145     "24.2=integrals: contour - sum style - lower only,\\oint\\limits#2[L][STARTSUB][ENDSUB] #1[M] ",
3146     "25.0=integrals: area - sum style - lower only,\\iint\\limits#2[L][STARTSUB][ENDSUB] #1[M] ",
3147     "25.1=integrals: double - sum style - lower only,\\iint\\limits#2[L][STARTSUB][ENDSUB] #1[M] ",
3148     "26.0=integrals: volume - sum style - lower only,\\iiint\\limits#2[L][STARTSUB][ENDSUB] #1[M] ",
3149     "26.1=integrals: triple - sum style - lower only,\\iiint\\limits#2[L][STARTSUB][ENDSUB] #1[M] ",
3150     "27.0=horizontal braces: upper,\\stackrel{#2[M]}{\\overbrace{#1[M]}} ",
3151     "28.0=horizontal braces: lower,\\stackunder{#2[M]}{\\underbrace{#1[M]}} ",
3152     "29.0=sum: limits top/bottom - lower only,\\sum\\limits#2[L][STARTSUB][ENDSUB]#1[M] ",
3153     "29.1=sum: limits top/bottom - both,\\sum\\limits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3154     "29.2=sum: no limits,\\sum #1[M] ",
3155     "30.0=sum: limits right - lower only,\\sum\\nolimits#2[L][STARTSUB][ENDSUB]#1[M] ",
3156     "30.1=sum: limits right - both,\\sum\\nolimits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3157     "31.0=product: limits top/bottom - lower only,\\dprod\\limits#2[L][STARTSUB][ENDSUB]#1[M] ",
3158     "31.1=product: limits top/bottom - both,\\dprod\\limits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3159     "31.2=product: no limits,\\dprod #1[M] ",
3160     "32.0=product: limits right - lower only,\\dprod\\nolimits#2[L][STARTSUB][ENDSUB]#1[M] ",
3161     "32.1=product: limits right - both,\\dprod\\nolimits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3162     "33.0=coproduct: limits top/bottom - lower only,\\dcoprod\\limits#2[L][STARTSUB][ENDSUB]#1[M] ",
3163     "33.1=coproduct: limits top/bottom - both,\\dcoprod\\limits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3164     "33.2=coproduct: no limits,\\dcoprod #1[M] ",
3165     "34.0=coproduct: limits right - lower only,\\dcoprod\\nolimits#2[L][STARTSUB][ENDSUB]#1[M] ",
3166     "34.1=coproduct: limits right - both,\\dcoprod\\nolimits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3167     "35.0=union: limits top/bottom - lower only,\\dbigcup\\limits#2[L][STARTSUB][ENDSUB]#1[M] ",
3168     "35.1=union: limits top/bottom - both,\\dbigcup\\limits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3169     "35.2=union: no limits,\\dbigcup #1[M] ",
3170     "36.0=union: limits right - lower only,\\dbigcup\\nolimits#2[L][STARTSUB][ENDSUB]#1[M] ",
3171     "36.1=union: limits right - both,\\dbigcup\\nolimits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3172     "37.0=intersection: limits top/bottom - lower only,\\dbigcap\\limits#2[L][STARTSUB][ENDSUB]#1[M] ",
3173     "37.1=intersection: limits top/bottom - both,\\dbigcap\\limits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3174     "37.2=intersection: no limits,\\dbigcap #1[M] ",
3175     "38.0=intersection: limits right - lower only,\\dbigcap\\nolimits#2[L][STARTSUB][ENDSUB]#1[M] ",
3176     "38.1=intersection: limits right - both,\\dbigcap\\nolimits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3177     "39.0=limit: upper,#1 #2[L][STARTSUP][ENDSUP] ",
3178     "39.1=limit: lower,#1 #2[L][STARTSUB][ENDSUB] ",
3179     "39.2=limit: both,#1 #2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP] ",
3180     "40.0=long divisionW,",
3181     "40.1=long divisionWO,",
3182     "41.0=slash fraction: normal,\\frac{#1[M]}{#2[M]} ",
3183     "41.1=slash fraction: baseline,#1[M]/#2[M] ",
3184     "41.2=slash fraction: subscript-sized,\\frac{#1[M]}{#2[M]} ",
3185     "42.0=INTOP: upper,",
3186     "42.1=INTOP: lower,",
3187     "42.2=INTOP: both,",
3188     "43.0=SUMOP: upper,",
3189     "43.1=SUMOP: lower,",
3190     "43.2=SUMOP: both,",
3191     "44.0=leadingSUPER,",
3192     "44.1=leadingSUB,",
3193     "44.2=leadingSUBSUP,",
3194     "45.0=Dirac: both,\\left\\langle #1[M]\\right.\\left| #2[M]\\right\\rangle ",
3195     "45.1=Dirac: left,\\left\\langle #1[M]\\right| ",
3196     "45.2=Dirac: right,\\left| #1[M]\\right\\rangle ",
3197     "46.0=under arrow: left,\\underleftarrow{#1[M]} ",
3198     "46.1=under arrow: right,\\underrightarrow{#1[M]} ",
3199     "46.2=under arrow: both,\\underleftrightarrow{#1[M]} ",
3200     "47.0=over arrow: left,\\overleftarrow{#1[M]} ",
3201     "47.1=over arrow: right,\\overrightarrow{#1[M]} ",
3202     "47.2=over arrow: both,\\overleftrightarrow{#1[M]} ",
3203     "TextInMath=\\text{#1} ",
3204     0
3205 };
3206 
3207 /* [TEMPLATES] */
3208 char *Profile_TEMPLATES_5[] = {
3209     "0.1=fence: angle-left only,\\left\\langle #1[M]\\right. ",
3210     "0.2=fence: angle-right only,\\left. #1[M]\\right\\rangle ",
3211     "0.3=fence: angle-both,\\left\\langle #1[M]\\right\\rangle ",
3212     "1.1=fence: paren-left only,\\left( #1[M]\\right. ",
3213     "1.2=fence: paren-right only,\\left. #1[M]\\right) ",
3214     "1.3=fence: paren-both,\\left( #1[M]\\right) ",
3215     "2.1=fence: brace-left only,\\left\\{ #1[M]\\right. ",
3216     "2.2=fence: brace-right only,\\left. #1[M]\\right\\} ",
3217     "2.3=fence: brace-both,\\left\\{ #1[M]\\right\\} ",
3218     "3.1=fence: brack-left only,\\lef]t[ #1[M]\\right. ",
3219     "3.2=fence: brack-right only,\\left. #1[M]\\right] ",
3220     "3.3=fence: brack-both,\\left[ #1[M]\\right] ",
3221     "4.1=fence: bar-left only,\\left| #1[M]\\right. ",
3222     "4.2=fence: bar-right only,\\left. #1[M]\\right| ",
3223     "4.3=fence: bar-both,\\left| #1[M]\\right| ",
3224     "5.1=fence: dbar-left only,\\left\\| #1[M]\\right. ",
3225     "5.2=fence: dbar-right only,\\left. #1[M]\\right\\| ",
3226     "5.3=fence: dbar-both,\\left\\| #1[M]\\right\\| ",
3227     "6.1=fence: floor,\\left\\lfloor #1[M]\\right. ",
3228     "6.2=fence: floor,\\left. #1[M]\\right\\rfloor ",
3229     "6.3=fence: floor,\\left\\lfloor #1[M]\\right\\rfloor ",
3230     "7.1=fence: ceiling,\\left\\lceil #1[M]\\right. ",
3231     "7.2=fence: ceiling,\\left. #1[M]\\right\\rceil ",
3232     "7.3=fence: ceiling,\\left\\lceil #1[M]\\right\\rceil ",
3233     "8.0=fence: LBLB,\\left[ #1[M]\\right[ ",
3234     "9.0=fence: LPLP,\\left( #1[M]\\right( ",
3235     "9.1=fence: RPLP,\\left) #1[M]\\right( ",
3236     "9.2=fence: LBLP,\\left[ #1[M]\\right( ",
3237     "9.3=fence: RBLP,\\left] #1[M]\\right( ",
3238     "9.16=fence: LPRP,\\left( #1[M]\\right) ",
3239     "9.17=fence: RPRP,\\left) #1[M]\\right) ",
3240     "9.18=fence: LBRP,\\left[ #1[M]\\right) ",
3241     "9.19=fence: RBRP,\\left] #1[M]\\right) ",
3242     "9.32=fence: LPLB,\\left( #1[M]\\right[ ",
3243     "9.33=fence: RPLB,\\left) #1[M]\\right[ ",
3244     "9.34=fence: LBLB,\\left[ #1[M]\\right[ ",
3245     "9.35=fence: RBLB,\\left] #1[M]\\right[ ",
3246     "9.48=fence: LPRB,\\left( #1[M]\\right] ",
3247     "9.49=fence: RPRB,\\left) #1[M]\\right] ",
3248     "9.50=fence: LBRB,\\left[ #1[M]\\right] ",
3249     "9.51=fence: RBRB,\\left] #1[M]\\right] ",
3250     "10.0=root: sqroot,\\sqrt{#1[M]} ",
3251     "10.1=root: nthroot,\\sqrt[#2[M]]{#1[M]} ",
3252     "11.0=fract: tmfract,\\frac{#1[M]}{#2[M]} ",
3253     "11.1=fract: smfract,\\frac{#1[M]}{#2[M]} ",
3254     "11.2=fract: slfract,{#1[M]}/{#2[M]} ",
3255     "11.3=fract: slfract,{#1[M]}/{#2[M]} ",
3256     "11.4=fract: slfract,{#1[M]}/{#2[M]} ",
3257     "11.5=fract: smfract,\\frac{#1[M]}{#2[M]} ",
3258     "11.6=fract: slfract,{#1[M]}/{#2[M]} ",
3259     "11.7=fract: slfract,{#1[M]}/{#2[M]} ",
3260     "12.0=ubar: subar,\\underline{#1[M]} ",
3261     "12.1=ubar: dubar,\\underline{\\underline{#1[M]}} ",
3262     "13.0=obar: sobar,\\overline{#1[M]} ",
3263     "13.1=obar: dobar,\\overline{\\overline{#1[M]}} ",
3264     "14.0=larrow: box on top,\\stackrel{#1[M]}{\\longleftarrow} ",
3265     "14.1=larrow: box below ,\\stackunder{#1[M]}{\\longleftarrow} ",
3266     "14.0=rarrow: box on top,\\stackrel{#1[M]}{\\longrightarrow} ",
3267     "14.1=rarrow: box below ,\\stackunder{#1[M]}{\\longrightarrow} ",
3268     "14.0=barrow: box on top,\\stackrel{#1[M]}{\\longleftrightarrow} ",
3269     "14.1=barrow: box below ,\\stackunder{#1[M]}{\\longleftrightarrow} ",
3270     "15.0=integrals: single - no limits,\\int #1[M] ",
3271     "15.1=integrals: single - both,\\int\\nolimits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3272     "15.2=integrals: double - both,\\iint\\nolimits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3273     "15.3=integrals: triple - both,\\iiint\\nolimits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3274     "15.4=integrals: contour - no limits,\\oint #1[M] ",
3275     "15.8=integrals: contour - no limits,\\oint #1[M] ",
3276     "15.12=integrals: contour - no limits,\\oint #1[M] ",
3277     "16.0=sum: limits top/bottom - both,\\sum\\limits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3278     "17.0=product: limits top/bottom - both,\\dprod\\limits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3279     "18.0=coproduct: limits top/bottom - both,\\dcoprod\\limits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3280     "19.0=union: limits top/bottom - both,\\dbigcup\\limits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3281     "20.0=intersection: limits top/bottom - both,\\dbigcap\\limits#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3282     "21.0=integrals: single - both,\\int#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3283     "22.0=sum: single - both,\\sum#2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP]#1[M] ",
3284     "23.0=limit: both,#1 #2[L][STARTSUB][ENDSUB]#3[L][STARTSUP][ENDSUP] ",
3285     "24.0=horizontal brace: lower,\\stackunder{#2[M]}{\\underbrace{#1[M]}} ",
3286     "24.1=horizontal brace: upper,\\stackrel{#2[M]}{\\overbrace{#1[M]}} ",
3287     "25.0=horizontal brace: lower,\\stackunder{#2[M]}{\\underbrace{#1[M]}} ",
3288     "25.1=horizontal brace: upper,\\stackrel{#2[M]}{\\overbrace{#1[M]}} ",
3289     "25.0=hbracket,",
3290     "26.0=limi",
3291     "27.0=script: sub,#1[L][STARTSUB][ENDSUB] ",
3292     "27.1=script: sub,#1[L][STARTSUB][ENDSUB] ",
3293     "28.0=script: super,#2[L][STARTSUP][ENDSUP] ",
3294     "28.1=script: super,#2[L][STARTSUP][ENDSUP] ",
3295     "29.0=script: subsup,#1[L][STARTSUB][ENDSUB]#2[L][STARTSUP][ENDSUP] ",
3296     "30.0=limi",
3297     "31.0=limi",
3298     "32.0=limi",
3299     "33.0=limi",
3300     "34.0=limi",
3301     "35.0=limi",
3302     "36.0=limi",
3303     "37.0=limi",
3304     "TextInMath=\\text{#1} ",
3305     0
3306 };
3307 
3308 /* [EMBELLS] */
3309 /* ;format is "math template,text template" (different from all the above) */
3310 char *Template_EMBELLS[] = {
3311                 "",
3312                 "",
3313 /* embDOT       */ "\\dot{%1} ,\\.%1 ",
3314 /* embDDOT      */ "\\ddot{%1} ,\\\"%1 ",
3315 /* embTDOT      */ "\\dddot{%1} ,%1 ",
3316 /* embPRIME     */ "%1' ,%1 ",
3317 /* embDPRIME    */ "%1'' ,%1 ",
3318 /* embBPRIME    */ "\\backprime %1 , %1",
3319 /* embTILDE     */ "\\tilde{%1} ,\\~%1 ",
3320 /* embHAT       */ "\\hat{%1} ,\\^%1 ",
3321 /* embNOT       */ "\\not %1 ,\\NEG %1 ",
3322 /* embRARROW    */ "\\vec{%1} ,%1 ",
3323 /* embLARROW    */ "\\overleftarrow1{%1} ,%1 ",
3324 /* embBARROW    */ "\\overleftrightarrow{%1} ,%1 ",
3325 /* embR1ARROW   */ "\\overrightarrow{%1} ,%1 ",
3326 /* embL1ARROW   */ "\\overleftarrow{%1} ,%1 ",
3327 /* embMBAR      */ "\\underline{%1} ,%1 ",
3328 /* embOBAR      */ "\\bar{%1} ,\\=%1 ",
3329 /* embTPRIME    */ "%1''' ,",
3330 /* embFROWN     */ "\\widehat{%1} ,%1 ",
3331 /* embSMILE     */ "\\breve{%1} ,%1 ",
3332 /* embX_BARS    */ "{%1} ,%1 ",
3333 /* embUP_BAR    */ "{%1} ,%1 ",
3334 /* embDOWN_BAR  */ "{%1} ,%1 ",
3335 /* emb4DOT      */ "{%1} ,%1 ",
3336 /* embU_1DOT    */ "\\d{%1} ,\\d{%1} ",
3337 /* embU_2DOT    */ "{%1} ,%1 ",
3338 /* embU_3DOT    */ "{%1} ,%1 ",
3339 /* embU_4DOT    */ "{%1} ,%1 ",
3340 /* embU_BAR     */ "{%1} ,%1 ",
3341 /* embU_TILDE   */ "{%1} ,%1 ",
3342 /* embU_FROWN   */ "{%1} ,%1 ",
3343 /* embU_SMILE   */ "{%1} ,%1 ",
3344 /* embU_RARROW  */ "{%1} ,%1 ",
3345 /* embU_LARROW  */ "{%1} ,%1 ",
3346 /* embU_BARROW  */ "{%1} ,%1 ",
3347 /* embU_R1ARROW */ "{%1} ,%1 ",
3348 /* embU_L1ARROW */ "{%1} ,%1 ",
3349     0
3350 };
3351