summaryrefslogtreecommitdiff
path: root/data/vim/patches/8.1.1099
diff options
context:
space:
mode:
Diffstat (limited to 'data/vim/patches/8.1.1099')
-rw-r--r--data/vim/patches/8.1.10991326
1 files changed, 1326 insertions, 0 deletions
diff --git a/data/vim/patches/8.1.1099 b/data/vim/patches/8.1.1099
new file mode 100644
index 000000000..9aa426928
--- /dev/null
+++ b/data/vim/patches/8.1.1099
@@ -0,0 +1,1326 @@
+To: vim_dev@googlegroups.com
+Subject: Patch 8.1.1099
+Fcc: outbox
+From: Bram Moolenaar <Bram@moolenaar.net>
+Mime-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+------------
+
+Patch 8.1.1099
+Problem: The do_tag() function is too long.
+Solution: Factor parts out to separate functions. Move simplify_filename()
+ to a file where it fits better. (Andy Massimino, closes #4195)
+Files: src/tag.c, src/proto/tag.pro, src/findfile.c,
+ src/proto/findfile.pro
+
+
+*** ../vim-8.1.1098/src/tag.c 2019-03-30 21:41:44.218279831 +0100
+--- src/tag.c 2019-03-31 19:14:18.988597395 +0200
+***************
+*** 74,79 ****
+--- 74,83 ----
+ static int test_for_current(char_u *, char_u *, char_u *, char_u *);
+ #endif
+ static int find_extra(char_u **pp);
++ static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char_u **matches);
++ #if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL)
++ static int add_llist_tags(char_u *tag, int num_matches, char_u **matches);
++ #endif
+
+ static char_u *bottommsg = (char_u *)N_("E555: at bottom of tag stack");
+ static char_u *topmsg = (char_u *)N_("E556: at top of tag stack");
+***************
+*** 125,149 ****
+ int prevtagstackidx = tagstackidx;
+ int prev_num_matches;
+ int new_tag = FALSE;
+! int other_name;
+! int i, j, k;
+! int idx;
+ int ic;
+- char_u *p;
+- char_u *name;
+ int no_regexp = FALSE;
+ int error_cur_match = 0;
+- char_u *command_end;
+ int save_pos = FALSE;
+ fmark_T saved_fmark;
+- int taglen;
+ #ifdef FEAT_CSCOPE
+ int jumped_to_tag = FALSE;
+ #endif
+- tagptrs_T tagp, tagp2;
+ int new_num_matches;
+ char_u **new_matches;
+- int attr;
+ int use_tagstack;
+ int skip_msg = FALSE;
+ char_u *buf_ffname = curbuf->b_ffname; /* name to use for
+--- 129,145 ----
+ int prevtagstackidx = tagstackidx;
+ int prev_num_matches;
+ int new_tag = FALSE;
+! int i;
+ int ic;
+ int no_regexp = FALSE;
+ int error_cur_match = 0;
+ int save_pos = FALSE;
+ fmark_T saved_fmark;
+ #ifdef FEAT_CSCOPE
+ int jumped_to_tag = FALSE;
+ #endif
+ int new_num_matches;
+ char_u **new_matches;
+ int use_tagstack;
+ int skip_msg = FALSE;
+ char_u *buf_ffname = curbuf->b_ffname; /* name to use for
+***************
+*** 482,487 ****
+--- 478,486 ----
+ */
+ for (;;)
+ {
++ int other_name;
++ char_u *name;
++
+ /*
+ * When desired match not found yet, try to find it (and others).
+ */
+***************
+*** 541,549 ****
+ * ":tnext" and jumping to another file. */
+ if (!new_tag && !other_name)
+ {
+ /* Find the position of each old match in the new list. Need
+ * to use parse_match() to find the tag line. */
+- idx = 0;
+ for (j = 0; j < num_matches; ++j)
+ {
+ parse_match(matches[j], &tagp);
+--- 540,551 ----
+ * ":tnext" and jumping to another file. */
+ if (!new_tag && !other_name)
+ {
++ int j, k;
++ int idx = 0;
++ tagptrs_T tagp, tagp2;
++
+ /* Find the position of each old match in the new list. Need
+ * to use parse_match() to find the tag line. */
+ for (j = 0; j < num_matches; ++j)
+ {
+ parse_match(matches[j], &tagp);
+***************
+*** 552,558 ****
+ parse_match(new_matches[i], &tagp2);
+ if (STRCMP(tagp.tagname, tagp2.tagname) == 0)
+ {
+! p = new_matches[i];
+ for (k = i; k > idx; --k)
+ new_matches[k] = new_matches[k - 1];
+ new_matches[idx++] = p;
+--- 554,560 ----
+ parse_match(new_matches[i], &tagp2);
+ if (STRCMP(tagp.tagname, tagp2.tagname) == 0)
+ {
+! char_u *p = new_matches[i];
+ for (k = i; k > idx; --k)
+ new_matches[k] = new_matches[k - 1];
+ new_matches[idx++] = p;
+***************
+*** 587,927 ****
+ else
+ #endif
+ if (type == DT_TAG && *tag != NUL)
+! /*
+! * If a count is supplied to the ":tag <name>" command, then
+! * jump to count'th matching tag.
+! */
+ cur_match = count > 0 ? count - 1 : 0;
+ else if (type == DT_SELECT || (type == DT_JUMP && num_matches > 1))
+ {
+! /*
+! * List all the matching tags.
+! * Assume that the first match indicates how long the tags can
+! * be, and align the file names to that.
+! */
+! parse_match(matches[0], &tagp);
+! taglen = (int)(tagp.tagname_end - tagp.tagname + 2);
+! if (taglen < 18)
+! taglen = 18;
+! if (taglen > Columns - 25)
+! taglen = MAXCOL;
+! if (msg_col == 0)
+! msg_didout = FALSE; /* overwrite previous message */
+! msg_start();
+! msg_puts_attr(_(" # pri kind tag"), HL_ATTR(HLF_T));
+! msg_clr_eos();
+! taglen_advance(taglen);
+! msg_puts_attr(_("file\n"), HL_ATTR(HLF_T));
+!
+! for (i = 0; i < num_matches && !got_int; ++i)
+! {
+! parse_match(matches[i], &tagp);
+! if (!new_tag && (
+! #if defined(FEAT_QUICKFIX)
+! (g_do_tagpreview != 0
+! && i == ptag_entry.cur_match) ||
+! #endif
+! (use_tagstack
+! && i == tagstack[tagstackidx].cur_match)))
+! *IObuff = '>';
+! else
+! *IObuff = ' ';
+! vim_snprintf((char *)IObuff + 1, IOSIZE - 1,
+! "%2d %s ", i + 1,
+! mt_names[matches[i][0] & MT_MASK]);
+! msg_puts((char *)IObuff);
+! if (tagp.tagkind != NULL)
+! msg_outtrans_len(tagp.tagkind,
+! (int)(tagp.tagkind_end - tagp.tagkind));
+! msg_advance(13);
+! msg_outtrans_len_attr(tagp.tagname,
+! (int)(tagp.tagname_end - tagp.tagname),
+! HL_ATTR(HLF_T));
+! msg_putchar(' ');
+! taglen_advance(taglen);
+!
+! /* Find out the actual file name. If it is long, truncate
+! * it and put "..." in the middle */
+! p = tag_full_fname(&tagp);
+! if (p != NULL)
+! {
+! msg_outtrans_long_attr(p, HL_ATTR(HLF_D));
+! vim_free(p);
+! }
+! if (msg_col > 0)
+! msg_putchar('\n');
+! if (got_int)
+! break;
+! msg_advance(15);
+!
+! /* print any extra fields */
+! command_end = tagp.command_end;
+! if (command_end != NULL)
+! {
+! p = command_end + 3;
+! while (*p && *p != '\r' && *p != '\n')
+! {
+! while (*p == TAB)
+! ++p;
+!
+! /* skip "file:" without a value (static tag) */
+! if (STRNCMP(p, "file:", 5) == 0
+! && vim_isspace(p[5]))
+! {
+! p += 5;
+! continue;
+! }
+! /* skip "kind:<kind>" and "<kind>" */
+! if (p == tagp.tagkind
+! || (p + 5 == tagp.tagkind
+! && STRNCMP(p, "kind:", 5) == 0))
+! {
+! p = tagp.tagkind_end;
+! continue;
+! }
+! /* print all other extra fields */
+! attr = HL_ATTR(HLF_CM);
+! while (*p && *p != '\r' && *p != '\n')
+! {
+! if (msg_col + ptr2cells(p) >= Columns)
+! {
+! msg_putchar('\n');
+! if (got_int)
+! break;
+! msg_advance(15);
+! }
+! p = msg_outtrans_one(p, attr);
+! if (*p == TAB)
+! {
+! msg_puts_attr(" ", attr);
+! break;
+! }
+! if (*p == ':')
+! attr = 0;
+! }
+! }
+! if (msg_col > 15)
+! {
+! msg_putchar('\n');
+! if (got_int)
+! break;
+! msg_advance(15);
+! }
+! }
+! else
+! {
+! for (p = tagp.command;
+! *p && *p != '\r' && *p != '\n'; ++p)
+! ;
+! command_end = p;
+! }
+!
+! /*
+! * Put the info (in several lines) at column 15.
+! * Don't display "/^" and "?^".
+! */
+! p = tagp.command;
+! if (*p == '/' || *p == '?')
+! {
+! ++p;
+! if (*p == '^')
+! ++p;
+! }
+! /* Remove leading whitespace from pattern */
+! while (p != command_end && vim_isspace(*p))
+! ++p;
+!
+! while (p != command_end)
+! {
+! if (msg_col + (*p == TAB ? 1 : ptr2cells(p)) > Columns)
+! msg_putchar('\n');
+! if (got_int)
+! break;
+! msg_advance(15);
+!
+! /* skip backslash used for escaping a command char or
+! * a backslash */
+! if (*p == '\\' && (*(p + 1) == *tagp.command
+! || *(p + 1) == '\\'))
+! ++p;
+!
+! if (*p == TAB)
+! {
+! msg_putchar(' ');
+! ++p;
+! }
+! else
+! p = msg_outtrans_one(p, 0);
+!
+! /* don't display the "$/;\"" and "$?;\"" */
+! if (p == command_end - 2 && *p == '$'
+! && *(p + 1) == *tagp.command)
+! break;
+! /* don't display matching '/' or '?' */
+! if (p == command_end - 1 && *p == *tagp.command
+! && (*p == '/' || *p == '?'))
+! break;
+! }
+! if (msg_col)
+! msg_putchar('\n');
+! ui_breakcheck();
+! }
+! if (got_int)
+! got_int = FALSE; /* only stop the listing */
+ ask_for_selection = TRUE;
+ }
+ #if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL)
+ else if (type == DT_LTAG)
+ {
+! list_T *list;
+! char_u tag_name[128 + 1];
+! char_u *fname;
+! char_u *cmd;
+!
+! /*
+! * Add the matching tags to the location list for the current
+! * window.
+! */
+!
+! fname = alloc(MAXPATHL + 1);
+! cmd = alloc(CMDBUFFSIZE + 1);
+! list = list_alloc();
+! if (list == NULL || fname == NULL || cmd == NULL)
+! {
+! vim_free(cmd);
+! vim_free(fname);
+! if (list != NULL)
+! list_free(list);
+ goto end_do_tag;
+- }
+-
+- for (i = 0; i < num_matches; ++i)
+- {
+- int len, cmd_len;
+- long lnum;
+- dict_T *dict;
+-
+- parse_match(matches[i], &tagp);
+-
+- /* Save the tag name */
+- len = (int)(tagp.tagname_end - tagp.tagname);
+- if (len > 128)
+- len = 128;
+- vim_strncpy(tag_name, tagp.tagname, len);
+- tag_name[len] = NUL;
+-
+- /* Save the tag file name */
+- p = tag_full_fname(&tagp);
+- if (p == NULL)
+- continue;
+- vim_strncpy(fname, p, MAXPATHL);
+- vim_free(p);
+-
+- /*
+- * Get the line number or the search pattern used to locate
+- * the tag.
+- */
+- lnum = 0;
+- if (isdigit(*tagp.command))
+- /* Line number is used to locate the tag */
+- lnum = atol((char *)tagp.command);
+- else
+- {
+- char_u *cmd_start, *cmd_end;
+-
+- /* Search pattern is used to locate the tag */
+-
+- /* Locate the end of the command */
+- cmd_start = tagp.command;
+- cmd_end = tagp.command_end;
+- if (cmd_end == NULL)
+- {
+- for (p = tagp.command;
+- *p && *p != '\r' && *p != '\n'; ++p)
+- ;
+- cmd_end = p;
+- }
+-
+- /*
+- * Now, cmd_end points to the character after the
+- * command. Adjust it to point to the last
+- * character of the command.
+- */
+- cmd_end--;
+-
+- /*
+- * Skip the '/' and '?' characters at the
+- * beginning and end of the search pattern.
+- */
+- if (*cmd_start == '/' || *cmd_start == '?')
+- cmd_start++;
+-
+- if (*cmd_end == '/' || *cmd_end == '?')
+- cmd_end--;
+-
+- len = 0;
+- cmd[0] = NUL;
+-
+- /*
+- * If "^" is present in the tag search pattern, then
+- * copy it first.
+- */
+- if (*cmd_start == '^')
+- {
+- STRCPY(cmd, "^");
+- cmd_start++;
+- len++;
+- }
+-
+- /*
+- * Precede the tag pattern with \V to make it very
+- * nomagic.
+- */
+- STRCAT(cmd, "\\V");
+- len += 2;
+-
+- cmd_len = (int)(cmd_end - cmd_start + 1);
+- if (cmd_len > (CMDBUFFSIZE - 5))
+- cmd_len = CMDBUFFSIZE - 5;
+- STRNCAT(cmd, cmd_start, cmd_len);
+- len += cmd_len;
+-
+- if (cmd[len - 1] == '$')
+- {
+- /*
+- * Replace '$' at the end of the search pattern
+- * with '\$'
+- */
+- cmd[len - 1] = '\\';
+- cmd[len] = '$';
+- len++;
+- }
+-
+- cmd[len] = NUL;
+- }
+-
+- if ((dict = dict_alloc()) == NULL)
+- continue;
+- if (list_append_dict(list, dict) == FAIL)
+- {
+- vim_free(dict);
+- continue;
+- }
+-
+- dict_add_string(dict, "text", tag_name);
+- dict_add_string(dict, "filename", fname);
+- dict_add_number(dict, "lnum", lnum);
+- if (lnum == 0)
+- dict_add_string(dict, "pattern", cmd);
+- }
+-
+- vim_snprintf((char *)IObuff, IOSIZE, "ltag %s", tag);
+- set_errorlist(curwin, list, ' ', IObuff, NULL);
+-
+- list_free(list);
+- vim_free(fname);
+- vim_free(cmd);
+-
+ cur_match = 0; /* Jump to the first tag */
+ }
+ #endif
+--- 589,607 ----
+ else
+ #endif
+ if (type == DT_TAG && *tag != NUL)
+! // If a count is supplied to the ":tag <name>" command, then
+! // jump to count'th matching tag.
+ cur_match = count > 0 ? count - 1 : 0;
+ else if (type == DT_SELECT || (type == DT_JUMP && num_matches > 1))
+ {
+! print_tag_list(new_tag, use_tagstack, num_matches, matches);
+ ask_for_selection = TRUE;
+ }
+ #if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL)
+ else if (type == DT_LTAG)
+ {
+! if (add_llist_tags(tag, num_matches, matches) == FAIL)
+ goto end_do_tag;
+ cur_match = 0; /* Jump to the first tag */
+ }
+ #endif
+***************
+*** 1089,1094 ****
+--- 769,1116 ----
+ }
+
+ /*
++ * List all the matching tags.
++ */
++ static void
++ print_tag_list(
++ int new_tag,
++ int use_tagstack,
++ int num_matches,
++ char_u **matches)
++ {
++ taggy_T *tagstack = curwin->w_tagstack;
++ int tagstackidx = curwin->w_tagstackidx;
++ int i;
++ char_u *p;
++ char_u *command_end;
++ tagptrs_T tagp;
++ int taglen;
++ int attr;
++
++ /*
++ * Assume that the first match indicates how long the tags can
++ * be, and align the file names to that.
++ */
++ parse_match(matches[0], &tagp);
++ taglen = (int)(tagp.tagname_end - tagp.tagname + 2);
++ if (taglen < 18)
++ taglen = 18;
++ if (taglen > Columns - 25)
++ taglen = MAXCOL;
++ if (msg_col == 0)
++ msg_didout = FALSE; // overwrite previous message
++ msg_start();
++ msg_puts_attr(_(" # pri kind tag"), HL_ATTR(HLF_T));
++ msg_clr_eos();
++ taglen_advance(taglen);
++ msg_puts_attr(_("file\n"), HL_ATTR(HLF_T));
++
++ for (i = 0; i < num_matches && !got_int; ++i)
++ {
++ parse_match(matches[i], &tagp);
++ if (!new_tag && (
++ #if defined(FEAT_QUICKFIX)
++ (g_do_tagpreview != 0
++ && i == ptag_entry.cur_match) ||
++ #endif
++ (use_tagstack
++ && i == tagstack[tagstackidx].cur_match)))
++ *IObuff = '>';
++ else
++ *IObuff = ' ';
++ vim_snprintf((char *)IObuff + 1, IOSIZE - 1,
++ "%2d %s ", i + 1,
++ mt_names[matches[i][0] & MT_MASK]);
++ msg_puts((char *)IObuff);
++ if (tagp.tagkind != NULL)
++ msg_outtrans_len(tagp.tagkind,
++ (int)(tagp.tagkind_end - tagp.tagkind));
++ msg_advance(13);
++ msg_outtrans_len_attr(tagp.tagname,
++ (int)(tagp.tagname_end - tagp.tagname),
++ HL_ATTR(HLF_T));
++ msg_putchar(' ');
++ taglen_advance(taglen);
++
++ // Find out the actual file name. If it is long, truncate
++ // it and put "..." in the middle
++ p = tag_full_fname(&tagp);
++ if (p != NULL)
++ {
++ msg_outtrans_long_attr(p, HL_ATTR(HLF_D));
++ vim_free(p);
++ }
++ if (msg_col > 0)
++ msg_putchar('\n');
++ if (got_int)
++ break;
++ msg_advance(15);
++
++ // print any extra fields
++ command_end = tagp.command_end;
++ if (command_end != NULL)
++ {
++ p = command_end + 3;
++ while (*p && *p != '\r' && *p != '\n')
++ {
++ while (*p == TAB)
++ ++p;
++
++ // skip "file:" without a value (static tag)
++ if (STRNCMP(p, "file:", 5) == 0
++ && vim_isspace(p[5]))
++ {
++ p += 5;
++ continue;
++ }
++ // skip "kind:<kind>" and "<kind>"
++ if (p == tagp.tagkind
++ || (p + 5 == tagp.tagkind
++ && STRNCMP(p, "kind:", 5) == 0))
++ {
++ p = tagp.tagkind_end;
++ continue;
++ }
++ // print all other extra fields
++ attr = HL_ATTR(HLF_CM);
++ while (*p && *p != '\r' && *p != '\n')
++ {
++ if (msg_col + ptr2cells(p) >= Columns)
++ {
++ msg_putchar('\n');
++ if (got_int)
++ break;
++ msg_advance(15);
++ }
++ p = msg_outtrans_one(p, attr);
++ if (*p == TAB)
++ {
++ msg_puts_attr(" ", attr);
++ break;
++ }
++ if (*p == ':')
++ attr = 0;
++ }
++ }
++ if (msg_col > 15)
++ {
++ msg_putchar('\n');
++ if (got_int)
++ break;
++ msg_advance(15);
++ }
++ }
++ else
++ {
++ for (p = tagp.command;
++ *p && *p != '\r' && *p != '\n'; ++p)
++ ;
++ command_end = p;
++ }
++
++ // Put the info (in several lines) at column 15.
++ // Don't display "/^" and "?^".
++ p = tagp.command;
++ if (*p == '/' || *p == '?')
++ {
++ ++p;
++ if (*p == '^')
++ ++p;
++ }
++ // Remove leading whitespace from pattern
++ while (p != command_end && vim_isspace(*p))
++ ++p;
++
++ while (p != command_end)
++ {
++ if (msg_col + (*p == TAB ? 1 : ptr2cells(p)) > Columns)
++ msg_putchar('\n');
++ if (got_int)
++ break;
++ msg_advance(15);
++
++ // skip backslash used for escaping a command char or
++ // a backslash
++ if (*p == '\\' && (*(p + 1) == *tagp.command
++ || *(p + 1) == '\\'))
++ ++p;
++
++ if (*p == TAB)
++ {
++ msg_putchar(' ');
++ ++p;
++ }
++ else
++ p = msg_outtrans_one(p, 0);
++
++ // don't display the "$/;\"" and "$?;\""
++ if (p == command_end - 2 && *p == '$'
++ && *(p + 1) == *tagp.command)
++ break;
++ // don't display matching '/' or '?'
++ if (p == command_end - 1 && *p == *tagp.command
++ && (*p == '/' || *p == '?'))
++ break;
++ }
++ if (msg_col)
++ msg_putchar('\n');
++ ui_breakcheck();
++ }
++ if (got_int)
++ got_int = FALSE; // only stop the listing
++ }
++
++ #if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL)
++ /*
++ * Add the matching tags to the location list for the current
++ * window.
++ */
++ static int
++ add_llist_tags(
++ char_u *tag,
++ int num_matches,
++ char_u **matches)
++ {
++ list_T *list;
++ char_u tag_name[128 + 1];
++ char_u *fname;
++ char_u *cmd;
++ int i;
++ char_u *p;
++ tagptrs_T tagp;
++
++ fname = alloc(MAXPATHL + 1);
++ cmd = alloc(CMDBUFFSIZE + 1);
++ list = list_alloc();
++ if (list == NULL || fname == NULL || cmd == NULL)
++ {
++ vim_free(cmd);
++ vim_free(fname);
++ if (list != NULL)
++ list_free(list);
++ return FAIL;
++ }
++
++ for (i = 0; i < num_matches; ++i)
++ {
++ int len, cmd_len;
++ long lnum;
++ dict_T *dict;
++
++ parse_match(matches[i], &tagp);
++
++ /* Save the tag name */
++ len = (int)(tagp.tagname_end - tagp.tagname);
++ if (len > 128)
++ len = 128;
++ vim_strncpy(tag_name, tagp.tagname, len);
++ tag_name[len] = NUL;
++
++ // Save the tag file name
++ p = tag_full_fname(&tagp);
++ if (p == NULL)
++ continue;
++ vim_strncpy(fname, p, MAXPATHL);
++ vim_free(p);
++
++ // Get the line number or the search pattern used to locate
++ // the tag.
++ lnum = 0;
++ if (isdigit(*tagp.command))
++ // Line number is used to locate the tag
++ lnum = atol((char *)tagp.command);
++ else
++ {
++ char_u *cmd_start, *cmd_end;
++
++ // Search pattern is used to locate the tag
++
++ // Locate the end of the command
++ cmd_start = tagp.command;
++ cmd_end = tagp.command_end;
++ if (cmd_end == NULL)
++ {
++ for (p = tagp.command;
++ *p && *p != '\r' && *p != '\n'; ++p)
++ ;
++ cmd_end = p;
++ }
++
++ // Now, cmd_end points to the character after the
++ // command. Adjust it to point to the last
++ // character of the command.
++ cmd_end--;
++
++ // Skip the '/' and '?' characters at the
++ // beginning and end of the search pattern.
++ if (*cmd_start == '/' || *cmd_start == '?')
++ cmd_start++;
++
++ if (*cmd_end == '/' || *cmd_end == '?')
++ cmd_end--;
++
++ len = 0;
++ cmd[0] = NUL;
++
++ // If "^" is present in the tag search pattern, then
++ // copy it first.
++ if (*cmd_start == '^')
++ {
++ STRCPY(cmd, "^");
++ cmd_start++;
++ len++;
++ }
++
++ // Precede the tag pattern with \V to make it very
++ // nomagic.
++ STRCAT(cmd, "\\V");
++ len += 2;
++
++ cmd_len = (int)(cmd_end - cmd_start + 1);
++ if (cmd_len > (CMDBUFFSIZE - 5))
++ cmd_len = CMDBUFFSIZE - 5;
++ STRNCAT(cmd, cmd_start, cmd_len);
++ len += cmd_len;
++
++ if (cmd[len - 1] == '$')
++ {
++ // Replace '$' at the end of the search pattern
++ // with '\$'
++ cmd[len - 1] = '\\';
++ cmd[len] = '$';
++ len++;
++ }
++
++ cmd[len] = NUL;
++ }
++
++ if ((dict = dict_alloc()) == NULL)
++ continue;
++ if (list_append_dict(list, dict) == FAIL)
++ {
++ vim_free(dict);
++ continue;
++ }
++
++ dict_add_string(dict, "text", tag_name);
++ dict_add_string(dict, "filename", fname);
++ dict_add_number(dict, "lnum", lnum);
++ if (lnum == 0)
++ dict_add_string(dict, "pattern", cmd);
++ }
++
++ vim_snprintf((char *)IObuff, IOSIZE, "ltag %s", tag);
++ set_errorlist(curwin, list, ' ', IObuff, NULL);
++
++ list_free(list);
++ vim_free(fname);
++ vim_free(cmd);
++
++ return OK;
++ }
++ #endif
++
++ /*
+ * Free cached tags.
+ */
+ void
+***************
+*** 3431,3648 ****
+ }
+
+ /*
+- * Converts a file name into a canonical form. It simplifies a file name into
+- * its simplest form by stripping out unneeded components, if any. The
+- * resulting file name is simplified in place and will either be the same
+- * length as that supplied, or shorter.
+- */
+- void
+- simplify_filename(char_u *filename)
+- {
+- #ifndef AMIGA /* Amiga doesn't have "..", it uses "/" */
+- int components = 0;
+- char_u *p, *tail, *start;
+- int stripping_disabled = FALSE;
+- int relative = TRUE;
+-
+- p = filename;
+- #ifdef BACKSLASH_IN_FILENAME
+- if (p[1] == ':') /* skip "x:" */
+- p += 2;
+- #endif
+-
+- if (vim_ispathsep(*p))
+- {
+- relative = FALSE;
+- do
+- ++p;
+- while (vim_ispathsep(*p));
+- }
+- start = p; /* remember start after "c:/" or "/" or "///" */
+-
+- do
+- {
+- /* At this point "p" is pointing to the char following a single "/"
+- * or "p" is at the "start" of the (absolute or relative) path name. */
+- #ifdef VMS
+- /* VMS allows device:[path] - don't strip the [ in directory */
+- if ((*p == '[' || *p == '<') && p > filename && p[-1] == ':')
+- {
+- /* :[ or :< composition: vms directory component */
+- ++components;
+- p = getnextcomp(p + 1);
+- }
+- /* allow remote calls as host"user passwd"::device:[path] */
+- else if (p[0] == ':' && p[1] == ':' && p > filename && p[-1] == '"' )
+- {
+- /* ":: composition: vms host/passwd component */
+- ++components;
+- p = getnextcomp(p + 2);
+- }
+- else
+- #endif
+- if (vim_ispathsep(*p))
+- STRMOVE(p, p + 1); /* remove duplicate "/" */
+- else if (p[0] == '.' && (vim_ispathsep(p[1]) || p[1] == NUL))
+- {
+- if (p == start && relative)
+- p += 1 + (p[1] != NUL); /* keep single "." or leading "./" */
+- else
+- {
+- /* Strip "./" or ".///". If we are at the end of the file name
+- * and there is no trailing path separator, either strip "/." if
+- * we are after "start", or strip "." if we are at the beginning
+- * of an absolute path name . */
+- tail = p + 1;
+- if (p[1] != NUL)
+- while (vim_ispathsep(*tail))
+- MB_PTR_ADV(tail);
+- else if (p > start)
+- --p; /* strip preceding path separator */
+- STRMOVE(p, tail);
+- }
+- }
+- else if (p[0] == '.' && p[1] == '.' &&
+- (vim_ispathsep(p[2]) || p[2] == NUL))
+- {
+- /* Skip to after ".." or "../" or "..///". */
+- tail = p + 2;
+- while (vim_ispathsep(*tail))
+- MB_PTR_ADV(tail);
+-
+- if (components > 0) /* strip one preceding component */
+- {
+- int do_strip = FALSE;
+- char_u saved_char;
+- stat_T st;
+-
+- /* Don't strip for an erroneous file name. */
+- if (!stripping_disabled)
+- {
+- /* If the preceding component does not exist in the file
+- * system, we strip it. On Unix, we don't accept a symbolic
+- * link that refers to a non-existent file. */
+- saved_char = p[-1];
+- p[-1] = NUL;
+- #ifdef UNIX
+- if (mch_lstat((char *)filename, &st) < 0)
+- #else
+- if (mch_stat((char *)filename, &st) < 0)
+- #endif
+- do_strip = TRUE;
+- p[-1] = saved_char;
+-
+- --p;
+- /* Skip back to after previous '/'. */
+- while (p > start && !after_pathsep(start, p))
+- MB_PTR_BACK(start, p);
+-
+- if (!do_strip)
+- {
+- /* If the component exists in the file system, check
+- * that stripping it won't change the meaning of the
+- * file name. First get information about the
+- * unstripped file name. This may fail if the component
+- * to strip is not a searchable directory (but a regular
+- * file, for instance), since the trailing "/.." cannot
+- * be applied then. We don't strip it then since we
+- * don't want to replace an erroneous file name by
+- * a valid one, and we disable stripping of later
+- * components. */
+- saved_char = *tail;
+- *tail = NUL;
+- if (mch_stat((char *)filename, &st) >= 0)
+- do_strip = TRUE;
+- else
+- stripping_disabled = TRUE;
+- *tail = saved_char;
+- #ifdef UNIX
+- if (do_strip)
+- {
+- stat_T new_st;
+-
+- /* On Unix, the check for the unstripped file name
+- * above works also for a symbolic link pointing to
+- * a searchable directory. But then the parent of
+- * the directory pointed to by the link must be the
+- * same as the stripped file name. (The latter
+- * exists in the file system since it is the
+- * component's parent directory.) */
+- if (p == start && relative)
+- (void)mch_stat(".", &new_st);
+- else
+- {
+- saved_char = *p;
+- *p = NUL;
+- (void)mch_stat((char *)filename, &new_st);
+- *p = saved_char;
+- }
+-
+- if (new_st.st_ino != st.st_ino ||
+- new_st.st_dev != st.st_dev)
+- {
+- do_strip = FALSE;
+- /* We don't disable stripping of later
+- * components since the unstripped path name is
+- * still valid. */
+- }
+- }
+- #endif
+- }
+- }
+-
+- if (!do_strip)
+- {
+- /* Skip the ".." or "../" and reset the counter for the
+- * components that might be stripped later on. */
+- p = tail;
+- components = 0;
+- }
+- else
+- {
+- /* Strip previous component. If the result would get empty
+- * and there is no trailing path separator, leave a single
+- * "." instead. If we are at the end of the file name and
+- * there is no trailing path separator and a preceding
+- * component is left after stripping, strip its trailing
+- * path separator as well. */
+- if (p == start && relative && tail[-1] == '.')
+- {
+- *p++ = '.';
+- *p = NUL;
+- }
+- else
+- {
+- if (p > start && tail[-1] == '.')
+- --p;
+- STRMOVE(p, tail); /* strip previous component */
+- }
+-
+- --components;
+- }
+- }
+- else if (p == start && !relative) /* leading "/.." or "/../" */
+- STRMOVE(p, tail); /* strip ".." or "../" */
+- else
+- {
+- if (p == start + 2 && p[-2] == '.') /* leading "./../" */
+- {
+- STRMOVE(p - 2, p); /* strip leading "./" */
+- tail -= 2;
+- }
+- p = tail; /* skip to char after ".." or "../" */
+- }
+- }
+- else
+- {
+- ++components; /* simple path component */
+- p = getnextcomp(p);
+- }
+- } while (*p != NUL);
+- #endif /* !AMIGA */
+- }
+-
+- /*
+ * Check if we have a tag for the buffer with name "buf_ffname".
+ * This is a bit slow, because of the full path compare in fullpathcmp().
+ * Return TRUE if tag for file "fname" if tag file "tag_fname" is for current
+--- 3453,3458 ----
+*** ../vim-8.1.1098/src/proto/tag.pro 2018-11-11 15:20:32.436704418 +0100
+--- src/proto/tag.pro 2019-03-31 19:09:23.798893253 +0200
+***************
+*** 6,12 ****
+ void free_tag_stuff(void);
+ int get_tagfname(tagname_T *tnp, int first, char_u *buf);
+ void tagname_free(tagname_T *tnp);
+- void simplify_filename(char_u *filename);
+ int expand_tags(int tagnames, char_u *pat, int *num_file, char_u ***file);
+ int get_tags(list_T *list, char_u *pat, char_u *buf_fname);
+ void get_tagstack(win_T *wp, dict_T *retdict);
+--- 6,11 ----
+*** ../vim-8.1.1098/src/findfile.c 2019-03-09 12:32:50.673562149 +0100
+--- src/findfile.c 2019-03-31 19:09:15.586959263 +0200
+***************
+*** 2605,2607 ****
+--- 2605,2819 ----
+ }
+
+ #endif // FEAT_SEARCHPATH
++
++ /*
++ * Converts a file name into a canonical form. It simplifies a file name into
++ * its simplest form by stripping out unneeded components, if any. The
++ * resulting file name is simplified in place and will either be the same
++ * length as that supplied, or shorter.
++ */
++ void
++ simplify_filename(char_u *filename)
++ {
++ #ifndef AMIGA // Amiga doesn't have "..", it uses "/"
++ int components = 0;
++ char_u *p, *tail, *start;
++ int stripping_disabled = FALSE;
++ int relative = TRUE;
++
++ p = filename;
++ # ifdef BACKSLASH_IN_FILENAME
++ if (p[1] == ':') // skip "x:"
++ p += 2;
++ # endif
++
++ if (vim_ispathsep(*p))
++ {
++ relative = FALSE;
++ do
++ ++p;
++ while (vim_ispathsep(*p));
++ }
++ start = p; // remember start after "c:/" or "/" or "///"
++
++ do
++ {
++ // At this point "p" is pointing to the char following a single "/"
++ // or "p" is at the "start" of the (absolute or relative) path name.
++ # ifdef VMS
++ // VMS allows device:[path] - don't strip the [ in directory
++ if ((*p == '[' || *p == '<') && p > filename && p[-1] == ':')
++ {
++ // :[ or :< composition: vms directory component
++ ++components;
++ p = getnextcomp(p + 1);
++ }
++ // allow remote calls as host"user passwd"::device:[path]
++ else if (p[0] == ':' && p[1] == ':' && p > filename && p[-1] == '"' )
++ {
++ // ":: composition: vms host/passwd component
++ ++components;
++ p = getnextcomp(p + 2);
++ }
++ else
++ # endif
++ if (vim_ispathsep(*p))
++ STRMOVE(p, p + 1); // remove duplicate "/"
++ else if (p[0] == '.' && (vim_ispathsep(p[1]) || p[1] == NUL))
++ {
++ if (p == start && relative)
++ p += 1 + (p[1] != NUL); // keep single "." or leading "./"
++ else
++ {
++ // Strip "./" or ".///". If we are at the end of the file name
++ // and there is no trailing path separator, either strip "/." if
++ // we are after "start", or strip "." if we are at the beginning
++ // of an absolute path name .
++ tail = p + 1;
++ if (p[1] != NUL)
++ while (vim_ispathsep(*tail))
++ MB_PTR_ADV(tail);
++ else if (p > start)
++ --p; // strip preceding path separator
++ STRMOVE(p, tail);
++ }
++ }
++ else if (p[0] == '.' && p[1] == '.' &&
++ (vim_ispathsep(p[2]) || p[2] == NUL))
++ {
++ // Skip to after ".." or "../" or "..///".
++ tail = p + 2;
++ while (vim_ispathsep(*tail))
++ MB_PTR_ADV(tail);
++
++ if (components > 0) // strip one preceding component
++ {
++ int do_strip = FALSE;
++ char_u saved_char;
++ stat_T st;
++
++ /* Don't strip for an erroneous file name. */
++ if (!stripping_disabled)
++ {
++ // If the preceding component does not exist in the file
++ // system, we strip it. On Unix, we don't accept a symbolic
++ // link that refers to a non-existent file.
++ saved_char = p[-1];
++ p[-1] = NUL;
++ # ifdef UNIX
++ if (mch_lstat((char *)filename, &st) < 0)
++ # else
++ if (mch_stat((char *)filename, &st) < 0)
++ # endif
++ do_strip = TRUE;
++ p[-1] = saved_char;
++
++ --p;
++ // Skip back to after previous '/'.
++ while (p > start && !after_pathsep(start, p))
++ MB_PTR_BACK(start, p);
++
++ if (!do_strip)
++ {
++ // If the component exists in the file system, check
++ // that stripping it won't change the meaning of the
++ // file name. First get information about the
++ // unstripped file name. This may fail if the component
++ // to strip is not a searchable directory (but a regular
++ // file, for instance), since the trailing "/.." cannot
++ // be applied then. We don't strip it then since we
++ // don't want to replace an erroneous file name by
++ // a valid one, and we disable stripping of later
++ // components.
++ saved_char = *tail;
++ *tail = NUL;
++ if (mch_stat((char *)filename, &st) >= 0)
++ do_strip = TRUE;
++ else
++ stripping_disabled = TRUE;
++ *tail = saved_char;
++ # ifdef UNIX
++ if (do_strip)
++ {
++ stat_T new_st;
++
++ // On Unix, the check for the unstripped file name
++ // above works also for a symbolic link pointing to
++ // a searchable directory. But then the parent of
++ // the directory pointed to by the link must be the
++ // same as the stripped file name. (The latter
++ // exists in the file system since it is the
++ // component's parent directory.)
++ if (p == start && relative)
++ (void)mch_stat(".", &new_st);
++ else
++ {
++ saved_char = *p;
++ *p = NUL;
++ (void)mch_stat((char *)filename, &new_st);
++ *p = saved_char;
++ }
++
++ if (new_st.st_ino != st.st_ino ||
++ new_st.st_dev != st.st_dev)
++ {
++ do_strip = FALSE;
++ // We don't disable stripping of later
++ // components since the unstripped path name is
++ // still valid.
++ }
++ }
++ # endif
++ }
++ }
++
++ if (!do_strip)
++ {
++ // Skip the ".." or "../" and reset the counter for the
++ // components that might be stripped later on.
++ p = tail;
++ components = 0;
++ }
++ else
++ {
++ // Strip previous component. If the result would get empty
++ // and there is no trailing path separator, leave a single
++ // "." instead. If we are at the end of the file name and
++ // there is no trailing path separator and a preceding
++ // component is left after stripping, strip its trailing
++ // path separator as well.
++ if (p == start && relative && tail[-1] == '.')
++ {
++ *p++ = '.';
++ *p = NUL;
++ }
++ else
++ {
++ if (p > start && tail[-1] == '.')
++ --p;
++ STRMOVE(p, tail); // strip previous component
++ }
++
++ --components;
++ }
++ }
++ else if (p == start && !relative) // leading "/.." or "/../"
++ STRMOVE(p, tail); // strip ".." or "../"
++ else
++ {
++ if (p == start + 2 && p[-2] == '.') // leading "./../"
++ {
++ STRMOVE(p - 2, p); // strip leading "./"
++ tail -= 2;
++ }
++ p = tail; // skip to char after ".." or "../"
++ }
++ }
++ else
++ {
++ ++components; // simple path component
++ p = getnextcomp(p);
++ }
++ } while (*p != NUL);
++ #endif // !AMIGA
++ }
+*** ../vim-8.1.1098/src/proto/findfile.pro 2019-02-13 22:45:21.512636158 +0100
+--- src/proto/findfile.pro 2019-03-31 19:09:20.870916772 +0200
+***************
+*** 15,18 ****
+--- 15,19 ----
+ int vim_ispathlistsep(int c);
+ void uniquefy_paths(garray_T *gap, char_u *pattern);
+ int expand_in_path(garray_T *gap, char_u *pattern, int flags);
++ void simplify_filename(char_u *filename);
+ /* vim: set ft=c : */
+*** ../vim-8.1.1098/src/version.c 2019-03-31 15:31:54.592053004 +0200
+--- src/version.c 2019-03-31 19:39:26.094371299 +0200
+***************
+*** 773,774 ****
+--- 773,776 ----
+ { /* Add new patch number below this line */
++ /**/
++ 1099,
+ /**/
+
+--
+hundred-and-one symptoms of being an internet addict:
+175. You send yourself e-mail before you go to bed to remind you
+ what to do when you wake up.
+
+ /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
+/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
+\\\ an exciting new programming language -- http://www.Zimbu.org ///
+ \\\ help me help AIDS victims -- http://ICCF-Holland.org ///