Crossfire Server, Trunk  R20513
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 int get_language(object *op) {
56  if (!op->contr)
57  return 0;
58  if (op->contr->language < 0 || op->contr->language >= i18n_count)
59  return 0;
60  return op->contr->language;
61 }
62 
69 const char *i18n(const object *who, const char *code) {
70  i18n_message search, *found;
71 
72  if (!who || !who->contr)
73  return code;
74 
75  if (who->contr->language < 0 || who->contr->language >= i18n_count)
76  return code;
77 
78  search.code = add_string(code);
79 
80  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);
81 
82  free_string(search.code);
83 
84  if (found)
85  return found->message;
86 
87  return code;
88 }
89 
95 int i18n_find_language_by_code(const char *code) {
96  int index;
97  for (index = 0; index < i18n_count; index++) {
98  if (strcmp(code, i18n_files[index].code) == 0)
99  return index;
100  }
101 
102  return -1;
103 }
104 
110 int i18n_get_language_by_code(const char *code) {
111  int try = i18n_find_language_by_code(code);
112  if (try != -1)
113  return try;
114  return i18n_default;
115 }
116 
123  if (language < 0 || language >= i18n_count)
124  return i18n_files[i18n_default].code;
125  return i18n_files[language].code;
126 }
127 
132 void i18n_list_languages(object *who) {
133  int index;
134  for (index = 0; index < i18n_count; index++) {
136  "[fixed]%s: %s",
137  i18n_files[index].code,
138  i18n_files[index].name
139  );
140  }
141 }
142 
151 static void convert_newline(char *line) {
152  char *next;
153  char buf[MAX_BUF];
154 
155  while ((next = strstr(line, "\\n")) != NULL) {
156  *next = '\n';
157  *(next+1) = '\0';
158  snprintf(buf, MAX_BUF, "%s%s", line, next+2);
159  strcpy(line, buf);
160  }
161 }
162 
168 void i18n_init(void) {
169  char dirname[MAX_BUF], filename[MAX_BUF], line[HUGE_BUF];
170  FILE *fp;
171  char *token;
172  DIR *dir;
173  struct dirent *file;
174  i18n_message code, *found;
175 
176  snprintf(dirname, sizeof(dirname), "%s/i18n/", settings.datadir);
177 
178  dir = opendir(dirname);
179  if (dir == NULL) {
180  LOG(llevError, "i18n: couldn't open %s\n", dirname);
182  }
183 
184  code.code = add_string("LN");
185 
186  while ((file = readdir(dir)) != NULL) {
187  if (strncmp(file->d_name, "messages.", 9) != 0)
188  continue;
189 
190  snprintf(filename, sizeof(filename), "%s%s", dirname, file->d_name);
191  if ((fp = fopen(filename, "r")) == NULL) {
192  LOG(llevError, "i18n: couldn't open %s\n",
193  filename, strerror(errno));
195  }
196 
197  i18n_files = realloc(i18n_files, (i18n_count + 1) * sizeof(i18n_file));
198  i18n_files[i18n_count].code = add_string(file->d_name + 9);
199  i18n_files[i18n_count].count = 0;
200  i18n_files[i18n_count].messages = NULL;
201 
202  while (fgets(line, MAX_BUF, fp)) {
203  if (line[0] != '#') {
204  line[strlen(line)-1] = '\0'; /* erase the final newline that messes things. */
205 
206  i18n_files[i18n_count].messages = realloc(i18n_files[i18n_count].messages, (i18n_files[i18n_count].count + 1) * sizeof(i18n_message));
207 
208  token = strtok(line, "|");
209  convert_newline(token);
210  i18n_files[i18n_count].messages[i18n_files[i18n_count].count].code = add_string(token);
211  token = strtok(NULL, "|");
212  if (token != NULL) {
213  convert_newline(token);
214  i18n_files[i18n_count].messages[i18n_files[i18n_count].count].message = add_string(token);
215  } else {
216  i18n_files[i18n_count].messages[i18n_files[i18n_count].count].message = add_refcount(i18n_files[i18n_count].messages[i18n_files[i18n_count].count].code);
217  }
218  i18n_files[i18n_count].count++;
219  }
220  }
221  fclose(fp);
222 
223  qsort(i18n_files[i18n_count].messages, i18n_files[i18n_count].count, sizeof(i18n_message), (int (*)(const void *, const void *))i18n_message_compare_code);
224  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);
225  if (found == NULL) {
226  LOG(llevError, "i18n: no language set in %s\n", filename);
228  }
229 
230  i18n_files[i18n_count].name = found->message;
231  LOG(llevDebug, "i18n: %d strings for %s\n",
232  i18n_files[i18n_count].count, found->message);
233 
234  if (strcmp(i18n_files[i18n_count].code, "en") == 0)
236 
237  i18n_count++;
238  }
239  closedir(dir);
240 
241  free_string(code.code);
242 
243  if (i18n_default == -1) {
244  LOG(llevError, "i18n: couldn't find default language (en)\n");
246  }
247 }
248 
252 void i18n_free(void) {
253  int file, message;
254 
255  for (file = 0; file < i18n_count; file++) {
256  free_string(i18n_files[file].code); /* name is a copy of a message */
257  for (message = 0; message < i18n_files[file].count; message++) {
258  free_string(i18n_files[file].messages[message].code);
259  free_string(i18n_files[file].messages[message].message);
260  }
261  free(i18n_files[file].messages);
262  }
263  free(i18n_files);
264  i18n_files = NULL;
265  i18n_count = 0;
266 }
One available language.
Definition: languages.c:31
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Sends message to player(s).
Definition: main.c:315
Error, serious thing.
Definition: logger.h:11
static int i18n_message_compare_code(const i18n_message *a, const i18n_message *b)
Definition: languages.c:45
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.c:210
int i18n_get_language_by_code(const char *code)
Find the identifier of a language from its code.
Definition: languages.c:110
static struct i18n_file * i18n_files
Defined languages.
Definition: languages.c:41
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.c:596
sstring name
Language&#39;s name, in its native version.
Definition: languages.c:33
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.c:280
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
DIR * opendir(const char *)
Opens a directory for reading.
Definition: win32.c:37
int count
How many items in messages.
Definition: languages.c:34
sstring code
Message code, usually the English version.
Definition: languages.c:24
int language
The language the player wishes to use.
Definition: player.h:201
void i18n_free(void)
Clears all i18n-related data.
Definition: languages.c:252
Definition: win32.h:110
Global type definitions and header inclusions.
struct i18n_file i18n_file
One available language.
sstring message
Message to display.
Definition: languages.c:25
void i18n_init(void)
Initializes the i18n subsystem.
Definition: languages.c:168
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:379
Definition: win32.h:120
#define snprintf
Definition: win32.h:46
static int i18n_default
Index of "English" in the i18nfiles array.
Definition: languages.c:43
static int i18n_count
Number of defined languages.
Definition: languages.c:39
struct pl * contr
Pointer to the player which control this object.
Definition: object.h:276
sstring code
Language code, "message." extension.
Definition: languages.c:32
char d_name[_MAX_FNAME+1]
Definition: win32.h:114
static void convert_newline(char *line)
Replaces &#39; &#39; by a newline char.
Definition: languages.c:151
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
One message.
Definition: languages.c:23
const char * sstring
Strings that should be manipulated through add_string() and free_string().
Definition: global.h:40
const char * datadir
Read only data files.
Definition: global.h:244
int get_language(object *op)
Returns the i18n language index associated with the given object.
Definition: languages.c:55
sstring i18n_get_language_code(int language)
Return the code of a specified language.
Definition: languages.c:122
Only for debugging purposes.
Definition: logger.h:13
struct Settings settings
Server settings.
Definition: init.c:40
struct dirent * readdir(DIR *)
Returns the next file/directory for specified directory handle, obtained through a call to opendir()...
Definition: win32.c:75
sstring add_string(const char *str)
This will add &#39;str&#39; to the hash table.
Definition: shstr.c:124
int i18n_find_language_by_code(const char *code)
Attenmpt to find the identifier of a language from its code.
Definition: languages.c:95
int closedir(DIR *)
Dispose of a directory handle.
Definition: win32.c:108
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
struct i18n_message * messages
Available messages for this language.
Definition: languages.c:35
#define MSG_SUBTYPE_NONE
Definition: newclient.h:398
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
const char * i18n(const object *who, const char *code)
Translate a message in the appropriate language.
Definition: languages.c:69
struct i18n_message i18n_message
One message.
void i18n_list_languages(object *who)
List all languages for who.
Definition: languages.c:132