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/domain.h"
24 #include "config/home.h"
25 #include "config/kbdbind.h"
26 #include "config/options.h"
27 #include "config/opttypes.h"
28 #include "intl/gettext/libintl.h"
29 #include "osdep/osdep.h"
30 #include "terminal/terminal.h"
31 #include "util/error.h"
32 #include "util/memory.h"
33 #include "util/secsave.h"
34 #include "util/string.h"
37 /* Config file has only very simple grammar:
39 * /set *option *= *value/
40 * /bind *keymap *keystroke *= *action/
44 * Where option consists from any number of categories separated by dots and
45 * name of the option itself. Both category and option name consists from
46 * [a-zA-Z0-9_-*] - using uppercase letters is not recommended, though. '*' is
47 * reserved and is used only as escape character in place of '.' originally in
50 * Value can consist from:
51 * - number (it will be converted to int/long)
52 * - enum (like on, off; true, fake, last_url; etc ;) - in planning state yet
53 * - string - "blah blah" (keymap, keystroke and action and file looks like that too)
55 * "set" command is parsed first, and then type-specific function is called,
56 * with option as one parameter and value as a second. Usually it just assigns
57 * value to an option, but sometimes you may want to first create the option
58 * ;). Then this will come handy. */
60 struct conf_parsing_state
{
61 /** This part may be copied to a local variable as a bookmark
62 * and restored later. So it must not contain any pointers
63 * that would have to be freed in that situation. */
64 struct conf_parsing_pos
{
65 /** Points to the next character to be parsed from the
66 * configuration file. */
69 /** The line number corresponding to #look. This is
70 * shown in error messages. */
74 /** When ELinks is rewriting the configuration file, @c mirrored
75 * indicates the end of the part that has already been copied
76 * to the mirror string. Otherwise, @c mirrored is not used.
78 * @invariant @c mirrored @<= @c pos.look */
79 unsigned char *mirrored
;
81 /** File name for error messages. If NULL then do not display
83 const unsigned char *filename
;
86 /** Tell the user about an error in the configuration file.
87 * @return @a err, for convenience. */
88 static enum parse_error
89 show_parse_error(const struct conf_parsing_state
*state
, enum parse_error err
)
91 static const unsigned char error_msg
[][40] = {
92 "no error", /* ERROR_NONE */
93 "unknown command", /* ERROR_COMMAND */
94 "parse error", /* ERROR_PARSE */
95 "unknown option", /* ERROR_OPTION */
96 "bad value", /* ERROR_VALUE */
97 "no memory left", /* ERROR_NOMEM */
100 if (state
->filename
) {
101 fprintf(stderr
, "%s:%d: %s\n",
102 state
->filename
, state
->pos
.line
, error_msg
[err
]);
107 /** Skip comments and whitespace. */
109 skip_white(struct conf_parsing_pos
*pos
)
111 unsigned char *start
= pos
->look
;
114 while (isspace(*start
)) {
115 if (*start
== '\n') {
122 start
+= strcspn(start
, "\n");
132 /** Skip a quoted string.
133 * This function allows "mismatching quotes' because str_rd() does so. */
135 skip_quoted(struct conf_parsing_pos
*pos
)
137 assert(isquote(*pos
->look
));
138 if_assert_failed
return;
144 if (isquote(*pos
->look
)) {
148 if (*pos
->look
== '\\' && pos
->look
[1])
150 if (*pos
->look
== '\n')
156 /** Skip the value of an option.
158 * This job is normally done by the reader function that corresponds
159 * to the type of the option. However, if ELinks does not recognize
160 * the name of the option, it cannot look up the type and has to use
161 * this function instead. */
163 skip_option_value(struct conf_parsing_pos
*pos
)
165 if (isquote(*pos
->look
)) {
166 /* Looks like OPT_STRING, OPT_CODEPAGE, OPT_LANGUAGE,
170 /* Looks like OPT_BOOL, OPT_INT, or OPT_LONG. */
171 while (isasciialnum(*pos
->look
) || *pos
->look
== '.'
172 || *pos
->look
== '+' || *pos
->look
== '-')
177 /** Skip to the next newline or comment that is not part of a quoted
178 * string. When ELinks hits a parse error in the configuration file,
179 * it calls this in order to find the place where is should resume
180 * parsing. This is intended to prevent ELinks from treating words
181 * in strings as commands. */
183 skip_to_unquoted_newline_or_comment(struct conf_parsing_pos
*pos
)
185 while (*pos
->look
&& *pos
->look
!= '#' && *pos
->look
!= '\n') {
186 if (isquote(*pos
->look
))
193 /* Parse a command. Returns error code. */
194 /* If dynamic string credentials are supplied, we will mirror the command at
195 * the end of the string; however, we won't load the option value to the tree,
196 * and we will even write option value from the tree to the output string.
197 * We will only possibly set or clear OPT_MUST_SAVE flag in the option. */
199 static enum parse_error
200 parse_set_common(struct option
*opt_tree
, struct conf_parsing_state
*state
,
201 struct string
*mirror
, int is_system_conf
, int want_domain
)
203 const unsigned char *domain_orig
= NULL
;
204 size_t domain_len
= 0;
205 unsigned char *domain_copy
= NULL
;
206 const unsigned char *optname_orig
;
208 unsigned char *optname_copy
;
210 skip_white(&state
->pos
);
211 if (!*state
->pos
.look
) return show_parse_error(state
, ERROR_PARSE
);
214 domain_orig
= state
->pos
.look
;
215 while (isident(*state
->pos
.look
) || *state
->pos
.look
== '*'
216 || *state
->pos
.look
== '.' || *state
->pos
.look
== '+')
218 domain_len
= state
->pos
.look
- domain_orig
;
220 skip_white(&state
->pos
);
224 optname_orig
= state
->pos
.look
;
225 while (isident(*state
->pos
.look
) || *state
->pos
.look
== '*'
226 || *state
->pos
.look
== '.' || *state
->pos
.look
== '+')
228 optname_len
= state
->pos
.look
- optname_orig
;
230 skip_white(&state
->pos
);
233 if (*state
->pos
.look
!= '=')
234 return show_parse_error(state
, ERROR_PARSE
);
235 state
->pos
.look
++; /* '=' */
236 skip_white(&state
->pos
);
237 if (!*state
->pos
.look
)
238 return show_parse_error(state
, ERROR_VALUE
);
240 optname_copy
= memacpy(optname_orig
, optname_len
);
241 if (!optname_copy
) return show_parse_error(state
, ERROR_NOMEM
);
243 domain_copy
= memacpy(domain_orig
, domain_len
);
245 mem_free(optname_copy
);
246 return show_parse_error(state
, ERROR_NOMEM
);
254 const struct conf_parsing_pos pos_before_value
= state
->pos
;
256 if (want_domain
&& *domain_copy
) {
257 struct option
*domain_tree
;
259 domain_tree
= get_domain_tree(domain_copy
);
261 mem_free(domain_copy
);
262 mem_free(optname_copy
);
263 skip_option_value(&state
->pos
);
264 return show_parse_error(state
, ERROR_NOMEM
);
268 opt
= get_opt_rec_real(domain_tree
,
271 opt
= get_opt_rec(opt_tree
, optname_copy
);
273 opt
= get_option_shadow(opt
, opt_tree
,
276 mem_free(domain_copy
);
277 mem_free(optname_copy
);
278 skip_option_value(&state
->pos
);
279 return show_parse_error(state
,
286 ? get_opt_rec_real(opt_tree
, optname_copy
)
287 : get_opt_rec(opt_tree
, optname_copy
);
290 mem_free(domain_copy
);
292 mem_free(optname_copy
);
295 if (!opt
|| (opt
->flags
& OPT_HIDDEN
)) {
296 show_parse_error(state
, ERROR_OPTION
);
297 skip_option_value(&state
->pos
);
299 /* TODO: Distinguish between two scenarios:
300 * - A newer version of ELinks has saved an
301 * option that this version does not recognize.
302 * The option must be preserved. (This works.)
303 * - The user has added an option, saved
304 * elinks.conf, restarted ELinks, deleted the
305 * option, and is now saving elinks.conf again.
306 * The option should be rewritten to "unset".
307 * (This does not work yet.)
308 * In both cases, ELinks has no struct option
309 * for that name. Possible fixes:
310 * - If the tree has OPT_AUTOCREATE, then
311 * assume the user had created that option,
312 * and rewrite it to "unset". Otherwise,
314 * - When the user deletes an option, just mark
315 * it with OPT_DELETED, and keep it in memory
316 * as long as OPT_TOUCHED is set. */
319 if (!option_types
[opt
->type
].read
) {
320 show_parse_error(state
, ERROR_VALUE
);
321 skip_option_value(&state
->pos
);
325 val
= option_types
[opt
->type
].read(opt
, &state
->pos
.look
,
328 /* The reader function failed. Jump back to
329 * the beginning of the value and skip it with
330 * the generic code. For the error message,
331 * use the line number at the beginning of the
332 * value, because the ending position is not
333 * interesting if there is an unclosed quote. */
334 state
->pos
= pos_before_value
;
335 show_parse_error(state
, ERROR_VALUE
);
336 skip_option_value(&state
->pos
);
341 /* loading a configuration file */
342 if (!option_types
[opt
->type
].set
343 || !option_types
[opt
->type
].set(opt
, val
)) {
345 return show_parse_error(state
, ERROR_VALUE
);
347 } else if (is_system_conf
) {
348 /* scanning a file that will not be rewritten */
349 struct option
*flagsite
= indirect_option(opt
);
351 if (!(flagsite
->flags
& OPT_DELETED
)
352 && option_types
[opt
->type
].equals
353 && option_types
[opt
->type
].equals(opt
, val
))
354 flagsite
->flags
&= ~OPT_MUST_SAVE
;
356 flagsite
->flags
|= OPT_MUST_SAVE
;
358 /* rewriting a configuration file */
359 struct option
*flagsite
= indirect_option(opt
);
361 if (flagsite
->flags
& OPT_DELETED
) {
362 /* Replace the "set" command with an
363 * "unset" command. */
364 add_to_string(mirror
, "unset ");
365 add_bytes_to_string(mirror
, optname_orig
,
367 state
->mirrored
= state
->pos
.look
;
368 } else if (option_types
[opt
->type
].write
) {
369 add_bytes_to_string(mirror
, state
->mirrored
,
370 pos_before_value
.look
372 option_types
[opt
->type
].write(opt
, mirror
);
373 state
->mirrored
= state
->pos
.look
;
375 /* Remember that the option need not be
376 * written to the end of the file. */
377 flagsite
->flags
&= ~OPT_MUST_SAVE
;
385 static enum parse_error
386 parse_set_domain(struct option
*opt_tree
, struct conf_parsing_state
*state
,
387 struct string
*mirror
, int is_system_conf
)
389 return parse_set_common(opt_tree
, state
, mirror
, is_system_conf
, 1);
392 static enum parse_error
393 parse_set(struct option
*opt_tree
, struct conf_parsing_state
*state
,
394 struct string
*mirror
, int is_system_conf
)
396 return parse_set_common(opt_tree
, state
, mirror
, is_system_conf
, 0);
400 static enum parse_error
401 parse_unset(struct option
*opt_tree
, struct conf_parsing_state
*state
,
402 struct string
*mirror
, int is_system_conf
)
404 const unsigned char *optname_orig
;
406 unsigned char *optname_copy
;
408 skip_white(&state
->pos
);
409 if (!*state
->pos
.look
) return show_parse_error(state
, ERROR_PARSE
);
412 optname_orig
= state
->pos
.look
;
413 while (isident(*state
->pos
.look
) || *state
->pos
.look
== '*'
414 || *state
->pos
.look
== '.' || *state
->pos
.look
== '+')
416 optname_len
= state
->pos
.look
- optname_orig
;
418 optname_copy
= memacpy(optname_orig
, optname_len
);
419 if (!optname_copy
) return show_parse_error(state
, ERROR_NOMEM
);
424 opt
= get_opt_rec_real(opt_tree
, optname_copy
);
425 mem_free(optname_copy
);
428 if (!opt
|| (opt
->flags
& OPT_HIDDEN
)) {
429 /* The user wanted to delete the option, and
430 * it has already been deleted; this is not an
431 * error. This might happen if a version of
432 * ELinks has a built-in URL rewriting rule,
433 * the user disables it, and a later version
434 * no longer has it. */
439 /* loading a configuration file */
440 if (opt
->flags
& OPT_ALLOC
) delete_option(opt
);
441 else mark_option_as_deleted(opt
);
442 } else if (is_system_conf
) {
443 /* scanning a file that will not be rewritten */
444 struct option
*flagsite
= indirect_option(opt
);
446 if (flagsite
->flags
& OPT_DELETED
)
447 flagsite
->flags
&= ~OPT_MUST_SAVE
;
449 flagsite
->flags
|= OPT_MUST_SAVE
;
451 /* rewriting a configuration file */
452 struct option
*flagsite
= indirect_option(opt
);
454 if (flagsite
->flags
& OPT_DELETED
) {
455 /* The "unset" command is already in the file,
456 * and unlike with "set", there is no value
458 } else if (option_types
[opt
->type
].write
) {
459 /* Replace the "unset" command with a
461 add_to_string(mirror
, "set ");
462 add_bytes_to_string(mirror
, optname_orig
,
464 add_to_string(mirror
, " = ");
465 option_types
[opt
->type
].write(opt
, mirror
);
466 state
->mirrored
= state
->pos
.look
;
468 /* Remember that the option need not be
469 * written to the end of the file. */
470 flagsite
->flags
&= ~OPT_MUST_SAVE
;
477 static enum parse_error
478 parse_bind(struct option
*opt_tree
, struct conf_parsing_state
*state
,
479 struct string
*mirror
, int is_system_conf
)
481 unsigned char *keymap
, *keystroke
, *action
;
482 enum parse_error err
= ERROR_NONE
;
483 struct conf_parsing_pos before_error
;
485 skip_white(&state
->pos
);
486 if (!*state
->pos
.look
) return show_parse_error(state
, ERROR_PARSE
);
489 before_error
= state
->pos
;
490 keymap
= option_types
[OPT_STRING
].read(NULL
, &state
->pos
.look
,
492 skip_white(&state
->pos
);
493 if (!keymap
|| !*state
->pos
.look
) {
494 state
->pos
= before_error
;
495 return show_parse_error(state
, ERROR_PARSE
);
499 before_error
= state
->pos
;
500 keystroke
= option_types
[OPT_STRING
].read(NULL
, &state
->pos
.look
,
502 skip_white(&state
->pos
);
503 if (!keystroke
|| !*state
->pos
.look
) {
504 mem_free(keymap
); mem_free_if(keystroke
);
505 state
->pos
= before_error
;
506 return show_parse_error(state
, ERROR_PARSE
);
510 skip_white(&state
->pos
);
511 if (*state
->pos
.look
!= '=') {
512 mem_free(keymap
); mem_free(keystroke
);
513 return show_parse_error(state
, ERROR_PARSE
);
515 state
->pos
.look
++; /* '=' */
517 skip_white(&state
->pos
);
518 if (!*state
->pos
.look
) {
519 mem_free(keymap
); mem_free(keystroke
);
520 return show_parse_error(state
, ERROR_PARSE
);
524 before_error
= state
->pos
;
525 action
= option_types
[OPT_STRING
].read(NULL
, &state
->pos
.look
,
528 mem_free(keymap
); mem_free(keystroke
);
529 state
->pos
= before_error
;
530 return show_parse_error(state
, ERROR_PARSE
);
534 /* loading a configuration file */
535 /* We don't bother to bind() if -default-keys. */
536 if (!get_cmd_opt_bool("default-keys")
537 && bind_do(keymap
, keystroke
, action
, is_system_conf
)) {
538 /* bind_do() tried but failed. */
539 err
= show_parse_error(state
, ERROR_VALUE
);
543 } else if (is_system_conf
) {
544 /* scanning a file that will not be rewritten */
547 /* rewriting a configuration file */
548 /* Mirror what we already have. If the keystroke has
549 * been unbound, then act_str is simply "none" and
550 * this does not require special handling. */
551 unsigned char *act_str
= bind_act(keymap
, keystroke
);
554 add_bytes_to_string(mirror
, state
->mirrored
,
555 before_error
.look
- state
->mirrored
);
556 add_to_string(mirror
, act_str
);
558 state
->mirrored
= state
->pos
.look
;
560 err
= show_parse_error(state
, ERROR_VALUE
);
563 mem_free(keymap
); mem_free(keystroke
); mem_free(action
);
567 static int load_config_file(unsigned char *, unsigned char *, struct option
*,
568 struct string
*, int);
570 static enum parse_error
571 parse_include(struct option
*opt_tree
, struct conf_parsing_state
*state
,
572 struct string
*mirror
, int is_system_conf
)
574 unsigned char *fname
;
575 struct string dumbstring
;
576 struct conf_parsing_pos before_error
;
578 if (!init_string(&dumbstring
))
579 return show_parse_error(state
, ERROR_NOMEM
);
581 skip_white(&state
->pos
);
582 if (!*state
->pos
.look
) {
583 done_string(&dumbstring
);
584 return show_parse_error(state
, ERROR_PARSE
);
588 before_error
= state
->pos
;
589 fname
= option_types
[OPT_STRING
].read(NULL
, &state
->pos
.look
,
592 done_string(&dumbstring
);
593 state
->pos
= before_error
;
594 return show_parse_error(state
, ERROR_PARSE
);
597 /* We want load_config_file() to watermark stuff, but not to load
598 * anything, polluting our beloved options tree - thus, we will feed it
599 * with some dummy string which we will destroy later; still better
600 * than cloning whole options tree or polluting interface with another
601 * rarely-used option ;). */
602 /* XXX: We should try CONFDIR/<file> when proceeding
603 * CONFDIR/<otherfile> ;). --pasky */
604 if (load_config_file(fname
[0] == '/' ? (unsigned char *) ""
607 mirror
? &dumbstring
: NULL
, 1)) {
608 done_string(&dumbstring
);
610 return show_parse_error(state
, ERROR_VALUE
);
613 done_string(&dumbstring
);
619 struct parse_handler
{
620 const unsigned char *command
;
621 enum parse_error (*handler
)(struct option
*opt_tree
,
622 struct conf_parsing_state
*state
,
623 struct string
*mirror
, int is_system_conf
);
626 static const struct parse_handler parse_handlers
[] = {
627 { "set_domain", parse_set_domain
},
628 { "set", parse_set
},
629 { "unset", parse_unset
},
630 { "bind", parse_bind
},
631 { "include", parse_include
},
636 static enum parse_error
637 parse_config_command(struct option
*options
, struct conf_parsing_state
*state
,
638 struct string
*mirror
, int is_system_conf
)
640 const struct parse_handler
*handler
;
642 /* If we're mirroring, then everything up to this point must
643 * have already been mirrored. */
644 assert(mirror
== NULL
|| state
->mirrored
== state
->pos
.look
);
645 if_assert_failed
return show_parse_error(state
, ERROR_PARSE
);
647 for (handler
= parse_handlers
; handler
->command
;
649 int cmdlen
= strlen(handler
->command
);
651 if (!strncmp(state
->pos
.look
, handler
->command
, cmdlen
)
652 && isspace(state
->pos
.look
[cmdlen
])) {
653 enum parse_error err
;
655 state
->pos
.look
+= cmdlen
;
656 err
= handler
->handler(options
, state
, mirror
,
659 /* Mirror any characters that the handler
660 * consumed but did not already mirror. */
661 add_bytes_to_string(mirror
, state
->mirrored
,
662 state
->pos
.look
- state
->mirrored
);
663 state
->mirrored
= state
->pos
.look
;
669 return show_parse_error(state
, ERROR_COMMAND
);
674 parse_config_exmode_command(unsigned char *cmd
)
676 struct conf_parsing_state state
= {{ 0 }};
678 state
.pos
.look
= cmd
;
680 state
.mirrored
= NULL
; /* not read because mirror is NULL too */
681 state
.filename
= NULL
; /* prevent error messages */
683 return parse_config_command(config_options
, &state
, NULL
, 0);
685 #endif /* CONFIG_EXMODE */
688 parse_config_file(struct option
*options
, unsigned char *name
,
689 unsigned char *file
, struct string
*mirror
,
692 struct conf_parsing_state state
= {{ 0 }};
693 int error_occurred
= 0;
695 state
.pos
.look
= file
;
697 state
.mirrored
= file
;
698 if (!mirror
&& get_cmd_opt_int("verbose") >= VERBOSE_WARNINGS
)
699 state
.filename
= name
;
701 while (state
.pos
.look
&& *state
.pos
.look
) {
702 enum parse_error err
= ERROR_NONE
;
704 /* Skip all possible comments and whitespace. */
705 skip_white(&state
.pos
);
707 /* Mirror what we already have */
709 add_bytes_to_string(mirror
, state
.mirrored
,
710 state
.pos
.look
- state
.mirrored
);
711 state
.mirrored
= state
.pos
.look
;
714 /* Second chance to escape from the hell. */
715 if (!*state
.pos
.look
) break;
717 err
= parse_config_command(options
, &state
, mirror
,
725 /* Jump over this crap we can't understand. */
726 skip_to_unquoted_newline_or_comment(&state
.pos
);
728 /* Mirror what we already have */
730 add_bytes_to_string(mirror
, state
.mirrored
,
731 state
.pos
.look
- state
.mirrored
);
732 state
.mirrored
= state
.pos
.look
;
742 if (!error_occurred
|| !state
.filename
) return;
744 /* If an error occurred make sure that the user is notified and is able
745 * to see it. First sound the bell. Then, if the text viewer is going to
746 * be started, sleep for a while so the message will be visible before
747 * ELinks starts drawing to on the screen and overwriting any error
748 * messages. This should not be necessary for terminals supporting the
749 * alternate screen mode but better to be safe. (debian bug 305017) */
753 if (get_cmd_opt_bool("dump")
754 || get_cmd_opt_bool("source"))
762 static unsigned char *
763 read_config_file(unsigned char *name
)
765 #define FILE_BUF 1024
766 unsigned char cfg_buffer
[FILE_BUF
];
767 struct string string
;
771 fd
= open(name
, O_RDONLY
| O_NOCTTY
);
772 if (fd
< 0) return NULL
;
775 if (!init_string(&string
)) return NULL
;
777 while ((r
= safe_read(fd
, cfg_buffer
, FILE_BUF
)) > 0) {
780 /* Clear problems ;). */
781 for (i
= 0; i
< r
; i
++)
785 add_bytes_to_string(&string
, cfg_buffer
, r
);
788 if (r
< 0) done_string(&string
);
791 return string
.source
;
795 /* Return 0 on success. */
797 load_config_file(unsigned char *prefix
, unsigned char *name
,
798 struct option
*options
, struct string
*mirror
,
801 unsigned char *config_str
, *config_file
;
803 config_file
= straconcat(prefix
, STRING_DIR_SEP
, name
,
804 (unsigned char *) NULL
);
805 if (!config_file
) return 1;
807 config_str
= read_config_file(config_file
);
809 mem_free(config_file
);
810 config_file
= straconcat(prefix
, STRING_DIR_SEP
, ".", name
,
811 (unsigned char *) NULL
);
812 if (!config_file
) return 2;
814 config_str
= read_config_file(config_file
);
816 mem_free(config_file
);
821 parse_config_file(options
, config_file
, config_str
, mirror
,
824 mem_free(config_str
);
825 mem_free(config_file
);
831 load_config_from(unsigned char *file
, struct option
*tree
)
833 load_config_file(CONFDIR
, file
, tree
, NULL
, 1);
834 load_config_file(empty_string_or_(elinks_home
), file
, tree
, NULL
, 0);
840 load_config_from(get_cmd_opt_str("config-file"),
845 static int indentation
= 2;
846 /* 0 -> none, 1 -> only option full name+type, 2 -> only desc, 3 -> both */
847 static int comments
= 3;
849 static inline unsigned char *
850 conf_i18n(unsigned char *s
, int i18n
)
852 if (i18n
) return gettext(s
);
857 add_indent_to_string(struct string
*string
, int depth
)
861 add_xchar_to_string(string
, ' ', depth
* indentation
);
864 static unsigned char *smart_config_output_fn_domain
;
867 smart_config_output_fn(struct string
*string
, struct option
*option
,
868 unsigned char *path
, int depth
, int do_print_comment
,
869 int action
, int i18n
)
871 unsigned char *desc_i18n
;
873 if (option
->type
== OPT_ALIAS
)
878 if (!(comments
& 1)) break;
880 add_indent_to_string(string
, depth
);
882 add_to_string(string
, "## ");
884 add_to_string(string
, path
);
885 add_char_to_string(string
, '.');
887 add_to_string(string
, option
->name
);
888 add_char_to_string(string
, ' ');
889 add_to_string(string
, option_types
[option
->type
].help_str
);
890 add_char_to_string(string
, '\n');
894 if (!(comments
& 2)) break;
896 if (!option
->desc
|| !do_print_comment
)
899 desc_i18n
= conf_i18n(option
->desc
, i18n
);
901 if (!*desc_i18n
) break;
903 add_indent_to_string(string
, depth
);
904 add_to_string(string
, "# ");
906 unsigned char *i
= desc_i18n
;
907 unsigned char *j
= i
;
908 unsigned char *last_space
= NULL
;
909 int config_width
= 80;
910 int n
= depth
* indentation
+ 3;
912 for (; *i
; i
++, n
++) {
918 if (*i
== ' ') last_space
= i
;
920 if (n
>= config_width
&& last_space
) {
922 add_bytes_to_string(string
, j
, last_space
- j
);
923 add_char_to_string(string
, '\n');
924 add_indent_to_string(string
, depth
);
925 add_to_string(string
, "# ");
927 n
= depth
* indentation
+ 2 + i
- last_space
;
931 add_to_string(string
, j
);
933 add_char_to_string(string
, '\n');
938 add_indent_to_string(string
, depth
);
939 if (option
->flags
& OPT_DELETED
) {
940 add_to_string(string
, "un");
942 if (smart_config_output_fn_domain
) {
943 add_to_string(string
, "set_domain ");
944 add_to_string(string
, smart_config_output_fn_domain
);
945 add_char_to_string(string
, ' ');
947 add_to_string(string
, "set ");
950 add_to_string(string
, path
);
951 add_char_to_string(string
, '.');
953 add_to_string(string
, option
->name
);
954 if (!(option
->flags
& OPT_DELETED
)) {
955 add_to_string(string
, " = ");
956 /* OPT_ALIAS won't ever. OPT_TREE won't reach action 2.
957 * OPT_SPECIAL makes no sense in the configuration
959 assert(option_types
[option
->type
].write
);
960 option_types
[option
->type
].write(option
, string
);
962 add_char_to_string(string
, '\n');
963 if (do_print_comment
) add_char_to_string(string
, '\n');
967 if (do_print_comment
< 2)
968 add_char_to_string(string
, '\n');
975 add_cfg_header_to_string(struct string
*string
, unsigned char *text
)
977 int n
= strlen(text
) + 2;
979 int_bounds(&n
, 10, 80);
981 add_to_string(string
, "\n\n\n");
982 add_xchar_to_string(string
, '#', n
);
983 add_to_string(string
, "\n# ");
984 add_to_string(string
, text
);
985 add_to_string(string
, "#\n\n");
989 create_config_string(unsigned char *prefix
, unsigned char *name
)
991 struct option
*options
= config_options
;
992 struct string config
;
993 /* Don't write headers if nothing will be added anyway. */
994 struct string tmpstring
;
996 int savestyle
= get_opt_int("config.saving_style", NULL
);
997 int i18n
= get_opt_bool("config.i18n", NULL
);
999 if (!init_string(&config
)) return NULL
;
1002 int set_all
= (savestyle
== 1 || savestyle
== 2);
1003 struct domain_tree
*domain
;
1005 prepare_mustsave_flags(options
->value
.tree
, set_all
);
1006 foreach (domain
, domain_trees
) {
1007 prepare_mustsave_flags(domain
->tree
->value
.tree
,
1014 || load_config_file(prefix
, name
, options
, &config
, 0)
1015 || !config
.length
) {
1016 /* At first line, and in English, write ELinks version, may be
1017 * of some help in future. Please keep that format for it.
1019 add_to_string(&config
, "## ELinks " VERSION
" configuration file\n\n");
1020 assert(savestyle
>= 0 && savestyle
<= 3);
1021 switch (savestyle
) {
1023 add_to_string(&config
, conf_i18n(N_(
1024 "## This is ELinks configuration file. You can edit it manually,\n"
1025 "## if you wish so; this file is edited by ELinks when you save\n"
1026 "## options through UI, however only option values will be altered\n"
1027 "## and all your formatting, own comments etc will be kept as-is.\n"),
1031 add_to_string(&config
, conf_i18n(N_(
1032 "## This is ELinks configuration file. You can edit it manually,\n"
1033 "## if you wish so; this file is edited by ELinks when you save\n"
1034 "## options through UI, however only option values will be altered\n"
1035 "## and missing options will be added at the end of file; if option\n"
1036 "## is not written in this file, but in some file included from it,\n"
1037 "## it is NOT counted as missing. Note that all your formatting,\n"
1038 "## own comments and so on will be kept as-is.\n"), i18n
));
1041 add_to_string(&config
, conf_i18n(N_(
1042 "## This is ELinks configuration file. You can edit it manually,\n"
1043 "## if you wish so, but keep in mind that this file is overwritten\n"
1044 "## by ELinks when you save options through UI and you are out of\n"
1045 "## luck with your formatting and own comments then, so beware.\n"),
1050 add_to_string(&config
, "##\n");
1052 add_to_string(&config
, conf_i18n(N_(
1053 "## Obviously, if you don't like what ELinks is going to do with\n"
1054 "## this file, you can change it by altering the config.saving_style\n"
1055 "## option. Come on, aren't we friendly guys after all?\n"), i18n
));
1058 if (savestyle
== 0) goto get_me_out
;
1060 indentation
= get_opt_int("config.indentation", NULL
);
1061 comments
= get_opt_int("config.comments", NULL
);
1063 if (!init_string(&tmpstring
)) goto get_me_out
;
1065 add_cfg_header_to_string(&tmpstring
,
1066 conf_i18n(N_("Automatically saved options\n"), i18n
));
1068 origlen
= tmpstring
.length
;
1069 smart_config_string(&tmpstring
, 2, i18n
, options
->value
.tree
, NULL
, 0,
1070 smart_config_output_fn
);
1073 struct domain_tree
*domain
;
1075 foreach (domain
, domain_trees
) {
1076 smart_config_output_fn_domain
= domain
->name
;
1077 smart_config_string(&tmpstring
, 2, i18n
,
1078 domain
->tree
->value
.tree
,
1080 smart_config_output_fn
);
1083 smart_config_output_fn_domain
= NULL
;
1086 if (tmpstring
.length
> origlen
)
1087 add_string_to_string(&config
, &tmpstring
);
1088 done_string(&tmpstring
);
1090 if (!init_string(&tmpstring
)) goto get_me_out
;
1092 add_cfg_header_to_string(&tmpstring
,
1093 conf_i18n(N_("Automatically saved keybindings\n"), i18n
));
1095 origlen
= tmpstring
.length
;
1096 bind_config_string(&tmpstring
);
1097 if (tmpstring
.length
> origlen
)
1098 add_string_to_string(&config
, &tmpstring
);
1099 done_string(&tmpstring
);
1102 return config
.source
;
1106 write_config_file(unsigned char *prefix
, unsigned char *name
,
1107 struct terminal
*term
)
1110 struct secure_save_info
*ssi
;
1111 unsigned char *config_file
= NULL
;
1112 unsigned char *cfg_str
= create_config_string(prefix
, name
);
1113 int prefixlen
= strlen(prefix
);
1114 int prefix_has_slash
= (prefixlen
&& dir_sep(prefix
[prefixlen
- 1]));
1115 int name_has_slash
= dir_sep(name
[0]);
1116 unsigned char *slash
= name_has_slash
|| prefix_has_slash
? "" : STRING_DIR_SEP
;
1118 if (!cfg_str
) return -1;
1120 if (name_has_slash
&& prefix_has_slash
) name
++;
1122 config_file
= straconcat(prefix
, slash
, name
, (unsigned char *) NULL
);
1123 if (!config_file
) goto free_cfg_str
;
1125 ssi
= secure_open(config_file
);
1127 secure_fputs(ssi
, cfg_str
);
1128 ret
= secure_close(ssi
);
1130 struct domain_tree
*domain
;
1132 untouch_options(config_options
->value
.tree
);
1133 foreach (domain
, domain_trees
)
1134 untouch_options(domain
->tree
->value
.tree
);
1138 write_config_dialog(term
, config_file
, secsave_errno
, ret
);
1139 mem_free(config_file
);
1148 write_config(struct terminal
*term
)
1153 write_config_dialog(term
, get_cmd_opt_str("config-file"),
1154 SS_ERR_DISABLED
, 0);
1158 return write_config_file(elinks_home
, get_cmd_opt_str("config-file"),