chiark / gitweb /
Initial revision
[ssr] / StraySrc / Libraries / Steel / c / prefs
1 /*
2  * prefs
3  *
4  * Preferences loading and saving
5  *
6  * © 1993-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 "prefs.h"
29 #include "os.h"
30 #include "utils.h"
31 #include "msgs.h"
32 #include "choices.h"
33 #include "res.h"
34 #include "kernel.h"
35 #include "werr.h"
36
37 #include <stdio.h>
38 #include <string.h>
39 #include <ctype.h>
40
41 #define unused(x) ((x)=(x))
42
43 static prefs_prefstr *prefs__prefs;
44
45 /*
46  * char *prefs__match(char *a,char *b)
47  *
48  * Use
49  *  Checks to see if the first part of a matches b.  If it does, it returns
50  *  the rest of a.
51  *
52  * Parameters
53  *  char *a == an input string
54  *  char *b == a keyword
55  *
56  * Returns
57  *  The part of a following b, or NULL if no match
58  */
59
60 static char *prefs__match(char *a,char *b)
61 {
62   if (!*a)
63     return (0);
64   while (*b)
65   {
66     if (tolower(*(a++))!=tolower(*(b++)))
67       return (0);
68   }
69   while (*a==' ')
70     a++;
71   if (*a=='=')
72     a++;
73   while (*a==' ')
74     a++;
75   return (a);
76 }
77
78 /*
79  * char *prefs_readBoolean(char *tag,char *args,void *handle)
80  *
81  * Use
82  *  Reads a Boolean variable (i.e. one that can be either TRUE or FALSE).
83  */
84
85 char *prefs_readBoolean(char *tag,char *args,void *handle)
86 {
87   unused(tag);
88   if (utils_caselessCmp(args,"true")==0)
89     *(BOOL *)handle=TRUE;
90   else if (utils_caselessCmp(args,"false")==0)
91     *(BOOL *)handle=FALSE;
92   else
93     return (msgs_lookup("prefsRBB:Bad boolean variable '%s' at line %i (must be 'true' or 'false')"));
94   return (0);
95 }
96
97 /*
98  * char *prefs_writeBoolean(char *tag,FILE *fp,void *handle)
99  *
100  * Use
101  *  Writes a Boolean variable to the preferences file.
102  */
103
104 char *prefs_writeBoolean(char *tag,FILE *fp,void *handle)
105 {
106   fprintf(fp,"%s=%s\n",tag,*(BOOL *)handle ? "true" : "false");
107   return (0);
108 }
109
110 /*
111  * char *prefs_readNumeric(char *tag,char *args,void *handle)
112  *
113  * Use
114  *  Reads a signed integer from the preferences file.
115  */
116
117 char *prefs_readNumeric(char *tag,char *args,void *handle)
118 {
119   unused(tag);
120   sscanf(args,"%d",(int *)handle);
121   return (0);
122 }
123
124 /*
125  * char *prefs_writeNumeric(char *tag,FILE *fp,void *handle)
126  *
127  * Use
128  *  Writes a signed integer to the preferences file.
129  */
130
131 char *prefs_writeNumeric(char *tag,FILE *fp,void *handle)
132 {
133   fprintf(fp,"%s=%i\n",tag,*(int *)handle);
134   return (0);
135 }
136
137 /*
138  * char *prefs_readString(char *tag,char *args,void *handle)
139  *
140  * Use
141  *  Reads a string from the preferences file.  It is assumed that the buffer
142  *  pointed to by handle is big enough.
143  */
144
145 char *prefs_readString(char *tag,char *args,void *handle)
146 {
147   char *p;
148   unused(tag);
149   if (*args=='\'')
150   {
151     for (p=++args;*p && *p!='\'';p++)
152       /* blank! */;
153     *p=0;
154   }
155   strcpy((char *)handle,args);
156   return (0);
157 }
158
159 /*
160  * char *prefs_writeString(char *tag,FILE *fp,void *handle)
161  *
162  * Use
163  *  Writes a signed integer to the preferences file.
164  */
165
166 char *prefs_writeString(char *tag,FILE *fp,void *handle)
167 {
168   fprintf(fp,"%s='%s'\n",tag,(char *)handle);
169   return (0);
170 }
171
172 /*
173  * void prefs_preferences(prefs_prefstr *p)
174  *
175  * Use
176  *  Sets up the prefs system to use the preferences definition specified.
177  *  'p' should be a pointer to an array of prefs_prefstrs, terminated by an
178  *  entry with a null 'tag'.  The preferences file created will be called
179  *  'Choices' in the current application's directory (<App$Dir>.Choices).
180  *
181  * Parameters
182  *  prefs_prefstr *p == pointer to an array of preferences definitions
183  */
184
185 void prefs_preferences(prefs_prefstr *p)
186 {
187   prefs__prefs=p;
188 }
189
190 /*
191  * void prefs_read(void)
192  *
193  * Use
194  *  Reads preferences from the preferences file.
195  */
196
197 void prefs_read(void)
198 {
199   FILE *fp;
200   int i;
201   int line=0;
202   char buff[256];
203   char *p;
204   char *args;
205   char *error;
206   char *preffile=choices_name("Choices",FALSE);
207
208   /* --- Make sure the Preferences file exists --- *
209    *
210    * If we can't find the Preferences, we leave the user's buffer unchanged
211    * to allow defaults
212    */
213
214   if (!res_fileExists(preffile))
215     return;
216
217   /* --- Open the Preferences file --- */
218
219   fp=fopen(preffile,"r");
220   if (!fp)
221   {
222     werr(FALSE,
223          msgs_lookup("prefsERP:Error reading preferences.  "
224                      "Assuming default preferences."));
225     return;
226   }
227
228   /* --- Read the file a line at a time and parse it --- */
229
230   while (fgets(buff,256,fp))
231   {
232     /* --- Bump line count for error messages --- */
233
234     line++;
235
236     /* --- Strip leading spaces --- */
237
238     for (p=buff;isspace(*p);p++)
239       /* blank! */;
240
241     /* --- fgets leaves a return on the end -- kill it --- */
242
243     utils_ctermToNterm(p);
244
245     /* --- Do something about the line --- */
246
247     switch (*p)
248     {
249       /* --- Discard blank lines and comments --- */
250       case 0:
251       case ';':
252         break;
253
254       /* --- Otherwise find the parser for this variable and call it --- */
255
256       default:
257         for (i=0;prefs__prefs[i].tag;i++)
258         {
259           if (args=prefs__match(p,prefs__prefs[i].tag),args)
260           {
261             if (prefs__prefs[i].read)
262             {
263               if (error=prefs__prefs[i].read(prefs__prefs[i].tag,
264                                              args,
265                                              prefs__prefs[i].handle),error)
266               {
267                 werr(FALSE,error,prefs__prefs[i].tag,line);
268                 fclose(fp);
269                 return;
270               }
271             }
272             break;
273           }
274         }
275         break;
276     }
277   }
278   fclose(fp);
279 }
280
281 /*
282  * void prefs_write(void)
283  *
284  * Use
285  *  Writes preferences out to disk.
286  */
287
288 void prefs_write(void)
289 {
290   int i;
291   FILE *fp=fopen(choices_name("Choices",TRUE),"w");
292   char *error;
293
294   /* --- Complain if we can't write the file --- */
295
296   if (!fp)
297   {
298     werr(FALSE,
299          msgs_lookup("prefsEWP:Error writing preferences: '%s'"),
300          _kernel_last_oserror()->errmess);
301     return;
302   }
303
304   /* --- Go through the entries one by one calling the output fns --- */
305
306   for (i=0;prefs__prefs[i].tag;i++)
307   {
308     if (prefs__prefs[i].tag[0]==';' || prefs__prefs[i].tag[0]=='\n')
309       fprintf(fp,"%s",prefs__prefs[i].tag);
310     else if (!prefs__prefs[i].write)
311       /* blank! */;
312     else if (error=prefs__prefs[i].write(prefs__prefs[i].tag,
313                                          fp,
314                                          prefs__prefs[i].handle),error)
315     {
316       werr(FALSE,error,prefs__prefs[i].tag);
317       fclose(fp);
318       return;
319     }
320   }
321
322   /* --- Close the file and exit --- */
323
324   fclose(fp);
325   return;
326 }