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