RFC: msvcrt _popen/_wpopen/_pclose

Jaco Greeff jaco at puxedo.org
Thu Oct 31 15:27:43 CST 2002


Hi,

I want some comments on the possibility of a _popen/_wpopen/_pclose
implementation in Wine. Reference available at:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__popen.2c_._wpopen.asp

The open functions basically operate in the same way as the popen function
in Linux, ie. it spawns a process with the command via the command
interpreter. Now, unfortionately we don't have our won cmd.exe available,
but should people really need this functionality it might not be too much to
ask as to copy it from a working Windows installation.

In my mind, supporting the Win 95/98 command interpreters might be a
nightmare - my gutt feel is that these two rely too much on DOS internals to
be sucessfully launched via Wine. No, I haven't tried it, so I might be
completely wrong. Either way, something like this might be better
implemented via the Win NT/2000/XP cmd.exe. (I'll test my assumptions
tomorrow, I don't have access to the command interpreters tonight.)

I've hacked (yes, it was quick) a potential implementation of the _popen
family of functions. (Haven't compiled, haven't tested, this is just and RFC
- if it can work, I'll spend some real time on it.) Anyway, here it is,
comments appreciated:

--[ inline-ish RFC ]----

#include "config.h"
#include "wine/port.h"

#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif

#include "winbase.h"
#include "winnls.h"
#include "wine/unicode.h"
#include "msvcrt/stdio.h"
#include "msvcrt/string.h"

#include "wine/debug.h"

#define POPEN_FLAG_READ     0x0001
#define POPEN_FLAG_WRITE    0x0002
#define POPEN_FLAG_TEXT     0x0004
#define POPEN_FLAG_BINARY   0x0008

inline CHAR *LPCWSTRToLPSTR(const LPCWSTR lpwstrIn, INT nIn)
{
    INT nLen = WideCharToMultiByte(CP_ACP, 0, lpwszIn, nIn, NULL, 0, NULL,
NULL);
    CHAR *szOut = (CHAR *)malloc((nLen+1)*sizeof(CHAR));
    if (szOut)
    {
        WideCharToMultiByte(CP_ACP, 0, lpwszIn, nIn, szOut, nLen+1, NULL, NULL);
        szOut[nLen] = '\0';
    }
    return szOut;
}

INT POPEN_parseModeFlags(const CHAR *szMode)
{
    INT nFlags = 0;
    while (szMode && *szMode)
    {
        switch (*szMode)
        {
            case 'r':
            {
                if (nFlags & POPEN_FLAG_WRITE)
                    WARN(": _popen: Cannot set both read and write open
flags, ignoring read flag\n");
                else
                    nFlags = nFlags & POPEN_FLAG_READ;
                break;
            }
            case 'w':
            {
                if (nFlags & POPEN_FLAG_READ)
                    WARN(": _popen: Cannot set both read and write open
flags, ignoring write flag\n");
                else
                    nFlags = nFlags & POPEN_FLAG_WRITE;
                break;
            }
            case 'b':
            case 't':
            {
                FIXME(": _popen: %c mode flag not implemented, ignoring\n",
*szMode);
                break;
            }
            default:
            {
                WARN(": _popen: unknown mode flag %c, ignoring\n", *szMode);
                break;
            }
        }
    }
    return nFlags;
}

MSVCRT_FILE *MSVCRT_popen(const CHAR *szCommand, const CHAR *szMode)
{
    MSVCRT_FILE *fProcess = NULL;

    if (!szCommand || !szMode)
        return NULL;

    INT nFlags = POPEN_parseModeFlags(szMode);
    if (!(nFlags & (POPEN_FLAG_READ|POPEN_FLAG_WRITE)))
    {
        ERR("No open mode flag r or w specified\n");
        return NULL;
    }

    /* _popen/_wpopen executes the required command via the command
     * processor, either command.com (Win 95/98) or cmd.exe (Win NT/2000/XP).
     * Wine does not currently have it's own "cmd.exe" hence we cannot
     * really do anything more at this point. However, we try to lauch it
     * and hope for the best...
     */
    CHAR *szExec = (CHAR *)malloc(strlen("wine -- C:/cmd.exe -C
")+strlen(szCommand)+1);
    if (szExec)
    {
        sprintf(szExec, "wine -- C:/cmd.exe -C %s", szCommand);
        fProcess = popen(szExec, (nFlags & POPEN_FLAG_READ) ? "r" : "w");
        if (!fProcess)
            ERR("Execution of C:/cmd.exe via wine failed\n");
        else
            WARN("Launch of %s succeeded, no guarentees of success made\n",
debugstr_a(szExec));
        free(szExec);
    }

    return fProcess;
}

MSVCRT_FILE *MSVCRT_wpopen(const WCHAR *wszCommand, const WCHAR *wszMode)
{
    MSVCRT_FILE *fProcess = NULL;

    if (!wszCommand || !wszMode)
        return NULL;

    CHAR *szCommand = LPCWSTRToLPSTR(wszCommand, strlenW(wszCommand));
    if (szCommand)
    {
        CHAR *szMode = LPCWSTRToLPSTR(wszMode, strlenW(wszMode));
        if (szMode)
        {
            fProcess = _popen(szCommand, szMode);
            free(szMode);
            free(szCommand);
        }
        free(szCommand);
    }

    return fProcess;
}

int MSVCRT_pclose(MSVCRT_FILE *fProcess)
{
    if (!fProcess)
        return -1;
    return pclose(fProcess);
}




More information about the wine-devel mailing list