aboutsummaryrefslogtreecommitdiff
path: root/contrib/texmacs/src/texbreaker.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/texmacs/src/texbreaker.c')
-rwxr-xr-xcontrib/texmacs/src/texbreaker.c2007
1 files changed, 2007 insertions, 0 deletions
diff --git a/contrib/texmacs/src/texbreaker.c b/contrib/texmacs/src/texbreaker.c
new file mode 100755
index 00000000..49a5966c
--- /dev/null
+++ b/contrib/texmacs/src/texbreaker.c
@@ -0,0 +1,2007 @@
+/* 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 8*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];
+char bufout[2*MATHBUFLEN];
+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 putcBuf(char, char []);
+void putsBuf(char [], 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 putsBuf();
+void putcBuf();
+void resetCharMults();
+listNode *string2NodeList();
+void ttCharMults();
+#endif
+
+
+/*
+ * Function Definitions.
+ */
+
+int
+#ifndef _NO_PROTO
+texbreak(char bufinp[])
+#else
+texbreak(bufinp)
+char bufinp[];
+#endif
+{
+ initCharTable();
+ strcpy(bufout,"");
+ mathBufferLen=strlen(bufinp);
+ if (mathBufferLen > MATHBUFLEN) {
+ fprintf(stderr, "mathBuffer too small. Need: %d\n", mathBufferLen);
+ return 0;
+ };
+ mathBufferPtr = 0;
+ strcpy(mathBuffer,bufinp);
+/* fprintf(stderr, "bufinp: %s\n", mathBuffer); */
+ 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;
+ printMathList(mathList->data.node, TRUE);
+ freeMathList(mathList);
+ return 1;
+}
+
+/*
+ * 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("\\begin{array}{@{}l}\\displaystyle", 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("{@{}l}", 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("\\begin{array}{@{}l}\\displaystyle", 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;
+ }
+}
+
+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)) {
+ putcBuf('\n', bufout);
+ 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)) {
+ putcBuf('\n', bufout);
+ outLineNum++;
+ charsOut = 0;
+ }
+
+ putcBuf(c, bufout);
+ lastPrinted = c;
+ charsOut++;
+
+ /*
+ * break lines after following characters
+ */
+
+ if ((charsOut > MAXCHARSINLINE) && strchr("+- ,_^", c)) {
+ putcBuf('\n', bufout);
+ 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 {
+ putsBuf(s,bufout);
+ charsOut += strlen(s);
+ }
+ }
+ return FALSE;
+}
+
+void
+#ifndef _NO_PROTO
+putsBuf(char s[], char buf[])
+#else
+putsBuf(s,buf)
+char s[], buf[]
+#endif
+{
+ strcat(buf,s);
+}
+
+void
+#ifndef _NO_PROTO
+putcBuf(char c,char buf[])
+#else
+putcBuf(c,buf)
+char c, buf[]
+#endif
+{
+ char s[2];
+
+ s[0] = c;
+ s[1] = '\0';
+ strcat(buf,s);
+}
+
+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;
+}