1
by brian
clean slate |
1 |
/* Copyright (C) 2000 MySQL AB
|
2 |
||
3 |
This program is free software; you can redistribute it and/or modify
|
|
4 |
it under the terms of the GNU General Public License as published by
|
|
5 |
the Free Software Foundation; version 2 of the License.
|
|
6 |
||
7 |
This program is distributed in the hope that it will be useful,
|
|
8 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
9 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
10 |
GNU General Public License for more details.
|
|
11 |
||
12 |
You should have received a copy of the GNU General Public License
|
|
13 |
along with this program; if not, write to the Free Software
|
|
14 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
15 |
||
16 |
/* readline for batch mode */
|
|
17 |
||
18 |
#include <my_global.h> |
|
19 |
#include <my_sys.h> |
|
20 |
#include <m_string.h> |
|
21 |
#include "my_readline.h" |
|
22 |
||
23 |
static bool init_line_buffer(LINE_BUFFER *buffer,File file,ulong size, |
|
24 |
ulong max_size); |
|
25 |
static bool init_line_buffer_from_string(LINE_BUFFER *buffer,char * str); |
|
26 |
static size_t fill_buffer(LINE_BUFFER *buffer); |
|
27 |
static char *intern_read_line(LINE_BUFFER *buffer,ulong *out_length); |
|
28 |
||
29 |
||
30 |
LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file) |
|
31 |
{
|
|
32 |
LINE_BUFFER *line_buff; |
|
33 |
if (!(line_buff=(LINE_BUFFER*) |
|
34 |
my_malloc(sizeof(*line_buff),MYF(MY_WME | MY_ZEROFILL)))) |
|
35 |
return 0; |
|
36 |
if (init_line_buffer(line_buff,fileno(file),IO_SIZE,max_size)) |
|
37 |
{
|
|
38 |
my_free(line_buff,MYF(0)); |
|
39 |
return 0; |
|
40 |
}
|
|
41 |
return line_buff; |
|
42 |
}
|
|
43 |
||
44 |
||
45 |
char *batch_readline(LINE_BUFFER *line_buff) |
|
46 |
{
|
|
47 |
char *pos; |
|
48 |
ulong out_length; |
|
49 |
||
50 |
if (!(pos=intern_read_line(line_buff,&out_length))) |
|
51 |
return 0; |
|
52 |
if (out_length && pos[out_length-1] == '\n') |
|
53 |
if (--out_length && pos[out_length-1] == '\r') /* Remove '\n' */ |
|
54 |
out_length--; /* Remove '\r' */ |
|
55 |
line_buff->read_length=out_length; |
|
56 |
pos[out_length]=0; |
|
57 |
return pos; |
|
58 |
}
|
|
59 |
||
60 |
||
61 |
void batch_readline_end(LINE_BUFFER *line_buff) |
|
62 |
{
|
|
63 |
if (line_buff) |
|
64 |
{
|
|
65 |
my_free(line_buff->buffer,MYF(MY_ALLOW_ZERO_PTR)); |
|
66 |
my_free(line_buff,MYF(0)); |
|
67 |
}
|
|
68 |
}
|
|
69 |
||
70 |
||
71 |
LINE_BUFFER *batch_readline_command(LINE_BUFFER *line_buff, char * str) |
|
72 |
{
|
|
73 |
if (!line_buff) |
|
74 |
if (!(line_buff=(LINE_BUFFER*) |
|
75 |
my_malloc(sizeof(*line_buff),MYF(MY_WME | MY_ZEROFILL)))) |
|
76 |
return 0; |
|
77 |
if (init_line_buffer_from_string(line_buff,str)) |
|
78 |
{
|
|
79 |
my_free(line_buff,MYF(0)); |
|
80 |
return 0; |
|
81 |
}
|
|
82 |
return line_buff; |
|
83 |
}
|
|
84 |
||
85 |
||
86 |
/*****************************************************************************
|
|
87 |
Functions to handle buffered readings of lines from a stream
|
|
88 |
******************************************************************************/
|
|
89 |
||
90 |
static bool |
|
91 |
init_line_buffer(LINE_BUFFER *buffer,File file,ulong size,ulong max_buffer) |
|
92 |
{
|
|
93 |
buffer->file=file; |
|
94 |
buffer->bufread=size; |
|
95 |
buffer->max_size=max_buffer; |
|
96 |
if (!(buffer->buffer = (char*) my_malloc(buffer->bufread+1, |
|
97 |
MYF(MY_WME | MY_FAE)))) |
|
98 |
return 1; |
|
99 |
buffer->end_of_line=buffer->end=buffer->buffer; |
|
100 |
buffer->buffer[0]=0; /* For easy start test */ |
|
101 |
return 0; |
|
102 |
}
|
|
103 |
||
104 |
/*
|
|
105 |
init_line_buffer_from_string can be called on the same buffer
|
|
106 |
several times. the resulting buffer will contain a
|
|
107 |
concatenation of all strings separated by spaces
|
|
108 |
*/
|
|
109 |
static bool init_line_buffer_from_string(LINE_BUFFER *buffer,char * str) |
|
110 |
{
|
|
111 |
uint old_length=(uint)(buffer->end - buffer->buffer); |
|
112 |
uint length= (uint) strlen(str); |
|
113 |
if (!(buffer->buffer= buffer->start_of_line= buffer->end_of_line= |
|
114 |
(char*) my_realloc((uchar*) buffer->buffer, old_length+length+2, |
|
115 |
MYF(MY_FAE|MY_ALLOW_ZERO_PTR)))) |
|
116 |
return 1; |
|
117 |
buffer->end= buffer->buffer + old_length; |
|
118 |
if (old_length) |
|
119 |
buffer->end[-1]=' '; |
|
120 |
memcpy(buffer->end, str, length); |
|
121 |
buffer->end[length]= '\n'; |
|
122 |
buffer->end[length+1]= 0; |
|
123 |
buffer->end+= length+1; |
|
124 |
buffer->eof=1; |
|
125 |
buffer->max_size=1; |
|
126 |
return 0; |
|
127 |
}
|
|
128 |
||
129 |
||
130 |
/*
|
|
131 |
Fill the buffer retaining the last n bytes at the beginning of the
|
|
132 |
newly filled buffer (for backward context). Returns the number of new
|
|
133 |
bytes read from disk.
|
|
134 |
*/
|
|
135 |
||
136 |
static size_t fill_buffer(LINE_BUFFER *buffer) |
|
137 |
{
|
|
138 |
size_t read_count; |
|
139 |
uint bufbytes= (uint) (buffer->end - buffer->start_of_line); |
|
140 |
||
141 |
if (buffer->eof) |
|
142 |
return 0; /* Everything read */ |
|
143 |
||
144 |
/* See if we need to grow the buffer. */
|
|
145 |
||
146 |
for (;;) |
|
147 |
{
|
|
148 |
uint start_offset=(uint) (buffer->start_of_line - buffer->buffer); |
|
149 |
read_count=(buffer->bufread - bufbytes)/IO_SIZE; |
|
150 |
if ((read_count*=IO_SIZE)) |
|
151 |
break; |
|
152 |
buffer->bufread *= 2; |
|
153 |
if (!(buffer->buffer = (char*) my_realloc(buffer->buffer, |
|
154 |
buffer->bufread+1, |
|
155 |
MYF(MY_WME | MY_FAE)))) |
|
156 |
return (uint) -1; |
|
157 |
buffer->start_of_line=buffer->buffer+start_offset; |
|
158 |
buffer->end=buffer->buffer+bufbytes; |
|
159 |
}
|
|
160 |
||
161 |
/* Shift stuff down. */
|
|
162 |
if (buffer->start_of_line != buffer->buffer) |
|
163 |
{
|
|
164 |
bmove(buffer->buffer,buffer->start_of_line,(uint) bufbytes); |
|
165 |
buffer->end=buffer->buffer+bufbytes; |
|
166 |
}
|
|
167 |
||
168 |
/* Read in new stuff. */
|
|
169 |
if ((read_count= my_read(buffer->file, (uchar*) buffer->end, read_count, |
|
170 |
MYF(MY_WME))) == MY_FILE_ERROR) |
|
171 |
return (size_t) -1; |
|
172 |
||
173 |
DBUG_PRINT("fill_buff", ("Got %lu bytes", (ulong) read_count)); |
|
174 |
||
175 |
/* Kludge to pretend every nonempty file ends with a newline. */
|
|
176 |
if (!read_count && bufbytes && buffer->end[-1] != '\n') |
|
177 |
{
|
|
178 |
buffer->eof = read_count = 1; |
|
179 |
*buffer->end = '\n'; |
|
180 |
}
|
|
181 |
buffer->end_of_line=(buffer->start_of_line=buffer->buffer)+bufbytes; |
|
182 |
buffer->end+=read_count; |
|
183 |
*buffer->end=0; /* Sentinel */ |
|
184 |
return read_count; |
|
185 |
}
|
|
186 |
||
187 |
||
188 |
||
189 |
char *intern_read_line(LINE_BUFFER *buffer,ulong *out_length) |
|
190 |
{
|
|
191 |
char *pos; |
|
192 |
size_t length; |
|
193 |
DBUG_ENTER("intern_read_line"); |
|
194 |
||
195 |
buffer->start_of_line=buffer->end_of_line; |
|
196 |
for (;;) |
|
197 |
{
|
|
198 |
pos=buffer->end_of_line; |
|
199 |
while (*pos != '\n' && *pos) |
|
200 |
pos++; |
|
201 |
if (pos == buffer->end) |
|
202 |
{
|
|
203 |
if ((uint) (pos - buffer->start_of_line) < buffer->max_size) |
|
204 |
{
|
|
205 |
if (!(length=fill_buffer(buffer)) || length == (size_t) -1) |
|
206 |
DBUG_RETURN(0); |
|
207 |
continue; |
|
208 |
}
|
|
209 |
pos--; /* break line here */ |
|
210 |
}
|
|
211 |
buffer->end_of_line=pos+1; |
|
212 |
*out_length=(ulong) (pos + 1 - buffer->eof - buffer->start_of_line); |
|
213 |
DBUG_RETURN(buffer->start_of_line); |
|
214 |
}
|
|
215 |
}
|