1913cc679Smrg#!/usr/bin/env perl
204b94745Smrg# $XTermId: query-status.pl,v 1.10 2021/11/11 21:31:48 tom Exp $
3913cc679Smrg# -----------------------------------------------------------------------------
4913cc679Smrg# this file is part of xterm
5913cc679Smrg#
6a5ae21e4Smrg# Copyright 2017-2019,2021 by Thomas E. Dickey
7913cc679Smrg#
8913cc679Smrg#                         All Rights Reserved
9913cc679Smrg#
10913cc679Smrg# Permission is hereby granted, free of charge, to any person obtaining a
11913cc679Smrg# copy of this software and associated documentation files (the
12913cc679Smrg# "Software"), to deal in the Software without restriction, including
13913cc679Smrg# without limitation the rights to use, copy, modify, merge, publish,
14913cc679Smrg# distribute, sublicense, and/or sell copies of the Software, and to
15913cc679Smrg# permit persons to whom the Software is furnished to do so, subject to
16913cc679Smrg# the following conditions:
17913cc679Smrg#
18913cc679Smrg# The above copyright notice and this permission notice shall be included
19913cc679Smrg# in all copies or substantial portions of the Software.
20913cc679Smrg#
21913cc679Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22913cc679Smrg# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23913cc679Smrg# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24913cc679Smrg# IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
25913cc679Smrg# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26913cc679Smrg# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27913cc679Smrg# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28913cc679Smrg#
29913cc679Smrg# Except as contained in this notice, the name(s) of the above copyright
30913cc679Smrg# holders shall not be used in advertising or otherwise to promote the
31913cc679Smrg# sale, use or other dealings in this Software without prior written
32913cc679Smrg# authorization.
33913cc679Smrg# -----------------------------------------------------------------------------
34913cc679Smrg# Test the status features of xterm using DECRQSS.
35913cc679Smrg#
36913cc679Smrg# TODO: use Term::ReadKey rather than system/stty
37913cc679Smrg
38913cc679Smrguse strict;
39913cc679Smrguse warnings;
40913cc679Smrg
41913cc679Smrguse Getopt::Std;
42913cc679Smrguse IO::Handle;
43913cc679Smrg
44a5ae21e4Smrgour ( $opt_a, $opt_c, $opt_d, $opt_8 );
45f2e35a3aSmrg
46f2e35a3aSmrg$Getopt::Std::STANDARD_HELP_VERSION = 1;
47a5ae21e4Smrg&getopts('acd8') || die(
48a5ae21e4Smrg    "Usage: $0 [options] [suffixes]\n
49913cc679SmrgOptions:\n
50a5ae21e4Smrg  -a      test ANSI colors with SGR controls
51a5ae21e4Smrg  -c      test cursor appearance with DECSCUSR controls
52a5ae21e4Smrg  -d      test direct colors with SGR controls
53913cc679Smrg  -8      use 8-bit controls
54f2e35a3aSmrg
55f2e35a3aSmrgOptions which use C1 controls may not work with UTF-8.
56913cc679Smrg"
57913cc679Smrg);
58913cc679Smrg
59a5ae21e4Smrgour $ST  = $opt_8 ? "\x9c" : "\x1b\\";
60a5ae21e4Smrgour $CSI = $opt_8 ? "\x9a" : "\x1b[";
61913cc679Smrg
62913cc679Smrgour %suffixes;
63913cc679Smrg$suffixes{DECSCA}   = '"q';
64913cc679Smrg$suffixes{DECSCL}   = '"p';
65913cc679Smrg$suffixes{DECSTBM}  = 'r';
66913cc679Smrg$suffixes{DECSLRM}  = 's';
67913cc679Smrg$suffixes{SGR}      = 'm';
68913cc679Smrg$suffixes{DECSCUSR} = ' q';
69913cc679Smrg
70913cc679Smrgsub get_reply($) {
71913cc679Smrg    open TTY, "+</dev/tty" or die("Cannot open /dev/tty\n");
72913cc679Smrg    autoflush TTY 1;
73913cc679Smrg    my $old = `stty -g`;
74913cc679Smrg    system "stty raw -echo min 0 time 5";
75913cc679Smrg
76913cc679Smrg    print TTY @_;
77913cc679Smrg    my $reply = <TTY>;
78913cc679Smrg    close TTY;
79913cc679Smrg    system "stty $old";
80913cc679Smrg    if ( defined $reply ) {
81913cc679Smrg        die("^C received\n") if ( "$reply" eq "\003" );
82913cc679Smrg    }
83913cc679Smrg    return $reply;
84913cc679Smrg}
85913cc679Smrg
86913cc679Smrgsub visible($) {
87913cc679Smrg    my $reply = $_[0];
88913cc679Smrg    my $n;
89913cc679Smrg    my $result = "";
90913cc679Smrg    for ( $n = 0 ; $n < length($reply) ; ) {
91913cc679Smrg        my $c = substr( $reply, $n, 1 );
92913cc679Smrg        if ( $c =~ /[[:print:]]/ ) {
93913cc679Smrg            $result .= $c;
94913cc679Smrg        }
95913cc679Smrg        else {
96913cc679Smrg            my $k = ord substr( $reply, $n, 1 );
97913cc679Smrg            if ( ord $k == 0x1b ) {
98913cc679Smrg                $result .= "\\E";
99913cc679Smrg            }
100913cc679Smrg            elsif ( $k == 0x7f ) {
101913cc679Smrg                $result .= "^?";
102913cc679Smrg            }
103913cc679Smrg            elsif ( $k == 32 ) {
104913cc679Smrg                $result .= "\\s";
105913cc679Smrg            }
106913cc679Smrg            elsif ( $k < 32 ) {
107913cc679Smrg                $result .= sprintf( "^%c", $k + 64 );
108913cc679Smrg            }
109913cc679Smrg            elsif ( $k > 128 ) {
110913cc679Smrg                $result .= sprintf( "\\%03o", $k );
111913cc679Smrg            }
112913cc679Smrg            else {
113913cc679Smrg                $result .= chr($k);
114913cc679Smrg            }
115913cc679Smrg        }
116913cc679Smrg        $n += 1;
117913cc679Smrg    }
118913cc679Smrg
119913cc679Smrg    return $result;
120913cc679Smrg}
121913cc679Smrg
122913cc679Smrgsub query_one($) {
123a5ae21e4Smrg    my $name = shift;
124a5ae21e4Smrg
125a5ae21e4Smrg    return unless $suffixes{$name};
126a5ae21e4Smrg
127913cc679Smrg    my $suffix = $suffixes{$name};
128913cc679Smrg    my $prefix = $opt_8 ? "\x90" : "\x1bP";
129a5ae21e4Smrg    my $st     = $opt_8 ? "\x9c" : qr/\x1b\\/;
130a5ae21e4Smrg    my $DCS    = qr/${prefix}/;
131a5ae21e4Smrg    my $match  = qr/${DCS}.*${st}/;
132a5ae21e4Smrg    my $reply  = get_reply( $prefix . '$q' . $suffix . $ST );
133913cc679Smrg
134913cc679Smrg    printf "%-10s query{%s}%*s", $name,    #
135913cc679Smrg      &visible($suffix),                   #
136913cc679Smrg      4 - length($suffix), " ";
137913cc679Smrg
138913cc679Smrg    if ( defined $reply ) {
139913cc679Smrg        printf "%2d ", length($reply);
140913cc679Smrg        if ( $reply =~ /${match}/ ) {
141913cc679Smrg
142913cc679Smrg            $reply =~ s/^${DCS}//;
143913cc679Smrg            $reply =~ s/^;//;
144913cc679Smrg            $reply =~ s/${st}$//;
145913cc679Smrg        }
146913cc679Smrg        else {
147913cc679Smrg            printf "? ";
148913cc679Smrg        }
149913cc679Smrg
150913cc679Smrg        printf "{%s}", visible($reply);
151913cc679Smrg    }
152913cc679Smrg    printf "\n";
153913cc679Smrg}
154913cc679Smrg
155a5ae21e4Smrgsub ansi_color($) {
156a5ae21e4Smrg    my $color = shift;
157a5ae21e4Smrg    return $color;
158a5ae21e4Smrg}
159a5ae21e4Smrg
160a5ae21e4Smrgsub direct_color($) {
161a5ae21e4Smrg    my $color  = shift;
162a5ae21e4Smrg    my $result = "8:2:";
163a5ae21e4Smrg    $result .= ( $color & 4 ) ? ":255" : ":0";
164a5ae21e4Smrg    $result .= ( $color & 2 ) ? ":255" : ":0";
165a5ae21e4Smrg    $result .= ( $color & 1 ) ? ":255" : ":0";
166a5ae21e4Smrg    return $result;
167a5ae21e4Smrg}
168a5ae21e4Smrg
169a5ae21e4Smrgsub default_colors() {
170a5ae21e4Smrg    return "39;49";
171a5ae21e4Smrg}
172a5ae21e4Smrg
173f2e35a3aSmrgprintf "\x1b G" if ($opt_8);
174f2e35a3aSmrg
175913cc679Smrgif ( $#ARGV >= 0 ) {
176913cc679Smrg    while ( $#ARGV >= 0 ) {
177913cc679Smrg        &query_one( shift @ARGV );
178913cc679Smrg    }
179913cc679Smrg}
180a5ae21e4Smrgelsif ($opt_a) {
181a5ae21e4Smrg    for my $fg ( 0 .. 7 ) {
182a5ae21e4Smrg        printf "%s3%sm", $CSI, &ansi_color($fg);
183a5ae21e4Smrg        for my $bg ( 0 .. 7 ) {
184a5ae21e4Smrg            printf "%s4%sm", $CSI, &ansi_color($bg);
185a5ae21e4Smrg            &query_one("SGR");
186a5ae21e4Smrg        }
187a5ae21e4Smrg    }
188a5ae21e4Smrg    printf "%s%sm", $CSI, &default_colors;
189a5ae21e4Smrg}
190a5ae21e4Smrgelsif ($opt_c) {
191a5ae21e4Smrg    for my $c ( 0 .. 6 ) {
192a5ae21e4Smrg        printf "%s%d q", $CSI, $c;
193a5ae21e4Smrg        &query_one("DECSCUSR");
194a5ae21e4Smrg    }
195a5ae21e4Smrg    printf "%s q", $CSI;
196a5ae21e4Smrg}
197a5ae21e4Smrgelsif ($opt_d) {
198a5ae21e4Smrg    for my $fg ( 0 .. 7 ) {
199a5ae21e4Smrg        printf "%s3%sm", $CSI, &direct_color($fg);
200a5ae21e4Smrg        for my $bg ( 0 .. 7 ) {
201a5ae21e4Smrg            printf "%s4%sm", $CSI, &direct_color($bg);
202a5ae21e4Smrg            &query_one("SGR");
203a5ae21e4Smrg        }
204a5ae21e4Smrg    }
205a5ae21e4Smrg    printf "%s39;49m", $CSI;
206a5ae21e4Smrg}
207913cc679Smrgelse {
208913cc679Smrg    for my $key ( sort keys %suffixes ) {
209913cc679Smrg        &query_one($key);
210913cc679Smrg    }
211913cc679Smrg}
212f2e35a3aSmrg
213f2e35a3aSmrgprintf "\x1b F" if ($opt_8);
214