[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Why aren't char bits portable?
[Retrying mail returned due to network problems; apologies if anyone
got duplicate copies.]
There's nothing unportable about char bits. They just have to be
used correctly, but I think the necessary primitives are provided.
eg, MACSYMA has an editor which uses one-character commands and
extended commands. In some implementations, users have to use more
commands than in others, because in implementations which allow
char bits, MACSYMA will install commands on those characters.
Although this somewhat affects the behavior of the program between
implementations, I don't think the effect is likely to be serious
at the program level primarily because (with the exception of AI
programs that manipulate robot arms which in turn want to enter
key sequences on the terminal), programs mostly can't tell the
difference between not having those characters and having those
characters be available but just never executed. You have to be
careful not to use #\Control-..., of course. That's not portable.
But you can do, for example:
(DEFVAR *MY-COMMAND-TABLE* (MAKE-HASH-TABLE))
(DEFVAR *COMMAND-TABLE* NIL)
(DEFUN INSTALL-COMMAND-ON-KEY (FUNCTION CHAR &REST BIT-NAMES)
(DO ((CH CHAR (SET-CHAR-BIT CH (CAR B) T)) (B BIT-NAMES (CDR B)))
((NOT B)
(SETF (GETHASH CH *MY-COMMAND-TABLE*) FUNCTION))))
(DEFUN GET-COMMAND-ON-KEY (KEY) (GETHASH KEY *MY-COMMAND-TABLE*))
(DEFUN PROMPT (X)
(UNLESS (LISTEN) ;Tolerate line-at-a-time systems
(FORMAT T "~&~A: " X)))
(DEFUN READ-KEY-COMMAND () (PROMPT "Command") (READ-CHAR))
(DEFVAR *LAST-NUMBER* 0)
(DEFUN READ-NUMBER () (PROMPT "Value") (SETQ *LAST-NUMBER* (READ)))
(DEFUN CALCULATOR (&OPTIONAL (VAL 0) (*COMMAND-TABLE* *MY-COMMAND-TABLE*))
(DO ((CH (READ-KEY-COMMAND) (READ-KEY-COMMAND)))
((MEMBER CH '(#\X #\x)))
(LET ((FN (GET-COMMAND-ON-KEY CH)))
(COND (FN (PRINT (SETQ VAL (FUNCALL FN VAL))))
((CHAR= CH #\Newline) NIL) ;Tolerate line-at-a-time systems
(T
(FORMAT T "~&~@:C is not a defined command.~%" CH))))))
(INSTALL-COMMAND-ON-KEY #'(LAMBDA (X) X 0) #\0)
(INSTALL-COMMAND-ON-KEY #'(LAMBDA (X) (+ X (READ-NUMBER))) #\+)
(INSTALL-COMMAND-ON-KEY #'(LAMBDA (X) (- X (READ-NUMBER))) #\-)
(INSTALL-COMMAND-ON-KEY #'(LAMBDA (X) (* X (READ-NUMBER))) #\*)
(INSTALL-COMMAND-ON-KEY #'(LAMBDA (X) X) #\=)
(UNLESS (ZEROP CHAR-CONTROL-BIT)
(INSTALL-COMMAND-ON-KEY #'(LAMBDA (X) (+ X *LAST-NUMBER*)) #\+ :CONTROL)
(INSTALL-COMMAND-ON-KEY #'(LAMBDA (X) (- X)) #\- :CONTROL))
(CALCULATOR)
Command: =
0
Command: +
Value: 3
3
Command: *
Value: 4
12
Command: Control--
-12
Of course, in some implementations, it won't be possible to type Control--,
so the user of that interpretation will never observe any difference in behavior
other than the inaccessibility of certain commands. And there are no
functionalities in the above calculator which are on Control-anything which
are not otherwise accessible, so a portable program would not be "broken"
by their non-accessibility. In fact, the above program could use MAPHASH to
portably create self-documentation that worked correctly for the appropriate
implementation even if implementations varied.
Note that the thing which makes this reasonable (where package problems of
a similar nature are not) is that the funny bits are a property of a user
interface, not of a program interface.
I'm certainly willing to believe that lots of people won't use this feature,
but I do think it's meaningful. I'm also not 100% convinced that there are no
pitfalls to the style-of-use I'm proposing above, but I've not run across
any. If anyone has experience with using the above strategy or a similar one
and running into unforseen problems I've not mentioned, I'd be interested
to hear about them.
If people agree that the above program is neither faulty nor unportable, then
perhaps it or something like it could be included in the next manual draft
so that readers could see an example of the careful programming style you
have to stick to in order to make this stuff work. I admit it's not the sort
of strategy that leaps to mind the first time you see the available primitives.
The line-at-a-time issue that comes up implicitly in that example is much more
problemsome to me. I wish someone would suggest how we could deal more
satisfactorily with that.
By the way, I see no purpose in fonted char-bits. Bits are something that
it seems to me are associated with an input operation and fonts are something
associated with an output operation. I'm not sure what to draw from this,
but my impression is that it is nearly always the case that either the bits
are 0 or the font is 0, even in systems which use both bits and fonts. I
just can't imagine treating Bold Control-A different than Italic Control-A.