You need this generality only if you need someone other than (after)
the developer(s), like a user or admin, to modify the emulation, or
perhaps to select among multiple (many?) emulations. To just emulate a
specific terminal/mode (or even family), I would hardcode at least the
common structure for it (e.g. the X3.64 style of CSI, operands,
somecols2-3 modifiers, cols4-5char terminator or cols6-7char + I don't
recall) leaving the rest of the problem simpler.
But if you want to (or must) stay with using termcap(ish) strings:
In other words, I have an array that holds termcap info:
Except for the \E, which isn't a valid C escape character, and the ^O
and ^N, which aren't C escape characters at all, those look very much
like *scanf() strings to me.
For example, for the cm string, the terminal can see incoming strings like
this:
{esc}[3;4H
{esc}[;4H
{esc}[3;H
I can't quite come up with a parser that can handle that, and which
doesn't get all convoluted...
Perhaps you don't need to? You might be able to get sscanf() to do the
job for you.
Translate the \E and ^Whatever in your strings to the corresponding real
C characters (presumably your compiler allows \E as an extension, so you
_might_ not need to do that bit, but your code does become non-portable
if you rely on this; and ^Letter is presumably quite easy to do). Then,
see if you can mangle either the %spec bits, or your call to sscanf(),
so that it accepts your input.
But: *printf %i will generate only decimal digits, but *scanf %i will
accept optional whitespace, optional sign and digits, and also allow
0octal and 0xhex forms; *scanf %d and (even!) %u will allow the first
two but not the third; these might result in false matches for
improper input, if that is a concern. (Perhaps not, if the source from
which the terminal emulator is receiving this data never makes
mistakes, and the comms path never silently corrupts.) Conversely,
*scanf %i or %d will fail, and cause scanning to stop, if the number
is entirely omitted, as is legal for (most) X3.64/VT100 escape
sequences, as the OP's example shows. Similarly %i (or %d) followed
immediately by %d, applied to contiguous digits which they could have
generated (or did) in *printf, will fail because the first specifier
doesn't 'see' the boundary that (would have) occurred in generation
and uses up (all) the data that should match the second specifier.
Also a space in *scanf format will match any amount of whitespace in
the data or none, not just a single space. If necessary, you can do
the latter by changing to %1[ ], but since I think trying to use
actual *scanf is not worth it anyway, see below, I wouldn't bother. I
also don't recall offhand any terminal commands that use exactly a
space as (required) data, although some (ADM3A, IIRC) do use a single
character whose code STARTS at (ASCII) space.
If that doesn't work, the easiest way to get your hands on a sscanf()-
variation which can handle your termcap strings would be to start from
normal sscanf() code and modify that. If Ganuck code would be
acceptable, you could use that; if not, many textbooks have you write
one as an exercise, and include simplified sample code, which may
already be useful enough. IIRC K&R is one of these.
This problem appears to me enough different from and simpler than what
*scanf must do that I would find it easier to start from scratch and
build up, perhaps looking at *scanf for ideas in the unlikely event I
had difficulty with a particular point.
I would probably also try, if it doesn't make the code too complex
(and difficult to maintain) or require more space than allowable,
which could be any at all if this must run multithreaded and can't be
provided with an instance pointer or similar, to make the scans
'restartable' so that for each possible currently possible match I
record the state and for the next received character only advance or
fail each scan from that state.
- formerly david.thompson1 || achar(64) || worldnet.att.net