'   SBKX.BAS
'
'   Helper functions for QuickBasic 4.5, Basic PDS 7.1 and
'   Visual Basic for DOS version 1.0.
'
'   Functions are:
'       sbkMakeAsciizString&()
'       sbkLoadDriver%()
'       sbkDosRead%()
'       sbkDosWrite%()
'       sbkGetCmdLine()
'
'   Note:
'       QuickBasic 4.5 is using near string implementation.
'       Therefore, you need to replace the SSEG() function
'       with VARSEG() if you are using QuickBasic 4.5.
'
'
'   Copyright (c) Creative Technology Ltd, 1993.  All rights reserved.
'
'   Important Note:
'       This source code is only intended as a supplement to the
'       existing Basic functions to facilitate the use of SBK
'       library.
'
'       You can use and modify these functions in any way you find
'       useful, provided that you agree that Creative Technology Ltd
'       has no warranty obligations or liability for any functions
'       which are modified.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

' $INCLUDE: 'SBKX.BI'
' $INCLUDE: 'SBKVOICE.BI'

' Below two functions are in FILEIO.ASM
DECLARE FUNCTION  DosRead% CDECL (BYVAL iFileHandle%, BYVAL wSegment%, BYVAL wOffset%, BYVAL wLength%)
DECLARE FUNCTION  DosWrite% CDECL (BYVAL iFileHandle%, BYVAL wSegment%, BYVAL wOffset%, BYVAL wLength%)


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Converts Basic string to ASCIIZ (null terminated string).
'
'   FUNCTION  sbkMakeAsciizString& (BString$)
'
'   Entry:
'       BString$ :- Basic string by reference
'
'   Exit:
'       Far pointer to ASCIIZ string.  BString$ will be appended a null
'       terminating character at the end.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
FUNCTION sbkMakeAsciizString& (BString$)

  DIM Segm AS INTEGER, Offs AS INTEGER

  BString$ = BString$ + CHR$(0)
  Segm = VARSEG(BString$)
  Offs = SADD(BString$)
  sbkMakeAsciizString& = sbkMakeDWord&(Segm, Offs)

END FUNCTION


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Loads driver into memory with the driver name specified. The driver
' is always loaded to the offset 0 of a segment.
'
'   FUNCTION sbkLoadDriver% (DrvName$,wEmbedBuffer%)
'
'   Entry:
'       szDrvName       :- Driver name to be loaded.
'       wEmbedBuffer    :- Zero     : unused or to load the driver together
'                                     with embedded DMA buffer.
'                          Non-zero : to load the driver without embedded
'                                     DMA buffer.
'                          Note that this argument only applicable when
'                          loading Creative Voice drivers CTVDSK.DRV and
'                          CT-VOICE.DRV.
'
'   Exit:
'       Segment of the loaded driver if successfull, else returns 0
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
FUNCTION sbkLoadDriver% (DrvName$,wEmbedBuffer%)

    DIM DrvFile$, Handle%, dwFileLen&, wDrvSeg%, dwDrvSize&
    DIM lpDrvName&, fEXit%


    ' driver not loaded
    sbkLoadDriver% = 0

    ' search SOUND environment \DRV subdirectory for driver
    DrvFile$ = ENVIRON$("SOUND")

    IF (DrvFile$ <> "") THEN
        DrvFile$ = DrvFile$ + "\DRV\" + DrvName$

        lpDrvName& = sbkMakeAsciizString(DrvFile$)
        IF (sbkFindFile%(lpDrvName&) = 0) THEN
            DrvFile$ = ""
        END IF
    END IF

    ' search the current directory for driver
    IF (DrvFile$ = "") THEN
        DrvFile$ = DrvName$

        lpDrvName& = sbkMakeAsciizString(DrvFile$)
        IF (sbkFindFile%(lpDrvName&) = 0) THEN
            DrvFile$ = ""
        END IF
    END IF

    ' driver found, load it into memory
    IF  (DrvFile$ <> "") THEN
        Handle% = sbkDosOpen%(lpDrvName&)

        IF (Handle% <> -1) THEN
            dwFileLen& = sbkFileSize&(Handle%)

            DO
                wDrvSeg% = sbkAllocMem%(INT((dwFileLen& + 15) / 16))

                IF (wDrvSeg% <> 0) THEN
                    IF sbkDosRead%(Handle%, wDrvSeg%,_
                        0%, dwFileLen&) = 0 THEN
                        CALL sbkFreeMem(wDrvSeg%)
                        wEmbedBuffer% = UNUSED
                    ELSE
                        sbkLoadDriver% = wDrvSeg%
                    END IF
                ELSE
                    wEmbedBuffer% = UNUSED
                END IF

                fExit% = 1

                IF wEmbedBuffer% <> UNUSED THEN
                    SELECT CASE UCASE$(DrvName$)
                        CASE "CT-VOICE.DRV"
                            CALL ctvmSetDriverEntry (wDrvSeg%)
                            IF ctvmGetParam%(CTVOCxDRIVERSIZE,dwDrvSize&) = 0_
                            THEN
                                fEXit% = 0
                                wEmbedBuffer% = UNUSED
                            END IF

                            CALL sbkFreeMem(wDrvSeg%)
                            sbkLoadDriver% = 0

                        CASE "CTVDSK.DRV"
                            CALL ctvdSetDriverEntry (wDrvSeg%)
                            IF ctvdGetParam%(CTVOCxDRIVERSIZE,dwDrvSize&) = 0_
                            THEN
                                fExit% = 0
                                wEmbedBuffer% = UNUSED
                            END IF

                            CALL sbkFreeMem(wDrvSeg%)
                            sbkLoadDriver% = 0

                    END SELECT

                    retVal& = sbkDosLSeek&(Handle%, 0, 0)
                    dwFileLen = dwDrvSize&

                END IF

            LOOP UNTIL fExit% <> 0

            sbkDosClose(Handle%)
        END IF
    END IF

