utilsunx.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,275 行 · 第 1/3 页

CPP
1,275
字号

    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(fd, &readfds);
    switch ( select(fd + 1, &readfds, NULL, NULL, &tv) )
    {
        case -1:
            wxLogSysError(_("Impossible to get child process input"));
            // fall through

        case 0:
            return false;

        default:
            wxFAIL_MSG(_T("unexpected select() return value"));
            // still fall through

        case 1:
            // input available -- or maybe not, as select() returns 1 when a
            // read() will complete without delay, but it could still not read
            // anything
            return !Eof();
    }
}

#endif // wxUSE_STREAMS

// ----------------------------------------------------------------------------
// wxExecute: the real worker function
// ----------------------------------------------------------------------------

#ifdef __VMS
    #pragma message disable codeunreachable
#endif
               
long wxExecute(wxChar **argv,
               int flags,
               wxProcess *process)
{
    // for the sync execution, we return -1 to indicate failure, but for async
    // case we return 0 which is never a valid PID
    //
    // we define this as a macro, not a variable, to avoid compiler warnings
    // about "ERROR_RETURN_CODE value may be clobbered by fork()"
    #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)

    wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );

#if wxUSE_UNICODE
    int mb_argc = 0;
    char *mb_argv[WXEXECUTE_NARGS];

    while (argv[mb_argc])
    {
        wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
        mb_argv[mb_argc] = strdup(mb_arg);
        mb_argc++;
    }
    mb_argv[mb_argc] = (char *) NULL;

    // this macro will free memory we used above
    #define ARGS_CLEANUP                                 \
        for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
            free(mb_argv[mb_argc])
#else // ANSI
    // no need for cleanup
    #define ARGS_CLEANUP

    wxChar **mb_argv = argv;
#endif // Unicode/ANSI

    // we want this function to work even if there is no wxApp so ensure that
    // we have a valid traits pointer
    wxConsoleAppTraits traitsConsole;
    wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
    if ( !traits )
        traits = &traitsConsole;

    // this struct contains all information which we pass to and from
    // wxAppTraits methods
    wxExecuteData execData;
    execData.flags = flags;
    execData.process = process;

    // create pipes
    if ( !traits->CreateEndProcessPipe(execData) )
    {
        wxLogError( _("Failed to execute '%s'\n"), *argv );

        ARGS_CLEANUP;

        return ERROR_RETURN_CODE;
    }

    // pipes for inter process communication
    wxPipe pipeIn,      // stdin
           pipeOut,     // stdout
           pipeErr;     // stderr

    if ( process && process->IsRedirected() )
    {
        if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
        {
            wxLogError( _("Failed to execute '%s'\n"), *argv );

            ARGS_CLEANUP;

            return ERROR_RETURN_CODE;
        }
    }

    // fork the process
    //
    // NB: do *not* use vfork() here, it completely breaks this code for some
    //     reason under Solaris (and maybe others, although not under Linux)
    //     But on OpenVMS we do not have fork so we have to use vfork and
    //     cross our fingers that it works.
#ifdef __VMS
   pid_t pid = vfork();
#else
   pid_t pid = fork();
#endif
   if ( pid == -1 )     // error?
    {
        wxLogSysError( _("Fork failed") );

        ARGS_CLEANUP;

        return ERROR_RETURN_CODE;
    }
    else if ( pid == 0 )  // we're in child
    {
        // These lines close the open file descriptors to to avoid any
        // input/output which might block the process or irritate the user. If
        // one wants proper IO for the subprocess, the right thing to do is to
        // start an xterm executing it.
        if ( !(flags & wxEXEC_SYNC) )
        {
            // FD_SETSIZE is unsigned under BSD, signed under other platforms
            // so we need a cast to avoid warnings on all platforms
            for ( int fd = 0; fd < (int)FD_SETSIZE; fd++ )
            {
                if ( fd == pipeIn[wxPipe::Read]
                        || fd == pipeOut[wxPipe::Write]
                        || fd == pipeErr[wxPipe::Write]
                        || traits->IsWriteFDOfEndProcessPipe(execData, fd) )
                {
                    // don't close this one, we still need it
                    continue;
                }

                // leave stderr opened too, it won't do any harm
                if ( fd != STDERR_FILENO )
                    close(fd);
            }
        }

#if !defined(__VMS) && !defined(__EMX__)
        if ( flags & wxEXEC_MAKE_GROUP_LEADER )
        {
            // Set process group to child process' pid.  Then killing -pid
            // of the parent will kill the process and all of its children.
            setsid();
        }
#endif // !__VMS

        // reading side can be safely closed but we should keep the write one
        // opened
        traits->DetachWriteFDOfEndProcessPipe(execData);

        // redirect stdin, stdout and stderr
        if ( pipeIn.IsOk() )
        {
            if ( dup2(pipeIn[wxPipe::Read], STDIN_FILENO) == -1 ||
                 dup2(pipeOut[wxPipe::Write], STDOUT_FILENO) == -1 ||
                 dup2(pipeErr[wxPipe::Write], STDERR_FILENO) == -1 )
            {
                wxLogSysError(_("Failed to redirect child process input/output"));
            }

            pipeIn.Close();
            pipeOut.Close();
            pipeErr.Close();
        }

        execvp (*mb_argv, mb_argv);
       
        fprintf(stderr, "execvp(");
        // CS changed ppc to ppc_ as ppc is not available under mac os CW Mach-O
        for ( char **ppc_ = mb_argv; *ppc_; ppc_++ )
            fprintf(stderr, "%s%s", ppc_ == mb_argv ? "" : ", ", *ppc_);
        fprintf(stderr, ") failed with error %d!\n", errno);

        // there is no return after successful exec()
        _exit(-1);

        // some compilers complain about missing return - of course, they
        // should know that exit() doesn't return but what else can we do if
        // they don't?
        //
        // and, sure enough, other compilers complain about unreachable code
        // after exit() call, so we can just always have return here...
#if defined(__VMS) || defined(__INTEL_COMPILER)
        return 0;
#endif
    }
    else // we're in parent
    {
        ARGS_CLEANUP;

        // save it for WaitForChild() use
        execData.pid = pid;

        // prepare for IO redirection

#if wxUSE_STREAMS
        // the input buffer bufOut is connected to stdout, this is why it is
        // called bufOut and not bufIn
        wxStreamTempInputBuffer bufOut,
                                bufErr;
#endif // wxUSE_STREAMS

        if ( process && process->IsRedirected() )
        {
#if wxUSE_STREAMS
            wxOutputStream *inStream =
                new wxFileOutputStream(pipeIn.Detach(wxPipe::Write));

            wxPipeInputStream *outStream =
                new wxPipeInputStream(pipeOut.Detach(wxPipe::Read));

            wxPipeInputStream *errStream =
                new wxPipeInputStream(pipeErr.Detach(wxPipe::Read));

            process->SetPipeStreams(outStream, inStream, errStream);

            bufOut.Init(outStream);
            bufErr.Init(errStream);

            execData.bufOut = &bufOut;
            execData.bufErr = &bufErr;
#endif // wxUSE_STREAMS
        }

        if ( pipeIn.IsOk() )
        {
            pipeIn.Close();
            pipeOut.Close();
            pipeErr.Close();
        }

        return traits->WaitForChild(execData);
    }

    return ERROR_RETURN_CODE;
}

