PAGE 72,128 TITLE INDEXAM - CCBBS INDEXED ACCESS METHOD PAGE .XLIST INCLUDE CCBBS.DEF INCLUDE CCBBS.MAC .LIST ;--------------------------------------------------------------------- ;INDEX NAME DEFINITIONS ;--------------------------------------------------------------------- MAILMSGNO EQU 0 ;CCEMAIL MSG # INDEX MAILTO EQU 1 ;CCEMAIL ADDRESSEE INDEX MAILFROM EQU 2 ;CCEMAIL AUTHOR INDEX MAILSUBJ EQU 3 ;CCEMAIL SUBJECT INDEX USERNAME EQU 100H ;USER FILE NAME INDEX FILENAME EQU 200H ;DIRECTORY FILE NAME INDEX ;--------------------------------------------------------------------- ;INDEX FILE RECORD DEFINITIONS ;--------------------------------------------------------------------- IBLKSIZ EQU 512 ;INDEX BLOCK SIZE ;COMMON HEADER IXBLKNO EQU 0 ;LOGICAL BLOCK NUMBER IXFLAGS EQU 2 ;FLAGS IXPARNT EQU 4 ;POINTER TO PARENT IXFWD EQU 6 ;FORWARD TWIN POINTER IXBKWD EQU 8 ;BACKWARD TWIN POINTER IXEXTN EQU 10 ;EXTENSION BLOCK ;INDEX ROOT BLOCK IXNKEYS EQU 12 ;NUMBER OF DIFFERENT KEYS IXKEYL EQU 14 ;LIST OF KEY ENTRIES ;IXKEYL+4N KEY TYPE FLAGS KALPHA EQU 1 ;ALPHANUMERIC KEYS KNONUQ EQU 2 ;NON-UNIQUE KEYS KEYPTR EQU 4 ;SS POINTER IS A KEY KEYSS EQU 8 ;THIS NODE IS SEQUENCE SET KPART EQU 10H ;PARTIAL KEYS KEYEXT EQU 20H ;THIS NODE IS EXTENSION BLOCK ;IXKEYS+4N+2 POINTER TO ROOT FOR THAT KEY ;FREE SPACE ROOT IXLSTBK EQU 12 ;HIGHEST BLOCK NUMBER IN FILE ;INDEX NODE BLOCK IXNFRE EQU 12 ;FREE SPACE POINTER IXNTRY EQU 14 ;1ST KEY ENTRY ;IXNTRY EQU 180H ;1ST KEY ENTRY - STRESS TEST ;-------------------------------------------------------------------- ;INDEX FILE DFCB DEFINITIONS ;-------------------------------------------------------------------- DFCNTRS EQU 32 ;NUMBER OF DFCB ENTRIES DFCHSIZ EQU 2 ;DFCB HEADER SIZE DFCSIZE EQU 8 ;DFCB ENTRY SIZE DFC1STE EQU 2 ;DFCB HEADER SIZE DFCFLAG EQU 0 ;DFCB FLAGS WORD DFALLOC EQU 1 ;ENTRY IN USE DFDIRTY EQU 2 ;ENTRY HAS BEEN CHANGED DFREFER EQU 4 ;ENTRY REFERENCED DFCSLOT EQU 2 ;DFCB NODE NUMBER DFCBUFF EQU 4 ;DFCB BUFFER ADDRESS DFCUSE EQU 6 ;DFCB USE COUNT ;--------------------------------------------------------------------- ;SYSTEM DATA SEGMENT ;--------------------------------------------------------------------- SYSDATA SEGMENT PARA PUBLIC 'DATA' EXTRN MSGINX2:WORD PUBLIC EMIXF INXCNT DW 0 ;INSERT RECORD CONT INXTST DW 08AH ;MATCH FOR DEBUG EMIXTN DB 'CCEMAIL.BIX',0 ;EMAIL INDEX TEMP NAME EMIXN DB 'CCEMAIL.INX',0 ;EMAIL INDEX FILE NAME EMIXH DW 0 ;EMAIL INDEX FILE HANDLE EMIXF DW 0 ;EMAIL INDEX FILE FLAGS EMDFCB DW 0 ;EMAIL BUFFER POOL CTL BLOCK EMIXL DW 0 ;EMAIL INDEX FILE LOCK DW 0 EMIXRL DW 0 ;EMAIL INDEX FILE ROOT LOCK DW 0 USRIXN DB 'CCUSERS.INX',0 ;USERS INDEX FILE NAME USRIXH DW 0 ;USERS INDEX FILE HANDLE USRIXF DW 0 ;USERS INDEX FILE FLAGS USRIXL DW 0 ;USERS INDEX FILE LOCK DW 0 FDIXN DB 'CCFILDIR.INX',0 ;FILE DIR INDEX NAME FDIXH DW 0 ;FILE DIR INDEX HANDLE FIDXF DW 0 ;FILE DIR INDEX FLAGS FIDXL DW 0 ;FILE DIR INDEX LOCK DW 0 SYSDATA ENDS ;----------------------------------------------- ;CODE SEGMENT ;----------------------------------------------- CSEG SEGMENT PARA PUBLIC 'CODE' ASSUME CS:CSEG,DS:NOTHING,ES:SYSDATA EXTRN CMPSTA:NEAR,GETBUF:NEAR,YIELD:NEAR EXTRN FREBUF:NEAR,GETSBF:NEAR,ERROR:NEAR EXTRN CKMSG:NEAR,TSYSOP:NEAR,MMENU2:NEAR,MMENU1:NEAR EXTRN FEOF:NEAR,READM:NEAR,STRIP:NEAR,TAYSOP:NEAR EXTRN LOCKWT:NEAR,UNLOCK:NEAR,WMSGNO:NEAR EXTRN ILINEB:NEAR,GETSBF:NEAR,LOGDSK:NEAR EXTRN BINASP:NEAR,APPBYT:NEAR,WRMSG:NEAR EXTRN MOVMSG:NEAR,MOVSTR:NEAR,FRELBF:NEAR EXTRN MOVSTL:NEAR,FINDMN:NEAR,INSTRG:NEAR EXTRN DQTIOA:NEAR,XLATE:NEAR PUBLIC BIXFIL,MAILIX,MXOPEN,OIXFIL,CIXFIL PUBLIC ATOINX,DTOINX,AFRINX,DFRINX,ASBINX,DSBINX PUBLIC OLDMAL,ALLMAL,PRGINX INDEXAM PROC NEAR ;--------------------------------------------------------------------- ;ENABLE INDEX FILE - OIX FROM MAIN MENU ;--------------------------------------------------------------------- OIXFIL: CALL TSYSOP ;AUTHORIZED CALLER? JNZ OIXF00 ;YES JMP MMENU2 ;UNKNOWN COMMAND OIXF00: FRAME CMP EMIXH,0 ;FILE OPEN? JZ OIXF10 ;NO - CALL OPEN MOV EMIXF,80H ;SHOW INDEX AVAILABLE JMP OIXF90 ;EXIT OIXF10: CALL MXOPEN OIXF90: MOV SP,BP ;FREE LOCAL STORAGE POP BP ;RESTORE CALLER'S FRAME JMP MMENU1 ;MAIN MENU ;--------------------------------------------------------------------- ;DISABLE INDEX FILE - CIX FROM MAIN MENU ;--------------------------------------------------------------------- CIXFIL: CALL TSYSOP ;AUTHORIZED CALLER? JNZ CIXF10 ;YES JMP MMENU2 ;UNKNOWN COMMAND CIXF10: FRAME CMP EMIXH,0 ;FILE OPEN? JZ CIXF90 ;NO - EXIT MOV EMIXF,0 ;CLEAR INDEX FLAGS CALL PRGINX ;PURGE INDEX BUFFERS CALL MXCLOS CIXF90: MOV SP,BP ;FREE LOCAL STORAGE POP BP ;RESTORE CALLER'S FRAME JMP MMENU1 ;MAIN MENU ;--------------------------------------------------------------------- ; BUILD NEW EMAIL INDEX FILE ; BP-2 A(SECTOR BUFFER) ; BP-4 POINTER TO MESSAGE BLOCK ; BP-6 TEST LOOP COUNTER ;--------------------------------------------------------------------- BIXFIL: CALL TSYSOP ;AUTHORIZED CALLER? JNZ BIXF10 ;YES JMP MMENU2 ;UNKNOWN COMMAND BIXF10: FRAME 3 ;CLOSE EXISTING INDEX FILE CALL PRGINX ;PURGE INDEX BUFFERS CALL MXCLOS ;CLOSE OLD FILE ;CREATE NEW MESSAGE INDEX FILE MOV EMIXF,40H ;SHOW BUILD IN PROCESS MOV AH,3CH ;CREATE FUNCTION XOR CX,CX ;NORMAL ATTRIBUTE MOV DX,OFFSET EMIXTN ;EMAIL INDEX FILE TEMP NAME PUSH DS PUSH ES POP DS INT 21H ;DOS REQUEST POP DS MOV EMIXH,AX ;NEW HANDLE JNC BIXF20 ;OPEN OK BIXF18: ERR 12H BIXF20: CALL NEWBLK ;GET ROOT BLOCK CMP WORD PTR [SI+IXBLKNO],0 ;1ST BLOCK? JNZ BIXF18 ;NO -SOMETHING WRONG CALL FREINX ;RELEASE ROOT ;CREATE FREE SPACE RECORD CALL NEWBLK ;GET FREE SPACE BLOCK MOV WORD PTR [SI+IXLSTBK],5 ;LAST BLOCK IN FILE CALL PUTINX ;WRITE TO INDEX FILE ;BUILD KEY STRUCTURES ;MESSAGE NUMBER KEYS XOR AX,AX ;UNIQUE NUMERIC KEYS MOV CX,AX ;INDEX NUMBER 0 ; PUSH CX ;INDEX NUMBER ; PUSH AX ;FLAGS ; CALL BLDKEY ;BUILD INITIAL NODE & LEAF ;"TO" KEYS MOV AX,KALPHA+KNONUQ+KEYPTR ;NON-UNIQUE ALPHA KEY PTRS INC CX ;NEXT INDEX PUSH CX ;INDEX NUMBER PUSH AX ;FLAGS CALL BLDKEY ;BUILD INITIAL NODE & LEAF ;"FROM" KEYS INC CX ;NEXT INDEX ; PUSH CX ;INDEX NUMBER ; PUSH AX ;FLAGS ; CALL BLDKEY ;BUILD INITIAL NODE & LEAF ;"SUBJECT" KEYS INC CX ;NEXT INDEX ; PUSH CX ;INDEX NUMBER ; PUSH AX ;FLAGS ; CALL BLDKEY ;BUILD INITIAL NODE & LEAF ;READ ALL ACTIVE MESSAGES AND BUILD INDEX ENTRIES MOV DI,MSGINX2 ;MESSAGE BLOCK INDEX ADD DI,DS:MSGCKPT+MIFRST ;1ST ACTIVE INDEX ENTRY MOV CX,DS:MSGCKPT+MIACTM ;NUMBER OF ACTIVE MESSAGES BIXF30: MOV [BP-4],DI ;SAVE BLOCK POINTER MOV AX,[DI] ;NEXT MESSAGE BLOCK MOV WORD PTR [BX+USRMP],AX ;SET FOR READ CALL READM ;READ MESSAGE CALL ATOINX ;ADD "TO" ENTRY ; CALL AFRINX ;ADD "FROM" ENTRY ; CALL ASBINX ;ADD SUBJECT ENTRY MOV DI,[BP-4] ;BLOCK POINTER ADD DI,2 ;NEXT ENTRY LOOP BIXF30 ;HANDLE NEXT MESSAGE BIXF90: MOV EMIXF,0 ;INDEX NOT AVAILABLE CALL PRGINX ;PURGE INDEX BUFFERS ;CLOSE NEW FILE MOV AX,EMIXH ;FILE HANDLE MOV AH,3EH ;CLOSE REQUEST INT 21H ;DOS CALL ;DELETE OLD INDEX FILE MOV AH,41H ;DELETE REQUEST MOV DX,OFFSET EMIXN ;OLD FILE NAME PUSH DS PUSH ES POP DS INT 21H ;DOS CALL ;RENAME NEW FILE TO PERMANENT NAME MOV AH,56H ;RENAME REQUEST MOV DX,OFFSET EMIXTN ;TEMPORARY NAME MOV DI,OFFSET EMIXN ;PERMANENT NAME INT 21H ;DOS CALL POP DS JNC BIXF95 ;GOOD RETURN ERR 12H ;OPEN NEW INDEX FILE BIXF95: CALL MXOPEN JNC BIXF97 ;OPEN OK ERR 12H ;DISPLAY AND LOG RESULTS BIXF97: CALL ILINEB ;INITIALIZE LINE BUFFER MOV AX,408 ;INDEX FILE BUILD CALL MOVMSG ;MOVE TO BUFFER CALL WRMSG ;DISPLAY RESULT CALL LOGDSK ;LOG RESULT MOV SP,BP ;FREE LOCAL STORAGE POP BP ;RESTORE CALLER'S FRAME JMP MMENU1 ;EXIT ;--------------------------------------------------------------------- ; NEW MAIL CHECK ROUTINE - REPLACES CKMSG ;--------------------------------------------------------------------- MAILIX: TEST EMIXF,80H ;INDEX AVAILABLE? JNZ MAIL10 ;YES JMP CKMSG ;OLD ROUTINE MAIL10: MOV AX,32 ;CHECKING ... CALL WMSGNO ;CHECKING MESSAGE BASE XOR AX,AX ;CLEAR FLAGS CALL CKTMSG ;CHECK PERSONAL MAIL XOR AX,AX ;CLEAR FLAGS CALL CKAMSG ;CHECK GENERAL MESSAGES RET ;--------------------------------------------------------------------- ; CHECK ALL MAIL FOR USER - READ OR NOT ;--------------------------------------------------------------------- OLDMAL: TEST EMIXF,80H ;INDEX AVAILABLE? JZ OLDM90 ;NO - EXIT MOV AX,32 ;CHECKING ... CALL WMSGNO ;CHECKING MESSAGE BASE MOV AX,1 ;REPORT ALREADY READ MAIL CALL CKTMSG ;CHECK PERSONAL MAIL OLDM90: JMP MMENU1 ;--------------------------------------------------------------------- ; CHECK ALL GENERAL MAIL IGNORING HIGH MESSAGE POINTER ;--------------------------------------------------------------------- ALLMAL: TEST EMIXF,80H ;INDEX AVAILABLE? JZ ALLM90 ;NO - EXIT MOV AX,32 ;CHECKING ... CALL WMSGNO ;CHECKING MESSAGE BASE MOV AX,2 ;IGNORE HIGH MESSAGE POINTER CALL CKAMSG ;CHECK ALL MAIL ALLM90: JMP MMENU1 ;--------------------------------------------------------------------- ;CHECK FOR UNREAD PERSONAL MESSAGES ; BP-2 # OF MSGS FOUND ; BP-4 LOCAL FLAGS ; BP-6 USER NAME STRING ; BP-8 USER SECTION MASK ; BP-10 USER STATUS MASK ; BP-12 MESSAGE NUMBER STRING ; BP-14 LOOP COUNTER ; BP-16 POSITION IN NUMBER STRING ;--------------------------------------------------------------------- CKTMSG: FRAME 8 MOV [BP-4],AX ;LOCAL FLAGS XOR AX,AX ;FOR CLEARING MOV WORD PTR [BP-12],AX ;NO RESULTS YET MOV DI,WORD PTR [BX+USRST] ;USER RECORD MOV AX,WORD PTR [DI+UESECT] ;AUTHORIZED SECTIONS MOV [BP-8],AX XOR AX,AX MOV AL,BYTE PTR [DI+UESTAT] ;USER STATUS MOV [BP-10],AX MOV WORD PTR [BP-2],-1 ;CLEAR COUNTER CALL TAYSOP ;PRIVILEDGED USER? JZ CKTM06 ;NO CALL DQTIOA ;GET NAME STRING JNC CKTM08 ;USE SUPPLIED NAME ;CHECK FOR USERS OWN MAIL CKTM06: MOV AX,80 ;MORE THAN ENOUGH CALL GETBUF ;GET BUFFER MOV DI,[BX+USR3N] ;USER NAME STRING CALL MOVSTR ;MOVE TO BUFFER CALL UNTAGN ;JUST BASIC NAME ;GET INDEX ENTRY STRING CKTM08: CALL XLATE ;MAKE UPPER CASE MOV [BP-6],SI ;FILTERED NAME STRING MOV AX,MAILTO ;INDEX NUMBER CALL GINTRY ;GET RESULT STRING JNC CKTM10 ;FOUND IT JMP CKTM60 ;NO MAIL CKTM10: MOV [BP-12],SI ;AND REMEMBER WHERE MOV CX,[SI-2] ;LIST LENGTH SHR CX,1 ;CONVERT TO WORDS MOV DI,SI ;START OF LIST JCXZ CKTM60 ;EMPTY LIST CKTM30: MOV [BP-14],CX ;SAVE COUNT MOV [BP-16],DI ;AND POSITION MOV AX,[DI] ;MESSAGE NUMBER CALL FINDMN ;GET MESSAGE BLOCK NUMBER JC CKTM50 ;MESSAGE NUMBER NOT FOUND MOV WORD PTR [BX+USRMP],AX ;SET FOR READ CALL READM ;READ MESSAGE HEADER JZ CKTM32 ;GOOD READ JMP CKTM50 ;TRY NEXT MSG CKTM32: TEST WORD PTR [BP-4],1 ;REPORT OLD MAIL? JNZ CKTM33 ;YES TEST BYTE PTR [SI+MRSTAT],8 ;ALREADY READ? JNZ CKTM50 ;YES - SKIP CKTM33: CMP WORD PTR [BP-2],-1 ;FIRST ONE? JNZ CKTM34 ;NO MOV AX,404 ;FOLLOWING MSGS ... CALL WMSGNO INC WORD PTR [BP-2] ;MARK MSGS FOUND CALL ILINEB ;GET LINE BUFFER CKTM34: MOV DI,WORD PTR [BX+USRMB] ;MESSAGE HEADER MOV AX,WORD PTR [DI+MMNUMB] ;MESSAGE NUMBER MOV SI,WORD PTR [BX+USRLB] ;LINE BUFFER CALL BINASP ;PUT NUMBER IN BUFFER TEST BYTE PTR [DI+MPFLAG],2 ;PRIVATE? JZ CKTM36 ;NO MOV AL,'!' ;PRIVATE MARKER CALL APPBYT ;ADD TO STRING CKTM36: INC WORD PTR [SI-2] ;ALLOW ONE SPACE INC WORD PTR [BP-2] ;COUNT MSG CMP WORD PTR [BP-2],12 ;LINE FULL? JBE CKTM50 ;NO MOV SI,WORD PTR [BX+USRLB] ;START OF LINE CALL WRMSG ;DISPLAY CALL ILINEB ;GET NEW BUFFER MOV WORD PTR [BP-2],0 ;CLEAR COUNT CKTM50: ADD WORD PTR [BP-16],2 ;NEXT MSG INX MOV DI,[BP-16] ;MSG INX MOV CX,[BP-14] ;REMAINING COUNT LOOP CKTM30 ;GO CHECK NEXT MSG CKTM60: CMP WORD PTR [BP-2],0 ;ANY MSGS FOUND? JZ CKTM80 ;ALREADY PRINTED JG CKTM70 ;YES - GO PRINT CALL ILINEB ;GET BUFFER MOV AX,160 ;'SORRY CALL MOVMSG ;PUT IN BUFFER MOV DI,WORD PTR [BX+USR1N] ;1ST NAME CALL MOVSTR ;PUT IN BUFFER MOV AX,186 ;'NO MAIL CALL MOVMSG ;PUT IN BUFFER CKTM70: MOV SI,WORD PTR [BX+USRLB] ;START OF BUFFER CALL WRMSG ;DISPLAY CKTM80: CALL FRELBF ;FREE LINE BUFFER MOV SI,WORD PTR [BX+USRMB] ;MESSAGE BUFFER CALL FREBUF ;FREE IT MOV WORD PTR [BX+USRMB],0 ;MARK FREE MOV SI,[BP-6] ;ALL STRING BUFFER CALL FREBUF ;FREE IT MOV SI,[BP-12] ;RESULT STRING CALL FREBUF ;FREE IT EXITF ;--------------------------------------------------------------------- ;CHECK FOR UNREAD GENERAL MESSAGES ; BP-2 # OF MSGS FOUND ; BP-4 LOCAL FLAGS ; BP-6 `ALL' STRING ; BP-8 USER SECTION MASK ; BP-10 USER STATUS MASK ; BP-12 MESSAGE NUMBER STRING ; BP-14 LOOP COUNTER ; BP-16 POSITION IN NUMBER STRING ;--------------------------------------------------------------------- CKAMSG: FRAME 8 MOV [BP-4],AX ;LOCAL FLAGS XOR AX,AX ;FOR CLEARING MOV WORD PTR [BP-6],AX ;NO STRING YET MOV WORD PTR [BP-12],AX ;NO RESULTS YET MOV DI,WORD PTR [BX+USRST] ;USER RECORD MOV AX,WORD PTR [DI+UESECT] ;AUTHORIZED SECTIONS MOV [BP-8],AX XOR AX,AX MOV AL,BYTE PTR [DI+UESTAT] ;USER STATUS MOV [BP-10],AX MOV WORD PTR [BP-2],-1 ;CLEAR COUNTER TEST WORD PTR [DI+UEOPTS],32 ;SEE 'ALL' MSGS? JZ CKAM00 ;YES JMP CKAM80 ;NO - EXIT ;GET INDEX ENTRY STRING CKAM00: MOV AX,80 ;MORE THAN ENOUGH CALL GETBUF ;GET BUFFER MOV AX,174 ;'ALL' CALL MOVMSG ;MOVE TO BUFFER CALL STRIP ;TRIM TRAILING BLANKS MOV [BP-6],SI ;REMEMBER WHERE MOV AX,MAILTO ;INDEX NUMBER CALL GINTRY ;GET RESULT STRING JNC CKAM10 ;FOUND IT JMP CKAM60 ;NO MAIL CKAM10: MOV [BP-12],SI ;AND REMEMBER WHERE MOV CX,[SI-2] ;LIST LENGTH SHR CX,1 ;CONVERT TO WORDS ;FIND STARTING MESSAGE NUMBER IN RESULT STRING MOV DI,SI ;START OF LIST XOR AX,AX ;NO HIGH MESSAGE POINTER TEST WORD PTR [BP-4],2 ;REPORT ALL MESSAGES? JNZ CKAM20 ;YES MOV SI,WORD PTR [BX+USRST] ;USER RECORD MOV AX,[SI+UEHMSG] ;USER HIGH MESSAGE # CKAM20: CMP AX,[DI] ;MSG NUMBER JB CKAM30 ;YES - START HERE ADD DI,2 ;NEXT MESSAGE LOOP CKAM20 ;GO CHECK IT JMP CKAM60 ;NO MESSAGES CKAM30: MOV [BP-14],CX ;SAVE COUNT MOV [BP-16],DI ;AND POSITION MOV AX,[DI] ;MESSAGE NUMBER CALL FINDMN ;GET MESSAGE BLOCK NUMBER JC CKAM50 ;MESSAGE NUMBER NOT FOUND MOV WORD PTR [BX+USRMP],AX ;SET FOR READ CALL READM ;READ MESSAGE HEADER JZ CKAM32 ;GOOD READ JMP CKAM50 ;NO - TRY NEXT CKAM32: TEST BYTE PTR [SI+MPFLAG],1 ;FLASH MSG? JNZ CKAM50 ;YES - SKIP CMP WORD PTR [SI+MFSECT],0 ;GLOBAL MSG? JZ CKAM34 ;YES MOV AX,[BP-8] ;USER SECTION MASK TEST WORD PTR [SI+MFSECT],AX ;VALID SECTION FOR USER? JZ CKAM50 ;NO CKAM34: CMP WORD PTR [BP-2],-1 ;FIRST ONE? JNZ CKAM40 ;NO MOV AX,405 ;FOLLOWING MSGS ... CALL WMSGNO INC WORD PTR [BP-2] ;MARK MSGS FOUND CALL ILINEB ;GET LINE BUFFER CKAM40: MOV SI,WORD PTR [BX+USRMB] ;MESSAGE HEADER MOV AX,WORD PTR [SI+MMNUMB] ;MESSAGE NUMBER MOV SI,WORD PTR [BX+USRLB] ;LINE BUFFER CALL BINASP ;PUT NUMBER IN BUFFER INC WORD PTR [SI-2] ;ALLOW ONE SPACE INC WORD PTR [BP-2] ;COUNT MSG CMP WORD PTR [BP-2],12 ;LINE FULL? JBE CKAM50 ;NO MOV SI,WORD PTR [BX+USRLB] ;START OF LINE CALL WRMSG ;DISPLAY CALL ILINEB ;GET NEW BUFFER MOV WORD PTR [BP-2],0 ;CLEAR COUNT CKAM50: ADD WORD PTR [BP-16],2 ;NEXT MSG INX MOV DI,[BP-16] ;MSG INX POSITION MOV CX,[BP-14] ;REMAINING COUNT LOOP CKAM30 ;CHECK NEXT MESSAGE CKAM60: CMP WORD PTR [BP-2],0 ;ANY MSGS FOUND? JLE CKAM80 ;ALREADY PRINTED CKAM70: MOV SI,WORD PTR [BX+USRLB] ;START OF BUFFER CALL WRMSG ;DISPLAY CKAM80: CALL FRELBF ;FREE LINE BUFFER MOV SI,WORD PTR [BX+USRMB] ;MESSAGE BUFFER CALL FREBUF ;FREE IT MOV WORD PTR [BX+USRMB],0 ;MARK FREE MOV SI,[BP-6] ;ALL STRING BUFFER CALL FREBUF ;FREE IT MOV SI,[BP-12] ;RESULT STRING CALL FREBUF ;FREE IT EXITF ;--------------------------------------------------------------------- ;GET INDEX ENTRY STRING ; ;ENTRY AX INDEX NUMBER ; SI TARGET NAME STRING ;RETURNS SI RESULT STRING IF C=0 ;LOCAL BP-2 SECTOR BUFFER ; BP-4 RESULT BUFFER ; BP-6 PASSED STRING ; BP-8 POSITION IN SECTOR BUFFER ; BP-10 INDEX NUMBER ;--------------------------------------------------------------------- GINTRY: FRAME 5 MOV [BP-10],AX ;INDEX NUMBER MOV [BP-6],SI ;TARGET STRING MOV SI,OFFSET EMIXRL ;INDEX FILE ROOT LOCK WORD CALL LOCKWT ;ACQUIRE LOCK MOV AX,[BP-10] ;INDEX NUMBER CALL GIXNDE ;GET STARTING NODE NUMBER JNC GINT12 ;OK SO FAR ERR 14H ;INVALID INDEX REQUEST GINT10: CALL FREINX ;RELEASE OLD NODE OR AX,AX ;VALID? JNZ GINT12 ;PROBABLY JMP GINT70 ;INVALID INDEX STRUCTURE GINT12: CALL GETINX ;READ NODE RECORD JNC GENT14 ;GOOD READ JMP GINT70 ;RECORD NOT FOUND GENT14: MOV [BP-2],SI ;REMEMBER MOV DX,[SI+IXNFRE] ;FREE SPACE POINTER ADD DX,SI ;INDEX INTO BUFFER MOV DI,SI ;WORK INDEX ADD DI,IXNTRY ;1ST ENTRY GINT20: MOV [BP-8],DI ;POSITION IN ENTRY LIST MOV SI,[BP-2] ;RESTORE SECTOR POINTER CMP DI,DX ;END OF ENTRIES? JB GINT30 ;NO MOV AX,[SI+IXFWD] ;NEXT TWIN OR AX,AX ;EXIST? JNZ GINT10 ;YES - CHAIN TO IT TEST WORD PTR [SI+IXFLAGS],KEYSS ;SEQUENCE SET? JZ GINT22 ;NO JMP GINT72 ;YES - NO ENTRY EXISTS GINT22: MOV AX,[DI-2] ;CHILD POINTER JMP GINT10 ;CHAIN TO CHILD ;CHECK CURRENT ENTRY FOR MATCH GINT30: MOV SI,[BP-6] ;KEY STRING ADD DI,4 ;CURRENT KEY CALL CVLSTR ;COMPARE VL STRINGS JBE GINT32 ;CHECK FOR SS MOV DI,[BP-8] ;START OF ENTRY CMP WORD PTR [DI],0 ;VALID LENGTH? JNZ GINT31 ;NO PROBLEM JMP GINT70 ;INVALID INDEX GINT31: ADD DI,[DI] ;POINT PAST ENTRY MOV [BP-8],DI ;UPDATE POINTER CMP DI,DX ;ANY MORE ENTRIES JB GINT30 ;CHECK NEXT ENTRY JMP GINT20 ;CHECK NEXT NODE GINT32: PUSHF ;REMEMBER RESULT OF COMPARE MOV SI,[BP-2] ;NODE POINTER TEST WORD PTR [SI+IXFLAGS],KEYSS ;SEQUENCE SET? JNZ GINT36 ;YES ;NON-TERMINAL NODE POPF JZ GINT34 ;FOLLOW CURRENT CHAIN MOV AX,[BP-2] ;START OF BUFFER ADD AX,IXNTRY+4 ;1ST KEY STRING CMP AX,DI ;AT BEGINNING OF RECORD? JZ GINT34 ;YES - SEARCH 1ST NODE MOV AX,[DI-6] ;PREVIOUS CHILD POINTER JMP GINT10 ;READ NODE GINT34: ADD DI,[DI-2] ;POINT PAST KEY MOV AX,[DI] ;CHILD POINTER JMP GINT10 ;NEXT NODE ;SEQUENCE SET GINT36: POPF ;RESULTS OF STRING COMPARE JZ GINT40 ;THIS KEY JMP GINT72 ;NOT FOUND GINT40: MOV DI,[BP-8] ;START OF ENTRY MOV CX,[DI] ;ENTRY LENGTH SUB CX,[DI+2] ;LESS STRING LENGTH SUB CX,4 ;LESS LENGTH FIELDS MOV AX,CX ;ENTRY LENGTH CALL GETBUF ;GET RESULT BUFFER MOV [BP-4],SI ;AND REMEMBER WHERE GINT50: ADD DI,4 ;START OF STRING ADD DI,[DI-2] ;POINT PAST STRING CALL MOVSTL ;MOVE TO RESULT BUFFER MOV [BP-4],SI ;IN CASE STRING EXTENDED ;SEE IF EXTENSION RECORD EXISTS MOV SI,[BP-2] ;SECTOR BUFFER MOV AX,[SI+IXEXTN] ;EXTENSION POINTER OR AX,AX ;EXIST? JZ GINT80 ;NO - DONE CALL FREINX ;RETURN IT CALL GETINX ;CHAIN TO EXTENSION JC GINT70 ;RECORD NOT FOUND MOV [BP-2],SI ;EXTENSION BUFFER ;APPEND EXTENSION STRING TO ORIGINAL MOV DI,SI ;START OF RECORD ADD DI,IXNTRY ;ONLY ENTRY MOV CX,[DI] ;ENTRY LENGTH SUB CX,[DI+2] ;LESS STRING LENGTH SUB CX,4 ;LESS LENGTH FIELDS MOV SI,[BP-4] ;RESULT STRING JMP GINT50 ;GO APPEND ENTRY ;LOG ERROR IN INDEX SEARCH GINT70: CALL ILINEB ;INITIALIZE LINE BUFFER MOV AX,407 ;INDEX SEARCH FAILURE CALL MOVMSG ;MOVE TO BUFFER CALL LOGDSK ;LOG ERROR ;NO ENTRIES FOUND GINT72: MOV SI,[BP-2] ;SECTOR BUFFER CALL FREINX ;RETURN TO POOL MOV SI,OFFSET EMIXRL ;INDEX FILE ROOT LOCK WORD CALL UNLOCK ;FREE LOCK STC ;SHOW NOT FOUND JMP GINT90 GINT80: MOV SI,[BP-2] ;SECTOR BUFFER CALL FREINX ;RETURN TO POOL MOV SI,OFFSET EMIXRL ;INDEX FILE ROOT LOCK WORD CALL UNLOCK ;FREE LOCK MOV SI,[BP-4] ;RETURN RESULT BUFFER CLC ;SHOW GOOD RETURN GINT90: EXITF ;--------------------------------------------------------------------- ;DELETE INDEX ENTRY POINTER ; ;ENTRY AX INDEX NUMBER ; CX MESSAGE NUMBER ; SI TARGET NAME STRING ;LOCAL BP-2 SECTOR BUFFER ; BP-4 MESSAGE NUMBER ; BP-6 PASSED STRING ; BP-8 POSITION IN SECTOR BUFFER ; BP-10 INDEX NUMBER ;--------------------------------------------------------------------- DELINX: FRAME 5 MOV [BP-6],SI ;TARGET STRING MOV [BP-4],CX ;MESSAGE NUMBER MOV [BP-10],AX ;INDEX NUMBER MOV SI,OFFSET EMIXRL ;INDEX FILE ROOT LOCK WORD CALL LOCKWT ;ACQUIRE LOCK MOV AX,[BP-10] ;INDEX NUMBER CALL GIXNDE ;GET 1ST SEARCH NODE JNC DELI12 ;OK SO FAR ERR 14H ;INVALID INDEX REQUEST DELI10: CALL FREINX ;RETURN IT DELI12: CALL GETINX ;READ NODE RECORD JNC DELI14 ;GOOD READ ERR 15H ;RECORD NOT FOUND DELI14: MOV [BP-2],SI ;REMEMBER MOV DX,[SI+IXNFRE] ;FREE SPACE POINTER ADD DX,SI ;INDEX INTO BUFFER MOV DI,SI ;WORK INDEX ADD DI,IXNTRY ;1ST ENTRY DELI20: MOV [BP-8],DI ;POSITION IN ENTRY LIST MOV SI,[BP-2] ;RESTORE SECTOR POINTER CMP DI,DX ;END OF ENTRIES? JB DELI30 ;NO MOV AX,[SI+IXFWD] ;NEXT TWIN OR AX,AX ;EXIST? JNZ DELI10 ;YES - CHAIN TO IT TEST WORD PTR [SI+IXFLAGS],KEYSS ;SEQUENCE SET? JNZ DELI22 ;YES - NO ENTRY EXISTS MOV AX,[DI-2] ;CHILD POINTER JMP DELI10 ;CHAIN TO CHILD DELI22: MOV SI,[BP-2] ;SECTOR BUFFER CALL FREINX ;RETURN TO POOL MOV SI,OFFSET EMIXRL ;INDEX FILE ROOT LOCK WORD CALL UNLOCK ;FREE LOCK STC ;SHOW NOT FOUND JMP DELI90 ;CHECK CURRENT ENTRY FOR MATCH DELI30: MOV SI,[BP-6] ;KEY STRING ADD DI,4 ;CURRENT KEY CALL CVLSTR ;COMPARE VL STRINGS JBE DELI32 ;CHECK FOR SS MOV DI,[BP-8] ;START OF ENTRY CMP WORD PTR [DI],0 ;VALID LENGTH? JNZ DELI31 ;NO PROBLEM E15D: ERR 15H ;INVALID DELI31: ADD DI,[DI] ;POINT PAST ENTRY MOV [BP-8],DI ;UPDATE POINTER CMP DI,DX ;ANY MORE ENTRIES JB DELI30 ;CHECK NEXT ENTRY JMP DELI20 ;CHECK NEXT NODE DELI32: PUSHF ;REMEMBER RESULT OF COMPARE MOV SI,[BP-2] ;NODE POINTER TEST WORD PTR [SI+IXFLAGS],KEYSS ;SEQUENCE SET? JNZ DELI36 ;YES ;NON-TERMINAL NODE POPF JZ DELI34 ;FOLLOW CURRENT CHAIN MOV AX,[BP-2] ;START OF BUFFER ADD AX,IXNTRY+4 ;1ST KEY STRING CMP AX,DI ;AT BEGINNING OF RECORD? JZ DELI34 ;YES - SEARCH 1ST NODE MOV AX,[DI-6] ;PREVIOUS CHILD POINTER JMP DELI10 ;READ NODE DELI34: ADD DI,[DI-2] ;POINT PAST KEY MOV AX,[DI] ;CHILD POINTER JMP DELI10 ;NEXT NODE ;SEQUENCE SET DELI36: POPF ;RESULTS OF STRING COMPARE JZ DELI40 ;THIS KEY JMP DELI22 ;NOT FOUND DELI40: MOV DI,[BP-8] ;START OF ENTRY DELI50: MOV CX,[DI] ;ENTRY LENGTH SUB CX,[DI+2] ;LESS STRING LENGTH SUB CX,4 ;LESS LENGTH FIELDS SHR CX,1 ;NUMBER OF POINTERS ADD DI,4 ;START OF STRING ADD DI,[DI-2] ;POINT PAST STRING ;SEARCH ENTRYS FOR MATCH ON MESSAGE NUMBER MOV AX,[BP-4] ;MESSAGE NUMBER JCXZ DELI62 ;EMPTY ENTRY DELI55: CMP AX,[DI] ;MATCH? JNZ DELI60 ;NO MOV CX,2 ;SPACE TO DELETE MOV SI,[BP-2] ;BUFFER MOV DX,[SI+IXNFRE] ;FREE SPACE POINTER ADD DX,SI ;CONVERT TO ADDRESS CALL DELETE ;DELETE ENTRY MOV DI,[BP-8] ;START OF ENTRY SUB WORD PTR [DI],2 ;NEW ENTRY LENGTH CALL PUTINX ;RE-WRITE RECORD JMP DELI80 ;DONE DELI60: ADD DI,2 ;NEXT POINTER LOOP DELI55 ;CHECK ;SEE IF EXTENSION RECORD EXISTS DELI62: MOV SI,[BP-2] ;SECTOR BUFFER MOV AX,[SI+IXEXTN] ;EXTENSION POINTER OR AX,AX ;EXIST? JZ DELI80 ;NO - DONE CALL FREINX ;RETURN IT CALL GETINX ;CHAIN TO EXTENSION JNC DELI70 ;GOOD READ ERR 15H ;RECORD NOT FOUND DELI70: MOV [BP-2],SI ;REMEMBER WHERE MOV DI,SI ;START OF RECORD ADD DI,IXNTRY ;ONLY ENTRY JMP DELI50 ;GO APPEND ENTRY DELI80: MOV SI,[BP-2] ;SECTOR BUFFER CALL FREINX ;RETURN TO POOL MOV SI,OFFSET EMIXRL ;INDEX FILE ROOT LOCK WORD CALL UNLOCK ;FREE LOCK CLC ;SHOW GOOD RETURN DELI90: EXITF ;--------------------------------------------------------------------- ;OPEN EMAIL INDEX FILE ;NOTE: THIS ROUTINE IS CALLED DURING INITIATION AND THEREFORE ;CAN NOT ISSUE ANY COMMANDS WHICH DEPEND ON TCB SETTINGS ;--------------------------------------------------------------------- MXOPEN: FRAME MOV AX,3D02H ;OPEN FOR UPDATE MOV DX,OFFSET EMIXN ;EMAIL INDEX FILE NAME PUSH DS PUSH ES POP DS INT 21H ;DOS REQUEST POP DS JNC MXOP80 ;OPEN OK MOV EMIXF,0 ;CLEAR FLAGS JMP MXOP90 ;EXIT MXOP80: MOV EMIXF,80H ;SHOW INDEX AVAILABLE MOV EMIXH,AX ;NEW HANDLE MXOP90: EXITF ;--------------------------------------------------------------------- ;CLOSE EMAIL INDEX FILE ;--------------------------------------------------------------------- MXCLOS: FRAME CMP EMIXH,0 ;CURRENTLY OPEN? JZ MXCL90 ;NO - EXIT MOV AH,3EH ;CLOSE REQUEST PUSH BX MOV BX,EMIXH ;INDEX FILE HANDLE INT 21H ;DOS REQUEST POP BX MOV EMIXF,0 ;CLEAR FLAGS MOV EMIXH,0 ;NOT OPEN MXCL90: EXITF ;--------------------------------------------------------------------- ;EXTRACT MESSAGE NUMBER AND "TO" KEY AND PASS TO INDEX ADD ROUTINE ;ENTRY SI -> MESSAGE BUFFER ;LOCAL BP-2 MESSAGE BUFFER ; BP-4 KEY BUFFER ;--------------------------------------------------------------------- ATOINX: FRAME 2 CMP EMIXH,0 ;INDEX OPEN? JNZ ATOI00 ;YES JMP ATOI90 ;EXIT ATOI00: MOV [BP-2],SI ;A(MESSAGE BUFFER) PUSH AX PUSH CX PUSH DX PUSH SI PUSH DI MOV DI,[BP-2] ;MESSAGE ADDRESS ADD DI,MTNAME ;TO NAME MOV CX,MTSTMP-MTNAME ;MAX KEY LENGTH CALL BLDSTR ;BUILD NAME STRING CALL UNTAGN ;UNTAG NAME STRING MOV [BP-4],SI ;BUFFER ADDRESS MOV AX,MAILTO ;INDEX NUMBER MOV DI,[BP-2] ;MESSAGE ADDRESS MOV CX,[DI+MMNUMB] ;MESSAGE NUMBER CALL ADDINX ;ADD INDEX ENTRY MOV SI,[BP-4] ;KEY BUFFER CALL FREBUF ;FREE BUFFER POP DI POP SI POP DX POP CX POP AX ATOI90: EXITF ;--------------------------------------------------------------------- ;EXTRACT MESSAGE NUMBER AND KEY AND PASS TO INDEX DELETE ROUTINE ;ENTRY SI -> MESSAGE BUFFER ;LOCAL BP-2 MESSAGE BUFFER ; BP-4 KEY BUFFER ; BP-6 MESSAGE NUMBER ;--------------------------------------------------------------------- DTOINX: FRAME 3 CMP EMIXH,0 ;INDEX OPEN? JNZ DTOI00 ;YES JMP DTOI90 ;EXIT DTOI00: MOV [BP-2],SI ;A(MESSAGE BUFFER) PUSH AX PUSH CX PUSH DX PUSH SI PUSH DI MOV DI,[BP-2] ;MESSAGE ADDRESS ADD DI,MTNAME ;TO NAME MOV CX,MTSTMP-MTNAME ;MAX KEY LENGTH CALL BLDSTR ;BUILD NAME STRING CALL UNTAGN ;UNTAG NAME STRING MOV [BP-4],SI ;BUFFER ADDRESS MOV AX,MAILTO ;INDEX NUMBER MOV DI,[BP-2] ;MESSAGE ADDRESS MOV CX,[DI+MMNUMB] ;MESSAGE NUMBER CALL DELINX ;DELETE INDEX ENTRY MOV SI,[BP-4] ;KEY BUFFER CALL FREBUF ;FREE BUFFER POP DI POP SI POP DX POP CX POP AX DTOI90: EXITF ;--------------------------------------------------------------------- ;EXTRACT MESSAGE NUMBER AND "FROM" KEY AND PASS TO INDEX ADD ROUTINE ;ENTRY SI -> MESSAGE BUFFER ;LOCAL BP-2 MESSAGE BUFFER ; BP-4 KEY BUFFER ;--------------------------------------------------------------------- AFRINX: FRAME 2 CMP EMIXH,0 ;INDEX OPEN? JNZ AFRI00 ;YES JMP AFRI90 ;EXIT AFRI00: MOV [BP-2],SI ;A(MESSAGE BUFFER) PUSH AX PUSH CX PUSH DX PUSH SI PUSH DI MOV DI,[BP-2] ;MESSAGE ADDRESS ADD DI,MFNAME ;FROM NAME MOV CX,MTNAME-MFNAME ;MAX KEY LENGTH CALL BLDSTR ;BUILD NAME STRING CALL UNTAGN ;UNTAG NAME STRING MOV [BP-4],SI ;BUFFER ADDRESS MOV AX,MAILFROM ;INDEX NUMBER MOV DI,[BP-2] ;MESSAGE ADDRESS MOV CX,[DI+MMNUMB] ;MESSAGE NUMBER CALL ADDINX ;ADD INDEX ENTRY MOV SI,[BP-4] ;KEY BUFFER CALL FREBUF ;FREE BUFFER POP DI POP SI POP DX POP CX POP AX AFRI90: EXITF ;--------------------------------------------------------------------- ;EXTRACT MESSAGE NUMBER AND FROM KEY AND PASS TO INDEX DELETE ROUTINE ;ENTRY SI -> MESSAGE BUFFER ;LOCAL BP-2 MESSAGE BUFFER ; BP-4 KEY BUFFER ; BP-6 MESSAGE NUMBER ;--------------------------------------------------------------------- DFRINX: FRAME 3 CMP EMIXH,0 ;INDEX OPEN? JNZ DFRI00 ;YES JMP DFRI90 ;EXIT DFRI00: MOV [BP-2],SI ;A(MESSAGE BUFFER) PUSH AX PUSH CX PUSH DX PUSH SI PUSH DI MOV DI,[BP-2] ;MESSAGE ADDRESS ADD DI,MFNAME ;FROM NAME MOV CX,MTNAME-MFNAME ;MAX KEY LENGTH CALL BLDSTR ;BUILD NAME STRING CALL UNTAGN ;UNTAG NAME STRING MOV [BP-4],SI ;BUFFER ADDRESS MOV AX,MAILFROM ;INDEX NUMBER MOV DI,[BP-2] ;MESSAGE ADDRESS MOV CX,[DI+MMNUMB] ;MESSAGE NUMBER CALL DELINX ;DELETE INDEX ENTRY MOV SI,[BP-4] ;KEY BUFFER CALL FREBUF ;FREE BUFFER POP DI POP SI POP DX POP CX POP AX DFRI90: EXITF ;--------------------------------------------------------------------- ;EXTRACT MESSAGE NUMBER AND SUBJECT KEY AND PASS TO INDEX ADD ROUTINE ;ENTRY SI -> MESSAGE BUFFER ;LOCAL BP-2 MESSAGE BUFFER ; BP-4 KEY BUFFER ;--------------------------------------------------------------------- ASBINX: FRAME 2 CMP EMIXH,0 ;INDEX OPEN? JNZ ASBI00 ;YES JMP ASBI90 ;EXIT ASBI00: MOV [BP-2],SI ;A(MESSAGE BUFFER) PUSH AX PUSH CX PUSH DX PUSH SI PUSH DI MOV DI,[BP-2] ;MESSAGE ADDRESS ADD DI,MFSUBJ ;SUBJECT MOV CX,MFBPTR-MFSUBJ ;MAX KEY LENGTH CALL BLDSTR ;BUILD NAME STRING CALL UNTAGN ;UNTAG NAME STRING MOV [BP-4],SI ;BUFFER ADDRESS MOV AX,MAILSUBJ ;INDEX NUMBER MOV DI,[BP-2] ;MESSAGE ADDRESS MOV CX,[DI+MMNUMB] ;MESSAGE NUMBER CALL ADDINX ;ADD INDEX ENTRY MOV SI,[BP-4] ;KEY BUFFER CALL FREBUF ;FREE BUFFER POP DI POP SI POP DX POP CX POP AX ASBI90: EXITF ;--------------------------------------------------------------------- ;EXTRACT MESSAGE NUMBER AND SUBJECT AND PASS TO INDEX DELETE ROUTINE ;ENTRY SI -> MESSAGE BUFFER ;LOCAL BP-2 MESSAGE BUFFER ; BP-4 KEY BUFFER ; BP-6 MESSAGE NUMBER ;--------------------------------------------------------------------- DSBINX: FRAME 3 CMP EMIXH,0 ;INDEX OPEN? JNZ DSBI00 ;YES JMP DSBI90 ;EXIT DSBI00: MOV [BP-2],SI ;A(MESSAGE BUFFER) PUSH AX PUSH CX PUSH DX PUSH SI PUSH DI MOV DI,[BP-2] ;MESSAGE ADDRESS ADD DI,MFSUBJ ;SUBJECT MOV CX,MFBPTR-MFSUBJ ;MAX KEY LENGTH CALL BLDSTR ;BUILD NAME STRING CALL UNTAGN ;UNTAG NAME STRING MOV [BP-4],SI ;BUFFER ADDRESS MOV AX,MAILSUBJ ;INDEX NUMBER MOV DI,[BP-2] ;MESSAGE ADDRESS MOV CX,[DI+MMNUMB] ;MESSAGE NUMBER CALL DELINX ;DELETE INDEX ENTRY MOV SI,[BP-4] ;KEY BUFFER CALL FREBUF ;FREE BUFFER POP DI POP SI POP DX POP CX POP AX DSBI90: EXITF INDEXAM ENDP ;--------------------------------------------------------------------- ;INDEXED ACCESS METHOD SUBROUTINES ;--------------------------------------------------------------------- SUBRTNS PROC NEAR ;-------------------------------------------------------------------- ;ADD ENTRY TO INDEX ;ENTRY: AX INDEX NUMBER ; CX MESSAGE NUMBER ; SI KEY STRING ;LOCAL BP-2 INDEX SECTOR BUFFER ; BP-4 INDEX NUMBER ; BP-6 KEY STRING ; BP-8 MESSAGE NUMBER ; BP-10 UNUSED ; BP-12 NEW ENTRY LENGTH ; BP-14 CURRENT POSITION IN NODE ENTRIES ;-------------------------------------------------------------------- ADDINX: FRAME 7 MOV [BP-8],CX ;MESSAGE NUMBER MOV [BP-6],SI ;KEY STRING MOV [BP-4],AX ;INDEX NUMBER MOV INXCNT,CX ;MESSAGE NUBMER MOV AX,INXTST ;DEBUG MESSAGE NUMBER CMP AX,INXCNT ;STOP HERE? JNZ ADDIN0 ;NO ADDIDB: NOP ADDIN0: MOV CX,[SI-2] ;KEY LENGTH ADD CX,6 ;TWO LENGTH FIELDS + POINTER MOV [BP-12],CX ;NEW ENTRY LENGTH MOV SI,OFFSET EMIXRL ;INDEX FILE ROOT LOCK WORD CALL LOCKWT ;ACQUIRE LOCK ;RESTART POINT AFTER BUILD INDEX LEVEL CALL ADDI00: MOV AX,[BP-4] ;INDEX NUMBER CALL GIXNDE ;GET 1ST SEARCH NODE JNC ADDI14 ;OK SO FAR ADDI10: OR AX,AX ;EXIST? JNZ ADDI12 ;NO PROBLEM ERR 14H ;INVALID INDEX REQUEST ADDI12: CALL FREINX ;RETURN IT ADDI14: CALL GETINX ;READ NODE RECORD JC E15A ;RECORD NOT FOUND MOV [BP-2],SI ;SAVE ADDRESS MOV DX,[SI+IXNFRE] ;FREE SPACE POINTER ADD DX,SI ;INDEX INTO BUFFER MOV DI,SI ;WORK INDEX ADD DI,IXNTRY ;1ST KEY ENTRY CMP DI,DX ;EMPTY RECORD? JNZ ADDI20 ;NO - SCAN FOR MATCH TEST WORD PTR [SI+IXFLAGS],KEYSS ;SEQUENCE SET? JNZ ADDI22 ;YES - ADD NEW ENTRY E15A: CALL PRGINX ;PURGE INDEX BUFFERS ERR 15H ;INVALID INDEX STRUCTURE ADDI20: MOV [BP-14],DI ;POSITION IN ENTRY LIST MOV SI,[BP-2] ;RESTORE SECTOR POINTER CMP DI,DX ;END OF ENTRIES? JNB ADDI21 ;YES - CHECK TWIN POINTER JMP ADDI30 ;NO ADDI21: MOV AX,[SI+IXFWD] ;NEXT TWIN OR AX,AX ;EXIST? JNZ ADDI10 ;YES - CHAIN TO IT TEST WORD PTR [SI+IXFLAGS],KEYSS ;SEQUENCE SET? JNZ ADDI22 ;YES - ADD NEW ENTRY MOV AX,[DI-2] ;CHILD POINTER JMP ADDI10 ;CHAIN TO CHILD ;ADD NEW ENTRY TO SEQUENCE SET NODE ADDI22: MOV SI,[BP-6] ;KEY STRING MOV CX,[BP-12] ;NEW ENTRY LENGTH PUSH [BP-2] ;START OF BUFFER CALL INSERT ;INSERT SPACE JNC ADDI24 ;NO PROBLEM XOR AX,AX PUSH AX ;STRATEGY FLAGS PUSH [BP-4] ;INDEX NUMBER PUSH [BP-2] ;RECORD TO SPLIT PUSH DI ;SPLIT LOCATION PUSH [BP-6] ;KEY STRING PUSH [BP-8] ;MESSAGE NUMBER CALL BIXLVL ;BUILD NEW INDEX LEVEL JMP ADDI90 ;EXIT ADDI24: MOV [BP-14],DI ;POSITION IN ENTRY LIST MOV CX,[BP-12] ;NEW ENTRY LENGTH MOV [DI],CX ;SET NEW ENTRY LENGTH ADD DI,4 ;START OF STRING MOV CX,[SI-2] ;STRING LENGTH MOV [DI-2],CX ;INTO NEW ENTRY PUSH ES PUSH DS POP ES REP MOVSB ;COPY ENTRY POP ES MOV AX,[BP-8] ;MESSAGE NUMBER MOV [DI],AX ;MOVE TO ENTRY MOV SI,[BP-2] ;START OF RECORD SUB DX,SI ;CONVERT BACK TO OFFSET MOV [SI+IXNFRE],DX ;SET NEW FREE SPACE PTR CALL PUTINX ;RE-WRITE NODE ;CHECK IF INSERTING NEW KEY AT BEGINNING OF RANGE MOV DI,[BP-14] ;POSITION IN ENTRY LIST SUB DI,SI ;OFFSET TO ENTRY CMP DI,IXNTRY ;AT START? JNZ ADDI28 ;NO PROBLEM TEST WORD PTR [SI+IXFLAGS],KEYEXT ;EXTENSION BLOCK? JNZ ADDI28 ;YES - PARENT IS OK PUSH [BP-6] ;KEY STRING PUSH [SI+IXBLKNO] ;OUR NODE PUSH [SI+IXPARNT] ;PARENT NODE PUSH [BP-4] ;INDEX NUMBER CALL BUBBLE ;ADJUST HIGHER NODE RANGES ADDI28: JMP ADDI90 ;DONE ;CHECK CURRENT ENTRY FOR MATCH ADDI30: MOV SI,[BP-6] ;KEY STRING ADD DI,4 ;CURRENT KEY CALL CVLSTR ;COMPARE VL STRINGS JBE ADDI32 ;CHECK FOR SS MOV DI,[BP-14] ;START OF ENTRY CMP WORD PTR [DI],0 ;VALID LENGTH? JNZ ADDI31 ;NO PROBLEM E15B: CALL PRGINX ;PURGE INDEX BUFFERS ERR 15H ;INVALID ADDI31: ADD DI,[DI] ;POINT PAST ENTRY MOV [BP-14],DI ;UPDATE POINTER CMP DI,DX ;ANY MORE ENTRIES JB ADDI30 ;CHECK NEXT ENTRY JMP ADDI20 ;CHECK NEXT NODE ADDI32: PUSHF ;REMEMBER RESULT OF COMPARE MOV SI,[BP-2] ;NODE POINTER TEST WORD PTR [SI+IXFLAGS],KEYSS ;SEQUENCE SET? JNZ ADDI36 ;YES ;NON-TERMINAL NODE POPF JZ ADDI34 ;FOLLOW CURRENT CHAIN MOV AX,[BP-2] ;START OF BUFFER ADD AX,IXNTRY+4 ;1ST KEY STRING CMP AX,DI ;AT BEGINNING OF RECORD? JZ ADDI34 ;YES - INSERT IN 1ST NODE MOV AX,[DI-6] ;PREVIOUS CHILD POINTER JMP ADDI10 ;READ NODE ADDI34: ADD DI,[DI-2] ;POINT PAST KEY MOV AX,[DI] ;CHILD POINTER JMP ADDI10 ;NEXT NODE ;SEQUENCE SET ADDI36: POPF ;RESULTS OF STRING COMPARE JZ ADDI40 ;ADD POINTER TO CURRENT KEY MOV DI,[BP-14] ;START OF ENTRY JMP ADDI22 ;INSERT NEW KEY ;ADD POINTER TO EXISTING KEY ADDI40: MOV CX,2 ;SPACE TO INSERT ADDI42: MOV DI,[BP-14] ;START OF ENTRY ADD DI,[DI] ;POINT PAST ENTRY PUSH [BP-2] ;START OF BUFFER CALL INSERT ;INSERT FREE SPACE JNC ADDI50 ;NO PROBLEM ;SEE IF AN EXTENSION EXISTS FOR THIS KEY ADDTST: MOV AX,[SI+IXEXTN] ;EXTENSION BLOCK NODE OR AX,AX ;EXIST? JZ ADDI46 ;NO - TRY TO SPLIT RECORD JMP ADDI10 ;LINK TO EXTENSION NODE ADDI46: MOV SI,[BP-2] ;RECORD TO SPLIT MOV DI,[BP-14] ;SPLIT LOCATION MOV AX,DI SUB AX,SI ;OFFSET TO SPLIT CMP AX,IXNTRY ;1ST ENTRY? JNZ ADDI48 ;NO PROBLEM ADD DI,[DI] ;POINT PAST RECORD CMP DI,DX ;ONLY ENTRY? JB ADDI48 ;NO - GO SPLIT HERE ;BUILD EXTENSION RECORD FOR THIS KEY CALL NEWBLK ;GET EXTENSION BLOCK MOV AX,[SI+IXBLKNO] ;NEW BLOCK NUMBER MOV DI,SI ;NEW NODE IS DESTINATION MOV SI,[BP-2] ;FULL NODE MOV [SI+IXEXTN],AX ;CHAIN EXTENSION TO PARENT MOV AX,[SI+IXFLAGS] ;PARENT FLAGS OR AX,KEYEXT ;EXTENSION BLOCK MOV [DI+IXFLAGS],AX ;FLAGS SAME AS PARENT MOV AX,[SI+IXBLKNO] ;PARENT NODE MOV [DI+IXPARNT],AX ;SET IN CHILD MOV WORD PTR [DI+IXNFRE],IXNTRY ;SET EMPTY CALL PUTINX ;RE-WRITE PARENT MOV SI,DI ;EXTENSION CALL PUTINX ;RE-WRITE EXTENSION JMP ADDI00 ;TRY INSERT AGAIN ;SPLIT CURRENT NODE ADDI48: XOR AX,AX PUSH AX ;STRATEGY FLAGS PUSH [BP-4] ;INDEX NUMBER PUSH [BP-2] ;RECORD TO SPLIT PUSH DI ;SPLIT LOCATION XOR AX,AX ;NO NEW KEY PUSH AX ;KEY STRING PUSH AX ;MESSAGE NUMBER CALL BIXLVL ;BUILD NEW INDEX LEVEL JMP ADDI00 ;RETRY REQUEST ADDI50: MOV AX,[BP-8] ;MESSAGE NUMBER MOV [DI],AX ;PUT IN ENTRY MOV DI,[BP-14] ;START OF ENTRY ADD [DI],CX ;NEW ENTRY LENGTH MOV SI,[BP-2] ;START OF RECORD SUB DX,SI ;CONVERT BACK TO OFFSET MOV [SI+IXNFRE],DX ;SET NEW FREE SPACE PTR CALL PUTINX ;RE-WRITE NODE MOV AX,EMIXH ;FILE HANDLE ADDI90: MOV SI,OFFSET EMIXRL ;INDEX FILE ROOT LOCK WORD CALL UNLOCK ;FREE LOCK EXITF ;--------------------------------------------------------------------- ;BUBBLE UP THROUGH INDEX LEVELS ADJUSTING KEY RANGE AS REQUIRED ;ENTRY BP+4 INDEX NUMBER ; BP+6 PARENT NODE NUMBER ; BP+8 CHILD NODE NUMBER ; BP+10 KEY STRING ;LOCAL BP-2 SECTOR BUFFER ; BP-4 CURRENT ENTRY POSITION ;--------------------------------------------------------------------- BUBBLE: FRAME 2 PUSH AX PUSH CX PUSH DX PUSH SI PUSH DI MOV WORD PTR [BP-2],0 ;NO BUFFER YET BUBB00: CMP WORD PTR [BP+6],0 ;ROOT? JNZ BUBB10 JMP BUBB90 ;YES - EXIT BUBB10: MOV AX,[BP+6] ;NODE NUMBER CALL GETINX ;READ NODE JNC BUBB12 ;GOOD READ ERR 15H ;RECORD NOT FOUND BUBB12: MOV [BP-2],SI ;BUFFER ADDRESS ;SEARCH FOR ENTRY WITH CHILD NODE POINTER MOV DX,[SI+IXNFRE] ;FREE SPACE OFFSET ADD DX,SI ;FREE SPACE POINTER MOV AX,[BP+8] ;CHILD NODE MOV DI,SI ;WORK REG ADD DI,IXNTRY ;1ST ENTRY BUBB20: MOV [BP-4],DI ;CURRENT ENTRY POSITION ADD DI,[DI] ;POINT PAST ENTRY CMP AX,[DI-2] ;THIS ENTRY? JZ BUBB30 ;YES CMP DI,DX ;AT END? JB BUBB20 ;NO - CHECK NEXT ENTRY MOV AX,[SI+IXFWD] ;FORWARD POINTER MOV [BP+6],AX ;NEW CHAIN OR AX,AX ;EXIST? JZ BUBB28 ;NO CALL FREINX ;RELEASE BUFFER JMP BUBB10 ;CHAIN TO NEXT RECORD BUBB28: CALL PRGINX ;PURGE INDEX BUFFERS ERR 15H ;SHOULD NOT OCCUR BUBB30: MOV DI,[BP-4] ;START OF ENTRY MOV SI,[BP+10] ;KEY STRING MOV CX,[SI-2] ;STRING LENGTH ADD CX,6 ;POINTER INFO MOV AX,CX ;REMEMBER ENTRY LENGTH CMP CX,[DI] ;SAME AS CURRENT? JZ BUBB40 ;YES - JUST REPLACE SUB CX,[DI] ;SPACE TO ADD JNB BUBB32 ;GO TRY TO ADD IT NEG CX ;OOPS - MUST DELETE CALL DELETE ;DELETE OLD ENTRY JMP BUBB40 ;COPY ENTRY BUBB32: PUSH [BP-2] ;START OF BUFFER CALL INSERT ;OBTAIN SPACE JNB BUBB40 ;NO PROBLEM MOV AX,10H ;REPLACE STRING AT SPLIT PUSH AX ;STRATEGY FLAGS PUSH [BP+4] ;INDEX NUMBER PUSH [BP-2] ;RECORD TO SPLIT PUSH DI ;SPLIT LOCATION PUSH [BP+10] ;KEY STRING PUSH [BP+8] ;CHILD POINTER CALL BIXLVL ;SPLIT NODE JMP BUBB90 ;EXIT BUBB40: MOV [DI],AX ;SET NEW ENTRY LENGTH ADD DI,4 ;START OF STRING MOV CX,[SI-2] ;STRING LENGTH MOV [DI-2],CX ;INTO NEW ENTRY PUSH ES PUSH DS POP ES REP MOVSB ;COPY ENTRY POP ES MOV AX,[BP+8] ;CHILD POINTER MOV [DI],AX ;MOVE TO ENTRY ;WRITE CHANGED RECORD MOV SI,[BP-2] ;START OF BUFFER SUB DX,SI ;FREE SPACE OFFSET MOV [SI+IXNFRE],DX ;UPDATE RECORD ;CHECK FOR ESCULATION MOV DI,[BP-4] ;RESTORE POSITION MOV AX,[BP-2] ;START OF BUFFER ADD AX,IXNTRY ;1ST ENTRY CMP DI,AX ;CHANGED FIRST ENTRY? JNZ BUBB80 ;NO - DONE MOV AX,[SI+IXPARNT] ;NEXT LEVEL UP MOV [BP+6],AX ;NEW PARENT MOV AX,[SI+IXBLKNO] ;THIS NODE MOV [BP+8],AX ;NEW CHILD CALL PUTINX ;RE-WRITE RECORD JMP BUBB00 ;CHECK NEXT LEVEL BUBB80: CALL PUTINX ;RE-WRITE RECORD BUBB90: POP DI POP SI POP DX POP CX POP AX EXITF 4 ;--------------------------------------------------------------------- ;INSERT ROOM FOR CX BYTES AT DI - UPDATE FREE SPACE PTR IN DX ;ENTRY CX BYTES TO INSERT ; DX FREE SPACE POINTER ; DI POINTER TO INSERT LOCATION ; BP+4 START OF BUFFER ;RETURNS CARRY SET IF NOT ENOUGH ROOM ;--------------------------------------------------------------------- INSERT: FRAME PUSH AX MOV AX,[BP+4] ;START OF BUFFER ADD AX,IBLKSIZ ;BUFFER SIZE SUB AX,DX ;FREE SPACE POINTER CMP AX,CX ;ENOUGH ROOM? JNB INSE10 ;YES MOV AX,IBLKSIZ ;BUFFER SIZE SUB AX,IXNTRY ;1ST ENTRY CMP AX,CX ;ROOM IN EMPTY BLOCK? JNB INSE00 ;YES, ALLOW SPLIT ERR 15H ;INVALID KEY SIZE INSE00: STC ;SHOW NO SPACE JMP INSE90 ;EXIT INSE10: CMP DI,DX ;ADD AT END? JB INSE20 ;NO - GO MOVE ADD DX,CX ;NEW FREE SPACE PTR JMP INSE80 ;SKIP MOVE INSE20: PUSH SI PUSH DI PUSH CX MOV AX,CX ;SPACE TO INSERT MOV CX,DX ;END OF MOVE SUB CX,DI ;LENGTH TO MOVE DEC DX ;LAST CHAR MOV SI,DX ;TOP OF STRING TO MOVE ADD DX,AX ;ADD SPACE MOV DI,DX ;TOP OF MOVED STRING INC DX ;NEW FREE SPACE PTR PUSH ES PUSH DS POP ES STD ;MOVE TOP FIRST REP MOVSB ;MOVE ENTRIES CLD ;NORMAL MOVES POP ES POP CX POP DI POP SI INSE80: CLC ;SHOW GOOD RETURN INSE90: POP AX EXITF 1 ;--------------------------------------------------------------------- ;DELETE CX BYTES AT DI - UPDATE FREE SPACE PTR IN DX ;ENTRY CX BYTES TO DELETE ; DX FREE SPACE POINTER ; DI POINTER TO DELETE LOCATION ;--------------------------------------------------------------------- DELETE: PUSH AX MOV AX,DI ;CURRENT POSITION ADD AX,[DI] ;ADD CURRENT ENTRY LENGTH CMP AX,DX ;DELETE LAST ENTRY? JNZ DELE20 ;NO - GO MOVE SUB DX,CX ;NEW FREE SPACE PTR JMP DELE90 ;SKIP MOVE DELE20: PUSH SI PUSH DI PUSH CX MOV AX,CX ;SPACE TO DELETE MOV CX,DX ;END OF MOVE SUB CX,DI ;LENGTH TO MOVE SUB CX,AX ;LESS DELETE LENGTH SUB DX,AX ;NEW FREE SPACE POINTER MOV SI,DI ;START OF DELETED STRING ADD SI,AX ;START OF REMAINING STRING PUSH ES PUSH DS POP ES REP MOVSB ;MOVE ENTRIES POP ES POP CX POP DI POP SI DELE90: POP AX CLC ;SHOW GOOD RETURN RET ;--------------------------------------------------------------------- ;READ BLOCK FROM INDEX FILE ;ENTRY AX BLOCK NUMBER ; SI A(BUFFER) ;LOCAL BP-2 A(SECTOR BUFFER) ;--------------------------------------------------------------------- RDINDX: FRAME 1 MOV [BP-2],SI PUSH AX PUSH CX MOV SI,OFFSET EMIXL ;INDEX FILE LOCK WORD CALL LOCKWT ;ACQUIRE LOCK CALL IXSEEK ;SEEK TO BLOCK MOV SI,[BP-2] ;BUFFER ADDRESS CALL RIBUF ;READ BUFFER MOV SI,OFFSET EMIXL ;INDEX FILE LOCK WORD CALL UNLOCK ;FREE LOCK CALL YIELD POP CX POP AX MOV SI,[BP-2] ;RESTORE BUFFER POINTER EXITF ;--------------------------------------------------------------------- ;WRITE BLOCK TO INDEX FILE ;ENTRY SI A(BUFFER) ;LOCAL BP-2 A(SECTOR BUFFER) ;--------------------------------------------------------------------- WRINDX: FRAME 1 MOV [BP-2],SI MOV SI,OFFSET EMIXL ;INDEX FILE LOCK WORD CALL LOCKWT ;ACQUIRE LOCK MOV SI,[BP-2] ;RECORD POINTER MOV AX,[SI+IXBLKNO] ;BLOCK TO WRITE CALL IXSEEK ;SEEK TO BLOCK CALL WIBUF ;WRITE BUFFER MOV SI,OFFSET EMIXL ;INDEX FILE LOCK WORD CALL UNLOCK ;FREE LOCK CALL YIELD MOV SI,[BP-2] ;RESTORE BUFFER POINTER EXITF IXSEEK: PUSH AX PUSH CX PUSH DX MOV DX,IBLKSIZ ;BLOCK SIZE MUL DX ;BYTE OFFSET MOV CX,DX ;MSW MOV DX,AX ;LSW PUSH BX MOV BX,EMIXH ;FILE HANDLE MOV AX,4200H ;SEEK FILE INT 21H ;DOS CALL POP BX POP DX POP CX POP AX RET RIBUF: FRAME PUSH AX PUSH CX PUSH DX MOV AH,3FH ;READ FUNCTION MOV CX,IBLKSIZ ;BYTES TO READ MOV DX,SI ;BUFFER ADDRESS PUSH BX MOV BX,EMIXH ;FILE HANDLE INT 21H ;DOS REQUEST POP BX JNC RIBUF1 ;NO ERROR ERR 15 RIBUF1: CMP AX,CX ;GOOD READ? POP DX POP CX POP AX EXITF WIBUF: FRAME PUSH AX PUSH CX PUSH DX MOV AH,40H ;WRITE FUNCTION MOV CX,IBLKSIZ ;BYTES TO WRITE MOV DX,SI ;BUFFER ADDRESS PUSH BX MOV BX,EMIXH ;FILE HANDLE INT 21H ;DOS REQUEST POP BX JNC WIBUF1 ;NO ERROR ERR 15 WIBUF1: CMP AX,CX ;OUT OF SPACE? POP DX POP CX POP AX EXITF ;--------------------------------------------------------------------- ;ALLOCATE NEW BLOCK ;RETURNS SI SECTOR BUFFER WITH BLK NUMBER SET ;LOCAL BP-2 A(SECTOR BUFFER) ; BP-4 DFCB POINTER ;--------------------------------------------------------------------- NEWBLK: FRAME 2 PUSH AX PUSH CX PUSH DX MOV AX,-2 ;INVALID SLOT NUMBER CALL FNDINX ;GET A BUFFER SLOT MOV [BP-4],DI ;SLOT ADDRESS OR WORD PTR [DI+DFCFLAG],DFALLOC ;SHOW IN USE INC WORD PTR [DI+DFCUSE] ;INCREMENT USE COUNT MOV AX,IBLKSIZ ;SECTOR BUFFER CALL GETSBF ;GET BUFFER MOV [BP-2],SI MOV [DI+DFCBUFF],SI ;ENTER IN DFCB MOV SI,OFFSET EMIXL ;INDEX FILE LOCK WORD CALL LOCKWT ;ACQUIRE LOCK XOR DX,DX ;BYTE OFFSET MOV CX,DX ;MSW PUSH BX MOV BX,EMIXH ;FILE HANDLE MOV AX,4202H ;SEEK END OF FILE INT 21H ;DOS CALL POP BX ;FILE SIZE NOW IN DX:AX MOV CX,IBLKSIZ ;BLOCK SIZE DIV CX MOV [BP-4],AX ;BLOCK NUMBER MOV AX,[BP-4] ;BLOCK NUMBER MOV [DI+DFCSLOT],AX ;PUT IN DFCB MOV SI,[BP-2] ;BUFFER ADDRESS MOV [SI+IXBLKNO],AX ;PUT IN BUFFER CALL WIBUF ;WRITE BUFFER MOV SI,OFFSET EMIXL ;INDEX FILE LOCK WORD CALL UNLOCK ;FREE LOCK CALL YIELD MOV SI,[BP-2] ;RESTORE BUFFER POINTER POP DX POP CX POP AX EXITF ;--------------------------------------------------------------------- ;BUILD NEW INDEX LEVEL ;ENTRY BP+14 STRATEGY FLAGS ; 1 NEW BLOCK CHAINS TO LEFT ; 2 NEW ENTRY APPENDS TO ORIGINAL BLOCK ; 4 OLD BLOCK DOES NOT SPLIT ; 8 NEW INDEX LEVEL CREATED ; 10H REPLACE STRING AT SPLIT LOCATION ; BP+12 INDEX NUMBER ; BP+10 BLOCK TO SPLIT ; BP+8 ENTRY TO MOVE TO NEW BLOCK ; BP+6 ENTRY TO ADD TO NEW BLOCK ; BP+4 POINTER VALUE FOR NEW ENTRY ;RETURNS AX NEW PEER BLOCK NUMBER ; UPDATED BLOCKS WRITTEN TO FILE ;LOCAL BP-2 (UNUSED) ; BP-4 NEW PEER BLOCK NUMBER ; BP-6 NEW INTERMEDIATE NODE BUFFER ; BP-8 NEW PEER BLOCK BUFFER ; BP-10 PARENT BLOCK BUFFER ;--------------------------------------------------------------------- BIXLVL: FRAME 5 PUSH CX PUSH DX PUSH SI PUSH DI TEST WORD PTR [BP+14],10H ;REPLACE CURRENT ENTRY? JZ BIXL00 ;NO MOV SI,[BP+10] ;PASSED RECORD MOV DX,[SI+IXNFRE] ;FREE SPACE OFFSET ADD DX,SI ;FREE SPACE POINTER MOV DI,[BP+8] ;SPLIT LOCATION MOV CX,[DI] ;CURRENT ENTRY LENGTH CALL DELETE ;DELETE OLD ENTRY SUB DX,SI ;CONVERT TO OFFSET MOV [SI+IXNFRE],DX ;NEW FREE SPACE PTR BIXL00: CALL NEWBLK ;GET NEW PEER NODE MOV [BP-8],SI ;RECORD BUFFER MOV AX,[SI+IXBLKNO] ;NEW NODE NUMBER MOV [BP-4],AX ;SAVE FOR RETURN ;INITIALIZE NEW PEER MOV DI,SI ;NEW PEER MOV SI,[BP+10] ;ORIGINAL RECORD MOV WORD PTR [DI+IXNFRE],IXNTRY ;MARK EMPTY MOV AX,[SI+IXFLAGS] ;FLAGS MOV [DI+IXFLAGS],AX ;COPY TO PEER ;SEE WHERE TO SPLIT EXISTING BLOCK MOV DI,[BP+8] ;LOCATION TO SPLIT TEST WORD PTR [SI+IXFLAGS],KEYSS ;SPLITTING A NODE? JNZ BIXL10 ;NO BIXTST: NOP ;DEBUG HOOK BIXL10: MOV DX,[SI+IXNFRE] ;OFFSET TO END OF DATA ADD DX,SI ;END OF DATA ADDRESS CMP DI,DX ;SPLIT AT END? JB BIXL11 ;NO OR WORD PTR [BP+14],4 ;CHAIN NEW BLOCK TO RIGHT JMP BIXL15 BIXL11: MOV AX,SI ;START OF BLOCK ADD AX,IXNTRY ;1ST ENTRY LOCATION CMP DI,AX ;SPLIT AT BEGINNING? JNZ BIXL12 ;NO OR WORD PTR [BP+14],5 ;CHAIN NEW BLOCK TO LEFT JMP BIXL15 BIXL12: MOV AX,IBLKSIZ ;BLOCK SIZE SUB AX,IXNTRY ;1ST ENTRY SHR AX,1 ;MID POINT ADD AX,SI ;MID POINT ADDRESS CMP DI,AX ;SPLIT PAST MIDDLE? JAE BIXL15 ;YES - NEW ENTRY IN NEW BLOCK OR WORD PTR [BP+14],2 ;APPEND NEW ENTRY TO OLD BLOCK ;MOVE NEW ENTRY TO PEER BLOCK BIXL15: TEST WORD PTR [BP+14],2 ;NEW ENTRY IN OLD BLOCK? JNZ BIXL16 ;YES - DEFER MOVE PUSH [BP-8] ;NEW BLOCK BUFFER PUSH [BP+6] ;KEY STRING PUSH [BP+4] ;POINTER VALUE PUSH [BP+12] ;INDEX NUMBER CALL NEWKEY ;ADD TO NEW BLOCK ;MOVE OLD ENTRIES TO NEW PEER BIXL16: TEST WORD PTR [BP+14],4 ;SPLIT OLD BLOCK? JNZ BIXL17 ;NO MOV DI,[BP-8] ;NEW PEER BUFFER ADDRESS MOV AX,[SI+IXNFRE] ;OLD FREE SPACE PTR MOV DX,[BP+8] ;RECORD SPLIT LOCATION MOV CX,DX ;NEW FREE SPACE POINTER SUB CX,[BP+10] ;START OF BUFFER MOV WORD PTR [SI+IXNFRE],CX ;NEW FREE SPACE PTR MOV SI,DX ;START OF AREA TO MOVE MOV CX,AX ;OLD FREE SPACE PTR ADD CX,[BP+10] ;CONVERT TO ADDRESS SUB CX,DX ;LENGTH TO MOVE MOV DX,[DI+IXNFRE] ;OFFSET TO START IN PEER ADD DX,DI ;ENTRY ADDRESS TO MOVE ADD [DI+IXNFRE],CX ;NEW FREE SPACE PTR MOV DI,DX ;FOR MOVSB PUSH ES PUSH DS POP ES REP MOVSB POP ES ;CHAIN NEW PEER BLOCK TO OLD BIXL17: MOV SI,[BP+10] ;PASSED NODE MOV DI,[BP-8] ;PEER BLOCK TEST WORD PTR [BP+14],1 ;CHAIN TO LEFT? JNZ BIXL18 ;YES MOV AX,[SI+IXBLKNO] ;PASSED BLOCK NO MOV [DI+IXBKWD],AX ;BACKWARD CHAIN MOV AX,[SI+IXFWD] ;FORWARD PTR MOV [DI+IXFWD],AX ;COPY MOV AX,[DI+IXBLKNO] ;PEER BLOCK NO MOV [SI+IXFWD],AX ;FORWARD CHAIN MOV AX,[DI+IXFWD] ;ORIGINAL FORWARD PTR OR AX,AX ;EXIST? JZ BIXL19 ;NO CALL GETINX ;GET NEXT BLOCK JNC BIX17A ;GOOD READ ERR 15H ;RECORD NOT FOUND BIX17A: MOV AX,[DI+IXBLKNO] ;PEER BLOCK NO MOV [SI+IXBKWD],AX ;SET AS BACK POINTER CALL PUTINX ;RE-WRITE RECORD JMP BIXL19 BIXL18: MOV AX,[SI+IXBLKNO] ;PASSED BLOCK NO MOV [DI+IXFWD],AX ;FORWARD CHAIN MOV AX,[SI+IXBKWD] ;BACKWARD PTR MOV [DI+IXBKWD],AX ;COPY MOV AX,[DI+IXBLKNO] ;PEER BLOCK NO MOV [SI+IXBKWD],AX ;BACKWARD CHAIN MOV AX,[DI+IXBKWD] ;ORIGINAL BACKWARD PTR OR AX,AX ;EXIST? JZ BIXL19 ;NO CALL GETINX ;GET PREVIOUS BLOCK JNC BIX18A ;GOOD READ ERR 15H ;RECORD NOT FOUND BIX18A: MOV AX,[DI+IXBLKNO] ;PEER BLOCK NO MOV [SI+IXFWD],AX ;SET AS FORWARD POINTER CALL PUTINX ;RE-WRITE RECORD ;SEE IF PARENT NODE IS ROOT BIXL19: MOV SI,[BP+10] ;PASSED RECORD MOV DX,[SI+IXPARNT] ;PARENT NODE OR DX,DX ;ROOT? JZ BIXL20 ;YES - CREATE NEW NODE ;READ EXISTING PARENT NODE MOV AX,DX ;PARENT NODE CALL GETINX ;READ IT JNC BIX19A ;GOOD READ ERR 15H ;RECORD NOT FOUND BIX19A: MOV [BP-6],SI ;NODE BUFFER JMP BIXL25 ;GO INSERT KEY ;BUILD NEW INTERMEDIATE NODE BIXL20: OR WORD PTR [BP+14],8 ;SHOW NEW INDEX LEVEL CALL NEWBLK ;GET NEW NODE MOV [BP-6],SI ;REMEMBER MOV DI,SI ;BASE REG MOV SI,[BP+10] ;PASSED RECORD MOV AX,[SI+IXFLAGS] ;PASSED FLAGS AND AX,NOT KEYSS ;TURN OFF LEAF FLAG MOV [DI+IXFLAGS],AX ;SET IN NODE MOV AX,[SI+IXPARNT] ;POINTER TO PARENT MOV [DI+IXPARNT],AX ;SET IN NODE MOV AX,[DI+IXBLKNO] ;NODE BLOCK NUMBER MOV [SI+IXPARNT],AX ;SET IN PASSED RECORD MOV WORD PTR [DI+IXNFRE],IXNTRY ;MARK NODE EMPTY ;INSERT KEY FROM PASSED RECORD INTO NODE MOV AX,[SI+IXBLKNO] ;PASSED RECORD BLK NO ADD SI,IXNTRY+4 ;KEY STRING CMP WORD PTR [SI-2],0 ;NULL KEY? JNZ BIXL23 ;NO PROBLEM BIXLT0: NOP ;DEBUG HOOK BIXL23: PUSH DI ;TARGET RECORD PUSH SI ;KEY STRING PUSH AX ;PASSED RECORD BLK NO PUSH [BP+12] ;INDEX NUMBER CALL NEWKEY ;INSERT KEY ;INSERT KEY ENTRY FROM NEW PEER RECORD INTO PARENT NODE BIXL25: MOV SI,[BP-8] ;NEW PEER BLOCK MOV DI,[BP-6] ;NODE BLOCK MOV AX,[DI+IXBLKNO] ;NODE BLOCK NUMBER MOV [SI+IXPARNT],AX ;SET IN PEER RECORD MOV AX,[SI+IXBLKNO] ;PEER RECORD BLK NO ADD SI,IXNTRY+4 ;KEY STRING PUSH DI ;TARGET RECORD PUSH SI ;KEY STRING PUSH AX ;PASSED RECORD BLK NO PUSH [BP+12] ;INDEX NUMBER CALL NEWKEY ;INSERT KEY ;ADJUST PARENT POINTER FOR PASSED RECORD MOV AX,[BP+14] ;STRATEGY FLAGS AND AX,15H ;ISOLATE FLAGS OF INTEREST CMP AX,15H ;ADJUST PARENT? JNZ BIXL29 ;NOT NECESSARY MOV SI,[BP+10] ;ORIGINAL RECORD MOV AX,SI ;START OF RECORD ADD AX,IXNTRY+4 ;KEY STRING PUSH AX MOV AX,[SI+IXBLKNO] ;CHILD POINTER PUSH AX MOV AX,[SI+IXPARNT] ;PARENT POINTER PUSH AX PUSH [BP+12] ;INDEX NUMBER CALL BUBBLE ;ADJUST PARENT POINTER ;CHAIN NEW NODE TO PARENT BIXL29: TEST WORD PTR [BP+14],8 ;NEW NODE CREATED? JZ BIXL40 ;NO MOV DI,[BP-6] ;NEW NODE RECORD MOV AX,[DI+IXPARNT] ;PARENT NODE NUMBER CALL GETINX ;READ PARENT JNC BIX29A ;GOOD READ ERR 15H ;RECORD NOT FOUND BIX29A: MOV [BP-10],SI ;PARENT BLOCK CMP WORD PTR [SI+IXBLKNO],0 ;ROOT? JNZ BIXL30 ;NO ;PARENT IS ROOT MOV AX,[DI+IXBLKNO] ;THIS BLOCK MOV DI,[BP+12] ;INDEX NUMBER SHL DI,1 ;INDEX OFFSET SHL DI,1 ADD DI,IXKEYL ;OFFSET TO KEY LIST ADD DI,SI ;INDEX INTO RECORD MOV [DI+2],AX ;NEW 1ST NODE FOR THIS KEY JMP BIXL40 ;PARENT IS NON-ROOT BIXL30: MOV AX,[DI+IXBLKNO] ;THIS BLOCK MOV DI,[DI+IXNTRY] ;NODE 1ST ENTRY ADD DI,[DI] ;POINT PAST ENTRY MOV CX,[DI-2] ;1ST CHILD PTR MOV DI,SI ;START OF RECORD ADD DI,IXNTRY ;1ST ENTRY MOV DX,[SI+IXNFRE] ;FREE SPACE OFFSET ADD DX,SI ;FREE SPACE POINTER BIXL32: CMP DI,DX ;END OF ENTRIES? JAE BIXL40 ;YES - DONE ADD DI,[DI] ;POINT PAST ENTRY CMP CX,[DI-2] ;THIS ENTRY? JNZ BIXL32 ;NO - CHECK NEXT ENTRY MOV [DI-2],AX ;SET NEW POINTER ;APPEND NEW RECORD TO ORIGINAL NODE BIXL40: TEST WORD PTR [BP+14],2 ;APPEND NEW ENTRY? JZ BILX42 ;NO PUSH [BP+10] ;ORIGINAL BLOCK BUFFER PUSH [BP+6] ;KEY STRING PUSH [BP+4] ;POINTER VALUE PUSH [BP+12] ;INDEX NUMBER CALL NEWKEY ;ADD TO NEW BLOCK ;CLEAR MOVED RECORDS IN ORIGINAL NODE BILX42: MOV DI,[BP+10] ;PASSED RECORD ADD DI,[DI+IXNFRE] ;START OF FREE SPACE MOV CX,IBLKSIZ ;RECORD SIZE ADD CX,[BP+10] ;END OF RECORD SUB CX,DI ;LENGTH TO MOVE XOR AX,AX ;CLEAR TO ZEROS JCXZ BIXL50 ;NOTHING TO CLEAR BIXL45: MOV [DI],AL ;CLEAR BYTE INC DI ;NEXT POSITION LOOP BIXL45 ;KEEP IT MOVING ;RE-WRITE RECORDS - ORDER IS IMPORTANT FOR SAFETY BIXL50: MOV SI,[BP-8] ;NEW PEER BLOCK CALL PUTINX ;UPDATE FILE MOV SI,[BP-6] ;NEW NODE BLOCK CALL PUTINX ;UPDATE FILE TEST WORD PTR [BP+14],8 ;NEW NODE CREATED? JZ BIXL52 ;NO - PARENT NOT READ MOV SI,[BP-10] ;PARENT BLOCK CALL PUTINX ;UPDATE FILE BIXL52: MOV SI,[BP+10] ;PASSED BLOCK TEST WORD PTR [SI+IXFLAGS],KEYSS ;SEQUENCE SET? JNZ BIXL80 ;YES - DONE ;MUST UPDATE PARENT POINTER FOR EACH NODE OWNED BY NEW NODE MOV AX,[SI+IXFWD] ;NEW PEER BLOCK TEST WORD PTR [BP+14],1 ;NEW BLOCK CHAIN TO LEFT? JZ BIXL55 ;NO PROBLEM MOV AX,[SI+IXBKWD] ;NEW PEER BLOCK BIXL55: CALL GETINX ;READ RECORD JNC BIXL56 ;GOOD READ ERR 15H ;RECORD NOT FOUND BIXL56: MOV [BP-8],SI ;REMEMBER WHERE MOV CX,[SI+IXBLKNO] ;OUR BLOCK # MOV DX,[SI+IXNFRE] ;FREE SPACE OFFSET ADD DX,SI ;FREE SPACE POINTER MOV DI,SI ;START OF RECORD ADD DI,IXNTRY ;1ST ENTRY ;LOOP THROUGH ENTRIES, UPDATING CHILD RECORDS BIXL60: CMP DI,DX ;DONE? JAE BIXL70 ;YES - FREE RESOURCES ADD DI,[DI] ;POINT PAST ENTRY MOV AX,[DI-2] ;GET CHILD POINTER CALL GETINX ;READ RECORD JNC BIXL65 ;GOOD READ ERR 15H ;RECORD NOT FOUND BIXL65: MOV [SI+IXPARNT],CX ;SET NEW PARENT CALL PUTINX ;RE-WRITE RECORD JMP BIXL60 ;CHECK NEXT ENTRY BIXL70: MOV SI,[BP-8] ;OTHER WORK BUFFER CALL FREINX ;FREE IT TOO BIXL80: MOV SI,[BP+10] ;ORIGINAL BLOCK CALL PUTINX ;UPDATE FILE BIXL90: MOV AX,[BP-4] ;NEW PEER BLOCK POP DI POP SI POP DX POP CX EXITF 6 ;-------------------------------------------------------------------- ;INSERT NEW KEY INTO LIST ;ENTRY BP+4 INDEX NUMBER ; BP+6 POINTER VALUE ; BP+8 KEY STRING ; BP+10 TARGET NODE ;RETURNS UPDATED NODE BLOCKS ;LOCAL BP-2 CURRENT LIST POINTER ; BP-4 CURRENT NODE BUFFER ;-------------------------------------------------------------------- NEWKEY: FRAME 2 PUSH AX PUSH CX PUSH DX PUSH SI PUSH DI MOV DI,[BP+10] ;TARGET NODE MOV AX,[DI+IXBLKNO] ;NODE NUMBER CMP WORD PTR [BP+8],0 ;EMPTY STRING? JNZ NEWK00 ;NO PROBLEM JMP NEWK90 ;EXIT NEWK00: CALL GETINX ;GET RECORD JNC NEWK01 ;GOOD READ ERR 15H ;RECORD NOT FOUND NEWK01: MOV [BP-4],SI ;SAVE ADDRESS MOV DI,SI ;START OF BUFFER MOV DX,[DI+IXNFRE] ;FREE SPACE OFFSET ADD DX,DI ;FREE SPACE POINTER ADD DI,IXNTRY ;START OF ENTRIES MOV [BP-2],DI ;CURRENT POSITION CMP DI,DX ;EMPTY RECORD? JZ NEWK40 ;YES - ADD TO BEGINNING ;POINT TO START OF ENTRIES ;CHECK CURRENT ENTRY FOR MATCH NEWK10: MOV SI,[BP+8] ;KEY STRING ADD DI,4 ;CURRENT KEY CALL CVLSTR ;COMPARE VL STRINGS JB NEWK40 ;INSERT GOES HERE JNZ NEWK20 ;CHECK NEXT ENTRY ;DUPLICATE KEY LOGIC GOES HERE - FOR NOW ADD NEW KEY AFTER CURRENT NEWKDB: NOP ;DEBUG HOOK MOV DI,[BP-2] ;START OF ENTRY CMP WORD PTR [DI],0 ;VALID LENGTH? JZ E15K ;NO ADD DI,[DI] ;POINT PAST ENTRY MOV [BP-2],DI ;UPDATE POINTER JMP NEWK40 ;GO INSERT NEWK20: MOV DI,[BP-2] ;START OF ENTRY CMP WORD PTR [DI],0 ;VALID LENGTH? JNZ NEWK30 ;NO PROBLEM E15K: CALL PRGINX ;PURGE INDEX BUFFERS ERR 15H ;INVALID NEWK30: ADD DI,[DI] ;POINT PAST ENTRY MOV [BP-2],DI ;UPDATE POINTER CMP DI,DX ;ANY MORE ENTRIES JB NEWK10 ;CHECK NEXT ENTRY MOV SI,[BP-4] ;RESTORE SECTOR POINTER MOV AX,[SI+IXFWD] ;NEXT TWIN OR AX,AX ;EXIST? JZ NEWK40 ;NO - TRY INSERT AT END CALL FREINX ;RELEASE BUFFER JMP NEWK00 ;CHAIN TO TWIN NEWK40: MOV DI,[BP-2] ;INSERT LOCATION MOV SI,[BP+8] ;KEY STRING MOV CX,[SI-2] ;KEY LENGTH ADD CX,6 ;NEW ENTRY LENGTH PUSH [BP-4] ;START OF BUFFER CALL INSERT ;INSERT SPACE JNC NEWK50 ;NO PROBLEM XOR AX,AX PUSH AX ;STRATEGY FLAGS PUSH [BP+4] ;INDEX NUMBER PUSH [BP-4] ;RECORD TO SPLIT PUSH DI ;SPLIT LOCATION PUSH [BP+8] ;KEY STRING PUSH [BP+6] ;NODE POINTER CALL BIXLVL ;BUILD NEW INDEX LEVEL NEWTST: JMP NEWK90 ;EXIT REQUEST NEWK50: MOV [BP-2],DI ;POSITION IN ENTRY LIST MOV [DI],CX ;SET NEW ENTRY LENGTH ADD DI,4 ;START OF STRING MOV CX,[SI-2] ;STRING LENGTH MOV [DI-2],CX ;INTO NEW ENTRY PUSH ES PUSH DS POP ES REP MOVSB ;COPY ENTRY POP ES MOV AX,[BP+6] ;MESSAGE NUMBER MOV [DI],AX ;MOVE TO ENTRY MOV SI,[BP-4] ;START OF RECORD SUB DX,SI ;CONVERT BACK TO OFFSET MOV [SI+IXNFRE],DX ;SET NEW FREE SPACE PTR MOV DI,[BP-2] ;INSERT POSITION SUB DI,IXNTRY ;OFFSET TO 1ST ENTRY CMP SI,DI ;WAS INSERT AT BEGINNING? JNZ NEWK80 ;NO -EXIT PUSH [BP+8] ;KEY STRING PUSH [SI+IXBLKNO] ;THIS NODE PUSH [SI+IXPARNT] ;PARENT NODE PUSH [BP+4] ;INDEX NUMBER CALL BUBBLE ;ADJUST PARENT NODE POINTER NEWK80: CALL PUTINX ;RETURN IT NEWK90: POP DI POP SI POP DX POP CX POP AX EXITF 4 ;--------------------------------------------------------------------- ;COMPARE TWO STRINGS OF DIFFERENT LENGTHS ;--------------------------------------------------------------------- CVLSTR: PUSH CX MOV CX,[SI-2] ;1ST STRING LENGTH CMP CX,[DI-2] ;1ST STRING LONGER? JBE CVLS10 ;NO - USE 1ST STRING LENGTH MOV CX,[DI-2] ;USE 2ND STRING LENGTH CVLS10: JCXZ CVLS20 ;SPECIAL CASE PUSH SI PUSH DI PUSH ES PUSH DS POP ES REPZ CMPSB ;COMPARE STRINGS POP ES POP DI POP SI JNZ CVLS90 ;RETURN RESULT CVLS20: MOV CX,[SI-2] ;1ST STRING LENGTH CMP CX,[DI-2] ;1ST STRING LONGER? CVLS90: POP CX RET ;--------------------------------------------------------------------- ;BUILD A STRING FROM BUFFER TEXT ;ENTRY CX TEXT LENGTH ; DI TEXT OFFSET ;RETURNS SI STRING ADDRESS ;LOCAL BP-2 STRING BUFFER ;--------------------------------------------------------------------- BLDSTR: FRAME 1 PUSH AX PUSH CX PUSH DX PUSH DI MOV AX,CX ;STRING SIZE CALL GETBUF ;GET BUFFER MOV [BP-2],SI ;STRING BUFFER XOR DX,DX ;LENGTH COUNTER BLDS10: MOV AL,[DI] ;GET NEXT CHAR CMP AL,'(' ;SPECIAL TAG? JZ BLDS20 MOV [SI],AL ;MOVE CHARACTER INC SI INC DI INC DX LOOP BLDS10 BLDS20: MOV SI,[BP-2] ;KEY BUFFER MOV [SI-2],DX ;SET LENGTH CALL STRIP ;SET CORRECT SIZE POP DI POP DX POP CX POP AX EXITF ;--------------------------------------------------------------------- ;UNTAG NAME STRING ;ENTRY SI STRING TO BE FILTERED ;--------------------------------------------------------------------- UNTAGN: FRAME PUSH AX PUSH CX PUSH DI MOV DI,SI ;TARGET STRING MOV AX,80 ;MORE THAN ENOUGH CALL GETBUF ;GET WORK BUFFER MOV AX,184 ;'SYSOP' CALL MOVMSG ;MOVE TO BUFFER CALL STRIP ;TRIM TRAILING BLANKS MOV AX,[DI-2] ;LENGTH OF NAME STRING MOV CX,[SI-2] ;LENGTH OF TEST STRING CALL INSTRG ;SYSOP IN STRING? JC UNTA00 ;NO - EXIT MOV [DI-2],AX ;SET NEW LENGTH UNTA00: CALL FREBUF ;FREE IT MOV SI,DI ;TARGET STRING POP DI POP CX POP AX EXITF ;--------------------------------------------------------------- ;MESSAGE INDEX FILE SUBROUTINES ; INPUT AX = INDEX NODE NUMBER ; OUTPUT SI -> INDEX RECORD OR ZERO ; CARRY = 0 IF NO ERROR ; LOCAL STORAGE ; BP-2 INDEX NODE NUMBER ; BP-4 DFCB ENTRY POINTER ;--------------------------------------------------------------- GETINX: FRAME 2 MOV [BP-2],AX ;SAVE PASSED PARM PUSH BX PUSH CX PUSH DX PUSH DI CALL FNDINX ;FIND USER ENTRY MOV [BP-4],DI ;DFCB POINTER INC WORD PTR [DI+DFCUSE] ;INCREMENT USE COUNT JNC GETI30 ;RECORD ALREADY IN BUFFER MOV [DI+DFCSLOT],AX ;ENTER SLOT NUMBER OR WORD PTR [DI+DFCFLAG],DFALLOC ;SHOW IN USE MOV AX,IBLKSIZ ;INDEX RECORD SIZE CALL GETSBF ;GET SYSTEM BUFFER MOV [DI+DFCBUFF],SI ;ENTER IN DFCB MOV AX,[BP-2] ;NODE NUMBER CALL RDINDX ;READ RECORD INTO BUFFER JZ GETI30 ;GOOD READ CALL FREFCB ;FREE ENTRY STC ;SHOW END OF FILE JMP GETI90 ;EXIT GETI30: MOV SI,[DI+DFCBUFF] ;LOAD BUFFER ADDRESS MOV AX,[BP-2] ;RESTORE SLOT # CMP WORD PTR [DI+DFCUSE],1 ;ONLY ONE USER? JZ GETI90 ;NO PROBLEM GETIDB: NOP ;DEBUG HOOK CLC ;SHOW GOOD RETURN GETI90: POP DI POP DX POP CX POP BX EXITF PUTINX: FRAME 1 PUSH AX PUSH BX PUSH CX PUSH DX PUSH DI MOV AX,[SI+IXBLKNO] ;BLOCK NUMBER MOV [BP-2],AX ;SAVE PASSED PARM CALL FNDINX ;FIND USER SLOT JNC PUTI10 ;FOUND IT ERR 702H PUTI10: OR WORD PTR [DI+DFCFLAG],DFDIRTY ;MARK CHANGED TEST EMIXF,40H ;LAZY WRITE? JNZ PUTI15 ;DEFER WRITE MOV SI,[DI+DFCBUFF] ;BUFFER ADDRESS CALL WRINDX ;WRITE RECORD AND WORD PTR [DI+DFCFLAG],NOT DFDIRTY ;CLEAR CHANGE FLAG PUTI15: DEC WORD PTR [DI+DFCUSE] ;REDUCE USE COUNT JNS PUTI20 PUTIDB: NOP ;DEBUG HOOK MOV WORD PTR [DI+DFCUSE],0 ;TEMP FIX PUTI20: POP DI POP DX POP CX POP BX POP AX EXITF UPDINX: FRAME 2 PUSH AX PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI MOV AX,[SI+IXBLKNO] ;BLOCK NUMBER MOV [BP-2],AX ;SAVE PASSED PARM CALL FNDINX ;FIND USER SLOT JNC UPDI10 ;FOUND IT ERR 702H UPDI10: OR WORD PTR [DI+DFCFLAG],DFDIRTY ;MARK CHANGED TEST EMIXF,40H ;LAZY WRITE? JNZ UPDI15 ;DEFER WRITE MOV SI,[DI+DFCBUFF] ;BUFFER ADDRESS CALL WRINDX ;WRITE RECORD AND WORD PTR [DI+DFCFLAG],NOT DFDIRTY ;CLEAR CHANGE FLAG UPDI15: POP DI POP SI POP DX POP CX POP BX POP AX MOV SP,BP ;FREE LOCAL STORAGE POP BP ;RESTORE CALLER'S FRAME RET FREINX: FRAME 2 PUSH AX PUSH BX PUSH CX PUSH DX PUSH DI MOV AX,[SI+IXBLKNO] ;BLOCK NUMBER MOV [BP-2],AX ;SAVE SLOT NUMBER CALL FNDINX ;FIND USER SLOT JNC FREI10 ;FOUND IT FREIDB: NOP ;DEBUG HOOK JMP PUTI20 ;NOT IN TABLE - IGNORE FREI10: MOV SI,[DI+DFCBUFF] ;BUFFER ADDRESS JMP PUTI15 ;ENTER COMMON CODE ;--------------------------------------------------------------------- ;TRMINX TRIM LOW USAGE BLOCKS FROM DFCB ;--------------------------------------------------------------------- TRMINX: FRAME PUSH AX PUSH CX PUSH DX PUSH SI MOV DI,EMDFCB ;POINT TO DFCB MOV CX,[DI] ;ENTRY COUNT ADD DI,DFC1STE ;1ST DFCB ENTRY XOR DX,DX ;NO EMPTY ENTRY YET TRMI20: TEST WORD PTR [DI+DFCFLAG],DFALLOC ;ENTRY IN USE? JZ TRMI30 ;NO CMP WORD PTR [DI+DFCUSE],0 ;PURGE THIS ENTRY? JNZ TRMI30 ;NO CMP WORD PTR [DI+DFCSLOT],0 ;ROOT BLOCK? JZ TRMI30 ;YES - DON'T PURGE MOV SI,[DI+DFCBUFF] ;BUFFER ADDRESS TEST WORD PTR [SI+IXFLAGS],KEYSS ;SEQUENCE SET? JZ TRMI30 ;NO - DON'T PURGE NODE OR DX,DX ;FOUND PURGED SLOT YET? JNZ TRMI25 ;YES - KEEP IT MOVING MOV DX,DI ;REMEMBER EMPTY SLOT TRMI25: TEST WORD PTR [DI+DFCFLAG],DFDIRTY ;BEEN CHANGED? JZ TRMI28 ;NO MOV SI,[DI+DFCBUFF] ;BUFFER ADDRESS CALL WRINDX ;WRITE RECORD TRMI28: CALL FREFCB ;FREE ENTRY TRMI30: ADD DI,DFCSIZE ;NEXT ENTRY LOOP TRMI20 ;TRY AGAIN MOV AX,EMIXH ;FILE HANDLE CALL FEOF ;TCLOSE FILE MOV DI,DX ;PURGED ENTRY OR DI,DI ;SET FLAGS POP SI POP DX POP CX POP AX EXITF ;--------------------------------------------------------------------- ;PRGINX PURGE UNUSED BLOCKS FROM DFCB ;--------------------------------------------------------------------- PRGINX: FRAME PUSH AX PUSH CX PUSH DX PUSH SI MOV DI,EMDFCB ;POINT TO DFCB OR DI,DI ;EXIST? JNZ PRGI10 ;NO PROBLEM JMP PRGI90 PRGI10: MOV CX,[DI] ;ENTRY COUNT ADD DI,DFC1STE ;1ST DFCB ENTRY XOR DX,DX ;NO EMPTY ENTRY YET PRGI20: TEST WORD PTR [DI+DFCFLAG],DFALLOC ;ENTRY IN USE? JZ PRGI30 ;NO CMP WORD PTR [DI+DFCUSE],0 ;PURGE THIS ENTRY? JNZ PRGI30 ;NO OR DX,DX ;FOUND PURGED SLOT YET? JNZ PRGI25 ;YES - KEEP IT MOVING MOV DX,DI ;REMEMBER EMPTY SLOT PRGI25: TEST WORD PTR [DI+DFCFLAG],DFDIRTY ;BEEN CHANGED? JZ PRGI28 ;NO MOV SI,[DI+DFCBUFF] ;BUFFER ADDRESS CALL WRINDX ;WRITE RECORD PRGI28: CALL FREFCB ;FREE ENTRY PRGI30: ADD DI,DFCSIZE ;NEXT ENTRY LOOP PRGI20 ;TRY AGAIN MOV AX,EMIXH ;FILE HANDLE CALL FEOF ;TCLOSE FILE MOV DI,DX ;PURGED ENTRY OR DI,DI ;SET FLAGS PRGI90: POP SI POP DX POP CX POP AX EXITF ;--------------------------------------------------------------------- ;FNDINX - FIND ENTRY IN DFCB ;--------------------------------------------------------------------- FNDINX: PUSH CX PUSH DX CMP EMDFCB,0 ;DFCB EXIST? JNZ FNDI10 ;YES PUSH AX PUSH SI MOV AX,DFCNTRS ;NUMBER OF DFCB ENTRIES PUSH AX MOV CX,DFCSIZE ;ENTRY SIZE MUL CX ;SIZE FOR ENTRIES ADD AX,DFCHSIZ ;PREAMBLE SIZE CALL GETSBF ;ALLOCATE STORAGE MOV EMDFCB,SI ;REMEMBER WHERE POP AX MOV WORD PTR [SI],AX ;SET NUMBER OF ENTRIES POP SI POP AX FNDI10: MOV DI,EMDFCB ;POINT TO DFCB MOV CX,[DI] ;ENTRY COUNT XOR DX,DX ;NO AVAILABLE SLOT YET ADD DI,DFC1STE ;1ST DFCB ENTRY FNDI20: TEST WORD PTR [DI+DFCFLAG],DFALLOC ;ENTRY ALLOCATED? JNZ FNDI25 ;YES OR DX,DX ;FOUND EMPTY SLOT YET? JNZ FNDI30 ;YES - KEEP IT MOVING MOV DX,DI ;REMEMBER EMPTY SLOT JMP FNDI30 ;CHECK NEXT ENTRY FNDI25: CMP [DI+DFCSLOT],AX ;THIS ENTRY? JZ FNDI90 ;YES - EXIT FNDI30: ADD DI,DFCSIZE ;NEXT ENTRY LOOP FNDI20 ;TRY AGAIN MOV DI,DX ;1ST EMPTY SLOT OR DI,DI ;FIND ONE? JNZ FNDI40 ;YES - SET STATUS CALL TRMINX ;TRIM INDEX ENTRIES JNZ FNDI40 ;ENTRY NOW AVAILABLE CALL PRGINX ;PURGE UNUSED ENTRIES JNZ FNDI40 ;ENTRY NOW AVAILABLE ERR 702H ;SHOULD NOT OCCUR FNDI40: STC ;SHOW ENTRY NOT FOUND FNDI90: POP DX POP CX RET ;--------------------------------------------------------------------- ;FREFCB FREE DFCB ENTRY ;INPUT SI A(INDEX RECORD) ; DI A(DFCB ENTRY) ;RETURNS SI,AX 0 ;--------------------------------------------------------------------- FREFCB: PUSH AX PUSH CX PUSH DI MOV SI,[DI+DFCBUFF] ;BUFFER ADDRESS CALL FREBUF ;FREE BUFFER MOV CX,3 ;ENTRY LENGTH XOR AX,AX ;FILL CHAR push es push ds pop es REP STOSW ;CLEAR ENTRY pop es MOV SI,AX ;SHOW RECORD GONE POP DI POP CX POP AX RET ;--------------------------------------------------------------------- ; BLDKEY(INDEX,FLAGS) BUILD INDEX STRUCTURE FOR NEW KEY ;ENTRY BP+4 FLAGS ; BP+6 INDEX # ;LOCAL BP-2 LEAF BUFFER ; BP-4 NODE BUFFER ; BP-6 ROOT BUFFER ;--------------------------------------------------------------------- BLDKEY: FRAME 3 PUSH AX PUSH DX PUSH SI PUSH DI MOV AX,0 ;ROOT BLOCK NUMBER CALL GETINX ;ADDRESS IT MOV [BP-6],SI ;REMEMBER CALL NEWBLK ;GET 1ST NODE MOV [BP-4],SI ;REMEMBER MOV DX,[SI+IXBLKNO] ;NODE BLOCK NUMBER CALL NEWBLK ;GET 1ST LEAF MOV [BP-2],SI ;REMEMBER MOV AX,[BP+4] ;FLAGS OR AX,KEYSS ;MARK AS LEAF MOV WORD PTR [SI+IXFLAGS],AX ;FLAGS MOV WORD PTR [SI+IXPARNT],DX ;NODE NUMBER MOV WORD PTR [SI+IXNFRE],IXNTRY ;EMPTY NODE MOV DX,[SI+IXBLKNO] ;LEAF BLOCK NUMBER CALL PUTINX ;WRITE NEW LEAF MOV SI,[BP-4] ;NODE BUFFER MOV AX,[BP+4] ;FLAGS MOV WORD PTR [SI+IXFLAGS],AX ;FLAGS MOV WORD PTR [SI+IXNFRE],IXNTRY+6 ;NULL ENTRY ONLY MOV DI,SI ;WORK REGISTER ADD DI,IXNTRY ;START OF ENTRIES MOV WORD PTR [DI],6 ;NULL ENTRY LENGTH MOV WORD PTR [DI+2],0 ;NULL STRING LENGTH MOV WORD PTR [DI+4],DX ;CHILD POINTER MOV DX,[SI+IXBLKNO] ;NODE BLOCK NUMBER CALL PUTINX ;WRITE NEW NODE MOV SI,[BP-6] ;ROOT BUFFER MOV DI,[BP+6] ;INDEX NUMBER SHL DI,1 SHL DI,1 ADD DI,IXKEYL ;OFFSET TO INDEX NUMBER ADD DI,SI ;INDEX INTO RECORD MOV [DI+2],DX ;1ST NODE FOR THIS INDEX MOV AX,[BP+4] ;FLAGS MOV [DI],AX ;FLAGS FOR THIS INDEX INC WORD PTR [SI+IXNKEYS] ;NUMBER OF INDICES DEFINED CALL PUTINX ;UPDATE ROOT POP DI POP SI POP DX POP AX EXITF 2 ;--------------------------------------------------------------------- ; GIXNDE GET 1ST NODE NUMBER FOR A GIVEN INDEX NUMBER ; ; INPUT AX INDEX NUMBER ; RETURNS AX NODE NUMBER IF C=0 ;--------------------------------------------------------------------- GIXNDE: PUSH SI PUSH DI MOV DI,AX ;INDEX NUMBER SHL DI,1 ;INDEX OFFSET SHL DI,1 ADD DI,IXKEYL ;OFFSET TO KEY LIST MOV AX,0 ;ROOT BLOCK CALL GETINX ;READ INDEX RECORD ADD DI,SI ;INDEX INTO RECORD MOV AX,[DI+2] ;1ST NODE FOR THIS KEY CALL FREINX ;RELEASE ROOT CMP AX,1 ;EXIST? POP DI POP SI RET SUBRTNS ENDP CSEG ENDS END