axiom-developer
[Top][All Lists]
Advanced

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

[Axiom-developer] Patch for axiom plugin: line-breaking algorithm & supp


From: David MENTRE
Subject: [Axiom-developer] Patch for axiom plugin: line-breaking algorithm & support of both NAG and free Axiom
Date: Fri, 31 Oct 2003 20:04:39 +0100
User-agent: Gnus/5.1002 (Gnus v5.10.2) Emacs/21.2 (gnu/linux)

Hello,

Here is a patch against TeXmacs 1.0.2.4 axiom plugin that includes:

 - support of both free and NAG versions of Axiom (only tested on the
   free Axiom, I have not access to the NAG version)

 - inclusion of a line-breaking algorithm

 - modification on prompt handling to interact correctly with Axiom

Please notice that this patch will work only with releases of Axiom
starting from current CVS tree. Older Axiom (like those found
precompiled on Axiom web site) won't work.

Most of the work of this patch comes from Bill Page.

Let me know of any issue with this patch.

Yours,
d.

diff -aur TeXmacs-1.0.2.4-src.orig/plugins/axiom/progs/init-axiom.scm 
TeXmacs-1.0.2.4-src/plugins/axiom/progs/init-axiom.scm
--- TeXmacs-1.0.2.4-src.orig/plugins/axiom/progs/init-axiom.scm Thu Jul 17 
12:44:08 2003
+++ TeXmacs-1.0.2.4-src/plugins/axiom/progs/init-axiom.scm      Fri Oct 31 
19:23:52 2003
@@ -17,7 +17,7 @@
   (lazy-input-converter (axiom-input) axiom))
 
 (plugin-configure axiom
-  (:require (url-exists-in-path? "axiom"))
+  (:require (url-exists-in-path? "AXIOMsys"))
   (:initialize (axiom-initialize))
   (:launch "tm_axiom")
   (:session "Axiom"))
diff -aur TeXmacs-1.0.2.4-src.orig/plugins/axiom/src/tm_axiom.c 
TeXmacs-1.0.2.4-src/plugins/axiom/src/tm_axiom.c
--- TeXmacs-1.0.2.4-src.orig/plugins/axiom/src/tm_axiom.c       Fri Apr 18 
15:42:59 2003
+++ TeXmacs-1.0.2.4-src/plugins/axiom/src/tm_axiom.c    Fri Oct 31 19:49:51 2003
@@ -1,4 +1,3 @@
-
 /******************************************************************************
 * MODULE     : tm_axiom.c
 * DESCRIPTION: Glue between TeXmacs and Axiom
@@ -8,9 +7,39 @@
 * ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
 * If you don't have this file, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-******************************************************************************/
+******************************************************************************
+*
+* Including TeX Display Math Mode Line Breaking Program
+*
+* Author: Robert S. Sutor
+*
+* Date: 1991
+*
+* Change History:
+*
+* 09/01/92 RSS Format and fix =-.
+* 09/29/03 WSP Incorporated linebreaker into tm_axiom
+*              Replace \root{n} \of {x} with \sqrt[n]{x}
+*
+* Operation:
+*
+* 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. 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
 #include <unistd.h>
 
 #define NORMAL 0
@@ -20,11 +49,79 @@
 #define MATH   4
 #define TYPE   5
 
-#define LEN 128
-/*#define LOG "/home/grozin/tmax/log"*/
+#define LEN 256
+/* #define LOG "/tmp/tm_axiom.log" */
+
+#define MATHBUFLEN     16*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;
 
 char buf[LEN];
-int len,code,writing=1,wait_type=0;
+int len,code,writing=0,wait_type=0,mmode=0; /* was writing=1 */
 char prompt[]="-> ";
 char math[]="$$\n";
 char Type[]="Type: ";
@@ -76,7 +173,7 @@
       else if (c=='\n') { if (writing) putchar('\n'); break; }
       else if (writing) putchar(c);
     }
-    else putchar(c);
+    else if (writing) putchar(c);
   }
 }
 
@@ -90,7 +187,7 @@
     { for (k=0;k<j;) buf[i++]=prompt[k++];
       j=0;
       if (i>LEN-4) { code=LONG; break; }
-      else if (c==EOF) { code==END; break; }
+      else if (c==EOF) { code=END; break; }
       else if (c=='\n') { buf[i++]='\n'; code=NORMAL; break; }
       else buf[i++]=c;
     }
@@ -115,7 +212,7 @@
   if (code==LONG) code=NORMAL;
 }
 