#ifdef __VMS
    #pragma message enable codeunreachable
#endif

#undef ERROR_RETURN_CODE
#undef ARGS_CLEANUP

// ----------------------------------------------------------------------------
// file and directory functions
// ----------------------------------------------------------------------------

const wxChar* wxGetHomeDir( wxString *home  )
{
    *home = wxGetUserHome( wxEmptyString );
    wxString tmp;
    if ( home->empty() )
        *home = wxT("/");
#ifdef __VMS
    tmp = *home;
    if ( tmp.Last() != wxT(']'))
        if ( tmp.Last() != wxT('/')) *home << wxT('/');
#endif
    return home->c_str();
}

#if wxUSE_UNICODE
const wxMB2WXbuf wxGetUserHome( const wxString &user )
#else // just for binary compatibility -- there is no 'const' here
char *wxGetUserHome( const wxString &user )
#endif
{
    struct passwd *who = (struct passwd *) NULL;

    if ( !user )
    {
        wxChar *ptr;

        if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
        {
#if wxUSE_UNICODE
            wxWCharBuffer buffer( ptr );
            return buffer;
#else
            return ptr;
#endif
        }
        if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
        {
            who = getpwnam(wxConvertWX2MB(ptr));
        }

        // We now make sure the the user exists!
        if (who == NULL)
        {
            who = getpwuid(getuid());
        }
    }
    else
    {
      who = getpwnam (user.mb_str());
    }

    return wxConvertMB2WX(who ? who->pw_dir : 0);
}

// ----------------------------------------------------------------------------
// network and user id routines
// ----------------------------------------------------------------------------

// retrieve either the hostname or FQDN depending on platform (caller must
// check whether it's one or the other, this is why this function is for
// private use only)
static bool wxGetHostNameInternal(wxChar *buf, int sz)
{
    wxCHECK_MSG( buf, false, wxT("NULL pointer in wxGetHostNameInternal") );

    *buf = wxT('\0');

    // we're using uname() which is POSIX instead of less standard sysinfo()
#if defined(HAVE_UNAME)
    struct utsname uts;
    bool ok = uname(&uts) != -1;
    if ( ok )
    {
        wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1);
        buf[sz] = wxT('\0');
    }
#elif defined(HAVE_GETHOSTNAME)
    bool ok = gethostname(buf, sz) != -1;
#else // no uname, no gethostname
    wxFAIL_MSG(wxT("don't know host name for this machine"));

    bool ok = false;
#endif // uname/gethostname

    if ( !ok )
    {
        wxLogSysError(_("Cannot get the hostname"));
    }

    return ok;
}

bool wxGetHostName(wxChar *buf, int sz)
{
    bool ok = wxGetHostNameInternal(buf, sz);

    if ( ok )
    {
        // BSD systems return the FQDN, we only want the hostname, so extract
        // it (we consider that dots are domain separators)
        wxChar *dot = wxStrchr(buf, wxT('.'));
        if ( dot )
        {
            // nuke it
            *dot = wxT('\0');
        }
    }

    return ok;
}

bool wxGetFullHostName(wxChar *buf, int sz)
{
    bool ok = wxGetHostNameInternal(buf, sz);

    if ( ok )
    {
        if ( !wxStrchr(buf, wxT('.')) )
        {
            struct hostent *host = gethostbyname(wxConvertWX2MB(buf));
            if ( !host )
            {
                wxLogSysError(_("Cannot get the official hostname"));

                ok = false;
            }
            else
            {
                // the canonical name
                wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz);
            }
        }
        //else: it's already a FQDN (BSD behaves this way)
    }

    return ok;
}

bool wxGetUserId(wxChar *buf, int sz)
{
    struct passwd *who;

    *buf = wxT('\0');
    if ((who = getpwuid(getuid ())) != NULL)
    {
        wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
        return true;
    }

    return false;
}

bool wxGetUserName(wxChar *buf, int sz)
{
    struct passwd *who;

    *buf = wxT('\0');

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?