#!/usr/bin/env perl
#
# Updates http://cvs.gnome.org/viewcvs/gtk%2B/gtk/gtkimcontextsimple.c from upstream (X.org 6.9/7.0),
# from http://gitweb.freedesktop.org/?p=xorg/lib/libX11.git;a=blob_plain;f=nls/en_US.UTF-8/Compose.pre
#
# Name    : compose-sequence-update.pl
# Author  : Simos Xenitellis <simos at gnome dot org>.
# Version : 1.4
#
# Input   : http://gitweb.freedesktop.org/?p=xorg/lib/libX11.git;a=blob_plain;f=nls/en_US.UTF-8/Compose.pre
# Input   : http://svn.gnome.org/viewcvs/gtk%2B/trunk/gdk/gdkkeysyms.h
# Input	  : http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
# Output  : http://cvs.gnome.org/viewcvs/gtk%2B/gtk/gtkimcontextsimple.c
#
# Notes   : It downloads Compose.pre from the Internet if not found locally
# Notes   : and creates an updated gtkimcontextsimple.c
#

use strict;

my $line;
my $firstletter;
my @components;
my $i;
my $semicolon_pos;
my $letter;
my $codepoint;
my $codepointhex;
my @entry;
my @gtkimcontext;
my @gtkimcontextsorted;
my @gtkimcontextsorteduniqued;
my $packedline;
my @unpackeda;
my @unpackedb;
my @existingelements;
my @existingseqs;
my $element;
my $previouselement;
my @c;
my $counter = 0;
my $lines = 0;
my $previoussym;
my $quadruplet;
my @quadrupletset;
my $toplevel = 1;
my $topcounter;
my $main_output_filename = "gtkimcontextsimpleseqs.h";
my @startkeys;
my $previouskeysym;
my $key;
my $keysym;
my @offset2elements;
my @offset3elements;
my @offset4elements;
my @offset5elements;
my $offset;
my $hadfirstguint32;
my $isnotyetguint32;

# Used for reading the GDK key symbols.
my @gdkelements;
my %gdksyms;

# Used for reading the UnicodeData.txt file.
my @unicodeelements;
my %unicodedata;

if ( ! -f "Compose.pre" )
{
        print "Trying to download en_US/Compose.pre from\n";
        print "http://gitweb.freedesktop.org/?p=xorg/lib/libX11.git;a=blob_plain;f=nls/en_US.UTF-8/Compose.pre\n";
        die "Unable to download Compose.pre from http://gitweb.freedesktop.org/?p=xorg/lib/libX11.git;a=blob_plain;f=nls/en_US.UTF-8/Compose.pre\n"
                unless system("wget -O Compose.pre -c \"http://gitweb.freedesktop.org/?p=xorg/lib/libX11.git;a=blob_plain;f=nls/en_US.UTF-8/Compose.pre\"") == 0;
        print " done.\n\n";
}
else
{
        print "We are using an existing Compose.pre (Compose) file found in this directory.\n";
        print "It is assumed that you took care and it is a recent version\n";
        print "as found at http://gitweb.freedesktop.org/?p=xorg/lib/libX11.git;a=blob_plain;f=nls/en_US.UTF-8/Compose.pre\n";
	print "If you erase the Compose.pre file and run the script again, we will download a fresh copy.\n\n";
}


# Source: http://gitweb.freedesktop.org/?p=xorg/lib/libX11.git;a=blob_plain;f=nls/en_US.UTF-8/Compose.pre
# or /usr/share/X11/locale/en_US.UTF-8/Compose
# The file can be used verbatim. Comments start with "^XCOMM".
die "\nCould not open Compose.pre: $!\n" unless open(IN_COMPOSE, "<:utf8", "Compose.pre");

if ( ! -f "../gdk/gdkkeysyms.h" )
{
        print "It appears you do not have a gdkkeysyms.h file in ../gdk/\n";
        print "Copy it from http://svn.gnome.org/viewcvs/gtk%2B/trunk/gdk/gdkkeysyms.h\n";
        die "Or see http://svn.gnome.org/viewcvs/gtk%2B/trunk/gdk/gdkkeysyms-update.pl if it requires update.\n"
}

