;======================================================= ; ; 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