from typing import Iterator
import warnings


def _read_next_tag(fp: Iterator[str]) -> bytes:
  """Read the next tag from the tag file.

  Attempts to read the next item from the iterator (usually a text file) `fp`
  for use as the printable final 18 bytes of a block tag.  bootloader_hd
  prints the last 18 bytes of all but the final block's tag to the screen,
  making these tags useful progress indicators. Tags can be up to eighteen
  bytes long and may only contain the characters A..Z, 0..9, and "./-?" (quotes
  not included), which are all that's defined in the ROM. Any tag with fewer
  than eighteen characters will be padded with spaces.

  Args:
    fp: iterator to read tags from.

  Returns: 18-byte string for use as the printable part of a block tag.

  Raises:
    IOError: if end of file is encountered.
    RuntimeError: if a tag uses characters not found in the Lisa Boot ROM.
  """
  # Read "raw" line and clip away CR/CRLF/LF.
  try:
    tag = next(fp)
  except StopIteration:
    raise IOError('ran out of tags in the tag file.')
  tag = tag.rstrip('\r\n')

  # Scan line for chars not in the ROM.
  if any(c not in '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ ./-?' for c in tag):
    raise RuntimeError('tag {} has chars not found in the ROM'.format(tag))

  # Warn if the tag is too long and truncate to 20 bytes.
  if len(tag) > 18:
    warnings.warn('tag {} will be clipped to 18 bytes'.format(tag), UserWarning)
    tag = tag[:18]

  # Space-pad, convert to bytes, and return.
  return bytes(tag + (' ' * (18 - len(tag))), 'ascii')