Logo Search packages:      
Sourcecode: latex2rtf version File versions  Download package

equations.c

/* equations.c - Translate TeX equations

Copyright (C) 1995-2002 The Free Software Foundation

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

This file is available from http://sourceforge.net/projects/latex2rtf/
 
Authors:
    1995-1997 Ralf Schlatterbeck
    1998-2000 Georg Lehner
    2001-2002 Scott Prahl
*/

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "main.h"
#include "convert.h"
#include "commands.h"
#include "stack.h"
#include "fonts.h"
#include "cfg.h"
#include "ignore.h"
#include "parser.h"
#include "equations.h"
#include "counters.h"
#include "funct1.h"
#include "lengths.h"
#include "utils.h"
#include "graphics.h"
#include "xrefs.h"
#include "chars.h"
#include "preamble.h"
#include "vertical.h"

int g_equation_column = 1;
int g_amsmath_package = FALSE;

int script_shift(void)
{
    return CurrentFontSize() / 3.0;
}

int script_size(void)
{
    return CurrentFontSize() / 1.2;
}

void CmdNonumber(int code)

/******************************************************************************
 purpose   : Handles \nonumber to suppress numbering in equations
 ******************************************************************************/
{
    if (g_processing_eqnarray || !g_processing_tabular)
        g_suppress_equation_number = TRUE;
}

static char *SlurpDollarEquation(void)

/******************************************************************************
 purpose   : reads an equation delimited by $...$
                   this routine is needed to handle $ x \mbox{if $x$} $ 
 ******************************************************************************/
{
    int brace = 0;
    int slash = 0;
    int i;
    char *s, *t, *u;

    s = malloc(1024 * sizeof(char));
    t = s;

    for (i = 0; i < 1024; i++) {
        *t = getTexChar();
        if (*t == '\\')
            slash++;
        else if (*t == '{' && even(slash) &&
          !(i > 5 && strncmp(t - 5, "\\left{", 6) == 0) && !(i > 6 && strncmp(t - 6, "\\right{", 7) == 0))
            brace++;
        else if (*t == '}' && even(slash) &&
          !(i > 5 && !strncmp(t - 5, "\\left}", 6)) && !(i > 6 && !strncmp(t - 6, "\\right}", 7)))
            brace--;
        else if (*t == '$' && even(slash) && brace == 0) {
            break;
        } else
            slash = 0;
        t++;
    }
    *t = '\0';

    u = strdup(s);              /* return much smaller string */
    free(s);                    /* release the big string */
    return u;
}

static void SlurpEquation(int code, char **pre, char **eq, char **post)
{
    int true_code = code & ~ON;

    switch (true_code) {

        case EQN_MATH:
            diagnostics(4, "SlurpEquation() ... \\begin{math}");
            *pre = strdup("\\begin{math}");
            *post = strdup("\\end{math}");
            *eq = getTexUntil(*post, 0);
            break;

        case EQN_DOLLAR:
            diagnostics(4, "SlurpEquation() ... $");
            *pre = strdup("$");
            *post = strdup("$");
            *eq = SlurpDollarEquation();
            break;

        case EQN_RND_OPEN:
            diagnostics(4, "SlurpEquation() ... \\(");
            *pre = strdup("\\(");
            *post = strdup("\\)");
            *eq = getTexUntil(*post, 0);
            break;

        case EQN_DISPLAYMATH:
            diagnostics(4, "SlurpEquation -- displaymath");
            *pre = strdup("\\begin{displaymath}");
            *post = strdup("\\end{displaymath}");
            *eq = getTexUntil(*post, 0);
            break;

        case EQN_EQUATION_STAR:
            diagnostics(4, "SlurpEquation() -- equation*");
            *pre = strdup("\\begin{equation*}");
            *post = strdup("\\end{equation*}");
            *eq = getTexUntil(*post, 0);
            break;

        case EQN_DOLLAR_DOLLAR:
            diagnostics(4, "SlurpEquation() -- $$");
            *pre = strdup("$$");
            *post = strdup("$$");
            *eq = getTexUntil(*post, 0);
            break;

        case EQN_BRACKET_OPEN:
            diagnostics(4, "SlurpEquation()-- \\[");
            *pre = strdup("\\[");
            *post = strdup("\\]");
            *eq = getTexUntil(*post, 0);
            break;

        case EQN_EQUATION:
            diagnostics(4, "SlurpEquation() -- equation");
            *pre = strdup("\\begin{equation}");
            *post = strdup("\\end{equation}");
            *eq = getTexUntil(*post, 0);
            break;

        case EQN_ARRAY_STAR:
            diagnostics(4, "Entering CmdDisplayMath -- eqnarray* ");
            *pre = strdup("\\begin{eqnarray*}");
            *post = strdup("\\end{eqnarray*}");
            *eq = getTexUntil(*post, 0);
            break;

        case EQN_ARRAY:
            diagnostics(4, "SlurpEquation() --- eqnarray");
            *pre = strdup("\\begin{eqnarray}");
            *post = strdup("\\end{eqnarray}");
            *eq = getTexUntil(*post, 0);
            break;

        case EQN_ALIGN_STAR:
            diagnostics(4, "Entering CmdDisplayMath -- align* ");
            *pre = strdup("\\begin{align*}");
            *post = strdup("\\end{align*}");
            *eq = getTexUntil(*post, 0);
            break;

        case EQN_ALIGN:
            diagnostics(4, "SlurpEquation() --- align");
            *pre = strdup("\\begin{align}");
            *post = strdup("\\end{align}");
            *eq = getTexUntil(*post, 0);
            break;
    }
}

static int EquationNeedsFields(char *eq)

