package unstar;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.NoSuchElementException;
import lombok.SneakyThrows;
import lombok.extern.java.Log;

/**
 * Provide codes from a file.
 */
@Log
public final class InputStreamCodeProvider implements CodeProvider {

    /** The file reader for reading codes. */
    private final BufferedReader reader;

    /** The next code. */
    private String next = null;

    /**
     * Create a new provider for the given file.
     * @param in  the stream to read codes from
     */
    @SneakyThrows
    public InputStreamCodeProvider(final InputStream in) {
        reader = new BufferedReader(new InputStreamReader(in));
        next = reader.readLine();
    }

    @Override
    @SneakyThrows
    public String next() {
        String ret = next;
        next = reader.readLine();
        if (ret == null) {
            throw new NoSuchElementException();
        }
        return ret;
    }

    @Override
    public boolean hasNext() {
        return next != null;
    }

    @Override
    public void report(final String code) {
        log.info("valid: " + code);
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }
}

@@ -29,84 +29,19 @@
 .io.
-BufferedReader;%0Aimport java.io.InputStream;%0Aimport java.io.InputStreamReader
+InputStream
 ;%0Aim
@@ -79,16 +79,42 @@
 eption;%0A
+import java.util.Scanner;%0A
 import l
@@ -294,105 +294,253 @@
 The 
-file reader for reading codes. */%0A    private final BufferedReader reader;%0A%0A    /** The next code
+terminator line that can end the stream early. */%0A    public static final String TERMINATOR = %22--------%22;%0A%0A    /** The file reader for reading codes. */%0A    private final Scanner scanner;%0A%0A    /** Peekahead string for checking for the terminator
 . */
@@ -559,20 +559,20 @@
  String 
-next
+peek
  = null;
@@ -573,16 +573,111 @@
  null;%0A%0A
+    /** True if the terminator line has been read. */%0A    private boolean terminated = false;%0A%0A
     /**%0A
@@ -866,20 +866,21 @@
         
-read
+scann
 er = new
@@ -884,82 +884,18 @@
 new 
-BufferedReader(new InputStreamReader(in));%0A        next = reader.readLine(
+Scanner(in
 );%0A 
@@ -971,84 +971,218 @@
     
-String ret = next;%0A        next = reader.readLine();%0A        if (ret == null
+if (terminated) %7B%0A            throw new NoSuchElementException();%0A        %7D else if (peek != null) %7B%0A            String ret = peek;%0A            peek = null;%0A            return ret;%0A        %7D else if (!hasNext()
 ) %7B%0A
@@ -1250,27 +1250,30 @@
      return 
-ret
+next()
 ;%0A    %7D%0A%0A   
@@ -1326,28 +1326,301 @@
     
-return next != null;
+if (peek != null) %7B%0A            return true;%0A        %7D else if (scanner.hasNextLine()) %7B%0A            peek = scanner.nextLine();%0A            terminated = peek.equals(TERMINATOR);%0A            return !terminated;%0A        %7D else %7B%0A            terminated = true;%0A            return false;%0A        %7D
 %0A   
@@ -1703,14 +1703,13 @@
 fo(%22
-valid:
+VALID
  %22 +

Add a terminator line to InputStreamCodeProvider.