code:
use strict;

use File::Spec;
BEGIN { if (defined($ENV{'top_srcdir'})) {unshift @INC, File::Spec->catdir($ENV{'top_srcdir'}, 'tp');} }

require 't/test_utils.pl';

my $invalid_node_name_text = '
@node Top

@menu
* @asis{truc:}: @asis{nodename. a}
* machin: node@comma{}comma, def
* @asis{bidule:}::
@end menu

@node @asis{nodename. a}

@node node@comma{}comma

@node @asis{bidule:}

@ref{@asis{nodename. a}, @asis{truc:}}. @ref{node@comma{}comma, machin}.
@ref{@asis{bidule:}}.
';

my @test_cases = (
['no_nodes',
'Text.'],
['no_top_node',
'@node node Top not Top node
'],
['paragraphindent_and_preamble',
'@copying
In copying.

Copying second para.
@end copying

@node Top
@top test @@paragraphindent effect in preamble

First para.

Before paragraphindent.

@paragraphindent 1

After paragraphindent.

@bye

'],
['paragraphindent_asis_first',
'
     bbb

@paragraphindent asis
     ccc
'],
['paragraphindent_none_first',
'
      first

      second

@paragraphindent none

      after none
'],
['space_at_menu_end',
'@node Top

@menu
* (out)::

@end menu

A para.
'],
['space_in_menu',
'@node Top
@top Element

Text.

@menu
* node::
@end menu

@node node
@chapter node

in chapter.
'],
['text_before_node',
'@node Top
@top top

@menu
* chapter node::
@end menu

text.
@node chapter node
@chapter chapter'
],
['ref_tests',
'
@node Top

@ref{(m)in ref followed by comma},
@ref{(m)in ref not followed by comma} after ref.
@code{@ref{(m)in ref followed by end command}}.

@ref{(m)in ref followed by comma, name},
@ref{(m)in ref not followed by comma, name} after ref.
@code{@ref{(m)in ref followed by end command, name}}.
@ref{(m)in ref ending with a dot., name} after ref.

'],
['xref_test',
'
@node Top

@xref{(m)in xref}. @xref{(m)bad xref} after xref.
@code{@xref{(m)bad nested xref}}.
@xref{(m)in ref ending with a dot., name} ! after xref and dot inside.
@xref{(m)in ref followed by symbol}# g.
'],
['pxref_test',
'@node Top

Hey (@pxref{(m) in pxref}) and continue (@pxref{(m) in pxref, name}) and end.
@pxref{(m) n}. @pxref{(m) n, name}.
'],
['contents_setcontentsaftertitlepage_before_node',
'
@contents
@setcontentsaftertitlepage

@node Top
@top Double contents
'],
['anchor_in_command',
'@node Top

@strong{aaa @TeX{} @emph{in emph} after
@c emph @emph{emph2 @anchor{anchor in emph} }}.
emph @emph{emph2 @anchor{anchor in emph}}}.
'],
['anchor_and_spaces',
'@node Top
@top Element
@anchor{anchor 0}

Now @anchor{anchor1}.

No space@anchor{anchor2}.
'],
['before_node_and_section',
'Garbage
ref to Top @ref{Top}.
@cindex index entry before anything
Hey@footnote{a footnote}.
An anchor @anchor{anchor1}.

@menu
* node1::
@end menu

@node Top
@top top @@top section
Node top

ref to anchor1@footnote{another footnote}, which is before @@node Top: @ref{anchor1}.
@menu
* node1::
@end menu

@node node1
@chapter node1 chapter

@printindex cp

'],
['image_quotes',
'@node Top

@image{f--ile,,,alt""\\}
'],
['image_in_paragraph',
'@node Top

Para.
@image{f--ile,,,alt""\\}. End para.
'],
['image_not_found',
'@node Top
@image{n_f_image}
'],
['image_file_search',
'@node Top

@c does not work in the standalone perl module
@c @image{tp/t/include_dir/f--ile}

@@image dot.
@image{./tp/t/include_dir/f--ile}

@@image dot parent.
@image{../include_dir/f--ile}
',{'include_directories' => ['.', '..', 't/include_dir']}],
['image_extension',
'@node Top

@image{fext,,,,ext}
@image{fdotext,,,,ext}
@image{f--ile,,,,ext}
'],
['image_text_encoded',
'@documentencoding utf-8

@image{image_encoded}
'],
['image_and_spaces_formatting',
'@node Top

@image{words} @image{words} @image{words} @image{words} @image{words} @image{words} @image{words}

Some text @image{words} @image{words} @image{words} @image{words} @image{words} @image{words} @image{words}.

Some text @image{words} text aaaaaaaaa @image{words} text bbbbbbbbbbb @image{words} text ccccccccccccc @image{words} text ddddddddddddd @image{words} text eeeeeeeeeeeeeee @image{words} text fffffffffff @image{words}.

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA @image{words}

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB @image{words}

Text. @image{words}       @image{words}.

'],
['image_and_punctuation',
'@node Top

One space. @image{f--ile}.

Two spaces.  @image{f--ile}.

End line.
@image{f--ile}.

One space. @image{words}.

Two spaces.  @image{words}.

End line.
@image{words}.
'],
[ 'multitable_anchor_and_index_entry',
'@node Top

@multitable @columnfractions 0.4 0.6
@headitem mu--ltitable headitem @tab another tab
@item mu--ltitable item @tab multitable tab
@c comment in multitable
@item mu--ltitable item 2 @tab multitable tab 2
@cindex index entry within multitable
@anchor{anchor in multitable}
@item lone mu--ltitable item
@end multitable

@multitable {A} {B}
@item A
B

C
@tab G
@item lsfd mlkdsf lk s
mlsdmjlfdsjm mdsfk
@cindex index entry
@item lsfd2 mlkdsf2 lk2 s2
mlsdmjlfdsjm mdsfk2
@tab ATTTTTTTTTTTTTTTTTTTTT
BTTTTTTt @anchor{mark}

CTTTTTT

@end multitable

@printindex cp
@ref{mark}
@ref{anchor in multitable}
'],
['note_in_strong',
'@node Top

3 One @strong{Note}.

5 @strong{Note a}.

9 @strong{note}.

11 @strong{note b}.

13 @strong{ note}.

15 @strong{note-bbb}.
'],
['note_in_strong_end_of_line',
'@node Top

bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb vvvvvvvvvvvvvvvv @strong{note a}

bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb vvvvvvvvvvvvvvvv @strong{note
a}
'],
['nested_multitable_anchor_index',
'@node Top

@multitable {truc AAAA   machin}    {bidule}
@item
@multitable {AAAA} {machin}
@item AAAA @tab machin @anchor{mark inside}
@cindex index entry inside
@end multitable
 @tab bidule
@item other item @tab in tab @anchor{mark}
@cindex index entry
@end multitable

@printindex cp

@xref{mark}.
@xref{mark inside}.
'],
['def_in_copying',
'@macro mymacro
@deffn aa bb cc
@deffnx aax bbx ccx
deffnx lines
@end deffn
@end macro

@node Top
@top Test for definition commands

@copying
In copying
@mymacro{}
@end copying

In text
@mymacro{}

@printindex fn
'],
['file_only_png',
'@node Top

Just before an image @image{this_is_a_long_unknown_file} text after the image, and more text, and more @image{this_is_a_long_unknown_file} text.
'],
['float_long_captions',
'@node Top

@float Text, text1
@caption{AAAAAAAAAAAAAAAA BBBBB CCCCCCCCCCC}
@end float

@float Text, text2
@caption{AAAAAAAAAAAAAAAA BBBBBB CCCCCCCCCCC}
@end float

@listoffloats Text
'],
['error_in_footnote',
'
@node Top

@float Text, label

Float text1

@caption{Caption. @TeX.
In caption @strong{note caption}.
Now footnote@footnote{@LaTeX.
and strong @strong{Note footnote}.}}
@end float

@listoffloats Text

@listoffloats Text
'],
['nested_footnotes_separate',
'@footnotestyle separate
@node Top

F@footnote{F1

V@footnote{F2}
}
'],
['encoding_us_ascii',
'
@documentencoding US-ASCII

@node Top

'],
['known_encoding',
'
@documentencoding latin1

@node Top

'],
['unknown_encoding',
'
@documentencoding ggg

@node Top

'],
['top_node_normalization',
'@node ToP

@xref{TOP}. @xref{tOP}.

@menu
* tOP::
@end menu
'],
# since there is no split in the test suite, there is no split tested
# here, in fact.
['split_no_copying',
'\input texinfo
@setfilename split-nocopying.info

@node Top
@top Top

This is the top node.

@menu
* Ch1::
@end menu

@node Ch1
@chapter Ch1

First chapter.

@bye

',{},{'SPLIT_SIZE' => 10}],
['no_node_but_top',
'@top top
'],
['space_in_setfilename',
'@setfilename @ @verb{: name :}@

@node Top
'],
['novalidate_empty_refs',
'
@novalidate

@node Top

@xref{@:}.
@xref{@asis{ }}.

@node @
@node @:
@node @asis{ }
'],
['invalid_node_name_warning',
$invalid_node_name_text
],
['invalid_node_name_no_warning',
$invalid_node_name_text,
{},{'INFO_SPECIAL_CHARS_WARNING' => 0}
],
['only_documentencoding',
'@documentencoding ISO-8859-1'],
['direntry_dircategory_and_commands',
'@dircategory ``category---@var{th  ere}?\'\'
@direntry
* foo: (foo).   ``hello---@var{there}?\'\'
@end direntry

@dircategory cat2
@direntry
* aaa ::               aaaa
                   bbbbb

menutitle
@end direntry

@node Top
@top Test dircategory and direntry

Text
'],
['colon_in_index_entry',
'@node Top

@synindex vr cp

@cindex a:b

@vtable @emph
@item %main::value
@end vtable

@defvr {a:b} {c:d} e f
@defvrx {x:y} {z:t} n m o
@end defvr

@printindex cp
'],
['test_index',
'@node Top
@top Element top

@xref{a counting anchor}.

before menu.
@cindex in Top
@cindex @@
@cindex @exclamdown{}
@cindex "

@deffn fset @var{i} a g
@deffnx truc machin bidule chose

@end deffn

@ftable @emph
@item a fun
Var text

@item second fun
@itemx itemx fun

@end ftable

@menu
* name::
* name1 looooooooooooooooooooooooooooooooooooooooooooooooooooooooong::
@end menu

@node name
@chapter A chapter

@cindex index entry looooooooooooooooooooooooooooooooooooooooooooooooooooooooong
@findex function index entry

A paragraph
@findex other function
end paragraph

a

a

a

a

a

@findex after lines.

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

b

@findex after more than 100 lines

@node name1 looooooooooooooooooooooooooooooooooooooooooooooooooooooooong
@appendix Index

@cindex index entry in appendix before para
Para.

Concept index
@printindex cp

@findex index entry between indices

Functions index
@printindex fn

@appendixsec appendixsec

@appendixsubsec appendixsubsec

@appendixsubsubsec appendixsubsubsec

@chapheading chapheading

@centerchap centerchap

@chapter chapter end

@cindex index in chapter end

@anchor{a counting anchor}

@bye
'],
['index_entry_at_end_node',
'@node Top
@top Element

@menu
* chapter::
* indices::
@end menu

@node chapter
@chapter Chapter

@cindex index entry

@node indices
@appendix indices

@printindex cp
'],
['center_flush',
'@center centered

@flushleft
left and
left2

left3.

left Last
  with space.

Now anchor
@anchor{anchor in flushleft}
after anchor
@end flushleft

@flushright
right and
right2

Right3

Right last
  with space.

Now anchor
@anchor{anchor in flushright}
after anchor
Second anchor in text @anchor{second anchor in flushright} after anchor.
@end flushright
'],
# if this test is changed, the corresponding test in t/plaintext_tests.t
# should be changed too
['multiline_image_and_align',
'@center @image{figure}

@center CCCC @image{figure}

@center fffffffffffffffffffffffffffffffffffffff @image{figure}

@center dddd @image{figure} iiiii

@flushright
AAA
@image{figure}

BBB @image{figure} gggg @image{figure}

HHH
@image{figure} JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
@end flushright

@center @image{figure, , , ,txt}

@center CCCC @image{figure, , , ,txt}

@center fffffffffffffffffffffffffffffffffffffff @image{figure, , , ,txt}

@center dddd @image{figure, , , ,txt} iiiii

@flushright
AAA
@image{figure, , , ,txt}

BBB @image{figure, , , ,txt} gggg @image{figure, , , ,txt}

HHH
@image{figure, , , ,txt} JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
@end flushright
'],
);

my @file_tests = (
['split_test_before_first_node',
'@setfilename split_test_before_first_node.info

truc machin et reuc machin  ze aze zea zae eaz eaz zae

@node Top
@top top

In top node

@menu
* chap1::
@end menu

@node chap1
@chapter chap

In chap1.

',{},{'SPLIT_SIZE' => 10}],
['split_test_before_first_node_no_empty_line',
'@setfilename split_test_before_first_node.info

truc machin et reuc machin  ze aze zea zae eaz eaz zae
@node Top
@top top

In top node

@menu
* chap1::
@end menu

@node chap1
@chapter chap

In chap1.

',{},{'SPLIT_SIZE' => 10}],
);

foreach my $test (@test_cases) {
  push @{$test->[2]->{'test_formats'}}, 'info';
}

foreach my $test (@file_tests) {
  push @{$test->[2]->{'test_formats'}}, 'file_info';
}

our ($arg_test_case, $arg_generate, $arg_debug);

run_all ('info_tests', [@test_cases, @file_tests], $arg_test_case,
   $arg_generate, $arg_debug);

1;


code:
use vars qw($texinfo_code_types);

$texinfo_code_types->{'menu_comment'} = 1;

repo_name: mthl/texinfo

license: mit


code:
set_from_init_file('ICONS', 1);

# insert here name of icon images for buttons
# Icons are used, if ICONS and resp. value are set
%ACTIVE_ICONS =
    (
     'Top',         'a_top.png',
     'Contents',    'a_tableofcon.png',
     'Overview',    'a_tableofcon.png',
     'Index',       'a_index.png',
     'This',        '',
     'Back',        'a_left.png',
     'FastBack',    'a_leftdouble.png',
     'Prev',        'a_left.png',
     'Up',          'a_up.png',
     'Next',        'a_right.png',
     'NodeUp',      'a_up.png',
     'NodeNext',    'a_right.png',
     'NodePrev',    'a_left.png',
     'NodeForward', 'a_right.png',
     'NodeBack',    'a_left.png',
     'Forward',     'a_right.png',
     'FastForward', 'a_rightdouble.png',
     'About' ,      'a_help.png',
     'First',       '',
     'Last',        '',
     ' ',           ''
    );

# insert here name of icon images for these, if button is inactive
%PASSIVE_ICONS =
    (
     'Top',         'a_top_na.png',
     'Contents',    'a_tableofcon_na.png',
     'Overview',    'a_tableofcon_na.png',
     'Index',       'a_index_na.png',
     'This',        '',
     'Back',        'a_left_na.png',
     'FastBack',    'a_leftdouble_na.png',
     'Prev',        'a_left_na.png',
     'Up',          'a_up_na.png',
     'Next',        'a_right_na.png',
     'NodeUp',      'a_up_na.png',
     'NodeNext',    'a_right_na.png',
     'NodePrev',    'a_left_na.png',
     'NodeForward', 'a_right_na.png',
     'NodeBack',    'a_left_na.png',
     'Forward',     'a_right_na.png',
     'FastForward', 'a_rightdouble_na.png',
     'About' ,      'a_help_na.png',
     'First',       '',
     'Last',        '',
    );

set_from_init_file('ACTIVE_ICONS', \%ACTIVE_ICONS);
set_from_init_file('PASSIVE_ICONS', \%PASSIVE_ICONS);

1;


code:
use strict;

use vars qw(%commands_conversion);

sub convert_comment_command($$$)
{
  my $self = shift;
  my $cmdname = shift;
  my $command = shift;

  if ($command->{'args'} and $command->{'args'}->[0]) {
    return $self->xml_comment($command->{'args'}->[0]->{'text'});
  } else {
    return '';
  }
}

texinfo_register_command_formatting('c', \&convert_comment_command);
texinfo_register_command_formatting('comment', \&convert_comment_command);

sub convert_ignore_command($$$$)
{
  my $self = shift;
  my $cmdname = shift;
  my $command = shift;
  my $content = shift;

  # FIXME should the spacing be set differently for raw commands?
  return $self->xml_comment(" ".$content."\n");
}

texinfo_register_command_formatting('ignore', \&convert_ignore_command);


code:
######################################################################
# from here on, its l2h init stuff
#

## initialization for latex2html as for Singular manual generation
## obachman 3/99

#
# Options controlling Titles, File-Names, Tracing and Sectioning
#
$TITLE = '';

$SHORTEXTN = 0;

$LONG_TITLES = 0;

#$DESTDIR = '';

$NO_SUBDIR = 1;

#$PREFIX = '';

$AUTO_PREFIX = 0;

$AUTO_LINK = 0;

$SPLIT = 0;

$MAX_LINK_DEPTH = 0;

#$TMP = '';

$DEBUG = 0;

$VERBOSE = 1;

#
# Options controlling Extensions and Special Features
#
#$HTML_VERSION = "3.2";         # set by command line

$TEXDEFS = 1;                   # we absolutely need that

$EXTERNAL_FILE = '';

$SCALABLE_FONTS = 1;

$NO_SIMPLE_MATH = 1;

$LOCAL_ICONS = 1;

$SHORT_INDEX = 0;

$NO_FOOTNODE = 1;

$ADDRESS = '';

$INFO = '';

#
# Switches controlling Image Generation
#
$ASCII_MODE = 0;

$NOLATEX = 0;

$EXTERNAL_IMAGES = 0;

$PS_IMAGES = 0;

$NO_IMAGES = 0;

$IMAGES_ONLY = 0;

$REUSE = 2;

$ANTI_ALIAS = 1;

$ANTI_ALIAS_TEXT = 1;

#
#Switches controlling Navigation Panels
#
$NO_NAVIGATION = 1;
$ADDRESS = '';
$INFO = 0;                      # 0 = do not make a "About this document..." section

#
#Switches for Linking to other documents
#
# currently -- we don't care

$MAX_SPLIT_DEPTH = 0;           # Stop making separate files at this depth

$MAX_LINK_DEPTH = 0;            # Stop showing child nodes at this depth

$NOLATEX = 0;                   # 1 = do not pass unknown environments to Latex

$EXTERNAL_IMAGES = 0;           # 1 = leave the images outside the document

$ASCII_MODE = 0;                # 1 = do not use any icons or internal images

# 1 =  use links to external postscript images rather than inlined bitmap
# images.
$PS_IMAGES = 0;
$SHOW_SECTION_NUMBERS = 0;

### Other global variables ###############################################

# put dvips stderr on stdout since latex2html is alread very verbose
$DVIPS = "$DVIPS ".' 2>&1';

$CHILDLINE = "";

# This is the line width measured in pixels and it is used to right justify
# equations and equation arrays;
$LINE_WIDTH = 500;

# Used in conjunction with AUTO_NAVIGATION
$WORDS_IN_PAGE = 300;

# The value of this variable determines how many words to use in each
# title that is added to the navigation panel (see below)
#
$WORDS_IN_NAVIGATION_PANEL_TITLES = 0;

# This number will determine the size of the equations, special characters,
# and anything which will be converted into an inlined image
# *except* "image generating environments" such as "figure", "table"
# or "minipage".
# Effective values are those greater than 0.
# Sensible values are between 0.1 - 4.
$MATH_SCALE_FACTOR = 1.5;

# This number will determine the size of
# image generating environments such as "figure", "table" or "minipage".
# Effective values are those greater than 0.
# Sensible values are between 0.1 - 4.
$FIGURE_SCALE_FACTOR = 1.6;

#  If both of the following two variables are set then the "Up" button
#  of the navigation panel in the first node/page of a converted document
#  will point to $EXTERNAL_UP_LINK. $EXTERNAL_UP_TITLE should be set
#  to some text which describes this external link.
$EXTERNAL_UP_LINK = "";
$EXTERNAL_UP_TITLE = "";

# If this is set then the resulting HTML will look marginally better if viewed
# with Netscape.
$NETSCAPE_HTML = 1;

# Valid paper sizes are "letter", "legal", "a4","a3","a2" and "a0"
# Paper sizes has no effect other than in the time it takes to create inlined
# images and in whether large images can be created at all ie
#  - larger paper sizes *MAY* help with large image problems
#  - smaller paper sizes are quicker to handle
$PAPERSIZE = "a4";

# Replace "english" with another language in order to tell LaTeX2HTML that you
# want some generated section titles (eg "Table of Contents" or "References")
# to appear in a different language. Currently only "english" and "french"
# is supported but it is very easy to add your own. See the example in the
# file "latex2html.config"
$TITLES_LANGUAGE = "english";

1;                              # This must be the last non-comment line

# End File l2h.init
######################################################################


code:
set_from_init_file('shortcontents', 1);

sub mini_ker_element_type($$$$)
{
  my $self = shift;
  my $cmdname = shift;
  my $command = shift;
  my $content = shift;

  if ($self->element_is_top($command)) {
    my $result = '';
    $result .= &{$self->{'format_navigation_header'}}($self,
          $self->get_conf('MISC_BUTTONS'), $cmdname, $command)
      if ($self->get_conf('SPLIT') or $self->get_conf('HEADERS'));
    $result .= &{$self->{'format_titlepage'}}($self);
    my $overview = &{$self->{'format_contents'}}($self, 'shortcontents', undef);
    if ($overview) {
      $result .= '
 ' .$self->convert_tree($self->gdt('Overview:'))
                  . "
\n" . "
\n";
      $result .= $overview;;
      $result .= "
\n";
    }
    $result .= &{$self->default_formatting_function('element_footer')}($self,
                                                 $cmdname, $command, $content);
    return $result;
  } else {
    return &{$self->default_types_conversion($cmdname)}($self,
        $cmdname, $command, $content);
  }
}

texinfo_register_type_formatting('element', \&mini_ker_element_type);


code:
use strict;

use vars qw($element_file_name);

$element_file_name = \&test_misc_file_name;

sub test_misc_file_name($$$)
{
  my $converter = shift;
  my $element = shift;
  my $filename = shift;

  if ($converter->element_is_top($element)
      or ($converter->{'elements'}->[2]
          and $converter->{'elements'}->[2] eq $element)) {
    my $extension = $converter->get_conf('EXTENSION');
    my $prefix = $converter->{'document_name'};
    $filename = "${prefix}_abt"
      . ((defined($extension)) ? ".$extension" : '');
  }
  return $filename;
}

set_from_init_file('DO_ABOUT', 1);

1;


code:
use strict;

use vars qw($special_element_target_file_name);

$special_element_target_file_name = \&toc_out_element_file_name;

sub toc_out_element_file_name($$$$$)
{
    my $converter = shift;
    my $element = shift;
    my $target = shift;
    my $filename = shift;

    my $prefix = $converter->{'document_name'};
    my $type = $element->{'extra'}->{'special_element'};
    if ($type and $type ne 'Contents')
    {
        $filename = "$prefix.".$converter->get_conf('EXTENSION');
    }
    return ($target, $filename);
}

1;


code:
use strict;

texinfo_register_command_formatting('need', \&my_need_formatting);

sub my_need_formatting($$$)
{
  my $converter = shift;
  my $cmdname = shift;
  my $command = shift;

  if ($command->{'extra'} and $command->{'extra'}->{'misc_args'}
      and @{$command->{'extra'}->{'misc_args'}}) {
    $converter->line_warn ("need has the right arg: $command->{'extra'}->{'misc_args'}->[0]",
                           $command->{'line_nr'});
  } else {
    $converter->line_warn ("Bad arg for $cmdname",
                           $command->{'line_nr'});
  }
  my $arg_text;
  if ($command->{'args'} and $command->{'args'}->[0]) {
    $arg_text = Texinfo::Convert::Text::convert($command->{'args'}->[0]);
  } else {
    $arg_text = '';
  }
  return (&{$converter->{'format_comment'}}($converter, "$cmdname: $arg_text"));
}


code:
# -*-perl-*-
######################################################################
#
# File: t2h_singular.init init file for singular t2h
#

use strict;

my $T2H_BLUE_BUTTONS = 0;

# we only redefine things which ar of relevance to singular
# all the others we simply "include"

# -prefix
# Set the output file prefix, prepended to all .html, .png and .pl files.
set_from_init_file('setfilename', 'sing');

# -expand
# if set to "tex" (or, "info") expand @iftex and @tex (or, @ifinfo) sections
# else, neither expand @iftex, @tex, nor @ifinfo sections
set_from_init_file('EXPANDED_FORMATS', ['html', 'tex']);

# if set, creates one html file per node
set_from_init_file('SPLIT', 'node');

#if set cross-references use the xref node name argument
set_from_init_file('XREF_USE_NODE_NAME_ARG', 1);

# if set, chatter about what we are doing
set_from_init_file('VERBOSE', 1);

# print index summary for 'cp' index
# obsolete
#set_from_init_file('IDX_SUMMARY', 'cp');

my $T2H_SING_base_images = '../singular_images/';

# inside
set_from_init_file('BODYTEXT','lang="en"  background="'.${T2H_SING_base_images}.'Mybg.png"');

# after
set_from_init_file('AFTER_BODY_OPEN', "\n");

# before
set_from_init_file('PRE_BODY_CLOSE', "\n");

# if using tex4ht, must be in latex mode due to \textbf
$Texinfo::TeX4HT::STYLE='latex';

# title is already in the manual
#$print_title = \&T2H_DEFAULT_print_title;
set_from_init_file('SHOW_TITLE', 0);

# footer

texinfo_register_formatting_function('element_footer' , \&singular_footer);

sub singular_footer($$$$)
{
  my $self = shift;
  my $type = shift;
  my $element = shift;
  my $content = shift;

  my $end_page = (!$element->{'element_next'}
       or (defined($element->{'filename'})
           and $element->{'filename'} ne $element->{'element_next'}->{'filename'}
           and $self->{'file_counters'}->{$element->{'filename'}} == 1));

  if ($self->element_is_top($element)) {
    my $buttons = $self->get_conf('TOP_BUTTONS');
    my $content_href = $self->_element_direction($element, 'Contents',
                                               'href');
    my $about_href = $self->_element_direction($element, 'About',
                                               'href');
    my $result = '';
    if ($content_href or $about_href) {
      $result .= "
\n";
      $result .= "Table of Contents\n
\n"
         if ($content_href);
      $result .= "About this document"
         if ($about_href);
      $result .= "
";
    }
    $result .= "

"
       if ($self->get_conf('VERTICAL_HEAD_NAVIGATION'));
    $result .= $self->get_conf('DEFAULT_RULE')."\n"
       if (defined($self->get_conf('DEFAULT_RULE')));
    if ($end_page) {
      $result .= &{$self->{'format_navigation_header_panel'}}($self,
                                            $buttons, undef, $element);
    }
    return $result;
  }

  return &{$self->default_formatting_function('element_footer')}($self,
                                            $type, $element, $content);
}

texinfo_register_formatting_function('end_file' , \&singular_end_file);

# footer of page
sub singular_end_file($)
{
  my $self = shift;
  my $pre_body_close = $self->get_conf('PRE_BODY_CLOSE');
  my $program_homepage = $self->get_conf('PACKAGE_URL');
  my $program_and_version = $self->get_conf('PACKAGE_AND_VERSION');
  my $version = $self->get_value('VERSION');
  my $version_date = $self->get_value('VERSION_DATE');
  $version = 'NO VERSION' if (!defined($version));
  $version_date = 'NO VERSION DATE' if (!defined($version_date));
  my $result = '

            User manual for Singular version '."$version, $version_date,
generated by $program_and_version.

$pre_body_close

";
}

sub singular_banner
{
  my $result = '';
  $result .= <<EOT;

EOT
  return $result;
}

# always use bottom navigation
set_from_init_file('WORDS_IN_PAGE', 0);

set_from_init_file('VERTICAL_HEAD_NAVIGATION', 1);
my @SECTION_BUTTONS =
  (
   \&singular_banner,
   'Back', 'Forward',   'FastBack', 'FastForward',
   'Up', 'Top', 'Contents', 'Index', 'About'
  );

set_from_init_file ('SECTION_BUTTONS', \@SECTION_BUTTONS);

my @NODE_FOOTER_BUTTONS = @SECTION_BUTTONS;
set_from_init_file ('NODE_FOOTER_BUTTONS', \@SECTION_BUTTONS);

# buttons for misc stuff
my @MISC_BUTTONS = (\&singular_banner, 'Top', 'Contents', 'Index', 'About');
my @TOP_BUTTONS = (\&singular_banner, 'Top', 'Contents', 'Index', 'About');

set_from_init_file ('MISC_BUTTONS', \@MISC_BUTTONS);
set_from_init_file ('TOP_BUTTONS', \@TOP_BUTTONS);

set_from_init_file('ICONS', 1);

my %ACTIVE_ICONS;
my %PASSIVE_ICONS;

if ($T2H_BLUE_BUTTONS) {

  %ACTIVE_ICONS =
  (
   'Top',      'blue_top.png',
   'Contents', 'blue_dir.png',
   'Overview', '',
   'Index',    'blue_readme.png',
   'Back',     'blue_prev.png',
   'FastBack', 'blue_pprev.png',
   'Prev',     'blue_pprev.png',
   'Up',       'blue_up.png',
   'Next',     'blue_nnext.png',
   'Forward',  'blue_next.png',
   'FastForward', 'blue_nnext.png',
   'About' ,    'blue_help.png',
   ' ',        ''
  );

  %PASSIVE_ICONS =
  (
   'Top',      'blue_top.png',
   'Contents', 'blue_dir.png',
   'Overview', '',
   'Index',    'blue_readme.png',
   'Back',     'blue_prev.png',
   'FastBack', 'blue_pprev.png',
   'Prev',     'blue_pprev.png',
   'Up',       'blue_up.png',
   'Next',     'blue_nnext.png',
   'Forward',  'blue_next.png',
   'FastForward', 'blue_nnext.png',
   'About' ,    'blue_help.png',
  );

} else {

  %ACTIVE_ICONS =
  (
   'Top',      'a_top.png',
   'Contents', 'a_tableofcon.png',
   'Overview', '',
   'Index',    'a_index.png',
   'Back',     'a_left.png',
   'FastBack', 'a_leftdouble.png',
   'Prev',     'a_leftdouble.png',
   'Up',       'a_up.png',
   'Next',     'a_rightdouble.png',
   'Forward',  'a_right.png',
   'FastForward', 'a_rightdouble.png',
   'About' ,    'a_help.png',
   ' ',        'a_empty.png'
  );

  %PASSIVE_ICONS =
  (
   'Top',      'a_top_na.png',
   'Contents', 'a_tableofcon_na.png',
   'Overview', '',
   'Index',    'a_index_na.png',
   'Back',     'a_left_na.png',
   'FastBack', 'a_leftdouble_na.png',
   'Prev',     'a_leftdouble_na.png',
   'Up',       'a_up_na.png',
   'Next',     'a_rightdouble_na.png',
   'Forward',  'a_right_na.png',
   'FastForward', 'a_rightdouble_na.png',
   'About' ,    'a_help_na.png',
  );
}

foreach my $hash_ref((\%ACTIVE_ICONS, \%PASSIVE_ICONS)) {
  foreach my $key (keys(%$hash_ref)) {
    next if ($hash_ref->{$key} eq '');
    $hash_ref->{$key} = $T2H_SING_base_images.$hash_ref->{$key};
  }
}

set_from_init_file ('ACTIVE_ICONS', \%ACTIVE_ICONS);
set_from_init_file ('PASSIVE_ICONS', \%PASSIVE_ICONS);

sub T2H_SING_pre_about($$)
{
  my $self = shift;
  my $element = shift;
  my $version = $self->get_value('VERSION');
  my $version_date = $self->get_value('VERSION_DATE');
  $version = 'NO VERSION' if (!defined($version));
  $version_date = 'NO VERSION DATE' if (!defined($version_date));
  my $program_homepage = $self->get_conf('PACKAGE_URL');
  my $program_and_version = $self->get_conf('PACKAGE_AND_VERSION');
  my $result = '';
  $result .= <<EOT;
This document is the user manual for Singular version $version, $version_date.

For questions and comments about Singular, send email to singular\@mathematik.uni-kl.de.

This document was generated by $program_and_version
and LaTeX2<tt>HTML</tt>
and is best  viewed with a 16 or 18 point screen font.

EOT
  return $result;
}

set_from_init_file ('PRE_ABOUT', \&T2H_SING_pre_about);

# a whole menu
texinfo_register_command_formatting('menu', \&t2h_sing_menu);

sub t2h_sing_menu($)
{
  my $self = shift;
  my $cmdname = shift;
  my $command = shift;
  my $content = shift;

  if ($content =~ /\S/) {
    return "

\n" . $content. "

\n";
  }
  return '';
}

1;    # This must be the last line


code:
@SECTION_BUTTONS = ();

foreach my $direction (('Up', 'Forward', 'Back', 'Next',
                        'Prev', 'FastForward', 'FastBack', 'This', 'NodeUp',
                        'NodePrev', 'NodeNext', 'NodeForward', NodeBack ))
#                        'NodePrev', 'NodeNext', 'ToplevelPrev', 'ToplevelNext',  'Following' ))

{
    my $direction_node = "node-".$direction;
    my $direction_href = "href-".$direction;
    my $direction_name = "name-".$direction;
    push @SECTION_BUTTONS, \"|", \$direction_node, [$direction, '-> node'], \$direction_href, [$direction, '-> href'], \$direction_name, [$direction, '-> text'], \"|";
}

@MISC_BUTTONS = @SECTION_BUTTONS;
@TOP_BUTTONS = @SECTION_BUTTONS;

set_from_init_file('MISC_BUTTONS', \@MISC_BUTTONS);
set_from_init_file('SECTION_BUTTONS', \@SECTION_BUTTONS);
set_from_init_file('TOP_BUTTONS', \@TOP_BUTTONS);

1;


code:
$renamed_nodes = {
 'old node' => 'node',
 'Top' => 'node',
 'ToP' => 'node',
 'old non existing' => 'non existing file',
 '@strong{}' => 'node',
};


code:
@documentencoding utf-8

@node Top

CHARACTER TABULATION: |	|

LINE FEED (LF): |
|

LINE TABULATION: ||

FORM FEED (FF): ||

CARRIAGE RETURN (CR): |
|

SPACE: | |

NEXT LINE (NEL): ||

NO-BREAK SPACE: | |

OGHAM SPACE MARK: | |

MONGOLIAN VOWEL SEPARATOR: ||

EN QUAD: | |

EM QUAD: | |

EN SPACE: | |

EM SPACE: | |

THREE-PER-EM SPACE: | |

FOUR-PER-EM SPACE: | |

SIX-PER-EM SPACE: | |

FIGURE SPACE: | |

PUNCTUATION SPACE: | |

THIN SPACE: | |

HAIR SPACE: | |

LINE SEPARATOR: |
|

PARAGRAPH SEPARATOR: |
|

NARROW NO-BREAK SPACE: | |

MEDIUM MATHEMATICAL SPACE: | |

IDEOGRAPHIC SPACE: |　|


code:
\input texinfo

@setfilename char_latin1_utf8_in_refs.info

@documentencoding iso-8859-1

@node Top
@top top

@printindex cp

@menu
* � � � � � � � � � � �::
* �::
* � � �::
* � � � � � � � � � �::
* �::
@end menu

@node � � � � � � � � � � �
@chapter � � � � � � � � � � �

@node �
@chapter �

@node � � �
@chapter � � �

@node � � � � � � � � � �
@chapter � � � � � � � � � �

@node �
@chapter �

@ref{� � � � � � � � � � �}
@ref{�}
@ref{� � �}
@ref{� � � � � � � � � �}
@ref{�}

@cindex � � � � � �
@cindex � � � � �
@cindex �
@cindex �
@cindex � � � � � � � � � �
@cindex �

@bye


code:
\input texinfo

@setfilename char_latin1_utf8_in_refs.info

@documentencoding utf-8

@node Top
@top top

@printindex cp

@menu
* ä ë ï ö ü ÿ Ä Ë Ï Ö Ü::
* é::
* à è ù::
* â ê î ô û Â Ê Î Ô Û::
* ç::
@end menu

@node ä ë ï ö ü ÿ Ä Ë Ï Ö Ü
@chapter ä ë ï ö ü ÿ Ä Ë Ï Ö Ü

@node é
@chapter é

@node à è ù
@chapter à è ù

@node â ê î ô û Â Ê Î Ô Û
@chapter â ê î ô û Â Ê Î Ô Û

@node ç
@chapter ç

@ref{ä ë ï ö ü ÿ Ä Ë Ï Ö Ü}
@ref{é}
@ref{à è ù}
@ref{â ê î ô û Â Ê Î Ô Û}
@ref{ç}

@cindex ä ë ï ö ü ÿ
@cindex Ä Ë Ï Ö Ü
@cindex é
@cindex è
@cindex â ê î ô û Â Ê Î Ô Û
@cindex ç

@bye


code:
\input texinfo
@setfilename char_latin2_latin2_in_refs.info

@documentencoding ISO-8859-2

@node Top
@top top

@ref{� � � � �}.

@printindex cp

@c Aogonek(0xa1=0241) aogonek(0xb1=0261) standalone ogonek(0xca=0312) Eogonek(0xea=0352) eogonek
@menu
* � � � � �::
@end menu

@node � � � � �
@chapter � � � � �

@cindex � � � � �

@bye


code:
\input texinfo
@documentencoding utf-8
@setfilename chinese_mixed_with_en.info
@settitle chinese mixed with english

@node Top

1. english only

The Emacs mode for programming in Ada 95 with GNAT helps the user
in
understanding existing code and facilitates writing new code.  It
furthermore provides some utility functions for easier integration of
standard Emacs features when programming in Ada.

2. chinese already aligned in source(this result)

这常用于修饰多个线程会访问或修改的全局变量，让编译器保证每次都从内存读取
变量的值，而不是作某些优化。（这些优化有可能导致程序不能获得正确的值）

3. chinese not aligned in source

这常用于修饰多个线程会访问或修改的全局变量，让编译器保证每次都从内存
读取
变量的值，而不是作某些优化。
（这些优化有可能导致程序不能获得正确的值）

4. a mix of chinese and english

restrict 表示在当前 scope 内不允许其它变量指向它。用处，比如防止 memory
overlap。

@bye


code:
\input texinfo @c -*-texinfo-*-

@setfilename contents_at_document_begin.info

@contents

@node Top
@top top

@chapter chap

@bye


code:
\input texinfo @c -*-texinfo-*-

@setfilename contents_at_end_document.info

@node Top
@top top

@chapter chap

@contents

@bye


code:
\input texinfo @c -*-texinfo-*-

@setfilename contents_at_end_document_after_node.info

@node Top
@top top

@menu
* a node::
@end menu

@chapter chap

@node a node,,,Top

@contents

@bye


code:
\input texinfo @c -*-texinfo-*-

@setfilename contents_in_document.info

@node Top
@top top

@contents

@chapter chap

@bye


code:
\input texinfo @c -*-texinfo-*-

@setfilename contents_no_section.info

@node Top

@contents

@bye


code:
\input texinfo
@setfilename cpp_lines.info

#line 3 "a_file"
 # 66 "g_f" 4

@email{before top}.

@node Top

# 10 25 209
# 1 2
# 46

@verbatim

  #line 5 "f"
@end verbatim

@macro macr
# line 7 "k"
@end macro

@email{after lacro def}

@macr{}

@email{after macro call}.

@include file_with_cpp_lines.texi
@email{after inc}.

@verb{:
#line 5 "in verb"
:}

@email{after verb}

@bye


code:
\input texinfo
@setfilename delcomment.info

@c this tests both the del comment and a file without
@c element.

 this is a comment.

This line is the only output.

@bye


code:
@documentencoding utf-8

This option overrides an include file name section and aaaaa aaaa
(@w{包含文字}).

@noindent
This option overrides an include file name section and aaaaa aaaa
(包含文字).


code:
\input texinfo

@c comment

@node Top
@top top

@bye


code:
\input texinfo

@center centered

Some text.

@bye


code:
\input texinfo @c -*- coding: utf-8; mode: texinfo; -*-
@documentencoding shift_jis
@setfilename japanese_shift_jis.info
@settitle GNU LilyPond -- Manuel d'initiation japanese

@documentlanguage ja

@node Top
@top GNU LilyPond --- �w�K�}�j���A��

@copying
Copyright @copyright{} 1999--2008 ����҈ꓯ

@emph{The translation of the following copyright notice is provided
for courtesy to non-English speakers, but only the notice in English
legally counts.}

@emph{�ȉ��͉p���b���Ȃ��l�X�̂��߂̒��쌠�ɂ��Ă̒��ӏ����ł��B�������Ȃ���A
�p��ŏ����ꂽ���ӏ����������@�I�ɗL���ł��B}
@end copying

����� GNU LilyPond �o�[�W����

@menu
* Preface::
* Introduction::                   LilyPond �Ƃ͉��Ȃ̂��A�Ȃ� LilyPond ���g���̂��A�ǂ������ LilyPond ���g���̂�
@end menu

@node Preface
@chapter Preface

����� 1995 �N�̂������ EJE (Eindhoven Youth Orchestra) �̃��n�[�T�����̂ł����Ƃł��� �| ����ς��҂̃o�C�I�����t�҂ł���W�����͓������ς��҂̃t�����`�z�����t�҂̃n��-�E�F���ɔނ���������Ă���V�����傫�ȃv���W�F�N�g�̂��Ƃ�b���܂����B����͉��y���o�ł��邽�߂̎��������ꂽ�V�X�e���ł� (���m�ɂ́A����� MPP �| MusiXTeX �̃v���v���Z�b�T�ł�)�B����𕷂��ăn��-�E�F���͂����Ɋy�����炢�����̕������v�����g�A�E�g�������Ǝv���A�ނ͂��̂��߂̃\�t�g�E�F�A��T���n�߁A�����ɂ��̗��ɂȂ��Ă��܂��܂����B���ꂪ MPP �̏I��������t���܂����B�����̓N�w�I�l�@���܂ݔ��M���� email �̌����̌�A�n��-�E�F���� 1996 �N�� LilyPond �̐�����J�n���܂����B���̎��A�W�����̓n��-�E�F���̐V�����v���W�F�N�g�Ɉ������荞�܂�܂����B

@node Introduction
@chapter Introduction

���̏͂ł͓ǎ҂� LilyPond �Ƃ��̃h�L�������g�ɂ��Ă̏Љ���s���܂��B

@bye


code:
\input texinfo @c -*- coding: utf-8; mode: texinfo; -*-
@documentencoding UTF-8
@setfilename japanese_utf8.info
@settitle GNU LilyPond -- Manuel d'initiation japanese

@documentlanguage ja

@node Top
@top GNU LilyPond --- 学習マニュアル

@copying
Copyright @copyright{} 1999--2008 著作者一同

@emph{The translation of the following copyright notice is provided
for courtesy to non-English speakers, but only the notice in English
legally counts.}

@emph{以下は英語を話さない人々のための著作権についての注意書きです。しかしながら、
英語で書かれた注意書きだけが法的に有効です。}
@end copying

これは GNU LilyPond バージョン

@menu
* Preface::
* Introduction::                   LilyPond とは何なのか、なぜ LilyPond を使うのか、どうやって LilyPond を使うのか
@end menu

@node Preface
@chapter Preface

それは 1995 年のある日の EJE (Eindhoven Youth Orchestra) のリハーサル中のできごとでした − ある変わり者のバイオリン奏者であるジャンは同じく変わり者のフレンチホルン奏者のハン-ウェンに彼がかかわっている新しい大きなプロジェクトのことを話しました。それは音楽を出版するための自動化されたシステムです (正確には、それは MPP − MusiXTeX のプリプロセッサです)。それを聞いてハン-ウェンはすぐに楽譜からいくつかの部分をプリントアウトしたいと思い、彼はそのためのソフトウェアを探し始め、すぐにその虜になってしまいました。それが MPP の終わりを決定付けました。多くの哲学的考察を含み白熱した email の交換の後、ハン-ウェンは 1996 年に LilyPond の製作を開始しました。この時、ジャンはハン-ウェンの新しいプロジェクトに引きずり込まれました。

@node Introduction
@chapter Introduction

この章では読者に LilyPond とこのドキュメントについての紹介を行います。

@bye


code:
@node Top
@top

@xref{normal node, the::caption and a word}
@xref{normal node, the::caption}

@xref{blah:blah, the::caption and a word}
@xref{blah:blah, the::caption}

@xref{blumpty.fump, the::caption and a word}
@xref{blumpty.fump, the::caption}.mrmrmrmmrmrmr

@xref{blah:blah}

@xref{@asis{secret,node}}

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA @xref{blah:blah}.)

@menu
* blah@asis{:}blah::
* the topic:blumpty@asis{.}fump.
* normal node::
* funny@asis{:}label:@asis{secret,node}.

@end menu

@node blah:blah
@chapter blah:blah

stuff here.

@node blumpty.fump
@chapter blumpty.fump

@node normal node
@chapter normal node

@node @asis{secret,node}
@chapter @asis{secret,node}

@node top secret node

stuff here.


code:
@documentencoding utf-8

@node Top

NO-BREAK SPACE: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbb
NARROW NO-BREAK SPACE: ccccccccccccccccccccccccccccccccccccccccccccccccccccccccc dddddddddddddddddddd


code:
\input texinfo   @c -*-texinfo-*-
@c %**start of header
@setfilename sample_utf8.info
@settitle Sample
@documentencoding UTF-8
@c %**end of header

@copying
This is a short example of a complete Texinfo file.

Copyright (C) 2005 Someone.
Texinfo中文示例
@end copying

@titlepage
@title 标题示例 ĄĘ ae ąę Â ù
@page
Texinfo中文示例
@vskip 0pt plus 1filll
@insertcopying
@end titlepage

@c Output the table of the contents at the beginning.
@contents

@ifnottex
@node Top
@top Texinfo中文示例

@insertcopying
@end ifnottex

@menu
* 第一章（First Chapter）:: 这是此示例文档的第一章
                           (with mixed cjk & latin char title)
* Second Chapter AE ĄĘ ae ąę::  this is chapter 2. AE ĄĘ ae ąę
* Index node::    Complete index.
@end menu

@node 第一章（First Chapter）
@chapter 第一章（First Chapter）

@cindex chapter, first

This is the first chapter. 这是第一章。
@cindex 另一个，index entry
@cindex ĄĘ ae ąę
@cindex é Â

Here is a numbered list.

@enumerate
@item 第
This is the first item.

@item ĄĘ
This is the second item.
@end enumerate

@node Second Chapter AE ĄĘ ae ąę
@chapter Chapter 2 AE ĄĘ ae ąę

Zażółć gęślą jaźń!

@node Index node
@unnumbered Index

@printindex cp

@bye


code:
\input texinfo

@anchor{An anchor}

Ref to the anchor:
@ref{An anchor}

Ref to the anchor in footnote:
@ref{Anchor in footnote}.

@footnote{In footnote.

@anchor{Anchor in footnote}

Ref to main text anchor
@ref{An anchor}
}

@float , float anchor
In float
@end float

Ref to float
@ref{float anchor}.

@float Text, ta
In float

@caption{ta caption}
@end float

@contents

@menu
* An anchor::                menu entry pointing to the anchor.
@end menu

@cindex index entry

@printindex cp

@listoffloats Text

@setfilename things_before_setfilename.info

@node Top
@top top section

Ref to anchor
@ref{An anchor}

Ref to footnote anchor
@ref{Anchor in footnote}


code:
\input texinfo

@anchor{An anchor}

Ref to the anchor:
@ref{An anchor}

Ref to the anchor in footnote:
@ref{Anchor in footnote}.

@footnote{In footnote.

@anchor{Anchor in footnote}

Ref to main text anchor
@ref{An anchor}
}

@float , float anchor
In float
@end float

Ref to float
@ref{float anchor}.

@float Text, ta
In float

@caption{ta caption}
@end float

@contents

@menu
* An anchor::                menu entry pointing to the anchor.
@end menu

@cindex index entry

@printindex cp

@listoffloats Text

@setfilename things_before_setfilename_no_element.info

Ref to anchor
@ref{An anchor}

Ref to footnote anchor
@ref{Anchor in footnote}


code:
use strict;

use File::Spec;
BEGIN { if (defined($ENV{'top_srcdir'})) {unshift @INC, File::Spec->catdir($ENV{'top_srcdir'}, 'tp');} }

require 't/test_utils.pl';

my @test_cases = (
['simple',
'@documentlanguage fr

@node Top

@defivar AAA BBB CCC
@end defivar
'],
['multiple',
'@documentlanguage fr

@copying
@defivar copying a b
@end defivar
@end copying

@node Top

@defivar fr BBB CCC
@end defivar

@insertcopying

@documentlanguage pt

@defivar pt BBB CCC
@end defivar

@insertcopying
'],
['appendix_translated',
'@documentlanguage fr

@node Top
@top top

@appendix dernier

@contents
'
],
['command_translated',
'@documentlanguage fr

@node Top
@top top @error{}

@error{}
'],
['unknown_language',
'@documentlanguage unknown

@node Top
@top unknkown language

Unknown language. @xref{Top}.

@documentlanguage another_UNKNOWN

Another unknown language. @xref{Top}.
'],
['unknown_region',
'@documentlanguage fr_NOWHERE

@node Top

@defivar AAA BBB CCC
@end defivar
'],
);

my $multiple_lang_chapters_text =
'@setfilename multiple_lang_chapters.info
@documentencoding utf-8

@node Top
@top Multi language file

@menu
* chapter ja::
* chapter en::
* chapter fr_FR::
* chapter de::
* chapter pt_BR::
@end menu

@documentlanguage ja
@node chapter ja
@chapter ja

In japanese. @xref{Top}.
@defivar AAA BBB CCC
@end defivar

@documentlanguage en
@node chapter en
@chapter en

In english. @xref{Top}.
@defivar AAA BBB CCC
@end defivar

@documentlanguage fr_FR
@node chapter fr_FR
@chapter fr_FR

@defivar AAA BBB CCC
@end defivar

@documentlanguage de
@node chapter de
@chapter de

@documentlanguage pt_BR
@node chapter pt_BR
@chapter pt_bR

In brazilian. @xref{Top}.
';
my @file_tests = (
['multiple_lang_chapters',
$multiple_lang_chapters_text, {}, {'SPLIT' => 0}],
['multiple_lang_chapters_texi2html',
$multiple_lang_chapters_text,
{'test_input_file_name' => 'multiple_lang_chapters.texi'},
{'SPLIT' => 0, 'TEXI2HTML' => 1, 'TEST' => 1}],
);

my %info_tests = (
  'multiple' => 1,
  'appendix_translated' => 1,
  'command_translated' => 1,
  'unknown_language' => 1,
  'unknown_region' => 1,
);

foreach my $test (@test_cases) {
  push @{$test->[2]->{'test_formats'}}, 'plaintext';
  if ($info_tests{$test->[0]}) {
    push @{$test->[2]->{'test_formats'}}, 'info';
    push @{$test->[2]->{'test_formats'}}, 'html';
  }
}

foreach my $test (@file_tests) {
  push @{$test->[2]->{'test_formats'}}, 'file_html';
  push @{$test->[2]->{'test_formats'}}, 'file_info';
}

our ($arg_test_case, $arg_generate, $arg_debug);

run_all ('languages', [@test_cases, @file_tests], $arg_test_case,
   $arg_generate, $arg_debug);

1;


code:
$manual_tree = { 'cmdname' => 'multitable',
  'args' => [
        { 'type' => 'block_line_arg',
          'contents' => [
             { 'text' => ' ' },
             { 'type' => 'bracketed',
               'contents' => [
                               {'text' => 'aaaa'},
                            ]
             },
             { 'text' => ' ' },
             { 'type' => 'bracketed',
               'contents' => [
                               {'text' => 'xx'},
                               {'cmdname' => 'b',
                                'args' => [
                                            {
                                              'type' => 'brace_command_arg',
                                              'contents' => [
                                                            { 'text' => 'rr' }
                                                         ]
                                            }
                                          ]
                               }
                            ]
             },
             {'text' => " ccc\n"},
          ],
       } ],
  'extra' => { 'number_of_columns' => 3,
               'end_command' => {} },
  'contents' => [
           { 'type' => 'multitable_title',
             'contents' => [
                             { 'type' => 'paragraph',
                               'contents' => [
                                                { 'text' => "title" },
                                                { 'cmdname' => 'verb',
                                                  'args' => [ {
                                                               'contents' => [
                                                                  { 'text' => ' in verb } ',
                                                                    'type' => 'raw' }
                                                                ],
                                                                'type' => 'brace_command_arg',
                                                            } ],
                                                  'type' => ':'
                                                },
                                                { 'cmdname' => '@'},
                                                { 'text' => ".\n"},
                                             ]
                             }
                           ]
           },
           { 'cmdname' => 'item',
             'type' => 'multitable_row',
             'extra' => {'row_number' => 1},
             'contents' => [
                             {
                                'type' => 'multitable_cell',
                                'extra' => {'col_number' => 1,
                                            'row_number' => 1},
                                'contents' => [ {'text' => " \n" } ]
                              }
                           ]
           },
           { 'cmdname' => 'end',
             'extra' => {'command_argument' => 'multitable',
                         'text_arg' => 'multitable',
                         },
            'args' => [
                {
                  'contents' => [
                    {
                      'parent' => {},
                      'text' => ' ',
                      'type' => 'empty_spaces_after_command'
                    },
                    {
                      'parent' => {},
                      'text' => 'multitable'
                    },
                    {
                      'parent' => {},
                      'text' => '
',
                      'type' => 'spaces_at_end'
                    }
                  ],
                  'parent' => {},
                  'type' => 'misc_line_arg'
                }
              ],

           }
  ]

};

$manual_tree_result = '@multitable {aaaa} {xx@b{rr}} ccc
title@verb{: in verb } :}@@.
@item
@end multitable
';

1;


code:
use strict;

BEGIN {
  require Texinfo::ModulePath;
  Texinfo::ModulePath::init(undef, undef, 'updirs' => 2);
}

use Test::More;

BEGIN { plan tests => 8; }

use Texinfo::Convert::NodeNameNormalization qw(normalize_node transliterate_texinfo);
use Texinfo::Parser;
use Data::Dumper;

# Currently, tests check that NodeNameNormalization do not break with complete
# Texinfo trees, not that the output is correct.

my $srcdir = $ENV{'srcdir'};
if (defined($srcdir)) {
  $srcdir =~ s/\/*$/\//;
} else {
  $srcdir = '';
}

my $strings_textdomain = 'texinfo_document';
Locale::Messages->select_package ('gettext_pp');
Locale::Messages::bindtextdomain ('texinfo_document', 't/locales');

my $parser = Texinfo::Parser::parser({'TEST' => 1,
                                      'include_directories' => [
                                          't/include_dir/',
                                          't/include/',
                                          $srcdir.'t/include/'],
                                      'expanded_formats' => ['html', 'tex']});

my $invalid_line = '@noindent Text @titlefont{in titlefont} @anchor{in anchor}@footnote{footnote} @exdent exdent';

my $tree = $parser->parse_texi_text($invalid_line);
#print STDERR Data::Dumper->Dump([$tree]);
my $normalized_invalid = normalize_node($tree);
#print STDERR "Invalid: $normalized_invalid\n";

# misc commands are ignored, this implies @node and sectioning contents
# are ignored...
my $node_texi = '@node Top

in node

@top top section

in top section
';
my $node_tree = $parser->parse_texi_text($node_texi);
my $normalized_node = normalize_node($node_tree);
is ($normalized_node, '', 'node ignored');

# try on a full manual, but with node and sections commented out
# as they are ignored
my $texinfo_manual = '@setfilename toto.info

@definfoenclose some, ;, ;

@documentlanguage fr

@settitle test manual

@copying

Your rights
@sp 2
Here
@end copying

@paragraphindent 6

@c @node Top
@c @top top @~e

@insertcopying

@noindent
Para. @LaTeX{}, @sc{@AA{} bbb}. @image{unknown,,,}. @ref{index}
@anchor{anchor}. @abbr{ABR, expl}. @abbr{ABR}.
@~@@. @some{infoenclosed}. @today{}.

@cindex index

@html
in html
@end html

@multitable {a@TeX{}} {b}
@item gg @tab hhh
@end multitable

@example
in example
@vtable @emph
@item item

@itemx itemx
in vtable.
@end vtable

@deffn a b {c} d e f
in deffn
@end deffn

@exdent exdented

@end example

@flushright
right
@end flushright

@float Theor@`eme, label
in float

@math{a \frac{a}{b} @\ @minus{}}

@caption{in caption}
@end float

@menu
* index::
@end menu

@c @node index
@c @appendix appendix

@printindex cp

@heading list of floats

@listoffloats Theor@`eme

@bye
';

my $manual_tree = $parser->parse_texi_text($texinfo_manual);
my $check_texinfo = Texinfo::Convert::Texinfo::convert($manual_tree);
is ($texinfo_manual, $check_texinfo, 'check manual parsing');

#print STDERR Data::Dumper->Dump([$manual_tree]);
my $normalized_manual = normalize_node($manual_tree);
#print STDERR "Manual: $normalized_manual\n";

ok($normalized_manual =~ /^[\w\-]+$/, 'normalized tree is a valid id');

# Now test some node normalizations

my $texi_line = 'A @sc{sc} accents @"i @"{@dotless{i}} @`{@=E} @l{} @,{@\'C} @={@,{@~{n}}} @v{@\'{r}} @={@~{@dotless{i}}} @"y @dotless{i} @dotless{j} @,{C} @ogonek{E} @udotaccent{a} @tieaccent{a} @dotaccent{a} characters @l{} @exclamdown{} @aa{} @oe{} @comma{} @error{} @today{} @dots{} @enddots{} no brace commands @@ @: @. @	 @* @} signs  -- --- `` \'\' !_"#$%&\'()*+-. /;<=>?[\\]^_`|~';

my $line_tree = $parser->parse_texi_text($texi_line);
my $normalized_line = normalize_node($line_tree);
is ($normalized_line,
'A-SC-accents-_00ef-_00ef-_1e14-_0142-_1e08-_0146_0303_0304-_0155_030c-_0129_0304-_00ff-_0131-j-_00c7-_0118-_1ea1-a_0361-_0227-characters-_0142-_00a1-_00e5-_0153-_002c-error_002d_002d_003e--_2026-_002e_002e_002e-no-brace-commands-_0040--_002e-----_007d-signs-_002d_002d-_002d_002d_002d-_0060_0060-_0027_0027-_0021_005f_0022_0023_0024_0025_0026_0027_0028_0029_002a_002b_002d_002e-_002f_003b_003c_003d_003e_003f_005b_005c_005d_005e_005f_0060_007c_007e',
  'normalized complex line');
my $transliterated_line = transliterate_texinfo($line_tree);
is ($transliterated_line,
'A-SC-accents-i-i-E-l-C-n-r-i-y-i-j-C-E-a-a-a-characters-l-_00a1-aa-oe-_002c-error_002d_002d_003e--_2026-_002e_002e_002e-no-brace-commands-_0040--_002e-----_007d-signs-_002d_002d-_002d_002d_002d-_0060_0060-_0027_0027-_0021_005f_0022_0023_0024_0025_0026_0027_0028_0029_002a_002b_002d_002e-_002f_003b_003c_003d_003e_003f_005b_005c_005d_005e_005f_0060_007c_007e',
 'transliterated complex line');
my $transliterated_line_no_unidecode = transliterate_texinfo($line_tree, 1);
is ($transliterated_line_no_unidecode,
'A-SC-accents-i-i-_1e14-l-_1e08-n-r-i-y-_0131-j-C-E-a-a-a-characters-l-_00a1-aa-oe-_002c-error_002d_002d_003e--_2026-_002e_002e_002e-no-brace-commands-_0040--_002e-----_007d-signs-_002d_002d-_002d_002d_002d-_0060_0060-_0027_0027-_0021_005f_0022_0023_0024_0025_0026_0027_0028_0029_002a_002b_002d_002e-_002f_003b_003c_003d_003e_003f_005b_005c_005d_005e_005f_0060_007c_007e',
  'transliterated complex line no unidecode');

my $top_text = ' tOp';
my $top_tree = $parser->parse_texi_text($top_text);
my $top_normalized = normalize_node($top_tree);
is ($top_normalized, 'Top', 'normalize Top node');

my $top_and_spaces_text = 'TOP ';
my $top_and_spaces_tree = $parser->parse_texi_text($top_and_spaces_text);
my $top_and_spaces_normalized = normalize_node($top_and_spaces_tree);
is ($top_and_spaces_normalized, 'TOP-', 'normalize Top node followed by spaces');


code:
use strict;

use Test::More;
use File::Spec;
use File::Basename;

BEGIN {

plan tests => 119;

my ($real_command_name, $command_directory, $command_suffix)
  = fileparse($0, '.t');
my $updir = File::Spec->updir();
my $up = File::Spec->catdir($command_directory, $updir);
push @INC, $up;
if (!defined($ENV{'top_srcdir'})) {
  $ENV{'top_srcdir'} = File::Spec->catdir($up, $updir);
}
require Texinfo::ModulePath;
Texinfo::ModulePath::init();

}; # end BEGIN

use Texinfo::Convert::Paragraph;
use Texinfo::Convert::Line;
use Texinfo::Convert::UnFilled;

ok(1, "modules loading"); # If we made it this far, we're ok.

sub test_para($$$;$)
{
  my $args = shift;
  my $reference = shift;
  my $name = shift;
  my $conf = shift;

  my $result = '';
  #$conf = {'DEBUG' => 1} if (!defined($conf));
  $conf = {} if (!defined($conf));
  my $para = Texinfo::Convert::Paragraph->new($conf);
  foreach my $arg (@$args) {
    $result .= add_text($para, $arg);
  }
  $result .= Texinfo::Convert::Paragraph::end($para);
  if (defined($reference)) {
    is ($result, $reference, $name);
  } else {
    print STDERR "$result\n";
  }
}

test_para(['word'], "word\n", 'word');
test_para(['word other'], "word other\n", 'two_words');
test_para(['word  other'], "word other\n", 'two_words two spaces');
test_para(['word ', ' other'], "word other\n", 'two_words feed, space inside');
test_para(['word '], "word\n", 'trailing spaces');
test_para([' word'], "word\n", 'leading spaces');
test_para([' ', ' word'], "word\n", 'double leading spaces');
test_para(["word\n", "a"], "word a\n", 'trailing end of line and word');
test_para(['word', "\n", "a"], "word a\n", 'appended end of line and word');
test_para(['word other'], "word\nother\n", 'two_words_max', {'max' => 2});
test_para(['word other'], "word\nother\n", 'two_words_max_less_one', {'max' => 3});
test_para(['word other'], "word\nother\n", 'two_words_max_exact', {'max' => 4});
test_para(['word other'], "word\nother\n", 'two_words_max_plus_one', {'max' => 5});
test_para(['word other'], "word\nother\n", 'two_words_max_plus_two', {'max' => 6});
test_para(['word o'], "word\no\n", 'word_letter_max_exact', {'max' => 5});
test_para(['word o'], "word o\n", 'word_letter_max_plus_two', {'max' => 6});
test_para(['word  other'], "word other\n", 'two_words_two_spaces');
test_para(['word.  other'], "word.  other\n", 'two_words_dot');
#test_para(['word. other'], "word.  other\n", 'two_words_dot_one_space');
test_para(['word. other'], "word.  other\n", 'two_words_dot_one_space');
test_para(['word.) other'], "word.)  other\n", 'two_words_dot_paren_one_space');
test_para(['word.). other'], "word.).  other\n", 'two_words_dot_paren_dot');
test_para(['word.. other'], "word..  other\n", 'two_words_dot_dot');
test_para(['worD.  other'], "worD. other\n", 'two_words_dot_upper');
test_para(['worD.)  other'], "worD.) other\n", 'two_words_dot_paren_upper');
test_para(['worD).  other'], "worD). other\n", 'two_words_paren_dot_upper');
test_para(["word.\n", "\n", "\n", 'other',], "word.  other\n", 'three_newlines');
test_para(['word','other'], "wordother\n", 'concatenate');
test_para(['word.', ' A'], "word.  A\n", 'punctuation_at_end_fragment');
test_para(['word','other'], "wordother\n", 'concatenate_max', {'max' => 2});
test_para(['word ','other'], "word\nother\n", 'two_elements_max', {'max' => 2});
test_para(['word',' other'], "word\nother\n", 'two_elements_space_max', {'max' => 2});
test_para(["\x{7b2c}\x{4e00} ",'other'], "\x{7b2c}\n\x{4e00}\nother\n", 'east_asian', {'max' => 2});
test_para(['word.  other'], "word. other\n", 'two_words_dot_frenchspacing', {'frenchspacing' => 1});
test_para(["aa.)\x{7b2c} b"], "aa.)\x{7b2c} b\n", 'end_sentence_east_asian');
test_para(["aaaa bbbbbbb cccccccc dddddddddddd eeeeeeeeeeee fffffffff ggggggg"],
"   aaaa
 bbbbbbb
 cccccccc
 dddddddddddd
 eeeeeeeeeeee
 fffffffff
 ggggggg
",
   'indent_indent_next', {'max' => 6, 'indent_length' => 3, 'indent_length_next' => 1});
test_para(["aaaa bbbbbbb cccccccc dddddddddddd eeeeeeeeeeee fffffffff ggggggg"],
"    aaaa
bbbbbbb
cccccccc
dddddddddddd
eeeeeeeeeeee
fffffffff
ggggggg
",
   'indent_no_indent_next', {'max' => 12, 'indent_length' => 4, 'indent_length_next' => 0});
test_para(["aaaa bbbbbbb cccccccc dddddddddddd eeeeeeeeeeee fffffffff ggggggg"],
"    aaaa
    bbbbbbb
    cccccccc
    dddddddddddd
    eeeeeeeeeeee
    fffffffff
    ggggggg
",
   'indent_undef_indent_next', {'max' => 12, 'indent_length' => 4});
test_para(["aaaa bbbbbbb cccccccc dddddddddddd eeeeeeeeeeee fffffffff ggggggg"],
"aaaa bbbbbbb
   cccccccc
   dddddddddddd
   eeeeeeeeeeee
   fffffffff
   ggggggg
",
   'indent_next_no_indent', {'max' => 12, 'indent_length' => 0, 'indent_length_next' => 3});
test_para(["aaaa bbbbbbb cccccccc dddddddddddd eeeeeeeeeeee fffffffff ggggggg"],
"aaaa bbbbbbb
   cccccccc
   dddddddddddd
   eeeeeeeeeeee
   fffffffff
   ggggggg
",
   'indent_next_undef_indent', {'max' => 12, 'indent_length_next' => 3});
test_para(["aaaa"], "  aaaa\n", 'indent_and_counter_lower',
  {'indent_length' => 8, 'counter' => 6});
test_para(["aaaa"], "aaaa\n", 'indent_zero_and_counter',
  {'indent_length' => 0, 'counter' => 6});
test_para(["aaaa"], "aaaa\n", 'indent_and_counter_higher',
  {'indent_length' => 3, 'counter' => 6});
test_para(["aaaa bbbbbbb cccccccc dddddddddddd"],
  "aaaa bbbbbbb\ncccccccc dddddddddddd\n",
  "counter_and_line", {'counter' => 60});

my $para = Texinfo::Convert::Paragraph->new();
my $result = '';
$result .= add_text($para, 'aa.)');
$result .= add_next($para, '_');
$result .= add_text($para, ' after');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "aa.)_  after\n", 'add char after end sentence parentheses');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, 'b ');
$result .= add_next($para, '_');
$result .= add_text($para, '.');
$result .= add_next($para, '_');
$result .= add_text($para, ' after');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "b _._  after\n", 'add char after end sentence');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_next($para, 'a');
$result .= add_next($para, "\n");
$result .= add_next($para, '_');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "a\n_\n", 'add_next: add char after separate end line');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_next($para, "a\n");
$result .= add_next($para, '_');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "a\n_\n", 'add_next: add char after end line');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, "A");
$result .= add_next($para, '_');
$result .= add_text($para, ".)");
$result .= add_text($para, " Next");
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "A_.)  Next\n", 'add_next: period after next, not transparent');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, "A");
$result .= add_next($para, '_', 1);
$result .= add_text($para, ".)");
$result .= add_text($para, " Next");
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "A_.) Next\n", 'add_next: period after next, transparent');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, "aa.\n");
$result .= set_space_protection($para, undef,undef,undef,1);
$result .= add_next($para, '_');
$result .= add_text($para, "b");
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "aa.  _b\n", 'add char after space protection end sentence space');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= set_space_protection($para, undef,undef,undef,1);
$result .= add_text($para, "b");
$result .= set_space_protection($para, undef,undef,undef,0);
$result .= add_text($para, ". after");
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "b.  after\n", 'punctuation after end space protection');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= set_space_protection($para, undef,undef,undef,1);
$result .= add_text($para, "b.");
$result .= set_space_protection($para, undef,undef,undef,0);
$result .= add_text($para, " follow");
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "b. follow\n", 'punctuation before end space protection');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= set_space_protection($para, undef,undef,undef,1);
$result .= add_text($para, "b.");
$result .= set_space_protection($para, undef,undef,undef,0);
$result .= add_text($para, "  follow");
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "b. follow\n", 'punctuation before end space protection 2 space');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= set_space_protection($para, undef,undef,undef,1);
$result .= add_text($para, "b. ");
$result .= set_space_protection($para, undef,undef,undef,0);
$result .= add_text($para, " follow");
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "b. follow\n", 'punctuation space before end space protection');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, "In w:\n");
$result .= set_space_protection($para, 1,1);
$result .= add_text($para, "Out of code -- out-of-code.   ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg");
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "In w: Out of code -- out-of-code.   ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg\n", 'space protection after end sentence');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, "In w:\n");
$result .= set_space_protection($para, 1,1);
$result .= add_text($para, "Out of code -- out-of-code.");
$result .= set_space_protection($para, undef,undef,undef,1);
$result .= add_text($para, "in code");
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "In w: Out of code -- out-of-code.in code\n", 'set frenchspacing after space protection');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, "a ");
$result .= add_next($para, '...', 1);
$result .= add_text($para, "c");
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "a ...c\n", 'add end sentence and text');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= end_line($para);
$result .= add_text($para, ' after');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "\nafter\n", 'space after end_line');
#print STDERR "$result";

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, 'aa.)');
$result .= add_pending_word($para);
is ($result, 'aa.)', 'call add_pending_word');
$result = end_line($para);
is ($result, "\n", 'call end_line after add_pending_word');
$result = Texinfo::Convert::Paragraph::end($para);
is ($result, '', 'call end after end_line');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, 'aa.)');
$result .= add_pending_word($para);
$result .= add_text($para, ' after');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "aa.)  after\n", 'space after sentence and add_pending_word');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, 'aA');
$result .= add_next($para, '.');
add_end_sentence($para, 1);
$result .= add_text($para, ' after');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "aA.  after\n", 'force end sentence after upper case');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, 'aa');
$result .= add_next($para, '.');
add_end_sentence($para, 1);
$result .= add_text($para, 'b c');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "aa.b c\n", 'force end sentence followed by text');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, 'aA');
$result .= add_text($para, '.');
$result .= add_text($para, ' after');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "aA. after\n", 'end sentence after upper case');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, 'aa.)');
$result .= add_text($para, '))');
$result .= add_text($para, ' after');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "aa.)))  after\n", 'continue with after_punctuation_characters');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, 'aa.)');
remove_end_sentence($para, );
$result .= add_text($para, ' after');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "aa.) after\n", 'inhibit end sentence');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, 'aa.)');
remove_end_sentence($para, );
$result .= add_next($para, '_');
$result .= add_text($para, ' after');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "aa.)_ after\n", 'inhibit end sentence then add next');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, 'aa.)');
remove_end_sentence($para, );
$result .= add_text($para, 'aa.)');
$result .= add_text($para, ' after');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "aa.)aa.)  after\n", 'cancel inhibit end sentence');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, 'aa.)');
remove_end_sentence($para, );
$result .= add_text($para, '))');
$result .= add_text($para, ' after');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "aa.))) after\n", 'inhibit end sentence and ))');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
set_space_protection($para, undef,1,1);
$result .= add_text($para, '  aa.) bb.');
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result,"aa.)  bb.\n", 'leading spaces ignore columns and keep spaces');

$para = Texinfo::Convert::Paragraph->new({'max' => 2});
$result = '';
set_space_protection($para, 1,1);
$result .= add_text($para, 'aa.)    bb ');
$result = add_text($para, ' eee ');
$result .= add_text($para, '   .)');
$result .= add_next($para, '_');
$result .= add_text($para, "\n");
$result .= add_text($para, "aa\n");
$result .= add_text($para, ' . gg');
$result .= add_text($para, ". \n");
$result .= add_text($para, "a");
$result .= add_text($para, '  ');
$result .= set_space_protection($para, 0,0);
$result .= add_text($para, "c ");
is ($result, "aa.)    bb  eee    .)_ aa  . gg.  a  c\n", "protected spaces many inputs");
Texinfo::Convert::Paragraph::end($para);

$para = Texinfo::Convert::Paragraph->new({'max' => 10});
$result = '';
$result .= add_next($para, "AAAAAAA");
$result .= add_text($para, "GGG GGG");
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "AAAAAAAGGG\nGGG\n", 'line split check');

$para = Texinfo::Convert::Paragraph->new({'max' => 10});
$result = '';
$result .= add_next($para, "AAAAAAA\n");
$result .= add_text($para, "GGG GGG");
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "AAAAAAA\nGGG GGG\n", 'end line reset counter');

$para = Texinfo::Convert::Paragraph->new({'indent_length' => 3});
$result = '';
$result .= set_space_protection($para, 1,1);
$result .= add_text($para, " a\n");
$result .= set_space_protection($para, 0,0);
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "    a \n", 'end space protection by end line');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= set_space_protection($para, 1,1);
$result .= add_text($para, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbb bbbbb bbb b b b b b b b b b bb .\n");
$result .= add_text($para,  "ccc dddd");
$result .= set_space_protection($para, 0,0);
$result .= add_text($para,  "gg.\n");
$result .= Texinfo::Convert::Paragraph::end($para);
is ($result, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbb bbbbb bbb b b b b b b b b b bb . ccc ddddgg.\n", 'long text followed by text protected');

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result .= add_text($para, 'aa');
$result .= set_space_protection($para, 1,1);
$result .= add_text($para, '  f  f');
$result .= set_space_protection($para, 0,0);
$result .= add_text($para, "ggg\n");
is ($result, 'aa  f  fggg', 'protected space within words');
Texinfo::Convert::Paragraph::end($para);

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result = add_text($para, 'aa');
$result .= set_space_protection($para, 1,1);
$result .= add_text($para, '  f  f ');
$result .= set_space_protection($para, 0,0);
$result .= add_text($para, "ggg\n");
is ($result, 'aa  f  f ggg', 'protected space and space within words');
Texinfo::Convert::Paragraph::end($para);

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result = add_text($para, 'aa ');
$result .= set_space_protection($para, 1,1);
$result .= add_text($para, '  f  f ');
$result .= set_space_protection($para, 0,0);
$result .= add_text($para, "ggg\n");
is ($result, 'aa   f  f ggg', 'text space protected space and space within words');
Texinfo::Convert::Paragraph::end($para);

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result = add_text($para, 'aa ');
$result .= set_space_protection($para, 1,1);
$result .= add_text($para, '  f  f ');
$result .= set_space_protection($para, 0,0);
$result .= add_text($para, " ggg\n");
is ($result, 'aa   f  f  ggg', 'text space protected space and space after');
Texinfo::Convert::Paragraph::end($para);

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result = add_text($para, 'aa ');
$result .= set_space_protection($para, 1,1);
$result .= set_space_protection($para, 0,0);
$result .= add_text($para, " ggg\n");
is ($result, 'aa  ggg', 'empty protected 2 space');
Texinfo::Convert::Paragraph::end($para);

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result = add_text($para, 'aa ');
$result .= set_space_protection($para, 1,1);
set_space_protection($para, 0,0);
$result .= add_text($para, "ggg\n");
is ($result, 'aa ggg', 'empty protected 1 before space');
Texinfo::Convert::Paragraph::end($para);

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result = add_text($para, 'aa');
$result .= set_space_protection($para, 1,1);
$result .= set_space_protection($para, 0,0);
$result .= add_text($para, " ggg\n");
is ($result, 'aa ggg', 'empty protected 1 after space');
Texinfo::Convert::Paragraph::end($para);

$para = Texinfo::Convert::Paragraph->new();
$result = '';
$result = add_text($para, 'aa ');
$result .= set_space_protection($para, 1,1);
$result .= add_text($para, ' ');
$result .= set_space_protection($para, 0,0);
$result .= add_text($para, " ggg\n");
is ($result, 'aa   ggg', 'space protected space');
Texinfo::Convert::Paragraph::end($para);

sub test_line($$$;$)
{
  my $args = shift;
  my $reference = shift;
  my $name = shift;
  my $conf = shift;

  my $result = '';
  #$conf = {'DEBUG' => 1} if (!defined($conf));
  $conf = {} if (!defined($conf));
  my $line = Texinfo::Convert::Line->new($conf);
  foreach my $arg (@$args) {
    $result .= add_text($line, $arg);
  }
  $result .= Texinfo::Convert::Paragraph::end($line);
  is ($result, $reference, "line $name");
  #print STDERR "$result\n";
}

test_line(["word\n"], "word\n", 'word');
test_line(['word other'], "word other", 'two_words');
test_line(['word '], 'word ', 'trailing spaces');
test_line(["word \n"], "word\n", 'trailing spaces eol');
test_line([' word'], "word", 'leading spaces');
test_line([' ', ' word'], "word", 'double leading spaces');
test_line(['word  other'], "word other", 'two_words_two_spaces');
test_line(['word.  other'], "word.  other", 'two_words_dot');
test_line(['word. other'], "word.  other", 'two_words_dot_one_space');
test_line(['word.) other'], "word.)  other", 'two_words_dot_paren_one_space');
test_line(['worD.  other'], "worD. other", 'two_words_dot_upper');
test_line(['word','other',"\n"], "wordother\n", 'concatenate');
test_line(["\x{7b2c}\x{4e00} ","other \n"], "\x{7b2c}\x{4e00} other\n", 'east_asian');
test_line(['word.  other'], "word. other", 'two_words_dot_frenchspacing', {'frenchspacing' => 1});
test_line(["aa.)\x{7b2c} b"], "aa.)\x{7b2c} b", 'end_sentence_east_asian');

my $line = Texinfo::Convert::Line->new();
$result = '';
$result .= add_text($line, 'aa.)');
$result .= add_next($line, '_');
$result .= add_text($line, ' after');
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "aa.)_  after", 'line add char after end sentence');

$para = Texinfo::Convert::Line->new();
$result = '';
$result .= end_line($line);
$result .= add_text($line, ' after');
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "\nafter", 'line space after end_line');
#print STDERR "$result";

$line = Texinfo::Convert::Line->new();
$result = '';
$result .= add_text($line, "A");
$result .= add_next($line, '_', 1);
$result .= add_text($line, ".)");
$result .= add_text($line, " Next");
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "A_.) Next", 'line add_next: period after next, transparent');

$line = Texinfo::Convert::Line->new();
$result = '';
$result .= add_text($line, 'aa.)');
$result .= add_pending_word($line);
is ($result, 'aa.)', 'line call add_pending_word');
$result = end_line($line);
is ($result, "\n", 'line call end_line after add_pending_word');
$result = Texinfo::Convert::Paragraph::end($line);
is ($result, "", 'line call end after end_line');

$para = Texinfo::Convert::Line->new();
$result = '';
$result .= add_text($line, 'aa.)');
$result .= add_pending_word($line);
$result .= add_text($line, ' after');
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "aa.)  after", 'line space after sentence and add_pending_word');

