1 /**
2 * Copyright (C) 2017 Aaron Ball <nullspoon@oper.io>
3 *
4 * Luminous is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Luminous is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with noteless. If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include "config.h"
18
19
20 /**
21 * config_new:
22 * @c Config struct to initialize
23 * @path Path to the config file to initialize from (only used by config_load)
24 *
25 * Config struct constructor.
26 *
27 * Returns success (0) or failure (-1). Failure occurs when specified config
28 * file is not accessible or could not be found.
29 */
30 int config_new(struct config* c, const char* path) {
31 FILE* fd;
32
33 // Check if the config file exists
34 fd = fopen(path, "r");
35 if(!fd)
36 return -1;
37 fclose(fd);
38
39 c->count = 0;
40 c->path = path;
41 c->keys = malloc(0);
42 c->vals = malloc(0);
43 return 0;
44 }
45
46
47 /**
48 * line_get_key:
49 * @line Line to search for key in
50 * @start Pointer to integer holding substring start index
51 * @end Pointer to integer holding substring end index
52 *
53 * Searches the specified string for a key (preceeding an '=' delimiter).
54 *
55 * Returns Length of found key, otherwise -1.
56 */
57 int line_get_key(char* line, int* start, int* end) {
58 *start = 0;
59 *end = 0;
60
61 // Find beginning of key, allowing for preceeding whitespace
62 while(line[*start] == ' ' && line[*start] != '\0')
63 *start = *start + 1;
64
65 // Return error if no non-whitespace text was found
66 if(line[*start] == '\0')
67 return -1;
68
69 *end = *start;
70
71 // Find the end of the key
72 while(line[*end] != ' ' && line[*end] != '=' && line[*end] != '\0')
73 *end = *end + 1;
74
75 return *end - *start;
76 }
77
78
79 /**
80 * line_get_val:
81 * @line Line to search for value in
82 * @start Pointer to integer holding substring start index
83 * @end Pointer to integer holding substring end index
84 *
85 * Searches the specified string for a value (following an '=' delimiter).
86 *
87 * Returns Length of found value, otherwise -1.
88 */
89 int line_get_val(char* line, int* start, int* end) {
90 *start = 0;
91 *end = 0;
92
93 // Find beginning of key, allowing for preceeding whitespace
94 // Set the start cursor to the first non-whitespace character after the
95 // equals sign
96 while(line[*start] != '=' && line[*start] != '\0')
97 *start = *start + 1;
98
99 // Advance one to pass the equals sign
100 *start = *start + 1;
101
102 // A seperate loop to handle leading whitespace. Having this outside of the
103 // previous loop prevents us from allowing for multiple contiguous equals
104 // signs
105 while(line[*start] == ' ')
106 *start = *start + 1;
107
108 // Return error if no equals sign was found
109 if(line[*start] == '\0')
110 return -1;
111
112 // Find the end of the string, not including the newline char if one is
113 // present (this is why we don't use strlen, becuase it includes the index of
114 // the newline char if one is present)
115 while(line[*end] != '\n' && line[*end] != '\0')
116 *end = *end + 1;
117
118 return *end - *start;
119 }
120
121
122 /**
123 * config_load:
124 * @c Config struct to load config data into
125 *
126 * Returns number of config items found in the config file
127 */
128 int config_load(struct config* c) {
129 // Values for tracking config line component start and end indexes
130 int keystart = 0, keyend = 0, keylen = 0;
131 int valstart = 0, valend = 0, vallen = 0;
132 char buf[512]; // Config line buffer
133 FILE* fd; // Config file descriptor
134
135 fd = fopen(c->path, "r");
136
137 while(fgets(buf, 512, fd) != NULL) {
138 c->count++;
139
140 // Allocate array space for new keys and values
141 c->keys = realloc(c->keys, sizeof(char*) * c->count);
142 c->vals = realloc(c->vals, sizeof(char*) * c->count);
143
144 // Get the key start and end index
145 keylen = line_get_key(buf, &keystart, &keyend);
146 // Allocate space for new key
147 c->keys[c->count - 1] = malloc(keylen + 1);
148 // Copy the key into the new memory
149 strncpy(c->keys[c->count - 1], &buf[keystart], keylen);
150 // Dont' forget the null byte!
151 c->keys[c->count - 1][keylen] = '\0';
152
153 // Do the exact same thing for the value
154 vallen = line_get_val(buf, &valstart, &valend);
155 c->vals[c->count - 1] = malloc(vallen + 1);
156 strncpy(c->vals[c->count - 1], &buf[valstart], vallen);
157 c->vals[c->count - 1][vallen] = '\0';
158
159 // Reset our index variables
160 keystart = 0, keyend = 0, keylen = 0;
161 valstart = 0, valend = 0, vallen = 0;
162 }
163
164 fclose(fd);
165
166 return c->count;
167 }
168
169
170 /**
171 * config_dump:
172 * @c Config struct to dump
173 * @fd File descriptor to print dump text to. If NULL, prints to stdout
174 *
175 * Dumps the provided config struct to the specified file descriptor.
176 */
177 void config_dump(struct config* c, FILE* fd) {
178 int i = 0;
179 if(!fd)
180 fd = stdout;
181
182 while(i < c->count) {
183 fprintf(fd, "%d %s %s\n", i, c->keys[i], c->vals[i]);
184 i++;
185 }
186 }
187
188
189 /**
190 * config_get:
191 * @c Config struct to search for a matching key
192 * @key Config key to find value for
193 * @out Output buffer to copy value to
194 *
195 * Returns Status integer (0 == key found, -1 == key not found)
196 */
197 int config_get(struct config* c, char* key, char* out) {
198 int i = 0;
199
200 while(i < c->count) {
201 // Copy value for matching key to output buffer
202 if(strcmp(c->keys[i], key) == 0) {
203 strcpy(out, c->vals[i]);
204 return 0;
205 }
206 i++;
207 }
208
209 // If we reach this point, no matching keys were found
210 return -1;
211 }
212
213
214 /**
215 * config_free:
216 * @c Config struct to free
217 */
218 int config_free(struct config* c) {
219 while(c->count > 0) {
220 // Free the corresponding
221 free(c->keys[c->count - 1]);
222 free(c->vals[c->count - 1]);
223 c->count--;
224 }
225
226 // Free the array space
227 free(c->keys);
228 free(c->vals);
229
230 return 0;
231 }
|