query-dynamic.pl revision 04b94745
1f2e35a3aSmrg#!/usr/bin/env perl
204b94745Smrg# $XTermId: query-dynamic.pl,v 1.6 2019/05/19 08:56:11 tom Exp $
3f2e35a3aSmrg# -----------------------------------------------------------------------------
4f2e35a3aSmrg# this file is part of xterm
5f2e35a3aSmrg#
6f2e35a3aSmrg# Copyright 2019 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# Test the color-query features of xterm for dynamic-colors
35f2e35a3aSmrg
36f2e35a3aSmrguse strict;
37f2e35a3aSmrguse warnings;
38f2e35a3aSmrg
39f2e35a3aSmrguse Getopt::Std;
40f2e35a3aSmrguse IO::Handle;
41f2e35a3aSmrg
42f2e35a3aSmrgour ( $opt_q, $opt_s, $opt_8 );
43f2e35a3aSmrg
44f2e35a3aSmrgour @query_params;
45f2e35a3aSmrg
46f2e35a3aSmrgour @color_names = (
47f2e35a3aSmrg    "VT100 text foreground color",
48f2e35a3aSmrg    "VT100 text background color",
49f2e35a3aSmrg    "text cursor color",
50f2e35a3aSmrg    "mouse foreground color",
51f2e35a3aSmrg    "mouse background color",
52f2e35a3aSmrg    "Tektronix foreground color",
53f2e35a3aSmrg    "Tektronix background color",
54f2e35a3aSmrg    "highlight background color",
55f2e35a3aSmrg    "Tektronix cursor color",
56f2e35a3aSmrg    "highlight foreground color"
57f2e35a3aSmrg);
58f2e35a3aSmrg
59f2e35a3aSmrg$Getopt::Std::STANDARD_HELP_VERSION = 1;
60f2e35a3aSmrg&getopts('qs8') || die(
61f2e35a3aSmrg    "Usage: $0 [options]\n
62f2e35a3aSmrgOptions:\n
63f2e35a3aSmrg  -q      quicker results by merging queries
64f2e35a3aSmrg  -s      use ^G rather than ST
65f2e35a3aSmrg  -8      use 8-bit controls
66f2e35a3aSmrg"
67f2e35a3aSmrg);
68f2e35a3aSmrg
69f2e35a3aSmrgour $OSC = "\x1b\]";
70f2e35a3aSmrg$OSC = "\x9d" if ($opt_8);
71f2e35a3aSmrgour $ST = $opt_8 ? "\x9c" : ( $opt_s ? "\007" : "\x1b\\" );
72f2e35a3aSmrg
73f2e35a3aSmrgsub get_reply($) {
74f2e35a3aSmrg    open TTY, "+</dev/tty" or die("Cannot open /dev/tty\n");
75f2e35a3aSmrg    autoflush TTY 1;
76f2e35a3aSmrg    my $old = `stty -g`;
77f2e35a3aSmrg    system "stty raw -echo min 0 time 5";
78f2e35a3aSmrg
79f2e35a3aSmrg    print TTY @_;
80f2e35a3aSmrg    my $reply = <TTY>;
81f2e35a3aSmrg    close TTY;
82f2e35a3aSmrg    system "stty $old";
83f2e35a3aSmrg    if ( defined $reply ) {
84f2e35a3aSmrg        die("^C received\n") if ( "$reply" eq "\003" );
85f2e35a3aSmrg    }
86f2e35a3aSmrg    return $reply;
87f2e35a3aSmrg}
88f2e35a3aSmrg
89f2e35a3aSmrgsub visible($) {
90f2e35a3aSmrg    my $reply = $_[0];
91f2e35a3aSmrg    my $n;
92f2e35a3aSmrg    my $result = "";
93f2e35a3aSmrg    for ( $n = 0 ; $n < length($reply) ; ) {
94f2e35a3aSmrg        my $c = substr( $reply, $n, 1 );
95f2e35a3aSmrg        if ( $c =~ /[[:print:]]/ ) {
96f2e35a3aSmrg            $result .= $c;
97f2e35a3aSmrg        }
98f2e35a3aSmrg        else {
99f2e35a3aSmrg            my $k = ord substr( $reply, $n, 1 );
100f2e35a3aSmrg            if ( ord $k == 0x1b ) {
101f2e35a3aSmrg                $result .= "\\E";
102f2e35a3aSmrg            }
103f2e35a3aSmrg            elsif ( $k == 0x7f ) {
104f2e35a3aSmrg                $result .= "^?";
105f2e35a3aSmrg            }
106f2e35a3aSmrg            elsif ( $k == 32 ) {
107f2e35a3aSmrg                $result .= "\\s";
108f2e35a3aSmrg            }
109f2e35a3aSmrg            elsif ( $k < 32 ) {
110f2e35a3aSmrg                $result .= sprintf( "^%c", $k + 64 );
111f2e35a3aSmrg            }
112f2e35a3aSmrg            elsif ( $k > 128 ) {
113f2e35a3aSmrg                $result .= sprintf( "\\%03o", $k );
114f2e35a3aSmrg            }
115f2e35a3aSmrg            else {
116f2e35a3aSmrg                $result .= chr($k);
117f2e35a3aSmrg            }
118f2e35a3aSmrg        }
119f2e35a3aSmrg        $n += 1;
120f2e35a3aSmrg    }
121f2e35a3aSmrg
122f2e35a3aSmrg    return $result;
123f2e35a3aSmrg}
124f2e35a3aSmrg
125f2e35a3aSmrgsub begin_query() {
126f2e35a3aSmrg    @query_params = ();
127f2e35a3aSmrg}
128f2e35a3aSmrg
129f2e35a3aSmrgsub add_param($) {
130f2e35a3aSmrg    $query_params[ $#query_params + 1 ] = $_[0];
131f2e35a3aSmrg}
132f2e35a3aSmrg
133f2e35a3aSmrgsub show_reply($) {
134f2e35a3aSmrg    my $reply = shift;
135f2e35a3aSmrg    printf "data={%s}", &visible($reply);
136f2e35a3aSmrg}
137f2e35a3aSmrg
138f2e35a3aSmrgsub finish_query($) {
139f2e35a3aSmrg    return unless (@query_params);
140f2e35a3aSmrg
141f2e35a3aSmrg    my $reply;
142f2e35a3aSmrg    my $n;
143f2e35a3aSmrg    my $st = $opt_8 ? qr/\x9c/ : ( $opt_s ? qr/\007/ : qr/\x1b\\/ );
144f2e35a3aSmrg    my $osc = $opt_8 ? qr/\x9d/ : qr/\x1b]/;
145f2e35a3aSmrg    my $match = qr/${osc}.*${st}/;
146f2e35a3aSmrg
147f2e35a3aSmrg    my $params = join( ";", @query_params );
148f2e35a3aSmrg    $params =~ s/\d+/?/g;
149f2e35a3aSmrg    $params = sprintf( "%d;%s", $query_params[0], $params );
150f2e35a3aSmrg    $reply = &get_reply( $OSC . $params . $ST );
151f2e35a3aSmrg
152f2e35a3aSmrg    printf "query{%s}", &visible($params);
153f2e35a3aSmrg
154f2e35a3aSmrg    if ( defined $reply ) {
155f2e35a3aSmrg        printf " len=%2d ", length($reply);
156f2e35a3aSmrg        if ( $reply =~ /${match}/ ) {
157f2e35a3aSmrg            my @chunks = split /${st}${osc}/, $reply;
158f2e35a3aSmrg            printf "\n" if ( $#chunks > 0 );
159f2e35a3aSmrg            for my $c ( 0 .. $#chunks ) {
160f2e35a3aSmrg                $chunks[$c] =~ s/^${osc}// if ( $c == 0 );
161f2e35a3aSmrg                $chunks[$c] =~ s/${st}$//  if ( $c == $#chunks );
162f2e35a3aSmrg                my $param = $chunks[$c];
163f2e35a3aSmrg                $param =~ s/^(\d+);.*/$1/;
164f2e35a3aSmrg                $param = -1 unless ( $param =~ /^\d+$/ );
165f2e35a3aSmrg                $chunks[$c] =~ s/^\d+;//;
166f2e35a3aSmrg                printf "\t%d: ", $param if ( $#chunks > 0 );
167f2e35a3aSmrg                &show_reply( $chunks[$c] );
168f2e35a3aSmrg                printf " %s", $color_names[ $param - 10 ]
169f2e35a3aSmrg                  if (  ( $param >= 10 )
170f2e35a3aSmrg                    and ( ( $param - 10 ) <= $#color_names ) );
171f2e35a3aSmrg                printf "\n" if ( $c < $#chunks );
172f2e35a3aSmrg            }
173f2e35a3aSmrg        }
174f2e35a3aSmrg        else {
175f2e35a3aSmrg            printf "? ";
176f2e35a3aSmrg            &show_reply($reply);
177f2e35a3aSmrg        }
178f2e35a3aSmrg    }
179f2e35a3aSmrg    printf "\n";
180f2e35a3aSmrg}
181f2e35a3aSmrg
182f2e35a3aSmrgsub query_color($) {
183f2e35a3aSmrg    my $param = shift;
184f2e35a3aSmrg
185f2e35a3aSmrg    &begin_query unless $opt_q;
186f2e35a3aSmrg    if ( $#query_params >= 0
187f2e35a3aSmrg        and ( $param != $query_params[$#query_params] + 1 ) )
188f2e35a3aSmrg    {
189f2e35a3aSmrg        &finish_query;
190f2e35a3aSmrg        &begin_query;
191f2e35a3aSmrg    }
192f2e35a3aSmrg    &add_param($param);
193f2e35a3aSmrg    &finish_query unless $opt_q;
194f2e35a3aSmrg}
195f2e35a3aSmrg
196f2e35a3aSmrgsub query_colors($$) {
197f2e35a3aSmrg    my $lo = shift;
198f2e35a3aSmrg    my $hi = shift;
199f2e35a3aSmrg    my $n;
200f2e35a3aSmrg    for ( $n = $lo ; $n <= $hi ; ++$n ) {
201f2e35a3aSmrg        &query_color($n);
202f2e35a3aSmrg    }
203f2e35a3aSmrg}
204f2e35a3aSmrg
205f2e35a3aSmrgprintf "\x1b G" if ($opt_8);
206f2e35a3aSmrg
207f2e35a3aSmrg&begin_query if ($opt_q);
208f2e35a3aSmrg
209f2e35a3aSmrgif ( $#ARGV >= 0 ) {
210f2e35a3aSmrg    while ( $#ARGV >= 0 ) {
211f2e35a3aSmrg        if ( $ARGV[0] =~ /-/ ) {
212f2e35a3aSmrg            my @args = split /-/, $ARGV[0];
213f2e35a3aSmrg            &query_colors( $args[0], $args[1] );
214f2e35a3aSmrg        }
215f2e35a3aSmrg        else {
216f2e35a3aSmrg            &query_colors( $ARGV[0], $ARGV[0] );
217f2e35a3aSmrg        }
218f2e35a3aSmrg        shift @ARGV;
219f2e35a3aSmrg    }
220f2e35a3aSmrg}
221f2e35a3aSmrgelse {
222f2e35a3aSmrg    &query_colors( 10, 19 );
223f2e35a3aSmrg}
224f2e35a3aSmrg
225f2e35a3aSmrg&finish_query if ($opt_q);
226f2e35a3aSmrg
227f2e35a3aSmrgprintf "\x1b F" if ($opt_8);
228f2e35a3aSmrg
229f2e35a3aSmrg1;
230