-void line(void)
+void oline(void)
 { int i=0,j,k,c; char *s;
   code=NORMAL; c=ch();
   if (c==EOF) code=END;
@@ -162,37 +259,1681 @@
 #ifdef LOG
   lline();
 #endif
-  if (wait_type&&(code==NORMAL))
+  if (/*wait_type && */(code==NORMAL))
   { if (len==1) return;
     wait_type=0;
     if (len==78)
     { for (s=buf,k=0;k<len-7;s++,k++) if ((*s)!=' ') break;
       for (k=0;k<6;s++,k++) if ((*s)!=Type[k]) break;
       if (k==6)
-      { buf[77]='\0';
+      { /* buf[77]='\0'; */
+       wait_type=1;
         printf("\2latex:\\axiomtype{%s}\5",s);
         return;
       }
     }
-  }
-  fputs(buf,stdout);
+  };
+  if (wait_type) printf("\2latex:\\red$\\rightarrow$\\black\\ \5");
+  if (mmode) {
+    strcat(mathBuffer,buf);
+  } else {
+    fputs(buf,stdout);
+  };
   if (code==LONG) tail();
   if (code==LONG) code=NORMAL;
 }
 
 void must_be_prompt(char *mess)
-{ line();
+{ iline();
   if (code!=PROMPT)
   { printf("\2latex:\\red Cannot get prompt %s\\black\5\5",mess);
     exit(1);
   }
 }
 
+void error(char *msg, char *insert)
+{
+ 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);
+}
+
+listNode * newListNode(enum nodeTypes nt)
+{
+ listNode *n;
+/* fputs("newListNode\n",stdout); debug */
+ 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];
+/* fputs("nextMathToken: ",stdout); debug */
+ 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;
+ }
+/* fputs(mathToken,stdout);
+  fputs("\n",stdout); debug */
+
+ return 1;
+}
+
+void buildMathList(listNode * oldNode)
+{
+ listNode *curNode, *tmpNode;
+/* fputs("buildMathList\n",stdout); debug */
+ 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;
+ }
+}
+
+listNode * string2NodeList(char *s, listNode * n)
+{
+
+ /*
+  * 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;
+}
+
+listNode * insertStringAfter(char *s, listNode * n)
+{
+
+ /*
+  * 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 * insertStringAtBack(char *s, listNode * n)
+{
+
+ /*
+  * 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 * insertStringAtFront(char *s, listNode * n)
+{
+
+ /*
+  * 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 charWidth(char c)
+{
+ return (charMultNum * charTable[(int)c]) / charMultDenom;
+}
+
+void computeNodeWidth(listNode * n)
+{
+ char *s;
+ int i;
+ listNode *tmp;
+
+ long computeWidth();
+
+ 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 computeWidth(listNode * n)
+{
+ 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 displaySplitMsg(char *s, int ok)
+{
+/* fprintf(stderr, "%sCan split %s: %s\n", blanks, s, ok ? "TRUE" : "FALSE"); 
*/
+}
+
+void arrayTooDeep()
+{
+ fprintf(stderr, "%s->Array nesting too deep!\n", blanks);
+}
+
+/*
+ * 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 breakMathList(listNode * n, long lineWidth)
+{
+
+int breakFracProd();
+int breakFunction();
+int breakList();
+int breakNumber();
+int breakPMEB();
+int breakParen();
+/* fputs("breakMathList\n",stdout); debug */
+ 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;
+}
+
+/*
+ * 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 breakFracProd(listNode * n, long lineWidth, char *match, char *label, int 
paren)
+{
+
+ 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 breakFunction(listNode * n, long lineWidth)
+{
+ listNode *t2;
+ int ok = FALSE;
+
+ 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 breakList(listNode * n, long lineWidth)
+{
+ 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 breakNumber(listNode * rootNode, long lineWidth)
+{
+ 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 resetWidths(listNode * n)
+{
+ 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 breakParen(listNode * n, long lineWidth)
+{
+ 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 breakPMEB(listNode * n, long lineWidth)
+{
+ 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;
+}
+
+void freeMathList(listNode * n)
+{
+  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;
+  }
+}
+
+int newLineIfNecessary(int lastWasNewLine)
+{
+ if (!lastWasNewLine || (charsOut > 0)) {
+ putc('\n', stdout);
+ outLineNum++;
+ charsOut = 0;
+ }
+ return TRUE;
+}
+
+int printChar(char c)
+{
+ 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 printString(char *s)
+{
+  if (s[0]) {
+    if (!s[1])
+      return printChar(s[0]);
+    else {
+      fputs(s, stdout);
+      charsOut += strlen(s);
+    }
+  }
+  return FALSE;
+}
+
+int printMathList(listNode * n, int lastWasNewLine)
+{
+  listNode *tmpNode, *rowNode, *colNode;
+  int begin, group;
+/* fputs("printMathList\n",stdout); debug */
+  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) {
+      if ((0 == strcmp(n->data.text, "\\root"))) {
+        printString("\\sqrt[");
+      }
+      else if ((0 == strcmp(n->data.text, "\\of"))) {
+        printString("]");
+      }
+ /*
+  * handle keywords that might appear in math mode
+  */
+
+      else 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;
+}
+
+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;
+}
+
+void 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 tex_to_latex()
+{
+  char *ptr1, leqno[60];
+/* fputs("tex_to_latex\n",stdout); debug */
+  while ((ptr1=strchr(mathBuffer,'\n'))) { strcpy(ptr1,ptr1+1); };
+/*
+ * handle equation number
+ */
+  if ((ptr1=strstr(mathBuffer,"\\leqno("))) {
+    strcpy(leqno,ptr1);
+    *ptr1 = '\0';
+  } else {
+    strcpy(leqno,"");
+  };
+/*
+ * Break long lines
+ * Replace \root{n} \of {x} with \sqrt[n]{x}
+ */
+  mathBufferLen=strlen(mathBuffer);
+  fatDelimiter = 1;
+  arrayDepth = 0;
+  mathList = newListNode(N_NODE);
+  buildMathList(mathList);
+  resetCharMults();
+  computeWidth(mathList);
+  breakMathList(mathList, maxLineWidth);
+  charsOut = 0;
+  printMathList(mathList->data.node, TRUE);
+  freeMathList(mathList);
+  fputs(leqno,stdout);
+}
+
 void session(void)
