Fastest draw in the west!
section .text

global _start

_start:
  xor r8, r8
  xor r9, r9
  xor r10, r10

_do_while:

_getchar:
  cmp r9, r10

  jne _getchar_done

_getchar_read_buffer:
  xor r9, r9

  xor eax, eax
  xor edi, edi
  mov rsi, in_buf
  mov rdx, inbuf_maxlen

  syscall

  mov r10, rax

_getchar_done:
  mov al, [in_buf + r9]
  inc r9


_do_while_cont:
  cmp al, [req + r8]

  jne _reset

_increment:
  inc r8

  cmp r8, 5

  jne _do_while

  mov rax, 1
  mov rdi, 1
  mov rsi, ans
  mov rdx, 5

  syscall

_end:
  mov rax, 60
  xor rdi, rdi

  syscall

_reset:
  xor r8, r8

  cmp al, 'd'

  jne _do_while

  inc r8

  jmp _do_while

section .rodata
  inbuf_maxlen equ 1000000

  req db &quot;draw!&quot;

ALIGN 8
  ans db &quot;bang!&quot;

section .bss
  in_buf resb inbuf_maxlen


A little hand-written assembly. Compile with:
nasm -felf64 foobar.s &amp;&amp; ld foobar.o -o foobar

Edit: move in_bi into a register and use xor.
Edit: used the wrong jump, my code was wrong...
Edit: the previous code had a bug where it would read garbage if the read syscall did not return a full buffer. This version is more efficient (and correct)...
Edit: make sure to process ddraw! correctly. Thanks to Anders Kaseorg for the test case.
Edit: re-structure to move getchar out of a function and to jump less.
Edit: don't xor the high bits of the registers at the suggestion of Cody Gray
Edit: align (thanks to Joshua) and move into .rodata