$para = Texinfo::Convert::Line->new();
$result = '';
$result .= add_text($line, 'aA');
$result .= add_next($line, '.');
add_end_sentence($line, 1);
$result .= add_text($line, ' after');
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "aA.  after", 'line force end sentence after upper case');

$line = Texinfo::Convert::Line->new();
$result = '';
$result .= add_text($line, 'aA');
$result .= add_text($line, '.');
$result .= add_text($line, ' after');
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "aA. after", 'line end sentence after upper case');

$line = Texinfo::Convert::Line->new();
$result = '';
$result .= add_text($line, 'aa.)');
$result .= add_text($line, '))');
$result .= add_text($line, ' after');
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "aa.)))  after", 'line continue with after_punctuation_characters');

$line = Texinfo::Convert::Line->new();
$result = '';
$result .= add_text($line, 'aa.)');
remove_end_sentence($line, );
$result .= add_text($line, ' after');
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "aa.) after", 'line inhibit end sentence');

$line = Texinfo::Convert::Line->new();
$result = '';
$result .= add_text($line, 'aa.)');
remove_end_sentence($line, );
$result .= add_next($line, '_');
$result .= add_text($line, ' after');
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "aa.)_ after", 'line inhibit end sentence then add next');

$line = Texinfo::Convert::Line->new();
$result = '';
$result .= add_text($line, 'aa.)');
remove_end_sentence($line, );
$result .= add_text($line, 'aa.)');
$result .= add_text($line, ' after');
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "aa.)aa.)  after", 'line cancel inhibit end sentence');

