| /* texi2any.c -- conversion of Texinfo |
| |
| Copyright 2010-2025 Free Software Foundation, Inc. |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #include <config.h> |
| |
| #include <stdlib.h> |
| #include <stddef.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <ctype.h> |
| #include <stdarg.h> |
| #include <sys/stat.h> |
| #include <errno.h> |
| /* from Gnulib codeset.m4 */ |
| #ifdef HAVE_LANGINFO_CODESET |
| #include <langinfo.h> |
| #endif |
| #include <locale.h> |
| #ifdef ENABLE_NLS |
| #include <libintl.h> |
| #endif |
| /* for pgettext and to have a definition of gettext in case ENABLE_NLS |
| is not set */ |
| #include "gettext.h" |
| #include <getopt.h> |
| #ifdef _WIN32 |
| /* for GetACP */ |
| #include <windows.h> |
| #endif |
| |
| #include "text.h" |
| #include "option_types.h" |
| #include "document_types.h" |
| #include "converter_types.h" |
| /* read_var_len */ |
| #include "base_utils.h" |
| /* for xvasprintf */ |
| #include "text.h" |
| /* parse_file_path whitespace_chars encode_string xasprintf digit_chars |
| wipe_values locate_file_in_dirs */ |
| #include "utils.h" |
| #include "errors.h" |
| #include "customization_options.h" |
| #include "txi_config.h" |
| /* print_tree_details */ |
| #include "manipulate_tree.h" |
| /* set_document_options */ |
| #include "document.h" |
| #include "convert_to_texinfo.h" |
| #include "create_buttons.h" |
| /* needed because commands are used to determine expanded regions names */ |
| #include "builtin_commands.h" |
| /* output_files_open_out output_files_register_closed */ |
| #include "convert_utils.h" |
| /* destroy_converter_initialization_info new_converter_initialization_info |
| encoded_output_file_name */ |
| #include "converter.h" |
| /* for html_output_internal_links */ |
| #include "html_converter_api.h" |
| #include "texinfo.h" |
| |
| #define LOCALEDIR DATADIR "/locale" |
| |
| #define _(String) gettext (String) |
| |
| static const char *conf_file_name = "texi2any-config.pm"; |
| |
| typedef struct FORMAT_COMMAND_LINE_NAME { |
| const char *command_line_name; |
| const char *output_name; |
| } FORMAT_COMMAND_LINE_NAME; |
| |
| static FORMAT_COMMAND_LINE_NAME format_command_line_names[] = { |
| {"xml", "texinfoxml"}, |
| {NULL, NULL}, |
| }; |
| |
| typedef struct FORMAT_REGION_NAME { |
| const char *output_name; |
| const char *region_name; |
| } FORMAT_REGION_NAME; |
| |
| static FORMAT_REGION_NAME converter_format_expanded_region_name[] = { |
| {"texinfoxml", "xml"}, |
| {NULL, NULL}, |
| }; |
| |
| typedef struct FORMAT_SPECIFICATION { |
| const char *name; |
| unsigned long flags; |
| const char *converted_format; |
| /* Perl module name */ |
| const char *module; |
| const char *init_file; |
| } FORMAT_SPECIFICATION; |
| |
| static FORMAT_SPECIFICATION formats_table[] = { |
| {"info", STTF_nodes_tree | STTF_floats |
| | STTF_setup_index_entries_sort_strings, |
| NULL, "Texinfo::Convert::Info", NULL}, |
| {"html", STTF_relate_index_entries_to_table_items |
| | STTF_move_index_entries_after_items |
| | STTF_no_warn_non_empty_parts |
| | STTF_nodes_tree | STTF_floats | STTF_split |
| | STTF_setup_index_entries_sort_strings |
| | STTF_internal_links, |
| NULL, "Texinfo::Convert::HTML", NULL}, |
| {"plaintext", STTF_nodes_tree | STTF_floats | STTF_split |
| | STTF_setup_index_entries_sort_strings, |
| NULL, "Texinfo::Convert::Plaintext", NULL}, |
| {"latex", STTF_floats | STTF_move_index_entries_after_items |
| | STTF_no_warn_non_empty_parts, |
| NULL, "Texinfo::Convert::LaTeX", NULL}, |
| {"docbook", STTF_move_index_entries_after_items |
| | STTF_no_warn_non_empty_parts, |
| NULL, "Texinfo::Convert::DocBook", NULL}, |
| {"epub3", 0, "html", NULL, "epub3.pm"}, |
| {"texinfoxml", STTF_nodes_tree, |
| NULL, "Texinfo::Convert::TexinfoXML", NULL}, |
| {"pdf", STTF_texi2dvi_format, NULL, NULL, NULL}, |
| {"ps", STTF_texi2dvi_format, NULL, NULL, NULL}, |
| {"dvi", STTF_texi2dvi_format, NULL, NULL, NULL}, |
| {"dvipdf", STTF_texi2dvi_format, NULL, NULL, NULL}, |
| {"debugtree", STTF_split, |
| NULL, "Texinfo::DebugTree", NULL}, |
| {"textcontent", 0, NULL, "Texinfo::Convert::TextContent", NULL}, |
| {"plaintexinfo", 0, NULL, NULL, NULL}, |
| {"rawtext", 0, NULL, NULL, NULL}, |
| {"parse", 0, NULL, NULL, NULL}, |
| {"structure", STTF_nodes_tree | STTF_floats | STTF_split, NULL, NULL, NULL}, |
| {NULL, 0, NULL, NULL, NULL} |
| }; |
| |
| static VALUE_LIST values; |
| |
| /* options common to parser and converter */ |
| static OPTIONS_LIST program_options; |
| static OPTIONS_LIST cmdline_options; |
| static OPTIONS_LIST *init_files_options; |
| |
| static char *program_file; |
| |
| static int embedded_interpreter = 0; |
| |
| /* texi2any */ |
| static void |
| add_config_paths (const char *env_string, const char *subdir, |
| /* unused in Perl |
| const STRING_LIST *default_base_dirs, |
| */ |
| const char *installation_dir, |
| const DEPRECATED_DIRS_LIST *overriding_dirs, |
| STRING_LIST *result_dirs, |
| DEPRECATED_DIRS_LIST *deprecated_dirs) |
| { |
| static STRING_LIST xdg_result_dirs; |
| size_t i; |
| /* |
| read the env directories to avoid setting the overriding_dirs |
| as deprecated if they are explicitely specified in the environnement |
| variable. |
| */ |
| const char *env_value = getenv (env_string); |
| if (env_value && strlen (env_value)) |
| { |
| char *text = strdup (env_value); |
| char *dir = strtok (text, ":"); |
| |
| while (dir) |
| { |
| if (strlen (dir)) |
| { |
| add_include_directory (dir, &xdg_result_dirs); |
| } |
| dir = strtok (NULL, ":"); |
| } |
| free (text); |
| } |
| |
| if (installation_dir) |
| { |
| char *install_result_dir; |
| xasprintf (&install_result_dir, "%s/%s", installation_dir, subdir); |
| add_string (install_result_dir, result_dirs); |
| if (overriding_dirs) |
| { |
| DEPRECATED_DIR_INFO *deprecated_dir_info |
| = find_deprecated_dir_info (overriding_dirs, installation_dir); |
| |
| if (deprecated_dir_info) |
| { |
| char *deprecated_result_dir; |
| xasprintf (&deprecated_result_dir, "%s/%s", |
| deprecated_dir_info->obsolete_dir, subdir); |
| if (!find_string (&xdg_result_dirs, |
| deprecated_dir_info->obsolete_dir)) |
| { |
| add_new_deprecated_dir_info (deprecated_dirs, |
| deprecated_dir_info->obsolete_dir, |
| deprecated_dir_info->reference_dir); |
| add_string (deprecated_result_dir, result_dirs); |
| } |
| free (deprecated_result_dir); |
| } |
| } |
| free (install_result_dir); |
| } |
| |
| for (i = 0; i < xdg_result_dirs.number; i++) |
| { |
| char *dir = xdg_result_dirs.list[i]; |
| if (!find_string (result_dirs, dir)) |
| { |
| char *result_dir; |
| xasprintf (&result_dir, "%s/%s", dir, subdir); |
| add_string (result_dir, result_dirs); |
| free (result_dir); |
| } |
| free (dir); |
| } |
| |
| xdg_result_dirs.number = 0; |
| } |
| |
| #define XDG_SYSCONFDIR SYSCONFDIR "/xdg" |
| |
| static DEPRECATED_DIR_INFO overriding_sysconfdir_info[1] = { |
| {XDG_SYSCONFDIR, SYSCONFDIR} }; |
| static const DEPRECATED_DIRS_LIST overriding_sysconfdir_list = { |
| 1, 1, overriding_sysconfdir_info }; |
| |
| static STRING_LIST * |
| set_subdir_directories (const char *subdir, |
| DEPRECATED_DIRS_LIST *deprecated_dirs) |
| { |
| STRING_LIST *result = new_string_list (); |
| STRING_LIST *config_dirs = new_string_list (); |
| char *dir_string; |
| char *xdg_config_home; |
| |
| xasprintf (&dir_string, ".%s", subdir); |
| add_string (dir_string, result); |
| free (dir_string); |
| |
| xdg_config_home = getenv ("XDG_CONFIG_HOME"); |
| if (xdg_config_home && strlen (xdg_config_home)) |
| { |
| xasprintf (&dir_string, "%s/%s", xdg_config_home, subdir); |
| add_string (dir_string, result); |
| free (dir_string); |
| } |
| else |
| { |
| const char *home_dir = getenv ("HOME"); |
| if (home_dir) |
| { |
| char *deprecated_config_home; |
| xasprintf (&dir_string, "%s/%s/%s", home_dir, ".config", subdir); |
| xasprintf (&deprecated_config_home, "%s/.%s", home_dir, subdir); |
| add_new_deprecated_dir_info (deprecated_dirs, |
| deprecated_config_home, dir_string); |
| add_string (dir_string, result); |
| free (dir_string); |
| add_string (deprecated_config_home, result); |
| free (deprecated_config_home); |
| } |
| } |
| |
| add_config_paths ("XDG_CONFIG_DIRS", subdir, XDG_SYSCONFDIR, |
| &overriding_sysconfdir_list, config_dirs, deprecated_dirs); |
| |
| merge_strings (result, config_dirs); |
| |
| free (config_dirs->list); |
| free (config_dirs); |
| |
| xasprintf (&dir_string, DATADIR "/%s", subdir); |
| add_string (dir_string, result); |
| free (dir_string); |
| |
| return result; |
| } |
| |
| static void |
| set_format (const char *format_name) |
| { |
| size_t i; |
| const char *new_output_format = 0; |
| int format_found = 0; |
| |
| for (i = 0; format_command_line_names[i].command_line_name; i++) |
| { |
| if (!strcmp (format_command_line_names[i].command_line_name, |
| format_name)) |
| { |
| new_output_format = format_command_line_names[i].output_name; |
| break; |
| } |
| } |
| |
| if (!new_output_format) |
| new_output_format = format_name; |
| |
| for (i = 0; formats_table[i].name; i++) |
| { |
| if (!strcmp (formats_table[i].name, new_output_format)) |
| { |
| format_found = 1; |
| break; |
| } |
| } |
| if (!format_found) |
| { |
| txi_config_document_warn ( |
| "ignoring unrecognized TEXINFO_OUTPUT_FORMAT value `%s'", |
| format_name); |
| } |
| else |
| GNUT_set_from_init_file ("TEXINFO_OUTPUT_FORMAT", new_output_format); |
| } |
| |
| static void |
| get_cmdline_customization_option (OPTIONS_LIST *options_list, |
| char *text) |
| { |
| size_t identifier_len = read_var_len (text); |
| if (identifier_len > 0) |
| { |
| char *option_name = strndup (text, identifier_len); |
| OPTION *option = find_option_string (options_list->sorted_options, |
| option_name); |
| |
| if (option) |
| { |
| char *p = text + identifier_len; |
| p += strspn (p, whitespace_chars); |
| if (*p == '=') |
| { |
| p++; |
| p += strspn (p, whitespace_chars); |
| } |
| |
| if (!strcmp (option_name, "TEXINFO_OUTPUT_FORMAT")) |
| { |
| char *option_value = GNUT_decode_input (p); |
| set_format (option_value); |
| free (option_value); |
| } |
| else |
| { |
| if (!strcasecmp (p, "undef")) |
| { |
| clear_option (option); |
| options_list_add_option_number (options_list, option->number); |
| } |
| else |
| { |
| char *option_value = p; |
| if (option->type == GOT_char) |
| option_value = GNUT_decode_input (p); |
| |
| GNUT_set_from_cmdline (options_list, option->number, |
| option_value); |
| |
| if (option->type == GOT_char) |
| free (option_value); |
| } |
| } |
| } |
| else |
| { |
| /* in Perl obsolete options may get another error message */ |
| txi_config_document_warn ("unknown variable from command line: %s", |
| option_name); |
| } |
| free (option_name); |
| } |
| } |
| |
| static void |
| push_include_directory (STRING_LIST *include_dirs_list, char *text) |
| { |
| char *dir = strtok (text, PATH_SEP); |
| |
| while (dir) |
| { |
| if (strlen (dir)) |
| { |
| add_include_directory (dir, include_dirs_list); |
| } |
| dir = strtok (NULL, PATH_SEP); |
| } |
| } |
| |
| static void |
| set_expansion (OPTIONS_LIST *options_list, STRING_LIST *ignored_formats, |
| const char *format_name) |
| { |
| OPTION *option = &options_list->options->EXPANDED_FORMATS; |
| size_t ignored_idx = find_string (ignored_formats, format_name); |
| |
| txi_config_add_to_option_list (option, format_name, 0); |
| |
| if (ignored_idx) |
| remove_from_strings_list (ignored_formats, ignored_idx -1); |
| } |
| |
| static void |
| unset_expansion (OPTIONS_LIST *options_list, STRING_LIST *ignored_formats, |
| const char *format_name) |
| { |
| OPTION *option = &options_list->options->EXPANDED_FORMATS; |
| size_t ignored_idx = find_string (ignored_formats, format_name); |
| |
| txi_config_remove_from_option_list (option, format_name); |
| |
| if (!ignored_idx) |
| add_string (format_name, ignored_formats); |
| } |
| |
| static void |
| format_expanded_formats (STRING_LIST *default_expanded_formats, |
| FORMAT_SPECIFICATION *format_specification, |
| STRING_LIST *texi2dvi_args, int *call_texi2dvi) |
| { |
| const char *converter_format; |
| const char *expanded_region = 0; |
| size_t i; |
| |
| if (format_specification->flags & STTF_texi2dvi_format) |
| { |
| char *format_option; |
| |
| *call_texi2dvi = 1; |
| xasprintf (&format_option, "--%s", |
| format_specification->name); |
| add_string (format_option, texi2dvi_args); |
| free (format_option); |
| |
| converter_format = "tex"; |
| } |
| else if (format_specification->converted_format) |
| converter_format = format_specification->converted_format; |
| else |
| converter_format = format_specification->name; |
| |
| for (i = 0; converter_format_expanded_region_name[i].output_name; i++) |
| { |
| if (!strcmp (converter_format, |
| converter_format_expanded_region_name[i].output_name)) |
| { |
| expanded_region |
| = converter_format_expanded_region_name[i].region_name; |
| break; |
| } |
| } |
| |
| if (!expanded_region) |
| expanded_region = converter_format; |
| |
| if (!strcmp (expanded_region, "plaintext")) |
| { |
| add_string (expanded_region, default_expanded_formats); |
| add_string ("info", default_expanded_formats); |
| } |
| /* Texinfo::Common::texinfo_output_formats */ |
| else |
| { |
| const char *expanded_format = 0; |
| if (!strcmp (expanded_region, "info")) |
| expanded_format = expanded_region; |
| else |
| { |
| enum command_id cmd = lookup_builtin_command (expanded_region); |
| if (cmd && builtin_command_data[cmd].flags & CF_block |
| && builtin_command_data[cmd].data == BLOCK_format_raw) |
| expanded_format = expanded_region; |
| } |
| if (expanded_format) |
| add_string (expanded_format, default_expanded_formats); |
| } |
| } |
| |
| static void |
| set_cmdline_format (const char *format_name) |
| { |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->TEXINFO_OUTPUT_FORMAT.number, |
| format_name); |
| } |
| |
| /* If the file overwriting becomes an error, should increase $ERROR_COUNT. */ |
| static size_t |
| merge_opened_files (STRING_LIST *opened_files, |
| STRING_LIST *added_opened_files, size_t error_count) |
| { |
| if (added_opened_files) |
| { |
| size_t i; |
| for (i = 0; i < added_opened_files->number; i++) |
| { |
| char *opened_file = added_opened_files->list[i]; |
| if (find_string (opened_files, opened_file)) |
| txi_config_document_warn ("overwriting file: %s", opened_file); |
| else |
| add_string (opened_file, opened_files); |
| } |
| } |
| |
| return error_count; |
| } |
| |
| static void |
| exit_if_errors (size_t error_count, STRING_LIST *opened_files) |
| { |
| OPTION *error_limit_option |
| = GNUT_get_conf (program_options.options->ERROR_LIMIT.number); |
| OPTION *force_option |
| = GNUT_get_conf (program_options.options->FORCE.number); |
| int force = (force_option->o.integer > 0); |
| /* implicit conversion */ |
| size_t error_limit = error_limit_option->o.integer; |
| |
| if (opened_files->number > 0 && error_count && !force) |
| { |
| size_t i; |
| for (i = opened_files->number; i > 0 ; i--) |
| { |
| size_t index = i - 1; |
| char *opened_file = strdup (opened_files->list[index]); |
| unlink (opened_file); |
| remove_from_strings_list (opened_files, index); |
| free (opened_file); |
| } |
| } |
| |
| if ((error_count && !force) || error_count > error_limit) |
| exit (EXIT_FAILURE); |
| } |
| |
| static size_t |
| handle_errors (size_t additional_error_count, size_t error_count, |
| STRING_LIST *opened_files) |
| { |
| error_count += additional_error_count; |
| exit_if_errors (error_count, opened_files); |
| return error_count; |
| } |
| |
| static size_t |
| handle_parser_errors (DOCUMENT *document, int no_warn, int test_mode_set, |
| const char *set_message_encoding, size_t error_count, |
| STRING_LIST *opened_files) |
| { |
| size_t errors_nr |
| = txi_handle_parser_error_messages (document, no_warn, test_mode_set, |
| set_message_encoding); |
| return handle_errors (errors_nr, error_count, opened_files); |
| } |
| |
| /* NOTE could also have used strtol */ |
| static int |
| is_ascii_digit (const char *text) |
| { |
| const char *p = text; |
| size_t digits_nr = strspn (text, digit_chars); |
| |
| if (digits_nr) |
| { |
| p += digits_nr; |
| if (!*p) |
| return 1; |
| } |
| return 0; |
| } |
| |
| /* warn and also clear deprecated_dirs_used */ |
| static void |
| warn_deprecated_dirs (DEPRECATED_DIRS_LIST *deprecated_dirs_used) |
| { |
| if (deprecated_dirs_used->number) |
| { |
| size_t i; |
| for (i = 0; i < deprecated_dirs_used->number; i++) |
| { |
| char *dir_name, *replacement_dir; |
| DEPRECATED_DIR_INFO *deprecated_dir_info |
| = &deprecated_dirs_used->list[i]; |
| dir_name = GNUT_decode_input (deprecated_dir_info->obsolete_dir); |
| replacement_dir |
| = GNUT_decode_input (deprecated_dir_info->reference_dir); |
| |
| txi_config_document_warn ( |
| "%s directory is deprecated. Use %s instead", |
| dir_name, replacement_dir); |
| |
| free (dir_name); |
| free (replacement_dir); |
| free (deprecated_dir_info->obsolete_dir); |
| free (deprecated_dir_info->reference_dir); |
| } |
| } |
| deprecated_dirs_used->number = 0; |
| } |
| |
| int loaded_init_files_nr = 0; |
| |
| static void |
| locate_and_load_init_file (const char *filename, STRING_LIST *directories, |
| DEPRECATED_DIRS_LIST *deprecated_dirs) |
| { |
| static DEPRECATED_DIRS_LIST deprecated_dirs_used; |
| |
| char *file = locate_file_in_dirs (filename, directories, 0, |
| deprecated_dirs, &deprecated_dirs_used); |
| |
| if (file) |
| { |
| int status = txi_load_init_file (file, embedded_interpreter); |
| |
| if (status) |
| loaded_init_files_nr++; |
| else |
| { |
| char *decoded_filename = GNUT_decode_input ((char *) filename); |
| if (!embedded_interpreter) |
| fprintf (stderr, "WARNING: no interpreter, cannot load: %s\n", |
| filename); |
| else |
| fprintf (stderr, "ERROR: could not load: %s\n", |
| filename); |
| free (decoded_filename); |
| } |
| free (file); |
| } |
| else |
| { |
| char *decoded_filename = GNUT_decode_input ((char *) filename); |
| txi_config_document_warn ("could not read init file %s", |
| decoded_filename); |
| |
| free (decoded_filename); |
| } |
| |
| if (deprecated_dirs) |
| warn_deprecated_dirs (&deprecated_dirs_used); |
| } |
| |
| static void |
| locate_and_load_extension_file (const char *filename, STRING_LIST *directories) |
| { |
| char *file = locate_file_in_dirs (filename, directories, 0, 0, 0); |
| |
| if (file) |
| { |
| int status = txi_load_init_file (file, embedded_interpreter); |
| |
| if (status) |
| loaded_init_files_nr++; |
| else |
| { |
| char *decoded_filename = GNUT_decode_input ((char *) filename); |
| if (!embedded_interpreter) |
| fprintf (stderr, "WARNING: no interpreter, cannot load: %s\n", |
| filename); |
| else |
| fprintf (stderr, "ERROR: could not load: %s\n", |
| filename); |
| free (decoded_filename); |
| } |
| free (file); |
| } |
| else |
| { |
| char *decoded_filename = GNUT_decode_input ((char *) filename); |
| txi_config_document_warn ("could not read extension file %s", |
| decoded_filename); |
| |
| free (decoded_filename); |
| exit (EXIT_FAILURE); |
| } |
| } |
| |
| static void |
| write_to_file (char *output_text, FILE *file_fh, |
| const char *encoded_file_name) |
| { |
| size_t write_len; |
| size_t res_len; |
| const ENCODING_CONVERSION *conversion = 0; |
| char *result_text = 0; |
| OPTION *out_encoding_option |
| = GNUT_get_conf (program_options.options->OUTPUT_ENCODING_NAME.number); |
| if (out_encoding_option && out_encoding_option->o.string |
| && strcmp (out_encoding_option->o.string, "utf-8")) |
| { |
| conversion |
| = get_encoding_conversion (out_encoding_option->o.string, |
| &output_conversions); |
| if (conversion) |
| result_text = encode_with_iconv (conversion->iconv, |
| output_text, 0); |
| } |
| |
| if (!result_text) |
| result_text = output_text; |
| |
| res_len = strlen (result_text); |
| |
| write_len = fwrite (result_text, sizeof (char), |
| res_len, file_fh); |
| |
| if (conversion) |
| free (result_text); |
| |
| if (write_len != res_len) |
| { /* register error message instead? */ |
| fprintf (stderr, |
| "ERROR: write to %s failed (%zu/%zu)\n", |
| encoded_file_name, write_len, res_len); |
| } |
| } |
| |
| typedef struct FORMAT_NAME { |
| const char *format; |
| const char *name; |
| } FORMAT_NAME; |
| |
| static const FORMAT_NAME format_names[] = { |
| {"info", "Info"}, |
| {"html", "HTML"}, |
| {"docbook", "DocBook"}, |
| {"epub3", "EPUB 3"}, |
| {"plaintext", "Plain Text"}, |
| {"texinfoxml", "Texinfo XML"}, |
| {NULL, NULL}, |
| }; |
| |
| static const char * |
| name_of_format (const char *format) |
| { |
| int i; |
| |
| for (i = 0; format_names[i].format; i++) |
| { |
| if (!strcmp (format, format_names[i].format)) |
| return format_names[i].name; |
| } |
| |
| return format; |
| } |
| |
| const char *input_file_suffixes[] = { |
| ".txi",".texinfo",".texi",".txinfo", "", NULL |
| }; |
| |
| /* If non-zero, show help and exit */ |
| static int print_help_p; |
| |
| #define DOCUMENT_LANGUAGE_OPT 2 |
| #define NO_SPLIT_OPT 3 |
| #define SPLIT_OPT 4 |
| #define FOOTNOTE_STYLE_OPT 5 |
| #define IFDOCBOOK_OPT 6 |
| #define NO_IFDOCBOOK_OPT 7 |
| #define IFINFO_OPT 8 |
| #define NO_IFINFO_OPT 9 |
| #define IFHTML_OPT 10 |
| #define NO_IFHTML_OPT 11 |
| #define IFLATEX_OPT 12 |
| #define NO_IFLATEX_OPT 13 |
| #define IFPLAINTEXT_OPT 14 |
| #define NO_IFPLAINTEXT_OPT 15 |
| #define IFTEX_OPT 16 |
| #define NO_IFTEX_OPT 17 |
| #define IFXML_OPT 18 |
| #define NO_IFXML_OPT 19 |
| #define NO_WARN_OPT 20 |
| #define _FORMAT_OPT 21 |
| #define XML_OPT 22 |
| #define INTERNAL_LINKS_OPT 23 |
| #define NO_MIMICKING_OPT 24 |
| #define XOPT_OPT 25 |
| #define _SILENT_OPT 26 |
| /* can add here */ |
| #define TRACE_INCLUDES_OPT 33 |
| #define NO_VERBOSE_OPT 34 |
| #define HEADERS_OPT 35 |
| #define NO_HEADERS_OPT 36 |
| #define NUMBER_SECTIONS_OPT 37 |
| #define NO_NUMBER_SECTIONS_OPT 38 |
| #define ENABLE_ENCODING_OPT 39 |
| #define DISABLE_ENCODING_OPT 40 |
| #define NUMBER_FOOTNOTES_OPT 41 |
| #define NO_NUMBER_FOOTNOTES_OPT 42 |
| #define NODE_FILES_OPT 43 |
| #define NO_NODE_FILES_OPT 44 |
| #define TRANSLITERATE_FILE_NAMES_OPT 45 |
| #define NO_TRANSLITERATE_FILE_NAMES_OPT 46 |
| #define SPLIT_SIZE_OPT 47 |
| #define DEBUG_OPT 48 |
| #define NO_VALIDATE_OPT 49 |
| #define CSS_INCLUDE_OPT 50 |
| #define CSS_REF_OPT 51 |
| #define CONF_DIR_OPT 52 |
| #define INIT_FILE_OPT 53 |
| |
| #define IFFORMAT_TABLE(upcase, name) \ |
| {"if" #name, 0, 0, IF ## upcase ## _OPT}, \ |
| {"no-if" #name, 0, 0, NO_IF ## upcase ## _OPT}, |
| |
| static struct option long_options[] = { |
| /* next not in texi2any */ |
| {"no-mimicking", 0, 0, NO_MIMICKING_OPT}, |
| |
| {"conf-dir", required_argument, 0, CONF_DIR_OPT}, |
| {"css-include", required_argument, 0, CSS_INCLUDE_OPT}, |
| {"css-ref", required_argument, 0, CSS_REF_OPT}, |
| {"debug", required_argument, 0, DEBUG_OPT}, |
| {"disable-encoding", 0, 0, DISABLE_ENCODING_OPT}, |
| {"document-language", required_argument, 0, DOCUMENT_LANGUAGE_OPT}, |
| {"enable-encoding", 0, 0, ENABLE_ENCODING_OPT}, |
| {"error-limit", required_argument, 0, 'e'}, |
| {"fill-column", required_argument, 0, 'f'}, |
| {"footnote-style", required_argument, 0, FOOTNOTE_STYLE_OPT}, |
| {"force", 0, 0, 'F'}, |
| {"headers", 0, 0, HEADERS_OPT}, |
| {"no-headers", 0, 0, NO_HEADERS_OPT}, |
| {"help", 0, 0, 'h'}, |
| {"init-file", required_argument, 0, INIT_FILE_OPT}, |
| {"internal-links", required_argument, 0, INTERNAL_LINKS_OPT}, |
| {"macro-expand", required_argument, 0, 'E'}, |
| {"node-files", 0, 0, NODE_FILES_OPT}, |
| {"no-node-files", 0, 0, NO_NODE_FILES_OPT}, |
| {"number-footnotes", 0, 0, NUMBER_FOOTNOTES_OPT}, |
| {"no-number-footnotes", 0, 0, NO_NUMBER_FOOTNOTES_OPT}, |
| {"number-sections", 0, 0, NUMBER_SECTIONS_OPT}, |
| {"no-number-sections", 0, 0, NO_NUMBER_SECTIONS_OPT}, |
| {"paragraph-indent", required_argument, 0, 'p'}, |
| {"no-warn", 0, 0, NO_WARN_OPT}, |
| {"out", required_argument, 0, 'o'}, |
| {"output", required_argument, 0, 'o'}, |
| {"no-split", 0, 0, NO_SPLIT_OPT}, |
| {"split", required_argument, 0, SPLIT_OPT}, |
| {"set-customization-variable", required_argument, 0, 'c'}, |
| {"split-size", required_argument, 0, SPLIT_SIZE_OPT}, |
| {"trace-include", 0, 0, TRACE_INCLUDES_OPT}, |
| {"transliterate-file-names", 0, 0, TRANSLITERATE_FILE_NAMES_OPT}, |
| {"no-transliterate-file-names", 0, 0, NO_TRANSLITERATE_FILE_NAMES_OPT}, |
| {"no-validate", 0, 0, NO_VALIDATE_OPT}, |
| {"no-pointer-validate", 0, 0, NO_VALIDATE_OPT}, |
| {"verbose", 0, 0, 'v'}, |
| {"no-verbose", 0, 0, NO_VERBOSE_OPT}, |
| {"version", 0, 0, 'V'}, |
| {"Xopt", required_argument, 0, XOPT_OPT}, |
| {"silent", 0, 0, _SILENT_OPT}, |
| {"quiet", 0, 0, _SILENT_OPT}, |
| {"html", 0, 0, _FORMAT_OPT}, |
| {"plaintext", 0, 0, _FORMAT_OPT}, |
| {"latex", 0, 0, _FORMAT_OPT}, |
| {"info", 0, 0, _FORMAT_OPT}, |
| {"docbook", 0, 0, _FORMAT_OPT}, |
| {"epub3", 0, 0, _FORMAT_OPT}, |
| {"xml", 0, 0, XML_OPT}, |
| {"dvi", 0, 0, _FORMAT_OPT}, |
| {"dvipdf", 0, 0, _FORMAT_OPT}, |
| {"ps", 0, 0, _FORMAT_OPT}, |
| {"pdf", 0, 0, _FORMAT_OPT}, |
| IFFORMAT_TABLE(DOCBOOK, docbook) |
| IFFORMAT_TABLE(INFO, info) |
| IFFORMAT_TABLE(HTML, html) |
| IFFORMAT_TABLE(LATEX, latex) |
| IFFORMAT_TABLE(PLAINTEXT, plaintext) |
| IFFORMAT_TABLE(TEX, tex) |
| IFFORMAT_TABLE(XML, xml) |
| {NULL, 0, NULL, 0} |
| }; |
| #undef IFFORMAT_TABLE |
| |
| static const char *possible_split[] = { |
| "chapter", "section", "node", NULL |
| }; |
| |
| /* we use env in case a Perl interpreter is embedded in order to blindly |
| follow the documentation in perlembed, which is not very explicit */ |
| int |
| main (int argc, char *argv[], char *env[]) |
| { |
| int getopt_long_index; |
| const char *langinfo_locale_encoding; |
| char *locale_encoding = 0; |
| const char *input_file_arg; |
| int status; |
| char *program_file_name_and_directory[2]; |
| /* |
| char *command_directory; |
| */ |
| OPTIONS_LIST parser_options; |
| OPTIONS_LIST convert_options; |
| /* used except for the first file, to remove some options that are only |
| relevant for the first file */ |
| OPTIONS_LIST non_first_file_cmdline_options; |
| /* make sure that non_first_file_cmdline_options was initialized, |
| even if a file was skipped */ |
| int non_first_file_cmdline_initialized = 0; |
| size_t errors_count = 0; |
| size_t errors_nr; |
| STRING_LIST *texinfo_language_config_dirs; |
| STRING_LIST ignored_formats; |
| STRING_LIST default_expanded_formats; |
| STRING_LIST prepend_dirs; |
| STRING_LIST reversed_converter_config_dirs; |
| STRING_LIST config_init_files; |
| CONVERTER_INITIALIZATION_INFO *format_defaults; |
| DEPRECATED_DIRS_LIST deprecated_directories; |
| char *t2a_srcdir = 0; |
| char *t2a_builddir = 0; |
| OPTION *html_math_option; |
| OPTION *highlight_syntax_option; |
| OPTION *test_option; |
| OPTION *no_warn_option; |
| OPTION *format_menu_option; |
| OPTION *debug_option; |
| OPTION *message_encoding_option; |
| OPTION *sort_element_count_option; |
| OPTION *tree_transformations_option; |
| OPTION *split_option; |
| OPTION *show_builtin_css_rules_option; |
| int no_warn = 0; |
| int test_mode_set = 0; |
| int debug = 0; |
| size_t i; |
| STRING_LIST input_files; |
| STRING_LIST opened_files; |
| STRING_LIST prepended_include_directories; |
| STRING_LIST conf_dirs; |
| STRING_LIST converter_config_dirs; |
| STRING_LIST converter_init_dirs; |
| STRING_LIST *converter_config_dirs_array_ref; |
| STRING_LIST internal_extension_dirs; |
| STRING_LIST init_file_dirs; |
| STRING_LIST texi2dvi_args; |
| char *extensions_dir; |
| char *texinfo_output_format_env; |
| OPTION *output_format_option; |
| OPTION *expanded_formats_option; |
| const char *output_format; |
| const char *converted_format; |
| FORMAT_SPECIFICATION *format_specification = 0; |
| int do_menu = 0; |
| size_t format_menu_option_nr; |
| char *conversion_format_menu_default = 0; |
| int texinfo_uninstalled = 0; |
| const char *converterdatadir = DATADIR "/" CONVERTER_CONFIG; |
| const char *curdir = "."; |
| CONVERTER_INITIALIZATION_INFO *converter_init_info; |
| const char *external_module = 0; |
| int default_is_html = 1; |
| char *init_file_format; |
| const char *set_message_encoding = 0; |
| const char *version_for_embedded_interpreter_check; |
| int call_texi2dvi = 0; |
| int Xopt_arg_nr = 0; |
| char *texi2dvi = 0; |
| unsigned long transformation_flags = 0; |
| const char *txi_xs_external_conversion; |
| const char *txi_xs_external_formatting; |
| FILE_STREAM main_program_unclosed_stdout; |
| DEPRECATED_DIRS_LIST deprecated_dirs_used; |
| char *perl_embed_env; |
| char *texinfo_dev_source_env; |
| char *command_directory; |
| char *program_basename; |
| |
| memset (&main_program_unclosed_stdout, 0, sizeof (FILE_STREAM)); |
| |
| texinfo_dev_source_env = getenv ("TEXINFO_DEV_SOURCE"); |
| |
| parse_file_path (argv[0], program_file_name_and_directory); |
| program_basename = program_file_name_and_directory[0]; |
| command_directory = program_file_name_and_directory[1]; |
| |
| program_file = strdup ("texi2any"); |
| |
| if (texinfo_dev_source_env && strcmp (texinfo_dev_source_env, "0")) |
| texinfo_uninstalled = 1; |
| else |
| { |
| /* determine if uninstalled by looking at the absolute directory |
| and checking the last directories. It is not perfectly robust |
| but we do not have anything better */ |
| char *abs_command_directory = 0; |
| if (!command_directory || !file_name_is_absolute (command_directory)) |
| { |
| size_t space = 512; |
| char *cwd; |
| |
| while (1) |
| { |
| cwd = getcwd (NULL, space); |
| if (!cwd) |
| { |
| if (errno == ERANGE) |
| { |
| size_t max_size = (size_t)-1; |
| if (space > max_size / 2 -1) |
| break; |
| space *= 2; |
| } |
| else |
| break; |
| } |
| else |
| break; |
| } |
| if (cwd) |
| { |
| if (command_directory) |
| { |
| xasprintf (&abs_command_directory, "%s/%s", |
| cwd, command_directory); |
| } |
| else |
| abs_command_directory = strdup (cwd); |
| free (cwd); |
| } |
| } |
| else |
| abs_command_directory = strdup (command_directory); |
| |
| if (abs_command_directory) |
| { |
| STRING_LIST *file_directories |
| = splitdir (abs_command_directory); |
| free (abs_command_directory); |
| size_t nr = file_directories->number; |
| char **list = file_directories->list; |
| |
| if (nr > 3 && !strcmp (list[nr -1], ".libs") |
| && !strcmp (list[nr -2], "C") |
| && !strcmp (list[nr -3], "tta")) |
| texinfo_uninstalled = 1; |
| destroy_strings_list (file_directories); |
| } |
| } |
| |
| #ifdef EMBED_PERL |
| embedded_interpreter = 1; |
| default_is_html = 0; |
| #endif |
| |
| perl_embed_env = getenv ("TEXINFO_C_EMBED_PERL"); |
| if (perl_embed_env && !strcmp (perl_embed_env, "0")) |
| embedded_interpreter = 0; |
| |
| if (texinfo_uninstalled) |
| { |
| t2a_srcdir = getenv ("t2a_srcdir"); |
| if (t2a_srcdir) |
| t2a_srcdir = strdup (t2a_srcdir); |
| else |
| { |
| /* similar to ModulePath.pm with updir 2 (or 3 for .libs) */ |
| if (command_directory) |
| {/* within tta/C/.libs */ |
| xasprintf (&t2a_srcdir, "%s/../..", |
| command_directory); |
| } |
| else |
| t2a_srcdir = strdup (".."); |
| } |
| |
| t2a_builddir = getenv ("t2a_builddir"); |
| if (!t2a_builddir) |
| /* this is correct for in-source builds only. */ |
| t2a_builddir = strdup (t2a_srcdir); |
| else |
| t2a_builddir = strdup (t2a_builddir); |
| |
| xasprintf (&extensions_dir, "%s/perl/ext", t2a_srcdir); |
| } |
| else |
| xasprintf (&extensions_dir, "%s/ext", converterdatadir); |
| |
| free (command_directory); |
| |
| memset (&internal_extension_dirs, 0, sizeof (STRING_LIST)); |
| |
| add_string (extensions_dir, &internal_extension_dirs); |
| |
| |
| if (texinfo_uninstalled) |
| version_for_embedded_interpreter_check = PACKAGE_VERSION_CONFIG "+nc"; |
| else |
| version_for_embedded_interpreter_check = PACKAGE_VERSION_CONFIG; |
| |
| /* load interpreter if needed and setup paths and defauts if not already |
| done by the interpreter. |
| Done early because options defaults are used in help |
| and paths are needed to locate file used for interpreter embedding |
| and setup by the interpreter */ |
| txi_setup_main_load_interpreter (embedded_interpreter, |
| texinfo_uninstalled, |
| converterdatadir, t2a_builddir, t2a_srcdir, |
| &argc, &argv, &env, |
| version_for_embedded_interpreter_check); |
| |
| free (t2a_builddir); |
| free (t2a_srcdir); |
| |
| /* the encoding used to decode command line arguments, and also for |
| file names encoding */ |
| /* needs to be called after setlocale */ |
| /* from Gnulib codeset.m4 */ |
| #ifdef HAVE_LANGINFO_CODESET |
| langinfo_locale_encoding = nl_langinfo (CODESET); |
| if (langinfo_locale_encoding) |
| locale_encoding = strdup (langinfo_locale_encoding); |
| #endif |
| |
| #ifdef _WIN32 |
| if (!locale_encoding) |
| { |
| unsigned cp = GetACP (); |
| xasprintf (&locale_encoding, "cp%u", cp); |
| } |
| #endif |
| |
| /* Set initial configuration */ |
| /* program_options corresponds to main_program_set_options in texi2any */ |
| txi_set_base_default_options (&program_options, locale_encoding, |
| program_file); |
| |
| free (locale_encoding); |
| |
| /* NOTE this is not exactly the same as in Perl. In Perl, when uninstalled, |
| it is possible to be configured or not, and +nc is only postpended if |
| not configured. This code is always configured. We still |
| set to not configured if not installed, to correspond to texi2any.pl |
| being called in the build directory */ |
| if (texinfo_uninstalled) |
| { |
| add_option_value (&program_options, "PACKAGE_AND_VERSION", 0, |
| PACKAGE_NAME_CONFIG " " PACKAGE_VERSION_CONFIG "+nc"); |
| add_option_value (&program_options, "PACKAGE_VERSION", 0, |
| PACKAGE_VERSION_CONFIG "+nc"); |
| } |
| |
| /* set default output format. Is info in texi2any.pl */ |
| /* better than making it the default value independently of the |
| implementation */ |
| if (default_is_html) |
| add_option_value (&program_options, "TEXINFO_OUTPUT_FORMAT", 0, "html"); |
| else |
| add_option_value (&program_options, "TEXINFO_OUTPUT_FORMAT", 0, "info"); |
| |
| #ifdef _WIN32 |
| /* |
| In Windows, a character in file name is encoded according to the current |
| codepage, and converted to/from UTF-16 in the filesystem. If a file name is |
| not encoded in the current codepage, the file name will appear with erroneous |
| characters when listing file names. Also the encoding and decoding to |
| UTF-16 may fail, especially when the codepage is 8bit while the file name |
| is encoded in a multibyte encoding. |
| We assume that in Windows the file names are reencoded in the current |
| codepage encoding to avoid those issues. |
| */ |
| add_option_value (&program_options, "DOC_ENCODING_FOR_INPUT_FILE_NAME", |
| 0, 0); |
| #endif |
| |
| memset (&deprecated_directories, 0, sizeof (DEPRECATED_DIRS_LIST)); |
| |
| texinfo_language_config_dirs |
| = set_subdir_directories ("texinfo", &deprecated_directories); |
| |
| converter_config_dirs_array_ref |
| = set_subdir_directories (CONVERTER_CONFIG, &deprecated_directories); |
| |
| memset (&converter_config_dirs, 0, sizeof (STRING_LIST)); |
| add_string (curdir, &converter_config_dirs); |
| copy_strings (&converter_config_dirs, converter_config_dirs_array_ref); |
| |
| destroy_strings_list (converter_config_dirs_array_ref); |
| |
| memset (&converter_init_dirs, 0, sizeof (STRING_LIST)); |
| copy_strings (&converter_init_dirs, &converter_config_dirs); |
| |
| for (i = 0; i < texinfo_language_config_dirs->number; i++) |
| { |
| char *init_dir; |
| DEPRECATED_DIR_INFO *deprecated_dir_info; |
| char *texinfo_config_dir = texinfo_language_config_dirs->list[i]; |
| |
| xasprintf (&init_dir, "%s/init", texinfo_config_dir); |
| add_string (init_dir, &converter_init_dirs); |
| |
| deprecated_dir_info = find_deprecated_dir_info (&deprecated_directories, |
| texinfo_config_dir); |
| if (deprecated_dir_info) |
| { |
| char *reference_init_dir; |
| xasprintf (&reference_init_dir, "%s/init", |
| deprecated_dir_info->reference_dir); |
| add_new_deprecated_dir_info (&deprecated_directories, |
| init_dir, reference_init_dir); |
| free (reference_init_dir); |
| } |
| free (init_dir); |
| } |
| add_string (extensions_dir, &converter_init_dirs); |
| |
| memset (&prepend_dirs, 0, sizeof (STRING_LIST)); |
| memset (&conf_dirs, 0, sizeof (STRING_LIST)); |
| |
| memset (&input_files, 0, sizeof (STRING_LIST)); |
| |
| initialize_options_list (&cmdline_options); |
| |
| store_value (&values, "txicommandconditionals", "1"); |
| |
| /* always consider that command-line array options are set from |
| the command-line */ |
| |
| options_list_add_option_number (&cmdline_options, |
| cmdline_options.options->CSS_FILES.number); |
| options_list_add_option_number (&cmdline_options, |
| cmdline_options.options->CSS_REFS.number); |
| options_list_add_option_number (&cmdline_options, |
| cmdline_options.options->INCLUDE_DIRECTORIES.number); |
| options_list_add_option_number (&cmdline_options, |
| cmdline_options.options->TEXINFO_LANGUAGE_DIRECTORIES.number); |
| options_list_add_option_number (&cmdline_options, |
| cmdline_options.options->EXPANDED_FORMATS.number); |
| |
| init_files_options = |
| GNUT_initialize_customization (&program_file, &program_options, |
| &cmdline_options); |
| |
| /* |
| read initialization files. Better to do that after |
| Texinfo::Config::GNUT_initialize_customization() in case loaded |
| files replace default options. |
| */ |
| memset (&config_init_files, 0, sizeof (STRING_LIST)); |
| memset (&reversed_converter_config_dirs, 0, sizeof (STRING_LIST)); |
| memset (&deprecated_dirs_used, 0, sizeof (DEPRECATED_DIRS_LIST)); |
| |
| if (converter_config_dirs.number > 0) |
| { |
| for (i = converter_config_dirs.number; i > 0; i--) |
| { |
| add_string (converter_config_dirs.list[i-1], |
| &reversed_converter_config_dirs); |
| } |
| } |
| |
| locate_file_in_dirs (conf_file_name, &reversed_converter_config_dirs, |
| &config_init_files, |
| &deprecated_directories, &deprecated_dirs_used); |
| |
| free_strings_list (&reversed_converter_config_dirs); |
| |
| for (i = 0; i < config_init_files.number; i++) |
| { |
| int status = txi_load_init_file (config_init_files.list[i], |
| embedded_interpreter); |
| if (status) |
| loaded_init_files_nr++; |
| } |
| |
| warn_deprecated_dirs (&deprecated_dirs_used); |
| free_strings_list (&config_init_files); |
| |
| /* Parse command line */ |
| |
| memset (&init_file_dirs, 0, sizeof (STRING_LIST)); |
| memset (&ignored_formats, 0, sizeof (STRING_LIST)); |
| memset (&texi2dvi_args, 0, sizeof (STRING_LIST)); |
| |
| while (1) |
| { |
| int option_character; |
| |
| option_character = getopt_long (argc, argv, "VhvFc:D:e:f:I:P:o:E:U:", |
| long_options, |
| &getopt_long_index); |
| |
| if (option_character == -1) |
| break; |
| |
| switch (option_character) |
| { |
| case 0: |
| /* option sets a flag, nothing to do */ |
| break; |
| case _FORMAT_OPT: |
| set_cmdline_format (long_options[getopt_long_index].name); |
| break; |
| case XML_OPT: |
| set_cmdline_format ("texinfoxml"); |
| break; |
| case NO_MIMICKING_OPT: |
| free (program_file); |
| program_file = strdup (program_basename); |
| GNUT_set_from_cmdline (&program_options, |
| cmdline_options.options->PROGRAM.number, |
| program_file); |
| break; |
| case 'c': |
| get_cmdline_customization_option (&cmdline_options, optarg); |
| break; |
| case DOCUMENT_LANGUAGE_OPT: |
| { |
| const char *region_code; |
| int lang_is_valid; |
| int region_is_valid; |
| char *lang; |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->documentlanguage.number, |
| optarg); |
| |
| lang = analyze_documentlanguage_argument (optarg, ®ion_code, |
| &lang_is_valid, ®ion_is_valid); |
| if (!lang_is_valid) |
| { |
| txi_config_document_warn ("%s is not a valid language code", |
| lang); |
| } |
| free (lang); |
| if (!region_is_valid) |
| { |
| txi_config_document_warn ("%s is not a valid region code", |
| region_code); |
| } |
| } |
| break; |
| case DEBUG_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->DEBUG.number, |
| optarg); |
| add_string ("--debug", &texi2dvi_args); |
| break; |
| case 'e': |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->ERROR_LIMIT.number, |
| optarg); |
| break; |
| case 'f': |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->FILLCOLUMN.number, |
| optarg); |
| break; |
| case 'E': |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->MACRO_EXPAND.number, |
| optarg); |
| break; |
| case 'F': |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->FORCE.number, "1"); |
| break; |
| case DISABLE_ENCODING_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->ENABLE_ENCODING.number, |
| "0"); |
| break; |
| case ENABLE_ENCODING_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->ENABLE_ENCODING.number, |
| "1"); |
| break; |
| case INTERNAL_LINKS_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->INTERNAL_LINKS.number, |
| optarg); |
| break; |
| case NODE_FILES_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->NODE_FILES.number, |
| "1"); |
| break; |
| case NO_NODE_FILES_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->NODE_FILES.number, |
| "0"); |
| break; |
| case NUMBER_FOOTNOTES_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->NUMBER_FOOTNOTES.number, |
| "1"); |
| break; |
| case NO_NUMBER_FOOTNOTES_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->NUMBER_FOOTNOTES.number, |
| "0"); |
| break; |
| case NUMBER_SECTIONS_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->NUMBER_SECTIONS.number, |
| "1"); |
| break; |
| case NO_NUMBER_SECTIONS_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->NUMBER_SECTIONS.number, |
| "0"); |
| break; |
| case SPLIT_SIZE_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->SPLIT_SIZE.number, |
| optarg); |
| break; |
| case TRACE_INCLUDES_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->TRACE_INCLUDES.number, |
| "1"); |
| break; |
| case TRANSLITERATE_FILE_NAMES_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->TRANSLITERATE_FILE_NAMES.number, |
| "1"); |
| break; |
| case NO_TRANSLITERATE_FILE_NAMES_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->TRANSLITERATE_FILE_NAMES.number, |
| "0"); |
| break; |
| case NO_VALIDATE_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->novalidate.number, "1"); |
| break; |
| case 'v': |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->VERBOSE.number, "1"); |
| add_string ("--verbose", &texi2dvi_args); |
| break; |
| case NO_VERBOSE_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->VERBOSE.number, "0"); |
| break; |
| case NO_WARN_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->NO_WARN.number, "1"); |
| break; |
| case NO_HEADERS_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->HEADERS.number, "0"); |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->FORMAT_MENU.number, |
| "nomenu"); |
| { |
| size_t option_nr |
| = program_options.options->TEXINFO_OUTPUT_FORMAT.number; |
| OPTION *output_format_option = GNUT_get_conf (option_nr); |
| if (output_format_option && output_format_option->o.string |
| && !strcmp (output_format_option->o.string, "info")) |
| GNUT_set_customization_default (option_nr, "plaintext"); |
| } |
| break; |
| case HEADERS_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->HEADERS.number, "1"); |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->FORMAT_MENU.number, |
| "set_format_menu_from_cmdline_header_option"); |
| break; |
| case 'I': |
| { |
| OPTION *option = &cmdline_options.options->INCLUDE_DIRECTORIES; |
| push_include_directory (option->o.strlist, optarg); |
| add_string ("-I", &texi2dvi_args); |
| add_string (optarg, &texi2dvi_args); |
| } |
| break; |
| case 'P': |
| push_include_directory (&prepend_dirs, optarg); |
| break; |
| case CONF_DIR_OPT: |
| push_include_directory (&conf_dirs, optarg); |
| break; |
| case CSS_INCLUDE_OPT: |
| { |
| OPTION *option = &cmdline_options.options->CSS_FILES; |
| add_string (optarg, option->o.strlist); |
| } |
| break; |
| case CSS_REF_OPT: |
| { |
| OPTION *option = &cmdline_options.options->CSS_REFS; |
| char *value = GNUT_decode_input ((char *) optarg); |
| add_string (value, option->o.strlist); |
| free (value); |
| } |
| break; |
| case 'h': |
| print_help_p = 1; |
| break; |
| case INIT_FILE_OPT: |
| { |
| test_option = GNUT_get_conf (program_options.options->TEST.number); |
| if (test_option && test_option->o.integer > 0) |
| test_mode_set = 1; |
| |
| if (test_mode_set) |
| locate_and_load_init_file (optarg, &conf_dirs, 0); |
| else |
| { |
| copy_strings (&init_file_dirs, &conf_dirs); |
| copy_strings (&init_file_dirs, &converter_init_dirs); |
| locate_and_load_init_file (optarg, &init_file_dirs, |
| &deprecated_directories); |
| clear_strings_list (&init_file_dirs); |
| } |
| } |
| break; |
| case XOPT_OPT: |
| add_string (optarg, &texi2dvi_args); |
| Xopt_arg_nr++; |
| break; |
| case _SILENT_OPT: |
| { |
| char *format_option; |
| xasprintf (&format_option, "--%s", |
| long_options[getopt_long_index].name); |
| add_string (format_option, &texi2dvi_args); |
| free (format_option); |
| } |
| break; |
| case 'D': |
| { |
| const char *p = optarg; |
| size_t flag_len = strcspn (optarg, whitespace_chars); |
| if (flag_len) |
| { |
| size_t spaces_len; |
| const char *flag_value = 0; |
| char *decoded_flag_value; |
| char *flag = strndup (optarg, flag_len); |
| char *decoded_flag = GNUT_decode_input (flag); |
| char *texi2dvi_option; |
| |
| p += flag_len; |
| spaces_len = strspn (p, whitespace_chars); |
| if (spaces_len) |
| { |
| p += spaces_len; |
| if (*p) |
| { |
| flag_value = p; |
| /* actually const but constrained by prototypes */ |
| decoded_flag_value |
| = GNUT_decode_input ((char *) flag_value); |
| } |
| } |
| if (!flag_value) |
| { |
| flag_value = "1"; |
| decoded_flag_value = strdup (flag_value); |
| } |
| store_value (&values, decoded_flag, decoded_flag_value); |
| free (decoded_flag); |
| free (decoded_flag_value); |
| |
| xasprintf (&texi2dvi_option, "--command=@set %s %s", |
| flag, flag_value); |
| add_string (texi2dvi_option, &texi2dvi_args); |
| free (texi2dvi_option); |
| |
| free (flag); |
| } |
| } |
| break; |
| case 'U': |
| { |
| char *texi2dvi_option; |
| /* actually const but constrained by prototypes */ |
| char *value = GNUT_decode_input ((char *) optarg); |
| clear_value (&values, value); |
| free (value); |
| |
| xasprintf (&texi2dvi_option, "--command=@clear %s", optarg); |
| add_string (texi2dvi_option, &texi2dvi_args); |
| free (texi2dvi_option); |
| } |
| break; |
| case 'V': |
| { |
| char *encoded_message; |
| char *message |
| = CONVERTER_CONFIG " (GNU texinfo) " PACKAGE_VERSION_CONFIG "\n\n"; |
| char *formatted_message; |
| |
| encoded_message = GNUT_encode_message (message); |
| printf ("%s", encoded_message); |
| free (encoded_message); |
| |
| xasprintf (&formatted_message, _( |
| "Copyright (C) %s Free Software Foundation, Inc.\n" |
| "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n" |
| "This is free software: you are free to change and redistribute it.\n" |
| "There is NO WARRANTY, to the extent permitted by law."), |
| "2024"); |
| encoded_message = GNUT_encode_message (formatted_message); |
| free (formatted_message); |
| printf ("%s\n", encoded_message); |
| free (encoded_message); |
| |
| exit (EXIT_SUCCESS); |
| } |
| break; |
| case FOOTNOTE_STYLE_OPT: |
| { |
| /* actually const but constrained by prototypes */ |
| char *value = GNUT_decode_input ((char *) optarg); |
| if (!strcmp (value, "end") || !strcmp (value, "separate")) |
| { |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->footnotestyle.number, |
| value); |
| } |
| else |
| { |
| char *formatted_message; |
| char *encoded_message; |
| |
| xasprintf (&formatted_message, |
| _("%s: --footnote-style arg must be `separate' or `end', not `%s'."), |
| program_file, value); |
| encoded_message = GNUT_encode_message (formatted_message); |
| free (formatted_message); |
| fprintf (stderr, "%s\n", encoded_message); |
| free (encoded_message); |
| exit (EXIT_FAILURE); |
| } |
| free (value); |
| } |
| break; |
| case 'p': |
| { |
| /* actually const but constrained by prototypes */ |
| char *value = GNUT_decode_input ((char *) optarg); |
| if (!strcmp (value, "none") || !strcmp (value, "asis") |
| || is_ascii_digit (value)) |
| { |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->paragraphindent.number, |
| value); |
| } |
| else |
| { |
| char *formatted_message; |
| char *encoded_message; |
| |
| xasprintf (&formatted_message, |
| _("%s: --paragraph-indent arg must be numeric/`none'/`asis', not `%s'."), |
| program_file, value); |
| encoded_message = GNUT_encode_message (formatted_message); |
| free (formatted_message); |
| fprintf (stderr, "%s\n", encoded_message); |
| free (encoded_message); |
| exit (EXIT_FAILURE); |
| } |
| free (value); |
| } |
| break; |
| case 'o': |
| { |
| OPTION *option = &cmdline_options.options->OUTFILE; |
| /* actually const but constrained by prototypes */ |
| char *decoded_string = GNUT_decode_input ((char *) optarg); |
| if (strcmp (optarg, "-")) |
| { |
| size_t opt_len = strlen (optarg); |
| struct stat finfo; |
| |
| if (optarg[opt_len -1] == '/' |
| || (stat (optarg, &finfo) == 0 && S_ISDIR (finfo.st_mode))) |
| { |
| GNUT_set_from_cmdline (&cmdline_options, |
| option->number, "undef"); |
| option = &cmdline_options.options->SUBDIR; |
| } |
| } |
| GNUT_set_from_cmdline (&cmdline_options, |
| option->number, decoded_string); |
| free (decoded_string); |
| |
| add_string ("-o", &texi2dvi_args); |
| add_string (optarg, &texi2dvi_args); |
| } |
| break; |
| case NO_SPLIT_OPT: |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->SPLIT.number, ""); |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->SPLIT_SIZE.number, |
| "undef"); |
| break; |
| case SPLIT_OPT: |
| { |
| char *split = GNUT_decode_input (optarg); |
| size_t i; |
| for (i = 0; possible_split[i]; i++) |
| if (!strcmp (possible_split[i], optarg)) |
| break; |
| if (!possible_split[i]) |
| { |
| txi_config_document_warn ("%s is not a valid split possibility", |
| split); |
| free (split); |
| split = strdup ("node"); |
| } |
| GNUT_set_from_cmdline (&cmdline_options, |
| cmdline_options.options->SPLIT.number, split); |
| free (split); |
| } |
| break; |
| #define IFFORMAT_CASE(upcase, name) \ |
| case IF ## upcase ## _OPT: \ |
| set_expansion (&cmdline_options, &ignored_formats, #name); \ |
| break; \ |
| case NO_IF ## upcase ## _OPT: \ |
| unset_expansion (&cmdline_options, &ignored_formats, #name); \ |
| break; |
| IFFORMAT_CASE(DOCBOOK, docbook) |
| IFFORMAT_CASE(INFO, info) |
| IFFORMAT_CASE(HTML, html) |
| IFFORMAT_CASE(LATEX, latex) |
| IFFORMAT_CASE(PLAINTEXT, plaintext) |
| IFFORMAT_CASE(TEX, tex) |
| IFFORMAT_CASE(XML, xml) |
| #undef IFFORMAT_CASE |
| /* |
| case IFTEX_OPT: |
| set_expansion (&cmdline_options, &ignored_formats, "tex"); |
| break; |
| case NO_IFTEX_OPT: |
| unset_expansion (&cmdline_options, &ignored_formats, "tex"); |
| break; |
| */ |
| /* |
| case '?': |
| if (isprint (optopt)) |
| fprintf (stderr, "Unknown option `-%c'\n", optopt); |
| else |
| fprintf (stderr, |
| "Unknown option character `\\x%x'\n", |
| optopt); |
| break; |
| */ |
| case '?': /* unknown option or option with missing argument */ |
| exit (EXIT_FAILURE); |
| break; |
| default: |
| fprintf (stderr, |
| "BUG: getopt_long unexpected option_character: %d '%c'\n", |
| option_character, (char) option_character); |
| exit (EXIT_FAILURE); |
| } |
| } |
| |
| free_strings_list (&init_file_dirs); |
| |
| if (print_help_p) |
| { |
| char *encoded_message; |
| char *endptr; |
| const char *option_value; |
| int paragraphindent_size; |
| TEXT help_message; |
| OPTION *error_limit_option |
| = GNUT_get_conf (program_options.options->ERROR_LIMIT.number); |
| |
| text_init (&help_message); |
| text_printf (&help_message, |
| _("Usage: %s [OPTION]... TEXINFO-FILE..."), program_file); |
| text_append_n (&help_message, "\n\n", 2); |
| /* no added translations, reuse translations with they already exist */ |
| if (default_is_html) |
| text_append (&help_message, |
| "Translate Texinfo source documentation to various other formats."); |
| else |
| /* lie on the name, but this is no such a big lie */ |
| text_append (&help_message, |
| _("Translate Texinfo source documentation to various other formats, by default\n" |
| "Info files suitable for reading online with Emacs or standalone GNU Info.\n\n" |
| "This program is commonly installed as both `makeinfo' and `texi2any';\n" |
| "the behavior is identical, and does not depend on the installed name.")); |
| text_append_n (&help_message, "\n\n", 2); |
| |
| text_append (&help_message, _("General options:")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --document-language=STR locale to use in translating Texinfo keywords\n" |
| " for the output document (default C)")); |
| text_append_n (&help_message, "\n", 1); |
| text_printf (&help_message, |
| _(" --error-limit=NUM quit after NUM errors (default %d)"), |
| error_limit_option->o.integer); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --force preserve output even if errors")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --help display this help and exit")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --no-validate suppress node cross-reference validation")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --no-warn suppress warnings (but not errors)")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --conf-dir=DIR search also for initialization files in DIR")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --init-file=FILE load FILE to modify the default behavior")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" -c, --set-customization-variable VAR=VAL set customization variable VAR\n" |
| " to value VAL")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --trace-includes print names of included files")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" -v, --verbose explain what is being done")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --version display version information and exit")); |
| text_append_n (&help_message, "\n\n", 2); |
| |
| if (default_is_html) |
| text_append (&help_message, "Output format selection (default is to produce HTML):"); |
| else |
| text_append (&help_message, _("Output format selection (default is to produce Info):")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --docbook output Docbook XML")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --html output HTML")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --epub3 output EPUB 3")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --latex output LaTeX")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --plaintext output plain text rather than Info")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --xml output Texinfo XML")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" --dvi, --dvipdf, --ps, --pdf call texi2dvi to generate given output,\n" |
| " after checking validity of TEXINFO-FILE")); |
| text_append_n (&help_message, "\n\n", 2); |
| |
| text_append (&help_message, _("General output options:")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " -E, --macro-expand=FILE output macro-expanded source to FILE,\n" |
| " ignoring any @setfilename")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --no-headers suppress node separators, Node: lines, and menus\n" |
| " from Info output (thus producing plain text)\n" |
| " or from HTML (thus producing shorter output).\n" |
| " Also, if producing Info, write to\n" |
| " standard output by default.")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --no-split suppress any splitting of the output;\n" |
| " generate only one output file")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --[no-]number-sections output chapter and sectioning numbers;\n" |
| " default is on")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --[no-]number-footnotes number footnotes sequentially; default is on")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " -o, --output=DEST output to DEST.\n" |
| " With split output, create DEST as a directory\n" |
| " and put the output files there.\n" |
| " With non-split output, if DEST is already\n" |
| " a directory or ends with a /,\n" |
| " put the output file there.\n" |
| " Otherwise, DEST names the output file.")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --disable-encoding do not output accented and special characters\n" |
| " in Info and plain text output based on document\n" |
| " encoding")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --enable-encoding override --disable-encoding (default)")); |
| text_append_n (&help_message, "\n\n", 2); |
| |
| text_append (&help_message, _("Options for Info and plain text:")); |
| text_append_n (&help_message, "\n", 1); |
| text_printf (&help_message, _( |
| " --fill-column=NUM break Info lines at NUM columns (default %d)"), |
| txi_base_sorted_options[program_options.options->FILLCOLUMN.number -1]->o.integer); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --footnote-style=STYLE output footnotes in Info according to STYLE:\n" |
| " `separate' to put them in their own node;\n" |
| " `end' to put them at the end of the node, in\n" |
| " which they are defined (this is the default)")); |
| text_append_n (&help_message, "\n", 1); |
| |
| option_value |
| = txi_base_sorted_options[program_options.options->paragraphindent.number -1]->o.string; |
| paragraphindent_size = strtol (option_value, &endptr, 10); |
| text_printf (&help_message, _( |
| " --paragraph-indent=VAL indent Info paragraphs by VAL spaces (default %d).\n" |
| " If VAL is `none', do not indent; if VAL is\n" |
| " `asis', preserve existing indentation."), |
| paragraphindent_size); |
| text_append_n (&help_message, "\n", 1); |
| text_printf (&help_message, _( |
| " --split-size=NUM split Info files at size NUM (default %d)"), |
| txi_base_sorted_options[program_options.options->SPLIT_SIZE.number -1]->o.integer); |
| text_append_n (&help_message, "\n\n", 2); |
| |
| text_append (&help_message, _("Options for HTML:")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --css-include=FILE include FILE in HTML <style> output;\n" |
| " read stdin if FILE is -")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --css-ref=URL generate CSS reference to URL")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --internal-links=FILE produce list of internal links in FILE")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --split=SPLIT split at SPLIT, where SPLIT may be `chapter',\n" |
| " `section' or `node'")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --transliterate-file-names use file names in ASCII transliteration")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --node-files produce redirection files for nodes and\n" |
| " anchors; default is set only if split")); |
| text_append_n (&help_message, "\n\n", 2); |
| |
| text_append (&help_message, _("Options for DVI/PS/PDF:")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --Xopt=OPT pass OPT to texi2dvi; can be repeated")); |
| text_append_n (&help_message, "\n\n", 2); |
| |
| text_append (&help_message, _("Input file options:")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" -D VAR define the variable VAR, as with @set")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" -D 'VAR VAL' define VAR to VAL (one shell argument)")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" -I DIR append DIR to the @include search path")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" -P DIR prepend DIR to the @include search path")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, |
| _(" -U VAR undefine the variable VAR, as with @clear")); |
| text_append_n (&help_message, "\n\n", 2); |
| |
| text_append (&help_message, _( |
| "Conditional processing in input:")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --ifdocbook process @ifdocbook and @docbook")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --ifhtml process @ifhtml and @html")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --ifinfo process @ifinfo")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --iflatex process @iflatex and @latex")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --ifplaintext process @ifplaintext")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --iftex process @iftex and @tex")); |
| text_append_n (&help_message, "\n", 1); |
| text_append (&help_message, _( |
| " --ifxml process @ifxml and @xml")); |
| text_append_n (&help_message, "\n", 1); |
| |
| text_append_n (&help_message, "\n", 1); |
| |
| text_append (&help_message, _( |
| " By default, an --ifFORMAT setting is on only when the output format\n" |
| " is FORMAT; for example, --ifhtml is on when outputting HTML.\n" |
| " Also, when --ifFORMAT is on, @ifnotFORMAT text is not processed.")); |
| |
| text_append_n (&help_message, "\n\n", 2); |
| |
| text_append (&help_message, _( |
| " Each --ifFORMAT option may be prefixed with `--no-' to negate it;\n" |
| " for example, --no-ifhtml means not to process @ifhtml or @html text,\n" |
| " and to process @ifnothtml text.")); |
| text_append_n (&help_message, "\n\n", 2); |
| |
| text_append (&help_message, _("Examples:")); |
| text_append_n (&help_message, "\n", 1); |
| text_printf (&help_message, _( |
| " %s foo.texi write Info"), program_file); |
| text_append_n (&help_message, "\n", 1); |
| text_printf (&help_message, _( |
| " %s --html foo.texi write HTML"), program_file); |
| text_append_n (&help_message, "\n", 1); |
| text_printf (&help_message, _( |
| " %s --xml foo.texi write Texinfo XML"), program_file); |
| text_append_n (&help_message, "\n", 1); |
| text_printf (&help_message, _( |
| " %s --docbook foo.texi write Docbook XML"), program_file); |
| text_append_n (&help_message, "\n", 1); |
| text_printf (&help_message, _( |
| " %s --plaintext foo.texi write plain text to standard output"), program_file); |
| text_append_n (&help_message, "\n", 1); |
| text_printf (&help_message, _( |
| " %s --pdf foo.texi write PDF using texi2dvi"), program_file); |
| text_append_n (&help_message, "\n\n", 2); |
| |
| text_printf (&help_message, _( |
| " %s --html --no-headers foo.texi write html without node lines, menus"), program_file); |
| text_append_n (&help_message, "\n", 1); |
| text_printf (&help_message, _( |
| " %s --number-sections foo.texi write Info with numbered sections"), program_file); |
| text_append_n (&help_message, "\n", 1); |
| text_printf (&help_message, _( |
| " %s --no-split foo.texi write one Info file however big"), program_file); |
| text_append_n (&help_message, "\n\n", 2); |
| |
| text_append (&help_message, _("Email bug reports to bug-texinfo@gnu.org,\n" |
| "general questions and discussion to help-texinfo@gnu.org.\n" |
| "Texinfo home page: https://www.gnu.org/software/texinfo/")); |
| text_append_n (&help_message, "\n", 1); |
| |
| encoded_message = GNUT_encode_message (help_message.text); |
| free (help_message.text); |
| printf ("%s", encoded_message); |
| free (encoded_message); |
| exit (EXIT_SUCCESS); |
| } |
| |
| if (cmdline_options.options->TEXI2HTML.o.integer > 0) |
| { |
| set_format ("html"); |
| store_value (&values, "TEXI2HTML", "1"); |
| } |
| |
| if (!embedded_interpreter) |
| /* it is the best we have without an embedded interpreter */ |
| add_option_value (&program_options, "XS_STRXFRM_COLLATION_LOCALE", 0, |
| "en_US"); |
| |
| html_math_option = GNUT_get_conf (program_options.options->HTML_MATH.number); |
| if (html_math_option && html_math_option->o.string |
| && !strcmp (html_math_option->o.string, "l2h")) |
| locate_and_load_extension_file ("latex2html.pm", &internal_extension_dirs); |
| |
| if (html_math_option && html_math_option->o.string |
| && !strcmp (html_math_option->o.string, "t4h")) |
| locate_and_load_extension_file ("tex4ht.pm", &internal_extension_dirs); |
| |
| highlight_syntax_option |
| = GNUT_get_conf (program_options.options->HIGHLIGHT_SYNTAX.number); |
| if (highlight_syntax_option && highlight_syntax_option->o.string |
| && strlen (highlight_syntax_option->o.string)) |
| locate_and_load_extension_file ("highlight_syntax.pm", |
| &internal_extension_dirs); |
| |
| /* re-set in case it was set in init files */ |
| test_option = GNUT_get_conf (program_options.options->TEST.number); |
| if (test_option && test_option->o.integer > 0) |
| test_mode_set = 1; |
| |
| no_warn_option = GNUT_get_conf (program_options.options->NO_WARN.number); |
| if (no_warn_option && no_warn_option->o.integer > 0) |
| no_warn = 1; |
| |
| debug_option = GNUT_get_conf (program_options.options->DEBUG.number); |
| if (debug_option && debug_option->o.integer > 0) |
| debug = debug_option->o.integer; |
| |
| if (test_mode_set) |
| { |
| add_option_value (&program_options, "PACKAGE_VERSION", 0, ""); |
| add_option_value (&program_options, "PACKAGE", 0, "texinfo"); |
| add_option_value (&program_options, "PACKAGE_NAME", 0, "GNU Texinfo"); |
| add_option_value (&program_options, "PACKAGE_AND_VERSION", 0, |
| "texinfo"); |
| add_option_value (&program_options, "PACKAGE_URL", 0, |
| "https://www.gnu.org/software/texinfo/"); |
| add_option_value (&program_options, "PROGRAM", 0, "texi2any"); |
| |
| free (program_file); |
| program_file = strdup ("texi2any"); |
| } |
| |
| init_file_format = GNUT_get_format_from_init_file (); |
| if (init_file_format) |
| { |
| set_format (init_file_format); |
| free (init_file_format); |
| } |
| |
| texinfo_output_format_env = getenv ("TEXINFO_OUTPUT_FORMAT"); |
| if (texinfo_output_format_env && strlen (texinfo_output_format_env)) |
| { |
| char *format_name = GNUT_decode_input (texinfo_output_format_env); |
| set_format (format_name); |
| free (format_name); |
| } |
| |
| output_format_option |
| = GNUT_get_conf (program_options.options->TEXINFO_OUTPUT_FORMAT.number); |
| output_format = output_format_option->o.string; |
| |
| if (!test_mode_set && txi_paths_info.texinfo_uninstalled |
| && txi_paths_info.p.uninstalled.t2a_srcdir) |
| { |
| char *in_source_util_dir; |
| xasprintf (&in_source_util_dir, "%s/../util", |
| txi_paths_info.p.uninstalled.t2a_srcdir); |
| add_string (in_source_util_dir, texinfo_language_config_dirs); |
| free (in_source_util_dir); |
| } |
| |
| /* Setup output string translations (including Locales path). */ |
| txi_general_output_strings_setup (0); |
| |
| /* determine the format_specification now that the output format is known */ |
| for (i = 0; formats_table[i].name; i++) |
| { |
| if (!strcmp (formats_table[i].name, output_format)) |
| { |
| format_specification = &formats_table[i]; |
| break; |
| } |
| } |
| |
| tree_transformations_option |
| = GNUT_get_conf (program_options.options->TREE_TRANSFORMATIONS.number); |
| if (tree_transformations_option && tree_transformations_option->o.string |
| && strlen (tree_transformations_option->o.string)) |
| { |
| char *text = strdup (tree_transformations_option->o.string); |
| char *transformation = strtok (text, ","); |
| |
| while (transformation) |
| { |
| if (strlen (transformation)) |
| { |
| unsigned long transfo_flag |
| = txi_find_tree_transformation (transformation); |
| if (transfo_flag) |
| transformation_flags |= transfo_flag; |
| else |
| txi_config_document_warn ("unknown tree transformation %s", |
| transformation); |
| } |
| transformation = strtok (NULL, ","); |
| } |
| free (text); |
| } |
| |
| /* for a format setup with an init file */ |
| if (format_specification->init_file) |
| locate_and_load_extension_file (format_specification->init_file, |
| &internal_extension_dirs); |
| |
| if (format_specification->converted_format) |
| { |
| converted_format = format_specification->converted_format; |
| /* reset the format_specification to the converted_format specification */ |
| for (i = 0; formats_table[i].name; i++) |
| { |
| if (!strcmp (formats_table[i].name, converted_format)) |
| { |
| format_specification = &formats_table[i]; |
| break; |
| } |
| } |
| } |
| else |
| converted_format = output_format; |
| |
| split_option = GNUT_get_conf (program_options.options->SPLIT.number); |
| if (split_option && split_option->o.string |
| && strlen (split_option->o.string) |
| && !(format_specification->flags & STTF_split)) |
| { |
| if (strcmp (converted_format, output_format)) |
| { |
| txi_config_document_warn ( |
| "ignoring splitting for converted format %s (for %s)", |
| name_of_format (converted_format), name_of_format (output_format)); |
| } |
| else |
| { |
| txi_config_document_warn ("ignoring splitting for format %s", |
| name_of_format (converted_format)); |
| } |
| GNUT_set_from_cmdline (&cmdline_options, |
| program_options.options->SPLIT.number, ""); |
| } |
| split_option = GNUT_get_conf (program_options.options->SPLIT.number); |
| |
| memset (&default_expanded_formats, 0, sizeof (STRING_LIST)); |
| format_expanded_formats (&default_expanded_formats, format_specification, |
| &texi2dvi_args, &call_texi2dvi); |
| |
| expanded_formats_option = &cmdline_options.options->EXPANDED_FORMATS; |
| |
| for (i = 0; i < ignored_formats.number; i++) |
| { |
| size_t ignored_fmt_nr |
| = find_string (&default_expanded_formats, ignored_formats.list[i]); |
| if (ignored_fmt_nr) |
| remove_from_strings_list (&default_expanded_formats, ignored_fmt_nr-1); |
| } |
| for (i = 0; i < default_expanded_formats.number; i++) |
| { |
| txi_config_add_to_option_list (expanded_formats_option, |
| default_expanded_formats.list[i], 0); |
| } |
| |
| free_strings_list (&default_expanded_formats); |
| |
| if (call_texi2dvi) |
| { |
| OPTION *outfile_option |
| = GNUT_get_conf (program_options.options->OUTFILE.number); |
| if (outfile_option && outfile_option->o.string && argc - optind > 1) |
| { |
| char *formatted_message; |
| char *encoded_message; |
| |
| xasprintf (&formatted_message, |
| _("%s: when generating %s, only one input FILE may be specified with -o"), |
| program_file, name_of_format (output_format)); |
| encoded_message = GNUT_encode_message (formatted_message); |
| free (formatted_message); |
| fprintf (stderr, "%s\n", encoded_message); |
| free (encoded_message); |
| |
| exit (EXIT_FAILURE); |
| } |
| } |
| else if (Xopt_arg_nr) |
| txi_config_document_warn ("%s", "--Xopt option without printed output"); |
| |
| /* special case, show all the built in HTML CSS rules and exit */ |
| show_builtin_css_rules_option |
| = GNUT_get_conf (program_options.options->SHOW_BUILTIN_CSS_RULES.number); |
| if (show_builtin_css_rules_option |
| && show_builtin_css_rules_option->o.integer > 0) |
| { |
| char *default_css_text; |
| default_css_text = txi_builtin_default_css_text (); |
| printf ("%s", default_css_text); |
| free (default_css_text); |
| exit (EXIT_SUCCESS); |
| } |
| |
| if (format_specification->module) |
| { |
| if (!strcmp (converted_format, "html")) |
| { |
| /* setup of need_latex to be kept in sync with setup of |
| CONVERT_TO_LATEX_IN_MATH in html_initialize_output_state |
| based on HTML_MATH */ |
| int need_latex = 0; |
| OPTION *convert_to_latex_in_math_option |
| = GNUT_get_conf ( |
| program_options.options->CONVERT_TO_LATEX_IN_MATH.number); |
| if (!convert_to_latex_in_math_option |
| || convert_to_latex_in_math_option->o.integer < 0) |
| { |
| OPTION *option_html_math |
| = GNUT_get_conf (program_options.options->HTML_MATH.number); |
| if (option_html_math && option_html_math->o.string) |
| need_latex = 1; |
| } |
| |
| /* to be kept in sync with build_html_perl_info.c |
| html_pass_conversion_initialization */ |
| if (loaded_init_files_nr > 0 || need_latex) |
| external_module = format_specification->module; |
| } |
| else |
| external_module = format_specification->module; |
| |
| if (external_module) |
| { |
| if (!embedded_interpreter) |
| { |
| fprintf (stderr, "ERROR: no interpreter for %s\n", |
| external_module); |
| exit (EXIT_FAILURE); |
| } |
| else if (debug) |
| fprintf (stderr, "ctexi2any: loading module: %s\n", external_module); |
| } |
| } |
| |
| /* corresponds to eval "require $module"; in texi2any.pl */ |
| txi_converter_output_format_setup (converted_format, external_module); |
| |
| /* |
| For now, FORMAT_MENU is the only variable that can be set from converter |
| defaults for the main program structuring and for the parser. |
| */ |
| /* |
| $cmdline_options is passed to have command line settings, here |
| in practice TEXI2HTML set, for conversion to HTML to select |
| possibly different customization variable values. |
| */ |
| format_defaults = txi_converter_format_defaults (converted_format, |
| external_module, |
| &cmdline_options); |
| |
| format_menu_option_nr = program_options.options->FORMAT_MENU.number; |
| |
| /* Converters may set format_defaults to NULL (Text converter) */ |
| if (format_defaults) |
| { |
| if (format_defaults->conf.options->FORMAT_MENU.o.string) |
| conversion_format_menu_default |
| = strdup (format_defaults->conf.options->FORMAT_MENU.o.string); |
| if (conversion_format_menu_default != 0) |
| { |
| /* |
| fprintf (stderr, "FORMAT_MENU %s\n", conversion_format_menu_default); |
| */ |
| GNUT_set_customization_default (format_menu_option_nr, |
| conversion_format_menu_default); |
| } |
| |
| destroy_converter_initialization_info (format_defaults); |
| } |
| |
| /* special case for FORMAT_MENU of delayed setting based in |
| some case on converter */ |
| format_menu_option = GNUT_get_conf (format_menu_option_nr); |
| if (format_menu_option && format_menu_option->o.string |
| && !strcmp (format_menu_option->o.string, |
| "set_format_menu_from_cmdline_header_option")) |
| { |
| if (conversion_format_menu_default |
| && strcmp (conversion_format_menu_default, "nomenu")) |
| { |
| GNUT_set_from_cmdline (&cmdline_options, format_menu_option_nr, |
| conversion_format_menu_default); |
| } |
| else |
| GNUT_set_from_cmdline (&cmdline_options, |
| format_menu_option_nr, "menu"); |
| } |
| |
| free (conversion_format_menu_default); |
| |
| format_menu_option = GNUT_get_conf (format_menu_option_nr); |
| if (!format_menu_option || !format_menu_option->o.string |
| || !strcmp (format_menu_option->o.string, |
| "menu")) |
| do_menu = 1; |
| |
| sort_element_count_option |
| = GNUT_get_conf (program_options.options->SORT_ELEMENT_COUNT.number); |
| |
| initialize_options_list (&parser_options); |
| /* Copy relevant customization variables into the parser options. */ |
| for (i = 0; i < TXI_OPTIONS_NR; i++) |
| { |
| OPTION *parser_option = parser_options.sorted_options[i]; |
| if (parser_option->flags & OF_parser_option) |
| { |
| /* note that INCLUDE_DIRECTORIES is reset before parsing |
| to add prepended directories, current directory and manual |
| directory */ |
| OPTION *option = GNUT_get_conf (parser_option->number); |
| if (option) |
| { |
| options_list_add_option_number (&parser_options, |
| parser_option->number); |
| copy_option (parser_option, option); |
| } |
| } |
| } |
| |
| message_encoding_option |
| = GNUT_get_conf (program_options.options->MESSAGE_ENCODING.number); |
| if (message_encoding_option && message_encoding_option->o.string) |
| set_message_encoding = message_encoding_option->o.string; |
| |
| if (optind < argc) |
| { |
| int j; |
| for (j = optind; j < argc; j++) |
| add_string (argv[j], &input_files); |
| } |
| else if (!isatty (fileno (stdin)) && !call_texi2dvi) |
| { |
| add_string ("-", &input_files); |
| } |
| else |
| { |
| char *formatted_message; |
| char *encoded_message; |
| |
| xasprintf (&formatted_message, _("%s: missing file argument."), |
| program_file); |
| encoded_message = GNUT_encode_message (formatted_message); |
| free (formatted_message); |
| fprintf (stderr, "%s\n", encoded_message); |
| free (encoded_message); |
| |
| xasprintf (&formatted_message, |
| _("Try `%s --help' for more information."), |
| program_file); |
| encoded_message = GNUT_encode_message (formatted_message); |
| free (formatted_message); |
| fprintf (stderr, "%s\n", encoded_message); |
| free (encoded_message); |
| exit (EXIT_FAILURE); |
| } |
| |
| /* NOTE there is an effect only if Perl converter is used */ |
| txi_xs_external_conversion = getenv ("TEXINFO_XS_EXTERNAL_CONVERSION"); |
| if (txi_xs_external_conversion && strlen (txi_xs_external_conversion) |
| && strcmp (txi_xs_external_conversion, "0")) |
| GNUT_set_from_cmdline (&cmdline_options, |
| program_options.options->XS_EXTERNAL_CONVERSION.number, "1"); |
| |
| txi_xs_external_formatting = getenv ("TEXINFO_XS_EXTERNAL_FORMATTING"); |
| if (txi_xs_external_formatting && strlen (txi_xs_external_formatting) |
| && strcmp (txi_xs_external_formatting, "0")) |
| GNUT_set_from_cmdline (&cmdline_options, |
| program_options.options->XS_EXTERNAL_FORMATTING.number, "1"); |
| |
| initialize_options_list (&convert_options); |
| |
| memset (&opened_files, 0, sizeof (STRING_LIST)); |
| memset (&prepended_include_directories, 0, sizeof (STRING_LIST)); |
| converter_init_info = new_converter_initialization_info (); |
| |
| for (i = 0; i < input_files.number; i++) |
| { |
| DOCUMENT *document; |
| CONVERTER *converter; |
| char *result; |
| char *input_file_name_and_directory[2]; |
| char *input_file_name; |
| char *input_directory; |
| char *canon_input_dir = 0; |
| OPTION *trace_includes_option; |
| OPTION *macro_expand_option; |
| OPTION *dump_texi_option; |
| OPTION *converter_include_dirs_option; |
| OPTION *converter_texinfo_language_directories_option; |
| OPTION *dump_tree_option; |
| OPTION *input_file_name_encoding_option; |
| OPTION *doc_encoding_for_input_file_name_option; |
| OPTION *locale_encoding_option; |
| OPTION *dump_structure_option; |
| STRING_LIST *cmdline_include_dirs |
| = cmdline_options.options->INCLUDE_DIRECTORIES.o.strlist; |
| STRING_LIST *parser_include_dirs |
| = parser_options.options->INCLUDE_DIRECTORIES.o.strlist; |
| STRING_LIST *converter_include_dirs; |
| STRING_LIST *converter_texinfo_language_config_dirs; |
| char *input_file_path = 0; |
| char *locale_encoding = 0; |
| char *input_name_encoding_val = 0; |
| size_t file_path_len; |
| size_t j; |
| OPTIONS_LIST *file_cmdline_options; |
| |
| input_file_arg = input_files.list[i]; |
| |
| file_path_len = strlen (input_file_arg); |
| if (file_path_len > strlen (".info") |
| && !memcmp (input_file_arg + file_path_len -strlen (".info"), |
| ".info", strlen (".info"))) |
| { |
| char *corrected; |
| char *arg_basename; |
| char *decoded_corrected; |
| char *decoded_arg_basename; |
| |
| parse_file_path (input_file_arg, input_file_name_and_directory); |
| arg_basename = input_file_name_and_directory[0]; |
| free (input_file_name_and_directory[1]); |
| corrected = strdup (arg_basename); |
| memcpy (corrected + strlen (corrected) -strlen (".info"), ".texi", |
| strlen (".texi")); |
| |
| decoded_corrected = GNUT_decode_input (corrected); |
| decoded_arg_basename = GNUT_decode_input (arg_basename); |
| |
| txi_config_document_warn ("input file %s; did you mean %s?", |
| decoded_arg_basename, |
| decoded_corrected); |
| free (corrected); |
| free (arg_basename); |
| free (decoded_arg_basename); |
| free (decoded_corrected); |
| } |
| |
| /* try to concatenate with different suffixes. The last suffix is '' |
| such that the plain file name is checked. */ |
| for (j = 0; input_file_suffixes[j]; j++) |
| { |
| struct stat finfo; |
| char *path_name; |
| xasprintf (&path_name, "%s%s", input_file_arg, |
| input_file_suffixes[j]); |
| if (stat (path_name, &finfo) == 0) |
| { |
| input_file_path = path_name; |
| break; |
| } |
| else |
| free (path_name); |
| } |
| |
| /* in case no file was found, still set the file name */ |
| if (!input_file_path) |
| input_file_path = strdup (input_file_arg); |
| |
| parse_file_path (input_file_path, input_file_name_and_directory); |
| input_file_name = input_file_name_and_directory[0]; |
| input_directory = input_file_name_and_directory[1]; |
| |
| if (prepend_dirs.number > 0) |
| copy_strings (&prepended_include_directories, &prepend_dirs); |
| |
| add_string (curdir, &prepended_include_directories); |
| |
| if (input_directory) |
| canon_input_dir = canonpath (input_directory); |
| |
| if (canon_input_dir && strcmp (curdir, canon_input_dir)) |
| add_string (input_directory, &prepended_include_directories); |
| |
| /* tune for the input file include directory and prepend to |
| INCLUDE_DIRECTORIES by merging prepended directories and command |
| line include directories */ |
| clear_strings_list (parser_include_dirs); |
| copy_strings (parser_include_dirs, &prepended_include_directories); |
| copy_strings (parser_include_dirs, cmdline_include_dirs); |
| |
| /* Texinfo file parsing */ |
| /* initialize parser */ |
| txi_parser (input_file_path, &values, &parser_options); |
| |
| /* Texinfo document tree parsing */ |
| document = txi_parse_texi_file (input_file_path, &status); |
| |
| set_document_options (document, &program_options, &cmdline_options, |
| init_files_options); |
| |
| dump_tree_option |
| = GNUT_get_conf (program_options.options->DUMP_TREE.number); |
| input_file_name_encoding_option |
| = GNUT_get_conf ( |
| program_options.options->INPUT_FILE_NAME_ENCODING.number); |
| doc_encoding_for_input_file_name_option |
| = GNUT_get_conf ( |
| program_options.options->DOC_ENCODING_FOR_INPUT_FILE_NAME.number); |
| locale_encoding_option |
| = GNUT_get_conf (program_options.options->LOCALE_ENCODING.number); |
| |
| if (locale_encoding_option) |
| locale_encoding = locale_encoding_option->o.string; |
| |
| if (input_file_name_encoding_option) |
| input_name_encoding_val = input_file_name_encoding_option->o.string; |
| |
| if (!status && ((dump_tree_option && dump_tree_option->o.string) |
| || debug >= 10)) |
| { |
| const char *input_file_names_encoding |
| = input_file_name_encoding (input_name_encoding_val, |
| (!(doc_encoding_for_input_file_name_option |
| && doc_encoding_for_input_file_name_option->o.integer == 0)), |
| locale_encoding, &document->global_info, 0); |
| char *debug_tree = print_tree_details (document->tree, |
| input_file_names_encoding, test_mode_set); |
| const char *output_encoding = 0; |
| OPTION *out_encoding_option |
| = GNUT_get_conf ( |
| program_options.options->OUTPUT_ENCODING_NAME.number); |
| |
| if (out_encoding_option && out_encoding_option->o.string |
| && strcmp (out_encoding_option->o.string, "utf-8")) |
| output_encoding = out_encoding_option->o.string; |
| |
| if (dump_tree_option && dump_tree_option->o.string |
| && strcmp (dump_tree_option->o.string, "-") |
| && strcmp (dump_tree_option->o.string, "1")) |
| { |
| const char *dump_tree = dump_tree_option->o.string; |
| char *dump_tree_name |
| = GNUT_decode_input ((char *) dump_tree); |
| |
| FILE *file_fh = fopen (dump_tree, "w"); |
| if (file_fh) |
| { |
| if (output_encoding) |
| { |
| char *encoding_line; |
| xasprintf (&encoding_line, "OUTPUT_ENCODING: %s\n", |
| output_encoding); |
| write_to_file (encoding_line, file_fh, dump_tree_name); |
| free (encoding_line); |
| } |
| write_to_file (debug_tree, file_fh, dump_tree_name); |
| |
| if (fclose (file_fh)) |
| { |
| txi_config_document_warn ( |
| "error on closing tree dump file %s: %s", |
| dump_tree_name, strerror (errno)); |
| } |
| } |
| else |
| txi_config_document_warn ("could not open %s for writing: %s", |
| dump_tree_name, strerror (errno)); |
| |
| free (dump_tree_name); |
| } |
| else |
| { |
| if (output_encoding) |
| fprintf (stderr, "OUTPUT_ENCODING: %s\n", output_encoding); |
| fprintf (stderr, "%s", debug_tree); |
| } |
| free (debug_tree); |
| } |
| |
| if (status) |
| { |
| errors_count = handle_parser_errors (document, no_warn, test_mode_set, |
| set_message_encoding, |
| errors_count, &opened_files); |
| goto next_input_file; |
| } |
| |
| if (!strcmp (output_format, "parse")) |
| { |
| errors_count = handle_parser_errors (document, no_warn, test_mode_set, |
| set_message_encoding, |
| errors_count, &opened_files); |
| goto next_input_file; |
| } |
| |
| trace_includes_option |
| = GNUT_get_conf (program_options.options->TRACE_INCLUDES.number); |
| if (trace_includes_option && trace_includes_option->o.integer > 0) |
| { |
| errors_count = handle_parser_errors (document, no_warn, test_mode_set, |
| set_message_encoding, |
| errors_count, &opened_files); |
| if (document->global_info.included_files.number) |
| { |
| for (i = 0; i < document->global_info.included_files.number; |
| i++) |
| { |
| printf ("%s\n", |
| document->global_info.included_files.list[i]); |
| } |
| } |
| goto next_input_file; |
| } |
| |
| macro_expand_option |
| = GNUT_get_conf (program_options.options->MACRO_EXPAND.number); |
| if (macro_expand_option && macro_expand_option->o.string && i == 0) |
| { |
| const char *encoded_macro_expand_file_name |
| = macro_expand_option->o.string; |
| char *macro_expand_file_name |
| = GNUT_decode_input ((char *) encoded_macro_expand_file_name); |
| FILE *file_fh; |
| OUTPUT_FILES_INFORMATION output_files_information; |
| char *open_error_message; |
| int overwritten_file; |
| size_t error_macro_expand_file = 0; |
| |
| char *texinfo_text = convert_to_texinfo (document->tree); |
| |
| /* fprintf (stderr, "%s", texinfo_text); */ |
| |
| memset (&output_files_information, 0, |
| sizeof (OUTPUT_FILES_INFORMATION)); |
| |
| file_fh = output_files_open_out (&output_files_information, |
| encoded_macro_expand_file_name, |
| &open_error_message, |
| &overwritten_file, 0); |
| /* overwritten_file, set if the file has already been used |
| in this files_information is not checked as this cannot happen. |
| */ |
| |
| if (file_fh) |
| { |
| write_to_file (texinfo_text, file_fh, |
| encoded_macro_expand_file_name); |
| |
| if (!strcmp (macro_expand_file_name, "-")) |
| { |
| main_program_unclosed_stdout.stream = file_fh; |
| main_program_unclosed_stdout.file_path = "-"; |
| } |
| else |
| { |
| output_files_register_closed (&output_files_information, |
| encoded_macro_expand_file_name); |
| if (fclose (file_fh)) |
| { |
| txi_config_document_warn ( |
| "error on closing macro expand file %s: %s", |
| macro_expand_file_name, strerror (errno)); |
| error_macro_expand_file = 1; |
| } |
| } |
| } |
| else |
| { |
| txi_config_document_warn ("could not open %s for writing: %s", |
| macro_expand_file_name, open_error_message); |
| error_macro_expand_file = 1; |
| } |
| |
| error_macro_expand_file |
| = merge_opened_files (&opened_files, |
| &output_files_information.opened_files, |
| error_macro_expand_file); |
| |
| if (error_macro_expand_file) |
| { |
| errors_count = handle_errors (error_macro_expand_file, |
| errors_count, &opened_files); |
| } |
| free_output_files_information (&output_files_information); |
| free (macro_expand_file_name); |
| free (texinfo_text); |
| } |
| |
| dump_texi_option |
| = GNUT_get_conf (program_options.options->DUMP_TEXI.number); |
| |
| if ((dump_texi_option && dump_texi_option->o.integer > 0) |
| || format_specification->flags & STTF_texi2dvi_format) |
| { |
| errors_count = handle_parser_errors (document, no_warn, test_mode_set, |
| set_message_encoding, |
| errors_count, &opened_files); |
| goto next_input_file; |
| } |
| |
| /* structure and transformations */ |
| /* do_menu corresponds to FORMAT_MENU undef or set to menu */ |
| txi_complete_document (document, format_specification->flags |
| | transformation_flags, do_menu); |
| |
| merge_error_messages_lists (&document->parser_error_messages, |
| &document->error_messages); |
| |
| errors_nr |
| = txi_handle_parser_error_messages (document, no_warn, |
| test_mode_set, |
| set_message_encoding); |
| |
| errors_count = handle_errors (errors_nr, errors_count, &opened_files); |
| |
| dump_structure_option |
| = GNUT_get_conf (program_options.options->DUMP_STRUCTURE.number); |
| |
| if ((dump_structure_option && dump_structure_option->o.integer > 0) |
| || debug >= 20) |
| { |
| const char *input_file_names_encoding |
| = input_file_name_encoding (input_name_encoding_val, |
| (!(doc_encoding_for_input_file_name_option |
| && doc_encoding_for_input_file_name_option->o.integer == 0)), |
| locale_encoding, &document->global_info, 0); |
| char *debug_tree = print_tree_details (document->tree, |
| input_file_names_encoding, test_mode_set); |
| const char *output_encoding = 0; |
| OPTION *out_encoding_option |
| = GNUT_get_conf ( |
| program_options.options->OUTPUT_ENCODING_NAME.number); |
| |
| if (out_encoding_option && out_encoding_option->o.string |
| && strcmp (out_encoding_option->o.string, "utf-8")) |
| output_encoding = out_encoding_option->o.string; |
| |
| if (dump_structure_option && dump_structure_option->o.string |
| && strcmp (dump_structure_option->o.string, "-")) |
| { |
| const char *dump_structure = dump_structure_option->o.string; |
| char *dump_structure_name |
| = GNUT_decode_input ((char *) dump_structure); |
| |
| FILE *file_fh = fopen (dump_structure, "w"); |
| if (file_fh) |
| { |
| if (output_encoding) |
| { |
| char *encoding_line; |
| xasprintf (&encoding_line, "OUTPUT_ENCODING: %s\n", |
| output_encoding); |
| write_to_file (encoding_line, file_fh, |
| dump_structure_name); |
| free (encoding_line); |
| } |
| write_to_file (debug_tree, file_fh, dump_structure_name); |
| |
| if (fclose (file_fh)) |
| { |
| txi_config_document_warn ( |
| "error on closing structure dump file %s: %s", |
| dump_structure_name, strerror (errno)); |
| } |
| } |
| else |
| txi_config_document_warn ("could not open %s for writing: %s", |
| dump_structure_name, strerror (errno)); |
| |
| free (dump_structure_name); |
| } |
| else |
| { |
| if (output_encoding) |
| fprintf (stderr, "OUTPUT_ENCODING: %s\n", output_encoding); |
| fprintf (stderr, "%s", debug_tree); |
| } |
| free (debug_tree); |
| } |
| |
| if (!strcmp (output_format, "structure")) |
| goto next_input_file; |
| |
| if (i != 0) |
| { |
| if (!non_first_file_cmdline_initialized) |
| { |
| initialize_options_list (&non_first_file_cmdline_options); |
| non_first_file_cmdline_initialized = 1; |
| } |
| copy_options_list (&non_first_file_cmdline_options, |
| &cmdline_options); |
| options_list_remove_option_number (&non_first_file_cmdline_options, |
| program_options.options->OUTFILE.number); |
| options_list_remove_option_number (&non_first_file_cmdline_options, |
| program_options.options->PREFIX.number); |
| if (split_option && split_option->o.string |
| && strlen (split_option->o.string)) |
| options_list_remove_option_number ( |
| &non_first_file_cmdline_options, |
| program_options.options->SUBDIR.number); |
| |
| file_cmdline_options = &non_first_file_cmdline_options; |
| } |
| else |
| file_cmdline_options = &cmdline_options; |
| |
| /* conversion initialization */ |
| copy_options_list (&convert_options, &program_options); |
| copy_options_list (&convert_options, init_files_options); |
| copy_options_list (&convert_options, file_cmdline_options); |
| |
| if (i != 0) |
| clear_options_list (&non_first_file_cmdline_options); |
| |
| /* prepend to INCLUDE_DIRECTORIES by resetting include directories to |
| merged prepended directories and command line include directories */ |
| converter_include_dirs_option |
| = &convert_options.options->INCLUDE_DIRECTORIES; |
| converter_include_dirs = converter_include_dirs_option->o.strlist; |
| clear_strings_list (converter_include_dirs); |
| copy_strings (converter_include_dirs, &prepended_include_directories); |
| copy_strings (converter_include_dirs, cmdline_include_dirs); |
| |
| /* set TEXINFO_LANGUAGE_DIRECTORIES by prepending current directory |
| and input directory to texinfo_language_config_dirs */ |
| converter_texinfo_language_directories_option |
| = &convert_options.options->TEXINFO_LANGUAGE_DIRECTORIES; |
| converter_texinfo_language_config_dirs |
| = converter_texinfo_language_directories_option->o.strlist; |
| clear_strings_list (converter_texinfo_language_config_dirs); |
| |
| add_string (curdir, converter_texinfo_language_config_dirs); |
| if (canon_input_dir && strcmp (curdir, canon_input_dir)) |
| { |
| add_string (input_directory, |
| converter_texinfo_language_config_dirs); |
| } |
| |
| copy_strings (converter_texinfo_language_config_dirs, |
| texinfo_language_config_dirs); |
| |
| txi_converter_initialization_setup (converter_init_info, |
| &deprecated_directories, |
| &convert_options); |
| |
| converter = txi_converter_setup (external_module, |
| converted_format, |
| converter_init_info); |
| |
| /* conversion */ |
| /* return value can be NULL in case of errors or an empty string, but |
| not anything else as parse_file is used with a file */ |
| result = txi_converter_output (external_module, converter, document); |
| |
| free (result); |
| clear_converter_initialization_info (converter_init_info); |
| |
| errors_count |
| = merge_opened_files (&opened_files, |
| &converter->output_files_information.opened_files, |
| errors_count); |
| |
| errors_nr |
| = txi_handle_converter_error_messages (converter, no_warn, |
| test_mode_set, set_message_encoding); |
| |
| errors_count = handle_errors (errors_nr, errors_count, &opened_files); |
| |
| if (converter->output_files_information.unclosed_files.number > 0) |
| { |
| FILE_STREAM_LIST *unclosed_files |
| = &converter->output_files_information.unclosed_files; |
| |
| for (j = 0; j < unclosed_files->number; j++) |
| { |
| FILE_STREAM *file_stream = &unclosed_files->list[j]; |
| /* |
| fprintf (stderr, "%zu: Unclosed file %p %p '%s' %p %p\n", j, |
| unclosed_files, file_stream, |
| file_stream->file_path, file_stream->stream, file_stream->io); |
| */ |
| if (!strcmp (file_stream->file_path, "-")) |
| /* we may be overwriting information on C file stream |
| but it is not an issue, as it is probably more |
| important to close the PerlIO, and it is not clear if it |
| is possible to close both. Also using stdout for more than |
| one type of output should be considered as an error, |
| so it is not a big deal if there are no error messages |
| if stdout cannot be closed in that case. |
| */ |
| { |
| main_program_unclosed_stdout = *file_stream; |
| /* do not keep the original file path, as it is held by |
| the converter which is bound to be destroyed, |
| while main_program_unclosed_stdout data must survive |
| until the end of the program. |
| */ |
| main_program_unclosed_stdout.file_path = "-"; |
| } |
| else |
| { |
| int close_error = txi_close_file_stream (program_file, |
| file_stream); |
| |
| if (close_error) |
| errors_count = handle_errors (close_error, |
| errors_count, &opened_files); |
| } |
| } |
| } |
| |
| if (format_specification->flags & STTF_internal_links && i == 0) |
| { |
| OPTION *internal_links_option |
| = GNUT_get_conf (program_options.options->INTERNAL_LINKS.number); |
| if (internal_links_option && internal_links_option->o.string) |
| { |
| char *internal_links_file_name; |
| char *internal_links_text |
| = html_output_internal_links (converter); |
| FILE *file_fh; |
| OUTPUT_FILES_INFORMATION output_files_information; |
| char *open_error_message; |
| int overwritten_file; |
| char *encoded_internal_links_file_name |
| = internal_links_option->o.string; |
| int error_internal_links_file = 0; |
| |
| if (!internal_links_text) |
| internal_links_text = strdup (""); |
| |
| internal_links_file_name |
| = GNUT_decode_input (encoded_internal_links_file_name); |
| |
| memset (&output_files_information, 0, |
| sizeof (OUTPUT_FILES_INFORMATION)); |
| |
| file_fh = output_files_open_out (&output_files_information, |
| encoded_internal_links_file_name, |
| &open_error_message, |
| &overwritten_file, 0); |
| |
| /* overwritten_file, set if the file has already been used |
| in this files_information is not checked as this cannot happen. |
| */ |
| |
| if (file_fh) |
| { |
| write_to_file (internal_links_text, file_fh, |
| encoded_internal_links_file_name); |
| |
| if (!strcmp (internal_links_file_name, "-")) |
| { |
| main_program_unclosed_stdout.stream = file_fh; |
| main_program_unclosed_stdout.file_path = "-"; |
| } |
| else |
| { |
| output_files_register_closed (&output_files_information, |
| encoded_internal_links_file_name); |
| if (fclose (file_fh)) |
| { |
| txi_config_document_warn ( |
| "error on closing internal links file %s: %s", |
| internal_links_file_name, strerror (errno)); |
| error_internal_links_file = 1; |
| } |
| } |
| } |
| else |
| { |
| txi_config_document_warn ("could not open %s for writing: %s", |
| internal_links_file_name, open_error_message); |
| error_internal_links_file = 1; |
| } |
| |
| error_internal_links_file |
| = merge_opened_files (&opened_files, |
| &output_files_information.opened_files, |
| error_internal_links_file); |
| |
| if (error_internal_links_file) |
| { |
| errors_count = handle_errors (error_internal_links_file, |
| errors_count, &opened_files); |
| } |
| |
| free_output_files_information (&output_files_information); |
| free (internal_links_file_name); |
| free (internal_links_text); |
| } |
| } |
| |
| /* free after output */ |
| txi_converter_reset (converter); |
| |
| /* destroy converter */ |
| txi_converter_destroy (converter); |
| |
| if (i == 0) |
| { |
| const char *sort_element_count_file_name = 0; |
| if (sort_element_count_option && sort_element_count_option->o.string) |
| { |
| sort_element_count_file_name |
| = sort_element_count_option->o.string; |
| } |
| |
| if (sort_element_count_file_name && !embedded_interpreter) |
| { |
| fprintf (stderr, |
| "ERROR: no interpreter for SORT_ELEMENT_COUNT\n"); |
| exit (EXIT_FAILURE); |
| } |
| |
| if (sort_element_count_file_name) |
| { |
| char *sort_element_count_text; |
| CONVERTER_TEXT_INFO *sort_element_count_info; |
| OPTION *use_nodes_option |
| = GNUT_get_conf (program_options.options->USE_NODES.number); |
| int no_use_nodes = (use_nodes_option |
| && use_nodes_option->o.integer == 0); |
| int use_sections |
| = (!(format_specification->flags & STTF_nodes_tree) |
| || no_use_nodes); |
| |
| OPTION *sort_element_count_words_option |
| = GNUT_get_conf ( |
| program_options.options->SORT_ELEMENT_COUNT_WORDS.number); |
| OPTION *output_file_name_encoding_option |
| = GNUT_get_conf ( |
| program_options.options->OUTPUT_FILE_NAME_ENCODING.number); |
| OPTION *doc_encoding_for_output_file_name_option |
| = GNUT_get_conf ( |
| program_options.options->DOC_ENCODING_FOR_OUTPUT_FILE_NAME.number); |
| |
| FILE *file_fh; |
| OUTPUT_FILES_INFORMATION output_files_information; |
| char *open_error_message; |
| int overwritten_file; |
| char *path_encoding; |
| char *encoded_sort_element_count_file_name; |
| int error_element_count_file = 0; |
| char *output_file_name_encoding = 0; |
| |
| /* reuse converter options list memory */ |
| clear_options_list (&convert_options); |
| |
| copy_options_list (&convert_options, &program_options); |
| copy_options_list (&convert_options, init_files_options); |
| copy_options_list (&convert_options, &cmdline_options); |
| |
| /* prepend to INCLUDE_DIRECTORIES by resetting include directories to |
| merged prepended directories and command line include directories */ |
| converter_include_dirs_option |
| = &convert_options.options->INCLUDE_DIRECTORIES; |
| converter_include_dirs = converter_include_dirs_option->o.strlist; |
| clear_strings_list (converter_include_dirs); |
| copy_strings (converter_include_dirs, &prepended_include_directories); |
| copy_strings (converter_include_dirs, cmdline_include_dirs); |
| |
| sort_element_count_info |
| = txi_sort_element_counts ("Texinfo::Convert::TextContent", |
| &convert_options, document, |
| use_sections, (sort_element_count_words_option |
| && sort_element_count_words_option->o.integer > 0)); |
| |
| sort_element_count_text = sort_element_count_info->text; |
| |
| if (!sort_element_count_text) |
| sort_element_count_text = strdup (""); |
| |
| if (output_file_name_encoding_option) |
| output_file_name_encoding |
| = output_file_name_encoding_option->o.string; |
| encoded_sort_element_count_file_name |
| = encoded_output_file_name (output_file_name_encoding, |
| (!(doc_encoding_for_output_file_name_option |
| && doc_encoding_for_output_file_name_option->o.integer == 0)), |
| locale_encoding, &document->global_info, |
| (char *)sort_element_count_file_name, &path_encoding, 0); |
| free (path_encoding); |
| |
| memset (&output_files_information, 0, |
| sizeof (OUTPUT_FILES_INFORMATION)); |
| |
| file_fh = output_files_open_out (&output_files_information, |
| encoded_sort_element_count_file_name, |
| &open_error_message, |
| &overwritten_file, 0); |
| |
| /* overwritten_file, set if the file has already been used |
| in this files_information is not checked as this cannot happen. |
| */ |
| |
| if (file_fh) |
| { |
| write_to_file (sort_element_count_text, file_fh, |
| encoded_sort_element_count_file_name); |
| |
| if (!strcmp (sort_element_count_file_name, "-")) |
| { |
| output_files_register_closed (&output_files_information, |
| encoded_sort_element_count_file_name); |
| if (fclose (file_fh)) |
| { |
| txi_config_document_warn ( |
| "error on closing internal links file %s: %s", |
| sort_element_count_file_name, strerror (errno)); |
| error_element_count_file = 1; |
| } |
| } |
| else |
| { |
| main_program_unclosed_stdout.stream = file_fh; |
| main_program_unclosed_stdout.file_path = "-"; |
| } |
| } |
| else |
| { |
| txi_config_document_warn ("could not open %s for writing: %s", |
| sort_element_count_file_name, open_error_message); |
| error_element_count_file = 1; |
| } |
| free (encoded_sort_element_count_file_name); |
| free (sort_element_count_text); |
| |
| /* destroy converter and sort_element_count_info */ |
| txi_converter_reset (sort_element_count_info->converter); |
| txi_converter_destroy (sort_element_count_info->converter); |
| free (sort_element_count_info); |
| |
| error_element_count_file |
| = merge_opened_files (&opened_files, |
| &output_files_information.opened_files, |
| error_element_count_file); |
| |
| if (error_element_count_file) |
| { |
| errors_count = handle_errors (error_element_count_file, |
| errors_count, &opened_files); |
| } |
| |
| free_output_files_information (&output_files_information); |
| } |
| } |
| |
| next_input_file: |
| /* destroy document */ |
| txi_document_remove (document); |
| |
| free (input_directory); |
| free (canon_input_dir); |
| free (input_file_name); |
| free (input_file_path); |
| |
| clear_strings_list (&prepended_include_directories); |
| clear_options_list (&convert_options); |
| } |
| |
| if (main_program_unclosed_stdout.file_path) |
| { |
| int close_error = txi_close_file_stream (program_file, |
| &main_program_unclosed_stdout); |
| if (close_error) |
| errors_count = handle_errors (close_error, errors_count, &opened_files); |
| } |
| |
| destroy_converter_initialization_info (converter_init_info); |
| |
| if (non_first_file_cmdline_initialized) |
| free_options_list (&non_first_file_cmdline_options); |
| |
| free_strings_list (&prepended_include_directories); |
| free_options_list (&convert_options); |
| |
| if (call_texi2dvi) |
| { |
| OPTION *texi2dvi_option |
| = GNUT_get_conf (program_options.options->TEXI2DVI.number); |
| |
| /* For efficiency, reuse debug variable value for verbose too */ |
| OPTION *verbose_option |
| = GNUT_get_conf (program_options.options->VERBOSE.number); |
| if (verbose_option && verbose_option->o.integer > 0) |
| debug = 1; |
| |
| if (!texi2dvi_option || !texi2dvi_option->o.string |
| || !strlen (texi2dvi_option->o.string)) |
| { |
| errors_count = handle_errors (1, errors_count, &opened_files); |
| } |
| else |
| { |
| STRING_LIST tmp_strings; |
| |
| memset (&tmp_strings, 0, sizeof (STRING_LIST)); |
| |
| texi2dvi = strdup (texi2dvi_option->o.string); |
| |
| /* prepend texi2dvi to texi2dvi_args */ |
| copy_strings (&tmp_strings, &texi2dvi_args); |
| clear_strings_list (&texi2dvi_args); |
| add_string (texi2dvi, &texi2dvi_args); |
| merge_strings (&texi2dvi_args, &tmp_strings); |
| tmp_strings.number = 0; |
| free_strings_list (&tmp_strings); |
| |
| merge_strings (&texi2dvi_args, &input_files); |
| input_files.number = 0; |
| } |
| } |
| |
| free_strings_list (&input_files); |
| |
| free_options_list (&parser_options); |
| |
| free (program_basename); |
| free (program_file); |
| |
| free_options_list (&cmdline_options); |
| free_options_list (init_files_options); |
| free_options_list (&program_options); |
| |
| free_strings_list (&conf_dirs); |
| free_strings_list (&prepend_dirs); |
| |
| free_strings_list (&converter_init_dirs); |
| free_strings_list (&converter_config_dirs); |
| |
| free_deprecated_dirs_list (&deprecated_dirs_used); |
| free_deprecated_dirs_list (&deprecated_directories); |
| |
| destroy_strings_list (texinfo_language_config_dirs); |
| wipe_values (&values); |
| |
| free_strings_list (&internal_extension_dirs); |
| free (extensions_dir); |
| |
| txi_stop_interpreter (embedded_interpreter); |
| |
| free_strings_list (&opened_files); |
| |
| if (call_texi2dvi && texi2dvi) |
| { |
| char **argv; |
| size_t i; |
| |
| if (debug) |
| { |
| char *texi2dvi_call = join_strings_list (&texi2dvi_args); |
| fprintf (stderr, "EXEC %s\n", texi2dvi_call); |
| free (texi2dvi_call); |
| } |
| argv = (char **) malloc ((texi2dvi_args.number +1) * sizeof (char *)); |
| for (i = 0; i < texi2dvi_args.number; i++) |
| argv[i] = strdup (texi2dvi_args.list[i]); |
| argv[texi2dvi_args.number] = NULL; |
| |
| free_strings_list (&texi2dvi_args); |
| |
| execvp (texi2dvi, argv); |
| } |
| |
| free_strings_list (&texi2dvi_args); |
| } |