Mercurial > repos > blastem
comparison config.c @ 487:c08a4efeee7f opengl
Update opengl branch from default. Fix build breakage unrelated to merge
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 26 Oct 2013 22:38:47 -0700 |
parents | 140af5509ce7 |
children | 39cad98d2789 |
comparison
equal
deleted
inserted
replaced
449:7696d824489d | 487:c08a4efeee7f |
---|---|
1 /* | |
2 Copyright 2013 Michael Pavone | |
3 This file is part of BlastEm. | |
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. | |
5 */ | |
6 #include "tern.h" | |
7 #include <stdio.h> | |
8 #include <stdlib.h> | |
9 #include <string.h> | |
10 #include <stdarg.h> | |
11 #include <ctype.h> | |
12 | |
13 #include <sys/types.h> | |
14 #include <sys/stat.h> | |
15 #include <unistd.h> | |
16 | |
17 char * alloc_concat(char * first, char * second) | |
18 { | |
19 int flen = strlen(first); | |
20 int slen = strlen(second); | |
21 char * ret = malloc(flen + slen + 1); | |
22 memcpy(ret, first, flen); | |
23 memcpy(ret+flen, second, slen+1); | |
24 return ret; | |
25 } | |
26 | |
27 char * alloc_concat_m(int num_parts, char ** parts) | |
28 { | |
29 int total = 0; | |
30 for (int i = 0; i < num_parts; i++) { | |
31 total += strlen(parts[i]); | |
32 } | |
33 char * ret = malloc(total + 1); | |
34 *ret = 0; | |
35 for (int i = 0; i < num_parts; i++) { | |
36 strcat(ret, parts[i]); | |
37 } | |
38 return ret; | |
39 } | |
40 | |
41 long file_size(FILE * f) | |
42 { | |
43 fseek(f, 0, SEEK_END); | |
44 long fsize = ftell(f); | |
45 fseek(f, 0, SEEK_SET); | |
46 return fsize; | |
47 } | |
48 | |
49 char * strip_ws(char * text) | |
50 { | |
51 while (*text && (!isprint(*text) || isblank(*text))) | |
52 { | |
53 text++; | |
54 } | |
55 char * ret = text; | |
56 text = ret + strlen(ret) - 1; | |
57 while (text > ret && (!isprint(*text) || isblank(*text))) | |
58 { | |
59 *text = 0; | |
60 text--; | |
61 } | |
62 return ret; | |
63 } | |
64 | |
65 char * split_keyval(char * text) | |
66 { | |
67 while (*text && !isblank(*text)) | |
68 { | |
69 text++; | |
70 } | |
71 if (!*text) { | |
72 return text; | |
73 } | |
74 *text = 0; | |
75 return text+1; | |
76 } | |
77 | |
78 #define MAX_NEST 30 //way more than I'll ever need | |
79 | |
80 tern_node * parse_config(char * config_data) | |
81 { | |
82 char *state, *curline; | |
83 char *prefix = NULL; | |
84 int nest_level = 0; | |
85 char * prefix_parts[MAX_NEST]; | |
86 int line = 1; | |
87 tern_node * head = NULL; | |
88 while ((curline = strtok_r(config_data, "\n", &state))) | |
89 { | |
90 config_data = NULL; | |
91 curline = strip_ws(curline); | |
92 int len = strlen(curline); | |
93 if (!len) { | |
94 continue; | |
95 } | |
96 if (curline[0] == '#') { | |
97 continue; | |
98 } | |
99 if (curline[0] == '}') { | |
100 if (!nest_level) { | |
101 fprintf(stderr, "unexpected } on line %d\n", line); | |
102 exit(1); | |
103 } | |
104 if (prefix) { | |
105 free(prefix); | |
106 prefix = NULL; | |
107 } | |
108 nest_level--; | |
109 curline = strip_ws(curline+1); | |
110 } | |
111 char * end = curline + len - 1; | |
112 if (*end == '{') { | |
113 *end = 0; | |
114 curline = strip_ws(curline); | |
115 prefix_parts[nest_level++] = curline; | |
116 if (prefix) { | |
117 free(prefix); | |
118 prefix = NULL; | |
119 } | |
120 } else { | |
121 if (nest_level && !prefix) { | |
122 prefix = alloc_concat_m(nest_level, prefix_parts); | |
123 } | |
124 char * val = strip_ws(split_keyval(curline)); | |
125 char * key = curline; | |
126 if (*key) { | |
127 if (prefix) { | |
128 key = alloc_concat(prefix, key); | |
129 } | |
130 head = tern_insert_ptr(head, key, strdup(val)); | |
131 if (prefix) { | |
132 free(key); | |
133 } | |
134 } | |
135 } | |
136 } | |
137 if (prefix) { | |
138 free(prefix); | |
139 } | |
140 return head; | |
141 } | |
142 | |
143 tern_node * parse_config_file(char * config_path) | |
144 { | |
145 tern_node * ret = NULL; | |
146 FILE * config_file = fopen(config_path, "r"); | |
147 if (!config_file) { | |
148 goto open_fail; | |
149 } | |
150 long config_size = file_size(config_file); | |
151 if (!config_size) { | |
152 goto config_empty; | |
153 } | |
154 char * config_data = malloc(config_size); | |
155 if (fread(config_data, 1, config_size, config_file) != config_size) { | |
156 goto config_read_fail; | |
157 } | |
158 ret = parse_config(config_data); | |
159 config_read_fail: | |
160 free(config_data); | |
161 config_empty: | |
162 fclose(config_file); | |
163 open_fail: | |
164 return ret; | |
165 } | |
166 | |
167 char * readlink_alloc(char * path) | |
168 { | |
169 char * linktext = NULL; | |
170 ssize_t linksize = 512; | |
171 ssize_t cursize = 0; | |
172 do { | |
173 if (linksize > cursize) { | |
174 cursize = linksize; | |
175 if (linktext) { | |
176 free(linktext); | |
177 } | |
178 } | |
179 linktext = malloc(cursize); | |
180 linksize = readlink(path, linktext, cursize-1); | |
181 if (linksize == -1) { | |
182 perror("readlink"); | |
183 free(linktext); | |
184 linktext = NULL; | |
185 } | |
186 } while (linksize > cursize); | |
187 return linktext; | |
188 } | |
189 | |
190 tern_node * load_config(char * expath) | |
191 { | |
192 char * linktext; | |
193 char * home = getenv("HOME"); | |
194 if (!home) { | |
195 goto load_in_app_dir; | |
196 } | |
197 char * path = alloc_concat(home, "/.config/blastem/blastem.cfg"); | |
198 tern_node * ret = parse_config_file(path); | |
199 if (ret) { | |
200 goto success; | |
201 } | |
202 free(path); | |
203 load_in_app_dir: | |
204 | |
205 linktext = readlink_alloc("/proc/self/exe"); | |
206 if (!linktext) { | |
207 goto link_prob; | |
208 } | |
209 char * cur; | |
210 int linksize = strlen(linktext); | |
211 for(cur = linktext + linksize - 1; cur != linktext; cur--) | |
212 { | |
213 if (*cur == '/') { | |
214 *cur = 0; | |
215 break; | |
216 } | |
217 } | |
218 if (cur == linktext) { | |
219 goto link_prob; | |
220 } | |
221 path = alloc_concat(linktext, "/default.cfg"); | |
222 ret = parse_config_file(path); | |
223 success: | |
224 return ret; | |
225 link_prob: | |
226 if (linktext) { | |
227 free(linktext); | |
228 } | |
229 no_proc: | |
230 //TODO: Fall back to using expath if /proc is not available | |
231 fputs("Failed to find a config file in ~/.config/blastem/blastem.cfg or in the blastem executable directory\n", stderr); | |
232 exit(1); | |
233 } | |
234 |