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 | |
24 | |
24 | #include <stdio.h> |
25 | #include <stdio.h> |
25 | #include <stdlib.h> |
26 | #include <stdlib.h> |
26 | #include <string.h> |
27 | #include <string.h> |
|
|
28 | #include <strings.h> |
27 | #include <sys/types.h> |
29 | #include <sys/types.h> |
28 | #include <sys/stat.h> |
30 | #include <sys/stat.h> |
29 | #include <unistd.h> |
31 | #include <unistd.h> |
30 | #include <fcntl.h> |
32 | #include <fcntl.h> |
31 | |
33 | |
… | |
… | |
34 | #ifdef DMALLOC |
36 | #ifdef DMALLOC |
35 | #include <dmalloc.h> |
37 | #include <dmalloc.h> |
36 | #endif |
38 | #endif |
37 | |
39 | |
38 | #ifndef CONFIGURATION_SEARCH_PATH |
40 | #ifndef CONFIGURATION_SEARCH_PATH |
39 | #define CONFIGURATION_SEARCH_PATH "/etc/psiconv.conf:~/.psiconv.conf" |
41 | #define CONFIGURATION_SEARCH_PATH PSICONVETCDIR "/psiconv.conf:~/.psiconv.conf" |
40 | #endif |
42 | #endif |
41 | static struct psiconv_config_s default_config = |
43 | static struct psiconv_config_s default_config = |
42 | { PSICONV_VERB_WARN, 2, 0,0,0,psiconv_bool_false,NULL }; |
44 | { PSICONV_VERB_WARN, 2, 0,0,0,psiconv_bool_false,NULL,'?' }; |
43 | |
45 | |
44 | static void psiconv_config_parse_statement(const char *filename, |
46 | static void psiconv_config_parse_statement(const char *filename, |
45 | int linenr, |
47 | int linenr, |
46 | const char *var, int value, |
48 | const char *var, int value, |
47 | psiconv_config *config); |
49 | psiconv_config *config); |
… | |
… | |
58 | result = malloc(sizeof(*result)); |
60 | result = malloc(sizeof(*result)); |
59 | *result = default_config; |
61 | *result = default_config; |
60 | return result; |
62 | return result; |
61 | } |
63 | } |
62 | |
64 | |
|
|
65 | void psiconv_config_free(psiconv_config config) |
|
|
66 | { |
|
|
67 | free(config); |
|
|
68 | } |
|
|
69 | |
63 | void psiconv_config_parse_statement(const char *filename, |
70 | void psiconv_config_parse_statement(const char *filename, |
64 | int linenr, |
71 | int linenr, |
65 | const char *var, int value, |
72 | const char *var, int value, |
66 | psiconv_config *config) |
73 | psiconv_config *config) |
67 | { |
74 | { |
|
|
75 | int charnr; |
|
|
76 | |
68 | if (!(strcasecmp(var,"verbosity"))) { |
77 | if (!(strcasecmp(var,"verbosity"))) { |
69 | if ((value >= 1) && (value <= 4)) |
78 | if ((value >= 1) && (value <= 4)) |
70 | (*config)->verbosity = value; |
79 | (*config)->verbosity = value; |
71 | else |
80 | else |
72 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
81 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
73 | "Verbosity should be between 1 and 4",filename,linenr); |
82 | "Verbosity should be between 1 and 5",filename,linenr); |
74 | } else if (!(strcasecmp(var,"color"))) { |
83 | } else if (!(strcasecmp(var,"color"))) { |
75 | if ((value == 0) || (value == 1)) |
84 | if ((value == 0) || (value == 1)) |
76 | (*config)->color = value; |
85 | (*config)->color = value; |
77 | else |
86 | else |
78 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
87 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
79 | "Color should be 0 or 1",filename,linenr); |
88 | "Color should be 0 or 1",filename,linenr); |
80 | } else if (!(strcasecmp(var,"colordepth"))) { |
89 | } else if (!(strcasecmp(var,"colordepth"))) { |
81 | if ((value > 0) && (value <= 32)) |
90 | if ((value > 0) && (value <= 32)) |
82 | (*config)->colordepth = value; |
91 | (*config)->colordepth = value; |
83 | else |
92 | else |
84 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
93 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
85 | "ColorDepth should be between 1 and 32",filename,linenr); |
94 | "ColorDepth should be between 1 and 32",filename,linenr); |
86 | } else if (!(strcasecmp(var,"redbits"))) { |
95 | } else if (!(strcasecmp(var,"redbits"))) { |
87 | if ((value >= 0) && (value <= 32)) |
96 | if ((value >= 0) && (value <= 32)) |
88 | (*config)->redbits = value; |
97 | (*config)->redbits = value; |
89 | else |
98 | else |
90 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
99 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
91 | "RedBits should be between 1 and 32 or 0",filename,linenr); |
100 | "RedBits should be between 1 and 32 or 0",filename,linenr); |
92 | } else if (!(strcasecmp(var,"greenbits"))) { |
101 | } else if (!(strcasecmp(var,"greenbits"))) { |
93 | if ((value >= 0) && (value <= 32)) |
102 | if ((value >= 0) && (value <= 32)) |
94 | (*config)->greenbits = value; |
103 | (*config)->greenbits = value; |
95 | else |
104 | else |
96 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
105 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
97 | "GreenBits should be between 1 and 32 or 0",filename,linenr); |
106 | "GreenBits should be between 1 and 32 or 0",filename,linenr); |
98 | } else if (!(strcasecmp(var,"bluebits"))) { |
107 | } else if (!(strcasecmp(var,"bluebits"))) { |
99 | if ((value >= 0) && (value <= 32)) |
108 | if ((value >= 0) && (value <= 32)) |
100 | (*config)->bluebits = value; |
109 | (*config)->bluebits = value; |
101 | else |
110 | else |
102 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
111 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
103 | "BlueBits should be between 1 and 32 or 0",filename,linenr); |
112 | "BlueBits should be between 1 and 32 or 0",filename,linenr); |
|
|
113 | } else if (!(strcasecmp(var,"characterset"))) { |
|
|
114 | if ((value >= 0) && (value <= 1)) |
|
|
115 | psiconv_unicode_select_characterset(*config,value); |
|
|
116 | else |
|
|
117 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
|
|
118 | "CharacterSet should be between 0 and 0", |
|
|
119 | filename,linenr); |
|
|
120 | } else if (!(strcasecmp(var,"unknownunicodechar"))) { |
|
|
121 | if ((value >= 1) && (value < 0x10000)) |
|
|
122 | (*config)->unknown_unicode_char = value; |
|
|
123 | else |
|
|
124 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
|
|
125 | "UnknownUnicodeChar should be between 1 and 65535", |
|
|
126 | filename,linenr); |
|
|
127 | } else if (!(strcasecmp(var,"unknownepocchar"))) { |
|
|
128 | if ((value >= 1) && (value < 0x100)) |
|
|
129 | (*config)->unknown_epoc_char = value; |
|
|
130 | else |
|
|
131 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
|
|
132 | "UnknownEPOCChar should be between 1 and 255", |
|
|
133 | filename,linenr); |
|
|
134 | } else if (sscanf(var,"char%d",&charnr) == strlen(var)) { |
|
|
135 | if ((charnr < 0) || (charnr > 255)) |
|
|
136 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
|
|
137 | "CharXXX should have XXX between 0 and 255", |
|
|
138 | filename,linenr); |
|
|
139 | if ((value >= 1) && (value <= 0x10000)) |
|
|
140 | (*config)->unicode_table[charnr] = value; |
|
|
141 | else |
|
|
142 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
|
|
143 | "CharXXX should be between 1 and 65535", |
|
|
144 | filename,linenr); |
104 | } else { |
145 | } else { |
105 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
146 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
106 | "Unknown variable %s",filename,linenr,var); |
147 | "Unknown variable %s",filename,linenr,var); |
107 | } |
148 | } |
108 | psiconv_debug(*config,0,0,"Configuration file %s, line %d: " |
149 | psiconv_debug(*config,0,0,"Configuration file %s, line %d: " |
109 | "Set variable %s to %d",filename,linenr,var,value); |
150 | "Set variable %s to %d",filename,linenr,var,value); |
110 | } |
151 | } |
… | |
… | |
126 | return; |
167 | return; |
127 | eovar = sovar; |
168 | eovar = sovar; |
128 | while (line[eovar] && (((line[eovar] >= 'A') && (line[eovar] <= 'Z')) || |
169 | while (line[eovar] && (((line[eovar] >= 'A') && (line[eovar] <= 'Z')) || |
129 | ((line[eovar] >= 'a') && (line[eovar] <= 'z')))) |
170 | ((line[eovar] >= 'a') && (line[eovar] <= 'z')))) |
130 | eovar ++; |
171 | eovar ++; |
131 | if (sovar == eovar) |
172 | if (sovar == eovar) { |
132 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
173 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
133 | "Syntax error (no variable found)",filename,linenr); |
174 | "Syntax error (no variable found)",filename,linenr); |
|
|
175 | return; |
|
|
176 | } |
134 | soval = eovar; |
177 | soval = eovar; |
135 | while (line[soval] && (line[soval] <= 32)) |
178 | while (line[soval] && (line[soval] <= 32)) |
136 | soval ++; |
179 | soval ++; |
137 | if (line[soval] != '=') |
180 | if (line[soval] != '=') { |
138 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
181 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
139 | "Syntax error (no = token found)",filename,linenr); |
182 | "Syntax error (no = token found)",filename,linenr); |
|
|
183 | return; |
|
|
184 | } |
140 | soval ++; |
185 | soval ++; |
141 | while (line[soval] && (line[soval] <= 32)) |
186 | while (line[soval] && (line[soval] <= 32)) |
142 | soval ++; |
187 | soval ++; |
143 | eoval = soval; |
188 | eoval = soval; |
144 | while (line[eoval] && ((line[eoval] >= '0') && (line[eovar] <= '9'))) |
189 | while (line[eoval] && ((line[eoval] >= '0') && (line[eovar] <= '9'))) |
145 | eoval ++; |
190 | eoval ++; |
146 | if (eoval == soval) |
191 | if (eoval == soval) { |
147 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
192 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
148 | "Syntax error (no value found)",filename,linenr); |
193 | "Syntax error (no value found)",filename,linenr); |
|
|
194 | return; |
|
|
195 | } |
149 | if (soval - eoval > 7) |
196 | if (soval - eoval > 7) { |
150 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
197 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
151 | "Syntax error (value too large)",filename,linenr); |
198 | "Syntax error (value too large)",filename,linenr); |
|
|
199 | return; |
|
|
200 | } |
152 | eol = eoval; |
201 | eol = eoval; |
153 | while (line[eol] && (line[eol] < 32)) |
202 | while (line[eol] && (line[eol] < 32)) |
154 | eol ++; |
203 | eol ++; |
155 | if (line[eol]) |
204 | if (line[eol]) { |
156 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
205 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
157 | "Syntax error (trailing garbage)",filename,linenr); |
206 | "Syntax error (trailing garbage)",filename,linenr); |
|
|
207 | return; |
|
|
208 | } |
158 | |
209 | |
159 | var = malloc(eovar - sovar + 1); |
210 | var = malloc(eovar - sovar + 1); |
160 | memcpy(var,line + sovar, eovar - sovar); |
211 | memcpy(var,line + sovar, eovar - sovar); |
161 | var[eovar-sovar] = 0; |
212 | var[eovar-sovar] = 0; |
162 | |
213 | |
… | |
… | |
177 | psiconv_progress(*config,0,0, |
228 | psiconv_progress(*config,0,0, |
178 | "Going to access configuration file %s",filename); |
229 | "Going to access configuration file %s",filename); |
179 | |
230 | |
180 | /* Try to open the file; it may fail, if it does not exist for example */ |
231 | /* Try to open the file; it may fail, if it does not exist for example */ |
181 | if ((file = open(filename,O_RDONLY)) == -1) |
232 | if ((file = open(filename,O_RDONLY)) == -1) |
182 | return; |
233 | goto ERROR0; |
183 | |
234 | |
184 | /* Read the contents of the file into filebuffer. This may fail */ |
235 | /* Read the contents of the file into filebuffer. This may fail */ |
185 | if (fstat(file,&stat_buf)) { |
236 | if (fstat(file,&stat_buf)) { |
186 | if (close(file)) |
237 | if (close(file)) |
187 | psiconv_fatal(*config,0,0,"Configuration file %s: " |
238 | psiconv_error(*config,0,0,"Configuration file %s: " |
188 | "Couldn't close file",filename); |
239 | "Couldn't close file",filename); |
189 | return; |
240 | return; |
190 | } |
241 | } |
191 | |
242 | |
192 | filesize = stat_buf.st_size; |
243 | filesize = stat_buf.st_size; |
193 | if (!(filebuffer = malloc(filesize + 1))) |
244 | if (!(filebuffer = malloc(filesize + 1))) { |
194 | psiconv_fatal(*config,0,0,"Configuration file %s: " |
245 | psiconv_error(*config,0,0,"Configuration file %s: " |
195 | "Out of memory error",filename); |
246 | "Out of memory error",filename); |
|
|
247 | goto ERROR1; |
|
|
248 | } |
|
|
249 | |
196 | filebuffer_ptr = filebuffer; |
250 | filebuffer_ptr = filebuffer; |
197 | bytes_left = filesize; |
251 | bytes_left = filesize; |
198 | bytes_read = 1; /* Dummy for the first time through the loop */ |
252 | bytes_read = 1; /* Dummy for the first time through the loop */ |
199 | while ((bytes_read > 0) && bytes_left) { |
253 | while ((bytes_read > 0) && bytes_left) { |
200 | bytes_read = read(file,filebuffer_ptr,bytes_left); |
254 | bytes_read = read(file,filebuffer_ptr,bytes_left); |
… | |
… | |
204 | } |
258 | } |
205 | } |
259 | } |
206 | |
260 | |
207 | /* On NFS, the first read may fail and this is not fatal */ |
261 | /* On NFS, the first read may fail and this is not fatal */ |
208 | if (bytes_left && (bytes_left != filesize)) { |
262 | if (bytes_left && (bytes_left != filesize)) { |
209 | psiconv_fatal(*config,0,0,"Configuration file %s: " |
263 | psiconv_error(*config,0,0,"Configuration file %s: " |
210 | "Couldn't read file into memory",filename); |
264 | "Couldn't read file into memory",filename); |
|
|
265 | goto ERROR2; |
211 | } |
266 | } |
212 | |
267 | |
213 | if (close(file)) |
268 | if (close(file)) { |
214 | psiconv_fatal(*config,0,0,"Configuration file %s: " |
269 | psiconv_error(*config,0,0,"Configuration file %s: " |
215 | "Couldn't close file",filename); |
270 | "Couldn't close file",filename); |
|
|
271 | file = -1; |
|
|
272 | goto ERROR2; |
|
|
273 | } |
|
|
274 | file = -1; |
216 | |
275 | |
217 | psiconv_progress(*config,0,0, |
276 | psiconv_progress(*config,0,0, |
218 | "Going to parse configuration file %s: ",filename); |
277 | "Going to parse configuration file %s: ",filename); |
219 | /* Now we walk through the file to isolate lines */ |
278 | /* Now we walk through the file to isolate lines */ |
220 | linenr = 0; |
279 | linenr = 0; |
… | |
… | |
225 | eol = sol; |
284 | eol = sol; |
226 | while ((eol < filesize) && (filebuffer[eol] != 13) && |
285 | while ((eol < filesize) && (filebuffer[eol] != 13) && |
227 | (filebuffer[eol] != 10) && (filebuffer[eol] != 0)) |
286 | (filebuffer[eol] != 10) && (filebuffer[eol] != 0)) |
228 | eol ++; |
287 | eol ++; |
229 | |
288 | |
230 | if ((eol < filesize) && (filebuffer[eol] == 0)) |
289 | if ((eol < filesize) && (filebuffer[eol] == 0)) { |
231 | psiconv_fatal(*config,0,0,"Configuration file %s, line %d: " |
290 | psiconv_error(*config,0,0,"Configuration file %s, line %d: " |
232 | "Unexpected character \000 found",filename,linenr); |
291 | "Unexpected character \000 found",filename,linenr); |
|
|
292 | goto ERROR2; |
|
|
293 | } |
233 | if ((eol < filesize + 1) && |
294 | if ((eol < filesize + 1) && |
234 | (((filebuffer[eol] == 13) && (filebuffer[eol+1] == 10)) || |
295 | (((filebuffer[eol] == 13) && (filebuffer[eol+1] == 10)) || |
235 | ((filebuffer[eol] == 10) && (filebuffer[eol+1] == 13)))) { |
296 | ((filebuffer[eol] == 10) && (filebuffer[eol+1] == 13)))) { |
236 | filebuffer[eol] = 0; |
297 | filebuffer[eol] = 0; |
237 | eol ++; |
298 | eol ++; |
… | |
… | |
239 | filebuffer[eol] = 0; |
300 | filebuffer[eol] = 0; |
240 | psiconv_config_parse_line(filename,linenr,filebuffer + sol,config); |
301 | psiconv_config_parse_line(filename,linenr,filebuffer + sol,config); |
241 | sol = eol+1; |
302 | sol = eol+1; |
242 | } |
303 | } |
243 | free(filebuffer); |
304 | free(filebuffer); |
|
|
305 | return; |
|
|
306 | |
|
|
307 | ERROR2: |
|
|
308 | free(filebuffer); |
|
|
309 | ERROR1: |
|
|
310 | if ((file != -1) && close(file)) |
|
|
311 | psiconv_error(*config,0,0,"Configuration file %s: " |
|
|
312 | "Couldn't close file",filename); |
|
|
313 | ERROR0: |
|
|
314 | return; |
244 | } |
315 | } |
245 | |
316 | |
246 | void psiconv_config_read(const char *extra_config_files, |
317 | void psiconv_config_read(const char *extra_config_files, |
247 | psiconv_config *config) |
318 | psiconv_config *config) |
248 | { |
319 | { |
… | |
… | |
286 | } |
357 | } |
287 | |
358 | |
288 | psiconv_config_parse_file(filename,config); |
359 | psiconv_config_parse_file(filename,config); |
289 | free(filename); |
360 | free(filename); |
290 | } |
361 | } |
|
|
362 | free(path); |
291 | } |
363 | } |