FileDocCategorySizeDatePackage
GetMark.javaAPI DocExample4883Sun Feb 08 17:57:30 GMT 2004None

GetMark.java

import java.io.*;

/** GetMark -- get marked lines.
 * <p>
 * GetMark is a general tool for including/excluding parts of a file.
 * It can be used, for example, to extract parts of a file for use
 * in documentation, or to delete parts of a file such as the working
 * part of a solution.
 * <p>
 * The marks that it looks for are simple, and can be left in the
 * master source (they never print). The mark //+ (as looked for
 * with line.trim().equals("//+) in Java) begins printing, and the
 * opposite mark //- stops printing.
 * <p>
 * So, for a course exercise, you would develop the working
 * solution and comment it neatly, and add a //- mark after the TODO
 * comments but before the working solution, and a //+ mark after it.
 * For example:
 * </p><pre>
 * 	public methodA() {
 * 		// TODO:
 * 		// Look up the object to be invoked.
 * 		// Use a Lookup Name of "ex31object"
 * 
 * 		//-
 * 		Object o = Naming.lookup("ex31object");
 * 		//+
 * 
 * 		// TODO #2
 * 		// Downcast the looked up object using the IIOP portability
 * 
 * 		//-
 * 		Ex31Object obj = (Ex31Object)PortableRemoteObject.narrow(
 * 			o, Ex31Object.class);
 * 		//+
 * 	}
 * </pre><p>
 * When run through GetMark in "exclude" mode, the above will produce:
 * </p><pre>
 *  public methodA() {
 *      // TODO:
 *      // Look up the object to be invoked.
 *      // Use a Lookup Name of "ex31object"
 * 
 * 
 *      // TODO #2
 *      // Downcast the looked up object using the IIOP portability
 *
 *  }
 * </pre><p>
 * You could use this in a script:
 * </p><pre>
 * for f in *.java
 * do
 *    echo $f
 *    java GetMark $f > ../solutions/$f
 * done
 * </pre><p>
 * For an example of using GetMark for extraction
 * (GetMark first appeared in my 
 * <a href="http://javacook.darwinsys.com/">Java Cookbook</a>),
 * see the comments in the code for GetMark itself.
 * <p>
 * In this version, the mode (include or extract) and the strings for
 * the marks are hard-coded; ideally they would come
 * from a Properties or Preferences object and/or from the command line.
 *
 * @author Ian F. Darwin, http://www.darwinsys.com/
 * @version $Id: GetMark.java,v 1.16 2004/02/08 23:57:29 ian Exp $
 */
public class GetMark {
	/** the default starting mark. */
	public final String startMark = "//+";
	/** the default ending mark. */
	public final String endMark = "//-";
	/** Set this to TRUE for running in "exclude" mode (e.g., for
	 * building exercises from solutions) and to FALSE for running
	 * in "extract" mode (e.g., writing a book and ommittin the
	 * imports and "public class" stuff).
	 */
	public final static boolean START = true;
	/** True if we are currently inside marks. */
	protected boolean printing = START;
	/** True if you want line numbers */
	protected final boolean number = false;
	//-
	/* This part should be excluded! */
	int foo = 42;
	//+

    /** Get Marked parts of one file, given an open LineNumberReader.
	 * This is the main operation of this class, and can be used
	 * inside other programs or from the main() wrapper.
	 */
    public void process(String fileName,
		LineNumberReader is,
		PrintStream out) {
		//+
		int nLines = 0;
		try {
			String inputLine;

			while ((inputLine = is.readLine()) != null) {
				if (inputLine.trim().equals(startMark)) {
					if (printing)
						// These go to stderr, so you can redirect the output
						System.err.println("ERROR: START INSIDE START, " +
							fileName + ':' + is.getLineNumber());
					printing = true;
				} else if (inputLine.trim().equals(endMark)) {
					if (!printing)
						System.err.println("ERROR: STOP WHILE STOPPED, " +
							fileName + ':' + is.getLineNumber());
					printing = false;
				} else if (printing) {
					if (number) {
						out.print(nLines);
						out.print(": ");
					}
					out.println(inputLine);
					++nLines;
				}
            }
            is.close();
			out.flush(); // Must not close - caller may still need it.
			if (nLines == 0)
				System.err.println("ERROR: No marks in " + fileName +
					"; no output generated!");
		//-
        } catch (IOException e) {
            System.out.println("IOException: " + e);
        }
    }

	/** This simple main program looks after filenames and
	 * opening files and such like for you, when GetMark is being
	 * used standalone.
	 * XXX TODO options parsing, allow include/exclude, number, etc.
	 * to be set from the command line.
	 */
    public static void main(String[] av) {
        GetMark o = new GetMark();
		PrintStream pw = new PrintStream(System.out);
        if (av.length == 0) {
            o.process("standard input", new LineNumberReader(
				new InputStreamReader(System.in)), pw);
		} else {
			for (int i=0; i<av.length; i++)
				try {
					o.process(av[i],
						new LineNumberReader(new FileReader(av[i])), pw);
				} catch (FileNotFoundException e) {
					System.err.println(e);
				}
        }
    }
}