You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

269 lines
11 KiB
NASM

;GETCD V 1.0 | 3-NOV-2024 Jay Moore/dewdude@pickmy.org
;Finds CDROM drive letter and places in CDROM
;environment variable
;
;A replacement for FINDCD.EXE written in NASM Assembly and
;manipulates a lot of memory directly. Not a drop-in
;replacement, but close. Designed as a .BAT utility, the
;only user interaction is feeding it a path/filename and
;checking the environment variable. Default returns first
;CDROM drive that has a disc.
;
;GETCD [/?] SEARCHSTRING
;
;SEARCHSTRING can be a file, directory name, path, or wildcard.
;Not specifying a file does a wildcard search on root of CD.
;You do not need to add a leading \ to the string.
;/? displays the usual help, except poorly written.
;
;CDROM=E:
;
;Is how the variable will be set. If you desire a trailing \;
;just have your script 'set CDROM=%CDROM%\'
;
;This will absolutely overwrite any existing CDROM= contents with
;the above format; and will also shift data around to make it the
;exact length. It will also create an environment variable if none
;exists. This is contrast with FINDCD.EXE; which not only needs
;you to set the CDROM= variable first, but requires patching the
;.exe to change the file search. Gross.
;
;Displayed output is minimal. The only error displayed is if the
;environment block is full. A lack of CDROM drives will exit with
;errorlevel 255. Anything else just doesn't change (or create) the
;CDROM variable. You'll need to do that after execution in your script.
;
;argument section of PSP starts at 80h; byte count, bytes, terminator.
;term is 0x0D, but it's not included in byte count. this can include
;spaces if full name.ext is used or user just hit space.
;the pointer to parent's PSP lives at 16h; env-block pointer is 2Ch
;offset 3 one segment back is the block allocation size.
;this means I initialize di to 10h now and just leave es where it is
;as all counts are relative from di's initialization
[CPU 8086]
[BITS 16]
org 100h
section .text
global start
start:
xor cx, cx ; clear out cx
mov si, 80h ; move si to psp argument count
mov cl, [si] ; load argument byte count
argproc:
jcxz varinit ; stop if cx is 0
inc si ; increment si
cmp byte [si], 20h ; Invalid char/space check
jbe skipit ; jump to loop if <20h
cmp byte [si], 5ch ; is it backslash
jz skipit ; jump if it is
cmp word [si], 3f2fh ; check for /?
jz hllp ; jump if it is
jmp ldfile ; land here when done
skipit:
loop argproc ; dec cx, jmp argproc ;)
ldfile:
lea di, filename ; load filename to di
repe movsb ; copy argument to filename
mov byte [di], 0 ; null for good measure
varinit:
mov es, [16h] ; parent psp pointer
mov ax, [es:2ch] ; load block segment
dec ax ; segment one below
mov es, ax ; go back a segment
mov ax, [es:3h] ; this is the size
mov cl, 4 ; load 4 to cl for shl
shl ax, cl ; bit shift left 4
mov [blocksize], ax ; store
mov di, 10h ; move di up to env blk
readblock:
cmp word [es:di], 0 ; end of block?
jz endofblock ; variiable missing
lea si, envname ; load envname address
mov cx, 6 ; load six
repe cmpsb ; repe compare string
jnz readblock ; if not variable, go back up
sub di, 6 ; subtract 6
mov [envstart], di ; write starting location
add di, 6 ; place it back
findend:
inc di ; now to find the end
cmp word [es:di], 0 ; is it the end?
jnz findend ; jump back up if not
endofblock:
inc di ; actual end of block
mov [blockend], di ; write that down
cmp word [envstart], 0 ; did we find a var
jz noenv ; jump if novar
mov di, [envstart] ; go back to the env start
mov ax, 1212h ; get the asciz length
int 2fh ; in to cx
cmp cx, 9 ; and see if it's 9
jb envtoosmall ; jump to envtosmall if too small
ja envtoobig ; jump to envtoobig if too big
envokay:
add di, 6 ; drive letter is six in
jmp drivego ; es:di ready for letter
envtoobig:
mov si, di ; duplicate pointers
mov word [es:di+7], 0x003A ; write : and null
add si, 9 ; put si where i need di
call endcheck ; check relative position
call bytesize ; get byte count to copy
xchg di, si ; now we swap
cld ; clear that direction
call copybytes ; copy byte routine
mov word [es:di], 0 ; double null new end
mov di, [envstart] ; go back to the env
jmp envokay ; might as well jump
noenv:
call envfree ; check free space
mov di, [blockend] ; go to block end
newenv:
lea si, envname ; load address of envname
mov cx, 8 ; we want 8 bytes
repe movsb ; write 'em
mov word [es:di], 0000h ; double null new term
sub di, 2 ; back di up two
jmp drivego ; es:di is ready
envtoosmall:
mov byte [oneornine], 01h ; change envfree's cmp value
call envfree ; check environment space
call endcheck ; check relative position
call bytesize ; call for byte count
add cx, 3 ; add three to that count
mov si, [blockend] ; load the end of block offset to si
mov di, [blockend] ; load it again to di
inc di ; move it up one
std ; set direction flag
call copybytes ; copybytes routine
mov word [es:di+1], 0x003A ; write the : and null one byte up
drivego:
mov ax, 2524h ; Ignore Critical Errors
lea dx, [new24] ; pointer to new handler
int 21h ; interrupt to change ivt
mov ax, 1500h ; function to get drive info
int 2Fh ; from int 2f
xchg bx, cx ; swap count and starting number
jcxz nodrives ; see if we have drives
add bl, 41h ; convert number to letter
loadltr:
push cx ; push drive count to stack
mov [drivevar], bl ; copy drive letter to ram
lea dx, drivevar ; load address of drivevar
mov ah, 4Eh ; load find first file
mov cl, 17h ; all the options
int 21h ; call the interrupt
jnc envset ; found file, go on
pop cx ; pop drive count back in to CX
inc bl ; increment to next drive
loop loadltr ; loop back around
jmp exit ; no match, leave
envset:
lea si, drivevar ; loads address to si
movsb ; moves ds:si to es:di
jmp exit ; we're done, go home
nodrives:
mov al, 0FFh ; load errorlevel 255 to al
exit:
mov ax, 4c00h ; standard dos kernel terminate
int 21h ; bye.
endcheck:
push cx ; push cx to stack
add cx, di ; add di to cx
sub cx, [blockend] ; subtract blockend from cx
jcxz fakenew ; jump if zero
pop cx ; invert cx (it should be neg)
ret ; go back to moving bytes
fakenew:
sub sp, 04h ; reset the stack you animal
mov di, [envstart] ; load di
jmp newenv ; pretend it's new
copybytes:
push ds ; push ds on to the stack
push es ; push es on to the stack
pop ds ; pop es in to ds for this
repe movsb ; copy ds:si to es:di till cx is 0
pop ds ; pop ds's original value back out
ret
envfree:
mov ax, [blocksize] ; load size
sub ax, [blockend] ; calculate free
cmp al, [oneornine] ; need n free
jz blockfull ; not enough space
ret ; return if ok
bytesize:
add di, cx ; place di at next variable
mov cx, [blockend] ; load the end of the block
sub cx, di ; subtract the actual usage
ret ; return from subroutine
hllp:
lea dx, hlptxt ; address of $-terminated strong
mov ah, 09h ; display string function
int 21h ; dos interrupt
jmp exit ; exit
new24:
mov al, 3 ; FAIL! (Hitting F, but faster)
iret ; Return from interrupt.
section .data
hlptxt:
db 'GETCD 1.0 | 4-NOV-2024 | dewdude@pickmy.org | Freeware/MIT', 0x0d, 0x0a
db 'Sets "CDROM=[driveletter]:" by searching CD-ROM drives', 0x0d, 0x0a
db 'USAGE: GETCD [/?] [FILE/OR/PATH/TO/FILE.EXT]', 0x0d, 0x0a
db 'Finds file on CD-ROM drives. Returns first match. Allows wildcards.', 0x0d, 0x0a
db 'Creates/adjusts variable. Default search is wildcard.$', 0x0d, 0x0a
blockfull: db 'NO ENV FREE $'
blocksize: db 0, 0 ; holds block size
envstart: db 0, 0 ; start of cdrom=
blockend: db 0, 0 ; end of used block
oneornine: db 09h ; default 9
envname: db 'CDROM=' ; variable name
drivevar: db '0:\' ; variable's variable
filename: db '*', 0x00 ; (default) filename
;MIT No Attribution
;
;Copyright 2024 Jay Moore
;
;Permission is hereby granted, free of charge, to any person obtaining a copy of this
;software and associated documentation files (the "Software"), to deal in the Software
;without restriction, including without limitation the rights to use, copy, modify,
;merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
;permit persons to whom the Software is furnished to do so.
;
;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
;INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
;PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
;HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
;OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
;SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.