1a5ae21e4Smrg#!/usr/bin/env perl
204b94745Smrg# $XTermId: halves.pl,v 1.11 2022/11/17 00:45:00 tom Exp $
3a5ae21e4Smrg# -----------------------------------------------------------------------------
4a5ae21e4Smrg# this file is part of xterm
5a5ae21e4Smrg#
65307cd1aSmrg# Copyright 2007,2022 by Thomas E. Dickey
7a5ae21e4Smrg#
8a5ae21e4Smrg#                         All Rights Reserved
9a5ae21e4Smrg#
10a5ae21e4Smrg# Permission is hereby granted, free of charge, to any person obtaining a
11a5ae21e4Smrg# copy of this software and associated documentation files (the
12a5ae21e4Smrg# "Software"), to deal in the Software without restriction, including
13a5ae21e4Smrg# without limitation the rights to use, copy, modify, merge, publish,
14a5ae21e4Smrg# distribute, sublicense, and/or sell copies of the Software, and to
15a5ae21e4Smrg# permit persons to whom the Software is furnished to do so, subject to
16a5ae21e4Smrg# the following conditions:
17a5ae21e4Smrg#
18a5ae21e4Smrg# The above copyright notice and this permission notice shall be included
19a5ae21e4Smrg# in all copies or substantial portions of the Software.
20a5ae21e4Smrg#
21a5ae21e4Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22a5ae21e4Smrg# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23a5ae21e4Smrg# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24a5ae21e4Smrg# IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
25a5ae21e4Smrg# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26a5ae21e4Smrg# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27a5ae21e4Smrg# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28a5ae21e4Smrg#
29a5ae21e4Smrg# Except as contained in this notice, the name(s) of the above copyright
30a5ae21e4Smrg# holders shall not be used in advertising or otherwise to promote the
31a5ae21e4Smrg# sale, use or other dealings in this Software without prior written
32a5ae21e4Smrg# authorization.
33a5ae21e4Smrg# -----------------------------------------------------------------------------
34a5ae21e4Smrg# Draw a grid of characters (optionally double-width) and modify it using
35a5ae21e4Smrg# overstrike, insert- and delete-characters to see if the double-width
36a5ae21e4Smrg# characters are completely cleared when "partly" modified.
37a5ae21e4Smrguse strict;
385307cd1aSmrguse warnings;
39a5ae21e4Smrg
40a5ae21e4Smrguse Getopt::Std;
41a5ae21e4Smrg
425307cd1aSmrgour ( $opt_c, $opt_n, $opt_r, $opt_w );
435307cd1aSmrgour ( $lineno, $test_string, $term_width );
44a5ae21e4Smrg
45a5ae21e4Smrg# returns the number of columns in the screen
46a5ae21e4Smrgsub screen_width() {
475307cd1aSmrg    open( FP, "resize -u |" ) or exit $!;
485307cd1aSmrg    my (@input) = <FP>;
495307cd1aSmrg    chomp @input;
505307cd1aSmrg    close(FP);
515307cd1aSmrg    my $result = 80;
525307cd1aSmrg    for my $n ( 0 .. $#input ) {
535307cd1aSmrg        if ( $input[$n] =~ /^COLUMNS=/ ) {
545307cd1aSmrg            $result = $input[$n];
555307cd1aSmrg            $result =~ s/^[^=]*=//;
565307cd1aSmrg            $result =~ s/;.*//;
575307cd1aSmrg            last;
585307cd1aSmrg        }
595307cd1aSmrg    }
605307cd1aSmrg    return $result;
61a5ae21e4Smrg}
62a5ae21e4Smrg
63a5ae21e4Smrgsub set_color($) {
645307cd1aSmrg    my $code = $_[0];
655307cd1aSmrg    if ( defined($opt_c) ) {
665307cd1aSmrg        if ( $code == 3 ) {
675307cd1aSmrg            printf "\x1b[1;33;42m";    # yellow-on-green
685307cd1aSmrg        }
695307cd1aSmrg        elsif ( $code == 2 ) {
705307cd1aSmrg            printf "\x1b[0;31;45m";    # red-on-magenta
715307cd1aSmrg        }
725307cd1aSmrg        elsif ( $code == 1 ) {
735307cd1aSmrg            printf "\x1b[0;36;44m";    # cyan-on-blue
745307cd1aSmrg        }
755307cd1aSmrg        else {
765307cd1aSmrg            printf "\x1b[0;39;49m";
775307cd1aSmrg        }
785307cd1aSmrg    }
79a5ae21e4Smrg}
80a5ae21e4Smrg
81a5ae21e4Smrg# returns a string of two-column characters given an ASCII alpha/numeric string
82a5ae21e4Smrgsub double_cells($) {
835307cd1aSmrg    my $value = $_[0];
845307cd1aSmrg    $value =~ s/ /  /g;
855307cd1aSmrg    pack(
865307cd1aSmrg        "U*",
875307cd1aSmrg        map {
885307cd1aSmrg            ( $_ <= 32 || $_ > 127 )        # if non-ASCII character...
895307cd1aSmrg              ? 32                          # ...just show a blank
905307cd1aSmrg              : ( 0xff00 + ( $_ - 32 ) )    # map to "Fullwidth Form"
915307cd1aSmrg        } unpack( "C*", $value )
925307cd1aSmrg    );                                      # unpack unsigned-char characters
93a5ae21e4Smrg}
94a5ae21e4Smrg
95a5ae21e4Smrgsub move_to($) {
965307cd1aSmrg    printf "\x1b[%dG", $_[0] + 1;
97a5ae21e4Smrg}
98a5ae21e4Smrg
99a5ae21e4Smrgsub delete_char() {
1005307cd1aSmrg    set_color(2);
1015307cd1aSmrg    printf "\x1b[%dP", 1;
1025307cd1aSmrg    set_color(1);
103a5ae21e4Smrg}
104a5ae21e4Smrg
105a5ae21e4Smrgsub insert_once($) {
1065307cd1aSmrg    set_color(2);
1075307cd1aSmrg    printf "\x1b[%d@", length( $_[0] );
1085307cd1aSmrg    write_chars( $_[0] );
109a5ae21e4Smrg}
110a5ae21e4Smrg
111a5ae21e4Smrgsub insert_mode($) {
1125307cd1aSmrg    set_color(2);
1135307cd1aSmrg    printf "\x1b[%dP", length( $_[0] );
1145307cd1aSmrg    printf "\x1b[4h";
1155307cd1aSmrg    write_chars( $_[0] );
1165307cd1aSmrg    printf "\x1b[4l";
117a5ae21e4Smrg}
118a5ae21e4Smrg
119a5ae21e4Smrgsub write_chars($) {
1205307cd1aSmrg    set_color(3);
1215307cd1aSmrg    printf "%s", $_[0];
1225307cd1aSmrg    set_color(1);
123a5ae21e4Smrg}
124a5ae21e4Smrg
125a5ae21e4Smrg# vary the starting point of each line, to make a more interesting pattern
126a5ae21e4Smrgsub starts_of($) {
1275307cd1aSmrg    my $value = $_[0];
1285307cd1aSmrg    if ( defined($opt_w) ) {
1295307cd1aSmrg
1305307cd1aSmrg        # 0,1,1,2,2,3,3,...
1315307cd1aSmrg        $value = ( ( $value + 1 ) / 2 ) % length($test_string);
1325307cd1aSmrg    }
1335307cd1aSmrg    else {
1345307cd1aSmrg        $value %= length($test_string);
1355307cd1aSmrg    }
1365307cd1aSmrg    return $value;
137a5ae21e4Smrg}
138a5ae21e4Smrg
139a5ae21e4Smrg# write the text for the given line-number
140a5ae21e4Smrgsub testit($) {
1415307cd1aSmrg    my $number = $_[0];
1425307cd1aSmrg    my $length = $term_width;
1435307cd1aSmrg    if ( defined($opt_n) ) {
1445307cd1aSmrg        printf "%5d ", $number % 99999;
1455307cd1aSmrg        $length -= 6;
1465307cd1aSmrg    }
1475307cd1aSmrg
1485307cd1aSmrg    # if we're printing double-column characters, we have half as much
1495307cd1aSmrg    # space effectively - but don't forget the remainder, so we can push
1505307cd1aSmrg    # the characters by single-columns.
1515307cd1aSmrg    if ( defined($opt_c) ) {
1525307cd1aSmrg        set_color(1);
1535307cd1aSmrg        printf "\x1b[K";
1545307cd1aSmrg    }
1555307cd1aSmrg    my $starts = starts_of($number);
1565307cd1aSmrg    if ( defined($opt_w) ) {
1575307cd1aSmrg        printf " ", if ( ( $number % 2 ) != 0 );
1585307cd1aSmrg        $length = ( $length - ( ($number) % 2 ) ) / 2;
1595307cd1aSmrg    }
1605307cd1aSmrg    my $string = substr( $test_string, $starts );
1615307cd1aSmrg    while ( length($string) < $length ) {
1625307cd1aSmrg        $string = $string . $test_string;
1635307cd1aSmrg    }
1645307cd1aSmrg    $string = substr( $string, 0, $length );
1655307cd1aSmrg    if ( defined($opt_w) ) {
1665307cd1aSmrg        $string = double_cells($string);
1675307cd1aSmrg    }
1685307cd1aSmrg    printf "%s", $string;
1695307cd1aSmrg
1705307cd1aSmrg    # now - within the line - modify it
1715307cd1aSmrg    move_to( ( 4 * $term_width ) / 5 );
1725307cd1aSmrg    insert_mode("XX");
1735307cd1aSmrg    move_to( ( 3 * $term_width ) / 5 );
1745307cd1aSmrg    delete_char();
1755307cd1aSmrg    move_to( ( 2 * $term_width ) / 5 );
1765307cd1aSmrg    insert_once('~');
1775307cd1aSmrg    move_to( ( 1 * $term_width ) / 5 );
1785307cd1aSmrg    write_chars('~');
1795307cd1aSmrg    move_to(0);
1805307cd1aSmrg    set_color(0);
1815307cd1aSmrg    printf "\n";
182a5ae21e4Smrg}
183a5ae21e4Smrg
184a5ae21e4Smrgsub main::HELP_MESSAGE() {
1855307cd1aSmrg    printf STDERR <<EOF
186a5ae21e4SmrgUsage: $0 [options]
187a5ae21e4Smrg
188a5ae21e4SmrgOptions:
189a5ae21e4Smrg
190a5ae21e4Smrg-c   use color
191a5ae21e4Smrg-n   write line-numbers
192a5ae21e4Smrg-r   repeat indefinitely
193a5ae21e4Smrg-w   write wide-characters
194a5ae21e4SmrgEOF
1955307cd1aSmrg      ;
1965307cd1aSmrg    exit;
197a5ae21e4Smrg}
198a5ae21e4Smrg
199a5ae21e4Smrg&getopts('cnrw') || die();
200a5ae21e4Smrg
201a5ae21e4Smrg$term_width = screen_width();
202a5ae21e4Smrg
2035307cd1aSmrg$test_string =
2045307cd1aSmrg  "0123456789 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ";
205a5ae21e4Smrg
2065307cd1aSmrgbinmode( STDOUT, ":utf8" );
207a5ae21e4Smrgif ( defined($opt_r) ) {
2085307cd1aSmrg    for ( $lineno = 0 ; ; ++$lineno ) {
2095307cd1aSmrg        testit($lineno);
2105307cd1aSmrg    }
2115307cd1aSmrg}
2125307cd1aSmrgelse {
2135307cd1aSmrg    for ( $lineno = 0 ; $lineno < 24 ; ++$lineno ) {
2145307cd1aSmrg        testit($lineno);
2155307cd1aSmrg    }
216a5ae21e4Smrg}
217a5ae21e4Smrg
218a5ae21e4Smrgexit;
219