PSCAN1, PSCAN2, and?

Feeling not so bright, I wrote a couple more programs.  Again, like everything else lately, file scan programs.  If you're NOT an old IBM programmer, maybe some background is in order.  When I punch cards (okay, maybe that far back) or type stuff on my terminal, I can create a program I want to run, and then create the control cards (yeah we old guys still call 'em cards) to assemble, or compile the program and then run it.  Those control cards are called JCL,  or Job Control Language.  We'll do one example of JCL to run a program after it's been compiled.
 
//RUNIT     EXEC  PGM=PSCAN2,PARM='MVC,Z390,WHATEVER'
//STEPLIB   DD  DISP=SHR,DSN=
//SYSPRINT  DD  SYSOUT=*

//IN        DD  DISP=SHR,DSN=MY.LISTING

//OUT       DD  SYSOUT=*

 
Notes:
RUNIT  EXEC tells the system to run the  PGM= program.  PARM= provides some data I want to use.

STEPLIB  is the run library where the program is stored.

SYSPRINT  is the traditional name for a print file.  (SYSOUT is also used.)

DISP=SHR  indicates that the file exists.  For a new file, you'd code  DISP=(NEW,CATLG)   catlg puts it in an index.
IN  is the file I'm going to read,  in this case a listing of my program.

OUT  is the file I'm going to write.

SYSOUT=*  means that the file will be written to paper, or my terminal.

  

I use the Z390 simulator for testing.  It's a 'pretend operating system' that allows me to assemble and execute what I've written.  It's really pretty amazing.

In the olden days, there were programs to read files and copy selected records.  I assume they still do that, but it's been 20+ years since I've been in a data center.  In any case, it's a task I like doing -- writing a program that can select records based on the content of those records, and copy them to output files.  I'm working on one that I've long thought about, but this week I needed a break, because I didn't feel up to the task of that program.  SO, I wrote 2 programs, PSCAN1 and PSCAN2.  They both read a file and copy selected records that contain the character strings I specify in the PARM field.  (see above.)  


Maybe it's time for a bit of philosophy:
1) In any scan, the object is to minimize the number of string compares.  Those are what takes time.
2) You can scan for a single thing, or for several different things.  When it's 1 thing, you just look.  But when you're looking for various different things, there is another problem:
2a) Are you looking through the entire record, or
2b) Are you looking at different places for different things.


