1 /* configfile.c: parsing of config files
2  *
3  * Copyright (C) 2017-2018 Nikola Kolev <koue@chaosophia.net>
4  * Copyright (C) 2008 Lars Hjemli
5  *
6  * Licensed under GNU General Public License v2
7  *   (see COPYING for full license text)
8  */
9 
10 #include <errno.h>
11 #include <stdio.h>
12 #include <string.h>
13 
14 #include "cez_config.h"
15 
next_char(FILE * f)16 static int next_char(FILE *f)
17 {
18 	int c = fgetc(f);
19 	if (c=='\r') {
20 		c = fgetc(f);
21 		if (c!='\n') {
22 			ungetc(c, f);
23 			c = '\r';
24 		}
25 	}
26 	return (c);
27 }
28 
skip_line(FILE * f)29 static void skip_line(FILE *f)
30 {
31 	int c;
32 
33 	while((c=next_char(f)) && c!='\n' && c!=EOF)
34 		;
35 }
36 
configfile_isspace(char c)37 static int configfile_isspace(char c)
38 {
39 	return c==' ' || (c<='\r' && c>='\t');
40 }
41 
read_config_line(FILE * f,char * line,const char ** value,int bufsize)42 static int read_config_line(FILE *f, char *line, const char **value, int bufsize)
43 {
44 	int i = 0, isname = 0;
45 
46 	*value = NULL;
47 	while(i<bufsize-1) {
48 		int c = next_char(f);
49 		if (!isname && (c=='#' || c==';')) {
50 			skip_line(f);
51 			continue;
52 		}
53 		if (!isname && configfile_isspace(c))
54 			continue;
55 
56 		if (c=='=' && !*value) {
57 			line[i] = 0;
58 			*value = &line[i+1];
59 		} else if (c=='\n' && !isname) {
60 			i = 0;
61 			continue;
62 		} else if (c=='\n' || c==EOF) {
63 			line[i] = 0;
64 			break;
65 		} else {
66 			line[i]=c;
67 		}
68 		isname = 1;
69 		i++;
70 	}
71 	line[i+1] = 0;
72 	return (i);
73 }
74 
configfile_parse(const char * filename,configfile_value_fn fn)75 int configfile_parse(const char *filename, configfile_value_fn fn)
76 {
77 	int len;
78 	char line[256];
79 	const char *value;
80 	FILE *f;
81 
82 	if (!(f = fopen(filename, "r"))) {
83 		fprintf(stderr, "[ERROR] %s: %s, %s\n", __func__, filename,
84 								strerror(errno));
85 		return (-1);
86 	}
87 	while((len = read_config_line(f, line, &value, sizeof(line))) > 0) {
88 		if (value == NULL) {
89 			fprintf(stderr, "[ERROR] %s: configuration error: %s\n",
90 								__func__, line);
91 			return (-1);
92 		}
93 		fn(line, value);
94 	}
95 	fclose(f);
96 	return (0);
97 }
98