/******************************************************************************
 purpose   : Determine if equation needs EQ field for RTF conversion
 ******************************************************************************/
{
    if (strstr(eq, "\\frac"))
        return 1;
    if (strstr(eq, "\\sum"))
        return 1;
    if (strstr(eq, "\\int"))
        return 1;
    if (strstr(eq, "\\iint"))
        return 1;
    if (strstr(eq, "\\iiint"))
        return 1;
    if (strstr(eq, "\\prod"))
        return 1;
    if (strstr(eq, "\\begin{array}"))
        return 1;
    if (strstr(eq, "\\left"))
        return 1;
    if (strstr(eq, "\\right"))
        return 1;
    if (strstr(eq, "\\root"))
        return 1;
    if (strstr(eq, "\\sqrt"))
        return 1;
    if (strstr(eq, "\\over"))
        return 1;
    if (strstr(eq, "\\stackrel"))
        return 1;
    if (strstr(eq, "_") || strstr(eq, "^"))
        return 1;
    if (strstr(eq, "\\dfrac"))
        return 1;
    if (strstr(eq, "\\lim"))
        return 1;
    if (strstr(eq, "\\liminf"))
        return 1;
    if (strstr(eq, "\\limsup"))
        return 1;
    if (strstr(eq, "\\overline"))
        return 1;
    return 0;
}

static void WriteEquationAsRawLatex(char *pre, char *eq, char *post)

/******************************************************************************
 purpose   : Writes equation to RTF file as plain text 
 ******************************************************************************/
{
    fprintRTF("<<:");
    putRtfStrEscaped(pre);
    putRtfStrEscaped(eq);
    putRtfStrEscaped(post);
    fprintRTF(":>>");
}

static void WriteEquationAsComment(char *pre, char *eq, char *post)

/******************************************************************************
 purpose   : Writes equation to RTF file as text of COMMENT field
 ******************************************************************************/
{
    fprintRTF("{\\field{\\*\\fldinst{ COMMENTS \" ");
    putRtfStrEscaped(pre);
    putRtfStrEscaped(eq);
    putRtfStrEscaped(post);
    fprintRTF("\" }{ }}{\\fldrslt }}");
}

static void PrepareRtfEquation(int code, int EQ_Needed)
{
    int width, a, b, c;

    width = getLength("textwidth");
    a = (int) (0.45 * width);
    b = (int) (0.50 * width);
    c = (int) (0.55 * width);

    switch (code) {

        case EQN_MATH:
            diagnostics(4, "PrepareRtfEquation ... \\begin{math}");
            setTexMode(MODE_MATH);
            break;

        case EQN_DOLLAR:
            diagnostics(4, "PrepareRtfEquation ... $");
            fprintRTF("{");
            setTexMode(MODE_MATH);
            break;

        case EQN_ENSUREMATH:
            diagnostics(4, "PrepareRtfEquation ... \\ensuremath{}");
            fprintRTF("{");
            setTexMode(MODE_MATH);
            break;

        case EQN_RND_OPEN:
            diagnostics(4, "PrepareRtfEquation ... \\(");
            fprintRTF("{");
            setTexMode(MODE_MATH);
            break;

        case EQN_DOLLAR_DOLLAR:
            diagnostics(4, "PrepareRtfEquation -- $$");
            CmdEndParagraph(0);
            setTexMode(MODE_DISPLAYMATH);
            g_show_equation_number = FALSE;
            fprintRTF("{\\pard\\tqc\\tx%d\\tab ", b);
            break;

        case EQN_BRACKET_OPEN:
        case EQN_DISPLAYMATH:
            if (code == EQN_DISPLAYMATH)
                diagnostics(4, "PrepareRtfEquation -- displaymath");
            else
                diagnostics(4, "PrepareRtfEquation -- \\[");
            g_show_equation_number = FALSE;
            fprintRTF("\\par\\par\n\\pard");
            fprintRTF("\\tqc\\tx%d", b);
            fprintRTF("\\tab ");
            setTexMode(MODE_DISPLAYMATH);
            break;

        case EQN_EQUATION_STAR:
            diagnostics(4, "PrepareRtfEquation -- equation*");
            g_show_equation_number = FALSE;
            fprintRTF("\\par\\par\n\\pard");
            fprintRTF("\\tqc\\tx%d", b);
            fprintRTF("\\tab ");
            setTexMode(MODE_DISPLAYMATH);
            break;

        case EQN_EQUATION:
            diagnostics(4, "PrepareRtfEquation -- equation");
            g_equation_column = 5;  /* avoid adding \tabs when finishing */
            g_show_equation_number = TRUE;
            g_suppress_equation_number = FALSE;
            fprintRTF("\\par\\par\n\\pard");
            fprintRTF("\\tqc\\tx%d\\tqr\\tx%d", b, width);
            fprintRTF("\\tab ");
            setTexMode(MODE_DISPLAYMATH);
            break;

        case EQN_ARRAY_STAR:
            diagnostics(4, "PrepareRtfEquation -- eqnarray* ");
            g_show_equation_number = FALSE;
            g_processing_eqnarray = TRUE;
            g_processing_tabular = TRUE;
            g_suppress_equation_number = FALSE;
            g_equation_column = 1;
            fprintRTF("\\par\\par\n\\pard");
            if (g_equation_display_bitmap)
                  fprintRTF("\\tqc\\tx%d\\tqr\\tx%d", b, width);
            else
                  fprintRTF("\\tqr\\tx%d\\tqc\\tx%d\\tql\\tx%d", a, b, c);
            fprintRTF("\\tab ");
            setTexMode(MODE_DISPLAYMATH);
            break;

        case EQN_ARRAY:
            diagnostics(4, "PrepareRtfEquation --- eqnarray");
            g_show_equation_number = TRUE;
            g_processing_eqnarray = TRUE;
            g_processing_tabular = TRUE;
            g_equation_column = 1;
            fprintRTF("\\par\\par\n\\pard");
            if (g_equation_display_bitmap)
                  fprintRTF("\\tqc\\tx%d\\tqr\\tx%d", b, width);
            else
                  fprintRTF("\\tqr\\tx%d\\tqc\\tx%d\\tql\\tx%d\\tqr\\tx%d", a, b, c, width);
            fprintRTF("\\tab ");
            setTexMode(MODE_DISPLAYMATH);
            break;

        case EQN_ALIGN_STAR:
            diagnostics(4, "PrepareRtfEquation -- align* ");
            g_show_equation_number = FALSE;
            g_processing_eqnarray = TRUE;
            g_processing_tabular = TRUE;
            g_equation_column = 1;
            fprintRTF("\\par\\par\n\\pard");
            if (g_equation_display_bitmap)
                  fprintRTF("\\tqc\\tx%d\\tqr\\tx%d", b, width);
            else
                  fprintRTF("\\tqr\\tx%d\\tql\\tx%d", a, b);
            fprintRTF("\\tab ");
            setTexMode(MODE_DISPLAYMATH);
            break;

        case EQN_ALIGN:
            diagnostics(4, "PrepareRtfEquation --- align");
            g_show_equation_number = TRUE;
            g_processing_eqnarray = TRUE;
            g_processing_tabular = TRUE;
            g_equation_column = 1;
                  fprintRTF("\\par\\par\n\\pard");
            if (g_equation_display_bitmap)
                  fprintRTF("\\tqc\\tx%d\\tqr\\tx%d", b, width);
            else
                        fprintRTF("\\tqr\\tx%d\\tql\\tx%d\\tqr\\tx%d", a, b, width);
                  fprintRTF("\\tab ");
            setTexMode(MODE_DISPLAYMATH);
            break;
            
        default:
            diagnostics(ERROR, "calling PrepareRtfEquation with OFF code");
            break;
    }

    if (g_fields_use_EQ && EQ_Needed && g_processing_fields == 0) {
        fprintRTF("{\\field{\\*\\fldinst{ EQ ");
        g_processing_fields++;
    }

}

