This is w32proc.c in view mode; [Download] [Up]
#include <config.h>
#include <stdio.h>
#include <slang.h>
#include <stdlib.h>
#include "jprocess.h"
#include "buffer.h"
#include "ins.h"
#include "ledit.h"
#include "misc.h"
#include "paste.h"
int Num_Subprocesses;
LONG Has_Subprocess_Input;
CRITICAL_SECTION Critical_Section;
volatile int Child_Status_Changed_Flag;/* if this is non-zero, editor
* should call the appropriate
* function below to call slang
* handlers.
*/
typedef struct
{
int flags; /* This is zero if the process is gone
* and the status is nolonger avail */
#define PROCESS_RUNNING 1
#define PROCESS_STOPPED 2
#define PROCESS_ALIVE 3
#define PROCESS_EXITED 4
#define PROCESS_SIGNALLED 8
int return_status; /* This value depends on the flags */
int status_changed; /* non-zero if status changed. */
HANDLE rd, wd; /* read/write handles */
HANDLE hprocess; /* real process handle */
int output_type;
#define PROCESS_USE_BUFFER 1
#define PROCESS_USE_SLANG 2
#define PROCESS_SAVE_POINT 4
#define PROCESS_AT_POINT 8
Buffer *buffer; /* buffer associated with process */
SLang_Name_Type *slang_fun; /* function to pass output to */
SLuser_Object_Type *umark; /* marks point of last output */
SLang_Name_Type *status_change_fun; /* call this if process status changes
* The function should be declared like
* define fun (pid, flags);
* The flags parameter corresponds to
* the flags field in this struct and
* the pid is NOT the pid of this struct
*/
HANDLE input_event;
unsigned char *input_buf;
int input_bufsize;
} Process_Type;
static Process_Type Processes[MAX_PROCESSES];
static Process_Type *get_process (int fd)
{
Process_Type *p;
if ((fd >= 0) && (fd < MAX_PROCESSES)
&& (p = &Processes[fd], p->flags != 0)) return p;
msg_error ("process does not exist.");
return NULL;
}
static void call_slang_status_change_hook (Process_Type *p)
{
Buffer *cbuf = CBuf;
if ((p->status_change_fun == NULL) || (p->buffer == NULL)) return;
cbuf->locked++;
switch_to_buffer (p->buffer);
SLang_push_integer ((int) (p - Processes));
SLang_push_integer (p->flags);
SLexecute_function (p->status_change_fun);
touch_screen ();
if (CBuf != cbuf) switch_to_buffer (cbuf);
cbuf->locked--;
}
/* This routine is called to clean up after the process has exited.
* After getting the exit status, we call a slang hook and if the
* process is dead, adjust the process arrays to delete the process.
*/
static void get_process_status (Process_Type *p)
{
int i;
/* Call slang to let it know what happened. Do it first before we
* really shut it down to give the hook a chance to query the state of
* it before it returns.
*/
call_slang_status_change_hook (p);
if (p->flags & PROCESS_ALIVE) return;
/* Process is dead. So perform clean up. */
CloseHandle(Input_Events[(int)(p - Processes)]);
CloseHandle(p->rd);
CloseHandle(p->wd);
if (p->input_buf) SLFREE(p->input_buf);
if (p->buffer != NULL) p->buffer->subprocess = 0;
p->flags = 0;
if (p->umark != NULL) jed_free_user_object_mark (p->umark);
/* Adjust the array of read descriptors */
i = 0;
while (i < Num_Subprocesses)
{
if (Input_Events[i] == p->input_event)
{
while (i < Num_Subprocesses - 1)
{
Input_Events[i] = Input_Events[i + 1];
i++;
}
break;
}
i++;
}
Num_Subprocesses--;
}
int jed_close_process (int *fd)
{
Process_Type *p;
if (NULL == (p = get_process (*fd))) return -1;
TerminateProcess(p->hprocess, 0);
if (p->buffer != NULL) p->buffer->subprocess = 0;
/* This next function wraps things up --- no need to. Let handler do it. */
/* get_process_status (p); */
return 0;
}
void jed_kill_process (int fd)
{
/* This function is called when the buffer is going to be destroyed */
Processes[fd].buffer = NULL;
jed_close_process (&fd);
}
void jed_get_child_status (void)
{
Process_Type *p, *pmin;
Child_Status_Changed_Flag--;
pmin = Processes; p = pmin + Num_Subprocesses;
while (p > pmin)
{
p--;
if (p->status_changed)
{
p->status_changed--;
get_process_status (p);
}
}
}
static DWORD thread_func(int fd)
{
char buf[513]; /* last byte for 0 char */
DWORD n;
int bufsize;
Process_Type *p = get_process(fd);
while(ReadFile(p->rd, buf, 512, &n, NULL))
{
EnterCriticalSection(&Critical_Section);
bufsize = p->input_bufsize + n;
p->input_buf = SLREALLOC(p->input_buf, bufsize + 1);
MEMCPY((char *)&(p->input_buf[p->input_bufsize]), buf, n);
p->input_bufsize = bufsize;
SetEvent(Input_Events[fd]);
LeaveCriticalSection(&Critical_Section);
}
p->flags = PROCESS_EXITED;
p->status_changed++;
Child_Status_Changed_Flag++;
return 0;
}
void read_process_input(int fd)
{
Buffer *b = CBuf, *pbuf;
int otype;
Process_Type *p;
if (NULL == (p = get_process (fd))) return;
EnterCriticalSection(&Critical_Section);
otype = p->output_type;
pbuf = p->buffer;
if (pbuf != NULL && (otype != PROCESS_USE_SLANG))
{
switch_to_buffer (pbuf);
pbuf->locked++;
}
if (otype & PROCESS_SAVE_POINT) push_spot ();
if (otype & PROCESS_USE_BUFFER)
{
if (0 == (otype & PROCESS_AT_POINT)) eob ();
ins_chars (p->input_buf, p->input_bufsize);
jed_move_user_object_mark (p->umark);
}
else if (otype == PROCESS_USE_SLANG)
{
p->input_buf[p->input_bufsize] = 0;
SLang_push_string ((char *) p->input_buf);
SLang_push_integer ((int) (p - Processes));
SLexecute_function (p->slang_fun); /* function to pass output to */
}
if (otype & PROCESS_SAVE_POINT)
pop_spot ();
else
if (otype & PROCESS_USE_BUFFER)
move_window_marks (0);
if ((p->buffer != NULL) && (otype != PROCESS_USE_SLANG))
{
if (b != CBuf) switch_to_buffer (b);
pbuf->locked--;
}
SLFREE(p->input_buf);
p->input_buf = NULL;
p->input_bufsize = 0;
ResetEvent(p->input_event);
LeaveCriticalSection(&Critical_Section);
touch_screen ();
}
static int open_process (char *pgm, char **argv)
{
int pd;
HANDLE fds0[2], fds1[2];
Process_Type *p;
char **arg, *cmd_line;
SLuser_Object_Type *uo;
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
DWORD d, id_thread;
pd = 0; while ((pd < MAX_PROCESSES) && Processes[pd].flags) pd++;
if (pd == MAX_PROCESSES) return -1;
p = &Processes[pd];
MEMSET ((char *) p, 0, sizeof (Process_Type));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
if (CreatePipe(&fds0[0], &fds0[1], &sa, 0))
{
if (!CreatePipe(&fds1[0], &fds1[1], &sa, 0))
{
CloseHandle(fds0[0]);
CloseHandle(fds0[1]);
return -1;
}
}
else
return -1;
if (NULL == (uo = jed_make_user_object_mark (SLANG_IVARIABLE))) return -1;
si.cb = sizeof(STARTUPINFO);
si.lpReserved = NULL;
si.lpReserved2 = NULL;
si.cbReserved2 = 0;
si.lpDesktop = NULL;
si.lpTitle = NULL;
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_MINIMIZE;
si.hStdInput = fds0[0];
si.hStdOutput = fds1[1];
si.hStdError = fds1[1];
d = strlen(pgm) + 1;
arg = argv;
while (*arg != NULL)
{
d += strlen(*arg) + 1;
arg++;
}
if (NULL == (cmd_line = SLMALLOC(d))) return -1;
cmd_line[0] = 0;
arg = argv;
while (*arg != NULL)
{
strcat(cmd_line, *arg);
arg++;
}
if (CreateProcess(NULL, cmd_line, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
CloseHandle(fds0[0]);
CloseHandle(fds1[1]);
p->flags = PROCESS_RUNNING;
p->rd = fds1[0];
p->wd = fds0[1];
p->hprocess = pi.hProcess;
Num_Subprocesses += 1;
CBuf->subprocess = pd + 1;
/* Processing options */
p->buffer = CBuf;
p->output_type = PROCESS_USE_BUFFER;
p->umark = uo;
p->input_bufsize = 0;
p->input_buf = NULL;
p->input_event = CreateEvent(NULL, TRUE, FALSE, NULL);
Input_Events[pd] = p->input_event;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_func, (LPVOID) pd, 0, &id_thread);
}
else
{
msg_error("exec failed!\n");
CloseHandle(fds0[0]);
CloseHandle(fds0[1]);
CloseHandle(fds1[0]);
CloseHandle(fds1[1]);
jed_free_user_object_mark (uo);
return -1;
}
return pd;
}
int jed_send_process (int *fd, char *str)
{
DWORD d;
Process_Type *p = get_process (*fd);
if ((p == NULL) || (p->wd == NULL)) return -1;
WriteFile(p->wd, str, strlen(str), &d, NULL);
return 0;
}
void jed_send_process_eof (int *fd)
{
Process_Type *p = get_process (*fd);
if (p == NULL) return;
if (p->rd != NULL) CloseHandle(p->rd);
p->wd = NULL;
}
void jed_set_process (int *pd, char *what, char *s)
{
Process_Type *p;
SLang_Name_Type *f;
if (NULL == (p = get_process (*pd))) return;
if (!strcmp (what, "output"))
{
if (*s == '.') p->output_type = PROCESS_AT_POINT | PROCESS_USE_BUFFER;
else if (*s == '@') p->output_type = PROCESS_SAVE_POINT | PROCESS_USE_BUFFER;
else if (*s && (NULL != (f = SLang_get_function (s))))
{
p->output_type = PROCESS_USE_SLANG;
p->slang_fun = f;
}
else p->output_type = PROCESS_USE_BUFFER;
}
else if (!strcmp (what, "signal"))
{
if (*s && (NULL != (f = SLang_get_function (s))))
{
p->status_change_fun = f;
}
}
}
void jed_get_process_mark (int *fd)
{
Process_Type *p;
if (NULL == (p = get_process (*fd))) return;
SLang_push_user_object (p->umark);
}
int jed_open_process (int *np)
{
int fd = -1;
char *argv[502];
int do_free[502];
int n = *np;
if (CBuf->subprocess)
{
msg_error ("There is already a process attached to this buffer.");
return -1;
}
if ((n > 500) || (n < 0))
{
msg_error ("Arguments out of range.");
return -1;
}
n++; /* for argv0 since *np does not include
* it.
*/
argv[n] = NULL;
while (n--)
{
if (SLang_pop_string (&argv[n], &do_free[n]))
{
n++;
goto free_return;
}
}
n = 0;
if ((fd = open_process(argv[0], argv)) < 0)
{
msg_error ("Unable to open process.");
}
/* free up the argument strings */
free_return:
while (n <= *np)
{
if (do_free[n]) SLFREE (argv[n]);
n++;
}
return fd;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.