patch 8.2.1269: language and locale code spread out
Problem:    Language and locale code spread out.
Solution:   Move relevant code to src/locale.c. (Yegappan Lakshmanan,
            closes #6509)
			
			
This commit is contained in:
		
							
								
								
									
										2
									
								
								Filelist
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Filelist
									
									
									
									
									
								
							| @ -76,6 +76,7 @@ SRC_ALL =	\ | |||||||
| 		src/json_test.c \ | 		src/json_test.c \ | ||||||
| 		src/kword_test.c \ | 		src/kword_test.c \ | ||||||
| 		src/list.c \ | 		src/list.c \ | ||||||
|  | 		src/locale.c \ | ||||||
| 		src/keymap.h \ | 		src/keymap.h \ | ||||||
| 		src/macros.h \ | 		src/macros.h \ | ||||||
| 		src/main.c \ | 		src/main.c \ | ||||||
| @ -247,6 +248,7 @@ SRC_ALL =	\ | |||||||
| 		src/proto/insexpand.pro \ | 		src/proto/insexpand.pro \ | ||||||
| 		src/proto/json.pro \ | 		src/proto/json.pro \ | ||||||
| 		src/proto/list.pro \ | 		src/proto/list.pro \ | ||||||
|  | 		src/proto/locale.pro \ | ||||||
| 		src/proto/main.pro \ | 		src/proto/main.pro \ | ||||||
| 		src/proto/map.pro \ | 		src/proto/map.pro \ | ||||||
| 		src/proto/mark.pro \ | 		src/proto/mark.pro \ | ||||||
|  | |||||||
| @ -751,6 +751,7 @@ OBJ = \ | |||||||
| 	$(OUTDIR)/insexpand.o \ | 	$(OUTDIR)/insexpand.o \ | ||||||
| 	$(OUTDIR)/json.o \ | 	$(OUTDIR)/json.o \ | ||||||
| 	$(OUTDIR)/list.o \ | 	$(OUTDIR)/list.o \ | ||||||
|  | 	$(OUTDIR)/locale.o \ | ||||||
| 	$(OUTDIR)/main.o \ | 	$(OUTDIR)/main.o \ | ||||||
| 	$(OUTDIR)/map.o \ | 	$(OUTDIR)/map.o \ | ||||||
| 	$(OUTDIR)/mark.o \ | 	$(OUTDIR)/mark.o \ | ||||||
|  | |||||||
| @ -70,6 +70,7 @@ SRC =	arabic.c						\ | |||||||
| 	insexpand.c						\ | 	insexpand.c						\ | ||||||
| 	json.c							\ | 	json.c							\ | ||||||
| 	list.c							\ | 	list.c							\ | ||||||
|  | 	locale.c						\ | ||||||
| 	main.c							\ | 	main.c							\ | ||||||
| 	map.c							\ | 	map.c							\ | ||||||
| 	mark.c							\ | 	mark.c							\ | ||||||
|  | |||||||
| @ -773,6 +773,7 @@ OBJ = \ | |||||||
| 	$(OUTDIR)\insexpand.obj \ | 	$(OUTDIR)\insexpand.obj \ | ||||||
| 	$(OUTDIR)\json.obj \ | 	$(OUTDIR)\json.obj \ | ||||||
| 	$(OUTDIR)\list.obj \ | 	$(OUTDIR)\list.obj \ | ||||||
|  | 	$(OUTDIR)\locale.obj \ | ||||||
| 	$(OUTDIR)\main.obj \ | 	$(OUTDIR)\main.obj \ | ||||||
| 	$(OUTDIR)\map.obj \ | 	$(OUTDIR)\map.obj \ | ||||||
| 	$(OUTDIR)\mark.obj \ | 	$(OUTDIR)\mark.obj \ | ||||||
| @ -1669,6 +1670,8 @@ $(OUTDIR)/json.obj:	$(OUTDIR) json.c  $(INCL) | |||||||
|  |  | ||||||
| $(OUTDIR)/list.obj:	$(OUTDIR) list.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)/main.obj:	$(OUTDIR) main.c  $(INCL) $(CUI_INCL) | ||||||
|  |  | ||||||
| $(OUTDIR)/map.obj:	$(OUTDIR) map.c  $(INCL) | $(OUTDIR)/map.obj:	$(OUTDIR) map.c  $(INCL) | ||||||
| @ -1939,6 +1942,7 @@ proto.h: \ | |||||||
| 	proto/insexpand.pro \ | 	proto/insexpand.pro \ | ||||||
| 	proto/json.pro \ | 	proto/json.pro \ | ||||||
| 	proto/list.pro \ | 	proto/list.pro \ | ||||||
|  | 	proto/locale.pro \ | ||||||
| 	proto/main.pro \ | 	proto/main.pro \ | ||||||
| 	proto/map.pro \ | 	proto/map.pro \ | ||||||
| 	proto/mark.pro \ | 	proto/mark.pro \ | ||||||
|  | |||||||
| @ -345,6 +345,7 @@ SRC = \ | |||||||
| 	insexpand.c \ | 	insexpand.c \ | ||||||
| 	json.c \ | 	json.c \ | ||||||
| 	list.c \ | 	list.c \ | ||||||
|  | 	locale.c \ | ||||||
| 	main.c \ | 	main.c \ | ||||||
| 	map.c \ | 	map.c \ | ||||||
| 	mark.c \ | 	mark.c \ | ||||||
| @ -460,6 +461,7 @@ OBJ = \ | |||||||
| 	insexpand.obj \ | 	insexpand.obj \ | ||||||
| 	json.obj \ | 	json.obj \ | ||||||
| 	list.obj \ | 	list.obj \ | ||||||
|  | 	locale.obj \ | ||||||
| 	main.obj \ | 	main.obj \ | ||||||
| 	map.obj \ | 	map.obj \ | ||||||
| 	mark.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 \ |  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 \ |  beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \ | ||||||
|  globals.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   \ | 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 \ |  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 \ |  [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \ | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								src/Makefile
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/Makefile
									
									
									
									
									
								
							| @ -1647,6 +1647,7 @@ BASIC_SRC = \ | |||||||
| 	insexpand.c \ | 	insexpand.c \ | ||||||
| 	json.c \ | 	json.c \ | ||||||
| 	list.c \ | 	list.c \ | ||||||
|  | 	locale.c \ | ||||||
| 	main.c \ | 	main.c \ | ||||||
| 	map.c \ | 	map.c \ | ||||||
| 	mark.c \ | 	mark.c \ | ||||||
| @ -1798,6 +1799,7 @@ OBJ_COMMON = \ | |||||||
| 	objects/indent.o \ | 	objects/indent.o \ | ||||||
| 	objects/insexpand.o \ | 	objects/insexpand.o \ | ||||||
| 	objects/list.o \ | 	objects/list.o \ | ||||||
|  | 	objects/locale.o \ | ||||||
| 	objects/map.o \ | 	objects/map.o \ | ||||||
| 	objects/mark.o \ | 	objects/mark.o \ | ||||||
| 	objects/match.o \ | 	objects/match.o \ | ||||||
| @ -1973,6 +1975,7 @@ PRO_AUTO = \ | |||||||
| 	insexpand.pro \ | 	insexpand.pro \ | ||||||
| 	json.pro \ | 	json.pro \ | ||||||
| 	list.pro \ | 	list.pro \ | ||||||
|  | 	locale.pro \ | ||||||
| 	main.pro \ | 	main.pro \ | ||||||
| 	map.pro \ | 	map.pro \ | ||||||
| 	mark.pro \ | 	mark.pro \ | ||||||
| @ -3378,6 +3381,9 @@ objects/kword_test.o: kword_test.c | |||||||
| objects/list.o: list.c | objects/list.o: list.c | ||||||
| 	$(CCC) -o $@ list.c | 	$(CCC) -o $@ list.c | ||||||
|  |  | ||||||
|  | objects/locale.o: locale.c | ||||||
|  | 	$(CCC) -o $@ locale.c | ||||||
|  |  | ||||||
| objects/main.o: main.c | objects/main.o: main.c | ||||||
| 	$(CCC) -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 \ |  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/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ | ||||||
|  proto.h globals.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 \ | 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 \ |  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/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ | ||||||
|  | |||||||
| @ -52,6 +52,7 @@ help.c		| vim help related functions | |||||||
| highlight.c	| syntax highlighting | highlight.c	| syntax highlighting | ||||||
| indent.c	| text indentation | indent.c	| text indentation | ||||||
| insexpand.c	| Insert mode completion | insexpand.c	| Insert mode completion | ||||||
|  | locale.c	| locale/language handling | ||||||
| map.c		| mapping and abbreviations | map.c		| mapping and abbreviations | ||||||
| mark.c		| marks | mark.c		| marks | ||||||
| match.c		| highlight matching | match.c		| highlight matching | ||||||
|  | |||||||
							
								
								
									
										502
									
								
								src/ex_cmds2.c
									
									
									
									
									
								
							
							
						
						
									
										502
									
								
								src/ex_cmds2.c
									
									
									
									
									
								
							| @ -996,505 +996,3 @@ ex_checktime(exarg_T *eap) | |||||||
|     } |     } | ||||||
|     no_check_timestamps = save_no_check_timestamps; |     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 |  | ||||||
|  | |||||||
							
								
								
									
										564
									
								
								src/locale.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										564
									
								
								src/locale.c
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
							
								
								
									
										53
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								src/main.c
									
									
									
									
									
								
							| @ -34,9 +34,6 @@ | |||||||
