diff options
Diffstat (limited to 'contrib/texmacs/src/texbreaker.c')
-rwxr-xr-x | contrib/texmacs/src/texbreaker.c | 2007 |
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; +} |