demose: Remove tralling whitespaces too.
[gfxprim/pasky.git] / demos / grinder / params.c
blob3f39a36aa7a7001eec251908f48efa87037a6072
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim 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 GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2011 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
23 #include <stdio.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <errno.h>
30 #include "params.h"
32 static const char *param_type_names[] = {
33 "bool",
34 "integer",
35 "float",
36 "string",
37 "enum",
40 const char *param_type_name(enum param_type type)
42 if (type > PARAM_ENUM)
43 return NULL;
45 return param_type_names[type];
48 static const char *param_type_names_padd[] = {
49 "bool ",
50 "integer",
51 "float ",
52 "string ",
53 "enum ",
56 static void padd(unsigned int n)
58 while (n--)
59 putchar(' ');
63 static void print_enum(const char *enum_table[])
65 unsigned int i;
67 printf(" = [");
69 for (i = 0; enum_table[i] != NULL; i++)
70 if (enum_table[i+1] == NULL)
71 printf("%s]", enum_table[i]);
72 else
73 printf("%s | ", enum_table[i]);
76 void param_describe(const struct param *param_desc, const char *prefix)
78 unsigned int i, len = 0, l;
80 for (i = 0; param_desc[i].name != NULL; i++) {
81 l = strlen(param_desc[i].name);
83 if (l > len)
84 len = l;
87 for (i = 0; param_desc[i].name != NULL; i++) {
88 printf("%s%s", prefix, param_desc[i].name);
89 padd(len - strlen(param_desc[i].name));
90 printf(" : %s", param_type_names_padd[param_desc[i].type]);
91 printf(" - %s", param_desc[i].desc);
93 if (param_desc[i].type == PARAM_ENUM)
94 print_enum(param_desc[i].enum_table);
96 printf("\n");
100 static unsigned int count_params(const char *params)
102 unsigned int ret = 1, i;
103 char prev = ':';
105 for (i = 0; params[i] != '\0'; i++) {
107 if (params[i] == ':' && prev != ':')
108 ret++;
110 prev = params[i];
113 return ret;
116 static void split_params(char *params, char **names)
118 unsigned int i, n = 0;
119 char prev = ':';
121 for (i = 0; params[i] != '\0'; i++) {
123 if (params[i] != ':' && prev == ':')
124 names[n++] = &params[i];
126 prev = params[i];
128 if (params[i] == ':')
129 params[i] = '\0';
133 static void do_split(char *param, char **value)
135 unsigned int i;
137 *value = NULL;
139 for (i = 0; param[i] != '\0'; i++) {
141 if (param[i] == '=' || isspace(param[i])) {
142 param[i] = '\0';
143 *value = &param[i+1];
148 static void split_values(char **names, char **values, unsigned int n)
150 unsigned int i;
152 for (i = 0; i < n; i++)
153 do_split(names[i], &values[i]);
156 int param_pos(char *names[], const char *name, unsigned int start, unsigned int n)
158 unsigned int i;
160 for (i = start; i < n; i++)
161 if (!strcasecmp(names[i], name))
162 return i;
164 return -1;
167 int set_int(int *res, char *val)
169 long l;
170 char *end;
172 errno = 0;
173 l = strtol(val, &end, 0);
175 if (*end != '\0')
176 return 1;
178 if (errno != 0)
179 return 1;
181 *res = l;
183 return 0;
186 static char *bool_false[] = {
187 "No",
188 "False",
189 "Off",
190 NULL
193 static char *bool_true[] = {
194 "Yes",
195 "True",
196 "On",
197 NULL
200 int set_bool(int *res, char *val)
202 unsigned int i;
204 for (i = 0; bool_false[i] != NULL; i++)
205 if (!strcasecmp(val, bool_false[i])) {
206 *res = 0;
207 return 0;
210 for (i = 0; bool_true[i] != NULL; i++)
211 if (!strcasecmp(val, bool_true[i])) {
212 *res = 1;
213 return 0;
216 return 1;
219 int set_float(float *res, char *val)
221 char *end;
222 double d;
224 errno = 0;
225 d = strtod(val, &end);
227 if (*end != '\0')
228 return 1;
230 if (errno != 0)
231 return 1;
233 *res = d;
235 return 0;
238 int set_enum(int *res, char *val, const char *enums[])
240 unsigned int i;
242 for (i = 0; enums[i] != NULL; i++)
243 if (!strcasecmp(enums[i], val)) {
244 *res = i;
245 return 0;
248 return 1;
251 int set_str(char **res, char *val)
253 *res = val;
254 return 0;
257 #define CALL_ERR_CALLBACK(error, p, value, private) do { \
258 int error_ret; \
260 if (error != NULL) \
261 if ((error_ret = error(p, value, private))) \
262 return error_ret; \
263 } while (0)
265 int param_parse(const char *params, const struct param *param_desc, void *priv,
266 int (*err)(const struct param *self, const char *val, void *priv), ...)
268 char *par;
269 unsigned int n, i;
270 va_list va;
271 int ret = 0;
273 if (params == NULL || *params == '\0')
274 return 0;
276 par = strdup(params);
278 if (par == NULL) {
279 fprintf(stderr, "Malloc failed :(\n");
280 return 1;
283 n = count_params(params);
285 char *names[n];
286 char *values[n];
287 int flags[n];
289 memset(flags, 0, sizeof(flags));
291 split_params(par, names);
292 split_values(names, values, n);
294 va_start(va, err);
296 for (i = 0; param_desc[i].name != NULL; i++) {
297 void *arg = va_arg(va, void*);
298 int pos = 0;
300 while ((pos = param_pos(names, param_desc[i].name, pos, n)) >= 0) {
302 if (values[pos] == NULL || *values[pos] == '\0') {
303 CALL_ERR_CALLBACK(err, &param_desc[i], "", priv);
304 goto err;
307 flags[pos]++;
309 switch (param_desc[i].type) {
310 case PARAM_BOOL:
311 if ((ret = set_bool(arg, values[pos]))) {
312 CALL_ERR_CALLBACK(err, &param_desc[i],
313 values[pos], priv);
314 goto err;
316 break;
317 case PARAM_INT:
318 if ((ret = set_int(arg, values[pos]))) {
319 CALL_ERR_CALLBACK(err, &param_desc[i],
320 values[pos], priv);
321 goto err;
323 break;
324 case PARAM_FLOAT:
325 if ((ret = set_float(arg, values[pos]))) {
326 CALL_ERR_CALLBACK(err, &param_desc[i],
327 values[pos], priv);
328 goto err;
330 break;
331 case PARAM_STR:
332 if ((ret = set_str(arg, values[pos]))) {
333 CALL_ERR_CALLBACK(err, &param_desc[i],
334 values[pos], priv);
335 goto err;
337 break;
338 case PARAM_ENUM:
339 if ((ret = set_enum(arg, values[pos],
340 param_desc[i].enum_table))) {
341 CALL_ERR_CALLBACK(err, &param_desc[i],
342 values[pos], priv);
343 goto err;
345 break;
348 if (param_desc[i].check != NULL)
349 if ((ret = param_desc[i].check(&param_desc[i], arg, flags[i]))) {
350 CALL_ERR_CALLBACK(err, &param_desc[i],
351 values[pos], priv);
352 goto err;
354 pos++;
358 for (i = 0; i < n; i++) {
359 switch (flags[i]) {
360 /* unknown parameter passed */
361 case 0:
362 CALL_ERR_CALLBACK(err, NULL, names[i], priv);
363 break;
364 case 1:
365 break;
366 /* parameter redefined */
367 default:
368 break;
372 ret = 0;
373 err:
374 va_end(va);
375 free(par);
376 return ret;