static char *CreateEquationLabel(void)
{
      char *number = malloc(30);
      int n;
      
      n = getCounter("equation");
      
      if (g_document_type == FORMAT_REPORT ||
          g_document_type == FORMAT_BOOK )
            snprintf(number, 29, "%d.%d", getCounter("chapter"), getCounter("equation"));
      else
            snprintf(number, 29, "%d", getCounter("equation"));
            
      return number;
}

      


static void FinishRtfEquation(int code, int EQ_Needed)
{
    if (g_fields_use_EQ && EQ_Needed && g_processing_fields == 1) {
        fprintRTF("}}{\\fldrslt }}");
        g_processing_fields--;
    }

    switch (code) {

        case EQN_MATH:
            diagnostics(4, "FinishRtfEquation -- \\end{math}");
            CmdIndent(INDENT_INHIBIT);
            setTexMode(MODE_HORIZONTAL);
            break;

        case EQN_DOLLAR:
            diagnostics(4, "FinishRtfEquation -- $");
            fprintRTF("}");
            setTexMode(MODE_HORIZONTAL);
            break;

        case EQN_ENSUREMATH:
            diagnostics(4, "FinishRtfEquation -- \e\nsuremath{}");
            fprintRTF("}");
            setTexMode(MODE_HORIZONTAL);
            break;

        case EQN_RND_OPEN:
            diagnostics(4, "FinishRtfEquation -- \\)");
            fprintRTF("}");
            setTexMode(MODE_HORIZONTAL);
            break;

        case EQN_DOLLAR_DOLLAR:
            diagnostics(4, "FinishRtfEquation -- $$");
            CmdEndParagraph(0);
            CmdIndent(INDENT_INHIBIT);
            fprintRTF("}");
            break;

        case EQN_BRACKET_OPEN:
        case EQN_DISPLAYMATH:
            if (code == EQN_DISPLAYMATH)
                diagnostics(4, "FinishRtfEquation -- displaymath");
            else
                diagnostics(4, "FinishRtfEquation -- \\]");
            CmdEndParagraph(0);
            CmdIndent(INDENT_INHIBIT);
            break;

        case EQN_EQUATION_STAR:
            diagnostics(4, "FinishRtfEquation -- equation*");
            CmdEndParagraph(0);
            CmdIndent(INDENT_INHIBIT);
            break;

        case EQN_ARRAY_STAR:
            diagnostics(4, "FinishRtfEquation -- eqnarray* ");
            CmdEndParagraph(0);
            CmdIndent(INDENT_INHIBIT);
            g_processing_eqnarray = FALSE;
            g_processing_tabular = FALSE;
            break;

        case EQN_ALIGN_STAR:
            diagnostics(4, "FinishRtfEquation -- align* ");
            CmdEndParagraph(0);
            CmdIndent(INDENT_INHIBIT);
            g_processing_eqnarray = FALSE;
            g_processing_tabular = FALSE;
            break;

        case EQN_EQUATION:
        case EQN_ARRAY:
        case EQN_ALIGN:
            diagnostics(4, "FinishRtfEquation --- equation or eqnarray or align");
            if (g_show_equation_number && !g_suppress_equation_number) {
                char *number;

               incrementCounter("equation");
               if (!g_equation_display_bitmap) {
                  for (; g_equation_column < 3; g_equation_column++)
                        fprintRTF("\\tab ");
                }
                fprintRTF("\\tab{\\b0 (");
                number = CreateEquationLabel();
                InsertBookmark(g_equation_label, number);
                free(number);
                if (g_equation_label) {
                    free(g_equation_label);
                    g_equation_label = NULL;
                }
                fprintRTF(")}");
            }
            g_processing_eqnarray = FALSE;
            g_processing_tabular = FALSE;
            CmdEndParagraph(0);
            CmdIndent(INDENT_INHIBIT);
            break;

        default:
            diagnostics(ERROR, "calling FinishRtfEquation with OFF code");
            break;
    }
}

