📄 nhstutil.asm
字号:
; the current block (pointed by SI).
; If both are unallocated, then combine and try again.
SS_SCAN_NEXT:
MOV CX,[DI] ;get header of next string entry
TEST CL,1 ;test if next entry is allocated
JZ SS_SCAN_TRY_ALLOC ;if so, then try allocation with current
INC CX ;get length of string header and data
JZ SS_SCAN_TRY_FINAL ;if string end, then try final allocation
ADD AX,CX ;add entry length to current header value
ADD DI,CX ;move the next block pointer along
JMP SHORT SS_SCAN_NEXT ;and continue the scanning
; Check entry at SI (with header AX) for sufficient room.
; If not enough, compute the pointer to the entry after the
; allocated one that stopped the combining.
SS_SCAN_TRY_ALLOC:
MOV [SI],AX ;update the header in the current entry
CMP AX,BX ;compare current header with needed one
JAE SS_SCAN_ALC ;if enough room, then finish allocation
MOV AX,CX ;move header (descriptor) of allocated entry
MOV SI,DI ;skip past allocated entry pointed by DI
; Compute pointer after the allocated entry at SI whose descriptor
; is pointed by AX.
SS_SCAN_SKIP:
MOV DI,AX ;move descriptor pointer for referencing
ADD SI,[DI] ;add length of string to pointer
ADD SI,3 ;add 2 for header and 1 for even roundup
AND SI,NOT 1 ;finish roundup process
CMP SI,DX ;test new pointer to scan finish
JBE SS_SCAN_START ;if not finished, then try again
; The scan has failed, set carry and return.
; Set DX to string space end since last entry was allocated.
SS_SCAN_FAILED:
MOV DX,SI ;points to string space end
STC ;set carry to show failure
RET ;and return to caller
; Try a final allocation. If the allocation fails, then scan fails.
SS_SCAN_TRY_FINAL:
MOV [SI],AX ;update current string entry
CMP AX,BX ;compare current header with needed one
JNAE SS_SCAN_BYPASS ;if not enough room, bypass long jump
SS_SCAN_ALC:
MOV [b$STRING_FREE],SI ;set scanned entry as free string
JMP SS_ALC ;if room, jump to finish allocation
SS_SCAN_BYPASS:
MOV DX,SI ;point to last unallocated entry
RET ;return to caller with carry set
PAGE
;***
; B$STCPCT - compact string space
; Purpose:
; Compacts all allocated strings to the bottom of string space.
; The string descriptors referenced by the string header are
; adjusted to reflect their movement.
; The remaining unallocated space is made into the free string.
;
; Inputs:
; None.
; Outputs:
; None.
; Modifies:
; None.
; Exceptions:
; B$ERR_SSC - nontrappable error if compaction finds corruption
; in string space structure.
;****
B$STCPCT:
PUSH AX ;save registers used...
PUSH BX
PUSH CX
PUSH SI
PUSH DI
PUSH ES
PUSH DS
POP ES ;Set ES = DS
MOV SI,[b$STRING_FIRST] ;pointer to string scan
; Skip over leading allocated entries which can be ignored since
; they will not be moved.
SS_CPCT_SKIP:
MOV BX,[SI] ;get header of scanned string entry
TEST BL,1 ;test if entry is allocated
JNZ SS_CPCT_FIRST_FREE ;if not allocated, skipping is over
; Entry is allocated. First test for backpointer consistency.
MOV AX,[BX+2] ;get descriptor pointer to string data
SUB AX,2 ;adjust to point to string header
CMP AX,SI ;test for backpointer consistency
JNE SSC_ERR ; if not, signal string space corruption
; Compute from descriptor string length the entry length and
; therefore, the next string entry. Jump to process this new entry
ADD SI,[BX] ;add string length from descriptor
ADD SI,3 ;add 2 for header length and 1 for roundup
AND SI,NOT 1 ;complete roundup to next word
JMP SHORT SS_CPCT_SKIP ;and try again for next entry
; First unallocated string found. Initialize compacted pointer DI.
SS_CPCT_FIRST_FREE:
MOV DI,SI ;SI=scan pointer - DI=compacted pointer
; Unallocated entry encountered in scan. First test if string space
; end (0FFFFH) and if so, jump to finish up. Otherwise advance the
; scan pointer SI by the entry size.
SS_CPCT_NEXT_FREE:
INC BX ;entry size from header value (hdr+size)
JZ SS_CPCT_END ;if it was 0FFFFH, then jump for end
ADD SI,BX ;advance scan pointer to next entry
; Process next entry at scan pointer SI. If entry unallocated, jump
; to process it above.
SS_CPCT_NEXT_STRING:
MOV BX,[SI] ;get header of scanned entry
TEST BL,1 ;test if entry is allocated
JNZ SS_CPCT_NEXT_FREE ;if not, then jump to advance scan pointer
; Entry is allocated. First test for backpointer consistency.
MOV AX,[BX+2] ;get string data offset from descriptor
SUB AX,2 ;adjust to point to string entry
CMP AX,SI ;test for consistency
JNE SSC_ERR ; jump to process corruption error
; Allocated entry at SI must be moved down to compacted space at DI.
; First adjust descriptor pointer from SI+2 to DI+2.
MOV AX,DI ;get compacted space pointer
ADD AX,2 ;point to new data portion of moved string
MOV [BX+2],AX ;and move it to the descriptor pointer
; Move the string entry at SI to DI.
MOV CX,[BX] ;get length of string to move
ADD CX,3 ;add 2 for header and 1 for roundup
SHR CX,1 ;length of entry in words
REP MOVSW ;move the string - SI and DI updated
JMP SHORT SS_CPCT_NEXT_STRING ;jump to process next entry
; String space end encountered. Put space between pointers SI and
; DI into one unallocation string entry and make it the free string.
SS_CPCT_END:
SUB SI,DI ;get length of new free string entry at DI
JE SS_CPCT_NO_FREE ;if no space, then just update [b$STRING_FREE]
DEC SI ;new value of header (string data + 1)
MOV [DI],SI ;move in new free string header
SS_CPCT_NO_FREE:
MOV [b$STRING_FREE],DI ;update new free string pointer
; Finished with compaction - restore registers and return.
POP ES
POP DI ;restore registers...
POP SI
POP CX
POP BX
POP AX
RET ;return to caller
SSC_ERR:
JMP B$ERR_SSC ;[23]
PAGE
;***
; B$STMOV - move string space
; Purpose:
; Moves string space to the offset specified in AX. String space
; start [b$STRING_FIRST] is now set to AX and the free string entry
; is adjusted since the string space end at [b$STRING_END] remains
; as the same value. The space is returned compacted.
;
; Inputs:
; SI = offset for new string space start.
; Outputs:
; CF = 0 - no error
; 1 - error, not enough memory for move
; Modifies:
; None.
; Exceptions:
; B$ERR_SSC - nontrappable error if compaction finds corruption
; in string space structure.
;****
B$STMOV:
PUSH AX ;save registers...
PUSH SI
; Determine if string space is to be expanded, contracted, or
; neither.
MOV AX,[b$STRING_FIRST] ;get present start of string space
CMP SI,AX ;test new start with present start offset
JE MOVSTR_COMPACT ;if no difference, then just return
JB MOVSTR_DOWN ;if less, then expand space
; Contract string space by compacting, moving allocated
; strings up in memory, and adjusting the free string size.
CALL B$STCPCT ;compact the string space
CALL B$STFromLH ;get any leading heap entries
CALL SS_MOV_UP ;move allocated strings up to [SI]
;this call sets carry if not enough memory
JMP SHORT MOVSTR_RETURN ;finished - jump to return
; Expand string space by prefixing an unallocated string entry
; located from the new offset to the old and then compacting.
MOVSTR_DOWN:
SUB AX,SI ;get size of string entry to create
DEC AX ;header is data length plus one
MOV [SI],AX ;place header value in string entry
MOV [b$STRING_FIRST],SI ;new value of string space start
MOV [b$NH_first],SI ; start of string space is start of dynamic
; space for QB4
MOVSTR_COMPACT:
CALL B$STCPCT ;compact strings with new entry
CALL B$STFromLH ;get any leading heap entries
CLC ;clear carry for no error
MOVSTR_RETURN:
POP SI ;restore registers...
POP AX
RET ;return...
PAGE
;***
; SS_MOV_UP - move allocated string entries up
; Purpose:
; Assuming a compacted string space, move all allocated entries
; starting at offset [SI]. This is done by updating the string
; descriptor offsets to point to the new entry locations and
; then moving the allocated strings up as a block. The new free
; string is then created as well as the new [b$STRING_FIRST] and
; [b$STRING_FREE] pointers.
;
; Inputs:
; AX = offset of present string space start.
; SI = offset for new string space start.
; Outputs:
; CF = 0 - no error
; 1 - error, not enough memory for move
; Modifies:
; AX, SI.
; Exceptions:
; None.
;****
SS_MOV_UP:
PUSH BX ;save registers...
PUSH CX
PUSH DI
PUSH ES
PUSH DS
POP ES ;Set ES = DS
XCHG AX,SI ;AX=new offset - SI=present offset
SUB AX,SI ;compute adjustment factor for move up
; Test if enough room exists to move the strings down in memory.
; The present free string will be reduced by the adjustment factor,
; so a negative string length sets carry to denote the error.
CALL B$STGETFRESIZ ;get size of free string in BX
CMP BX,AX ;compare present free length with adj factor
JB SS_MOV_RETURN ;return immediately with carry set
; Scan through the compacted string space using pointer [SI] and
; adjust the string descriptor referenced by the backpointer by
; adding AX to the offset word.
SS_MOV_SCAN_LOOP:
MOV BX,[SI] ;get header of current scanned entry
TEST BL,1 ;test if entry is allocated
JNZ SS_MOV_BLOCK ;if not allocated, then end of scan, jump
ADD [BX+2],AX ;adjust the descriptor offset up
ADD SI,[BX] ;add string length to scan pointer
ADD SI,3 ;add for header and round up to next word...
AND SI,NOT 1 ;if string length was odd
JMP SHORT SS_MOV_SCAN_LOOP ;loop to try for next entry
; Move all allocated strings together up AX bytes in memory.
SS_MOV_BLOCK:
MOV SI,[b$STRING_FREE] ;entry past last allocated one
MOV CX,SI ;get offset to compute block length...
SUB CX,[b$STRING_FIRST] ;by subtracting start of string space
SHR CX,1 ;get number of words to move
SUB SI,2 ;point to highest word to move
MOV DI,SI ;compute destination...
ADD DI,AX ;by adding amount to move up
STD ;moving up requires direction flag set
REP MOVSW ;perform the move of CX words
CLD ;restore direction flag
; Adjust string space pointer and create new free entry.
ADD [b$STRING_FIRST],AX ;adjust new start of string space
ADD [b$NH_first],AX ; start of string space is start of dynamic
; space for QB4
MOV BX,[b$STRING_FREE] ;get original free entry offset
ADD BX,AX ;compute new free entry offset
MOV [b$STRING_FREE],BX ;put in new free entry offset
MOV CX,[b$STRING_END] ;get unchanging end offset of string space
SUB CX,BX ;get size of new free entry
DEC CX ;header is data length + 1 (entry length - 1)
MOV [BX],CX ;define new free entry by inserting header
SS_MOV_RETURN:
POP ES
POP DI ;restore registers...
POP CX
POP BX
RET ;return to caller
PAGE
;***
; B$STALCMAXTMP - allocate maximum-sized temporary string
; B$STALCMAXTMPNC - Allocate maximum-sized temp string w/o compact
; Purpose:
; Allocate the maximum-sized string availiable and attach it to a temp
; descriptor. Backpointer in string space set but data is not moved in.
;
; Inputs:
; None.
; Outputs:
; DX = Address of string data area.
; BX = Address of temp string descriptor
; Modifies:
; None.
; Exceptions:
; None.
;****
cProc B$STALCMAXTMP,<PUBLIC,NEAR>
cBegin
CALL B$STCPCT ;compact the string space
labelNP <B$STALCMAXTMPNC> ; Alloc after compaction
CALL B$STFromLH ;append any leading local heap entries
CALL B$STGETFRESIZ ;get the resulting free string size in BX
PUSH [b$STRING_FREE] ; Save ptr to free size
CALL B$STALCTMP ;use the size in BX to allocate temp string
POP [b$STRING_FREE] ; Get back saved value
; return to caller (PAINT)
cEnd ; End of B$STALCMAXTMP,B$STALCMAXTMPNC
PAGE
;***
;B$STALCTMP - allocate temporary string
;DBCS-callback
;
;Purpose:
; Allocate the requested amount of free space and attach it to a temp
; descriptor. Backpointer in string space set but data is not moved in.
;
;Inputs:
; BX = Length of string
;
;Outputs:
; DX = Address of string data area.
; BX = Address of temp string descriptor
;
;Uses:
; Per Convention
;
;Preserves:
; AX, CX
;
;Exceptions:
; None
;****
B$STALCTMP:
OR BX,BX
JZ ATSNUL ;Nul strings have special descriptor
CMP WORD PTR[TMPHDR],0 ;See if we have any temps left
JZ TEMPOV
PUSH SI
PUSH BX
CALL B$STALC ;[C1]Allocate the space
ALCTMP: ;jumped to from MakeTemp
MOV SI,[TMPHDR] ;Get the next temp
MOV DX,[SI] ;Make the one after that
MOV [TMPHDR],DX ; the new "next temp"
POP [SI] ;Set length in descriptor
MOV [BX-2],SI ;Set backpointer
MOV [SI+2],BX ;Set pointer in descriptor
MOV DX,b$curlevel ;set program level of allocation
MOV [SI+4],DX ; in descriptor
MOV DX,BX ;Put data pointer in DX
MOV BX,SI ;Need temp descriptor in BX
POP SI
RET
; Return pointer to null string.
ATSNUL:
MOV DX,OFFSET DGROUP:NULSTR
MOV BX,OFFSET DGROUP:b$nuldes
RET
TEMPOV:
JMP B$ERR_ST ; Clean stack and report string temporary ovfl.
PAGE
;***
;B$STMakeTemp - transfer ownership of a string to a temp. (QBI only).
;
;Purpose:
; Added with revision [22].
; Transfers ownership of a string to a temp. This is used
; for QBI string functions where the return sd lives on the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -