]> granicus.if.org Git - vim/commitdiff
patch 8.2.1269: language and locale code spread out v8.2.1269
authorBram Moolenaar <Bram@vim.org>
Wed, 22 Jul 2020 17:11:19 +0000 (19:11 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 22 Jul 2020 17:11:19 +0000 (19:11 +0200)
Problem:    Language and locale code spread out.
Solution:   Move relevant code to src/locale.c. (Yegappan Lakshmanan,
            closes #6509)

14 files changed:
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 [new file with mode: 0644]
src/main.c
src/proto.h
src/proto/ex_cmds2.pro
src/proto/locale.pro [new file with mode: 0644]
src/version.c

index 77fabbebffe9e3965ea69696fadbc3f5becb2559..1e22554d40aced383fa13b076530322964b2c736 100644 (file)
--- a/Filelist
+++ b/Filelist
@@ -76,6 +76,7 @@ SRC_ALL =     \
                src/json_test.c \
                src/kword_test.c \
                src/list.c \
+               src/locale.c \
                src/keymap.h \
                src/macros.h \
                src/main.c \
@@ -247,6 +248,7 @@ SRC_ALL =   \
                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 \
index 3e8bb04e0fb3d995b83a6b7e63e2c59ad4841c09..dedc98d7905944478b29cbad8e4a4c85a2a44271 100644 (file)
@@ -751,6 +751,7 @@ OBJ = \
        $(OUTDIR)/insexpand.o \
        $(OUTDIR)/json.o \
        $(OUTDIR)/list.o \
+       $(OUTDIR)/locale.o \
        $(OUTDIR)/main.o \
        $(OUTDIR)/map.o \
        $(OUTDIR)/mark.o \
index 6fc50ed1fd16eb796c941df69cb1b470617df362..d293829ae1657fb0abf676b303c26a81c740f281 100644 (file)
@@ -70,6 +70,7 @@ SRC = arabic.c                                                \
        insexpand.c                                             \
        json.c                                                  \
        list.c                                                  \
+       locale.c                                                \
        main.c                                                  \
        map.c                                                   \
        mark.c                                                  \
index 65d530f359c023ff5f185cac0a7f5e1603ee8d46..3b72001a80983bcc6d3f49053f7c90e3d72956a2 100644 (file)
@@ -773,6 +773,7 @@ OBJ = \
        $(OUTDIR)\insexpand.obj \
        $(OUTDIR)\json.obj \
        $(OUTDIR)\list.obj \
+       $(OUTDIR)\locale.obj \
        $(OUTDIR)\main.obj \
        $(OUTDIR)\map.obj \
        $(OUTDIR)\mark.obj \
@@ -1669,6 +1670,8 @@ $(OUTDIR)/json.obj:       $(OUTDIR) json.c  $(INCL)
 
 $(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,6 +1942,7 @@ proto.h: \
        proto/insexpand.pro \
        proto/json.pro \
        proto/list.pro \
+       proto/locale.pro \
        proto/main.pro \
        proto/map.pro \
        proto/mark.pro \
index 0d80c0617b598dfbce1dad42ce2e9d7f282cb238..83b31f2979669f0a0da0466c4a50a2fdc7877748 100644 (file)
@@ -345,6 +345,7 @@ SRC = \
        insexpand.c \
        json.c \
        list.c \
+       locale.c \
        main.c \
        map.c \
        mark.c \
@@ -460,6 +461,7 @@ OBJ = \
        insexpand.obj \
        json.obj \
        list.obj \
+       locale.obj \
        main.obj \
        map.obj \
        mark.obj \
@@ -865,6 +867,10 @@ list.obj : list.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
+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 \
index bac4e1273b9d2639ccc565b46b3d69e7b7150663..8ac7dc58beb7fdaa7bd773ab9d77860dd59fd961 100644 (file)
@@ -1647,6 +1647,7 @@ BASIC_SRC = \
        insexpand.c \
        json.c \
        list.c \
+       locale.c \
        main.c \
        map.c \
        mark.c \
@@ -1798,6 +1799,7 @@ OBJ_COMMON = \
        objects/indent.o \
        objects/insexpand.o \
        objects/list.o \
+       objects/locale.o \
        objects/map.o \
        objects/mark.o \
        objects/match.o \
@@ -1973,6 +1975,7 @@ PRO_AUTO = \
        insexpand.pro \
        json.pro \
        list.pro \
+       locale.pro \
        main.pro \
        map.pro \
        mark.pro \
@@ -3378,6 +3381,9 @@ objects/kword_test.o: kword_test.c
 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,6 +3974,10 @@ objects/list.o: list.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/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 \
index f499c4cdb21d273f830a059a1cc52478973493cb..b4d9bdd89a3b5e79e09fa6b7ccb9751259cb837e 100644 (file)
@@ -52,6 +52,7 @@ help.c                | vim help related functions
 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
index f0b5bfd45199ff6a7f432d000889f3dbd11e557e..738bdb11d3f706cbf3ccd3f2ae416d3ec47c5533 100644 (file)
@@ -996,505 +996,3 @@ ex_checktime(exarg_T *eap)
     }
     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
diff --git a/src/locale.c b/src/locale.c
new file mode 100644 (file)
index 0000000..7fad9d9
--- /dev/null
@@ -0,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
index 39e67e998793cb58d9c5efbcac63263287243b88..86156b7281faad2dc2f4aa24fdc88007b9a24e39 100644 (file)
@@ -34,9 +34,6 @@
 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);
@@ -1716,56 +1713,6 @@ getout(int exitval)
     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.
index e3a25f9882fcf90bdfb4a8e31c18f5bf0d82f208..95fd81ac96c3aeffaac10c7c35f528d1136a14d1 100644 (file)
@@ -101,6 +101,7 @@ extern int _stricoll(char *a, char *b);
 # include "insexpand.pro"
 # include "json.pro"
 # include "list.pro"
+# include "locale.pro"
 # include "blob.pro"
 # include "main.pro"
 # include "map.pro"
index b9d1929f7dd87b24e00adcdfe1c691893655951a..127e018074251c219d6b94241bb40bf7f8ec5c7b 100644 (file)
@@ -15,10 +15,4 @@ void ex_pyxfile(exarg_T *eap);
 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 : */
diff --git a/src/proto/locale.pro b/src/proto/locale.pro
new file mode 100644 (file)
index 0000000..151e68a
--- /dev/null
@@ -0,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 : */
index 1ab604036ba3e9df82fd8a2707d2a24d54a41ace..cf64327208790db272e7ab89bc94abebb98bdaf0 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1269,
 /**/
     1268,
 /**/