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

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

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


Revision 1.13 - (show annotations) (download) (as text)
Sat Jan 8 21:23:14 2000 UTC (20 years, 3 months ago) by per
Branch: MAIN
CVS Tags: eggdrop104030RC2, eggdrop10403RC1, eggdrop10402RC1, eggdrop10403, eggdrop10402
Changes since 1.12: +2 -2 lines
File MIME type: text/x-chdr
copyright

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23