File "unix.inc"

Path: /ShuffleGUI/inc/unix.inc
File size: 7.21 KB
MIME-type:
Charset: utf-8

'---------------------------------------------------------------------------------------------------------------------
' This is +Unix.inc v1.2+ for PBWin9
' This library offers tool functions to run Unix commands from within Wine
'---------------------------------------------------------------------------------------------------------------------
MACRO UNIX_HOME = "z:\home\" + ENVIRON$("USERNAME") + "\"  ' Returns the Wine path of Unix '~' (User home)
DECLARE FUNCTION IsOnUnix() AS LONG                        ' Return %True if we are on a Unix system, %False otherwise
DECLARE SUB GetWineDrivesMapping()                         ' Get all Wine drives and their mapping
DECLARE FUNCTION WinePath(BYVAL file AS STRING) AS STRING  ' Return the Wine path of a Unix file
DECLARE FUNCTION UnixPath(BYVAL file AS STRING) AS STRING  ' Return the Unix path of a Wine file
DECLARE FUNCTION UnixExists(BYVAL file AS STRING) AS LONG  ' Return existence of a Unix file e.g. /usr/bin/vlc
DECLARE FUNCTION GetUnixRet(BYVAL cmd AS STRING) AS STRING ' Return the full output of a Unix command
DECLARE SUB UnixShell(BYVAL cmd AS STRING)                 ' Execute a Unix command asynchronously
'---------------------------------------------------------------------------------------------------------------------
GLOBAL dosdevices() AS STRING ' list of Wine drives followed by their mapping, in the form "d:/media/user/myhdd"
'---------------------------------------------------------------------------------------------------------------------
#INCLUDE ONCE "Win32Api.inc"
'---------------------------------------------------------------------------------------------------------------------

'-----------------------------------------------------------------------------------------
FUNCTION IsOnUnix() AS LONG
' Return %True if we are on a Unix system, %False otherwise
    LOCAL hNt AS DWORD
    LOCAL pwv AS DWORD
    hNt = GetModuleHandle("ntdll.dll")
    IF hNt = 0 THEN
        FUNCTION = %FALSE
    ELSE
        pwv = GetProcAddress(hNt, "wine_get_version")
        FUNCTION = (pwv <> 0)
    END IF
END FUNCTION
'-----------------------------------------------------------------------------------------

'-----------------------------------------------------------------------------------------
SUB GetWineDrivesMapping()
' Get all Wine drives and their mapping
    LOCAL r, e AS STRING
    LOCAL i, j AS LONG

    REDIM dosdevices(-1)

    r = GetUnixRet("ls -al ~/.wine/dosdevices")
    IF r = "" THEN EXIT SUB

    FOR i = 1 TO PARSECOUNT(r, $LF)
        e = PARSE$(r, $LF, i)
        j = INSTR(e, " -> ")
        IF j = 0 THEN ITERATE FOR
        j = INSTR(j - LEN(e) - 2, e, " ")
        e = MID$(e, j + 1)
        IF INSTR(e, "/dev/") > 0 OR _
           INSTR(e, "c:") > 0 OR _
           INSTR(e, "z:") > 0 THEN
           ITERATE FOR
        END IF
        e = REMOVE$(e, " -> ")
        REPLACE "::" WITH ":" IN e
        REDIM PRESERVE dosdevices(UBOUND(dosdevices) + 1)
        dosdevices(UBOUND(dosdevices)) = e
    NEXT

END SUB
'-----------------------------------------------------------------------------------------

'-----------------------------------------------------------------------------------------
FUNCTION WinePath(BYVAL file AS STRING) AS STRING
' Return the Wine path of a Unix file e.g. /usr/bin/vlc -> z:\usr\bin\vlc
    file = "z:" + file
    REPLACE "/" WITH "\" IN file
    FUNCTION = file
END FUNCTION
'-----------------------------------------------------------------------------------------

