diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rwxr-xr-x | configure | 18 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | configure.ac.pamphlet | 2 | ||||
-rwxr-xr-x | contrib/texmacs/Makefile | 18 | ||||
-rwxr-xr-x | contrib/texmacs/README.txt | 53 | ||||
-rwxr-xr-x | contrib/texmacs/packages/session/openaxiom.ts | 42 | ||||
-rwxr-xr-x | contrib/texmacs/progs/init-openaxiom.scm | 23 | ||||
-rwxr-xr-x | contrib/texmacs/progs/openaxiom-input.scm | 53 | ||||
-rwxr-xr-x | contrib/texmacs/src/texbreaker.c | 2007 | ||||
-rwxr-xr-x | contrib/texmacs/src/tm_openaxiom.c | 603 | ||||
-rwxr-xr-x | contrib/texmacs/src/useproto.h | 43 |
12 files changed, 2857 insertions, 11 deletions
@@ -1,3 +1,7 @@ +2009-07-04 Alfredo Portes <doyenatccny@gmail.com> + + * contrib/texmacs: New. + 2009-07-02 Gabriel Dos Reis <gdr@cse.tamu.edu> * configure.ac.pamphlet: Support --enable-profiling. @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.63 for OpenAxiom 1.4.0-2009-07-03. +# Generated by GNU Autoconf 2.63 for OpenAxiom 1.4.0-2009-07-04. # # Report bugs to <open-axiom-bugs@lists.sf.net>. # @@ -745,8 +745,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='OpenAxiom' PACKAGE_TARNAME='openaxiom' -PACKAGE_VERSION='1.4.0-2009-07-03' -PACKAGE_STRING='OpenAxiom 1.4.0-2009-07-03' +PACKAGE_VERSION='1.4.0-2009-07-04' +PACKAGE_STRING='OpenAxiom 1.4.0-2009-07-04' PACKAGE_BUGREPORT='open-axiom-bugs@lists.sf.net' ac_unique_file="src/Makefile.pamphlet" @@ -1502,7 +1502,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures OpenAxiom 1.4.0-2009-07-03 to adapt to many kinds of systems. +\`configure' configures OpenAxiom 1.4.0-2009-07-04 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1572,7 +1572,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of OpenAxiom 1.4.0-2009-07-03:";; + short | recursive ) echo "Configuration of OpenAxiom 1.4.0-2009-07-04:";; esac cat <<\_ACEOF @@ -1675,7 +1675,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -OpenAxiom configure 1.4.0-2009-07-03 +OpenAxiom configure 1.4.0-2009-07-04 generated by GNU Autoconf 2.63 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1689,7 +1689,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by OpenAxiom $as_me 1.4.0-2009-07-03, which was +It was created by OpenAxiom $as_me 1.4.0-2009-07-04, which was generated by GNU Autoconf 2.63. Invocation command line was $ $0 $@ @@ -17704,7 +17704,7 @@ exec 6>&1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by OpenAxiom $as_me 1.4.0-2009-07-03, which was +This file was extended by OpenAxiom $as_me 1.4.0-2009-07-04, which was generated by GNU Autoconf 2.63. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -17767,7 +17767,7 @@ Report bugs to <bug-autoconf@gnu.org>." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ -OpenAxiom config.status 1.4.0-2009-07-03 +OpenAxiom config.status 1.4.0-2009-07-04 configured by $0, generated by GNU Autoconf 2.63, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" diff --git a/configure.ac b/configure.ac index 186a4dcd..4bd9bec5 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ sinclude(config/open-axiom.m4) sinclude(config/aclocal.m4) -AC_INIT([OpenAxiom], [1.4.0-2009-07-03], +AC_INIT([OpenAxiom], [1.4.0-2009-07-04], [open-axiom-bugs@lists.sf.net]) AC_CONFIG_AUX_DIR(config) diff --git a/configure.ac.pamphlet b/configure.ac.pamphlet index d7945d12..7785a67a 100644 --- a/configure.ac.pamphlet +++ b/configure.ac.pamphlet @@ -1141,7 +1141,7 @@ information: <<Autoconf init>>= sinclude(config/open-axiom.m4) sinclude(config/aclocal.m4) -AC_INIT([OpenAxiom], [1.4.0-2009-07-03], +AC_INIT([OpenAxiom], [1.4.0-2009-07-04], [open-axiom-bugs@lists.sf.net]) @ 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 <on>|<off> line-break algorithm
+ over <on>|<off> convert 2-d \over to 1-d /
+ cdot <on>|<off> convert \cdot to \ (space)
+ space <on>|<off> convert \ (space) to \,
+ big( <on>|<off> 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 @@ +<TeXmacs|WinTeXmacs-1.0.4.4>
+
+<style|source>
+
+<\body>
+ <active*|<\src-title>
+ <src-package|openaxiom|1.0>
+
+ <\src-purpose>
+ Markup for OpenAxiom sessions.
+ </src-purpose>
+
+ <src-copyright|2002--2004|Joris van der Hoeven>
+
+ <\src-license>
+ This <TeXmacs> style package falls under the <hlink|GNU general public
+ license|$TEXMACS_PATH/LICENSE> 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.
+ </src-license>
+ </src-title>>
+
+ <assign|openaxiom-input|<macro|prompt|body|<style-with|src-compact|none|<generic-input|<resize|<arg|prompt>|||1.75fn||>|<arg|body>>>>>
+
+ <assign|openaxiom-output|<macro|body|<style-with|src-compact|none|<surround|<vspace*|1fn>|<vspace|1fn>|<with|par-left|<plus|<value|par-left>|1.75fn>|<generic-output*|<arg|body>>>>>>>
+
+ \;
+
+ <assign|leqno|<macro|<htab|5mm>>>
+
+ <assign|openaxiomtype|<macro|type|<vspace*|0.5fn><next-line><hflush><with|color|brown|Type:
+ <arg|type>>>>
+
+ \;
+</body>
+
+<\initial>
+ <\collection>
+ <associate|preamble|true>
+ </collection>
+</initial>
\ 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 <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define MATHBUFLEN 8*8192 +#define MAXMATHTOKEN 80 +#define MAXCHARSINLINE 60 +#define FATDELIMMULT 2 + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define TRUE 1 +#define FALSE 0 + +#define STRCHREQ(str,char) (str[0] == char) + +/* + * Type declarations. + */ + +enum nodeTypes { + N_NODE, + N_TEXT, + N_ARRAY +}; + +typedef struct listNodeStruct { + struct listNodeStruct *nextListNode; + struct listNodeStruct *prevListNode; + enum nodeTypes nodeType; + long width; + long realWidth; + union { + char *text; + struct listNodeStruct *node; + struct arrayNodeStruct *array; + } data; +} listNode; + +typedef struct arrayNodeStruct { + int cols; + listNode *argsNode; + listNode *entries; /* linked list of nodes, each pointing to a + * row */ +} arrayNode; + + +/* + * Global Variables. + */ + +char line[1024]; +char blanks[] = " "; +char lastPrinted = '\0'; +int indent = 0; +char mathBuffer[MATHBUFLEN], mathToken[MAXMATHTOKEN]; +char bufout[2*MATHBUFLEN]; +int lineLen, mathBufferLen, mathBufferPtr, mathTokenLen; +listNode *mathList; +int charsOut, fatDelimiter; +int maxLineWidth = 4500; /* 4.5 inches * 1000 */ +int maxLineSlop = 0; /* 0.0 inches * 1000 */ +int charTable[256]; +int avgCharWidth; +int spaceWidths[5], extraOverWidth; +int arrayDepth = 0, arrayMaxDepth = 3; +int charMultNum, charMultDenom; +int sinWidth, cosWidth, tanWidth, erfWidth; +long outLineNum = 0L; + +/* + * Function Prototypes. + */ +#ifndef _NO_PROTO +void arrayTooDeep(); +int breakFracProd(listNode *, long, char *, char *, int); +int breakFunction(listNode *, long); +int breakList(listNode *, long); +int breakMathList(listNode *, long); +int breakNumber(listNode *, long); +int breakPMEB(listNode *, long); +int breakParen(listNode *, long); +int bufferMathLines(); +void buildMathList(); +int charWidth(char); +void computeNodeWidth(listNode *); +long computeWidth(listNode *); +void displaySplitMsg(char *, int); +void error(char *, char *); +void freeMathList(listNode *); +void getOptions(int, char **); +void initCharTable(); +listNode *insertStringAfter(char *, listNode *); +listNode *insertStringAtBack(char *, listNode *); +listNode *insertStringAtFront(char *, listNode *); +int newLineIfNecessary(int); +listNode *newListNode(enum nodeTypes); +int nextMathToken(); +int printChar(char); +int printMathList(listNode *, int); +int printString(char *); +void putcBuf(char, char []); +void putsBuf(char [], char []); +void resetCharMults(); +listNode *string2NodeList(char *, listNode *); +void ttCharMults(); +#else +void arrayTooDeep(); +int breakFracProd(); +int breakFunction(); +int breakList(); +int breakMathList(); +int breakNumber(); +int breakPMEB(); +int breakParen(); +int bufferMathLines(); +void buildMathList(); +int charWidth(); +void computeNodeWidth(); +long computeWidth(); +void displaySplitMsg(); +void error(); +void freeMathList(); +void getOptions(); +void initCharTable(); +listNode *insertStringAfter(); +listNode *insertStringAtBack(); +listNode *insertStringAtFront(); +int newLineIfNecessary(); +listNode *newListNode(); +int nextMathToken(); +int printChar(); +int printMathList(); +int printString(); +void putsBuf(); +void putcBuf(); +void resetCharMults(); +listNode *string2NodeList(); +void ttCharMults(); +#endif + + +/* + * Function Definitions. + */ + +int +#ifndef _NO_PROTO +texbreak(char bufinp[]) +#else +texbreak(bufinp) +char bufinp[]; +#endif +{ + initCharTable(); + strcpy(bufout,""); + mathBufferLen=strlen(bufinp); + if (mathBufferLen > MATHBUFLEN) { + fprintf(stderr, "mathBuffer too small. Need: %d\n", mathBufferLen); + return 0; + }; + mathBufferPtr = 0; + strcpy(mathBuffer,bufinp); +/* fprintf(stderr, "bufinp: %s\n", mathBuffer); */ + fatDelimiter = 1; + arrayDepth = 0; + mathList = newListNode(N_NODE); + buildMathList(mathList); + resetCharMults(); + computeWidth(mathList); +/* if (mathList->width > maxLineWidth) + fprintf(stderr, "Width = %ld units, Output line = %ld.\n", mathList->width, outLineNum); */ + breakMathList(mathList, maxLineWidth); + charsOut = 0; + printMathList(mathList->data.node, TRUE); + freeMathList(mathList); + return 1; +} + +/* + * breakFracProd: + * + * Arguments: + * + * n : the starting node at which we are to try to break + * + * lineWidth : the maximum width of a line + * + * match : either "\\over" or "\\ " + * + * label : either "quotient" or "product" + * + * paren : add parentheses (TRUE or FALSE) + * + * + * Returns: TRUE or FALSE, depending on whether the expression was broken + * + * + * Function: Tries to break up a quotient t1 \over t2 or a product t1 \ t2 by + * splitting and parenthesizing the numerator and/or the denominator. + */ + +int +#ifndef _NO_PROTO +breakFracProd(listNode * n, long lineWidth, char *match, char *label, int paren) +#else +breakFracProd(n,lineWidth,match,label,paren) +listNode * n; +long lineWidth; +char *match; +char *label; +int paren; +#endif +{ + + listNode *rootNode, *lastNode, *t1, *t2; + int ok; + long workWidth1, workWidth2; + + if (n->nodeType != N_NODE) + return FALSE; + + rootNode = n; + + ok = FALSE; + t1 = n = rootNode->data.node; + n = n->nextListNode; + if (n) { + if ((n->nodeType == N_TEXT) && + (0 == strcmp(n->data.text, match))) { + t2 = n->nextListNode; + if (t2 && (NULL == t2->nextListNode)) + ok = TRUE; + } + } + + displaySplitMsg(label, ok); + + if (ok) { + + /* for products, determine rough widths for the two factors */ + + if (0 == strcmp(label, "product")) { + computeNodeWidth(t1); + computeNodeWidth(t2); + workWidth1 = lineWidth - charWidth(' '); + + if (workWidth1 / 2 > t1->realWidth) { + workWidth2 = workWidth1 - t1->realWidth; + workWidth1 = t1->realWidth; + } + else if (workWidth1 / 2 > t2->realWidth) { + workWidth1 = workWidth1 - t2->realWidth; + workWidth2 = t2->realWidth; + } + else + workWidth1 = workWidth2 = workWidth1 / 2; + + if (paren) { + if (t1->realWidth > workWidth1) + workWidth1 = workWidth1 - 4 * FATDELIMMULT * charWidth('('); + if (t2->realWidth > workWidth2) + workWidth2 = workWidth2 - 4 * FATDELIMMULT * charWidth('('); + } + } + else /* "quotient" */ + workWidth1 = workWidth2 = + lineWidth - paren * 4 * FATDELIMMULT * charWidth('('); + + if ((t1->nodeType == N_NODE) && (t1->realWidth > workWidth1)) { + t1->width = t1->realWidth; + + if (breakMathList(t1, workWidth1) && paren) { + /* insert the \left( */ + lastNode = insertStringAtFront("\\left(", t1); + + while (lastNode->nextListNode) + lastNode = lastNode->nextListNode; + + /* insert the \right) */ + insertStringAtBack("\\right)", lastNode); + } + } + + if ((t2->nodeType == N_NODE) && (t2->realWidth > workWidth2)) { + t2->width = t2->realWidth; + + if (breakMathList(t2, workWidth2) && paren) { + /* insert the \left( */ + lastNode = insertStringAtFront("\\left(", t2); + + while (lastNode->nextListNode) + lastNode = lastNode->nextListNode; + + /* insert the \right) */ + insertStringAtBack("\\right)", lastNode); + } + } + + return TRUE; + } + return FALSE; +} + + +int +#ifndef _NO_PROTO +breakFunction(listNode * n, long lineWidth) +#else +breakFunction(n,lineWidth) +listNode * n; +long lineWidth; +#endif +{ + listNode *rootNode, *tmpNode, *lastNode, *t1, *t2, *t3; + int ok = FALSE; + long workWidth, maxWidth = 0; + + if (n->nodeType != N_NODE) + return FALSE; + + n = n->data.node; + + if (n->nodeType == N_NODE) + return FALSE; + + if ((0 == strcmp(n->data.text, "\\sin")) || + (0 == strcmp(n->data.text, "\\cos")) || + (0 == strcmp(n->data.text, "\\tan")) || + (0 == strcmp(n->data.text, "\\log")) || + (0 == strcmp(n->data.text, "\\arctan")) || + (0 == strcmp(n->data.text, "\\erf"))) { + computeNodeWidth(n); + ok = TRUE; + } + + displaySplitMsg("function", ok); + + if (ok) { + t2 = newListNode(N_NODE); + t2->data.node = n->nextListNode; + t2->prevListNode = n; + n->nextListNode = t2; + ok = breakMathList(t2, lineWidth - n->realWidth); + } + + return ok; +} + +/* + * breakList: + * + * Arguments: + * + * n : the starting node at which we are to try to break + * + * lineWidth : the maximum width of a line + * + * + * Returns: TRUE or FALSE, depending on whether the expression was broken + * + * + * Function: Tries to split an expression that is bracketed by \left[ and + * \right] (or \left\{ and \right\} and contains at least one comma. + */ + +int +#ifndef _NO_PROTO +breakList(listNode * n, long lineWidth) +#else +breakList(n,lineWidth) +listNode * n; +long lineWidth; +#endif +{ + listNode *rootNode, *tmpNode, *lastNode, *t1, *t2, *t3; + int ok, comma; + long workWidth, maxWidth = 0; + + if (n->nodeType != N_NODE) + return FALSE; + + rootNode = n; + + t1 = n = rootNode->data.node; + comma = ok = FALSE; + + if ((t1->nodeType == N_TEXT) && + (0 == strcmp(t1->data.text, "\\left")) && + (t1->nextListNode) && + (t1->nextListNode->nodeType == N_TEXT) && + ((0 == strcmp(t1->nextListNode->data.text, "[")) || + (0 == strcmp(t1->nextListNode->data.text, "\\{")))) { + + t1 = t1->nextListNode->nextListNode; + + /* + * Check for a special case: sometimes the whole body of the list is + * a node. Flatten this, if possible. + */ + + if ((t1->nodeType == N_NODE) && + (t1->nextListNode->nodeType == N_TEXT) && + (0 == strcmp(t1->nextListNode->data.text, "\\right"))) { + tmpNode = t1->prevListNode; + t2 = t1->nextListNode; + t3 = t1->data.node; + tmpNode->nextListNode = t3; + t3->prevListNode = tmpNode; + while (t3->nextListNode) + t3 = t3->nextListNode; + t3->nextListNode = t2; + t2->prevListNode = t3; + free(t1); + t1 = tmpNode->nextListNode; + } + + while (t1->nextListNode && !ok) { + if ((t1->nodeType == N_TEXT) && + (0 == strcmp(t1->data.text, ","))) + comma = TRUE; + else if ((t1->nodeType == N_TEXT) && + (0 == strcmp(t1->data.text, "\\right")) && + (t1->nextListNode->nodeType == N_TEXT) && + ((0 == strcmp(t1->nextListNode->data.text, "]")) || + (0 == strcmp(t1->nextListNode->data.text, "\\}"))) && + (NULL == t1->nextListNode->nextListNode)) { + ok = comma; + tmpNode = t1->nextListNode; + } + t1 = t1->nextListNode; + } + } + + displaySplitMsg("list", ok); + + if (ok) { + if (arrayDepth >= arrayMaxDepth) { + arrayTooDeep(); + return FALSE; + } + + /* + * Create array environment + */ + + lastNode = insertStringAtFront("\\begin{array}{@{}l}\\displaystyle", rootNode); + arrayDepth++; + insertStringAtBack("\\end{array}", tmpNode); + + /* + * Now break at best place short of width. Start after the + * environment begins and after the \left( + */ + + n = lastNode->nextListNode->nextListNode->nextListNode; + + /* + * try to split the first expression if too big + */ + + tmpNode = n->nextListNode; + if (breakMathList(n, lineWidth)) { + workWidth = n->width; + n = tmpNode; + } + else + workWidth = n->width; + maxWidth = workWidth; + + while (n->nextListNode) { + if ((n->nodeType == N_TEXT) && + ((0 == strcmp(n->data.text, ",")) || + (0 == strcmp(n->data.text, "\\:"))) && + (workWidth + n->nextListNode->width > lineWidth)) { + maxWidth = max(maxWidth, workWidth); + n = insertStringAfter("\\right. \\\\ \\\\ \\displaystyle \\left.", n); + + /* + * try to split the next expression if too big + */ + + tmpNode = n->nextListNode; + if (breakMathList(n, lineWidth)) { + workWidth = n->width; + n = tmpNode; + } + else + workWidth = n->width; + } + else { + workWidth += n->nextListNode->width; + n = n->nextListNode; + } + } + + rootNode->width = rootNode->realWidth = + rootNode->data.node->width = rootNode->data.node->realWidth = + maxWidth; + arrayDepth--; + + return TRUE; + } + + return FALSE; +} + +/* + * breakNumber: + * + * Arguments: + * + * rootNode : the starting node at which we are to try to break + * + * lineWidth : the maximum width of a line + * + * + * Returns: TRUE or FALSE, depending on whether the expression was broken + * + * + * Function: Tries to break an expression that contains only digits and possibly + * a decimal point. + */ + +int +#ifndef _NO_PROTO +breakNumber(listNode * rootNode, long lineWidth) +#else +breakNumber(rootNode,lineWidth) +listNode * rootNode; +long lineWidth; +#endif +{ + int ok = TRUE; + listNode *n, *arrNode, *rowNode, *colNode; + long workWidth, maxWidth = 0; + + if (rootNode->nodeType != N_NODE) + return FALSE; + + n = rootNode->data.node; + while (n && ok) { + if ((n->nodeType == N_TEXT) && + (n->data.text[1] == '\0') && + (isdigit(n->data.text[0]) || ('.' == n->data.text[0]))) { + n = n->nextListNode; + } + else + ok = FALSE; + } + + displaySplitMsg("number", ok); + + if (ok) { + if (arrayDepth >= arrayMaxDepth) { + arrayTooDeep(); + return FALSE; + } + + arrayDepth++; + arrNode = newListNode(N_ARRAY); + arrNode->data.array->entries = rowNode = newListNode(N_NODE); + arrNode->data.array->cols = 1; + arrNode->data.array->argsNode = newListNode(N_NODE); + string2NodeList("{@{}l}", arrNode->data.array->argsNode); + + n = rootNode->data.node; + computeWidth(n); + maxWidth = workWidth = n->width; + rowNode->data.node = colNode = newListNode(N_NODE); + colNode->data.node = n; + n = n->nextListNode; + + while (n) { + computeWidth(n); + + if (workWidth + n->width > lineWidth) { + maxWidth = max(maxWidth, workWidth); + + /* + * time to start a new row + */ + + n->prevListNode->nextListNode = NULL; + n->prevListNode = NULL; + workWidth = n->width; + rowNode->nextListNode = newListNode(N_NODE); + rowNode = rowNode->nextListNode; + rowNode->data.node = colNode = newListNode(N_NODE); + colNode->data.node = n; + } + else + workWidth += (n->nextListNode) ? n->nextListNode->width :0 ; + + n = n->nextListNode; + } + + rootNode->data.node = arrNode; + rootNode->width = rootNode->realWidth = + arrNode->width = arrNode->realWidth = maxWidth; + arrayDepth--; + + return TRUE; + } + + return FALSE; +} + +void +#ifndef _NO_PROTO +resetWidths(listNode * n) +#else +resetWidths(n) +listNode * n; +#endif +{ + if (n) { + n->width = -1; + n->realWidth = 0; + if (n->nodeType == N_NODE) + resetWidths(n->data.node); + resetWidths(n->nextListNode); + } +} + +/* + * breakParen: + * + * Arguments: + * + * n : the starting node at which we are to try to break + * + * lineWidth : the maximum width of a line + * + * + * Returns: TRUE or FALSE, depending on whether the expression was broken + * + * + * Function: Tries to split an expression that is bracketed by left( and \right) + * (e.g., a factor). + */ + +int +#ifndef _NO_PROTO +breakParen(listNode * n, long lineWidth) +#else +breakParen(n,lineWidth) +listNode * n; +long lineWidth; +#endif +{ + listNode *tmpNode, *workNode; + int ok = FALSE; + + if (n->nodeType != N_NODE) + goto say_msg; + + tmpNode = n->data.node; + + /* + * check for \left + */ + + if ((tmpNode == NULL) || + (tmpNode->nodeType == N_NODE) || + (0 != strcmp(tmpNode->data.text, "\\left"))) + goto say_msg; + + /* + * check for '(' + */ + + tmpNode = tmpNode->nextListNode; + + if ((tmpNode == NULL) || + (tmpNode->nodeType == N_NODE) || + ('(' != tmpNode->data.text[0])) + goto say_msg; + + /* + * now move to the end + */ + + tmpNode = tmpNode->nextListNode; + + if (tmpNode != NULL) { + while (tmpNode->nextListNode) + tmpNode = tmpNode->nextListNode; + tmpNode = tmpNode->prevListNode; + } + + /* + * check for \right + */ + + if ((tmpNode == NULL) || + (tmpNode->nodeType == N_NODE) || + (0 != strcmp(tmpNode->data.text, "\\right"))) + goto say_msg; + + /* + * check for ')' + */ + + tmpNode = tmpNode->nextListNode; + + if ((tmpNode == NULL) || + (tmpNode->nodeType == N_NODE) || + (')' != tmpNode->data.text[0])) + goto say_msg; + + ok = TRUE; + +say_msg: + displaySplitMsg("parenthesized expression", ok); + + if (ok) { + + /* + * nest the whole inside if necessary, i.e., there is more than one + * term between the ( and the \right + */ + + if (tmpNode->prevListNode->prevListNode != + n->data.node->nextListNode->nextListNode) { + workNode = newListNode(N_NODE); + workNode->data.node = n->data.node->nextListNode->nextListNode; + n->data.node->nextListNode->nextListNode = workNode; + tmpNode->prevListNode->prevListNode->nextListNode = NULL; + tmpNode->prevListNode->prevListNode = workNode; + workNode->prevListNode = n->data.node->nextListNode; + workNode->nextListNode = tmpNode->prevListNode; + resetWidths(workNode); + computeWidth(workNode); + } + + return breakMathList(n->data.node->nextListNode->nextListNode, + lineWidth - 4 * FATDELIMMULT * charWidth('(')); + } + + return FALSE; +} + +/* + * breakPMEB: + * + * Arguments: + * + * n : the starting node at which we are to try to break + * + * lineWidth : the maximum width of a line + * + * + * Returns: TRUE or FALSE, depending on whether the expression was broken + * + * + * Function: Tries to split an expression that contains only +, -, = or \ as + * operators. The split occurs after the operator. + */ + +int +#ifndef _NO_PROTO +breakPMEB(listNode * n, long lineWidth) +#else +breakPMEB(n,lineWidth) +listNode * n; +long lineWidth; +#endif +{ + char *s; + listNode *rootNode, *tmpNode, *lastNode; + int ok, op; + long workWidth, maxWidth = 0; + + if (n->nodeType != N_NODE) + return FALSE; + + if (n->width <= lineWidth + maxLineSlop) /* allow a little slop here */ + return FALSE; + + rootNode = n; + tmpNode = n = n->data.node; + ok = TRUE; + op = FALSE; + + while (n && ok) { + if (n->nodeType == N_TEXT) { + s = n->data.text; + if (STRCHREQ(s, '+') || STRCHREQ(s, '-') || STRCHREQ(s, '=') || + (0 == strcmp(s, "\\ "))) + op = TRUE; + else if ((0 == strcmp(s, "\\left")) || + (0 == strcmp(s, "\\right")) || + (0 == strcmp(s, "\\over")) || + STRCHREQ(s, ',')) { + ok = FALSE; + break; + } + } + tmpNode = n; + n = n->nextListNode; + } + ok = ok & op; + + displaySplitMsg("(+,-,=, )-expression", ok); + + + if (ok) { + if (arrayDepth >= arrayMaxDepth) { + arrayTooDeep(); + return FALSE; + } + + /* + * Create array environment + */ + + lastNode = insertStringAtFront("\\begin{array}{@{}l}\\displaystyle", rootNode); + arrayDepth++; + insertStringAtBack("\\end{array}", tmpNode); + + /* + * Now break at best place short of width. Start after the + * environment begins. + */ + + n = lastNode->nextListNode; + + /* + * try to split the first expression if too big + */ + + tmpNode = n->nextListNode; + if (breakMathList(n, lineWidth)) { + workWidth = n->width; + n = tmpNode; + } + else + workWidth = n->width; + maxWidth = workWidth; + + while (n->nextListNode) { + loop_top: + if ((n->nodeType == N_TEXT) && + (STRCHREQ(n->data.text, '+') || STRCHREQ(n->data.text, '-') || + STRCHREQ(n->data.text, '=') || + (0 == strcmp(n->data.text, "\\ "))) && + (workWidth > 24) && /* avoid - or + on their own line */ + (workWidth + n->nextListNode->width > lineWidth)) { + + if ((workWidth < lineWidth / 3) && + (breakMathList(n->nextListNode, lineWidth - workWidth))) { + n->nextListNode->width = -1; + n->nextListNode->realWidth = 0; + computeNodeWidth(n->nextListNode); + goto loop_top; + } + + /* + * \ means multiplication. Use a \cdot to make this clearer + */ + + if (0 == strcmp(n->data.text, "\\ ")) + n = insertStringAfter("\\cdot \\\\ \\\\ \\displaystyle", n); + else + n = insertStringAfter("\\\\ \\\\ \\displaystyle", n); + maxWidth = max(maxWidth, workWidth); + + /* + * try to split the next expression if too big + */ + + tmpNode = n->nextListNode; + if (breakMathList(n, lineWidth)) { + workWidth = n->width; + n = tmpNode; + } + else + workWidth = n->width; + } + else { + workWidth += n->nextListNode->width; + n = n->nextListNode; + } + } + + rootNode->width = rootNode->realWidth = + rootNode->data.node->width = rootNode->data.node->realWidth = + maxWidth; + arrayDepth--; + + return TRUE; + } + + return FALSE; +} + +/* + * breakMathList: + * + * Arguments: + * + * n : the starting node at which we are to try to break + * + * lineWidth : the maximum width of a line + * + * + * Returns: TRUE or FALSE, depending on whether the expression was broken + * + * + * Function: Tries various methods to break the expression up into multiple + * lines if the expression is too big. + */ + +int +#ifndef _NO_PROTO +breakMathList(listNode * n, long lineWidth) +#else +breakMathList(n,lineWidth) +listNode * n; +long lineWidth; +#endif +{ + int split = FALSE; + + /* + * Don't do anything if already short enough. + */ + + if (n->width <= lineWidth) + return FALSE; + + /* + * Can't split strings, so just return. + */ + + if (n->nodeType == N_TEXT) + return FALSE; + + blanks[indent] = ' '; + indent += 2; + blanks[indent] = '\0'; + + /* + * We know we have a node, so see what we can do. + */ + + /* + * Case 1: a product: t1 \ t2 + */ + + if (split = breakFracProd(n, lineWidth, "\\ ", "product", FALSE)) + goto done; + + /* + * Case 2: a sequence of tokens separated by +, - or = + */ + + if (split = breakPMEB(n, lineWidth)) + goto done; + + /* + * Case 3: a fraction of terms: t1 \over t2 + */ + + if (split = breakFracProd(n, lineWidth, "\\over", "quotient", TRUE)) + goto done; + + /* + * Case 4: a list of terms bracketed by \left[ and \right] with a comma + */ + + if (split = breakList(n, lineWidth)) + goto done; + + /* + * Case 5: a list of digits, possibly with one "." + */ + + if (split = breakNumber(n, lineWidth)) + goto done; + + /* + * Case 6: a parenthesized expression (e.g., a factor) + */ + + if (split = breakParen(n, lineWidth)) + goto done; + + /* + * Case 7: a function application + */ + + if (split = breakFunction(n, lineWidth)) + goto done; + +done: + blanks[indent] = ' '; + indent -= 2; + blanks[indent] = '\0'; + + return split; +} + +void +#ifndef _NO_PROTO +buildMathList(listNode * oldNode) +#else +buildMathList(oldNode) +listNode * oldNode; +#endif +{ + listNode *curNode, *tmpNode; + + curNode = NULL; + while (nextMathToken()) { + if (mathToken[0] == '}') + break; + if (mathToken[0] == '{') { + tmpNode = newListNode(N_NODE); + buildMathList(tmpNode); + } + else { + tmpNode = newListNode(N_TEXT); + tmpNode->data.text = strdup(mathToken); + } + if (curNode == NULL) { + oldNode->data.node = tmpNode; + } + else { + tmpNode->prevListNode = curNode; + curNode->nextListNode = tmpNode; + } + curNode = tmpNode; + } + + /* + * leave with one level of nesting, e.g., {{{x}}} --> {x} + */ + + tmpNode = oldNode->data.node; + while ( tmpNode && (tmpNode->nodeType == N_NODE) && + (tmpNode->nextListNode == NULL) ) { + oldNode->data.node = tmpNode->data.node; + free(tmpNode); + tmpNode = oldNode->data.node; + } +} + +void +#ifndef _NO_PROTO +computeNodeWidth(listNode * n) +#else +computeNodeWidth(n) +listNode * n; +#endif +{ + char *s; + int i; + listNode *tmp; + + if (n->width != -1) /* only = -1 if unprocessed */ + return; + + n->realWidth = 0; + + if (n->nodeType == N_TEXT) { + s = n->data.text; + if (s[0] == '\\') { + if (s[2] == '\0') { + switch (s[1]) { + case ' ': + n->width = spaceWidths[0]; + break; + case ',': + n->width = spaceWidths[1]; + break; + case '!': + n->width = spaceWidths[2]; + break; + case ':': + n->width = spaceWidths[3]; + break; + case ';': + n->width = spaceWidths[4]; + break; + default: + n->width = avgCharWidth; + } + n->realWidth = n->width; + } + else if ((0 == strcmp(s, "\\displaystyle")) || + (0 == strcmp(s, "\\bf")) || + (0 == strcmp(s, "\\sf")) || + (0 == strcmp(s, "\\tt")) || + (0 == strcmp(s, "\\rm")) || + (0 == strcmp(s, "\\hbox")) || + (0 == strcmp(s, "\\mbox")) || + (0 == strcmp(s, "\\overline")) || + (0 == strcmp(s, "\\textstyle")) || + (0 == strcmp(s, "\\scriptstyle")) || + (0 == strcmp(s, "\\scriptscriptstyle"))) { + n->width = 0; + } + else if (0 == strcmp(s, "\\ldots")) + n->width = 3 * charWidth('.'); + else if (0 == strcmp(s, "\\left")) { + tmp = n->nextListNode; + if (tmp->nodeType != N_TEXT) + error("unusual token following \\left", ""); + n->realWidth = n->width = (tmp->data.text[0] == '.') + ? 0 + : charWidth(tmp->data.text[0]); + tmp->width = 0; + fatDelimiter = 1; + } + else if (0 == strcmp(s, "\\over")) { + + /* + * have already added in width of numerator + */ + computeNodeWidth(n->nextListNode); + n->realWidth = extraOverWidth + max(n->prevListNode->width, n->nextListNode->width); + n->width = n->realWidth - n->prevListNode->width; + n->nextListNode->width = 0; + fatDelimiter = FATDELIMMULT; + } + else if (0 == strcmp(s, "\\right")) { + tmp = n->nextListNode; + if (tmp->nodeType != N_TEXT) + error("unusual token following \\right", ""); + n->realWidth = n->width = fatDelimiter * + ((tmp->data.text[0] == '.') ? 0 : charWidth(tmp->data.text[0])); + tmp->width = 0; + fatDelimiter = 1; + } + else if (0 == strcmp(s, "\\root")) { + computeNodeWidth(n->nextListNode); /* which root */ + n->nextListNode->nextListNode->width = 0; /* \of */ + tmp = n->nextListNode->nextListNode->nextListNode; + computeNodeWidth(tmp); /* root of */ + n->realWidth = n->width = tmp->width + (avgCharWidth / 2) + + max(avgCharWidth, n->nextListNode->width); + n->nextListNode->width = 0; + tmp->width = 0; + } + else if (0 == strcmp(s, "\\sqrt")) { + computeNodeWidth(n->nextListNode); + n->realWidth = n->width = + avgCharWidth + (avgCharWidth / 2) + n->nextListNode->width; + n->nextListNode->width = 0; + } + else if (0 == strcmp(s, "\\zag")) { + computeNodeWidth(n->nextListNode); + computeNodeWidth(n->nextListNode->nextListNode); + n->realWidth = n->width = avgCharWidth + max(n->nextListNode->width, + n->nextListNode->nextListNode->width); + n->nextListNode->width = 0; + n->nextListNode->nextListNode->width = 0; + fatDelimiter = FATDELIMMULT; + } + else if ((0 == strcmp(s, "\\alpha")) || + (0 == strcmp(s, "\\beta")) || + (0 == strcmp(s, "\\pi"))) { + n->realWidth = n->width = avgCharWidth; + } + else if (0 == strcmp(s, "\\sin")) + /* should use table lookup here */ + n->realWidth = n->width = sinWidth; + else if (0 == strcmp(s, "\\cos")) + n->realWidth = n->width = cosWidth; + else if (0 == strcmp(s, "\\tan")) + n->realWidth = n->width = tanWidth; + else if (0 == strcmp(s, "\\erf")) + n->realWidth = n->width = erfWidth; + + /* + * otherwise just compute length of token after \ + */ + else { + n->width = 0; + for (i = 1; i < strlen(s); i++) + n->width += charWidth(s[i]); + n->realWidth = n->width; + } + } + else if (s[1] == '\0') + switch (s[0]) { + case '^': + case '_': + tmp = n->nextListNode; + computeNodeWidth(tmp); + n->width = n->width = tmp->width; + tmp->width = 0; + break; + default: + n->realWidth = n->width = charWidth(s[0]); + } + else { + n->width = 0; + for (i = 0; i < strlen(s); i++) + n->width += charWidth(s[i]); + n->realWidth = n->width; + } + } + else { + n->realWidth = n->width = computeWidth(n->data.node); + } +} + +long +#ifndef _NO_PROTO +computeWidth(listNode * n) +#else +computeWidth(n) +listNode * n; +#endif +{ + long w = 0; + + while (n != NULL) { + if (n->width == -1) { + computeNodeWidth(n); + w += n->width; + } + n = n->nextListNode; + } + return w; +} + +/* + * displaySplitMsg: + * + * Arguments: + * + * s : a string describing the kind of expression we are trying to split. + * + * ok : whether we can split it (TRUE or FALSE) + * + * + * Returns: nothing + * + * + * Function: Displays a message on stderr about whether a particular method of + * line breaking will be successful. + */ + +void +#ifndef _NO_PROTO +displaySplitMsg(char *s, int ok) +#else +displaySplitMsg(s,ok) +char *s; +int ok; +#endif +{ +/* fprintf(stderr, "%sCan split %s: %s\n", blanks, s, ok ? "TRUE" : "FALSE"); */ +} + +void +arrayTooDeep() +{ + fprintf(stderr, "%s->Array nesting too deep!\n", blanks); +} + +void +#ifndef _NO_PROTO +error(char *msg, char *insert) +#else +error(msg,insert) +char *msg; +char *insert; +#endif +{ + fputs("Error (texbreak): ", stderr); + fputs(msg, stderr); + fputs(insert, stderr); + fputc('\n', stderr); + + fputs("% Error (texbreak): ", stdout); + fputs(msg, stdout); + fputs(insert, stdout); + fputc('\n', stdout); + exit(1); +} + +void +#ifndef _NO_PROTO +freeMathList(listNode * n) +#else +freeMathList(n) +listNode * n; +#endif +{ + listNode *tmpNode; + + while (n != NULL) { + if (n->nodeType == N_NODE) + freeMathList(n->data.node); + else if (n->nodeType == N_TEXT) + free(n->data.text); + else { + freeMathList(n->data.array->argsNode); + freeMathList(n->data.array->entries); + free(n->data.array); + } + tmpNode = n->nextListNode; + free(n); + n = tmpNode; + } +} + +listNode * +#ifndef _NO_PROTO +insertStringAfter(char *s, listNode * n) +#else +insertStringAfter(s,n) +char *s; +listNode * n; +#endif +{ + + /* + * returns node after inserted string + */ + listNode *workNode, *lastNode; + + workNode = newListNode(N_NODE); + lastNode = string2NodeList(s, workNode); + + n->nextListNode->prevListNode = lastNode; + lastNode->nextListNode = n->nextListNode; + n->nextListNode = workNode->data.node; + workNode->data.node->prevListNode = n; + + free(workNode); + return lastNode->nextListNode; +} + +listNode * +#ifndef _NO_PROTO +insertStringAtBack(char *s, listNode * n) +#else +insertStringAtBack(s,n) +char *s; +listNode * n; +#endif +{ + + /* + * Breaks s up into a list of tokens and appends them onto the end of n. + * n must be non-NULL. + */ + + listNode *workNode, *lastNode; + + workNode = newListNode(N_NODE); + lastNode = string2NodeList(s, workNode); + n->nextListNode = workNode->data.node; + workNode->data.node->prevListNode = n; + free(workNode); + + return lastNode; +} + +listNode * +#ifndef _NO_PROTO +insertStringAtFront(char *s, listNode * n) +#else +insertStringAtFront(s,n) +char *s; +listNode * n; +#endif +{ + + /* + * Breaks s up into a list of tokens and appends them onto the front of + * n. n must be a node. + */ + + listNode *workNode, *lastNode; + + workNode = newListNode(N_NODE); + lastNode = string2NodeList(s, workNode); + lastNode->nextListNode = n->data.node; + n->data.node->prevListNode = lastNode; + n->data.node = workNode->data.node; + free(workNode); + + return lastNode; +} + +int +#ifndef _NO_PROTO +newLineIfNecessary(int lastWasNewLine) +#else +newLineIfNecessary(lastWasNewLine) +int lastWasNewLine; +#endif +{ + if (!lastWasNewLine || (charsOut > 0)) { + putcBuf('\n', bufout); + outLineNum++; + charsOut = 0; + } + return TRUE; +} + +listNode * +#ifndef _NO_PROTO +newListNode(enum nodeTypes nt) +#else +newListNode(nt) +enum nodeTypes nt; +#endif +{ + listNode *n; + + n = (listNode *) malloc(sizeof(listNode)); + n->nextListNode = n->prevListNode = NULL; + n->nodeType = nt; + n->width = -1; + n->realWidth = -1; + if (nt == N_NODE) + n->data.node = NULL; + else if (nt == N_TEXT) + n->data.text = NULL; + else { + n->data.array = (arrayNode *) malloc(sizeof(arrayNode)); + n->data.array->argsNode = NULL; + n->data.array->entries = NULL; + n->data.array->cols = 0; + } + return n; +} + +int +nextMathToken() +{ + + + /* + * Sets mathToken. Returns 1 if ok, 0 if no more tokens. + */ + + char curChar, errChar[2]; + + errChar[1] = '\0'; + mathToken[0] = '\0'; + mathTokenLen = 0; + + /* + * Kill any blanks. + */ + + while ((mathBufferPtr < mathBufferLen) && (mathBuffer[mathBufferPtr] == ' ')) + mathBufferPtr++; + + /* + * If at end, exit saying so. + */ + + if (mathBufferPtr >= mathBufferLen) + return 0; + + mathToken[mathTokenLen++] = curChar = mathBuffer[mathBufferPtr++]; + + if (curChar == '\\') { + curChar = mathBuffer[mathBufferPtr++]; + switch (curChar) { + case '\0': /* at end of buffer */ + mathToken[mathTokenLen++] = ' '; + goto done; + case '\\': + case ' ': + case '!': + case '#': + case '$': + case '%': + case '&': + case ',': + case ':': + case ';': + case '^': + case '_': + case '{': + case '}': + mathToken[mathTokenLen++] = curChar; + goto done; + } + if (isalpha(curChar) || (curChar == '@')) { + mathToken[mathTokenLen++] = curChar; + while ((curChar = mathBuffer[mathBufferPtr]) && + (isalpha(curChar) || (curChar == '@'))) { + mathToken[mathTokenLen++] = curChar; + mathBufferPtr++; + } + } + else { + errChar[0] = curChar; + errChar[1] = '\0'; + error("strange character following \\: ", errChar); + } + } + else if (isdigit(curChar)) /* digits are individual tokens */ + ; + else if (isalpha(curChar)) { + while ((curChar = mathBuffer[mathBufferPtr]) && + (isalpha(curChar))) { + mathToken[mathTokenLen++] = curChar; + mathBufferPtr++; + } + } + else if (curChar == '"') { /* handle strings */ + while ((curChar = mathBuffer[mathBufferPtr]) && + (curChar != '"')) { + mathToken[mathTokenLen++] = curChar; + mathBufferPtr++; + } + mathToken[mathTokenLen++] = '"'; + mathBufferPtr++; + } + +done: + mathToken[mathTokenLen--] = '\0'; + + /* + * Some translations. + */ + if (0 == strcmp(mathToken, "\\sp")) { + mathToken[0] = '^'; + mathToken[1] = '\0'; + mathTokenLen = 1; + } + else if (0 == strcmp(mathToken, "\\sb")) { + mathToken[0] = '_'; + mathToken[1] = '\0'; + mathTokenLen = 1; + } + + return 1; +} + +int +#ifndef _NO_PROTO +printChar(char c) +#else +printChar(c) +char c; +#endif +{ + if ((charsOut > MAXCHARSINLINE) && + isdigit(lastPrinted) && isdigit(c)) { + putcBuf('\n', bufout); + outLineNum++; + charsOut = 0; + } + + putcBuf(c, bufout); + lastPrinted = c; + charsOut++; + + /* + * break lines after following characters + */ + + if ((charsOut > MAXCHARSINLINE) && strchr("+- ,_^", c)) { + putcBuf('\n', bufout); + outLineNum++; + charsOut = 0; + lastPrinted = '\0'; + return TRUE; + } + return FALSE; +} + +int +#ifndef _NO_PROTO +printMathList(listNode * n, int lastWasNewLine) +#else +printMathList(n,lastWasNewLine) +listNode * n; +int lastWasNewLine; +#endif +{ + listNode *tmpNode, *rowNode, *colNode; + int begin, group, r, c; + + while (n != NULL) { + if (n->nodeType == N_NODE) { + lastWasNewLine = printChar('{'); + lastWasNewLine = printMathList(n->data.node, lastWasNewLine); + lastWasNewLine = printChar('}'); + } + else if (n->nodeType == N_ARRAY) { + lastWasNewLine = newLineIfNecessary(lastWasNewLine); + lastWasNewLine = printString("\\begin{array}"); + lastWasNewLine = printMathList(n->data.array->argsNode, lastWasNewLine); + lastWasNewLine = printString("\\displaystyle"); + lastWasNewLine = newLineIfNecessary(lastWasNewLine); + + rowNode = n->data.array->entries; /* node pointing to first row */ + while (rowNode) { + colNode = rowNode->data.node; + while (colNode) { + if (colNode->prevListNode) { /* if not first column */ + lastWasNewLine = printString(" & "); + lastWasNewLine = newLineIfNecessary(lastWasNewLine); + } + lastWasNewLine = printMathList(colNode->data.node, lastWasNewLine); + colNode = colNode->nextListNode; + } + if (rowNode->nextListNode) /* if not last row */ + lastWasNewLine = printString(" \\\\"); + + lastWasNewLine = newLineIfNecessary(lastWasNewLine); + rowNode = rowNode->nextListNode; + } + + lastWasNewLine = printString("\\end{array}"); + lastWasNewLine = newLineIfNecessary(lastWasNewLine); + } + else if (n->nodeType == N_TEXT) { + + /* + * handle keywords that might appear in math mode + */ + + if ((0 == strcmp(n->data.text, "by")) || + (0 == strcmp(n->data.text, "if")) || + (0 == strcmp(n->data.text, "then")) || + (0 == strcmp(n->data.text, "else"))) { + lastWasNewLine = printString(" \\hbox{ "); + lastWasNewLine = printString(n->data.text); + lastWasNewLine = printString(" } "); + } + + /* + * handle things that should be in a special font + */ + + else if ((0 == strcmp(n->data.text, "true")) || + (0 == strcmp(n->data.text, "false")) || + (0 == strcmp(n->data.text, "table")) || + (0 == strcmp(n->data.text, "Aleph")) + ) { + lastWasNewLine = printString(" \\mbox{\\rm "); + lastWasNewLine = printString(n->data.text); + lastWasNewLine = printString("} "); + } + + /* + * handle things that should always be on their own line + */ + + else if ((0 == strcmp(n->data.text, "\\\\")) || + (0 == strcmp(n->data.text, "\\displaystyle"))) { + lastWasNewLine = newLineIfNecessary(lastWasNewLine); + lastWasNewLine = printString(n->data.text); + lastWasNewLine = newLineIfNecessary(lastWasNewLine); + } + + /* + * handle phrases that should be on their own line. + */ + + else if ((0 == strcmp(n->data.text, "\\begin")) || + (0 == strcmp(n->data.text, "\\end"))) { + lastWasNewLine = newLineIfNecessary(lastWasNewLine); + lastWasNewLine = printString(n->data.text); + begin = (n->data.text[1] == 'b') ? TRUE : FALSE; + + n = n->nextListNode; /* had better be a node */ + tmpNode = n->data.node; + lastWasNewLine = printChar('{'); + lastWasNewLine = printMathList(tmpNode, lastWasNewLine); + lastWasNewLine = printChar('}'); + + if (begin) { + + /* + * if array, print the argument. + */ + + if (0 == strcmp(tmpNode->data.text, "array")) { + n = n->nextListNode; /* had better be a node */ + lastWasNewLine = printChar('{'); + lastWasNewLine = printMathList(n->data.node, lastWasNewLine); + lastWasNewLine = printChar('}'); + } + } + lastWasNewLine = newLineIfNecessary(FALSE); + } + + /* + * handle everything else, paying attention as to whether we + * should include a trailing blank. + */ + + else { + group = 0; + /* guess whether next word is part of a type */ + if ((strlen(n->data.text) > 2) && + ('A' <= n->data.text[0]) && + ('Z' >= n->data.text[0])) { + group = 1; + lastWasNewLine = printString("\\hbox{\\axiomType{"); + } + lastWasNewLine = printString(n->data.text); + if (group) { + lastWasNewLine = printString("}\\ }"); + group = 0; + } + tmpNode = n->nextListNode; + if ((n->data.text[0] == '_') || + (n->data.text[0] == '^') || + (n->data.text[0] == '.') || + (n->data.text[0] == '(') || + (0 == strcmp(n->data.text, "\\left")) || + (0 == strcmp(n->data.text, "\\right")) || + (0 == strcmp(n->data.text, "\\%"))); + else if (tmpNode && (tmpNode->nodeType == N_TEXT)) { + if (((isdigit(n->data.text[0])) && + (isdigit(tmpNode->data.text[0]))) || + ((isdigit(n->data.text[0])) && + (',' == tmpNode->data.text[0])) || + (tmpNode->data.text[0] == '\'') || + (tmpNode->data.text[0] == '_') || + (tmpNode->data.text[0] == '^') || + (tmpNode->data.text[0] == '.') || + (tmpNode->data.text[0] == ')')); + else + lastWasNewLine = printChar(' '); + } + } + } + n = n->nextListNode; + } + return lastWasNewLine; +} + +int +#ifndef _NO_PROTO +printString(char *s) +#else +printString(s) +char *s; +#endif +{ + if (s[0]) { + if (!s[1]) + return printChar(s[0]); + else { + putsBuf(s,bufout); + charsOut += strlen(s); + } + } + return FALSE; +} + +void +#ifndef _NO_PROTO +putsBuf(char s[], char buf[]) +#else +putsBuf(s,buf) +char s[], buf[] +#endif +{ + strcat(buf,s); +} + +void +#ifndef _NO_PROTO +putcBuf(char c,char buf[]) +#else +putcBuf(c,buf) +char c, buf[] +#endif +{ + char s[2]; + + s[0] = c; + s[1] = '\0'; + strcat(buf,s); +} + +listNode * +#ifndef _NO_PROTO +string2NodeList(char *s, listNode * n) +#else +string2NodeList(s,n) +char *s; +listNode * n; +#endif +{ + + /* + * First argument is string to be broken up, second is a node. Return + * value is last item in list. + */ + + mathBufferPtr = 0; + strcpy(mathBuffer, s); + mathBufferLen = strlen(s); + buildMathList(n); + n = n->data.node; + while (n->nextListNode) { + + /* + * set width to 0: other funs will have to set for real + */ + n->width = 0; + n = n->nextListNode; + } + n->width = 0; + return n; +} + +void +resetCharMults() +{ + + /* + * this is a ratio by which the standard \mit should be multiplied to get + * other fonts, roughly + */ + + charMultNum = charMultDenom = 1; +} + +void +ttCharMults() +{ + + /* + * this is a ratio by which the standard \mit should be multiplied to get + * the \tt font, roughly + */ + + charMultNum = 11; + charMultDenom = 10; +} + +int +#ifndef _NO_PROTO +charWidth(char c) +#else +charWidth(c) +char c; +#endif +{ + return (charMultNum * charTable[c]) / charMultDenom; +} + +void +#ifndef _NO_PROTO +#else +#endif +initCharTable() +{ + int i; + + avgCharWidth = 95; /* where 1000 = 1 inch */ + + spaceWidths[0] = 51; /* \ */ + spaceWidths[1] = 25; /* \, */ + spaceWidths[2] = -25; /* \! */ + spaceWidths[3] = 37; /* \: */ + spaceWidths[4] = 42; /* \; */ + + extraOverWidth = 33; /* extra space in fraction bar */ + + sinWidth = 186; /* width of \sin */ + cosWidth = 203; + tanWidth = 219; + erfWidth = 185; + + for (i = 0; i < 256; i++) + charTable[i] = avgCharWidth; + + charTable['!'] = 42; + charTable['"'] = 76; + charTable['%'] = 126; + charTable['('] = 59; + charTable[')'] = 59; + charTable['+'] = 185; + charTable[','] = 42; + charTable['-'] = 185; + charTable['.'] = 42; + charTable['/'] = 76; + charTable['0'] = 76; + charTable['1'] = 76; + charTable['2'] = 76; + charTable['3'] = 76; + charTable['4'] = 76; + charTable['5'] = 76; + charTable['6'] = 76; + charTable['7'] = 76; + charTable['8'] = 76; + charTable['9'] = 76; + charTable[':'] = 42; + charTable[';'] = 42; + charTable['<'] = 202; + charTable['='] = 202; + charTable['>'] = 202; + charTable['A'] = 114; + charTable['B'] = 123; + charTable['C'] = 119; + charTable['D'] = 130; + charTable['E'] = 121; + charTable['F'] = 119; + charTable['G'] = 119; + charTable['H'] = 138; + charTable['I'] = 79; + charTable['J'] = 99; + charTable['K'] = 140; + charTable['L'] = 103; + charTable['M'] = 164; + charTable['N'] = 138; + charTable['O'] = 120; + charTable['P'] = 118; + charTable['Q'] = 120; + charTable['R'] = 116; + charTable['S'] = 102; + charTable['T'] = 110; + charTable['U'] = 120; + charTable['V'] = 122; + charTable['W'] = 164; + charTable['X'] = 137; + charTable['Y'] = 122; + charTable['Z'] = 114; + charTable['['] = 42; + charTable[']'] = 42; + charTable['a'] = 80; + charTable['b'] = 65; + charTable['c'] = 66; + charTable['d'] = 79; + charTable['e'] = 71; + charTable['f'] = 91; + charTable['g'] = 78; + charTable['h'] = 87; + charTable['i'] = 52; + charTable['j'] = 71; + charTable['k'] = 84; + charTable['l'] = 48; + charTable['m'] = 133; + charTable['n'] = 91; + charTable['o'] = 73; + charTable['p'] = 76; + charTable['q'] = 73; + charTable['r'] = 73; + charTable['s'] = 71; + charTable['t'] = 55; + charTable['u'] = 87; + charTable['v'] = 79; + charTable['w'] = 113; + charTable['x'] = 87; + charTable['y'] = 80; + charTable['z'] = 77; + charTable['{'] = 76; + charTable['|'] = 42; + charTable['}'] = 76; +} 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 <bill.page1@sympatico.ca>
+ * (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 <windows.h>
+#include <process.h>
+#include <memory.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <io.h>
+
+/* 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;i<nargs;i++) {
+ pTM_OPENAXIOM=args[i]; /* args override environment */
+ if (i>0 || (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<n;i++) {
+ if (strncmp(&Buffer[i],"$$\n",3)==0) { /* Found a LaTeX marker */
+ #ifdef DEBUG_OUT
+ fprintf(stderr, "LaTeX marker at: %d, mode: %d\n",i,mmode);
+ fflush(stderr);
+ #endif /* DEBUG_OUT */
+ Buffer[i]='\0'; /* something ends here */
+ if (mmode<=0) { /* we were not in mathmode */
+ fputs(&Buffer[j],stdout); /* send the plain text ---> 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<n) {
+ fputs(&Buffer[j],stdout); /* send the plain text ---> 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 <arg>\n\
+ where arg can be one or more of\n\
+ break <on>|<off> line-break algorithm\n\
+ over <on>|<off> convert 2-d \\over to 1-d /\n\
+ cdot <on>|<off> convert \\cdot to \\ (space)\n\
+ space <on>|<off> convert \\ (space) to \\,\n\
+ big( <on>|<off> convert \\left( \\right to ( )\n\
+ width <9.99> line width in inches\n\
+\n\
+ <on> may be on, yes, 1\n\
+ <off> 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_ */
+
|