50c4f9cc5b5764af88e8501904cb49c1f68a1707
[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 struct cfgopt *gliar_load_cfg(const char *fname)
33 {
34         FILE *fp;
35         char buf[512];
36         struct cfgopt *optlist = 0;
37         struct cfgopt *opt = 0;
38
39         if(!(fp = fopen(fname, "r"))) {
40                 return 0;
41         }
42
43         while(fgets(buf, sizeof buf, fp)) {
44                 char *line = stripspace(buf);
45
46                 if(!*line || *line == '#') {
47                         continue;
48                 }
49
50                 if(*line == '[') {
51                         char *end = strrchr(line, ']');
52                         if(!end) {
53                                 fprintf(stderr, "invalid config %s: %s\n", fname, line);
54                                 continue;
55                         }
56                         line++;
57                         *end = 0;
58
59                         if(opt) {
60                                 opt->next = optlist;
61                                 optlist = opt;
62                                 concat_values(opt);
63                         }
64
65                         if((opt = malloc(sizeof *opt))) {
66                                 if((opt->key = malloc(strlen(line) + 1))) {
67                                         strcpy(opt->key, line);
68                                         opt->str_val = 0;
69                                         opt->num_val = 0;
70                                         opt->str_count = 0;
71                                         opt->type = GLIAR_STRING;
72                                 } else {
73                                         free(opt);
74                                         opt = 0;
75                                 }
76                         }
77                 } else {
78                         int new_sz = opt->str_count + 1;
79                         char **tmp;
80
81                         char *end;
82                         int num = strtol(line, &end, 10);
83
84                         if(!*end) {
85                                 opt->num_val = line;
86                                 opt->type = GLIAR_NUMBER;
87                         }
88
89                         if(opt && (tmp = realloc(opt->str_val, new_sz * sizeof(char*)))) {
90                                 opt->str_val = tmp;
91                                 if((opt->str_val[new_sz - 1] = malloc(strlen(line) + 1))) {
92                                         strcpy(opt->str_val[new_sz -1], line);
93                                         opt->str_count = new_sz;
94                                 }
95                         }
96
97                         if(new_sz > 1) {
98                                 opt->type = GLIAR_STRING;
99                         }
100                 }
101         }
102
103         if(opt) {
104                 opt->next = optlist;
105                 optlist = opt;
106                 concat_values(opt);
107         }
108
109         fclose(fp);
110         return optlist;
111 }
112
113 const struct cfgopt *gliar_find_opt(struct cfgopt *list, const char *name)
114 {
115         if(!list || !name) {
116                 return 0;
117         }
118
119         while(list) {
120                 if(strcmp(list->key, name) == 0) {
121                         return list;
122                 }
123                 list = list->next;
124         }
125         return 0;
126 }
127
128 void gliar_print_opt(struct cfgopt *list)
129 {
130         printf("OPTIONS\n");
131         while(list) {
132                 if(list->type == GLIAR_NUMBER) {
133                         printf("\"%s\" -> %d\n", list->key, list->num_val);
134                 }
135                 else {
136                         int i;
137                         for(i=0; i<list->str_count; i++) {
138                                 printf("\"%s\" -> \"%s\"\n", list->key, list->str_val[i]);
139                         }
140                 }
141                 list = list->next;
142         }
143 }
144
145 static char *stripspace(char *s)
146 {
147         char *end = s + strlen(s) - 1;
148
149         while(isspace(*s)) s++;
150
151         while(isspace(*end)) {
152                 *end-- = 0;
153         }
154         return s;
155 }
156
157 static void concat_values(struct cfgopt *opt)
158 {
159         int i;
160         int sz = opt->str_count - 1;
161
162         for(i=0; i<opt->str_count; i++) {
163                 sz += strlen(opt->str_val[i]);
164         }
165
166         if(!(opt->conc_vals = malloc(sz + 1))) {
167                 return;
168         }
169
170         *opt->conc_vals = 0;
171         for(i=0; i<opt->str_count - 1; i++) {
172                 strcat(opt->conc_vals, opt->str_val[i]);
173                 strcat(opt->conc_vals, " ");
174         }
175         strcat(opt->conc_vals, opt->str_val[i]);
176 }