// Generates a token-to-line cross-reference listing import java.util.*; import java.io.*; class Xref { // Comparator to ignore case: static class NoCase implements Comparator { public int compare(Object o1, Object o2) { String s1 = (String) o1; String s2 = (String) o2; return s1.compareToIgnoreCase(s2); } } // This method does the work: static void process(BufferedReader r) throws IOException { TreeMap map = new TreeMap(new NoCase()); String line; int lineno = 0; // Build map, reading a line at a time: while ((line = r.readLine()) != null) { ++lineno; // Read each token: String delim = " `~!@#$%^&*()-_=+\\|[{]};:'\",<.>/?" + "0123456789"; StringTokenizer tokens = new StringTokenizer(line, delim); while (tokens.hasMoreTokens()) { String token = tokens.nextToken(); if (!map.containsKey(token)) { // Add token and empty list to map: map.put(token, new LinkedList()); } // See if this line is in there already: LinkedList lines = (LinkedList) map.get(token); if (lines.isEmpty() || ((Integer)lines.getLast()).intValue() != lineno) { // Add line number to list: lines.addLast(new Integer(lineno)); } } } // Output: Iterator p = map.entrySet().iterator(); while (p.hasNext()) { Map.Entry e = (Map.Entry) p.next(); System.out.print(e.getKey() + ": "); LinkedList lines = (LinkedList) e.getValue(); Iterator lineIter = lines.iterator(); while (lineIter.hasNext()) { Integer i = (Integer) lineIter.next(); if (i != (Integer) lines.getFirst()) { System.out.print(", "); } System.out.print(i); } System.out.println(); } } public static void main(String[] args) throws IOException { if (args.length == 0) { // Process standard input: Reader r = new InputStreamReader(System.in); process(new BufferedReader(r)); } else { // Process each specified file: for (int i = 0; i < args.length; ++i) { if (i > 0) { System.out.println(); } System.out.println("*** File: " + args[i] + " ***"); FileReader f = new FileReader(args[i]); process(new BufferedReader(f)); } } } }