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

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

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


Revision 1.1.1.1 - (hide annotations) (download) (as text) (vendor branch)
Mon Jul 26 21:11:06 2010 UTC (8 years, 11 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 simple 1.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