1 /* Config file manipulation */
10 #include <sys/types.h>
11 #include <sys/stat.h> /* OS/2 needs this after sys/types.h */
13 #include <fcntl.h> /* OS/2 needs this after sys/types.h */
21 #include "config/conf.h"
22 #include "config/dialogs.h"
23 #include "config/home.h"
24 #include "config/kbdbind.h"
25 #include "config/options.h"
26 #include "config/opttypes.h"
27 #include "intl/gettext/libintl.h"
28 #include "osdep/osdep.h"
29 #include "terminal/terminal.h"
30 #include "util/error.h"
31 #include "util/memory.h"
32 #include "util/secsave.h"
33 #include "util/string.h"
36 /* Config file has only very simple grammar:
38 * /set *option *= *value/
39 * /bind *keymap *keystroke *= *action/
43 * Where option consists from any number of categories separated by dots and
44 * name of the option itself. Both category and option name consists from
45 * [a-zA-Z0-9_-*] - using uppercase letters is not recommended, though. '*' is
46 * reserved and is used only as escape character in place of '.' originally in
49 * Value can consist from:
50 * - number (it will be converted to int/long)
51 * - enum (like on, off; true, fake, last_url; etc ;) - in planning state yet
52 * - string - "blah blah" (keymap, keystroke and action and file looks like that too)
54 * "set" command is parsed first, and then type-specific function is called,
55 * with option as one parameter and value as a second. Usually it just assigns
56 * value to an option, but sometimes you may want to first create the option
57 * ;). Then this will come handy. */
59 struct conf_parsing_state
{
60 /** This part may be copied to a local variable as a bookmark
61 * and restored later. So it must not contain any pointers
62 * that would have to be freed in that situation. */
63 struct conf_parsing_pos
{
64 /** Points to the next character to be parsed from the
65 * configuration file. */
68 /** The line number corresponding to #look. This is
69 * shown in error messages. */
73 /** When ELinks is rewriting the configuration file, @c mirrored
74 * indicates the end of the part that has already been copied
75 * to the mirror string. Otherwise, @c mirrored is not used.
77 * @invariant @c mirrored @<= @c pos.look */
78 unsigned char *mirrored
;
80 /** File name for error messages. If NULL then do not display
82 const unsigned char *filename
;
85 /** Tell the user about an error in the configuration file.
86 * @return @a err, for convenience. */
87 static enum parse_error
88 show_parse_error(const struct conf_parsing_state
*state
, enum parse_error err
)
90 static const unsigned char error_msg
[][40] = {
91 "no error", /* ERROR_NONE */
92 "unknown command", /* ERROR_COMMAND */
93 "parse error", /* ERROR_PARSE */
94 "unknown option", /* ERROR_OPTION */
95 "bad value", /* ERROR_VALUE */
96 "no memory left", /* ERROR_NOMEM */
99 if (state
->filename
) {
100 fprintf(stderr
, "%s:%d: %s\n",
101 state
->filename
, state
->pos
.line
, error_msg
[err
]);
106 /** Skip comments and whitespace. */
108 skip_white(struct conf_parsing_pos
*pos
)
110 unsigned char *start
= pos
->look
;
113 while (isspace(*start
)) {
114 if (*start
== '\n') {
121 start
+= strcspn(start
, "\n");
131 /** Skip a quoted string.
132 * This function allows "mismatching quotes' because str_rd() does so. */
134 skip_quoted(struct conf_parsing_pos
*pos
)
136 assert(isquote(*pos
->look
));
137 if_assert_failed
return;
143 if (isquote(*pos
->look
)) {
147 if (*pos
->look
== '\\' && pos
->look
[1])
149 if (*pos
->look
== '\n')
155 /** Skip the value of an option.
157 * This job is normally done by the reader function that corresponds
158 * to the type of the option. However, if ELinks does not recognize
159 * the name of the option, it cannot look up the type and has to use
160 * this function instead. */
162 skip_option_value(struct conf_parsing_pos
*pos
)
164 if (isquote(*pos
->look
)) {
165 /* Looks like OPT_STRING, OPT_CODEPAGE, OPT_LANGUAGE,
169 /* Looks like OPT_BOOL, OPT_INT, or OPT_LONG. */
170 while (isasciialnum(*pos
->look
) || *pos
->look
== '.'
171 || *pos
->look
== '+' || *pos
->look
== '-')
176 /** Skip to the next newline or comment that is not part of a quoted
177 * string. When ELinks hits a parse error in the configuration file,
178 * it calls this in order to find the place where is should resume
179 * parsing. This is intended to prevent ELinks from treating words
180 * in strings as commands. */
182 skip_to_unquoted_newline_or_comment(struct conf_parsing_pos
*pos
)
184 while (*pos
->look
&& *pos
->look
!= '#' && *pos
->look
!= '\n') {
185 if (isquote(*pos
->look
))
192 /* Parse a command. Returns error code. */
193 /* If dynamic string credentials are supplied, we will mirror the command at
194 * the end of the string; however, we won't load the option value to the tree,
195 * and we will even write option value from the tree to the output string.
196 * We will only possibly set or clear OPT_MUST_SAVE flag in the option. */
198 static enum parse_error
199 parse_set(struct option
*opt_tree
, struct conf_parsing_state
*state
,
200 struct string
*mirror
, int is_system_conf
)
202 const unsigned char *optname_orig
;
204 unsigned char *optname_copy
;
206 skip_white(&state
->pos
);
207 if (!*state
->pos
.look
) return show_parse_error(state
, ERROR_PARSE
);
210 optname_orig
= state
->pos
.look
;
211 while (isident(*state
->pos
.look
) || *state
->pos
.look
== '*'
212 || *state
->pos
.look
== '.' || *state
->pos
.look
== '+')
214 optname_len
= state
->pos
.look
- optname_orig
;
216 skip_white(&state
->pos
);
219 if (*state
->pos
.look
!= '=')
220 return show_parse_error(state
, ERROR_PARSE
);
221 state
->pos
.look
++; /* '=' */
222 skip_white(&state
->pos
);
223 if (!*state
->pos
.look
)
224 return show_parse_error(state
, ERROR_VALUE
);
226 optname_copy
= memacpy(optname_orig
, optname_len
);
227 if (!optname_copy
) return show_parse_error(state
, ERROR_NOMEM
);
233 const struct conf_parsing_pos pos_before_value
= state
->pos
;
236 ? get_opt_rec_real(opt_tree
, optname_copy
)
237 : get_opt_rec(opt_tree
, optname_copy
);
238 mem_free(optname_copy
);
241 if (!opt
|| (opt
->flags
& OPT_HIDDEN
)) {
242 show_parse_error(state
, ERROR_OPTION
);
243 skip_option_value(&state
->pos
);
245 /* TODO: Distinguish between two scenarios:
246 * - A newer version of ELinks has saved an
247 * option that this version does not recognize.
248 * The option must be preserved. (This works.)
249 * - The user has added an option, saved
250 * elinks.conf, restarted ELinks, deleted the
251 * option, and is now saving elinks.conf again.
252 * The option should be rewritten to "unset".
253 * (This does not work yet.)
254 * In both cases, ELinks has no struct option
255 * for that name. Possible fixes:
256 * - If the tree has OPT_AUTOCREATE, then
257 * assume the user had created that option,
258 * and rewrite it to "unset". Otherwise,
260 * - When the user deletes an option, just mark
261 * it with OPT_DELETED, and keep it in memory
262 * as long as OPT_TOUCHED is set. */
265 if (!option_types
[opt
->type
].read
) {
266 show_parse_error(state
, ERROR_VALUE
);
267 skip_option_value(&state
->pos
);
271 val
= option_types
[opt
->type
].read(opt
, &state
->pos
.look
,
274 /* The reader function failed. Jump back to
275 * the beginning of the value and skip it with
276 * the generic code. For the error message,
277 * use the line number at the beginning of the
278 * value, because the ending position is not
279 * interesting if there is an unclosed quote. */
280 state
->pos
= pos_before_value
;
281 show_parse_error(state
, ERROR_VALUE
);
282 skip_option_value(&state
->pos
);
287 /* loading a configuration file */
288 if (!option_types
[opt
->type
].set
289 || !option_types
[opt
->type
].set(opt
, val
)) {
291 return show_parse_error(state
, ERROR_VALUE
);
293 } else if (is_system_conf
) {
294 /* scanning a file that will not be rewritten */
295 struct option
*flagsite
= indirect_option(opt
);
297 if (!(flagsite
->flags
& OPT_DELETED
)
298 && option_types
[opt
->type
].equals
299 && option_types
[opt
->type
].equals(opt
, val
))
300 flagsite
->flags
&= ~OPT_MUST_SAVE
;
302 flagsite
->flags
|= OPT_MUST_SAVE
;
304 /* rewriting a configuration file */
305 struct option
*flagsite
= indirect_option(opt
);
307 if (flagsite
->flags
& OPT_DELETED
) {
308 /* Replace the "set" command with an
309 * "unset" command. */
310 add_to_string(mirror
, "unset ");
311 add_bytes_to_string(mirror
, optname_orig
,
313 state
->mirrored
= state
->pos
.look
;
314 } else if (option_types
[opt
->type
].write
) {
315 add_bytes_to_string(mirror
, state
->mirrored
,
316 pos_before_value
.look
318 option_types
[opt
->type
].write(opt
, mirror
);
319 state
->mirrored
= state
->pos
.look
;
321 /* Remember that the option need not be
322 * written to the end of the file. */
323 flagsite
->flags
&= ~OPT_MUST_SAVE
;
331 static enum parse_error
332 parse_unset(struct option
*opt_tree
, struct conf_parsing_state
*state
,
333 struct string
*mirror
, int is_system_conf
)
335 const unsigned char *optname_orig
;
337 unsigned char *optname_copy
;
339 skip_white(&state
->pos
);
340 if (!*state
->pos
.look
) return show_parse_error(state
, ERROR_PARSE
);
343 optname_orig
= state
->pos
.look
;
344 while (isident(*state
->pos
.look
) || *state
->pos
.look
== '*'
345 || *state
->pos
.look
== '.' || *state
->pos
.look
== '+')
347 optname_len
= state
->pos
.look
- optname_orig
;
349 optname_copy
= memacpy(optname_orig
, optname_len
);
350 if (!optname_copy
) return show_parse_error(state
, ERROR_NOMEM
);
355 opt
= get_opt_rec_real(opt_tree
, optname_copy
);
356 mem_free(optname_copy
);
359 if (!opt
|| (opt
->flags
& OPT_HIDDEN
)) {
360 /* The user wanted to delete the option, and
361 * it has already been deleted; this is not an
362 * error. This might happen if a version of
363 * ELinks has a built-in URL rewriting rule,
364 * the user disables it, and a later version
365 * no longer has it. */
370 /* loading a configuration file */
371 if (opt
->flags
& OPT_ALLOC
) delete_option(opt
);
372 else mark_option_as_deleted(opt
);
373 } else if (is_system_conf
) {
374 /* scanning a file that will not be rewritten */
375 struct option
*flagsite
= indirect_option(opt
);
377 if (flagsite
->flags
& OPT_DELETED
)
378 flagsite
->flags
&= ~OPT_MUST_SAVE
;
380 flagsite
->flags
|= OPT_MUST_SAVE
;
382 /* rewriting a configuration file */
383 struct option
*flagsite
= indirect_option(opt
);
385 if (flagsite
->flags
& OPT_DELETED
) {
386 /* The "unset" command is already in the file,
387 * and unlike with "set", there is no value
389 } else if (option_types
[opt
->type
].write
) {
390 /* Replace the "unset" command with a
392 add_to_string(mirror
, "set ");
393 add_bytes_to_string(mirror
, optname_orig
,
395 add_to_string(mirror
, " = ");
396 option_types
[opt
->type
].write(opt
, mirror
);
397 state
->mirrored
= state
->pos
.look
;
399 /* Remember that the option need not be
400 * written to the end of the file. */
401 flagsite
->flags
&= ~OPT_MUST_SAVE
;
408 static enum parse_error
409 parse_bind(struct option
*opt_tree
, struct conf_parsing_state
*state
,
410 struct string
*mirror
, int is_system_conf
)
412 unsigned char *keymap
, *keystroke
, *action
;
413 enum parse_error err
= ERROR_NONE
;
414 struct conf_parsing_pos before_error
;
416 skip_white(&state
->pos
);
417 if (!*state
->pos
.look
) return show_parse_error(state
, ERROR_PARSE
);
420 before_error
= state
->pos
;
421 keymap
= option_types
[OPT_STRING
].read(NULL
, &state
->pos
.look
,
423 skip_white(&state
->pos
);
424 if (!keymap
|| !*state
->pos
.look
) {
425 state
->pos
= before_error
;
426 return show_parse_error(state
, ERROR_PARSE
);
430 before_error
= state
->pos
;
431 keystroke
= option_types
[OPT_STRING
].read(NULL
, &state
->pos
.look
,
433 skip_white(&state
->pos
);
434 if (!keystroke
|| !*state
->pos
.look
) {
435 mem_free(keymap
); mem_free_if(keystroke
);
436 state
->pos
= before_error
;
437 return show_parse_error(state
, ERROR_PARSE
);
441 skip_white(&state
->pos
);
442 if (*state
->pos
.look
!= '=') {
443 mem_free(keymap
); mem_free(keystroke
);
444 return show_parse_error(state
, ERROR_PARSE
);
446 state
->pos
.look
++; /* '=' */
448 skip_white(&state
->pos
);
449 if (!*state
->pos
.look
) {
450 mem_free(keymap
); mem_free(keystroke
);
451 return show_parse_error(state
, ERROR_PARSE
);
455 before_error
= state
->pos
;
456 action
= option_types
[OPT_STRING
].read(NULL
, &state
->pos
.look
,
459 mem_free(keymap
); mem_free(keystroke
);
460 state
->pos
= before_error
;
461 return show_parse_error(state
, ERROR_PARSE
);
465 /* loading a configuration file */
466 /* We don't bother to bind() if -default-keys. */
467 if (!get_cmd_opt_bool("default-keys")
468 && bind_do(keymap
, keystroke
, action
, is_system_conf
)) {
469 /* bind_do() tried but failed. */
470 err
= show_parse_error(state
, ERROR_VALUE
);
474 } else if (is_system_conf
) {
475 /* scanning a file that will not be rewritten */
478 /* rewriting a configuration file */
479 /* Mirror what we already have. If the keystroke has
480 * been unbound, then act_str is simply "none" and
481 * this does not require special handling. */
482 unsigned char *act_str
= bind_act(keymap
, keystroke
);
485 add_bytes_to_string(mirror
, state
->mirrored
,
486 before_error
.look
- state
->mirrored
);
487 add_to_string(mirror
, act_str
);
489 state
->mirrored
= state
->pos
.look
;
491 err
= show_parse_error(state
, ERROR_VALUE
);
494 mem_free(keymap
); mem_free(keystroke
); mem_free(action
);
498 static int load_config_file(unsigned char *, unsigned char *, struct option
*,
499 struct string
*, int);
501 static enum parse_error
502 parse_include(struct option
*opt_tree
, struct conf_parsing_state
*state
,
503 struct string
*mirror
, int is_system_conf
)
505 unsigned char *fname
;
506 struct string dumbstring
;
507 struct conf_parsing_pos before_error
;
509 if (!init_string(&dumbstring
))
510 return show_parse_error(state
, ERROR_NOMEM
);
512 skip_white(&state
->pos
);
513 if (!*state
->pos
.look
) {
514 done_string(&dumbstring
);
515 return show_parse_error(state
, ERROR_PARSE
);
519 before_error
= state
->pos
;
520 fname
= option_types
[OPT_STRING
].read(NULL
, &state
->pos
.look
,
523 done_string(&dumbstring
);
524 state
->pos
= before_error
;
525 return show_parse_error(state
, ERROR_PARSE
);
528 /* We want load_config_file() to watermark stuff, but not to load
529 * anything, polluting our beloved options tree - thus, we will feed it
530 * with some dummy string which we will destroy later; still better
531 * than cloning whole options tree or polluting interface with another
532 * rarely-used option ;). */
533 /* XXX: We should try CONFDIR/<file> when proceeding
534 * CONFDIR/<otherfile> ;). --pasky */
535 if (load_config_file(fname
[0] == '/' ? (unsigned char *) ""
538 mirror
? &dumbstring
: NULL
, 1)) {
539 done_string(&dumbstring
);
541 return show_parse_error(state
, ERROR_VALUE
);
544 done_string(&dumbstring
);
550 struct parse_handler
{
551 const unsigned char *command
;
552 enum parse_error (*handler
)(struct option
*opt_tree
,
553 struct conf_parsing_state
*state
,
554 struct string
*mirror
, int is_system_conf
);
557 static const struct parse_handler parse_handlers
[] = {
558 { "set", parse_set
},
559 { "unset", parse_unset
},
560 { "bind", parse_bind
},
561 { "include", parse_include
},
566 static enum parse_error
567 parse_config_command(struct option
*options
, struct conf_parsing_state
*state
,
568 struct string
*mirror
, int is_system_conf
)
570 const struct parse_handler
*handler
;
572 /* If we're mirroring, then everything up to this point must
573 * have already been mirrored. */
574 assert(mirror
== NULL
|| state
->mirrored
== state
->pos
.look
);
575 if_assert_failed
return show_parse_error(state
, ERROR_PARSE
);
577 for (handler
= parse_handlers
; handler
->command
;
579 int cmdlen
= strlen(handler
->command
);
581 if (!strncmp(state
->pos
.look
, handler
->command
, cmdlen
)
582 && isspace(state
->pos
.look
[cmdlen
])) {
583 enum parse_error err
;
585 state
->pos
.look
+= cmdlen
;
586 err
= handler
->handler(options
, state
, mirror
,
589 /* Mirror any characters that the handler
590 * consumed but did not already mirror. */
591 add_bytes_to_string(mirror
, state
->mirrored
,
592 state
->pos
.look
- state
->mirrored
);
593 state
->mirrored
= state
->pos
.look
;
599 return show_parse_error(state
, ERROR_COMMAND
);
604 parse_config_exmode_command(unsigned char *cmd
)
606 struct conf_parsing_state state
= {{ 0 }};
608 state
.pos
.look
= cmd
;
610 state
.mirrored
= NULL
; /* not read because mirror is NULL too */
611 state
.filename
= NULL
; /* prevent error messages */
613 return parse_config_command(config_options
, &state
, NULL
, 0);
615 #endif /* CONFIG_EXMODE */
618 parse_config_file(struct option
*options
, unsigned char *name
,
619 unsigned char *file
, struct string
*mirror
,
622 struct conf_parsing_state state
= {{ 0 }};
623 int error_occurred
= 0;
625 state
.pos
.look
= file
;
627 state
.mirrored
= file
;
628 if (!mirror
&& get_cmd_opt_int("verbose") >= VERBOSE_WARNINGS
)
629 state
.filename
= name
;
631 while (state
.pos
.look
&& *state
.pos
.look
) {
632 enum parse_error err
= ERROR_NONE
;
634 /* Skip all possible comments and whitespace. */
635 skip_white(&state
.pos
);
637 /* Mirror what we already have */
639 add_bytes_to_string(mirror
, state
.mirrored
,
640 state
.pos
.look
- state
.mirrored
);
641 state
.mirrored
= state
.pos
.look
;
644 /* Second chance to escape from the hell. */
645 if (!*state
.pos
.look
) break;
647 err
= parse_config_command(options
, &state
, mirror
,
655 /* Jump over this crap we can't understand. */
656 skip_to_unquoted_newline_or_comment(&state
.pos
);
658 /* Mirror what we already have */
660 add_bytes_to_string(mirror
, state
.mirrored
,
661 state
.pos
.look
- state
.mirrored
);
662 state
.mirrored
= state
.pos
.look
;
672 if (!error_occurred
|| !state
.filename
) return;
674 /* If an error occurred make sure that the user is notified and is able
675 * to see it. First sound the bell. Then, if the text viewer is going to
676 * be started, sleep for a while so the message will be visible before
677 * ELinks starts drawing to on the screen and overwriting any error
678 * messages. This should not be necessary for terminals supporting the
679 * alternate screen mode but better to be safe. (debian bug 305017) */
683 if (get_cmd_opt_bool("dump")
684 || get_cmd_opt_bool("source"))
692 static unsigned char *
693 read_config_file(unsigned char *name
)
695 #define FILE_BUF 1024
696 unsigned char cfg_buffer
[FILE_BUF
];
697 struct string string
;
701 fd
= open(name
, O_RDONLY
| O_NOCTTY
);
702 if (fd
< 0) return NULL
;
705 if (!init_string(&string
)) return NULL
;
707 while ((r
= safe_read(fd
, cfg_buffer
, FILE_BUF
)) > 0) {
710 /* Clear problems ;). */
711 for (i
= 0; i
< r
; i
++)
715 add_bytes_to_string(&string
, cfg_buffer
, r
);
718 if (r
< 0) done_string(&string
);
721 return string
.source
;
725 /* Return 0 on success. */
727 load_config_file(unsigned char *prefix
, unsigned char *name
,
728 struct option
*options
, struct string
*mirror
,
731 unsigned char *config_str
, *config_file
;
733 config_file
= straconcat(prefix
, STRING_DIR_SEP
, name
,
734 (unsigned char *) NULL
);
735 if (!config_file
) return 1;
737 config_str
= read_config_file(config_file
);
739 mem_free(config_file
);
740 config_file
= straconcat(prefix
, STRING_DIR_SEP
, ".", name
,
741 (unsigned char *) NULL
);
742 if (!config_file
) return 2;
744 config_str
= read_config_file(config_file
);
746 mem_free(config_file
);
751 parse_config_file(options
, config_file
, config_str
, mirror
,
754 mem_free(config_str
);
755 mem_free(config_file
);
761 load_config_from(unsigned char *file
, struct option
*tree
)
763 load_config_file(CONFDIR
, file
, tree
, NULL
, 1);
764 load_config_file(empty_string_or_(elinks_home
), file
, tree
, NULL
, 0);
770 load_config_from(get_cmd_opt_str("config-file"),
775 static int indentation
= 2;
776 /* 0 -> none, 1 -> only option full name+type, 2 -> only desc, 3 -> both */
777 static int comments
= 3;
779 static inline unsigned char *
780 conf_i18n(unsigned char *s
, int i18n
)
782 if (i18n
) return gettext(s
);
787 add_indent_to_string(struct string
*string
, int depth
)
791 add_xchar_to_string(string
, ' ', depth
* indentation
);
795 wrap_option_desc(struct string
*out
, const unsigned char *src
,
796 const struct string
*indent
, int maxwidth
)
798 const unsigned char *last_space
= NULL
;
799 const unsigned char *uncopied
= src
;
802 /* TODO: multibyte or fullwidth characters */
803 for (; *src
; src
++, width
++) {
809 if (*src
== ' ') last_space
= src
;
811 if (width
>= maxwidth
&& last_space
) {
813 if (!add_string_to_string(out
, indent
))
815 if (!add_bytes_to_string(out
, uncopied
,
816 last_space
- uncopied
))
818 if (!add_char_to_string(out
, '\n'))
820 uncopied
= last_space
+ 1;
821 width
= src
- uncopied
;
826 if (!add_string_to_string(out
, indent
))
828 if (!add_to_string(out
, uncopied
))
830 if (!add_char_to_string(out
, '\n'))
837 output_option_desc_as_comment(struct string
*out
, const struct option
*option
,
840 unsigned char *desc_i18n
= conf_i18n(option
->desc
, i18n
);
841 struct string indent
;
843 if (!init_string(&indent
)) return;
845 add_indent_to_string(&indent
, depth
);
846 if (!add_to_string(&indent
, "# ")) goto out_of_memory
;
847 if (!wrap_option_desc(out
, desc_i18n
, &indent
, 80 - indent
.length
))
851 done_string(&indent
);
855 smart_config_output_fn(struct string
*string
, struct option
*option
,
856 unsigned char *path
, int depth
, int do_print_comment
,
857 int action
, int i18n
)
859 if (option
->type
== OPT_ALIAS
)
864 if (!(comments
& 1)) break;
866 add_indent_to_string(string
, depth
);
868 add_to_string(string
, "## ");
870 add_to_string(string
, path
);
871 add_char_to_string(string
, '.');
873 add_to_string(string
, option
->name
);
874 add_char_to_string(string
, ' ');
875 add_to_string(string
, option_types
[option
->type
].help_str
);
876 add_char_to_string(string
, '\n');
880 if (!(comments
& 2)) break;
882 if (!option
->desc
|| !do_print_comment
)
885 output_option_desc_as_comment(string
, option
,
891 add_indent_to_string(string
, depth
);
892 if (option
->flags
& OPT_DELETED
) {
893 add_to_string(string
, "un");
895 add_to_string(string
, "set ");
897 add_to_string(string
, path
);
898 add_char_to_string(string
, '.');
900 add_to_string(string
, option
->name
);
901 if (!(option
->flags
& OPT_DELETED
)) {
902 add_to_string(string
, " = ");
903 /* OPT_ALIAS won't ever. OPT_TREE won't reach action 2.
904 * OPT_SPECIAL makes no sense in the configuration
906 assert(option_types
[option
->type
].write
);
907 option_types
[option
->type
].write(option
, string
);
909 add_char_to_string(string
, '\n');
910 if (do_print_comment
) add_char_to_string(string
, '\n');
914 if (do_print_comment
< 2)
915 add_char_to_string(string
, '\n');
922 add_cfg_header_to_string(struct string
*string
, unsigned char *text
)
924 int n
= strlen(text
) + 2;
926 int_bounds(&n
, 10, 80);
928 add_to_string(string
, "\n\n\n");
929 add_xchar_to_string(string
, '#', n
);
930 add_to_string(string
, "\n# ");
931 add_to_string(string
, text
);
932 add_to_string(string
, "#\n\n");
936 create_config_string(unsigned char *prefix
, unsigned char *name
,
937 struct option
*options
)
939 struct string config
;
940 /* Don't write headers if nothing will be added anyway. */
941 struct string tmpstring
;
943 int savestyle
= get_opt_int("config.saving_style");
944 int i18n
= get_opt_bool("config.i18n");
946 if (!init_string(&config
)) return NULL
;
948 prepare_mustsave_flags(options
->value
.tree
,
949 savestyle
== 1 || savestyle
== 2);
953 || load_config_file(prefix
, name
, options
, &config
, 0)
955 /* At first line, and in English, write ELinks version, may be
956 * of some help in future. Please keep that format for it.
958 add_to_string(&config
, "## ELinks " VERSION
" configuration file\n\n");
959 assert(savestyle
>= 0 && savestyle
<= 3);
962 add_to_string(&config
, conf_i18n(N_(
963 "## This is ELinks configuration file. You can edit it manually,\n"
964 "## if you wish so; this file is edited by ELinks when you save\n"
965 "## options through UI, however only option values will be altered\n"
966 "## and all your formatting, own comments etc will be kept as-is.\n"),
970 add_to_string(&config
, conf_i18n(N_(
971 "## This is ELinks configuration file. You can edit it manually,\n"
972 "## if you wish so; this file is edited by ELinks when you save\n"
973 "## options through UI, however only option values will be altered\n"
974 "## and missing options will be added at the end of file; if option\n"
975 "## is not written in this file, but in some file included from it,\n"
976 "## it is NOT counted as missing. Note that all your formatting,\n"
977 "## own comments and so on will be kept as-is.\n"), i18n
));
980 add_to_string(&config
, conf_i18n(N_(
981 "## This is ELinks configuration file. You can edit it manually,\n"
982 "## if you wish so, but keep in mind that this file is overwritten\n"
983 "## by ELinks when you save options through UI and you are out of\n"
984 "## luck with your formatting and own comments then, so beware.\n"),
989 add_to_string(&config
, "##\n");
991 add_to_string(&config
, conf_i18n(N_(
992 "## Obviously, if you don't like what ELinks is going to do with\n"
993 "## this file, you can change it by altering the config.saving_style\n"
994 "## option. Come on, aren't we friendly guys after all?\n"), i18n
));
997 if (savestyle
== 0) goto get_me_out
;
999 indentation
= get_opt_int("config.indentation");
1000 comments
= get_opt_int("config.comments");
1002 if (!init_string(&tmpstring
)) goto get_me_out
;
1004 add_cfg_header_to_string(&tmpstring
,
1005 conf_i18n(N_("Automatically saved options\n"), i18n
));
1007 origlen
= tmpstring
.length
;
1008 smart_config_string(&tmpstring
, 2, i18n
, options
->value
.tree
, NULL
, 0,
1009 smart_config_output_fn
);
1010 if (tmpstring
.length
> origlen
)
1011 add_string_to_string(&config
, &tmpstring
);
1012 done_string(&tmpstring
);
1014 if (!init_string(&tmpstring
)) goto get_me_out
;
1016 add_cfg_header_to_string(&tmpstring
,
1017 conf_i18n(N_("Automatically saved keybindings\n"), i18n
));
1019 origlen
= tmpstring
.length
;
1020 bind_config_string(&tmpstring
);
1021 if (tmpstring
.length
> origlen
)
1022 add_string_to_string(&config
, &tmpstring
);
1023 done_string(&tmpstring
);
1026 return config
.source
;
1030 write_config_file(unsigned char *prefix
, unsigned char *name
,
1031 struct option
*options
, struct terminal
*term
)
1034 struct secure_save_info
*ssi
;
1035 unsigned char *config_file
= NULL
;
1036 unsigned char *cfg_str
= create_config_string(prefix
, name
, options
);
1037 int prefixlen
= strlen(prefix
);
1038 int prefix_has_slash
= (prefixlen
&& dir_sep(prefix
[prefixlen
- 1]));
1039 int name_has_slash
= dir_sep(name
[0]);
1040 unsigned char *slash
= name_has_slash
|| prefix_has_slash
? "" : STRING_DIR_SEP
;
1042 if (!cfg_str
) return -1;
1044 if (name_has_slash
&& prefix_has_slash
) name
++;
1046 config_file
= straconcat(prefix
, slash
, name
, (unsigned char *) NULL
);
1047 if (!config_file
) goto free_cfg_str
;
1049 ssi
= secure_open(config_file
);
1051 secure_fputs(ssi
, cfg_str
);
1052 ret
= secure_close(ssi
);
1054 untouch_options(options
->value
.tree
);
1057 write_config_dialog(term
, config_file
, secsave_errno
, ret
);
1058 mem_free(config_file
);
1067 write_config(struct terminal
*term
)
1072 write_config_dialog(term
, get_cmd_opt_str("config-file"),
1073 SS_ERR_DISABLED
, 0);
1077 return write_config_file(elinks_home
, get_cmd_opt_str("config-file"),
1078 config_options
, term
);