/******************************************************************************* * Copyright (c) 2007 Red Hat Inc.. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat Incorporated - initial API and implementation *******************************************************************************/ package org.eclipse.linuxtools.cdt.libhover.texinfoparsers; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; //This file contains a texinfo parser that can be //run to create the Autotools glibc.xml file. //Usage is as follows: //1. compile this file using javac //2. run this file using java, passing the //arguments: dir_to_automake_texi_files output_xml_file_name public class ParseAutomakeTexinfo { static final boolean DEBUG = false; static final String ATcmd = "(@\\w*)"; // Currently in automake docs, the macro section starts with // a subsection as below and a table which contains macros which // are item and itemx entries. static final String MacrosStart = "@subsection\\sPublic\\smacros"; static final String OldMacrosStart = "@section\\sAutoconf\\smacros.*"; static final Pattern MacroSection1 = Pattern.compile(MacrosStart); static final Pattern MacroSection2 = Pattern.compile(OldMacrosStart); // 0 static final String Defmac = "@item"; static final String Defmacx = "@itemx"; // 1 static final String MacroName = "(\\w*)"; static final int MacroNameIndex = 1; // 2 3 static final String Parms = "(\\((.*)\\))"; static final int ParmsIndex = 2; static final String rest = ".*"; static final String WhiteSpace = "\\s*"; static final Pattern MacroPattern = Pattern.compile("^" + Defmac + WhiteSpace + MacroName + WhiteSpace + Parms + rest, Pattern.MULTILINE + Pattern.CASE_INSENSITIVE); static final Pattern MacroPattern2 = Pattern.compile("^" + Defmac + WhiteSpace + MacroName + rest, Pattern.MULTILINE + Pattern.CASE_INSENSITIVE); static final Pattern MacroPatternx = Pattern.compile("^" + Defmacx + WhiteSpace + MacroName + WhiteSpace + Parms + rest, Pattern.MULTILINE + Pattern.CASE_INSENSITIVE); static final Pattern MacroPatternx2 = Pattern.compile("^" + Defmacx + WhiteSpace + MacroName + rest, Pattern.MULTILINE + Pattern.CASE_INSENSITIVE); static final Pattern ParmBracketPattern = Pattern.compile("\\((.*)\\)"); static final Pattern IndexPattern = Pattern.compile("@\\w*index.*"); static final Pattern IndexPattern2 = Pattern.compile("@\\w*index\\{[a-zA-Z0-9_@\\{\\}]*\\}"); static final Pattern ExamplePattern = Pattern.compile("@example"); static final Pattern EndExamplePattern = Pattern.compile("@end\\s+example"); static final Pattern EnumeratePattern = Pattern.compile("@enumerate"); static final Pattern EndEnumeratePattern = Pattern.compile("@end\\s+enumerate"); static final Pattern VerbatimPattern = Pattern.compile("@verbatim"); static final Pattern ItemPattern = Pattern.compile("@item"); static final Pattern NoIndentPattern = Pattern.compile("@noindent"); static final Pattern BRPattern = Pattern.compile("<br>"); static final Pattern EOLPattern = Pattern.compile("<eol>"); static final Pattern EndVerbatimPattern = Pattern.compile("@end\\s+verbatim"); static final Pattern TableSampItemPattern = Pattern.compile("(@table\\s*@samp.*)@item\\s*([a-zA-Z_0-9+\\-<>/ ]*)<eol>(.*@end\\s*table)", Pattern.DOTALL); static final Pattern TableAsisItemPattern = Pattern.compile("(@table\\s*@asis.*)@item\\s*([a-zA-Z_0-9+\\-,<>/ ]*)<eol>(.*@end\\s*table)", Pattern.DOTALL); static final Pattern TableSampPattern = Pattern.compile("@table\\s*@samp", Pattern.MULTILINE); static final Pattern TableAsisPattern = Pattern.compile("@table\\s*@asis", Pattern.MULTILINE); static final Pattern EndTablePattern = Pattern.compile("@end\\s+table"); static final Pattern DotsPattern = Pattern.compile("@dots\\{\\}"); static final Pattern ItemizeMinusPattern= Pattern.compile("@itemize\\s+@minus" + "(.*)" + "@end\\s+itemize", Pattern.MULTILINE); static final Pattern ItemizeBulletPattern= Pattern.compile("@itemize\\s+@bullet" + "(.*)" + "@end\\s+itemize", Pattern.MULTILINE); static final Pattern XrefPattern = Pattern.compile("@xref\\{[^\\}]*\\}", Pattern.MULTILINE); static final Pattern CommandPattern = Pattern.compile("@command\\{([^\\}]*)\\}"); static final Pattern KbdPattern = Pattern.compile("@kbd\\{([^\\}]*)\\}"); static final Pattern RPattern = Pattern.compile("@r\\{([^\\}]*)\\}"); static final Pattern FilePattern = Pattern.compile("@file\\{([^\\}]*)\\}"); static final Pattern VarPattern = Pattern.compile("@var\\{([^\\}]*)\\}"); static final Pattern OVarPattern = Pattern.compile("@ovar\\{([^\\}]*)\\}"); static final Pattern DVarPattern = Pattern.compile("@dvar\\{([^\\},\\,]*),([^\\}]*)\\}"); static final Pattern CodePattern = Pattern.compile("@code\\{([^\\}]*)\\}"); static final Pattern EmphPattern = Pattern.compile("@emph\\{([^\\}]*)\\}"); static final Pattern SampPattern = Pattern.compile("@samp\\{([^\\}]*)\\}"); static final Pattern OptionPattern = Pattern.compile("@option\\{([^\\}]*)\\}"); static final Pattern UrefPattern = Pattern.compile("@uref\\{([^,]*),\\s+([^\\}]*)\\}"); static final Pattern TagPattern = Pattern.compile("@\\w*\\{([^\\}]*)\\}"); static final Pattern AmpersandPattern = Pattern.compile("&"); static final Pattern LeftAnglePattern = Pattern.compile("<"); static final Pattern RightAnglePattern = Pattern.compile(">"); private static Map<String, MacroDef> macroMap; static class MacroParms { String[] parms; MacroParms nextParms = null; public MacroParms(String[] parms) { this.parms = parms; } } static class MacroDef { String MacroName; MacroParms Parameters; String Synopsis; } static class TPElement { String Content; String Synopsis; } static class TPDef { String TPType; String TPName; String TPSynopsis; TPElement[] TPElements; Object[] IncludeList; } private static String killTagsParms(String tt) { Matcher mm; mm = ParmBracketPattern.matcher(tt); tt= mm.replaceAll("$1"); mm = OVarPattern.matcher(tt); tt = mm.replaceAll("[$1]"); mm = DVarPattern.matcher(tt); tt = mm.replaceAll("[$1=$2]"); mm = VarPattern.matcher(tt); tt = mm.replaceAll("$1"); mm = RPattern.matcher(tt); tt = mm.replaceAll("$1"); mm = DotsPattern.matcher(tt); tt = mm.replaceAll("..."); return tt; } private static String killTags(String tt) { Matcher mm; String ss = ""; while (ss != tt) { mm = XrefPattern.matcher(tt); ss = tt; tt = mm.replaceAll(""); } ss = ""; while (ss != tt) { mm = IndexPattern.matcher(tt); ss = tt; tt = mm.replaceAll(""); } ss = ""; while (ss != tt) { mm = IndexPattern2.matcher(tt); ss = tt; tt = mm.replaceAll(""); } ss = ""; while (ss != tt) { mm = NoIndentPattern.matcher(tt); ss = tt; tt = mm.replaceAll(""); } ss = ""; while (ss != tt) { mm = VarPattern.matcher(tt); ss = tt; tt = mm.replaceAll("<VAR>$1</VAR>"); } ss = ""; while (ss != tt) { mm = DotsPattern.matcher(tt); ss = tt; tt = mm.replaceAll("<small>...</small>"); } ss = ""; while (ss != tt) { mm = CommandPattern.matcher(tt); ss = tt; tt = mm.replaceAll("<CODE>$1</CODE>"); } ss = ""; while (ss != tt) { mm = CodePattern.matcher(tt); ss = tt; tt = mm.replaceAll("<CODE>$1</CODE>"); } ss = ""; while (ss != tt) { mm = UrefPattern.matcher(tt); ss = tt; tt = mm.replaceAll("<A HREF=\"$1>$2</A>"); } ss = ""; while (ss != tt) { mm = KbdPattern.matcher(tt); ss = tt; tt = mm.replaceAll("<KBD>$1</KBD>"); } ss = ""; while (ss != tt) { mm = EmphPattern.matcher(tt); ss = tt; tt = mm.replaceAll("<EM>$1</EM>"); } ss = ""; while (ss != tt) { mm = FilePattern.matcher(tt); ss = tt; tt = mm.replaceAll("<TT>$1</TT>"); } ss = ""; while (ss != tt) { mm = VerbatimPattern.matcher(tt); ss = tt; tt = mm.replaceAll("<CODE>"); } ss = ""; while (ss != tt) { mm = EndVerbatimPattern.matcher(tt); ss = tt; tt = mm.replaceAll("</CODE>"); } ss = ""; while (ss != tt) { mm = SampPattern.matcher(tt); ss = tt; tt = mm.replaceAll("<samp>$1</samp>"); } ss = ""; while (ss != tt) { mm = OptionPattern.matcher(tt); ss = tt; tt = mm.replaceAll("<samp>$1</samp>"); } ss = ""; while (ss != tt) { mm = ExamplePattern.matcher(tt); ss = tt; tt = mm.replaceAll("<TABLE><tr><td> </td><td class=example><pre>"); } ss = ""; while (ss != tt) { mm = EndExamplePattern.matcher(tt); ss = tt; tt = mm.replaceAll("</pre></td></tr></table>"); } ss = ""; while (ss != tt) { mm = EnumeratePattern.matcher(tt); ss = tt; tt = mm.replaceAll("<OL>"); } ss = ""; while (ss != tt) { mm = EndEnumeratePattern.matcher(tt); ss = tt; tt = mm.replaceAll("</OL>"); } ss = ""; while (ss != tt) { mm = TableSampItemPattern.matcher(tt); ss = tt; if (mm.matches()) { System.out.println("group 1 is " + mm.group(1)); System.out.println("group 2 is " + mm.group(2)); System.out.println("group 3 is " + mm.group(3)); } tt = mm.replaceAll("$1<DT>'<SAMP>$2</SAMP>'\n<DD>$3"); } ss = ""; while (ss != tt) { mm = TableAsisItemPattern.matcher(tt); ss = tt; tt = mm.replaceAll("$1<DT>$2\n<DD>$3"); } ss = ""; while (ss != tt) { mm = TableSampPattern.matcher(tt); ss = tt; tt = mm.replaceAll("<DL>\n"); } ss = ""; while (ss != tt) { mm = TableAsisPattern.matcher(tt); ss = tt; tt = mm.replaceAll("<DL>\n"); } ss = ""; while (ss != tt) { mm = EndTablePattern.matcher(tt); ss = tt; tt = mm.replaceAll("</DL>"); } //FIXME: if there ever is a @itemize @bullet within a // @itemize @minus or vice-versa, the following // logic will get it wrong. ss = ""; while (ss != tt) { mm = ItemizeMinusPattern.matcher(tt); ss = tt; tt = mm.replaceAll("<UL>$1</UL>"); } ss = ""; while (ss != tt) { mm = ItemizeBulletPattern.matcher(tt); ss = tt; tt = mm.replaceAll("<OL>$1</OL>"); } ss = ""; while (ss != tt) { mm = ItemPattern.matcher(tt); ss = tt; tt = mm.replaceAll("<LI>"); } ss = ""; while (ss != tt) { mm = TagPattern.matcher(tt); ss = tt; tt = mm.replaceAll("$1"); } mm = AmpersandPattern.matcher(tt); tt = mm.replaceAll("&"); mm = LeftAnglePattern.matcher(tt); tt = mm.replaceAll("<"); mm = RightAnglePattern.matcher(tt); tt = mm.replaceAll(">"); // Clean up the eol markers we used to mark end of line for items mm = EOLPattern.matcher(tt); tt = mm.replaceAll(""); return tt; } private static MacroDef BuildMacroDef(Matcher m) { MacroDef md = new MacroDef(); md.MacroName = m.group(MacroNameIndex); if (null != m.group(ParmsIndex)) { String tt = killTagsParms(m.group(ParmsIndex)); String[] parms = tt.split(",\\s"); md.Parameters = new MacroParms(parms); } return md; } private static MacroParms AddMacroDefxParms(MacroParms mp, Matcher mx) { if (null != mx.group(ParmsIndex)) { String tt = killTagsParms(mx.group(ParmsIndex)); String[] parms = tt.split(",\\s"); MacroParms mpnew = new MacroParms(parms); mp.nextParms = mpnew; return mpnew; } return null; } private static MacroDef HandleMacroDef(BufferedReader is, String s) throws IOException { MacroDef fd = null; Matcher m = MacroPattern.matcher(s); if (m.matches()) { fd = BuildMacroDef(m); } else { // assume the line got split and retry is.mark(100); String il = is.readLine(); m = MacroPattern.matcher(s + il); if (m.matches()) { fd = BuildMacroDef(m); } else { is.reset(); m = MacroPattern2.matcher(s); if (m.matches()) { fd = new MacroDef(); fd.MacroName = m.group(MacroNameIndex); fd.Parameters = new MacroParms(new String[0]); } } } if (fd != null) { // Look for @defmacx which are alternate prototypes for the macro is.mark(100); String il = is.readLine(); if (il != null) { Matcher mx = MacroPatternx.matcher(il); Matcher mx2 = MacroPatternx2.matcher(il); MacroParms mp = fd.Parameters; while (mx.matches() || mx2.matches()) { if (mx.matches()) { mp = AddMacroDefxParms(mp, mx); } else { MacroParms mpnew = new MacroParms(new String[0]); mp.nextParms = mpnew; mp = mpnew; } is.mark(100); il = is.readLine(); if (il != null) { mx = MacroPatternx.matcher(il); mx2 = MacroPatternx2.matcher(il); } } is.reset(); } if (macroMap.get(fd.MacroName) != null) { return null; } macroMap.put(fd.MacroName, fd); } return fd; } private static void WriteString(BufferedWriter os, String s) throws IOException { // System.out.println(s); os.write(s+"\n", 0, 1+s.length()); } private static void CreateHeader(BufferedWriter os) throws IOException { WriteString(os, "<!-- This file automatically generated by ParseAutomakeTexinfo utility -->"); WriteString(os, "<!-- cvs -d:pserver:anonymous@sources.redhat.com:/cvs/eclipse \\ -->"); WriteString(os, "<!-- co autotools/ParseTexinfo -->"); WriteString(os, "<!DOCTYPE macros ["); WriteString(os, ""); WriteString(os, " <!ELEMENT macros (macro)*>"); WriteString(os, ""); WriteString(os, " <!ELEMENT macro (prototype*,synopsis)>"); WriteString(os, " <!ATTLIST macro"); WriteString(os, " id ID #REQUIRED"); WriteString(os, " >"); WriteString(os, ""); WriteString(os, " <!ELEMENT synopsis (#PCDATA)*>"); WriteString(os, ""); WriteString(os, " <!ELEMENT prototype (parameter+)?>"); WriteString(os, ""); WriteString(os, " <!ELEMENT parameter (#PCDATA)*>"); WriteString(os, " <!ATTLIST parameter"); WriteString(os, " content CDATA #REQUIRED"); WriteString(os, " >"); WriteString(os, ""); WriteString(os, "]>"); WriteString(os, ""); } private static void CreateTrailer(BufferedWriter os) throws IOException { WriteString(os, "</macros>"); } private static void WriteSynopsis(BufferedWriter os, String Synopsis, boolean indent) throws IOException { String ss = Synopsis; String[] tt = ss.split("\\s"); String aa = ""; String spaces = indent ? " " : " "; WriteString(os, spaces + "<synopsis>"); if (null != Synopsis) { for (int pp = 0; pp < tt.length; pp++) { if (tt[pp].equals("<br>")) { WriteString(os, spaces + aa + "</P><P>\n"); aa = ""; } else { if ((aa.length() + tt[pp].length()) > 64) { WriteString(os, spaces + aa); aa = ""; } aa = aa + " " + tt[pp]; } } } if (aa.length() > 0) { WriteString(os, " " + aa); } WriteString(os, spaces + "</synopsis>"); } private static void HandleDefmacro(BufferedWriter os, BufferedReader is, String s) throws IOException { String il; MacroDef md = null; List<MacroDef> FDefs = new ArrayList<>(); while (null != (il = is.readLine())) { if (il.startsWith(Defmac)) { if (null != (md = HandleMacroDef(is, il))) { FDefs.add(md); } } else if (il.startsWith("@comment") || il.startsWith("@c ")) { // comment -- ignore it } else if (il.startsWith("@subsection") || il.startsWith("@section")) { for (int kk = 0; kk < FDefs.size(); kk++) { md = FDefs.get(kk); WriteString(os, " <macro id=\"" + md.MacroName + "\">"); MacroParms mp = md.Parameters; do { WriteString(os, " <prototype>"); String[] parms = mp.parms; for (int i = 0; i < parms.length; i++) { WriteString(os, " <parameter content=\"" + parms[i] + "\"/>"); } WriteString(os, " </prototype>"); mp = mp.nextParms; } while (mp != null); if (null != md.Synopsis) { WriteSynopsis(os, md.Synopsis, false); } WriteString(os, " </macro>"); } return; } else { if (md != null) { md.Synopsis = ((md.Synopsis == null) ? "" : md.Synopsis + " " ) + ((il.length() == 0) ? "<br><br>" : il.startsWith("@item") ? killTags(il) + "<eol>" : killTags(il)); } } } FDefs.clear(); } private static class OnlyTexi implements FilenameFilter { @Override public boolean accept(File dir, String s) { return (s.endsWith(".texi")) ? true : false; } } public static void BuildXMLFromTexinfo(String srcdir, String dstdir) { try { macroMap = new HashMap<>(); BufferedWriter os = new BufferedWriter(new FileWriter(dstdir)); CreateHeader(os); WriteString(os, "<macros>"); try { String[] dir = new java.io.File(srcdir).list(new OnlyTexi()); for (int i = 0; i < dir.length; i++) { String qFile = srcdir.endsWith("/") ? srcdir + dir[i] : srcdir + "/" + dir[i]; try (BufferedReader is = new BufferedReader(new FileReader(qFile))) { String il; while (null != (il = is.readLine())) { Matcher mm1 = MacroSection1.matcher(il); Matcher mm2 = MacroSection2.matcher(il); if (mm1.matches() || mm2.matches()) { HandleDefmacro(os, is, il); } } } catch (IOException e) { System.out.println("Input File IOException: " + e); return; } } } catch (NullPointerException e) { System.out.println("NullPointerException: " + e); return; } CreateTrailer(os); os.close(); } catch (IOException e) { System.out.println("Output File IOException: " + e); return; } } public static void main(String[] args) { // arg[0] is input directory containing .texi documents to read // arg[1] is output xml file to create BuildXMLFromTexinfo(args[0], args[1]); } }