Multiple accept keys - a possible solution
Posted in 1996
Folks,
Some time ago I posted an article requesting help on how to implement in 4gl multiple accept keys. It was the last of a long series.
For those of you who have forgotten, let me refresh the whole thing:
Multiple accept keys (or a way of faking them) are useful in that one can have an input/input array/construct etc statement terminated (that is, the input variables are filled with the contents of the input buffer, validated by the appropriate after field, etc) by more than one accept key, so that, after the input, the processing can continue in different ways depending on the last key hit by the user.
To further clarify things, let me show 2 examples:
1) A multi page input. A master detail relationship made of a huge record, an array & some text. They don't fit in a single page form and 4gl does not allow multi page forms (Perform does). Having to use three different forms, one for each input, it would be nice to use ESC to flag that the whole record input has finished, <Next Scrn> to terminate one input [array] & move to the next, <Prev Scrn> to move to the previous.
2) An invoice. The user may want to save and print it (say using ^P) or just save it as a draft for later printout (ESC).
The obvious solution (the one I don't want to adopt) is to use on key clauses & get_fldbuf, like in the code below:
input by name tons_of_fields_list
after field field1
if do_some_processing()
then
next field field1
end if
#
# more after fields here
#
after field field_nnnnnnnn
if do_some_other_processing()
then
next field_nnnnnnnn
end if
on key (2nd_accept)
call get_fldbuf(tons_of_fields_list)
returning tons_of_fields_list
case
when infield(field1)
if do_some_processing()
then
next field field1
end if
#
# more when infield() here
#
when infield(field_nnnnnnn)
if do_some_other_processing()
then
next field field_nnnnnnn
end if
end case goto exit_input #dirty, but it works!
after input
label exit_input:
#
# some global validation code here
#
end input
case
when fgl_lastkey()=fgl_keyval("accept")
#
# etc, etc
#
end case
However when the number of field becomes high, and the after field code huge, maintaining such a code becomes almost impossible, not to mention the waste of code.
What's more,
- you'll have to forget about any value validation included in your form and use after fields instead
- get_fldbuf rudely complains when the contents of a buffer cannot be properly converted to the type of the destination variable. This might not be appropriate for production code.
All this for not being able to write something like
options accept key key1, key2, key3...
or
on key (my_other_accept_key)
call fgl_force_the_@#$$%&_input_to_validate_buffered_values()
Other solutions, many already outlined here, comprise things like ungetc()ing the accept key into the input buffer, redirecting the input buffer to temporarily read the accept key from a file, sticking a 2016 in _eflastkey or playing with the appropriate _EFICB struct. These, while simplifying 4gl code, either are too dangerous / highly unportable, or quite simply do not work.
Tim Schaefer has suggested the usage of code generation techniques. Sorry, Tim, not for me!
Turning to 4gl, the code I outline below, while certainly not being clean, has the advantage of not duplicating validation code (thus being easy to maintain) and, if your after fields are big enough (those in example 1 above exceed 500 lines, and that's not counting all the code I managed to move to functions), it does save memory devoted to code.
Enough talk. A bit of code now:
options accept key F64 #a useless key
input by name tons_of_fields_list
before field tons_of_fields_list
let user_accept_key=0
after field field1
label entry_field1:
if do_some_processing()
then
next field field1
end if
goto exit_input
#
# more after fields here
#
after field field_nnnnnnnn
label entry_field_nnnnnnn:
if do_some_other_processing()
then
next field_nnnnnnnn
end if
goto exit_input
on key (true_accept_key, 2nd_accept_key, ...)
let user_accept_key=fgl_lastkey()
call get_fldbuf(tons_of_fields_list)
returning tons_of_fields_list
case
when infield(field1)
goto entry_field1
#
# more when infield() here
#
when infield(field_nnnnnnn)
goto entry_field_nnnnnnn
end case
after input
label exit_input:
if user_accept_key=0
then
continue input
end if
#
# some global validation code here
#
end input
options accept key true_accept_key
case
when user_accept_key=true_accept_key
#
# etc. etc.
#
end case
Those of you who have peeked at 4gl generated c code may see a resemblance with the internal workings of compiled 4gl input statements.
Of course, many of the previous limitations apply, and the code above cannot be used if options input no wrap is in effect (but finding a workaround shouldn't be difficult).
Is there anyone out there who has a better solution? Maybe Informix employees contributing to this forum (Jonathan?!) could give us some help. Please let me know...
ciao,
marco.
____________________________________________________________________________
rem radioterapia, which I immeritately manage, seldom agrees with what I say
marco greco (Catania, Italy) Work:
marcog@ctonline.it rem radioterapia 39 95 447828 fax 446558
(was mar.greco@agora.stm.it) Achea 39 95 503117