added support for glGetIntegerv
[libgliar] / src / cfg.c
1 /*
2 libgliar - a library that can fake the OpenGL context info returned by
3 the glGet OpenGL calls
4
5 Copyright (C) 2013 Canonical Ltd
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.        If not, see <http://www.gnu.org/licenses/>.
19
20 Author: Eleni Maria Stea <elene.mst@gmail.com>
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include "cfg.h"
28
29 static char *stripspace(char *s);
30 static void concat_values(struct cfgopt *opt);
31
32 /* linked list of valid value filters */
33 static struct cfgopt *valid_vals;
34
35 /* adds a new filter set of valid values for the key "key" */
36 void gliar_value_set(const char *key, char **valid, int vcount)
37 {
38         int i;
39         struct cfgopt *node;
40
41         if(!(node = malloc(sizeof *node))) {
42                 return;
43         }
44         if(!(node->key = malloc(strlen(key) + 1))) {
45                 free(node);
46                 return;
47         }
48         strcpy(node->key, key);
49
50         if(!(node->str_val = malloc(vcount * sizeof *node->str_val))) {
51                 free(node->key);
52                 free(node);
53                 return;
54         }
55         for(i=0; i<vcount; i++) {
56                 if(!(node->str_val[i] = malloc(strlen(valid[i]) + 1))) {
57                         for(; i>=0; i--) {
58                                 free(node->str_val[i]);
59                                 free(node->key);
60                                 free(node);
61                                 return;
62                         }
63                 }
64                 strcpy(node->str_val[i], valid[i]);
65         }
66
67         node->str_count = vcount;
68
69         node->next = valid_vals;
70         valid_vals = node;
71 }
72
73 struct cfgopt *gliar_load_cfg(const char *fname)
74 {
75         FILE *fp;
76         char buf[512];
77         struct cfgopt *optlist = 0;
78         struct cfgopt *opt = 0;
79         const struct cfgopt *filter;
80
81         if(!(fp = fopen(fname, "r"))) {
82                 return 0;
83         }
84
85         while(fgets(buf, sizeof buf, fp)) {
86                 char *line = stripspace(buf);
87
88                 if(!*line || *line == '#') {
89                         continue;
90                 }
91
92                 if(*line == '[') {
93                         /* found a new key */
94                         char *end = strrchr(line, ']');
95                         if(!end) {
96                                 fprintf(stderr, "invalid config %s: %s\n", fname, line);
97                                 continue;
98                         }
99                         line++;
100                         *end = 0;
101
102                         if(opt) {
103                                 opt->next = optlist;
104                                 optlist = opt;
105                                 concat_values(opt);
106                         }
107
108                         /* find the valid values for this particular key (if any) */
109                         filter = gliar_find_opt(valid_vals, line);
110
111                         if((opt = malloc(sizeof *opt))) {
112                                 if((opt->key = malloc(strlen(line) + 1))) {
113                                         strcpy(opt->key, line);
114                                         opt->str_val = 0;
115                                         opt->num_val = 0;
116                                         opt->str_count = 0;
117                                         opt->type = GLIAR_STRING;
118                                 } else {
119                                         free(opt);
120                                         opt = 0;
121                                 }
122                         }
123                 } else {
124                         /* found a value for the current key (opt->key) */
125                         int i, num, new_sz = opt->str_count + 1;
126                         char **tmp;
127                         char *end;
128
129                         if(filter) {
130                                 for(i=0; i<filter->str_count; i++) {
131                                         if(strcmp(line, filter->str_val[i]) == 0) {
132                                                 break;
133                                         }
134                                 }
135
136                                 if(i == filter->str_count) {
137                                         /* the string is not in the valid list, ignore it */
138                                         fprintf(stderr, "GLIAR: extension %s not supported, ignoring\n", line);
139                                         continue;
140                                 }
141                         }
142
143                         num = strtol(line, &end, 10);
144                         if(!*end) {
145                                 opt->num_val = num;
146                                 opt->type = GLIAR_NUMBER;
147                         }
148
149                         if(opt && (tmp = realloc(opt->str_val, new_sz * sizeof(char*)))) {
150                                 opt->str_val = tmp;
151                                 if((opt->str_val[new_sz - 1] = malloc(strlen(line) + 1))) {
152                                         strcpy(opt->str_val[new_sz -1], line);
153                                         opt->str_count = new_sz;
154                                 }
155                         }
156
157                         if(new_sz > 1) {
158                                 opt->type = GLIAR_STRING;
159                         }
160                 }
161         }
162
163         if(opt) {
164                 opt->next = optlist;
165                 optlist = opt;
166                 concat_values(opt);
167         }
168
169         fclose(fp);
170         return optlist;
171 }
172
173 const struct cfgopt *gliar_find_opt(struct cfgopt *list, const char *name)
174 {
175         if(!list || !name) {
176                 return 0;
177         }
178
179         while(list) {
180                 if(strcmp(list->key, name) == 0) {
181                         return list;
182                 }
183                 list = list->next;
184         }
185         return 0;
186 }
187
188 void gliar_print_opt(struct cfgopt *list)
189 {
190         printf("OPTIONS\n");
191         while(list) {
192                 if(list->type == GLIAR_NUMBER) {
193                         printf("\"%s\" -> %d\n", list->key, list->num_val);
194                 }
195                 else {
196                         int i;
197                         for(i=0; i<list->str_count; i++) {
198                                 printf("\"%s\" -> \"%s\"\n", list->key, list->str_val[i]);
199                         }
200                 }
201                 list = list->next;
202         }
203 }
204
205 static char *stripspace(char *s)
206 {
207         char *end = s + strlen(s) - 1;
208
209         while(isspace(*s)) s++;
210
211         while(isspace(*end)) {
212                 *end-- = 0;
213         }
214         return s;
215 }
216
217 static void concat_values(struct cfgopt *opt)
218 {
219         int i;
220         int sz = opt->str_count - 1;
221
222         if(!opt->str_count) {
223                 opt->conc_vals = 0;
224                 return;
225         }
226
227         for(i=0; i<opt->str_count; i++) {
228                 sz += strlen(opt->str_val[i]);
229         }
230
231         if(!(opt->conc_vals = malloc(sz + 1))) {
232                 return;
233         }
234
235         *opt->conc_vals = 0;
236         for(i=0; i<opt->str_count - 1; i++) {
237                 strcat(opt->conc_vals, opt->str_val[i]);
238                 strcat(opt->conc_vals, " ");
239         }
240         strcat(opt->conc_vals, opt->str_val[i]);
241 }