;	SCCSID = @(#)dosexec.asm	6.1 90/11/17
;      SCCSID = @(#)dosexec.asm 1.5 90/01/30

	TITLE	dosexec - DOSEXECPGM interface

;***	dosexec.asm - implement the visible API for DOSEXECPGM
;
;	DOSEXECPGM is used to do explicit searching of the PATH
;	environment variable. It first determines if the user supplied
;	name is absolute (see IsPathAbsolute for details). If it is then
;	no path searching is performed. If not the DOSSEARCHPATH API is
;	used to explicitly search the paths pointed to by PATH.


;***	Modification History
;
;	Jun-01-1988	JSF	Add DBCS checks to IsPathAbsolute
;				(1.2 PTM 987)
;	11/18/93	noto	Define which segment for Page Tuning DLL



page	,132
.286p

.xlist
include curdir.inc
include basemaca.inc
include error.inc
include dc1segs.inc						; DCR 704
.list

DATA	SEGMENT 						; DCR 704

PATHStr DB	'PATH',0                ; path env. var.

DATA	ENDS

SHRDATA SEGMENT 						; DCR 704

	extrn	dbcs_data:byte

SHRDATA ENDS

SEARCHCTRL	EQU	7		; search cur. dir. first & interpret
					; PathRef as an env. var.
					; Ignore net errors.

	EXTRN	DOSSEARCHPATH:FAR
	EXTRN	DOSIEXECPGM:FAR


CODE16C_TUNE2	SEGMENT DWORD USE16 PUBLIC 'CODE'
CODE16C_TUNE2	ENDS

CODE16C_TUNE3	SEGMENT DWORD USE16 PUBLIC 'CODE'
	extrn	StrNCpy:near
CODE16C_TUNE3	ENDS



CODE16C_TUNE2	   SEGMENT					; DCR 704

    ASSUME cs:CODE16C_TUNE2

;**	DOSEXECPGM - Execute a program
;
;	ENTRY		DWORD	ObjNameBuf
;			WORD	ONBLen
;			WORD	0 = start sync process
;				1 = start async process, discard result code
;				2 = start async proc, save result code for CWait
;				3 = start async process, with tracing
;			DWORD	Address to argument string
;			DWORD	Address to environment string
;			DWORD	Address to place PID of new program
;			DWORD	Address of filename string to execute
;		SS:SP ->DWORD	Far return to caller
;
;	EXIT	AX = error code
;
;	USES	FLAGS

Procedure   DOSEXECPGM,FAR
    ASSUME ds:NOTHING, es:NOTHING, ss:NOTHING

ArgVar	    PgmPointer,DWORD
ArgVar	    PIDPointer,DWORD
ArgVar	    EnvPointer,DWORD
ArgVar	    ArgPointer,DWORD
ArgVar	    AsyncFlag,WORD
ArgVar	    ONBLen,WORD
ArgVar	    ObjNameBuf,DWORD

LocalVar    PathBuf,PMPATHLEN		; path building buffer
LocalVar    AbsFlag,BYTE		; absolute path flag = NOT 0 if path
					; is absolute

	EnterProc

	pushf
	SaveReg 	<ds, es, si, di, bx>

	mov	AbsFlag,NOT 0		; assume path is absolute

	lds	si,PgmPointer
	ASSUME	ds:NOTHING
	call	IsPathAbsolute		; check if absolute path is specified.
	jc	dep1			; if so, do not search PATH

	mov	AbsFlag,0		; path is not absolute
	push	SEARCHCTRL		; DOSSEARCHPATH control word
	push	DATA
	pop	ds
	ASSUME	ds:DATA
	lea	si,PATHStr		; (ds:si) -> "PATH", env. var. name
	ASSUME	ds:NOTHING
	push	ds
	push	si
	lds	si,PgmPointer		; (ds:si) -> program (file) name
	push	ds
	push	si
	lea	ax,PathBuf		; (ss:ax) -> path buffer
	push	ss
	push	ax
	push	PMPATHLEN		; length of path buffer
	call	DOSSEARCHPATH
	or	ax,ax			; error?
	jnz	dep4			;  yes

;	If AbsFlag is set the user passed an absolute path, so we will attempt
;	to exec what is pointed at by PgmPointer. If AbsFlag is clear then we
;	have built a path which is in PathBuf.

dep1:	push	ObjNameBufh
	push	ObjNameBufl
	push	ONBLen
	push	AsyncFlag
	push	ArgPointerh
	push	ArgPointerl
	push	EnvPointerh
	push	EnvPointerl
	push	PIDPointerh
	push	PIDPointerl
	cmp	AbsFlag,0		; is path path caller passed absolute?
	jne	dep2			; yes

	lea	ax,PathBuf		; (ss:ax) -> path (from DOSSEARCHPATH)
	push	ss
	push	ax
	jmp	SHORT dep3

dep2:	push	PgmPointerh		; caller supplied path
	push	PgmPointerl

dep3:	call	DOSIEXECPGM
	jmp	SHORT dep6		; done

;	If we get here then DOSSEARCHPATH returned an error.
;	We must copy the name of the program we were searching
;	for into the object name buffer.

dep4:	cmp	ax,ERROR_ENVVAR_NOT_FOUND	; need to map the error code?
	jne	dep4d				;  no

	mov	ax,ERROR_FILE_NOT_FOUND
dep4d:	SaveReg 	<ax, cx>
	lds	si,PgmPointer		; (ds:si) -> program name
	ASSUME	ds:NOTHING
	les	di,ObjNameBuf		; (es:di) -> object name buffer
	ASSUME	es:NOTHING
	mov	cx,es
	or	cx,di			; is ObjectNameBuf NULL?
	jz	dep5			; yes
	mov	cx,ONBLen		; cx = length of ObjectNamBuf
	mov	bx,di			; (es:bx) -> object name buffer
	add	bx,cx
	jnc	dep4h			; jump if we didn't go beyond 64k limit

	xor	bx,bx
dep4h:	dec	bx			; (es:bx) -> end of object name buffer
	call	StrNCpy 		; copy the program name into the buffer
dep5:	RestoreReg	<cx, ax>

dep6:	RestoreReg	<bx, di, si, es, ds>
	ASSUME	ds:NOTHING
	popf
	LeaveProc
	ret	?aframe

EndProc DOSEXECPGM


;**	IsPathAbsolute - determine if a path is 'absolute'
;
;	IsPathAbsolute determines if a given path represents an
;	absolute path name. Absolute is defined to have either of
;	the following characteristics:
;
;	1) A ':' as its second character. This is taken to mean
;	   that a drive has been specified.
;
;	2) A '/' or a '\' occuring anywhere in the name.
;	 (Except after a DBCS lead character, see below)
;
;	There is no attempt to recognize any abnormalities with the path
;	(e.g. missing NUL terminator).
;
;
;	ENTRY	(ds:si) -> path to be checked.
;
;	EXIT	Carry set if path is absolute, clear otherwise.
;
;	USES	al, bx, si, es, flags


