ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hybrid-ircservices-1/language.c
(Generate patch)

Comparing hybrid-ircservices-1/language.c (file contents):
Revision 1208 by michael, Mon Aug 22 18:55:33 2011 UTC vs.
Revision 1209 by michael, Thu Aug 25 19:05:49 2011 UTC

# Line 7 | Line 7
7   * details.
8   */
9  
10 < #define LANGSTR_ARRAY  /* define langstrs[] in langstrs.h, via language.h */
10 > #define LANGSTR_ARRAY           /* define langstrs[] in langstrs.h, via language.h */
11  
12   #include "services.h"
13   #include "language.h"
# Line 19 | Line 19
19   /*************************************************************************/
20  
21   /* Indexes of available languages (exported), terminated by -1: */
22 < int langlist[NUM_LANGS+1];
22 > int langlist[NUM_LANGS + 1];
23  
24   /* List and count of available strings: */
25   static char **langstrs;
# Line 32 | Line 32 | static char **origtexts[NUM_LANGS];
32  
33   /* Order in which languages should be displayed: (alphabetical in English) */
34   static int langorder[] = {
35 <    LANG_EN_US,         /* English (US) */
36 <    LANG_NL,            /* Dutch */
37 <    LANG_FR,            /* French */
38 <    LANG_DE,            /* German */
39 <    LANG_HU,            /* Hungarian */
40 < /*    LANG_IT,*/        /* Italian */
41 <    LANG_JA_EUC,        /* Japanese (EUC encoding) */
42 <    LANG_JA_SJIS,       /* Japanese (SJIS encoding) */
43 < /*    LANG_PT,*/        /* Portugese */
44 <    LANG_RU,            /* Russian */
45 <    LANG_ES,            /* Spanish */
46 <    LANG_TR,            /* Turkish */
35 >  LANG_EN_US,                   /* English (US) */
36 >  LANG_NL,                      /* Dutch */
37 >  LANG_FR,                      /* French */
38 >  LANG_DE,                      /* German */
39 >  LANG_HU,                      /* Hungarian */
40 >  /*    LANG_IT, *//* Italian */
41 >  LANG_JA_EUC,                  /* Japanese (EUC encoding) */
42 >  LANG_JA_SJIS,                 /* Japanese (SJIS encoding) */
43 >  /*    LANG_PT, *//* Portugese */
44 >  LANG_RU,                      /* Russian */
45 >  LANG_ES,                      /* Spanish */
46 >  LANG_TR,                      /* Turkish */
47   };
48  
49   /* Filenames for language files: */
50 < static struct {
51 <    int num;
52 <    const char *filename;
53 < } filenames[] = {
54 <    { LANG_EN_US,       "en_us" },
55 <    { LANG_NL,          "nl" },
56 <    { LANG_FR,          "fr" },
57 <    { LANG_DE,          "de" },
58 <    { LANG_HU,          "hu" },
59 <    { LANG_IT,          "it" },
60 <    { LANG_JA_EUC,      "ja_euc" },
61 <    { LANG_JA_SJIS,     "ja_sjis" },
62 <    { LANG_PT,          "pt" },
63 <    { LANG_RU,          "ru" },
64 <    { LANG_ES,          "es" },
65 <    { LANG_TR,          "tr" },
66 <    { -1, NULL }
50 > static struct
51 > {
52 >  int num;
53 >  const char *filename;
54 > } filenames[] =
55 > {
56 >  {
57 >  LANG_EN_US, "en_us"},
58 >  {
59 >  LANG_NL, "nl"},
60 >  {
61 >  LANG_FR, "fr"},
62 >  {
63 >  LANG_DE, "de"},
64 >  {
65 >  LANG_HU, "hu"},
66 >  {
67 >  LANG_IT, "it"},
68 >  {
69 >  LANG_JA_EUC, "ja_euc"},
70 >  {
71 >  LANG_JA_SJIS, "ja_sjis"},
72 >  {
73 >  LANG_PT, "pt"},
74 >  {
75 >  LANG_RU, "ru"},
76 >  {
77 >  LANG_ES, "es"},
78 >  {
79 >  LANG_TR, "tr"},
80 >  {
81 >  -1, NULL}
82   };
83  
84   /* Mapping of language strings (to allow on-the-fly replacement of strings) */
# Line 83 | Line 98 | static int is_loaded[NUM_LANGS];
98  
99   /* Helper functions. */
100  
101 < static inline int read_int32(int32 *ptr, FILE *f)
101 > static inline int
102 > read_int32(int32 * ptr, FILE * f)
103   {
104 <    int a = fgetc(f);
105 <    int b = fgetc(f);
106 <    int c = fgetc(f);
107 <    int d = fgetc(f);
108 <    if (a == EOF || b == EOF || c == EOF || d == EOF)
109 <        return -1;
110 <    *ptr = a<<24 | b<<16 | c<<8 | d;
111 <    return 0;
104 >  int a = fgetc(f);
105 >  int b = fgetc(f);
106 >  int c = fgetc(f);
107 >  int d = fgetc(f);
108 >  if (a == EOF || b == EOF || c == EOF || d == EOF)
109 >    return -1;
110 >  *ptr = a << 24 | b << 16 | c << 8 | d;
111 >  return 0;
112   }
113  
114 < static inline int read_uint32(uint32 *ptr, FILE *f)
114 > static inline int
115 > read_uint32(uint32 * ptr, FILE * f)
116   {
117 <    return read_int32((int32 *)ptr, f);
117 >  return read_int32((int32 *) ptr, f);
118   }
119  
120   /*************************************************************************/
# Line 105 | Line 122 | static inline int read_uint32(uint32 *pt
122  
123   /* Load a language file, storing the data in origtexts[index]. */
124  
125 < static void load_lang(int index, const char *filename)
125 > static void
126 > load_lang(int index, const char *filename)
127   {
128 <    char buf[256];
129 <    FILE *f;
130 <    uint32 num, size, i;
131 <    char *data = NULL;
132 <
133 <    log_debug(1, "Loading language %d from file `languages/%s'",
116 <              index, filename);
117 <    snprintf(buf, sizeof(buf), "languages/%s", filename);
118 <    if (!(f = fopen(buf, "r"))) {
119 <        log_perror("Failed to load language %d (%s)", index, filename);
120 <        return;
121 <    } else if (read_uint32(&num, f) < 0) {
122 <        log("Failed to read number of strings for language %d (%s)",
123 <            index, filename);
124 <        return;
125 <    } else if (read_uint32(&size, f) < 0) {
126 <        log("Failed to read data size for language %d (%s)",
127 <            index, filename);
128 <        return;
129 <    } else if (num != NUM_BASE_STRINGS) {
130 <        log("Warning: Bad number of strings (%d, wanted %d) "
131 <            "for language %d (%s)", num, NUM_BASE_STRINGS, index, filename);
132 <    }
133 <    origtexts[index] = scalloc(sizeof(char *), NUM_BASE_STRINGS+1);
134 <    if (num > NUM_BASE_STRINGS)
135 <        num = NUM_BASE_STRINGS;
136 <    origtexts[index][0] = data = smalloc(size+4);
137 <    *((uint32 *)data) = size;
138 <    data += 4;
139 <    if (fread(data, size, 1, f) != 1) {
140 <        log("Failed to read language data for language %d (%s)",
128 >  char buf[256];
129 >  FILE *f;
130 >  uint32 num, size, i;
131 >  char *data = NULL;
132 >
133 >  log_debug(1, "Loading language %d from file `languages/%s'",
134              index, filename);
135 <        goto fail;
136 <    }
137 <    for (i = 0; i < num; i++) {
138 <        int32 pos;
146 <        if (read_int32(&pos, f) < 0) {
147 <            log("Failed to read entry %d in language %d (%s) TOC",
148 <                i, index, filename);
149 <            goto fail;
150 <        }
151 <        if (pos == -1) {
152 <            origtexts[index][i+1] = NULL;
153 <        } else {
154 <            origtexts[index][i+1] = data + pos;
155 <        }
156 <    }
157 <    fclose(f);
158 <    is_loaded[index] = 1;
135 >  snprintf(buf, sizeof(buf), "languages/%s", filename);
136 >  if (!(f = fopen(buf, "r")))
137 >  {
138 >    log_perror("Failed to load language %d (%s)", index, filename);
139      return;
140 <
141 <  fail:
142 <    free(data);
143 <    free(origtexts[index]);
144 <    origtexts[index] = NULL;
140 >  }
141 >  else if (read_uint32(&num, f) < 0)
142 >  {
143 >    log("Failed to read number of strings for language %d (%s)",
144 >        index, filename);
145 >    return;
146 >  }
147 >  else if (read_uint32(&size, f) < 0)
148 >  {
149 >    log("Failed to read data size for language %d (%s)", index, filename);
150      return;
151 +  }
152 +  else if (num != NUM_BASE_STRINGS)
153 +  {
154 +    log("Warning: Bad number of strings (%d, wanted %d) "
155 +        "for language %d (%s)", num, NUM_BASE_STRINGS, index, filename);
156 +  }
157 +  origtexts[index] = scalloc(sizeof(char *), NUM_BASE_STRINGS + 1);
158 +  if (num > NUM_BASE_STRINGS)
159 +    num = NUM_BASE_STRINGS;
160 +  origtexts[index][0] = data = smalloc(size + 4);
161 +  *((uint32 *) data) = size;
162 +  data += 4;
163 +  if (fread(data, size, 1, f) != 1)
164 +  {
165 +    log("Failed to read language data for language %d (%s)", index, filename);
166 +    goto fail;
167 +  }
168 +  for (i = 0; i < num; i++)
169 +  {
170 +    int32 pos;
171 +    if (read_int32(&pos, f) < 0)
172 +    {
173 +      log("Failed to read entry %d in language %d (%s) TOC",
174 +          i, index, filename);
175 +      goto fail;
176 +    }
177 +    if (pos == -1)
178 +    {
179 +      origtexts[index][i + 1] = NULL;
180 +    }
181 +    else
182 +    {
183 +      origtexts[index][i + 1] = data + pos;
184 +    }
185 +  }
186 +  fclose(f);
187 +  is_loaded[index] = 1;
188 +  return;
189 +
190 + fail:
191 +  free(data);
192 +  free(origtexts[index]);
193 +  origtexts[index] = NULL;
194 +  return;
195   }
196  
197   /*************************************************************************/
198  
199   /* Initialize list of lists. */
200  
201 < int lang_init(void)
201 > int
202 > lang_init(void)
203   {
204 <    int i, j, n = 0;
175 <
176 <    /* Set up the string list */
177 <    langstrs = malloc(sizeof(char *) * NUM_BASE_STRINGS);
178 <    if (!langstrs) {
179 <        log_perror("malloc(langstrs)");
180 <        return 0;
181 <    }
182 <    memcpy(langstrs, base_langstrs, sizeof(char *) * NUM_BASE_STRINGS);
183 <    num_strings = NUM_BASE_STRINGS;
184 <
185 <    /* Set up the string remap list */
186 <    langmap = smalloc(sizeof(int) * num_strings);
187 <    for (i = 0; i < num_strings; i++)
188 <        langmap[i] = i;
189 <
190 <    /* Load language files */
191 <    memset(is_loaded, 0, sizeof(is_loaded));
192 <    for (i = 0; i < lenof(langorder); i++) {
193 <        for (j = 0; filenames[j].num >= 0; j++) {
194 <            if (filenames[j].num == langorder[i])
195 <                break;
196 <        }
197 <        if (filenames[j].num >= 0) {
198 <            load_lang(langorder[i], filenames[j].filename);
199 <        } else {
200 <            log("BUG: lang_init(): no filename entry for language %d!",
201 <                langorder[i]);
202 <        }
203 <    }
204 >  int i, j, n = 0;
205  
206 <    /* Make sure the default language has all strings available */
207 <    if (!origtexts[DEF_LANGUAGE]) {
208 <        log("Unable to load default language");
206 >  /* Set up the string list */
207 >  langstrs = malloc(sizeof(char *) * NUM_BASE_STRINGS);
208 >  if (!langstrs)
209 >  {
210 >    log_perror("malloc(langstrs)");
211 >    return 0;
212 >  }
213 >  memcpy(langstrs, base_langstrs, sizeof(char *) * NUM_BASE_STRINGS);
214 >  num_strings = NUM_BASE_STRINGS;
215 >
216 >  /* Set up the string remap list */
217 >  langmap = smalloc(sizeof(int) * num_strings);
218 >  for (i = 0; i < num_strings; i++)
219 >    langmap[i] = i;
220 >
221 >  /* Load language files */
222 >  memset(is_loaded, 0, sizeof(is_loaded));
223 >  for (i = 0; i < lenof(langorder); i++)
224 >  {
225 >    for (j = 0; filenames[j].num >= 0; j++)
226 >    {
227 >      if (filenames[j].num == langorder[i])
228 >        break;
229 >    }
230 >    if (filenames[j].num >= 0)
231 >    {
232 >      load_lang(langorder[i], filenames[j].filename);
233 >    }
234 >    else
235 >    {
236 >      log("BUG: lang_init(): no filename entry for language %d!",
237 >          langorder[i]);
238 >    }
239 >  }
240 >
241 >  /* Make sure the default language has all strings available */
242 >  if (!origtexts[DEF_LANGUAGE])
243 >  {
244 >    log("Unable to load default language");
245 >    return 0;
246 >  }
247 >  for (i = 0; i < num_strings; i++)
248 >  {
249 >    if (!origtexts[DEF_LANGUAGE][i + 1])
250 >    {
251 >      if (is_loaded[LANG_EN_US] && origtexts[LANG_EN_US][i + 1])
252 >      {
253 >        uint32 oldsize = *((uint32 *) origtexts[DEF_LANGUAGE][0]);
254 >        uint32 newsize = strlen(origtexts[LANG_EN_US][i + 1]) + 1;
255 >        origtexts[DEF_LANGUAGE][0] =
256 >          realloc(origtexts[DEF_LANGUAGE][0], oldsize + newsize + 4);
257 >        if (!origtexts[DEF_LANGUAGE][0])
258 >        {
259 >          log("Out of memory while loading languages");
260 >          return 0;
261 >        }
262 >        *((uint32 *) origtexts[DEF_LANGUAGE][0]) = oldsize + newsize;
263 >        origtexts[DEF_LANGUAGE][i + 1] =
264 >          origtexts[DEF_LANGUAGE][0] + 4 + oldsize;
265 >        strcpy(origtexts[DEF_LANGUAGE][i + 1], origtexts[LANG_EN_US][i + 1]);
266 >      }
267 >      else
268 >      {
269 >        log("String %s missing from default language", langstrs[i]);
270          return 0;
271 +      }
272      }
273 <    for (i = 0; i < num_strings; i++) {
211 <        if (!origtexts[DEF_LANGUAGE][i+1]) {
212 <            if (is_loaded[LANG_EN_US] && origtexts[LANG_EN_US][i+1]) {
213 <                uint32 oldsize = *((uint32 *)origtexts[DEF_LANGUAGE][0]);
214 <                uint32 newsize = strlen(origtexts[LANG_EN_US][i+1]) + 1;
215 <                origtexts[DEF_LANGUAGE][0] =
216 <                    realloc(origtexts[DEF_LANGUAGE][0], oldsize + newsize + 4);
217 <                if (!origtexts[DEF_LANGUAGE][0]) {
218 <                    log("Out of memory while loading languages");
219 <                    return 0;
220 <                }
221 <                *((uint32 *)origtexts[DEF_LANGUAGE][0]) = oldsize + newsize;
222 <                origtexts[DEF_LANGUAGE][i+1] =
223 <                    origtexts[DEF_LANGUAGE][0] + 4 + oldsize;
224 <                strcpy(origtexts[DEF_LANGUAGE][i+1],
225 <                       origtexts[LANG_EN_US][i+1]);
226 <            } else {
227 <                log("String %s missing from default language", langstrs[i]);
228 <                return 0;
229 <            }
230 <        }
231 <    }
273 >  }
274  
275 <    /* Set up the list of available languages in langlist[] */
276 <    for (i = 0; i < lenof(langorder); i++) {
277 <        if (is_loaded[langorder[i]])
278 <            langlist[n++] = langorder[i];
279 <    }
280 <    while (n < lenof(langlist))
281 <        langlist[n++] = -1;
275 >  /* Set up the list of available languages in langlist[] */
276 >  for (i = 0; i < lenof(langorder); i++)
277 >  {
278 >    if (is_loaded[langorder[i]])
279 >      langlist[n++] = langorder[i];
280 >  }
281 >  while (n < lenof(langlist))
282 >    langlist[n++] = -1;
283  
284 <    /* Initialize the active string tables in langtexts[] */
285 <    reset_ext_lang();
284 >  /* Initialize the active string tables in langtexts[] */
285 >  reset_ext_lang();
286  
287 <    return 1;
287 >  return 1;
288   }
289  
290   /*************************************************************************/
291  
292   /* Clean up language data. */
293  
294 < void lang_cleanup(void)
294 > void
295 > lang_cleanup(void)
296   {
297 <    int i;
297 >  int i;
298  
299 <    for (i = 0; i < NUM_LANGS; i++) {
300 <        if (langtexts[i]) {
301 <            free(langtexts[i][0]);
302 <            free(langtexts[i]);
303 <            langtexts[i] = NULL;
304 <        }
305 <        if (origtexts[i]) {
306 <            free(origtexts[i][0]);
307 <            free(origtexts[i]);
308 <            langtexts[i] = NULL;
309 <        }
310 <    }
311 <    free(langmap);
312 <    free(langstrs);
299 >  for (i = 0; i < NUM_LANGS; i++)
300 >  {
301 >    if (langtexts[i])
302 >    {
303 >      free(langtexts[i][0]);
304 >      free(langtexts[i]);
305 >      langtexts[i] = NULL;
306 >    }
307 >    if (origtexts[i])
308 >    {
309 >      free(origtexts[i][0]);
310 >      free(origtexts[i]);
311 >      langtexts[i] = NULL;
312 >    }
313 >  }
314 >  free(langmap);
315 >  free(langstrs);
316   }
317  
318   /*************************************************************************/
# Line 285 | Line 332 | void lang_cleanup(void)
332   * Returns 0 on failure, nonzero on success.
333   */
334  
335 < int load_ext_lang(const char *filename)
335 > int
336 > load_ext_lang(const char *filename)
337   {
338 <    FILE *f;
339 <    char buf[BUFSIZE], *s;
340 <    char **newtexts[NUM_LANGS];
341 <    uint32 newsizes[NUM_LANGS];
342 <    int i, curstr, curlang, line;
343 <    int retval = 1, firstline = 1;
344 <
345 <    memset(newtexts, 0, sizeof(newtexts));
346 <    memset(newsizes, 0, sizeof(newsizes));
347 <    f = fopen(filename, "r");
348 <    if (!f) {
349 <        log_perror("load_ext_lang(): Unable to open file %s", filename);
350 <        return 0;
351 <    }
338 >  FILE *f;
339 >  char buf[BUFSIZE], *s;
340 >  char **newtexts[NUM_LANGS];
341 >  uint32 newsizes[NUM_LANGS];
342 >  int i, curstr, curlang, line;
343 >  int retval = 1, firstline = 1;
344 >
345 >  memset(newtexts, 0, sizeof(newtexts));
346 >  memset(newsizes, 0, sizeof(newsizes));
347 >  f = fopen(filename, "r");
348 >  if (!f)
349 >  {
350 >    log_perror("load_ext_lang(): Unable to open file %s", filename);
351 >    return 0;
352 >  }
353  
354 <    curstr = curlang = -1;
355 <    line = 0;
356 <    while (fgets(buf, sizeof(buf), f) && *buf) {
357 <        line++;
358 <        s = buf + strlen(buf) - 1;
359 <        if (*s == '\r') {  /* in case we get half a CRLF */
360 <            *s = fgetc(f);
361 <            if (*s != '\n') {
362 <                ungetc(*s, f);
363 <                *s = '\r';
364 <            }
365 <        }
366 <        if (*s == '\n') {
367 <            *s = 0;
368 <            if (s > buf && s[-1] == '\r')
369 <                s[-1] = 0;
370 <        } else {
371 <            char buf2[BUFSIZE];
372 <            log("load_ext_lang(): %s:%d: Line too long (maximum %d"
373 <                " characters)", filename, line, sizeof(buf)-2);
374 <            retval = 0;
375 <            while (fgets(buf2, sizeof(buf2), f)
376 <                   && *buf2 && buf2[strlen(buf2)-1] != '\n')
377 <                ;
378 <        }
379 <        if (*buf == '#')
380 <            continue;
381 <        if (*buf != '\t') {
382 <            curstr = curlang = -1;
383 <            s = strtok(buf, " \t\r\n");
384 <            if (!s)
385 <                continue;  /* empty line */
386 <            if ((curstr = lookup_string(s)) < 0) {
387 <                log("load_ext_lang: %s:%d: Unknown string ID `%s'",
388 <                    filename, line, s);
389 <                retval = 0;
390 <            } else {
391 <                s = strtok(NULL, " \t\r\n");
392 <                if (!s) {
393 <                    log("load_ext_lang: %s:%d: Missing language ID\n",
394 <                        filename, line);
395 <                    retval = 0;
396 <                    curstr = -1;
397 <                } else if ((curlang = lookup_language(s)) < 0) {
398 <                    log("load_ext_lang: %s:%d: Unknown language ID `%s'",
399 <                        filename, line, s);
400 <                    retval = 0;
401 <                    curstr = -1;
402 <                } else if (!is_loaded[curlang]) {
403 <                    log("load_ext_lang: %s:%d: Language `%s' is not"
404 <                        " available", filename, line, s);
405 <                    retval = 0;
406 <                    curstr = -1;
407 <                }
408 <            }
409 <            if (curstr >= 0 && curlang >= 0) {
410 <                /* Valid string/language ID--set up storage space if not
411 <                 * yet done */
412 <                if (!newtexts[curlang]) {
413 <                    newtexts[curlang] = calloc(num_strings+1, sizeof(char *));
414 <                    if (!newtexts[curlang]) {
415 <                        log_perror("load_ext_lang: %s:%d", filename, line);
416 <                        goto fail;
417 <                    }
418 <                    newsizes[curlang] = 0;
419 <                }
420 <                /* Point to location of string in data buffer; we add 1
421 <                 * to the offset to differentiate the value from 0 (not
422 <                 * present) */
423 <                newtexts[curlang][curstr+1] = (char *)newsizes[curlang] + 1;
424 <                /* Set first-line flag (signals whether to insert a
425 <                 * newline) */
426 <                firstline = 1;
427 <            }
428 <        } else {  /* line begins with tab -> text line */
429 <            if (curstr >= 0 && curlang >= 0) {
430 <                int oldsize = newsizes[curlang];
431 <                if (!firstline)
432 <                    oldsize--;  // overwrite the trailing \0 with a newline
433 <                newsizes[curlang] += strlen(buf+1)+1;  // skip initial tab
434 <                newtexts[curlang][0] =
435 <                    realloc(newtexts[curlang][0], newsizes[curlang]);
387 <                sprintf(newtexts[curlang][0]+oldsize, "%s%s",
388 <                        firstline ? "" : "\n", buf+1);
389 <                firstline = 0;
390 <            }
391 <        }
392 <    }  /* for each line */
393 <    fclose(f);
394 <
395 <    if (retval) {
396 <        /* Success, install new strings.  First set up new string arrays in
397 <         * newtexts[], then, when all succeeds (i.e. no ENOMEM), move the
398 <         * new data to langtexts[]. */
399 <        for (curlang = 0; curlang < NUM_LANGS; curlang++) {
400 <            char *newbuf;
401 <            uint32 oldlen, newlen;
402 <            if (!newtexts[curlang])
403 <                continue;
404 <            oldlen = *((uint32 *)langtexts[curlang][0]);
405 <            newlen = newsizes[curlang];
406 <            newbuf = malloc(4 + oldlen + newlen);
407 <            if (!newbuf) {
408 <                log_perror("load_ext_lang: %s:%d", filename, line);
409 <                goto fail;
410 <            }
411 <            *((uint32 *)newbuf) = oldlen + newlen;
412 <            memcpy(newbuf+4, langtexts[curlang][0]+4, oldlen);
413 <            memcpy(newbuf+4+oldlen, newtexts[curlang][0], newlen);
414 <            free(newtexts[curlang][0]);
415 <            newtexts[curlang][0] = newbuf;
416 <            for (i = 0; i < num_strings; i++) {
417 <                if (newtexts[curlang][i+1]) {
418 <                    int ofs = (int)newtexts[curlang][i+1] - 1;
419 <                    newtexts[curlang][i+1] = newbuf+4 + oldlen + ofs;
420 <                } else if (langtexts[curlang][i+1]) {
421 <                    int ofs = langtexts[curlang][i+1]
422 <                              - langtexts[curlang][0];
423 <                    newtexts[curlang][i+1] = newbuf + ofs;
424 <                } else {
425 <                    newtexts[curlang][i+1] = NULL;
426 <                }
427 <            }
428 <        }  /* for each language */
429 <        /* All okay, actually install the data */
430 <        for (curlang = 0; curlang < NUM_LANGS; curlang++) {
431 <            if (!newtexts[curlang])
432 <                continue;
433 <            free(langtexts[curlang][0]);
434 <            free(langtexts[curlang]);
435 <            langtexts[curlang] = newtexts[curlang];
436 <        }
437 <    }  /* if (retval) */
438 <
439 <    return retval;
440 <
441 <  fail:
442 <    for (curlang = 0; curlang < NUM_LANGS; curlang++) {
443 <        if (newtexts[curlang]) {
444 <            free(newtexts[curlang][0]);
445 <            free(newtexts[curlang]);
354 >  curstr = curlang = -1;
355 >  line = 0;
356 >  while (fgets(buf, sizeof(buf), f) && *buf)
357 >  {
358 >    line++;
359 >    s = buf + strlen(buf) - 1;
360 >    if (*s == '\r')
361 >    {                           /* in case we get half a CRLF */
362 >      *s = fgetc(f);
363 >      if (*s != '\n')
364 >      {
365 >        ungetc(*s, f);
366 >        *s = '\r';
367 >      }
368 >    }
369 >    if (*s == '\n')
370 >    {
371 >      *s = 0;
372 >      if (s > buf && s[-1] == '\r')
373 >        s[-1] = 0;
374 >    }
375 >    else
376 >    {
377 >      char buf2[BUFSIZE];
378 >      log("load_ext_lang(): %s:%d: Line too long (maximum %d"
379 >          " characters)", filename, line, sizeof(buf) - 2);
380 >      retval = 0;
381 >      while (fgets(buf2, sizeof(buf2), f)
382 >             && *buf2 && buf2[strlen(buf2) - 1] != '\n')
383 >        ;
384 >    }
385 >    if (*buf == '#')
386 >      continue;
387 >    if (*buf != '\t')
388 >    {
389 >      curstr = curlang = -1;
390 >      s = strtok(buf, " \t\r\n");
391 >      if (!s)
392 >        continue;               /* empty line */
393 >      if ((curstr = lookup_string(s)) < 0)
394 >      {
395 >        log("load_ext_lang: %s:%d: Unknown string ID `%s'",
396 >            filename, line, s);
397 >        retval = 0;
398 >      }
399 >      else
400 >      {
401 >        s = strtok(NULL, " \t\r\n");
402 >        if (!s)
403 >        {
404 >          log("load_ext_lang: %s:%d: Missing language ID\n", filename, line);
405 >          retval = 0;
406 >          curstr = -1;
407 >        }
408 >        else if ((curlang = lookup_language(s)) < 0)
409 >        {
410 >          log("load_ext_lang: %s:%d: Unknown language ID `%s'",
411 >              filename, line, s);
412 >          retval = 0;
413 >          curstr = -1;
414 >        }
415 >        else if (!is_loaded[curlang])
416 >        {
417 >          log("load_ext_lang: %s:%d: Language `%s' is not"
418 >              " available", filename, line, s);
419 >          retval = 0;
420 >          curstr = -1;
421 >        }
422 >      }
423 >      if (curstr >= 0 && curlang >= 0)
424 >      {
425 >        /* Valid string/language ID--set up storage space if not
426 >         * yet done */
427 >        if (!newtexts[curlang])
428 >        {
429 >          newtexts[curlang] = calloc(num_strings + 1, sizeof(char *));
430 >          if (!newtexts[curlang])
431 >          {
432 >            log_perror("load_ext_lang: %s:%d", filename, line);
433 >            goto fail;
434 >          }
435 >          newsizes[curlang] = 0;
436          }
437 <    }
438 <    fclose(f);
439 <    return 0;
437 >        /* Point to location of string in data buffer; we add 1
438 >         * to the offset to differentiate the value from 0 (not
439 >         * present) */
440 >        newtexts[curlang][curstr + 1] = (char *) newsizes[curlang] + 1;
441 >        /* Set first-line flag (signals whether to insert a
442 >         * newline) */
443 >        firstline = 1;
444 >      }
445 >    }
446 >    else
447 >    {                           /* line begins with tab -> text line */
448 >      if (curstr >= 0 && curlang >= 0)
449 >      {
450 >        int oldsize = newsizes[curlang];
451 >        if (!firstline)
452 >          oldsize--;            // overwrite the trailing \0 with a newline
453 >        newsizes[curlang] += strlen(buf + 1) + 1;       // skip initial tab
454 >        newtexts[curlang][0] =
455 >          realloc(newtexts[curlang][0], newsizes[curlang]);
456 >        sprintf(newtexts[curlang][0] + oldsize, "%s%s",
457 >                firstline ? "" : "\n", buf + 1);
458 >        firstline = 0;
459 >      }
460 >    }
461 >  }                             /* for each line */
462 >  fclose(f);
463 >
464 >  if (retval)
465 >  {
466 >    /* Success, install new strings.  First set up new string arrays in
467 >     * newtexts[], then, when all succeeds (i.e. no ENOMEM), move the
468 >     * new data to langtexts[]. */
469 >    for (curlang = 0; curlang < NUM_LANGS; curlang++)
470 >    {
471 >      char *newbuf;
472 >      uint32 oldlen, newlen;
473 >      if (!newtexts[curlang])
474 >        continue;
475 >      oldlen = *((uint32 *) langtexts[curlang][0]);
476 >      newlen = newsizes[curlang];
477 >      newbuf = malloc(4 + oldlen + newlen);
478 >      if (!newbuf)
479 >      {
480 >        log_perror("load_ext_lang: %s:%d", filename, line);
481 >        goto fail;
482 >      }
483 >      *((uint32 *) newbuf) = oldlen + newlen;
484 >      memcpy(newbuf + 4, langtexts[curlang][0] + 4, oldlen);
485 >      memcpy(newbuf + 4 + oldlen, newtexts[curlang][0], newlen);
486 >      free(newtexts[curlang][0]);
487 >      newtexts[curlang][0] = newbuf;
488 >      for (i = 0; i < num_strings; i++)
489 >      {
490 >        if (newtexts[curlang][i + 1])
491 >        {
492 >          int ofs = (int) newtexts[curlang][i + 1] - 1;
493 >          newtexts[curlang][i + 1] = newbuf + 4 + oldlen + ofs;
494 >        }
495 >        else if (langtexts[curlang][i + 1])
496 >        {
497 >          int ofs = langtexts[curlang][i + 1] - langtexts[curlang][0];
498 >          newtexts[curlang][i + 1] = newbuf + ofs;
499 >        }
500 >        else
501 >        {
502 >          newtexts[curlang][i + 1] = NULL;
503 >        }
504 >      }
505 >    }                           /* for each language */
506 >    /* All okay, actually install the data */
507 >    for (curlang = 0; curlang < NUM_LANGS; curlang++)
508 >    {
509 >      if (!newtexts[curlang])
510 >        continue;
511 >      free(langtexts[curlang][0]);
512 >      free(langtexts[curlang]);
513 >      langtexts[curlang] = newtexts[curlang];
514 >    }
515 >  }                             /* if (retval) */
516 >
517 >  return retval;
518 >
519 > fail:
520 >  for (curlang = 0; curlang < NUM_LANGS; curlang++)
521 >  {
522 >    if (newtexts[curlang])
523 >    {
524 >      free(newtexts[curlang][0]);
525 >      free(newtexts[curlang]);
526 >    }
527 >  }
528 >  fclose(f);
529 >  return 0;
530   }
531  
532   /*************************************************************************/
# Line 456 | Line 536 | int load_ext_lang(const char *filename)
536   * addstring() are retained but reset to empty.
537   */
538  
539 < void reset_ext_lang(void)
539 > void
540 > reset_ext_lang(void)
541   {
542 <    int i, j;
542 >  int i, j;
543  
544 <    for (i = 0; i < NUM_LANGS; i++) {
545 <        if (is_loaded[i]) {
546 <            uint32 datasize = *((uint32 *)origtexts[i][0]);
547 <            if (langtexts[i]) {
548 <                free(langtexts[i][0]);
549 <                free(langtexts[i]);
550 <            }
551 <            langtexts[i] = smalloc(sizeof(char *) * (num_strings+1));
552 <            langtexts[i][0] = smalloc(datasize+4);
553 <            memcpy(langtexts[i][0], origtexts[i][0], datasize+4);
554 <            for (j = 0; j < num_strings; j++) {
555 <                if (IS_BASE_STRING(j)) {
556 <                    if (origtexts[i][j+1]) {
557 <                        langtexts[i][j+1] = origtexts[i][j+1]
558 <                                          - origtexts[i][0]
559 <                                          + langtexts[i][0];
560 <                    } else {
561 <                        langtexts[i][j+1] = NULL;
562 <                    }
563 <                } else if (i == DEF_LANGUAGE) {
564 <                    langtexts[i][j+1] = langtexts[i][0] + datasize - 1;
565 <                } else {
566 <                    langtexts[i][j+1] = NULL;
567 <                }
568 <            }
544 >  for (i = 0; i < NUM_LANGS; i++)
545 >  {
546 >    if (is_loaded[i])
547 >    {
548 >      uint32 datasize = *((uint32 *) origtexts[i][0]);
549 >      if (langtexts[i])
550 >      {
551 >        free(langtexts[i][0]);
552 >        free(langtexts[i]);
553 >      }
554 >      langtexts[i] = smalloc(sizeof(char *) * (num_strings + 1));
555 >      langtexts[i][0] = smalloc(datasize + 4);
556 >      memcpy(langtexts[i][0], origtexts[i][0], datasize + 4);
557 >      for (j = 0; j < num_strings; j++)
558 >      {
559 >        if (IS_BASE_STRING(j))
560 >        {
561 >          if (origtexts[i][j + 1])
562 >          {
563 >            langtexts[i][j + 1] = origtexts[i][j + 1]
564 >              - origtexts[i][0] + langtexts[i][0];
565 >          }
566 >          else
567 >          {
568 >            langtexts[i][j + 1] = NULL;
569 >          }
570 >        }
571 >        else if (i == DEF_LANGUAGE)
572 >        {
573 >          langtexts[i][j + 1] = langtexts[i][0] + datasize - 1;
574          }
575 +        else
576 +        {
577 +          langtexts[i][j + 1] = NULL;
578 +        }
579 +      }
580      }
581 +  }
582   }
583  
584   /*************************************************************************/
# Line 496 | Line 588 | void reset_ext_lang(void)
588   * is not found, returns -1.
589   */
590  
591 < int lookup_language(const char *name)
591 > int
592 > lookup_language(const char *name)
593   {
594 <    int i;
594 >  int i;
595  
596 <    for (i = 0; filenames[i].num >= 0; i++) {
597 <        if (stricmp(filenames[i].filename, name) == 0)
598 <            return filenames[i].num;
599 <    }
600 <    return -1;
596 >  for (i = 0; filenames[i].num >= 0; i++)
597 >  {
598 >    if (stricmp(filenames[i].filename, name) == 0)
599 >      return filenames[i].num;
600 >  }
601 >  return -1;
602   }
603  
604   /*************************************************************************/
605  
606   /* Return true if the given language is loaded, false otherwise. */
607  
608 < int have_language(int language)
608 > int
609 > have_language(int language)
610   {
611 <    return language >= 0 && language < NUM_LANGS && is_loaded[language];
611 >  return language >= 0 && language < NUM_LANGS && is_loaded[language];
612   }
613  
614   /*************************************************************************/
# Line 522 | Line 617 | int have_language(int language)
617   * returns -1.  Note that string names are case sensitive.
618   */
619  
620 < int lookup_string(const char *name)
620 > int
621 > lookup_string(const char *name)
622   {
623 <    int i;
623 >  int i;
624  
625 <    for (i = 0; i < num_strings; i++) {
626 <        if (strcmp(langstrs[i], name) == 0)
627 <            return i;
628 <    }
629 <    return -1;
625 >  for (i = 0; i < num_strings; i++)
626 >  {
627 >    if (strcmp(langstrs[i], name) == 0)
628 >      return i;
629 >  }
630 >  return -1;
631   }
632  
633   /*************************************************************************/
# Line 539 | Line 636 | int lookup_string(const char *name)
636   * NickGroupInfo (if NickGroupInfo is NULL, use DEF_LANGUAGE).
637   */
638  
639 < const char *getstring(const NickGroupInfo *ngi, int index)
639 > const char *
640 > getstring(const NickGroupInfo * ngi, int index)
641   {
642 <    int language;
643 <    const char *text;
642 >  int language;
643 >  const char *text;
644  
645 <    if (index < 0 || index >= num_strings) {
646 <        log("getstring(): BUG: index (%d) out of range!", index);
647 <        return NULL;
648 <    }
649 <    language = (ngi && ngi != NICKGROUPINFO_INVALID
650 <                    && ngi->language != LANG_DEFAULT)
651 <               ? ngi->language
652 <               : DEF_LANGUAGE;
653 <    text = langtexts[language][langmap[index]+1];
654 <    if (!text)
655 <        text = langtexts[DEF_LANGUAGE][langmap[index]+1];
656 <    return text;
645 >  if (index < 0 || index >= num_strings)
646 >  {
647 >    log("getstring(): BUG: index (%d) out of range!", index);
648 >    return NULL;
649 >  }
650 >  language = (ngi && ngi != NICKGROUPINFO_INVALID
651 >              && ngi->language != LANG_DEFAULT)
652 >    ? ngi->language : DEF_LANGUAGE;
653 >  text = langtexts[language][langmap[index] + 1];
654 >  if (!text)
655 >    text = langtexts[DEF_LANGUAGE][langmap[index] + 1];
656 >  return text;
657   }
658  
659   /*************************************************************************/
660  
661   /* Retrieve a message text using the given language. */
662  
663 < const char *getstring_lang(int language, int index)
663 > const char *
664 > getstring_lang(int language, int index)
665   {
666 <    const char *text;
666 >  const char *text;
667  
668 <    if (language < 0 || language >= NUM_LANGS) {
669 <        log("getstring_lang(): BUG: language (%d) out of range!", language);
670 <        language = DEF_LANGUAGE;
671 <    } else if (index < 0 || index >= num_strings) {
672 <        log("getstring_lang(): BUG: index (%d) out of range!", index);
673 <        return NULL;
674 <    }
675 <    text = langtexts[language][langmap[index]+1];
676 <    if (!text)
677 <        text = langtexts[DEF_LANGUAGE][langmap[index]+1];
678 <    return text;
668 >  if (language < 0 || language >= NUM_LANGS)
669 >  {
670 >    log("getstring_lang(): BUG: language (%d) out of range!", language);
671 >    language = DEF_LANGUAGE;
672 >  }
673 >  else if (index < 0 || index >= num_strings)
674 >  {
675 >    log("getstring_lang(): BUG: index (%d) out of range!", index);
676 >    return NULL;
677 >  }
678 >  text = langtexts[language][langmap[index] + 1];
679 >  if (!text)
680 >    text = langtexts[DEF_LANGUAGE][langmap[index] + 1];
681 >  return text;
682   }
683  
684   /*************************************************************************/
# Line 587 | Line 689 | const char *getstring_lang(int language,
689   * to be saved by the caller.
690   */
691  
692 < int setstring(int language, int index, const char *text)
692 > int
693 > setstring(int language, int index, const char *text)
694   {
695 <    uint32 oldlen, newlen;
696 <    char *oldtext, *newtext;
697 <    int i;
698 <
699 <    if (language < 0 || language >= NUM_LANGS) {
700 <        log("setstring(): language (%d) out of range!", language);
701 <        return 0;
702 <    } else if (index < 0 || index >= num_strings) {
703 <        log("setstring(): index (%d) out of range!", index);
704 <        return 0;
705 <    } else if (IS_BASE_STRING(index)) {
706 <        log("setstring(): index (%d) is a base string and cannot be set",
707 <            index);
708 <        return 0;
709 <    } else if (!text) {
710 <        log("setstring(): text is NULL!");
711 <        return 0;
712 <    } else if (!is_loaded[language]) {
713 <        log_debug(1, "setstring(): language %d not available", language);
714 <        return 0;
715 <    }
716 <    oldtext = langtexts[language][0];
717 <    oldlen = *((uint32 *)oldtext);
718 <    newlen = oldlen + strlen(text) + 1;
719 <    newtext = malloc(newlen + 4);
720 <    if (!newtext) {
721 <        log("setstring(): out of memory");
722 <        return 0;
723 <    }
724 <    *((uint32 *)newtext) = newlen;
725 <    memcpy(newtext+4, oldtext+4, oldlen);
726 <    strcpy(newtext+4+oldlen, text);
727 <    for (i = 0; i < num_strings; i++) {
728 <        if (i == index) {
729 <            langtexts[language][i+1] = newtext+4 + oldlen;
730 <        } else {
731 <            int ofs = langtexts[language][i+1] - oldtext;
732 <            langtexts[language][i+1] = newtext + ofs;
733 <        }
734 <    }
735 <    langtexts[language][0] = newtext;
736 <    free(oldtext);
737 <    return 1;
695 >  uint32 oldlen, newlen;
696 >  char *oldtext, *newtext;
697 >  int i;
698 >
699 >  if (language < 0 || language >= NUM_LANGS)
700 >  {
701 >    log("setstring(): language (%d) out of range!", language);
702 >    return 0;
703 >  }
704 >  else if (index < 0 || index >= num_strings)
705 >  {
706 >    log("setstring(): index (%d) out of range!", index);
707 >    return 0;
708 >  }
709 >  else if (IS_BASE_STRING(index))
710 >  {
711 >    log("setstring(): index (%d) is a base string and cannot be set", index);
712 >    return 0;
713 >  }
714 >  else if (!text)
715 >  {
716 >    log("setstring(): text is NULL!");
717 >    return 0;
718 >  }
719 >  else if (!is_loaded[language])
720 >  {
721 >    log_debug(1, "setstring(): language %d not available", language);
722 >    return 0;
723 >  }
724 >  oldtext = langtexts[language][0];
725 >  oldlen = *((uint32 *) oldtext);
726 >  newlen = oldlen + strlen(text) + 1;
727 >  newtext = malloc(newlen + 4);
728 >  if (!newtext)
729 >  {
730 >    log("setstring(): out of memory");
731 >    return 0;
732 >  }
733 >  *((uint32 *) newtext) = newlen;
734 >  memcpy(newtext + 4, oldtext + 4, oldlen);
735 >  strcpy(newtext + 4 + oldlen, text);
736 >  for (i = 0; i < num_strings; i++)
737 >  {
738 >    if (i == index)
739 >    {
740 >      langtexts[language][i + 1] = newtext + 4 + oldlen;
741 >    }
742 >    else
743 >    {
744 >      int ofs = langtexts[language][i + 1] - oldtext;
745 >      langtexts[language][i + 1] = newtext + ofs;
746 >    }
747 >  }
748 >  langtexts[language][0] = newtext;
749 >  free(oldtext);
750 >  return 1;
751   }
752  
753   /*************************************************************************/
# Line 641 | Line 757 | int setstring(int language, int index, c
757   * parameter).
758   */
759  
760 < int mapstring(int old, int new)
760 > int
761 > mapstring(int old, int new)
762   {
763 <    int prev;
763 >  int prev;
764  
765 <    if (old < 0 || old >= num_strings) {
766 <        log("mapstring(): old string index (%d) is out of range!", old);
767 <        return -1;
768 <    } else if (new < 0 || new >= num_strings) {
769 <        log("mapstring(): new string index (%d) is out of range!", new);
770 <        return -1;
771 <    }
772 <    prev = langmap[old];
773 <    langmap[old] = langmap[new];
774 <    return prev;
765 >  if (old < 0 || old >= num_strings)
766 >  {
767 >    log("mapstring(): old string index (%d) is out of range!", old);
768 >    return -1;
769 >  }
770 >  else if (new < 0 || new >= num_strings)
771 >  {
772 >    log("mapstring(): new string index (%d) is out of range!", new);
773 >    return -1;
774 >  }
775 >  prev = langmap[old];
776 >  langmap[old] = langmap[new];
777 >  return prev;
778   }
779  
780   /*************************************************************************/
# Line 666 | Line 786 | int mapstring(int old, int new)
786   * (invalid parameters or attempting to re-add a base string).
787   */
788  
789 < int addstring(const char *name)
789 > int
790 > addstring(const char *name)
791   {
792 <    int index, i;
793 <    char **new_langstrs, **new_langtexts[NUM_LANGS];
794 <    int *new_langmap;
795 <
796 <    if (!name) {
797 <        log("addstring(): BUG: name is NULL!");
798 <        return -1;
799 <    }
800 <    if (!*name) {
801 <        log("addstring(): name is the empty string!");
802 <        return -1;
803 <    }
804 <    if ((index = lookup_string(name)) >= 0) {
805 <        if (IS_BASE_STRING(index)) {
806 <            log("addstring(): attempt to re-add base string `%s'!", name);
807 <            return -1;
808 <        } else {
809 <            return index;
810 <        }
811 <    }
812 <    new_langstrs = malloc(sizeof(char *) * (num_strings+1));
813 <    new_langmap = malloc(sizeof(int) * (num_strings+1));
814 <    if (!new_langstrs || !new_langmap) {
815 <        log("addstring(): Out of memory!");
816 <        free(new_langmap);
817 <        free(new_langstrs);
818 <        return -1;
819 <    }
820 <    memcpy(new_langstrs, langstrs, sizeof(char *) * num_strings);
821 <    memcpy(new_langmap, langmap, sizeof(int) * num_strings);
822 <    new_langstrs[num_strings] = strdup(name);
823 <    if (!new_langstrs[num_strings]) {
824 <        log("addstring(): Out of memory!");
825 <        free(new_langmap);
826 <        free(new_langstrs);
827 <        return -1;
828 <    }
829 <    new_langmap[num_strings] = num_strings;
830 <    for (i = 0; i < NUM_LANGS; i++) {
831 <        if (!is_loaded[i])
832 <            continue;
833 <        new_langtexts[i] = malloc(sizeof(char *) * (num_strings+2));
834 <        if (!new_langtexts[i]) {
835 <            log("addstring(): Out of memory!");
836 <            while (--i >= 0)
837 <                free(new_langtexts[i]);
838 <            free(new_langstrs[num_strings]);
839 <            free(new_langmap);
840 <            free(new_langstrs);
841 <            return -1;
842 <        }
843 <        memcpy(new_langtexts[i], langtexts[i],
844 <               sizeof(char *) * (num_strings+1));
845 <        if (i == DEF_LANGUAGE) {
846 <            /* Point at the \0 ending the last string in the text buffer */
847 <            new_langtexts[i][num_strings+1] =
848 <                new_langtexts[i][0]+4 + *((uint32 *)new_langtexts[i][0]) - 1;
849 <        } else {
850 <            new_langtexts[i][num_strings+1] = NULL;
851 <        }
852 <    }
853 <    free(langstrs);
854 <    langstrs = new_langstrs;
855 <    free(langmap);
856 <    langmap = new_langmap;
857 <    for (i = 0; i < NUM_LANGS; i++) {
858 <        if (is_loaded[i]) {
859 <            free(langtexts[i]);
860 <            langtexts[i] = new_langtexts[i];
861 <        }
792 >  int index, i;
793 >  char **new_langstrs, **new_langtexts[NUM_LANGS];
794 >  int *new_langmap;
795 >
796 >  if (!name)
797 >  {
798 >    log("addstring(): BUG: name is NULL!");
799 >    return -1;
800 >  }
801 >  if (!*name)
802 >  {
803 >    log("addstring(): name is the empty string!");
804 >    return -1;
805 >  }
806 >  if ((index = lookup_string(name)) >= 0)
807 >  {
808 >    if (IS_BASE_STRING(index))
809 >    {
810 >      log("addstring(): attempt to re-add base string `%s'!", name);
811 >      return -1;
812 >    }
813 >    else
814 >    {
815 >      return index;
816 >    }
817 >  }
818 >  new_langstrs = malloc(sizeof(char *) * (num_strings + 1));
819 >  new_langmap = malloc(sizeof(int) * (num_strings + 1));
820 >  if (!new_langstrs || !new_langmap)
821 >  {
822 >    log("addstring(): Out of memory!");
823 >    free(new_langmap);
824 >    free(new_langstrs);
825 >    return -1;
826 >  }
827 >  memcpy(new_langstrs, langstrs, sizeof(char *) * num_strings);
828 >  memcpy(new_langmap, langmap, sizeof(int) * num_strings);
829 >  new_langstrs[num_strings] = strdup(name);
830 >  if (!new_langstrs[num_strings])
831 >  {
832 >    log("addstring(): Out of memory!");
833 >    free(new_langmap);
834 >    free(new_langstrs);
835 >    return -1;
836 >  }
837 >  new_langmap[num_strings] = num_strings;
838 >  for (i = 0; i < NUM_LANGS; i++)
839 >  {
840 >    if (!is_loaded[i])
841 >      continue;
842 >    new_langtexts[i] = malloc(sizeof(char *) * (num_strings + 2));
843 >    if (!new_langtexts[i])
844 >    {
845 >      log("addstring(): Out of memory!");
846 >      while (--i >= 0)
847 >        free(new_langtexts[i]);
848 >      free(new_langstrs[num_strings]);
849 >      free(new_langmap);
850 >      free(new_langstrs);
851 >      return -1;
852 >    }
853 >    memcpy(new_langtexts[i], langtexts[i],
854 >           sizeof(char *) * (num_strings + 1));
855 >    if (i == DEF_LANGUAGE)
856 >    {
857 >      /* Point at the \0 ending the last string in the text buffer */
858 >      new_langtexts[i][num_strings + 1] =
859 >        new_langtexts[i][0] + 4 + *((uint32 *) new_langtexts[i][0]) - 1;
860 >    }
861 >    else
862 >    {
863 >      new_langtexts[i][num_strings + 1] = NULL;
864 >    }
865 >  }
866 >  free(langstrs);
867 >  langstrs = new_langstrs;
868 >  free(langmap);
869 >  langmap = new_langmap;
870 >  for (i = 0; i < NUM_LANGS; i++)
871 >  {
872 >    if (is_loaded[i])
873 >    {
874 >      free(langtexts[i]);
875 >      langtexts[i] = new_langtexts[i];
876      }
877 <    return num_strings++;
877 >  }
878 >  return num_strings++;
879   }
880  
881   /*************************************************************************/
# Line 756 | Line 892 | int addstring(const char *name)
892   * greater than BUFSIZE or contains the '%' character.
893   */
894  
895 < int strftime_lang(char *buf, int size, const NickGroupInfo *ngi,
896 <                  int format, time_t time)
895 > int
896 > strftime_lang(char *buf, int size, const NickGroupInfo * ngi,
897 >              int format, time_t time)
898   {
899 <    int ngi_is_valid = (ngi && ngi != NICKGROUPINFO_INVALID);
900 <    int language = (ngi_is_valid && ngi->language != LANG_DEFAULT)
901 <                   ? ngi->language
902 <                   : DEF_LANGUAGE;
903 <    char tmpbuf[BUFSIZE], buf2[BUFSIZE];
904 <    char *s;
905 <    int i, ret;
906 <    struct tm *tm;
907 <
908 <    strbcpy(tmpbuf, getstring_lang(language,format));
909 <    if (ngi_is_valid && ngi->timezone != TIMEZONE_DEFAULT) {
910 <        time += ngi->timezone*60;
911 <        tm = gmtime(&time);
912 <        /* Remove "%Z" (timezone) specifiers */
913 <        while ((s = strstr(tmpbuf, "%Z")) != NULL) {
914 <            char *end = s+2;
915 <            while (s > tmpbuf && s[-1] == ' ')
916 <                s--;
917 <            strmove(s, end);
918 <        }
919 <    } else {
920 <        tm = localtime(&time);
921 <    }
922 <    if ((s = langtexts[language][STRFTIME_DAYS_SHORT+1]) != NULL) {
923 <        for (i = 0; i < tm->tm_wday; i++)
924 <            s += strcspn(s, "\n")+1;
925 <        i = strcspn(s, "\n");
926 <        strncpy(buf2, s, i);
927 <        buf2[i] = 0;
928 <        strnrepl(tmpbuf, sizeof(tmpbuf), "%a", buf2);
929 <    }
930 <    if ((s = langtexts[language][STRFTIME_DAYS_LONG+1]) != NULL) {
931 <        for (i = 0; i < tm->tm_wday; i++)
932 <            s += strcspn(s, "\n")+1;
933 <        i = strcspn(s, "\n");
934 <        strncpy(buf2, s, i);
935 <        buf2[i] = 0;
936 <        strnrepl(tmpbuf, sizeof(tmpbuf), "%A", buf2);
937 <    }
938 <    if ((s = langtexts[language][STRFTIME_MONTHS_SHORT+1]) != NULL) {
939 <        for (i = 0; i < tm->tm_mon; i++)
940 <            s += strcspn(s, "\n")+1;
941 <        i = strcspn(s, "\n");
942 <        strncpy(buf2, s, i);
943 <        buf2[i] = 0;
944 <        strnrepl(tmpbuf, sizeof(tmpbuf), "%b", buf2);
945 <    }
946 <    if ((s = langtexts[language][STRFTIME_MONTHS_LONG+1]) != NULL) {
947 <        for (i = 0; i < tm->tm_mon; i++)
948 <            s += strcspn(s, "\n")+1;
949 <        i = strcspn(s, "\n");
950 <        strncpy(buf2, s, i);
951 <        buf2[i] = 0;
952 <        strnrepl(tmpbuf, sizeof(tmpbuf), "%B", buf2);
953 <    }
954 <    ret = strftime(buf, size, tmpbuf, tm);
955 <    if (ret >= size)  // buffer overflow, should be impossible
956 <        return 0;
957 <    return ret;
899 >  int ngi_is_valid = (ngi && ngi != NICKGROUPINFO_INVALID);
900 >  int language = (ngi_is_valid && ngi->language != LANG_DEFAULT)
901 >    ? ngi->language : DEF_LANGUAGE;
902 >  char tmpbuf[BUFSIZE], buf2[BUFSIZE];
903 >  char *s;
904 >  int i, ret;
905 >  struct tm *tm;
906 >
907 >  strbcpy(tmpbuf, getstring_lang(language, format));
908 >  if (ngi_is_valid && ngi->timezone != TIMEZONE_DEFAULT)
909 >  {
910 >    time += ngi->timezone * 60;
911 >    tm = gmtime(&time);
912 >    /* Remove "%Z" (timezone) specifiers */
913 >    while ((s = strstr(tmpbuf, "%Z")) != NULL)
914 >    {
915 >      char *end = s + 2;
916 >      while (s > tmpbuf && s[-1] == ' ')
917 >        s--;
918 >      strmove(s, end);
919 >    }
920 >  }
921 >  else
922 >  {
923 >    tm = localtime(&time);
924 >  }
925 >  if ((s = langtexts[language][STRFTIME_DAYS_SHORT + 1]) != NULL)
926 >  {
927 >    for (i = 0; i < tm->tm_wday; i++)
928 >      s += strcspn(s, "\n") + 1;
929 >    i = strcspn(s, "\n");
930 >    strncpy(buf2, s, i);
931 >    buf2[i] = 0;
932 >    strnrepl(tmpbuf, sizeof(tmpbuf), "%a", buf2);
933 >  }
934 >  if ((s = langtexts[language][STRFTIME_DAYS_LONG + 1]) != NULL)
935 >  {
936 >    for (i = 0; i < tm->tm_wday; i++)
937 >      s += strcspn(s, "\n") + 1;
938 >    i = strcspn(s, "\n");
939 >    strncpy(buf2, s, i);
940 >    buf2[i] = 0;
941 >    strnrepl(tmpbuf, sizeof(tmpbuf), "%A", buf2);
942 >  }
943 >  if ((s = langtexts[language][STRFTIME_MONTHS_SHORT + 1]) != NULL)
944 >  {
945 >    for (i = 0; i < tm->tm_mon; i++)
946 >      s += strcspn(s, "\n") + 1;
947 >    i = strcspn(s, "\n");
948 >    strncpy(buf2, s, i);
949 >    buf2[i] = 0;
950 >    strnrepl(tmpbuf, sizeof(tmpbuf), "%b", buf2);
951 >  }
952 >  if ((s = langtexts[language][STRFTIME_MONTHS_LONG + 1]) != NULL)
953 >  {
954 >    for (i = 0; i < tm->tm_mon; i++)
955 >      s += strcspn(s, "\n") + 1;
956 >    i = strcspn(s, "\n");
957 >    strncpy(buf2, s, i);
958 >    buf2[i] = 0;
959 >    strnrepl(tmpbuf, sizeof(tmpbuf), "%B", buf2);
960 >  }
961 >  ret = strftime(buf, size, tmpbuf, tm);
962 >  if (ret >= size)              // buffer overflow, should be impossible
963 >    return 0;
964 >  return ret;
965   }
966  
967   /*************************************************************************/
# Line 834 | Line 978 | int strftime_lang(char *buf, int size, c
978   * language.h.
979   */
980  
981 < char *maketime(const NickGroupInfo *ngi, time_t time, int flags)
981 > char *
982 > maketime(const NickGroupInfo * ngi, time_t time, int flags)
983   {
984 <    static char buf[BUFSIZE];
985 <    int unit;
984 >  static char buf[BUFSIZE];
985 >  int unit;
986  
987 <    if (time < 1)  /* Enforce a minimum of one second */
988 <        time = 1;
987 >  if (time < 1)                 /* Enforce a minimum of one second */
988 >    time = 1;
989  
990 <    if ((flags & MT_SECONDS) && time <= 59) {
991 <
847 <        unit = (time==1 ? STR_SECOND : STR_SECONDS);
848 <        snprintf(buf, sizeof(buf), "%ld%s", (long)time, getstring(ngi,unit));
849 <
850 <    } else if (!(flags & MT_SECONDS) && time <= 59*60) {
851 <
852 <        time = (time+59) / 60;
853 <        unit = (time==1 ? STR_MINUTE : STR_MINUTES);
854 <        snprintf(buf, sizeof(buf), "%ld%s", (long)time, getstring(ngi,unit));
855 <
856 <
857 <    } else if (flags & MT_DUALUNIT) {
858 <
859 <        time_t time2;
860 <        int unit2;
861 <
862 <        if (time <= 59*60+59) {  /* 59 minutes, 59 seconds */
863 <            time2 = time % 60;
864 <            unit2 = (time2==1 ? STR_SECOND : STR_SECONDS);
865 <            time = time / 60;
866 <            unit = (time==1 ? STR_MINUTE : STR_MINUTES);
867 <        } else if (time <= (23*60+59)*60+30) {  /* 23 hours, 59.5 minutes */
868 <            time = (time+30) / 60;
869 <            time2 = time % 60;
870 <            unit2 = (time2==1 ? STR_MINUTE : STR_MINUTES);
871 <            time = time / 60;
872 <            unit = (time==1 ? STR_HOUR : STR_HOURS);
873 <        } else {
874 <            time = (time+(30*60)) / (60*60);
875 <            time2 = time % 24;
876 <            unit2 = (time2==1 ? STR_HOUR : STR_HOURS);
877 <            time = time / 24;
878 <            unit = (time==1 ? STR_DAY : STR_DAYS);
879 <        }
880 <        if (time2)
881 <            snprintf(buf, sizeof(buf), "%ld%s%s%ld%s", (long)time,
882 <                     getstring(ngi,unit), getstring(ngi,STR_TIMESEP),
883 <                     (long)time2, getstring(ngi,unit2));
884 <        else
885 <            snprintf(buf, sizeof(buf), "%ld%s", (long)time,
886 <                     getstring(ngi,unit));
887 <
888 <    } else {  /* single unit */
889 <
890 <        if (time <= 59*60+30) {  /* 59 min 30 sec; MT_SECONDS known true */
891 <            time = (time+30) / 60;
892 <            unit = (time==1 ? STR_MINUTE : STR_MINUTES);
893 <        } else if (time <= (23*60+30)*60) {  /* 23 hours, 30 minutes */
894 <            time = (time+(30*60)) / (60*60);
895 <            unit = (time==1 ? STR_HOUR : STR_HOURS);
896 <        } else {
897 <            time = (time+(12*60*60)) / (24*60*60);
898 <            unit = (time==1 ? STR_DAY : STR_DAYS);
899 <        }
900 <        snprintf(buf, sizeof(buf), "%ld%s", (long)time, getstring(ngi,unit));
990 >  if ((flags & MT_SECONDS) && time <= 59)
991 >  {
992  
993 +    unit = (time == 1 ? STR_SECOND : STR_SECONDS);
994 +    snprintf(buf, sizeof(buf), "%ld%s", (long) time, getstring(ngi, unit));
995 +
996 +  }
997 +  else if (!(flags & MT_SECONDS) && time <= 59 * 60)
998 +  {
999 +
1000 +    time = (time + 59) / 60;
1001 +    unit = (time == 1 ? STR_MINUTE : STR_MINUTES);
1002 +    snprintf(buf, sizeof(buf), "%ld%s", (long) time, getstring(ngi, unit));
1003 +
1004 +
1005 +  }
1006 +  else if (flags & MT_DUALUNIT)
1007 +  {
1008 +
1009 +    time_t time2;
1010 +    int unit2;
1011 +
1012 +    if (time <= 59 * 60 + 59)
1013 +    {                           /* 59 minutes, 59 seconds */
1014 +      time2 = time % 60;
1015 +      unit2 = (time2 == 1 ? STR_SECOND : STR_SECONDS);
1016 +      time = time / 60;
1017 +      unit = (time == 1 ? STR_MINUTE : STR_MINUTES);
1018 +    }
1019 +    else if (time <= (23 * 60 + 59) * 60 + 30)
1020 +    {                           /* 23 hours, 59.5 minutes */
1021 +      time = (time + 30) / 60;
1022 +      time2 = time % 60;
1023 +      unit2 = (time2 == 1 ? STR_MINUTE : STR_MINUTES);
1024 +      time = time / 60;
1025 +      unit = (time == 1 ? STR_HOUR : STR_HOURS);
1026 +    }
1027 +    else
1028 +    {
1029 +      time = (time + (30 * 60)) / (60 * 60);
1030 +      time2 = time % 24;
1031 +      unit2 = (time2 == 1 ? STR_HOUR : STR_HOURS);
1032 +      time = time / 24;
1033 +      unit = (time == 1 ? STR_DAY : STR_DAYS);
1034 +    }
1035 +    if (time2)
1036 +      snprintf(buf, sizeof(buf), "%ld%s%s%ld%s", (long) time,
1037 +               getstring(ngi, unit), getstring(ngi, STR_TIMESEP),
1038 +               (long) time2, getstring(ngi, unit2));
1039 +    else
1040 +      snprintf(buf, sizeof(buf), "%ld%s", (long) time, getstring(ngi, unit));
1041 +
1042 +  }
1043 +  else
1044 +  {                             /* single unit */
1045 +
1046 +    if (time <= 59 * 60 + 30)
1047 +    {                           /* 59 min 30 sec; MT_SECONDS known true */
1048 +      time = (time + 30) / 60;
1049 +      unit = (time == 1 ? STR_MINUTE : STR_MINUTES);
1050 +    }
1051 +    else if (time <= (23 * 60 + 30) * 60)
1052 +    {                           /* 23 hours, 30 minutes */
1053 +      time = (time + (30 * 60)) / (60 * 60);
1054 +      unit = (time == 1 ? STR_HOUR : STR_HOURS);
1055 +    }
1056 +    else
1057 +    {
1058 +      time = (time + (12 * 60 * 60)) / (24 * 60 * 60);
1059 +      unit = (time == 1 ? STR_DAY : STR_DAYS);
1060      }
1061 +    snprintf(buf, sizeof(buf), "%ld%s", (long) time, getstring(ngi, unit));
1062 +
1063 +  }
1064  
1065 <    return buf;
1065 >  return buf;
1066   }
1067  
1068   /*************************************************************************/
# Line 914 | Line 1075 | char *maketime(const NickGroupInfo *ngi,
1075   * null byte).
1076   */
1077  
1078 < void expires_in_lang(char *buf, int size, const NickGroupInfo *ngi,
1079 <                     time_t expires)
1078 > void
1079 > expires_in_lang(char *buf, int size, const NickGroupInfo * ngi,
1080 >                time_t expires)
1081   {
1082 <    time_t seconds = expires - time(NULL);
1082 >  time_t seconds = expires - time(NULL);
1083  
1084 <    if (expires == 0) {
1085 <        strscpy(buf, getstring(ngi,EXPIRES_NONE), size);
1086 <    } else if (seconds <= 0 && noexpire) {
1087 <        strscpy(buf, getstring(ngi,EXPIRES_NOW), size);
1088 <    } else {
1089 <        if (seconds <= 0) {
1090 <            /* Already expired--it will be cleared out by the next get() */
1091 <            seconds = 1;
1092 <        }
1093 <        snprintf(buf, size, getstring(ngi,EXPIRES_IN),
1094 <                 maketime(ngi,seconds,MT_DUALUNIT));
1095 <    }
1084 >  if (expires == 0)
1085 >  {
1086 >    strscpy(buf, getstring(ngi, EXPIRES_NONE), size);
1087 >  }
1088 >  else if (seconds <= 0 && noexpire)
1089 >  {
1090 >    strscpy(buf, getstring(ngi, EXPIRES_NOW), size);
1091 >  }
1092 >  else
1093 >  {
1094 >    if (seconds <= 0)
1095 >    {
1096 >      /* Already expired--it will be cleared out by the next get() */
1097 >      seconds = 1;
1098 >    }
1099 >    snprintf(buf, size, getstring(ngi, EXPIRES_IN),
1100 >             maketime(ngi, seconds, MT_DUALUNIT));
1101 >  }
1102   }
1103  
1104   /*************************************************************************/
# Line 938 | Line 1106 | void expires_in_lang(char *buf, int size
1106  
1107   /* Send a syntax-error message to the user. */
1108  
1109 < void syntax_error(const char *service, const User *u, const char *command,
1110 <                  int msgnum)
1109 > void
1110 > syntax_error(const char *service, const User * u, const char *command,
1111 >             int msgnum)
1112   {
1113 <    char buf[BUFSIZE];
1114 <    snprintf(buf, sizeof(buf), getstring(u->ngi, msgnum), command);
1115 <    notice_lang(service, u, SYNTAX_ERROR, buf);
1116 <    notice_lang(service, u, MORE_INFO, service, command);
1113 >  char buf[BUFSIZE];
1114 >  snprintf(buf, sizeof(buf), getstring(u->ngi, msgnum), command);
1115 >  notice_lang(service, u, SYNTAX_ERROR, buf);
1116 >  notice_lang(service, u, MORE_INFO, service, command);
1117   }
1118  
1119   /*************************************************************************/

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)