Hey,

 

So on my computer; I currently have cygwin installed, in addition to a number of MSYS-based environments. That being said, I've always kind of wanted an environment-agnostic alternative for cygpath that uses the system libraries for whatever environment is currently detects itself in. (msys-1.0.dll or cygwin1.dll)

 

Decided to take a few hours tonight and write up a quick prototype so see how I would do it if I decided to. Ended up with this:

 

#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define _MBCS
#define MBCS
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define FATAL_PREFIX "Error: "
#define NEW_LINE "\n"

#define CYGWIN_DLL "cygwin1.dll"
#define MSYS_DLL "msys-1.0.dll"

#define CYGWIN_INIT "cygwin_dll_init"
#define MSYS_INIT "msys_dll_init"

#define CYGWIN_DETACH "cygwin_detach_dll"
#define MSYS_DETACH "msys_detach_dll"

#define FUNC_CYG_WIN32_LIST         "cygwin_posix_to_win32_path_list"
#define FUNC_CYG_WIN32_LIST_SIZE    "cygwin_posix_to_win32_path_list_buf_size"
#define FUNC_CYG_POSIX_LIST         "cygwin_win32_to_posix_path_list"
#define FUNC_CYG_POSIX_LIST_SIZE    "cygwin_win32_to_posix_path_list_buf_size"

#define FUNC_MSYS_WIN32_LIST        "cygwin32_posix_to_win32_path_list"
#define FUNC_MSYS_WIN32_LIST_SIZE   "cygwin32_posix_to_win32_path_list_buf_size"
#define FUNC_MSYS_POSIX_LIST        "cygwin32_win32_to_posix_path_list"
#define FUNC_MSYS_POSIX_LIST_SIZE   "cygwin32_win32_to_posix_path_list_buf_size"

#define FUNC_WIN32_PATH         "cygwin_conv_to_win32_path"
#define FUNC_WIN32_FULL_PATH    "cygwin_conv_to_full_win32_path"
#define FUNC_POSIX_PATH         "cygwin_conv_to_posix_path"
#define FUNC_POSIX_FULL_PATH    "cygwin_conv_to_full_posix_path"

// Load posix sys dll or get the handle to a dll already loaded.
#define SetSysDll(h) if((h = GetModuleHandleA(dllName)) == NULL) \
        if((h = LoadLibraryA(dllName)) == NULL) \
            fatal("Could not load %s.", dllName);

// void cygwin_dll_init()
typedef void (*pInit)();
#define SetInitFunc(h,m) if((m = (pInit)GetProcAddress(h, initFunc)) == NULL) {\
        FreeLibrary(h); \
        fatal("Failed to load %s(const char *, char *) from %s.", initFunc, dllName); \
    }

// int cygwin_conv_to_win32_path (const char *, char *)
typedef int (*pConvPathFunc)(const char *, char *);
#define SetConvPathFunc(h,m,f) if((m = (pConvPathFunc)GetProcAddress(h, f)) == NULL) {\
        FreeLibrary(h); \
        fatal("Failed to load %s(const char *, char *) from %s.", f, dllName); \
    }

// int cygwin_posix_to_win32_path_list_buf_size (const char *)
typedef int (*pPathBufferSizeFunc)(const char *);
#define SetPathBufferSizeFunc(h,m,f) if((m = (pPathBufferSizeFunc)GetProcAddress(h, f)) == NULL) {\
        FreeLibrary(h); \
        fatal("Failed to load %s(const char *) from %s.", f, dllName); \
    }

#ifndef MAX_PATH
#   define MAX_PATH _MAX_PATH
#endif

typedef enum {
    SYS_MSYS = 0,
    SYS_CYGWIN
} PosixSysType;

typedef struct {
    HMODULE hInstance;
    pInit Init;
    pConvPathFunc ToWin32List;
    pPathBufferSizeFunc ToWin32ListBuffSize;
    pConvPathFunc ToPosixList;
    pPathBufferSizeFunc ToPosixListBuffSize;
    pConvPathFunc ToWin32Path;
    pConvPathFunc ToWin32FullPath;
    pConvPathFunc ToPosixPath;
    pConvPathFunc ToPosixFullPath;
} PosixSys, *pPosixSys;

#define DEFAULT_POSIXSYS {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}

void fatal(const char* format, ...)
{
    va_list ap;
    fprintf(stderr, FATAL_PREFIX);
    va_start(ap, format);
    vfprintf(stderr, format, ap);
    va_end(ap);
    fprintf(stderr, NEW_LINE); // TODO: Print to log here.
    exit(EXIT_FAILURE);
}

PosixSysType FindSysType()
{
    char* msys = getenv("MSYSTEM");
    return (msys && (_stricmp(msys, "MINGW32") == 0)) ? SYS_MSYS : SYS_CYGWIN;
}

BOOL IsPosixSys()
{
    char* term = getenv("TERM");
    return (getenv("SHLVL") && term && (_stricmp(term, "cygwin") == 0));
}

