title	dosa.asm
;
; ASM routines lifted from WINCOM
;
; ToddLa & RussellW
;
; DavidLe removed all but current drive/directory functions
;
?PLM=1	    ; PASCAL Calling convention is DEFAULT
?WIN=0      ; Windows calling convention
PMODE=1     ; Enable enter/leave

        .xlist
        include cmacros.inc
        .list

; -------------------------------------------------------
;               DATA SEGMENT DECLARATIONS
; -------------------------------------------------------

ifndef SEGNAME
    SEGNAME equ <_TEXT>
endif

createSeg %SEGNAME, CodeSeg, word, public, CODE

sBegin  CodeSeg
        assumes CS,CodeSeg
        assumes DS,Data
        assumes ES,nothing

; ----------------------------------------------------------------
;
; @doc	INTERNAL
; @api  int | DosChangeDir | This function changes the current drive
; and directory.
;
; @parm LPSTR | lpszPath | Points to the desired drive and directory path.
; The optional drive identifier must be the first character, followed by
; a colon.  The drive identifier is followed by an optional path
; specification, which may be relative or absolute.
;
; @rdesc Returns one of the following values:
;
; @flag	1	The drive and directory were successfully changed.
; @flag	0	The specified pathname is invalid.  The drive and
;		current directory is restored
;		to the default values when the function was called.
; @flag	-1	The specified drive is invalid.  The drive and directory
;		current directory is restored to the default values when the
;		function was called.
;
; @xref	DosGetCurrentDir, DosGetCurrentPath, DosGetCurrentDrive
;
szCurDir:
        db '.',0

cProc	DosChangeDir,<PUBLIC, FAR, PASCAL>, <ds>
	parmD	lpszPath

	LocalW	fDriveChange
	LocalW	wLastDrive
	LocalW	wReturn
	LocalV	szPoint, 2
cBegin
	mov	fDriveChange, 0

	lds	dx, lpszPath
	mov	bx, dx

	; Check if a drive was specified.  If not, then go direct to ChDir
	cmp	BYTE PTR ds:[bx+1],':'	; no drive allowed
	jnz	chdnodrive

	;  get the current drive to save it in case the drive change/
	;  dir change fails, so we can restore it.
	mov	ah, 19h
	int	21h
	mov	wLastDrive, ax

	mov	fDriveChange, 1		; flag the drive change

	;  Now, change the drive to that specified in the input
	;  string.
	mov	dl, ds:[bx]		; Get the drive letter
	or	dl, 20h			; lower case it
	sub	dl, 'a'			; and adjust so 0 = a:, 1 = b:, etc

	mov	ah, 0eh			; set current drive
	int	21h

	mov	ah, 19h			; get current drive
	int	21h

	cmp	al, dl			; check that chDrive succeeded
	jne	chdDriveError

	;  as a further test of whether the drive change took, attempt
	;  to change to the current directory on the new drive.
        mov     ax, cs
	mov	ds, ax
        mov     dx, CodeSegOFFSET szCurDir
	mov	ah, 3bh
	int	21h
	jc	chdDriveError

	lds	dx, lpszPath
	add	dx, 2			; skip over the drive identifier
	mov	bx, dx
	;; if they passed only drive: without dir path, then end now
	cmp	BYTE PTR ds:[bx], 0	; if path name is "", we are there
	jz	chdok

chdnodrive:
	mov	ah, 3bh
	int	21h
	jc	chdPathError
chdok:
	mov	ax, 1
chdexit:
cEnd

chdPathError:
	mov	wReturn, 0
	jmp	short chderror

chdDriveError:
	mov	wReturn, -1

chderror:
	;  if a drive change occurred, but the CD failed, change
	;  the drive back to that which was the original drive
	;  when entered.
	mov	ax, fDriveChange
	or	ax, ax
	jz	chdNoCD
	
	mov	dx, wLastDrive
	mov	ah, 0eh
	int	21h
	mov	ax, wReturn
	jmp	short chdexit
