home *** CD-ROM | disk | FTP | other *** search
- PAGE 60,132
- NAME CMOSSAVE
- TITLE CMOSSave Save CMOS to a file on disk or floppy
- Comment |
- Version 3.0 by Roedy Green
- works with MASM 6.0 and Optasm
- This assembler code generates all three programs:
- CMOSSAVE.COM CMOSREST.COM and CMOSCHK.COM.
-
- Note that we never compute or verify a checksum. Every vendor computes
- may compute it a slightly different way.
-
- To come:
- /V:xx - additional volatile byte
-
- See CMOS.TXT for details on use.
-
- USAGE:
-
- Examples:
- *********
-
- CMOSSave A:\MyCMOS.Sav /Q
-
- CMOSRest A:\MyCMOS.Sav /Q
-
- CMOSChk A:\ByCMOS.Sav /Q
-
- Syntax errors or missing file trouble generates an ERRORLEVEL 4.
- CMOSChk generates an ERRORLEVEL 1 if the CMOS has changed since
- the CMOSSave was done.
-
- Version History
- ***************
-
- Version 1.0
- - released to BIX 91/09/07
-
- Version 1.1
- - released to BIX 91/09/18
- - added special check for small 64 character CMOSes.
-
- Version 1.2
- - fix spelling errors
- - use CMOS.SAV instead of MyCMOS.SAV in examples
-
- Version 1.3
- - now consider fewer bytes volatile, restore more stuff.
- - hints in docs about clearing CMOS.
-
- Version 1.4
- - now consider flags Status register C, offset 0C as volatile.
- fixes false alarms.
-
- Version 1.5 1994 June 1
- - change of address and phone number
- - address now appears in the banner.
-
- Version 1.6 1994 August 29
- - more information about how CMOS bits are used.
-
- Version 2.0 1994 October 1
- - easier configuration of CHKCMOS volatile bytes.
- - smarter bat files.
- - docs on different ways to use.
-
- Version 2.2 1995 April 16
- - docs on use before experimentation
-
- Version 2.3 1995 July 24
- - add 3F as volatile byte. PCI Pentiums are volatile.
-
- Version 2.4 1995 August 7
- - add /Q switch to suppress banners, only complain
- - presume installation done to C:\CMP and that files saved there too.
-
- Version 2.5 1996 January 27
- - better documentation
-
- Version 2.6 1996 June 3
- - better documentation. Win 95 explanations.
-
- Version 2.7 1996 August 19
- - treat hex 3F differently in CMOSRest and CMOSChk
-
- Version 2.8 1996 October 23
- - POB in Quathiaski address. Back to C:\SAFE as presumed directory
- - lower cost $10, combined site licence.
-
- Version 2.9 1996 November 22
- - fix missing com files.
-
- Version 3.0 1997 July 8
- - notes on Y2K checking
- - notes on separate rescue diskettes.
-
- CMOS Usage - see also CMOS.OFS
-
- How to Assemble
- ***************
-
- Manually set the GENERATING equate embedded in this code, then:
-
- to assemble with MASM 6.0 use:
- ML.EXE /AT /c /Fl /VM /Zf /Zm CMOS.Asm
- LINK.EXE /TINY /MAP CMOS.Obj,CMOS.com,CMOS.map;
- copy cmos.com cmossave.com
-
- to assemble with OPTASM use:
- Optasm CMOS.Asm,CMOS.Obj,CMOS.Lst/L/N/G/S
- OLINK CMOS.Obj,CMOS.COM,/MAP/TINY;
- copy cmos.com cmossave.com
-
- Register Conventions
- ********************
-
- Subroutines may trash all registers except those explicity
- documented as input or output.
-
- | ; end of comment
-
-
- ; E Q U A T E S
-
- CMOSSAVE EQU 1
- CMOSREST EQU 2
- CMOSCHK EQU 3
-
- ; use /DGenerating#CMOSSAVE
- ; /DGenerating#CMOSREST
- ; /DGenerating#CMOSCHK
- ; on the assembler command line to select which version
- ; of the code to assemble.
- ; Or add code following of the form:
-
- ; GENERATING EQU CMOSSave
-
-
- If Generating eq CMOSSave
- %OUT Generating CMOSSave.Com
- Endif
-
- If Generating eq CMOSRest
- %OUT Generating CMOSRest.Com
- endif
-
- If Generating eq CMOSChk
- %OUT Generating CMOSChk.Com
- endif
- ;==============================================================
-
-
- stack segment stack ; keep MS link happy by providing null stack
- stack ends
-
- CODE SEGMENT PARA ; start off in code.
-
- ;==============================================================
-
- data segment byte ; provide a separate DATA segment
- ; actually all come after the code
- ;==============================================================
- ; V A R I A B L E S
-
-
- If Generating eq CMOSSave
-
- BannerMsg label byte
- DB '░▒▓█ CMOSSave 3.0 █▓▒░',13d,10d
- DB 13d,10d
- DB 'Saves contents of CMOS to a file on hard disk or floppy.',13,10
- DB 'Copyright (c) 1991,1996 Roedy Green Canadian Mind Products.',13,10
- DB 'POB 707 Quathiaski Cove, Quadra Island, BC Canada V0P 1N0',13,10
- DB 'Telephone: (250) 285-2954 Internet:roedy@bix.com',13,10
- DB 'Shareware to freely distribute and use for any purpose except military.',13,10
- DB 13,10
- db '$'
-
- UsageMsg DB '░▒▓█ Error █▓▒░',7,13,10
- DB 'Insert a formatted diskette.',13,10
- DB 'then try:',13,10
- DB 'CMOSSave A:\CMOS.Sav',13,10
- DB 'or if want to save on hard disk try:',13,10
- DB 'CMOSSave C:\SAFE\CMOS.Sav',13,10
- DB 'Read CMOS.TXT to find how to use it properly.',13,10
- db '$'
-
- FileTroubleMsg DB '░▒▓█ Error █▓▒░',7,13,10
- DB 'Cannot create the disk file.',13,10
- db '$'
-
- WorkedMsg DB 'CMOS successfully saved',13,10
- db '$'
-
- EndIf
-
-
- If Generating eq CMOSRest
- BannerMsg label byte
- DB '░▒▓█ CMOSRest 3.0 █▓▒░',13d,10d
- DB 13d,10d
- DB 'Restores CMOS from a CMOSSave file on hard disk or floppy.',13,10
- DB 'Copyright (c) 1991,1996 Roedy Green Canadian Mind Products.',13,10
- DB 'POB 707 Quathiaski Cove, Quadra Island, BC Canada V0P 1N0',13,10
- DB 'Telephone: (250) 285-2954 Internet:roedy@bix.com',13,10
- DB 'Shareware to freely distribute and use for any purpose except military.',13,10
- DB 13,10
- db '$'
-
- UsageMsg DB '░▒▓█ Error █▓▒░',13,10
- DB 'Insert the diskette you used for CMOSSave.',13,10
- DB 'then try:',13,10
- DB 'CMOSRest A:\CMOS.Sav',13,10
- DB 'or if the file is on hard disk try:',13,10
- DB 'CMOSRest C:\SAFE\CMOS.Sav',13,10
- DB 'Read CMOS.TXT to find how to use it properly.',13,10
- db '$'
-
- FileTroubleMsg DB '░▒▓█ Error █▓▒░',7,13,10
- DB 'Cannot find/read the disk file.',13,10
- db '$'
-
- WorkedMsg DB 'CMOS successfully restored',13,10
- db '$'
-
- EndIf
-
- If Generating eq CMOSChk
- BannerMsg label byte
- DB '░▒▓█ CMOSChk 3.0 █▓▒░',13d,10d
- DB 13d,10d
- DB 'Ensures CMOS not corrupted or changed.',13,10
- DB 'Copyright (c) 1991,1996 Roedy Green Canadian Mind Products.',13,10
- DB 'POB 707 Quathiaski Cove, Quadra Island, BC Canada V0P 1N0',13,10
- DB 'Telephone: (250) 285-2954 Internet:roedy@bix.com',13,10
- DB 'Shareware to freely distribute and use for any purpose except military.',13,10
- DB 13,10
- db '$'
-
- UsageMsg DB '░▒▓█ Error █▓▒░',7,13,10
- DB 'Insert the diskette you used for CMOSSave.',13,10
- DB 'then try:',13,10
- DB 'CMOSChk A:\CMOS.Sav',13,10
- DB 'or if you have the file on hard disk try:',13,10
- DB 'CMOSChk C:\SAFE\CMOS.Sav',13,10
- DB 'Read CMOS.TXT to find how to use it properly.',13,10
- db '$'
-
- FileTroubleMsg DB '░▒▓█ Error █▓▒░',7,13,10
- DB 'Cannot find/read the disk file.',13,10
- db '$'
-
- MatchTroubleMsg DB '░▒▓█ Error █▓▒░',7,13,10
- DB 'CMOS has been corrupted! at hex offset:value:expected ',13,10
- db '$'
-
- ColonMsg db ':','$'
-
- NextTripleMsg db 13,10,'$'
-
-
- WorkedMsg DB 'CMOS is OK, i.e. unchanged since the last CMOSSave.',13,10
- db '$'
-
- EndIf
-
- ParmIndex DW 0
-
-
- Filename DB 64 dup (0)
- ; asciiz filename
-
- SlashQuiet DB 0
- ; -1 means quiet mode /Q
-
- CMOSSize DB 0
- ; size of cmos in bytes
-
- CMOSBuff db 0 ; dynamic buffer will grow to 128
- ; it hangs out past the end of the program
-
- data ends
-
- com group code,data ; force data segment to go at the end
-
- ASSUME CS:com,DS:com,ES:com,SS:com
- ; seg regs cover everything
- ORG 100H ; in Code segment
-
- ;==========================
-
- Main proc far
-
- ; M A I N L I N E R O U T I N E
- Start:
- Call Parse ; get filename and /Q from command line
-
- lea dx,BannerMsg ; display the banner if no /Q
- Call SayQ
-
- If Generating eq CMOSSave
- call GetCMOS ; fetch CMOS to buffer
- call WriteCMOS ; write CMOS contents to file
- lea dx,WorkedMsg ; crow about success
- Call Say
- EndIf
-
- If Generating eq CMOSRest
- call ReadCMOS ; read CMOS contents from file
- call CalcCMOSSize ; it is 64 or 128 bytes long?
- call PutCMOS ; store buffer to CMOS
- lea dx,WorkedMsg ; crow about success
- Call Say
- EndIf
-
- If Generating eq CMOSChk
- call ReadCMOS ; read CMOS contents from file
- call CalcCMOSSize ; it is 64 or 128 bytes long?
- call CompareCMOS ; compare CMOS with buffer
- lea dx,WorkedMsg ; crow about success
- Call SayQ
- EndIf
-
- Done:
- mov ax,4c00h
- int 21h ;normal termination
-
- Main EndP
-
- ;===============================================================
-
- Trouble proc near
-
- FileTrouble:
- Lea dx,FileTroubleMsg ; display file trouble
- Call Say
- Jmp Abort
-
- SyntaxTrouble:
- lea dx,BannerMsg
- Call Say
- LEA dx,UsageMsg
- Call Say
- Jmp Abort
-
- abort:
- ; error exit
- mov ax, 4c04h ; ERRORLEVEL = 4
- int 21h ; DIE
-
- Trouble endp
-
- ;===============================================================
-
- SayQ Proc
- ; on entry DX points to a string to display
- ; Only displays string if /Q not on
- test SlashQuiet,-1
- jnz Quietly
- call Say
- Quietly:
- ret
- SayQ Endp
-
- ;========================================
-
- Say Proc
-
- ; on entry DX points to a string to display
- push ax
- MOV AH,9
- Int 21h
- pop ax
- ret
-
- Say EndP
-
- ;======================================
-
- If Generating eq CMOSSave
-
- GetCMOS Proc Near
-
- ; Get 128 byte contents of CMOS into a buffer.
-
- mov cx,128 ; count of times through loop
- lea bx,CMOSBuff ; where to put the contents
- sub al,al ; start offset in CMOS
- GetLoop:
- Call PeekCmos ; al=offset ah=contents
- mov byte ptr[bx],ah
- inc al
- inc bx
- loop GetLoop
- ret
-
- GetCMOS EndP
-
- EndIf
-
- ;===============================================================
-
- If Generating eq CMOSRest
-
- PutCMOS Proc Near
-
- ; Put 128-byte contents of buffer into CMOS.
- ; do not touch the volatile bytes
-
- mov cx,128 ; count of times through loop
- lea bx,CMOSBuff ; where to put the contents
- sub al,al ; start offset in CMOS
- PutLoop:
- call Volatile ; test if this is a volatile byte
- ; test offset in al
- jc LeaveItAlone
- mov ah,byte ptr[bx]
- Call PokeCMOS ; al=offset ah=contents
-
- LeaveItAlone:
- inc bx
- inc al
- loop PutLoop
- ret
-
- PutCMOS EndP
-
- EndIf
-
- ;===============================================================
-
- If Generating eq CMOSChk
-
- hexPAD DB '00$' ; where numeric output built by SayHexByte
-
- SayHexByte proc Near
- ; al contains hex byte to display:
-
- push ax ; preserve regs
- push bx
- push cx
- push dx
- mov dl,al ; save input
- ; Do first (leftmost digit)
- mov cl,4
- shr al,cl
- and al,0fh ; get first digit
- cmp al,9
- jg HexChar1
- add al,'0' ; convert digit to ASCII
- jmp StoreChar1
- HexChar1:
- add al,'A'-0AH ; convert to uppercase A..H
- StoreChar1:
- mov hexPad,al
-
- ; Do second (rightmost digit)
- mov al,dl
- and al,0fh ; get last digit
- cmp al,9
- jg HexChar2
- add al,'0' ; convert digit to ASCII
- jmp StoreChar2
- HexChar2:
- add al,'A'-0AH ; convert to uppercase A..H
- StoreChar2:
- mov hexPad+1,al
-
- ; Number is ready
- lea dx,Hexpad
- mov AH,09h ; BIOS put string terminated by $
- int 21h
- pop dx
- pop cx
- pop bx
- pop ax
- ret
-
- SayHexByte ENDP
-
- EndIf
-
- ;===============================================================
-
- If Generating eq CMOSChk
- CompareCMOS proc Near
-
- ; compares buffer version of CMOS with contents of actual CMOS
- ; ignores mismatches of volatile bytes.
- ; Aborts if finds a mismatch
-
- mov cx,128 ; count of times through loop
- lea bx,CMOSBuff ; where to find comparison set
- sub al,al ; start offset in CMOS
- push si
- sub si,si ; count of mismatches
- CompLoop:
- call Volatile ; test if this is a volatile byte
- ; test offset in al
- jc MatchedOk
- Call PeekCMOS ; al=offset ah=contents
- cmp ah,byte ptr[bx] ; compare CMOS with buffer
- je MatchedOk
-
- ; Mismatch
- test si,si ; only complain on first mismatch
- jnz AlreadyComplained
- lea dx,MatchTroubleMsg ; display CMOS mismatch
- call Say
- AlreadyComplained:
- push ax
- inc si ; count of how many mismatches found
- Call SayHexByte ; report offset
- lea dx,ColonMsg
- call Say
- mov al,ah ; report bad value in CMOS
- Call SayHexByte
- lea dx,ColonMsg
- call Say
- mov al,byte ptr[bx] ; report what value should be from file.
- call SayHexByte
- lea dx,NextTripleMsg
- call Say
- pop ax
-
- MatchedOk:
- inc bx
- inc al
- loop CompLoop
-
- test si,si
- jz NoMismatches
-
- mov ax, 4c01h ; ERRORLEVEL = 1
- int 21h ; DIE
-
- NoMisMatches:
- pop si
- ret
-
- CompareCMOS EndP
-
- EndIf
-
- ;===============================================================
-
- If Generating ne CMOSSave
-
- ; Add to this list if you need more volatile bytes.
- ; Remember the trailing h.
- ; Volatile bytes are not checked or restored.
-
- ; 0..09 are volatile
- ; 0ch is status byte
- ; 032h is century byte
- ; 03Fh is Pentium volatile byte
-
-
- if Generating eq CMOSChk
- VolatileList db 0ch,032h,03Fh
- ; see restore list below
- Endif
-
- if Generating eq CMOSRest
- VolatileList db 0ch,032h
- ; leave off 03Fh
- Endif
-
- VolatileCount equ $-VolatileList
-
-
- Volatile Proc near
-
- ; Is cmos offset in AL volatile? If so set carry.
- ; These bytes will be undisturbed.
- ; Preserves all registers.
- ; 00..09, 0C, 32 and 3F are volatile, rest are not.
- ; 0A 0B 0D 0E 0F used to be considered volatile, now are not.
- ; if cmos is small, all bytes past end are considered volatile
-
- cmp al,CMOSSize ; bytes past end are volatile
- jae IsVolatile
- cmp al,09h
- jbe IsVolatile ; early bytes are for timing
- push cx
- push di
- mov cx,VolatileCount
- lea di,VolatileList
- repne scasb ; search till find a match
- pop di
- pop cx
- je IsVolatile
-
- IsNotVolatile:
- clc ; clear carry
- ret
-
- IsVolatile:
- stc
- ret
-
- Volatile EndP
- EndIf
-
- ;===============================================================
-
- If Generating ne CMOSSave
-
- CalcCMOSSize Proc near
-
- ; Is CMOS 64 or 128 bytes long?
- ; It is 64 if bytes at 10..2F match those at 50..6F.
- ; Otherwise it is 128 bytes.
- ; Preserves all registers.
-
- push si
- push di
- push cx
- lea si,CMOSBuff+10h
- lea di,CMOSBuff+50h
- mov cx,02fh+1-10h
- repe cmpsb
- je IsCMOS64
-
- IsCMOS128:
- mov CMOSSize,128 ; differ, must be a big CMOS
- jmp CalcCMOSSizeDone
-
- IsCMOS64:
- mov CMOSSize,64 ; all same, small CMOS
-
- CalcCMOSSizeDone:
- pop cx
- pop di
- pop si
-
- ret
-
- CalcCMOSSize EndP
- EndIf
-
- ;===============================================================
-
- if Generating ne CMOSRest
-
- PeekCMOS proc near
-
- ; Reads one byte from cmos.
- ; on entry al has offset desired
- ; on exit ah has the contents of that byte.
- ; preserves all registers
-
- ; See page 5-81 IBM AT Tech ref BIOS listing for how to read CMOS
- ; We always enable the NMI with bit 7 on.
-
- push bx
- push ax
- cli ; disable interrupts
- or al,80h ; disable NMI
- ; controlled by port 70
- out 70h,al ; output the byte address to CMOS
- jmp $+2 ; delay, safer than nop
- in al,71h ; read the CMOS byte
- jmp $+2 ; delay, safer than nop
- mov bl,al
- ; re-enable the NMI, high bit off
- mov al,0dh ; point to battery status register
- out 70h,al ; leave pointing at a safe r/o register
- sti ; restore interrupts
- pop ax
- mov ah,bl
- pop bx
- ret
-
- PeekCMOS EndP
-
- EndIf
-
- ;===============================================================
-
- If Generating eq CMOSRest
-
- PokeCMOS proc near
-
- ; Stuffs one byte into cmos.
- ; on entry al has offset desired, ah has the value to stuff.
- ; Preserves all registers.
-
- ; See page 5-81 IBM AT Tech ref BIOS listing for how to write CMOS
- ; We always enable the NMI with bit 7 on.
-
- push ax
- cli ; disable interrupts
- or al,80h ; disable NMI
- out 70h,al ; output the byte address to CMOS
- jmp $+2 ; delay, safer than nop
-
- mov al,ah ; get contents
- out 71h,al ; poke the CMOS byte
- jmp $+2 ; delay, safer than nop
- ; re-enable the NMI
- mov al,0dh ; point to battery status register
- out 70h,al ; leave pointing at a safe r/o register
- sti ; restore interrupts
- pop ax
- ret
-
- PokeCMOS EndP
-
- EndIf
-
- ;===============================================================
-
- If Generating ne CMOSSave
-
- ReadCMOS Proc Near
-
- ; Open a file read the CMOS into a buffer
-
- lea dx,FileName ; DS:DX point to file
- xor al,al ; AL=0 is attribute read/only
- mov ah,03Dh ; DOS open function
- int 21h
- jc FileTrouble
- mov bx,ax ; save handle
- mov cx,128 ; read 128 bytes
- lea dx,CMOSBuff ; buffer address
- mov ah,3fH ; DOS read
- int 21h
- jc FileTrouble
- cmp ax,128
- jne FileTrouble
- mov ah,3eh ; DOS close
- int 21h
- jc FileTrouble
- ret
-
- ReadCMOS EndP
-
- EndIf
-
- ;===============================================================
-
- if Generating eq CMOSSave
-
- WriteCMOS Proc Near
-
- ; Create a file; write CMOS to it
-
- lea dx,FileName ; DS:DX point to file
- xor cx,cx ; CX=0 is attribute
- mov ah,03ch ; DOS create function
- int 21h
- jc FileTrouble
- mov bx,ax ; SAVE HANDLE
- MOV CX,128 ; write 128 bytes
- lea dx,CMOSBuff ; buffer address
- mov ah,40h ; DOS write
- int 21h
- jc FileTrouble
- cmp ax,128
- jne FileTrouble
- mov ah,3eh ; DOS close
- int 21h
- jc FileTrouble
- ret
-
- WriteCMOS EndP
-
- EndIf
-
- ;===============================================================
-
- Parse Proc near
- ; Parse the command line and process each parameter.
- ; sample inputs
- ; CMOSSAVE A:\CMOS.SAV /Q
- ; CMOSREST C:\CMP\CMOS.SAV
- ; counted string at HEX 80 PSP
- ; contains command line.
- ; Preceeded by unwanted spaces.
- ; possibly followed by unwanted spaces.
- ; currently missing a trailing null.
- ; Both ES and DS cover the command line
- ; since this is a COM file.
- ; However to make code compatible with EXE
- ; files we use ES: to cover the command line.
- call CommandLine ; string addr ES:bx, length cx.
- jcxz NullParms
-
- mov ParmIndex,1 ; start parsing with the 1st parm
- ; note start with 1 not 0!
- ; We don't want the the program name.
- jmp Short Parseloop
-
- NullParms:
- NoMoreParms:
- test fileName,-1 ; ensure some sort of filename provided
- jz BadCmd ; by the time all done
- mov ax,DS
- mov ES,ax ; restore ES to match DS
- ret ; we are done
-
- Parseloop:
- call CommandLine ; commmandline=ES:bx, length=cx
- mov dx,ParmIndex
- call NthParm ; work left to right
- jcxz NoMoreParms ; null param means no more
- ; e.g. ES:bx points to A: or /Q
- ; cx is length of that piece
- mov ax,ES:[bx] ; al=A ah=: or al=/ ah=Q
- call ToUc ; Convert both chars to upper case
- xchg ah,al
- call ToUc
- cmp ah,'/' ; drive or Switch?
- jne ProcessDrive
- ; it was a switch with slash
- ; was it /Q?
- cmp al,'Q'
- JE ProcessQ
- ; something else, give up.
- BadCmd:
- jmp SyntaxTrouble
-
- ProcessDrive:
- ; don't insist on drive letter.
- ; should have C:\CMP\CMOS.SAV
- ; copy string to FileName
- ; followed by a null
-
- mov si,bx
- lea di,FileName ; ES:si -> DS:di ( segs are backwards )
- push ES ; swap ES DS
- push DS
- pop ES
- pop DS
- rep movsb ; copy filename DS:si -> ES:di
- mov ES:[di],byte ptr 0 ; append a null
- push ES ; swap ES DS back to normal
- push DS
- pop ES
- pop DS
- jmp short Next
-
- ProcessQ: ; handle /Quiet
- mov SlashQuiet,-1
-
- Next:
- inc ParmIndex ; bump loop counter
- jmp Parseloop ; loop till hit null param
-
- Parse EndP
-
- ;===============================================================
-
- CommandLine Proc near
- ; gets command line into ES:bx with length in cx.
- ; This version works for a COM file only.
- xor ch,ch
- mov cl,ES:80H
- mov bx,81H
- ret
- CommandLine EndP
-
- ;===============================================================
- NthParm Proc near
- ; Parses string for Nth Parameter delimited by blanks
- ; e.g. " A: /Q " with bx=1 would give string "/Q"
- ; on entry:
- ; ES:bx - string, usually the command line
- ; cx - length of string
- ; dx - which parm wanted 1=parm1 2=parm2 etc.
- ; NthParm only finds one parm per call.
- ; On exit ES:bx points to string and cx is its length.
- ; If there is no parm, the length will be 0.
- ; It also handles multiple leading/trailing blanks on parms.
- mov al,20h ; al = blank -- the search char
- mov di,bx
- Parmloop:
- ; Remove leading blanks on parm
- jcxz NullParm ; jump if null string
- repe scasb ; scan ES:di forwards till hit non blank
-
- ; di points just after it
- ; cx is one too small, or 0 if none found
- je NullParm ; jump if entire string was blank
- inc cx ; cx is length of remainder of string
- dec di ; di points to non-blank
- mov si,di ; remember start of string
- ; Search for terminating blank on parm
- jcxz NullParm ; jump if null string
- repne scasb ; scan ES:di forwards till hit blank
- ; di points just after it
- ; cx is one too small, or 0 if none found
- jne NoBlank ; jump if entire string was non blank
- inc cx ; cx is length of remainder of string
- dec di ; backup di to point to blank at string end
- NoBlank:
- ; di=addr tail end of command string,
- ; cx=len tail end of command string
- ; si=addr parm just parsed
- ; Major loop for each parm
- dec dx
- jnz Parmloop ; loop once for each parm
-
- mov cx,di
- sub cx,si ; cx is length of parameter.
- mov bx,si
- ret
- NullParm: ; was no nth parameter
- mov cx,0
- mov bx,si
- ret
- NthParm EndP
-
- ;==============================================================
-
- ToUC PROC NEAR
- ; converts char in AL to upper case
- cmp al,'a'
- jb FineAsIs
- cmp al,'z'
- ja FineAsIs
- sub al,20H ; convert a to A
- FineAsIs:
- ret
-
- ToUc ENDP
-
- ;======================================
-
- ;===============================================================
-
- CODE ends ; end of code segment
- end Start
-