Implementing ‘noecho’ Programming details regarding the Linux implementation for ‘struct termios’ objects

advertisement
Implementing ‘noecho’
Programming details regarding
the Linux implementation for
‘struct termios’ objects
Basic issues to consider
•
•
•
•
•
•
Normal tty operation is ‘canonical’ mode
Input gets processed one line at a time
Line-editing is allowed (e.g., backspace)
User’s keystrokes echoed to the screen
In C/C++ demo we could turn off echoing
We used two standard interface functions:
• int tcgetattr( int fileno, struct termios *tty );
• Int tcsetattr( int fileno, int flag, struct termios *tty );
Basic Algorithm
• Save a copy of the initial terminal settings
• Modify certain bits in the ‘c_lflag’ field:
– Turn off the ECHO bit, and
– Turn on the ECHONL bit
• Install the modified terminal settings
• Perform desired echo-free keyboard input
• Then reinstall the original terminal settings
How much storage space?
• We must reserve adequate space for
storing the initial terminal settings
• But we don’t know how big this object is
• This issue was transparently handled for
us in our ‘noecho.cpp” demo by including:
• #include <termios.h>
• struct termios save_termios;
• How can we accomplish this in assembly?
The ‘c_lflag’ field
• We needed to modify bits in ‘c_lflag’ field
• Those bits were represented by constants:
ECHO and ECHONL
• Their values were defined in <termios.h>
• We did not need to know the actual values
• But header-file isn’t available in assembly
• So now we do need to know these values
• Another constant needed is TCSANOW
Memory addressing
•
•
•
•
•
•
Where’s ‘c_lflag’ field within termios object
We can’t modify its bits until we know that
One idea is to study the Linux header-file
But where is it? There seem to be several
Nested type-declarations add to confusion
Another approach: let’s write a program to report
the specific information we’ll need
• Our ‘ttyinfo.cpp’ demo program shows us that
sizeof( struct termios ) equals 60 bytes
.section
.data
# we need storage for two ‘termios’ objects
origtty: .space
60 # original settings
worktty: .space
60 # a ‘working copy’
# Insufficient space would cause big trouble!
origtty
worktty
tcgetattr() does not
know the size that
we have allocated
system would overwite part of the next data-area
Constants in assembly
• We can use the .equ directive to create
our own manifest constants:
.equ
ECHO,
0x00000008
.equ
ECHONL, 0x00000040
.equ
TCSANOW, 0x00000000
• Question: will our program also work on
other versions of UNIX besides Linux?
Copying a structure object
• We can create a program loop to copy the
contents of a data-structure
• Here again we need to know the number of
bytes in the structure we want to copy
• We can use a ‘counted loop’ to do copying
• Three initialization steps:
– put source-address in register %esi
– put dest’n address in register %edi
– put the byte-count into register %ecx
• Advance %esi and %edi as each byte is copied
The actual loop code
again:
movl
movl
movl
movb
movb
incl
incl
loop
$origtty, %esi
$worktty, %edi
$60, %ecx
(%esi), %al
%al, (%edi)
%esi
%edi
again
Modifying some flag bits
• Determine offset of the ‘c_lflag’ field (=12)
• Setup this offset in a CPU register (%edi)
movl $12, %edi
• Use AND-instruction to turn a bit off:
andl $~ECHO, worktty(%edi)
• Use OR-instruction to turn a bit on:
orl
$ECHONL, worktty(%edi)
• (Here other approaches also are possible)
Non-canonical terminal modes
• Certain kinds of applications do not lend
themselves to ‘canonical’ terminal input
• We may want an instant response to each
individual keystroke (not to an entire line)
• Example: computer game using keyboard
• We can ‘turn off’ canonical line-processing
• Very similar to ‘turning off’ the input echo
i.e.,
worktty.c_lflag &= ~ICANON;
Two further adjustments
• Need two changes in the c_cc[] array:
worktty.c_cc[ VMIN ] = 1;
worktty.c_cc[ VTIME ] = 0;
• First change causes ‘read()’ function to
return as soon as at least one character
has been typed
• Second change causes ‘read() function to
return without any time-delay
An application
• You could use this ‘non-canonical’ terminal
mode to implement visual “user feedback”
in your ‘password’ program
• Whenever the user presses a new key, the
program immediately responds by printing
a neutral character (e.g. ‘*’) to confirm that
it has indeed received the user’s input
• Special handling for ‘backspace’ is needed
• Suggestion: Try it first in a C/C++ program
Download