#define info(m) printf(# m "\n");
void LoadSys(pPosixSys sys)
{
    char *dllName, *initFunc, *win32list, *win32listSize, *posixlist, *posixlistSize;
    PosixSysType sys_type = FindSysType();
    if(sys_type == SYS_MSYS) {
        dllName =  MSYS_DLL;
        initFunc = MSYS_INIT;
        win32list = FUNC_MSYS_WIN32_LIST;
        win32listSize = FUNC_MSYS_WIN32_LIST_SIZE;
        posixlist = FUNC_MSYS_POSIX_LIST;
        posixlistSize = FUNC_MSYS_POSIX_LIST_SIZE;
    } else {
        dllName = CYGWIN_DLL;
        initFunc = CYGWIN_INIT;
        win32list = FUNC_CYG_WIN32_LIST;
        win32listSize = FUNC_CYG_WIN32_LIST_SIZE;
        posixlist = FUNC_CYG_POSIX_LIST;
        posixlistSize = FUNC_CYG_POSIX_LIST_SIZE;
    }

    SetSysDll(sys->hInstance);
    SetInitFunc(sys->hInstance, sys->Init);

    SetConvPathFunc(sys->hInstance, sys->ToWin32List, win32list);
    SetPathBufferSizeFunc(sys->hInstance, sys->ToWin32ListBuffSize, win32listSize);

    SetConvPathFunc(sys->hInstance, sys->ToPosixList, posixlist);
    SetPathBufferSizeFunc(sys->hInstance, sys->ToPosixListBuffSize, posixlistSize);

    SetConvPathFunc(sys->hInstance, sys->ToWin32Path, FUNC_WIN32_PATH);
    SetConvPathFunc(sys->hInstance, sys->ToWin32FullPath, FUNC_WIN32_FULL_PATH);

    SetConvPathFunc(sys->hInstance, sys->ToPosixPath, FUNC_POSIX_PATH);
    SetConvPathFunc(sys->hInstance, sys->ToPosixFullPath, FUNC_POSIX_FULL_PATH);

    info(sys->Init())
    sys->Init();
}



int main(int argc, char* argv[])
{
    PosixSys sys = DEFAULT_POSIXSYS;
    char* inputBuffer = "/bin/bash";
    char outBuffer[MAX_PATH*MAX_PATH] = "\0";
    int result = 0;

    if(!IsPosixSys()) {
        printf("Not currently in a posix system.\n");
        return 0;
    }
    LoadSys(&sys);

    if(argc > 1) inputBuffer = argv[1];
    info(result = sys.ToWin32Path((const char *)inputBuffer, outBuffer))
    result = sys.ToWin32Path((const char *)inputBuffer, outBuffer);

    printf("cygwin_conv_to_win32_path returned %d.\n", result);
    printf("outBuffer : %s\n", outBuffer);
    FreeLibrary(sys.hInstance);
    return EXIT_SUCCESS;
}

 

After writing it, I did a quick run in cygwin. Got:

 

$ ./posix-path.exe
sys->Init()
result = sys.ToWin32Path((const char *)inputBuffer, outBuffer)
cygwin_conv_to_win32_path returned 0.
outBuffer : C:\ShellEnv\bin\bash

 

So that's good. However, when I opened a new shell and tried running it in any of my msys environments, I get the following:

 

$ ./posix-path.exe
sys->Init()
      0 [main] posix-path 2112 handle_exceptions: Exception: STATUS_ACCESS_VIOLATION
    483 [main] posix-path 2112 open_stackdumpfile: Dumping stack trace to posix-path.exe.stackdump
Segmentation fault (core dumped)

 

After finding out that it's failing at the sys->Init(); call, I ran it through gdb and got the following:

 

warning:   GetEnvironmentVariableA
warning:   GetProcAddress
warning:   LoadLibraryA
warning:   LoadLibraryExA
warning:   WriteFile
warning: WriteFile->
warning: WriteConsoleA: 13 "sys->Init()\r\n"
sys->Init()
warning: Hooking in advapi32 (LoadLibraryA)
warning:   LoadLibraryExW
warning:   GetProcAddress
warning:   LoadLibraryA
warning:   LoadLibraryW
warning:   LoadLibraryExA
warning:   WriteFile
warning: Hooking in SspiCli.dll (LoadLibraryExA)
warning:   GetProcAddress
warning:   LoadLibraryExW
warning:   LoadLibraryExA

Program received signal SIGSEGV, Segmentation fault.
0x6080affb in unsetenv ()
   from C:\ShellEnv\j-tree\usr\sbin\develop\compilers\mingw\msys\1.0\bin\msys-1.0.dll

 

Anyone have any ideas? (Also, I realize the cygwin_conv_to_win32_path, etc. functions are depreciated. Figured I'd keep it simple for the moment, and change over to the new implementations once I get it working. Both DLLs still export the functions.)