/*
* GenerateSyntaxZip.java
*
* Copyright (C) 2015 Pixelgaffer
*
* This work is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2 of the License, or any later
* version.
*
* This work 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 version 2 and version 3 of the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.io.*;
import java.text.*;
import java.util.*;
import java.util.zip.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
public class GenerateSyntaxZip
{
static String xmlElement (Element e, int indent, boolean hasEnd)
{
StringBuilder xml = new StringBuilder();
for (int i = 0; i < indent; i++) xml.append("\t");
xml.append("<").append(e.getTagName());
NamedNodeMap nl = e.getAttributes();
if (nl != null)
{
for (int i = 0; i < nl.getLength(); i++)
{
Node n = nl.item(i);
if (n instanceof Attr)
{
Attr a = (Attr)n;
xml.append(" ").append(a.getName());
String value = a.getValue();
value = value.replace("&", "&");
value = value.replace("<", "<");
value = value.replace(">", ">");
value = value.replace("\"", """);
xml.append("=\"").append(value).append("\"");
}
}
}
xml.append(hasEnd ? ">" : " />");
return xml.toString();
}
static String xmlElementWithChildren (Element e, int indent)
{
StringBuilder xml = new StringBuilder();
NodeList nl = e.getChildNodes();
if (nl == null || nl.getLength() == 0)
{
String cdata = e.getTextContent().trim();
if (cdata == null || cdata.length() == 0)
xml.append(xmlElement(e, indent, false));
else
{
cdata = cdata.replace("&", "&");
cdata = cdata.replace("<", "<");
cdata = cdata.replace(">", ">");
cdata = cdata.replace("\"", """);
xml.append(xmlElement(e, indent, true));
xml.append(cdata).append("</").append(e.getTagName()).append(">");
}
}
else
{
xml.append(xmlElement(e, indent, true)).append("\n");
int elements = 0;
for (int in = 0; in < nl.getLength(); in++)
{
Node n = nl.item(in);
if (n instanceof Element)
{
elements++;
xml.append(xmlElementWithChildren((Element)n, indent + 1)).append("\n");
}
}
if (elements == 0)
{
for (int i = 0; i <= indent; i++) xml.append("\t");
xml.append(e.getTextContent().trim()).append("\n");
}
for (int i = 0; i < indent; i++) xml.append("\t");
xml.append("</").append(e.getTagName()).append(">");
}
return xml.toString();
}
static final BufferedReader sysin = new BufferedReader(new InputStreamReader(System.in));
static Map<String, List<String>> lists;
static void handleElement (Element e, PrintWriter out, int indent, Properties props, String lang) throws Throwable
{
if (e.getTagName().equals("lists"))
{
NodeList nl = e.getChildNodes();
if (nl != null)
{
for (int i = 0; i < nl.getLength(); i++)
{
Node n = nl.item(i);
if (n instanceof Element)
{
handleElement((Element)n, out, indent + 1, props, lang);
}
}
}
}
else if (e.getTagName().equals("list"))
{
List<String> list = new ArrayList<>();
NodeList nl = e.getChildNodes();
if (nl != null)
{
for (int i = 0; i < nl.getLength(); i++)
{
Node n = nl.item(i);
if (n instanceof Element)
{
Element elem = (Element)n;
if (elem.getTagName().equals("item"))
{
list.add(elem.getTextContent());
}
else
{
System.err.println("Unbekanntes Element in Liste:");
System.err.println(xmlElementWithChildren(elem, 0));
}
}
}
}
String name = e.getAttribute("name");
lists.put(name, list);
}
else if (e.getTagName().equals("itemDatas"))
{
out.println(xmlElement(e, 2, true));
NodeList nl = e.getChildNodes();
if (nl != null)
{
for (int i = 0; i < nl.getLength(); i++)
{
Node n = nl.item(i);
if (n instanceof Element)
{
Element itemData = (Element)n;
if (itemData.getTagName().equals("itemData"))
{
NamedNodeMap attributes = itemData.getAttributes();
String name = null, defStyleNum = null;
Map<String, String> styleInfo = new HashMap<>();
boolean ask = false;
if (attributes != null)
{
for (int j = 0; j < attributes.getLength(); j++)
{
Node n0 = attributes.item(j);
if (n0 instanceof Attr)
{
Attr attribute = (Attr)n0;
if (attribute.getName().equals("name"))
name = attribute.getValue();
else if (attribute.getName().equals("defStyleNum"))
defStyleNum = attribute.getValue();
else if (!attribute.getName().equals("spellChecking"))
{
ask = true;
styleInfo.put(attribute.getName(), attribute.getValue());
}
}
}
}
if (ask)
{
String newDefault = props.getProperty(lang + "." + name + ".newDefault");
if (newDefault == null)
{
System.out.print("Das itemData-Element für " + name + " (default: " + defStyleNum + ") enthält eigene Style-Informationen (" + xmlElement(itemData, 0, false) + "). Neues default: ");
newDefault = sysin.readLine();
}
if (newDefault.isEmpty())
{
out.println(xmlElement(itemData, 3, false));
}
else
{
out.println("\t\t\t<itemData name=\"" + name + "\" defStyleNum=\"" + newDefault + "\" />");
}
props.put(lang + "." + name + ".newDefault", newDefault);
}
else
out.println(xmlElement(itemData, 3, false));
}
else
{
System.out.println("Warnung: Unbekanntes Element in " + xmlElement(e, 0, true) + ":");
System.out.println(xmlElementWithChildren(e, 0));
out.println(xmlElementWithChildren(e, 3));
}
}
}
}
out.println("\t\t</itemDatas>");
}
else
out.println(xmlElementWithChildren(e, indent));
}
public static void main (String args[]) throws Throwable
{
File propsFile = new File(System.getProperty("user.home"), ".generateSyntaxZip.prop");
Properties props = new Properties();
if (propsFile.exists())
props.load(new FileInputStream(propsFile));
File dir = new File("/usr/share/katepart5/syntax");
File zipFile = new File("syntax.zip");
ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(zipFile));
PrintWriter out = new PrintWriter(new OutputStreamWriter(zip, "utf8"), true);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
DocumentBuilder db = dbf.newDocumentBuilder();
for (String filename : dir.list())
{
if (!filename.endsWith(".xml"))
continue;
File file = new File(dir, filename);
lists = new HashMap<>();
System.out.println("Lese Datei " + file.getAbsolutePath());
Document doc = db.parse(file);
Element root = doc.getDocumentElement();
String lang = root.getAttribute("name");
String answer = props.getProperty(lang + ".include");
if (answer == null)
{
System.out.print("Soll die Sprache " + lang + " in die syntax.zip-Datei geschrieben werden?");
answer = sysin.readLine();
}
props.put(lang + ".include", answer);
boolean include = !answer.startsWith("n");
if (!include)
{
props.store(new FileOutputStream(propsFile), "user input");
continue;
}
ZipEntry entry = new ZipEntry(filename);
zip.putNextEntry(entry);
out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
out.println("<!-- read from " + file.getAbsolutePath() + " at " + DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, Locale.UK).format(new Date()) + " -->");
out.println(xmlElement(root, 0, true));
NodeList nl = root.getChildNodes();
if (nl != null)
{
for (int i = 0; i < nl.getLength(); i++)
{
Node n = nl.item(i);
if (n instanceof Element)
{
Element e = (Element)n;
if (e.getTagName().equals("highlighting"))
{
out.println(xmlElement(e, 1, true));
NodeList nl1 = e.getChildNodes();
if (nl1 != null)
{
for (int i1 = 0; i1 < nl1.getLength(); i1++)
{
Node n1 = nl1.item(i1);
if (n1 instanceof Element)
{
Element e1 = (Element) n1;
handleElement(e1, out, 2, props, lang);
}
}
}
for (String name : lists.keySet())
{
out.println("\t\t<list name=\"" + name + "\">");
for (String item : lists.get(name))
{
item = item.replace("&", "&");
item = item.replace("<", "<");
item = item.replace(">", ">");
item = item.replace("\"", """);
out.println("\t\t\t<item>" + item + "</item>");
}
out.println("\t\t</list>");
}
out.println("\t</highlighting>");
}
else
out.println(xmlElementWithChildren(e, 1));
}
}
}
answer = props.getProperty(lang + ".isProgrammingLanguage");
if (answer == null)
{
System.out.print("Ist die Sprache " + lang + " eine Programmiersprache?");
answer = sysin.readLine();
}
props.put(lang + ".isProgrammingLanguage", answer);
boolean isProgrammingLanguage = !answer.startsWith("n");
String classDef = null, methodDef = null, classList = null;
if (isProgrammingLanguage)
{
classDef = props.getProperty(lang + ".classDef");
if (classDef == null)
{
System.out.print("Syntax für Klassendefinitionen (RegEx mit der Gruppe (?P<classname> … ) für den Klassennamen):");
classDef = sysin.readLine();
}
props.put(lang + ".classDef", classDef);
methodDef = props.getProperty(lang + ".methodDef");
if (methodDef == null)
{
System.out.print("Syntax für Methodendefinitionen (RegEx mit der Gruppe (?P<methodname> … ) für den Methodennamen):");
methodDef = sysin.readLine();
}
props.put(lang + ".methodDef", methodDef);
classList = props.getProperty(lang + ".classList");
if (classList == null)
{
System.out.print("Liste mit den definierten Klassen (" + lists.keySet() + "):");
classList = sysin.readLine();
}
props.put(lang + ".classList", classList);
out.println("\t<codr>");
if (classDef.contains("(?P<classname>"))
{
classDef = classDef.replace("&", "&");
classDef = classDef.replace("<", "<");
classDef = classDef.replace(">", ">");
classDef = classDef.replace("\"", """);
out.println("\t\t<classDef>" + classDef + "</classDef>");
}
if (methodDef.contains("(?P<methodname>"))
{
methodDef = methodDef.replace("&", "&");
methodDef = methodDef.replace("<", "<");
methodDef = methodDef.replace(">", ">");
methodDef = methodDef.replace("\"", """);
out.println("\t\t<methodDef>" + methodDef + "</methodDef>");
}
if (lists.containsKey(classList))
{
classList = classList.replace("&", "&");
classList = classList.replace("<", "<");
classList = classList.replace(">", ">");
classList = classList.replace("\"", """);
out.println("\t\t<classList>" + classList + "</classList>");
}
out.println("\t</codr>");
}
out.println("</" + root.getTagName() + ">");
props.store(new FileOutputStream(propsFile), "user input");
}
zip.close();
props.store(new FileOutputStream(propsFile), "user input");
}
}