From 44a49cb801191cd6e803204aaffe04ab7a65a345 Mon Sep 17 00:00:00 2001 From: dos-reis Date: Sat, 4 Jul 2009 15:29:29 +0000 Subject: 2009-07-04 Alfredo Portes * contrib/texmacs: New. --- contrib/texmacs/Makefile | 18 + contrib/texmacs/README.txt | 53 + contrib/texmacs/packages/session/openaxiom.ts | 42 + contrib/texmacs/progs/init-openaxiom.scm | 23 + contrib/texmacs/progs/openaxiom-input.scm | 53 + contrib/texmacs/src/texbreaker.c | 2007 +++++++++++++++++++++++++ contrib/texmacs/src/tm_openaxiom.c | 603 ++++++++ contrib/texmacs/src/useproto.h | 43 + 8 files changed, 2842 insertions(+) create mode 100755 contrib/texmacs/Makefile create mode 100755 contrib/texmacs/README.txt create mode 100755 contrib/texmacs/packages/session/openaxiom.ts create mode 100755 contrib/texmacs/progs/init-openaxiom.scm create mode 100755 contrib/texmacs/progs/openaxiom-input.scm create mode 100755 contrib/texmacs/src/texbreaker.c create mode 100755 contrib/texmacs/src/tm_openaxiom.c create mode 100755 contrib/texmacs/src/useproto.h (limited to 'contrib') diff --git a/contrib/texmacs/Makefile b/contrib/texmacs/Makefile new file mode 100755 index 00000000..3109524e --- /dev/null +++ b/contrib/texmacs/Makefile @@ -0,0 +1,18 @@ + +############################################################################### +# MODULE : Make file for opeenaxiom plugin +# BY : Joris van der Hoeven +# COPYRIGHT : This software falls under the GNU general public license; +# see the file 'LICENSE', which is provided with this package. +############################################################################### + +CC = gcc +RM = rm -f + +all: bin/tm_openaxiom + +bin/tm_openaxiom: src/tm_openaxiom.c + $(CC) src/tm_openaxiom.c src/texbreaker.c -o bin/tm_openaxiom + +clean: + $(RM) bin/tm_openaxiom diff --git a/contrib/texmacs/README.txt b/contrib/texmacs/README.txt new file mode 100755 index 00000000..52181db8 --- /dev/null +++ b/contrib/texmacs/README.txt @@ -0,0 +1,53 @@ +tm_openaxiom - TeXmacs OpenAxiom Interface Program + + Version 0.0.1 + 3 July 2009 + +Original Version by: Bill Page +Modified by: Alfredo Portes + +Compile this program within the MSYS environment on Windows using +the command: + + gcc tm_openaxiom.c texbreaker.c -o tm_openaxiom + +Copy the executable file 'tm_openaxiom.exe' to the OPENAXIOM bin directory: + + ... /installation-directory/bin + +Default options can be specified by the environment variable: + + export TM_OPENAXIOM='break 1, over 1, cdot 1, space 0, big( 1, width 4.500' + +These can be overridden by on the command line: + + tm_openaxiom 'break 1, over 1, cdot 1, space 0, big( 1, width 4.500' + +and can be modified dynamically via the simulated OpenAxiom command: + + )set output texmacs break 1, over 1, cdot 1, space 0, big( 1, width 4.500 + +You may use 1 yes or on and 0 no or off. + + break | line-break algorithm + over | convert 2-d \over to 1-d / + cdot | convert \cdot to \ (space) + space | convert \ (space) to \, + big( | convert \left( \right to ( ) + width <9.99> line width in inches + +I have also included an updated style file for OPENAXIOM + + openaxiom.ts + +which corrects the positioning of the OpenAxiom Type: clause. + +After installing TeXmacs for Windows, copy this file into the +TeXmacs directory: + + c:\Program Files\wintexmacs\texmacs\plugins\openaxiom\packages\session + +or the equivalent location for the Cygwin version of TeXmacs. + +Questions? bill.page1@sympatico.ca + doyenatccy@gmail.com \ No newline at end of file diff --git a/contrib/texmacs/packages/session/openaxiom.ts b/contrib/texmacs/packages/session/openaxiom.ts new file mode 100755 index 00000000..3dbb7cfe --- /dev/null +++ b/contrib/texmacs/packages/session/openaxiom.ts @@ -0,0 +1,42 @@ + + + + +<\body> + + + + <\src-purpose> + Markup for OpenAxiom sessions. + + + + + <\src-license> + This style package falls under the and comes WITHOUT ANY WARRANTY + WHATSOEVER. If you do not have a copy of the license, then write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + + > + + |||1.75fn||>|>>>> + + |||1.75fn>|>>>>>> + + \; + + >> + + >>> + + \; + + +<\initial> + <\collection> + + + \ No newline at end of file diff --git a/contrib/texmacs/progs/init-openaxiom.scm b/contrib/texmacs/progs/init-openaxiom.scm new file mode 100755 index 00000000..b6d485a3 --- /dev/null +++ b/contrib/texmacs/progs/init-openaxiom.scm @@ -0,0 +1,23 @@ + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; MODULE : init-openaxiom.scm +;; DESCRIPTION : Initialize openaxiom plugin +;; COPYRIGHT : (C) 1999 Joris van der Hoeven +;; +;; This software falls under the GNU general public license and comes WITHOUT +;; ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define (openaxiom-initialize) + (import-from (texmacs plugin plugin-convert)) + (lazy-input-converter (openaxiom-input) openaxiom)) + +(plugin-configure openaxiom + (:require (url-exists-in-path? "open-axiom")) + (:initialize (openaxiom-initialize)) + (:launch "tm_openaxiom") + (:session "OpenAxiom")) diff --git a/contrib/texmacs/progs/openaxiom-input.scm b/contrib/texmacs/progs/openaxiom-input.scm new file mode 100755 index 00000000..81da0b8f --- /dev/null +++ b/contrib/texmacs/progs/openaxiom-input.scm @@ -0,0 +1,53 @@ + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; MODULE : openopenaxiom-input.scm +;; DESCRIPTION : OpenAxiom input converters +;; COPYRIGHT : (C) 1999 Joris van der Hoeven +;; +;; This software falls under the GNU general public license and comes WITHOUT +;; ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(texmacs-module (openaxiom-input) + (:use (texmacs plugin plugin-convert))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Specific conversion routines +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define (openaxiom-input-var-row r) + (if (not (null? r)) + (begin + (display ", ") + (plugin-input (car r)) + (openaxiom-input-var-row (cdr r))))) + +(define (openaxiom-input-row r) + (display "[") + (plugin-input (car r)) + (openaxiom-input-var-row (cdr r)) + (display "]")) + +(define (openaxiom-input-var-rows t) + (if (not (null? t)) + (begin + (display ", ") + (openaxiom-input-row (car t)) + (openaxiom-input-var-rows (cdr t))))) + +(define (openaxiom-input-rows t) + (display "matrix([") + (openaxiom-input-row (car t)) + (openaxiom-input-var-rows (cdr t)) + (display "])")) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Initialization +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(plugin-input-converters openaxiom + (rows openaxiom-input-rows)) 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 +#include +#include +#include + +#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; +} diff --git a/contrib/texmacs/src/tm_openaxiom.c b/contrib/texmacs/src/tm_openaxiom.c new file mode 100755 index 00000000..edad4f68 --- /dev/null +++ b/contrib/texmacs/src/tm_openaxiom.c @@ -0,0 +1,603 @@ +/* tm_openaxiom.c + * COPYRIGHT : (C) 2004 Bill Page + * (Portions) COPYRIGHT : (C) 1999 Andrey Grozin + *********************************************************************** + * This software falls under the GNU general public license and comes + * WITHOUT 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. + *********************************************************************** + * + * The program runs OPENAXIOMsys as a separate process under Windows + * using CreateProcess() and asynchronous reader threads. It provides + * an interface between OpenAxiom and TeXmacs for windows. + * + * Before launching, stdin/out/err are each redirected into pipes + * so that OPENAXIOM can be fed commands and its output read from + * those pipes. A separate thread is created to manage reading the + * output of OpenAxiom and sending it (appropriatedly modified) to + * TeXmacs. The main thread reads from TeXmacs and sends it's + * output to OpenAxiom. In this way the input and output is completely + * asynchronous. There may be some advantage to the use of such + * "light weight" threads in Windows. + * + * Build with the command: + * gcc tm_openaxiom.c texbreaker.c -o tm_openaxiom.exe + * It is known to compile with gcc version 3.4.2 (mingw-special) + * under MinGW/MSYS. Other compilers may also work. + * + * Install the tm_openaxiom.exe file in the directory + * C:\Program Files\WinTeXmacs\TeXmacs\bin + * + * Written by Bill Page 20041203 + * - based on Maxima test version by Mike Thomas 20030624 + * (Thankyou Mike!) + * and on the TeXmacs tm_openaxiom.c program (linux) + * Modified by Bill Page 20041215 + * - add call to Robert Sutor line-break routine + * Modified by Bill Page 20041217 + * - initialize OPENAXIOM_exe from OPENAXIOM environment variable + * Modified by Bill Page 20041220 + * - use args, TM_OPENAXIOM environment variable and/or + * )set output texmacs option,option, ... + * to specify options + * break no -- disables line-break algorithm + * over no -- converts 2-d \over to 1-d / + * cdot no -- converts \cdot to \ (space) + * space no -- convert \ (space) to \, + * big( no -- convert \left( \right to ( ) + * width 4.5 -- 4.5 inches * 1000 + * - process OpenAxiom output with no LaTeX content, e.g. + * )set output tex off + * )set output algebra on + * */ + +#include +#include +#include +#include +#include +#include +#include + +/* Allow some debugging output from the IO threads */ +/*#define DEBUG_OUT*/ + +int option_texbreak = 1, /* default options */ + option_use_over = 1, + option_use_cdot = 1, + option_big_space = 0, + option_big_paren = 1; + +#define INP_BUFF_SIZE 3072 +#define OUT_BUFF_SIZE 8192 +char szBuffer[OUT_BUFF_SIZE]; +#define MATHBUFLEN 8*8192 +extern int maxLineWidth; +extern char bufout[2*MATHBUFLEN]; + +int nBuffer=0; +int nRead; +int IgnorePrompts=0; + +#define READ_HANDLE 0 +#define WRITE_HANDLE 1 + +char OPENAXIOM_cmd[256]; +char ENV_OPENAXIOM[256]; + +int fdStdOutPipe[2], fdStdInPipe[2], fdStdErrPipe[2]; + +HANDLE hProcess; +STARTUPINFO si; /* Only need to set si.cb */ +PROCESS_INFORMATION pi; /* Post launch child process information. */ + +/* consult the environment */ + +void parse_options(int nargs, char *args[]) { + char *pOPENAXIOM, *pTM_OPENAXIOM, *pOption; + int i; + float w; + + if (pOPENAXIOM=getenv("OPENAXIOM")) { + strcpy(OPENAXIOM_cmd,pOPENAXIOM); strcat(OPENAXIOM_cmd, "/../../../../bin/open-axiom.exe"); + strcat(OPENAXIOM_cmd," --system=\""); strcat(OPENAXIOM_cmd,pOPENAXIOM); + strcat(OPENAXIOM_cmd,"\""); + strcpy(ENV_OPENAXIOM,"OPENAXIOM="); strcat(ENV_OPENAXIOM, pOPENAXIOM); + } + else { + printf("You must set the OPENAXIOM environment variable, e.g.\n"); + exit(1); + } + +/* e.g. TM_OPENAXIOM='break off, over yes, ... + * if not found or different options, ignore silently */ + for (i=0;i0 || (pTM_OPENAXIOM=getenv("TM_OPENAXIOM"))) { + if (strstr(pTM_OPENAXIOM,"break off") + || strstr(pTM_OPENAXIOM,"break n") + || strstr(pTM_OPENAXIOM,"break 0")) + option_texbreak=0; + if (strstr(pTM_OPENAXIOM,"break on") + || strstr(pTM_OPENAXIOM,"break y") + || strstr(pTM_OPENAXIOM,"break 1")) + option_texbreak=1; + if (strstr(pTM_OPENAXIOM,"over off") + || strstr(pTM_OPENAXIOM,"over n") + || strstr(pTM_OPENAXIOM,"over 0")) + option_use_over=0; + if (strstr(pTM_OPENAXIOM,"over on") + || strstr(pTM_OPENAXIOM,"over y") + || strstr(pTM_OPENAXIOM,"over 1")) + option_use_over=1; + if (strstr(pTM_OPENAXIOM,"cdot off") + || strstr(pTM_OPENAXIOM,"cdot n") + || strstr(pTM_OPENAXIOM,"cdot 0")) + option_use_cdot=0; + if (strstr(pTM_OPENAXIOM,"cdot on") + || strstr(pTM_OPENAXIOM,"cdot y") + || strstr(pTM_OPENAXIOM,"cdot 1")) + option_use_cdot=1; + if (strstr(pTM_OPENAXIOM,"space off") + || strstr(pTM_OPENAXIOM,"space n") + || strstr(pTM_OPENAXIOM,"space 0")) + option_big_space=0; + if (strstr(pTM_OPENAXIOM,"space on") + || strstr(pTM_OPENAXIOM,"space y") + || strstr(pTM_OPENAXIOM,"space 1")) + option_big_space=1; + if (strstr(pTM_OPENAXIOM,"big( off") + || strstr(pTM_OPENAXIOM,"big( n") + || strstr(pTM_OPENAXIOM,"big( 0")) + option_big_paren=0; + if (strstr(pTM_OPENAXIOM,"big( on") + || strstr(pTM_OPENAXIOM,"big( y") + || strstr(pTM_OPENAXIOM,"big( 1")) + option_big_paren=1; + if (pOption=strstr(pTM_OPENAXIOM,"width ")) { + sscanf(pOption+strlen("width "),"%f",&w); + maxLineWidth=trunc(1000.0*w); + }; + }; + }; +} + +/* This is the OpenAxiom Reader thread. It runs asynchronously and + * in parallel with the main thread. It reads output from OpenAxiom + * and after some selection and conversion, it is sent on to + * TeXmacs. */ + +unsigned __stdcall StdOutReadThread ( void* pArguments ) +{ + int nExitCode = STILL_ACTIVE; + + fputs("\2verbatim:",stdout); /* ---> to TeXmacs */ + + GetExitCodeProcess ( hProcess, (unsigned long*) &nExitCode ); + + while ( nExitCode == STILL_ACTIVE ) { + #ifdef DEBUG_OUT + fprintf ( stderr, " - Stdout read loop\n" ); + fflush ( stderr ); + #endif /* DEBUG_OUT */ + nRead = _read ( fdStdOutPipe[READ_HANDLE], &szBuffer[nBuffer], + OUT_BUFF_SIZE-nBuffer ); /* Read <--- from OpenAxiom */ + + szBuffer[nBuffer+nRead]='\0'; + #ifdef DEBUG_OUT + fprintf ( stderr, "After _read on stdoutpipe (%d bytes read)\n%s\n", + nRead, &szBuffer[nBuffer] ); fflush ( stderr ); + #endif /* DEBUG_OUT */ + while (nRead>0) { /* fill buffer until we see OpenAxiom prompt */ + if ( strncmp(&szBuffer[nBuffer],"-> ",3)==0 ) { /* done */ + HandleOutput(szBuffer, nBuffer); /* send output ---> to TeXmacs */ + nRead = nRead-3; /* keep the left overs */ + if (nRead>0) strncpy(szBuffer,&szBuffer[nBuffer+3],nRead); + nBuffer = 0; szBuffer[nRead]='\0'; + #ifdef DEBUG_OUT + fprintf(stderr, "Leftovers\n%s\n",&szBuffer); + fflush(stderr); + #endif /* DEBUG_OUT */ + } else { + nBuffer++; + nRead--; + }; + }; + GetExitCodeProcess ( hProcess, (unsigned long*) &nExitCode ); + }; + + fputs("\2latex:\\red The end\\black\5\5",stdout); /* The ends --> TeXmacs */ + fflush(stdout); + _endthreadex(0); +} + +/* This routine parses all OpenAxiom output between -> prompts */ + +HandleOutput(char Buffer[], int n) /* sends output ---> to TeXmacs */ +{ + int mmode, i, j; + + #ifdef DEBUG_OUT + fprintf(stderr, "HandleOutput IgnorePrompts:%d\n%s\n",IgnorePrompts, + Buffer); + fflush(stderr); + #endif /* DEBUG_OUT */ + if (IgnorePrompts) --IgnorePrompts; /* counting down */ + else { /* its a good packet */ + while (n>0 && Buffer[n-1]=='\n') n--; + Buffer[n]='\0'; /* mark the real end */ + mmode = 0; j=0; + while (Buffer[j]=='\n') j++; /* find the real start */ + for (i=j;i to TeXmacs */ + mmode = i+3; /* start of LaTeX */ + fputs("\2latex:$$",stdout);/* tell ---> TeXmacs */ + } else { /* we were in mathmode */ + HandleLatex(&Buffer[mmode]); /* make some adjustments */ + fputs("$$\5",stdout); /* Say "that's all" ---> to TeXmacs */ + mmode = -1; j=i+3; /* aftermath */ + } + } else { /* this is not a marker */ + if (mmode<=0) { /* if not in mathmode */ + if (strncmp(&Buffer[i],"Type:",5)==0) { /* look for OpenAxiom Type */ + int k; + k=i-1; while (Buffer[k]==' ') k--; + Buffer[k]='\0'; /* mark end of previous */ + fputs(&Buffer[j],stdout); /* send the plain text -> to TeXmacs */ + fprintf(stdout,"\2latex:\\openaxiomtype{%s}\5", + &Buffer[i+6]); + i=n; j=n; /* and we are done */ + } + } + } + }; + if (j to TeXmacs */ + }; + /* ask for some more work from ---> TeXmacs */ + fputs("\2channel:prompt\5\2latex:\\red$\\rightarrow$\\ \5\5",stdout); + fflush(stdout); /* Say "give me a prompt" ---> to TeXmacs */ + fputs("\2verbatim:",stdout); /* maybe plain text next ---> to TeXmacs */ + } +} + +HandleLatex(char buf[]) { /* fixup Latex coding */ + + char *ptr1, *ptr2, *ptr3; + char label[64]; + +/* /n -> blank */ + while (ptr1=strchr(buf,'\n')) { *ptr1=' '; }; + +if (option_texbreak) { /* break long TeX lines */ + +/* prepare OpenAxiom output in buf for call to texbreak */ + +/* remove the label and save it for later */ + label[0]='\0'; + while (ptr1=strstr(buf,"\\leqno(")) { + if ((ptr2=strchr(ptr1,')')) && (ptr2-ptr1<64)) { + ptr2++; + strncpy(label,ptr1,ptr2-ptr1); label[ptr2-ptr1]='\0'; + strcpy(ptr1,ptr2); + } + }; + + texbreak(buf); /* output is in global external called bufout */ + strcat(bufout,"\\hfill \\leqno "); + strcat(bufout,&label[6]); /* put label back */ +} else { + strcpy(bufout,buf); +}; + +/* do some LaTex conversions for TeXmacs */ + +/* \root { a } \of { b } ---> \sqrt[ a ] { b } */ +/* ptr1^ ptr2^ ^ptr3 ^ ^ ptr1^ ^ */ + + while (ptr1=strstr(bufout,"\\root")) { + ptr2=ptr1+5; while (*ptr2==' ') ptr2++; + if ((*ptr2=='{') && (ptr3=strstr(ptr2,"}"))) { + #ifdef DEBUG_OUT + fprintf(stderr, "ptr1: %s\nptr2: %s\nptr3: %s\n",ptr1,ptr2,ptr3); + fflush(stderr); + #endif /* DEBUG_OUT */ + strncpy(ptr1,"\\sqrt[",6); ptr1=ptr1+6; + strncpy(ptr1,ptr2+1,ptr3-ptr2-1); ptr1=ptr1+(ptr3-ptr2-1); + strncpy(ptr1,"]",1); ptr1++; + ptr3++; while (*ptr3==' ') ptr3++; + #ifdef DEBUG_OUT + fprintf(stderr, "ptr1: %s\nptr2: %s\nptr3: %s\n",ptr1,ptr2,ptr3); + fflush(stderr); + #endif /* DEBUG_OUT */ + if (strncmp(ptr3,"\\of",3)==0) { + ptr3+=3; while (*ptr3==' ') ptr3++; + if (*ptr3=='{') { + strcpy(ptr1,ptr3); + } else { + error("No \\of { \n"); + } + } else { + error("No \\of \n"); + } + } else { + error("No \\root { } \n"); + } + }; + + if (!option_big_space) { /* use smaller spaces \ ---> \, */ + while (ptr1=strstr(bufout,"\\ ")) { + strncpy(ptr1,"\\,",2); /* use thin spaces */ + }; + }; + +/* other possible conversions */ + + if (!option_use_cdot) { + while (ptr1=strstr(bufout,"\\cdot")) { + strncpy(ptr1,"\\ ",2); + strcpy(ptr1+2,ptr1+5); + }; + }; + + if (!option_big_paren) { + while (ptr1=strstr(bufout,"\\left(")) { + strncpy(ptr1,"(",1); + strcpy(ptr1+1,ptr1+6); + }; + while (ptr1=strstr(bufout,"\\right)")) { + strncpy(ptr1,")",1); + strcpy(ptr1+1,ptr1+7); + }; + }; + if (!option_use_over) { + while (ptr1=strstr(bufout,"\\over")) { + strncpy(ptr1,"/",1); + strcpy(ptr1+1,ptr1+5); + }; + }; + #ifdef DEBUG_OUT + fprintf(stderr, "HandleLatex:\n%s\n",bufout); + fflush(stderr); + #endif /* DEBUG_OUT */ + fputs(bufout,stdout); /* send the LaTeX code ---> to TeXmacs */ +} + +unsigned __stdcall StdErrReadThread ( void* pArguments ) +{ + int nExitCode = STILL_ACTIVE; + int nRead; + char szBuffer[OUT_BUFF_SIZE]; + + GetExitCodeProcess ( hProcess, (unsigned long*) &nExitCode ); + + while ( nExitCode == STILL_ACTIVE ) { + #ifdef DEBUG_OUT + fprintf ( stderr, " - Stderr read loop\n" ); fflush ( stderr ); + #endif /* DEBUG_OUT */ + nRead = _read ( fdStdErrPipe[READ_HANDLE], szBuffer, OUT_BUFF_SIZE ); + #ifdef DEBUG_OUT + fprintf ( stderr, "After _read on stderrpipe (%d bytes read)\n", + nRead ); + fflush ( stderr ); + #endif /* DEBUG_OUT */ + if ( nRead ) { /* just pass the message on through to TeXmacs */ + fwrite(szBuffer, 1, nRead, stderr); + } + GetExitCodeProcess ( hProcess, (unsigned long*) &nExitCode ); + } + _endthreadex(0); +} + +void pipe_write(int fdPipe, char Buffer[]) +{ + _write(fdPipe, Buffer, strlen(Buffer) ); +} + +/* process texmacs options */ + +process_options(char line[]) { + char *optargs[2]; + + optargs[1]=line; + if (*(optargs[1])!='\n') { + parse_options(2,optargs); + } else { /* display current options */ + show_options(); + }; + /* ask for some more work from ---> TeXmacs */ + fputs("\2channel:prompt\5\2latex:\\red$\\rightarrow$\\ \5\5",stdout); + fflush(stdout); /* Say "give me a prompt" ---> to TeXmacs */ + fputs("\2verbatim:",stdout); /* maybe plain text next ---> to TeXmacs */ + + #ifdef DEBUG_OUT + fprintf ( stderr, + "TM_OPENAXIOM=texbreak:%d,use_over:%d,use_cdot:%d,big_space:%d,big_paren:%d,\n", + option_texbreak, option_use_over, option_use_cdot, + option_big_space, option_big_paren ); + fprintf ( stderr, + " maxLineWidth:%d\n", maxLineWidth ); + fflush ( stderr ); + #endif /* DEBUG_OUT */ +} + +show_options() { + fprintf(stdout, +"--------------------------- The texmacs Option ----------------------------\n\ +\n\ + Description: options for display of OPENAXIOM output in TeXmacs\n\ +\n\ + )set output texmacs is used to control the TeXmacs-OPENAXIOM interface\n\ +The default values are controlled by environment variable TM_OPENAXIOM\n\ +and may be overriden by command line options.\n\ +\n\ +Syntax: )set output texmacs \n\ + where arg can be one or more of\n\ + break | line-break algorithm\n\ + over | convert 2-d \\over to 1-d /\n\ + cdot | convert \\cdot to \\ (space)\n\ + space | convert \\ (space) to \\,\n\ + big( | convert \\left( \\right to ( )\n\ + width <9.99> line width in inches\n\ +\n\ + may be on, yes, 1\n\ + may be off, no , 0\n\ +\n\ +The current settings are:\n\ + break %d, over %d, cdot %d, space %d, big( %d, width %2.3f\n", + option_texbreak, option_use_over, option_use_cdot, + option_big_space, option_big_paren, maxLineWidth/1000.0 ); + +}; + +int main(int nargs, char *args[]) +{ + HANDLE hStdOutReadThread; + int fdStdOut, fdStdIn; + unsigned threadIDOut; + HANDLE hStdErrReadThread; + int fdStdErr; + unsigned threadIDErr; + int i; + char line[INP_BUFF_SIZE]; + + parse_options(nargs,args); + + #ifdef DEBUG_OUT + fprintf ( stderr, "CREATE PROCESS: %s\n", OPENAXIOM_cmd ); + fprintf ( stderr, "Setting env var: %s\n", ENV_OPENAXIOM ); + fprintf ( stderr, + "TM_OPENAXIOM=texbreak:%d,use_over:%d,use_cdot:%d,big_space:%d,big_paren:%d,\n", + option_texbreak, option_use_over, option_use_cdot, + option_big_space, option_big_paren ); + fprintf ( stderr, + " maxLineWidth:%d\n", maxLineWidth ); + fflush ( stderr ); + #endif /* DEBUG_OUT */ + + if ( -1 == _setmode( _fileno( stdin ), _O_BINARY ) ) { + perror ( "machinfo: Cannot set stdin BINARY mode" ); exit(1); + }; + if ( -1 == _setmode( _fileno( stdout ), _O_BINARY ) ) { + perror ( "machinfo: Cannot set stdout BINARY mode" ); exit(1); + }; + if ( -1 == _setmode( _fileno( stderr ), _O_BINARY ) ) { + perror ( "machinfo: Cannot set stderr BINARY mode" ); exit(1); + }; + + /* Make pipes to be passed to the spawned process as stdin/out/err */ + if ( _pipe ( fdStdOutPipe, 512, O_BINARY | O_NOINHERIT ) == -1 ) return 1; + if ( _pipe ( fdStdInPipe, 512, O_BINARY | O_NOINHERIT ) == -1 ) return 1; + if ( _pipe ( fdStdErrPipe, 512, O_BINARY | O_NOINHERIT ) == -1 ) return 1; + + /* Duplicate and save original stdin/out/err handles */ + fdStdOut = _dup ( _fileno(stdout) ); + fdStdIn = _dup ( _fileno(stdin) ); + fdStdErr = _dup ( _fileno(stderr) ); + + /* Duplicate write end of new pipes to current stdout/err handles, + * read to stdin */ + if ( _dup2 ( fdStdOutPipe[WRITE_HANDLE], _fileno(stdout) ) != 0 ) return 2; + if ( _dup2 ( fdStdInPipe[READ_HANDLE], _fileno(stdin) ) != 0 ) return 2; + if ( _dup2 ( fdStdErrPipe[WRITE_HANDLE], _fileno(stderr) ) != 0 ) return 2; + /* Close the duplicated handles to the new pipes */ + close ( fdStdOutPipe[WRITE_HANDLE] ); + close ( fdStdInPipe[READ_HANDLE] ); + close ( fdStdErrPipe[WRITE_HANDLE] ); + + putenv ( ENV_OPENAXIOM ); + + /* Zero startup and process info structures, take care of Windows + * startup info structure future proofing. */ + ZeroMemory( &si, sizeof(si) ); + si.cb = sizeof(si); + ZeroMemory( &pi, sizeof(pi) ); + + /* Start the child process. */ + if ( !CreateProcess( + NULL, /* No module name (use command line). */ + OPENAXIOM_cmd, /* Command line. */ + NULL, /* Process handle not inheritable. */ + NULL, /* Thread handle not inheritable. */ + TRUE, /* Allow handle inheritance. */ + 0, /* No creation flags. */ + NULL, /* Use parent's environment block. */ + NULL, /* Use parent's starting directory. */ + &si, /* Pointer to STARTUPINFO structure.*/ + &pi ) /* Pointer to PROCESS_INFORMATION structure. */ ) { + fprintf(stderr, "CreateProcess failed: %s\n", args[1]); + fflush(stderr); + return -1; + } + hProcess = pi.hProcess; + + /* Now that the process is launched, + * replace the original stdin/out/err handles */ + if ( _dup2 ( fdStdOut, _fileno ( stdout ) ) != 0 ) return 3; + if ( _dup2 ( fdStdIn, _fileno ( stdin ) ) != 0 ) return 3; + if ( _dup2 ( fdStdErr, _fileno ( stderr ) ) != 0 ) return 3; + + /* Close duplicates */ + close(fdStdOut); + close(fdStdIn); + close(fdStdErr); + + /* The child process will become the OpenAxiom read filter and + * we will be the OpenAxiom write filter. */ + + /* Create the OpenAxiom stderr listening thread. (Doesn't do much.) */ + hStdErrReadThread = (HANDLE)_beginthreadex( NULL, 0, &StdErrReadThread, + NULL, 0, &threadIDErr ); + if ( 0 == hStdErrReadThread ) return 5; + + /* * * * * * * * * */ + /* start talking! */ + /* * * * * * * * * */ + + IgnorePrompts = 5; /* Tell the OpenAxiom Reader to ignore first 5 prompts */ + /* then create the OpenAxiom stdout Reader thread.*/ + hStdOutReadThread = (HANDLE)_beginthreadex( NULL, 0, &StdOutReadThread, + NULL, 0, &threadIDOut ); + if ( 0 == hStdOutReadThread ) return 5; + /* start force-feeding ---> to OpenAxiom */ + pipe_write(fdStdInPipe[WRITE_HANDLE],")set message prompt plain\n" ); /* 1 */ + pipe_write(fdStdInPipe[WRITE_HANDLE],")set messages autoload off\n" );/* 2 */ + pipe_write(fdStdInPipe[WRITE_HANDLE],")set quit unprotected\n" ); /* 3 */ + pipe_write(fdStdInPipe[WRITE_HANDLE],")set output tex on\n" ); /* 4 */ + pipe_write(fdStdInPipe[WRITE_HANDLE],")set output algebra off\n" ); /* 5 */ + while (fgets(line,INP_BUFF_SIZE,stdin)!=NULL) { /* wait <--- for TeXmacs */ + #ifdef DEBUG_OUT + fprintf ( stderr, "Input:\n%s", line ); + #endif /* DEBUG_OUT */ + if (strncmp(line,")set output texmacs", + strlen(")set output texmacs"))==0) { /* process texmacs options */ + process_options(&line[strlen(")set output texmacs")]); + } else { + pipe_write(fdStdInPipe[WRITE_HANDLE], line ); /* Start ---> OpenAxiom */ + } + }; + if (nBuffer) HandleOutput(szBuffer,nBuffer); /* anything leftover? */ + pipe_write(fdStdInPipe[WRITE_HANDLE], ")quit\n" ); /* stop work */ + + WaitForSingleObject ( hStdErrReadThread, INFINITE ); + WaitForSingleObject ( hStdOutReadThread, INFINITE ); + + /* Wait until child process exits to block the terminal. */ + WaitForSingleObject( pi.hProcess, INFINITE ); + + /* As we are using gebinthreadex/endthreadex, + * we must close the thread handles. */ + CloseHandle ( hStdOutReadThread ); + CloseHandle ( hStdErrReadThread ); + + return 0; +} diff --git a/contrib/texmacs/src/useproto.h b/contrib/texmacs/src/useproto.h new file mode 100755 index 00000000..ed7f76f8 --- /dev/null +++ b/contrib/texmacs/src/useproto.h @@ -0,0 +1,43 @@ + +/* released under the Modified BSD License */ + +#ifndef _USEPROTO_H_ +#define _USEPROTO_H_ 1 + +#if defined(SGIplatform)||defined(LINUXplatform)||defined(HPplatform) ||defined(RIOSplatform) ||defined(RIOS4platform) || defined(SUN4OS5platform) +#ifdef _NO_PROTO +#undef _NO_PROTO +#endif +#ifndef NeedFunctionPrototypes +#define NeedFunctionPrototypes 1 +#endif +#endif /*SGIplatform ... */ + + +#if defined(ALPHAplatform) +#ifdef __STDC__ + +#ifdef _NO_PROTO +#undef _NO_PROTO +#endif +#ifndef NeedFunctionPrototypes +#define NeedFunctionPrototypes 1 +#endif + +#else + +#define _NO_PROTO +#undef NeedFunctionPrototypes + +#endif +#endif /* ALPHA */ + + + +#ifdef SUNplatform +#define _NO_PROTO +#define const +#endif + +#endif /* _USEPROTO_H_ */ + -- cgit v1.2.3