Introduce printf_term() macro and use it.
[geeqie.git] / src / rcfile.c
1 /*
2  * Geeqie
3  * (C) 2006 John Ellis
4  *
5  * Author: John Ellis
6  *
7  * This software is released under the GNU General Public License (GNU GPL).
8  * Please read the included file COPYING for more information.
9  * This software comes with no warranty of any kind, use at your own risk!
10  */
11
12 #include <glib/gstdio.h>
13 #include <errno.h>
14
15 #include "main.h"
16 #include "rcfile.h"
17
18 #include "bar_exif.h"
19 #include "filelist.h"
20 #include "secure_save.h"
21 #include "slideshow.h"
22 #include "ui_fileops.h"
23
24
25 /*
26  *-----------------------------------------------------------------------------
27  * line write/parse routines (private)
28  *-----------------------------------------------------------------------------
29  */ 
30  
31 /* 
32    returns text without quotes or NULL for empty or broken string
33    any text up to first '"' is skipped
34    tail is set to point at the char after the second '"'
35    or at the ending \0 
36    
37 */
38
39 gchar *quoted_value(const gchar *text, const gchar **tail)
40 {
41         const gchar *ptr;
42         gint c = 0;
43         gint l = strlen(text);
44         gchar *retval = NULL;
45         
46         if (tail) *tail = text;
47         
48         if (l == 0) return retval;
49
50         while (c < l && text[c] !='"') c++;
51         if (text[c] == '"')
52                 {
53                 gint e;
54                 c++;
55                 ptr = text + c;
56                 e = c;
57                 while (e < l)
58                         {
59                         if (text[e-1] != '\\' && text[e] == '"') break;
60                         e++;
61                         }
62                 if (text[e] == '"')
63                         {
64                         if (e - c > 0)
65                                 {
66                                 gchar *substring = g_strndup(ptr, e - c);
67                                 
68                                 if (substring)
69                                         {
70                                         retval = g_strcompress(substring);
71                                         g_free(substring);
72                                         }
73                                 }
74                         }
75                 if (tail) *tail = text + e + 1;
76                 }
77         else
78                 /* for compatibility with older formats (<0.3.7)
79                  * read a line without quotes too */
80                 {
81                 c = 0;
82                 while (c < l && text[c] !=' ' && text[c] !=8 && text[c] != '\n') c++;
83                 if (c != 0)
84                         {
85                         retval = g_strndup(text, c);
86                         }
87                 if (tail) *tail = text + c;
88                 }
89
90         return retval;
91 }
92
93 gchar *escquote_value(const gchar *text)
94 {
95         gchar *e;
96         
97         if (!text) return g_strdup("\"\"");
98
99         e = g_strescape(text, "");
100         if (e)
101                 {
102                 gchar *retval = g_strdup_printf("\"%s\"", e);
103                 g_free(e);
104                 return retval;
105                 }
106         return g_strdup("\"\"");
107 }
108
109 static void write_char_option(SecureSaveInfo *ssi, gchar *label, gchar *text)
110 {
111         gchar *escval = escquote_value(text);
112
113         secure_fprintf(ssi, "%s: %s\n", label, escval);
114         g_free(escval);
115 }
116
117 static void read_char_option(FILE *f, gchar *option, gchar *label, gchar *value, gchar **text)
118 {
119         if (text && strcasecmp(option, label) == 0)
120                 {
121                 g_free(*text);
122                 *text = quoted_value(value, NULL);
123                 }
124 }
125
126 /* Since gdk_color_to_string() is only available since gtk 2.12
127  * here is an equivalent stub function. */
128 static gchar *color_to_string(GdkColor *color)
129 {
130         return g_strdup_printf("#%04X%04X%04X", color->red, color->green, color->blue);
131 }
132
133 static void write_color_option(SecureSaveInfo *ssi, gchar *label, GdkColor *color)
134 {
135         if (color)
136                 {
137                 gchar *colorstring = color_to_string(color);
138
139                 write_char_option(ssi, label, colorstring);
140                 g_free(colorstring);
141                 }
142         else
143                 secure_fprintf(ssi, "%s: \n", label);
144 }
145
146 static void read_color_option(FILE *f, gchar *option, gchar *label, gchar *value, GdkColor *color)
147 {
148         if (color && strcasecmp(option, label) == 0)
149                 {
150                 gchar *colorstr = quoted_value(value, NULL);
151                 if (colorstr) gdk_color_parse(colorstr, color);
152                 g_free(colorstr);
153                 }
154 }
155
156
157 static void write_int_option(SecureSaveInfo *ssi, gchar *label, gint n)
158 {
159         secure_fprintf(ssi, "%s: %d\n", label, n);
160 }
161
162 static void read_int_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n)
163 {
164         if (n && strcasecmp(option, label) == 0)
165                 {
166                 *n = strtol(value, NULL, 10);
167                 }
168 }
169
170 static void write_uint_option(SecureSaveInfo *ssi, gchar *label, guint n)
171 {
172         secure_fprintf(ssi, "%s: %u\n", label, n);
173 }
174
175 static void read_uint_option(FILE *f, gchar *option, gchar *label, gchar *value, guint *n)
176 {
177         if (n && strcasecmp(option, label) == 0)
178                 {
179                 *n = strtoul(value, NULL, 10);
180                 }
181 }
182
183
184
185 static void read_int_option_clamp(FILE *f, gchar *option, gchar *label, gchar *value, gint *n, gint min, gint max)
186 {
187         if (n && strcasecmp(option, label) == 0)
188                 {
189                 *n = CLAMP(strtol(value, NULL, 10), min, max);
190                 }
191 }
192
193
194 static void write_int_unit_option(SecureSaveInfo *ssi, gchar *label, gint n, gint subunits)
195 {
196         gint l, r;
197
198         if (subunits > 0)
199                 {
200                 l = n / subunits;
201                 r = n % subunits;
202                 }
203         else
204                 {
205                 l = n;
206                 r = 0;
207                 }
208
209         secure_fprintf(ssi, "%s: %d.%d\n", label, l, r);
210 }
211
212 static void read_int_unit_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n, gint subunits)
213 {
214         if (n && strcasecmp(option, label) == 0)
215                 {
216                 gint l, r;
217                 gchar *ptr;
218
219                 ptr = value;
220                 while (*ptr != '\0' && *ptr != '.') ptr++;
221                 if (*ptr == '.')
222                         {
223                         *ptr = '\0';
224                         l = strtol(value, NULL, 10);
225                         *ptr = '.';
226                         ptr++;
227                         r = strtol(ptr, NULL, 10);
228                         }
229                 else
230                         {
231                         l = strtol(value, NULL, 10);
232                         r = 0;
233                         }
234
235                 *n = l * subunits + r;
236                 }
237 }
238
239 static void write_bool_option(SecureSaveInfo *ssi, gchar *label, gint n)
240 {
241         secure_fprintf(ssi, "%s: ", label);
242         if (n) secure_fprintf(ssi, "true\n"); else secure_fprintf(ssi, "false\n");
243 }
244
245 static void read_bool_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n)
246 {
247         if (n && strcasecmp(option, label) == 0)
248                 {
249                 if (strcasecmp(value, "true") == 0 || strcmp(value, "1") == 0)
250                         *n = TRUE;
251                 else
252                         *n = FALSE;
253                 }
254 }
255
256 /*
257  *-----------------------------------------------------------------------------
258  * save configuration (public)
259  *-----------------------------------------------------------------------------
260  */ 
261
262 void save_options(void)
263 {
264         SecureSaveInfo *ssi;
265         gchar *rc_path;
266         gchar *rc_pathl;
267         gint i;
268
269         rc_path = g_strconcat(homedir(), "/", GQ_RC_DIR, "/", RC_FILE_NAME, NULL);
270
271         rc_pathl = path_from_utf8(rc_path);
272         ssi = secure_open(rc_pathl);
273         g_free(rc_pathl);
274         if (!ssi)
275                 {
276                 printf_term(_("error saving config file: %s\n"), rc_path);
277                 g_free(rc_path);
278                 return;
279                 }
280         
281 #define WRITE_BOOL(_name_) write_bool_option(ssi, #_name_, options->_name_)
282 #define WRITE_INT(_name_) write_int_option(ssi, #_name_, options->_name_)
283 #define WRITE_UINT(_name_) write_uint_option(ssi, #_name_, options->_name_)
284 #define WRITE_INT_UNIT(_name_, _unit_) write_int_unit_option(ssi, #_name_, options->_name_, _unit_)
285 #define WRITE_CHAR(_name_) write_char_option(ssi, #_name_, options->_name_)
286 #define WRITE_COLOR(_name_) write_color_option(ssi, #_name_, &options->_name_)
287
288 #define WRITE_SEPARATOR() secure_fputc(ssi, '\n')
289 #define WRITE_SUBTITLE(_title_) secure_fprintf(ssi, "\n\n##### "_title_" #####\n\n")
290
291         secure_fprintf(ssi, "######################################################################\n");
292         secure_fprintf(ssi, "# %30s config file         version %7s #\n", GQ_APPNAME, VERSION);
293         secure_fprintf(ssi, "######################################################################\n");
294         WRITE_SEPARATOR();
295
296         secure_fprintf(ssi, "# Note: This file is autogenerated. Options can be changed here,\n");
297         secure_fprintf(ssi, "#       but user comments and formatting will be lost.\n");
298         WRITE_SEPARATOR();
299
300         WRITE_SUBTITLE("General Options");
301
302         WRITE_BOOL(show_icon_names);
303         WRITE_SEPARATOR();
304
305         WRITE_BOOL(tree_descend_subdirs);
306         WRITE_BOOL(lazy_image_sync);
307         WRITE_BOOL(update_on_time_change);
308         WRITE_SEPARATOR();
309
310         WRITE_BOOL(startup_path_enable);
311         WRITE_CHAR(startup_path);
312
313         WRITE_BOOL(progressive_key_scrolling);
314         WRITE_BOOL(enable_metadata_dirs);
315
316         WRITE_INT(duplicates_similarity_threshold);
317         WRITE_SEPARATOR();
318
319         WRITE_BOOL(mousewheel_scrolls);
320         WRITE_INT(open_recent_list_maxsize);
321         WRITE_BOOL(place_dialogs_under_mouse);
322
323
324         WRITE_SUBTITLE("File operations Options");
325
326         WRITE_BOOL(file_ops.enable_in_place_rename);
327         WRITE_BOOL(file_ops.confirm_delete);
328         WRITE_BOOL(file_ops.enable_delete_key);
329         WRITE_BOOL(file_ops.safe_delete_enable);
330         WRITE_CHAR(file_ops.safe_delete_path);
331         WRITE_INT(file_ops.safe_delete_folder_maxsize);
332
333         
334         WRITE_SUBTITLE("Layout Options");
335
336         WRITE_INT(layout.style);
337         WRITE_CHAR(layout.order);
338         WRITE_BOOL(layout.view_as_icons);
339         WRITE_UINT(layout.dir_view_type);
340         WRITE_BOOL(layout.show_thumbnails);
341         WRITE_SEPARATOR();
342
343         WRITE_BOOL(layout.save_window_positions);
344         WRITE_SEPARATOR();
345
346         WRITE_INT(layout.main_window.x);
347         WRITE_INT(layout.main_window.y);
348         WRITE_INT(layout.main_window.w);
349         WRITE_INT(layout.main_window.h);
350         WRITE_BOOL(layout.main_window.maximized);
351         WRITE_INT(layout.main_window.hdivider_pos);
352         WRITE_INT(layout.main_window.vdivider_pos);
353         WRITE_SEPARATOR();
354
355         WRITE_INT(layout.float_window.x);
356         WRITE_INT(layout.float_window.y);
357         WRITE_INT(layout.float_window.w);
358         WRITE_INT(layout.float_window.h);
359         WRITE_INT(layout.float_window.vdivider_pos);
360         WRITE_SEPARATOR();
361
362         WRITE_BOOL(layout.tools_float);
363         WRITE_BOOL(layout.tools_hidden);
364         WRITE_BOOL(layout.tools_restore_state);
365         WRITE_SEPARATOR();
366
367         WRITE_BOOL(layout.toolbar_hidden);
368
369
370         WRITE_SUBTITLE("Image Options");
371         
372         secure_fprintf(ssi, "# image.zoom_mode possible values are:\n"
373                             "#   original\n"
374                             "#   fit\n"
375                             "#   dont_change\n");
376         secure_fprintf(ssi, "image.zoom_mode: ");
377         if (options->image.zoom_mode == ZOOM_RESET_ORIGINAL)
378                 secure_fprintf(ssi, "original\n");
379         else if (options->image.zoom_mode == ZOOM_RESET_FIT_WINDOW)
380                 secure_fprintf(ssi, "fit\n");
381         else if (options->image.zoom_mode == ZOOM_RESET_NONE)
382                 secure_fprintf(ssi, "dont_change\n");
383         WRITE_SEPARATOR();
384         WRITE_BOOL(image.zoom_2pass);
385         WRITE_BOOL(image.zoom_to_fit_allow_expand);
386         WRITE_INT(image.zoom_quality);
387         WRITE_INT(image.zoom_increment);
388         WRITE_BOOL(image.fit_window_to_image);
389         WRITE_BOOL(image.limit_window_size);
390         WRITE_INT(image.max_window_size);
391         WRITE_BOOL(image.limit_autofit_size);
392         WRITE_INT(image.max_autofit_size);
393         WRITE_INT(image.scroll_reset_method);
394         WRITE_INT(image.tile_cache_max);
395         WRITE_INT(image.dither_quality);
396         WRITE_BOOL(image.enable_read_ahead);
397         WRITE_BOOL(image.exif_rotate_enable);
398         WRITE_BOOL(image.use_custom_border_color);
399         WRITE_COLOR(image.border_color);
400
401
402         WRITE_SUBTITLE("Thumbnails Options");
403
404         WRITE_INT(thumbnails.max_width);
405         WRITE_INT(thumbnails.max_height);
406         WRITE_BOOL(thumbnails.enable_caching);
407         WRITE_BOOL(thumbnails.cache_into_dirs);
408         WRITE_BOOL(thumbnails.fast);
409         WRITE_BOOL(thumbnails.use_xvpics);
410         WRITE_BOOL(thumbnails.spec_standard);
411         WRITE_INT(thumbnails.quality);
412
413
414         WRITE_SUBTITLE("File sorting Options");
415
416         WRITE_INT(file_sort.method);
417         WRITE_BOOL(file_sort.ascending);
418         WRITE_BOOL(file_sort.case_sensitive);
419
420         
421         WRITE_SUBTITLE("Fullscreen Options");
422
423         WRITE_INT(fullscreen.screen);
424         WRITE_BOOL(fullscreen.clean_flip);
425         WRITE_BOOL(fullscreen.disable_saver);
426         WRITE_BOOL(fullscreen.above);
427         WRITE_BOOL(fullscreen.show_info);
428         WRITE_CHAR(fullscreen.info);
429
430         WRITE_SUBTITLE("Slideshow Options");
431
432         WRITE_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
433         WRITE_BOOL(slideshow.random);
434         WRITE_BOOL(slideshow.repeat);
435
436
437         WRITE_SUBTITLE("Collection Options");
438
439         WRITE_BOOL(collections.rectangular_selection);
440
441
442         WRITE_SUBTITLE("Filtering Options");
443
444         WRITE_BOOL(file_filter.show_hidden_files);
445         WRITE_BOOL(file_filter.show_dot_directory);
446         WRITE_BOOL(file_filter.disable);
447         WRITE_SEPARATOR();
448
449         filter_write_list(ssi);
450         
451
452         WRITE_SUBTITLE("Sidecars Options");
453
454         sidecar_ext_write(ssi);
455
456
457         WRITE_SUBTITLE("Color Profiles");
458
459 #ifndef HAVE_LCMS
460         secure_fprintf(ssi, "# NOTICE: %s was not built with support for color profiles,\n"
461                             "#         color profile options will have no effect.\n\n", GQ_APPNAME);
462 #endif
463
464         WRITE_BOOL(color_profile.enabled);
465         WRITE_BOOL(color_profile.use_image);
466         WRITE_INT(color_profile.input_type);
467         WRITE_SEPARATOR();
468
469         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
470                 {
471                 gchar *buf;
472
473                 buf = g_strdup_printf("color_profile.input_file_%d", i + 1);
474                 write_char_option(ssi, buf, options->color_profile.input_file[i]);
475                 g_free(buf);
476
477                 buf = g_strdup_printf("color_profile.input_name_%d", i + 1);
478                 write_char_option(ssi, buf, options->color_profile.input_name[i]);
479                 g_free(buf);
480                 }
481
482         WRITE_SEPARATOR();
483         WRITE_INT(color_profile.screen_type);
484         WRITE_CHAR(color_profile.screen_file);
485
486         WRITE_SUBTITLE("External Programs");
487         secure_fprintf(ssi, "# Maximum of %d programs (external_1 through external_%d)\n", GQ_EDITOR_GENERIC_SLOTS, GQ_EDITOR_GENERIC_SLOTS);
488         secure_fprintf(ssi, "# external_%d through external_%d are used for file ops\n", GQ_EDITOR_GENERIC_SLOTS + 1, GQ_EDITOR_SLOTS);
489         secure_fprintf(ssi, "# format: external_n: \"menu name\" \"command line\"\n\n");
490
491         for (i = 0; i < GQ_EDITOR_SLOTS; i++)
492                 {
493                 if (i == GQ_EDITOR_GENERIC_SLOTS) secure_fputc(ssi, '\n');
494                 gchar *qname = escquote_value(options->editor_name[i]);
495                 gchar *qcommand = escquote_value(options->editor_command[i]);
496                 secure_fprintf(ssi, "external_%d: %s %s\n", i+1, qname, qcommand);
497                 g_free(qname);
498                 g_free(qcommand);
499                 }
500
501
502         WRITE_SUBTITLE("Exif Options");
503         secure_fprintf(ssi, "# Display: 0: never\n"
504                             "#          1: if set\n"
505                             "#          2: always\n\n");
506         for (i = 0; ExifUIList[i].key; i++)
507                 {
508                 secure_fprintf(ssi, "exif.display.");
509                 write_int_option(ssi, (gchar *)ExifUIList[i].key, ExifUIList[i].current);
510                 }
511
512         WRITE_SEPARATOR();
513         WRITE_SEPARATOR();
514
515         secure_fprintf(ssi, "######################################################################\n");
516         secure_fprintf(ssi, "#                         end of config file                         #\n");
517         secure_fprintf(ssi, "######################################################################\n");
518
519         
520         if (secure_close(ssi))
521                 {
522                 printf_term(_("error saving config file: %s\nerror: %s\n"), rc_path,
523                             secsave_strerror(secsave_errno));
524                 g_free(rc_path);
525                 return;
526                 }
527
528         g_free(rc_path);
529 }
530
531 /*
532  *-----------------------------------------------------------------------------
533  * load configuration (public)
534  *-----------------------------------------------------------------------------
535  */ 
536
537 void load_options(void)
538 {
539         FILE *f;
540         gchar *rc_path;
541         gchar *rc_pathl;
542         gchar s_buf[1024];
543         gchar option[1024];
544         gchar value[1024];
545         gchar value_all[1024];
546         gint i;
547
548         for (i = 0; ExifUIList[i].key; i++)
549                 ExifUIList[i].current = ExifUIList[i].default_value;
550
551         rc_path = g_strconcat(homedir(), "/", GQ_RC_DIR, "/", RC_FILE_NAME, NULL);
552
553         rc_pathl = path_from_utf8(rc_path);
554         f = fopen(rc_pathl,"r");
555         g_free(rc_pathl);
556         if (!f)
557                 {
558                 g_free(rc_path);
559                 return;
560                 }
561
562         while (fgets(s_buf, sizeof(s_buf), f))
563                 {
564                 gchar *option_start, *value_start;
565                 gchar *p = s_buf;
566
567                 while(g_ascii_isspace(*p)) p++;
568                 if (!*p || *p == '\n' || *p == '#') continue;
569                 option_start = p;
570                 while(*p && *p != ':') p++;
571                 if (!*p) continue;
572                 *p = '\0';
573                 p++;
574                 strncpy(option, option_start, sizeof(option));
575                 while(g_ascii_isspace(*p)) p++;
576                 value_start = p;
577                 strncpy(value_all, value_start, sizeof(value_all));
578                 while(*p && !g_ascii_isspace(*p) && *p != '\n') p++;
579                 *p = '\0';
580                 strncpy(value, value_start, sizeof(value));
581
582 #define READ_BOOL(_name_) read_bool_option(f, option, #_name_, value, &options->_name_)
583 #define READ_INT(_name_) read_int_option(f, option, #_name_, value, &options->_name_)
584 #define READ_UINT(_name_) read_uint_option(f, option, #_name_, value, &options->_name_)
585 #define READ_INT_CLAMP(_name_, _min_, _max_) read_int_option_clamp(f, option, #_name_, value, &options->_name_, _min_, _max_)
586 #define READ_INT_UNIT(_name_, _unit_) read_int_unit_option(f, option, #_name_, value, &options->_name_, _unit_)
587 #define READ_CHAR(_name_) read_char_option(f, option, #_name_, value_all, &options->_name_)
588 #define READ_COLOR(_name_) read_color_option(f, option, #_name_, value, &options->_name_)
589
590                 /* general options */
591                 READ_BOOL(show_icon_names);
592
593                 READ_BOOL(tree_descend_subdirs);
594                 READ_BOOL(lazy_image_sync);
595                 READ_BOOL(update_on_time_change);
596         
597                 READ_BOOL(startup_path_enable);
598                 READ_CHAR(startup_path);
599
600                 READ_INT(duplicates_similarity_threshold);
601
602                 READ_BOOL(progressive_key_scrolling);
603
604                 READ_BOOL(enable_metadata_dirs);
605
606                 READ_BOOL(mousewheel_scrolls);
607         
608                 READ_INT(open_recent_list_maxsize);
609
610                 READ_BOOL(place_dialogs_under_mouse);
611
612
613                 /* layout options */
614
615                 READ_INT(layout.style);
616                 READ_CHAR(layout.order);
617                 READ_BOOL(layout.view_as_icons);
618                 READ_UINT(layout.dir_view_type);
619                 READ_BOOL(layout.show_thumbnails);
620
621                 /* window positions */
622
623                 READ_BOOL(layout.save_window_positions);
624
625                 READ_INT(layout.main_window.x);
626                 READ_INT(layout.main_window.y);
627                 READ_INT(layout.main_window.w);
628                 READ_INT(layout.main_window.h);
629                 READ_BOOL(layout.main_window.maximized);
630                 READ_INT(layout.float_window.x);
631                 READ_INT(layout.float_window.y);
632                 READ_INT(layout.float_window.w);
633                 READ_INT(layout.float_window.h);
634                 READ_INT(layout.float_window.vdivider_pos);
635                 READ_INT(layout.main_window.hdivider_pos);
636                 READ_INT(layout.main_window.vdivider_pos);
637                 READ_BOOL(layout.tools_float);
638                 READ_BOOL(layout.tools_hidden);
639                 READ_BOOL(layout.tools_restore_state);
640                 READ_BOOL(layout.toolbar_hidden);
641
642
643                 /* image options */
644                 if (strcasecmp(option, "image.zoom_mode") == 0)
645                         {
646                         if (strcasecmp(value, "original") == 0)
647                                 options->image.zoom_mode = ZOOM_RESET_ORIGINAL;
648                         else if (strcasecmp(value, "fit") == 0)
649                                 options->image.zoom_mode = ZOOM_RESET_FIT_WINDOW;
650                         else if (strcasecmp(value, "dont_change") == 0)
651                                 options->image.zoom_mode = ZOOM_RESET_NONE;
652                         }
653                 READ_BOOL(image.zoom_2pass);
654                 READ_BOOL(image.zoom_to_fit_allow_expand);
655                 READ_BOOL(image.fit_window_to_image);
656                 READ_BOOL(image.limit_window_size);
657                 READ_INT(image.max_window_size);
658                 READ_BOOL(image.limit_autofit_size);
659                 READ_INT(image.max_autofit_size);
660                 READ_INT(image.scroll_reset_method);
661                 READ_INT(image.tile_cache_max);
662                 READ_INT_CLAMP(image.zoom_quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
663                 READ_INT_CLAMP(image.dither_quality, GDK_RGB_DITHER_NONE, GDK_RGB_DITHER_MAX);
664                 READ_INT(image.zoom_increment);
665                 READ_BOOL(image.enable_read_ahead);
666                 READ_BOOL(image.exif_rotate_enable);
667                 READ_BOOL(image.use_custom_border_color);
668                 READ_COLOR(image.border_color);
669
670
671                 /* thumbnails options */
672                 READ_INT_CLAMP(thumbnails.max_width, 16, 512);
673                 READ_INT_CLAMP(thumbnails.max_height, 16, 512);
674
675                 READ_BOOL(thumbnails.enable_caching);
676                 READ_BOOL(thumbnails.cache_into_dirs);
677                 READ_BOOL(thumbnails.fast);
678                 READ_BOOL(thumbnails.use_xvpics);
679                 READ_BOOL(thumbnails.spec_standard);
680                 READ_INT_CLAMP(thumbnails.quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
681
682                 /* file sorting options */
683                 READ_UINT(file_sort.method);
684                 READ_BOOL(file_sort.ascending);
685                 READ_BOOL(file_sort.case_sensitive);
686
687                 /* file operations options */
688                 READ_BOOL(file_ops.enable_in_place_rename);
689                 READ_BOOL(file_ops.confirm_delete);
690                 READ_BOOL(file_ops.enable_delete_key);
691                 READ_BOOL(file_ops.safe_delete_enable);
692                 READ_CHAR(file_ops.safe_delete_path);
693                 READ_INT(file_ops.safe_delete_folder_maxsize);
694
695                 /* fullscreen options */
696                 READ_INT(fullscreen.screen);
697                 READ_BOOL(fullscreen.clean_flip);
698                 READ_BOOL(fullscreen.disable_saver);
699                 READ_BOOL(fullscreen.above);
700                 READ_BOOL(fullscreen.show_info);
701                 READ_CHAR(fullscreen.info);
702
703                 /* slideshow options */
704
705                 READ_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
706                 READ_BOOL(slideshow.random);
707                 READ_BOOL(slideshow.repeat);
708
709                 /* collection options */
710
711                 READ_BOOL(collections.rectangular_selection);
712
713                 /* filtering options */
714
715                 READ_BOOL(file_filter.show_hidden_files);
716                 READ_BOOL(file_filter.show_dot_directory);
717                 READ_BOOL(file_filter.disable);
718
719                 if (strcasecmp(option, "file_filter.ext") == 0)
720                         {
721                         filter_parse(value_all);
722                         }
723
724                 if (strcasecmp(option, "sidecar.ext") == 0)
725                         {
726                         sidecar_ext_parse(value_all, TRUE);
727                         }
728                 
729                 /* Color Profiles */
730
731                 READ_BOOL(color_profile.enabled);
732                 READ_BOOL(color_profile.use_image);
733                 READ_INT(color_profile.input_type);
734
735                 if (strncasecmp(option, "color_profile.input_file_", 25) == 0)
736                         {
737                         i = strtol(option + 25, NULL, 0) - 1;
738                         if (i >= 0 && i < COLOR_PROFILE_INPUTS)
739                                 {
740                                 read_char_option(f, option, option, value, &options->color_profile.input_file[i]);
741                                 }
742                         }
743                 if (strncasecmp(option, "color_profile.input_name_", 25) == 0)
744                         {
745                         i = strtol(option + 25, NULL, 0) - 1;
746                         if (i >= 0 && i < COLOR_PROFILE_INPUTS)
747                                 {
748                                 read_char_option(f, option, option, value, &options->color_profile.input_name[i]);
749                                 }
750                         }
751
752                 READ_INT(color_profile.screen_type);
753                 READ_CHAR(color_profile.screen_file);
754
755                 /* External Programs */
756
757                 if (strncasecmp(option, "external_", 9) == 0)
758                         {
759                         i = strtol(option + 9, NULL, 0);
760                         if (i > 0 && i <= GQ_EDITOR_SLOTS)
761                                 {
762                                 const gchar *ptr;
763                                 i--;
764                                 g_free(options->editor_name[i]);
765                                 g_free(options->editor_command[i]);
766                                 
767                                 options->editor_name[i] = quoted_value(value_all, &ptr);
768                                 options->editor_command[i] = quoted_value(ptr, NULL);
769                                 }
770                         }
771
772                 /* Exif */
773                 if (0 == strncasecmp(option, "exif.display.", 13))
774                         {
775                         for (i = 0; ExifUIList[i].key; i++)
776                                 if (0 == strcasecmp(option + 13, ExifUIList[i].key))
777                                         ExifUIList[i].current = strtol(value, NULL, 10);
778                         }
779                 }
780
781         fclose(f);
782         g_free(rc_path);
783 }
784