1#!/usr/bin/perl -w 2# 3# Copyright (c) 2003-2004, Artem B. Bityuckiy, SoftMine Corporation. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions 7# are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 14# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24# SUCH DAMAGE. 25# 26use integer; 27use Getopt::Std; 28use IO::Seekable; 29use strict; 30 31 32# ############################################################################## 33# 34# FUNCTION PROTOTYPES AND GLOBAL DATA DECLARATION SECTION 35# 36# ############################################################################## 37 38 39# SUPPLEMENTARY FUNCTIONS FORWARD DECLARATIONS 40sub ProcessOptions(); 41sub Err($;$); 42sub Generate8bitToUCS(); 43sub GenerateSpeed($); 44sub Generate16bitSize($); 45sub Output8bitToUCS(;$); 46sub Output8bitFromUCS(;$); 47sub OutputSpeed($;$); 48sub OutputSize($;$); 49 50# VARIABLES RELATING TO COMMAND-LINE OPTIONS 51my $Verbose; # Be verbose if true 52my $Source; # Output C source code instead of binary .cct file if true 53my $Plane; # Use this plane if defined 54my $InFile; # Use this file for input 55my $OutFile; # Use this file for output 56my $CCSName; # Use this CCS name 57my $NoSpeed; # Don't generate speed-optimized tables (binary files only) 58my $NoSize; # Don't generate size-optimized tables (binary files only) 59my $NoBE; # Don't generate big-endian tables (binary files only) 60my $NoLE; # Don't generate big-endian tables (binary files only) 61my $NoTo; # Don't generate "to_ucs" table (binary files only) 62my $NoFrom; # Don't generate "from_ucs" table (binary files only) 63my $CCSCol; # CCS column number in source file 64my $UCSCol; # UCS column number in source file 65 66 67# DATA STRUCTURES WITH "TO_UCS" AND "FROM_UCS" SPEED/SIZE -OPTIMIZED TABLES 68my (@FromSpeedTbl, @ToSpeedTbl, @FromSizeTbl, @ToSizeTbl); 69# "TO_UCS" AND "FROM_UCS" SPEED/SIZE -OPTIMIZED TABLES SIZE IN BYTES 70my ($FromSpeedBytes, $ToSpeedBytes, $FromSizeBytes, $ToSizeBytes) = 71 (0, 0, 0, 0); 72 73my (%CCSUCS, %UCSCCS); # CCS->UCS and UCS->CCS mappings 74my $Bits = 8; # Table bits (8 or 16); 75 76# SPECIAL MARKER CODES 77my $InvCode = 0xFFFF; # FFFF indicates 18 bit invalid codes 78my $InvBlock = 0xFFFF; # FFFF also mark empty blocks in speed-optimized tables 79my $LostCode = 0x3F; # ASCII '?' marks codes lost during CCS->UCS mapping 80# To mark invalid codes in 8bit encodings 0xFF is used CCS's 0xFF mapping is saved 81# separately. $FFMap variable stores real 0xFF mapping if defined. 82my $InvCode8bit = 0xFF; 83my $FFMap; 84 85# 8 Bit "From UCS" table header size (bytes) 86my $Hdr8bitFromUCS = 2; 87# Binary table header size (bytes) 88my $HdrBinary = 8; 89 90# At first all lost CCS codes are marked by $TmpLost to distinguish between 91# code which is equivalent to $LostCode and lost codes. This is done in order to 92# output $MacroLostCode instead of $LostCode in source file. 93my $TmpLost = 0x1FFFF; 94 95# VARIABLES RELATING TO C SOURCE CODE 96my $MacroInvCode = 'INVALC'; 97my $MacroInvBlock = 'INVBLK'; 98my $MacroLostCode = 'LOST_C'; 99my $MacroCCSName = 'ICONV_CCS_%s'; 100my $GuardSize = 'defined (TABLE_USE_SIZE_OPTIMIZATION)'; 101my $GuardToUCS = "ICONV_TO_UCS_CCS_%s"; 102my $GuardFromUCS = "ICONV_FROM_UCS_CCS_%s"; 103my $MacroSpeedTable = 'TABLE_SPEED_OPTIMIZED'; 104my $MacroSizeTable = 'TABLE_SIZE_OPTIMIZED'; 105my $Macro8bitTable = 'TABLE_8BIT'; 106my $Macro16bitTable = 'TABLE_16BIT'; 107my $MacroVer1Table = 'TABLE_VERSION_1'; 108my $TypeBICCS = 'iconv_ccs_t'; 109my $VarToUCSSize = "to_ucs_size_%s"; 110my $VarToUCSSpeed = "to_ucs_speed_%s"; 111my $VarFromUCSSize = "from_ucs_size_%s"; 112my $VarFromUCSSpeed = "from_ucs_speed_%s"; 113my $VarBICCS = "_iconv_ccs_%s"; 114# Text block that visually separates tables. 115my $Separator = '=' x 70; 116 117# ############################################################################## 118# 119# SCRIPT ENTRY POINT 120# 121# ############################################################################## 122 123 124# Parse command-line options, check them and set correspondent global variables 125ProcessOptions(); 126 127# Initialize global variables tat depend on CCS name. 128$_ = sprintf $_, $CCSName foreach +($VarToUCSSpeed, 129 $VarToUCSSize, 130 $VarToUCSSpeed, 131 $VarFromUCSSpeed, 132 $VarFromUCSSize, 133 $VarBICCS); 134$_ = sprintf $_, "\U$CCSName" foreach +($GuardToUCS, 135 $GuardFromUCS, 136 $MacroCCSName); 137 138# Open input and output files 139Err "Can't open \"$InFile\" file for reading: $!.\n", 1 140unless open(INFILE, '<', $InFile); 141Err "Can't open \"$OutFile\" file for writing: $!.\n", 1 142unless open(OUTFILE, '>', $OutFile); 143 144# ============================================================================== 145# EXTRACT CODES MAP FROM INPUT FILE 146# ============================================================================== 147 148for (my $ln = 1; my $l = <INFILE>; $ln += 1) 149{ 150 # Skip comment and empty lines, remove ending CR symbol 151 next if $l =~ /^#.*$/ or $l =~ /^\s*$/; 152 $l =~ s/^(.*)\n$/$1/, $l =~ s/^(.*)\r$/$1/; 153 154 # Remove comment and extra spaces 155 $l =~ s/(.*)\s*#.*/$1/; 156 $l =~ s/\s+/ /g; 157 $l =~ s/(.*)\s*$/$1/; 158 159 # Split line into individual codes 160 my @codes = split / /, $l; 161 162 # Skip line if there is no needed columns 163 unless (defined $codes[$CCSCol]) 164 { 165 print("Warning (line $ln): no CCS column, skip.\n") if $Verbose; 166 next; 167 } 168 unless (defined $codes[$UCSCol]) 169 { 170 print("Warning (line $ln): no UCS column, skip.\n") if $Verbose; 171 next; 172 } 173 174 # Extract codes strings from needed columns 175 my ($ccs, $ucs) = ($codes[$CCSCol], $codes[$UCSCol]); 176 my $patt = qr/(0[xX])?[0-9a-fA-F]{1,8}/; # HEX digit regexp pattern. 177 178 # Check that CCS and UCS code strings has right format. 179 unless ($ccs =~ m/^$patt$/) 180 { 181 print("Warning (line $ln): $ccs CCS code isn't recognized, skip.\n") 182 if $Verbose; 183 next; 184 } 185 unless ($ucs =~ m/^($patt(,|\+))*$patt$/) 186 { 187 print("Warning (line $ln): $ucs UCS code isn't recognized, skip.\n") 188 if $Verbose; 189 next; 190 } 191 192 # Convert code to numeric format (assume hex). 193 $ccs = hex $ccs; 194 195 if ($ucs =~ m/,/ or $ucs =~ m/\+/) 196 { 197 # Mark CCS codes with "one to many" mappings as lost 198 printf "Warning (line $ln): only one to one mapping is supported, " 199 . "mark 0x%.4X CCS code as lost.\n", hex $ccs if $Verbose; 200 $ucs = $TmpLost; 201 } 202 else 203 { 204 # Convert code to numeric format 205 $ucs = hex $ucs; 206 207 # Check that UCS code isn't longer than 16 bits. 208 if ($ucs > 0xFFFF) 209 { 210 printf("Warning (line $ln): UCS code should fit 16 bits, " 211 . "mark 0x%.4X CCS code as lost.\n", hex $ccs) if $Verbose; 212 $ucs = $TmpLost; 213 } 214 } 215 216 # If CCS value > 0xFFFF user should specify plane number. 217 if ($ccs > 0xFFFF && !defined $Plane) 218 { 219 print("Warning (line $ln): $ccs is > 16 bit, plane number should be specified," 220 . " skip this mapping.\n") if $Verbose; 221 next; 222 } 223 224 if (defined $Plane) 225 { 226 next if (($ccs & 0xFFFF0000) >> 16) != hex $Plane; # Skip alien plane. 227 $ccs &= 0xFFFF; 228 } 229 230 # Check that reserved codes aren't used. 231 if ($ccs == $InvCode or $ucs == $InvCode) 232 { 233 print("Warning (line $ln): $InvCode is reserved to mark invalid codes and " 234 . "shouldn't be used in mappings, skip.\n") if $Verbose; 235 next; 236 } 237 238 # Save mapping in UCSCCS and CCSUCS hash arrays. 239 $UCSCCS{$ucs} = $ccs if $ucs != $TmpLost && !defined $UCSCCS{$ucs}; 240 $CCSUCS{$ccs} = $ucs if !defined $CCSUCS{$ccs}; 241 242 $Bits = 16 if $ccs > 0xFF; 243} 244 245if (not %CCSUCS) 246{ 247 Err "Error: there is no plane $Plane in \"$0\".\n" if defined $Plane; 248 Err "Error: mapping wasn't found.\n"; 249} 250 251 252# ============================================================================== 253# GENERATE TABLE DATA 254# ============================================================================== 255 256if ($Bits == 8) 257{ 258 $FFMap = $CCSUCS{0xFF}; 259 $FFMap = $InvCode if !defined $FFMap; 260} 261 262if ($Bits == 8) 263{ 264 Generate8bitToUCS() unless $NoTo; 265} 266else 267{ 268 GenerateSpeed("to_ucs") unless $NoTo || $NoSpeed; 269 Generate16bitSize("to_ucs") unless $NoTo || $NoSize; 270} 271 272GenerateSpeed("from_ucs") unless $NoFrom || $NoSpeed; 273Generate16bitSize("from_ucs") unless $NoFrom || $NoSize; 274 275# ============================================================================== 276# OUTPUT ARRAYS 277# ============================================================================== 278 279if ($Source) 280{ 281 # OUTPUT SOURCE 282 print OUTFILE 283"/* 284 * This file was generated automatically - don't edit it. 285 * File contains iconv CCS tables for $CCSName encoding. 286 */ 287 288#include \"ccsbi.h\" 289 290#if defined ($GuardToUCS) \\ 291 || defined ($GuardFromUCS) 292 293#include <_ansi.h> 294#include <sys/types.h> 295#include <sys/param.h> 296#include \"ccs.h\" 297#include \"ccsnames.h\" 298 299"; 300 301 if ($Bits == 8) 302 { 303 print OUTFILE 304"#if (_BYTE_ORDER == _LITTLE_ENDIAN) 305# define W(word) (word) & 0xFF, (word) >> 8 306#elif (_BYTE_ORDER == _BIG_ENDIAN) 307# define W(word) (word) >> 8, (word) & 0xFF 308#else 309# error \"Unknown byte order.\" 310#endif 311 312"; 313 } 314 315 unless ($NoTo) 316 { 317 if ($Bits == 8) 318 { 319 Output8bitToUCS(); 320 } 321 else 322 { 323 OutputSpeed("to_ucs") unless $NoSpeed; 324 OutputSize("to_ucs") unless $NoSize; 325 } 326 } 327 unless ($NoFrom) 328 { 329 if ($Bits == 8) 330 { 331 Output8bitFromUCS(); 332 } 333 else 334 { 335 OutputSpeed("from_ucs") unless $NoSpeed; 336 OutputSize("from_ucs") unless $NoSize; 337 } 338 } 339 340 # OUTPUT TABLE DESCRIPTION STRUCTURE 341 print OUTFILE 342"/* 343 * $CCSName CCS description table. 344 * $Separator 345 */ 346const $TypeBICCS 347$VarBICCS = 348{ 349\t$MacroVer1Table, /* Table version */ 350\t$MacroCCSName, /* CCS name */ 351"; 352 if ($Bits == 8) 353 { 354 print OUTFILE 355"\t$Macro8bitTable, /* Table bits */ 356\t0, /* Not Used */ 357#if defined ($GuardFromUCS) 358\t(__uint16_t *)&$VarFromUCSSpeed, /* UCS -> $CCSName table */ 359#else 360\t(__uint16_t *)NULL, 361#endif 362\t0, /* Not Used */ 363#if defined ($GuardToUCS) 364\t(__uint16_t *)&$VarToUCSSpeed /* $CCSName -> UCS table */ 365#else 366\t(__uint16_t *)NULL, 367#endif 368};\n"; 369 } 370 else 371 { 372 print OUTFILE 373"\t$Macro16bitTable, /* Table bits */ 374#if defined ($GuardFromUCS) \\ 375 && ($GuardSize) 376\t$MacroSizeTable, 377\t(__uint16_t *)&$VarFromUCSSize, /* UCS -> $CCSName table size-optimized table */ 378#elif defined ($GuardFromUCS) \\ 379 && !($GuardSize) 380\t$MacroSpeedTable, 381\t(__uint16_t *)&$VarFromUCSSpeed, /* UCS -> $CCSName table speed-optimized table */ 382#else 383\t$MacroSpeedTable, 384\t(__uint16_t *)NULL, 385#endif 386#if defined ($GuardToUCS) \\ 387 && ($GuardSize) 388\t$MacroSizeTable, 389\t(__uint16_t *)&$VarToUCSSize /* $CCSName -> UCS table speed-optimized table */ 390#elif defined ($GuardToUCS) \\ 391 && !($GuardSize) 392\t$MacroSpeedTable, 393\t(__uint16_t *)&$VarToUCSSpeed /* $CCSName -> UCS table speed-optimized table */ 394#else 395\t$MacroSpeedTable, 396\t(__uint16_t *)NULL, 397#endif 398};\n"; 399 } 400 print OUTFILE "\n#endif /* $GuardToUCS) || ... */\n\n"; 401} 402else 403{ 404 # OUTPUT BINARY TABLES DESCRIPTION STRUCTURE (ALWAYS BIG ENDIAN) 405 print OUTFILE pack "n", 1; 406 print OUTFILE pack "n", $Bits; 407 my $len = length $CCSName; 408 print OUTFILE pack "N", $len; 409 print OUTFILE pack "a$len", $CCSName; 410 411 my $pos = $HdrBinary + $len; 412 if ($pos & 3) 413 { 414 my $l = 4 - ($pos & 3); 415 print OUTFILE pack "a$l", 'XXX'; 416 $pos += $l; 417 } 418 419 $pos += 16*4; 420 421 my @tables; 422 for (my $i = 0; $i < 16; $i++) 423 { 424 $tables[$i] = 0; 425 } 426 427 $tables[0] = $pos, $tables[1] = $FromSpeedBytes, $pos += $FromSpeedBytes 428 unless $NoFrom || $NoSpeed || $NoBE; 429 $tables[2] = $pos, $tables[3] = $FromSpeedBytes, $pos += $FromSpeedBytes 430 unless $NoFrom || $NoSpeed || $NoLE; 431 if ($Bits == 16) 432 { 433 $tables[4] = $pos, $tables[5] = $FromSizeBytes, $pos += $FromSizeBytes 434 unless $NoFrom || $NoSize || $NoBE; 435 $tables[6] = $pos, $tables[7] = $FromSizeBytes, $pos += $FromSizeBytes 436 unless $NoFrom || $NoSize || $NoLE; 437 } 438 $tables[8] = $pos, $tables[9] = $ToSpeedBytes, $pos += $ToSpeedBytes 439 unless $NoTo || $NoSpeed || $NoBE; 440 $tables[10] = $pos, $tables[11] = $ToSpeedBytes, $pos += $ToSpeedBytes 441 unless $NoTo || $NoSpeed || $NoLE; 442 if ($Bits == 16) 443 { 444 $tables[12] = $pos, $tables[13] = $ToSizeBytes, $pos += $ToSizeBytes 445 unless $NoTo || $NoSize || $NoBE; 446 $tables[14] = $pos, $tables[15] = $ToSizeBytes, $pos += $ToSizeBytes 447 unless $NoTo || $NoSize || $NoLE; 448 } 449 450 print OUTFILE pack("N", $_) foreach @tables; 451 452 print "Total bytes for output: $pos.\n" if $Verbose; 453 454 # OUTPUT BINARY TABLES 455 unless ($NoFrom) 456 { 457 if ($Bits == 8) 458 { 459 Output8bitFromUCS("n") unless $NoBE; 460 Output8bitFromUCS("v") unless $NoLE; 461 } 462 else 463 { 464 unless ($NoSpeed) 465 { 466 OutputSpeed("from_ucs", "n") unless $NoBE; 467 OutputSpeed("from_ucs", "v") unless $NoLE; 468 } 469 unless ($NoSize) 470 { 471 OutputSize("from_ucs", "n") unless $NoBE; 472 OutputSize("from_ucs", "v") unless $NoLE; 473 } 474 } 475 } 476 unless ($NoTo) 477 { 478 if ($Bits == 8) 479 { 480 Output8bitToUCS("n") unless $NoBE; 481 Output8bitToUCS("v") unless $NoLE; 482 } 483 else 484 { 485 unless ($NoSpeed) 486 { 487 OutputSpeed("to_ucs", "n") unless $NoBE; 488 OutputSpeed("to_ucs", "v") unless $NoLE; 489 } 490 unless ($NoSize) 491 { 492 OutputSize("to_ucs", "n") unless $NoBE; 493 OutputSize("to_ucs", "v") unless $NoLE; 494 } 495 } 496 } 497} 498 499close INFILE; 500close OUTFILE; 501exit 0; 502 503 504# ############################################################################## 505# 506# SUPPLEMENTARY FUNCTIONS 507# 508# ############################################################################## 509 510 511# ============================================================================= 512# 513# Generate 8bit "to_ucs" table. Store table data in %ToSpeedTbl hash. 514# Store table size in $ToSpeedBytes scalar. 515# 516# ============================================================================= 517sub Generate8bitToUCS() 518{ 519 for (my $i = 0; $i <= 255; $i++) 520 { 521 $ToSpeedTbl[$i] = defined $CCSUCS{$i} ? $CCSUCS{$i} : $InvCode; 522 } 523 $ToSpeedBytes = 256*2; 524} 525 526 527# ============================================================================= 528# 529# Generate speed-optimized table. 530# 531# Parameter 1: 532# "to_ucs" - generate "to_ucs" table, store table data in @ToSpeedTbl 533# array, store table size in $ToSpeedBytes scalar. 534# "from_ucs" - generate "from_ucs" table, store table data in @FromSpeedTbl 535# array, store table size in $FromSpeedBytes scalar. 536# 537# Data is written to @ToSpeedTbl or @FromSpeedTbl (@map) table and has the 538# following format: 539# $table[0] - 256-element array (control block); 540# $table[1 .. $#table] - 256-element arrays (data blocks). 541# 542# ============================================================================= 543sub GenerateSpeed($) 544{ 545 my $map; 546 my $tbl; 547 my $bytes; 548 549 if ($_[0] eq "to_ucs") 550 { 551 $map = \%CCSUCS; 552 $tbl = \@ToSpeedTbl; 553 $bytes = \$ToSpeedBytes; 554 } 555 elsif ($_[0] eq "from_ucs") 556 { 557 $map = \%UCSCCS; 558 $tbl = \@FromSpeedTbl; 559 $bytes = \$FromSpeedBytes; 560 } 561 else 562 { 563 Err "Internal script error in GenerateSpeed()\n"; 564 } 565 566 # Identify unused blocks 567 my @busy_blocks; 568 $busy_blocks[$_ >> 8] = 1 foreach (keys %$map); 569 570 # GENERATE FIRST 256-ELEMENT CONTROL BLOCK 571 for (my $i = 0, 572 my $idx = $Bits == 16 ? 0 : 256 + $Hdr8bitFromUCS; 573 $i <= 0xFF; $i++) 574 { 575 $tbl->[0]->[$i] = $busy_blocks[$i] ? $idx += 256 : undef; 576 } 577 578 # GENERATE DATA BLOCKS 579 $$bytes = 0; 580 for (my $i = 0; $i <= 0xFF; $i++) 581 { 582 next unless $busy_blocks[$i]; 583 $$bytes += 256; 584 for (my $j = 0; $j <= 0xFF; $j++) 585 { 586 $tbl->[$i+1]->[$j] = $map->{($i << 8) | $j}; 587 } 588 } 589 $$bytes *= 2 if $Bits == 16; 590 $$bytes += $Hdr8bitFromUCS if $Bits == 8; 591 $$bytes += 512; 592} 593 594 595# ============================================================================= 596# 597# Generate 16bit size-optimized table. 598# 599# Parameter 1: 600# "to_ucs" - generate "to_ucs" table, store table data in @ToSizeTbl 601# array, store table size in $ToSizeBytes scalar. 602# "from_ucs" - generate "from_ucs" table, store table data in @FromSizeTbl 603# array, store table size in $FromSizeBytes scalar. 604# 605# Data is written to @ToSizeTbl or @FromSizeTbl (@map) table and has the 606# following format: 607# $table[0] - number of ranges; 608# $table[1] - number of unranged codes; 609# $table[2] - unranged codes index in resulting array; 610# $table[3]->[0 .. $table[0]] - array of arrays of ranges: 611# $table[3]->[x]->[0] - first code; 612# $table[3]->[x]->[1] - last code; 613# $table[3]->[x]->[2] - range index in resulting array; 614# $table[4]->[0 .. $table[0]] - array of arrays of ranges content; 615# $table[5]->[0 .. $table[1]] - array of arrays of unranged codes; 616# $table[5]->[x]->[0] - CCS code; 617# $table[5]->[x]->[0] - UCS code; 618# 619# ============================================================================= 620sub Generate16bitSize($) 621{ 622 my $map; 623 my $tbl; 624 my $bytes; 625 626 if ($_[0] eq "to_ucs") 627 { 628 $map = \%CCSUCS; 629 $tbl = \@ToSizeTbl; 630 $bytes = \$ToSizeBytes; 631 } 632 elsif ($_[0] eq "from_ucs") 633 { 634 $map = \%UCSCCS; 635 $tbl = \@FromSizeTbl; 636 $bytes = \$FromSizeBytes; 637 } 638 else 639 { 640 Err "Internal script error Generate16bitSize()\n"; 641 } 642 643 # CREATE LIST OF RANGES. 644 my @codes = sort {$a <=> $b} keys %$map; 645 my @ranges; # Code ranges 646 my @range; # Current working range 647 foreach (@codes) 648 { 649 if (not @range or $_ - 1 == $range[$#range]) 650 { 651 push @range, $_; 652 } 653 else 654 { 655 my @tmp = @range; 656 push @ranges, \@tmp; 657 undef @range; 658 redo; 659 } 660 } 661 # Add Last range too 662 if (@range) 663 { 664 my @tmp = @range; 665 push @ranges, \@tmp; 666 } 667 668 # OPTIMIZE LIST OF RANGES. 669 my $r = 0; # Working range number 670 while (1) 671 { 672 last if ($r == $#ranges); 673 674 my @r1 = @{$ranges[$r]}; 675 my @r2 = @{$ranges[$r + 1]}; 676 677 # Calculate how many array entries two ranges need 678 my ($s1, $s2); 679 680 if ($#r1 == 0) 681 { $s1 = 2; } 682 elsif ($#r1 == 1) 683 { $s1 = 4; } 684 else 685 { $s1 = $#r1 + 1 + 3; } 686 687 if ($#r2 == 0) 688 { $s2 = 2; } 689 elsif ($#r2 == 1) 690 { $s2 = 4; } 691 else 692 { $s2 = $#r2 + 1 + 3; } 693 694 my $two = $s1 + $s2; 695 696 # Calculate how many array entries will be needed if we join them 697 my $one = $r2[$#r2] - $r1[0] + 1 + 3; 698 699 $r += 1, next if ($one > $two); 700 701 # Join ranges 702 my @r; # New range. 703 push @r, $_ foreach (@r1); 704 for (my $i = $r1[$#r1]+1; $i < $r2[0]; $i++) 705 { 706 push @r, undef; 707 } 708 push @r, $_ foreach (@r2); 709 $ranges[$r] = \@r; 710 splice @ranges, $r+1, 1; 711 } 712 713 # SEPARATE RANGED AND UNRANGED CODES. SPLIT 2-CODES RANGES ON 2 UNRANGED. 714 my @unranged; 715 foreach (@ranges) 716 { 717 if ($#$_ == 0) 718 { 719 push @unranged, $$_[0]; 720 undef $_; 721 } 722 elsif ($#$_ == 1) 723 { 724 push @unranged, $$_[0]; 725 push @unranged, $$_[1]; 726 undef $_; 727 } 728 } 729 730 # DELETE UNUSED ELEMENTS 731 for (my $i = 0; $i <= $#ranges; $i++) 732 { 733 splice @ranges, $i--, 1 unless defined $ranges[$i]; 734 } 735 736 # CALCULATE UNRANGED CODES ARRAY INDEX 737 my $idx = 3 + ($#ranges + 1)*3; 738 $idx += $#$_ + 1 foreach @ranges; 739 740 # COMPOSE TABLE 741 $tbl->[0] = $#ranges + 1; # Number of ranges 742 $tbl->[1] = $#unranged + 1; # Number of unranged codes 743 $tbl->[2] = $idx; # Array index of unranged codes 744 745 # Generate ranges list 746 $idx = 3 + ($#ranges + 1)*3; # First range data index 747 $$bytes = $idx*2; 748 my $num = 0; 749 foreach (@ranges) 750 { 751 $tbl->[3]->[$num]->[0] = $_->[0]; 752 $tbl->[3]->[$num]->[1] = $_->[$#$_]; 753 $tbl->[3]->[$num]->[2] = $idx; 754 $idx += $#$_ + 1; 755 $num += 1; 756 } 757 758 # Generate ranges content 759 $num = 0; 760 foreach (@ranges) 761 { 762 for (my $i = 0; $i <= $#$_; $i++) 763 { 764 $tbl->[4]->[$num]->[$i] = defined $_->[$i] ? $map->{$_->[$i]} : undef; 765 } 766 $num += 1; 767 $$bytes += ($#$_ + 1)*2; 768 } 769 770 # Generate unranged codes list 771 $num = 0; 772 foreach (@unranged) 773 { 774 $tbl->[5]->[$num]->[0] = $_; 775 $tbl->[5]->[$num]->[1] = $map->{$_}; 776 $num += 1; 777 } 778 779 $$bytes += ($#unranged + 1)*4; 780} 781 782 783# ============================================================================= 784# 785# Output 8bit "to UCS" table. Output table's source code if $Source 786# and table's binary data if !$Source. 787# 788# Parameter 1: Not used when sources are output. Output BE binary if 'n' and 789# LE binary if 'v'. 790# 791# ============================================================================= 792sub Output8bitToUCS(;$) 793{ 794 my $endian = $_[0]; 795 my $br = 0; 796 797 printf "Output%s 8-bit UCS -> $CCSName table ($ToSpeedBytes bytes).\n", 798 defined $endian ? ($endian eq 'n' ? 799 " Big Endian" : " Little Endian") : "" if $Verbose; 800 if ($Source) 801 { 802 # Output heading information 803 printf OUTFILE 804"/* 805 * 8-bit $CCSName -> UCS table ($ToSpeedBytes bytes). 806 * $Separator 807 */ 808#if defined ($GuardToUCS) 809 810static const __uint16_t 811${VarToUCSSpeed}\[] = 812{\n\t"; 813 } 814 815 if ($Source) 816 { 817 foreach (@ToSpeedTbl) 818 { 819 $br += 1; 820 if ($_ != $InvCode) 821 { 822 if ($_ != $TmpLost) 823 { 824 printf OUTFILE "0x%.4X,", $_; 825 } 826 else 827 { 828 print OUTFILE "$MacroLostCode,"; 829 } 830 } 831 else 832 { 833 print OUTFILE "$MacroInvCode,"; 834 } 835 print(OUTFILE "\n\t"), $br = 0 unless $br % 8; 836 } 837 print OUTFILE "\n};\n\n#endif /* $GuardToUCS */\n\n"; 838 } 839 else 840 { 841 foreach (@ToSpeedTbl) 842 { 843 print OUTFILE pack($endian, $_ == $TmpLost ? $LostCode : $_); 844 } 845 } 846} 847 848 849# ============================================================================= 850# 851# Output 8bit "from UCS" table. Output table's source code if $Source 852# and table's binary data if !$Source. 853# 854# Parameter 1: Not used when sources are output. Output BE binary if 'n' and 855# LE binary if 'v'. 856# 857# ============================================================================= 858sub Output8bitFromUCS(;$) 859{ 860 my $endian = $_[0]; 861 862 printf "Output%s 8-bit $CCSName -> UCS table ($FromSpeedBytes bytes).\n", 863 defined $endian ? ($endian eq 'n' ? 864 " Big Endian" : " Little Endian") : "" if $Verbose; 865 if ($Source) 866 { 867 print OUTFILE 868"/* 869 * 8-bit UCS -> $CCSName speed-optimized table ($FromSpeedBytes bytes). 870 * $Separator 871 */ 872 873#if defined ($GuardFromUCS) 874 875static const unsigned char 876${VarFromUCSSpeed}\[] = 877{ 878"; 879 } 880 881 # SAVE 0xFF MAPPING. 882 if ($Source) 883 { 884 printf OUTFILE "\tW(0x%.4X), /* Real 0xFF mapping. 0xFF is used " 885 . "to mark invalid codes */\n", $FFMap; 886 } 887 else 888 { 889 print OUTFILE pack($endian, $FFMap); 890 } 891 892 # OUTPUT HEADING BLOCK (ALWAYS 16 BIT) 893 if ($Source) 894 { 895 my $count = 0; 896 print OUTFILE "\t/* Heading Block */"; 897 for (my $i = 0, my $br = 0; $i < 256; $br = ++$i % 4) 898 { 899 print OUTFILE "\n\t" unless $br; 900 if (defined $FromSpeedTbl[0]->[$i]) 901 { 902 printf OUTFILE "W(0x%.4X),", $FromSpeedTbl[0]->[$i]; 903 } 904 else 905 { 906 print OUTFILE "W($MacroInvBlock),"; 907 } 908 } 909 } 910 else 911 { 912 print OUTFILE pack($endian, defined $_ ? $_ : $InvBlock) 913 foreach @{$FromSpeedTbl[0]}; 914 } 915 916 if ($Source) 917 { 918 my $index = 512 + $Hdr8bitFromUCS; 919 for (my $blk = 1; $blk <= $#FromSpeedTbl; $blk++) 920 { 921 next unless defined $FromSpeedTbl[$blk]; 922 printf OUTFILE "\n\t/* Block $blk, Array index 0x%.4X */", $index; 923 $index += 256; 924 for (my $i = 0, my $br = 0; $i < 256; $i++, $br = $i % 8) 925 { 926 print OUTFILE "\n\t" unless $br; 927 my $code = $FromSpeedTbl[$blk]->[$i]; 928 if (!defined $code) 929 { 930 printf OUTFILE "0x%.2X,", $InvCode8bit; 931 } 932 else 933 { 934 printf OUTFILE "0x%.2X,", $code == $TmpLost ? $LostCode : $code; 935 } 936 } 937 } 938 print OUTFILE "\n};\n\n#endif /* $GuardFromUCS */\n\n"; 939 } 940 else 941 { 942 for (my $blk = 1; $blk <= $#FromSpeedTbl; $blk++) 943 { 944 next unless defined $FromSpeedTbl[$blk]; 945 for (my $i = 0, my $br = 0; $i < 256; $br = ++$i % 8) 946 { 947 my $code = $FromSpeedTbl[$blk]->[$i]; 948 if (!defined $code) 949 { 950 printf OUTFILE pack 'C', $InvCode8bit; 951 } 952 else 953 { 954 print OUTFILE $code == $TmpLost ? pack('C', $LostCode) 955 : pack('C', $code); 956 } 957 } 958 } 959 } 960} 961 962 963# ============================================================================= 964# 965# Output 16bit Speed-optimized table. Output table's source code if $Source 966# and table's binary data if !$Source. 967# 968# Parameter 1: 969# "to_ucs" - Output "to_ucs" table. 970# "from_ucs" - Output "from_ucs" table. 971# Parameter 2: Not used when sources are output. Output BE binary if 'n' and 972# LE binary if 'v'. 973# 974# ============================================================================= 975sub OutputSpeed($;$) 976{ 977 my $endian = $_[1]; 978 my $tbl; 979 my ($direction, $optimiz, $e, $bytes); 980 $optimiz = $Bits == 16 ? " speed-optimized" : ""; 981 $e = $endian ? ($endian eq 'n' ? " Big Endian" : " Little Endian") : ""; 982 if ($_[0] eq "to_ucs") 983 { 984 $tbl = \@ToSpeedTbl; 985 $direction = " $CCSName -> UCS"; 986 $bytes = $ToSpeedBytes; 987 988 if ($Source) 989 { 990 print OUTFILE 991"/* 992 * 16-bit $CCSName -> UCS speed-optimized table ($ToSpeedBytes bytes). 993 * $Separator 994 */ 995#if defined ($GuardToUCS) \\ 996 && !($GuardSize) 997 998static const __uint16_t 999${VarToUCSSpeed}\[] = 1000{ 1001"; 1002 } 1003 } 1004 elsif ($_[0] eq "from_ucs") 1005 { 1006 $tbl = \@FromSpeedTbl; 1007 $direction = " UCS -> $CCSName"; 1008 $bytes = $FromSpeedBytes; 1009 1010 if ($Source) 1011 { 1012 print OUTFILE 1013"/* 1014 * 16-bit UCS -> $CCSName speed-optimized table ($FromSpeedBytes bytes). 1015 * $Separator 1016 */ 1017 1018#if defined ($GuardFromUCS) \\ 1019 && !($GuardSize) 1020 1021static const __uint16_t 1022${VarFromUCSSpeed}\[] = 1023{ 1024"; 1025 } 1026 } 1027 else 1028 { 1029 Err "Internal script error Output16bitSpeed()\n"; 1030 } 1031 1032 printf "Output%s 16-bit%s%s table (%d bytes).\n", 1033 $e, $direction, $optimiz, $bytes if $Verbose; 1034 1035 # OUTPUT HEADING BLOCK (ALWAYS 16 BIT) 1036 if ($Source) 1037 { 1038 my $count = 0; 1039 print OUTFILE "\t/* Heading Block */"; 1040 for (my $i = 0, my $br = 0; $i < 256; $br = ++$i % 8) 1041 { 1042 print OUTFILE "\n\t" unless $br; 1043 if (defined $tbl->[0]->[$i]) 1044 { 1045 printf OUTFILE "0x%.4X,", $tbl->[0]->[$i]; 1046 } 1047 else 1048 { 1049 print OUTFILE "$MacroInvBlock,"; 1050 } 1051 } 1052 } 1053 else 1054 { 1055 print OUTFILE pack($endian, defined $_ ? $_ : $InvBlock) 1056 foreach @{$tbl->[0]}; 1057 } 1058 1059 # OUTPUT OTHER BLOCKS 1060 if ($Source) 1061 { 1062 my $index = 256; 1063 for (my $blk = 1; $blk <= $#$tbl; $blk++) 1064 { 1065 next unless defined $tbl->[$blk]; 1066 printf OUTFILE "\n\t/* Block $blk, Array index 0x%.4X */", $index; 1067 $index += 256; 1068 for (my $i = 0, my $br = 0; $i < 256; $br = ++$i % 8) 1069 { 1070 print OUTFILE "\n\t" unless $br; 1071 my $code = $tbl->[$blk]->[$i]; 1072 print OUTFILE defined $code ? 1073 ($code == $TmpLost ? $MacroLostCode : sprintf "0x%.4X", $code) 1074 : $MacroInvCode, ","; 1075 } 1076 } 1077 } 1078 else 1079 { 1080 for (my $blk = 1; $blk <= $#$tbl; $blk++) 1081 { 1082 next unless defined $tbl->[$blk]; 1083 for (my $i = 0, my $br = 0; $i < 256; $br = ++$i % 8) 1084 { 1085 my $code = $tbl->[$blk]->[$i]; 1086 print OUTFILE pack($endian, 1087 defined $code ? ($code == $TmpLost ? $LostCode : $code) : $InvCode); 1088 } 1089 } 1090 } 1091 1092 if ($Source) 1093 { 1094 if ($_[0] eq "to_ucs") 1095 { 1096 print OUTFILE 1097" 1098}; 1099 1100#endif /* $GuardToUCS && !$GuardSize */ 1101 1102"; 1103 } 1104 else 1105 { 1106 print OUTFILE 1107" 1108}; 1109 1110#endif /* $GuardFromUCS && !$GuardSize */ 1111 1112"; 1113 } 1114 } 1115} 1116 1117# ============================================================================= 1118# 1119# Output 16bit Size-optimized table. Output table's source code if $Source 1120# and table's binary data if !$Source. 1121# 1122# Parameter 1: 1123# "to_ucs" - Output "to_ucs" table. 1124# "from_ucs" - Output "from_ucs" table. 1125# Parameter 2: Not used when sources are output. Output BE binary if 'n' and 1126# LE binary if 'v'. 1127# 1128# ============================================================================= 1129sub OutputSize($;$) 1130{ 1131 my $endian = $_[1]; 1132 my $tbl; 1133 my ($direction, $optimiz, $e, $bytes); 1134 $optimiz = $Bits == 16 ? " size-optimized" : ""; 1135 $e = $endian ? ($endian eq 'n' ? " Big Endian" : " Little Endian") : ""; 1136 if ($_[0] eq "to_ucs") 1137 { 1138 $tbl = \@ToSizeTbl; 1139 $direction = " $CCSName -> UCS"; 1140 $bytes = $ToSizeBytes; 1141 1142 if ($Source) 1143 { 1144 print OUTFILE 1145"/* 1146 * 16-bit $CCSName -> UCS size-optimized table ($ToSizeBytes bytes). 1147 * $Separator 1148 */ 1149#if defined ($GuardToUCS) \\ 1150 && ($GuardSize) 1151 1152static const __uint16_t 1153${VarToUCSSize}\[] = 1154{ 1155"; 1156 } 1157 } 1158 elsif ($_[0] eq "from_ucs") 1159 { 1160 $tbl = \@FromSizeTbl; 1161 $direction = " UCS -> $CCSName"; 1162 $bytes = $FromSizeBytes; 1163 if ($Source) 1164 { 1165 print OUTFILE 1166"/* 1167 * 16-bit UCS -> $CCSName size-optimized table ($FromSizeBytes bytes). 1168 * $Separator 1169 */ 1170 1171#if defined ($GuardFromUCS) \\ 1172 && ($GuardSize) 1173 1174static const __uint16_t 1175${VarFromUCSSize}\[] = 1176{ 1177"; 1178 } 1179 } 1180 else 1181 { 1182 Err "Internal script error Output16bitSize()\n"; 1183 } 1184 1185 printf "Output%s 16-bit%s%s table (%d bytes).\n", 1186 $e, $direction, $optimiz, $bytes if $Verbose; 1187 1188 # OUTPUT FIRST 3 ELEMENTS 1189 if ($Source) 1190 { 1191 printf OUTFILE "\t0x%.4X, /* Ranges number */\n", $tbl->[0]; 1192 printf OUTFILE "\t0x%.4X, /* Unranged codes number */\n", $tbl->[1]; 1193 printf OUTFILE "\t0x%.4X, /* First unranged code index */\n", $tbl->[2]; 1194 } 1195 else 1196 { 1197 printf OUTFILE pack $endian, $tbl->[0]; 1198 printf OUTFILE pack $endian, $tbl->[1]; 1199 printf OUTFILE pack $endian, $tbl->[2]; 1200 } 1201 1202 my $idx = 0; 1203 # OUTPUT RANGES 1204 if ($Source) 1205 { 1206 print OUTFILE "\t/* Ranges list: first code, last Code, array index. */\n"; 1207 for (my $range = 0; $range <= $#{$tbl->[3]}; $range++) 1208 { 1209 printf OUTFILE "\t/* Array index: 0x%.4X */ 0x%.4X, 0x%.4X, 0x%.4X,\n", 1210 $idx += 3, 1211 $tbl->[3]->[$range]->[0], 1212 $tbl->[3]->[$range]->[1], 1213 $tbl->[3]->[$range]->[2]; 1214 } 1215 } 1216 else 1217 { 1218 for (my $range = 0; $range <= $#{$tbl->[3]}; $range++) 1219 { 1220 print OUTFILE pack($endian, $tbl->[3]->[$range]->[0]), 1221 pack($endian, $tbl->[3]->[$range]->[1]), 1222 pack($endian, $tbl->[3]->[$range]->[2]); 1223 } 1224 } 1225 $idx += 3; 1226 1227 # OUTPUT RANGES CONTENT 1228 if ($Source) 1229 { 1230 print OUTFILE "\t/* Ranges content */"; 1231 for (my $range = 0; $range <= $#{$tbl->[3]}; $range++) 1232 { 1233 printf OUTFILE "\n\t/* Range 0x%.4X - 0x%.4X, array index: 0x%.4X */", 1234 $tbl->[3]->[$range]->[0], $tbl->[3]->[$range]->[1], $idx; 1235 $idx += $tbl->[3]->[$range]->[1] - $tbl->[3]->[$range]->[0] + 1; 1236 for (my $elt = 0, my $br = 0; 1237 $elt <= $#{$tbl->[4]->[$range]}; 1238 $br = ++$elt % 8) 1239 { 1240 print OUTFILE "\n\t" unless $br; 1241 if (defined $tbl->[4]->[$range]->[$elt]) 1242 { 1243 if ($tbl->[4]->[$range]->[$elt] != $TmpLost) 1244 { 1245 printf OUTFILE "0x%.4X,", $tbl->[4]->[$range]->[$elt]; 1246 } 1247 else 1248 { 1249 print OUTFILE "$MacroLostCode,"; 1250 } 1251 } 1252 else 1253 { 1254 print OUTFILE "$MacroInvCode,"; 1255 } 1256 } 1257 } 1258 } 1259 else 1260 { 1261 for (my $range = 0; $range <= $#{$tbl->[3]}; $range++) 1262 { 1263 for (my $elt = 0; $elt <= $#{$tbl->[4]->[$range]}; $elt++) 1264 { 1265 if (defined $tbl->[4]->[$range]->[$elt]) 1266 { 1267 if ($tbl->[4]->[$range]->[$elt] != $TmpLost) 1268 { 1269 print OUTFILE pack $endian, $tbl->[4]->[$range]->[$elt]; 1270 } 1271 else 1272 { 1273 print OUTFILE pack $endian, $LostCode; 1274 } 1275 } 1276 else 1277 { 1278 print OUTFILE pack $endian, $InvCode; 1279 } 1280 } 1281 } 1282 } 1283 1284 # OUTPUT UNRANGED CODES 1285 if ($Source) 1286 { 1287 printf OUTFILE "\n\t/* Unranged codes (%d codes) */", $#{$tbl->[4]} + 1; 1288 for (my $i = 0; $i <= $#{$tbl->[5]}; $i++) 1289 { 1290 printf OUTFILE "\n\t/* Array index: 0x%.4X */ 0x%.4X,0x%.4X,", 1291 $idx, $tbl->[5]->[$i]->[0], $tbl->[5]->[$i]->[1]; 1292 } 1293 } 1294 else 1295 { 1296 for (my $i = 0; $i <= $#{$tbl->[5]}; $i++) 1297 { 1298 print OUTFILE pack($endian, $tbl->[5]->[$i]->[0]), 1299 pack($endian, $tbl->[5]->[$i]->[1]); 1300 } 1301 } 1302 1303 if ($Source) 1304 { 1305 if ($_[0] eq "to_ucs") 1306 { 1307 print OUTFILE 1308" 1309}; 1310 1311#endif /* $GuardToUCS && $GuardSize */ 1312 1313"; 1314 } 1315 else 1316 { 1317 print OUTFILE 1318" 1319}; 1320 1321#endif /* $GuardFromUCS && $GuardSize */ 1322 1323"; 1324 } 1325 } 1326} 1327 1328 1329# ============================================================================= 1330# 1331# Parse command line options 1332# 1333# ============================================================================= 1334sub ProcessOptions() 1335{ 1336 my $help_opt = 'h'; # Print help option 1337 my $input_opt = 'i'; # Input file name option 1338 my $output_opt = 'o'; # Output file name option 1339 my $source_opt = 'S'; # Generate C source file option 1340 my $enc_opt = 'N'; # Encoding name 1341 my $plane_opt = 'p'; # Plane number 1342 my $verbose_opt = 'v'; # Verbose output 1343 my $ccscol_opt = 'x'; # Encoding's column number 1344 my $ucscol_opt = 'y'; # UCS column number 1345 my $nosize_opt = 'l'; # Don't generate size-optimized tables 1346 my $nospeed_opt = 'b'; # Don't generate speed-optimized tables 1347 my $nobe_opt = 'B'; # Don't generate big-endian tables 1348 my $nole_opt = 'L'; # Don't generate big-endian tables 1349 my $noto_opt = 't'; # Don't generate "to_ucs" table 1350 my $nofrom_opt = 'f'; # Don't generate "from_ucs" table 1351 1352 my %args; # Command line arguments found by getopts() 1353 1354 my $getopts_string = 1355 "$help_opt$source_opt$enc_opt:$verbose_opt$input_opt:$output_opt:$plane_opt:" 1356 . "$nosize_opt$nospeed_opt$nobe_opt$nole_opt$noto_opt$nofrom_opt$ccscol_opt:" 1357 . "$ucscol_opt:"; 1358 1359 getopts($getopts_string, \%args) || Err "getopts() failed: $!.\n", 1; 1360 1361 # Print usage rules and exit. 1362 if ($args{$help_opt}) 1363 { 1364 print<<END 1365Usage: 1366 -$help_opt - this help message; 1367 -$input_opt - input file name (required); 1368 -$output_opt - output file name; 1369 -$enc_opt - CCS or encoding name; 1370 -$plane_opt - plane number (high 16 bits) to use (in hex); 1371 -$source_opt - generate C source file; 1372 -$nospeed_opt - don't generate speed-optimized tables (binary files only); 1373 -$nosize_opt - don't generate size-optimized tables (binary files only); 1374 -$nobe_opt - don't generate Big Endian tables (binary files only); 1375 -$nole_opt - don't generate Little Endian tables (binary files only); 1376 -$noto_opt - don't generate "to_ucs" table; 1377 -$nofrom_opt - don't generate "from_ucs" table; 1378 -$ccscol_opt - encoding's column number; 1379 -$ucscol_opt - UCS column number; 1380 -$verbose_opt - verbose output. 1381 1382If output file name isn't specified, <infile>.c (for sources) or 1383<infile>.cct (for binaries) is assumed. 1384If encoding name isn't specified <infile> is assumed. 1385<infile> is normalized (small letters, "-" are substituted by "_") input file 1386name base (no extension). For example, for Koi8-r.txt input file, <infile> 1387is koi8_r. 1388END 1389; 1390 exit 0; 1391 } 1392 1393 $Verbose = $args{$verbose_opt}; 1394 $Source = $args{$source_opt}; 1395 $NoSpeed = $args{$nospeed_opt}; 1396 $NoSize = $args{$nosize_opt}; 1397 $NoBE = $args{$nobe_opt}; 1398 $NoLE = $args{$nole_opt}; 1399 $NoFrom = $args{$nofrom_opt}; 1400 $NoTo = $args{$noto_opt}; 1401 $CCSCol = $args{$ccscol_opt}; 1402 $UCSCol = $args{$ucscol_opt}; 1403 $Plane = $args{$plane_opt}; 1404 $InFile = $args{$input_opt}; 1405 $OutFile = $args{$output_opt}; 1406 $CCSName = $args{$enc_opt}; 1407 1408 Err "Error: input file isn't defined. Use -$help_opt for help.\n", 1 1409 unless $InFile; 1410 1411 unless ($OutFile) 1412 { 1413 # Construct output file name 1414 $OutFile = $InFile; 1415 $OutFile =~ s/(.*\/)*([0-9a-zA-Z-_]*)(\..*)$/\L$2/; 1416 $OutFile =~ tr/-/_/; 1417 if ($Source) 1418 { 1419 $OutFile = "$OutFile.c"; 1420 } 1421 else 1422 { 1423 $OutFile = "$OutFile.cct" 1424 } 1425 } 1426 1427 unless ($CCSName) 1428 { 1429 # Construct CCS name 1430 $CCSName = $InFile; 1431 $CCSName =~ s/(.*\/)*([0-9a-zA-Z-_]*)(\..*)$/\L$2/; 1432 $CCSName =~ tr/-/_/; 1433 } 1434 1435 Err "-$nosize_opt option can't be used with -$nospeed_opt option " 1436 . "simultaniously.\n", 1 if $NoSpeed && $NoSize; 1437 1438 Err "-$nobe_opt option can't be used with -$nole_opt option " 1439 . "simultaniously.\n", 1 if $NoBE && $NoLE; 1440 1441 Err "-$noto_opt option can't be used with -$nofrom_opt option" 1442 . "simultaniously.\n", 1 if $NoTo && $NoFrom; 1443 1444 Err "-$nosize_opt, -$nospeed_opt, -$nobe_opt -$nole_opt " 1445 . "-$noto_opt and -$nofrom_opt " 1446 . "options can't be used with -$source_opt option.\n" 1447 . "Source code always contains both speed- and size-optimized " 1448 . "tables in System Endian. Use -$help_opt for help.\n", 1 1449 if $Source and $NoSpeed || $NoSize || $NoBE || $NoLE || $NoTo || $NoFrom; 1450 1451 if (!$CCSCol && !$UCSCol) 1452 { 1453 $CCSCol = 0; 1454 $UCSCol = 1; 1455 } 1456 elsif ($CCSCol && $UCSCol) 1457 { 1458 Err "Column number should be >= 0\n", 1 if ($CCSCol <= 0 or $UCSCol <= 0); 1459 $CCSCol -= 1; 1460 $UCSCol -= 1; 1461 } 1462 else 1463 { 1464 Err "Please, define both CCS and UCS column numbers\n", 1; 1465 } 1466 1467 if ($Verbose) 1468 { 1469 print "Use $InFile file for input.\n", 1470 "Use $OutFile file for output.\n", 1471 "Use $CCSName as CCS name.\n"; 1472 print "Generate C source file.\n" if $Source; 1473 print "Generate binary file.\n" if !$Source; 1474 printf "Use plane N 0x%.4X.\n", hex $Plane if defined $Plane; 1475 printf "Use column N $CCSCol for $CCSName.\n"; 1476 printf "Use column N $UCSCol for UCS.\n"; 1477 print "Don't generate size-optimized tables.\n" if $NoSize; 1478 print "Don't generate speed-optimized tables.\n" if $NoSpeed; 1479 print "Don't generate big-endian tables.\n" if $NoBE; 1480 print "Don't generate little-endian tables.\n" if $NoLE; 1481 print "Don't generate \"to_ucs\" table.\n" if $NoTo; 1482 print "Don't generate \"from_ucs\" table.\n" if $NoFrom; 1483 } 1484 1485 return; 1486} 1487 1488 1489# ============================================================================= 1490# 1491# Print error message, close all and exit 1492# 1493# Parameter 1: error message 1494# Parameter 2: don't delete output file if > 1 1495# 1496# ============================================================================= 1497sub Err($;$) 1498{ 1499 print STDERR "$_[0]"; 1500 close INFILE; 1501 close OUTFILE; 1502 unlink $OutFile unless $_[1]; 1503 1504 exit 1; 1505}