ocument_info->{'setfilename'})) {
    $setfilename = $document_info->{'setfilename'};
  }

  my $input_basename_for_outfile = $input_basename;
  my $setfilename_for_outfile = $setfilename;
  # PREFIX overrides both setfilename and the input file base name
  if (defined($self->get_conf('PREFIX'))) {
    $setfilename_for_outfile = undef;
    $input_basename_for_outfile = $self->get_conf('PREFIX');
  }

  # the document path, in general the outfile without
  # extension and can be set from setfilename if outfile is not set
  my $document_path;
  # determine output file and output file name
  my $output_file;
  if (!defined($self->get_conf('OUTFILE'))) {
    if (defined($setfilename_for_outfile)) {
      $document_path = $setfilename_for_outfile;
      $document_path =~ s/\.[^\.]*$//;
      if (!$self->get_conf('USE_SETFILENAME_EXTENSION')) {
        $output_file = $document_path;
        $output_file .= '.'.$self->get_conf('EXTENSION')
          if (defined($self->get_conf('EXTENSION'))
              and $self->get_conf('EXTENSION') ne '');
      } else {
        $output_file = $setfilename_for_outfile;
      }
    } elsif ($input_basename_for_outfile ne '') {
      $output_file = $input_basename_for_outfile;
      $document_path = $input_basename_for_outfile;
      $output_file .= '.'.$self->get_conf('EXTENSION')
        if (defined($self->get_conf('EXTENSION'))
            and $self->get_conf('EXTENSION') ne '');
    } else {
      $output_file = '';
      $document_path = $output_file;
    }
    if (defined($self->get_conf('SUBDIR')) and $output_file ne '') {
      my $dir = File::Spec->canonpath($self->get_conf('SUBDIR'));
      $output_file = join('/', ($dir, $output_file));
    }
  } else {
    $document_path = $self->get_conf('OUTFILE');
    $document_path =~ s/\.[^\.]*$//;
    $output_file = $self->get_conf('OUTFILE');
  }

  # the output file path, in general same as the outfile but can be
  # set from setfilename if outfile is not set.
  my $output_filepath = $output_file;
  # in this case one wants to get the result in a string and there
  # is a setfilename.  The setfilename is used to get something.
  # This happens in the test suite.
  if ($output_file eq '' and defined($setfilename_for_outfile)) {
    $output_filepath = $setfilename_for_outfile;
    $document_path = $setfilename_for_outfile;
    $document_path =~ s/\.[^\.]*$//;
  }

  # $document_name is the name of the document, which is the output
  # file basename, $output_filename, without extension.
  my ($document_name, $output_filename, $directories, $suffix);
  # We may be handling setfilename there, so it is not obvious that we
  # want to use fileparse and not consider unixish separators.  However,
  # if this is setfilename, it should be a simple file name, so it
  # should hopefully be harmless to use fileparse
  ($document_name, $directories, $suffix) = fileparse($document_path);
  ($output_filename, $directories, $suffix) = fileparse($output_filepath);
  my $destination_directory;
  if ($self->get_conf('SPLIT')) {
    if (defined($self->get_conf('OUTFILE'))) {
      $destination_directory = $self->get_conf('OUTFILE');
    } elsif (defined($self->get_conf('SUBDIR'))) {
      $destination_directory = $self->get_conf('SUBDIR');
    } else {
      $destination_directory = $document_name;
      if (defined($output_format) and $output_format ne '') {
        $destination_directory .= '_'.$output_format;
      }
    }
  } else {
    # $output_file_filename is not used, but $output_filename should be
    # the same as long as $output_file is the same as $output_filepath
    # which is the case except if $output_file is ''.
    # Note that fileparse may return a string for the directory part even
    # for a relative file without directory, ie
    # myfile.html -> $output_dir = './'
    # In that case the $destination_directory will never be ''.
    my ($output_file_filename, $output_dir, $suffix) = fileparse($output_file);
    $destination_directory = $output_dir;
  }
  if ($destination_directory ne '') {
    $destination_directory = File::Spec->canonpath($destination_directory);
  }
  return ($output_file, $destination_directory, $output_filename,
          $document_name, $input_basefile);
}

# determine the default, with $INIT_CONF if set, or the default common
# to all the converters
sub _command_init($$)
{
  my $global_command = shift;
  my $init_conf = shift;
  if (exists($Texinfo::Common::document_settable_at_commands{$global_command})) {
    if (defined($init_conf->{$global_command})) {
      return $init_conf->{$global_command};
    } elsif (defined($Texinfo::Common::document_settable_at_commands{$global_command})) {
      return $Texinfo::Common::document_settable_at_commands{$global_command};
    }
  }
  return undef;
}