static char *scanback(char *s, char *t)

/******************************************************************************
 purpose   : Find '{' that starts a fraction designated by \over 
                   Consider \int_0 { \{a_{x+y} + b \} \over a_{x+y} }
                        ^            ^                  ^
                        s    result               t
 ******************************************************************************/
{
    int braces = 1;

    if (!s || !t || t < s)
        return NULL;

    while (braces && s < t) {
        if (*t == '{' && !(*(t - 1) == '\\') && /* avoid \{ */
          !(s + 5 <= t && !strncmp(t - 5, "\\left", 5)) &&  /* avoid \left{ */
          !(s + 6 <= t && !strncmp(t - 6, "\\right", 6))    /* avoid \right{ */
          )
            braces--;

        if (*t == '}' && !(*(t - 1) == '\\') && /* avoid \} */
          !(s + 5 <= t && !strncmp(t - 5, "\\left", 5)) &&  /* avoid \left} */
          !(s + 6 <= t && !strncmp(t - 6, "\\right", 6))    /* avoid \right} */
          )
            braces++;

        if (braces)
            t--;
    }
    return t;
}

static char *scanahead(char *s)

/******************************************************************************
 purpose   : Find '}' that ends a fraction designated by \over 
                   Consider \int_0 { \{a_{x+y} + b \} \over a_{x+y} }
                                                  ^             ^ 
                                                  s             t
 ******************************************************************************/
{
    char *t;
    int braces = 1;
    int slashes = 0;

    if (!s)
        return NULL;
    t = s;

    while (braces && t && *t != '\0') {

        if (even(slashes)) {
            if (*t == '}' && !(s + 5 <= t && !strncmp(t - 5, "\\left", 5)) &&   /* avoid \left} */
              !(s + 6 <= t && !strncmp(t - 6, "\\right", 6))    /* avoid \right} */
              )
                braces--;

            if (*t == '{' && !(s + 5 <= t && !strncmp(t - 5, "\\left", 5)) &&   /* avoid \left{ */
              !(s + 6 <= t && !strncmp(t - 6, "\\right", 6))    /* avoid \right{ */
              )
                braces++;
        }

        if (*t == '\\')
            slashes++;
        else
            slashes = 0;
        if (braces)
            t++;
    }

    return t;
}

static void ConvertOverToFrac(char **equation)

/******************************************************************************
 purpose   : Convert {A \over B} to \frac{A}{B} 
 ******************************************************************************/
{
    char cNext, *eq, *mid, *first, *last, *s, *p, *t;

    eq = *equation;
    p = eq;
    diagnostics(4, "ConvertOverToFrac before <%s>", p);

    while ((mid = strstr(p, "\\over")) != NULL) {
        diagnostics(5, "Matched at <%s>", mid);
        cNext = *(mid + 5);
        diagnostics(5, "Next char is <%c>", cNext);
        if (!isalpha((int) cNext)) {

            first = scanback(eq, mid);
            diagnostics(6, "first = <%s>", first);
            last = scanahead(mid);
            diagnostics(6, "last = <%s>", last);

            strncpy(mid, "  }{ ", 5);
            diagnostics(6, "mid = <%s>", mid);
            s = (char *) malloc(strlen(eq) + sizeof("\\frac{}") + 1);
            t = s;

            strncpy(t, eq, (size_t) (first - eq));  /* everything up to {A\over B} */
            t += first - eq;

            strncpy(t, "\\frac", 5);    /* insert new \frac */
            t += 5;
            if (*first != '{') {
                *t = '{';
                t++;
            }
            /* add { if missing */
            strncpy(t, first, (size_t) (last - first)); /* copy A}{B */
            t += last - first;

            if (*last != '}') {
                *t = '}';
                t++;
            }
            /* add } if missing */
            strcpy(t, last);    /* everything after {A\over B} */
            free(eq);
            eq = s;
            p = eq;
        } else
            p = mid + 5;
        diagnostics(6, "ConvertOverToFrac current <%s>", eq);
    }
    *equation = eq;
    diagnostics(4, "ConvertOverToFrac after <%s>", eq);
}

static int EquationGetsNoNumber(const char *s)
{
  if (strstr(s, "\\nonumber"))
      return TRUE;
  if (strstr(s, "\\notag"))
      return TRUE;
  
  return FALSE;
}


static void WriteEquationAsRTF(int code, char **eq)

/******************************************************************************
 purpose   : Translate equation to RTF 
 ******************************************************************************/
{
    int EQ_Needed;

    EQ_Needed = EquationNeedsFields(*eq);

    PrepareRtfEquation(code, EQ_Needed);
    ConvertOverToFrac(eq);
    fprintRTF("{");
    ConvertString(*eq);
    fprintRTF("}");
    FinishRtfEquation(code, EQ_Needed);
}

void CmdEquation(int code)

