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

Reply via email to