Skip to content

Commit 6be8c8e

Browse files
committed
patch 7.4.1802
Problem: Quickfix doesn't handle long lines well, they are split. Solution: Drop characters after a limit. (Anton Lindqvist)
1 parent 113ce08 commit 6be8c8e

4 files changed

Lines changed: 251 additions & 27 deletions

File tree

src/quickfix.c

Lines changed: 209 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@ qf_init(
174174
qf_title);
175175
}
176176

177+
/*
178+
* Maximum number of bytes allowed per line while reading a errorfile.
179+
*/
180+
#define LINE_MAXLEN 4096
181+
177182
/*
178183
* Read the errorfile "efile" into memory, line by line, building the error
179184
* list.
@@ -197,8 +202,15 @@ qf_init_ext(
197202
{
198203
char_u *namebuf;
199204
char_u *errmsg;
205+
int errmsglen;
200206
char_u *pattern;
201207
char_u *fmtstr = NULL;
208+
char_u *growbuf = NULL;
209+
int growbuflen;
210+
int growbufsiz;
211+
char_u *linebuf;
212+
int linelen;
213+
int discard;
202214
int col = 0;
203215
char_u use_viscol = FALSE;
204216
int type = 0;
@@ -227,6 +239,7 @@ qf_init_ext(
227239
char_u *directory = NULL;
228240
char_u *currfile = NULL;
229241
char_u *tail = NULL;
242+
char_u *p_buf = NULL;
230243
char_u *p_str = NULL;
231244
listitem_T *p_li = NULL;
232245
struct dir_stack_T *file_stack = NULL;
@@ -250,7 +263,8 @@ qf_init_ext(
250263
};
251264

252265
namebuf = alloc_id(CMDBUFFSIZE + 1, aid_qf_namebuf);
253-
errmsg = alloc_id(CMDBUFFSIZE + 1, aid_qf_errmsg);
266+
errmsglen = CMDBUFFSIZE + 1;
267+
errmsg = alloc_id(errmsglen, aid_qf_errmsg);
254268
pattern = alloc_id(CMDBUFFSIZE + 1, aid_qf_pattern);
255269
if (namebuf == NULL || errmsg == NULL || pattern == NULL)
256270
goto qf_init_end;
@@ -513,37 +527,87 @@ qf_init_ext(
513527
/* Get the next line from the supplied string */
514528
char_u *p;
515529

516-
if (!*p_str) /* Reached the end of the string */
530+
if (*p_str == NUL) /* Reached the end of the string */
517531
break;
518532

519533
p = vim_strchr(p_str, '\n');
520-
if (p)
521-
len = (int)(p - p_str + 1);
534+
if (p != NULL)
535+
len = (int)(p - p_str) + 1;
522536
else
523537
len = (int)STRLEN(p_str);
524538

525-
if (len > CMDBUFFSIZE - 2)
526-
vim_strncpy(IObuff, p_str, CMDBUFFSIZE - 2);
539+
if (len > IOSIZE - 2)
540+
{
541+
/*
542+
* If the line exceeds LINE_MAXLEN exclude the last
543+
* byte since it's not a NL character.
544+
*/
545+
linelen = len > LINE_MAXLEN ? LINE_MAXLEN - 1 : len;
546+
if (growbuf == NULL)
547+
{
548+
growbuf = alloc(linelen);
549+
growbufsiz = linelen;
550+
}
551+
else if (linelen > growbufsiz)
552+
{
553+
growbuf = vim_realloc(growbuf, linelen);
554+
if (growbuf == NULL)
555+
goto qf_init_end;
556+
growbufsiz = linelen;
557+
}
558+
linebuf = growbuf;
559+
}
527560
else
528-
vim_strncpy(IObuff, p_str, len);
561+
{
562+
linebuf = IObuff;
563+
linelen = len;
564+
}
565+
vim_strncpy(linebuf, p_str, linelen);
529566

