CS344-321 Assembly Language Programming example 3 page 1 CS344-321 Assembly Language Programming example 3 page 2 CS344-321 Assembly Language Programming example 3 page 3 CS344-321 Assembly Language Programming example 3 page 4 CS344-321 Assembly Language Programming example 3 page 5 CS344-321 Assembly Language Programming example 3 page 6 CS344-321 Assembly Language Programming 7 example 3 page Figure 3-2. GETENV.ASM, a procedure that returns a pointer to the value portion of the specified environment string. title GETENV.ASM --- Get Environment String page 55,132 ; GETENV.ASM --- Return address and length of variable ; portion of environment string. CS344-321 Assembly Language Programming example 3 page ; ; Copyright (c) 1989 Ray Duncan ; ; Call with: DS:SI = ASCIIZ name of environment variable ; ES = segment of program segment prefix (PSP) ; ; Returns: ES:DI = address of value of environment variable ; AX = length (0 = not found) ; ; Destroys: Nothing psp_ptr equ 002ch ; offset of environment ; pointer within PSP _TEXT segment word public 'CODE' assume cs:_TEXT public getenv getenv proc near push cx push si ; save registers 8 CS344-321 Assembly Language Programming 9 example 3 page mov es,es:[psp_ptr] ; get pointer to environment mov cx,8000h ; assume max env. = 32 KB xor di,di ; initial env. offset xor ax,ax ; default length result get1: cmp byte ptr es:[di],0 ; check for end of environment je get4 ; end reached, return AX = 0 pop si ; initialize address of target push si ; variable to be found repe cmpsb ; compare target and env. strings cmp byte ptr [si-1],0 jne get2 ; jump if incomplete match cmp byte ptr es:[di-1],'=' je get3 get2: ; jump if match was complete ; match was incomplete repne scasb ; scan for end of env. string jmp get1 ; and try again to match CS344-321 Assembly Language Programming example 3 page get3: push di repne scasb ; save address after = sign ; look for end of this string pop ax ; get back starting address xchg di,ax ; find string length sub ax,di dec ax get4: ; don't include null byte ; common exit point pop si ; restore registers pop cx ret ; return to caller getenv endp _TEXT ends end 10 CS344-321 Assembly Language Programming example 3 page 11 CS344-321 Assembly Language Programming example 3 page 12 CS344-321 Assembly Language Programming example 3 page 13 CS344-321 Assembly Language Programming example 3 page 14 CS344-321 Assembly Language Programming 15 example 3 page Figure 3-3. PUTENV.ASM, a procedure that modifies an existing environment variable in the environment block or adds a new environment varible. title PUTENV.ASM --- Modify Environment Variable page 55,132 ; ; PUTENV.ASM --- Add or modify MS-DOS environment variable. ; ; Copyright (C) 1989 Ray Duncan ; ; Call with: DS:SI = new ASCIIZ environment variable CS344-321 Assembly Language Programming 16 example 3 page ; in the form name=value ; ES = segment of program segment prefix (PSP) ; ; Returns: AX ; = 0 if successful = -1 if failed ; ; Destroys: ES psp_ptr equ 002ch ; offset of environment ; pointer within PSP DGROUP group_DATA _TEXT segment word public 'CODE' assume cs:_TEXT extrn getenv:near ; names for working storage oldenv equ [bp-2] ; segment of old environment envlen equ [bp-4] environment ; length of old CS344-321 Assembly Language Programming example 3 page newenv equ [bp-6] ; segment of new environment pspseg equ [bp-8] ; segment of program segment prefix oldlen equ [bp-10] ; length of existing equ [bp-12] ; length of new env. variable newlen variable newname equ [bp-14] ; offset of new name portion newvar equ [bp-16] ; offset of new param. portion public putenv putenv proc near push bp ; set up stack frame for mov bp,sp ; working storage sub sp,16 mov newname,si ; save offset of new variable mov pspseg,es ; save PSP segment mov es,es:[psp_ptr] ; pick up segment of old mov oldenv,es ; environment and save it 17 CS344-321 Assembly Language Programming 18 example 3 page push cx ; save other registers push si push di ; find old environment length mov cx,8000h ; assume max = 32 KBytes xor di,di ; ES:DI = environment base xor al,al put1: repne scasb ; scan for double null (can't use scasb ; SCASW since might be on odd addr) jne put1 mov envlen,di ; save length of old environment mov di,si ; find length of new env. variable mov ax,ds ; ES:DI = addr of new variable mov es,ax mov cx,-1 xor al,al repne scasb null byte ; scan for terminating CS344-321 Assembly Language Programming 19 example 3 page not cx ; now CX = length including null mov newlen,cx ; save length of new variable ; attempt to allocate memory ; block for new environment... mov bx,cx ; length of old environment add bx,envlen ; + length of new variable mov cl,4 ; divide by 16 and round shr bx,cl ; up to find paragraphs to inc bx ; allocate for new environment mov ah,48h ; Fxn 48h=allocate memory block int 21h ; transfer to MS-DOS jnc put2 ; jump if allocation succeeded mov ax,-1 ; otherwise, return error flag jmp put6 put2: mov newenv,ax ; save new environment segment mov di,offset envar ; copy name portion of new ; variable to local storage CS344-321 Assembly Language Programming 20 example 3 page put3: movsb ; copy characters up to '=' cmp byte ptr [si],'=' jne put3 ; loop until end of name found xor al,al ; append null byte to name si ; save address of param. stosb inc mov newvar,si ; portion of new variable mov si,offset envar ; check if new environment mov es,pspseg ; variable has a previous value call getenv ; in old environment mov oldlen,ax ; save length of value, if any or ax,ax ; was it present in old block? jnz put4 ; yes, PUTENV the hard way push ds ; no just copy existing environment ; and add the new variable mov ds,oldenv ; DS:SI = old env. block mov es,newenv ; ES:DI = new env. block CS344-321 Assembly Language Programming 21 example 3 page mov cx,envlen ; CX = length of old environment dec cx xor si,si xor di,di ; less the extra null byte rep movsb ; copy the old stuff pop ds ; DS:SI = address of new variable mov si,newname ; ES:DI = end of new environment mov cx,newlen ; CX = length of new variable rep movsb ; append the new variable xor ; and the extra null byte al,al stosb ; marking end of environment jmp put5 ; go update PSP env. pointer put4: ; come here on the messy case, ; env. variable already exists ; ES:DI = offset+1 of '=' in ; old variable from 'getenv' push ds ; copy old environment to new mov ax,es ; up through the '=' of the mov ds,ax ; variable we are changing CS344-321 Assembly Language Programming 22 example 3 page mov cx,di ; DS:SI = old environment mov es,newenv ; ES:DI = new environment xor si,si ; CX = offset+1 of '=' xor di,di ; in old variable rep movsb pop ds ; now let DS:SI = offset+1 push si ; of '=' in new variable mov si,newvar ; and CX = length of portion mov cx,newname ; following the '=' add cx,newlen sub cx,newvar ; copy the new parameter portion rep movsb ; to the new environment pop si ; skip over parameter portion add si,oldlen ; of the old variable inc ; and its null byte si push ds ; now copy remainder of mov ds,oldenv ; old environment to new one mov cx,envlen ; total length less portion sub cx,si ; already copied and length rep movsb ; of old environment variable pop ds CS344-321 Assembly Language Programming 23 example 3 page put5: ; PUTENV function successful, mov es,oldenv ; release old environment block mov ah,49h int 21h ; transfer to MS-DOS mov es,pspseg ; update pointer to new mov ax,newenv ; environment in caller's PSP mov es:[psp_ptr],ax xor ax,ax put6: pop di ; return success code ; restore registers pop si pop cx mov sp,bp ; discard stack frame pop bp ret ; back to caller putenv endp _TEXT ends _DATA segment word public 'DATA' CS344-321 Assembly Language Programming example 3 page envar db 80 dup (0) ; name of new environment var. ; for call to 'getenv' _DATA end ends 24 CS344-321 Assembly Language Programming example 3 page 25 CS344-321 Assembly Language Programming example 3 page 26 CS344-321 Assembly Language Programming example 3 page 27 CS344-321 Assembly Language Programming example 3 page 28 CS344-321 Assembly Language Programming example 3 page 29 CS344-321 Assembly Language Programming 30 example 3 page Program TRYENV.ASM ------------------------------------------------------------------------------title TRYENV.ASM --- Demo of PUTENV.ASM and GETENV.ASM page 55,132 ; ; TRYENV.ASM --- Interactive Demo of PUTENV.ASM and GETENV.ASM Modules ; ; Copyright (C) 1989 Ray Duncan ; ; To build: MAKE TRYENV stdin equ 0 stdout equ 1 stderrequ 2 ; standard input handle ; standard output handle ; standard error handle CS344-321 Assembly Language Programming 31 example 3 page cr equ 0dh ; ASCII carriage return lf equ 0ah ; ASCII line feed stksize equ 128 DGROUP group_DATA,STACK _TEXT segment word public 'CODE' assume cs:_TEXT,ds:DGROUP,ss:STACK extrn getenv:near extrn putenv:near main proc far mov ax,DGROUP ; make our data segment mov ds,ax ; addressable ; now give back extra memory... mov ax,es ; AX = segment of PSP base mov bx,ss ; BX = segment of stack base sub bx,ax ; reserve seg stack - seg psp CS344-321 Assembly Language Programming 32 example 3 page add bx,stksize/16 ; plus paragraphs of stack inc bx ; round up for safety mov ah,4ah ; fxn 4ah = modify memory block int 21h jc main2 mov pspseg,es main1: ; transfer to MS-DOS ; exit if resize failed ; save segment of PSP mov ax,DGROUP ; make our data segment mov ds,ax ; addressable again... ; prompt user 'Enter name:'... mov dx,offset msg1 ; message address mov cx,msg1_len ; message length call pmsg ; go display message ; get name of env. variable mov dx,offset buff1 mov cx,buff1_len mov bx,stdin mov ah,3fh int 21h ; address of input buffer ; length of buffer ; standard input handle ; func. 3fh = read ; transfer to MS-DOS CS344-321 Assembly Language Programming 33 example 3 page sub ax,2 ; ignore CR-LF characters or ax,ax ; anything entered? jnz main3 ; yes, proceed mov ax,4c00h ; final exit to MS-DOS main2: int main3: 21h ; with return code = 0 mov bx,ax ; append null to user's mov byte ptr [bx+buff1],0 ; input string... mov si,offset buff1 ; address of ASCIIZ string call strupr ; fold lower case to upper mov es,pspseg ; segment address of PSP case call getenv ; search environment for match or ax,ax jz main4 ; find anything? ; no, display error message push ds ; save data segment push ax ; save length of value push di ; save offset of value ; display 'The value is:' ... CS344-321 Assembly Language Programming 34 example 3 page mov dx,offset msg2 ; address of message mov cx,msg2_len ; length of message call pmsg ; go display message push es ; display current value pop ds ; of environment variable pop dx ; address of string pop cx ; length of string call ; go display message pmsg pop ds ; restore segment of DGROUP mov dx,offset msg6 ; extra blank line mov cx,msg6_len call pmsg main4: ; prompt user 'Enter value:'... mov dx,offset msg3 ; message address mov cx,msg3_len ; message length call pmsg ; go display message ; get value for env. variable... mov dx,offset buff2 mov cx,buff2_len mov bx,stdin ; address of input buffer ; length of buffer ; standard input handle CS344-321 Assembly Language Programming 35 example 3 page mov ah,3fh int 21h ; func. 3fh = read ; transfer to MS-DOS sub ax,1 ; ignore CR-LF characters mov bx,ax ; append null to user's input... mov byte ptr [bx+buff2-1],0 ; and include null in length push ds ; let ES = DGROUP too pop es mov di,offset buff1 ; scan to end of name mov cx,-1 ; of environment variable xor al,al repne scasb mov byte ptr [di-1],'=' ; replace null with equal sign mov si,offset buff2 ; then append new value and mov cx,bx ; terminating null rep movsb mov si,offset buff1 ; store new value in environment mov es,pspseg ; using our PUTENV routine call putenv or ax,ax ; was environment modified? jnz main5 ; no, display error message CS344-321 Assembly Language Programming 36 example 3 page mov dx,offset msg4 ; display 'Environment mov cx,msg4_len ; now contains:' block call pmsg mov es,pspseg ; let ES = segment of environment mov es,es:[002ch] call dumpenv jmp main1 main5: ; dump environment strings ; go prompt user again ; environment can't be modified mov dx,offset msg7 ; address of error message mov cx,msg7_len ; length of error message call pmsg jmp main1 main endp ; ; go display message ; go prompt user again CS344-321 Assembly Language Programming 37 example 3 page ; DUMPENV Dump entire environment block to stdout ; ; Call with: ES = segment base address of environment ; ; Returns: Nothing ; ; Destroys: AX, BX, CX, DX, DI, DS ; dumpenv proc xor dump1: near di,di ; initialize env. offset cmp byte ptr es:[di],0 ; reached end of environment? je dump2 ; yes, exit mov dx,offset msg6 ; no, move to new line mov cx,msg6_len ; by sending carriage call pmsg ; return/line feed mov dx,di ; save address of next mov cx,-1 ; environment variable xor ; and find its length al,al repne scasb null not cx ; scan for terminating CS344-321 Assembly Language Programming 38 example 3 page dec cx ; now CX = length push ds ; save our data segment mov ax,es ; let DS:DX = address mov ds,ax ; of environment variable call ; and display it pmsg pop ds ; restore our data segment jmp dump1 dump2: ; get next env. variable mov dx,offset msg6 ; display extra blank line mov cx,msg6_len call pmsg ret ; back to caller dumpenv endp ; ; STRUPR --- Fold ASCIIZ string to upper case ; ; Call with: DS:SI = address of ASCIIZ string ; ; Returns: Nothing ; ; Destroys: AX CS344-321 Assembly Language Programming example 3 page ; struprproc near push si ; save string address strup1: lodsb ; get next character or al,al ; found end (null byte) ? jz strup2 cmp al,'a' jb ; yes, jump ; test if in range 'a'-'z' strup1 ; skip it if not >= a cmp al,'z' ja strup1 ; skip it if not <= z sub byte ptr [si-1],'a'-'A' ; fold to upper case jmp strup1 strup2: pop si ret ; get another char ; restore original string ; address and return struprendp ; ; PMSG --- Display message on standard output ; ; Call with: DS:DX = message address ; ; CX = message length 39 CS344-321 Assembly Language Programming example 3 page ; Returns: Nothing ; ; Destroys: AX, BX ; pmsg proc near mov bx,stdout ; standard output handle mov ah,40h int 21h ; func. 40h = write ; transfer to MS-DOS ret ; return to caller pmsg endp _TEXT ends _DATA segment word public 'DATA' pspseg dw ? ; segment of program segment prefix msg1 db cr,lf,'Enter name of environment variable: ' msg1_len equ $-msg1 msg2 db cr,lf,'Current value is: ' msg2_len equ $-msg2 40 CS344-321 Assembly Language Programming 41 example 3 page msg3 db cr,lf,'Enter new value: ' msg3_len equ $-msg3 msg4 db cr,lf,'Environment block now contains: ' msg4_len equ $-msg4 msg6 db cr,lf ; carriage return/line feed msg6_len equ $-msg6 msg7 db cr,lf,'Cannot modify environment!',cr,lf msg7_len equ $-msg7 buff1 db 80 dup (?) buff1_len equ $-buff1 buff2 db 80 dup (?) buff2_len equ $-buff2 ; input buffer for name of ; environment variable ; input buffer for value of ; environment variable _DATA ends STACK segment para stack 'STACK' db stksize dup (?) CS344-321 Assembly Language Programming example 3 page STACK ends end main Make file for TRYENV.EXE getenv.obj : getenv.asm masm /Zi getenv; putenv.obj : putenv.asm masm /Zi putenv; tryenv.obj : tryenv.asm masm /Zi tryenv; tryenv.exe : tryenv.obj putenv.obj getenv.obj LINK /CODEVIEW tryenv+putenv+getenv; 42 CS344-321 Assembly Language Programming example 3 page 43