$line = Texinfo::Convert::Line->new();
$result = '';
$result .= add_text($line, 'aa.)');
remove_end_sentence($line, );
$result .= add_text($line, '))');
$result .= add_text($line, ' after');
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "aa.))) after", 'line inhibit end sentence and ))');

$line = Texinfo::Convert::Line->new();
$result = '';
set_space_protection($line, 1,1);
$result .= add_text($line, ' aa.)');
$result .= add_text($line, ' ');
$result .= add_text($line, 'then');
$result .= add_text($line, 'fff     g');
set_space_protection($line, 0,0);
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, " aa.) thenfff     g", 'line space_protection and spaces');

$line = Texinfo::Convert::Line->new();
$result = '';
$result .= add_text($line, "aa. ");
$result .= set_space_protection($line, undef,undef,undef,1);
$result .= add_next($line, '_');
$result .= add_text($line, "b");
$result .= set_space_protection($line, undef,undef,undef,0);
$result .= add_text($line, ". after");
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "aa.  _b.  after", 'line add char after space protection end sentence space');

$line = Texinfo::Convert::Line->new();
$result = '';
$result .= set_space_protection($line, undef,undef,undef,1);
$result .= add_text($line, "b.");
$result .= set_space_protection($line, undef,undef,undef,0);
$result .= add_text($line, "  follow");
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "b. follow", 'line punctuation before end space protection 2 space');