567+
/*
568+
* Increment using len in order to discard the rest of the
569+
* line if it exceeds LINE_MAXLEN.
570+
*/
530571
p_str += len;
531572
}
532573
else if (tv->v_type == VAR_LIST)
533574
{
534575
/* Get the next line from the supplied list */
535-
while (p_li && (p_li->li_tv.v_type != VAR_STRING
536-
|| p_li->li_tv.vval.v_string == NULL))
576+
while (p_li != NULL
577+
&& (p_li->li_tv.v_type != VAR_STRING
578+
|| p_li->li_tv.vval.v_string == NULL))
537579
p_li = p_li->li_next; /* Skip non-string items */
538580

539-
if (!p_li) /* End of the list */
581+
if (p_li == NULL) /* End of the list */
540582
break;
541583

542584
len = (int)STRLEN(p_li->li_tv.vval.v_string);
543-
if (len > CMDBUFFSIZE - 2)
544-
len = CMDBUFFSIZE - 2;
585+
if (len > IOSIZE - 2)
586+
{
587+
linelen = len;
588+
if (linelen > LINE_MAXLEN)
589+
linelen = LINE_MAXLEN - 1;
590+
if (growbuf == NULL)
591+
{
592+
growbuf = alloc(linelen);
593+
growbufsiz = linelen;
594+
}
595+
else if (linelen > growbufsiz)
596+
{
597+
if ((growbuf = vim_realloc(growbuf,
598+
linelen)) == NULL)
599+
goto qf_init_end;
600+
growbufsiz = linelen;
601+
}
602+
linebuf = growbuf;
603+
}
604+
else
605+
{
606+
linebuf = IObuff;
607+
linelen = len;
608+
}
545609

546-
vim_strncpy(IObuff, p_li->li_tv.vval.v_string, len);
610+
vim_strncpy(linebuf, p_li->li_tv.vval.v_string, linelen);
547611

548612
p_li = p_li->li_next; /* next item */
549613
}
@@ -553,23 +617,118 @@ qf_init_ext(
553617
/* Get the next line from the supplied buffer */
554618
if (buflnum > lnumlast)
555619
break;
556-
vim_strncpy(IObuff, ml_get_buf(buf, buflnum++, FALSE),
557-
CMDBUFFSIZE - 2);
620+
p_buf = ml_get_buf(buf, buflnum++, FALSE);
621+
linelen = (int)STRLEN(p_buf);
622+
if (linelen > IOSIZE - 2)
623+
{
624+
if (growbuf == NULL)
625+
{
626+
growbuf = alloc(linelen);
627+
growbufsiz = linelen;
628+
}
629+
else if (linelen > growbufsiz)
630+
{
631+
if (linelen > LINE_MAXLEN)
632+
linelen = LINE_MAXLEN - 1;
633+
if ((growbuf = vim_realloc(growbuf, linelen)) == NULL)
634+
goto qf_init_end;
635+
growbufsiz = linelen;
636+
}
637+
linebuf = growbuf;
638+
}
639+
else
640+
linebuf = IObuff;
641+
vim_strncpy(linebuf, p_buf, linelen);
558642
}
559643
}
560-
else if (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) == NULL)
561-
break;
644+
else
645+
{
646+
if (fgets((char *)IObuff, IOSIZE, fd) == NULL)
647+
break;
562648

563-
IObuff[CMDBUFFSIZE - 2] = NUL; /* for very long lines */
564-
#ifdef FEAT_MBYTE
565-
remove_bom(IObuff);
649+
discard = FALSE;
650+
linelen = (int)STRLEN(IObuff);
651+
if (linelen == IOSIZE - 1 && (IObuff[linelen - 1] != '\n'
652+
#ifdef USE_CRNL
653+
|| IObuff[linelen - 1] != '\r'
654+
#endif
655+
))
656+
{
657+
/*
658+
* The current line exceeds IObuff, continue reading using
659+
* growbuf until EOL or LINE_MAXLEN bytes is read.
660+
*/
661+
if (growbuf == NULL)
662+
{
663+
growbufsiz = 2 * (IOSIZE - 1);
664+
growbuf = alloc(growbufsiz);
665+
if (growbuf == NULL)
666+
goto qf_init_end;
667+
}
668+
669+
/* Copy the read part of the line, excluding null-terminator */
670+
memcpy(growbuf, IObuff, IOSIZE - 1);
671+
growbuflen = linelen;
672+
673+
for (;;)
674+
{
675+
if (fgets((char *)growbuf + growbuflen,
676+
growbufsiz - growbuflen, fd) == NULL)
677+
break;
678+
linelen = STRLEN(growbuf + growbuflen);
679+
growbuflen += linelen;
680+
if (growbuf[growbuflen - 1] == '\n'
681+
#ifdef USE_CRNL
682+
|| growbuf[growbuflen - 1] == '\r'
683+
#endif
684+
)
685+
break;
686+
if (growbufsiz == LINE_MAXLEN)
687+
{
688+
discard = TRUE;
689+
break;
690+
}
691+
692+
growbufsiz = 2 * growbufsiz < LINE_MAXLEN
693+
? 2 * growbufsiz : LINE_MAXLEN;
694+
growbuf = vim_realloc(growbuf, 2 * growbufsiz);
695+
if (growbuf == NULL)
696+
goto qf_init_end;
697+
}
698+
699+
while (discard)
700+
{
701+
/*
702+
* The current line is longer than LINE_MAXLEN, continue
703+
* reading but discard everything until EOL or EOF is
704+
* reached.
705+
*/
706+
if (fgets((char *)IObuff, IOSIZE, fd) == NULL
707+
|| (int)STRLEN(IObuff) < IOSIZE - 1
708+
|| IObuff[IOSIZE - 1] == '\n'
709+
#ifdef USE_CRNL
710+
|| IObuff[IOSIZE - 1] == '\r'
566711
#endif
712+
)
713+
break;
714+
}
715+
716+
linebuf = growbuf;
717+
linelen = growbuflen;
718+
}
719+
else
720+
linebuf = IObuff;
721+
}
567722

