Crossfire Server, Trunk  R22047
languages.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
14 #include "global.h"
15 
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <string.h>
19 
23 typedef struct i18n_message {
26 } i18n_message;
27 
31 typedef struct i18n_file {
34  int count;
36 } i18n_file;
37 
39 static int i18n_count = 0;
41 static struct i18n_file *i18n_files = NULL;
43 static int i18n_default = -1;
44 
45 static int i18n_message_compare_code(const i18n_message *a, const i18n_message *b) {
46  return strcmp(a->code, b->code);
47 }
48 
55 const char *i18n(const object *who, const char *code) {
56  i18n_message search, *found;
57 
58  if (!who || !who->contr)
59  return code;
60 
61  if (who->contr->language < 0 || who->contr->language >= i18n_count)
62  return code;
63 
64  search.code = add_string(code);
65 
66  found = bsearch(&search, i18n_files[who->contr->language].messages, i18n_files[who->contr->language].count, sizeof(i18n_message), (int (*)(const void *, const void *))i18n_message_compare_code);
67 
68  free_string(search.code);
69 
70  if (found)
71  return found->message;
72 
73  return code;
74 }
75 
81 int i18n_find_language_by_code(const char *code) {
82  int index;
83  for (index = 0; index < i18n_count; index++) {
84  if (strcmp(code, i18n_files[index].code) == 0)
85  return index;
86  }
87 
88  return -1;
89 }
90 
96 int i18n_get_language_by_code(const char *code) {
97  int try = i18n_find_language_by_code(code);
98  if (try != -1)
99  return try;
100  return i18n_default;
101 }
102 
109  if (language < 0 || language >= i18n_count)
110  return i18n_files[i18n_default].code;
111  return i18n_files[language].code;
112 }
113 
118 void i18n_list_languages(object *who) {
119  int index;
120  for (index = 0; index < i18n_count; index++) {
122  "[fixed]%s: %s",
123  i18n_files[index].code,
124  i18n_files[index].name
125  );
126  }
127 }
128 
137 static void convert_newline(char *line) {
138  char *next;
139  char buf[MAX_BUF];
140 
141  while ((next = strstr(line, "\\n")) != NULL) {
142  *next = '\n';
143  *(next+1) = '\0';
144  snprintf(buf, MAX_BUF, "%s%s", line, next+2);
145  strcpy(line, buf);
146  }
147 }
148 
154 void i18n_init(void) {
155  char dirname[MAX_BUF], filename[MAX_BUF*2], line[HUGE_BUF];
156  FILE *fp;
157  char *token;
158  DIR *dir;
159  struct dirent *file;
160  i18n_message code, *found;
161 
162  snprintf(dirname, sizeof(dirname), "%s/i18n/", settings.datadir);
163 
164  dir = opendir(dirname);
165  if (dir == NULL) {
166  LOG(llevError, "i18n: couldn't open %s\n", dirname);
168  }
169 
170  code.code = add_string("LN");
171 
172  while ((file = readdir(dir)) != NULL) {
173  if (strncmp(file->d_name, "messages.", 9) != 0)
174  continue;
175 
176  snprintf(filename, sizeof(filename), "%s%s", dirname, file->d_name);
177  if ((fp = fopen(filename, "r")) == NULL) {
178  LOG(llevError, "i18n: couldn't open %s\n",
179  filename, strerror(errno));
181  }
182 
183  i18n_files = realloc(i18n_files, (i18n_count + 1) * sizeof(i18n_file));
184  i18n_files[i18n_count].code = add_string(file->d_name + 9);
185  i18n_files[i18n_count].count = 0;
186  i18n_files[i18n_count].messages = NULL;
187 
188  while (fgets(line, MAX_BUF, fp)) {
189  if (line[0] != '#') {
190  line[strlen(line)-1] = '\0'; /* erase the final newline that messes things. */
191 
192  i18n_files[i18n_count].messages = realloc(i18n_files[i18n_count].messages, (i18n_files[i18n_count].count + 1) * sizeof(i18n_message));
193 
194  token = strtok(line, "|");
195  convert_newline(token);
196  i18n_files[i18n_count].messages[i18n_files[i18n_count].count].code = add_string(token);
197  token = strtok(NULL, "|");
198  if (token != NULL) {
199  convert_newline(token);
200  i18n_files[i18n_count].messages[i18n_files[i18n_count].count].message = add_string(token);
201  } else {
202  i18n_files[i18n_count].messages[i18n_files[i18n_count].count].message = add_refcount(i18n_files[i18n_count].messages[i18n_files[i18n_count].count].code);
203  }
204  i18n_files[i18n_count].count++;
205  }
206  }
207  fclose(fp);
208 
209  qsort(i18n_files[i18n_count].messages, i18n_files[i18n_count].count, sizeof(i18n_message), (int (*)(const void *, const void *))i18n_message_compare_code);
210  found = bsearch(&code, i18n_files[i18n_count].messages, i18n_files[i18n_count].count, sizeof(i18n_message), (int (*)(const void *, const void *))i18n_message_compare_code);
211  if (found == NULL) {
212  LOG(llevError, "i18n: no language set in %s\n", filename);
214  }
215 
216  i18n_files[i18n_count].name = found->message;
217  LOG(llevDebug, "i18n: %d strings for %s\n",
218  i18n_files[i18n_count].count, found->message);
219 
220  if (strcmp(i18n_files[i18n_count].code, "en") == 0)
222 
223  i18n_count++;
224  }
225  closedir(dir);
226 
227  free_string(code.code);
228 
229  if (i18n_default == -1) {
230  LOG(llevError, "i18n: couldn't find default language (en)\n");
232  }
233 }
234 
238 void i18n_free(void) {
239  int file, message;
240 
241  for (file = 0; file < i18n_count; file++) {
242  free_string(i18n_files[file].code); /* name is a copy of a message */
243  for (message = 0; message < i18n_files[file].count; message++) {
244  free_string(i18n_files[file].messages[message].code);
245  free_string(i18n_files[file].messages[message].message);
246  }
247  free(i18n_files[file].messages);
248  }
249  free(i18n_files);
250  i18n_files = NULL;
251  i18n_count = 0;
252 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:313
static int i18n_message_compare_code(const i18n_message *a, const i18n_message *b)
Definition: languages.c:45
sstring add_refcount(sstring str)
Definition: shstr.c:210
int i18n_get_language_by_code(const char *code)
Definition: languages.c:96
static struct i18n_file * i18n_files
Definition: languages.c:41
StringBuffer * buf
Definition: readable.c:1591
void fatal(enum fatal_error err)
Definition: utils.c:597
sstring name
Definition: languages.c:33
void free_string(sstring str)
Definition: shstr.c:280
#define HUGE_BUF
Definition: define.h:37
DIR * opendir(const char *)
Definition: win32.c:37
int count
Definition: languages.c:34
sstring code
Definition: languages.c:24
void i18n_free(void)
Definition: languages.c:238
Definition: win32.h:110
struct i18n_file i18n_file
sstring message
Definition: languages.c:25
void i18n_init(void)
Definition: languages.c:154
#define MSG_TYPE_COMMAND
Definition: newclient.h:379
Definition: win32.h:120
#define snprintf
Definition: win32.h:46
static int i18n_default
Definition: languages.c:43
static int i18n_count
Definition: languages.c:39
sstring code
Definition: languages.c:32
char d_name[_MAX_FNAME+1]
Definition: win32.h:114
static void convert_newline(char *line)
Definition: languages.c:137
#define MAX_BUF
Definition: define.h:35
const char * sstring
Definition: global.h:40
const char * datadir
Definition: global.h:245
sstring i18n_get_language_code(int language)
Definition: languages.c:108
struct Settings settings
Definition: init.c:39
struct dirent * readdir(DIR *)
Definition: win32.c:75
sstring add_string(const char *str)
Definition: shstr.c:124
int i18n_find_language_by_code(const char *code)
Definition: languages.c:81
int closedir(DIR *)
Definition: win32.c:108
#define NDI_UNIQUE
Definition: newclient.h:245
struct i18n_message * messages
Definition: languages.c:35
#define MSG_SUBTYPE_NONE
Definition: newclient.h:398
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
const char * i18n(const object *who, const char *code)
Definition: languages.c:55
struct i18n_message i18n_message
void i18n_list_languages(object *who)
Definition: languages.c:118