chiark / gitweb /
Initial revision
[ssr] / StraySrc / Libraries / Steel / c / msgs
1 /*
2  * msgs.c
3  *
4  * Handling of messages files
5  *
6  * © 1994-1998 Straylight
7  */
8
9 /*----- Licensing note ----------------------------------------------------*
10  *
11  * This file is part of Straylight's Steel library.
12  *
13  * Steel is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2, or (at your option)
16  * any later version.
17  *
18  * Steel is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with Steel.  If not, write to the Free Software Foundation,
25  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32
33 #include "os.h"
34 #include "mem.h"
35 #include "werr.h"
36 #include "res.h"
37 #include "msgs.h"
38
39 /*----- Special types -----------------------------------------------------*/
40
41 typedef struct msgs__node
42 {
43   struct msgs__node *left;
44   struct msgs__node *right;
45   char tag[20];
46   char *message;
47 }
48 msgs__node;
49
50 /*----- Variables ---------------------------------------------------------*/
51
52 #define msgs__HASHSIZE 64
53
54 static msgs__node *msgs__all[msgs__HASHSIZE];
55
56 /*----- Main code ---------------------------------------------------------*/
57
58 /*
59  * int msgs__hash(char *p)
60  *
61  * Use
62  *  Hashes the string pointed to by p
63  */
64
65 static int msgs__hash(char *p)
66 {
67   unsigned int h=0;
68   unsigned int seed=0x46bc93d5;
69   for (;*p && *p!=':';p++)
70   {
71     h=(h*(*p)) ^ seed ^ h;
72     seed=seed*3141592621ul + 271828189;
73   }
74   return ((int)h & (msgs__HASHSIZE-1));
75 }
76
77 /*
78  * void msgs__add(msgs__node *t,msgs__node **p)
79  *
80  * Use
81  *  Adds node t to the tree with *p as its root
82  */
83
84 static void msgs__add(msgs__node *t,msgs__node **p)
85 {
86   int s;
87   if (*p)
88   {
89     s=strcmp(t->tag,(*p)->tag);
90     if (s>0)
91       msgs__add(t,&(*p)->right);
92     else if (s<0)
93       msgs__add(t,&(*p)->left);
94   }
95   else
96     *p=t;
97 }
98
99 /*
100  * int msgs__cmp(char *a,char *b)
101  *
102  * Use
103  *  Compares a tag-and-default a with a tag b.
104  */
105
106 static int msgs__cmp(char *a,char *b)
107 {
108   for (;;)
109   {
110     if ((*a==':' || *a==0) && *b==0)
111       return (0);
112     else if (*a!=*b)
113       return (*a-*b);
114     a++;
115     b++;
116   }
117 }
118
119 /*
120  * msgs__node *msgs__find(char *tag,msgs__node *t)
121  *
122  * Use
123  *  Finds the tag in the tree pointed to by t
124  */
125
126 static msgs__node *msgs__find(char *tag,msgs__node *t)
127 {
128   int s;
129   if (!t)
130     return (0);
131   s=msgs__cmp(tag,t->tag);
132   if (s>0)
133     return (msgs__find(tag,t->right));
134   else if (s<0)
135     return (msgs__find(tag,t->left));
136   else
137     return (t);
138 }
139
140 /*
141  * void msgs__insert(msgs__node *t)
142  *
143  * Use
144  *  Inserts the given messages structure into the overall messages system.
145  *
146  * Parameters
147  *  msgs__node *t == pointer to a filled in messages structure to fit in.
148  */
149
150 static void msgs__insert(msgs__node *t)
151 {
152   int i=msgs__hash(t->tag);
153   t->left=t->right=0;
154   msgs__add(t,msgs__all+i);
155 }
156
157 /*
158  * void msgs_readfile(char *name)
159  *
160  * Use
161  *  Loads the messages file given by name into the messages area.
162  */
163
164 void msgs_readfile(char *name)
165 {
166   FILE *fp=res_openfile(name,"r");
167   int c;
168   enum
169   {
170     newline,
171     comment,
172     tag,
173     newalt,
174     message,
175     endoffile
176   }
177   state=newline;
178   msgs__node *t[10];
179   char *p=0;
180   int len=0;
181   int i;
182   int alts=0;
183   char msg[1024];
184
185   if (!fp)
186     return;
187
188   while (state!=endoffile)
189   {
190     c=getc(fp);
191
192     switch (state)
193     {
194       case newline:
195         if (c==';' || c=='|' || c=='#')
196           state=comment;
197         else if (c==EOF)
198           state=endoffile;
199         else if (!isspace(c))
200         {
201           alts=0;
202           t[alts]=mem_alloc(sizeof(msgs__node));
203           if (!t[alts])
204           {
205             fclose(fp);
206             werr(FALSE,
207                  msgs_lookup("msgsNEM:Not enough memory to read "
208                                      "messages file '%s'"),
209                  name);
210             return;
211           }
212           p=t[alts]->tag;
213           *p++=c;
214           state=tag;
215         }
216         break;
217
218       case comment:
219         if (c=='\n')
220           state=newline;
221         else if (c==EOF)
222           state=endoffile;
223         break;
224
225       case newalt:
226         if (c==EOF)
227         {
228           for (i=0;i<alts;i++)
229             mem_free(t[i]);
230           werr(FALSE,
231                msgs_lookup("msgsEOF:Unexpected end of file in "
232                                    "messages file '%s'"),
233                name);
234           state=endoffile;
235         }
236         else
237         {
238           t[alts]=mem_alloc(sizeof(msgs__node));
239           if (!t[alts])
240           {
241             fclose(fp);
242             for (i=0;i<alts;i++)
243               mem_free(t[i]);
244             werr(FALSE,
245                  msgs_lookup("msgsNEM:Not enough memory to read "
246                                      "messages file '%s'"),
247                  name);
248             return;
249           }
250           p=t[alts]->tag;
251           *p++=c;
252           state=tag;
253         }
254         break;
255
256       case tag:
257         if (c=='\n' || c=='/')
258         {
259           *p++=0;
260           alts++;
261           state=newalt;
262         }
263         else if (c==':')
264         {
265           *p++=0;
266           alts++;
267           len=0;
268           p=msg;
269           state=message;
270         }
271         else if (c==EOF)
272         {
273           for (i=0;i<=alts;i++)
274             mem_free(t[i]);
275           werr(FALSE,
276                msgs_lookup("msgsEOF:Unexpected end of file in "
277                                    "messages file '%s'"),
278                name);
279           state=endoffile;
280         }
281         else
282           *p++=c;
283         break;
284
285       case message:
286         if (c==EOF || c=='\n')
287         {
288           *p=0;
289           p=mem_alloc(len+1);
290           if (!p)
291           {
292             fclose(fp);
293             for (i=0;i<alts;i++)
294               mem_free(t[i]);
295             werr(FALSE,
296                  msgs_lookup("msgsNEM:Not enough memory to read "
297                                      "messages file '%s'"),
298                  name);
299             return;
300           }
301           strcpy(p,msg);
302           for (i=0;i<alts;i++)
303           {
304             t[i]->message=p;
305             msgs__insert(t[i]);
306           }
307           alts=0;
308           state=(c==EOF ? endoffile : newline);
309         }
310         else
311         {
312           *p++=c;
313           len++;
314         }
315         break;
316     }
317   }
318   fclose(fp);
319 }
320
321 /*
322  * void msgs_init(void)
323  *
324  * Use
325  *  Reads the messages file `Messages' into memory.
326  */
327
328 void msgs_init(void)
329 {
330   msgs_readfile("Messages");
331 }
332
333 /*
334  * char *msgs_lookup(char *tag)
335  *
336  * Use
337  *  Searches the messages for one with a given tag.
338  */
339
340 char *msgs_lookup(char *tag)
341 {
342   msgs__node *t=msgs__find(tag,msgs__all[msgs__hash(tag)]);
343   char *p;
344   if (t)
345     return (t->message);
346   p=tag;
347   while (*p)
348   {
349     if (*p++==':')
350       return (p);
351   }
352   return (tag);
353 }
354
355 /*
356  * void msgs_delete(void)
357  *
358  * Use
359  *  Removes all messages from memory.
360  */
361
362 static void msgs__delTree(msgs__node *t)
363 {
364   if (!t)
365     return;
366   msgs__delTree(t->left);
367   msgs__delTree(t->right);
368   mem_free(t);
369   return;
370 }
371
372 void msgs_delete(void)
373 {
374   int i;
375   for (i=0;i<msgs__HASHSIZE;i++)
376   {
377     msgs__delTree(msgs__all[i]);
378     msgs__all[i]=0;
379   }
380 }