$line = Texinfo::Convert::Line->new();
$result = '';
$result .= set_space_protection($line, 1,1);
$result .= add_text($line, "protected. B");
$result .= set_space_protection($line, 0,0);
$result .= add_text($line, "  after");
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "protected. B after", 'line 2 spaces after end space protection');

$line = Texinfo::Convert::Line->new();
$result = '';
$result .= set_space_protection($line, 1,1);
$result .= add_text($line, "protected");
$result .= set_space_protection($line, 0,0);
$result .= add_text($line, "  after");
$result .= Texinfo::Convert::Paragraph::end($line);
is ($result, "protected after", 'line 2 spaces after end space protection with dot');

1;


code:
# $Id$
use strict;

use File::Spec;
BEGIN { if (defined($ENV{'top_srcdir'})) {unshift @INC, File::Spec->catdir($ENV{'top_srcdir'}, 'tp');} }

require 't/test_utils.pl';

my @test_cases = (
['settitle_and_empty_top',
'@settitle Title

@top

'],
['anchor_and_empty_lines',
'text 1.

@anchor{in anchor}

text 2.
'],
['long_line',
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBB

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaa BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBb
1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBB
2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBB
3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBB
4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBB
5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBB
6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBB
7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBB
8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBB
9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBB
10AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBB
11AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBB
'],
['commands_and_punctuation',
'SomthingA@.   and now inhibit.@: Now dots @dots{} and enddots @enddots{} and'],
['inhibit_punctuation',
'foo vs.@: bar.
colon :@:And something else.
semi colon ;@:.
And ? ?@:. ?@:
Now ! !@:@@ !@:
but , ,@:
'],
['punctuation_in_sc', 'one @sc{two.} three @sc{FOUR.} five'],
['accent_command_punctuation',
'@dotaccent{e} after'],
['empty_line_in_example_end',
'@example
in example

@end example

After line
'],
['protected_space_end_line',
'First para

This is a very simple texi manual followed by tab a <>.
followed by @ @ newline.

This is a very simple texi manual followed by tab a <>.
followed @ @ @ newline.

This is a very simple texi manual followed by tab a <>. @ @ @ @ @ @ @ @ @ @
text.
'],
['end_sentence_space_protected',
'Some text. @
Next sentence.
'],
['protect_spaces_on_line',
'
Before samp. @samp{a}. after samp, w @w{in   w. after dot}  afterw

@quotation
@exdent before samp. @samp{a}. after samp, w @w{in   w. after dot}  afterw
@end quotation
'],
['html_expanded',
'Before
@html
html
@end html
after.
',{'expanded_formats' => ['html']}, {'expanded_formats' => ['html']}
],
['isolated_html_expanded',
'
@html
html
@end html
',{'expanded_formats' => ['html']}, {'expanded_formats' => ['html']}
],
['star_at_command_formatting',
'@macro mymacro
Some text @*
more text. @
Even more text. @* not at eol.

Now followed by @@ : followed@*@
And now followed by a space and @@ : follow @* @
And now followed by a space and @@ and text: follow @* @ text
Followed by empty asis and a space @asis{}
Followed by asis with space and a space @asis{ }
And now with * empty @@asis: @*@asis{}
And now with * asis with space @@asis: @* @asis{ }
And end para.
@end macro

@mymacro{}

@example
Example
@mymacro{}
@end example

@quotation
Quotation
@mymacro{}
@end quotation

'],
['line_passed_and_formats',
'@node Top

@quotation special
Quotation special.
@quotation
Nested quotation sdflkmsfdlkmfsdqmlkfsdq mlfdsqlkmfdsqmlkfdsq klm fsqdlkmfdsq
fdsfsdqmlkfsqd m lqlkmf qskmlfq sklm fqds
@end quotation
@end quotation

@quotation
quotation  text
@example
example in   quotation
@end example
@end quotation

@example
 In  example.
@quotation
   In quotation   in example
@end quotation
@end example

@example
In 1 example
@end example
@example
In 2 example
@end example

@quotation
In 1 quotation
@end quotation
@quotation
In 2 quotation
@end quotation

@quotation
Quotation
@quotation
Nested quotation
@end quotation
Quotation 2
@end quotation

@example
In  example.
@quotation
In quotation   in example
@end quotation
In  example 2.
@end example

@quotation
quotation  text
@example
example in   quotation
@end example
quotation  text 2
@end quotation

Before quotation
@quotation
quotation  text
@end quotation
after end

Before example
@example
In example
@end example
After example

Before quotation and empty line
@quotation

In quotation

@end quotation
After quotation

Before example and empty line
@example

In example

@end example
After example

Nested and empty lines

Quotation empty out, spaces inside
@quotation

@quotation

In nested

@end quotation

@end quotation

Quotation empty out, no spaces inside
@quotation

@quotation
In nested
@end quotation

@end quotation

Example empty out, spaces inside
@example

@example

In nested

@end example

@end example

Example empty out, no spaces inside
@example

@example
In nested
@end example

@end example

menu
@menu
* (manual)node::
@end menu
end menu
'],
['nested_indentedblock',
'@example
in example
@indentedblock
   f  f  f``g
@end indentedblock
@end example

@indentedblock
   v  v  v``a
@example
in example
@end example
@end indentedblock
'],
['multitable',
'@multitable {truc}    {bidule}
@item truc @tab bidule
@item   truc2     @tab bidule2
@end multitable

@multitable {t}    {b}
@item AAAAAAAAAAAA @tab BBBBBBBBBBBBBBB
@item A @tab B
@item AA @tab BB
@item AAA @tab BBB
@item AAAA @tab BBBB
@item 1 1 @tab 1 2B
@item 1 3BB @tab 1 4BBB
@item 2A 1 @tab AA AA
@item 2A 3BB @tab 2A 4BBB
@item 3AA 1 @tab 3AA 2B
@item 3AA 3BB @tab 3AA 4BBB
@item 4AAA 1 @tab 4AAA 2B
@item 4AAA 3BB @tab 4AAA 4BBB
@headitem he @tab th
@end multitable

@multitable {AA} {BB}
@item a b @tab AA BB
@item aa b @tab AA B
@item aaa b @tab A BB
@end multitable

@multitable {A}
@item A
B
@item a b
@end multitable

@multitable {A} {B}
@item U
V
@tab u
v
@item a b
@tab A B
@end multitable
'],
['nested_multitable',
'
@multitable {truc AAAA @  machin}    {bidule}
@item
@multitable {AAAA} {machin}
@item AAAA @tab machin
@end multitable
 @tab bidule
@item other item @tab in tab
@end multitable
'],
['empty_multitable_in_itemize',
'@itemize a--n itemize line
@item in macro

@multitable
@end multitable

@end itemize
'],
['long_uref_after_item',
'@itemize
@item
@uref{http://foo.org/some/long/url/which/goes/past/eighty/columns/and/has/no/alternative/text.html}
@end itemize
'],
['before_accent_punctuation',
'a. @^a'],
['invalid_accent_punctuation',
'a. @^@@'],
['punctuation_in_command',
'
Text. Email @email{a. b,a. b} dmn @dmn{1. 2} and text. indicateurl @indicateurl{i. u} and then kbd @kbd{k. d} and math @math{m. a} and cite @cite{c. e} and emph @emph{e. h} text.
asis in code @code{@asis{a. c}}
'],
['punctuation_at_end_command',
'
Text. Email @email{.,.} dmn @dmn{1.} and text. indicateurl @indicateurl{.} and
then kbd @kbd{.} and math @math{.} and cite @cite{.} and emph @emph{.} text.
asis in code @code{@asis{.}} text. a dot before a emph open .@emph{ and in emph.}
'],
['punctuation_in_command_end_line',
'Text. Email @email{.,.}
dmn @dmn{1.}
and text. indicateurl @indicateurl{.}
and then kbd @kbd{.}
and math @math{.}
and cite @cite{.}
and emph @emph{.}
text. asis in code @code{@asis{.}}
text. a dot before a emph open .@emph{
and in emph.}
'],
['after_punctuation_character_in_command',
'Text.@asis{)
follows}.
'],
['sc_with_utf8_enable_encoding',
'@documentencoding utf-8
@sc{in sc}.
'],
['U_with_utf8_enable_encoding',
'@documentencoding utf-8
@U{00FF} (should be a real y-dieresis in UTF-8).
'],
['flushright_not_closed_and_format',
'@flushright
flushright

@quotation
A quot---ation
@end quotation
'],
['punctuation_abbr_acronym',
'@abbr{AAA}. @acronym{BBB}. @abbr{aaa}. @acronym{bbb}. Next.
@abbr{AAA, expL}. @acronym{BBB, explA}. @abbr{aaa, expl}.
@acronym{bbb, expla}. Last.
'],
['punctuation_and_upper_case_commands',
'
@var{aaa}. @var{@~e}. @var{@aa{}}.
@var{AAA}. @var{@~E}. @var{@AA{}}.
@var{double AAA}.  @var{double @~E}. @var{double @AA{}}.  End.

@sc{aaa}. @sc{@~e}. @sc{@aa{}}.
@sc{AAA}. @sc{@~E}. @sc{@AA{}}.
@sc{double AAA}.  @sc{double @~E}. @sc{double @AA{}}.  End.
'],
['punctuation_and_upper_case_commands_utf8',
'@documentencoding utf-8
@var{aaa}. @var{@~e}. @var{@aa{}}.
@var{AAA}. @var{@~E}. @var{@AA{}}.
@var{double AAA}.  @var{double @~E}. @var{double @AA{}}.  End.

@sc{aaa}. @sc{@~e}. @sc{@aa{}}.
@sc{AAA}. @sc{@~E}. @sc{@AA{}}.
@sc{double AAA}.  @sc{double @~E}. @sc{double @AA{}}.  End.
'],
['punctuation_and_code_style_commands',
'@command{aaa}. @code{@~e}. @samp{@aa{}}.
@command{AAA}. @code{@~E}. @samp{@AA{}}.
@command{double AAA}.  @code{double @~E}. @samp{double @AA{}}.  End.
'],
['punctuation_and_code_style_commands_utf8',
'@documentencoding utf-8
@command{aaa}. @code{@~e}. @samp{@aa{}}.
@command{AAA}. @code{@~E}. @samp{@AA{}}.
@command{double AAA}.  @code{double @~E}. @samp{double @AA{}}.  End.
'],
['characters_and_commands_in_var',
'@var{aaa}. @var{dlksfjf ) }. @var{(fdfdsfsd}. @var{sqdq,qdsdsq}.

@var{somethingf  @c ]
vvar}.

@var{AA@,c @u{r} @`e @aa{}}.

AAA@footnote{jdhfmqsdf
dsf
ds @var{rrrr , azeeaz}
end footnote}
'],
['transparent_text',
'AA@footnote{in footnote}). B (@emph{C}). D.
'],
['accents_in_var_enable_encoding',
'@documentencoding utf-8

@var{AA@,c @u{r} @`e}.
'],
['command_brace_no_arg_punctuation',
'@TeX{}. And @LaTeX{}. @copyright{}. @registeredsymbol{}. End.
'],
['code_commands_and_punctuation',
'@code{AA}. @samp{aa}. After.
'],
['sp_with_text_before_in_example',
'
@example
sp@sp 4
text
@end example
'],
['expanded_tex',
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
@tex
TTT
GGG
HHH
@end tex
bbbbbbbbb1 bbbbbbbbbbb2 bbbbbbbbbb3 bbbbbbbbbbbbbb4.
', {'expanded_formats' => ['tex']}, {'expanded_formats' => ['tex']}
],
['paragraphindent',
'First

           aaa b default

@paragraphindent asis

           aaa b asis

@paragraphindent 0

           aaa b 0

@paragraphindent 7

           aaa b 7
'],
['no_empty_line_after_section',
'Text
@top top
Other text

@chapter chap
@c comment

Para
@comment c
@section sec
@uref{url} A.

@sp 3
@section after sp
@indent
Para indented.

'],
['nested_code_commands',
'@code{aA @kbd{fg}}.
@code{cc @code{gg}}.
@command{in command @kbd{fg}}
@code{in code @command{in command}}
@samp{in samp @code{in code}}
@code{in code @samp{in samp}}
@var{in var @code{in code}}
@code{in code @var{in var}}

@example
@code{in code}
@code{aA @kbd{fg}}
@kbd{hh}
@command{in command @kbd{fg}}
@code{in code @command{in command}}
@samp{in samp @code{in code}}
@code{in code @samp{in samp}}
@var{in var @code{in code}}
@code{in code @var{in var}}
@end example

@display
@kbd{in disp}
@code{aA @kbd{fg}}
@command{in command @kbd{fg}}
@code{in code @command{in command}}
@samp{in samp @code{in code}}
@code{in code @samp{in samp}}
@var{in var @code{in code}}
@code{in code @var{in var}}
@end display
'],
['multiline_verb_after_space',
'AA @verb{*aa
bb*}.
'],
['multitable_in_example_extraneous_tab',
'@example
@multitable a
@item ita @tab tmp
@item secit @tab
@end multitable
@end example
'],
['itemize_in_headitem_in_example',
'@example
@itemize
@headitem a
@end itemize

@itemize
@item bbb
@headitem ccc
@end itemize

@itemize
@headitem ddd
@item eee
@end itemize

@itemize
@item fff
@headitem ggg
@item hhh
@end itemize

@end example
'],
['tab_in_table_in_example',
'@example
@table @code
@tab in tab
@item table item
T
@tab other tab
@end table
@end example
'],
['tab_item_in_example',
'@example
@tab in tab
@item in item
@end example
'],
['lone_braces_in_inlineraw',
'@inlineraw{plaintext, {truc}}.
'],
# if this test is modified, the corresponding test in t/info_tests.t should
# be changed too
['multiline_image_and_align',
'@center @image{figure}

@center CCCC @image{figure}

@center fffffffffffffffffffffffffffffffffffffff @image{figure}

@center dddd @image{figure} iiiii

@flushright
AAA
@image{figure}

BBB @image{figure} gggg @image{figure}

HHH
@image{figure} JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
@end flushright
'],
);

my $insert_copying_and_paragraph =
'@copying
In copying.
@end copying

Insertcopying
@insertcopying
';

push @test_cases, ['insert_copying_and_paragraph',
                    $insert_copying_and_paragraph];
push @test_cases, ['insert_copying_inline_and_paragraph',
                    $insert_copying_and_paragraph,
                    {'INLINE_INSERTCOPYING' => 1}];

my $at_commands_glued_text = 'at@@.
TeX@TeX{}TeX.
code@code{in code}code.
acronym@acronym{ABC, aaa bb cc}acronym.
acronym2@acronym{ABC}acronym.
email@email{somebody, mali}email.
ref@ref{Top}ref.
Foornote@footnote{in footnote}after footnote.
accent@^{@dotless{i}}accent.
and star@*star.
noindent@noindent after noindent
sp@sp 4
anchor@anchor{anchor}anchor
index@cindex index
';

my @at_commands_glued_tests = (
['at_commands_glued_in_paragraph',
$at_commands_glued_text
],
['at_commands_glued_in_example',
'@example'."\n".$at_commands_glued_text.'@end example'."\n"],
);

push @test_cases, @at_commands_glued_tests;

my $punctuation_text = '
Dot. Exclam! Question? Dot.  Exclam!  Question?  GAAA.

End of lines Dot.
Exclam!
Question?
End.

End of lines and spaces
Dot.
Exclam!
Question?
End.

With paren.) paren.)  Symb.)"\'] Symb.)"\']  End.

End of lines paren.)
Symb.)"\']
End.

End of lines and spaces paren.)
Symb.)"\']
End.
';

push @test_cases, (
['punctuation',
$punctuation_text
],
['punctuation_frenchspacing',
'@frenchspacing on'."\n".$punctuation_text],
);

my $punctuation_commands_text = '
Dot@. Exclam@! Question@? Dot@.  Exclam@!  Question@?  GAAA.

Enddots@enddots{} Enddots@enddots{}  GBBB.

End of lines Dot@.
Exclam@!
Question@?
Enddots@enddots{}
End.

End of lines and spaces
Dot@.
Exclam@!
Question@?
Enddots@enddots{}
End.

With paren@.) paren@.)  Symb@.)"\'] Symb@.)"\']  End.

End of lines paren@.)
Symb@.)"\']
End.

End of lines and spaces paren@.)
Symb@.)"\']
End.
';

push @test_cases, (
['punctuation_commands',
$punctuation_commands_text
],
['punctuation_commands_frenchspacing',
'@frenchspacing on'."\n".$punctuation_commands_text],
);

my $no_punctuation_commands_text = '
Dot.@: Exclam!@: Question?@: Dot.@:  Exclam!@:  Question?@:  GAAA.

End of lines Dot.@:
Exclam!@:
Question?@:
End.

End of lines and spaces
Dot.@:
Exclam!@:
Question?@:
End.

With paren.@:) paren.@:)  Symb.@:)"\'] Symb.@:)"\']  End.

End of lines paren.@:)
Symb.@:)"\']
End.

End of lines and spaces paren.@:)
Symb.@:)"\']
End.
';

push @test_cases, (
['no_punctuation_commands',
$no_punctuation_commands_text
],
['no_punctuation_commands_frenchspacing',
'@frenchspacing on'."\n".$no_punctuation_commands_text],
);

my $punctuation_and_footnotes_text = '
Text.@footnote{after period} Sentence
end.@footnote{after period double}  S2.@footnote{after period triple}   S3.

No PERIOD.@footnote{no period} worD.@footnote{no period double}  w2
wW.@footnote{no period triple}   S3.

Force PERIOD@.@footnote{after forced period} Sentence
W@.@footnote{after forced period double}  S2
W@.@footnote{after forced period triple}   S3.

Force no period.@:@footnote{after forced no period} Sentence
w.@:@footnote{after forced no period double}  S2
w.@:@footnote{after forced no period triple}   S3.
';

push @test_cases, (
['punctuation_and_footnotes',
$punctuation_and_footnotes_text
],
['punctuation_and_footnotes_frenchspacing',
'@frenchspacing on'."\n".$punctuation_and_footnotes_text],
);

my @deep_recursion_tests = (
# more than 100 calls -> perl gives an error message, so those tests are
# disabled for now.
['deep_recursion_in_formats',
'
@enumerate
@item
@example
@example
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@itemize truc
@item
@table @asis
@item t
@smallexample
@enumerate
@item

@end enumerate
@end smallexample
@end table
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end itemize
@end example
@end example
@end enumerate
'],
['deep_recursion_in_brace_commands',
'@code{@samp{@code{@sc{@b{@var{@code{@samp{@code{@sc{@b{@var{
@code{@samp{@code{@sc{@b{@var{@code{@samp{@code{@sc{@b{@var{
@code{@samp{@code{@sc{@b{@var{@code{@samp{@code{@sc{@b{@var{
@code{@samp{@code{@sc{@b{@var{@code{@samp{@code{@sc{@b{@var{
@code{@samp{@code{@sc{@b{@var{@code{@samp{@code{@sc{@b{@var{
}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
'],
);

my @file_tests = (
['japanese_utf8',
undef, {'test_file' => 'japanese_utf8.texi'}
],
['chinese_mixed_with_en',
undef, {'test_file' => 'chinese_mixed_with_en.texi'}
],
['non_break_spaces',
undef, {'test_file' => 'non_break_spaces.texi'}
],
['all_spaces',
undef, {'test_file' => 'all_spaces.texi',
        'todo' => {'file_plaintext' =>
                          'NEL handled differently between perl versions'}}
],
['east_asian_in_w',
undef, {'test_file' => 'east_asian_in_w.texi'}
],
['quote_node_names',
undef, {'test_file' => 'nodequote.texi',},
{'INFO_SPECIAL_CHARS_QUOTE' => 1,
 'INFO_SPECIAL_CHARS_WARNING' => 0,}
],
);

foreach my $test (@test_cases) {
  $test->[2]->{'test_formats'} = ['plaintext'];
}

foreach my $test (@file_tests) {
  $test->[2]->{'test_formats'} = ['file_plaintext'];
}

our ($arg_test_case, $arg_generate, $arg_debug);

run_all ('plaintext_tests', [@test_cases, @file_tests], $arg_test_case,
   $arg_generate, $arg_debug);

1;


code:
use strict;

BEGIN {
  require Texinfo::ModulePath;
  Texinfo::ModulePath::init(undef, undef, 'updirs' => 2);
}

use Test::More;

BEGIN { plan tests => 4; }

use Texinfo::Parser qw(parse_texi_text);
use Texinfo::Common qw(protect_comma_in_tree protect_colon_in_tree
      protect_node_after_label_in_tree);
use Texinfo::Convert::Texinfo;

ok(1);

sub run_test($$$$)
{
  my $do = shift;
  my $in = shift;
  my $out = shift;
  my $name = shift;

  my $tree = parse_texi_text(undef, $in);
  if ($do->{'protect_comma'}) {
    $tree = protect_comma_in_tree($tree);
  }
  if ($do->{'protect_colon'}) {
    $tree = protect_colon_in_tree($tree);
  }
  if ($do->{'protect_node_after_label'}) {
    $tree = protect_node_after_label_in_tree($tree);
  }

  my $texi_result = Texinfo::Convert::Texinfo::convert($tree);

  if (!defined($out)) {
    print STDERR " --> $name:\n$texi_result";
  } else {
    is ($texi_result, $out, $name);
  }
}

run_test({'protect_comma' => 1},
'Some, text,,,@code{,} @asis{, text} @verb{:v,:} @,c',
'Some@comma{} text@comma{}@comma{}@comma{}@code{@comma{}} @asis{@comma{} text} @verb{:v,:} @,c',
'protect comma');

run_test({'protect_colon' => 1},
'Some :: colons: @code{:} @verb{: in verb::} @:.:',
'Some @asis{::} colons@asis{:} @code{@asis{:}} @verb{: in verb::} @:.@asis{:}',
'protect colon');

run_test({'protect_node_after_label' => 1},
"\t\t".'., text @code{,.t.} @verb{:, .:} .'."\t t",
'@asis{		}@asis{.,} text @code{@asis{,.}t@asis{.}} @verb{:, .:} @asis{.	} t',
'protect node after label characters');