text: #! @PERL@ -w
  #
  #  Man page to help file converter
  #  Copyright (C) 1994, 1995, 1998, 2000, 2001, 2002, 2003, 2004, 2005,
  #  2007, 2010, 2011
  #  The Free Software Foundation, Inc.
  #
  #  Originally written by:
  #   Andrew V. Samoilov, 2002
  #   Pavel Roskin, 2002
  #   Andrew Borodin <aborodin@vmail.ru>, 2010
  #
  #  Completely rewritten in Perl by:
  #   Alexandr Prenko, 2010
  #
  # This program is free software: you can redistribute it and/or modify
  # it under the terms of the GNU General Public License as published by
  # the Free Software Foundation, either version 3 of the License, or
  # (at your option) any later version.
  #
  # This program is distributed in the hope that it will be useful,
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  # GNU General Public License for more details.
  #
  # You should have received a copy of the GNU General Public License
  # along with this program.  If not, see <http://www.gnu.org/licenses/>.
  #
  # \file man2hlp
  # \brief Source: man page to help file converter
  
  use strict;
  use warnings;
  
  # Perl have no static variables, so this hash emulates them
  my %static = (
      "string_len anchor_flag"    => 0,
      "string_len lc_link_flag"   => 0,
      "handle_link old"           => undef
  );
  
  # Imported constants
  my $CHAR_LINK_START     = chr(01);      # Ctrl-A
  my $CHAR_LINK_POINTER   = chr(02);      # Ctrl-B
  my $CHAR_LINK_END       = chr(03);      # Ctrl-C
  my $CHAR_NODE_END       = chr(04);      # Ctrl-D
  my $CHAR_ALTERNATE      = chr(05);      # Ctrl-E
  my $CHAR_NORMAL         = chr(06);      # Ctrl-F
  my $CHAR_VERSION        = chr(07);      # Ctrl-G
  my $CHAR_FONT_BOLD      = chr(010);     # Ctrl-H
  my $CHAR_FONT_NORMAL    = chr(013);     # Ctrl-K
  my $CHAR_FONT_ITALIC    = chr(024);     # Ctrl-T
  # end of import
  
  my $col = 0;            # Current output column
  my $out_row = 1;        # Current output row
  my $in_row = 0;         # Current input row
  my $no_split_flag = 0;  # Flag: Don't split section on next ".SH"
  my $skip_flag = 0;      # Flag: Skip this section.
                          #       0 = don't skip,
                          #       1 = skipping title,
                          #       2 = title skipped, skipping text
  my $link_flag = 0;      # Flag: Next line is a link
  my $verbatim_flag = 0;  # Flag: Copy input to output verbatim
  my $node = 0;           # Flag: This line is an original ".SH"
  
  my $c_out;              # Output filename
  my $f_out;              # Output file
  
  my $c_in;               # Current input filename
  
  my $indentation;        # Indentation level, n spaces
  my $tp_flag;            # Flag: .TP paragraph
                          #       1 = this line is .TP label,
                          #       2 = first line of label description.
  my $topics = undef;
  
  # Emulate C strtok()
  my $strtok;
  
  sub strtok($$) {
      my ($str, $chars) = @_;
  
      if (! defined $chars || $chars eq "")
      {
          my $result = $strtok;
          $strtok = undef;
          return $result;
      }
  
      $str = $strtok unless defined $str;
      return undef unless defined $str;
  
      my $result;
      $str =~ s/^[$chars]+//;
      ($result, $strtok) = split /[$chars]+/, $str, 2;
      ($result, $strtok) = split /[$chars]+/, $strtok, 2 if defined $result && $result eq "";
      $strtok = undef if ! defined $strtok || $strtok eq "";
      return $result;
  }
  
  sub struct_node() {
      return {
          "node"          => undef,   # Section name
          "lname"         => undef,   # Translated .SH, undef if not translated
          "next"          => undef,
          "heading_level" => undef
      }
  }
  
  my $nodes = struct_node();
  my $cnode;              # Current node
  
  # Report error in input
  sub print_error($)
  {
      my ($message) = @_;
      warn sprintf  "man2hlp: %s in file \"%s\" on line %d\n", $message, $c_in, $in_row;
  }
  
  # Do open, exit if it fails
  sub fopen_check ($$)
  {
      my ($mode, $filename) = @_;
      my $f;
  
      unless (open $f, $mode, $filename)
      {
          warn sprintf("man2hlp: Cannot open file \"%s\" ($!)\n", $filename);
          exit 3;
      }
      return $f;
  }
  
  # Do close, exit if it fails
  sub fclose_check($)
  {
      my ($f) = @_;
      unless (close $f) 
      {
          warn "man2hlp: Cannot close file ($!)\n";
          exit 3;
      }
  }
  
  # Change output line
  sub newline()
  {
      $out_row++;
      $col = 0;
      print $f_out "\n";
  }
  
  # Calculate the length of string
  sub string_len
  {
      my ($buffer) = @_;
      my $anchor_flag = \$static{"string_len anchor_flag"}; # Flag: Inside hypertext anchor name ho4u_v_Ariom
      my $lc_link_flag = \$static{"string_len lc_link_flag"}; # Flag: Inside hypertext link target name
      my $backslash_flag = 0;     # Flag: Backslash quoting
      my $len = 0;                # Result: the length of the string
  
  
      foreach my $c (split //, $buffer)
      {
          if ($c eq $CHAR_LINK_POINTER)
          {
              $$lc_link_flag = 1;   # Link target name starts
          }
          elsif ($c eq $CHAR_LINK_END)
          {
              $$lc_link_flag = 0;   # Link target name ends
          }
          elsif ($c eq $CHAR_NODE_END)
          {
              # Node anchor name starts
              $$anchor_flag = 1;
              # Ugly hack to prevent loss of one space
              $len++;
          }
          # Don't add control characters to the length
          next if ord($c) >= 0 && ord($c) < 32;
          # Attempt to handle backslash quoting
          if ($c eq '\\' && !$backslash_flag)
          {
              $backslash_flag = 1;
              next;
          }
          $backslash_flag = 0;
          # Increase length if not inside anchor name or link target name
          $len++ if !$$anchor_flag && !$$lc_link_flag;
          if ($$anchor_flag && $c eq ']')
          {
              # Node anchor name ends
              $$anchor_flag = 0;
          }
      }
      return $len;
  }
  
  # Output the string
  sub print_string($)
  {
      my ($buffer) = @_;
      my $len;                    # The length of current word
      my $backslash_flag = 0;
      my $font_change_flag = 0;
  
      # Skipping lines?
      return if $skip_flag;
      # Copying verbatim?
      if ($verbatim_flag)
      {
          # Attempt to handle backslash quoting
          foreach (split //, $buffer)
          {
              if ($_ eq '\\' && !$backslash_flag)
              {
                  $backslash_flag = 1;
                  next;
              }
              $backslash_flag = 0;
              print $f_out $_;
          }
      }
      else
      {
          # Split into words
          $buffer = strtok($buffer, " \t\n");
          # Repeat for each word
          while (defined $buffer)
          {
              # Skip empty strings
              if ($buffer ne '')
              {
                  $len = string_len($buffer);
                  # Words are separated by spaces
                  if ($col > 0)
                  {
                      print $f_out ' ';
                      $col++;
                  }
                  elsif ($indentation)
                  {
                      print $f_out ' ' while $col++ < $indentation;
                  }
                  # Attempt to handle backslash quoting
                  foreach (split //, $buffer)
                  {
                      # handle \fR, \fB, \fI and \fP commands
                      if ($font_change_flag)
                      {
                          if ($_ eq 'B')
                          {
                              print $f_out $CHAR_FONT_BOLD;
                          }
                          elsif ($_ eq 'I')
                          {
                              print $f_out $CHAR_FONT_ITALIC;
                          }
                          elsif ($_ eq 'R' || $_ eq 'P')
                          {
                              print $f_out $CHAR_FONT_NORMAL;
                          }
                          else
                          {
                              print $f_out 'f' . $_;
                              print_error "Syntax error: unsupported \\f" . $_ . " command";
                          }
  
                          $font_change_flag = 0;
                          next;
                      }
                      if ($_ eq 'f' && $backslash_flag)
                      {
                          $font_change_flag = 1;
                          $backslash_flag = 0;
                          next;
                      }
                      if ($_ eq '\\' && !$backslash_flag)
                      {
                          $backslash_flag = 1;
                          next;
                      }
                      $backslash_flag = 0;
                      $font_change_flag = 0;
                      print $f_out $_;
                  }
                  # Increase column
                  $col += $len;
              }
              # Get the next word
              $buffer = strtok(undef, " \t\n");
          }                       # while
      }
  }
  
  # Like print_string but with printf-like syntax
  sub printf_string
  {
      print_string sprintf shift, @_;
  }
  
  # Handle NODE and .SH commands.  is_sh is 1 for .SH, 0 for NODE
  # FIXME: Consider to remove first parameter
  sub handle_node($$)
  {
      my ($buffer, $is_sh) = @_;
      my ($len, $heading_level);
  
      # If we already skipped a section, don't skip another
      $skip_flag = 0 if $skip_flag == 2;
  
      # Get the command parameters
      $buffer = strtok(undef, "");
      if (! defined $buffer)
      {
          print_error "Syntax error: .SH: no title";
          return;
      }
      else
      {
          # Remove quotes
          $buffer =~ s/^"// and $buffer =~ s/"$//;
          # Calculate heading level
          $heading_level = 0;
          $heading_level++ while substr($buffer, $heading_level, 1) eq ' ';
          # Heading level must be even
          if ($heading_level % 2)
          {
              print_error "Syntax error: .SH: odd heading level";
          }
          if ($no_split_flag)
          {
              # Don't start a new section
              newline;
              print_string $buffer;
              newline;
              newline;
              $no_split_flag = 0;
          }
          elsif ($skip_flag)
          {
              # Skipping title and marking text for skipping
              $skip_flag = 2;
          }
          else
          {
              $buffer = substr($buffer, $heading_level);
              if (! $is_sh || ! $node)
              {
                  # Start a new section, but omit empty section names
                  if ($buffer ne '')
                  {
                      printf $f_out "%s[%s]", $CHAR_NODE_END, $buffer;
                      newline;
                  }
  
                  # Add section to the linked list
                  if (! defined $cnode)
                  {
                      $cnode = $nodes;
                  }
                  else
                  {
                      $cnode->{'next'} = struct_node();
                      $cnode = $cnode->{'next'};
                  }
                  $cnode->{'node'} = $buffer;
                  $cnode->{'lname'} = undef;
                  $cnode->{'next'} = undef;
                  $cnode->{'heading_level'} = $heading_level;
              }
              if ($is_sh)
              {
                  $cnode->{'lname'} = $buffer;
                  print_string $buffer;
                  newline;
                  newline;
              }
          }                       # Start new section
      }                         # Has parameters
      $node = ! $is_sh;
  }
  
  # Convert character from the macro name to the font marker
  sub char_to_font($)
  {
      my ($c) = @_;
      my %font = (
          'R' => $CHAR_FONT_NORMAL,
          'B' => $CHAR_FONT_BOLD,
          'I' => $CHAR_FONT_ITALIC
      );
      return exists $font{$c} ? $font{$c} : chr(0);
  }
  
  #
  # Handle alternate font commands (.BR, .IR, .RB, .RI, .BI, .IB)
  # Return 0 if the command wasn't recognized, 1 otherwise
  #
  sub handle_alt_font($)
  {
      my ($buffer) = @_;
      my $in_quotes = 0;
      my $alt_state = 0;
  
      return 0 if length($buffer) != 3;
      return 0 if substr($buffer, 0, 1) ne '.';
  
      my @font = (
          char_to_font substr($buffer, 1, 1),
          char_to_font substr($buffer, 2, 1)
      );
  
      # Exclude names with unknown characters, .BB, .II and .RR
      if ($font[0] eq chr(0) || $font[1] eq chr(0) || $font[0] eq $font[1])
      {
          return 0;
      }
  
      my $p = strtok(undef, "");
      return 1 unless defined $p;
  
      $buffer = $font[0];
  
      my @p = split //, $p;
      while (@p)
      {
  
          if ($p[0] eq '"')
          {
              $in_quotes = !$in_quotes;
              shift @p;
              next;
          }
  
          if ($p[0] eq ' ' && !$in_quotes)
          {
              shift @p;
              # Don't change font if we are at the end
              if (@p)
              {
                  $alt_state = $alt_state ? 0 : 1;
                  $buffer .= $font[$alt_state];
              }
  
              # Skip more spaces
              shift @p while @p && $p[0] eq ' ';
  
              next;
          }
  
          $buffer .= shift @p;
      }
  
      # Turn off attributes if necessary
      if ($font[$alt_state] ne $CHAR_FONT_NORMAL)
      {
          $buffer .= $CHAR_FONT_NORMAL;
      }
  
      print_string $buffer;
  
      return 1;
  }
  
  # Handle .IP and .TP commands.  is_tp is 1 for .TP, 0 for .IP
  sub handle_tp_ip($)
  {
      my ($is_tp) = @_;
      newline if $col > 0;
      newline;
      if ($is_tp)
      {
          $tp_flag = 1;
          $indentation = 0;
      }
      else
      {
          $indentation = 8;
      }
  }
  
  # Handle all the roff dot commands.  See man groff_man for details
  sub handle_command($)
  {
      my ($buffer) = @_;
      my $len;
  
      # Get the command name
      $buffer = strtok($buffer, " \t");
  
      if ($buffer eq ".SH")
      {
          $indentation = 0;
          handle_node $buffer, 1;
      }
      elsif ($buffer eq ".\\\"NODE")
      {
          handle_node $buffer, 0;
      }
      elsif ($buffer eq ".\\\"DONT_SPLIT\"")
      {
          $no_split_flag = 1;
      }
      elsif ($buffer eq ".\\\"SKIP_SECTION\"")
      {
          $skip_flag = 1;
      }
      elsif ($buffer eq ".\\\"LINK2\"")
      {
          # Next two input lines form a link
          $link_flag = 2;
      }
      elsif ($buffer eq ".PP" || $buffer eq ".P" || $buffer eq ".LP")
      {
          $indentation = 0;
          # End of paragraph
          newline if $col > 0;
          newline;
      }
      elsif ($buffer eq ".nf")
      {
          # Following input lines are to be handled verbatim
          $verbatim_flag = 1;
          newline if $col > 0;
      }
      elsif ($buffer eq ".I" || $buffer eq ".B" || $buffer eq ".SB")
      {
          # Bold text or italics text
          my $backslash_flag = 0;
  
          # .SB [text]
          # Causes the text on the same line or the text on the
          # next  line  to  appear  in boldface font, one point
          # size smaller than the default font.
          #
  
          # FIXME: text is optional, so there is no error
  
          my $p = strtok(undef, "");
          if (! defined $p)
          {
              print_error "Syntax error: .I | .B | .SB : no text";
              return;
          }
  
          $buffer = substr($buffer, 1, 1) eq 'I' ? $CHAR_FONT_ITALIC : $CHAR_FONT_BOLD;
  
          # Attempt to handle backslash quoting
          foreach (split //, $p)
          {
              if ($_ eq '\\' && !$backslash_flag)
              {
                  $backslash_flag = 1;
                  next;
              }
              $backslash_flag = 0;
              $buffer .= $_;
          }
          print_string $buffer . $CHAR_FONT_NORMAL;
      }
      elsif ($buffer eq ".TP")
      {
          handle_tp_ip 1;
      }
      elsif ($buffer eq ".IP")
      {
          handle_tp_ip 0;
      }
      elsif ($buffer eq ".\\\"TOPICS")
      {
          if ($out_row > 1)
          {
              print_error "Syntax error: .\\\"TOPICS must be first command";
              return;
          }
          $buffer = strtok(undef, "");
          if (! defined $buffer)
          {
              print_error "Syntax error: .\\\"TOPICS: no text";
              return;
          }
          # Remove quotes
          $buffer =~ s/^"// and $buffer =~ s/"$//;
          $topics = $buffer;
      }
      elsif ($buffer eq ".br")
      {
          newline if $col;
      }
      elsif ($buffer =~  /^\.\\"/)
      {
          # Comment { Hello from K.O. ;-) }
      }
      elsif ($buffer eq ".TH")
      {
          # Title header
      }
      elsif ($buffer eq ".SM")
      {
          # Causes the text on the same line or the text on the
          # next  line  to  appear  in a font that is one point
          # size smaller than the default font.
          $buffer = strtok(undef, "");
          print_string $buffer if defined $buffer;
      }
      elsif (handle_alt_font($buffer) == 1)
      {
          return;
      }
      elsif ($buffer eq ".RE")
      {
          newline;
      }
      else
      {
          # Other commands are ignored
          print_error sprintf "Warning: unsupported command %s", $buffer;
          return;
      }
  }
  
  sub struct_links()
  {
      return {
          'linkname'  => undef,   # Section name
          'line'      => undef,   # Input line in ...
          'filename'  => undef,
          'next'      => undef
      }
  }
  
  my $links = struct_links();
  my $current_link;
  
  
  sub handle_link($)
  {
      my ($buffer) = @_;
      my $old = \$static{"handle_link old"};
      my $len;
      my $amp;
      my $amp_arg;
  
      if ($link_flag == 1)
      {
          # Old format link, not supported
      }
      elsif ($link_flag == 2)
      {
          # First part of new format link
          # Bold text or italics text
          if (substr($buffer, 0, 2) eq '.I' || substr($buffer, 0, 2) eq '.B')
          {
              $buffer =~ s/^..[\s\t]*//;
          }
          $$old = $buffer;
          $link_flag = 3;
  
      }
      elsif ($link_flag == 3)
      {
          # Second part of new format link
          $buffer =~ s/^\.//;
          $buffer =~ s/^\\//;
          $buffer =~ s/^"//;
          $buffer =~ s/"$//;
  
          # "Layout\&)," -- "Layout" should be highlighted, but not "),"
          ($$old, $amp_arg) = split /\\&/, $$old, 2;
          $amp_arg = "" unless defined $amp_arg;
          printf_string "%s%s%s%s%s%s\n", $CHAR_LINK_START, $$old,
                         $CHAR_LINK_POINTER, $buffer, $CHAR_LINK_END, $amp_arg;
          $link_flag = 0;
          # Add to the linked list
          if (defined $current_link)
          {
              $current_link->{'next'} = struct_links();
              $current_link = $current_link->{'next'};
              $current_link->{'next'} = undef;
          }
          else
          {
              $current_link = $links;
          }
          $current_link->{'linkname'} = $buffer;
          $current_link->{'filename'} = $c_in;
          $current_link->{'line'} = $in_row;
      }
  }
  
  sub main
  {
      my $len;                    # Length of input line
      my $c_man;                  # Manual filename
      my $c_tmpl;                 # Template filename
      my $f_man;                  # Manual file
      my $f_tmpl;                 # Template file
      my $buffer;                 # Full input line
      my $lc_node = undef;
      my $outfile_buffer;         # Large buffer to keep the output file
      my $cont_start;             # Start of [Contents]
      my $file_end;               # Length of the output file
  
      # Validity check for arguments
      if (@ARGV != 3)
      {
          warn "Usage: man2hlp file.man template_file helpfile\n";
          return 3;
      }
  
      $c_man  = $ARGV[0];
      $c_tmpl = $ARGV[1];
      $c_out  = $ARGV[2];
  
      # First stage - process the manual, write to the output file
  
      $f_man = fopen_check "<", $c_man;
      $f_out = fopen_check ">", $c_out;
      $c_in = $c_man;
  
      # Repeat for each input line
      while (<$f_man>)
      {
          # Remove terminating newline
          chomp;
          $buffer = $_;
          my $input_line;       # Input line without initial "\&"
  
          if (substr($buffer, 0, 2) eq '\\&')
          {
              $input_line = substr($buffer, 2);
          }
          else
          {
              $input_line = $buffer;
          }
  
          $in_row++;
          $len = length($input_line);
  
          if ($verbatim_flag)
          {
              # Copy the line verbatim
              if ($input_line eq ".fi")
              {
                  $verbatim_flag = 0;
              }
              else
              {
                  print_string $input_line;
                  newline;
              }
          }
          elsif ($link_flag)
          {
              # The line is a link
              handle_link $input_line;
          }
          elsif (substr($buffer, 0, 1) eq '.')
          {
              # The line is a roff command
              handle_command $input_line;
          }
          else
          {
              #A normal line, just output it
              print_string $input_line;
          }
          # .TP label processed as usual line
          if ($tp_flag)
          {
              if ($tp_flag == 1)
              {
                  $tp_flag = 2;
              }
              else
              {
                  $tp_flag = 0;
                  $indentation = 8;
                  if ($col >= $indentation)
                  {
                      newline;
                  }
                  else
                  {
                      print $f_out " " while ++$col < $indentation;
                  }
              }
          }
      }
  
      newline;
      fclose_check $f_man;
      # First stage ends here, closing the manual
  
      # Second stage - process the template file
      $f_tmpl = fopen_check "<", $c_tmpl;
      $c_in = $c_tmpl;
  
      # Repeat for each input line
      # Read a line
      while (<$f_tmpl>)
      {
          $buffer = $_;
          if (defined $lc_node)
          {
              if ($buffer ne "\n")
              {
                  $cnode->{'lname'} = $buffer;
                  chomp $cnode->{'lname'};
              }
              $lc_node = undef;
          }
          else
          {
              my $char_node_end = index($buffer, $CHAR_NODE_END);
              $lc_node = $char_node_end < 0 ? undef : substr($buffer, $char_node_end);
  
              if (defined $lc_node && substr($lc_node, 1, 1) eq '[')
              {
                  my $p = index($lc_node, ']');
                  if ($p >= 0) {
                      if (substr($lc_node, 1, 6) eq '[main]')
                      {
                          $lc_node = undef;
                      }
                      else
                      {
                          if (! defined $cnode)
                          {
                              $cnode = $nodes;
                          }
                          else
                          {
                              $cnode->{'next'} = struct_node();
                              $cnode = $cnode->{'next'};
                          }
                          $cnode->{'node'} = substr($lc_node, 2, $p-2);
                          $cnode->{'lname'} = undef;
                          $cnode->{'next'} = undef;
                          $cnode->{'heading_level'} = 0;
                      }
                  }
                  else
                  {
                    $lc_node = undef;
                  }
              }
              else
              {
                  $lc_node = undef;
              }
          }
          print $f_out $buffer;
      }
  
      $cont_start = tell $f_out;
      if ($cont_start <= 0)
      {
          perror $c_out;
          return 1;
      }
  
      if ($topics)
      {
          printf $f_out "\004[Contents]\n%s\n\n", $topics;
      }
      else
      {
          print $f_out "\004[Contents]\n";
      }
  
      for ($current_link = $links; defined $current_link && defined $current_link->{'linkname'};)
      {
          my $found = 0;
          my $next = $current_link->{'next'};
  
          if ($current_link->{'linkname'} eq "Contents")
          {
              $found = 1;
          }
          else
          {
              for ($cnode = $nodes; defined $cnode && defined $cnode->{'node'}; $cnode = $cnode->{'next'})
              {
                  if ($cnode->{'node'} eq $current_link->{'linkname'})
                  {
                      $found = 1;
                      last;
                  }
              }
          }
          if (! $found)
          {
              $buffer = sprintf "Stale link \"%s\"", $current_link->{'linkname'};
              $c_in = $current_link->{'filename'};
              $in_row = $current_link->{'line'};
              print_error $buffer;
          }
  
          $current_link = $next;
      }
  
      for ($cnode = $nodes; defined $cnode && defined $cnode->{'node'};)
      {
          my $next = $cnode->{'next'};
          $lc_node = $cnode->{'node'};
  
          if (defined $lc_node && $lc_node ne '') {
              printf $f_out "  %*s\001%s\002%s\003", $cnode->{'heading_level'},
                  "", $cnode->{'lname'} ? $cnode->{'lname'} : $lc_node, $lc_node;
          }
          print $f_out "\n";
          $cnode = $next;
      }
  
      $file_end = tell $f_out;
  
      # Sanity check
      if (($file_end <= 0) || ($file_end - $cont_start <= 0))
      {
          warn $c_out ."\n";
          return 1;
      }
  
      fclose_check $f_out;
      fclose_check $f_tmpl;
      # Second stage ends here, closing all files, note the end of output
  
      #
      # Third stage - swap two parts of the output file.
      # First, open the output file for reading and load it into the memory.
      #
      $outfile_buffer = '';
      $f_out = fopen_check '<', $c_out;
      $outfile_buffer .= $_ while <$f_out>;
      fclose_check $f_out;
      # Now the output file is in the memory
  
      # Again open output file for writing
      $f_out = fopen_check '>', $c_out;
  
      # Write part after the "Contents" node
      print $f_out substr($outfile_buffer, $cont_start, $file_end - $cont_start);
  
      # Write part before the "Contents" node
      print $f_out substr($outfile_buffer, 0, $cont_start-1);
      print $f_out "\n";
      fclose_check $f_out;
  
      return 0;
  }
  
  exit main();
  