1# ex:ts=8 sw=4: 2# $OpenBSD: Interactive.pm,v 1.23 2023/06/13 09:07:17 espie Exp $ 3# 4# Copyright (c) 2005-2007 Marc Espie <espie@openbsd.org> 5# 6# Permission to use, copy, modify, and distribute this software for any 7# purpose with or without fee is hereby granted, provided that the above 8# copyright notice and this permission notice appear in all copies. 9# 10# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 17use v5.36; 18 19package OpenBSD::Interactive; 20 21sub new($class, $state, $level) 22{ 23 bless { 24 state => $state, 25 always => 0, 26 level => $level, 27 }, $class; 28} 29 30sub ask_list($self, $prompt, @values) 31{ 32 if ($self->{always}) { 33 return $values[0]; 34 } 35 my ($fh, $pid); 36 if ($self->{state}->height <= @values + 1) { 37 $pid = open($fh, "|-", "more", "-ce"); 38 } 39 40 $fh //= \*STDERR; 41 42 $self->{state}->fhsay($fh, '#1', $prompt); 43 my $i = 0; 44 for my $v (@values) { 45 $self->{state}->fhsay($fh, "#1\t#2: #3", 46 $i == 0 ? "a" : "", $i, $v); 47 $i++; 48 } 49 if (defined $pid) { 50 close($fh); 51 waitpid $pid, 0; 52 } 53LOOP: 54 $self->{state}->errprint("Your choice: "); 55 my $result = <STDIN>; 56 unless (defined $result) { 57 $self->{state}->errsay(""); 58 return $values[0]; 59 } 60 chomp $result; 61 if ($result eq '') { 62 return $values[0]; 63 } 64 if ($result eq 'a') { 65 $self->{always} = 1; 66 return $values[0]; 67 } 68 if ($result =~ m/^\d+$/o) { 69 if ($result >= 0 && $result < @values) { 70 return $values[$result]; 71 } 72 $self->{state}->errsay("invalid numeric value !"); 73 goto LOOP; 74 } 75 if (grep { $result eq $_ } @values) { 76 return $result; 77 } else { 78 $self->{state}->errsay("Ambiguous value !"); 79 goto LOOP; 80 } 81} 82 83sub confirm($self, $prompt, $yesno = 0) 84{ 85 if ($self->{always}) { 86 return 1; 87 } 88LOOP2: 89 $self->{state}->errprint("#1 ? [#2/a] ", 90 $prompt, $yesno ? "Y/n" : "y/N"); 91 92 my $result = <STDIN>; 93 unless (defined $result) { 94 $self->{state}->errsay(""); 95 return $yesno; 96 } 97 chomp $result; 98 $result =~ s/\s+//go; 99 $result =~ tr/A-Z/a-z/; 100 if ($result eq 'yes' or $result eq 'y') { 101 return 1; 102 } 103 if ($result eq 'no' or $result eq 'n') { 104 return 0; 105 } 106 if ($result eq 'a') { 107 $self->{always} = 1; 108 return 1; 109 } 110 if ($result eq '') { 111 return $yesno; 112 } 113 $self->{state}->errsay("Ambiguous answer"); 114 goto LOOP2; 115} 116 117sub is_interactive($self) 118{ 119 return $self->{level}; 120} 121 1221; 123