* Bugs 16071+16072+16075 fixed: prettyprint() debugged & a bit improved
[scilab.git] / scilab / modules / string / macros / prettyprint.sci
index c120681..f0766c5 100644 (file)
@@ -1,7 +1,7 @@
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
 // Copyright (C) 2009-2010 - Calixte Denizet
-//
 // Copyright (C) 2012 - 2016 - Scilab Enterprises
+// Copyright (C) 2019 - Samuel GOUGEON
 //
 // This file is hereby licensed under the terms of the GNU GPL v2.0,
 // pursuant to article 5.3.4 of the CeCILL v.2.1.
@@ -69,60 +69,31 @@ function str = prettyprint(a, exportFormat, delimiter, processByElement, isWrapp
     //
     // Authors
     // Calixte Denizet
+    // Samuel Gougeon
 
-    nargs = argn(2);
-
-    select nargs
-    case 0 then
+    if argn(2)<1 | argn(2)>5
         error(msprintf(gettext("%s: Wrong number of input argument(s): %d to %d expected."),"prettyprint",1,4));
-    case 1 then
-        exportFormat="latex";
-        delimiter = "(";
-        processByElement = %F;
-        isWrapped = %T;
-    case 2 then
-        if type(exportFormat) <> 10 then
-            error(msprintf(gettext("%s: Wrong type for input argument #%d: String expected.\n"),"prettyprint",2));
-        end
-        delimiter = "(";
-        processByElement = %F;
-        isWrapped = %T;
-    case 3 then
-        if type(exportFormat) <> 10 then
-            error(msprintf(gettext("%s: Wrong type for input argument #%d: String expected.\n"),"prettyprint",2));
-        end
-        if type(delimiter) <> 10 | (delimiter <> "(" &  delimiter <> "[" & delimiter <> "|" & delimiter <> "||" & delimiter <> "{" & delimiter <> "") then
-            error(msprintf(gettext("%s: Wrong value for input argument #%d: ''%s'', ''%s'', ''%s'', ''%s'', ''%s'' or ''%s'' expected.\n"),"prettyprint",3,"(","[","|","||","{",""));
-        end
-        processByElement = %F;
-        isWrapped = %T;
-    case 4 then
-        if type(exportFormat) <> 10 then
-            error(msprintf(gettext("%s: Wrong type for input argument #%d: String expected.\n"),"prettyprint",2));
-        end
-        if type(delimiter) <> 10 | (delimiter <> "(" &  delimiter <> "[" & delimiter <> "|" & delimiter <> "||" & delimiter <> "{" & delimiter <> "") then
-            error(msprintf(gettext("%s: Wrong value for input argument #%d: ''%s'', ''%s'', ''%s'', ''%s'', ''%s'' or ''%s'' expected.\n"),"prettyprint",3,"(","[","|","||","{",""));
-        end
-        if type(processByElement) <> 4 then
-            error(msprintf(gettext("%s: Wrong type for argument #%d: Boolean expected.\n"),"prettyprint",4));
-        end
-        isWrapped = %T;
-    case 5
-        if type(exportFormat) <> 10 then
-            error(msprintf(gettext("%s: Wrong type for input argument #%d: String expected.\n"),"prettyprint",2));
-        end
-        if type(delimiter) <> 10 | (delimiter <> "(" &  delimiter <> "[" & delimiter <> "|" & delimiter <> "||" & delimiter <> "{" & delimiter <> "") then
-            error(msprintf(gettext("%s: Wrong value for input argument #%d: ''%s'', ''%s'', ''%s'', ''%s'', ''%s'' or ''%s'' expected.\n"),"prettyprint",3,"(","[","|","||","{",""));
-        end
-        if type(processByElement) <> 4 then
-            error(msprintf(gettext("%s: Wrong type for argument #%d: Boolean expected.\n"),"prettyprint",4));
-        end
-        if type(isWrapped) <> 4 then
-            error(msprintf(gettext("%s: Wrong type for argument #%d: Boolean expected.\n"),"prettyprint",5));
-        end
-    else
-        error(msprintf(gettext("%s: Wrong number of input arguments: %d to %d expected"),"prettyprint",1,4));
     end
+
+    if ~isdef("exportFormat","l")    , exportFormat = "latex", end
+    if ~isdef("delimiter","l")       , delimiter = "("       , end
+    if ~isdef("processByElement","l"), processByElement = %F,  end
+    if ~isdef("isWrapped","l")       , isWrapped = %T,         end
+
+    if type(exportFormat) <> 10 then
+        error(msprintf(gettext("%s: Wrong type for input argument #%d: String expected.\n"),"prettyprint",2));
+    end
+    if type(delimiter) <> 10 | and(delimiter <> ["(" "[" "|" "||" "{" ""]) then
+        error(msprintf(gettext("%s: Wrong value for input argument #%d: ''%s'', ''%s'', ''%s'', ''%s'', ''%s'' or ''%s'' expected.\n"),"prettyprint",3,"(","[","|","||","{",""));
+    end
+    if type(processByElement) <> 4 then
+        error(msprintf(gettext("%s: Wrong type for argument #%d: Boolean expected.\n"),"prettyprint",4));
+    end
+    if type(isWrapped) <> 4 then
+        error(msprintf(gettext("%s: Wrong type for argument #%d: Boolean expected.\n"),"prettyprint",5));
+    end
+
+    // ---------------------
     try
         execstr("[plus,minus,img,op,cp,ow,cw,d2s]=" + exportFormat + "conf()");
     catch
@@ -131,16 +102,18 @@ function str = prettyprint(a, exportFormat, delimiter, processByElement, isWrapp
 
     typ = type(a);
 
+
     select typ
-        //Scalar type : real or complex
     case 1 then
+        // number : real or complex
         if or(isinf(a) | isnan(a)) | norm(imag(a)) > %eps * norm(real(a)) then
             str = comp2str(a,plus,minus,img,d2s);
         else
             str = comp2str(real(a),plus,minus,img,d2s);
         end
-        //Polynomial type
+
     case 2 then
+        //Polynomial type
         x = varn(a);
         C = coeff(a);
         [m,n] = size(a);
@@ -163,27 +136,58 @@ function str = prettyprint(a, exportFormat, delimiter, processByElement, isWrapp
                 end
             end
         end
-        //The null polynomial is represented by '' so we must replace it by '0'
-        str(str == "") = d2s(0);
-        //Boolean type
+        //The null polynomial is represented by '' so we must replace it by '0z'
+        if exportFormat=="mathml"
+            str(str == "") = d2s(0) + "<mi>" + x + "</mi>";
+        else
+            str(str == "") = d2s(0) + x;
+        end
+
     case 4 then
+        //Boolean type
         str = "F" + emptystr(a);
         str(a) = "T";
         execstr("str=" + exportFormat + "exp(str,1)");
-        //Int type
+
     case 8 then
+        //Int type
         str = d2s(a);
-        //String type
+
     case 10 then
+        //String type
+        if or(exportFormat == ["tex" "latex"])
+            a = strsubst(a, "\", "\backslash\!")
+            a = strsubst(a, "$", "\$")
+            a = strsubst(a, "%", "\%")
+            a = strsubst(a, "&", "\&")
+            a = strsubst(a, "{", "\{")
+            a = strsubst(a, "}", "\}")
+            a = strsubst(a, "~", "\sim\!")
+            a = strsubst(a, "^", "\^\;\,")
+            a = strsubst(a, "<", "\!<\!")
+            a = strsubst(a, ">", "\!>\!")
+            // a = strsubst(a, "_", "\_ ")  // not required
+            // a = strsubst(a, "#", "\#")   // not required
+            if ~processByElement | isWrapped
+                a = "\mathsf{\text{" + a + "}}" // default protection of spaces
+                // Otherwise: we let the user choose the type of text
+                // encapsulation
+            end
+        elseif exportFormat == "mathml"
+            a = strsubst(a, "<", "&lt;")
+            // " ' and & do not need protection
+            execstr("a = " + exportFormat + "exp(a,1)");
+        end
         str = a;
-        //Tlist type
+
     case 16 then
+        //Tlist type
         t = a(1);
         select t(1)
             //Rationnal type
         case "r" then
-            num = prettyprint(a("num"),exportFormat,"(",%T,%F);
-            den = prettyprint(a("den"),exportFormat,"(",%T,%F);
+            num = prettyprint(a("num"), exportFormat, "(", %T, %F);
+            den = prettyprint(a("den"), exportFormat, "(", %T, %F);
             execstr("str=rational2" + exportFormat + "(num,den)");
             //Linear state space type
         case "lss" then
@@ -192,11 +196,12 @@ function str = prettyprint(a, exportFormat, delimiter, processByElement, isWrapp
             str = unknown_type(t(1),a,exportFormat);
             return;
         end
+
     case 17  then
-        a1=getfield(1,a);
-        select a1(1)
-            //Cell type
+        tof = typeof(a);
+        select tof
         case "ce" then
+            //Cell type
             dim = double(size(a));
             L = length(dim);
             if L >= 3 then
@@ -210,12 +215,12 @@ function str = prettyprint(a, exportFormat, delimiter, processByElement, isWrapp
                 end
             end
         else
-            str = unknown_type(a1(1),a,exportFormat);
+            str = unknown_type(tof,a,exportFormat);
             return;
         end
     else
         str = unknown_type(typeof(a),a,exportFormat);
-        return;
+        return
     end
 
     [m,n] = size(a);
@@ -228,6 +233,10 @@ function str = prettyprint(a, exportFormat, delimiter, processByElement, isWrapp
     end
 endfunction
 
+// ----------------------------------------------------------------------------
+
+// MATHML
+// ======
 //This function gives different elements of configuration
 //plus is '+', minus is '-', img is sqrt(-1), op and cp are opening ang closing
 //parenthesis (useful to generate complex coeff in polynomials), ow and cw are
@@ -247,7 +256,7 @@ endfunction
 //This function generates var^n (useful for polynomials)
 function str = mathmlexp(var,n)
     if n >= 2 then
-        str = "<msup><mi>" + var + "</mi><mn>" + string(n) + "</mn></msup>";
+        str = "<msup><mi>" + var + "</mi><mn>" + string(n) + "</mn></msup> ";
     elseif n == 1 then
         str = "<mi>" + var + "</mi>";
     else
@@ -257,31 +266,43 @@ endfunction
 
 //This function creates a fraction with the given numerator and denominator
 function str = rational2mathml(num,den)
-    str = "<mfrac><mrow>" + num + "</mrow><mrow>" + den + "</mrow></mfrac>";
+    nl = ascii(10)
+    str = "<mfrac>" + nl + ..
+            "<mrow>" + nl + num + nl + "</mrow>" + nl + ..
+            "<mrow>" + nl + den + nl + "</mrow>" + nl + ..
+          "</mfrac>";
 endfunction
 
 //This function converts a double into a mathml string
 //Negative and positive are handled and the scientific notation too
 function str = mathmldbl2str(x)
     if x == %inf then
-        str = "<infinity/>";
+        str = "<mi>∞</mi>";
     elseif x == -%inf then
-        str = "<mo>-</mo><infinity/>";
+        str = "<mo>-</mo><mi>∞</mi>";
     elseif isnan(x) then
         str = "<mi>NaN</mi>";
     else
         str= strsubst(string(x),"-","<mo>-</mo><mn>");
-        if strindex(str,"D") <> [] then
-            str = strsubst(str,"+","<mo>+</mo><mn>");
-            str = strsubst(str,"D","</mn><mo>&#x00D7;</mo><msup><mn>10</mn><mrow>");
-            if x > 0 then
-                str = "<mn>" + str;
+        if type(x) <> 8
+            if strindex(str,"D") <> [] then
+                str = strsubst(str,"+","<mo>+</mo><mn>");
+                str = strsubst(str,"D","</mn><mo>&#x00D7;</mo><msup><mn>10</mn><mrow>");
+                if x > 0 then
+                    str = "<mn>" + str;
+                end
+                str = str + "</mn></mrow></msup>";
+            elseif x >= 0 then
+                str = "<mn>" + str + "</mn>";
+            else
+                str = str + "</mn>";
             end
-            str = str + "</mn></mrow></msup>";
-        elseif x >= 0 then
-            str = "<mn>" + str + "</mn>";
         else
-            str = str + "</mn>";
+            k = x>=0
+            if k~=[]
+                str(k) =  "<mn>" + str(k)
+            end
+            str = str + "</mn>"
         end
     end
 endfunction
@@ -291,6 +312,7 @@ function str = mathmlmatrix(mat,delimiter)
     if argn(2) == 1 then
         delimiter = "(";
     end
+    nl = ascii(10)
     select delimiter
     case "[" then
         com = "<mfenced open=""["" close=""]"">";
@@ -299,7 +321,7 @@ function str = mathmlmatrix(mat,delimiter)
     case "|" then
         com = "<mfenced open=""&#x2223;"" close=""&#x2223;"">";
     case "" then
-        com = "<mfenced>";
+        com = "<mfenced open="""" close="""">";
     case "{" then
         com = "<mfenced open=""{"" close=""}"">";
     case "||" then
@@ -308,33 +330,53 @@ function str = mathmlmatrix(mat,delimiter)
         com = "<mfenced open=""("" close="")"">";
     end
     [m,n] = size(mat);
-    str = com + "<mtable>";
+    str = nl + com + nl + "<mtable>";
     for i=1:m do
-        str = str + "<mtr><mtd>" + strcat(mat(i,:),"</mtd><mtd>") + "</mtd></mtr>";
+        str = str + nl + "<mtr>" + nl + ..
+              "<mtd>" + strcat(mat(i,:),"</mtd>"+nl+"<mtd>") + "</mtd>" + nl + ..
+              "</mtr>";
     end
-    str = str + "</mtable></mfenced>";
+    str = str + nl + "</mtable>" + nl + "</mfenced>" + nl;
 endfunction
 
 //This function handles the syslin
 function str = lss2mathml(sys)
+    nl = ascii(10);
     ptp = "<mo>(</mo><mi>t</mi><mo>)</mo>";
     if sys(7) == "c" then
         der = "<mrow><mover><mi>X</mi><mo>.</mo></mover>" + ptp + "</mrow>";
     else
         der = "<mrow><mover><mi>X</mi><mo>+</mo></mover>" + ptp + "</mrow>"
     end
-    str = "<mfenced close="""" open=""{""><mtable columnalign=""right center left""><mtr><mtd>" + der + "</mtd><mtd><mo>=</mo></mtd><mtd>" + prettyprint(sys(2),"mathml","(",%F,%F) + "<mrow><mi>X</mi>" + ptp + "</mrow><mo>+</mo>" + prettyprint(sys(3),"mathml","(",%F,%F) + "<mrow><mi>U</mi>" + ptp + "</mrow></mtd></mtr><mtr><mtd><mrow><mi>Y</mi>" + ptp + "</mrow></mtd><mtd><mo>=</mo></mtd><mtd>" + prettyprint(sys(4),"mathml","(",%F,%F) + "<mrow><mi>X</mi>" + ptp + "</mrow>";
+    str = "<mfenced close="""" open=""{"">" + nl + ..
+          "<mtable columnalign=""right center left"">" + nl + ..
+          "<mtr>" + ..
+          "<mtd>" + der + "</mtd><mtd><mo>=</mo></mtd>" + ..
+          "<mtd>" + prettyprint(sys(2),"mathml","(",%F,%F) + ..
+          "<mrow><mi>X</mi>" + ptp + "</mrow><mo>+</mo>" + ..
+          prettyprint(sys(3),"mathml","(",%F,%F) + ..
+          "<mrow><mi>U</mi>" + ptp + "</mrow></mtd></mtr>" + nl + ..
+          "<mtr><mtd><mrow><mi>Y</mi>" + ptp + "</mrow></mtd>" + ..
+          "<mtd><mo>=</mo></mtd>" + ..
+          "<mtd>" + prettyprint(sys(4),"mathml","(",%F,%F) + "<mrow><mi>X</mi>" + ptp + "</mrow>";
     try
         if norm(sys(5),1) == 0 then
-            str = str + "</mtd></mtr></mtable></mfenced>";
+            str = str + "</mtd></mtr>"
         else
-            str = str + "<mo>+</mo>" + prettyprint(sys(5),"mathml","(",%F,%F) + "<mrow><mi>U</mi>" + ptp + "</mrow></mtd></mtr></mtable></mfenced>";
+            str = str + "<mo>+</mo>" + prettyprint(sys(5),"mathml","(",%F,%F) + ..
+            "<mrow><mi>U</mi>" + ptp + "</mrow></mtd></mtr>" 
         end
     catch
-        str = str + "<mo>+</mo>" + prettyprint(sys(5),"mathml","(",%F,%F) + "<mrow><mi>U</mi>" + ptp + "</mrow></mtd></mtr></mtable></mfenced>";
+        str = str + "<mo>+</mo>" + prettyprint(sys(5),"mathml","(",%F,%F) + ..
+            "<mrow><mi>U</mi>" + ptp + "</mrow></mtd></mtr>" 
     end
+    str = str + nl + "</mtable>" + nl + "</mfenced>" + nl;
 endfunction
 
+// ----------------------------------------------------------------------------
+
+// LATEX
+// =====
 function [plus,minus,img,op,cp,ow,cw,d2s] = latexconf()
     plus = "+";
     minus = "-";
@@ -354,6 +396,9 @@ function str = latexexp(var,n)
     else
         str = "";
     end
+    if typ==2 then
+        str = str + " " // Makes easier wrapping long polynomials
+    end
 endfunction
 
 function str = rational2latex(num,den)
@@ -369,8 +414,9 @@ function str = latexdbl2str(x)
         str = "{\mathrm{NaN}}";
     else
         str = string(x);
-        if strindex(str,"D") <> [] then
-            str = strsubst(str,"D","\times10^{");
+        if type(x)~=8 & strindex(str,"D") <> [] then
+            str = strsubst(str,"D+","D");
+            str = strsubst(str,"D","\!\times\!10^{");
             str = str + "}";
         end
     end
@@ -382,7 +428,10 @@ function str = lss2latex(sys)
     else
         der = "\stackrel{+}{X}(t)"
     end
-    str = "{\left\{\begin{array}{rcl}" + der + "&=&" + prettyprint(sys(2),"latex","(",%F,%F) + " X(t)+" + prettyprint(sys(3),"latex","(",%F,%F) + "U(t)\cr Y(t) &=& " + prettyprint(sys(4),"latex","(",%F,%F) + " X(t) ";
+    str = "{\left\{\begin{array}{rcl}" + der + "&=&" + ..
+            prettyprint(sys(2),"latex","(",%F,%F) + " X(t)+" + ..
+            prettyprint(sys(3),"latex","(",%F,%F) + "U(t)\cr " + ..
+            "Y(t) &=& " + prettyprint(sys(4),"latex","(",%F,%F) + " X(t) ";
     try
         if norm(sys(5),1) == 0 then
             str = str + "\end{array}\right.}";
@@ -417,15 +466,20 @@ function str = latexmatrix(mat,delimiter)
     [m,n] = size(mat);
     str = "{\begin{" + com + "}";
     if m*n == 0 then
+
         str = str + "\ ";
     else
         for i=1:m do
             str = str + strcat(mat(i,:),"&") + "\cr ";
         end
     end
+
     str = str + "\end{" + com + "}}";
 endfunction
 
+// ----------------------------------------------------------------------------
+// TEX
+// ===
 function [plus,minus,img,op,cp,ow,cw,d2s] = texconf()
     [plus,minus,img,op,cp,ow,cw,d2s] = latexconf()
 endfunction
@@ -448,7 +502,8 @@ function str = texdbl2str(x)
     else
         str = string(x);
         if strindex(str,"D") <> [] then
-            str = strsubst(str,"D","\times10^{");
+            str = strsubst(str,"D+","D");
+            str = strsubst(str,"D","\!\times\!10^{");
             str = str + "}";
         end
     end
@@ -460,7 +515,10 @@ function str = lss2tex(sys)
     else
         der = "{\buildrel + \over X(t)}"
     end
-    str = "{\left\{\eqalign{" + der + " &= " + prettyprint(sys(2),"tex","(",%F,%F) + " X(t)+" + prettyprint(sys(3),"tex","(",%F,%F) + "U(t)\cr Y(t) &= " + prettyprint(sys(4),"tex","(",%F,%F) + " X(t) ";
+    str = "{\left\{\eqalign{" + der + " &= " + ..
+          prettyprint(sys(2),"tex","(",%F,%F) + " X(t)+" + ..
+          prettyprint(sys(3),"tex","(",%F,%F) + "U(t)\cr " + ..
+          "Y(t) &= " + prettyprint(sys(4),"tex","(",%F,%F) + " X(t) ";
     try
         if norm(sys(5),1) == 0 then
             str = str + "}\right.}";
@@ -504,6 +562,8 @@ function str = texmatrix(mat,delimiter)
     str = str + "}}";
 endfunction
 
+// ==========================================================================
+
 //This function converts a complex (or a double) into a string in using the
 //function d2s (double2string) fixed by mathmlconf or latexconf.
 function str = comp2str(z,plus,minus,img,d2s)
@@ -537,7 +597,7 @@ function str = comp2str(z,plus,minus,img,d2s)
         else
             str = d2s(re);
         end
-    elseif im > 0 then
+    elseif im > 0 | im<>im then
         if im == 1 then
             str = d2s(re) + plus + img;
         else
@@ -567,9 +627,13 @@ function str = comp2coef(z,var,plus,minus,img,op,cp,d2s)
     end
     re = real(z);
     im = imag(z);
-    if var <> "" then
+    if var <> "" & var <> " " then
         if re <> 0 & im <> 0 then
-            str = plus + op + comp2str(z,plus,minus,img,d2s) + cp + var;
+            if re < 0 then
+                str = minus + op + comp2str(-z,plus,minus,img,d2s) + cp + var;
+            else
+                str = plus + op + comp2str(z,plus,minus,img,d2s) + cp + var;
+            end
         elseif re == 0 & im == 0 then
             str = "";
         elseif re == 1 & im == 0 then