comparison src/quickfix.c @ 13868:1282a54c1f5a v8.0.1805

patch 8.0.1805: qf_parse_line() is too long commit https://github.com/vim/vim/commit/18cebf44177542e6658251bacf6152aa9009ca58 Author: Bram Moolenaar <Bram@vim.org> Date: Tue May 8 22:31:37 2018 +0200 patch 8.0.1805: qf_parse_line() is too long Problem: qf_parse_line() is too long. Solution: Split it in parts. Properly handle vim_realloc() failing. (Yegappan Lakshmanan, closes #2881)
author Christian Brabandt <cb@256bit.org>
date Tue, 08 May 2018 22:45:06 +0200
parents 98274127d675
children f48fcaa196a9
comparison
equal deleted inserted replaced
13867:4e1289c328a1 13868:1282a54c1f5a
211 static struct fmtpattern 211 static struct fmtpattern
212 { 212 {
213 char_u convchar; 213 char_u convchar;
214 char *pattern; 214 char *pattern;
215 } fmt_pat[FMT_PATTERNS] = 215 } fmt_pat[FMT_PATTERNS] =
216 { 216 {
217 {'f', ".\\+"}, /* only used when at end */ 217 {'f', ".\\+"}, /* only used when at end */
218 {'n', "\\d\\+"}, 218 {'n', "\\d\\+"},
219 {'l', "\\d\\+"}, 219 {'l', "\\d\\+"},
220 {'c', "\\d\\+"}, 220 {'c', "\\d\\+"},
221 {'t', "."}, 221 {'t', "."},
222 {'m', ".\\+"}, 222 {'m', ".\\+"},
223 {'r', ".*"}, 223 {'r', ".*"},
224 {'p', "[- .]*"}, 224 {'p', "[- .]*"},
225 {'v', "\\d\\+"}, 225 {'v', "\\d\\+"},
226 {'s', ".\\+"}, 226 {'s', ".\\+"},
227 {'o', ".\\+"} 227 {'o', ".\\+"}
228 }; 228 };
229 229
230 /* 230 /*
231 * Converts a 'errorformat' string to regular expression pattern 231 * Converts a 'errorformat' string to regular expression pattern
232 */ 232 */
233 static int 233 static int
502 enum { 502 enum {
503 QF_FAIL = 0, 503 QF_FAIL = 0,
504 QF_OK = 1, 504 QF_OK = 1,
505 QF_END_OF_INPUT = 2, 505 QF_END_OF_INPUT = 2,
506 QF_NOMEM = 3, 506 QF_NOMEM = 3,
507 QF_IGNORE_LINE = 4 507 QF_IGNORE_LINE = 4,
508 QF_MULTISCAN = 5,
508 }; 509 };
509 510
510 typedef struct { 511 typedef struct {
511 char_u *linebuf; 512 char_u *linebuf;
512 int linelen; 513 int linelen;
523 } qfstate_T; 524 } qfstate_T;
524 525
525 static char_u * 526 static char_u *
526 qf_grow_linebuf(qfstate_T *state, int newsz) 527 qf_grow_linebuf(qfstate_T *state, int newsz)
527 { 528 {
529 char_u *p;
530
528 /* 531 /*
529 * If the line exceeds LINE_MAXLEN exclude the last 532 * If the line exceeds LINE_MAXLEN exclude the last
530 * byte since it's not a NL character. 533 * byte since it's not a NL character.
531 */ 534 */
532 state->linelen = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz; 535 state->linelen = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz;
537 return NULL; 540 return NULL;
538 state->growbufsiz = state->linelen; 541 state->growbufsiz = state->linelen;
539 } 542 }
540 else if (state->linelen > state->growbufsiz) 543 else if (state->linelen > state->growbufsiz)
541 { 544 {
542 state->growbuf = vim_realloc(state->growbuf, state->linelen + 1); 545 if ((p = vim_realloc(state->growbuf, state->linelen + 1)) == NULL)
543 if (state->growbuf == NULL)
544 return NULL; 546 return NULL;
547 state->growbuf = p;
545 state->growbufsiz = state->linelen; 548 state->growbufsiz = state->linelen;
546 } 549 }
547 return state->growbuf; 550 return state->growbuf;
548 } 551 }
549 552
694 memcpy(state->growbuf, IObuff, IOSIZE - 1); 697 memcpy(state->growbuf, IObuff, IOSIZE - 1);
695 growbuflen = state->linelen; 698 growbuflen = state->linelen;
696 699
697 for (;;) 700 for (;;)
698 { 701 {
702 char_u *p;
703
699 if (fgets((char *)state->growbuf + growbuflen, 704 if (fgets((char *)state->growbuf + growbuflen,
700 state->growbufsiz - growbuflen, state->fd) == NULL) 705 state->growbufsiz - growbuflen, state->fd) == NULL)
701 break; 706 break;
702 state->linelen = (int)STRLEN(state->growbuf + growbuflen); 707 state->linelen = (int)STRLEN(state->growbuf + growbuflen);
703 growbuflen += state->linelen; 708 growbuflen += state->linelen;
709 break; 714 break;
710 } 715 }
711 716
712 state->growbufsiz = 2 * state->growbufsiz < LINE_MAXLEN 717 state->growbufsiz = 2 * state->growbufsiz < LINE_MAXLEN
713 ? 2 * state->growbufsiz : LINE_MAXLEN; 718 ? 2 * state->growbufsiz : LINE_MAXLEN;
714 state->growbuf = vim_realloc(state->growbuf, state->growbufsiz); 719 if ((p = vim_realloc(state->growbuf, state->growbufsiz)) == NULL)
715 if (state->growbuf == NULL)
716 return QF_NOMEM; 720 return QF_NOMEM;
721 state->growbuf = p;
717 } 722 }
718 723
719 while (discard) 724 while (discard)
720 { 725 {
721 /* 726 /*
823 int type; 828 int type;
824 int valid; 829 int valid;
825 } qffields_T; 830 } qffields_T;
826 831
827 /* 832 /*
833 * Parse the error format matches in 'regmatch' and set the values in 'fields'.
834 * fmt_ptr contains the 'efm' format specifiers/prefixes that have a match.
835 * Returns QF_OK if all the matches are successfully parsed. On failure,
836 * returns QF_FAIL or QF_NOMEM.
837 */
838 static int
839 qf_parse_match(
840 char_u *linebuf,
841 int linelen,
842 efm_T *fmt_ptr,
843 regmatch_T *regmatch,
844 qffields_T *fields,
845 int qf_multiline,
846 int qf_multiscan,
847 char_u **tail)
848 {
849 char_u *p;
850 int idx = fmt_ptr->prefix;
851 int i;
852 int len;
853
854 if ((idx == 'C' || idx == 'Z') && !qf_multiline)
855 return QF_FAIL;
856 if (vim_strchr((char_u *)"EWI", idx) != NULL)
857 fields->type = idx;
858 else
859 fields->type = 0;
860 /*
861 * Extract error message data from matched line.
862 * We check for an actual submatch, because "\[" and "\]" in
863 * the 'errorformat' may cause the wrong submatch to be used.
864 */
865 if ((i = (int)fmt_ptr->addr[0]) > 0) /* %f */
866 {
867 int c;
868
869 if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL)
870 return QF_FAIL;
871
872 /* Expand ~/file and $HOME/file to full path. */
873 c = *regmatch->endp[i];
874 *regmatch->endp[i] = NUL;
875 expand_env(regmatch->startp[i], fields->namebuf, CMDBUFFSIZE);
876 *regmatch->endp[i] = c;
877
878 if (vim_strchr((char_u *)"OPQ", idx) != NULL
879 && mch_getperm(fields->namebuf) == -1)
880 return QF_FAIL;
881 }
882 if ((i = (int)fmt_ptr->addr[1]) > 0) /* %n */
883 {
884 if (regmatch->startp[i] == NULL)
885 return QF_FAIL;
886 fields->enr = (int)atol((char *)regmatch->startp[i]);
887 }
888 if ((i = (int)fmt_ptr->addr[2]) > 0) /* %l */
889 {
890 if (regmatch->startp[i] == NULL)
891 return QF_FAIL;
892 fields->lnum = atol((char *)regmatch->startp[i]);
893 }
894 if ((i = (int)fmt_ptr->addr[3]) > 0) /* %c */
895 {
896 if (regmatch->startp[i] == NULL)
897 return QF_FAIL;
898 fields->col = (int)atol((char *)regmatch->startp[i]);
899 }
900 if ((i = (int)fmt_ptr->addr[4]) > 0) /* %t */
901 {
902 if (regmatch->startp[i] == NULL)
903 return QF_FAIL;
904 fields->type = *regmatch->startp[i];
905 }
906 if (fmt_ptr->flags == '+' && !qf_multiscan) /* %+ */
907 {
908 if (linelen >= fields->errmsglen)
909 {
910 /* linelen + null terminator */
911 if ((p = vim_realloc(fields->errmsg, linelen + 1)) == NULL)
912 return QF_NOMEM;
913 fields->errmsg = p;
914 fields->errmsglen = linelen + 1;
915 }
916 vim_strncpy(fields->errmsg, linebuf, linelen);
917 }
918 else if ((i = (int)fmt_ptr->addr[5]) > 0) /* %m */
919 {
920 if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL)
921 return QF_FAIL;
922 len = (int)(regmatch->endp[i] - regmatch->startp[i]);
923 if (len >= fields->errmsglen)
924 {
925 /* len + null terminator */
926 if ((p = vim_realloc(fields->errmsg, len + 1)) == NULL)
927 return QF_NOMEM;
928 fields->errmsg = p;
929 fields->errmsglen = len + 1;
930 }
931 vim_strncpy(fields->errmsg, regmatch->startp[i], len);
932 }
933 if ((i = (int)fmt_ptr->addr[6]) > 0) /* %r */
934 {
935 if (regmatch->startp[i] == NULL)
936 return QF_FAIL;
937 *tail = regmatch->startp[i];
938 }
939 if ((i = (int)fmt_ptr->addr[7]) > 0) /* %p */
940 {
941 char_u *match_ptr;
942
943 if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL)
944 return QF_FAIL;
945 fields->col = 0;
946 for (match_ptr = regmatch->startp[i];
947 match_ptr != regmatch->endp[i]; ++match_ptr)
948 {
949 ++fields->col;
950 if (*match_ptr == TAB)
951 {
952 fields->col += 7;
953 fields->col -= fields->col % 8;
954 }
955 }
956 ++fields->col;
957 fields->use_viscol = TRUE;
958 }
959 if ((i = (int)fmt_ptr->addr[8]) > 0) /* %v */
960 {
961 if (regmatch->startp[i] == NULL)
962 return QF_FAIL;
963 fields->col = (int)atol((char *)regmatch->startp[i]);
964 fields->use_viscol = TRUE;
965 }
966 if ((i = (int)fmt_ptr->addr[9]) > 0) /* %s */
967 {
968 if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL)
969 return QF_FAIL;
970 len = (int)(regmatch->endp[i] - regmatch->startp[i]);
971 if (len > CMDBUFFSIZE - 5)
972 len = CMDBUFFSIZE - 5;
973 STRCPY(fields->pattern, "^\\V");
974 STRNCAT(fields->pattern, regmatch->startp[i], len);
975 fields->pattern[len + 3] = '\\';
976 fields->pattern[len + 4] = '$';
977 fields->pattern[len + 5] = NUL;
978 }
979 if ((i = (int)fmt_ptr->addr[10]) > 0) /* %o */
980 {
981 if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL)
982 return QF_FAIL;
983 len = (int)(regmatch->endp[i] - regmatch->startp[i]);
984 if (len > CMDBUFFSIZE)
985 len = CMDBUFFSIZE;
986 STRNCAT(fields->module, regmatch->startp[i], len);
987 }
988
989 return QF_OK;
990 }
991
992 /*
993 * Parse an error line in 'linebuf' using a single error format string in
994 * 'fmt_ptr->prog' and return the matching values in 'fields'.
995 * Returns QF_OK if the efm format matches completely and the fields are
996 * successfully copied. Otherwise returns QF_FAIL or QF_NOMEM.
997 */
998 static int
999 qf_parse_get_fields(
1000 char_u *linebuf,
1001 int linelen,
1002 efm_T *fmt_ptr,
1003 qffields_T *fields,
1004 int qf_multiline,
1005 int qf_multiscan,
1006 char_u **tail)
1007 {
1008 regmatch_T regmatch;
1009 int status = QF_FAIL;
1010 int r;
1011
1012 if (qf_multiscan &&
1013 vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL)
1014 return QF_FAIL;
1015
1016 fields->namebuf[0] = NUL;
1017 fields->module[0] = NUL;
1018 fields->pattern[0] = NUL;
1019 if (!qf_multiscan)
1020 fields->errmsg[0] = NUL;
1021 fields->lnum = 0;
1022 fields->col = 0;
1023 fields->use_viscol = FALSE;
1024 fields->enr = -1;
1025 fields->type = 0;
1026 *tail = NULL;
1027
1028 regmatch.regprog = fmt_ptr->prog;
1029 r = vim_regexec(&regmatch, linebuf, (colnr_T)0);
1030 fmt_ptr->prog = regmatch.regprog;
1031 if (r)
1032 status = qf_parse_match(linebuf, linelen, fmt_ptr, &regmatch,
1033 fields, qf_multiline, qf_multiscan, tail);
1034
1035 return status;
1036 }
1037
1038 /*
1039 * Parse directory error format prefixes (%D and %X).
1040 * Push and pop directories from the directory stack when scanning directory
1041 * names.
1042 */
1043 static int
1044 qf_parse_dir_pfx(int idx, qffields_T *fields, qf_list_T *qfl)
1045 {
1046 if (idx == 'D') /* enter directory */
1047 {
1048 if (*fields->namebuf == NUL)
1049 {
1050 EMSG(_("E379: Missing or empty directory name"));
1051 return QF_FAIL;
1052 }
1053 qfl->qf_directory =
1054 qf_push_dir(fields->namebuf, &qfl->qf_dir_stack, FALSE);
1055 if (qfl->qf_directory == NULL)
1056 return QF_FAIL;
1057 }
1058 else if (idx == 'X') /* leave directory */
1059 qfl->qf_directory = qf_pop_dir(&qfl->qf_dir_stack);
1060
1061 return QF_OK;
1062 }
1063
1064 /*
1065 * Parse global file name error format prefixes (%O, %P and %Q).
1066 */
1067 static int
1068 qf_parse_file_pfx(
1069 int idx,
1070 qffields_T *fields,
1071 qf_list_T *qfl,
1072 char_u *tail)
1073 {
1074 fields->valid = FALSE;
1075 if (*fields->namebuf == NUL || mch_getperm(fields->namebuf) >= 0)
1076 {
1077 if (*fields->namebuf && idx == 'P')
1078 qfl->qf_currfile =
1079 qf_push_dir(fields->namebuf, &qfl->qf_file_stack, TRUE);
1080 else if (idx == 'Q')
1081 qfl->qf_currfile = qf_pop_dir(&qfl->qf_file_stack);
1082 *fields->namebuf = NUL;
1083 if (tail && *tail)
1084 {
1085 STRMOVE(IObuff, skipwhite(tail));
1086 qfl->qf_multiscan = TRUE;
1087 return QF_MULTISCAN;
1088 }
1089 }
1090
1091 return QF_OK;
1092 }
1093
1094 /*
1095 * Parse a non-error line (a line which doesn't match any of the error
1096 * format in 'efm').
1097 */
1098 static int
1099 qf_parse_line_nomatch(char_u *linebuf, int linelen, qffields_T *fields)
1100 {
1101 char_u *p;
1102
1103 fields->namebuf[0] = NUL; /* no match found, remove file name */
1104 fields->lnum = 0; /* don't jump to this line */
1105 fields->valid = FALSE;
1106 if (linelen >= fields->errmsglen)
1107 {
1108 /* linelen + null terminator */
1109 if ((p = vim_realloc(fields->errmsg, linelen + 1)) == NULL)
1110 return QF_NOMEM;
1111 fields->errmsg = p;
1112 fields->errmsglen = linelen + 1;
1113 }
1114 /* copy whole line to error message */
1115 vim_strncpy(fields->errmsg, linebuf, linelen);
1116
1117 return QF_OK;
1118 }
1119
1120 /*
1121 * Parse multi-line error format prefixes (%C and %Z)
1122 */
1123 static int
1124 qf_parse_multiline_pfx(
1125 qf_info_T *qi,
1126 int qf_idx,
1127 int idx,
1128 qf_list_T *qfl,
1129 qffields_T *fields)
1130 {
1131 char_u *ptr;
1132 int len;
1133
1134 if (!qfl->qf_multiignore)
1135 {
1136 qfline_T *qfprev = qfl->qf_last;
1137
1138 if (qfprev == NULL)
1139 return QF_FAIL;
1140 if (*fields->errmsg && !qfl->qf_multiignore)
1141 {
1142 len = (int)STRLEN(qfprev->qf_text);
1143 if ((ptr = alloc((unsigned)(len + STRLEN(fields->errmsg) + 2)))
1144 == NULL)
1145 return QF_FAIL;
1146 STRCPY(ptr, qfprev->qf_text);
1147 vim_free(qfprev->qf_text);
1148 qfprev->qf_text = ptr;
1149 *(ptr += len) = '\n';
1150 STRCPY(++ptr, fields->errmsg);
1151 }
1152 if (qfprev->qf_nr == -1)
1153 qfprev->qf_nr = fields->enr;
1154 if (vim_isprintc(fields->type) && !qfprev->qf_type)
1155 /* only printable chars allowed */
1156 qfprev->qf_type = fields->type;
1157
1158 if (!qfprev->qf_lnum)
1159 qfprev->qf_lnum = fields->lnum;
1160 if (!qfprev->qf_col)
1161 qfprev->qf_col = fields->col;
1162 qfprev->qf_viscol = fields->use_viscol;
1163 if (!qfprev->qf_fnum)
1164 qfprev->qf_fnum = qf_get_fnum(qi, qf_idx,
1165 qfl->qf_directory,
1166 *fields->namebuf || qfl->qf_directory != NULL
1167 ? fields->namebuf
1168 : qfl->qf_currfile != NULL && fields->valid
1169 ? qfl->qf_currfile : 0);
1170 }
1171 if (idx == 'Z')
1172 qfl->qf_multiline = qfl->qf_multiignore = FALSE;
1173 line_breakcheck();
1174
1175 return QF_IGNORE_LINE;
1176 }
1177
1178 /*
828 * Parse a line and get the quickfix fields. 1179 * Parse a line and get the quickfix fields.
829 * Return the QF_ status. 1180 * Return the QF_ status.
830 */ 1181 */
831 static int 1182 static int
832 qf_parse_line( 1183 qf_parse_line(
836 int linelen, 1187 int linelen,
837 efm_T *fmt_first, 1188 efm_T *fmt_first,
838 qffields_T *fields) 1189 qffields_T *fields)
839 { 1190 {
840 efm_T *fmt_ptr; 1191 efm_T *fmt_ptr;
841 char_u *ptr;
842 int len;
843 int i;
844 int idx = 0; 1192 int idx = 0;
845 char_u *tail = NULL; 1193 char_u *tail = NULL;
846 regmatch_T regmatch;
847 qf_list_T *qfl = &qi->qf_lists[qf_idx]; 1194 qf_list_T *qfl = &qi->qf_lists[qf_idx];
848 1195 int status;
849 /* Always ignore case when looking for a matching error. */
850 regmatch.rm_ic = TRUE;
851 1196
852 restofline: 1197 restofline:
853 /* If there was no %> item start at the first pattern */ 1198 /* If there was no %> item start at the first pattern */
854 if (fmt_start == NULL) 1199 if (fmt_start == NULL)
855 fmt_ptr = fmt_first; 1200 fmt_ptr = fmt_first;
856 else 1201 else
857 { 1202 {
1203 /* Otherwise start from the last used pattern */
858 fmt_ptr = fmt_start; 1204 fmt_ptr = fmt_start;
859 fmt_start = NULL; 1205 fmt_start = NULL;
860 } 1206 }
861 1207
862 /* 1208 /*
864 * match or no match. 1210 * match or no match.
865 */ 1211 */
866 fields->valid = TRUE; 1212 fields->valid = TRUE;
867 for ( ; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) 1213 for ( ; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next)
868 { 1214 {
869 int r;
870
871 idx = fmt_ptr->prefix; 1215 idx = fmt_ptr->prefix;
872 if (qfl->qf_multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) 1216 status = qf_parse_get_fields(linebuf, linelen, fmt_ptr, fields,
873 continue; 1217 qfl->qf_multiline, qfl->qf_multiscan, &tail);
874 fields->namebuf[0] = NUL; 1218 if (status == QF_NOMEM)
875 fields->module[0] = NUL; 1219 return status;
876 fields->pattern[0] = NUL; 1220 if (status == QF_OK)
877 if (!qfl->qf_multiscan)
878 fields->errmsg[0] = NUL;
879 fields->lnum = 0;
880 fields->col = 0;
881 fields->use_viscol = FALSE;
882 fields->enr = -1;
883 fields->type = 0;
884 tail = NULL;
885
886 regmatch.regprog = fmt_ptr->prog;
887 r = vim_regexec(&regmatch, linebuf, (colnr_T)0);
888 fmt_ptr->prog = regmatch.regprog;
889 if (r)
890 {
891 if ((idx == 'C' || idx == 'Z') && !qfl->qf_multiline)
892 continue;
893 if (vim_strchr((char_u *)"EWI", idx) != NULL)
894 fields->type = idx;
895 else
896 fields->type = 0;
897 /*
898 * Extract error message data from matched line.
899 * We check for an actual submatch, because "\[" and "\]" in
900 * the 'errorformat' may cause the wrong submatch to be used.
901 */
902 if ((i = (int)fmt_ptr->addr[0]) > 0) /* %f */
903 {
904 int c;
905
906 if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL)
907 continue;
908
909 /* Expand ~/file and $HOME/file to full path. */
910 c = *regmatch.endp[i];
911 *regmatch.endp[i] = NUL;
912 expand_env(regmatch.startp[i], fields->namebuf, CMDBUFFSIZE);
913 *regmatch.endp[i] = c;
914
915 if (vim_strchr((char_u *)"OPQ", idx) != NULL
916 && mch_getperm(fields->namebuf) == -1)
917 continue;
918 }
919 if ((i = (int)fmt_ptr->addr[1]) > 0) /* %n */
920 {
921 if (regmatch.startp[i] == NULL)
922 continue;
923 fields->enr = (int)atol((char *)regmatch.startp[i]);
924 }
925 if ((i = (int)fmt_ptr->addr[2]) > 0) /* %l */
926 {
927 if (regmatch.startp[i] == NULL)
928 continue;
929 fields->lnum = atol((char *)regmatch.startp[i]);
930 }
931 if ((i = (int)fmt_ptr->addr[3]) > 0) /* %c */
932 {
933 if (regmatch.startp[i] == NULL)
934 continue;
935 fields->col = (int)atol((char *)regmatch.startp[i]);
936 }
937 if ((i = (int)fmt_ptr->addr[4]) > 0) /* %t */
938 {
939 if (regmatch.startp[i] == NULL)
940 continue;
941 fields->type = *regmatch.startp[i];
942 }
943 if (fmt_ptr->flags == '+' && !qfl->qf_multiscan) /* %+ */
944 {
945 if (linelen >= fields->errmsglen)
946 {
947 /* linelen + null terminator */
948 if ((fields->errmsg = vim_realloc(fields->errmsg,
949 linelen + 1)) == NULL)
950 return QF_NOMEM;
951 fields->errmsglen = linelen + 1;
952 }
953 vim_strncpy(fields->errmsg, linebuf, linelen);
954 }
955 else if ((i = (int)fmt_ptr->addr[5]) > 0) /* %m */
956 {
957 if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL)
958 continue;
959 len = (int)(regmatch.endp[i] - regmatch.startp[i]);
960 if (len >= fields->errmsglen)
961 {
962 /* len + null terminator */
963 if ((fields->errmsg = vim_realloc(fields->errmsg, len + 1))
964 == NULL)
965 return QF_NOMEM;
966 fields->errmsglen = len + 1;
967 }
968 vim_strncpy(fields->errmsg, regmatch.startp[i], len);
969 }
970 if ((i = (int)fmt_ptr->addr[6]) > 0) /* %r */
971 {
972 if (regmatch.startp[i] == NULL)
973 continue;
974 tail = regmatch.startp[i];
975 }
976 if ((i = (int)fmt_ptr->addr[7]) > 0) /* %p */
977 {
978 char_u *match_ptr;
979
980 if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL)
981 continue;
982 fields->col = 0;
983 for (match_ptr = regmatch.startp[i];
984 match_ptr != regmatch.endp[i]; ++match_ptr)
985 {
986 ++fields->col;
987 if (*match_ptr == TAB)
988 {
989 fields->col += 7;
990 fields->col -= fields->col % 8;
991 }
992 }
993 ++fields->col;
994 fields->use_viscol = TRUE;
995 }
996 if ((i = (int)fmt_ptr->addr[8]) > 0) /* %v */
997 {
998 if (regmatch.startp[i] == NULL)
999 continue;
1000 fields->col = (int)atol((char *)regmatch.startp[i]);
1001 fields->use_viscol = TRUE;
1002 }
1003 if ((i = (int)fmt_ptr->addr[9]) > 0) /* %s */
1004 {
1005 if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL)
1006 continue;
1007 len = (int)(regmatch.endp[i] - regmatch.startp[i]);
1008 if (len > CMDBUFFSIZE - 5)
1009 len = CMDBUFFSIZE - 5;
1010 STRCPY(fields->pattern, "^\\V");
1011 STRNCAT(fields->pattern, regmatch.startp[i], len);
1012 fields->pattern[len + 3] = '\\';
1013 fields->pattern[len + 4] = '$';
1014 fields->pattern[len + 5] = NUL;
1015 }
1016 if ((i = (int)fmt_ptr->addr[10]) > 0) /* %o */
1017 {
1018 if (regmatch.startp[i] == NULL)
1019 continue;
1020 len = (int)(regmatch.endp[i] - regmatch.startp[i]);
1021 if (len > CMDBUFFSIZE)
1022 len = CMDBUFFSIZE;
1023 STRNCAT(fields->module, regmatch.startp[i], len);
1024 }
1025 break; 1221 break;
1026 }
1027 } 1222 }
1028 qfl->qf_multiscan = FALSE; 1223 qfl->qf_multiscan = FALSE;
1029 1224
1030 if (fmt_ptr == NULL || idx == 'D' || idx == 'X') 1225 if (fmt_ptr == NULL || idx == 'D' || idx == 'X')
1031 { 1226 {
1032 if (fmt_ptr != NULL) 1227 if (fmt_ptr != NULL)
1033 { 1228 {
1034 if (idx == 'D') /* enter directory */ 1229 /* 'D' and 'X' directory specifiers */
1035 { 1230 status = qf_parse_dir_pfx(idx, fields, qfl);
1036 if (*fields->namebuf == NUL) 1231 if (status != QF_OK)
1037 { 1232 return status;
1038 EMSG(_("E379: Missing or empty directory name")); 1233 }
1039 return QF_FAIL; 1234
1040 } 1235 status = qf_parse_line_nomatch(linebuf, linelen, fields);
1041 qfl->qf_directory = 1236 if (status != QF_OK)
1042 qf_push_dir(fields->namebuf, &qfl->qf_dir_stack, FALSE); 1237 return status;
1043 if (qfl->qf_directory == NULL) 1238
1044 return QF_FAIL;
1045 }
1046 else if (idx == 'X') /* leave directory */
1047 qfl->qf_directory = qf_pop_dir(&qfl->qf_dir_stack);
1048 }
1049 fields->namebuf[0] = NUL; /* no match found, remove file name */
1050 fields->lnum = 0; /* don't jump to this line */
1051 fields->valid = FALSE;
1052 if (linelen >= fields->errmsglen)
1053 {
1054 /* linelen + null terminator */
1055 if ((fields->errmsg = vim_realloc(fields->errmsg,
1056 linelen + 1)) == NULL)
1057 return QF_NOMEM;
1058 fields->errmsglen = linelen + 1;
1059 }
1060 /* copy whole line to error message */
1061 vim_strncpy(fields->errmsg, linebuf, linelen);
1062 if (fmt_ptr == NULL) 1239 if (fmt_ptr == NULL)
1063 qfl->qf_multiline = qfl->qf_multiignore = FALSE; 1240 qfl->qf_multiline = qfl->qf_multiignore = FALSE;
1064 } 1241 }
1065 else if (fmt_ptr != NULL) 1242 else if (fmt_ptr != NULL)
1066 { 1243 {
1073 qfl->qf_multiline = TRUE; /* start of a multi-line message */ 1250 qfl->qf_multiline = TRUE; /* start of a multi-line message */
1074 qfl->qf_multiignore = FALSE;/* reset continuation */ 1251 qfl->qf_multiignore = FALSE;/* reset continuation */
1075 } 1252 }
1076 else if (vim_strchr((char_u *)"CZ", idx) != NULL) 1253 else if (vim_strchr((char_u *)"CZ", idx) != NULL)
1077 { /* continuation of multi-line msg */ 1254 { /* continuation of multi-line msg */
1078 if (!qfl->qf_multiignore) 1255 status = qf_parse_multiline_pfx(qi, qf_idx, idx, qfl, fields);
1079 { 1256 if (status != QF_OK)
1080 qfline_T *qfprev = qfl->qf_last; 1257 return status;
1081
1082 if (qfprev == NULL)
1083 return QF_FAIL;
1084 if (*fields->errmsg && !qfl->qf_multiignore)
1085 {
1086 len = (int)STRLEN(qfprev->qf_text);
1087 if ((ptr = alloc((unsigned)(len + STRLEN(fields->errmsg) + 2)))
1088 == NULL)
1089 return QF_FAIL;
1090 STRCPY(ptr, qfprev->qf_text);
1091 vim_free(qfprev->qf_text);
1092 qfprev->qf_text = ptr;
1093 *(ptr += len) = '\n';
1094 STRCPY(++ptr, fields->errmsg);
1095 }
1096 if (qfprev->qf_nr == -1)
1097 qfprev->qf_nr = fields->enr;
1098 if (vim_isprintc(fields->type) && !qfprev->qf_type)
1099 /* only printable chars allowed */
1100 qfprev->qf_type = fields->type;
1101
1102 if (!qfprev->qf_lnum)
1103 qfprev->qf_lnum = fields->lnum;
1104 if (!qfprev->qf_col)
1105 qfprev->qf_col = fields->col;
1106 qfprev->qf_viscol = fields->use_viscol;
1107 if (!qfprev->qf_fnum)
1108 qfprev->qf_fnum = qf_get_fnum(qi, qf_idx,
1109 qfl->qf_directory,
1110 *fields->namebuf || qfl->qf_directory != NULL
1111 ? fields->namebuf
1112 : qfl->qf_currfile != NULL && fields->valid
1113 ? qfl->qf_currfile : 0);
1114 }
1115 if (idx == 'Z')
1116 qfl->qf_multiline = qfl->qf_multiignore = FALSE;
1117 line_breakcheck();
1118 return QF_IGNORE_LINE;
1119 } 1258 }
1120 else if (vim_strchr((char_u *)"OPQ", idx) != NULL) 1259 else if (vim_strchr((char_u *)"OPQ", idx) != NULL)
1121 { 1260 { /* global file names */
1122 /* global file names */ 1261 status = qf_parse_file_pfx(idx, fields, qfl, tail);
1123 fields->valid = FALSE; 1262 if (status == QF_MULTISCAN)
1124 if (*fields->namebuf == NUL || mch_getperm(fields->namebuf) >= 0) 1263 goto restofline;
1125 {
1126 if (*fields->namebuf && idx == 'P')
1127 qfl->qf_currfile =
1128 qf_push_dir(fields->namebuf, &qfl->qf_file_stack, TRUE);
1129 else if (idx == 'Q')
1130 qfl->qf_currfile = qf_pop_dir(&qfl->qf_file_stack);
1131 *fields->namebuf = NUL;
1132 if (tail && *tail)
1133 {
1134 STRMOVE(IObuff, skipwhite(tail));
1135 qfl->qf_multiscan = TRUE;
1136 goto restofline;
1137 }
1138 }
1139 } 1264 }
1140 if (fmt_ptr->flags == '-') /* generally exclude this line */ 1265 if (fmt_ptr->flags == '-') /* generally exclude this line */
1141 { 1266 {
1142 if (qfl->qf_multiline) 1267 if (qfl->qf_multiline)
1143 /* also exclude continuation lines */ 1268 /* also exclude continuation lines */
1356 #endif 1481 #endif
1357 1482
1358 return retval; 1483 return retval;
1359 } 1484 }
1360 1485
1486 /*
1487 * Set the title of the specified quickfix list. Frees the previous title.
1488 * Prepends ':' to the title.
1489 */
1361 static void 1490 static void
1362 qf_store_title(qf_info_T *qi, int qf_idx, char_u *title) 1491 qf_store_title(qf_info_T *qi, int qf_idx, char_u *title)
1363 { 1492 {
1364 VIM_CLEAR(qi->qf_lists[qf_idx].qf_title); 1493 VIM_CLEAR(qi->qf_lists[qf_idx].qf_title);
1365 1494
1431 qf_free(qi, i); 1560 qf_free(qi, i);
1432 vim_free(qi); 1561 vim_free(qi);
1433 } 1562 }
1434 } 1563 }
1435 1564
1565 /*
1566 * Free all the quickfix/location lists in the stack.
1567 */
1436 void 1568 void
1437 qf_free_all(win_T *wp) 1569 qf_free_all(win_T *wp)
1438 { 1570 {
1439 int i; 1571 int i;
1440 qf_info_T *qi = &ql_info; 1572 qf_info_T *qi = &ql_info;
2874 buf[i] = *p++; 3006 buf[i] = *p++;
2875 } 3007 }
2876 buf[i] = NUL; 3008 buf[i] = NUL;
2877 } 3009 }
2878 3010
3011 /*
3012 * Display information (list number, list size and the title) about a
3013 * quickfix/location list.
3014 */
2879 static void 3015 static void
2880 qf_msg(qf_info_T *qi, int which, char *lead) 3016 qf_msg(qf_info_T *qi, int which, char *lead)
2881 { 3017 {
2882 char *title = (char *)qi->qf_lists[which].qf_title; 3018 char *title = (char *)qi->qf_lists[which].qf_title;
2883 int count = qi->qf_lists[which].qf_count; 3019 int count = qi->qf_lists[which].qf_count;
2953 } 3089 }
2954 qf_msg(qi, qi->qf_curlist, ""); 3090 qf_msg(qi, qi->qf_curlist, "");
2955 qf_update_buffer(qi, NULL); 3091 qf_update_buffer(qi, NULL);
2956 } 3092 }
2957 3093
3094 /*
3095 * Display the information about all the quickfix/location lists in the stack
3096 */
2958 void 3097 void
2959 qf_history(exarg_T *eap) 3098 qf_history(exarg_T *eap)
2960 { 3099 {
2961 qf_info_T *qi = &ql_info; 3100 qf_info_T *qi = &ql_info;
2962 int i; 3101 int i;
3693 3832
3694 /* Restore KeyTyped, setting 'filetype' may reset it. */ 3833 /* Restore KeyTyped, setting 'filetype' may reset it. */
3695 KeyTyped = old_KeyTyped; 3834 KeyTyped = old_KeyTyped;
3696 } 3835 }
3697 3836
3837 /*
3838 * For every change made to the quickfix list, update the changed tick.
3839 */
3698 static void 3840 static void
3699 qf_list_changed(qf_info_T *qi, int qf_idx) 3841 qf_list_changed(qf_info_T *qi, int qf_idx)
3700 { 3842 {
3701 qi->qf_lists[qf_idx].qf_changedtick++; 3843 qi->qf_lists[qf_idx].qf_changedtick++;
3702 } 3844 }
5002 QF_GETLIST_CONTEXT = 0x10, 5144 QF_GETLIST_CONTEXT = 0x10,
5003 QF_GETLIST_ID = 0x20, 5145 QF_GETLIST_ID = 0x20,
5004 QF_GETLIST_IDX = 0x40, 5146 QF_GETLIST_IDX = 0x40,
5005 QF_GETLIST_SIZE = 0x80, 5147 QF_GETLIST_SIZE = 0x80,
5006 QF_GETLIST_TICK = 0x100, 5148 QF_GETLIST_TICK = 0x100,
5007 QF_GETLIST_ALL = 0x1FF 5149 QF_GETLIST_ALL = 0x1FF,
5008 }; 5150 };
5009 5151
5010 /* 5152 /*
5011 * Parse text from 'di' and return the quickfix list items. 5153 * Parse text from 'di' and return the quickfix list items.
5012 * Existing quickfix lists are not modified. 5154 * Existing quickfix lists are not modified.
5783 } 5925 }
5784 5926
5785 return retval; 5927 return retval;
5786 } 5928 }
5787 5929
5930 /*
5931 * Mark the context as in use for all the lists in a quickfix stack.
5932 */
5788 static int 5933 static int
5789 mark_quickfix_ctx(qf_info_T *qi, int copyID) 5934 mark_quickfix_ctx(qf_info_T *qi, int copyID)
5790 { 5935 {
5791 int i; 5936 int i;
5792 int abort = FALSE; 5937 int abort = FALSE;
6165 FreeWild(fcount, fnames); 6310 FreeWild(fcount, fnames);
6166 } 6311 }
6167 } 6312 }
6168 6313
6169 /* 6314 /*
6170 * Search for a pattern in all the help files in the 'runtimepath'. 6315 * Search for a pattern in all the help files in the 'runtimepath'
6316 * and add the matches to a quickfix list.
6317 * 'arg' is the language specifier. If supplied, then only matches in the
6318 * specified language are found.
6171 */ 6319 */
6172 static void 6320 static void
6173 hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch, char_u *arg) 6321 hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch, char_u *arg)
6174 { 6322 {
6175 char_u *p; 6323 char_u *p;
6190 #ifdef FEAT_MULTI_LANG 6338 #ifdef FEAT_MULTI_LANG
6191 /* Check for a specified language */ 6339 /* Check for a specified language */
6192 lang = check_help_lang(arg); 6340 lang = check_help_lang(arg);
6193 #endif 6341 #endif
6194 6342
6195 /* Go through all directories in 'runtimepath' */ 6343 /* Go through all the directories in 'runtimepath' */
6196 p = p_rtp; 6344 p = p_rtp;
6197 while (*p != NUL && !got_int) 6345 while (*p != NUL && !got_int)
6198 { 6346 {
6199 copy_option_part(&p, NameBuff, MAXPATHL, ","); 6347 copy_option_part(&p, NameBuff, MAXPATHL, ",");
6200 6348