# Source: gtk+/gdk/gdkkeysyms.h
# or /usr/include/gtk-2.0/gdk/gdkkeysyms.h
die "Could not open file ../gdk/gdkkeysyms.h: $!\n" unless open(IN_GDKKEYSYMS, "<:utf8", "../gdk/gdkkeysyms.h");

if ( ! -f "UnicodeData.txt" )
{
        print "Trying to download UnicodeData.txt from\n";
        print "http://www.unicode.org/Public/UNIDATA/UnicodeData.txt\n";
        die "Unable to download UnicodeData.txt from http://www.unicode.org/Public/UNIDATA/UnicodeData.txt\n"
                unless system("wget -c \"http://www.unicode.org/Public/UNIDATA/UnicodeData.txt\"") == 0;
        print "Done downloading UnicodeData.txt.\n\n";
}
else
{
        print "We are using an existing UnicodeData.txt file found in this directory.\n";
        print "It is assumed that you took care and it is a recent version\n";
        print "as found at http://www.unicode.org/Public/UNIDATA/UnicodeData.txt\n\n";
}

# if ( -f $main_output_filename )
# {
# 	print "You already have a file named $main_output_filename in the current directory.\n";
# 	print "Please rename/erase it in order to continue. A $main_output_filename\n";
# 	print "is the output of this program, to be placed in svn://gtk+/gtk/\n";
# 	die  "I am quiting now.\n";
# }

# Source: http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
# or /usr/lib/perl5/5.8.3/unicore/UnicodeData.txt
die "Could not open file UnicodeData.txt: $!\n" unless open(IN_UNICODEDATA, "<:utf8", "UnicodeData.txt");

# Output file: multiples.result
die "Could not open output file multiples.result: $!\n" unless open(OUT_MULTIPLES, ">:utf8", "multiples.result");

# Output file: conflicts.result
die "Could not open output file conflicts.result: $!\n" unless open(OUT_CONFLICTS, ">:utf8", "conflicts.result");

# Output file: gtkimcontextsimple.c.UPDATEDOPTIMISED
die "Could not open output file gtkimcontextsimpleseqs.h: $!\n" unless open(OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED, ">:utf8", $main_output_filename);

# Output file: offsets.temp
die "Could not create temp output file offsets.temp: $!\n" unless open(OUT_OFFSETS_TEMP, ">:utf8", "offsets.temp");

# Output file: flatversion.temp
die "Could not create temp output file flatversion.temp: $!\n" unless open(OUT_FLATVERSION_TEMP, ">:utf8", "flatversion.temp");

# Output file: needsguint32.temp
die "Could not create temp output file needsguint32.temp: $!\n" unless open(OUT_NEEDSGUINT32_TEMP, ">:utf8", "needsguint32.temp");

# Now we start work.
keys(%unicodedata) = 20000;
keys(%gdksyms) = 2500;

sub printgtkentrymultiples
{
  my @a = unpack("A100 A100 A100 A100 A100 A50 A150", shift);
  my $destinationfile = shift;

  print OUT_MULTIPLES "  $a[0],\t$a[1],\t$a[2],\t$a[3],\t$a[4],\t$a[5], /* $a[6] */\n";

  return;
}

sub printgtkentryconflicts
{
  my @a = unpack("A100 A100 A100 A100 A100 A50 A150", shift);
  my $destinationfile = shift;

  print OUT_CONFLICTS "  $a[0],\t$a[1],\t$a[2],\t$a[3],\t$a[4],\t$a[5], /* $a[6] */\n";

  return;
}

while (<IN_UNICODEDATA>)
{
	@unicodeelements = split(/;/);
	die "Internal error, no unicodeelements, \$_: $_, \@unicodeelements: @unicodeelements\n" unless @unicodeelements;

	$unicodeelements[1] =~ s/\s+/_/g; 
	$unicodedata{$unicodeelements[0]} = $unicodeelements[1];
	# Example: { "00ED" } = "LATIN_SMALL_LETTER_I_WITH_ACUTE";
}

