gliv-1.7
[gliv.git] / src / rcfile.c
blob3a8998ef2d800dc97d7a876a69ee72bcafe38124
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * See the COPYING file for license information.
18 * Guillaume Chazarain <gfc@altern.org>
21 /***********************
22 * Configuration file. *
23 ***********************/
25 #include "gliv.h"
27 #ifndef HAVE_GETLINE
28 # include "../lib/getline.h"
29 #endif
31 #include <unistd.h> /* R_OK */
32 #include <stdio.h> /* FILE, f*(), perror(), getline() */
33 #include <string.h> /* strlen(), memcpy() */
35 static GHashTable *table = NULL;
36 static gboolean options_read = FALSE;
38 /* The link between options and the rcfile. */
39 static options_struct opts = {
40 /* Default options */
41 .fullscreen = FALSE,
42 .maximize = FALSE,
43 .scaledown = FALSE,
44 .menu_bar = TRUE,
45 .status_bar = TRUE,
46 .scrollbars = TRUE,
47 .zoom_pointer = FALSE,
48 .alpha_checks = TRUE,
49 .dither = FALSE,
50 .force = FALSE,
51 .build_menus = FALSE,
52 .mipmap = FALSE,
53 .mnemonics = FALSE,
54 .loop = FALSE,
55 .delay = 0,
56 .history_size = 1000,
57 .duration = 10,
58 .bg_col = {0, 0, 0},
59 .alpha1 = {0x6666, 0x6666, 0x6666},
60 .alpha2 = {0x9999, 0x9999, 0x9999}
63 typedef struct {
64 const gchar *name;
65 gint *option;
66 const gchar *comment;
67 const gboolean is_bool;
68 } option_struct;
70 /* *INDENT-OFF* */
71 static option_struct option_names[] = {
72 /* To fill the hash table and the configuration file. */
73 { "full-screen", &opts.fullscreen, N_("Start in full screen mode"), 1 },
74 { "maximize", &opts.maximize, N_("Maximize small images"), 1 },
75 { "scale-down", &opts.scaledown, N_("Scale down larges images"), 1 },
76 { "menu", &opts.menu_bar, N_("Display the menu bar"), 1 },
77 { "info", &opts.status_bar, N_("Display infos about the image"), 1 },
78 { "scrollbars", &opts.scrollbars, N_("Display scrollbars"), 1 },
79 { "zoom-pointer", &opts.zoom_pointer, N_("Zoom centered on pointer"), 1 },
80 { "alpha-checks", &opts.alpha_checks, N_("Alpha checks in the background"), 1 },
81 { "dither", &opts.dither, N_("Dithering"), 1 },
82 { "force-load", &opts.force, N_("Try to load every file"), 1 },
83 { "build-menus", &opts.build_menus, N_("Build images menus at startup"), 1 },
84 { "mipmap", &opts.mipmap, N_("Build Mipmaps"), 1 },
85 { "mnemonics", &opts.mnemonics, N_("Make mnemonics for images menus"),1 },
86 { "loop", &opts.loop, N_("Make the slide show loop"), 1 },
87 { "delay", &opts.delay, N_("Delay before hiding the cursor"), 0 },
88 { "history", &opts.history_size, N_("History length"), 0 },
89 { "slide-show", &opts.duration, N_("Delay between images"), 0 },
90 { "bg_col_red", opts.bg_col, N_("background: red channel"), 0 },
91 { "bg_col_green", opts.bg_col + 1, N_("background: green channel"), 0 },
92 { "bg_col_blue", opts.bg_col + 2, N_("background: blue channel"), 0 },
93 { "alpha1_red", opts.alpha1, N_("alpha1 tile: red channel"), 0 },
94 { "alpha1_green", opts.alpha1 + 1, N_("alpha1 tile: green channel"), 0 },
95 { "alpha1_blue", opts.alpha1 + 2, N_("alpha1 tile: blue channel"), 0 },
96 { "alpha2_red", opts.alpha2, N_("alpha2 tile: red channel"), 0 },
97 { "alpha2_green", opts.alpha2 + 1, N_("alpha2 tile: green channel"), 0 },
98 { "alpha2_blue", opts.alpha2 + 2, N_("alpha2 tile: blue channel"), 0 },
99 { NULL, NULL, NULL, 0 }
101 /* *INDENT-ON* */
104 * Maximum length of the option names, currently
105 * it is strlen("zoom-pointer") == 12.
106 * Used to indent the option file.
108 #define MAX_OPT_LEN 12
110 /* Between the options and the keyboard accelerators. */
111 #define SEPARATOR "==========\n"
113 static gchar *find_rcfile(gboolean test)
115 gchar *filename;
117 filename = g_build_filename(g_get_home_dir(), ".glivrc", NULL);
119 if (test == FALSE || g_file_test(filename, G_FILE_TEST_EXISTS))
120 /* When loading the file, we really try to access it. */
121 /* When saving, we just need the filename. */
122 return filename;
124 g_free(filename);
125 return NULL;
128 /*** Loading options. ***/
130 static void init_hash_table(void)
132 gint i;
134 table = g_hash_table_new(g_str_hash, g_str_equal);
136 for (i = 0; option_names[i].name != NULL; i++)
137 g_hash_table_insert(table, (gchar *) option_names[i].name,
138 &option_names[i]);
141 /* Processes spaces and '#'. */
142 static gchar *clean_str(const gchar * str)
144 gchar *new_str;
145 gchar *ptr;
147 new_str = g_new(gchar, strlen(str) + 1);
149 for (ptr = new_str; *str != '\n' && *str != '\0'; str++) {
150 if (*str == ' ')
151 continue;
153 if (*str == '#') {
154 g_free(new_str);
155 return NULL;
158 *ptr = *str;
159 ptr++;
161 *ptr = '\0';
163 new_str = g_renew(gchar, new_str, ptr - new_str + 1);
164 return new_str;
167 static void process_line(const gchar * line)
169 gchar **res;
170 option_struct *opt;
171 gchar *clean;
173 if (*line == '\n' || *line == '\0')
174 /* Skip this line. */
175 return;
177 clean = clean_str(line);
178 if (clean == NULL)
179 /* This line is a '#' comment. */
180 return;
182 /* res[0]: option name ; res[1]: value */
183 res = g_strsplit(clean, "=", 2);
185 g_free(clean);
187 if (res[0] != NULL && res[1] != NULL && res[2] == NULL) {
188 /* No error during split. */
189 opt = g_hash_table_lookup(table, res[0]);
191 if (opt != NULL) {
192 /* Option found. */
194 if (opt->is_bool) {
195 gboolean *bool;
197 bool = (gboolean *) opt->option;
198 *bool = g_strcasecmp(res[1], "true") ? FALSE : TRUE;
199 } else
200 /* opt->is_bool == FALSE */
201 *opt->option = (gint) g_strtod(res[1], NULL);
205 g_strfreev(res);
208 options_struct *load_rc(gboolean from_file)
210 gchar *filename;
211 FILE *file;
212 gchar *line = NULL;
213 size_t nb = 0;
215 if (from_file == FALSE)
216 return &opts;
218 init_hash_table();
220 filename = find_rcfile(TRUE);
221 if (filename == NULL)
222 return &opts;
224 file = fopen(filename, "r");
225 if (file == NULL) {
227 * Not very frequent because find_rcfile(TRUE)
228 * should have made us return.
230 perror(filename);
231 return &opts;
234 while (feof(file) == 0) {
235 getline(&line, &nb, file);
236 if (g_str_equal(line, SEPARATOR))
237 break;
239 process_line(line);
242 g_free(line);
243 fclose(file);
244 g_free(filename);
245 g_hash_table_destroy(table);
247 options_read = TRUE;
248 return &opts;
251 void load_accelerators(void)
253 gchar *filename;
254 FILE *file;
255 gchar *line = NULL;
256 size_t nb = 0;
258 if (options_read == FALSE)
259 return;
261 filename = find_rcfile(TRUE);
262 if (filename == NULL)
263 return;
265 file = fopen(filename, "r");
266 if (file == NULL) {
267 perror(filename);
268 return;
271 while (getline(&line, &nb, file) != -1 &&
272 g_str_equal(line, SEPARATOR) == FALSE);
274 fflush(file);
276 gtk_accel_map_load_fd(fileno(file));
278 fclose(file);
282 /*** Saving options. ***/
284 static void write_option_line(FILE * f, gint index)
286 gint i, value;
288 fputs(option_names[index].name, f);
290 for (i = strlen(option_names[index].name); i < MAX_OPT_LEN; i++)
291 fputc(' ', f);
293 value = *(option_names[index].option);
295 if (option_names[index].is_bool)
296 fprintf(f, " = %s\n\n", value ? "True" : "False");
297 else
298 fprintf(f, " = %d\n\n", value);
301 static void write_rc(gchar * filename)
303 FILE *file;
304 gint i;
306 file = fopen(filename, "w");
307 if (file == NULL) {
308 perror(filename);
309 return;
312 fprintf(file, _("# Configuration file for GLiv %s\n\n"), VERSION);
313 fputs(_("# Option names are case sensitive.\n"), file);
314 fputs(_("# Option values are case insensitive.\n\n"), file);
315 fputs(_("# Note: 'maximize = True' or 'scale-down = True'"
316 " implies 'full-screen = True'.\n\n"), file);
318 for (i = 0; option_names[i].name != NULL; i++) {
319 /* The comment line. */
320 fprintf(file, "# %s\n", _(option_names[i].comment));
322 /* The option line. */
323 write_option_line(file, i);
326 /* The separation between options and keyboard accelerators. */
327 fprintf(file, "%s\n", SEPARATOR);
328 fflush(file);
330 gtk_accel_map_save_fd(fileno(file));
332 fclose(file);
333 g_free(filename);
336 void save_rc(options_struct * opt)
338 memcpy(&opts, opt, sizeof(options_struct));
339 write_rc(find_rcfile(FALSE));