language.c

Go to the documentation of this file.
00001 /* Multi-language support.
00002  *
00003  * (C) 2003-2007 Anope Team
00004  * Contact us at info@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church. 
00010  * 
00011  * $Id: language.c 1265 2007-08-26 15:33:06Z geniusdex $ 
00012  *
00013  */
00014 
00015 #include "services.h"
00016 #include "language.h"
00017 
00018 /*************************************************************************/
00019 
00020 /* The list of lists of messages. */
00021 char **langtexts[NUM_LANGS];
00022 
00023 /* The list of names of languages. */
00024 char *langnames[NUM_LANGS];
00025 
00026 /* Indexes of available languages: */
00027 int langlist[NUM_LANGS];
00028 
00029 /* Order in which languages should be displayed: (alphabetical) */
00030 static int langorder[NUM_LANGS] = {
00031     LANG_EN_US,                 /* English (US) */
00032     LANG_FR,                    /* French */
00033     LANG_DE,                    /* German */
00034     LANG_IT,                    /* Italian */
00035     LANG_JA_JIS,                /* Japanese (JIS encoding) */
00036     LANG_JA_EUC,                /* Japanese (EUC encoding) */
00037     LANG_JA_SJIS,               /* Japanese (SJIS encoding) */
00038     LANG_PT,                    /* Portugese */
00039     LANG_ES,                    /* Spanish */
00040     LANG_TR,                    /* Turkish */
00041     LANG_CAT,                   /* Catalan */
00042     LANG_GR,                    /* Greek */
00043     LANG_NL,                    /* Dutch */
00044     LANG_RU,                    /* Russian */
00045     LANG_HUN,                   /* Hungarian */
00046     LANG_PL,                    /* Polish */
00047 };
00048 
00049 /*************************************************************************/
00050 
00051 /* Load a language file. */
00052 
00053 static int read_int32(int32 * ptr, FILE * f)
00054 {
00055     int a = fgetc(f);
00056     int b = fgetc(f);
00057     int c = fgetc(f);
00058     int d = fgetc(f);
00059     if (a == EOF || b == EOF || c == EOF || d == EOF)
00060         return -1;
00061     *ptr = a << 24 | b << 16 | c << 8 | d;
00062     return 0;
00063 }
00064 
00065 static void load_lang(int index, const char *filename)
00066 {
00067     char buf[256];
00068     FILE *f;
00069     int32 num, i;
00070 
00071     if (debug) {
00072         alog("debug: Loading language %d from file `languages/%s'",
00073              index, filename);
00074     }
00075     snprintf(buf, sizeof(buf), "languages/%s", filename);
00076 #ifndef _WIN32
00077     if (!(f = fopen(buf, "r"))) {
00078 #else
00079     if (!(f = fopen(buf, "rb"))) {
00080 #endif
00081         log_perror("Failed to load language %d (%s)", index, filename);
00082         return;
00083     } else if (read_int32(&num, f) < 0) {
00084         alog("Failed to read number of strings for language %d (%s)",
00085              index, filename);
00086         return;
00087     } else if (num != NUM_STRINGS) {
00088         alog("Warning: Bad number of strings (%d, wanted %d) "
00089              "for language %d (%s)", num, NUM_STRINGS, index, filename);
00090     }
00091     langtexts[index] = scalloc(sizeof(char *), NUM_STRINGS);
00092     if (num > NUM_STRINGS)
00093         num = NUM_STRINGS;
00094     for (i = 0; i < num; i++) {
00095         int32 pos, len;
00096         fseek(f, i * 8 + 4, SEEK_SET);
00097         if (read_int32(&pos, f) < 0 || read_int32(&len, f) < 0) {
00098             alog("Failed to read entry %d in language %d (%s) TOC",
00099                  i, index, filename);
00100             while (--i >= 0) {
00101                 if (langtexts[index][i])
00102                     free(langtexts[index][i]);
00103             }
00104             free(langtexts[index]);
00105             langtexts[index] = NULL;
00106             return;
00107         }
00108         if (len == 0) {
00109             langtexts[index][i] = NULL;
00110         } else if (len >= 65536) {
00111             alog("Entry %d in language %d (%s) is too long (over 64k)--"
00112                  "corrupt TOC?", i, index, filename);
00113             while (--i >= 0) {
00114                 if (langtexts[index][i])
00115                     free(langtexts[index][i]);
00116             }
00117             free(langtexts[index]);
00118             langtexts[index] = NULL;
00119             return;
00120         } else if (len < 0) {
00121             alog("Entry %d in language %d (%s) has negative length--"
00122                  "corrupt TOC?", i, index, filename);
00123             while (--i >= 0) {
00124                 if (langtexts[index][i])
00125                     free(langtexts[index][i]);
00126             }
00127             free(langtexts[index]);
00128             langtexts[index] = NULL;
00129             return;
00130         } else {
00131             langtexts[index][i] = scalloc(len + 1, 1);
00132             fseek(f, pos, SEEK_SET);
00133             if (fread(langtexts[index][i], 1, len, f) != len) {
00134                 alog("Failed to read string %d in language %d (%s)",
00135                      i, index, filename);
00136                 while (--i >= 0) {
00137                     if (langtexts[index][i])
00138                         free(langtexts[index][i]);
00139                 }
00140                 free(langtexts[index]);
00141                 langtexts[index] = NULL;
00142                 return;
00143             }
00144             langtexts[index][i][len] = 0;
00145         }
00146     }
00147     fclose(f);
00148 }
00149 
00150 /*************************************************************************/
00151 
00152 /* Replace all %M's with "/msg " or "/" */
00153 void lang_sanitize()
00154 {
00155     int i = 0, j = 0;
00156     int len = 0;
00157     char tmp[2000];
00158     char *newstr = NULL;
00159     for (i = 0; i < NUM_LANGS; i++) {
00160         for (j = 0; j < NUM_STRINGS; j++) {
00161             if (strstr(langtexts[i][j], "%R")) {
00162                 len = strlen(langtexts[i][j]);
00163                 strscpy(tmp, langtexts[i][j], sizeof(tmp));
00164                 if (UseStrictPrivMsg) {
00165                     strnrepl(tmp, sizeof(tmp), "%R", "/");
00166                 } else {
00167                     strnrepl(tmp, sizeof(tmp), "%R", "/msg ");
00168                 }
00169                 newstr = sstrdup(tmp);
00170                 free(langtexts[i][j]);
00171                 langtexts[i][j] = newstr;
00172             }
00173         }
00174     }
00175 }
00176 
00177 
00178 /* Initialize list of lists. */
00179 
00180 void lang_init()
00181 {
00182     int i, j, n = 0;
00183 
00184     load_lang(LANG_CAT, "cat");
00185     load_lang(LANG_DE, "de");
00186     load_lang(LANG_EN_US, "en_us");
00187     load_lang(LANG_ES, "es");
00188     load_lang(LANG_FR, "fr");
00189     load_lang(LANG_GR, "gr");
00190     load_lang(LANG_PT, "pt");
00191     load_lang(LANG_TR, "tr");
00192     load_lang(LANG_IT, "it");
00193     load_lang(LANG_NL, "nl");
00194     load_lang(LANG_RU, "ru");
00195     load_lang(LANG_HUN, "hun");
00196     load_lang(LANG_PL, "pl");
00197 
00198     for (i = 0; i < NUM_LANGS; i++) {
00199         if (langtexts[langorder[i]] != NULL) {
00200             langnames[langorder[i]] = langtexts[langorder[i]][LANG_NAME];
00201             langlist[n++] = langorder[i];
00202             for (j = 0; j < NUM_STRINGS; j++) {
00203                 if (!langtexts[langorder[i]][j]) {
00204                     langtexts[langorder[i]][j] =
00205                         langtexts[DEF_LANGUAGE][j];
00206                 }
00207                 if (!langtexts[langorder[i]][j]) {
00208                     langtexts[langorder[i]][j] = langtexts[LANG_EN_US][j];
00209                 }
00210             }
00211         }
00212     }
00213     while (n < NUM_LANGS)
00214         langlist[n++] = -1;
00215 
00216     /* Not what I intended to do, but these services are so archaïc
00217      * that it's difficult to do more. */
00218     if ((NSDefLanguage = langlist[NSDefLanguage]) < 0)
00219         NSDefLanguage = DEF_LANGUAGE;
00220 
00221     if (!langtexts[DEF_LANGUAGE])
00222         fatal("Unable to load default language");
00223     for (i = 0; i < NUM_LANGS; i++) {
00224         if (!langtexts[i])
00225             langtexts[i] = langtexts[DEF_LANGUAGE];
00226     }
00227     lang_sanitize();
00228 }
00229 
00230 /*************************************************************************/
00231 /*************************************************************************/
00232 
00233 /* Format a string in a strftime()-like way, but heed the user's language
00234  * setting for month and day names.  The string stored in the buffer will
00235  * always be null-terminated, even if the actual string was longer than the
00236  * buffer size.
00237  * Assumption: No month or day name has a length (including trailing null)
00238  * greater than BUFSIZE.
00239  */
00240 
00241 int strftime_lang(char *buf, int size, User * u, int format, struct tm *tm)
00242 {
00243     int language = u && u->na ? u->na->nc->language : NSDefLanguage;
00244     char tmpbuf[BUFSIZE], buf2[BUFSIZE];
00245     char *s;
00246     int i, ret;
00247 
00248     if (!tm) {
00249         return 0;
00250     }
00251 
00252     strscpy(tmpbuf, langtexts[language][format], sizeof(tmpbuf));
00253     if ((s = langtexts[language][STRFTIME_DAYS_SHORT]) != NULL) {
00254         for (i = 0; i < tm->tm_wday; i++)
00255             s += strcspn(s, "\n") + 1;
00256         i = strcspn(s, "\n");
00257         strncpy(buf2, s, i);
00258         buf2[i] = 0;
00259         strnrepl(tmpbuf, sizeof(tmpbuf), "%a", buf2);
00260     }
00261     if ((s = langtexts[language][STRFTIME_DAYS_LONG]) != NULL) {
00262         for (i = 0; i < tm->tm_wday; i++)
00263             s += strcspn(s, "\n") + 1;
00264         i = strcspn(s, "\n");
00265         strncpy(buf2, s, i);
00266         buf2[i] = 0;
00267         strnrepl(tmpbuf, sizeof(tmpbuf), "%A", buf2);
00268     }
00269     if ((s = langtexts[language][STRFTIME_MONTHS_SHORT]) != NULL) {
00270         for (i = 0; i < tm->tm_mon; i++)
00271             s += strcspn(s, "\n") + 1;
00272         i = strcspn(s, "\n");
00273         strncpy(buf2, s, i);
00274         buf2[i] = 0;
00275         strnrepl(tmpbuf, sizeof(tmpbuf), "%b", buf2);
00276     }
00277     if ((s = langtexts[language][STRFTIME_MONTHS_LONG]) != NULL) {
00278         for (i = 0; i < tm->tm_mon; i++)
00279             s += strcspn(s, "\n") + 1;
00280         i = strcspn(s, "\n");
00281         strncpy(buf2, s, i);
00282         buf2[i] = 0;
00283         strnrepl(tmpbuf, sizeof(tmpbuf), "%B", buf2);
00284     }
00285     ret = strftime(buf, size, tmpbuf, tm);
00286     if (ret == size)
00287         buf[size - 1] = 0;
00288     return ret;
00289 }
00290 
00291 /*************************************************************************/
00292 /*************************************************************************/
00293 
00294 /* Send a syntax-error message to the user. */
00295 
00296 void syntax_error(char *service, User * u, const char *command, int msgnum)
00297 {
00298     const char *str;
00299 
00300     if (!u) {
00301         return;
00302     }
00303 
00304     str = getstring(u->na, msgnum);
00305     notice_lang(service, u, SYNTAX_ERROR, str);
00306     notice_lang(service, u, MORE_INFO, service, command);
00307 }
00308 
00309 /*************************************************************************/

Generated on Sun Dec 30 09:26:49 2007 for Anope by  doxygen 1.5.1-20070107