1 To: vim_dev@googlegroups.com
4 From: Bram Moolenaar <Bram@moolenaar.net>
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
11 Problem: readfile() can be slow with long lines.
12 Solution: Use realloc() instead of alloc(). (John Little)
16 *** ../vim-7.3.426/src/eval.c 2012-01-26 14:32:26.000000000 +0100
17 --- src/eval.c 2012-02-05 00:25:39.000000000 +0100
26 ! #define FREAD_SIZE 200 /* optimized for text lines */
27 ! char_u buf[FREAD_SIZE];
28 ! int readlen; /* size of last fread() */
29 ! int buflen; /* nr of valid chars in buf[] */
30 ! int filtd; /* how much in buf[] was NUL -> '\n' filtered */
31 ! int tolist; /* first byte in buf[] still to be put in list */
32 ! int chop; /* how many CR to chop off */
33 ! char_u *prev = NULL; /* previously read bytes, if any */
34 ! int prevlen = 0; /* length of "prev" if not NULL */
37 ! long maxline = MAXLNUM;
40 if (argvars[1].v_type != VAR_UNKNOWN)
49 ! char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
50 ! int io_size = sizeof(buf);
51 ! int readlen; /* size of last fread() */
52 ! char_u *prev = NULL; /* previously read bytes, if any */
53 ! long prevlen = 0; /* length of data in prev */
54 ! long prevsize = 0; /* size of prev buffer */
55 ! long maxline = MAXLNUM;
57 ! char_u *p; /* position in buf */
58 ! char_u *start; /* start of current line */
60 if (argvars[1].v_type != VAR_UNKNOWN)
68 while (cnt < maxline || maxline < 0)
70 ! readlen = (int)fread(buf + filtd, 1, FREAD_SIZE - filtd, fd);
71 ! buflen = filtd + readlen;
73 ! for ( ; filtd < buflen || readlen <= 0; ++filtd)
75 ! if (readlen <= 0 || buf[filtd] == '\n')
77 ! /* In binary mode add an empty list item when the last
78 ! * non-empty line ends in a '\n'. */
79 ! if (!binary && readlen == 0 && filtd == 0 && prev == NULL)
82 ! /* Found end-of-line or end-of-file: add a text line to the
86 ! while (filtd - chop - 1 >= tolist
87 ! && buf[filtd - chop - 1] == '\r')
89 ! len = filtd - tolist - chop;
91 ! s = vim_strnsave(buf + tolist, len);
94 ! s = alloc((unsigned)(prevlen + len + 1));
97 ! mch_memmove(s, prev, prevlen);
100 ! mch_memmove(s + prevlen, buf + tolist, len);
101 s[prevlen + len] = NUL;
104 ! tolist = filtd + 1;
106 ! li = listitem_alloc();
112 li->li_tv.v_type = VAR_STRING;
117 while (cnt < maxline || maxline < 0)
119 ! readlen = (int)fread(buf, 1, io_size, fd);
121 ! /* This for loop processes what was read, but is also entered at end
122 ! * of file so that either:
123 ! * - an incomplete line gets written
124 ! * - a "binary" file gets an empty line at the end if it ends in a
126 ! for (p = buf, start = buf;
127 ! p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
130 ! if (*p == '\n' || readlen <= 0)
134 ! long_u len = p - start;
136 ! /* Finished a line. Remove CRs before NL. */
137 ! if (readlen > 0 && !binary)
139 ! while (len > 0 && start[len - 1] == '\r')
141 ! /* removal may cross back to the "prev" string */
143 ! while (prevlen > 0 && prev[prevlen - 1] == '\r')
147 ! s = vim_strnsave(start, len);
150 ! /* Change "prev" buffer to be the right size. This way
151 ! * the bytes are only copied once, and very long lines are
152 ! * allocated only once. */
153 ! if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
155 ! mch_memmove(s + prevlen, start, len);
156 s[prevlen + len] = NUL;
157 + prev = NULL; /* the list will own the string */
158 + prevlen = prevsize = 0;
163 ! do_outofmem_msg((long_u) prevlen + len + 1);
168 ! if ((li = listitem_alloc()) == NULL)
174 li->li_tv.v_type = VAR_STRING;
177 li->li_tv.vval.v_string = s;
178 list_append(rettv->vval.v_list, li);
180 ! if (++cnt >= maxline && maxline >= 0)
185 ! else if (buf[filtd] == NUL)
188 ! else if (buf[filtd] == 0xef
190 ! && filtd + 2 < buflen
192 ! && buf[filtd + 1] == 0xbb
193 ! && buf[filtd + 2] == 0xbf)
195 ! /* remove utf-8 byte order mark */
196 ! mch_memmove(buf + filtd, buf + filtd + 3, buflen - filtd - 3);
207 ! if (buflen >= FREAD_SIZE / 2)
209 ! /* "buf" is full, need to move text to an allocated buffer */
212 ! prev = vim_strnsave(buf, buflen);
217 ! s = alloc((unsigned)(prevlen + buflen));
220 ! mch_memmove(s, prev, prevlen);
221 ! mch_memmove(s + prevlen, buf, buflen);
232 ! mch_memmove(buf, buf + tolist, buflen - tolist);
238 * For a negative line count use only the lines at the end of the file,
242 while (cnt > -maxline)
244 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
252 li->li_tv.vval.v_string = s;
253 list_append(rettv->vval.v_list, li);
255 ! start = p + 1; /* step over newline */
256 ! if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
259 ! else if (*p == NUL)
262 ! /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
263 ! * when finding the BF and check the previous two bytes. */
264 ! else if (*p == 0xbf && enc_utf8 && !binary)
266 ! /* Find the two bytes before the 0xbf. If p is at buf, or buf
267 ! * + 1, these may be in the "prev" string. */
268 ! char_u back1 = p >= buf + 1 ? p[-1]
269 ! : prevlen >= 1 ? prev[prevlen - 1] : NUL;
270 ! char_u back2 = p >= buf + 2 ? p[-2]
271 ! : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
272 ! : prevlen >= 2 ? prev[prevlen - 2] : NUL;
274 ! if (back2 == 0xef && back1 == 0xbb)
276 ! char_u *dest = p - 2;
278 ! /* Usually a BOM is at the beginning of a file, and so at
279 ! * the beginning of a line; then we can just step over it.
285 ! /* have to shuffle buf to close gap */
286 ! int adjust_prevlen = 0;
290 ! adjust_prevlen = buf - dest; /* must be 1 or 2 */
293 ! if (readlen > p - buf + 1)
294 ! mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
295 ! readlen -= 3 - adjust_prevlen;
296 ! prevlen -= adjust_prevlen;
304 ! if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
308 ! /* There's part of a line in buf, store it in "prev". */
309 ! if (p - start + prevlen >= prevsize)
311 ! /* need bigger "prev" buffer */
314 ! /* A common use case is ordinary text files and "prev" gets a
315 ! * fragment of a line, so the first allocation is made
316 ! * small, to avoid repeatedly 'allocing' large and
317 ! * 'reallocing' small. */
319 ! prevsize = p - start;
322 ! long grow50pc = (prevsize * 3) / 2;
323 ! long growmin = (p - start) * 2 + prevlen;
324 ! prevsize = grow50pc > growmin ? grow50pc : growmin;
326 ! if ((newprev = vim_realloc(prev, prevsize)) == NULL)
328 ! do_outofmem_msg((long_u)prevsize);
334 + /* Add the line part to end of "prev". */
335 + mch_memmove(prev + prevlen, start, p - start);
336 + prevlen += p - start;
341 * For a negative line count use only the lines at the end of the file,
344 ! if (!failed && maxline < 0)
345 while (cnt > -maxline)
347 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
353 + list_free(rettv->vval.v_list, TRUE);
354 + /* readfile doc says an empty list is returned on error */
355 + rettv->vval.v_list = list_alloc();
361 *** ../vim-7.3.426/src/version.c 2012-02-04 23:34:57.000000000 +0100
362 --- src/version.c 2012-02-05 00:38:34.000000000 +0100
366 { /* Add new patch number below this line */
372 One difference between a man and a machine is that a machine is quiet
375 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
376 /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
377 \\\ an exciting new programming language -- http://www.Zimbu.org ///
378 \\\ help me help AIDS victims -- http://ICCF-Holland.org ///