/[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.10 - (show annotations) (download) (as text)
Wed Apr 5 19:35:43 2000 UTC (19 years, 3 months ago) by fabian
Branch: MAIN
CVS Tags: eggdrop10503, eggdrop105040, eggdrop10403
Changes since 1.9: +34 -23 lines
File MIME type: text/x-chdr
make_quiet_lang patch

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23