jjg@1455: package tidystats; jjg@1455: jjg@1455: import java.io.IOException; jjg@1455: import java.nio.charset.Charset; jjg@1455: import java.nio.file.FileSystem; jjg@1455: import java.nio.file.FileSystems; jjg@1455: import java.nio.file.Files; jjg@1455: import java.nio.file.Path; jjg@1455: import java.util.ArrayList; jjg@1455: import java.util.Comparator; jjg@1455: import java.util.HashMap; jjg@1455: import java.util.List; jjg@1455: import java.util.Map; jjg@1455: import java.util.Set; jjg@1455: import java.util.TreeMap; jjg@1455: import java.util.TreeSet; jjg@1455: import java.util.regex.Matcher; jjg@1455: import java.util.regex.Pattern; jjg@1455: jjg@1455: public class Main { jjg@1455: public static void main(String... args) throws IOException { jjg@1455: new Main().run(args); jjg@1455: } jjg@1455: jjg@1455: void run(String... args) throws IOException { jjg@1455: FileSystem fs = FileSystems.getDefault(); jjg@1455: List paths = new ArrayList<>(); jjg@1455: jjg@1455: int i; jjg@1455: for (i = 0; i < args.length; i++) { jjg@1455: String arg = args[i]; jjg@1455: if (arg.startsWith("-")) jjg@1455: throw new IllegalArgumentException(arg); jjg@1455: else jjg@1455: break; jjg@1455: } jjg@1455: jjg@1455: for ( ; i < args.length; i++) { jjg@1455: Path p = fs.getPath(args[i]); jjg@1455: paths.add(p); jjg@1455: } jjg@1455: jjg@1455: for (Path p: paths) { jjg@1455: scan(p); jjg@1455: } jjg@1455: jjg@1455: print("%6d files read", files); jjg@1455: print("%6d files had no errors or warnings", ok); jjg@1455: print("%6d files reported \"Not all warnings/errors were shown.\"", overflow); jjg@1455: print("%6d errors found", errs); jjg@1455: print("%6d warnings found", warns); jjg@1455: print("%6d recommendations to use CSS", css); jjg@1455: print(""); jjg@1455: jjg@1455: Map> sortedCounts = new TreeMap<>( jjg@1455: new Comparator() { jjg@1455: @Override jjg@1455: public int compare(Integer o1, Integer o2) { jjg@1455: return o2.compareTo(o1); jjg@1455: } jjg@1455: }); jjg@1455: jjg@1455: for (Map.Entry e: counts.entrySet()) { jjg@1455: Pattern p = e.getKey(); jjg@1455: Integer n = e.getValue(); jjg@1455: Set set = sortedCounts.get(n); jjg@1455: if (set == null) jjg@1455: sortedCounts.put(n, (set = new TreeSet<>())); jjg@1455: set.add(p.toString()); jjg@1455: } jjg@1455: jjg@1455: for (Map.Entry> e: sortedCounts.entrySet()) { jjg@1455: for (String p: e.getValue()) { jjg@1455: if (p.startsWith(".*")) p = p.substring(2); jjg@1455: print("%6d: %s", e.getKey(), p); jjg@1455: } jjg@1455: } jjg@1455: } jjg@1455: jjg@1455: void scan(Path p) throws IOException { jjg@1455: if (Files.isDirectory(p)) { jjg@1455: for (Path c: Files.newDirectoryStream(p)) { jjg@1455: scan(c); jjg@1455: } jjg@1455: } else if (isTidyFile(p)) { jjg@1455: scan(Files.readAllLines(p, Charset.defaultCharset())); jjg@1455: } jjg@1455: } jjg@1455: jjg@1455: boolean isTidyFile(Path p) { jjg@1455: return Files.isRegularFile(p) && p.getFileName().toString().endsWith(".tidy"); jjg@1455: } jjg@1455: jjg@1455: void scan(List lines) { jjg@1455: Matcher m; jjg@1455: files++; jjg@1455: for (String line: lines) { jjg@1455: if (okPattern.matcher(line).matches()) { jjg@1455: ok++; jjg@1455: } else if ((m = countPattern.matcher(line)).matches()) { jjg@1455: warns += Integer.valueOf(m.group(1)); jjg@1455: errs += Integer.valueOf(m.group(2)); jjg@1455: if (m.group(3) != null) jjg@1455: overflow++; jjg@1455: } else if ((m = guardPattern.matcher(line)).matches()) { jjg@1455: boolean found = false; jjg@1455: for (Pattern p: patterns) { jjg@1455: if ((m = p.matcher(line)).matches()) { jjg@1455: found = true; jjg@1455: count(p); jjg@1455: break; jjg@1455: } jjg@1455: } jjg@1455: if (!found) jjg@1455: System.err.println("Unrecognized line: " + line); jjg@1455: } else if (cssPattern.matcher(line).matches()) { jjg@1455: css++; jjg@1455: } jjg@1455: } jjg@1455: } jjg@1455: jjg@1455: Map counts = new HashMap<>(); jjg@1455: void count(Pattern p) { jjg@1455: Integer i = counts.get(p); jjg@1455: counts.put(p, (i == null) ? 1 : i + 1); jjg@1455: } jjg@1455: jjg@1455: void print(String format, Object... args) { jjg@1455: System.out.println(String.format(format, args)); jjg@1455: } jjg@1455: jjg@1455: Pattern okPattern = Pattern.compile("No warnings or errors were found."); jjg@1455: Pattern countPattern = Pattern.compile("([0-9]+) warnings, ([0-9]+) errors were found!.*?(Not all warnings/errors were shown.)?"); jjg@1455: Pattern cssPattern = Pattern.compile("You are recommended to use CSS.*"); jjg@1455: Pattern guardPattern = Pattern.compile("line [0-9]+ column [0-9]+ - (Error|Warning):.*"); jjg@1455: jjg@1455: Pattern[] patterns = { jjg@1455: Pattern.compile(".*Error: <.*> is not recognized!"), jjg@1455: Pattern.compile(".*Error: missing quote mark for attribute value"), jjg@1455: Pattern.compile(".*Warning: <.*> anchor \".*\" already defined"), jjg@1455: Pattern.compile(".*Warning: <.*> attribute \".*\" has invalid value \".*\""), jjg@1455: Pattern.compile(".*Warning: <.*> attribute \".*\" lacks value"), jjg@1455: Pattern.compile(".*Warning: <.*> attribute \".*\" lacks value"), jjg@1455: Pattern.compile(".*Warning: <.*> attribute with missing trailing quote mark"), jjg@1455: Pattern.compile(".*Warning: <.*> dropping value \".*\" for repeated attribute \".*\""), jjg@1455: Pattern.compile(".*Warning: <.*> inserting \".*\" attribute"), jjg@1455: Pattern.compile(".*Warning: <.*> is probably intended as "), jjg@1455: Pattern.compile(".*Warning: <.*> isn't allowed in <.*> elements"), jjg@1455: Pattern.compile(".*Warning: <.*> lacks \".*\" attribute"), jjg@1455: Pattern.compile(".*Warning: <.*> missing '>' for end of tag"), jjg@1455: Pattern.compile(".*Warning: <.*> proprietary attribute \".*\""), jjg@1455: Pattern.compile(".*Warning: <.*> unexpected or duplicate quote mark"), jjg@1455: Pattern.compile(".*Warning: cannot copy name attribute to id"), jjg@1455: Pattern.compile(".*Warning: escaping malformed URI reference"), jjg@1455: Pattern.compile(".*Warning:
proprietary attribute \"pre\""), jjg@1455: Pattern.compile(".*Warning: discarding unexpected <.*>"), jjg@1455: Pattern.compile(".*Warning: discarding unexpected "), jjg@1455: Pattern.compile(".*Warning: entity \".*\" doesn't end in ';'"), jjg@1455: Pattern.compile(".*Warning: inserting implicit <.*>"), jjg@1455: Pattern.compile(".*Warning: inserting missing 'title' element"), jjg@1455: Pattern.compile(".*Warning: missing declaration"), jjg@1455: Pattern.compile(".*Warning: missing <.*>"), jjg@1455: Pattern.compile(".*Warning: missing before <.*>"), jjg@1455: Pattern.compile(".*Warning: nested emphasis <.*>"), jjg@1455: Pattern.compile(".*Warning: plain text isn't allowed in <.*> elements"), jjg@1455: Pattern.compile(".*Warning: replacing

by
"), jjg@1455: Pattern.compile(".*Warning: replacing invalid numeric character reference .*"), jjg@1455: Pattern.compile(".*Warning: replacing unexpected .* by "), jjg@1455: Pattern.compile(".*Warning: trimming empty <.*>"), jjg@1455: Pattern.compile(".*Warning: unescaped & or unknown entity \".*\""), jjg@1455: Pattern.compile(".*Warning: unescaped & which should be written as &"), jjg@1455: Pattern.compile(".*Warning: using
in place of

") jjg@1455: }; jjg@1455: jjg@1455: int files; jjg@1455: int ok; jjg@1455: int warns; jjg@1455: int errs; jjg@1455: int css; jjg@1455: int overflow; jjg@1455: } jjg@1455: