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