# -*-perl-*- #+############################################################################## # # chm.pm: convert to chm intermediate formats hhp, hhc, hhk and html files # # Copyright 2004, 2006, 2009, 2011-2023 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 . # # Originally written by Patrice Dumas. # #-############################################################################## # loading with -d:TraceUse leads to an error like # texi2any: warning: error loading ../init/chm.pm: Undefined subroutine &Devel::TraceUse::texinfo_set_format_from_init_file called at ../init/chm.pm line 43. # defining the package here avoids this error. package Texinfo::Config; use strict; # To check if there is no erroneous autovivification #no autovivification qw(fetch delete exists store strict); use File::Spec; # Also for __( use Texinfo::Common; # load modules to make sure that they are loaded before use use Texinfo::Convert::Unicode; use Texinfo::Convert::Utils; use Texinfo::Convert::Text; use Texinfo::Structuring; texinfo_set_format_from_init_file('html'); texinfo_set_from_init_file('TOP_FILE', undef); texinfo_set_from_init_file('contents', 1); # remove navigation information, it is done by the viewer, and remove # anything that gets in the way of the navigation. texinfo_set_from_init_file('FORMAT_MENU', 'nomenu'); texinfo_set_from_init_file('SPLIT', 'node'); texinfo_set_from_init_file('DEFAULT_RULE', ''); texinfo_set_from_init_file('BIG_RULE', ''); texinfo_set_from_init_file('HEADERS', 0); texinfo_set_from_init_file('footnotestyle', 'end'); texinfo_set_from_init_file('PROGRAM_NAME_IN_FOOTER', 0); texinfo_register_formatting_function('format_navigation_header', \&chm_noop); texinfo_register_formatting_function('format_navigation_panel', \&chm_noop); my %chm_languages = ( 'en' => '0x409 English (United States)', 'sq' => '0x041c Albanian', # 'ar' => '0x1401 Arabic (ALGERIA)', # 'es' => '0x2c0a Spanish (ARGENTINA)', # 'en' => '0x0c09 English (AUSTRALIA)', # 'de' => '0x0c07 German (AUSTRIA)', # 'ar' => '0x3c01 Arabic (BAHRAIN)', 'be' => '0x0423 Byelorussian', # 'fr' => '0x080c French (BELGIUM)', # 'en' => '0x2809 English (BELIZE)', # 'es' => '0x400a Spanish (BOLIVIA)', # 'pt' => '0x0416 Portuguese (BRAZIL)', # 'ms' => '0x083e Malay (BRUNEI DARUSSALAM)', 'bg' => '0x0402 Bulgarian', # 'fr' => '0x0c0c French (CANADA)', # 'es' => '0x340a Spanish (CHILE)', 'zh' => '0x0804 Chinese (CHINA)', # 'es' => '0x240a Spanish (COLOMBIA)', # 'es' => '0x140a Spanish (COSTA RICA)', 'hr' => '0x041a Croatian', 'cs' => '0x0405 Czech', 'da' => '0x0406 Danish', # 'es' => '0x1c0a Spanish (DOMINICAN REPUBLIC)', # 'es' => '0x300a Spanish (ECUADOR)', # 'ar' => '0x0c01 Arabic (EGYPT)', # 'es' => '0x440a Spanish (EL SALVADOR)', 'et' => '0x0425 Estonian', 'fo' => '0x0438 Faeroese', 'fi' => '0x040b Finnish', 'fr' => '0x040c French (FRANCE)', 'de' => '0x0407 German (GERMANY)', 'el' => '0x0408 Greek', # 'es' => '0x100a Spanish (GUATEMALA)', # 'es' => '0x480a Spanish (HONDURAS)', # 'zh' => '0x0c04 Chinese (HONG KONG)', 'hu' => '0x040e Hungarian', 'is' => '0x040f Icelandic', 'hi' => '0x0439 Hindi', 'in' => '0x04', 'fa' => '0x0429 Farsi', # 'ar' => '0x0801 Arabic (IRAQ)', # 'en' => '0x1809 English (IRELAND)', 'iw' => '0x04', 'it' => '0x0410 Italian', # 'en' => '0x2009 English (JAMAICA)', 'ja' => '0x0411 Japanese', # 'ar' => '0x2c01 Arabic (JORDAN)', 'sw' => '0x0441 Swahili', 'ko' => '0x0412 Korean', # 'ar' => '0x3401 Arabic (KUWAIT)', 'al' => '0x0426 Latvian (Lettish)', # 'ar' => '0x3001 Arabic (LEBANON)', # 'ar' => '0x1001 Arabic (LIBYAN ARAB JAMAHIRIYA)', # 'de' => '0x1407 German (LIECHTENSTEIN)', 'lt' => '0x0427 Lithuanian', # 'de' => '0x1007 German (LUXEMBOURG)', # 'zh' => '0x1404 Chinese (MACAU)', 'mk' => '0x042f Macedonian', # 'ms' => '0x043e Malay (MALAYSIA)', # 'es' => '0x080a Spanish (MEXICO)', # 'fr' => '0x180c French (MONACO)', # 'ar' => '0x1801 Arabic (MOROCCO)', 'nl' => '0x0413 Dutch', # 'en' => '0x1409 English (NEW ZEALAND)', # 'es' => '0x4c0a Spanish (NICARAGUA)', 'no' => '0x0414 Norwegian', # 'ar' => '0x2001 Arabic (OMAN)', 'ur' => '0x0420 Urdu', # 'es' => '0x180a Spanish (PANAMA)', # 'es' => '0x3c0a Spanish (PARAGUAY)', # 'es' => '0x280a Spanish (PERU)', # 'en' => '0x3409 English (PHILIPPINES)', 'pl' => '0x0415 Polish', 'pt' => '0x0816 Portuguese (PORTUGAL)', # 'es' => '0x500a Spanish (PUERTO RICO)', # 'ar' => '0x4001 Arabic (QATAR)', 'ro' => '0x0418 Romanian', 'ru' => '0x0419 Russian', 'ar' => '0x0401 Arabic (SAUDI ARABIA)', # 'zh' => '0x1004 Chinese (SINGAPORE)', 'sk' => '0x041b Slovak', 'sl' => '0x0424 Slovenian', 'af' => '0x0436 Afrikaans', 'ca' => '0x0403 Catalan', 'sv' => '0x041d Swedish', # 'de' => '0x0807 German (SWITZERLAND)', # 'ar' => '0x2801 Arabic (SYRIAN ARAB REPUBLIC)', # 'zh' => '0x0404 Chinese (TAIWAN, PROVINCE OF CHINA)', 'th' => '0x041e Thai', # 'en' => '0x2c09 English (TRINIDAD AND TOBAGO)', # 'ar' => '0x1c01 Arabic (TUNISIA)', 'tr' => '0x041f Turkish', 'uk' => '0x0422 Ukrainian', # 'ar' => '0x3801 Arabic (UNITED ARAB EMIRATES)', # 'en' => '0x0809 English (UNITED KINGDOM)', # 'en' => '0x0409 English (UNITED STATES)', # 'es' => '0x380a Spanish (URUGUAY)', # 'es' => '0x200a Spanish (VENEZUELA)', 'vi' => '0x242a Vietnamese', # 'ar' => '0x2401 Arabic (YEMEN)', # 'en' => '0x3009 English (ZIMBABWE)', #'' => '', ); my %hhk_global_property = ( 'ImageType' => 'Folder', ); my %hhc_global_property = ( 'ImageType' => 'Folder', ); # at least kchmviewer has trouble with the corresponding textual entities foreach my $thing ('OE', 'oe', 'euro') { texinfo_register_no_arg_command_formatting($thing, undef, $Texinfo::Convert::Unicode::unicode_entities{$thing}); } sub chm_noop($$) { return ''; } sub _chm_convert_tree_to_text($$;$) { my $converter = shift; my $tree = shift; my $options = shift; $options = {} if (!defined($options)); return &{$converter->formatting_function('format_protect_text')}($converter, Texinfo::Convert::Text::convert_to_text($tree, {Texinfo::Convert::Text::copy_options_for_convert_text($converter), %$options})); } sub chm_init($) { my $self = shift; return 0 if (defined($self->get_conf('OUTFILE')) and $Texinfo::Common::null_device_file{$self->get_conf('OUTFILE')}); my $verbose = $self->get_conf('VERBOSE'); my $document_name = $self->get_info('document_name'); my $outdir = $self->get_info('destination_directory'); $outdir = File::Spec->curdir() if ($outdir eq ''); my $hhk_filename = $document_name . ".hhk"; my $hhk_file_path_name = File::Spec->catfile($outdir, $hhk_filename); my ($encoded_hhk_file_path_name, $hhk_path_encoding) = $self->encoded_output_file_name($hhk_file_path_name); my ($hhk_fh, $hhk_error_message) = Texinfo::Common::output_files_open_out( $self->output_files_information(), $self, $encoded_hhk_file_path_name); if (!defined($hhk_fh)) { $self->document_error($self, sprintf(__("chm.pm: could not open %s for writing: %s\n"), $hhk_file_path_name, $hhk_error_message)); return 1; } print STDERR "# chm: writing HTML Help index in $hhk_file_path_name...\n" if ($verbose); print $hhk_fh "\n\n"; print $hhk_fh "\nget_conf('PROGRAM') ."\">\n"; print $hhk_fh "\n\n\n"; print $hhk_fh "\n"; foreach my $property (sort(keys(%hhk_global_property))) { print $hhk_fh "\n"; } print $hhk_fh "\n"; my ($index_entries, $index_entries_sort_strings) = Texinfo::Structuring::sort_indices($self, $self, $self->get_info('index_entries'), $self->get_info('indices_information')); if ($index_entries) { foreach my $index_name (sort(keys(%$index_entries))) { foreach my $index_entry_ref (@{$index_entries->{$index_name}}) { my $main_entry_element = $index_entry_ref->{'entry_element'}; my $entry_index_name = $index_entry_ref->{'index_name'}; # do not register index entries that do not point to the document next if ($main_entry_element->{'extra'} and ($main_entry_element->{'extra'}->{'seeentry'} or $main_entry_element->{'extra'}->{'seealso'})); my $origin_href = $self->command_href($main_entry_element, ''); my $entry_content_element = Texinfo::Common::index_content_element($main_entry_element); my $indices_information = $self->get_info('indices_information'); my $in_code = 0; $in_code = 1 if ($indices_information->{$index_entry_ref->{'index_name'}}->{'in_code'}); my $entry = _chm_convert_tree_to_text($self, {'contents' => [$entry_content_element]}, {'code' => $in_code}); print $hhk_fh "
  • \n" ."\n" ."\n" ."
  • \n" if ($entry =~ /\S/); } } } print $hhk_fh "\n\n"; Texinfo::Common::output_files_register_closed( $self->output_files_information(), $encoded_hhk_file_path_name); if (!close ($hhk_fh)) { $self->document_error($self, sprintf(__("chm.pm: error on closing %s: %s"), $hhk_file_path_name, $!)); return 1; } my $hhc_filename = $document_name . ".hhc"; my $hhc_file_path_name = File::Spec->catfile($outdir, $hhc_filename); my ($encoded_hhc_file_path_name, $hhc_path_encoding) = $self->encoded_output_file_name($hhc_file_path_name); my ($hhc_fh, $hhc_error_message) = Texinfo::Common::output_files_open_out( $self->output_files_information(), $self, $encoded_hhc_file_path_name); if (!defined($hhc_fh)) { $self->document_error($self, sprintf(__("chm.pm: could not open %s for writing: %s\n"), $hhc_file_path_name, $hhc_error_message)); return 1; } print STDERR "# chm: writing HTML Help project in $hhc_file_path_name...\n" if ($verbose); print $hhc_fh "\n\n"; print $hhc_fh "\nget_conf('PROGRAM') ."\">\n"; print $hhc_fh "\n\n\n"; print $hhc_fh "\n"; foreach my $property (sort(keys(%hhc_global_property))) { print $hhc_fh "\n"; } print $hhc_fh "\n"; if ($self->{'structuring'} and $self->{'structuring'}->{'sectioning_root'}) { my $section_root = $self->{'structuring'}->{'sectioning_root'}; my $upper_level = $section_root->{'structure'}->{'section_childs'}->[0] ->{'structure'}->{'section_level'}; foreach my $top_section (@{$section_root->{'structure'}->{'section_childs'}}) { $upper_level = $top_section->{'structure'}->{'section_level'} if ($top_section->{'structure'}->{'section_level'} < $upper_level); } $upper_level = 1 if ($upper_level <= 0); my $root_level = $upper_level - 1; my $level = $root_level; foreach my $section (@{$self->{'structuring'}->{'sections_list'}}) { next if ($section->{'cmdname'} eq 'part'); my $section_level = $section->{'structure'}->{'section_level'}; $section_level = 1 if ($section_level == 0); if ($level < $section_level) { while ($level < $section_level) { print $hhc_fh "\n"; $level--; } } my $text = _chm_convert_tree_to_text($self, $section->{'args'}->[0]); # should not be needed as end of lines are not converted, end of line # can be added with invalid nestings. chomp($text); $text = Texinfo::Convert::Utils::add_heading_number($self,$section, $text, $self->get_conf('NUMBER_SECTIONS')); # the empty string as second argument makes sure that the # source file is different from the target file. my $origin_href = $self->command_href($section, ''); print $hhc_fh "
  • \n\n\n
  • \n"; } while ($level > $root_level) { print $hhc_fh "\n"; $level--; } } print $hhc_fh "\n\n"; Texinfo::Common::output_files_register_closed( $self->output_files_information(), $encoded_hhc_file_path_name); if (!close ($hhc_fh)) { $self->document_error($self, sprintf(__("chm.pm: error on closing %s: %s"), $hhc_file_path_name, $!)); return 1; } my $hhp_filename = $document_name . ".hhp"; my $hhp_file_path_name = File::Spec->catfile($outdir, $hhp_filename); my ($encoded_hhp_file_path_name, $hhp_path_encoding) = $self->encoded_output_file_name($hhp_file_path_name); my ($hhp_fh, $hhp_error_message) = Texinfo::Common::output_files_open_out( $self->output_files_information(), $self, $encoded_hhp_file_path_name); if (!defined($hhp_fh)) { $self->document_error( $self, sprintf(__("chm.pm: could not open %s for writing: %s\n"), $hhp_file_path_name, $hhp_error_message)); return 1; } print STDERR "# chm: writing HTML Help project in $hhp_file_path_name...\n" if ($verbose); my $language = $chm_languages{'en'}; my $documentlanguage = $self->get_conf('documentlanguage'); $documentlanguage =~ s/_.*//; if (exists ($chm_languages{$documentlanguage})) { $language = $chm_languages{$documentlanguage}; } my $title = _chm_convert_tree_to_text($self, $self->get_info('title_tree')); my $top_file = ''; my $top_element = $self->global_direction_element('Top'); if ($top_element) { $top_file = $top_element->{'structure'}->{'unit_filename'}; } print $hhp_fh <{'tree_units'}) { foreach my $element (@{$self->{'tree_units'}}) { if (!$chm_files{$element->{'structure'}->{'unit_filename'}}) { print $hhp_fh "$element->{'structure'}->{'unit_filename'}\n"; $chm_files{$element->{'structure'}->{'unit_filename'}} = 1; } } } Texinfo::Common::output_files_register_closed( $self->output_files_information(), $encoded_hhp_file_path_name); if (!close ($hhp_fh)) { $self->document_error($self, sprintf(__("chm.pm: error on closing %s: %s"), $hhp_file_path_name, $!)); return 1; } return 0; } texinfo_register_handler('init', \&chm_init); 1;