DO NOT REPLY TO THIS MESSAGE. INSTEAD, POST ANY RESPONSES TO THE LINK BELOW.
[STR New]
Link: http://www.fltk.org/str.php?L2107
Version: 1.1.9
Link: http://www.fltk.org/str.php?L2107
Version: 1.1.9
#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include "FL/Fl.H"
#include "FL/Fl_Window.H"
#include "FL/Fl_Box.H"
#include <FL/Fl_Return_Button.H>
#include <FL/Fl_Multiline_Output.H>
#include <FL/Fl_Scrollbar.H>
#include <FL/fl_ask.H>
extern "C" {int trim_key(char *name);} /* remove trailing spaces */
enum {running, completed, aborted, closed};
struct listener_data {
int status;
Fl_Multiline_Output *o;
#ifdef WIN32
HANDLE pid;
#else
pid_t pid;
#endif
Fl_Button *ok, *interrupt;
Fl_Scrollbar *bar;
int c, l, nl;
int view_nl;
};
static void inter_callback(Fl_Widget *o, void *p)
{
struct listener_data *data = (struct listener_data *)p;
data->status = aborted;
#ifdef WIN32
TerminateProcess(data->pid, 0);
Sleep(500 /*msec*/); //some delay seems necessary between
TerminateProcess and deletion of open files
#else
kill(data->pid, SIGKILL);
#endif
}
static void ok_callback(Fl_Widget *o, void *p)
{
struct listener_data *data = (struct listener_data *)p;
data->status = closed;
}
static void bar_callback(Fl_Widget *wgt, void *data)
{
Fl_Multiline_Output *o = (Fl_Multiline_Output *)data;
int first_line = ((Fl_Scrollbar *)wgt)->value();
const char *p = o->value();
do {
if(*p == '\n') first_line--;
p++;
}
while(*p != 0 && first_line > 0);
o->position(p - o->value());
o->redraw();
}
void ext_prog_listener(int fd, void *ptr)
{//transmits data from fd to fltk viewer with correct handling of \r
char line[300], *p;
struct listener_data *data = (struct listener_data *)ptr;
Fl_Multiline_Output *o = data->o;
int l = read(fd, line, sizeof(line));
if(l > 0) {
do {
p = line;
while(p < line + l && *p != '\r' && *p != '\n') p++;
int l2 = p - line;
if( l2 > 0) {
o->replace(data->c, data->c + l2, line, l2);
data->c += l2;
if(data->c > data->l) data->l = data->c;
l -= l2;
}
else if(*line == '\r') {
int eol = data->l;
do eol--; while(eol > 0 && o->index(eol) !=
'\n');
data->c = eol + 1;
p = line + 1;
l--;
}
else if(*line == '\n') {
(data->nl)++;
o->replace(data->l, data->l, line, 1);
(data->l)++;
data->c = data->l;
p = line + 1;
l--;
}
if(l>0) memmove(line, p, l);
}
while(l>0);
data->bar->value(data->nl, data->view_nl, 0, data->nl);
}
else {
if(!data->ok->active()) {
data->ok->activate();
data->interrupt->label("Cancel");
data->status = completed;
}
}
}
Fl_Window *create_and_run_pseudoterminal(const char *label, struct
listener_data *data,
#ifdef WIN32
HANDLE pipe, HANDLE pid
#else
int masterfd, pid_t pid
#endif
)
{
static char message[100];
Fl_Window *w = new Fl_Window(700, 600);
w->xclass("Terminal");
w->label(label);
w->callback(inter_callback, data);
Fl_Multiline_Output *o = new Fl_Multiline_Output(0, 3, w->w() - 15,
w->h() - 40);
o->textfont(FL_COURIER);
o->textsize(12);
o->maximum_size(5000000);
data->bar = new Fl_Scrollbar(o->x() + o->w(), o->y(), 15, o->h());
data->bar->callback(bar_callback, o);
data->view_nl = o->h() / o->textsize();
data->bar->value(0, data->view_nl, 0, data->view_nl);
sprintf(message, "Wait for %s completion", label);
Fl_Box *w_message = new Fl_Box(0, o->y() + o->h() + 3, w->w(), 20,
message);
data->status = running;
data->o = o;
data->pid = pid;
data->c = data->l = data->nl = 0;
#ifndef WIN32
Fl::add_fd(masterfd, FL_READ, ext_prog_listener, data);
#else
//add_fd does not work well under WIN32: Fl::wait() blocks in read(fd
when nothing comes in the pipe
//so an equivalent is done outside from Fl::wait()
int masterfd = _open_osfhandle((long)pipe, _O_RDONLY);
#endif
Fl_Button *interrupt = new Fl_Button(5, w->h() - 35, 70, 30,
"Interrupt");
interrupt->callback(inter_callback, data);
interrupt->labelfont(FL_HELVETICA_BOLD);
Fl_Return_Button *ok = new Fl_Return_Button(w->w() - 60,
interrupt->y(), 50, 30, "OK");
ok->callback(ok_callback, data);
ok->labelfont(FL_HELVETICA_BOLD);
ok->deactivate();
data->ok = ok;
data->interrupt = interrupt;
w->end();
w->position( (Fl::w() - w->w())/2, (Fl::h() - w->h())/2 );
Fl_Box *r = new Fl_Box(interrupt->x() + interrupt->w(), o->y(), ok->x()
- interrupt->x() - interrupt->w(), o->h());
w->resizable(r);
w->show();
while(data->status == running) {
#ifdef WIN32
DWORD avail = 0;
PeekNamedPipe(pipe, NULL,0,NULL, &avail, NULL);//is there data
in pipe?
if(avail > 0) ext_prog_listener(masterfd, data);//read data
from pipe
if( WaitForSingleObject(pid, 0) == WAIT_OBJECT_0) {//is pid
dead?
//complete reading from pipe and detect closed pipe
while(data->status == running)
ext_prog_listener(masterfd, data);
}
Fl::wait(0.1);//process any interface event, especially
interrupt requests
#else
Fl::wait();
#endif
}
sprintf(message, "%s completed", label);
w_message->label(message);
w_message->labelfont(FL_HELVETICA_BOLD);
w_message->redraw();
#ifdef WIN32
_close(masterfd);
#endif
return w;
}
int run_external_prog_in_pseudoterm(char *cmd, const char *dialogfname, const
char *label)
/*
cmd can be:
prog arg1 arg2 ...
or:
prog arg1 arg2 ... > outfile
and:
prog can also use file named in dialogfname as stdin (NULL if no such file)
label: short name of operation that is run
returns 0 iff cmd completed correctly
*/
{
struct listener_data data;
Fl_Window *w;
#ifdef WIN32
HANDLE ChildInput, ChildStdoutRd, ChildStdoutWr, stdouthandle = NULL;
SECURITY_ATTRIBUTES saAttr;
PROCESS_INFORMATION pi;
STARTUPINFO si;
char *p;
if(dialogfname != NULL) {
FILE *in = fopen(dialogfname, "r");
if(in == NULL) return 1;
ChildInput = (HANDLE)_get_osfhandle(fileno(in));
}
p = cmd;//is there stdout redirection in cmd ?
if(*p == '"') p = strchr(p+1, '"') + 1;
p = strchr(p, '>');
if(p != NULL) {
*p = 0;
p++;
while(*p == ' ') p++;
char *stdoutfname = strdup(p);
FILE *out = fopen(stdoutfname, "w");
free(stdoutfname);
if(out != NULL) stdouthandle =
(HANDLE)_get_osfhandle(fileno(out));
}
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
CreatePipe(&ChildStdoutRd, &ChildStdoutWr, &saAttr, 0/*suggested buffer
size*/);
int tmp = _open_osfhandle((long)ChildStdoutWr, _O_APPEND);
if(tmp != -1) {
write(tmp, "Running ", 8);
write(tmp, cmd, strlen(cmd));
write(tmp, "\n ", 1);
}
SetHandleInformation(ChildStdoutRd, HANDLE_FLAG_INHERIT, 0);
ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &si, sizeof(STARTUPINFO) );
si.cb = sizeof(STARTUPINFO);
si.hStdError = ChildStdoutWr;
si.hStdOutput = stdouthandle ? stdouthandle : ChildStdoutWr;
if(dialogfname != NULL) si.hStdInput = ChildInput;
si.dwFlags |= STARTF_USESTDHANDLES;
int retval = CreateProcess(NULL, cmd, 0,0,TRUE,CREATE_NO_WINDOW,0,0,
&si, &pi);
CloseHandle(ChildStdoutWr);
if(stdouthandle != NULL) CloseHandle(stdouthandle);
if(dialogfname != NULL) CloseHandle(ChildInput);
if(retval == 0) {
CloseHandle(ChildStdoutRd);
return 1;
}
CloseHandle(pi.hThread);
w = create_and_run_pseudoterminal(label, &data, ChildStdoutRd,
pi.hProcess);
CloseHandle(pi.hProcess);
#else
//creates a pseudoterminal
int masterfd = posix_openpt(O_RDWR|O_NOCTTY);
grantpt(masterfd);
unlockpt(masterfd);
char *slavename=ptsname(masterfd);
if(masterfd == -1 || slavename == NULL) return 1;
pid_t pid = fork();
if(pid == -1) return 1;
else if(pid > 0) {// the parent
w = create_and_run_pseudoterminal(label, &data, masterfd, pid);
}
else {//the child
if(dialogfname != NULL) {//case of use of dialog file
freopen(dialogfname, "r", stdin);
}
//decode progname
char *p, *q, *progpath, **argv;
int stderronly = 0, argc;
close(masterfd);
p = cmd;
while(*p == ' ') p++;
if(*p == '"') q = strchr(++p, '"');
else {
q = strchr(p, ' ');
if(q == NULL) q = p + strlen(p);
}
progpath = new char[q-p+1];
memcpy(progpath, p, q-p); progpath[q-p] = 0;
//goto end of progname
p = q;
if(*p == '"') p++;
if((q = strchr(p, '>')) != NULL) {//open desired stdout file
char stdoutfile[150];
*q = 0;
do q++; while(*q == ' ');
strcpy(stdoutfile, q);
trim_key(stdoutfile);
freopen(stdoutfile, "w", stdout);
stderronly = 1;
}
//count args
argc = 1;
q = p - 1;
while (*q != 0) {
q++;
if(*q == ' ') {
argc++;
do q++; while (*q == ' ');
}
}
if(*(q-1)==' ')argc--;
//put args in argv array
argv = (char **)malloc((argc + 1)*sizeof(char *));
argv[0] = progpath;
argv[argc] = NULL;
if(argc > 1) {
argv[1] = strtok(p, " ");
for(int i = 2; i < argc; i++) argv[i] = strtok(NULL, "
");
}
freopen(slavename, "a", stderr);
if(!stderronly) freopen(slavename, "a", stdout);
int err = execv(progpath, argv);
return err;
}
Fl::remove_fd(masterfd);
close(masterfd);
#endif
while(data.status == completed) Fl::wait();
delete w;
if(dialogfname != NULL) remove(dialogfname);
return data.status == aborted;
}
_______________________________________________
fltk-bugs mailing list
fltk-bugs@easysw.com
http://lists.easysw.com/mailman/listinfo/fltk-bugs