568-
if ((efmp = vim_strrchr(IObuff, '\n')) != NULL)
569-
*efmp = NUL;
723+
if (linelen > 0 && linebuf[linelen - 1] == '\n')
724+
linebuf[linelen - 1] = NUL;
570725
#ifdef USE_CRNL
571-
if ((efmp = vim_strrchr(IObuff, '\r')) != NULL)
572-
*efmp = NUL;
726+
if (linelen > 0 && linebuf[linelen - 1] == '\r')
727+
linebuf[linelen - 1] = NUL;
728+
#endif
729+
730+
#ifdef FEAT_MBYTE
731+
remove_bom(linebuf);
573732
#endif
574733

575734
/* If there was no %> item start at the first pattern */
@@ -606,7 +765,7 @@ qf_init_ext(
606765
tail = NULL;
607766

608767
regmatch.regprog = fmt_ptr->prog;
609-
r = vim_regexec(&regmatch, IObuff, (colnr_T)0);
768+
r = vim_regexec(&regmatch, linebuf, (colnr_T)0);
610769
fmt_ptr->prog = regmatch.regprog;
611770
if (r)
612771
{
@@ -663,12 +822,27 @@ qf_init_ext(
663822
type = *regmatch.startp[i];
664823
}
665824
if (fmt_ptr->flags == '+' && !multiscan) /* %+ */
666-
STRCPY(errmsg, IObuff);
825+
{
826+
if (linelen > errmsglen) {
827+
/* linelen + null terminator */
828+
if ((errmsg = vim_realloc(errmsg, linelen + 1)) == NULL)
829+
goto qf_init_end;
830+
errmsglen = linelen + 1;
831+
}
832+
vim_strncpy(errmsg, linebuf, linelen);
833+
}
667834
else if ((i = (int)fmt_ptr->addr[5]) > 0) /* %m */
668835
{
669836
if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL)
670837
continue;
671838
len = (int)(regmatch.endp[i] - regmatch.startp[i]);
839+
if (len > errmsglen) {
840+
/* len + null terminator */
841+
if ((errmsg = vim_realloc(errmsg, len + 1))
842+
== NULL)
843+
goto qf_init_end;
844+
errmsglen = len + 1;
845+
}
672846
vim_strncpy(errmsg, regmatch.startp[i], len);
673847
}
674848
if ((i = (int)fmt_ptr->addr[6]) > 0) /* %r */
@@ -742,7 +916,14 @@ qf_init_ext(
742916
namebuf[0] = NUL; /* no match found, remove file name */
743917
lnum = 0; /* don't jump to this line */
744918
valid = FALSE;
745-
STRCPY(errmsg, IObuff); /* copy whole line to error message */
919+
if (linelen > errmsglen) {
920+
/* linelen + null terminator */
921+
if ((errmsg = vim_realloc(errmsg, linelen + 1)) == NULL)
922+
goto qf_init_end;
923+
errmsglen = linelen + 1;
924+
}
925+
/* copy whole line to error message */
926+
vim_strncpy(errmsg, linebuf, linelen);
746927
if (fmt_ptr == NULL)
747928
multiline = multiignore = FALSE;
748929
}
@@ -878,6 +1059,7 @@ qf_init_ext(
8781059
vim_free(errmsg);
8791060
vim_free(pattern);
8801061
vim_free(fmtstr);
1062+
vim_free(growbuf);
8811063

8821064
#ifdef FEAT_WINDOWS
8831065
qf_update_buffer(qi, TRUE);

0 commit comments

Comments
 (0)