Listing 15: Xref.java — a cross-reference lister

//  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));
            }
        }
    }
}