/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include "formula.h" #include "grammar.hxx" #include "mzstring.h" #include "nodes.h" #include "mapping.h" #include "hwpeq.h" #include #ifndef DEBUG #include "hcode.h" #define rstartEl(x,y) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->startElement(x,y); } while(false) #define rendEl(x) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->endElement(x); } while(false) #define rchars(x) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->characters(x); } while(false) #define runistr(x) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->characters(x); } while(false) #define reucstr(x,y) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->characters(OUString(x,y, RTL_TEXTENCODING_EUC_KR)); } while(false) #define padd(x,y,z) mxList->addAttribute(x,y,z) #else static int indent = 0; #define inds indent++; for(int i = 0 ; i < indent ; i++) fprintf(stderr," ") #define inde for(int i = 0 ; i < indent ; i++) fprintf(stderr," "); indent-- #define indo indent--; #endif void Formula::makeMathML(Node *res) { Node *tmp = res; if( !tmp ) return; #ifdef DEBUG inds; fprintf(stderr,"\n"); #else padd("xmlns:math", "CDATA", "http://www.w3.org/1998/Math/MathML"); rstartEl("math:math", mxList); mxList->clear(); rstartEl("math:semantics", mxList); #endif if( tmp->child ) makeLines( tmp->child ); #ifdef DEBUG inds; fprintf(stderr,"\n"); indo; inde; fprintf(stderr,"\n"); #else rendEl("math:semantics"); rendEl("math:math"); #endif } void Formula::makeLines(Node *res) { Node *tmp = res; if( !tmp ) return; if( tmp->child ){ if( tmp->child->id == ID_LINES ) makeLines( tmp->child ); else makeLine( tmp->child ); } if( tmp->next ) makeLine( tmp->next ); } void Formula::makeLine(Node *res) { if( !res ) return; #ifdef DEBUG inds; fprintf(stderr,"\n"); #else rstartEl("math:mrow", mxList); #endif if( res->child ) makeExprList( res->child ); #ifdef DEBUG inde; fprintf(stderr,"\n"); #else rendEl("math:mrow"); #endif } void Formula::makeExprList(Node *res) { if( !res ) return; Node *tmp = res->child; if( !tmp ) return ; if( tmp->id == ID_EXPRLIST ){ Node *next = tmp->next; makeExprList( tmp ) ; if( next ) makeExpr( next ); } else makeExpr( tmp ); } void Formula::makeExpr(Node *res) { if( !res ) return; Node *tmp = res->child; if( !tmp ) return; switch( tmp->id ) { case ID_PRIMARYEXPR: if( tmp->next ){ #ifdef DEBUG inds; fprintf(stderr,"\n"); #else rstartEl("math:mrow", mxList); #endif } makePrimary(tmp); if( tmp->next ){ #ifdef DEBUG inde; fprintf(stderr,"\n"); #else rendEl("math:mrow"); #endif } break; case ID_SUBEXPR: case ID_SUPEXPR: case ID_SUBSUPEXPR: makeSubSup(tmp); break; case ID_FRACTIONEXPR: case ID_OVER: makeFraction(tmp); break; case ID_DECORATIONEXPR: makeDecoration(tmp); break; case ID_SQRTEXPR: case ID_ROOTEXPR: makeRoot(tmp); break; case ID_ARROWEXPR: break; case ID_ACCENTEXPR: makeAccent(tmp); break; case ID_PARENTH: case ID_ABS: makeParenth(tmp); break; case ID_FENCE: makeFence(tmp); break; case ID_BLOCK: makeBlock(tmp); break; case ID_BEGIN: case ID_END: break; } } void Formula::makeIdentifier(Node *res) { Node *tmp = res; if( !tmp ) return; if( !tmp->value ) return; switch( tmp->id ){ case ID_CHARACTER : #ifdef DEBUG inds; fprintf(stderr,"%s\n",tmp->value); indo; #else rstartEl("math:mi", mxList); rchars(OUString::createFromAscii(tmp->value)); rendEl("math:mi"); #endif break; case ID_STRING : { #ifdef DEBUG #else rstartEl("math:mi", mxList); reucstr(tmp->value, strlen(tmp->value)); rendEl("math:mi"); #endif } break; case ID_IDENTIFIER : #ifdef DEBUG inds; fprintf(stderr,"%s\n", getMathMLEntity(tmp->value).c_str()); indo; #else rstartEl("math:mi", mxList); runistr(fromHcharStringToOUString(getMathMLEntity(tmp->value))); rendEl("math:mi"); #endif break; case ID_NUMBER : #ifdef DEBUG inds; fprintf(stderr,"%s\n",tmp->value); indo; #else rstartEl("math:mn", mxList); rchars(OUString::createFromAscii(tmp->value)); rendEl("math:mn"); #endif break; case ID_OPERATOR : case ID_DELIMITER : { #ifdef DEBUG inds; fprintf(stderr,"%s\n",tmp->value); indo; #else rstartEl("math:mo", mxList); runistr(fromHcharStringToOUString(getMathMLEntity(tmp->value))); rendEl("math:mo"); #endif break; } } } void Formula::makePrimary(Node *res) { Node *tmp = res; if( !tmp ) return ; if( tmp->child ){ if( tmp->child->id == ID_PRIMARYEXPR ){ makePrimary(tmp->child); } else{ makeIdentifier(tmp->child); } } if( tmp->next ){ makeIdentifier(tmp->next); } } void Formula::makeSubSup(Node *res) { Node *tmp = res; if( !tmp ) return; #ifdef DEBUG inds; if( res->id == ID_SUBEXPR ) fprintf(stderr,"\n"); else if( res->id == ID_SUPEXPR ) fprintf(stderr,"\n"); else fprintf(stderr,"\n"); #else if( res->id == ID_SUBEXPR ) rstartEl("math:msub", mxList); else if( res->id == ID_SUPEXPR ) rstartEl("math:msup", mxList); else rstartEl("math:msubsup", mxList); #endif tmp = tmp->child; if( res->id == ID_SUBSUPEXPR ) { makeExpr(tmp); makeBlock(tmp->next); makeBlock(tmp->next->next); } else{ makeExpr(tmp); makeExpr(tmp->next); } #ifdef DEBUG inde; if( res->id == ID_SUBEXPR ) fprintf(stderr,"\n"); else if( res->id == ID_SUPEXPR ) fprintf(stderr,"\n"); else fprintf(stderr,"\n"); #else if( res->id == ID_SUBEXPR ) rendEl("math:msub"); else if( res->id == ID_SUPEXPR ) rendEl("math:msup"); else rendEl("math:msubsup"); #endif } void Formula::makeFraction(Node *res) { Node *tmp = res; if( !tmp ) return; #ifdef DEBUG inds; fprintf(stderr,"\n"); #else rstartEl("math:mfrac", mxList); #endif tmp = tmp->child; #ifdef DEBUG inds; fprintf(stderr,"\n"); #else rstartEl("math:mrow", mxList); #endif if( res->id == ID_FRACTIONEXPR ) makeBlock(tmp); else makeExprList(tmp); #ifdef DEBUG inde; fprintf(stderr,"\n"); inds; fprintf(stderr,"\n"); #else rendEl("math:mrow"); rstartEl("math:mrow", mxList); #endif if( res->id == ID_FRACTIONEXPR ) makeBlock(tmp->next); else makeExprList(tmp->next); #ifdef DEBUG inde; fprintf(stderr,"\n"); inde; fprintf(stderr,"\n"); #else rendEl("math:mrow"); rendEl("math:mfrac"); #endif } void Formula::makeDecoration(Node *res) { int isover = 1; Node *tmp = res->child; if( !tmp ) return; if( !strncmp(tmp->value,"under", 5) ) isover = 0; #ifdef DEBUG inds; if( isover ) fprintf(stderr,"\n"); else fprintf(stderr,"\n"); #else /* FIXME: no idea when 'accent' is true or false. */ if( isover ){ padd("accent","CDATA","true"); rstartEl("math:mover", mxList); } else{ padd("accentunder","CDATA","true"); rstartEl("math:munder", mxList); } mxList->clear(); #endif makeBlock(tmp->next); #ifdef DEBUG inds; fprintf(stderr,"%s\n", getMathMLEntity(tmp->value).c_str()); indo; #else rstartEl("math:mo", mxList); runistr(fromHcharStringToOUString(getMathMLEntity(tmp->value))); rendEl("math:mo"); #endif #ifdef DEBUG inde; if( isover ) fprintf(stderr,"\n"); else fprintf(stderr,"\n"); #else if( isover ) rendEl("math:mover"); else rendEl("math:munder"); #endif } void Formula::makeRoot(Node *res) { Node *tmp = res; if( !tmp ) return; #ifdef DEBUG inds; if( tmp->id == ID_SQRTEXPR ) fprintf(stderr,"\n"); else fprintf(stderr,"\n"); #else if( tmp->id == ID_SQRTEXPR ) rstartEl("math:msqrt", mxList); else rstartEl("math:mroot", mxList); #endif if( tmp->id == ID_SQRTEXPR ){ makeBlock(tmp->child); } else{ makeBracket(tmp->child); makeBlock(tmp->child->next); } #ifdef DEBUG inde; if( tmp->id == ID_SQRTEXPR ) fprintf(stderr,"\n"); else fprintf(stderr,"\n"); #else if( tmp->id == ID_SQRTEXPR ) rendEl("math:msqrt"); else rendEl("math:mroot"); #endif } void Formula::makeAccent(Node *res) { makeDecoration( res ); } void Formula::makeParenth(Node *res) { Node *tmp = res; if( !tmp ) return; #ifdef DEBUG inds; fprintf(stderr,"\n"); inds; if( tmp->id == ID_PARENTH ){ fprintf(stderr,"(\n"); } else fprintf(stderr,"|\n"); indo; inds; fprintf(stderr,"\n"); #else rstartEl("math:mrow", mxList); rstartEl("math:mo", mxList); if( tmp->id == ID_PARENTH ) rchars("("); else rchars("|"); rendEl("math:mo"); rstartEl("math:mrow", mxList); #endif if( tmp->child ) makeExprList(tmp->child); #ifdef DEBUG inde; fprintf(stderr,"\n"); inds; if( tmp->id == ID_PARENTH ) fprintf(stderr,")\n"); else fprintf(stderr,"|\n"); indo; inde; fprintf(stderr,"\n"); #else rendEl("math:mrow"); rstartEl("math:mo", mxList); if( tmp->id == ID_PARENTH ) rchars(")"); else rchars("|"); rendEl("math:mo"); rendEl("math:mrow"); #endif } void Formula::makeFence(Node *res) { Node *tmp = res->child; #ifdef DEBUG inds; fprintf(stderr,"\n", getMathMLEntity(tmp->value).c_str(), getMathMLEntity(tmp->next->next->value).c_str()); #else padd("open", "CDATA", OUString(reinterpret_cast(getMathMLEntity(tmp->value).c_str()))); padd("close", "CDATA", OUString(reinterpret_cast(getMathMLEntity(tmp->next->next->value).c_str()))); rstartEl("math:mfenced", mxList); mxList->clear(); #endif makeExprList(tmp->next); #ifdef DEBUG inde; fprintf(stderr,"\n"); #else rendEl("math:mfenced"); #endif } void Formula::makeBracket(Node *res) { makeBlock(res); } void Formula::makeBlock(Node *res) { #ifdef DEBUG inds; fprintf(stderr,"\n"); #else rstartEl("math:mrow", mxList); #endif if( res->child ) makeExprList(res->child); #ifdef DEBUG inde; fprintf(stderr,"\n"); #else rendEl("math:mrow"); #endif } void Formula::parse() { Node *res = nullptr; if( !eq ) return; MzString a; // fprintf(stderr,"\n\n[BEFORE]\n[%s]\n",eq); eq2latex(a,eq); int idx=a.find(sal::static_int_cast(0xff)); while(idx){ //printf("idx = [%d]\n",idx); a.replace(idx,0x20); if((idx = a.find(sal::static_int_cast(0xff),idx+1)) < 0) break; } char *buf = static_cast(malloc(a.length()+1)); bool bStart = false; int i, j; for( i = 0, j=0 ; i < a.length() ; i++){ // rtrim and ltrim 32 10 13 if( bStart ){ buf[j++] = a[i]; } else{ if( a[i] != 32 && a[i] != 10 && a[i] != 13){ bStart = true; buf[j++] = a[i]; } } } buf[j] = 0; for( i = j-1 ; i >= 0 ; i++ ){ if( buf[i] == 32 || buf[i] == 10 || buf[i] == 13 ){ buf[i] = 0; } else break; } // fprintf(stderr,"\n\n[RESULT]\n[%s]\n",a.c_str()); if( buf[0] != '\0' ) res = mainParse( a.c_str() ); else res = nullptr; free(buf); if( res ){ makeMathML( res ); } nodelist.clear(); } void Formula::trim() { int len = strlen(eq); char *buf = static_cast(malloc(len+1)); bool bStart = false; int i, j; for( i = 0, j=0 ; i < len ; i++){ // rtrim and ltrim 32 10 13 if( bStart ){ buf[j++] = eq[i]; } else{ if( eq[i] != 32 && eq[i] != 10 && eq[i] != 13){ bStart = true; buf[j++] = eq[i]; } } } buf[j] = 0; for( i = j-1 ; i >= 0 ; i++ ){ if( buf[i] == 32 || buf[i] == 10 || buf[i] == 13 ){ buf[i] = 0; } else break; } if( buf[0] != '\0' ) strcpy(eq, buf); else eq = nullptr; free(buf); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */