Patch 8.2.1269
Problem:    Language and locale code spread out.
Solution:   Move relevant code to src/locale.c. (Yegappan Lakshmanan,
            closes #6509)
Files:      Filelist, src/Make_cyg_ming.mak, src/Make_morph.mak,
            src/Make_mvc.mak, src/Make_vms.mms, src/Makefile, src/README.md,
            src/ex_cmds2.c, src/locale.c, src/main.c, src/proto.h,
            src/proto/ex_cmds2.pro, src/proto/locale.pro


*** ../vim-8.2.1268/Filelist    2020-07-21 21:07:00.716496755 +0200
--- Filelist    2020-07-22 19:03:10.315786917 +0200
***************
*** 76,81 ****
--- 76,82 ----
                src/json_test.c \
                src/kword_test.c \
                src/list.c \
+               src/locale.c \
                src/keymap.h \
                src/macros.h \
                src/main.c \
***************
*** 247,252 ****
--- 248,254 ----
                src/proto/insexpand.pro \
                src/proto/json.pro \
                src/proto/list.pro \
+               src/proto/locale.pro \
                src/proto/main.pro \
                src/proto/map.pro \
                src/proto/mark.pro \
*** ../vim-8.2.1268/src/Make_cyg_ming.mak       2020-07-21 21:07:00.716496755 
+0200
--- src/Make_cyg_ming.mak       2020-07-22 19:03:10.315786917 +0200
***************
*** 751,756 ****
--- 751,757 ----
        $(OUTDIR)/insexpand.o \
        $(OUTDIR)/json.o \
        $(OUTDIR)/list.o \
+       $(OUTDIR)/locale.o \
        $(OUTDIR)/main.o \
        $(OUTDIR)/map.o \
        $(OUTDIR)/mark.o \
*** ../vim-8.2.1268/src/Make_morph.mak  2020-07-21 21:07:00.716496755 +0200
--- src/Make_morph.mak  2020-07-22 19:03:10.315786917 +0200
***************
*** 70,75 ****
--- 70,76 ----
        insexpand.c                                             \
        json.c                                                  \
        list.c                                                  \
+       locale.c                                                \
        main.c                                                  \
        map.c                                                   \
        mark.c                                                  \
*** ../vim-8.2.1268/src/Make_mvc.mak    2020-07-21 21:07:00.716496755 +0200
--- src/Make_mvc.mak    2020-07-22 19:03:10.315786917 +0200
***************
*** 773,778 ****
--- 773,779 ----
        $(OUTDIR)\insexpand.obj \
        $(OUTDIR)\json.obj \
        $(OUTDIR)\list.obj \
+       $(OUTDIR)\locale.obj \
        $(OUTDIR)\main.obj \
        $(OUTDIR)\map.obj \
        $(OUTDIR)\mark.obj \
***************
*** 1669,1674 ****
--- 1670,1677 ----
  
  $(OUTDIR)/list.obj:   $(OUTDIR) list.c  $(INCL)
  
+ $(OUTDIR)/locale.obj: $(OUTDIR) locale.c  $(INCL)
+ 
  $(OUTDIR)/main.obj:   $(OUTDIR) main.c  $(INCL) $(CUI_INCL)
  
  $(OUTDIR)/map.obj:    $(OUTDIR) map.c  $(INCL)
***************
*** 1939,1944 ****
--- 1942,1948 ----
        proto/insexpand.pro \
        proto/json.pro \
        proto/list.pro \
+       proto/locale.pro \
        proto/main.pro \
        proto/map.pro \
        proto/mark.pro \
*** ../vim-8.2.1268/src/Make_vms.mms    2020-07-21 21:07:00.716496755 +0200
--- src/Make_vms.mms    2020-07-22 19:03:10.315786917 +0200
***************
*** 345,350 ****
--- 345,351 ----
        insexpand.c \
        json.c \
        list.c \
+       locale.c \
        main.c \
        map.c \
        mark.c \
***************
*** 460,465 ****
--- 461,467 ----
        insexpand.obj \
        json.obj \
        list.obj \
+       locale.obj \
        main.obj \
        map.obj \
        mark.obj \
***************
*** 865,870 ****
--- 867,876 ----
   ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
   beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
   globals.h
+ locale.obj : locale.c vim.h [.auto]config.h feature.h os_unix.h \
+  ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
+  beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
+  globals.h
  main.obj : main.c vim.h [.auto]config.h feature.h os_unix.h   \
   ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
   [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
*** ../vim-8.2.1268/src/Makefile        2020-07-21 22:34:37.909099597 +0200
--- src/Makefile        2020-07-22 19:03:10.315786917 +0200
***************
*** 1647,1652 ****
--- 1647,1653 ----
        insexpand.c \
        json.c \
        list.c \
+       locale.c \
        main.c \
        map.c \
        mark.c \
***************
*** 1798,1803 ****
--- 1799,1805 ----
        objects/indent.o \
        objects/insexpand.o \
        objects/list.o \
+       objects/locale.o \
        objects/map.o \
        objects/mark.o \
        objects/match.o \
***************
*** 1973,1978 ****
--- 1975,1981 ----
        insexpand.pro \
        json.pro \
        list.pro \
+       locale.pro \
        main.pro \
        map.pro \
        mark.pro \
***************
*** 3378,3383 ****
--- 3381,3389 ----
  objects/list.o: list.c
        $(CCC) -o $@ list.c
  
+ objects/locale.o: locale.c
+       $(CCC) -o $@ locale.c
+ 
  objects/main.o: main.c
        $(CCC) -o $@ main.c
  
***************
*** 3968,3973 ****
--- 3974,3983 ----
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
   proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
   proto.h globals.h
+ objects/locale.o: locale.c vim.h protodef.h auto/config.h feature.h os_unix.h 
\
+  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+  proto.h globals.h
  objects/main.o: main.c vim.h protodef.h auto/config.h feature.h os_unix.h \
   auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
   proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
*** ../vim-8.2.1268/src/README.md       2020-07-21 21:07:00.716496755 +0200
--- src/README.md       2020-07-22 19:03:10.315786917 +0200
***************
*** 52,57 ****
--- 52,58 ----
  highlight.c   | syntax highlighting
  indent.c      | text indentation
  insexpand.c   | Insert mode completion
+ locale.c      | locale/language handling
  map.c         | mapping and abbreviations
  mark.c                | marks
  match.c               | highlight matching
*** ../vim-8.2.1268/src/ex_cmds2.c      2020-06-16 20:03:38.747351038 +0200
--- src/ex_cmds2.c      2020-07-22 19:03:10.315786917 +0200
***************
*** 996,1500 ****
      }
      no_check_timestamps = save_no_check_timestamps;
  }
