Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
control/conf.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010-2011, 2014 Henrik Andersson.
4 Copyright (C) 2010-2013 johannes hanika.
5 Copyright (C) 2010, 2012-2017 Tobias Ellinghaus.
6 Copyright (C) 2012 Christian Tellefsen.
7 Copyright (C) 2012 Jérémy Rosen.
8 Copyright (C) 2012 Richard Wonka.
9 Copyright (C) 2012 Simon Spannagel.
10 Copyright (C) 2012, 2014 Ulrich Pegelow.
11 Copyright (C) 2013 Jean-Sébastien Pédron.
12 Copyright (C) 2013 Jesper Pedersen.
13 Copyright (C) 2014 parafin.
14 Copyright (C) 2014, 2020-2021 Pascal Obry.
15 Copyright (C) 2014, 2016 Roman Lebedev.
16 Copyright (C) 2016-2018 Peter Budai.
17 Copyright (C) 2019 jakubfi.
18 Copyright (C) 2019, 2021 luzpaz.
19 Copyright (C) 2020 Hubert Kowalski.
20 Copyright (C) 2020 Philippe Weyland.
21 Copyright (C) 2021 Aldric Renaudin.
22 Copyright (C) 2021 Marco Carrarini.
23 Copyright (C) 2021 Mark-64.
24 Copyright (C) 2021 Ralf Brown.
25 Copyright (C) 2022 Hanno Schwalm.
26 Copyright (C) 2022 Martin Bařinka.
27 Copyright (C) 2025 Aurélien PIERRE.
28
29 darktable is free software: you can redistribute it and/or modify
30 it under the terms of the GNU General Public License as published by
31 the Free Software Foundation, either version 3 of the License, or
32 (at your option) any later version.
33
34 darktable is distributed in the hope that it will be useful,
35 but WITHOUT ANY WARRANTY; without even the implied warranty of
36 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 GNU General Public License for more details.
38
39 You should have received a copy of the GNU General Public License
40 along with darktable. If not, see <http://www.gnu.org/licenses/>.
41*/
42
43#ifdef HAVE_CONFIG_H
44#include "config.h"
45#endif
46
47#include "common/calculator.h"
48#include "common/darktable.h"
50#include "common/math.h"
51#include "control/conf.h"
52
53#include <glib.h>
54#include <glib/gstdio.h>
55#include <glib/gprintf.h>
56#include <inttypes.h>
57#include <stdio.h>
58#include <stdlib.h>
59#include <strings.h>
60
61typedef struct dt_conf_dreggn_t
62{
63 GSList *result;
64 const char *match;
66
67static void _free_confgen_value(void *value)
68{
70 dt_free(s->def);
71 dt_free(s->min);
72 dt_free(s->max);
75 dt_free(s->longdesc);
76 dt_free(s);
77}
78
80static inline char *dt_conf_get_var(const char *name)
81{
82 char *str;
83
85
86 str = (char *)g_hash_table_lookup(darktable.conf->override_entries, name);
87 if(!IS_NULL_PTR(str)) goto fin;
88
89 str = (char *)g_hash_table_lookup(darktable.conf->table, name);
90 if(!IS_NULL_PTR(str)) goto fin;
91
92 // not found, try defaults
93 str = (char *)dt_confgen_get(name, DT_DEFAULT);
94 if(!IS_NULL_PTR(str))
95 {
96 char *str_new = g_strdup(str);
97 g_hash_table_insert(darktable.conf->table, g_strdup(name), str_new);
98 str = str_new;
99 goto fin;
100 }
101
102 // FIXME: why insert garbage?
103 // still no luck? insert garbage:
104 str = (char *)g_malloc0(sizeof(int32_t));
105 g_hash_table_insert(darktable.conf->table, g_strdup(name), str);
106
107fin:
109 return str;
110}
111
112/* set the value only if it hasn't been overridden from commandline
113 * return 1 if key/value is still the one passed on commandline. */
114static int dt_conf_set_if_not_overridden(const char *name, char *str)
115{
117
118 char *over = (char *)g_hash_table_lookup(darktable.conf->override_entries, name);
119 const int is_overridden = (over && !strcmp(str, over));
120 if(!is_overridden)
121 {
122 g_hash_table_insert(darktable.conf->table, g_strdup(name), str);
123 }
124
126
127 return is_overridden;
128}
129
130void dt_conf_set_int(const char *name, int val)
131{
132 char *str = g_strdup_printf("%d", val);
134 {
135 dt_free(str);
136 }
137}
138
139void dt_conf_set_int64(const char *name, int64_t val)
140{
141 char *str = g_strdup_printf("%" PRId64, val);
143 {
144 dt_free(str);
145 }
146}
147
148void dt_conf_set_float(const char *name, float val)
149{
150 char *str = (char *)g_malloc(G_ASCII_DTOSTR_BUF_SIZE);
151 g_ascii_dtostr(str, G_ASCII_DTOSTR_BUF_SIZE, val);
153 {
154 dt_free(str);
155 }
156}
157
158void dt_conf_set_bool(const char *name, int val)
159{
160 char *str = g_strdup(val ? "TRUE" : "FALSE");
162 {
163 dt_free(str);
164 }
165}
166
167void dt_conf_set_string(const char *name, const char *val)
168{
169 char *str = g_strdup(val);
171 {
172 dt_free(str);
173 }
174}
175
176void dt_conf_set_folder_from_file_chooser(const char *name, GtkFileChooser *chooser)
177{
178
179#ifdef WIN32
180 // for Windows native file chooser, gtk_file_chooser_get_current_folder()
181 // does not work, so we workaround
182 if(GTK_IS_FILE_CHOOSER_NATIVE(chooser))
183 {
184 gchar *pathname = gtk_file_chooser_get_filename(chooser);
185 if(pathname)
186 {
187 gchar *folder = g_path_get_dirname(pathname);
189 {
190 dt_free(folder);
191 }
192 dt_free(pathname);
193 }
194 return;
195 }
196#endif
197
198 gchar *folder = gtk_file_chooser_get_current_folder(chooser);
200 {
201 dt_free(folder);
202 }
203}
204
206{
207 const char *str = dt_conf_get_var(name);
208 float new_value = dt_calculator_solve(1, str);
209 if(isnan(new_value))
210 {
211 //we've got garbage, check default
212 const char *def_val = dt_confgen_get(name, DT_DEFAULT);
213 if(!IS_NULL_PTR(def_val))
214 {
215 new_value = dt_calculator_solve(1, def_val);
216 if(isnan(new_value))
217 new_value = 0.0;
218 else
219 {
220 char *fix_badval = g_strdup(def_val);
221 if(dt_conf_set_if_not_overridden(name, fix_badval))
222 {
223 dt_free(fix_badval);
224 }
225 }
226 }
227 else
228 {
229 new_value = 0.0;
230 }
231 }
232
233 int val;
234 if(new_value > 0)
235 val = new_value + 0.5;
236 else
237 val = new_value - 0.5;
238 return val;
239}
240
241int dt_conf_get_int(const char *name)
242{
243 const int min = dt_confgen_get_int(name, DT_MIN);
244 const int max = dt_confgen_get_int(name, DT_MAX);
245 const int val = dt_conf_get_int_fast(name);
246 const int ret = CLAMP(val, min, max);
247 return ret;
248}
249
250int64_t dt_conf_get_int64_fast(const char *name)
251{
252 const char *str = dt_conf_get_var(name);
253 float new_value = dt_calculator_solve(1, str);
254 if(isnan(new_value))
255 {
256 //we've got garbage, check default
257 const char *def_val = dt_confgen_get(name, DT_DEFAULT);
258 if(!IS_NULL_PTR(def_val))
259 {
260 new_value = dt_calculator_solve(1, def_val);
261 if(isnan(new_value))
262 new_value = 0.0;
263 else
264 {
265 char *fix_badval = g_strdup(def_val);
266 if(dt_conf_set_if_not_overridden(name, fix_badval))
267 {
268 dt_free(fix_badval);
269 }
270 }
271 }
272 else
273 {
274 new_value = 0.0;
275 }
276 }
277
278 int64_t val;
279 if(new_value > 0)
280 val = new_value + 0.5;
281 else
282 val = new_value - 0.5;
283 return val;
284}
285
286int64_t dt_conf_get_int64(const char *name)
287{
288 const int64_t min = dt_confgen_get_int64(name, DT_MIN);
289 const int64_t max = dt_confgen_get_int64(name, DT_MAX);
290 const int64_t val = dt_conf_get_int64_fast(name);
291 const int64_t ret = CLAMP(val, min, max);
292 return ret;
293}
294
295float dt_conf_get_float_fast(const char *name)
296{
297 const char *str = dt_conf_get_var(name);
298 float new_value = dt_calculator_solve(1, str);
299 if(isnan(new_value))
300 {
301 //we've got garbage, check default
302 const char *def_val = dt_confgen_get(name, DT_DEFAULT);
303 if(!IS_NULL_PTR(def_val))
304 {
305 new_value = dt_calculator_solve(1, def_val);
306 if(isnan(new_value))
307 new_value = 0.0;
308 else
309 {
310 char *fix_badval = g_strdup(def_val);
311 if(dt_conf_set_if_not_overridden(name, fix_badval))
312 {
313 dt_free(fix_badval);
314 }
315 }
316 }
317 else
318 {
319 new_value = 0.0;
320 }
321 }
322 return new_value;
323}
324
325float dt_conf_get_float(const char *name)
326{
327 const float min = dt_confgen_get_float(name, DT_MIN);
328 const float max = dt_confgen_get_float(name, DT_MAX);
329 const float val = dt_conf_get_float_fast(name);
330 const float ret = CLAMP(val, min, max);
331 return ret;
332}
333
334int dt_conf_get_and_sanitize_int(const char *name, int min, int max)
335{
336 const int cmin = dt_confgen_get_int(name, DT_MIN);
337 const int cmax = dt_confgen_get_int(name, DT_MAX);
338 const int val = dt_conf_get_int_fast(name);
339 const int ret = CLAMPS(val, MAX(min, cmin), MIN(max, cmax));
340 dt_conf_set_int(name, ret);
341 return ret;
342}
343
344int64_t dt_conf_get_and_sanitize_int64(const char *name, int64_t min, int64_t max)
345{
346 const int64_t cmin = dt_confgen_get_int64(name, DT_MIN);
347 const int64_t cmax = dt_confgen_get_int64(name, DT_MAX);
348 const int64_t val = dt_conf_get_int64_fast(name);
349 const int64_t ret = CLAMPS(val, MAX(min, cmin), MIN(max, cmax));
351 return ret;
352}
353
354float dt_conf_get_and_sanitize_float(const char *name, float min, float max)
355{
356 const float cmin = dt_confgen_get_float(name, DT_MIN);
357 const float cmax = dt_confgen_get_float(name, DT_MAX);
358 const float val = dt_conf_get_float_fast(name);
359 const float ret = CLAMPS(val, MAX(min, cmin), MIN(max, cmax));
361 return ret;
362}
363
364int dt_conf_get_bool(const char *name)
365{
366 const char *str = dt_conf_get_var(name);
367 const int val = (str[0] == 'T') || (str[0] == 't');
368 return val;
369}
370
371gchar *dt_conf_get_string(const char *name)
372{
373 const char *str = dt_conf_get_var(name);
374 return g_strdup(str);
375}
376
377const char *dt_conf_get_string_const(const char *name)
378{
379 return dt_conf_get_var(name);
380}
381
382gboolean dt_conf_key_not_empty(const char *name)
383{
384 const char *val = dt_conf_get_string_const(name);
385 if(IS_NULL_PTR(val)) return FALSE;
386 if(strlen(val) == 0) return FALSE;
387 return TRUE;
388}
389
390gboolean dt_conf_get_folder_to_file_chooser(const char *name, GtkFileChooser *chooser)
391{
392 const gchar *folder = dt_conf_get_string_const(name);
393 if (!IS_NULL_PTR(folder))
394 {
395 gtk_file_chooser_set_current_folder(chooser, folder);
396 return TRUE;
397 }
398 return FALSE;
399}
400
401gboolean dt_conf_is_equal(const char *name, const char *value)
402{
403 const char *str = dt_conf_get_var(name);
404 return g_strcmp0(str, value) == 0;
405}
406
407static char *_sanitize_confgen(const char *name, const char *value)
408{
409 const dt_confgen_value_t *item = g_hash_table_lookup(darktable.conf->x_confgen, name);
410
411 if(IS_NULL_PTR(item)) return g_strdup(value);
412
413 char *result = NULL;
414
415 switch(item->type)
416 {
417 case DT_INT:
418 {
419 float v = dt_calculator_solve(1, value);
420
421 const int min = item->min ? (int)dt_calculator_solve(1, item->min) : INT_MIN;
422 const int max = item->max ? (int)dt_calculator_solve(1, item->max) : INT_MAX;
423 // if garbage, use default
424 const int val = isnan(v) ? dt_confgen_get_int(name, DT_DEFAULT) : (int)v;
425 result = g_strdup_printf("%d", CLAMP(val, min, max));
426 }
427 break;
428 case DT_INT64:
429 {
430 float v = dt_calculator_solve(1, value);
431
432 const int64_t min = item->min ? (int64_t)dt_calculator_solve(1, item->min) : INT64_MIN;
433 const int64_t max = item->max ? (int64_t)dt_calculator_solve(1, item->max) : INT64_MAX;
434 // if garbage, use default
435 const int64_t val = isnan(v) ? dt_confgen_get_int64(name, DT_DEFAULT) : (int64_t)v;
436 result = g_strdup_printf("%"PRId64, CLAMP(val, min, max));
437 }
438 break;
439 case DT_FLOAT:
440 {
441 float v = dt_calculator_solve(1, value);
442
443 const float min = item->min ? (float)dt_calculator_solve(1, item->min) : -FLT_MAX;
444 const float max = item->max ? (float)dt_calculator_solve(1, item->max) : FLT_MAX;
445 // if garbage, use default
446 const float val = isnan(v) ? dt_confgen_get_float(name, DT_DEFAULT) : v;
447 result = g_strdup_printf("%f", CLAMP(val, min, max));
448 }
449 break;
450 case DT_BOOL:
451 {
452 if(strcasecmp(value, "true") && strcasecmp(value, "false"))
453 result = g_strdup(dt_confgen_get(name, DT_DEFAULT));
454 else
455 result = g_strdup(value);
456 }
457 break;
458 case DT_ENUM:
459 {
460 char *v = g_strdup_printf("[%s]", value);
461 if(!strstr(item->enum_values, v))
462 result = g_strdup(dt_confgen_get(name, DT_DEFAULT));
463 else
464 result = g_strdup(value);
465 dt_free(v);
466 }
467 break;
468 default:
469 result = g_strdup(value);
470 break;
471 }
472
473 return result;
474}
475
476void dt_conf_init(dt_conf_t *cf, const char *filename, GSList *override_entries)
477{
478 cf->x_confgen = g_hash_table_new_full(g_str_hash, g_str_equal, dt_free_gpointer, _free_confgen_value);
479
480 cf->table = g_hash_table_new_full(g_str_hash, g_str_equal, dt_free_gpointer, dt_free_gpointer);
481 cf->override_entries = g_hash_table_new_full(g_str_hash, g_str_equal, dt_free_gpointer, dt_free_gpointer);
483
484 // init conf filename
485 g_strlcpy(darktable.conf->filename, filename, sizeof(darktable.conf->filename));
486
487#define LINE_SIZE 1023
488
489 char line[LINE_SIZE + 1];
490
491 FILE *f = NULL;
492
493 // check for user config
494 f = g_fopen(filename, "rb");
495
496 // if file has been found, parse it
497
498 if(!IS_NULL_PTR(f))
499 {
500 while(!feof(f))
501 {
502 const int read = fscanf(f, "%" STR(LINE_SIZE) "[^\r\n]\r\n", line);
503 if(read > 0)
504 {
505 char *c = line;
506 char *end = line + strlen(line);
507 // check for '=' which is separator between the conf name and value
508 while(*c != '=' && c < end) c++;
509
510 if(*c == '=')
511 {
512 *c = '\0';
513
514 char *name = g_strdup(line);
515 // ensure that numbers are properly clamped if min/max
516 // defined and if not and garbage is read then the default
517 // value is returned.
518 char *value = _sanitize_confgen(name, (const char *)(c + 1));
519
520 g_hash_table_insert(darktable.conf->table, name, value);
521 }
522 }
523 }
524 fclose(f);
525 }
526 else
527 {
528 // we initialize the conf table with default values
529 GHashTableIter iter;
530 gpointer key, value;
531
532 g_hash_table_iter_init (&iter, darktable.conf->x_confgen);
533 while (g_hash_table_iter_next (&iter, &key, &value))
534 {
535 const char *name = (const char *)key;
537 g_hash_table_insert(darktable.conf->table, g_strdup(name), g_strdup(entry->def));
538 }
539 }
540
541 if(!IS_NULL_PTR(override_entries))
542 {
543 for(GSList *p = override_entries; p; p = g_slist_next(p))
544 {
546 g_hash_table_insert(darktable.conf->override_entries, entry->key, entry->value);
547 }
548 }
549
550#undef LINE_SIZE
551
552 return;
553}
554
556int dt_conf_key_exists(const char *key)
557{
559 const int res = (g_hash_table_lookup(darktable.conf->table, key) != NULL)
560 || (g_hash_table_lookup(darktable.conf->override_entries, key) != NULL);
562 return (res || dt_confgen_value_exists(key, DT_DEFAULT));
563}
564
565static void _conf_add(char *key, char *val, dt_conf_dreggn_t *d)
566{
567 if(strncmp(key, d->match, strlen(d->match)) == 0)
568 {
570 nv->key = g_strdup(key + strlen(d->match) + 1);
571 nv->value = g_strdup(val);
572 d->result = g_slist_append(d->result, nv);
573 }
574}
575
577GSList *dt_conf_all_string_entries(const char *dir)
578{
581 d.result = NULL;
582 d.match = dir;
583 g_hash_table_foreach(darktable.conf->table, (GHFunc)_conf_add, &d);
585 return d.result;
586}
587
588void dt_conf_string_entry_free(gpointer data)
589{
591 dt_free(nv->key);
592 dt_free(nv->value);
593 nv->key = NULL;
594 nv->value = NULL;
595 dt_free(nv);
596}
597
598gboolean dt_confgen_exists(const char *name)
599{
600 return g_hash_table_lookup(darktable.conf->x_confgen, name) != NULL;
601}
602
604{
605 const dt_confgen_value_t *item = g_hash_table_lookup(darktable.conf->x_confgen, name);
606
607 if(!IS_NULL_PTR(item))
608 return item->type;
609 else
610 return DT_STRING;
611}
612
614{
615 const dt_confgen_value_t *item = g_hash_table_lookup(darktable.conf->x_confgen, name);
616 if(IS_NULL_PTR(item))
617 return FALSE;
618
619 switch(kind)
620 {
621 case DT_DEFAULT:
622 return !IS_NULL_PTR(item->def);
623 case DT_MIN:
624 return !IS_NULL_PTR(item->min);
625 case DT_MAX:
626 return !IS_NULL_PTR(item->max);
627 case DT_VALUES:
628 return !IS_NULL_PTR(item->enum_values);
629 }
630 return FALSE;
631}
632
634{
635 const dt_confgen_value_t *item = g_hash_table_lookup(darktable.conf->x_confgen, name);
636
637 if(!IS_NULL_PTR(item))
638 {
639 switch(kind)
640 {
641 case DT_DEFAULT:
642 return item->def;
643 case DT_MIN:
644 return item->min;
645 case DT_MAX:
646 return item->max;
647 case DT_VALUES:
648 return item->enum_values;
649 }
650 }
651
652 return "";
653}
654
655const char *dt_confgen_get_label(const char *name)
656{
657 const dt_confgen_value_t *item = g_hash_table_lookup(darktable.conf->x_confgen, name);
658
659 if(!IS_NULL_PTR(item))
660 {
661 return item->shortdesc;
662 }
663
664 return "";
665}
666
667const char *dt_confgen_get_tooltip(const char *name)
668{
669 const dt_confgen_value_t *item = g_hash_table_lookup(darktable.conf->x_confgen, name);
670
671 if(!IS_NULL_PTR(item))
672 {
673 return item->longdesc;
674 }
675
676 return "";
677}
678
680{
682 {
683 //early bail
684 switch (kind)
685 {
686 case DT_MIN:
687 return INT_MIN;
688 break;
689 case DT_MAX:
690 return INT_MAX;
691 break;
692 default:
693 return 0;
694 break;
695 }
696 }
697 const char *str = dt_confgen_get(name, kind);
698
699 //if str is NULL or empty, dt_calculator_solve will return NAN
700 const float value = dt_calculator_solve(1, str);
701
702 switch (kind)
703 {
704 case DT_MIN:
705 return isnan(value) ? INT_MIN : (value > 0 ? value + 0.5f : value - 0.5f);
706 break;
707 case DT_MAX:
708 return isnan(value) ? INT_MAX : (value > 0 ? value + 0.5f : value - 0.5f);
709 break;
710 default:
711 return isnan(value) ? 0.0f : (value > 0 ? value + 0.5f : value - 0.5f);
712 break;
713 }
714 return (int)value;
715}
716
718{
720 {
721 //early bail
722 switch (kind)
723 {
724 case DT_MIN:
725 return INT64_MIN;
726 break;
727 case DT_MAX:
728 return INT64_MAX;
729 break;
730 default:
731 return 0;
732 break;
733 }
734 }
735 const char *str = dt_confgen_get(name, kind);
736
737 //if str is NULL or empty, dt_calculator_solve will return NAN
738 const float value = dt_calculator_solve(1, str);
739
740 switch (kind)
741 {
742 case DT_MIN:
743 return isnan(value) ? INT64_MIN : (value > 0 ? value + 0.5f : value - 0.5f);
744 break;
745 case DT_MAX:
746 return isnan(value) ? INT64_MAX : (value > 0 ? value + 0.5f : value - 0.5f);
747 break;
748 default:
749 return isnan(value) ? 0.0f : (value > 0 ? value + 0.5f : value - 0.5f);
750 break;
751 }
752 return (int64_t)value;
753}
754
756{
757 const char *str = dt_confgen_get(name, kind);
758 return !strcmp(str, "true");
759}
760
762{
764 {
765 //early bail
766 switch (kind)
767 {
768 case DT_MIN:
769 return -FLT_MAX;
770 break;
771 case DT_MAX:
772 return FLT_MAX;
773 break;
774 default:
775 break;
776 }
777 return 0.0f;
778 }
779
780 const char *str = dt_confgen_get(name, kind);
781
782 //if str is NULL or empty, dt_calculator_solve will return NAN
783 const float value = dt_calculator_solve(1, str);
784
785 switch (kind)
786 {
787 case DT_MIN:
788 // to anyone askig FLT_MIN is superclose to 0, not furthest value from 0 possible in float
789 return isnan(value) ? -FLT_MAX : value;
790 break;
791 case DT_MAX:
792 return isnan(value) ? FLT_MAX : value;
793 break;
794 default:
795 break;
796 }
797 return isnan(value) ? 0.0f : value;
798}
799
800gboolean dt_conf_is_default(const char *name)
801{
803 return TRUE; // well if default doesn't know about it, it's default
804
805 switch(dt_confgen_type(name))
806 {
807 case DT_INT:
809 break;
810 case DT_INT64:
812 break;
813 case DT_FLOAT:
815 break;
816 case DT_BOOL:
818 break;
819 case DT_PATH:
820 case DT_STRING:
821 case DT_ENUM:
822 default:
823 {
824 const char *def_val = dt_confgen_get(name, DT_DEFAULT);
825 const char *cur_val = dt_conf_get_var(name);
826 return g_strcmp0(def_val, cur_val) == 0;
827 break;
828 }
829 }
830}
831
832gchar* dt_conf_expand_default_dir(const char *dir)
833{
834 // expand special dirs
835#define CONFIG_DIR "$(config)"
836#define HOME_DIR "$(home)"
837
838 gchar *path = NULL;
839 if(g_str_has_prefix(dir, CONFIG_DIR))
840 {
841 gchar configdir[PATH_MAX] = { 0 };
842 dt_loc_get_user_config_dir(configdir, sizeof(configdir));
843 path = g_strdup_printf("%s%s", configdir, dir + strlen(CONFIG_DIR));
844 }
845 else if(g_str_has_prefix(dir, HOME_DIR))
846 {
847 gchar *homedir = dt_loc_get_home_dir(NULL);
848 path = g_strdup_printf("%s%s", homedir, dir + strlen(HOME_DIR));
849 dt_free(homedir);
850 }
851 else path = g_strdup(dir);
852
853 gchar *normalized_path = dt_util_normalize_path(path);
854 dt_free(path);
855
856 return normalized_path;
857}
858
859static void dt_conf_print(const gchar *key, const gchar *val, FILE *f)
860{
861 fprintf(f, "%s=%s\n", key, val);
862}
863
865{
866 FILE *f = g_fopen(cf->filename, "wb");
867 if(!IS_NULL_PTR(f))
868 {
869 GList *keys = g_hash_table_get_keys(cf->table);
870 GList *sorted = g_list_sort(keys, (GCompareFunc)g_strcmp0);
871
872 for(GList *iter = sorted; iter; iter = g_list_next(iter))
873 {
874 const gchar *key = (const gchar *)iter->data;
875 const gchar *val = (const gchar *)g_hash_table_lookup(cf->table, key);
876 dt_conf_print(key, val, f);
877 }
878
879 g_list_free(sorted);
880 sorted = NULL;
881 fclose(f);
882 }
883}
885{
886 dt_conf_save(cf);
887 g_hash_table_unref(cf->table);
888 g_hash_table_unref(cf->override_entries);
889 g_hash_table_unref(cf->x_confgen);
891}
892
893// clang-format off
894// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
895// vim: shiftwidth=2 expandtab tabstop=2 cindent
896// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
897// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
float dt_calculator_solve(const float x, const char *formula)
Definition calculator.c:322
static const dt_adaptation_t kind
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
const dt_aligned_pixel_t f
static const float const float const float min
const float max
char * key
char * name
dt_confgen_value_kind_t
Definition conf.h:95
@ DT_DEFAULT
Definition conf.h:96
@ DT_MAX
Definition conf.h:98
@ DT_MIN
Definition conf.h:97
@ DT_VALUES
Definition conf.h:99
dt_confgen_type_t
Definition conf.h:58
@ DT_BOOL
Definition conf.h:62
@ DT_STRING
Definition conf.h:64
@ DT_FLOAT
Definition conf.h:61
@ DT_INT64
Definition conf.h:60
@ DT_ENUM
Definition conf.h:65
@ DT_PATH
Definition conf.h:63
@ DT_INT
Definition conf.h:59
void dt_conf_cleanup(dt_conf_t *cf)
void dt_conf_string_entry_free(gpointer data)
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
#define HOME_DIR
int dt_conf_key_exists(const char *key)
float dt_confgen_get_float(const char *name, dt_confgen_value_kind_t kind)
int64_t dt_conf_get_int64_fast(const char *name)
static char * _sanitize_confgen(const char *name, const char *value)
void dt_conf_init(dt_conf_t *cf, const char *filename, GSList *override_entries)
void dt_conf_set_float(const char *name, float val)
float dt_conf_get_float(const char *name)
const char * dt_confgen_get_tooltip(const char *name)
static void _conf_add(char *key, char *val, dt_conf_dreggn_t *d)
static int dt_conf_set_if_not_overridden(const char *name, char *str)
gchar * dt_conf_get_string(const char *name)
int dt_conf_get_int_fast(const char *name)
int dt_conf_get_and_sanitize_int(const char *name, int min, int max)
static void _free_confgen_value(void *value)
void dt_conf_set_int(const char *name, int val)
gboolean dt_confgen_get_bool(const char *name, dt_confgen_value_kind_t kind)
void dt_conf_set_int64(const char *name, int64_t val)
gchar * dt_conf_expand_default_dir(const char *dir)
GSList * dt_conf_all_string_entries(const char *dir)
gboolean dt_conf_is_default(const char *name)
int dt_conf_get_int(const char *name)
int64_t dt_conf_get_int64(const char *name)
gboolean dt_confgen_value_exists(const char *name, dt_confgen_value_kind_t kind)
int64_t dt_confgen_get_int64(const char *name, dt_confgen_value_kind_t kind)
gboolean dt_confgen_exists(const char *name)
int dt_confgen_get_int(const char *name, dt_confgen_value_kind_t kind)
#define LINE_SIZE
void dt_conf_set_string(const char *name, const char *val)
float dt_conf_get_float_fast(const char *name)
const char * dt_conf_get_string_const(const char *name)
static char * dt_conf_get_var(const char *name)
const char * dt_confgen_get(const char *name, dt_confgen_value_kind_t kind)
#define CONFIG_DIR
void dt_conf_save(dt_conf_t *cf)
int64_t dt_conf_get_and_sanitize_int64(const char *name, int64_t min, int64_t max)
void dt_conf_set_folder_from_file_chooser(const char *name, GtkFileChooser *chooser)
dt_confgen_type_t dt_confgen_type(const char *name)
static void dt_conf_print(const gchar *key, const gchar *val, FILE *f)
gboolean dt_conf_is_equal(const char *name, const char *value)
const char * dt_confgen_get_label(const char *name)
gboolean dt_conf_get_folder_to_file_chooser(const char *name, GtkFileChooser *chooser)
float dt_conf_get_and_sanitize_float(const char *name, float min, float max)
gboolean dt_conf_key_not_empty(const char *name)
darktable_t darktable
Definition darktable.c:181
#define STR(x)
Definition darktable.h:170
static void dt_free_gpointer(gpointer ptr)
Definition darktable.h:463
#define dt_free(ptr)
Definition darktable.h:456
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
#define PATH_MAX
Definition darktable.h:1062
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:374
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Definition dtpthread.h:359
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:379
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:364
gchar * dt_loc_get_home_dir(const gchar *user)
void dt_loc_get_user_config_dir(char *configdir, size_t bufsize)
const float v
#define CLAMPS(A, L, H)
Definition math.h:76
struct dt_conf_t * conf
Definition darktable.h:769
const char * match
Definition conf.h:89
char * key
Definition conf.h:90
char * value
Definition conf.h:91
GHashTable * override_entries
Definition conf.h:85
char filename[PATH_MAX]
Definition conf.h:82
dt_pthread_mutex_t mutex
Definition conf.h:81
GHashTable * x_confgen
Definition conf.h:84
GHashTable * table
Definition conf.h:83
char * enum_values
Definition conf.h:74
char * shortdesc
Definition conf.h:75
dt_confgen_type_t type
Definition conf.h:70
char * longdesc
Definition conf.h:76
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29
gchar * dt_util_normalize_path(const gchar *_input)
Definition utility.c:680