Files
LNXSDK/Kha/Backends/Kinc-HL/hl/src/std/process.c
2025-01-22 16:18:30 +01:00

307 lines
7.9 KiB
C

/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#if defined(HL_CONSOLE)
# include <posix/posix.h>
#elif !defined(HL_WIN)
# include <sys/types.h>
# include <unistd.h>
# include <errno.h>
# include <signal.h>
# if !defined(HL_MAC)
# if defined(HL_BSD) || defined (HL_IOS) || defined (HL_TVOS)
# include <sys/wait.h>
# else
# include <wait.h>
# endif
# endif
#endif
#include <stdio.h>
#include <stdlib.h>
typedef struct _vprocess vprocess;
struct _vprocess {
void (*finalize)( vprocess * );
#ifdef HL_WIN
HANDLE oread;
HANDLE eread;
HANDLE iwrite;
PROCESS_INFORMATION pinf;
#else
int oread;
int eread;
int iwrite;
int pid;
#endif
};
static void process_finalize( vprocess *p ) {
# ifdef HL_WIN
CloseHandle(p->eread);
CloseHandle(p->oread);
CloseHandle(p->iwrite);
CloseHandle(p->pinf.hProcess);
CloseHandle(p->pinf.hThread);
# else
close(p->eread);
close(p->oread);
close(p->iwrite);
# endif
}
HL_PRIM vprocess *hl_process_run( vbyte *cmd, varray *vargs, bool detached ) {
vprocess *p;
# ifdef HL_WIN
SECURITY_ATTRIBUTES sattr;
STARTUPINFO sinf;
HANDLE proc = GetCurrentProcess();
HANDLE oread,eread,iwrite;
if( vargs )
return NULL; // should have been pre-processed by toplevel
p = (vprocess*)hl_gc_alloc_finalizer(sizeof(vprocess));
p->finalize = process_finalize;
// startup process
sattr.nLength = sizeof(sattr);
sattr.bInheritHandle = detached ? FALSE : TRUE;
sattr.lpSecurityDescriptor = NULL;
memset(&sinf,0,sizeof(sinf));
sinf.cb = sizeof(sinf);
sinf.dwFlags = detached ? 0 : STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
sinf.wShowWindow = SW_HIDE;
if( !detached ) {
CreatePipe(&oread,&sinf.hStdOutput,&sattr,0);
CreatePipe(&eread,&sinf.hStdError,&sattr,0);
CreatePipe(&sinf.hStdInput,&iwrite,&sattr,0);
DuplicateHandle(proc,oread,proc,&p->oread,0,FALSE,DUPLICATE_SAME_ACCESS);
DuplicateHandle(proc,eread,proc,&p->eread,0,FALSE,DUPLICATE_SAME_ACCESS);
DuplicateHandle(proc,iwrite,proc,&p->iwrite,0,FALSE,DUPLICATE_SAME_ACCESS);
CloseHandle(oread);
CloseHandle(eread);
CloseHandle(iwrite);
} else {
p->oread = NULL;
p->eread = NULL;
p->iwrite = NULL;
}
if( !CreateProcess(NULL,(uchar*)cmd,NULL,NULL,detached?FALSE:TRUE,detached?CREATE_NEW_CONSOLE:0,NULL,NULL,&sinf,&p->pinf) ) {
// handles will be finalized
return NULL;
}
// close unused pipes
if( !detached ) {
CloseHandle(sinf.hStdOutput);
CloseHandle(sinf.hStdError);
CloseHandle(sinf.hStdInput);
}
# else
char **argv;
if( !vargs ) {
argv = (char**)malloc(sizeof(char*)*4);
argv[0] = "/bin/sh";
argv[1] = "-c";
argv[2] = (char*)cmd;
argv[3] = NULL;
} else {
int i;
if( vargs->at->kind != HBYTES )
return NULL;
argv = (char**)malloc(sizeof(char*)*(vargs->size+2));
argv[0] = (char*)cmd;
for(i=0;i<vargs->size;i++)
argv[i+1] = hl_aptr(vargs,char*)[i];
argv[i+1] = NULL;
}
int input[2], output[2], error[2];
if( pipe(input) || pipe(output) || pipe(error) )
return NULL;
p = (vprocess*)hl_gc_alloc_finalizer(sizeof(vprocess));
#ifdef HL_TVOS
hl_error("hl_process_run() not available for this platform");
p->pid = -1;
#else
p->pid = fork();
#endif
if( p->pid == -1 ) {
close(input[0]);
close(input[1]);
close(output[0]);
close(output[1]);
close(error[0]);
close(error[1]);
return NULL;
}
// child
if( p->pid == 0 ) {
close(input[1]);
close(output[0]);
close(error[0]);
dup2(input[0],0);
dup2(output[1],1);
dup2(error[1],2);
#ifdef HL_TVOS
hl_error("hl_process_run() not available for this platform");
#else
execvp(argv[0],argv);
#endif
fprintf(stderr,"Command not found : %s\n",cmd);
exit(1);
}
// parent
close(input[0]);
close(output[1]);
close(error[1]);
p->iwrite = input[1];
p->oread = output[0];
p->eread = error[0];
# endif
p->finalize = process_finalize;
return p;
}
HL_PRIM int hl_process_stdout_read( vprocess *p, vbyte *str, int pos, int len ) {
# ifdef HL_WIN
DWORD nbytes;
if( !ReadFile(p->oread,str+pos,len,&nbytes,NULL) )
return -1;
return nbytes;
# else
int nbytes = read(p->oread,str+pos,len);
if( nbytes <= 0 )
return -1;
return nbytes;
# endif
}
HL_PRIM int hl_process_stderr_read( vprocess *p, vbyte *str, int pos, int len ) {
# ifdef HL_WIN
DWORD nbytes;
if( !ReadFile(p->eread,str+pos,len,&nbytes,NULL) )
return -1;
return nbytes;
# else
int nbytes = read(p->eread,str+pos,len);
if( nbytes <= 0 )
return -1;
return nbytes;
# endif
}
HL_PRIM int hl_process_stdin_write( vprocess *p, vbyte *str, int pos, int len ) {
# ifdef HL_WIN
DWORD nbytes;
if( !WriteFile(p->iwrite,str+pos,len,&nbytes,NULL) )
return -1;
return nbytes;
# else
int nbytes = write(p->iwrite,str+pos,len);
if( nbytes < 0 )
return -1;
return nbytes;
# endif
}
HL_PRIM bool hl_process_stdin_close( vprocess *p ) {
# ifdef HL_WIN
if( !CloseHandle(p->iwrite) )
return false;
# else
if( close(p->iwrite) )
return false;
p->iwrite = -1;
# endif
return true;
}
HL_PRIM int hl_process_exit( vprocess *p, bool *running ) {
# ifdef HL_WIN
DWORD rval;
if( !running )
WaitForSingleObject(p->pinf.hProcess,INFINITE);
if( !GetExitCodeProcess(p->pinf.hProcess,&rval) )
return -1;
if( running ) {
*running = rval == STILL_ACTIVE;
if( *running ) rval = 0;
}
return rval;
# else
int rval = 0;
int wret = waitpid(p->pid,&rval,running ? WNOHANG : 0);
if( running ) *running = false;
if( wret != p->pid ) {
if( running ) {
if( wret == 0 )
*running = true;
return 0;
} else
return -1;
}
if( !WIFEXITED(rval) ) {
if( WIFSIGNALED(rval) )
return 0x40000000 | WTERMSIG(rval);
return -2;
}
return WEXITSTATUS(rval);
# endif
}
HL_PRIM int hl_process_pid( vprocess *p ) {
# ifdef HL_WIN
return p->pinf.dwProcessId;
# else
return p->pid;
# endif
}
HL_PRIM void hl_process_close( vprocess *p ) {
if( !p->finalize ) return;
p->finalize = NULL;
process_finalize(p);
}
HL_PRIM void hl_process_kill( vprocess *p ) {
# ifdef HL_WIN
TerminateProcess(p->pinf.hProcess,0xCDCDCDCD);
# elif defined(HL_IOS) || defined(HL_TVOS)
hl_error("hl_process_kill() not available on this platform");
# else
kill(p->pid,9);
# endif
}
#define _PROCESS _ABSTRACT(hl_process)
DEFINE_PRIM( _PROCESS, process_run, _BYTES _ARR _BOOL);
DEFINE_PRIM( _I32, process_stdout_read, _PROCESS _BYTES _I32 _I32);
DEFINE_PRIM( _I32, process_stderr_read, _PROCESS _BYTES _I32 _I32);
DEFINE_PRIM( _BOOL, process_stdin_close, _PROCESS);
DEFINE_PRIM( _I32, process_stdin_write, _PROCESS _BYTES _I32 _I32);
DEFINE_PRIM( _I32, process_exit, _PROCESS _REF(_BOOL));
DEFINE_PRIM( _I32, process_pid, _PROCESS);
DEFINE_PRIM( _VOID, process_close, _PROCESS);
DEFINE_PRIM( _VOID, process_kill, _PROCESS);
/* ************************************************************************ */