| static int file_owned(char *fname); | static int file_owned(char *fname); | ||||||
| #endif | #endif | ||||||
| static void mainerr(int, char_u *); | 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); | static void early_arg_scan(mparm_T *parmp); | ||||||
| #ifndef NO_VIM_MAIN | #ifndef NO_VIM_MAIN | ||||||
| static void usage(void); | static void usage(void); | ||||||
| @ -1716,56 +1713,6 @@ getout(int exitval) | |||||||
|     mch_exit(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 |  * Get the name of the display, before gui_prepare() removes it from | ||||||
|  * argv[].  Used for the xterm-clipboard display. |  * argv[].  Used for the xterm-clipboard display. | ||||||
|  | |||||||
| @ -101,6 +101,7 @@ extern int _stricoll(char *a, char *b); | |||||||
| # include "insexpand.pro" | # include "insexpand.pro" | ||||||
| # include "json.pro" | # include "json.pro" | ||||||
| # include "list.pro" | # include "list.pro" | ||||||
|  | # include "locale.pro" | ||||||
| # include "blob.pro" | # include "blob.pro" | ||||||
| # include "main.pro" | # include "main.pro" | ||||||
| # include "map.pro" | # include "map.pro" | ||||||
|  | |||||||
| @ -15,10 +15,4 @@ void ex_pyxfile(exarg_T *eap); | |||||||
| void ex_pyx(exarg_T *eap); | void ex_pyx(exarg_T *eap); | ||||||
| void ex_pyxdo(exarg_T *eap); | void ex_pyxdo(exarg_T *eap); | ||||||
| void ex_checktime(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 : */ | /* vim: set ft=c : */ | ||||||
|  | |||||||
							
								
								
									
										9
									
								
								src/proto/locale.pro
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/proto/locale.pro
									
									
									
									
									
										Normal file
									
								
							| @ -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 : */ | ||||||
| @ -754,6 +754,8 @@ static char *(features[]) = | |||||||
|  |  | ||||||
| static int included_patches[] = | static int included_patches[] = | ||||||
| {   /* Add new patch number below this line */ | {   /* Add new patch number below this line */ | ||||||
|  | /**/ | ||||||
|  |     1269, | ||||||
| /**/ | /**/ | ||||||
|     1268, |     1268, | ||||||
| /**/ | /**/ | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user