-{ int c,i,mmode,delims=0,prompts=0;
+{ int c,delims=0;
 #ifdef LOG
   log=fopen(LOG,"w");
 #endif
+
+ initCharTable();
+
   /* Write initial lines up to (but not including)
      the line with the first prompt
   */
@@ -200,13 +1941,18 @@
   while (1)
   { iline();
     if (code==TYPE) { if ((++delims)==2) writing=0; }
-    else if (code==PROMPT) { if ((++prompts)==2) break; }
+    else if (code==PROMPT) break;
   }
   /* force-feeding */
   fputs(")set messages prompt plain\n",axin); fflush(axin);
 #ifdef LOG
   fputs("SENT )set messages prompt plain\n",log); fflush(log);
 #endif
+  must_be_prompt("0");
+  fputs(")set messages autoload off\n",axin); fflush(axin);
+#ifdef LOG
+  fputs("SENT )set messages autoload off\n",log); fflush(log);
+#endif
   must_be_prompt("1");
   fputs(")set quit unprotected\n",axin); fflush(axin);
 #ifdef LOG
@@ -238,11 +1984,22 @@
     fflush(axin);
     mmode=0;
     while (1)
-    { line();
+    { oline();
       if ((code==PROMPT)||(code==END)) break;
-      if (code==MATH)
-      if (mmode) { mmode=0; wait_type=1; fputs("$\5\n",stdout); }
-      else { mmode=1; fputs("\2latex:$\\displaystyle\n",stdout); }
+      if (code==MATH) {
+        if (mmode) { /* convert TeX to LaTex etc. */
+/* fputs(mathBuffer,stdout);  debug */
+          fputs("\2latex:$\\displaystyle\n",stdout);
+         tex_to_latex();
+         mmode=0; wait_type=1;
+          fputs("$\5\n",stdout);
+               } else {
+          mathBufferPtr = 0;
+          mathBufferLen = 0;
+          mathBuffer[0] = '\0';
+         mmode=1;
+               }
+     };
     }
     if (code==END) break;
   }
@@ -263,11 +2020,12 @@
     case 0: /* Axiom */
       dup2(p1[1],1); close(p1[1]); close(p1[0]);
       dup2(p2[0],0); close(p2[0]); close(p2[1]);
-      execlp("axiom","axiom","-noclef",0);
-      fatal("exec axiom");
+      execlp("AXIOMsys","AXIOMsys","-noclef",0);
+      fatal("exec AXIOMsys");
     default: /* parent */
       close(p1[1]); close(p2[0]);
       axin=fdopen(p2[1],"w"); axout=fdopen(p1[0],"r");
       session();
   }
+  return 0;
 }

-- 
 David Mentré <address@hidden>
   http://www.linux-france.org/~dmentre/david-mentre-public-key.asc
 GnuPG key fingerprint: A7CD 7357 3EC4 1163 745B  7FD3 FB3E AD7C 2A18 BE9E




reply via email to

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