00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifdef HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028
00029 #include "execbox.h"
00030 #include <iostream>
00031 #include <string>
00032
00033 using std::cout;
00034 using std::endl;
00035
00036 #ifndef WIN32
00037
00038 #ifdef HAVE_SYS_TYPES_H
00039 #include <sys/types.h>
00040 #endif
00041 #include <unistd.h>
00042 #include <signal.h>
00043 #include <sys/wait.h>
00044
00045
00046
00047
00048
00049 Exec_process::Exec_process
00050 (
00051 ) : child_stdin(-1), child_stdout(-1), child_stderr(-1),
00052 child_pid(-1), reader(0),
00053 stdout_tag(-1), stderr_tag(-1)
00054 {
00055 }
00056
00057
00058
00059
00060
00061 Exec_process::~Exec_process
00062 (
00063 )
00064 {
00065 kill_child();
00066 }
00067
00068
00069
00070
00071
00072 void Exec_process::kill_child
00073 (
00074 )
00075 {
00076 if (child_pid > 0)
00077 kill(child_pid, SIGINT);
00078 if (child_stdin >= 0)
00079 close(child_stdin);
00080 if (child_stdout >= 0)
00081 close(child_stdout);
00082 if (child_stderr >= 0)
00083 close(child_stderr);
00084 if (stdout_tag >= 0)
00085 gdk_input_remove(stdout_tag);
00086 if (stderr_tag >= 0)
00087 gdk_input_remove(stderr_tag);
00088 child_pid = child_stdin = child_stdout = child_stderr =
00089 stdout_tag = stderr_tag = -1;
00090 }
00091
00092
00093
00094
00095
00096 static void Read_from_child
00097 (
00098 gpointer data,
00099 gint id,
00100 GdkInputCondition condition
00101 )
00102 {
00103 Exec_process *ex = (Exec_process *) data;
00104 ex->read_from_child(id);
00105 }
00106 void Exec_process::read_from_child
00107 (
00108 int id
00109 )
00110 {
00111 char buf[1024];
00112 int len;
00113 while ((len = read(id, buf, sizeof(buf))) > 0)
00114 if (reader)
00115 (*reader)(buf, len, 0, reader_data);
00116 int exit_code;
00117 if (!check_child(exit_code))
00118 {
00119 kill_child();
00120 if (reader)
00121 (*reader)(0, 0, exit_code, reader_data);
00122 }
00123 }
00124
00125
00126
00127
00128
00129
00130
00131 inline void Close_pipe
00132 (
00133 int p[2]
00134 )
00135 {
00136 if (p[0] >= 0) close(p[0]);
00137 if (p[1] >= 0) close(p[1]);
00138 }
00139
00140
00141
00142
00143
00144 static void Close_pipes
00145 (
00146 int p0[2], int p1[2], int p2[2]
00147 )
00148 {
00149 Close_pipe(p0);
00150 Close_pipe(p1);
00151 Close_pipe(p2);
00152 }
00153
00154
00155
00156
00157
00158
00159
00160 bool Exec_process::exec
00161 (
00162 const char *file,
00163 char *argv[],
00164 Reader_fun rfun,
00165 void *udata
00166 )
00167 {
00168 reader = rfun;
00169 reader_data = udata;
00170
00171 int stdin_pipe[2], stdout_pipe[2], stderr_pipe[2];
00172 stdin_pipe[0] = stdin_pipe[1] = stdout_pipe[0] = stdout_pipe[1] =
00173 stderr_pipe[0] = stderr_pipe[1] = -1;
00174 kill_child();
00175
00176 if (pipe(stdin_pipe) != 0 || pipe(stdout_pipe) != 0 ||
00177 pipe(stderr_pipe) != 0)
00178 {
00179 Close_pipes(stdin_pipe, stdout_pipe, stderr_pipe);
00180 return false;
00181 }
00182 child_pid = fork();
00183 if (child_pid == -1)
00184 {
00185 Close_pipes(stdin_pipe, stdout_pipe, stderr_pipe);
00186 return false;
00187 }
00188 if (child_pid == 0)
00189 {
00190 close(0);
00191 dup(stdin_pipe[0]);
00192 Close_pipe(stdin_pipe);
00193 close(1);
00194 dup(stdout_pipe[1]);
00195 Close_pipe(stdout_pipe);
00196 close(2);
00197 dup(stderr_pipe[1]);
00198 Close_pipe(stderr_pipe);
00199 execvp(file, argv);
00200 exit(-1);
00201 }
00202
00203 child_stdin = stdin_pipe[1];
00204 close(stdin_pipe[0]);
00205 child_stdout = stdout_pipe[0];
00206 close(stdout_pipe[1]);
00207 child_stderr = stderr_pipe[0];
00208 close(stderr_pipe[1]);
00209 cout << "Child_stdout is " << child_stdout << ", Child_stderr is " <<
00210 child_stderr << endl;
00211 stdout_tag = gdk_input_add(child_stdout,
00212 GDK_INPUT_READ, Read_from_child, this);
00213 stderr_tag = gdk_input_add(child_stderr,
00214 GDK_INPUT_READ, Read_from_child, this);
00215 return true;
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225 bool Exec_process::check_child
00226 (
00227 int& exit_code
00228 )
00229 {
00230 if (child_pid < 0)
00231 return false;
00232 int status;
00233
00234 int ret = waitpid(child_pid, &status, WNOHANG);
00235 if (ret != child_pid)
00236 return true;
00237 else
00238 {
00239 cout << "Exec_box: Child done." << endl;
00240 exit_code = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
00241 return false;
00242 }
00243 }
00244
00245 #endif
00246
00247
00248
00249
00250
00251 Exec_box::Exec_box
00252 (
00253 GtkTextView *b,
00254 GtkStatusbar *s,
00255 Exec_done_fun dfun,
00256 gpointer udata
00257 ) : box(b), status(s), done_fun(dfun), user_data(udata)
00258 {
00259 executor = new Exec_process;
00260 status_ctx = gtk_statusbar_get_context_id(status, "execstatus");
00261
00262 gtk_statusbar_push(status, status_ctx, "");
00263 }
00264
00265
00266
00267
00268
00269 Exec_box::~Exec_box
00270 (
00271 )
00272 {
00273 delete executor;
00274 }
00275
00276
00277
00278
00279
00280 void Exec_box::show_status
00281 (
00282 const char *msg
00283 )
00284 {
00285 gtk_statusbar_pop(status, status_ctx);
00286 gtk_statusbar_push(status, status_ctx, msg);
00287 }
00288
00289
00290
00291
00292
00293 static void Exec_callback
00294 (
00295 char *data,
00296 int datalen,
00297 int exit_code,
00298 void *user_data
00299 )
00300 {
00301 Exec_box *box = (Exec_box *) user_data;
00302 box->read_from_child(data, datalen, exit_code);
00303 }
00304 void Exec_box::read_from_child
00305 (
00306 char *data,
00307 int datalen,
00308 int exit_code
00309 )
00310 {
00311 if (datalen > 0)
00312 {
00313 GtkTextBuffer *buffer = gtk_text_view_get_buffer(box);
00314 gtk_text_buffer_insert_at_cursor(buffer,data,datalen);
00315 return;
00316 }
00317 if (exit_code == 0)
00318 show_status("Done: Success");
00319 else
00320 show_status("Done: Errors occurred");
00321 if (done_fun)
00322 done_fun(exit_code, this, user_data);
00323 }
00324
00325
00326
00327
00328
00329 void Exec_box::add_message
00330 (
00331 const char *txt
00332 )
00333 {
00334 GtkTextBuffer *buffer = gtk_text_view_get_buffer(box);
00335 gtk_text_buffer_insert_at_cursor(buffer,txt,strlen(txt));
00336 }
00337
00338
00339
00340
00341
00342
00343
00344 bool Exec_box::exec
00345 (
00346 const char *file,
00347 char *argv[]
00348 )
00349 {
00350 GtkTextBuffer *buffer = gtk_text_view_get_buffer(box);
00351 gtk_text_buffer_set_text(buffer, "", 0);
00352 if (!executor->exec(file, argv, Exec_callback, this))
00353 return false;
00354 return true;
00355 }
00356
00357
00358
00359
00360
00361 void Exec_box::kill_child
00362 (
00363 )
00364 {
00365 executor->kill_child();
00366 }