'=========================================================================== ' Subject: MESSAGE FILTER Date: 07-28-93 (00:00) ' Author: Victor Yiu Code: QB, PDS, VBDOS ' Keys: MESSAGE,FILTER Packet: TEXT.ABC '=========================================================================== ; ============ MessageFilter v1.0 ============= ; ; Strips all LF (ascii 10) and ascii 141s ; ; ======== by Victor Yiu, July 25, 1993 ======= ; ; v1.0 -- First release using hybrid in-line code ; ; QB users: ; DECLARE FUNCTION StripLF% (BYVAL Segm%, BYVAL Offst%, BYVAL Leng%) ; Text$ = LEFT$(Text$, StripLF(VARSEG(Text$), VARPTR(Text$), LEN(Text$)) ; ; PDS (far string)/VB-DOS users: ; DECLARE FUNCTION StripLF% (BYVAL FarAddr&, BYVAL Leng%) ; Text$ = LEFT$(Text$, StripLF(SSEGADD(Text$), LEN(Text$))) ; ; Function returns new length of string, so you should truncate old ; string with a LEFT$(Text$, ResultingCode) after calling this func. ; The reason for different syntaxes is for speed. BTW -- this routines ; automatically adjusts segment/offset overflows, so no need to adjust them ; in QB program. ; ; This routine is fast! It minimizes jumps and uses partial in-line coding. ; CODE SEGMENT PARA PUBLIC 'CODE' ASSUME CS:CODE, DS:nothing, ES:nothing, SS:nothing PUBLIC StripLF LineFeed EQU 10 OtherBad EQU 141 StripLF PROC FAR PUSH BP MOV BP, SP ; set up stack frame PUSH DS ; save required variables PUSH SI PUSH DI LES AX, DWORD PTR SS:[BP+8] ; load starting and ending addresses CLD ; go forward MOV DI, AX ; save copy of offset in DI MOV CL, 4 ; divide offset by 16 to add to segment SHR AX, CL MOV DX, ES ; add to segment ADD DX, AX AND DI, 15 ; adjust offset after operation MOV ES, DX MOV BX, DI ; save offset in BX for later MOV DS, DX MOV SI, DI MOV CX, WORD PTR SS:[BP+6] ; get count MOV AX, CX ; get remainder in AX SHR CX, 1 ; divide loop count by 8 SHR CX, 1 SHR CX, 1 AND AX, 7 ; mask MOV DL, 10 ; prepare to x10 AL INC CX ; to take into account the extra loop MUL DL NEG AX ADD AX, OFFSET LoopCheck MOV DX, (LineFeed * 256) + OtherBad ; preload for speed ; DH DL JMP AX EVEN ; each byte processed is 10 bytes of code StripTop: LODSB ; load byte CMP AL, DH ; LF? JE Byte2 ; yep -- skip CMP AL, DL ; 141? JE Byte2 ; yep -- skip STOSB ; just store then... Byte2: LODSB CMP AL, DH JE Byte3 CMP AL, DL JE Byte3 STOSB Byte3: LODSB CMP AL, DH JE Byte4 CMP AL, DL JE Byte4 STOSB Byte4: LODSB CMP AL, DH JE Byte5 CMP AL, DL JE Byte5 STOSB Byte5: LODSB CMP AL, DH JE Byte6 CMP AL, DL JE Byte6 STOSB Byte6: LODSB CMP AL, DH JE Byte7 CMP AL, DL JE Byte7 STOSB Byte7: LODSB CMP AL, DH JE Byte8 CMP AL, DL JE Byte8 STOSB Byte8: LODSB CMP AL, DH JE LoopCheck CMP AL, DL JE LoopCheck STOSB LoopCheck: LOOP StripTop MOV DX, DI ; get new offset count SUB DI, BX ; get length MOV AX, DI ; return result POP DI POP SI ; restore registers POP DS POP BP RET 6 ; shave off 6 bytes -- new length returned in AX StripLF ENDP End ;============== end of asm. code. Look at next message for BASIC ; program to test it. 'Here's the BASIC source to utilitze the asm. routine? --------- ' ======== CFilter 1.0 ======= ' asm. by Victor Yiu ' ' QB users: ' DECLARE FUNCTION StripLF% (BYVAL Segm%, BYVAL Offst%, BYVAL Leng%) ' Text$ = LEFT$(Text$, StripLF(VARSEG(Text$), VARPTR(Text$), LEN(Text$)) ' ' PDS (far string)/VB-DOS users: ' DECLARE FUNCTION StripLF% (BYVAL FarAddr&, BYVAL Leng%) ' Text$ = LEFT$(Text$, StripLF(SSEGADD(Text$), LEN(Text$))) ' ' Function returns new length of string, so you should truncate old ' string with a LEFT$(Text$, ResultingCode) after calling this func. ' The reason for different syntaxes is for speed. BTW -- this routines ' automatically adjusts segment/offset overflows, so no need to adjust them ' in QB program. DECLARE FUNCTION Filter$ (Text$, Array() AS STRING) 'one you call DECLARE FUNCTION StripLF% (BYVAL FarAddr&, BYVAL Leng%) 'asm func. DEFINT A-Z OPEN "Sample" FOR BINARY AS #1 Text$ = INPUT$(LOF(1), 1): PRINT "Size:"; LOF(1) CLOSE : IF LEN(Text$) = 0 THEN KILL "sample": PRINT "File?": END CLS DIM Array() AS STRING ' Text$ is modified -- LFs and 141s are stripped Address$ = Filter$(Text$, Array()) Text$ = "" OPEN "Output" FOR OUTPUT AS #1 FOR Num = 1 TO UBOUND(Array) PRINT #1, Array(Num); NEXT CLOSE PRINT Address$ FUNCTION Filter$ (Text$, MsgText() AS STRING) REDIM MsgText(1 TO 200) AS STRING AP = 1: CR$ = CHR$(13) ' ==== the FAST asm. procedure Text$ = LEFT$(Text$, StripLF(SSEGADD(Text$), LEN(Text$))) Prev = INSTR(Text$, CR$ + CHR$(1) + "MSGID: ") IF Prev THEN SpaceAfter = INSTR(Prev + 8, Text$, " ") IF SpaceAfter THEN Address$ = MID$(Text$, Prev + 8, SpaceAfter - Prev - 7) END IF IF RIGHT$(Text$, 1) <> CR$ THEN Text$ = Text$ + CR$ Pntr = 1: Prev = 1: CurrentTop = 200 DO Pntr = INSTR(Pntr, Text$, CR$) IF Pntr THEN ' dont include CR$ after each line MsgText(AP) = MID$(Text$, Prev, Pntr - Prev) Pntr = Pntr + 1: Prev = Pntr: AP = AP + 1 IF AP > CurrentTop THEN CurrentTop = CurrentTop + 50 REDIM PRESERVE MsgText(1 TO CurrentTop) AS STRING END IF END IF LOOP WHILE Pntr AP = AP - 1 REDIM PRESERVE MsgText(1 TO AP) AS STRING ' 'This portion of code looks for ^aMSGIDs and parses them. If it doesn't 'find a valid Fidonet address in the MSGID, it looks for the origin line 'address (Inside brackets) ' 'This portion of code follows directly after the above code. IF INSTR(Address$, ":") = 0 OR INSTR(Address$, "/") = 0 THEN FOR X = AP TO 1 STEP -1 IF LEFT$(MsgText(X), 11) = " ! Origin: " THEN LG = LEN(MsgText(X)) IF ASC(RIGHT$(MsgText(X), 1)) = 41 THEN ') FOR Y = LG TO 11 STEP -1 IF ASC(MID$(MsgText(X), Y)) = 40 THEN EXIT FOR '( END IF NEXT Address$ = MID$(MsgText(X), Y + 1, LG - Y - 1) END IF END IF NEXT END IF Filter$ = Address$ END FUNCTION