This month I am going to tie together a few things that I have shown in previous columns as well as introduce some new topics in the process. The first thing I am going to do is introduce you to my highly proprietary process for loading function keys. Over the years I have written at least five different methods of loading function keys before I finally hit on this method. They all had their strengths and weaknesses, but this was the easiest to code, and executed the fastest. It doesn't have the modularity of keeping them in a flat file, but it is a hell of a lot faster. Keep in mind as we go through this, that this is meant to spark your imagination, go ahead and use whatever bits that you think are worth using.
Ok, go ahead and take a look at the sample code so we are both talking about the same thing. All the variables in the WORKING-STORAGE section are what I define by default, I keep them in an INCLUDE file to keep it simple. As an aside, did you know that using $INCLUDE instead of COPY will cause your code to compile faster?
The variables KEY-POINT and KEY-BUFF are used to actually display the function keys and are referenced in the macros, so we will cover them shortly. The SET-FKEY variable defines the escape sequence to load a single function key with two characters of data. I always use the default values for the function keys, which are two characters, you will need to modify that if you want a different length. The escape sequence is described in detail in the terminal manual for the 2392 terminal. You can also find many of these described in the WRQ manual for the Reflection product. The KEY-ON and KEY-OFF escape sequences will turn on and off the display of the function keys respectivly.
The definitions of KEY1 thru KEY8 are the default value for the function
keys. It's as easy to use the default values as it is to input special
values, so to avoid conflict with some other escape sequence I always use
the default values. So now that we have covered the variables and
escape sequences needed to program the function keys, let's look at how
to actually do it.
The PREPFKEY macro should be called everytime you are going to be loading
and displaying a function key sequence. It clears out the buffer
we use to load the function keys and initializes the buffer pointer to
1.
The LOADFKEY macro will take three parameters to determine the label that will display in the function key, the data in the function key, and which function key number to load. You can specify other parameters if you wish, but for me I take the defaults for the rest that I have put in WORKING-STORAGE. The real trick here is the STRING command and how it is being used to concatenate data into a variable. As you know, when you MOVE data to a variable it first clears the receiving variable out, and then transfer's the data. There is no way to use MOVE to link to strings together. Using the STRING command will allow you to link multiple strings together in one long concatenated field, but what many people don't realize is that you can specify a pointer on the STRING command and keep concatenating data through successive calls. So what we are doing in LOADFKEY is building our escape sequence for each function key one at a time and then stuffing it into KEY-BUFF. We are using KEY-POINT to maintain the pointer to KEY-BUFF of the end of the last string that was moved in. We set KEY-POINT to 1 initially to make sure it points at the first byte. If you have KEY-POINT set to 0, nothing will ever end up in KEY-BUFF because there is no zeroth byte. The reason I use this methodology will become clear shortly.
The SHOWFKEY macro first appends the KEY-ON escape sequence to KEY-BUFF. This is to make sure that the function keys will be displayed and not just loaded, this is just a saftey precaution. We next subtract one from KEY-POINT because it is pointing to the next available byte, not the last used byte, and we need the exact length of the string. Now I convert KEY-POINT to a negative value in preperation for the call to the PRINT intrinsic. Finally I call the PRINT intrinsic specifying a carriage control value of %320, this is the equivalent of saying DISPLAY WITH NO ADVANCING, and will keep the cursor for issuing a carriage return/line feed at the end.
Now why did I load up a buffer and use the PRINT intrinsic? Let
me explain something about terminal I/O first. Everytime you issue
the DISPLAY command it causes a CPU interrupt, this takes potential CPU
time away from something else. If I had done these function keys
one at a time I would have issued 9 CPU interrupts, one for each function
key, and one to turn on the function keys. Now all I/O to eventually
uses the FREAD and FWRITE intrinsics no matter what it is you use
in your program, ie. ACCEPT, DISPLAY, READ, WRITE. Since you can DISPLAY
virtually anything the compilier has to go through several steps before
it get's to the FWRITE.
As I recall the DISPLAY statement actually is five call's above
FWRITE, so now those 9 DISPLAY statements convert into about 45 calls
to the CPU. The PRINT intrinsic is only 2 or 3 levels above
FWRITE, and since we buffer up all of our data into one buffer we
only have to make the one CPU interrupt to load all of the function
keys. The advantage to PRINT over FWRITE is that it is fairly
low level, doesn't require you to FOPEN the terminal, and it is pretty
easy to code for. It is overkill for some things since you have to
specify a length to the call, and using code to calculate the length of
a string could kill any speed advantage to using PRINT in the first place.
WORKING-STORAGE SECTION. * 01 WS-OPTION
PIC X(02) VALUE SPACES. * **************
FKEY STUFF * 01 KEY-POINT
PIC S9(9) COMP VALUE 0. 01 KEY-BUFF
PIC X(300) VALUE SPACES. * 01 SET-FKEY.
03
PIC X
VALUE %33. 03
PIC X(02) VALUE '&f'.
03 FKEY-TYPE PIC 9
VALUE 2. 03
PIC X
VALUE 'a'. 03 FKEY-NUM
PIC 9. 03
PIC X(04) VALUE 'k16d'.
03 FKEY-LEN PIC 99
VALUE 02. 03
PIC X
VALUE 'L'. 03 FKEY-LABEL
PIC X(16). 03 FKEY-DATA
PIC X(02). 03
PIC X
VALUE %15. * 01 KEY-ON. 03
PIC X
VALUE %33. 03
PIC X(03) VALUE "&jB". *
01 KEY-OFF. 03
PIC X
VALUE %33. 03
PIC X(03) VALUE "&j@". *
01 KEY1. 05
PIC X VALUE %33. 05
PIC X VALUE 'p'. * 01 KEY2.
05
PIC X VALUE %33. 05
PIC X VALUE 'q'. * 01 KEY3.
05
PIC X VALUE %33. 05
PIC X VALUE 'r'. * 01 KEY4.
05
PIC X VALUE %33. 05
PIC X VALUE 's'. * 01 KEY5.
05
PIC X VALUE %33. 05
PIC X VALUE 't'. * 01 KEY6.
05
PIC X VALUE %33. 05
PIC X VALUE 'u'. * 01 KEY7.
05
PIC X VALUE %33. 05
PIC X VALUE 'v'. * 01 KEY8.
05
PIC X VALUE %33. 05
PIC X VALUE 'w'. * PROCEDURE DIVISION. A0000-MACROS.
$DEFINE %PREPFKEY= MOVE SPACES
TO KEY-BUFF MOVE 1
TO KEY-POINT# * $DEFINE %LOADFKEY=
MOVE !1 TO FKEY-LABEL MOVE
!2 TO FKEY-DATA MOVE !3
TO FKEY-NUM STRING SET-FKEY DELIMITED
BY SIZE INTO KEY-BUFF
WITH POINTER KEY-POINT# * $DEFINE %SHOWFKEY=
STRING KEY-ON DELIMITED BY SIZE INTO KEY-BUFF
WITH POINTER KEY-POINT SUBTRACT
1 FROM KEY-POINT MULTIPLY KEY-POINT
BY -1 GIVING KEY-POINT CALL INTRINSIC
"PRINT" USING KEY-BUFF, KEY-POINT, %320# * A1000-INIT.
%PREPFKEY. %LOADFKEY(" Add
Record "#,KEY1#,1#). %LOADFKEY(" Change Record
"#,KEY2#,2#). %LOADFKEY(" Delete Record "#,KEY3#,3#).
%LOADFKEY(" Ignore Changes"#,KEY4#,4#). %LOADFKEY("
"#,KEY5#,5#). %LOADFKEY("
"#,KEY6#,6#). %LOADFKEY(" Back
Up "#,KEY7#,7#). %LOADFKEY("
Stop Run "#,KEY8#,8#).
%SHOWFKEY.
ACCEPT WS-OPTION FREE.
IF WS-OPTION = KEY8 STOP RUN.
Here is an interesting bit of trivia, I wrote a tiny program that just
did a simple display of one word. I then changed the program to use
the PRINT intrinsic instead of DISPLAY. I decompiled both programs
to see what instructions had gotten generated, and from the following
two lists you can see the difference.
EXAMPLE WITH DISPLAY VERB:
. 0.133 177777 ..
STT COBOLTRAP . 0.134 177777 ..
STT DEBUG . 0.135 177777 ..
STT TERMINATE' . 0.136 177777 ..
STT C'DISPLAY'INIT . 0.137 177777 ..
STT C'DISPLAY'FIN . 0.140 177777 ..
STT C'DISPLAY . 0.141 000027 ..
STT %27 . 0.142 000000
.. STT %0 . 0.143
040010 @. STT LENGTH = %10 , INTERNAL = %2
EXAMPLE WITH PRINT INTRINSIC:
. 0.121 177777 ..
STT COBOLTRAP . 0.122 177777 ..
STT DEBUG . 0.123 177777 ..
STT TERMINATE' . 0.124 177777 ..
STT PRINT . 0.125 000012 ..
STT %12 . 0.126 000000
.. STT %0 . 0.127
040006 @. STT LENGTH = %6 , INTERNAL = %2
I want to wrap up this month by once again reminding you to let me
know what you think of this column. If you have tips that you would
like to share, or question you want to ask, please feel free. I want
to start relying on your input for future columns so let me know if these
are to basic, not basic enough, need more detail, need less detail, whatever
you want, and I will do my best to accomodate everyone. You can get
a hold of me through Interex, or by leaving me electronic mail on Compuserve.
Until next month........