'--------------------------------------------------------------------------------------------------------------------- ' 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 '-----------------------------------------------------------------------------------------