00001 #include <stdlib.h> 00002 #include <ctype.h> 00003 #if defined(_WIN32) && !defined(__CYGWIN__) 00004 #undef UNICODE 00005 #include <windows.h> 00006 #else 00007 #include <unistd.h> 00008 #include <stdlib.h> 00009 #include <sys/types.h> 00010 #include <sys/wait.h> 00011 #include <errno.h> 00012 extern char **environ; 00013 #endif 00014 00015 #include <qglobal.h> 00016 #include <qdatetime.h> 00017 #include <iconv.h> 00018 00019 #if defined(_MSC_VER) || defined(__BORLANDC__) 00020 #define popen _popen 00021 #define pclose _pclose 00022 #endif 00023 00024 #include "portable.h" 00025 #ifndef NODEBUG 00026 #include "debug.h" 00027 #endif 00028 //#include "doxygen.h" 00029 00030 static double sysElapsedTime; 00031 00032 int portable_system(const char *command,const char *args,bool commandHasConsole) 00033 { 00034 QTime time; 00035 time.start(); 00036 00037 if (command==0) return 1; 00038 00039 QCString fullCmd=command; 00040 fullCmd=fullCmd.stripWhiteSpace(); 00041 if (fullCmd.at(0)!='"' && fullCmd.find(' ')!=-1) 00042 { 00043 // add quotes around command as it contains spaces and is not quoted already 00044 fullCmd="\""+fullCmd+"\""; 00045 } 00046 fullCmd += " "; 00047 fullCmd += args; 00048 #ifndef NODEBUG 00049 Debug::print(Debug::ExtCmd,0,"Executing external command `%s`\n",fullCmd.data()); 00050 #endif 00051 00052 #if !defined(_WIN32) || defined(__CYGWIN__) 00053 commandHasConsole=commandHasConsole; 00055 int pid,status=0; 00056 00057 #ifdef _OS_SOLARIS // for Solaris we use vfork since it is more memory efficient 00058 00059 // on Solaris fork() duplicates the memory usage 00060 // so we use vfork instead 00061 00062 // spawn shell 00063 if ((pid=vfork())<0) 00064 { 00065 status=-1; 00066 } 00067 else if (pid==0) 00068 { 00069 execl("/bin/sh","sh","-c",fullCmd.data(),(char*)0); 00070 _exit(127); 00071 } 00072 else 00073 { 00074 while (waitpid(pid,&status,0 )<0) 00075 { 00076 if (errno!=EINTR) 00077 { 00078 status=-1; 00079 break; 00080 } 00081 } 00082 } 00083 sysElapsedTime+=((double)time.elapsed())/1000.0; 00084 return status; 00085 00086 #else // Other Unices just use fork 00087 00088 pid = fork(); 00089 if (pid==-1) return -1; 00090 if (pid==0) 00091 { 00092 const char * argv[4]; 00093 argv[0] = "sh"; 00094 argv[1] = "-c"; 00095 argv[2] = fullCmd.data(); 00096 argv[3] = 0; 00097 execve("/bin/sh",(char * const *)argv,environ); 00098 exit(127); 00099 } 00100 for (;;) 00101 { 00102 if (waitpid(pid,&status,0)==-1) 00103 { 00104 if (errno!=EINTR) return -1; 00105 } 00106 else 00107 { 00108 sysElapsedTime+=((double)time.elapsed())/1000.0; 00109 if (WIFEXITED(status)) 00110 { 00111 return WEXITSTATUS(status); 00112 } 00113 else 00114 { 00115 return status; 00116 } 00117 } 00118 } 00119 #endif // !_OS_SOLARIS 00120 00121 #else // Win32 specific 00122 if (commandHasConsole) 00123 { 00124 return system(fullCmd); 00125 } 00126 else 00127 { 00128 // gswin32 is a GUI api which will pop up a window and run 00129 // asynchronously. To prevent both, we use ShellExecuteEx and 00130 // WaitForSingleObject (thanks to Robert Golias for the code) 00131 00132 SHELLEXECUTEINFO sInfo = { 00133 sizeof(SHELLEXECUTEINFO), /* structure size */ 00134 SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI, /* tell us the process 00135 * handle so we can wait till it's done | 00136 * do not display msg box if error 00137 */ 00138 NULL, /* window handle */ 00139 NULL, /* action to perform: open */ 00140 command, /* file to execute */ 00141 args, /* argument list */ 00142 NULL, /* use current working dir */ 00143 SW_HIDE, /* minimize on start-up */ 00144 0, /* application instance handle */ 00145 NULL, /* ignored: id list */ 00146 NULL, /* ignored: class name */ 00147 NULL, /* ignored: key class */ 00148 0, /* ignored: hot key */ 00149 NULL, /* ignored: icon */ 00150 NULL /* resulting application handle */ 00151 }; 00152 if (!ShellExecuteEx(&sInfo)) 00153 { 00154 return -1; 00155 } 00156 else if (sInfo.hProcess) /* executable was launched, wait for it to finish */ 00157 { 00158 WaitForSingleObject(sInfo.hProcess,INFINITE); 00159 CloseHandle(sInfo.hProcess); 00160 } 00161 } 00162 sysElapsedTime+=((double)time.elapsed())/1000.0; 00163 return 0; 00164 #endif 00165 00166 } 00167 00168 uint portable_pid() 00169 { 00170 uint pid; 00171 #if !defined(_WIN32) || defined(__CYGWIN__) 00172 pid = (uint)getpid(); 00173 #else 00174 pid = (uint)GetCurrentProcessId(); 00175 #endif 00176 return pid; 00177 } 00178 00179 static char **last_environ; 00180 00181 void portable_setenv(const char *name,const char *value) 00182 { 00183 #ifdef _WIN32 00184 SetEnvironmentVariable(name,value); 00185 #else 00186 register char **ep = 0; 00187 register size_t size; 00188 const size_t namelen=strlen(name); 00189 const size_t vallen=strlen(value) + 1; 00190 00191 size = 0; 00192 if (environ!=0) 00193 { 00194 for (ep = environ; *ep; ++ep) 00195 { 00196 if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') 00197 break; 00198 else 00199 ++size; 00200 } 00201 } 00202 00203 if (environ==0 || *ep==0) /* add new string */ 00204 { 00205 char **new_environ; 00206 if (environ == last_environ && environ!=0) 00207 { 00208 // We allocated this space; we can extend it. 00209 new_environ = (char **) realloc (last_environ, (size + 2) * sizeof (char *)); 00210 } 00211 else 00212 { 00213 new_environ = (char **) malloc ((size + 2) * sizeof (char *)); 00214 } 00215 00216 if (new_environ==0) // no more memory 00217 { 00218 return; 00219 } 00220 00221 new_environ[size] = (char *)malloc (namelen + 1 + vallen); 00222 if (new_environ[size]==0) 00223 { 00224 free (new_environ); 00225 return; 00226 } 00227 00228 if (environ != last_environ) 00229 { 00230 memcpy ((char *) new_environ, environ, size * sizeof (char *)); 00231 } 00232 00233 memcpy(new_environ[size], name, namelen); 00234 new_environ[size][namelen] = '='; 00235 memcpy(&new_environ[size][namelen + 1], value, vallen); 00236 new_environ[size + 1] = 0; 00237 last_environ = environ = new_environ; 00238 } 00239 else /* replace existing string */ 00240 { 00241 size_t len = strlen (*ep); 00242 if (len + 1 < namelen + 1 + vallen) 00243 { 00244 /* The existing string is too short; malloc a new one. */ 00245 char *newString = (char *)malloc(namelen + 1 + vallen); 00246 if (newString==0) 00247 { 00248 return; 00249 } 00250 *ep = newString; 00251 } 00252 memcpy(*ep, name, namelen); 00253 (*ep)[namelen] = '='; 00254 memcpy(&(*ep)[namelen + 1], value, vallen); 00255 } 00256 00257 #endif 00258 } 00259 00260 void portable_unsetenv(const char *variable) 00261 { 00262 #ifdef _WIN32 00263 SetEnvironmentVariable(variable,0); 00264 #else 00265 /* Some systems don't have unsetenv(), so we do it ourselves */ 00266 size_t len; 00267 char **ep; 00268 00269 if (variable == NULL || *variable == '\0' || strchr (variable, '=') != NULL) 00270 { 00271 return; // not properly formatted 00272 } 00273 00274 len = strlen(variable); 00275 00276 ep = environ; 00277 while (*ep != NULL) 00278 { 00279 if (!strncmp(*ep, variable, len) && (*ep)[len]=='=') 00280 { 00281 /* Found it. Remove this pointer by moving later ones back. */ 00282 char **dp = ep; 00283 do dp[0] = dp[1]; while (*dp++); 00284 /* Continue the loop in case NAME appears again. */ 00285 } 00286 else 00287 { 00288 ++ep; 00289 } 00290 } 00291 #endif 00292 } 00293 00294 const char *portable_getenv(const char *variable) 00295 { 00296 return getenv(variable); 00297 } 00298 00299 portable_off_t portable_fseek(FILE *f,portable_off_t offset, int whence) 00300 { 00301 #if defined(_WIN32) && !defined(__CYGWIN__) 00302 return _fseeki64(f,offset,whence); 00303 #else 00304 return fseeko(f,offset,whence); 00305 #endif 00306 } 00307 00308 portable_off_t portable_ftell(FILE *f) 00309 { 00310 #if defined(_WIN32) && !defined(__CYGWIN__) 00311 return _ftelli64(f); 00312 #else 00313 return ftello(f); 00314 #endif 00315 } 00316 00317 char portable_pathSeparator() 00318 { 00319 #if defined(_WIN32) && !defined(__CYGWIN__) 00320 return '\\'; 00321 #else 00322 return '/'; 00323 #endif 00324 } 00325 00326 char portable_pathListSeparator() 00327 { 00328 #if defined(_WIN32) && !defined(__CYGWIN__) 00329 return ';'; 00330 #else 00331 return ':'; 00332 #endif 00333 } 00334 00335 const char *portable_ghostScriptCommand() 00336 { 00337 #if defined(_WIN32) && !defined(__CYGWIN__) 00338 return "gswin32c.exe"; 00339 #else 00340 return "gs"; 00341 #endif 00342 } 00343 00344 const char *portable_commandExtension() 00345 { 00346 #if defined(_WIN32) && !defined(__CYGWIN__) 00347 return ".exe"; 00348 #else 00349 return ""; 00350 #endif 00351 } 00352 00353 bool portable_fileSystemIsCaseSensitive() 00354 { 00355 #if defined(_WIN32) || defined(macintosh) || defined(__MACOSX__) || defined(__APPLE__) 00356 return FALSE; 00357 #else 00358 return TRUE; 00359 #endif 00360 } 00361 00362 FILE * portable_popen(const char *name,const char *type) 00363 { 00364 return popen(name,type); 00365 } 00366 00367 int portable_pclose(FILE *stream) 00368 { 00369 return pclose(stream); 00370 } 00371 00372 void * portable_iconv_open(const char* tocode, const char* fromcode) 00373 { 00374 return iconv_open(tocode,fromcode); 00375 } 00376 00377 size_t portable_iconv (void *cd, const char** inbuf, size_t *inbytesleft, 00378 char** outbuf, size_t *outbytesleft) 00379 { 00380 // libiconv is a mess. For some platforms/version the prototype of inbuf is 00381 // "const char **", for others it is "char **". C++ requires the proper cast to 00382 // avoid a compile error, that is were the CASTNEEDED is for. 00383 #if ((defined(_LIBICONV_VERSION) && (_LIBICONV_VERSION>=0x0109) && \ 00384 !((defined(_OS_MAC_) || defined(Q_OS_MACX) )&& (_LIBICONV_VERSION==0x010B))) \ 00385 || defined(_OS_SOLARIS_)) 00386 #define CASTNEEDED(x) (x) 00387 #else 00388 #define CASTNEEDED(x) (char **)(x) 00389 #endif 00390 return iconv((iconv_t)cd,CASTNEEDED(inbuf),inbytesleft,outbuf,outbytesleft); 00391 } 00392 00393 int portable_iconv_close (void *cd) 00394 { 00395 return iconv_close((iconv_t)cd); 00396 } 00397