SirBones has asked for the wisdom of the Perl Monks concerning the following question:
This is kind of a forced exercise in minimalism; good for the soul, I guess, if not for the digestion.
What I've got: A bunch (potentially dozens) of Linux-based control stations, all with special Linux builds with a pre-packaged Perl (5.8.3) with a set of some very few CPAN modules, selected as the Bare Necessities by The Great and Powerful Code Image Builder Who Cannot Be Argued With. For various practical, logistical, and possibly legal reasons (uninteresting in this discourse, I assure you) I will not have the option to install any additional Perl modules (and would have a hard time doing so anyway, since nether CPAN.pm or a make utility is included on these boxes.) So I am absolutely, positively stuck with the Perl capability I've got on these, and I have to make do.
I've written a Perl utility that provides a simple shell to process various user commands that interface with some external hardware; a standard while(<>) { }loop. A user will tend to be sitting there for a long time issuing commands and wanting to repeat them in various ways; in other words, it would be really nice if they had a standard left/right arrow non-destructive spacing, and up/down arrow command history/retrieval. Well, more than really nice; it's going to be a real burden on them if every time they make a typo or want to repeat the command with a slight change they have to retype the whole line. As it is right now, all they get when they hit the arrows is the code sequences '^[[A' or '^[[B' stuff. (esc character plus whatever.)
So perhaps you've guessed by now: There is no functional Term::Readline or Term:Readkey on these systems, and I cannot install one. I don't know a lot about terminal I/O or how shells operate on command lines under the covers, but I am guessing that these (or some of their brethren) would get me out of this mess. But I digress. It's obvious I need to come up with something home-grown, or do without. So, in that light...
Taking the example code for using the standard POSIX module from Camel pp. 905-906, I've hacked a possibility for detecting up and down arrow presses and gathering the current command string. This is far from elegant right now; it's just meant to show how far I've gotten, and the direction I'm going:
#!/usr/bin/perl use warnings; use strict; my $str; my $buff; $| = 1; for (1..100) { my $got; $got = getone(); my $hx = unpack("H*",$got); # Look for "esc" character if ($hx eq '1b') { $str = $hx; } # Look for the 3 byte arrow sequence elsif ($str) { $str .= $hx; if ( length($str) == 6 ) { if ( lc($str) eq '1b5b41' ) { print "up arrow!\n"; } elsif ( lc($str) eq '1b5b42' ) { print "down arrow!\n"; } $str = undef; } } # If not enter key, add to buffer elsif (lc($hx) ne '0a') { print "$got"; $buff .= $hx; } else { print "\nline is: ". pack("H*", $buff)."\n"; $buff = undef; } } exit; # Camel 3rd ed, pp. 905-906 BEGIN { use POSIX qw(:termios_h); my ($term, $oterm, $echo, $noecho, $fd_stdin); $fd_stdin = fileno(STDIN); $term = POSIX::Termios->new(); $term->getattr($fd_stdin); $oterm = $term->getlflag(); $echo = ECHO | ECHOK | ICANON; $noecho = $oterm & ~$echo; sub cbreak { $term->setlflag($noecho); $term->setcc(VTIME, 1); $term->setattr($fd_stdin, TCSANOW); } sub cooked { $term->setlflag($oterm); $term->setcc(VTIME, 0); $term->setattr($fd_stdin, TCSANOW); } sub getone { my $key = ""; cbreak; sysread(STDIN, $key, 1); cooked(); return $key; } } END { cooked() }
It would obviously be easy enough to extend this to detecting left and right arrows as well. But that's not the problem; I don't want to just detect them. I want them to function as if I'm in a regular shell and let me move around and edit the line.
A sidebar is that when I run my tool under a Win32 system (ActiveState Perl), it seems to have all this command line editing stuff built in without my having to do anything; I don't know if that's a function of ActiveState Perl, or the Win32 DOS Command shell. In any case, that's not an option here; the "shell" will need to run under Linux.
All this hot air (and I apologize for its length) is simply to prefix the question: Is there a way to get a line editing function using the arrow keys just using POSIX (or some other standard approach) without access to any of the extended functionality provided by CPAN modules?
Thanks in advance, lads & lassies; you are the best. But you knew that already.
-Ken
|
---|