math.c
上传用户:zlh9724
上传日期:2007-01-04
资源大小:1991k
文件大小:62k
源码类别:

浏览器

开发平台:

Unix_Linux

  1. /* Experimental html-math parser for X11 browser */
  2. /* Written by Dave Ragget, 1995 */
  3. /*
  4. Janne Saarela
  5. janne.saarela@hut.fi
  6. 28.7.1995
  7. I took the liberty of extending the mathematical text to hold
  8. the emphasis attribute. The different EMPH-* macros
  9. correspond to different emphasis one can give to different
  10. symbols and text using <above> and <below> elements.
  11. Therefore each math_box or Box now also holds the emph
  12. as an unsigned int.
  13. The parsing of mathematical markup was also improved to
  14. take the attributes into account. Before they were simply
  15. dropped out. This is why in ParseExpr() all shortrefs have
  16. to be carefully handled. This means in TAG_SUP, TAG_SUB
  17. and TAG_BOX the *bufptr has to be checked for the >
  18. character.
  19. Generally, the ParseExpr() routine is the trickies one
  20. to understand in this file. It's highly recursive and
  21. generates, as it proceeds, a list of boxes. In addition
  22. one should update the x value which corresponds to the
  23. x-coordinate of each box. The w member of the box
  24. holds the width of each box and can be used to calculate
  25. the x.
  26. The next variable is created in each case: and its next
  27. member is made to link to box variable which is always the
  28. list of previously created boxes. This is why the box = next
  29. assignment is also performed.
  30. The root and sqrt elements are parsed but the corresponding
  31. symbols and their alignments are not of satisfactory, though.
  32. */
  33. /*
  34.   .
  35. Stale Schumacher
  36. staalesc@usit.uio.no / stale@hypnotech.com
  37. 15.8.95
  38. I have extended the math support and corrected a few minor
  39. bugs. These are the most important changes:
  40.   - Added support for the <ATOP> tag
  41.   - Added new entity &lim; (limit function)
  42.   - Functions (&sin;, &cos;, &tan;, etc.) are now rendered in
  43.     an upright font, _not_ italic as they used to be. Furtermore,
  44.     all unknown entities are treated as functions. This avoids
  45.     the problem of defining one FUNC code for each mathematical
  46.     function (and believe me, there are quite a few if you take
  47.     into account things like arctan, sinh, arccosh etc.) This
  48.     solution also enables the HTML author to "invent" new
  49.     functions as an alternative to using <t>...</t>:
  50.       myfunc   - rendered in italics
  51.       &myfunc; - rendered in an upright font
  52.     Misuse of this "feature" is discouraged... :-)
  53.   - The characters '!' and ':' are now treated as SYMBOLs
  54.   - Added new macro IsISOLetter to prevent Arena from hanging if
  55.     the math markup contains national characters
  56.   - Curly brackets (braces: '{' and '}') may now be stretched
  57.     using <left> and <right>, just as '[', ']', '(', ')', and '|'
  58.   - Commented out some obsolete code, including FuncCode
  59.   - Reimplemented &prod; in MathEntity
  60. Changes 13.12.95:
  61.   - Changed <sqrt> and <root> to draw the radical graphically
  62.     rather than using the symbol font
  63.   - Changed the behaviour of <above>, <below>, <vec>, <bar> etc.
  64.     to draw _one_ contiguous line or arrow
  65.   - Fixed/improved a large number of alignment/placement problems
  66.   - Added new entity &dots;
  67. */
  68. #include <stdio.h>
  69. #include <stdlib.h>
  70. #include <string.h>
  71. #include "www.h"
  72. #define LATIN1  0
  73. #define SYMSET  1
  74. #define HLINE           0x40     /* width instead of right coord */
  75. #define NORMAL  0
  76. #define SMALL   1
  77. #define EMPH_NORMAL      0
  78. /*#define EMPH_ANCHOR     (1 << 0)*/
  79. #define EMPH_UNDERLINE  (1 << 1)
  80. #define EMPH_STRIKE     (1 << 2)
  81. #define EMPH_HIGHLIGHT  (1 << 3)
  82. #define EMPH_OVERLINE   (1 << 4)
  83. #define EMPH_OVERLARR (1 << 5)
  84. #define EMPH_OVERRARR (1 << 6)
  85. #define EMPH_OVERTILDE (1 << 7)
  86. #define EMPH_OVERHAT (1 << 8)
  87. #define EMPH_OVERDOT    (1 << 9)
  88. #define EMPH_OVERDDOT   (1 << 10)
  89. #define EMPH_UNDERLARR (1 << 11)
  90. #define EMPH_UNDERRARR (1 << 12)
  91. #define EMPH_UNDERTILDE (1 << 13)
  92. #define EMPH_UNDERHAT (1 << 14)
  93. #define EMPH_ROOTLINE   (1 << 15)
  94. #define IDX_NORMALFONT          5
  95. #define IDX_INORMALFONT         6
  96. #define IDX_BNORMALFONT         7
  97. #define IDX_BINORMALFONT        8
  98. #define IDX_FIXEDFONT           9
  99. #define IDX_IFIXEDFONT         10
  100. #define IDX_BFIXEDFONT         11
  101. #define IDX_BIFIXEDFONT        12
  102. #define IDX_SMALLFONT          13
  103. #define IDX_SYMBOLFONT         14
  104. #define IDX_SUBSYMFONT         15
  105. #if 0
  106. /*  janet: commented, already defined in www.h  */
  107. /* reproduce Frame struct here for quick hack interface */
  108. struct frame_struct 
  109.      { 
  110.          struct frame_struct *next;  /* linked list of peer frames */ 
  111.          struct frame_struct *child; /* linked list of nested frames */ 
  112.          unsigned char *top;         /* where to start displaying from */ 
  113.          long offset;                /* from start of document */ 
  114.          unsigned int indent;        /* from left of document */ 
  115.          long height;                /* documents can be very long */ 
  116.          unsigned int width; 
  117.          int leftmargin;             /* indent from lhs of frame */ 
  118.          int rightmargin;            /* indent from rhs of frame */ 
  119.          unsigned int info;    /* to BEGIN_FRAME object in paint stream */ 
  120.          unsigned int length;        /* byte count of frame's data */ 
  121.          unsigned int lastrow;       /* used in parsing tables */ 
  122.          unsigned char style;        /* frame's background style */ 
  123.          unsigned char border;       /* frame's border style */ 
  124.          int flow;    /* ALIGN_LEFT, ALIGN_NOTE, ALIGN_CENTER or ALIGN_RIGHT */ 
  125.          int oldmargin;     /* previous value of parent's margin */ 
  126.          int pushcount;     /* save count value for restore */ 
  127.          int leftcount;     /* of frames with ALIGN_LEFT or ALIGN_NOTE */ 
  128.          int rightcount;    /* of frames with ALIGN_RIGHT */ 
  129.      }; 
  130. typedef struct frame_struct Frame; 
  131. #endif
  132. extern int Here;
  133. extern char *bufptr, *lastbufptr;
  134. extern XFontStruct *Fonts[FONTS]; /* staalesc 13/12/95 */
  135. /******** end of interface to X11 browser ********/
  136. /* staalesc 15/08/95: these are now obsolete
  137. #define SIN             1
  138. #define COS             2
  139. #define TAN             3
  140. #define LOG             4
  141. #define EXP             5
  142. */
  143. /* integral, summation and product signs */
  144. #define INT             100
  145. #define SUM             101
  146. #define PROD            102
  147. /* staalesc 15/08/95: limit function */
  148. #define LIM             103
  149. /* staalesc 13/12/95: horizontal dots */
  150. #define DOTS            104
  151. #define LBRACKET        200
  152. #define RBRACKET        201
  153. #define LSQBRACKET      202
  154. #define RSQBRACKET      203
  155. #define LBRACE          204
  156. #define RBRACE          205
  157. /* janet 1/8/95: #define UNKNOWN        -2     */
  158. #define BUFFEND        -1
  159. #define NONE            0
  160. #define SPACE           1
  161. #define NAME            2
  162. #define FUNC            3
  163. #define OPERATOR        4
  164. #define DELIM           5
  165. #define SYM             6
  166. #define BOX             7
  167. #define DIVIDER         8
  168. #define TAG_BOX         9
  169. /* janet 1/8/95: #define TAG_SUP        10 */
  170. /* janet 1/8/95: #define TAG_SUB        11 */
  171. #define TAG_OVER       12
  172. #define TAG_LEFT       13
  173. #define TAG_RIGHT      14
  174. /* janet 1/8/95: #define TAG_MATH       15 */
  175. #define TAG_ROOT       16
  176. #define TAG_ABOVE      17
  177. #define TAG_BELOW      18
  178. #define TAG_UPRIGHT    19
  179. #define TAG_BUPRIGHT   20
  180. #define TAG_BOLDTEXT   21
  181. #define TAG_OF         22
  182. #define TAG_VEC        23
  183. #define TAG_BAR        24
  184. #define TAG_DOT        25
  185. #define TAG_DDOT       26
  186. #define TAG_HAT        27
  187. #define TAG_TILDE      28
  188. #define TAG_SQRT       29
  189. #define TAG_ATOP       30   /* staalesc 15/08/95 */
  190. #define RADICAL        31   /* staalesc 13/12/95 */
  191. #define STARTTAG        0
  192. /* janet 1/8/95: #define ENDTAG          1 */
  193. #define SHORTREF        2
  194. #define EXPR            1
  195. #define RSUP            2
  196. #define RSUB            3
  197. #define LDELIM          4
  198. #define CSUP            5
  199. #define CSUB            6
  200. #define RDELIM          7
  201. #define LSUP            8
  202. #define LSUB            9
  203. /* janet 1/8/95: #define ALIGN_LEFT      0 */
  204. /* janet 1/8/95: #define ALIGN_CENTER    1 */
  205. /* janet 1/8/95: #define ALIGN_RIGHT     2 */
  206. #define ROWS 24
  207. /* janet 1/8/95: #define COLS 80 */
  208. #ifndef max
  209. #define     max(a, b)   ((a) > (b) ? (a) : (b))
  210. #endif
  211. struct math_box
  212. {
  213.     int role;   /* EXPR, RSUP, RSUB, LDELIM, CSUP, CSUB, RDELIM, LSUP, LSUB */
  214.     int type;   /* NAME, FUNC, OPERATOR, DELIM, BOX */
  215.     struct math_box *next;
  216.     struct math_box *base;
  217.     struct math_box *indices;
  218.     int font;
  219.     char *str;
  220.     int len;
  221.     int code;
  222.     int subcode;
  223.     int dx, dy, w, above, below;
  224.     unsigned int emph;
  225. };
  226. typedef struct math_box Box;
  227. static int token_code, token_len, token_width, token_above, token_font,
  228.            token_below, token_align, token_charset, token_subcode;
  229. static char *token_str;
  230. int math_normal_sym_font = 0, math_small_sym_font, math_normal_text_font, 
  231.     math_small_text_font, math_italic_text_font, math_bold_text_font, math_ibold_text_font;
  232. static int current_font_tag = 0;
  233. int TextFont(int size, int emp)
  234. {
  235.     if (size == SMALL) {
  236. switch (emp) {
  237. case TAG_UPRIGHT:
  238.     return math_small_text_font;
  239.     break;
  240. case TAG_BUPRIGHT:
  241.     return math_small_text_font;
  242.     break;
  243. case TAG_BOLDTEXT:
  244.     return math_small_text_font;
  245.     break;
  246. default:
  247.     return math_small_text_font;
  248.     break;
  249. }
  250.     } else {
  251. switch (emp) {
  252. case TAG_UPRIGHT:
  253.     return math_normal_text_font;
  254.     break;
  255. case TAG_BUPRIGHT:
  256.     return math_bold_text_font;
  257.     break;
  258. case TAG_BOLDTEXT:
  259.     return math_ibold_text_font;
  260.     break;
  261. default:
  262.     return math_italic_text_font;
  263.     break;
  264. }
  265.     }
  266. }
  267. #define SymFont(size) (size == NORMAL ? math_normal_sym_font : math_small_sym_font)
  268. #define UprightTextFont(size) (TextFont(size, TAG_UPRIGHT))
  269. int Space(int font)
  270. {
  271.     int up, down;
  272.     static int myfont = -1, width = 0;
  273.     if (font != myfont)
  274.     {
  275.         myfont = font;
  276.         width = TextWidth(myfont, " ", 1, &up, &down);
  277.     }
  278.     return width;
  279. }
  280. int divide_base(int font) /* staalesc 13/12/95 */
  281. {
  282.     int direction_hint, font_ascent, font_descent;
  283.     XCharStruct overall;
  284.     XTextExtents(Fonts[font], "o", 1,
  285.                     &direction_hint,
  286.                     &font_ascent,
  287.                     &font_descent,
  288.                     &overall);
  289.     return font_ascent / 2;
  290. }
  291. Box *NewBox(int font)
  292. {
  293.     Box *box;
  294.     box = (Box *)malloc(sizeof(Box));
  295.     box->role = EXPR;
  296.     box->next = NULL;
  297.     box->base = NULL;
  298.     box->indices = NULL;
  299.     box->type = NAME;
  300.     box->str = NULL;
  301.     box->len = 0;
  302.     box->dx = box->dy = box->below = 0;
  303.     box->w = box->above = 0;
  304.     box->font = font;
  305.     box->emph = EMPH_NORMAL;
  306.     return (box); /* howcome 12/10/94: the return was missing! */
  307. }
  308. /* janet 1/8/95: defined in www.h: #define IsWhite(c) (c == ' ' || c == 't' || c == 'n' || c== 'r') */
  309. #define IsLetter(c) (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
  310. #define IsISOLetter(c) (IsLetter(c) || (192 <= c && c <= 255 && c!=215 && c!=247))
  311. #define IsDigit(c) ('0' <= c && c <= '9')
  312. #define IsAlphaNumeric(c) (IsLetter(c) || IsDigit(c))
  313. static void ParseAboveAttrs (int *emph)
  314. {
  315.     int n, m, isSet; /* janet 21/09/95: not used: c */
  316.     char *attr, *attrval;
  317.     isSet = 0;
  318.     bufptr--;
  319.     for (;;)
  320.     {
  321.         if (*bufptr == '')
  322.             break;
  323.         if (*bufptr == '>') {
  324.     bufptr++;
  325.             break;
  326. }
  327.         if (IsWhite(*bufptr)) {
  328.     bufptr++;
  329.             continue;
  330. }
  331.         attr = ParseAttribute(&n);
  332.         attrval = ParseValue(&m);
  333.         if (n == 3 && strncasecmp(attr, "sym", n) == 0)
  334.         {
  335.             if (m == 3 && strncasecmp(attrval, "hat", m) == 0) {
  336.                 *emph |= EMPH_OVERHAT;
  337. isSet = 1;
  338. continue;
  339.     }
  340.             else if (m == 5 && strncasecmp(attrval, "tilde", m) == 0) {
  341.                 *emph |= EMPH_OVERTILDE;
  342. isSet = 1;
  343. continue;
  344.     }
  345.             else if (m == 4 && strncasecmp(attrval, "larr", m) == 0) {
  346.                 *emph |= EMPH_OVERLARR;
  347. isSet = 1;
  348. continue;
  349.     }
  350.             else if (m == 4 && strncasecmp(attrval, "rarr", m) == 0) {
  351.                 *emph |= EMPH_OVERRARR;
  352. isSet = 1;
  353. continue;
  354.     }
  355.     continue;
  356.         }
  357.     }
  358.     if (!isSet)
  359. *emph |= EMPH_OVERLINE;
  360. }
  361. static void ParseBelowAttrs (int *emph)
  362. {
  363.     int n, m, isSet; /* janet 21/07/95: not used: c */
  364.     char *attr, *attrval;
  365.     isSet = 0;
  366.     bufptr--;
  367.     for (;;)
  368.     {
  369.         if (*bufptr == '')
  370.             break;
  371.         if (*bufptr == '>') {
  372.     bufptr++;
  373.             break;
  374. }
  375.         if (IsWhite(*bufptr)) {
  376.     bufptr++;
  377.             continue;
  378. }
  379.         attr = ParseAttribute(&n);
  380.         attrval = ParseValue(&m);
  381.         if (n == 3 && strncasecmp(attr, "sym", n) == 0)
  382.         {
  383.             if (m == 3 && strncasecmp(attrval, "hat", m) == 0) {
  384.                 *emph |= EMPH_UNDERHAT;
  385. isSet = 1;
  386. continue;
  387.     }
  388.             else if (m == 5 && strncasecmp(attrval, "tilde", m) == 0) {
  389.                 *emph |= EMPH_UNDERTILDE;
  390. isSet = 1;
  391. continue;
  392.     }
  393.             else if (m == 4 && strncasecmp(attrval, "larr", m) == 0) {
  394.                 *emph |= EMPH_UNDERLARR;
  395. isSet = 1;
  396. continue;
  397.     }
  398.             else if (m == 4 && strncasecmp(attrval, "rarr", m) == 0) {
  399.                 *emph |= EMPH_UNDERRARR;
  400. isSet = 1;
  401. continue;
  402.     }
  403.     continue;
  404.         }
  405.     }
  406.     if (!isSet)
  407. *emph |= EMPH_UNDERLINE;
  408. }
  409. static int GetTag(void)
  410. {
  411.     int len; /* janet 21/07/95: not used: c */
  412.     char *tag;
  413.  /* bufptr -> "sub> or "/sub> etc */
  414.     len = 0;
  415.     token_code = STARTTAG;
  416.     tag = bufptr;
  417.     if (*bufptr == '/')
  418.     {
  419.         token_code = ENDTAG;
  420.         ++tag;
  421.         ++bufptr;
  422.     }
  423.     while (IsAlphaNumeric(*bufptr)) {
  424.         len++;
  425.         bufptr++;
  426.     }
  427.     /* don't skip attributes, Janne Saarela 9.6.1995 */
  428.     /* skip blank space before attributes or end tag character > */
  429.     while (IsWhite(*bufptr))
  430.         bufptr++;
  431.     /* skip the last > character */
  432. /*    if (token_code == ENDTAG)
  433.         bufptr++; */
  434.     if (len == 3 && strncasecmp(tag, "sub", len) == 0)
  435.         return TAG_SUB;
  436.     if (len == 3 && strncasecmp(tag, "sup", len) == 0)
  437.         return TAG_SUP;
  438.     if (len == 3 && strncasecmp(tag, "box", len) == 0)
  439.         return TAG_BOX;
  440.     if (len == 4 && strncasecmp(tag, "over", len) == 0)
  441.         return TAG_OVER;
  442.     if (len == 4 && strncasecmp(tag, "atop", len) == 0)
  443.         return TAG_ATOP;
  444.     if (len == 4 && strncasecmp(tag, "left", len) == 0)
  445.         return TAG_LEFT;
  446.     if (len == 5 && strncasecmp(tag, "right", len) == 0)
  447.         return TAG_RIGHT;
  448.     if (len == 4 && strncasecmp(tag, "math", len) == 0)
  449.         return TAG_MATH;
  450.     if (len == 4 && strncasecmp(tag, "root", len) == 0)
  451.         return TAG_ROOT;
  452.     if (len == 4 && strncasecmp(tag, "sqrt", len) == 0)
  453.         return TAG_SQRT;
  454.     if (len == 2 && strncasecmp(tag, "of", len) == 0)
  455.         return TAG_OF;
  456.     if (len == 5 && strncasecmp(tag, "above", len) == 0)
  457.         return TAG_ABOVE;
  458.     if (len == 5 && strncasecmp(tag, "below", len) == 0)
  459.         return TAG_BELOW;
  460.     if (len == 1 && strncasecmp(tag, "t", len) == 0)
  461.         return TAG_UPRIGHT;
  462.     if (len == 2 && strncasecmp(tag, "bt", len) == 0)
  463.         return TAG_BUPRIGHT;
  464.     if (len == 1 && strncasecmp(tag, "b", len) == 0)
  465.         return TAG_BOLDTEXT;
  466.     if (len == 3 && strncasecmp(tag, "vec", len) == 0)
  467.         return TAG_VEC;
  468.     if (len == 3 && strncasecmp(tag, "bar", len) == 0)
  469.         return TAG_BAR;
  470.     if (len == 3 && strncasecmp(tag, "dot", len) == 0)
  471.         return TAG_DOT;
  472.     if (len == 4 && strncasecmp(tag, "ddot", len) == 0)
  473.         return TAG_DDOT;
  474.     if (len == 3 && strncasecmp(tag, "hat", len) == 0)
  475.         return TAG_HAT;
  476.     if (len == 5 && strncasecmp(tag, "tilde", len) == 0)
  477.         return TAG_TILDE;
  478.     
  479.     return UNKNOWN;
  480. }
  481. /* needs expanding to cover full range of symbols as per TeX
  482.    one unresolve question is the set of tokens like ","  */
  483. static int DelimSymCode(int c, int *ch)
  484. {
  485.     if (c == '[')
  486.     {
  487.         *ch = 91;
  488.         return 234;
  489.     }
  490.     if (c == ']')
  491.     {
  492.         *ch = 93;
  493.         return 250;
  494.     }
  495.     if (c == '(')
  496.     {
  497.         *ch = 40;
  498.         return 231;
  499.     }
  500.     if (c == ')')
  501.     {
  502.         *ch = 41;
  503.         return 247;
  504.     }
  505.     if (c == '{')
  506.     {
  507.         *ch = 123;
  508.         return 237;
  509.     }
  510.     if (c == '}')
  511.     {
  512.         *ch = 125;
  513.         return 253;
  514.     }
  515.     if (c == '|')
  516.     {
  517.         *ch = 124;
  518.         return 239;
  519.     }
  520.     return TRUE;  /* janet: not of much use here, only for compilation */
  521. }
  522. static int DelimCode(int c, int size)
  523. {
  524.     char ch;
  525.     if (c == '[' || c == ']' || c == '(' || c == ')' || c == '{' || c == '}' || c == '|')
  526.     {
  527.         token_font = SymFont(size);
  528.         ch = c;
  529.         token_width = TextWidth(token_font, &ch, 1, &token_above, &token_below);
  530.         if (c == ')' || c == '|' || c == ']') /* staalesc 13/12/95: added extra space */
  531.             token_width += Space(token_font)/2;
  532.         token_code = DelimSymCode(c, &token_subcode);
  533.         token_charset = SYMSET;
  534.         return c;
  535.     }
  536. /*    return NULL;*/
  537.     return 0;
  538. }
  539. static int OperatorCode(int c, int size)
  540. {
  541.     char ch;
  542.     if (c == '=' || c == '+' || c == '-' || c == '/' ||
  543.         c == '.' || c == ',' || c == '<' || c == '>' ||
  544.         c == '!' || c == ':')
  545.     {
  546.         token_font = SymFont(size);
  547.         token_charset = SYMSET;
  548.         ch = c;
  549.         token_width = TextWidth(token_font, &ch, 1, &token_above, &token_below);
  550.         if (c != '.') token_width += Space(token_font)/2; /* staalesc 13/12/95 */
  551.         token_code = c;
  552.         return c;
  553.     }
  554. /*    return NULL;*/
  555.     return 0;
  556. }
  557. /* staalesc 15/08/95: FuncCode is never called, its job is done by MathEntity instead
  558. static int FuncCode(char *str, int len, int size)
  559. {
  560.     int up, down;
  561.     char ch;
  562.     token_font = UprightTextFont(size);
  563.     if (len == 3 && strncasecmp(str, "sin", len) == 0)
  564.     {
  565.         token_width = TextWidth(token_font, "sin", 3, &token_above, &token_below);
  566.         token_code = SIN;
  567.         return token_code;
  568.     }
  569.     if (len == 3 && strncasecmp(str, "cos", len) == 0)
  570.     {
  571.         token_width = TextWidth(token_font, "cos", 3, &token_above, &token_below);
  572.         token_code = COS;
  573.         return token_code;
  574.     }
  575.     if (len == 3 && strncasecmp(str, "tan", len) == 0)
  576.     {
  577.         token_width = TextWidth(token_font, "tan", 3, &token_above, &token_below);
  578.         token_code = TAN;
  579.         return token_code;
  580.     }
  581.     if (len == 3 && strncasecmp(str, "log", len) == 0)
  582.     {
  583.         token_width = TextWidth(token_font, "log", 3, &token_above, &token_below);
  584.         token_code = LOG;
  585.         return token_code;
  586.     }
  587.     if (len == 3 && strncasecmp(str, "exp", len) == 0)
  588.     {
  589.         token_width = TextWidth(token_font, "e", 1, &token_above, &token_below);
  590.         token_code = EXP;
  591.         return token_code;
  592.     }
  593.     if (len == 3 && strncasecmp(str, "int", len) == 0)
  594.     {
  595.         token_font = SymFont(size);
  596.         ch = 243;
  597.         token_width = TextWidth(token_font, &ch, 1, &up, &down);
  598.         token_above = up + up + down;
  599.         token_below = down + up + down;
  600.         token_align = ALIGN_CENTER;
  601.         token_code = INT;
  602.         token_charset = SYMSET;
  603.         return token_code;
  604.     }
  605.     if (len == 3 && strncasecmp(str, "sum", len) == 0)
  606.     {
  607.         token_font = SymFont(size);
  608.         ch = 229;        
  609.         token_width = TextWidth(token_font, &ch, 1, &token_above, &token_below);
  610.         token_align = ALIGN_CENTER;
  611.         token_code = SUM;
  612.         token_charset = SYMSET;
  613.         return token_code;
  614.     }
  615.     if (len == 4 && strncasecmp(str, "prod", len) == 0)
  616.     {
  617.         token_font = SymFont(size);
  618.         ch = 213;        
  619.         token_width = TextWidth(token_font, &ch, 1, &token_above, &token_below);
  620.         token_align = ALIGN_CENTER;
  621.         token_code = PROD;
  622.         token_charset = SYMSET;
  623.         return token_code;
  624.     }
  625.     return 0;
  626. }
  627. */
  628. static int MathEntity(int size)
  629. {
  630.     int  c, length;
  631.     char ch;
  632.     token_font = TextFont(size, current_font_tag);
  633.     if (strncmp(bufptr, "sp;", 3) == 0)
  634.     {
  635.         token_width = Space(token_font);
  636.         token_code = ' ';
  637.         bufptr += 3;
  638.         return SPACE;
  639.     }
  640.     if (strncmp(bufptr, "thinsp;", 7) == 0)
  641.     {
  642.         token_width = Space(token_font)/2;
  643.         token_code = ' ';
  644.         bufptr += 7;
  645.         return SPACE;
  646.     }
  647.     if (strncmp(bufptr, "dots;", 5) == 0)
  648.     {
  649.         token_font = SymFont(size);
  650.         token_width = TextWidth(token_font, "... ", 4, &token_above, &token_below);
  651.         token_align = ALIGN_CENTER;
  652.         token_code = DOTS;
  653. bufptr += 5;
  654.         token_charset = SYMSET;
  655.         return FUNC;
  656.     }
  657.     if (strncmp(bufptr, "int;", 4) == 0)
  658.     {
  659.         token_font = SymFont(size);
  660.         ch = 243;
  661.         token_width = TextWidth(token_font, &ch, 1, &token_above, &token_below);
  662.         token_above = token_above + token_above + token_below;
  663.         /* token_below = token_below + token_above + token_below; */  /* staalesc 13/12/95 */
  664.         token_align = ALIGN_CENTER;
  665.         token_code = INT;
  666. bufptr += 4;
  667.         token_charset = SYMSET;
  668.         return FUNC;
  669.     }
  670.     if (strncmp(bufptr, "sum;", 4) == 0)
  671.     {
  672.         token_font = SymFont(size);
  673.         ch = 229;        
  674.         token_width = TextWidth(token_font, &ch, 1, &token_above, &token_below);
  675.         token_align = ALIGN_CENTER;
  676.         token_code = SUM;
  677. bufptr += 4;
  678.         token_charset = SYMSET;
  679.         return FUNC;
  680.     }
  681.     if (strncmp(bufptr, "prod;", 5) == 0)
  682.     {
  683.         token_font = SymFont(size);
  684.         ch = 213;        
  685.         token_width = TextWidth(token_font, &ch, 1, &token_above, &token_below);
  686.         token_align = ALIGN_CENTER;
  687.         token_code = PROD;
  688. bufptr += 5;
  689.         token_charset = SYMSET;
  690.         return FUNC;
  691.     }
  692.     if (strncmp(bufptr, "lim;", 4) == 0)
  693.     { 
  694.         token_font = UprightTextFont(size);
  695.         token_width = TextWidth(token_font, "lim", 3, &token_above, &token_below);
  696.         token_align = ALIGN_CENTER;
  697.         token_code = LIM;
  698.   bufptr += 4;
  699.         return FUNC;
  700.     }
  701.     /* Janne Saarela 1/3/95
  702.        All the symbols entities are in the same hash table with the other
  703.        entity names. See entities.c */
  704.     if ( (c = entity(bufptr, &length)) )
  705.     {
  706.       bufptr += length-1;
  707.       if (DelimCode(c, size))
  708.           return DELIM; /* staalesc 15/08/95: entity may be '{' or '}' */
  709.       ch = c;
  710.       token_font = SymFont (size);
  711.       token_width = TextWidth(token_font, &ch, 1, &token_above, &token_below);
  712.       token_width += Space(token_font);
  713. /*      token_code = ch;*/
  714.       token_code = c; /* howcome 8/3/95 */
  715.       token_charset = SYMSET;
  716.       return SYM;
  717.     }
  718.     token_len = 0;
  719.     token_str = bufptr;
  720.     c = *bufptr++;
  721.     while (IsAlphaNumeric(c))
  722.     {
  723.         ++token_len;
  724.         c = *bufptr++;
  725.     }
  726.     if (token_len == 0)
  727.         return UNKNOWN;
  728.     token_font = UprightTextFont(size); /* Functions should not be rendered in italics */
  729.     token_width = TextWidth(token_font, token_str, token_len, &token_above, &token_below);
  730.     token_width += Space(token_font);
  731.     return NAME;
  732. }
  733. static int GetMathToken(int size)
  734. {
  735.   /* janet 21/07/95: not used:    Box *box; */
  736.   /* janet 21/07/95: not used:    char *str; */
  737.     unsigned char c; /* staalesc 15/08/95: changed from int to unsigned char */
  738.     int n; /* janet 21/07/95: not used: font */
  739.     token_align = ALIGN_RIGHT;
  740.     lastbufptr = bufptr;
  741.     token_charset = LATIN1;
  742.     token_font = TextFont(size, current_font_tag);
  743.     token_code = token_subcode = 0;
  744.     while (c = *bufptr++, IsWhite(c));
  745.     if (c == '')
  746.     {
  747.         --bufptr;
  748.         return BUFFEND;
  749.     }
  750. /*    if (c == '&' && (n = MathEntity(font)))*/ /* howcome 28/2/95: font should be size? */
  751.     if (c == '&' && (n = MathEntity(size)))
  752.         return n;
  753.     if (c == '^')
  754.     {
  755.         token_code = SHORTREF;
  756.         return TAG_SUP;
  757.     }
  758.     if (c == '_')
  759.     {
  760.         token_code = SHORTREF;
  761.         return TAG_SUB;
  762.     }
  763.     if (c == '{')
  764.     {
  765.         token_code = STARTTAG;
  766.         return TAG_BOX;
  767.     }
  768.     if (c == '}')
  769.     {
  770.         token_code = ENDTAG;
  771.         return TAG_BOX;
  772.     }
  773.     if ( (c == '<') &&  (bufptr[0] == '/' && IsLetter(bufptr[1]) || IsLetter(bufptr[0])) )
  774.         return GetTag();
  775.     if (DelimCode(c, size))
  776.         return DELIM;
  777.     if (OperatorCode(c, size))
  778.         return OPERATOR;
  779.     /* probably a NAME or FUNC */
  780.     token_len = 0;
  781.     token_str = bufptr - 1;
  782. #if 0
  783.     /* howcome 28/2/94: added more characters to the while test There
  784.        are probably even more of these */
  785.     while (IsAlphaNumeric(c) || (c == ''') || (c == '*') ||
  786.    (c == '%') || (c == ':') || (c == ';'))
  787.     {
  788.         ++token_len;
  789.         c = *bufptr++;
  790.     }
  791.     
  792. #endif
  793.     /* howcome 28/2/94: added more characters to the while test There
  794.        are probably even more of these */
  795.     /* jsaarela 7/3/95: had to separate digits from other symbols since
  796.        otherwise letters following digits would be in the symbol font */
  797.     if (IsISOLetter (c) || (c == ''') || (c == '*') || (c == '%') ||
  798.        (c == ';') || (c == '.'))
  799.     {
  800. while (IsISOLetter(c) || (c == ''') || (c == '*') || (c == '%') ||
  801.        (c == ';') || (c == '.'))
  802. {
  803.     ++token_len;
  804.     c = *bufptr++;
  805. }
  806.     } else if (IsDigit(c))
  807.     {
  808. while (IsDigit(c))
  809. {
  810.     ++token_len;
  811.     c = *bufptr++;
  812. }
  813.     }
  814. /* howcome 8/3/95: jannes part ends here */
  815.     --bufptr;
  816.     if (token_len == 0)
  817.         return UNKNOWN;
  818. /* staalesc 15/08/95: FuncCode obsolete
  819.     if (FuncCode(token_str, token_len, size))
  820.         return FUNC;
  821. */
  822.     if (IsDigit(*token_str))
  823.     {
  824.         if (size == SMALL)
  825.             token_font = TextFont(size, current_font_tag);
  826.         else
  827.             token_font = SymFont(size);
  828.     }
  829.     else
  830.         token_font = TextFont(size, current_font_tag);
  831.     token_width = TextWidth(token_font, token_str, token_len, &token_above, &token_below);
  832.     token_width += Space(token_font);
  833.     return NAME;
  834. }
  835. /* janet 21/07/95: function is never used:
  836. static void UnGetMathToken(void)
  837. {
  838.     bufptr = lastbufptr;
  839. }
  840. */
  841. /* vertically reposition indices following stretching of base */
  842. static void AdjustIndices(Box *base, int *above, int *below)
  843. {
  844.     int up, down;
  845.     Box *box;
  846.     up = base->above;
  847.     down = base->below;
  848.     for (box = base->indices; box; box = box->next)
  849.     {
  850.         if (box->role == LSUP || box->role == CSUP || box->role == RSUP)
  851.         {
  852.             box->dy = base->above + box->below;
  853.             up = max(up, box->dy + box->above);
  854.             continue;
  855.         }
  856.         if (box->role == LSUB || box->role == CSUB || box->role == RSUB)
  857.         {
  858.             box->dy = - (base->below + box->above);
  859.             down = max(down, box->below - box->dy);
  860.             continue;
  861.         }
  862.     }
  863.     *above = up;
  864.     *below = down;
  865. }
  866. int StretchSymbol(int font, int *up, int *down)
  867. {
  868.     int n, H, H1, h, ascent, descent;
  869.     FontSize(font, &ascent, &descent);
  870.     h = ascent + descent;
  871.     H = *up + *down;
  872.     if (H <= h)
  873.         return 0;
  874.     n = ((H + h - 1)/h) - 2;
  875.     n = max(n, 1);
  876.     H1 = (n + 2) * h;
  877.     *up += (H1 - H)/2;
  878.     *down = (H1 - *up);
  879.     return n;
  880. }
  881. static void SetDelimHeight(Box *delim, int above, int below, int *above1, int *below1)
  882. {
  883.     int up, down;
  884.     Box *box;
  885.     for (box = delim; box; box = box->next)
  886.     {
  887.         up = above;
  888.         down = below;
  889.         if (box->type == DELIM)
  890.         {
  891.             box->above = above;
  892.             box->below = below;
  893.             box->len = StretchSymbol(box->font, &(box->above), &(box->below));
  894.             up = max(up, box->above);
  895.             down = max(down, box->below);
  896.         }
  897.         else if (box->type == FUNC)
  898.         {
  899.             if (box->code == INT)
  900.             {
  901.                 box->above = max(above, box->above);
  902.                 box->below = max(below, box->below);
  903.                 box->len = StretchSymbol(box->font, &(box->above), &(box->below));
  904.                 AdjustIndices(box, &up, &down);
  905.                 up = max(up, box->above);
  906.                 down = max(down, box->below);
  907.             }
  908.         }
  909.         else if (box->type == BOX)
  910.             SetDelimHeight(box->base, above, below, &up, &down);
  911.         *above1 = max(up, above);
  912.         *below1 = max(down, below);
  913.     }
  914. }
  915. static Box *ParseExpr(int size, int tag, int emph, int *closetag)
  916. {
  917.     int token, x, hw, above, below, left, right, limits=0, endtag;
  918.     int up, down, asc, desc, oldemph; /* janet 21/07/95: not used: tmp */
  919.     char ch;
  920.     int basex, baseleft, baseright, baseup, basedown; /* janet 21/07/95: not used: baseh */
  921.     Box *box, *next, *numerator, *denominator, *ldelim; /* janet 21/07/95: not used: *tmpBox */
  922.     oldemph = EMPH_NORMAL;
  923.     box = NULL;
  924.     x = above = below = 0;
  925.     basex = baseleft = baseright = baseup = basedown = 0;
  926.     *closetag = BUFFEND;
  927.     while ((token = GetMathToken(size)) != BUFFEND)
  928.     {
  929.         if (token == tag)
  930.         {
  931.             if (token_code == ENDTAG || token_code == SHORTREF)
  932.             {
  933.                 *closetag = token;
  934. /* don't use swallowattribute as it does not work with } */
  935. if (*bufptr == '>')
  936.     bufptr++;
  937.                 break;
  938.             }
  939.         }
  940.      /* need to do something smarter based on tag classes */
  941.         if (token == TAG_OVER || token == TAG_ATOP || token == TAG_LEFT ||
  942.     token == TAG_RIGHT || token == TAG_OF)
  943.         {
  944.             *closetag = token;
  945.     SwallowAttributes ();
  946.             break;
  947.         }
  948.         switch (token)
  949.         {
  950.             case SPACE:
  951.                 basex = x;
  952.                 baseleft = baseright = baseup = basedown = 0;
  953.                 x += token_width;
  954.                 above = max(above, token_above);
  955.                 below = max(below, token_below);
  956.                 break;
  957.             case TAG_SUP:
  958. /* SwallowAttributes ();*/
  959. if (*bufptr == '>')
  960.     bufptr++;
  961.                 if (token_code != ENDTAG)
  962.                 {
  963.                     next = ParseExpr(SMALL, TAG_SUP, emph, &endtag);
  964.                     next->role = RSUP;
  965.                     if (!box)
  966.                         box = NewBox(token_font);
  967.                     next->next = box->indices;
  968.                     box->indices = next;
  969.                     if (limits == ALIGN_RIGHT)
  970.                     {
  971.                         baseright = max(baseright, next->w);
  972.                         next->dx = box->w - Space(token_font)/2; /* staalesc 13/12/95 */
  973.                         next->dy = box->above;
  974.                         baseup = max(baseup, next->above);
  975.                         x = basex + baseleft + box->w + baseright;
  976.                     }
  977.                     else if (limits == ALIGN_CENTER)
  978.                     {
  979.                         right = (next->w)/2;
  980.                         hw = (box->w)/2;
  981.                         if (right > baseright + hw)
  982.                             baseright = right + hw;
  983.                         left = next->w - right;
  984.                         hw = box->w - hw;
  985.                         next->dx = hw - left;
  986.                         if (left > baseleft + hw)
  987.                         {
  988.                             baseleft = left - hw;
  989.                             box->dx = basex + baseleft;
  990.                         }
  991.                         next->dy = box->above + next->below;
  992.                         baseup = max(baseup, next->above + next->below);
  993.                         x = basex + box->w + baseright;
  994.                     }
  995.                     above = max(above, box->above + baseup);
  996.                 }
  997.                 break;
  998.             case TAG_SUB:
  999. /* SwallowAttributes ();*/
  1000. if (*bufptr == '>')
  1001.     bufptr++;
  1002.                 if (token_code != ENDTAG)
  1003.                 {
  1004.                     next = ParseExpr(SMALL, TAG_SUB, emph, &endtag);
  1005.                     next->role = RSUB;
  1006.                     if (!box)
  1007.                         box = NewBox(token_font);
  1008.                     next->next = box->indices;
  1009.                     box->indices = next;
  1010.                     if (limits == ALIGN_RIGHT)
  1011.                     {
  1012.                         baseright = max(baseright, next->w);
  1013.                         next->dx = box->w - Space(token_font)/2;  /* staalesc 13/12/95 */
  1014.                         next->dy = - (box->below);
  1015.                         basedown = max(basedown, next->below);
  1016.                         x = baseleft + basex + box->w + baseright;
  1017.                     }
  1018.                     else if (limits == ALIGN_CENTER)
  1019.                     {
  1020.                         right = (next->w)/2;
  1021.                         hw = (box->w)/2;
  1022.                         if (right > baseright + hw)
  1023.                             baseright = right + hw;
  1024.                         left = next->w - right;
  1025.                         hw = box->w - hw;
  1026.                         next->dx = hw - left;
  1027.                         if (left > baseleft + hw)
  1028.                         {
  1029.                             baseleft = left - hw;
  1030.                             box->dx = basex + baseleft;
  1031.                         }
  1032.                         next->dy = box->dy - (box->below + next->above);  /* staalesc 13/12/95 */
  1033.                         basedown = max(basedown, next->above + next->below);
  1034.                         x = baseleft + basex + baseright + Space(token_font);
  1035.                     }
  1036.                     below = max(below, box->below + basedown - box->dy);
  1037.                 }
  1038.                 break;
  1039.             case TAG_BOX:
  1040. /* cannot swallow attributes here as they cannot be found
  1041.    in case of { and }. If some day someone introduces
  1042.    attributes to BOX elements, this has to be changed */
  1043. if (*bufptr == '>') {
  1044.     bufptr++;
  1045. }
  1046.                 if (token_code != ENDTAG)
  1047.                 {
  1048.                     int up1, down1;
  1049.                     limits = token_align;
  1050.                     basex = x;
  1051.                     baseleft = baseright = baseup = basedown = 0;
  1052.                     next = ParseExpr(size, TAG_BOX, emph, &endtag);
  1053.                     if (endtag == TAG_LEFT)
  1054.                     {
  1055.                         ldelim = next;
  1056.                         if (ldelim)
  1057.                             ldelim->role = LDELIM;
  1058.                         next = ParseExpr(size, TAG_BOX, emph, &endtag);
  1059.                     }
  1060.                     else
  1061.                         ldelim = NULL;
  1062.                     if (endtag == TAG_OVER || endtag == TAG_ATOP)
  1063.                     {
  1064.                         int previous_endtag = endtag; /* Need to remember this */
  1065.                         numerator = next;
  1066.                         numerator->role = CSUP;
  1067.                         denominator = ParseExpr(size, TAG_BOX, emph, &endtag);
  1068.                         denominator->role = CSUB;
  1069.                         next = NewBox(SymFont(size));
  1070.                         if (previous_endtag == TAG_OVER)
  1071.                             next->type = DIVIDER;
  1072.                         else /* previous_endtag == TAG_ATOP */
  1073.                             next->type = NONE;
  1074.                         next->code = 0;
  1075.                         next->above = 1;
  1076.                         next->below = 2;
  1077.                         next->w = 10;
  1078.                         next->dy = divide_base(next->font);  /* staalesc 13/12/95 */
  1079.                         next->indices = denominator;
  1080.                         denominator->next = numerator;
  1081.                         if (numerator->w > denominator->w)
  1082.                         {
  1083.                             right = (numerator->w)/2;
  1084.                             left = numerator->w - right;
  1085.                             numerator->dx = 2;  /* staalesc 13/12/95 */
  1086.                             denominator->dx = 2 + left - denominator->w + (denominator->w)/2;
  1087.                         }
  1088.                         else
  1089.                         {
  1090.                             right = (denominator->w)/2;
  1091.                             left = denominator->w - right;
  1092.                             denominator->dx = 2;  /* staalesc 13/12/95*/
  1093.                             numerator->dx = 2 + left - numerator->w + (numerator->w)/2;
  1094.                         }
  1095.                         numerator->dy = next->dy + next->above + numerator->below;
  1096.                         denominator->dy = next->dy - (next->below + denominator->above);
  1097.                         up = next->above + (numerator->above + numerator->below);
  1098.                         down = next->below + (denominator->above + denominator->below);
  1099.                         next->w = left + right + 3;             /* staalesc 13/12/95 */
  1100.                         above = max(above, up + next->dy);      /* staalesc 13/12/95 */
  1101.                         below = max(below, down - next->dy);    /* staalesc 13/12/95 */
  1102.                     }
  1103.                     else
  1104.                     {
  1105.                         up = next->above;
  1106.                         down = next->below;
  1107.                         above = max(above, up);
  1108.                         below = max(below, down);
  1109.                     }
  1110.                  /* at this point next is the boxed expression */
  1111.                     if (next)
  1112.                     {
  1113.                         next->next = box;
  1114.                         box = next;
  1115.                         box->dx = x;
  1116.                         /* box->dy = 0; */  /* staalesc 13/12/95 */
  1117.                     }
  1118.                 /* insert left delimited in list of indices
  1119.                    and adjust position of expression to make room */
  1120.                     if (ldelim)
  1121.                     {
  1122.                         if (!box)  /* avoid core dump */
  1123.                         {
  1124.                             box = NewBox(SymFont(size));
  1125.                             box = next;
  1126.                             box->dx = x;
  1127.                             box->dy = 0;
  1128.                         }
  1129.                         SetDelimHeight(ldelim, up, down, &up1, &down1);
  1130.                         above = max(above, up1 + box->dy);
  1131.                         below = max(below, down1 + box->dy);
  1132.                         ldelim->next = box->indices;
  1133.                         box->indices = ldelim;
  1134.                         ldelim->dx = - ldelim->w;
  1135.                         ldelim->dy = 0;
  1136.                         box->dx += ldelim->w;
  1137.                     }
  1138.                     if (box)
  1139.                         x = box->dx + box->w + Space(token_font)/2;  /* staalesc 13/12/95 */
  1140.                 /* and check for a <RIGHT> element */
  1141.                     if (endtag == TAG_RIGHT)
  1142.                     {
  1143.                         next = ParseExpr(size, TAG_BOX, emph, &endtag);
  1144.                         if (next)
  1145.                         {
  1146.                             if (!box)  /* avoid core dump */
  1147.                             {
  1148.                                 box = NewBox(SymFont(size));
  1149.                                 box = next;
  1150.                                 box->dx = x;
  1151.                                 box->dy = 0;
  1152.                             }
  1153.                             next->role = RDELIM;
  1154.                             SetDelimHeight(next, up, down, &up1, &down1);
  1155.                             above = max(above, up1 + box->dy);
  1156.                             below = max(below, down1 + box->dy);
  1157.                             next->next = box->indices;
  1158.                             box->indices = next;
  1159.                             next->dx = box->w;
  1160.                             next->dy = 0;
  1161.                             x += next->w;
  1162.                         }
  1163.                     }
  1164.                 }
  1165.                 break;
  1166.     case TAG_UPRIGHT:
  1167. SwallowAttributes ();
  1168.                 if (token_code != ENDTAG)
  1169.                 {
  1170.     limits = token_align;
  1171.     basex = x;
  1172.     baseleft = baseright = baseup = basedown = 0;
  1173.     current_font_tag = TAG_UPRIGHT;
  1174.     next = ParseExpr(size, TAG_UPRIGHT, emph, &endtag);
  1175.     if (next)
  1176.     {
  1177. if (box) {
  1178.     next->next = box;
  1179.     box = next;
  1180. } else {
  1181.     box = next;
  1182. }
  1183. next->font = TextFont(size, current_font_tag);
  1184. current_font_tag = 0;
  1185. next->dx = x;
  1186. next->dy = 0;
  1187.     }
  1188.                     above = max(above, next->above);  /* staalesc 13/12/95 */
  1189.     x += next->w + 2;
  1190. }
  1191. break;
  1192.     case TAG_BUPRIGHT:
  1193. SwallowAttributes ();
  1194.                 if (token_code != ENDTAG)
  1195.                 {
  1196.     limits = token_align;
  1197.     basex = x;
  1198.     baseleft = baseright = baseup = basedown = 0;
  1199.     current_font_tag = TAG_BUPRIGHT;
  1200.     next = ParseExpr(size, TAG_BUPRIGHT, emph, &endtag);
  1201.     if (next)
  1202.     {
  1203. if (box) {
  1204.     next->next = box;
  1205.     box = next;
  1206. } else {
  1207.     box = next;
  1208. }
  1209. next->font = TextFont(size, current_font_tag);
  1210. current_font_tag = 0;
  1211. next->dx = x;
  1212. next->dy = 0;
  1213.     }
  1214.                     above = max(above, next->above);  /* staalesc 13/12/95 */
  1215.     x += next->w + 2;
  1216. }
  1217. break;
  1218.     case TAG_BOLDTEXT:
  1219. SwallowAttributes ();
  1220.                 if (token_code != ENDTAG)
  1221.                 {
  1222.     limits = token_align;
  1223.     basex = x;
  1224.     baseleft = baseright = baseup = basedown = 0;
  1225.     current_font_tag = TAG_BOLDTEXT;
  1226.     next = ParseExpr(size, TAG_BOLDTEXT, emph, &endtag);
  1227.     if (next)
  1228.     {
  1229. if (box) {
  1230.     next->next = box;
  1231.     box = next;
  1232. } else {
  1233.     box = next;
  1234. }
  1235. next->font = TextFont(size, current_font_tag);
  1236. current_font_tag = 0;
  1237. next->dx = x;
  1238. next->dy = 0;
  1239.     }
  1240.                     above = max(above, next->above);  /* staalesc 13/12/95 */
  1241.     x += next->w + 2;
  1242. }
  1243. break;
  1244.     case TAG_SQRT:
  1245. SwallowAttributes ();
  1246.                 if (token_code != ENDTAG)
  1247.                 {
  1248.                     limits = token_align;
  1249.                     basex = x;
  1250.                     baseleft = baseright = baseup = basedown = 0;
  1251.     /* Create a box for the square root symbol */
  1252.     next = NewBox (SymFont(size));
  1253.     next->font = SymFont (size);
  1254.     next->type = RADICAL;
  1255.     ch = 214; /* the square root character */
  1256.     next->w = 2 + TextWidth(next->font, &ch, 1,
  1257. &token_above, &token_below);
  1258.     next->dx = x;
  1259.     next->dy = 0;
  1260.     next->above = token_above;
  1261.     next->below = token_below;
  1262.     next->next = box;
  1263.     box = next;
  1264.     x += next->w;
  1265.                     next = ParseExpr(size, TAG_SQRT, emph, &endtag);
  1266.     if (next)
  1267.     {
  1268. next->dx = x;
  1269. next->dy = 0;
  1270. x += next->w;
  1271.                         /* staalesc 13/12/95: Stretch the radical to fit expression */
  1272. box->above = next->above += 2;
  1273.                         box->below = next->below;
  1274. next->next = box;
  1275. box = next;
  1276.                         /* staalesc 13/12/95: Place the whole expression inside its own box */
  1277.                         next = NewBox(token_font);
  1278.                         next->type = BOX;
  1279.         next->emph |= EMPH_ROOTLINE;
  1280.                         next->dx = box->dx;
  1281.                         next->dy = 0;
  1282.                         next->above = box->above;
  1283.                         next->below = box->below;
  1284.                         next->w = x - box->dx;
  1285.                         next->next = box;
  1286.                         box = next;
  1287. limits = token_align;
  1288. above = max (above, next->above);
  1289. below = max (below, next->below);
  1290.     }
  1291. }
  1292. break;
  1293.     case TAG_ROOT:
  1294. SwallowAttributes ();
  1295.                 if (token_code != ENDTAG)
  1296.                 {
  1297.                     limits = token_align;
  1298.                     basex = x;
  1299.                     baseleft = baseright = baseup = basedown = 0;
  1300.     /* create a box in which we can draw the square root symbol */
  1301.     next = NewBox (SymFont(size));
  1302.     next->font = SymFont (size);
  1303.     next->type = RADICAL;
  1304.     ch = 214; /* the square root character */
  1305.     next->w = 2 + TextWidth(next->font, &ch, 1,
  1306. &token_above, &token_below);
  1307.     next->dx = x;
  1308.     next->dy = 0;
  1309.     next->above = token_above;
  1310.     next->below = token_below;
  1311.     next->next = box;
  1312.     box = next;
  1313.     x += next->w;
  1314.                     next = ParseExpr(SMALL, TAG_ROOT, emph, &endtag);
  1315.                     if (endtag == TAG_OF)
  1316.                     {
  1317. /* place the index of the root over the root sign */
  1318. if (next)
  1319.                         {
  1320.     FontSize(next->font, &asc, &desc);
  1321.     next->dx = box->dx-next->w+box->w;
  1322.     /* next->dy = (asc+desc)*0.95; */
  1323.     next->above = token_above;
  1324.     next->below = token_below;
  1325.     next->next = box;
  1326.     box = next;
  1327.     limits = token_align;
  1328.     above = max (above, next->above);
  1329.     below = max (below, next->below);
  1330. }
  1331. next = ParseExpr(size, TAG_ROOT, emph, &endtag);
  1332. if (next)
  1333.                         {
  1334.     next->dx = x;
  1335.     next->dy = 0;
  1336.     x += next->w;
  1337.                             /* staalesc 13/12/95: Stretch the radical to fit expression */
  1338.     box->next->above = next->above += 2;
  1339.                             box->next->below = next->below;
  1340.                             box->dy = next->above-asc+2; /* position the index correctly */
  1341.     next->next = box;
  1342.     box = next;
  1343.                             /* staalesc 13/12/95: Place the whole expression inside its own box */
  1344.                             next = NewBox(token_font);
  1345.                             next->type = BOX;
  1346.             next->emph |= EMPH_ROOTLINE;
  1347.                             next->dx = box->dx;
  1348.                             next->dy = 0;
  1349.                             next->above = box->above;
  1350.                             next->below = box->below;
  1351.                             next->w = x - box->dx;
  1352.                             next->next = box;
  1353.                             box = next;
  1354.     
  1355.     limits = token_align;
  1356.     above = max (above, next->above);
  1357.     below = max (below, next->below);
  1358. }
  1359.       } else { /* Missing <OF> tag: treat just like <SQRT> */
  1360. if (next)
  1361. {
  1362.     next->dx = x;
  1363.     next->dy = 0;
  1364.     x += next->w;
  1365.                             /* staalesc 13/12/95: Stretch the radical to fit expression */
  1366.     box->above = next->above += 2;
  1367.                             box->below = next->below;
  1368.     next->next = box;
  1369.     box = next;
  1370.                             /* staalesc 13/12/95: Place the whole expression inside its own box */
  1371.                             next = NewBox(token_font);
  1372.                             next->type = BOX;
  1373.             next->emph |= EMPH_ROOTLINE;
  1374.                             next->dx = box->dx;
  1375.                             next->dy = 0;
  1376.                             next->above = box->above;
  1377.                             next->below = box->below;
  1378.                             next->w = x - box->dx;
  1379.                             next->next = box;
  1380.                             box = next;
  1381.     limits = token_align;
  1382.     above = max (above, next->above);
  1383.     below = max (below, next->below);
  1384. }
  1385.     }
  1386. }
  1387. break;
  1388.             case TAG_VEC:
  1389.             case TAG_BAR:
  1390.             case TAG_DOT:
  1391.             case TAG_DDOT:
  1392.             case TAG_HAT:
  1393.             case TAG_TILDE:
  1394. SwallowAttributes ();
  1395.                 if (token_code != ENDTAG)
  1396.                 {
  1397.                     limits = token_align;
  1398.                     basex = x;
  1399.                     baseleft = baseright = baseup = basedown = 0;
  1400.                     next = ParseExpr (size, token, emph, &endtag);
  1401.                     if (next)
  1402.                     {
  1403.                         next->dx = x;
  1404.                         next->dy = 0;
  1405.                         next->above = token_above;
  1406.                         next->below = token_below;
  1407.                         next->next = box;
  1408.                         box = next;
  1409.                         x += next->w;
  1410.                         oldemph = emph;
  1411.                         switch (token) {
  1412.                         case TAG_VEC:
  1413.                             emph |= EMPH_OVERRARR;
  1414.                             break;
  1415.                         case TAG_BAR:
  1416.                             emph |= EMPH_OVERLINE;
  1417.                             break;
  1418.                         case TAG_DOT:
  1419.                             emph |= EMPH_OVERDOT;
  1420.                             break;
  1421.                         case TAG_DDOT:
  1422.                             emph |= EMPH_OVERDDOT;
  1423.                             break;
  1424.                         case TAG_HAT:
  1425.                             emph |= EMPH_OVERHAT;
  1426.                             break;
  1427.                         case TAG_TILDE:
  1428.                             emph |= EMPH_OVERTILDE;
  1429.                             break;
  1430.                         default:
  1431.                             break;
  1432.                         }   
  1433.                         /* staalesc 13/12/95: Place the whole expression inside its own box */
  1434.                         next = NewBox(token_font);
  1435.                         next->type = BOX;
  1436.         next->emph = emph;
  1437.                         next->dx = basex;
  1438.                         next->dy = 0;
  1439.                         next->above = box->above;
  1440.                         next->below = box->below;
  1441.                         next->w = x - basex;
  1442.                         next->next = box;
  1443.                         box = next;
  1444.                         emph = oldemph;
  1445.                         above = max(above, next->above);
  1446.                         below = max(below, next->below);
  1447.                     }
  1448.                 }
  1449.                 break;
  1450.     case TAG_ABOVE:
  1451. if (token_code != ENDTAG)
  1452. {
  1453.                     int newemph = 0;
  1454.     ParseAboveAttrs (&newemph);
  1455.     limits = token_align;
  1456.     basex = x;
  1457.     baseleft = baseright = baseup = basedown = 0;
  1458.     next = ParseExpr (size, TAG_ABOVE, emph, &endtag);
  1459.     if (next)
  1460.     {
  1461. next->dx = x;
  1462. next->dy = 0;
  1463. next->above = token_above;
  1464. next->below = token_below;
  1465. next->next = box;
  1466. box = next;
  1467. x += next->w;
  1468.                         /* staalesc 13/12/95: Place the whole expression inside its own box */
  1469.                         next = NewBox(token_font);
  1470.                         next->type = BOX;
  1471.         next->emph = newemph;
  1472.                         next->dx = basex;
  1473.                         next->dy = 0;
  1474.                         next->above = box->above;
  1475.                         next->below = box->below;
  1476.                         next->w = x - basex;
  1477.                         next->next = box;
  1478.                         box = next;
  1479. above = max(above, next->above);
  1480. below = max(below, next->below);
  1481.     }
  1482. }
  1483. break;
  1484.     case TAG_BELOW:
  1485. if (token_code != ENDTAG)
  1486. {
  1487.                     int newemph = 0;
  1488.     ParseBelowAttrs (&newemph);
  1489.     limits = token_align;
  1490.     basex = x;
  1491.     baseleft = baseright = baseup = basedown = 0;
  1492.     next = ParseExpr (size, TAG_BELOW, emph, &endtag);
  1493.     if (next)
  1494.     {
  1495. next->dx = x;
  1496. next->dy = 0;
  1497. next->above = token_above;
  1498. next->below = token_below;
  1499. next->next = box;
  1500. box = next;
  1501. x += next->w;
  1502.                         /* staalesc 13/12/95: Place the whole expression inside its own box */
  1503.                         next = NewBox(token_font);
  1504.                         next->type = BOX;
  1505.         next->emph = newemph;
  1506.                         next->dx = basex;
  1507.                         next->dy = 0;
  1508.                         next->above = box->above;
  1509.                         next->below = box->below;
  1510.                         next->w = x - basex;
  1511.                         next->next = box;
  1512.                         box = next;
  1513. above = max(above, next->above);
  1514. below = max(below, next->below);
  1515.     }
  1516. }
  1517. break;
  1518.             case NAME:
  1519.                 limits = token_align;
  1520.                 basex = x;
  1521.                 baseleft = baseright = baseup = basedown = 0;
  1522.                 next = NewBox(token_font);
  1523.                 next->font = token_font;
  1524.                 next->type = NAME;
  1525.                 next->str = token_str;
  1526.                 next->len = token_len;
  1527. next->emph = emph;
  1528.                 next->dx = x;
  1529.                 next->dy = 0;
  1530.                 next->above = token_above;
  1531.                 next->below = token_below;
  1532.                 next->w = token_width;
  1533.                 next->next = box;
  1534.                 box = next;
  1535.                 x += box->w;
  1536.                 above = max(above, token_above);
  1537.                 below = max(below, token_below);
  1538.                 break;
  1539.             case FUNC:
  1540.                 limits = token_align;
  1541.                 basex = x;
  1542.                 baseleft = baseright = baseup = basedown = 0;
  1543.                 next = NewBox(token_font);
  1544.                 next->font = token_font;
  1545.                 next->type = FUNC;
  1546.                 next->code = token_code;
  1547. next->emph = emph;
  1548.                 next->dx = x;
  1549.                 if (next->code == LIM)
  1550.                     next->dy = divide_base(next->font);  /* staalesc 13/12/95 */
  1551.                 else
  1552.                     next->dy = 0;
  1553.                 next->above = token_above;
  1554.                 next->below = token_below;
  1555.                 next->w = token_width;
  1556.                 next->next = box;
  1557.                 box = next;
  1558.                 x += box->w;
  1559.                 above = max(above, token_above + box->dy);
  1560.                 below = max(below, token_below - box->dy);
  1561.                 break;
  1562.             case OPERATOR:
  1563.                 if (token_code=='=')
  1564.                     token_align = ALIGN_CENTER;  /* staalesc 13/12/95 */
  1565.                 limits = token_align;
  1566.                 basex = x;
  1567.                 baseleft = baseright = baseup = basedown = 0;
  1568.                 next = NewBox(token_font);
  1569.                 next->type = OPERATOR;
  1570.                 next->code = token_code;
  1571. next->emph = emph;
  1572.                 if (next->code == '.')
  1573.                     x -= Space(token_font);  /* staalesc 13/12/95 */
  1574.                 next->dx = x;
  1575.                 next->dy = 0;
  1576.                 next->above = token_above;
  1577.                 next->below = token_below;
  1578.                 next->w = token_width;
  1579.                 next->next = box;
  1580.                 box = next;
  1581.                 x += box->w+2;
  1582.                 above = max(above, token_above);
  1583.                 below = max(below, token_below);
  1584.                 break;
  1585.             case RADICAL:
  1586.             case DELIM:
  1587.             case SYM:
  1588.                 if (token_code==174 || token_code==222 || token_code==219)
  1589.                     token_align = ALIGN_CENTER;  /* staalesc 13/12/95 */
  1590.                 limits = token_align;
  1591.                 basex = x;
  1592.                 baseleft = baseright = baseup = basedown = 0;
  1593.                 next = NewBox(token_font);
  1594.                 next->type = token;
  1595.                 next->code = token_code;
  1596.                 next->subcode = token_subcode;
  1597. next->emph = emph;
  1598.                 next->dx = x;
  1599.                 next->dy = 0;
  1600.                 next->above = token_above;
  1601.                 next->below = token_below;
  1602.                 next->w = token_width;
  1603.                 next->next = box;
  1604.                 box = next;
  1605.                 x += box->w;
  1606.                 above = max(above, token_above);
  1607.                 below = max(below, token_below);
  1608.                 break;
  1609.     case TAG_MATH:
  1610.     case TAG_LEFT:
  1611.     case TAG_RIGHT:
  1612. SwallowAttributes ();
  1613. break;
  1614.         }
  1615.     }
  1616.  /* place non-atomic expression in a box */
  1617.     if (box)
  1618.     {
  1619.         if (box->next != NULL || box->indices != NULL)
  1620.         {
  1621.             next = NewBox(TextFont(size, current_font_tag));
  1622.             next->type = BOX;
  1623.             next->base = box;
  1624.             box = next;
  1625.         }
  1626.         box->w = x;
  1627.         box->above = above;
  1628.         box->below = below;
  1629.     }
  1630.     return box;
  1631. }
  1632. static void PutChar(Frame *frame, int emph, int font, char c, int x, int y)
  1633. {
  1634.     PutText(frame, emph, font, &c, 1, x, y);
  1635. }
  1636. static void PrintStr(Frame *frame, Box *box, int x, int y)
  1637. {
  1638.     x += box->dx;
  1639.     y += box->dy;
  1640.     PutText(frame, box->emph, box->font, box->str, box->len, x, y);
  1641. }
  1642. /* added void before DrawBigSym wm 20.Jan.95 */
  1643. static void DrawBigSym(Frame *frame, Box *box, int x, int y, char topch, char middlech, char bottomch)
  1644. {
  1645.     int len, h, asc, desc, m;
  1646.     FontSize(box->font, &asc, &desc);
  1647.     h = asc + desc;
  1648.     y += box->above - asc;
  1649.     PutChar(frame, box->emph, box->font, topch, x, y);
  1650.     len = box->len;
  1651.     m = len/2;
  1652.     while (len-- > 0)
  1653.     {
  1654.         y -= h;
  1655.         /* staalesc 15/08/95: kludge for '{' and '}' */
  1656.         if ((len!=m) && ((box->subcode==123) || (box->subcode==125)))
  1657.             PutChar(frame, box->emph, box->font, 239, x, y);
  1658.         else
  1659.             PutChar(frame, box->emph, box->font, middlech, x, y);
  1660.     }
  1661.      y -= h;
  1662.     PutChar(frame, box->emph, box->font, bottomch, x, y);
  1663. }
  1664. static void PrintFunc(Frame *frame, Box *box, int x, int y)
  1665. {
  1666.   /* janet 21/07/95: not used:    int i; */
  1667.     char *s = NULL;
  1668.     x += box->dx;
  1669.     y += box->dy;
  1670.     switch(box->code)
  1671.     {
  1672.         case INT:
  1673.             DrawBigSym(frame, box, x, y, 243, 244, 245);
  1674.             return;
  1675.         case SUM:
  1676.             PutChar(frame, box->emph, box->font, 229, x, y);
  1677.             return;
  1678.         case PROD:
  1679.             PutChar(frame, box->emph, box->font, 213, x, y);
  1680.             return;
  1681.         case LIM:
  1682.             s = "lim";
  1683.             break;
  1684.         case DOTS:
  1685.             s = "...";
  1686.             break;
  1687.     }
  1688.     PutText(frame, box->emph, box->font, s, strlen(s), x, y);
  1689. }
  1690. static void PrintSym(Frame *frame, Box *box, int x, int y)
  1691. {
  1692.   /*  janet 21/07/95: not used:   int i;   */
  1693.   /*  janet 21/07/95: not used:   char *s; */
  1694.     x += box->dx;
  1695.     y += box->dy;
  1696.     PutChar(frame, box->emph, box->font, box->code, x, y);
  1697. }
  1698. static void PrintOperator(Frame *frame, Box *box, int x, int y)
  1699. {
  1700.     x += box->dx;
  1701.     y += box->dy;
  1702.     PutChar(frame, box->emph, box->font, box->code, x, y);
  1703. }
  1704. static void PrintDelim(Frame *frame, Box *box, int x, int y)
  1705. {
  1706.   /*  janet 21/07/95: not used:   int i; */
  1707.     x += box->dx;
  1708.     y += box->dy;
  1709.     if (box->len > 0)
  1710.     {
  1711.         if (box->subcode == 124)  /* kludge for '|' */
  1712.             DrawBigSym(frame, box, x, y, box->code, box->code, box->code);
  1713.         else
  1714.             DrawBigSym(frame, box, x, y, box->code-1, box->code, box->code+1);
  1715.     }
  1716.     else
  1717.         PutChar(frame, box->emph, box->font, box->subcode, x, y);
  1718. }
  1719. static void RenderMath(Frame *frame, Box *box, int x, int y)
  1720. {
  1721.   /* janet 21/07/95: not used:    Box *indices; */
  1722.     if (box == NULL)
  1723.         return;
  1724.     RenderMath(frame, box->next, x, y);
  1725. /* staalesc: Uncomment this for debugging:
  1726.     PrintLine (frame,
  1727.                x + box->dx,
  1728.                x + box->dx + box->w,
  1729.        y + box->dy - box->below,
  1730.                y + box->dy - box->below);
  1731.     PrintLine (frame,
  1732.                x + box->dx,
  1733.                x + box->dx + box->w,
  1734.        y + box->dy + box->above,
  1735.                y + box->dy + box->above);
  1736.     PrintLine (frame,
  1737.                x + box->dx,
  1738.                x + box->dx,
  1739.        y + box->dy - box->below,
  1740.                y + box->dy + box->above);
  1741.     PrintLine (frame,
  1742.                x + box->dx + box->w,
  1743.                x + box->dx + box->w,
  1744.        y + box->dy - box->below,
  1745.                y + box->dy + box->above);
  1746. */
  1747.     switch(box->type)
  1748.     {
  1749.         case NAME:
  1750.             PrintStr(frame, box, x, y);
  1751.             break;
  1752.         case FUNC:
  1753.             PrintFunc(frame, box, x, y);
  1754.             break;
  1755.         case OPERATOR:
  1756.             PrintOperator(frame, box, x, y);
  1757.             break;
  1758.         case DELIM:
  1759.             PrintDelim(frame, box, x, y);
  1760.             break;
  1761.         case RADICAL:
  1762.             {
  1763. PrintLine (frame,
  1764.                            x + box->dx,
  1765.                            x + box->dx+2,
  1766.    y + box->dy - box->below + (box->above+box->below)/2,
  1767.                            y + box->dy - box->below + (box->above+box->below)/2 + 1);
  1768. PrintLine (frame,
  1769.                            x + box->dx+2,
  1770.                            x + box->dx+2 + (box->w-2)/3,
  1771.    y + box->dy - box->below + (box->above+box->below)/2,
  1772.                            y + box->dy - box->below + 1);
  1773. PrintLine (frame,
  1774.                            x + box->dx+2 + (box->w-2)/3,
  1775.                            x + box->dx + box->w,
  1776.    y + box->dy - box->below + 1,
  1777.                            y + box->dy + box->above);
  1778.             }
  1779.             break;
  1780.         case SYM:
  1781.             PrintSym(frame, box, x, y);
  1782.             break;
  1783.         case DIVIDER:
  1784.             PrintRule(frame, HLINE, x + box->dx, box->w, y + box->dy);
  1785.             break;
  1786.         case BOX:
  1787.     /* staalesc 13/12/95: Handle all the EMPH tags here */
  1788.     if (box->emph & EMPH_ROOTLINE) {
  1789. PrintRule (frame, HLINE, x + box->dx, box->w,
  1790.    y + box->dy + box->above);
  1791. PrintLine (frame, x + box->dx + box->w, x + box->dx + box->w,
  1792.    y + box->dy + box->above, y + box->dy + box->above - 2);
  1793.     }
  1794.     if (box->emph & EMPH_OVERLINE) {
  1795. PrintRule (frame, HLINE, x + box->dx, box->w,
  1796.    y + box->dy + box->above - 1);
  1797.     }
  1798.     if (box->emph & EMPH_OVERRARR) {
  1799. PrintRule (frame, HLINE, x + box->dx, box->w,
  1800.    y + box->dy + box->above - 1);
  1801. PrintLine (frame, x + box->dx + box->w, x + box->dx + box->w - 2,
  1802.    y + box->dy + box->above - 1, y + box->dy + box->above - 3);
  1803.         PrintLine (frame, x + box->dx + box->w, x + box->dx + box->w - 2,
  1804.    y + box->dy + box->above - 1, y + box->dy + box->above + 1);
  1805.     }
  1806.     if (box->emph & EMPH_OVERLARR) {
  1807. PrintRule (frame, HLINE, x + box->dx, box->w,
  1808.    y + box->dy + box->above - 1);
  1809. PrintLine (frame, x + box->dx, x + box->dx + 2,
  1810.    y + box->dy + box->above - 1, y + box->dy + box->above - 3);
  1811.         PrintLine (frame, x + box->dx, x + box->dx + 2,
  1812.    y + box->dy + box->above - 1, y + box->dy + box->above + 1);
  1813.     }
  1814.     if (box->emph & EMPH_UNDERLINE) {
  1815. PrintRule (frame, HLINE, x + box->dx, box->w,
  1816.    y + box->dy - box->below - 1);
  1817.     }
  1818.     if (box->emph & EMPH_UNDERRARR) {
  1819. PrintRule (frame, HLINE, x + box->dx, box->w,
  1820.    y + box->dy - box->below - 1);
  1821. PrintLine (frame, x + box->dx + box->w, x + box->dx + box->w - 3,
  1822.    y + box->dy - box->below - 1, y + box->dy - box->below - 3);
  1823.         PrintLine (frame, x + box->dx + box->w, x + box->dx + box->w - 2,
  1824.    y + box->dy - box->below - 1, y + box->dy - box->below + 1);
  1825.     }
  1826.     if (box->emph & EMPH_UNDERLARR) {
  1827. PrintRule (frame, HLINE, x + box->dx, box->w,
  1828.    y + box->dy - box->below - 1);
  1829. PrintLine (frame, x + box->dx, x + box->dx + 2,
  1830.    y + box->dy - box->below - 1, y + box->dy - box->below - 3);
  1831.         PrintLine (frame, x + box->dx, x + box->dx + 2,
  1832.    y + box->dy - box->below - 1, y + box->dy - box->below + 1);
  1833.     }
  1834.     RenderMath(frame, box->base, x + box->dx, y + box->dy);
  1835.             break;
  1836.     }
  1837.     RenderMath(frame, box->indices, x + box->dx, y);
  1838. }
  1839. /* shouldn't BoxFree be freeing more than b->next? */
  1840. void BoxFree(Box *b)
  1841. {
  1842.   if (b->next) 
  1843.     BoxFree(b->next);
  1844. #if 0
  1845.   else {
  1846.     Free(b->indices); /* janet 2/8/95: added  */
  1847.     Free(b->base);
  1848.     Free(b->str); 
  1849.     Free(b);
  1850.     return;
  1851.   }
  1852. */
  1853.   /* janet 2/8/95: added freeing base and indices too  */
  1854.   if (b->base)
  1855.     BoxFree(b->base);
  1856.   else
  1857.     return;
  1858.   
  1859.   if (b->indices)
  1860.     BoxFree(b->indices);
  1861.   else
  1862.     return;
  1863.   
  1864.   Free(b->next);  /* janet: what about free(b->indices), free(b->base), free(b->str), free(b) ?*/
  1865.   b->next = NULL;
  1866. #endif 
  1867.   if (b->indices)
  1868.     BoxFree(b->indices); /* janet 2/8/95: added  */
  1869.   if (b->base)
  1870.     BoxFree(b->base);
  1871.   /*   Free(b->str); */
  1872.   Free(b);
  1873. }
  1874. #define IDX_IFIXEDFONT         10
  1875. void ParseMath(Frame *frame, int *up, int *down)
  1876. {
  1877.     int endtag;
  1878.     Box *box;
  1879.     box = ParseExpr(NORMAL, TAG_MATH, EMPH_NORMAL, &endtag); /* purify: box and it's children has allocated memory */
  1880.     /* howcome 16/3/95: added test for box existance, but why doesn't <MATH></MATH> render properly? */
  1881.     if (box) { 
  1882. RenderMath(frame, box, Here, 0);
  1883. *up = box->above;
  1884. *down = box->below;
  1885. Here += box->w;
  1886.     }
  1887.     BoxFree(box);  /* janet: something is not being freed here, what? (64 bytes)*/
  1888. }