⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 atoms.asm

📁 这是一些例程
💻 ASM
📖 第 1 页 / 共 3 页
字号:
	.ENDIF

	les     di, [lpHeader]          ; re-load the request header

	ASSUME  di:PTR REQ_HEADER       ; to use the REQ_HEADER offsets

	mov     es:[di].xcount, bx      ; store the number of chars transferred

	ASSUME  di:NOTHING              ; di will be something else now

	mov     pAtomVal, offset null   ; set pAtomVal to null:won't read twice
	xor     ax, ax                  ; set status to OK
	ret                             ; return

Read    ENDP

;----------------------------------------------------------------------------;
; output (write) status: if there's still memory, fine. Otherwise, error
;----------------------------------------------------------------------------;

OutStat PROC NEAR       
	mov     ax, MemEnd      ; mov MemEnd into ax   
	inc     ax              ; increment ax (test space for 1 more char)
	.IF (ax < MaxMem)       ; if MemEnd less than MaxMem, we have space,
		xor     ax, ax  ; set status to OK
	.ELSE                   ; otherwise, set the Write Fault error  
		mov     ax, fERROR + fWRITE_E   
	.ENDIF
	ret
OutStat ENDP

;----------------------------------------------------------------------------;
; function 8 = write (output) to device from program
;----------------------------------------------------------------------------;
; big chunk of the program.
;        if string: 'variable', it's a search
;        if string: 'variable=' it's a delete
;        if string: 'variable=value' it's an insert
;----------------------------------------------------------------------------;

Write PROC NEAR USES si es di cx ds     
	LOCAL   func:BYTE, count:WORD, pAtom:NPTR, buf_seg:SEGPTR, buf_off:NPTR
		; func is used to see what function we're doing
		; count is used to store the length of the current atom
		; pAtom is used to point to the start of the current atom
		; buf_seg and buf_off point to the buffer to read from

	ASSUME  di:PTR REQ_HEADER       ; to use the REQ_HEADER offsets

	mov     ax, es:[di].xseg        ; load buf_seg with the buffer segment
	mov     buf_seg, ax     
	mov     cx, es:[di].xfer        ; load buf_off with the buffer offset
	mov     buf_off, cx     

	ASSUME  di:NOTHING              ; di will be something else now

	mov     es, ax                  ; load string into ES:DI
	mov     di, cx
	INVOKE  st_len, di, es          ; load string length into ax, since
					; we're not interested in xcount (for
					; safety reasons) 
	mov     count, ax               ; Store length in count
	mov     cx, ax                  ; and copy to cx


