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