#!/usr/bin/env perl
# Copyright (C) 2023,2024 Free Software Foundation, Inc.
# This file is part of LibreDWG.
# Created from scratch by Reini Urban
# for t in *.TXT; do ./txt2h.pl $t >`basename $t .TXT`.h; done

use strict;
use warnings;
use File::Basename qw( basename );
my $in = shift;
open my $F, $in or die;

$in = basename $in, '.TXT';

# $in =~ s/\.TXT$//;
$in =~ s/-/_/g;
$in = lc $in;
print "/* ex: set ro ft=c: -*- mode: c; buffer-read-only: t -*- */\n";
print "// Copyright (C) 2023,2024 Free Software Foundation, Inc.\n";
print "// This file is part of LibreDWG.\n";
print "// Created from scratch by Reini Urban\n";
print "// Generated by txt2h.pl.\n\n";
print "#include <stdint.h>\n\n";
print "/* unsorted rhs values */\n";
print "static const uint16_t cptbl_$in\[\] = {\n";

my ( $los, $his, $lod, $hid, @out, @exclow ) = ( 0xffff, 0, 0xffff, 0 );
my @alnum;
my $lastsrc = 0;

sub add_line {
    my ( $arr, $src, $d, $cmt ) = @_;
    for ( my $i = $lastsrc + 1; $i < hex($src); $i++ ) {
        push @$arr, sprintf( "  /*[0x%x] = */%u,\n", $i, $i < 127 ? $i : 0 );
    }
    push @$arr, "  /*[$src] = */$d,$cmt\n";
    $lastsrc = hex($src);
}

sub add_alnum {
    my ( $arr, $src, $d, $cmt ) = @_;
    push @$arr, "  $src,$cmt\n";
}

LINE:
while (<$F>) {
    /^#/ and next;
    next unless /^(0x[0-9a-fA-F]+)\s+(0x[0-9a-fA-F]+)(.*)/;
    my $src = $1;
    my $d   = $2;
    my $cmt = $3;
    my $sn  = hex($src);
    my $dn  = hex($d);
    $cmt =~ s/\t#//;

    if ($cmt) {
        $cmt = "\t// $cmt";
    }
    if ( $sn > 0x7f and / (LETTER|DIGIT) / ) {
        add_alnum( \@alnum, $src, $d, $cmt );
    }
    if ( $sn <= 0x7f and $sn != $dn ) {

        # exceptions
        if (   ( $in eq 'johab' and $src eq '0x5C' )
            or ( $in eq 'cp932' and $src eq '0x5C' )
            or ( $in eq 'cp932' and $src eq '0x7E' )
            or ( $in eq 'cp864' and $src eq '0x25' ) )
        {
            warn "$in: $src != $d\n";
            add_line( \@out,    $src, $d, $cmt );
            add_line( \@exclow, $src, $d, $cmt );
        }
        else {
            die "$in: $src != $d";
        }
    }
    $los = $sn if $sn < $los;
    $his = $sn if $sn > $his;
    $lod = $dn if $dn < $lod;
    $hid = $dn if $dn > $hid;
    if ( $sn > 0x7f ) {
        add_line( \@out, $src, $d, $cmt );
    }
}

print "  /*[0x0] = */$his,\t// size of vector\n";
print $_ for @out;
print "};\n";

my $type = 'uint16_t';
if ( $his < 256 ) {
    $type = 'uint8_t';
}
print "/* sorted, without the first 127 characters */\n";
print "static const $type cptbl_alnum_$in\[\] = {\n";
printf( "  %u,\t\t// size of vector\n", scalar @alnum );
print $_ for @alnum;
print "};\n";

print "#define MIN_", uc $in, "\t$los\n";
print "#define MAX_", uc $in, "\t$his\n";
print "#define MIN_", uc $in, "_UC\t$lod\n";
print "#define MAX_", uc $in, "_UC\t$hid\n";
if (@exclow) {
    print "#if 0\n";
    print "/* Exceptions, already integrated above. */\n";
    print "static const uint16_t cptbl_exc_$in\[\] = {\n";
    print $_ for @exclow;
    print "};\n";
    print "#endif\n";
}