END FUNCTION


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'   Writes data from buffer to a file.
'
'   FUNCTION  sbkDosWrite% (iFileHandle%, wSegment%, wOffset%, dwLength&)
'
'   Entry:
'       iFileHandle% :- handle of file to write
'       wSegment%    :- segment address of the memory buffer
'       wOffset%     :- offset address of the memory buffer
'       dwLength&    :- number of bytes to write
'
'   Exit:
'       Non-zero if sucessful, else returns 0.
'
'   Note:
'       Crossed segment is taken care of. You need not to do segment and
'       offset adjustment prior to calling this function.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
FUNCTION sbkDosWrite% (iFileHandle%, wSegment%, wOffset%, dwLength&)

    DIM   wActualWrite AS INTEGER, wByteWrite AS INTEGER
    DIM   wSeg AS INTEGER, wOff AS INTEGER, dwByteToWrite AS LONG


    wSeg = wSegment%
    wOff = wOffset%
    dwByteToWrite = dwLength&
    sbkDosWrite% = 1

    WHILE (dwByteToWrite <> 0)

        wSeg = sbkNormalizeSegment% (wSeg, wOff)
        wOff = sbkNormalizeOffset% (wOff)

        IF (dwByteToWrite > &H4000) THEN
            wByteWrite = &H4000
        ELSE
            wByteWrite = dwByteToWrite
        END IF

        wActualWrite = DosWrite%((iFileHandle%),(wSeg),(wOff),(wByteWrite))
        IF wActualWrite = wByteWrite THEN
            wOff = wOff + wActualWrite
            dwByteToWrite = dwByteToWrite - wActualWrite
        ELSE
            dwByteToWrite = 0
            sbkDosWrite% = 0
        END IF
    WEND

END FUNCTION


'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'   Read data from file into buffer.
'
'   FUNCTION  sbkDosRead% (iFileHandle%, wSegment%, wOffset%, dwLength&)
'
'   Entry:
'       iFileHandle% :- handle of file to read
'       wSegment%    :- segment address of the memory buffer
'       wOffset%     :- offset address of the memory buffer
'       dwLength&    :- number of bytes to read
'
'   Exit:
'       Non-zero if sucessful, else returns 0.
'
'   Note:
'       Crossed segment is taken care of. You need not to do segment and
'       offset adjustment prior to calling this function.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
FUNCTION sbkDosRead% (iFileHandle%, wSegment%, wOffset%, dwLength&)

    DIM   wActualRead AS INTEGER, wByteRead AS INTEGER
    DIM   wSeg AS INTEGER, wOff AS INTEGER, dwByteToRead AS LONG


    sbkDosRead% = 1
    wSeg = wSegment%
    wOff = wOffset%
    dwByteToRead = dwLength&


    WHILE (dwByteToRead <> 0)

        wSeg = sbkNormalizeSegment% (wSeg, wOff)
        wOff = sbkNormalizeOffset% (wOff)

        IF (dwByteToRead > &H4000) THEN
          wByteRead = &H4000
        ELSE
          wByteRead = dwByteToRead
        END IF

        wActualRead = DosRead%((iFileHandle%),(wSeg),(wOff),(wByteRead))
        IF wActualRead = wByteRead THEN
            wOff = wOff + wActualRead
            dwByteToRead = dwByteToRead - wActualRead
        ELSE
            dwByteToRead = 0
            sbkDosRead% = 0
        END IF

    WEND

END FUNCTION


'* ------------------------------------------------------------------------ *'
'*  @@ Usage                                                                   *'
'*                                                                          *'
'*  sbkGetCmdLine (NumArgs%,Args$(),MaxArgs%)                               *'
'*                                                                          *'
'*   DESCRIPTION:                                                      *'
'*      To get command line and split it into arguments.                    *'
'*                                                                          *'
'*   ENTRY:                                                                    *'
'*      NumArgs% :- Number of command-line argument found.                  *'
'*      Args$()  :- Array in which to return arguments.                     *'
'*      MaxArgs% :- Maximun number of arguments array can return.           *'
'*                                                                          *'
'*   EXIT:                                                             *'
'*       None.                                                               *'
'*                                                                          *'
'* ------------------------------------------------------------------------ *'

SUB sbkGetCmdLine (NumArgs%, Args$(), MaxArgs%) STATIC

CONST TRUE = -1, FALSE = 0

    NumArgs% = 0
    In% = FALSE

    CmdL$ = COMMAND$  'Get command line
    L% = Len(CmdL$)
    FOR I% = 1 TO L%
        C$ = MID$(CmdL$,I%,1)

        ' Is it blank or tab ?
        IF C$ <> " " AND C$ <> CHR$(9) THEN
            IF NOT In% THEN ' it is a new argument
                IF NumArgs% = MaxArgs% THEN EXIT FOR
                NumArgs% = NumArgs% + 1
                In% = TRUE
            END IF
            Args$(NumArgs%) = Args$(NumArgs%) + C$
        ELSE
            In%= FALSE
        END IF
    NEXT I%
END SUB
'End of file