; find if we're doing a search, delete or insert

	mov     bx, cx          ; store the count temporarily 
	mov     al, '='         ; we will look in the string for a '='
	repnz   scasb           ; do the scanning
	.IF (ZERO?)             ; zero will be set if we found a '=',
		xor     al, al  ; in which case we have to see if it's a delete
		scasb           ; or insert: in a delete, the char after the 
				; '=' has to be a 0
		.IF (ZERO?)                     ; if there was a 0 after the =,
			mov     func,fDELETE    ; set the function to delete
		.ELSE
			mov     func,fINSERT    ; else, the function is insert
		.ENDIF
	.ELSE
		mov     func, fSEARCH   ; else (no '=' in string) it's a search
	.ENDIF
	inc     cx              ; cx holds amount of bytes after the '=', so 
	sub     bx, cx          ; by increasing it, cx holds # of bytes after
				; the variable name. If we substract cx from
				; the original length (in bx), bx will have 
				; the length of the variable only 

	.IF     (bx == 0)       ; if the length of the variable is 0 (i.e.      
		xor     ax, ax  ; string= "=....", then finish. set ax to OK
		jmp     wri_e   ; jump to the return place
	.ENDIF

	mov     pAtomVal, offset null   ; set pAtomVal to null. only a search 
					; will change this value, taken care
					; of in the loops below
	
; now go into the memory space and search for a matching variable. we will stop
; if we find a match or a variable that starts with a 0 (meaning no matches)

	mov     si, offset AtomList ; load SI the start of the driver memory
				    ; (pointed to by AtomList, of course)
		
.WHILE 1                        
	mov     pAtom, si       ; save the start of the current atom in memory
	INVOKE  st_len, si, ds  ; length of current atom will be in ax

	.IF (ax <= 1)           ; if the length of the current atom is 1 (never
		mov     di, si  ; can be 0), that means that we reached the end
		mov     si, ds  ; of the driver memory. set ES:DI to DS:SI, the 
		mov     es, si  ; end of memory, 
		.BREAK          ; and break from the loop
	.ENDIF                  

	mov     di, buf_off     ; restore di to the buffer offset
	mov     cx, bx          ; load into the count reg. the variable length  
		
	.IF     (cx >= ax)      ; if the length of the var.name is greater than
		add     si, ax  ; the whole atom length, it's sure not to be a 
		.CONTINUE       ; match. increase si by the length of the 
	.ENDIF                  ; current atom, and continue to next iteration
	
	repe    cmpsb           ; find the first non-matching character between
				; the current atom and the string buffer, for 
				; a maximum count of the length of the name
				
	.IF (!ZERO? || (byte ptr [si]!='='))            
		mov     si,pAtom; if we didn't stop because of two chars not
		add     si,ax   ; matching in the repe, or if the next char
	.CONTINUE               ; is not a '=' (i.e. comspec would match com),
	.ENDIF                  ; increase si by the length of the atom, and
				; go to the next iteration

; at this point we have found a match for the requested variable
				
	.IF     (func==fSEARCH) ; if we're doing a search,              
		inc     si      ; increment si (to skip over the '=')
		mov     pAtomVal,si     ; set pAtomVal to address of the char
	
	.ELSE                   ; else, we're doing a delete or insert: we have
				; to take the current atom out of the memory.
				; we will scan for the chars beyond our current
				; atom. then we shift those chars to a position
				; 'ax' places back. ax still holds the length
				; of the current atom
		mov     si,pAtom; set si to the beginning of the current atom,
		mov     di, ds  ; set ES:DI to be the same as DS:SI, since
		mov     es, di  ; scan uses ES:DI
		mov     di, si  

		add     di, ax  ; set DI to point to the char just after the
		mov     bx, ax  ; current atom. save atom length in bx.
		
		xor     al, al  ; clear al (will be used in the scan)
		mov     cx, -1  ; cx=-1 so that the reps only stop with a match

		.WHILE 1                ; a loop:
			dec     cx      ; decrease cx (because scasb doesn't)
			scasb           ; and test if it's a 0 (to signal end)
			.BREAK .IF ZERO?; break if the character matches
			repne   scasb   ; else repeat scanning (decrements cx)
		.ENDW                   ; until the next 0. then continue loop.

		not     cx      ; if cx=-(length+1), not cx=length (see st_len)

		mov     si,pAtom; get back to the beginning of the atom to
		mov     di, si  ; erase. the source for the movsb will be ahead
		add     si, bx  ; by bx chars (the atom length). 
		rep     movsb   ; move as many chars as left in memory

		dec     di      ; for the insert following, we'll want di to            
				; point to the end of memory. the rep took us
				; one beyond, so we decrement it.

		sub     MemEnd,bx       ; De-allocate the memory used by atom 
	
	.ENDIF                  ; of (func == fSEARCH)

	.BREAK                  ; break from the loop: one match is all we need

.ENDW                           ; actually, no one gets here. they either do a
				; continue or a break.

; if we're doing an insert, we'll do it at the end of the memory space

	.IF (func == fINSERT)   
		mov     ds, buf_seg     ; load DS:SI with the buffer to read from
		mov     si, buf_off
		mov     cx, count       ; cx and bx will have the count
		mov     bx, cx

		add     bx, cs:MemEnd   ; add to bx the end of memory

	; if we have a carry, it means that if bx > MaxMem, we don't have space
	; in our local AtomList. The bx>MaxMem test is not enough because if
	; MemEnd is high and adding cx goes over the segment boundary (starting
	; at 0000h), we wouldn't catch it with a bx >= MaxMem 

		.IF (CARRY? || bx >= cs:MaxMem)                         
			mov     ax, fERROR + fWRITE_E   ; set write fault error
			jmp     wri_e
		.ELSE
			mov     cs:MemEnd , bx          ; set new memory size
		.ENDIF
	
		rep     movsb           ; copy the buffer into our memory

		xor     ax, ax          ; add a null byte to the end of strings, 
		stosb                   ; to signal the end of memory
	.ENDIF  

	xor ax, ax              ; set status to OK

wri_e:  ret                     ; return!

Write ENDP

;----------------------------------------------------------------------------;
; Success: When the only thing the program needs to do is set status to OK 
;----------------------------------------------------------------------------;

Success PROC NEAR
	xor     ax, ax          ; set status to OK
	ret
Success ENDP

;----------------------------------------------------------------------------;
; error: set the status word to error: unknown command                       
;----------------------------------------------------------------------------;
Error   PROC    NEAR            
	mov     ax, fERROR + fUNKNOWN_E  ; error bit + "Unknown command" code
	ret                     
Error   ENDP

;----------------------------------------------------------------------------;
; st_len
; finds the length of the string pointed to by st_off and st_seg and stores it
; in ax. no other registers are affected
;----------------------------------------------------------------------------;

st_len  PROC NEAR USES es di cx, st_off:NPBYTE, st_seg:SEGPTR   
	mov     di, st_off      ; load string into ES:DI, since scas uses       

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -