1 /**
2 * A class to help with parsing standard config files
3 *
4 * Copyright (C) 2014 Aaron Ball <nullspoon@iohq.net>
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_new(config_t* conf, char* p) {
28 // TODO
29 strcpy(conf->path, p);
30
31 conf->count = config_valid_line_count(p);
32
33 conf->keys = malloc(sizeof(char*) * conf->count);
34 conf->values = malloc(sizeof(char*) * conf->count);
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 int i = 0;
53 while(fgets(buf, len, f) != NULL) {
54 int start = 0;
55 // This loop allows for lines to not start at the beginning
56 while(buf[start] != '\0') {
57 if(buf[start] != ' ') {
58 break;
59 } else {
60 start++;
61 }
62 }
63
64 // Skip all lines starting with a comment char
65 if(buf[start] == '#') { continue; }
66 // Skip empty lines
67 if(buf[start] == '\n') { continue; }
68
69 int end = start;
70 while(buf[end] != '\0') {
71 // This allows for inline comment chars. The line ends when the first
72 // comment char is found.
73 if(buf[end] == '#' || buf[end] == '\n') { break; }
74 end++;
75 }
76
77 //char tmp_line[end - start + 10];
78 char tmp_line[config_line_len] = "";
79 // Temp variable to store the text between index start and index end
80 strncpy(tmp_line, &buf[start], end - start + 1);
81 // Make sure it has a trailing newline so sscanf works
82 strcat(tmp_line, "\n");
83
84 // Parse the line into temp variables
85 sscanf(tmp_line, "%s %s", key, value);
86
87 // Allocate heap memory for values since these need to persist.
88 // Note that here we are using the temp variables to establish string
89 // length for when we allocate heap memory.
90 conf->keys[i] = malloc(sizeof(char) * (strlen(key) + 1));
91 conf->values[i] = malloc(sizeof(char) * (strlen(value) + 1));
92
93 // Copy in the temp values
94 strcpy(conf->keys[i], key);
95 strcpy(conf->values[i], value);
96
97 // Increment the counter for tracking keys and values in their respective
98 // arrays
99 i++;
100 }
101
102 fclose(f);
103
104 return 0;
105 }
106
107
108 /**
109 * Destructor for config struct.
110 *
111 * @param conf Config_t pointer to be freed from memory
112 */
113 void config_free(config_t* conf) {
114 for(int i = 0; i < conf->count; i++) {
115 free(conf->keys[i]);
116 free(conf->values[i]);
117 }
118 free(conf->keys);
119 free(conf->values);
120 }
121
122
123 /**
124 * Performs a line count of valid lines in the specified config file. This is
125 * useful for determining the size of an array to store keys or values in.
126 * A valid line is considered to be a line that is not empty or commented out.
127 *
128 * @param path Path to the config file to be parsed
129 *
130 * @return int Count of lines that are not commented out or empty
131 */
132 int config_valid_line_count(char* path) {
133 int count = 0;
134
135 FILE* f;
136 f = fopen(path, "r");
137
138 int len = config_line_len;
139 char buf[config_line_len];
140
141 while(fgets(buf, len, f) != NULL) {
142 int start = 0;
143
144 // Find the first char
145 while(buf[start] == ' ') { start++; }
146
147 // Confirm the line is not a comment or empty
148 if(buf[start] != '#' && buf[start] != '\n') { count++; }
149 }
150 fclose(f);
151
152 return count;
153 }
154
155
156 /**
157 * Checks the configuration struct for the given key's value.
158 *
159 * @param conf Config_t instance pointer containing keys and values to check
160 * @param key Key to check if exists
161 *
162 * @return int Key value exists (1) or not (0)
163 */
164 int config_isset(config_t* conf, char* key) {
165 for(int i = 0; i < conf->count; i++) {
166 if(strcmp(conf->keys[i], key) == 0) {
167 return 1;
168 }
169 }
170 return 0;
171 }
172
173 /**
174 * TODO
175 */
176 char* config_get(config_t* conf, char* key) {
177 for(int i = 0; i < conf->count; i++) {
178 if(strcmp(conf->keys[i], key) == 0) {
179 return conf->values[i];
180 }
181 }
182 return NULL;
183 }
184
185
186 /**
187 * Parses one line of the config file. Strips illegal characters first, then
188 * sets key to the text on the left of the equals sign and value to the text on
189 * the right.
190 *
191 * string line - Config file line to be parsed and added to the config object
192 *
193 * return int Success or failure
194 */
195 // int config::parse_line( string line ) {
196 // // The two vars that will be appended to the key value vector
197 // string key;
198 // string value;
199 // int split;
200 //
201 // // Clean spaces and other illegal chars
202 // string clean_line;
203 // for( int i = 0; i < line.length(); i++ ) {
204 // if( line[i] == ' ' ) {
205 // // Ignore, it's a space
206 // continue;
207 // } else {
208 // clean_line += line[i];
209 // }
210 // }
211 //
212 // // Line was empty, skip 'er
213 // if( clean_line.length() == 0 ) { return 0; }
214 //
215 // // One character at a time
216 // for( int i = 0; i < clean_line.length(); i++ ) {
217 // if( clean_line[i] == '=' ) {
218 // // Set the key
219 // key = clean_line.substr( 0, i );
220 // split = i;
221 // break;
222 // }
223 // }
224 // // Set the value
225 // value = clean_line.substr( split + 1, clean_line.length() );
226 //
227 // // Append to class global values
228 // values.push_back( key );
229 // values.push_back( value );
230 //
231 // // Success!
232 // return 0;
233 // }
|