Mercurial > vim
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(®match, linebuf, (colnr_T)0); | |
1030 fmt_ptr->prog = regmatch.regprog; | |
1031 if (r) | |
1032 status = qf_parse_match(linebuf, linelen, fmt_ptr, ®match, | |
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(®match, 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 |