7 Tips and tricks: custom data conversion
V. DATE = ICONV(TD[10,11], ’D’)
V.TD = OCONV(V.DATE, ’DY2’) : FMT(OCONV(V.DATE, ’DM’), "R0%2") \ : FMT(OCONV(V.DATE, ’DD’), "R0%2") : V.TIME
R.OUTPUT<V.DATE.TIME> = V.TD
There is a lot of conversion codes (see jBC manual and jBASE knowledgebase). Also there are some special codes – for example, *A9999 shows record size (try the following under jrunT24.cmd):
Another conversion code sample C:\sa-tafc> jrunT24.cmd
jsh ~ --> LIST F.COMPANY *A9999
@ID... *A9999...
GB0010003 2166
SG0010001 2173
EU0010001 2173
GB0010002 2174
GB0010004 2166
GB0010001 2607
6 Records Listed
J of BASE, TAF of C 27 By KZM
7 TIPS AND TRICKS: CUSTOM DATA CONVERSION
If we’re way too suspicious let’t check if the output is correct. To do that we’ll change the program prog1 to output the size of all records in COMPANY application data file rather then their contents.
prog1 - the changes
18
19 * CRT V.KEY : ’ >>> ’ : R.CMP
20 CRT V.KEY : ’ >>> ’ : BYTELEN(R.CMP)
21
Why bytelen() rather that len()? Because if we have a UTF-8 environment (and we do have it, see environment variable JBASE I18N), len() will give us the number of characters rather than the number of bytes in a record.
So - compile, run (jrunT24.cmd again since we need T24 data access), see:
Record sizes checked jsh ~ --> prog1
HELLO
GB0010003 >>> 2166 SG0010001 >>> 2173 EU0010001 >>> 2173 GB0010002 >>> 2174 GB0010004 >>> 2166 GB0010001 >>> 2607
Looks like it works. What have we just done? Achieved the same goal using 2 different methods. Which one to choose? In this case - first (a built-in) one is easier. But it’s not always the same so the final choice in every particular case is yours.
Please note that in this book some examples are run under jrunT24.cmd, some – under jrunSH.cmd etc. Make sure you lanch the same cmd that is shown in an example, otherwise it might not work.
Little more about “A” conversion codes – also known as “A-correlatives”. A*n means
“field n”, so if you don’t have the dictionary file (or too lazy to type field names) you can try the following:
Another conversion code sample C:\sa-tafc> jrunT24.cmd
jsh ~ --> LIST F.COMPANY *A1 *A2 *A3
@ID... *A1... *A2... *A3...
J of BASE, TAF of C 28 By KZM
7 TIPS AND TRICKS: CUSTOM DATA CONVERSION
GB0010003 R11 MF BRANCH R11 MF BRANCH MF2
1 1
SG0010001 R11 LEAD SG CO R11 LEAD SG CO SG1
MPANY MPANY
EU0010001 R11 LEAD CO GE R11 LEAD CO GE EU1
RMANY RMANY
GB0010002 R11 LEAD MF CO R11 LEAD MF CO MF1
MPANY MPANY
GB0010004 R11 MF BRANCH R11 MF BRANCH MF3
2 2
GB0010001 Model Bank 18 Place De Ph BNK ilosophes,
CH 1205 Geneva ,
Switzerland 6 Records Listed
As we saw earlier, A*9999 is a special code, A*9998 also is:
Yet another conversion code sample C:\sa-tafc> jrunT24.cmd
jsh ~ --> LIST F.COMPANY *A9998
@ID... *A9998...
GB0010003 1
SG0010001 2
EU0010001 3
GB0010002 4
GB0010004 5
GB0010001 6
6 Records Listed
No, that’s not record “physical” location number or like as I initially thought – just a sequential number in the output. Change the sequence of records with SSELECT and see:
And yet another conversion code sample C:\sa-tafc> jrunT24.cmd
jsh ~ --> SSELECT F.COMPANY
> LIST F.COMPANY *A9998
@ID... *A9998...
J of BASE, TAF of C 29 By KZM
7 TIPS AND TRICKS: CUSTOM DATA CONVERSION
EU0010001 1
GB0010001 2
GB0010002 3
GB0010003 4
GB0010004 5
SG0010001 6
6 Records Listed
A*n is not limited by actual number of fields (most probably executing something equiv-alent to var = arr<n> ), though there is a limitation (and this number is quite large to terminate the session). To (most probably) get out-of-memory error you might try the following:
Trying to terminate the session C:\sa-tafc> jrunT24.cmd
jsh ~ --> LIST F.COMPANY *A99999999
Session dies and we have a nice new file in our bnk.run directory:
Core dump C:\sa-tafc> jrunT24.cmd
jsh ~ --> LIST . LIKE ...dmp DICT ...
TAFC_coredump-20110707213724386.dmp 1 Records Listed
Something more about solving problems in different ways. There’s an application in T24 called OFS.REQUEST.DETAIL which you most probably already know about. Let’s see its contents. Normally it’s something like:
OFS.REQUEST.DETAIL sample contents C:\sa-tafc> jrunT24.cmd
jsh ~ --> LIST F.OFS.REQUEST.DETAIL
@ID... SCRPT11062000160~I
@ID... SCRPT11062000160~I MESSAGE.KEY... SCRPT11062000160~I
APPLICATION... AA.PRD.DES.PAYMENT.SCHEDULE VERSION...
J of BASE, TAF of C 30 By KZM
7 TIPS AND TRICKS: CUSTOM DATA CONVERSION
FUNCTION... I
TRANS.REFERENCE. NOTICE.ACCOUNT-EUR-20100809 USER.NAME... SUSER1
COMPANY... GB0010001
DATE.TIME.RECD.. 09:08:03:875 10 MAR 2011 DATE.TIME.QUEUE.
DATE.TIME.PROC.. 09:08:03:928 10 MAR 2011 STATUS... PROCESSED
MSG.IN... AA.PRD.DES.PAYMENT.SCHEDULE,/I/PROCESS/1/0/,SUSER1/******/GB001 0001////,NOTICE.ACCOUNT-EUR-20100809/SCRPT11062000160~I,DESCRIPT ION:1:1=Savings Account,PAYMENT.TYPE:1:1=INTEREST.ONLY,PAYMENT.T YPE:2:1=INTEREST.ONLY,PAYMENT.METHOD:1:1=CAPITALISE,PAYMENT.METH OD:2:1=CAPITALISE,PAYMENT.FREQ:1:1=e0Y e1M e0W e0D e0F,PAYMENT.F REQ:2:1=e0Y e1M e0W e0D e0F,PROPERTY:1:1=CRINTEREST,PROPERTY:2:1
=DRINTEREST,DUE.FREQ:1:1=e0Y e1M e0W e0D e0F,DUE.FREQ:2:1=e0Y e1 M e0W e0D e0F,DEFAULT.NEGOTIABLE:1:1=YES,
MSG.OUT... NOTICE.ACCOUNT-EUR-20100809/SCRPT11062000160~I/1,DESCRIPTION:1:
1=Savings Account,PAYMENT.TYPE:1:1=INTEREST.ONLY,PAYMENT.TYPE:2:
1=INTEREST.ONLY,PAYMENT.METHOD:1:1=CAPITALISE,PAYMENT.METHOD:2:1
=CAPITALISE,PAYMENT.FREQ:1:1=e0Y e1M e0W e0D e0F,PAYMENT.FREQ:2:
1=e0Y e1M e0W e0D e0F,PROPERTY:1:1=CRINTEREST,PROPERTY:2:1=DRINT EREST,DUE.FREQ:1:1=e0Y e1M e0W e0D e0F,DUE.FREQ:2:1=e0Y e1M e0W e0D e0F,DEFAULT.NEGOTIABLE:1:1=YES,ID.COMP.1:1:1=NOTICE.ACCOUNT,
As we know, in OFS messages comma is a delimiter. Imagine we’d like to see each part of the message at a different line. What can we do here? Possible choices are:
• Create an ENQUIRY with some special processing using ENQUIRY field conversion ...and build a web service based on that enquiry... no, forget a web service – we’re aiming to low level rather than adding more and more wrappers. In general, it looks feasible but showing a single-valued field in several lines (like a multi-valued) might be a little tricky in ENQUIRY.
• Create an I-descriptor with user routine and then display the output either in EN-QUIRY or in jsh. Good idea but let’t go deeper and try “not to harm any animal”... sorry, I meant “keep T24 intact”.
• Create what in jBASE (and not only here but in all “multi-valued” world) is called
“user exit”. This technique is described in details in jBASE knowledgebase; let’t take an example from there and amend it to cater our needs.
J of BASE, TAF of C 31 By KZM
7 TIPS AND TRICKS: CUSTOM DATA CONVERSION
There are two methods to create a custom conversion code (read: user exit) - create one routine per each new code or to put everything into one routine with standard name JBCUserConversions. In this example we’ll use the second one.
Our chosen name for a conversion code will be “XZ”. So then the source of the routine JBCUserConversions will look like:
JBCUserConversions - amended
1 * Amended by KZM
2 SUBROUTINE JBCUserConversions (result, source, code, type, error)
3
4 BEGIN CASE
5 CASE code EQ "XZ"
6 IF type THEN
7 * result = source : " was OCONV"
8 result = source
9 CHANGE ’,’ TO @VM IN result
16 END CASE
17
18 RETURN
19
20 END
21
Some code was commented by me but retained to give you the better idea of this method.
Now let’s compile it (for reasons yet unknown to me I wasn’t able to compile any sub-routine using jcompile so here’s good old BASIC and CATALOG). But firstly we need to add some environment variables to jrunSH.cmd:
New variables in jrunSH.cmd
29
30 set JBCOBJECTLIST=%HOME%\lib
31 set JBCDEV_LIB=%HOME%\lib
32
Here goes compilation:
Compilation of JBCUserConversions C:\sa-tafc> jrunSH.cmd
jsh ~ --> BASIC . JBCUserConversions
J of BASE, TAF of C 32 By KZM
7 TIPS AND TRICKS: CUSTOM DATA CONVERSION
JBCUserConversions BASIC_1.c
Source file JBCUserConversions compiled successfully jsh ~ --> CATALOG . JBCUserConversions
JBCUserConversions
Object JBCUserConversions cataloged successfully
mt -nologo -manifest C:\sa-tafc\lib\lib0.dll.manifest -outputresource:
C:\sa-tafc\lib\lib0.dll;2 failed , command returned a code of -1 Library C:\sa-tafc\lib\lib0.dll rebuild okay
jsh ~ -->
We can see that the file $JBCUserConversions appeared in sa-tafc (we can delete it), the directory sa-tafc\lib was automatically created and – what matters for us – in it we have the new file lib0.dll where the compiled routine is supposedly been placed; in any case, jshow will let us know if it is so:
Check of JBCUserConversions jsh ~ --> jshow -c JBCUserConversions
Subroutine: C:\sa-tafc\lib\lib0.dll
jBC JBCUserConversions version 201014.0 Mon Jun 20 09:58:23 2011 jBC JBCUserConversions source file .
jsh ~ -->
As soon as we’re going to apply our new conversion code“XZ”to T24 data file, we need our conversion subroutine to be visible for work in T24 environment. To achieve that we need to add the directory with our lib0.dll here:
Correction of jrunT24.cmd
37 set JBCOBJECTLIST=%T24_HOME%\lib;%T24_HOME%\t24lib;%HOME%\lib
Now try to see the results. After toying a little with output width finally we can see something more readable (the full command didn’t fit here properly and of course should be entered in one line):
Results of customization of JBCUserConversions C:\sa-tafc> jrunT24.cmd
jsh ~ --> LIST F.OFS.REQUEST.DETAIL ID-SUPP EVAL "@ID[1,20]"
EVAL "OCONV(MSG.IN, ’XZ’)" EVAL "OCONV(MSG.OUT, ’XZ’)"
@ID[1,20
. OCONV(MSG.IN, "XZ")... OCONV(MSG.OUT, "XZ")...
J of BASE, TAF of C 33 By KZM
7 TIPS AND TRICKS: CUSTOM DATA CONVERSION
SCRPT11062 AA.PRD.DES.PAYMENT.SCHEDULE NOTICE.ACCOUNT-EUR-20100809/SC
000160~I RPT11062000160~I/1
/I/PROCESS/1/0/ DESCRIPTION:1:1=Savings Accoun
t
SUSER1/******/GB0010001//// PAYMENT.TYPE:1:1=INTEREST.ONLY NOTICE.ACCOUNT-EUR-20100809/SC PAYMENT.TYPE:2:1=INTEREST.ONLY RPT11062000160~I
DESCRIPTION:1:1=Savings Accoun PAYMENT.METHOD:1:1=CAPITALISE t
PAYMENT.TYPE:1:1=INTEREST.ONLY PAYMENT.METHOD:2:1=CAPITALISE PAYMENT.TYPE:2:1=INTEREST.ONLY PAYMENT.FREQ:1:1=e0Y e1M e0W e
0D e0F
PAYMENT.METHOD:1:1=CAPITALISE PAYMENT.FREQ:2:1=e0Y e1M e0W e 0D e0F
PAYMENT.METHOD:2:1=CAPITALISE PROPERTY:1:1=CRINTEREST PAYMENT.FREQ:1:1=e0Y e1M e0W e PROPERTY:2:1=DRINTEREST 0D e0F
PAYMENT.FREQ:2:1=e0Y e1M e0W e DUE.FREQ:1:1=e0Y e1M e0W e0D e
0D e0F 0F
PROPERTY:1:1=CRINTEREST DUE.FREQ:2:1=e0Y e1M e0W e0D e 0F
PROPERTY:2:1=DRINTEREST DEFAULT.NEGOTIABLE:1:1=YES DUE.FREQ:1:1=e0Y e1M e0W e0D e ID.COMP.1:1:1=NOTICE.ACCOUNT 0F
DUE.FREQ:2:1=e0Y e1M e0W e0D e ID.COMP.2:1:1=EUR 0F
Note ID-SUPP keyword suppressing the output of @id since default display parameter for it is too big to fit all we need into screen width.
If we hadn’t included our lib directory to JBCOBJECTLIST, we would have got the following error:
Error message Error in named attribute XZ
Unknown conversion code.
J of BASE, TAF of C 34 By KZM
7 TIPS AND TRICKS: CUSTOM DATA CONVERSION
This conversion code now also can be used in ENQUIRY field conversion. Of course to make your custom conversion code generally available you need the compiled subroutine JBCUserConversions to be visible for all T24 users, whether it’s Classic or Browser (in latter case it’s environment.vars or whichever file used in jBoss or TCServer is to be amended).
The template for an individual routine for each custom conversion you can find going to TAFC home directory, then to subdirectory src. It’s named jBASE UserExit.
J of BASE, TAF of C 35 By KZM
8 SOME PERFORMANCE TRICKS – DYNAMIC ARRAY POPULATION, SUBSTRING SEARCH