|
|
;======================================================= ; ; Macros stolen from cmacros.inc (so we don't have to include it all) ; .286p
externNP macro n irp x,<n> extrn x:near endm endm
externFP macro n irp x,<n> extrn x:far endm endm
externW macro w irp x,<w> extrn x:word endm endm
assumes macro s,ln assume s:_&ln endm
createSeg macro n,ln,a,co,cl,grp n segment a co '&cl' n ends endm
sBegin macro seg assume cs:_&seg _&seg segment endm
sEnd macro seg _&seg ends assume cs:nothing endm
errnz macro x ;;display error if expression is <>0 if2 if x ;;if expression is non-zero, errnz1 <x>,%(x) endif endif endm
errnz1 macro x1,x2 = *errnz* x1 = x2 .err endm
errn$ macro l,x ;;error if <$-label1 (exp2)> <>0 errnz <offset $ - offset l x> endm
createSeg _DATA,DATA,WORD,PUBLIC,DATA
;======================================================= ; ; Error API definitions ; ExternFP <HandleParamError>
; error codes include logerror.inc
;================================================================ ; Variable and temporary initialization
VLseg equ <> ; Holds current segment name
VLopen = 0 VLerrnotinvoked = 0 ifndef VLnogenpall VLnogenpall = 0 endif
VLnogen = 0 VLnogenparm = 0
VLsavees = 0 VLsavebx = 0
;if1 if 1
;================================================================ ; Utility macros
;--------------------------------------------------------------------------- ; ; lodsw cs:[si] ; cslodsw macro db 2eh ;; CS override lodsw endm
;--------------------------------------------------------------------------- ; ; lodsb cs:[si] ; cslodsb macro db 2eh ;; CS override lodsb endm
SkipTwoBytes macro db 0A9h ;; Opcode for CMP AX,(immediate word) endm
;--------------------------------------------------------------------------- ; ; Define a as the concatenation of b & c ; concat macro a,b,c,d,e,f a equ <b&c&d&e&f> endm
;--------------------------------------------------------------------------- ; ; Assign a to b. ; equate macro a,b a = b endm
; ; Print a message ; _print macro a,b,c if2 %out a&b&c endif endm
;===============================================================
;--------------------------------------------------------------------------- ; ; _gensub LABEL ; ; Causes per-segment subroutine code associated with type LABEL ; to be generated, by setting the genLABEL&lseg flag. ; _gensub2 macro l,s gen&l&s = 1 endm
_gensub macro l _gensub2 <l>,%VLseg endm
;--------------------------------------------------------------------------- ; _SwitchSeg ; ; Switches current segment to seg, creating the segment if needed. ; _SwitchSeg macro seg,oldseg ifdifi <&seg>,<oldseg>
ifnb <oldseg> sEnd oldseg endif
concat <VLseg>,seg,
createSeg _&seg,seg,WORD,PUBLIC,CODE
sBegin seg assumes CS,seg
endif endm
;--------------------------------------------------------------------------- ; API ; API macro rettype,name,seg,optlist
if VLopen APIEND endif
VLname equ <name> VLcbparms = 0 VLcbskip = 0 VLerrnotinvoked= 1 VLopen = 1 VLnogen = 0 VLnogenparm = 0 VLasm = 0 VLfunnyframe = 0 VLnodata = 0 VLcargs = 0 VLplist equ <> VLATMframe = 0 ; special entry/exit code sequence for ATM's patching VLATMfrmds = 0 ; ATM entry/exit code: mov ax,_DATA at beginning.
VLsavees = 0 VLsavebx = 0 _SwitchSeg seg,%VLseg
irp opt,<optlist>
ifidni <opt>,<NOGEN> VLnogen = 1 endif
ifidni <opt>,<VOID> VLnogen = 1 endif
ifidni <opt>,<ASM> VLasm = 1 endif
ifidni <opt>,<ATMFRAME> VLATMframe = 1 endif
ifidni <opt>,<ATMFRAMEDS> VLATMfrmds = 1 VLATMframe = 1 endif
ifidni <opt>,<FUNNYFRAME> VLfunnyframe = 1 endif
ifidni <opt>,<NODATA> VLnodata = 1 endif
ifidni <opt>,<DEBUGONLY> ifndef DEBUG VLnogen = 1 endif endif
ifidni <opt>,<C> VLcargs = 1 endif
ifidni <opt>,<SAVEES> VLsavees = 2 ; sizeof(ES) endif
ifidni <opt>,<SAVEBX> VLsavebx = 2 ; sizeof(BX) endif
endm
concat <VLsegoffset>,<seg>,<offset> concat <VLnameerror>,<name>,<_error> concat <VLnamecbparms>,<name>,<cbparms>
if1 equate %VLnamecbparms, %VLcbparms else equate %VLnamecbparms, %VLnamecbparms endif
ife VLnogen
ife VLcargs concat <VLiname>,<I>,<name> ExternNP I&name
public name name: else concat <VLiname>,<_I>,<name> ExternNP _I&name
public _&name _&name: endif
VLframe = 0 ; no frame set up yet.
endif ; VLnogen
endm ;; VL
;--------------------------------------------------------------------------- ; APIERR ; ; Optionally used after parameter decls to begin error handling code ; APIERR macro opts
ife VLnogen ife VLframe _print <Nothing to validate for >,%VLiname else pop dx ; pop off error handler address pop bp ; restore BP if VLATMframe dec bp ; fix BP back up endif if VLsavees pop es endif if VLsavebx pop bx endif endif jmp VLiname ; jmp to internal routine.
equate %VLnamecbparms, %VLcbparms
VLnameerror: VLerrnotinvoked = 0
endif ; VLnogen
endm ;; APIERR
;--------------------------------------------------------------------------- ; APIEND ; ; Used after APIERR to terminate error handling code. ; APIEND macro
_PurgeParms %VLplist
ife VLnogen
if VLerrnotinvoked APIERR endif if VLsavees pop es endif if VLsavebx pop bx endif ife VLcargs retf VLcbparms else retf endif
VLopen = 0
endif ; VLnogen
endm ;; APIEND
;--------------------------------------------------------------------------- ; ; _FlsFrame - Generate frame code ; _FlsFrame macro ife VLframe if VLATMfrmds mov ax,_DATA endif if VLsavebx push bx endif if VLsavees push es endif if VLATMframe inc bp push bp mov bp,sp push ds ; push ds and pop it off. pop ds ; (we need to pop DS rather than ; something fast like pop AX because ; ATM doesn't preserve DS itself) else push bp mov bp,sp endif push offset VLnameerror ; push address of error handler VLframe = 1 endif endm
;--------------------------------------------------------------------------- ; _ChkName ; ; Ensure name was specified
_ChkName macro name ifb <name> _print <Missing parameter name in >,%VLiname endif endm
;--------------------------------------------------------------------------- ; _ParmOpts ; ; Parse parameter option flags ; _ParmOpts macro opts
VLnogenparm = VLnogenpall
irp opt,<opts> ifidni <opt>,<DEBUGONLY> ifndef DEBUG VLnogenparm = 1 endif ifidni <opt>,<NOGEN> VLnogenparm = 1 endif endif endm endm
;--------------------------------------------------------------------------- ; _DefParm name,cb,opts ; ; Take care of default parameter stuff, such as defining argument. ; _DP_Add macro old,new ifb <old> VLplist equ <new> else VLplist equ <old,new> endif endm
_DefParm macro name,cb,opts _ChkName <name> _ParmOpts <opts>
if VLcargs concat _P_&name,<[bp]+6+>,%(VLcbparms+VLsavees+VLsavebx) VLcbparms=VLcbparms+(cb) else VLcbparms=VLcbparms+(cb) concat _P_&name,<[bp]+6->,%VLcbparms,<+>,%(VLnamecbparms+VLsavees+VLsavebx) endif
_DP_Add %VLplist,<_P_&name>
VLgen = 1 if VLnogenparm or VLnogen VLgen = 0 endif endm
;---------------------------------------------------------------------------- ; ; _GenParm name, cb, opts ; _GenParm macro name,cb,opts _DefParm <name>,<cb>,<opts> if VLgen _FlsFrame endif endm
lcall2 macro op,label,seg op label&seg endm
lcall macro label lcall2 <call>,<label>,%VLseg endm
ljmp macro label lcall2 <jmp>,<label>,%VLseg endm
; ; _PurgeParms - purge list of parameters we've defined ; _PurgeParms macro list irp sym,<list> sym equ <> endm endm
;--------------------------------------------------------------------------- ; LAYER_START ; ; Used before any VL invocations ; LAYER_START macro assumes ds,DATA
endm
;--------------------------------------------------------------------------- ; LAYER_END ; ; Ends all VL definitions ; LAYER_END macro if VLsopen ENDSTRUCT endif if VLopen APIEND endif if VLerrnotinvoked APIERR endif endm
;========================================================================= ; ; Structure related macros ; ; Structure globals
VLsopen =0
; ; STRUCT - begins a structure declaration ; STRUCT macro name,opts if VLsopen ENDSTRUCT endif VLsopen=1
concat VLcbs,<VLcbs>,name VLcbstruct = 0 endm
; ; ENDSTRUCT macro - terminates a STRUCT declaration ; ENDSTRUCT macro equate %VLcbs,%VLcbstruct
VLsopen =0 endm
; ; Define simple field macro, given: ; f = macro name ; cb = size of field ; _SSize macro cb,opts VLcbstruct = VLcbstruct + (cb) endm
_DefSimpleF macro f,cb f ¯o name,opts equate _F_&&name,%VLcbstruct _SSize cb &endm endm
_DefSimpleF F_char,1 _DefSimpleF F_BYTE,1
_DefSimpleF F_int,2 _DefSimpleF F_WORD,2 _DefSimpleF F_BOOL,2 _DefSimpleF F_FLAGS,2
_DefSimpleF F_LONG,4 _DefSimpleF F_DWORD,4
_DefSimpleF F_intMBZ,2 _DefSimpleF F_DWORDMBZ,4
_DefSimpleF F_LPVOID,4 _DefSimpleF F_CLPSTR,4 _DefSimpleF F_CLPSTR0,4 _DefSimpleF F_LPSTR,4
_DefSimpleF F_POINT,4 _DefSimpleF F_RECT,8
F_RGB macro name,cb,opts equate _F_&name,%VLcbstruct _SSize cb endm
F_RGCH equ <F_RGB>
F_RGW macro name,cw,opts equate _F_&name,%VLcbstruct _SSize (cw*2) endm
; ; Generate a P_?LP???? macro, given: ; ; n = parameter macro name (e.g., P_LPRECT) ; r = handler routine name (e.g., LP) ; cb = size of buffer ; ; The generated macro checks only whether the ; buffer is big enough. ; _GenLP macro n,r,cb &n ¯o name,opts _GenParm <name>,4,<opts> if VLgen mov ax,_P_&&name mov cx,_P_&&name+2 mov bx,cb lcall &r _gensub <LP> endif &endm endm
;========================================================================= ; ; Generic parameter macros ; P_2 macro name, opts _DefParm <name>,2,<opts> endm
P_4 macro name, opts _DefParm <name>,4,<opts> endm
P_char equ <P_2> P_int equ <P_2> P_BYTE equ <P_2> P_BOOL equ <P_2> P_WORD equ <P_2>
P_WORDMBZ equ <P_2> P_WORDMBNZ equ <P_2>
P_LONG equ <P_4> P_DWORD equ <P_4>
; ; Generic handle ; P_H macro name, opts _GenParm <name>,2,<opts> if VLgen mov ax,_P_&name lcall H _gensub H endif endm
; ; Generic handle or NULL ; P_H0 equ <P_2>
; ; Ensure signed value is min <= value <= max ; P_RVALUE macro name, min, max, opts local valok _GenParm <name>,2,<opts> if VLgen mov ax,_P_&name cmp ax,min jl @F cmp ax,max jle valok @@: mov bx,ERR_BAD_VALUE or ERR_WARNING lcall Inval_Param_ valok: endif endm
; ; Ensure signed value is 0 <= value <= max ; P_VALUE macro name, max, opts _GenParm <name>,2,<opts> if VLgen mov ax,_P_&name cmp ax,max jbe @F ;; unsigned comparison to catch < 0. mov bx,ERR_BAD_VALUE or ERR_WARNING lcall Inval_Param_ @@: endif endm
; ; Ensure unsigned value is value <= max ; P_UVALUE equ <P_VALUE>
; ; Ensure signed value is 0 <= value <= max ; P_VALUEW macro name, max, opts _GenParm <name>,2,<opts> if VLgen mov ax,_P_&name cmp ax,max jbe @F ;; unsigned comparison to catch < 0. mov bx,ERR_BAD_VALUE or ERR_WARNING lcall Inval_Param_ @@: endif endm
; ; Ensure unsigned value is value <= max ; P_UVALUEW equ <P_VALUEW>
; ; Ensure signed byte value is min <= value <= max ; if 0 P_BVALUE macro name,max,opts _GenParm <name>,2,<opts> if VLGen mov al,_P_&name cmp al,max jle @F lcall ErrorBValue @@: endif endm else P_BVALUE equ <P_2> endif
; ; Ensure that no incorrect bits are set in a flags word ; (i.e., (name & ~valid) == 0) ; P_FLAGS macro name, valid, opts _DefParm <name>,2,<opts> if not(valid) if VLgen _FlsFrame mov ax,_P_&name ife (low(not(valid))) test ah,high(not(valid)) else ife (high(not(valid))) test al,low(not(valid)) else test ax,not(valid) endif endif jz @F mov bx,ERR_BAD_FLAGS or ERR_WARNING lcall Inval_Param_ @@: endif endif endm
; ; Ensure that no incorrect bits are set in a flags dword ; (i.e., (name & ~valid) == 0) ; P_DFLAGS macro name, valid_l, valid_h, opts local flagok _DefParm <name>,4,<opts> if not(valid_l) or not(valid_h) if VLgen _FlsFrame mov ax,_P_&name mov cx,_P_&name+2 if not(valid_l) test ax,not(valid_l) if not(valid_h) jnz @F else jz flagok endif endif if not(valid_h) test cx,not(valid_h) jz flagok @@: endif mov bx,ERR_BAD_DFLAGS or ERR_WARNING lcall Inval_Param_ flagok: endif endif endm
; ; P_LPFN - function pointer ; P_LPFN0 - function pointer or NULL ; P_LPFN macro name, opts _GenParm <name>,4,<opts> if VLgen mov ax,_P_&name mov cx,_P_&name+2 lcall LPFN _gensub LPFN endif endm
P_LPFN0 macro name, opts _GenParm <name>,4,<opts> if VLgen mov ax,_P_&name mov cx,_P_&name+2 lcall LPFN0 _gensub LPFN endif endm
_GenBuf macro p,r P_&p ¯o lpch, cch, opts _DefParm <lpch>,4,<opts> _DefParm <cch>,2,<opts> if VLgen _FlsFrame mov ax,_P_&&lpch mov cx,_P_&&lpch+2 mov bx,_P_&&cch lcall &r _gensub LP endif &endm endm
_GenBufspl macro p,r P_&p ¯o lpch, cch, opts _DefParm <lpch>,4,<opts> _DefParm <cch>,2,<opts> if VLgen _FlsFrame mov ax,_P_&&lpch mov cx,_P_&&lpch+2 lea bx,_P_&&cch lcall &r _gensub LPBUF endif &endm endm
_GenBufspl <LPBUFFER>,<LPBUF> _GenBuf <CLPBUFFER>,<CLP> _GenBufspl <LPBUFFER0>,<LPBUF0> _GenBuf <CLPBUFFER0>,<CLP0>
; ; If pszBuf is valid, set its first byte to 0 ; E_SETEMPTY macro pszBuf,cchBuf,opts push bp mov bp,sp mov cx,_P_&cchBuf mov bx,_P_&pszBuf mov dx,_P_&pszBuf+2 pop bp lcall SETEMPTY _gensub SETEMPTY endm
; Same as above, but with no supplied count ; E_SETEMPTYNC macro pszBuf,opts push bp mov bp,sp mov cx,1 mov bx,_P_&pszBuf mov dx,_P_&pszBuf+2 pop bp lcall SETEMPTY _gensub SETEMPTY endm
_GenLP <P_LPSTR>,<LP>,1 _GenLP <P_LPSTR0>,<LP0>,1
P_CLPSTR macro name,cch,opts _GenParm <name>,4,<opts> if VLgen mov ax,_P_&name mov cx,_P_&name+2 ifb <cch> mov bx,-1 else mov bx,cch endif lcall CLPSZ _gensub LPSZ endif endm
P_CLPSTR0 macro name,cch,opts _GenParm <name>,4,<opts> if VLgen mov ax,_P_&name mov cx,_P_&name+2 ifb <cch> mov bx,-1 else mov bx,cch endif lcall CLPSZ0 _gensub LPSZ endif endm
_GenLP <P_LPVOID>,<LP>,1 _GenLP <P_LPVOID0>,<LP0>,1 _GenLP <P_CLPVOID>,<CLP>,1 _GenLP <P_CLPVOID0>,<CLP0>,1
_GenLP <P_LPBYTE>,<LP>,1 _GenLP <P_LPBYTE0>,<LP0>,1 _GenLP <P_CLPBYTE>,<CLP>,1 _GenLP <P_CLPBYTE0>,<CLP0>,1
_GenLP <P_LPINT>,<LP>,2 _GenLP <P_LPINT0>,<LP0>,2 _GenLP <P_CLPINT>,<CLP>,2 _GenLP <P_CLPINT0>,<CLP0>,2
_GenLP <P_LPWORD>,<LP>,2 _GenLP <P_LPWORD0>,<LP0>,2 _GenLP <P_CLPWORD>,<CLP>,2 _GenLP <P_CLPWORD0>,<CLP0>,2
_GenLP <P_LPBOOL>,<LP>,2 _GenLP <P_LPBOOL0>,<LP0>,2 _GenLP <P_CLPBOOL>,<CLP>,2 _GenLP <P_CLPBOOL0>,<CLP0>,2
_GenLP <P_LPLONG>,<LP>,4 _GenLP <P_LPLONG0>,<LP0>,4 _GenLP <P_CLPLONG>,<CLP>,4 _GenLP <P_CLPLONG0>,<CLP0>,4
_GenLP <P_LPDWORD>,<LP>,4 _GenLP <P_LPDWORD0>,<LP0>,4 _GenLP <P_CLPDWORD>,<CLP>,4 _GenLP <P_CLPDWORD0>,<CLP0>,4
;======================================================================= ; ; Common USER types ; STRUCT <POINT> F_int x F_int y ENDSTRUCT
_GenLP <P_LPPOINT>,<LP>,%VLcbsPOINT _GenLP <P_LPPOINT0>,<LP0>,%VLcbsPOINT _GenLP <P_CLPPOINT>,<CLP>,%VLcbsPOINT _GenLP <P_CLPPOINT0>,<CLP0>,%VLcbsPOINT P_POINT equ <P_4>
STRUCT <RECT> F_int left F_int top F_int right F_int bottom ENDSTRUCT
_GenLP <P_LPRECT>,<LP>,%VLcbsRECT _GenLP <P_LPRECT0>,<LP0>,%VLcbsRECT _GenLP <P_CLPRECT>,<CLP>,%VLcbsRECT _GenLP <P_CLPRECT0>,<CLP0>,%VLcbsRECT
;======================================================================= ; ; Common KERNEL types ; P_GHANDLE macro h,opts _GenParm <h>,2,<opts> if VLgen mov ax,_P_&h lcall GHANDLE _gensub GHANDLE endif
endm
P_GHANDLE0 macro h,opts _GenParm <h>,2,<opts> if VLgen mov ax,_P_&h lcall GHANDLE0 _gensub GHANDLE endif endm
P_GHANDLE32 macro h,opts _GenParm <h>,2,<opts> if VLgen mov ax,_P_&h test al, 0100b; jz @F lcall GHANDLE @@: endif endm
P_HANDLE equ <P_H> P_HANDLE0 equ <P_H0>
P_ATOM equ <P_H>
P_HINSTANCE equ <P_GHANDLE> P_HINSTANCE0 equ <P_GHANDLE0>
P_HMODULE equ <P_GHANDLE> P_HMODULE0 equ <P_GHANDLE0> P_HMODULE32 equ <P_GHANDLE32>
P_HTASK equ <P_GHANDLE> P_HTASK0 equ <P_GHANDLE0>
P_CLPSTRATOM macro name, opts _GenParm <name>,4,<opts> if VLgen mov ax,_P_&name mov cx,_P_&name+2 lcall CLPSTRATOM _gensub LPSZ endif endm
P_CLPSTRATOM0 macro name, opts _GenParm <name>,4,<opts> if VLgen mov ax,_P_&name mov cx,_P_&name+2 lcall CLPSTRATOM0 _gensub LPSZ endif endm
P_CLPSTRRSRC equ <P_CLPSTRATOM> P_CLPSTRRSRC0 equ <P_CLPSTRATOM0>
;--------------------------------------------------------------------------- ; LAYER_EXPAND lseg ; ; Expands per-segment validation boilerplate code into segment lseg ; LAYER_EXPAND macro lseg .list .lall _SwitchSeg &lseg,%VLseg
public VStart&lseg VStart&lseg:
EXTRA_EXPAND lseg
; ; Handle validation ; ifdef genH&lseg
public H&lseg H&lseg: or ax,ax jz @F ret @@: mov bx,ERR_BAD_HANDLE jmp short Inval_Param_&lseg
endif ; genH&lseg
ifdef genGHANDLE&lseg
public GHANDLE0&lseg GHANDLE0&lseg: or ax,ax ; accept NULL jz GHexit&lseg
public GHANDLE&lseg GHANDLE&lseg: test al,0100b ; Reject GDT selectors jnz GHldt&lseg ; not yet. Some WOW cursor/icon handles cmp ax, 0f000h ; look like GDT sels and are > 0xf000 ifdef JAPAN jb GHerr&lseg ; Reject GDT sels now. else jae GHexit&lseg jmp GHerr&lseg ; Reject GDT sels now. endif ; JAPAN GHldt&lseg: cmp ax,0ffffh ; special case: -1 -> DS jz GHexit&lseg lar dx,ax ; is it a valid selector? jnz GHerr&lseg GHexit&lseg: ret
GHerr&lseg: mov bx,ERR_BAD_GLOBAL_HANDLE jmp short Inval_Param_&lseg
endif ; genGHANDLE&lseg
ifdef genLPFN&lseg
; ; Function pointer validation ; public LPFN0&lseg LPFN0&lseg: mov bx,ax ; Allow NULL or bx,cx jz LPFN_exit&lseg
public LPFN&lseg LPFN&lseg: beg_fault_trap LPFNbad&lseg lar bx,cx jnz LPFNerr&lseg test bh,8 jz LPFNerr&lseg mov es,cx ; validate pointer & offset mov bx,ax mov al,es:[bx] end_fault_trap
ifdef DEBUG ; ; Make sure the function is exported by ; ensuring that the first instructions are NOT ; push ds, pop ax or mov ax,ds. ; mov bx,es:[bx]+2
cmp bx,0581eh ; Push ds, pop ax instructions? jz LPFNerr&lseg ; Yes, must be an error. cmp bx,0d88ch ; Mov ax,ds instruction? jz LPFNerr&lseg ; No, we're ok, so jump ahead endif ; DEBUG
LPFN_exit&lseg: ret
LPFNbad&lseg: fault_fix_stack LPFNerr&lseg: mov bx,ERR_BAD_FUNC_PTR jmp short Inval_Param_&lseg
endif ; genLPFN&lseg
public Inval_Param_&lseg Inval_Param_&lseg: pop dx ; convert near return addr to far push cs push dx jmp HandleParamError
ifdef genLP&lseg
public LP0&lseg LP0&lseg: or ax,ax ; if cx:ax == NULL, exit jnz @F jcxz CLPexit&lseg @@: public LP&lseg LP&lseg: beg_fault_trap CLPbad&lseg mov es,cx or bx,bx ; cb == 0? jz CLPexit&lseg ; yes: just check selector dec bx add bx,ax jc CLPbad1&lseg ; check 16 bit overflow or byte ptr es:[bx],0 ; check write permission, limit end_fault_trap ret
public CLP0&lseg CLP0&lseg: or ax,ax ; Accept ax:cx == 0 jnz @F jcxz CLPexit&lseg @@: public CLP&lseg CLP&lseg: beg_fault_trap CLPbad&lseg mov es,cx or bx,bx ; cb == 0? jz CLPexit&lseg ; yes: just check selector dec bx add bx,ax jc CLPbad1&lseg ; check 16 bit overflow mov bl,es:[bx] ; check read permission, limit end_fault_trap
public CLPexit&lseg CLPexit&lseg: ret
CLPbad&lseg: fault_fix_stack CLPbad1&lseg: mov bx,ERR_BAD_PTR jmp Inval_Param_&lseg
endif ; genLP&lseg
ifdef genLPBUF&lseg public LPBUF0&lseg LPBUF0&lseg: or ax,ax ; if cx:ax == NULL, exit jnz @F jcxz LPBUFexit&lseg @@: public LPBUF&lseg LPBUF&lseg: beg_fault_trap LPBUFbad&lseg mov es,cx mov cx, word ptr ss:[bx] ; cb == 0? jcxz LPBUFexit&lseg ; yes: just check selector mov dx, bx mov bx, ax or byte ptr es:[bx],0 ; check write permission, start mov bx, dx LPBUFpast1&lseg: dec cx add cx,ax jnc @f ; 16-bit overflow mov bx, 0ffffh mov cx, bx or byte ptr es:[bx],0 ; check write permission, 64k-1 jmp LPBUFov&lseg @@: mov bx, cx or byte ptr es:[bx],0 ; check write permission, end ret end_fault_trap
public LPBUFexit&lseg LPBUFexit&lseg: ret LPBUFbad&lseg: mov bx, dx pop dx ; fault ip add sp, 2 ; fault cmp dx, offset LPBUFpast1&lseg jb LPBUFbad1&lseg
mov dx, es lsl cx, dx jnz LPBUFbad1&lseg ; should not occur, we have loaded es LPBUFov&lseg: sub cx, ax ; max legal cb inc cx mov word ptr ss:[bx], cx ; fix cb passed by user on stack mov cx, es ; HandleParamError prints cx:ax mov bx,ERR_BAD_PTR or ERR_WARNING jmp Inval_Param_&lseg LPBUFbad1&lseg: mov cx, es ; HandleParamError prints cx:ax mov bx,ERR_BAD_PTR jmp Inval_Param_&lseg endif ; genLPBUF&lseg
ifdef genLPSZ&lseg
; ; cx:ax -> const pointer to z-terminated string or MAKEINTATOM atom. ; public CLPSTRATOM0&lseg CLPSTRATOM0&lseg: jcxz CLPSZexit&lseg ; If selector is NULL, then all is well.
public CLPSTRATOM&lseg CLPSTRATOM&lseg: jcxz @F ; if selector == 0, then may be atom. mov bx,256 ; max string length of 255 characters. jmp short CLPSZ&lseg @@: or ax,ax ; offset == 0? if so, it's bogus jz ErrorStrPtr&lseg CLPSZexit&lseg: ret ; ; cx:ax => const pointer to zero-terminated string. ; bx => Maximum string length (including zero terminator) ; public CLPSZ0&lseg CLPSZ0&lseg: mov dx,ax or dx,cx jz CLPSZexit&lseg public CLPSZ&lseg CLPSZ&lseg: push di ; preserve these regs push cx mov dx,ax ; preserve original ax in dx beg_fault_trap LPSZfault&lseg mov es,cx mov di,ax
xor ax,ax mov cx,-1 cld repnz scasb end_fault_trap neg cx ; cx = string length + 1 dec cx cmp cx,bx ; error if string length + 1 > cchMax
pop cx ; restore regs before branching pop di xchg ax,dx
ja ErrorStrPtr&lseg ; jump if error ret
LPSZfault&lseg: fault_fix_stack pop cx ; restore regs pop di xchg ax,dx
public ErrorStrPtr&lseg ErrorStrPtr&lseg: mov bx,ERR_BAD_STRING_PTR jmp Inval_Param_&lseg
endif ; genLPSZ&lseg
ifdef genSETEMPTY&lseg
public SETEMPTY&lseg SETEMPTY&lseg: jcxz SETEMPTYexit&lseg ; 0-length buffer: do nothing. beg_fault_trap SETEMPTYbad&lseg mov es,dx mov byte ptr es:[bx],0 ; jam in a zero terminator end_fault_trap SETEMPTYexit&lseg: xor ax,ax cwd ret
SETEMPTYbad&lseg: fault_fix_stack jmp short SETEMPTYexit&lseg
endif ; genSETEMPTY&lseg
public VEnd&lseg VEnd&lseg:
sEnd %VLseg VLseg equ <>
endm ;LAYER_EXPAND
endif ;; IF1
|