1f2e35a3aSmrg#!/usr/bin/perl -w 204b94745Smrg# $XTermId: print-vt-chars.pl,v 1.23 2020/12/13 15:05:06 tom Exp $ 3f2e35a3aSmrg# ----------------------------------------------------------------------------- 4f2e35a3aSmrg# this file is part of xterm 5f2e35a3aSmrg# 6f2e35a3aSmrg# Copyright 2018,2020 by Thomas E. Dickey 7f2e35a3aSmrg# 8f2e35a3aSmrg# All Rights Reserved 9f2e35a3aSmrg# 10f2e35a3aSmrg# Permission is hereby granted, free of charge, to any person obtaining a 11f2e35a3aSmrg# copy of this software and associated documentation files (the 12f2e35a3aSmrg# "Software"), to deal in the Software without restriction, including 13f2e35a3aSmrg# without limitation the rights to use, copy, modify, merge, publish, 14f2e35a3aSmrg# distribute, sublicense, and/or sell copies of the Software, and to 15f2e35a3aSmrg# permit persons to whom the Software is furnished to do so, subject to 16f2e35a3aSmrg# the following conditions: 17f2e35a3aSmrg# 18f2e35a3aSmrg# The above copyright notice and this permission notice shall be included 19f2e35a3aSmrg# in all copies or substantial portions of the Software. 20f2e35a3aSmrg# 21f2e35a3aSmrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22f2e35a3aSmrg# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23f2e35a3aSmrg# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24f2e35a3aSmrg# IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 25f2e35a3aSmrg# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 26f2e35a3aSmrg# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 27f2e35a3aSmrg# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28f2e35a3aSmrg# 29f2e35a3aSmrg# Except as contained in this notice, the name(s) of the above copyright 30f2e35a3aSmrg# holders shall not be used in advertising or otherwise to promote the 31f2e35a3aSmrg# sale, use or other dealings in this Software without prior written 32f2e35a3aSmrg# authorization. 33f2e35a3aSmrg# ----------------------------------------------------------------------------- 34f2e35a3aSmrg# Print GL and GR, with the same charset (if possible) for testing. 35f2e35a3aSmrg 36f2e35a3aSmrguse strict; 37f2e35a3aSmrguse warnings; 38f2e35a3aSmrg 39f2e35a3aSmrg$| = 2; 40f2e35a3aSmrg 41f2e35a3aSmrguse Getopt::Std; 42f2e35a3aSmrg 43f2e35a3aSmrgour ( $opt_L, $opt_l, $opt_R, $opt_r, $opt_v ); 44f2e35a3aSmrg 45f2e35a3aSmrgour %charsets; 46f2e35a3aSmrgour %caseless; 47f2e35a3aSmrgour $vt_level; 48f2e35a3aSmrg 49f2e35a3aSmrgbinmode STDOUT; 50f2e35a3aSmrg 51f2e35a3aSmrgsub NRC($) { 52f2e35a3aSmrg printf "\033[?42%s", $_[0] ? "h" : "l"; 53f2e35a3aSmrg} 54f2e35a3aSmrg 55f2e35a3aSmrgsub LS0($) { 56f2e35a3aSmrg printf "\017"; 57f2e35a3aSmrg} 58f2e35a3aSmrg 59f2e35a3aSmrgsub LS1() { 60f2e35a3aSmrg printf "\016"; 61f2e35a3aSmrg} 62f2e35a3aSmrg 63f2e35a3aSmrgsub LS1R() { 64f2e35a3aSmrg printf "\033~"; 65f2e35a3aSmrg} 66f2e35a3aSmrg 67f2e35a3aSmrgsub LS2() { 68f2e35a3aSmrg printf "\033n"; 69f2e35a3aSmrg} 70f2e35a3aSmrg 71f2e35a3aSmrgsub LS2R() { 72f2e35a3aSmrg printf "\033}"; 73f2e35a3aSmrg} 74f2e35a3aSmrg 75f2e35a3aSmrgsub LS3() { 76f2e35a3aSmrg printf "\033o"; 77f2e35a3aSmrg} 78f2e35a3aSmrg 79f2e35a3aSmrgsub LS3R($) { 80f2e35a3aSmrg printf "\033|"; 81f2e35a3aSmrg} 82f2e35a3aSmrg 83f2e35a3aSmrgsub G0($) { 84f2e35a3aSmrg my %charset = %{ $_[0] }; 85f2e35a3aSmrg printf "\033(%s", $charset{TAG} if ( $charset{HOW} == 0 ); 86f2e35a3aSmrg} 87f2e35a3aSmrg 88f2e35a3aSmrgsub G1($) { 89f2e35a3aSmrg my %charset = %{ $_[0] }; 90f2e35a3aSmrg printf "\033)%s", $charset{TAG} if ( $charset{HOW} == 0 ); 91f2e35a3aSmrg printf "\033-%s", $charset{TAG} if ( $charset{HOW} == 1 ); 92f2e35a3aSmrg} 93f2e35a3aSmrg 94f2e35a3aSmrgsub G2($) { 95f2e35a3aSmrg my %charset = %{ $_[0] }; 96f2e35a3aSmrg printf "\033*%s", $charset{TAG} if ( $charset{HOW} == 0 ); 97f2e35a3aSmrg printf "\033.%s", $charset{TAG} if ( $charset{HOW} == 1 ); 98f2e35a3aSmrg} 99f2e35a3aSmrg 100f2e35a3aSmrgsub G3($) { 101f2e35a3aSmrg my %charset = %{ $_[0] }; 102f2e35a3aSmrg printf "\033+%s", $charset{TAG} if ( $charset{HOW} == 0 ); 103f2e35a3aSmrg printf "\033/%s", $charset{TAG} if ( $charset{HOW} == 1 ); 104f2e35a3aSmrg} 105f2e35a3aSmrg 106f2e35a3aSmrgsub init_charset($$$$$$) { 107f2e35a3aSmrg my %charset; 108f2e35a3aSmrg my $mixed = shift; 109f2e35a3aSmrg $charset{WHO} = $mixed; 110f2e35a3aSmrg $charset{HOW} = shift; 111f2e35a3aSmrg $charset{TAG} = shift; 112f2e35a3aSmrg $charset{MIN} = shift; 113f2e35a3aSmrg $charset{MAX} = shift; 114f2e35a3aSmrg $charset{NRC} = shift; 115f2e35a3aSmrg $charsets{$mixed} = \%charset; 116f2e35a3aSmrg my $lower = lc $charset{WHO}; 117f2e35a3aSmrg $caseless{$lower} = $charset{WHO}; 118f2e35a3aSmrg} 119f2e35a3aSmrg 120f2e35a3aSmrgsub find_charset($) { 121f2e35a3aSmrg my $mixed = shift; 122f2e35a3aSmrg my $lower = lc $mixed; 123f2e35a3aSmrg my %result; 124f2e35a3aSmrg if ( $caseless{$lower} ) { 125f2e35a3aSmrg $mixed = $caseless{$lower}; 126f2e35a3aSmrg %result = %{ $charsets{$mixed} }; 127f2e35a3aSmrg undef %result 128f2e35a3aSmrg if ( $result{MAX} < $vt_level or $result{MIN} > $vt_level ); 129f2e35a3aSmrg } 130f2e35a3aSmrg printf STDERR "? no match for $mixed with VT-level $vt_level\n" 131f2e35a3aSmrg unless %result; 132f2e35a3aSmrg return \%result; 133f2e35a3aSmrg} 134f2e35a3aSmrg 135f2e35a3aSmrgsub failed($) { 136f2e35a3aSmrg my $msg = shift; 137f2e35a3aSmrg printf STDERR "? %s\n", $msg; 138f2e35a3aSmrg exit 1; 139f2e35a3aSmrg} 140f2e35a3aSmrg 141f2e35a3aSmrgsub valid_code($) { 142f2e35a3aSmrg my $code = shift; 143f2e35a3aSmrg my $result = 0; 144f2e35a3aSmrg $result = 1 if ( $code =~ /^[0-3]$/ ); 145f2e35a3aSmrg return $result; 146f2e35a3aSmrg} 147f2e35a3aSmrg 148f2e35a3aSmrgsub valid_name($) { 149f2e35a3aSmrg my $mixed = shift; 150f2e35a3aSmrg my $lower = lc $mixed; 151f2e35a3aSmrg my $result = 0; 152f2e35a3aSmrg $result = 1 if ( defined( $caseless{$lower} ) ); 153f2e35a3aSmrg return $result; 154f2e35a3aSmrg} 155f2e35a3aSmrg 156f2e35a3aSmrgsub setup_charsets($$$$) { 157f2e35a3aSmrg my $gl_code = shift; 158f2e35a3aSmrg my $gl_name = shift; 159f2e35a3aSmrg my $gr_code = shift; 160f2e35a3aSmrg my $gr_name = shift; 161f2e35a3aSmrg my %gl_data = %{ &find_charset($gl_name) }; 162f2e35a3aSmrg my %gr_data = %{ &find_charset($gr_name) }; 163f2e35a3aSmrg 164f2e35a3aSmrg return 0 unless %gl_data; 165f2e35a3aSmrg return 0 unless %gr_data; 166f2e35a3aSmrg 167f2e35a3aSmrg &NRC(1) if ( $gl_data{NRC} or $gr_data{NRC} ); 168f2e35a3aSmrg 169f2e35a3aSmrg if ( $gl_code == 0 ) { 170f2e35a3aSmrg &G0( \%gl_data ); 171f2e35a3aSmrg &LS0; 172f2e35a3aSmrg } 173f2e35a3aSmrg elsif ( $gl_code == 1 ) { 174f2e35a3aSmrg &G1( \%gl_data ); 175f2e35a3aSmrg &LS1; 176f2e35a3aSmrg } 177f2e35a3aSmrg elsif ( $gl_code == 2 ) { 178f2e35a3aSmrg &G2( \%gl_data ); 179f2e35a3aSmrg &LS2; 180f2e35a3aSmrg } 181f2e35a3aSmrg elsif ( $gl_code == 3 ) { 182f2e35a3aSmrg &G3( \%gl_data ); 183f2e35a3aSmrg &LS3; 184f2e35a3aSmrg } 185f2e35a3aSmrg 186f2e35a3aSmrg if ( $gr_code == 0 ) { 187f2e35a3aSmrg &G0( \%gr_data ); 188f2e35a3aSmrg } 189f2e35a3aSmrg elsif ( $gr_code == 1 ) { 190f2e35a3aSmrg &G1( \%gr_data ); 191f2e35a3aSmrg &LS1R; 192f2e35a3aSmrg } 193f2e35a3aSmrg elsif ( $gr_code == 2 ) { 194f2e35a3aSmrg &G2( \%gr_data ); 195f2e35a3aSmrg &LS2R; 196f2e35a3aSmrg } 197f2e35a3aSmrg elsif ( $gr_code == 3 ) { 198f2e35a3aSmrg &G3( \%gr_data ); 199f2e35a3aSmrg &LS3R; 200f2e35a3aSmrg } 201f2e35a3aSmrg return 1; 202f2e35a3aSmrg} 203f2e35a3aSmrg 204f2e35a3aSmrgsub cleanup() { 205f2e35a3aSmrg &setup_charsets( 0, "ASCII", 1, "ASCII" ); 206f2e35a3aSmrg &NRC(0); 207f2e35a3aSmrg} 208f2e35a3aSmrg 209f2e35a3aSmrgsub doit($$$$) { 210f2e35a3aSmrg my $gl_code = shift; 211f2e35a3aSmrg my $gl_name = shift; 212f2e35a3aSmrg my $gr_code = shift; 213f2e35a3aSmrg my $gr_name = shift; 214f2e35a3aSmrg 215f2e35a3aSmrg &failed("Illegal left-code $gl_code") unless &valid_code($gl_code); 216f2e35a3aSmrg &failed("Illegal right-code $gr_code") unless &valid_code($gr_code); 217f2e35a3aSmrg &failed("Unknown left-charset $gl_name") unless &valid_name($gl_name); 218f2e35a3aSmrg &failed("Unknown right charset $gr_name") unless &valid_name($gr_name); 219f2e35a3aSmrg 220f2e35a3aSmrg printf "GL (G%d %s):\n", $gl_code, $gl_name; 221f2e35a3aSmrg if ( &setup_charsets( $gl_code, $gl_name, $gr_code, $gr_name ) ) { 222f2e35a3aSmrg 223f2e35a3aSmrg for my $c ( 32 .. 127 ) { 224f2e35a3aSmrg printf "%c", $c; 225f2e35a3aSmrg printf "\n" if ( ( ( $c - 31 ) % 16 ) == 0 ); 226f2e35a3aSmrg } 227f2e35a3aSmrg printf "\n"; 228f2e35a3aSmrg 229f2e35a3aSmrg &cleanup; 230f2e35a3aSmrg } 231f2e35a3aSmrg 232f2e35a3aSmrg printf "GR (G%d %s):\n", $gr_code, $gr_name; 233f2e35a3aSmrg if ( &setup_charsets( $gl_code, $gl_name, $gr_code, $gr_name ) ) { 234f2e35a3aSmrg 235f2e35a3aSmrg for my $c ( 32 .. 127 ) { 236f2e35a3aSmrg printf "%c", $c + 128; 237f2e35a3aSmrg printf "\n" if ( ( ( $c - 31 ) % 16 ) == 0 ); 238f2e35a3aSmrg } 239f2e35a3aSmrg printf "\n"; 240f2e35a3aSmrg 241f2e35a3aSmrg &cleanup; 242f2e35a3aSmrg } 243f2e35a3aSmrg} 244f2e35a3aSmrg 245f2e35a3aSmrgsub main::HELP_MESSAGE() { 246f2e35a3aSmrg printf STDERR <<EOF 247f2e35a3aSmrgUsage: $0 [options] 248f2e35a3aSmrg 249f2e35a3aSmrgOptions: 250f2e35a3aSmrg 251f2e35a3aSmrg -L code index 0-3 for GL 252f2e35a3aSmrg -l name charset to map to GL 253f2e35a3aSmrg -R code index 0-3 for GR 254f2e35a3aSmrg -r name charset to map to GR 255f2e35a3aSmrg -v level set/override VT-level 256f2e35a3aSmrg 257f2e35a3aSmrgCharsets are determined by the VT-level (currently VT${vt_level}xx): 258f2e35a3aSmrgEOF 259f2e35a3aSmrg ; 260f2e35a3aSmrg my @known; 261f2e35a3aSmrg my $known = -1; 262f2e35a3aSmrg my $width = 0; 263f2e35a3aSmrg foreach my $key ( sort( keys %charsets ) ) { 264f2e35a3aSmrg my %charset = %{ $charsets{$key} }; 265f2e35a3aSmrg next if ( $charset{MAX} < $vt_level ); 266f2e35a3aSmrg next if ( $charset{MIN} > $vt_level ); 267f2e35a3aSmrg $known[ ++$known ] = $key; 268f2e35a3aSmrg $width = length($key) if ( length($key) > $width ); 269f2e35a3aSmrg } 270f2e35a3aSmrg $width += 3; 271f2e35a3aSmrg my $cols = int( 78 / $width ); 272f2e35a3aSmrg my $high = int( ( $known + $cols ) / $cols ); 273f2e35a3aSmrg for my $y ( 0 .. $high - 1 ) { 274f2e35a3aSmrg printf STDERR " "; 275f2e35a3aSmrg for my $x ( 0 .. $cols - 1 ) { 276f2e35a3aSmrg my $z = $x * $high + $y; 277f2e35a3aSmrg next if ( $z > $known ); 278f2e35a3aSmrg printf STDERR "%-*s", $width, $known[$z]; 279f2e35a3aSmrg } 280f2e35a3aSmrg printf STDERR "\n"; 281f2e35a3aSmrg } 282f2e35a3aSmrg exit 1; 283f2e35a3aSmrg} 284f2e35a3aSmrg 285f2e35a3aSmrg&init_charset( "ASCII", 0, 'B', 1, 9, 0 ); 286f2e35a3aSmrg&init_charset( "British", 0, 'A', 1, 9, 0 ); 287f2e35a3aSmrg&init_charset( "DEC_Spec_Graphic", 0, '0', 1, 9, 0 ); 288f2e35a3aSmrg&init_charset( "DEC_Alt_Chars", 0, '1', 1, 1, 0 ); 289f2e35a3aSmrg&init_charset( "DEC_Alt_Graphics", 0, '2', 1, 1, 0 ); 290f2e35a3aSmrg&init_charset( "DEC_Supp", 0, '<', 2, 9, 0 ); 291f2e35a3aSmrg&init_charset( "Dutch", 0, '4', 2, 9, 1 ); 292f2e35a3aSmrg&init_charset( "Finnish", 0, '5', 2, 9, 1 ); 293f2e35a3aSmrg&init_charset( "Finnish2", 0, 'C', 2, 9, 1 ); 294f2e35a3aSmrg&init_charset( "French", 0, 'R', 2, 9, 1 ); 295f2e35a3aSmrg&init_charset( "French2", 0, 'f', 2, 9, 1 ); 296f2e35a3aSmrg&init_charset( "French_Canadian", 0, 'Q', 2, 9, 1 ); 297f2e35a3aSmrg&init_charset( "German", 0, 'K', 2, 9, 1 ); 298f2e35a3aSmrg&init_charset( "Italian", 0, 'Y', 2, 9, 1 ); 299f2e35a3aSmrg&init_charset( "Norwegian_Danish2", 0, 'E', 2, 9, 1 ); 300f2e35a3aSmrg&init_charset( "Norwegian_Danish3", 0, '6', 2, 9, 1 ); 301f2e35a3aSmrg&init_charset( "Spanish", 0, 'Z', 2, 9, 1 ); 302f2e35a3aSmrg&init_charset( "Swedish", 0, '7', 2, 9, 1 ); 303f2e35a3aSmrg&init_charset( "Swedish2", 0, 'H', 2, 9, 1 ); 304f2e35a3aSmrg&init_charset( "Swiss", 0, '=', 2, 9, 1 ); 305f2e35a3aSmrg&init_charset( "British_Latin_1", 0, 'A', 3, 9, 1 ); 306f2e35a3aSmrg&init_charset( "DEC_Supp_Graphic", 0, '%5', 3, 9, 0 ); 307f2e35a3aSmrg&init_charset( "DEC_Technical", 0, '>', 3, 9, 0 ); 308f2e35a3aSmrg&init_charset( "French_Canadian2", 0, '9', 3, 9, 1 ); 309f2e35a3aSmrg&init_charset( "Norwegian_Danish", 0, '`', 3, 9, 1 ); 310f2e35a3aSmrg&init_charset( "Portuguese", 0, '%6', 3, 9, 1 ); 311f2e35a3aSmrg&init_charset( "ISO_Greek_Supp", 1, 'F', 5, 9, 0 ); 312f2e35a3aSmrg&init_charset( "ISO_Hebrew_Supp", 1, 'H', 5, 9, 0 ); 313f2e35a3aSmrg&init_charset( "ISO_Latin_5_Supp", 1, 'M', 5, 9, 0 ); 314f2e35a3aSmrg&init_charset( "ISO_Latin_Cyrillic", 1, 'L', 5, 9, 0 ); 315f2e35a3aSmrg&init_charset( "Greek", 0, '">', 5, 9, 1 ); 316f2e35a3aSmrg&init_charset( "DEC_Greek", 0, '"?', 5, 9, 1 ); 317f2e35a3aSmrg&init_charset( "Cyrillic", 0, '&4', 5, 9, 0 ); 318f2e35a3aSmrg&init_charset( "DEC_Hebrew", 0, '"4', 5, 9, 0 ); 319f2e35a3aSmrg&init_charset( "Hebrew", 0, '%=', 5, 9, 1 ); 320f2e35a3aSmrg&init_charset( "Russian", 0, '&5', 5, 9, 1 ); 321f2e35a3aSmrg&init_charset( "SCS_NRCS", 0, '%3', 5, 9, 0 ); 322f2e35a3aSmrg&init_charset( "Turkish", 0, '%2', 5, 9, 1 ); 323f2e35a3aSmrg&init_charset( "DEC_Turkish", 0, '%0', 5, 9, 0 ); 324f2e35a3aSmrg 325f2e35a3aSmrg$vt_level = 1; # don't expect much 326f2e35a3aSmrgif ( -t 0 and -t 1 ) { 327f2e35a3aSmrg my $da2 = ` 328f2e35a3aSmrg old=\$(stty -g); 329f2e35a3aSmrg stty raw -echo min 0 time 5; 330f2e35a3aSmrg printf '\033[>c' >/dev/tty; 331f2e35a3aSmrg read response; 332f2e35a3aSmrg stty \$old; 333f2e35a3aSmrg echo "\$response"`; 334f2e35a3aSmrg if ( $da2 =~ /^\033\[>\d+;\d+;\d+c$/ ) { 335f2e35a3aSmrg my $Pp = $da2; 336f2e35a3aSmrg $Pp =~ s/^.*>//; 337f2e35a3aSmrg $Pp =~ s/;.*$//; 338f2e35a3aSmrg if ( $Pp == 0 ) { 339f2e35a3aSmrg $vt_level = 1; 340f2e35a3aSmrg } 341f2e35a3aSmrg elsif ( $Pp == 1 or $Pp == 2 ) { 342f2e35a3aSmrg $vt_level = 2; 343f2e35a3aSmrg } 344f2e35a3aSmrg elsif ( $Pp == 18 or $Pp == 19 or $Pp == 24 ) { 345f2e35a3aSmrg $vt_level = 3; 346f2e35a3aSmrg } 347f2e35a3aSmrg elsif ( $Pp == 41 ) { 348f2e35a3aSmrg $vt_level = 4; 349f2e35a3aSmrg } 350f2e35a3aSmrg elsif ( $Pp == 61 or $Pp == 64 or $Pp == 65 ) { 351f2e35a3aSmrg $vt_level = 5; 352f2e35a3aSmrg } 353f2e35a3aSmrg } 354f2e35a3aSmrg} 355f2e35a3aSmrg 356f2e35a3aSmrg$Getopt::Std::STANDARD_HELP_VERSION = 1; 357f2e35a3aSmrg&getopts('L:l:R:r:v:') || main::HELP_MESSAGE; 358f2e35a3aSmrg$vt_level = $opt_v if ( defined $opt_v ); 359f2e35a3aSmrg&failed("VT-level must be 1-5") if ( $vt_level < 1 or $vt_level > 5 ); 360f2e35a3aSmrg 361f2e35a3aSmrgif ( $#ARGV >= 0 ) { 362f2e35a3aSmrg while ( $#ARGV >= 0 ) { 363f2e35a3aSmrg my $name = shift @ARGV; 364f2e35a3aSmrg &doit( 365f2e35a3aSmrg defined($opt_L) ? $opt_L : 2, # 366f2e35a3aSmrg defined($opt_l) ? $opt_l : $name, # 367f2e35a3aSmrg defined($opt_R) ? $opt_R : 3, # 368f2e35a3aSmrg defined($opt_r) ? $opt_r : $name 369f2e35a3aSmrg ); 370f2e35a3aSmrg last 371f2e35a3aSmrg if ( 372f2e35a3aSmrg defined($opt_L) # 373f2e35a3aSmrg and defined($opt_l) # 374f2e35a3aSmrg and defined($opt_R) # 375f2e35a3aSmrg and defined($opt_r) 376f2e35a3aSmrg ); 377f2e35a3aSmrg } 378f2e35a3aSmrg} 379f2e35a3aSmrgelse { 380f2e35a3aSmrg &doit( 381f2e35a3aSmrg defined($opt_L) ? $opt_L : 2, # 382f2e35a3aSmrg defined($opt_l) ? $opt_l : "ASCII", # 383f2e35a3aSmrg defined($opt_R) ? $opt_R : 3, # 384f2e35a3aSmrg defined($opt_r) ? $opt_r : "ASCII" 385f2e35a3aSmrg ); 386f2e35a3aSmrg} 387f2e35a3aSmrg 388f2e35a3aSmrg1; 389