/******************************************************************************
 purpose   : Handle everything associated with equations
 ******************************************************************************/
{
    char *pre=NULL, *eq, *post=NULL;
    int inline_equation, number, true_code;

    true_code = code & ~ON;

    if (!(code & ON || code==EQN_ENSUREMATH))
        return;

    if (code==EQN_ENSUREMATH)
      eq = getBraceParam();
    else
      SlurpEquation(code, &pre, &eq, &post);

    diagnostics(4, "Entering CmdEquation --------%x\n<%s>\n<%s>\n<%s>", code, pre, eq, post);

    inline_equation = (true_code == EQN_MATH) || 
                      (true_code == EQN_DOLLAR) || 
                      (true_code == EQN_RND_OPEN) ||
                      (true_code == EQN_ENSUREMATH);

    number = getCounter("equation");

    if (g_equation_comment)
        WriteEquationAsComment(pre, eq, post);

    if (g_equation_raw_latex)
        WriteEquationAsRawLatex(pre, eq, post);

    diagnostics(4, "inline=%d  inline_bitmap=%d", inline_equation, g_equation_inline_bitmap);
    diagnostics(4, "inline=%d display_bitmap=%d", inline_equation, g_equation_display_bitmap);
    diagnostics(4, "inline=%d  inline_rtf   =%d", inline_equation, g_equation_inline_rtf);
    diagnostics(4, "inline=%d display_rtf   =%d", inline_equation, g_equation_display_rtf);

    if ((inline_equation && g_equation_inline_bitmap) || (!inline_equation && g_equation_display_bitmap)) {
      if (true_code == EQN_ALIGN || true_code == EQN_ARRAY) {
            char *s, *t;

            s = eq;
            diagnostics(4, "eqnarray whole = <%s>", s);
            do {
                t = strstr(s, "\\\\");
                if (t) *t = '\0';
                g_suppress_equation_number = EquationGetsNoNumber(s);
                PrepareRtfEquation(true_code, FALSE);

                  if (true_code == EQN_ARRAY)
                  WriteLatexAsBitmap("\\begin{eqnarray*}", s, "\\end{eqnarray*}");
                else
                  WriteLatexAsBitmap("\\begin{align*}", s, "\\end{align*}");

                FinishRtfEquation(true_code, FALSE);
                if (t) s = t + 2;
            } while (t);
                   
        } else {
            PrepareRtfEquation(true_code, FALSE);
            if (true_code == EQN_EQUATION && g_amsmath_package)
                  g_suppress_equation_number = EquationGetsNoNumber(eq);
            WriteLatexAsBitmap(pre, eq, post);
            FinishRtfEquation(true_code, FALSE);
        }
    }

    if ((inline_equation && g_equation_inline_rtf) || (!inline_equation && g_equation_display_rtf)) {
        setCounter("equation", number);
        WriteEquationAsRTF(true_code, &eq);
    }

/* balance \begin{xxx} with \end{xxx} call */
    if (true_code == EQN_MATH     || true_code == EQN_DISPLAYMATH   ||
        true_code == EQN_EQUATION || true_code == EQN_EQUATION_STAR ||
        true_code == EQN_ARRAY    || true_code == EQN_ARRAY_STAR    ||
        true_code == EQN_ALIGN    || true_code == EQN_ALIGN_STAR)
        ConvertString(post);

    free(pre);
    free(eq);
    free(post);

}

/******************************************************************************
 purpose   : Handle \ensuremath
 ******************************************************************************/
void CmdEnsuremath(int code)
{
      int mode = getTexMode();

    diagnostics(4, "Entering CmdEnsuremath");
      if (mode == MODE_MATH || mode == MODE_DISPLAYMATH) {
            char *eq = getBraceParam();
        diagnostics(4, "already in math mode <%s>", eq);
            ConvertString(eq);
            free(eq);
      } else {
        diagnostics(4, "need to start new equation");
            CmdEquation(EQN_ENSUREMATH);
      }
}


void CmdRoot(int code)

/******************************************************************************
 purpose: converts \sqrt{x} or \root[\alpha]{x+y}
******************************************************************************/
{
    char *root = NULL;
    char *power = NULL;

    power = getBracketParam();
    root = getBraceParam();

    if (g_fields_use_EQ) {
        fprintRTF(" \\\\R(");
        if (power && strlen(power) > 0)
            ConvertString(power);
        fprintRTF("%c", g_field_separator);
        ConvertString(root);
        fprintRTF(")");
    } else {
        if (power && strlen(power) > 0) {
            fprintRTF("{\\up%d\\fs%d ", script_shift(), script_size());
            ConvertString(power);
            fprintRTF("}");
        }
        CmdSymbolChar(0xd6);
        fprintRTF("(");
        ConvertString(root);
        fprintRTF(")");
    }

    if (power)
        free(power);
    if (root)
        free(root);
}

void CmdFraction(int code)

/******************************************************************************
 purpose: converts \frac{x}{y}
******************************************************************************/
{
    char *denominator, *numerator, *nptr, *dptr;

    numerator = getBraceParam();
    nptr = strdup_noendblanks(numerator);
    skipSpaces();
    denominator = getBraceParam();
    dptr = strdup_noendblanks(denominator);

    free(numerator);
    free(denominator);
    diagnostics(4, "CmdFraction -- numerator   = <%s>", nptr);
    diagnostics(4, "CmdFraction -- denominator = <%s>", dptr);

    if (g_fields_use_EQ) {
        fprintRTF(" \\\\F(");
        ConvertString(nptr);
        fprintRTF("%c", g_field_separator);
        ConvertString(dptr);
        fprintRTF(")");
    } else {
        fprintRTF(" ");
        ConvertString(nptr);
        fprintRTF("/");
        ConvertString(dptr);
        fprintRTF(" ");
    }

    free(nptr);
    free(dptr);
}

void CmdArrows(int code)

