Blame src/portable.cpp

Packit 1c1d7e
#include <stdlib.h>
Packit 1c1d7e
#include <ctype.h>
Packit 1c1d7e
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 1c1d7e
#undef UNICODE
Packit 1c1d7e
#define _WIN32_DCOM
Packit 1c1d7e
#include <windows.h>
Packit 1c1d7e
#else
Packit 1c1d7e
#include <unistd.h>
Packit 1c1d7e
#include <stdlib.h>
Packit 1c1d7e
#include <sys/types.h>
Packit 1c1d7e
#include <sys/wait.h>
Packit 1c1d7e
#include <errno.h>
Packit 1c1d7e
extern char **environ;
Packit 1c1d7e
#endif
Packit 1c1d7e
Packit 1c1d7e
#include <qglobal.h>
Packit 1c1d7e
#include <qdatetime.h>
Packit 1c1d7e
Packit 1c1d7e
#if defined(_MSC_VER) || defined(__BORLANDC__)
Packit 1c1d7e
#define popen _popen
Packit 1c1d7e
#define pclose _pclose
Packit 1c1d7e
#endif
Packit 1c1d7e
Packit 1c1d7e
#include "portable.h"
Packit 1c1d7e
#ifndef NODEBUG
Packit 1c1d7e
#include "debug.h"
Packit 1c1d7e
#endif
Packit 1c1d7e
//#include "doxygen.h"
Packit 1c1d7e
Packit 1c1d7e
static double  g_sysElapsedTime;
Packit 1c1d7e
static QTime   g_time;
Packit 1c1d7e
Packit 1c1d7e
int portable_system(const char *command,const char *args,bool commandHasConsole)
Packit 1c1d7e
{
Packit 1c1d7e
Packit 1c1d7e
  if (command==0) return 1;
Packit 1c1d7e
Packit 1c1d7e
  QCString fullCmd=command;
Packit 1c1d7e
  fullCmd=fullCmd.stripWhiteSpace();
Packit 1c1d7e
  if (fullCmd.at(0)!='"' && fullCmd.find(' ')!=-1)
Packit 1c1d7e
  {
Packit 1c1d7e
    // add quotes around command as it contains spaces and is not quoted already
Packit 1c1d7e
    fullCmd="\""+fullCmd+"\"";
Packit 1c1d7e
  }
Packit 1c1d7e
  fullCmd += " ";
Packit 1c1d7e
  fullCmd += args;
Packit 1c1d7e
#ifndef NODEBUG
Packit 1c1d7e
  Debug::print(Debug::ExtCmd,0,"Executing external command `%s`\n",qPrint(fullCmd));
Packit 1c1d7e
#endif
Packit 1c1d7e
Packit 1c1d7e
#if !defined(_WIN32) || defined(__CYGWIN__)
Packit 1c1d7e
  (void)commandHasConsole;
Packit 1c1d7e
  /*! taken from the system() manpage on my Linux box */
Packit 1c1d7e
  int pid,status=0;
Packit 1c1d7e
Packit 1c1d7e
#ifdef _OS_SOLARIS // for Solaris we use vfork since it is more memory efficient
Packit 1c1d7e
Packit 1c1d7e
  // on Solaris fork() duplicates the memory usage
Packit 1c1d7e
  // so we use vfork instead
Packit 1c1d7e
  
Packit 1c1d7e
  // spawn shell
Packit 1c1d7e
  if ((pid=vfork())<0)
Packit 1c1d7e
  {
Packit 1c1d7e
    status=-1;
Packit 1c1d7e
  }
Packit 1c1d7e
  else if (pid==0)
Packit 1c1d7e
  {
Packit 1c1d7e
     execl("/bin/sh","sh","-c",fullCmd.data(),(char*)0);
Packit 1c1d7e
     _exit(127);
Packit 1c1d7e
  }
Packit 1c1d7e
  else
Packit 1c1d7e
  {
Packit 1c1d7e
    while (waitpid(pid,&status,0 )<0)
Packit 1c1d7e
    {
Packit 1c1d7e
      if (errno!=EINTR)
Packit 1c1d7e
      {
Packit 1c1d7e
        status=-1;
Packit 1c1d7e
        break;
Packit 1c1d7e
      }
Packit 1c1d7e
    }
Packit 1c1d7e
  }
Packit 1c1d7e
  return status;
Packit 1c1d7e
Packit 1c1d7e
#else  // Other Unices just use fork
Packit 1c1d7e
Packit 1c1d7e
  pid = fork();
Packit 1c1d7e
  if (pid==-1)
Packit 1c1d7e
  {
Packit 1c1d7e
    perror("fork error");
Packit 1c1d7e
	  return -1;
Packit 1c1d7e
  }
Packit 1c1d7e
  if (pid==0)
Packit 1c1d7e
  {
Packit 1c1d7e
    const char * argv[4];
Packit 1c1d7e
    argv[0] = "sh";
Packit 1c1d7e
    argv[1] = "-c";
Packit 1c1d7e
    argv[2] = fullCmd.data();
Packit 1c1d7e
    argv[3] = 0;
Packit 1c1d7e
    execve("/bin/sh",(char * const *)argv,environ);
Packit 1c1d7e
    exit(127);
Packit 1c1d7e
  }
Packit 1c1d7e
  for (;;)
Packit 1c1d7e
  {
Packit 1c1d7e
    if (waitpid(pid,&status,0)==-1)
Packit 1c1d7e
    {
Packit 1c1d7e
      if (errno!=EINTR) return -1;
Packit 1c1d7e
    }
Packit 1c1d7e
    else
Packit 1c1d7e
    {
Packit 1c1d7e
      if (WIFEXITED(status))
Packit 1c1d7e
      {
Packit 1c1d7e
        return WEXITSTATUS(status);
Packit 1c1d7e
      }
Packit 1c1d7e
      else
Packit 1c1d7e
      {
Packit 1c1d7e
        return status;
Packit 1c1d7e
      }
Packit 1c1d7e
    }
Packit 1c1d7e
  }
Packit 1c1d7e
#endif // !_OS_SOLARIS
Packit 1c1d7e
Packit 1c1d7e
#else // Win32 specific
Packit 1c1d7e
  if (commandHasConsole)
Packit 1c1d7e
  {
Packit 1c1d7e
    return system(fullCmd);
Packit 1c1d7e
  }
Packit 1c1d7e
  else
Packit 1c1d7e
  {
Packit 1c1d7e
    // Because ShellExecuteEx can delegate execution to Shell extensions 
Packit 1c1d7e
    // (data sources, context menu handlers, verb implementations) that 
Packit 1c1d7e
    // are activated using Component Object Model (COM), COM should be 
Packit 1c1d7e
    // initialized before ShellExecuteEx is called. Some Shell extensions 
Packit 1c1d7e
    // require the COM single-threaded apartment (STA) type. 
Packit 1c1d7e
    // For that case COM is initialized as follows
Packit 1c1d7e
    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
Packit 1c1d7e
Packit 1c1d7e
    QString commandw = QString::fromUtf8( command );
Packit 1c1d7e
    QString argsw = QString::fromUtf8( args );
Packit 1c1d7e
Packit 1c1d7e
    // gswin32 is a GUI api which will pop up a window and run
Packit 1c1d7e
    // asynchronously. To prevent both, we use ShellExecuteEx and
Packit 1c1d7e
    // WaitForSingleObject (thanks to Robert Golias for the code)
Packit 1c1d7e
Packit 1c1d7e
    SHELLEXECUTEINFOW sInfo = {
Packit 1c1d7e
      sizeof(SHELLEXECUTEINFOW),   /* structure size */
Packit 1c1d7e
      SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI,  /* tell us the process
Packit 1c1d7e
                                                       *  handle so we can wait till it's done | 
Packit 1c1d7e
                                                       *  do not display msg box if error 
Packit 1c1d7e
                                                       */
Packit 1c1d7e
      NULL,                       /* window handle */
Packit 1c1d7e
      NULL,                       /* action to perform: open */
Packit 1c1d7e
      (LPCWSTR)commandw.ucs2(),   /* file to execute */
Packit 1c1d7e
      (LPCWSTR)argsw.ucs2(),      /* argument list */ 
Packit 1c1d7e
      NULL,                       /* use current working dir */
Packit 1c1d7e
      SW_HIDE,                    /* minimize on start-up */
Packit 1c1d7e
      0,                          /* application instance handle */
Packit 1c1d7e
      NULL,                       /* ignored: id list */
Packit 1c1d7e
      NULL,                       /* ignored: class name */
Packit 1c1d7e
      NULL,                       /* ignored: key class */
Packit 1c1d7e
      0,                          /* ignored: hot key */
Packit 1c1d7e
      NULL,                       /* ignored: icon */
Packit 1c1d7e
      NULL                        /* resulting application handle */
Packit 1c1d7e
    };
Packit 1c1d7e
Packit 1c1d7e
    if (!ShellExecuteExW(&sInfo))
Packit 1c1d7e
    {
Packit 1c1d7e
      return -1;
Packit 1c1d7e
    }
Packit 1c1d7e
    else if (sInfo.hProcess)      /* executable was launched, wait for it to finish */
Packit 1c1d7e
    {
Packit 1c1d7e
      WaitForSingleObject(sInfo.hProcess,INFINITE); 
Packit 1c1d7e
      /* get process exit code */
Packit 1c1d7e
      DWORD exitCode;
Packit 1c1d7e
      if (!GetExitCodeProcess(sInfo.hProcess,&exitCode))
Packit 1c1d7e
      {
Packit 1c1d7e
        exitCode = -1;
Packit 1c1d7e
      }
Packit 1c1d7e
      CloseHandle(sInfo.hProcess);
Packit 1c1d7e
      return exitCode;
Packit 1c1d7e
    }
Packit 1c1d7e
  }
Packit 1c1d7e
#endif
Packit 1c1d7e
  return 1; // we should never get here
Packit 1c1d7e
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
uint portable_pid()
Packit 1c1d7e
{
Packit 1c1d7e
  uint pid;
Packit 1c1d7e
#if !defined(_WIN32) || defined(__CYGWIN__)
Packit 1c1d7e
  pid = (uint)getpid();
Packit 1c1d7e
#else
Packit 1c1d7e
  pid = (uint)GetCurrentProcessId();
Packit 1c1d7e
#endif
Packit 1c1d7e
  return pid;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 1c1d7e
#else
Packit 1c1d7e
  static char **last_environ;
Packit 1c1d7e
#endif
Packit 1c1d7e
Packit 1c1d7e
void portable_setenv(const char *name,const char *value)
Packit 1c1d7e
{
Packit 1c1d7e
    if (value==0) value="";
Packit 1c1d7e
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 1c1d7e
    SetEnvironmentVariable(name,value);
Packit 1c1d7e
#else
Packit 1c1d7e
    register char **ep = 0;
Packit 1c1d7e
    register size_t size;
Packit 1c1d7e
    const size_t namelen=qstrlen(name);
Packit 1c1d7e
    const size_t vallen=qstrlen(value) + 1;
Packit 1c1d7e
Packit 1c1d7e
    size = 0;
Packit 1c1d7e
    if (environ!=0)
Packit 1c1d7e
    {
Packit 1c1d7e
      for (ep = environ; *ep; ++ep)
Packit 1c1d7e
      {
Packit 1c1d7e
        if (!qstrncmp (*ep, name, (uint)namelen) &&
Packit 1c1d7e
            (*ep)[namelen] == '=')
Packit 1c1d7e
          break;
Packit 1c1d7e
        else
Packit 1c1d7e
          ++size;
Packit 1c1d7e
      }
Packit 1c1d7e
    }
Packit 1c1d7e
Packit 1c1d7e
    if (environ==0 || *ep==0) /* add new string */
Packit 1c1d7e
    {
Packit 1c1d7e
      char **new_environ;
Packit 1c1d7e
      if (environ == last_environ && environ!=0)
Packit 1c1d7e
      {
Packit 1c1d7e
        // We allocated this space; we can extend it. 
Packit 1c1d7e
        new_environ = (char **) realloc (last_environ, (size + 2) * sizeof (char *));
Packit 1c1d7e
      }
Packit 1c1d7e
      else
Packit 1c1d7e
      {
Packit 1c1d7e
        new_environ = (char **) malloc ((size + 2) * sizeof (char *));
Packit 1c1d7e
      }
Packit 1c1d7e
Packit 1c1d7e
      if (new_environ==0) // no more memory 
Packit 1c1d7e
      {
Packit 1c1d7e
        return;
Packit 1c1d7e
      }
Packit 1c1d7e
Packit 1c1d7e
      new_environ[size] = (char *)malloc (namelen + 1 + vallen);
Packit 1c1d7e
      if (new_environ[size]==0)
Packit 1c1d7e
      {
Packit 1c1d7e
        free (new_environ);
Packit 1c1d7e
        return;
Packit 1c1d7e
      }
Packit 1c1d7e
Packit 1c1d7e
      if (environ != last_environ)
Packit 1c1d7e
      {
Packit 1c1d7e
        memcpy ((char *) new_environ, environ, size * sizeof (char *));
Packit 1c1d7e
      }
Packit 1c1d7e
Packit 1c1d7e
      memcpy(new_environ[size], name, namelen);
Packit 1c1d7e
      new_environ[size][namelen] = '=';
Packit 1c1d7e
      memcpy(&new_environ[size][namelen + 1], value, vallen);
Packit 1c1d7e
      new_environ[size + 1] = 0;
Packit 1c1d7e
      last_environ = environ = new_environ;
Packit 1c1d7e
    }
Packit 1c1d7e
    else /* replace existing string */
Packit 1c1d7e
    {
Packit 1c1d7e
      size_t len = qstrlen (*ep);
Packit 1c1d7e
      if (len + 1 < namelen + 1 + vallen)
Packit 1c1d7e
      {
Packit 1c1d7e
        /* The existing string is too short; malloc a new one.  */
Packit 1c1d7e
        char *newString = (char *)malloc(namelen + 1 + vallen);
Packit 1c1d7e
        if (newString==0)
Packit 1c1d7e
        {
Packit 1c1d7e
          return;
Packit 1c1d7e
        }
Packit 1c1d7e
        *ep = newString;
Packit 1c1d7e
      }
Packit 1c1d7e
      memcpy(*ep, name, namelen);
Packit 1c1d7e
      (*ep)[namelen] = '=';
Packit 1c1d7e
      memcpy(&(*ep)[namelen + 1], value, vallen);
Packit 1c1d7e
    }
Packit 1c1d7e
Packit 1c1d7e
#endif
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void portable_unsetenv(const char *variable)
Packit 1c1d7e
{
Packit 1c1d7e
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 1c1d7e
    SetEnvironmentVariable(variable,0);
Packit 1c1d7e
#else
Packit 1c1d7e
    /* Some systems don't have unsetenv(), so we do it ourselves */
Packit 1c1d7e
    size_t len;
Packit 1c1d7e
    char **ep;
Packit 1c1d7e
Packit 1c1d7e
    if (variable == NULL || *variable == '\0' || strchr (variable, '=') != NULL)
Packit 1c1d7e
    {
Packit 1c1d7e
      return; // not properly formatted
Packit 1c1d7e
    }
Packit 1c1d7e
Packit 1c1d7e
    len = qstrlen(variable);
Packit 1c1d7e
Packit 1c1d7e
    ep = environ;
Packit 1c1d7e
    while (*ep != NULL)
Packit 1c1d7e
    {
Packit 1c1d7e
      if (!qstrncmp(*ep, variable, (uint)len) && (*ep)[len]=='=')
Packit 1c1d7e
      {
Packit 1c1d7e
        /* Found it.  Remove this pointer by moving later ones back.  */
Packit 1c1d7e
        char **dp = ep;
Packit 1c1d7e
        do dp[0] = dp[1]; while (*dp++);
Packit 1c1d7e
        /* Continue the loop in case NAME appears again.  */
Packit 1c1d7e
      }
Packit 1c1d7e
      else
Packit 1c1d7e
      {
Packit 1c1d7e
        ++ep;
Packit 1c1d7e
      }
Packit 1c1d7e
    }
Packit 1c1d7e
#endif
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
const char *portable_getenv(const char *variable)
Packit 1c1d7e
{
Packit 1c1d7e
  return getenv(variable);
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
portable_off_t portable_fseek(FILE *f,portable_off_t offset, int whence)
Packit 1c1d7e
{
Packit 1c1d7e
#if defined(__MINGW32__)
Packit 1c1d7e
  return fseeko64(f,offset,whence);
Packit 1c1d7e
#elif defined(_WIN32) && !defined(__CYGWIN__)
Packit 1c1d7e
  return _fseeki64(f,offset,whence);
Packit 1c1d7e
#else
Packit 1c1d7e
  return fseeko(f,offset,whence);
Packit 1c1d7e
#endif
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
portable_off_t portable_ftell(FILE *f)
Packit 1c1d7e
{
Packit 1c1d7e
#if defined(__MINGW32__)
Packit 1c1d7e
  return ftello64(f);  
Packit 1c1d7e
#elif defined(_WIN32) && !defined(__CYGWIN__)
Packit 1c1d7e
  return _ftelli64(f);
Packit 1c1d7e
#else
Packit 1c1d7e
  return ftello(f);
Packit 1c1d7e
#endif
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
FILE *portable_fopen(const char *fileName,const char *mode)
Packit 1c1d7e
{
Packit 1c1d7e
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 1c1d7e
  QString fn(fileName);
Packit 1c1d7e
  QString m(mode);
Packit 1c1d7e
  return _wfopen((wchar_t*)fn.ucs2(),(wchar_t*)m.ucs2());
Packit 1c1d7e
#else
Packit 1c1d7e
  return fopen(fileName,mode);
Packit 1c1d7e
#endif
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
char  portable_pathSeparator()
Packit 1c1d7e
{
Packit 1c1d7e
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 1c1d7e
  return '\\';
Packit 1c1d7e
#else
Packit 1c1d7e
  return '/';
Packit 1c1d7e
#endif
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
char  portable_pathListSeparator()
Packit 1c1d7e
{
Packit 1c1d7e
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 1c1d7e
  return ';';
Packit 1c1d7e
#else
Packit 1c1d7e
  return ':';
Packit 1c1d7e
#endif
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
const char *portable_ghostScriptCommand()
Packit 1c1d7e
{
Packit 1c1d7e
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 1c1d7e
    return "gswin32c.exe";
Packit 1c1d7e
#else
Packit 1c1d7e
    return "gs";
Packit 1c1d7e
#endif
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
const char *portable_commandExtension()
Packit 1c1d7e
{
Packit 1c1d7e
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 1c1d7e
    return ".exe";
Packit 1c1d7e
#else
Packit 1c1d7e
    return "";
Packit 1c1d7e
#endif
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
bool portable_fileSystemIsCaseSensitive()
Packit 1c1d7e
{
Packit 1c1d7e
#if defined(_WIN32) || defined(macintosh) || defined(__MACOSX__) || defined(__APPLE__)
Packit 1c1d7e
  return FALSE;
Packit 1c1d7e
#else
Packit 1c1d7e
  return TRUE;
Packit 1c1d7e
#endif
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
FILE * portable_popen(const char *name,const char *type)
Packit 1c1d7e
{
Packit 1c1d7e
  return popen(name,type);
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
int portable_pclose(FILE *stream)
Packit 1c1d7e
{
Packit 1c1d7e
  return pclose(stream);
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void portable_sysTimerStart()
Packit 1c1d7e
{
Packit 1c1d7e
  g_time.start();
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void portable_sysTimerStop()
Packit 1c1d7e
{
Packit 1c1d7e
  g_sysElapsedTime+=((double)g_time.elapsed())/1000.0;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
double portable_getSysElapsedTime()
Packit 1c1d7e
{
Packit 1c1d7e
  return g_sysElapsedTime;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void portable_sleep(int ms)
Packit 1c1d7e
{
Packit 1c1d7e
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 1c1d7e
  Sleep(ms);
Packit 1c1d7e
#else
Packit 1c1d7e
  usleep(1000*ms);
Packit 1c1d7e
#endif
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
bool portable_isAbsolutePath(const char *fileName)
Packit 1c1d7e
{
Packit 1c1d7e
# ifdef _WIN32
Packit 1c1d7e
  if (isalpha (fileName [0]) && fileName[1] == ':')
Packit 1c1d7e
    fileName += 2;
Packit 1c1d7e
# endif
Packit 1c1d7e
  char const fst = fileName [0];
Packit 1c1d7e
  if (fst == '/')  {
Packit 1c1d7e
    return true;
Packit 1c1d7e
  }
Packit 1c1d7e
# ifdef _WIN32
Packit 1c1d7e
  if (fst == '\\')
Packit 1c1d7e
    return true;
Packit 1c1d7e
# endif
Packit 1c1d7e
  return false;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
/**
Packit 1c1d7e
 * Correct a possible wrong PATH variable
Packit 1c1d7e
 *
Packit 1c1d7e
 * This routine was inspired by the cause for bug 766059 was that in the Windows path there were forward slahes.
Packit 1c1d7e
 */
Packit 1c1d7e
void portable_correct_path(void)
Packit 1c1d7e
{
Packit 1c1d7e
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 1c1d7e
  const char *p = portable_getenv("PATH");
Packit 1c1d7e
  char *q = (char *)malloc(strlen(p) + 1);
Packit 1c1d7e
  strcpy(q, p);
Packit 1c1d7e
  bool found = false;
Packit 1c1d7e
  for (int i = 0 ; i < strlen(q); i++)
Packit 1c1d7e
  {
Packit 1c1d7e
    if (q[i] == '/')
Packit 1c1d7e
    {
Packit 1c1d7e
      q[i] = '\\';
Packit 1c1d7e
      found = true;
Packit 1c1d7e
    }
Packit 1c1d7e
  }
Packit 1c1d7e
  if (found) portable_setenv("PATH",q);
Packit 1c1d7e
  free(q);
Packit 1c1d7e
#endif
Packit 1c1d7e
}