- 
- #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
-       && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
- # define HAVE_GET_LOCALE_VAL
-     static char_u *
- get_locale_val(int what)
- {
-     char_u    *loc;
- 
-     // Obtain the locale value from the libraries.
-     loc = (char_u *)setlocale(what, NULL);
- 
- # ifdef MSWIN
-     if (loc != NULL)
-     {
-       char_u  *p;
- 
-       // setocale() returns something like "LC_COLLATE=<name>;LC_..." when
-       // one of the values (e.g., LC_CTYPE) differs.
-       p = vim_strchr(loc, '=');
-       if (p != NULL)
-       {
-           loc = ++p;
-           while (*p != NUL)   // remove trailing newline
-           {
-               if (*p < ' ' || *p == ';')
-               {
-                   *p = NUL;
-                   break;
-               }
-               ++p;
-           }
-       }
-     }
- # endif
- 
-     return loc;
- }
- #endif
- 
- 
- #ifdef MSWIN
- /*
-  * 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 (char_u *)mtable[i + 1];
-     return name;
- }
- #endif
- 
- #if defined(FEAT_MULTI_LANG) || defined(PROTO)
- /*
-  * Return TRUE when "lang" starts with a valid language name.
-  * Rejects NULL, empty string, "C", "C.UTF-8" and others.
-  */
-     static int
- is_valid_mess_lang(char_u *lang)
- {
-     return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
- }
- 
- /*
-  * Obtain the current messages language.  Used to set the default for
-  * 'helplang'.  May return NULL or an empty string.
-  */
-     char_u *
- get_mess_lang(void)
- {
-     char_u *p;
- 
- # ifdef HAVE_GET_LOCALE_VAL
- #  if defined(LC_MESSAGES)
-     p = 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.  LC_COLLATE is the best guess, LC_TIME
-     // and LC_MONETARY may be set differently for a Japanese working in the
-     // US.
-     p = get_locale_val(LC_COLLATE);
- #  endif
- # else
-     p = mch_getenv((char_u *)"LC_ALL");
-     if (!is_valid_mess_lang(p))
-     {
-       p = mch_getenv((char_u *)"LC_MESSAGES");
-       if (!is_valid_mess_lang(p))
-           p = mch_getenv((char_u *)"LANG");
-     }
- # endif
- # ifdef MSWIN
-     p = gettext_lang(p);
- # endif
-     return is_valid_mess_lang(p) ? p : NULL;
- }
- #endif
- 
- // Complicated #if; matches with where get_mess_env() is used below.
- #if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
-           && defined(LC_MESSAGES))) \
-       || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
-               && !defined(LC_MESSAGES))
- /*
-  * Get the language used for messages from the environment.
-  */
-     static char_u *
- get_mess_env(void)
- {
-     char_u    *p;
- 
-     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");
-           if (p != NULL && VIM_ISDIGIT(*p))
-               p = NULL;               // ignore something like "1043"
- # ifdef HAVE_GET_LOCALE_VAL
-           if (p == NULL || *p == NUL)
-               p = get_locale_val(LC_CTYPE);
- # endif
-       }
-     }
-     return p;
- }
- #endif
- 
- #if defined(FEAT_EVAL) || defined(PROTO)
- 
- /*
-  * Set the "v:lang" variable according to the current locale setting.
-  * Also do "v:lc_time"and "v:ctype".
-  */
-     void
- set_lang_var(void)
- {
-     char_u    *loc;
- 
- # ifdef HAVE_GET_LOCALE_VAL
-     loc = get_locale_val(LC_CTYPE);
- # else
-     // setlocale() not supported: use the default value
-     loc = (char_u *)"C";
- # endif
-     set_vim_var_string(VV_CTYPE, loc, -1);
- 
-     // When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
-     // back to LC_CTYPE if it's empty.
- # if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
-     loc = get_locale_val(LC_MESSAGES);
- # else
-     loc = get_mess_env();
- # endif
-     set_vim_var_string(VV_LANG, loc, -1);
- 
- # ifdef HAVE_GET_LOCALE_VAL
-     loc = get_locale_val(LC_TIME);
- # endif
-     set_vim_var_string(VV_LC_TIME, loc, -1);
- 
- # ifdef HAVE_GET_LOCALE_VAL
-     loc = get_locale_val(LC_COLLATE);
- # else
-     // setlocale() not supported: use the default value
-     loc = (char_u *)"C";
- # endif
-     set_vim_var_string(VV_COLLATE, loc, -1);
- }
- #endif
- 
- #if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
- /*
-  * ":language":  Set the language (locale).
-  */
-     void
- ex_language(exarg_T *eap)
- {
-     char      *loc;
-     char_u    *p;
-     char_u    *name;
-     int               what = LC_ALL;
-     char      *whatstr = "";
- # ifdef LC_MESSAGES
- #  define VIM_LC_MESSAGES LC_MESSAGES
- # else
- #  define VIM_LC_MESSAGES 6789
- # endif
- 
-     name = eap->arg;
- 
-     // Check for "messages {name}", "ctype {name}" or "time {name}" argument.
-     // Allow abbreviation, but require at least 3 characters to avoid
-     // confusion with a two letter language name "me" or "ct".
-     p = skiptowhite(eap->arg);
-     if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
-     {
-       if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
-       {
-           what = VIM_LC_MESSAGES;
-           name = skipwhite(p);
-           whatstr = "messages ";
-       }
-       else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
-       {
-           what = LC_CTYPE;
-           name = skipwhite(p);
-           whatstr = "ctype ";
-       }
-       else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
-       {
-           what = LC_TIME;
-           name = skipwhite(p);
-           whatstr = "time ";
-       }
-       else if (STRNICMP(eap->arg, "collate", p - eap->arg) == 0)
-       {
-           what = LC_COLLATE;
-           name = skipwhite(p);
-           whatstr = "collate ";
-       }
-     }
- 
-     if (*name == NUL)
-     {
- # ifndef LC_MESSAGES
-       if (what == VIM_LC_MESSAGES)
-           p = get_mess_env();
-       else
- # endif
-           p = (char_u *)setlocale(what, NULL);
-       if (p == NULL || *p == NUL)
-           p = (char_u *)"Unknown";
-       smsg(_("Current %slanguage: \"%s\""), whatstr, p);
-     }
-     else
-     {
- # ifndef LC_MESSAGES
-       if (what == VIM_LC_MESSAGES)
-           loc = "";
-       else
- # endif
-       {
-           loc = setlocale(what, (char *)name);
- # if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
-           // Make sure strtod() uses a decimal point, not a comma.
-           setlocale(LC_NUMERIC, "C");
- # endif
-       }
-       if (loc == NULL)
-           semsg(_("E197: Cannot set language to \"%s\""), name);
-       else
-       {
- # ifdef HAVE_NL_MSG_CAT_CNTR
-           // Need to do this for GNU gettext, otherwise cached translations
-           // will be used again.
-           extern int _nl_msg_cat_cntr;
- 
-           ++_nl_msg_cat_cntr;
- # endif
-           // Reset $LC_ALL, otherwise it would overrule everything.
-           vim_setenv((char_u *)"LC_ALL", (char_u *)"");
- 
-           if (what != LC_TIME && what != LC_COLLATE)
-           {
-               // Tell gettext() what to translate to.  It apparently doesn't
-               // use the currently effective locale.  Also do this when
-               // FEAT_GETTEXT isn't defined, so that shell commands use this
-               // value.
-               if (what == LC_ALL)
-               {
-                   vim_setenv((char_u *)"LANG", name);
- 
-                   // Clear $LANGUAGE because GNU gettext uses it.
-                   vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
- # ifdef MSWIN
-                   // Apparently MS-Windows printf() may cause a crash when
-                   // we give it 8-bit text while it's expecting text in the
-                   // current locale.  This call avoids that.
-                   setlocale(LC_CTYPE, "C");
- # endif
-               }
-               if (what != LC_CTYPE)
-               {
-                   char_u      *mname;
- # ifdef MSWIN
-                   mname = gettext_lang(name);
- # else
-                   mname = name;
- # endif
-                   vim_setenv((char_u *)"LC_MESSAGES", mname);
- # ifdef FEAT_MULTI_LANG
-                   set_helplang_default(mname);
- # endif
-               }
-           }
- 
- # ifdef FEAT_EVAL
-           // Set v:lang, v:lc_time, v:collate and v:ctype to the final result.
-           set_lang_var();
- # endif
- # ifdef FEAT_TITLE
-           maketitle();
- # endif
-       }
-     }
- }
- 
- static char_u **locales = NULL;       // Array of all available locales
- 
- static int    did_init_locales = FALSE;
- 
- /*
-  * Return an array of strings for all available locales + NULL for the
-  * last element.  Return NULL in case of error.
-  */
-     static char_u **
- find_locales(void)
- {
-     garray_T  locales_ga;
-     char_u    *loc;
-     char_u    *locale_list;
- # ifdef MSWIN
-     size_t    len = 0;
- # endif
- 
-     // Find all available locales by running command "locale -a".  If this
-     // doesn't work we won't have completion.
- # ifndef MSWIN
-     locale_list = get_cmd_output((char_u *)"locale -a",
-                                                   NULL, SHELL_SILENT, NULL);
- # else
-     // Find all available locales by examining the directories in
-     // $VIMRUNTIME/lang/
-     {
-       int             options = WILD_SILENT|WILD_USE_NL|WILD_KEEP_ALL;
-       expand_T        xpc;
-       char_u          *p;
- 
-       ExpandInit(&xpc);
-       xpc.xp_context = EXPAND_DIRECTORIES;
-       locale_list = ExpandOne(&xpc, (char_u *)"$VIMRUNTIME/lang/*",
-                                                     NULL, options, WILD_ALL);
-       ExpandCleanup(&xpc);
-       if (locale_list == NULL)
-           // Add a dummy input, that will be skipped lated but we need to
-           // have something in locale_list so that the C locale is added at
-           // the end.
-           locale_list = vim_strsave((char_u *)".\n");
-       p = locale_list;
-       // find the last directory delimiter
-       while (p != NULL && *p != NUL)
-       {
-           if (*p == '\n')
-               break;
-           if (*p == '\\')
-               len = p - locale_list;
-           p++;
-       }
-     }
- # endif
-     if (locale_list == NULL)
-       return NULL;
-     ga_init2(&locales_ga, sizeof(char_u *), 20);
- 
-     // Transform locale_list string where each locale is separated by "\n"
-     // into an array of locale strings.
-     loc = (char_u *)strtok((char *)locale_list, "\n");
- 
-     while (loc != NULL)
-     {
-       int ignore = FALSE;
- 
- # ifdef MSWIN
-       if (len > 0)
-           loc += len + 1;
-       // skip locales with a dot (which indicates the charset)
-       if (vim_strchr(loc, '.') != NULL)
-           ignore = TRUE;
- # endif
-       if (!ignore)
-       {
-           if (ga_grow(&locales_ga, 1) == FAIL)
-               break;
- 
-           loc = vim_strsave(loc);
-           if (loc == NULL)
-               break;
- 
-           ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
-       }
-       loc = (char_u *)strtok(NULL, "\n");
-     }
- 
- # ifdef MSWIN
-     // Add the C locale
-     if (ga_grow(&locales_ga, 1) == OK)
-       ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] =
-                                                   vim_strsave((char_u *)"C");
- # endif
- 
-     vim_free(locale_list);
-     if (ga_grow(&locales_ga, 1) == FAIL)
-     {
-       ga_clear(&locales_ga);
-       return NULL;
-     }
-     ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
-     return (char_u **)locales_ga.ga_data;
- }
- 
- /*
-  * Lazy initialization of all available locales.
-  */
-     static void
- init_locales(void)
- {
-     if (!did_init_locales)
-     {
-       did_init_locales = TRUE;
-       locales = find_locales();
-     }
- }
- 
- # if defined(EXITFREE) || defined(PROTO)
-     void
- free_locales(void)
- {
-     int                       i;
-     if (locales != NULL)
-     {
-       for (i = 0; locales[i] != NULL; i++)
-           vim_free(locales[i]);
-       VIM_CLEAR(locales);
-     }
- }
- # endif
- 
- /*
-  * Function given to ExpandGeneric() to obtain the possible arguments of the
-  * ":language" command.
-  */
-     char_u *
- get_lang_arg(expand_T *xp UNUSED, int idx)
- {
-     if (idx == 0)
-       return (char_u *)"messages";
-     if (idx == 1)
-       return (char_u *)"ctype";
-     if (idx == 2)
-       return (char_u *)"time";
-     if (idx == 3)
-       return (char_u *)"collate";
- 
-     init_locales();
-     if (locales == NULL)
-       return NULL;
-     return locales[idx - 4];
- }
- 
- /*
-  * Function given to ExpandGeneric() to obtain the available locales.
-  */
-     char_u *
- get_locales(expand_T *xp UNUSED, int idx)
- {
-     init_locales();
-     if (locales == NULL)
-       return NULL;
-     return locales[idx];
- }
- 
- #endif
--- 996,998 ----
*** ../vim-8.2.1268/src/locale.c        2020-07-22 19:10:21.069268953 +0200
--- src/locale.c        2020-07-22 19:03:10.315786917 +0200
***************
*** 0 ****
--- 1,564 ----
+ /* vi:set ts=8 sts=4 sw=4 noet:
+  *
+  * VIM - Vi IMproved  by Bram Moolenaar
+  *
+  * Do ":help uganda"  in Vim to read copying and usage conditions.
+  * Do ":help credits" in Vim to see a list of people who contributed.
+  * See README.txt for an overview of the Vim source code.
+  */
+ 
+ /*
+  * locale.c: functions for language/locale configuration
+  */
+ 
+ #include "vim.h"
+ 
+ #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
+       && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
+ # define HAVE_GET_LOCALE_VAL
+     static char_u *
+ get_locale_val(int what)
+ {
+     char_u    *loc;
+ 
+     // Obtain the locale value from the libraries.
+     loc = (char_u *)setlocale(what, NULL);
+ 
+ # ifdef MSWIN
+     if (loc != NULL)
+     {
+       char_u  *p;
+ 
+       // setocale() returns something like "LC_COLLATE=<name>;LC_..." when
+       // one of the values (e.g., LC_CTYPE) differs.
+       p = vim_strchr(loc, '=');
+       if (p != NULL)
+       {
+           loc = ++p;
+           while (*p != NUL)   // remove trailing newline
+           {
+               if (*p < ' ' || *p == ';')
+               {
+                   *p = NUL;
+                   break;
+               }
+               ++p;
+           }
+       }
+     }
+ # endif
+ 
+     return loc;
+ }
+ #endif
+ 
+ 
+ #ifdef MSWIN
+ /*
+  * 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 (char_u *)mtable[i + 1];
+     return name;
+ }
+ #endif
+ 
+ #if defined(FEAT_MULTI_LANG) || defined(PROTO)
+ /*
+  * Return TRUE when "lang" starts with a valid language name.
+  * Rejects NULL, empty string, "C", "C.UTF-8" and others.
+  */
+     static int
+ is_valid_mess_lang(char_u *lang)
+ {
+     return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
+ }
+ 
+ /*
+  * Obtain the current messages language.  Used to set the default for
+  * 'helplang'.  May return NULL or an empty string.
+  */
+     char_u *
+ get_mess_lang(void)
+ {
+     char_u *p;
+ 
+ # ifdef HAVE_GET_LOCALE_VAL
+ #  if defined(LC_MESSAGES)
+     p = 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.  LC_COLLATE is the best guess, LC_TIME
+     // and LC_MONETARY may be set differently for a Japanese working in the
+     // US.
+     p = get_locale_val(LC_COLLATE);
+ #  endif
+ # else
+     p = mch_getenv((char_u *)"LC_ALL");
+     if (!is_valid_mess_lang(p))
+     {
+       p = mch_getenv((char_u *)"LC_MESSAGES");
+       if (!is_valid_mess_lang(p))
+           p = mch_getenv((char_u *)"LANG");
+     }
+ # endif
+ # ifdef MSWIN
+     p = gettext_lang(p);
+ # endif
+     return is_valid_mess_lang(p) ? p : NULL;
+ }
+ #endif
+ 
+ // Complicated #if; matches with where get_mess_env() is used below.
+ #if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
+           && defined(LC_MESSAGES))) \
+       || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
+               && !defined(LC_MESSAGES))
+ /*
+  * Get the language used for messages from the environment.
+  */
+     static char_u *
+ get_mess_env(void)
+ {
+     char_u    *p;
+ 
+     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");
+           if (p != NULL && VIM_ISDIGIT(*p))
+               p = NULL;               // ignore something like "1043"
+ # ifdef HAVE_GET_LOCALE_VAL
+           if (p == NULL || *p == NUL)
+               p = get_locale_val(LC_CTYPE);
+ # endif
+       }
+     }
+     return p;
+ }
+ #endif
+ 
+ #if defined(FEAT_EVAL) || defined(PROTO)
+ 
+ /*
+  * Set the "v:lang" variable according to the current locale setting.
+  * Also do "v:lc_time"and "v:ctype".
+  */
+     void
+ set_lang_var(void)
+ {
+     char_u    *loc;
+ 
+ # ifdef HAVE_GET_LOCALE_VAL
+     loc = get_locale_val(LC_CTYPE);
+ # else
+     // setlocale() not supported: use the default value
+     loc = (char_u *)"C";
+ # endif
+     set_vim_var_string(VV_CTYPE, loc, -1);
+ 
+     // When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
+     // back to LC_CTYPE if it's empty.
+ # if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
+     loc = get_locale_val(LC_MESSAGES);
+ # else
+     loc = get_mess_env();
+ # endif
+     set_vim_var_string(VV_LANG, loc, -1);
+ 
+ # ifdef HAVE_GET_LOCALE_VAL
+     loc = get_locale_val(LC_TIME);
+ # endif
+     set_vim_var_string(VV_LC_TIME, loc, -1);
+ 
+ # ifdef HAVE_GET_LOCALE_VAL
+     loc = get_locale_val(LC_COLLATE);
+ # else
+     // setlocale() not supported: use the default value
+     loc = (char_u *)"C";
+ # endif
+     set_vim_var_string(VV_COLLATE, loc, -1);
+ }
+ #endif
+ 
+ #if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+ /*
+  * Setup to use the current locale (for ctype() and many other things).
+  */
+     void
+ init_locale(void)
+ {
+     setlocale(LC_ALL, "");
+ 
+ # ifdef FEAT_GUI_GTK
+     // Tell Gtk not to change our locale settings.
+     gtk_disable_setlocale();
+ # endif
+ # if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
+     // Make sure strtod() uses a decimal point, not a comma.
+     setlocale(LC_NUMERIC, "C");
+ # endif
+ 
+ # ifdef MSWIN
+     // Apparently MS-Windows printf() may cause a crash when we give it 8-bit
+     // text while it's expecting text in the current locale.  This call avoids
+     // that.
+     setlocale(LC_CTYPE, "C");
+ # endif
+ 
+ # ifdef FEAT_GETTEXT
+     {
+       int     mustfree = FALSE;
+       char_u  *p;
+ 
+ #  ifdef DYNAMIC_GETTEXT
+       // Initialize the gettext library
+       dyn_libintl_init();
+ #  endif
+       // expand_env() doesn't work yet, because g_chartab[] is not
+       // initialized yet, call vim_getenv() directly
+       p = vim_getenv((char_u *)"VIMRUNTIME", &mustfree);
+       if (p != NULL && *p != NUL)
+       {
+           vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p);
+           bindtextdomain(VIMPACKAGE, (char *)NameBuff);
+       }
+       if (mustfree)
+           vim_free(p);
+       textdomain(VIMPACKAGE);
+     }
+ # endif
+ }
+ 
+ /*
+  * ":language":  Set the language (locale).
+  */
+     void
+ ex_language(exarg_T *eap)
+ {
+     char      *loc;
+     char_u    *p;
+     char_u    *name;
+     int               what = LC_ALL;
+     char      *whatstr = "";
+ # ifdef LC_MESSAGES
+ #  define VIM_LC_MESSAGES LC_MESSAGES
+ # else
+ #  define VIM_LC_MESSAGES 6789
+ # endif
+ 
+     name = eap->arg;
+ 
+     // Check for "messages {name}", "ctype {name}" or "time {name}" argument.
+     // Allow abbreviation, but require at least 3 characters to avoid
+     // confusion with a two letter language name "me" or "ct".
+     p = skiptowhite(eap->arg);
+     if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
+     {
+       if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
+       {
+           what = VIM_LC_MESSAGES;
+           name = skipwhite(p);
+           whatstr = "messages ";
+       }
+       else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
+       {
+           what = LC_CTYPE;
+           name = skipwhite(p);
+           whatstr = "ctype ";
+       }
+       else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
+       {
+           what = LC_TIME;
+           name = skipwhite(p);
+           whatstr = "time ";
+       }
+       else if (STRNICMP(eap->arg, "collate", p - eap->arg) == 0)
+       {
+           what = LC_COLLATE;
+           name = skipwhite(p);
+           whatstr = "collate ";
+       }
+     }
+ 
+     if (*name == NUL)
+     {
+ # ifndef LC_MESSAGES
+       if (what == VIM_LC_MESSAGES)
+           p = get_mess_env();
+       else
+ # endif
+           p = (char_u *)setlocale(what, NULL);
+       if (p == NULL || *p == NUL)
+           p = (char_u *)"Unknown";
+       smsg(_("Current %slanguage: \"%s\""), whatstr, p);
+     }
+     else
+     {
+ # ifndef LC_MESSAGES
+       if (what == VIM_LC_MESSAGES)
+           loc = "";
+       else
+ # endif
+       {
+           loc = setlocale(what, (char *)name);
+ # if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
+           // Make sure strtod() uses a decimal point, not a comma.
+           setlocale(LC_NUMERIC, "C");
+ # endif
+       }
+       if (loc == NULL)
+           semsg(_("E197: Cannot set language to \"%s\""), name);
+       else
+       {
+ # ifdef HAVE_NL_MSG_CAT_CNTR
+           // Need to do this for GNU gettext, otherwise cached translations
+           // will be used again.
+           extern int _nl_msg_cat_cntr;
+ 
+           ++_nl_msg_cat_cntr;
+ # endif
+           // Reset $LC_ALL, otherwise it would overrule everything.
+           vim_setenv((char_u *)"LC_ALL", (char_u *)"");
+ 
+           if (what != LC_TIME && what != LC_COLLATE)
+           {
+               // Tell gettext() what to translate to.  It apparently doesn't
+               // use the currently effective locale.  Also do this when
+               // FEAT_GETTEXT isn't defined, so that shell commands use this
+               // value.
+               if (what == LC_ALL)
+               {
+                   vim_setenv((char_u *)"LANG", name);
+ 
+                   // Clear $LANGUAGE because GNU gettext uses it.
+                   vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
+ # ifdef MSWIN
+                   // Apparently MS-Windows printf() may cause a crash when
+                   // we give it 8-bit text while it's expecting text in the
+                   // current locale.  This call avoids that.
+                   setlocale(LC_CTYPE, "C");
+ # endif
+               }
+               if (what != LC_CTYPE)
+               {
+                   char_u      *mname;
+ # ifdef MSWIN
+                   mname = gettext_lang(name);
+ # else
+                   mname = name;
+ # endif
+                   vim_setenv((char_u *)"LC_MESSAGES", mname);
+ # ifdef FEAT_MULTI_LANG
+                   set_helplang_default(mname);
+ # endif
+               }
+           }
+ 
+ # ifdef FEAT_EVAL
+           // Set v:lang, v:lc_time, v:collate and v:ctype to the final result.
+           set_lang_var();
+ # endif
+ # ifdef FEAT_TITLE
+           maketitle();
+ # endif
+       }
+     }
+ }
+ 
+ static char_u **locales = NULL;       // Array of all available locales
+ 
+ static int    did_init_locales = FALSE;
+ 
+ /*
+  * Return an array of strings for all available locales + NULL for the
+  * last element.  Return NULL in case of error.
+  */
+     static char_u **
+ find_locales(void)
+ {
+     garray_T  locales_ga;
+     char_u    *loc;
+     char_u    *locale_list;
+ # ifdef MSWIN
+     size_t    len = 0;
+ # endif
+ 
+     // Find all available locales by running command "locale -a".  If this
+     // doesn't work we won't have completion.
+ # ifndef MSWIN
+     locale_list = get_cmd_output((char_u *)"locale -a",
+                                                   NULL, SHELL_SILENT, NULL);
+ # else
+     // Find all available locales by examining the directories in
+     // $VIMRUNTIME/lang/
+     {
+       int             options = WILD_SILENT|WILD_USE_NL|WILD_KEEP_ALL;
+       expand_T        xpc;
+       char_u          *p;
+ 
+       ExpandInit(&xpc);
+       xpc.xp_context = EXPAND_DIRECTORIES;
+       locale_list = ExpandOne(&xpc, (char_u *)"$VIMRUNTIME/lang/*",
+                                                     NULL, options, WILD_ALL);
+       ExpandCleanup(&xpc);
+       if (locale_list == NULL)
+           // Add a dummy input, that will be skipped lated but we need to
+           // have something in locale_list so that the C locale is added at
+           // the end.
+           locale_list = vim_strsave((char_u *)".\n");
+       p = locale_list;
+       // find the last directory delimiter
+       while (p != NULL && *p != NUL)
+       {
+           if (*p == '\n')
+               break;
+           if (*p == '\\')
+               len = p - locale_list;
+           p++;
+       }
+     }
+ # endif
+     if (locale_list == NULL)
+       return NULL;
+     ga_init2(&locales_ga, sizeof(char_u *), 20);
+ 
+     // Transform locale_list string where each locale is separated by "\n"
+     // into an array of locale strings.
+     loc = (char_u *)strtok((char *)locale_list, "\n");
+ 
+     while (loc != NULL)
+     {
+       int ignore = FALSE;
+ 
+ # ifdef MSWIN
+       if (len > 0)
+           loc += len + 1;
+       // skip locales with a dot (which indicates the charset)
+       if (vim_strchr(loc, '.') != NULL)
+           ignore = TRUE;
+ # endif
+       if (!ignore)
+       {
+           if (ga_grow(&locales_ga, 1) == FAIL)
+               break;
+ 
+           loc = vim_strsave(loc);
+           if (loc == NULL)
+               break;
+ 
+           ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
+       }
+       loc = (char_u *)strtok(NULL, "\n");
+     }
+ 
+ # ifdef MSWIN
+     // Add the C locale
+     if (ga_grow(&locales_ga, 1) == OK)
+       ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] =
+                                                   vim_strsave((char_u *)"C");
+ # endif
+ 
+     vim_free(locale_list);
+     if (ga_grow(&locales_ga, 1) == FAIL)
+     {
+       ga_clear(&locales_ga);
+       return NULL;
+     }
+     ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
+     return (char_u **)locales_ga.ga_data;
+ }
+ 
+ /*
+  * Lazy initialization of all available locales.
+  */
+     static void
+ init_locales(void)
+ {
+     if (!did_init_locales)
+     {
+       did_init_locales = TRUE;
+       locales = find_locales();
+     }
+ }
+ 
+ # if defined(EXITFREE) || defined(PROTO)
+     void
+ free_locales(void)
+ {
+     int                       i;
+     if (locales != NULL)
+     {
+       for (i = 0; locales[i] != NULL; i++)
+           vim_free(locales[i]);
+       VIM_CLEAR(locales);
+     }
+ }
+ # endif
+ 
+ /*
+  * Function given to ExpandGeneric() to obtain the possible arguments of the
+  * ":language" command.
+  */
+     char_u *
+ get_lang_arg(expand_T *xp UNUSED, int idx)
+ {
+     if (idx == 0)
+       return (char_u *)"messages";
+     if (idx == 1)
+       return (char_u *)"ctype";
+     if (idx == 2)
+       return (char_u *)"time";
+     if (idx == 3)
+       return (char_u *)"collate";
+ 
+     init_locales();
+     if (locales == NULL)
+       return NULL;
+     return locales[idx - 4];
+ }
+ 
+ /*
+  * Function given to ExpandGeneric() to obtain the available locales.
+  */
+     char_u *
+ get_locales(expand_T *xp UNUSED, int idx)
+ {
+     init_locales();
+     if (locales == NULL)
+       return NULL;
+     return locales[idx];
+ }
+ 
+ #endif
*** ../vim-8.2.1268/src/main.c  2020-06-13 15:47:21.070282268 +0200
--- src/main.c  2020-07-22 19:03:10.315786917 +0200
***************
*** 34,42 ****
  static int file_owned(char *fname);
  #endif
  static void mainerr(int, char_u *);
- # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
- static void init_locale(void);
- # endif
  static void early_arg_scan(mparm_T *parmp);
  #ifndef NO_VIM_MAIN
  static void usage(void);
--- 34,39 ----
***************
*** 1716,1771 ****
      mch_exit(exitval);
  }
  
- #if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
- /*
-  * Setup to use the current locale (for ctype() and many other things).
-  */
-     static void
- init_locale(void)
- {
-     setlocale(LC_ALL, "");
- 
- # ifdef FEAT_GUI_GTK
-     // Tell Gtk not to change our locale settings.
-     gtk_disable_setlocale();
- # endif
- # if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
-     // Make sure strtod() uses a decimal point, not a comma.
-     setlocale(LC_NUMERIC, "C");
- # endif
- 
- # ifdef MSWIN
-     // Apparently MS-Windows printf() may cause a crash when we give it 8-bit
-     // text while it's expecting text in the current locale.  This call avoids
-     // that.
-     setlocale(LC_CTYPE, "C");
- # endif
- 
- # ifdef FEAT_GETTEXT
-     {
-       int     mustfree = FALSE;
-       char_u  *p;
- 
- #  ifdef DYNAMIC_GETTEXT
-       // Initialize the gettext library
-       dyn_libintl_init();
- #  endif
-       // expand_env() doesn't work yet, because g_chartab[] is not
-       // initialized yet, call vim_getenv() directly
-       p = vim_getenv((char_u *)"VIMRUNTIME", &mustfree);
-       if (p != NULL && *p != NUL)
-       {
-           vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p);
-           bindtextdomain(VIMPACKAGE, (char *)NameBuff);
-       }
-       if (mustfree)
-           vim_free(p);
-       textdomain(VIMPACKAGE);
-     }
- # endif
- }
- #endif
- 
  /*
   * Get the name of the display, before gui_prepare() removes it from
   * argv[].  Used for the xterm-clipboard display.
--- 1713,1718 ----
*** ../vim-8.2.1268/src/proto.h 2020-07-21 21:07:00.720496743 +0200
--- src/proto.h 2020-07-22 19:03:10.315786917 +0200
***************
*** 101,106 ****
--- 101,107 ----
  # include "insexpand.pro"
  # include "json.pro"
  # include "list.pro"
+ # include "locale.pro"
  # include "blob.pro"
  # include "main.pro"
  # include "map.pro"
*** ../vim-8.2.1268/src/proto/ex_cmds2.pro      2020-02-14 13:21:55.646197062 
+0100
--- src/proto/ex_cmds2.pro      2020-07-22 19:03:10.315786917 +0200
***************
*** 15,24 ****
  void ex_pyx(exarg_T *eap);
  void ex_pyxdo(exarg_T *eap);
  void ex_checktime(exarg_T *eap);
- char_u *get_mess_lang(void);
- void set_lang_var(void);
- void ex_language(exarg_T *eap);
- void free_locales(void);
- char_u *get_lang_arg(expand_T *xp, int idx);
- char_u *get_locales(expand_T *xp, int idx);
  /* vim: set ft=c : */
--- 15,18 ----
*** ../vim-8.2.1268/src/proto/locale.pro        2020-07-22 19:10:21.085268870 
+0200
--- src/proto/locale.pro        2020-07-22 19:03:10.315786917 +0200
***************
*** 0 ****
--- 1,9 ----
+ /* locale.c */
+ char_u *get_mess_lang(void);
+ void set_lang_var(void);
+ void init_locale(void);
+ void ex_language(exarg_T *eap);
+ void free_locales(void);
+ char_u *get_lang_arg(expand_T *xp, int idx);
+ char_u *get_locales(expand_T *xp, int idx);
+ /* vim: set ft=c : */
*** ../vim-8.2.1268/src/version.c       2020-07-22 18:17:04.235863872 +0200
--- src/version.c       2020-07-22 19:06:29.514532644 +0200
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     1269,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
57. You begin to wonder how on earth your service provider is allowed to call
    200 hours per month "unlimited."

 /// Bram Moolenaar -- [email protected] -- 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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202007221711.06MHBkXF1071634%40masaka.moolenaar.net.

Raspunde prin e-mail lui