/*
* #%~
* org.overture.ide.plugins.latex
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* 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 3 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, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.ide.plugins.latex.utility;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.overture.ast.intf.lex.ILexNameToken;
import org.overture.ast.lex.LexLocation;
import org.overture.ast.lex.LexNameList;
import org.overture.config.Settings;
import org.overture.interpreter.runtime.SourceFile;
import org.overture.parser.config.Properties;
public class XetexSourceFile extends SourceFile
{
private static final String CURLY_BRACKET_VDM_AL = "{vdm_al}";
private static final String CURLY_BRACKET_VDM_SL = "{vdmsl}";
private static final String CURLY_BRACKET_VDM_PP = "{vdmpp}";
private static final String CURLY_BRACKET_VDM_RT = "{vdmrt}";
private static final String BEGIN = "\\begin";
private static final String END = "\\end";
public List<String> rawLines = new Vector<String>();
public final boolean hasVdm_al;
// The argument to lstset is: escapeinside={(*@}{@*)}
public final String LST_ESCAPE_BEGIN = "(*@";
public final String LST_ESCAPE_END = "@*)";
private static final String sectionFont = "{\\jmsg{";
private static final String docFont = "{\\jmsm{";
private static final String fontEnd = "}}";
public boolean useJPNFont;
public XetexSourceFile(SourceFile source) throws IOException
{
this(source.filename, source.charset);
}
public XetexSourceFile(File filename, String charset) throws IOException
{
super(filename, charset);
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filename), charset));
String line = br.readLine();
boolean vdm_al = false;
while (line != null)
{
if (line.startsWith(BEGIN + CURLY_BRACKET_VDM_AL))
{
vdm_al = true;
}
rawLines.add(line);
line = br.readLine();
}
hasVdm_al = vdm_al;
br.close();
}
public void printCoverage(PrintWriter out, boolean headers)
{
printCoverage(out, headers, false, true);
}
public void printCoverage(PrintWriter out, boolean headers,
boolean modelOnly, boolean includeCoverageTable)
{
print(out, headers, modelOnly, includeCoverageTable, true);
}
public void print(PrintWriter out, boolean headers, boolean modelOnly,
boolean includeCoverageTable, boolean markCoverage)
{
Map<Integer, List<LexLocation>> hits = LexLocation.getMissLocations(filename);
if (headers)
{
out.println("\\documentclass[a4paper]{article}");
out.println("\\usepackage{longtable}");
// out.println("\\input{times}");
// out.println("\\input{graphicx}");
out.println("\\usepackage[color]{vdmlisting}");
out.println("\\usepackage{fullpage}");
out.println("\\usepackage{hyperref}");
out.println("%JPNFONT\\usepackage{fontspec}"); // added by his 2013/10/08
out.println("%JPNFONT\\setmainfont{Times New Roman}"); // added by his 2013/10/24
out.println("%JPNFONT\\setmonofont[Scale=0.9]{Courier New}"); // added by his 2013/10/24
out.println("%JPNFONT\\newfontfamily\\jmsm[Scale=0.92]{MS Mincho}"); // added by his 2013/10/24
out.println("%JPNFONT\\newfontfamily\\jmsg[Scale=0.92]{MS Gothic}"); // added by his 2013/10/24
out.println("\\begin{document}");
out.println("\\title{}");
out.println("\\author{}");
}
// move here
boolean endDocFound = false;
boolean inVdmAlModelTag = false;
useJPNFont = checkFont("MS Gothic");
if (!hasVdm_al)
{
out.println(BEGIN + getListingEnvironment());
inVdmAlModelTag = true; // added
}
// boolean endDocFound = false;
// boolean inVdmAlModelTag = false;
// useJPNFont = checkFont("MS Gothic");
LexNameList spans = LexLocation.getSpanNames(filename);
for (int lnum = 1; lnum <= rawLines.size(); lnum++)
{
for (ILexNameToken name : spans)
{
if (name.getLocation().getStartLine() == lnum)
{
out.println(LST_ESCAPE_BEGIN);
out.println("\\label{" + latexLabel(name.getName()) + ":"
+ name.getLocation().getStartLine() + "}");
out.println(LST_ESCAPE_END);
}
}
String line = rawLines.get(lnum - 1);
if (line.contains("\\end{document}"))
{
endDocFound = true;
break;
}
if (line.contains(BEGIN + CURLY_BRACKET_VDM_AL))
{
inVdmAlModelTag = true;
}
// if (line.contains("\\subsection{")) // added by his 2013/10/16
// {
// inVdmAlModelTag = false;
// }
if (hasVdm_al && modelOnly && !inVdmAlModelTag)
{
// continue;
}
String spaced = detab(line, Properties.parser_tabstop);
spaced = spaced.replace(BEGIN + CURLY_BRACKET_VDM_AL, BEGIN
+ getListingEnvironment()).replace(END
+ CURLY_BRACKET_VDM_AL, END + getListingEnvironment());
if (markCoverage)
{
// List<LexLocation> list = hits.get(lnum);
// out.println(markup(spaced, list));
if (inVdmAlModelTag)
{
List<LexLocation> list = hits.get(lnum);
out.println(markup(spaced, list));
} else
{
// List<LexLocation> list = hits.get(lnum);
if (spaced.contains("\\subsection{")
|| spaced.contains("\\subsubsection{"))
{
spaced = utfIncludeCheck(spaced, false);
out.println(spaced.replace(docFont, sectionFont));
} else
{
out.println(utfIncludeCheck(spaced, false));
}
}
} else
{
out.println(spaced);
}
// if (line.contains(END + getListingEnvironment()))
// {
// inVdmAlModelTag = false;
// }
if (spaced.contains(END + getListingEnvironment()))
{
inVdmAlModelTag = false;
}
}
if (!hasVdm_al)
{
out.println(END + getListingEnvironment());
inVdmAlModelTag = false; // added
}
if (includeCoverageTable)
{
out.println("\\bigskip");
out.println(createCoverageTable());
}
if (headers || endDocFound)
{
out.println("\\end{document}");
}
}
private String getListingEnvironment()
{
switch (Settings.dialect)
{
case VDM_PP:
return CURLY_BRACKET_VDM_PP;
case VDM_RT:
return CURLY_BRACKET_VDM_RT;
case VDM_SL:
return CURLY_BRACKET_VDM_SL;
case CML:
default:
return CURLY_BRACKET_VDM_AL;
}
}
private String createCoverageTable()
{
StringBuilder sb = new StringBuilder();
sb.append("\\begin{longtable}{|l|r|r|r|}" + "\n");
sb.append("\\hline" + "\n");
sb.append("Function or operation & Line & Coverage & Calls \\\\" + "\n");
sb.append("\\hline" + "\n");
sb.append("\\hline" + "\n");
long total = 0;
LexNameList spans = LexLocation.getSpanNames(filename);
Collections.sort(spans);
for (ILexNameToken name : spans)
{
long calls = LexLocation.getSpanCalls(name);
total += calls;
sb.append("\\hyperref[" + latexLabel(name.getName()) + ":"
+ name.getLocation().getStartLine() + "]{"
+ utfIncludeCheck(latexQuote(name.toString()), false)
+ "}" + " & " + name.getLocation().getStartLine() + " & "
+ LexLocation.getSpanPercent(name) + "\\% & " + calls
+ " \\\\" + "\n");
sb.append("\\hline" + "\n");
}
sb.append("\\hline" + "\n");
sb.append(latexQuote(filename.getName()) + " & & "
+ LexLocation.getHitPercent(filename) + "\\% & " + total
+ " \\\\" + "\n");
sb.append("\\hline" + "\n");
sb.append("\\end{longtable}" + "\n");
return sb.toString();
}
private String markup(String line, List<LexLocation> list)
{
if (list == null)
{
// return line;
return utfIncludeCheck(line, true);
} else
{
StringBuilder sb = new StringBuilder();
int p = 0;
for (LexLocation m : list)
{
int start = m.startPos - 1;
int end = m.startLine == m.endLine ? m.endPos - 1
: line.length();
if (start >= p) // Backtracker produces duplicate tokens
{
// sb.append(line.substring(p, start));
sb.append(utfIncludeCheck(line.substring(p, start), true));
sb.append(LST_ESCAPE_BEGIN + "\\vdmnotcovered{");
// String temp = utfIncludeCheck(latexQuote(line.substring(start, end)), false);
// if(temp.charAt(temp.length()-1)==' ') temp=temp.substring(0, temp.length()-1);
sb.append(utfIncludeCheck(latexQuote(line.substring(start, end)), false)); // modified by his
sb.append("}" + LST_ESCAPE_END); // \u00A3");
p = end;
}
}
// sb.append(line.substring(p));
sb.append(utfIncludeCheck(line.substring(p), true));
return sb.toString();
}
}
private String latexQuote(String s)
{
// Latex specials: \# \$ \% \^{} \& \_ \{ \} \~{} \\
return s.replace("\\", "\\textbackslash ").replace("#", "\\#").replace("$", "\\$").replace("%", "\\%").replace("&", "\\&").replace("_", "\\_").replace("{", "\\{").replace("}", "\\}").replace("~", "\\~").replaceAll("\\^{1}", "\\\\^{}");
}
// add by his 2013/10/08
private String utfIncludeCheck(String line, Boolean addatsign)
{
String checked = "";
boolean start = false;
for (int i = 0; i < line.length(); i++)
{
if (isOneByte(line.substring(i, i + 1)))
{
if (start)
{
start = false;
checked += (addatsign ? useJPNFont ? fontEnd
+ LST_ESCAPE_END : "" : fontEnd)
+ line.substring(i, i + 1);
} else
{
checked += line.substring(i, i + 1);
}
} else
{
if (!start)
{
checked += (addatsign ? useJPNFont ? LST_ESCAPE_BEGIN : ""
: "")
+ (useJPNFont ? docFont : "")
+ line.substring(i, i + 1);
start = true;
} else
{
checked += line.substring(i, i + 1);
}
}
}
if (start)
{
checked += addatsign ? useJPNFont ? fontEnd + LST_ESCAPE_END : ""
: fontEnd;
}
return checked;
}
private boolean isOneByte(String a_String)
{
boolean result = false;
try
{
byte[] code = a_String.getBytes("UTF-8");
result = code.length == 1 ? true : false;
} catch (IOException ex)
{
}
return result;
}
private boolean checkFont(String FontName)
{
boolean checked = false;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
Font fonts[] = ge.getAllFonts();
for (int i = 0; i < fonts.length; i++)
{
if (fonts[i].getName().toString().equals(FontName))
{
checked = true;
break;
}
}
return checked;
}
private String latexLabel(String s)
{
// Latex specials: \# \$ \% \^{} \& \_ \{ \} \~{} \\
return s.replace("\\", ":").replace("#", ":").replace("$", ":").replace("%", ":").replace("&", ":").replace("_", ":").replace("{", ":").replace("}", ":").replace("~", ":").replaceAll("\\^{1}", ":");
}
}