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

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

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


Revision 1.1.1.1 - (show annotations) (download) (as text) (vendor branch)
Mon Jul 26 21:11:06 2010 UTC (8 years, 9 months ago) by simple
Branch: eggheads, MAIN
CVS Tags: v1, HEAD
Branch point for: gettext
Changes since 1.1: +0 -0 lines
File MIME type: text/x-chdr
Imported Eggdrop 1.6.20

1 /*
2 * language.c -- handles:
3 * language support code
4 *
5 * $Id: language.c,v 1.30 2010/01/03 13:27:32 pseudo Exp $
6 */
7 /*
8 * Copyright (C) 1997 Robey Pointer
9 * Copyright (C) 1999 - 2010 Eggheads Development Team
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;
199 char *langfile;
200
201 for (ls = langsection; ls && ls->section; ls = ls->next) {
202 langfile = get_langfile(ls);
203 /* Found a language with a more preferred language? */
204 if (langfile) {
205 read_lang(langfile);
206 nfree(langfile);
207 }
208 }
209 }
210
211 /* Parse a language file
212 */
213 static void read_lang(char *langfile)
214 {
215 FILE *FLANG;
216 char lbuf[512];
217 char *ltext = NULL;
218 char *ctmp, *ctmp1;
219 int lidx;
220 int lnew = 1;
221 int lline = 1;
222 int lskip = 0;
223 int ltexts = 0;
224 int ladd = 0, lupdate = 0;
225
226 FLANG = fopen(langfile, "r");
227 if (FLANG == NULL) {
228 putlog(LOG_MISC, "*", "LANG: unexpected: reading from file %s failed.",
229 langfile);
230 return;
231 }
232
233 for (*(ltext = nmalloc(sizeof lbuf)) = 0; fgets(lbuf, sizeof lbuf, FLANG);
234 ltext = nrealloc(ltext, strlen(ltext) + sizeof lbuf), lskip = 0) {
235 if (lnew) {
236 if ((lbuf[0] == '#') || (sscanf(lbuf, "%s", ltext) == EOF))
237 lskip = 1;
238 else if (sscanf(lbuf, "0x%x,", &lidx) != 1) {
239 putlog(LOG_MISC, "*", "LANG: Malformed text line in %s at %d.",
240 langfile, lline);
241 lskip = 1;
242 }
243 if (lskip) {
244 while (!strchr(lbuf, '\n')) {
245 fgets(lbuf, 511, FLANG);
246 lline++;
247 }
248 lline++;
249 lnew = 1;
250 continue;
251 }
252 strcpy(ltext, strchr(lbuf, ',') + 1);
253 } else
254 strcpy(strchr(ltext, 0), lbuf);
255 if ((ctmp = strchr(ltext, '\n'))) {
256 lline++;
257 *ctmp = 0;
258 if (ctmp[-1] == '\\') {
259 lnew = 0;
260 ctmp[-1] = 0;
261 } else {
262 ltexts++;
263 lnew = 1;
264 /* Convert literal \n and \t escapes */
265 for (ctmp1 = ctmp = ltext; *ctmp1; ctmp++, ctmp1++) {
266 if ((*ctmp1 == '\\') && ctmp1[1] == 'n') {
267 *ctmp = '\n';
268 ctmp1++;
269 } else if ((*ctmp1 == '\\') && ctmp1[1] == 't') {
270 *ctmp = '\t';
271 ctmp1++;
272 } else
273 *ctmp = *ctmp1;
274 }
275 *ctmp = 0;
276 if (add_message(lidx, ltext)) {
277 lupdate++;
278 } else
279 ladd++;
280 }
281 } else
282 lnew = 0;
283 }
284 nfree(ltext);
285 fclose(FLANG);
286
287 debug3("LANG: %d messages of %d lines loaded from %s", ltexts, lline,
288 langfile);
289 debug2("LANG: %d adds, %d updates to message table", ladd, lupdate);
290 }
291
292 /* Returns 1 if the section exists, otherwise 0.
293 */
294 int exist_lang_section(char *section)
295 {
296 lang_sec *ls;
297
298 for (ls = langsection; ls; ls = ls->next)
299 if (!strcmp(section, ls->section))
300 return 1;
301 return 0;
302 }
303
304 /* Add a new language section. e.g. section "core"
305 * Load an apropriate language file for the specified section.
306 */
307 void add_lang_section(char *section)
308 {
309 char *langfile = NULL;
310 lang_sec *ls, *ols = NULL;
311 int ok = 0;
312
313 for (ls = langsection; ls; ols = ls, ls = ls->next)
314 /* Already know of that section? */
315 if (!strcmp(section, ls->section))
316 return;
317
318 /* Create new section entry */
319 ls = nmalloc(sizeof(lang_sec));
320 ls->section = nmalloc(strlen(section) + 1);
321 strcpy(ls->section, section);
322 ls->lang = NULL;
323 ls->next = NULL;
324
325 /* Connect to existing list of sections */
326 if (ols)
327 ols->next = ls;
328 else
329 langsection = ls;
330 debug1("LANG: Section loaded: %s", section);
331
332 /* Always load base language */
333 langfile = get_specific_langfile(BASELANG, ls);
334 if (langfile) {
335 read_lang(langfile);
336 nfree(langfile);
337 ok = 1;
338 }
339 /* Now overwrite base language with a more preferred one */
340 langfile = get_langfile(ls);
341 if (!langfile) {
342 if (!ok)
343 putlog(LOG_MISC, "*", "LANG: No lang files found for section %s.",
344 section);
345 return;
346 }
347 read_lang(langfile);
348 nfree(langfile);
349 }
350
351 int del_lang_section(char *section)
352 {
353 lang_sec *ls, *ols;
354
355 for (ls = langsection, ols = NULL; ls; ols = ls, ls = ls->next)
356 if (ls->section && !strcmp(ls->section, section)) {
357 if (ols)
358 ols->next = ls->next;
359 else
360 langsection = ls->next;
361 nfree(ls->section);
362 if (ls->lang)
363 nfree(ls->lang);
364 nfree(ls);
365 debug1("LANG: Section unloaded: %s", section);
366 return 1;
367 }
368 return 0;
369 }
370
371 static char *get_specific_langfile(char *language, lang_sec *sec)
372 {
373 char *ldir = getenv("EGG_LANGDIR");
374 char *langfile;
375
376 if (!ldir)
377 ldir = LANGDIR;
378 langfile = nmalloc(strlen(ldir) + strlen(sec->section) + strlen(language) +
379 8);
380 sprintf(langfile, "%s/%s.%s.lang", ldir, sec->section, language);
381
382 if (file_readable(langfile)) {
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
389 nfree(langfile);
390 return NULL;
391 }
392
393 /* Searches for available language files and returns the file with the
394 * most preferred language.
395 */
396 static char *get_langfile(lang_sec *sec)
397 {
398 char *langfile;
399 lang_pri *lp;
400
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 langfile = get_specific_langfile(lp->lang, sec);
406 if (langfile)
407 return langfile;
408 }
409 /* We did not find any files, clear the language field */
410 if (sec->lang)
411 nfree(sec->lang);
412 sec->lang = NULL;
413 return NULL;
414 }
415
416 /* Split up a string /path/<section>.<language>.lang into the
417 * needed information for the new language system.
418 * Only needed for compability functions.
419 */
420 static int split_lang(char *par, char **lang, char **section)
421 {
422 char *p;
423
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 */
444 int cmd_loadlanguage(struct userrec *u, int idx, char *par)
445 {
446 char *section, *lang, *buf;
447
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 if (!par || !par[0]) {
472 dprintf(idx, "Usage: +lang <language>\n");
473 return 0;
474 }
475 putlog(LOG_CMDS, "*", "#%s# +lang %s", dcc[idx].nick, par);
476 add_lang(par);
477 recheck_lang_sections();
478 return 0;
479 }
480
481 static int cmd_mnslang(struct userrec *u, int idx, char *par)
482 {
483 if (!par || !par[0]) {
484 dprintf(idx, "Usage: -lang <language>\n");
485 return 0;
486 }
487 putlog(LOG_CMDS, "*", "#%s# -lang %s", dcc[idx].nick, par);
488 if (!del_lang(par))
489 dprintf(idx, "Language %s not found.\n", par);
490 else
491 recheck_lang_sections();
492 return 0;
493 }
494
495 static int cmd_plslsec(struct userrec *u, int idx, char *par)
496 {
497 if (!par || !par[0]) {
498 dprintf(idx, "Usage: +lsec <section>\n");
499 return 0;
500 }
501 putlog(LOG_CMDS, "*", "#%s# +lsec %s", dcc[idx].nick, par);
502 add_lang_section(par);
503 return 0;
504 }
505
506 static int cmd_mnslsec(struct userrec *u, int idx, char *par)
507 {
508 if (!par || !par[0]) {
509 dprintf(idx, "Usage: -lsec <section>\n");
510 return 0;
511 }
512 putlog(LOG_CMDS, "*", "#%s# -lsec %s", dcc[idx].nick, par);
513 if (!del_lang_section(par))
514 dprintf(idx, "Section %s not found.\n", par);
515 return 0;
516 }
517
518 static int cmd_relang(struct userrec *u, int idx, char *par)
519 {
520 dprintf(idx, "Rechecking language sections...\n");
521 recheck_lang_sections();
522 return 0;
523 }
524
525 static int cmd_languagedump(struct userrec *u, int idx, char *par)
526 {
527 lang_tab *l;
528 char ltext2[512];
529 int idx2, i;
530
531 putlog(LOG_CMDS, "*", "#%s# ldump %s", dcc[idx].nick, par);
532 if (par[0]) {
533 /* atoi (hence strtol) don't work right here for hex */
534 if (strlen(par) > 2 && par[0] == '0' && par[1] == 'x')
535 sscanf(par, "%x", &idx2);
536 else
537 idx2 = (int) strtol(par, (char **) NULL, 10);
538 strcpy(ltext2, get_language(idx2));
539 dprintf(idx, "0x%x: %s\n", idx2, ltext2);
540 return 0;
541 }
542 dprintf(idx, " LANGIDX TEXT\n");
543 for (i = 0; i < 64; i++)
544 for (l = langtab[i]; l; l = l->next)
545 dprintf(idx, "0x%x %s\n", l->idx, l->text);
546 return 0;
547 }
548
549 static char text[512];
550 char *get_language(int idx)
551 {
552 lang_tab *l;
553
554 if (!idx)
555 return "MSG-0-";
556 for (l = langtab[idx & 63]; l; l = l->next)
557 if (idx == l->idx)
558 return l->text;
559 egg_snprintf(text, sizeof text, "MSG%03X", idx);
560 return text;
561 }
562
563 int expmem_language()
564 {
565 lang_tab *l;
566 lang_sec *ls;
567 lang_pri *lp;
568 int i, size = 0;
569
570 for (i = 0; i < 64; i++)
571 for (l = langtab[i]; l; l = l->next) {
572 size += sizeof(lang_tab);
573 size += (strlen(l->text) + 1);
574 }
575 for (ls = langsection; ls; ls = ls->next) {
576 size += sizeof(lang_sec);
577 if (ls->section)
578 size += strlen(ls->section) + 1;
579 if (ls->lang)
580 size += strlen(ls->lang) + 1;
581 }
582 for (lp = langpriority; lp; lp = lp->next) {
583 size += sizeof(lang_pri);
584 if (lp->lang)
585 size += strlen(lp->lang) + 1;
586 }
587 return size;
588 }
589
590 /* A report on the module status - only for debugging purposes
591 */
592 static int cmd_languagestatus(struct userrec *u, int idx, char *par)
593 {
594 int ltexts = 0;
595 register int i, c, maxdepth = 0, used = 0, empty = 0;
596 lang_tab *l;
597 lang_sec *ls = langsection;
598 lang_pri *lp = langpriority;
599
600 putlog(LOG_CMDS, "*", "#%s# lstat %s", dcc[idx].nick, par);
601 for (i = 0; i < 64; i++) {
602 c = 0;
603 for (l = langtab[i]; l; l = l->next)
604 c++;
605 if (c > maxdepth)
606 maxdepth = c;
607 if (c)
608 used++;
609 else
610 empty++;
611 ltexts += c;
612 }
613 dprintf(idx, "Language code report:\n");
614 dprintf(idx, " Table size : %d bytes\n", expmem_language());
615 dprintf(idx, " Text messages: %d\n", ltexts);
616 dprintf(idx, " %d used, %d unused, maxdepth %d, avg %f\n",
617 used, empty, maxdepth, (float) ltexts / 64.0);
618 if (lp) {
619 int c = 0;
620
621 dprintf(idx, " Supported languages:");
622 for (; lp; lp = lp->next) {
623 dprintf(idx, "%s %s", c ? "," : "", lp->lang);
624 c = 1;
625 }
626 dprintf(idx, "\n");
627 }
628 if (ls) {
629 dprintf(idx, "\n SECTION LANG\n");
630 dprintf(idx, " ==============================\n");
631 for (; ls; ls = ls->next)
632 dprintf(idx, " %-20s %s\n", ls->section,
633 ls->lang ? ls->lang : "<none>");
634 }
635 return 0;
636 }
637
638 /* Compability function to allow scripts to use the old command.
639 */
640 static int tcl_language STDVAR
641 {
642 char *lang, *section, *buf;
643
644 putlog(LOG_MISC, "*", "The Tcl command 'language' is obsolete. Use "
645 "'addlang' instead.");
646 BADARGS(2, 2, " language");
647
648 buf = nmalloc(strlen(argv[1]) + 1);
649 strcpy(buf, argv[1]);
650
651 if (!split_lang(buf, &lang, &section)) {
652 Tcl_AppendResult(irp, "Invalid parameter", NULL);
653 nfree(buf);
654 return TCL_ERROR;
655 }
656 add_lang(lang);
657
658 add_lang_section(section);
659 nfree(buf);
660 recheck_lang_sections();
661 return TCL_OK;
662 }
663
664 static int tcl_plslang STDVAR
665 {
666 BADARGS(2, 2, " language");
667
668 add_lang(argv[1]);
669 recheck_lang_sections();
670
671 return TCL_OK;
672 }
673
674 static int tcl_mnslang STDVAR
675 {
676 BADARGS(2, 2, " language");
677
678 if (!del_lang(argv[1])) {
679 Tcl_AppendResult(irp, "Language not found.", NULL);
680 return TCL_ERROR;
681 }
682 recheck_lang_sections();
683
684 return TCL_OK;
685 }
686
687 static int tcl_addlangsection STDVAR
688 {
689 BADARGS(2, 2, " section");
690
691 add_lang_section(argv[1]);
692 return TCL_OK;
693 }
694
695 static int tcl_dellangsection STDVAR
696 {
697 BADARGS(2, 2, " section");
698
699 if (!del_lang_section(argv[1])) {
700 Tcl_AppendResult(irp, "Section not found", NULL);
701 return TCL_ERROR;
702 }
703 return TCL_OK;
704 }
705
706 static int tcl_relang STDVAR
707 {
708 recheck_lang_sections();
709 return TCL_OK;
710 }
711
712 static cmd_t langdcc[] = {
713 {"language", "n", cmd_loadlanguage, NULL},
714 {"+lang", "n", cmd_plslang, NULL},
715 {"-lang", "n", cmd_mnslang, NULL},
716 {"+lsec", "n", cmd_plslsec, NULL},
717 {"-lsec", "n", cmd_mnslsec, NULL},
718 {"ldump", "n", cmd_languagedump, NULL},
719 {"lstat", "n", cmd_languagestatus, NULL},
720 {"relang", "n", cmd_relang, NULL},
721 {NULL, NULL, NULL, NULL}
722 };
723
724 static tcl_cmds langtcls[] = {
725 {"language", tcl_language},
726 {"addlang", tcl_plslang},
727 {"dellang", tcl_mnslang},
728 {"addlangsection", tcl_addlangsection},
729 {"dellangsection", tcl_dellangsection},
730 {"relang", tcl_relang},
731 {NULL, NULL}
732 };
733
734 void init_language(int flag)
735 {
736 int i;
737 char *deflang;
738
739 if (flag) {
740 for (i = 0; i < 32; i++)
741 langtab[i] = 0;
742 /* The default language is always BASELANG as language files are
743 * gauranteed to exist in that language.
744 */
745 add_lang(BASELANG);
746 /* Let the user choose a different, preferred language */
747 deflang = getenv("EGG_LANG");
748 if (deflang)
749 add_lang(deflang);
750 add_lang_section("core");
751 } else {
752 add_tcl_commands(langtcls);
753 add_builtins(H_dcc, langdcc);
754 }
755 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23