1 /**
2 * A class to help with parsing standard config files
3 *
4 * Copyright (C) 2016 Aaron Ball <nullspoon@oper.io>
5 *
6 * Noteless is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Noteless is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with noteless. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "config.h"
20
21 /**
22 * Constructor for the config class. Reads config file into a vector (one line
23 * per index), then parses each line into a vector size 2x.
24 *
25 * @param const char* p Path to the config file to be read in
26 */
27 int config_load(config_t* conf, char* p) {
28 // TODO
29 strcpy(conf->path, p);
30
31 int line_count = config_valid_line_count(p);
32
33 // The file couldn't be opened or no valid lines found, return -1
34 if(line_count == 0) { return -1; }
35
36 FILE* f;
37 f = fopen(conf->path, "r");
38
39 // Verify the file could be opened
40 if(!f) {
41 // printf("Could not open config file at %s.\n", conf->path);
42 return -1;
43 }
44
45 // Set the maximum read width and read buffer array
46 int len = config_line_len;
47 char buf[config_line_len] = "";
48
49 char key[32];
50 char value[256];
51
52 while(fgets(buf, len, f) != NULL) {
53 int start = 0;
54 // This loop allows for lines to not start at the beginning
55 while(buf[start] != '\0') {
56 if(buf[start] != ' ') {
57 break;
58 } else {
59 start++;
60 }
61 }
62
63 // Skip all lines starting with a comment char
64 if(buf[start] == '#') { continue; }
65 // Skip empty lines
66 if(buf[start] == '\n') { continue; }
67
68 int end = start;
69 while(buf[end] != '\0') {
70 // This allows for inline comment chars. The line ends when the first
71 // comment char is found.
72 if(buf[end] == '#' || buf[end] == '\n') { break; }
73 end++;
74 }
75
76 char tmp_line[config_line_len] = "";
77 // Temp variable to store the text between index start and index end
78 strncpy(tmp_line, &buf[start], end - start + 1);
79 // Make sure it has a trailing newline so sscanf works
80 strcat(tmp_line, "\n");
81
82 // Parse the line into temp variables
83 sscanf(tmp_line, "%s %s", key, value);
84
85 // Set the config key/value
86 config_set(conf, key, value);
87 }
88
89 fclose(f);
90
91 return 0;
92 }
93
94
95 /**
96 * Destructor for config struct.
97 *
98 * @param conf Config_t pointer to be freed from memory
99 */
100 void config_free(config_t* conf) {
101 for(int i = 0; i < conf->count; i++) {
102 free(conf->keys[i]);
103 free(conf->values[i]);
104 }
105 }
106
107
108 /**
109 * Performs a line count of valid lines in the specified config file. This is
110 * useful for determining the size of an array to store keys or values in.
111 * A valid line is considered to be a line that is not empty or commented out.
112 *
113 * @param path Path to the config file to be parsed
114 *
115 * @return int Count of lines that are not commented out or empty
116 */
117 int config_valid_line_count(char* path) {
118 int count = 0;
119
120 FILE* f;
121 f = fopen(path, "r");
122 if(!f) { return -1; }
123
124 int len = config_line_len;
125 char buf[config_line_len];
126
127 while(fgets(buf, len, f) != NULL) {
128 int start = 0;
129
130 // Find the first char
131 while(buf[start] == ' ') { start++; }
132
133 // Confirm the line is not a comment or empty
134 if(buf[start] != '#' && buf[start] != '\n') { count++; }
135 }
136 fclose(f);
137
138 return count;
139 }
140
141
142 /**
143 * Checks the configuration struct for the given key's value.
144 *
145 * @param conf Config_t instance pointer containing keys and values to check
146 * @param key Key to check if exists
147 *
148 * @return int Key value exists (1) or not (0)
149 */
150 int config_isset(config_t* conf, char* key) {
151 for(int i = 0; i < conf->count; i++) {
152 if(strcmp(conf->keys[i], key) == 0) {
153 return 1;
154 }
155 }
156 return 0;
157 }
158
159
160 /**
161 * TODO
162 */
163 char* config_get(config_t* conf, char* key) {
164 for(int i = 0; i < conf->count; i++) {
165 if(strcmp(conf->keys[i], key) == 0) {
166 return conf->values[i];
167 }
168 }
169 return NULL;
170 }
171
172
173 /**
174 * Sets the value of the specified key. If the key exists, its value is reset
175 * to the value that is passed in. If the key does not exist, the key and value
176 * are appended to the end of the key/value arrays.
177 *
178 * @param conf The config object containing the keys and values
179 * @param key Key to set the value for
180 * @param value Value to be set for the given key
181 *
182 * @return Index of the key/value that has been set
183 */
184 int config_set(config_t* conf, char* key, char* value) {
185 for(int i = 0; i < conf->count; i++) {
186 if(strcmp(conf->keys[i], key) == 0) {
187 // Key exists, reset its value
188 strcpy(conf->values[i], value);
189 return i;
190 }
191 }
192 // Key does not exist, create and add
193 char* h_key = malloc(strlen(key) + 1);
194 char* h_value = malloc(strlen(value) + 1);
195 strcpy(h_key, key);
196 strcpy(h_value, value);
197 conf->keys[conf->count] = h_key;
198 conf->values[conf->count] = h_value;
199 conf->count++;
200 return (conf->count - 1);
201 }
202
203
204 /**
205 * TODO
206 */
207 int config_add(config_t* conf, char* key, char* value) {
208 // Allocate the new key and value memory
209 char* h_key = malloc(strlen(key) + 1);
210 char* h_value = malloc(strlen(value) + 1);
211 // Assign
212 strcpy(h_key, key);
213 strcpy(h_value, value);
214
215 conf->count++;
216 conf->keys[conf->count] = h_key;
217 conf->values[conf->count] = h_value;
218
219 return conf->count;
220 }
|