'-----------------------------------------------------------------------------------------
FUNCTION UnixPath(BYVAL file AS STRING) AS STRING
' Return the Unix path of a Wine file e.g. z:\usr\bin\vlc -> /usr/bin/vlc
    LOCAL i AS LONG

    ' Get the mapping for all Wine drives
    IF UBOUND(dosdevices) < 0 THEN GetWineDrivesMapping()
    REPLACE "\" WITH "/" IN file

    ' Special cases: files on Z:\ and C:\ are easy to translate
    IF LEFT$(LCASE$(file), 3) = "z:/" THEN
        FUNCTION = MID$(file, 3)
        EXIT FUNCTION
    END IF
    IF LEFT$(LCASE$(file), 3) = "c:/" THEN
        FUNCTION = "/home/" + ENVIRON$("USERNAME") + "/.wine/drive_c/" + MID$(file, 4)
        EXIT FUNCTION
    END IF

    ' Else use dosdevices() mapping
    FOR i = 0 TO UBOUND(dosdevices)
        IF LEFT$(LCASE$(file), 3) = LEFT$(dosdevices(i), 2) + "/" THEN
            FUNCTION = MID$(dosdevices(i), 3) + MID$(file, 3)
            EXIT FUNCTION
        END IF
    NEXT

    ' Final case, in case drive is not mapped (should not happen?)
    file = "/home/" + ENVIRON$("USERNAME") + "/.wine/dosdevices/" + file
    i = INSTR(file, ":") ' the following is needed to transform the drive letter to smaller case
    IF i > 1 THEN file = LEFT$(file, i-2) + LCASE$(MID$(file, i-1, 1)) + MID$(file, i)
    FUNCTION = file

END FUNCTION
'-----------------------------------------------------------------------------------------

'-----------------------------------------------------------------------------------------
FUNCTION UnixExists(BYVAL file AS STRING) AS LONG
' Return existence of a Unix file e.g. /usr/bin/vlc
    LOCAL lRes AS LONG
    lRes = GETATTR(WinePath(file))
    FUNCTION = (ERRCLEAR = 0)
END FUNCTION
'-----------------------------------------------------------------------------------------

'-----------------------------------------------------------------------------------------
SUB CreateExecSh(BYVAL cmd AS STRING)
' Create the 'Dynamic Unix Execution Script' (dues) to be called from Wine
    LOCAL dues AS STRING
    LOCAL lRes, ff AS LONG

    ' Reset script
    dues = UNIX_HOME + "dues.sh"
    KILL dues

    ' Write script
    ff = FREEFILE
    OPEN dues FOR BINARY ACCESS WRITE AS #ff
    PUT$ #ff, "#! /usr/bin/sh" + $LF + cmd
    CLOSE #ff

    ' Make script executable
    SHELL "start /exec /usr/bin/chmod +x /home/" + ENVIRON$("USERNAME") + "/dues.sh"

END SUB
'-----------------------------------------------------------------------------------------

'-----------------------------------------------------------------------------------------
FUNCTION GetUnixRet(BYVAL cmd AS STRING) AS STRING
' Return the full output of a Unix command
    LOCAL timout AS SINGLE
    LOCAL logfl AS STRING
    LOCAL ret AS STRING
    LOCAL ff AS LONG

    ' Define temporary files
    logfl = UNIX_HOME + "dues.log"
    KILL logfl

    ' Now, synchronously call the command
    UnixShell cmd + " > ~/dues.log"

    ' Poll the temporary file every 1/4s until filled
    ' or we reach a timeout of 3s (arbitrary)
    DO
        SLEEP 250 : timout += 0.25
        ff = FREEFILE
        OPEN logfl FOR BINARY ACCESS READ LOCK SHARED AS #ff
        GET$ #ff, LOF(#ff), ret
        CLOSE #ff
    LOOP UNTIL ret <> "" OR timout >= 3

    ' Clean-up temporary files
    KILL LEFT$(logfl,-3) + "sh"
    KILL logfl

    FUNCTION = ret
END FUNCTION
'-----------------------------------------------------------------------------------------

'-----------------------------------------------------------------------------------------
SUB UnixShell(BYVAL cmd AS STRING)
' Execute a Unix command asynchronously
    LOCAL pid AS DWORD
    CreateExecSh(cmd)
    pid = SHELL("start /exec /usr/bin/sh /home/" + ENVIRON$("USERNAME") + "/dues.sh", 0)
    SLEEP 1000
END SUB
'-----------------------------------------------------------------------------------------