chdNoCD:
	xor	ax, ax			; return zero on error
	jmp	short chdexit




; ----------------------------------------------------------------
;
; @doc	INTERNAL
; @api  WORD | DosGetCurrentDrive | This function returns the drive identifier
;	of the current drive.
; @rdesc        Returns the drive code of the current drive: 0 is drive
;		A:, 1 is drive B:, etc.
;
; @comm This function assumes that drive A: is zero. Some
;	other DOS functions assume drive A: is one.
;
; @xref	DosSetCurrentDrive
;

cProc	DosGetCurrentDrive,<PUBLIC, FAR, PASCAL>
cBegin
	mov	ah, 19h		; Get Current Drive
	int	21h
	sub	ah, ah		; Zero out AH
cEnd


; ----------------------------------------------------------------
;
; @doc	INTERNAL WINCOM
; @api	WORD | DosSetCurrentDrive | This function sets the current DOS
;		drive to be the specified drive.
;
; @parm	WORD | wDrive | Specifies the drive to be set as the current drive.
;               0 indicates drive A:, 1 is B:, etc.
;
; @rdesc	Returns TRUE if the drive change was successful, or FALSE
;               if the current drive was not changed.
;
; @comm         This is the same range returned by <f DosGetCurrentDrive>.
;               Other functions assume drive A: is 1.
;
;
; @xref	DosGetCurrentDrive
;

cProc	DosSetCurrentDrive,<FAR, PUBLIC, PASCAL>
ParmW Drive
cBegin
	mov     dx, Drive
	mov     ah, 0Eh		; Set Current Drive
	int     21h

	; Check if successful
	mov	ah, 19h		; get current drive
	int	21h

	cmp	al, dl		; check that chDrive succeeded
	jne	SetDriveError
	mov	ax, 1h		; return true on success
SetDriveExit:
cEnd
SetDriveError:
	xor	ax, ax		; return false on error
	jmp	short SetDriveExit



; ----------------------------------------------------------------
;
; @doc	INTERNAL WINCOM
;
; @api	WORD | DosGetCurrentDir | This function copies the current
; directory of the specified drive into a caller-supplied buffer.  This
; function differs from the <f DosGetCurrentPath> function in that it
; copies only the current directory of the specified drive, whereas
; <f DosGetCurrentPath> copies the current drive and its current directory
; into the caller's buffer.
;
; @parm	WORD | wCurdrive | Specifies the drive.  0 is the default drive,
;		1 is drive A, 2 is drive B, etc.
;
; @parm	LPSTR | lpszBuf | Points to the buffer in which to place the
; current directory.  This buffer must be 66 bytes in length.
; The returned directory name will always have a leading '\' character.
;
; @rdesc Returns NULL if the function succeeded.  Otherwise, it returns
; the DOS error code.
;
; @comm The drive identifier value specified by <p wCurdrive>
;	assumes that drive A: is one, whereas the <f DosGetCurrentDrive>
;	function assumes that drive A: is zero.
;
; @xref	DosGetCurrentDrive, DosChangeDir, DosGetCurrentPath
;

cProc	DosGetCurrentDir,<PUBLIC,FAR,PASCAL>,<si,di,ds>
	parmW	wCurdrive
	parmD	lpDest
cBegin
	cld
	les	di, lpDest	; es:di = lpDest
	mov	al, '\'
	stosb
	push	es
	pop	ds		; ds = es
	mov	si, di		; ds:si = lpDest + 1
	; Add NULL char for case of error
	xor	al, al
	stosb			; null terminate in case of error
	
	mov	ah, 47h		; GetCurrentDirectory
	mov	dx, wCurdrive	; of this drive
	int	21h
	jc	CWDexit		; return error code for failure
	xor	ax, ax		; return NULL on success
CWDexit:
cEnd

sEnd	CodeSeg

end