Loading ...
Sorry, an error occurred while loading the content.
 

RE: Patch 6.2.299

Expand Messages
  • Bram Moolenaar
    ... Hmm, I thought (hoped) that wildcards without a match would be ignored silently. Somehow I have been testing this in a wrong way. Ignoring the ls
    Message 1 of 10 , Mar 1, 2004
      Servatius Brandt wrote:

      > After adding patch 6.2.299 "make install" fails. I have just added the
      > patch, but not downloaded any new runtime files, so there are no *.??x
      > and tags-?? files in runtime/doc. The following patch fixes the
      > problem:

      Hmm, I thought (hoped) that wildcards without a match would be ignored
      silently. Somehow I have been testing this in a wrong way.

      Ignoring the "ls" failing completely looks a bit dangerous to me.
      Isn't there a simple and portable way to add files with wildcard
      expansion optionally?

      One solution could be to expand "*.txt" like before, and add "*.??x
      tags-??" while ignoring errors. This seems to work, but I wonder if
      there is a simpler way:

      cd $(HELPSOURCE); \
      files=`ls *.txt tags`; \
      (files="$$files `ls *.??x tags-?? 2>/dev/null || true`"); \
      $(INSTALL_DATA) $$files $(DEST_HELP); \
      cd $(DEST_HELP); \
      chmod $(HELPMOD) $$files

      --
      Futility Factor: No experiment is ever a complete failure - it can always
      serve as a negative example.

      /// Bram Moolenaar -- Bram@... -- http://www.Moolenaar.net \\\
      /// Sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
      \\\ Project leader for A-A-P -- http://www.A-A-P.org ///
      \\\ Buy at Amazon and help AIDS victims -- http://ICCF.nl/click1.html ///
    • Brandt, Servatius
      ... true` ); ... doesn t ... ksh leaves @(notexistent) unchanged, it doesn t replace it by nothing: this is the same as for sh when a pattern does not
      Message 2 of 10 , Mar 1, 2004
        Bram Moolenaar wrote:

        > Servatius Brandt wrote:
        >
        > > Bram Moolenaar wrote:
        > >
        > > > cd $(HELPSOURCE); \
        > > > files=`ls *.txt tags`; \
        > > > (files="$$files `ls *.??x tags-?? 2>/dev/null ||
        true`"); \
        > > > $(INSTALL_DATA) $$files $(DEST_HELP); \
        > > > cd $(DEST_HELP); \
        > > > chmod $(HELPMOD) $$files
        > >
        > > With KornShell or bash it would be possible to use
        > >
        > > `echo @(*.txt|tags|*.??x|tags-??)`
        > >
        > > but you could also use the find command inside the backquotes.
        >
        > We need a solution that works with every sh-like shell. My "sh"
        doesn't
        > support @().

        "ksh" leaves "@(notexistent)" unchanged, it doesn't replace it by
        nothing: this is the same as for "sh" when a pattern does not match.
        The trick with @(...) above was that the pattern matches because there
        are matching subpatterns, so that the complete pattern is replaced by
        the match, which makes all the non-matching patterns disappear.

        I don't think that the "sh" file patterns are capable enough to build
        a single pattern argument for all four file types. Hmm, you could use
        a two-pattern version:

        `ls *.??[xt] tags*`

        This catches all of "*.txt", "tags", "*.??x" and "tags-??", and does not
        fail if no "*.??x" or "tags-??" files are present. But it is not
        readable very well, and it matches also "tags.rej" or "tags.~1~".
        Trying to fix this would make readability even worse.

        > Would using "find" be less complicated than using "ls"?

        Not really. You could get rid of the "2 > /dev/null || true", and you
        would only need one command setting "files". But this "find" command
        would need four well-escaped "-name" arguments and get a bit longer.

        I don't think we'll be able to find a really simpler solution than what
        you suggested.

        - Servatius
      • Bram Moolenaar
        ... Great. My French is very rusty, but I ll install them to try it out. I must say I m impressed by the effort to translate all the help files. I never
        Message 3 of 10 , Mar 2, 2004
          David Odin wrote:

          > > The best solution is when I setup a page on www.vim.org with links to
          > > the available translation packages. To keep this organized a bit, let's
          > > agree on what a package contains and what archives are used.
          > >
          > > Contents:
          > > README_??.txt info about the translation
          > > doc/*.??x translated help files
          > > doc/tags-?? tags file
          > > lang/menu_*.vim menu translations (optional)
          > > keymap/*.vim keymaps (optional)
          > >
          > OK. I have done this for the french translation. You can find it here:
          > http://vim.dindinx.net/vimhelp-fr.tar.bz2

          Great. My French is very rusty, but I'll install them to try it out.

          I must say I'm impressed by the effort to translate all the help files.
          I never thought this huge task would be accomplished.


          A few remarks:
          - Please don't include "doc/Makefile", because this is a file from the
          base distribution. You could rename it to "Make_fr.mak".
          - The "tags-fr" you included points to *.txt files instead of the *.frx
          files. ":helptags ~/.vim/doc" fixed that.

          > I've chosen the name of the archive to be vimhelp-??, but I can easily
          > change it if you want. Since I do not coordinate the translation of the
          > menu or keymap french translation, I haven't included these files.

          I expect more archives to appear sooner or later. To allow the right
          person to update this information I would prefer to put one link on
          www.vim.org to a site that has a page on the French documentation and
          translations. Currently that would be a simple link to the tar archive,
          later you can add more. This avoids that you have to ask me every time
          a link has to be added or changed.

          Perhaps a version number should be included?

          > I don't have the tools to builds .zip or .exe files. So, I would
          > greatly appreciate if someone could build them for me.

          Don't you have a "zip" command for Unix? It's available in many places
          and very useful.

          --
          LAUNCELOT: I am, sir. I am a Knight of King Arthur.
          FATHER: 'Mm ... very nice castle, Camelot ... very good pig country....
          "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

          /// Bram Moolenaar -- Bram@... -- http://www.Moolenaar.net \\\
          /// Sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
          \\\ Project leader for A-A-P -- http://www.A-A-P.org ///
          \\\ Buy at Amazon and help AIDS victims -- http://ICCF.nl/click1.html ///
        • Gordon Prieur
          Bram, I ve found several problems with this patch related to the VIMEXE make variable. First off, you have: -@cd $(HELPSOURCE); VIMEXE=$(VIMTARGET) $(MAKE)
          Message 4 of 10 , Mar 16, 2004
            Bram,

            I've found several problems with this patch related to the VIMEXE make
            variable. First off, you have:

            -@cd $(HELPSOURCE); VIMEXE=$(VIMTARGET) $(MAKE) vimtags

            At least with Solaris' make, setting VIMEXE in the environment doesn't
            superscede the VIMEXE=vim in $HELPSOURCE/Makefile, so your aren't
            overriding the default. Thats OK on my system, but my release engineering
            group has a vim 5.3 version in their path so it fails. What you (probably)
            want is something like:

            -@cd $(HELPSOURCE); $(MAKE) VIMEXE=../../src/$(VIMTARGET) vimtag

            It passes VIMEXE as a make variable, which does override the default in
            $HELPSOURCE/Makefile. It also passes in the vim you just built, so it
            doesn't look in your path for vim.

            Gordon


            Bram Moolenaar wrote:

            >Patch 6.2.299
            >Problem: Can only use one language for help files.
            >Solution: Add the 'helplang' option to select the preferred language(s).
            > Make ":helptags" generate tags files for all languages.
            >Files: runtime/doc/options.txt, runtime/doc/various.txt, src/Makefile,
            > src/ex_cmds.c, src/ex_cmds2.c, src/ex_cmds.h, src/ex_getln.c,
            > src/normal.c, src/option.c, src/option.h, src/proto/ex_cmds.pro,
            > src/proto/ex_cmds2.pro, src/proto/option.pro, src/structs.h,
            > src/tag.c, src/vim.h
            >
            >
            >*** ../vim-6.2.298/runtime/doc/options.txt Sun Jan 25 20:42:15 2004
            >--- runtime/doc/options.txt Tue Feb 24 19:52:50 2004
            >***************
            >*** 1,4 ****
            >! *options.txt* For Vim version 6.2. Last change: 2004 Jan 22
            >
            >
            > VIM REFERENCE MANUAL by Bram Moolenaar
            >--- 1,4 ----
            >! *options.txt* For Vim version 6.2. Last change: 2004 Feb 24
            >
            >
            > VIM REFERENCE MANUAL by Bram Moolenaar
            >***************
            >*** 2991,2996 ****
            >--- 3008,3032 ----
            > windows. When the height is less than 'helpheight', the height is
            > set to 'helpheight'. Set to zero to disable.
            >
            >+ *'helplang'* *'hlg'*
            >+ 'helplang' 'hlg' string (default: messages language or emtpy)
            >+ global
            >+ {only available when compiled with the |+multi_lang|
            >+ feature}
            >+ {not in Vi}
            >+ Comma separated list of languages. Vim will use the first language
            >+ for which the desired help can be found. The English help will always
            >+ be used as a last resort. You can add "en" to prefer English over
            >+ another language, but that will only find tags that exist in that
            >+ language and not in the English help.
            >+ Example: >
            >+ :set helplang=de,it
            >+ < This will first search German, then Italian and finally English help
            >+ files.
            >+ When using |CTRL-]| and ":help!" in a non-English help file Vim will
            >+ try to find the tag in the current language before using this option.
            >+ See |help-translated|.
            >+
            > *'hidden'* *'hid'* *'nohidden'* *'nohid'*
            > 'hidden' 'hid' boolean (default off)
            > global
            >*** ../vim-6.2.298/runtime/doc/various.txt Sun Jan 25 19:32:46 2004
            >--- runtime/doc/various.txt Tue Feb 24 19:53:44 2004
            >***************
            >*** 1,4 ****
            >! *various.txt* For Vim version 6.2. Last change: 2004 Jan 21
            >
            >
            > VIM REFERENCE MANUAL by Bram Moolenaar
            >--- 1,4 ----
            >! *various.txt* For Vim version 6.2. Last change: 2004 Feb 24
            >
            >
            > VIM REFERENCE MANUAL by Bram Moolenaar
            >***************
            >*** 507,515 ****
            > wide, the help window will appear just above the
            > current window. Otherwise the new window is put at
            > the very top.
            > {not in Vi}
            >
            >! *{subject}* *E149*
            > :h[elp] {subject} Like ":help", additionally jump to the tag {subject}.
            > {subject} can include wildcards like "*", "?" and
            > "[a-z]":
            >--- 507,517 ----
            > wide, the help window will appear just above the
            > current window. Otherwise the new window is put at
            > the very top.
            >+ The 'helplang' option is used to select a language, if
            >+ the main help file is available in several languages.
            > {not in Vi}
            >
            >! *{subject}* *E149* *E661*
            > :h[elp] {subject} Like ":help", additionally jump to the tag {subject}.
            > {subject} can include wildcards like "*", "?" and
            > "[a-z]":
            >***************
            >*** 529,534 ****
            >--- 531,543 ----
            > better than a match further on.
            > - The more alphanumeric characters match, the better.
            > - The shorter the length of the match, the better.
            >+
            >+ The 'helplang' option is used to select a language, if
            >+ the {subject} is available in several languages.
            >+ To find a tag in a specific language, append '@ab",
            >+ where "ab" is the two-letter language code. See
            >+ |help-translated|.
            >+
            > Note that the longer the {subject} you give, the less
            > matches will be found. You can get an idea how this
            > all works by using commandline completion (type CTRL-D
            >***************
            >*** 554,559 ****
            >--- 563,572 ----
            > :help so<C-V><CR>only
            > < {not in Vi}
            >
            >+ :h[elp]! [subject] Like ":help", but in non-English help files prefer to
            >+ find a tag in a file with the same language as the
            >+ current file. See |help-translated|.
            >+
            > *:helpg* *:helpgrep*
            > :helpg[rep] {pattern}
            > Search all help text files and make a list of lines
            >***************
            >*** 610,632 ****
            >
            > *help-xterm-window*
            > If you want to have the help in another xterm window, you could use this
            >! command:
            > :!xterm -e vim +help &
            >!
            >
            > *:helpfind* *:helpf*
            > :helpf[ind] Like |:help|, but use a dialog to enter the argument.
            >! Only for backwards compatibilty. It now executes the
            >! ToolBar.HelpFind menu entry instead of using a builtin
            > dialog. {only when compiled with |+GUI_GTK|}
            >
            >! *:helpt* *:helptags* *E154* *E150* *E151* *E152* *E153*
            >! :helpt[ags] {dir} Generate the help tags file for directory {dir}. All
            >! "*.txt" files in the directory are scanned for a help
            >! tag definition in between stars. The generated tags
            >! file is sorted. When there are duplicates an error
            >! message is given. An existing tags file is silently
            >! overwritten.
            >
            > ==============================================================================
            > 3. Printing *printing*
            >--- 623,702 ----
            >
            > *help-xterm-window*
            > If you want to have the help in another xterm window, you could use this
            >! command: >
            > :!xterm -e vim +help &
            >! <
            >
            > *:helpfind* *:helpf*
            > :helpf[ind] Like |:help|, but use a dialog to enter the argument.
            >! Only for backwards compatibility. It now executes the
            >! ToolBar.FindHelp menu entry instead of using a builtin
            > dialog. {only when compiled with |+GUI_GTK|}
            >
            >! *:helpt* *:helptags*
            >! *E154* *E150* *E151* *E152* *E153*
            >! :helpt[ags] {dir} Generate the help tags file(s) for directory {dir}.
            >! All "*.txt" and "*.??x" files in the directory are
            >! scanned for a help tag definition in between stars.
            >! The "*.??x" files are for translated docs, they
            >! generate the "tags-??" file, see |help-translated|.
            >! The generated tags files are sorted.
            >! When there are duplicates an error message is given.
            >! An existing tags file is silently overwritten.
            >! To rebuild the help tags in the runtime directory
            >! (requires write permission there): >
            >! :helptags $VIMRUNTIME/doc
            >!
            >!
            >! TRANSLATED HELP *help-translated*
            >!
            >! It is possible to add translated help files, next to the original English help
            >! files. Vim will search for all help in "doc" directories in 'runtimepath'.
            >! This is only available when compiled with the |+multi_lang| feature.
            >!
            >! A set of translated help files consists of these files:
            >!
            >! help.abx
            >! howto.abx
            >! ...
            >! tags-ab
            >!
            >! "ab" is the two-letter language code. Thus for Italian the names are:
            >!
            >! help.itx
            >! howto.itx
            >! ...
            >! tags-it
            >!
            >! The 'helplang' option can be set to the preferred language(s). The default is
            >! set according to the environment. Vim will first try to find a matching tag
            >! in the preferred language(s). English is used when it cannot be found.
            >!
            >! To find a tag in a specific language, append "@ab" to a tag, where "ab" is the
            >! two-letter language code. Example: >
            >! :he user-manual@it
            >! :he user-manual@en
            >! The first one finds the Italian user manual, even when 'helplang' is empty.
            >! The second one finds the English user manual, even when 'helplang' is set to
            >! "it".
            >!
            >! When using command-line completion for the ":help" command, the "@en"
            >! extention is only shown when a tag exists for multiple languages. When the
            >! tag only exists for English "@en" is omitted.
            >!
            >! When using |CTRL-]| or ":help!" in a non-English help file Vim will try to
            >! find the tag in the same language. If not found then 'helplang' will be used
            >! to select a language.
            >!
            >! Hints for translators:
            >! - Do not translate the tags. This makes it possible to use 'helplang' to
            >! specify the preferred language.
            >! - When you do not translate a part of a file, add tags to the English version,
            >! using the "tag@en" notation.
            >! - Make a package with all the files and the tags file available for download.
            >! Users can drop it in one of the "doc" directories and start use it.
            >! - Use the |:helptags| command to generate the tags files. It will find all
            >! languages in the specified directory.
            >
            > ==============================================================================
            > 3. Printing *printing*
            >*** ../vim-6.2.298/src/Makefile Thu Feb 19 14:48:06 2004
            >--- src/Makefile Sat Feb 28 17:09:19 2004
            >***************
            >*** 1654,1662 ****
            > $(HELPSOURCE)/evim.1 > $(DEST_MAN)/$(EVIMNAME).1
            > chmod $(MANMOD) $(DEST_MAN)/$(EVIMNAME).1
            > @echo generating help tags
            >! -@cd $(HELPSOURCE); $(MAKE) tags
            >! cd $(HELPSOURCE); $(INSTALL_DATA) *.txt tags $(DEST_HELP)
            >! cd $(DEST_HELP); chmod $(HELPMOD) *.txt tags
            > $(INSTALL_DATA) $(HELPSOURCE)/*.pl $(DEST_HELP)
            > chmod $(SCRIPTMOD) $(DEST_HELP)/*.pl
            > # install the menu files
            >--- 1664,1676 ----
            > $(HELPSOURCE)/evim.1 > $(DEST_MAN)/$(EVIMNAME).1
            > chmod $(MANMOD) $(DEST_MAN)/$(EVIMNAME).1
            > @echo generating help tags
            >! # Generate the help tags with ":helptags" to handle all languages.
            >! -@cd $(HELPSOURCE); VIMEXE=$(VIMTARGET) $(MAKE) vimtags
            >! cd $(HELPSOURCE); \
            >! files=`ls *.txt *.??x tags tags-??`; \
            >! $(INSTALL_DATA) $$files $(DEST_HELP); \
            >! cd $(DEST_HELP); \
            >! chmod $(HELPMOD) $$files
            > $(INSTALL_DATA) $(HELPSOURCE)/*.pl $(DEST_HELP)
            > chmod $(SCRIPTMOD) $(DEST_HELP)/*.pl
            > # install the menu files
            >***************
            >*** 1932,1937 ****
            >--- 1946,1952 ----
            > # Note: the "rmdir" will fail if any files were added after "make install"
            > uninstall_runtime:
            > -rm -f $(DEST_HELP)/*.txt $(DEST_HELP)/tags $(DEST_HELP)/*.pl
            >+ -rm -f $(DEST_HELP)/*.??x $(DEST_HELP)/tags-??
            > -rm -f $(SYS_MENU_FILE) $(SYS_SYNMENU_FILE) $(SYS_DELMENU_FILE)
            > -rm -f $(SYS_BUGR_FILE) $(EVIM_FILE) $(MSWIN_FILE)
            > -rm -f $(DEST_SCRIPT)/gvimrc_example.vim $(DEST_SCRIPT)/vimrc_example.vim
            >*** ../vim-6.2.298/src/ex_cmds.c Fri Feb 20 22:08:18 2004
            >--- src/ex_cmds.c Sun Feb 29 17:06:24 2004
            >***************
            >*** 4533,4550 ****
            > exarg_T *eap;
            > {
            > char_u *arg;
            > FILE *helpfd; /* file descriptor of help file */
            > int n;
            > #ifdef FEAT_WINDOWS
            > win_T *wp;
            > #endif
            > int num_matches;
            > char_u **matches;
            >- int need_free = FALSE;
            > char_u *p;
            > int empty_fnum = 0;
            > int alt_fnum = 0;
            > buf_T *buf;
            >
            > if (eap != NULL)
            > {
            >--- 4533,4555 ----
            > exarg_T *eap;
            > {
            > char_u *arg;
            >+ char_u *tag;
            > FILE *helpfd; /* file descriptor of help file */
            > int n;
            >+ int i;
            > #ifdef FEAT_WINDOWS
            > win_T *wp;
            > #endif
            > int num_matches;
            > char_u **matches;
            > char_u *p;
            > int empty_fnum = 0;
            > int alt_fnum = 0;
            > buf_T *buf;
            >+ #ifdef FEAT_MULTI_LANG
            >+ int len;
            >+ char_u *lang = NULL;
            >+ #endif
            >
            > if (eap != NULL)
            > {
            >***************
            >*** 4564,4598 ****
            > }
            > arg = eap->arg;
            >
            > if (eap->skip) /* not executing commands */
            > return;
            > }
            > else
            > arg = (char_u *)"";
            >
            > /*
            >! * If an argument is given, check if there is a match for it.
            > */
            >! if (*arg != NUL)
            >! {
            >! /* remove trailing blanks */
            >! p = arg + STRLEN(arg) - 1;
            >! while (p > arg && vim_iswhite(*p) && p[-1] != '\\')
            >! *p-- = NUL;
            >
            >! n = find_help_tags(arg, &num_matches, &matches);
            >! if (num_matches == 0 || n == FAIL)
            >! {
            >! EMSG2(_("E149: Sorry, no help for %s"), arg);
            >! return;
            > }
            >!
            >! /* The first match is the best match. */
            >! arg = vim_strsave(matches[0]);
            >! need_free = TRUE;
            >! FreeWild(num_matches, matches);
            > }
            >
            > #ifdef FEAT_GUI
            > need_mouse_correct = TRUE;
            > #endif
            >--- 4569,4639 ----
            > }
            > arg = eap->arg;
            >
            >+ if (eap->forceit && *arg == NUL)
            >+ {
            >+ EMSG(_("E478: Don't panic!"));
            >+ return;
            >+ }
            >+
            > if (eap->skip) /* not executing commands */
            > return;
            > }
            > else
            > arg = (char_u *)"";
            >
            >+ /* remove trailing blanks */
            >+ p = arg + STRLEN(arg) - 1;
            >+ while (p > arg && vim_iswhite(*p) && p[-1] != '\\')
            >+ *p-- = NUL;
            >+
            >+ #ifdef FEAT_MULTI_LANG
            >+ /* Check for a specified language */
            >+ len = STRLEN(arg);
            >+ if (len >= 3 && arg[len - 3] == '@' && ASCII_ISALPHA(arg[len - 2])
            >+ && ASCII_ISALPHA(arg[len - 1]))
            >+ {
            >+ lang = arg + len - 2;
            >+ lang[-1] = NUL; /* remove the '@' */
            >+ }
            >+ #endif
            >+
            >+ /* When no argument given go to the index. */
            >+ if (*arg == NUL)
            >+ arg = (char_u *)"help.txt";
            >+
            > /*
            >! * Check if there is a match for the argument.
            > */
            >! n = find_help_tags(arg, &num_matches, &matches,
            >! eap != NULL && eap->forceit);
            >
            >! i = 0;
            >! #ifdef FEAT_MULTI_LANG
            >! if (n != FAIL && lang != NULL)
            >! /* Find first item with the requested language. */
            >! for (i = 0; i < num_matches; ++i)
            >! {
            >! len = STRLEN(matches[i]);
            >! if (len > 3 && matches[i][len - 3] == '@'
            >! && STRICMP(matches[i] + len - 2, lang) == 0)
            >! break;
            > }
            >! #endif
            >! if (i >= num_matches || n == FAIL)
            >! {
            >! #ifdef FEAT_MULTI_LANG
            >! if (lang != NULL)
            >! EMSG3(_("E661: Sorry, no '%s' help for %s"), lang, arg);
            >! else
            >! #endif
            >! EMSG2(_("E149: Sorry, no help for %s"), arg);
            >! return;
            > }
            >
            >+ /* The first match (in the requested language) is the best match. */
            >+ tag = vim_strsave(matches[i]);
            >+ FreeWild(num_matches, matches);
            >+
            > #ifdef FEAT_GUI
            > need_mouse_correct = TRUE;
            > #endif
            >***************
            >*** 4660,4671 ****
            > if (!p_im)
            > restart_edit = 0; /* don't want insert mode in help file */
            >
            >! if (arg == NULL || *arg == NUL)
            >! {
            >! arg = (char_u *)"help.txt"; /* go to the index */
            >! need_free = FALSE;
            >! }
            >! do_tag(arg, DT_HELP, 1, FALSE, TRUE);
            >
            > /* Delete the empty buffer if we're not using it. */
            > if (empty_fnum != 0 && curbuf->b_fnum != empty_fnum)
            >--- 4701,4708 ----
            > if (!p_im)
            > restart_edit = 0; /* don't want insert mode in help file */
            >
            >! if (tag != NULL)
            >! do_tag(tag, DT_HELP, 1, FALSE, TRUE);
            >
            > /* Delete the empty buffer if we're not using it. */
            > if (empty_fnum != 0 && curbuf->b_fnum != empty_fnum)
            >***************
            >*** 4680,4687 ****
            > curwin->w_alt_fnum = alt_fnum;
            >
            > erret:
            >! if (need_free)
            >! vim_free(arg);
            > }
            >
            >
            >--- 4717,4723 ----
            > curwin->w_alt_fnum = alt_fnum;
            >
            > erret:
            >! vim_free(tag);
            > }
            >
            >
            >***************
            >*** 4757,4768 ****
            > * Find all help tags matching "arg", sort them and return in matches[], with
            > * the number of matches in num_matches.
            > * The matches will be sorted with a "best" match algorithm.
            > */
            > int
            >! find_help_tags(arg, num_matches, matches)
            > char_u *arg;
            > int *num_matches;
            > char_u ***matches;
            > {
            > char_u *s, *d;
            > int i;
            >--- 4793,4806 ----
            > * Find all help tags matching "arg", sort them and return in matches[], with
            > * the number of matches in num_matches.
            > * The matches will be sorted with a "best" match algorithm.
            >+ * When "keep_lang" is TRUE try keeping the language of the current buffer.
            > */
            > int
            >! find_help_tags(arg, num_matches, matches, keep_lang)
            > char_u *arg;
            > int *num_matches;
            > char_u ***matches;
            >+ int keep_lang;
            > {
            > char_u *s, *d;
            > int i;
            >***************
            >*** 4778,4783 ****
            >--- 4816,4822 ----
            > "/\\\\?", "/\\\\z(\\\\)",
            > "\\[count]", "\\[quotex]", "\\[range]",
            > "\\[pattern]", "\\\\bar", "/\\\\%\\$"};
            >+ int flags;
            >
            > d = IObuff; /* assume IObuff is long enough! */
            >
            >***************
            >*** 4909,4923 ****
            >
            > *matches = (char_u **)"";
            > *num_matches = 0;
            >! if (find_tags(IObuff, num_matches, matches,
            >! TAG_HELP | TAG_REGEXP | TAG_NAMES | TAG_VERBOSE, (int)MAXCOL) == OK)
            >! /*
            >! * Sort the matches found on the heuristic number that is after the
            >! * tag name.
            >! */
            > qsort((void *)*matches, (size_t)*num_matches,
            >! sizeof(char_u *), help_compare)
            >! ;
            > return OK;
            > }
            >
            >--- 4948,4962 ----
            >
            > *matches = (char_u **)"";
            > *num_matches = 0;
            >! flags = TAG_HELP | TAG_REGEXP | TAG_NAMES | TAG_VERBOSE;
            >! if (keep_lang)
            >! flags |= TAG_KEEP_LANG;
            >! if (find_tags(IObuff, num_matches, matches, flags, (int)MAXCOL) == OK
            >! && *num_matches > 0)
            >! /* Sort the matches found on the heuristic number that is after the
            >! * tag name. */
            > qsort((void *)*matches, (size_t)*num_matches,
            >! sizeof(char_u *), help_compare);
            > return OK;
            > }
            >
            >***************
            >*** 5081,5086 ****
            >--- 5120,5127 ----
            > }
            >
            > #if defined(FEAT_EX_EXTRA) || defined(PROTO)
            >+ static void helptags_one __ARGS((char_u *dir, char_u *ext, char_u *lang));
            >+
            > /*
            > * ":helptags"
            > */
            >***************
            >*** 5088,5093 ****
            >--- 5129,5243 ----
            > ex_helptags(eap)
            > exarg_T *eap;
            > {
            >+ garray_T ga;
            >+ int i, j;
            >+ int len;
            >+ char_u lang[2];
            >+ char_u ext[5];
            >+ char_u fname[8];
            >+ int filecount;
            >+ char_u **files;
            >+
            >+ if (!mch_isdir(eap->arg))
            >+ {
            >+ EMSG2(_("E150: Not a directory: %s"), eap->arg);
            >+ return;
            >+ }
            >+
            >+ #ifdef FEAT_MULTI_LANG
            >+ /* Get a list of all files in the directory. */
            >+ STRCPY(NameBuff, eap->arg);
            >+ add_pathsep(NameBuff);
            >+ STRCAT(NameBuff, "*");
            >+ if (gen_expand_wildcards(1, &NameBuff, &filecount, &files,
            >+ EW_FILE|EW_SILENT) == FAIL
            >+ || filecount == 0)
            >+ {
            >+ EMSG2("E151: No match: %s", NameBuff);
            >+ return;
            >+ }
            >+
            >+ /* Go over all files in the directory to find out what languages are
            >+ * present. */
            >+ ga_init2(&ga, 1, 10);
            >+ for (i = 0; i < filecount; ++i)
            >+ {
            >+ len = STRLEN(files[i]);
            >+ if (len > 4)
            >+ {
            >+ if (STRICMP(files[i] + len - 4, ".txt") == 0)
            >+ {
            >+ /* ".txt" -> language "en" */
            >+ lang[0] = 'e';
            >+ lang[1] = 'n';
            >+ }
            >+ else if (files[i][len - 4] == '.'
            >+ && ASCII_ISALPHA(files[i][len - 3])
            >+ && ASCII_ISALPHA(files[i][len - 2])
            >+ && TOLOWER_ASC(files[i][len - 1]) == 'x')
            >+ {
            >+ /* ".abx" -> language "ab" */
            >+ lang[0] = TOLOWER_ASC(files[i][len - 3]);
            >+ lang[1] = TOLOWER_ASC(files[i][len - 2]);
            >+ }
            >+ else
            >+ continue;
            >+
            >+ /* Did we find this language already? */
            >+ for (j = 0; j < ga.ga_len; j += 2)
            >+ if (STRNCMP(lang, ((char_u *)ga.ga_data) + j, 2) == 0)
            >+ break;
            >+ if (j == ga.ga_len)
            >+ {
            >+ /* New language, add it. */
            >+ if (ga_grow(&ga, 2) == FAIL)
            >+ break;
            >+ ((char_u *)ga.ga_data)[ga.ga_len++] = lang[0];
            >+ ((char_u *)ga.ga_data)[ga.ga_len++] = lang[1];
            >+ ga.ga_room -= 2;
            >+ }
            >+ }
            >+ }
            >+
            >+ /*
            >+ * Loop over the found languages to generate a tags file for each one.
            >+ */
            >+ for (j = 0; j < ga.ga_len; j += 2)
            >+ {
            >+ STRCPY(fname, "tags-xx");
            >+ fname[5] = ((char_u *)ga.ga_data)[j];
            >+ fname[6] = ((char_u *)ga.ga_data)[j + 1];
            >+ if (fname[5] == 'e' && fname[6] == 'n')
            >+ {
            >+ /* English is an exception: use ".txt" and "tags". */
            >+ fname[4] = NUL;
            >+ STRCPY(ext, ".txt");
            >+ }
            >+ else
            >+ {
            >+ /* Language "ab" uses ".abx" and "tags-ab". */
            >+ STRCPY(ext, ".xxx");
            >+ ext[1] = fname[5];
            >+ ext[2] = fname[6];
            >+ }
            >+ helptags_one(eap->arg, ext, fname);
            >+ }
            >+
            >+ ga_clear(&ga);
            >+ FreeWild(filecount, files);
            >+
            >+ #else
            >+ /* No language support, just use "*.txt" and "tags". */
            >+ helptags_one(eap->arg, (char_u *)".txt", (char_u *)"tags");
            >+ #endif
            >+ }
            >+
            >+ static void
            >+ helptags_one(dir, ext, tagfname)
            >+ char_u *dir; /* doc directory */
            >+ char_u *ext; /* suffix, ".txt", ".itx", ".frx", etc. */
            >+ char_u *tagfname; /* "tags" for English, "tags-it" for Italian. */
            >+ {
            > FILE *fd_tags;
            > FILE *fd;
            > garray_T ga;
            >***************
            >*** 5099,5116 ****
            > int i;
            > char_u *fname;
            >
            >- if (!mch_isdir(eap->arg))
            >- {
            >- EMSG2(_("E150: Not a directory: %s"), eap->arg);
            >- return;
            >- }
            >-
            > /*
            > * Find all *.txt files.
            > */
            >! STRCPY(NameBuff, eap->arg);
            > add_pathsep(NameBuff);
            >! STRCAT(NameBuff, "*.txt");
            > if (gen_expand_wildcards(1, &NameBuff, &filecount, &files,
            > EW_FILE|EW_SILENT) == FAIL
            > || filecount == 0)
            >--- 5249,5261 ----
            > int i;
            > char_u *fname;
            >
            > /*
            > * Find all *.txt files.
            > */
            >! STRCPY(NameBuff, dir);
            > add_pathsep(NameBuff);
            >! STRCAT(NameBuff, "*");
            >! STRCAT(NameBuff, ext);
            > if (gen_expand_wildcards(1, &NameBuff, &filecount, &files,
            > EW_FILE|EW_SILENT) == FAIL
            > || filecount == 0)
            >***************
            >*** 5123,5131 ****
            > * Open the tags file for writing.
            > * Do this before scanning through all the files.
            > */
            >! STRCPY(NameBuff, eap->arg);
            > add_pathsep(NameBuff);
            >! STRCAT(NameBuff, "tags");
            > fd_tags = fopen((char *)NameBuff, "w");
            > if (fd_tags == NULL)
            > {
            >--- 5268,5276 ----
            > * Open the tags file for writing.
            > * Do this before scanning through all the files.
            > */
            >! STRCPY(NameBuff, dir);
            > add_pathsep(NameBuff);
            >! STRCAT(NameBuff, tagfname);
            > fd_tags = fopen((char *)NameBuff, "w");
            > if (fd_tags == NULL)
            > {
            >***************
            >*** 5138,5154 ****
            > * If generating tags for "$VIMRUNTIME/doc" add the "help-tags" tag.
            > */
            > ga_init2(&ga, (int)sizeof(char_u *), 100);
            >! if (fullpathcmp((char_u *)"$VIMRUNTIME/doc", eap->arg, FALSE) == FPC_SAME)
            > {
            > if (ga_grow(&ga, 1) == FAIL)
            > got_int = TRUE;
            > else
            > {
            >! s = vim_strsave((char_u *)"help-tags\ttags\t1\n");
            > if (s == NULL)
            > got_int = TRUE;
            > else
            > {
            > ((char_u **)ga.ga_data)[ga.ga_len] = s;
            > ++ga.ga_len;
            > --ga.ga_room;
            >--- 5283,5300 ----
            > * If generating tags for "$VIMRUNTIME/doc" add the "help-tags" tag.
            > */
            > ga_init2(&ga, (int)sizeof(char_u *), 100);
            >! if (fullpathcmp((char_u *)"$VIMRUNTIME/doc", dir, FALSE) == FPC_SAME)
            > {
            > if (ga_grow(&ga, 1) == FAIL)
            > got_int = TRUE;
            > else
            > {
            >! s = alloc(30);
            > if (s == NULL)
            > got_int = TRUE;
            > else
            > {
            >+ sprintf((char *)s, "help-tags\t%s\t1\n", tagfname);
            > ((char_u **)ga.ga_data)[ga.ga_len] = s;
            > ++ga.ga_len;
            > --ga.ga_room;
            >***************
            >*** 5260,5266 ****
            > for (i = 0; i < ga.ga_len; ++i)
            > {
            > s = ((char_u **)ga.ga_data)[i];
            >! if (STRNCMP(s, "help-tags\t", 10) == 0)
            > /* help-tags entry was added in formatted form */
            > fprintf(fd_tags, (char *)s);
            > else
            >--- 5406,5412 ----
            > for (i = 0; i < ga.ga_len; ++i)
            > {
            > s = ((char_u **)ga.ga_data)[i];
            >! if (STRNCMP(s, "help-tags", 9) == 0)
            > /* help-tags entry was added in formatted form */
            > fprintf(fd_tags, (char *)s);
            > else
            >*** ../vim-6.2.298/src/ex_cmds2.c Thu Feb 5 16:04:26 2004
            >--- src/ex_cmds2.c Wed Feb 25 15:11:43 2004
            >***************
            >*** 1863,1869 ****
            > if (p_verbose > 2)
            > msg_str((char_u *)_("Searching for \"%s\""), buf);
            >
            >! /* Expand wildcards and source each match. */
            > if (gen_expand_wildcards(1, &buf, &num_files, &files,
            > EW_FILE) == OK)
            > {
            >--- 1863,1869 ----
            > if (p_verbose > 2)
            > msg_str((char_u *)_("Searching for \"%s\""), buf);
            >
            >! /* Expand wildcards, invoke the callback for each match. */
            > if (gen_expand_wildcards(1, &buf, &num_files, &files,
            > EW_FILE) == OK)
            > {
            >***************
            >*** 5301,5310 ****
            > # endif /*FEAT_POSTSCRIPT*/
            > #endif /*FEAT_PRINTER*/
            >
            >!
            >! #ifdef FEAT_EVAL
            >!
            >! # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
            > static char *get_locale_val __ARGS((int what));
            >
            > static char *
            >--- 5301,5308 ----
            > # endif /*FEAT_POSTSCRIPT*/
            > #endif /*FEAT_PRINTER*/
            >
            >! #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
            >! && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
            > static char *get_locale_val __ARGS((int what));
            >
            > static char *
            >***************
            >*** 5317,5323 ****
            > * redefined and it doesn't use the arguments. */
            > loc = setlocale(what, NULL);
            >
            >! # if defined(__BORLANDC__)
            > if (loc != NULL)
            > {
            > char_u *p;
            >--- 5315,5321 ----
            > * redefined and it doesn't use the arguments. */
            > loc = setlocale(what, NULL);
            >
            >! # if defined(__BORLANDC__)
            > if (loc != NULL)
            > {
            > char_u *p;
            >***************
            >*** 5339,5349 ****
            > }
            > }
            > }
            >! # endif
            >
            > return loc;
            > }
            > # endif
            >
            > /*
            > * Set the "v:lang" variable according to the current locale setting.
            >--- 5337,5422 ----
            > }
            > }
            > }
            >! # endif
            >
            > return loc;
            > }
            >+ #endif
            >+
            >+
            >+ #ifdef WIN32
            >+ /*
            >+ * On MS-Windows locale names are strings like "German_Germany.1252", but
            >+ * gettext expects "de". Try to translate one into another here for a few
            >+ * supported languages.
            >+ */
            >+ static char_u *
            >+ gettext_lang(char_u *name)
            >+ {
            >+ int i;
            >+ static char *(mtable[]) = {
            >+ "afrikaans", "af",
            >+ "czech", "cs",
            >+ "dutch", "nl",
            >+ "german", "de",
            >+ "english_united kingdom", "en_GB",
            >+ "spanish", "es",
            >+ "french", "fr",
            >+ "italian", "it",
            >+ "japanese", "ja",
            >+ "korean", "ko",
            >+ "norwegian", "no",
            >+ "polish", "pl",
            >+ "russian", "ru",
            >+ "slovak", "sk",
            >+ "swedish", "sv",
            >+ "ukrainian", "uk",
            >+ "chinese_china", "zh_CN",
            >+ "chinese_taiwan", "zh_TW",
            >+ NULL};
            >+
            >+ for (i = 0; mtable[i] != NULL; i += 2)
            >+ if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
            >+ return mtable[i + 1];
            >+ return name;
            >+ }
            >+ #endif
            >+
            >+ #if defined(FEAT_MULTI_LANG) || defined(PROTO)
            >+ /*
            >+ * Obtain the current messages language. Used to set the default for
            >+ * 'helplang'. May return NULL or an empty string.
            >+ */
            >+ char_u *
            >+ get_mess_lang()
            >+ {
            >+ char_u *p;
            >+
            >+ # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
            >+ # if defined(LC_MESSAGES)
            >+ p = (char_u *)get_locale_val(LC_MESSAGES);
            >+ # else
            >+ /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
            >+ * may be set to the LCID number. */
            >+ p = (char_u *)get_locale_val(LC_ALL);
            >+ # endif
            >+ # else
            >+ p = mch_getenv((char_u *)"LC_ALL");
            >+ if (p == NULL || *p == NUL)
            >+ {
            >+ p = mch_getenv((char_u *)"LC_MESSAGES");
            >+ if (p == NULL || *p == NUL)
            >+ p = mch_getenv((char_u *)"LANG");
            >+ }
            >+ # endif
            >+ # ifdef WIN32
            >+ p = gettext_lang(p);
            > # endif
            >+ return p;
            >+ }
            >+ #endif
            >+
            >+ #if defined(FEAT_EVAL) || defined(PROTO)
            >
            > /*
            > * Set the "v:lang" variable according to the current locale setting.
            >***************
            >*** 5475,5516 ****
            > vim_setenv((char_u *)"LANG", name);
            > if (what != LC_CTYPE)
            > {
            > #ifdef WIN32
            >! char_u *mname = name;
            >! int i;
            >! static char *(mtable[]) = {
            >! "afrikaans", "af",
            >! "czech", "cs",
            >! "german", "de",
            >! "english_united kingdom", "en_gb",
            >! "spanish", "es",
            >! "french", "fr",
            >! "italian", "it",
            >! "japanese", "ja",
            >! "korean", "ko",
            >! "norwegian", "no",
            >! "polish", "pl",
            >! "russian", "ru",
            >! "slovak", "sk",
            >! "swedish", "sv",
            >! "ukrainian", "uk",
            >! "chinese_china", "zh_cn",
            >! "chinese_taiwan", "zh_tw",
            >! NULL};
            >!
            >! /* On MS-Windows locale names are strings like
            >! * "German_Germany.1252", but gettext expects "de". Try
            >! * to translate one into another here for a few supported
            >! * languages. */
            >! for (i = 0; mtable[i] != NULL; i += 2)
            >! if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
            >! {
            >! mname = mtable[i + 1];
            >! break;
            >! }
            >! vim_setenv((char_u *)"LC_MESSAGES", mname);
            > #else
            >! vim_setenv((char_u *)"LC_MESSAGES", name);
            > #endif
            > }
            >
            >--- 5548,5562 ----
            > vim_setenv((char_u *)"LANG", name);
            > if (what != LC_CTYPE)
            > {
            >+ char_u *mname;
            > #ifdef WIN32
            >! mname = gettext_lang(name);
            > #else
            >! mname = name;
            >! #endif
            >! vim_setenv((char_u *)"LC_MESSAGES", mname);
            >! #ifdef FEAT_MULTI_LANG
            >! set_helplang_default(mname);
            > #endif
            > }
            >
            >*** ../vim-6.2.298/src/ex_cmds.h Sun Feb 29 20:46:43 2004
            >--- src/ex_cmds.h Sun Feb 29 18:12:43 2004
            >***************
            >*** 389,395 ****
            > EX(CMD_gvim, "gvim", ex_gui,
            > BANG|FILES|EDITCMD|ARGOPT|TRLBAR|CMDWIN),
            > EX(CMD_help, "help", ex_help,
            >! EXTRA|NOTRLCOM),
            > EX(CMD_helpfind, "helpfind", ex_helpfind,
            > EXTRA|NOTRLCOM),
            > EX(CMD_helpgrep, "helpgrep", ex_helpgrep,
            >--- 389,395 ----
            > EX(CMD_gvim, "gvim", ex_gui,
            > BANG|FILES|EDITCMD|ARGOPT|TRLBAR|CMDWIN),
            > EX(CMD_help, "help", ex_help,
            >! BANG|EXTRA|NOTRLCOM),
            > EX(CMD_helpfind, "helpfind", ex_helpfind,
            > EXTRA|NOTRLCOM),
            > EX(CMD_helpgrep, "helpgrep", ex_helpgrep,
            >*** ../vim-6.2.298/src/ex_getln.c Sun Feb 29 14:45:49 2004
            >--- src/ex_getln.c Sat Feb 28 16:33:29 2004
            >***************
            >*** 3592,3597 ****
            >--- 3594,3632 ----
            > return EXPAND_OK;
            > }
            >
            >+ #ifdef FEAT_MULTI_LANG
            >+ /*
            >+ * Cleanup matches for help tags: remove "@en" if "en" is the only language.
            >+ */
            >+ static void cleanup_help_tags __ARGS((int num_file, char_u **file));
            >+
            >+ static void
            >+ cleanup_help_tags(num_file, file)
            >+ int num_file;
            >+ char_u **file;
            >+ {
            >+ int i, j;
            >+ int len;
            >+
            >+ for (i = 0; i < num_file; ++i)
            >+ {
            >+ len = (int)STRLEN(file[i]) - 3;
            >+ if (len > 0 && STRCMP(file[i] + len, "@en") == 0)
            >+ {
            >+ /* Sorting on priority means the same item in another language may
            >+ * be anywhere. Search all items for a match up to the "@en". */
            >+ for (j = 0; j < num_file; ++j)
            >+ if (j != i
            >+ && (int)STRLEN(file[j]) == len + 3
            >+ && STRNCMP(file[i], file[j], len + 1) == 0)
            >+ break;
            >+ if (j == num_file)
            >+ file[i][len] = NUL;
            >+ }
            >+ }
            >+ }
            >+ #endif
            >+
            > /*
            > * Do the expansion based on xp->xp_context and "pat".
            > */
            >***************
            >*** 3660,3666 ****
            > *file = (char_u **)"";
            > *num_file = 0;
            > if (xp->xp_context == EXPAND_HELP)
            >! return find_help_tags(pat, num_file, file);
            >
            > #ifndef FEAT_CMDL_COMPL
            > return FAIL;
            >--- 3695,3710 ----
            > *file = (char_u **)"";
            > *num_file = 0;
            > if (xp->xp_context == EXPAND_HELP)
            >! {
            >! if (find_help_tags(pat, num_file, file, FALSE) == OK)
            >! {
            >! #ifdef FEAT_MULTI_LANG
            >! cleanup_help_tags(*num_file, *file);
            >! #endif
            >! return OK;
            >! }
            >! return FAIL;
            >! }
            >
            > #ifndef FEAT_CMDL_COMPL
            > return FAIL;
            >*** ../vim-6.2.298/src/normal.c Sun Feb 29 20:46:43 2004
            >--- src/normal.c Sun Feb 29 20:33:32 2004
            >***************
            >*** 4880,4886 ****
            >
            > case 'K':
            > if (kp_help)
            >! STRCPY(buf, ":he ");
            > else
            > {
            > /* When a count is given, turn it into a range. Is this
            >--- 4880,4886 ----
            >
            > case 'K':
            > if (kp_help)
            >! STRCPY(buf, "he! ");
            > else
            > {
            > /* When a count is given, turn it into a range. Is this
            >***************
            >*** 4915,4921 ****
            >
            > default:
            > if (curbuf->b_help)
            >! STRCPY(buf, "he ");
            > else if (g_cmd)
            > STRCPY(buf, "tj ");
            > else
            >--- 4915,4921 ----
            >
            > default:
            > if (curbuf->b_help)
            >! STRCPY(buf, "he! ");
            > else if (g_cmd)
            > STRCPY(buf, "tj ");
            > else
            >*** ../vim-6.2.298/src/option.c Tue Feb 17 20:41:09 2004
            >--- src/option.c Tue Feb 24 19:48:05 2004
            >***************
            >*** 1057,1062 ****
            >--- 1057,1071 ----
            > (char_u *)NULL, PV_NONE,
            > #endif
            > {(char_u *)20L, (char_u *)0L}},
            >+ {"helplang", "hlg", P_STRING|P_VI_DEF|P_COMMA,
            >+ #ifdef FEAT_MULTI_LANG
            >+ (char_u *)&p_hlg, PV_NONE,
            >+ {(char_u *)"", (char_u *)0L}
            >+ #else
            >+ (char_u *)NULL, PV_NONE,
            >+ {(char_u *)0L, (char_u *)0L}
            >+ #endif
            >+ },
            > {"hidden", "hid", P_BOOL|P_VI_DEF,
            > (char_u *)&p_hid, PV_NONE,
            > {(char_u *)FALSE, (char_u *)0L}},
            >***************
            >*** 2802,2807 ****
            >--- 2811,2821 ----
            > }
            > }
            > #endif
            >+
            >+ #ifdef FEAT_MULTI_LANG
            >+ /* Set the default for 'helplang'. */
            >+ set_helplang_default(get_mess_lang());
            >+ #endif
            > }
            >
            > /*
            >***************
            >*** 3115,3120 ****
            >--- 3129,3162 ----
            > #endif
            > }
            >
            >+ #if defined(FEAT_MULTI_LANG) || defined(PROTO)
            >+ /*
            >+ * When 'helplang' is still at its default value, set it to "lang".
            >+ * Only the first two characters of "lang" are used.
            >+ */
            >+ void
            >+ set_helplang_default(lang)
            >+ char_u *lang;
            >+ {
            >+ int idx;
            >+
            >+ if (lang == NULL || STRLEN(lang) < 2) /* safety check */
            >+ return;
            >+ idx = findoption((char_u *)"hlg");
            >+ if (!(options[idx].flags & P_WAS_SET))
            >+ {
            >+ if (options[idx].flags & P_ALLOCED)
            >+ free_string_option(p_hlg);
            >+ p_hlg = vim_strsave(lang);
            >+ if (p_hlg == NULL)
            >+ p_hlg = empty_option;
            >+ else
            >+ p_hlg[2] = NUL;
            >+ options[idx].flags |= P_ALLOCED;
            >+ }
            >+ }
            >+ #endif
            >+
            > #ifdef FEAT_GUI
            > static char_u *gui_bg_default __ARGS((void));
            >
            >***************
            >*** 4591,4596 ****
            >--- 4633,4656 ----
            > }
            > }
            >
            >+ #ifdef FEAT_MULTI_LANG
            >+ /* 'helplang' */
            >+ else if (varp == &p_hlg)
            >+ {
            >+ /* Check for "", "ab", "ab,cd", etc. */
            >+ for (s = p_hlg; *s != NUL; s += 3)
            >+ {
            >+ if (s[1] == NUL || ((s[2] != ',' || s[3] == NUL) && s[2] != NUL))
            >+ {
            >+ errmsg = e_invarg;
            >+ break;
            >+ }
            >+ if (s[2] == NUL)
            >+ break;
            >+ }
            >+ }
            >+ #endif
            >+
            > /* 'highlight' */
            > else if (varp == &p_hl)
            > {
            >*** ../vim-6.2.298/src/option.h Sun Jan 25 20:42:15 2004
            >--- src/option.h Tue Feb 24 19:47:35 2004
            >***************
            >*** 471,476 ****
            >--- 471,479 ----
            > #ifdef FEAT_WINDOWS
            > EXTERN long p_hh; /* 'helpheight' */
            > #endif
            >+ #ifdef FEAT_MULTI_LANG
            >+ EXTERN char_u *p_hlg; /* 'helplang' */
            >+ #endif
            > EXTERN int p_hid; /* 'hidden' */
            > /* Use P_HID to check if a buffer is to be hidden when it is no longer
            > * visible in a window. */
            >*** ../vim-6.2.298/src/proto/ex_cmds.pro Sun Jun 1 12:26:07 2003
            >--- src/proto/ex_cmds.pro Mon Feb 16 17:12:54 2004
            >***************
            >*** 39,45 ****
            > void prepare_tagpreview __ARGS((void));
            > void ex_help __ARGS((exarg_T *eap));
            > int help_heuristic __ARGS((char_u *matched_string, int offset, int wrong_case));
            >! int find_help_tags __ARGS((char_u *arg, int *num_matches, char_u ***matches));
            > void fix_help_buffer __ARGS((void));
            > void ex_helptags __ARGS((exarg_T *eap));
            > void ex_sign __ARGS((exarg_T *eap));
            >--- 39,45 ----
            > void prepare_tagpreview __ARGS((void));
            > void ex_help __ARGS((exarg_T *eap));
            > int help_heuristic __ARGS((char_u *matched_string, int offset, int wrong_case));
            >! int find_help_tags __ARGS((char_u *arg, int *num_matches, char_u ***matches, int keep_lang));
            > void fix_help_buffer __ARGS((void));
            > void ex_helptags __ARGS((exarg_T *eap));
            > void ex_sign __ARGS((exarg_T *eap));
            >*** ../vim-6.2.298/src/proto/ex_cmds2.pro Thu Feb 5 16:04:26 2004
            >--- src/proto/ex_cmds2.pro Mon Feb 16 21:04:22 2004
            >***************
            >*** 68,73 ****
            >--- 68,74 ----
            > void mch_print_set_font __ARGS((int iBold, int iItalic, int iUnderline));
            > void mch_print_set_bg __ARGS((long_u bgcol));
            > void mch_print_set_fg __ARGS((long_u fgcol));
            >+ char_u *get_mess_lang __ARGS((void));
            > void set_lang_var __ARGS((void));
            > void ex_language __ARGS((exarg_T *eap));
            > char_u *get_lang_arg __ARGS((expand_T *xp, int idx));
            >*** ../vim-6.2.298/src/proto/option.pro Sun Jun 1 12:26:17 2003
            >--- src/proto/option.pro Mon Feb 16 20:50:10 2004
            >***************
            >*** 4,9 ****
            >--- 4,10 ----
            > void set_number_default __ARGS((char *name, long val));
            > void set_init_2 __ARGS((void));
            > void set_init_3 __ARGS((void));
            >+ void set_helplang_default __ARGS((char_u *lang));
            > void init_gui_options __ARGS((void));
            > void set_title_defaults __ARGS((void));
            > int do_set __ARGS((char_u *arg, int opt_flags));
            >*** ../vim-6.2.298/src/structs.h Sun Feb 29 20:46:43 2004
            >--- src/structs.h Sun Feb 29 16:45:20 2004
            >***************
            >*** 55,60 ****
            >--- 55,62 ----
            > void *ga_data; /* pointer to the first item */
            > } garray_T;
            >
            >+ #define GA_EMPTY {0, 0, 0, 0, NULL}
            >+
            > /*
            > * This is here because regexp.h needs pos_T and below regprog_T is used.
            > */
            >*** ../vim-6.2.298/src/tag.c Wed Feb 11 14:40:25 2004
            >--- src/tag.c Thu Feb 26 22:06:45 2004
            >***************
            >*** 986,995 ****
            > * Tags in an emacs-style tags file are always global.
            > *
            > * flags:
            >! * TAG_HELP only search for help tags
            >! * TAG_NAMES only return name of tag
            >! * TAG_REGEXP use "pat" as a regexp
            >! * TAG_NOIC don't always ignore case
            > */
            > int
            > find_tags(pat, num_matches, matchesp, flags, mincount)
            >--- 986,996 ----
            > * Tags in an emacs-style tags file are always global.
            > *
            > * flags:
            >! * TAG_HELP only search for help tags
            >! * TAG_NAMES only return name of tag
            >! * TAG_REGEXP use "pat" as a regexp
            >! * TAG_NOIC don't always ignore case
            >! * TAG_KEEP_LANG keep language
            > */
            > int
            > find_tags(pat, num_matches, matchesp, flags, mincount)
            >***************
            >*** 1078,1083 ****
            >--- 1079,1090 ----
            > int mtt;
            > int len;
            > int help_save;
            >+ #ifdef FEAT_MULTI_LANG
            >+ int help_pri = 0;
            >+ char_u *help_lang_find = NULL; /* lang to be found */
            >+ char_u help_lang[3]; /* lang of current tags file */
            >+ char_u *saved_pat = NULL; /* copy of pat[] */
            >+ #endif
            >
            > int patlen; /* length of pat[] */
            > char_u *pathead; /* start of pattern head */
            >***************
            >*** 1102,1112 ****
            >
            > help_save = curbuf->b_help;
            >
            >- if (has_re)
            >- regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
            >- else
            >- regmatch.regprog = NULL;
            >-
            > /*
            > * Allocate memory for the buffers that are used
            > */
            >--- 1109,1114 ----
            >***************
            >*** 1137,1142 ****
            >--- 1139,1162 ----
            > curbuf->b_help = TRUE; /* will be restored later */
            >
            > patlen = (int)STRLEN(pat);
            >+ #ifdef FEAT_MULTI_LANG
            >+ if (curbuf->b_help)
            >+ {
            >+ /* When "@ab" is specified use only the "ab" language, otherwise
            >+ * search all languages. */
            >+ if (patlen > 3 && pat[patlen - 3] == '@')
            >+ {
            >+ saved_pat = vim_strnsave(pat, patlen - 3);
            >+ if (saved_pat != NULL)
            >+ {
            >+ help_lang_find = &pat[patlen - 2];
            >+ pat = saved_pat;
            >+ patlen -= 3;
            >+ }
            >+ }
            >+ }
            >+ #endif
            >+
            > if (p_tl != 0 && patlen > p_tl) /* adjust for 'taglength' */
            > patlen = p_tl;
            >
            >***************
            >*** 1161,1166 ****
            >--- 1181,1191 ----
            > patheadlen = p_tl;
            > }
            >
            >+ if (has_re)
            >+ regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
            >+ else
            >+ regmatch.regprog = NULL;
            >+
            > #ifdef FEAT_TAG_BINS
            > /* This is only to avoid a compiler warning for using search_info
            > * uninitialised. */
            >***************
            >*** 1205,1212 ****
            >--- 1230,1287 ----
            > else
            > #endif
            > {
            >+ #ifdef FEAT_MULTI_LANG
            >+ if (curbuf->b_help)
            >+ {
            >+ /* Prefer help tags according to 'helplang'. Put the
            >+ * two-letter language name in help_lang[]. */
            >+ i = STRLEN(tag_fname);
            >+ if (i > 3 && tag_fname[i - 3] == '-')
            >+ STRCPY(help_lang, tag_fname + i - 2);
            >+ else
            >+ STRCPY(help_lang, "en");
            >+
            >+ /* When searching for a specific language skip tags files
            >+ * for other languages. */
            >+ if (help_lang_find != NULL
            >+ && STRICMP(help_lang, help_lang_find) != 0)
            >+ continue;
            >+
            >+ /* For CTRL-] in a help file prefer a match with the same
            >+ * language. */
            >+ if ((flags & TAG_KEEP_LANG)
            >+ && help_lang_find == NULL
            >+ && (i = STRLEN(curbuf->b_fname)) > 4
            >+ && curbuf->b_fname[i - 1] == 'x'
            >+ && curbuf->b_fname[i - 4] == '.'
            >+ && STRNICMP(curbuf->b_fname + i - 3, help_lang, 2) == 0)
            >+ help_pri = 0;
            >+ else
            >+ {
            >+ help_pri = 1;
            >+ for (s = p_hlg; *s != NUL; ++s)
            >+ {
            >+ if (STRNICMP(s, help_lang, 2) == 0)
            >+ break;
            >+ ++help_pri;
            >+ if ((s = vim_strchr(s, ',')) == NULL)
            >+ break;
            >+ }
            >+ if (s == NULL || *s == NUL)
            >+ {
            >+ /* Language not in 'helplang': use last, prefer English,
            >+ * unless found already. */
            >+ ++help_pri;
            >+ if (STRICMP(help_lang, "en") != 0)
            >+ ++help_pri;
            >+ }
            >+ }
            >+ }
            >+ #endif
            >+
            > if ((fp = mch_fopen((char *)tag_fname, "r")) == NULL)
            > continue;
            >+
            > if (p_verbose >= 5)
            > msg_str((char_u *)_("Searching tags file %s"), tag_fname);
            > }
            >***************
            >*** 1216,1221 ****
            >--- 1291,1297 ----
            > #ifdef FEAT_EMACS_TAGS
            > is_etag = 0; /* default is: not emacs style */
            > #endif
            >+
            > /*
            > * Read and parse the lines in the file one by one
            > */
            >***************
            >*** 1811,1816 ****
            >--- 1887,1897 ----
            > {
            > if (help_only)
            > {
            >+ #ifdef FEAT_MULTI_LANG
            >+ # define ML_EXTRA 3
            >+ #else
            >+ # define ML_EXTRA 0
            >+ #endif
            > /*
            > * Append the help-heuristic number after the
            > * tagname, for sorting it later.
            >***************
            >*** 1818,1832 ****
            > *tagp.tagname_end = NUL;
            > len = (int)(tagp.tagname_end - tagp.tagname);
            > mfp = (struct match_found *)
            >! alloc(sizeof(struct match_found) + len + 10);
            > if (mfp != NULL)
            > {
            >! mfp->len = len + 1; /* also compare the NUL */
            > p = mfp->match;
            > STRCPY(p, tagp.tagname);
            >! sprintf((char *)p + len + 1, "%06d",
            > help_heuristic(tagp.tagname,
            >! match_re ? matchoff : 0, !match_no_ic));
            > }
            > *tagp.tagname_end = TAB;
            > }
            >--- 1899,1925 ----
            > *tagp.tagname_end = NUL;
            > len = (int)(tagp.tagname_end - tagp.tagname);
            > mfp = (struct match_found *)
            >! alloc(sizeof(struct match_found) + len
            >! + 10 + ML_EXTRA);
            > if (mfp != NULL)
            > {
            >! /* "len" includes the language and the NUL, but
            >! * not the priority. */
            >! mfp->len = len + ML_EXTRA + 1;
            >! #define ML_HELP_LEN 6
            > p = mfp->match;
            > STRCPY(p, tagp.tagname);
            >! #ifdef FEAT_MULTI_LANG
            >! p[len] = '@';
            >! STRCPY(p + len + 1, help_lang);
            >! #endif
            >! sprintf((char *)p + len + 1 + ML_EXTRA, "%06d",
            > help_heuristic(tagp.tagname,
            >! match_re ? matchoff : 0, !match_no_ic)
            >! #ifdef FEAT_MULTI_LANG
            >! + help_pri
            >! #endif
            >! );
            > }
            > *tagp.tagname_end = TAB;
            > }
            >***************
            >*** 2070,2076 ****
            > * match_found into a string. For help the priority was not
            > * included in the length. */
            > mch_memmove(mfp, mfp->match,
            >! (size_t)(mfp->len + (help_only ? 9 : 0)));
            > matches[match_count++] = (char_u *)mfp;
            > }
            > }
            >--- 2163,2169 ----
            > * match_found into a string. For help the priority was not
            > * included in the length. */
            > mch_memmove(mfp, mfp->match,
            >! (size_t)(mfp->len + (help_only ? ML_HELP_LEN : 0)));
            > matches[match_count++] = (char_u *)mfp;
            > }
            > }
            >***************
            >*** 2081,2090 ****
            >--- 2174,2205 ----
            > *num_matches = match_count;
            >
            > curbuf->b_help = help_save;
            >+ #ifdef FEAT_MULTI_LANG
            >+ vim_free(saved_pat);
            >+ #endif
            >
            > return retval;
            > }
            >
            >+ static garray_T tag_fnames = GA_EMPTY;
            >+ static void found_tagfile_cb __ARGS((char_u *fname));
            >+
            >+ /*
            >+ * Callback function for finding all "tags" and "tags-??" files in
            >+ * 'runtimepath' doc directories.
            >+ */
            >+ static void
            >+ found_tagfile_cb(fname)
            >+ char_u *fname;
            >+ {
            >+ if (ga_grow(&tag_fnames, 1) == OK)
            >+ {
            >+ ((char_u **)(tag_fnames.ga_data))[tag_fnames.ga_len++] =
            >+ vim_strsave(fname);
            >+ --tag_fnames.ga_room;
            >+ }
            >+ }
            >+
            > /*
            > * Get the next name of a tag file from the tag file list.
            > * For help files, use "tags" file only.
            >***************
            >*** 2099,2105 ****
            > static void *search_ctx = NULL;
            > static char_u *np = NULL;
            > static int did_filefind_init;
            >! static int did_use_hf = FALSE;
            > char_u *fname = NULL;
            > char_u *r_ptr;
            >
            >--- 2214,2220 ----
            > static void *search_ctx = NULL;
            > static char_u *np = NULL;
            > static int did_filefind_init;
            >! static int hf_idx = 0;
            > char_u *fname = NULL;
            > char_u *r_ptr;
            >
            >***************
            >*** 2107,2114 ****
            > {
            > if (curbuf->b_help)
            > {
            >! np = p_rtp;
            >! did_use_hf = FALSE;
            > }
            > else if (*curbuf->b_p_tags != NUL)
            > np = curbuf->b_p_tags;
            >--- 2222,2241 ----
            > {
            > if (curbuf->b_help)
            > {
            >! /*
            >! * For a help window find "doc/tags" and "doc/tags-??" in all
            >! * directories in 'runtimepath'.
            >! */
            >! ga_clear(&tag_fnames);
            >! ga_init2(&tag_fnames, sizeof(char_u *), 10);
            >! do_in_runtimepath((char_u *)
            >! #ifdef FEAT_MULTI_LANG
            >! "doc/tags doc/tags-??"
            >! #else
            >! "doc/tags"
            >! #endif
            >! , TRUE, found_tagfile_cb);
            >! hf_idx = 0;
            > }
            > else if (*curbuf->b_p_tags != NUL)
            > np = curbuf->b_p_tags;
            >***************
            >*** 2118,2154 ****
            > did_filefind_init = FALSE;
            > }
            >
            >- /* tried already (or bogus call) */
            >- if (np == NULL)
            >- return FAIL;
            >-
            > if (curbuf->b_help)
            > {
            >! /*
            >! * For a help window find "doc/tags" in all directories in
            >! * 'runtimepath'.
            >! */
            >! if (*np == NUL || copy_option_part(&np, buf, MAXPATHL, ",") == 0)
            > {
            >! if (did_use_hf || *p_hf == NUL)
            > return FAIL;
            >!
            >! /* Not found in 'runtimepath', use 'helpfile', replacing
            >! * "help.txt" with "tags". */
            >! did_use_hf = TRUE;
            > STRCPY(buf, p_hf);
            > STRCPY(gettail(buf), "tags");
            >- return OK;
            > }
            >! add_pathsep(buf);
            >! #ifndef COLON_AS_PATHSEP
            >! STRCAT(buf, "doc/tags");
            >! #else
            >! STRCAT(buf, "doc:tags");
            >! #endif
            > }
            > else
            > {
            > /*
            > * Loop until we have found a file name that can be used.
            > * There are two states:
            >--- 2245,2274 ----
            > did_filefind_init = FALSE;
            > }
            >
            > if (curbuf->b_help)
            > {
            >! if (hf_idx >= tag_fnames.ga_len)
            > {
            >! /* Not found in 'runtimepath', use 'helpfile', if it exists and
            >! * wasn't used yet, replacing "help.txt" with "tags". */
            >! if (hf_idx > tag_fnames.ga_len || *p_hf == NUL)
            > return FAIL;
            >! ++hf_idx;
            > STRCPY(buf, p_hf);
            > STRCPY(gettail(buf), "tags");
            > }
            >! else
            >! {
            >! STRNCPY(buf, ((char_u **)(tag_fnames.ga_data))[hf_idx++], MAXPATHL);
            >! buf[MAXPATHL - 1] = NUL;
            >! }
            > }
            > else
            > {
            >+ /* tried already (or bogus call) */
            >+ if (np == NULL)
            >+ return FAIL;
            >+
            > /*
            > * Loop until we have found a file name that can be used.
            > * There are two states:
            >***************
            >*** 2637,2644 ****
            >
            > if (keep_help)
            > {
            >! /* A :ta from a help file will keep the b_help flag set. For ":ptag" we
            >! * need to use the flag from the window where we came from. */
            > #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
            > if (g_do_tagpreview)
            > keep_help_flag = curwin_save->w_buffer->b_help;
            >--- 2757,2764 ----
            >
            > if (keep_help)
            > {
            >! /* A :ta from a help file will keep the b_help flag set. For ":ptag"
            >! * we need to use the flag from the window where we came from. */
            > #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
            > if (g_do_tagpreview)
            > keep_help_flag = curwin_save->w_buffer->b_help;
            >*** ../vim-6.2.298/src/vim.h Tue Feb 10 19:35:15 2004
            >--- src/vim.h Wed Feb 25 14:42:25 2004
            >***************
            >*** 893,898 ****
            >--- 893,900 ----
            > #endif
            > #define TAG_VERBOSE 32 /* message verbosity */
            > #define TAG_INS_COMP 64 /* Currently doing insert completion */
            >+ #define TAG_KEEP_LANG 128 /* keep current language */
            >+
            > #define TAG_MANY 200 /* When finding many tags (for completion),
            > find up to this many tags */
            >
            >***************
            >*** 1234,1239 ****
            >--- 1236,1242 ----
            > #define MSG_ATTR(s, attr) msg_attr((char_u *)(s), (attr))
            > #define EMSG(s) emsg((char_u *)(s))
            > #define EMSG2(s, p) emsg2((char_u *)(s), (char_u *)(p))
            >+ #define EMSG3(s, p, q) emsg3((char_u *)(s), (char_u *)(p), (char_u *)(q))
            > #define EMSGN(s, n) emsgn((char_u *)(s), (long)(n))
            > #define OUT_STR(s) out_str((char_u *)(s))
            > #define OUT_STR_NF(s) out_str_nf((char_u *)(s))
            >
            >
            >
          • Bram Moolenaar
            ... Right, I forgot about make having these strange rules about which value is being used. And $PATH is not under our control. ... Even better is to use the
            Message 5 of 10 , Mar 16, 2004
              Gordon Prieur wrote:

              > I've found several problems with this patch related to the VIMEXE make
              > variable. First off, you have:
              >
              > -@cd $(HELPSOURCE); VIMEXE=$(VIMTARGET) $(MAKE) vimtags
              >
              > At least with Solaris' make, setting VIMEXE in the environment doesn't
              > superscede the VIMEXE=vim in $HELPSOURCE/Makefile, so your aren't
              > overriding the default.

              Right, I forgot about "make" having these strange rules about which
              value is being used. And $PATH is not under our control.

              > Thats OK on my system, but my release engineering
              > group has a vim 5.3 version in their path so it fails. What you (probably)
              > want is something like:
              >
              > -@cd $(HELPSOURCE); $(MAKE) VIMEXE=../../src/$(VIMTARGET) vimtag
              >
              > It passes VIMEXE as a make variable, which does override the default in
              > $HELPSOURCE/Makefile. It also passes in the vim you just built, so it
              > doesn't look in your path for vim.

              Even better is to use the path to the just installed Vim, that avoids
              trouble with $srcdir is used. I'll make a patch for that:

              -@cd $(HELPSOURCE); $(MAKE) VIMEXE=$(DEST_BIN)/$(VIMTARGET) vimtags

              --
              On the other hand, you have different fingers.
              -- Steven Wright

              /// Bram Moolenaar -- Bram@... -- http://www.Moolenaar.net \\\
              /// Sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
              \\\ Project leader for A-A-P -- http://www.A-A-P.org ///
              \\\ Buy at Amazon and help AIDS victims -- http://ICCF.nl/click1.html ///
            Your message has been successfully submitted and would be delivered to recipients shortly.