/******************************************************************************
 converts: amssymb \leftrightarrows and \rightleftarrows
 ******************************************************************************/
{
    int size = (int) (CurrentFontSize() / 4.5);

    fprintRTF(" \\\\o ({\\up%d ", size);

    switch (code) {
        case LEFT_RIGHT:
            ConvertString("\\leftarrow");
            fprintRTF("}%c{\\dn%d ", g_field_separator, size);
            ConvertString("\\rightarrow");
            break;

        case RIGHT_LEFT:
            ConvertString("\\rightarrow");
            fprintRTF("}%c{\\dn%d ", g_field_separator, size);
            ConvertString("\\leftarrow");
            break;

        case RIGHT_RIGHT:
            ConvertString("\\rightarrow");
            fprintRTF("}%c{\\dn%d ", g_field_separator, size);
            ConvertString("\\rightarrow");
            break;

        case LEFT_LEFT:
            ConvertString("\\leftarrow");
            fprintRTF("}%c{\\dn%d ", g_field_separator, size);
            ConvertString("\\leftarrow");
            break;

        case LONG_LEFTRIGHT:
            ConvertString("\\longleftarrow");
            fprintRTF("}%c{\\dn%d ", g_field_separator, size);
            ConvertString("\\longrightarrow");
            break;

        case LONG_RIGHTLEFT:
            ConvertString("\\longrightarrow");
            fprintRTF("}%c{\\dn%d ", g_field_separator, size);
            ConvertString("\\longleftarrow");
            break;

        case LONG_LEFT:
            ConvertString("\\leftarrow");
            CmdSymbolChar(0xbe);  /* extension character */
            break;

        case LONG_RIGHT:
            CmdSymbolChar(0xbe);  /* extension character */
            ConvertString("\\rightarrow");
            break;
    }
    fprintRTF("}) ");
}

void CmdLim(int code)

/******************************************************************************
 purpose: handles \lim
parameter: 0=\lim, 1=\limsup, 2=\liminf
 ******************************************************************************/
{
    char cThis, *s, *lower_limit = NULL;

    cThis = getNonBlank();
    if (cThis == '_')
        lower_limit = getBraceParam();
    else
        ungetTexChar(cThis);

    if (code == 0)
        s = strdup("lim");
    else if (code == 1)
        s = strdup("lim sup");
    else
        s = strdup("lim inf");

    if (g_fields_use_EQ) {
        if (lower_limit)
            fprintRTF("\\\\a\\\\ac(");

        fprintRTF("%s", s);

        if (lower_limit) {
            fprintRTF("%c", g_field_separator);
            ConvertString(lower_limit);
            fprintRTF(")");
        }

    } else {
        fprintRTF("%s ", s);
        if (lower_limit) {
            fprintRTF("{\\dn%d\\fs%d ", script_shift(), script_size());
            ConvertString(lower_limit);
            fprintRTF("}");
        }

    }

    free(s);
}

void CmdIntegral(int code)

/******************************************************************************
 purpose: converts integral symbol and the "exponent" and "subscript" fields
parameter: type of operand
 ******************************************************************************/
{
    char *upper_limit = NULL;
    char *lower_limit = NULL;
    int possible_limits = TRUE;
      char * command = NULL;
    char cThis;
      
      diagnostics(4, "Entering CmdIntegral");
      
    /* is there an exponent/subscript ? */
    cThis = getNonBlank();

    if (cThis == '\\') {        /* accept \nolimits and \limits */
        char *command;

        ungetTexChar(cThis);
        command = getSimpleCommand();
        if (strcmp(command, "\\nolimits") == 0) {
            free(command);
            command = NULL;
            possible_limits = FALSE;
        } else if (strcmp(command, "\\limits") == 0) {
            free(command);
            command = NULL;
            cThis = getNonBlank();
        } else {
            possible_limits = FALSE;
        }    
    }
    
    if (possible_limits) {
            if (cThis == '_')
                  lower_limit = getBraceParam();
            else if (cThis == '^')
                  upper_limit = getBraceParam();
            else
                  ungetTexChar(cThis);
      
            if (upper_limit || lower_limit) {
                  cThis = getNonBlank();
                  if (cThis == '_')
                        lower_limit = getBraceParam();
                  else if (cThis == '^')
                        upper_limit = getBraceParam();
                  else
                        ungetTexChar(cThis);
            }
      }
      
    if (g_fields_use_EQ) {

        fprintRTF(" \\\\i ");
        switch (code) {
            case 4:
                if (upper_limit || lower_limit)
                    fprintRTF("( %c %c )\\\\I", g_field_separator, g_field_separator);
                else
                    fprintRTF("\\\\in( %c %c )\\\\I", g_field_separator, g_field_separator);
                /* \iiint --- fall through */
            case 3:
                if (upper_limit || lower_limit)
                    fprintRTF("( %c %c )\\\\I", g_field_separator, g_field_separator);
                else
                    fprintRTF("\\\\in( %c %c )\\\\I", g_field_separator, g_field_separator);
                /* \iint --- fall through */
            case 0:
                if (upper_limit || lower_limit)
                    fprintRTF("(", g_field_separator, g_field_separator);
                else
                    fprintRTF("\\\\in(", g_field_separator, g_field_separator);
                break;
            case 1:
                fprintRTF("\\\\su(");
                break;
            case 2:
                fprintRTF("\\\\pr(");
                break;
            default:
                diagnostics(ERROR, "Illegal code to CmdIntegral");
        }

        if (lower_limit)
            ConvertString(lower_limit);
        fprintRTF("%c", g_field_separator);
        if (upper_limit)
            ConvertString(upper_limit);
        fprintRTF("%c )", g_field_separator);

    } else {

        switch (code) {
            case 0:
                CmdSymbolChar(0xf2);
                break;
            case 1:
                CmdSymbolChar(0xe5);
                break;
            case 2:
                CmdSymbolChar(0xd5);
                break;
            case 3:  /* \iint  */
                CmdSymbolChar(0xf2);
                CmdSymbolChar(0xf2);
                break;
            case 4:  /* \iiint  */
                CmdSymbolChar(0xf2);
                CmdSymbolChar(0xf2);
                CmdSymbolChar(0xf2);
                break;
                
            default:
                diagnostics(ERROR, "Illegal code to CmdIntegral");
        }

        if (lower_limit) {
            fprintRTF("{\\dn%d\\fs%d ", script_shift(), script_size());
            ConvertString(lower_limit);
            fprintRTF("}");
        }
        if (upper_limit) {
            fprintRTF("{\\up%d\\fs%d ", script_shift(), script_size());
            ConvertString(upper_limit);
            fprintRTF("}");
        }
    }

      if (command) {
            ConvertString(command);
            free(command);
      }
    if (lower_limit)
        free(lower_limit);
    if (upper_limit)
        free(upper_limit);
}

