1/*
2 Copyright (c) 2000, 2011, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16*/
17
18/* readline for batch mode */
19
20#include <my_global.h>
21#include <my_sys.h>
22#include <m_string.h>
23#include <my_dir.h>
24#include "my_readline.h"
25
26static bool init_line_buffer(LINE_BUFFER *buffer,File file,ulong size,
27 ulong max_size);
28static bool init_line_buffer_from_string(LINE_BUFFER *buffer,char * str);
29static size_t fill_buffer(LINE_BUFFER *buffer);
30static char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length);
31
32
33LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file)
34{
35 LINE_BUFFER *line_buff;
36
37#ifndef __WIN__
38 MY_STAT input_file_stat;
39 if (my_fstat(fileno(file), &input_file_stat, MYF(MY_WME)) ||
40 MY_S_ISDIR(input_file_stat.st_mode) ||
41 MY_S_ISBLK(input_file_stat.st_mode))
42 return 0;
43#endif
44
45 if (!(line_buff=(LINE_BUFFER*)
46 my_malloc(sizeof(*line_buff),MYF(MY_WME | MY_ZEROFILL))))
47 return 0;
48 if (init_line_buffer(line_buff,my_fileno(file),IO_SIZE,max_size))
49 {
50 my_free(line_buff);
51 return 0;
52 }
53 return line_buff;
54}
55
56
57char *batch_readline(LINE_BUFFER *line_buff, bool binary_mode)
58{
59 char *pos;
60 ulong UNINIT_VAR(out_length);
61
62 if (!(pos=intern_read_line(line_buff, &out_length)))
63 return 0;
64 if (out_length && pos[out_length-1] == '\n')
65 {
66 /*
67 On Windows platforms we also need to remove '\r', unconditionally. On
68 Unix-like platforms we only remove it if we are not on binary mode.
69 */
70
71 /* Remove '\n' */
72 if (--out_length && IF_WIN(1,!binary_mode) && pos[out_length-1] == '\r')
73 /* Remove '\r' */
74 out_length--;
75 }
76 line_buff->read_length=out_length;
77 pos[out_length]=0;
78 return pos;
79}
80
81
82void batch_readline_end(LINE_BUFFER *line_buff)
83{
84 if (line_buff)
85 {
86 my_free(line_buff->buffer);
87 my_free(line_buff);
88 }
89}
90
91
92LINE_BUFFER *batch_readline_command(LINE_BUFFER *line_buff, char * str)
93{
94 if (!line_buff)
95 if (!(line_buff=(LINE_BUFFER*)
96 my_malloc(sizeof(*line_buff),MYF(MY_WME | MY_ZEROFILL))))
97 return 0;
98 if (init_line_buffer_from_string(line_buff,str))
99 {
100 my_free(line_buff);
101 return 0;
102 }
103 return line_buff;
104}
105
106
107/*****************************************************************************
108 Functions to handle buffered readings of lines from a stream
109******************************************************************************/
110
111static bool
112init_line_buffer(LINE_BUFFER *buffer,File file,ulong size,ulong max_buffer)
113{
114 buffer->file=file;
115 buffer->bufread=size;
116 buffer->max_size=max_buffer;
117 if (!(buffer->buffer = (char*) my_malloc(buffer->bufread+1,
118 MYF(MY_WME | MY_FAE))))
119 return 1;
120 buffer->end_of_line=buffer->end=buffer->buffer;
121 buffer->buffer[0]=0; /* For easy start test */
122 return 0;
123}
124
125/*
126 init_line_buffer_from_string can be called on the same buffer
127 several times. the resulting buffer will contain a
128 concatenation of all strings separated by spaces
129*/
130static bool init_line_buffer_from_string(LINE_BUFFER *buffer,char * str)
131{
132 uint old_length=(uint)(buffer->end - buffer->buffer);
133 uint length= (uint) strlen(str);
134 if (!(buffer->buffer= buffer->start_of_line= buffer->end_of_line=
135 (char*) my_realloc((uchar*) buffer->buffer, old_length+length+2,
136 MYF(MY_FAE|MY_ALLOW_ZERO_PTR))))
137 return 1;
138 buffer->end= buffer->buffer + old_length;
139 if (old_length)
140 buffer->end[-1]=' ';
141 memcpy(buffer->end, str, length);
142 buffer->end[length]= '\n';
143 buffer->end[length+1]= 0;
144 buffer->end+= length+1;
145 buffer->eof=1;
146 buffer->max_size=1;
147 return 0;
148}
149
150
151/*
152 Fill the buffer retaining the last n bytes at the beginning of the
153 newly filled buffer (for backward context). Returns the number of new
154 bytes read from disk.
155*/
156
157static size_t fill_buffer(LINE_BUFFER *buffer)
158{
159 size_t read_count;
160 uint bufbytes= (uint) (buffer->end - buffer->start_of_line);
161
162 if (buffer->eof)
163 return 0; /* Everything read */
164
165 /* See if we need to grow the buffer. */
166
167 for (;;)
168 {
169 uint start_offset=(uint) (buffer->start_of_line - buffer->buffer);
170 read_count=(buffer->bufread - bufbytes)/IO_SIZE;
171 if ((read_count*=IO_SIZE))
172 break;
173 if (buffer->bufread * 2 > buffer->max_size)
174 {
175 /*
176 So we must grow the buffer but we cannot due to the max_size limit.
177 Return 0 w/o setting buffer->eof to signal this condition.
178 */
179 return 0;
180 }
181 buffer->bufread *= 2;
182 if (!(buffer->buffer = (char*) my_realloc(buffer->buffer,
183 buffer->bufread+1,
184 MYF(MY_WME | MY_FAE))))
185 {
186 buffer->error= my_errno;
187 return (size_t) -1;
188 }
189 buffer->start_of_line=buffer->buffer+start_offset;
190 buffer->end=buffer->buffer+bufbytes;
191 }
192
193 /* Shift stuff down. */
194 if (buffer->start_of_line != buffer->buffer)
195 {
196 bmove(buffer->buffer,buffer->start_of_line,(uint) bufbytes);
197 buffer->end=buffer->buffer+bufbytes;
198 }
199
200 /* Read in new stuff. */
201 if ((read_count= my_read(buffer->file, (uchar*) buffer->end, read_count,
202 MYF(MY_WME))) == MY_FILE_ERROR)
203 {
204 buffer->error= my_errno;
205 return (size_t) -1;
206 }
207
208 DBUG_PRINT("fill_buff", ("Got %lu bytes", (ulong) read_count));
209
210 if (!read_count)
211 {
212 buffer->eof = 1;
213 /* Kludge to pretend every nonempty file ends with a newline. */
214 if (bufbytes && buffer->end[-1] != '\n')
215 {
216 read_count = 1;
217 *buffer->end = '\n';
218 }
219 }
220 buffer->end_of_line=(buffer->start_of_line=buffer->buffer)+bufbytes;
221 buffer->end+=read_count;
222 *buffer->end=0; /* Sentinel */
223 return read_count;
224}
225
226
227char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length)
228{
229 char *pos;
230 size_t length;
231 DBUG_ENTER("intern_read_line");
232
233 buffer->start_of_line=buffer->end_of_line;
234 for (;;)
235 {
236 pos=buffer->end_of_line;
237 while (*pos != '\n' && pos != buffer->end)
238 pos++;
239 if (pos == buffer->end)
240 {
241 /*
242 fill_buffer() can return NULL on EOF (in which case we abort),
243 on error, or when the internal buffer has hit the size limit.
244 In the latter case return what we have read so far and signal
245 string truncation.
246 */
247 if (!(length= fill_buffer(buffer)))
248 {
249 if (buffer->eof)
250 DBUG_RETURN(0);
251 }
252 else if (length == (size_t) -1)
253 DBUG_RETURN(NULL);
254 else
255 continue;
256 pos--; /* break line here */
257 buffer->truncated= 1;
258 }
259 else
260 buffer->truncated= 0;
261 buffer->end_of_line=pos+1;
262 *out_length=(ulong) (pos + 1 - buffer->eof - buffer->start_of_line);
263 DBUG_RETURN(buffer->start_of_line);
264 }
265}
266