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 }