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

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

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


Revision 1.4 - (hide annotations) (download) (as text)
Tue Oct 26 21:38:37 1999 UTC (19 years, 9 months ago) by fabian
Branch: MAIN
Changes since 1.3: +1 -1 lines
File MIME type: text/x-chdr
resync 940380771-940924890

1 segfault 1.1 /*
2     * language.c - language support code.
3     */
4    
5     /*
6     * DOES:
7     * Nothing <- typical BB code :)
8     *
9     * ENVIRONMENT VARIABLES:
10     * EGG_LANG - language to use (default: "english")
11     * EGG_LANGDIR - directory with all lang files
12     * (default: "./language")
13     * WILL DO:
14     * Upon loading:
15     * o default loads section core, if possible.
16     * Commands:
17     * DCC .+lang <language>
18     * DCC .-lang <language>
19     * DCC .+lsec <section>
20     * DCC .-lsec <section>
21     * DCC .relang
22     * DCC .ldump
23     * DCC .lstat
24     *
25     * FILE FORMAT: language.lang
26     * <textidx>,<text>
27     * TEXT MESSAGE USAGE:
28     * get_language(<textidx> [,<PARMS>])
29     *
30     * ADDING LANGUAGES:
31     * o Copy an existing <section>.<oldlanguage>.lang to a
32     * new .lang file and modify as needed.
33     * Use %s or %d where necessary, for plug-in
34     * insertions of parameters (see core.english.lang).
35     * o Ensure <section>.<newlanguage>.lang is in the lang
36     * directory.
37     * o .+lang <newlanguage>
38     * ADDING SECTIONS:
39     * o Create a <newsection>.english.lang file.
40     * o Add add_lang_section("<newsection>"); to your module
41     * startup function.
42     *
43     */
44    
45     #include "main.h"
46    
47     extern struct dcc_t *dcc;
48    
49     typedef struct lang_st {
50     struct lang_st *next;
51     char *lang;
52     char *section;
53     } lang_sec;
54    
55     typedef struct lang_pr {
56     struct lang_pr *next;
57     char *lang;
58     } lang_pri;
59    
60     typedef struct lang_t {
61     int idx;
62     char *text;
63     struct lang_t *next;
64     } lang_tab;
65    
66     static lang_tab *langtab[64];
67     static lang_sec *langsection = NULL;
68     static lang_pri *langpriority = NULL;
69    
70     static int del_lang(char *);
71     static int add_message(int, char *);
72     static void recheck_lang_sections(void);
73     static void read_lang(char *);
74     void add_lang_section(char *);
75     int del_lang_section(char *);
76 fabian 1.3 static char *get_specific_langfile(char *, lang_sec *);
77     static char *get_langfile(lang_sec *);
78 segfault 1.1 static int split_lang(char *, char **, char **);
79 fabian 1.3 int cmd_loadlanguage(struct userrec *, int, char *);
80 segfault 1.1
81    
82     /* add a new preferred language to the list of languages. Newly added
83     * languages get the highest priority.
84     */
85     void add_lang(char *lang)
86     {
87     lang_pri *lp = langpriority, *lpo = NULL;
88    
89     context;
90     while (lp) {
91     /* the language already exists, moving to the beginning */
92     if (!strcmp(lang, lp->lang)) {
93     /* already at the front? */
94     if (!lpo)
95     return;
96     lpo->next = lp->next;
97     lp->next = lpo;
98     langpriority = lp;
99     return;
100     }
101     lpo = lp;
102     lp = lp->next;
103     }
104    
105     /* no existing entry, create a new one */
106     lp = nmalloc(sizeof(lang_pri));
107     lp->lang = nmalloc(strlen(lang) + 1);
108     strcpy(lp->lang, lang);
109     lp->next = NULL;
110    
111     /* if we have other entries, point to the beginning of the old list */
112     if (langpriority)
113     lp->next = langpriority;
114     langpriority = lp;
115 fabian 1.4 putlog(LOG_MISC, "*", "LANG: Added language support for %s.", lang);
116 segfault 1.1 }
117    
118     /* remove a language from the list of preferred languages. */
119     static int del_lang(char *lang)
120     {
121     lang_pri *lp = langpriority, *lpo = NULL;
122    
123     context;
124     while (lp) {
125     /* found the language? */
126     if (!strcmp(lang, lp->lang)) {
127     if (lpo)
128     lpo->next = lp->next;
129     else
130     langpriority = lp->next;
131     if (lp->lang)
132     nfree(lp->lang);
133     nfree(lp);
134     putlog(LOG_MISC, "*", "LANG: Not supporting language %s any longer.",
135     lang);
136     return 1;
137     }
138     lpo = lp;
139     lp = lp->next;
140     }
141     /* language not found */
142     return 0;
143     }
144    
145     static int add_message(int lidx, char *ltext)
146     {
147     lang_tab *l = langtab[lidx & 63];
148    
149     while (l) {
150     if (l->idx && (l->idx == lidx)) {
151     nfree(l->text);
152     l->text = nmalloc(strlen(ltext) + 1);
153     strcpy(l->text, ltext);
154     return 1;
155     }
156     if (!l->next)
157     break;
158     l = l->next;
159     }
160     if (l) {
161     l->next = nmalloc(sizeof(lang_tab));
162     l = l->next;
163     } else
164     l = langtab[lidx & 63] = nmalloc(sizeof(lang_tab));
165     l->idx = lidx;
166     l->text = nmalloc(strlen(ltext) + 1);
167     strcpy(l->text, ltext);
168     l->next = 0;
169     return 0;
170     }
171    
172     /* recheck all sections and check if any language files are available
173     * which match the preferred language(s) more closely
174     */
175     static void recheck_lang_sections(void)
176     {
177     lang_sec *ls = langsection;
178     char *langfile;
179    
180     context;
181     while (ls) {
182     if (ls->section) {
183 fabian 1.3 langfile = get_langfile(ls);
184 segfault 1.1 /* found a language with a more preferred language? */
185     if (langfile) {
186     read_lang(langfile);
187     nfree(langfile);
188     }
189     }
190     ls = ls->next;
191     }
192     }
193    
194     /* parse a language file */
195     static void read_lang(char *langfile)
196     {
197     FILE *FLANG;
198     char lbuf[512];
199     char *ltext = NULL;
200     char *ctmp, *ctmp1;
201     int lidx;
202     int lline = 0;
203     int lskip;
204     int ltexts = 0;
205     int ladd = 0, lupdate = 0;
206    
207     context;
208     FLANG = fopen(langfile, "r");
209     if (FLANG == NULL) {
210 fabian 1.3 putlog(LOG_MISC, "*", "LANG: unexpected: reading from file %s failed.",
211     langfile);
212 segfault 1.1 return;
213     }
214    
215     lskip = 0;
216     while (fgets(lbuf, 511, FLANG)) {
217     lline++;
218     if (lbuf[0] != '#' || lskip) {
219     ltext = nrealloc(ltext, 512);
220     if (sscanf(lbuf, "%s", ltext) != EOF) {
221     if (sscanf(lbuf, "0x%x,%500c", &lidx, ltext) != 2) {
222     putlog(LOG_MISC, "*", "Malformed text line in %s at %d.",
223     langfile, lline);
224     } else {
225     ltexts++;
226     ctmp = strchr(ltext, '\n');
227     *ctmp = 0;
228     while (ltext[strlen(ltext) - 1] == '\\') {
229     ltext[strlen(ltext) - 1] = 0;
230     if (fgets(lbuf, 511, FLANG)) {
231     lline++;
232     ctmp = strchr(lbuf, '\n');
233     *ctmp = 0;
234     ltext = nrealloc(ltext, strlen(lbuf) + strlen(ltext) + 1);
235     strcpy(strchr(ltext, 0), lbuf);
236     }
237     }
238     }
239     /* We gotta fix \n's here as, being arguments to sprintf(), */
240     /* they won't get translated */
241     ctmp = ltext;
242     ctmp1 = ltext;
243     while (*ctmp1) {
244     if (*ctmp1 == '\\' && *(ctmp1 + 1) == 'n') {
245     *ctmp = '\n';
246     ctmp1++;
247     } else
248     *ctmp = *ctmp1;
249     ctmp++;
250     ctmp1++;
251     }
252     *ctmp = '\0';
253     if (add_message(lidx, ltext)) {
254     lupdate++;
255     } else
256     ladd++;
257     }
258     } else {
259     ctmp = strchr(lbuf, '\n');
260     if (lskip && (strlen(lbuf) == 1 || *(ctmp - 1) != '\\'))
261     lskip = 0;
262     }
263     }
264     nfree(ltext);
265     fclose(FLANG);
266    
267     putlog(LOG_MISC, "*", "LANG: %d messages of %d lines loaded from %s",
268     ltexts, lline, langfile);
269     putlog(LOG_MISC, "*", "LANG: %d adds, %d updates to message table",
270     ladd, lupdate);
271     }
272    
273     /* Add a new language section. e.g. section "core"
274     * Load an apropriate language file for the specified section.
275     */
276     void add_lang_section(char *section)
277     {
278     char *langfile = NULL;
279     lang_sec *ls = langsection, *ols = NULL;
280 fabian 1.3 int ok = 0;
281    
282 segfault 1.1 context;
283     while (ls) {
284     /* already know of that section? */
285     if (!strcmp(section, ls->section))
286     return;
287     ols = ls;
288     ls = ls->next;
289     }
290    
291     /* create new section entry */
292     ls = nmalloc(sizeof(lang_sec));
293     ls->section = nmalloc(strlen(section) + 1);
294     strcpy(ls->section, section);
295     ls->lang = NULL;
296     ls->next = NULL;
297    
298     /* connect to existing list of sections */
299     if (ols)
300     ols->next = ls;
301     else
302     langsection = ls;
303     putlog(LOG_MISC, "*", "LANG: Added section %s.", section);
304    
305 fabian 1.3 /* Always load base language */
306     langfile = get_specific_langfile(BASELANG, ls);
307     if (langfile) {
308     read_lang(langfile);
309     nfree(langfile);
310     ok = 1;
311     }
312     /* Now overwrite base language with a more preferred one */
313     langfile = get_langfile(ls);
314 segfault 1.1 if (!langfile) {
315 fabian 1.3 if (!ok)
316     putlog(LOG_MISC, "*", "LANG: No lang files found for section %s.",
317     section);
318 segfault 1.1 return;
319     }
320     read_lang(langfile);
321     nfree(langfile);
322     }
323    
324     int del_lang_section(char *section)
325     {
326     lang_sec *ls = langsection, *ols = NULL;
327    
328     while (ls) {
329     if (ls->section && !strcmp(ls->section, section)) {
330     if (ols)
331     ols->next = ls->next;
332     else
333     langsection = ls->next;
334     nfree(ls->section);
335     if (ls->lang)
336     nfree(ls->lang);
337     nfree(ls);
338     putlog(LOG_MISC, "*", "LANG: Removed section %s.", section);
339     return 1;
340     }
341     ols = ls;
342     ls = ls->next;
343     }
344     return 0;
345     }
346    
347 fabian 1.3 static char *get_specific_langfile(char *language, lang_sec *sec)
348     {
349     char *ldir = getenv("EGG_LANGDIR");
350     char *langfile;
351     FILE *sfile = NULL;
352    
353     if (!ldir)
354     ldir = LANGDIR;
355     langfile = nmalloc(strlen(ldir) + strlen(sec->section) + strlen(language)+8);
356     sprintf(langfile, "%s/%s.%s.lang", ldir, sec->section, language);
357     sfile = fopen(langfile, "r");
358     if (sfile) {
359     fclose(sfile);
360     /* save language used for this section */
361     sec->lang = nrealloc(sec->lang, strlen(language) + 1);
362     strcpy(sec->lang, language);
363     return langfile;
364     }
365     nfree(langfile);
366     return NULL;
367     }
368    
369 segfault 1.1 /* Searches for available language files and returns the file with the
370     * most preferred language.
371     */
372 fabian 1.3 static char *get_langfile(lang_sec *sec)
373 segfault 1.1 {
374     char *langfile;
375     lang_pri *lp = langpriority;
376    
377     context;
378     while (lp) {
379     /* there is no need to reload the same language */
380     if (sec->lang && !strcmp(sec->lang, lp->lang)) {
381     return NULL;
382     }
383 fabian 1.3 langfile = get_specific_langfile(lp->lang, sec);
384     if (langfile)
385 segfault 1.1 return langfile;
386     lp = lp->next;
387     }
388     /* we did not find any files, clear the language field */
389     if (sec->lang)
390     nfree(sec->lang);
391     sec->lang = NULL;
392     return NULL;
393     }
394    
395     /* Split up a string /path/<section>.<language>.lang into the
396     * needed information for the new language system.
397     * Only needed for compability functions.
398     */
399     static int split_lang(char *par, char **lang, char **section)
400     {
401     char *p;
402    
403     context;
404     p = strrchr(par, '/');
405     /* path attached? */
406     if (p)
407     *section = p + 1;
408     else
409     *section = par;
410     p = strchr(*section, '.');
411     if (p)
412     p[0] = 0;
413     else
414     return 0;
415     *lang = p + 1;
416     p = strstr(*lang, ".lang");
417     if (p)
418     p[0] = 0;
419     return 1;
420     }
421    
422     /* compability function to allow users/modules to use the old command. */
423     int cmd_loadlanguage(struct userrec *u, int idx, char *par)
424     {
425     char *section, *lang, *buf;
426    
427     context;
428     dprintf(idx, "Note: This command is obsoleted by +lang.\n");
429     if (!par || !par[0]) {
430     dprintf(idx, "Usage: language <section>.<language>\n");
431     return 0;
432     }
433     if (idx != DP_LOG)
434     putlog(LOG_CMDS, "*", "#%s# language %s", dcc[idx].nick, par);
435     buf = nmalloc(strlen(par)+1);
436     strcpy(buf, par);
437     if (!split_lang(buf, &lang, &section)) {
438     nfree(buf);
439     dprintf(idx, "Invalid parameter %s.\n", par);
440     return 0;
441     }
442     add_lang(lang);
443     add_lang_section(section);
444     nfree(buf);
445     recheck_lang_sections();
446     return 0;
447     }
448    
449     static int cmd_plslang(struct userrec *u, int idx, char *par)
450     {
451     context;
452     if (!par || !par[0]) {
453     dprintf(idx, "Usage: +lang <language>\n");
454     return 0;
455     }
456     putlog(LOG_CMDS, "*", "#%s# +lang %s", dcc[idx].nick, par);
457     add_lang(par);
458     recheck_lang_sections();
459     return 0;
460     }
461    
462     static int cmd_mnslang(struct userrec *u, int idx, char *par)
463     {
464     context;
465     if (!par || !par[0]) {
466     dprintf(idx, "Usage: -lang <language>\n");
467     return 0;
468     }
469     putlog(LOG_CMDS, "*", "#%s# -lang %s", dcc[idx].nick, par);
470     if (!del_lang(par))
471     dprintf(idx, "Language %s not found.\n", par);
472     else
473     recheck_lang_sections();
474     return 0;
475     }
476    
477     static int cmd_plslsec(struct userrec *u, int idx, char *par)
478     {
479     context;
480     if (!par || !par[0]) {
481     dprintf(idx, "Usage: +lsec <section>\n");
482     return 0;
483     }
484     putlog(LOG_CMDS, "*", "#%s# +lsec %s", dcc[idx].nick, par);
485     add_lang_section(par);
486     return 0;
487     }
488    
489     static int cmd_mnslsec(struct userrec *u, int idx, char *par)
490     {
491     context;
492     if (!par || !par[0]) {
493     dprintf(idx, "Usage: -lsec <section>\n");
494     return 0;
495     }
496     putlog(LOG_CMDS, "*", "#%s# -lsec %s", dcc[idx].nick, par);
497     if (!del_lang_section(par))
498     dprintf(idx, "Section %s not found.\n", par);
499     return 0;
500     }
501    
502     static int cmd_relang(struct userrec *u, int idx, char *par)
503     {
504     dprintf(idx, "Rechecking language sections...\n");
505     recheck_lang_sections();
506     return 0;
507     }
508    
509     static int cmd_languagedump(struct userrec *u, int idx, char *par)
510     {
511     lang_tab *l;
512     char ltext2[512];
513     int idx2, i;
514    
515     context;
516     putlog(LOG_CMDS, "*", "#%s# ldump %s", dcc[idx].nick, par);
517     if (par[0]) {
518     /* atoi (hence strtol) don't work right here for hex */
519     if (strlen(par) > 2 && par[0] == '0' && par[1] == 'x')
520     sscanf(par, "%x", &idx2);
521     else
522     idx2 = (int) strtol(par, (char **) NULL, 10);
523     strcpy(ltext2, get_language(idx2));
524     dprintf(idx, "0x%x: %s\n", idx2, ltext2);
525     return 0;
526     }
527     dprintf(idx, " LANGIDX TEXT\n");
528     for (i = 0; i < 64; i++)
529     for (l = langtab[i]; l; l = l->next)
530     dprintf(idx, "0x%x %s\n", l->idx, l->text);
531     return 0;
532     }
533    
534     static char text[512];
535     char *get_language(int idx)
536     {
537     lang_tab *l = langtab[idx & 63];
538    
539     if (!idx)
540     return "MSG-0-";
541     while (l) {
542     if (idx == l->idx)
543     return l->text;
544     l = l->next;
545     }
546     sprintf(text, "MSG%03X", idx);
547     return text;
548     }
549    
550     int expmem_language()
551     {
552     lang_tab *l;
553     lang_sec *ls = langsection;
554     lang_pri *lp = langpriority;
555     int i, size = 0;
556    
557     context;
558     for (i = 0; i < 64; i++)
559     for (l = langtab[i]; l; l = l->next) {
560     size += sizeof(lang_tab);
561     size += (strlen(l->text) + 1);
562     }
563     while (ls) {
564     size += sizeof(lang_sec);
565     if (ls->section)
566     size += strlen(ls->section)+1;
567     if (ls->lang)
568     size += strlen(ls->lang)+1;
569     ls = ls->next;
570     }
571     while (lp) {
572     size += sizeof(lang_pri);
573     if (lp->lang)
574     size += strlen(lp->lang)+1;
575     lp = lp->next;
576     }
577     return size;
578     }
579    
580     /* a report on the module status - not sure if we need this now :/ */
581     static int cmd_languagestatus(struct userrec *u, int idx, char *par)
582     {
583     int ltexts = 0;
584     int maxdepth = 0, used = 0, empty = 0, i, c;
585     lang_tab *l;
586     lang_sec *ls = langsection;
587     lang_pri *lp = langpriority;
588    
589     for (i = 0; i < 64; i++) {
590     c = 0;
591     for (l = langtab[i]; l; l = l->next)
592     c++;
593     if (c > maxdepth)
594     maxdepth = c;
595     if (c)
596     used++;
597     else
598     empty++;
599     ltexts += c;
600     }
601     context;
602     dprintf(idx, "language code report:\n");
603     dprintf(idx, " Table size: %d bytes\n", expmem_language());
604     dprintf(idx, " Text messages: %d\n", ltexts);
605     dprintf(idx, " %d used, %d unused, maxdepth %d, avg %f\n",
606     used, empty, maxdepth, (float) ltexts / 64.0);
607     if (lp) {
608     dprintf(idx, "languages:\n");
609     while (lp) {
610     dprintf(idx, " %s\n", lp->lang);
611     lp = lp->next;
612     }
613     }
614     if (ls) {
615     dprintf(idx, "language sections:\n");
616     while (ls) {
617     dprintf(idx, " %s - %s\n", ls->section,
618     ls->lang ? ls->lang : "<none>");
619     ls = ls->next;
620     }
621     }
622     return 0;
623     }
624    
625     /* compability function to allow scripts to use the old command. */
626     static int tcl_language STDVAR
627     {
628     char *lang, *section, *buf;
629     BADARGS(2, 2, " language");
630    
631     buf = nmalloc(strlen(argv[1])+1);
632     strcpy(buf, argv[1]);
633     if (!split_lang(buf, &lang, &section)) {
634     Tcl_AppendResult(irp, "Invalid parameter", NULL);
635     nfree(buf);
636     return TCL_ERROR;
637     }
638     add_lang(lang);
639     add_lang_section(section);
640     nfree(buf);
641     recheck_lang_sections();
642     return TCL_OK;
643     }
644    
645     static int tcl_plslang STDVAR
646     {
647     BADARGS(2, 2, " language");
648    
649     add_lang(argv[1]);
650     recheck_lang_sections();
651    
652     return TCL_OK;
653     }
654    
655     static int tcl_mnslang STDVAR
656     {
657     BADARGS(2, 2, " language");
658    
659     if (!del_lang(argv[1])) {
660     Tcl_AppendResult(irp, "Language not found.", NULL);
661     return TCL_ERROR;
662     }
663     recheck_lang_sections();
664    
665     return TCL_OK;
666     }
667    
668     static int tcl_addlangsection STDVAR
669     {
670     BADARGS(2, 2, " section");
671    
672     add_lang_section(argv[1]);
673     return TCL_OK;
674     }
675    
676     static int tcl_dellangsection STDVAR
677     {
678     BADARGS(2, 2, " section");
679    
680     if (!del_lang_section(argv[1])) {
681     Tcl_AppendResult(irp, "Section not found", NULL);
682     return TCL_ERROR;
683     }
684     return TCL_OK;
685     }
686    
687     static int tcl_relang STDVAR
688     {
689     recheck_lang_sections();
690     return TCL_OK;
691     }
692    
693     static cmd_t langdcc[] =
694     {
695     {"language", "n", cmd_loadlanguage, NULL},
696     {"+lang", "n", cmd_plslang, NULL},
697     {"-lang", "n", cmd_mnslang, NULL},
698     {"+lsec", "n", cmd_plslsec, NULL},
699     {"-lsec", "n", cmd_mnslsec, NULL},
700     {"ldump", "n", cmd_languagedump, NULL},
701     {"lstat", "n", cmd_languagestatus, NULL},
702     {"relang", "n", cmd_relang, NULL},
703 fabian 1.2 {0, 0, 0, 0}
704 segfault 1.1 };
705    
706     static tcl_cmds langtcls[] =
707     {
708     {"language", tcl_language},
709     {"addlang", tcl_plslang},
710     {"dellang", tcl_mnslang},
711     {"addlangsection", tcl_addlangsection},
712     {"dellangsection", tcl_dellangsection},
713     {"relang", tcl_relang},
714     {0, 0}
715     };
716    
717     void init_language(int flag)
718     {
719     int i;
720     char *deflang;
721    
722     context;
723     if (flag) {
724     for (i = 0; i < 32; i++)
725     langtab[i] = 0;
726     /* The default language is always "english" as language files are
727     * gauranteed to exist in english. */
728     add_lang("english");
729     /* Let the user choose a different, preferred language */
730     deflang = getenv("EGG_LANG");
731     if (deflang)
732     add_lang(deflang);
733     add_lang_section("core");
734     } else {
735     add_tcl_commands(langtcls);
736 fabian 1.2 add_builtins(H_dcc, langdcc);
737 segfault 1.1 }
738     }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23