1 | /* |
1 | /* |
2 | configuration.c - Part of psiconv, a PSION 5 file formats converter |
2 | configuration.c - Part of psiconv, a PSION 5 file formats converter |
3 | Copyright (c) 1999, 2000,2003 Frodo Looijaard <frodol@dds.nl> |
3 | Copyright (c) 1999-2004 Frodo Looijaard <frodol@dds.nl> |
4 | |
4 | |
5 | This program is free software; you can redistribute it and/or modify |
5 | This program is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published by |
6 | it under the terms of the GNU General Public License as published by |
7 | the Free Software Foundation; either version 2 of the License, or |
7 | the Free Software Foundation; either version 2 of the License, or |
8 | (at your option) any later version. |
8 | (at your option) any later version. |
… | |
… | |
16 | along with this program; if not, write to the Free Software |
16 | along with this program; if not, write to the Free Software |
17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
18 | */ |
18 | */ |
19 | |
19 | |
20 | #include "config.h" |
20 | #include "config.h" |
|
|
21 | #include "compat.h" |
21 | #include "error.h" |
22 | #include "error.h" |
22 | #include "compat.h" |
|
|
23 | #include "unicode.h" |
23 | #include "unicode.h" |
24 | |
24 | |
25 | #include <stdio.h> |
25 | #include <stdio.h> |
26 | #include <stdlib.h> |
26 | #include <stdlib.h> |
27 | #include <string.h> |
27 | #include <string.h> |
|
|
28 | #include <strings.h> |
28 | #include <sys/types.h> |
29 | #include <sys/types.h> |
29 | #include <sys/stat.h> |
30 | #include <sys/stat.h> |
30 | #include <unistd.h> |
31 | #include <unistd.h> |
31 | #include <fcntl.h> |
32 | #include <fcntl.h> |
32 | |
33 | |
… | |
… | |
35 | #ifdef DMALLOC |
36 | #ifdef DMALLOC |
36 | #include <dmalloc.h> |
37 | #include <dmalloc.h> |
37 | #endif |
38 | #endif |
38 | |
39 | |
39 | #ifndef CONFIGURATION_SEARCH_PATH |
40 | #ifndef CONFIGURATION_SEARCH_PATH |
40 | #define CONFIGURATION_SEARCH_PATH "/etc/psiconv.conf:~/.psiconv.conf" |
41 | #define CONFIGURATION_SEARCH_PATH PSICONVETCDIR "/psiconv.conf:~/.psiconv.conf" |
41 | #endif |
42 | #endif |
42 | static struct psiconv_config_s default_config = |
43 | static struct psiconv_config_s default_config = |
43 | { PSICONV_VERB_WARN, 2, 0,0,0,psiconv_bool_false,NULL,'?' }; |
44 | { PSICONV_VERB_WARN, 2, 0,0,0,psiconv_bool_false,NULL,'?' }; |
44 | |
45 | |
45 | static void psiconv_config_parse_statement(const char *filename, |
46 | static void psiconv_config_parse_statement(const char *filename, |
… | |
… | |
70 | |
71 | |
71 | if (!(strcasecmp(var,"verbosity"))) { |
72 | if (!(strcasecmp(var,"verbosity"))) { |
72 | if ((value >= 1) && (value <= 4)) |
73 | if ((value >= 1) && (value <= 4)) |
73 | (*config)->verbosity = value; |
74 | (*config)->verbosity = value; |
74 | else |
75 | else |
75 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
76 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
76 | "Verbosity should be between 1 and 4",filename,linenr); |
77 | "Verbosity should be between 1 and 5",filename,linenr); |
77 | } else if (!(strcasecmp(var,"color"))) { |
78 | } else if (!(strcasecmp(var,"color"))) { |
78 | if ((value == 0) || (value == 1)) |
79 | if ((value == 0) || (value == 1)) |
79 | (*config)->color = value; |
80 | (*config)->color = value; |
80 | else |
81 | else |
81 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
82 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
82 | "Color should be 0 or 1",filename,linenr); |
83 | "Color should be 0 or 1",filename,linenr); |
83 | } else if (!(strcasecmp(var,"colordepth"))) { |
84 | } else if (!(strcasecmp(var,"colordepth"))) { |
84 | if ((value > 0) && (value <= 32)) |
85 | if ((value > 0) && (value <= 32)) |
85 | (*config)->colordepth = value; |
86 | (*config)->colordepth = value; |
86 | else |
87 | else |
87 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
88 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
88 | "ColorDepth should be between 1 and 32",filename,linenr); |
89 | "ColorDepth should be between 1 and 32",filename,linenr); |
89 | } else if (!(strcasecmp(var,"redbits"))) { |
90 | } else if (!(strcasecmp(var,"redbits"))) { |
90 | if ((value >= 0) && (value <= 32)) |
91 | if ((value >= 0) && (value <= 32)) |
91 | (*config)->redbits = value; |
92 | (*config)->redbits = value; |
92 | else |
93 | else |
93 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
94 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
94 | "RedBits should be between 1 and 32 or 0",filename,linenr); |
95 | "RedBits should be between 1 and 32 or 0",filename,linenr); |
95 | } else if (!(strcasecmp(var,"greenbits"))) { |
96 | } else if (!(strcasecmp(var,"greenbits"))) { |
96 | if ((value >= 0) && (value <= 32)) |
97 | if ((value >= 0) && (value <= 32)) |
97 | (*config)->greenbits = value; |
98 | (*config)->greenbits = value; |
98 | else |
99 | else |
99 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
100 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
100 | "GreenBits should be between 1 and 32 or 0",filename,linenr); |
101 | "GreenBits should be between 1 and 32 or 0",filename,linenr); |
101 | } else if (!(strcasecmp(var,"bluebits"))) { |
102 | } else if (!(strcasecmp(var,"bluebits"))) { |
102 | if ((value >= 0) && (value <= 32)) |
103 | if ((value >= 0) && (value <= 32)) |
103 | (*config)->bluebits = value; |
104 | (*config)->bluebits = value; |
104 | else |
105 | else |
105 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
106 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
106 | "BlueBits should be between 1 and 32 or 0",filename,linenr); |
107 | "BlueBits should be between 1 and 32 or 0",filename,linenr); |
107 | } else if (!(strcasecmp(var,"characterset"))) { |
108 | } else if (!(strcasecmp(var,"characterset"))) { |
108 | if ((value >= 0) && (value <= 0)) |
109 | if ((value >= 0) && (value <= 1)) |
109 | psiconv_unicode_select_characterset(*config,value); |
110 | psiconv_unicode_select_characterset(*config,value); |
110 | else |
111 | else |
111 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
112 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
112 | "CharacterSet should be between 0 and 0", |
113 | "CharacterSet should be between 0 and 0", |
113 | filename,linenr); |
114 | filename,linenr); |
114 | } else if (!(strcasecmp(var,"unknownunicodechar"))) { |
115 | } else if (!(strcasecmp(var,"unknownunicodechar"))) { |
115 | if ((value >= 1) && (value < 0x10000)) |
116 | if ((value >= 1) && (value < 0x10000)) |
116 | (*config)->unknown_unicode_char = value; |
117 | (*config)->unknown_unicode_char = value; |
117 | else |
118 | else |
118 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
119 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
119 | "UnknownUnicodeChar should be between 1 and 65535", |
120 | "UnknownUnicodeChar should be between 1 and 65535", |
120 | filename,linenr); |
121 | filename,linenr); |
121 | } else if (!(strcasecmp(var,"unknownepocchar"))) { |
122 | } else if (!(strcasecmp(var,"unknownepocchar"))) { |
122 | if ((value >= 1) && (value < 0x100)) |
123 | if ((value >= 1) && (value < 0x100)) |
123 | (*config)->unknown_epoc_char = value; |
124 | (*config)->unknown_epoc_char = value; |
124 | else |
125 | else |
125 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
126 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
126 | "UnknownEPOCChar should be between 1 and 255", |
127 | "UnknownEPOCChar should be between 1 and 255", |
127 | filename,linenr); |
128 | filename,linenr); |
128 | } else if (sscanf(var,"char%d",&charnr) == strlen(var)) { |
129 | } else if (sscanf(var,"char%d",&charnr) == strlen(var)) { |
129 | if ((charnr < 0) || (charnr > 255)) |
130 | if ((charnr < 0) || (charnr > 255)) |
130 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
131 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
131 | "CharXXX should have XXX between 0 and 255", |
132 | "CharXXX should have XXX between 0 and 255", |
132 | filename,linenr); |
133 | filename,linenr); |
133 | if ((value >= 1) && (value <= 0x10000)) |
134 | if ((value >= 1) && (value <= 0x10000)) |
134 | (*config)->unicode_table[charnr] = value; |
135 | (*config)->unicode_table[charnr] = value; |
135 | else |
136 | else |
136 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
137 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
137 | "CharXXX should be between 1 and 65535", |
138 | "CharXXX should be between 1 and 65535", |
138 | filename,linenr); |
139 | filename,linenr); |
139 | } else { |
140 | } else { |
140 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
141 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
141 | "Unknown variable %s",filename,linenr,var); |
142 | "Unknown variable %s",filename,linenr,var); |
142 | } |
143 | } |
143 | psiconv_debug(*config,0,0,"Configuration file %s, line %d: " |
144 | psiconv_debug(*config,0,0,"Configuration file %s, line %d: " |
144 | "Set variable %s to %d",filename,linenr,var,value); |
145 | "Set variable %s to %d",filename,linenr,var,value); |
145 | } |
146 | } |
… | |
… | |
161 | return; |
162 | return; |
162 | eovar = sovar; |
163 | eovar = sovar; |
163 | while (line[eovar] && (((line[eovar] >= 'A') && (line[eovar] <= 'Z')) || |
164 | while (line[eovar] && (((line[eovar] >= 'A') && (line[eovar] <= 'Z')) || |
164 | ((line[eovar] >= 'a') && (line[eovar] <= 'z')))) |
165 | ((line[eovar] >= 'a') && (line[eovar] <= 'z')))) |
165 | eovar ++; |
166 | eovar ++; |
166 | if (sovar == eovar) |
167 | if (sovar == eovar) { |
167 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
168 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
168 | "Syntax error (no variable found)",filename,linenr); |
169 | "Syntax error (no variable found)",filename,linenr); |
|
|
170 | return; |
|
|
171 | } |
169 | soval = eovar; |
172 | soval = eovar; |
170 | while (line[soval] && (line[soval] <= 32)) |
173 | while (line[soval] && (line[soval] <= 32)) |
171 | soval ++; |
174 | soval ++; |
172 | if (line[soval] != '=') |
175 | if (line[soval] != '=') { |
173 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
176 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
174 | "Syntax error (no = token found)",filename,linenr); |
177 | "Syntax error (no = token found)",filename,linenr); |
|
|
178 | return; |
|
|
179 | } |
175 | soval ++; |
180 | soval ++; |
176 | while (line[soval] && (line[soval] <= 32)) |
181 | while (line[soval] && (line[soval] <= 32)) |
177 | soval ++; |
182 | soval ++; |
178 | eoval = soval; |
183 | eoval = soval; |
179 | while (line[eoval] && ((line[eoval] >= '0') && (line[eovar] <= '9'))) |
184 | while (line[eoval] && ((line[eoval] >= '0') && (line[eovar] <= '9'))) |
180 | eoval ++; |
185 | eoval ++; |
181 | if (eoval == soval) |
186 | if (eoval == soval) { |
182 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
187 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
183 | "Syntax error (no value found)",filename,linenr); |
188 | "Syntax error (no value found)",filename,linenr); |
|
|
189 | return; |
|
|
190 | } |
184 | if (soval - eoval > 7) |
191 | if (soval - eoval > 7) { |
185 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
192 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
186 | "Syntax error (value too large)",filename,linenr); |
193 | "Syntax error (value too large)",filename,linenr); |
|
|
194 | return; |
|
|
195 | } |
187 | eol = eoval; |
196 | eol = eoval; |
188 | while (line[eol] && (line[eol] < 32)) |
197 | while (line[eol] && (line[eol] < 32)) |
189 | eol ++; |
198 | eol ++; |
190 | if (line[eol]) |
199 | if (line[eol]) { |
191 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
200 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
192 | "Syntax error (trailing garbage)",filename,linenr); |
201 | "Syntax error (trailing garbage)",filename,linenr); |
|
|
202 | return; |
|
|
203 | } |
193 | |
204 | |
194 | var = malloc(eovar - sovar + 1); |
205 | var = malloc(eovar - sovar + 1); |
195 | memcpy(var,line + sovar, eovar - sovar); |
206 | memcpy(var,line + sovar, eovar - sovar); |
196 | var[eovar-sovar] = 0; |
207 | var[eovar-sovar] = 0; |
197 | |
208 | |
… | |
… | |
212 | psiconv_progress(*config,0,0, |
223 | psiconv_progress(*config,0,0, |
213 | "Going to access configuration file %s",filename); |
224 | "Going to access configuration file %s",filename); |
214 | |
225 | |
215 | /* Try to open the file; it may fail, if it does not exist for example */ |
226 | /* Try to open the file; it may fail, if it does not exist for example */ |
216 | if ((file = open(filename,O_RDONLY)) == -1) |
227 | if ((file = open(filename,O_RDONLY)) == -1) |
217 | return; |
228 | goto ERROR0; |
218 | |
229 | |
219 | /* Read the contents of the file into filebuffer. This may fail */ |
230 | /* Read the contents of the file into filebuffer. This may fail */ |
220 | if (fstat(file,&stat_buf)) { |
231 | if (fstat(file,&stat_buf)) { |
221 | if (close(file)) |
232 | if (close(file)) |
222 | psiconv_fatal(*config,0,0,"Configuration file %s: " |
233 | psiconv_error(*config,0,0,"Configuration file %s: " |
223 | "Couldn't close file",filename); |
234 | "Couldn't close file",filename); |
224 | return; |
235 | return; |
225 | } |
236 | } |
226 | |
237 | |
227 | filesize = stat_buf.st_size; |
238 | filesize = stat_buf.st_size; |
228 | if (!(filebuffer = malloc(filesize + 1))) |
239 | if (!(filebuffer = malloc(filesize + 1))) { |
229 | psiconv_fatal(*config,0,0,"Configuration file %s: " |
240 | psiconv_error(*config,0,0,"Configuration file %s: " |
230 | "Out of memory error",filename); |
241 | "Out of memory error",filename); |
|
|
242 | goto ERROR1; |
|
|
243 | } |
|
|
244 | |
231 | filebuffer_ptr = filebuffer; |
245 | filebuffer_ptr = filebuffer; |
232 | bytes_left = filesize; |
246 | bytes_left = filesize; |
233 | bytes_read = 1; /* Dummy for the first time through the loop */ |
247 | bytes_read = 1; /* Dummy for the first time through the loop */ |
234 | while ((bytes_read > 0) && bytes_left) { |
248 | while ((bytes_read > 0) && bytes_left) { |
235 | bytes_read = read(file,filebuffer_ptr,bytes_left); |
249 | bytes_read = read(file,filebuffer_ptr,bytes_left); |
… | |
… | |
239 | } |
253 | } |
240 | } |
254 | } |
241 | |
255 | |
242 | /* On NFS, the first read may fail and this is not fatal */ |
256 | /* On NFS, the first read may fail and this is not fatal */ |
243 | if (bytes_left && (bytes_left != filesize)) { |
257 | if (bytes_left && (bytes_left != filesize)) { |
244 | psiconv_fatal(*config,0,0,"Configuration file %s: " |
258 | psiconv_error(*config,0,0,"Configuration file %s: " |
245 | "Couldn't read file into memory",filename); |
259 | "Couldn't read file into memory",filename); |
|
|
260 | goto ERROR2; |
246 | } |
261 | } |
247 | |
262 | |
248 | if (close(file)) |
263 | if (close(file)) { |
249 | psiconv_fatal(*config,0,0,"Configuration file %s: " |
264 | psiconv_error(*config,0,0,"Configuration file %s: " |
250 | "Couldn't close file",filename); |
265 | "Couldn't close file",filename); |
|
|
266 | file = -1; |
|
|
267 | goto ERROR2; |
|
|
268 | } |
|
|
269 | file = -1; |
251 | |
270 | |
252 | psiconv_progress(*config,0,0, |
271 | psiconv_progress(*config,0,0, |
253 | "Going to parse configuration file %s: ",filename); |
272 | "Going to parse configuration file %s: ",filename); |
254 | /* Now we walk through the file to isolate lines */ |
273 | /* Now we walk through the file to isolate lines */ |
255 | linenr = 0; |
274 | linenr = 0; |
… | |
… | |
260 | eol = sol; |
279 | eol = sol; |
261 | while ((eol < filesize) && (filebuffer[eol] != 13) && |
280 | while ((eol < filesize) && (filebuffer[eol] != 13) && |
262 | (filebuffer[eol] != 10) && (filebuffer[eol] != 0)) |
281 | (filebuffer[eol] != 10) && (filebuffer[eol] != 0)) |
263 | eol ++; |
282 | eol ++; |
264 | |
283 | |
265 | if ((eol < filesize) && (filebuffer[eol] == 0)) |
284 | if ((eol < filesize) && (filebuffer[eol] == 0)) { |
266 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
285 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
267 | "Unexpected character \000 found",filename,linenr); |
286 | "Unexpected character \000 found",filename,linenr); |
|
|
287 | goto ERROR2; |
|
|
288 | } |
268 | if ((eol < filesize + 1) && |
289 | if ((eol < filesize + 1) && |
269 | (((filebuffer[eol] == 13) && (filebuffer[eol+1] == 10)) || |
290 | (((filebuffer[eol] == 13) && (filebuffer[eol+1] == 10)) || |
270 | ((filebuffer[eol] == 10) && (filebuffer[eol+1] == 13)))) { |
291 | ((filebuffer[eol] == 10) && (filebuffer[eol+1] == 13)))) { |
271 | filebuffer[eol] = 0; |
292 | filebuffer[eol] = 0; |
272 | eol ++; |
293 | eol ++; |
… | |
… | |
274 | filebuffer[eol] = 0; |
295 | filebuffer[eol] = 0; |
275 | psiconv_config_parse_line(filename,linenr,filebuffer + sol,config); |
296 | psiconv_config_parse_line(filename,linenr,filebuffer + sol,config); |
276 | sol = eol+1; |
297 | sol = eol+1; |
277 | } |
298 | } |
278 | free(filebuffer); |
299 | free(filebuffer); |
|
|
300 | return; |
|
|
301 | |
|
|
302 | ERROR2: |
|
|
303 | free(filebuffer); |
|
|
304 | ERROR1: |
|
|
305 | if ((file != -1) && close(file)) |
|
|
306 | psiconv_error(*config,0,0,"Configuration file %s: " |
|
|
307 | "Couldn't close file",filename); |
|
|
308 | ERROR0: |
|
|
309 | return; |
279 | } |
310 | } |
280 | |
311 | |
281 | void psiconv_config_read(const char *extra_config_files, |
312 | void psiconv_config_read(const char *extra_config_files, |
282 | psiconv_config *config) |
313 | psiconv_config *config) |
283 | { |
314 | { |