void SubSupWorker(bool big)

/******************************************************************************
 purpose   : Stack a superscript and a subscript together  
 ******************************************************************************/
{
    int vertical_shift;
    char cThis;
    char *upper_limit = NULL;
    char *lower_limit = NULL;

    diagnostics(4, "SubSupWorker() ... big=%d",big);
    for (;;) {
        cThis = getNonBlank();
        if (cThis == '_') {
            if (lower_limit)
                diagnostics(WARNING, "Double subscript");
            lower_limit = getBraceParam();
        } else if (cThis == '^') {
            if (upper_limit)
                diagnostics(WARNING, "Double superscript");
            upper_limit = getBraceParam();
        } else {
            ungetTexChar(cThis);
            break;
        }
    }

    diagnostics(4, "...subscript  ='%s'",lower_limit ? lower_limit : "");
    diagnostics(4, "...superscript='%s'",upper_limit ? upper_limit : "");

    if (big)
        vertical_shift = CurrentFontSize() / 1.4;
    else
        vertical_shift = CurrentFontSize() / 4;

    if (upper_limit && lower_limit) {
        fprintRTF("\\\\s\\\\up({\\fs%d ", script_size());
        ConvertString(upper_limit);
        if (big)
            fprintRTF("%c %c", g_field_separator, g_field_separator);
        else
            fprintRTF("%c", g_field_separator);
        ConvertString(lower_limit);
        fprintRTF("})");

    } else if (lower_limit) {
        fprintRTF("\\\\s\\\\do%d({\\fs%d ", vertical_shift, script_size());
        ConvertString(lower_limit);
        fprintRTF("})");

    } else if (upper_limit) {
        fprintRTF("\\\\s\\\\up%d({\\fs%d ", vertical_shift, script_size());
        ConvertString(upper_limit);
        fprintRTF("})");
    }

    if (lower_limit)
        free(lower_limit);
    if (upper_limit)
        free(upper_limit);
}

void CmdSuperscript(int code)

/******************************************************************************
 purpose   : Handles superscripts ^\alpha, ^a, ^{a}       code=0
                                  \textsuperscript{a}     code=1
 ******************************************************************************/
{
    char *s = NULL;

    diagnostics(4, "CmdSuperscript() ... ");

    if (code == 0 && g_fields_use_EQ) {
        ungetTexChar('^');
        SubSupWorker(FALSE);
        return;
    }

    if ((s = getBraceParam())) {
        fprintRTF("{\\up%d\\fs%d ", script_shift(), script_size());
        ConvertString(s);
        fprintRTF("}");
        free(s);
    }
}

void CmdSubscript(int code)

/******************************************************************************
 purpose   : Handles subscripts _\alpha, _a, _{a},           code=0
                                \textsubscript{script}       code=1
                                \lower4emA                   code=2
 ******************************************************************************/
{
    char *s = NULL;
    int size;
    

    if (code == 0) {
        diagnostics(4, "CmdSubscript() code==0, equation ");
      if (g_fields_use_EQ) {
                  ungetTexChar('_');
                  SubSupWorker(FALSE);
       }
    }

    if (code == 1) {
        diagnostics(4, "CmdSubscript() code==1, \\textsubscript ");
        s=getBraceParam();
        fprintRTF("{\\dn%d\\fs%d ", script_shift(), script_size());
        ConvertString(s);
        fprintRTF("}");
        free(s);
    }

    if (code == 2) {
        diagnostics(4, "CmdSubscript() code==2, \\lower ");
            size = getDimension();  /* size is in half-points */
        fprintRTF("{\\dn%d ", size);
        s=getBraceParam();
        if (strcmp(s,"\\hbox")==0)
            CmdBox(BOX_HBOX);
        else
            ConvertString(s);
        fprintRTF("}");
        free(s);
    }

}

/* slight extension of getSimpleCommand to allow \{ and \| */
static void getDelimOrCommand(char *delim, char **s)
{
    *delim = '\0';
    
    ungetTexChar('\\');
    *s = getSimpleCommand();
    
/* handle special cases \{ \} and \| */
    if (strlen(*s) == 1) {
        free(*s);
        *s = malloc(3 * sizeof(char));
        (*s)[0] = '\\';
        (*s)[1] = getTexChar();
        (*s)[2] = '\0';
    } 

/* commands have a simple delimiter should just use the delimiter */
    if (*s) {
        if (strcmp(*s,"\\{")      ==0 || strcmp(*s,"\\lbrace")==0)
            *delim = '{';
        if (strcmp(*s,"\\}")      ==0 || strcmp(*s,"\\rbrace")==0)
            *delim = '}';
        if (strcmp(*s,"\\bracevert")==0)
            *delim = '|';
        if (strcmp(*s,"\\langle") ==0)
            *delim = '<';
        if (strcmp(*s,"\\rangle") ==0) {
            *delim ='>';
        }
        
        if (*delim) {
            free (*s);
            *s = NULL;
        }
    }
}