close IN_UNICODEDATA;

print STDERR "Done reading Unicode Data\n";

while (<IN_GDKKEYSYMS>)
{
	last if (/^#define GDK/);
}

while (<IN_GDKKEYSYMS>)
{
	last if ( /^$/ );

	@gdkelements = split(/\s+/);
	die "Internal error, no gdkelements, \$_: $_, \@gdkelements: @gdkelements\n" unless @gdkelements;

	$gdksyms{$gdkelements[1]} = hex($gdkelements[2]);
	# Example: { "GDK_dead_grave" } = "FE50";
}

$gdksyms{"0"} = "0000";

close IN_GDKKEYSYMS;

print STDERR "Done reading GDK Key Syms\n";

LINE:
while (<IN_COMPOSE>)
{
	next if ( /^XCOMM/ );

	$line = $_;
	$firstletter = substr($line, 0, 1);
	if ( $firstletter eq "#" || $firstletter eq "\n" )
	{
		next LINE;
	}

	# There is one line in the input file that has no space between >:
	$line =~ s/>:/> :/g;

	# There are some lines where keysyms have no whitespace in between, like <dead_acute><Y>
	$line =~ s/></> </g;

	# Some lines begin with spaces, let's remove them first for the split to work.
	$line =~ s/^\s+//g;	

	@components = split(/\s+/, $line);
	die "Internal error, no components, \$_: $_, \@components: @components\n" unless @components;

	$semicolon_pos = 0;
	for ($i = 0; $i < @components; $i++ )
	{
		if ( $components[$i] eq ":" )
		{
			$semicolon_pos = $i;
			last;
		}
	}	
	die "Internal error, no colon, \$_: $_\n" unless $semicolon_pos;

	@entry = ();
	for ( $i = 0; $i < $semicolon_pos; $i++ )
	{
		$_ = $components[$i];
		if ( /^\</ )
		{
			$_ =~ s/^\<(\w*)\>/GDK_$1/g;
			push @entry, $_;
		} 
	}

	for ( $i = $semicolon_pos; $i < 5; $i++ )
	{		
		push @entry, "0";
	}

	# Some keysyms look like <U11ab>. We have to detect them
	# and convert to hex. Else gtk+ won't compile.
	for ( $i = 0; $i < 5; $i++ )
	{
		# If it begins with U (the string has already "GDK_" attached to it),
		if ( index($entry[$i], "GDK_U") == 0 )
		{
			# If it is not just <U>,
			if ( length($entry[$i]) > 5 ) 
			{
				# If it is not something like <Uhorn>,
				if ( hex(substr($entry[$i], 5)) > 0 && (substr($entry[$i], 5) cmp "00000") )
				{
					$entry[$i] = sprintf("0x%04X", hex(substr($entry[$i], 5)));
					# IF 
                			if ( hex(substr($entry[$i], 5)) > 0xFFFF )
                			{
					die "Found keysym > 0xFFFF! Dying...\n";
					#   	$entry[$i] = sprintf("0x100%05X", hex(substr($entry[$i], 5)));
                			}
                			else 
                			{
					#	$entry[$i] = sprintf("0x1000%04X", hex(substr($entry[$i], 5)));
                			}
				}
			}
		}
	}

	# Now it is time to check if the GDK_* keysyms we guessed
	# actually exists in gdkkeysyms.h
	for ( $i = 0; $i < 5; $i++ )
	{
		# If it begins with "GDK_",
		if ( index($entry[$i], "GDK_") == 0 )
		{
			if ( length($gdksyms{$entry[$i]}) == 0 )
			{
            # Per discussion with Daniel Stone
            # (http://bugzilla.gnome.org/show_bug.cgi?id=321896#c13)
            # we remove any keysyms with 'combining_xxxx'.
            # This takes out 799 compose sequences covering Latin Extended (A or B?)
            # and Ancient Greek.
            #
		      # If it begins with "GDK_",
            if ( $entry[$i] =~ /combining_/ )
            {
               next LINE;
            }
            else
            {
				   print "Could not find $entry[$i], I just got $gdksyms{$entry[$i]}\n";
				   print "A keysym was used in the Compose file but was not found in keysymdef.h\n";
				   print "See https://bugs.freedesktop.org/show_bug.cgi?id=5107\n";
				   die "Fix this first and try again\n";
            }
			}
			else
			{
#				printf "I got %s = 0x%X\n", $entry[$i], $gdksyms{$entry[$i]};
			}
		}
	}

	$letter = $components[$semicolon_pos + 1];
	$letter =~ s/\"//g;

   # We found a quirkiness in Perl; if $a is a Plane 1+ character,
   # ord($a) returns <FFFF, or it chops off the bits over FFFF.
   if ( $components[$semicolon_pos + 2] =~ /^U/ )
   {
      $codepoint = $components[$semicolon_pos + 2];
      $codepoint =~ s/^U//g;
      $codepoint = sprintf("\U${codepoint}");

      # Some boundary conditions, capturing two cases.
      die if (length($codepoint) < 3);
      if ( length($codepoint) < 4 )
      {
         $codepoint = "0" . $codepoint;
      }

	   $codepointhex = "0x" . $codepoint;
   }
   else
   {
	   $codepoint = sprintf("%04X", ord($letter));
	   $codepointhex = sprintf("0x%04X", ord($letter));
   }

	push @entry, $codepointhex;
	push @entry, $unicodedata{$codepoint};

   if ( ! defined($unicodedata{$codepoint}) )
   {
      die "Cannot find $codepoint in UnicodeData.txt\n";
   }

	$packedline = pack("A100 A100 A100 A100 A100 A50 A150", @entry);
	push @gtkimcontext, $packedline;
	# printf "%s %s %s %s %s : %s  %s\n", $entry[0], $entry[1], $entry[2], $entry[3], $entry[4], $codepointhex, $unicodedata{$codepoint};
	# Example: { GDK_dead_acute, GDK_dead_diaeresis, GDK_Greek_upsilon, 0, 0, 0x03B0, GREEK_SMALL_LETTER_UPSILON_WITH_DIALYTIKA_AND_TONOS }
}

close IN_COMPOSE;

print STDERR "Done reading Compose.pre Compose file\n";

# The Compose files has either keysyms or unicode values. We need to do
# sorting, so this function allows to compare the two on their value.
sub get_symbolunivalue
{
	my $a = pop;
  
	# If it begins with GDK_ (it's a keysym),
	if ( index($a, "GDK_") == 0 )
	{
#		printf "DEBUG: We got a keysym %s: %d\n", $a, $gdksyms{$a};
		return $gdksyms{$a};
	}
	else
	{
		# It's already a Unicode character, send it over.
#		printf "DEBUG: We got a unichar : %d, out of string %s\n", hex($a), $a;
		return hex($a);
	}
}

sub gtkentrycmp
{
  my @a = unpack("A100 A100 A100 A100 A100 A50 A150", shift);
  my @b = unpack("A100 A100 A100 A100 A100 A50 A150", shift);
  my $verbose = shift;

  for ( $i = 0; $i < 5; $i++ )
  { 
    if ( get_symbolunivalue($a[$i]) <=> get_symbolunivalue($b[$i]) )
    {
      return get_symbolunivalue($a[$i]) <=> get_symbolunivalue($b[$i]);
    }
  }
  
  if ( $a[5] ne $b[5] )
  { 
    if ( $verbose eq "yes" )
    {
      print STDERR "WARNING: Same keysyms for\n1: $a[6] and \n2: $b[6]\n($a[0], $a[1], $a[2], $a[3], $a[4])\n"; 
    }
    return 0;
  }

  return 0;
}

sub gtkentrycmpall
{
  my @a = unpack("A100 A100 A100 A100 A100 A50 A150", shift);
  my @b = unpack("A100 A100 A100 A100 A100 A50 A150", shift);
  my $verbose = shift;

  for ( $i = 0; $i < 5; $i++ )
  {
    # If they are different, comparison is over and return.
    if ( get_symbolunivalue($a[$i]) <=> get_symbolunivalue($b[$i]) )
    {
      return get_symbolunivalue($a[$i]) <=> get_symbolunivalue($b[$i]);
    }
  }

  return $a[5] cmp $b[5];
}

### gtkimcontextsimple.c has some compose sequences that are specific to Win32
#   and do not exist in the X.org Compose file. This stuff has to be added.
#   This script should it at this point.
#
# Let's concatenate the old list with the new one;
### push(@gtkimcontext, @existingseqs);

# Now, let's play. Sorting is ascending.
@gtkimcontextsorted = sort { gtkentrycmpall $a, $b; } @gtkimcontext;

# Ok, also need to uniq this.
$previouselement = "";
foreach $element (@gtkimcontextsorted)
{
	if ( $previouselement eq "" ) 
	{ 
		push @gtkimcontextsorteduniqued, $element;
		$previouselement = $element;
		next; 
	}

	if ( gtkentrycmpall($element, $previouselement) )
	{
	  push @gtkimcontextsorteduniqued, $element;
	}
	else 
	{ 
	  printgtkentrymultiples($element);
	}

	$previouselement = $element;
}

# Now we print same sequences that produce different characters.
$previouselement = "";
foreach $element (@gtkimcontextsorteduniqued)
{
	# Just starting?
	if ( $previouselement eq "" ) 
 	{ 
 		$previouselement = $element;
 		next; 
 	}
  
 	if ( gtkentrycmp($element, $previouselement, "yes") == 0)
 	{
 	  printgtkentryconflicts($element); 
 	  printgtkentryconflicts($previouselement); 
 	}
 
 	$previouselement = $element;
}

# Another iteration to count the startkeys, how many different first-column keysyms exist.
$previouskeysym = "";
foreach $element (@gtkimcontextsorteduniqued)
{
	my @items = unpack("A100 A100 A100 A100 A100 A50 A150", $element);

	if ( $previouskeysym ne $items[0] ) 
 	{ 
#		print "Pushing $items[0]\n";
		push @startkeys, $items[0];
 	}

 	$previouskeysym = $items[0];
}

# print "We got ", $#startkeys+1, " startkeys\n";
# foreach $key (@startkeys)
# {
# 	printf "%s\n", $key;
# }

print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED<<EOF;
/* GTK - The GIMP Tool Kit
 * Copyright (C) 2007 GNOME Foundation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * File auto-generated from script http://svn.gnome.org/viewcvs/gtk%2B/trunk/gtk/compose-sequence-update.pl
 * using the input files
 *  Input   : http://gitweb.freedesktop.org/?p=xorg/lib/libX11.git;a=blob_plain;f=nls/en_US.UTF-8/Compose.pre
 *  Input   : http://svn.gnome.org/viewcvs/gtk%2B/trunk/gdk/gdkkeysyms.h
 *  Input   : http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
 * 
 * The resulting file is placed at http://svn.gnome.org/viewcvs/gtk%2B/trunk/gtk/gtkimcontextsimpleseqs.h
 * This file is mentioned in report http://bugzilla.gnome.org/show_bug.cgi?id=321896
 */

/*
 * Modified by the GTK+ Team and others 2007-.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
 */

#ifndef __GTK_IM_CONTEXT_SIMPLE_SEQS_H__
#define __GTK_IM_CONTEXT_SIMPLE_SEQS_H__

/* === These are the original comments of the file; we keep for historical purposes ===
 * The following table was generated from the X compose tables include with
 * XFree86 4.0 using a set of Perl scripts. Contact Owen Taylor <otaylor\@redhat.com>
 * to obtain the relevant perl scripts.
 *
 * The following compose letter letter sequences confliced
 *   Dstroke/dstroke and ETH/eth; resolved to Dstroke (Croation, Vietnamese, Lappish), over
 *                                ETH (Icelandic, Faroese, old English, IPA)  [ D- -D d- -d ]
 *   Amacron/amacron and ordfeminine; resolved to ordfeminine                 [ _A A_ a_ _a ]
 *   Amacron/amacron and Atilde/atilde; resolved to atilde                    [ -A A- a- -a ]
 *   Omacron/Omacron and masculine; resolved to masculine                     [ _O O_ o_ _o ]
 *   Omacron/omacron and Otilde/atilde; resolved to otilde                    [ -O O- o- -o ]
 *
 * [ Amacron and Omacron are in Latin-4 (Baltic). ordfeminine and masculine are used for
 *   spanish. atilde and otilde are used at least for Portuguese ]
 *
 *   at and Aring; resolved to Aring                                          [ AA ]
 *   guillemotleft and caron; resolved to guillemotleft                       [ << ]
 *   ogonek and cedilla; resolved to cedilla                                  [ ,, ]
 *
 * This probably should be resolved by first checking an additional set of compose tables
 * that depend on the locale or selected input method.
 */

static const guint16 gtk_compose_seqs[] = {
EOF

print OUT_FLATVERSION_TEMP "static const guint16 gtk_compose_seqs[] = {\n";

foreach $element (@gtkimcontextsorteduniqued)
{
	@c = unpack("A100 A100 A100 A100 A100 A50 A150", $element);	

        print OUT_FLATVERSION_TEMP "  $c[0],\t$c[1],\t$c[2],\t$c[3],\t$c[4],\t$c[5], /* $c[6] */\n";
	$lines++;
}

close OUT_FLATVERSION_TEMP;

print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED "  ", $#startkeys + 1, ", \t/* Number of starting keysyms */\n";
$offset = ($#startkeys + 1) * 4 + 1 + 1;

foreach $key (@startkeys)
{
	@offset2elements = ();
	@offset3elements = ();
	@offset4elements = ();

	print "Matching $key: ";
	foreach $element (@gtkimcontextsorteduniqued)
	{
		my @items = unpack("A100 A100 A100 A100 A100 A50 A150", $element);
	
		$isnotyetguint32 = 1;
		for ( $i = 0; $i < 6 && $isnotyetguint32 == 1; $i++ )
		{
			if ( $items[$i] > 0xFFFF || get_symbolunivalue($items[$i]) > 0xFFFF )
			{
				# print "NON-BMP: @c\n";
				if ( ! $hadfirstguint32 )
				{
					print OUT_NEEDSGUINT32_TEMP "static const guint32 gtk_compose_seqs_nonbmp[] = {\n";

				}
				print OUT_NEEDSGUINT32_TEMP "  $items[0],\t$items[1],\t$items[2],\t$items[3],\t$items[4],\t$items[5], /* $items[6] */\n";
				$isnotyetguint32 = 0;
				$hadfirstguint32++;
			}
		}

		if ( $items[0] eq $key && $isnotyetguint32) 
	 	{ 
			if ( $items[1] eq "0" )
			{
				die "Got startkey-only sequence $key, dying...\n";
			}
			if ( $items[1] ne "0" )
			{
				push @offset2elements, $element;
			}
			if ( $items[2] ne "0" )
			{
				push @offset3elements, $element;
			}
			if ( $items[3] ne "0" )
			{
				push @offset4elements, $element;
			}
			if ( $items[4] ne "0" )
			{
				push @offset5elements, $element;
			}
			print ".";
 		}
        }	

	print "\n";

	print OUT_NEEDSGUINT32_TEMP "};\n";
	close OUT_NEEDSGUINT32_TEMP;
	print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED "  $key, ";

	# Now we put together the offset line (per startkey) and at the same time
	# we dump the offset contents in a temporary file that we will use at the end.
	if ( $#offset2elements != -1 )
	{
		print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED "  $offset, ";
		$offset += 2 * ($#offset2elements + 1) + 1;

		print OUT_OFFSETS_TEMP "  ", $#offset2elements + 1, ", \t\t/* $key */\n";
		foreach $element (@offset2elements)
		{
			my @items = unpack("A100 A100 A100 A100 A100 A50 A150", $element);
			
			print OUT_OFFSETS_TEMP "  $items[1], $items[5], \t\t/* $items[6] */\n";
		}

		if ( $#offset3elements != -1 )
		{
			print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED "$offset, ";
			$offset += 3 * ($#offset3elements + 1) + 1;

			print OUT_OFFSETS_TEMP "  ", $#offset3elements + 1, ", \t\t/* $key */\n";
			foreach $element (@offset3elements)
			{
				my @items = unpack("A100 A100 A100 A100 A100 A50 A150", $element);
				
				print OUT_OFFSETS_TEMP "  $items[1], $items[2], $items[5], \t\t/* $items[6] */\n";
			}

			if ( $#offset4elements != -1 )
			{
				print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED $offset, ", ";
				$offset += 4 * ($#offset4elements + 1) + 1;
			
				print OUT_OFFSETS_TEMP "  ", $#offset4elements + 1, ", \t\t/* $key */\n";
				foreach $element (@offset4elements)
				{
					my @items = unpack("A100 A100 A100 A100 A100 A50 A150", $element);
					
					print OUT_OFFSETS_TEMP "  $items[1], $items[2], $items[3], $items[5], \t\t/* $items[6] */\n";
				}

				if ( $#offset5elements != -1 )
				{
					print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED $offset, ",\n";
					$offset += 5 * ($#offset5elements + 1) + 1;

					print OUT_OFFSETS_TEMP "  ", $#offset5elements + 1, ", \t\t/* $key */\n";
					foreach $element (@offset5elements)
					{
						my @items = unpack("A100 A100 A100 A100 A100 A50 A150", $element);
					
						print OUT_OFFSETS_TEMP "  $items[1], $items[2], $items[3], $items[4], $items[5], \t\t/* $items[6] */\n";
					}
				}
				else
				{
					print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED "0, \n";
				}
			}
			else
			{
				print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED "0, 0, \n";
			}
		}
		else
		{
			print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED "0, 0, 0, \n";
		}
	}
	else
	{
		print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED "0, 0, 0, 0, \n";
	}
}

# Output file: offsets.temp
die "Could not reopen temp output file offsets.temp: $!\n" unless open(OUT_OFFSETS_TEMP, "<:utf8", "offsets.temp");

while (<OUT_OFFSETS_TEMP>)
{
	print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED $_;
}

close OUT_OFFSETS_TEMP;

print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED "};\n\n";

# Output file: needsguint32.temp
die "Could not create temp output file needsguint32.temp: $!\n" unless open(OUT_NEEDSGUINT32_TEMP, "<:utf8", "needsguint32.temp");

$hadfirstguint32 = 0;
while (<OUT_NEEDSGUINT32_TEMP>)
{
	print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED $_;
	$hadfirstguint32++;
}

$hadfirstguint32 -= 2; # heh

# Final printing of the structure.
print OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED "\n#endif __GTK_IM_CONTEXT_SIMPLE_SEQS_H__\n";

print STDERR "Done writing $main_output_filename\n";

close OUT_GTKIMCONTEXTSIMPLE_UPDATEDOPTIMISED;
close OUT_MULTIPLES;
close OUT_CONFLICTS;

print "\nThe above messages (if any) are for debuging purposes\n";

print "\nWe generated the following\n";
if ( ! -z "multiples.result" )
{
print " - multiples.result, when two different sequences produce the same codepoint. This is warning level. \n";  
}
if ( ! -z "conflicts.result" )
{
print " - conflicts.result, when a sequence repeats itself, producing a different codepoint. Due to this, one compose sequence is hidden. This is error level.\n";
}
printf "\nDone.\n\n";

print "We got two tables, an optimised one with the majority of the data, and a small unoptimised one\n";
print "The optimised table occupies ", $offset * 2, " bytes, while the unoptimised one ", 4 * 6 * $hadfirstguint32, " bytes, in total ", $offset * 2 + 4 * 6 * $hadfirstguint32, "\n";
print "Without optimisation, we would have consumed ", $lines * 4 * 6, " bytes (guint32)\n";

# print "Some stats for you. We have $lines lines, with 6 guint16s per line, total ", $lines * 6 * 2, " bytes\n";
# print "The original gtkimcontextsimple.c file has 847 compose sequences, occupying ", 847 * 6 * 2, " bytes\n";
# print "Offset is $offset\n";
