#!/usr/bin/perl

#
# Find all the modifiers and all the characters that have a
# decomposition mapping.
#
# Note that
#       field[0] is the character point code
#       field[1] is the character name
#       field[2] is the general category and any category beginning
#                "M" is a modifier
#       field[5] is the space separated list of characters that can be
#                used to make this one
#
# We also ignore any character larger than 16 bits.  Also also
# mathematical symbols that combine with 0338 (ie fields[2] eq "Sm"
# and "COMBINING LONG SOLIDUS OVERLAY") as that is used to add a "not"
# to the symbol.
#

#
# In Unicode 4.1.0, the following are missing their decompositions.
# These decompositions may not be correct but they're good for the
# purposes of downgrading.  Note that the trade mark sign (U+2122)
# does decompose to "TM" but not having parentheses is confusing.
#
%missing = (
   "00A9" => "<compat> 0028 0043 0029",      # COPYRIGHT SIGN
   "00AE" => "<compat> 0028 0052 0029",      # REGISTERED SIGN
   "00C6" => "<compat> 0041 0045",           # LATIN CAPITAL LETTER AE
   "00D8" => "<compat> 004F 0338",           # LATIN CAPITAL LETTER O WITH STROKE
   "00DF" => "<compat> 0073 0073",           # LATIN SMALL LETTER SHARP S
   "00E6" => "<compat> 0061 0065",           # LATIN SMALL LETTER AE
   "00F8" => "<compat> 006F 0338",           # LATIN SMALL LETTER O WITH STROKE
   "0131" => "<compat> 0069",                # LATIN SMALL LETTER DOTLESS I
   "0152" => "<compat> 004F 0045",           # LATIN CAPITAL LIGATURE OE
   "0153" => "<compat> 006F 0065",           # LATIN SMALL LIGATURE OE
   "0237" => "<compat> 006A",                # LATIN SMALL LETTER DOTLESS J
   "025F" => "<compat> 006A",                # LATIN SMALL LETTER DOTLESS J WITH STROKE
   "0284" => "<compat> 006A",                # LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK
   "2122" => "<compat> 0028 0054 004D 0029", # TRADE MARK SIGN
);

while (<>) {
  s/ *#.*//;
  next if /^$/;
  @fields = split(/;/);
  next if $fields[0] =~ /...../;
  next if $fields[2] =~ /S[om]/ && $fields[5] =~ /0338/;
  if ($fields[2] =~ /^M/) {
    $modifier{$fields[0]} = $fields[0];
  } else {
    $fields[5] = $missing{$fields[0]} if exists $missing{$fields[0]};
    $composite{$fields[0]} = $fields[5] if $fields[5] ne "";
    $names{$fields[0]} = $fields[1];
  }
}

#
# Now we've got all the composite characters and all the modifiers we
# can generate a table of full decompositions for all characters with
# the modifiers removed.
#
sub decompose {
  my ($base) = @_;
  if (exists $composite{$base}) {
    my ($char, $comp) = ("", "");
    my ($fraction, $circle, $square) = (0, 0);
    foreach $char (split(/ +/, $composite{$base})) {
      if ($char eq "<fraction>") {
	$fraction = 1;
      } elsif ($char eq "<circle>") {
	$circle = 1;
      } elsif ($char eq "<square>") {
	$square = 1;
      } elsif ($char !~ /<.*>/) {
	$comp .= " " . decompose($char) unless exists $modifier{$char};
      }
    }
    $comp =~ s/2044/002F/g if $fraction;
    $comp = "0028 " . $comp . " 0029" if $circle;
    $comp = "005B " . $comp . " 005D" if $square;
    $comp =~ s/^ *//;
    $comp =~ s/ +/ /g;
    return $comp;
  } else {
    return $base;
  }
}

sub ascii {
  my ($chars) = @_;
  my ($char, $str);
  $str = "";
  foreach $char (split(/ /, "0x" . join(" 0x", split(/ +/, $chars)))) {
    eval "\$char = $char"; # convert to an integer
    if ($char < 0x7f) {
      $str .= sprintf("%c", $char);
    } else {
      return "";
    }
  }
  return ($str eq "()") ? "" : $str;
}

foreach $char (sort keys %composite) {
  $x = $composite{$char};
  $x =~ s/<.*> *//;
  $y = decompose($char);
  next if $y eq "";
  $z = ascii($y);
  if ($z ne "") {
    $z =~ s/([\\\"])/\\$1/g;
    if (defined($map{$z})) {
      $map{$z} .= " " . $char;
    } else {
      $map{$z} = $char;
    }
  }
}

foreach $str (sort keys %map) {
  foreach $char (split(/ /, $map{$str})) {
    print "            case '\\u$char': /* $names{$char} */\n";
  }
  print "                output.append(\"$str\"); break;\n";
}

