static int read_and_execute(bool interactive)
{
#if defined(__WIN__)
  String tmpbuf;
  String buffer;
#endif

  char	*line= NULL;
  char	in_string=0;
  ulong line_number=0;
  bool ml_comment= 0;  
  COMMANDS *com;
  ulong line_length= 0;
  status.exit_status=1;

  real_binary_mode= !interactive && opt_binary_mode;
  for (;;)
  {
    if (!interactive)
    {
      /*
        batch_readline can return 0 on EOF or error.
        In that case, we need to double check that we have a valid
        line before actually setting line_length to read_length.
        */
      line= batch_readline(status.line_buff, real_binary_mode);
      if (line) 
      {
        line_length= status.line_buff->read_length;

        /*
          ASCII 0x00 is not allowed appearing in queries if it is not in binary
          mode.
        */
        if (!real_binary_mode && strlen(line) != line_length)
        {
          status.exit_status= 1;
          String msg;
          msg.append("ASCII '\\0' appeared in the statement, but this is not "
                     "allowed unless option --binary-mode is enabled and mysql is "
                     "run in non-interactive mode. Set --binary-mode to 1 if ASCII "
                     "'\\0' is expected. Query: '");
          msg.append(glob_buffer);
          msg.append(line);
          msg.append("'.");
          put_info(msg.c_ptr(), INFO_ERROR);
          break;
        }

        /*
          Skip UTF8 Byte Order Marker (BOM) 0xEFBBBF.
          Editors like "notepad" put this marker in
          the very beginning of a text file when
          you save the file using "Unicode UTF-8" format.
        */
        if (!line_number &&
             (uchar) line[0] == 0xEF &&
             (uchar) line[1] == 0xBB &&
             (uchar) line[2] == 0xBF)
        {
          line+= 3;
          // decrease the line length accordingly to the 3 bytes chopped
          line_length -=3;
        }
      }
      line_number++;
      if (!glob_buffer.length())
	status.query_start_line=line_number;
    }
    else
    {
      char *prompt= (char*) (ml_comment ? "   /*> " :
                             glob_buffer.is_empty() ?  construct_prompt() :
			     !in_string ? "    -> " :
			     in_string == '\'' ?
			     "    '> " : (in_string == '`' ?
			     "    `> " :
			     "    \"> "));
      if (opt_outfile && glob_buffer.is_empty())
	fflush(OUTFILE);

#if defined(__WIN__)
      tee_fputs(prompt, stdout);
      if (!tmpbuf.is_alloced())
        tmpbuf.alloc(65535);
      tmpbuf.length(0);
      buffer.length(0);
      line= my_win_console_readline(charset_info,
                                    (char *) tmpbuf.ptr(),
                                    tmpbuf.alloced_length());
#else
      if (opt_outfile)
	fputs(prompt, OUTFILE);
      /*
        free the previous entered line.
        Note: my_free() cannot be used here as the memory was allocated under
        the readline/libedit library.
      */
      if (line)
        free(line);
      line= readline(prompt);
#endif /* defined(__WIN__) */

      /*
        When Ctrl+d or Ctrl+z is pressed, the line may be NULL on some OS
        which may cause coredump.
      */
      if (opt_outfile && line)
	fprintf(OUTFILE, "%s\n", line);

      line_length= line ? strlen(line) : 0;
    }
    // End of file or system error
    if (!line)
    {
      if (status.line_buff && status.line_buff->error)
        status.exit_status= 1;
      else
        status.exit_status= 0;
      break;
    }

    /*
      Check if line is a mysql command line
      (We want to allow help, print and clear anywhere at line start
    */
    if ((named_cmds || glob_buffer.is_empty())
	&& !ml_comment && !in_string && (com= find_command(line)))
    {
      if ((*com->func)(&glob_buffer,line) > 0)
	break;
      if (glob_buffer.is_empty())		// If buffer was emptied
	in_string=0;
#ifdef HAVE_READLINE
      if (interactive && status.add_to_history && not_in_history(line))
	add_filtered_history(line);
#endif
      continue;
    }
    if (add_line(glob_buffer, line, line_length, &in_string, &ml_comment,
                 status.line_buff ? status.line_buff->truncated : 0))
      break;
  }
  /* if in batch mode, send last query even if it doesn't end with \g or go */

  if (!interactive && !status.exit_status)
  {
    remove_cntrl(glob_buffer);
    if (!glob_buffer.is_empty())
    {
      status.exit_status=1;
      if (com_go(&glob_buffer,line) <= 0)
	status.exit_status=0;
    }
  }

#if defined(__WIN__)
  buffer.free();
  tmpbuf.free();
#else
  if (interactive)
    /*
      free the last entered line.
      Note: my_free() cannot be used here as the memory was allocated under
      the readline/libedit library.
    */
    free(line);
#endif

  /*
    If the function is called by 'source' command, it will return to interactive
    mode, so real_binary_mode should be FALSE. Otherwise, it will exit the
    program, it is safe to set real_binary_mode to FALSE.
  */
  real_binary_mode= FALSE;
  return status.exit_status;
}