/[cvs]/eggdrop1.9/src/language.c
ViewVC logotype

Contents of /eggdrop1.9/src/language.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.5 - (show annotations) (download) (as text)
Sat Dec 11 18:58:03 1999 UTC (19 years, 7 months ago) by fabian
Branch: MAIN
Changes since 1.4: +16 -16 lines
File MIME type: text/x-chdr
tothwolf's remove-context-bloat patch

1 /*
2 * language.c - language support code.
3 */
4
5 /*
6 * DOES:
7 * Nothing <- typical BB code :)
8 *
9 * ENVIRONMENT VARIABLES:
10 * EGG_LANG - language to use (default: "english")
11 * EGG_LANGDIR - directory with all lang files
12 * (default: "./language")
13 * WILL DO:
14 * Upon loading:
15 * o default loads section core, if possible.
16 * Commands:
17 * DCC .+lang <language>
18 * DCC .-lang <language>
19 * DCC .+lsec <section>
20 * DCC .-lsec <section>
21 * DCC .relang
22 * DCC .ldump
23 * DCC .lstat
24 *
25 * FILE FORMAT: language.lang
26 * <textidx>,<text>
27 * TEXT MESSAGE USAGE:
28 * get_language(<textidx> [,<PARMS>])
29 *
30 * ADDING LANGUAGES:
31 * o Copy an existing <section>.<oldlanguage>.lang to a
32 * new .lang file and modify as needed.
33 * Use %s or %d where necessary, for plug-in
34 * insertions of parameters (see core.english.lang).
35 * o Ensure <section>.<newlanguage>.lang is in the lang
36 * directory.
37 * o .+lang <newlanguage>
38 * ADDING SECTIONS:
39 * o Create a <newsection>.english.lang file.
40 * o Add add_lang_section("<newsection>"); to your module
41 * startup function.
42 *
43 */
44
45 #include "main.h"
46
47 extern struct dcc_t *dcc;
48
49 typedef struct lang_st {
50 struct lang_st *next;
51 char *lang;
52 char *section;
53 } lang_sec;
54
55 typedef struct lang_pr {
56 struct lang_pr *next;
57 char *lang;
58 } lang_pri;
59
60 typedef struct lang_t {
61 int idx;
62 char *text;
63 struct lang_t *next;
64 } lang_tab;
65
66 static lang_tab *langtab[64];
67 static lang_sec *langsection = NULL;
68 static lang_pri *langpriority = NULL;
69
70 static int del_lang(char *);
71 static int add_message(int, char *);
72 static void recheck_lang_sections(void);
73 static void read_lang(char *);
74 void add_lang_section(char *);
75 int del_lang_section(char *);
76 static char *get_specific_langfile(char *, lang_sec *);
77 static char *get_langfile(lang_sec *);
78 static int split_lang(char *, char **, char **);
79 int cmd_loadlanguage(struct userrec *, int, char *);
80
81
82 /* add a new preferred language to the list of languages. Newly added
83 * languages get the highest priority.
84 */
85 void add_lang(char *lang)
86 {
87 lang_pri *lp = langpriority, *lpo = NULL;
88
89 Context;
90 while (lp) {
91 /* the language already exists, moving to the beginning */
92 if (!strcmp(lang, lp->lang)) {
93 /* already at the front? */
94 if (!lpo)
95 return;
96 lpo->next = lp->next;
97 lp->next = lpo;
98 langpriority = lp;
99 return;
100 }
101 lpo = lp;
102 lp = lp->next;
103 }
104
105 /* no existing entry, create a new one */
106 lp = nmalloc(sizeof(lang_pri));
107 lp->lang = nmalloc(strlen(lang) + 1);
108 strcpy(lp->lang, lang);
109 lp->next = NULL;
110
111 /* if we have other entries, point to the beginning of the old list */
112 if (langpriority)
113 lp->next = langpriority;
114 langpriority = lp;
115 putlog(LOG_MISC, "*", "LANG: Added language support for %s.", lang);
116 }
117
118 /* remove a language from the list of preferred languages. */
119 static int del_lang(char *lang)
120 {
121 lang_pri *lp = langpriority, *lpo = NULL;
122
123 Context;
124 while (lp) {
125 /* found the language? */
126 if (!strcmp(lang, lp->lang)) {
127 if (lpo)
128 lpo->next = lp->next;
129 else
130 langpriority = lp->next;
131 if (lp->lang)
132 nfree(lp->lang);
133 nfree(lp);
134 putlog(LOG_MISC, "*", "LANG: Not supporting language %s any longer.",
135 lang);
136 return 1;
137 }
138 lpo = lp;
139 lp = lp->next;
140 }
141 /* language not found */
142 return 0;
143 }
144
145 static int add_message(int lidx, char *ltext)
146 {
147 lang_tab *l = langtab[lidx & 63];
148
149 while (l) {
150 if (l->idx && (l->idx == lidx)) {
151 nfree(l->text);
152 l->text = nmalloc(strlen(ltext) + 1);
153 strcpy(l->text, ltext);
154 return 1;
155 }
156 if (!l->next)
157 break;
158 l = l->next;
159 }
160 if (l) {
161 l->next = nmalloc(sizeof(lang_tab));
162 l = l->next;
163 } else
164 l = langtab[lidx & 63] = nmalloc(sizeof(lang_tab));
165 l->idx = lidx;
166 l->text = nmalloc(strlen(ltext) + 1);
167 strcpy(l->text, ltext);
168 l->next = 0;
169 return 0;
170 }
171
172 /* recheck all sections and check if any language files are available
173 * which match the preferred language(s) more closely
174 */
175 static void recheck_lang_sections(void)
176 {
177 lang_sec *ls = langsection;
178 char *langfile;
179
180 Context;
181 while (ls) {
182 if (ls->section) {
183 langfile = get_langfile(ls);
184 /* found a language with a more preferred language? */
185 if (langfile) {
186 read_lang(langfile);
187 nfree(langfile);
188 }
189 }
190 ls = ls->next;
191 }
192 }
193
194 /* parse a language file */
195 static void read_lang(char *langfile)
196 {
197 FILE *FLANG;
198 char lbuf[512];
199 char *ltext = NULL;
200 char *ctmp, *ctmp1;
201 int lidx;
202 int lline = 0;
203 int lskip;
204 int ltexts = 0;
205 int ladd = 0, lupdate = 0;
206
207 Context;
208 FLANG = fopen(langfile, "r");
209 if (FLANG == NULL) {
210 putlog(LOG_MISC, "*", "LANG: unexpected: reading from file %s failed.",
211 langfile);
212 return;
213 }
214
215 lskip = 0;
216 while (fgets(lbuf, 511, FLANG)) {
217 lline++;
218 if (lbuf[0] != '#' || lskip) {
219 ltext = nrealloc(ltext, 512);
220 if (sscanf(lbuf, "%s", ltext) != EOF) {
221 if (sscanf(lbuf, "0x%x,%500c", &lidx, ltext) != 2) {
222 putlog(LOG_MISC, "*", "Malformed text line in %s at %d.",
223 langfile, lline);
224 } else {
225 ltexts++;
226 ctmp = strchr(ltext, '\n');
227 *ctmp = 0;
228 while (ltext[strlen(ltext) - 1] == '\\') {
229 ltext[strlen(ltext) - 1] = 0;
230 if (fgets(lbuf, 511, FLANG)) {
231 lline++;
232 ctmp = strchr(lbuf, '\n');
233 *ctmp = 0;
234 ltext = nrealloc(ltext, strlen(lbuf) + strlen(ltext) + 1);
235 strcpy(strchr(ltext, 0), lbuf);
236 }
237 }
238 }
239 /* We gotta fix \n's here as, being arguments to sprintf(), */
240 /* they won't get translated */
241 ctmp = ltext;
242 ctmp1 = ltext;
243 while (*ctmp1) {
244 if (*ctmp1 == '\\' && *(ctmp1 + 1) == 'n') {
245 *ctmp = '\n';
246 ctmp1++;
247 } else
248 *ctmp = *ctmp1;
249 ctmp++;
250 ctmp1++;
251 }
252 *ctmp = '\0';
253 if (add_message(lidx, ltext)) {
254 lupdate++;
255 } else
256 ladd++;
257 }
258 } else {
259 ctmp = strchr(lbuf, '\n');
260 if (lskip && (strlen(lbuf) == 1 || *(ctmp - 1) != '\\'))
261 lskip = 0;
262 }
263 }
264 nfree(ltext);
265 fclose(FLANG);
266
267 putlog(LOG_MISC, "*", "LANG: %d messages of %d lines loaded from %s",
268 ltexts, lline, langfile);
269 putlog(LOG_MISC, "*", "LANG: %d adds, %d updates to message table",
270 ladd, lupdate);
271 }
272
273 /* Add a new language section. e.g. section "core"
274 * Load an apropriate language file for the specified section.
275 */
276 void add_lang_section(char *section)
277 {
278 char *langfile = NULL;
279 lang_sec *ls = langsection, *ols = NULL;
280 int ok = 0;
281
282 Context;
283 while (ls) {
284 /* already know of that section? */
285 if (!strcmp(section, ls->section))
286 return;
287 ols = ls;
288 ls = ls->next;
289 }
290
291 /* create new section entry */
292 ls = nmalloc(sizeof(lang_sec));
293 ls->section = nmalloc(strlen(section) + 1);
294 strcpy(ls->section, section);
295 ls->lang = NULL;
296 ls->next = NULL;
297
298 /* connect to existing list of sections */
299 if (ols)
300 ols->next = ls;
301 else
302 langsection = ls;
303 putlog(LOG_MISC, "*", "LANG: Added section %s.", section);
304
305 /* Always load base language */
306 langfile = get_specific_langfile(BASELANG, ls);
307 if (langfile) {
308 read_lang(langfile);
309 nfree(langfile);
310 ok = 1;
311 }
312 /* Now overwrite base language with a more preferred one */
313 langfile = get_langfile(ls);
314 if (!langfile) {
315 if (!ok)
316 putlog(LOG_MISC, "*", "LANG: No lang files found for section %s.",
317 section);
318 return;
319 }
320 read_lang(langfile);
321 nfree(langfile);
322 }
323
324 int del_lang_section(char *section)
325 {
326 lang_sec *ls = langsection, *ols = NULL;
327
328 while (ls) {
329 if (ls->section && !strcmp(ls->section, section)) {
330 if (ols)
331 ols->next = ls->next;
332 else
333 langsection = ls->next;
334 nfree(ls->section);
335 if (ls->lang)
336 nfree(ls->lang);
337 nfree(ls);
338 putlog(LOG_MISC, "*", "LANG: Removed section %s.", section);
339 return 1;
340 }
341 ols = ls;
342 ls = ls->next;
343 }
344 return 0;
345 }
346
347 static char *get_specific_langfile(char *language, lang_sec *sec)
348 {
349 char *ldir = getenv("EGG_LANGDIR");
350 char *langfile;
351 FILE *sfile = NULL;
352
353 if (!ldir)
354 ldir = LANGDIR;
355 langfile = nmalloc(strlen(ldir) + strlen(sec->section) + strlen(language)+8);
356 sprintf(langfile, "%s/%s.%s.lang", ldir, sec->section, language);
357 sfile = fopen(langfile, "r");
358 if (sfile) {
359 fclose(sfile);
360 /* save language used for this section */
361 sec->lang = nrealloc(sec->lang, strlen(language) + 1);
362 strcpy(sec->lang, language);
363 return langfile;
364 }
365 nfree(langfile);
366 return NULL;
367 }
368
369 /* Searches for available language files and returns the file with the
370 * most preferred language.
371 */
372 static char *get_langfile(lang_sec *sec)
373 {
374 char *langfile;
375 lang_pri *lp = langpriority;
376
377 Context;
378 while (lp) {
379 /* there is no need to reload the same language */
380 if (sec->lang && !strcmp(sec->lang, lp->lang)) {
381 return NULL;
382 }
383 langfile = get_specific_langfile(lp->lang, sec);
384 if (langfile)
385 return langfile;
386 lp = lp->next;
387 }
388 /* we did not find any files, clear the language field */
389 if (sec->lang)
390 nfree(sec->lang);
391 sec->lang = NULL;
392 return NULL;
393 }
394
395 /* Split up a string /path/<section>.<language>.lang into the
396 * needed information for the new language system.
397 * Only needed for compability functions.
398 */
399 static int split_lang(char *par, char **lang, char **section)
400 {
401 char *p;
402
403 Context;
404 p = strrchr(par, '/');
405 /* path attached? */
406 if (p)
407 *section = p + 1;
408 else
409 *section = par;
410 p = strchr(*section, '.');
411 if (p)
412 p[0] = 0;
413 else
414 return 0;
415 *lang = p + 1;
416 p = strstr(*lang, ".lang");
417 if (p)
418 p[0] = 0;
419 return 1;
420 }
421
422 /* compability function to allow users/modules to use the old command. */
423 int cmd_loadlanguage(struct userrec *u, int idx, char *par)
424 {
425 char *section, *lang, *buf;
426
427 Context;
428 dprintf(idx, "Note: This command is obsoleted by +lang.\n");
429 if (!par || !par[0]) {
430 dprintf(idx, "Usage: language <section>.<language>\n");
431 return 0;
432 }
433 if (idx != DP_LOG)
434 putlog(LOG_CMDS, "*", "#%s# language %s", dcc[idx].nick, par);
435 buf = nmalloc(strlen(par)+1);
436 strcpy(buf, par);
437 if (!split_lang(buf, &lang, &section)) {
438 nfree(buf);
439 dprintf(idx, "Invalid parameter %s.\n", par);
440 return 0;
441 }
442 add_lang(lang);
443 add_lang_section(section);
444 nfree(buf);
445 recheck_lang_sections();
446 return 0;
447 }
448
449 static int cmd_plslang(struct userrec *u, int idx, char *par)
450 {
451 Context;
452 if (!par || !par[0]) {
453 dprintf(idx, "Usage: +lang <language>\n");
454 return 0;
455 }
456 putlog(LOG_CMDS, "*", "#%s# +lang %s", dcc[idx].nick, par);
457 add_lang(par);
458 recheck_lang_sections();
459 return 0;
460 }
461
462 static int cmd_mnslang(struct userrec *u, int idx, char *par)
463 {
464 Context;
465 if (!par || !par[0]) {
466 dprintf(idx, "Usage: -lang <language>\n");
467 return 0;
468 }
469 putlog(LOG_CMDS, "*", "#%s# -lang %s", dcc[idx].nick, par);
470 if (!del_lang(par))
471 dprintf(idx, "Language %s not found.\n", par);
472 else
473 recheck_lang_sections();
474 return 0;
475 }
476
477 static int cmd_plslsec(struct userrec *u, int idx, char *par)
478 {
479 Context;
480 if (!par || !par[0]) {
481 dprintf(idx, "Usage: +lsec <section>\n");
482 return 0;
483 }
484 putlog(LOG_CMDS, "*", "#%s# +lsec %s", dcc[idx].nick, par);
485 add_lang_section(par);
486 return 0;
487 }
488
489 static int cmd_mnslsec(struct userrec *u, int idx, char *par)
490 {
491 Context;
492 if (!par || !par[0]) {
493 dprintf(idx, "Usage: -lsec <section>\n");
494 return 0;
495 }
496 putlog(LOG_CMDS, "*", "#%s# -lsec %s", dcc[idx].nick, par);
497 if (!del_lang_section(par))
498 dprintf(idx, "Section %s not found.\n", par);
499 return 0;
500 }
501
502 static int cmd_relang(struct userrec *u, int idx, char *par)
503 {
504 dprintf(idx, "Rechecking language sections...\n");
505 recheck_lang_sections();
506 return 0;
507 }
508
509 static int cmd_languagedump(struct userrec *u, int idx, char *par)
510 {
511 lang_tab *l;
512 char ltext2[512];
513 int idx2, i;
514
515 Context;
516 putlog(LOG_CMDS, "*", "#%s# ldump %s", dcc[idx].nick, par);
517 if (par[0]) {
518 /* atoi (hence strtol) don't work right here for hex */
519 if (strlen(par) > 2 && par[0] == '0' && par[1] == 'x')
520 sscanf(par, "%x", &idx2);
521 else
522 idx2 = (int) strtol(par, (char **) NULL, 10);
523 strcpy(ltext2, get_language(idx2));
524 dprintf(idx, "0x%x: %s\n", idx2, ltext2);
525 return 0;
526 }
527 dprintf(idx, " LANGIDX TEXT\n");
528 for (i = 0; i < 64; i++)
529 for (l = langtab[i]; l; l = l->next)
530 dprintf(idx, "0x%x %s\n", l->idx, l->text);
531 return 0;
532 }
533
534 static char text[512];
535 char *get_language(int idx)
536 {
537 lang_tab *l = langtab[idx & 63];
538
539 if (!idx)
540 return "MSG-0-";
541 while (l) {
542 if (idx == l->idx)
543 return l->text;
544 l = l->next;
545 }
546 sprintf(text, "MSG%03X", idx);
547 return text;
548 }
549
550 int expmem_language()
551 {
552 lang_tab *l;
553 lang_sec *ls = langsection;
554 lang_pri *lp = langpriority;
555 int i, size = 0;
556
557 Context;
558 for (i = 0; i < 64; i++)
559 for (l = langtab[i]; l; l = l->next) {
560 size += sizeof(lang_tab);
561 size += (strlen(l->text) + 1);
562 }
563 while (ls) {
564 size += sizeof(lang_sec);
565 if (ls->section)
566 size += strlen(ls->section)+1;
567 if (ls->lang)
568 size += strlen(ls->lang)+1;
569 ls = ls->next;
570 }
571 while (lp) {
572 size += sizeof(lang_pri);
573 if (lp->lang)
574 size += strlen(lp->lang)+1;
575 lp = lp->next;
576 }
577 return size;
578 }
579
580 /* a report on the module status - not sure if we need this now :/ */
581 static int cmd_languagestatus(struct userrec *u, int idx, char *par)
582 {
583 int ltexts = 0;
584 int maxdepth = 0, used = 0, empty = 0, i, c;
585 lang_tab *l;
586 lang_sec *ls = langsection;
587 lang_pri *lp = langpriority;
588
589 for (i = 0; i < 64; i++) {
590 c = 0;
591 for (l = langtab[i]; l; l = l->next)
592 c++;
593 if (c > maxdepth)
594 maxdepth = c;
595 if (c)
596 used++;
597 else
598 empty++;
599 ltexts += c;
600 }
601 Context;
602 dprintf(idx, "language code report:\n");
603 dprintf(idx, " Table size: %d bytes\n", expmem_language());
604 dprintf(idx, " Text messages: %d\n", ltexts);
605 dprintf(idx, " %d used, %d unused, maxdepth %d, avg %f\n",
606 used, empty, maxdepth, (float) ltexts / 64.0);
607 if (lp) {
608 dprintf(idx, "languages:\n");
609 while (lp) {
610 dprintf(idx, " %s\n", lp->lang);
611 lp = lp->next;
612 }
613 }
614 if (ls) {
615 dprintf(idx, "language sections:\n");
616 while (ls) {
617 dprintf(idx, " %s - %s\n", ls->section,
618 ls->lang ? ls->lang : "<none>");
619 ls = ls->next;
620 }
621 }
622 return 0;
623 }
624
625 /* compability function to allow scripts to use the old command. */
626 static int tcl_language STDVAR
627 {
628 char *lang, *section, *buf;
629 BADARGS(2, 2, " language");
630
631 buf = nmalloc(strlen(argv[1])+1);
632 strcpy(buf, argv[1]);
633 if (!split_lang(buf, &lang, &section)) {
634 Tcl_AppendResult(irp, "Invalid parameter", NULL);
635 nfree(buf);
636 return TCL_ERROR;
637 }
638 add_lang(lang);
639 add_lang_section(section);
640 nfree(buf);
641 recheck_lang_sections();
642 return TCL_OK;
643 }
644
645 static int tcl_plslang STDVAR
646 {
647 BADARGS(2, 2, " language");
648
649 add_lang(argv[1]);
650 recheck_lang_sections();
651
652 return TCL_OK;
653 }
654
655 static int tcl_mnslang STDVAR
656 {
657 BADARGS(2, 2, " language");
658
659 if (!del_lang(argv[1])) {
660 Tcl_AppendResult(irp, "Language not found.", NULL);
661 return TCL_ERROR;
662 }
663 recheck_lang_sections();
664
665 return TCL_OK;
666 }
667
668 static int tcl_addlangsection STDVAR
669 {
670 BADARGS(2, 2, " section");
671
672 add_lang_section(argv[1]);
673 return TCL_OK;
674 }
675
676 static int tcl_dellangsection STDVAR
677 {
678 BADARGS(2, 2, " section");
679
680 if (!del_lang_section(argv[1])) {
681 Tcl_AppendResult(irp, "Section not found", NULL);
682 return TCL_ERROR;
683 }
684 return TCL_OK;
685 }
686
687 static int tcl_relang STDVAR
688 {
689 recheck_lang_sections();
690 return TCL_OK;
691 }
692
693 static cmd_t langdcc[] =
694 {
695 {"language", "n", cmd_loadlanguage, NULL},
696 {"+lang", "n", cmd_plslang, NULL},
697 {"-lang", "n", cmd_mnslang, NULL},
698 {"+lsec", "n", cmd_plslsec, NULL},
699 {"-lsec", "n", cmd_mnslsec, NULL},
700 {"ldump", "n", cmd_languagedump, NULL},
701 {"lstat", "n", cmd_languagestatus, NULL},
702 {"relang", "n", cmd_relang, NULL},
703 {0, 0, 0, 0}
704 };
705
706 static tcl_cmds langtcls[] =
707 {
708 {"language", tcl_language},
709 {"addlang", tcl_plslang},
710 {"dellang", tcl_mnslang},
711 {"addlangsection", tcl_addlangsection},
712 {"dellangsection", tcl_dellangsection},
713 {"relang", tcl_relang},
714 {0, 0}
715 };
716
717 void init_language(int flag)
718 {
719 int i;
720 char *deflang;
721
722 Context;
723 if (flag) {
724 for (i = 0; i < 32; i++)
725 langtab[i] = 0;
726 /* The default language is always "english" as language files are
727 * gauranteed to exist in english. */
728 add_lang("english");
729 /* Let the user choose a different, preferred language */
730 deflang = getenv("EGG_LANG");
731 if (deflang)
732 add_lang(deflang);
733 add_lang_section("core");
734 } else {
735 add_tcl_commands(langtcls);
736 add_builtins(H_dcc, langdcc);
737 }
738 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23