diff --git a/harbour/ChangeLog b/harbour/ChangeLog index b240daa4bd..6c65fde497 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,24 @@ past entries belonging to author(s): Viktor Szakats. */ +2009-07-07 00:18 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/source/rtl/gttrm/gttrm.c + ! do not catch SIGCHLD + + * harbour/include/hbapifs.h + * harbour/source/rtl/hbproces.c + + added C function: hb_fsProcessRun() + + * harbour/source/rtl/hbprocfn.c + + added .prg function: + hb_processRun( , [ ], [ @ ], ; + [ @ ], [ ] ) -> + This function is implemented for all builds also in DOS ones where + temporary files are used to simulate pipes. + TODO: in OS2 builds it should be possible to implement this function + without temporary files just like in *nixes and MS-Windows builds. + I would like to ask OS2 users to make it. + 2009-07-06 14:05 UTC+0200 Viktor Szakats (harbour.01 syenar.hu) * bin/postinst.bat + Added .hbc search paths: /contrib, /contrib/rddsql, /addins, /examples. diff --git a/harbour/include/hbapifs.h b/harbour/include/hbapifs.h index 22e1d48a8d..7eb49cd529 100644 --- a/harbour/include/hbapifs.h +++ b/harbour/include/hbapifs.h @@ -293,12 +293,17 @@ extern HB_EXPORT BOOL hb_fsFindNext( PHB_FFIND ffind ); extern HB_EXPORT void hb_fsFindClose( PHB_FFIND ffind ); /* functions to create, wait and terminate processes */ -HB_FHANDLE hb_fsProcessOpen( const char *pszFilename, - HB_FHANDLE *phStdin, HB_FHANDLE *phStdout, - HB_FHANDLE *phStderr, - BOOL fDetach, ULONG *pulPID ); -int hb_fsProcessValue( HB_FHANDLE hProcess, BOOL fWait ); -BOOL hb_fsProcessClose( HB_FHANDLE hProcess, BOOL fGentle ); +extern HB_FHANDLE hb_fsProcessOpen( const char *pszFilename, + HB_FHANDLE *phStdin, HB_FHANDLE *phStdout, + HB_FHANDLE *phStderr, + BOOL fDetach, ULONG *pulPID ); +extern int hb_fsProcessRun( const char *pszFilename, + const char * pStdInBuf, ULONG ulStdInLen, + char ** pStdOutPtr, ULONG * pulStdOut, + char ** pStdErrPtr, ULONG * pulStdErr, + BOOL fDetach ); +extern int hb_fsProcessValue( HB_FHANDLE hProcess, BOOL fWait ); +extern BOOL hb_fsProcessClose( HB_FHANDLE hProcess, BOOL fGentle ); /* Misc helper functions */ extern ULONG hb_fsAttrFromRaw( ULONG raw_attr ); diff --git a/harbour/source/rtl/gttrm/gttrm.c b/harbour/source/rtl/gttrm/gttrm.c index 54bf5eb12e..80f378b5bc 100644 --- a/harbour/source/rtl/gttrm/gttrm.c +++ b/harbour/source/rtl/gttrm/gttrm.c @@ -645,7 +645,7 @@ static void set_sig_handler( int iSig ) static void set_signals( void ) { - int i, sigs[] = { SIGINT, SIGQUIT, SIGTSTP, SIGWINCH, SIGCHLD, 0 }; + int i, sigs[] = { SIGINT, SIGQUIT, SIGTSTP, SIGWINCH /*, SIGCHLD */, 0 }; /* Ignore SIGPIPEs so they don't kill us. */ signal( SIGPIPE, SIG_IGN ); diff --git a/harbour/source/rtl/hbproces.c b/harbour/source/rtl/hbproces.c index 0351b4876a..7663ff5328 100644 --- a/harbour/source/rtl/hbproces.c +++ b/harbour/source/rtl/hbproces.c @@ -75,9 +75,18 @@ # if defined( HB_OS_OS2 ) # include # endif +#elif defined( HB_OS_DOS ) +# include +# include +# if defined( __DJGPP__ ) +# include +# include +# else +# include +# endif #endif -#if defined( HB_OS_OS2 ) || defined( HB_OS_UNIX ) || \ +#if defined( HB_OS_DOS ) || defined( HB_OS_OS2 ) || defined( HB_OS_UNIX ) || \ ( defined( HB_OS_WIN ) && !defined( HB_IO_WIN ) ) /* convert command to argument list using standard bourne shell encoding: @@ -182,6 +191,165 @@ static void hb_freeArgs( char ** argv ) #endif +#if defined( HB_OS_DOS ) || defined( HB_OS_OS2 ) /* || defined( HB_OS_WIN_CE ) */ +static int hb_fsProcessExec( const char *pszFilename, + HB_FHANDLE hStdin, HB_FHANDLE hStdout, + HB_FHANDLE hStderr ) +{ + int iResult = FS_ERROR; + + HB_TRACE(HB_TR_DEBUG, ("hb_fsProcessExec(%s, %p, %p, %p, %d, %p)", pszFilename, ( void * ) ( HB_PTRDIFF ) hStdin, ( void * ) ( HB_PTRDIFF ) hStdout, ( void * ) ( HB_PTRDIFF ) hStderr)); + +#if defined( HB_IO_WIN ) + + PROCESS_INFORMATION pi; + STARTUPINFO si; + DWORD dwFlags = 0; +#if defined(UNICODE) + LPWSTR lpCommand = hb_mbtowc( pszFilename ); +#else + char * lpCommand = hb_strdup( pszFilename ); +#endif + BOOL fError; + + memset( &pi, 0, sizeof( pi ) ); + memset( &si, 0, sizeof( si ) ); + si.cb = sizeof( si ); + si.hStdInput = hStdin == FS_ERROR ? GetStdHandle( STD_INPUT_HANDLE ) : hStdin; + si.hStdOutput = hStdout == FS_ERROR ? GetStdHandle( STD_OUTPUT_HANDLE ) : hStdout; + si.hStdError = hStderr == FS_ERROR ? GetStdHandle( STD_ERROR_HANDLE ) : hStderr; +#ifdef STARTF_USESTDHANDLES + si.dwFlags = STARTF_USESTDHANDLES; +#endif + hb_vmUnlock(); + fError = ! CreateProcess( NULL, /* lpAppName */ + lpCommand, + NULL, /* lpProcessAttr */ + NULL, /* lpThreadAttr */ + TRUE, /* bInheritHandles */ + dwFlags, /* dwCreationFlags */ + NULL, /* lpEnvironment */ + NULL, /* lpCurrentDirectory */ + &si, + &pi ); + hb_fsSetIOError( !fError, 0 ); + if( !fError ) + { + CloseHandle( pi.hThread ); + if( WaitForSingleObject( pi.hProcess, INFINITE ) == WAIT_OBJECT_0 ) + { + DWORD dwResult = 0; + fError = !GetExitCodeProcess( pi.hProcess, &dwResult ); + iResult = !fError ? ( int ) dwResult : -2; + } + hb_fsSetIOError( !fError, 0 ); + CloseHandle( pi.hProcess ); + } + hb_vmLock(); + hb_xfree( lpCommand ); + +#elif defined( HB_OS_DOS ) || defined( HB_OS_WIN ) || defined( HB_OS_OS2 ) || \ + defined( HB_OS_UNIX ) + + int iStdIn, iStdOut, iStdErr; + char ** argv; + + argv = hb_buildArgs( pszFilename ); + + hb_vmUnlock(); + + iStdIn = iStdOut = iStdErr = FS_ERROR; + + if( hStdin != FS_ERROR ) + { + iStdIn = dup( 0 ); + dup2( hStdin, 0 ); + } + if( hStdout != FS_ERROR ) + { + iStdOut = dup( 1 ); + dup2( hStdout, 1 ); + } + if( hStderr != FS_ERROR ) + { + iStdErr = dup( 2 ); + dup2( hStderr, 2 ); + } +#if defined( HB_OS_UNIX ) + { + pid_t pid = fork(); + if( pid == 0 ) + { + /* close all non std* handles */ + { + int iMaxFD, i; + iMaxFD = sysconf( _SC_OPEN_MAX ); + if( iMaxFD < 3 ) + iMaxFD = 1024; + for( i = 3; i < iMaxFD; ++i ) + close( i ); + } + /* reset extended process attributes */ + setuid( getuid() ); + setgid( getgid() ); + + /* execute command */ + execvp( argv[ 0 ], argv ); + exit(1); + } + else if( pid != -1 ) + { + int iStatus; + iResult = waitpid( pid, &iStatus, 0 ); +#ifdef ERESTARTSYS + if( iResult < 0 && errno != ERESTARTSYS ) +#else + if( iResult < 0 ) +#endif + iResult = -2; + else if( iResult == 0 ) + iResult = -1; + else + iResult = WIFEXITED( iStatus ) ? WEXITSTATUS( iStatus ) : 0; + } + } +#elif defined( _MSC_VER ) || defined( __LCC__ ) || \ + defined( __XCC__ ) || defined( __POCC__ ) + iResult = _spawnvp( _P_WAIT, argv[ 0 ], argv ); +#elif defined( __MINGW32__ ) + iResult = spawnvp( P_WAIT, argv[ 0 ], ( const char * const * ) argv ); +#else + iResult = spawnvp( P_WAIT, argv[ 0 ], ( char * const * ) argv ); +#endif + hb_fsSetIOError( iResult >= 0, 0 ); + + if( iStdIn != FS_ERROR ) + dup2( iStdIn, 0 ); + if( iStdOut != FS_ERROR ) + dup2( iStdOut, 1 ); + if( iStdErr != FS_ERROR ) + dup2( iStdErr, 2 ); + + hb_vmLock(); + hb_freeArgs( argv ); + +#else +{ + int TODO; /* TODO: for given platform */ + + HB_SYMBOL_UNUSED( pszFilename ); + HB_SYMBOL_UNUSED( hStdin ); + HB_SYMBOL_UNUSED( hStdout ); + HB_SYMBOL_UNUSED( hStderr ); + + hb_fsSetError( ( USHORT ) FS_ERROR ); +} +#endif + + return iResult; +} +#endif + HB_FHANDLE hb_fsProcessOpen( const char *pszFilename, HB_FHANDLE *phStdin, HB_FHANDLE *phStdout, HB_FHANDLE *phStderr, @@ -628,7 +796,7 @@ int hb_fsProcessValue( HB_FHANDLE hProcess, BOOL fWait ) iRetStatus = waitpid( pid, &iStatus, fWait ? 0 : WNOHANG ); hb_fsSetIOError( iRetStatus >= 0, 0 ); #ifdef ERESTARTSYS - if( iRetStatus < 0 && errno != ERESTARTSYS) + if( iRetStatus < 0 && errno != ERESTARTSYS ) #else if( iRetStatus < 0 ) #endif @@ -736,6 +904,345 @@ BOOL hb_fsProcessClose( HB_FHANDLE hProcess, BOOL fGentle ) return fResult; } +#define HB_STD_BUFFER_SIZE 4096 + +int hb_fsProcessRun( const char *pszFilename, + const char * pStdInBuf, ULONG ulStdInLen, + char ** pStdOutPtr, ULONG * pulStdOut, + char ** pStdErrPtr, ULONG * pulStdErr, + BOOL fDetach ) +{ + HB_FHANDLE hStdin, hStdout, hStderr, *phStdin, *phStdout, *phStderr; + char * pOutBuf, *pErrBuf; + ULONG ulOutSize, ulErrSize, ulOutBuf, ulErrBuf; + int iResult; + + HB_TRACE(HB_TR_DEBUG, ("hb_fsProcessRun(%s, %p, %lu, %p, %p, %p, %p, %d)", pStdInBuf, ulStdInLen, pStdOutPtr, pulStdOut, pStdErrPtr, pulStdErr, fDetach)); + + ulOutBuf = ulErrBuf = ulOutSize = ulErrSize = 0; + pOutBuf = pErrBuf = NULL; + hStdin = hStdout = hStderr = FS_ERROR; + phStdin = pStdInBuf ? &hStdin : NULL; + phStdout = pStdOutPtr && pulStdOut ? &hStdout : NULL; + phStderr = pStdErrPtr && pulStdErr ? &hStderr : NULL; + +#if defined( HB_OS_DOS ) || defined( HB_OS_OS2 ) /* || defined( HB_OS_WIN_CE ) */ +{ + +#if defined( HB_OS_UNIX ) +# define _HB_NULLHANDLE() open( "/dev/null", O_RDWR ) +#else +# define _HB_NULLHANDLE() open( "NUL:", O_RDWR ) +#endif + char sTmpIn[ HB_PATH_MAX ]; + char sTmpOut[ HB_PATH_MAX ]; + char sTmpErr[ HB_PATH_MAX ]; + + sTmpIn[ 0 ] = sTmpOut[ 0 ] = sTmpErr[ 0 ] = '\0'; + if( pStdInBuf ) + { + hStdin = hb_fsCreateTempEx( sTmpIn, NULL, NULL, NULL, FC_NORMAL ); + if( ulStdInLen ) + { + hb_fsWriteLarge( hStdin, pStdInBuf, ulStdInLen ); + hb_fsSeek( hStdin, 0, FS_SET ); + } + } + else if( fDetach ) + hStdin = _HB_NULLHANDLE(); + + if( pStdOutPtr && pulStdOut ) + hStdout = hb_fsCreateTempEx( sTmpOut, NULL, NULL, NULL, FC_NORMAL ); + else if( fDetach ) + hStdout = _HB_NULLHANDLE(); + + if( pStdErrPtr && pulStdErr ) + hStderr = hb_fsCreateTempEx( sTmpErr, NULL, NULL, NULL, FC_NORMAL ); + else if( fDetach ) + hStderr = _HB_NULLHANDLE(); + + iResult = hb_fsProcessExec( pszFilename, hStdin, hStdout, hStderr ); + + if( hStdin != FS_ERROR ) + { + hb_fsClose( hStdin ); + if( sTmpIn[ 0 ] ) + hb_fsDelete( sTmpIn ); + } + if( hStdout != FS_ERROR ) + { + if( pStdOutPtr && pulStdOut ) + { + ulOutBuf = hb_fsSeek( hStdout, 0, FS_END ); + if( ulOutBuf ) + { + pOutBuf = ( char * ) hb_xgrab( ulOutBuf + 1 ); + hb_fsSeek( hStdout, 0, FS_SET ); + ulOutBuf = hb_fsReadLarge( hStdout, pOutBuf, ulOutBuf ); + } + } + hb_fsClose( hStdout ); + if( sTmpOut[ 0 ] ) + hb_fsDelete( sTmpOut ); + } + if( hStderr != FS_ERROR ) + { + if( pStdErrPtr && pulStdErr ) + { + ulErrBuf = hb_fsSeek( hStderr, 0, FS_END ); + if( ulErrBuf ) + { + pErrBuf = ( char * ) hb_xgrab( ulErrBuf + 1 ); + hb_fsSeek( hStderr, 0, FS_SET ); + ulErrBuf = hb_fsReadLarge( hStderr, pErrBuf, ulErrBuf ); + } + } + hb_fsClose( hStderr ); + if( sTmpErr[ 0 ] ) + hb_fsDelete( sTmpErr ); + } +} + +#else +{ + HB_FHANDLE hProcess; + + iResult = -1; + hProcess = hb_fsProcessOpen( pszFilename, phStdin, phStdout, phStderr, + fDetach, NULL ); + if( hProcess != FS_ERROR ) + { +#if defined( HB_IO_WIN ) + + DWORD dwResult, dwCount; + HANDLE lpHandles[ 4 ]; + ULONG ul; + + if( ulStdInLen == 0 && hStdin != FS_ERROR ) + { + hb_fsClose( hStdin ); + hStdin = FS_ERROR; + } + + for( ;; ) + { + dwCount = 0; + if( ulStdInLen && hStdin != FS_ERROR ) + lpHandles[ dwCount++ ] = ( HANDLE ) hb_fsGetOsHandle( hStdin ); + if( hStdout != FS_ERROR ) + lpHandles[ dwCount++ ] = ( HANDLE ) hb_fsGetOsHandle( hStdout ); + if( hStderr != FS_ERROR ) + lpHandles[ dwCount++ ] = ( HANDLE ) hb_fsGetOsHandle( hStderr ); + + lpHandles[ dwCount++ ] = ( HANDLE ) hb_fsGetOsHandle( hProcess ); + + dwResult = WaitForMultipleObjects( dwCount, lpHandles, FALSE, INFINITE ); + + if( /* dwResult >= WAIT_OBJECT_0 && */ dwResult < WAIT_OBJECT_0 + dwCount ) + { + if( ulStdInLen && hStdin != FS_ERROR && + lpHandles[ dwResult ] == ( HANDLE ) hb_fsGetOsHandle( hStdin ) ) + { + ul = hb_fsWriteLarge( hStdin, pStdInBuf, ulStdInLen ); + pStdInBuf += ul; + ulStdInLen -= ul; + if( ulStdInLen == 0 ) + { + hb_fsClose( hStdin ); + hStdin = FS_ERROR; + } + } + else if( hStdout != FS_ERROR && + lpHandles[ dwResult ] == ( HANDLE ) hb_fsGetOsHandle( hStdout ) ) + { + if( ulOutBuf == ulOutSize ) + { + ulOutSize += HB_STD_BUFFER_SIZE; + pOutBuf = ( char * ) hb_xrealloc( pOutBuf, ulOutSize + 1 ); + } + ul = hb_fsReadLarge( hStdout, pOutBuf + ulOutBuf, ulOutSize - ulOutBuf ); + if( ul == 0 ) + { + hb_fsClose( hStdout ); + hStdout = FS_ERROR; + } + else + ulOutBuf += ul; + } + else if( hStderr != FS_ERROR && lpHandles[ dwResult ] == ( HANDLE ) hb_fsGetOsHandle( hStderr ) ) + { + if( ulErrBuf == ulErrSize ) + { + ulErrSize += HB_STD_BUFFER_SIZE; + pErrBuf = ( char * ) hb_xrealloc( pErrBuf, ulErrSize + 1 ); + } + ul = hb_fsReadLarge( hStderr, pErrBuf + ulErrBuf, ulErrSize - ulErrBuf ); + if( ul == 0 ) + { + hb_fsClose( hStderr ); + hStderr = FS_ERROR; + } + else + ulErrBuf += ul; + } + else if( lpHandles[ dwResult ] == ( HANDLE ) hb_fsGetOsHandle( hProcess ) ) + { + if( GetExitCodeProcess( ( HANDLE ) hb_fsGetOsHandle( hProcess ), &dwResult ) ) + iResult = ( int ) dwResult; + else + iResult = -2; + break; + } + } + else + break; + } + + if( hStdin != FS_ERROR ) + hb_fsClose( hStdin ); + if( hStdout != FS_ERROR ) + hb_fsClose( hStdout ); + if( hStderr != FS_ERROR ) + hb_fsClose( hStderr ); + +#elif defined( HB_OS_UNIX ) + + fd_set rfds, wfds, *prfds, *pwfds; + HB_FHANDLE fdMax; + ULONG ul; + int n; + + if( ulStdInLen == 0 && hStdin != FS_ERROR ) + { + hb_fsClose( hStdin ); + hStdin = FS_ERROR; + } + + for( ;; ) + { + fdMax = 0; + prfds = pwfds = NULL; + if( hStdout != FS_ERROR || hStderr != FS_ERROR ) + { + FD_ZERO( &rfds ); + if( hStdout != FS_ERROR ) + { + FD_SET( hStdout, &rfds ); + if( hStdout > fdMax ) + fdMax = hStdout; + } + if( hStderr != FS_ERROR ) + { + FD_SET( hStderr, &rfds ); + if( hStderr > fdMax ) + fdMax = hStderr; + } + prfds = &rfds; + } + if( ulStdInLen && hStdin != FS_ERROR ) + { + FD_ZERO( &wfds ); + FD_SET( hStdin, &wfds ); + if( hStdin > fdMax ) + fdMax = hStdin; + pwfds = &wfds; + } + if( prfds == NULL && pwfds == NULL ) + break; + + hb_vmUnlock(); + n = select( fdMax + 1, prfds, pwfds, NULL, NULL ); + if( n > 0 ) + { + if( ulStdInLen && hStdin != FS_ERROR && FD_ISSET( hStdin, &wfds ) ) + { + ul = hb_fsWriteLarge( hStdin, pStdInBuf, ulStdInLen ); + pStdInBuf += ul; + ulStdInLen -= ul; + if( ulStdInLen == 0 ) + { + hb_fsClose( hStdin ); + hStdin = FS_ERROR; + } + } + + if( hStdout != FS_ERROR && FD_ISSET( hStdout, &rfds ) ) + { + if( ulOutBuf == ulOutSize ) + { + ulOutSize += HB_STD_BUFFER_SIZE; + pOutBuf = ( char * ) hb_xrealloc( pOutBuf, ulOutSize + 1 ); + } + ul = hb_fsReadLarge( hStdout, pOutBuf + ulOutBuf, ulOutSize - ulOutBuf ); + if( ul == 0 ) + { + /* zero bytes read after positive select() + * - writing process closed the pipe + */ + hb_fsClose( hStdout ); + hStdout = FS_ERROR; + } + else + ulOutBuf += ul; + } + + if( hStderr != FS_ERROR && FD_ISSET( hStderr, &rfds ) ) + { + if( ulErrBuf == ulErrSize ) + { + ulErrSize += HB_STD_BUFFER_SIZE; + pErrBuf = ( char * ) hb_xrealloc( pErrBuf, ulErrSize + 1 ); + } + ul = hb_fsReadLarge( hStderr, pErrBuf + ulErrBuf, ulErrSize - ulErrBuf ); + if( ul == 0 ) + { + /* zero bytes read after positive select() + * - writing process closed the pipe + */ + hb_fsClose( hStderr ); + hStderr = FS_ERROR; + } + else + ulErrBuf += ul; + } + } + hb_vmLock(); + } + + if( hStdin != FS_ERROR ) + hb_fsClose( hStdin ); + if( hStdout != FS_ERROR ) + hb_fsClose( hStdout ); + if( hStderr != FS_ERROR ) + hb_fsClose( hStderr ); + + iResult = hb_fsProcessValue( hProcess, TRUE ); + +#else + + int TODO; + + HB_SYMBOL_UNUSED( ulStdInLen ); + +#endif + } +} +#endif + + if( phStdout ) + { + *pStdOutPtr = pOutBuf; + *pulStdOut = ulOutBuf; + } + if( phStderr ) + { + *pStdErrPtr = pErrBuf; + *pulStdErr = ulErrBuf; + } + + return iResult; +} + /* temporary hack for still missing sysconf() in Watcom 1.8 */ #if defined( HB_OS_LINUX ) && defined( __WATCOMC__ ) _WCRTLINK long sysconf( int __name ) diff --git a/harbour/source/rtl/hbprocfn.c b/harbour/source/rtl/hbprocfn.c index aaa4691a95..4966fd1a77 100644 --- a/harbour/source/rtl/hbprocfn.c +++ b/harbour/source/rtl/hbprocfn.c @@ -117,3 +117,49 @@ HB_FUNC( HB_PROCESSCLOSE ) else hb_errRT_BASE_SubstR( EG_ARG, 4001, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } + +/* hb_processRun( , [ ], [ @ ], [ @ ], ; + [ ] ) -> */ +HB_FUNC( HB_PROCESSRUN ) +{ + const char *szName = hb_parc( 1 ); + const char *szStdIn = hb_parc( 2 ); + PHB_ITEM pStdOut = hb_param( 3, HB_IT_BYREF ); + PHB_ITEM pStdErr = hb_param( 4, HB_IT_BYREF ); + BOOL fDetach = hb_parl( 5 ); + + if( szName && + ( szStdIn || HB_ISNIL( 2 ) ) && + ( pStdOut || HB_ISNIL( 3 ) ) && + ( pStdErr || HB_ISNIL( 4 ) ) && + ( HB_ISLOG( 5 ) || HB_ISNIL( 5 ) ) ) + { + ULONG ulStdOut, ulStdErr; + char * pStdOutBuf, * pStdErrBuf; + char ** pStdOutPtr, ** pStdErrPtr; + int iResult; + + ulStdOut = ulStdErr = 0; + pStdOutBuf = pStdErrBuf = NULL; + pStdOutPtr = pStdOut ? &pStdOutBuf : NULL; + pStdErrPtr = pStdErr ? &pStdErrBuf : NULL; + + iResult = hb_fsProcessRun( szName, szStdIn, hb_parclen( 2 ), + pStdOutPtr, &ulStdOut, pStdErrPtr, &ulStdErr, + fDetach ); + + if( pStdOutBuf ) + hb_storclen_buffer( pStdOutBuf, ulStdOut, 3 ); + else if( pStdOut ) + hb_storclen( "", 0, 3 ); + + if( pStdErrBuf ) + hb_storclen_buffer( pStdErrBuf, ulStdErr, 4 ); + else if( pStdErr ) + hb_storclen( "", 0, 4 ); + + hb_retni( iResult ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 4001, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +}