You are on page 1of 383

c c

c
Hitchhiker’s Guide To
c

jBASE and

c
Edition 4, final. Built at June 12, 2013
c
c b a n V. K a z i m i r ch i k 2011 2012 2013
0.1 What’s new in edition 4
New jBC code parser – different colours are now assigned for keywords, functions and special
variables like @FM. Hope that code became more readable. See comments in the example
below:

* The comment
$INSERT I_COMMON ;* special keyword, default text
$INSERT I_EQUATE

CRT CHECKSUM('ABC') ;* regular keyword, function and a string

IF var_1 EQ 3.14 THEN CRT "Pi is nearby" ;* number

#ifdef DEBUGGING
CRT var_1
#endif

var_2 = TODAY : FM ;* T24 global variables


GOSUB DO.IT ;* keyword that passes the execution elsewhere...
STOP ;* ...or stops it

* a label:
DO.IT:
var_1 = @TIME : @FM : TIME() ;* more special keywords (or variables)
RETURN

END

The book was fully revised; some manual formatting was done to achieve a better look.
All jBC code examples were retested (and many of them enhanced); now their style is the
same, including such things like variables naming etc. Some new examples and chapters were
added.

REM Page 2
Contents
0.1 What’s new in edition 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1 Preface 11

2 What I prefer not to use 13

3 jBC 14
3.1 Code compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.2 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.3 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.4 String variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.5 Line continuation; several statements on the same line . . . . . . . . . . . . . 18
3.6 String operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.7 Comparisons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.8 Numeric variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.9 Boolean variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.10 Data files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.11 File variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.12 Dynamic arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.13 Differences between emulations . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.14 jBC statements and functions . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.15 ABORT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.16 ASCII() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.17 ASSERTEQUALS(), ASSERTTRUE() . . . . . . . . . . . . . . . . . . . . . 37
3.18 BREAK ON/OFF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.19 BYTELEN(), LEN(), CHAR() . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.20 CALL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.21 CALLJ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.22 CASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
3.23 CATS() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.24 CHAIN, CLEARINPUT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.25 CHANGE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.26 CHANGETIMESTAMP(), LOCALDATE() . . . . . . . . . . . . . . . . . . 42
3.27 CHAR() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.28 CHDIR() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.29 CHECKSUM() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.30 CLEAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.31 CLEARCOMMON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.32 CLEARDATA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.33 CLEARFILE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.34 CLOSE, ASSIGNED() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.35 COMMON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.36 CONVERT statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

REM Page 3
3.37 CONVERT() function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.38 CREATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.39 CRT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.40 DEL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.41 DELETE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.42 DELETELIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.43 DELETESEQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.44 DIM, MAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.45 DIR() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.46 DIV() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.47 DROUND() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.48 DTX(), XTD() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.49 ENCRYPT() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.50 EXECUTE/RTNLIST/CAPTURING, DATA, DCOUNT() . . . . . . . . . . 52
3.51 GETENV() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.52 GETLIST, SELECT, READNEXT, OPEN, READ, WRITE . . . . . . . . . 54
3.53 GOSUB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.54 GROUPSTORE() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.55 FIELD(), COL1(), COL2() . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.56 FILEINFO(), NULL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.57 FIND, FINDSTR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.58 FOLD() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.59 FOR...NEXT...STEP...CONTINUE...BREAK . . . . . . . . . . . . . . . . . 58
3.60 ICONV(), OCONV(), FMT() . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.61 IN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.62 INDEX() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.63 INMAT() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.64 INPUT, DOWNCASE() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
3.65 INSERT() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
3.66 IOCTL() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.67 ISCNTRL() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.68 ISDIGIT(), ISLOWER(), ISPRINT(), ISSPACE(), ISUPPER() . . . . . . . 65
3.69 ITYPE() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
3.70 JBASECOREDUMP() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
3.71 JBASESubroutineExist() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
3.72 JQLCOMPILE(), JQLEXECUTE(), JQLFETCH(), JQLGETPROPERTY() 70
3.73 KEYIN(), TIMEDATE(), UPCASE() . . . . . . . . . . . . . . . . . . . . . . 71
3.74 LATIN1() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
3.75 LEN(), INT() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
3.76 LOCATE, INS, MINIMUM(), MAXIMUM() . . . . . . . . . . . . . . . . . . 72
3.77 LOWER() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
3.78 MAKETIMESTAMP() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
3.79 MATBUILD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
3.80 MATCH(ES) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
3.81 MATPARSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

REM Page 4
3.82 MAXIMUM() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
3.83 MOD() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
3.84 MSLEEP() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
3.85 NEGS() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
3.86 NUM() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
3.87 OPENSEQ, READSEQ, CLOSESEQ . . . . . . . . . . . . . . . . . . . . . . 79
3.88 OSBREAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
3.89 OSREAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
3.90 PRECISION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
3.91 PRINTERR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
3.92 PROMPT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
3.93 PUTENV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
3.94 PWR() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
3.95 RAISE() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
3.96 READBLK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
3.97 READL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
3.98 READNEXT combined with READPREV . . . . . . . . . . . . . . . . . . . 84
3.99 READSEQ – platforms compatibility . . . . . . . . . . . . . . . . . . . . . . 85
3.100 READU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
3.101 READV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
3.102 RECORDLOCKED() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
3.103 REGEXP() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
3.104 RELEASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
3.105 REMOVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
3.106 REPLACE() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
3.107 REUSE(), SUBS() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
3.108 SEEK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
3.109 SENTENCE() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
3.110 SEQ() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
3.111 SORT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
3.112 SSELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
3.113 SSELECTV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
3.114 STATUS() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
3.115 STATUS statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
3.116 STR() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
3.117 SUM() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
3.118 SYSTEM() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
3.119 TIME() and @TIME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
3.120 TIMESTAMP() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
3.121 TRANSTART, TRANSEND, TRANSQUERY(), TRANSABORT . . . . . . 99
3.122 TRIM() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
3.123 TRIMBS() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
3.124 TRIMFS() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
3.125 UNASSIGNED() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
3.126 UNIQUEKEY() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

REM Page 5
3.127 UTF8() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
3.128 WEOFSEQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
3.129 WRITEBLK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
3.130 WRITELIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
3.131 WRITESEQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
3.132 WRITEU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
3.133 WRITEV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
3.134 XLATE() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110

4 jQL 111
4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
4.2 LIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
4.3 SELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
4.4 SSELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
4.5 NSELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
4.6 XSELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
4.7 BSELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
4.8 EVAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
4.9 Manipulations with lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
4.10 Other jQL stuff . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136

5 Environment variables 139

6 Some examples of paragraphs 146


6.1 Automate routine jQL task . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
6.2 Automate routine T24 task . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
6.3 Output something to screen (jCL) . . . . . . . . . . . . . . . . . . . . . . . . 147
6.4 Read a file (jCL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
6.5 Wrap long lines in jQL statement using jCL . . . . . . . . . . . . . . . . . . 147
6.6 Run jBC program from jCL . . . . . . . . . . . . . . . . . . . . . . . . . . . 147

7 JED 147
7.1 Text indentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
7.2 Input @VM and @SM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
7.3 Return where you were last time . . . . . . . . . . . . . . . . . . . . . . . . . 149

8 Debugger 149
8.1 Enter the debugger at program start . . . . . . . . . . . . . . . . . . . . . . 149
8.2 Get call stack information . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
8.3 List variables using mask . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
8.4 List a variable with additional information . . . . . . . . . . . . . . . . . . . 149
8.5 Amend a variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
8.6 Remove the value altogether . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
8.7 Set variable contents to CHAR(0) . . . . . . . . . . . . . . . . . . . . . . . . . 150

REM Page 6
9 Tools and utilities 150
9.1 jgrep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
9.2 jprof - quick tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
9.3 LIST-OPEN-FILES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
9.4 MW42 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
9.5 t24version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
9.6 SQLUPDATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
9.7 telnetd.exe, Transcmd.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
9.8 WHERE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
9.9 LOGOFF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
9.10 jshelltype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
9.11 SP-NEWTAB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
9.12 MSG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157

10 OFS 157
10.1 Characters substitution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
10.2 “Replace” option . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
10.3 Launch an enquiry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
10.4 Prepare complex OFS message using SELECT...SAVING EVAL . . . . . . . 162

11 T24 global variables 162


11.1 F array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
11.2 N array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
11.3 T array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
11.4 LOCAL.REF.FIELD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
11.5 Other useful things for the current application . . . . . . . . . . . . . . . . . 165
11.6 Current user and session info . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
11.7 File variables that are global . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
11.8 Cached records or arrays with useful information – so no need to read that all
from disk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
11.9 Other useful things in I COMMON and I EQUATE . . . . . . . . . . . . . . 167
11.10 I ENQUIRY.COMMON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
11.11 Other inserts of interest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167

12 T24 hooks 167


12.1 Record types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
12.2 Mainline routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
12.3 VERSION/ID.RTN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
12.4 VERSION/CHECK.REC.RTN . . . . . . . . . . . . . . . . . . . . . . . . . 168
12.5 VERSION/AUT.NEW.CONTENT . . . . . . . . . . . . . . . . . . . . . . . 170
12.6 VERSION/VALIDATION.RTN . . . . . . . . . . . . . . . . . . . . . . . . . 172
12.7 VERSION/INPUT.ROUTINE . . . . . . . . . . . . . . . . . . . . . . . . . . 173
12.8 VERSION/AUTH.ROUTINE . . . . . . . . . . . . . . . . . . . . . . . . . . 174
12.9 VERSION/AFTER.UNAU.RTN, BEFORE.AUTH.RTN . . . . . . . . . . . 175
12.10 ENQUIRY/BUILD.ROUTINE . . . . . . . . . . . . . . . . . . . . . . . . . 175

REM Page 7
12.11 ENQUIRY/CONVERSION routine . . . . . . . . . . . . . . . . . . . . . . . 178
12.12 NOFILE enquiry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
12.13 OFS.SOURCE/IN.MSG.RTN . . . . . . . . . . . . . . . . . . . . . . . . . . 181
12.14 OFS.SOURCE/OUT.MSG.RTN . . . . . . . . . . . . . . . . . . . . . . . . 183
12.15 DE.MAPPING/ROUTINE . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
12.16 DE.DISP.CONTROL/FIELD.NAME . . . . . . . . . . . . . . . . . . . . . . 190
12.17 ACCOUNT.PARAMETER/ACCOUNTING.SUBRTN . . . . . . . . . . . . 192
12.18 EB.FREQUENCY/SPECIAL.ROUTINE . . . . . . . . . . . . . . . . . . . 194
12.19 I-descriptors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195

13 T24 API 196


13.1 CDD() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
13.2 CDT(), REM() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
13.3 CFQ() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
13.4 DISPLAY.MESSAGE() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
13.5 DUP() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
13.6 EB.ROUND.AMOUNT() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
13.7 EB.SET.NEXT.TASK(), EB.SET.NEW.TASK() . . . . . . . . . . . . . . . . 200
13.8 ENQUIRY.DISPLAY() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
13.9 FATAL.ERROR() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
13.10 F.READ() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
13.11 F.READU(), F.WRITE(), F.RELEASE() . . . . . . . . . . . . . . . . . . . 204
13.12 F.DELETE() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
13.13 GET.STANDARD.SELECTION.DETS() . . . . . . . . . . . . . . . . . . . 205
13.14 LOAD.COMPANY() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
13.15 IN2() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
13.16 OFS.GLOBUS.MANAGER() . . . . . . . . . . . . . . . . . . . . . . . . . . 208
13.17 OFS.POST.MESSAGE() . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
13.18 OPF(), TXTINP() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
13.19 OVE() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
13.20 PRO() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
13.21 STORE.END.ERROR() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
13.22 STORE.OVERRIDE() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
13.23 TXT() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216

14 How-tos 218
14.1 Get rid of speaker beeps in jsh (Windows) . . . . . . . . . . . . . . . . . . . 218
14.2 Get rid of speaker beeps in T24 Classic . . . . . . . . . . . . . . . . . . . . . 219
14.3 Automatically create the new file on target system when using DL.DEFINE 219
14.4 Correct the screen used in “L” function . . . . . . . . . . . . . . . . . . . . . 219
14.5 To see changes in the example given above without necessity to relogin to T24 221
14.6 Overcome “200 pages” ENQUIRY limit set in SPF . . . . . . . . . . . . . . 224
14.7 Avoid hanging of Globus Desktop on DEBUG statement . . . . . . . . . . . . 225
14.8 Place “$” files separately from sources . . . . . . . . . . . . . . . . . . . . . 225
14.9 See last jsh commands issued from the same port number . . . . . . . . . . 226

REM Page 8
14.10 See last jsh and jed commands issued from any port number . . . . . . . . 226
14.11 Correct the error appearing after LIST VOC command . . . . . . . . . . . . 227
14.12 Enter debugger in tSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
14.13 Clean shared memory after installing new release in Unix (example for jBASE5)228
14.14 Install TAFC without admin rights under XP . . . . . . . . . . . . . . . . . 229
14.15 See which files and records took part in T24 transaction . . . . . . . . . . . 229
14.16 Distribute a file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
14.17 Set up transaction journalling . . . . . . . . . . . . . . . . . . . . . . . . . . 234
14.18 Create an online service that is activated at certain periods of time . . . . . 244
14.19 Embed python into jBC code . . . . . . . . . . . . . . . . . . . . . . . . . . 250
14.20 Adapt PuTTY for accepting T24 functional keys F1 ... F7 . . . . . . . . 254
14.21 Run PuTTY in typical T24 environment without using registry . . . . . . . 257
14.22 Create a reverse tunnel so you can log in from Unix server to your local PC 259
14.23 Upload a file to server in one step (SCP) . . . . . . . . . . . . . . . . . . . . 260
14.24 Automate frequently used command on a server (e.g. compile a source) . . . 260
14.25 Login automatically to T24 using Browser client . . . . . . . . . . . . . . . 260
14.26 Execute a program in background . . . . . . . . . . . . . . . . . . . . . . . 261
14.27 Generate a simple temporary text file on the fly . . . . . . . . . . . . . . . . 262
14.28 Create a directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262

15 Performance notes 262

16 Known issues 263


16.1 jQL “BUT” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
16.2 Basic SSELECT...TO {list number} . . . . . . . . . . . . . . . . . . . . . . . 264
16.3 SSELECT...SAVING EVAL . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
16.4 EVAL ABSS() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
16.5 Differences in default SELECT list and a numbered one with non-zero number 265
16.6 NSELECT doesn’t keep a list . . . . . . . . . . . . . . . . . . . . . . . . . . 266
16.7 jQL “COPY...UPDATING” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
16.8 Nesting of jsh shells . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
16.9 FIELD() with multi-character delimiter . . . . . . . . . . . . . . . . . . . . . 268
16.10 COMPARE() doesn’t work as expected . . . . . . . . . . . . . . . . . . . . 268
16.11 DELETEU behaviour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269

17 T24 classic 269


17.1 What works there (as well as elsewhere) . . . . . . . . . . . . . . . . . . . . 269
17.2 What works only there . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
17.3 What doesn’t work there . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
17.4 Navigation keys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
17.5 Navigation levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
17.6 Navigation lesson #1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
17.7 Navigation lesson #2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
17.8 Navigation lesson #3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
17.9 Navigation lesson #4. Non-standard navigation. . . . . . . . . . . . . . . . . 329

REM Page 9
18 Source code editing 335
18.1 To highlight jBC code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
18.2 Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
18.3 Find all CALLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
18.4 Display contents of an insert file under the cursor . . . . . . . . . . . . . . . 345
18.5 Autocomplete jBC/T24 keywords . . . . . . . . . . . . . . . . . . . . . . . . 347
18.6 Code intentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
18.7 Code folding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
18.8 Exec Putty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
18.9 Other things . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
18.10 Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358

19 Useful programs 363


19.1 Load many dynamically-prepared OFS strings to T24 . . . . . . . . . . . . . 363
19.2 Estimate performance of bulk data upload to T24 . . . . . . . . . . . . . . . 366
19.3 Calendar for the next 28 months . . . . . . . . . . . . . . . . . . . . . . . . . 369
19.4 Brainf--k interpreter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
19.5 “Fifteen” puzzle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
19.6 Program in jBC that prints its own source . . . . . . . . . . . . . . . . . . . 380
19.7 Dancing jBC letters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381

20 Errors in my previous publications 383

REM Page 10
1 Preface
This is the “copy-and-paste”-friendly book with jBC, jQL and other samples, how-tos etc –
for people who know the ropes but are too lazy to memorize, for example, all parameters of
f.readu or all options of trim() (like I am). I recently added “jBASE and” into the book
title because the more I write, the more the focus shifts from “pure” T24 to other things like
jBC, jQL etc.
Some areas are well-represented, some are populated quite sparsely. That was as much as
I could gather of 100%-tested examples. That’s why many T24 things from my old records
hadn’t found their way here – I either wasn’t able to retest them or just understood that I
did things wrongly then.
Most things here occupy somewhat lower level than T24 does. Main aspect is jBC program-
ming. Other languages (Python, C, Lua) are used quite in an amateur way just to make the
life easier.
When you copy some code including page breaks – page numbers will become comments (to
avoid compilation fail; that’s why they look like “REM Page 2” for jBC and, e.g., “-- Page
150” for Lua code).
The only exception known to me at the moment is that if REM is at the middle of jBC code
lines with continuation – it wouldn’t compile (unlike “*”; but I haven’t found a way to use
asterisk in page number definition). See an example. The following code wouldn’t compile:

utf_line = CHAR(XTD('C3')) \
: CHAR(XTD('9F')) \ ;* c3 9f: LATIN SMALL LETTER SHARP S
REM Page 201
: CHAR(XTD('C3')) \
: CHAR(XTD('9D')) ;* c3 9d: LATIN CAPITAL LETTER Y WITH ACUTE

And the following will be all right:

utf_line = CHAR(XTD('C3')) \
: CHAR(XTD('9F')) \ ;* c3 9f: LATIN SMALL LETTER SHARP S
*REM Page 201
: CHAR(XTD('C3')) \
: CHAR(XTD('9D')) ;* c3 9d: LATIN CAPITAL LETTER Y WITH ACUTE

So the only thing you need to do is search, copy, paste and compile. Most jBC examples
(those that don’t have subroutine statement) can be pasted to a test.b file. (Don’t forget
to press Enter after the last line – compiler wouldn’t be happy otherwise; in some editors
there are settings for this - for example, for SciTE it’s ensure.final.line.end=1.)
When the source code is saved – jcompile test.b; then run it.
If your PDF viewer dooesn’t preserve leading spaces after copy/paste - use JED (in jBC case)
to get them back or see chapter “Source code editing”. (This is optional for Java, C, jBC
and Lua but mandatory for Python.)

REM Page 11
I’ve tested copying the source code from this PDF in different PDF viewers; the best results
were achieved in Sumatra PDF (which is free and remembers current position for each PDF
file as well). Thanks to Sumatra support too for pointing me to LATEX package that allows
to keep single quotes correct after paste (without converting them to Unicode).
Each chapter contains some useful things – definitely not all that are available. (Who needs
the mathematical tangent in T24?)
All financial data in examples is from Temenos Model Bank.
Starting from edition 3 (i.e. from October 2012) I also contribute to “Temenos jBC docu-
mentation” which you can read at:
http://jbc.temenos.com

Examples written by me there and in this book are often the same or similar.
Enjoy!

REM Page 12
2 What I prefer not to use
There are things in T24 area that I don’t use. Reasons for that are not discussed here; I
just supply a replacement suggestion. And – I’m not saying I’m never going to use all that
– someday and to solve a certain task I might have to...
• jBASE secondary indexes. Replacement: T24 application EB.ALTERNATE.KEY.
• CALL DAS(), CALL EB.READLIST(). Replacement: EXECUTE SELECT, Basic SELECT.
• New application template. “Template V3” is good enough for me.
• “=” as comparison in jBC – only for assignment. E.g. “V.VAR = 1”; “IF V.VAR EQ 1”.
• jBC GOTO, “RETURN TO”. I believe that LOOP...REPEAT with a BREAK can bring you wher-
ever you want inside current section; and passing execution to another section with GOTO is
absolute nightmare.
• jBC IF...ELSE without THEN.
• EB.COMPILE. For programs jcompile os OK, for subroutines – BASIC...CATALOG.
• Including I COMMON and I EQUATE isn’t necessary if you don’t use variables declared there.
(Just – if necessary – don’t forget to add “PRECISION 13” statement in this case to match
T24 default.)
• Capturing data to dynamic array if I don’t know the volume of data. After certain size
the performance drops.
• Unnamed COMMON.
• EQU in jBC. Not being able to see actual value in debugger disturbs me.
• I use CALL OFS.GLOBUS.MANAGER() outside T24 transaction boundary – Temenos still
does the same in the core quite extensively. Places where it can be used safely – everywhere
with “VALIDATE” option, in mainline routine or in “Verify” section of “W” template. (Two
last options are also true for CALL JOURNAL.UPDATE.)
• CALL JULDATE() might be considered obsolete – OCONV() with “DJ” code gives you the
number of day in a year.
• Manipulating of such things as T array, T.ENRI, T.LOCREF on-the-fly – often people try to
make, for example, one field NOINPUT depending on a value of another field etc. Sometimes it
works, but more often it doesn’t. Or – which even worse – it stops working after an upgrade
or update.
• Calling core routines which are not listed in “Subroutine guide”. (Some exceptions exist
though – say, TXTINP() but it was there some time ago.) But calling something that is
subject to change or disappear from core – no way.
• CALL EB.ACCOUNTING(). In some legacy code I have to, but the way to go is OFS Clearing.
• EBS.AUTO.FUNCTION application. Instead – SELECT...SAVING EVAL to create OFS
string for each record, then copy/paste to tSS or put the saved list for batch file listener to
proceed.
• Repgens. ENQUIRY is much better though not ideal either.
• Non-zero values for the following environment variables: JBASE ERRMSG DIVIDE BY ZERO,
JBASE ERRMSG ZERO USED and JBASE ERRMSG NON NUMERIC in development environment. It’s
better to see errors than to hide them.
• EB.PHANTOM – it’s really outdated.
• VB scripting – it works only in Desktop.

REM Page 13
• jBC DEFFUN – it doesn’t make any difference to have a function intead of a subroutine.
The only useful thing that comes to my mind is – make the code more compact by writ-
ing something like “V.RET = FUNC1(FUNC2(V.PAR2), FUNC3(V.PAR3))” instead of several
subsequent CALLs...
• LOOP...WHILE, LOOP...UNTIL – left only in legacy code. Just LOOP...REPEAT with con-
ditional BREAKs for all new code.
• Numeric labels. Of course you can compile even the following code but think twice before
doing that...

001 var = 0
002 var += 1
003 IF var LT 5 THEN GOTO 002 ELSE CRT var

• Empty record @id.


• Code in an INSERT file.
• Special symbols in jBC variable names - $ etc. See debugger example:

jBASE debugger->V V$FUNCTION


COMMON variables
V : 36
VAL.TEXT :
V$ACTION : 0
V$DISPLAY : GB-001-0001 Model Bank
V$FUNCTION : S
STANDARD Variables
V2 : (UNASSIGNED)
VM : (UNASSIGNED)
VERSION.POS : (UNASSIGNED)

3 jBC
3.1 Code compilation
jcompile could be used to compile a program in one step:

jcompile test.b

Don’t forget to add the location of resulting executable and shared library to
PATH environment variable, otherwise COMMON areas wouldn’t be preserved.
For a subroutine (especially T24-type one without “.b” extension) it’s easier to use BASIC...
CATALOG:

BASIC TEST.BP PROG1


PROG1
BASIC_3.c

REM Page 14
Source file PROG1 compiled successfully

CATALOG TEST.BP PROG1


PROG1
Object PROG1 cataloged successfully

If you use INCLUDEs from T24:


jcompile -IT24.BP test.b

note: full or relative path to T24.BP might be necessary.


If you recompile a PROGRAM very often and don’t want to relogin each time for the system
to pick up the last version – use “-E” option to create only executable and not shared library:
jcompile -E test.b

note: COMMON areas wouldn’t be preserved in this case; CHAIN behaviour also differs.
How to look into generated C source:
jcompile -S test.b

note: test.c and test.j files will be generated and that’s it.
See which commands are executed during compilation:
jcompile -v test.b

cl /nologo /DWIN32 /MD /W2 /GR /EHa -c -IC:\TAFC\include -DJBC_OPTLEVEL2 test.c


...
cl /nologo /DWIN32 /MD /W3 /GR /EHa /GF /Zi /F5000000 -D_LARGEFILE_SOURCE ...

Same switch works for BASIC and CATALOG as well:


BASIC -v . INCR.NUM
jcompile -F. -v -c BASIC_5.b > BASIC_5.x
INCR.NUM
jbccom -f -d -a. BASIC_5.b
cl /nologo /DWIN32 /MD /W2 /GR /EHa -c -IC:\TAFC\include -DJBC_OPTLEVEL2
BASIC_5.c
BASIC_5.c
Source file INCR.NUM compiled successfully

CATALOG -v . INCR.NUM
INCR.NUM
Object INCR.NUM cataloged successfully
jcompile -Qs C:\home\kzm\v-t24\client\lib\lib0.dll -b 805306368 -fCATALOG_5.TMP
Library C:\home\kzm\v-t24\client\lib\lib0.dll rebuild okay

REM Page 15
Conditional compilation:

the_var = 1
CRT 'Version ':
#ifdef VER1
CRT the_var:
#else
CRT the_var + 1:
#endif
CRT ' finished'

jcompile -DVER1 test.b


test.c
test
Version 1 finished

jcompile test.b
test.c
test
Version 2 finished

See program information:

jshow -c PROG1

Executable: $HOME\bin\PROG1.dll
jBC main() version 11.0 Wed Nov 21 22:03:18 2012
jBC main() source file TEST.BP
Executable (DUP!!): $HOME\bin\PROG1.exe
jBC main() version 11.0 Wed Nov 21 22:03:18 2012
jBC main() source file TEST.BP

Remove a subroutine or a program:

DECATALOG TEST.BP PROG1


PROG1
Object PROG1 decataloged successfully

3.2 Variables
Visibility and lifetime.
Variable is visible throughout the program or its subroutine (i.e. in the bounds of particu-
lar source code file). (Yes, you’re unable to put several subroutines into same source code
file.) To share a variable between different programs/subroutines pass them as parameters in
CALL statement or use a named or unnamed COMMON. PASSDATA/RTNDATA clauses

REM Page 16
in EXECUTE statement can also help here (and there is also PASSDATA and COLLECT-
DATA statements). All variables (except ones in COMMON areas) are reset (i.e. become
unassigned) upon program end.
Naming.
I’d recommend to use low case with underscores style. Don’t forget that variable names
(as well as jBC keywords and functions) are case-sensitive.

3.3 Comments
* This is a comment
! And this is a comment
REM This is also a comment
// Even this is a comment
CRT '1' ;* this is a comment sharing the same line with some code
CRT '2' // yet another way to define a comment
GOSUB DO.IT
STOP

DO.IT: * even here comment may occur - with or without ";"


CRT 3
RETURN

3.4 String variables


CRT 'QWERTZ' ;* this is a string
CRT "QWERTZ" ;* this is also a string
CRT 'QWE"RTZ' ;* and even this is a string
CRT 1 : 'pm' // numeric was converted to string here
CRT \QWERTZ\ ;* another way to define a string
* and here a backslash means line continuation
CRT 'QWE' \
: 'RTZ'

As you’ve seen above, if you need to have a string delimiter as part of a string, just use other
delimiter. Duplication method doesn’t work; compiler wouldn’t give an error message in this
case:

a_string = 'I don''t'


CRT DQUOTE(a_string) ;* "I don"
another_string = 'I don''t know'
CRT DQUOTE(another_string) ;* " know"
correct_string = "I don't know"
CRT DQUOTE(correct_string) ;* "I don't know"

REM Page 17
3.5 Line continuation; several statements on the same line
* Usual way is a backslash at the end of line
CRT 'QWE' \
: 'RTZ'
CRT STR('QWE', ;* no need in that if the line ends with comma
5)
* several statements together:
CRT 'QWE' ; CRT 'XYZ': ; CRT 'ABC'
CRT 'QWE' ; CRT 'XYZ' ;* comment is also possible here
* as soon as you have a comment, all the rest turns to comments as well:
v_var = 2
v_var-- ;* comment goes to the EOL so no "1" in the output ; CRT v_var
v_var--
CRT v_var ;* 0 will be output
* multi-line conditional statements are also supported:
var_1 = 1 ; var_2 = 2 ; IF var_1 + var_2 EQ 3 THEN
CRT var_1, '+', var_2, '= 3'
END

Its a good idea to move line continuation(s) even more than 3 usual positions to the right,
e.g.:

current_date = DATE()
current_day = OCONV(current_date, 'DD')
current_month = OCONV(current_date, 'DM')
ansi_date = OCONV(current_date, 'DY') : '-' \
: FMT(current_month, 'R0%2' ) : '-' \
: FMT(current_day, 'R0%2' )
CRT ansi_date ;* e.g. 2013-03-08

REM Page 18
3.6 String operations
* concatenate strings
a_line = 'QWE' : 'RT'
CRT a_line ;* QWERT
* unary concatenation
a_line := 'Y'
CRT a_line ;* QWERTY
* extract a substring
CRT a_line[1,2] ;* QW
CRT a_line[2] ;* TY
CRT a_line[-4,2] ;* ER
* add quotes around a string
CRT SQUOTE(a_line[4,999]) ;* 'RTY'
CRT QUOTE(a_line) ;* "QWERTY"
* change case
CRT DOWNCASE(a_line) ;* qwerty
* length of a string
CRT LEN(a_line) ;* 6
* length of i18n string
a_line := CHAR(353)
CRT LEN(a_line) ;* 7
CRT BYTELEN(a_line) ;* 8
* repeat string several times
CRT STR('QWE', 5) ;* QWEQWEQWEQWEQWE
* dynamic array is also a string
dyn_array = 'qwe' : @FM : "rty" : @VM : \xYZ\
dyn_array := @SM : 123
CRT LEN(dyn_array) ;* 15
CRT FMT(UPCASE(dyn_array), 'MCP') ;* QWE^RTY]XYZ\123
* reassign parts of a string
a_string = 'ABC'
a_string[2,1] = 'Q'
CRT a_string ;* AQC
a_string[2,1] = 'WER'
CRT a_string ;* AWERC
* get ASCII value of a character
CRT SEQ(a_string[1,1]) ;* 65 (ASCII code of "A")
* pad a string
CRT '/' : FMT(a_string, '25R') : '/' ;* / AWERC/
* strip spaces...
a_string = ' QWERTZ '
CRT DQUOTE(TRIM(a_string, ' ', 'B')) ;* "QWERTZ"
* ...or other characters, e.g. leading zeroes
CRT '"' : TRIM('000033', '0', 'L') : '"' ;* "33"
* another method of removing zeroes
CRT '"' : '000033' + 0 : '"' ;* "33"

REM Page 19
And more:

a_string = 'AWERC'
* check if there are only alphabetic characters
CRT ISALPHA(a_string) ;* 1
* add number to the end, unary operation (can omit quotes)
a_string := 1 ; CRT a_string ;* AWERC1
* check again if there are only alphabetic characters
CRT ISALPHA(a_string) ;* 0
* check if there are only alphanumeric characters
CRT ISALNUM(a_string) ;* 1
* check a string for control characters
a_string = CHAR(13) : CHAR(10)
CRT ISCNTRL(a_string) ;* 1
a_string := @FM
CRT ISCNTRL(a_string) ;* 1
CHANGE @FM TO ' ' IN a_string
CRT ISCNTRL(a_string) ;* 0

3.7 Comparisons
Strings comparison is done from left to right:

a_string = 'ABC'
char_a = 'A'
char_b = 'B'
CRT a_string GT char_a ;* 1
CRT a_string GT char_b ;* 0

There’s more than one way to say “non equal”:

a_char = 'E'
IF a_char # 'A' THEN CRT 'Not an "A"'
IF a_char NE 'B' THEN CRT 'Not a "B"'
IF a_char ! 'C' THEN CRT 'Not even a "C"'
IF a_char <> 'D' THEN CRT 'Surprisingly, but neither a "D"'

REM Page 20
3.8 Numeric variables
v_var= 5 ; CRT v_var ;* 5
CRT ISDIGIT(v_var) ;* 1
v_var= v_var+ 1 ; CRT v_var ;* 6
v_var++ ; CRT v_var ;* 7
v_var += 1 ; CRT v_var ;* 8
v_var -= 1 ; CRT v_var ;* 7
v_var =- 1 ; CRT v_var ;* -1... easy to make a mistake
CRT ISDIGIT(v_var) ;* 0 (we have minus now)

CLEAR
CRT v_var ;* 0

v_var_2 = v_var++ ; CRT v_var_2 ;* 0 - old value of v_var


v_var_3 = ++v_var ; CRT v_var_3 ;* 2 - value of v_var (that is 1) + 1
* other operators
CRT 2 * 3 ;* 6
CRT 2 ** 10 ;* power of 2 (1024)
CRT 2 ^ 10 ;* same as above
PRECISION 6
CRT 17 / 7 ;* 2.428571
PRECISION 17
CRT 17 / 7 ;* 2.42857142857142857
CRT MOD(1007, 1000) ;* 7
CRT SQRT(144) ;* 12
* precedence is quite expected
CRT 7 / 2 + 3 ;* 6.5
CRT 7 / (2 + 3) ;* 1.4
* dot, plus, minus are considered non-numeric - in all emulations
* dot_not_numeric = true
CRT ISDIGIT(-1) ;* 0
CRT ISDIGIT(1.234) ;* 0

note: ++v var etc isn’t my favourite way; this might help to understand legacy code.

3.9 Boolean variables


Boolean variables as such don’t exist in jBC; the result of a statement like IF (VAR) THEN...
depends on that variable contents.

REM Page 21
Examples:

CRT @TRUE ;* 1
CRT @FALSE ;* 0
IF NOT(unassigned_var) THEN CRT 'Unassigned var is false'
true_var = 1 ; false_var = 0
IF true_var THEN CRT '1 is true'
IF NOT(false_var) THEN CRT '0 is false'
a_string = 'YES'
IF a_string THEN CRT 'Non-empty string is true'
IF NOT('0.00') THEN CRT '0.00 is false'
IF NOT('-0.00') THEN CRT '"-0.00" is still false - treated as numeric'
* and this test depends on PRECISION
PRECISION 9
GOSUB TRUE.OR.FALSE
PRECISION 17
GOSUB TRUE.OR.FALSE
STOP
*------------------------------------------------------------------------
TRUE.OR.FALSE:
*
IF NOT('0.00000000000001') THEN CRT '0.00000000000001 is false' \
ELSE CRT '0.00000000000001 is true with PRECISION 17'
RETURN

END

Output:

1
0
Non-numeric value -- ZERO USED ,
Variable 'unassigned_var' , Line 3 , Source test2.b
Unassigned var is false
1 is true
0 is false
Non-empty string is true
0.00 is false
"-0.00" is still false - treated as numeric
0.00000000000001 is false
0.00000000000001 is true with PRECISION 17

Parentheses change the order of evaluations, e.g. in the following example code lines 2, 3 and
4 are the same (except parentheses); only second IF is true:

var_1 = 1 ; var_2 = 2 ; var_3 = 3 ; var_4 = 4


IF var_1 EQ 1 OR var_2 EQ 20 AND var_3 EQ 30 OR var_4 EQ 40 THEN CRT 1
IF var_1 EQ 1 OR (var_2 EQ 20 AND var_3 EQ 30 OR var_4 EQ 40) THEN CRT 2
IF (var_1 EQ 1 OR var_2 EQ 20) AND (var_3 EQ 30 OR var_4 EQ 40) THEN CRT 3

REM Page 22
3.10 Data files
The most used formats for data files nowadays are “J4” and “JR”. The former has size
limitation (up to 2Gb if OS-level limits allow that) and needs resizing on regular basis though
when it’s properly sized it’s faster. “JR” – “resilient” – doesn’t have size limitation and
doesn’t need resizing.
The following samples can be executed in jshell prompt or (except JED - it makes no sense)
in a jBC program or subroutine (using EXECUTE/PERFORM). In blue colour is what you
type, in black – what system types for you.
Create hashed file (data and dictionary):

CREATE-FILE F.SAMPLE 101 1

[ 417 ] File F.SAMPLE]D created , type = J4


[ 417 ] File F.SAMPLE created , type = J4

If the file already exists, the error message appears:

CREATE-FILE F.SAMPLE 101 1

[ 413 ] File name DICT F.SAMPLE already exists

Delete hashed file (both data and dictionary):

DELETE-FILE F.SAMPLE

Create hashed file (data only):

CREATE-FILE DATA F.SAMPLE 101 1

[ 417 ] File F.SAMPLE created , type = J4

Create hashed file (dictionary only):

CREATE-FILE DICT F.SAMPLE 101 1

[ 417 ] File F.SAMPLE]D created , type = J4

Put some data to file:


JED F.SAMPLE REC1

0001 Field 1
0002 Field 2
0003 Field 3

REM Page 23
Save the record:

Esc FI

Record 'REC1' written to file 'F.SAMPLE'

List file contents:

LIST F.SAMPLE

F.SAMPLE......

REC1

1 Records Listed

No dictionary; we see only @ID. Raw output:

CT F.SAMPLE

REC1
001 Field 1
002 Field 2
003 Field 3

As an alternative, we can use standard correlatives:

LIST F.SAMPLE *A1 *A2 *A3

F.SAMPLE...... *A1........... *A2........... *A3...........

REC1 Field 1 Field 2 Field 3

Add a dictionary item to assign the name to a field:

JED DICT F.SAMPLE FLD1

0001 D
0002 1
0003
0004 FIELD 1 HEADER
0005 10L
0006 S
0007

REM Page 24
Save the record.
note: In T24 use application STANDARD.SELECTION to create dictionary entries.

Use field name:

LIST F.SAMPLE FLD1

F.SAMPLE...... FIELD 1 HEADER

REC1 Field 1

1 Records Listed

LIST F.SAMPLE WITH FLD1 EQ ''

No Records Listed

In default view we still don’t have it:

LIST F.SAMPLE

F.SAMPLE......

REC1

Set the field to be seen by default:

JED DICT F.SAMPLE @

0001 PH
0002 @ID FLD1

Save the record. See the result:

LIST F.SAMPLE

F.SAMPLE...... ID.................. FIELD 1 HEADER

REC1 REC1 Field 1

See file statistics:

jstat -v F.SAMPLE

File C:\r11\bnk\bnk.run\F.SAMPLE
Type=J4 , Hash method = 5

REM Page 25
Created at Tue Nov 20 19:38:25 2012
Groups = 101 , Frame size = 4096 bytes , Secondary Record Size = 8192 bytes
Restore re-size parameters : (none)
File size = 417792 bytes , Inode = 29838 , Device = Id 24915
Last Accessed Tue Nov 20 19:50:30 2012 , Last Modified Tue Nov 20 19:50:30 2012
Backup = YES , Log = YES , Rollback = YES , Network = NO

Record Count = 1 , Record Bytes = 45


Bytes/Record = 45 , Bytes/Group = 0
Primary file space: Total Frames = 101 , Total Bytes = 45
Secondary file space: Total Frames = 0 , Total Bytes = 0

note: 101 – number of groups – was defined when file was created.
Add more records:

COPY FROM F.SAMPLE REC1,REC2

1 records copied

Resize the file:

jrf -V F.SAMPLE

...
Downsizing skipped from modulo 101 to 3.

Resize it anyway:

jrf -VD F.SAMPLE

...
Downsizing from modulo 101 to 3

Change file type to JR:

jrf -H6 F.SAMPLE

See statistics now:

jstat -v F.SAMPLE

File Path = C:\r11\bnk\bnk.run\F.SAMPLE


File Type = JR, Hash method = 5, Created = Tue Nov 20 19:56:00 2012
Frame size = 4096, OOG Threshold = 2048

REM Page 26
File size = 8192, Freespace = 0 frames
Internal Modulo = 3/7/11, External Modulo = 13
Inode no. = 29838, Device no. = 24915
Accessed = Tue Nov 20 19:56:13 2012, Modified = Tue Nov 20 19:56:13 2012
Backup = YES, Log = YES, Rollback = YES, Secure updates = NO
Deallocate pointers : NO Deallocate frames NO
Revision level = 2
Record Bytes = 82, Record Count = 2
Bytes/Record = 41, Bytes/Group = 82
Data Frames = 1, Ptr Frames = 0
OOG Bytes = 0, OOG Frames = 0
Sum Squares = 3362, Std Dev Mean = 41

Turn on secure updates:

jchmod +S F.SAMPLE

jstat -v F.SAMPLE

...
Backup = YES, Log = YES, Rollback = YES, Secure updates = YES
...

Delete a record:

DELETE F.SAMPLE REC2

1 record(s) deleted.

Add data sections:

CREATE-FILE F.SAMPLE,TWO TYPE=JR

[ 417 ] File F.SAMPLE]MTWO created , type = JR

CREATE-FILE F.SAMPLE,THREE TYPE=JR

[ 417 ] File F.SAMPLE]MTHREE created , type = JR

Create a record in a section:

JED F.SAMPLE,TWO REC5

0001 Section 2/1


0002 Section 2/2
0003 Section 2/3

REM Page 27
Save the record. See that all sections use the same dictionary:
LIST F.SAMPLE,TWO

F.SAMPLE,TWO.. ID.................. FIELD 1 HEADER

REC5 REC5 Section 2/1

LIST F.SAMPLE,THREE

F.SAMPLE,THREE ID.................. FIELD 1 HEADER

No Records Listed

Note that file F.SAMPLE still reports 1 record in it; here’s the difference between having
several data sections and a distributed file. In T24 environment splitting of data into sections
isn’t used.
Folders are treated like data files (type UD); flat files in them – like records. This allows,
for example, use JED to edit source code. Data can be copied transparently between hashed
files and folders. Some examples:
CREATE-FILE DATA TEST.BP TYPE=UD
[ 417 ] File TEST.BP created , type = UD

JED TEST.BP PROG1

0001 CRT 2*2

Save file. Compile and run it:


BASIC TEST.BP PROG1
PROG1
BASIC_3.c
Source file PROG1 compiled successfully

CATALOG TEST.BP PROG1


PROG1
Object PROG1 cataloged successfully

PROG1
4

Copy data:

COPY FROM F.SAMPLE TO TEST.BP REC1


1 records copied

REM Page 28
Edit file REC1 in TEST.BP folder with any text editor so it now looks like:

Field 1 - updated
Field 2
Field 3

Copy it back to hashed file:

COPY FROM TEST.BP TO F.SAMPLE REC1 OVERWRITING


1 records copied

See the result:

LIST F.SAMPLE

F.SAMPLE...... ID.................. FIELD 1 HEADER

REC1 REC1 Field 1 - upda


ted

1 Records Listed

3.11 File variables


Even if they are shown in debugger the following way...

jBASE debugger->V F.LOCK


F.LOCK : File '..\bnk.data\eb\F_LOCKING'

...they are not strings. But – like strings – can be compared with each other:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

fn_lock = 'F.LOCKING' ; f_lock = ''


CALL OPF(fn_lock, f_lock)
IF f_lock EQ F.LOCKING THEN
TEXT = 'FILE WAS ALREADY OPENED'
CALL REM
END
RETURN
END

REM Page 29
Runtime:

CONTINUE (Y) FILE WAS ALREADY OPENED

note: File variable can also be compared with an empty string to see if file was opened.
Be careful about assigning a file variable to another one. In the following example we’ll use
a dimensioned array to store file variables.

seq_no = 0
DIM files_list(3) ;* array for flat file handles

out_dir = '.'
out_file = 'account-file.csv'
GOSUB INIT.FLAT.FILE
out_file = 'customer-file.csv'
GOSUB INIT.FLAT.FILE
out_file = 'system-file.csv'
GOSUB INIT.FLAT.FILE

file_type = 1 ; GOSUB WRITE.FLAT.FILE


file_type = 2 ; GOSUB WRITE.FLAT.FILE
file_type = 3 ; GOSUB WRITE.FLAT.FILE

STOP

INIT.FLAT.FILE:
seq_no ++
OPENSEQ out_dir, out_file TO f_out THEN
WEOFSEQ f_out ;* truncate the file
END

files_list(seq_no) = f_out
RETURN

WRITE.FLAT.FILE:
WRITESEQ file_type : ') here we are' TO files_list(file_type) ELSE
CRT 'WRITE ERROR'
STOP
END
RETURN

END

In older versions of jBASE the name of one file would be trashed:

SELECT . LIKE ...csv...

3 Records selected

REM Page 30
>CT .

account-file.csv
001 1) here we are

customer-file.csv
001 2) here we are

system-file.csv3ITiDfhyT
001 3) here we are

In more modern version we would get the runtime error:

** Error [ NOT_FILE_VAR ] **
Variable is not an opened file descriptor , Line 28 , Source test.b
Trap from an error message, error message name = NOT_FILE_VAR

REM Page 31
Now amend the program to avoid the reassigning:

seq_no = 0
DIM files_list(3) ;* array for flat file handles

out_dir = '.'
out_file = 'account-file.csv'
GOSUB INIT.FLAT.FILE
out_file = 'customer-file.csv'
GOSUB INIT.FLAT.FILE
out_file = 'system-file.csv'
GOSUB INIT.FLAT.FILE

file_type = 1 ; GOSUB WRITE.FLAT.FILE


file_type = 2 ; GOSUB WRITE.FLAT.FILE
file_type = 3 ; GOSUB WRITE.FLAT.FILE

STOP

INIT.FLAT.FILE:
seq_no ++
// OPENSEQ out_dir, out_file TO f_out THEN
OPENSEQ out_dir, out_file TO files_list(seq_no) THEN
// WEOFSEQ f_out ;* truncate the file
WEOFSEQ files_list(seq_no) ;* truncate the file
END

// files_list(seq_no) = f_out
RETURN

WRITE.FLAT.FILE:
WRITESEQ file_type : ') here we are' TO files_list(file_type) ELSE
CRT 'WRITE ERROR'
STOP
END
RETURN

END

Result is now correct:

SELECT . LIKE ...csv...

3 Records selected

>CT .

account-file.csv
001 1) here we are

REM Page 32
customer-file.csv
001 2) here we are

system-file.csv
001 3) here we are

3.12 Dynamic arrays


Different methods of population:

dyn_array = 1
dyn_array<2> = 2
dyn_array<-1> = 3
dyn_array := @FM : 4
CRT FMT(dyn_array, 'MCP') ;* 1^2^3^4

“Angle brackets” nesting was discouraged to be used in earlier releases of jBASE; it works
now:

num_array = 1 :@FM: 2 :@FM: 3 :@FM: 4 :@FM: 5


data_array = 'First' :@FM: 'Second' :@FM: 'Third' :@FM: 'Fourth' \
:@FM: 'Fifth'
seq_number = data_array<num_array<3>>
CRT 'The', seq_number, 'Man' ;* The Third Man

Always be sure that there are commas to indicate positions. Dot will mess it up:

dyn_array = 1 :@FM: 2 :@FM: '3-1' :@VM: '3-2' :@VM: '3-3' :@FM: 4 :@FM: 5
CRT FMT(dyn_array, 'MCP') ;* 1^2^3-1]3-2]3-3^4^5
dyn_array<3,2> = 'new value'
CRT FMT(dyn_array, 'MCP') ;* 1^2^3-1]new value]3-3^4^5
dyn_array<3.2> = 'brand new value'
CRT FMT(dyn_array, 'MCP') ;* 1^2^brand new value^4^5 - the whole
;* field 3 is replaced

3.13 Differences between emulations


The very same code behaves differently under different emulations. For example, the following
code will run successfully under “prime” emulation and will fail under “ros”:

ret_code = GETENV('JBCEMULATE', jbc_emu) ; CRT jbc_emu


dyn_array = 3 :@AM: 7
dyn_array += 4
CRT FMT(dyn_array, 'MCP')

note: Setting in Config EMULATE: no value maths = false|true

REM Page 33
Runtime:

prime
7^7

ros
Non-numeric value -- ZERO USED ,
Variable 'dyn_array' , Line 3 , Source test.b
Trap from an error message, error message name = NON_NUMERIC

note: It’s not that I encourage such way of programming...

More examples:

dir_name = '.'
file_name = 'report.txt'
DELETESEQ dir_name, file_name ELSE NULL

OPENSEQ dir_name, file_name TO f_report THEN NULL


CRT '<' : DIR(file_name)<1> : '>' ;* <>

This program outputs “<>” under “prime” and “<0>” under “seq” emulation. In the latter
case there will be zero-sized file report.txt after program terminates. So if, for example,
nothing was written to a report under “prime” emulation (or, in fact, any other except
“seq”), there will be no output file left after that.
note: Setting in Config EMULATE: openseq creates = false|true

And more... The following program outputs 1 under “prime” emulation and 0 under “r83”:

COMMON /MY.COMM/ var_1, var_2

CRT ASSIGNED(var_1)

note: Setting in Config EMULATE: named common = unassigned|null|zero


The following program outputs A^1^2^3^4^5 under “seq” or “r83” emulations; under others
(that do add additional delimiter even if one exists at the end of an array in question) the
output will be: A^^1^2^3^4^5.

dyn_array = 'A' : @AM


FOR i = 1 TO 5
dyn_array<-1> = i
NEXT i
CRT OCONV(dyn_array, 'MCP')

REM Page 34
note: Setting in Config EMULATE: no extra delimiter = false|true
The following READV example outputs “REC1” (i.e. record key) when is run under “jbase”
emulation and “3” (i.e. fields count) under, e.g., “ap” or “r83”:

OPEN 'F.TEMP' TO f_temp THEN


ret_error = ''
CLEARFILE f_temp SETTING ret_error
IF ret_error NE '' THEN
CRT 'ERROR ' : ret_error
STOP
END
END ELSE
EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'
END

out_record = 'LINE 1' :@FM: 'LINE 2' :@FM: 'LINE 3'


WRITE out_record TO f_temp, 'REC1'

READV in_record FROM f_temp, 'REC1', 0 ELSE


CRT 'Read error'
STOP
END

CRT in_record

note: Setting in Config EMULATE: readv0 = key|dcount|binary


Some settings are effective at runtime, others apply during compilation. For example, the
following program compiles successfully under “prime” emulation and runs successfully af-
ter that under all emulations. However, it’s not possible to compile it under, say, “jbase”
emulation. Reason of error – redimensioning of an array.
Program source code:

DIMENSION dyn_array(10)
MAT dyn_array = '!'
dyn_array(5) = '?'
FOR i = 1 TO 10
CRT dyn_array(i): ;* output: !!!!?!!!!!
NEXT i
DIM dyn_array(15)
dyn_array(15) = '...'
CRT dyn_array(15)

Compilation under “jbase” emulation:


[error 1 (32)] "test.b", 7 (offset 18) near ")":
Array dyn_array has already been DIMensioned

1 error was found

REM Page 35
note: Setting in Config EMULATE: resize array = false|true

* number of seconds past midnight


CRT SYSTEM(12) ;* e.g. 30938703.4097 under prime, 309387 under ros

3.14 jBC statements and functions


See below. They are sorted more or less alphabetically, sometimes grouped together for
better understanding.

3.15 ABORT
* Open a file with random name (just to make sure that it doesn't exist)
file_name = ''
FOR i = 1 TO 8
random_char_no = RND(26) + 65
file_name := CHAR(random_char_no) ;* A...Z
NEXT i
OPEN file_name TO f_report ELSE ABORT 201, file_name

Sample output:

** Error [ 201 ] **
Unable to open file XCICLJPH

3.16 ASCII()
Create the file test.txt in hex editor containing the following characters (in hex):

C8 85 93 93 96 40 91 C2 C3

Run the following program:

OSREAD the_line FROM 'test.txt' ELSE NULL


CRT ASCII(the_line)

Output:

Hello jBC

REM Page 36
3.17 ASSERTEQUALS(), ASSERTTRUE()
Useful for tesing purposes. Example (reflects some items from “known issues” chapter):

INCLUDE JBC.h

a_string = 'ABC->DEF->QWE->XYZ'
exp_result = 'DEF->QWE'
test_result = FIELD(a_string, '->', 2, 2)

ASSERTEQUALS(test_result, exp_result)

abss_result = ABSS(-1:@FM:-2:@FM:-3)
CRT FMT(abss_result, 'MCP')

IF NOT(GETENV('TAFC_HOME', V.HOME)) THEN


CRT 'TAFC_HOME not defined'
STOP
END
HUSH ON
EXECUTE 'SELECT ' : V.HOME : '/jbcmessages' \
: ' SAMPLE 1 EVAL "ABSS(-1:@FM:-2:@FM:-3)"' RTNLIST abss_eval_result
HUSH OFF
CRT FMT(abss_eval_result, 'MCP')
* array returns SM-delimited
ASSERTTRUE(EXTRACT(abss_eval_result, 1, 1, 2) GT 0)

Program output (in case these issues aren’t yet fixed):

ERROR! Assert equal test failed in test.b, at line 7


1^2^3
1\0\0
ERROR! Assert true test failed in test.b, at line 22

3.18 BREAK ON/OFF


BREAK OFF
CRT "Next 5 seconds Ctrl-C makes no action"
MSLEEP(5000)
BREAK ON
CRT "And next 5 seconds Ctrl-C invokes debugger"
MSLEEP(5000)
CRT 'Exiting...'
STOP

Output (user is to try to press Ctrl-C at both prompts):

Next 5 seconds Ctrl-C makes no action


And next 5 seconds Ctrl-C invokes debugger
Interrupt signal

REM Page 37
Source changed to .\test2.b
0009 MSLEEP(5000)
jBASE debugger->

3.19 BYTELEN(), LEN(), CHAR()


CHAR() is an opposite of SEQ(); it returns the character given its code (not limited to ASCII).
Here’s an example string containing some non-ASCII characters (Serbian ones: š, Š, č, Č, ć,
Ć, ž, Ž, d− , D):

utf_string = 'ABCDEF' \
: CHAR(353) : CHAR(352) : CHAR(269) : CHAR(268) : CHAR(263) \
: CHAR(262) : CHAR(382) : CHAR(381) : CHAR(273) : CHAR(272)
CRT LEN(utf_string) ;* 16
CRT BYTELEN(utf_string) ;* 26

CRT FMT(utf_string, 'MX')


* 414243444546C5A1C5A0C48DC48CC487C486C5BEC5BDC491C490

CRT OCONV(FMT(FMT(utf_string, 'MX'), '2L'), 'MCP ')


* 41 42 43 44 45 46 C5 A1 C5 A0 C4 8D C4 8C C4 87 C4 86 C5 BE C5 BD C4 91 C4 90
* e.g. C490 means "LATIN CAPITAL LETTER D WITH STROKE"

* [] takes characters, not bytes


CRT FMT(utf_string[2], 'MX') ;* C491C490
CRT FMT(utf_string[9,1], 'MX') ;* C48D

* try to add extended ASCII character (ß)


new_string = utf_string : CHAR(223)
CRT FMT(new_string, 'MX')[4] ;* C39F -
;* which is a representaion of ("LATIN SMALL
;* LETTER SHARP S") in UTF-8.

note: CHAR() accepts values which are greater than 255.

3.20 CALL
A subroutine:

SUBROUTINE INCR.NUM(P.NUMBER)
* increase the parameter
P.NUMBER ++
RETURN
END

REM Page 38
Program that calls it:

dyn_array = 1 :@FM: 2 :@FM: 3 :@FM: 4


CRT FMT(dyn_array, 'MCP') ;* 1^2^3^4

* array element can be processed directly


dyn_array<2> += 1 ;* "dyn_array<2> ++" gives compilation error
CRT FMT(dyn_array, 'MCP') ;* 1^3^3^4

* passing array element as subroutine parameter doesn't work


CALL INCR.NUM(dyn_array<2>)
CRT FMT(dyn_array, 'MCP') ;* still 1^3^3^4

* this method does work


a_number = dyn_array<2>
CALL INCR.NUM(a_number)
dyn_array<2> = a_number
CRT FMT(dyn_array, 'MCP') ;* now 1^4^3^4

a_subr = 'INCR.NUM'
CALL @a_subr(a_number) ;* can call a subroutine this way
CRT a_number ;* 5
* Dimensioned array is ok as well
DIM V.DIM.ARR(3)
V.DIM.ARR(2) = 'INCR.NUM'
V.I = 2
CALL @V.DIM.ARR(V.I) (a_number)
CRT a_number ;* 6
* Pass by value rather than by reference - variable keeps its value:
CALL INCR.NUM((a_number))
CRT a_number ;* still 6
* Wrong CALL:
CALL INCR.NUM(a_number, 1) ;* ** Error [ SUBROUTINE_PARM_ERROR ] **

3.21 CALLJ
Sample: getting contents of certain URL from the internet and display retrieved HTML in
the default browser.
jBC subroutine calljGetHTTP.b:

the_URL = 'http://www.temenos.com'
CALLJ "gethttp", "getit", the_URL SETTING ret_code ON ERROR CRT 'ERROR:'
CRT ret_code

Java program gethttp.java:

import java.net.*;
import java.io.*;

// Page 39
public class gethttp {
public String getit(String cURL) throws Exception {
String returnText = "";
URL site = new URL(cURL);
URLConnection uc = site.openConnection();
BufferedReader in = new BufferedReader(
new InputStreamReader(
uc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
returnText += inputLine;
in.close();
return returnText;
}
}

Compile (javac gethttp.java), run (in “sh” mode):


calljGetHTTP > %TEMP%\out.html && %TEMP%\out.html

note: JAVA HOME should be set and PATH should contain %JAVA HOME%\bin.

3.22 CASE
a_string = 'B'
GOSUB CHK.IT
a_string = 'ABC'
GOSUB CHK.IT
STOP
*
CHK.IT:
*
BEGIN CASE
CASE a_string EQ 'A'
CRT 'an A'
CASE a_string EQ 'B'
CRT 'a B'
CASE a_string EQ 'C'
CRT 'a C'
CASE 1
CRT 'neither A nor B nor C'
END CASE
RETURN
END
Output:
a B
neither A nor B nor C

Unlike for, e.g., switch...case in Javascript, we don’t need break in the end of each CASE
to pass execution after the END CASE line.

REM Page 40
3.23 CATS()
Concatenate corresponding array elements together.

* Same array structure


an_array = "a" : @VM : "b" : @VM : "c"
another_array = 1 : @VM : 2 : @VM : 3
GOSUB DO.PROCEED ;* a1]b2]c3
* Different array structure
an_array = "a" : @SM : "b" : @VM : "c" : @VM : "d"
another_array = "x" : @VM : "y" : @SM : "z"
GOSUB DO.PROCEED ;* ax\b]cy\z]d
STOP

DO.PROCEED:
the_result = CATS(an_array, another_array)
CRT OCONV(the_result, 'MCP')
RETURN

3.24 CHAIN, CLEARINPUT


Passes the execution to another program (without returning to to “master” one). See the
example of a program which asks for user login and password, remembers them in a named
COMMON and launches T24 session using CHAIN statement. Until the session is closed, user
credentials won’t be asked again.

* authenticate once, login w/o credentials until the session is valid


COMMON /KZM.COMMON/ the_login, the_passwd

IF the_login EQ 0 THEN
CLEARINPUT ;* don't take anything in advance
INPUT the_login
CLEARINPUT
HUSH ON
INPUT the_passwd
HUSH OFF
END

DATA the_login
DATA the_passwd
CHAIN 'EX'

STOP
END

REM Page 41
3.25 CHANGE
the_string = 'ABCDEFCDYZ'
CHANGE 'C' TO 'Q' IN the_string
CRT the_string ;* ABQDEFQDYZ
CHANGE 'QD' TO 'nnn' IN the_string
CRT the_string ;* ABnnnEFnnnYZ
* Both types of arrays are OK as well (dynamic ones can be processed in one go)
dyn_array = the_string
dyn_array<2> = the_string
CHANGE 'nnn' TO 'mmm' IN dyn_array
CRT OCONV(dyn_array, 'MCP') ;* ABmmmEFmmmYZ^BmmmEFmmmYZ
DIM dim_array(3)
MAT dim_array = the_string
CHANGE 'nnn' TO 'mmm' IN dim_array(2)
CRT dim_array(2) ;* ABmmmEFmmmYZ
* Funny but numbers can also be processed
the_number = 12345.67
CHANGE 3 TO 9 IN the_number
CRT the_number ;* 12945.67
* Compatibility mode
the_string = CHANGE(the_string, 'YZ', '+-=/')
CRT the_string ;* ABnnnEFnnn+-=/

3.26 CHANGETIMESTAMP(), LOCALDATE()


start_time = MAKETIMESTAMP(DATE(), TIME(), '')
CRT start_time ;* e.g. 11369812364.43
* Structure of time-shifting array:
* Years^Months^Weeks^Days^Hours^Minutes^Seconds^Milliseconds
*
* Add 100 milliseconds
time_shift = ''
time_shift<8> = 100
CRT CHANGETIMESTAMP(start_time, time_shift) ;* 1369812364.53 for above data
time_shift<8> = ''
time_shift<1> = 100 ;* 100 years
end_time = CHANGETIMESTAMP(start_time, time_shift)
CRT OCONV(LOCALDATE(end_time, ''), 'D') ;* 29 MAY 2113

3.27 CHAR()
EQUATE VM TO CHAR(253) ;* value Mark; defined in I_EQUATE hence the colouring
FOR i = 1 TO 6
CRT CHAR(64 + i): ;* ABCDEF
NEXT i
CRT ''
CRT OCONV(CHAR(353), 'MX') ;* C5A1
CRT CHAR(7) ;* rings a bell

REM Page 42
3.28 CHDIR()
INCLUDE JBC.h
IF GETENV('TAFC_HOME', tafc_home) THEN
IF CHDIR(tafc_home : DIR_DELIM_CH : 'config') ELSE
CRT "TAFC configuration cannot be found"
ABORT
END
END ELSE CRT 'TAFC home can not be found'

note: usage of DIR DELIM CH from JBC.h allows to have cross-platform code.

3.29 CHECKSUM()
Can not provide the reliable result by itself.

CRT CHECKSUM('A') ;* 65
CRT CHECKSUM('AA') ;* 65*1 + 65*2 = 195
CRT CHECKSUM('B') ;* 66
CRT CHECKSUM(CHAR(0) : '!') ;* 0*1 + 33*2 = 66

3.30 CLEAR
COMMON /MY.COMM/ global_var
global_var = 1000
var = 5 ; CRT var ;* 5
var ++ ; CRT var ;* 6
CLEAR
* only regular variables will be cleared
CRT var ;* 0
CRT global_var ;* 1000

3.31 CLEARCOMMON
COMMON /MY.COMM/ global_var
COMMON gl_unnamed
global_var = 1000
gl_unnamed = 1001
CLEARCOMMON
* only unnamed common will be cleared
CRT global_var ;* 1000
CRT gl_unnamed ;* 0

REM Page 43
3.32 CLEARDATA

Clears data queue created by DATA statement.

* SYSTEM(14) returns the number of characters available in input buffer


CRT SYSTEM(14) ;* 0
DATA '123'
DATA '456'
CRT SYSTEM(14) ;* 8 (including 2 line end characters)
CLEARDATA
CRT SYSTEM(14) ;* 0

3.33 CLEARFILE
OPEN 'F.TEMP' TO f_temp THEN
err_code = ''
CLEARFILE f_temp SETTING err_code
IF err_code NE '' THEN
CRT 'ERROR ' : err_code
STOP
END
CRT 'FILE CLEARED'
END ELSE
EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'
END

3.34 CLOSE, ASSIGNED()


Temenos doesn’t recommend to close any file in T24 environment. Outside it – why not if
you opened many files and you no more need some of them?
When you close a file, the corresponding file variable becomes unassigned:

EXECUTE 'DELETE-FILE DATA F.TEMP'


EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'
CRT ASSIGNED(f_temp) ;* 1

rec_data = 'LINE 1' :@FM: 'LINE 2' :@FM: 'LINE 3'

WRITE rec_data TO f_temp, 'REC1'


CLOSE f_temp
CRT ASSIGNED(f_temp) ;* 0

REM Page 44
3.35 COMMON
COMMON /MY.COMM/ var_1

CRT ASSIGNED(var_1) ;* 1 (under prime)


CRT var_1 ;* 0 at the first run, YES at the second
CRT ASSIGNED(var_2) ;* 0

var_1 = 'YES'
var_2 = 'NO'

3.36 CONVERT statement


One-to-one characters conversion in a string.

the_string = 'ABCCCDEFCDYZ'
CONVERT 'CEY' TO '+-*' IN the_string
CRT the_string ;* AB+++D-F+D*Z

3.37 CONVERT() function


Note that the order of parameters is different for different emulations:

* compile this program under same emulation that you're testing

IF NOT(GETENV('JBCEMULATE', jbc_emu)) THEN


CRT 'Emulation setting not found'
STOP
END

the_string = 'ABCCCDEFCDYZ'
IF jbc_emu = 'prime' THEN
the_result = CONVERT('CEY', '+-*', the_string)
END ELSE
the_result = CONVERT(the_string, 'CEY', '+-*')
END

CRT jbc_emu, the_result ;* e.g. prime AB+++D-F+D*Z

REM Page 45
3.38 CREATE

Creates a sequential file.

INCLUDE JBC.h
out_dir = '.' ; out_file = 'report.txt'
OPENSEQ out_dir, out_file TO f_out THEN
WEOFSEQ f_out
END ELSE
CREATE f_out ELSE CRT 'File create error' ; STOP
CRT 'File created'
END
WRITESEQ 'ABCDEFabcdef' TO f_out ELSE
CRT 'Write error'
STOP
END
CLOSESEQ f_out
OSREAD the_content FROM out_dir : DIR_DELIM_CH : out_file ELSE NULL
CRT the_content ;* ABCDEFabcdef

3.39 CRT
* normal output
var = 5
CRT var
* result of an expression
CRT var > 2 ;* 1
CRT 2 > 1 ;* 1, though compiler gives the warning
;* "Expression always evaluates as TRUE"
* next 6 outputs will appear at the same line (note ":" in CRT command)
FOR i = 1 TO 6
CRT CHAR(64 + i): ;* ABCDEF
NEXT i
* start a new line
CRT ''
* ring a bell
CRT CHAR(7)
* several things together
CRT 'Loop counter is ' : i
* TAB-delimited output
CRT 'Loop counter is', i
* formatted output
CRT i, i+1 "20R" ;* 6 7
* output at specific location
CRT @(-1) ;* clears the screen and homes the cursor
CRT @(40, 12):'Hello' ;* will start output at row 11, column 39
* compatibility note
DISPLAY 'DISPLAY is synonym of CRT'

REM Page 46
3.40 DEL
Delete an element from dynamic array:

dyn_array = ''
dyn_array<-1> = '' ;* element isn't created here...
FOR i = 1 TO 5
dyn_array<-1> = i
NEXT i
dyn_array<-1> = '' ;* ...and here it is
dyn_array<-1> = 'The end'
CRT FMT(dyn_array, 'MCP') ;* 1^2^3^4^5^^The end
DEL dyn_array<1>
CRT FMT(dyn_array, 'MCP') ;* 2^3^4^5^^The end
dyn_array<2,2> = 6
CRT FMT(dyn_array, 'MCP') ;* 2^3]6^4^5^^The end
DEL dyn_array<2,1>
CRT FMT(dyn_array, 'MCP') ;* 2^6^4^5^^The end
DEL dyn_array<2,1,3>
CRT FMT(dyn_array, 'MCP') ;* still 2^6^4^5^^The end - no such element
//
* An element from dimensioned array can't be deleted but
* can be processed as a dynamic array:
DIM dim_array(5)
MAT dim_array = '*' :@VM: '/'
DEL dim_array(3)<1,2>
MATBUILD delim_array FROM dim_array USING ":"
CRT FMT(delim_array, 'MCP') ;* *]/:*]/:*:*]/:*]/

note: ”<-1>” doesn’t add an empty string as the first element of an array.

REM Page 47
3.41 DELETE

Delete a record from a file:

EXECUTE 'DELETE-FILE DATA F.TEMP'


EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'

rec_data = 'LINE 1' :@FM: 'LINE 2' :@FM: 'LINE 3'

WRITE rec_data TO f_temp, 'REC1'


WRITE rec_data TO f_temp, 'REC2'
WRITE rec_data TO f_temp, 'REC3'

DELETE f_temp, 'REC2' ON ERROR


CRT 'DELETE ERROR'
STOP
END
* "ON ERROR" part isn't triggered if a record doesn't exist
return_code = ''
DELETE f_temp, 'REC5' SETTING return_code ON ERROR
CRT 'REC5 - DELETE ERROR' ;* not appears on the screen
END
* other methods also can't be applied in this case
CRT SQUOTE(return_code) ;* ''
CRT STATUS() ;* 0

Output of LIST command:

LIST F.TEMP

DICT F.TEMP...

REC1
REC3

2 Records Listed

note: In T24 environment use CALL F.DELETE().

3.42 DELETELIST
Delete a saved list:

EXECUTE 'SELECT .' :@FM: 'SAVE-LIST FILES-LIST'


EXECUTE 'LIST &SAVEDLISTS& LIKE FILES-...' ;* FILES-LIST is here
DELETELIST 'FILES-LIST'
EXECUTE 'LIST &SAVEDLISTS& LIKE FILES-...' ;* and now it's not

REM Page 48
3.43 DELETESEQ
The following example is to be put into file test.b:

EXECUTE 'COPY FROM . test.b,temp.txt OVERWRITING'

OPENSEQ '.', 'temp.txt' TO temp_file ELSE


CRT 'Failed to open temporary file'
STOP
END

READSEQ first_line FROM temp_file ELSE


CRT 'Failed to read temporary file'
STOP
END

CRT first_line ;* EXECUTE 'COPY FROM . test.b,temp.txt OVERWRITING'


CLOSESEQ temp_file
CRT DQUOTE(DIR('temp.txt')<1>) ;* "524"

DELETESEQ '.', 'temp.txt' ELSE NULL


CRT DQUOTE(DIR('temp.txt')<1>) ;* ""

3.44 DIM, MAT


Set size for dimensioned array; populate it with default value:

size_x = SYSTEM(2) - 15 ; size_y = SYSTEM(3) - 5


DIM the_screen(size_x, size_y)
MAT the_screen = '*'
GOSUB DRAW.SCREEN
MAT the_screen = '#'
GOSUB DRAW.SCREEN
STOP

DRAW.SCREEN:
CRT @(-1)
FOR i = 1 TO size_x
FOR j = 1 TO size_y
CRT @(i, j) : the_screen(i, j):
NEXT i
MSLEEP(100) ;* 0.1 sec
NEXT j
MSLEEP 5000 ;* this syntax also works
RETURN
END

REM Page 49
Another example:

DIM dim_array(10)
MAT dim_array = '!'
dim_array(5) = '?'
FOR i = 1 TO 10
CRT dim_array(i): ;* output: !!!!?!!!!!
NEXT i

DIM threedim_array(2, 3, 4)
MAT threedim_array = 1
threedim_array(1, 2, 1) *= 2
CRT ''
CRT threedim_array(1, 2, 1) ;* 2
CRT threedim_array(1, 2) ;* still 2
CRT threedim_array(1, 20, 1) ;* runtime error ARRAY_SUBS

3.45 DIR()
Get file information:

IF NOT(GETENV('TAFC_HOME', tafc_home)) THEN


CRT 'TAFC_HOME not defined'
STOP
END
dir_info = DIR(tafc_home)
CRT OCONV(dir_info, 'MCP') ;* e.g. 0^16214^32712^D
IF dir_info<4> EQ 'D' THEN CRT tafc_home : ' is a directory'
file_info = DIR(tafc_home : '/jbcmessages')
CRT OCONV(file_info, 'MCP') ;* e.g. 204800^15815^57980
CRT 'Size of file jbcmessages is ' : file_info<1>
CRT OCONV(file_info<2>, 'D') ;* e.g. 19 APR 2011
CRT OCONV(file_info<3>, 'MTS') ;* e.g. 16:06:20

3.46 DIV()
CRT DIV(400, 200) ;* 2
CRT DIV(200, 400) ;* 0.5
CRT DIV(200, -400) ;* -0.5
PRECISION 9
CRT DIV(1, 10000000000) ;* 0
PRECISION 17
CRT DIV(1, 10000000000) ;* 0.0000000001
a_zero = 0
zero_div = DIV(1, a_zero) ;* Divide by zero !!
CRT zero_div ;* 0.0nan

REM Page 50
3.47 DROUND()
PRECISION 6 ;* non-dependent on PRECISION setting
FOR i = 0 TO 20
CRT DROUND(3.14159265358979323846, i)
NEXT i

Output:

3
3.1
3.14
3.142
3.1416
3.14159
3.141593
3.1415927
3.14159265
3.141592654
3.1415926536
3.14159265359
3.14159265359
3.1415926535898
3.14159265358979
3.141592653589793
3.1415926535897932
3.14159265358979324
3.141592653589793238
3.1415926535897932385
3.14159265358979323846

3.48 DTX(), XTD()


Decimal to hex conversion and vice versa:

CRT XTD('FF') ;* 255


CRT FMT(DTX(13), 'R%2') : FMT(DTX(10), 'R%2') ;* 0D0A
CRT XTD('BADBEEF') ;* 195935983 (binary: 00001011101011011011111011101111)
CRT XTD('DEADBEEF') ;* -559038737 (binary: 11011110101011011011111011101111)
CRT XTD('1aGHI') ;* 26 - stopped after processing "1a"
CRT XTD('GHI') ;* 0

note: negative result in line 4 is caused by the first bit of binary result being set.

REM Page 51
3.49 ENCRYPT()
As a sample of usage – encode a text to base64 (useful if you’re going to store hexadecimal
data in a table):

INCLUDE JBC.h
CRT ENCRYPT('This is a test line' : @FM : CHAR(9), '', JBASE_CRYPT_BASE64)

* Output: VGhpcyBpcyBhIHRlc3QgbGluZf4J

3.50 EXECUTE/RTNLIST/CAPTURING, DATA, DCOUNT()


Use jQL SELECT:

sel_q = \SSELECT VOC WITH *A1 LIKE "'F'..." SAMPLE 10 TO 9\


EXECUTE sel_q

LOOP
READNEXT next_id FROM 9 ELSE BREAK
CRT next_id
REPEAT

Use jQL SEARCH:

* Search old-style templates in T24 environment


DATA 'DEFINE.PARAMETERS'
DATA ''
DATA '*'
EXECUTE 'SEARCH T24.BP' RTNLIST ret_list
the_size = DCOUNT(ret_list, @FM)
CRT 'Found', the_size
CRT ret_list<1> ;* AC.ENRICHMENT
CRT ret_list<2> ;* CHEQUE.CHARGE
CRT ret_list<3> ;* CHEQUE.CHARGE.BAL
CRT ret_list<4> ;* CHEQUE.CHARGE.BAL.HOLD
CRT ret_list<5> ;* CHEQUE.ISSUE
CRT '...'
CRT ret_list<the_size> ;* TEMPLATE.W

Several commands (especially when it’s not possible to run them one-by-one):

EXECUTE 'DELETE.LIST ACCT-LIST' :@FM: 'SELECT FBNK.ACCOUNT' \


:@FM: 'SAVE.LIST ACCT-LIST'

Get the data from a child process:

* Count number of files in current directory


count_cmd = \COUNT .\
HUSH ON
EXECUTE count_cmd RETURNING the_result
HUSH OFF
CRT the_result<1,2> ;* e.g. 15

REM Page 52
Run an external executable or OS command and capture its output:

EXECUTE 'df -m' CAPTURING the_result


LOOP
REMOVE a_line FROM the_result SETTING the_status
CRT '[' : a_line : ']'
IF the_status EQ 0 THEN BREAK ;* do it after processing the last
;* result, not before
REPEAT

Sample result:

[Filesystem 1M-blocks Used Available Use% Mounted on]


[/dev/sda6 15380 2929 11670 21% /]
[none 1467 1 1467 1% /dev]
[none 1471 1 1471 1% /dev/shm]
[none 1471 1 1471 1% /var/run]
[none 1471 0 1471 0% /var/lock]
[none 1471 0 1471 0% /lib/init/rw]
[/dev/sda7 179556 79170 91265 47% /home]

There’s also a possibility to use different Unix shells:

EXECUTE CHAR(255) : 'kecho $0' ;* /usr/bin/ksh


EXECUTE CHAR(255) : 'becho $0' ;* /bin/sh
EXECUTE CHAR(255) : 'cecho $shell' ;* /usr/bin/csh

3.51 GETENV()
IF NOT(GETENV('JBASE_ERRMSG_ZERO_USED', zero_using)) THEN
CRT 'GETENV failed'
STOP
END

IF zero_using NE 0 THEN
CRT 'Please set JBASE_ERRMSG_ZERO_USED to 0'
STOP
END ELSE
CRT "Setting's all right, let's go..."
END

REM Page 53
3.52 GETLIST, SELECT, READNEXT, OPEN, READ, WRITE
* Here we get a list that was saved before; if it wasn't - select a file
* (T24 environment - we need file F.ENQUIRY)
* This is a program hence OPEN...READ instead of T24 style (OPF...F.READ etc)
*----------------------------------------------------------------------------
OPEN 'F.ENQUIRY' TO f_enq ELSE
CRT 'ERROR OPENING F.ENQUIRY'
STOP
END

GETLIST 'ENQ-LIST' TO enq_list SETTING enq_qty ELSE


SELECT f_enq TO enq_list
END

OPEN 'F.TEMP' TO f_temp THEN


err_code = ''
CLEARFILE f_temp SETTING err_code
IF err_code NE '' THEN
CRT 'ERROR ' : err_code
STOP
END
END ELSE
EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'
END

LOOP
READNEXT enq_id FROM enq_list ELSE BREAK
// Read the record:
READ rec_enq FROM f_enq, enq_id ELSE
CRT 'ERROR READING THE FILE, ID=' : enq_id : ''
STOP
END

// write it with different @ID:


WRITE rec_enq TO f_temp, 'ENQ.' : enq_id
REPEAT

REM Page 54
3.53 GOSUB
var_1 = 1 ; var_2 = 2 ; var_3 = 3
GOSUB MAKE.ARRAY
GOSUB OUTPUT ;* -1^-2^-3
var_1 = -1 ; var_2 = -2 ; var_3 = -3
GOSUB MAKE.ARRAY
GOSUB OUTPUT ;* 1^2^3
var_1 = 1 ; var_2 = -2 ; var_3 = 3
GOSUB MAKE.ARRAY
GOSUB OUTPUT ;* -1^2^-3
STOP
*------------------------Subroutines-----------------------------------
MAKE.ARRAY:
dyn_array = NEGS(var_1 :@FM: var_2 :@FM: var_3)
RETURN
*
OUTPUT:
CRT FMT(dyn_array, 'MCP')
RETURN

If you, for example, forget a RETURN in MAKE.ARRAY section the execution will continue
till the next RETURN, i.e. section OUTPUT will be executed 6 times instead of 3.

3.54 GROUPSTORE()
Insert the variable contents into dynamic array (or replace an element in it):

to.var = 'QQQ' :@FM: 'WWW' :@FM: 'DDD'


from.var = 'rtz'
GROUPSTORE from.var IN to.var USING 2, 0, @FM ;* start,replace,delim
CRT FMT(to.var, 'MCP') ;* QQQ^rtz^WWW^DDD
GROUPSTORE from.var IN to.var USING 4, 1
CRT FMT(to.var, 'MCP') ;* QQQ^rtz^WWW^rtz
GROUPSTORE from.var IN to.var USING 2, 0, @VM
CRT FMT(to.var, 'MCP') ;* QQQ^rtz^WWW^rtz]rtz

REM Page 55
3.55 FIELD(), COL1(), COL2()

Extract “field(s)” from delimited string:

a_string = 'ABC/DEF/QWE/XYZ'
* One field
CRT FIELD(a_string, '/', 2) ;* DEF
CRT COL1() ;* 4 - position right before "DEF"
CRT COL2() ;* 8 - position right after it
CRT FIELD(a_string, '/', -2) ;* ABC - negative doesn't work here
;* so 1st element is returned by default
* Alternate way
CRT a_string[ '/', 2, 1 ] ;* DEF
* More than one field
CRT FIELD(a_string, '/', 2, 2) ;* DEF/QWE
CRT COL1() ;* 4
CRT COL2() ;* 12
CRT a_string[ '/', 2, 3 ] ;* DEF/QWE/XYZ
CRT DQUOTE(FIELD(a_string, '/', 2, 99))
;* "DEF/QWE/XYZ" - all after 1st one
* Delimiter can consist of several characters:
CHANGE '/' TO '->' IN a_string ; CRT a_string ;* ABC->DEF->QWE->XYZ
CRT FIELD(a_string, '->', 2) ;* DEF
CRT FIELD(a_string, '->', 2, 2) ;* >DEF->QWE, should be: DEF->QWE

3.56 FILEINFO(), NULL


See if file variable is a valid one. Open some files, do nothing if file doesn’t open:

IF NOT(GETENV('JEDIFILENAME_SYSTEM', sys_file)) THEN ABORT


OPEN sys_file TO f_sys ELSE NULL
OPEN 'SOMENONEXISTENTFILE' TO f_non_existing ELSE NULL
CRT FILEINFO(f_sys, 0) ;* 1
CRT FILEINFO(f_non_existing, 0) ;* 0

REM Page 56
3.57 FIND, FINDSTR
dyn_array = 'ABC' \
:@FM: 'DEF' :@VM: '123' :@VM: 'XYZ' :@VM: '456' \
:@FM: '789' \
:@FM: '---' : @SM: 'XYZ'
GOSUB INIT
FIND 'XYZ' IN dyn_array SETTING field_posn, value_posn ELSE NULL
CRT field_posn, value_posn ;* 2 3
GOSUB INIT
FIND 'XYYYZ' IN dyn_array SETTING field_posn, value_posn ELSE NULL
CRT field_posn, value_posn ;* 0 0
GOSUB INIT
FIND 'XYZ' IN dyn_array, 2 SETTING field_posn, value_posn, subval_posn ELSE NULL
CRT field_posn, value_posn, subval_posn ;* 4 1 2
GOSUB INIT
* FIND looks for whole string match, FINDSTR can find a substring
FIND 'XY' IN dyn_array SETTING field_posn, value_posn ELSE NULL
CRT field_posn, value_posn ;* 0 0
GOSUB INIT
FINDSTR 'XY' IN dyn_array SETTING field_posn, value_posn ELSE NULL
CRT field_posn, value_posn ;* 2 3
STOP

INIT:
field_posn = 0 ; value_posn = 0 ; subval_posn = 0
RETURN

3.58 FOLD()
Program:

a_string = 'Lorem ipsum dolor sit amet, consectetur adipisici elit, ' \
: 'sed do eiusmod tempor incididunt ut labore et dolore magna ' \
: 'aliqua. Ut enim ad minim veniam, quis nostrud exercitation ' \
: 'ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis ' \
: 'aute irure dolor in reprehenderit in voluptate velit esse ' \
: 'cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat ' \
: 'cupidatat non proident, sunt in culpa qui officia deserunt ' \
: 'mollit anim id est laborum.'
the_fold = FOLD(a_string, 35)
CHANGE @FM TO CHAR(10) IN the_fold
CRT the_fold

Output:

Lorem ipsum dolor sit amet,


consectetur adipisici elit, sed do
eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud

REM Page 57
exercitation ullamco laboris nisi
ut aliquip ex ea commodo
consequat. Duis aute irure dolor
in reprehenderit in voluptate
velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint
occaecat cupidatat non proident,
sunt in culpa qui officia deserunt
mollit anim id est laborum.

3.59 FOR...NEXT...STEP...CONTINUE...BREAK
dyn_array = ''
FOR i = 1 TO 10
IF i EQ 3 THEN CONTINUE
dyn_array<-1> = i
NEXT i
* we can also pass from the end to beginning; step isn't necessarily 1
FOR j = 10 TO 1 STEP -2
IF j EQ 4 THEN BREAK
dyn_array<-1> = j
NEXT j
CRT FMT(dyn_array, 'MCP') ;* 1^2^4^5^6^7^8^9^10^10^8^6

3.60 ICONV(), OCONV(), FMT()


Date and time:

CRT OCONV(1, 'D') ;* 01 JAN 1968


CRT OCONV(DATE(), 'D') ;* here and below output for 30 MAY 2013
CRT OCONV(DATE(), 'D2') ;* 30 MAY 13
CRT OCONV(DATE(), 'D4/') ;* 05/30/2013
CRT OCONV(DATE(), 'DY') ;* 2013
CRT OCONV(DATE(), 'DY2') ;* 13
CRT OCONV(DATE(), 'DQ') ;* 2 (quarter)
CRT OCONV(DATE(), 'DM') ;* 5 (month number)
CRT OCONV(DATE(), 'DMA') ;* MAY
CRT OCONV(DATE(), 'DD') ;* 30
CRT OCONV(DATE(), 'DJ') ;* 150 (number of a day in the year)
CRT OCONV(DATE(), 'DW') ;* 4 (day number in a week, starting from Monday)
CRT OCONV(DATE(), 'DWA') ;* THURSDAY
CRT OCONV(TIME(), 'MT') ;* 20:04
CRT OCONV(TIME(), 'MTS') ;* 20:04:08
CRT OCONV(1, 'MTS') ;* 00:00:01
* difference of 2 dates (in days)
CRT ICONV('20121231', 'D') - ICONV('20111231', 'D') ;* 366
* Check if a year is a leap one
CRT OCONV(ICONV('20131231', 'D4'), 'DJ') ;* 365
CRT OCONV(ICONV('20161231', 'D4'), 'DJ') ;* 366

REM Page 58
Strings:

* split a string
the_string = 'LONG STRING TO BE SPLIT'
the_split = FMT(the_string, '10L')
CRT OCONV(the_split, 'MCP') ;* LONG STRIN.G TO BE SP.LIT
* hexadecimal output
CRT OCONV(the_split, 'MX')
* Output:
* 4C4F4E4720535452494EFB4720544F204245205350FB4C495420202020202020
*
* Remove non-alphabetic symbols:
CRT OCONV(the_split, 'MCA') ;* LONGSTRINGTOBESPLIT
* Remove all alphabetic symbols:
CRT OCONV(OCONV(the_split, 'MC/A'), 'MX') ;* 20FB202020FB20202020202020
* Note FB symbols in the output above.. see what's that
CRT OCONV('FB', 'MCXD') ;* 251 a.k.a. @TM
CHANGE @TM TO '->' IN the_split ; CRT the_split ;* LONG STRIN->G TO BE SP->LIT
* Remove non-numeric symbols:
CRT OCONV('another 1 bites the dust', 'MCN') ;* 1
* Remove all numeric symbols:
CRT OCONV('another 1 bites the dust', 'MC/N') ;* another bites the dust
* formatting
CRT SQUOTE(FMT(the_string, '30L')) ;* 'LONG STRING TO BE SPLIT '
CRT SQUOTE(FMT(the_string, '30R')) ;* ' LONG STRING TO BE SPLIT'
* replace some data
CRT OCONV(the_string, 'MCC;STRING;DATA') ;* LONG DATA TO BE SPLIT
* change case
CRT OCONV(the_string, 'MCL') ;* long string to be split
CRT OCONV('do it', 'MCU') ;* DO IT
CRT OCONV(the_string, 'MCT') ;* Long String To Be Split
* extract delimited fields: skip 1 space-delimited word, take 3 from that point
CRT OCONV(the_string, 'G1 3') ;* STRING TO BE

Numbers:

* amounts
amount_fcy = 1234
CRT FMT(amount_fcy, 'R%7') ;* 0001234
amount_fcy += 0.56
CRT FMT(amount_fcy, 'R2*19') ;* ************1234.56
CRT SQUOTE(FMT(amount_fcy, 'L2,#19')) ;* '1,234.56 '
CRT FMT(-amount_fcy, 'R2,C&*$#15') ;* $1,234.56CR
CRT FMT(amount_fcy,'L0') ;* 1235
* phone numbers
CRT FMT(1234567890, 'R((###) ###-###)') ;* (234) 567-890
CRT FMT(74952223355, 'R(+# (#3) #3-#2-#2)') ;* +7 (495) 222-33-55
* FMT() and OCONV() are often interchangeable;
* though it's not the case for next 2 lines...
CRT DQUOTE(FMT(123456.78, 'R2,$#15')) ;* " $123,456.78"
CRT DQUOTE(OCONV(123456.78, 'R2,$#15')) ;* Error in Range Test

REM Page 59
User exits:

CRT OCONV("", "U50BB") ;* port number and user name


HUSH ON
EXECUTE 'SELECT .'
HUSH OFF
CRT OCONV("", "U30E0") ;* number of items in active SELECT list
* sleep
start_time = TIME() ; dummy = OCONV(3, "U307A")
CRT TIME() - start_time ;* 3
* reverse a string
CRT OCONV('desrever saw gnirtS', "U51AA")
* remove duplicate consecutive characters
CRT OCONV('hhahhahh', "U31AC") ;* haha (should it be hahah?)

Create the date and time stamp in T24 style (what’s used in audit trail field date.time):

date_time = TIMEDATE()
V.TIME = date_time[1,2] : date_time[4,2]
V.DATE = ICONV(date_time[10,11], 'D')
date_time = OCONV(V.DATE, 'DY2') : FMT(OCONV(V.DATE, 'DM'), "R0%2") \
: FMT(OCONV(V.DATE, 'DD'), "R0%2") : V.TIME
CRT date_time ;* e.g. 1305302237

3.61 IN
Receive raw data from keyboard:

LOOP
IN in_key
IF in_key EQ 27 THEN ;* ESC seen
IN in_key_2 FOR 2 THEN ;* Function Key?
IN in_key_3 FOR 2 THEN
CRT ''
BEGIN CASE
CASE in_key_2 EQ 79 AND in_key_3 EQ 80
CRT 'F1 detected'
CASE in_key_2 EQ 79 AND in_key_3 EQ 81
CRT 'F2 detected'
END CASE
END
END ELSE
CRT ''
CRT 'ESC pressed, exiting'
STOP
END
END
REPEAT

REM Page 60
3.62 INDEX()
Find a substring:

CRT INDEX('qwerty123rt', 'rt', 1) ;* 4 - 1st occurrence


CRT INDEX('qwerty123rt', 'rt', 2) ;* 10 - 2nd occurrence
CRT INDEX('qwerty123rt', '1234', 1) ;* 0 - not found

3.63 INMAT()
Get the number of elements in dimensioned array.

DIM cust_rec(99)
MAT cust_rec = ''
CRT INMAT(cust_rec) ;* 99
DIM cust_rec(299) ;* array re-dimensioning works not in all emulations
cust_rec(150) = 'Y'
CRT INMAT(cust_rec) ;* 299
CRT INMAT() ;* 0 - no operations like MATREAD occured yet

* write the record into file to MATREAD it later


EXECUTE 'DELETE-FILE DATA F.TEMP'
EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'
new_rec = 'LINE 1' :@FM: 'LINE 2' :@FM: 'LINE 3'
WRITE new_rec TO f_temp, 'REC1'

MAT cust_rec = ''


MATREAD cust_rec FROM f_temp, 'REC1' ELSE
CRT 'Read error'
STOP
END
CRT INMAT(cust_rec) ;* 299 - current size
CRT INMAT() ;* 3

dyn_array = 1 :@FM: 2.1 :@VM: 2.2 :@SM: 2.3: @FM: 3 :@FM: 4


MATPARSE cust_rec FROM dyn_array
CRT INMAT() ;* 4 (only FMs count when MATPARSE creates the array)
CRT FMT(cust_rec(2), 'MCP') ;* 2.1]2.2\2.3
DIM cust_rec(100,2)
CRT FMT(INMAT(cust_rec), 'MCP') ;* 100]2
CRT FMT(cust_rec(2), 'MCP') ;* now it's 3 - alignment has changed

REM Page 61
3.64 INPUT, DOWNCASE()

Ask user for input for 60 seconds; every 3 seconds update the counter:

time_out = 60
GOSUB UPD.CNT
answer = ''
wait_time = 30 ;* 3 seconds
LOOP
WHILE 1 DO
INPUT answer, 1 : FOR wait_time ELSE
time_out -= 3
IF time_out LE 0 THEN answer = '###'
END

BEGIN CASE
CASE answer EQ '' ; GOSUB UPD.CNT
CASE DOWNCASE(answer) EQ 'b' ; CRT @(-9): 'Wrong... boom!' ; BREAK
CASE DOWNCASE(answer) EQ 'r' ; wait_time = 5 ;* make it faster
CASE answer EQ '###' ; CRT ' Battery low...exit' ; BREAK
CASE 1 ; CRT ' Boom!' ; BREAK
END CASE

REPEAT

STOP

UPD.CNT:
CRT @(0):'Seconds left: ': FMT(time_out, '2R') : ', (r)ed or (b)lue wire':
RETURN

Padding the input field:

CRT @(-1)
INPUT @(17,2):answer,50,'_..':_

User screen:

? _________________________________________________

3.65 INSERT()
dyn_array = 'Field 1' :@VM: 2 :@VM: 3 :@VM: 5 :@FM: 'Field 2'
out_array = INSERT(dyn_array, 1,4 ; 'Field1Value4')
CRT OCONV(out_array, 'MCP') ;* Field 1]2]3]Field1Value4]5^Field 2

REM Page 62
3.66 IOCTL()
* Program to get the last update time for particular record
INCLUDE JBC.h
the_file = SENTENCE(1)
the_rec = SENTENCE(2)
OPEN the_file TO F.TEST.FILE ELSE ABORT 201, the_file
V.NAME = the_rec
V.STAT = IOCTL(F.TEST.FILE, JIOCTL_COMMAND_FINDRECORD_EXTENDED, V.NAME)
IF V.STAT THEN
date_time = V.NAME<2>
the_date = OCONV(date_time, 'U0ff1') ; the_time = OCONV(date_time, "U0ff0")
CRT OCONV(the_date, 'D4') : ' at ' : OCONV(the_time, \MTS\)
END ELSE
CRT '*** FAILED TO GET RECORD INFO ***'
END

Sample output (Model Bank data):

jsh --> test F.SPF SYSTEM


27 JUN 2012 at 10:19:31
jsh --> test F.COMPANY GB0010001
06 JUL 2011 at 06:52:57

Processing sequential files with long (with more than 1024 characters) lines.
Step 1. Program to create such file:

* Create a file with long lines


OPENSEQ '.', 'test.txt' TO f_out THEN
WEOFSEQ f_out
END ELSE
CREATE f_out ELSE
CRT 'File creation error'
STOP
END
END
* Create a ruler-like output
the_line = ''
FOR i = 1 TO 1100 STEP 10
j = i + 9
the_line := STR('-', 10-LEN(j)) : j
NEXT i
* Write 10 lines
FOR i = 1 TO 10
WRITESEQ the_line TO f_out ELSE
CRT 'File write error'
STOP
END
NEXT i
STOP
END

REM Page 63
Ends of lines in that file look this way:

------1040------1050------1060------1070------1080------1090------1100
------1040------1050------1060------1070------1080------1090------1100
------1040------1050------1060------1070------1080------1090------1100
------1040------1050------1060------1070------1080------1090------1100
------1040------1050------1060------1070------1080------1090------1100
------1040------1050------1060------1070------1080------1090------1100
------1040------1050------1060------1070------1080------1090------1100
------1040------1050------1060------1070------1080------1090------1100
------1040------1050------1060------1070------1080------1090------1100
------1040------1050------1060------1070------1080------1090------1100

READSEQ by default reads lines up to 1024 characters; the rest of such line would be read by
subsequent READSEQ. To override this we can use IOCTL() function.
Step 2. Program to read file:

INCLUDE JBC.h
OPENSEQ '.', 'test.txt' TO f_in THEN NULL
ELSE CRT 'File open error' ; STOP

counter = 0
GOSUB READ.LINE
GOSUB READ.LINE ;* one time isn't enough in this mode

IF NOT(IOCTL(f_in, JIOCTL_COMMAND_SEQ_CHANGE_RECORDSIZE, 2048)) THEN


CRT 'IOCTL() error'
STOP
END

GOSUB READ.LINE
STOP

READ.LINE:
counter ++
READSEQ the_line FROM f_in ELSE CRT 'File read error' ; STOP
CRT counter : ':' : DQUOTE(the_line[1,30] : '...' : the_line[30])
RETURN
END

Program output:

1:"--------10--------20--------30...--1000------1010------1020----"
2:"--1030------1040------1050----...------1080------1090------1100"
3:"--------10--------20--------30...------1080------1090------1100"

REM Page 64
3.67 ISCNTRL()
Check if the expression consists entirely of control characters:

the_string = CHAR(13) : CHAR(10)


CRT ISCNTRL(the_string) ;* 1
the_string = @FM : the_string
CRT ISCNTRL(the_string) ;* 1
the_string := 'A' ; CRT ISCNTRL(the_string) ;* 0

3.68 ISDIGIT(), ISLOWER(), ISPRINT(), ISSPACE(), ISUPPER()


Check for digits, lowercase characters, printable characters, spaces and uppercase characters
respectively.

CRT ISDIGIT(123) ;* 1
CRT ISDIGIT(-123) ;* 0
CRT ISDIGIT(123.456) ;* 0
CRT ISLOWER('qwertz') ;* 1
CRT ISLOWER('qweRtz') ;* 0
CRT ISPRINT('abcde') ;* 1
CRT ISPRINT('abcde' : @FM) ;* 0
CRT ISSPACE('') ;* 0
CRT ISSPACE(' ') ;* 1
CRT ISUPPER('QWERTZ') ;* 1
CRT ISUPPER('QWERTZ1') ;* 0

REM Page 65
3.69 ITYPE()

Get the value of an I-descriptor.

* Data preparation
file_name = 'F.TEMP'
EXECUTE 'DELETE-FILE ' : file_name
EXECUTE 'CREATE-FILE ' : file_name : ' 1 101 TYPE=J4'
OPEN file_name TO f_temp ELSE ABORT 201, file_name
OPEN 'DICT', file_name TO f_temp_dict ELSE ABORT 201, file_name : ']D'
* Field 1 dictionary entry
rec_dict_type_d = ''
rec_dict_type_d<1> = 'D'
rec_dict_type_d<2> = '1'
rec_dict_type_d<5> = '25L'
rec_dict_type_d<6> = 'S'
WRITE rec_dict_type_d TO f_temp_dict, 'FOOTWEAR'
* I-descriptors
fwsize_idesc_name = 'FWSIZE'
rec_dict_type_i = ''
rec_dict_type_i<1> = 'I'
rec_dict_type_i<2> = 'FOOTWEAR[":", 2, 1]'
rec_dict_type_i<4> = fwsize_idesc_name
rec_dict_type_i<5> = '3R'
rec_dict_type_i<6> = 'S'
WRITE rec_dict_type_i TO f_temp_dict, fwsize_idesc_name
fwname_idesc_name = 'FWNAME'
rec_dict_type_i<2> = 'FOOTWEAR[":", 1, 1]'
rec_dict_type_i<4> = fwname_idesc_name
rec_dict_type_i<5> = '12L'
WRITE rec_dict_type_i TO f_temp_dict, fwname_idesc_name
* Data records
rec_data = '' ; rec_data<1> = 'SLIPPERS:8'
WRITE rec_data TO f_temp, 'JIM'
rec_data = '' ; rec_data<1> = 'BOOTS:10'
WRITE rec_data TO f_temp, 'GREG'
rec_data = '' ; rec_data<1> = 'SLIPPERS:5'
WRITE rec_data TO f_temp, 'ALAN'
* Data is prepared; now proceed it
@FILENAME = file_name
READ fwsize_idesc_rec FROM f_temp_dict, fwsize_idesc_name ELSE ABORT
READ fwname_idesc_rec FROM f_temp_dict, fwname_idesc_name ELSE ABORT
SSELECT f_temp TO staff_list
LOOP
READNEXT next_id FROM staff_list ELSE BREAK
@ID = next_id
READ @RECORD FROM f_temp, @ID ELSE ABORT
fw_size = ITYPE(fwsize_idesc_rec) ; fw_name = ITYPE(fwname_idesc_rec)
CRT OCONV(@ID, 'MCT') : ' wears ' : DOWNCASE(fw_name) : ', size: ' : fw_size
REPEAT

REM Page 66
Program output:

Alan wears slippers, size: 5


Greg wears boots, size: 10
Jim wears slippers, size: 8

Output of LIST F.TEMP FWNAME FWSIZE after running this program:

F.TEMP........ FWNAME...... FWSIZE

GREG BOOTS 10
ALAN SLIPPERS 5
JIM SLIPPERS 8

3.70 JBASECOREDUMP()
Example of usage: get T24 application structure (log in to T24 and log out before running
this program):

$INSERT I_COMMON
$INSERT I_EQUATE

V$FUNCTION = 'TEST' ;* anything that is longer than one character will do


CALL FT.TXN.TYPE.CONDITION

ret_code = JBASECOREDUMP('all-vars.txt', 0)

Some contents of file all-vars.txt:

jBASE Core dump created at Fri May 31 19:54:03 2013


Program C:\home\kzm\v-t24\r11\bnk\bnk.run\TEST.exe , port 286 , process id 3432

CALL/GOSUB stack

Backtrace:
#0: jmainfunction.b:7
#1: test.b:7 -> Line 7 , Source jmainfunction.b

Backtrace log:
Program jmainfunction.b, Line 7, Stack level 0
Line 0 , Source jmainfunction.b , Level 0
>>> Program test.b, Line 7, Stack level 1
Line 7 , Source jmainfunction.b

All the defined VAR's in the program

COMMON variables

REM Page 67
003FF278 : T.RETURN.DATA : (V) Integer : 0
003FEF30 : T.CONTROLWORD : (V) Integer : 0
003FF4F8 : F.STATIC.TEXT : (V) Integer : 0
01D93B08 : C$MULTI.BOOK : (V) Integer : 0
01D93BA8 : C$DE.EU.LIST : (V) Integer : 0
003FEBC0 : PGM.TYPE.NEXT : (V) Integer : 0
003FE260 : A : (V) Integer : 0
003FE3C8 : C : (V) Integer : 0
003FF520 : F.FILE.CONTROL : (V) Integer : 0
003FE4B8 : E : (V) Integer : 0
01DA7A68 : F(0) : (V) String : 0 bytes at address 22131690 :
01DA7A90 : F(1) : (V) String : 17 bytes at address 003FD838 : XX.LL.DESCRIPTION
01DA7AB8 : F(2) : (V) String : 17 bytes at address 01D932F8 : XX.LL.SHORT.DESCR
...
01A407E8 : N(1) : (V) String : 4 bytes at address 019C5AA0 : 35.3
01A40810 : N(2) : (V) String : 4 bytes at address 019C5B30 : 15.3
01A40838 : N(3) : (V) String : 5 bytes at address 019C5BC0 : 3.1.C
01A40860 : N(4) : (V) String : 5 bytes at address 019C5C50 : 3.1.C
...
01A5DDF8 : T(1) : (V) String : 1 bytes at address 0181DA68 : A
01A5DE20 : T(2) : (V) String : 1 bytes at address 0181DAB0 : A
01A5DE48 : T(3) : (V) String : 0 bytes at address 22119A4C :
01A5DE70 : T(4) : (V) String : 0 bytes at address 22119A4C :
...
0181C430 : ID.N : (V) Scaled (13) float : 4.2
...
01A28030 : CHECKFILE(1) : (V) String : 0 bytes at address 22119A4C :
01A28058 : CHECKFILE(2) : (V) String : 0 bytes at address 22119A4C :
01A28080 : CHECKFILE(3) : (V) String : 17 bytes at address .. TRANSACTION^1^L.A
01A280A8 : CHECKFILE(4) : (V) String : 17 bytes at address .. TRANSACTION^1^L.A
...
01A31CE0 : CONCATFILE(1) : (V) String : 0 bytes at address 22119A4C :
01A31D08 : CONCATFILE(2) : (V) String : 0 bytes at address 22119A4C :
01A31D30 : CONCATFILE(3) : (V) String : 0 bytes at address 22119A4C :
01A31D58 : CONCATFILE(4) : (V) String : 0 bytes at address 22119A4C :
...
0181C390 : ID.CONCATFILE : (V) String : 2 bytes at address 019C5A10 : AR
...
01DC4FC8 : R.OPF(497) : (V) Integer : 0
01DC4FF0 : R.OPF(498) : (V) Integer : 0
01DC5018 : R.OPF(499) : (V) Integer : 0
01DC5040 : R.OPF(500) : (V) Integer : 0
003FF1D8 : T.OPF : (V) Integer : 0
003FF250 : T.RAT : (V) Integer : 0
01DB1718 : R.NEW(0) : (V) Integer : 0
01DB1740 : R.NEW(1) : (V) Integer : 0
01DB1768 : R.NEW(2) : (V) Integer : 0
01DB1790 : R.NEW(3) : (V) Integer : 0

REM Page 68
01DB17B8 : R.NEW(4) : (V) Integer : 0
...
003FF3E0 : F.FILE$NAU : (V) Integer : 0
003FF3B8 : F.FILE$HIS : (V) Integer : 0
01D92C20 : SPARE.FKEY13 : (V) Integer : 0
01D92C48 : SPARE.FKEY14 : (V) Integer : 0
003FF548 : T.VAL.ASSOC : (V) Integer : 0
01D92C70 : SPARE.FKEY15 : (V) Integer : 0
01D92C98 : SPARE.FKEY16 : (V) Integer : 0
003FF2C8 : T.SUB.ASSOC : (V) Integer : 0
01D93A90 : USING.EBCDIC : (V) Integer : 0
003FE5A8 : V$FUNCTION : (V) String : 4
bytes at address 003FD4E8 : TEST
003FEF08 : CLEAR.SCREEN : (V) Integer : 0
003FF750 : COMI.DEFAULT : (V) Integer : 0
003FECD8 : SCREEN.TITLE : (V) Integer : 0
003FE8A0 : INPUT.BUFFER : (V) Integer : 0
003FF6B0 : F.IDS.LATEST : (V) Integer : 0
003FF0E8 : T.MULTI.PAGE : (V) Integer : 0
003FE378 : AUTH.QUALITY : (V) Integer : 0
003FEA30 : LEVEL.STATUS : (V) Integer : 0
003FE6C0 : ID.CONCATFILE : (V) String : 2
bytes at address 003FD618 : AR
003FF2F0 : BATCH.DETAILS : (V) Integer : 0
003FE990 : OVERRIDE.FLAG : (V) Integer : 0
003FEE90 : R.SPF.SYSTEM : (V) Integer : 0
01D93D60 : F.T24.SESSION : (V) Integer : 0
003FF188 : T.MULTI.TEXT : (V) Integer : 0
STANDARD Variables in SUBROUTINE main()
008DFCCC : PASSED.NO : (V) String : 0 bytes at address 22131690 :
008DFCF4 : PASSED.CHAR : (V) String : 0 bytes at address 22131690 :
008DFD1C : ret_code : (V) String : 0 bytes at address 22131690 :

3.71 JBASESubroutineExist()
Check if a subroutine exists in current environment:

subr_name = 'CDD'
result = CALLC JBASESubroutineExist(subr_name, subr_info)
CRT result ;* 1 (in T24 environment)
subr_name = 'QWERTY'
result = CALLC JBASESubroutineExist(subr_name, subr_info)
CRT result ;* 0

note: Is said to be faster than EXECUTE ‘‘jshow -c <routine-name>’’.

REM Page 69
3.72 JQLCOMPILE(), JQLEXECUTE(), JQLFETCH(), JQLGET-
PROPERTY()
Working with compiled jQL statements.

INCLUDE jQLProperties.h

IF NOT(GETENV('TAFC_HOME', tafc_home)) THEN


CRT 'TAFC_HOME not defined'
STOP
END

jql_query = 'LIST ONLY ' : tafc_home : '/jbcmessages'


jql_statement = ''

message = 0
ret_code = JQLCOMPILE(jql_statement, jql_query, 0, message)
IF message NE 0 THEN CRT 'Statement compilation error' ; STOP

select_var = ''
ret_code = JQLEXECUTE(jql_statement, select_var)
IF ret_code NE 0 THEN CRT 'JQLEXECUTE returned', ret_code ; STOP

LOOP
GOSUB GET.NEXT
UNTIL fetch_ret_code NE 1
REPEAT

STOP

GET.NEXT:
fetch_ret_code = JQLFETCH(jql_statement, control_var, data_var)
IF fetch_ret_code NE 1 THEN RETURN
ret_code = JQLGETPROPERTY(property_value, jql_statement, 0, \
STMT_PROPERTY_EXECUTE_COUNT)
CRT '@ID #' : property_value : ':' , data_var<1>
IF ret_code NE 0 THEN CRT 'JQLGETPROPERTY returned', ret_code ; STOP
RETURN
END

Output:

@ID #1: INV_FILE_TYPE


@ID #2: DEVICE_QUIT
@ID #3: RTN_NOGOSUB
@ID #4: ARRAY_ILLEGAL_SIZE
@ID #5: DIFF_COMMON
@ID #6: QLNOVERB
@ID #7: QLPARAMERR
...
@ID #487: 417

REM Page 70
@ID #488: 80044228
@ID #489: 80044233
@ID #490: 80045024

3.73 KEYIN(), TIMEDATE(), UPCASE()


Do something in a loop until certain key is pressed:

cursor_posn = @(0) ;* remember cursor position (start of the current line)


LOOP
LOOP
buffer = SYSTEM(14) ;* check if there's anything in keyboard buffer
IF buffer NE 0 THEN BREAK
CRT cursor_posn:TIMEDATE(): ;* e.g. 22:27:08 31 MAY 2013
MSLEEP 3000
REPEAT

key_pressed = UPCASE(KEYIN())
IF key_pressed EQ 'Q' THEN BREAK ;* exit if q or Q was pressed
REPEAT

3.74 LATIN1()
utf_line = CHAR(XTD('C3')) \
: CHAR(XTD('9F')) \ ;* c3 9f: LATIN SMALL LETTER SHARP S
: CHAR(XTD('C3')) \
: CHAR(XTD('9D')) ;* c3 9d: LATIN CAPITAL LETTER Y WITH ACUTE
lat_line = LATIN1(utf_line)
CRT lat_line, SEQ(lat_line[1,1]), SEQ(lat_line[2,1])

The output of this program is:

ßÝ 223 221

3.75 LEN(), INT()


* Centered string output (couldn't find appropriate FMT())
the_string = 'I WILL BE IN THE VERY CENTER' ; width = 50
CRT the_string, '...'
CHANGE 'WILL BE' TO 'AM' IN the_string
length = LEN(the_string)
left_offset = INT((width - length) / 2) ;* left offset
right_offset = width - length - left_offset ;* right offset
CRT SQUOTE(STR(' ', left_offset) : the_string : STR(' ', right_offset))
* Output: ' I AM IN THE VERY CENTER '

REM Page 71
3.76 LOCATE, INS, MINIMUM(), MAXIMUM()
I prefer FIND to search an array. But LOCATE can be used for sorting:

dyn_array = ''
FOR i = 1 TO 1000
dyn_array := @FM : RND(1000)
NEXT i
DEL dyn_array<1>
sorted_array = ''

FOR V.I = 1 TO 1000


num_to_proc = dyn_array<V.I>
LOCATE num_to_proc IN sorted_array<1> BY 'AN' SETTING insert_posn ELSE NULL
INS num_to_proc BEFORE sorted_array<insert_posn>
NEXT V.I

CRT MINIMUM(dyn_array), MAXIMUM(dyn_array) ;* e.g. "0 998"


CRT sorted_array<1>, sorted_array<1000> ;* numbers should be same as above

3.77 LOWER()
Convert field, value etc marks to one-level-lower ones:

dyn_array = 3 :@FM: 3 :@VM: 3 :@SM: 3 ;* "3" chosen for better readability


;* of hexadecimal output
CRT dyn_array 'MX' ;* 33FE33FD33FC33
lower_array = LOWER(dyn_array)
CRT lower_array 'MX' ;* 33FD33FC33FB33
CHANGE @VM TO ' :@VM: ' IN lower_array
CHANGE @SM TO ' :@SM: ' IN lower_array
CHANGE @TM TO ' :@TM: ' IN lower_array
CRT lower_array ;* 3 :@VM: 3 :@SM: 3 :@TM: 3

REM Page 72
3.78 MAKETIMESTAMP()

Time stamp (up to milliseconds):

start_ts = MAKETIMESTAMP(DATE(), TIME(), '') ;* e.g. 1319585861.358


MSLEEP(1010)
end_ts = MAKETIMESTAMP(DATE(), TIME(), '')
CRT end_ts - start_ts ;* e.g. 1.016

* check the impact of the third parameter


the_time = TIME()
IF NOT(GETENV('JBASE_TIMEZONE', timezone)) THEN
CRT 'GETENV failed'
STOP
END
CRT '3rd parameter not set: ' : MAKETIMESTAMP(DATE(), the_time, '')
;* e.g. 1369993831.151
CRT '3rd parameter: ' : timezone : ':' : MAKETIMESTAMP(DATE(), \
the_time, timezone) ;* e.g. Europe\London; number is the same as above
CRT '3rd parameter set to Belgrade: ' \ ;* e.g. 1369986631.151
: MAKETIMESTAMP(DATE(), the_time, 'Europe/Belgrade')

There are no milliseconds in the output under AIX so I found an appropirate C program
example on the Net and tried to obtain the proper time stamp there:
Step 1. C program nanosec.c:

#include <stdio.h>
#include <sys/time.h>
#include <stdlib.h>
#include <sys/types.h>

void main(){
struct timeval tm;
gettimeofday( &tm, NULL );
printf( "%d.%6d\n", tm.tv_sec, tm.tv_usec );
}

Step 2. Compile it (jcompile -R nanosec.c).


Step 3: jBC program.

the_time = TIME()
EXECUTE './nanosec' CAPTURING std_out
CRT 'Timestamp (up to nanoseconds) is: ' : std_out
CRT 'Timestamp (up to milliseconds) is: ' \
: FMT(std_out, 'R3')

REM Page 73
Sample output:

Timestamp (up to nanoseconds) is: 1369992903.775150


Timestamp (up to milliseconds) is: 1369992903.775

3.79 MATBUILD
Build a dynamic array from dimensioned one:

SUBROUTINE SOME.TEST
* T24 input routine
$INSERT I_COMMON
$INSERT I_EQUATE

MATBUILD r_new_dynamic FROM R.NEW


TEXT = 'RECORD HAS & FIELDS' :FM: DCOUNT(r_new_dynamic, FM)
CALL REM ;* e.g. for CUSTOMER: "RECORD HAS 187 FIELDS"
RETURN
END

Partial build; custom delimiters:

DIM dim_array(40)
MAT dim_array = 'Element '
FOR i = 1 TO 40
dim_array(i) := i
NEXT i
MATBUILD delim_array FROM dim_array, 3, 7 USING ":"
CRT delim_array ;* Element 3:Element 4:Element 5:Element 6:Element 7

REM Page 74
3.80 MATCH(ES)
* T24 IDs matching
transfer_id = 'FT130172HQJ4'
CRT transfer_id MATCHES "'FT'5N5X" ;* 1
hist_id = 'FT130172HQJ4;1'
CRT hist_id MATCHES "'FT'5N5X" ;* 0
CRT hist_id MATCHES "'FT'5N5X;1N" ;* 1
* date
start_date = '2011-10-25'
CRT start_date MATCHES "4N'-'2N'-'2N" ;* 1
* emulations compatibility
cust_name = 'JOHN DORY'
CRT cust_name MATCH "JOHN..." ;* 1 under prime, 0 under jbase
CRT cust_name MATCH "'JOHN'..." ;* 1 under prime, 0 under jbase
CRT cust_name MATCH "'JOHN'0X" ;* 1 under both
CRT cust_name MATCH "'John'..." ;* 0 under both
* "C" - alphanumeric - isn't supported at all under prime
CRT '2HQJ4' MATCHES "5C" ;* 1 under jbase emulation
* numbers
CRT 9.99 MATCHES "0N'.'2N" ;* 1
CRT '.99' MATCHES "0N'.'2N" ;* 1
* avoid messing up data with patterns (example for prime):
cust_address = '3RD FLOOR, 17A ELM STREET'
CRT cust_address MATCH "...17A..." ;* 0 - 17A means 17 alpha characters
CRT cust_address MATCH "...'17A'..." ;* 1 - here '17A' is a string to search

3.81 MATPARSE
If the dynamic array taken into a dimensioned one has more elements than the dimensioned
does, extra elements will be placed to zero element of target array; if dimensioned array has
2 dimensions - it will be populated “left-to right”.

REM Page 75
Example:

DIM dim_array(100)
dyn_array = '' ; delim_array = ''
FOR i = 1 TO 100
dyn_array<-1> = i
delim_array := i*2 : '-'
NEXT i
* Full copy
MATPARSE dim_array FROM dyn_array
CRT dim_array(1) ;* 1
CRT dim_array(100) ;* 100
* Using different array delimiter
MAT dim_array = 'Default'
MATPARSE dim_array FROM delim_array USING '-'
CRT dim_array(1) ;* 2
CRT dim_array(100) ;* 200
* Partial copy
MAT dim_array = 'Default'
MATPARSE dim_array, 3, 7 FROM dyn_array
CRT dim_array(1) ;* Default
CRT dim_array(3) ;* 1
CRT dim_array(5) ;* 3
CRT dim_array(100) ;* Default
* "Over-copy"
FOR i = 101 TO 103 ;* add 3 elements to dynamic array
dyn_array<-1> = i
NEXT i
MAT dim_array = 'Default'
MATPARSE dim_array FROM dyn_array
CRT dim_array(1) ;* 1
CRT dim_array(100) ;* 100
the_extra = dim_array(0) ;* all excess elements are here
CHANGE @FM TO '>>>' IN the_extra
CRT the_extra ;* 101>>>102>>>103
* 2-dimensioned array population: "left-to-right":
DIM two_dim_array(100,2)
MATPARSE two_dim_array FROM dyn_array
CRT two_dim_array(1,1) ;* 1
CRT two_dim_array(1,2) ;* 2
CRT two_dim_array(2,1) ;* 3
CRT two_dim_array(2,2) ;* 4
CRT two_dim_array(50,2) ;* 100
CRT DQUOTE(two_dim_array(100,1)) ;* ""

REM Page 76
3.82 MAXIMUM()
PRECISION 5
dyn_array = 4.29442 :@AM: -3.60441 :@VM :4.29445 :@AM: 2.00042 \
:@SM: -33.90228
CRT MAXIMUM(dyn_array) ;* 4.29445
* non-numeric elements are ignored
dyn_array<2,1> = '9000,00'
CRT MAXIMUM(dyn_array) ;* still 4.29445
* PRECISION matters
PRECISION 2
CRT MAXIMUM(dyn_array) ;* now 4.29442

3.83 MOD()
In this sample a dot will be output to the screen after every 1000 iterations:

FOR i = 1 TO 100000
IF MOD(i, 1000) EQ 0 THEN
CRT '.':
END
* some processing here
NEXT i

3.84 MSLEEP()
CRT MAKETIMESTAMP(DATE(), TIME(), '') ;* e.g. 1353068005.934
MSLEEP(100) ;* 0.1 sec
CRT MAKETIMESTAMP(DATE(), TIME(), '') ;* e.g. 1353068006.044
MSLEEP(3000) ;* 3 sec
CRT MAKETIMESTAMP(DATE(), TIME(), '') ;* e.g. 1353068009.039
MSLEEP 3000 ;* this syntax also works
CRT MAKETIMESTAMP(DATE(), TIME(), '') ;* e.g. 1353068012.035
* Sleep until the beginning of the next hour
time = OCONV(TIME(), 'MT')
sleep_until = time[1, 2] + 1
IF sleep_until EQ 24 THEN sleep_until = '00'
sleep_until := ':00'
CRT 'Will sleep until ' : sleep_until ;* e.g. Will sleep until 13:00
SLEEP sleep_until
CRT OCONV(TIME(), 'MTS'), ',', "I'm back as promised"

REM Page 77
3.85 NEGS()
dyn_array = 1 :@FM: 2 :@VM :3
GOSUB PROC.IT ;* -1^-2]-3
dyn_array = 1 :@FM: '' :@VM :3
GOSUB PROC.IT ;* -1^0]-3
dyn_array = -1 :@FM: -2 :@VM: -3
GOSUB PROC.IT ;* 1^2]3
dyn_array = 1 :@SM: -2 :@FM: 3
GOSUB PROC.IT ;* -1\2^-3
dyn_array<-1> = 'A text'
GOSUB PROC.IT ;* Non-numeric value -- ZERO USED
;* -1\2^-3^0
STOP

PROC.IT:
CRT FMT(NEGS(dyn_array), 'MCP')
RETURN

3.86 NUM()
It doesn’t check if every character in expression is a numeric (that’s what ISDIGIT is for) –
rather if an expression can be considered as a number:

CRT NUM('') ;* 1
CRT NUM('123334440.12') ;* 1
CRT NUM('1233344.40.12') ;* 0
CRT NUM('1,233,344.40') ;* 0 - thousand delimiters don't do
CRT NUM('1 233 344.40') ;* 0 - neither do spaces
CRT NUM('00012') ;* 1 - leading zeroes are ok
CRT NUM('-123334440.12') ;* 1 - minus is ok...
CRT NUM('123334440.12-') ;* 0 - ...but not everywhere
CRT NUM('+123334440.12') ;* 1
CRT NUM('6.02e23') ;* 0 - E notation doesn't work
CRT NUM('1233Q34440.12') ;* 0 - of course it's not
CRT NUM(2 + 2) ;* 1
CRT NUM('.00') ;* 1

REM Page 78
3.87 OPENSEQ, READSEQ, CLOSESEQ

In this example we read a flat file and proceed it line by line (line length is not limited):

* first we need to prepare a file to read


ret_code = JBASECOREDUMP('all-vars.txt', 0)

* now the sample itself


dir_in = '.'
file_in = 'all-vars.txt'
OPENSEQ dir_in, file_in TO f_file_in ELSE
* error handling here - file doesn't exist or access is denied
CRT 'Error while opening the file'
STOP
END
* we read each line in a loop to proceed possible long (>1024) lines;
* another method is to use IOCTL()
eof = ''
LOOP
line = ''
LOOP
READSEQ chunk FROM f_file_in ELSE
eof = 1
BREAK
END
length = BYTELEN(chunk)
line := chunk
IF length LT 1024 THEN BREAK
REPEAT
* line processing goes here
IF INDEX(line, 'file', 1) THEN CRT line

IF eof THEN BREAK


REPEAT
CLOSESEQ f_file_in

Output:

008DFC04 : f_file_in : (V) Uninitialised : (UNASSIGNED)


008DFCF4 : file_in : (V) Uninitialised : (UNASSIGNED)

3.88 OSBREAD
The following program, being put to test.b file, reads its source and outputs it to the screen:

OSOPEN 'test.b' TO f_source ELSE STOP


OSBREAD contents FROM f_source AT 0 LENGTH 10000
CRT contents

REM Page 79
3.89 OSREAD
Unlike OSBREAD, it reads not a portion but the whole file so take care about file size. Also,
it requires file name rather than file variable.
Example:

* set some variables to search for later


the_string = 'QWERTZ'
the_pi = 3.14
longer_pi = 3.141592

* prepare a file to read


dump_file = 'all-vars.txt'
ret_code = JBASECOREDUMP(dump_file, 0)
* now read it
OSREAD all_vars FROM dump_file ELSE
CRT 'Error reading the file'
STOP
END
* look up variables
lookup = 'the_string'
GOSUB FIND.IT

lookup = 'the_pi'
GOSUB FIND.IT

lookup = 'longer_pi'
GOSUB FIND.IT

lookup = 'something_wrong'
GOSUB FIND.IT

STOP

FIND.IT:

posn = INDEX(all_vars, lookup, 1)


IF posn EQ 0 THEN
CRT DQUOTE(lookup), 'not found'
RETURN
END

the_rest = all_vars[posn, 999]


lf_posn = INDEX(the_rest, @FM, 1) ;* lines are delimited by field mark
IF lf_posn = 0 THEN CRT the_rest ;* the very end of file
ELSE CRT the_rest[1, lf_posn - 1]

RETURN
END

REM Page 80
Output:

the_string : (V) String : 6 bytes at address 003FBAB8 : QWERTZ


the_pi : (V) Scaled (4) float : 3.14
longer_pi : (V) String : 8 bytes at address 003FBBA0 : 3.141592
"something_wrong" not found

note: With “PRECISION 10” clause at program start longer pi would be float as well.

3.90 PRECISION
Don’t believe manuals, it can be greater than 9. A little program to illustrate its behaviour:

var_1 = '0.123456789012345678901234567890123456789012345678901234567890'
var_2 = '0.1234567890123456789012345678901234567890123456789012345678901'

PRECISION 13
GOSUB TEST ;* Equal
PRECISION 17
GOSUB TEST ;* Not equal
STOP

TEST:
results = 'Not equal' :@FM: 'Equal'
compare = (var_1 = var_2)
CRT results<compare + 1>
RETURN
END

note: T24 default is 13.


Another example:

PRECISION 6
CRT 2 / 3 ;* 0.666666 - truncation, not rounding
PRECISION 8
CRT 2 / 3 ;* 0.66666666

3.91 PRINTERR
PRINTERR 201 : CHAR(254) : "CUSTOMERS"

Output:

** Error [ 201 ] **
Unable to open file CUSTOMERS

REM Page 81
3.92 PROMPT
Change the prompt used in INPUT statement:

the_prompt = SYSTEM(26) ; CRT DQUOTE(the_prompt) ;* "?"


PROMPT 'Your choice:'
INPUT something ;* 'Your choice:'
PROMPT the_prompt
INPUT something

3.93 PUTENV
See the impact of JBASE ERRMSG ZERO USED setting:

zero_use = 'JBASE_ERRMSG_ZERO_USED'
IF NOT(PUTENV(zero_use : '=35')) THEN
CRT 'PUTENV failed'
STOP
END
CRT 'See the impact of JBASE_ERRMSG_ZERO_USED'
CRT '=35'
CRT var_1 ;* variable not assigned; nothing is being output
IF NOT(PUTENV(zero_use : '=0')) THEN
CRT 'PUTENV failed'
STOP
END
CRT '=0'
CRT var_1 ;* Invalid or uninitialised variable -- NULL USED ,
;* Var (UNKNOWN) , Line 17 , Source test.b

3.94 PWR()
number = 2
power = 31
CRT "2 GB is " : number ^ power ;* 2 GB is 2147483648
CRT "2 GB is definitely " : PWR(number, power)
;* 2 GB is definitely 2147483648
CRT "-2 GB is " : NEG(number)^power ;* -2 GB is -2147483648
CRT "2 to the power of 31.5 is " : PWR(number, power + 0.5)
;* 2 to the power of 31.5 is 3037000499.9761
CRT "-2 to the power of 31.5 is " : PWR(NEG(number), power + 0.5)
;* -2 to the power of 31.5 is 0.0nan

REM Page 82
3.95 RAISE()

Opposite of LOWER().

dyn_array = 1 :@TM: 2 :@SM: 3 :@VM: 4 :@FM: 5


CRT OCONV(dyn_array, 'MCP') ;* 1.2\3]4^5
raised_array = RAISE(dyn_array)
CRT OCONV(raised_array, 'MCP') ;* 1\2]3^4_5
CRT raised_array 'MX' ;* 31FC32FD33FE34FF35
CHANGE @VM TO ' :@VM: ' IN raised_array
CHANGE @SM TO ' :@SM: ' IN raised_array
CHANGE @FM TO ' :@FM: ' IN raised_array
CHANGE CHAR(255) TO ' :0xFF: ' IN raised_array
CRT raised_array ;* 1 :@SM: 2 :@VM: 3 :@FM: 4 :0xFF: 5
* FF is the limit:
CRT RAISE(3 : @FM : 3 : CHAR(XTD('FF')) : 3) 'MX' ;* 33FF33FF33

3.96 READBLK
IF NOT(GETENV('TAFC_HOME', tafc_home)) THEN
CRT 'TAFC_HOME not defined'
STOP
END
file_in = 'RELEASE'
file_info = DIR(tafc_home : '/' : file_in)
file_size = file_info<1>
OPENSEQ tafc_home, file_in TO f_release ELSE
CRT 'Failed to open', file_in
STOP
END
block_size = MINIMUM(file_size :@FM: 512)
READBLK rel_info FROM f_release, block_size ELSE
CRT 'Failed to read', file_in
STOP
END
CRT rel_info[1, INDEX(rel_info, CHAR(10), 1)] ;* 1st line, e.g.:
;* jBase Release : R11.0.0.0

REM Page 83
3.97 READL

Under Windows READL has the same effect as READU:

OPEN 'F.TEMP' TO f_temp ELSE


EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE
CRT 'OPEN FAILED'
STOP
END
END
rec_id = 'REC1'
READL record FROM f_temp, rec_id LOCKED
CRT 'Lock failure'
STOP
END ELSE NULL
CRT RECORDLOCKED(f_temp, rec_id) ;* 2 under Windows, 1 under Unix

3.98 READNEXT combined with READPREV


Though I wouldn’t recommend anyone to change the direction when retrieving keys from a
list, keep in mind that jBC behaviour in this case differs from one described in manuals.

EXECUTE 'DELETE-FILE DATA F.TEMP'


EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'

record = 'LINE 1' :@FM: 'LINE 2' :@FM: 'LINE 3'

WRITE record TO f_temp, 'REC1'


WRITE record TO f_temp, 'REC2'
WRITE record TO f_temp, 'REC3'

query = 'SSELECT F.TEMP TO 9'


EXECUTE query

READNEXT id FROM 9 ELSE CRT 'READNEXT 1 FAILED'


CRT 'NEXT:' : id
READNEXT id FROM 9 ELSE CRT 'READNEXT 2 FAILED'
CRT 'NEXT:' : id
READPREV id FROM 9 ELSE CRT 'READPREV 1 FAILED'
CRT 'PREVIOUS:' : id
READPREV id FROM 9 ELSE CRT 'READPREV 2 FAILED'
CRT 'PREVIOUS:' : id
READNEXT id FROM 9 ELSE CRT 'READNEXT 3 FAILED'
CRT 'NEXT:' : id

REM Page 84
Output:

NEXT:REC1
NEXT:REC2
PREVIOUS:REC3 ---> expected to be REC1
READPREV 2 FAILED ---> would be true if we had REC1 as expected
PREVIOUS:
READNEXT 3 FAILED ---> expected to be REC1
NEXT:

note: Works as expected under jbase emulation; however we’re under prime in T24.

3.99 READSEQ – platforms compatibility


In text files lines end differently under Unix/Linux and Windows. If you have Windows-style
line ends (CR + LF) in Unix environment, READSEQ adds CR (ASCII 13) to the line being
read. See the example:
Step 1. Ceate file input-file in Notepad:

LINE 1
LINE 2
LINE 3

Step 2. A program:

dir_in = '.'
file_in = 'input-file'
OPENSEQ dir_in, file_in TO f_in ELSE
CRT 'FLAT FILE OPEN ERROR'
STOP
END

LOOP
READSEQ line FROM f_in ELSE BREAK
DEBUG
CRT OCONV(line, 'MX')
REPEAT
CLOSESEQ f_in

Step 3. Run this program under Windows:

DEBUG statement seen


Source changed to .\readtest.b
0010 DEBUG
jBASE debugger->V line
line : LINE 1

REM Page 85
jBASE debugger->S
0011 CRT OCONV(line, 'MX')
jBASE debugger->S
4C494E452031
0012 REPEAT
jBASE debugger->

Step 4. Upload the file input-file in binary mode to Unix server. Run the same program
there:

DEBUG statement seen


Source changed to ./readtest.b
0010 DEBUG
jBASE debugger->V line
line : LINE 1~0D
jBASE debugger->S
Source changed to ./readtest.b
0011 CRT OCONV(line, 'MX')
jBASE debugger->S
4C494E4520310D
0012 REPEAT
jBASE debugger->

3.100 READU
In this example a record in the file is opened (or created) and a new field is appended to it.

OPEN 'F.TEMP' TO f_temp ELSE


EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE
CRT 'OPEN FAILED'
STOP
END
END
rec_id = 'REC1'
READU record FROM f_temp, rec_id LOCKED
CRT 'Lock failure'
STOP
END ELSE NULL
CRT RECORDLOCKED(f_temp, rec_id) ;* 2 (locked by same process with READU)
record<-1> = 'New field'
fld_qty = DCOUNT(record, @FM)
WRITE record TO f_temp, rec_id
CRT RECORDLOCKED(f_temp, rec_id) ;* 0 (not locked - WRITE released the lock)
EXECUTE "LIST F.TEMP '" : rec_id : "' *A" : fld_qty

REM Page 86
Sample output:

F.TEMP........ *A9...........

REC1 New field

3.101 READV
Read particular field instead of the whole record:

OPEN 'F.TEMP' TO f_temp THEN


ret_error = ''
CLEARFILE f_temp SETTING ret_error
IF ret_error NE '' THEN
CRT 'ERROR ' : ret_error
STOP
END
END ELSE
EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'
END

out_record = 'Field 1' :@FM: 'Field 2' :@FM: 'Field 3'


WRITE out_record TO f_temp, 'REC1'

READV second_field FROM f_temp, 'REC1', 2 ELSE


CRT 'Read error'
STOP
END

CRT second_field ;* Field 2

REM Page 87
3.102 RECORDLOCKED()

Check lock status without trying to lock a record:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

lock_id = 'USER.COUNTER' ;* ID can be non-existing one.


* don't need to open F.LOCKING - T24 core did it already
IF RECORDLOCKED(F.LOCKING, lock_id) LT 0 THEN
TEXT = 'LOCKED BY SOMEBODY ELSE...' ;* -1 READL
CALL REM ;* -2 READU
RETURN ;* -3 FILELOCK
END

* Shouldn't use READU for T24...


retry = 'E' ;* Return immediately with error message
CALL F.READU('F.LOCKING', lock_id, rec_lock, F.LOCKING, error_code, retry)
IF error_code AND error_code NE 'RECORD NOT FOUND' THEN
TEXT = error_code
CALL REM
RETURN
END

IF RECORDLOCKED(F.LOCKING, lock_id) EQ 2 THEN


TEXT = 'LOCKED. NOW RUN THIS ROUTINE IN ANOTHER SESSION'
CALL REM
END

CALL F.RELEASE('F.LOCKING', lock_id, F.LOCKING)


IF RECORDLOCKED(F.LOCKING, lock_id) LT 1 THEN ;* 0 (OK) or less (others)
TEXT = 'UNLOCKED...'
CALL REM
END

RETURN
END

REM Page 88
3.103 REGEXP()

Regular expressions support. Some samples:

string = "jBC program test.b" ;* 5 (position of matching pattern -


CRT REGEXP(string, 'p[^t]*') ;* "p" followed by "t" later on)

* find an exact value in a list


CRT REGEXP("051", "^(050|5001|051|053|265|4007|5007|037|060|098)$") ;* 1
CRT REGEXP("05123", "^(050|5001|051|053|265|4007|5007|037|060|098)$") ;* 0

* everything in range "000" - "999" except "037"


CRT REGEXP("036", "(0[0-24-9][0-9]|0[0-9][0-68-9]|[1-9][0-9][0-9])") ;* 1
CRT REGEXP("037", "(0[0-24-9][0-9]|0[0-9][0-68-9]|[1-9][0-9][0-9])") ;* 0
CRT REGEXP("137", "(0[0-24-9][0-9]|0[0-9][0-68-9]|[1-9][0-9][0-9])") ;* 1

* everything in range "000" - "999" except "037" and "057"


CRT REGEXP("036", "(0[0-246-9][0-9]|0[0-9][0-68-9]|[1-9][0-9][0-9])") ;* 1
CRT REGEXP("037", "(0[0-246-9][0-9]|0[0-9][0-68-9]|[1-9][0-9][0-9])") ;* 0
CRT REGEXP("057", "(0[0-246-9][0-9]|0[0-9][0-68-9]|[1-9][0-9][0-9])") ;* 0
CRT REGEXP("957", "(0[0-246-9][0-9]|0[0-9][0-68-9]|[1-9][0-9][0-9])") ;* 1

* all T24 country codes except "RS"


CRT REGEXP('RS', "([A-QS-Z][A-Z]|[R][A-RT-Z])") ;* 0
CRT REGEXP('AE', "([A-QS-Z][A-Z]|[R][A-RT-Z])") ;* 1
CRT REGEXP('RU', "([A-QS-Z][A-Z]|[R][A-RT-Z])") ;* 1

* negative lookahead assertion isn't supported ("all not containing 'bar'")


CRT REGEXP("bar", '"^(?!.*?bar).*"') ;* -1

note: Not supported under Windows.

3.104 RELEASE
This program optionally creates file F.TEMP and writes to it a record REC1, on the following
runs it updates that record – puts a new field in it, but only if there’s less than 7 fields;
otherwise we need to release the lock.

REM Page 89
Example:

OPEN 'F.TEMP' TO f_temp ELSE


EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE
CRT 'OPEN FAILED'
STOP
END
END

rec_id = 'REC1'
READU record FROM f_temp, rec_id LOCKED
CRT 'Record locked (' : RECORDLOCKED(f_temp, rec_id) : ')'
STOP
END ELSE NULL

IF DCOUNT(record, @FM) GT 5 THEN


CRT 'Nothing to write, releasing...'
RELEASE f_temp, rec_id
END ELSE
record<-1> = 'New field'
WRITE record TO f_temp, rec_id
CRT 'New field written'
END

To test “LOCKED” clause run this program at least once (to create the file), then open another
session and run JED there: JED F.TEMP REC1, then return to the first session and try to
execute this program one more time. Output will be:

Record locked (-2)

note: Always use CALL F.RELEASE() in T24 environment.

3.105 REMOVE
Retrieve elements of a dynamic array one by one – and it’s faster than using angle-brackets
notation indicated as “try 4” at the code below (see also the last chapter of this book).

REM Page 90
* This example requires T24 environment
EXECUTE 'SELECT FBNK.ACCOUNT SAMPLE 10' RTNLIST acct_list
* Retrieve @IDs one by one
CRT 'Try 1:'
LOOP
REMOVE acct_id FROM acct_list SETTING status
CRT acct_id
IF status EQ 0 THEN BREAK ;* check the status at the end of the loop
REPEAT ;* otherwise we'll lose the last item

* To proceed the list one more time we need to reset


* so-called "loop counter":
acct_list = acct_list

CRT 'Try 2:'


LOOP
REMOVE acct_id FROM acct_list SETTING status
CRT acct_id
IF status EQ 0 THEN BREAK
REPEAT

* If we don't do that we wouldn't be able to retrieve anything:


CRT 'Try 3:'
LOOP
REMOVE acct_id FROM acct_list SETTING status
CRT acct_id ;* nothing
IF status EQ 0 THEN BREAK
REPEAT

* Alternate method:
CRT 'Try 4:'
count = DCOUNT(acct_list, @FM)
FOR i = 1 TO count
acct_id = acct_list<i>
CRT acct_id
NEXT i
This example shows that current array delimiter can be determined:

record = "Field 1" :@FM: "Field 2" :@SM: " Sub-value" :@VM: "Value"
REMOVE rec_data FROM record SETTING status ; CRT status ;* 2 (FM)
REMOVE rec_data FROM record SETTING status ; CRT status ;* 4 (SM)
REMOVE rec_data FROM record SETTING status ; CRT status ;* 3 (VM)
REMOVE rec_data FROM record SETTING status ; CRT status ;* 0 (end of array)
record = record ;* reset "remove pointer"
REMOVE rec_data FROM record SETTING status ; CRT status ;* 2 (start again)
record := @TM : "Some text"
* data changed; hence we start again...
REMOVE rec_data FROM record SETTING status ; CRT status ;* 2
REMOVE rec_data FROM record SETTING status ; CRT status ;* 4
REMOVE rec_data FROM record SETTING status ; CRT status ;* 3
REMOVE rec_data FROM record SETTING status ; CRT status ;* 5 (text mark)
REMOVE rec_data FROM record SETTING status ; CRT status ;* 0 - that's it...

REM Page 91
3.106 REPLACE()
dyn_array = "Life" :@VM: "is" :@VM: "wonderful" :@FM: '!'
* note semicolon in the next line - quite unusual for jBC...
more_dyn_array = REPLACE(dyn_array, 1, 2; "is really")
* it doesn't mean that some arrays are more dynamic than others... just a name
CRT FMT(dyn_array, 'MCP') ;* Life]is]wonderful^!
CRT FMT(more_dyn_array, 'MCP') ;* Life]is really]wonderful^!

3.107 REUSE(), SUBS()


* decrease each element of an array by a constant
bigger_array = 500: @VM: 400: @VM: 300 :@SM: 200 :@SM: 100
smaller_array = SUBS(bigger_array, REUSE(300))
CRT OCONV(smaller_array, 'MCP') ;* 200]100]0\-100\-200

3.108 SEEK
Note that it’s possible to go to position after EOF:

dir_out = '.' ; file_out = 'report.txt'


OPENSEQ dir_out, file_out TO f_out THEN
WEOFSEQ f_out
END ELSE
CREATE f_out ELSE CRT 'File create error' ; STOP
END
WRITESEQ '1234567890ABCDEF' TO f_out ELSE
CRT 'Write error'
STOP
END
* go right after position 5 from the beginning
SEEK f_out, 5, 0 ELSE CRT 'Seek error' ; STOP
READSEQ line FROM f_out ELSE CRT 'Read error' ; STOP
CRT line ;* 67890ABCDEF
* go 3 bytes beyond end of file and write something there
SEEK f_out, 3, 2 ELSE CRT 'Seek error' ; STOP
WRITESEQ 'VWXYZ' TO f_out ELSE CRT 'Write error' ; STOP
CLOSESEQ f_out
* read full file contents
OSREAD contents FROM file_out ELSE CRT 'Read error' ; STOP
CRT FMT(FMT(OCONV(contents, 'MX'), '2L'), 'MCP ')
* Output (note presence of ASCII 0 characters caused by writing beyond EOF):
* 31 32 33 34 35 36 37 38 39 30 41 42 43 44 45 46 FE 00 00 00 56 57 58 59 5A

REM Page 92
3.109 SENTENCE()
this_prog = SENTENCE(0) ;* name of this program
phrase_part = 'to understand recursion '
IF SENTENCE(1) EQ '-2' THEN ;* first parameter
CRT TRIM(SENTENCE(2), '"', 'B'): ;* 2nd parameter
CRT phrase_part
END ELSE
CRT phrase_part:
EXECUTE this_prog : ' -2 "you firstly need "'
END

note: See also SYSTEM(1000).

3.110 SEQ()
Opposite to CHAR(). Get character code (and not only ASCII):

CRT SEQ('A') ;* 65
CRT SEQ('AB') ;* still 65 - only one character counts
* Unicode Character 'LATIN SMALL LETTER S WITH CARON' (C5A1)
CRT SEQ(ICONV('C5A1', 'MX')) ;* 353

3.111 SORT
Ascending, left-justified sort of a dynamic array:

EXECUTE 'SELECT .' :@FM: 'SAVE-LIST FILES-LIST'


GETLIST 'FILES-LIST' TO files_list ELSE CRT 'GETLIST error' ; STOP
sorted_list = SORT(files_list)
CRT sorted_list<1> : '...' : sorted_list<2> : '...' \
: sorted_list<DCOUNT(sorted_list, @FM)> ;* e.g. &COMO&...&ED&...VOCLIB]D

REM Page 93
3.112 SSELECT

Get the sorted list of @IDs in a file:

OPEN 'F.TEMP' TO f_temp THEN


err_code = ''
CLEARFILE f_temp SETTING err_code
IF err_code NE '' THEN
CRT 'ERROR ' : err_code
STOP
END
END ELSE
EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'
END
record = 'LINE 1' :@FM: 'LINE 2' :@FM: 'LINE 3'
WRITE record TO f_temp, 'REC3'
WRITE record TO f_temp, 'REC1'
WRITE record TO f_temp, 'REC2'
SSELECT f_temp TO id_list
READNEXT next_id FROM id_list THEN CRT next_id ;* REC1
READNEXT next_id FROM id_list THEN CRT next_id ;* REC2
READNEXT next_id FROM id_list THEN CRT next_id ;* REC3

3.113 SSELECTV
SSELECTV can be used to proceed with a simple sort of dynamic array :

random_list = ''
FOR i = 1 TO 1000
random_list<-1> = FMT(RND(10000), 'R%4') ;* FMT() - for proper sorting
NEXT i

SSELECTV random_list TO sorted_list


CRT 'Got numbers from ' : sorted_list<1> * 1 : ' to ' : sorted_list<1000> * 1

* Sample outputs:
* Got numbers from 3 to 9988
* Got numbers from 7 to 9991
* Got numbers from 12 to 9998
* Got numbers from 6 to 9990

note: As you see, multiplication by 1 strips leading zeroes; trim() could also be used.

REM Page 94
3.114 STATUS()
DELETE not_valid_filevar, 'REC5' SETTING ret_code ON ERROR
CRT 'REC5 - DELETE ERROR'
END
CRT STATUS() ;* -1
CRT ret_code ;* 32768

3.115 STATUS statement


Get information about opened file.

IF NOT(GETENV('JEDIFILENAME_SYSTEM', system_file)) THEN ABORT


OPEN system_file TO f_sys ELSE NULL
STATUS info_array FROM f_sys ELSE ABORT

CRT info_array<5> ;* permissions in octal, e.g. 655


CRT info_array<6> ;* file size in bytes
CRT info_array<20> ;* full path to file (also in <27>)
CRT info_array<21> ;* file type, e.g. J4, JR, XMLDB2, SEQ

note: If there’s no data file, values for dictionary part will be displayed.

3.116 STR()
* repeat a variable contents, not necesserily a string
CRT STR('-', 30) ;* ------------------------------
CRT STR('+-', 10) ;* +-+-+-+-+-+-+-+-+-+-
CRT STR(123, 3) ;* 123123123

3.117 SUM()
Results depend on array structure (i.e. set of delimiters):

dyn_array = 1 :@FM: 2 :@FM: 3.1


CRT FMT(SUM(dyn_array), 'MCP') ;* 6.1
dyn_array<4> = 6
CRT FMT(SUM(dyn_array), 'MCP') ;* 12.1
dyn_array<4,2> = 7
CRT FMT(SUM(dyn_array), 'MCP') ;* 1^2^3.1^13
dyn_array<4,3> = 'QWERTY'
CRT FMT(SUM(dyn_array), 'MCP') ;* still 1^2^3.1^13
dyn_array<4,3,2> = 8
CRT FMT(SUM(dyn_array), 'MCP') ;* 1^2^3.1^6]7]8

REM Page 95
3.118 SYSTEM()
Command line parameters and options:

command_line = SYSTEM(1000)
this_prog = command_line<1> ;* name of this program
IF command_line<2> EQ '' THEN
EXECUTE this_prog : ' -Jd par_1 "par 2"'
END ELSE
CRT 'Parameter 1 is:', command_line<2>
CRT 'Parameter 2 is:', command_line<3>
CRT 'Launch option was:', SYSTEM(1001)<2>
END

On debugger prompt type C; output is:

Parameter 1 is: par_1


Parameter 2 is: "par 2"
Launch option was: -Jd

Get information about all active jBASE sessions:

OPEN SYSTEM(1027) TO proc_file ELSE STOP 201, "PROC"


SELECT proc_file TO proc_list
LOOP
WHILE READNEXT proc_id FROM proc_list DO
READ proc_record FROM proc_file, proc_id ELSE CRT "Read Error"; STOP
port_no = proc_record<1>
login = proc_record<5>
pid = proc_record<4>
t24_user = proc_record<28>
call_stack = proc_record<41>
CONVERT @VM TO '>' IN call_stack

PRINT FMT(port_no, '4R') : '|' : FMT(pid, '8R') : '|' : login \


: '|' : FMT(t24_user, '60L') : '|' : call_stack
REPEAT

REM Page 96
Other useful samples:

* get server OS
CRT SYSTEM(1017) ;* WINNT or UNIX
* get program or subroutine name (but not a section)
CRT SYSTEM(40) ;* e.g. test
GOSUB SUB1 ;* output is the same
* get own port number
CRT SYSTEM(18)
* get own PID
CRT SYSTEM(1037)
* get screen size
CRT SYSTEM(2) ;* e.g. 80
CRT SYSTEM(3) ;* e.g. 24
* is there anything in keyboard buffer
CRT SYSTEM(14) ;* 0
* Buffer is not necessarily filled manually
DATA 'QWE'
CRT SYSTEM(14) ;* 4 (includes end-of-line character)
* Prompt...
CRT SYSTEM(26) ;* ? (default one)
PROMPT 'Your choice:'
CRT SYSTEM(26) ;* Your choice:
* Active SELECT
IF NOT(GETENV('TAFC_HOME', tafc_home)) THEN
CRT 'TAFC_HOME not defined'
STOP
END
CLEARDATA ;* otherwise "QWE" will be executed
CRT SYSTEM(11) ;* 0
HUSH ON
EXECUTE 'SELECT ' : tafc_home : '/jbcmessages'
HUSH OFF
CRT SYSTEM(11) ;* 490

STOP
*-----------------------
SUB1:
CRT SYSTEM(40)
RETURN

REM Page 97
3.119 TIME() and @TIME
The former is current time; the latter is program start time:

MSLEEP 3000
CRT @TIME, TIME() ;* e.g. 80557 80560

note: same goes for DATE() and @DATE.

3.120 TIMESTAMP()
Returns UTC timestamp value:

timestamp = TIMESTAMP()
CRT timestamp ;* e.g. 1370330053.058
CRT (MAKETIMESTAMP(DATE(), TIME(), \
'Europe/Amsterdam') - timestamp) / 3600 ;* -1 or -2 (depending on
CRT (MAKETIMESTAMP(DATE(), TIME(), \ ;* daylight saving)
'Asia/Singapore') - timestamp) / 3600 ;* -8

REM Page 98
3.121 TRANSTART, TRANSEND, TRANSQUERY(), TRANS-
ABORT

Never use that in T24 environment; though it might be useful for some standalone reports.
Example illustrating the parallel write to 2 files.

EXECUTE 'DELETE-FILE DATA F.TEMP'


EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'

EXECUTE 'DELETE-FILE DATA F.TMP'


EXECUTE 'CREATE-FILE DATA F.TMP 1 101 TYPE=J4'
OPEN 'F.TMP' TO f_tmp ELSE ABORT 201, 'F.TMP'

TRANSTART ELSE
CRT 'ERROR STARTING TXN 1'
STOP
END
CRT SYSTEM(47) ;* 1 - we're inside a transaction

record = 'Field 1' :@FM: 'Field 2' :@FM: 'Field 3'


new_record = record :@VM: 'Field 3, value 2'

WRITE record TO f_temp, 'REC1'


WRITE record TO f_tmp, 'REC1'

TRANSEND THEN CRT 'TXN 1 WRITTEN'


CRT SYSTEM(47) ;* 0 - we're not inside a transaction

TRANSTART ELSE
CRT 'ERROR STARTING TXN 2'
STOP
END

WRITE new_record TO f_temp, 'REC1'


WRITE new_record TO f_tmp, 'REC1'
WRITE record TO f_temp, 'REC2'
WRITE record TO f_tmp, 'REC2'
TRANSABORT THEN CRT 'TXN 2 ABORTED'

EXECUTE 'LIST F.TEMP *A1 *A2 *A3'


EXECUTE 'LIST F.TMP *A1 *A2 *A3'

Output:

[ 201 ] F.TEMP is not a file name


[ 417 ] File F.TEMP created , type = J4
[ 201 ] F.TMP is not a file name
[ 417 ] File F.TMP created , type = J4

REM Page 99
1
TXN 1 WRITTEN
0
TXN 2 ABORTED

LIST F.TEMP *A1 *A2 *A3

DICT F.TEMP... *A1........... *A2........... *A3...........

REC1 Field 1 Field 2 Field 3

1 Records Listed

LIST F.TMP *A1 *A2 *A3

DICT F.TMP.... *A1........... *A2........... *A3...........

REC1 Field 1 Field 2 Field 3

1 Records Listed

note: REC2 doesn’t exist in both files – transaction was aborted; REC1 is in initial state.

Example showing the commit of written data.


Program 1: write to file without transactions.

EXECUTE 'DELETE-FILE DATA F.TEMP'


EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'
record = 'Field 1' :@FM: 'Field 2' :@FM: 'Field 3'
WRITE record TO f_temp, 'REC1'
EXECUTE 'LIST F.TEMP *A1 *A2 *A3'
PROMPT 'Press any key to continue'
INPUT dummy
EXECUTE 'LIST F.TEMP *A1 *A2 *A3'

Output: LIST will show the same results both times:

LIST F.TEMP *A1 *A2 *A3

DICT F.TEMP... *A1........... *A2........... *A3...........

REC1 Field 1 Field 2 Field 3

1 Records Listed

REM Page 100


Program 2: write to file in a transaction.

EXECUTE 'DELETE-FILE DATA F.TEMP'


EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'
TRANSTART ELSE
CRT 'ERROR STARTING TXN'
STOP
END
CRT TRANSQUERY() ;* 1 - we're inside a transaction
CRT SYSTEM(47) ;* another method to check it
record = 'Field 1' :@FM: 'Field 2' :@FM: 'Field 3'
WRITE record TO f_temp, 'REC1'
EXECUTE 'LIST F.TEMP *A1 *A2 *A3'
PROMPT 'Press any key to continue'
INPUT dummy
TRANSEND THEN CRT 'TXN WRITTEN'
EXECUTE 'LIST F.TEMP *A1 *A2 *A3'

Until transaction is over – no records will be shown:

LIST F.TEMP *A1 *A2 *A3

DICT F.TEMP... *A1........... *A2........... *A3...........

No Records Listed

Press any key to continue

LIST F.TEMP *A1 *A2 *A3

DICT F.TEMP... *A1........... *A2........... *A3...........

REC1 Field 1 Field 2 Field 3

1 Records Listed

REM Page 101


Another example shows writes inside and outside a transaction.

EXECUTE 'DELETE-FILE DATA F.TEMP'


EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'
record = 'Field 1' :@FM: 'Field 2' :@FM: 'Field 3'
WRITE record TO f_temp, 'REC1' ;* write before a transaction
TRANSTART ELSE
CRT 'ERROR STARTING TXN'
STOP
END
WRITE record TO f_temp, 'REC2'
TRANSABORT THEN CRT 'TXN ABORTED' ;* abandon the second write
WRITE record TO f_temp, 'REC3' ;* write after a transaction
EXECUTE 'LIST F.TEMP *A1 *A2 *A3'

Output:

LIST F.TEMP *A1 *A2 *A3

DICT F.TEMP... *A1........... *A2........... *A3...........

REC1 Field 1 Field 2 Field 3


REC3 Field 1 Field 2 Field 3

2 Records Listed

3.122 TRIM()
string = ' A string '
* Get rid of leading spaces
CRT '"' : TRIM(string, ' ', 'L') : '"' ;* "A string "
* Get rid of trailing spaces
CRT '"' : TRIM(string, ' ', 'T') : '"' ;* " A string"
* Get rid of leading and trailing spaces
CRT '"' : TRIM(string, ' ', 'B') : '"' ;* "A string"
* Get rid of leading, trailing and redundant spaces
CRT '"' : TRIM(string, ' ', 'R') : '"' ;* "A string"
* Get rid of leading zeroes
CRT '"' : TRIM('000033', '0', 'L') : '"' ;* "33"

3.123 TRIMBS()
TRIM the dynamic array:

dyn_array = ' Use ' :@FM: ' the ' :@VM: ' ' :@FM: 'source Luke ! '
CRT DQUOTE(OCONV(TRIMBS(dyn_array), 'MCP'))

REM Page 102


Output:

" Use^ the]^source Luke !"

note: Leading and redundant spaces are not removed.

3.124 TRIMFS()
dyn_array = ' Use ' :@FM: ' the ' :@VM: '' :@FM: 'source Luke ! '
CRT DQUOTE(OCONV(TRIMFS(dyn_array), 'MCP'))
* Compare this with TRIMBS()
CRT DQUOTE(OCONV(TRIMBS(dyn_array), 'MCP'))

Output:

"Use ^the ]^source Luke ! "


" Use^ the]^source Luke !"

3.125 UNASSIGNED()
Opposite of ASSIGNED():

OPEN 'F.TEMP' TO f_temp ELSE


EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'
END
CRT UNASSIGNED(f_temp) ;* 0
CLOSE f_temp
CRT UNASSIGNED(f_temp) ;* 1
CRT UNASSIGNED(var) ;* 1
var = 5
CRT UNASSIGNED(var) ;* 0
CLEAR
CRT UNASSIGNED(var) ;* 0 (it was assigned the value 0)
DIM dim_array(10)
CRT UNASSIGNED(dim_array(1)) ;* 1 ("UNASSIGNED(dim_array)" wouldn't compile)
MAT dim_array = 2
CRT UNASSIGNED(dim_array(1)) ;* 0

3.126 UNIQUEKEY()
Generates a UUID (Universally Unique Identifier).

the_key = UNIQUEKEY()
CRT the_key ;* e.g. AAADrAAADEy5+H7m
CRT FMT(DOWNCASE(FMT(the_key, 'MX')), \
'L(########-####-####-############)')
* e.g. 41414144-7241-4141-444579352b48

REM Page 103


3.127 UTF8()
lat_line = CHAR(198) : CHAR(189) : CHAR(191)
utf_line = UTF8(lat_line)
FOR i = 1 TO 6 STEP 2
CRT DTX(SEQ(utf_line[i,1])), DTX(SEQ(utf_line[i+1,1]))
NEXT i

The output of this program is:

C3 86 (latin capital letter ae)


C2 BD (vulgar fraction one half)
C2 BF (inverted question mark)

3.128 WEOFSEQ
Truncate the sequential file at the current position.
In this example a flat file is created and written to. If file already exists – ask user to agree
with file recreation. Last 5 bytes of written data will be deleted.

REM Page 104


out_dir = '.'
out_file = 'report.txt'

OPENSEQ out_dir, out_file TO f_out THEN


CRT 'TARGET FILE EXISTS. OVERWRITE[Y/N]':
CLEARINPUT ;* don't take anything in advance
INPUT reply
IF UPCASE(reply) NE 'Y' THEN ;* y or Y
* exit - user refused to overwrite the file
STOP ;* or RETURN
END
WEOFSEQ f_out ;* truncate the file
END

* We don't need to explicitly create a file; as soon as the first


* WRITESEQ will be issued - file will be created, otherwise it won't be -
* "openseq_creates" isn't set to "true" for Prime emulation.

* Processing loop starts


line_no = 0
LOOP
line_no ++

* Provide a way to exit a loop


IF line_no GT 7 THEN BREAK

* Get an output string into variable and...


line = 'Line ' : line_no
* ...either skip it...
IF line_no EQ 3 THEN CONTINUE
* ...or write it
WRITESEQ line TO f_out ELSE
* Write error - notify user and quit the program
CRT 'Write error'
STOP ;* or RETURN
END
REPEAT

* truncate the file at certain position


SEEK f_out, -5, 2 ELSE CRT 'Seek error' ; STOP
WEOFSEQ f_out
CLOSESEQ f_out

Contents of file report.txt:

Line 1
Line 2
Line 4
Line 5
Line 6
Li

REM Page 105


3.129 WRITEBLK
We have to explicitly create the output file if it doesn’t exist (we didn’t have to with
WRITESEQ). See an example:

* Create a file with random name and write to it


file_name = ''
FOR j = 1 TO 8
random_num = RND(26) + 65
file_name := CHAR(random_num) ;* A...Z
NEXT j

file_name := '.txt'

OPENSEQ '.', file_name TO f_out THEN


WEOFSEQ f_out ;* truncate the file
END ELSE ;* will have to create - WRITEBLK wouldn't do that
CREATE f_out ELSE
CRT 'FILE CREATION FAILURE'
STOP
END
END

data = 'LINE 1' : CHAR(10) : 'LINE 2' : CHAR(10) : 'LINE 3'

WRITEBLK data TO f_out ELSE


CRT 'WRITE ERROR'
STOP
END

CRT 'File ' : file_name : ' created'


CLOSESEQ f_out

If you run it several times, the output looks like:

File REBGRYNN.txt created


File EBOOJFAX.txt created

etc

REM Page 106


Now amend the routine to look more like in WRITESEQ case:

* Create a file with random name and write to it


file_name = ''
FOR j = 1 TO 8
random_num = RND(26) + 65
file_name := CHAR(random_num) ;* A...Z
NEXT j

file_name := '.txt'

OPENSEQ '.', file_name TO f_out THEN


WEOFSEQ f_out ;* truncate the file
* END ELSE ;* will have to create - WRITEBLK wouldn't do that
* CREATE f_out ELSE
* CRT 'FILE CREATION FAILURE'
* STOP
* END
END

data = 'LINE 1' : CHAR(10) : 'LINE 2' : CHAR(10) : 'LINE 3'

WRITEBLK data TO f_out ELSE


CRT 'WRITE ERROR'
STOP
END

CRT 'File ' : file_name : ' created'


CLOSESEQ f_out

Run it and see:

** Error [ NOT_FILE_VAR ] **
Variable is not an opened file descriptor , Line 21 , Source test.b
Trap from an error message, error message name = NOT_FILE_VAR
Source changed to .\test.b
0021 WRITEBLK data TO f_out ELSE
jBASE debugger->

REM Page 107


To double-check the things change WRITEBLK to WRITESEQ and see that all is well now:

* Create a file with random name and write to it


file_name = ''
FOR j = 1 TO 8
random_num = RND(26) + 65
file_name := CHAR(random_num) ;* A...Z
NEXT j

file_name := '.txt'

OPENSEQ '.', file_name TO f_out THEN


WEOFSEQ f_out ;* truncate the file
* END ELSE ;* will have to create - WRITEBLK wouldn't do that
* CREATE f_out ELSE
* CRT 'FILE CREATION FAILURE'
* STOP
* END
END

data = 'LINE 1' : CHAR(10) : 'LINE 2' : CHAR(10) : 'LINE 3'

* WRITEBLK data TO f_out ELSE


WRITESEQ data TO f_out ELSE
CRT 'WRITE ERROR'
STOP
END

CRT 'File ' : file_name : ' created'


CLOSESEQ f_out

3.130 WRITELIST
EXECUTE 'SELECT . SAMPLE 5' RTNLIST ret_list
WRITELIST ret_list TO 'SOME-FILES'
GETLIST 'SOME-FILES' TO files_list ELSE NULL
CRT OCONV(files_list, 'MCP') ;* e.g. &COMO&^&COMO&]D^&ED&^&ED&]D^&PH&

3.131 WRITESEQ
Write to sequential file.

REM Page 108


In this example a flat file is created and written to. If file already exists – data is appended
to it:

out_dir = '.'
out_file = 'report.txt'
OPENSEQ out_dir, out_file TO f_out THEN
SEEK f_out, 0, 2 ELSE ;* go to the end
CRT 'Seek error'
STOP
END
WRITESEQ 'One more line' TO f_out ELSE
CRT 'Write error'
STOP
END
END ELSE
WRITESEQ 'Line 1' TO f_out ELSE
CRT 'Write error'
STOP
END
END

Another way to append data to file – use APPEND keyword:

out_dir = '.'
out_file = 'time.log'
OPENSEQ out_dir, out_file TO f_out THEN NULL
WRITESEQ TIMEDATE() APPEND TO f_out ELSE
CRT 'Write error'
STOP
END

3.132 WRITEU
Write a record without releasing the previously applied lock.

REM Page 109


Example:

OPEN 'F.TEMP' TO f_temp ELSE


EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE
CRT 'OPEN FAILED'
STOP
END
END
rec_id = 'REC1'
READU data FROM f_temp, rec_id LOCKED
CRT 'Lock failure'
STOP
END ELSE NULL
data<-1> = 'A field'
CRT RECORDLOCKED(f_temp, rec_id) ;* 2 - "Locked by this process by a READU"
WRITEU data TO f_temp, rec_id
CRT RECORDLOCKED(f_temp, rec_id) ;* still 2
RELEASE f_temp, rec_id
CRT RECORDLOCKED(f_temp, rec_id) ;* 0 - not locked

note: T24 has its own locking mechanism.

3.133 WRITEV
Write the specific field to a record.

EXECUTE 'DELETE-FILE DATA F.TEMP'


EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'
new_rec = 'Field 1' : @FM : 'Field 2' : @FM : 'Field 3'
WRITE new_rec TO f_temp, 'REC1'
WRITEV 'New field 2' TO f_temp, 'REC1', 2 ON ERROR
CRT 'WRITEV error'
STOP
END
EXECUTE "I-DUMP F.TEMP 'REC1'" ;* "REC1^Field 1^New field 2^Field 3^"
WRITEV 'Field 7' TO f_temp, 'REC1', 7 ON ERROR
CRT 'WRITEV error'
STOP
END
EXECUTE "I-DUMP F.TEMP 'REC1'" ;* REC1^Field 1^New field 2^Field 3^^^^Field 7^

3.134 XLATE()
Get data from a file without opening it explicitly:

* T24 environment is necessary for this sample


BRANCH.ID = 'GB0010001'
CRT DQUOTE(XLATE('F.COMPANY', BRANCH.ID, 1, 'X')) ;* "Model Bank"

REM Page 110


4 jQL
4.1 Introduction
Clauses are common for most commands, e.g. you can use BY both in SELECT and LIST.
In many cases clauses are case-insensitive and have several variants of spelling (the latter can
be illustrated with BY.DSND and BY-DSND).

4.2 LIST
List particular fields:

LIST F.COMPANY COMPANY.NAME MNEMONIC


@ID........ COMPANY.NAME.......... MNEMONIC

GB0010003 R11 MF BRANCH 1 MF2


SG0010001 R11 LEAD SG COMPANY SG1
EU0010001 R11 LEAD CO GERMANY EU1
GB0010002 R11 LEAD MF COMPANY MF1
GB0010004 R11 MF BRANCH 2 MF3
GB0010001 Model Bank BNK

Make a custom column header:

LIST F.COMPANY COMPANY.NAME COL.HDR "Branch name" MNEMONIC


@ID........ Branch name........... MNEMONIC

GB0010003 MF Branch 1 MF2


SG0010001 Model Bank - Singapore SG1
EU0010001 Model Bank - Europe EU1
GB0010001 Model Bank BNK
GB0010002 MF Lead Company MF1
GB0010004 MF Branch 2 MF3

List particular fields (without @id):

LIST F.COMPANY COMPANY.NAME MNEMONIC ID.SUPP


COMPANY.NAME.......... MNEMONIC

R11 MF BRANCH 1 MF2


R11 LEAD SG COMPANY SG1
R11 LEAD CO GERMANY EU1
R11 LEAD MF COMPANY MF1
R11 MF BRANCH 2 MF3
Model Bank BNK

REM Page 111


List @id only:

LIST ONLY F.COMPANY


@ID........

GB0010003
SG0010001
EU0010001
GB0010002
GB0010004
GB0010001

List depending on field contents:

LIST F.COMPANY COMPANY.NAME MNEMONIC WITH MNEMONIC LIKE ...1


@ID........ COMPANY.NAME.......... MNEMONIC

SG0010001 R11 LEAD SG COMPANY SG1


EU0010001 R11 LEAD CO GERMANY EU1
GB0010002 R11 LEAD MF COMPANY MF1

note: Also can use: LIST F.COMPANY COMPANY.NAME MNEMONIC WITH MNEMONIC EQ "[1"
List depending on a field being empty:

LIST ONLY FBNK.CUSTOMER WITH CONTACT.DATE EQ ''


@ID.......

188888
122122
100362
...

note: Also can use: LIST ONLY FBNK.CUSTOMER WITHOUT CONTACT.DATE


Field contents – multiple criteria:

LIST FBNK.ACCOUNT CATEGORY WITH CATEGORY EQ 1002 1004


@ID................ CATEGORY

41017 1002
46396 1004
41475 1002
41947 1002
42137 1002
47058 1004
...

REM Page 112


Usage of AND:

LIST FBNK.ACCOUNT CATEGORY WITH CATEGORY EQ 1002 1004 AND CURRENCY EQ EUR
@ID................ CATEGORY

No Records Listed

Usage of OR:

LIST FBNK.ACCOUNT CATEGORY CURRENCY WITH CATEGORY EQ 1002 1004 OR CURRENCY EQ EUR
@ID................ CATEGORY CURRENCY
...
EUR141850084 14185 EUR
17531 6001 EUR
41947 1002 USD
EUR141850264 14185 EUR
EUR141250001 14125 EUR
42137 1002 USD
...

List particular record:

LIST F.COMPANY 'GB0010001'


@ID................ GB0010001
@ID................ GB0010001
COMPANY.CODE....... GB0010001
COMPANY.NAME....... Model Bank
NAME.ADDRESS....... 18 Place De Philosophes, CH 1205 Geneva, Switzerland
MNEMONIC........... BNK
LANGUAGE.CODE...... 1
...

Alternate way to do that (though it doesn’t always work – the previous example wouldn’t):

LIST F.COMPANY = GB0010001


No Records Listed

LIST F.ENQUIRY = DE.MONITOR


@ID................ DE.MONITOR
@ID................ DE.MONITOR
ENQUIRY............ DE.MONITOR
PAGE.SIZE.......... 4,19
FILE.NAME.......... GUI.DE.MONITOR
...

REM Page 113


List several records:

LIST F.COUNTRY 'DE' 'AN'


@ID................ DE
@ID................ DE
COUNTRY.CODE....... DE
CURRENCY.CODE......
COUNTRY.NAME....... Germany Allemagne Deutschland
SHORT.NAME......... Germany Allemagne Deutsch.
PRESENTATION.CODE..
...
@ID................ AN
@ID................ AN
COUNTRY.CODE....... AN
CURRENCY.CODE......
COUNTRY.NAME....... Netherlands Antilles Antilles
SHORT.NAME......... Neth Ant. Ant. Neerl. Ned.
...

2 Records Listed

List set of records:

LIST F.LOCKING LIKE J...


@ID..... J28445.19980723
@ID..... J28445.19980723
KEY..... J28445.19980723
CONTENT. F.CONVERSION.PGMS G13 F.CONVERSION.PGMS$NAU G13
F.CONVERSION.PGMS$HIS G13;4
REMARK..
...

Use other dictionary:

LIST F.LOCKING LIKE J... USING DICT F.JOURNAL


@ID......... J28445.19980723
@ID......... J28445.19980723
FWT......... F.CONVERSION.PGMS G13 F.CONVERSION.PGMS$NAU G13
F.CONVERSION.PGMS$HIS G13;4
TXN.REF..... G13
APPLICATION. CONVERSION.PGMS
FUNCTION.... A
TIME........ 10:09
DEPT........ 1
USER........ INPUTTER
SIZE........

REM Page 114


COMPANY..... GB0010001
...

Suppress paging:

LIST FBNK.ACCOUNT (N
...
LIST FBNK.ACCOUNT (N PAGE 16275 19:31:57 19 DEC 2011
...
LOCKED.WITH.LIMIT..
LOCK.INC.THIS.MVMT.

1673 Records Listed

Suppress headers:

LIST F.SPF HDR-SUPP

@ID.................. SYSTEM
@ID.................. SYSTEM
SYSTEM.SPEC.......... SYSTEM
RUN.DATE............. 20110330
SITE.NAME............ R11 Model Bank
OP.MODE.............. O
...

Customize page header:

LIST F.SPF HEADING "Page 'P3'"


Page 1
@ID.................. SYSTEM
@ID.................. SYSTEM
SYSTEM.SPEC.......... SYSTEM
RUN.DATE............. 20110330
SITE.NAME............ R11 Model Bank
...
Page 2
BRANCH.ID............
INFO.JOURNAL.........
BROWSER.REC.LOCK..... YES
COMMIT.TIME.OUT......
...

REM Page 115


Calculate totals without showing records:

LIST FBNK.ACCOUNT WITH CURRENCY EQ EUR TOTAL WORKING.BALANCE DET-SUPP


@ID................ WORKING.BALANCE....

*** 25104974.25

199 Records Listed

Calculate average value of a field (again without showing records):

LIST FBNK.ACCOUNT WITH CURRENCY EQ EUR AVERAGE WORKING.BALANCE DET-SUPP


@ID................ WORKING.BALANCE....

*** 126155.6494

199 Records Listed

List particular fields (without knowing their names):

LIST F.COMPANY *A1 *A2 *A3


@ID........ *A1........... *A2........... *A3...........

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

note: Some shortcuts are also available in VOC, see the next screen.

CT VOC F1 F2 F3
F1
001 D

REM Page 116


002 1
003
004
005 15T
006 S

F2
001 D
002 2
003
004
005 13T
006 S

F3
001 D
002 3
003
004
005 13T
006 S

LIST F.COMPANY F1 F2 F3
@ID........ F1............. F2........... F3...........

GB0010003 MF Branch 1 MF Branch 1 MF2


SG0010001 Model Bank - Model Bank - SG1
Singapore Singapore
EU0010001 Model Bank - Model Bank - EU1
Europe Europe
GB0010001 Model Bank 18 Place De BNK
Philosophes,
CH 1205
Geneva,
Switzerland
GB0010002 MF Lead Company MF Lead MF1
Company
GB0010004 MF Branch 2 MF Branch 2 MF3

6 Records Listed

Sorting the output in ascending order:

LIST F.COMPANY *A1 *A2 *A3 BY *A3


@ID........ *A1........... *A2........... *A3...........

GB0010001 Model Bank 18 Place De Ph BNK

REM Page 117


ilosophes,
CH 1205 Geneva
,
Switzerland
EU0010001 Model Bank - E Model Bank - E EU1
urope urope
GB0010002 MF Lead Compan MF Lead Compan MF1
y y
GB0010003 MF Branch 1 MF Branch 1 MF2
GB0010004 MF Branch 2 MF Branch 2 MF3
SG0010001 Model Bank - S Model Bank - S SG1
ingapore ingapore

Sorting the output in descending order:

LIST F.COMPANY *A1 *A2 *A3 BY.DSND *A3


@ID........ *A1........... *A2........... *A3...........

SG0010001 Model Bank - S Model Bank - S SG1


ingapore ingapore
GB0010004 MF Branch 2 MF Branch 2 MF3
GB0010003 MF Branch 1 MF Branch 1 MF2
GB0010002 MF Lead Compan MF Lead Compan MF1
y y
EU0010001 Model Bank - E Model Bank - E EU1
urope urope
GB0010001 Model Bank 18 Place De Ph BNK
ilosophes,
CH 1205 Geneva
,
Switzerland

Formatting the output to make it more readable:

LIST F.COMPANY *A1 FMT "25L" *A2 FMT "25L" *A3 FMT "3R"
@ID........ *A1...................... *A2...................... *A3

GB0010003 MF Branch 1 MF Branch 1 MF2


SG0010001 Model Bank - Singapore Model Bank - Singapore SG1
EU0010001 Model Bank - Europe Model Bank - Europe EU1
GB0010001 Model Bank 18 Place De Philosophes, BNK
CH 1205 Geneva,
Switzerland
GB0010002 MF Lead Company MF Lead Company MF1
GB0010004 MF Branch 2 MF Branch 2 MF3

REM Page 118


CNV keyword allows conversion. Adding dashes to company code:

LIST F.COMPANY ID.SUPP @ID CNV "ML& ##-###-####" FMT "12L" *A1 FMT "25L"
@ID......... *A1......................

GB-001-0003 MF Branch 1
SG-001-0001 Model Bank - Singapore
EU-001-0001 Model Bank - Europe
GB-001-0001 Model Bank
GB-001-0002 MF Lead Company
GB-001-0004 MF Branch 2

Another CNV example – list only amounts that fall into certain range:

LIST FBNK.ACCOUNT WITH CURRENCY EQ USD CURRENCY WORKING.BALANCE CNV "R1000,10000"


@ID................ CURRENCY WORKING.BALANCE....
...
41785 USD
USDPHP190220001 USD 9261.4
14966 USD
41386 USD 5000
24422 USD
41912 USD
41289 USD
44598 USD 5000
40193 USD
...

List size of records:

LIST F.COMPANY *A9999


@ID........ *A9999........

SG0010001 2071
GB0010003 2063
EU0010001 2071
GB0010002 2068
GB0010004 2062
GB0010001 2163

Usage of EVERY clause:

LIST FBNK.FUNDS.TRANSFER INPUTTER WITH INPUTTER UNLIKE ...CONV...


FT10221S4V81 9605_BUILDUSER86_I_INAU
3883_CONVERSION.DETAILS
FT102217DKNB 75_SUJA1_I_INAU_OFS_BROWSERTC

REM Page 119


3883_CONVERSION.DETAILS
FT10221SR3TJ 5169_SEAT.USER_I_INAU_OFS_SEAT
FT10221R2LM9 5169_SEAT.USER_I_INAU_OFS_SEAT
...

LIST FBNK.FUNDS.TRANSFER INPUTTER WITH EVERY INPUTTER UNLIKE ...CONV...


FT10221SR3TJ 5169_SEAT.USER_I_INAU_OFS_SEAT
FT10221R2LM9 5169_SEAT.USER_I_INAU_OFS_SEAT
FT10221SSFX3 37_BUILDUSER8149_I_INAU_OFS_BROWSERTC
FT1022148L5W 64_INPUTTER_I_INAU_OFS_FT.BULK.PROCESS
FT10221PMDPX 402_INPUTTER_I_INAU_OFS_FT.BULK.PROCESS
...

Usage of BY.EXP clause:

LIST F.VERSION 'AM.MATRIX,HDG' INPUT.ROUTINE


@ID........... AM.MATRIX,HDG
INPUT.ROUTINE. V.BLS.AM.MAT.HDG.CHECK.RECORD V.BLS.AM.MAT.NEW.AXIS.HDG
V.BLS.AM.MAT.UPD.AXIS.HDG

LIST F.VERSION 'AM.MATRIX,HDG' INPUT.ROUTINE BY-EXP INPUT.ROUTINE


@ID........... AM.MATRIX,HDG
INPUT.ROUTINE. V.BLS.AM.MAT.HDG.CHECK.RECORD

@ID........... AM.MATRIX,HDG
INPUT.ROUTINE. V.BLS.AM.MAT.NEW.AXIS.HDG

@ID........... AM.MATRIX,HDG
INPUT.ROUTINE. V.BLS.AM.MAT.UPD.AXIS.HDG

3 Records Listed

Another BY.EXP example:

LIST FBNK.ACCT.ACTIVITY WITH DAY.NO EQ 11 DAY.NO TURNOVER.CREDIT BY-EXP DAY.NO


@ID............................................... DAY.NO TURNOVER.CREDIT
...
USD128000003-201103 10 137012
USD128000003-201104 10
USD140200001-201104 10 576.81
USD147000001-201104 10
CHF141850049-201103 11 19691.35
CHF147000001-201103 11 80000
CHFUSD140160001-201103 11 153198.24
CHFUSD140180001-201103 11
10596-201103 11 8000
10693-201103 11 1189518

REM Page 120


10707-201103 11 17180
...

BREAK-ON examples:

SORT FBNK.ACCOUNT WITH *A1 NE '' BY *A1 BREAK-ON *A1


@ID................ *A1...........

42398 100100
42428 100100
42439 100100
...
***

45028 100101
45039 100101
45055 100101

***

47791 100105
...

SORT FBNK.ACCOUNT WITH *A1 NE '' BY *A1 BREAK-ON "-----------" *A1


@ID................ *A1...........

42398 100100
42428 100100
42439 100100
...
-----------

45028 100101
45039 100101
45055 100101

-----------

47791 100105
...

LIST FBNK.COLLATERAL BY CURRENCY TOTAL NOMINAL.VALUE BREAK-ON CURRENCY DET-SUPP


@ID............... NOMINAL.VALUE...... CURRENCY

456014.62 GBP
11448663.27 USD
===================

REM Page 121


*** 11904677.89

51 Records Listed

Adding pounds to dollars doesn’t make sense of course. Here we’ll calculate the local amounts
and sum them up (sometimes I wish there would be a line continuation character in jQL – 4
lines’ worth of symbols are to be input in one line of course).
Note: we omit only the empty QUOTATION.CODE support.

LIST FBNK.ACCOUNT WITH CURRENCY NE USD AND WORKING.BALANCE GT 0 EVAL


"FMT(WORKING.BALANCE*OCONV(CURRENCY,'TFBNK.CURRENCY;V1;14;14')
/10**OCONV(CURRENCY,'TFBNK.CURRENCY;V;5;5'),'R2')"
AS LOCALAMT TOTAL LOCALAMT HDR-SUPP DET-SUPP

@ID................ LOCALAMT........... LOCALAMT...........

*** 30092437288.71

119 Records Listed

Here the totals are calculated every 10 records:

LIST FBNK.COLLATERAL HDR-SUPP WITH CURRENCY EQ USD BY.DSND NOMINAL.VALUE


EVAL "OCONV(NOMINAL.VALUE, 'A;NI')" COL.HDR "#" TOTAL NOMINAL.VALUE
BREAK-ON EVAL "INT(OCONV(NOMINAL.VALUE, 'A;NI')/10)" COL.HDR "CTRL"
@ID............... #.................. NOMINAL.VALUE...... CTRL...............

100315.4.1 1 1188250.00 0
100291.1.1 2 959013.27 0
100317.1.1 3 750000.00 0
100344.1.1 4 677000.00 0
120019.1.1 5 563000.00 0
120014.1.1 6 559000.00 0
120016.1.1 7 559000.00 0
120006.1.1 8 530000.00 0
100332.1.1 9 471000.00 0
111419.1.1 10 370000.00 1

6626263.27 ***

100315.6.1 11 365000.00 1
100327.1.1 12 353000.00 1
100361.1.1 13 353000.00 1
100395.1.1 14 306000.00 1
111747.1.1 15 290000.00 1
100396.1.1 16 224000.00 1

REM Page 122


100345.1.1 17 165000.00 1

@ID............... #.................. NOMINAL.VALUE...... CTRL...............

120012.1.1 18 165000.00 1
100378.1.1 19 153000.00 1
100805.1.1 20 150000.00 2

2524000 ***

100372.1.1 21 124000.00 2
100310.1.1 22 118000.00 2
100315.9.1 23 117700.00 2
120110.1.1 24 107000.00 2
100272.1.1 25 106000.00 2
100346.1.1 26 106000.00 2
100107.1.1 27 100000.00 2
100283.8.1 28 100000.00 2
100283.9.1 29 100000.00 2
100297.1.1 30 100000.00 3

1078700 ***
...

SORT FBNK.ACCOUNT WITH *A1 NE '' BY *A1 BREAK-ON " 'U' " *A1
@ID................ *A1...........

42398 100100
42428 100100
42439 100100
...

45028 100101
45039 100101
45055 100101

47791 100105
...

note: Not sure what ’U’ means here... supposed to be “underline”.


Adding the data line number to the previous example:

SORT FBNK.ACCOUNT WITH *A1 NE '' BY *A1 BREAK-ON " 'U' " *A1 *A9998
@ID................ *A1........... *A9998........

REM Page 123


42398 100100 1
42428 100100 2
42439 100100 3
42692 100100 4
43451 100100 5
...
45028 100101 21
45039 100101 22
45055 100101 23

47791 100105 24
48194 100105 25
...
47635 188888 1078

28298 555555 1079

1079 Records Listed

4.3 SELECT
Prepare a list for DL.DEFINE:

SELECT F.ABBREVIATION SAVING EVAL "'ABBREVIATION>':@ID"

Using current SELECT list to select another file, e.g.: see how many T24 accounts have
history:

SELECT FBNK.ACCOUNT$HIS SAVING UNIQUE EVAL "FIELD(@ID,';',1)"

232 Records selected

>SELECT FBNK.ACCOUNT (R

214 Records selected

note: “(R” suppresses error messages “202 ** Record is not on file”.


If the first SELECT in the example above results in none records being selected, the second
SELECT takes all records in the file. To avoid that add REQUIRE.SELECT clause to the
second SELECT, e.g.:
Before:

SELECT FBNK.ACCOUNT$HIS LIKE 123... SAVING UNIQUE EVAL "FIELD(@ID,';',1)"

No Records selected

REM Page 124


SELECT FBNK.ACCOUNT (R

1691 Records selected

After:

SELECT FBNK.ACCOUNT$HIS LIKE 123... SAVING UNIQUE EVAL "FIELD(@ID,';',1)"

No Records selected

SELECT FBNK.ACCOUNT REQUIRE.SELECT (R

!!! Error message A Select list was required and not supplied.
not found !!!

Save a value of a field, method 1:

SELECT FBNK.STMT.ENTRY SAVING EVAL "@ID:'*':ACCOUNT.NUMBER"

Result:

155520547050531.030001*28169
155440192725431.090002*45691
155710780457593.020002*34638
155720675739306.000001*14265
157740260025724.000002*47546
155650497154461.020002*46598
155520742538909.170001*USD145550001
...

Save a value of a field, method 2:

SELECT FBNK.STMT.ENTRY @ID ACCOUNT.NUMBER

Result:

155520547050531.030001
28169
155440192725431.090002
45691
155710780457593.020002
34638
155720675739306.000001

REM Page 125


14265
157740260025724.000002
47546
155650497154461.020002
46598
155520742538909.170001
USD145550001
...

Create an OFS message – good replacement for EBS.AUTO.FUNCTION:

SELECT FBNK.FUNDS.TRANSFER$NAU WITH RECORD.STATUS EQ INAU


SAVING EVAL "'FUNDS.TRANSFER,/A/PROCESS//0,INPUTT/123456,':@ID"

note: Then put the saved list to batch file listener input folder or copy/paste to tSS.
Get 10 top balances on accounts. Wrong:
hhhh (((
hhhh
( (( (((
hhhh (
hhh (((
hhhh (( ((((
(
SELECT FBNK.ACCOUNT WITH CURRENCY
( ((EQ
h(h(EUR
h(hhBY.DSND
hhh WORKING.BALANCE SAMPLE 10
(( ( ( hhhh
(( ( hhh
( ( hhhh
>LIST ( ( (((
FBNK.ACCOUNT WORKING.BALANCE hhh
((( hh

@ID................ WORKING.BALANCE....

EURUSD190220006 4000000
40339 14209.92
EUR165050006 5000
14087
46213
53015
EUR150050001
46205 -28351.31
EUR144410001 -54551.98
EUR141570002 -58000

10 Records Listed

Get 10 top balances on accounts. Right:

SELECT FBNK.ACCOUNT WITH CURRENCY EQ EUR BY.DSND WORKING.BALANCE

>SELECT FBNK.ACCOUNT BY.DSND WORKING.BALANCE SAMPLE 10

>LIST FBNK.ACCOUNT WORKING.BALANCE


@ID................ WORKING.BALANCE....

REM Page 126


36668 46830634.32
EURUSD190220007 8775163.4
EURUSD190220006 4000000
43184 2500000
EURUSD190220002 2352941.18
EUR140102100 1412992
EUR144410008 1389492.61
EUR144410002 1312495.01
23938 1168152.61
EUR141970001 1023416.9

10 Records Listed

Sample with BY-EXP-DSND (digits at the end of each list entry represent the value number):

SELECT F.VERSION WITH INPUT.ROUTINE NE '' BY-EXP-DSND INPUT.ROUTINE

>SAVE.LIST QWE

EDIT.LIST QWE
.P
001 AC.ACCOUNT.OPENING,INPUT.PW.JOINT]1
002 SEC.OPEN.ORDER,MIFID]1
003 SEC.OPEN.ORDER,MIFID.INPUT]1
004 SEC.TRADE,MIFID]1
005 SEC.TRADE,MIFID.INPUT]1
006 SEC.OPEN.ORDER,MIFID.INPUT]2
007 SEC.TRADE,MIFID.INPUT]2
008 EB.LENDING.HP,RETAIL.LENDING]1
...
.EXIT

4.4 SSELECT
What doesn’t make sense since SSELECT sorts by @id:
h ((
BYh
SSELECT F.COMPANY ( (MNEMONIC
h
(h(h(
hh

4.5 NSELECT
Returns records in specified (or default) select list that do not present in a file specified. E.g.:
get unauthorised ACCOUNT records that were never authorised before:

SELECT FBNK.ACCOUNT$NAU

REM Page 127


6 Records selected

>NSELECT FBNK.ACCOUNT

5 Records selected

>

If there’s no default select list, NSELECT asks for it:

SELECT FBNK.ACCOUNT$NAU TO 9

6 Records selected

NSELECT FBNK.ACCOUNT
Input list name 9
5 Records selected

>

4.6 XSELECT
“Reverses” a SELECT:

COUNT F.COMPANY

6 Records counted

SELECT F.COMPANY LIKE ...3

1 Records selected

>XSELECT F.COMPANY

5 Records selected

>

4.7 BSELECT
Put all fields of a file into SELECT list:

BSELECT FBNK.ACCOUNT

356505 Records selected

REM Page 128


>SAVE.LIST QWE

EDIT.LIST QWE
.P
TOP
001 EUR141850743
002 EUR141850743
003
004 14185
005 RECORD.AUTOMATICALLY.OPENED
006 RECORD.AUTOMATICALLY.OPENED
007 RECORD.AUTOMATICALLY.OPENED
008
009 TR
010 EUR
011 1
...

note: Makes sense with files like FBNK.ACCT.ENT.TODAY.


Same as above – counters of processed records are displayed (default - every 500 records):

BSELECT FBNK.ACCOUNT (C
...
Processed '500' Selected '500'
Processed '1000' Selected '1000'
...
Processed '1673' Selected '1673'
356505 Records selected

Put some fields of a file into SELECT list:

BSELECT FBNK.ACCOUNT @ID CATEGORY CURRENCY

5019 Records selected

>SAVE.LIST QWE

EDIT.LIST QWE
.P
TOP
001 EUR141850743
002 14185
003 EUR
004 14095
005 1001
006 GBP

REM Page 129


007 14087
008 1001
009 EUR
...

4.8 EVAL
Using EVAL as a calculator...

LIST . SAMPLE 1 EVAL "2*2"

DICT ......... 2*2.......

$FT-PART-ALGO 4

1 Records Listed

...or to check some jBC functionality:

LIST . SAMPLE 1 EVAL "FMT(123, 'R%5')"


00123

LIST . SAMPLE 1 EVAL "ABS(-12)"


12

LIST . SAMPLE 1 EVAL "COUNT(-12:@FM:5:@FM:-7, @FM)"


2

The following doesn’t work as expected though...

LIST . SAMPLE 1 EVAL "ABSS(-12:@FM:5:@FM:-7)"


12
0
0

...or doesn’t work at all...


LIST . SAMPLE 1 EVAL "ABS(-12.2)"
Error in Statement "LIST . SAMPLE 1 EVAL "ABS(-12.2)""
Error in attribute definition item ABS(-12.2)
Error in Itype: unexpected char: '.'

...until being rephrased:

LIST . SAMPLE 1 EVAL "ABS('-12.2')"


12.2

REM Page 130


But sometimes even that doesn’t help...

LIST . SAMPLE 1 EVAL "DROUND('123.45',0)"


Error in Statement "LIST . SAMPLE 1 EVAL "DROUND('123.45',0)""
Error in attribute definition item DROUND('123.45',0)
Error in Itype:
Cannot locate Basic subroutine DROUND

...but sometimes still can be overridden:

LIST ONLY FBNK.ACCT.ACTIVITY WITH EVAL "RIGHT(@ID,6)[1,4]" EQ 2008


Error in Statement
"LIST ONLY FBNK.ACCT.ACTIVITY WITH EVAL "RIGHT(@ID,6)[1,4]" EQ 2008"
Error in attribute definition item RIGHT(@ID,6)[1,4]
Error in Itype:
Cannot locate Basic subroutine RIGHT

LIST ONLY FBNK.ACCT.ACTIVITY WITH EVAL "SUBSTRINGS(@ID,LEN(@ID)-5,4)" EQ 2008


@ID...............................................

GBP141850768-200802
GBP141850768-200812
15393-200801
USD140550220-200803
USD140550220-200811
...

Some jBC functions might look redundant but are useful for EVAL:

LIST . SAMPLE 1 EVAL "(-12:@FM:5:@FM:-7)<2>"


Error in Statement "LIST . SAMPLE 1 EVAL "(-12:@FM:5:@FM:-7)<2>""
Error in attribute definition item (-12:@FM:5:@FM:-7)<2>
Error in Itype: expecting EOF, found '>'

LIST . SAMPLE 1 EVAL "EXTRACT(-12:@FM:5:@FM:-7, 2)"


5

Extraction of characters works...

LIST . SAMPLE 1 EVAL "'ABCDEFXYZ'[2,3]"


BCD

LIST . SAMPLE 1 EVAL "'ABCDEFXYZ'[3]"


XYZ

REM Page 131


...as well as field():

LIST . SAMPLE 1 EVAL "FIELD('ABC/DEF/XYZ', '/',2)"


DEF

Another field() example – see at what system date a forward accounting entry was gener-
ated:

LIST FBNK.STMT.ENTRY LIKE F... EVAL "OCONV(@ID['.',2,1][1,5],'D')"


@ID.......................... F20110414.15826077544910414
OCONV(@ID[".",2,1][1,5],"D"). 30 APR 2011

@ID.......................... F20110414.15826077544910428
OCONV(@ID[".",2,1][1,5],"D"). 30 APR 2011

@ID.......................... F20110415.15825031964301106
OCONV(@ID[".",2,1][1,5],"D"). 29 APR 2011
...

Also don’t forget that fields can be used in evaluations:

LIST F.OFS.REQUEST.DETAIL EVAL "FIELD(FIELD(MSG.OUT,'INPUTTER:1:1=',2),',',1)"


@ID........................................... SCRPT11061000073-05-I
FIELD(FIELD(MSG.OUT,"INPUTTER:1:1=",2),",",1). 4423_SEAT.USER_I_INAU_OFS_SEAT

@ID........................................... SCRPT11062000160-I
FIELD(FIELD(MSG.OUT,"INPUTTER:1:1=",2),",",1). 4964_SEAT.USER_I_INAU_OFS_SEAT

Some comparisons:

LIST FBNK.AA.PRODUCT.MANAGER PROCESS.STATUS AVAILABLE.DATE


EVAL "AVAILABLE.DATE EQ 20110311"
@ID........................ PROXY.PERMISSION
PROCESS.STATUS............. COMPLETED SUCESSFULLY
AVAILABLE.DATE............. 20110311
AVAILABLE.DATE EQ 20110311. 1

@ID........................ C.FIXED.PLACEMENT
PROCESS.STATUS............. COMPLETED SUCESSFULLY
AVAILABLE.DATE............. 20110311
AVAILABLE.DATE EQ 20110311. 1
...
@ID........................ TD.PARENT
PROCESS.STATUS............. COMPLETED SUCESSFULLY
AVAILABLE.DATE............. 20110309

REM Page 132


AVAILABLE.DATE EQ 20110311. 0

@ID........................ CURRENT.PARENT
PROCESS.STATUS............. COMPLETED SUCESSFULLY
AVAILABLE.DATE............. 20110309
AVAILABLE.DATE EQ 20110311. 0

Using EVAL for breaks:

LIST FBNK.ACCOUNT WITH CURRENCY EQ USD TOTAL WORKING.BALANCE BY OPENING.DATE


BREAK.ON EVAL "OPENING.DATE[1,4]" DET-SUPP
@ID................ WORKING.BALANCE.... OPENING.DATE[1,4

10497824.8 1998
-958489.37 2007
18248067.18 2008
-15850 2010
-9927303.88 2011
===================
*** 17844248.73

Simple EVAL...AS example:

LIST FBNK.ACCOUNT EVAL "'USD'" AS LOCAL.CCY WITH CURRENCY EQ LOCAL.CCY


@ID................ LOCAL.CCY.

USD140300001 USD
USD141850990 USD
42218 USD
USDCHF140180001 USD
...

One more EVAL...AS example that saves some typing:

LIST FBNK.ACCOUNT WITH MNEMONIC NE '' EVAL "MNEMONIC:':':SHORT.TITLE" AS SORTING


FMT "45L" BY SORTING
@ID................ SORTING......................................

USD122150001 AADEPTAX:AA Deposit Tax receivable


GBP122150001 AAGBPTAX:AA Deposit Tax receivable
USD147000001 AASUSPENSE:AA Suspense Transactions
41556 ABNNOSTRO:ABN Amro USD Nostro
40525 ABUDHAUSD1:ABUDHAOIL MG DD AC
15288 ABUOIL1:ABU DHABI NATIONAL OIL COMPANY
...

REM Page 133


My record-breaking query (317 characters) which outputs other parties for AA retail loans
as semicolon-delimited report (Alt.acct ID; customer ID; role):

LIST FBNK.AA.ARR.CUSTOMER WITH EVAL "FIELD(OCONV(FIELD(@ID,'-',1),


'TFBNK.AA.ARRANGEMENT;V;10;10'),'.',1)" EQ 'RETAIL' AND OTHER.PARTY
NE '' BY.EXP OTHER.PARTY EVAL "OCONV(OCONV(FIELD(@ID,'-',1),
'TFBNK.AA.ARRANGEMENT;V;8;8'),'TFBNK.ACCOUNT;V1;100;100'):';'
:OTHER.PARTY:';':ROLE" FMT "45L" HDR-SUPP COL-HDR-SUPP ID.SUPP

8888674688;77481;GUARANTOR
8888512388;77020;GUARANTOR
8888599888;77162;GUARANTOR
8888169488;77261;GUARANTOR
8888574188;77424;CO-SIGNER
8888574188;77435;CO-SIGNER
8888286188;77445;GUARANTOR
8888554888;77641;GUARANTOR
8888599488;77828;GUARANTOR
8888086088;77932;GUARANTOR
8888099688;77127;CO-SIGNER
8888762988;77127;GUARANTOR
8888521888;77142;GUARANTOR
...

Trying to do it with SELECT resulted in something like:

8888674688;777446;GUARANTOR]77481;GUARANTOR
8888512388;77020;GUARANTOR
8888599888;779100;GUARANTOR]77162;GUARANTOR]777740;GUARANTOR
8888169488;77261;GUARANTOR]777365;CO-SIGNER
8888574188;777304;GUARANTOR]77424;CO-SIGNER]77435;CO-SIGNER

... so – COMO ON, LIST, COMO OFF, remove COMO header and footer in editor... that’s
it.

4.9 Manipulations with lists


SAVE.LIST/GET.LIST. Obvious – save a SELECT list for future use and retrieve it later.
SORT-LIST. Sorts a saved list. Makes sense if you save something other than @id – it might
be faster than using “BY EVAL "something"”.

SELECT FBNK.ACCOUNT SAVING UNIQUE EVAL "SHORT.TITLE"

915 Records selected

>SAVE.LIST AC.TITLE

REM Page 134


915 record(s) saved to list 'AC.TITLE'

SORT-LIST AC.TITLE
List 'AC.TITLE' sorted with 915 records

EDIT.LIST AC.TITLE
.jBASE.el.1
TOP
.P
TOP
001 Aa Dep Tax
002 AA Dep Tax
003 Aa Suspense Transactions
004 AA Suspense Transactions
005 Abn Amro Usd Nostro
006 Abu Dhabi National Oil Company
007 Abudhaoil Mg Dd Ac
...

Remove duplicates while sorting:

SELECT FBNK.ACCOUNT SAVING CUSTOMER


1673 Records selected

>SAVE.LIST QWE
1673 record(s) saved to list 'QWE'
SORT.LIST QWE (U
List 'QWE' sorted with 239 records

AND-LISTS. Get common part of two lists. E.g. find if any unauthorised record in AC-
COUNT was authorised before:

SELECT FBNK.ACCOUNT$NAU
2 Records selected

>SAVE.LIST LIST1
2 record(s) saved to list 'LIST1'

SELECT FBNK.ACCOUNT
1673 Records selected

>SAVE.LIST LIST2
1673 record(s) saved to list 'LIST1'

AND-LISTS LIST1 LIST2


No Records selected

REM Page 135


OR-LISTS. Quite the opposite – get all records that present at least in one of specified lists.
So we can combine lists, at the same time avoiding duplicates:

OR-LISTS LIST1 LIST2


1675 Records selected
>SAVE.LIST LIST3
1675 record(s) saved to list 'LIST3'

OR-LISTS LIST1 LIST3


1675 Records selected

XOR-LISTS. Records that present in one list but not in the other and vice versa in the
resulting SELECT.

XOR-LISTS LIST2 LIST3


2 Records selected

note: Performance isn’t very good so avoid comparing big lists.

4.10 Other jQL stuff


Copy a record (for example, from hashed file to a directory):

COPY FROM F.OFS.REQUEST.DETAIL TO &TEMP& MIGR103340170349090.15

Copy that record back (e.g. after manual editing) overwriting the target:

COPY FROM &TEMP& TO F.OFS.REQUEST.DETAIL MIGR103340170349090.15 OVERWRITING

Copy all records:

COPY FROM F.COMPANY TO &TEMP& ALL


6 records copied

LIST &TEMP&

EU0010001
GB0010001
GB0010002
GB0010003
GB0010004
SG0010001

REM Page 136


“Dump” a record:

I-DUMP F.SPF 'SYSTEM'


SYSTEM^20110330^R11 Model Bank^O^^../bnk.data^^^201107^1^^^200^^TAPE^Y^N^5^^../
bnk.data^../bnk.run^../bnk.dict^^NT^./backup.hd &M&^./restore.hd &M&^^5^500^^20
1106^^10^^^BEF]ESP]ITL]JPY]PTE]KWD]XAU]XAG^EURGBTMNS000^20120531^^AA]AB]AC]AD]A
I]AL]AM]AP]AR]AS]BE]BL]BM]BR]CM]CO]CR]DC]DD]DE]DM]DW]DX]EB]ET]EU]FD]FR]FT]FX]GP
]IA]IB]IC]IM]LC]LD]LI]LM]MC]MD]MF]MM]MO]MS]NR]NS]OF]OO]OP]OV]PC]PD]PM]PV]PW]RE]
RP]SA]SB]SC]SE]SG]SL]SP]ST]SW]SY]TK]TT]TV]TX]WR]WS]XT^^Y^N^500^^^^^^1^^^^^^^^^^
^^^^^YES^^^^^^^^^^^^^^^^^3^2097_VLADIMIR.K^1111301249^2097_VLADIMIR.K^GB0010001
^1^

Count records in a file:

COUNT FBNK.ACCOUNT

1673 Records counted

COUNT FBNK.ACCOUNT WITH CATEGORY EQ 1001

460 Records counted

Delete records:

DELETE F.OFS.MESSAGE.QUEUE
Record Keys : *
54 record(s) deleted.

LIST &COMO&

QWERTY
tSA_15_20120123_22-28-57
tSA_15_20120123_22-35-41
tSA_54_20120123_22-28-58
tSA_54_20120123_22-35-42
tSA_55_20120123_22-28-59
tSA_55_20120123_22-35-43

SELECT &COMO& LIKE tSA...


6 Records selected

>DELETE &COMO&
6 record(s) deleted.

DELETE &COMO& QWERTY


1 record(s) deleted.

REM Page 137


Statistics on record and (supposedly) field sizes:

STAT F.COMPANY
Statistics of record length :
total = 13854 average = 2309 count = 6

STAT F.COMPANY *A1


Statistics of *A1 :
total = 0 average = 0 count = 6

LIST F.COMPANY *A1


@ID........ *A1...........

GB0010003 MF Branch 1
SG0010001 Model Bank - S
ingapore
EU0010001 Model Bank - E
urope
GB0010001 Model Bank
GB0010002 MF Lead Compan
y
GB0010004 MF Branch 2

Measuring the performance of, e.g., SELECT:

time SELECT FBNK.STMT.ENTRY


3212135 Records selected

usr: 109.29 sys: 0.00 elapsed: 1m49.28s


>

REM Page 138


Getting difference between 2 lists stored in a file:

dyn_array_1 = 100 :@FM: 200 :@FM: 300 :@FM: 400


dyn_array_2 = 150 :@FM: 200 :@FM: 350 :@FM: 450

OPEN 'F.TEMP' TO f_temp ELSE


EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'
END

WRITE dyn_array_1 TO f_temp, 'REC1'


WRITE dyn_array_2 TO f_temp, 'REC2'
DATA 'REC2'
EXECUTE 'DIFF-LIST F.TEMP REC1 TO DIFF'
GETLIST 'DIFF' TO diff ELSE STOP
CRT FMT(diff, 'MCP') ;* 100^300^400
;* (those that are in REC1 and not in REC2)
DATA '(F.TEMP REC1'
EXECUTE 'DIFF-LIST F.TEMP REC2'
LOOP
READNEXT next_id ELSE EXIT ;* result is in default list
CRT next_id : ':' : ;* 150:350:450:
REPEAT ;* (those that are in REC2 and not in REC1)

List dictionary item:

LISTDICT FBNK.ACCOUNT 'CUSTOMER'

*A0........... D/CODE... A/AMC.... S/NAME... V/CONV... V/CORR... V/TYPE... V/MAX

CUSTOMER D 1 CUSTOMER R 10

LISTDICT FBNK.ACCOUNT 'ADI.ID'

*A0........... D/CODE... A/AMC.... S/NAME... V/CONV... V/CORR... V/TYPE... V/MAX

ADI.ID I SUBR("AC. ADI.ID L 25


GET.CRDR.
ID","DR",
ACCT.ID)

5 Environment variables
There are variables that are used by jBASE/T24; some of them are their own, others are
OS-specific.
Warning: some of these variables might be temporary or strictly for internal use. Descriptions
are for your information only!

REM Page 139


Minimum set of variables necessary to start TAFC

Windows:

set TAFC_HOME=[path to installed TAFC]


set JBCGLOBALDIR=%TAFC_HOME%
set PATH=%TAFC_HOME%\bin;%PATH%

note: If you don’t set JBCBASETMP – “$HOME” directory will be created for this purpose.
Unix/Linux:

export TAFC_HOME=[path to installed TAFC]


export JBCGLOBALDIR=$TAFC_HOME
export PATH=$TAFC_HOME/bin:$PATH

export LD_LIBRARY_PATH=$TAFC_HOME/lib:/usr/ccs/lib:/usr/lib:/lib
(Linux)

export LIBPATH=$TAFC_HOME/lib:/usr/ccs/lib:/usr/lib
(AIX)

export SHLIB_PATH=$TAFC_HOME/lib:${SHLIB_PATH:-/usr/lib:/lib}
(HP-UX)

note: For jBASE 5 and earlier use variable JBCRELEASEDIR instead of TAFC HOME.
The following environment variables are sorted alphabetically (excluding underscores).

CLASSPATH

Used in T24 environment to point to multiple extensions written in Java, such as e-mail or
SMS carriers.

DRIVER_HOME

Setting for DBMS-based system.

INCLUDE

If sources compilation is to be done – needs to contain include subfolder of Visual C folder


(for Windows; other platforms have their own folders).

JAVA_HOME

Used for CALLJ (many core subroutines use it).

REM Page 140


JBASE_CODEPAGE

Directs how data is displayed (e.g. utf8, windows-1251 etc).

JBASE_DEBUG_PIPE

Being set to 1 allows debugging under TC Server.

JBASE_DISABLE_NEW_PHANTOM

Setting it to 1 helps to avoid appearance of defunct background processes (agents).

JBASE_DISTRIB_FASTSCAN

Setting it to 1 is reported to improve performance when distributed files are used.

JBASE_ERRMSG_DIVIDE_BY_ZERO

Allows to suppress error messages and/or a program entering the debugger when divide by
zero is encountered.
note: My personal recommendation of its value for development: 0.

JBASE_ERRMSG_NON_NUMERIC

Allows to suppress error messages and/or a program entering the debugger when non-numeric
variable is used in an equation.
note: My personal recommendation of its value for development: 0.

JBASE_ERRMSG_ZERO_USED

Allows to suppress error messages and/or a program entering the debugger when uninitialized
variable is used in an equation.
note: My personal recommendation of its value for development: 0.

JBASE_I18N

Being set to 1 means utf-8 environment (requires files conversion when changed).

JBASE_INHIBIT_ZERO_USED

Seen being set to 1.

REM Page 141


JBASE_IPC_LOCAL

Seen being set to 1.

JBASE_JBCOBJECTLIST_DIR

Being set to 1 makes jBASE understand that the folder t24lib contains T24 subroutines
that are distributed into subdirectories.

JBASE_LOCALE

Usually en US.

JBASE_NOCOLLATION

Turns off icu collation handling for compares, locates, sorts etc (according to jBASE Knowl-
edgebase).

JBASE_PATH

Makes jBASE understand that the folder being set in this variable (usually t24bin) contains
T24 programs that are distributed into subdirectories.

JBASE_TIMEZONE

E.g. Europe/London.

JBASE_USE_INTERNAL_TXN_CACHE

Seen being set to 1.

JBASE_WARNLEVEL

Obsolete; use instead JBASE ERRMSG DIVIDE BY ZERO etc.

JBCBASETMP

Sets location of temporary file(s):

set JBCBASETMP=%HOME%\tmp_workfile
export JBCBASETMP=$HOME/jBASEWORK/tmp_$TTYNO

JBC_CCOMPILER_PATH, JBC_SHAREDIDE_PATH

Not needed if PATH, INCLUDE and LIB are set properly (not sure about Temenos Toolbox
though).

REM Page 142


JBC_CORE_DUMP

Being set to 1 causes creation of a core dump when the session crashes.

JBCDEV_BIN

Where programs will be put after compilation.

JBCDEV_LIB

Where subroutines will be put after compilation.

JBCEMULATE

Should be set to prime in all T24 environments.

JBCGLOBALDIR

Usually is set to be the same as TAFC HOME.

JBCJVMLIB

Seen being set to:

set JBCJVMLIB=%JAVA_HOME%\jre\bin\client\jvm.dll
export JBCJVMLIB=$JAVA_HOME/jre/bin/classic/libjvm.so

JBCLISTFILE

Points to folder with saved lists, e.g.:

set JBCLISTFILE=%HOME%\^&SAVEDLISTS^&
export JBCLISTFILE=$HOME/\&SAVEDLISTS\&

note: &SAVEDLISTS& is sometimes hardcoded so if your setting is different, beware!

JBCOBJECTLIST

Where to look for libraries containing compiled subroutines. Could be several entries, e.g.:

set JBCOBJECTLIST=%HOME%\lib;%HOME%\t24lib
export JBCOBJECTLIST=$HOME/lib:$HOME/t24lib

note: If there are duplicates of a subroutine, what’s the earlier gets priority.

REM Page 143


JBCPORTNO

Range of ports available for jBASE sessions, e.g. 1000-2000.

JBCPROCDIR

Setting for “Multiple application servers” environment.

JBCSPOOLERDIR

Where spooler directory is located. It’s a good idea to have a separate directory for each
T24 environment.

JBC_STDERR

Being set to 1 redirects stderr to stdout. Useful to catch errors during COB.

JBC_TELNET_FLAG

Being set to 1 reportedly prevented T24 from committing any transaction from Browser in
Windows environment.

JBC_UNLOCK_LASTCLOSE

Set JBC UNLOCK LASTCLOSE=1 to ensure locks are not released upon subroutine termi-
nation (according to jBASE Knowledgebase).

JDIAG

Sets jBASE tracing options, e.g.:

set JDIAG=trace=JVM,CALLJ
set JDIAG=TRACE=INDEX

JEDI_DISTRIB_DEFOPEN

Being set to 1 prevents all parts of a distributed file to be opened as soon as the stub had
been.

JEDIENABLEQ2Q

Allows a chain in Q-pointers resolution.

JEDIFILENAME_MD

Usually points to VOC.

REM Page 144


JEDIFILENAME_SYSTEM

Points to SYSTEM file:

set JEDIFILENAME_SYSTEM=%JBCGLOBALDIR%\src\SYSTEM
export JEDIFILENAME_SYSTEM=$JBCRELEASEDIR/src/SYSTEM

JEDIFILEPATH

Default path to jBASE data files. Doesn’t make much sense under T24 because mainly VOC
pointers are used there.

JEDI_PREFILEOP

Sets mode for file creation. E.g.:

set JEDI_PREFILEOP=TYPE=J4
export JEDI_PREFILEOP="SECURE=NO"

The second setting prevents the creation of new JR file with SECURE mode enabled.

JEDI_XMLDB2_SORT_RID_PARTIAL

Being seen set to 1 in DB2 environment.

JQL_TRACE_DEBUG

Reported that being set to 1 combined with JDIAG=TRACE=INDEX allows to determine if a


secondary index is being used when running a jQL statement.

LD_LIBRARY_PATH, LIBPATH, SHLIB_PATH

Path to system libraries for Linux, AIX and HP-UX accordingly.

LDR_CNTRL

Under AIX allows more memory for libraries’ upload, thus avoiding errors “Not enough
space...SUBROUTINE CALL FAIL”, e.g.:

export LDR_CNTRL=MAXDATA=0x60000000

LIB

If sources compilation is to be done – needs to contain lib subfolder of Visual C folder (for
Windows; other platforms have their own folders).

REM Page 145


TAFC_HOME

Replacement for JBCRELEASEDIR in new TAFC releases.

TAFC_MONITORING_STORE

Seen being set to REMOTE:127.0.0.1:58002.

PATH

Needs to contain: bin subfolder of TAFC, bin subfolder of Java home (after TAFC/bin!),
t24bin subfolder of bnk.run, the folder where JBCDEV BIN points, C:\windows\system32
(for Windows), bin subfolder of Visual C folder (for Windows; other platforms have their
own folders, like /usr/vac/bin for AIX).

TERM

Terminal type, e.g. ntcon, vt220 etc.

6 Some examples of paragraphs


6.1 Automate routine jQL task
List @ids of ACCOUNT which were edited but the changes were not yet authorised:

001 PA
002 SELECT FBNK.ACCOUNT$NAU
003 SELECT FBNK.ACCOUNT REQUIRE.SELECT (R
004 LIST ONLY FBNK.ACCOUNT$NAU

6.2 Automate routine T24 task


Start tSM (ask for the password, bring up the screen and wait for F5 ):

001 PA
002 ETS
003 DISPLAY PASSWORD?
004 HUSH ON
005 DISPLAY <<ADMIN.PASSWORD>>
006 HUSH OFF
007 EX
008 DATA INPUTT
009 DATA <<ADMIN.PASSWORD>>
010 DATA TSA.SERVICE, I TSM 6 STA

note: If you add 17 in hex mode to the end of the last line, F5 won’t be necessary.

REM Page 146


6.3 Output something to screen (jCL)
001 PQN
002 T (25,10), *=10, Welcome!, *=10

6.4 Read a file (jCL)


0001 PQN
0002 F-OPEN 1 F.SPF
0003 X ERROR: Can't open SPF
0004 F-READ 1 SYSTEM
0005 X ERROR: SYSTEM record not found
0006 MV %1 &1.8
0007 T "T24 release ", %1, " detected",I10
0008 F-K 1

Sample output:
T24 release R11.000 detected

6.5 Wrap long lines in jQL statement using jCL


File VOC , Record 'COLL.LIST' Insert 19:09:05
Command->
0001 PQN
0002 HLIST FBNK.COLLATERAL HDR-SUPP WITH CURRENCY EQ USD BY.DSND NOMINAL.VALUE
0003 H EVAL "OCONV(NOMINAL.VALUE, 'A;NI')" COL.HDR "#" TOTAL NOMINAL.VALUE
0004 H BREAK-ON EVAL "INT(OCONV(NOMINAL.VALUE, 'A;NI')/10)" COL.HDR "CTRL"
0005 P
-------------------------------- End Of Record --------------------------------

6.6 Run jBC program from jCL


0001 PQN
0002 H./test
0003 P
0004 T "Done"

7 JED
7.1 Text indentation
Use indent of 3 characters (default is 4) for jBC source code; format the code (BI command):

JED MY.BP NEW.PROG (B3,1)

REM Page 147


Before:

0001 SUBROUTINE NEW.PROG(P1, P2)


0002
0003 * this is totally new program
0004
0005 IF P2 EQ '' THEN
0006 TEXT = 'SECOND PARAMETER ABSENTS'
0007 CALL REM
0008 END

After bi command:

0001 SUBROUTINE NEW.PROG(P1, P2)


0002
0003 * this is totally new program
0004
0005 IF P2 EQ '' THEN
0006 TEXT = 'SECOND PARAMETER ABSENTS'
0007 CALL REM
0008 END

7.2 Input @VM and @SM


In the following example a @VM is to be put between ABC and DEF and an @SM – between
DEF and XYZ.
Step 1:

Command-> HEX
0001 ABCDEFXYZ

Step 2:

Command->
0001 414243FD444546FC58595A

Step 3:

Command-> HEX
0001 414243FD444546FC58595A

Result:

Command->
0001 ABC]DEF\XYZ

REM Page 148


7.3 Return where you were last time
Typing just JED from jsh will do the trick.

8 Debugger
8.1 Enter the debugger at program start
Use option -Jd in command line:

jsh t24 -->EX -Jd


Option -d seen on command line
Line 181 , Source T24.INITIALISE
jBASE debugger->

8.2 Get call stack information


jBASE debugger->j -g
Backtrace:
#0: UNKNOWN:121
#1: EX:50 -> Line 50 , Source EX
#2: T.EX:153 -> Line 153 , Source T.EX
#3: INP:18 -> Line 18 , Source INP
#4: I_SF.INPUT:121 -> Line 121 , Source INP

Backtrace log:
Line 0 , Source UNKNOWN , Level 0
Line 50 , Source EX
Line 153 , Source T.EX
Line 18 , Source INP

8.3 List variables using mask


jBASE debugger->v E*

COMMON variables
E : 0
ECOMI : Y
ETEXT :
END.ERROR : 0

8.4 List a variable with additional information


jBASE debugger->v -v TODAY

REM Page 149


COMMON variables
0194CDB8 : TODAY : (V) String : 8 bytes at address 01A3D880 : 20100809

8.5 Amend a variable


jBASE debugger->v -m V.DATE
V.DATE : 20100921 = 20100101
jBASE debugger->v V.DATE
V.DATE : 20100101

8.6 Remove the value altogether


jBASE debugger->v -m V.VAR
V.VAR : 1 = \0
jBASE debugger->v -v V.VAR
008DEA24 : V.VAR : (V) String : 0 bytes at address 22106790 :

8.7 Set variable contents to CHAR(0)


jBASE debugger->v -m V.VAR
V.VAR : 1 = \00
jBASE debugger->v -v V.VAR
008DEA24 : V.VAR : (V) String : 1 bytes at address 018F6150 : ~00

9 Tools and utilities


9.1 jgrep
EXECUTE 'DELETE-FILE DATA F.TEMP'
EXECUTE 'CREATE-FILE DATA F.TEMP 1 101 TYPE=J4'
OPEN 'F.TEMP' TO f_temp ELSE ABORT 201, 'F.TEMP'
* populate the file
rec_init = 'LINE 1' :@FM: 'LINE 2' :@FM: 'LINE 3'
WRITE rec_init TO f_temp, 'REC1'
rec_amended = 'Line 1' :@FM: 'Line 2' :@FM: 'Line 3'
WRITE rec_amended TO f_temp, 'REC2'
* Features:
* searches in @ID too
EXECUTE 'jgrep 2 F.TEMP' CAPTURING output
CHANGE @FM TO CHAR(10) IN output ; CRT output
* case-sensitive search by default
EXECUTE 'jgrep LINE F.TEMP' CAPTURING output
CHANGE @FM TO CHAR(10) IN output ; CRT output
* case-insensitive search
EXECUTE 'jgrep -c LINE F.TEMP' CAPTURING output
CHANGE @FM TO CHAR(10) IN output ; CRT output

REM Page 150


Output 1:

For record REC1 in file F.TEMP


0002 LINE 2

For record REC2 in file F.TEMP


0000 REC2
0002 Line 2

Output 2:

For record REC1 in file F.TEMP


0001 LINE 1
0002 LINE 2
0003 LINE 3

Output 3:

For record REC1 in file F.TEMP


0001 LINE 1
0002 LINE 2
0003 LINE 3

For record REC2 in file F.TEMP


0001 Line 1
0002 Line 2
0003 Line 3

9.2 jprof - quick tutorial


Open 2 sessions. From one of them get the port number for the second one:

WHERE
Port Device Account PID Command
*1 ntcon t24 2184 jsh
WHERE
2 ntcon t24 2452 jsh

Initiate the profiler for that port:

jprof 2 branch=on:output=t24.output

Message sent successfully to port 2

REM Page 151


In other session log in to T24. See contents of file t24.output:

EXECUTE: 1: ETS
BRANCH: 2: Subroutine Start: From unknown To SUBROUTINE main() Level 1
EXECUTE: 2: EBS.TERMINAL.SELECT EBS-JBASE
BRANCH: 3: Subroutine Start: From unknown To SUBROUTINE main() Level 1
EXIT: 3: EBS.TERMINAL.SELECT
EXIT: 2: para
BRANCH: 1: Subroutine Start: From SUBROUTINE main() To SUBROUTINE
JBASECommandNext Level 2
BRANCH: 1: Subroutine End: From SUBROUTINE JBASECommandNext To SUBROUTINE
main() Level 1
BRANCH: 1: Subroutine Start: From SUBROUTINE main() To SUBROUTINE
JBASECommandNext Level 2
BRANCH: 1: Subroutine End: From SUBROUTINE JBASECommandNext To SUBROUTINE
main() Level 1
BRANCH: 1: Subroutine Start: From SUBROUTINE main() To SUBROUTINE
JBASECommandNext Level 2
TIMESTAMP: time 1322650073
BRANCH: 1: Subroutine End: From SUBROUTINE JBASECommandNext To SUBROUTINE
main() Level 1
EXECUTE: 1: EX
BRANCH: 2: Subroutine Start: From unknown To SUBROUTINE main() Level 1
BRANCH: 2: Subroutine Start: From SUBROUTINE main() To SUBROUTINE OVERLAY.EX
Level 2
BRANCH: 2: Subroutine Start: From SUBROUTINE OVERLAY.EX To SUBROUTINE
T24.INITIALISE Level 3
...
BRANCH: 2: Subroutine End: From SUBROUTINE RUN.APPLICATION To SUBROUTINE
T.EX Level 2
BRANCH: 2: Subroutine Start: From SUBROUTINE T.EX To SUBROUTINE INP Level 3
BRANCH: 2: Subroutine Start: From SUBROUTINE INP To SUBROUTINE T.INP Level 4
BRANCH: 2: Subroutine Start: From SUBROUTINE T.INP To SUBROUTINE CHARX Level 5
BRANCH: 2: Subroutine End: From SUBROUTINE CHARX To SUBROUTINE T.INP Level 4
BRANCH: 2: Subroutine Start: From SUBROUTINE T.INP To SUBROUTINE CHARX Level 5
BRANCH: 2: Subroutine End: From SUBROUTINE CHARX To SUBROUTINE T.INP Level 4
BRANCH: 2: Subroutine Start: From SUBROUTINE T.INP To SUBROUTINE EB.AUTO.LOGOUT
Level 5
BRANCH: 2: Subroutine End: From SUBROUTINE EB.AUTO.LOGOUT To SUBROUTINE T.INP
Level 4

From session 1:

jprof 2 branch=off:memory=on:output=t24.output

REM Page 152


In session 2 type SPF S SYSTEM ←- . See contents of file t24.output:

MEMORY: -1*-1:
free 01C28030 at jlibBStore.c,548(I_SF.INPUT,134)
MEMORY: -1*-1:
malloc 74 to 01BD9B58 at jlibBStore.c,589(I_SF.INPUT,175)
MEMORY: -1*-1:
malloc 1 to 01BC3A00 at bigdigits.c,1275(I_SF.INPUT,177)
MEMORY: -1*-1:
free 01BC3A00 at bigdigits.c,1295(I_SF.INPUT,177)
MEMORY: -1*-1:
malloc 3 to 01BC3A00 at bigdigits.c,1275(I_SF.INPUT,178)
MEMORY: -1*-1:
free 01BC3A00 at bigdigits.c,1295(I_SF.INPUT,178)
MEMORY: -1*-1:
free 01BD9B58 at jlibBStore.c,55(I_SF.INPUT,179)
MEMORY: -1*-1:
malloc 4096 to 01C2C8E8 at jediHASHR.c,422(VALIDATE.APPLICATION,
276)
MEMORY: -1*-1: malloc 584 to 01B445E0 at jlibFNEWFILE.c,1447(VALIDATE.APPLICATI
ON,276)
...

Turn the profiling off – from session 1:

jprof 2 profile=off

Check memory usage summary (makes sense after memory profiling of the whole program
run):

jfatty t24.output

...
Remaining: 00000027 entries: Total 110592 bytes at jediHASHR.c,1525(OPF,403)
Remaining: 00000027 entries: Total 112104 bytes at jediHASHR.c,1470(OPF,403)
Remaining: 00000027 entries: Total 3456 bytes at jediBase.c,224(OPF,403)
Remaining: 00000027 entries: Total 410 bytes at jediBase.c,297(OPF,403)
Remaining: 00000027 entries: Total 945 bytes at jediBase.c,250(OPF,403)
Remaining: 00000038 entries: Total 23107 bytes at jlibBStore.c,589(System.putCac
he,49)
Remaining: 00000046 entries: Total 2622 bytes at jlibBCONVSFB.c,73(MATRIX.UPDATE,
335)
Remaining: 00000047 entries: Total 5266 bytes at jlibEMATPRS.c,134(LOAD.COMPANY,
180)
Total of 856 free spaces consuming 492441 bytes

9.3 LIST-OPEN-FILES
LIST-OPEN-FILES (V

Port File name Ref Count Inode rf blck stat fd


1 C:\TAFC\dev\PROC 1 000302E2 1 0 000b 1732
1 C:\TAFC\tmp\list_files_1 1 00000000 1 0 0013 -1

REM Page 153


1 C:\TAFC\tmp 1 00000000 1 0 0013 -1
1 C:\TAFC\jbcmessages 1 000305E3 1 0 000b 1768
1 C:\TAFC\tmp\jutil_ctrl 1 0005B503 1 0 000b 1788
1 C:\sa-tafc\&SAVEDLISTS& 1 00000000 1 0 0013 -1
1 C:\sa-tafc\tmp_workfile 1 000081F2 1 0 000b 1800
1 .\VOC 1 00047826 1 0 000b 1808

9.4 MW42
The Answer to the Ultimate Question of Life, the Universe, and Everything...
Parameter: interval between screen refreshes (in seconds, default 5).
Using “A” (or up-arrow) as a toggle, you can see @user.root information in “User” column:

Port User Pid Files Perf Del Read Write Open Mem Cpu Prog
1 7143606 41 (6) 54 5 1758 57 350 16.5M 1.20 1 I /usr/jb..
4UTHORISER-012451872 171 (6) 8 5 711K 475K 253 14.7M 5m 3 I EX (I_S..
* 5LADIMIR.K-010289170 91 (7) 17 17 844 69 209 12.2M 0.00 2 MW42 (mw4..
27 INPUTTER-0 9371854 32 (6) 110 1 9927 202 124 10.5M 1.46 3 SLEEP tSM..

“M” – show “MemF” and “MemU” (memory free and used accordingly); space bar – screen
refresh.

9.5 t24version
Gives more information about libraries than jdiag:

library:libTAFCcommon release:R10 changeno:87704 patchno:0


platform:WIN32_VC80 node:UKDSK-AMURPHY2 date:20100203_231155
library:libTAFCfrmwrk release:R10 changeno:88568 patchno:0
platform:WIN32_VC80 node:UKDSK-AMURPHY2 date:20100203_232531
etc

note: Used by T24 Updates.

9.6 SQLUPDATE
Mass update of data on low level (no T24 checks, updates of linked tables etc). Use with
extreme caution; I haven’t found much logic in the syntax facing many error messages.
Working sample:

SQLUPDATE F.USER SET END_DATE_PROFILE="20130101"

Updated 148 rows.

REM Page 154


9.7 telnetd.exe, Transcmd.exe
Programs that are necessary for local Telnet access under Windows (might be absent in
TAFC distribution).

9.8 WHERE
Show jBASE-related processes:
WHERE
Port Device Account PID Command
*1 ntcon t24 436 jsh
WHERE
2 ntcon vladimir.kaz 2928 jsh

Show everyone except yourself:


WHERE (U
Port Device Account PID Command
2 ntcon vladimir.kaz 2928 jsh

Show more detail for others:


WHERE (VU
Port Device Account PID Command
2 ntcon vladimir.kaz 2928 Port 2 details at 19:14:50 13 DEC 2011
Thread type Normal
Usage Count 58 from 100K
Application Open Files 6 , Actual O/S Open
Files 5
READ's 5 , WRITE's 0
DELETE's 1 , CLEARFILE's 0
EXECUTE's 0 , INPUT's 1
OPEN's 8
--- jsh
Program at keyboard INPUT at CommandNext.b,103

9.9 LOGOFF
It’s a good idea to try LOGOFF before (j)kill (especially the one with “-9” option):
MW42
Port User Pid Files Perf Del Read Write Open Mem Cpu Prog
1 t24test9830644 55 (6) 26 51 8.29M 131 309 12.4M 10m 3 I EX (I_SF.INPUT,121)
4 t24test2517600 8 (7) 34 1 117K 39 94 6.38M 8.47 2 I mw42 (mw42.b,221)
5 t24test0158156 32 (6) 80 1 77454 639 134 10.4M 6.69 3 SLEEP tSM (tSM,823)
11 t24test0813568 80 (6) 6 13 469 40 154 12.0M 0.73 3 I EX (UNKNOWN,121)
*19 t24test3041728 76 (7) 8 9 439 28 156 11.6M 0.00 2 MW42 (mw42.b,708)

REM Page 155


LOGOFF 1 4 11

MW42
Port User Pid Files Perf Del Read Write Open Mem Cpu Prog
5 t24test0158156 32 (6) 80 1 77454 639 134 10.4M 6.69 3 SLEEP tSM (tSM,823)
*19 t24test3041728 76 (7) 10 9 446 30 160 11.6M 0.00 2 MW42 (mw42.b,708)

9.10 jshelltype
Changes jBASE shell type (note the prompt):

jsh-->LIST &TEMP&
DICT &TEMP&...

No Records Listed

jsh-->jshelltype sh

sh-->LIST &TEMP&
No file name could be found for your query
'TEMP' is not recognized as an internal or external command,
operable program or batch file.

9.11 SP-NEWTAB
If JBCSPOOLERDIR environment variable points to non-existing directory, each attempt to
“print” something (even “P” T24 function) will hang the process. To avoid that, when
creating a new environment it’s a good idea to set that variable to, say, %HOME%\jspooler,
create it if it doesn’t exist and run SP-NEWTAB at jsh prompt, e.g.:

SP-NEWTAB
This operation deletes ALL print jobs and print queues, and
re-creates a new spooler with the following criteria:

1) Spooler directory = C:\home\kzm\v-t24\r11\jspooler


2) Default security of form queues = CREATOR
3) Default security of print jobs = CREATOR
4) Other owners of spooler =
Enter options 1) to 4) to modify, C to continue or Q to quit : C
[ 417 ] File C:\home\kzm\v-t24\r11\jspooler\jobs]D created , type = UD
[ 417 ] File C:\home\kzm\v-t24\r11\jspooler\jobs created , type = UD
[ 417 ] File C:\home\kzm\v-t24\r11\jspooler\jspool_log]D created , type = J4
[ 417 ] File C:\home\kzm\v-t24\r11\jspooler\jspool_log created , type = J4
Spooler RESTART completed

REM Page 156


9.12 MSG
Send message to other users (terminal-based ones).

MSG !37 hi port 37!

MSG t24test Please log off now!

10 OFS
10.1 Characters substitution
Some characters are considered by OFS as special ones – comma, underscore etc. To put
them into fields you need to substitute them by other ones.
For this test we’ll use a field that has IN2ANY routine attached to it, namely - enq.desc field
of CONTEXT.ENQUIRY application. The easiest way to input an OFS string in Model
Bank – type tSS TAG at jsh prompt, copy/paste the string, when finished type EXIT.
Even if a string is shown at several lines in the following examples – this is only for fitting
into the screen; OFS message is always one line.
Comma is to be replaced by question mark:

CONTEXT.ENQUIRY,/I/PROCESS,INPUTT/123456,ACCOUNT,
ENQ.DESC:1:1=Statement summary? list

Result:

Model Bank App-related enquiry info INPUT

FILE.NAME......... ACCOUNT
------------------------------------------------------------------------------
15. 1. 1 GB ENQ.DESC. Statement summary, list

Double quote is to be replaced with pipe:

CONTEXT.ENQUIRY,/I/PROCESS,INPUTT/123456,ACCOUNT,
ENQ.DESC:1:1=Statement |summary| list

Result:

Model Bank App-related enquiry info INPUT

FILE.NAME......... ACCOUNT
------------------------------------------------------------------------------
15. 1. 1 GB ENQ.DESC. Statement "summary" list

REM Page 157


Underscore should be enclosed in single quotes:

CONTEXT.ENQUIRY,/I/PROCESS,INPUTT/123456,ACCOUNT,
ENQ.DESC:1:1=Statement'_'summary'_'list

Result:

Model Bank App-related enquiry info INPUT

FILE.NAME......... ACCOUNT
------------------------------------------------------------------------------
15. 1. 1 GB ENQ.DESC. Statement_summary_list

Delete a subvalue:

CONTEXT.ENQUIRY,/I/PROCESS,INPUTT/123456,ACCOUNT,ENQ.DESC:4:1=-

Since fields are linked, all group #4 disappeared:

Model Bank App-related enquiry info INPUT

FILE.NAME......... ACCOUNT
------------------------------------------------------------------------------
15. 3. 1 GB ENQ.DESC. Forward movements
16. 3 AUTO.LAUNCH....
17. 1 VERSION.NAME...
18. 1. 1 GB VER.DESC.
19. 1 SCRIPT.NAME....
20. 1. 1 GB SPT.DESC.
21 RESERVED.6........
22 RESERVED.5........

Delete unauthorised record to get fields in group #4 back:

CONTEXT.ENQUIRY,/D/PROCESS,INPUTT/123456,ACCOUNT

Result:

Model Bank App-related enquiry info INPUT

FILE.NAME......... ACCOUNT
------------------------------------------------------------------------------
15. 3. 1 GB ENQ.DESC. Forward movements
16. 3 AUTO.LAUNCH....
2. 4 ENQUIRY.NAME... STMT.ENT.TODAY Statement Entries Today
3. 4. 1 SEL.FIELD... ACCOUNT.NUMBER

REM Page 158


To illustrate cleaning of a field firstly let’s populate it (with authorisation)...

CONTEXT.ENQUIRY,/I/PROCESS//0,INPUTT/123456,ACCOUNT,AUTO.LAUNCH:3:1=I

Result:

Model Bank App-related enquiry info INPUT

FILE.NAME......... ACCOUNT
------------------------------------------------------------------------------
15. 3. 1 GB ENQ.DESC. Forward movements
16. 3 AUTO.LAUNCH.... I
2. 4 ENQUIRY.NAME... STMT.ENT.TODAY Statement Entries Today
3. 4. 1 SEL.FIELD... ACCOUNT.NUMBER

...and now clean the contents:

CONTEXT.ENQUIRY,/I/PROCESS//0,INPUTT/123456,ACCOUNT,AUTO.LAUNCH:3:1=NULL

Result:

Model Bank App-related enquiry info INPUT

FILE.NAME......... ACCOUNT
------------------------------------------------------------------------------
15. 3. 1 GB ENQ.DESC. Forward movements
16. 3 AUTO.LAUNCH....
2. 4 ENQUIRY.NAME... STMT.ENT.TODAY Statement Entries Today
3. 4. 1 SEL.FIELD... ACCOUNT.NUMBER

10.2 “Replace” option


Retains only the values supplied in OFS message.
Step 1:

DL.DEFINE,/I/PROCESS,INPUTT/123456,TESTDLDEF,DESCRIPTN::=THE TEST ONE,


SHORT.DESC::=TEST,FILE.NAME:1:=ACCOUNT.PARAMETER,RECORD.NAME:1:=SYSTEM

Result:

Model Bank DL.DEFINE SEE

UNIT.NAME......... TMNS000-TESTDLDEF
------------------------------------------------------------------------------
1. 1. 1 GB DESCRIPTN THE TEST ONE

REM Page 159


2. 1 GB SHORT.DESC.. TEST
5 OPERATION......... S
9. 1 FILE.NAME...... ACCOUNT.PARAMETER
10. 1 RECO SYSTEM
31. 1 DATE.TIME...... 20 DEC 11 19:05

Step 2:

DL.DEFINE,/I/PROCESS,INPUTT/123456,TESTDLDEF,FILE.NAME:2:=MD.PARAMETER,
RECORD.NAME:2:=GB0010001

Result:

Model Bank DL.DEFINE SEE

UNIT.NAME......... TMNS000-TESTDLDEF
------------------------------------------------------------------------------
1. 1. 1 GB DESCRIPTN THE TEST ONE
2. 1 GB SHORT.DESC.. TEST
5 OPERATION......... S
9. 1 FILE.NAME...... ACCOUNT.PARAMETER
10. 1 RECO SYSTEM
9. 2 FILE.NAME...... MD.PARAMETER
10. 2 RECO GB0010001
31. 1 DATE.TIME...... 20 DEC 11 19:09

Step 3:

DL.DEFINE,/I/PROCESS,INPUTT/123456,TESTDLDEF,FILE.NAME:1:=LMM.INSTALL.CONDS,
RECORD.NAME:1:=GB0010001

Result:

Model Bank DL.DEFINE SEE

UNIT.NAME......... TMNS000-TESTDLDEF
------------------------------------------------------------------------------
1. 1. 1 GB DESCRIPTN THE TEST ONE
2. 1 GB SHORT.DESC.. TEST
5 OPERATION......... S
9. 1 FILE.NAME...... LMM.INSTALL.CONDS
10. 1 RECO GB0010001
9. 2 FILE.NAME...... MD.PARAMETER
10. 2 RECO GB0010001
31. 1 DATE.TIME...... 20 DEC 11 19:12

REM Page 160


Step 4 – apply “replace” option:

DL.DEFINE,/I/PROCESS,INPUTT/123456////1,TESTDLDEF,DESCRIPTN::=THE TEST ONE,


SHORT.DESC::=TEST,FILE.NAME:1:=LMM.INSTALL.CONDS,RECORD.NAME:1:=GB0010001

Result:

Model Bank DL.DEFINE SEE

UNIT.NAME......... TMNS000-TESTDLDEF
------------------------------------------------------------------------------
1. 1. 1 GB DESCRIPTN THE TEST ONE
2. 1 GB SHORT.DESC.. TEST
5 OPERATION......... S
9. 1 FILE.NAME...... LMM.INSTALL.CONDS
10. 1 RECO GB0010001
31. 1 DATE.TIME...... 20 DEC 11 19:14

10.3 Launch an enquiry


ENQUIRY.SELECT,/I/PROCESS,INPUTT/123456,USER2,USER.NAME:LK:=C...

Result:

HEADER="List of T24 Users",@ID::User ID/USER.NAME::User Name/SIGN.ON.NAME::Sign


On Name/LANG.DESCRIPTION::Language/DEPART.NAME::Department Name/START.DATE.PRO
FILE::Profile Start Date/END.DATE.PROFILE::Profile Expiry Date,"List of T24 Use
rs","ABI1 " "ABINAN.1 " "ABINAN.1
" "English " "Retail User
" "08 MAR 2011" "30 DEC 2020","List of T24 Users","ACCTEXEC
" "Account Executive " "ACCTEXEC1 " "En
glish " "Implementation " "
19 JUL 2010" "30 DEC 2020","List of T24 Users","AUTHORISER " "AUTHOR
ISER " "AUTHOR " "English
" "Implementation " "09 MAR 2011" "30
DEC 2015","List of T24 Users","BUILDUSER279 " "AUTHORISER
" "GOPIRAM " "English "
"Implementation " "23 SEP 2009" "30 DEC 2015","List o
f T24 Users","DEALER01 " "DEALER1 " "DE
ALER1 " "English " "Treasury Dealer
...

note: BUILD routine was executed; it doesn’t for CALL ENQUIRY.DISPLAY – see below.

REM Page 161


10.4 Prepare complex OFS message using SELECT...SAVING EVAL
Example: update DATES application.

SELECT F.DATES 'GB0010001' SAVING EVAL \'DATES,/I/PROCESS//0,INPUTT/123456,


GB0010001,BACK.VALUE.MINIMUM::=':LAST.WORKING.DAY:',FORW.VALUE.MINIMUM::='
:NEXT.WORKING.DAY:',FORW.VALUE.MAXIMUM::=':DQUOTE(OCONV(ICONV(TODAY,"D4")
+60,"D4"))\

Result:

DATES,/I/PROCESS//0,INPUTT/123456,GB0010001,BACK.VALUE.MINIMUM::=20110413,
FORW.VALUE.MINIMUM::=20110415,FORW.VALUE.MAXIMUM::="13 JUN 2011"

11 T24 global variables


Starting with application-related things.

11.1 F array
Defines field names in application (and such things like associations, single/multi property
etc). See examples for CUSTOMER:

Single field:
F(1) : (V) String : 8 bytes at address 022FFF38 : MNEMONIC
Multi-language field:
F(2) : (V) String : 16 bytes at address 022FF350 : XX.LL.SHORT.NAME
Multivalue field:
F(25) : (V) String : 16 bytes at address 01959290 : XX.OTHER.OFFICER
Multi-valued association:
F(34) : (V) String : 11 bytes at address 0230D2E0 : XX<LEGAL.ID
F(35) : (V) String : 17 bytes at address 0231C068 : XX-LEGAL.DOC.NAME
F(36) : (V) String : 20 bytes at address 0181D1A0 : XX-LEGAL.HOLDER.NAME
F(37) : (V) String : 17 bytes at address 022FFCD0 : XX-LEGAL.ISS.AUTH
F(38) : (V) String : 17 bytes at address 02315C90 : XX-LEGAL.ISS.DATE
F(39) : (V) String : 17 bytes at address 0192B120 : XX>LEGAL.EXP.DATE
Multi- and sub-valued association:
F(10) : (V) String : 16 bytes at address 02317A18 : XX<RELATION.CODE
F(11) : (V) String : 15 bytes at address 023464D8 : XX-REL.CUSTOMER
F(12) : (V) String : 18 bytes at address 02310188 : XX-REVERS.REL.CODE
F(13) : (V) String : 19 bytes at address 019B7F58 : XX-XX<REL.DELIV.OPT
F(14) : (V) String : 10 bytes at address 02302EC0 : XX-XX-ROLE
F(15) : (V) String : 20 bytes at address 019CEE60 : XX-XX-ROLE.MORE.INFO
F(16) : (V) String : 16 bytes at address 02315C48 : XX-XX>ROLE.NOTES
F(17) : (V) String : 14 bytes at address 01A07520 : XX-REL.RESERV6
F(18) : (V) String : 14 bytes at address 019FBC58 : XX-REL.RESERV5

REM Page 162


F(19) : (V) String : 14 bytes at address 019B3DC8 : XX-REL.RESERV4
F(20) : (V) String : 14 bytes at address 022E7540 : XX-REL.RESERV3
F(21) : (V) String : 14 bytes at address 0230EF70 : XX-REL.RESERV2
F(22) : (V) String : 14 bytes at address 01A15EC0 : XX>REL.RESERV1

Length more than 18 causes T24 classic to truncate the field name:

Model Bank CUSTOMER INPUT

CUSTOMER.CODE..... 120018
------------------------------------------------------------------------------
1 MNEMONIC.......... ABCDE
...
14. 1. 1 ROLE........
15. 1. 1 ROLE.MORE.IN
16. 1. 1 ROLE.NOTES..
------------------------------------------------------------------------------
06 DEC 2011 19:36:51 USER (09 AUG) VLADIMIR.K [6492,INPAGE 1 >>14>>>
ACTION
AWAITING PAGE INSTRUCTIONS

11.2 N array
Defines field length in application. See examples for CUSTOMER:

From 3 to 10 characters can be input:


N(1) : (V) String : 4 bytes at address 022E75C0 : 10.3
From 3 to 35 characters can be input,
additional check of field will be done after input:
N(2) : (V) String : 7 bytes at address 019FBB38 : 35.3.C
Up to 3 characters can be input, field isn't mandatory (no lower limit),
additional check of field will be done after input:
N(10) : (V) String : 4 bytes at address 023439D8 : 3..C
Up to 35 characters can be input, field isn't mandatory:
N(4) : (V) Integer : 35

11.3 T array
Defines field type in application. See examples for CUSTOMER:

IN2 routine is set to check (IN2MNE in this case):


T(1) : (V) String : 3 bytes at address 02301688 : MNE
Field is NOINPUT:
T(12) : (V) String : 9 bytes at address 023157E0 : ^^NOINPUT
IN2 routine is set; field is NOCHANGE:
T(44) : (V) String : 13 bytes at address 02301D10 : CUS^^NOCHANGE

REM Page 163


Field is of type DATE, allows values before 1950:
T(31) : (V) String : 6 bytes at address 019675C0 : D^1000
Choice of values:
T(52) : (V) String : 7 bytes at address 023179C8 : ^YES_NO
Anything can be input; after copying a record contents won't be copied:
T(67) : (V) String : 11 bytes at address 0230FD20 : ANY^^NOCOPY
Type: IN2A, no copying, multi-line text edit window:
T(105 : (V) String : 17 bytes at address 02342730 : A^^NOCOPY^^^^TEXT
Type: IN2COM (company); NOCHANGE, special formatting (e.g. GB-001-0001):
T(48) : (V) String : 26 bytes at address 022FFC80 : COM^^NOCHANGE^R##-###-####
Amount displayed with currency settings for currency code in the field 78:
T(79) : (V) String : 16 bytes at address 02366530 : AMT^]78.X^NOCOPY
Choices supplied from application EB.LOOKUP (built with CALL EB.LOOKUP.LIST);
(e.g., records CUS.MARITAL.STATUS*MARRIED and CUS.MARITAL.STATUS*SINGLE):
T(65) : (V) String : 112 bytes at address 02332FC8 :
^PARTNER_OTHER_SINGLE_WIDOWED_DIVORCED_MARRIED^NOCOPY^^^^^^^
^Spouse_Other_Unmarried_Widow woman_Divorced_Married

note: Analogs for @id are called ID.F, ID.N and ID.T respectively.

11.4 LOCAL.REF.FIELD
Local reference field position in application. Useful when you address a local reference only
– you don’t need to include the insert for the application:

SUBROUTINE SOME.TEST
* T24 input routine
$INSERT I_COMMON
$INSERT I_EQUATE

* Local ref fields used here are #1 and #2, though it's better
* to use an insert file and not address them by numbers

IF R.NEW(LOCAL.REF.FIELD)<1,2> AND NOT(R.NEW(LOCAL.REF.FIELD)<1,1>) THEN


AF = LOCAL.REF.FIELD
AV = 1
ETEXT = 'SHOULD BE POPULATED IF THE FIELD BELOW IS NOT EMPTY'
CALL STORE.END.ERROR
END

RETURN
END

note: Addressing local fields by numbers isn’t recommended – it’s done to simplify code.
Test sample:

Model Bank CUSTOMER,TEST INPUT

REM Page 164


CUSTOMER.CODE..... 188888
------------------------------------------------------------------------------
177 RESERVED.02.......
178 RESERVED.01.......
179. 1 SEGMENT........ SHOULD BE POPULATED IF THE FIELD BELOW IS NOT EMPTY
179. 2 CU.EFF.DATE.... 01 JAN 2011
180. 1 OVERRIDE.......
181 RECORD.STATUS.....
182 CURR.NO........... 1
183. 1 INPUTTER....... 4412_SEAT.USER__OFS_TEST
184. 1 DATE.TIME...... 06 APR 11 11:10
185 AUTHORISER........ 4412_SEAT.USER_OFS_TEST
186 CO.CODE........... GB-001-0001 Model Bank
187 DEPT.CODE......... 1 Implementation
188 AUDITOR.CODE......
189 AUDIT.DATE.TIME...

------------------------------------------------------------------------------
28 NOV 2011 19:18:08 USER (14 APR) VLADIMIR.K [3018,INPAGE 12
ACTION

11.5 Other useful things for the current application


• APPLICATION – its name, e.g. “ACCOUNT”.
• PGM.TYPE – type of application from PGM.FILE (with additional parameters), e.g. “U”
or “M.NOD.NOU.BDA.GAC”.
• FILE.CLASS – classification, e.g. “INT”.
• FULL.FNAME – full live file name, e.g. “FBNK.ACCOUNT”.
• PREFIX – prefix used for field names in insert file, e.g. “EB.ABB” for ABBREVIATION.
• PGM.VERSION – version name, e.g. “,AUTH”.
• V$FUNCTION – function, e.g. “I”.
• ID.NEW – @id of the record being processed.
• ID.OLD – @id of the record if it’s been authorised before, otherwise an empty sring.
• ID.NEW.LAST – @id of the record that was left unauthorised before or – if that’s not the
case – of the record being processed.
• R.NEW – the record being processed.
• R.OLD – the last authorised record.
• R.NEW.LAST – the last unauthorised record.
• A – position relative to screen (version) layout.
• AF, AV, AS – current position (field/value/subvalue).
• ANY.INPUT – “Y” if user did any input.
• COMI, COMI.ENRI – last user input and its enrichment.
• ECOMI – last user input (before preprocessing). E.g.: user inputs 1T in amount field; in
this case ECOMI is 1T and COMI is 1000.
• E – put there an error message to raise the error in CHECK.REC.RTN or AUTH.ROUTINE.

REM Page 165


• ETEXT – put there an error message to raise the error in VALIDATION.RTN or INPUT.ROUTINE
(the latter case also requires a call to STORE.END.ERROR).
• ECOMI – what will be displayed in current field in case of an error.
• V$DISPLAY – last user input as it shown on screen (with default delimiters – like dashes
in company @id – and so on).
• AUTH.NO – number of authorisations (0/1/2), though seen being empty at input stage.
• CHECKFILE – dimensioned array with fields’ links to external tables (ID.CHECKFILE variable
for @id).
• CONCATFILE – dimensioned array with fields’ links to external concat files (ID.CONCATFILE
variable for @id).
• SCREEN.TITLE – window title; not sure if it works for Browser.
• C$NS.OPERATION – parameter for non-stop mode.
• T.VAL.ASSOC – fields that are associated, e.g. for ACCOUNT:
“52\55]56\59]60\63]64\67]68\71]73\75]79\82]99\100]101\103]105...”

11.6 Current user and session info


• OPERATOR – currently signed-in user.
• LNGG – user’s language.
• TNO – terminal number (unique for current server).
• C$PORT.NO – port number of current session.
• CMD$STACK – user’s command stack, e.g.:
“ABBREVIATION,TEST]ABBREVIATION,]VERSION, I AB,TEST^QWER]ABBREVIATION,TEST”.
• TTYPE – terminal type, e.g. EBS-JBASE or EBS-GUI (for Desktop).
• RUNNING.IN.UTF8 – 1 if yes.
• ID.COMPANY – current company @id.

11.7 File variables that are global


• F.CURRENCY.
• F.DYNAMIC.TEXT.
• F.FILE – live file of current application.
• F.FILE$NAU – $NAU file of current application (if applicable).
• F.FILE$HIS – $HIS file of current application (if applicable).
• F.FILE.CONTROL.
• F.LOCKING.
• F.PROTOCOL.
• F.SPF.
• F.T24.SESSION.

11.8 Cached records or arrays with useful information – so no need


to read that all from disk
• C$DE.EU.LIST – countries-members of EU with date of introduction.

REM Page 166


• R.ACCOUNT.PARAMETER – record SYSTEM from ACCOUNT.PARAMETER.
• R.COMPANY (dimensioned).
• R.DATES (dimensioned).
• R.INTERCO.PARAMETER – record SYSTEM from INTERCO.PARAMETER.
• T.LANGUAGE – list of all used languages, e.g. “GB^FR^DE^ES”.
• C$R.LCCY – local CURRENCY record.
• R.SPF.SYSTEM.
• R.USER – current USER record.
• R.VERSION (dimensioned).

11.9 Other useful things in I COMMON and I EQUATE


• TODAY – current bank date.
• LCCY – local currency.
• RUNNING.UNDER.BATCH – supposed to be used to detemine if COB is in progress. In fact,
this variable is set for online services as well. (Hint: check DATES record instead.)

11.10 I ENQUIRY.COMMON
• ENQ.ERROR – can be set in “build routine” to cancel enquiry output.
• O.DATA – incoming/outgoing data for “conversion routine”.

11.11 Other inserts of interest


• I GTS.COMMON/GTSACTIVE – if it’s set then we’re under OFS or Browser.
• I GTS.COMMON/OFS$BROWSER – if it’s set then we’re under Browser.
• I GTS.COMMON/OFS$SOURCE.ID, OFS$SOURCE.REC – @id and the record of used OFS.SOURCE
record.

12 T24 hooks
12.1 Record types
Description of records that are to be created for certain hooks to work. (@id is always a
routine name.)
• PGM.FILE, record type: “M”.

Model Bank PROGRAM FILE SEE

PROGRAM SOME.TEST
------------------------------------------------------------------------------
1 TYPE.............. M
5 PRODUCT........... EB

REM Page 167


• PGM.FILE, record type: “S”.

Model Bank PROGRAM FILE, SEE

PROGRAM SOME.TEST
------------------------------------------------------------------------------
1 TYPE.............. S
5 PRODUCT........... EB
8. 1 APPL.FOR.SUBR.. FUNDS.TRANSFER FUNDS.TRANSFER

note: appl.for.subr is required only for VERSION/AUT.NEW.CONTENT.


• EB.API record:
Model Bank EB.API SEE

KEY............... SOME.TEST
------------------------------------------------------------------------------
2 PROTECTION.LEVEL.. FULL
3 SOURCE.TYPE....... BASIC

12.2 Mainline routines


To run a subroutine from T24 “AWAITING APPLICATION” prompt PGM.FILE record (type
“M”) is required.

12.3 VERSION/ID.RTN
Doesn’t make much sense. Could be useful if we got to it before system checks of @id –
to save typing, for example. And for local application it’s better to incorporate checks to
template.
Uses COMI to check and/or change the @id. ID.NEW is empty at this stage.

12.4 VERSION/CHECK.REC.RTN
In this example we’ll stop user from amending an existing record – only allow to input a new
one.
Step 1. Routine:

SUBROUTINE SOME.TEST
* t24 check.rec.rtn
$INSERT I_COMMON
$INSERT I_EQUATE

IF R.NEW(V-6) THEN E = 'EB-CANT.CHANGED' ;* ID of EB.ERROR record


RETURN
END

REM Page 168


Step 2. Create EB.API record.
Step 3. Attach routine:

Model Bank VERSION, SEE

PGM.NAME.VERSION.. ACCOUNT,TEST
------------------------------------------------------------------------------
75. 1 CHECK.REC.RTN.. SOME.TEST

Test case 1 (existing record, function S):

Model Bank ACCOUNT,TEST SEE


CHF Current Account
ACCOUNT.NUMBER.... 13226 Roberto Consoli
------------------------------------------------------------------------------
1 CUSTOMER.......... 100287 Roberto Consoli
2 CATEGORY.......... 1-001 Current Account
3 ACCOUNT.TITLE.1... Roberto Consoli
5 SHORT.TITLE....... Roberto Consoli
6 MNEMONIC.......... CONSOLICHF
7 POSITION.TYPE..... TR TRADING POSITION
8 CURRENCY.......... CHF Swiss Franc
9 CURRENCY.MARKET... 1 Currency Market
11 ACCOUNT.OFFICER... 14 Private Corporate Action Officer
21 CONDITION.GROUP... 1 Current Account Personal
23 OPEN.ACTUAL.BAL... -24,204.15
24 OPEN.CLEARED.BAL.. -24,204.15
25 ONLINE.ACTUAL.BAL. -24,074.15
26 ONLINE.CLEARED.BAL -24,074.15
27 WORKING.BALANCE... -24,074.15
34 DATE.LAST.CR.BANK. 05 AUG 2010
------------------------------------------------------------------------------
17 NOV 2011 22:34:03 USER (09 AUG) VLADIMIR.K [5317,INPAGE 1 >>>3>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Test case 2 (existing record, function I):

Model Bank ACCOUNT,TEST INPUT

------------------------------------------------------------------------------

REM Page 169


------------------------------------------------------------------------------
17 NOV 2011 22:36:18 USER (09 AUG) VLADIMIR.K [5317,IN]
ACTION 13226 CANNOT BE CHANGED
AWAITING ID

Test case 3 (new record, function I):

Model Bank ACCOUNT,TEST INPUT

ACCOUNT.NUMBER.... 60623
------------------------------------------------------------------------------
1 CUSTOMER..........
2 CATEGORY..........
3 ACCOUNT.TITLE.1...
4 ACCOUNT.TITLE.2...
5 SHORT.TITLE.......
6 MNEMONIC..........
7 POSITION.TYPE.....
8 CURRENCY..........
9 CURRENCY.MARKET... 1 Currency Market
10 LIMIT.REF.........
11 ACCOUNT.OFFICER...
12. 1 OTHER.OFFICER..
13 POSTING.RESTRICT..
14 RECONCILE.ACCT....
15 INTEREST.LIQU.ACCT
16 INTEREST.COMP.ACCT
------------------------------------------------------------------------------
17 NOV 2011 22:36:32 USER (09 AUG) VLADIMIR.K [5317,I PAGE 1 >>14>>>
ACTION

12.5 VERSION/AUT.NEW.CONTENT
Auto-populate a field. In the past it was also used to stop user from entering an inappropriate
record. It doesn’t make sense now – CHECK.REC.RTN can be used for that.

REM Page 170


Step 1. Routine:

SUBROUTINE SOME.TEST
* T24 aut.new.content routine
$INSERT I_COMMON
$INSERT I_EQUATE

IF NOT(R.NEW(AF)) THEN R.NEW(AF) = 'NEW REFERENCE'


RETURN
END
Step 2. Create PGM.FILE record (type “S”).
Step 3. Attach routine:
Model Bank VERSION SEE

PGM.NAME.VERSION.. FUNDS.TRANSFER,TEST
------------------------------------------------------------------------------
50. 1 AUTOM.FIELD.NO. DEBIT.THEIR.REF DEBIT.THEIR.REF
51. 1 AUT.OLD.CONTENT
52. 1 AUT.NEW.CONTENT @SOME.TEST

Run:
Model Bank FUNDS.TRANSFER,TEST INPUT REF FT102210VT31

------------------------------------------------------------------------------
1 TRANSACTION.TYPE..
2 DEBIT.ACCT.NO.....
3 IN.DEBIT.ACCT.NO..
4 CURRENCY.MKT.DR... 1 Currency Market
5 DEBIT.CURRENCY....
6 DEBIT.AMOUNT......
7 DEBIT.VALUE.DATE..
8 IN.DEBIT.VDATE....
9 DEBIT.THEIR.REF... NEW REFERENCE
10 CREDIT.THEIR.REF..
11 CREDIT.ACCT.NO....
12 CURRENCY.MKT.CR... 1 Currency Market
13 CREDIT.CURRENCY...
14 CREDIT.AMOUNT.....
15 CREDIT.VALUE.DATE.
16 TREASURY.RATE.....
------------------------------------------------------------------------------
18 NOV 2011 20:05:24 USER (09 AUG) VLADIMIR.K [1212,INPAGE 1 >>15>>>
ACTION

note: You can populate any field from such routine, not necessarily the “current” one.

REM Page 171


12.6 VERSION/VALIDATION.RTN
Validate user input to particular field. In this example user input which is shorter than 15
characters will be rejected.
Step 1. Routine:

SUBROUTINE SOME.TEST
* T24 validation routine
$INSERT I_COMMON
$INSERT I_EQUATE

IF LEN(COMI) LT 15 THEN ETEXT = 'EB-TOO.FEW.CHARACTERS' ;* ID of EB.ERROR rec


RETURN
END

Step 2. Create EB.API record.


Step 3. Attach routine:

Model Bank VERSION SEE

PGM.NAME.VERSION.. FUNDS.TRANSFER,TEST
------------------------------------------------------------------------------
58. 1 VALIDATION.FLD. DEBIT.THEIR.REF DEBIT.THEIR.REF
59. 1 VALIDATION.RTN. SOME.TEST

Step 4 (for Browser):

Model Bank VERSION SEE

PGM.NAME.VERSION.. FUNDS.TRANSFER,TEST
------------------------------------------------------------------------------
13. x FIELD.NO....... DEBIT.THEIR.REF DEBIT.THEIR.REF
...
42. x. 1 ATTRIBS..... HOT.FIELD

Run:

Model Bank FUNDS.TRANSFER,TEST INPUT REF FT10221MYLPY

------------------------------------------------------------------------------
1 TRANSACTION.TYPE..
2 DEBIT.ACCT.NO.....
3 IN.DEBIT.ACCT.NO..
4 CURRENCY.MKT.DR... 1 Currency Market
5 DEBIT.CURRENCY....
6 DEBIT.AMOUNT......

REM Page 172


7 DEBIT.VALUE.DATE..
8 IN.DEBIT.VDATE....
9 DEBIT.THEIR.REF... NOT SO LONG TOO FEW CHARACTERS
10 CREDIT.THEIR.REF..
11 CREDIT.ACCT.NO....
12 CURRENCY.MKT.CR... 1 Currency Market
13 CREDIT.CURRENCY...
14 CREDIT.AMOUNT.....
15 CREDIT.VALUE.DATE.
16 TREASURY.RATE.....
------------------------------------------------------------------------------
18 NOV 2011 20:26:26 USER (09 AUG) VLADIMIR.K [9487,INPAGE 1 >>15>>>
ACTION

12.7 VERSION/INPUT.ROUTINE
Cross-validation of a record. In this example user will be forced to input something to either
debit.their.ref or credit.their.ref.
Step 1. Routine:

SUBROUTINE SOME.TEST
* T24 input routine
$INSERT I_COMMON
$INSERT I_EQUATE
$INSERT I_F.FUNDS.TRANSFER

IF NOT(R.NEW(FT.DEBIT.THEIR.REF)) \
AND NOT(R.NEW(FT.CREDIT.THEIR.REF)) THEN
AF = FT.DEBIT.THEIR.REF
ETEXT = 'ENTER EITHER THIS OR CREDIT REF'
CALL STORE.END.ERROR
AF = FT.CREDIT.THEIR.REF
ETEXT = 'ENTER EITHER THIS OR DEBIT REF'
CALL STORE.END.ERROR
END

RETURN
END

Step 2. Create EB.API record.


Step 3. Attach routine:

Model Bank VERSION SEE

PGM.NAME.VERSION.. FUNDS.TRANSFER,TEST
------------------------------------------------------------------------------
63. 1 INPUT.ROUTINE.. SOME.TEST

REM Page 173


Input FT deal, commit:

Model Bank FUNDS.TRANSFER,TEST INPUT REF FT102212RNZX

------------------------------------------------------------------------------
1 TRANSACTION.TYPE.. AC Account Transfer
2 DEBIT.ACCT.NO..... 13487 Sears Roebuck
3 IN.DEBIT.ACCT.NO..
4 CURRENCY.MKT.DR... 1 Currency Market
5 DEBIT.CURRENCY.... EUR Euro
6 DEBIT.AMOUNT...... 150.00
7 DEBIT.VALUE.DATE.. 09 AUG 2010
8 IN.DEBIT.VDATE....
9 DEBIT.THEIR.REF... ENTER EITHER THIS OR CREDIT REF
10 CREDIT.THEIR.REF.. ENTER EITHER THIS OR DEBIT REF
11 CREDIT.ACCT.NO.... 40827 Jacob Eur Ac

12.8 VERSION/AUTH.ROUTINE
Performs custom checks, update of local tables etc at authorisation stage. In this example
user will not be allowed to authorise any record using this VERSION:
Step 1. Routine:

SUBROUTINE SOME.TEST
* T24 authorisation routine
$INSERT I_COMMON
$INSERT I_EQUATE

E = 'USE OTHER VERSION TO AUTHORISE'

RETURN
END

Step 2. Create EB.API record.


Step 3. Attach routine:

Model Bank VERSION SEE

PGM.NAME.VERSION.. FUNDS.TRANSFER,TEST
------------------------------------------------------------------------------
64. 1 AUTH.ROUTINE .. SOME.TEST

REM Page 174


Input FT deal, commit, log in as another user, try to authorise:

Model Bank FUNDS.TRANSFER,TEST AUTHORISE REF FT10221DWT58

------------------------------------------------------------------------------
1 TRANSACTION.TYPE.. AC Account Transfer
2 DEBIT.ACCT.NO..... 13487 Sears Roebuck
4 CURRENCY.MKT.DR... 1 Currency Market
5 DEBIT.CURRENCY.... EUR Euro
6 DEBIT.AMOUNT...... 150.00
7 DEBIT.VALUE.DATE.. 09 AUG 2010
11 CREDIT.ACCT.NO.... 40827 Jacob Eur Ac
12 CURRENCY.MKT.CR... 1 Currency Market
13 CREDIT.CURRENCY... EUR Euro
15 CREDIT.VALUE.DATE. 09 AUG 2010
18 PROCESSING.DATE... 09 AUG 2010
44 CHARGE.COM.DISPLAY
45 COMMISSION.CODE... DEBIT PLUS CHARGES
49 CHARGE.CODE....... DEBIT PLUS CHARGES
55 PROFIT.CENTRE.CUST 100295 Sears Roebuck
57 RETURN.TO.DEPT.... NO
------------------------------------------------------------------------------
18 NOV 2011 22:09:50 USER (09 AUG) VLADIMIR.K [3161,INPAGE 1 >>>3>>>
ACTION USE OTHER VERSION TO AUTHORISE
AWAITING PAGE INSTRUCTIONS

12.9 VERSION/AFTER.UNAU.RTN, BEFORE.AUTH.RTN


Never used that. Other VERSION hooks listed above were enough.

12.10 ENQUIRY/BUILD.ROUTINE
Here we are able to create or amend a selection criteria for an enquiry, as well as to raise an
error. In this example a selection will be required from a user; if it starts with “USER.NAME
LK” then it will be amended to “USER.NAME LK A... D...”

REM Page 175


Step 1. Routine:

SUBROUTINE SOME.TEST(P.ENQ)
* T24 build routine for ENQUIRY
$INSERT I_COMMON
$INSERT I_EQUATE
$INSERT I_ENQUIRY.COMMON

IF P.ENQ<2,1> EQ '' THEN ;* no selections were input


ENQ.ERROR = 'PLEASE PROVIDE SELECTION'
END ELSE
IF P.ENQ<2,1> EQ 'USER.NAME' AND P.ENQ<3,1> EQ 'LK' THEN
P.ENQ<4,1> = ''
P.ENQ<4,1,1> = 'A...'
P.ENQ<4,1,2> = 'D...'
END
END

RETURN
END

Step 2. Attach routine:

Model Bank ENQUIRY, INPUT

ENQUIRY........... USER
------------------------------------------------------------------------------
12. 1 BUILD.ROUTINE.. SOME.TEST

Test case 1:

Model Bank ENQUIRY INPUT

SELECT NAME....... USER


------------------------------------------------------------------------------
1. 1 SELECTION.TYPE.
2. 1 SELECTION.FIELD USER.NAME
3. 1 OPERAND........
4. 1. 1 LIST........
1. 2 SELECTION.TYPE.
2. 2 SELECTION.FIELD DEPARTMENT.CODE
3. 2 OPERAND........
4. 2. 1 LIST........
1. 3 SELECTION.TYPE.
2. 3 SELECTION.FIELD START.DATE.PROFILE
3. 3 OPERAND........
4. 3. 1 LIST........
1. 4 SELECTION.TYPE.

REM Page 176


2. 4 SELECTION.FIELD END.DATE.PROFILE
3. 4 OPERAND........
4. 4. 1 LIST........
------------------------------------------------------------------------------
17 NOV 2011 23:10:02 USER (09 AUG) VLADIMIR.K [8127,IN
ACTION PLEASE PROVIDE SELECTION

Return to “AWAITING APPLICATION” prompt; launch enquiry again. Test case 2, screen 1:

Model Bank ENQUIRY INPUT

SELECT NAME....... USER


------------------------------------------------------------------------------
1. 1 SELECTION.TYPE.
2. 1 SELECTION.FIELD USER.NAME
3. 1 OPERAND........ LK
4. 1. 1 LIST........ C...

Test case 2, screen 2:

Model Bank
List of T24 Users

------------------------------------------------------------------------------
1 ABI1 ABINAN.1 ABINAN.1
2 ACCTEXEC Account Executive ACCTEXEC1
3 AUTHORISER AUTHORISER AUTHOR
4 BUILDUSER279 AUTHORISER GOPIRAM
5 DEALER01 DEALER1 DEALER1
6 DXBO DX Back Office User DXBOUSER
7 DXMO DXMO DXMOUSER
8 DXO DX Front Office User DXOUSER
9 GOPIRAMK AUTHORISER GOPI123

------------------------------------------------------------------------------
17 NOV 2011 23:11:13 USER (09 AUG) VLADIMIR.K [8127,INPAGE 1 >>>1>>>
ACTION
AWAITING PAGE INSTRUCTIONS

REM Page 177


12.11 ENQUIRY/CONVERSION routine
Change a field of an enquiry. In this example all amounts greater than 100000 will be
displayed as “A LOT”.
Step 1. Routine:

SUBROUTINE SOME.TEST
* T24 conversion routine for ENQUIRY
$INSERT I_COMMON
$INSERT I_EQUATE
$INSERT I_ENQUIRY.COMMON

IF O.DATA GT 100000 THEN O.DATA = 'A LOT'

RETURN
END

Step 2. Attach routine:

Model Bank ENQUIRY SEE

ENQUIRY........... AC.TEST
------------------------------------------------------------------------------
1 PAGE.SIZE ........ 4,19
2 FILE.NAME......... ACCOUNT
14. 1 FIELD.NAME..... WORKING.BALANCE
15. 1. 1 OPERATION... WORKING.BALANCE
16. 1 COLUMN......... 4
17. 1 LENGTH.MASK.... 19R
18. 1. 1 CONVERSION.. @ SOME.TEST
35. 1 SINGLE.MULTI... S
14. 2 FIELD.NAME..... ID
15. 2. 1 OPERATION... @ID
16. 2 COLUMN......... 25
17. 2 LENGTH.MASK.... 19R
35. 2 SINGLE.MULTI... S

Run enquiry:

Model Bank

------------------------------------------------------------------------------
1 0 CHF141850697
2 0 CHF141850746
3 0 CHF141850786
4 0 CHF141850833
5 CHF141850963

REM Page 178


6 0 CHF141950577
7 8900 CHF141970001
8 9200 CHF141970002
9 168.3 CHF141980001
10 79.35 CHF141980002
11 -250000 CHF143020001
12 A LOT CHF143020002
13 A LOT CHF143020003
14 -375000 CHF143020004
15 0 CHF143040006
16 0 CHF143040011
------------------------------------------------------------------------------

12.12 NOFILE enquiry


When selection is to be done from more than one file – here we are. This example shows how
to display data from both HELPTEXT.MENU and HELPTEXT.MAINMENU.
Step 1. Routine:

SUBROUTINE NOFILE.TEST(P.LIST)
* T24 nofile enquiry routine
$INSERT I_COMMON
$INSERT I_EQUATE
$INSERT I_ENQUIRY.COMMON

HUSH ON
EXECUTE 'SELECT F.HELPTEXT.MAINMENU' RTNLIST V.LIST.1
EXECUTE 'SELECT F.HELPTEXT.MENU' RTNLIST V.LIST.2
HUSH OFF

V.LEN.1 = DCOUNT(V.LIST.1, FM)


V.LEN.2 = DCOUNT(V.LIST.2, FM)

FOR V.I = 1 TO V.LEN.1


P.LIST<-1> = '1*' : V.LIST.1<V.I>
NEXT V.I

FOR V.I = 1 TO V.LEN.2


P.LIST<-1> = '2*' : V.LIST.2<V.I>
NEXT V.I

RETURN
END

Step 2. SS record:

Model Bank STANDARD SELECTION FIELDS SEE

FILE.NAME......... NOFILE.TEST

REM Page 179


------------------------------------------------------------------------------
15. 1 USR.FIELD.NAME. OUTPUT
16. 1 USR.TYPE....... R
17. 1. 1 USR.FIELD.NO NOFILE.TEST
20. 1 USR.DISPLAY.FMT 75L
24. 1 USR.SINGLE.MULT S
15. 2 USR.FIELD.NAME. DATAFLD
16. 2 USR.TYPE....... D
17. 2. 1 USR.FIELD.NO 0
20. 2 USR.DISPLAY.FMT 75L
24. 2 USR.SINGLE.MULT S
35 CURR.NO........... 4
36. 1 INPUTTER....... 4924_VLADIMIR.K_I_INAU
37. 1 DATE.TIME...... 18 NOV 11 18:13
37. 2 DATE.TIME...... 18 NOV 11 18:13
38 AUTHORISER........ 4924_VLADIMIR.K
39 CO.CODE........... GB-001-0001 Model Bank
------------------------------------------------------------------------------
18 NOV 2011 18:46:30 USER (09 AUG) VLADIMIR.K [5502,INPAGE 1 >>>2>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Step 3. ENQUIRY:
Model Bank ENQUIRY SEE

ENQUIRY........... MENUTEST
------------------------------------------------------------------------------
1 PAGE.SIZE ........ 4,19
2 FILE.NAME......... NOFILE.TEST
3. 1 FIXED.SELECTION OUTPUT LK ...
14. 1 FIELD.NAME..... SOURCE
15. 1. 1 OPERATION... DATAFLD
16. 1 COLUMN......... 4
17. 1 LENGTH.MASK.... 20L
18. 1. 1 CONVERSION.. F *,1
18. 1. 2 CONVERSION.. SUBSTITUTE 1,HELPTEXT.MAINMENU
18. 1. 3 CONVERSION.. SUBSTITUTE 2,HELPTEXT.MENU
14. 2 FIELD.NAME..... NAME
15. 2. 1 OPERATION... DATAFLD
16. 2 COLUMN......... 26
17. 2 LENGTH.MASK.... 35L
18. 2. 1 CONVERSION.. F *,2
40 PAGE.FIELDS.......
------------------------------------------------------------------------------
18 NOV 2011 18:48:54 USER (09 AUG) VLADIMIR.K [5502,INPAGE 1 >>>2>>>
ACTION
AWAITING PAGE INSTRUCTIONS

REM Page 180


Enquiry execution:

Model Bank

------------------------------------------------------------------------------
HELPTEXT.MAINMENU 164
HELPTEXT.MAINMENU 66
HELPTEXT.MAINMENU 501
HELPTEXT.MAINMENU 100
HELPTEXT.MAINMENU 1
HELPTEXT.MAINMENU 500
HELPTEXT.MENU LC.ENQUIRIES
HELPTEXT.MENU RL.AUTH.HOME.PAGE
HELPTEXT.MENU TF.EXLCTRF
HELPTEXT.MENU FOREX.CONFIRM
HELPTEXT.MENU TELLER.DEPOSIT
HELPTEXT.MENU MF.POS.ENQ
HELPTEXT.MENU LI.GRP.MENU
HELPTEXT.MENU CHQ.COLL.HP.AUTH
HELPTEXT.MENU AI.CORP.SWEEP
HELPTEXT.MENU BLOCK.PF.CASH.FO
------------------------------------------------------------------------------
18 NOV 2011 18:50:04 USER (09 AUG) VLADIMIR.K [5502,INPAGE 1 >>>3>>>
ACTION
AWAITING PAGE INSTRUCTIONS

12.13 OFS.SOURCE/IN.MSG.RTN
Receives, optionally amends and returns full incoming OFS message. In this example we set
time restrictions for processing incoming OFS messages and supply default T24 login if it
absents.

REM Page 181


Step 1. Routine:

SUBROUTINE OFS.IN.RTN(P.MSG)
* T24 OFS in-message routine.
* We don't use I_COMMON and I_EQUATE variables here.
* Set time restriction (in conjunction with OUT.MSG.RTN -
* there's no known way to stop processing so we create
* an erroneous request that we analyse there)
V.TIME = OCONV(TIME(), 'MT')
IF V.TIME GT '18:00' THEN
P.MSG = 'SPF,/I/VALIDATE,INPUTT/123456,' : V.TIME : ',SITE.NAME::=QWERTZ'
RETURN
END

* Supply default login information (of course not recommended in production)


CHANGE ',' TO @FM IN P.MSG
IF P.MSG<3> EQ '' THEN P.MSG<3> = 'INPUTT/123456'
CHANGE @FM TO ',' IN P.MSG

RETURN
END

note: Of course storing the pasword in the source code isn’t the way to go.

Step 2. Create PGM.FILE record (type “S”).


Step 3. Attach routine:

Model Bank OFS SOURCE, INPUT

SOURCE.NAME....... TAG
------------------------------------------------------------------------------
9 IN.MSG.RTN........ OFS.IN.RTN

Run:
tSS TAG

CONTEXT.ENQUIRY,/I/PROCESS,,ACCOUNT,ENQ.DESC:1:1=Statement |summary| list

ACCOUNT//1,DESCRIPTION:1:1=Account Enquiries,ENQUIRY.NAME:1:1=ACCT.STMT.HIST,EN
QUIRY.NAME:2:1=ACCT.BAL.TODAY,ENQUIRY.NAME:3:1=NOSTRO.FWD.BAL,ENQUIRY.NAME:4:1=
STMT.ENT.TODAY,SEL.FIELD:1:1=STMT.ACCOUNT.NO,SEL.FIELD:2:1=ACCOUNT.NUMBER,SEL.F
IELD:3:1=ACCOUNT.ID,SEL.FIELD:4:1=ACCOUNT.NUMBER,CONTEXT.TYPE:1:1=ENQUIRY,CONTE
XT.TYPE:2:1=ENQUIRY,CONTEXT.TYPE:3:1=ENQUIRY,CONTEXT.TYPE:4:1=ENQUIRY,ENQ.DESC:
1:1=Statement "summary" list,ENQ.DESC:2:1=Current balance information,ENQ.DESC:
3:1=Forward_movements,ENQ.DESC:4:1=Entries posted today,RECORD.STATUS:1:1=INAU,
CURR.NO:1:1=2,INPUTTER:1:1=152_INPUTTER__OFS_TAG,DATE.TIME:1:1=1111291754,CO.CO
DE:1:1=GB0010001,DEPT.CODE:1:1=56

REM Page 182


Run after “cut-over time”:

tSS TAG

CONTEXT.ENQUIRY,/I/PROCESS,,ACCOUNT,ENQ.DESC:1:1=Statement |summary| list

18:03//-1/NO,NO SPECIFIED VALUE

To make this error message more friendly – proceed with the OUT.MSG.RTN below.

12.14 OFS.SOURCE/OUT.MSG.RTN
Step 1. Routine:

SUBROUTINE OFS.OUT.RTN(P.MSG)
* T24 OFS out-message routine.

IF P.MSG MATCHES "2N':'2N'//-1/NO,NO SPECIFIED VALUE'" THEN


P.MSG = FIELD(P.MSG, ',', 1) : ',TIME NOT ALLOWED'
END

RETURN
END

Step 2. Create PGM.FILE record (type “S”).


Step 3. Attach routine:

Model Bank OFS SOURCE, INPUT

SOURCE.NAME....... TAG
------------------------------------------------------------------------------
10 OUT.MSG.RTN....... OFS.OUT.RTN

Run after “cut-over time”:

tSS TAG

CONTEXT.ENQUIRY,/I/PROCESS,,ACCOUNT,ENQ.DESC:1:1=Statement |summary| list

18:18//-1/NO,TIME NOT ALLOWED

REM Page 183


12.15 DE.MAPPING/ROUTINE
Can be used to amend the outward delivery data “on-the-fly”. In this example we’ll change
field 20 (transaction reference) in outward MT103 message generated from FT deal.
See how this field is created by T24.

Firstly look into DE.FORMAT.SWIFT:

Model Bank DE.FORMAT.SWIFT INPUT

ID................ 103.1.1 CUSTOMER CREDIT TRANSFER


------------------------------------------------------------------------------
1. 1 GB DESCRIPTION. CUSTOMER CREDIT TRANSFER
2 MESSAGE TYPE...... 103
3. 1 FIELD TAG...... 20
4. 1 FIELD NAME..... SENDER REF
5. 1. 1 CONVERSION..
6. 1 CALCULATION....
7. 1 MULTIPLES...... NO
8. 1 INWARD ROUTINE. NO
9. 1 OUTWARD ROUTINE NO
10. 1 HEADER NAME.... TRANS.REF

Note the value of field FIELD NAME (yes, this application has unusual space in some field
names) and go visit the application DE.MESSAGE where we can get the idea how not to
break the rules assigned to this field:

Model Bank DE.MESSAGE INPUT

MESSAGE.TYPE...... 103
------------------------------------------------------------------------------
1. 1 GB DESCRIPTION. CUSTOMER CREDIT TRANSFER
2 COPIES............ Y
3 TRANSLATION....... Y
4 DELETE............ Y
5 TEST.KEY.REQ...... NO
6 APPLICATION.QUEUE.
7. 1 FIELD.NAME..... SENDER REF
8. 1 LENGTH......... 16
9. 1 PRINT.TYPE..... A
10. 1 SINGLE.MULTI... S
11. 1 MANDATORY...... Y

REM Page 184


Now – DE.MAPPING:

Model Bank DE.MAPPING INPUT

ID................ 103.FT.1 CUSTOMER CREDIT TRANSFER


------------------------------------------------------------------------------
5. 1 INPUT.POSITION. 2.2
6. 1 INPUT.NAME.....
7. 1. 1 FIELD.DESCR.
8. 1 FIELD.NAME..... SENDER REF
9. 1 HEADER.NAME.... TRANS.REF

We now know that in so-called “handoff” the SWIFT field 20 corresponds to position “2.2”,
i.e. “record #2, field #2”. To amend it a subroutine must be written. (Note that population
of fields in handoff is in most cases hardcoded in the core so we just amend the existing value
on-the-fly.)
We’re going to add “T24” before FT @id which is usually placed into that field (it will not
exceed the limitation of 16 characters stipulated by DE.MESSAGE):

SUBROUTINE EXPAND.FT.REF(MAT HANDOFF.REC, ERR.MSG)


* T24 delivery mapping routine
HANDOFF.REC(2)<2> = 'T24' : HANDOFF.REC(2)<2>
RETURN
END

Compile the subroutine, then attach it:

Model Bank DE.MAPPING, INPUT

ID................ 103.FT.1
------------------------------------------------------------------------------
15.45 HEADER.POSITION
15.46 HEADER.POSITION
15.47 HEADER.POSITION
15.48 HEADER.POSITION
15.49 HEADER.POSITION
15.50 HEADER.POSITION
15.51 HEADER.POSITION
15.52 HEADER.POSITION
15.53 HEADER.POSITION
15.54 HEADER.POSITION
15.55 HEADER.POSITION
15.56 HEADER.POSITION
16 ROUTINE........... @EXPAND.FT.REF
17. 1 AC.FIELD.......

REM Page 185


Search FT (live or history) with “DELIVERY.OUTREF LK ...-103....”, copy that record and
commit it. See the result:
Model Bank FUNDS.TRANSFER SEE REF FT11104110WY

------------------------------------------------------------------------------
1 TRANSACTION.TYPE.. OT03 Outward SWIFT Payment
2 DEBIT.ACCT.NO..... 13315 GENERAL MOTORS
4 CURRENCY.MKT.DR... 1 Currency Market
5 DEBIT.CURRENCY.... USD US Dollar
7 DEBIT.VALUE.DATE.. 14 APR 2011
...
80. 2 DELIVERY.OUTREF D20120120024027272702-103.1.1 CABLE TO CUST

See the handoff (ENQ DE.HANDOFF.DETS):

Model Bank ENQUIRY INPUT

SELECT NAME....... DE.HANDOFF.DETS


------------------------------------------------------------------------------
1. 1 SELECTION.TYPE. <k>
2. 1 SELECTION.FIELD DELIVERY.REF
3. 1 OPERAND........ EQ
4. 1. 1 LIST........ D20120120024027272702
1. 2 SELECTION.TYPE. <d>
2. 2 SELECTION.FIELD MAPPING.KEY
3. 2 OPERAND........
4. 2. 1 LIST........

Model Bank Delivery Handoff Details

Position Field name Field Content


------------------------------------------------------------------------------
1 0.0 DELIVERY KEY D20120120024027272702
2 0.1 MAPPING.KEY 103.FTOT.1
3 0.2 BANK.DATE 20110414
4 1.1 TRANS TYPE OT03
5 1.2 13315
6 1.3
...
3 1.204
4 1.205
5 2.1 HDR - CUSTOMER 100464
6 2.2 SENDER REF T24FT11104110WY
7 2.3 HDR - LANGUAGE 1
8 2.4 USD

REM Page 186


Of course it would be nice to see the SWIFT message itself. Assuming that we hadn’t
started any delivery services yet, out message is now mapped but not formatted. Let’s check
DE.O.HEADER:

Model Bank OUTWARD DELIVERY HEADER SEE

DATE.TIME.STAMP... D20120120-02402-72727-02
------------------------------------------------------------------------------
1 MESSAGE TYPE...... 103
3 APPLICATION....... FTOT
4 DISPOSITION....... UNFORMATTED
...
21 TRANSACTION REF... T24FT11104110WY

To format it (and thus form the SWIFT message) we need to start the service SWIFT.OUT
(“debugger mode” was used for this sample).
Step 1:

Model Bank TSA.SERVICE, INPUT

SERVICE........... TSM
------------------------------------------------------------------------------
1. 1 DESCRIPTION.... TSM Record for running upgrade as service
2. 1 SERVER.NAME....
3. 1 WORK.PROFILE... TSM WORK LOAD PROFILE FOR TSM
4. 1 SERVER.STATUS..
5 USER.............. INPUTTER
6 SERVICE.CONTROL... START
7 REVIEW.TIME.......
8 TIME.OUT..........

Step 2:

Model Bank TSA.SERVICE, INPUT

SERVICE........... SWIFT.OUT
------------------------------------------------------------------------------
1. 1 DESCRIPTION.... DE FORMATTING SERVICE
2. 1 SERVER.NAME....
3. 1 WORK.PROFILE... DE.FORMATTING.SERVICE USED FOR DE FORMATTING SERVICE
4. 1 SERVER.STATUS..
5 USER.............. INPUTTER
6 SERVICE.CONTROL... START

REM Page 187


Step 3:

jsh --> START.TSM -DEBUG


START.TSM -DEBUG
tSA 15 -DEBUG
<como>
<agent>15</agent>
<processid>3656</processid>
<portno>39</portno>
Agent 15 started 20 JAN 12 20-42-48
Agent's Process id 3656
<servername>homepc</servername>
Running on server homepc PortNumber 39
<service name = TSM>
tSM -DEBUG

Service Profile SWIFT.OUT DE FORMATTING SERVICE (2)


TSM TSM Record for running upgrade as service (1)

Manually launch tSA 54 SWIFT.OUT


Manually launch tSA 55 SWIFT.OUT

Step 4 (in a new session):

jsh --> tSA 54


tSA 54
<como>
<agent>54</agent>
<processid>2480</processid>
<portno>40</portno>
Agent 54 started 20 JAN 12 20-43-20
Agent's Process id 2480
<servername>homepc</servername>
Running on server homepc PortNumber 40
<service name = SWIFT.OUT>
<process name = SWIFT.OUT>
<job name = DE.OUTWARD>
_SWIFT.OUT_DE.OUTWARD_54_20 JAN 2012_20:43:20_Standard multi-thread job
_SWIFT.OUT_DE.OUTWARD_54_20 JAN 2012_20:43:20_Calling load routine
_SWIFT.OUT_DE.OUTWARD_54_20 JAN 2012_20:43:21_SELECT F.SWIFT.OUT.LIST SAMPLE 100
Selected=1 time=0secs
_SWIFT.OUT_DE.OUTWARD_54_20 JAN 2012_20:43:23_SELECT F.SWIFT.OUT.LIST SAMPLE 100
Selected=0 time=0secs
...

REM Page 188


Now see that the message is formatted and its status is “waiting for acknowledgement”:

Model Bank OUTWARD DELIVERY HEADER SEE

DATE.TIME.STAMP... D20120120-02402-72727-02
------------------------------------------------------------------------------
1 MESSAGE TYPE...... 103
3 APPLICATION....... FTOT
4 DISPOSITION....... FORMATTED
...
21 TRANSACTION REF... T24FT11104110WY
23 TEST KEY REQ...... NO
25. 1 CARRIER ADDR NO SWIFT.1
...
32. 1 MSG DISPOSITION WACK

And – the message itself. In JED it wouldn’t look very well so:

SELECT F.DE.O.MSG.SWIFT LIKE "'D20120120024027272702'..."


1 Records selected

>COPY FROM F.DE.O.MSG.SWIFT TO &TEMP&


1 records copied

SELECT &TEMP& LIKE "'D20120120024027272702'..."


1 Records selected

>CT &TEMP&

Result:

D20120120024027272702.1
001 {1:F01DEMOGBPXAXXX.SN...ISN.}{2:I103BCITIT24XXXXN}{3:{108:xxxxx}}{4:
002 :20:T24FT11104110WY
003 :23B:CRED
004 :32A:110414EUR40000,00
005 :33B:EUR40000,00
006 :50F:/13315
007 1/General Motors
008 2/100 RENAISSANCE CENTRE
009 3/US/DETROIT
010 :53B:/D/EUR-IT-1223354566
011 :59:DREAM REALTY VENTURES INC
012 :70:PAYMENT OF INVOICE NO.23701
013 :71A:SHA
014 -}

REM Page 189


12.16 DE.DISP.CONTROL/FIELD.NAME
In this example we put to HOLD (HOLD in Delivery terms, not making RECORD.STATUS field
“IHLD”) all MT103 outward messages that have amount exceeding 100,000 in local currency.
Then these messages are to be released manually.
Check if disp.control is enabled:

Model Bank DE.PARM SEE

ID................ SYSTEM.STATUS
------------------------------------------------------------------------------
...
11 DISP CONTROL...... Y

REM Page 190


Routine (how to attach it is shown in its comments):

SUBROUTINE TEST.FT.DATA(HEADER.REC, OPERAND, CONDITION, RETURN.FLAG)


* Check MT103 if the amount exceeds 100,000 in local currency.
* Used in DE.DISP.CONTROL to put such message to HOLD:
* STATUS.KEY........ 2
* --------------------------------------------------------------
* 1. 1 FIELD.NAME..... APPLICATION
* 2. 1 OPERAND........ EQUAL
* 3. 1 CONDITION...... FTOT
* 1. 2 FIELD.NAME..... MESSAGE.TYPE
* 2. 2 OPERAND........ EQUAL
* 3. 2 CONDITION...... 103
* 1. 3 FIELD.NAME..... @TEST.FT.DATA
* 2. 3 OPERAND........ EQUAL
* 3. 3 CONDITION...... 1
*---------------------------------------------------------------
$INSERT I_COMMON
$INSERT I_EQUATE
$INSERT I_F.DE.HEADER ;* note non-standard INSERT file name
$INSERT I_F.FUNDS.TRANSFER

RETURN.FLAG = 0 ;* OK by default

* V.AMT = HEADER.REC<DE.HDR.AMOUNT> ;* no amount in 103 ;((


* Taking the amount from application

V.AMT = R.NEW(FT.CREDIT.AMOUNT)
IF NOT(V.AMT) THEN V.AMT = R.NEW(FT.DEBIT.AMOUNT)

V.CCY = HEADER.REC<DE.HDR.CURRENCY>
IF V.CCY NE LCCY THEN
V.LCY.AMT = ''
CALL MIDDLE.RATE.CONV.CHECK(V.AMT, V.CCY, '', 1, V.LCY.AMT, '', '')
END ELSE
V.LCY.AMT = V.AMT
END

IF V.LCY.AMT GT 100000 THEN RETURN.FLAG = 1

RETURN
END

Step 2. Take an FT from the previous example, copy it, make credit amount somewhat less
than 100,000 EUR (which amounts to somewhat more than 100,000 in local currency – USD)
and commit. See result in DE.O.HEADER:
Model Bank OUTWARD DELIVERY HEADER SEE

DATE.TIME.STAMP... D20120123-02177-72009-04
------------------------------------------------------------------------------

REM Page 191


1 MESSAGE TYPE...... 103
3 APPLICATION....... FTOT
4 DISPOSITION....... UNFORMATTED
...
31. 1 MSG STATUS..... HOLD

Release it manually:

Model Bank OUTWARD DELIVERY HEADER, INPUT

DATE.TIME.STAMP... D20120123-02177-72009-04
------------------------------------------------------------------------------
17 VALUE DATE........ 14 APR 2011
18 CURRENCY.......... EUR
19 AMOUNT............
20 DEPARTMENT........ 1
21 TRANSACTION REF... T24FT11104HQYBV
22 APPLICATION QUEUE.
23 TEST KEY REQ...... NO
24 INWARD PAY TYPE...
25. 1 CARRIER ADDR NO SWIFT.1
26. 1 COPY NUMBER.... 1-100464
27. 1 FRAME NUMBER... 1
28. 1 FORMAT......... 1
29. 1 MSG LANGUAGE... GB
30. 1 MSG PRIORITY... N
31. 1 MSG STATUS..... RELEASE
32. 1 MSG DISPOSITION
------------------------------------------------------------------------------

See the result (assuming that services are running):

DATE.TIME.STAMP... D20120123-02177-72009-04
------------------------------------------------------------------------------
1 MESSAGE TYPE...... 103
3 APPLICATION....... FTOT
4 DISPOSITION....... FORMATTED
...
32. 1 MSG DISPOSITION WACK

12.17 ACCOUNT.PARAMETER/ACCOUNTING.SUBRTN
This subroutine is triggered every time when any accounting entry (STMT.ENTRY or
CATEG.ENTRY) is created online. And note that if entries are created during COB –
it isn’t.
In the following example all new accounting entries will be copied to another file.

REM Page 192


Step 1. Routine:

SUBROUTINE ACCT.SUBR(P.ENT.TYPE, P.POST.TYPE, P.ENTRY.ID, P.ENTRY)


* T24 global accounting routine
$INSERT I_COMMON
$INSERT I_EQUATE

OPEN 'ALL.ENTRY' TO F.ENTRY ELSE RETURN


WRITE P.ENTRY TO F.ENTRY, P.ENT.TYPE : P.ENTRY.ID

RETURN
END

Step 2. Create PGM.FILE record (type “S”).


Step 3. Attach routine:

Model Bank Accounting Parameter SEE

KEY............... SYSTEM
------------------------------------------------------------------------------
39 ACCOUNTING.SUBRTN. ACCT.SUBR

Step 4. Create the target file for collecting entries:

CREATE-FILE ALL.ENTRY TYPE=J4 101 1

Log in, input and authorise FT deal. See results:

LIST ALL.ENTRY

STMT160470490350839.000001
STMT160470490350839.000002

LIST ALL.ENTRY USING DICT F.STMT.ENTRY

ALL.ENTRY.......... STMT160470490350839.000001
@ID................ STMT160470490350839.000001
STMT.ENTRY.ID...... STMT160470490350839.000001
ACCOUNT.NUMBER..... 20467
COMPANY.CODE....... GB0010001
AMOUNT.LCY......... 7800.00
TRANSACTION.CODE... 258
...

REM Page 193


12.18 EB.FREQUENCY/SPECIAL.ROUTINE
Possibility to create your own frequency. Here we’ll create a frequency that moves the date
to the next one which has an even day number.
Step 1. Routine:

SUBROUTINE FREQ.TEST
* T24 custome frequency routine
$INSERT I_COMMON
$INSERT I_EQUATE

V.DATE = COMI[1,8]
LOOP
CALL CDT('', V.DATE, '+1C')
IF INDEX('02468', V.DATE[8,1], 1) THEN EXIT
REPEAT
COMI = V.DATE : COMI[9,5]

RETURN
END

Step 2. Create PGM.FILE record (type “S”).


Step 3. Attach routine to a new record in EB.FREQUENCY application:

Model Bank EB.FREQUENCY SEE

FREQ.ID........... EVEND
------------------------------------------------------------------------------
1. 1 GB DESCRIPTION. EVEN DAYS ONLY
3 SPECIAL.ROUTINE... FREQ.TEST

Use (force user INPUTTER to change password on every 2nd , 4th , 6th ... etc day of month):

Model Bank USER PROFILE, INPUT

USER.ID........... INPUTTER
------------------------------------------------------------------------------
1 USER.NAME......... Inputter, yes it is
2 SIGN.ON.NAME...... INPUTT
3 CLASSIFICATION.... INT
4 LANGUAGE.......... 1 English
5. 1 COMPANY.CODE... GB0010001 Model Bank
5. 2 COMPANY.CODE... GB0010002 MF Lead Company
5. 3 COMPANY.CODE... GB0010003 MF Branch 1
5. 4 COMPANY.CODE... GB0010004 MF Branch 2
5. 5 COMPANY.CODE... SG0010001 Model Bank - Singapore
5. 6 COMPANY.CODE... EU0010001 Model Bank - Europe
6 DEPARTMENT.CODE... 56 Trade Finance Supervisor
7 PASSWORD.VALIDITY. EVEND

REM Page 194


Now press ←- :

7 PASSWORD.VALIDITY. 10 DEC 2011 EVEND 10 DEC 2011 EVEN DAYS ONLY

12.19 I-descriptors
Routines can be used in STANDARD.SELECTION fields with usr.type = I. This example
creates an I-descriptor that shows the difference (in work days) between processing date and
the current date for FUNDS.TRANSFER application.

SUBROUTINE FT.IDESC(P.RESULT, P.PROC.DATE)


*------------------------------------------------------------------
* T24 API.
* See how many work days ago the FT deal was processed.
* Binding:
* Model Bank STANDARD SELECTION FIELDS SEE
*
* FILE.NAME......... FUNDS.TRANSFER
* -----------------------------------------------------------------
* 15. n USR.FIELD.NAME. PROC.DIFF
* 16. n USR.TYPE....... I
* 17. n. 1 USR.FIELD.NO SUBR('FT.IDESC',PROCESSING.DATE)
* 20. n USR.DISPLAY.FMT 5R
* 24. n USR.SINGLE.MULT S
*------------------------------------------------------------------
* Can be used in ENQUIRY or jQL query like:
* LIST FBNK.FUNDS.TRANSFER$HIS PROC.DIFF
*------------------------------------------------------------------
$INSERT I_COMMON
$INSERT I_EQUATE

IF TODAY EQ 0 THEN
P.RESULT = '!!!' ;* need to log in and out of T24
RETURN ;* to obtain TODAY value
END

V.PR.DATE = P.PROC.DATE
V.DIFF = 'W' ;* or C for calendar days
CALL CDD('', TODAY, V.PR.DATE, V.DIFF)

P.RESULT = V.DIFF

RETURN
END

Output:

@ID...................... PROC.DIFF

FT11070870KS;1 -13

REM Page 195


FT1108400IF3;1 -8
FT11103ZQ4ZS;1 -1
FT11070ZZK94;1 -13
FT110703WVC7;1 -13
FT110730QG7K;1 -8
FT11070B74LX;1 -13

Can also use the following (and it doesn’t require SS binding):

LIST FBNK.FUNDS.TRANSFER$HIS EVAL "SUBR('FT.IDESC',PROCESSING.DATE)"

Adding logic outside the routine:

Model Bank STANDARD SELECTION FIELDS, INPUT

FILE.NAME......... FUNDS.TRANSFER
------------------------------------------------------------------------------
15. 1 USR.FIELD.NAME. PROC.DIFF
16. 1 USR.TYPE....... I
17. 1. 1 USR.FIELD.NO SUBR('FT.IDESC',PROCESSING.DATE);ABS(@1);
17. 1. 2 USR.FIELD.NO IF @2 LE 5 THEN @2 ELSE @2:' - time to review!'
18. 1. 1 USR.VAL.PROG
19. 1 USR.CONVERSION.
20. 1 USR.DISPLAY.FMT 25L

Result:

@ID...................... PROC.DIFF................

FT11070870KS;1 13 - time to review!


FT1108400IF3;1 8 - time to review!
FT11103ZQ4ZS;1 1
FT11070ZZK94;1 13 - time to review!
FT110703WVC7;1 13 - time to review!
FT11096PH7BD;1 5
FT110730QG7K;1 8 - time to review!

13 T24 API
13.1 CDD()
See I-descriptors sample right above.

REM Page 196


13.2 CDT(), REM()
CDT() returns the date which differs from the specified one by specified number of work or
calendar days.
REM() just writes a message to user (without any choice but “Y to continue”). Under Browser
outputs the message to resulting box without asking user to continue (or at least it did so
last time I checked).

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

V.DATE = TODAY
CALL CDT('', V.DATE, '31W')

TEXT = TODAY : '+31 work days=' : V.DATE


CALL REM

RETURN
END

Output:

20100809+31 work days=20100921

note: Negative difference, e.g. “-15C” is OK as well.


How not to use it (TODAY will be amended and it’s absolutely wrong):

SUBROUTINE SOME.TEST
$INSERT I_COMMON
$INSERT I_EQUATE

TEXT = TODAY
CALL REM ;* e.g. 20100809

CALL CDT('', TODAY, '31W') ;* that's absolutely wrong!

TEXT = TODAY
CALL REM ;* now 20100921

RETURN
END

REM Page 197


13.3 CFQ()

Get the next date according to specified frequency:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

start_date = '20130514M0617'
GOSUB ROLL.DATE ;* output: 20131017M0617
start_date = '20130517M0617'
GOSUB ROLL.DATE ;* output: 20131117M0617
RETURN

ROLL.DATE:
COMI = start_date
CALL CFQ
TEXT = COMI
CALL REM
RETURN

END

13.4 DISPLAY.MESSAGE()
Output something to predefined position of T24 Classic screen without waiting for user input
(used in core to output “TXN COMPLETE” etc). In this example we construct sort of progress
indicator:

SUBROUTINE SOME.TEST
* T24 mainline rtn
$INSERT I_COMMON
$INSERT I_EQUATE

FOR i = 1 TO 20000
IF MOD(i, 1000) EQ 0 THEN
CALL DISPLAY.MESSAGE('->' : i : '...', 2)
MSLEEP(500) ;* not to be too fast
END
NEXT i

RETURN
END

-- LAST SIGN.ON, DATE: 14 MAY 2013 TIME: 20:25 ATTEMPTS: 0 --------


14 MAY 2013 20:30:12 USER (14 APR) VLADIMIR.K [2325,IN->3000...
ACTION

REM Page 198


-- LAST SIGN.ON, DATE: 14 MAY 2013 TIME: 20:25 ATTEMPTS: 0 --------
14 MAY 2013 20:30:12 USER (14 APR) VLADIMIR.K [2325,IN->8000...
ACTION

13.5 DUP()
Checks for duplicates in multi- or subvalued field (in VERSION hooks).
Routine:

SUBROUTINE SOME.TEST
* T24 input routine
$INSERT I_COMMON
$INSERT I_EQUATE
$INSERT I_F.CUSTOMER

AF = Customer_OffPhone ;* on older releases use EB.CUS.OFF.PHONE


CALL DUP

RETURN
END

Test case:

Model Bank CUSTOMER,TEST INPUT

CUSTOMER.CODE..... 100112
------------------------------------------------------------------------------
33. 1 TEXT...........
34. 1 LEGAL.ID.......
35. 1 LEGAL.DOC.NAME.
36. 1 LEGA
37. 1 LEGAL.ISS.AUTH.
38. 1 LEGAL.ISS.DATE.
39. 1 LEGAL.EXP.DATE.
40. 1 OFF.PHONE...... (123)456-7890
40. 2 OFF.PHONE...... (123)456-7890 DUPLICATE
41 REVIEW.FREQUENCY..
42 BIRTH.INCORP.DATE.
43 GLOBAL.CUSTOMER...
44 CUSTOMER.LIABILITY
45 LANGUAGE.......... 1 English
46 POSTING.RESTRICT..
47 DISPO.OFFICER.....
------------------------------------------------------------------------------
20 DEC 2011 21:44:31 USER (14 APR) VLADIMIR.K [2002,INPAGE 3 >>12>>>
ACTION

REM Page 199


13.6 EB.ROUND.AMOUNT()
Use it after calculations with amounts to avoid something like 12.349999987 to end up in a
table field.

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

amount = 1234.56
charge_amt = amount * 0.001

currency = LCCY
method = ''
TEXT = 'Default LCCY rounding'
GOSUB DO.IT ;* 1.23
currency = 'JPY'
method = ''
TEXT = 'Default JPY rounding'
GOSUB DO.IT ;* 1
currency = LCCY
method = 1 :FM: 'U'
TEXT = 'LCCY cash rounding (up)'
GOSUB DO.IT ;* 1.24
currency = 'EUR'
method = 1 :FM: 'D'
TEXT = 'EUR cash rounding (down)'
GOSUB DO.IT ;* 1.23

RETURN

DO.IT:
result = charge_amt
CALL EB.ROUND.AMOUNT(currency, result, method, '')
TEXT := ': ' : result
CALL REM
RETURN
END

13.7 EB.SET.NEXT.TASK(), EB.SET.NEW.TASK()


Launch a new application, enquiry etc after finishing a transaction:

SUBROUTINE SOME.TEST
* T24 input routine
$INSERT I_COMMON
$INSERT I_EQUATE

CALL EB.SET.NEXT.TASK(C.U : ' ENQ USER')

RETURN
END

REM Page 200


EB.SET.NEXT.TASK works under Browser as well. EB.SET.NEW.TASK works under Browser
only and, unlike EB.SET.NEXT.TASK, will open a new window without closing an existing
one.
note: Leading C.U and a space aren’t necessary under Browser.

13.8 ENQUIRY.DISPLAY()
Launch ENQUIRY from mainline routine:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

dyn_array<1> = 'USER'
dyn_array<2,1> = 'USER.NAME'
dyn_array<3,1> = 'LK'
dyn_array<4,1,1> = 'C...'
CALL ENQUIRY.DISPLAY(dyn_array)

RETURN
END
Run routine from AWAITING APPLICATION level:
Model Bank
List of T24 Users

------------------------------------------------------------------------------
1 CALLCENTRE1 Call Centre Agent CALLCENTRE
2 CHEQUESMANAGER CHEQUES MANAGER RETAILMGR01
3 CHEQUESOFFICER CHEQUES OFFICER RETAILOFF01
4 COMPOFFICER Compliance Officer COMPOFF
5 CORPMANAGER CORPMANAGER CORP.MGR
6 CORPOFFICER CORPOFFICER CORP.OFF
7 CREDITMANAGER CREDIT MANAGER CREDITMGR
8 CREDITMANAGER1 Credit Manager CREDITMANAGER
9 CREDITMGR Credit Manager CREDITMGR1
10 CREDITOFF Credit Officer CREDITOFF1
11 CREDITOFFICER CREDIT OFFICER CREDITOFF
12 CREDITOFFICER1 Credit Officer CREDITOFFICER
13 CSAGENT1 Customer Service Agent CSAGENT
14 CSREP Customer Service Representative CSREP1
15 CSS Customer Service Supervisor CSS123

------------------------------------------------------------------------------

note: BUILD routine won’t be launched.

REM Page 201


13.9 FATAL.ERROR()
SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

TEXT = 'VERY SERIOUS ERROR'


CALL FATAL.ERROR(SYSTEM(40))

RETURN
END

Runtime:

-- LAST SIGN.ON, DATE: 24 JAN 2012 TIME: 22:24 ATTEMPTS: 0 --------


24 JAN 2012 23:26:47 USER (14 APR) VLADIMIR.K [6572,IN]
ACTION

** FATAL ERROR IN (SOME.TEST) **


VERY SERIOUS ERROR

jsh -->

F.PROTOCOL record is created in this case:

001 20110414
002 1
003 232650
004 23:26:50:646
005 6572
006
007 GB0010001
008 VLADIMIR.K
009 SOME.TEST
010 1
011
012 VERY SERIOUS ERROR
013

REM Page 202


13.10 F.READ()

Read a record from file or cache.

SUBROUTINE SOME.TEST
* T24 mainline rtn
$INSERT I_COMMON
$INSERT I_EQUATE

acct_file = 'F.ACCOUNT' ; f_acct = ''


CALL OPF(acct_file, f_acct)
query = 'SSELECT ' : acct_file : ' TO 9'
HUSH ON ; EXECUTE query ; HUSH OFF

LOOP
READNEXT acct_id FROM 9 ELSE BREAK
acct_rec = ''
CALL F.READ(acct_file, acct_id, acct_rec, f_acct, '')
IF acct_rec EQ '' THEN
TEXT = 'COULD NOT READ ID=&' :FM: acct_id
CALL REM
END
REPEAT

RETURN
END

note: F.READ() is able to read an account from another company, see the next screen:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE
$INSERT I_F.ACCOUNT

acct_id = '2000000429'
acct_file = 'F.ACCOUNT' ; f_acct = '' ; CALL OPF(acct_file, f_acct)
CALL F.READ(acct_file, acct_id, acct_rec, f_acct, '')

TEXT = acct_rec<Account_AccountTitle1>
CALL REM ;* AUDIGBPSW3

* Check if we can access this account using manual input.


* We are at "AWAITING APPLICATION" level in a mainline routine
* so we don't need 'C.U ' in the call to EB.SET.NEXT.TASK:

CALL EB.SET.NEXT.TASK('AC S ' : acct_id) ;* 'INVALID ID FOR COMPANY'

RETURN
END

REM Page 203


13.11 F.READU(), F.WRITE(), F.RELEASE()
Read a record with the lock, write the changes back or release without writing respectively.

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

locking_id = 'USER.COUNTER' ;* ID can be non-existing one.


retry = 'R 01 05' ;* Retry 5 times with 1-second delay.
;* Other options are: 'E' - return with error message,
;* 'P msg' - prompt user to retry, 'I' - ignore,
;* '' - try each second continuously.
* No need to open F.LOCKING - it's opened by core already
CALL F.READU('F.LOCKING', locking_id, locking_rec, F.LOCKING, error_code, retry)
IF error_code AND error_code NE 'RECORD NOT FOUND' THEN
TEXT = error_code
CALL REM
RETURN
END

* Increase the counter but only if it's an odd number


counter = locking_rec<1>
IF counter EQ '' THEN counter = 1
ELSE
IF MOD(counter, 2) NE 0 THEN
CALL F.RELEASE('F.LOCKING', locking_id, F.LOCKING)
GOSUB SET.NEXT.TASK
RETURN
END ELSE counter ++
END
locking_rec<1> = counter

* Write the result


CALL F.WRITE('F.LOCKING', locking_id, locking_rec)
CALL JOURNAL.UPDATE(SYSTEM(40)) ;* mainline routine requires that
* (no need in F.RELEASE() here)

GOSUB SET.NEXT.TASK
RETURN

SET.NEXT.TASK:
CALL EB.SET.NEXT.TASK('LOCKING S ' : locking_id)
RETURN
END
Run this routine one or more times; output will be:

KEY............... USER.COUNTER
-------------------------------------
1. 1 CONTENT........ 1

REM Page 204


Then edit the record contents (JED F.LOCKING USER.COUNTER, set its value to, e.g., 1000.
Run routine again. Output:

KEY............... USER.COUNTER
-------------------------------------
1. 1 CONTENT........ 1001

13.12 F.DELETE()
In this example the record created in the example right above will be deleted.

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

locking_id = 'USER.COUNTER'
retry = 'P' ;* Prompt user: record locked by... retry Y/N?
CALL F.READU('F.LOCKING', locking_id, R.LOCKING, F.LOCKING, error_code,
retry)
IF error_code AND error_code NE 'RECORD NOT FOUND' THEN
TEXT = error_code
CALL REM
RETURN
END

IF error_code EQ 'RECORD NOT FOUND' THEN RETURN


CALL F.DELETE('F.LOCKING', locking_id)
CALL JOURNAL.UPDATE(SYSTEM(40))

CALL EB.SET.NEXT.TASK('LOCKING S ' : locking_id) ;* RECORD MISSING

RETURN
END

13.13 GET.STANDARD.SELECTION.DETS()
Gets SS record and merges system and user fields. The following example resolves local
references’ names to numbers.

REM Page 205


Standard subroutine:

SUBROUTINE TEST.SUB(the_app, lref_name, lref_num)


* regular T24 subroutine
$INSERT I_F.STANDARD.SELECTION ;* this one is enough

CALL GET.STANDARD.SELECTION.DETS(the_app, ss_rec)

FIND lref_name IN ss_rec<SSL.SYS.FIELD.NAME> SETTING field_posn,


value_posn ELSE
lref_num = -1
RETURN
END
lref_num = FIELD(FIELD(ss_rec<SSL.SYS.FIELD.NO, value_posn>, ',', 2),
'>', 1)
RETURN
END

Calling subroutine:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

CALL TEST.SUB('CUSTOMER', 'CU.EFF.DATE', cu_eff_date_posn)


TEXT = cu_eff_date_posn ; CALL REM ;* 2
CALL TEST.SUB('MD.DEAL', 'CL.LODGED.CUST', md_lcust_posn)
TEXT = md_lcust_posn ; CALL REM ;* 3

RETURN
END

REM Page 206


13.14 LOAD.COMPANY()

Makes another company to be the current one and loads its environment:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

GOSUB AC.OPEN ;* FBNK.ACCOUNT


CALL LOAD.COMPANY('EU0010001')
GOSUB AC.OPEN ;* FEU1.ACCOUNT
RETURN ;* after that we stay in another company
;* and screen header changes to reflect that
AC.OPEN:
acct_file = 'F.ACCOUNT' ; f_acct = ''
CALL OPF(acct_file, f_acct)
TEXT = acct_file ; CALL REM
RETURN

END

REM Page 207


13.15 IN2()

There are many of them – see the appropriate manual; here’s in2d() example:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

COMI = '20111231'
GOSUB DO.CHECK ;* 20111231
COMI = '20110229'
GOSUB DO.CHECK ;* EB.RTN.DATE.DOES.NOT.EXIST
COMI = '2011001'
GOSUB DO.CHECK ;* EB.RTN.INVALID.DATE.LENGTH
COMI = '19171108'
GOSUB DO.CHECK ;* EB.RTN.YEAR.CANT.PRECEDE.1950
COMI = '171108'
GOSUB DO.CHECK ;* 20081117
COMI = '20111313'
GOSUB DO.CHECK ;* EB.RTN.MONTH.CAN..11
COMI = '2011/12/31'
GOSUB DO.CHECK ;* 20111231
COMI = '31 MAY 2013'
GOSUB DO.CHECK ;* 20130531
RETURN

DO.CHECK:
CALL IN2D('D', 11)
IF ETEXT THEN TEXT = ETEXT
ELSE TEXT = COMI ;* processed value
CALL REM
RETURN

END

13.16 OFS.GLOBUS.MANAGER()
Synchronous creation of OFS message. Safe to use everywhere with “VALIDATE” option, in
mainline routine and in “Verify” section of “W” template.

REM Page 208


Routine:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

ofs_message = 'DL.DEFINE,/I/PROCESS,INPUTT/123456,TESTDLDEF,'
ofs_message := 'DESCRIPTN::=THE TEST ONE,SHORT.DESC::=TEST,'
ofs_message := 'FILE.NAME:1:=ACCOUNT.PARAMETER,RECORD.NAME:1:=SYSTEM'

CALL OFS.GLOBUS.MANAGER('TAG', ofs_message) ;* 'TAG' is OFS.SOURCE id


TEXT = ofs_message[1,65]
CALL REM
CALL EB.SET.NEXT.TASK('DL.DEFINE S TESTDLDEF')

RETURN
END

Runtime. Screen 1:
------------------------------------------------------------------------------
24 JAN 2012 20:50:23 USER (14 APR) VLADIMIR.K [6413,IN]
ACTION
CONTINUE (Y) TMNS000-TESTDLDEF//1,DESCRIPTN:1:1=THE TEST ONE,SHORT.DESC:1:1=TE

Screen 2:
Model Bank. R11.000 DL.DEFINE SEE

UNIT.NAME......... TMNS000-TESTDLDEF
------------------------------------------------------------------------------
1. 1. 1 GB DESCRIPTN THE TEST ONE
2. 1 GB SHORT.DESC.. TEST
5 OPERATION......... S
9. 1 FILE.NAME...... ACCOUNT.PARAMETER
10. 1 RECO SYSTEM
31. 1 DATE.TIME...... 05 JUN 13 19:40
32 AUTHORISER........ 7265_INPUTTER_OFS_TAG
33 CO.CODE........... GB-001-0001

------------------------------------------------------------------------------

REM Page 209


In case of an error your screen 1 can be:

------------------------------------------------------------------------------
05 JUN 2013 19:42:33 USER (14 APR) VLADIMIR.K [4081,IN]
ACTION
CONTINUE (Y) SECURITY VIOLATION DURING SIGN ON PROCESS

You can even specify non-existing OFS.SOURCE record – the only thing that is necessary
is syntax type (OFS or XML) that is supplied in field 2. The following routine updates the
record that was created in the previous example:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

ofs_message = 'DL.DEFINE,/I/PROCESS,INPUTT/123456,TESTDLDEF,'
ofs_message := 'FILE.NAME:2:=MD.PARAMETER,'
ofs_message := 'RECORD.NAME:2:=GB0010001'

CALL OFS.GLOBUS.MANAGER('DUMMY' :FM: 'OFS', ofs_message)


TEXT = ofs_message[1,65]
CALL REM

RETURN
END

Result:

Model Bank. R11.000 DL.DEFINE SEE

UNIT.NAME......... TMNS000-TESTDLDEF
------------------------------------------------------------------------------
1. 1. 1 GB DESCRIPTN THE TEST ONE
2. 1 GB SHORT.DESC.. TEST
5 OPERATION......... S
9. 1 FILE.NAME...... ACCOUNT.PARAMETER
10. 1 RECO SYSTEM
9. 2 FILE.NAME...... MD.PARAMETER
10. 2 RECO GB0010001
31. 1 DATE.TIME...... 05 JUN 13 19:45
32 AUTHORISER........ 8973_VLADIMIR.K_OFS_DUMMY

13.17 OFS.POST.MESSAGE()
Asynchronous creation of OFS message.

REM Page 210


Routine:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

ofs_message = 'DL.DEFINE,/I/PROCESS,/,TESTDLDEF,DESCRIPTN::=THE TEST ONE,'


ofs_message := 'SHORT.DESC::=TEST,FILE.NAME:1:=ACCOUNT.PARAMETER,'
ofs_message := 'RECORD.NAME:1:=SYSTEM'
ofs_message_id = ''

CALL OFS.POST.MESSAGE(ofs_message, ofs_message_id, 'TAG', '')


CALL JOURNAL.UPDATE(SYSTEM(40))
TEXT = ofs_message_id
CALL REM ;* e.g. 160950936835505.00

RETURN
END

Result:

CT F.OFS.MESSAGE.QUEUE 160950936835505.00-TAG

160950936835505.00-TAG
001 DL.DEFINE,/I/PROCESS,/,TESTDLDEF,DESCRIPTN::=THE TEST ONE,SHORT.DESC::=TES
T,FILE.NAME:1:=ACCOUNT.PARAMETER,RECORD.NAME:1:=SYSTEM

note: OFS.MESSAGE.SERVICE is to be activated to proceed the message.

13.18 OPF(), TXTINP()


OPF() opens a file (or gets its handle from cache). File name is resolved according to its type
and current company:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

acct_file = 'F.ACCOUNT' ; f_acct = ''


CALL OPF(acct_file, f_acct)
TEXT = DQUOTE(acct_file)
CALL REM ;* "FBNK.ACCOUNT"

RETURN
END

REM Page 211


If file was recently opened, it will not be reopened. Run the following routine twice (without
logging out from T24). First time number of OPENs will increase by 1, second time it will
not:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

counter = 0 ; number_of_opens = ''


acct_file = 'F.ACCOUNT' ; f_acct = ''

GOSUB GET.OPENS
CALL OPF(acct_file, f_acct)
GOSUB GET.OPENS
TEXT = number_of_opens<2> - number_of_opens<1>; CALL REM
RETURN

GET.OPENS:
counter ++
user_stats = @USERSTATS
number_of_opens<counter> = user_stats<18>

RETURN
END

How not to get the fatal error if file doesn’t exist:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

CALL TXTINP('ENTER APPLICATION', 10, 22, '64', 'ANY')


the_app = COMI

history_file = 'F.' : the_app : '$HIS' ; f_hist = ''


CALL OPF(history_file :FM: 'NO.FATAL.ERROR', f_hist)
IF ETEXT THEN TEXT = 'HISTORY ABSENTS' ;* e.g. for ABBREVIATION
ELSE TEXT = 'HISTORY PRESENTS' ;* e.g. for ACCOUNT
CALL REM

RETURN
END

REM Page 212


Another TXTINP()-related example – non-visible input (as for passwords):

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

cword_save = T.CONTROLWORD
T.CONTROLWORD<1> = 'NV'
CALL TXTINP('ENTER PASSWORD', 10, 22, '64', 'ANY')
T.CONTROLWORD = cword_save

TEXT = 'YOU ENTERED "' : COMI : '"'


CALL REM

RETURN
END

13.19 OVE()
Similar to REM() but adds a choice:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

the_score = 100

TEXT = 'GAME OVER. WRITE YOUR SCORE (&) ?' :FM: the_score
CALL OVE
IF TEXT EQ 'Y' THEN
TEXT = 'Will do'
END ELSE
TEXT = 'No probs'
END
CALL REM

RETURN
END

REM Page 213


13.20 PRO()

Writes an entry to PROTOCOL application:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

CALL PRO('A note for audit')

RETURN
END

F.PROTOCOL record:

201201240160580314.00
001 20110414
002 1
003 225834
004 22:58:34:047
005 1605
006
007 GB0010001
008 VLADIMIR.K
009 SOME.TEST
010 1
011
012 A note for audit
013

13.21 STORE.END.ERROR()
See examples in the section “T24 hooks”.

REM Page 214


13.22 STORE.OVERRIDE()

Adds custom override to proceed along with core ones:

SUBROUTINE SOME.TEST
* T24 input routine
$INSERT I_COMMON
$INSERT I_EQUATE
$INSERT I_F.FUNDS.TRANSFER

IF R.NEW(FT.CREDIT.THEIR.REF) EQ '' THEN


V.NO = DCOUNT(R.NEW(FT.OVERRIDE), VM) + 1
AF = FT.CREDIT.THEIR.REF ;* field to return to if reply was NO
TEXT = 'CREDIT.THEIR.REF NOT SUPPLIED'
CALL STORE.OVERRIDE(V.NO) ;* V.NO=0 will remove all previous overrides
END

RETURN
END

Record after commit:

Model Bank FUNDS.TRANSFER SEE REF FT11104X8FQG

------------------------------------------------------------------------------
112 TOT.REC.COMM.LCL.. 0.00
113 TOT.REC.CHG....... 0
114 TOT.REC.CHG.LCL... 0.00
136 RATE.FIXING....... NO
148 TOT.REC.CHG.CRCCY. 0.00
149 TOT.SND.CHG.CRCCY. 0.00
153 AUTH.DATE......... 14 APR 2011
195. 1 STMT.NOS....... 160600876767533.00
195. 2 STMT.NOS....... 1-2
196. 1 OVERRIDE....... WITHDRAWL MAKES A/C BAL LESS THAN MIN BAL
196. 2 OVERRIDE....... Unauthorised overdraft of USD 14400 on account 40622.
196. 3 OVERRIDE....... CREDIT.THEIR.REF NOT SUPPLIED
198 CURR.NO........... 1
199. 1 INPUTTER....... 1251_VLADIMIR.K
200. 1 DATE.TIME...... 20 DEC 11 22:12
201 AUTHORISER........ 1251_VLADIMIR.K
------------------------------------------------------------------------------
20 DEC 2011 22:12:42 USER (14 APR) VLADIMIR.K [1251,INPAGE 3 >>>4>>>
ACTION
AWAITING PAGE INSTRUCTIONS

REM Page 215


If user answers “NO” to the override – commit isn’t possible:

Model Bank FUNDS.TRANSFER,TEST INPUT REF FT11104X8FQG

------------------------------------------------------------------------------
1 TRANSACTION.TYPE.. AC Account Transfer
2 DEBIT.ACCT.NO..... 40622 Dell Computer
3 IN.DEBIT.ACCT.NO..
4 CURRENCY.MKT.DR... 1 Currency Market
5 DEBIT.CURRENCY.... USD US Dollar
6 DEBIT.AMOUNT......
7 DEBIT.VALUE.DATE.. 14 APR 2011
8 IN.DEBIT.VDATE....
9 DEBIT.THEIR.REF...
10 CREDIT.THEIR.REF.. _ 'NO' REPLIED TO LOCAL OVERRIDE
11 CREDIT.ACCT.NO.... 20467 DELL COMPUTER
12 CURRENCY.MKT.CR... 1 Currency Market
13 CREDIT.CURRENCY... USD US Dollar
14 CREDIT.AMOUNT..... 7,800.00
15 CREDIT.VALUE.DATE. 14 APR 2011
16 TREASURY.RATE.....
------------------------------------------------------------------------------
20 DEC 2011 22:10:42 USER (14 APR) VLADIMIR.K [1251,INPAGE 3 >>>4>>>
ACTION
AWAITING PAGE INSTRUCTIONS

13.23 TXT()
Process a dynamic message.

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

message = 'READ ERROR, FILE [&], RECORD [&]' :FM: 'FBNK.ACCOUNT' :VM: 999999
CALL TXT(message)
* We don't call REM here since it has the same functionality itself; so:
CRT @(8,22):message
MSLEEP(5000)

RETURN
END

Output:

------------------------------------------------------------------------------
26 JAN 2012 19:49:31 USER (14 APR) VLADIMIR.K [1405,IN]

REM Page 216


ACTION READ ERROR, FILE [FBNK.ACCOUNT], RECORD [999999]

If we run it being logged in as non-English language user, a new record appears in application
DYNAMIC.TEXT so we can add the translation, authorise that record and next time see
the message in desired language:

Model Bank USER PROFILE SEE

USER.ID........... VLADIMIR.K1
------------------------------------------------------------------------------
1 USER.NAME......... V.KAZIMIRCHIK
2 SIGN.ON.NAME...... VLADIMIRK1
3 CLASSIFICATION.... INT
4 LANGUAGE.......... 3 German

Model Bank MESSAGE TEXT INPUT

BASE.TEXT......... READ.ERROR,.FILE.[&],.RECORD.[&]
------------------------------------------------------------------------------
1 GB TEXT 1 ........ READ ERROR, FILE [&], RECORD [&]
2 FR TEXT 2 ........
3 DE TEXT 3 ........
4 ES TEXT 4 ........
5 ...TEXT 5 ........
6 ...TEXT 6 ........
7 ...TEXT 7 ........
8 ...TEXT 8 ........
9 ...TEXT 9 ........
10 ...TEXT 10 .......
11 ...TEXT 11 .......
12 ...TEXT 12 .......
13 RECORD.STATUS..... INAU INPUT Unauthorised
14 CURR.NO........... 1
15. 1 INPUTTER....... ****SOME.TEST
16. 1 DATE.TIME...... 26 JAN 2012 19:55
------------------------------------------------------------------------------
26 JAN 2012 19:56:11 USER (14 APR) VLADIMIR.K1 [5163,INPAGE 1 >>>2>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Model Bank MESSAGE TEXT, INPUT

BASE.TEXT......... READ.ERROR,.FILE.[&],.RECORD.[&]
------------------------------------------------------------------------------
1 GB TEXT 1 ........ READ ERROR, FILE [&], RECORD [&]
2 FR TEXT 2 ........

REM Page 217


3 DE TEXT 3 ........ Lesefehler, Datei [&], Rekord [&]
4 ES TEXT 4 ........
5 ...TEXT 5 ........

-- LAST SIGN.ON, DATE: 26 JAN 2012 TIME: 19:55 ATTEMPTS: 0 --------


26 JAN 2012 20:02:48 USER (14 APR) VLADIMIR.K1 [1519,IN]
ACTION Lesefehler, Datei [FBNK.ACCOUNT], Rekord [999999]

Here’s the idea of a dynamic message – we don’t need to do the translation every time when
a new file name and/or record @id appears in a message. Let’s amend the routine:

SUBROUTINE SOME.TEST
* T24 mainline routine
$INSERT I_COMMON
$INSERT I_EQUATE

TEXT = 'READ ERROR, FILE [&], RECORD [&]' :FM: 'FBNK.CUSTOMER' :VM: 12345
CALL REM

RETURN
END
Output:
-- LAST SIGN.ON, DATE: 26 JAN 2012 TIME: 12:02 ATTEMPTS: 0 --------
26 JAN 2012 12:07:29 USER (14 APR) VLADIMIR.K1 [1840,IN]
ACTION
CONTINUE (Y) Lesefehler, Datei [FBNK.CUSTOMER], Rekord [12345]

14 How-tos
14.1 Get rid of speaker beeps in jsh (Windows)
Step 1. Edit file jbase nt.ti in %TAFC HOME%\src directory – comment “bel” setting:
#
# Definiton of the NT console, use by jBASE to give ANSI emulation
#
ntcon|dumb|ansi|NT console emulation,
am, xon,
cols#80, lines#24,
# bel=^G,
blink=\E[5m, bold=\E[1m, cbt=\E[Z,

Step 2: “compile” it running the command:


jtic full-path\jbase_nt.ti

note: TERM environment variable should match the section header – e.g. ntcon.

REM Page 218


14.2 Get rid of speaker beeps in T24 Classic
Edit the record EBS-JBASE in application TERMINAL – make field bell empty:

Model Bank TERMINAL, INPUT

TERMINAL.......... EBS-JBASE
------------------------------------------------------------------------------
17. 1 INIT.SEQUENCE.. <027>&oR
17. 2 INIT.SEQUENCE.. <027>[?67h
18. 1 FUNCTION.KEYS.. <27>&f2a1k6d1LRETURN<21>
18. 2 FUNCTION.KEYS.. <27>&f2a2k4d1LBACK<2>
18. 3 FUNCTION.KEYS.. <27>&f2a3k7d1LFORWARD<6>
18. 4 FUNCTION.KEYS.. <27>&f2a4k4d1LLAST<5>
18. 5 FUNCTION.KEYS.. <27>&f2a5k5d1LENTER<22>
18. 6 FUNCTION.KEYS.. <27>&f2a6k4d1LNEXT<23>
18. 7 FUNCTION.KEYS.. <27>&f2a7k4d1LLEFT<29>
18. 8 FUNCTION.KEYS.. <27>&f2a8k5d1LRIGHT<30>
19. 1 INIT.EXECUTES..
20 BELL..............
21 RESET............. <027>[0;1m
22 CURSOR.BACK.......
23 PRINT............. <027>[D
24 PRINT.ECHO........ <027>[C
------------------------------------------------------------------------------
08 DEC 2011 20:12:28 USER (14 APR) VLADIMIR.K [2797,INPAGE 2 >>>5>>>
ACTION
AWAITING PAGE INSTRUCTIONS

14.3 Automatically create the new file on target system when us-
ing DL.DEFINE
Just include FILE.CONTROL record for your application to DL.DEFINE. (If you transfer
records of your application as well, put FILE.CONTROL record before them.)

14.4 Correct the screen used in “L” function


Before:

Model Bank

------------------------------------------------------------------------------
1 100112 ABNAMRO Abn Amro Securities Chief Securities De| N|
2 100369 ABUDHAOIL Abu Dhabi National Oil Company Corporate Loan Supe| U|
3 111706 ADMIN Administrator Of Acorn Engg CompMortgage Dept User 2 U|
4 100396 AIRBOURNE Airbourne Freight Retail Credit Offic| R|
5 111405 AKAI AKAI Trade Finance Offic| J|

REM Page 219


6 111410 AKAIGBP AKAI Trade Finance Offic| J|
7 100349 ALBRECHTT Theo Albrecht Retail Credit Offic| G|
8 111683 ALEX Alex Branch Operations M| U|
9 100600 ALEXFL Alex Call Centre Agent U|
10 100301 ALLEGRA Allegra Corporate Officer U|
11 111421 ALLENG Allen Gerling Customer Service Ag| G|
12 100971 ALLIANCE Alliance Investment Managers Chief Securities De| U|
13 100433 AMEXINDONE American Express Indonesia Trade Finance Offic| I|
14 100435 AMEXPARIS American Express Paris Treasury Dealer F|
15 100436 AMEXSINGAP American Express Singapore Treasury Dealer S|
16 100437 AMEXUK American Express Uk Treasury Dealer G|
17--100265-AMVIRT -Virtual Customer for Am PWM Portfolio Advis|--U|-
180 1117421ANDY Andy Retail CrPAGE 1 >>>3>>>
19CT111740 ANGELF Angel
9AWAITING PAGE INSTRUCTIONS

Correct the “percent” enquiry – set field 1 to “4,19”:

Model Bank ENQUIRY, INPUT

ENQUIRY........... %CUSTOMER
------------------------------------------------------------------------------
1 PAGE.SIZE ........ 4,19

After:

Model Bank

------------------------------------------------------------------------------
1 100112 ABNAMRO Abn Amro Securities Chief Securities De| N|
2 100369 ABUDHAOIL Abu Dhabi National Oil Company Corporate Loan Supe| U|
3 111706 ADMIN Administrator Of Acorn Engg CompMortgage Dept User 2 U|
4 100396 AIRBOURNE Airbourne Freight Retail Credit Offic| R|
5 111405 AKAI AKAI Trade Finance Offic| J|
6 111410 AKAIGBP AKAI Trade Finance Offic| J|
7 100349 ALBRECHTT Theo Albrecht Retail Credit Offic| G|
8 111683 ALEX Alex Branch Operations M| U|
9 100600 ALEXFL Alex Call Centre Agent U|
10 100301 ALLEGRA Allegra Corporate Officer U|
11 111421 ALLENG Allen Gerling Customer Service Ag| G|
12 100971 ALLIANCE Alliance Investment Managers Chief Securities De| U|
13 100433 AMEXINDONE American Express Indonesia Trade Finance Offic| I|
14 100435 AMEXPARIS American Express Paris Treasury Dealer F|
15 100436 AMEXSINGAP American Express Singapore Treasury Dealer S|
16 100437 AMEXUK American Express Uk Treasury Dealer G|
------------------------------------------------------------------------------
20 DEC 2011 20:09:34 USER (14 APR) VLADIMIR.K [6409,INPAGE 1 >>>3>>>

REM Page 220


ACTION
AWAITING PAGE INSTRUCTIONS

note: You might need to relogin to T24 to see changes.

14.5 To see changes in the example given above without necessity


to relogin to T24
In SPF there’s a field cache.expiry that is to be set to number of seconds after which a
record will be taken from the disk rather than from cache.
Step 1:

Model Bank SPF, INPUT

SYSTEM SPEC....... SYSTEM


------------------------------------------------------------------------------
1 RUN.DATE.......... 30 MAR 2011
2 SITE.NAME......... R11 Model Bank
3 OP.MODE........... O
4. 1 OP.CONSOLE.....
5. 1 MAIN.ACCOUNT... ../bnk.data
6. 1 BACKUP.CYCLE.1.
7. 1 BACKUP.CYCLE.2.
8 CURRENT.RELEASE... 201107
9 HIST.LIFE......... 1
10 ALL.PG.INC........
11 CACHE.EXPIRY...... 60

Step 2: relogin to T24.


Step 3. Find a “percent” enquiry that has the value “4,99” in the first field. In this example
application DE.MESSAGE will be used:

Model Bank ENQUIRY, SEE

ENQUIRY........... %DE.MESSAGE
------------------------------------------------------------------------------
1 PAGE.SIZE ........ 4,99

Step 4. Go to “AWAITING APPLICATION” prompt and type DE.MESSAGE L ←- :

Model Bank Delivery Message List

MessaDescription
------------------------------------------------------------------------------

REM Page 221


1 1 Complete Message def for AA
2 5 New Arrangement message
3 10 CHEQUE
4 20 CHEQUE ENCLOSURE
5 30 DRAFT
6 40 ADV. OF DRAWING
7 50 DRAFT ENCLOSURE
8 60 BANKERS PAYMENT
9 80 B.A.C.S. PAYMENT
10 100 CUSTOMER TRANSFER
11 101 REQUEST FOR TRANSFER
12 102 Multiple Customer Credit Transfer
13 103 CUSTOMER CREDIT TRANSFER
14 110 CHEQUE ADVICE
15 111 REQUEST FOR STOP PAYMENT OF CHEQUE
16 112 STATUS OF MT111
17- 190-Advice of Charges ------------------------------------
180 191 Request For Charges IR.K [7929,INPAGE 1 >>>3>>>
19C 192 Customer Transfer CANCELLAT
9AWAITING PAGE INSTRUCTIONS

Step 5. Edit the ENQUIRY record:

Model Bank ENQUIRY, INPUT

ENQUIRY........... %DE.MESSAGE
------------------------------------------------------------------------------
1 PAGE.SIZE ........ 4,19

Step 6. Immediately return to “AWAITING APPLICATION” prompt and type DE.MESSAGE L


←- again:

Model Bank Delivery Message List

MessaDescription
------------------------------------------------------------------------------
1 1 Complete Message def for AA
2 5 New Arrangement message
3 10 CHEQUE
4 20 CHEQUE ENCLOSURE
5 30 DRAFT
6 40 ADV. OF DRAWING
7 50 DRAFT ENCLOSURE
8 60 BANKERS PAYMENT
9 80 B.A.C.S. PAYMENT
10 100 CUSTOMER TRANSFER
11 101 REQUEST FOR TRANSFER

REM Page 222


12 102 Multiple Customer Credit Transfer
13 103 CUSTOMER CREDIT TRANSFER
14 110 CHEQUE ADVICE
15 111 REQUEST FOR STOP PAYMENT OF CHEQUE
16 112 STATUS OF MT111
17- 190-Advice of Charges ------------------------------------
180 191 Request For Charges IR.K [7929,INPAGE 1 >>>3>>>
19C 192 Customer Transfer CANCELLAT
9AWAITING PAGE INSTRUCTIONS

Step 7. Return to “AWAITING APPLICATION” prompt, wait at least one minute and type
DE.MESSAGE L ←- once again:

Model Bank Delivery Message List

MessaDescription
------------------------------------------------------------------------------
1 1 Complete Message def for AA
2 5 New Arrangement message
3 10 CHEQUE
4 20 CHEQUE ENCLOSURE
5 30 DRAFT
6 40 ADV. OF DRAWING
7 50 DRAFT ENCLOSURE
8 60 BANKERS PAYMENT
9 80 B.A.C.S. PAYMENT
10 100 CUSTOMER TRANSFER
11 101 REQUEST FOR TRANSFER
12 102 Multiple Customer Credit Transfer
13 103 CUSTOMER CREDIT TRANSFER
14 110 CHEQUE ADVICE
15 111 REQUEST FOR STOP PAYMENT OF CHEQUE
16 112 STATUS OF MT111
------------------------------------------------------------------------------
20 JAN 2012 22:45:02 USER (14 APR) VLADIMIR.K [7929,INPAGE 1 >>>3>>>
ACTION
AWAITING PAGE INSTRUCTIONS

note: In production don’t set this field (leave empty; value of 0 means “no cache at all”).

REM Page 223


14.6 Overcome “200 pages” ENQUIRY limit set in SPF

Use the application ENQUIRY.REPORT, e.g.:


View of “percent” enquiry on screen (DE.O.HEADER L, then P200):

Model Bank Outward Messages

Date/Time Message Status Short Name


------------------------------------------------------------------------------
1 D20110418098743011700 FORMATTED Allegra
2 D2011041809874301 900 FORMATTED Alliance Investment Mana|
3 D2011041809874301 900 FORMATTED Alliance Investment Mana|
4 D2011041900101522 515 FORMATTED Rolf Gerling
5 D2011041900101522 518 FORMATTED Citi Group Inc. (New Yor|
6 D2011041900101522 202 FORMATTED SWIFT CEDEL
7 D2011041900101523 515 FORMATTED Mr Alfred Heineken
8 D2011041900101523 518 FORMATTED Abn Amro Securities ABM |
9 D2011041900101525 515 FORMATTED Mr Alfred Heineken
10 D2011041900101525 518 FORMATTED Abn Amro Securities ABM |
11 D2011041900101525 515 FORMATTED Mr Alfred Heineken
12 D2011041900101525 518 FORMATTED The Bank Of New York BAN|
13 D2011041900101525 515 FORMATTED Mr Alfred Heineken
14 D2011041900101525 518 FORMATTED The Bank Of New York BAN|
15 D2011041900101527 515 FORMATTED Anthony Bamford
16 D2011041900101527 518 FORMATTED Abn Amro Securities ABM |
------------------------------------------------------------------------------
11 MAY 2012 19:56:13 USER (14 APR) VLADIMIR.K [3375,INPAGE 200 >200>>>
ACTION THIS IS THE LAST PAGE
AWAITING PAGE INSTRUCTIONS

Get the @id of the last visible record – it’s D20110419001015270002.


ENQUIRY.REPORT:

Model Bank ENQUIRY.REPORT VERIFY

KEY............... DOH
------------------------------------------------------------------------------
1. 1 GB DESCRIPTION. FULL DE.O.HEADER
2. 1 ENQUIRY........ %DE.O.HEADER DE.O.HEADER
3. 1. 1 SELECTION...
4. 1. 1 OPERAND.....
5. 1. 1 LIST........
6. 1. 1 SORT........
7 REPORT.CONTROL.... ENQUIRY.PRINT Enquiry screen print
8 STANDARD.HEADING..

REM Page 224


9. 1 ADDI
10. 1 GB REPORT.HDR..
11 OUTPUT.FORMAT..... FILE
12 RESERVED.13.......
13 RESERVED.12.......
14 RESERVED.11.......
15 RESERVED.10.......
16 RESERVED.9........
------------------------------------------------------------------------------
11 MAY 2012 19:59:25 USER (14 APR) VLADIMIR.K [3375,I PAGE 1 >>>3>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Result is being put to &HOLD&. Search it for the last record in the page 200 from the screen
above (D20110419001015270002) and see that here it’s not the last:

"D20110419001015270002 " " 518" "FORMATTED " "Abn Amro Securities


ABM |"
"D20110419001015280401 " " 515" "FORMATTED " "Anthony Bamford "
"D20110419001015280402 " " 518" "FORMATTED " "Citi Group Inc. (New Yor|"
"D20110419001015280403 " " 202" "FORMATTED " "HSBC BAN "
"D20110419001015287700 " " 515" "FORMATTED " "Anthony Bamford "
"D20110419001015287701 " " 518" "FORMATTED " "Citi Group Inc. (New Yor|"
"D20110419001015287702 " " 202" "FORMATTED " "EURO CLEAR1 "
...

14.7 Avoid hanging of Globus Desktop on DEBUG statement


SUBROUTINE SOME.TEST
* any T24 subroutine
$INSERT I_COMMON
$INSERT I_EQUATE

// ...

IF NOT(INDEX(TTYPE, 'GUI', 1)) THEN


DEBUG
END

// ...

14.8 Place “$” files separately from sources


Directory with sources is called ETC.BP in this example.

CREATE-FILE DATA ETC.BP,OBJECT 101

REM Page 225


[ 417 ] File ETC.BP]MOBJECT created , type = J4

LIST ETC.BP

SOME.TEST

1 Records Listed

BASIC -I..\T24.BP ETC.BP SOME.TEST

SOME.TEST
BASIC_2.c
Source file SOME.TEST compiled successfully

LIST ETC.BP

SOME.TEST

1 Records Listed

LIST ETC.BP,OBJECT

$SOME.TEST

1 Records Listed

14.9 See last jsh commands issued from the same port number
Ctrl - L

001 where
...
005 jcompile test.b
...
011 CLEAR-FILE F.TEST
012 SELECT VOC
013 CLEARSELECT
...
etc

14.10 See last jsh and jed commands issued from any port number
CT [path_to_TAFC]\tmp\jutil_ctrl

jutil_jed_CONIN_-2
001 .last.

REM Page 226


002 F.ABBREVIATION$NAU]QWERTZ
003 ]4]34]5]0]1]1]]1]

jutil_jsh_CONIN_-34
001 test9
002 build.bat

jutil_jsh_CONIN_-3
001 CT C:\home\kzm\v-t24\tafc201108\tmp\jutil_ctrl
002 where
003 test
004 jcompile test.b
005 LIST C:\home\kzm\v-t24\tafc201108\tmp\jutil_ctrl
006 LIST F.TEST
007 LIST F.TEST
008 jlogdup INPUT set=current terminate=eos OUTPUT set=database
009 SELECT F.LOG WITH PATH LIKE "...'\F.TEST'" AND TYPE EQ 'WRITE'
010 CLEAR-FILE F.TEST
...

note: “-n” at the end of @id is port number – first column of WHERE output.

14.11 Correct the error appearing after LIST VOC command


LIST VOC

Error in Statement "LIST VOC"


Error in attribute definition item DESC
Error in Itype:
Cannot open translate file NEWACC

JED DICT VOC @

0001 PH
0002 NAME TYPE 
DESC
X X ID.SUP


X

14.12 Enter debugger in tSS


Just type DEBUG:

tSS TAG
<tSS version="1.1"><t24version>R10.000</t24version><t24pid>.....
DEBUG
DEBUG statement seen
Line 182 , Source tSS

REM Page 227


jBASE debugger->
j -g
Backtrace:
#0: jmainfunction.b:182
#1: tSS:116 [0] -> Line 116 , Source tSS
#1: tSS:182 -> Line 182 , Source tSS

Backtrace log:
Line 0 , Source jmainfunction.b , Level 0
Line 116 , Source tSS

14.13 Clean shared memory after installing new release in Unix


(example for jBASE5)
ipcs -a
In the output of the above command you can see lines like:

Shared Memory:
m 0 0x580070b4 --rw-rw-rw- root system root system 1 134217728 192614 237696
m 131073 0x4a414310 --rw-rw-rw- root system root system 3 188 266478 483536 2
m 131074 0x0d00a2f0 --rw-rw-rw- root system root system 14 1440 237818 110204
m 131075 0xffffffff --rw-rw---- root system root system 1 4096 798876 798876
m 4 0x4a414311 --rw-rw-rw- root system root system 3 342616 266478 483536 20:
m 5 0x4a500064 --rw-rw-rw- sairam hdin sairam hdin 3 436504 757986 483538 20:
m 6 0x4a414032 --rw-rw-rw- bhavani hdin bhavani hdin 7 425632 651402 483334 2
m 7 0x4a415032 --rw-rw-rw- sonia hdin sonia hdin 6 351944 659586 483352 20:22
T ID KEY MODE OWNER GROUP CREATOR CGROUP NSEMS OTIME CTIME
Semaphores:
s 262144 0x580070b4 --ra-ra-ra- root system root system 1 22:37:45 22:37:45
s 1 0x440070b4 --ra-ra-ra- root system root system 2 22:37:45 22:37:45
s 131074 0x0100a0bc --ra------- root system root system 1 20:22:14 22:46:54
s 3 0x6200a0c0 --ra-r--r-- root system root system 1 22:38:31 22:38:31
s 4 0x4a414310 --ra-ra-ra- root system root system 61 20:17:54 22:47:23
s 5 0x4a414311 --ra-ra-ra- root system root system 61 16:39:13 22:47:23

Remove the ids starting with “0x4a5” using the command:

ipcrm -m <shared memory ID>


ipcrm -s <semaphore ID>

In the above case it would be:

ipcrm -m5

note: For jBASE4 address begins from 0x4a4, for TAFC – from 0x24.

REM Page 228


14.14 Install TAFC without admin rights under XP
• Proceed with installation. Refuse to install VC Redist package. After installation.
• Open TAFC distribution file in 7zip, go to:
\$[31]\bin\vcredist x86.exe\.\.\.\.\vc red.cab\.
• Extract F CENTRAL msvcp100 x86, copy it as %TAFC HOME%\bin\msvcp100.dll.
• Extract F CENTRAL msvcr100 x86, copy it as %TAFC HOME%\bin\msvcr100.dll.
note: jBASE telnet wouldn’t be installed as a service without admin rights.

14.15 See which files and records took part in T24 transaction
Step 1. Set appropriate spf field:

Model Bank SPF, INPUT

SYSTEM SPEC....... SYSTEM


------------------------------------------------------------------------------
63 INFO.JOURNAL...... Y

Step 2. Relogin, input something:

Model Bank USER PROFILE, INPUT

USER.ID........... INPUTTER
------------------------------------------------------------------------------
1 USER.NAME......... Inputter, yes it is |
2 SIGN.ON.NAME...... INPUTT
3 CLASSIFICATION.... INT
4 LANGUAGE.......... 1 English
5. 1 COMPANY.CODE... GB0010001 Model Bank
5. 2 COMPANY.CODE... GB0010002 MF Lead Company
5. 3 COMPANY.CODE... GB0010003 MF Branch 1
5. 4 COMPANY.CODE... GB0010004 MF Branch 2
5. 5 COMPANY.CODE... SG0010001 Model Bank - Singapore
5. 6 COMPANY.CODE... EU0010001 Model Bank - Europe
6 DEPARTMENT.CODE... 56 Trade Finance Supervisor
7 PASSWORD.VALIDITY. 01 MAY 2012 M0601 01 MAY 2012 Every 6 months on day 1
8 START.DATE.PROFILE 09 APR 2011
9 END.DATE.PROFILE.. 11 APR 2012
10. 1 START.TIME..... 00:01
11. 1 END.TIME....... 23:59
------------------------------------------------------------------------------
30 NOV 2011 19:36:36 USER (14 APR) VLADIMIR.K [1021,INPAGE 1 >>>6>>>
ACTION

REM Page 229


Step 3. See the result:

LIST F.JOURNAL *A1 *A2 *A3

F.JOURNAL..... *A1........... *A2........... *A3...........

1 F.EB.EXTERNAL.
ELETEnput INPUTTER
USER INPUTTER ter, yes it is
NE INPUTTINT1
GB0010001
F.EB.EXTERNAL. GB0010002
USER$NAU INPUT
TER NE
F.USER$NAU INP GB0010003
UTTER WLNE
F.USER INPUTTE GB0010004
R WL
F.SY.PARAMETER SG0010001
SYSTEM
F.SY.PARAMETER EU0010001562
GB0010001 0120501M06012
0110409201204
1112359999
9ALLALL.P
GA 2 B C D E
F H I L P R S
...

14.16 Distribute a file


Here we’ll take FBNK.STMT.ENTRY and put “regular” records to one file, “dummy” ones to
another and records with @ids like “S!20591!CR!EUR!FT!210!...” – to the third and
everything else – to another (default) file.
Create stub:

CREATE-FILE DATA STMT.ENT.DIST TYPE=DISTRIB


[ 417 ] File STMT.ENT.DIST created , type = DISTRIB

REM Page 230


Subroutine:

SUBROUTINE STMT.ENT.ALGO(P.DUMMY, P.KEY, P.PARTNO)


* Distribution algorithm for STMT.ENTRY
V.STRT = P.KEY[1,1]

BEGIN CASE
CASE ISDIGIT(V.STRT)
P.PARTNO = 1
CASE V.STRT EQ 'D'
P.PARTNO = 2
CASE V.STRT EQ 'S'
P.PARTNO = 3
CASE 1
P.PARTNO = 99
END CASE

RETURN
END

Attach it:

CREATE-DISTRIB -pUSER,STMT.ENT.ALGO STMT.ENT.DIST

Create data for “part” files:

CREATE-FILE DATA STMT.ENT.PART1 TYPE=J4 1 101


[ 417 ] File STMT.ENT.PART1 created , type = J4

CREATE-FILE DATA STMT.ENT.PART2 TYPE=J4 1 101


[ 417 ] File STMT.ENT.PART2 created , type = J4

CREATE-FILE DATA STMT.ENT.PART3 TYPE=J4 1 101


[ 417 ] File STMT.ENT.PART3 created , type = J4

CREATE-FILE DATA STMT.ENT.PART99 TYPE=J4 1 101


[ 417 ] File STMT.ENT.PART99 created , type = J4

Attach part files:

CREATE-DISTRIB -a STMT.ENT.DIST 1 STMT.ENT.PART1


Part file 'STMT.ENT.PART1', Part number 1 added

CREATE-DISTRIB -a STMT.ENT.DIST 2 STMT.ENT.PART2


Part file 'STMT.ENT.PART2', Part number 2 added

REM Page 231


CREATE-DISTRIB -a STMT.ENT.DIST 3 STMT.ENT.PART3
Part file 'STMT.ENT.PART3', Part number 3 added

CREATE-DISTRIB -a STMT.ENT.DIST 99 STMT.ENT.PART99


Part file 'STMT.ENT.PART99', Part number 99 added

Verify the setup:

VERIFY-DISTRIB STMT.ENT.DIST

Partitioning Algorithm is USER Subroutine 'STMT.ENT.ALGO'


User subroutine OK.
Part file 'STMT.ENT.PART1', part number 1 - OK
Part file 'STMT.ENT.PART2', part number 2 - OK
Part file 'STMT.ENT.PART3', part number 3 - OK
Part file 'STMT.ENT.PART99', part number 99 - OK

Copy data:

COPY FROM FBNK.STMT.ENTRY TO STMT.ENT.DIST ALL


12069 records copied

Move STMT.ENT.DIST, STMT.ENT.PART1, STMT.ENT.PART2, STMT.ENT.PART3,


STMT.ENT.PART99 to ../bnk.data/ac/. Save VOC entry:

COPY FROM VOC FBNK.STMT.ENTRY,FBNK.STMT.ENTRY-SAVE

Edit VOC entry for stub:

JED VOC FBNK.STMT.ENTRY

0002 ../bnk.data/ac/STMT.ENT.DIST

Create VOC entries for part files:

COPY FROM VOC FBNK.STMT.ENTRY,STMT.ENT.PART1


1 records copied

COPY FROM VOC FBNK.STMT.ENTRY,STMT.ENT.PART2


1 records copied

COPY FROM VOC FBNK.STMT.ENTRY,STMT.ENT.PART3


1 records copied

COPY FROM VOC FBNK.STMT.ENTRY,STMT.ENT.PART99


1 records copied

REM Page 232


Edit VOC entries for part files:

JED VOC STMT.ENT.PART1

0002 ../bnk.data/ac/STMT.ENT.PART1

JED VOC STMT.ENT.PART2

0002 ../bnk.data/ac/STMT.ENT.PART2

JED VOC STMT.ENT.PART3

0002 ../bnk.data/ac/STMT.ENT.PART3

JED VOC STMT.ENT.PART99

0002 ../bnk.data/ac/STMT.ENT.PART99

Check the results:

VERIFY-DISTRIB FBNK.STMT.ENTRY

Partitioning Algorithm is USER Subroutine 'STMT.ENT.ALGO'


User subroutine OK.
Part file 'STMT.ENT.PART1', part number 1 - OK
Part file 'STMT.ENT.PART2', part number 2 - OK
Part file 'STMT.ENT.PART3', part number 3 - OK
Part file 'STMT.ENT.PART99', part number 99 - OK

List individual part files:

LIST ONLY STMT.ENT.PART1

@ID. 158250319644408.000001
@ID. 158180605551490.020001
@ID. 158210768248728.020001
@ID. 158230320747851.040001
...

LIST ONLY STMT.ENT.PART2

@ID. DUMMY.ID502
@ID. DUMMY.ID188
@ID. DUMMY.ID424
@ID. DUMMY.ID226
...

REM Page 233


LIST ONLY STMT.ENT.PART3

@ID. S!EUR152100001!CR!EUR!SCPL!633!20110407!20110407!!1!!117!20110407
@ID. S!GBPUSD140180001!CR!GBP!AC!130!20110331!!!1!!15!20110331
@ID. S!USDGBP140160001!CR!USD!FT!130!20110414!20110414!!1!!366!20110414
@ID. S!20591!CR!EUR!FT!210!20110414!20110414!!1!!6408!20110414
...

LIST ONLY STMT.ENT.PART99

@ID. F20110414.15826077544910414
@ID. F20110415.15825031964301106
@ID. F20110414.15826077544910504
@ID. F20110428.15830060275557004
...

Now you can archive and remove the initial FBNK.STMT.ENTRY file (in my environment it’s
..\bnk.data\ac\FBNK STMT ENTRY).

14.17 Set up transaction journalling


First of all: this example is quite basic – just to see how it works. No detailed planning of
file sets, sizes, notifiers etc will be done. (And this is mandatory for a server setup of course.)

jsh --> jlogadmin -R

jBASE Transaction Journal Configuration

Status : INACTIVE Current switched log set : 0


Extended records : OFF Time between log file syncs : 10
Time between log file checkpoints : 10
Log notify program : (undefined)
Warning threshold : 70 % , thereafter every 1 % or 300 secs
Sync Transactions : ON Encrypt Records : OFF
File definitions for log set 1
1 : 2 :
3 : 4 :
5 : 6 :
7 : 8 :
9 : 10:
11: 12:
13: 14:
15: 16:

Use the cursor keys and tab keys to move around the screen.

REM Page 234


The fields can be edited using jed/jsh style editing comma
Press RETURN to continue :

Press ←- and use a →−


−−− (Tab) to move to the field where log files are set up:

jBASE Transaction Journal Configuration

Status : INACTIVE Current switched log set : 0


Extended records : OFF Time between log file syncs : 10
Time between log file checkpoints 10
Log notify program :
Warning threshold : 70 % , thereafter every 1 1 or 300 secs
Sync Transactions : ON Encrypt Records : OFF
File definitions for log set 1
1 : [_ ] 2 :
3 : 4 :
5 : 6 :
7 : 8 :
9 : 10:
11: 12:
13: 14:
15: 16:

Define the name (with full path) of the first file in a log set 1, e.g.:

jBASE Transaction Journal Configuration

Status : INACTIVE Current switched log set : 0


Extended records : OFF Time between log file syncs : 10
Time between log file checkpoints 10
Log notify program :
Warning threshold : 70
% , thereafter every 1 1 or 300 secs
Sync Transactions : ON Encrypt Records : OFF
File definitions for log set 1
1 : [C:\t24\bnk\logs\log1.1_ ] 2 :
3 : 4 :
5 : 6 :
7 : 8 :
9 : 10:
11: 12:
13: 14:
15: 16:

REM Page 235


Then press ←- and confirm creation of the file (if it didn’t exist):

C:\t24\bnk\logs\log1.1: No such file or directory


jlogadmin: File 'C:\t24\bnk\logs\log1.1' cannot be opened.
Do you want to create this file (Y/N) ? Y

INFORMATION: From user vladimir.kazimirchik at Fri Mar 09 14:21:29 2012


Process ID 4020 , Port 3 , tty CONIN$
File 1 for log set 1 changed to C:\t24\bnk\logs\log1.1

Press RETURN to continue :

Repeat that step to assign one more file to the set 1. Resulting screen:

jBASE Transaction Journal Configuration

Status : INACTIVE Current switched log set : 0


Extended records : OFF Time between log file syncs : 10
Time between log file checkpoints 10
Log notify program :
Warning threshold : 70 % , thereafter every 1 1 or 300 secs
Sync Transactions : ON Encrypt Records : OFF
File definitions for log set 1
1 : C:\t24\bnk\logs\log1.1 2 : C:\t24\bnk\logs\log1.2
3 : 4 :
5 : 6 :
7 : 8 :
9 : 10:
11: 12:
13: 14:
15: 16:

Navigate ( →−
−−− ) to menu item “Current switched log set” and set it to 1:

jBASE Transaction Journal Configuration

Status : INACTIVE Current switched log set : [1_]


Extended records : OFF Time between log file syncs : 10
Time between log file checkpoints 10
Log notify program :
Warning threshold : 70
% , thereafter every 1 1 or 300 secs
Sync Transactions : ON Encrypt Records : OFF
File definitions for log set 1
1 : C:\t24\bnk\logs\log1.1 2 : C:\t24\bnk\logs\log1.2
3 : 4 :

REM Page 236


5 : 6 :
7 : 8 :
9 : 10:
11: 12:
13: 14:
15: 16:

Now – make the logging active:

jBASE Transaction Journal Configuration

Status : [ACTIVE_ ] Current switched log set : 1


Extended records : OFF Time between log file syncs : 10
Time between log file checkpoints 10
Log notify program :
Warning threshold : 70% , thereafter every 1 1 or 300 secs
Sync Transactions : ON Encrypt Records : OFF
File definitions for log set 1
1 : C:\t24\bnk\logs\log1.1 2 : C:\t24\bnk\logs\log1.2
3 : 4 :
5 : 6 :
7 : 8 :
9 : 10:
11: 12:
13: 14:
15: 16:

Use Ctrl-X to exit. Create stub file to be able to be able to look at the journal:

CREATE-FILE F.LOG TYPE=TJLOG

[ 417 ] File F.LOG]D created , type = J4


[ 417 ] File F.LOG created , type = TJLOG

This file type has predefined dictionary entries:

CT DICT F.LOG

SET
001 A
002 1
003 Set
004
005
006
007

REM Page 237


008
009 L
010 3

TIME-UTC
001 A
002 6
003 Time]UTC
004
005
006
007
008
009 R
010 12

DATE
001 A
002 6
003 Update]Date
004
005
006
007
008 Uff1]D4
009 L
010 11
...

Log in to and out of T24. See the journal entries (at the beginning there will be entries
related to creation of F.LOG itself so skip them):

LIST F.LOG
...
WRITE vladimir.k F.TERMINAL.USER 19:26:10 09 MAR 2012
WRITE vladimir.k F.TSA.STATUS 19:26:11 09 MAR 2012
WRITE vladimir.k F.T24.SESSION 19:26:11 09 MAR 2012
WRITE vladimir.k F.LOCKING 19:26:11 09 MAR 2012
WRITE vladimir.k F.OS.TOKEN 19:26:11 09 MAR 2012
WRITE vladimir.k F.OS.TOKEN.USE 19:26:11 09 MAR 2012
WRITE vladimir.k F.USER 19:26:11 09 MAR 2012
WRITE vladimir.k F.OS.XML.CACHE 19:26:11 09 MAR 2012
DELETE vladimir.k F.OS.TOKEN 19:26:13 09 MAR 2012
DELETE vladimir.k F.OS.TOKEN.USE 19:26:13 09 MAR 2012
WRITE vladimir.k F.USER 19:26:13 09 MAR 2012
TRANSTART vladimir.k 19:26:13 09 MAR 2012
WRITE vladimir.k F.TSA.STATUS 19:26:13 09 MAR 2012

REM Page 238


DELETE vladimir.k F.T24.SESSION 19:26:13 09 MAR 2012
TRANSEND vladimir.k 19:26:13 09 MAR 2012
CHECKPOINT vladimir.k System 19:26:13 09 MAR 2012

All data can be seen this way:

LIST F.LOG ALL


...
Set.................... 1
Type................... WRITE
Type................... 2
Update Time............ 19:26:10
Update Date............ 09 MAR 2012
Process ID............. 4020
Port Number............ 3
Total Log Record Size.. 122
File Number............ 0
File Offset............ 5611
Trans.................. 0
Full file path name.... F.TERMINAL.USER
Record Key............. 3
jBASE login............ vladimir.kazimirchik
OS login...............
TTY....................
Application Identifier.
Transaction Identifier.
Actual Time............
Elapsed Time...........
Transactions Committed.
Transactions Aborted...

Set.................... 1
Type................... WRITE
Type................... 2
Update Time............ 19:26:11
Update Date............ 09 MAR 2012
Process ID............. 4020
Port Number............ 3
Total Log Record Size.. 169
File Number............ 0
File Offset............ 5733
Trans.................. 0
Full file path name.... F.TSA.STATUS
Record Key............. OLTP8239
jBASE login............ vladimir.kazimirchik
OS login...............
TTY....................

REM Page 239


Application Identifier.
Transaction Identifier.
Actual Time............
Elapsed Time...........
Transactions Committed.
Transactions Aborted...
...

“ALL” is a special directory entry:

CT DICT F.LOG 'ALL'

001 M
002 ID-SUPP SET FILE TYPE TYPENUM TIME DATE PID PORT LOGSIZE FILENO OFFSET
TRANS PATH RECKEY JBNAME OSNAME TTY APPID TRANSID REALTIME TRANSTIME
TRANSCOMP TRANSABORT

Now log in to T24, input an unauthorised ABBREVIATION record and see the impact in
the journal:

LIST F.LOG ALL WITH PATH LIKE F.ABBR...


Set.................... 1
Type................... WRITE
Type................... 2
Update Time............ 19:33:11
Update Date............ 09 MAR 2012
Process ID............. 4020
Port Number............ 3
Total Log Record Size.. 174
File Number............ 1
File Offset............ 7582
Trans.................. 1
Full file path name.... F.ABBREVIATION$NAU
Record Key............. QWERTZ
jBASE login............ vladimir.kazimirchik
OS login...............
TTY....................
Application Identifier.
Transaction Identifier.
Actual Time............
Elapsed Time...........
Transactions Committed.
Transactions Aborted...

REM Page 240


By the way, changes to a file will be logged only if it has “Log” attribute set to “YES”:

jstat -v F.ABBREVIATION
File Path = ..\bnk.data\eb\F_ABBREVIATION
File Type = JR, Hash method = 5, Created = Mon May 19 19:51:57 2008
Frame size = 4096, OOG Threshold = 2048
File size = 94208, Freespace = 1 frames
Internal Modulo = 3/7/19, External Modulo = 31
Inode no. = 145809, Device no. = 24915
Accessed = Fri Mar 09 19:26:00 2012, Modified = Fri Mar 09 19:26:00 2012
Backup = YES, Log = YES , Rollback = YES, Secure updates = YES
Deallocate pointers : NO Deallocate frames NO
Revision level = 1
Record Bytes = 30494, Record Count = 294
Bytes/Record = 103, Bytes/Group = 1452
Data Frames = 21, Ptr Frames = 0
OOG Bytes = 0, OOG Frames = 0
Sum Squares = 3190536, Std Dev Mean = 118

It’s better to switch logging off for certain files to gain some performance (for example, for
F.TERMINAL.USER):

jchmod -L F.TERMINAL.USER

jstat -v F.TERMINAL.USER
...
Backup = YES, Log = NO , Rollback = YES, Secure updates = YES
...

Now let’s try selective journal restore. To avoid over-complicating things let’s not involve
T24 – just create a new file, add some records to it (with logging), then stop logging and
clear the file, then restore the records added earlier. First step will be to create a fresh log
set (#2) and make it active:

jBASE Transaction Journal Configuration

Status : ACTIVE Current switched log set : 2


Extended records : OFF Time between log file syncs : 10
Time between log file checkpoints 10
Log notify program :
Warning threshold : 70
% , thereafter every 1 1 or 300 secs
Sync Transactions : ON Encrypt Records : OFF
File definitions for log set 2
1 : C:\t24\bnk\logs\log2 2 :
3 : 4 :

REM Page 241


5 : 6 :
7 : 8 :
9 : 10:
11: 12:
13: 14:
15: 16:

Check the “freshness” of this setup:

LIST F.LOG
Type....... jBASE..... Full file path name................ Update.. Update.....
login Time Date

No Records Listed

Create the new hashed file:

CREATE-FILE F.TEST 1 1
[ 417 ] File F.TEST]D created , type = J4
[ 417 ] File F.TEST created , type = J4

Check if this file is being logged (by default it should be, but anyway):

LIST F.LOG
Type....... jBASE..... Full file path name................ Update.. Update.....
login Time Date

CREATEFILE vladimir.k C:\t24\bnk\bnk.run\F.TEST]D 20:45:45 09 MAR 2012


azimirchik
CREATEFILE vladimir.k C:\t24\bnk\bnk.run\F.TEST 20:45:45 09 MAR 2012
azimirchik

2 Records Listed

Add some records:

SELECT VOC SAMPLE 5

>COPY FROM VOC TO F.TEST


5 records copied

LIST F.TEST
F.TEST........

F.DX.REVAL.DET.ENHANCED
F.GENERATE.ENTRY.WRK

REM Page 242


F.GT.SYSTEM.PARAMETER$NAU
F.RUN.GRP.PERF.TAKEON
F.SA.RATIOS

5 Records Listed

Make logging “INACTIVE” using jlogadmin. Clear F.TEST:

CLEAR-FILE F.TEST

LIST F.TEST
F.TEST........

No Records Listed

Now it’s time to restore the records (logging is yet “INACTIVE” of course):

SELECT F.LOG WITH PATH LIKE "...'\F.TEST'" AND TYPE EQ 'WRITE'

>jlogdup INPUT set=current terminate=eos OUTPUT set=database

21:28:05 09 MAR 2012 : STATUS:


Begin jlogdup process: From set 'set=current terminate=eos' to
set 'set=database'
21:28:05 09 MAR 2012 : STATUS:
Termination Statistics: usr 612.20 , sys 0.00 , elapsed 0m0.00
INPUT : 5 records , 0 blocks , 1130 record bytes , 0 errors
OUTPUT: 5 records , 0 blocks , 1130 bytes , 0 errors
21:28:05 09 MAR 2012 : STATUS:
Program terminated. Exit code is 0

LIST F.TEST
F.TEST........

F.DX.REVAL.DET.ENHANCED
F.GENERATE.ENTRY.WRK
F.GT.SYSTEM.PARAMETER$NAU
F.RUN.GRP.PERF.TAKEON
F.SA.RATIOS

5 Records Listed

Note that none of log files should ever exceed 2Gb in size (several log sets and their switching
should help here). Many other factors should be taken into consideration for transaction
journalling like online journal replication to another server etc; I believe what was described
here gives a good start to learn it all.

REM Page 243


14.18 Create an online service that is activated at certain periods
of time
In this example will be shown a service that runs 5 times during the work day; it will “process”
(actually – just put to a protocol) the records in unauthorised file of FUNDS.TRANSFER.
The name of the service is SERVICE.TEST.
Step 1. Create 3 routines and one insert file; names of 2 routines have standard parts in
them (.LOAD, .SELECT):

SUBROUTINE SERVICE.TEST(P.NEXT.ID)
*-----------------------------------------------------------------------------
$INSERT I_COMMON
$INSERT I_EQUATE
$INSERT I_SERVICE.TEST.COMMON
*-----------------------------------------------------------------------------

CALL OCOMO('Processing ' : P.NEXT.ID)


MSLEEP 30000 ;* to allow other agent to have something
CALL OCOMO('Finished processing ' : P.NEXT.ID)

RETURN
END

SUBROUTINE SERVICE.TEST.LOAD
*-----------------------------------------------------------------------------
$INSERT I_COMMON
$INSERT I_EQUATE
$INSERT I_SERVICE.TEST.COMMON
*-----------------------------------------------------------------------------

FN.FT.NAU = 'F.FUNDS.TRANSFER$NAU'
F.FT.NAU = ''
CALL OPF(FN.FT.NAU, F.FT.NAU)

RETURN
END

REM Page 244


SUBROUTINE SERVICE.TEST.SELECT
*-----------------------------------------------------------------------------
$INSERT I_COMMON
$INSERT I_EQUATE
$INSERT I_SERVICE.TEST.COMMON
*-----------------------------------------------------------------------------

* Main SELECT
V.SEL.CMD = 'SELECT ' : FN.FT.NAU
HUSH ON
EXECUTE V.SEL.CMD RTNLIST V.FT.LIST
HUSH OFF

* Build "key only" file


CALL BATCH.BUILD.LIST('', V.FT.LIST)

RETURN
END

* File: I_SERVICE.TEST.COMMON
COMMON /SERVICE.TEST.COMM/ FN.FT.NAU, F.FT.NAU
Step 2. Create the following records in T24 (applications for two initial screenshots are
PGM.FILE and BATCH respectively):
Model Bank PROGRAM FILE, INPUT

PROGRAM SERVICE.TEST
------------------------------------------------------------------------------
1 TYPE.............. B
2. 1 GB SCREEN.TITLE
3 ADDITIONAL.INFO...
4. 1 BATCH.JOB......
5 PRODUCT........... EB
6 SUB.PRODUCT.......
7. 1 DESCRIPTION....

Model Bank BATCH ENTRY, INPUT

BATCH PROCESS..... BNK/SERVICE.TEST


------------------------------------------------------------------------------
1 BATCH.STAGE.......
2 DEFAULT.PRINTER...
3 PROCESS.STATUS....
4 BATCH.ENVIRONMENT. F
5 DEPARTMENT.CODE...
6. 1 JOB.NAME....... SERVICE.TEST
7. 1. 1 VERIFICATION
8. 1 FREQUENCY...... D
9. 1 NEXT.RUN.DATE..

REM Page 245


Model Bank TSA.WORKLOAD.PROFILE, INPUT

WORKLOAD.PROFILE.. SERV.TST
------------------------------------------------------------------------------
1 DESCRIPTION....... TEST
2. 1 TIME........... 10:00
3. 1 AGENTS.REQUIRED 2
2. 2 TIME........... 10:05
3. 2 AGENTS.REQUIRED
2. 3 TIME........... 12:00
3. 3 AGENTS.REQUIRED 2
2. 4 TIME........... 12:05
3. 4 AGENTS.REQUIRED
2. 5 TIME........... 14:00
3. 5 AGENTS.REQUIRED 2
2. 6 TIME........... 14:05
3. 6 AGENTS.REQUIRED
2. 7 TIME........... 16:00
3. 7 AGENTS.REQUIRED 2
2. 8 TIME........... 16:05
3. 8 AGENTS.REQUIRED
2. 9 TIME........... 19:00
3. 9 AGENTS.REQUIRED 2
2.10 TIME........... 19:05
3.10 AGENTS.REQUIRED
4 RESERVED.9........

Model Bank TSA.SERVICE, INPUT

SERVICE........... BNK/SERVICE.TEST
------------------------------------------------------------------------------
1. 1 DESCRIPTION.... TEST
2. 1 SERVER.NAME....
3. 1 WORK.PROFILE... SERV.TST TEST
4. 1 SERVER.STATUS..
5 USER.............. INPUTTER Inputter, yes it is
6 SERVICE.CONTROL... AUTO
7 REVIEW.TIME.......

Now we can put START into field SERVICE.CONTROL of the TSA.SERVICE record TSM and
start tSM (typing START.TSM at jsh prompt). That’s it.
Under this setup 2 agents will be started at specified above moments of time and stopped
after 5 minutes (or after they finish the processing if it takes more than 5 minutes). However,
if they finish fast enough (less that in 5 minutes) they might be triggered again – so take
care not to duplicate the report data or whatever you’re doing.

REM Page 246


See the sample &COMO& output of 2 agents:

<process name = BNK/SERVICE.TEST>


<job name = SERVICE.TEST>
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:01:15_Standard multi-thread job
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:01:15_Calling load routine
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:01:15_Obtained the Locking with
BNK/SERVICE.TEST-SERVICE.TEST-1 and F.JOB.LIST.2
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:01:15_Using list file
F.JOB.LIST.2
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:01:15_Control list processing
7 7
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:01:15_Processing FT11104VJR82
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:01:45_Finished processing
FT11104VJR82
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:01:45_Processing FT11104G9HL9
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:02:15_Finished processing
FT11104G9HL9
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:02:15_19:17:15 Processed 2
lists [2]
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:02:15_SELECT F.JOB.LIST.2
SAMPLE 100000 Selected=2 time=0secs
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:02:15_Processing FT111043ZKCH
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:02:45_Finished processing
FT111043ZKCH
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:02:45_SELECT F.JOB.LIST.2 SAMPLE
100000 Selected=0 time=0secs
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:02:45_Using list file
F.JOB.LIST.2
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:02:45_Control list processing
7 7 6
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:02:45_SELECT F.JOB.LIST.2 SAMPLE
100000 Selected=0 time=0secs
</job>
</process>
<process name = BNK/SERVICE.TEST>
<job name = SERVICE.TEST>
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:03:45_Standard multi-thread job
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:03:45_Calling load routine
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:03:45_Starting job
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:03:45_Allocating List File for
BNK/SERVICE.TEST-SERVICE.TEST-1
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:03:45_Updating the Locking with
BNK/SERVICE.TEST-SERVICE.TEST-1 and F.JOB.LIST.2
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:03:45_Calling..
SERVICE.TEST.SELECT
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:03:45_List starting from 0 keys
processed so far 0

REM Page 247


_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:03:45_Building from list passed
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:03:45_Control list..
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:03:45_Using list file
F.JOB.LIST.2
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:03:45_Control list processing
7 7
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:03:45_Processing FT11104VJR82
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:04:15_Finished processing
FT11104VJR82
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:04:15_Processing FT111043W6YM
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:04:45_Finished processing
FT111043W6YM
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:04:45_19:19:45 Processed 2 lists
[2]
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:04:45_Processing FT11104G9HL9
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:05:15_Finished processing
FT11104G9HL9
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:05:15_SELECT F.JOB.LIST.2 SAMPLE
100000 Selected=2 time=0secs
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:05:15_Processing FT111043ZKCH
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:05:45_Finished processing
FT111043ZKCH
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:05:45_19:20:45 Processed 4 lists
[2]
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:05:45_SELECT F.JOB.LIST.2 SAMPLE
100000 Selected=0 time=0secs
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:05:45_Using list file
F.JOB.LIST.2
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:05:45_Control list processing
7 7 6
_BNK/SERVICE.TEST_SERVICE.TEST_2_04 MAR 2012_19:05:45_SELECT F.JOB.LIST.2 SAMPLE
100000 Selected=0 time=0secs
</job>
</process>

<process name = BNK/SERVICE.TEST>


<job name = SERVICE.TEST>
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:00:16_Standard multi-thread job
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:00:16_Calling load routine
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:00:16_Starting job
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:00:16_Allocating List File for
BNK/SERVICE.TEST-SERVICE.TEST-1
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:00:16_Updating the Locking with
BNK/SERVICE.TEST-SERVICE.TEST-1 and F.JOB.LIST.2
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:00:16_Calling..
SERVICE.TEST.SELECT
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:00:16_List starting from 0 keys
processed so far 0

REM Page 248


_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:00:16_Building from list passed
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:00:16_Control list..
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:00:16_Using list file
F.JOB.LIST.2
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:00:16_Control list processing
7 7
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:00:16_Processing FT11104G2J9N
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:00:46_Finished processing
FT11104G2J9N
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:00:46_Processing FT111043W6YM
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:01:16_Finished processing
FT111043W6YM
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:01:16_19:16:16 Processed 2 lists
[2]
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:01:16_Processing FT1110496NKZ
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:01:46_Finished processing
FT1110496NKZ
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:01:46_Processing FT11104V59GH
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:02:16_Finished processing
FT11104V59GH
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:02:16_19:17:16 Processed 4 lists
[2]
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:02:16_SELECT F.JOB.LIST.2 SAMPLE
100000 Selected=1 time=0secs
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:02:16_Available list IDs
exhausted
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:02:46_Job finished by another
agent
</job>
</process>
<process name = BNK/SERVICE.TEST>
<job name = SERVICE.TEST>
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:03:46_Standard multi-thread job
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:03:46_Calling load routine
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:03:46_Obtained the Locking with
BNK/SERVICE.TEST-SERVICE.TEST-1 and F.JOB.LIST.2
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:03:46_Using list file
F.JOB.LIST.2
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:03:46_Control list processing
7 7
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:03:46_Processing FT11104G2J9N
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:04:16_Finished processing
FT11104G2J9N
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:04:16_Processing FT1110496NKZ
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:04:46_Finished processing
FT1110496NKZ
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:04:46_19:19:46 Processed 2 lists
[2]

REM Page 249


_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:04:46_Processing FT11104V59GH
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:05:16_Finished processing
FT11104V59GH
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:05:16_SELECT F.JOB.LIST.2
SAMPLE 100000 Selected=1 time=0secs
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:05:16_Available list IDs
exhausted
_BNK/SERVICE.TEST_SERVICE.TEST_3_04 MAR 2012_19:05:46_Job finished by another
agent
</job>
</process>

As it was written above, even if 5 minutes pass and agents are still working, TSM won’t force
them to quit. This makes tempting the idea to specify 0 agents at, say, 19:01 to be sure that
agents will be triggered only once – but since TSM sleeps for 1 minute between its iterations
there might be a slim chance that agents won’t be triggered at all. If you need your service to
run only once a day – use START instead of AUTO for it and agents will definitely be triggered
one time only but then SERVICE.CONTROL value will become STOP and unless you somehow
change it to START before the next day – it will not be started ever again.

14.19 Embed python into jBC code


Why? Because a lot of Python libraries exist that can be used in jBC (almost) directly.
Python is free and is available for many platforms. Example below is created under Windows
32bit + Python 2.7. Code below requires several external libraries to be installed (all free).
You also need to add Python “home” directory to PATH environment variable; same goes for
INCLUDE and LIB, e.g.:

set PATH=%PATH%;C:\kzm\tools\python27
set INCLUDE=%INCLUDE%;C:\kzm\tools\python27\include
set LIB=%LIB%;C:\kzm\tools\python27\libs

In this example an Excel file will be created (with different text attributes and a formula),
also SHA1 checksum of a string and md5 checksum of a file will be calculated.
Step 1. C routine PYTOOLS.c:

#include <jsystem.h>
#include <assert.h>

#include <Python.h>
PyObject *pFile, *pModule, *pDict, *pFunc, *pArgs, *pValue;

#ifdef DPSTRUCT_DEF
#define JBASEDP DPSTRUCT *dp,
#else
#define JBASEDP

// Page 250
#endif

/*
* C function called from jBC
*/

VAR *PyCALL(VAR *Result, JBASEDP VAR *VarFile, VAR *VarFunc, VAR *VarArgs)
{
char *cFile, *cFunc, *cArgs;
assert(dp != NULL);

cFile = (char *) CONV_SFB(VarFile);


cFunc = (char *) CONV_SFB(VarFunc);
cArgs = (char *) CONV_SFB(VarArgs);

Py_Initialize();
pFile = PyString_FromString(cFile);
pModule = PyImport_Import(pFile);
pDict = PyModule_GetDict(pModule);
pFunc = PyDict_GetItemString(pDict, cFunc);
pArgs = Py_BuildValue("(s)", cArgs);

if (PyCallable_Check(pFunc))
{
pValue = PyObject_CallObject(pFunc, pArgs);
STORE_VBS(Result, PyString_AsString(pValue) );
Py_DECREF(pValue);
Py_DECREF(pFunc);
} else
{
STORE_VBS(Result, "PYerror" );
}

Py_DECREF(pFile);
Py_DECREF(pModule);
Py_DECREF(pDict);
Py_DECREF(pArgs);
Py_Finalize();

return(Result);
}

Step 2. Compile C code:

jcompile PYTOOLS.c -d -s PYTOOLS.dll

Step 3. Python ”library” py function.py:

#!/usr/bin/env python

from time import time,ctime

# Page 251
import hashlib
import xlwt

def createXLS(s_data):
wbk = xlwt.Workbook()

style_normal = xlwt.XFStyle()
font = xlwt.Font()
font.name = 'Calibri'
font.height = 11*20
style_normal.font = font
style_bold = xlwt.XFStyle()

pattern = xlwt.Pattern() # Create the Pattern


pattern.pattern = xlwt.Pattern.SOLID_PATTERN
pattern.pattern_fore_colour = 5
font = xlwt.Font()
font.name = 'Calibri'
font.height = 11*20
font.bold = True
style_bold.font = font
style_bold.pattern = pattern # Add Pattern to Style

l_data = s_data.split('#')
s_output = l_data[0]
n_len = len(l_data)
for i in range(1, n_len):
s_sheet = l_data[i]
l_sheet = s_sheet.split('^')
s_sh_name = l_sheet[0]
sheet = wbk.add_sheet(s_sh_name)
n_sh_len = len(l_sheet)
for j in range(1, n_sh_len):
l_cell_data = l_sheet[j].split('|')
n_y = int(l_cell_data[0])
n_x = int(l_cell_data[1])
sheet.col(n_x).width = 6500
s_text = l_cell_data[2]
n_text_prop = int(l_cell_data[3])
if n_text_prop == 0:
sheet.write(n_y, n_x, s_text, style_normal)
elif n_text_prop == 1:
sheet.write(n_y, n_x, s_text, style_bold)
else:
sheet.write(n_y, n_x, xlwt.Formula(s_text))

wbk.save(s_output)

# Page 252
return str(j-1) + ' sheet(s) written to ' + s_output

def sha1(s_infile):
f_file_in = open(s_infile, 'rb')
v_text = f_file_in.read()
converted = hashlib.sha1(v_text).hexdigest()
return converted

def md5(s_infile):
f_file_in = open(s_infile, 'rb')
v_text = f_file_in.read()
return hashlib.md5(v_text).hexdigest()

def datesay(s_dummy):
return ctime(time())

def pyecho(s_in):
return s_in

def main():
s_out = 'standard library for jBC'
print s_out
return s_out

if __name__ == '__main__':
main()

note: After copypasting Python code restore line indents exactly as they are shown here!

Step 4. jBC routine test9.b:

DEFC VAR PyCALL(VAR, VAR, VAR)

CRT 'START'
CRT PyCALL('py_function', 'pyecho', 'Python interface is OK, date is:')
CRT PyCALL('py_function', 'datesay', '')
CRT PyCALL('py_function', 'sha1', 'testsha1.txt')
CRT PyCALL('py_function', 'md5', 'C:\\WINDOWS\\system32\\cmd.exe')

V.DATA = 'test001.xls#sheet1^0|0|standard text|0'


V.DATA := '^2|5|bold and highlighted text|1'
V.DATA := '#sheet2^0|0|100|0^1|0|200|0^2|0|A1+A2|2'

CRT PyCALL('py_function', 'createXLS', V.DATA)


CRT 'FINISH'

Step 5. Compile jBC code:

jcompile test9.b PYTOOLS.lib

REM Page 253


Finally, run test9.exe:

START
Python interface is OK, date is:
Thu Jan 19 21:46:51 2012
eb4209cd79d6cdc2443f8d868b50e54dc5c66f16
eeb024f2c81f0d55936fb825d21a91d6
2 sheet(s) written to test001.xls
FINISH

14.20 Adapt PuTTY for accepting T24 functional keys F1 ... F7

From an experienced C programmer’s view (which I’m not) some of my actions might be
wrong; any comments are welcome. Tested on Windows XP/SP2 using lcc-win32 C com-
piler.
Step 0. Create a directory for this exercise (e.g. C:\putty-workshop).
Step 1. Download PuTTY source code (version 0.60 will do). Extract it to directory
C:\putty-workshop\source directory. In this example I decided not to retain the direc-
tory “putty-0.60” which resided in archive putty-0.60.tar.gz so the full path to, e.g.,
putty.h is: C:\putty-workshop\source\putty.h.
Step 2. Download and install lcc-win32 C compiler and install it to C:\putty-workshop\lcc.
(Note that it’s free for non-commercial use.)
Step 3. To avoid linker error “Invalid resource file putty.res” – download MS resource compiler
and put its files to C:\putty-workshop\lcc\bin. One I have is:

"Microsoft (R) Windows 32 Resource Compiler, Version 5.00.1641.1 - Build 1641"

18.10.2010 17:14 7.440 rc.exe


18.10.2010 17:23 107.792 RCDLL.DLL

md5:

348493a159d4f2063a62097c41d99b53 lrc.exe
a6060e5c881865daa6f1b406b050bb5a RCDLL.DLL

Step 4. Amend the source code of config.c. Find the following line:

ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,

The line at the end of this statement is:


"VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);

// Page 254
Replace it with:

/* T24 amendment: "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL); */


"VT400", I(3), "VT100+", I(4), "SCO", I(5), "T24", I(6), NULL);

note: “/* T24” comment will help us to locate all changes later if need be.

Step 5. Amend the source code of putty.h. Find the following code:

enum {
/* Function key types (cfg.funky_type) */
FUNKY_TILDE,
FUNKY_LINUX,
FUNKY_XTERM,
FUNKY_VT400,
FUNKY_VT100P,
FUNKY_SCO
};

Add T24 to key types:

enum {
/* Function key types (cfg.funky_type) */
FUNKY_TILDE,
FUNKY_LINUX,
FUNKY_XTERM,
FUNKY_VT400,
FUNKY_VT100P,
FUNKY_SCO,
FUNKY_T24 /* T24 addition */
};

Step 6. Amend the source code of windows\window.c. Find the following line:

term->vt52_mode || cfg.funky_type == FUNKY_VT100P) && code >= 11 && code <= 24

Right before it insert the following lines:

if (cfg.funky_type == FUNKY_T24 && /* T24 addition start */


code >= 11 && code <= 15 || code == 17 || code == 18) {
switch (wParam) {
case VK_F1: *p++ = '\x15'; break;
case VK_F2: *p++ = '\x02'; break;
case VK_F3: *p++ = '\x06'; break;
case VK_F4: *p++ = '\x05'; break;
case VK_F5: *p++ = '\x16'; break;
case VK_F6: *p++ = '\x17'; break;

// Page 255
case VK_F7: *p++ = '\x14'; break;
}
*p++ = '\n';
return p - output;
} /* T24 addition end */

Step 7. Amend the source code of windows\winstuff.h. Find the following line:

#define PUTTY_REG_POS "Software\\SimonTatham\\PuTTY"

Amend the name of registry entry to avoid collisions with the standard PuTTY, e.g.:

#define PUTTY_REG_POS "Software\\SimonTatham\\PuTTYt24" /* T24 amendment */

Step 8. Amend the make file (windows\Makefile.lcc).


Find the line starting with:

CFLAGS = -D_WINDOWS -I..\./ -I..\charset/ -I..

Add more defines and “-g” option there so it looks like:

CFLAGS = -D_WINDOWS -DNO_MULTIMON -DNO_IPV6 -g -I..\./ -I..\charset/ -I..

To avoid compilation error “cannot open include file winresrc.h” and to use resource compiler
from MS – find the following line:

lrc $(RCFL) -r $(RCFLAGS) ..\windows\putty.rc

Replace it with:

rc $(RCFL) /r /d__LCC__ ..\windows\putty.rc

note: Avoid removing TAB or changing it to spaces at the beginning of the line.

Turn compiler optimization off (remove -O in all lines like that). Before:

lcc -O -p6 $(COMPAT) $(CFLAGS) $(XFLAGS) ..\be_all_s.c

After:

lcc -p6 $(COMPAT) $(CFLAGS) $(XFLAGS) ..\be_all_s.c

note: Not all sources are needed for putty.exe but it might be easier to change them all.

// Page 256
Step 9. Create putty-compile.bat in C:\putty-workshop:

cd source\windows
set INCLUDE=C:\putty-workshop\lcc\include;%INCLUDE%
set PATH=C:\putty-workshop\lcc\bin;%PATH%
set LIB=C:\putty-workshop\lcc\lib;%LIB
make -f makefile.lcc putty.exe 2>ERR.TXT

Step 10. Run putty-compile.bat. If you see something like (note “Time:” at the last line):

...
..\windows\winucs.c
lcc -p6 -D_WINDOWS -DNO_MULTIMON -DNO_IPV6 -g -I..\./ -I..\charset/ -I..\w
..\windows\winutils.c
lcc -p6 -D_WINDOWS -DNO_MULTIMON -DNO_IPV6 -g -I..\./ -I..\charset/ -I..\w
..\x11fwd.c
lcclnk -subsystem windows -o putty.exe be_all_s.obj cmdline.obj config.obj
isc.obj ldiscucs.obj logging.obj minibidi.obj misc.obj pinger.ob
putty.res raw.obj rlogin.obj sercfg.obj settings.obj sizetip.obj ssh
sshbn.obj sshcrc.obj sshcrcda.obj sshdes.obj sshdh.obj
j sshrand.obj sshrsa.obj sshsh256.obj sshsh512.obj sshsha.obj ss
.obj timing.obj tree234.obj version.obj wcwidth.obj wildcard.obj wi
obj window.obj winhandl.obj winhelp.obj winmisc.obj winnet.obj
nt.obj winproxy.obj winser.obj winstore.obj wintime.obj winucs.obj
32.lib wsock32.lib ws2_32.lib winspool.lib winmm.lib imm32.lib
Time: 8.987 seconds

...then all is OK and you have putty.exe in source\windows subdirectoty. If not – see file
ERR.TXT located at the same place.

14.21 Run PuTTY in typical T24 environment without using reg-


istry
I also proceeded with certain changes that allowed me to run PuTTY using command line
only.
Changes in settings.c:

// Increased back scroll:


gppi(sesskey, "ScrollbackLines", 2000, &cfg->savelines);

/* Remove answer to Ctrl-E (otherwise there will be "PuTTY" hidden output


when T24 asks for user name - so one has to either use backspace or
get login error) */
gpps(sesskey, "Answerback", "", cfg->answerback,
sizeof(cfg->answerback));
...

// Page 257
// Set UTF-8 translation as a default:
gpps(sesskey, "LineCodePage", "UTF-8", cfg->line_codepage,
sizeof(cfg->line_codepage));
...

// Set T24 keyboard by default:


gppi(sesskey, "LinuxFunctionKeys", 6, &cfg->funky_type);
...

// Screen width=132:
gppi(sesskey, "TermWidth", 132, &cfg->width);

A new parameter (-z "window title") was added (I need it for automatic start from
SciTE, see “Source code editing” chapter). Changes done in cmdline.c, the very end of
cmdline process param function:

// Tuesday, 24 Jul 2012, 21:40:50


if (!strcmp(p, "-z")) {
RETURN(2);
SAVEABLE(0);
strncpy(cfg->wintitle, value, sizeof(cfg->wintitle));
cfg->wintitle[sizeof(cfg->wintitle) - 1] = '\0';
}

Another change – set the colour scheme in command line. See the excerpt from cmdline.c
that is situated right after the previous example:

// Thursday, 09 Aug 2012, 22:13:14


if (!strcmp(p, "-bkgr_red")) {
RETURN(1);
SAVEABLE(0);
cfg->colours[2][0] = 128;
}

if (!strcmp(p, "-bkgr_blue")) {
RETURN(1);
SAVEABLE(0);
cfg->colours[2][2] = 128;
}
if (!strcmp(p, "-bkgr_cyan")) {
RETURN(1);
SAVEABLE(0);
cfg->colours[0][0] = 255;
cfg->colours[0][1] = 255;
cfg->colours[0][2] = 255;
cfg->colours[2][1] = 144;
cfg->colours[2][2] = 144;
}

REM Page 258


Useful to tell one environment from another, like:

REM %1 is IP, %2 is login name


putty.exe %1 -ssh -l %2 -z "Development" -bkgr_blue

Or:

putty.exe %1 -ssh -l %2 -z "UAT" -bkgr_cyan

Or:

putty.exe %1 -ssh -l %2 -z "Production copy" -bkgr_red

14.22 Create a reverse tunnel so you can log in from Unix server
to your local PC
Step 1. Use plink.exe (shipped with PuTTY) on the local machine to create a tunnel:

plink.exe -R 19999:localhost:23 -pw <password> <user>@<Unix-server>

note: In this example local PC has Telnet (hence port 23) but of course ssh is better
Step 2. Open another session and log in to Unix server in normal way.
Step 3. In that session:

jsh -->bash
bash-3.00$ telnet localhost 19999
Trying...
Connected to loopback.
Escape character is '^]'.
jBASE Telnetd Server Version 3.6.9.1

Account Name: acct_name


Password:
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

jsh -->

note: “keepalive” is recommended (not in this sample since I hadn’t the latest plink)

REM Page 259


14.23 Upload a file to server in one step (SCP)
Use pscp.exe (shipped with PuTTY):

pscp.exe -l USER -pw PASSWORD -scp FILE SERVER-IP-ADDRESS:FILE

note: Uppercase parts are to be replaced with respective values.

14.24 Automate frequently used command on a server (e.g. com-


pile a source)
Use plink.exe (shipped with PuTTY):

plink.exe -m cmd-file.txt -ssh -l USER -pw PASSWORD SERVER-IP-ADDRESS

note: Uppercase parts are to be replaced with respective values.


Contents of cmd-file.txt used in this example:

export HOME=$PWD
export TAFC_HOME=/usr/jbc
export PATH=$TAFC_HOME/bin:$HOME/bin:/usr/vacpp/bin:$PATH
export LIBPATH=$TAFC_HOME/lib:/usr/ccs/lib:/usr/lib
export JEDIFILENAME_MD=$HOME/VOC
export JBCEMULATE=prime
export JBASE_I18N=1
export JBCOBJECTLIST=$HOME/lib:$HOME/t24lib
export JEDIENABLEQ2Q=1
jcompile -E -I../T24_BP test.b

14.25 Login automatically to T24 using Browser client


The long link below automatically logs in standard T24 user INPUTTER using password 123456
(all it is one line, splitted only to fit into this screen):

http://localhost:9095/BrowserWeb/servlet/BrowserServlet?method=POST
&command=login&requestType=CREATE.SESSION&counter=0&branchAdminLogin=
&signOnName=INPUTT&password=123456

note: Of course this method is recommended only for non-sensitive T24 environments.

REM Page 260


14.26 Execute a program in background
Program parameter “-Jb” is used for that. Example:
Step 1. A program:

EXECUTE 'COMO ON TEST'


CRT 'Command line: ' : SYSTEM(1000)
CRT 'Full command line: ' : SYSTEM(1001)
LOOP
CRT TIMEDATE()
MSLEEP 3000
REPEAT
EXECUTE 'COMO OFF'
Step 2. Run it:
test -Jb

Step 3. Stop it:


WHERE
Port Device Account PID Command
*1 vt220 Vladimir.Kaz 888 jsh
WHERE
2 vt220 Vladimir.Kaz 1276 C:\jBC\test.exe -Jz

LOGOFF 2

Step 4. See program output:


CT &COMO& TEST
COMO TEST established 19:08:57 05 JUN 2013
Command line: C:\jBC\test.exe
Full command line: C:\jBC\test.exe.-Jz
19:08:57 05 JUN 2013
19:09:00 05 JUN 2013
19:09:03 05 JUN 2013
19:09:06 05 JUN 2013
19:09:09 05 JUN 2013
19:09:12 05 JUN 2013
19:09:15 05 JUN 2013
19:09:18 05 JUN 2013
19:09:21 05 JUN 2013
19:09:24 05 JUN 2013
19:09:27 05 JUN 2013
19:09:30 05 JUN 2013
19:09:33 05 JUN 2013
19:09:36 05 JUN 2013
19:09:39 05 JUN 2013
Logged off by user 'Vladimir.Kazimirchik' from port 1

REM Page 261


14.27 Generate a simple temporary text file on the fly
Normally people generate them by CREATE-FILE UD ->OPEN ->WRITE approach.
Instead, you can (for example):

INCLUDE JBC.h
*
* Create custom "file.txt".
*
file_path_parent = '..'
file_path = file_path_parent : DIR_DELIM_CH : "file.txt"
file_contents = "";
file_contents<-1> = 'line1'
file_contents<-1> = 'line2'
file_contents<-1> = 'line3'
file_contents<-1> = 'line4'
* ...
OSWRITE file_contents ON file_path

note: DIR DELIM CH from JBC.h allows to make it cross-platform.

14.28 Create a directory


More often people call “mkdir” via EXECUTE/PERFORM. It always looks ugly, it has to
be tweaked for UNIX and Windows, and finally it’s slow on Windows because it invokes an
external process.
Instead you can:

INCLUDE JBC.h
*
file_path_parent = '..'
file_path = file_path_parent : DIR_DELIM_CH : "new_folder"
PERFORM "CREATE-FILE DATA " : file_path : " TYPE=UD" CAPTURING output

15 Performance notes
The main thing to remember is: poorly designed local development can easily bring even the
most powerful T24 server to its proverbial knees.
Some more or less obvious points:
• Minimize the time for keeping a lock. It’s wrong in my opinion to issue one and then let
user to decide something.
• Don’t create local applications with too many fields. There’s a limitation of 500 but it’s
too generous for my liking. Multi- and sub-valuing fields, associating them together adds to
that.
• Don’t create too many local fields for any application. Again, 999 is the limit which is too
big.

REM Page 262


• Always take a close look at the finalized code – maybe something “static” (like opening
a file) ended up inside a loop? Another thing to look at – do any sections have RETURN
statement missing? (And the latter might affect not only performance of course.)
• T24 caches many things (like SPF record) so you don’t need to read them from a table.
• In a local application (especially one that is often SELECTed) put as many things as you
can into @id (and construct it keeping in mind the most popular SELECTs – e.g. if you expect
to sort things mostly by date then put it to the first place).
• If a local application records are to be locked often – don’t make @id for it too generic
(e.g. using only the currency code means that all transactions that use the same currency
should wait in a queue).
• Creating EB.ALTERNATE.KEY or an index might help in SELECTs but adds time to
write records to “master” table.
• Use existing “concat” files wherever possible (such as CUSTOMER.ACCOUNT, ALTER-
NATE.ACCOUNT or MNEMONIC.CUSTOMER).
• Don’t be tempted to use a core routine to achieve your goal – besides the fact that it
might be extinct one day you might also face a huge overhead. In many cases you can avoid
all T24 overheads writing a program instead of a subroutine.
• Population of a new dynamic array proves to be faster if it’s started from the last element.
(Initial memory allocation is certainly bigger in this case.)
• Last but not least – many things in T24 setup can be switched off (provided that required
business functionality doesn’t suffer) – such as position update for certain type of deals etc.

16 Known issues
All these issues were reported (though unofficially) and either are in the process of being
corrected or declared to be the natural jBASE behaviour.

16.1 jQL “BUT”


“BUT” is supposed to be the same as “OR WITH”, but:

LIST FBNK.ACCOUNT CATEGORY CURRENCY WITH CATEGORY EQ 1002 BUT CURRENCY EQ EUR
@ID................ CATEGORY CURRENCY CURRENCY

41017 1002 USD


41475 1002 USD
41947 1002 USD
42137 1002 USD
41707 1002 USD
42102 1002 USD
41928 1002 USD
50032 1002 USD
49867 1002 USD
42118 1002 USD
42088 1002 USD

REM Page 263


44016 1002 USD

12 Records Listed

LIST FBNK.ACCOUNT CATEGORY CURRENCY WITH CATEGORY EQ 1002 OR WITH CURRENCY EQ EUR
@ID................ CATEGORY CURRENCY

EUR141850743 14185 EUR


14087 1001 EUR
EUR150050001 15005 EUR
44636 6601 EUR
EUR128000003 12800 EUR
40061 1001 EUR
43206 1001 EUR
EUR144410001 14441 EUR
42935 1001 EUR
15307 1001 EUR
EUR144210001 14421 EUR
41017 1002 USD
EUR143040074 14304 EUR
17124 6001 EUR
...
11312 1001 EUR
EUR100010001 10001 EUR

211 Records Listed

16.2 Basic SSELECT...TO {list number}


EXECUTE 'CREATE-FILE ABC.DEF TYPE=J4 101 1'
OPEN 'ABC.DEF' TO f_in ELSE ABORT 201, 'ABC.DEF'
WRITE 'FIELD 1' : @FM : 'FIELD 2' TO f_in, 'REC0001'
SSELECT f_in TO 9 ;* session terminates; "SSELECT f_in TO list_var" works

16.3 SSELECT...SAVING EVAL


SSELECT VOC WITH F1 LIKE F... SAVING EVAL "'COPY FROM ':@ID:' TO &TEMP& ALL'"

20549 Records selected

>SAVE.LIST LIST1

SELECT VOC WITH F1 LIKE F... SAVING EVAL "'COPY FROM ':@ID:' TO &TEMP& ALL'"

20549 Records selected

>SAVE.LIST LIST2

REM Page 264


CT &SAVEDLISTS& LIST1

001 "
002
003 "
004
005 (
006 "
007 !
008 )
009 )
...

CT &SAVEDLISTS& LIST2

001 COPY FROM F.DX.REVAL.DET.ENHANCED TO &TEMP& ALL


002 COPY FROM F.GENERATE.ENTRY.WRK TO &TEMP& ALL
003 COPY FROM F.GT.SYSTEM.PARAMETER$NAU TO &TEMP& ALL
004 COPY FROM F.RUN.GRP.PERF.TAKEON TO &TEMP& ALL
005 COPY FROM F.SA.RATIOS TO &TEMP& ALL
006 COPY FROM F.SC.CCY.RANK TO &TEMP& ALL
007 COPY FROM F.SETTLEMENT.FRA TO &TEMP& ALL
008 COPY FROM FBNK.ADHOC.STATEMENTS TO &TEMP& ALL
009 COPY FROM FBNK.AM.SIZING$NAU TO &TEMP& ALL
...

16.4 EVAL ABSS()


LIST . SAMPLE 1 EVAL "ABSS(-1:@FM:-2:@FM:-3)"

DICT ......... ABSS(-1:@FM:-2:@FM:-3)

$FORD.IN.OUT 1
0
0

16.5 Differences in default SELECT list and a numbered one with


non-zero number
SELECT FBNK.ACCOUNT

1673 Records selected

>SELECT FBNK.ACCOUNT UNLIKE ...

REM Page 265


No Records selected

CLEARSELECT 0
[526] List '0' is inactive.

SELECT FBNK.ACCOUNT TO 1

1673 Records selected

SELECT FBNK.ACCOUNT UNLIKE ... TO 1

No Records selected

CLEARSELECT 1
[528] List '1' cleared.

note: After second SELECT list #1 still contained records but default one didn’t.

16.6 NSELECT doesn’t keep a list


SELECT F.CATEGORY

1173 Records selected

>NSELECT FBNK.ACCOUNT CATEGORY

1157 Records selected

SAVE.LIST RESULTS
No default select list is active

16.7 jQL “COPY...UPDATING”


Is supposed to copy only records that present in the target files, but:

LIST &TEMP&
No Records Listed

CT VOC TEST.LOGIN
'TEST.LOGIN' record not found

COPY FROM VOC TO &TEMP& EBS.LOGIN


1 records copied

COPY FROM &TEMP& EBS.LOGIN,TEST.LOGIN


1 records copied

REM Page 266


COPY FROM &TEMP& TO VOC ALL UPDATING
2 records copied

CT VOC TEST.LOGIN
TEST.LOGIN
001 PA
002 EBS.TERMINAL.SELECT
003 EX
004 EX.INTEGRITY
005 * LO

16.8 Nesting of jsh shells


It’s a good idea to avoid (accidental or deliberate) starting another jsh shell from an existing
one.
A simplified example shows that some things work differently in this case. A paragraph with
a parameter is illustrated here.
Step 1. Create a paragraph to list some tafc system files:

JED VOC SYSF

0001 PA
0002 CT C:\home\kzm\v-t24\r11\tafc <<C2,''>>

note: Amend the path to TAFC to yours.


Step 2. List RELEASE file using this paragraph:

SYSF RELEASE

RELEASE
001 jBase Release : R11.0.0.0
002 Create date : Tue Apr 19 14:12:00 2011
003 Patch Level :
004 Change Level : 94295

Step 3. Start another copy of jsh and try to list OPTIONS file:

jsh

SYSF OPTIONS

RELEASE
001 jBase Release : R11.0.0.0
002 Create date : Tue Apr 19 14:12:00 2011

REM Page 267


003 Patch Level :
004 Change Level : 94295

Still we see contents of RELEASE (even if you omit file name):

SYSF

RELEASE
001 jBase Release : R11.0.0.0
002 Create date : Tue Apr 19 14:12:00 2011
003 Patch Level :
004 Change Level : 94295

Step 4. Return to 1st jshell (Ctrl-D or exit). Now:

SYSF OPTIONS

OPTIONS
001 #
002 # This file was auto-created at Tue Apr 19 14:12:01 2011
003 # Created from E:\src\TAFC\R11\port\Template\Options.template
004 #
...etc.

16.9 FIELD() with multi-character delimiter


string = 'ABC>DEF>QWE>XYZ'
CRT FIELD(string, '>', 2) ;* DEF
CRT FIELD(string, '>', 2, 2) ;* DEF>QWE - correct
string = 'ABC->DEF->QWE->XYZ'
CRT FIELD(string, '->', 2) ;* DEF
CRT FIELD(string, '->', 2, 2) ;* >DEF->QWE, should be: DEF->QWE
CRT string[ '->', 2, 3 ] ;* >DEF->QWE->XYZ, leading '>' again...
CHANGE '->' TO '(-)' IN string ; CRT string ;* ABC(-)DEF(-)QWE(-)XYZ
CRT SQUOTE(FIELD(string, '(-)', 2)) ;* 'DEF'
CRT SQUOTE(FIELD(string, '(-)', 2, 2)) ;* '-)DEF(-)QWE'

16.10 COMPARE() doesn’t work as expected


INCLUDE JBC.h
string_a = 'XY999'
string_b = 'XY1000'
result_l = COMPARE(string_a, string_b, 'L')
exp_result_l = 1 ;* string_a is greater than string_b
ASSERTEQUALS(result_l, exp_result_l)
result_r = COMPARE(string_a, string_b, 'R')
exp_result_r = -1 ;* string_a is less than string_b if right-justified
ASSERTEQUALS(result_r, exp_result_r)

REM Page 268


Output:

ERROR! Assert equal test failed in test.b, at line 9

16.11 DELETEU behaviour


In contraversion to the manual, it DOES release the lock on the deleted record.

17 T24 classic
17.1 What works there (as well as elsewhere)
• Non-tabbed VERSION’s.
• ENQUIRY’s
• OFS.

17.2 What works only there


• EBS.AUTO.FUNCTION
• Mainline routines (Desktop also has it).

17.3 What doesn’t work there


• VB scripts (that’s – Desktop only).
• Multi-tabbed VERSION’s (you see only the first tab).
• AA stuff (though AA-related OFS does).

17.4 Navigation keys


F1/Ctrl-U+Return - “Up”.
F2/Ctrl-B+Return - “Back”.
F3/Ctrl-F+Return - “Forward”.
F4/Ctrl-E+Return - “End”.
F5/Ctrl-V+Return - “Verify (actually – commit)”.
F6/Ctrl-W+Return - “Double-V (commit and move forward)”.
F7/Ctrl-T+Return - “Text edit”.

17.5 Navigation levels


• AWAITING APPLICATION
• AWAITING FUNCTION
• AWAITING ID
• AWAITING PAGE INSTRUCTIONS

REM Page 269


17.6 Navigation lesson #1
Screen after login:

Model Bank SELECT APPLICATION

------------------------------------------------------------------------------

------------------------------------------------------------------------------
16 NOV 2011 19:06:18 USER (09 AUG) VLADIMIR.K [6567,IN]
ACTION
AWAITING APPLICATION

Enter application (SPF ←- ):

Model Bank SPF

------------------------------------------------------------------------------

REM Page 270


------------------------------------------------------------------------------
16 NOV 2011 19:31:09 USER (09 AUG) VLADIMIR.K [6567,IN]
ACTION
AWAITING FUNCTION

Go back ( F1 ):

Model Bank SELECT APPLICATION

------------------------------------------------------------------------------

------------------------------------------------------------------------------
16 NOV 2011 19:33:50 USER (09 AUG) VLADIMIR.K [6567,IN]
ACTION
AWAITING APPLICATION

Another application (VERSION ←- ):

Model Bank VERSION

------------------------------------------------------------------------------

REM Page 271


------------------------------------------------------------------------------
16 NOV 2011 19:35:21 USER (09 AUG) VLADIMIR.K [6567,IN]
ACTION
AWAITING FUNCTION

List records ( L ←- ):

Model Bank VERSION - Default List

ID PRINT.ONLY FUNCT.
------------------------------------------------------------------------------
1 AA.ACCRUAL.FREQUENCY,
2 AA.ACCRUAL.FREQUENCY,AA
3 AA.ACCRUAL.FREQUENCY,AA.AUDIT
4 AA.ACCRUAL.FREQUENCY,MB.OFS.AUTH
5 AA.ACTIVITY,
6 AA.ACTIVITY,AA
7 AA.ACTIVITY,AA.AUDIT
8 AA.ACTIVITY,MB.OFS.AUTH
9 AA.ACTIVITY.CLASS,
10 AA.ACTIVITY.CLASS,AA
11 AA.ACTIVITY.CLASS,AA.ACTIONS
12 AA.ACTIVITY.CLASS,AA.AUDIT
13 AA.ACTIVITY.CLASS,AA.BATCH
14 AA.ACTIVITY.CLASS,AA.TYPE
15 AA.ACTIVITY.CLASS,MB.OFS.AUTH
16 AA.ARR.AC.ACCT.GROUP.CONDN,
------------------------------------------------------------------------------
16 NOV 2011 19:35:54 USER (09 AUG) VLADIMIR.K [6567,INPAGE 1 >>>3>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Go forward ( F3 ):

Model Bank VERSION - Default List

REM Page 272


ID PRINT.ONLY FUNCT.
------------------------------------------------------------------------------
1 AA.ARR.AC.GENERAL.CHARGE,
2 AA.ARR.AC.GROUP.CAP,
3 AA.ARR.AC.GROUP.INTEREST,
4 AA.ARR.ACCOUNT,
5 AA.ARR.ACCOUNT,AA
6 AA.ARR.ACCOUNT,AA.NEGOTIABLE
7 AA.ARR.ACCOUNT,AA.SIMPLE
8 AA.ARR.ACCOUNT,CONTROL
9 AA.ARR.ACCOUNT,MB.OFS.AUTH
10 AA.ARR.ACCOUNTING,
11 AA.ARR.ACCOUNTING,AA
12 AA.ARR.ACTIVITY.API,
13 AA.ARR.ACTIVITY.API,AA
14 AA.ARR.ACTIVITY.CHARGES,
15 AA.ARR.ACTIVITY.CHARGES,AA
16 AA.ARR.ACTIVITY.CHARGES,MB.OFS.AUTH
------------------------------------------------------------------------------
16 NOV 2011 19:35:54 USER (09 AUG) VLADIMIR.K [6567,INPAGE 2 >>>4>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Go to page #5 ( P5 ←- ):

Model Bank VERSION - Default List

ID PRINT.ONLY FUNCT.
------------------------------------------------------------------------------
1 AA.ARR.CHANGE.PRODUCT,
2 AA.ARR.CHANGE.PRODUCT,AA
3 AA.ARR.CHANGE.PRODUCT,AA.CONTROL
4 AA.ARR.CHANGE.PRODUCT,AA.MORTGAGE
5 AA.ARR.CHANGE.PRODUCT,AA.NOINPUT
6 AA.ARR.CHANGE.PRODUCT,AA.SIMPLE
7 AA.ARR.CHARGE,
8 AA.ARR.CHARGE,AA
9 AA.ARR.CHARGE,AA.CALCULATED
10 AA.ARR.CHARGE,AA.CALCULATED.PA
11 AA.ARR.CHARGE,AA.CONTROL
12 AA.ARR.CHARGE,AA.FIXED
13 AA.ARR.CHARGE,AA.FIXED.PA
14 AA.ARR.CHARGE,AA.NOINPUT
15 AA.ARR.CHARGE,MB.OFS.AUTH
16 AA.ARR.CHARGE.OVERRIDE,
------------------------------------------------------------------------------
16 NOV 2011 19:37:35 USER (09 AUG) VLADIMIR.K [6567,INPAGE 5 >>>7>>>

REM Page 273


ACTION
AWAITING PAGE INSTRUCTIONS

note: Might get “Page incomplete” message, press F3 then.


Go back one page ( F2 ):

Model Bank VERSION - Default List

ID PRINT.ONLY FUNCT.
------------------------------------------------------------------------------
1 AA.ARR.ALERTS,AA.NR
2 AA.ARR.ALERTS,MB.OFS.AUTH
3 AA.ARR.AZ.ACCOUNTING,
4 AA.ARR.AZ.CR.CARD,
5 AA.ARR.AZ.DEPOSIT,
6 AA.ARR.AZ.LOAN,
7 AA.ARR.AZ.SAVINGS,
8 AA.ARR.BALANCE.AVAILABILITY,AA
9 AA.ARR.BALANCE.MAINTENANCE,
10 AA.ARR.BALANCE.MAINTENANCE,AA
11 AA.ARR.BALANCE.MAINTENANCE,AA.ADJ.BALS
12 AA.ARR.BALANCE.MAINTENANCE,AA.ADJ.BILLS
13 AA.ARR.BALANCE.MAINTENANCE,AA.BALS
14 AA.ARR.BALANCE.MAINTENANCE,AA.BILLS
15 AA.ARR.BALANCE.MAINTENANCE,AA.NOINPUT
16 AA.ARR.BALANCE.MAINTENANCE,MB.OFS.AUTH
------------------------------------------------------------------------------
16 NOV 2011 19:37:35 USER (09 AUG) VLADIMIR.K [6567,INPAGE 4 >>>7>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Go one level up ( F1 ):

Model Bank VERSION

------------------------------------------------------------------------------

REM Page 274


------------------------------------------------------------------------------
16 NOV 2011 19:41:22 USER (09 AUG) VLADIMIR.K [6567,IN]
ACTION
AWAITING FUNCTION

Start listing from particular @ids ( L -FUN ←- ):

Model Bank VERSION LIST

NO. ID RECORD FIELDS FUNCT.


------------------------------------------------------------------------------
1 FUNDS.TRANSFER, 1 1 0 COMMISSION.TYPE LOCAL.REF YES 1 YES|
2 FUNDS.TRANSFER,AA.ACCR 1 MULTI 1 CREDIT.ACCT.NO 1 17 Arran|
3 FUNDS.TRANSFER,AA.ACDF 1 MULTI 1 CREDIT.ACCT.NO 1 17 Arran|
4 FUNDS.TRANSFER,AA.ACDI 1 MULTI 1 DEBIT.ACCT.NO 1 17 Arrang|
5 FUNDS.TRANSFER,AA.ACDP 1 MULTI 1 DEBIT.ACCT.NO 1 17 Arrang|
6 FUNDS.TRANSFER,AA.ACPD 1 MULTI 1 CREDIT.ACCT.NO 1 17 Arran|
7 FUNDS.TRANSFER,AA.ACPO 1 MULTI 1 CREDIT.ACCT.NO 1 17 Arran|
8 FUNDS.TRANSFER,AA.ACPP 1 MULTI 1 DEBIT.ACCT.NO 1 17 Arrang|
9 FUNDS.TRANSFER,AA.ACR1 1 MULTI 1 CREDIT.ACCT.NO 1 17 Arran|
10 FUNDS.TRANSFER,AA.ACR2 1 MULTI 1 DEBIT.ACCT.NO 1 17 Arrang|
11 FUNDS.TRANSFER,AA.ACRP 1 MULTI 1 CREDIT.ACCT.NO 1 17 Arran|
12 FUNDS.TRANSFER,AA.ML.ACDI 1 MULTI 1 DEBIT.ACCT.NO 1 17 Deb|
13 FUNDS.TRANSFER,AC 1 MULTI 1 Transfer Between Accounts DEBIT.|
14 FUNDS.TRANSFER,ACT.CLOSURE 1 MULTI 1 Transfer Between Account|
15 FUNDS.TRANSFER,ACT.CLOSURE.PW 1 MULTI 1 Transfer Between Acco|
16 FUNDS.TRANSFER,ACTR 1 MULTI 1 Transfer Between Accounts DEBI|
------------------------------------------------------------------------------
16 NOV 2011 19:42:24 USER (09 AUG) VLADIMIR.K [6567,INPAGE 1
ACTION
AWAITING PAGE INSTRUCTIONS

note: Not able to “go back” from here.


Edit particular record ( 13 ←- I F5 ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------

REM Page 275


1 PRINT.ONLY........
2 RECORDS.PER.PAGE.. 1
3 FIELDS.PER.LINE... MULTI
4. 1 LANGUAGE.CODE.. 1 English
5. 1 HDR.1.001..039. Transfer Between Accounts
6. 1 HDR.1.040..078.
7. 1 HDR.1.079..117.
8. 1 HDR.1.118..132.
9. 1 HDR.2.001..039.
10. 1 HDR.2.040..078.
11. 1 HDR.2.079..117.
12. 1 HDR.2.118..132.
13. 1 FIELD.NO....... DEBIT.ACCT.NO DEBIT.ACCT.NO
14. 1 COLUMN......... 1
15. 1 EXPANSION......
16. 1 TEXT.CHAR.MAX.. 25
------------------------------------------------------------------------------
16 NOV 2011 19:45:44 USER (09 AUG) VLADIMIR.K [6567,I PAGE 1 >>42>>>
ACTION
AWAITING PAGE INSTRUCTIONS

note: Several records can be marked at the same time; functions can be different:

Model Bank VERSION LIST

NO. ID RECORD FIELDS FUNCT.


------------------------------------------------------------------------------
1 FUNDS.TRANSFER, 1 1 0 COMMISSION.TYPE LOCAL.REF YES 1 YES| S
2 FUNDS.TRANSFER,AA.ACCR 1 MULTI 1 CREDIT.ACCT.NO 1 17 Arran| S
3 FUNDS.TRANSFER,AA.ACDF 1 MULTI 1 CREDIT.ACCT.NO 1 17 Arran| I
4 FUNDS.TRANSFER,AA.ACDI 1 MULTI 1 DEBIT.ACCT.NO 1 17 Arrang| R
5 FUNDS.TRANSFER,AA.ACDP 1 MULTI 1 DEBIT.ACCT.NO 1 17 Arrang|
6 FUNDS.TRANSFER,AA.ACPD 1 MULTI 1 CREDIT.ACCT.NO 1 17 Arran|
7 FUNDS.TRANSFER,AA.ACPO 1 MULTI 1 CREDIT.ACCT.NO 1 17 Arran| R
8 FUNDS.TRANSFER,AA.ACPP 1 MULTI 1 DEBIT.ACCT.NO 1 17 Arrang|
9 FUNDS.TRANSFER,AA.ACR1 1 MULTI 1 CREDIT.ACCT.NO 1 17 Arran| S
10 FUNDS.TRANSFER,AA.ACR2 1 MULTI 1 DEBIT.ACCT.NO 1 17 Arrang|
11 FUNDS.TRANSFER,AA.ACRP 1 MULTI 1 CREDIT.ACCT.NO 1 17 Arran|
12 FUNDS.TRANSFER,AA.ML.ACDI 1 MULTI 1 DEBIT.ACCT.NO 1 17 Deb|
13 FUNDS.TRANSFER,AC 1 MULTI 1 Transfer Between Accounts DEBIT.|
14 FUNDS.TRANSFER,ACT.CLOSURE 1 MULTI 1 Transfer Between Account|
15 FUNDS.TRANSFER,ACT.CLOSURE.PW 1 MULTI 1 Transfer Between Acco|
16 FUNDS.TRANSFER,ACTR 1 MULTI 1 Transfer Between Accounts DEBI|
------------------------------------------------------------------------------
16 NOV 2011 19:46:34 USER (09 AUG) VLADIMIR.K [6567,INPAGE 1
ACTION
AWAITING PAGE INSTRUCTIONS

REM Page 276


note: F5 will start processing records – one at a time.

Back to edit screen; go to last page ( F4 ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
99 RESERVED.3........
100 RESERVED.2........
101. 1 OVERRIDE.......
102 RECORD.STATUS.....
103 CURR.NO........... 2
104. 1 INPUTTER....... 1_DIM
105. 1 DATE.TIME...... 10 MAR 11 05:33
105. 2 DATE.TIME...... 10 MAR 11 05:32
106 AUTHORISER........ 495_INPUTTER_OFS_MB.OFS.AUTH
107 CO.CODE........... GB-001-0001 Model Bank
108 DEPT.CODE......... 1 Implementation
109 AUDITOR.CODE......
110 AUDIT.DATE.TIME...

------------------------------------------------------------------------------
16 NOV 2011 19:48:39 USER (09 AUG) VLADIMIR.K [6567,I PAGE 42
ACTION
AWAITING PAGE INSTRUCTIONS

Go back one page ( F2 ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
83 COMPANY.ACCESS....
84 BUSINESS.DAY......
85 AUTO.COMP.CHANGE..
86 SYS.MSG.SUPPRESS..
87. 1 ATTRIBUTES..... NO.HEADER.TAB
88 D.SLIP.STYLE.SHEET
89 WEB.VAL.RTN.......
90 CONFIRM.VERSION...
91 PREVIEW.VERSION...
92 BROWSER.TOOLBAR...
93 EXPOSE............
94. 1 SERVICE........

REM Page 277


95 ACTIVITY..........
96 FUNCT.............
97 EXPOSE.DESC.......
98 CHALL.RESP........
------------------------------------------------------------------------------
16 NOV 2011 19:49:32 USER (09 AUG) VLADIMIR.K [6567,I PAGE 41 >>42>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Go to particular field ( 87.1 ←- ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
83 COMPANY.ACCESS....
84 BUSINESS.DAY......
85 AUTO.COMP.CHANGE..
86 SYS.MSG.SUPPRESS..
87. 1 ATTRIBUTES..... N O.HEADER.TAB
88 D.SLIP.STYLE.SHEET
89 WEB.VAL.RTN.......
90 CONFIRM.VERSION...
91 PREVIEW.VERSION...
92 BROWSER.TOOLBAR...
93 EXPOSE............
94. 1 SERVICE........
95 ACTIVITY..........
96 FUNCT.............
97 EXPOSE.DESC.......
------------------------------------------------------------------------------
16 NOV 2011 19:50:31 USER (09 AUG) VLADIMIR.K [6567,I PAGE 41 >>42>>>
ACTION

Expand it ( < ←- ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
83 COMPANY.ACCESS....
84 BUSINESS.DAY......
85 AUTO.COMP.CHANGE..
86 SYS.MSG.SUPPRESS..
87. 1 ATTRIBUTES.....
87. 2 ATTRIBUTES..... NO.HEADER.TAB

REM Page 278


88 D.SLIP.STYLE.SHEET
89 WEB.VAL.RTN.......
90 CONFIRM.VERSION...
91 PREVIEW.VERSION...
92 BROWSER.TOOLBAR...
93 EXPOSE............
94. 1 SERVICE........
95 ACTIVITY..........
96 FUNCT.............
97 EXPOSE.DESC.......
------------------------------------------------------------------------------
16 NOV 2011 19:51:31 USER (09 AUG) VLADIMIR.K [6567,I PAGE 41 >>42>>>
ACTION

note: Underlined are new and changed fields.


Use a list of choices for this field ( ←- ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
83 COMPANY.ACCESS....
84 BUSINESS.DAY......
85 AUTO.COMP.CHANGE..
86 SYS.MSG.SUPPRESS..
87. 1 ATTRIBUTES.....
87. 2 ATTRIBUTES..... NO.HEADER.TAB
88 D.SLIP.STYLE.SHEET
89 WEB.VAL.RTN.......
90 CONFIRM.VERSION...
91 PREVIEW.VERSION...
92 BROWSER.TOOLBAR...
93 EXPOSE............
94. 1 SERVICE........
95 ACTIVITY..........
96 FUNCT.............
97 EXPOSE.DESC.......
------------------------------------------------------------------------------
16 NOV 2011 20:10:24 USER (09 AUG) VLADIMIR.K [6567,I PAGE 41 >>42>>>
ACTION
PROPOSAL 'NO.HEADER.TAB' OK. (Y, NO, _)

Get a next choice from a list ( ←- ):

------------------------------------------------------------------------------
16 NOV 2011 20:10:24 USER (09 AUG) VLADIMIR.K [6567,I PAGE 41 >>42>>>

REM Page 279


ACTION
PROPOSAL 'SHOW.NULL.FIELDS' OK. (Y, NO, _)

Select this value ( Y ←- ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
83 COMPANY.ACCESS....
84 BUSINESS.DAY......
85 AUTO.COMP.CHANGE..
86 SYS.MSG.SUPPRESS..
87. 1 ATTRIBUTES..... SHOW.NULL.FIELDS
87. 2 ATTRIBUTES..... N O.HEADER.TAB
88 D.SLIP.STYLE.SHEET
89 WEB.VAL.RTN.......
90 CONFIRM.VERSION...
91 PREVIEW.VERSION...
92 BROWSER.TOOLBAR...
93 EXPOSE............
94. 1 SERVICE........
95 ACTIVITY..........
96 FUNCT.............
97 EXPOSE.DESC.......
------------------------------------------------------------------------------
16 NOV 2011 20:10:24 USER (09 AUG) VLADIMIR.K [6567,I PAGE 41 >>42>>>
ACTION

note: Value might not be seen immediately, use F2..F3 to refresh.

Go back to command line ( F4 ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
83 COMPANY.ACCESS....
84 BUSINESS.DAY......
85 AUTO.COMP.CHANGE..
86 SYS.MSG.SUPPRESS..
87. 1 ATTRIBUTES..... SHOW.NULL.FIELDS
87. 2 ATTRIBUTES..... NO.HEADER.TAB
88 D.SLIP.STYLE.SHEET
89 WEB.VAL.RTN.......

REM Page 280


90 CONFIRM.VERSION...
91 PREVIEW.VERSION...
92 BROWSER.TOOLBAR...
93 EXPOSE............
94. 1 SERVICE........
95 ACTIVITY..........
96 FUNCT.............
97 EXPOSE.DESC.......
------------------------------------------------------------------------------
16 NOV 2011 20:10:24 USER (09 AUG) VLADIMIR.K [6567,I PAGE 41 >>42>>>
ACTION
AWAITING PAGE INSTRUCTIONS

See help for @id – an old one but sometimes useful ( ? ←- ):

Model Bank VERSION INPUT

ID = PGM.NAME.VERSION
------------------------------------------------------------------------------
Enables the specific Version of an application to be
uniquely identified.

The name, or an Abbreviation, for the Application of


which a Version is required must be entered followed by a comma. In
cases where more than one Version exists, each Version must be
specified by appending further unique identity.

Example:

The following is a list of possible ID's for the creation of various


Versions for the CUSTOMER file:

. Customer,1
. Customer,99
. Customer,abc
------------------------------------------------------------------------------
16 NOV 2011 20:16:25 USER (09 AUG) VLADIMIR.K [6567,I PAGE 1 >>>3>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Go to next page ( F3 ):

Model Bank VERSION INPUT

ID = PGM.NAME.VERSION
------------------------------------------------------------------------------

REM Page 281


. Customer,3a
. Customer,Smith etc...
. Cust,Special (where CUST is an abbreviation of
CUSTOMER)

__________________________________________________

(1) 2-30 type SS (uppercase alpha or numeric, first


character alpha) character Application name or
Abbreviation, appended by ',X' (where 'X' = Version
identity).
(Mandatory input)

(2) It must be prefixed by a valid Application name


or abbreviation of a valid application name.
------------------------------------------------------------------------------
16 NOV 2011 20:18:29 USER (09 AUG) VLADIMIR.K [6567,I PAGE 2 >>>3>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Leave help ( F1 ); go to freshly input value ( 87.1 ←- ), delete this value ( - ←- ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
83 COMPANY.ACCESS....
84 BUSINESS.DAY......
85 AUTO.COMP.CHANGE..
86 SYS.MSG.SUPPRESS..
87. 1 ATTRIBUTES..... N O.HEADER.TAB
88 D.SLIP.STYLE.SHEET
89 WEB.VAL.RTN.......
90 CONFIRM.VERSION...
91 PREVIEW.VERSION...
92 BROWSER.TOOLBAR...
93 EXPOSE............
94. 1 SERVICE........
95 ACTIVITY..........
96 FUNCT.............
97 EXPOSE.DESC.......
98 CHALL.RESP........
------------------------------------------------------------------------------
16 NOV 2011 20:21:43 USER (09 AUG) VLADIMIR.K [6567,I PAGE 41 >>42>>>
ACTION

REM Page 282


Go to command line ( F4 ) and see an old help for a field #17 ( ?17 ←- ):

Model Bank VERSION INPUT

FIELD NO 17 = TEXT
------------------------------------------------------------------------------
Indicates the Text that User wants to define for the
field specified in FIELD NO (Field 13). This is a
sub-value field which can be expanded by itself to
allow the Text to be entered in the various languages
defined in Language code field.

If no Text is entered by the User, the Version screen


will be presented without any Text for this specific field. Spaces
which are created by the User in this field will not be ignored.

Optionally the number of the field can also be displayed by the


System in front of the Text itself. If required, it should be defined
before the Text as follows:

1. For Single fields enter in this field N, NN or NNN


according to the size of the field i.e. N if field number
------------------------------------------------------------------------------
16 NOV 2011 20:25:00 USER (09 AUG) VLADIMIR.K [6567,I PAGE 1 >>>4>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Go back to command line ( F1 ) and then to the field #17 that’s not on the screen ( 17.1.1
←- ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
17. 1. 1 TEXT........ # Debit Account
18. 1. 1 TXT.040..078
19. 1. 1 TXT.079..117
20. 1. 1 TXT.118..132
21. 1 ENRICHM.CHAR... 25
22. 1 TABLE.COLUMN... 170
23. 1 TABLE.LINE..... 0
24. 1 ENRI.COL.......
25. 1 PROMPT.COL.....
26. 1 RESERVED05.....
27. 1 RESERVED04.....
28. 1 RESERVED03.....
29. 1 RESERVED02.....

REM Page 283


30. 1 RESERVED01.....
31. 1. 1 P
32. 1. 1 TOOL.TIP.... A/c being debited in respect of the transfer
------------------------------------------------------------------------------
16 NOV 2011 20:27:36 USER (09 AUG) VLADIMIR.K [6567,I PAGE 2 >>42>>>
ACTION

note: Just 17 or 17.1 won’t work – field has values and subvalues.

Expand a sub-value ( ( ←- ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
17. 1. 1 TEXT........
18. 1. 1 TXT.040..078
19. 1. 1 TXT.079..117
20. 1. 1 TXT.118..132
17. 1. 2 TEXT........ # Debit Account
18. 1. 2 TXT.040..078
19. 1. 2 TXT.079..117
20. 1. 2 TXT.118..132
21. 1 ENRICHM.CHAR... 25
22. 1 TABLE.COLUMN... 170
23. 1 TABLE.LINE..... 0
24. 1 ENRI.COL.......
25. 1 PROMPT.COL.....
26. 1 RESERVED05.....
27. 1 RESERVED04.....
28. 1 RESERVED03.....
------------------------------------------------------------------------------
16 NOV 2011 21:50:47 USER (09 AUG) VLADIMIR.K [6567,I PAGE 2 >>43>>>
ACTION

note: See that group of fields was added – that’s what is called associated fields.

Remove the added group of fields ( - ←- ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
17. 1. 1 TEXT........ # Debit Account

REM Page 284


18. 1. 1 TXT.040..078
19. 1. 1 TXT.079..117
20. 1. 1 TXT.118..132
21. 1 ENRICHM.CHAR... 25
22. 1 TABLE.COLUMN... 170
23. 1 TABLE.LINE..... 0
24. 1 ENRI.COL.......
25. 1 PROMPT.COL.....
26. 1 RESERVED05.....
27. 1 RESERVED04.....
28. 1 RESERVED03.....
29. 1 RESERVED02.....
30. 1 RESERVED01.....
31. 1. 1 P
32. 1. 1 TOOL.TIP.... A/c being debited in respect of the transfer
------------------------------------------------------------------------------
16 NOV 2011 21:55:24 USER (09 AUG) VLADIMIR.K [6567,I PAGE 2 >>42>>>
ACTION

Enter edit mode ( F7 ), move cursor forward ( F3 F3 F3 ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
17. 1. 1 TEXT........ # D e bit Account |
18. 1. 1 TXT.040..078
19. 1. 1 TXT.079..117
20. 1. 1 TXT.118..132
21. 1 ENRICHM.CHAR... 25
22. 1 TABLE.COLUMN... 170
23. 1 TABLE.LINE..... 0
24. 1 ENRI.COL.......
25. 1 PROMPT.COL.....
26. 1 RESERVED05.....
27. 1 RESERVED04.....
28. 1 RESERVED03.....
29. 1 RESERVED02.....
30. 1 RESERVED01.....
31. 1. 1 P
32. 1. 1 TOOL.TIP.... A/c being debited in respect of the transfer
------------------------------------------------------------------------------
16 NOV 2011 21:55:24 USER (09 AUG) VLADIMIR.K [6567,I PAGE 2 >>42>>>
ACTION

REM Page 285


note: Pipe on the right side means that edit mode is on and also shows field length.

Type something (e.g. EBIIT):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
17. 1. 1 TEXT........ # DEBIIT A ccount |
18. 1. 1 TXT.040..078
19. 1. 1 TXT.079..117
20. 1. 1 TXT.118..132
21. 1 ENRICHM.CHAR... 25
22. 1 TABLE.COLUMN... 170
23. 1 TABLE.LINE..... 0
24. 1 ENRI.COL.......
25. 1 PROMPT.COL.....
26. 1 RESERVED05.....
27. 1 RESERVED04.....
28. 1 RESERVED03.....
29. 1 RESERVED02.....
30. 1 RESERVED01.....
31. 1. 1 P
32. 1. 1 TOOL.TIP.... A/c being debited in respect of the transfer
------------------------------------------------------------------------------
16 NOV 2011 21:55:24 USER (09 AUG) VLADIMIR.K [6567,I PAGE 2 >>42>>>
ACTION

note: If you type a symbol not appropriate for field type – e.g.“{” – it won’t show up.

Correct the typo – go back ( F2 F2 ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
17. 1. 1 TEXT........ # DEBI I TAccount |
18. 1. 1 TXT.040..078
19. 1. 1 TXT.079..117
20. 1. 1 TXT.118..132
21. 1 ENRICHM.CHAR... 25
22. 1 TABLE.COLUMN... 170
23. 1 TABLE.LINE..... 0
24. 1 ENRI.COL.......
25. 1 PROMPT.COL.....
26. 1 RESERVED05.....
27. 1 RESERVED04.....

REM Page 286


28. 1 RESERVED03.....
29. 1 RESERVED02.....
30. 1 RESERVED01.....
31. 1. 1 P
32. 1. 1 TOOL.TIP.... A/c being debited in respect of the transfer
------------------------------------------------------------------------------
16 NOV 2011 22:09:18 USER (09 AUG) VLADIMIR.K [6567,I PAGE 2 >>42>>>
ACTION

Delete redundant character ( F5 ):

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
17. 1. 1 TEXT........ # DEBI T Account |
18. 1. 1 TXT.040..078
19. 1. 1 TXT.079..117
20. 1. 1 TXT.118..132
21. 1 ENRICHM.CHAR... 25
22. 1 TABLE.COLUMN... 170
23. 1 TABLE.LINE..... 0
24. 1 ENRI.COL.......
25. 1 PROMPT.COL.....
26. 1 RESERVED05.....
27. 1 RESERVED04.....
28. 1 RESERVED03.....
29. 1 RESERVED02.....
30. 1 RESERVED01.....
31. 1. 1 P
32. 1. 1 TOOL.TIP.... A/c being debited in respect of the transfer
------------------------------------------------------------------------------
16 NOV 2011 22:09:18 USER (09 AUG) VLADIMIR.K [6567,I PAGE 2 >>42>>>
ACTION

Get the space back – move forward ( F3 ), toggle insert/overwrite ( F6 ), type space:

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
17. 1. 1 TEXT........ # DEBIT A ccount |
18. 1. 1 TXT.040..078
19. 1. 1 TXT.079..117
20. 1. 1 TXT.118..132
21. 1 ENRICHM.CHAR... 25

REM Page 287


22. 1 TABLE.COLUMN... 170
23. 1 TABLE.LINE..... 0
24. 1 ENRI.COL.......
25. 1 PROMPT.COL.....
26. 1 RESERVED05.....
27. 1 RESERVED04.....
28. 1 RESERVED03.....
29. 1 RESERVED02.....
30. 1 RESERVED01.....
31. 1. 1 P
32. 1. 1 TOOL.TIP.... A/c being debited in respect of the transfer
------------------------------------------------------------------------------
16 NOV 2011 22:09:18 USER (09 AUG) VLADIMIR.K [6567,I PAGE 2 >>42>>>
ACTION

Finish editing ( F7 ); you are now at the next field:

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
17. 1. 1 TEXT........ # DEBIT Account
18. 1. 1 TXT.040..078
19. 1. 1 TXT.079..117
20. 1. 1 TXT.118..132
21. 1 ENRICHM.CHAR... 25
22. 1 TABLE.COLUMN... 170
23. 1 TABLE.LINE..... 0
24. 1 ENRI.COL.......
25. 1 PROMPT.COL.....
26. 1 RESERVED05.....
27. 1 RESERVED04.....
28. 1 RESERVED03.....
29. 1 RESERVED02.....
30. 1 RESERVED01.....
31. 1. 1 P
32. 1. 1 TOOL.TIP.... A/c being debited in respect of the transfer
------------------------------------------------------------------------------
16 NOV 2011 22:09:18 USER (09 AUG) VLADIMIR.K [6567,I PAGE 2 >>42>>>
ACTION

Copy contents of one field to another – type source field number ( 32.1.1 )...

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------

REM Page 288


17. 1. 1 TEXT........ # DEBIT Account
18. 1. 1 TXT.040..078 32.1.1
19. 1. 1 TXT.079..117
20. 1. 1 TXT.118..132
21. 1 ENRICHM.CHAR... 25
22. 1 TABLE.COLUMN... 170
23. 1 TABLE.LINE..... 0
24. 1 ENRI.COL.......
25. 1 PROMPT.COL.....
26. 1 RESERVED05.....
27. 1 RESERVED04.....
28. 1 RESERVED03.....
29. 1 RESERVED02.....
30. 1 RESERVED01.....
31. 1. 1 P
32. 1. 1 TOOL.TIP.... A/c being debited in respect of the transfer
------------------------------------------------------------------------------
16 NOV 2011 22:31:43 USER (09 AUG) VLADIMIR.K [6567,I PAGE 2 >>42>>>
ACTION

...and press F7 :

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
17. 1. 1 TEXT........ # DEBIT Account
18. 1. 1 TXT.040..078 A /c being debited in respect of the tra|
19. 1. 1 TXT.079..117
20. 1. 1 TXT.118..132
21. 1 ENRICHM.CHAR... 25
22. 1 TABLE.COLUMN... 170
23. 1 TABLE.LINE..... 0
24. 1 ENRI.COL.......
25. 1 PROMPT.COL.....
26. 1 RESERVED05.....
27. 1 RESERVED04.....
28. 1 RESERVED03.....
29. 1 RESERVED02.....
30. 1 RESERVED01.....
31. 1. 1 P
32. 1. 1 TOOL.TIP.... A/c being debited in respect of the transfer
------------------------------------------------------------------------------
16 NOV 2011 22:31:43 USER (09 AUG) VLADIMIR.K [6567,I PAGE 2 >>42>>>
ACTION

note: Field is too short to hold the new content; pipe indicates truncation point.

REM Page 289


Cancel the edit mode ( F1 ) ; use F3 to refresh:

Model Bank VERSION INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
17. 1. 1 TEXT........ # DEBIT Account
18. 1. 1 TXT.040..078
19. 1. 1 TXT.079..117
20. 1. 1 TXT.118..132
21. 1 ENRICHM.CHAR... 25
22. 1 TABLE.COLUMN... 170
23. 1 TABLE.LINE..... 0
24. 1 ENRI.COL.......
25. 1 PROMPT.COL.....
26. 1 RESERVED05.....
27. 1 RESERVED04.....
28. 1 RESERVED03.....
29. 1 RESERVED02.....
30. 1 RESERVED01.....
31. 1. 1 P
32. 1. 1 TOOL.TIP.... A/c being debited in respect of the transfer
------------------------------------------------------------------------------
16 NOV 2011 22:31:43 USER (09 AUG) VLADIMIR.K [6567,I PAGE 2 >>42>>>
ACTION

Commit changes ( F5 ):

Model Bank VERSION, INPUT

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------

REM Page 290


------------------------------------------------------------------------------
16 NOV 2011 22:32:18 USER (09 AUG) VLADIMIR.K [6567,I TXN COMPLETE
ACTION
AWAITING ID

Go to the first level ( F1 ):

Model Bank SELECT APPLICATION

------------------------------------------------------------------------------

------------------------------------------------------------------------------
16 NOV 2011 23:11:24 USER (09 AUG) VLADIMIR.K [6567,IN]
ACTION
AWAITING APPLICATION

Go into changed record in “See” mode ( VERSION S FT,AC ←- ):

Model Bank VERSION SEE

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
2 RECORDS.PER.PAGE.. 1
3 FIELDS.PER.LINE... MULTI
4. 1 LANGUAGE.CODE.. 1 English
5. 1 HDR.1.001..039. Transfer Between Accounts
13. 1 FIELD.NO....... DEBIT.ACCT.NO DEBIT.ACCT.NO
14. 1 COLUMN......... 1
16. 1 TEXT.CHAR.MAX.. 25

REM Page 291


17. 1. 1 TEXT........ # DEBIT Account
# Debit Account
21. 1 ENRICHM.CHAR... 25
22. 1 TABLE.COLUMN... 170
23. 1 TABLE.LINE..... 0
32. 1. 1 TOOL.TIP.... A/c being debited in respect of the transfer
13. 2 FIELD.NO....... DEBIT.CURRENCY DEBIT.CURRENCY
14. 2 COLUMN......... 1
16. 2 TEXT.CHAR.MAX.. 25
------------------------------------------------------------------------------
16 NOV 2011 23:15:52 USER (09 AUG) VLADIMIR.K [6567,I PAGE 1 >>12>>>
ACTION
AWAITING PAGE INSTRUCTIONS

note: Record isn’t authorised so changes are shown in the field 17.1.1.

Go to bottom to see audit trail ( F4 ):

Model Bank VERSION SEE

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
65 REPORT.LOCKS...... YES
67. 1 GB D Transfer Between Accounts
68. 1 ASSOC.VERSION.. FUNDS.TRANSFER,AUDIT Audit
73 EXC.INC.RTN....... YES
87. 1 ATTRIBUTES..... NO.HEADER.TAB
102 RECORD.STATUS..... INAU INPUT Unauthorised
103 CURR.NO........... 3
104. 1 INPUTTER....... 6567_VLADIMIR.K_I_INAU
105. 1 DATE.TIME...... 16 NOV 11 22:32
107 CO.CODE........... GB-001-0001
108 DEPT.CODE......... 1

------------------------------------------------------------------------------
16 NOV 2011 23:31:36 USER (09 AUG) VLADIMIR.K [6567,I PAGE 12
ACTION
AWAITING PAGE INSTRUCTIONS

Go two levels up ( F1 F1 ):

Model Bank SELECT APPLICATION

REM Page 292


------------------------------------------------------------------------------

------------------------------------------------------------------------------
16 NOV 2011 23:35:15 USER (09 AUG) VLADIMIR.K [6567,IN]
ACTION
AWAITING APPLICATION

Enter the edit mode for the previous command line ( F7 ):

Model Bank SELECT APPLICATION

------------------------------------------------------------------------------

------------------------------------------------------------------------------
16 NOV 2011 23:35:15 USER (09 AUG) VLADIMIR.K [6567,IN]

REM Page 293


ACTION V ERSION S FT,AC |
AWAITING APPLICATION

Move pointer to function and replace it to “D” ( F3 F3 F3 F3 F3 F3 F3 F3 D ):

Model Bank SELECT APPLICATION

------------------------------------------------------------------------------

------------------------------------------------------------------------------
16 NOV 2011 23:35:15 USER (09 AUG) VLADIMIR.K [6567,IN]
ACTION VERSION D FT,AC |
AWAITING APPLICATION

Finish editing mode and execute the command ( F7 ):

Model Bank VERSION DELETE

PGM.NAME.VERSION.. FUNDS.TRANSFER,AC
------------------------------------------------------------------------------
2 RECORDS.PER.PAGE.. 1
3 FIELDS.PER.LINE... MULTI
4. 1 LANGUAGE.CODE.. 1 English
5. 1 HDR.1.001..039. Transfer Between Accounts
13. 1 FIELD.NO....... DEBIT.ACCT.NO DEBIT.ACCT.NO
14. 1 COLUMN......... 1
16. 1 TEXT.CHAR.MAX.. 25
17. 1. 1 TEXT........ # DEBIT Account
# Debit Account
21. 1 ENRICHM.CHAR... 25

REM Page 294


22. 1 TABLE.COLUMN... 170
23. 1 TABLE.LINE..... 0
32. 1. 1 TOOL.TIP.... A/c being debited in respect of the transfer
13. 2 FIELD.NO....... DEBIT.CURRENCY DEBIT.CURRENCY
14. 2 COLUMN......... 1
16. 2 TEXT.CHAR.MAX.. 25
------------------------------------------------------------------------------
16 NOV 2011 23:42:20 USER (09 AUG) VLADIMIR.K [6567,I PAGE 1 >>12>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Commit deleting of unauthorised record ( F5 ) and exit T24 ( @BK ←- ):

------------------------------------------------------------------------------
16 NOV 2011 23:44:17 USER (09 AUG) VLADIMIR.K [6567,IN]
ACTION

jsh t24 -->

note: “@” is used to navigate to the upmost level before issuing the command.

17.7 Navigation lesson #2


Log in. List ENQUIRY application using “comma VERSION” ( ENQUIRY, L ←- ):

Model Bank

Enquiry Description File


------------------------------------------------------------------------------
1 %25BALANCE.REQBL.REQ Default List BALANCE.REQUIREMENT
2 %AA.PRODUCT.DE AA.PRODUCT.DESIGNER
3 %AA.PRODUCT.GR AA.PRODUCT.GROUP
4 %AA.PRODUCT.LI AA.PRODUCT.LINE
5 %ABBREVIATION ABBREVIATION
6 %AC.ACCOUNT.SWSweep For an Account His| AC.ACCOUNT.SWEEP.HIST
7 %AC.VIOLATION Account Violation Defaul| AC.VIOLATION
8 %AC.VIOLATION.Account Violation Histor| AC.VIOLATION.HIST
9 %ACCOUNT ACCOUNT Default List ACCOUNT
10 %ACCOUNT.DEBITAccount Debit Interest -| ACCOUNT.DEBIT.INT
11 %ACCOUNT$NAU Unauthorised Accounts ACCOUNT$NAU
12 %ACCT.GEN.CONDAcct Gen Condition - List ACCT.GEN.CONDITION
13 %ACCT.STATEMENAccount Statement Charge| ACCT.STATEMENT.CHARGE
14 %ACTIVITY ACTIVITY
15 %AGENCY AGENCY
16 %AM.CALC.METHO AM.CALC.METHOD

REM Page 295


------------------------------------------------------------------------------
17 NOV 2011 18:33:49 USER (09 AUG) VLADIMIR.K [8141,INPAGE 1 >>>3>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Go to page #200 – that’s the limit set in SPF ( P200 ←- ; might also need F3 to draw
the screen):

Model Bank

Enquiry Description File


------------------------------------------------------------------------------
1 SC.VAL.COST SC.POS.ASSET
2 SC.VAL.EQ.COUN SC.VAL.SUM12
3 SC.VAL.EQ.INDU SC.VAL.SUM12
4 SC.VAL.EXERCIS SC.POS.ASSET.EXERCISE.WORK
5 SC.VAL.FIXED.S SC.VAL.SUM12
6 SC.VAL.LIQUIDI SC.VAL.SUM12
7 SC.VAL.MARGIN SC.POS.ASSET
8 SC.VAL.MARKET SC.POS.ASSET
9 SC.VAL.MATRIX SC.VAL.SUM12
10 SC.VAL.PL SC.POS.ASSET
11 SC.VAL.REPO SC.POS.ASSET
12 SC.VAL.REPORT SC.CASH.FLOW12
13 SC.VARIATION.PPortfolio Performance De| SC.PERF.DETAIL
14 SC.VARIATION.P SC.PERF.DETAIL
15 SC.VAULT VAULT.CONTROL
16 SC.VAULT.DAILY HOLD.CONTROL
------------------------------------------------------------------------------
17 NOV 2011 18:33:49 USER (09 AUG) VLADIMIR.K [8141,INPAGE 200 >200>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Press F3 :

------------------------------------------------------------------------------
17 NOV 2011 18:33:49 USER (09 AUG) VLADIMIR.K [8141,INPAGE 200 >200>>>
ACTION THIS IS THE LAST PAGE
AWAITING PAGE INSTRUCTIONS

Use a trick to see beyond that ( F1 , then L -SC.VAULT ←- ):

Model Bank ENQUIRY, LIST

NO. ID RECORD FIELDS FUNCT.


------------------------------------------------------------------------------

REM Page 296


1 SC.VAULT 4,19 VAULT.CONTROL SECURITY.NO NE "" PORTFOLIO.NO P|
2 SC.VAULT.DAILY.MOVE 4,19 HOLD.CONTROL REPORT.NAME EQ VAULT.DAI|
3 SC.VAULT.HIST 4,99 VAULT.CONTROL$HIS PORTFOLIO.NO PORTFOLIO.N|
4 SC.VAULT.LIST 4,99 VAULT.CONTROL PORTFOLIO.NO PORTFOLIO.NO P|
5 SC.VDATE.POS 6,97 SECURITY.TRANS SECURITY.ACCOUNT UL ...-999 |
6 SC.VDATE.POS.DIARY 4,99 SECURITY.TRANS SECURITY.ACCOUNT UL ...|
7 SC.VDATE.POS1 6,17 SECURITY.TRANS SECURITY.ACCOUNT LK ...-999 |
8 SC.VOSTRO 4,19 ACCOUNT CATEGORY EQ 2001 CURRENCY @ID Accoun|
9 SCC.INCOMING.DETAILS 4,19 FT.SCC.TAPE.DATA TAPE.NAME ACCOUNT.|
10 SCRIPT.DETAIL 4,19 SEAT.RESULTS @ID @ID @ID 1 45L S 9 1|
11 SCRIPT.LIST 4,19 SCRIPT.DESIGNER DESCRIPTION DESCRIPTION 1 |
12 SCRIPT.SUMMARY 4,19 SEAT.RESULTS SEAT.ID NE '' SEAT - SCRIPT |
13 SCV.ACCOUNT.LIST 4,99 ACCOUNT CUSTOMER Customer E.MB.CUST.AC|
14 SCV.ACCT.ENT.FWD.T1 4,99 ACCT.ENT.FWD @ID STMT.ENTRY Custome|
15 SCV.ACCT.STMT.HIST 6,99 ACCT.STMT.PRINT STMT.ACCOUNT.NO @ID |
16 SCV.ARC.SUM.LD 8,19 LD.LOANS.AND.DEPOSITS @ID Primary Key EQ|
------------------------------------------------------------------------------
17 NOV 2011 18:39:35 USER (09 AUG) VLADIMIR.K [8141,INPAGE 1
ACTION
AWAITING PAGE INSTRUCTIONS

Press F3 until you are at the last page:

Model Bank ENQUIRY, LIST

NO. ID RECORD FIELDS FUNCT.


------------------------------------------------------------------------------
769 WR.REPORTS 4,19 WR.IMAGE.MANAGEMENT IM.DOCUMENT.UPLOAD NE "" |
770 WR.REQ.REPORT.SAM 4,99 SEC.ACC.MASTER WR.REPORTING EQ 'Y' @ID|
771 WR.ROLLING.PERFORMANCE 4,19 WR.ENQUIRY.WORKFILE SAM.NO EQ WR|
772 WR.SECURITY.TRANSACTION.DETAILS 4,19 SECURITY.TRANS SECURITY.A|
773 WR.VALUATION.DETAILS 4,19 AM.VAL.EXTRACT.WRK SAM.NO E.AM.BUIL|
774 WR.VALUATION.TOTALS 4,99 WR.ENQUIRY.WORKFILE SAM.NO Portfolio|
775 YIELD.ENQUIRY 7,19 SECURITY.SUPP SECURITY.CODE @(1,1)Yield En|

------------------------------------------------------------------------------
17 NOV 2011 18:40:55 USER (09 AUG) VLADIMIR.K [8141,INPAGE 49
ACTION
AWAITING PAGE INSTRUCTIONS

REM Page 297


Go one level up and proceed with a search ( F1 , then L L ←- ):

Model Bank ENQUIRY, LIST

NO. ID RECORD FIELDS FUNCT.


------------------------------------------------------------------------------
SELECTION FIELDS - LIVE FILE [EQ NE LT GT LE GE RG NR LK UL]
-------------------------------------------------------------------------------
0.. @ID 0A. ENQUIRY 1.. PAGE.SIZE
2.. FILE.NAME 3.. FIXED.SELECTION 4.. FIXED.SORT
5.. OPEN.BRACKET 6.. SELECTION.FLDS 7.. SEL.LABEL
8.. SEL.FLD.OPER 9.. REQUIRED.SEL 10. CLOSE.BRACKET
11. REL.NEXT.FIELD 12. BUILD.ROUTINE 13. K.HEADER
13A HEADER 14. FIELD.NAME 15. OPERATION
16. K.COLUMN 16A COLUMN 17. LENGTH.MASK
18. K.CONVERSION 18A CONVERSION 19. COMMENTS
20. K.TYPE 20A TYPE 21. DISPLAY.BREAK
22. FIELD.LBL 23. FIELD.DISP.TYPE 24. SECTION
25. ATTRIBS 26. TARGET.FIELD 27. COL.WIDTH
28. RESERVED7 29. RESERVED6 30. RESERVED5
31. RESERVED4 32. RESERVED3 33. RESERVED2
34. RESERVED1 35. SINGLE.MULTI 36. ENQUIRY.NAME
------------------------------------------------------------------------------
17 NOV 2011 18:47:37 USER (09 AUG) VLADIMIR.K [8141,I PPAGE 1 >>3>>>
ACTION
ENTER SELECTION (eg CUST EQ 123456) , <F5> TO EXECUTE LIST

note: E E searches the unauthorised file, L ; L – history.


Enter selection (2 EQ USER ←- ):

Model Bank ENQUIRY, LIST

------------------------------------------------------------------------------
SELECTION FIELDS - LIVE FILE [EQ NE LT GT LE GE RG NR LK UL]
-------------------------------------------------------------------------------
0.. @ID 0A. ENQUIRY 1.. PAGE.SIZE
2.. FILE.NAME 3.. FIXED.SELECTION 4.. FIXED.SORT
5.. OPEN.BRACKET 6.. SELECTION.FLDS 7.. SEL.LABEL
8.. SEL.FLD.OPER 9.. REQUIRED.SEL 10. CLOSE.BRACKET
11. REL.NEXT.FIELD 12. BUILD.ROUTINE 13. K.HEADER
13A HEADER 14. FIELD.NAME 15. OPERATION
16. K.COLUMN 16A COLUMN 17. LENGTH.MASK
18. K.CONVERSION 18A CONVERSION 19. COMMENTS
20. K.TYPE 20A TYPE 21. DISPLAY.BREAK
22. FIELD.LBL 23. FIELD.DISP.TYPE 24. SECTION

REM Page 298


25. ATTRIBS 26. TARGET.FIELD 27. COL.WIDTH
28. RESERVED7 29. RESERVED6 30. RESERVED5
------------------------------------------------------------------------------
FILE.NAME EQ USER
------------------------------------------------------------------------------
17 NOV 2011 18:50:49 USER (09 AUG) VLADIMIR.K [8141,IN]PAGE 1 >>3>>>
ACTION
ENTER SELECTION (eg CUST EQ 123456) , <F5> TO EXECUTE LIST

Press F5 to proceed:

Model Bank

Enquiry Description File


------------------------------------------------------------------------------
1 %USER USER
2 BROWSER.TIMEOU USER
3 TEC.MONITOR.US USER
4 USER USER
5 USER.STATUS USER

------------------------------------------------------------------------------
17 NOV 2011 18:51:53 USER (09 AUG) VLADIMIR.K [8141,INPAGE 1 >>>1>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Select record #4 for “see” mode ( 4 ←- S F5 ):

Model Bank ENQUIRY, SEE

ENQUIRY........... USER
------------------------------------------------------------------------------
1 PAGE.SIZE ........ 4,19
2 FILE.NAME......... USER
6. 1 SELECTION.FLDS. APPLICATION
7. 1. 1 GB SEL.LABEL User Group

REM Page 299


6. 2 SELECTION.FLDS. USER.NAME
7. 2. 1 GB SEL.LABEL User Name
6. 3 SELECTION.FLDS. START.DATE.PROFILE
7. 3. 1 GB SEL.LABEL Start Date
6. 4 SELECTION.FLDS. END.DATE.PROFILE
7. 4. 1 GB SEL.LABEL End Date
6. 5 SELECTION.FLDS. DEPARTMENT.CODE
7. 5. 1 GB SEL.LABEL Department Code
14. 1 FIELD.NAME..... HDR.1
15. 1. 1 OPERATION... "List of T24 Users"
16. 1 COLUMN......... 1,1
23. 1 FIELD.DISP.TYPE CLASS-ENQ.H.TITLE
------------------------------------------------------------------------------
17 NOV 2011 18:54:02 USER (09 AUG) VLADIMIR.K [8141,INPAGE 1 >>>6>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Copy this record ( F1 C ←- ):

Model Bank ENQUIRY, COPY

ENQUIRY........... USER
------------------------------------------------------------------------------

------------------------------------------------------------------------------
17 NOV 2011 18:55:35 USER (09 AUG) VLADIMIR.K [8141,I
ACTION
AWAITING ID

Enter new @id ( e.g. USER2 ←- ):

Model Bank ENQUIRY, COPY

REM Page 300


ENQUIRY........... USER2
------------------------------------------------------------------------------
1 PAGE.SIZE ........ 4,19
2 FILE.NAME......... USER
3. 1 FIXED.SELECTION
4. 1 FIXED.SORT.....
5. 1 OPEN.BRACKET...
6. 1 SELECTION.FLDS. APPLICATION
7. 1. 1 GB SEL.LABEL User Group
8. 1 SEL.FLD.OPER...
9. 1 REQUIRED.SEL...
10. 1 CLOSE.BRACKET..
11. 1 REL.NEXT.FIELD.
5. 2 OPEN.BRACKET...
6. 2 SELECTION.FLDS. USER.NAME
7. 2. 1 GB SEL.LABEL User Name
8. 2 SEL.FLD.OPER...
9. 2 REQUIRED.SEL...
------------------------------------------------------------------------------
17 NOV 2011 18:57:12 USER (09 AUG) VLADIMIR.K [8141,I PAGE 1 >>20>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Put record to HOLD ( HLD ←- ):

Model Bank ENQUIRY, COPY

ENQUIRY........... USER2
------------------------------------------------------------------------------

------------------------------------------------------------------------------
17 NOV 2011 18:57:12 USER (09 AUG) VLADIMIR.K [8141,I TXN COMPLETE

REM Page 301


ACTION
AWAITING ID

See unauthorised records ( E ←- ); also you can use search of unauthorised records (E E –
just like L L example several pages above):

Model Bank ENQUIRY - Default Exceptions

ID STATUS FUNCT.
------------------------------------------------------------------------------
1 USER2 CHLD

------------------------------------------------------------------------------
17 NOV 2011 18:59:21 USER (09 AUG) VLADIMIR.K [8141,INPAGE 1 >>>1>>>
ACTION
AWAITING PAGE INSTRUCTIONS

note: STATUS is CHLD rather than IHLD; avoid using ’IHLD’ to check record status!

Edit this record ( 1 ←- I F5 ):

Model Bank ENQUIRY, INPUT

------------------------------------------------------------------------------

REM Page 302


------------------------------------------------------------------------------
17 NOV 2011 19:01:46 USER (09 AUG) VLADIMIR.K [8141,IN]
ACTION
OVERRIDE (Y/NO) RECORD IN HOLD-STATUS

Confirm your intention ( Y ←- ):

Model Bank ENQUIRY, INPUT

ENQUIRY........... USER2
------------------------------------------------------------------------------
1 PAGE.SIZE ........ 4,19
2 FILE.NAME......... USER
3. 1 FIXED.SELECTION
4. 1 FIXED.SORT.....
5. 1 OPEN.BRACKET...
6. 1 SELECTION.FLDS. APPLICATION
7. 1. 1 GB SEL.LABEL User Group
8. 1 SEL.FLD.OPER...
9. 1 REQUIRED.SEL...
10. 1 CLOSE.BRACKET..
11. 1 REL.NEXT.FIELD.
5. 2 OPEN.BRACKET...
6. 2 SELECTION.FLDS. USER.NAME
7. 2. 1 GB SEL.LABEL User Name
8. 2 SEL.FLD.OPER...
9. 2 REQUIRED.SEL...
------------------------------------------------------------------------------
17 NOV 2011 19:04:27 USER (09 AUG) VLADIMIR.K [8141,INPAGE 1 >>20>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Go to field #57 ( 57 ←- ):

Model Bank ENQUIRY, INPUT

ENQUIRY........... USER2

REM Page 303


------------------------------------------------------------------------------
43 BREAK.FIELDS...... 0
44 PROCESS.BREAKS.... 0
45 TOTAL.FIELDS...... 0
46 NEXT.LVL.FLDS..... 1 2
47 LINES.OSIDE.PAGE..
48 SMS.APPLICATION...
49 SMS.ID............
50 SMS.ABORT.........
51 USE.FIELD.NUMBERS.
52 CUSTOMER.NO.FLD...
53 ACCOUNT.NO.FLD....
54. 1 SPOOL.BRK.FLD..
55. 1. 1 GB DESCRIPT.
56. 1 ATTRIBUTES..... NO.SELECTION
57 PRODUCT........... E B System Core
58. 1 GB SHORT.DESC.. List of System Users
------------------------------------------------------------------------------
17 NOV 2011 19:09:30 USER (09 AUG) VLADIMIR.K [8141,INPAGE 18 >>20>>>
ACTION

Choose other value from a CHECKFILE ( ! ←- ):

Model Bank ENQUIRY, INPUT

ENQUIRY........... USER2
------------------------------------------------------------------------------
Model Bank PRODUCT CONTROL FILE

------------------------------------------------------------------------------

------------------------------------------------------------------------------
17 NOV 2011 19:11:40 USER (09 AUG) VLADIMIR.K [8141,I
ACTION

REM Page 304


AWAITING FUNCTION

Use usual navigation ( L ←- ):

Model Bank ENQUIRY, INPUT

ENQUIRY........... USER2
------------------------------------------------------------------------------
Model Bank EB.PRODUCT - Default List

ID DESCRIPTION RESERVED9 RESERVED8 FUNCT.


------------------------------------------------------------------------------
1 AA Arrangment Architecture
2 AB ARRANGEMENT BUNDLE
3 AC Accounts
4 AD Arrangement Deposits
5 AI ARC Internet Banking
6 ALL All products
7 AM Wealth Management
8 AP ARC Proxy Services
9 AR AA Retail accounts.
10 AS Arrangement Savings Plan
11 AZ All in One Accounts
12 BA Branch Automation
------------------------------------------------------------------------------
17 NOV 2011 19:13:57 USER (09 AUG) VLADIMIR.K [8141,I PAGE 1 >>>3>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Choose a record, copy its @id to the target field ( 3 ←- C F5 ):

Model Bank ENQUIRY, INPUT

------------------------------------------------------------------------------
43 BREAK.FIELDS...... 0
44 PROCESS.BREAKS.... 0
45 TOTAL.FIELDS...... 0
46 NEXT.LVL.FLDS..... 1 2
47 LINES.OSIDE.PAGE..
48 SMS.APPLICATION...
49 SMS.ID............
50 SMS.ABORT.........
51 USE.FIELD.NUMBERS.
52 CUSTOMER.NO.FLD...
53 ACCOUNT.NO.FLD....

REM Page 305


54. 1 SPOOL.BRK.FLD..
55. 1. 1 GB DESCRIPT.
56. 1 ATTRIBUTES..... NO.SELECTION
57 PRODUCT........... AC Accounts
58. 1 GB SHORT.DESC.. L ist of System Users
------------------------------------------------------------------------------
17 NOV 2011 19:16:14 USER (09 AUG) VLADIMIR.K [8141,I PAGE 18 >>20>>>
ACTION

Commit changes ( F5 ), then edit the record again – change field #57 back to “EB”,
commit changes, then edit again – change field #57 to “ST”, commit it, go to “AWAITING
APPLICATION” level, then search the history ( ENQUIRY L ; L ←- ):

Model Bank ENQUIRY LIST

------------------------------------------------------------------------------
SELECTION FIELDS - HISTORY FILE [EQ NE LT GT LE GE RG NR LK UL]
-------------------------------------------------------------------------------
0.. @ID 0A. ENQUIRY 1.. PAGE.SIZE
2.. FILE.NAME 3.. FIXED.SELECTION 4.. FIXED.SORT
5.. OPEN.BRACKET 6.. SELECTION.FLDS 7.. SEL.LABEL
8.. SEL.FLD.OPER 9.. REQUIRED.SEL 10. CLOSE.BRACKET
11. REL.NEXT.FIELD 12. BUILD.ROUTINE 13. K.HEADER
13A HEADER 14. FIELD.NAME 15. OPERATION
16. K.COLUMN 16A COLUMN 17. LENGTH.MASK
18. K.CONVERSION 18A CONVERSION 19. COMMENTS
20. K.TYPE 20A TYPE 21. DISPLAY.BREAK
22. FIELD.LBL 23. FIELD.DISP.TYPE 24. SECTION
25. ATTRIBS 26. TARGET.FIELD 27. COL.WIDTH
28. RESERVED7 29. RESERVED6 30. RESERVED5
31. RESERVED4 32. RESERVED3 33. RESERVED2
34. RESERVED1 35. SINGLE.MULTI 36. ENQUIRY.NAME
------------------------------------------------------------------------------
17 NOV 2011 19:22:12 USER (09 AUG) VLADIMIR.K [8141,IN]PAGE 1 >>3>>>
ACTION EB.RTN.INVALID.SELECTION.FLD.1
ENTER SELECTION (eg CUST EQ 123456) , <F5> TO EXECUTE LIST

Enter selection criteria ( 0 LK USER2... ←- ):

Model Bank ENQUIRY LIST

------------------------------------------------------------------------------
SELECTION FIELDS - HISTORY FILE [EQ NE LT GT LE GE RG NR LK UL]
-------------------------------------------------------------------------------

REM Page 306


0.. @ID 0A. ENQUIRY 1.. PAGE.SIZE
2.. FILE.NAME 3.. FIXED.SELECTION 4.. FIXED.SORT
5.. OPEN.BRACKET 6.. SELECTION.FLDS 7.. SEL.LABEL
8.. SEL.FLD.OPER 9.. REQUIRED.SEL 10. CLOSE.BRACKET
11. REL.NEXT.FIELD 12. BUILD.ROUTINE 13. K.HEADER
13A HEADER 14. FIELD.NAME 15. OPERATION
16. K.COLUMN 16A COLUMN 17. LENGTH.MASK
18. K.CONVERSION 18A CONVERSION 19. COMMENTS
20. K.TYPE 20A TYPE 21. DISPLAY.BREAK
22. FIELD.LBL 23. FIELD.DISP.TYPE 24. SECTION
25. ATTRIBS 26. TARGET.FIELD 27. COL.WIDTH
28. RESERVED7 29. RESERVED6 30. RESERVED5
------------------------------------------------------------------------------
@ID LK USER2...
------------------------------------------------------------------------------
17 NOV 2011 19:22:12 USER (09 AUG) VLADIMIR.K [8141,IN]PAGE 1 >>3>>>
ACTION
ENTER SELECTION (eg CUST EQ 123456) , <F5> TO EXECUTE LIST

And then F5 :

Model Bank

Enquiry Description File


------------------------------------------------------------------------------
1 USER2;2 USER
2 USER2;1 USER

------------------------------------------------------------------------------
17 NOV 2011 19:35:42 USER (09 AUG) VLADIMIR.K [8141,INPAGE 1 >>>1>>>
ACTION
AWAITING PAGE INSTRUCTIONS

REM Page 307


Go back to “AWAITING APPLICATION” level, then open the record in “see” mode ( ENQUIRY
S USER2 ←- ), then go to the end of the record:

Model Bank ENQUIRY SEE

ENQUIRY........... USER2
------------------------------------------------------------------------------
45 TOTAL.FIELDS...... 0
46 NEXT.LVL.FLDS..... 1 2
56. 1 ATTRIBUTES..... NO.SELECTION
57 PRODUCT........... ST System Tables
58. 1 GB SHORT.DESC.. List of System Users
77 CURR.NO........... 3
78. 1 INPUTTER....... 8141_VLADIMIR.K_I_INAU
79. 1 DATE.TIME...... 17 NOV 11 19:33
79. 2 DATE.TIME...... 17 NOV 11 19:33
80 AUTHORISER........ 8141_VLADIMIR.K
81 CO.CODE........... GB-001-0001
82 DEPT.CODE......... 1

------------------------------------------------------------------------------
17 NOV 2011 19:44:33 USER (09 AUG) VLADIMIR.K [8141,INPAGE 6
ACTION
AWAITING PAGE INSTRUCTIONS

note: CURR.NO is 3, records #1 and #2 are history ones.

See changes in the record – firstly between records #2 and #3 ( F1 ; ←- F4 ):

Model Bank ENQUIRY SEE

ENQUIRY........... USER2 ;
------------------------------------------------------------------------------
45 TOTAL.FIELDS...... 0
46 NEXT.LVL.FLDS..... 1 2
56. 1 ATTRIBUTES..... NO.SELECTION
57 PRODUCT........... ST System Tables
EB System Core
58. 1 GB SHORT.DESC.. List of System Users
77 CURR.NO........... 3
78. 1 INPUTTER....... 8141_VLADIMIR.K_I_INAU
79. 1 DATE.TIME...... 17 NOV 11 19:33
79. 2 DATE.TIME...... 17 NOV 11 19:33

REM Page 308


80 AUTHORISER........ 8141_VLADIMIR.K
81 CO.CODE........... GB-001-0001
82 DEPT.CODE......... 1

------------------------------------------------------------------------------
17 NOV 2011 19:47:13 USER (09 AUG) VLADIMIR.K [8141,INPAGE 6
ACTION
AWAITING PAGE INSTRUCTIONS

And then compare the records #1 and #2 ( F1 ;2 ←- F4 ):

Model Bank ENQUIRY SEE

ENQUIRY........... USER2 ; 2
------------------------------------------------------------------------------
45 TOTAL.FIELDS...... 0
46 NEXT.LVL.FLDS..... 1 2
56. 1 ATTRIBUTES..... NO.SELECTION
57 PRODUCT........... EB System Core
AC Accounts
58. 1 GB SHORT.DESC.. List of System Users
77 CURR.NO........... 2
78. 1 INPUTTER....... 8141_VLADIMIR.K_I_INAU
79. 1 DATE.TIME...... 17 NOV 11 19:22
79. 2 DATE.TIME...... 17 NOV 11 19:22
80 AUTHORISER........ 8141_VLADIMIR.K
81 CO.CODE........... GB-001-0001
82 DEPT.CODE......... 1

------------------------------------------------------------------------------
17 NOV 2011 19:51:04 USER (09 AUG) VLADIMIR.K [8141,INPAGE 6
ACTION
AWAITING PAGE INSTRUCTIONS

Go back to “AWAITING APPLICATION” level; reverse the record ( ENQUIRY R USER2 ←- ),


then press F5 :

Model Bank ENQUIRY REVERSE

ENQUIRY........... USER2
------------------------------------------------------------------------------

REM Page 309


------------------------------------------------------------------------------
17 NOV 2011 19:56:23 USER (09 AUG) VLADIMIR.K [8141,INTXN COMPLETE
ACTION
AWAITING ID

See “exceptions” ( E ←- ):

Model Bank ENQUIRY - Default Exceptions

ID STATUS FUNCT.
------------------------------------------------------------------------------
1 USER2 RNAU

------------------------------------------------------------------------------
17 NOV 2011 19:58:50 USER (09 AUG) VLADIMIR.K [8141,INPAGE 1 >>>1>>>
ACTION
AWAITING PAGE INSTRUCTIONS

REM Page 310


note: STATUS is RNAU – we used “pure” application.

Login as another user, authorise the reverse ( ENQUIRY A USER2 ←- , then F5 ):

Model Bank ENQUIRY AUTHORISE

ENQUIRY........... USER2
------------------------------------------------------------------------------

------------------------------------------------------------------------------
17 NOV 2011 20:02:45 USER (09 AUG) VLADIMIR.K1 [3625,INTXN COMPLETE
ACTION
AWAITING ID

See the record ( S USER2 ←- ):

Model Bank ENQUIRY SEE

ENQUIRY........... USER2 ; 4
------------------------------------------------------------------------------
1 PAGE.SIZE ........ 4,19
2 FILE.NAME......... USER
6. 1 SELECTION.FLDS. APPLICATION
7. 1. 1 GB SEL.LABEL User Group
6. 2 SELECTION.FLDS. USER.NAME
7. 2. 1 GB SEL.LABEL User Name
6. 3 SELECTION.FLDS. START.DATE.PROFILE
7. 3. 1 GB SEL.LABEL Start Date
6. 4 SELECTION.FLDS. END.DATE.PROFILE
7. 4. 1 GB SEL.LABEL End Date
6. 5 SELECTION.FLDS. DEPARTMENT.CODE
7. 5. 1 GB SEL.LABEL Department Code

REM Page 311


14. 1 FIELD.NAME..... HDR.1
15. 1. 1 OPERATION... "List of T24 Users"
16. 1 COLUMN......... 1,1
23. 1 FIELD.DISP.TYPE CLASS-ENQ.H.TITLE
------------------------------------------------------------------------------
17 NOV 2011 20:04:00 USER (09 AUG) VLADIMIR.K1 [3625,I PAGE 1 >>>6>>>
ACTION
AWAITING PAGE INSTRUCTIONS

note: @id is shown with a semicolon – only history records present.

Go to the end:

Model Bank ENQUIRY SEE

ENQUIRY........... USER2 ; 4
------------------------------------------------------------------------------
45 TOTAL.FIELDS...... 0
46 NEXT.LVL.FLDS..... 1 2
56. 1 ATTRIBUTES..... NO.SELECTION
57 PRODUCT........... ST System Tables
58. 1 GB SHORT.DESC.. List of System Users
76 RECORD.STATUS..... REVE REVERSE Reversed
77 CURR.NO........... 4
78. 1 INPUTTER....... 8141_VLADIMIR.K_R_RNAU
79. 1 DATE.TIME...... 17 NOV 11 20:02
79. 2 DATE.TIME...... 17 NOV 11 19:56
80 AUTHORISER........ 3625_VLADIMIR.K1
81 CO.CODE........... GB-001-0001 Model Bank
82 DEPT.CODE......... 1 Implementation

------------------------------------------------------------------------------
17 NOV 2011 20:06:05 USER (09 AUG) VLADIMIR.K1 [3625,I PAGE 6
ACTION
AWAITING PAGE INSTRUCTIONS

note: RECORD.STATUS is REVE.

Try to input the record again – go to “AWAITING APPLICATION” level, then (ENQUIRY I
USER2):

Model Bank ENQUIRY INPUT

------------------------------------------------------------------------------

REM Page 312


------------------------------------------------------------------------------
17 NOV 2011 20:07:40 USER (09 AUG) VLADIMIR.K1 [3625,IN]
ACTION U SER2 NO NEW RECORD (ALREADY STORED IN HISTORY FILE)
AWAITING ID

Here “history restore” comes along ( H USER2 ←- ), then F5 ; status will become HNAU.
After authorisation we have our record back and – finally – we can run the enquiry from
“AWAITING APPLICATION” level ( ENQ USER2 ←- ):

Model Bank ENQUIRY INPUT

SELECT NAME....... USER2


------------------------------------------------------------------------------
1. 1 SELECTION.TYPE.
2. 1 SELECTION.FIELD USER.NAME
3. 1 OPERAND........
4. 1. 1 LIST........
1. 2 SELECTION.TYPE.
2. 2 SELECTION.FIELD DEPARTMENT.CODE
3. 2 OPERAND........
4. 2. 1 LIST........
1. 3 SELECTION.TYPE.
2. 3 SELECTION.FIELD START.DATE.PROFILE
3. 3 OPERAND........
4. 3. 1 LIST........
1. 4 SELECTION.TYPE.
2. 4 SELECTION.FIELD END.DATE.PROFILE
3. 4 OPERAND........
4. 4. 1 LIST........
------------------------------------------------------------------------------
17 NOV 2011 20:13:07 USER (09 AUG) VLADIMIR.K [7480,INPAGE 1 >>>3>>>

REM Page 313


ACTION

F5 :

Model Bank
List of T24 Users

------------------------------------------------------------------------------
1 ACCTEXEC Account Executive ACCTEXEC1 Eng
2 ARCUSER GENERIC USER FOR ARC IB ARCUSER01 Eng
3 AUTHORISER AUTHORISER AUTHOR Eng
4 BALA BALA PANDIAN Eng
5 BASEAUTH BAUTH BUSER2 Eng
6 BASEUSER BUSER BUSER1 Eng
7 BRANCHMANAGER1 Branch Manager BRANCHMANAGER Eng
8 BTOOLSUSER BUSINESS TOOLS USER BTOOLS Eng
9 BU007 BU007 ARUSER2 Eng
10 BU008 BU008 ARUSER1 Eng
11 BUILDUSER00 BUILDUSER00 KAILASH3 Eng
12 BUILDUSER0001 BUILDUSER0001 INMAIT Eng
13 BUILDUSER0002 BUILDUSER0002 TGMAIT Eng
14 BUILDUSER0003 BUILDUSER0003 MAITIN Eng
15 BUILDUSER001 BUILDUSER001 SHAR123 Eng
16 BUILDUSER002 BUILDUSER002 SHAR456 Eng
------------------------------------------------------------------------------
17 NOV 2011 20:14:35 USER (09 AUG) VLADIMIR.K [7480,INPAGE 1 >>>3>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Current page can be printed (type PRINT ←- for that; we’ll see the printout in the next
lesson).

17.8 Navigation lesson #3


Log in to T24; try to see unauthorised records for the application ENQUIRY.REPORT
(ENQUIRY.REPORT E ←- ):

Model Bank ENQUIRY.REPORT EXCEPTION

------------------------------------------------------------------------------

REM Page 314


-- LAST SIGN.ON, DATE: 21 NOV 2011 TIME: 19:47 ATTEMPTS: 0 --------
24 NOV 2011 19:09:35 USER (09 AUG) VLADIMIR.K [8445,IN]
ACTION E FUNCTION NOT ALLOWED FOR THIS APPLICATION
AWAITING FUNCTION

note: Not all applications have unauthorised file.

Use V function for particular record to output a report ( V JOURNAL.SUMMARY ←- ):

Model Bank ENQUIRY.REPORT VERIFY

KEY............... JOURNAL.SUMMARY
------------------------------------------------------------------------------
1. 1 GB DESCRIPTION. JOURNAL SUMMARY
2. 1 ENQUIRY........ JOURNAL.CHECK EB.JOURNAL.SUMMARY
3. 1. 1 SELECTION... COMP.CODE
4. 1. 1 OPERAND..... EQ
5. 1. 1 LIST........ !COMPANY
3. 1. 2 SELECTION... SYS.DATE
4. 1. 2 OPERAND..... EQ
5. 1. 2 LIST........ !TODAY-1W
6. 1. 1 SORT........
7 REPORT.CONTROL.... JOURNAL.SUMMARY SUMMARY JNL
8 STANDARD.HEADING.. 80
9. 1 ADDI
10. 1 GB REPORT.HDR..
11 OUTPUT.FORMAT.....
12 RESERVED.13.......
13 RESERVED.12.......
------------------------------------------------------------------------------
24 NOV 2011 19:22:57 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1 >>>3>>>
ACTION
AWAITING PAGE INSTRUCTIONS

REM Page 315


F5 :

------------------------------------------------------------------------------
24 NOV 2011 19:22:57 USER (09 AUG) VLADIMIR.K [8445,IN
ACTION 1 file(s) copied.
AWAITING ID

See the list of last reports ( @ENQ REPORT.LIST ←- ), then F5 :

Hold Control List


Batch Run: :

------------------------------------------------------------------------------
1 BNK JOURNAL.SUMMARY 24 NOV 2011 19:23 No 16034084453382100
2 BNK ENQUIRY.PRINT 17 NOV 2011 20:14 No 15780013442341701
3 BNK TT.DEAL.SLIP 12 MAR 2011 09:11 No 15777047623306300
4 BNK P.FUNCTION 21 JUL 2011 12:48 No 15908082054613400
5 BNK NEW.FILES.CREA| 15 MAR 2011 07:06 No 15780032782560100
6 BNK NEW.FILES.CREA| 15 MAR 2011 07:06 No 15780032782560200
7 BNK NEW.FILES.CREA| 15 MAR 2011 07:06 No 15780032782560300
8 BNK NEW.FILES.CREA| 15 MAR 2011 07:06 No 15780032782560301
9 BNK NEW.FILES.CREA| 15 MAR 2011 07:06 No 15780032782560400
10 BNK NEW.FILES.CREA| 15 MAR 2011 07:06 No 15780032782560401
11 BNK NEW.FILES.CREA| 15 MAR 2011 06:57 No 15780077082506400
12 BNK NEW.FILES.CREA| 15 MAR 2011 06:56 No 15780079962499700
13 BNK NEW.FILES.CREA| 15 MAR 2011 06:30 No 15780013442341100
14 BNK NEW.FILES.CREA| 15 MAR 2011 06:30 No 15780013442341500
15 BNK NEW.FILES.CREA| 15 MAR 2011 06:30 No 15780013442341600
16 BNK NEW.FILES.CREA| 15 MAR 2011 06:30 No 15780013442341601
------------------------------------------------------------------------------
24 NOV 2011 19:25:17 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1 >>>3>>>
ACTION
AWAITING PAGE INSTRUCTIONS

If you’re curious how records are selected and sorted – type SELECTION ←- :

Hold Control List


Batch Run: :

------------------------------------------------------------------------------

SSELECT F.HOLD.CONTROL BY.DSND DATE.CREATED


BY.DSND TIME.CREATED

REM Page 316


------------------------------------------------------------------------------
24 NOV 2011 19:25:37 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1 >>>3>>>
ACTION
AWAITING PAGE INSTRUCTIONS

note: SSELECT doesn’t make any sense here since custom sort is applied.

Then go back – type REFRESH ←- or use any navigation command (like F3). Now see the
report ( 1 ←- , then S F5 ):

Hold Control List


Batch Run: :

------------------------------------------------------------------------------

------------------------------------------------------------------------------
24 NOV 2011 19:25:17 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1 >>>5>>>
ACTION LINE 16 >>>1>>>
AWAITING PAGE INSTRUCTIONS + Pnnn, Lnnn, Reprint, Screen width

REM Page 317


Go down several pages ( F3 F3 F3 ):

Hold Control List


Batch Run: :

------------------------------------------------------------------------------
JOURNAL.CHECK Model Bank 09 AUG 10 Page 1
Area Implementation No 1 Printed at 24 NOV 2011 19:23:41
To Implementation Implementation

Non ContingentJournal
Currency : USD Company : GB0010
Date : 06 AUG 2010

AC 1,155.02 1,155.02- 0.0


LD 1.30 1.30- 0.0
MM 11,696.88 11,696.88- 0.0
RE 199.71 199.71- 0.0
RV 198.58 198.58- 0.0
SL 1,092.25 1,092.25- 0.0

Total 14,343.74 14,343.74- 0.0


------------------------------------------------------------------------------
24 NOV 2011 19:29:18 USER (09 AUG) VLADIMIR.K [8445,INPAGE 4 >>>5>>>
ACTION LINE 16 >>21>>>
AWAITING PAGE INSTRUCTIONS + Pnnn, Lnnn, Reprint, Screen width

Back to list of reports. Entry #2 appeared after printing a page from enquiry USER2 during
the previous lesson:

2 BNK ENQUIRY.PRINT 17 NOV 2011 20:14 No 15780013442341701

Let’s see it:

Hold Control List


Batch Run: :

------------------------------------------------------------------------------
ENQUIRY Model Bank 14 APR 11 PRINT USER2 Page 1
Area Implementation No 1 Printed at 17 NOV 2011 20:14:55
To Implementation Implementation
REQUESTED SCREEN PRINT FROM PAGE 1 TO 1
--------------------------------------------------------------------------------

List of T24 Users

REM Page 318


--------------------------------------------------------------------------------
ACCTEXEC Account Executive ACCTEXEC1 Engli
ARCUSER GENERIC USER FOR ARC IB ARCUSER01 Engli
AUTHORISER AUTHORISER AUTHOR Engli
BALA BALA PANDIAN Engli
BASEAUTH BAUTH BUSER2 Engli
BASEUSER BUSER BUSER1 Engli
------------------------------------------------------------------------------
24 NOV 2011 19:39:18 USER (09 AUG) VLADIMIR.K [8445,INPAGE 3 >>>3>>>
ACTION LINE 16 >>30>>>
AWAITING PAGE INSTRUCTIONS + Pnnn, Lnnn, Reprint, Screen width

Go back to “AWAITING APPLICATION” level; navigate menu #1 ( ?1 ←- ):

Model Bank MAINMENU


Universal Model Bank
NO. DESCRIPTION
------------------------------------------------------------------------------
1 User Menu
2 Admin Menu
3 Role Based Home Pages

------------------------------------------------------------------------------
24 NOV 2011 19:33:02 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1
ACTION
AWAITING PAGE INSTRUCTIONS

Select “User Menu” ( 1 ←- ):

Model Bank MENU USER.MENU


User Menu
NO. DESCRIPTION
------------------------------------------------------------------------------

REM Page 319


1 Customer CUST.MENU
2 CRM CRM.OPS
3 Mandate Management CU.MANDATE
4 Product Catalog COS AA.PRODUCT.CATALOG
5 Retail Operations RETAIL.OPS
6 Credit Operations CREDIT.OPS
7 Payment Services PAYMENT.OPS
8 Corporate Operations CORP.OPS
9 Treasury Operations TREASURY.OPS
10 Private Operations PRIVATE.OPS
11 Finance FINANCE
12 Business Tools BUSINESS.TOOLS

------------------------------------------------------------------------------
24 NOV 2011 19:33:47 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1
ACTION
AWAITING PAGE INSTRUCTIONS

note: F1 can be used to go back.

Select “Customer” ( 1 ←- ):

Model Bank MENU CUST.MENU

NO. DESCRIPTION
------------------------------------------------------------------------------
1 Individual Customer
2 Corporate Customer
3 Create Prospect
4 Activate Customer
5 Amend Customer
6 Unauthorised Customer
7 Authorise/Delete Customer
8 Create/Amend Routing Instructions
9 Authorise/Delete Routing Instructions
10 Additional Address of Customer
11 Amend Customer Charge
12 Authorise/Delete Customer Charge
13 Set/Remove Posting Restrict
14 Authorise/Delete Posting Restrict
15 Capture External Arrangement
16 Authorise/Delete External Arrangement
------------------------------------------------------------------------------
24 NOV 2011 19:35:51 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1 >>>2>>>

REM Page 320


ACTION
AWAITING PAGE INSTRUCTIONS

Go to “Individual Customer” menu item ( 1 ←- ):

Model Bank CUSTOMER,INPUT INPUT


Basic Details

------------------------------------------------------------------------------

------------------------------------------------------------------------------
24 NOV 2011 19:38:17 USER (09 AUG) VLADIMIR.K [8445,IN]
ACTION F 3 TOO FEW MNEMONIC CHAR.
AWAITING ID

note: We’ll address this error message later.

Generate new @id ( F3 ):

Model Bank CUSTOMER,INPUT INPUT


Basic Details
CUSTOMER.CODE..... 120236
------------------------------------------------------------------------------
Title Given Name Family Name

Full Name...............
Full Name-2..............
Short Name............... Mnemonic.................
Gender................... Marital Status...........
Account Officer..........

REM Page 321


Second Officer...........
Sector................... Industry.................
Target................... Customer Status..........
Nationality.............. Residence................
Customer Type............
Customer Rating..........
Date of Birth............ Language................. 1 English
------------------------------------------------------------------------------
24 NOV 2011 19:39:55 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1
ACTION

Go back to “AWAITING APPLICATION” level; see our path along menus ( HELPTEXT.MAINMENU
S 1 ←- ):

Model Bank HELPTEXT.MAINMENU SEE

ACTION.CODE....... 1
------------------------------------------------------------------------------
1. 1 GB TITLE....... Universal Model Bank
2. 1 ID.OF.HELP.MENU USER.MENU
3. 1. 1 GB DESCRIPT. User Menu
2. 2 ID.OF.HELP.MENU ADMIN.MENU
3. 2. 1 GB DESCRIPT. Admin Menu
2. 3 ID.OF.HELP.MENU HOME.PAGE
3. 3. 1 GB DESCRIPT. Role Based Home Pages
6 CURR.NO........... 19
7. 1 INPUTTER....... 224_BUILDUSER85__OFS_BROWSERTC
8. 1 DATE.TIME...... 27 AUG 10 05:50
9 AUTHORISER........ 224_BUILDUSER85_OFS_BROWSERTC
10 CO.CODE........... GB-001-0001 Model Bank
11 DEPT.CODE......... 74 PWM Relationship Manager

------------------------------------------------------------------------------
24 NOV 2011 19:42:56 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1
ACTION
AWAITING PAGE INSTRUCTIONS

So “User menu” that we’ve chosen initially has @id USER.MENU.


Application is HELPTEXT.MENU. Let’s see it ( HELPTEXT.MENU S USER.MENU ←- from
“AWAITING APPLICATION” level):

Model Bank HELPTEXT.MENU SEE

REM Page 322


MENU.NAME......... USER.MENU
------------------------------------------------------------------------------
1. 1 APPL CUST.MENU
2. 1. 1 GB DESCRIPT. Customer
1. 2 APPL CRM.OPS
2. 2. 1 GB DESCRIPT. CRM
1. 3 APPL CU.MANDATE
2. 3. 1 GB DESCRIPT. Mandate Management
1. 4 APPL COS AA.PRODUCT.CATALOG
2. 4. 1 GB DESCRIPT. Product Catalog
1. 5 APPL RETAIL.OPS
2. 5. 1 GB DESCRIPT. Retail Operations
1. 6 APPL CREDIT.OPS
2. 6. 1 GB DESCRIPT. Credit Operations
1. 7 APPL PAYMENT.OPS
2. 7. 1 GB DESCRIPT. Payment Services
1. 8 APPL CORP.OPS
2. 8. 1 GB DESCRIPT. Corporate Operations
------------------------------------------------------------------------------
24 NOV 2011 19:48:05 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1 >>>2>>>
ACTION
AWAITING PAGE INSTRUCTIONS

Following this chain finally we can see the command that gave us an error before:

Model Bank HELPTEXT.MENU SEE

MENU.NAME......... CUST.MENU
------------------------------------------------------------------------------
1. 1 APPL CUSTOMER,INPUT I F3
2. 1. 1 GB DESCRIPT. Individual Customer
1. 2 APPL CUSTOMER,CORP I F3
2. 2. 1 GB DESCRIPT. Corporate Customer
1. 3 APPL CUSTOMER,PROSPECT I F3
2. 3. 1 GB DESCRIPT. Create Prospect
1. 4 APPL COS ACTIVATE.CUSTOMER
2. 4. 1 GB DESCRIPT. Activate Customer
1. 5 APPL COS CUST.AMEND
2. 5. 1 GB DESCRIPT. Amend Customer
1. 6 APPL COS CUSTOMER.NAU.AMEND
2. 6. 1 GB DESCRIPT. Unauthorised Customer
1. 7 APPL COS CUSTOMER.NAU
2. 7. 1 GB DESCRIPT. Authorise/Delete Customer
1. 8 APPL COS CUST.AGENCY
2. 8. 1 GB DESCRIPT. Create/Amend Routing Instructions
------------------------------------------------------------------------------
24 NOV 2011 19:49:57 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1 >>>3>>>

REM Page 323


ACTION
AWAITING PAGE INSTRUCTIONS

note: “F3” in command line worked before; now it doesn’t.


Instead of typing “F3” or pressing F3 it’s possible to save typing using a number or a
“mnemonic”. Type FT I 1 ←- or COMPANY I BNK ←- from “AWAITING APPLICATION”
level:

Model Bank FUNDS.TRANSFER INPUT REF FT102210000 1

------------------------------------------------------------------------------
1 TRANSACTION.TYPE..
2 DEBIT.ACCT.NO.....
3 IN.DEBIT.ACCT.NO..
4 CURRENCY.MKT.DR... 1 Currency Market
5 DEBIT.CURRENCY....
6 DEBIT.AMOUNT......
7 DEBIT.VALUE.DATE..
8 IN.DEBIT.VDATE....
9 DEBIT.THEIR.REF...
10 CREDIT.THEIR.REF..
11 CREDIT.ACCT.NO....
12 CURRENCY.MKT.CR... 1 Currency Market
13 CREDIT.CURRENCY...
14 CREDIT.AMOUNT.....
15 CREDIT.VALUE.DATE.
16 TREASURY.RATE.....
------------------------------------------------------------------------------
24 NOV 2011 20:00:05 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1 >>15>>>
ACTION

Model Bank COMPANY INPUT

COMPANY.CODE...... GB-001-0001 Great Britain COMPANY GROUP 1


------------------------------------------------------------------------------
1. 1 GB COMPANY.NAME Model Bank
2. 1 NAME.ADDRESS... 18 Place De Philosophes,
2. 2 NAME.ADDRESS... CH 1205 Geneva,
2. 3 NAME.ADDRESS... Switzerland
3 MNEMONIC.......... BNK
4 LANGUAGE.CODE..... 1 English
5 STAT.REP.AREA.....
6 STAT.REP.NAME.....
7 STAT.REP.DELIV....

REM Page 324


8 MGMT.REP.AREA.....
9 MGMT.REP.NAME.....
10 MGMT.REP.DELIV....
11 CONSOLIDATION.MARK N
12 DEFAULT.NO.OF.AUTH 1
13. 1 PGM.AUTOM.ID... ACCOUNT
13. 2 PGM.AUTOM.ID... DX.CO.EXT.XFER.MANUAL
------------------------------------------------------------------------------
24 NOV 2011 20:01:44 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1 >>18>>>
ACTION
AWAITING PAGE INSTRUCTIONS

We can input function at “AWAITING ID” level as well. What if @id looks like a function?
Example of such application - INTEREST.BASIS:

Model Bank INTEREST.BASIS - Default List

ID DESCRIPTION INT.BASIS OLD.CALC.METHOD CURR.NO FUNCT.


------------------------------------------------------------------------------
1 A 360/360 360/360 1
2 A1 360/360 360/360 1
3 A2 30/360 30/360 1
4 A3 30/360 30/360 1
5 B 366/360 366/360 1
6 C 366/366 366/366 1
7 C2 366/366 366/366 1
8 D 360/366 360/366 1
9 E 366/365 366/365 1
10 E1 365/365 365/365 2
11 F 360/365 360/365 1
12 F1 360/365 360/365 1
13 F2 30/365 30/365 1
14 G 366/364 366/364 2
15 H 30/356 30/356 1
16 S SPECIAL 1
------------------------------------------------------------------------------
24 NOV 2011 20:06:43 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1 >>>2>>>
ACTION
AWAITING PAGE INSTRUCTIONS

1 ←- S F5 takes us to authorisation:

Model Bank INTEREST.BASIS AUTHORISE

------------------------------------------------------------------------------

REM Page 325


------------------------------------------------------------------------------
24 NOV 2011 20:07:19 USER (09 AUG) VLADIMIR.K [8445,IN]
ACTION
AWAITING ID

Dot before an @id will help (S ←- .A ←- ):

Model Bank INTEREST.BASIS SEE

INTEREST.BASIS.... A
------------------------------------------------------------------------------
1. 1 GB DESCRIPTION. 360/360
2 INT.BASIS......... 360/360
9 CURR.NO........... 1
10. 1 INPUTTER....... 1_G6.0.05
11. 1 DATE.TIME...... 24 OCT 95 11:44
12 AUTHORISER........ 54_INPUTTER
13 CO.CODE........... GB-001-0001 Model Bank
14 DEPT.CODE......... 1 Implementation

------------------------------------------------------------------------------
24 NOV 2011 20:10:10 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1
ACTION
AWAITING PAGE INSTRUCTIONS

REM Page 326


To see more records without marking them in advance we can use F6 :

Model Bank INTEREST.BASIS SEE

INTEREST.BASIS.... A1
------------------------------------------------------------------------------
1. 1 GB DESCRIPTION. 360/360
2 INT.BASIS......... 360/360
9 CURR.NO........... 1
10. 1 INPUTTER....... 1_G7.2.01
11. 1 DATE.TIME...... 01 MAY 97 13:43
12 AUTHORISER........ 46_INPUTTER
13 CO.CODE........... GB-001-0001 Model Bank
14 DEPT.CODE......... 1 Implementation

------------------------------------------------------------------------------
24 NOV 2011 20:12:08 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1
ACTION
AWAITING PAGE INSTRUCTIONS

Model Bank INTEREST.BASIS SEE

INTEREST.BASIS.... A2
------------------------------------------------------------------------------
1. 1 GB DESCRIPTION. 30/360
2 INT.BASIS......... 30/360
9 CURR.NO........... 1
10. 1 INPUTTER....... 1_G6.0.05
11. 1 DATE.TIME...... 24 OCT 95 11:44
12 AUTHORISER........ 54_INPUTTER
13 CO.CODE........... GB-001-0001 Model Bank
14 DEPT.CODE......... 1 Implementation

REM Page 327


------------------------------------------------------------------------------
24 NOV 2011 20:12:40 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1
ACTION
AWAITING PAGE INSTRUCTIONS

Model Bank INTEREST.BASIS SEE

INTEREST.BASIS.... A3
------------------------------------------------------------------------------
1. 1 GB DESCRIPTION. 30/360
2 INT.BASIS......... 30/360
9 CURR.NO........... 1
10. 1 INPUTTER....... 35_AUTHORISER
11. 1 DATE.TIME...... 03 AUG 07 12:39
12 AUTHORISER........ 35_INPUTTER
13 CO.CODE........... GB-001-0001 Model Bank
14 DEPT.CODE......... 1 Implementation

------------------------------------------------------------------------------
24 NOV 2011 20:12:52 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1
ACTION
AWAITING PAGE INSTRUCTIONS

Last but not least – there’s a navigation help that can be accessed at “AWAITING FUNCTION”
level ( ? ←- ):

Model Bank ACCOUNT

NO. FUNCTION NAME ACT.


------------------------------------------------------------------------------
1 '!'CHARACTER
2 '('CHARACTER
3 ')'CHARACTER
4 ';'CHARACTER
5 '-'CHARACTER
6 '<'CHARACTER
7 '>'CHARACTER
8 '?'CHARACTER
9 '@'CHARACTER
10 AUTHORISE

REM Page 328


11 BACKGROUND.VALID
12 COPY
13 DELETE
14 EXCEPTION
15 FAST.INPUT
16 HISTORY.RESTORE
------------------------------------------------------------------------------
24 NOV 2011 20:26:11 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1 >>>3>>>
ACTION
AWAITING PAGE INSTRUCTIONS

To see a chapter enter its number like we did before for application records but use “?”
instead of a function, e.g. 2 ←- ? F5 :

Model Bank ACCOUNT

FUNCTION = '('CHARACTER
------------------------------------------------------------------------------
This command will expand a sub-value, or sub-value set, within a
multivalue field.

To Use: DATA SECTION


Enter: (
(At the position where the additional sub-value is to be
inserted.)

Certain fields within the GLOBUS database are defined as being multivalue,
which means that the field can be expanded to accommodate different
values. Some multivalue fields have the additional facility of having
sub-values within each multivalue element.

e.g. Field No 1 Single Value


Field No 2.1 Multivalue
Field No 3.1.1 Multivalue with sub-values
------------------------------------------------------------------------------
24 NOV 2011 20:27:33 USER (09 AUG) VLADIMIR.K [8445,INPAGE 1 >>>5>>>
ACTION
AWAITING PAGE INSTRUCTIONS

17.9 Navigation lesson #4. Non-standard navigation.


At “AWAITING APPLICATION” prompt type DE.MM.DISPLAY ←- :

Model Bank DISPLAY QUEUES

NO. QUEUE FUNCT.

REM Page 329


------------------------------------------------------------------------------
1 --
2 OUTWARD - UNFORMATTED
3 HOLD
4 REPAIR
5 AWAITING TESTKEY
6 AWAITING ACKNOWLEDGEMENT
7 FORMATTED - PRINT (FILE)
8 FORMATTED - PRINT (BVAL)
9 FORMATTED - PRINT (FULLPG)
10 FORMATTED - PRINT (WR.EXT)
11 FORMATTED - PRINT (ADVICE)
12 FORMATTED - PRINT (D.SLIP)
13 FORMATTED - PRINT (HOLD)
14 FORMATTED - PRINT (STMT)
15 FORMATTED - PRINT (SYSCOM)
16 FORMATTED - PRINT (BPMNT)
-- LAST SIGN.ON, DATE: 28 FEB 2012 TIME: 13:12 ATTEMPTS: 0 --------
01 MAR 2012 19:18:13 USER (14 APR) VLADIMIR.K [1596,INPAGE 1 >>>3>>>
ACTION
AWAITING FUNCTION

3 ←- shows HOLD queue:

Model Bank OUTWARD - HOLD DISPLAY

NO. REFERENCE NO. TRANS. REF MSG TYPE STATUS PRIORITY FUNCT.
------------------------------------------------------------------------------
1 D20110420-049754593400.1 FX1107036479 202 HOLD
2 D20110420-049754593807.1 FX1107001307 202 HOLD

-- LAST SIGN.ON, DATE: 28 FEB 2012 TIME: 13:12 ATTEMPTS: 0 --------


01 MAR 2012 19:18:13 USER (14 APR) VLADIMIR.K [1596,INPAGE 1
ACTION

REM Page 330


AWAITING FUNCTION

1 ←- S ←- shows first record:

Model Bank OUTWARD DELIVERY HEADER SEE

DATE.TIME.STAMP... D20110420-04975-45934-00
------------------------------------------------------------------------------
1 MESSAGE TYPE...... 202
3 APPLICATION....... FX
4 DISPOSITION....... UNFORMATTED
6 PRIORITY.......... N
10 ACCOUNT NUMBER.... 23752
11. 1 CUSTOMER NUMBER 100492
12 CUS. COMPANY...... GB0010001
13 COMPANY CODE...... GB0010001
16 LANGUAGE.......... GB
17 VALUE DATE........ 15 MAR 2011
18 CURRENCY.......... USD
19 AMOUNT............ 304000.00
20 DEPARTMENT........ 5
21 TRANSACTION REF... FX1107036479
23 TEST KEY REQ...... Y
25. 1 CARRIER ADDR NO SWIFT.1
------------------------------------------------------------------------------
01 MAR 2012 19:23:55 USER (14 APR) VLADIMIR.K [1596,I PAGE 1 >>>2>>>
ACTION
AWAITING PAGE INSTRUCTIONS

You can use F2 , F3 and F4 to navigate the record; F1 pressed twice takes you back
to records list (and you are positioned on the next record):

Model Bank OUTWARD - HOLD DISPLAY

NO. REFERENCE NO. TRANS. REF MSG TYPE STATUS PRIORITY FUNCT.
------------------------------------------------------------------------------
1 D20110420-049754593400.1 FX1107036479 202 HOLD
2 D20110420-049754593807.1 FX1107001307 202 HOLD

REM Page 331


------------------------------------------------------------------------------
01 MAR 2012 19:25:25 USER (14 APR) VLADIMIR.K [1596,I PAGE 1
ACTION
AWAITING FUNCTION

F1 – back to queues list. To view a resulting document we need to choose some queue that
has formatted records, e.g. “FORMATTED - PRINT (ADVICE)” (11 ←- ):

Model Bank OUTWARD - FORMATTED - PRINT (ADVICE) DISPLAY

NO. REFERENCE NO. TRANS. REF MSG TYPE STATUS PRIORITY FUNCT.
------------------------------------------------------------------------------
1 D20110411-023435075003.1 FT11070NRKBC 910
2 D20110411-072784681604.1 FT11070MB903 910
3 D20110415-055532794904.1 FT11070Z06ZQ 910
4 D20110504-086292907601.1 FT11104XY3W6 910
5 D20110428-065424049704.1 FT11097F3PJS 910
6 D20110411-000293919305.1 SCTRSC1107066YJK 518
7 D20110411-000294308805.1 SCTRSC11070HDBNF 518
8 D20110411-046934187805.1 SCTRSC11070X51KY 518
9 D20110411-046934189204.1 SCTRSC11070DL8S3 518
10 D20110411-046934192004.1 SCTRSC11070DYLK6 518
11 D20110411-046934193604.1 SCTRSC11070FPZ7W 518
12 D20110411-046934198400.1 SCTRSC11070Q7B00 518
13 D20110411-046934200004.1 SCTRSC11070SQBLS 518
14 D20110411-046935146705.1 SCTRSC110708LN5G 518
15 D20110419-001015232502.1 SCTRSC11070C9XC5 518
16 D20110419-001015251502.1 SCTRSC11070DPNLJ 518
------------------------------------------------------------------------------
01 MAR 2012 19:27:02 USER (14 APR) VLADIMIR.K [1596,I PAGE 1 >>>330>>>
ACTION
AWAITING FUNCTION

To view the message choose one and use “V” (e.g. 5 ←- V ←- ):

Model Bank DISPLAY PRINTED MESSAGES

------------------------------------------------------------------------------
Do you want to display or print the message
Enter D (Display), P (Print) or <RETURN> to end

REM Page 332


------------------------------------------------------------------------------
01 MAR 2012 19:27:02 USER (14 APR) VLADIMIR.K [1596,I PAGE 1 >>>330>>>
ACTION
AWAITING FUNCTION

D ←- :

Model Bank DISPLAY PRINTED MESSAGES

REFERENCE......... D20110428-065424049704.1
------------------------------------------------------------------------------
********************************************************************************
PAGE 1 PAGE 1 PAGE 1 PAGE 1 PAGE
********************************************************************************

DATE : 07 APRIL 2011 Collin Cash


Collin Cash
REFERENCE : FT/11097/F3PJS 1234 - 12th Ave.
------------------------------------------------------------------------------
01 MAR 2012 19:27:02 USER (14 APR) VLADIMIR.K [1596,I PAGE 1
ACTION
AWAITING FUNCTION

REM Page 333


Navigation here is regular (e.g. press F3 twice):

Model Bank DISPLAY PRINTED MESSAGES

REFERENCE......... D20110428-065424049704.1
------------------------------------------------------------------------------
WE HAVE TODAY RECEIVED THE FOLLOWING ACCOUNT TRANSFER INSTRUCTION FOR
VALUE 07 APRIL 2011

BY ORDER OF : YOURSELVES

WE HAVE CREDITED YOUR USD ACCOUNT NO 47872 AS FOLLOWS:

TRANSFER AMOUNT USD 30,000.00


--------------------
AMOUNT CREDITED USD 30,000.00

IF YOU HAVE ANY QUERIES REGARDING THE ABOVE DETAILS, PLEASE CONTACT
US AS SOON AS POSSIBLE QUOTING OUR TRANSACTION NUMBER.
------------------------------------------------------------------------------
01 MAR 2012 19:27:02 USER (14 APR) VLADIMIR.K [1596,I PAGE 1
ACTION
AWAITING FUNCTION

Similarly for SWIFT (the following example is from inward REPAIR queue):

Model Bank DISPLAY SWIFT MESSAGES

REF......... R20110419-045402954102
------------------------------------------------------------------------------
{1:F01DEMOGBPXAXXX.SN...ISN.}{2:I300AEIBSGSGXXXXN}{3:{108:xxxxx}}{4:
:15A/Sequence Identi :
:20/TRANSACTION REFE : FX1107008005
:21/Related Referenc : NEW
:22A/Type of Operati : NEWT
:22C/Common Referenc : DEMOPX3125AEIBSG
:82A/PARTY A : AEIBSGS
:87A/RECEIVER/DELIVE : DEMOGBPX
:15B/Sequence Identi :
:30T/Trade Date : 20110311
:30V/Value Date : 20110315
:36/EXCHANGE RATE : 0,703125
:32B/Currency Code, : GBP6400,00
:57A/Account with Ba : BARCGB22
:33B/Currency, Amoun : USD4500,00

REM Page 334


:57A/Account with Ba : /577848738
------------------------------------------------------------------------------
01 MAR 2012 19:38:01 USER (14 APR) VLADIMIR.K [1596,INPAGE 1 >>>2>>>
ACTION ~colorbox{custom5}{ }
AWAITING FUNCTION

18 Source code editing


In this chapter described the usage of SciTE editor as a lightweight IDE for JBC code.
Scite used is: Sc1, Version 3.2.0, Jun 1 2012 18:28:19 (win32). All Lua code isn’t optimized
(no time for that) but it works for me.
The most interesting task was:

18.1 To highlight jBC code


None of standard syntax highlighters did the task well (and they weren’t supposed to). So
several Lua functions were written to do that (this is a part of kzm-lib.lua that is set as a
startup script in my SciTEUser.properties):

function Set(list)
local set = {}
for _, l in ipairs(list) do set[l] = true end
return set
end

function string.starts(String,Start)
return string.sub(String,1,string.len(Start))==Start
end

---------------------------
function get_jbc_kwords(n_set)
if n_set == 1 then
return {
'$INSERT', '@FM', '@VM', '@SM', '@TM', '@AM', '@ID', '@RECORD',
'@FILENAME',
'ABS', 'ACOS', 'ADDS', 'ALPHA', 'AND', 'ANDS', 'APPEND',
'APPENDING', 'ARG', 'ASCII', 'ASIN',
'ASSIGNED', 'AT', 'ATAN', 'ATKEY', 'ATVARBEFORE',
'BEFORE', 'BEGIN', 'BFUNC', 'BITAND', 'BITCHANGE', 'BITCHECK',
'BITLOAD', 'BITNOT', 'BITOR', 'BITRESET', 'BITSET', 'BITXOR',
'BLOB', 'BREAK', 'BY', 'BYTELEN',
'CAPTURING', 'CASE', 'CATS', 'CE', 'CFUNC', 'CHANGE', 'CHAR',
'CHARS', 'CHDIR', 'CHECKSUM', 'CLEAR', 'CLEARCOMMON', 'CLEARDATA',
'CLEARFILE', 'CLEARINPUT', 'CLEARSELECT', 'CLOSE', 'CLOSESEQ', 'CREATE',
'COL1', 'COL2', 'COLLECTDATA', 'COMMON', 'COMPARE', 'CONTINUE',
'CONVERT', 'COS', 'COUNT', 'CRC', 'CRT', 'CTYPE', 'DATA', 'DATE',
'DCOUNT', 'DE', 'DEBUG', 'DECLARE', 'DECRYPT', 'DEFB', 'DEFC',
'DEFCPP', 'DEFFUN', 'DEL', 'DELETE', 'DELETELIST', 'DELETESEQ',
'DICT', 'DIM', 'DIR', 'DISPLAY', 'DIVS', 'DO', 'DOWNCASE',

-- Page 335
'DQUOTE', 'DTX', 'EBCDIC', 'ECHO', 'EDYN', 'ELSE', 'ENCRYPT',
'END', 'ENVFUNC', 'EOL', 'EQ', 'EQU', 'EQUATE', 'ERROR', 'ERRTEXT',
'EXISTING',
'EXP', 'EXTRACT', 'FADD', 'FCMP', 'FDIV', 'FFIX', 'FFLT', 'FIELD',
'FIELDS', 'FILEINFO', 'FILELOCK', 'FIND', 'FINDSTR', 'FLOAT',
'FMT', 'FMUL', 'FOLD', 'FOOTING', 'FOR', 'FORMLIST', 'FROM',
'FSUB', 'FUNCTION', 'GE', 'GES', 'GET', 'GETCWD', 'GETENV',
'GETLIST', 'GETX', 'GROUP', 'GROUPSTORE', 'GT', 'HEADING', 'HUSH',
'ICONV', 'IF', 'IN', 'INCLUDE', 'INDEX', 'INDICES', 'INMAT',
'INPUT', 'INPUTCLEAR', 'INPUTERR', 'INPUTNULL', 'INPUTTRAP',
'INS', 'INSERT', 'INT', 'IOCTL', 'ISALPHA', 'ISALNUM', 'ISDIGIT',
'ITYPE',
'JBASECOREDUMP', 'JBASESubroutineExist',
'KEY', 'KEYIN',
'LATIN1', 'LE', 'LEN', 'LN', 'LOCATE', 'LOCK', 'LOCKED', 'LOOP',
'LOWCASE', 'LOWER', 'LP', 'LT',
'MAKETIMESTAMP',
'MAT', 'MATBUILD', 'MATCHES', 'MATCHFIELD', 'MATPARSE', 'MATREAD',
'MATREADU', 'MATVAR', 'MATWRITE', 'MATWRITEU', 'MAXIMUM', 'ME',
'MINIMUM', 'MM', 'MOD', 'MSG', 'MSLEEP', 'MULS', 'NE', 'NEG',
'NEGS', 'NEXT', 'NOT', 'NULL', 'NUM', 'OBJEXCALLBACK', 'OCONV',
'OFF', 'ON', 'ONGOSUB', 'ONGOTO', 'OPEN', 'OPENDEV', 'OPENINDEX',
'OPENPATH', 'OPENSEQ', 'OPENSER', 'OR', 'ORS', 'OSBREAD',
'OSBWRITE', 'OSCLOSE', 'OSDELETE', 'OSOPEN', 'OSREAD', 'OSWRITE',
'OUT', 'PAGE', 'PASSDATA', 'PASSLIST', 'PAUSE', 'PE', 'PERROR',
'POSCUR', 'PP', 'PRECISION', 'PRINT', 'PRINTER', 'PRINTERR',
'PROCREAD', 'PROCWRITE', 'PROGRAM', 'PROMPT', 'PUTENV', 'PWR',
'QUOTE',
'RAISE', 'READ', 'READLIST', 'READNEXT', 'READONLY', 'READPREV',
'READSEQ', 'READT', 'READTX',
'READU', 'READV', 'READVU', 'READX', 'READXU', 'RECORDLOCKE',
'RECORDLOCKU', 'REGEXP', 'RELEASE', 'RECORDLOCKED', 'REMOVE',
'REPEAT', 'REPLACE', 'REUSE', 'REWIND', 'RND', 'RTNDATA',
'RTNLIST',
'SADD', 'SCMP', 'SDIV', 'SDYN', 'SECTION', 'SELECT', 'SELECTE',
'SELECTINDEX', 'SELECTINFO', 'SEND', 'SENDX', 'SENTENCE', 'SEQ',
'SETTING', 'SIN', 'SLEEP', 'SMUL', 'SORT', 'SOUNDEX', 'SPACE',
'SPLICE', 'SPOOLER', 'SQL', 'SQRT', 'SQUOTE', 'SSUB', 'SSELECT',
'SSELECTN', 'SSELECTV', 'STATIC', 'STATUS', 'STEP', 'STR',
'STRING', 'SUBR', 'SUBROUTINE', 'SUBS', 'SUBSTRINGS', 'SUM',
'SUMMATION', 'SWAP', 'SYNC', 'SYSTEM',
'System.getUserVariables',
'TA', 'TABLE', 'TAN', 'TE',
'THEN', 'TIME', 'TIMEDATE', 'TO', 'TRANS', 'TRANSABORT',
'TRANSEND', 'TRANSQUERY', 'TRANSTART', 'TRIM', 'TRIMB', 'TRIMF',
'UNASSIGNED', 'UNFILTERED', 'UNLOCK', 'UNTIL', 'UPCASE', 'USING',
'UTF8', 'VAR', 'VARCHAR', 'WAITING', 'WAKE', 'WEOF', 'WEOFSEQ',
'WHILE', 'WITH', 'WRITE', 'WRITEBLK', 'WRITELIST', 'WRITEP',
'WRITEPU', 'WRITESEQ', 'WRITESEQF', 'WRITET', 'WRITETX', 'WRITEU',
'WRITEV', 'WRITEVU', 'WRITEX', 'WRITEXU',
'XLATE', 'XTD'
}
end

-- Page 336
if n_set == 2 then
return {
'ABORT', 'CALL', 'CALLC', 'CALLJ', 'CHAIN', 'ENTER', 'EXEC',
'EXECUTE', 'EXIT', 'GO', 'GOSUB', 'GOTO', 'PERFORM', 'STOP', 'RETURN'
}
end
end

---------------------------
function OnStyle(styler)

--This feature is being developed and is not stable.


-- The API may change in the future.

-- config:
-- lexer.*.b=script_b
-- style.script_b.0=fore:#000000
-- style.script_b.1=fore:#98280C
-- style.script_b.2=fore:#0000FF
-- style.script_b.3=fore:#757877
-- style.script_b.4=fore:#FF0000
-- style.script_b.5=fore:#DF7401
-- style.script_b.6=fore:#DF01A5
-- style.script_b.7=fore:#088C4B

S_DEFAULT = 0
S_STRING = 1
S_KEYWORD = 2
S_COMMENT = 3
S_FORK = 4
S_LABEL = 5
S_T24_KWORD = 6
S_NUMBER = 7

-- 1,2 for COL1 (2), other digits - for labels and numbers
-- SAVED local kw_characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.@$_"
local kw_characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.@$_abcdefghijklmnopqrstuvwxyz"

local jbc_kw = Set(get_jbc_kwords(1))


local jbc_kw_fork = Set(get_jbc_kwords(2))

-- I_COMMON and I_EQUATE


local t24_kwords = Set{
'A', 'AF', 'ANY.INPUT', 'APPLICATION', 'AS', 'AUTH.NO',
'AUTH.QUALITY', 'AV',
'BATCH.DETAILS',
'C', 'C$ACTION.DETAIL', 'C$APP.STORE.DATA', 'C$BA.PARAMETER',
'C$CHARX', 'C$COMP.EOD.LIST', 'C$DE.EU.LIST',
'C$EB.PHANTOM.ID', 'C$FUNCTION.LIST',
'C$INT.MOVEMENT.PARAM', 'C$MULTI.BOOK', 'C$NS.OPERATION',
'C$PC.CLOSING.DATE', 'C$PORT.NO', 'C$R.LCCY',
'C$SC.FEE.RECALC', 'C$SEQX', 'C$SPARE', 'C$T24.SESSION.NO',

-- Page 337
'C$.UNIVERSE.RELEASE', 'C$.USE.CCY.CACHE', 'C.U', 'C.B',
'C.F', 'C.E', 'C.V', 'C.W', 'C.T', 'C.PRINT', 'CACHE.OFF',
'CACHE.TEXT.TABLE', 'CHARSX', 'CHARX', 'CHECKFILE',
'CLEAR.SCREEN', 'CMD$STACK', 'COMI', 'COMI.DEFAULT',
'COMI.ENRI', 'CONCATFILE', 'CONTROL.MODULO', 'CONTROLWORD.OK',
'E', 'ECOMI', 'END.ERROR', 'ETEXT',
'F', 'F.ACTIVITY', 'F.CURRENCY', 'F.DYNAMIC.TEXT', 'F.FILE',
'F.FILE$HIS', 'F.FILE$NAU', 'F.FILE.CONTROL', 'F.IDS.LATEST',
'F.JOURNAL', 'F.LOCKING', 'F.PROTOCOL', 'F.SPF',
'F.STATIC.TEXT', 'F.T24.SESSION', 'FILE.CLASS', 'FILE.TYPE',
'FM', 'FULL.FNAME', 'G.SPARE1', 'G.SPARE2', 'G.SPARE3',
'G.SPARE4', 'G.SPARE5', 'G.SPARE6', 'G.SPARE7', 'G.SPARE8',
'G.SPARE9', 'G.SPARE10', 'G.SPARE11', 'G.SPARE12',
'G.SPARE13', 'G.SPARE14', 'G.SPARE15', 'G.SPARE16',
'G.SPARE17', 'G.SPARE18', 'G.SPARE19', 'G.SPARE20',
'G.SPARE21',
'HIST.NO',
'ID.ALL', 'ID.AUT', 'ID.CHECKFILE', 'ID.COMPANY',
'ID.CONCATFILE', 'ID.ENRI', 'ID.ETEXT', 'ID.F', 'ID.N',
'ID.NEW', 'ID.NEW.LAST', 'ID.OLD', 'ID.POINTER', 'ID.R',
'ID.T', 'INPUT.BUFFER',
'JOURNAL.BYPASS',
'L', 'L.MULTI', 'L1ST', 'LANG.NO', 'LASTA', 'LASTL.MULTI',
'LASTP', 'LCCY', 'LEVEL.NO', 'LEVEL.STATUS',
'LEVELS.NOT.ALLOWED', 'LIMIT.NETTING.IND', 'LINK.DATA',
'LIVE.RECORD.MANDATORY', 'LNGG', 'LOCAL.REF.FIELD',
'LOCAL1', 'LOCAL2', 'LOCAL3', 'LOCAL4', 'LOCAL5', 'LOCAL6',
'LOCAL7', 'LOCAL8',
'MESSAGE', 'MULTI.POSSIBLE', 'MTHPOS',
'N', 'NOTNUMERIC', 'NUMERIC',
'OPERATOR', 'OPF.NO', 'OTHERWISE', 'OVERRIDE.FLAG',
'P', 'PGM.TYPE', 'PGM.TYPE.NEXT', 'PGM.VERSION', 'PHNO',
'PREFIX', 'PRT.PARAMS', 'PRINTER.STATUS', 'R',
'R.ACCOUNT.PARAMETER', 'R.BANK.RETURN.PARAMS', 'R.COMPANY',
'R.DATES', 'R.INTERCO.PARAMETER', 'R.NEW', 'R.NEW.LAST',
'R.OLD', 'R.OPF', 'R.SPF.SYSTEM', 'R.USER', 'R.VERSION',
'RCOL', 'RLIN', 'RTXT', 'RELN', 'RFLN', 'RETURN.COMI',
'RUNNING.IN.JBASE', 'RUNNING.IN.UTF8', 'RUNNING.UNDER.BATCH',
'SCREEN.MODE', 'SCREEN.TITLE', 'SENSITIVITY', 'SEQSX', 'SEQX',
'SM', 'SPARE.FKEY8', 'SPARE.FKEY9', 'SPARE.FKEY10',
'SPARE.FKEY11', 'SPARE.FKEY12', 'SPARE.FKEY13',
'SPARE.FKEY14', 'SPARE.FKEY15', 'SPARE.FKEY16',
'T', 'T.AUTH.PAGE', 'T.CAT', 'T.CCY', 'T.CONTROLWORD',
'T.DEF.BASE', 'T.DEF.BASE.TARGET', 'T.ENRI', 'T.ETEXT',
'T.FIELDNO', 'T.FUNCTION', 'T.LANGUAGE', 'T.LOCREF', 'T.MTH',
'T.MTH.DAY', 'T.MULTI.PAGE', 'T.MULTI.TEXT', 'T.OPF',
'T.OPF.FC', 'T.OPF.FN', 'T.OPF.MAX', 'T.OV.CLASS', 'T.PWD',
'T.PWP', 'T.RAT', 'T.REMTEXT', 'T.RETURN.DATA', 'T.SELECT',
'T.SEQU', 'T.SUB.ASSOC', 'T.VAL.ASSOC', 'TEXT', 'TIME.STAMP',
'TNO', 'TODAY', 'TTYPE', 'USER.DATE.FORMAT', 'USING.EBCDIC',
'V', 'V$ACTION', 'V$DISPLAY', 'V$FUNCTION',
'VAL.TEXT', 'VM',
'WRITE.CACHE',

-- Page 338
'Z',
'O.DATA' -- the most used one from I_ENQUIRY.COMMON as well
}

local compressed_line = ''


local string_start = ''
local cur_word = ''
local cur_sym = ''
local n_posn, n_len

styler:StartStyling(styler.startPos, styler.lengthDoc, styler.initStyle)


while styler:More() do

cur_sym = styler:Current()

-- if we are at start of a line of code (spaces and tabs don't count)


-- - being either a start of physical line or right after ";"

if not styler:Match(" ") and not styler:Match("\t") then


compressed_line = compressed_line .. cur_sym
end

-- comments

if styler:State() == S_DEFAULT and


(compressed_line == '*' or compressed_line == '!') then
styler:SetState(S_COMMENT)
end

if styler:State() == S_DEFAULT and compressed_line == '/'


and styler:Next() == '/' then
styler:SetState(S_COMMENT)
end

-- string constants

if styler:State() == S_STRING and cur_sym == string_start then


styler:ForwardSetState(S_DEFAULT)
string_start = ''
end

if styler:State() == S_DEFAULT and


(styler:Match("'") or styler:Match('"')) then
styler:SetState(S_STRING)
string_start = cur_sym
end

if styler:State() == S_DEFAULT and styler:Match('\\') then


styler:SetState(S_STRING)
string_start = cur_sym
-- so far line continuation is highlighted the same way...
end

-- Page 339
-- line (or statement) end

if styler:AtLineEnd() or (styler:State() == S_DEFAULT


and styler:Match(';')) then
styler:SetState(S_DEFAULT) -- new line starts from default
compressed_line = ''
end

-- complex case like:


-- CRT V.STRING : \ ;* comment \
-- V.STR2

if styler:State() == S_STRING and styler:Match(';')


and string_start == '\\' then
styler:SetState(S_DEFAULT)
compressed_line = ''
string_start = ''
end

-- keywords
-- we can move only forward so we try to assemble all keyword here

if styler:State() == S_DEFAULT then

if cur_word == ''
and kw_characters:find(cur_sym, 1, true) then
cur_word = cur_sym -- new word started

while styler:More() do
styler:Forward()
cur_sym = styler:Current()

if cur_sym == '\n' or cur_sym == '\r' then


compressed_line = ''
else
-- needed for REM analysis
compressed_line = compressed_line .. cur_sym
end

if kw_characters:find(cur_sym, 1, true) then


cur_word = cur_word .. cur_sym

else -- word ended


if cur_word ~= '' then

if jbc_kw[cur_word] then
styler:ChangeState(S_KEYWORD)

elseif jbc_kw_fork[cur_word] then


styler:ChangeState(S_FORK)

elseif t24_kwords[cur_word] then


styler:ChangeState(S_T24_KWORD)

-- Page 340
elseif cur_word == 'REM'
and string.starts(compressed_line, 'REM ') then
styler:ChangeState(S_COMMENT)

elseif cur_sym == ':'


and string.gsub(compressed_line, '[A-Z,0-9,%.,:]', '') == ''
and (styler:Next() == '\n' or styler:Next() == '\r') then
styler:ChangeState(S_LABEL)

elseif tonumber(cur_word) ~= nil then


styler:ChangeState(S_NUMBER)
end

cur_word = ''
end

break

end

end

end
if styler:State() ~= S_COMMENT and styler:State() ~= S_LABEL then
styler:SetState(S_DEFAULT)
end
end

----------------------

styler:Forward()
end

styler:EndStyling()
end

-- Page 341
Result:

18.2 Compilation
jBC programs can be compiled and executed in one step. Press F5...

-- Page 342
T24 subroutines are triggered from T24 itself so they are only compiled. See the local
compilation on the next screen:

The upload to a server and compilation there is assigned to F7 key:

-- Page 343
18.3 Find all CALLs

Another part of kzm-lib.lua:

function list_all_calls()

local n_init
local n_posn
local n_line
local line
local n_eol_posn
n_init = editor.CurrentPos
editor:GotoPos(0)
print('--------- list of calls ----------')
editor:MarkerDeleteAll(1)
while true do
editor:SearchAnchor()
n_posn = editor:SearchNext(0, 'CALL ')

if n_posn == -1 then break end

if editor.StyleAt[n_posn] == 4 then
-- S_FORK doesn't work sometimes.. supposed to be global?
n_line = editor:LineFromPosition(n_posn)

if editor:MarkerGet(n_line) ~= 2 then -- already marked


line = editor:GetCurLine()
n_eol_posn = editor.LineEndPosition[n_line]
output:AppendText(n_line+1 ..': '..string.sub(line,
n_posn - n_eol_posn - 2)) -- negative (from the end)
editor:MarkerAdd(n_line, 1)
end
end

n_posn = n_posn + 1
editor:GotoPos(n_posn)

end

editor:GotoPos(n_init)

end

-- Page 344
Crtl-Alt-C:

18.4 Display contents of an insert file under the cursor


Yet another part of kzm-lib.lua:
function open_t24_insert_file()
editor:SearchAnchor()
local n_cur_posn = editor.CurrentPos
local n_posn_start = editor:SearchPrev(0, '$INSERT ')
if n_posn_start == -1 then return end
local n_line_start, n_line_cur = editor:LineFromPosition(n_posn_start),
editor:LineFromPosition(n_cur_posn)

editor:GotoPos(n_cur_posn) -- otherwise a fake selection appears


if n_line_start ~= n_line_cur then return end
local n_posn_fini_table = {}
table.insert(n_posn_fini_table, editor:SearchNext(0, ' '))
table.insert(n_posn_fini_table, editor:SearchNext(0, ';'))
table.insert(n_posn_fini_table, editor:SearchNext(0, '\n'))
table.insert(n_posn_fini_table, editor:SearchNext(0, '\r'))
table.sort(n_posn_fini_table)
editor:GotoPos(n_cur_posn) -- otherwise a fake selection appears too
local n_posn_fini = nil
for k,v in ipairs(n_posn_fini_table) do
if v ~= -1 then
n_posn_fini = v
break
end
end

-- Page 345
local n_posn_line_start = editor:PositionFromLine(n_line_start)
local cur_line = editor:GetCurLine()

if n_posn_fini == nil then -- the very end of document


n_posn_fini = -1
else
n_posn_fini = n_posn_fini - n_posn_line_start
end

local tmpfile = 'C:/home/kzm/v-t24/r11/bnk/T24_BP/'


..string.sub(cur_line, n_posn_start - n_posn_line_start+ 9, n_posn_fini)
local f = io.open(tmpfile)
if f then
local ins_line
for ins_line in f:lines() do
print(ins_line)
end
f:close()
output:GotoPos(1)
-- scite.Open(tmpfile) -- it's better to display it rather than open...
end

end

Crtl-Alt-I:

-- Page 346
18.5 Autocomplete jBC/T24 keywords

And yet another part of kzm-lib.lua:

function jbc_auto_complete()
local jbc_kw = get_jbc_kwords(1)
local jbc_kw_fork = get_jbc_kwords(2)

-- next calculation is necessary to avoid opening of "ENCRYPT" for "OPEN"


-- when a constant (2 for example above) is set
local n_start = editor:WordStartPosition(editor.CurrentPos, true)

--local all_kw = jbc_kw..jbc_kw_fork

local k,v
for k,v in pairs(jbc_kw_fork) do table.insert(jbc_kw, v) end

-- sort resulting list, otherwise we'll not find "RETURN" which is in the
-- second list
table.sort(jbc_kw)
editor:AutoCShow(editor.CurrentPos - n_start, table.concat(jbc_kw, " "))

end

Crtl-Alt-A:

-- Page 347
18.6 Code intentation
And again another part of kzm-lib.lua – see ”function cure indents()” code in the next
sub-chapter.
Let’s take an example from this book and copy/paste it to the editor (suppose pdf viewer
doesn’t preserve leading spaces while copying):

Crtl-Alt-U:

-- Page 348
Besides helping to improve the code readability, it might be useful to detect incomplete code
structures. Here END after line 27 is missing – and the code after it is shifted to the right:

18.7 Code folding


To improve code readability even further, Scite “folding” functionality can be used. For jBC
I included it into the Lua function that corrects indents. (Tried to put it into styling section
but faced several problems – like it processed only code that was visible on screen which
caused some weird results.)
One level of folding was done so far. (Intend to do more.) The code for Ctrl-Alt-U key event
that supports both indentation and folding:

-------------------------------------
function cure_indents()
-- needs setting where trailing spaces are not saved
-- BEGIN.CASE...CASE...END.CASE are on the same level to save space
-- $INSERTs start from the beginning of line
editor:BeginUndoAction()
local lines_qty = editor.LineCount
local line, n_start, n_indent, n_current, n_line_cont = '', 3, 3, 3, 6
local is_line_cont, is_comment
local is_case = false
local count, n_line
local n_fold_header, n_fold_body, n_fold_deflt = 9216, 1028, 1024
local n_fold_level = 0
local n_level_shift = 0

for n_line = 0, lines_qty do

-- Page 349
line = editor:GetLine(n_line)
if line == nil then break end
line = string.gsub(line, '\n', '')
line = string.gsub(line, '\r', '')
line = string.gsub(line, "^%s*", "")

if is_line_cont == true or string.sub(line, 1, 2) == ';*' then


editor.LineIndentation[n_line] = n_current + n_line_cont
else
editor.LineIndentation[n_line] = n_current
end

is_line_cont, is_comment = false, false

-- comments are first to check - who knows what's inside thwm?


if string.sub(line, 1, 4) == 'REM ' or string.sub(line, 1, 1) == '*'
or string.sub(line, 1, 1) == '!' or string.sub(line, 1, 2) == '//'
then
editor.LineIndentation[n_line] = 0
is_comment = true

elseif string.sub(line, 1, 8) == '$INSERT '


or string.sub(line, 1, 8) == 'INCLUDE ' or string.sub(line, 1, 1) == '#'
then
editor.LineIndentation[n_line] = 0

elseif string.sub(line, 1, 3) == 'IF '


and string.sub(line, -5) == ' THEN' then
n_current = n_current + n_indent

elseif string.sub(line, 1, 4) == 'END ' or line == 'END' then


n_current = n_current - n_indent
editor.LineIndentation[n_line] = n_current
if string.sub(line, -5) == ' ELSE'
or string.find(string.gsub(line, " ",""), 'ELSE;%*', 1) ~= nil
then
n_current = n_current + n_indent
end

elseif string.sub(line, -9) == ' ON ERROR'


or string.find(string.gsub(line, " ",""), 'ONERROR;%*', 1) ~= nil
then
n_current = n_current + n_indent

elseif string.sub(line, -7) == ' LOCKED'


or string.find(string.gsub(line, " ",""), 'LOCKED;%*', 1) ~= nil
then
n_current = n_current + n_indent

elseif string.sub(line, -5) == ' ELSE' or line == 'ELSE' then


n_current = n_current + n_indent

elseif string.sub(line, -5) == ' THEN' then -- THEN after OPENSEQ etc

-- Page 350
n_current = n_current + n_indent

elseif string.sub(line, -1) == '\\' then


_, count = string.gsub(line, "\\", "\\")
if math.mod(count, 2) ~= 0 then -- odd number so it's really line cont.
is_line_cont = true
end

elseif string.sub(line, 1, 4) == 'FOR '


or string.sub(line, 1, 4) == 'LOOP' then
n_current = n_current + n_indent

elseif string.sub(line, 1, 5) == 'NEXT '


or line == 'NEXT'
or string.sub(line, 1, 6) == 'REPEAT' then
n_current = n_current - n_indent
editor.LineIndentation[n_line] = n_current

elseif string.sub(line, 1, 6) == 'WHILE '


or string.sub(line, 1, 6) == 'UNTIL ' then
editor.LineIndentation[n_line] = n_current - n_indent
if string.sub(line, -6) == 'REPEAT'
or string.find(string.gsub(line, " ",""), 'REPEAT;%*', 1) ~= nil
then -- WHILE/REPEAT
n_current = n_current - n_indent
end

elseif string.sub(line, 1, 10) == 'BEGIN CASE' then


n_current = n_current + n_indent
is_case = true

elseif string.sub(line, 1, 8) == 'END CASE' then


n_current = n_current - n_indent
is_case = false

elseif string.sub(line, 1, 5) == 'CASE ' and is_case then


editor.LineIndentation[n_line] = n_current - n_indent

-- labels
elseif string.sub(line, -1) == ':'
and string.gsub(line, '[A-Z,0-9,%.,:]', "") == '' then
editor.LineIndentation[n_line] = 0

elseif string.find(string.gsub(line, " ",""), '%,;%*', 1) ~= nil then


is_line_cont = true

elseif string.find(string.gsub(line, " ",""), 'ELSE;%*', 1) ~= nil then


n_current = n_current + n_indent

elseif string.find(string.gsub(line, " ",""), 'THEN;%*', 1) ~= nil then


n_current = n_current + n_indent

end

-- Page 351
if is_comment == false and string.sub(line, -1) == ',' then
is_line_cont = true
end

-- get a header/footer for folding


n_level_shift = 0

if is_comment == false then


if (string.sub(line, -5) == ' THEN'
or string.find(string.gsub(line, " ",""), 'THEN;%*', 1) ~= nil
or string.sub(line, -9) == ' ON ERROR'
or string.find(string.gsub(line, " ",""), 'ONERROR;%*', 1) ~= nil
or string.sub(line, -7) == ' LOCKED'
or string.find(string.gsub(line, " ",""), 'LOCKED;%*', 1) ~= nil
or string.sub(line, -5) == ' ELSE'
or line == 'ELSE'
or string.find(string.gsub(line, " ",""), 'ELSE;%*', 1) ~= nil
or string.sub(line, 1, 4) == 'LOOP'
or string.find(string.gsub(line, " ",""), 'LOOP;%*', 1) ~= nil
or string.sub(line, 1, 4) == 'FOR '
or string.sub(line, 1, 10) == 'BEGIN CASE'
or string.find(string.gsub(line, " ",""), 'BEGINCASE;%*', 1) ~= nil)
and line ~= 'END ELSE'
and string.find(string.gsub(line, " ",""), 'ENDELSE;%*', 1) == nil
then
n_level_shift = 1
end

if line == 'END'
or string.find(string.gsub(line, " ",""), 'END;%*', 1) ~= nil
or line == 'REPEAT'
or (string.find(string.gsub(line, " ",""), 'REPEAT;%*', 1) ~= nil
and string.sub(line, 1, 7) == 'REPEAT ')
or string.sub(line, -7) == ' REPEAT'
or string.sub(line, 1, 5) == 'NEXT '
or line == 'NEXT'
or line == 'END CASE'
or string.find(string.gsub(line, " ",""), 'ENDCASE;%*', 1) ~= nil
then
n_level_shift = -1
end
end

n_fold_level = n_fold_level + n_level_shift

if n_fold_level == 1 and n_level_shift == 1 then -- fold just started


editor.FoldLevel[n_line] = n_fold_header
elseif (n_fold_level == 0 and n_level_shift == -1)
or n_fold_level >= 1
then -- fold in progress or just finished
editor.FoldLevel[n_line] = n_fold_body
else

-- Page 352
editor.FoldLevel[n_line] = n_fold_deflt
end

-- print(n_line+1, n_fold_level, editor.FoldLevel[n_line])


end
editor:EndUndoAction()
end

Screen before Ctrl-Alt-U:

-- Page 353
Screen after Ctrl-Alt-U:

Click on “-” button closes the fold:

If you like other indent size – it’s easy to set up. For example, to have initial indent of 6, the
subsequent indents of 4 and additional indentation for line continuation of 2 – change one
line in Lua function cure indents():

-- (old) local line, n_start, n_indent, n_current, n_line_cont = '', 3, 3, 3, 6


local line, n_start, n_indent, n_current, n_line_cont = '', 6, 4, 6, 2

-- Page 354
See the result:

18.8 Exec Putty


Here the modified version of PuTTY (described above in this book) is used.
Again kzm-lib.lua:

function exec_putty()
-- format env:ip:header
local line = editor:GetCurLine()
local n_posn = string.find(line, ':', 1)
if n_posn == nil then return end
local c_env = string.sub(line, 1, n_posn - 1)
line = string.sub(line, n_posn + 1)
n_posn = string.find(line, ':', 1)
if n_posn == nil then return end

local c_IP = string.sub(line, 1, n_posn - 1)


local c_header = string.sub(line, n_posn + 1)
c_header = string.gsub(c_header, '\n', '')
c_header = string.gsub(c_header, '\r', '')

os.execute('start C:/home/kzm/v-tools/putty2012.exe '


..c_IP..' -ssh -l '..c_env..' -pw '..c_env..'123'..' -z '..c_header)
end

Password for environment is “name of env123” – just for this sample only! Omit password
in command line for anything sensitive.
If you use the standard PuTTY, get rid of “-z” parameter.

-- Page 355
Step 1:

Ctrl-Alt-P:

18.9 Other things


Crtl-Alt-D: insert timestamp as a comment in format:
// Tuesday, 31 Jul 2012, 21:46:17

-- Page 356
Lua code:

function ins_time_stamp()
editor:AddText('// '..os.date('%A, %d %b %Y, %H:%M:%S'))
end

Ctrl-Q (standard key in SciTE) comments a block of selected code. Before:

After:

-- Page 357
Press Ctrl-Q once more – and code becomes uncommented again.

Also – new for edition 4:

Dark colour scheme for SciTE which looks like the title page of this book.

18.10 Settings
Here are all settings that are in my SciTEUser.properties; though not all of them are
mandatory for the described samples to work:

font.base=font:Courier,size:12
font.comment=font:Courier,size:12
font.monospace=font:Courier,size:12
font.smaller=font:Courier,size:10

check.if.already.open
save.session=1
save.recent=1

strip.trailing.spaces=1
line.margin.visible=1
view.indentation.guides=1
view.indentation.examine=3

# Page 358
fold=1
fold.compact=1
fold.flags=16
fold.symbols=3
fold.on.open=0
fold.comment=1
fold.preprocessor=1

split.vertical=1
output.initial.hide=1
output.horizontal.size=420
output.magnification=1
output.wrap=1
clear.before.execute=1

caret.fore=#FF0000
caret.width=4
caret.line.back=#FFFED8
caret.line.back.alpha=73

edge.mode=1
edge.column=80
ensure.final.line.end=1

virtual.space=3
eol.mode=LF

# opens a file open dialog in the same directory where the current file is
open.dialog.in.file.directory=1

# filters for file open dialog


open.filter=\
$(all.files)\
Source Files (jBC, Python, Lua)|*.b;*.py;*.lua|\
Text (txt, readme)|*.txt;readme;read.me| \

# after opening an insert file Crtl-Tab will bring you right back
buffers.zorder.switching=1

backspace.unindents=0

# lua startup
ext.lua.startup.script=$(SciteUserHome)/lualib/kzm-lib.lua

command.name.11.*=Fix indentation
command.11.*=cure_indents
command.subsystem.11.*=3
command.mode.11.*=savebefore:no
command.shortcut.11.*=Ctrl+Alt+U

command.name.12.*=Autocomplete jbc/T24 keywords


command.12.*=jbc_auto_complete

# Page 359
command.subsystem.12.*=3
command.mode.12.*=savebefore:no
command.shortcut.12.*=Ctrl+Alt+A

command.name.13.*=Insert timestamp
command.13.*=ins_time_stamp
command.subsystem.13.*=3
command.mode.13.*=savebefore:no
command.shortcut.13.*=Ctrl+Alt+D

command.name.14.*=Show insert file


command.14.*=open_t24_insert_file()
command.mode.14.*=savebefore:no
command.shortcut.14.*=Ctrl+Alt+I
command.subsystem.14.*=3

command.name.16.*=List all CALLs


command.16.*=list_all_calls()
command.subsystem.16.*=3
command.mode.16.*=savebefore:no
command.shortcut.16.*=Ctrl+Alt+C

command.name.18.*=Exec Putty
command.18.*=exec_putty()
command.subsystem.18.*=3
command.mode.18.*=savebefore:no
command.shortcut.18.*=Ctrl+Alt+P

############################## jBC programs (local PC)


file.patterns.jbc=*.b;
lexer.$(file.patterns.jbc)=script_b
# supports: keywords (3 kinds - jBC regular/fork, T24),
# strings, comments, labels, numbers
style.script_b.0=fore:#000000
style.script_b.1=fore:#98280C
style.script_b.2=fore:#0000FF
style.script_b.3=fore:#757877
style.script_b.4=fore:#FF0000
style.script_b.5=fore:#DF7401,bold
style.script_b.6=fore:#DF01A5
style.script_b.7=fore:#088C4B
# Ctrl-Q: comment/uncomment
comment.block.script_b=//

command.go.$(file.patterns.jbc)=$(SciteUserHome)/jbc-compile-program.cmd \
"$(FilePath)" "$(FileNameExt)" "$(FileName)"

############################## T24 subroutines (local PC)


# this is a temporary solution - add ".t24" to the end; will be stripped
# before compilation

file.patterns.t24=*.t24
lexer.$(file.patterns.t24)=script_b

# Page 360
command.go.$(file.patterns.t24)=$(SciteUserHome)/jbc-compile-t24-sub.cmd \
"$(FileNameExt)" "$(FileName)"
command.build.$(file.patterns.t24)=$(SciteUserHome)/jbc-upload-t24-sub.cmd \
"$(FilePath)" $(FileName) "$(SciteUserHome)"

CMD files to proceed with “Go” and “Build” options; jbc-compile-program.cmd:

@echo off
rem %1: file with full path
rem %2: file name and extension
rem %3: file name (for run)
set ROOT=C:\home\kzm\v-t24
copy %1 %ROOT%\r11\BATfiles
cd %ROOT%\r11\BATfiles
set TAFC_HOME=%ROOT%\r11\tafc
set JBCRELEASEDIR=%TAFC_HOME%
set PATH=%TAFC_HOME%\bin;%ROOT%\msvc\bin;%PATH%
set JBCEMULATE=prime
set INCLUDE=%ROOT%\msvc\include;%INCLUDE%
set LIB=%ROOT%\msvc\lib;%LIB%
set JBCBASETMP=%TEMP%\tmp_workfile
set JBASE_ERRMSG_DIVIDE_BY_ZERO=0
set JBASE_ERRMSG_NON_NUMERIC=0
set JBASE_ERRMSG_ZERO_USED=0
set JBCSPOOLERDIR=%ROOT%\r11\BATfiles\jspooler
jcompile -E %2
if errorlevel 1 goto error
%3
goto exitt
:error
echo "error"
:exitt

jbc-compile-t24-sub.cmd:

@echo off
rem %1 - file with full path, %2 - file name
rem (extension is .t24 - we don't need it)
set ROOT=C:\home\kzm\v-t24
set HOME=%ROOT%\r11\bnk\bnk.run
copy %1 %HOME%\ETC.BP\%2

cd %HOME%
set TAFC_HOME=%ROOT%\r11\tafc
set JBCRELEASEDIR=%TAFC_HOME%
set PATH=%TAFC_HOME%\bin;%ROOT%\msvc\bin;%PATH%
set JBCEMULATE=prime
set INCLUDE=%ROOT%\msvc\include;%INCLUDE%
set LIB=%ROOT%\msvc\lib;%LIB%
set JBCBASETMP=%TEMP%\tmp_workfile

REM Page 361


set JBASE_ERRMSG_DIVIDE_BY_ZERO=0
set JBASE_ERRMSG_NON_NUMERIC=0
set JBASE_ERRMSG_ZERO_USED=0
set JBCSPOOLERDIR=%ROOT%\r11\BATfiles\jspooler

BASIC -IT24.BP ETC.BP %2


CATALOG ETC.BP %2
goto exitt
:error
echo "error"
:exitt

jbc-upload-t24-sub.cmd (you’ll need programs winscp and plink here; amend the [PATH]
to them; also replace [USER], [PASSWORD] and [SERVER IP] to your data; last but not
least – replace KZM.BP with your BP directory name):

@echo off
rem %1 - file with full path, %2 - file name, %3 -user home
rem (extension is .t24 - we don't need it)

copy %1 %3\tmp\%2

echo option confirm off > %3\tmp\winscp.cmds


echo open [USER]:[PASSWORD]@[SERVER_IP] >> %3\tmp\winscp.cmds
echo cd KZM.BP >> %3\tmp\winscp.cmds
echo put %3\tmp\%2 >> %3\tmp\winscp.cmds
echo exit >> %3\tmp\winscp.cmds

[PATH]\WinSCP.com /script=%3\tmp\winscp.cmds

copy %3\cmd-template.conf %3\tmp\compile.cmds


echo BASIC -I../T24_BP KZM.BP %2 >> %3\tmp\compile.cmds
echo CATALOG KZM.BP %2 >> %3\tmp\compile.cmds
[PATH]\plink.exe -m %3\tmp\compile.cmds -ssh -l [USER] -pw [PASSWORD] [SERVER_IP]

File cmd-template.conf that is used in that CMD file contains settings necessary for com-
pilation, e.g.:

export HOME=$PWD
export TAFC_HOME=/usr/jbc
export PATH=/usr/vac/bin:$TAFC_HOME/bin:$HOME/bin:$PATH
export JBASE_PATH=$HOME/t24bin
export LIBPATH=$TAFC_HOME/lib:/usr/ccs/lib:/usr/lib
export JEDIFILENAME_MD=$HOME/VOC
export JEDIFILENAME_SYSTEM=$TAFC_HOME/src/SYSTEM
export JBCEMULATE=prime
export JBASE_I18N=1
export JBCOBJECTLIST=$HOME/lib:$HOME/t24lib
export JEDIENABLEQ2Q=1
export JBASE_ERRMSG_DIVIDE_BY_ZERO=0
export JBASE_ERRMSG_ZERO_USED=0

REM Page 362


export JBASE_ERRMSG_NON_NUMERIC=0
export JBCDEV_BIN=$HOME/bin
export JBCDEV_LIB=$HOME/lib
export JBCOBJECTLIST=$HOME/lib:$HOME/t24lib
export JBASE_JBCOBJECTLIST_DIR=1

19 Useful programs
Here you can find some of my tools that might be useful in everyday life (or add a little fun
to it).

19.1 Load many dynamically-prepared OFS strings to T24


In chapter “Prepare complex OFS message using SELECT...SAVING EVAL” we saw that
quite complex OFS strings might be prepared and stored in a saved LIST. In case there’s
a lot of them it wouldn’t be handy at all to copy and paste them to tSS line by line. A
short mainline subroutine was written to avoid that. This subroutine also shows a simple
but efficient logging mechanism.

REM Page 363


SUBROUTINE PASTE.OFS
* Take OFS messages from a saved LIST and proceed them.
* V.Kazimirchik, last update: Thursday, 04 Apr 2013, 22:02:32
$INSERT I_COMMON
$INSERT I_EQUATE

CALL TXTINP('Input list name or ENTER to cancel', 10, 22, '64', 'ANY')
IF COMI EQ '' THEN
TEXT = 'Cancelled' ; CALL REM ; RETURN
END
list_name = COMI
GETLIST list_name TO ofs_list SETTING total_qty ELSE
TEXT = 'List not found' ; CALL REM ; RETURN
END
TEXT = 'Found & messages. Continue?' :FM: total_qty
CALL OVE
IF TEXT NE 'Y' THEN RETURN
GOSUB INIT.LOG
LOOP
READNEXT ofs_msg FROM ofs_list ELSE BREAK
CALL OFS.GLOBUS.MANAGER('TAG', ofs_msg)
log_message = ofs_msg
log_message<-1> = '----------------------------------------------------'
GOSUB ADD.LOG.REC
REPEAT
GOSUB FINISH.LOG ; TEXT = 'Finished' ; CALL REM
RETURN
* ------------- standard logging subroutines
INIT.LOG:
log_name = 'OFS.Paste.Log.'
log_contents = 'Started at: ' : TIMEDATE()
log_lines_counter = 1
RETURN
ADD.LOG.REC:
no_of_lines = DCOUNT(log_message, @FM) ;* can use an array to speed up
log_lines_counter += no_of_lines
log_contents<-1> = log_message
IF log_lines_counter GT 10000 THEN ;* start a new log
log_contents<-1> = 'To be continued...'
GOSUB FLUSH.LOG
log_contents = '...continued at ' : TIMEDATE()
log_lines_counter = no_of_lines + 1
END
RETURN
FLUSH.LOG:
WRITELIST log_contents TO log_name : TIMESTAMP() ;* write to &SAVEDLISTS&
RETURN ;* (with unique name)
FINISH.LOG:
log_contents<-1> = 'Finished at ' : TIMEDATE() ; GOSUB FLUSH.LOG
RETURN
* ---------------------------------------------------------------------------
END

REM Page 364


To test this routine you can, for example, prepare a select list with OFS messages to delete
all unauthorised FT records (we use VALIDATE option here not to accidentally delete them,
just test the functionality):

SELECT FBNK.FUNDS.TRANSFER$NAU SAVING EVAL "'FUNDS.TRANSFER,/D/VALIDATE//0,INPUTT/123456,':@ID"


SAVE.LIST FT.NAU.DEL

Use this list name in the routine; after it finishes the contents of log file (in my case
OFS.Paste.Log.1370460034.2958) would be like:

Started at: 20:20:15 05 JUN 2013


FT11104Q2Y5L//1,TRANSACTION.TYPE:1:1=OT20,DEBIT.ACCT.NO:1:1=15393,
CURRENCY.MKT.DR:1:1=1,DEBIT.CURRENCY:1:1=GBP,DEBIT.VALUE.DATE:1:1=20110414,
CREDIT.ACCT.NO:1:1=23701,CURRENCY.MKT.CR:1:1=1,CREDIT.CURRENCY:1:1=GBP,
CREDIT.AMOUNT:1:1=200000.00,CREDIT.VALUE.DATE:1:1=20110414,
PROCESSING.DATE:1:1=20110414,COMMISSION.CODE:1:1=WAIVE,CHARGE.CODE:1:1=WAIVE,
PROFIT.CENTRE.DEPT:1:1=1,RETURN.TO.DEPT:1:1=NO,FED.FUNDS:1:1=NO,
POSITION.TYPE:1:1=TR,AMOUNT.DEBITED:1:1=GBP200000.00,
AMOUNT.CREDITED:1:1=GBP200000.00,CREDIT.COMP.CODE:1:1=GB0010001,
DEBIT.COMP.CODE:1:1=GB0010001,LOC.AMT.DEBITED:1:1=330000.00,
LOC.AMT.CREDITED:1:1=330000.00,CUST.GROUP.LEVEL:1:1=99,SEND.PAYMENT.Y.N:1:1=Y,
DR.ADVICE.REQD.Y.N:1:1=N,CR.ADVICE.REQD.Y.N:1:1=N,CHARGED.CUSTOMER:1:1=100461,
TOT.REC.COMM:1:1=0,TOT.REC.COMM.LCL:1:1=0,TOT.REC.CHG:1:1=0,
TOT.REC.CHG.LCL:1:1=0,SEND.TO.PARTY:1:1=CRCUST,BK.TO.BK.OUT:1:1=/REC/ OWN BOOK
TRANSFER,MESSAGE.TYPE:1:1=200,RATE.FIXING:1:1=NO,TOT.REC.CHG.CRCCY:1:1=0,
TOT.SND.CHG.CRCCY:1:1=0,RECORD.STATUS:1:1=INAU,CURR.NO:1:1=1,
INPUTTER:1:1=228_SUPERVISOR1__OFS_BROWSERTC,DATE.TIME:1:1=1105031150,
CO.CODE:1:1=GB0010001,DEPT.CODE:1:1=8
----------------------------------------------------
...

REM Page 365


19.2 Estimate performance of bulk data upload to T24

Assuming usage of OFS.MESSAGE.SERVICE.

PROGRAM FOMQ.COUNT3
* Counts F.OFS.MESSAGE.QUEUE at regular time intervals --------|
* and outputs the performance and estimated finish time. |
* By V.Kazimirchik, 20101222; last change 20110111. |
* 20110121, KZM: added number of running agents. |
* 2012-0405 (FOMQ.COUNT2) additional filter for FOMQ counting. |
* 2012-0711 additional '---' every 5 iterations |
* Tuesday, 17 Jul 2012, 10:20:31 KZM cleanup |
* Friday, 09 Nov 2012, 10:03:15 KZM: changed logic for number |
* of running agents. |
* Saturday, 09 Feb 2013, 12:02:29: New name (.3)
* If parameter is 'FT' or 'ft' then apply the filter automatically
* If something else - ask.
* No parameters - act as FOMQ.COUNT.
* New output format (more compact).
*--------------------------------------------------------------|

V.CNTCMD = 'COUNT F.OFS.MESSAGE.QUEUE'

first_param = DOWNCASE(SENTENCE(1))

BEGIN CASE

CASE first_param EQ '-h' OR first_param EQ '--help'


CRT ''
CRT 'Usage:'
CRT SYSTEM(40) : ' -h | --help: this help screen'
CRT SYSTEM(40) : ' FT | ft : AA disbursements mode'
CRT SYSTEM(40) : ' <anything else> : enter custom FOMQ filter'
CRT 'No parameters - just like initial FOMQ.COUNT'
STOP

CASE first_param EQ 'ft'


V.CNTCMD := ' WITH *A1 LIKE FUNDS...'

CASE first_param NE ''


CRT ''
CRT 'Filter for FOMQ [e.g.: WITH *A1 LIKE FUNDS... ; Enter-none]':
INPUT V.FILT
IF V.FILT NE '' THEN V.CNTCMD := ' ' : V.FILT

END CASE

OPEN SYSTEM(1027) TO PROC ELSE STOP 201, "PROC"

REM Page 366


CRT 'PRESS Q ANY TIME TO EXIT'
CRT 'CALCULATING...'

V.REC.QTY.SAVED = ''
V.TIME = ''
LOOP

GOSUB COUNT.Q
IF V.REC.QTY EQ 'ERROR' THEN
CRT 'SYSTEM ERROR'
STOP
END

IF V.REC.QTY EQ 0 THEN
CRT 'Upload finished'
STOP
END

IF V.TIME NE '' THEN

V.DELTA = TIME() - V.TIME


IF V.DELTA LT 0 THEN CRT 'New day!' ; V.DELTA += 86400
V.SPEED = (V.REC.QTY.SAVED - V.REC.QTY) / V.DELTA
IF V.SPEED GT 0 THEN
V.FINI.TIME = TIME() + (V.REC.QTY / V.SPEED)
V.DAYS.QTY = INT(V.FINI.TIME / 86400)

BEGIN CASE
CASE V.DAYS.QTY EQ 0
V.DAYS.OUT = 'today'

CASE V.DAYS.QTY EQ 1
V.DAYS.OUT = @(-13) : 'tomorrow' : @(-14) ;* REVERSE

CASE 1
V.DAYS.OUT = @(-13) : 'in ' : V.DAYS.QTY : ' days' : @(-14)
END CASE

V.FINI.TIME = OCONV(MOD(V.FINI.TIME, 86400), 'MTS')

V.FINI.TIME.OUTP = @(-15) : V.FINI.TIME : @(-16) ;* underline


IF V.DAYS.OUT NE 'today' THEN V.FINI.TIME.OUTP := ' (' : V.DAYS.OUT : ')'

END ELSE
* reverse output for next 2 lines
IF V.SPEED EQ 0 THEN V.FINI.TIME.OUTP = @(-13) : 'never' : @(-14)
ELSE V.FINI.TIME.OUTP = @(-13) : '??? (file is growing)' : @(-14)
END

GOSUB GET.AGENTS.QTY

REM Page 367


V.TIME = TIME()
CRT OCONV(V.TIME, 'MTS') : '->' : V.FINI.TIME.OUTP \
: ', records left: ' : V.REC.QTY \
: ', upload speed: ' : V.SPEED \
: ' rec/sec, agents' : V.AGENTS.OUT
V.REC.QTY.SAVED = V.REC.QTY

END ELSE

V.TIME = TIME()
V.REC.QTY.SAVED = V.REC.QTY

END

V.LOOP.TIME = 0
LOOP
V.BUFF = SYSTEM(14)
IF V.BUFF NE 0 THEN
V.KEY = KEYIN()
IF UPCASE(V.KEY) EQ 'Q' THEN
CRT ''
CRT 'EXITING'
STOP
END
END

MSLEEP 100
V.LOOP.TIME += 100
IF V.LOOP.TIME GE 10000 THEN BREAK
REPEAT

REPEAT

STOP

*-------------------- SUBROUTINES -------------------------------------


COUNT.Q:

EXECUTE V.CNTCMD CAPTURING V.OUTPUT

V.LINES.QTY = DCOUNT(V.OUTPUT, @FM)

V.REC.QTY = 'ERROR'
FOR V.I = 1 TO V.LINES.QTY
V.LINE = V.OUTPUT<V.I>

V.POSN = INDEX(V.LINE, 'Records counted', 1)


IF V.POSN THEN
V.REC.QTY = TRIM(V.LINE[1, V.POSN-1], ' ', 'B')
IF V.REC.QTY EQ 'No' THEN V.REC.QTY = 0
BREAK
END

REM Page 368


NEXT V.I

RETURN
*-----------------------------------------------------------------
GET.AGENTS.QTY:

V.AGENTS.QTY = 0

SELECT PROC TO SEL


LOOP
WHILE READNEXT key FROM SEL DO
READ PROCESSRECORD FROM PROC, key ELSE \
V.AGENTS.OUT = " could not be obtained"; RETURN
V.T24.LOGIN = PROCESSRECORD<28>

IF INDEX(V.T24.LOGIN, 'OFS.MESSAGE.SERVICE', 1) THEN V.AGENTS.QTY ++

REPEAT

V.AGENTS.OUT = ': ' : V.AGENTS.QTY

RETURN

*-----------------------------------------------------------------

END

Output looks like:

14:57:17->never, records left: 5519, upload speed: 0 rec/sec, agents: 21


14:57:27->18:47:14, records left: 5515, upload speed: 0.4 rec/sec, agents: 31
14:57:37->18:01:17, records left: 5510, upload speed: 0.5 rec/sec, agents: 40
14:57:47->18:47:12, records left: 5506, upload speed: 0.4 rec/sec, agents: 45
14:57:57->16:39:44, records left: 5497, upload speed: 0.9 rec/sec, agents: 45
14:58:08->16:49:56, records left: 5488, upload speed: 0.8181 rec/sec, agents: 40
14:58:18->16:08:29, records left: 5475, upload speed: 1.3 rec/sec, agents: 32

19.3 Calendar for the next 28 months


I did it in order to snap a screenshot from the output (PuTTY full screen) and to use it as
a desktop background (4:3 monitor). My week starts from Monday, keep that in mind.

REM Page 369


* Calendar to full-screen of putty

* Full screen capacity is:


* 160x63
*
* September October Nov>>>
* Mon Tue Wed Thu Fri Sat Sun Mon Tue Wed Thu Fri Sat Sun Mon Tue Wed Th>>>
* 1 2 3 4 1 2 1 2 3>>>
* 5 6 7 8 9 10 11 3 4 5 6 7 8 9 7 8 9 10>>>
* 12 13 14 15 16 17 18 10 11 12 13 14 15 16 14 15 16 17>>>
* 19 20 21 22 23 24 25 17 18 19 20 21 22 23 21 22 23 24>>>
* 26 27 28 29 30 24 25 26 27 28 29 30 28 29 30 >>>
* 31
*
*----------------------------------------------------------------------------
GOSUB INIT

V.YR = 2012
V.MTH = 5

GOSUB YEAR.START
FOR V.H = 1 TO 7
GOSUB CREATE.CAL
* add additional empty lines to improve the resulting picture
* but not too much - otherwise everything wouldn't fit
IF V.H NE 7 THEN V.DISPL<-1> = ''
NEXT V.H
GOSUB DISPL.CAL

STOP
*----------------------------------------------------------------------------
INIT:
V.DISPL = ''
V.WDAYS.LINE = ''
FOR V.I = 1 TO 4
V.WDAYS.LINE := 'Mon Tue Wed Thu Fri Sat Sun '
NEXT V.I

DIM V.DAYS.L(4)
V.DAYQTY.L = 31 :@FM: 28 :@FM: 31 :@FM: 30 :@FM: 31 :@FM: 30 :@FM: 31 \
:@FM: 31 :@FM: 30 :@FM: 31 :@FM: 30 :@FM: 31
RETURN
*----------------------------------------------------------------------------
YEAR.START:
IF OCONV(ICONV(V.YR : '1231', 'D4'), 'DJ') EQ 366 THEN V.DAYQTY.L<2> = 29
ELSE V.DAYQTY.L<2> = 28

V.DISPL<-1> = STR(' ', 55) : V.YR[1,1] : ' ' : V.YR[2,1] : ' ': V.YR[3,1] \
: ' ' : V.YR[1]
RETURN

REM Page 370


*----------------------------------------------------------------------------
CREATE.CAL:
MAT V.DAYS.L = ''
V.MTH.LINE = ''

IF V.MTH GT 12 THEN
V.MTH = 1
V.YR ++
GOSUB YEAR.START
END

FOR V.I = 1 TO 4

V.DAY.1 = V.YR : FMT(V.MTH, 'R%2') : '01'


V.M.NAME = OCONV(ICONV(V.DAY.1, 'D4'), 'DMA')

V.LEN = LEN(V.M.NAME)
V.OFF.L = INT((27 - V.LEN) / 2)
V.OFF.R = 27 - V.LEN - V.OFF.L
V.MTH.LINE := STR(' ', V.OFF.L) : V.M.NAME : STR(' ', V.OFF.R) : ' '
V.DAY1.DOW = OCONV(ICONV(V.DAY.1, 'D4'), 'DW')

V.DAY = 0
V.WEEKNO = 0
LOOP
V.WEEKNO ++
FOR V.J = 1 TO 7
V.DAY ++
IF V.DAY GT V.DAYQTY.L<V.MTH> THEN BREAK

IF V.WEEKNO EQ 1 AND V.J LT V.DAY1.DOW THEN


V.DAYS.L(V.I)<V.WEEKNO> := ' '
V.DAY --
END ELSE
V.DAYS.L(V.I)<V.WEEKNO> := FMT(FMT(V.DAY, '2R'), '4L')
END
NEXT V.J

IF V.DAY GT V.DAYQTY.L<V.MTH> THEN BREAK


REPEAT

V.MTH ++
NEXT V.I

V.DISPL<-1> = V.MTH.LINE
V.DISPL<-1> = V.WDAYS.LINE

V.WEEKS.QTY = MAXIMUM(DCOUNT(V.DAYS.L(1), @FM) \


:@FM: DCOUNT(V.DAYS.L(2), @FM) \
:@FM: DCOUNT(V.DAYS.L(3), @FM) :@FM: DCOUNT(V.DAYS.L(4), @FM))

REM Page 371


FOR V.I = 1 TO V.WEEKS.QTY
V.DISPL<-1> = FMT(V.DAYS.L(1)<V.I>, '28L') : ' ' \
: FMT(V.DAYS.L(2)<V.I>, '28L') : ' ' \
: FMT(V.DAYS.L(3)<V.I>, '28L') : ' ' : FMT(V.DAYS.L(4)<V.I>, '28L')
NEXT V.I

RETURN
*----------------------------------------------------------------------------
DISPL.CAL:
CRT @(-1)
V.QTY = DCOUNT(V.DISPL, @FM)
FOR V.I = 1 TO V.QTY
CRT STR(' ', 20) : V.DISPL<V.I>
NEXT V.I

RETURN
*----------------------------------------------------------------------------
END

Result:

REM Page 372


Another result – to use 4 months later:

By the way, these screenshots were obtained with the following Python script:

"""
Screen grabbing utility
"""
from PIL import ImageGrab
import time

time.sleep(5) # you have 5 seconds to switch to target window


ImageGrab.grab().save('screen-full.png', "PNG")

19.4 Brainf--k interpreter


It was demonstrated – part by part – in my previous book; here it is in full glory (with an
added example).

REM Page 373


PROGRAM BF.RUN
* By V.Kazimirchik, 2011-12; Brainf#$k interpreter written in jBC.
*-----------------------------------------------------------------------
DIM V.VALUES(30000)
MAT V.VALUES = 0
V.POINTER = 1

V.FILE.IN = SENTENCE(1)
IF V.FILE.IN EQ '' THEN
CRT 'Usage: BF.RUN <file>'
CRT 'See sample below (created not by me)'
CRT '(Fibonacci numbers sequence in the range from 1 to 100):'
V.SRC = '+++++++++++' \
: '>+>>>>++++++++++++++++++++++++++++++++++++++++++++' \
: '>++++++++++++++++++++++++++++++++<<<<<<[>[>>>>>>+>' \
: '+<<<<<<<-]>>>>>>>[<<<<<<<+>>>>>>>-]<[>++++++++++[-' \
: '<-[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<[>>>+<<<' \
: '-]>>[-]]<<]>>>[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]' \
: '>[<<+>>[-]]<<<<<<<]>>>>>[+++++++++++++++++++++++++' \
: '+++++++++++++++++++++++.[-]]++++++++++<[->-<]>++++' \
: '++++++++++++++++++++++++++++++++++++++++++++.[-]<<' \
: '<<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<<' \
: '[-]]<<[>>+>+<<<-]>>>[<<<+>>>-]<<[<+>-]>[<+>-]<<<-]'
CRT V.SRC
CRT ''
CRT 'is interpreted as:'
CRT ''
END

IF V.FILE.IN NE '' THEN


OSREAD V.SRC FROM V.FILE.IN ELSE
CRT 'INPUT FILE - READ ERROR'
STOP
END
END
V.VOLUME = LEN(V.SRC)

*--------------------- cache loop points


* 1 2 3 3 4 4 2 5 6
REM Page 365
* >++++++++++>>+<+[[+++++[>++++++++<-]>.<++++++[>--------<-]+<<]>.>[->[
* 17 18 24 36 46 58 62 66 69
*
*
* 7 8 9 10 11 11 12 12/10/6 13 13 5 1
* <++>-[<++>-[<++>-[<++>-[<-------->>[-]++<-[<++>-]]]]]]<[>+<-]+>>]<<]
* 77 83 89 95 107 109 114 120 127 132 136 139
*
* for left brackets populate the arrays (position to 1st, 0 to 2nd),
* for right - find the last 0 in 2nd array
* and put current position there
*-----------------------------------------------------------------------

REM Page 374


V.LEFT.BRACKETS = ''
V.RIGHT.BRACKETS = ''
V.BR.CNT = 0
V.BR.CNT.MATCH = 0

FOR V.I = 1 TO V.VOLUME


V.INSTR = V.SRC[V.I,1]
IF V.INSTR EQ '[' THEN
V.BR.CNT ++
V.LEFT.BRACKETS<V.BR.CNT> = V.I
V.RIGHT.BRACKETS<V.BR.CNT> = 0
END ELSE
IF V.INSTR EQ ']' THEN
FOR V.J = V.BR.CNT TO 1 STEP -1
IF V.RIGHT.BRACKETS<V.J> EQ 0 THEN
V.RIGHT.BRACKETS<V.J> = V.I
BREAK
END
NEXT
END
END
NEXT V.I
*-----------------------------------------------------------------------
V.CNT = 0
LOOP

V.CNT ++
IF V.CNT GT V.VOLUME THEN STOP

V.INSTR = V.SRC[V.CNT,1] ;* bf instruction


IF NOT(INDEX('.,+-<>[]', V.INSTR, 1)) THEN CONTINUE

BEGIN CASE
CASE V.INSTR EQ '>'
V.POINTER ++
IF V.POINTER GT 30000 THEN V.POINTER = 30000

CASE V.INSTR EQ '<'


V.POINTER --
IF V.POINTER LT 1 THEN V.POINTER = 1

CASE V.INSTR EQ '+'


V.VALUES(V.POINTER) ++
IF V.VALUES(V.POINTER) EQ 256 THEN V.VALUES(V.POINTER) = 0

CASE V.INSTR EQ '-'


V.VALUES(V.POINTER) --
IF V.VALUES(V.POINTER) EQ -1 THEN V.VALUES(V.POINTER) = 255

REM Page 375


CASE V.INSTR EQ '.'

V.CURR.VAL = V.VALUES(V.POINTER)
IF V.CURR.VAL GT 0 AND V.CURR.VAL LT 256 THEN CRT CHAR(V.CURR.VAL):

CASE V.INSTR EQ ','

ECHO OFF
V.KEY = KEYIN()
ECHO ON
V.VALUES(V.POINTER) = SEQ(V.KEY)

CASE V.INSTR EQ '['

IF V.VALUES(V.POINTER) NE 0 THEN CONTINUE

* find matching bracket


FIND V.CNT IN V.LEFT.BRACKETS SETTING V.POSN ELSE
CRT 'STRUCTURE ERROR AT POSITION ' : V.CNT
STOP
END

V.CNT = V.RIGHT.BRACKETS<V.POSN>
IF V.CNT EQ 0 THEN
CRT 'STRUCTURE ERROR AT POSITION ' : V.CNT
STOP
END

CASE V.INSTR EQ ']'

IF V.VALUES(V.POINTER) EQ 0 THEN CONTINUE

FIND V.CNT IN V.RIGHT.BRACKETS SETTING V.POSN ELSE


CRT 'STRUCTURE ERROR AT POSITION ' : V.CNT
STOP
END

V.CNT = V.LEFT.BRACKETS<V.POSN>

END CASE

REPEAT
STOP
END

19.5 “Fifteen” puzzle


Also from my old book; I revised it recently and compacted a little.

REM Page 376


* By V.KAZIMIRCHIK (KZM), 2007 (small corrections: Tuesday, 23 Oct 2012, 22:15)
* 15 Puzzle.
* Feel free to distribute provided that you fully retain this header.
* Author bears no responsibility if you run it during work hours :-))
*------------------------------------------------------------------------------
GOSUB INIT
LOOP

IF V.BOARD EQ V.FINI THEN


TEXT = 'YOU WIN'
PRINT TEXT
BREAK
END

V.KEY = KEYIN()
BEGIN CASE

CASE V.KEY EQ CHAR(27) ;* Esc

V.KEY.2 = KEYIN() ;* ]
V.KEY.3 = KEYIN()
FIND 0 IN V.BOARD SETTING V.ZERO.POSN ELSE
CRT 'FATAL ERROR 1'
BREAK
END

BEGIN CASE
CASE V.KEY.3 EQ 'C' AND MOD(V.ZERO.POSN, 4) NE 1 ;* right
V.POSN.ZERO.NEW = V.ZERO.POSN - 1
GOSUB SWAP.PIECES

CASE V.KEY.3 EQ 'B' AND V.ZERO.POSN GE 5 ;* down


V.POSN.ZERO.NEW = V.ZERO.POSN - 4
GOSUB SWAP.PIECES

CASE V.KEY.3 EQ 'D' AND MOD(V.ZERO.POSN, 4) NE 0 ;* left


V.POSN.ZERO.NEW = V.ZERO.POSN + 1
GOSUB SWAP.PIECES

CASE V.KEY.3 EQ 'A' AND V.ZERO.POSN LE 12 ;* up


V.POSN.ZERO.NEW = V.ZERO.POSN + 4
GOSUB SWAP.PIECES

END CASE

CASE 1
V.KEY = UPCASE(V.KEY)
IF V.KEY EQ 'Q' THEN BREAK

END CASE

REPEAT

REM Page 377


CRT @(-1)
ECHO ON
STOP

*------------------------------------------------------------------------------
SWAP.PIECES:
V.BOARD<V.ZERO.POSN> = V.BOARD<V.POSN.ZERO.NEW>
V.BOARD<V.POSN.ZERO.NEW> = 0
V.PIECE = V.POSN.ZERO.NEW
GOSUB DRAW.PIECE
V.PIECE = V.ZERO.POSN
GOSUB DRAW.PIECE
RETURN
*------------------------------------------------------------------------------
DRAW.BORDER:
FOR V.I = 4 TO 19
CRT @(22,V.I):'|':
CRT @(57,V.I):'|':
NEXT V.I
RETURN
*------------------------------------------------------------------------------
DRAW.PIECE:
V.X = MOD(V.PIECE+3, 4) * 8 + 24
V.Y = (INT((V.PIECE-1) / 4) + 1) * 4

V.NUMBER = V.BOARD<V.PIECE>
IF V.NUMBER EQ 0 THEN
CRT @(V.X+1,V.Y):' ':
CRT @(V.X,V.Y+1):' ':
CRT @(V.X,V.Y+2):' ':
CRT @(V.X,V.Y+3):' ':
END ELSE
CRT @(V.X+1,V.Y):'______':
CRT @(V.X,V.Y+1):'| |':
CRT @(V.X,V.Y+2):'| ':FMT(V.NUMBER,"2R"):' |':
CRT @(V.X,V.Y+3):'|______|':
END

CRT @(8,22):
RETURN
*------------------------------------------------------------------------------
DRAW.FIELD:
GOSUB CLEAR.FIELD
GOSUB DRAW.BORDER

FOR V.PIECE = 1 TO 16
GOSUB DRAW.PIECE
NEXT V.PIECE

CRT @(25,0):SYSTEM(40):@(-4):
CRT @(8,22):
RETURN

REM Page 378


*------------------------------------------------------------------------------
CLEAR.FIELD:
FOR V.I = 2 TO 19
IF V.I NE 3 THEN
CRT @(0, V.I):
CRT @(-4):
END
NEXT V.I
RETURN
*------------------------------------------------------------------------------
INIT:
ECHO OFF
CRT @(-1)

* Generate the field


V.BOARD = ''
V.FINI = ''
FOR V.I = 1 TO 15
LOOP
V.NUMBER = RND(15) + 1
FIND V.NUMBER IN V.BOARD SETTING V.DUMMY ELSE
V.BOARD<-1> = V.NUMBER
BREAK
END
REPEAT

V.FINI<V.I> = V.I ;* solved array for comparison


NEXT V.I
V.BOARD<16> = 0
V.FINI<16> = 0

GOSUB DRAW.FIELD
RETURN
*------------------------------------------------------------------------------
END

REM Page 379


Game screen looks like:

| ______ ______ ______ ______ |


| | || || || | |
| | 8 || 1 || 13 || 3 | |
| |______||______||______||______| |
| ______ ______ ______ ______ |
| | || || || | |
| | 2 || 10 || 5 || 7 | |
| |______||______||______||______| |
| ______ ______ ______ ______ |
| | || || || | |
| | 11 || 12 || 9 || 6 | |
| |______||______||______||______| |
| ______ ______ ______ |
| | || || | |
| | 4 || 14 || 15 | |
| |______||______||______| |

Next 2 samples – courtesy of Alexander Demin:

19.6 Program in jBC that prints its own source


Q="CRT CHAR(81):CHAR(61):CHAR(34):Q:CHAR(34):CHAR(10):Q"
CRT CHAR(81):CHAR(61):CHAR(34):Q:CHAR(34):CHAR(10):Q

REM Page 380


19.7 Dancing jBC letters
height = 24
width = 79

DIM S(24), M(24)


FOR I = 0 TO height-1
S(I) = SPACE(width)
M(I) = SPACE(width)
NEXT I

GOSUB build_gfx

time = 0

loop:

GOSUB refresh

FOR iy = 0 TO height-1
y = 2.0 * iy / height - 1.0
FOR ix = 0 TO width-1
x = 2.0 * (ix - width/2) / width

z = 0.08 * (SIN((COS(time)+x)*360) + COS((SIN(time)+y)*360))


zdiv = 2 / (1 + z)

u = x * zdiv
v = y * zdiv

iu = width/2 + INT(0.6 * u * width/2)


iv = height/2 + INT(0.6 * v * height/2)

ch = " "
IF (iu >= 0) AND (iu < width) AND (iv >= 0) AND (iv < height) THEN
ch = M(iv)[iu + 1, 1]
END
S(iy)[ix + 1, 1] = ch
NEXT
NEXT

IF SYSTEM(14) > 0 THEN STOP

time = time + 0.5

GOTO loop

STOP

refresh:
CRT @(-2)
FOR I = 0 TO 23

REM Page 381


CRT S(I):
CRT
NEXT I
RETURN

build_gfx:

M( 0) = " "
M( 1) = " "
M( 2) = " XXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXX "
M( 3) = " XXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXX "
M( 4) = " XXX XXX XXX "
M( 5) = " XXX XXX XXX "
M( 6) = " XXX XXX XXX "
M( 7) = " XXX XXX XXX "
M( 8) = " XXX XXX XXX XXX "
M( 9) = " XXX XXX XXX XXX "
M(10) = " XXX XXX XXX "
M(11) = " XXXXXXXXXXXXXXXXXXXXX XXX "
M(12) = " XXX XXXXXXXXXXXXXXXXXXXXX XXX "
M(13) = " XXX XXX XXX XXX "
M(14) = " XXX XXX XXX XXX "
M(15) = " XXX XXX XXX XXXXXX "
M(16) = " XXX XXX XXX XXXXXX "
M(17) = " XXXXXX XXXXXX XXX XXXXXX "
M(18) = " XXXXXX XXXXXX XXX XXXXXX "
M(19) = " XXXXXX XXXXXX XXX XXXXXX "
M(20) = " XXXXXX XXXXXX XXX XXXXXX "
M(21) = " XXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXX "
M(22) = " XXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXX "
M(23) = " "

RETURN

That's all folks! And now I really mean it...

REM Page 382


20 Errors in my previous publications
“This Is How Globus Works”:
http://dl.dropbox.com/u/20902365/t24/tihgw.pdf

Page 35

h hhhhh ((((
EVAL "FIELD(@ID;';',1)"
(((( hhhh "FIELD(@ID,';',1)"
((
( h

“J of Base, TAF of C”:


http://dl.dropbox.com/u/20902365/t24/JofBASEcommaTAFofC.pdf

Page 107

FOR V.I = 1 TO V.CNT


hh (
V.ID = V.BIG.L (
<V.CNT>
(h
(h h <V.I>
(
NEXT V.I

note: And the result is opposite - REMOVE is faster... sorry for misleading.

Page 130
Regarding rnd() call with parameter 1000:

* prepare an array of 1000 random numbers from 0 to 


1000
X X 999


X

cban 2011-2013 Vladimir Kazimirchik.


Written in LATEX; this is source line #20313.

REM Page 383

You might also like