/[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.9 - (show annotations) (download) (as text)
Sun Jan 30 19:26:20 2000 UTC (19 years, 8 months ago) by fabian
Branch: MAIN
CVS Tags: eggdrop105020
Changes since 1.8: +62 -59 lines
File MIME type: text/x-chdr
cleanup3 patch

1 /*
2 * language.c -- handles:
3 * language support code
4 *
5 * $Id: language.c,v 1.8 2000/01/17 22:36:06 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 static char *get_specific_langfile(char *, lang_sec *);
99 static char *get_langfile(lang_sec *);
100 static int split_lang(char *, char **, char **);
101 int cmd_loadlanguage(struct userrec *, int, char *);
102
103
104 /* Add a new preferred language to the list of languages. Newly added
105 * languages get the highest priority.
106 */
107 void add_lang(char *lang)
108 {
109 lang_pri *lp = langpriority, *lpo = NULL;
110
111 Context;
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 putlog(LOG_MISC, "*", "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 Context;
147 while (lp) {
148 /* Found the language? */
149 if (!strcmp(lang, lp->lang)) {
150 if (lpo)
151 lpo->next = lp->next;
152 else
153 langpriority = lp->next;
154 if (lp->lang)
155 nfree(lp->lang);
156 nfree(lp);
157 putlog(LOG_MISC, "*", "LANG: Language unloaded: %s",
158 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
273 *ctmp = *ctmp1;
274 ctmp++;
275 ctmp1++;
276 }
277 *ctmp = '\0';
278 if (add_message(lidx, ltext)) {
279 lupdate++;
280 } else
281 ladd++;
282 }
283 } else {
284 ctmp = strchr(lbuf, '\n');
285 if (lskip && (strlen(lbuf) == 1 || *(ctmp - 1) != '\\'))
286 lskip = 0;
287 }
288 }
289 nfree(ltext);
290 fclose(FLANG);
291
292 putlog(LOG_MISC, "*", "LANG: %d messages of %d lines loaded from %s",
293 ltexts, lline, langfile);
294 putlog(LOG_MISC, "*", "LANG: %d adds, %d updates to message table",
295 ladd, lupdate);
296 }
297
298 /* Add a new language section. e.g. section "core"
299 * Load an apropriate language file for the specified section.
300 */
301 void add_lang_section(char *section)
302 {
303 char *langfile = NULL;
304 lang_sec *ls = langsection, *ols = NULL;
305 int ok = 0;
306
307 Context;
308 while (ls) {
309 /* Already know of that section? */
310 if (!strcmp(section, ls->section))
311 return;
312 ols = ls;
313 ls = ls->next;
314 }
315
316 /* Create new section entry */
317 ls = nmalloc(sizeof(lang_sec));
318 ls->section = nmalloc(strlen(section) + 1);
319 strcpy(ls->section, section);
320 ls->lang = NULL;
321 ls->next = NULL;
322
323 /* Connect to existing list of sections */
324 if (ols)
325 ols->next = ls;
326 else
327 langsection = ls;
328 putlog(LOG_MISC, "*", "LANG: Section loaded: %s", section);
329
330 /* Always load base language */
331 langfile = get_specific_langfile(BASELANG, ls);
332 if (langfile) {
333 read_lang(langfile);
334 nfree(langfile);
335 ok = 1;
336 }
337 /* Now overwrite base language with a more preferred one */
338 langfile = get_langfile(ls);
339 if (!langfile) {
340 if (!ok)
341 putlog(LOG_MISC, "*", "LANG: No lang files found for section %s.",
342 section);
343 return;
344 }
345 read_lang(langfile);
346 nfree(langfile);
347 }
348
349 int del_lang_section(char *section)
350 {
351 lang_sec *ls, *ols;
352
353 for (ls = langsection, ols = NULL; ls; ols = ls, ls = ls->next) {
354 if (ls->section && !strcmp(ls->section, section)) {
355 if (ols)
356 ols->next = ls->next;
357 else
358 langsection = ls->next;
359 nfree(ls->section);
360 if (ls->lang)
361 nfree(ls->lang);
362 nfree(ls);
363 putlog(LOG_MISC, "*", "LANG: Section unloaded: %s", section);
364 return 1;
365 }
366 }
367 return 0;
368 }
369
370 static char *get_specific_langfile(char *language, lang_sec *sec)
371 {
372 char *ldir = getenv("EGG_LANGDIR");
373 char *langfile;
374 FILE *sfile = NULL;
375
376 if (!ldir)
377 ldir = LANGDIR;
378 langfile = nmalloc(strlen(ldir) + strlen(sec->section) + strlen(language)+8);
379 sprintf(langfile, "%s/%s.%s.lang", ldir, sec->section, language);
380 sfile = fopen(langfile, "r");
381 if (sfile) {
382 fclose(sfile);
383 /* Save language used for this section */
384 sec->lang = nrealloc(sec->lang, strlen(language) + 1);
385 strcpy(sec->lang, language);
386 return langfile;
387 }
388 nfree(langfile);
389 return NULL;
390 }
391
392 /* Searches for available language files and returns the file with the
393 * most preferred language.
394 */
395 static char *get_langfile(lang_sec *sec)
396 {
397 char *langfile;
398 lang_pri *lp;
399
400 Context;
401 for (lp = langpriority; lp; lp = lp->next) {
402 /* There is no need to reload the same language */
403 if (sec->lang && !strcmp(sec->lang, lp->lang)) {
404 return NULL;
405 }
406 langfile = get_specific_langfile(lp->lang, sec);
407 if (langfile)
408 return langfile;
409 }
410 /* We did not find any files, clear the language field */
411 if (sec->lang)
412 nfree(sec->lang);
413 sec->lang = NULL;
414 return NULL;
415 }
416
417 /* Split up a string /path/<section>.<language>.lang into the
418 * needed information for the new language system.
419 * Only needed for compability functions.
420 */
421 static int split_lang(char *par, char **lang, char **section)
422 {
423 char *p;
424
425 Context;
426 p = strrchr(par, '/');
427 /* path attached? */
428 if (p)
429 *section = p + 1;
430 else
431 *section = par;
432 p = strchr(*section, '.');
433 if (p)
434 p[0] = 0;
435 else
436 return 0;
437 *lang = p + 1;
438 p = strstr(*lang, ".lang");
439 if (p)
440 p[0] = 0;
441 return 1;
442 }
443
444 /* Compability function to allow users/modules to use the old command.
445 */
446 int cmd_loadlanguage(struct userrec *u, int idx, char *par)
447 {
448 char *section, *lang, *buf;
449
450 Context;
451 dprintf(idx, "Note: This command is obsoleted by +lang.\n");
452 if (!par || !par[0]) {
453 dprintf(idx, "Usage: language <section>.<language>\n");
454 return 0;
455 }
456 if (idx != DP_LOG)
457 putlog(LOG_CMDS, "*", "#%s# language %s", dcc[idx].nick, par);
458 buf = nmalloc(strlen(par)+1);
459 strcpy(buf, par);
460 if (!split_lang(buf, &lang, &section)) {
461 nfree(buf);
462 dprintf(idx, "Invalid parameter %s.\n", par);
463 return 0;
464 }
465 add_lang(lang);
466 add_lang_section(section);
467 nfree(buf);
468 recheck_lang_sections();
469 return 0;
470 }
471
472 static int cmd_plslang(struct userrec *u, int idx, char *par)
473 {
474 Context;
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 Context;
488 if (!par || !par[0]) {
489 dprintf(idx, "Usage: -lang <language>\n");
490 return 0;
491 }
492 putlog(LOG_CMDS, "*", "#%s# -lang %s", dcc[idx].nick, par);
493 if (!del_lang(par))
494 dprintf(idx, "Language %s not found.\n", par);
495 else
496 recheck_lang_sections();
497 return 0;
498 }
499
500 static int cmd_plslsec(struct userrec *u, int idx, char *par)
501 {
502 Context;
503 if (!par || !par[0]) {
504 dprintf(idx, "Usage: +lsec <section>\n");
505 return 0;
506 }
507 putlog(LOG_CMDS, "*", "#%s# +lsec %s", dcc[idx].nick, par);
508 add_lang_section(par);
509 return 0;
510 }
511
512 static int cmd_mnslsec(struct userrec *u, int idx, char *par)
513 {
514 Context;
515 if (!par || !par[0]) {
516 dprintf(idx, "Usage: -lsec <section>\n");
517 return 0;
518 }
519 putlog(LOG_CMDS, "*", "#%s# -lsec %s", dcc[idx].nick, par);
520 if (!del_lang_section(par))
521 dprintf(idx, "Section %s not found.\n", par);
522 return 0;
523 }
524
525 static int cmd_relang(struct userrec *u, int idx, char *par)
526 {
527 dprintf(idx, "Rechecking language sections...\n");
528 recheck_lang_sections();
529 return 0;
530 }
531
532 static int cmd_languagedump(struct userrec *u, int idx, char *par)
533 {
534 lang_tab *l;
535 char ltext2[512];
536 int idx2, i;
537
538 Context;
539 putlog(LOG_CMDS, "*", "#%s# ldump %s", dcc[idx].nick, par);
540 if (par[0]) {
541 /* atoi (hence strtol) don't work right here for hex */
542 if (strlen(par) > 2 && par[0] == '0' && par[1] == 'x')
543 sscanf(par, "%x", &idx2);
544 else
545 idx2 = (int) strtol(par, (char **) NULL, 10);
546 strcpy(ltext2, get_language(idx2));
547 dprintf(idx, "0x%x: %s\n", idx2, ltext2);
548 return 0;
549 }
550 dprintf(idx, " LANGIDX TEXT\n");
551 for (i = 0; i < 64; i++)
552 for (l = langtab[i]; l; l = l->next)
553 dprintf(idx, "0x%x %s\n", l->idx, l->text);
554 return 0;
555 }
556
557 static char text[512];
558 char *get_language(int idx)
559 {
560 lang_tab *l = langtab[idx & 63];
561
562 if (!idx)
563 return "MSG-0-";
564 while (l) {
565 if (idx == l->idx)
566 return l->text;
567 l = l->next;
568 }
569 sprintf(text, "MSG%03X", idx);
570 return text;
571 }
572
573 int expmem_language()
574 {
575 lang_tab *l;
576 lang_sec *ls;
577 lang_pri *lp;
578 int i, size = 0;
579
580 Context;
581 for (i = 0; i < 64; i++)
582 for (l = langtab[i]; l; l = l->next) {
583 size += sizeof(lang_tab);
584 size += (strlen(l->text) + 1);
585 }
586 for (ls = langsection; ls; ls = ls->next) {
587 size += sizeof(lang_sec);
588 if (ls->section)
589 size += strlen(ls->section)+1;
590 if (ls->lang)
591 size += strlen(ls->lang)+1;
592 }
593 for (lp = langpriority; lp; lp = lp->next) {
594 size += sizeof(lang_pri);
595 if (lp->lang)
596 size += strlen(lp->lang)+1;
597 }
598 return size;
599 }
600
601 /* A report on the module status - only for debugging purposes
602 */
603 static int cmd_languagestatus(struct userrec *u, int idx, char *par)
604 {
605 int ltexts = 0;
606 register int i, c, maxdepth = 0, used = 0, empty = 0;
607 lang_tab *l;
608 lang_sec *ls = langsection;
609 lang_pri *lp = langpriority;
610
611 Context;
612 putlog(LOG_CMDS, "*", "#%s# lstat %s", dcc[idx].nick, par);
613 for (i = 0; i < 64; i++) {
614 c = 0;
615 for (l = langtab[i]; l; l = l->next)
616 c++;
617 if (c > maxdepth)
618 maxdepth = c;
619 if (c)
620 used++;
621 else
622 empty++;
623 ltexts += c;
624 }
625 Context;
626 dprintf(idx, "Language code report:\n");
627 dprintf(idx, " Table size : %d bytes\n", expmem_language());
628 dprintf(idx, " Text messages: %d\n", ltexts);
629 dprintf(idx, " %d used, %d unused, maxdepth %d, avg %f\n",
630 used, empty, maxdepth, (float) ltexts / 64.0);
631 if (lp) {
632 int c = 0;
633
634 dprintf(idx, " Supported languages:");
635 while (lp) {
636 dprintf(idx, "%s %s", c ? "," : "", lp->lang);
637 c = 1;
638 lp = lp->next;
639 }
640 dprintf(idx, "\n");
641 }
642 if (ls) {
643 dprintf(idx, "\n SECTION LANG\n");
644 dprintf(idx, " ==============================\n");
645 while (ls) {
646 dprintf(idx, " %-20s %s\n", ls->section,
647 ls->lang ? ls->lang : "<none>");
648 ls = ls->next;
649 }
650 }
651 return 0;
652 }
653
654 /* Compability function to allow scripts to use the old command.
655 */
656 static int tcl_language STDVAR
657 {
658 char *lang, *section, *buf;
659 BADARGS(2, 2, " language");
660
661 buf = nmalloc(strlen(argv[1])+1);
662 strcpy(buf, argv[1]);
663 if (!split_lang(buf, &lang, &section)) {
664 Tcl_AppendResult(irp, "Invalid parameter", NULL);
665 nfree(buf);
666 return TCL_ERROR;
667 }
668 add_lang(lang);
669 add_lang_section(section);
670 nfree(buf);
671 recheck_lang_sections();
672 return TCL_OK;
673 }
674
675 static int tcl_plslang STDVAR
676 {
677 BADARGS(2, 2, " language");
678
679 add_lang(argv[1]);
680 recheck_lang_sections();
681
682 return TCL_OK;
683 }
684
685 static int tcl_mnslang STDVAR
686 {
687 BADARGS(2, 2, " language");
688
689 if (!del_lang(argv[1])) {
690 Tcl_AppendResult(irp, "Language not found.", NULL);
691 return TCL_ERROR;
692 }
693 recheck_lang_sections();
694
695 return TCL_OK;
696 }
697
698 static int tcl_addlangsection STDVAR
699 {
700 BADARGS(2, 2, " section");
701
702 add_lang_section(argv[1]);
703 return TCL_OK;
704 }
705
706 static int tcl_dellangsection STDVAR
707 {
708 BADARGS(2, 2, " section");
709
710 if (!del_lang_section(argv[1])) {
711 Tcl_AppendResult(irp, "Section not found", NULL);
712 return TCL_ERROR;
713 }
714 return TCL_OK;
715 }
716
717 static int tcl_relang STDVAR
718 {
719 recheck_lang_sections();
720 return TCL_OK;
721 }
722
723 static cmd_t langdcc[] =
724 {
725 {"language", "n", cmd_loadlanguage, NULL},
726 {"+lang", "n", cmd_plslang, NULL},
727 {"-lang", "n", cmd_mnslang, NULL},
728 {"+lsec", "n", cmd_plslsec, NULL},
729 {"-lsec", "n", cmd_mnslsec, NULL},
730 {"ldump", "n", cmd_languagedump, NULL},
731 {"lstat", "n", cmd_languagestatus, NULL},
732 {"relang", "n", cmd_relang, NULL},
733 {NULL, NULL, NULL, NULL}
734 };
735
736 static tcl_cmds langtcls[] =
737 {
738 {"language", tcl_language},
739 {"addlang", tcl_plslang},
740 {"dellang", tcl_mnslang},
741 {"addlangsection", tcl_addlangsection},
742 {"dellangsection", tcl_dellangsection},
743 {"relang", tcl_relang},
744 {NULL, NULL}
745 };
746
747 void init_language(int flag)
748 {
749 int i;
750 char *deflang;
751
752 Context;
753 if (flag) {
754 for (i = 0; i < 32; i++)
755 langtab[i] = 0;
756 /* The default language is always BASELANG as language files are
757 * gauranteed to exist in that language.
758 */
759 add_lang(BASELANG);
760 /* Let the user choose a different, preferred language */
761 deflang = getenv("EGG_LANG");
762 if (deflang)
763 add_lang(deflang);
764 add_lang_section("core");
765 } else {
766 add_tcl_commands(langtcls);
767 add_builtins(H_dcc, langdcc);
768 }
769 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23