File r38/lisp/csl/cslbase/FXShowMath.cpp artifact 6e73a3aa9a part of check-in 3af273af29


//
// "FXShowMath.cpp"                       Copyright A C Norman 2004-2007
//
//
// Code to layout mathematical formulae for display. Formulae are
// described in a TeX-like style. This REQUIRES some Computer Modern
// typefaces to be available.
//

/******************************************************************************
* Copyright (C) 2004 by Arthur Norman, Codemist Ltd.     All Rights Reserved. *
*******************************************************************************
* This library is free software; you can redistribute it and/or               *
* modify it under the terms of the GNU Lesser General Public                  *
* License as published by the Free Software Foundation;                       *
* version 2.1 of the License.                                                 *
*                                                                             *
* This library is distributed in the hope that it will be useful,             *
* but WITHOUT ANY WARRANTY; without even the implied warranty of              *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU           *
* Lesser General Public License for more details.                             *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public            *
* License along with this library; if not, write to the Free Software         *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.  *
*                                                                             *
* See also the FOX Toolkit addendum to the LGPL, which also applies to this   *
* code. This addedum gives, in addition to the rights granted by the LGPL,    *
* permission to distribute this code statically linked against other code     *
* without any need for that other code to have its source released.           *
******************************************************************************/


/* Signature: 1fc4a0cf 04-Jan-2008 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifndef HAVE_LIBFOX

char FXShowMath_msg[] = "No FOX so no FXShowMath";

#else

#ifdef HAVE_XFT
#include <X11/Xft/Xft.h>
#endif

#include "fwin.h"
#include <fx.h>

#if FOX_MAJOR==1 && FOX_MINOR==0
#  define FXSEL(a,b) MKUINT(a,b)
#endif

#include <fxkeys.h>          // not included by <fx.h>

#include "fwin.h"

#include "FXTerminal.h"
#include "FXShowMath.h"
#include "FXDCNativePrinter.h"

#include <stdlib.h>

extern "C" {
extern int directoryp(char *a, char *b, size_t n);
extern int file_readable(char *a, char *b, size_t n);
}

#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdarg.h>

#ifdef WIN32
#else
#include <X11/Xlib.h>
#endif

static int DEBUGFONT = 0;

// I make the size of my memory pool depend on the size of a pointer
// because the size of box components depends on that. The setting here
// will use 128K on a 32-bit machine or 256K on a 64-bit one and will
// cache around say 80 full lines of maths display. Beyond that the
// system would need to re-parse for redisplay.

#define memoryPoolSize (0x4000*sizeof(void *))

static void *memoryPool = NULL;
static unsigned int memoryPoolIn, memoryPoolOut;

int handleFromPoolPointer(Box *p)
{
    return (int)((char *)p - (char *)memoryPool);
}

Box *poolPointerFromHandle(int i)
{
    return (Box *)((char *)memoryPool + i);
}

static void setupMemoryPool()
{
    memoryPool = (void *)malloc(memoryPoolSize);
    if (memoryPool == NULL)
    {   printf("Failed to allocate memory\n");
        exit(1);
    }
    memoryPoolIn = memoryPoolOut = 0;
}

static void poolDestroyChunk();

static void *poolAllocate(unsigned int n)
{
    if (n >= memoryPoolSize) return NULL;
    for (;;)
    {   int spare = memoryPoolOut - memoryPoolIn;
        if (spare <= 0) spare += memoryPoolSize;
        if (n < (unsigned int)spare) break;
        poolDestroyChunk();
    }
    unsigned int next = memoryPoolIn + n;
    if (next > memoryPoolSize)
    {   while (memoryPoolOut > memoryPoolIn) poolDestroyChunk();
        memoryPoolIn = 0;
        while (memoryPoolOut <= n) poolDestroyChunk();
        next = n;
    }
    void *r = (void *)((char *)memoryPool + memoryPoolIn);
    memoryPoolIn = next;
    return r;
}

struct IntVoidStar
{
    void *v;
    int i;
};

static void *chunkStart;

// Memory for a single formula will live in a "chunk", and chunks run
// cyclically around a region of memory. If at any stage I try to make a
// new chunk grow so that it would wrap round and overlap an earlier-allocated
// one I will discard that earlier chunk. When I do so I notify its "owner"
// so that they will not rely on it after its demise.

static void *poolStartChunk(int owner)
{
    chunkStart = poolAllocate(sizeof(struct IntVoidStar));
    IntVoidStar *rp = (IntVoidStar *)chunkStart;
    rp->i = owner;
    rp->v = NULL;
    return chunkStart;
}

static void poolEndChunk()
{
    IntVoidStar *rp = (IntVoidStar *)chunkStart;
    rp->v = (void *)((char *)memoryPool + memoryPoolIn);
}

static void poolDestroyChunk()
{
    if ((void *)((char *)memoryPool + memoryPoolOut) == chunkStart)
    {   printf("Attempt to create over-large chunk\n");
        exit(1);
    }
    IntVoidStar *rp = (IntVoidStar *)((char *)memoryPool + memoryPoolOut);
    reportDestroy(rp->i); // inform owner
    memoryPoolOut = (int)((char *)rp->v - (char *)memoryPool);
}

typedef struct TexState
{
    unsigned char currentFont;
    unsigned char insideFrac;
} TeXState;

TeXState currentState;

#define currentSize (currentState.currentFont & FontSizeMask)


// Some types. I have capacity in my encoding for up to 16 types of box.

#define BoxText        0x00
#define BoxNest        0x01
#define BoxNest3       0x02
#define BoxSym         0x03
#define BoxBracket     0x04
#define BoxMatrix      0x05
#define BoxFrame       0x06
#define BoxTop         0x07

#define NestMask       0xf0  // I use 0x0c bits for size information...
#define BoxTower       0x00  // one item over another, does not centre items
#define BoxStack       0x10  // one item over another, centred
#define BoxFraction    0x20  // one item over another, centred & with f-bar
#define BoxBeside      0x30
#define BoxAdjacent    0x40  // just like Beside, but moves boxes closer
#define BoxSubscript   0x50
#define BoxSuperscript 0x60
#define BoxBothScripts 0x70
#define BoxOverstrike  0x80
#define BoxPadSpace    0x90

#define SymTypeMask    0xf0
#define SymStar        0x00
#define SymComma       0x10
#define SymExclam      0x20
#define SymColon       0x30
#define SymSemiColon   0x40
#define SymBlank       0x50
#define SymNothing     0x60
#define SymUnderscore  0x70
#define SymRule        0x80

static Box *makeSymBox(int type)
{
    Box *b = (Box *)poolAllocate(sizeof(SymBox));
    b->text.type = BoxSym;
    b->text.flags = type + currentSize;
    b->text.height = 0;
    b->text.depth = 0;
    b->text.width = 0;
    return b;
}

Box *makeTextBox(const char *s, int n, int fontStyle)
{
    char *ss = (char *)poolAllocate(n+1);
    Box *b = (Box *)poolAllocate(sizeof(TextBox));
    memcpy(ss, s, n+1);
    b->text.type = BoxText;
    b->text.flags = fontStyle;
    b->text.height = 0;
    b->text.depth = 0;
    b->text.width = 0;
    b->text.n = n;
    b->text.text = ss;
    return b;
}

static Box *makeBracketBox(Box *b1, char left, char right)
{
    Box *b = (Box *)poolAllocate(sizeof(BracketBox));
    b->bracket.type = BoxBracket;
    b->bracket.flags = currentSize;
    b->bracket.height = 0;
    b->bracket.depth = 0;
    b->bracket.width = 0;
    b->bracket.sub = b1;
    b->bracket.leftBracket = left;
    b->bracket.rightBracket = right;
    b->bracket.dx = 0;
// \sqrt[n] will fill in any extra by hand...
    b->bracket.dx1 = 0;
    b->bracket.dy1 = 0;
    b->bracket.sub1 = NULL;
    return b;
}

static Box *makeMatrixBox(Box *b1)
{
    Box *b = (Box *)poolAllocate(sizeof(MatrixBox));
    b->matrix.type = BoxMatrix;
    b->matrix.flags = currentSize;
    b->matrix.height = 0;
    b->matrix.depth = 0;
    b->matrix.width = 0;
    b->matrix.sub = b1;
    b->matrix.dy = 0;
    return b;
}

static Box *makeNestBox(int style, Box *b1, Box *b2)
{
    Box *b = (Box *)poolAllocate(sizeof(NestBox));
    b->nest.type = BoxNest;
    b->nest.flags = style + currentSize;
    b->nest.height = 0;
    b->nest.depth = 0;
    b->nest.width = 0;
    b->nest.sub1 = b1;
    b->nest.sub2 = b2;
    b->nest.dx1 = b->nest.dy1 = 0;
    b->nest.dx2 = b->nest.dy2 = 0;
    return b;
}

static Box *makeNest3Box(int style, Box *b1, Box *b2, Box *b3)
{
    Box *b = (Box *)poolAllocate(sizeof(NestBox3));
    b->nest3.type = BoxNest3;
    b->nest3.flags = style + currentSize;
    b->nest3.height = 0;
    b->nest3.depth = 0;
    b->nest3.width = 0;
    b->nest3.sub1 = b1;
    b->nest3.sub2 = b2;
    b->nest3.sub3 = b3;
    b->nest3.dx1 = b->nest3.dy1 = 0;
    b->nest3.dx2 = b->nest3.dy2 = 0;
    b->nest3.dx3 = b->nest3.dy3 = 0;
    return b;
}

static Box *makeFrameBox(Box *b0)
{
    Box *b = (Box *)poolAllocate(sizeof(FrameBox));
    b->frame.type = BoxFrame;
    b->frame.flags = currentSize;
    b->frame.height = 0;
    b->frame.depth = 0;
    b->frame.width = 0;
    b->frame.sub = b0;
    return b;
}

static Box *makeTopBox(Box *b0)
{
    Box *b = (Box *)poolAllocate(sizeof(TopBox));
    b->top.type = BoxTop;
    b->top.flags = currentSize;
    b->top.height = 0;
    b->top.depth = 0;
    b->top.width = 0;
    b->top.sub = b0;
    b->top.chunk = chunkStart;
    b->top.measuredSize = -1;
    return b;
}

///////////////////////////////////////////////////////////////////////////

// I will use (up to) 36 fonts here:
//               Roman, Maths-italic, Symbol, Extra
// with each in main, subscript and sub-subscript sizes, but with
// a range of possible scales

// I have a set of metrics for the Computer Modern fonts that I use. They
// were extracted from the associated "AFM" files, but converted into
// static C tables for quick access. The table does not provide full
// information - it gives bounding boxes for the font as a whole together
// with widths of individual characters. At least at present I do not record
// individual character heights or kerning information there.

#include "cmfont-info.c"

static cm_font_info *findFont(const char *name)
{
    char ss[32];
    strcpy(ss, name);
// The info in the table has names in upper case. So I will force the
// name in my request to be in upper case to match.
    for (char *p=ss; *p!=0; p++) *p = toupper(*p);
    for (unsigned int i=0; i<sizeof(cm_font_widths)/sizeof(cm_font_info); i++)
    {   if (strcmp(ss, cm_font_widths[i].name) == 0)
            return &cm_font_widths[i];
    }
    return NULL;
}


// The master set of fonts, covering all scales. I extract relevant
// into into mathFont etc as necessary. If printDC is not NULL I will
// suppose I am in the middle of printing something and will use it, rather
// then the screen-access procedures that I normally use. In the printDC
// case I will use real local fonts in a Windows case when I am printing
// to a windows printing device context, but when using ANY sort of system
// if I am trying to generate Postscript I will use AFM metrics for the
// mathematical fonts that I want. In such case I will want the "font" to
// be a reference to the metric tables together with some scale information.

// @@@@ I will work on WINDOWS printing first... and assume that under Windows
// I am necessarily using a direct printer device context...

FXDCNativePrinter *printDC = NULL;

int mathFontSize = -1;
void       *masterFont[36];
static int masterFontHeight[36];
static int masterFontDepth[36];
static int masterFontWidth[36];
static cm_font_info *masterFontFontInfo[36];

// The array "font" will either hold FXFont or XftFont references
// and fwin_use_xft will discriminate about which to use. The arrays and
// variables here relate to the fonts in use at the current scale.

void       *mathFont[12];
int mathWidth;
static int mathFontHeight[12];
static int mathFontDepth[12];
static int mathFontWidth[12];
static cm_font_info *mathFontFontInfo[12];

// The next few are no longer used...
//  static int regHeight, scriptHeight, scriptScriptHeight;
//  static int regDepth, scriptDepth, scriptScriptDepth;
//  static int regWidth, scriptWidth, scriptScriptWidth;

// Short-hand to reference individual fonts.

#define frm   mathFont[FntRoman+FntRegular]
#define fmi   mathFont[FntItalic+FntRegular]
#define fsy   mathFont[FntSymbol+FntRegular]
#define fex   mathFont[FntExtension+FntRegular]
#define fsrm  mathFont[FntRoman+FntScript]
#define fsmi  mathFont[FntItalic+FntScript]
#define fssy  mathFont[FntSymbol+FntScript]
#define fsex  mathFont[FntExtension+FntScript]
#define fssrm mathFont[FntRoman+FntScrScr]
#define fssmi mathFont[FntItalic+FntScrScr]
#define fsssy mathFont[FntSymbol+FntScrScr]
#define fssex mathFont[FntExtension+FntScrScr]

///////////////////////////////////////////////////////////////////////////

// When I select a font I want the version from that family that
// has design-size best matched to the size that it will appear.
// The scheme here recognises the variants made available with the
// Computer Modern set and selects what to use.

static const char *cmrSizesTable[] =
{   NULL, NULL, NULL, NULL, NULL,                    // for sizes 0,1,2,3,4
    "cmr5", "cmr6", "cmr7", "cmr8", "cmr9",          // 5, 6, 7, 8, 9
    "cmr10", "cmr10", "cmr12", "cmr12",              // 10, 11, 12, 13
    "cmr12", "cmr12"                                 // 14, 15
};

#define cmrSize(n) (fwin_use_xft ? "cmr10" : \
                    (n)<5 ? "cmr5" : \
                    (n) > 15 ? "cmr17" : cmrSizesTable[n])

static const char *cmmiSizesTable[] =
{   NULL, NULL, NULL, NULL, NULL,                    // for sizes 0,1,2,3,4
    "cmmi5", "cmmi6", "cmmi7", "cmmi8", "cmmi9",     // 5, 6, 7, 8, 9
    "cmmi10", "cmmi10"                               // 10, 11
};

#define cmmiSize(n) (fwin_use_xft ? "cmmi10" : \
                     (n)<5 ? "cmmi5" : \
                     (n) > 11 ? "cmmi12" : cmmiSizesTable[n])

static const char *cmsySizesTable[] =
{   NULL, NULL, NULL, NULL, NULL,                    // for sizes 0,1,2,3,4
    "cmsy5", "cmsy6", "cmsy7", "cmsy8", "cmsy9"      // 5, 6, 7, 8, 9
};

#define cmsySize(n) (fwin_use_xft ? "cmsy10" : \
                     (n)<5 ? "cmsy5" : \
                     (n) > 9 ? "cmsy10" : cmsySizesTable[n])

#define cmexSize(n) "cmex10"

#ifdef HAVE_XFT

// At some stage I may well move all of these to be fields within a
// suitable object, but while I only have ONE window on which I will
// display things using Xft I can make them simple static varaible and hence
// local to this file.

Display      *dpy = NULL;
int          screen;
XftDraw      *ftDraw = NULL;
Visual       *ftVisual = NULL;
Colormap     ftColormap;
XRenderColor ftRenderBlack = {0x0000, 0x0000, 0x0000, 0xffff};
XRenderColor ftRenderWhite = {0xffff, 0xffff, 0xffff, 0xffff};
XftColor     ftBlack, ftWhite;
XftFont      *ftFont = NULL;

#endif

static void *getMathsFont(FXApp *app,
                          const char *name, const char *fallback,
                          int size)
{
#ifdef HAVE_XFT
// With Xft I do not seem to have a good way to check exactly what
// font gets found, and so to try to guarantee the best sanity I can I have
// only got here if I was able to add the custom fonts that I wanted. And
// I then use my "fallback" font name here, which is the one that the
// custom fonts were intended to provide. Thus with Xft I will use exactly
// cmr10, cmmi10, cmsy10 and cmex10 and NEVER Computer Modern fonts at any
// other size. Note that HAVE_XFT or at least fwin_use_xft should never
// end up true in a Windows world.
    if (fwin_use_xft)
    {   return XftFontOpen(dpy, screen,
            XFT_FAMILY, XftTypeString, fallback,
            XFT_SIZE,   XftTypeDouble, 0.1*(double)size,
            (const char *)0);
    }
#endif
    FXFontDesc fd;
    FXFont *f;
    FXString an;
    for (int i=0;i<2;i++)
    {
        strcpy(fd.face, i==0 ? name : fallback);
        fd.size = size;                    // NB size is in DECIPOINTS here
#if (FOX_MINOR<=4)
        fd.weight = FONTWEIGHT_DONTCARE;
        fd.slant = FONTSLANT_DONTCARE;
        fd.setwidth = FONTSETWIDTH_DONTCARE;
        fd.encoding = FONTENCODING_DEFAULT;
        fd.flags = FONTPITCH_DEFAULT;
#else
        fd.weight = 0;
        fd.slant = 0;
        fd.setwidth = 0;
        fd.encoding = FONTENCODING_DEFAULT;
        fd.flags = 0;
#endif
        f = new FXFont(app, fd);
        f->create();
// Now I check that the "actual name" bears at least some resemblence
// to the name asked for... and if not I ask the user to install
// fonts properly. Note that there is a fallback font-name to use.
        char ucname[32], ucactual[32];
        strcpy(ucname, fd.face);
        an = f->getActualName();
        strcpy(ucactual, an.text());
        char *p;
        for (p=ucname; *p!=0; p++) *p = toupper(*p);
        for (p=ucactual; *p!=0; p++) *p = toupper(*p);
        if (strncmp(ucname, ucactual, strlen(ucname)) == 0) return f;
        delete f;
    }
// The error exit here ought only to occur when the X client and server
// are different machines and I am NOT able to use Xft. It could
// arise if the "r38.fonts" directory had not been properly set up.
    return NULL;
// I will NOT generate a diagnostic here, but I WILL try to report back
// at a higher level that all this fancy display stuff can not be supported.
//- printf("Font %s apparently not available\n", fd.face);
//- printf("Nearest match found was %s. Please review and\n", an.text());
//- printf("if necessary install the Computer Modern Fonts\n");
//- printf("Note that this font is needed on your X server,\n");
//- printf("typically the one whose screen you are looking at.\n");
//- fflush(stdout);
//- exit(1);
}

#if 0

static void showMetrics(int ch, void *ff)
{
// This uses  FOX calls to measure characters. The results come back in
// screen coordinates, which are typically pixels. At present this is ONLY
// used for debugging!
    char b[2];
    b[0] = ch;
#ifdef HAVE_XFT
    if (fwin_use_xft && printDC==NULL)
    {   printf("showMetric not done for Xft yet\n");
        return;
    }
#endif
    if (printDC==NULL)
    {   printf("Char %.2x font %p height = %d depth = %d width = %d\n",
             ch, ff,
             ((FXFont *)ff)->getTextHeight(b, 1),
             ((FXFont *)ff)->getFontDescent(),
             ((FXFont *)ff)->getTextWidth(b, 1));
    }
    else
    {   printDC->setFont((FXFont *)ff);
        printf("Char %.2x font %p height = %d depth = %d width = %d\n",
             ch, ff,
             (int)printDC->fntGetTextHeight(b, 1),
             (int)printDC->fntGetFontDescent(),
             (int)printDC->fntGetTextWidth(b, 1));
    }
    fflush(stdout);
}

#endif

// The next function may not be used right now, but when I start
// developing the Postscript printer support I will need it to help me
// debug things...

static void showAFMMetrics(int ch, int fn)
{
// This used the AFM data to try to compute sizes. The results are returned
// in points not pixels, and so are NOT compatible with the ones above. In
// particular scaling by a "pixels per point for this screen" would be
// needed to make them agree. At present if I apply such a scaling (by hand)
// I think that widths then match, but I am still confused about heights and
// depths. Only used for debugging at present.
    cm_font_info *fi = masterFontFontInfo[fn];
    int cap=fi->capheight, x=fi->xheight,
        asc=fi->ascent, desc=fi->descent;
    int w = fi->charwidth[ch & 0xff];
    printf("Char %.2x font %x2 capH=%d xH=%d ascent=%d descent=%d width=%d\n",
         ch, fn, cap, x, asc, desc, w);
    fflush(stdout);
}


// LONGEST_LEGAL_FILENAME is a distinct HACK, and although on early versions
// of Windows there was a limit, with XP at least very long file paths are
// possible - and by exceeding this limit they could cause crashes. Tough
// Luck for now!

#ifndef LONGEST_LEGAL_FILENAME
#define LONGEST_LEGAL_FILENAME 1024
#endif

typedef struct localFonts
{
    const char *name;
    char *path;
} localFonts;

static localFonts fontNames[] =
{
    {"cmex10", NULL},
    {"cmmi10", NULL},
    {"cmr10",  NULL},
    {"cmsy10", NULL}
};

#ifdef WIN32
static HMODULE gdi32 = NULL;

typedef int FontResourceExType(
                LPCTSTR lpszFilename, // font file name
                DWORD fl,             // font characteristics
                PVOID pdv);           // reserved


// The next two flags instruct AddFontResourceEx that a font should be
// available only to this application and that other application should
// not even be able to see that it exists. I provide definitions here
// in case MinGW32 does not have them in its header files.
#ifndef FR_PRIVATE
#define FR_PRIVATE   0x10
#endif
#ifndef FR_NOT_ENUM
#define FR_NOT_ENUM  0x20
#endif
#define PRIVATE_FONT (FR_PRIVATE | FR_NOT_ENUM)

FontResourceExType *addFontEx = NULL;

static void unloadFonts(FXApp *appl)
{
// I have had some pain with this code! So my FIRST change was that under
// Windows 2000 and XP when the "Ex" version of AddFontResource is available
// I just do not even try to unload the fonts. That should not be
// damaging because in that case I have made them local to the current
// application and not enumerable by other applications, and because in that
// case Windows should discard then when my application exits.
//
// Under older versions of Windows I maybe ought to try to remove them,
// but I will in fact cop out and leave them present (and visible to others)
// until the computer concerned is next re-booted.
    return;
#ifdef SKETCH_CODE_THAT_IS_NOT_USED_AT_PRESENT
// When I tried activating this code I saw crashes that I had difficulty
// understanding. And so I will just leave local fonts under XP etc to be
// tidied up by the operating system, and leave my Maths fonts still
// loaded under 95/98.
    if (gdi32 == NULL) return;
    int unloaded = 0;
    for (int i=0; i<(int)(sizeof(fontNames)/sizeof(fontNames[0])); i++)
    {   if (fontNames[i].path == NULL) continue;
// If the font had been added using AddFontResourceEx then when the
// application closes it will automatically get unloaded for me, so I will
// not put any effort into removing it here. If however I had used the
// older-style AddFontResource (NB no "Ex") as on W95, W98, then I will
// unload it now.
        if (addFontEx == NULL)
        {   RemoveFontResource(fontNames[i].path);
            unloaded = 1;
        }
        free(fontNames[i].path);
        fontNames[i].path = NULL;
    }
    if (unloaded) SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
    FreeLibrary(gdi32);
    gdi32 = NULL;
#endif
}

static int fontNeeded = 0;

static int CALLBACK fontEnumProc(
    const LOGFONTA *lpelfe,     // logical-font data
    const TEXTMETRICA *lpntme,  // physical-font data
    DWORD FontType,             // type of font
    LPARAM lParam)              // application-defined data
{
    fontNeeded = 0;
    return 0;
}

#else  // WIN32

int nExistingPaths = 0;
char **existingPaths = NULL;
char **localPathP = NULL;

static void unloadFonts(FXApp *appl)
{
    if (!fwin_use_xft)
    {   XSetFontPath((Display *)appl->getDisplay(),
                     existingPaths, nExistingPaths);
        XFreeFontPath(existingPaths);
        free(localPathP);
    }
}

#endif // WIN32

#ifdef HAVE_XFT

static FT_UInt glyphs[100];

static int unmap(int ch);

static int convertGlyphs(const char *s, int len)
{
    if (len > 100) len = 100;
    for (int i=0; i<len; i++)
        glyphs[i] = (unmap(s[i]) & 0xff) + 1;
    return len;
}

static int xfWidth(void *ff, const char *s, int len)
{
    XGlyphInfo w;
    len = convertGlyphs(s, len);
    XftGlyphExtents(dpy, (XftFont *)ff, glyphs, len, &w);
// Observe that I believe that I want xOff, the "advance" figure, rather
// than width here.
    return w.xOff;
}

#endif

static void loadPrivateFonts(FXApp *appl)
{
    for (int i=0; i<12; i++) mathFont[i] = NULL;
    for (int i=0; i<36; i++) masterFont[i] = NULL;
// I want to ensure that the fonts needed will be available. On both
// Windows and X11 there are awkwardnesses about this:
// [Windows] AddFontResourceEx is only available on NT, 2000, XP, not
//           on earlier systems.
//           AddMemFontResource can only add TrueType fonts, and also
//           does not support older systems.
//           Two nuisances emerge from this. (a) the font resources
//           have to be in the form of a set of file on disc; (b) the
//           fonts that I temporarily install will be visible to and
//           enumerable by all aother applications. I work round this
//           by making a dynamic search for "AddFontResourceEx" in the
//           "gdi32" DLL and using it if it is found. So on NT/2000/XP
//           other applications will not be disturbed by any of my private
//           fonts.
// [X11]     A really very much want to have some of the Computer Modern
//           maths fonts available to me. Because with X there is a logical
//           distinction between the X server and client, using traditional
//           X would mean that I would HAVE To have those fonts installed on
//           the server - which is remote from the client upon which my code
//           runs. So when it is available and unless the user has asked me
//           not to I will use Xft and the Render extension to do client-
//           side rendering. This is a fairly recent development in X and
//           so may not always be available. Also it puts extra communication
//           load on the client-server link so may not be nice when using
//           a slow network. Font naming under Xft/fontconfig is very
//           different from the older model, and my code here only attempts
//           to access my own private Truetype/Type1 version of the CM fonts,
//           where I have taken trouble to ensure that their Truetype names
//           are set in the way I want them to be.
//           I seem to be having some delicacies about character encoding
//           and Xft. I work around this by assuming that the fonts I will
//           use with Xft are JUST the ones that I supply, and I then use
//           Glyph rather than Text access. BEWARE that trying to use
//           fonts other than the ones I supply will cause trouble.
//
// My private font directory contains just 4 fonts
//    cmr10   cmmi10   cmsy10   cmex10
// BUT when I am going to display things on the screen and unless I am
// using Xft I will try to use any from
//      cmr5, 6, 7, 8, 9, 10, 12, 17
//      cmmi5, 6, 7, 8, 9, 10, 12
//      cmsy5, 6, 7, 8, 9, 10
//      cmex10
// which come in the AMS set of Computer Modern Fonts, which can be
// downloaded freely either directly from AMS or from any major TeX
// archive. So if those extended fonts are installed you may get slightly
// more refined presentation on some platforms.
//
#ifdef WIN32
    addFontEx = NULL;
    gdi32 = LoadLibrary("Gdi32.dll");
    if (gdi32 != NULL)
    {   addFontEx = (FontResourceExType *)
            GetProcAddress(gdi32, "AddFontResourceExA");
// NB the "A" on the end of the name selects the ANSI rather than the Unicode
// variant.
        if (addFontEx == NULL)   // Sorry not available
        {   FreeLibrary(gdi32);
            gdi32 = NULL;
        }
    }

    HDC hDC = CreateCompatibleDC(NULL);
    LOGFONT lf;
// I check each of the fonts that this application wants to see if they
// are already installed. If they are then there is no merit in installing
// them for myself.
    int newFontAdded = 0;
    for (int i=0; i<(int)(sizeof(fontNames)/sizeof(fontNames[0])); i++)
    {   strcpy(lf.lfFaceName, fontNames[i].name);
        lf.lfCharSet = DEFAULT_CHARSET;
        lf.lfPitchAndFamily = 0;
        fontNeeded = 1;
        fontNames[i].path = NULL;
        EnumFontFamiliesEx(hDC, &lf, fontEnumProc, 0, 0);
        if (!fontNeeded) continue;
        char *ff = (char *)malloc(strlen(programDir) +
                                  strlen(fontNames[i].name)+16);
        strcpy(ff, programDir);
        strcat(ff, "\\r38.fonts\\");
        strcat(ff, fontNames[i].name); strcat(ff, ".ttf");
        DWORD attributes = GetFileAttributes(ff);
// If the file I want to use is not present I will not even try to add it as
// a font resource. I want to move this code towards being silent in use so
// the printf() statements I had when I was first debugging this are going
// away.
        if (attributes != INVALID_FILE_ATTRIBUTES &&
            (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
        {   fontNames[i].path = ff;
            if (addFontEx != NULL)
            {   if ((*addFontEx)(ff, PRIVATE_FONT, 0) == 0)
                {   continue;
                    printf("Failed to add font %s\n", ff);
                    fflush(stdout);
                }
            }
            else if (AddFontResource(ff) == 0)
            {   continue;
                printf("Failed to add font %s\n", ff);
                fflush(stdout);
            }
            newFontAdded = 1;
        }
    }
    DeleteDC(hDC);
    if (newFontAdded) SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
#else // WIN32
    nExistingPaths = 0;
    existingPaths = NULL;
    localPathP = NULL;
    if (fwin_use_xft)
    {   // I have already fudged the Xft font-access configuration so
        // that ONLY my own fonts will be available.
    }
    else
    {
// On traditional X11 I will always just append my own font directory at the
// end of the existing font search path. The means that fonts already
// installed on the system will take precedence (I will suppose that they
// had been installed properly!). This lets anybody who has better-hinted
// versions of the CM fonts use them. But if they play that game they had
// BETTER ensure that their font is compatible with the one I use in all
// respects.
        existingPaths = XGetFontPath((Display *)appl->getDisplay(), &nExistingPaths);
        char localPath[LONGEST_LEGAL_FILENAME], lp1[LONGEST_LEGAL_FILENAME];
        sprintf(localPath, "%s/r38.fonts/", programDir);
// Note that the fonts live in "r38.fonts" whatever the name of my executable
// is. If this does not exist or is not a directory I will not even try to
// add it to the fonts path. However the code here does not do anything to
// verify that the directory contains sensible things.
        if (directoryp(lp1, localPath, strlen(localPath)))
        {   localPathP = (char **)malloc((nExistingPaths+1)*sizeof(char *));
            for (int j=0; j<nExistingPaths; j++)
                localPathP[j] = existingPaths[j];
            localPathP[nExistingPaths] = &localPath[0];
            XSetFontPath((Display *)appl->getDisplay(),
                         localPathP, nExistingPaths+1);
        }
    }
#endif // WIN32
}

static double scaleTable[9] =
{
    1.0,
    1.1892,
    1.4142,
    1.6818,
    2.0,
    2.3784,
    2.8282,
    3.3636,
    4.0
};

// this returns 0 if it fails.
int changeMathFontSize(FXApp *appl, int mainSize)
{
    void *previousFont[36];
// I keep the current fonts until I have managed to open a new set, This
// may use up extra memory etc but is done so I can fall-back to retaining
// the existing set if something fails.
    for (int i=0; i<36; i++)
        previousFont[i] = masterFont[i];
// The user can pass a "main size" explicitly (in decipoints), but a negative
// argument instead specifies the width of the window, and I try to match
// that against 80 "M" in a half-sized font. The effect should be that SMALL
// mathematical formulae get displayed using a font that would fit around
// 40 of its widest characters across the screen, and around 60 or so
// "average width" chars. I think that seems reasonably visually pleasing...
    if (mainSize < 0)  // select font size based on screen width
    {   int sw = -mainSize;
#define probeSize 400
// I do things in two stages here, so I need to explain why!
// I first work in terms of a main font at 40 points and hence a "subscript"
// one at 28 points. I argue that at most plausible screen resolutions the
// width of an "M" here will be enough pixels that measurements will not be
// too badly corrupted by discretisation issues, and so I will end up with
// a prediction of the correct font size that will be accurate to within a
// reasonably small error. However if the user had a full set of CM fonts
// installed when I scale down and use a 7 or 10 point (say) script font then
// the version at small visual size is liable to have been designed to be
// thicker, so metrics got be just linear scaling from a 28-point version
// cen not be treated as reliable. However those simple measurements will
// still get me reasonably close. So I will measure again at that scale and
// make a final adjustment. I will NOT bother to iterate this procedure to
// convergence!
        mainSize = probeSize;
        int smallSize = (mainSize+1)/2;
        int smallWidth = 0;
        fsmi = getMathsFont(appl, cmmiSize(smallSize), "cmmi10", smallSize);
// At this stage all the existing fonts remain untouched.
        if (fsmi == NULL) return 0; // FAIL
#ifdef HAVE_XFT
        if (fwin_use_xft)
            smallWidth = xfWidth(fsmi, "MMMMMMMMMM", 10);
        else
#endif
        smallWidth = ((FXFont *)fsmi)->getTextWidth("MMMMMMMMMM", 10);
        smallWidth *= 8; // width of 80 "M" in small font
        mainSize = (probeSize*sw)/smallWidth;
#ifdef HAVE_XFT
        if (fwin_use_xft) XftFontClose(dpy, (XftFont *)fsmi);
        else
#endif
            delete (FXFont *)fsmi; // may leave bad font in printDC
        fsmi = NULL;
        smallSize = (mainSize+1)/2;
        fsmi = getMathsFont(appl, cmmiSize(smallSize), "cmmi10", smallSize);
// At this stage all the existing fonts remain untouched.
        if (fsmi == NULL) return 0;   // FAIL
#ifdef HAVE_XFT
        if (fwin_use_xft)
            smallWidth = xfWidth(fsmi, "MMMMMMMMMM", 10);
        else
#endif
        smallWidth = ((FXFont *)fsmi)->getTextWidth("MMMMMMMMMM", 10);
        smallWidth *= 8; // width of 80 "M" in small font
        mainSize = (mainSize*sw)/smallWidth;
#ifdef HAVE_XFT
        if (fwin_use_xft) XftFontClose(dpy, (XftFont *)fsmi);
        else
#endif
            delete (FXFont *)fsmi;
        fsmi = NULL;
    }
// I will insist that the main font be at least 10 point. Then at smallest
// scale I will have a regular size of 5pt. That would lead to
// scripts at 4pt and scripted scripts at 2.5pt. This is a pretty grossly
// tiny lower limit and if the smallest variation involved ever gets used
// it will not be readable. However I find that on a typical screen the
// size I need is around 13 points, not too far from this limit.
// NOTE that I work in decipoints here.

    if (mainSize < 100) mainSize = 100;

// Under Windows 2000/XP I make the maths fonts that I want available as
// private ones for this application. All existing fonts remain available at
// all times.
// Under Windows 95/98 I have added access to me fonts, but again existing
// ones remain available.
// Under raw X11 my fonts have been appended to the (global) list of
// font directories. As with Windows any fonts that the user has already
// installed remain available.
//
// With Xft I also have some application-specific fonts that I have
// merged in...


// Having ensured that the fonts that I need are available I create
// the 36 maths fonts that I can possibly use. I provide a font name
// that would be my first choice, tuned to the visual size that is to be
// used (eg cmr7), and a fall-back name (always 10-point visual size)
// that I guarantee by providing it in my own font directory. Under Xft I
// do NOT try the perfection-size since I do not know a way to check how well
// it works: I always go straight for the 10-point versions that I explicitly
// added as application-specific things.

    int p = 0;
    for (int i=0; i<9; i++)
    {   int size = (int)(0.25*(double)mainSize*scaleTable[i] + 0.5);
        int height=0, depth=0, width=0;
        for (int j=0; j<4; j++)
        {   const char *targetName, *fallbackName;
            switch(j)
            {
        default:
        case 0: targetName = cmmiSize(size/10); fallbackName = "cmmi10"; break;
        case 1: targetName = cmrSize(size/10);  fallbackName = "cmr10";  break;
        case 2: targetName = cmsySize(size/10); fallbackName = "cmsy10"; break;
        case 3: targetName = cmexSize(size/10); fallbackName = "cmex10"; break;
            }
            masterFont[p] = getMathsFont(appl, targetName, fallbackName, size);
            if (masterFont[p] == NULL)
            {   while (--p >= 0)
                {   void *ff = masterFont[p];
#ifdef HAVE_XFT
                    if (fwin_use_xft)
                        XftFontClose(dpy, (XftFont *)ff);
                    else
#endif
                    delete (FXFont *)ff;
                }
// Since opening fonts here failed I will restore the existing fonts, so that
// at least I have SOMETHING available to draw with.
                for (int i=0; i<36; i++)
                    masterFont[i] = previousFont[i];
                return 0;      // FAIL
            }
            masterFontFontInfo[p] = findFont(targetName);
// There will be places where I want to position items based on the
// general size of the fonts that are in use rather than the size of the
// particular glyphs involved. So I record an "X" height and an "M" width
// for my Italic font in each of the sizes that I use.
// For cmr, rmmi and cmsy this seems to give a reasonably consistent
// idea of sizes. I find the metric returned for cmex somewhat strange!
//
// The way that I want to measure things is with "height" measuring up from
// the baseline and "depth" measuring down from it. The metrics that FXFont
// gives me record overall height, so I adjust for that here.
// Observe I set up the "cmmi" font first so I can measure it and record
// its general metrics for all the other fonts.
            if (j==0)
            {
#ifdef HAVE_XFT
                if (fwin_use_xft)
                {   height = ((XftFont *)masterFont[p])->ascent;
                    depth = ((XftFont *)masterFont[p])->descent;
                    width = xfWidth(masterFont[p], "M", 1);
                }
                else
#endif
                {   depth = ((FXFont *)masterFont[p])->getFontDescent();
                    height = ((FXFont *)masterFont[p])->getTextHeight("X", 1) - depth;
                    width = ((FXFont *)masterFont[p])->getTextWidth("M", 1);
                }
            }
            masterFontHeight[p] = height;
            masterFontDepth[p] = depth;
            masterFontWidth[p] = width;
            p++;
        }
    }
    setMathsFontScale(4);
    mathFontSize = mainSize;
// Since I have managed to open the new fonts I can discard the old ones.
    for (int i=0; i<36; i++)
    {
#ifdef HAVE_XFT
// I will do some very magic things about font selection when I print to avoid
// problems here when Xft is around and I might otherwise get muddled between
// printer and screen font technology!
        if (fwin_use_xft)
        {   if (previousFont[i] != NULL)
                XftFontClose(dpy, (XftFont *)previousFont[i]);
        }
        else 
#endif
            delete (FXFont *)previousFont[i];
        previousFont[i] = NULL;
    }
    return 1;                       // OK!
}

// I have two interlocking ideas about font sizes. One is that for any
// formula I display I will have a Regular, Script and ScriptScript size
// of font, spanning a range of 2 in size. But as well as that I will want to
// be able to scale formulae to fit across the screen. If I always use a font
// that guarantees that even the largest formula would fit then generally
// everything looks cramped and tiny. So each set of 3 fonts will be made
// available in 5 scales: (1, 1.2, 1.4, 1.7, 2) where these will be selected
// so that "1.2" version expects 80 "M" to match my screen's width.
// changeMathsFontSize will set up the 9 fonts needed in each face
// (ie 1, 1.2, 1.4, 1.7, 2, 2.4, 2.8, 3.4, 4), while setMathsFontScale
// selects out the three that are to be used next. The argument to it
// should be 0, 1, 2, 3 or 4. Of these 4 is the default or preferred size and
// the smaller numbers are only used when formulae start to look too wide.

void setMathsFontScale(int scale)
{
    if (scale < 0) scale = 0;
    else if (scale > 4) scale = 4;
// In the master tables the arrangement is
//   cmmi, cmr, cmsy, cmex   0.5 (ie script-script)   0,1,2,3
//   cmmi, cmr, cmsy, cmex                            4,5,6,7
//   cmmi, cmr, cmsy, cmex   0.7 (ie script)          8,9,10,11
//   cmmi, cmr, cmsy, cmex                            12,13,14,15
//   cmmi, cmr, cmsy, cmex   1.0 (ie regular)         16,17,18,19
// in sizes tiny and so on upwards.
    int base = 4*scale;
    for (int i=0; i<3; i++)     // sizes
    {   for (int j=0; j<4; j++) // faces
        {   int x, y;
// Now I have the mess of mapping master to local font index info!
            x = j+4*i;
            y = (j==0?1: j==1?0 : j); // flip cmr and cmmi index values!
            y = base + 16 - 8*i + y;  // in mathFont biggest comes first!
            mathFont[x] = masterFont[y];
            mathFontHeight[x] = masterFontHeight[y];
            mathFontDepth[x] = masterFontDepth[y];
            mathFontWidth[x] = masterFontWidth[y];
            mathFontFontInfo[x] = masterFontFontInfo[y];
        }
    }
    mathWidth = mathFontWidth[FntItalic+FntRegular];
}

///////////////////////////////////////////////////////////////////////////

// This section measures boxes and thereby establish a layout.

static int intmax(int a, int b)
{
    return (a > b) ? a : b;
}

#if 0

// These could, I guess, be wanted at some stage...

static int intmin(int a, int b)
{
    return (a < b) ? a : b;
}

static int intabs(int a)
{
    return (a < 0) ? -a : a;
}

#endif

static int remap(int);

// This is intended to select a "bracket" (in other words "big delimiter")
// size measured in units of 0.5 the height of the smallest such delimiter
// in the cmex font. However there is a special case! For modest size
// formulae the code returns 1 which indicates "use a glyph from cmr or
// cmsy, rather than the one from cmex".

static int bracketCount(int flags, int height, int depth)
{
    int size = flags & FontSizeMask;
    int h = mathFontHeight[size], d = mathFontDepth[size];
    if (height<=h && depth<=d) return 1; // use simple cmsy or cmr glyph
    height += depth;
    h = (9*(h + d) + 4);   // 8 * total height of the cmex glyph
// I round up to ensure that the delimiter can totally enclose the contents
    return (16*height + h - 1)/h;
}

static int bracketWidth(char type, int flags, int height, int depth)
{
    int n = bracketCount(flags, height, depth);
// n is the size of bracket needed, measured in units of 0.5 times the
// normal cmex font height
    int fnt = FntExtension, ch = 0x00;
    if (n == 1)
    {   fnt = FntSymbol;
        switch(type)
        {
    case '.':
            return 0;
    case '(':
            fnt = FntRoman;
            ch = 0x28;
            break;
    case ')':
            fnt = FntRoman;
            ch = 0x29;
            break;
    case '[':
            fnt = FntRoman;
            ch = 0x5b;
            break;
    case ']':
            fnt = FntRoman;
            ch = 0x5d;
            break;
    case '{':
            ch = 0x64;
            break;
    case '}':
            ch = 0x65;
            break;
    case '|':                 // LEFT vertical bar
            ch = 0x6a;
            break;
    case '!':                 // RIGHT vertical bar
            ch = 0x6a;
            break;
    case 'Q':                 // square root marker
            ch = 0x70;        // NB this is a descender
            break;
    case '/':                 // slash
            ch = 0x36;
            break;
    case '\\':                // backslash
            ch = 0x6e;
            break;
    case 'L':                 // lfloor
            ch = 0x62;
            break;
    case 'G':                 // lceil (like Gamma)
            ch = 0x64;
            break;
    case 'J':                 // rfloor
            ch = 0x63;
            break;
    case '7':                 // rceil
            ch = 0x65;
            break;
    case '<':                 // langle
            ch = 0x68;
            break;
    case '>':                 // rangle
            ch = 0x69;
            break;
    case '#':                 // \|    (double vertical bar)
            ch = 0x6b;
            break;
    case '^':                 // uparrow
            ch = 0x22;
            break;
    case 'v':                 // downarrow
            ch = 0x23;
            break;
    case 'A':                 // Uparrow
            ch = 0x2a;
            break;
    case 'V':                 // Downarrow
            ch = 0x2b;
            break;
    case 'b':                 // updownarrow
            ch = 0x6c;
            break;
    case 'B':                 // Updownarrow
            ch = 0x6d;
            break;
    default:
            printf("Attempt to measure unknown delimiter \"%c\"\n", type);
            return 0;
        }
    }
    else
    {
        if (n > 6) n = 6;
        const char *s;
// All of this is amazingly tightly tied to the "cmex" font and the
// encoding it has for glyphs used to build up tall characters.
        switch(type)
        {
    case '.':
            return 0;
    case '(':
            s = "\x00\x10\x12\x20\x30";
            break;
    case ')':
            s = "\x01\x11\x13\x21\x31";
            break;
    case '[':
            s = "\x02\x68\x15\x22\x32";
            break;
    case ']':
            s = "\x03\x69\x16\x23\x33";
            break;
    case '{':
            s = "\x08\x6e\x1a\x28\x38";
            break;
    case '}':
            s = "\x09\x6f\x1b\x29\x39";
            break;
    case '|':                 // LEFT vertical bar
            s = "\x0c\x0c\x42\x42\x42";
            break;
    case '!':                 // RIGHT vertical bar
            s = "\x0c\x0c\x43\x43\x43";
            break;
    case 'Q':                 // square root marker
            s = "\x70\x71\x72\x73\x74";
            break;
    case 'L':           // lfloor
            s = "\x04\x6a\x16\x24\x36";
            break;
    case 'G':           // lceil
            s = "\x06\x6c\x18\x22\x32";
            break;
    case 'J':           // rfloor
            s = "\x05\x6b\x17\x25\x37";
            break;
    case '7':           // rceil
            s = "\x07\x6d\x19\x23\x33";
            break;
    case '^':           // uparrow
            s = "\x88\x78\x78\x78\x78";
            break;
    case 'v':           // downarrow
            s = "\x0c\x0c\x0c\x0c\x0c";
            break;
    case 'b':           // updownarrow
            s = "\x78\x78\x78\x78\x78";
            break;
    case 'A':           // Uparrow
            s = "\x7e\x7e\x7e\x7e\x7e";
            break;
    case 'V':           // Downarrow
            s = "\x77\x77\x77\x77\x77";
            break;
    case 'B':           // Updownarrow
            s = "\x7e\x7e\x7e\x7e\x7e";
            break;
    case '#':           // \| double vertical line
            s = "\x77\x77\x77\x77\x77";
            break;
    case '<':           // langle
    case '>':           // rangle
    case '\\':          // backslash
    case '/':           // slash
    default:
            printf("Attempt to measure unknown delimiter \"%c\"\n", type);
            return 0;
        }
        ch = s[n-2];
    }
    char ss[1];
    ss[0] = remap(ch);
    void *ff = mathFont[fnt + (flags & FontSizeMask)];
#ifdef HAVE_XFT
    if (fwin_use_xft) return xfWidth(ff, ss, 1);
    else
#endif
        return ((FXFont *)ff)->getTextWidth(ss, 1);
}

static int bracketHeightDepth(char type, int flags, int height, int depth)
{
    if (type == '.') return 0;
// the calculations here had better match the corresponding logic in
// paintBracket.
    int size = flags & FontSizeMask;
    int h = mathFontHeight[size], d = mathFontDepth[size];
    int n = bracketCount(flags, height, depth);
// n is the size of bracket needed, measured in units of 0.5 times the
// normal cmex font height
// If I use a cmsy or cmr glyph its height is easy to work out!
    if (n == 1)
    {   if (type == 'Q') h += (h + d + 12)/25;
        return (h<<16) | d;
    }
    int height1 = height + depth;
// the cmex glyphs seem to be (9/8) times as high as the cmr, cmmi
// and cmsy ones! So I scale here by that amount!
    int height2 = (9*n*(h + d) + 8)/16;
// height2 will be the actual total height of the bracket that I draw.
    int extra = (height2 - height1 + 1)/2;
    if (extra > 0)
    {   height += extra;
        depth += extra;
    }
    if (type == 'Q') height += (h + d + 12)/25; // rule width.
    return (height<<16) | depth;
}


// return width of column col in a BoxBeside row, or a negative
// value if there is not one.

static int widthOfColumn(Box *b, int col)
{
    while (col != 0)
    {   if (b->nest.type != BoxNest ||
            b->nest.flags != BoxBeside) return -1;
        b = b->nest.sub1;
        col--;
    }
    if (b->nest.type != BoxNest ||
        b->nest.flags != BoxBeside) return -1;
    b = b->nest.sub2;
    return b->text.width;
}

// return max width of any column with the given index, or a negative
// value if all rows in the matrix are shorter than that.

static int maxWidthInColumn(Box *b, int col)
{
    int r = -1;
    if (DEBUGFONT & 2) printf("find max width in column %d\n", col);
    while (b->nest.type == BoxNest &&
           b->nest.flags == BoxTower)
    {   int w = widthOfColumn(b->nest.sub2, col);
        if (DEBUGFONT & 2) printf("width in column %d is %d\n", col, w);
        if (w > r) r = w;
        if (DEBUGFONT & 2) printf("max now %d\n", r);
        b = b->nest.sub1;
    }
    return r;
}

// Here b is a set of BoxBesides and I want to widen one of the
// ones within it.

static void setOneWidth(Box *b, int col, int w, int xgap)
{
    int c0 = col;
    Box *b0 = b;
    if (DEBUGFONT & 2) printf("force width of column %d to %d in one row\n", col, w);
    while (col != 0)
    {   if (b->nest.type != BoxNest ||
            b->nest.flags != BoxBeside) return;
        b = b->nest.sub1;
        col--;
    }
    if (b->nest.type != BoxNest ||
        b->nest.flags != BoxBeside) return;
// Now b is a BoxBeside that represents the required cell of the
// matrix.
    int w0 = b->nest.sub2->text.width;  // current width of cell
    int extra = w - w0;
    if (DEBUGFONT & 2) printf("extra width needed = %d\n", extra);
    b->nest.dx2 += extra/2;             // centre the item
// Now all the enclosing boxes have got wider, so I need to adjust their
// record of their width.
    if (c0 == 0)
    {   b0->nest.width += extra;
        return;
    }
    if (DEBUGFONT & 2) printf("Now need to insert intercolumn gap\n");
    while (c0 > 0)
    {   b0->nest.width += extra + xgap;
        b0->nest.dx2 += extra + xgap;
        b0 = b0->nest.sub1;
        c0--;
    }
    b0->nest.width += extra + xgap;
    return;
}

static void setWidthsAndCentre(Box *b, int col, int w, int xgap, int ygap)
{
    Box *b0 = b;
    int n = 0;
    while (b0->nest.type == BoxNest &&
           b0->nest.flags == BoxTower)
    {   n++;
        b0 = b0->nest.sub1;
    }
    int dy = ygap*(n-1);
    if (DEBUGFONT & 2) printf("force width of column %d to %d\n", col, w);
    while (b->nest.type == BoxNest &&
           b->nest.flags == BoxTower)
    {   setOneWidth(b->nest.sub2, col, w, xgap);
// I have meddled with the width of an item in one row so the node here needs
// its width changed to match.
        b->nest.width = b->nest.sub2->nest.width;
        if (DEBUGFONT & 2) printf("Width of row is now %d\n", b->nest.width);
        b->nest.depth += dy;
        b->nest.dy2 += dy;
        dy -= ygap;
        b = b->nest.sub1;
    }
    return;
}

// return 0 if column col (starting with 0) does not exist. Otherwise
// change widths etc in all relevant BoxBeside entries. Note that the
// code I have here will scan the matrix repeatedly to find columns.
// I view the costs as OK since for display I never expect to have
// seriously large matrices.

static int balanceColumns(Box *b, int col, int xgap, int ygap)
{
    if (DEBUGFONT & 2) printf("balance column %d\n", col);
    int w = maxWidthInColumn(b, col);
    if (DEBUGFONT & 2) printf("column %d width = %d\n", col, w);
    if (w < 0) return 0;
    setWidthsAndCentre(b, col, w, xgap, ygap);
    if (DEBUGFONT & 2) printf("column %d balanced\n", col);
    return 1;
}

void measureBox(Box *b)
{
    b->top.measuredSize = -1;
    measureBox1(b);
}

int italicAdjust(int ch, int font)
{
//                        n
// In something like     X
// I need to space the superscript across by a bit when the base ends in
// a character that is tall and leans across to the right. The amount of
// adjustment is produced here and is really a bit of a fudge!
    int w = mathFontWidth[font];
    switch (font & FontFamilyMask)
    {
case FntItalic:
        switch (ch)
        {
    case 0x00: case 0x04: case 0x06: case 0x07: // Gamma etc!
    case 'f': case 'l':
    case 'B': case 'C': case 'E': case 'F':
    case 'H': case 'I': case 'J': case 'K':
    case 'M': case 'N': case 'P': case 'S':
    case 'T': case 'U': case 'V': case 'W':
    case 'X': case 'Y': case 'Z':
            return (w+6)/8;
    case 'O': case 'Q':
            return (w+8)/16;
    default:
            return 0;
        }
default:
        return 0;
    }
}

void measureBox1(Box *b)
{
    int f, h, w, d, dy, d1, h1;
    int sqrtcount=0, sqrtunit=0;
    void *ff;
    TextBox *t;
    SymBox *s;
    NestBox *n;
    NestBox3 *n3;
    MatrixBox *m;
    BracketBox *bb;
    TopBox *tt;
    if (DEBUGFONT & 4)
    {   printf("measureBox1(%p)\n", b); fflush(stdout);
        printf("type = %d\n", b->text.type); fflush(stdout);
    }
    switch (b->text.type)
    {
case BoxSym:
        s = &(b->sym);
        if ((s->flags & SymTypeMask) == SymRule) return; // measurements fixed
        s->height = 0;
        s->depth = 0;
        switch (s->flags & SymTypeMask)
        {
    case SymStar:   // used as space between items that are multiplied
            s->width = mathFontWidth[s->flags & FontSizeMask]/6;
            return;
    case SymComma:  // narrow space
            s->width = mathFontWidth[s->flags & FontSizeMask]/4;
            return;
    case SymExclam: // narrow negative space
            s->width = -mathFontWidth[s->flags & FontSizeMask]/4;
            return;
    case SymColon:  // medium space
            s->width = mathFontWidth[s->flags & FontSizeMask]/2;
            return;
    case SymSemiColon: // wide space
            s->width = mathFontWidth[s->flags & FontSizeMask];
            return;
    case SymBlank:  // used by tmprint, it seems. Intent unclear to me!
            s->width = mathFontWidth[s->flags & FontSizeMask]/3;
            return;
    case SymNothing: // used when I want an empty box as a placeholder
            s->height = s->depth = s->width = 0;
            return;
    case SymUnderscore: // not a glyph in any font! So draw as a rule.
            s->width = mathFontWidth[s->flags & FontSizeMask]/2;
            return;
    default:
            printf("Unknown SymBox type %.2x to measure\n", s->flags);
            return;
        }
case BoxText:
        t = &(b->text);
        if (DEBUGFONT & 4)
        {   printf("text = <%s>\n", t->text);
            fflush(stdout);
        }
        ff = mathFont[t->flags & FontMask];
        if (DEBUGFONT & 4)
        {   printf("fontid = %.2x font = %p\n", t->flags, ff);
            fflush(stdout);
        }
        h = mathFontHeight[t->flags & FontSizeMask];
        d = mathFontDepth[t->flags & FontSizeMask];
#ifdef HAVE_XFT
        if (fwin_use_xft) w = xfWidth(ff, t->text, t->n);
        else
#endif
            w = ((FXFont *)ff)->getTextWidth(t->text, t->n);
// Here I have a bit of shameless fudge. The "cmex" glyph for \int seems to
// record as its width a value that makes it finish just about at a point on
// its stem. I unilaterally add a little extra width here to get spacing that
// I like better! Furthermore I will position all "big" operators based on
// their mid-line
        if (t->flags & FntBig)
        {   int bigH = 0, hd = h+d;
// I know the heights of the "big" operators in the cmex font, so
// compute them here in terms of the height of my normal font. The
// numbers seem a little odd but are what I appear to observe from
// inspecting the font.
            if (t->text[0] == 0x5a)   // \int
            {   w += mathFontWidth[t->flags & FontSizeMask]/3;
                bigH = (2222*hd + 450)/900;
            }
            else bigH = (1400*hd + 450)/900;
            hd = h - d;
            h = (bigH + hd)/2;
            d = (bigH - hd)/2;
        }
        if (DEBUGFONT & 4)
        {   printf("text \"%s\" is size h=%d d=%d w=%d\n", t->text, h, d, w);
            fflush(stdout);
        }
        t->height = h;
        t->depth = d;
        t->width = w;
        return;
case BoxBracket:   // This is for big brackets
        bb = &(b->bracket);
// I have leftBracket, rightBracket and sub components here.
// The characters involved can be "(", "[", "{", "|" "." "}", "]", ")".
// "Q" (sqrt), "/", "\", "L", "G" (lceil), "J", "7" (rceil), "<", ">",
// "#" (double vertical bar), "^" (uparrow), "v" (downarrow), "A" (Uparrow)
// "V" (Downarrow), "b" (updownarrow), "B" (Updownarrow)
        measureBox1(bb->sub);
        bb->width = bb->sub->text.width;
        h1 = bb->height = bb->sub->text.height;
        d1 = bb->depth = bb->sub->text.depth;
        f = bb->flags & FontSizeMask;
        if (bb->leftBracket == 'Q')
        {   h = mathFontHeight[f];
            d = mathFontDepth[f];
            h1 += (h + d + 12)/25; // make contents seem taller
                                   // to leave gap before overbar
            sqrtcount = bracketCount(f, h1, d1);
            sqrtunit = h + d;
        }
        w = bracketWidth(bb->leftBracket, f, h1, d1);
        bb->width += w;
        bb->dx = w;
        w = bracketWidth(bb->rightBracket, f, h1, d1);
        bb->width += w;
        h = bracketHeightDepth(bb->leftBracket, f, h1, d1);
        d = (h & 0xffff);
        h = (h >> 16) & 0xffff;
        w = bracketHeightDepth(bb->rightBracket, f, h1, d1);
        bb->height = intmax(bb->height, h);
        bb->depth = intmax(bb->depth, d);
        d = (w & 0xffff);
        h = (w >> 16) & 0xffff;
        bb->height = intmax(bb->height, h);
        bb->depth = intmax(bb->depth, d);
        if (bb->sub1 != NULL)
        {   measureBox1(bb->sub1);
// OK, if I have a "sub1" box I had a radical sign that needs an explicit
// index give, as in for cube- or nth roots. I want to position the
// index just above the left end of the hook in the radical sign.
            int downby = 0;
            switch (sqrtcount)
            {
        case 1: downby = sqrtunit/2;       break;
        case 2: downby = (6*sqrtunit)/10;  break;
        case 3: downby = (15*sqrtunit)/16; break;
        case 4: downby = (5*sqrtunit)/4;   break;
        case 5: downby = (8*sqrtunit)/5;   break;
        default:downby = bb->height + bb->depth - (10*sqrtunit)/5; break;
            }
            bb->dy1 = -(bb->height + bb->sub1->text.depth - downby);
            h = bb->dy1 + bb->sub1->text.height;
            bb->height = intmax(bb->height, h);
        }
        return;
case BoxMatrix:
        m = &(b->matrix);
// I do an initial measure operation on the contents not paying any attention
// to the fact that the contents is in a matrix context. This will give me
// the "natural" size of each enclosed sub-box.
        measureBox1(m->sub);
// Now I expect the contents to be (eg)
//    ABOVE(ABOVE(row1,row2),row3)
// with each row a structure like BESIDE(BESIDE(col1, col2),col3).
// I need to scan this to find the greatest width in each column, and then
// re-work the BESIDE widths and offsets to centre each item in a field that
// width. I also need to ensure suitable gaps between rows and columns.
// And finally I will need to set the "dy" field to get the base-line where
// it neeeds to be.

        {   int interColumnGap = mathFontWidth[m->flags & FontSizeMask];
            int interRowGap = mathFontHeight[m->flags & FontSizeMask]/2;
            for (int col=0;;col++)
            {   if (!balanceColumns(m->sub, col,
                       interColumnGap, interRowGap)) break;
            }
            m->width = m->sub->text.width;
            int mmh = m->sub->text.height + m->sub->text.depth;
            m->depth = mmh/2;
            m->height = mmh - m->depth;
            m->dy = m->depth - m->sub->text.depth;
        }
        return;
case BoxNest:
        n = &(b->nest);
        switch (n->flags & NestMask)
        {
    case BoxFraction:  //     Aaaaaaaa
                       // --> --------
                       //        Bb
            {   measureBox1(n->sub1);
                measureBox1(n->sub2);
                n->width = intmax(n->sub1->text.width, n->sub2->text.width);
                int rh = mathFontHeight[n->flags & FontSizeMask]/4;
                int delta = (mathFontHeight[n->flags & FontSizeMask] -
                             mathFontDepth[n->flags & FontSizeMask])/2;
                n->height = n->sub1->text.height +
                            n->sub1->text.depth + rh + delta;
                n->depth = n->sub2->text.height +
                            n->sub2->text.depth + rh - delta;
                n->dx1 = (n->width - n->sub1->text.width)/2;
                n->dy1 = -(n->sub1->text.depth + rh + delta);
                n->dx2 = (n->width - n->sub2->text.width)/2;
                n->dy2 = n->sub2->text.height + rh - delta;
            }
            if (DEBUGFONT & 4)
            {   printf("Above h=%d d=%d w=%d\n",
                       n->height, n->depth, n->width);
                printf("dx1=%d dy1=%d dx2=%d dy2=%d\n",
                       n->dx1, n->dy1, n->dx2, n->dy2);
                fflush(stdout);
            }
            return;
    case BoxStack:     //     Aaaaaaaa
                       // -->    Bb
            {   measureBox1(n->sub1);
                measureBox1(n->sub2);
                n->width = intmax(n->sub1->text.width, n->sub2->text.width);
                n->height = n->sub1->text.height + n->sub1->text.depth +
                            n->sub2->text.height;
                n->depth = n->sub2->text.depth;
                n->dx1 = (n->width - n->sub1->text.width)/2;
                n->dy1 = -(n->sub1->text.depth + n->sub2->text.height);
                n->dx2 = (n->width - n->sub2->text.width)/2;
                n->dy2 = 0;
            }
            if (DEBUGFONT & 4)
            {   printf("Above h=%d d=%d w=%d\n",
                       n->height, n->depth, n->width);
                printf("dx1=%d dy1=%d dx2=%d dy2=%d\n",
                       n->dx1, n->dy1, n->dx2, n->dy2);
                fflush(stdout);
            }
            return;
   case BoxTower:      //     Aaaaaa
                       // --> Bbb
            measureBox1(n->sub1);
            measureBox1(n->sub2);
            n->width = intmax(n->sub1->text.width, n->sub2->text.width);
            n->height = n->sub1->text.height + n->sub1->text.depth + n->sub2->text.height;
            n->depth = n->sub2->text.depth;
            n->dx1 = 0;
            n->dy1 = -(n->sub1->text.depth + n->sub2->text.height);
            n->dx2 = 0;
            n->dy2 = 0;
            if (DEBUGFONT & 4)
            {   printf("Above h=%d d=%d w=%d\n",
                       n->height, n->depth, n->width);
                printf("dx1=%d dy1=%d dx2=%d dy2=%d\n",
                       n->dx1, n->dy1, n->dx2, n->dy2);
                fflush(stdout);
            }
            return;
    case BoxBeside:    // --> A B
            measureBox1(n->sub1);
            measureBox1(n->sub2);
            n->width = n->sub1->text.width + n->sub2->text.width;
            n->height = intmax(n->sub1->text.height, n->sub2->text.height);
            n->depth = intmax(n->sub1->text.depth, n->sub2->text.depth);
            n->dx1 = 0;
            n->dy1 = 0;
            n->dx2 = n->sub1->text.width;
            n->dy2 = 0;
            if (DEBUGFONT & 4)
            {   printf("Beside h=%d d=%d w=%d\n",
                       n->height, n->depth, n->width);
                printf("dx1=%d dy1=%d dx2=%d dy2=%d\n",
                       n->dx1, n->dy1, n->dx2, n->dy2);
                fflush(stdout);
            }
            return;
    case BoxAdjacent:    // --> A B
            measureBox1(n->sub1);
            measureBox1(n->sub2);
            w = n->sub1->text.width/4;  // amount to fudge by!
            n->width = n->sub1->text.width + n->sub2->text.width - w;
            n->height = intmax(n->sub1->text.height, n->sub2->text.height);
            n->depth = intmax(n->sub1->text.depth, n->sub2->text.depth);
            n->dx1 = 0;
            n->dy1 = 0;
            n->dx2 = n->sub1->text.width - w;
            n->dy2 = 0;
            if (DEBUGFONT & 4)
            {   printf("Adjacent h=%d d=%d w=%d\n",
                       n->height, n->depth, n->width);
                printf("dx1=%d dy1=%d dx2=%d dy2=%d\n",
                       n->dx1, n->dy1, n->dx2, n->dy2);
                fflush(stdout);
            }
            return;
    case BoxSubscript:   //   A    or in special cases    A
                         //    B                          B
            measureBox1(n->sub1);
            measureBox1(n->sub2);
// I will want to apply a special treatment here for "big" operators:
// subscripts and superscripts will be treated as forming a tower rather
// then the "usual" positioning.
            if (n->sub1->text.type==BoxText && n->sub1->text.flags & FntBig)
            {   n->width = intmax(n->sub1->text.width, n->sub2->text.width);
                n->height = n->sub1->text.height;
                n->depth = n->sub1->text.depth +
                           n->sub2->text.height + n->sub2->text.depth;
                n->dx1 = (n->width - n->sub1->text.width)/2;
                n->dy1 = 0;
                n->dx2 = (n->width - n->sub2->text.width)/2;
                n->dy2 = n->sub1->text.depth + n->sub2->text.height;
                if (DEBUGFONT & 4)
                {   printf("Special subscript h=%d d=%d w=%d\n",
                           n->height, n->depth, n->width);
                    printf("dx1=%d dy1=%d dx2=%d dy2=%d\n",
                           n->dx1, n->dy1, n->dx2, n->dy2);
                    fflush(stdout);
                }
                return;
            }
            n->width = n->sub1->text.width + n->sub2->text.width;
            n->dx1 = 0;
            n->dy1 = 0;
            n->dx2 = n->sub1->text.width;
            dy = mathFontHeight[n->flags & FontSizeMask]/2;
            {   int tt = n->sub1->text.depth - n->sub2->text.depth;
                if (tt > dy) dy = tt;
            }
            n->dy2 = dy;
            n->height = intmax(n->sub1->text.height, n->sub2->text.height - dy);
            n->depth = intmax(n->sub1->text.depth, n->sub2->text.depth + dy);
            if (DEBUGFONT & 4)
            {   printf("Subscript h=%d d=%d w=%d\n",
                       n->height, n->depth, n->width);
                printf("dx1=%d dy1=%d dx2=%d dy2=%d\n",
                       n->dx1, n->dy1, n->dx2, n->dy2);
                fflush(stdout);
            }
            return;
    case BoxSuperscript:    //    B                          B
                            //   A     or in special cases   A
            measureBox1(n->sub1);
            measureBox1(n->sub2);
            if (n->sub1->text.type==BoxText && n->sub1->text.flags & FntBig)
            {   n->width = intmax(n->sub1->text.width, n->sub2->text.width);
                n->height = n->sub1->text.height +
                           n->sub2->text.height + n->sub2->text.depth;
                n->depth = n->sub1->text.depth;
                n->dx1 = (n->width - n->sub1->text.width)/2;
                n->dy1 = 0;
                n->dx2 = (n->width - n->sub2->text.width)/2;
                n->dy2 = -(n->sub1->text.height + n->sub2->text.depth);
                if (DEBUGFONT & 4)
                {   printf("Special superscript h=%d d=%d w=%d\n",
                           n->height, n->depth, n->width);
                    printf("dx1=%d dy1=%d dx2=%d dy2=%d\n",
                           n->dx1, n->dy1, n->dx2, n->dy2);
                    fflush(stdout);
                }
                return;
            }
            n->width = n->sub1->text.width + n->sub2->text.width;
            n->dx1 = 0;
            n->dy1 = 0;
            n->dx2 = n->sub1->text.width;
// Now an utter hack! But it is here in part to alert me to the fact that
// similar tuning may be called for in other places. If I have "f^n" then the
// fact that "f" is tall and it slopes forward means that I want to put a tiny
// amount of extra space in. I will add some space for various cases here,
// but can imagine that further tuning could be applied!
//
            if (n->sub1->text.type==BoxText)
            {   const char *s = n->sub1->text.text;
                int len =  n->sub1->text.n;
                int w = italicAdjust(s[len-1], n->sub1->text.flags & FontMask);
                n->width += w;
                n->dx2 += w;
            }
// Superscripts are raised by at least half the height of the main font,
// but if the things that is being scripted is tall enough they line up with
// its top.
            dy = mathFontHeight[n->flags & FontSizeMask]/2;
            {   int tt = n->sub1->text.height - n->sub2->text.height;
                if (tt > dy) dy = tt;
            }
            n->dy2 = -dy;
            n->height = intmax(n->sub1->text.height, n->sub2->text.height + dy);
            n->depth = intmax(n->sub1->text.depth, n->sub2->text.depth - dy);
            if (DEBUGFONT & 4)
            {   printf("Superscript h=%d d=%d w=%d\n",
                       n->height, n->depth, n->width);
                printf("dx1=%d dy1=%d dx2=%d dy2=%d\n",
                       n->dx1, n->dy1, n->dx2, n->dy2);
                fflush(stdout);
            }
            return;
    case BoxOverstrike:    // --> A on top of B
            measureBox1(n->sub1);
            measureBox1(n->sub2);
            n->width = intmax(n->sub1->text.width, n->sub2->text.width);
            n->height = intmax(n->sub1->text.height, n->sub2->text.height);
            n->depth = intmax(n->sub1->text.depth, n->sub2->text.depth);
// I centre the items horizontally wrt each other
            n->dx1 = (n->width - n->sub1->text.width)/2;
            n->dy1 = 0;
            n->dx2 = (n->width - n->sub2->text.width)/2;
            n->dy2 = 0;
            if (DEBUGFONT & 4)
            {   printf("Overstrike h=%d d=%d w=%d\n",
                       n->height, n->depth, n->width);
                printf("dx1=%d dy1=%d dx2=%d dy2=%d\n",
                       n->dx1, n->dy1, n->dx2, n->dy2);
                fflush(stdout);
            }
            return;
    case BoxPadSpace:    // --> A    but with extra space around A
            measureBox1(n->sub1);
            w = mathFontWidth[n->flags & FontSizeMask]/4;
            n->width = n->sub1->text.width + 2*w;
            n->height = n->sub1->text.height;
            n->depth = n->sub1->text.depth;
            n->dx1 = w;
            n->dy1 = 0;
            if (DEBUGFONT & 4)
            {   printf("PadSpace h=%d d=%d w=%d\n",
                       n->height, n->depth, n->width);
                printf("dx1=%d dy1=%d dx2=%d dy2=%d\n",
                       n->dx1, n->dy1, n->dx2, n->dy2);
                fflush(stdout);
            }
            return;
    default:
            printf("Unknown nest style %d: failing\n", n->flags);
            return;
        }
        return;
case BoxNest3:
        n3 = &(b->nest3);
        switch (n3->flags & NestMask)
        {
    case BoxBothScripts:  //    C                           C
                          //   A       or in special cases  A
                          //    B                           B
// I will want to apply a special treatment here for "big" operators:
// subscripts and superscripts will be treated as forming a tower rather
// then the "usual" positioning.
            measureBox1(n3->sub1);
            measureBox1(n3->sub2);
            measureBox1(n3->sub3);
            if (n3->sub1->text.type==BoxText && n3->sub1->text.flags & FntBig)
            {   n3->width = 
                   intmax(n3->sub1->text.width, 
                      intmax(n3->sub2->text.width, n3->sub3->text.width));
                n3->height = n3->sub1->text.height +
                             n3->sub3->text.height + n3->sub3->text.depth;
                n3->depth = n3->sub1->text.depth +
                            n3->sub2->text.height + n3->sub2->text.depth;
                n3->dx1 = (n3->width - n3->sub1->text.width)/2;
                n3->dy1 = 0;
                n3->dx2 = (n3->width - n3->sub2->text.width)/2;
                n3->dy2 = n3->sub1->text.depth + n3->sub2->text.height;
                n3->dx3 = (n3->width - n3->sub3->text.width)/2;
                n3->dy3 = -(n3->sub1->text.height + n3->sub3->text.depth);
                if (DEBUGFONT & 4)
                {   printf("Special Bothscripts h=%d d=%d w=%d\n",
                           n3->height, n3->depth, n3->width);
                    printf("dx1=%d dy1=%d dx2=%d dy2=%d\n",
                           n3->dx1, n3->dy1, n3->dx2, n3->dy2);
                    fflush(stdout);
                }
                return;
            }
            n3->width = n3->sub1->text.width +
                        intmax(n3->sub2->text.width, n3->sub3->text.width);
            n3->dx1 = 0;
            n3->dy1 = 0;
            n3->dx2 = n3->sub1->text.width;
            dy = mathFontHeight[n3->flags & FontSizeMask]/2;
            {   int tt = n3->sub1->text.depth - n3->sub2->text.depth;
                if (tt > dy) dy = tt;
            }
            n3->dy2 = dy;
            n3->dx3 = n3->sub1->text.width;
// Now an "italic correction" for "f^n". See the BoxSuperscript case for
// more explanation.
            if (n3->sub1->text.type==BoxText)
            {   const char *s = n3->sub1->text.text;
                int len =  n3->sub1->text.n;
                int w = italicAdjust(s[len-1], n3->sub1->text.flags & FontMask);
                n3->width += w;
                n3->dx2 += w;
            }
            dy = mathFontHeight[n3->flags & FontSizeMask]/2;
            {   int tt = n3->sub1->text.height - n3->sub3->text.height;
                if (tt > dy) dy = tt;
            }
            n3->dy3 = -dy;
            n3->height =
               intmax(n3->sub1->text.height,
                  intmax(n3->sub2->text.height - dy, n3->sub3->text.height + dy));
            n3->depth =
               intmax(n3->sub1->text.depth,
                  intmax(n3->sub2->text.depth + dy, n3->sub3->text.depth - dy));
            if (DEBUGFONT & 4)
            {   printf("Bothscripts h=%d d=%d w=%d\n",
                       n3->height, n3->depth, n3->width);
                printf("dx1=%d dy1=%d dx2=%d dy2=%d\n",
                       n3->dx1, n3->dy1, n3->dx2, n3->dy2);
                fflush(stdout);
            }
            return;
    default:
            printf("Unknown nest3 style %d: failing\n", n3->flags);
            return;
        }
        return;
case BoxFrame:
        measureBox1(b->frame.sub);
        b->frame.width = b->frame.sub->text.width;
        b->frame.height = b->frame.sub->text.height;
        b->frame.depth = b->frame.sub->text.depth;
        return;
case BoxTop:               // top-level wrapper for boxes.
        tt = &(b->top);
// If I have measured before while the main maths font was the same
// size that it is now I will not do anything.
        if (tt->measuredSize == mathFontSize) return;
        measureBox1(tt->sub);
        tt->width = tt->sub->text.width;
        tt->height = tt->sub->text.height;
        tt->depth = tt->sub->text.depth;
        tt->measuredSize = mathFontSize;
        return;
default:
        printf("Measure unknown box type %d: failing\n", b->text.type);
        fflush(stdout);
        return;
    }
}

///////////////////////////////////////////////////////////////////////////

// Input will be presented in a LaTeX-like form so I will want to parse that
// so I can build my box-structure. To do that I will want a way of
// recognizing LaTeX keywords.

typedef struct Keyword
{
    const char *name;
    unsigned char type;
    unsigned char font; // includes size info
    int charCode;       // sometimes holds additional information!
    void *ptr;
} Keyword;

typedef Box *blockHandlerFunction(int l, int r, Box *b);
typedef Box *oneArgHandlerFunction(Box *b, Box *opt);
typedef Box *twoArgsHandlerFunction(Box *b1, Box *b2);
typedef Box *keywordHandlerFunction(int w);

// single character glyph
#define TeXSymbol    0x00
// single character glyph, but subscripts and superscripts form tower
#define TeXVSymbol   0x01
// single character glyph, but allow extra space on either ide
#define TeXWSymbol   0x02
// word to be set in Roman font (eg function name like "sin")
#define TeXRoman     0x03
// keyword not taking an argument, eg \longleftarrow, \not
#define TeX0Arg      0x04
// keyword taking one arg, eg \sqrt
#define TeX1Arg      0x05
// keyword taking 2 args, eg \frac
#define TeX2Arg      0x06
// the \rule keyword
#define TeXRule      0x07
// the \begin keyword
#define TeXBeginWord 0x08
// keyword that forms a sort of "open bracket"
#define TeXBegin     0x09
// "close bracket" to match TeXBegin
#define TeXEnd       0x0a
// "^" or "_".
#define TeXScript    0x0b

#define TeXFlag      0x80

#define matchCenter    1
#define matchMatrix    2
#define matchLeftRight 3
#define matchBrace     4
#define matchParen     5
#define matchBracket   6
#define matchDollar    7


int insideDollars;

static Box *doDisplayStyle(int w)
{
    return NULL;  // always does displaystyle!
}

static Box *doDollar(int l, int r, Box *b1)
{
    if (b1 == NULL)
    {   insideDollars = 1;
        currentState.currentFont = FntItalic + currentSize;
    }
    else insideDollars = 0;
    return b1;
}

static Box *doMathBrace(int l, int r, Box *b1)
{
    currentState.currentFont = FntItalic + currentSize;
    return b1;
}

static Box *doMathRm(Box *b1, Box *opt)
{
    if (b1 == NULL) currentState.currentFont = FntRoman + currentSize;
    return b1;
}

static Box *doMathIt(Box *b1, Box *opt)
{
    if (b1 == NULL) currentState.currentFont = FntItalic + currentSize;
    return b1;
}

static Box *doSpaceCommand(int w)
{
    switch (w)
    {
default:
case ' ': return makeSymBox(SymBlank); 
case '*': return makeSymBox(SymStar);
case ',': return makeSymBox(SymComma); 
case '!': return makeSymBox(SymExclam); 
case ':': return makeSymBox(SymColon);
case ';': return makeSymBox(SymSemiColon); 
case '_': return makeSymBox(SymUnderscore); 
    }
}

static Box *doAdjacent(int w)
{
// This builds a composite character by putting two glyphs together.
// The glyphs are passed in a 32-bit (or wider) packed integer argument.
    int f1, c1, f2, c2;
    f1 = (w >> 24) & 0xff;
    c1 = (w >> 16) & 0xff;
    f2 = (w >> 8) & 0xff;
    c2 = w & 0xff;
    char s1[1], s2[1];
    s1[0] = remap(c1);
    s2[0] = remap(c2);
    return makeNestBox(BoxAdjacent,
        makeTextBox(s1, 1, f1 + currentSize),
        makeTextBox(s2, 1, f2 + currentSize));
}

static Box *doLeftRight(int l, int r, Box *b)
{
    if (b == NULL) return NULL;
    return makeBracketBox(b, l, r);
}

static Box *doNeq(int w)
{
    Box *b1 = makeTextBox("\x3d", 1, FntRoman + currentSize);
    Box *b2 = makeTextBox("\x3d", 1, FntItalic + currentSize);
    return makeNestBox(BoxOverstrike, b1, b2);
}

static Box *readP();

static Box *doNot(int w)
{
// Overstrike anthing (much) with a "/". Hence "\not \equiv" etc.
    Box *b1 = readP();
    if (b1 == NULL) return NULL;
    Box *b2 = makeTextBox("\x3d", 1, FntItalic + currentSize);
    return makeNestBox(BoxOverstrike, b1, b2);
}

static Box *doPmod(Box *b, Box *opt)
{
    printf("pmod not handed yet");
    return b;
}

static Box *doSqrt(Box *b, Box *opt)
{
    if (b == NULL) return NULL;
// Note that sqrt will need to draw a rule above the item it encloses.
    Box *r = makeBracketBox(b, 'Q', '.');
    r->bracket.sub1 = opt;
    return r;
}

static Box *doFbox(Box *b, Box *opt)
{
    if (b == NULL) return NULL;
    return makeFrameBox(b);
}

static Box *doSymb(Box *b, Box *opt)
{
    if (b == NULL) return NULL;
    return makeFrameBox(b);      // At PRESENT I maye symb just a boxed number
}

static Box *doFrac(Box *b1, Box *b2)
{
    if (b1 == NULL) return b2;
    else if (b2 == NULL) return b1;
    return makeNestBox(BoxFraction, b1, b2);
}

static Box *doLarge(int w)
{
    if (currentSize != 0) currentState.currentFont-=FntScript;
    return NULL;
}

static Box *doStackrel(Box *b1, Box *b2)
{
    if (b1 == NULL) return b2;
    else if (b2 == NULL) return b1;
    return makeNestBox(BoxStack, b1, b2);
}

#if 0
// To assist debugging while I develop this code I want to be able to
// display information about a keyword.

static void printKeyword(Keyword *k)
{
    if (k == NULL) printf("NULL keyword\n");
    else printf("Keyword \"%s\" type %.2x font %.2x code %.2x ptr %p\n",
                k->name, k->type, k->font, k->charCode, k->ptr);
}

#endif // 0

// The table that follows is initially set up in an order designed to
// have some degree of coherence of presentation, but as soon as the code
// starts to run it gers rearranged as a hash table.

#define texWordBits 9


static Keyword texWords[1<<texWordBits] =
{
// Some important control words
//    name          type       font       charCode  ptr
// The next two NEVER get out from the lexer.
    {"begin",      TeXBeginWord,  1,         0,    NULL},
    {"end",        TeXBeginWord,  0,         0,    NULL},
// My lexer will map "\begin{center}" onto a single token "(center"
// and similarly for other uses of \begin and \end. In fact with the
// current REDUCE "tmprint" module the only brackets of this sort that
// are used are "center" and "matrix". Also in the CSL driver I will not
// actually generate the "center" case...
    {"(center",    TeXBegin,  matchCenter,    'c',  NULL},
    {")center",    TeXEnd,    matchCenter,    'c',  NULL},
    {"(matrix",    TeXBegin,  matchMatrix,    'm',  NULL},
    {")matrix",    TeXEnd,    matchMatrix,    'm',  NULL},

// Special-case bracket-like items (delimiters that get displayed
// at a size the cover the item on one size of them). The case "\right("
// is probably never used, but I include all cases here for consistency.
// A "\left" must match with a "\right", but the associated delimiter
// does not have to match.
    {"left:(",     TeXBegin,  matchLeftRight, '(',  (void *)doLeftRight},
    {"right:(",    TeXEnd,    matchLeftRight, '(',  (void *)doLeftRight},
    {"left:)",     TeXBegin,  matchLeftRight, ')',  (void *)doLeftRight},
    {"right:)",    TeXEnd,    matchLeftRight, ')',  (void *)doLeftRight},
    {"left:[",     TeXBegin,  matchLeftRight, '[',  (void *)doLeftRight},
    {"right:[",    TeXEnd,    matchLeftRight, '[',  (void *)doLeftRight},
    {"left:]",     TeXBegin,  matchLeftRight, ']',  (void *)doLeftRight},
    {"right:]",    TeXEnd,    matchLeftRight, ']',  (void *)doLeftRight},
    {"left:\\{",   TeXBegin,  matchLeftRight, '{',  (void *)doLeftRight},
    {"right:\\{",  TeXEnd,    matchLeftRight, '{',  (void *)doLeftRight},
    {"left:\\}",   TeXBegin,  matchLeftRight, '}',  (void *)doLeftRight},
    {"right:\\}",  TeXEnd,    matchLeftRight, '}',  (void *)doLeftRight},
    {"left:|",     TeXBegin,  matchLeftRight, '|',  (void *)doLeftRight},
// Note that I map left and right vertical bars onto different things (I
// abuse an exclamation mark to stand for the right one) since they may
// call for different spacings.
    {"right:|",    TeXEnd,    matchLeftRight, '!',  (void *)doLeftRight},
// "\left." and "\right." are invisible!
    {"left:.",     TeXBegin,  matchLeftRight, '.',  (void *)doLeftRight},
    {"right:.",    TeXEnd,    matchLeftRight, '.',  (void *)doLeftRight},
// "/", "\", "L", "G" (lceil), "J", "7" (rceil), "<", ">",
// "#" (double vertical bar), "^" (uparrow), "v" (downarrow), "A" (Uparrow)
// "V" (Downarrow), "b" (updownarrow), "B" (Updownarrow)
    {"left:/",        TeXBegin,     matchLeftRight, '/',  (void *)doLeftRight},
    {"right:/",       TeXEnd,       matchLeftRight, '/',  (void *)doLeftRight},
    {"left:\\|",      TeXBegin,     matchLeftRight, '#',  (void *)doLeftRight},
    {"right:\\|",     TeXEnd,       matchLeftRight, '#',  (void *)doLeftRight},
    {"left:\\langle", TeXBegin,     matchLeftRight, '<',  (void *)doLeftRight},
    {"right:\\langle",TeXEnd,       matchLeftRight, '<',  (void *)doLeftRight},
    {"left:\\rangle", TeXBegin,     matchLeftRight, '>',  (void *)doLeftRight},
    {"right:\\rangle",TeXEnd,       matchLeftRight, '>',  (void *)doLeftRight},
    {"left:\\backslash", TeXBegin,  matchLeftRight, '\\',  (void *)doLeftRight},
    {"right:\\backslash",TeXEnd,    matchLeftRight, '\\',  (void *)doLeftRight},
    {"left:\\lfloor", TeXBegin,     matchLeftRight, 'L',  (void *)doLeftRight},
    {"right:\\lfloor",TeXEnd,       matchLeftRight, 'L',  (void *)doLeftRight},
    {"left:\\rfloor", TeXBegin,     matchLeftRight, 'J',  (void *)doLeftRight},
    {"right:\\rfloor",TeXEnd,       matchLeftRight, 'J',  (void *)doLeftRight},
    {"left:\\lceil",  TeXBegin,     matchLeftRight, 'G',  (void *)doLeftRight},
    {"right:\\lceil", TeXEnd,       matchLeftRight, 'G',  (void *)doLeftRight},
    {"left:\\rceil",  TeXBegin,     matchLeftRight, '7',  (void *)doLeftRight},
    {"right:\\rceil", TeXEnd,       matchLeftRight, '7',  (void *)doLeftRight},
    {"left:\\uparrow", TeXBegin,    matchLeftRight, '^',  (void *)doLeftRight},
    {"right:\\uparrow",TeXEnd,      matchLeftRight, '^',  (void *)doLeftRight},
    {"left:\\downarrow", TeXBegin,  matchLeftRight, 'v',  (void *)doLeftRight},
    {"right:\\downarrow",TeXEnd,    matchLeftRight, 'v',  (void *)doLeftRight},
    {"left:\\updownarrow", TeXBegin,matchLeftRight, 'b',  (void *)doLeftRight},
    {"right:\\updownarrow",TeXEnd,  matchLeftRight, 'b',  (void *)doLeftRight},
    {"left:\\Uparrow", TeXBegin,    matchLeftRight, 'A',  (void *)doLeftRight},
    {"right:\\Uparrow",TeXEnd,      matchLeftRight, 'A',  (void *)doLeftRight},
    {"left:\\Downarrow", TeXBegin,  matchLeftRight, 'V',  (void *)doLeftRight},
    {"right:\\Downarrow",TeXEnd,    matchLeftRight, 'V',  (void *)doLeftRight},
    {"left:\\Updownarrow", TeXBegin,matchLeftRight, 'B',  (void *)doLeftRight},
    {"right:\\Updownarrow",TeXEnd,  matchLeftRight, 'B',  (void *)doLeftRight},
// Some other things that generate enclosing contexts
    {"{",          TeXBegin,  matchBrace,     '{',  NULL},
    {"}",          TeXEnd,    matchBrace,     '{',  NULL},
// "[" and "]" are fairly ordinary characters when they just happen in
// random places. But after "\sqrt" (and possibly other things) they
// enclose an optional argument.
    {"[",          TeXSymbol, FntRoman,  0x5b, NULL},
    {"]",          TeXSymbol, FntRoman,  0x5d, NULL},
// At present I will treate "\(" and "\[" as synonyms - both just
// enter maths mode.
    {"\\(",        TeXBegin,  matchParen,     '(',  (void *)doMathBrace},
    {"\\)",        TeXEnd,    matchParen,     '(',  (void *)doMathBrace},
    {"\\[",        TeXBegin,  matchBracket,   '[',  (void *)doMathBrace},
    {"\\]",        TeXEnd,    matchBracket,   '[',  (void *)doMathBrace},
    {"$",          TeXBegin,  matchDollar,    '$',  (void *)doDollar},

// Treatment for "\&" etc that just generate literal characters.
// Note and be warned - the TeX fonts that are going to be used
// here have their own special encoding schemes so the numeric values
// that stand for even ordinary-seeming glyphs need careful attention.
    {"\\{",        TeXSymbol, FntSymbol, 0x66, NULL},
    {"\\}",        TeXSymbol, FntSymbol, 0x67, NULL},
    {"\\$",        TeXSymbol, FntRoman,  0x24, NULL},
    {"\\&",        TeXWSymbol,FntRoman,  0x26, NULL},
    {"\\%",        TeXSymbol, FntRoman,  0x25, NULL},

// subscripts and superscripts involve some parsing magic
    {"^",          TeXScript, 0,         0,    NULL},
    {"_",          TeXScript, 1,         0,    NULL},

// Simple symbols that need some care because the normal code used
// here may not match TeX font encodings.
    {"+",          TeXWSymbol,FntRoman,  0x2b, NULL},
    {"-",          TeXWSymbol,FntSymbol, 0x00, NULL}, // Roman 0x2d is hyphen
    {"=",          TeXWSymbol,FntRoman,  0x3d, NULL},
    {"*",          TeXSymbol, FntRoman,  0x2a, NULL},
    {"/",          TeXSymbol, FntRoman,  0x2f, NULL},
    {":",          TeXSymbol, FntRoman,  0x3a, NULL},
    {";",          TeXSymbol, FntRoman,  0x3b, NULL},
    {"@",          TeXSymbol, FntRoman,  0x40, NULL},
    {",",          TeXSymbol, FntRoman,  0x2c, NULL},
    {".",          TeXSymbol, FntRoman,  0x2e, NULL},
    {"?",          TeXSymbol, FntRoman,  0x3f, NULL},
    {"!",          TeXSymbol, FntRoman,  0x21, NULL},
    {"|",          TeXSymbol, FntSymbol, 0x6a, NULL},
    {"`",          TeXSymbol, FntRoman,  0x12, NULL},
//  {"NOTSIGN",    TeXSymbol, FntSymbol, 0x3a, NULL},
    {"#",          TeXSymbol, FntRoman,  0x23, NULL},
    {"~",          TeXSymbol, FntRoman,  0x7f, NULL},
    {"(",          TeXSymbol, FntRoman,  0x28, NULL},
    {")",          TeXSymbol, FntRoman,  0x29, NULL},
    {"<",          TeXSymbol, FntItalic, 0x3c, NULL},
    {">",          TeXSymbol, FntItalic, 0x3e, NULL},

// Lower case Greek

    {"alpha",      TeXSymbol, FntItalic, 0x0b, NULL},
    {"beta",       TeXSymbol, FntItalic, 0x0c, NULL},
    {"gamma",      TeXSymbol, FntItalic, 0x0d, NULL},
    {"delta",      TeXSymbol, FntItalic, 0x0e, NULL},
    {"epsilon",    TeXSymbol, FntItalic, 0x0f, NULL},
    {"varepsilon", TeXSymbol, FntItalic, 0x22, NULL},
    {"zeta",       TeXSymbol, FntItalic, 0x10, NULL},
    {"eta",        TeXSymbol, FntItalic, 0x11, NULL},
    {"theta",      TeXSymbol, FntItalic, 0x12, NULL},
    {"vartheta",   TeXSymbol, FntItalic, 0x23, NULL},
    {"iota",       TeXSymbol, FntItalic, 0x13, NULL},
    {"kappa",      TeXSymbol, FntItalic, 0x14, NULL},
    {"lambda",     TeXSymbol, FntItalic, 0x15, NULL},
    {"mu",         TeXSymbol, FntItalic, 0x16, NULL},
    {"nu",         TeXSymbol, FntItalic, 0x17, NULL},
    {"xi",         TeXSymbol, FntItalic, 0x18, NULL},
    {"omicron",    TeXSymbol, FntItalic, 'o',  NULL},
    {"pi",         TeXSymbol, FntItalic, 0x19, NULL},
    {"varpi",      TeXSymbol, FntItalic, 0x24, NULL},
    {"rho",        TeXSymbol, FntItalic, 0x1a, NULL},
    {"varrho",     TeXSymbol, FntItalic, 0x25, NULL},
    {"sigma",      TeXSymbol, FntItalic, 0x1b, NULL},
    {"varsigma",   TeXSymbol, FntItalic, 0x26, NULL},
    {"tau",        TeXSymbol, FntItalic, 0x1c, NULL},
    {"upsilon",    TeXSymbol, FntItalic, 0x1d, NULL},
    {"phi",        TeXSymbol, FntItalic, 0x1e, NULL},
    {"varphi",     TeXSymbol, FntItalic, 0x27, NULL},
    {"chi",        TeXSymbol, FntItalic, 0x1f, NULL},
    {"psi",        TeXSymbol, FntItalic, 0x20, NULL},
    {"omega",      TeXSymbol, FntItalic, 0x21, NULL},
//
// Upper case Greek (using Maths Italic for A, B etc where shapes are
// the same).

    {"Alpha",      TeXSymbol, FntItalic, 'A',  NULL},
    {"Beta",       TeXSymbol, FntItalic, 'B',  NULL},
    {"Gamma",      TeXSymbol, FntItalic, 0x00, NULL},
    {"Delta",      TeXSymbol, FntItalic, 0x01, NULL},
    {"Epsilon",    TeXSymbol, FntItalic, 'E',  NULL},
    {"Zeta",       TeXSymbol, FntItalic, 'Z',  NULL},
    {"Eta",        TeXSymbol, FntItalic, 'H',  NULL},
    {"Theta",      TeXSymbol, FntItalic, 0x02, NULL},
    {"Iota",       TeXSymbol, FntItalic, 'I',  NULL},
    {"Kappa",      TeXSymbol, FntItalic, 'K',  NULL},
    {"Lambda",     TeXSymbol, FntItalic, 0x03, NULL},
    {"Mu",         TeXSymbol, FntItalic, 'M',  NULL},
    {"Nu",         TeXSymbol, FntItalic, 'N',  NULL},
    {"Xi",         TeXSymbol, FntItalic, 0x04, NULL},
    {"Omicron",    TeXSymbol, FntItalic, 'O',  NULL},
    {"Pi",         TeXSymbol, FntItalic, 0x05, NULL},
    {"Rho",        TeXSymbol, FntItalic, 'R',  NULL},
    {"Sigma",      TeXSymbol, FntItalic, 0x06, NULL},
    {"Tau",        TeXSymbol, FntItalic, 'T',  NULL},
    {"Upsilon",    TeXSymbol, FntItalic, 0x07, NULL},
    {"Phi",        TeXSymbol, FntItalic, 0x08, NULL},
    {"Chi",        TeXSymbol, FntItalic, 'X',  NULL},
    {"Psi",        TeXSymbol, FntItalic, 0x09, NULL},
    {"Omega",      TeXSymbol, FntItalic, 0x0a, NULL},
//
// More mathematical symbols. I have copied all the names from my LaTeX
// book and identified available characters in the cmmi or cmsy fonts where
// I can. I have at present commented out all characters for which I do not
// have a glyph. The effect will be that the TeX symbol that names them will
// be rejected. In some cases I note another font that could help.

    {"pm",               TeXWSymbol,FntSymbol, 0x06, NULL},
    {"mp",               TeXWSymbol,FntSymbol, 0x07, NULL},
    {"times",            TeXSymbol, FntSymbol, 0x02, NULL},
    {"div",              TeXSymbol, FntSymbol, 0x04, NULL},
    {"ast",              TeXSymbol, FntSymbol, 0x03, NULL},
    {"star",             TeXSymbol, FntItalic, 0x3f, NULL},
    {"circ",             TeXSymbol, FntSymbol, 0x0e, NULL},
    {"bullet",           TeXSymbol, FntSymbol, 0x0f, NULL},
    {"cdot",             TeXSymbol, FntSymbol, 0x01, NULL},
    {"cap",              TeXSymbol, FntSymbol, 0x5c, NULL},
    {"cup",              TeXSymbol, FntSymbol, 0x5b, NULL},
    {"uplus",            TeXSymbol, FntSymbol, 0x5d, NULL},
    {"sqcap",            TeXSymbol, FntSymbol, 0x75, NULL},
    {"sqcup",            TeXSymbol, FntSymbol, 0x74, NULL},
    {"vee",              TeXSymbol, FntSymbol, 0x5f, NULL},
    {"wedge",            TeXSymbol, FntSymbol, 0x5e, NULL},
// The Variable-sized symbols tend to come in two sizes, and although TeX
// only used one name (eg \int) and selects which to use based on whether
// one is in displaymath or ordinary (in-line) mode. Here I am "always" in
// displaymath mode so I always want the larger versions. But I provide
// alternative names starting "small" to keep the others available.
    {"smallsum",         TeXVSymbol, FntExtension, 0x50, NULL},
    {"sum",              TeXVSymbol, FntExtension, 0x58, NULL},
    {"smallprod",        TeXVSymbol, FntExtension, 0x51, NULL},
    {"prod",             TeXVSymbol, FntExtension, 0x59, NULL},
    {"smallcoprod",      TeXVSymbol, FntExtension, 0x60, NULL},
    {"coprod",           TeXVSymbol, FntExtension, 0x61, NULL},
    {"smallint",         TeXVSymbol, FntExtension, 0x52, NULL},
    {"int",              TeXVSymbol, FntExtension, 0x5a, NULL},
// It looks to me as if tmprint.red can generate either \int or \Int
// and maybe it expects one to be smaller than the other...???
    {"Int",              TeXVSymbol, FntExtension, 0x5a, NULL},
    {"smalloint",        TeXVSymbol, FntExtension, 0x48, NULL},
    {"oint",             TeXVSymbol, FntExtension, 0x49, NULL},
    {"smallbigcup",      TeXVSymbol, FntExtension, 0x53, NULL},
    {"nigcup",           TeXVSymbol, FntExtension, 0x5b, NULL},
    {"smallbigcap",      TeXVSymbol, FntExtension, 0x54, NULL},
    {"bigcap",           TeXVSymbol, FntExtension, 0x5c, NULL},
    {"smallbiguplus",    TeXVSymbol, FntExtension, 0x55, NULL},
    {"biguplus",         TeXVSymbol, FntExtension, 0x5d, NULL},
    {"smallbigodot",     TeXVSymbol, FntExtension, 0x4a, NULL},
    {"bigodot",          TeXVSymbol, FntExtension, 0x4b, NULL},
    {"smallbigotimes",   TeXVSymbol, FntExtension, 0x4e, NULL},
    {"bigotimes",        TeXVSymbol, FntExtension, 0x4f, NULL},
    {"smallbigoplus",    TeXVSymbol, FntExtension, 0x4c, NULL},
    {"bigoplus",         TeXVSymbol, FntExtension, 0x4d, NULL},
    {"smallbigsqcup",    TeXVSymbol, FntExtension, 0x46, NULL},
    {"bigsqcup",         TeXVSymbol, FntExtension, 0x47, NULL},
    {"smallbigwedge",    TeXVSymbol, FntExtension, 0x56, NULL},
    {"bigwedge",         TeXVSymbol, FntExtension, 0x5e, NULL},
    {"smallbigvee",      TeXVSymbol, FntExtension, 0x57, NULL},
    {"bigvee",           TeXVSymbol, FntExtension, 0x5f, NULL},
// end of variable sized things
    {"setminus",         TeXSymbol, FntSymbol, 0x6e, NULL},
    {"wr",               TeXSymbol, FntSymbol, 0x6f, NULL},
    {"diamond",          TeXSymbol, FntSymbol, 0x05, NULL},
    {"bigtriangleup",    TeXSymbol, FntSymbol, 0x35, NULL},
    {"bigtriangledown",  TeXSymbol, FntSymbol, 0x36, NULL},
    {"triangleleft",     TeXSymbol, FntItalic, 0x2f, NULL},
    {"triangleright",    TeXSymbol, FntItalic, 0x2e, NULL},
//  {"lhd",              TeXSymbol, FntSymbol, 0x00, NULL},  // msam 0x43
//  {"rhd",              TeXSymbol, FntSymbol, 0x00, NULL},  // msam 0x42
//  {"unlhd",            TeXSymbol, FntSymbol, 0x00, NULL},  // msam 0x45
//  {"unrhd",            TeXSymbol, FntSymbol, 0x00, NULL},  // msam 0x44
    {"oplus",            TeXSymbol, FntSymbol, 0x08, NULL},
    {"ominus",           TeXSymbol, FntSymbol, 0x09, NULL},
    {"otimes",           TeXSymbol, FntSymbol, 0x0a, NULL},
    {"oslash",           TeXSymbol, FntSymbol, 0x0b, NULL},
    {"odot",             TeXSymbol, FntSymbol, 0x0c, NULL},
    {"bigcirc",          TeXSymbol, FntSymbol, 0x0d, NULL},
    {"dagger",           TeXSymbol, FntSymbol, 0x79, NULL},
    {"ddagger",          TeXSymbol, FntSymbol, 0x7a, NULL},
    {"amalg",            TeXSymbol, FntSymbol, 0x71, NULL},
    {"leq",              TeXSymbol, FntSymbol, 0x14, NULL},
    {"prec",             TeXSymbol, FntSymbol, 0x1e, NULL},
    {"preceq",           TeXSymbol, FntSymbol, 0x16, NULL},
    {"ll",               TeXSymbol, FntSymbol, 0x1c, NULL},
    {"subset",           TeXSymbol, FntSymbol, 0x1a, NULL},
    {"subseteq",         TeXSymbol, FntSymbol, 0x12, NULL},
//  {"sqsubset",         TeXSymbol, FntSymbol, 0x00, NULL},  // lasy 0x3c
    {"sqsubseteq",       TeXSymbol, FntSymbol, 0x75, NULL},
    {"in",               TeXSymbol, FntSymbol, 0x32, NULL},
    {"vdash",            TeXSymbol, FntSymbol, 0x60, NULL},
    {"geq",              TeXSymbol, FntSymbol, 0x15, NULL},
    {"succ",             TeXSymbol, FntSymbol, 0x1f, NULL},
    {"succeq",           TeXSymbol, FntSymbol, 0x17, NULL},
    {"gg",               TeXSymbol, FntSymbol, 0x1d, NULL},
    {"supset",           TeXSymbol, FntSymbol, 0x1b, NULL},
    {"supseteq",         TeXSymbol, FntSymbol, 0x13, NULL},
//  {"sqsupset",         TeXSymbol, FntSymbol, 0x00, NULL},  // lasy 0x3d
    {"sqsupseteq",       TeXSymbol, FntSymbol, 0x77, NULL},
    {"ni",               TeXSymbol, FntSymbol, 0x33, NULL},
    {"dashv",            TeXSymbol, FntSymbol, 0x61, NULL},
    {"equiv",            TeXSymbol, FntSymbol, 0x11, NULL},
    {"sim",              TeXSymbol, FntSymbol, 0x18, NULL},
    {"simeq",            TeXSymbol, FntSymbol, 0x27, NULL},
    {"asymp",            TeXSymbol, FntSymbol, 0x10, NULL},
    {"approx",           TeXSymbol, FntSymbol, 0x19, NULL},
    {"cong",             TeXSymbol, FntSymbol, 0x00, NULL},  // msbm 0x74
//  {"doteq",            TeXSymbol, FntSymbol, 0x00, NULL},  // ?
//  {"propto",           TeXSymbol, FntSymbol, 0x2f, NULL},
    {"models",           TeXSymbol, FntSymbol, 0x00, NULL},  // msam 0x0f
//  {"perp",             TeXSymbol, FntSymbol, 0x3f, NULL},
    {"mid",              TeXSymbol, FntSymbol, 0x6a, NULL},
    {"parallel",         TeXSymbol, FntSymbol, 0x6b, NULL},
//  {"bowtie",           TeXSymbol, FntSymbol, 0x00, NULL},  // lasy 0x31
//  {"join",             TeXSymbol, FntSymbol, 0x00, NULL},  // ?
    {"smile",            TeXSymbol, FntItalic, 0x5e, NULL},
    {"frown",            TeXSymbol, FntItalic, 0x5f, NULL},
    {"leftarrow",        TeXSymbol, FntSymbol, 0x20, NULL},
    {"Leftarrow",        TeXSymbol, FntSymbol, 0x28, NULL},
    {"rightarrow",       TeXSymbol, FntSymbol, 0x21, NULL},
    {"Rightarrow",       TeXSymbol, FntSymbol, 0x29, NULL},
    {"leftrightarrow",   TeXSymbol, FntSymbol, 0x24, NULL},
    {"Leftrightarrow",   TeXSymbol, FntSymbol, 0x2c, NULL},
//  {"mapsto",           TeXSymbol, FntSymbol, 0x00, NULL},  // ?msam 0x110
//  {"hookleftarrow",    TeXSymbol, FntSymbol, 0x00, NULL},  // ?
//  {"leftharpoonup",    TeXSymbol, FntSymbol, 0x00, NULL},  // euex 0x18
//  {"leftharpoondown",  TeXSymbol, FntSymbol, 0x00, NULL},  // euex 0x19
//  {"rightleftharpoons",TeXSymbol, FntSymbol, 0x00, NULL},  // ?
//  {"longmapsto",       TeXSymbol, FntSymbol, 0x00, NULL},  // ?
//  {"hookrightarrow",   TeXSymbol, FntSymbol, 0x00, NULL},  // ?
//  {"rightharpoonup",   TeXSymbol, FntSymbol, 0x00, NULL},  // euex 0x1a
//  {"rightharpoondown", TeXSymbol, FntSymbol, 0x00, NULL},  // euex 0x1b
//  {"leadsto",          TeXSymbol, FntSymbol, 0x00, NULL},  // lasy 0x3a
    {"uparrow",          TeXSymbol, FntSymbol, 0x22, NULL},
    {"Uparrow",          TeXSymbol, FntSymbol, 0x2a, NULL},
    {"downarrow",        TeXSymbol, FntSymbol, 0x23, NULL},
    {"Downarrow",        TeXSymbol, FntSymbol, 0x2b, NULL},
    {"updownarrow",      TeXSymbol, FntSymbol, 0x6c, NULL},
    {"Updownarrow",      TeXSymbol, FntSymbol, 0x6d, NULL},
    {"nearrow",          TeXSymbol, FntSymbol, 0x25, NULL},
    {"searrow",          TeXSymbol, FntSymbol, 0x26, NULL},
    {"swarrow",          TeXSymbol, FntSymbol, 0x2e, NULL},
    {"nwarrow",          TeXSymbol, FntSymbol, 0x2d, NULL},
    {"aleph",            TeXSymbol, FntSymbol, 0x40, NULL},
//  {"hbar",             TeXSymbol, FntSymbol, 0x00, NULL},  // msbm 0x7e
    {"imath",            TeXSymbol, FntItalic, 0x7b, NULL},
    {"jmath",            TeXSymbol, FntItalic, 0x7c, NULL},
//  {"ell",              TeXSymbol, FntSymbol, 0x00, NULL},  // ?
//  {"wp",               TeXSymbol, FntSymbol, 0x00, NULL},  // eufb 0x50
    {"Re",               TeXSymbol, FntSymbol, 0x3c, NULL},
    {"Im",               TeXSymbol, FntSymbol, 0x3d, NULL},
//  {"mho",              TeXSymbol, FntSymbol, 0x00, NULL},  // lasy 0x30
    {"prime",            TeXSymbol, FntSymbol, 0x30, NULL},
    {"emptyset",         TeXSymbol, FntSymbol, 0x3b, NULL},
    {"nabla",            TeXSymbol, FntSymbol, 0x35, NULL},
    {"surd",             TeXSymbol, FntSymbol, 0x72, NULL},
    {"top",              TeXSymbol, FntSymbol, 0x3e, NULL},
    {"bot",              TeXSymbol, FntSymbol, 0x3f, NULL},
    {"|",                TeXSymbol, FntSymbol, 0x6b, NULL},
//  {"angle",            TeXSymbol, FntSymbol, 0x00, NULL},  // msam 0x5c
    {"forall",           TeXSymbol, FntSymbol, 0x38, NULL},
    {"exists",           TeXSymbol, FntSymbol, 0x39, NULL},
    {"neg",              TeXSymbol, FntSymbol, 0x3a, NULL},
    {"flat",             TeXSymbol, FntItalic, 0x5d, NULL},
    {"natural",          TeXSymbol, FntItalic, 0x5c, NULL},
    {"sharp",            TeXSymbol, FntItalic, 0x5b, NULL},
    {"backslash",        TeXSymbol, FntSymbol, 0x6e, NULL},
    {"partial",          TeXSymbol, FntItalic, 0x40, NULL},
    {"infty",            TeXSymbol, FntSymbol, 0x31, NULL},
//  {"Box",              TeXSymbol, FntSymbol, 0x00, NULL},  // msam 0x04
//  {"Diamond",          TeXSymbol, FntSymbol, 0x00, NULL},  // msam 0x07
//  {"Triangle",         TeXSymbol, FntSymbol, 0x00, NULL},  // msam 0x4d
    {"clubsuit",         TeXSymbol, FntSymbol, 0x7c, NULL},
    {"diamondsuit",      TeXSymbol, FntSymbol, 0x7d, NULL},
    {"heartsuit",        TeXSymbol, FntSymbol, 0x7e, NULL},
    {"spadesuit",        TeXSymbol, FntSymbol, 0x7f, NULL},

 //
 // Things to be rendered in Roman since they are function names

    {"arccos",     TeXRoman,  0,         0,    (void *)"arccos"},
    {"arcsin",     TeXRoman,  0,         0,    (void *)"arcsin"},
    {"arctan",     TeXRoman,  0,         0,    (void *)"arctan"},
    {"arg",        TeXRoman,  0,         0,    (void *)"arg"},
    {"cos",        TeXRoman,  0,         0,    (void *)"cos"},
    {"cosh",       TeXRoman,  0,         0,    (void *)"cosh"},
    {"cot",        TeXRoman,  0,         0,    (void *)"cot"},
    {"coth",       TeXRoman,  0,         0,    (void *)"coth"},
    {"csc",        TeXRoman,  0,         0,    (void *)"csc"},
    {"deg",        TeXRoman,  0,         0,    (void *)"deg"},
    {"det",        TeXRoman,  0,         0,    (void *)"det"},
    {"dim",        TeXRoman,  0,         0,    (void *)"dim"},
    {"exp",        TeXRoman,  0,         0,    (void *)"exp"},
    {"gcd",        TeXRoman,  0,         0,    (void *)"gcd"},
    {"hom",        TeXRoman,  0,         0,    (void *)"hom"},
    {"inf",        TeXRoman,  0,         0,    (void *)"inf"},
    {"ker",        TeXRoman,  0,         0,    (void *)"ker"},
    {"lg",         TeXRoman,  0,         0,    (void *)"lg"},
    {"lim",        TeXRoman,  0,         0,    (void *)"lim"},
    {"liminf",     TeXRoman,  0,         0,    (void *)"liminf"},
    {"limsup",     TeXRoman,  0,         0,    (void *)"limsup"},
    {"ln",         TeXRoman,  0,         0,    (void *)"ln"},
    {"log",        TeXRoman,  0,         0,    (void *)"log"},
    {"max",        TeXRoman,  0,         0,    (void *)"max"},
    {"min",        TeXRoman,  0,         0,    (void *)"min"},
    {"Pr",         TeXRoman,  0,         0,    (void *)"Pr"},
    {"sec",        TeXRoman,  0,         0,    (void *)"sec"},
    {"sin",        TeXRoman,  0,         0,    (void *)"sin"},
    {"sinh",       TeXRoman,  0,         0,    (void *)"sinh"},
    {"sup",        TeXRoman,  0,         0,    (void *)"sup"},
    {"tan",        TeXRoman,  0,         0,    (void *)"tan"},
    {"tanh",       TeXRoman,  0,         0,    (void *)"tanh"},


//
// TeX things that take do not take an argument, as in
//              \word
// eg \displaystyle

    {"displaystyle", TeX0Arg, 0,         0,    (void *)doDisplayStyle},
// I only intend (at least to start with!) to support the \large
// directive in the context of \stackrel{\large A}{B} where it defeats
// the way that stackrel would otherwise shrink its first argument.
    {"large",        TeX0Arg, 0,         0,    (void *)doLarge},
// \neq seems to be a unique horrid case for me. I can not see a glyph for
// it in the Computer Modern set and so will end up synthesizing it as
// an overstrike of "=" and "/".
    {"neq",          TeX0Arg, 0,         0,    (void *)doNeq},
    {"not",          TeX0Arg, 0,         0,    (void *)doNot},

// The next two are needed for matrix layout. Maybe and with luck they
// will not occur freestanding.
    {"&",            TeX0Arg, 0,         0,    NULL},
    {"\\\\",         TeX0Arg, 0,         0,    NULL},
// The next bunch insert spacing manually
    {"\\*",          TeX0Arg, 0,         '*',  (void *)doSpaceCommand},
    {"\\ ",          TeX0Arg, 0,         ' ',  (void *)doSpaceCommand},
    {"\\,",          TeX0Arg, 0,         ',',  (void *)doSpaceCommand},
    {"\\!",          TeX0Arg, 0,         '!',  (void *)doSpaceCommand},
    {"\\:",          TeX0Arg, 0,         ':',  (void *)doSpaceCommand},
    {"\\;",          TeX0Arg, 0,         ';',  (void *)doSpaceCommand},
    {"\\_",          TeX0Arg, 0,         '_',  (void *)doSpaceCommand},

#define pack4ints(a,b,c,d) (((a)<<24) + ((b)<<16) + ((c)<<8) + (d))

    {"longleftarrow",      TeX0Arg, 0,
                           pack4ints(FntSymbol, 0x20, FntSymbol, 0x00), 
                           (void *)doAdjacent},
    {"Longleftarrow",      TeX0Arg, 0,
                           pack4ints(FntSymbol, 0x28, FntRoman, 0x3d),
                           (void *)doAdjacent},
    {"longrightarrow",     TeX0Arg, 0,
                           pack4ints(FntSymbol, 0x00, FntSymbol, 0x21), 
                           (void *)doAdjacent},
    {"Longrightarrow",     TeX0Arg, 0,
                           pack4ints(FntRoman, 0x3d, FntSymbol, 0x29), 
                           (void *)doAdjacent},
    {"longleftrightarrow", TeX0Arg, 0,
                           pack4ints(FntSymbol, 0x20, FntSymbol, 0x21), 
                           (void *)doAdjacent},
    {"Longleftrightarrow", TeX0Arg, 0,
                           pack4ints(FntSymbol, 0x28, FntSymbol, 0x29), 
                           (void *)doAdjacent},


//
// TeX things that take one argument, as in
//              \word {arg}
// eg \pmod{whatever}

    {"pmod",       TeX1Arg,   0,         0,    (void *)doPmod},
    {"mathrm",     TeX1Arg,   0,         0,    (void *)doMathRm},
    {"mathit",     TeX1Arg,   0,         0,    (void *)doMathIt},
    {"sqrt",       TeX1Arg,   0,         0,    (void *)doSqrt},
    {"fbox",       TeX1Arg,   0,         0,    (void *)doFbox},
    {"symb",       TeX1Arg,   0,         0,    (void *)doSymb},
//
// TeX things that take two arguments, as in
//              \word {arg1} {arg2}
// eg \frac{numerator}{denominator}
// Note that both frac and stackrel both make adjustments to the
// size of the naterial set as their arguments... but in eccentric
// and one-off ways!
    {"frac",       TeX2Arg,   '/',       0,    (void *)doFrac},
    {"stackrel",   TeX2Arg,   'S',       0,    (void *)doStackrel},

    {"rule",       TeXRule,   0,         0,    NULL},
    {NULL,         0,         0,         0,    NULL}
};


#define hashTableSize ((unsigned int)(sizeof(texWords)/sizeof(Keyword)))

// The hash function here is not especially clever or fast! But it should
// suffice. It looks at the first 4 characters of the string and returns
// a result in the range 0 to 511.

static unsigned int texHash(const char *s)
{
    unsigned int h = 0x123456;
    if (*s != 0)
    {   h = 169*h + *s++;
        if (*s != 0)
        {   h = 169*h + *s++;
            if (*s != 0)
            {   h = 169*h + *s++;
                h = 169*h + *s;
            }
        }
    }
    return (h ^ (h>>11)) % hashTableSize;
}

// returns either a reference to a Keyword record, or NULL if the word
// is not found.

static Keyword *lookupHash(const char *s)
{
    unsigned int h = texHash(s);
    for (;;)
    {   if (texWords[h].name == NULL) return NULL;
        else if (strcmp(s, texWords[h].name) == 0) return &texWords[h];
        else h = (h + 1) % hashTableSize;
    }
}

// On system-startup this code converts the initial neat array/table
// of keywords into a hash table.

static void rehashKeywordTable()
{
    unsigned int i = 0;
// First set a flag on every item that has not yet been re-hashed.
    while (texWords[i].name != NULL) texWords[i++].type |= TeXFlag;
#if 0
// I want my hash-table of LaTeX keywords to have a comfortable loading
// to balance lookup cost against the amount of waste space. The
// current state uses a little under 300 of the 512 entries, which
// seems satisfactory to me at present.
    printf("%d out of %d loading in hash table\n", i, hashTableSize);
#endif
    while (i < hashTableSize)
    {   texWords[i].name = NULL;
        texWords[i++].type = 0;
    }
    Keyword insert, pend;
    for (i=0; i<hashTableSize; i++)
    {   if ((texWords[i].type & TeXFlag) == 0) continue;
        pend = texWords[i];
        texWords[i].name = NULL;
        texWords[i].type = 0;
        while ((pend.type & TeXFlag) != 0)
        {   pend.type &= ~TeXFlag;
            insert = pend;
            unsigned int h = texHash(insert.name);
            for (;;)
            {   if (texWords[h].name == NULL)   // empty space to insert into
                {   texWords[h] = insert;
                    break;
                }
// I might come across a place where some not-yet-relocated entry lives. As
// far as the NEW hash table is concerned this represents empty space, so I
// insert there, moving the displaced data to a "pending" status.
                else if ((texWords[h].type & TeXFlag) != 0)
                {   pend = texWords[h];
                    texWords[h] = insert;
                    break;
                }
// If I find a hash table position that is already in use it can never be
// a match, so I just view it as a clash.
// I use a simple linear scan after clashes. This can lead to clustering
// but I am not that worried!
                h = (h + 1) % hashTableSize;
            }
        }
    }
}

///////////////////////////////////////////////////////////////////////////

// I want to be able to parse LaTeX-like stuff so that I can display it.
// I will use a pretty naive parser! It will look for the special
// characters
//     # $ % & ~ _ ^ \ { and }
// It also has to treat some other individual characters individually
//     + = | < > ` '
// and any item of the form "\" followed either by a single punctuation
// mark or by a (case-sensitive) word.

// There is a "current state" and nesting constructs save and restore it.
// Eg if there are any instances of
//    { ... \em ... }
// then the "\em" sets a state for the materiual after it but until the
// end of the brace-enclosed block.
//
// Key bits of syntax are
//    \begin{word} ... \end{word}
//    \word-not-needing-args
//    \word-needing-arg { ... }
//    \word-needing-2-args { ... } { ... }
//    \word[ ... , ... ] { ... }           if cases with options are needed
//    { ... }
//    $ ... $
//    \leftX ... \rightX
//    item item item ...
//

// The stream of characters that I parse are returned by a procedure that
// is passed down to my code...

static getTeXchar *nextChar;

static int curChar;

// I had better make the size of my lexer buffer at last as wide as the
// longest item I ever expect to see on a line. Well I hope that any code
// that drives this splits lines well before 256 characters...

#define maxLexLength 256
static char lexerBuffer[maxLexLength+1];
static int lexType, lexLength;
static Keyword *lexKey;

#define lexError     0x00
#define lexEOF       0x01
#define lexSpecial   0x02
#define lexWord      0x03
#define lexNumber    0x04
#define lexBegin     0x05
#define lexEnd       0x06
#define lexSuper     0x07
#define lexSub       0x08

// More careful syntax, since this is what I will implement
//
// The category "P" is for complete items, either single words
// or things where their end is clear-cut because of bracketing rules.
//    P ::=  begin(word) E end(word)
//                         // I treat eg \begin{centre} s one lexical symbol
//                         // and need a bracketing rule for each such.
//      |    { E }
//      |    \( E \)
//      |    \[ E \]
//      |    $ E $
//      |    \leftX E \rightX
//      |    \begin{matrix} rows \end{matrix}
//      |    one-arg-word opts { E }
//      |    two-arg-word opts { E } { E }
//      |    word
//      |    punctuation-mark
//      ;
// The category "S" allows a "P" to be given optional sub- or super-scripts.
// It permits at most one of each. One can of course write something like
//    "{a^b}^c"
// if you really want, but "a^b^c" will not be valid in proper TeX. However
// as a matter of generosity I will allow it here via the code going a bit
// beyond the syntax written out here
//    S ::=  P
//      |    P ^ P
//      |    P _ P
//      |    P ^ P _ P
//      |    P _ P ^ P
// The category "E" is for a possibly empty list of "S" forms. I will in fact
// parameterise my code to read an "E" so that in one variant it stops only
// at a close bracket or end-of-file and in the other it also stops at
// a comma.
//    E ::=
//      |   S
//      |   E S
//      ;
// "opts" and "ol" provide for optional parameters marked out using square
// brackets and with commas to separate off separate parts. Note that I have
// a formal ambiguity here over the syntax "a,b" where the comma could be a
// punctuation mark as a P or separator between arguments. Actually inspection
// of the code that generated TeX for me shows that \sqrt is the only thing
// where an optional argument gets used, so I will handle the case specially
// for there and NOT use this general rule!
//    opts ::=
//         | []
//         | [ ol ]
//         ;
//    ol ::= E
//       | ol , E
//       ;
// I deal specially with matrices by recognising & and \\ as delimiters.
// I view an empty matrix as an error and have an extra constraint that things
// should be rectangular, ie each row should have the same number of items
// in it.
//    rows ::= matrow
//         | rows \\ matrow
//         ;
//    matrow ::= E
//         | matrow & E
//         ;
// QUESTION: Do I need to take special account of things that are to be
//           thought of as binary operators, such as +, - etc?
//           I may want to if I want the tree that I produce to be a
//           semantic model of the material being displayed and if I then
//           want selection to respect this structure. But to start with
//           I intend to try without.

// To do line-breaking here I will need to extend the syntax for E to be
// more like:
//
//    E ::=
//      |   S1
//      |   E S1
//      ;
// QUERY: especially in the light of REDLOG I may need precedence-related
// rules here for AND and OR and EQUALS. How pressing is that?
//    S1 := S2
//       | S1 + S2
//       | S1 - S2
//       | + S1
//       | - S1
//       ;
//    S2 ::= S3
//       | S2 \times S3
//       | \frac{E}{E}
//       ;
//    S3 ::= item LPAR ARGLIST RPAR
// etc.
// I am not yet really certain just how much I need to do here but my current
// thoughts are that for line-breaking I will need to be able to notice the
// cases for
//    A + B + C + D +
//    E + F + G                 break at a + or - rather than within a term
//                              and similarly for lists {A,B,C} and (A,B,C)
//
//    (... ... ...          vs    ... ... ...
//    ... ...) / (...)            -----------    for displayed fractions
//                                ... ... ...
//
//    matrix display where possible
//
//    Some uncomfortable fall-back for cases with huge expressions as
//    exponents, subscripts, single args for functions etc
//
//    Treatement of numbers that have huge numbers of digits (and I guess
//    words that are very very long too)
//
//    sqrt(... ... ...      vs   /---------------
//    ... ... ...)              v ... ... ... ...
//
//    Groupings implied by all sorts of brackets, also by the prefix
//    items \int, \sum (etc). This last one is NASTY since it is not clear
//    that there is any way to tell when the guarded expression ends!

static void nextSymbol();

static Box *readE(int stopAt);
#define stopComma 0x01
#define stopTab   0x02
#define stopNL    0x04
#define stopKet   0x08
static Box *readS();

// Some systems have problems with characters that have a numeric code
// less than (or possibly even equal to) 0x20. Although many modern systems
// can cope the Postscript fonts that I use provide re-mapped glyphs with
// code values in the 0x80 to 0xff range that may be safer to use.

// With some X servers I still have trouble with character 0xa1, which is
// where 0x00 gets mapped to. Actually it seems worse than that: I can
// re-map the font to change the code to yet something different and still
// sometimes the character does not appear. I reserve code 0xc5 for such
// and extra remapping, but the tables here do not touch it at present!

static char remapTable[33] =
{
    0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
    0xa9, 0xaa, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2,
    0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
    0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2,
    0xa0
};

static int remap(int ch)
{
    ch &= 0xff;       // in case chars are signed.
#ifndef WIN32
// If I use Xft to render things I can afford to (and indeed had better)
// use glyph positions in ther original locations. Also if I am printing
// I will avoid remapping.
    if (fwin_use_xft) return (char)ch;
#endif
    if (ch < 0x20) return remapTable[ch];
// There is SOME possibility that I should remap character 0x20 to 0xa0,
// but right now my belief is that I should not.
    else if (ch == 0x7f) return (char)0xc4;
    else return (char)ch;
}

#ifdef HAVE_XFT

// I will also set myself up so that I can restore the original encoding.

static char unmapTable[38] =
{
    0x20, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
    0x07, 0x08, 0x09, 0xab, 0xac, 0x0a, 0x0b, 0x0c,
    0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
    0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
    0x1d, 0x1e, 0x1f, 0x20, 0x7f, 0xc5
};

static int unmap(int ch)
{
    ch &= 0xff;
    if (ch < 0xa0 || ch > 0xc5) return (char)ch;
    return unmapTable[ch - 0xa0];
}

#endif

static Box *readRow()
{
    Box *result = makeSymBox(SymNothing);
    Box *n = readE(stopTab + stopNL);
    if (n != NULL) result = makeNestBox(BoxBeside, result, n);
    while (lexType == lexSpecial &&
            strcmp(lexKey->name, "&") == 0)
    {   nextSymbol();
        n = readE(stopTab + stopNL);
        if (n != NULL) result = makeNestBox(BoxBeside, result, n);
    }
    return result;
}

static Box *readRows()
{
    Box *result = makeSymBox(SymNothing);
    Box *n = readRow();
    if (n != NULL) result = makeNestBox(BoxTower, result, n);
    while (lexType == lexSpecial &&
            strcmp(lexKey->name, "\\\\") == 0)
    {   nextSymbol();
        Box *n = readRow();
        if (n != NULL) result = makeNestBox(BoxTower, result, n);
    }
    return result;
}

static Box *readMatrix()
{
    Box *contents = NULL;
    TeXState saveState = currentState;
    nextSymbol();
    contents = readRows();
    if (lexType == lexError) return NULL;
    else if (lexType != lexEnd || matchMatrix != lexKey->font)
    {   printf("end does not match begin properly\n");
        printf("Want \\end{matrix} got %d/%d\n", lexType, lexKey->font);
        lexType = lexError;
        return NULL;
    }
    currentState = saveState;
    contents = makeMatrixBox(contents);
    nextSymbol();
    return contents;
}

static void skipUnit()
{
    if (lexType != lexWord) return;
    if (strcmp(lexerBuffer, "pt") == 0) nextSymbol();
}

static int readNumber()
{
    int r;
    if (lexType == lexNumber)
    {   sscanf(lexerBuffer, "%d", &r);
        nextSymbol();
        skipUnit();
        return r;
    }
    else if (lexType == lexSpecial && strcmp(lexerBuffer, "-") == 0)
    {   nextSymbol();
        if (lexType == lexNumber)
        {   sscanf(lexerBuffer, "%d", &r);
            nextSymbol();
            skipUnit();
            return -r;
        }
    }
    return 0;
}

static Box *readP()
{   switch (lexType)
    {
case lexBegin:
        {   int w = lexKey->font; // used to say which sort of "begin"
            if (w == matchMatrix) return readMatrix();
            int chL = lexKey->charCode;
            Box *contents = NULL;
            TeXState saveState = currentState;
            blockHandlerFunction *fn = (blockHandlerFunction *)lexKey->ptr;
            if (fn != NULL) fn(chL, ' ', NULL);
            nextSymbol();
            contents = readE(0);
            if (lexType == lexError) return NULL;
            else if (lexType == lexEOF)
            {
// Here if I find an EOF when I was expecting a close bracket of some sort
// I just treat it as if the close bracket had been found, an in the case
// of \left..\right I treat it as if I had seen "\right .".
                if (fn != NULL) contents = fn(chL, '.', contents);
                return contents;
            }
            else if (lexType != lexEnd || w != lexKey->font)
            {   printf("end does not match begin properly\n");
                printf("Want %d/%d got %d/%d\n",
                       lexEnd, w, lexType, lexKey->font);
                lexType = lexError;
// In this case I will not perform any side-effects that calling the handler
// function normally would at the end of a block. That certainly means,
// for instance, that I lose track of whether I am inside or outside "$"
// markers. But since I have reported an error and the parse is getting
// nowhere this does not worry me.
                return NULL;
            }
            currentState = saveState;
            if (fn != NULL) contents = fn(chL, lexKey->charCode, contents);
            nextSymbol();
            return contents;
        }
case lexWord:
        {   Box *b = makeTextBox(lexerBuffer, lexLength,
                         currentState.currentFont); // includes currentSize
            nextSymbol();
            return b;
        }
case lexNumber:
        {   Box *b = makeTextBox(lexerBuffer, lexLength,
                         FntRoman + currentSize);
            nextSymbol();
            return b;
        }
case lexSpecial:   // in this case lexKey tells me which keyword it is.
        switch (lexKey->type)
        {
    case TeXSymbol:
            {   char s[2];
                s[0] = remap(lexKey->charCode);
                s[1] = 0;
                Box *b = makeTextBox(s, 1, lexKey->font + currentSize);
                nextSymbol();
                return b;
            }
    case TeXWSymbol:
            {   char s[2];
                s[0] = remap(lexKey->charCode);
                s[1] = 0;
                Box *b = makeTextBox(s, 1, lexKey->font + currentSize);
                nextSymbol();
                return makeNestBox(BoxPadSpace, b, NULL);
            }
    case TeXVSymbol:
// This case will need MORE WORK in a couple of ways:
//   (a) the symbol used is from the cmex font and so is positioned as
//       a descender. It will need moving to put it where it wants to go!
//   (b) subscripts and superscripts for these objects get put in special
//       places. Eg consider \sum{i=0}^{n}.
// I mark for these by setting the "FntBig" bit in the byte that gives font
// and size. That then mostly has to adjust the code that lays out subscripts.
            {   char s[2];
                s[0] = remap(lexKey->charCode);
                s[1] = 0;
                Box *b = makeTextBox(s, 1, lexKey->font + FntBig + currentSize);
                nextSymbol();
                return b;
            }
    case TeXRoman:
            {   Box *b = makeTextBox((const char *)lexKey->ptr,
                                     strlen((const char *)lexKey->ptr),
                                     FntRoman + currentSize);
                nextSymbol();
                return b;
            }
    case TeXScript:
            printf("TeX script-marker found but not handled (%s)\n", lexKey->name);
            nextSymbol();
            return NULL;
    case TeX0Arg:
            if (lexKey->ptr != NULL)
            {   Box *b = ((keywordHandlerFunction *)(lexKey->ptr))(lexKey->charCode);
                nextSymbol();
                return b;
            }
            printf("TeX keyword 0 found but not handled (%s)\n", lexKey->name);
            nextSymbol();
            return NULL;
    case TeX1Arg:
// One-arg things can include cases such as "\sqrt" which need to support
// optional args as well as the mandatory one. As best I can see in the
// current tmprint code "\sqrt" is the only such case used! Furthermore
// I think it only ever puts ONE item within the "[]", as in
//           \sqrt[3]{1+x}      or    \sqrt[p]{A}
// but it does put a "\," within the square brackets to adjust spacing.
            {   Keyword *key = lexKey;   // remember what introduced this
                Box *contents = NULL, *optarg = NULL;
                TeXState saveState = currentState;
                oneArgHandlerFunction *fn = (oneArgHandlerFunction *)key->ptr;
                nextSymbol();
// Check here for a "["
                if (lexType == lexSpecial &&
                    strcmp(lexKey->name, "[") == 0)
                {   nextSymbol();
                    if (currentSize < FntScrScr) currentState.currentFont+=FntScript;
                    optarg = readE(stopKet);
                    if (lexType != lexSpecial ||
                        strcmp(lexKey->name, "]") != 0)
                    {   printf("\"]\" not found\n");
                        lexType = lexError;
                        currentState = saveState;
                        return NULL;
                    }
                    currentState = saveState;
                    nextSymbol();
                }
// The state I use when parsing the argument may be changed by this where I
// call the handler with NULL arguments.
                if (fn != NULL) fn(NULL, NULL);
                if (lexType != lexBegin ||
                    lexKey->font != matchBrace)
                {   printf("\"{\" expected after keyword \"\\%s\"\n",
                        lexKey->name);
                    lexType = lexError;
                    currentState = saveState;
                    return NULL;
                }
                else nextSymbol();
                contents = readE(0);
                if (lexType == lexError)
                {   currentState = saveState;
                    return NULL;
                }
                else if (lexType != lexEnd || lexKey->font != matchBrace)
                {
// While I am lenient about SOME forms of bracketing, the "{}" surrounding
// arguments must be complete in one section of TeX input.
                    printf("\"}\" not found\n");
                    lexType = lexError;
                    currentState = saveState;
                    return NULL;
                }
                nextSymbol();
                currentState = saveState;
                if (fn != NULL) contents = fn(contents, optarg);
                return contents;
            }
    case TeX2Arg:
            {   Keyword *key = lexKey;
                Box *b1, *b2;
                TeXState saveState = currentState;
                twoArgsHandlerFunction *fn = (twoArgsHandlerFunction *)key->ptr;
                if (fn == NULL)
                {   printf("incomplete implementation for \"\\%s\"\n", lexKey->name);
                    return NULL;
                }
                nextSymbol();
                if (lexType != lexBegin ||
                    lexKey->font != matchBrace)
                {   printf("\"{\" expected after keyword \"\\%s\"\n",
                        lexKey->name);
                    lexType = lexError;
                    return NULL;
                }
                else nextSymbol();
// The SECOND (and deeper) depth of \frac causes its contents
// to be set in a smaller font, as for subscripts.
                if (key->font == '/')
                {   if (currentState.insideFrac)
                    {   if (currentSize < FntScrScr)
                            currentState.currentFont+=FntScript;
                    }
                    else currentState.insideFrac = 1;
                }
                if (key->font == 'S' &&
                    currentSize < FntScrScr)
                    currentState.currentFont+=FntScript;
                b1 = readE(0);
                if (lexType == lexError)
                {   currentState = saveState;
                    return NULL;
                }
                else if (lexType != lexEnd || lexKey->font != matchBrace)
                {   printf("\"}\" not found\n");
                    lexType = lexError;
                    currentState = saveState;
                    return NULL;
                }
                nextSymbol();
                currentState = saveState;
                if (key->font == '/')
                {   if (currentState.insideFrac)
                    {   if (currentSize < FntScrScr)
                            currentState.currentFont+=FntScript;
                    }
                    else currentState.insideFrac = 1;
                }
// The second arg can be any sort of block, but it could
// also be a simple atom. Thus "\frac{1}2" will be accepted
                b2 = readP();
                currentState = saveState;
                return fn(b1, b2);
            }
    case TeXRule:  // I want to support \rule[offset]{height}{width}
            {   Box *b1;
                int depth=0, height=0, width=0;
                TeXState saveState = currentState;
                nextSymbol();
                if (lexType == lexSpecial &&
                    strcmp(lexKey->name, "[") == 0)
                {   nextSymbol();
                    depth = readNumber();
                    if (lexType != lexSpecial ||
                        strcmp(lexKey->name, "]") != 0)
                    {   printf("\"]\" not found\n");
                        lexType = lexError;
                        currentState = saveState;
                        return NULL;
                    }
                    currentState = saveState;
                    nextSymbol();
                }
                currentState = saveState;
                if (lexType != lexBegin ||
                    lexKey->font != matchBrace)
                {   printf("\"{\" expected after keyword \"\\%s\"\n",
                        lexKey->name);
                    lexType = lexError;
                    currentState = saveState;
                    return NULL;
                }
                else nextSymbol();
                width = readNumber();
                if (lexType == lexError)
                {   currentState = saveState;
                    return NULL;
                }
                else if (lexType != lexEnd || lexKey->font != matchBrace)
                {   printf("\"}\" not found\n");
                    lexType = lexError;
                    currentState = saveState;
                    return NULL;
                }
                nextSymbol();
                currentState = saveState;
// The second arg can be any sort of block, but it could
// also be a simple atom. Thus "\rule{1}2" will be accepted.
                if (lexType == lexBegin &&
                    lexKey->font == matchBrace)
                {   nextSymbol();
                    height = readNumber();
                    if (lexType == lexError) return NULL;
                    else if (lexType != lexEnd || lexKey->font != matchBrace)
                    {   printf("\"}\" not found\n");
                        lexType = lexError;
                        return NULL;
                    }
                    nextSymbol();
                }
                else height = readNumber();
                currentState = saveState;
                b1 = makeSymBox(SymRule);
                b1->sym.height = height+depth;
                b1->sym.depth = -depth;
                b1->sym.width = width;
                return b1;
            }
    default:
            printf("TeX keyword found but not handled (%s)\n", lexKey->name);
            nextSymbol();
            return NULL;
        }
default:
        printf("TeX syntax problem\n");
        lexType = lexError;
case lexError:     // if the token is lexError a diagnostic has already
                   // been printed.
        return NULL;
    }
    return NULL;
}

static Box *readS()
{
    Box *base, *super=NULL, *sub=NULL;
    base = readP();
    for (;;)
    {   if (lexType == lexSuper)
        {   nextSymbol();
            TeXState saveState = currentState;
            if (currentSize < FntScrScr) currentState.currentFont+=FntScript;
            super = readP();
            currentState = saveState;
            if (lexType == lexSub)
            {   nextSymbol();
                saveState = currentState;
                if (currentSize < FntScrScr) currentState.currentFont+=FntScript;
                sub = readP();
                currentState = saveState;
            }
        }
        else if (lexType == lexSub)
        {   nextSymbol();
            TeXState saveState = currentState;
            if (currentSize < FntScrScr) currentState.currentFont+=FntScript;
            sub = readP();
            currentState = saveState;
            if (lexType == lexSuper)
            {   nextSymbol();
                saveState = currentState;
                if (currentSize < FntScrScr) currentState.currentFont+=FntScript;
                super = readP();
                currentState = saveState;
            }
        }
// Now I have parsed a bit: glue the boxes together...
        if (sub == NULL)
        {   if (super != NULL)
                base = makeNestBox(BoxSuperscript, base, super);
        }
        else if (super == NULL) base = makeNestBox(BoxSubscript, base, sub);
        else base = makeNest3Box(BoxBothScripts, base, sub, super);
// Going beyond what TeX supports I will permit things like
// x^y^z and x_y_z. I group sub- and superscripts so that at each level
// I support one of each in either order. The resulting layout may be
// less then perfect but should be what you would have got with
// {x^y}^z etc so is not outrageous. 
        if (lexType != lexSuper &&
            lexType != lexSub) break;
    }
    return base;
}

static Box *readE(int stopAt)
{
// I ALWAYS stop if I see a "}" or an "\end{xxx}". I can optionally
// stop on ",", "&" or "\\" (the first of these is used in optional argument
// lists and the second two in matrixes.
    Box *result = NULL;
// This ALWAYS stops as a lexEnd (or error or eof). Depending on the
// bitmask given as an argument it may stop at "\\", "&", "," or "]" too
    while (lexType != lexEnd &&
           lexType != lexError &&
           lexType != lexEOF &&
           (!(stopAt & stopTab) ||
            lexType != lexSpecial ||
            strcmp(lexKey->name, "&") != 0) &&
           (!(stopAt & stopNL) ||
            lexType != lexSpecial ||
            strcmp(lexKey->name, "\\\\") != 0) &&
           (!(stopAt & stopKet) ||
            lexType != lexSpecial ||
            strcmp(lexKey->name, "]") != 0) &&
           (!(stopAt & stopComma) ||
            lexType != lexSpecial ||
            strcmp(lexKey->name, ",") != 0))
    {   Box *n = readS();
        if (result == NULL) result = n;
        else if (n != NULL)
            result = makeNestBox(BoxBeside, result, n);
    }
    return result;
}

static Box *readE1()
{
// Read stuff until EOF.
    Box *result = NULL;
    while (lexType != lexError &&
           lexType != lexEOF)
    {
// Here if I get an "unexpected" close bracket I will in effect insert a
// "\left ." at the start of my input to match it.
        if (lexType == lexEnd)
        {   blockHandlerFunction *fn = (blockHandlerFunction *)lexKey->ptr;
            if (result == NULL) result = makeSymBox(SymNothing);
            if (fn != NULL) result = fn('.', lexKey->charCode, result);
            nextSymbol();
            continue;
        }
        Box *n = readS();
        if (result == NULL) result = n;
        else if (n != NULL)
            result = makeNestBox(BoxBeside, result, n);
    }
    return result;
}

static void nextSymbol()
{
// Discard whitespace
    while (curChar != 0 && isspace(curChar)) curChar = (*nextChar)();
// Detect end of input
    if (curChar == 0)
    {   lexType = lexEOF;
        return;
    }
// OK, now we have the start of a new symbol.
    switch (curChar)
    {
case '%':               // discard comments
        while ((curChar = (*nextChar)()) != 0 && curChar != '\n');
        nextSymbol();
        return;
case '^':
        lexType = lexSuper;
        curChar = (*nextChar)();
        return;
case '_':
        lexType = lexSub;
        curChar = (*nextChar)();
        return;
case '{':
case '}':
case '&':
        lexerBuffer[0] = curChar;
        lexerBuffer[1] = 0;
        lexLength = 1;
        lexKey = lookupHash(lexerBuffer);
        if (curChar == '{') lexType = lexBegin;
        else if (curChar == '}') lexType = lexEnd;
        else lexType = lexSpecial;
        curChar = (*nextChar)();
        return;
case '$':
        lexerBuffer[0] = curChar;
        lexerBuffer[1] = 0;
        lexLength = 1;
        lexKey = lookupHash(lexerBuffer);
// "$" will be a BEGIN if you are not in math mode, or an END if you are!
// This is yet another curious hack to cope with the syntax of LaTeX, which
// appears somewhat curious in places.
        lexType = insideDollars ? lexEnd : lexBegin;
        curChar = (*nextChar)();
        return;
// A bunch of characters are handled in a magic way here because they
// might map onto some specific font or character coding.
case '+':   case '-':   case '*':   case '/':
case ':':   case ';':   case '@':   case ',':
case '.':   case '?':   case '!':   case '|':
case '`':   case '#':   case '~':   case '=':
case '(':   case ')':   case '<':   case '>':
case '[':   case ']':
// "NOTSIGN" ??
        lexerBuffer[0] = curChar;
        lexerBuffer[1] = 0;
        lexLength = 1;
        if (DEBUGFONT & 8) printf("lexer special char %s\n", lexerBuffer);
        lexKey = lookupHash(lexerBuffer);
        lexType = lexSpecial;
        curChar = (*nextChar)();
        return;
case '\\':
        lexLength = 0;
        curChar = (*nextChar)();
        if (curChar == 0)             //  Treat "\<eof>" as just <eof>
        {   lexType = lexEOF;
            return;
        }
        while (isalnum(curChar))
        {   if (lexLength < maxLexLength)
                lexerBuffer[lexLength++] = curChar;
            curChar = (*nextChar)();
        }
// I assemble EITHER "\word" or "\delim"
        if (lexLength == 0)
        {   lexerBuffer[lexLength++] = '\\';   // put the "\" explicitly there
            lexerBuffer[lexLength++] = curChar;
            curChar = (*nextChar)();
        }
        lexerBuffer[lexLength] = 0;
// There is an UTTERLY odd bit of lexical treatment here that
// makes "\left(" one token. What I do is to take "\left" and "\right"
// and treat the token after it as part of a single token.
// Thus I have in effect "\left (" as just one token.
// The item following one of the words \left or \right must be a TeX
// "delimiter" and they can be in one of 3 forms:
//     character            (,),[,],/,|
//     escaped character    \{, \}, \|
//     escaped word         \lfloor, \Uparrow etc etc
// I will pack things in being a bit generous in what I allow, but bad cases
// will then get spotted because they will count as unknown TeX keywords.
        if ((strcmp(lexerBuffer, "left") == 0 ||
             strcmp(lexerBuffer, "right") == 0) &&
            curChar != 0)
        {   while (curChar != 0 && isspace(curChar)) curChar = (*nextChar)();
            lexerBuffer[lexLength++] = ':';
            if (curChar == '\\')
            {   lexerBuffer[lexLength++] = curChar;  // insert the backslash
                curChar = (*nextChar)();
                if (curChar != 0 && isalnum(curChar))
                {   while (isalnum(curChar))         // \word
                    {   if (lexLength < maxLexLength)
                            lexerBuffer[lexLength++] = curChar;
                        curChar = (*nextChar)();
                    }
                }
                else if (curChar != 0)               // \delim
                {   lexerBuffer[lexLength++] = curChar;
                    curChar = (*nextChar)();
                }
            }
            else if (curChar != 0)                   // just a delim
            {   lexerBuffer[lexLength++] = curChar;
                curChar = (*nextChar)();
            }
            lexerBuffer[lexLength] = 0;
        }
        lexKey = lookupHash(lexerBuffer);
        if (lexKey == NULL)
        {   printf("Unrecognised keyword \"\\%s\"\n", lexerBuffer);
            lexType = lexError;
            return;
        }
        if (lexKey->type == TeXBeginWord) // "\begin" or "\end"
        {   int beginFlag = lexKey->font;
            while (curChar != 0 && isspace(curChar)) curChar = (*nextChar)();
            if (curChar != '{')
            {   printf("Brace expected after \\begin or \\end\n");
                lexType = lexError;
                return;
            }
            else curChar = (*nextChar)();
            while (curChar != 0 && isspace(curChar)) curChar = (*nextChar)();
            lexLength = 0;
            lexerBuffer[lexLength++] = beginFlag ? '(' : ')';
            while (isalnum(curChar))
            {   if (lexLength < maxLexLength)
                    lexerBuffer[lexLength++] = curChar;
                curChar = (*nextChar)();
            }
            while (curChar != 0 && isspace(curChar)) curChar = (*nextChar)();
            if (curChar != '}')
            {   printf("Closing brace expected after \\begin or \\end\n");
                lexType = lexError;
                return;
            }
            else curChar = (*nextChar)();
            lexerBuffer[lexLength] = 0;
            lexKey = lookupHash(lexerBuffer);
            if (lexKey == NULL)
            {   printf("Unrecognised \\begin or \\end \"\\%s\"\n",
                       &lexerBuffer[1]);
                lexType = lexError;
                return;
            }
            lexType = beginFlag ? lexBegin : lexEnd;
            return;
        }
// I now need to cope with "\left(", "\(" and the like which are "begin/end"
// style items.
        if (lexKey->type == TeXBegin) lexType = lexBegin;
        else if (lexKey->type == TeXEnd) lexType = lexEnd;
        else lexType = lexSpecial;
        return;
default:
        lexLength = 0;
// Anything that starts with a digit will be taken to be a number. I permit
// digits then possibly "." followewd by more digits and possibly an exponent
// introduced by "e" or "E".
        if (isdigit(curChar))   // handle as a number
        {   while (isdigit(curChar))
            {   if (lexLength < maxLexLength)
                    lexerBuffer[lexLength++] = curChar;
                curChar = (*nextChar)();
            }
            if (curChar == '.')
            {   if (lexLength < maxLexLength)
                    lexerBuffer[lexLength++] = curChar;
                curChar = (*nextChar)();
                while (isdigit(curChar))
                {   if (lexLength < maxLexLength)
                        lexerBuffer[lexLength++] = curChar;
                    curChar = (*nextChar)();
                }
            }
            if (curChar == 'e' || curChar == 'E')
            {   if (lexLength < maxLexLength)
                    lexerBuffer[lexLength++] = curChar;
                curChar = (*nextChar)();
                if (curChar == '+' || curChar == '-')
                {   if (lexLength < maxLexLength)
                        lexerBuffer[lexLength++] = curChar;
                    curChar = (*nextChar)();
                }
                while (isdigit(curChar))
                {   if (lexLength < maxLexLength)
                        lexerBuffer[lexLength++] = curChar;
                    curChar = (*nextChar)();
                }
            }
            lexerBuffer[lexLength] = 0;
            lexType = lexNumber;
            return;
        }
        while (isalnum(curChar))
        {   if (lexLength < maxLexLength)
                lexerBuffer[lexLength++] = curChar;
            curChar = (*nextChar)();
        }
        if (lexLength == 0)
        {   lexerBuffer[lexLength++] = curChar;
            curChar = (*nextChar)();
        }
        lexerBuffer[lexLength] = 0;
        lexType = lexWord;
        return;
    }
}

Box *parseTeX(getTeXchar *fn, int owner)
{
    nextChar = fn;
    poolStartChunk(owner);
    curChar = (*nextChar)();
    nextSymbol();
    if (DEBUGFONT & 8) printf("lexType = %d\n", lexType);
// That has got the lexer ready - now I can do the REAL parsing!
// I do my parsing here in \displaymath mode, so the font I will use
// by default will be an italic one.
    insideDollars = 0;
    currentState.currentFont = FntItalic + FntRegular;
    currentState.insideFrac = 0;
// now the paser is initialised...
    Box *r = readE1();
    if (r != NULL) r = makeTopBox(r); // hook on a handle to the chunk start.
    poolEndChunk();
    return r;
}

void updateOwner(Box *b, int p)
{
    IntVoidStar *chunk = (IntVoidStar *)(b->top.chunk);
    chunk->i = p;
}

///////////////////////////////////////////////////////////////////////////

#ifdef WIN32

#define setFont1(dc, ff) dc->setFont((FXFont *)ff)
#define drawText1(dc, x, y, ss, l) dc->drawText(x, y, ss, l)

#else


#ifdef HAVE_XFT

// Try to set up to use Xft and client side fonts. If this is not
// possible (eg because the fonts that I want can not be found) set
// fwin_use_xft to 0 so that later code does not stumble.

static void setupXft(FXApp *app)
{
    ftDraw = NULL;  // I do this first so it is established even if Xft
                    // is not going to be used.
    if (!fwin_use_xft) return;
#ifdef USE_FCINIT
    if (!FcInit())
    {   fwin_use_xft = 0;
        return;
    }
#else
    {   FcConfig *w = FcConfigCreate();
        FcConfigSetCurrent(w);
    }
#endif
    XftInit("");
    dpy = (Display *)app->getDisplay();
    screen = DefaultScreen(dpy);
// NOTE: I probably want to be able to save the existing font configuration
// so that I restore if after opening the maths fonts in case I need to change
// the size or style of the main non-maths font that I use.
// Establish my own private supply of fonts

// I will add in the four font files that I want to use here. Note that
// with Xft I will force use of the ".pfb" versions. These are close to
// BUT NOT IDENTICAL TO the original AMS Type1 Computer Modern fonts.
// It is important to use MY versions of the fonts here.
    int someAdded = 0;
    for (int i=0; i<4; i++)
    {   char *ff = (char *)
            malloc(20+strlen(programDir)+strlen(fontNames[i].name));
        char ff1[LONGEST_LEGAL_FILENAME];
        if (ff == NULL)
        {   fwin_use_xft = 0;
            return;
        }
        sprintf(ff, "%s/r38.fonts/%s.pfb", programDir, fontNames[i].name);
// For Xft I will insist that ALL the fonts that I try to add have
// readable font file and are accepted by AppFontAdd, otherwise I will
// suppose that Xft is not usable.
// The "0" arg to FcConfigAppFontAddFile says "add to default configuration"
        if (!file_readable(ff1, ff, strlen(ff)) ||
            !FcConfigAppFontAddFile(0, (const FcChar8 *)ff))
        {   fwin_use_xft = 0;
            return;
        }
        else someAdded = 1;
    }
// ensure that fonts are really available. If I do not actually add any
// I will not fuss about this!
    if (someAdded && !FcConfigBuildFonts(FcConfigGetCurrent()))
    {   fwin_use_xft = 0;
        return;
    }
// I now have some confidence that the fonts that I want will be available
// to me. Well at least if the local font files existed!

#ifdef DEBUG_LIST_AVAILABLE_FONTS
    for (int i=0; i<4; i++)
    {   XftFontSet *fs = XftListFonts(dpy, screen,
                 XFT_FAMILY,  XftTypeString, fontNames[i].name,
                 (const char *)0, 
                 XFT_STYLE, XFT_FILE, XFT_ENCODING,
                 (const char *)0);
        if (fs->nfont == 0)
        {   XftFontSetDestroy(fs);
// Here at least one of the fonts that I ought to have in the r38.fonts
// directory does not seem to be available. I will thus disable use of
// Xft and fall back to the earlier style of X use via FOX's FXFont.
            fwin_use_xft = 0;
            return;
        }
        for (int j=0; j<fs->nfont; j++)
            FcPatternPrint(fs->fonts[j]);  // To help me debug
        XftFontSetDestroy(fs);
    }
#endif // DEBUG

    ftVisual = DefaultVisual(dpy, screen);
    ftColormap = DefaultColormap(dpy, screen);
// I really want the id() of the things that actually gets drawn on...
    Drawable draw = (Drawable)((FXText *)text)->id();
    ftDraw = XftDrawCreate(dpy, draw, ftVisual, ftColormap);
    XftColorAllocValue(dpy, ftVisual, ftColormap, &ftRenderBlack, &ftBlack);
    XftColorAllocValue(dpy, ftVisual, ftColormap, &ftRenderWhite, &ftWhite);
}

#endif

static void setFont1(FXDC *dc, void *ff)
{
#ifdef HAVE_XFT
    if (fwin_use_xft)
    {   ftFont = (XftFont *)ff;
        return;
    }
#endif
    dc->setFont((FXFont *)ff);
}

static void drawText1(FXDC *dc, int x, int y, const char *ss, int l)
{
#ifdef HAVE_XFT
    if (fwin_use_xft)
    {   l = convertGlyphs(ss, l);
        XftDrawGlyphs(ftDraw, &ftBlack, ftFont,
                      x, y, glyphs, l);
        return;
    }
#endif
    dc->drawText(x, y, ss, l);
}

#endif


///////////////////////////////////////////////////////////////////////////


static void paintBracket(FXDC *dc, int type, int flags,
                         int x, int y, int height, int depth)
{
// See the LaTeX manual for a list of "delimiters", and note that I encode
// each as a single character here, with a maybe curious encoding. Also I
// draw square root signs here since they are also variable height items
// manufactured (sometimes) out of multiple glyphs in a tower.
//
// Maybe the case that concerns me most here will be \langle and \rangle since
// they need horizontal offsets for glyphs. At least to start with I will not
// support them!!
    int size = flags & FontSizeMask;
    int n = bracketCount(flags, height, depth);
// n is the size of bracket needed, measured in units of 0.5 times the
// normal cmex font height
    if (n == 1)
    {   int fnt = FntSymbol, ch = 0x00;
        switch(type)
        {
    case '.':
            return;
    case '(':
            fnt = FntRoman;
            ch = 0x28;
            break;
    case ')':
            fnt = FntRoman;
            ch = 0x29;
            break;
    case '[':
            fnt = FntRoman;
            ch = 0x5b;
            break;
    case ']':
            fnt = FntRoman;
            ch = 0x5d;
            break;
    case '{':
            ch = 0x64;
            break;
    case '}':
            ch = 0x65;
            break;
    case '|':                 // LEFT vertical bar
            ch = 0x6a;
            break;
    case '!':                 // RIGHT vertical bar
            ch = 0x6a;
            break;
    case 'Q':                 // square root marker
            ch = 0x70;        // NB this is a descender
            y -= mathFontHeight[size];
            break;
    case '/':                 // slash
            ch = 0x36;
            break;
    case '\\':                // backslash
            ch = 0x6e;
            break;
    case 'L':                 // lfloor
            ch = 0x62;
            break;
    case 'G':                 // lceil (like Gamma)
            ch = 0x64;
            break;
    case 'J':                 // rfloor
            ch = 0x63;
            break;
    case '7':                 // rceil
            ch = 0x65;
            break;
    case '<':                 // langle
            ch = 0x68;
            break;
    case '>':                 // rangle
            ch = 0x69;
            break;
    case '#':                 // \|    (double vertical bar)
            ch = 0x6b;
            break;
    case '^':                 // uparrow
            ch = 0x22;
            break;
    case 'v':                 // downarrow
            ch = 0x23;
            break;
    case 'A':                 // Uparrow
            ch = 0x2a;
            break;
    case 'V':                 // Downarrow
            ch = 0x2b;
            break;
    case 'b':                 // updownarrow
            ch = 0x6c;
            break;
    case 'B':                 // Updownarrow
            ch = 0x6d;
            break;
    default:
            printf("Attempt to paint unknown delimiter \"%c\"\n", type);
            return;
        }
        char cc[1];
        cc[0] = remap(ch);
        setFont1(dc, mathFont[fnt + size]);
        drawText1(dc, x, y, cc, 1);
        return;
    }
    void *ff = mathFont[FntExtension + size];
    int h = mathFontHeight[size], d = mathFontDepth[size];
    int height1 = height + depth;
    int h1 = h + d;
    int height2 =(9*n*(h + d) + 8)/16;
// height2 will be the actual total height of the bracket that I draw.
    if (height2 < height1) height2 = height1; // top align always
    y = y - height - (height2 - height1 + 1)/2;
// The big delimiters are present in the font as "descenders" and so the
// place I must paint them is referenced to their top. y is now the
// coordinate to paint the top glyph.
    int n1 = n;
    if (n1 > 6) n1 = 6;
    const char *topp;
    int top, tower, mid = 0x00, bottom;
    int toph = 0;
    int ntower = -1;
    switch (type)
    {
case '.':
        return;
case '(':
        topp = "\x00\x10\x12\x20\x30";
        toph = 3;
        tower = 0x42;
        if (n >= 6) ntower = n - 6;
        bottom = 0x40;
        break;
case ')':
        topp = "\x01\x11\x13\x21\x31";
        toph = 3;
        tower = 0x43;
        if (n >= 6) ntower = n - 6;
        bottom = 0x41;
        break;
case '[':
        topp = "\x02\x68\x15\x22\x32";
        toph = 3;
        tower = 0x36;
        if (n >= 6) ntower = n - 6;
        bottom = 0x34;
        break;
case ']':
        topp = "\x03\x69\x16\x23\x33";
        toph = 3;
        tower = 0x37;
        if (n >= 6) ntower = n - 6;
        bottom = 0x35;
        break;
case '{':
        topp = "\x08\x6e\x1a\x28\x38";
        toph = 3;
        tower =  0x3e;
        if (ntower >= 6) ntower = n - 6;
        mid = 0x3c;
        bottom = 0x3a;
        break;
case '}':
        topp = "\x09\x6f\x1b\x29\x39";
        toph = 3;
        tower =  0x3e;
        if (n >= 6) ntower = n - 6;
        mid = 0x3d;
        bottom = 0x3b;
        break;
case '|':           // LEFT vertical bar
        topp = "\x0c\x0c\x42\x42\x42";
// Note that vertical bars have to use a tower of glyphs right from
// the very start, while all the other cases can use a single glyph for
// heights 2,3,4 and 5.
        toph = 1;
        tower =  0x0c;
        if (n >= 2) ntower = n - 2;
        bottom = 0x0a;
        break;
case '!':           // RIGHT vertical bar
        topp = "\x0c\x0c\x43\x43\x43";
        toph = 1;
        tower =  0x0c;
        if (n >= 2) ntower = n - 2;
        bottom = 0x0a;
        break;
case 'Q':
        topp = "\x70\x71\x72\x73\x76";
        toph = 1;
        tower = 0x75;
        if (n > 5) ntower = n - 4;
        bottom = 0x74;
        break;
case 'L':           // lfloor
        topp = "\x04\x6a\x16\x24\x36";
        toph = 1;
        tower = 0x36;
        if (n > 5) ntower = n - 4;
        bottom = 0x34;
        break;
case 'G':           // lceil
        topp = "\x06\x6c\x18\x22\x32";
        toph = 3;
        tower = 0x36;
        if (n > 5) ntower = n - 4;
        bottom = 0x36;
        break;
case 'J':           // rfloor
        topp = "\x05\x6b\x17\x25\x37";
        toph = 1;
        tower = 0x37;
        if (n > 5) ntower = n - 4;
        bottom = 0x35;
        break;
case '7':           // rceil
        topp = "\x07\x6d\x19\x23\x33";
        toph = 3;
        tower = 0x37;
        if (n > 5) ntower = n - 4;
        bottom = 0x37;
        break;
case '^':           // uparrow
// ALL cases are built up as towers, not just especially big ones
        topp = "\xff\xff\xff\xff\x78";
        toph = 1;
        tower = 0x3f;
        ntower = n - 2;
        bottom = 0x3f;
        break;
case 'v':           // downarrow
        topp = "\xff\xff\xff\xff\x3f";
        toph = 1;
        tower = 0x3f;
        ntower = n - 2;
        bottom = 0x79;
        break;
case 'b':           // updownarrow
        topp = "\xff\xff\xff\xff\x78";
        toph = 1;
        tower = 0x3f;
        ntower = n - 2;
        bottom = 0x79;
        break;
case 'A':           // Uparrow
        topp = "\xff\xff\xff\xff\x7e";
        toph = 1;
        tower = 0x77;
        ntower = n - 2;
        bottom = 0x77;
        break;
case 'V':           // Downarrow
        topp = "\xff\xff\xff\xff\x77";
        toph = 1;
        tower = 0x77;
        ntower = n - 2;
        bottom = 0x7f;
        break;
case 'B':           // Updownarrow
        topp = "\xff\xff\xff\xff\x7e";
        toph = 1;
        tower = 0x77;
        ntower = n - 2;
        bottom = 0x7f;
        break;
case '#':           // \| double vertical line
        topp = "\xff\xff\xff\xff\x77";
        toph = 1;
        tower = 0x77;
        ntower = n - 2;
        bottom = 0x77;
        break;
case '<':           // langle
case '>':           // rangle
case '\\':          // backslash
case '/':           // slash
default:
        printf("Attempt to paint unknown delimiter \"%c\"\n", type);
        return;
    }
    top = topp[n1-2];
    if ((top & 0xff) == 0xff) top = topp[4];
// I general here I need to display in one of several patterns based on
// midflag and ntower. I use ntower=-1 for the case where a single
// glyph pains the entire bracket, otherwise ntower is a repeat
// count.  mid is non-zero only in the "{}" case where everything is
// messier... In the easy case I go:
//
//     top                            height is toph
//     tower    done ntower times     height is 1
//     bottom                         height is toph (except sqrt!)
//
// If mid is non-zero I use:
//
//     top                            height is 1.5
//     tower    done ntower times     height is 0.5
//     mid                            height is 3
//     tower    done ntower times     height is 0.5
//     bottom                         height is 1.5
//

    char ss[1];
    setFont1(dc, ff);
// Draw the top glyph
    ss[0] = remap(top);
    drawText1(dc, x, y, ss, 1);
    if (ntower < 0) return;   // all done in just one glyph
    if (mid == 0x00)
    {   int delta2y = toph*h1; // twice the y delta needed for next glyph
        while (ntower > 1)
        {   ss[0] = remap(tower);
            drawText1(dc, x, y+(9*delta2y)/16, ss, 1);
            delta2y += h1;
            ntower--;
        }
        ss[0] = remap(bottom);
        drawText1(dc, x, y+(9*delta2y)/16, ss, 1);
        return;
    }
// Now I have a continuation of a { or }.
    int delta4y = toph*h1;
    for (n=1; n<ntower; n++)
    {   ss[0] = remap(tower);
        drawText1(dc, x, y+(9*delta4y)/32, ss, 1);
        delta4y += h1;
    }
    ss[0] = remap(mid);
    drawText1(dc, x, y+(9*delta4y)/32, ss, 1);
    delta4y += 6*h1;
    for (n=1; n<ntower; n++)
    {   ss[0] = remap(tower);
        drawText1(dc, x, y+(9*delta4y)/32, ss, 1);
        delta4y += h1;
    }
    ss[0] = remap(bottom);
    drawText1(dc, x, y+(9*delta4y)/32, ss, 1);
    return;
}

void paintBox(FXDC *dc, Box *b, int x, int y)
{
    void *ff;
    TextBox *t;
    SymBox *s;
    BracketBox *bb;
    int h1, d1;
    switch (b->text.type)
    {
case BoxSym:
        s = &(b->sym);
        switch (s->flags & SymTypeMask)
        {
    case SymStar:
    case SymComma:
    case SymExclam:
    case SymColon:
    case SymSemiColon:
    case SymBlank:
    case SymNothing:
    case SymRule:     // this is a rule with either height or width zero
            return;
    case SymUnderscore:
            {   int h = (mathFontHeight[b->nest.flags & FontSizeMask]+12)/25;
                if (h <= 0) h = 1;  // ensure bar is at least 1 pixel tall
                dc->fillRectangle(x, y, s->width, h);
                return;
            }
    default:
            printf("SymBox type %.2x not handled in paintBox\n", s->flags);
            return;
        }
case BoxText:
// Here (and in measureBox1) I have a WORRY. The material that ends up in a
// text box can be pretty-well arbitrary strings of ascii characters, but the
// font I am using may very well not cope with things beyond letters and
// numbers. And some glyphs that I might like (such as space and underline)
// are not even present in the Computer Modern fonts that I have available.
// so if I want to be REALLY picky I will need to scan character by character
// and take special action on characters that need it. While I am doing that
// I might take the view that in the Roman font I should convert things to
// use ligatures (eg ff, fi, fl, ffi, ffl) when relevant, and do kerning
// for myself...
//
// It may well be that via tmprint the only things that get into a BoxText
// directly involve simple alphanumerics. So otherwise I get BoxTexts that I
// myself have created in the clear knowledge of font-related complexity. So
// perhaps this is less of a worry than I had at one time feared! But I should
// try to ensure that I do not put blanks etc in these boxes.
//
// If the "FntBig" flag is set I will shift the material printed by
// my nominal character-cell height...  This shift seems a little delicate to
// me in that I ought to position the "big" symbol (eg \sum, \int, \bigvee)
// with regard to the base-line of normal symbols.
        t = &(b->text);
        if (t->flags & FntBig)
        {   int h = mathFontHeight[t->flags & FontSizeMask];
            int d = mathFontDepth[t->flags & FontSizeMask];
// The calculations here had better match those performed when I measured
// the symbol.
            int bigH = 0, hd = h+d;
            if (t->text[0] == 0x5a)   // \int
                 bigH = (2222*hd + 450)/900;
            else bigH = (1400*hd + 450)/900;
            hd = h - d;
            y -= (bigH + hd)/2;;
        }
        ff = mathFont[t->flags & FontMask];
        setFont1(dc, ff);
        drawText1(dc, x, y, t->text, t->n);
        if (DEBUGFONT & 1)
        {   dc->drawRectangle(x, y, t->width, t->depth);
            dc->drawRectangle(x, y - t->height, t->width, t->height);
        }
        return;
case BoxBracket:
        bb = (BracketBox *)b;
        h1 = bb->sub->text.height;
        d1 = bb->sub->text.depth;
        if (bb->leftBracket == 'Q')
        {   int f = bb->flags & FontSizeMask;
            int h = mathFontHeight[f];
            int d = mathFontDepth[f];
            h1 += (h + d + 12)/25; // make contents seem taller
                                   // to leave gap before overbar
        }
        if (DEBUGFONT & 1)
        {   dc->drawRectangle(x, y, bb->width, bb->depth);
            dc->drawRectangle(x, y - bb->height, bb->width, bb->height);
        }
        paintBox(dc, bb->sub, x + bb->dx, y);
        paintBracket(dc, bb->leftBracket, bb->flags,
                     x, y, h1, d1);
        paintBracket(dc, bb->rightBracket, bb->flags,
                     x + bb->dx + bb->sub->text.width, y, h1, d1);
        if (bb->leftBracket == 'Q')    // need rule above the contents
        {   int h = (mathFontHeight[bb->flags & FontSizeMask] +
                     mathFontDepth[bb->flags & FontSizeMask] + 12) /25;
// I want the rule here to be the same width as the stem that the "cmex" font
// gives the top-part of a huge sqrt sign. Measuring that seems to reveal that
// the rule thickness used is 40 units when the height of the whole font is
// 1000 - ie it is 1/25th of the whole height. So that is what I will use
// here.
            if (h <= 0) h = 1;  // ensure bar is at least 1 pixel tall
            dc->fillRectangle(x+bb->dx, y-bb->height-h, bb->sub->text.width, h);
        }
        if (bb->sub1 != NULL)
            paintBox(dc, bb->sub1, x+bb->dx1, y+bb->dy1);
        return;
case BoxMatrix:
        if (DEBUGFONT & 1)
        {   dc->drawRectangle(x,
                  y-b->matrix.height,
                  b->matrix.width,
                  b->matrix.depth + b->matrix.height);
        }
        paintBox(dc, b->matrix.sub, x, y + b->matrix.dy);
        return;
case BoxNest:
        if (DEBUGFONT & 1)
        {   dc->drawRectangle(x,
                  y-b->nest.height,
                  b->nest.width,
                  b->nest.depth + b->nest.height);
        }
        paintBox(dc, b->nest.sub1, x + b->nest.dx1, y + b->nest.dy1);
        if (b->nest.sub2 != NULL) // in case of PadSpace
            paintBox(dc, b->nest.sub2, x + b->nest.dx2, y + b->nest.dy2);
// I may need to tune the thickness of the rule that I use here
        if ((b->nest.flags & NestMask) == BoxFraction)
        {   int h = (mathFontHeight[b->nest.flags & FontSizeMask] +
                     mathFontDepth[b->nest.flags & FontSizeMask] + 12)/25;
            int dy = (mathFontHeight[b->nest.flags & FontSizeMask] -
                      mathFontDepth[b->nest.flags & FontSizeMask])/2;
            if (h <= 0) h = 1;  // ensure bar is at least 1 pixel tall
            dc->fillRectangle(x, y-h/2-dy, b->nest.width, h);
        }
        return;
case BoxNest3:
        paintBox(dc, b->nest3.sub1, x + b->nest3.dx1, y + b->nest3.dy1);
        paintBox(dc, b->nest3.sub2, x + b->nest3.dx2, y + b->nest3.dy2);
        paintBox(dc, b->nest3.sub3, x + b->nest3.dx3, y + b->nest3.dy3);
        return;
case BoxFrame:
        paintBox(dc, b->frame.sub, x, y);
        dc->drawRectangle(x,
              y-b->frame.height,
              b->frame.width,
              b->frame.depth + b->frame.height);
        return;
case BoxTop:
        paintBox(dc, b->top.sub, x, y);
        return;
default:
        printf("Paint unknown box type %d: failing\n", b->text.type);
        fflush(stdout);
        return;
    }
}



///////////////////////////////////////////////////////////////////////////


int setupShowMath(FXApp *app, int mainSize)
{
    setupMemoryPool();
    rehashKeywordTable();            // names in the table of TeX keywords
#ifdef HAVE_XFT
// Calling setupXft not only initialises Xft but it also tries to load the
// custom fonts that I need. If either of these steps fails I set
// fwin_use_xft to zero so that I do not try to use it at all further.
// The result is a fall-back to simple X11 protocols.
    setupXft(app);
#endif
// loadPrivateFonts does nothing if Xft was available, but otherwise tries
// to add cmr10 etc fonts for me. If it fails it does not complain - after
// all those fonts may be available already!
    loadPrivateFonts(app);
    return changeMathFontSize(app, mainSize);
}

void closeShowMath(FXApp *app)
{
    unloadFonts(app);
}

///////////////////////////////////////////////////////////////////////////


#endif // HAVE_LIBFOX

// End of FXShowMath.cpp



REDUCE Historical
REDUCE Sourceforge Project | Historical SVN Repository | GitHub Mirror | SourceHut Mirror | NotABug Mirror | Chisel Mirror | Chisel RSS ]