axiom-developer
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Axiom-developer] Re: patch to tex.spad.pamphlet


From: root
Subject: Re: [Axiom-developer] Re: patch to tex.spad.pamphlet
Date: Sun, 28 Sep 2003 22:08:59 -0400

Re: cloning. you need to look at the algebra code also. The tex is 
generated as a result of the algebra code output calls.

The file src/interp/setq.lisp.pamphlet contains the top level command list.
Search for the logic using the $systemCommands variable and you'll see how
these get processed. See src/interp/spad.lisp.pamphlet and follow the 
$texFormat variable and you'll see how TeX gets generated. 
In src/interp/setvars.boot.pamphlet you'll see the )set output tex command.
(beware that setvars.boot is a bootstrap file so you have to regen and reinsert
the generated .clisp file)

In the src/algebra/tex.spad.pamphlet file you'll find the domain that implements
TeX at the algebra level (TexFormat aka TEX). You could copy this domain and
make a TeXmacs domain which would implement the same interface. That way the
Tex and TeXmacs domains can be freely interchanged.

The source for the linebreak code is appended. This tool knows the form of
Axiom's TeX output code. To try it do:

(1) compile it
(2) start Axiom
(3) )set output tex on
(4) clip the tex output
(5) change the $$ ... $$ to \[ .. \]
(6) run this program
(7) tex the output

Tim

=========================================================================
/* Released under the Modified BSD license attached to Axiom sources.
 * TeX Display Math Mode Line Breaking Program
 *
 * Author: Robert S. Sutor
 *
 * Date:   1991
 *
 * Change History:
 *
 * 01/19/92   RSS   Change to use \[ \] instead of $$ $$
 *
 * 09/01/92   RSS   Format and fix =-.
 *
 * Operation:
 *
 * This program reads standard input and writes to standard output. Display math
 * mode starts with \[ at the beginning of a line and ends with \]. All lines
 * not in display math mode are simply printed on standard output.  The
 * expressions in display math mode are broken so that they fit on a page
 * better (line breaking).
 *
 * The array stuff is being converted to use the array node type.
 *
 * Restrictions:
 *
 * 1.  Assume \[ and \] start in column 1 and are the only things on the lines.
 *
 * 2.  Comments in display math mode are not preserved.
 *
 * 3. This is meant to deal with output from the AXIOM computer algebra system.
 * Unpredictable results may occur if used with hand-generated TeX code or
 * TeX code generated by other programs.
 */

/*
 * Include files and #defines.
 */
#include "useproto.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MATHBUFLEN     128*8192
#define MAXMATHTOKEN   80
#define MAXCHARSINLINE 60
#define FATDELIMMULT   2

#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif

#define TRUE 1
#define FALSE 0

#define STRCHREQ(str,char) (str[0] == char)

/*
 * Type declarations.
 */

enum nodeTypes {
    N_NODE,
    N_TEXT,
    N_ARRAY
};

typedef struct listNodeStruct {
    struct listNodeStruct *nextListNode;
    struct listNodeStruct *prevListNode;
    enum nodeTypes nodeType;
    long width;
    long realWidth;
    union {
        char *text;
        struct listNodeStruct *node;
        struct arrayNodeStruct *array;
    }   data;
}   listNode;

typedef struct arrayNodeStruct {
    int cols;
    listNode *argsNode;
    listNode *entries;          /* linked list of nodes, each pointing to a
                                 * row */
}   arrayNode;


/*
 * Global Variables.
 */

char line[1024];
char blanks[] = "                                                   ";
char lastPrinted = '\0';
int indent = 0;
char mathBuffer[MATHBUFLEN], mathToken[MAXMATHTOKEN];
int lineLen, mathBufferLen, mathBufferPtr, mathTokenLen;
listNode *mathList;
int charsOut, fatDelimiter;
int maxLineWidth = 4500;        /* 4.5  inches * 1000    */
int maxLineSlop = 0;            /* 0.0  inches * 1000    */
int charTable[256];
int avgCharWidth;
int spaceWidths[5], extraOverWidth;
int arrayDepth = 0, arrayMaxDepth = 3;
int charMultNum, charMultDenom;
int sinWidth, cosWidth, tanWidth, erfWidth;
long outLineNum = 0L;

/*
 * Function Prototypes.
 */
#ifndef _NO_PROTO
void        arrayTooDeep();
int         breakFracProd(listNode *, long, char *, char *, int);
int         breakFunction(listNode *, long);
int         breakList(listNode *, long);
int         breakMathList(listNode *, long);
int         breakNumber(listNode *, long);
int         breakPMEB(listNode *, long);
int         breakParen(listNode *, long);
int         bufferMathLines();
void        buildMathList();
int         charWidth(char);
void        computeNodeWidth(listNode *);
long        computeWidth(listNode *);
void        displaySplitMsg(char *, int);
void        error(char *, char *);
void        freeMathList(listNode *);
void        getOptions(int, char **);
void        initCharTable();
listNode   *insertStringAfter(char *, listNode *);
listNode   *insertStringAtBack(char *, listNode *);
listNode   *insertStringAtFront(char *, listNode *);
int         newLineIfNecessary(int);
listNode   *newListNode(enum nodeTypes);
int         nextMathToken();
int         printChar(char);
int         printMathList(listNode *, int);
int         printString(char *);
void        resetCharMults();
listNode   *string2NodeList(char *, listNode *);
void        ttCharMults();
#else
void        arrayTooDeep();
int         breakFracProd();
int         breakFunction();
int         breakList();
int         breakMathList();
int         breakNumber();
int         breakPMEB();
int         breakParen();
int         bufferMathLines();
void        buildMathList();
int         charWidth();
void        computeNodeWidth();
long        computeWidth();
void        displaySplitMsg();
void        error();
void        freeMathList();
void        getOptions();
void        initCharTable();
listNode   *insertStringAfter();
listNode   *insertStringAtBack();
listNode   *insertStringAtFront();
int         newLineIfNecessary();
listNode   *newListNode();
int         nextMathToken();
int         printChar();
int         printMathList();
int         printString();
void        resetCharMults();
listNode   *string2NodeList();
void        ttCharMults();
#endif


/*
 * Function Definitions.
 */

int
#ifndef _NO_PROTO
main(int argc, char *argv[])
#else
main(argc,argv)
int argc; 
char *argv[];
#endif
{
    int mathLinesRead;

    getOptions(argc, argv);
    initCharTable();

    /*
     * Read stdin line by line. When we come to a line that starts with \[,
     * go into math mode.
     */

    while (gets(line) != NULL) {
        lineLen = strlen(line);
        if ((lineLen > 1) && ('\\' == line[0]) && ('[' == line[1])) {
            puts("\\[");
            outLineNum++;

            mathLinesRead = bufferMathLines();
            if (mathLinesRead <= 0) {
                puts("\\quad");
                outLineNum++;
            }
            else {
                fatDelimiter = 1;
                arrayDepth = 0;
                mathList = newListNode(N_NODE);
                buildMathList(mathList);
                resetCharMults();
                computeWidth(mathList);
                if (mathList->width > maxLineWidth)
                    fprintf(stderr, "Width = %ld units, Output line = %ld.\n", 
mathList->width, outLineNum);
                breakMathList(mathList, maxLineWidth);
                charsOut = 0;
                if (FALSE == printMathList(mathList->data.node, TRUE)) {
                    putc('\n', stdout);
                    outLineNum++;
                }
                freeMathList(mathList);
            }
            puts("\\]");
        }
        else
            puts(line);
        outLineNum++;
    }
    return 0;
}

