]>
Commit | Line | Data |
---|---|---|
14b40f53 AG |
1 | To: vim-dev@vim.org |
2 | Subject: Patch 6.2.444 | |
3 | Fcc: outbox | |
4 | From: Bram Moolenaar <Bram@moolenaar.net> | |
5 | Mime-Version: 1.0 | |
6 | Content-Type: text/plain; charset=ISO-8859-1 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ------------ | |
9 | ||
10 | Patch 6.2.444 | |
11 | Problem: When adding the 'c' flag to a ":substitute" command it may replace | |
12 | more times than without the 'c' flag. Happens for a match that | |
13 | starts with "\ze" (Marcel Svitalsk) and when using "\@<=" (Klaus | |
14 | Bosau). | |
15 | Solution: Correct "prev_matchcol" when replacing the line. Don't replace | |
16 | the line when the pattern uses look-behind matching. | |
17 | Files: src/ex_cmds.c, src/proto/regexp.pro, src/regexp.c | |
18 | ||
19 | ||
20 | *** ../vim-6.2.443/src/ex_cmds.c Fri Mar 26 22:26:46 2004 | |
21 | --- src/ex_cmds.c Sun Apr 4 14:45:57 2004 | |
22 | *************** | |
23 | *** 4097,4107 **** | |
24 | lastone = ((sub_firstline[matchcol] == NUL && nmatch <= 1) | |
25 | || got_int || got_quit || !(do_all || do_again)); | |
26 | nmatch = -1; | |
27 | ! /* The check for nmatch_tl is needed for when multi-line | |
28 | * matching must replace the lines before trying to do another | |
29 | ! * match, otherwise "\@<=" won't work. */ | |
30 | if (lastone | |
31 | ! || do_ask | |
32 | || nmatch_tl > 0 | |
33 | || (nmatch = vim_regexec_multi(®match, curwin, | |
34 | curbuf, sub_firstlnum, matchcol)) == 0) | |
35 | --- 4097,4115 ---- | |
36 | lastone = ((sub_firstline[matchcol] == NUL && nmatch <= 1) | |
37 | || got_int || got_quit || !(do_all || do_again)); | |
38 | nmatch = -1; | |
39 | ! | |
40 | ! /* | |
41 | ! * Replace the line in the buffer when needed. This is | |
42 | ! * skipped when there are more matches. | |
43 | ! * The check for nmatch_tl is needed for when multi-line | |
44 | * matching must replace the lines before trying to do another | |
45 | ! * match, otherwise "\@<=" won't work. | |
46 | ! * When asking the user we like to show the already replaced | |
47 | ! * text, but don't do it when "\<@=" or "\<@!" is used, it | |
48 | ! * changes what matches. | |
49 | ! */ | |
50 | if (lastone | |
51 | ! || (do_ask && !re_lookbehind(regmatch.regprog)) | |
52 | || nmatch_tl > 0 | |
53 | || (nmatch = vim_regexec_multi(®match, curwin, | |
54 | curbuf, sub_firstlnum, matchcol)) == 0) | |
55 | *************** | |
56 | *** 4110,4121 **** | |
57 | { | |
58 | /* | |
59 | * Copy the rest of the line, that didn't match. | |
60 | ! * matchcol has to be adjusted, we use the end of the | |
61 | ! * line as reference, because the substitute may have | |
62 | ! * changed the number of characters. | |
63 | */ | |
64 | STRCAT(new_start, sub_firstline + copycol); | |
65 | matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol; | |
66 | ||
67 | if (u_savesub(lnum) != OK) | |
68 | break; | |
69 | --- 4118,4132 ---- | |
70 | { | |
71 | /* | |
72 | * Copy the rest of the line, that didn't match. | |
73 | ! * "matchcol" has to be adjusted, we use the end of | |
74 | ! * the line as reference, because the substitute may | |
75 | ! * have changed the number of characters. Same for | |
76 | ! * "prev_matchcol". | |
77 | */ | |
78 | STRCAT(new_start, sub_firstline + copycol); | |
79 | matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol; | |
80 | + prev_matchcol = (colnr_T)STRLEN(sub_firstline) | |
81 | + - prev_matchcol; | |
82 | ||
83 | if (u_savesub(lnum) != OK) | |
84 | break; | |
85 | *************** | |
86 | *** 4159,4164 **** | |
87 | --- 4170,4177 ---- | |
88 | sub_firstline = new_start; | |
89 | new_start = NULL; | |
90 | matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol; | |
91 | + prev_matchcol = (colnr_T)STRLEN(sub_firstline) | |
92 | + - prev_matchcol; | |
93 | copycol = 0; | |
94 | } | |
95 | if (nmatch == -1 && !lastone) | |
96 | *** ../vim-6.2.443/src/proto/regexp.pro Tue Mar 30 10:43:14 2004 | |
97 | --- src/proto/regexp.pro Sun Apr 4 14:46:22 2004 | |
98 | *************** | |
99 | *** 1,5 **** | |
100 | --- 1,6 ---- | |
101 | /* regexp.c */ | |
102 | int re_multiline __ARGS((regprog_T *prog)); | |
103 | + int re_lookbehind __ARGS((regprog_T *prog)); | |
104 | char_u *skip_regexp __ARGS((char_u *startp, int dirc, int magic, char_u **newp)); | |
105 | regprog_T *vim_regcomp __ARGS((char_u *expr, int re_flags)); | |
106 | int vim_regcomp_had_eol __ARGS((void)); | |
107 | *** ../vim-6.2.443/src/regexp.c Mon Mar 29 14:32:19 2004 | |
108 | --- src/regexp.c Sun Apr 4 14:51:07 2004 | |
109 | *************** | |
110 | *** 355,360 **** | |
111 | --- 355,361 ---- | |
112 | #define SIMPLE 0x2 /* Simple enough to be STAR/PLUS operand. */ | |
113 | #define SPSTART 0x4 /* Starts with * or +. */ | |
114 | #define HASNL 0x8 /* Contains some \n. */ | |
115 | + #define HASLOOKBH 0x10 /* Contains "\@<=" or "\@<!". */ | |
116 | #define WORST 0 /* Worst case. */ | |
117 | ||
118 | /* | |
119 | *************** | |
120 | *** 602,607 **** | |
121 | --- 603,609 ---- | |
122 | #define RF_NOICASE 2 /* don't ignore case */ | |
123 | #define RF_HASNL 4 /* can match a NL */ | |
124 | #define RF_ICOMBINE 8 /* ignore combining characters */ | |
125 | + #define RF_LOOKBH 16 /* uses "\@<=" or "\@<!" */ | |
126 | ||
127 | /* | |
128 | * Global work variables for vim_regcomp(). | |
129 | *************** | |
130 | *** 712,717 **** | |
131 | --- 714,730 ---- | |
132 | #endif | |
133 | ||
134 | /* | |
135 | + * Return TRUE if compiled regular expression "prog" looks before the start | |
136 | + * position (pattern contains "\@<=" or "\@<!"). | |
137 | + */ | |
138 | + int | |
139 | + re_lookbehind(prog) | |
140 | + regprog_T *prog; | |
141 | + { | |
142 | + return (prog->regflags & RF_LOOKBH); | |
143 | + } | |
144 | + | |
145 | + /* | |
146 | * Skip past regular expression. | |
147 | * Stop at end of 'p' of where 'dirc' is found ('/', '?', etc). | |
148 | * Take care of characters with a backslash in front of it. | |
149 | *************** | |
150 | *** 852,857 **** | |
151 | --- 865,872 ---- | |
152 | r->regflags = regflags; | |
153 | if (flags & HASNL) | |
154 | r->regflags |= RF_HASNL; | |
155 | + if (flags & HASLOOKBH) | |
156 | + r->regflags |= RF_LOOKBH; | |
157 | #ifdef FEAT_SYN_HL | |
158 | /* Remember whether this pattern has any \z specials in it. */ | |
159 | r->reghasz = re_has_z; | |
160 | *************** | |
161 | *** 1030,1036 **** | |
162 | * whole thing can. */ | |
163 | if (!(flags & HASWIDTH)) | |
164 | *flagp &= ~HASWIDTH; | |
165 | ! *flagp |= flags & (SPSTART | HASNL); | |
166 | while (peekchr() == Magic('|')) | |
167 | { | |
168 | skipchr(); | |
169 | --- 1045,1051 ---- | |
170 | * whole thing can. */ | |
171 | if (!(flags & HASWIDTH)) | |
172 | *flagp &= ~HASWIDTH; | |
173 | ! *flagp |= flags & (SPSTART | HASNL | HASLOOKBH); | |
174 | while (peekchr() == Magic('|')) | |
175 | { | |
176 | skipchr(); | |
177 | *************** | |
178 | *** 1040,1046 **** | |
179 | regtail(ret, br); /* BRANCH -> BRANCH. */ | |
180 | if (!(flags & HASWIDTH)) | |
181 | *flagp &= ~HASWIDTH; | |
182 | ! *flagp |= flags & (SPSTART | HASNL); | |
183 | } | |
184 | ||
185 | /* Make a closing node, and hook it on the end. */ | |
186 | --- 1055,1061 ---- | |
187 | regtail(ret, br); /* BRANCH -> BRANCH. */ | |
188 | if (!(flags & HASWIDTH)) | |
189 | *flagp &= ~HASWIDTH; | |
190 | ! *flagp |= flags & (SPSTART | HASNL | HASLOOKBH); | |
191 | } | |
192 | ||
193 | /* Make a closing node, and hook it on the end. */ | |
194 | *************** | |
195 | *** 1109,1116 **** | |
196 | if (latest == NULL) | |
197 | return NULL; | |
198 | /* If one of the branches has width, the whole thing has. If one of | |
199 | ! * the branches anchors at start-of-line, the whole thing does. */ | |
200 | ! *flagp |= flags & (HASWIDTH | SPSTART); | |
201 | /* If one of the branches doesn't match a line-break, the whole thing | |
202 | * doesn't. */ | |
203 | *flagp &= ~HASNL | (flags & HASNL); | |
204 | --- 1124,1132 ---- | |
205 | if (latest == NULL) | |
206 | return NULL; | |
207 | /* If one of the branches has width, the whole thing has. If one of | |
208 | ! * the branches anchors at start-of-line, the whole thing does. | |
209 | ! * If one of the branches uses look-behind, the whole thing does. */ | |
210 | ! *flagp |= flags & (HASWIDTH | SPSTART | HASLOOKBH); | |
211 | /* If one of the branches doesn't match a line-break, the whole thing | |
212 | * doesn't. */ | |
213 | *flagp &= ~HASNL | (flags & HASNL); | |
214 | *************** | |
215 | *** 1192,1198 **** | |
216 | latest = regpiece(&flags); | |
217 | if (latest == NULL) | |
218 | return NULL; | |
219 | ! *flagp |= flags & (HASWIDTH | HASNL); | |
220 | if (chain == NULL) /* First piece. */ | |
221 | *flagp |= flags & SPSTART; | |
222 | else | |
223 | --- 1208,1214 ---- | |
224 | latest = regpiece(&flags); | |
225 | if (latest == NULL) | |
226 | return NULL; | |
227 | ! *flagp |= flags & (HASWIDTH | HASNL | HASLOOKBH); | |
228 | if (chain == NULL) /* First piece. */ | |
229 | *flagp |= flags & SPSTART; | |
230 | else | |
231 | *************** | |
232 | *** 1248,1254 **** | |
233 | reg_magic == MAGIC_ALL); | |
234 | /* "\{}" is checked below, it's allowed when there is an upper limit */ | |
235 | } | |
236 | ! *flagp = (WORST | SPSTART | (flags & HASNL)); /* default flags */ | |
237 | ||
238 | skipchr(); | |
239 | switch (op) | |
240 | --- 1264,1271 ---- | |
241 | reg_magic == MAGIC_ALL); | |
242 | /* "\{}" is checked below, it's allowed when there is an upper limit */ | |
243 | } | |
244 | ! /* default flags */ | |
245 | ! *flagp = (WORST | SPSTART | (flags & (HASNL | HASLOOKBH))); | |
246 | ||
247 | skipchr(); | |
248 | switch (op) | |
249 | *************** | |
250 | *** 1279,1285 **** | |
251 | regtail(next, regnode(BRANCH)); /* or */ | |
252 | regtail(ret, regnode(NOTHING)); /* null. */ | |
253 | } | |
254 | ! *flagp = (WORST | HASWIDTH | (flags & HASNL)); | |
255 | break; | |
256 | ||
257 | case Magic('@'): | |
258 | --- 1296,1302 ---- | |
259 | regtail(next, regnode(BRANCH)); /* or */ | |
260 | regtail(ret, regnode(NOTHING)); /* null. */ | |
261 | } | |
262 | ! *flagp = (WORST | HASWIDTH | (flags & (HASNL | HASLOOKBH))); | |
263 | break; | |
264 | ||
265 | case Magic('@'): | |
266 | *************** | |
267 | *** 1302,1308 **** | |
268 | --- 1319,1328 ---- | |
269 | reg_magic == MAGIC_ALL); | |
270 | /* Look behind must match with behind_pos. */ | |
271 | if (lop == BEHIND || lop == NOBEHIND) | |
272 | + { | |
273 | regtail(ret, regnode(BHPOS)); | |
274 | + *flagp |= HASLOOKBH; | |
275 | + } | |
276 | regtail(ret, regnode(END)); /* operand ends */ | |
277 | reginsert(lop, ret); | |
278 | break; | |
279 | *************** | |
280 | *** 1342,1348 **** | |
281 | ++num_complex_braces; | |
282 | } | |
283 | if (minval > 0 && maxval > 0) | |
284 | ! *flagp = (HASWIDTH | (flags & HASNL)); | |
285 | break; | |
286 | } | |
287 | if (re_multi_type(peekchr()) != NOT_MULTI) | |
288 | --- 1362,1368 ---- | |
289 | ++num_complex_braces; | |
290 | } | |
291 | if (minval > 0 && maxval > 0) | |
292 | ! *flagp = (HASWIDTH | (flags & (HASNL | HASLOOKBH))); | |
293 | break; | |
294 | } | |
295 | if (re_multi_type(peekchr()) != NOT_MULTI) | |
296 | *************** | |
297 | *** 1498,1504 **** | |
298 | ret = reg(REG_PAREN, &flags); | |
299 | if (ret == NULL) | |
300 | return NULL; | |
301 | ! *flagp |= flags & (HASWIDTH | SPSTART | HASNL); | |
302 | break; | |
303 | ||
304 | case NUL: | |
305 | --- 1518,1524 ---- | |
306 | ret = reg(REG_PAREN, &flags); | |
307 | if (ret == NULL) | |
308 | return NULL; | |
309 | ! *flagp |= flags & (HASWIDTH | SPSTART | HASNL | HASLOOKBH); | |
310 | break; | |
311 | ||
312 | case NUL: | |
313 | *************** | |
314 | *** 1590,1596 **** | |
315 | ret = reg(REG_ZPAREN, &flags); | |
316 | if (ret == NULL) | |
317 | return NULL; | |
318 | ! *flagp |= flags & (HASWIDTH | SPSTART | HASNL); | |
319 | re_has_z = REX_SET; | |
320 | break; | |
321 | ||
322 | --- 1610,1616 ---- | |
323 | ret = reg(REG_ZPAREN, &flags); | |
324 | if (ret == NULL) | |
325 | return NULL; | |
326 | ! *flagp |= flags & (HASWIDTH|SPSTART|HASNL|HASLOOKBH); | |
327 | re_has_z = REX_SET; | |
328 | break; | |
329 | ||
330 | *************** | |
331 | *** 1632,1638 **** | |
332 | ret = reg(REG_NPAREN, &flags); | |
333 | if (ret == NULL) | |
334 | return NULL; | |
335 | ! *flagp |= flags & (HASWIDTH | SPSTART | HASNL); | |
336 | break; | |
337 | ||
338 | /* Catch \%^ and \%$ regardless of where they appear in the | |
339 | --- 1652,1658 ---- | |
340 | ret = reg(REG_NPAREN, &flags); | |
341 | if (ret == NULL) | |
342 | return NULL; | |
343 | ! *flagp |= flags & (HASWIDTH | SPSTART | HASNL | HASLOOKBH); | |
344 | break; | |
345 | ||
346 | /* Catch \%^ and \%$ regardless of where they appear in the | |
347 | *** ../vim-6.2.443/src/version.c Sun Apr 4 13:51:39 2004 | |
348 | --- src/version.c Sun Apr 4 15:37:32 2004 | |
349 | *************** | |
350 | *** 639,640 **** | |
351 | --- 639,642 ---- | |
352 | { /* Add new patch number below this line */ | |
353 | + /**/ | |
354 | + 444, | |
355 | /**/ | |
356 | ||
357 | -- | |
358 | hundred-and-one symptoms of being an internet addict: | |
359 | 264. You turn to the teletext page "surfing report" and are surprised that it | |
360 | is about sizes of waves and a weather forecast for seaside resorts. | |
361 | ||
362 | /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ | |
363 | /// Sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ | |
364 | \\\ Project leader for A-A-P -- http://www.A-A-P.org /// | |
365 | \\\ Buy at Amazon and help AIDS victims -- http://ICCF.nl/click1.html /// |