;       SCCSID = @(#)demgset.asm        6.9 92/02/17
page ,132
;       SCCSID = @(#)demgset.asm        6.9 92/02/17
TITLE  GETSET - GETting and SETting MS-DOS system calls
;NAME   GETSET
;
; System Calls which get and set various things
;
;   $GET_VERSION
;   $GET_VERIFY_ON_WRITE
;   $SET_VERIFY_ON_WRITE
;   $INTERNATIONAL
;   $GET_DRIVE_FREESPACE
;   $GET_DMA
;   $SET_DMA
;   $GET_DEFAULT_DRIVE
;   $SET_DEFAULT_DRIVE
;   $GET_INTERRUPT_VECTOR
;   $SET_INTERRUPT_VECTOR
;   RECSET
;   $CHAR_OPER
;   $GetExtendedError                  DOS 3.3
;   Get_Global_CdPg                    DOS 4.0
;   $ECS_CALL                          DOS 4.0
;
;   Revision history:
;
;Local
; Tag   D/P     By Whom Date        Comment
;-----  -----   ------- ----------- --------------------------------
;
;               ARR     30-Mar-1983 Created
;A000                      Jan-1988 version 4.0
;A006   D503                        fake version for IBMCACHE
;A008   P4070                       fake version for MS WINDOWS
;               danno   14-Nov-1988 Modified for MVDM
;
;B001   CP20 AC01388  9/16/91  Mark Rogalski
;       For function Set DTA, pass control to next in chain rather than
;       calling DOS directly. This will preserve regs and flags.
;
;B002   CP20 AA04039  9/17/91  Mark Rogalski
;       For function Set DTA, go back to calling DOS directly because this
;       function may be called internally. Need to save AX and set ZR flag.
;
; B003  11/18/91  CP20 B729525  Mark Rogalski
;       Novell requestor depends on the lastdrive statement to determine
;       which drive letters it can use for network access. Therefore, we must
;       obtain this value from DOS and not use our own LASTDRIVE variable.
;
; BC004 - 02/07/92 CP20 B732885  Mark Rogalski                          ;BN004;
;         We should let DOS handle get DTA calls.                       ;BN004;
;
; BC005 - 02/17/92 CP20 B731511  Mark Rogalski                          ;BN005;
;         Add generic function call support.                            ;BN005;
;
; 63183 - 03/05/93 Lisa M. Primm
;         Add DX=08 support for $generic so WinOS2 displays "Loading
;         Please Wait" message if run from VMBoot session.
;******************************************************************************
;
.xlist
;
; get the appropriate segment definitions
;
include v86seg.inc

IFNDEF  ALTVECT
ALTVECT EQU     0                       ; FALSE
ENDIF

V86CODE    SEGMENT
        ASSUME  CS:V86GROUP

.xcref
include basemaca.inc
include osmaca.inc
include oldmaca.inc
include demmac.inc
include demver.inc
include dossymc.inc
include demdbcs.inc
include doscntry.inc
include demmult.inc
include error.inc
include demsvc.inc
include mvdmexp.inc
include dpl.inc
include pdb.inc
include intnat.inc
include mi.inc
include struc30.inc                    ;BN005
.cref
.list
        CpuMode 8086

;m        ReferV86    USERNUM,WORD
;m        ReferV86    MSVERS,WORD
;m        ReferV86    VERFLG,BYTE
;m        ReferV86    CNTCFLAG,BYTE
;BD004        ReferV86    DMAADD,DWORD
        ReferV86    CURDRV,BYTE
        ReferV86    LastDrive,BYTE
;m        ReferV86    chSwitch,BYTE
;m        ReferV86    CDSCount,BYTE
        ReferV86    EXTERR,WORD
        ReferV86    EXTERR_ACTION,BYTE
        ReferV86    EXTERR_CLASS,BYTE
        ReferV86    EXTERR_LOCUS,BYTE
        ReferV86    EXTERRPT,DWORD
;m        ReferV86    Special_version,WORD                ;AN006;
;m        ReferV86    Fake_Count,BYTE                     ;AN008;
        ReferV86    CurrentPDB,WORD
;m        ReferV86    InterCon,BYTE               ; !0 if console mode == interim
;m        ReferV86    Country_CdPg,BYTE
;m        ReferV86    FILE_UCASE_TAB,BYTE
;m        ReferV86    UCASE_TAB,BYTE
;m        ReferV86    DBCS_TAB,BYTE                       ;AN000;
;m        ReferV86    NLS_YES,BYTE                        ;AN000;
;m        ReferV86    NLS_yes2,BYTE                       ;AN000;
;m        ReferV86    NLS_NO,BYTE                         ;AN000;
;m        ReferV86    NLS_no2,BYTE                        ;AN000;
        ReferV86    command_exec,BYTE
        ReferV86    os2_handled,BYTE                    ; mdr
        ReferV86    drivemap,BYTE                       ; mdr
        ReferV86    pOldInt21,DWORD                     ; mdr

;m        EXTRN   GETLET3:NEAR
;m        EXTRN   TESTKANJ:NEAR
        EXTRN   get_user_stack:NEAR
        EXTRN   FCB_RET_ERR:NEAR
        EXTRN   $OpenExtended:NEAR
        EXTRN   Sys_Return:NEAR
;m        EXTRN   MAP_CASE:NEAR
        EXTRN   VMcheck_drive:NEAR          ; mdr
        EXTRN   VSFNFromHandle:NEAR         ;BN005
        EXTRN   Sys_Ret_OK:NEAR             ; mdr
        EXTRN   Sys_Ret_Err:NEAR            ; mdr
        EXTRN   check_dos:NEAR              ; mdr

IF NOT_FILTER

SIZE_NLS_BUFFER equ     258

V86DATA SEGMENT

COUNTRYBUFFER   DB      SetCountryInfo                  ; MUST BE CONTIGUOUS
NLSBUFFER       DB      SIZE_NLS_BUFFER DUP(0)          ;

                PUBLIC  NLSBUFFERSEG
NLSBLOCK        DB      0                               ; MUST BE CONTIGUOUS
                DW      OFFSET V86GROUP:NLSBUFFER       ;
NLSBUFFERSEG    DW      0                               ;

V86DATA ENDS

BREAK <$Get_Version -- Return DOS version number>
        procedure   $GET_VERSION,NEAR
ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       None
; Function:
;       Return DOS version number
; Outputs:
;       OEM number in BH
;       User number in BL:CX (24 bits)
;       Version number as AL.AH in binary
;       NOTE: On pre 1.28 DOSs AL will be zero

        SVC     SVC_DEMGETVERSION
        invoke  get_user_stack
ASSUME  DS:NOTHING
        MOV     [SI.user_BX],BX
        MOV     [SI.user_CX],CX
        CMP     [Fake_Count],0FFH                  ;AN008;
        JZ      reg                                ;AN008;
        CMP     [Fake_Count],0                     ;AN008;
        JZ      usual                              ;AN008;
        DEC     [Fake_Count]                       ;AN008;
reg:                                               ;AN008;
        CMP     [Special_version],0                ;AN006;
        JZ      usual                              ;AN006;
        MOV     AX,[Special_version]               ;AN006;
usual:                                             ;AN006;
        MOV     [SI.user_AX],AX         ; Really only sets AH
        return
EndProc $GET_VERSION


BREAK <$Get_Verify_on_Write - return verify-after-write flag>
        procedure   $GET_VERIFY_ON_WRITE,NEAR
ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       none.
; Function:
;       returns flag
; Returns:
;       AL = value of VERIFY flag

        MOV     AL,[VERFLG]
        return
EndProc $GET_VERIFY_ON_WRITE

ENDIF

BREAK <$Set_Verify_on_Write - Toggle verify-after-write flag>
        procedure   $SET_VERIFY_ON_WRITE,NEAR
ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       AL = desired value of VERIFY flag
; Function:
;       Sets flag
; Returns:
;       None

        AND     AL,1
;m        MOV     [VERFLG],AL
        SVC     SVC_DEMSETWRITEVERIFY
        mov     cs:os2_handled,0            ; mdr let DOS do this func too
        return
EndProc $SET_VERIFY_ON_WRITE

IF NOT_FILTER

BREAK <$International - return country-dependent information>
;
; Inputs:
;       MOV     AH,International
;       MOV     AL,country      (al = 0 => current country)
;      [MOV     BX,country]
;       LDS     DX,block
;       INT     21
; Function:
;       give users an idea of what country the application is running
; Outputs:
;       IF DX != -1 on input (get country)
;         AL = 0 means return current country table.
;         0<AL<0FFH means return country table for country AL
;         AL = 0FF means return country table for country BX
;         No Carry:
;            Register BX will contain the 16-bit country code.
;            Register AL will contain the low 8 bits of the country code.
;            The block pointed to by DS:DX is filled in with the information
;            for the particular country.
;               BYTE  Size of this table excluding this byte and the next
;               BYTE  Country code represented by this table
;                       A sequence of n bytes, where n is the number specified
;                       by the first byte above and is not > internat_block_max,
;                       in the correct order for being returned by the
;                       INTERNATIONAL call as follows:
;               WORD    Date format 0=mdy, 1=dmy, 2=ymd
;               5 BYTE  Currency symbol null terminated
;               2 BYTE  thousands separator null terminated
;               2 BYTE  Decimal point null terminated
;               2 BYTE  Date separator null terminated
;               2 BYTE  Time separator null terminated
;               1 BYTE  Bit field.  Currency format.
;                       Bit 0.  =0 $ before #  =1 $ after #
;                       Bit 1.  no. of spaces between # and $ (0 or 1)
;               1 BYTE  No. of significant decimal digits in currency
;               1 BYTE  Bit field.  Time format.
;                       Bit 0.  =0 12 hour clock  =1 24 hour
;               DWORD   Call address of case conversion routine
;               2 BYTE  Data list separator null terminated.
;         Carry:
;            Register AX has the error code.
;       IF DX = -1 on input (set current country)
;         AL = 0 is an error
;         0<AL<0FFH means set current country to country AL
;         AL = 0FF means set current country to country BX
;         No Carry:
;           Current country SET
;           Register AL will contain the low 8 bits of the country code.
;         Carry:
;            Register AX has the error code.
;
;       NOTE    Set country information is restricted to setting of the
;               current country code, all others will be treated as
;               invalid.

        procedure   $INTERNATIONAL,NEAR   ; DOS 3.3
ASSUME  DS:NOTHING,ES:NOTHING
        CMP     AL,0FFH
        JZ      BX_HAS_CODE             ; -1 means country code is in BX
        MOV     BL,AL                   ; Put AL country code in BX
        XOR     BH,BH
BX_HAS_CODE:
        PUSH    DS
        POP     ES
        PUSH    DX
        POP     DI                      ; User buffer to ES:DI
        context DS
        CMP     DI,-1
        JZ      international_set
        OR      BX,BX
        JNZ     international_find
        MOV     SI,OFFSET V86GROUP:COUNTRY_CDPG
        JMP     SHORT international_copy

international_find:
        MOV     BP,0                    ; flag it for GetCntry only
        CALL    international_get
        JC      errtn
        CMP     BX,0                    ; nlsfunc finished it ?
        JNZ     SHORT international_copy ; no, copy by myself
        MOV     BX,DX                   ; put country back
        JMP     SHORT international_ok3

international_get:
        MOV     SI,OFFSET V86GROUP:COUNTRY_CDPG
        CMP     BX,[SI.ccDosCountry]    ; = current country id
        retz                            ; return if equal
        MOV     DX,BX
        XOR     BX,BX                   ; bx = 0, default code page

        CMP     BP,0                    ; GetCntry ?
        JNZ     interr                  ; return error on set country code
        MOV     AX,ES
        MOV     DS,AX
        MOV     SI,DI                   ; (DS:SI) = user buffer
        MOV     CX,OLD_COUNTRY_SIZE     ; (CX) = size of buffer
        XOR     AL,AL                   ; get $INTERNATIONAL country info
        SVC     SVC_DEMGETCOUNTRYINFO
        MOV     [SI].Map_call.Segmt,cs
        MOV     [SI].Map_call.Offst,offset V86GROUP:MAP_CASE
chkok:
        CMP     AL,0                    ; success ?
        retz                            ; yes
setcarry:
        STC                             ; set carry
        ret
interr:

        MOV     AL,0FFH                 ; flag nlsfunc error
        JMP     setcarry

international_copy:
        MOV     BX,[SI.ccDosCountry]    ; = current country id
        MOV     SI,OFFSET V86GROUP:COUNTRY_CDPG.ccDFormat
        MOV     CX,OLD_COUNTRY_SIZE
        REP     MOVSB                   ; copy country info
international_ok3:
        invoke  get_user_stack
ASSUME  DS:NOTHING
        MOV     [SI.user_BX],BX
international_ok:
        MOV     AX,BX                   ; return country code in AX too.
        transfer SYS_RET_OK

international_set:
ASSUME  DS:V86GROUP
        MOV     BP,1                    ; flag it for SetCodePage only
        CALL    international_get
        JNC     international_ok
errtn:
        CMP     AL,0FFH
        JZ      errtn2
        transfer SYS_RET_ERR_AL         ; return what we got from NLSFUNC
errtn2:
        error   error_Invalid_Function  ; NLSFUNC not existent

EndProc $INTERNATIONAL



BREAK <$GetExtCntry - return extended country-dependent information>
;
; Inputs:
;       if AL >= 20H
;         AL= 20H    capitalize single char, DL= char
;             21H    capitalize string ,CX= string length
;             22H    capitalize ASCIIZ string
;             23H    YES/NO check, DL=1st char DH= 2nd char (DBCS)
;             80H bit 0 = use normal upper case table
;                     1 = use file upper case table
;          DS:DX points to string
;
;       else
;
;       MOV     AH,GetExtCntry   ; DOS 3.3
;       MOV     AL,INFO_ID      ( info type,-1  selects all)
;       MOV     BX,CODE_PAGE    ( -1 = active code page )
;       MOV     DX,COUNTRY_ID   ( -1 = active country )
;       MOV     CX,SIZE         ( amount of data to return)
;       LES     DI,COUNTRY_INFO ( buffer for returned data )
;       INT     21
; Function:
;       give users extended country dependent information
;       or capitalize chars
; Outputs:
;         No Carry:
;            extended country info is succesfully returned
;         Carry:
;            Register AX has the error code.
;            AX=0, NO    for YES/NO CHECK
;               1, YES


        procedure   $GetExtCntry,NEAR   ; DOS 3.3
ASSUME  DS:NOTHING,ES:NOTHING
        CMP     AL,CAP_ONE_CHAR         ;AN000;MS. < 20H ?
        JAE     capcap                  ;AN000;MS.
        JMP     notcap                  ;AN000;MS. yes
capcap:                                 ;AN000;
        TEST    AL,UPPER_TABLE          ;AN000;MS. which upper case table
        JNZ     fileupper               ;AN000;MS. file upper case
        MOV     BX,OFFSET V86GROUP:UCASE_TAB+2 ;AN000;MS. get normal upper case
        JMP     SHORT capit                        ;AN000;MS.
fileupper:                                         ;AN000;
        MOV     BX,OFFSET V86GROUP:FILE_UCASE_TAB+2;AN000;MS. get file upper case
capit:                                  ;AN000;
        CMP     AL,CAP_ONE_CHAR         ;AN000;;MS.cap one char ?
        JNZ     chkyes                  ;AN000;;MS. no
        MOV     AL,DL                   ;AN000;;MS. set up AL
        invoke  GETLET3                 ;AN000;;MS. upper case it
        invoke  get_user_stack          ;AN000;;MS. get user stack
        MOV     byte ptr [SI.user_DX],AL;AN000;;MS. user's DL=AL
        JMP     SHORT nono              ;AN000;;MS. done
chkyes:                                 ;AN000;
        CMP     AL,CHECK_YES_NO         ;AN000;;MS. check YES or NO ?
        JNZ     capstring               ;AN000;;MS. no
        XOR     AX,AX                   ;AN000;;MS. presume NO
IF  DBCS                                ;AN000;
        PUSH    AX                      ;AN000;;MS.
        MOV     AL,DL                   ;AN000;;MS.
        invoke  TESTKANJ                ;AN000;;MS. DBCS ?
        POP     AX                      ;AN000;;MS.
        JNZ     dbcs_char               ;AN000;;MS. yes, return error
ENDIF                                   ;AN000;
                                        ;AN000;
        CMP     DL,NLS_YES              ;AN000;;MS. is 'Y' ?
        JZ      yesyes                  ;AN000;;MS. yes
        CMP     DL,NLS_yes2             ;AN000;;MS. is 'y' ?
        JZ      yesyes                  ;AN000;;MS. yes
        CMP     DL,NLS_NO               ;AN000;;MS. is  'N'?
        JZ      nono                    ;AN000;;MS. no
        CMP     DL,NLS_no2              ;AN000;;MS. is 'n' ?
        JZ      nono                    ;AN000;;MS. no
dbcs_char:                              ;AN000;
        INC     AX                      ;AN000;;MS. not YES or NO
yesyes:                                 ;AN000'
        INC     AX                      ;AN000;;MS. return 1
nono:                                   ;AN000;
        transfer SYS_RET_OK             ;AN000;;MS. done
capstring:                              ;AN000;
        MOV     SI,DX                   ;AN000;;MS. si=dx
        CMP     AL,CAP_STRING           ;AN000;;MS. cap string ?
        JNZ     capascii                ;AN000;;MS. no
        CMP     CX,0                    ;AN000;;MS. check count 0
        JZ      nono                    ;AN000;;MS. yes finished
concap:                                 ;AN000;
        LODSB                           ;AN000;;MS. get char
 IF  DBCS                               ;AN000;;MS.
        invoke  TESTKANJ                ;AN000;;MS. DBCS ?
        JZ      notdbcs                 ;AN000;;MS. no
        INC     SI                      ;AN000;;MS. skip 2 chars
        DEC     CX                      ;AN000;;MS. bad input, one DBCS char at end
        JZ      nono                    ;AN000;;MS. yes
        JMP     SHORT next99            ;AN000;;MS.
notdbcs:                                ;AN000;
 ENDIF                                  ;AN000;

        invoke  GETLET3                 ;AN000;;MS. upper case it
        MOV     byte ptr [SI-1],AL      ;AN000;;MS. store back
next99:                                 ;AN000;
        LOOP    concap                  ;AN000;;MS. continue
        JMP     nono                    ;AN000;;MS. done
capascii:                               ;AN000;
        CMP     AL,CAP_ASCIIZ           ;AN000;;MS. cap ASCIIZ string ?
        JNZ     capinval                ;AN000;;MS. no
concap2:                                ;AN000;
        LODSB                           ;AN000;;MS. get char
        CMP     AL,0                    ;AN000;;MS. end of string ?
        JZ      nono                    ;AN000;;MS. yes
 IF  DBCS                               ;AN000;;MS.
        invoke  TESTKANJ                ;AN000;;MS. DBCS ?
        JZ      notdbcs2                ;AN000;;MS. no
        CMP     BYTE PTR [SI],0         ;AN000;;MS. bad input, one DBCS char at end
        JZ      nono                    ;AN000;;MS. yes
        INC     SI                      ;AN000;;MS. skip 2 chars
        JMP     concap2                 ;AN000;;MS.
notdbcs2:                               ;AN000;
 ENDIF                                  ;AN000;
        invoke  GETLET3                 ;AN000;;MS. upper case it
        MOV     byte ptr [SI-1],AL      ;AN000;;MS. store back
        JMP     concap2                 ;AN000;;MS. continue


notcap:
        CMP     CX,5                    ; minimum size is 5
        JB      sizeerror
        context DS
        MOV     SI,OFFSET V86GROUP:COUNTRY_CDPG
        CMP     DX,-1                   ; active country ?
        JNZ     GETCDPG                 ; no
        MOV     DX,[SI.ccDosCountry]    ; get active country id
GETCDPG:
        CMP     BX,-1                   ; active code page?
        JNZ     CHKAGAIN                ; no, check again
        MOV     BX,[SI.ccDosCodePage]   ; get active code page id
CHKAGAIN:
        CMP     DX,[SI.ccDosCountry]    ; same as active country id?
        JNZ     CHKNLS                  ; no
        CMP     BX,[SI.ccDosCodePage]   ; same as active code page id?
        JNZ     CHKNLS                  ; no
CHKTYPE:
        MOV     BX,[SI.ccSysCodePage]   ; bx = sys code page id
;       CMP     AL,SetALL               ; select all?
;       JNZ     SELONE
;       MOV     SI,OFFSET V86GROUP:COUNTRY_CDPG.ccNumber_of_entries
SELONE:
        PUSH    CX                      ; save cx
        MOV     CX,[SI.ccNumber_of_entries]
        MOV     SI,OFFSET V86GROUP:COUNTRY_CDPG.ccSetUcase
NXTENTRY:
        CMP     AL,[SI]                 ; compare info type
        JZ      FOUNDIT
        ADD     SI,5                    ; next entry
        LOOP    NXTENTRY
        POP     CX
capinval:
        error   error_Invalid_Function  ; info type not found
FOUNDIT:
        MOVSB                           ; move info id byte
        POP     CX                      ; retsore char count
        CMP     AL,SetCountryInfo       ; select country info type ?
        JZ      setsize
        MOV     CX,4                    ; 4 bytes will be moved
        MOV     AX,5                    ; 5 bytes will be returned in CX
OK_RETN:
        REP     MOVSB                   ; copy info
        MOV     CX,AX                   ; CX = actual length returned
        MOV     AX,BX                   ; return sys code page in ax
GETDONE:
        invoke  get_user_stack          ; return actual length to user's CX
        MOV     [SI.user_CX],CX
        transfer SYS_RET_OK
setsize:
        SUB     CX,3                    ; size after length field
        CMP     WORD PTR [SI],CX        ; less than table size
        JAE     setsize2                ; no
        MOV     CX,WORD PTR [SI]        ; truncate to table size
setsize2:
        MOV     ES:[DI],CX              ; copy actual length to user's
        ADD     DI,2                    ; update index
        ADD     SI,2
        MOV     AX,CX
        ADD     AX,3                    ; AX has the actual length
        JMP     OK_RETN                 ; go move it
sizeerror:
        error   error_Invalid_Function
CHKNLS:
        PUSH    CX                      ; FOUNDIT pops CX off
        MOV     [NLSBLOCK],AL
        MOV     CX,SIZE_NLS_BUFFER
        MOV     SI,OFFSET V86GROUP:NLSBUFFER
        SVC     SVC_DEMGETCOUNTRYINFO
        OR      AL,AL                   ; success ?
        JNZ     NLSERROR

        MOV     AL,[NLSBLOCK]           ; (AL) = nls table type
        MOV     BX,[COUNTRY_CDPG].ccSysCodePage ; (BX) = system code page
        MOV     SI,OFFSET V86GROUP:NLSBLOCK
        CMP     AL,SetCountryInfo
        JNE     FOUNDIT                 ; jump if not set country info

        MOV     SI,OFFSET V86GROUP:COUNTRYBUFFER
        .errnz  (NLSBUFFER - COUNTRYBUFFER) - 1
        MOV     [SI].(ccMono_ptr-ccSetCountryInfo).Segmt,cs
        MOV     [SI].(ccMono_ptr-ccSetCountryInfo).Offst,offset V86GROUP:MAP_CASE
        JMP     FOUNDIT
NLSERROR:
        POP     CX
        transfer SYS_RET_ERR_AL         ; return what is got from NLSFUNC

EndProc $GetExtCntry

BREAK <$GetSetCdPg - get or set global code page>
;
; Inputs:
;       MOV     AH,GetSetCdPg   ; DOS 3.3
;       MOV     AL,n            ; n = 1 : get code page, n = 2 : set code page
;       MOV     BX,CODE_PAGE    ( set code page only)
;       INT     21
; Function:
;       get or set the global code page
; Outputs:
;         No Carry:
;            global code page is set    (set global code page)
;            BX = active code page id   (get global code page)
;            DX = system code page id   (get global code page)
;         Carry:
;            Register AX has the error code.


        procedure   $GetSetCdPg,NEAR   ; DOS 3.3
ASSUME  DS:NOTHING,ES:NOTHING
        context DS
        MOV     SI,OFFSET V86GROUP:COUNTRY_CDPG
        CMP     AL,1                   ; get global code page
        JNZ     setglpg                ; set global cod epage
        MOV     BX,[SI.ccDosCodePage]  ; get active code page id
        MOV     DX,[SI.ccSysCodePage]  ; get sys code page id
        invoke  get_user_stack
ASSUME DS:NOTHING
        MOV     [SI.user_BX],BX        ; update returned bx
        MOV     [SI.user_DX],DX        ; update returned dx
OK_RETURN:
        transfer SYS_RET_OK
ASSUME DS:V86GROUP
setglpg:
        CMP     AL,2
        JNZ     nomem
;;;;;;; CMP     BX,[SI.ccDosCodePage]  ; same as active code page
;;;;;;; JZ      OK_RETURN              ; yes
        MOV     DX,[SI.ccDosCountry]
        SVC     SVC_DEMSETCODEPAGE         ;set the code page
        MOV     [SI].ccMono_ptr.Segmt,cs
        MOV     [SI].ccMono_ptr.Offst,offset V86GROUP:MAP_CASE
        CMP     AL,0                       ; success ?
        JZ      OK_RETURN                  ; yes
        CMP     AL,65                      ; set device code page failed
        JNZ     seterr
        MOV     AX,65
        MOV     [EXTERR],AX
        MOV     [EXTERR_ACTION],errACT_Ignore
        MOV     [EXTERR_CLASS],errCLASS_HrdFail
        MOV     [EXTERR_LOCUS],errLOC_SerDev
        transfer SYS_RET_ERR

seterr:
        transfer  SYS_RET_ERR_AL
nomem:
        error   error_Invalid_Function ; function not defined
;
EndProc $GetSetCdPg

;filter
ENDIF


BREAK <$Get_Drive_Freespace -- Return bytes of free disk space on a drive>

; Inputs:
;       DL = Drive number
; Function:
;       Return number of free allocation units on drive
; Outputs:
;       BX = Number of free allocation units
;       DX = Total Number of allocation units on disk
;       CX = Sector size
;       AX = Sectors per allocation unit
;          = -1 if bad drive specified
; This call returns the same info in the same registers (except for FAT pointer)
;      as the old FAT pointer calls

        procedure   $GET_DRIVE_FREESPACE,NEAR
        call    VMcheck_drive           ; mdr  return if dos drive
ASSUME  DS:NOTHING,ES:NOTHING
        context DS
        SVC     SVC_DEMGETDRIVEFREESPACE
        JC      BADFDRV
        MOV     AX,SI                   ; (AX) = sectors per allocation unit
DoSt:
        invoke  get_user_stack
ASSUME  DS:NOTHING
        MOV     [SI.user_DX],DX
        MOV     [SI.user_CX],CX
        MOV     [SI.user_BX],BX
        MOV     [SI.user_AX],AX
        return
BADFDRV:
        invoke  FCB_RET_ERR
        MOV     AX,-1
        JMP     DoSt
EndProc $GET_DRIVE_FREESPACE



BREAK <$Get_DMA, $Set_DMA -- Get/Set current DMA address>

IF NOT_FILTER

        procedure   $GET_DMA,NEAR
ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       None
; Function:
;       Get DISK TRANSFER ADDRESS
; Returns:
;       ES:BX is current transfer address

        MOV     BX,WORD PTR [DMAADD]
        MOV     CX,WORD PTR [DMAADD+2]
        invoke  get_user_stack
        MOV     [SI.user_BX],BX
        MOV     [SI.user_ES],CX
        return
EndProc $GET_DMA

;filter
ENDIF

        procedure   $SET_DMA,NEAR
ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       DS:DX is desired new disk transfer address
; Function:
;       Set DISK TRANSFER ADDRESS
; Returns:
;       None

        push    ax                       ;BN002
;BD004        MOV     WORD PTR [DMAADD],DX
;BD004        MOV     WORD PTR [DMAADD+2],DS
        SVC     SVC_DEMSETDTA
        pop     ax                       ;BN002
        pushf                            ;BN002
        call    cs:[pOldInt21]           ;BN002 call DOS to set DTA
        call    get_user_stack           ;BN002
        or      [SI.user_F],f_Zero       ;BN002 turn on user's zero flag
        return

EndProc $SET_DMA

BREAK <$Get_Default_Drive, $Set_Default_Drive -- Set/Get default drive>
        procedure   $GET_DEFAULT_DRIVE,NEAR
ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       None
; Function:
;       Return current drive number
; Returns:
;       AL = drive number

        cmp     [CURDRV],-1         ; see if current drive is on dos
        je      gdd10               ; yes? then let dos handle request
        MOV     AL,[CURDRV]         ; no? then return curr drive
        jmp     Sys_ret_OK

gdd10:  mov     cs:os2_handled,0    ; allow DOS to set the default drive
        ret
EndProc $GET_DEFAULT_DRIVE

        procedure   $SET_DEFAULT_DRIVE,NEAR
ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       DL = Drive number for new default drive
; Function:
;       Set the default drive
; Returns:
;       AL = Number of drives, NO ERROR RETURN IF DRIVE NUMBER BAD

        push    bx                          ; set os/2 curr drive according
        push    dx                          ; to map
        mov     bl,dl
        xor     bh,bh
        cmp     cs:drivemap[bx],0           ; look up drive in map
        jne     sdd05                       ; if mapped then have os2 set
        mov     al,dl
        inc     al
        call    check_dos                   ; see if DOS knows drive
        jnc     short sdd20                 ; yes? let dos handle func
        jmp     short sdd08                 ; no? have os2 set it

sdd05:  mov     dl,cs:drivemap[bx]          ; get mapped drive letter
        sub     dl,'A'                      ; make it 0 based
sdd08:  SVC     SVC_DEMSETDEFAULTDRIVE      ; set current os/2 drive
        pop     dx
        pop     bx
        JC      sdd30                       ; if errors - do not change
        MOV     [CURDRV],DL         ; set this variable to current OS/2 drive
sdd30:  pushf                       ; call DOS to return the LASTDRIVE value   ;BC003
        call    cs:[pOldInt21]                                                 ;BC003
        mov     cs:[lastdrive],al   ; save this for later use ;BN005
        ret                                                                    ;BC003

sdd20:  pop     dx                  ; we only come here if DOS knows drive     ;BC003
        pop     bx                  ; so setting should be successful          ;BC003
        pushf                                                                  ;BC003
        call    cs:[pOldInt21]                                                 ;BC003
        MOV     [CURDRV],-1         ; set to -1 to show DOS knows curr drive   ;BC003
        ret                                                                    ;BC003

EndProc $SET_DEFAULT_DRIVE

IF NOT_FILTER

BREAK <$Get_Interrupt_Vector - Get/Set interrupt vectors>
        procedure   $GET_INTERRUPT_VECTOR,NEAR
ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       AL = interrupt number
; Function:
;       Get the interrupt vector
; Returns:
;       ES:BX is current interrupt vector

        CALL    RECSET
        LES     BX,DWORD PTR ES:[BX]
        invoke  get_user_stack
        MOV     [SI.user_BX],BX
        MOV     [SI.user_ES],ES
        return
EndProc $GET_INTERRUPT_VECTOR

        procedure   $SET_INTERRUPT_VECTOR,NEAR
ASSUME  DS:NOTHING,ES:NOTHING

; Inputs:
;       AL = interrupt number
;       DS:DX is desired new interrupt vector
; Function:
;       Set the interrupt vector
; Returns:
;       None

        CALL    RECSET
        CLI                             ; Watch out!!!!! Folks sometimes use
        MOV     ES:[BX],DX              ;   this for hardware ints (like timer).
        MOV     ES:[BX+2],DS
        STI
        return
EndProc $SET_INTERRUPT_VECTOR

        IF      ALTVECT
TABLE   SEGMENT
VECIN:
; INPUT VECTORS
Public GSET001S,GSET001E
GSET001S  label byte
        DB      22H                     ; Terminate
        DB      23H                     ; ^C
        DB      24H                     ; Hard error
        DB      28H                     ; Spooler
LSTVEC  DB      ?                       ; ALL OTHER

VECOUT:
; GET MAPPED VECTOR
        DB      int_terminate
        DB      int_ctrl_c
        DB      int_fatal_abort
        DB      int_spooler
LSTVEC2 DB      ?                       ; Map to itself

NUMVEC  =       VECOUT-VECIN
GSET001E label byte
TABLE   ENDS
        ENDIF

procedure   RECSET,NEAR

        IF      ALTVECT
        context ES
        MOV     [LSTVEC],AL             ; Terminate list with real vector
        MOV     [LSTVEC2],AL            ; Terminate list with real vector
        MOV     CX,NUMVEC               ; Number of possible translations
        MOV     DI,OFFSET V86GROUP:VECIN    ; Point to vectors
        REPNE   SCASB
        MOV     AL,ES:[DI+NUMVEC-1]     ; Get translation
        ENDIF

        XOR     BX,BX
        MOV     ES,BX
        MOV     BL,AL
        SHL     BX,1
        SHL     BX,1
        return
EndProc recset

BREAK <$Char_Oper - hack on paths, switches so that xenix can look like PCDOS>
;
; input:    AL = function:
;                   0 - read switch char
;                   1 - set switch char (char in DL)
;                   2 - read device availability
;                       Always returns available
;                   3 - set device availability
;                       No longer supported (NOP)
; output:   (get) DL - character/flag
;
        procedure   $CHAR_OPER,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING
        context DS
        CMP     AL,1
        JB      CharGetSw
        JZ      CharSetSw
        CMP     AL,3
        JB      CharGetDev
        JZ      CharSetDev
        MOV     AL,-1
        return
CharGetSw:
        MOV     DL,chSwitch
        JMP     SHORT CharSet
CharSetSw:
        MOV     chSwitch,DL
        return
CharGetDev:
        MOV     DL,-1
CharSet:
        Invoke  Get_User_Stack
        ASSUME  DS:NOTHING
        MOV     [SI.User_DX],DX
CharSetDev:
        return
EndProc $CHAR_OPER

BREAK <$GetExtendedError - Return Extended DOS error code>
;
; input:    None
; output:   AX = Extended error code (0 means no extended error)
;           BL = recommended action
;           BH = class of error
;           CH = locus of error
;           ES:DI = may be pointer
;
        procedure   $GetExtendedError,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING
        Context DS
        MOV     AX,[EXTERR]
        LES     DI,[EXTERRPT]
        MOV     BX,WORD PTR [EXTERR_ACTION]     ; BL = Action, BH = Class
        MOV     CH,[EXTERR_LOCUS]
        invoke  get_user_stack
ASSUME  DS:NOTHING
        MOV     [SI.user_DI],DI
        MOV     [SI.user_ES],ES
        MOV     [SI.user_BX],BX
        MOV     [SI.user_CX],CX
        transfer SYS_RET_OK
EndProc $GetExtendedError

;filter
ENDIF


Break   <$SetExtendedError - set extended error for later retrieval>

;
; $SetExtendedError takes extended error information and loads it up for the
; next extended error call.  This is used by interrupt-level processors to
; mask their actions.
;
;   Inputs: DS:SI points to DPL which contains all registers
;   Outputs: none
;

Procedure $SetExtendedError,near
        ASSUME  DS:NOTHING,ES:NOTHING
        MOV     AX,[SI].dpl_AX
        MOV     [EXTERR],AX
        MOV     AX,[SI].dpL_di
        MOV     WORD PTR ExtErrPt,AX
        MOV     AX,[SI].dpL_ES
        MOV     WORD PTR ExtErrPt+2,AX
        MOV     AX,[SI].dpL_BX
        MOV     WORD PTR [EXTERR_ACTION],AX
        MOV     AX,[SI].dpL_CX
        MOV     [EXTERR_LOCUS],AH
        return
EndProc     $SetExtendedError


;***    $Generic - Make calls to selected OS/2 workers
;
;       $Generic calls selected OS/2 workers to perform services for
;       OS/2 utilities via utilapi.
;       This is an Int21 dispatcher routine.
;
;       ENTRY   BX = ordinal (see ordinal.inc)
;               CX = signature (636Ch or 'cl')
;               DS = callers data segment
;               ES:DI -> Stack frame
;
;       EXIT    'NC'  - No Error
;
;               'C'   - Error
;
;       NOTE
;               $Generic is also a MVDM generic function. For such a case
;               BX should be zero and DX gives the sub function.Following
;               is the current usage:
;               DX = 0 - PRE_EXEC Notification from command.com
;                  = 1 - Set VDM Title  (ES:DI is the title string)
;                  = 2 - Get Old Title (returns old title in ES:DI)
;                  = 3 - Get the last drive value (returns lastdrive in al)
;

        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $Generic,NEAR
        cmp     cx,'cl'                 ; valid signature?
        je      short gnk10
        jmp     $OpenExtended

gnk10:
        or      bx,bx                   ; PRE_EXEC case is handled in V86
        jnz     short gnk25             ; mode and other functions in

        .if     <DX eq 0>               ; protect mode
          mov     [command_exec],1      ; PRE_EXEC notification
          clc
          jmp     short end_special
        .endif

        .if     <DX eq 3>               ; Command = Lastdrive?
          mov     al,[LastDrive]        ; al = lastdrive value
          clc
          jmp     short end_special
        .endif

        .if     <DX eq 5>                                             ;BN005
          mov     bx,di
          call    VSFNFromHandle        ; get actual OS/2 handle
          jc      short end_special
          .if     z
            mov     ax,1
            stc
            jmp     short end_special
          .endif
          mov     di,bx
          xor     bx,bx
        .endif                                                        ;BN005

        .if     <DX eq 8>                                             ;63183;
          EXTRN   TXT_MSG_STAND_BY: byte                              ;63183;
          call    Get_user_stack                                      ;63183;
          assume  ds:nothing                                          ;63183;
          mov     [si].user_DS,cs                                     ;63183;
          mov     [si].user_DX,offset V86GROUP:TXT_MSG_STAND_BY       ;63183;
        .endif                                                        ;63183;

gnk25:
        SVC     SVC_DEMGENERIC
end_special:                            ;BN005
        jmp     Sys_Return              ; exit processing

EndProc $Generic

V86CODE ENDS

        END
