@@ -227,20 +227,173 @@ static struct fmtpattern
227227 {'o' , ".\\+" }
228228 };
229229
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+
230384/*
231385 * Converts a 'errorformat' string to regular expression pattern
232386 */
233387 static int
234388efm_to_regpat (
235389 char_u * efm ,
236- int len ,
390+ int len ,
237391 efm_T * fmt_ptr ,
238392 char_u * regpat ,
239393 char_u * errmsg )
240394{
241395 char_u * ptr ;
242396 char_u * efmp ;
243- char_u * srcptr ;
244397 int round ;
245398 int idx = 0 ;
246399
@@ -260,102 +413,17 @@ efm_to_regpat(
260413 break ;
261414 if (idx < FMT_PATTERNS )
262415 {
263- if (fmt_ptr -> addr [idx ])
264- {
265- sprintf ((char * )errmsg ,
266- _ ("E372: Too many %%%c in format string" ), * efmp );
267- EMSG (errmsg );
268- return -1 ;
269- }
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 );
416+ ptr = fmtpat_to_regpat (efmp , fmt_ptr , idx , round , ptr ,
417+ errmsg );
418+ if (ptr == NULL )
281419 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 ++ = ')' ;
420+ round ++ ;
324421 }
325422 else if (* efmp == '*' )
326423 {
327- if (* ++ efmp == '[' || * efmp == '\\' )
328- {
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 );
424+ ptr = scanf_fmt_to_regpat (efm , len , & efmp , ptr , errmsg );
425+ if (ptr == NULL )
357426 return -1 ;
358- }
359427 }
360428 else if (vim_strchr ((char_u * )"%\\.^$~[" , * efmp ) != NULL )
361429 * ptr ++ = * efmp ; /* regexp magic characters */
@@ -365,17 +433,8 @@ efm_to_regpat(
365433 fmt_ptr -> conthere = TRUE;
366434 else if (efmp == efm + 1 ) /* analyse prefix */
367435 {
368- if (vim_strchr ((char_u * )"+-" , * efmp ) != NULL )
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 );
436+ if (efm_analyze_prefix (& efmp , fmt_ptr , errmsg ) == FAIL )
377437 return -1 ;
378- }
379438 }
380439 else
381440 {
0 commit comments