/*
 * breakFracProd:
 *
 * Arguments:
 *
 * n : the starting node at which we are to try to break
 *
 * lineWidth : the maximum width of a line
 *
 * match :  either "\\over" or "\\ "
 *
 * label :  either "quotient" or "product"
 *
 * paren :  add parentheses (TRUE or FALSE)
 *
 *
 * Returns: TRUE or FALSE, depending on whether the expression was broken
 *
 *
 * Function: Tries to break up a quotient t1 \over t2 or a product t1 \ t2 by
 * splitting and parenthesizing the numerator and/or the denominator.
 */

int
#ifndef _NO_PROTO
breakFracProd(listNode * n, long lineWidth, char *match, char *label, int paren)
#else
breakFracProd(n,lineWidth,match,label,paren)
listNode * n; 
long lineWidth; 
char *match; 
char *label; 
int paren;
#endif
{

    listNode *rootNode, *lastNode, *t1, *t2;
    int ok;
    long workWidth1, workWidth2;

    if (n->nodeType != N_NODE)
        return FALSE;

    rootNode = n;

    ok = FALSE;
    t1 = n = rootNode->data.node;
    n = n->nextListNode;
    if (n) {
        if ((n->nodeType == N_TEXT) &&
            (0 == strcmp(n->data.text, match))) {
            t2 = n->nextListNode;
            if (t2 && (NULL == t2->nextListNode))
                ok = TRUE;
        }
    }

    displaySplitMsg(label, ok);

    if (ok) {

        /* for products, determine rough widths for the two factors */

        if (0 == strcmp(label, "product")) {
            computeNodeWidth(t1);
            computeNodeWidth(t2);
            workWidth1 = lineWidth - charWidth(' ');

            if (workWidth1 / 2 > t1->realWidth) {
                workWidth2 = workWidth1 - t1->realWidth;
                workWidth1 = t1->realWidth;
            }
            else if (workWidth1 / 2 > t2->realWidth) {
                workWidth1 = workWidth1 - t2->realWidth;
                workWidth2 = t2->realWidth;
            }
            else
                workWidth1 = workWidth2 = workWidth1 / 2;

            if (paren) {
                if (t1->realWidth > workWidth1)
                    workWidth1 = workWidth1 - 4 * FATDELIMMULT * charWidth('(');
                if (t2->realWidth > workWidth2)
                    workWidth2 = workWidth2 - 4 * FATDELIMMULT * charWidth('(');
            }
        }
        else                    /* "quotient" */
            workWidth1 = workWidth2 =
                lineWidth - paren * 4 * FATDELIMMULT * charWidth('(');

        if ((t1->nodeType == N_NODE) && (t1->realWidth > workWidth1)) {
            t1->width = t1->realWidth;

            if (breakMathList(t1, workWidth1) && paren) {
                /* insert the \left( */
                lastNode = insertStringAtFront("\\left(", t1);

                while (lastNode->nextListNode)
                    lastNode = lastNode->nextListNode;

                /* insert the \right) */
                insertStringAtBack("\\right)", lastNode);
            }
        }

        if ((t2->nodeType == N_NODE) && (t2->realWidth > workWidth2)) {
            t2->width = t2->realWidth;

            if (breakMathList(t2, workWidth2) && paren) {
                /* insert the \left( */
                lastNode = insertStringAtFront("\\left(", t2);

                while (lastNode->nextListNode)
                    lastNode = lastNode->nextListNode;

                /* insert the \right) */
                insertStringAtBack("\\right)", lastNode);
            }
        }

        return TRUE;
    }
    return FALSE;
}


int
#ifndef _NO_PROTO
breakFunction(listNode * n, long lineWidth)
#else
breakFunction(n,lineWidth)
listNode * n; 
long lineWidth;
#endif
{
    listNode *rootNode, *tmpNode, *lastNode, *t1, *t2, *t3;
    int ok = FALSE;
    long workWidth, maxWidth = 0;

    if (n->nodeType != N_NODE)
        return FALSE;

    n = n->data.node;

    if (n->nodeType == N_NODE)
        return FALSE;

    if ((0 == strcmp(n->data.text, "\\sin")) ||
        (0 == strcmp(n->data.text, "\\cos")) ||
        (0 == strcmp(n->data.text, "\\tan")) ||
        (0 == strcmp(n->data.text, "\\log")) ||
        (0 == strcmp(n->data.text, "\\arctan")) ||
        (0 == strcmp(n->data.text, "\\erf"))) {
        computeNodeWidth(n);
        ok = TRUE;
    }

    displaySplitMsg("function", ok);

    if (ok) {
        t2 = newListNode(N_NODE);
        t2->data.node = n->nextListNode;
        t2->prevListNode = n;
        n->nextListNode = t2;
        ok = breakMathList(t2, lineWidth - n->realWidth);
    }

    return ok;
}

/*
 * breakList:
 *
 * Arguments:
 *
 * n : the starting node at which we are to try to break
 *
 * lineWidth : the maximum width of a line
 *
 *
 * Returns: TRUE or FALSE, depending on whether the expression was broken
 *
 *
 * Function: Tries to split an expression that is bracketed by \left[ and
 * \right] (or \left\{ and \right\} and contains at least one comma.
 */

