-
Notifications
You must be signed in to change notification settings - Fork 0
/
piv.rex
1420 lines (1376 loc) · 60.4 KB
/
piv.rex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*REXX*****************************************************************
** **
** NAME - PIV **
** **
** TITLE - POST IMPLEMENTATION VERIFIER **
** **
** FUNCTION - This uses the SDSF REXX interface to issue commands, **
** check the response text, and set a user specified **
** return code based on the command output. **
** **
** It is meant to be used to perform a sanity check after **
** implementing a system change, but it can be used for **
** much more than that. **
** **
** It is a vast improvement over simply running SDSF in **
** batch because: **
** 1. It reduces clutter because no 3270 screen **
** renderings appear. **
** 2. You can perform some conditional logic and set **
** a step condition code accordingly. **
** **
** It supports a number of commands including those that **
** check the contents of sysout datasets or z/OS datasets,**
** display SDSF panel content, and issue z/OS console **
** commands. **
** **
** All commands must begin in column 1. If column 1 is **
** a blank then the entire line is considered to be a **
** comment and is simply copied to the output report. **
** **
** When each command is issued, the command output is **
** stored in REXX variables called `line.n` (where `n` is **
** the line number). Command output is normally printed **
** to the output report, but you can suppress (or limit) **
** this output if you wish. **
** **
** When issuing z/OS commands, you can provide an auto- **
** matic reply depending on the command response. This **
** is useful for starting system traces, for example. **
** **
** There is also a READ command which will read the **
** specified dataset into the `line.n` variables, You **
** could use this command, for example, to check that the **
** contents of a SYS1.PARMLIB member is as expected. **
** **
** The SELECT command can be used to read a job's sysout **
** into the `line.n` variables. You can then check the **
** contents of the output from a job. **
** **
** The XF and XD commands can be used to save a job's **
** sysout into either a pre-allocated DD (e.g. a Unix **
** file) or a dataset. **
** **
** SYNTAX - PIV **
** **
** OUTPUT - All output is written to DD SYSTSOUT. **
** **
** INPUT - **
**< All commands and tests are read from DD INPUT. **
** **
** The syntax rules for the input file are: **
** **
** 0. CONTINUATIONS **
** **
** A line continuation is indicated by a comma `,` as **
** the last non-blank character (i.e. the same as a **
** REXX continuation). **
** **
** 1. COMMENTS **
** **
** Lines with a blank in column 1 are treated as **
** comments and are simply printed as-is. **
** **
** 2. COMMANDS **
** **
** A line NOT beginning with a blank is a command to **
** be processed. All commands are case-insensitive. **
** The output from each command is returned in REXX **
** variables called `line.n` where n = 1 to the number **
** of lines of available output. The REXX variable **
** `line.0` contains the number of lines available. **
** **
** A command may be either: **
** **
** - HELP **
** **
** Prints this help information. **
** **
** - A z/OS command (prefixed with a `/` character): **
** **
** /zoscommand **
** **
** - REPLY msgno replytext **
** **
** If `*nn msgno ...` is found in the command output **
** then reply by issuing: **
** **
** /R nn,replytext **
** **
** - PREFIX jobname **
** **
** Filter SPOOL files by job name **
** **
** - OWNER userid **
** **
** Filter SPOOL files by owner name **
** **
** - SYSNAME sysname **
** **
** Filter SPOOL files by system name **
** **
** - DEST destname **
** **
** Filter SPOOL files by destination name **
** **
** - SORT columnnames **
** **
** Sets the SDSF column sort order **
** **
** - An SDSF primary command: **
** **
** DA, O, H, I, ST, PS, etc **
** The PREFIX, OWNER, SYSNAME and DEST filters will **
** influence the command response. **
** **
** - ? **
** **
** Lists a jobs spool datasets (when issued after **
** DA, O, H, I or ST primary command) **
** **
** - SELECT jobname [sysoutdd [step [procstep]]] **
** **
** A special command to read the sysout of the **
** specified jobname into the `line.n` variables. **
** **
** You can refine the sysout to be selected by **
** sysoutdd, step name, and proc step name. **
** **
** - USS command **
** **
** A special command to issue a Unix System Services **
** shell command to put output in `line.n` variables.**
** **
** - READ {dsn | ddname | pathname} **
** **
** A special command to read the contents of the **
** specified dataset into the `line.n` variables. **
** **
** If `dsn` contains a `.` then it is treated as a **
** fully qualified dataset name that will be **
** dynamically allocated, otherwise it is assumed to **
** be the name of a pre-allocated DD in your JCL. **
** **
** If `dsn` contains a `/` then it is treated as a **
** Unix path name. The content of the file will be **
** converted to EBCDIC (IBM-1047) if necessary. **
** **
** - SET var = value **
** **
** Sets an SDSF/REXX interface special variable. **
** **
** The list of valid variables is described in **
** "SDSF Operation and Customization" (SA23-2274) **
** in Table 180 "Special REXX Variables". **
** **
** Some useful ones (when using XD/XDC/XF/XFC) are: **
** **
** ISFPRTDDNAME Export DD name (for XF/XFC) **
** ISFPRTDSNAME Export data set name (for XD/XDC) **
** ISFPRTDISP Disposition (NEW/OLD/SHR/MOD) **
** ISFPRTBLKSIZE Default 3120 (27994 is better) **
** ISFPRTLRECL Default 240 **
** ISFPRTRECFM Default VBA **
** ISFPRTSPACETYPE Default BLKS **
** ISFPRTPRIMARY Default 500 **
** ISFPRTSECONDARY Default 500 **
** **
** - XD jobname [sysoutdd [step [procstep]] **
** XDC jobname [sysoutdd [step [procstep]] **
** **
** Export the sysout of the specified jobname to **
** the dataset specified in REXX special variable **
** ISFPRTDSNAME (see SET above). **
** **
** You can refine the sysout to be selected by **
** sysoutdd, step name, and proc step name. **
** **
** - XF jobname [sysoutdd [step [procstep]] **
** XFC jobname [sysoutdd [step [procstep]] **
** **
** Export the sysout of the specified jobname to **
** the pre-allocated DD specified in REXX special **
** variable ISFPRTDDNAME (see SET above). **
** **
** You can refine the sysout to be selected by **
** sysoutdd, step name, and proc step name. **
** **
** - SHOW ? **
** Lists the possible column names for the **
** SDSF command last issued (e.g. DA, O, etc) **
** **
** - SHOW column [column...] **
** Displays specific columns (for example, JNAME, **
** JOBID, PNAME). Use `SHOW ?` to list all the **
** valid column names that you can specify for a **
** particular ISPF panel (DA, O, ST, etc). **
** **
** - SHOW ON **
** Automatically prints command output from now on. **
** **
** - SHOW OFF **
** Suppresses printint command output from now on. **
** **
** - SHOW **
** Displays the default columns (appropriate for **
** the command last issued) or the current **
** contents of the `line.n` variables (if the **
** command last issued was READ). **
** **
** - SHOW nnn **
** Limits the acquired output to nnn lines maximum. **
** **
** - SHOW heading[,m[,n]] **
** Prints the heading text followed by lines with **
** line numbers between `m` and `n`. The **
** default is to print ALL lines. A negative number **
** is relative to the last line, so for example: **
** **
** SHOW last lines,-5 **
** **
** ...will print the heading `LAST LINES` followed **
** by the last 5 lines of output. **
** **
** - SHOW 'word [word...]' **
** Prints each output line that contains at least **
** one of the specified words. **
** **
** 3. TESTS **
** **
** There are several alternative test syntaxes that **
** you can use. Mostly, you would only use the ASSERT **
** syntax: **
** **
** a. ASSERT syntax: **
** **
** ASSERT expression **
** **
** The expression is evaluated and if true then the **
** return code is set to 0 (pass), else the return **
** code is set to 4 (fail). **
** **
** The test expression can be any expression that is **
** valid on a REXX `if` statement. For example, **
** **
** ASSERT isPresent('SOMETHING') **
** or **
** ASSERT find('SOMETHING') **
** **
** ...means: **
** **
** "Set return code 0 if the string 'SOMETHING' is **
** present in the output, else set return code 4" **
** **
** b. IF syntax: **
** **
** IF expression THEN rc = x [; ELSE ...] **
** **
** This is exactly the same syntax as the REXX `if` **
** statement. The ASSERT example above could be **
** equivalently written as: **
** if \isPresent('SOMETHING') then rc = 8 **
** ...which means **
** "If the string 'SOMETHING' is not (\) present in **
** the output then set return code 8, else set return**
** code 0" **
** **
** c. A combination of USING, and PASSIF or FAILIF: **
** **
** USING template **
** PASSIF expression **
** FAILIF expression **
** **
** This is useful if you want to check a value that **
** may vary from time to time (i.e. is not simply a **
** constant string) and therefore needs to be **
** extracted from the output and assigned to a REXX **
** variable in order to test it. **
** **
** USING sets the parsing template to be applied **
** to each line of the output. The template **
** can be anything that is valid on a REXX **
** `parse var line.n` statement, where n = 1 **
** to the number of lines of output that are **
** available to be parsed. **
** **
** PASSIF sets the return code to 0 if the REXX **
** expression on PASSIF is true, or 4 if the **
** expression is false. **
** **
** FAILIF sets the return code to 4 if the REXX **
** expression on FAILIF is true, or 0 if the **
** expression is false. **
** **
** For example, you may want to verify that spool **
** usage is acceptable by checking the output of a **
** `$DSPOOL` JES command, which may look like: **
** **
** $HASP893 VOLUME(SPOOL1) STATUS=ACTIVE,PERCENT=23 **
** $HASP646 23.6525 PERCENT SPOOL UTILIZATION **
** **
** To verify this, you could use: **
** **
** USING msgno percent . **
** PASSIF msgno = '$HASP646' & percent < 80 **
** **
** This will cause each line of the output to be **
** parsed and the first and second words of each **
** line to be assigned to the REXX variables 'msgno' **
** and 'percent' respectively. If a line is found **
** where 'msgno' is '$HASP646' and the 'percent' **
** value is less than 80, then return code 0 is set. **
** If no line containing $HASP646 is found, or the **
** percent value is more than 80, then return code **
** 4 is set. The processing of output lines stops **
** when the expression on PASSIF or FAILIF is true. **
** Alternatively, you could examine the $HASP893 **
** messages: **
** **
** USING msgno . 'PERCENT='percent . **
** PASSIF msgno = '$HASP893' & percent < 80 **
** **
** This will cause each line of the output to be **
** parsed and the message number and percent **
** value to be extracted. Processing is similar to **
** the previous example. **
** **
** The job step return code is set to the highest **
** return code (rc) set by any test. **
** **
** There are a few convenience functions in the PIV **
** REXX procedure that you can on the ASSERT, IF, **
** PASSIF and FAILIF commands if you want. **
** **
** You can of course use any of the REXX built-in **
** functions too. For example: **
** **
** subword(line.3,2) = 'HI' **
** **
** Function Returns 1 (true) when **
** ----------------------- ---------------------------- **
** find(str) str is found in any line **
** find(str[,str...]) ALL strings are on one line **
** isPresent(str) str is found in any line **
** isPresent(str,line.n) str is found in line.n **
** isAbsent(str) str is not found in any line **
** isAbsent(str,line.n) str is not found in line.n **
** isNum(str) str is an integer **
** isWhole(str) str is an integer **
** isHex(str) str is non-blank hexadecimal **
** isAlpha(str) str is alphanumeric **
** isUpper(str) str is upper case alphabetic **
** isLower(str) str is lower case alphabetic **
** isMixed(str) str is mixed case alphabetic **
** **
**> **
** EXAMPLE - //PIV EXEC PGM=IKJEFT1A,PARM='%PIV' **
** //SYSEXEC DD DISP=SHR,DSN=your.rexx.lib **
** //SYSTSIN DD DUMMY **
** //SYSTSPRT DD SYSOUT=* **
** //INPUT DD DATA,DLM='++' **
** This tests the D ETR command output **
** /D ETR **
** show **
** Mode must be STP: **
** assert word(line.4,4) = 'STP' **
** Stratum must be less than 3: **
** assert word(line.5,6) < 3 **
** ++ **
** **
** The output from the D ETR command is captured in line.n**
** variables like this: **
** line.0 = 9 (i.e. the number of returned lines) **
** line.1 = ISF031 CONSOLE xxxxxxxx ACTIVATED **
** line.2 = D ETR **
** line.3 = IEA386I hh.mm.ss TIMING STATUS nnn **
** line.4 = SYNCHRONIZATION MODE = STP **
** line.5 = THIS SERVER IS A STRATUM 2 **
** line.6 = CTN ID = yyyyyyyy **
** line.7 = THE STRATUM 1 NODE ID = nnnnn.M... **
** line.8 = THIS IS THE BACKUP TIME SERVER **
** line.9 = NUMBER OF USABLE TIMING LINKS = nn **
** **
** The above will exit with return code 4 if word 4 of **
** command output line 4 is not 'STP', and will exit with **
** return code 4 if the stratum level is not 1 or 2. **
** **
** Alternatively, you could use: **
** **
** /D ETR **
** using keyword . . mode . **
** passif keyword = 'SYNCHRONIZATION' & mode = 'STP' **
** using . . . . keyword level . **
** passif keyword = 'STRATUM' & level < 3 **
** **
** Return code 4 means FAIL, and 0 means PASS. **
** **
** **
**********************************************************************/
trace o
g. = ''
head. = ''
call Prolog
isfdelay = 5 /* Console command reply delay in seconds */
isfprtblksize = 27994 /* Block size for XD, XDC, XF and XFC */
line.0 = 0 /* Number of command response lines */
g.0TABULAR = 0 /* Indicate it is not SDSF tabular output */
g.0SEPARATOR = 1 /* A separator line is wanted */
rc = isfcalls('ON')
nMaxRC = 0
sLine = getLine()
g.0COMMENT.0 = 0
do while g.0RC = 0
parse upper var sLine c +1 0 sVerb sOp1 sOp2 . 0 . sOperands
select
/*
*------------------------------------------------------------
* Comment text
*------------------------------------------------------------
*/
when c = ' ' then do /* This is a comment */
/* Comments are accumulated and emitted (after a separator)
before the next command */
n = g.0COMMENT.0 + 1
g.0COMMENT.0 = n
g.0COMMENT.n = sLine
end
/*
*------------------------------------------------------------
* /sdsfcommand
*------------------------------------------------------------
*/
when c = '/' then do /* Issue a (slash) console command */
call emitSeparatorCommentsAndCommand sLine
g.0SEPARATOR = 1
cmd.0 = 1
cmd.1 = substr(sLine,2)
address SDSF 'ISFSLASH (cmd.) (WAIT'
drop line.
line.0 = isfulog.0
do i = 1 to isfulog.0
line.i = isfulog.i
end
g.0TABULAR = 0 /* Not SDSF tabular output */
if g.0AUTOSHOW
then call emitLines
end
/*
*------------------------------------------------------------
* SET variable '=' value
*------------------------------------------------------------
*/
when sVerb = 'SET' then do
/* Set a REXX variable (usually an SDSF REXX interface var */
call emitSeparatorCommentsAndCommand sVerb sOperands
interpret sOperands /* For example: ISFPRTDDNAME = 'LOG' */
end
/*
*------------------------------------------------------------
* IF expression THEN rc = n [; ELSE rc = m]
*------------------------------------------------------------
*/
when sVerb = 'IF' then do
/* Check the previous command output and set return code */
call emitComments
sUpperLine = translate(sLine)
nThen = pos(' THEN',sUpperLine) /* ...not bullet proof */
sIf = left(sLine,nThen) /* Extract the 'if' clause */
parse var sIf . sExpression /* Extract the 'if' expression */
interpret 'bExpression =' sExpression
rc = 0
say sLine
interpret sLine
if bExpression = 1
then sResult = '(true: rc='rc')'
else sResult = '(false: rc='rc')'
if rc = 0
then say 'Pass: ' left(sLine,80) sResult
else say 'Failed:' left(sLine,80) sResult
nMaxRC = max(nMaxRC,rc)
end
/*
*------------------------------------------------------------
* ASSERT expression
*------------------------------------------------------------
*/
when sVerb = 'ASSERT' then do
call emitComments
parse var sLine . sExpression
interpret 'bExpression =' sExpression
if bExpression = 1
then do
say 'Pass: ' left(sLine,80) '(true: rc=0)'
rc = 0
end
else do
say 'Failed:' left(sLine,80) '(false: rc=4)'
rc = 4
end
nMaxRC = max(nMaxRC,rc)
end
/*
*------------------------------------------------------------
* USING template
*------------------------------------------------------------
*/
when sVerb = 'USING' then do
call emitCommentsAndCommand sVerb sOperands
parse var sLine . g.0USING
end
/*
*------------------------------------------------------------
* PASSIF expression
*------------------------------------------------------------
*/
when sVerb = 'PASSIF' then do
/* Set return code 0 if the expression is true */
call emitComments
parse var sLine . sExpression
bExpression = 0
do i = 1 to line.0 until bExpression
interpret 'parse var line.'i g.0USING
interpret 'bExpression =' sExpression
bExpression = bExpression = 1
end
if bExpression = 1
then do
say 'Pass: ' left(sLine,80) '(true: rc=0) on line' i
rc = 0
end
else do
say 'Failed:' left(sLine,80) '(false: rc=4)'
rc = 4
end
nMaxRC = max(nMaxRC,rc)
end
/*
*------------------------------------------------------------
* FAILIF expression
*------------------------------------------------------------
*/
when sVerb = 'FAILIF' then do
/* Set return code 4 if the expression is true */
call emitComments
parse var sLine . sExpression
bExpression = 0
do i = 1 to line.0 until bExpression
interpret 'parse var line.'i g.0USING
interpret 'bExpression =' sExpression
bExpression = bExpression = 1
end
if bExpression = 1
then do
say 'Failed:' left(sLine,80) '(true: rc=4) on line' i
rc = 4
end
else do
say 'Pass: ' left(sLine,80) '(false: rc=0)'
rc = 0
end
nMaxRC = max(nMaxRC,rc)
end
/*
*------------------------------------------------------------
* REPLY msgno replytext
*------------------------------------------------------------
*/
when sVerb = 'REPLY' then do
/* Reply to a specified message number */
call emitComments
call emitCommand sVerb sOperands
parse var sOperands sMsgNo sReply
if sMsgNo <> ''
then do
bReplied = 0
do i = 1 to line.0 until bReplied
parse var line.i . . . sWTOR
sWTOR = strip(sWTOR)
if left(sWTOR,1) = '*'
then do
parse var sWTOR '*'nReply sMsgNoPrompt .
if datatype(nReply,'WHOLE') & sMsgNo = sMsgNoPrompt
then do
cmd.0 = 1
cmd.1 = 'R' nReply','strip(sReply)
address SDSF 'ISFSLASH (cmd.) (WAIT'
bReplied = 1
end
end
end
if bReplied
then do
drop line.
line.0 = isfulog.0
do i = 1 to isfulog.0
line.i = isfulog.i
end
g.0TABULAR = 0
if g.0AUTOSHOW
then call emitLines
end
end
end
/*
*------------------------------------------------------------
* PREFIX jobname
*------------------------------------------------------------
*/
when abbrev('PREFIX',sVerb,3) then do /* Filter on jobname */
call emitSeparatorCommentsAndCommand sVerb sOperands
isfprefix = sOperands
end
/*
*------------------------------------------------------------
* OWNER ownername
*------------------------------------------------------------
*/
when abbrev('OWNER',sVerb,3) then do /* Filter on owner */
call emitSeparatorCommentsAndCommand sVerb sOperands
isfowner = sOperands
end
/*
*------------------------------------------------------------
* SYSNAME systemname
*------------------------------------------------------------
*/
when abbrev('SYSNAME',sVerb,3) then do /* Filter on sysname */
call emitSeparatorCommentsAndCommand sVerb sOperands
isfsysname = sOperands
end
/*
*------------------------------------------------------------
* DEST destinationname
*------------------------------------------------------------
*/
when abbrev('DEST',sVerb,3) then do /* Filter on destination */
call emitSeparatorCommentsAndCommand sVerb sOperands
isfdest = sOperands
end
/*
*------------------------------------------------------------
* SORT columnnames
*------------------------------------------------------------
*/
when sVerb = 'SORT' then do /* Set column sort order */
call emitCommentsAndCommand sVerb sOperands
isfsort = sOperands
end
/*
*------------------------------------------------------------
* SHOW {ON | OFF | limit | ? | 'word...' | heading[,n[,m]] }
*------------------------------------------------------------
*/
when abbrev('SHOW',sVerb,2) then do
call emitComments
call emitCommand sVerb sOperands
select
when sOp1 = 'ON' then g.0AUTOSHOW = 1 /* Print output */
when sOp1 = 'OFF' then g.0AUTOSHOW = 0 /* Suppress output */
when datatype(sOp1,'WHOLE') then do /* Limit acquired lines*/
if sOp1 > 0
then g.0MAXLINES = sOp1
say ' PIV001I Acquire limit is now' g.0MAXLINES 'lines'
end
when g.0TABULAR then do /* Last was SDSF primary command */
if sOp1 = '?' /* Print gamut of column names? */
then do
/* Display the valid column names for this SDSF panel */
say 'Valid column names for' g.0CMD 'are:'
say ' ' 'Name ' 'Title '
say ' ' '------------' '-----------'
do j = 1 to g.0COLTITLE.0
sColName = g.0COLTITLE.j
sColTitle = g.0COLTITLE.sColName
say ' ' left(sColName,12) sColTitle
end
end
else call emitColumns sOperands
end
when left(sOp1,1) = "'" then do
/* Print only lines containing any of these words */
call emitHits sLine
end
otherwise do
/* Print (possibly a subset of) the output lines */
parse var sOperands sHeading','nFrom','nTo
call emitLines sHeading,nFrom,nTo
end
end
end
/*
*------------------------------------------------------------
* READ
*------------------------------------------------------------
*/
when sVerb = 'READ' then do /* Read dataset into stem `line.` */
parse var sLine . sOperands
call emitSeparatorCommentsAndCommand sVerb sOperands
g.0SEPARATOR = 1
sOperands = strip(sOperands)
select
when pos('/',sOperands) > 0 then do /* Read Unix file */
nLines = readUnixFile(sOperands)
end
when pos('.',sOperands) = 0 then do /* Read z/OS DD(s) */
do i = 1 to words(sOperands) while g.0RC = 0
sDDNAME = word(sOperands,i)
'EXECIO' g.0MAXLINES 'DISKR' sDDNAME '(FINIS STEM line.'
g.0RC = rc
end
end
otherwise do /* Read z/OS dataset */
nLines = readDataset(sOperands)
end
end
g.0TABULAR = 0 /* Indicate it is not SDSF tabular output */
if g.0AUTOSHOW
then call emitLines
end
/*
*------------------------------------------------------------
* USS unixcommand
*------------------------------------------------------------
*/
when sVerb = 'USS' then do /* Issue Unix command */
parse var sLine . sOperands
call emitSeparatorCommentsAndCommand sVerb sOperands
g.0SEPARATOR = 1
nLines = issueUnixCommand(sOperands)
g.0TABULAR = 0 /* Indicate it is not SDSF tabular output */
if g.0AUTOSHOW
then call emitLines
end
/*
*------------------------------------------------------------
* ? (list a job's sysout datasets)
*------------------------------------------------------------
*/
when sVerb = '?' then do
call emitSeparatorCommentsAndCommand sVerb sOperands
if wordpos(g.0CMD,'DA I H O ST') = 0
then do
say ' PIV003E Issue DA, I, H, O or ST before issuing "'sVerb'"'
end
else do
g.0TABULAR = 0 /* Indicate not SDSF tabular output */
/* List this job's sysout datasets using the `?` command */
address SDSF 'ISFACT' g.0CMD "TOKEN('"sToken"') PARM(NP ?)",
"PREFIX so_"
drop line.
line.0 = 0
do r = 1 to g.0ROWS
say ' ' so_JNAME.r so_JOBID.r so_DDNAME.r
end
end
end
/*
*------------------------------------------------------------
* SELECT jobname [sysoutdd [stepname [procstep]]]
*------------------------------------------------------------
*/
when abbrev('SELECT',sVerb,1) then do
/* Read job output and store it in line.n variables */
g.0SEPARATOR = 1
call emitSeparatorCommentsAndCommand sVerb sOperands
if wordpos(g.0CMD,'DA I H O ST') = 0
then do
say ' PIV003E Issue DA, I, H, O or ST before issuing "'sVerb'"'
end
else do
g.0TABULAR = 0 /* Indicate it is not SDSF tabular output */
drop head.
head. = ''
parse var sOperands sJobName sSysoutDD sStepName sProcStep
if sJobName = '' then sJobName = JNAME.1
drop line.
line.0 = 0
do r = 1 to g.0ROWS
if JNAME.r = sJobName
then do
call readJobOutput TOKEN.r,JNAME.r,JOBID.r,,
sSysoutDD,sStepName,sProcStep
end
end
end
end
/*
*------------------------------------------------------------
* XF jobname [sysoutdd [stepname [procstep]]]
* XFC jobname [sysoutdd [stepname [procstep]]]
* XD jobname [sysoutdd [stepname [procstep]]]
* XDC jobname [sysoutdd [stepname [procstep]]]
*------------------------------------------------------------
*/
when wordpos(sVerb,'XF XFC XD XDC') > 0 then do
/* XF will export the job output to a pre-allocated DD name */
/* XFC same as XF but will Close the output DD afterwards */
/* XD will export the job output to a dataset */
/* XDC same as XD but will Close the output dataset afterwards */
call emitCommentsAndCommand sVerb sOperands
g.0SEPARATOR = 1
if wordpos(g.0CMD,'DA I H O ST') = 0
then do
say ' PIV003E Issue DA, I, H, O or ST before issuing "'sVerb'"'
end
else do
g.0TABULAR = 0 /* Indicate it is not SDSF tabular output */
parse var sOperands sJobName sSysoutDD sStepName sProcStep
drop line.
line.0 = 0
if sJobName = '' /* If no filter, export all job output */
then do
do r = 1 to g.0ROWS
say ' PIV002I Exporting all sysout for job' JNAME.r
call exportAllOutput TOKEN.r
end
end
else do /* Export sysout datasets matching the filter */
do r = 1 to g.0ROWS
if JNAME.r = sJobName
then do
say ' PIV002I Exporting filtered sysout for job',
JNAME.r
call exportJobOutput TOKEN.r,JNAME.r,JOBID.r,,
sSysoutDD,sStepName,sProcStep
end
end
end
end
end
/*
*------------------------------------------------------------
* HELP
*------------------------------------------------------------
*/
when sVerb = 'HELP' then do
call emitSeparatorCommentsAndCommand sVerb sOperands
g.0SEPARATOR = 1
do i = 1 until left(sourceline(i),3) = '**<'
end
do i = i until sEOD = '**>'
parse value sourceline(i) with 1 sEOD +3 15 sHelp 69 .
say ' ' sHelp
end
end
/*
*------------------------------------------------------------
* Issue an SDSF primary command (DA, H, I, etc)
*------------------------------------------------------------
*/
otherwise do
call emitSeparatorCommentsAndCommand sVerb sOperands
g.0SEPARATOR = 1
isfcols = ''
g.0CMD = sVerb /* Remember SDSF primary command for later */
address SDSF "ISFEXEC '"sLine"'(DELAYED"
if rc <> 0
then do /* Display error messages if the command failed */
nMaxRC = max(nMaxRC,rc)
do i = 1 to isfmsg2.0
say isfmsg2.i
end
end
else do /* Display title line */
g.0TABULAR = 1 /* Indicate SDSF tabular output */
isfsort = '' /* Reset column sort */
g.0ISFTLINE = isftline
g.0ISFDISPLAY = isfdisplay
g.0ISFTITLES = isftitles
/* Save column names and titles for later */
nColumns = words(isfcols)
/* Hack due to ' ID' being present... */
if word(isftitles,1) = "'"
then isftitles = subword(isftitles,2)
drop width.
width. = 0
rj. = 1
width.0 = nColumns
g.0COLTITLE.0 = nColumns
do c = 1 to g.0COLTITLE.0
sColName = word(isfcols,c)
sColTitle = strip(word(isftitles,c),'BOTH',"'")
g.0COLTITLE.sColName = sColTitle
g.0COLTITLE.c = sColName
width.sColName = length(sColTitle)
end
/* Save command output, if any, in `line.` stem variables */
drop line.
drop colname.
g.0ROWS = isfrows
line.0 = isfrows
colname.0 = nColumns
do r = 1 to line.0
line.r = ''
do c = 1 to nColumns
sColName = word(isfcols,c)
colname.c = sColName
sColValue = value(sColName'.'r)
if sColValue = '' then sColValue = '.'
line.r = line.r sColValue
width.sColName = max(width.sColName,length(sColValue))
rj.sColName = rj.sColName & datatype(sColValue,'NUM')
end
line.r = substr(line.r,2)
end
if g.0AUTOSHOW
then call emitColumns
end
end
end
sLine = getLine()
end
call Epilog
exit nMaxRC
Epilog:
rc = isfcalls('OFF')
say
say copies('-',130)
say
if nMaxRC = 0
then say 'Result: PIV successful'
else say 'Result: PIV failed with maxrc='nMaxRC
say
return
readJobOutput:
parse arg sToken,sJob,sJobId,sSysoutDD,sStepName,sProcStep
/* List this job's sysout datasets using the `?` SDSF line command */
address SDSF 'ISFACT' g.0CMD "TOKEN('"sToken"') PARM(NP ?)",
"(PREFIX so_"
line.0 = 0
nMaxLines = g.0MAXLINES
/* Read one or more sysout datasets into `line.n` variables */
do j = 1 to so_ddname.0 while line.0 < g.0MAXLINES
if isMatch(sSysoutDD,so_ddname.j),
& isMatch(sStepName,so_stepn.j),
& isMatch(sProcStep,so_procs.j)
then do
/* Allocate the specified sysout dataset using the SA command */
address SDSF 'ISFACT' g.0CMD "TOKEN('"so_token.j"') PARM(NP SA)"
/* Append a header that identifies the output being acquired */
n = line.0 + 1
head.n = 'JOB='left(sJob,8),
'JOBID='left(sJobId,8),
'DD='left(so_ddname.j,8),
'PROCSTEP='left(so_procs.j,8),
'DSID='left(so_dsid,j,8)
/* Read the sysout dataset contents (until limit reached) */
'EXECIO' nMaxLines 'DISKR' isfddname.1 '(FINIS STEM read.'
nMaxLines = nMaxLines - read.0
/* Append the acquired output to the `line.n` variables */
do k = 1 to read.0
call appendLine read.k
end
end
end
/* If user specified SHOW ON, then automatically display the lines */
if g.0AUTOSHOW
then call emitLines
return
exportAllOutput:
parse arg sToken
/* Export all of this job's sysout datasets */
address SDSF 'ISFACT' g.0CMD "TOKEN('"sToken"') PARM(NP" sVerb")"
isfprtdisp = 'MOD' /* Append subsequent sysout datasets */
/* If user specified SHOW ON, then automatically display the lines */
if g.0AUTOSHOW
then call emitLines
return
exportJobOutput:
parse arg sToken,sJob,sJobId,sSysoutDD,sStepName,sProcStep
/* List this job's sysout datasets using the `?` SDSF line command */
address SDSF 'ISFACT' g.0CMD "TOKEN('"sToken"') PARM(NP ?)",
"(PREFIX so_"
line.0 = 0
/* Read one or more sysout datasets into `line.n` variables */
do j = 1 to so_ddname.0
if isMatch(sSysoutDD,so_ddname.j),
& isMatch(sStepName,so_stepn.j),
& isMatch(sProcStep,so_procs.j)
then do
/* Export the specified sysout dataset using the Xxx SDSF */
/* line command. The ISFPRTxxxxxx variables must be set first */