General formatting clean-up.
[xiph/unicode.git] / vorbis-tools / ogg123 / cfgfile_options.c
blob4b5db39e782b177d6a86ea15e9ab8d93ac70e939
1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
5 * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
6 * PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2001 *
9 * by Stan Seibert <volsung@xiph.org> AND OTHER CONTRIBUTORS *
10 * http://www.xiph.org/ *
11 * *
12 ********************************************************************
14 last mod: $Id: cfgfile_options.c,v 1.3 2002/01/26 11:06:37 segher Exp $
16 ********************************************************************/
19 /* if strcasecmp is giving you problems, switch to strcmp or the appropriate
20 * function for your platform / compiler.
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <limits.h> /* for LONG_MAX / LONG_MIN */
31 #include <errno.h>
33 #include "cfgfile_options.h"
34 #include "status.h"
35 #include "i18n.h"
37 /* ------------------- Private Functions ---------------------- */
39 int print_space (FILE *f, int s, int c)
41 int tmp = 0;
42 do {
43 fputc (c, f);
44 tmp++;
45 } while (--s > 0);
46 return tmp;
50 int parse_error (parse_code_t pcode, int lineno, const char *filename,
51 char *line)
53 if (pcode == parse_syserr) {
54 if (errno != EEXIST && errno != ENOENT)
55 perror (_("System error"));
56 return -1;
57 } else {
58 status_error (_("=== Parse error: %s on line %d of %s (%s)\n"),
59 parse_error_string(pcode),
60 lineno, filename, line);
61 return 0;
66 /* ------------------- Public Interface ----------------------- */
68 void file_options_init (file_option_t opts[])
71 while (opts && opts->name) {
73 opts->found = 0;
75 if (opts->dfl) {
76 switch (opts->type) {
77 case opt_type_none:
78 /* do nothing */
79 break;
81 case opt_type_char:
82 *(char *) opts->ptr = *(char*) opts->dfl;
83 break;
85 case opt_type_string:
86 *(char **) opts->ptr = *(char **) opts->dfl;
87 break;
89 case opt_type_bool:
90 case opt_type_int:
91 *(long int *) opts->ptr = *(int *) opts->dfl;
92 break;
94 case opt_type_float:
95 *(float *) opts->ptr = *(float *) opts->dfl;
96 break;
98 case opt_type_double:
99 *(double *) opts->ptr = *(double *) opts->dfl;
100 break;
104 opts++;
109 /* DescribeOptions - describe available options to outfile */
110 void file_options_describe (file_option_t opts[], FILE *f)
112 /* name | description | type | default */
113 int colWidths[] = {0, 0, 7, 7};
114 int totalWidth = 0;
115 file_option_t *opt = opts;
117 while (opt->name) {
118 int len = strlen (opt->name) + 1;
119 if (len > colWidths[0])
120 colWidths[0] = len;
121 opt++;
124 opt = opts;
125 while (opt->name) {
126 int len = strlen (opt->desc) + 1;
127 if (len > colWidths[1])
128 colWidths[1] = len;
129 opt++;
132 /* Column headers */
133 /* Name */
134 totalWidth += fprintf (f, "%-*s", colWidths[0], _("Name"));
136 /* Description */
137 totalWidth += fprintf (f, "%-*s", colWidths[1], _("Description"));
139 /* Type */
140 totalWidth += fprintf (f, "%-*s", colWidths[2], _("Type"));
142 /* Default */
143 totalWidth += fprintf (f, "%-*s", colWidths[3], _("Default"));
145 fputc ('\n', f);
147 /* Divider */
148 print_space (f, totalWidth, '-');
150 fputc ('\n', f);
152 opt = opts;
153 while (opt->name)
155 /* name */
156 int w = colWidths[0];
157 w -= fprintf (f, "%s", opt->name);
158 print_space (f, w, ' ');
160 /* description */
161 w = colWidths[1];
162 w -= fprintf (f, "%s", opt->desc);
163 print_space (f, w, ' ');
165 /* type */
166 w = colWidths[2];
167 switch (opt->type) {
168 case opt_type_none:
169 w -= fprintf (f, _("none"));
170 break;
171 case opt_type_bool:
172 w -= fprintf (f, _("bool"));
173 break;
174 case opt_type_char:
175 w -= fprintf (f, _("char"));
176 break;
177 case opt_type_string:
178 w -= fprintf (f, _("string"));
179 break;
180 case opt_type_int:
181 w -= fprintf (f, _("int"));
182 break;
183 case opt_type_float:
184 w -= fprintf (f, _("float"));
185 break;
186 case opt_type_double:
187 w -= fprintf (f, _("double"));
188 break;
189 default:
190 w -= fprintf (f, _("other"));
192 print_space (f, w, ' ');
194 /* default */
195 if (opt->dfl == NULL)
196 fputs (_("(NULL)"), f);
197 else {
198 switch (opt->type) {
199 case opt_type_none:
200 fputs (_("(none)"), f);
201 break;
202 case opt_type_char:
203 fputc (*(char *) opt->dfl, f);
204 break;
205 case opt_type_string:
206 fputs (*(char **) opt->dfl, f);
207 break;
208 case opt_type_bool:
209 case opt_type_int:
210 fprintf (f, "%ld", *(long int *) opt->dfl);
211 break;
212 case opt_type_float:
213 fprintf (f, "%f", (double) (*(float *) opt->dfl));
214 break;
215 case opt_type_double:
216 fprintf (f, "%f", *(double *) opt->dfl);
217 break;
220 fputc ('\n', f);
221 opt++;
226 parse_code_t parse_line (file_option_t opts[], char *line)
228 char *equals, *value = "";
229 file_option_t *opt;
230 int len;
232 /* skip leading whitespace */
233 while (line[0] == ' ')
234 line++;
236 /* remove comments */
237 equals = strchr (line, '#');
238 if (equals)
239 *equals = '\0';
241 /* return if only whitespace on line */
242 if (!line[0] || line[0] == '#')
243 return parse_ok;
245 /* check for an '=' and set to \0 */
246 equals = strchr (line, '=');
247 if (equals) {
248 value = equals + 1;
249 *equals = '\0';
252 /* cut trailing whitespace from key (line = key now) */
253 while ((equals = strrchr(line, ' ')))
254 *equals = '\0';
256 /* remove this if you want a zero-length key */
257 if (strlen(line) == 0)
258 return parse_nokey;
260 if (value) {
261 /* cut leading whitespace from value */
262 while (*value == ' ')
263 value++;
265 /* cut trailing whitespace from value */
266 len = strlen (value);
267 while (len > 0 && value[len-1] == ' ') {
268 len--;
269 value[len] = '\0';
273 /* now key is in line and value is in value. Search for a matching option. */
274 opt = opts;
275 while (opt->name) {
276 if (!strcasecmp (opt->name, line)) {
277 long tmpl;
278 char *endptr;
280 /* found the key. now set the value. */
281 switch (opt->type) {
282 case opt_type_none:
283 if (value != NULL || strlen(value) > 0)
284 return parse_badvalue;
285 opt->found++;
286 break;
288 case opt_type_bool:
289 if (!value || *value == '\0')
290 return parse_badvalue;
292 /* Maybe this is a numeric bool */
293 tmpl = strtol (value, &endptr, 0);
295 if ( strncasecmp(value, "y", 1) == 0
296 || strcasecmp(value, "true")
297 || (*endptr == '\0' && tmpl) )
298 *(long int *) opt->ptr = 1;
299 else if ( strncasecmp(value, "n", 1) == 0
300 || strcasecmp(value, "false")
301 || (*endptr == '\0' && !tmpl) )
302 *(long int *) opt->ptr = 0;
303 else
304 return parse_badvalue;
305 break;
307 case opt_type_char:
308 if (strlen(value) != 1)
309 return parse_badvalue;
310 opt->found++;
311 *(char *) opt->ptr = value[0];
312 break;
314 case opt_type_string:
315 opt->found++;
316 if (*(char **)opt->ptr) free(*(char **)opt->ptr);
317 *(char **) opt->ptr = strdup (value);
318 break;
320 case opt_type_int:
321 if (!value || *value == '\0')
322 return parse_badvalue;
323 tmpl = strtol (value, &endptr, 0);
324 if (((tmpl == LONG_MIN || tmpl == LONG_MAX) && errno == ERANGE)
325 || (*endptr != '\0'))
326 return parse_badvalue;
327 opt->found++;
328 *(long int *) opt->ptr = tmpl;
329 break;
331 case opt_type_float:
332 if (!value || *value == '\0')
333 return parse_badvalue;
334 opt->found++;
335 *(float *) opt->ptr = atof (value);
336 break;
338 case opt_type_double:
339 if (!value || *value == '\0')
340 return parse_badvalue;
341 opt->found++;
342 *(double *) opt->ptr = atof (value);
343 break;
345 default:
346 return parse_badtype;
348 return parse_ok;
350 opt++;
352 return parse_keynotfound;
356 parse_code_t parse_config_file (file_option_t opts[], const char *filename)
358 unsigned int len=80;
359 char *line = malloc(len);
360 int readoffset, thischar, lineno;
361 FILE *file;
362 parse_code_t pcode;
363 char empty[] = "";
365 if (!line) {
366 parse_error(parse_syserr, 0, empty, empty);
367 return parse_syserr;
370 file = fopen (filename, "r");
371 if (!file) {
372 parse_error (parse_syserr, 0, empty, empty);
373 free (line);
374 return parse_syserr;
377 lineno = 0;
378 while (!feof (file)) {
380 lineno++;
381 readoffset = 0;
382 memset (line, 0, len);
384 while ((thischar = fgetc(file)) != EOF) {
386 if (readoffset + 1 > len) {
387 len *= 2;
388 line = realloc (line, len);
389 if (!line)
391 parse_error(parse_syserr, 0, empty, empty);
392 fclose (file);
393 return parse_syserr;
397 if (thischar == '\n') {
398 line[readoffset] = '\0';
399 break;
401 else
402 line[readoffset] = (unsigned char) thischar;
403 readoffset++;
407 pcode = parse_line (opts, line);
409 if (pcode != parse_ok)
410 if (!parse_error(pcode, lineno, filename, line)) {
411 free (line);
412 return pcode;
417 free (line);
418 return parse_ok;
421 /* ParseErr - returns a string corresponding to parse code pcode */
422 const char *parse_error_string (parse_code_t pcode)
424 switch (pcode) {
425 case parse_ok:
426 return _("Success");
427 case parse_syserr:
428 return strerror(errno);
429 case parse_keynotfound:
430 return _("Key not found");
431 case parse_nokey:
432 return _("No key");
433 case parse_badvalue:
434 return _("Bad value");
435 case parse_badtype:
436 return _("Bad type in options list");
437 default:
438 return _("Unknown error");
443 void parse_std_configs (file_option_t opts[])
445 char filename[FILENAME_MAX];
446 char *homedir = getenv("HOME");
448 parse_config_file(opts, "/etc/ogg123rc");
449 if (homedir && strlen(homedir) < FILENAME_MAX - 10) {
450 /* Try ~/.ogg123 */
451 strncpy(filename, homedir, FILENAME_MAX);
452 strcat(filename, "/.ogg123rc");
453 parse_config_file(opts, filename);