/[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.11 - (show annotations) (download) (as text)
Sun Dec 10 15:10:27 2000 UTC (18 years, 7 months ago) by guppy
Branch: MAIN
Changes since 1.10: +2 -19 lines
File MIME type: text/x-chdr
guppy: core_cleanup.diff ...

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23