/******************************************************************************
 purpose   : Handles \left \right
                   to properly handle \left. or \right. would require prescanning the
                   entire equation.  
 ******************************************************************************/
void CmdLeftRight(int code)
{
    char ldelim, rdelim;
    char *contents;
    char *lcommand = NULL;
    char *rcommand = NULL;

    diagnostics(4, "CmdLeftRight() ... ");
    ldelim = getNonSpace();
    
    if (ldelim=='\0') {
        PopSource();
        ldelim = getNonSpace();
     }

    if (ldelim == '\\') getDelimOrCommand(&ldelim, &lcommand);

    contents = getLeftRightParam();
    rdelim = getNonSpace();

    if (rdelim == '\\') getDelimOrCommand(&rdelim, &rcommand);
    
    if (code == 1)
        diagnostics(ERROR, "\\right without opening \\left");

    diagnostics(4, "CmdLeftRight() ... \\left <%c> \\right <%c>", ldelim, rdelim);
      
    if (g_fields_use_EQ) {

        fprintRTF(" \\\\b ");

        /* these first four cases () {} [] <> are most common and work best without \lc and \rc */
        if (ldelim == '(' && rdelim == ')') {
            fprintRTF("(");
            goto finish;
        }

        if (ldelim == '{' && rdelim == '}') {
            fprintRTF("\\\\bc\\\\\\{ (");
            goto finish;
        }

        if (ldelim == '[' && rdelim == ']') {
            fprintRTF("\\\\bc\\\\[ (");
            goto finish;
        }

        if (ldelim == '<' && rdelim == '>') {
            fprintRTF("\\\\bc\\\\< (");
            goto finish;
        }

        /* insert left delimiter if it is not a '.' */
        if (ldelim == '{' || ldelim == '}' || ldelim == '(' || ldelim == ')')
            fprintRTF("\\\\lc\\\\\\%c", ldelim);
        else if (ldelim && ldelim != '.')
            fprintRTF("\\\\lc\\\\%c", ldelim);
        else if (lcommand) {
            fprintRTF("\\\\lc\\\\");
            ConvertString(lcommand);
        }

        /* insert right delimiter if it is not a '.' */
        if (rdelim == '{' || rdelim == '}' || rdelim == '(' || rdelim == ')')
            fprintRTF("\\\\rc\\\\\\%c", rdelim);
        else if (rdelim && rdelim != '.')
            fprintRTF("\\\\rc\\\\%c", rdelim);
        else if (rcommand) {
             fprintRTF("\\\\rc\\\\");
             ConvertString(rcommand);
        }
        
        /* start bracketed equation */
        fprintRTF(" (");

      finish:
        ConvertString(contents);
        fprintRTF(")");
        SubSupWorker(TRUE);     /* move super or subscripts a lot */

    } else {                    /* g_fields_use_EQ */

        putRtfCharEscaped(ldelim);
        ConvertString(contents);
        putRtfCharEscaped(rdelim);
    }

    if (lcommand) free(lcommand);
    if (rcommand) free(rcommand);
}

void CmdArray(int code)

/******************************************************************************
 purpose   : Handles \begin{array}[c]{ccc} ... \end{array}
 ******************************************************************************/
{
    char *v_align, *col_align, *s;
    int n = 0;

    if (code & ON) {
        v_align = getBracketParam();
        col_align = getBraceParam();
        diagnostics(4, "CmdArray() ... \\begin{array}[%s]{%s}", v_align ? v_align : "", col_align);
        if (v_align)
            free(v_align);

        s = col_align;
        while (*s) {
            if (*s == 'c' || *s == 'l' || *s == 'r')
                n++;
            s++;
        }
        free(col_align);

        fprintRTF(" \\\\a \\\\ac \\\\co%d (", n);
        g_processing_arrays++;

    } else {
        fprintRTF(")");
        diagnostics(4, "CmdArray() ... \\end{array}");
        g_processing_arrays--;
    }
}

void CmdMatrix(int code)

/******************************************************************************
 purpose   : Does not handle plain tex \matrix command, but does not
             produce improper RTF either.
 ******************************************************************************/
{
    char *contents;

    fprintRTF(" matrix not implemented ");
    contents = getBraceParam();
    free(contents);
}

void CmdStackrel(int code)

/******************************************************************************
 purpose   : Handles \stackrel{a}{=}
 ******************************************************************************/
{
    char *numer, *denom;
    int size;

    size = CurrentFontSize() / 1.2;
    numer = getBraceParam();
    denom = getBraceParam();
    diagnostics(4, "CmdStackrel() ... \\stackrel{%s}{%s}", numer, denom);

    if (g_fields_use_EQ) {
        fprintRTF(" \\\\a ({\\fs%d ", size);
        ConvertString(numer);
        fprintRTF("}%c", g_field_separator);
        ConvertString(denom);
        fprintRTF(") ");

    } else {
        diagnostics(WARNING, "sorry stackrel requires fields");
        fprintRTF("{");
        ConvertString(numer);
        fprintRTF(" ");
        ConvertString(denom);
        fprintRTF("}");
    }

    free(numer);
    free(denom);
}

/******************************************************************************
 purpose   : Handles \overline{a}
 ******************************************************************************/
void CmdOverLine(int code)
{
    char *argument;

    argument = getBraceParam();
    diagnostics(4, "CmdOverLine() ... \\overline{%s}", argument);

    if (g_fields_use_EQ) {
        fprintRTF(" \\\\x\\\\to( ");
        ConvertString(argument);
        fprintRTF(") ");

    } else {
        diagnostics(WARNING, "sorry overline requires fields");
        fprintRTF("{");
        ConvertString(argument);
        fprintRTF("}");
    }

    free(argument);
}

Generated by  Doxygen 1.6.0   Back to index