Mercurial > vim
comparison src/quickfix.c @ 13984:9b1dc5c2f460 v8.1.0010
patch 8.1.0010: efm_to_regpat() is too long
commit https://github.com/vim/vim/commit/6bff719f7e472e918c60aa336de03e799b806c4f
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun May 20 15:41:17 2018 +0200
patch 8.1.0010: efm_to_regpat() is too long
Problem: efm_to_regpat() is too long.
Solution: Split off three functions. (Yegappan Lakshmanan, closes https://github.com/vim/vim/issues/2924)
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sun, 20 May 2018 15:45:04 +0200 |
parents | 2ed1585c6467 |
children | 710b1bb82f2c |
comparison
equal
deleted
inserted
replaced
13983:edbc72b9de83 | 13984:9b1dc5c2f460 |
---|---|
226 {'s', ".\\+"}, | 226 {'s', ".\\+"}, |
227 {'o', ".\\+"} | 227 {'o', ".\\+"} |
228 }; | 228 }; |
229 | 229 |
230 /* | 230 /* |
231 * Convert an errorformat pattern to a regular expression pattern. | |
232 * See fmt_pat definition above for the list of supported patterns. | |
233 */ | |
234 static char_u * | |
235 fmtpat_to_regpat( | |
236 char_u *efmp, | |
237 efm_T *fmt_ptr, | |
238 int idx, | |
239 int round, | |
240 char_u *ptr, | |
241 char_u *errmsg) | |
242 { | |
243 char_u *srcptr; | |
244 | |
245 if (fmt_ptr->addr[idx]) | |
246 { | |
247 /* Each errorformat pattern can occur only once */ | |
248 sprintf((char *)errmsg, | |
249 _("E372: Too many %%%c in format string"), *efmp); | |
250 EMSG(errmsg); | |
251 return NULL; | |
252 } | |
253 if ((idx && idx < 6 | |
254 && vim_strchr((char_u *)"DXOPQ", fmt_ptr->prefix) != NULL) | |
255 || (idx == 6 | |
256 && vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL)) | |
257 { | |
258 sprintf((char *)errmsg, | |
259 _("E373: Unexpected %%%c in format string"), *efmp); | |
260 EMSG(errmsg); | |
261 return NULL; | |
262 } | |
263 fmt_ptr->addr[idx] = (char_u)++round; | |
264 *ptr++ = '\\'; | |
265 *ptr++ = '('; | |
266 #ifdef BACKSLASH_IN_FILENAME | |
267 if (*efmp == 'f') | |
268 { | |
269 /* Also match "c:" in the file name, even when | |
270 * checking for a colon next: "%f:". | |
271 * "\%(\a:\)\=" */ | |
272 STRCPY(ptr, "\\%(\\a:\\)\\="); | |
273 ptr += 10; | |
274 } | |
275 #endif | |
276 if (*efmp == 'f' && efmp[1] != NUL) | |
277 { | |
278 if (efmp[1] != '\\' && efmp[1] != '%') | |
279 { | |
280 /* A file name may contain spaces, but this isn't | |
281 * in "\f". For "%f:%l:%m" there may be a ":" in | |
282 * the file name. Use ".\{-1,}x" instead (x is | |
283 * the next character), the requirement that :999: | |
284 * follows should work. */ | |
285 STRCPY(ptr, ".\\{-1,}"); | |
286 ptr += 7; | |
287 } | |
288 else | |
289 { | |
290 /* File name followed by '\\' or '%': include as | |
291 * many file name chars as possible. */ | |
292 STRCPY(ptr, "\\f\\+"); | |
293 ptr += 4; | |
294 } | |
295 } | |
296 else | |
297 { | |
298 srcptr = (char_u *)fmt_pat[idx].pattern; | |
299 while ((*ptr = *srcptr++) != NUL) | |
300 ++ptr; | |
301 } | |
302 *ptr++ = '\\'; | |
303 *ptr++ = ')'; | |
304 | |
305 return ptr; | |
306 } | |
307 | |
308 /* | |
309 * Convert a scanf like format in 'errorformat' to a regular expression. | |
310 */ | |
311 static char_u * | |
312 scanf_fmt_to_regpat( | |
313 char_u *efm, | |
314 int len, | |
315 char_u **pefmp, | |
316 char_u *ptr, | |
317 char_u *errmsg) | |
318 { | |
319 char_u *efmp = *pefmp; | |
320 | |
321 if (*++efmp == '[' || *efmp == '\\') | |
322 { | |
323 if ((*ptr++ = *efmp) == '[') /* %*[^a-z0-9] etc. */ | |
324 { | |
325 if (efmp[1] == '^') | |
326 *ptr++ = *++efmp; | |
327 if (efmp < efm + len) | |
328 { | |
329 *ptr++ = *++efmp; /* could be ']' */ | |
330 while (efmp < efm + len | |
331 && (*ptr++ = *++efmp) != ']') | |
332 /* skip */; | |
333 if (efmp == efm + len) | |
334 { | |
335 EMSG(_("E374: Missing ] in format string")); | |
336 return NULL; | |
337 } | |
338 } | |
339 } | |
340 else if (efmp < efm + len) /* %*\D, %*\s etc. */ | |
341 *ptr++ = *++efmp; | |
342 *ptr++ = '\\'; | |
343 *ptr++ = '+'; | |
344 } | |
345 else | |
346 { | |
347 /* TODO: scanf()-like: %*ud, %*3c, %*f, ... ? */ | |
348 sprintf((char *)errmsg, | |
349 _("E375: Unsupported %%%c in format string"), *efmp); | |
350 EMSG(errmsg); | |
351 return NULL; | |
352 } | |
353 | |
354 *pefmp = efmp; | |
355 | |
356 return ptr; | |
357 } | |
358 | |
359 /* | |
360 * Analyze/parse an errorformat prefix. | |
361 */ | |
362 static int | |
363 efm_analyze_prefix(char_u **pefmp, efm_T *fmt_ptr, char_u *errmsg) | |
364 { | |
365 char_u *efmp = *pefmp; | |
366 | |
367 if (vim_strchr((char_u *)"+-", *efmp) != NULL) | |
368 fmt_ptr->flags = *efmp++; | |
369 if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) | |
370 fmt_ptr->prefix = *efmp; | |
371 else | |
372 { | |
373 sprintf((char *)errmsg, | |
374 _("E376: Invalid %%%c in format string prefix"), *efmp); | |
375 EMSG(errmsg); | |
376 return FAIL; | |
377 } | |
378 | |
379 *pefmp = efmp; | |
380 | |
381 return OK; | |
382 } | |
383 | |
384 /* | |
231 * Converts a 'errorformat' string to regular expression pattern | 385 * Converts a 'errorformat' string to regular expression pattern |
232 */ | 386 */ |
233 static int | 387 static int |
234 efm_to_regpat( | 388 efm_to_regpat( |
235 char_u *efm, | 389 char_u *efm, |
236 int len, | 390 int len, |
237 efm_T *fmt_ptr, | 391 efm_T *fmt_ptr, |
238 char_u *regpat, | 392 char_u *regpat, |
239 char_u *errmsg) | 393 char_u *errmsg) |
240 { | 394 { |
241 char_u *ptr; | 395 char_u *ptr; |
242 char_u *efmp; | 396 char_u *efmp; |
243 char_u *srcptr; | |
244 int round; | 397 int round; |
245 int idx = 0; | 398 int idx = 0; |
246 | 399 |
247 /* | 400 /* |
248 * Build regexp pattern from current 'errorformat' option | 401 * Build regexp pattern from current 'errorformat' option |
258 for (idx = 0; idx < FMT_PATTERNS; ++idx) | 411 for (idx = 0; idx < FMT_PATTERNS; ++idx) |
259 if (fmt_pat[idx].convchar == *efmp) | 412 if (fmt_pat[idx].convchar == *efmp) |
260 break; | 413 break; |
261 if (idx < FMT_PATTERNS) | 414 if (idx < FMT_PATTERNS) |
262 { | 415 { |
263 if (fmt_ptr->addr[idx]) | 416 ptr = fmtpat_to_regpat(efmp, fmt_ptr, idx, round, ptr, |
264 { | 417 errmsg); |
265 sprintf((char *)errmsg, | 418 if (ptr == NULL) |
266 _("E372: Too many %%%c in format string"), *efmp); | |
267 EMSG(errmsg); | |
268 return -1; | 419 return -1; |
269 } | 420 round++; |
270 if ((idx | |
271 && idx < 6 | |
272 && vim_strchr((char_u *)"DXOPQ", | |
273 fmt_ptr->prefix) != NULL) | |
274 || (idx == 6 | |
275 && vim_strchr((char_u *)"OPQ", | |
276 fmt_ptr->prefix) == NULL)) | |
277 { | |
278 sprintf((char *)errmsg, | |
279 _("E373: Unexpected %%%c in format string"), *efmp); | |
280 EMSG(errmsg); | |
281 return -1; | |
282 } | |
283 fmt_ptr->addr[idx] = (char_u)++round; | |
284 *ptr++ = '\\'; | |
285 *ptr++ = '('; | |
286 #ifdef BACKSLASH_IN_FILENAME | |
287 if (*efmp == 'f') | |
288 { | |
289 /* Also match "c:" in the file name, even when | |
290 * checking for a colon next: "%f:". | |
291 * "\%(\a:\)\=" */ | |
292 STRCPY(ptr, "\\%(\\a:\\)\\="); | |
293 ptr += 10; | |
294 } | |
295 #endif | |
296 if (*efmp == 'f' && efmp[1] != NUL) | |
297 { | |
298 if (efmp[1] != '\\' && efmp[1] != '%') | |
299 { | |
300 /* A file name may contain spaces, but this isn't | |
301 * in "\f". For "%f:%l:%m" there may be a ":" in | |
302 * the file name. Use ".\{-1,}x" instead (x is | |
303 * the next character), the requirement that :999: | |
304 * follows should work. */ | |
305 STRCPY(ptr, ".\\{-1,}"); | |
306 ptr += 7; | |
307 } | |
308 else | |
309 { | |
310 /* File name followed by '\\' or '%': include as | |
311 * many file name chars as possible. */ | |
312 STRCPY(ptr, "\\f\\+"); | |
313 ptr += 4; | |
314 } | |
315 } | |
316 else | |
317 { | |
318 srcptr = (char_u *)fmt_pat[idx].pattern; | |
319 while ((*ptr = *srcptr++) != NUL) | |
320 ++ptr; | |
321 } | |
322 *ptr++ = '\\'; | |
323 *ptr++ = ')'; | |
324 } | 421 } |
325 else if (*efmp == '*') | 422 else if (*efmp == '*') |
326 { | 423 { |
327 if (*++efmp == '[' || *efmp == '\\') | 424 ptr = scanf_fmt_to_regpat(efm, len, &efmp, ptr, errmsg); |
328 { | 425 if (ptr == NULL) |
329 if ((*ptr++ = *efmp) == '[') /* %*[^a-z0-9] etc. */ | |
330 { | |
331 if (efmp[1] == '^') | |
332 *ptr++ = *++efmp; | |
333 if (efmp < efm + len) | |
334 { | |
335 *ptr++ = *++efmp; /* could be ']' */ | |
336 while (efmp < efm + len | |
337 && (*ptr++ = *++efmp) != ']') | |
338 /* skip */; | |
339 if (efmp == efm + len) | |
340 { | |
341 EMSG(_("E374: Missing ] in format string")); | |
342 return -1; | |
343 } | |
344 } | |
345 } | |
346 else if (efmp < efm + len) /* %*\D, %*\s etc. */ | |
347 *ptr++ = *++efmp; | |
348 *ptr++ = '\\'; | |
349 *ptr++ = '+'; | |
350 } | |
351 else | |
352 { | |
353 /* TODO: scanf()-like: %*ud, %*3c, %*f, ... ? */ | |
354 sprintf((char *)errmsg, | |
355 _("E375: Unsupported %%%c in format string"), *efmp); | |
356 EMSG(errmsg); | |
357 return -1; | 426 return -1; |
358 } | |
359 } | 427 } |
360 else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) | 428 else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) |
361 *ptr++ = *efmp; /* regexp magic characters */ | 429 *ptr++ = *efmp; /* regexp magic characters */ |
362 else if (*efmp == '#') | 430 else if (*efmp == '#') |
363 *ptr++ = '*'; | 431 *ptr++ = '*'; |
364 else if (*efmp == '>') | 432 else if (*efmp == '>') |
365 fmt_ptr->conthere = TRUE; | 433 fmt_ptr->conthere = TRUE; |
366 else if (efmp == efm + 1) /* analyse prefix */ | 434 else if (efmp == efm + 1) /* analyse prefix */ |
367 { | 435 { |
368 if (vim_strchr((char_u *)"+-", *efmp) != NULL) | 436 if (efm_analyze_prefix(&efmp, fmt_ptr, errmsg) == FAIL) |
369 fmt_ptr->flags = *efmp++; | |
370 if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) | |
371 fmt_ptr->prefix = *efmp; | |
372 else | |
373 { | |
374 sprintf((char *)errmsg, | |
375 _("E376: Invalid %%%c in format string prefix"), *efmp); | |
376 EMSG(errmsg); | |
377 return -1; | 437 return -1; |
378 } | |
379 } | 438 } |
380 else | 439 else |
381 { | 440 { |
382 sprintf((char *)errmsg, | 441 sprintf((char *)errmsg, |
383 _("E377: Invalid %%%c in format string"), *efmp); | 442 _("E377: Invalid %%%c in format string"), *efmp); |