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 -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language --
http://www.Zimbu.org ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///