/[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.6 - (hide annotations) (download) (as text)
Tue Dec 21 17:35:09 1999 UTC (19 years, 7 months ago) by fabian
Branch: MAIN
Changes since 1.5: +28 -7 lines
File MIME type: text/x-chdr
Tothwolf's id-header

1 fabian 1.6 /*
2     * language.c -- handles:
3     * language support code
4     *
5     * $Id$
6     */
7     /*
8     * Copyright (C) 1997 Robey Pointer
9     * Copyright (C) 1999 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 segfault 1.1 */
25    
26 fabian 1.6 /*
27 segfault 1.1 * DOES:
28     * Nothing <- typical BB code :)
29 fabian 1.6 *
30 segfault 1.1 * 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 fabian 1.6 *
46 segfault 1.1 * FILE FORMAT: language.lang
47     * <textidx>,<text>
48     * TEXT MESSAGE USAGE:
49     * get_language(<textidx> [,<PARMS>])
50 fabian 1.6 *
51 segfault 1.1 * 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 fabian 1.6 *
64 segfault 1.1 */
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 fabian 1.3 static char *get_specific_langfile(char *, lang_sec *);
98     static char *get_langfile(lang_sec *);
99 segfault 1.1 static int split_lang(char *, char **, char **);
100 fabian 1.3 int cmd_loadlanguage(struct userrec *, int, char *);
101 segfault 1.1
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 fabian 1.5 Context;
111 segfault 1.1 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 fabian 1.4 putlog(LOG_MISC, "*", "LANG: Added language support for %s.", lang);
137 segfault 1.1 }
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 fabian 1.5 Context;
145 segfault 1.1 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: Not supporting language %s any longer.",
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 fabian 1.5 Context;
202 segfault 1.1 while (ls) {
203     if (ls->section) {
204 fabian 1.3 langfile = get_langfile(ls);
205 segfault 1.1 /* 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 fabian 1.5 Context;
229 segfault 1.1 FLANG = fopen(langfile, "r");
230     if (FLANG == NULL) {
231 fabian 1.3 putlog(LOG_MISC, "*", "LANG: unexpected: reading from file %s failed.",
232     langfile);
233 segfault 1.1 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 fabian 1.3 int ok = 0;
302    
303 fabian 1.5 Context;
304 segfault 1.1 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: Added section %s.", section);
325    
326 fabian 1.3 /* Always load base language */
327     langfile = get_specific_langfile(BASELANG, ls);
328     if (langfile) {
329     read_lang(langfile);
330     nfree(langfile);
331     ok = 1;
332     }
333     /* Now overwrite base language with a more preferred one */
334     langfile = get_langfile(ls);
335 segfault 1.1 if (!langfile) {
336 fabian 1.3 if (!ok)
337     putlog(LOG_MISC, "*", "LANG: No lang files found for section %s.",
338     section);
339 segfault 1.1 return;
340     }
341     read_lang(langfile);
342     nfree(langfile);
343     }
344    
345     int del_lang_section(char *section)
346     {
347     lang_sec *ls = langsection, *ols = NULL;
348    
349     while (ls) {
350     if (ls->section && !strcmp(ls->section, section)) {
351     if (ols)
352     ols->next = ls->next;
353     else
354     langsection = ls->next;
355     nfree(ls->section);
356     if (ls->lang)
357     nfree(ls->lang);
358     nfree(ls);
359     putlog(LOG_MISC, "*", "LANG: Removed section %s.", section);
360     return 1;
361     }
362     ols = ls;
363     ls = ls->next;
364     }
365     return 0;
366     }
367    
368 fabian 1.3 static char *get_specific_langfile(char *language, lang_sec *sec)
369     {
370     char *ldir = getenv("EGG_LANGDIR");
371     char *langfile;
372     FILE *sfile = NULL;
373    
374     if (!ldir)
375     ldir = LANGDIR;
376     langfile = nmalloc(strlen(ldir) + strlen(sec->section) + strlen(language)+8);
377     sprintf(langfile, "%s/%s.%s.lang", ldir, sec->section, language);
378     sfile = fopen(langfile, "r");
379     if (sfile) {
380     fclose(sfile);
381     /* save language used for this section */
382     sec->lang = nrealloc(sec->lang, strlen(language) + 1);
383     strcpy(sec->lang, language);
384     return langfile;
385     }
386     nfree(langfile);
387     return NULL;
388     }
389    
390 segfault 1.1 /* Searches for available language files and returns the file with the
391     * most preferred language.
392     */
393 fabian 1.3 static char *get_langfile(lang_sec *sec)
394 segfault 1.1 {
395     char *langfile;
396     lang_pri *lp = langpriority;
397    
398 fabian 1.5 Context;
399 segfault 1.1 while (lp) {
400     /* there is no need to reload the same language */
401     if (sec->lang && !strcmp(sec->lang, lp->lang)) {
402     return NULL;
403     }
404 fabian 1.3 langfile = get_specific_langfile(lp->lang, sec);
405     if (langfile)
406 segfault 1.1 return langfile;
407     lp = lp->next;
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 fabian 1.5 Context;
425 segfault 1.1 p = strrchr(par, '/');
426     /* path attached? */
427     if (p)
428     *section = p + 1;
429     else
430     *section = par;
431     p = strchr(*section, '.');
432     if (p)
433     p[0] = 0;
434     else
435     return 0;
436     *lang = p + 1;
437     p = strstr(*lang, ".lang");
438     if (p)
439     p[0] = 0;
440     return 1;
441     }
442    
443     /* compability function to allow users/modules to use the old command. */
444     int cmd_loadlanguage(struct userrec *u, int idx, char *par)
445     {
446     char *section, *lang, *buf;
447    
448 fabian 1.5 Context;
449 segfault 1.1 dprintf(idx, "Note: This command is obsoleted by +lang.\n");
450     if (!par || !par[0]) {
451     dprintf(idx, "Usage: language <section>.<language>\n");
452     return 0;
453     }
454     if (idx != DP_LOG)
455     putlog(LOG_CMDS, "*", "#%s# language %s", dcc[idx].nick, par);
456     buf = nmalloc(strlen(par)+1);
457     strcpy(buf, par);
458     if (!split_lang(buf, &lang, &section)) {
459     nfree(buf);
460     dprintf(idx, "Invalid parameter %s.\n", par);
461     return 0;
462     }
463     add_lang(lang);
464     add_lang_section(section);
465     nfree(buf);
466     recheck_lang_sections();
467     return 0;
468     }
469    
470     static int cmd_plslang(struct userrec *u, int idx, char *par)
471     {
472 fabian 1.5 Context;
473 segfault 1.1 if (!par || !par[0]) {
474     dprintf(idx, "Usage: +lang <language>\n");
475     return 0;
476     }
477     putlog(LOG_CMDS, "*", "#%s# +lang %s", dcc[idx].nick, par);
478     add_lang(par);
479     recheck_lang_sections();
480     return 0;
481     }
482    
483     static int cmd_mnslang(struct userrec *u, int idx, char *par)
484     {
485 fabian 1.5 Context;
486 segfault 1.1 if (!par || !par[0]) {
487     dprintf(idx, "Usage: -lang <language>\n");
488     return 0;
489     }
490     putlog(LOG_CMDS, "*", "#%s# -lang %s", dcc[idx].nick, par);
491     if (!del_lang(par))
492     dprintf(idx, "Language %s not found.\n", par);
493     else
494     recheck_lang_sections();
495     return 0;
496     }
497    
498     static int cmd_plslsec(struct userrec *u, int idx, char *par)
499     {
500 fabian 1.5 Context;
501 segfault 1.1 if (!par || !par[0]) {
502     dprintf(idx, "Usage: +lsec <section>\n");
503     return 0;
504     }
505     putlog(LOG_CMDS, "*", "#%s# +lsec %s", dcc[idx].nick, par);
506     add_lang_section(par);
507     return 0;
508     }
509    
510     static int cmd_mnslsec(struct userrec *u, int idx, char *par)
511     {
512 fabian 1.5 Context;
513 segfault 1.1 if (!par || !par[0]) {
514     dprintf(idx, "Usage: -lsec <section>\n");
515     return 0;
516     }
517     putlog(LOG_CMDS, "*", "#%s# -lsec %s", dcc[idx].nick, par);
518     if (!del_lang_section(par))
519     dprintf(idx, "Section %s not found.\n", par);
520     return 0;
521     }
522    
523     static int cmd_relang(struct userrec *u, int idx, char *par)
524     {
525     dprintf(idx, "Rechecking language sections...\n");
526     recheck_lang_sections();
527     return 0;
528     }
529    
530     static int cmd_languagedump(struct userrec *u, int idx, char *par)
531     {
532     lang_tab *l;
533     char ltext2[512];
534     int idx2, i;
535    
536 fabian 1.5 Context;
537 segfault 1.1 putlog(LOG_CMDS, "*", "#%s# ldump %s", dcc[idx].nick, par);
538     if (par[0]) {
539     /* atoi (hence strtol) don't work right here for hex */
540     if (strlen(par) > 2 && par[0] == '0' && par[1] == 'x')
541     sscanf(par, "%x", &idx2);
542     else
543     idx2 = (int) strtol(par, (char **) NULL, 10);
544     strcpy(ltext2, get_language(idx2));
545     dprintf(idx, "0x%x: %s\n", idx2, ltext2);
546     return 0;
547     }
548     dprintf(idx, " LANGIDX TEXT\n");
549     for (i = 0; i < 64; i++)
550     for (l = langtab[i]; l; l = l->next)
551     dprintf(idx, "0x%x %s\n", l->idx, l->text);
552     return 0;
553     }
554    
555     static char text[512];
556     char *get_language(int idx)
557     {
558     lang_tab *l = langtab[idx & 63];
559    
560     if (!idx)
561     return "MSG-0-";
562     while (l) {
563     if (idx == l->idx)
564     return l->text;
565     l = l->next;
566     }
567     sprintf(text, "MSG%03X", idx);
568     return text;
569     }
570    
571     int expmem_language()
572     {
573     lang_tab *l;
574     lang_sec *ls = langsection;
575     lang_pri *lp = langpriority;
576     int i, size = 0;
577    
578 fabian 1.5 Context;
579 segfault 1.1 for (i = 0; i < 64; i++)
580     for (l = langtab[i]; l; l = l->next) {
581     size += sizeof(lang_tab);
582     size += (strlen(l->text) + 1);
583     }
584     while (ls) {
585     size += sizeof(lang_sec);
586     if (ls->section)
587     size += strlen(ls->section)+1;
588     if (ls->lang)
589     size += strlen(ls->lang)+1;
590     ls = ls->next;
591     }
592     while (lp) {
593     size += sizeof(lang_pri);
594     if (lp->lang)
595     size += strlen(lp->lang)+1;
596     lp = lp->next;
597     }
598     return size;
599     }
600    
601     /* a report on the module status - not sure if we need this now :/ */
602     static int cmd_languagestatus(struct userrec *u, int idx, char *par)
603     {
604     int ltexts = 0;
605     int maxdepth = 0, used = 0, empty = 0, i, c;
606     lang_tab *l;
607     lang_sec *ls = langsection;
608     lang_pri *lp = langpriority;
609    
610     for (i = 0; i < 64; i++) {
611     c = 0;
612     for (l = langtab[i]; l; l = l->next)
613     c++;
614     if (c > maxdepth)
615     maxdepth = c;
616     if (c)
617     used++;
618     else
619     empty++;
620     ltexts += c;
621     }
622 fabian 1.5 Context;
623 segfault 1.1 dprintf(idx, "language code report:\n");
624     dprintf(idx, " Table size: %d bytes\n", expmem_language());
625     dprintf(idx, " Text messages: %d\n", ltexts);
626     dprintf(idx, " %d used, %d unused, maxdepth %d, avg %f\n",
627     used, empty, maxdepth, (float) ltexts / 64.0);
628     if (lp) {
629     dprintf(idx, "languages:\n");
630     while (lp) {
631     dprintf(idx, " %s\n", lp->lang);
632     lp = lp->next;
633     }
634     }
635     if (ls) {
636     dprintf(idx, "language sections:\n");
637     while (ls) {
638     dprintf(idx, " %s - %s\n", ls->section,
639     ls->lang ? ls->lang : "<none>");
640     ls = ls->next;
641     }
642     }
643     return 0;
644     }
645    
646     /* compability function to allow scripts to use the old command. */
647     static int tcl_language STDVAR
648     {
649     char *lang, *section, *buf;
650     BADARGS(2, 2, " language");
651    
652     buf = nmalloc(strlen(argv[1])+1);
653     strcpy(buf, argv[1]);
654     if (!split_lang(buf, &lang, &section)) {
655     Tcl_AppendResult(irp, "Invalid parameter", NULL);
656     nfree(buf);
657     return TCL_ERROR;
658     }
659     add_lang(lang);
660     add_lang_section(section);
661     nfree(buf);
662     recheck_lang_sections();
663     return TCL_OK;
664     }
665    
666     static int tcl_plslang STDVAR
667     {
668     BADARGS(2, 2, " language");
669    
670     add_lang(argv[1]);
671     recheck_lang_sections();
672    
673     return TCL_OK;
674     }
675    
676     static int tcl_mnslang STDVAR
677     {
678     BADARGS(2, 2, " language");
679    
680     if (!del_lang(argv[1])) {
681     Tcl_AppendResult(irp, "Language not found.", NULL);
682     return TCL_ERROR;
683     }
684     recheck_lang_sections();
685    
686     return TCL_OK;
687     }
688    
689     static int tcl_addlangsection STDVAR
690     {
691     BADARGS(2, 2, " section");
692    
693     add_lang_section(argv[1]);
694     return TCL_OK;
695     }
696    
697     static int tcl_dellangsection STDVAR
698     {
699     BADARGS(2, 2, " section");
700    
701     if (!del_lang_section(argv[1])) {
702     Tcl_AppendResult(irp, "Section not found", NULL);
703     return TCL_ERROR;
704     }
705     return TCL_OK;
706     }
707    
708     static int tcl_relang STDVAR
709     {
710     recheck_lang_sections();
711     return TCL_OK;
712     }
713    
714     static cmd_t langdcc[] =
715     {
716     {"language", "n", cmd_loadlanguage, NULL},
717     {"+lang", "n", cmd_plslang, NULL},
718     {"-lang", "n", cmd_mnslang, NULL},
719     {"+lsec", "n", cmd_plslsec, NULL},
720     {"-lsec", "n", cmd_mnslsec, NULL},
721     {"ldump", "n", cmd_languagedump, NULL},
722     {"lstat", "n", cmd_languagestatus, NULL},
723     {"relang", "n", cmd_relang, NULL},
724 fabian 1.2 {0, 0, 0, 0}
725 segfault 1.1 };
726    
727     static tcl_cmds langtcls[] =
728     {
729     {"language", tcl_language},
730     {"addlang", tcl_plslang},
731     {"dellang", tcl_mnslang},
732     {"addlangsection", tcl_addlangsection},
733     {"dellangsection", tcl_dellangsection},
734     {"relang", tcl_relang},
735     {0, 0}
736     };
737    
738     void init_language(int flag)
739     {
740     int i;
741     char *deflang;
742    
743 fabian 1.5 Context;
744 segfault 1.1 if (flag) {
745     for (i = 0; i < 32; i++)
746     langtab[i] = 0;
747     /* The default language is always "english" as language files are
748     * gauranteed to exist in english. */
749     add_lang("english");
750     /* Let the user choose a different, preferred language */
751     deflang = getenv("EGG_LANG");
752     if (deflang)
753     add_lang(deflang);
754     add_lang_section("core");
755     } else {
756     add_tcl_commands(langtcls);
757 fabian 1.2 add_builtins(H_dcc, langdcc);
758 segfault 1.1 }
759     }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23