3.48. kink/io/SCANNER

Companion mod of scanners.

3.48.1. type scanner

A scanner is an input port for strs from an underlying source of runes such as a file.

A scanner provides sequential forward access to the underlying source of runes.

Example:

:FILE.require_from('kink/io/')
:CONTROL.require_from('kink/')

CONTROL.with_on_exit{(:on_exit)
  :S = FILE.open_to_scan('/etc/passwd' 'UTF-8')
  # result of FILE.open_to_scan also supports .close method of input type
  on_exit{ S.close }

  stdout.print_line(S.scan_line.repr)
}
# => "root:x:0:0:root:/root:/bin/bash\n"

Operations on a scanner may cause IO errors, thus the methods take $on_error optional parameter to handle an IO error.

Commonly used scanners:

• kink/CORE.stdin is a scanner+input connected to the standard input.

• kink/io/FILE.open_to_scan returns a scanner+input for a file.

• kink/io/STR_SCANNER.new returns an in-memory scanner for a str.

Scanner.scan_rune(...[$on_error])

Scanner.scan_rune reads a rune from the underlying source. If the rune exists, the method returns a single-element vec [rune]; otherwise, returns an empty vec [].

Example:

:STR_SCANNER.require_from('kink/io/')

:S <- STR_SCANNER.new('foo')
stdout.print_line(S.scan_rune.repr)   # => [102]
stdout.print_line(S.scan_rune.repr)   # => [111]
stdout.print_line(S.scan_rune.repr)   # => [111]
stdout.print_line(S.scan_rune.repr)   # => []
stdout.print_line(S.scan_rune.repr)   # => []

When an error occurs, Scanner.scan_rune tail-calls $on_error with an error message, or raises an exception if $on_error is not given.

Example:

:FILE.require_from('kink/io/')
:CONTROL.require_from('kink/')

:S <- FILE.open_to_scan('/etc/passwd' 'UTF-8')
S.close
S.scan_rune{(:M)
  stderr.print_line(M)
}
# => java.io.IOException: Stream Closed

CONTROL.try(
  { S.scan_rune }
  { raise('not here') }
  {(:Msg :Traces)
    stderr.print_line(Msg)
  }
)
# => java.io.IOException: Stream Closed

Scanner.scan_line(...[$on_error])

Scanner.scan_line reads a line, which ends with "\n" or the end of the stream.

If there is no remaining runes, the method returns an empty str.

Example:

:STR_SCANNER.require_from('kink/io/')

:S <- STR_SCANNER.new("foo\nbar")
stdout.print_line(S.scan_line.repr)   # => "foo\n"
stdout.print_line(S.scan_line.repr)   # => "bar"
stdout.print_line(S.scan_line.repr)   # => ""
stdout.print_line(S.scan_line.repr)   # => ""

When an error occurs, Scanner.scan_line tail-calls $on_error with an error message, or raises an exception if $on_error is not given.

Example:

:FILE.require_from('kink/io/')
:CONTROL.require_from('kink/')

:S <- FILE.open_to_scan('/etc/passwd' 'UTF-8')
S.close
S.scan_line{(:M)
  stderr.print_line(M)
}
# => java.io.IOException: Stream Closed

CONTROL.try(
  { S.scan_line }
  { raise('not here') }
  {(:Msg :Traces)
    stderr.print_line(Msg)
  }
)
# => java.io.IOException: Stream Closed

Scanner.scan_text(...[$on_error])

Scanner.scan_text reads the remaining runes as a str.

If there is no remaining runes, the method returns an empty str.

Example:

:STR_SCANNER.require_from('kink/io/')

:S <- STR_SCANNER.new("foo\nbar")
stdout.print_line(S.scan_text.repr)   # => "foo\nbar"
stdout.print_line(S.scan_text.repr)   # => ""
stdout.print_line(S.scan_text.repr)   # => ""

When an error occurs, Scanner.scan_text tail-calls $on_error with an error message, or raises an exception if $on_error is not given.

:FILE.require_from('kink/io/')
:CONTROL.require_from('kink/')

:S <- FILE.open_to_scan('/etc/passwd' 'UTF-8')
S.close
S.scan_text{(:M)
  stderr.print_line(M)
}
# => java.io.IOException: Stream Closed

CONTROL.try(
  { S.scan_text }
  { raise('not here') }
  {(:Msg :Traces)
    stderr.print_line(Msg)
  }
)
# => java.io.IOException: Stream Closed

3.48.2. SCANNER.scanner?(Val)

SCANNER.scanner? returns whether the Val is a scanner.

3.48.3. SCANNER.wrap(Input Encoding_name)

SCANNER.wrap makes a scanner+input, which reads bin from Input and decodes them as Encoding_name.

Preconditions:

• Input must be an input

• Encoding_name must be a str

• Encoding_name must be a valid encoding name

The result supports both scanner type and input type.

Input methods such as read_byte and read_bin read bytes from the underlying Input.

Scanner methods such as scan_rune and scan_line converts bytes read from the underlying Input to runes using the encoding.

Example:

:SCANNER.require_from('kink/io/')
:BIN.require_from('kink/')
:BIN_INPUT.require_from('kink/io/')

:In <- BIN_INPUT.new(BIN.of(102 111 111 10))
:S <- SCANNER.wrap(In 'UTF-8')

# the result suppors input
stdout.print_line(S.read_byte.repr) # => [102]

# the result suppors scanner
stdout.print_line(S.scan_line.repr) # => "oo\n"