int
#ifndef _NO_PROTO
breakList(listNode * n, long lineWidth)
#else
breakList(n,lineWidth)
listNode * n; 
long lineWidth;
#endif
{
    listNode *rootNode, *tmpNode, *lastNode, *t1, *t2, *t3;
    int ok, comma;
    long workWidth, maxWidth = 0;

    if (n->nodeType != N_NODE)
        return FALSE;

    rootNode = n;

    t1 = n = rootNode->data.node;
    comma = ok = FALSE;

    if ((t1->nodeType == N_TEXT) &&
        (0 == strcmp(t1->data.text, "\\left")) &&
        (t1->nextListNode) &&
        (t1->nextListNode->nodeType == N_TEXT) &&
        ((0 == strcmp(t1->nextListNode->data.text, "[")) ||
         (0 == strcmp(t1->nextListNode->data.text, "\\{")))) {

        t1 = t1->nextListNode->nextListNode;

        /*
         * Check for a special case: sometimes the whole body of the list is
         * a node. Flatten this, if possible.
         */

        if ((t1->nodeType == N_NODE) &&
            (t1->nextListNode->nodeType == N_TEXT) &&
            (0 == strcmp(t1->nextListNode->data.text, "\\right"))) {
            tmpNode = t1->prevListNode;
            t2 = t1->nextListNode;
            t3 = t1->data.node;
            tmpNode->nextListNode = t3;
            t3->prevListNode = tmpNode;
            while (t3->nextListNode)
                t3 = t3->nextListNode;
            t3->nextListNode = t2;
            t2->prevListNode = t3;
            free(t1);
            t1 = tmpNode->nextListNode;
        }

        while (t1->nextListNode && !ok) {
            if ((t1->nodeType == N_TEXT) &&
                (0 == strcmp(t1->data.text, ",")))
                comma = TRUE;
            else if ((t1->nodeType == N_TEXT) &&
                     (0 == strcmp(t1->data.text, "\\right")) &&
                     (t1->nextListNode->nodeType == N_TEXT) &&
                     ((0 == strcmp(t1->nextListNode->data.text, "]")) ||
                      (0 == strcmp(t1->nextListNode->data.text, "\\}"))) &&
                     (NULL == t1->nextListNode->nextListNode)) {
                ok = comma;
                tmpNode = t1->nextListNode;
            }
            t1 = t1->nextListNode;
        }
    }

    displaySplitMsg("list", ok);

    if (ok) {
        if (arrayDepth >= arrayMaxDepth) {
            arrayTooDeep();
            return FALSE;
        }

        /*
         * Create array environment
         */

        lastNode = insertStringAtFront("address@hidden", rootNode);
        arrayDepth++;
        insertStringAtBack("\\end{array}", tmpNode);

        /*
         * Now break at best place short of width.        Start after the
         * environment begins and after the \left(
         */

        n = lastNode->nextListNode->nextListNode->nextListNode;

        /*
         * try to split the first expression if too big
         */

        tmpNode = n->nextListNode;
        if (breakMathList(n, lineWidth)) {
            workWidth = n->width;
            n = tmpNode;
        }
        else
            workWidth = n->width;
        maxWidth = workWidth;

        while (n->nextListNode) {
            if ((n->nodeType == N_TEXT) &&
                ((0 == strcmp(n->data.text, ",")) ||
                 (0 == strcmp(n->data.text, "\\:"))) &&
                (workWidth + n->nextListNode->width > lineWidth)) {
                maxWidth = max(maxWidth, workWidth);
                n = insertStringAfter("\\right. \\\\ \\\\ \\displaystyle 
\\left.", n);

                /*
                 * try to split the next expression if too big
                 */

                tmpNode = n->nextListNode;
                if (breakMathList(n, lineWidth)) {
                    workWidth = n->width;
                    n = tmpNode;
                }
                else
                    workWidth = n->width;
            }
            else {
                workWidth += n->nextListNode->width;
                n = n->nextListNode;
            }
        }

        rootNode->width = rootNode->realWidth =
            rootNode->data.node->width = rootNode->data.node->realWidth =
            maxWidth;
        arrayDepth--;

        return TRUE;
    }

    return FALSE;
}

/*
 * breakNumber:
 *
 * Arguments:
 *
 * rootNode : the starting node at which we are to try to break
 *
 * lineWidth : the maximum width of a line
 *
 *
 * Returns: TRUE or FALSE, depending on whether the expression was broken
 *
 *
 * Function: Tries to break an expression that contains only digits and possibly
 * a decimal point.
 */

int
#ifndef _NO_PROTO
breakNumber(listNode * rootNode, long lineWidth)
#else
breakNumber(rootNode,lineWidth)
listNode * rootNode; 
long lineWidth;
#endif
{
    int ok = TRUE;
    listNode *n, *arrNode, *rowNode, *colNode;
    long workWidth, maxWidth = 0;

    if (rootNode->nodeType != N_NODE)
        return FALSE;

    n = rootNode->data.node;
    while (n && ok) {
        if ((n->nodeType == N_TEXT) &&
            (n->data.text[1] == '\0') &&
            (isdigit(n->data.text[0]) || ('.' == n->data.text[0]))) {
            n = n->nextListNode;
        }
        else
            ok = FALSE;
    }

    displaySplitMsg("number", ok);

    if (ok) {
        if (arrayDepth >= arrayMaxDepth) {
            arrayTooDeep();
            return FALSE;
        }

        arrayDepth++;
        arrNode = newListNode(N_ARRAY);
        arrNode->data.array->entries = rowNode = newListNode(N_NODE);
        arrNode->data.array->cols = 1;
        arrNode->data.array->argsNode = newListNode(N_NODE);
        string2NodeList("address@hidden", arrNode->data.array->argsNode);

        n = rootNode->data.node;
        computeWidth(n);
        maxWidth = workWidth = n->width;
        rowNode->data.node = colNode = newListNode(N_NODE);
        colNode->data.node = n;
        n = n->nextListNode;

        while (n) {
            computeWidth(n);

            if (workWidth + n->width > lineWidth) {
                maxWidth = max(maxWidth, workWidth);

                /*
                 * time to start a new row
                 */

                n->prevListNode->nextListNode = NULL;
                n->prevListNode = NULL;
                workWidth = n->width;
                rowNode->nextListNode = newListNode(N_NODE);
                rowNode = rowNode->nextListNode;
                rowNode->data.node = colNode = newListNode(N_NODE);
                colNode->data.node = n;
            }
            else
                workWidth += (n->nextListNode) ? n->nextListNode->width :0 ;

            n = n->nextListNode;
        }

        rootNode->data.node = arrNode;
        rootNode->width = rootNode->realWidth =
            arrNode->width = arrNode->realWidth = maxWidth;
        arrayDepth--;

        return TRUE;
    }

    return FALSE;
}

void
#ifndef _NO_PROTO
resetWidths(listNode * n)
#else
resetWidths(n)
listNode * n;
#endif
{
    if (n) {
        n->width = -1;
        n->realWidth = 0;
        if (n->nodeType == N_NODE)
            resetWidths(n->data.node);
        resetWidths(n->nextListNode);
    }
}

/*
 * breakParen:
 *
 * Arguments:
 *
 * n : the starting node at which we are to try to break
 *
 * lineWidth : the maximum width of a line
 *
 *
 * Returns: TRUE or FALSE, depending on whether the expression was broken
 *
 *
 * Function: Tries to split an expression that is bracketed by left( and \right)
 * (e.g., a factor).
 */

int
#ifndef _NO_PROTO
breakParen(listNode * n, long lineWidth)
#else
breakParen(n,lineWidth)
listNode * n;
long lineWidth;
#endif
{
    listNode *tmpNode, *workNode;
    int ok = FALSE;

    if (n->nodeType != N_NODE)
        goto say_msg;

    tmpNode = n->data.node;

    /*
     * check for \left
     */

    if ((tmpNode == NULL) ||
        (tmpNode->nodeType == N_NODE) ||
        (0 != strcmp(tmpNode->data.text, "\\left")))
        goto say_msg;

    /*
     * check for '('
     */

    tmpNode = tmpNode->nextListNode;

    if ((tmpNode == NULL) ||
        (tmpNode->nodeType == N_NODE) ||
        ('(' != tmpNode->data.text[0]))
        goto say_msg;

    /*
     * now move to the end
     */

    tmpNode = tmpNode->nextListNode;

    if (tmpNode != NULL) {
        while (tmpNode->nextListNode)
            tmpNode = tmpNode->nextListNode;
        tmpNode = tmpNode->prevListNode;
    }

    /*
     * check for \right
     */

    if ((tmpNode == NULL) ||
        (tmpNode->nodeType == N_NODE) ||
        (0 != strcmp(tmpNode->data.text, "\\right")))
        goto say_msg;

    /*
     * check for ')'
     */

    tmpNode = tmpNode->nextListNode;

    if ((tmpNode == NULL) ||
        (tmpNode->nodeType == N_NODE) ||
        (')' != tmpNode->data.text[0]))
        goto say_msg;

    ok = TRUE;

say_msg:
    displaySplitMsg("parenthesized expression", ok);

    if (ok) {

        /*
         * nest the whole inside if necessary, i.e., there is more than one
         * term between the ( and the \right
         */

        if (tmpNode->prevListNode->prevListNode !=
            n->data.node->nextListNode->nextListNode) {
            workNode = newListNode(N_NODE);
            workNode->data.node = n->data.node->nextListNode->nextListNode;
            n->data.node->nextListNode->nextListNode = workNode;
            tmpNode->prevListNode->prevListNode->nextListNode = NULL;
            tmpNode->prevListNode->prevListNode = workNode;
            workNode->prevListNode = n->data.node->nextListNode;
            workNode->nextListNode = tmpNode->prevListNode;
            resetWidths(workNode);
            computeWidth(workNode);
        }

        return breakMathList(n->data.node->nextListNode->nextListNode,
                             lineWidth - 4 * FATDELIMMULT * charWidth('('));
    }

    return FALSE;
}

/*
 * breakPMEB:
 *
 * Arguments:
 *
 * n : the starting node at which we are to try to break
 *
 * lineWidth : the maximum width of a line
 *
 *
 * Returns: TRUE or FALSE, depending on whether the expression was broken
 *
 *
 * Function: Tries to split an expression that contains only +, -, = or \  as
 * operators.  The split occurs after the operator.
 */

int
#ifndef _NO_PROTO
breakPMEB(listNode * n, long lineWidth)
#else
breakPMEB(n,lineWidth)
listNode * n; 
long lineWidth;
#endif
{
    char *s;
    listNode *rootNode, *tmpNode, *lastNode;
    int ok, op;
    long workWidth, maxWidth = 0;

    if (n->nodeType != N_NODE)
        return FALSE;

    if (n->width <= lineWidth + maxLineSlop)    /* allow a little slop here */
        return FALSE;

    rootNode = n;
    tmpNode = n = n->data.node;
    ok = TRUE;
    op = FALSE;

    while (n && ok) {
        if (n->nodeType == N_TEXT) {
            s = n->data.text;
            if (STRCHREQ(s, '+') || STRCHREQ(s, '-') || STRCHREQ(s, '=') ||
                (0 == strcmp(s, "\\ ")))
                op = TRUE;
            else if ((0 == strcmp(s, "\\left")) ||
                     (0 == strcmp(s, "\\right")) ||
                     (0 == strcmp(s, "\\over")) ||
                     STRCHREQ(s, ',')) {
                ok = FALSE;
                break;
            }
        }
        tmpNode = n;
        n = n->nextListNode;
    }
    ok = ok & op;

    displaySplitMsg("(+,-,=, )-expression", ok);


    if (ok) {
        if (arrayDepth >= arrayMaxDepth) {
            arrayTooDeep();
            return FALSE;
        }

        /*
         * Create array environment
         */

        lastNode = insertStringAtFront("address@hidden", rootNode);
        arrayDepth++;
        insertStringAtBack("\\end{array}", tmpNode);

        /*
         * Now break at best place short of width. Start after the
         * environment begins.
         */

        n = lastNode->nextListNode;

        /*
         * try to split the first expression if too big
         */

        tmpNode = n->nextListNode;
        if (breakMathList(n, lineWidth)) {
            workWidth = n->width;
            n = tmpNode;
        }
        else
            workWidth = n->width;
        maxWidth = workWidth;

        while (n->nextListNode) {
    loop_top:
            if ((n->nodeType == N_TEXT) &&
              (STRCHREQ(n->data.text, '+') || STRCHREQ(n->data.text, '-') ||
               STRCHREQ(n->data.text, '=') ||
               (0 == strcmp(n->data.text, "\\ "))) &&
                (workWidth > 24) &&     /* avoid - or + on their own line */
                (workWidth + n->nextListNode->width > lineWidth)) {

                if ((workWidth < lineWidth / 3) &&
                  (breakMathList(n->nextListNode, lineWidth - workWidth))) {
                    n->nextListNode->width = -1;
                    n->nextListNode->realWidth = 0;
                    computeNodeWidth(n->nextListNode);
                    goto loop_top;
                }

                /*
                 * \  means multiplication. Use a \cdot to make this clearer
                 */

                if (0 == strcmp(n->data.text, "\\ "))
                    n = insertStringAfter("\\cdot \\\\ \\\\ \\displaystyle", n);
                else
                    n = insertStringAfter("\\\\ \\\\ \\displaystyle", n);
                maxWidth = max(maxWidth, workWidth);

                /*
                 * try to split the next expression if too big
                 */

                tmpNode = n->nextListNode;
                if (breakMathList(n, lineWidth)) {
                    workWidth = n->width;
                    n = tmpNode;
                }
                else
                    workWidth = n->width;
            }
            else {
                workWidth += n->nextListNode->width;
                n = n->nextListNode;
            }
        }

        rootNode->width = rootNode->realWidth =
            rootNode->data.node->width = rootNode->data.node->realWidth =
            maxWidth;
        arrayDepth--;

        return TRUE;
    }

    return FALSE;
}

/*
 * breakMathList:
 *
 * Arguments:
 *
 * n : the starting node at which we are to try to break
 *
 * lineWidth : the maximum width of a line
 *
 *
 * Returns: TRUE or FALSE, depending on whether the expression was broken
 *
 *
 * Function: Tries various methods to break the expression up into multiple
 * lines if the expression is too big.
 */

int
#ifndef _NO_PROTO
breakMathList(listNode * n, long lineWidth)
#else
breakMathList(n,lineWidth)
listNode * n; 
long lineWidth;
#endif
{
    int split = FALSE;

    /*
     * Don't do anything if already short enough.
     */

    if (n->width <= lineWidth)
        return FALSE;

    /*
     * Can't split strings, so just return.
     */

    if (n->nodeType == N_TEXT)
        return FALSE;

    blanks[indent] = ' ';
    indent += 2;
    blanks[indent] = '\0';

    /*
     * We know we have a node, so see what we can do.
     */

    /*
     * Case 1: a product: t1 \  t2
     */

    if (split = breakFracProd(n, lineWidth, "\\ ", "product", FALSE))
        goto done;

    /*
     * Case 2: a sequence of tokens separated by +, - or =
     */

    if (split = breakPMEB(n, lineWidth))
        goto done;

    /*
     * Case 3: a fraction of terms: t1 \over t2
     */

    if (split = breakFracProd(n, lineWidth, "\\over", "quotient", TRUE))
        goto done;

    /*
     * Case 4: a list of terms bracketed by \left[ and \right] with a comma
     */

    if (split = breakList(n, lineWidth))
        goto done;

    /*
     * Case 5: a list of digits, possibly with one "."
     */

    if (split = breakNumber(n, lineWidth))
        goto done;

    /*
     * Case 6: a parenthesized expression (e.g., a factor)
     */

    if (split = breakParen(n, lineWidth))
        goto done;

    /*
     * Case 7: a function application
     */

    if (split = breakFunction(n, lineWidth))
        goto done;

done:
    blanks[indent] = ' ';
    indent -= 2;
    blanks[indent] = '\0';

    return split;
}

void
#ifndef _NO_PROTO
buildMathList(listNode * oldNode)
#else
buildMathList(oldNode)
listNode * oldNode;
#endif
{
    listNode *curNode, *tmpNode;

    curNode = NULL;
    while (nextMathToken()) {
        if (mathToken[0] == '}')
            break;
        if (mathToken[0] == '{') {
            tmpNode = newListNode(N_NODE);
            buildMathList(tmpNode);
        }
        else {
            tmpNode = newListNode(N_TEXT);
            tmpNode->data.text = strdup(mathToken);
        }
        if (curNode == NULL) {
            oldNode->data.node = tmpNode;
        }
        else {
            tmpNode->prevListNode = curNode;
            curNode->nextListNode = tmpNode;
        }
        curNode = tmpNode;
    }

    /*
     * leave with one level of nesting, e.g., {{{x}}} --> {x}
     */

    tmpNode = oldNode->data.node;
    while ( tmpNode && (tmpNode->nodeType == N_NODE) &&
           (tmpNode->nextListNode == NULL) ) {
        oldNode->data.node = tmpNode->data.node;
        free(tmpNode);
        tmpNode = oldNode->data.node;
    }
}

int
bufferMathLines()
{

    /*
     * Returns number of lines read. Returns negative this number if
     * end-of-file was reached before final \].
     */

    char curChar, lastChar, *eq;
    int i, linesRead = 0;

    mathBufferPtr = 0;
    mathBufferLen = 0;
    mathBuffer[0] = '\0';

    while (gets(line) != NULL) {
        lineLen = strlen(line);

        if (('\\' == line[0]) && (']' == line[1]))
            return linesRead;
        else {
            linesRead++;

            /*
             * Go through the line and change any unescaped % to a \0. Change
             * any tab to a blank.
             */

            lastChar = ' ';
            i = 0;
            while ((curChar = line[i]) != '\0') {
                if ((curChar == '%') && (lastChar != '\\')) {
                    line[i] = '\0';
                    break;
                }
                else if (curChar == '\t')
                    curChar = line[i] = ' ';
                i++;
                lastChar = curChar;
            }
            lineLen = i;

            if (lineLen == 0)   /* skip empty lines */
                ;
            else {

                /*
                 * Stick the line in the math buffer.
                 */

                if (mathBufferLen + 1 + lineLen >= MATHBUFLEN)
                    error("math buffer exceeded.", "");

                if ((mathBufferLen > 0) && (mathBuffer[mathBufferLen - 1] != ' 
')) {
                    strcat(mathBuffer, " ");
                    mathBufferLen++;
                }

                if (lineLen) {
                    strcat(mathBuffer, line);
                    mathBufferLen += lineLen;
                }
            }
        }
    }
    return (-linesRead);
}

void
#ifndef _NO_PROTO
computeNodeWidth(listNode * n)
#else
computeNodeWidth(n)
listNode * n;
#endif
{
    char *s;
    int i;
    listNode *tmp;

    if (n->width != -1)         /* only = -1 if unprocessed */
        return;

    n->realWidth = 0;

    if (n->nodeType == N_TEXT) {
        s = n->data.text;
        if (s[0] == '\\') {
            if (s[2] == '\0') {
                switch (s[1]) {
                  case ' ':
                    n->width = spaceWidths[0];
                    break;
                  case ',':
                    n->width = spaceWidths[1];
                    break;
                  case '!':
                    n->width = spaceWidths[2];
                    break;
                  case ':':
                    n->width = spaceWidths[3];
                    break;
                  case ';':
                    n->width = spaceWidths[4];
                    break;
                  default:
                    n->width = avgCharWidth;
                }
                n->realWidth = n->width;
            }
            else if ((0 == strcmp(s, "\\displaystyle")) ||
                     (0 == strcmp(s, "\\bf")) ||
                     (0 == strcmp(s, "\\sf")) ||
                     (0 == strcmp(s, "\\tt")) ||
                     (0 == strcmp(s, "\\rm")) ||
                     (0 == strcmp(s, "\\hbox")) ||
                     (0 == strcmp(s, "\\mbox")) ||
                     (0 == strcmp(s, "\\overline")) ||
                     (0 == strcmp(s, "\\textstyle")) ||
                     (0 == strcmp(s, "\\scriptstyle")) ||
                     (0 == strcmp(s, "\\scriptscriptstyle"))) {
                n->width = 0;
            }
            else if (0 == strcmp(s, "\\ldots"))
                n->width = 3 * charWidth('.');
            else if (0 == strcmp(s, "\\left")) {
                tmp = n->nextListNode;
                if (tmp->nodeType != N_TEXT)
                    error("unusual token following \\left", "");
                n->realWidth = n->width = (tmp->data.text[0] == '.')
                    ? 0
                    : charWidth(tmp->data.text[0]);
                tmp->width = 0;
                fatDelimiter = 1;
            }
            else if (0 == strcmp(s, "\\over")) {

                /*
                 * have already added in width of numerator
                 */
                computeNodeWidth(n->nextListNode);
                n->realWidth = extraOverWidth + max(n->prevListNode->width, 
n->nextListNode->width);
                n->width = n->realWidth - n->prevListNode->width;
                n->nextListNode->width = 0;
                fatDelimiter = FATDELIMMULT;
            }
            else if (0 == strcmp(s, "\\right")) {
                tmp = n->nextListNode;
                if (tmp->nodeType != N_TEXT)
                    error("unusual token following \\right", "");
                n->realWidth = n->width = fatDelimiter *
                    ((tmp->data.text[0] == '.') ? 0 : 
charWidth(tmp->data.text[0]));
                tmp->width = 0;
                fatDelimiter = 1;
            }
            else if (0 == strcmp(s, "\\root")) {
                computeNodeWidth(n->nextListNode);      /* which root */
                n->nextListNode->nextListNode->width = 0;       /* \of */
                tmp = n->nextListNode->nextListNode->nextListNode;
                computeNodeWidth(tmp);  /* root of    */
                n->realWidth = n->width = tmp->width + (avgCharWidth / 2) +
                    max(avgCharWidth, n->nextListNode->width);
                n->nextListNode->width = 0;
                tmp->width = 0;
            }
            else if (0 == strcmp(s, "\\sqrt")) {
                computeNodeWidth(n->nextListNode);
                n->realWidth = n->width =
                    avgCharWidth + (avgCharWidth / 2) + n->nextListNode->width;
                n->nextListNode->width = 0;
            }
            else if (0 == strcmp(s, "\\zag")) {
                computeNodeWidth(n->nextListNode);
                computeNodeWidth(n->nextListNode->nextListNode);
                n->realWidth = n->width = avgCharWidth + 
max(n->nextListNode->width,
                                      n->nextListNode->nextListNode->width);
                n->nextListNode->width = 0;
                n->nextListNode->nextListNode->width = 0;
                fatDelimiter = FATDELIMMULT;
            }
            else if ((0 == strcmp(s, "\\alpha")) ||
                     (0 == strcmp(s, "\\beta")) ||
                     (0 == strcmp(s, "\\pi"))) {
                n->realWidth = n->width = avgCharWidth;
            }
            else if (0 == strcmp(s, "\\sin"))
                /* should use table lookup here */
                n->realWidth = n->width = sinWidth;
            else if (0 == strcmp(s, "\\cos"))
                n->realWidth = n->width = cosWidth;
            else if (0 == strcmp(s, "\\tan"))
                n->realWidth = n->width = tanWidth;
            else if (0 == strcmp(s, "\\erf"))
                n->realWidth = n->width = erfWidth;

            /*
             * otherwise just compute length of token after \
             */
            else {
                n->width = 0;
                for (i = 1; i < strlen(s); i++)
                    n->width += charWidth(s[i]);
                n->realWidth = n->width;
            }
        }
        else if (s[1] == '\0')
            switch (s[0]) {
              case '^':
              case '_':
                tmp = n->nextListNode;
                computeNodeWidth(tmp);
                n->width = n->width = tmp->width;
                tmp->width = 0;
                break;
              default:
                n->realWidth = n->width = charWidth(s[0]);
            }
        else {
            n->width = 0;
            for (i = 0; i < strlen(s); i++)
                n->width += charWidth(s[i]);
            n->realWidth = n->width;
        }
    }
    else {
        n->realWidth = n->width = computeWidth(n->data.node);
    }
}

long
#ifndef _NO_PROTO
computeWidth(listNode * n)
#else
computeWidth(n)
listNode * n;
#endif
{
    long w = 0;

    while (n != NULL) {
        if (n->width == -1) {
            computeNodeWidth(n);
            w += n->width;
        }
        n = n->nextListNode;
    }
    return w;
}

/*
 * displaySplitMsg:
 *
 * Arguments:
 *
 * s : a string describing the kind of expression we are trying to split.
 *
 * ok : whether we can split it (TRUE or FALSE)
 *
 *
 * Returns: nothing
 *
 *
 * Function: Displays a message on stderr about whether a particular method of
 * line breaking will be successful.
 */

void
#ifndef _NO_PROTO
displaySplitMsg(char *s, int ok)
#else
displaySplitMsg(s,ok)
char *s; 
int ok;
#endif
{
    fprintf(stderr, "%sCan split %s: %s\n", blanks, s, ok ? "TRUE" : "FALSE");
}

void
arrayTooDeep()
{
    fprintf(stderr, "%s->Array nesting too deep!\n", blanks);
}

void
#ifndef _NO_PROTO
error(char *msg, char *insert)
#else
error(msg,insert)
char *msg;
char *insert;
#endif
{
    fputs("Error (texbreak): ", stderr);
    fputs(msg, stderr);
    fputs(insert, stderr);
    fputc('\n', stderr);

    fputs("% Error (texbreak): ", stdout);
    fputs(msg, stdout);
    fputs(insert, stdout);
    fputc('\n', stdout);
    exit(1);
}

void
#ifndef _NO_PROTO
freeMathList(listNode * n)
#else
freeMathList(n)
listNode * n;
#endif
{
    listNode *tmpNode;

    while (n != NULL) {
        if (n->nodeType == N_NODE)
            freeMathList(n->data.node);
        else if (n->nodeType == N_TEXT)
            free(n->data.text);
        else {
            freeMathList(n->data.array->argsNode);
            freeMathList(n->data.array->entries);
            free(n->data.array);
        }
        tmpNode = n->nextListNode;
        free(n);
        n = tmpNode;
    }
}

listNode *
#ifndef _NO_PROTO
insertStringAfter(char *s, listNode * n)
#else
insertStringAfter(s,n)
char *s; 
listNode * n;
#endif
{

    /*
     * returns node after inserted string
     */
    listNode *workNode, *lastNode;

    workNode = newListNode(N_NODE);
    lastNode = string2NodeList(s, workNode);

    n->nextListNode->prevListNode = lastNode;
    lastNode->nextListNode = n->nextListNode;
    n->nextListNode = workNode->data.node;
    workNode->data.node->prevListNode = n;

    free(workNode);
    return lastNode->nextListNode;
}

listNode *
#ifndef _NO_PROTO
insertStringAtBack(char *s, listNode * n)
#else
insertStringAtBack(s,n)
char *s; 
listNode * n;
#endif
{

    /*
     * Breaks s up into a list of tokens and appends them onto the end of n.
     * n must be non-NULL.
     */

    listNode *workNode, *lastNode;

    workNode = newListNode(N_NODE);
    lastNode = string2NodeList(s, workNode);
    n->nextListNode = workNode->data.node;
    workNode->data.node->prevListNode = n;
    free(workNode);

    return lastNode;
}

listNode *
#ifndef _NO_PROTO
insertStringAtFront(char *s, listNode * n)
#else
insertStringAtFront(s,n)
char *s; 
listNode * n;
#endif
{

    /*
     * Breaks s up into a list of tokens and appends them onto the front of
     * n. n must be a node.
     */

    listNode *workNode, *lastNode;

    workNode = newListNode(N_NODE);
    lastNode = string2NodeList(s, workNode);
    lastNode->nextListNode = n->data.node;
    n->data.node->prevListNode = lastNode;
    n->data.node = workNode->data.node;
    free(workNode);

    return lastNode;
}

int
#ifndef _NO_PROTO
newLineIfNecessary(int lastWasNewLine)
#else
newLineIfNecessary(lastWasNewLine)
int lastWasNewLine;
#endif
{
    if (!lastWasNewLine || (charsOut > 0)) {
        putc('\n', stdout);
        outLineNum++;
        charsOut = 0;
    }
    return TRUE;
}

listNode *
#ifndef _NO_PROTO
newListNode(enum nodeTypes nt)
#else
newListNode(nt)
enum nodeTypes nt;
#endif
{
    listNode *n;

    n = (listNode *) malloc(sizeof(listNode));
    n->nextListNode = n->prevListNode = NULL;
    n->nodeType = nt;
    n->width = -1;
    n->realWidth = -1;
    if (nt == N_NODE)
        n->data.node = NULL;
    else if (nt == N_TEXT)
        n->data.text = NULL;
    else {
        n->data.array = (arrayNode *) malloc(sizeof(arrayNode));
        n->data.array->argsNode = NULL;
        n->data.array->entries = NULL;
        n->data.array->cols = 0;
    }
    return n;
}

int
nextMathToken()
{


    /*
     * Sets mathToken. Returns 1 if ok, 0 if no more tokens.
     */

    char curChar, errChar[2];

    errChar[1] = '\0';
    mathToken[0] = '\0';
    mathTokenLen = 0;

    /*
     * Kill any blanks.
     */

    while ((mathBufferPtr < mathBufferLen) && (mathBuffer[mathBufferPtr] == ' 
'))
        mathBufferPtr++;

    /*
     * If at end, exit saying so.
     */

    if (mathBufferPtr >= mathBufferLen)
        return 0;

    mathToken[mathTokenLen++] = curChar = mathBuffer[mathBufferPtr++];

    if (curChar == '\\') {
        curChar = mathBuffer[mathBufferPtr++];
        switch (curChar) {
          case '\0':            /* at end of buffer */
            mathToken[mathTokenLen++] = ' ';
            goto done;
          case '\\':
          case ' ':
          case '!':
          case '#':
          case '$':
          case '%':
          case '&':
          case ',':
          case ':':
          case ';':
          case '^':
          case '_':
          case '{':
          case '}':
            mathToken[mathTokenLen++] = curChar;
            goto done;
        }
        if (isalpha(curChar) || (curChar == '@')) {
            mathToken[mathTokenLen++] = curChar;
            while ((curChar = mathBuffer[mathBufferPtr]) &&
                   (isalpha(curChar) || (curChar == '@'))) {
                mathToken[mathTokenLen++] = curChar;
                mathBufferPtr++;
            }
        }
        else {
            errChar[0] = curChar;
            errChar[1] = '\0';
            error("strange character following \\: ", errChar);
        }
    }
    else if (isdigit(curChar))  /* digits are individual tokens */
        ;
    else if (isalpha(curChar)) {
        while ((curChar = mathBuffer[mathBufferPtr]) &&
               (isalpha(curChar))) {
            mathToken[mathTokenLen++] = curChar;
            mathBufferPtr++;
        }
    }
    else if (curChar == '"') {  /* handle strings */
        while ((curChar = mathBuffer[mathBufferPtr]) &&
               (curChar != '"')) {
            mathToken[mathTokenLen++] = curChar;
            mathBufferPtr++;
        }
        mathToken[mathTokenLen++] = '"';
        mathBufferPtr++;
    }

done:
    mathToken[mathTokenLen--] = '\0';

    /*
     * Some translations.
     */
    if (0 == strcmp(mathToken, "\\sp")) {
        mathToken[0] = '^';
        mathToken[1] = '\0';
        mathTokenLen = 1;
    }
    else if (0 == strcmp(mathToken, "\\sb")) {
        mathToken[0] = '_';
        mathToken[1] = '\0';
        mathTokenLen = 1;
    }

    return 1;
}

int
#ifndef _NO_PROTO
printChar(char c)
#else
printChar(c)
char c;
#endif
{
    if ((charsOut > MAXCHARSINLINE) &&
        isdigit(lastPrinted) && isdigit(c)) {
        putc('\n', stdout);
        outLineNum++;
        charsOut = 0;
    }

    putc(c, stdout);
    lastPrinted = c;
    charsOut++;

    /*
     * break lines after following characters
     */

    if ((charsOut > MAXCHARSINLINE) && strchr("+- ,_^", c)) {
        putc('\n', stdout);
        outLineNum++;
        charsOut = 0;
        lastPrinted = '\0';
        return TRUE;
    }
    return FALSE;
}

int
#ifndef _NO_PROTO
printMathList(listNode * n, int lastWasNewLine)
#else
printMathList(n,lastWasNewLine)
listNode * n; 
int lastWasNewLine;
#endif
{
    listNode *tmpNode, *rowNode, *colNode;
    int begin, group, r, c;

    while (n != NULL) {
        if (n->nodeType == N_NODE) {
            lastWasNewLine = printChar('{');
            lastWasNewLine = printMathList(n->data.node, lastWasNewLine);
            lastWasNewLine = printChar('}');
        }
        else if (n->nodeType == N_ARRAY) {
            lastWasNewLine = newLineIfNecessary(lastWasNewLine);
            lastWasNewLine = printString("\\begin{array}");
            lastWasNewLine = printMathList(n->data.array->argsNode, 
lastWasNewLine);
            lastWasNewLine = printString("\\displaystyle");
            lastWasNewLine = newLineIfNecessary(lastWasNewLine);

            rowNode = n->data.array->entries;   /* node pointing to first row */
            while (rowNode) {
                colNode = rowNode->data.node;
                while (colNode) {
                    if (colNode->prevListNode) {        /* if not first column 
*/
                        lastWasNewLine = printString(" & ");
                        lastWasNewLine = newLineIfNecessary(lastWasNewLine);
                    }
                    lastWasNewLine = printMathList(colNode->data.node, 
lastWasNewLine);
                    colNode = colNode->nextListNode;
                }
                if (rowNode->nextListNode)      /* if not last row */
                    lastWasNewLine = printString(" \\\\");

                lastWasNewLine = newLineIfNecessary(lastWasNewLine);
                rowNode = rowNode->nextListNode;
            }

            lastWasNewLine = printString("\\end{array}");
            lastWasNewLine = newLineIfNecessary(lastWasNewLine);
        }
        else if (n->nodeType == N_TEXT) {

            /*
             * handle keywords that might appear in math mode
             */

            if ((0 == strcmp(n->data.text, "by")) ||
                (0 == strcmp(n->data.text, "if")) ||
                (0 == strcmp(n->data.text, "then")) ||
                (0 == strcmp(n->data.text, "else"))) {
                lastWasNewLine = printString(" \\hbox{ ");
                lastWasNewLine = printString(n->data.text);
                lastWasNewLine = printString(" } ");
            }

            /*
             * handle things that should be in a special font
             */

            else if ((0 == strcmp(n->data.text, "true")) ||
                     (0 == strcmp(n->data.text, "false")) ||
                     (0 == strcmp(n->data.text, "table")) ||
                     (0 == strcmp(n->data.text, "Aleph"))
                ) {
                lastWasNewLine = printString(" \\mbox{\\rm ");
                lastWasNewLine = printString(n->data.text);
                lastWasNewLine = printString("} ");
            }

            /*
             * handle things that should always be on their own line
             */

            else if ((0 == strcmp(n->data.text, "\\\\")) ||
                     (0 == strcmp(n->data.text, "\\displaystyle"))) {
                lastWasNewLine = newLineIfNecessary(lastWasNewLine);
                lastWasNewLine = printString(n->data.text);
                lastWasNewLine = newLineIfNecessary(lastWasNewLine);
            }

            /*
             * handle phrases that should be on their own line.
             */

            else if ((0 == strcmp(n->data.text, "\\begin")) ||
                     (0 == strcmp(n->data.text, "\\end"))) {
                lastWasNewLine = newLineIfNecessary(lastWasNewLine);
                lastWasNewLine = printString(n->data.text);
                begin = (n->data.text[1] == 'b') ? TRUE : FALSE;

                n = n->nextListNode;    /* had better be a node */
                tmpNode = n->data.node;
                lastWasNewLine = printChar('{');
                lastWasNewLine = printMathList(tmpNode, lastWasNewLine);
                lastWasNewLine = printChar('}');

                if (begin) {

                    /*
                     * if array, print the argument.
                     */

                    if (0 == strcmp(tmpNode->data.text, "array")) {
                        n = n->nextListNode;    /* had better be a node */
                        lastWasNewLine = printChar('{');
                        lastWasNewLine = printMathList(n->data.node, 
lastWasNewLine);
                        lastWasNewLine = printChar('}');
                    }
                }
                lastWasNewLine = newLineIfNecessary(FALSE);
            }

            /*
             * handle everything else, paying attention as to whether we
             * should include a trailing blank.
             */

            else {
                group = 0;
                /* guess whether next word is part of a type */
                if ((strlen(n->data.text) > 2) &&
                    ('A' <= n->data.text[0]) &&
                    ('Z' >= n->data.text[0])) {
                    group = 1;
                    lastWasNewLine = printString("\\hbox{\\axiomType{");
                }
                lastWasNewLine = printString(n->data.text);
                if (group) {
                    lastWasNewLine = printString("}\\ }");
                    group = 0;
                }
                tmpNode = n->nextListNode;
                if ((n->data.text[0] == '_') ||
                    (n->data.text[0] == '^') ||
                    (n->data.text[0] == '.') ||
                    (n->data.text[0] == '(') ||
                    (0 == strcmp(n->data.text, "\\left")) ||
                    (0 == strcmp(n->data.text, "\\right")) ||
                    (0 == strcmp(n->data.text, "\\%")));
                else if (tmpNode && (tmpNode->nodeType == N_TEXT)) {
                    if (((isdigit(n->data.text[0])) &&
                         (isdigit(tmpNode->data.text[0]))) ||
                        ((isdigit(n->data.text[0])) &&
                         (',' == tmpNode->data.text[0])) ||
                        (tmpNode->data.text[0] == '\'') ||
                        (tmpNode->data.text[0] == '_') ||
                        (tmpNode->data.text[0] == '^') ||
                        (tmpNode->data.text[0] == '.') ||
                        (tmpNode->data.text[0] == ')'));
                    else
                        lastWasNewLine = printChar(' ');
                }
            }
        }
        n = n->nextListNode;
    }
    return lastWasNewLine;
}

int
#ifndef _NO_PROTO
printString(char *s)
#else
printString(s)
char *s;
#endif
{
    if (s[0]) {
        if (!s[1])
            return printChar(s[0]);
        else {
            fputs(s, stdout);
            charsOut += strlen(s);
        }
    }
    return FALSE;
}

listNode *
#ifndef _NO_PROTO
string2NodeList(char *s, listNode * n)
#else
string2NodeList(s,n)
char *s;
listNode * n;
#endif
{

    /*
     * First argument is string to be broken up, second is a node. Return
     * value is last item in list.
     */

    mathBufferPtr = 0;
    strcpy(mathBuffer, s);
    mathBufferLen = strlen(s);
    buildMathList(n);
    n = n->data.node;
    while (n->nextListNode) {

        /*
         * set width to 0: other funs will have to set for real
         */
        n->width = 0;
        n = n->nextListNode;
    }
    n->width = 0;
    return n;
}

void
resetCharMults()
{

    /*
     * this is a ratio by which the standard \mit should be multiplied to get
     * other fonts, roughly
     */

    charMultNum = charMultDenom = 1;
}

void
ttCharMults()
{

    /*
     * this is a ratio by which the standard \mit should be multiplied to get
     * the \tt font, roughly
     */

    charMultNum = 11;
    charMultDenom = 10;
}

int
#ifndef _NO_PROTO
charWidth(char c)
#else
charWidth(c)
char c;
#endif
{
    return (charMultNum * charTable[c]) / charMultDenom;
}

void
#ifndef _NO_PROTO
#else
#endif
initCharTable()
{
    int i;

    avgCharWidth = 95;          /* where 1000 = 1 inch */

    spaceWidths[0] = 51;        /* \  */
    spaceWidths[1] = 25;        /* \, */
    spaceWidths[2] = -25;       /* \! */
    spaceWidths[3] = 37;        /* \: */
    spaceWidths[4] = 42;        /* \; */

    extraOverWidth = 33;        /* extra space in fraction bar */

    sinWidth = 186;             /* width of \sin */
    cosWidth = 203;
    tanWidth = 219;
    erfWidth = 185;

    for (i = 0; i < 256; i++)
        charTable[i] = avgCharWidth;

    charTable['!'] = 42;
    charTable['"'] = 76;
    charTable['%'] = 126;
    charTable['('] = 59;
    charTable[')'] = 59;
    charTable['+'] = 185;
    charTable[','] = 42;
    charTable['-'] = 185;
    charTable['.'] = 42;
    charTable['/'] = 76;
    charTable['0'] = 76;
    charTable['1'] = 76;
    charTable['2'] = 76;
    charTable['3'] = 76;
    charTable['4'] = 76;
    charTable['5'] = 76;
    charTable['6'] = 76;
    charTable['7'] = 76;
    charTable['8'] = 76;
    charTable['9'] = 76;
    charTable[':'] = 42;
    charTable[';'] = 42;
    charTable['<'] = 202;
    charTable['='] = 202;
    charTable['>'] = 202;
    charTable['A'] = 114;
    charTable['B'] = 123;
    charTable['C'] = 119;
    charTable['D'] = 130;
    charTable['E'] = 121;
    charTable['F'] = 119;
    charTable['G'] = 119;
    charTable['H'] = 138;
    charTable['I'] = 79;
    charTable['J'] = 99;
    charTable['K'] = 140;
    charTable['L'] = 103;
    charTable['M'] = 164;
    charTable['N'] = 138;
    charTable['O'] = 120;
    charTable['P'] = 118;
    charTable['Q'] = 120;
    charTable['R'] = 116;
    charTable['S'] = 102;
    charTable['T'] = 110;
    charTable['U'] = 120;
    charTable['V'] = 122;
    charTable['W'] = 164;
    charTable['X'] = 137;
    charTable['Y'] = 122;
    charTable['Z'] = 114;
    charTable['['] = 42;
    charTable[']'] = 42;
    charTable['a'] = 80;
    charTable['b'] = 65;
    charTable['c'] = 66;
    charTable['d'] = 79;
    charTable['e'] = 71;
    charTable['f'] = 91;
    charTable['g'] = 78;
    charTable['h'] = 87;
    charTable['i'] = 52;
    charTable['j'] = 71;
    charTable['k'] = 84;
    charTable['l'] = 48;
    charTable['m'] = 133;
    charTable['n'] = 91;
    charTable['o'] = 73;
    charTable['p'] = 76;
    charTable['q'] = 73;
    charTable['r'] = 73;
    charTable['s'] = 71;
    charTable['t'] = 55;
    charTable['u'] = 87;
    charTable['v'] = 79;
    charTable['w'] = 113;
    charTable['x'] = 87;
    charTable['y'] = 80;
    charTable['z'] = 77;
    charTable['{'] = 76;
    charTable['|'] = 42;
    charTable['}'] = 76;
}

void
#ifndef _NO_PROTO
getOptions(int argc, char **argv)
#else
getOptions(argc,argv)
int argc; 
char **argv;
#endif
{
    int i, j;

    for (i = 1; i < argc; i++) {

        if (argv[i][0] != '-')
            break;

        else if (0 == strcmp(argv[i], "-help")) {
            printf("No help yet.\n");
            exit(0);
        }

        else if (0 == strcmp(argv[i], "-width")) {
            if (++i < argc) {
                j = atoi(argv[i]);
                if (j < 1000) {
                    printf("A positive integer > 1000 is required after 
-width.\n");
                    exit(3);
                }
                maxLineWidth = j;
            }
            else {
                printf("A positive integer > 1000 is required after -width.\n");
                exit(3);
            }
        }

        else if (0 == strcmp(argv[i], "-slop")) {
            if (++i < argc) {
                j = atoi(argv[i]);
                if (j < 0) {
                    printf("An integer >= 0 is required after -slop.\n");
                    exit(3);
                }
                maxLineSlop = j;
            }
            else {
                printf("An integer >= 0 is required after -slop.\n");
                exit(3);
            }
        }

        else if (0 == strcmp(argv[i], "-depth")) {
            if (++i < argc) {
                j = atoi(argv[i]);
                if (j < 0) {
                    printf("An integer >= 0 is required after -depth.\n");
                    exit(3);
                }
                arrayMaxDepth = j;
            }
            else {
                printf("An integer >= 0 is required after -depth.\n");
                exit(3);
            }
        }

        else {
            printf("Unknown option %s for command %s.\n",
                   argv[i], argv[0]);
            exit(3);
        }
    }
}





reply via email to

[Prev in Thread] Current Thread [Next in Thread]