summaryrefslogtreecommitdiffstats
path: root/client/readline.cc
diff options
context:
space:
mode:
Diffstat (limited to 'client/readline.cc')
-rw-r--r--client/readline.cc267
1 files changed, 267 insertions, 0 deletions
diff --git a/client/readline.cc b/client/readline.cc
new file mode 100644
index 00000000..8d3d97b8
--- /dev/null
+++ b/client/readline.cc
@@ -0,0 +1,267 @@
+/*
+ Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
+*/
+
+/* readline for batch mode */
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <my_dir.h>
+#include "my_readline.h"
+
+static bool init_line_buffer(LINE_BUFFER *buffer,File file,ulong size,
+ ulong max_size);
+static bool init_line_buffer_from_string(LINE_BUFFER *buffer,char * str);
+static size_t fill_buffer(LINE_BUFFER *buffer);
+static char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length);
+
+
+LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file)
+{
+ LINE_BUFFER *line_buff;
+
+#ifndef __WIN__
+ MY_STAT input_file_stat;
+ if (my_fstat(fileno(file), &input_file_stat, MYF(MY_WME)) ||
+ MY_S_ISDIR(input_file_stat.st_mode) ||
+ MY_S_ISBLK(input_file_stat.st_mode))
+ return 0;
+#endif
+
+ if (!(line_buff=(LINE_BUFFER*)
+ my_malloc(PSI_NOT_INSTRUMENTED, sizeof(*line_buff),
+ MYF(MY_WME | MY_ZEROFILL))))
+ return 0;
+ if (init_line_buffer(line_buff,my_fileno(file),IO_SIZE,max_size))
+ {
+ my_free(line_buff);
+ return 0;
+ }
+ return line_buff;
+}
+
+
+char *batch_readline(LINE_BUFFER *line_buff, bool binary_mode)
+{
+ char *pos;
+ ulong UNINIT_VAR(out_length);
+
+ if (!(pos=intern_read_line(line_buff, &out_length)))
+ return 0;
+ if (out_length && pos[out_length-1] == '\n')
+ {
+ /*
+ On Windows platforms we also need to remove '\r', unconditionally. On
+ Unix-like platforms we only remove it if we are not on binary mode.
+ */
+
+ /* Remove '\n' */
+ if (--out_length && IF_WIN(1,!binary_mode) && pos[out_length-1] == '\r')
+ /* Remove '\r' */
+ out_length--;
+ }
+ line_buff->read_length=out_length;
+ pos[out_length]=0;
+ return pos;
+}
+
+
+void batch_readline_end(LINE_BUFFER *line_buff)
+{
+ if (line_buff)
+ {
+ my_free(line_buff->buffer);
+ my_free(line_buff);
+ }
+}
+
+
+LINE_BUFFER *batch_readline_command(LINE_BUFFER *line_buff, char * str)
+{
+ if (!line_buff)
+ if (!(line_buff=(LINE_BUFFER*)
+ my_malloc(PSI_NOT_INSTRUMENTED, sizeof(*line_buff),
+ MYF(MY_WME | MY_ZEROFILL))))
+ return 0;
+ if (init_line_buffer_from_string(line_buff,str))
+ {
+ my_free(line_buff);
+ return 0;
+ }
+ return line_buff;
+}
+
+
+/*****************************************************************************
+ Functions to handle buffered readings of lines from a stream
+******************************************************************************/
+
+static bool
+init_line_buffer(LINE_BUFFER *buffer,File file,ulong size,ulong max_buffer)
+{
+ buffer->file=file;
+ buffer->bufread=size;
+ buffer->max_size=max_buffer;
+ if (!(buffer->buffer = (char*) my_malloc(PSI_NOT_INSTRUMENTED,
+ buffer->bufread+1, MYF(MY_WME | MY_FAE))))
+ return 1;
+ buffer->end_of_line=buffer->end=buffer->buffer;
+ buffer->buffer[0]=0; /* For easy start test */
+ return 0;
+}
+
+/*
+ init_line_buffer_from_string can be called on the same buffer
+ several times. the resulting buffer will contain a
+ concatenation of all strings separated by spaces
+*/
+static bool init_line_buffer_from_string(LINE_BUFFER *buffer,char * str)
+{
+ uint old_length=(uint)(buffer->end - buffer->buffer);
+ uint length= (uint) strlen(str);
+ if (!(buffer->buffer= buffer->start_of_line= buffer->end_of_line=
+ (char*) my_realloc(PSI_NOT_INSTRUMENTED, buffer->buffer,
+ old_length+length+2, MYF(MY_FAE|MY_ALLOW_ZERO_PTR))))
+ return 1;
+ buffer->end= buffer->buffer + old_length;
+ if (old_length)
+ buffer->end[-1]=' ';
+ memcpy(buffer->end, str, length);
+ buffer->end[length]= '\n';
+ buffer->end[length+1]= 0;
+ buffer->end+= length+1;
+ buffer->eof=1;
+ buffer->max_size=1;
+ return 0;
+}
+
+
+/*
+ Fill the buffer retaining the last n bytes at the beginning of the
+ newly filled buffer (for backward context). Returns the number of new
+ bytes read from disk.
+*/
+
+static size_t fill_buffer(LINE_BUFFER *buffer)
+{
+ size_t read_count;
+ uint bufbytes= (uint) (buffer->end - buffer->start_of_line);
+
+ if (buffer->eof)
+ return 0; /* Everything read */
+
+ /* See if we need to grow the buffer. */
+
+ for (;;)
+ {
+ uint start_offset=(uint) (buffer->start_of_line - buffer->buffer);
+ read_count=(buffer->bufread - bufbytes)/IO_SIZE;
+ if ((read_count*=IO_SIZE))
+ break;
+ if (buffer->bufread * 2 > buffer->max_size)
+ {
+ /*
+ So we must grow the buffer but we cannot due to the max_size limit.
+ Return 0 w/o setting buffer->eof to signal this condition.
+ */
+ return 0;
+ }
+ buffer->bufread *= 2;
+ if (!(buffer->buffer = (char*) my_realloc(PSI_NOT_INSTRUMENTED,
+ buffer->buffer, buffer->bufread+1,
+ MYF(MY_WME | MY_FAE))))
+ {
+ buffer->error= my_errno;
+ return (size_t) -1;
+ }
+ buffer->start_of_line=buffer->buffer+start_offset;
+ buffer->end=buffer->buffer+bufbytes;
+ }
+
+ /* Shift stuff down. */
+ if (buffer->start_of_line != buffer->buffer)
+ {
+ bmove(buffer->buffer,buffer->start_of_line,(uint) bufbytes);
+ buffer->end=buffer->buffer+bufbytes;
+ }
+
+ /* Read in new stuff. */
+ if ((read_count= my_read(buffer->file, (uchar*) buffer->end, read_count,
+ MYF(MY_WME))) == MY_FILE_ERROR)
+ {
+ buffer->error= my_errno;
+ return (size_t) -1;
+ }
+
+ DBUG_PRINT("fill_buff", ("Got %lu bytes", (ulong) read_count));
+
+ if (!read_count)
+ {
+ buffer->eof = 1;
+ /* Kludge to pretend every nonempty file ends with a newline. */
+ if (bufbytes && buffer->end[-1] != '\n')
+ {
+ read_count = 1;
+ *buffer->end = '\n';
+ }
+ }
+ buffer->end_of_line=(buffer->start_of_line=buffer->buffer)+bufbytes;
+ buffer->end+=read_count;
+ *buffer->end=0; /* Sentinel */
+ return read_count;
+}
+
+
+char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length)
+{
+ char *pos;
+ size_t length;
+ DBUG_ENTER("intern_read_line");
+
+ buffer->start_of_line=buffer->end_of_line;
+ for (;;)
+ {
+ pos=buffer->end_of_line;
+ while (*pos != '\n' && pos != buffer->end)
+ pos++;
+ if (pos == buffer->end)
+ {
+ /*
+ fill_buffer() can return NULL on EOF (in which case we abort),
+ on error, or when the internal buffer has hit the size limit.
+ In the latter case return what we have read so far and signal
+ string truncation.
+ */
+ if (!(length= fill_buffer(buffer)))
+ {
+ if (buffer->eof)
+ DBUG_RETURN(0);
+ }
+ else if (length == (size_t) -1)
+ DBUG_RETURN(NULL);
+ else
+ continue;
+ pos--; /* break line here */
+ buffer->truncated= 1;
+ }
+ else
+ buffer->truncated= 0;
+ buffer->end_of_line=pos+1;
+ *out_length=(ulong) (pos + 1 - buffer->eof - buffer->start_of_line);
+ DBUG_RETURN(buffer->start_of_line);
+ }
+}