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