Both of these programs look through the entire record for 1 single, or several different, things. The main idea is that the area being scanned is the same for all of them.  There is an IBM instruction that makes that, not only possible, but fairly easy.  That's what I use.  In both these cases, I scan the entire record looking for all the requested strings at the same time. 

 
PSCAN1  uses the first character of a string to find possible strings in the file, and when a valid first character is found, it then tests to see if the entire string follows.  That is far faster than checking the entire string against every character in the file.  When doing this, you don't want to start your string with a blank, because there are lots of them, and it'd run slow.  (Besides, it won't let you.)  I've tested it, and it runs fine.

 
PSCAN2  is similar, but rather than look for the first character, it first scans each string, (there can be several) and tries to pick the character in that string that occurs in normal text, least frequently.  By doing that, we're able to do fewer longer compares.  And, for example, if you look for  "EQUAL",  there are way fewer  "Q"s in normal text than  "E"s, so the program runs faster.
 
PSCAN1 took me about a day to write, and is about 100 statements.
PSCAN2 took me nearly a week, with lots of stupid mistakes, and is about 400 statements.  (Seemed longer than that with all the gnashing of teeth over some really dumb mistakes.)  BUT, I did find a nice character frequency table in Wikipedia, that I used, and also saved elsewhere.

 

For PSCAN1, the report if pretty minimal.  PSCAN2 is more verbose:
Following the 2 sample reports is the code for both programs.
It's written to run on Z390, and the DCB's would need to be changed for MVS.


 PSCAN1, ASM 06/24/23 20.12, PARM= USING,LM,STM,MVC,MVI,ABEND,FIX


 ABEND 1 = NO PARM FIELD.

 ABEND 2 = SEARCH STRING IMPOSSIBLY LONG

 ABEND 3 = SEARCH STRING LENGTH=0

 ABEND 4 = SEARCH STRING LONGER THAN 29

 ABEND 5 = TOO MANY SEARCH ARGS. 15=MAX


          421  RECORDS READ

           42  RECORDS WRITTEN

           03  USING

           01  LM

           01  STM

           11  MVC

           02  MVI

           24  ABEND

           00  FIX



 

 PSCAN2, ASM 06/24/23 19.18 PARM= USING,PUSH,POP,PRINT,MVC,LM,STM,TRT,MVI,Z390,EQU   1,EQU   2,ABEND,QUICK

 READ A FILE, COPY RECORDS WITH STRINGS SPECIFIED IN THE PARM FIELD.

 READ //IN, LOOK FOR STRINGS SPECIFIED IN PARM FIELD,

 COPY THOSE RECORDS TO //OUT

 CANNOT HAVE A COMMA IN A STRING. MAX STRING LENGTH=32

 CAN HAVE UP TO 15 STRINGS.  IN THE PARM= FIELD.

 CAN GET AWAY WITH A COUPLE SPACES. EG, IN A LISTING:

 // EXEC PGM=PSCAN2,PARM="MVC,STM,EQU   2"

 //SYSPRINT DD SYSOUT=*

 //IN DD DISP=SHR,DSN=

 //OUT DD SYSOUT=*

 IF THERE ARE 2 STRINGS IN A REC, THE 2ND IS NOT COUNTED.


 # RECORDS

 |     BYTES BEFORE SCAN BYTE (IE SCAN CHAR OFFSET)

 |     |     STRING LENGTH-1

 |     |     |     BYTES FROM SCAN CHAR TO END

 |     |     |     |       SCAN CHAR

 |     |     |     |       | |-STRING--


 00000 00004 00004 00001   G USING

 00000 00000 00003 00004   P PUSH

 00000 00000 00002 00003   P POP

 00000 00000 00004 00005   P PRINT

 00000 00001 00002 00002   V MVC

 00000 00001 00001 00001   M LM

 00000 00002 00002 00001   M STM

 00000 00001 00002 00002   R TRT

 00000 00001 00002 00002   V MVI

 00000 00000 00003 00004   Z Z390

 00000 00001 00006 00006   Q EQU   1

 00000 00001 00006 00006   Q EQU   2

 00000 00001 00004 00004   B ABEND

 00000 00000 00004 00005   Q QUICK


 -------- AFTER BUBBLING --------

 00000 00001 00004 00004   B ABEND

 00000 00004 00004 00001   G USING

 00000 00001 00001 00001   M LM

 00000 00002 00002 00001   M STM

 00000 00000 00002 00003   P POP

 00000 00000 00004 00005   P PRINT

 00000 00000 00003 00004   P PUSH

 00000 00001 00006 00006   Q EQU   1

 00000 00001 00006 00006   Q EQU   2

 00000 00000 00004 00005   Q QUICK

 00000 00001 00002 00002   R TRT

 00000 00001 00002 00002   V MVC

 00000 00001 00002 00002   V MVI

 00000 00000 00003 00004   Z Z390


          658  RECORDS READ

          124  RECORDS WRITTEN

           18  ABEND

            1  USING

            4  LM

            4  STM

            2  POP

           23  PRINT

            2  PUSH

            7  EQU   1

            1  EQU   2

            0  QUICK

           19  TRT

           22  MVC

            1  MVI

           20  Z390

------------ Source code for PSCAN1 --------------------------- 

         AGO   .START

I USE THIS STUFF IN Z390 TESTING.


C:\USERS\LIN\DOCUMENTS\Z390CODE\PSCAN1


SET   PA="USING,DROP,LM,STM,END,WHATEVER"

SET    G=C:\USERS\LIN\DOCUMENTS\Z390CODE\PSCAN1

SET   IN=C:\USERS\LIN\DOCUMENTS\BUSHSTUFF.TXT

SET  OUT=%G%.OUT.TXT

BAT\ASMLG %G%.MLC TIME(1) PARM(%PA%)


.START   ANOP

* ------------------- SET UP, SAVE PARM AND SCAN PARMS ---------

PSCAN1   START 0

         YREGS

         USING *,13             ABEND 1 = NO PARM FIELD.

         B     72(R15)          ABEND 2 = SEARCH STRING IMPOSSIBLY LONG

         DC   17F'0'            ABEND 3 = SEARCH STRING LENGTH=0

         STM   14,12,12(13)     ABEND 4 = SEARCH STRING LONGER THAN 29

         ST    13,4(15)         ABEND 5 = TOO MANY SEARCH ARGS. 15=MAX

         ST    15,8(13)

         LR    13,15

         L     R2,0(R1)

         LH    R3,0(R2)

         SH    R3,=H'1'       WE HW LENGTH-1 AND SEARCH ARG

         LA    R4,TABLE       FOR EACH ARG.

         SR    R6,R6            R6 = MAX ARG LENGTH

         SR    R7,R7            R7 = ARE #

         BNM   SAVPARM          SO WE ONLY CLC STRINGS AT OR AFTER IT.

         LA    R5,1           ABEND # 1 = NO PARM

ABEND    ABEND (5)

         MVC   PARM(0),2(R2)

SAVPARM  EX    R3,*-6         MOVE PARM TO W/A

         PUSH  PRINT

         PRINT NOGEN

OPEN     OPEN  (IN,INPUT,OUT,OUTPUT,SYSPRINT,OUTPUT)  OPEN FILES

         POP   PRINT

         PUT   SYSPRINT,PARM-7

         SR    R0,R0

SAVPARML LA    R5,2

         TRT   PARM,FINDEND

         BZ    ABEND

         LA    R5,3

         LA    R2,0(R1)       CALC LENGTH-1 OF ARG

         S     R2,=A(PARM+1)

         BNP   ABEND          LENGTH=NEG, ERROR

         LA    R5,4                Q. ARG LONGER THAN 29?

         CH    R2,=AL2(L'TABLE-3)     YES, ABEND

         BNL   ABEND

         LA    R7,1(R7)            COUNT ARG

         LA    R5,5

         CLI   0(R4),C' '          Q. TABLE OVERFLOW?

         BNE   ABEND                   YES,  "WHY THAT MANY???"

         MVC   6(0,R4),PARM        MOVE ARE TO TABLE

         EX    R2,*-6

         STH   R2,4(R4)            STORE LENGTH-1

         ST    R0,0(R4)

         LA    R4,L'TABLE(R4)      BUMP TABLE INDEX

         CR    R6,R2               Q. LONGEST ARG SO FAR?

         BL    *+6                    NO.

         LR    R6,R2                  YES, SAVE IT.

         SR    R14,R14

         IC    R14,PARM            LOAD FIRST CHAR OF STRING

         LA    R14,TRTABLE(R14)    CALC OFFXET IN TRT TABLE

         CLI   0(R14),0            Q. FIRST TIME THIS CHAR?

         BNE   *+8                    NO, DON'T STORE

         STC   R7,0(R14)           YES, STORE INDEX

         MVC   PARM,1(R1)          MVC NEXT ARG TO BEG OF PARM

         CLI   PARM,C' '           Q. END OF ARGS?

         BNE   SAVPARML               NO, LOOP

         MVI   0(R4),X'FF'            YES, SET END FLAG

         LA    R6,1(R6)               CALC MAX LENGTH

         LA    R7,255                 ONLY TRT 255 BYTES AT A TIME

         SR    R8,R8

         SR    R9,R9

         B     GET                    GO READ.

* ------------------- READY, LETS READ, TEST, AND WRITE --------

         DC    F'0'                REC ADDR

PUT      LA    R0,1

         A     R0,0(R4)

         ST    R0,0(R4)

         L     R0,PUT-4            LOAD REC ADDR

         PUT   OUT,(0)             WRITE IT

         LA    R9,1(R9)

*

GET      GET   IN                  READ A REC

         LA    R8,1(R8)

         LA    R3,0(R1)            SAVE IT'S ADDR

         ST    R3,PUT-4            TWICE, JUST TO BE SURE.

         LH    R5,DCBLRECL-IHADCB+IN    LOAD LRECL

         LA    R5,0(R3,R5)           R3=REC ADDR

         SR    R5,R6                 R5=LAST USEABLE LOC

         LR    R1,R3                 -LENGTH OF LONGEST = END

TRTLOOP  LR    R2,R5               END

         SR    R2,R1               - START / CURRENT = LENGTH

         CR    R2,R7               Q. LONGER THAN 255

         BL    SHORT                  NO, JUST GO TEST SHORT

*

         TRT   0(255,R1),TRTABLE   TEST 255 BYTES

         BNZ   CHECK               A FIRST CHAR COUNT, GO CLC

         LA    R1,255(R1)          NOT FOUND, BUMP

         B     TRTLOOP             AND LOOP

*

         TRT   0(0,R1),TRTABLE

SHORT    EX    R2,SHORT-6          TEST SHORT

         BZ    GET                 NOT FOUND, JUST GO READ

         B     CHECK               YES,  GO DO  CLC'S

*

CLC      CLC   0(0,R1),6(R4)

CHECK    LA    R4,TABLE            POINT TO ARG TABLE

         N     R2,=F'31'           R2 = INDEX INTO ARG TABLE

         BCTR  R2,0                  START WITH 0, NOT 1

         SLL   R2,5                  MULT BY 32

         LA    R4,0(R2,R4)           CALC ARG TABLE ENTRY LOC

CHECKLH  LH    R15,4(R4)           LOAD ENTRY LENGTH

         EX    R15,CLC          Q. DOES THIS ENTRY MATCH?

         BE    PUT                 YEAH, GO WRITE

         LA    R4,L'TABLE(R4)      NO, BUMP TO NEXT

         CLI   0(R4),99         Q. END OF ARG TABLE?

         BL    CHECKLH             NO, TRY NEXT

         LA    R1,1(R1)            POINT TO NEXT BYTE

         CR    R1,R5            Q. END OF RECORD

         BNH   TRTLOOP             NO, GO TEST

         B     GET                 YES, GO READ.

* ---------------------- ALL DONE, CLOSE FILES AND EXIT -------

EDIT9    DC    X'402020206B2020206B212020'

Z        LA    R4,TABLE-64

         MVC   PARM,PARM-1

         ST    R8,#READ

         ST    R9,#WRITTEN

TOTALS   L     R0,0(R4)

         CVD   R0,16(R13)

         MVC   PARM(L'EDIT9),EDIT9

         ED    PARM(L'EDIT9),19(R13)

         LH    R1,4(R4)

         MVC   PARM+L'EDIT9+2(0),6(R4)

         EX    R1,*-6

         PUT   SYSPRINT,PARM-1

         MVC   PARM,PARM-1

         LA    R4,L'TABLE(R4)

         CLI   0(R4),99

         BL    TOTALS

         CLOSE (IN,,OUT,,SYSPRINT)

         L     13,4(13)

         LM    14,12,12(13)

         SR    R15,R15

         BR    14

         LTORG

         PUSH  PRINT

         PRINT NOGEN

IN       DCB   DDNAME=IN,DSORG=PS,EODAD=Z,MACRF=GL,LRECL=3990,RECFM=FT

OUT      DCB   DDNAME=OUT,DSORG=PS,LRECL=133,RECFM=FT,MACRF=PM,

SYSPRINT DCB   DDNAME=SYSPRINT,DSORG=PS,LRECL=133,RECFM=FT,MACRF=PM

         POP   PRINT

*

         DC    C' PARM='

         DC    C' '

PARM     DC    CL101' ',CL33' '

TRTABLE  DC    XL256'00'

#READ    DC    F'0',HL2'17',CL26'RECORDS READ'

#WRITTEN DC    F'0',HL2'17',CL26'RECORDS WRITTEN'

TABLE    DC    16CL32' ',X'FF'

FINDEND  DC    64X'00',C' ',191X'00'

         ORG   FINDEND+C','

         DC    C','

         ORG

*

*        DCBD  DEVD=DA

*

@@PAD#1  EQU   ((*-PSCAN1)/4096+1)*4096

@@PAD#2  EQU   @@PAD#1-(*-PSCAN1)

         ORG   *+@@PAD#2

*

         END   PSCAN1

 

----------------------  Source code for PSCAN2  -------------

 

         AGO   .START

I USE THIS STUFF IN Z390 TESTING.


C:\USERS\LIN\DOCUMENTS\Z390CODE\PSCAN2


SET   PA="USING,DROP,LM,STM,END,WHATEVER"

SET    G=C:\USERS\LIN\DOCUMENTS\Z390CODE\PSCAN2

SET   IN=C:\USERS\LIN\DOCUMENTS\BUSHSTUFF.TXT

SET  OUT=%G%.OUT.TXT

BAT\ASMLG %G%.MLC TIME(1) PARM(%PA%)


.START   ANOP

* ---------------------------------------

         MACRO

&LBL     @        &MSG

         LCLA  &L

&L       SETA  (K'&MSG-3)

&LBL     DC    AL1(&L),C&MSG

         MEND

* ---------------------------------------

* ------------------- SET UP, SAVE PARM AND SCAN PARMS ---------

PSCAN2   START 0

         YREGS

         USING *,13             ABEND 1 = NO PARM FIELD.

*        B     72(R15)          ABEND 2 = SEARCH STRING IMPOSSIBLY LONG

*        DC   17F'0'            ABEND 3 = SEARCH STRING LENGTH=0

         STM   14,12,12(13)     ABEND 4 = SEARCH STRING LONGER THAN 29

         ST    13,4(15)         ABEND 5 = TOO MANY SEARCH ARGS. 15=MAX

         ST    15,8(13)         ABEND 6 = BLANKS IN STRING

         LA    13,0(15)         ABEND 7 = SEARCH STRING START=BLANKS

         SR    14,14

         L     R2,0(R1)

         LH    R3,0(R2)

         SH    R3,=H'1'       WE HW LENGTH-1 AND SEARCH ARG

         LA    R4,TABLE       FOR EACH ARG.

         ST    R4,ATABLE

         SR    R6,R6            R6 = MAX ARG LENGTH

         SR    R7,R7            R7 = ARE #

         BNM   SAVPARM          SO WE ONLY CLC STRINGS AT OR AFTER IT.

         LA    R5,1           ABEND # 1 = NO PARM

         B     ABEND

         MVC   PARM(0),2(R2)

SAVPARM  EX    R3,*-6         MOVE PARM TO W/A

         PUSH  PRINT

         PRINT NOGEN

OPEN     OPEN  (IN,INPUT,OUT,OUTPUT,SYSPRINT,OUTPUT)  OPEN FILES

         POP   PRINT

         PUT   SYSPRINT,PARMPRT

         LA    R11,TRTABLE

         B     PUTLINE

*

ABEND    ABEND (5)

*

         MVC   LINE(0),1(R11)

MOVEDOC  IC    R7,0(R11)

         EX    R7,MOVEDOC-6

         LA    R11,2(R11,R7)

PUTLINE  PUT   SYSPRINT,LINE-1

         MVC   LINE,LINE-1

         CLI   0(R11),64

         BL    MOVEDOC

         PUT   SYSPRINT,LINE-1

         SR    R7,R7

         SR    R0,R0

SAVPARML LA    R5,7

         CLC   PARM(2),PARM+101

         BE    ABEND

         LA    R5,2

         TRT   PARM,FINDEND

         BZ    ABEND

TESTSPA  CLI   0(R1),C','

         BE    TESTLEN

         CLC   0(11,R1),PARM+99

         BE    TESTLEN

         TRT   1(33,R1),FINDEND

         B     TESTSPA

TESTLEN  LA    R5,3

         LA    R2,0(R1)       CALC LENGTH-1 OF ARG

         S     R2,=A(PARM+1)

         BNP   ABEND          LENGTH=NEG, ERROR

         LA    R5,4                Q. ARG LONGER THAN 29?

         CH    R2,=AL2(LTABLE-14)     YES, ABEND

         BNL   ABEND

         LA    R7,1(R7)            COUNT ARG

         LA    R5,5

         CLI   0(R4),C' '          Q. TABLE OVERFLOW?

         BNE   ABEND                   YES,  "WHY THAT MANY???"

         XC    0(12,R4),0(R4)

         MVC   12(0,R4),PARM        MOVE ARE TO TABLE

         EX    R2,*-6

         STH   R2,10(R4)            STORE LENGTH-1

         STH   R2,6(R4)

         LA    R4,LTABLE(R4)       BUMP TABLE INDEX

*          CR    R6,R2               Q. LONGEST ARG SO FAR?

*          BL    *+6                    NO.

*          LR    R6,R2                  YES, SAVE IT.

*          SR    R14,R14

*          IC    R14,PARM            LOAD FIRST CHAR OF STRING

*          LA    R14,TRTABLE(R14)    CALC OFFXET IN TRT TABLE

*          CLI   0(R14),0            Q. FIRST TIME THIS CHAR?

*          BNE   *+8                    NO, DON'T STORE

*          STC   R7,0(R14)(         YES, STORE INDEX

         MVC   PARM,1(R1)          MVC NEXT ARG TO BEG OF PARM

         CLI   PARM,C' '           Q. END OF ARGS?

         BNE   SAVPARML               NO, LOOP

         LA    R5,6

         CLC   PARM(44),PARM+45

         BNE   ABEND

         MVI   0(R4),X'FF'            YES, SET END FLAG

         ST    R4,ATABLE+4

*

         BAL   R14,QFREQ

         BAL   R14,LIST

         BAL   R14,BUBBLE

         MVC   LINE(35),=CL35'-------- AFTER BUBBLING --------'

         PUT   SYSPRINT,LINE-1

         MVC   LINE,LINE-1

         BAL   R14,LIST

*

SETUP    LA    R6,1(R6)               CALC MAX LENGTH

         LA    R7,255                 ONLY TRT 255 BYTES AT A TIME

         SR    R8,R8

         SR    R9,R9

         B     GET                    GO READ.

* ------------------- READY, LETS READ, TEST, AND WRITE --------

         DC    F'0'                REC ADDR

PUT      LA    R0,1

         A     R0,0(R4)

         ST    R0,0(R4)

         L     R0,PUT-4            LOAD REC ADDR

         PUT   OUT,(0)             WRITE IT

         LA    R9,1(R9)

*

GET      GET   IN                  READ A REC

         LA    R8,1(R8)

         LA    R3,0(R1)            SAVE IT'S ADDR

         ST    R3,PUT-4            TWICE, JUST TO BE SURE.

         LH    R5,DCBLRECL-IHADCB+IN    LOAD LRECL

         LA    R5,0(R3,R5)           R3=REC ADDR

         SR    R6,R5                 R6=END OF BUFFER

         SH    R5,=H'1'              R5=LAST USEABLE LOC

         LR    R1,R3                 -LENGTH OF LONGEST = END

TRTLOOP  LR    R2,R5               END

         SR    R2,R1               - START / CURRENT = LENGTH

         CR    R2,R7               Q. LONGER THAN 255

         BL    SHORT                  NO, JUST GO TEST SHORT

*

         TRT   0(255,R1),TRTABLE   TEST 255 BYTES

         BNZ   CHECK               A FIRST CHAR COUNT, GO CLC

         LA    R1,255(R1)          NOT FOUND, BUMP

         B     TRTLOOP             AND LOOP

*

         TRT   0(0,R1),TRTABLE

SHORT    EX    R2,SHORT-6          TEST SHORT

         BZ    GET                 NOT FOUND, JUST GO READ

         B     CHECK               YES,  GO DO  CLC'S

*

CLC      CLC   0(0,R14),12(R4)

CHECK    LA    R4,TABLE            POINT TO ARG TABLE

         N     R2,=F'255'          R2 = INDEX INTO ARG TABLE

         SH    R2,=H'3'              START WITH 0, NOT 1

         SLL   R2,4                  MULT BY 32

         LA    R4,TABLE(R2)          CALC ARG TABLE ENTRY LOC

         CLI   0(R1),C'Q'

         BNE   CHECKLH

         NOPR  0

CHECKLH  LH    R15,6(R4)           LOAD ENTRY LENGTH

         LR    R14,R1

         SH    R14,4(R4)

         LR    R0,R1

         AH    R0,8(R4)

         CR    R0,R5

         BNL   CHECKNEX

         EX    R15,CLC          Q. DOES THIS ENTRY MATCH?

         BE    PUT                 YEAH, GO WRITE

CHECKNEX CLC   11(1,R4),LTABLE+11(R4)       NO, BUMP TO NEXT

         BNE   NOT

         LA    R4,LTABLE(R4)       NO, BUMP TO NEXT

         C     R4,ATABLE+4      Q. END OF ARG TABLE?

         BL    CHECKLH             NO, TRY NEXT

NOT      LA    R1,1(R1)            POINT TO NEXT BYTE

         CR    R1,R5            Q. END OF RECORD

         BNH   TRTLOOP             NO, GO TEST

         B     GET                 YES, GO READ.

* ---------------------- ALL DONE, CLOSE FILES AND EXIT -------

EDIT9    DC    X'402020206B2020206B202120'

Z        LA    R4,TABLE-LTABLE-LTABLE

         MVC   PARM,PARM-1

         ST    R8,#READ

         ST    R9,#WRITTEN

TOTALS   L     R0,0(R4)

         CVD   R0,16(R13)

         MVC   PARM(L'EDIT9),EDIT9

         ED    PARM(L'EDIT9),19(R13)

         LH    R1,6(R4)

         MVC   PARM+L'EDIT9+2(0),12(R4)

         EX    R1,*-6

         PUT   SYSPRINT,PARM-1

         MVC   PARM,PARM-1

         LA    R4,LTABLE(R4)

         C     R4,ATABLE+4

         BL    TOTALS

         CLOSE (IN,,OUT,,SYSPRINT)

         L     13,4(13)

         LM    14,12,12(13)

         SR    R15,R15

         BR    14

*

LIST     MVC   TRTABLE(256),TRTABLE-1

         STM   R14,R6,12(R13)

         L     R2,ATABLE

         LA    R4,3

LISTA    LA    R1,2(R2)

         LA    R3,PARM

         SR    R5,R5

         LA    R0,4

LISTLH   LH    R14,0(R1)

         CVD   R14,32(R13)

         OI    39(R13),X'0F'

         UNPK  0(5,R3),37(3,R13)

         LA    R3,6(R3)

         LA    R1,2(R1)

         BCT   R0,LISTLH

         LH    R1,6(R2)

         MVC   2(1,R3),11(R2)

         MVC   4(0,R3),12(R2)

         EX    R1,*-6

         PUT   SYSPRINT,PARM-1

*

         IC    R5,11(R2)

         LA    R6,TRTABLE(R5)

         CLI   0(R6),0

         BNE   *+8

         STC   R4,0(R6)

         LA    R4,3(R4)

*

         MVC   PARM,PARM-1

         LA    R2,LTABLE(R2)

         C     R2,ATABLE+4

         BL    LISTA

         PUT   SYSPRINT,PARM-1

         LM    R14,R6,12(R13)

         BR    R14

*

BUBBLE   STM   R1,R3,12(R13)

         LA    R1,LTABLE

         L     R3,ATABLE+4

BUBBLEA  L     R2,ATABLE

         SR    R3,R1

         CR    R2,R3

         BL    BUBBLEC

         LM    R1,R3,12(R13)

         BR    R14

BUBBLEC  CLC   11(LTABLE-14,R2),11+LTABLE(R2)

         BL    BUBBLEN

         MVC   24(LTABLE,R13),0(R2)

         MVC   0(LTABLE,R2),LTABLE(R2)

         MVC   LTABLE(LTABLE,R2),24(R13)

BUBBLEN  LA    R2,LTABLE(R2)

         CR    R2,R3

         BL    BUBBLEC

         B     BUBBLEA

*

* INPUT  =R2= AL2(LENGTH-1),C'TEXT'

* OUTPUT =R3= CL2'CHAR',AL2(LEN TO BACK,LEN-1,LEN AFTER CHAR,TRT-ADDR

*

QFREQ    STM   R0,R9,12(R13)

*        XC    TRTABLE(256),TRTABLE

         L     R2,ATABLE  LL(TEXT),  FIRST,TOTAL,END LENGTHS

QFREQ$   LH    R4,10(R2)

         STH   R4,6(R2)       SAVE

         LA    R4,1(R4)       TOTAL LENGTH

         LR    R3,R2

         LA    R2,12(R2)       FIRST TEXT

         LR    R5,R2         FIRST TEXT

         LA    R6,0(R4,R5)    END OF STRING

         LA    R9,255

         SR    R7,R7

         SR    R8,R8

         LR    R10,R5

*

QFREQA   IC    R7,0(R5)            CHAR

         IC    R8,QFREQTBL(R7)     FREQ VALUE

         CR    R8,R9            Q. LESS FREQ

         BNL   QFREQB              NO

*

         LR    R9,R8               YES, SAVE FREQ VALUE

         MVC   11(1,R3),0(R5)       SAVE NEW CHAR

         LR    R0,R5               LOAD CURR ADDR

         SR    R0,R10              CALC OFFSET FROM START

         STH   R0,4(R3)            SAVE START OFFSET

         LR    R0,R6               LOAD END LOC

         SR    R0,R5               CALC LAST CHAR LOC

         STH   R0,8(R3)            SAVE TO NOT RUN OVER END OF REC

*

QFREQB   LA    R5,1(R5)            BUMP POINTER

         BCT   R4,QFREQA           LOOP THRU # CHARS

         LA    R2,LTABLE(R3)

         C     R2,ATABLE+4

         BL    QFREQ$

         LM    R0,R9,12(R13)       RELOAD REGS

         BR    R14                 AND RETURN

*

*        IC    R7,0(R3)            LOAD LEAST FREQ CHAR

*        LA    R0,TRTABLE              TRTABLE ADDR

*        SR    R0,R7               CALC ADDR TO DO TRT

*        ST    R0,8(R3)            SAVE ADDR TO DO TRT

*

         LTORG

         PUSH  PRINT

         PRINT NOGEN

IN       DCB   DDNAME=IN,DSORG=PS,EODAD=Z,MACRF=GL,LRECL=199,RECFM=FT

OUT      DCB   DDNAME=OUT,DSORG=PS,LRECL=133,RECFM=FT,MACRF=PM,

SYSPRINT DCB   DDNAME=SYSPRINT,DSORG=PS,LRECL=133,RECFM=FT,MACRF=PM

         POP   PRINT

*

ATABLE   DC    2F'0'

PARMPRT  DC    C' PSCAN2, ASM &SYSDATE &SYSTIME PARM= '

PARM     DC    CL101' ',CL33' '

LINE     DC    CL133'READ A FILE, COPY RECORDS WITH STRINGS SPECIFIED IN

               N THE PARM FIELD.'

         DC    X'00'

TRTABLE  EQU   *

DOC      @     'READ //IN, LOOK FOR STRINGS SPECIFIED IN PARM FIELD,'

         @     'COPY THOSE RECORDS TO //OUT'

         @     'CANNOT HAVE A COMMA IN A STRING. MAX STRING LENGTH=32'

         @     'CAN HAVE UP TO 15 STRINGS.  IN THE PARM= FIELD.'

         @     'CAN GET AWAY WITH A COUPLE SPACES. EG, IN A LISTING:'

         @     '// EXEC PGM=PSCAN2,PARM="MVC,STM,EQU   2"'

         @     '//SYSPRINT DD SYSOUT=*'

         @     '//IN DD DISP=SHR,DSN='

         @     '//OUT DD SYSOUT=*'

         @   'IF THERE ARE 2 STRINGS IN A REC, THE 2ND IS NOT COUNTED.'

*

         @     ' '

         @     '# RECORDS'

         @     '|     BYTES BEFORE SCAN BYTE (IE SCAN CHAR OFFSET)'

         @     '|     |     STRING LENGTH-1'

         @     '|     |     |     BYTES FROM SCAN CHAR TO END'

         @     '|     |     |     |       SCAN CHAR'

         @     '|     |     |     |       | |-STRING--'

         DC    X'FF'

#READ    DC    F'0',4HL2'17',CL36'RECORDS READ'

#WRITTEN DC    F'0',4HL2'17',CL36'RECORDS WRITTEN'

TABLE    DC    16CL48' ',X'FF'

LTABLE   EQU 48

FINDEND  DC    64X'00',C' ',191X'00'

         ORG   FINDEND+C','

         DC    C','

         ORG

*

QFREQTBL DS    0D

*

FREQTBL  DC    X'222120',253X'02'

         ORG   FREQTBL+X'81'

         DC    AL1(82,15,28,43,97,22,20,61,70)

         ORG   FREQTBL+X'91'

         DC    AL1(02,07,40,24,67,75,19,01,60)

         ORG   FREQTBL+X'A2'

         DC    AL1(63,91,28,10,24,01,20,01)

         ORG   FREQTBL+C'A'

         DC    AL1(82,15,28,43,97,22,20,61,70)

         ORG   FREQTBL+C'J'

         DC    AL1(02,07,40,24,67,75,19,01,60)

         ORG   FREQTBL+C'S'

         DC    AL1(63,91,28,10,24,01,20,01)

         ORG   FREQTBL+C'0'

         DC    AL1(89,88,87,86,85,84,83,82,81,80)

         ORG   FREQTBL+C' '

         DC    AL1(99)

         ORG   FREQTBL+C'.'

         DC    AL1(9)

         ORG   FREQTBL+C','

         DC    AL1(9)

         ORG   FREQTBL+C'/'

         DC    AL1(9)

*

         ORG   FREQTBL+X'20'      ------ ASCII CHARACTERS -----

         DC    AL1(98)

         ORG   FREQTBL+X'30'

         DC    AL1(89,88,87,86,85,84,83,82,81,80)

         ORG   FREQTBL+X'40'

         DC    AL1(82,15,28,43,97,22,20,61,70)

         DC    AL1(02,07,40,24,67,75,19,01,60)

         DC    AL1(63,91,28,10,24,01,20,01)

         ORG   FREQTBL+X'60'

         DC    AL1(82,15,28,43,97,22,20,61,70)

         DC    AL1(02,07,40,24,67,75,19,01,60)

         DC    AL1(63,91,28,10,24,01,20,01)

*

*        DCBD  DEVD=DA

*

@@PAD#1  EQU   ((*-PSCAN2)/4096+1)*4096

@@PAD#2  EQU   @@PAD#1-(*-PSCAN2)

         ORG   *+@@PAD#2

*

         END   PSCAN2


 

end