Procedure	IsPathAbsolute, NEAR
	ASSUME	ds:NOTHING, es:NOTHING

	push	SHRDATA
	pop	es			; Load segment of DBCS range data
	ASSUME	es:SHRDATA

	cmp	BYTE PTR [si],0 	; end of string already?
	je	ipa5			; yes, path absolute, jump to exit

	cmp	BYTE PTR [si + 1],':'   ; drive specified?
	je	ipa5			; yes, path absolute, jump to exit

	cld
ipa1:	lodsb

;	See if there is any DBCS support in operation. If not, the first
;	 DBCS range low byte will be zero.

	cmp	dbcs_data,0		; DBCS in operation?
	jne	ipa7			; yes, jump to DBCS check

;	Here character is not a DBCS character. Check to see if this is
;	 a slash character, and if so declare the path absolute.

ipa4:	cmp	al,'/'                  ; is char a '/'?
	je	ipa5			; yes, path absolute, jump to exit
	cmp	al,'\'                  ; is char a '\'?
	je	ipa5			; yes, path absolute, jump to exit
	or	al,al			; reached end of string?
	jnz	ipa1			; no, continue search
	stc				; next instruction toggles to clear

;	This is the common exit. To save a jump, exit through label
;	 as appropriate to set carry for absolute path, and carry clear
;	 for no absolute path.

ipa5:	cmc
ipa6:	ret


;	End of main routine


;	This is where we exhaustively check to see if this is a DBCS
;	 lead byte. This is removed from the main loop to optimise
;	 the non DBCS case.
;	Check to see if this character is a DBCS lead character by seeing
;	 if it lies in one of the ranges ocupied by DBCS lead bytes.
;	If it is a DBCS lead character, then the next character is not a
;	 normal ASCII character, and even if it is a slash, we ignore it.
;	Note that ordinary ASCII characters fall below the first DBCS
;	 range and will thus be detected by the first test.

ipa7:	mov	bx,offset dbcs_data	; address DBCS range table

ipa8:	cmp	al,es:[bx]		; char above low byte of DBCS range?
	jb	ipa4			; no, resume main loop

	cmp	al,es:[bx].1		; is char below high byte of range?
	jbe	ipa9			; yes, got DBCS lead char

;	Not in that DBCS range, try next range if we haven't reached
;	 end of table.

	inc	bx
	inc	bx			; point to next pair of range bytes
	cmp	byte ptr es:[bx],0	; end of table?
	jne	ipa8			; no, check next range
	jmp	ipa4			; yes, go check char for slash

;	Here we found a DBCS lead character. Skip check for slash on this
;	 and next character. (which will be the second DBCS byte). Make sure
;	 we are not skipping the terminating zero, otherwise we'll miss it.
;	Note that si has already been inc'ed to the next character by
;	 the lodsb.

ipa9:
	cmp	byte ptr [si],0 	; is next character the terminating
					;  zero?
	je	ipa6			; yes, finished search, jump to exit
	inc	si			; no, skip next character,
	jmp	ipa1			;  and try character after that one.

EndProc IsPathAbsolute


CODE16C_TUNE2	ENDS

END
