diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/doclets/CheckDocsDoclet.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/doclets/CheckDocsDoclet.java
new file mode 100644
index 000000000..b735996cb
--- /dev/null
+++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/doclets/CheckDocsDoclet.java
@@ -0,0 +1,331 @@
+////////////////////////////////////////////////////////////////////////////////
+// checkstyle: Checks Java source code for adherence to a set of rules.
+// Copyright (C) 2001-2004 Oliver Burn
+//
+// This library 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.1 of the License, or (at your option) any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+////////////////////////////////////////////////////////////////////////////////
+
+package com.puppycrawl.tools.checkstyle.doclets;
+
+import com.sun.javadoc.RootDoc;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.Tag;
+import com.sun.javadoc.SeeTag;
+import com.sun.javadoc.PackageDoc;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.TreeMap;
+import java.util.Set;
+import java.util.Iterator;
+import java.util.Collection;
+import java.io.Writer;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.File;
+import java.io.FileWriter;
+
+/**
+ * Doclet which is used to extract Anakia input files from the
+ * Javadoc of Check implementations, so the Check's docs are
+ * autogenerated.
+ *
+ * @author lkuehne
+ */
+public final class CheckDocsDoclet
+{
+ /** javadoc command line option for dest dir. */
+ private static final String DEST_DIR_OPT = "-d";
+
+ /** Maps package names to DocumentationPages. */
+ private static Map sDocumentationPages = new HashMap();
+
+ /**
+ * Collects the content of a page in the resulting documentation.
+ * Each Java package will result in one doc page.
+ * */
+ private static final class DocumentationPage
+ {
+ /** The javadoc for the corresponding java package. */
+ private PackageDoc mPackageDoc;
+
+ /** maps check names to class doc, sorted. */
+ private Map mChecks = new TreeMap();
+
+ /**
+ * The string inside a package doc
+ * to mark the beginning of a page title.
+ */
+ private static final String PAGETITLE =
+ "";
+
+ /**
+ * The string inside a package doc
+ * to mark the end of a page title.
+ */
+ private static final String PAGETITLE_END = "";
+
+ /**
+ * Creates a new Documentation page.
+ * @param aPackageDoc package.html for the corresponding java package
+ */
+ private DocumentationPage(PackageDoc aPackageDoc)
+ {
+ mPackageDoc = aPackageDoc;
+ }
+
+ /** @return the package name of the corresponding java package. */
+ private String getPackageName()
+ {
+ return mPackageDoc.name();
+ }
+
+ /**
+ * Register a Checkstyle check's class documentation for inclusion
+ * on the DocumentationPage.
+ *
+ * @param aClassDoc the check's documentation as extracted by javadoc
+ */
+ private void addCheck(ClassDoc aClassDoc)
+ {
+ final String strippedClassName = aClassDoc.typeName();
+ final String checkName = strippedClassName.endsWith("Check")
+ ? strippedClassName.substring(
+ 0, strippedClassName.length() - "Check".length())
+ : strippedClassName;
+ mChecks.put(checkName, aClassDoc);
+ }
+
+ /**
+ * Write page.
+ * @param aWriter the target to write to
+ * @throws IOException if there are problems writing output
+ */
+ private void write(Writer aWriter) throws IOException
+ {
+ // TODO: use velocity to implement this method???
+ PrintWriter pw = new PrintWriter(aWriter);
+ pw.println("");
+ pw.println("
"; + final int tagLen = openTag.length(); + if (aText.length() > tagLen + && aText.substring(0, tagLen).equals(openTag)) + { + aText.delete(0, tagLen); + } + } + + /** + * Removes a dot from the end of a StringBuffer if there is one. + * @param aText the aText to process + */ + private void removeClosingDot(final StringBuffer aText) + { + final int lastIdx = aText.length() - 1; + if (aText.length() > 0 && aText.charAt(lastIdx) == '.') { + aText.delete(lastIdx, lastIdx + 1); + } + } + + /** + * Calculates the title of the DocumentationPage using the first + * sentence in the package javadoc. + * If parts of the first sentence are enclosed between + * {@link #PAGETITLE} and {@link #PAGETITLE_END}, only those parts + * are returned. + * + * @return the calculated title + */ + private String getTitle() + { + final Tag[] tags = mPackageDoc.firstSentenceTags(); + final String tagText = tags[0].text(); + final int pagetitleIdx = tagText.indexOf(PAGETITLE); + final StringBuffer text; + if (pagetitleIdx != -1) { + int titleEndIdx = tagText.indexOf(PAGETITLE_END, pagetitleIdx); + final int titleStartIdx = pagetitleIdx + PAGETITLE.length(); + text = new StringBuffer( + tagText.substring(titleStartIdx, titleEndIdx)); + } + else { + text = new StringBuffer(tagText); + } + removeClosingDot(text); + removeOpeningParagraphTag(text); + System.out.println("text = '" + text + "'"); + return text.toString().trim(); + } + } + + /** + * Finds or creates a documentation page where the content of + * a check's class documentation should be included. + * + * @param aClassDoc the class documentation + * @return the found or created page, registered in + * {@link #sDocumentationPages} + */ + private static DocumentationPage findDocumentationPage(ClassDoc aClassDoc) + { + final PackageDoc packageDoc = aClassDoc.containingPackage(); + final String packageName = packageDoc.name(); + DocumentationPage page = + (DocumentationPage) sDocumentationPages.get(packageName); + + if (page == null) { + page = new DocumentationPage(packageDoc); + sDocumentationPages.put(packageName, page); + } + + return page; + } + + /** + * Doclet entry point. + * @param aRoot parsed javadoc of all java files passed to the javadoc task + * @return true (TODO: semantics of the return value is not clear to me) + * @throws IOException if there are problems writing output + */ + public static boolean start(RootDoc aRoot) throws IOException + { + final ClassDoc[] classDocs = aRoot.classes(); + for (int i = 0; i < classDocs.length; i++) { + ClassDoc classDoc = classDocs[i]; + // TODO: introduce a "CheckstyleModule" interface + // so we can do better in the next line... + if (classDoc.typeName().endsWith("Check") + && !classDoc.isAbstract()) + { + DocumentationPage page = findDocumentationPage(classDoc); + page.addCheck(classDoc); + } + } + + final Collection pages = sDocumentationPages.values(); + final File destDir = new File(getDestDir(aRoot.options())); + for (Iterator it = pages.iterator(); it.hasNext();) { + DocumentationPage page = (DocumentationPage) it.next(); + String pageName = getPageName(page); + File outfile = new File(destDir, "config_" + pageName + ".xml"); + Writer writer = new FileWriter(outfile); + page.write(writer); + writer.close(); + } + + return true; + } + + /** + * Calculates the human readable page name for a doc page. + * + * @param aPage the doc page. + * @return the human readable page name for the doc page. + */ + private static String getPageName(DocumentationPage aPage) + { + final String packageName = aPage.getPackageName(); + String pageName = + packageName.substring(packageName.lastIndexOf('.') + 1); + if ("checks".equals(pageName)) { + return "misc"; + } + return pageName; + } + + /** + * Return the destination directory for this Javadoc run. + * @param aOptions Javadoc commandline options + * @return the dest dir specified on the command line (or ant task) + */ + public static String getDestDir(String[][] aOptions) + { + for (int i = 0; i < aOptions.length; i++) { + String[] opt = aOptions[i]; + if (DEST_DIR_OPT.equalsIgnoreCase(opt[0])) { + return opt[1]; + } + } + return null; // TODO: throw exception here ??? + } + + /** + * Returns option length (how many parts are in option). + * @param aOption option name to process + * @return option length (how many parts are in option). + */ + public static int optionLength(String aOption) + { + if (DEST_DIR_OPT.equals(aOption)) { + return 2; + } + return 0; + } + +}