# $COMMANDS_LOCATION is 'before', 'last', 'preamble' or 'preamble_or_first'
# 'before' means setting to the values before the document commands
# (defaults and command-line).
# 'preamble' means setting sequentially to the values in the preamble.
# 'preamble_or_first'  means setting to the first value for the command
# in the document if the first command is not in the preamble, else set
# sequentially to the values in the preamble.
# 'last' means setting to the last value for the command in the document.
#
# Notice that the only effect is to use set_conf (directly or through
# set_global_document_command), no @-commands setting side effects are done
# and associated customization variables are not set/reset either.
sub set_global_document_commands($$$)
{
  my $self = shift;
  my $commands_location = shift;
  my $selected_commands = shift;

  my $init_conf;
  if (defined($self->{'output_init_conf'})) {
    # use in priority the initial customization per output
    $init_conf = $self->{'output_init_conf'};
  } else {
    $init_conf = $self->{'converter_init_conf'};
  }

  if (not defined($selected_commands)) {
    die "set_global_document_commands: requires selected commands";
  }
  if ($commands_location eq 'before') {
    foreach my $global_command (@{$selected_commands}) {
      # for commands not appearing in the document, this should set the
      # same value, the converter initialization value
      $self->set_conf($global_command, _command_init($global_command, $init_conf));
      # NOTE if the variable is set from an handler, or in the converter after
      # $init_conf was set, but before starting the conversion, it is ignored here
      # and the $init_conf value is set.  The previously set value could be
      # in $self->get_conf(), but what is available from $self->get_conf() could
      # also be a value set by a previous call of set_global_document_commands.
      # There is no easy way to deal with this issue, other than making sure that
      # a customization value that is expected to be set early is set in $init_conf.
    }
  } else {
    my $global_commands;
    if ($self->{'document'}) {
      $global_commands = $self->{'document'}->global_commands_information();
    }
    foreach my $global_command (@{$selected_commands}) {
      if ($self->get_conf('DEBUG')) {
        print STDERR "SET_global($commands_location) $global_command\n";
      }

      my $element;
      if ($global_commands) {
        $element = Texinfo::Common::set_global_document_command($self,
                  $global_commands, $global_command, $commands_location);
      }
      if (not defined($element)) {
        # commands not appearing in the document, this should set the
        # same value, the converter initialization value
        # the NOTE above in 'before' holds here too.
        $self->set_conf($global_command,
                        _command_init($global_command, $init_conf));
      }
    }
  }
}

sub present_bug_message($$;$)
{
  my $self = shift;
  my $message = shift;
  my $current = shift;

  my $line_message = '';
  my $current_element_message = '';
  if ($current) {
    if ($current->{'source_info'}) {
      my $source_info = $current->{'source_info'};
      my $file = $source_info->{'file_name'};
      $line_message
        = "in: $source_info->{'file_name'}:$source_info->{'line_nr'}";
      if ($source_info->{'macro'} ne '') {
        $line_message .= " (possibly involving $source_info->{'macro'})";
      }
      $line_message .= "\n";
    }
    if ($current) {
      $current_element_message = "current: ".
        Texinfo::Common::debug_print_element($current, 1);
    }
  }
  my $additional_information = '';
  if ($line_message.$current_element_message ne '') {
    $additional_information = "Additional information:\n".
       $line_message.$current_element_message."\n";
  }
  warn "You found a bug: $message\n\n".$additional_information;
}

# Reverse the decoding of the file name from the input encoding.
# A wrapper around Texinfo::Utils::encoded_input_file_name() that
# can be called in converters through an objet oriented syntax.
sub encoded_input_file_name($$;$)
{
  my $self = shift;
  my $file_name = shift;
  my $input_file_encoding = shift;

  return Texinfo::Convert::Utils::encoded_input_file_name($self, $file_name,
                                                          $input_file_encoding);
}

# A wrapper around Texinfo::Utils::encoded_output_file_name() that
# can be called in converters through an objet oriented syntax.
sub encoded_output_file_name($$)
{
  my $self = shift;
  my $file_name = shift;
  return Texinfo::Convert::Utils::encoded_output_file_name($self, $file_name);
}

# This is used when the formatted text has no comment nor new line, but
# one want to add the comment or new line from the original arg
sub format_comment_or_return_end_line($$)
{
  my $self = shift;
  my $element = shift;

  my $end_line;

  my $comment = $element->{'args'}->[-1]->{'info'}->{'comment_at_end'}
    if $element->{'args'} and $element->{'args'}->[-1]->{'info'};

  if ($comment) {
    $end_line = $self->convert_tree($comment);
  } elsif ($element->{'args'} and $element->{'args'}->[-1]->{'info'}
      and $element->{'args'}->[-1]->{'info'}->{'spaces_after_argument'}) {
    my $text = $element->{'args'}->[-1]
                   ->{'info'}->{'spaces_after_argument'}->{'text'};
    if (chomp($text)) {
      $end_line = "\n";
    } else {
      $end_line = '';
    }
  } else {
    $end_line = '';
  }
  return $end_line;
}

