summaryrefslogtreecommitdiff
path: root/fluid/shell_command.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'fluid/shell_command.cxx')
-rw-r--r--fluid/shell_command.cxx234
1 files changed, 234 insertions, 0 deletions
diff --git a/fluid/shell_command.cxx b/fluid/shell_command.cxx
new file mode 100644
index 000000000..7e77d1883
--- /dev/null
+++ b/fluid/shell_command.cxx
@@ -0,0 +1,234 @@
+//
+// FLUID main entry for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2021 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file. If this
+// file is missing or damaged, see the license at:
+//
+// https://www.fltk.org/COPYING.php
+//
+// Please see the following page on how to report bugs and issues:
+//
+// https://www.fltk.org/bugs.php
+//
+
+#include "shell_command.h"
+
+#include "fluid.h"
+#include "alignment_panel.h"
+
+#include <FL/Fl_Double_Window.H>
+#include <FL/fl_message.H>
+
+#include <errno.h>
+
+static Fl_Process s_proc;
+
+/** \class Fl_Process
+ \todo Explain.
+ */
+
+Fl_Process::Fl_Process() {
+ _fpt= NULL;
+}
+
+Fl_Process::~Fl_Process() {
+ if (_fpt) close();
+}
+
+// FIXME: popen needs the UTF-8 equivalent fl_popen
+// portable open process:
+FILE * Fl_Process::popen(const char *cmd, const char *mode) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // PRECONDITIONS
+ if (!mode || !*mode || (*mode!='r' && *mode!='w') ) return NULL;
+ if (_fpt) close(); // close first before reuse
+
+ ptmode = *mode;
+ pin[0] = pin[1] = pout[0] = pout[1] = perr[0] = perr[1] = INVALID_HANDLE_VALUE;
+ // stderr to stdout wanted ?
+ int fusion = (strstr(cmd,"2>&1") !=NULL);
+
+ // Create windows pipes
+ if (!createPipe(pin) || !createPipe(pout) || (!fusion && !createPipe(perr) ) )
+ return freeHandles(); // error
+
+ // Initialize Startup Info
+ ZeroMemory(&si, sizeof(STARTUPINFO));
+ si.cb = sizeof(STARTUPINFO);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = pin[0];
+ si.hStdOutput = pout[1];
+ si.hStdError = fusion ? pout[1] : perr [1];
+
+ if ( CreateProcess(NULL, (LPTSTR) cmd,NULL,NULL,TRUE,
+ DETACHED_PROCESS,NULL,NULL, &si, &pi)) {
+ // don't need theses handles inherited by child process:
+ clean_close(pin[0]); clean_close(pout[1]); clean_close(perr[1]);
+ HANDLE & h = *mode == 'r' ? pout[0] : pin[1];
+ _fpt = _fdopen(_open_osfhandle((fl_intptr_t) h,_O_BINARY),mode);
+ h= INVALID_HANDLE_VALUE; // reset the handle pointer that is shared
+ // with _fpt so we don't free it twice
+ }
+
+ if (!_fpt) freeHandles();
+ return _fpt;
+#else
+ _fpt=::popen(cmd,mode);
+ return _fpt;
+#endif
+}
+
+int Fl_Process::close() {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (_fpt) {
+ fclose(_fpt);
+ clean_close(perr[0]);
+ clean_close(pin[1]);
+ clean_close(pout[0]);
+ _fpt = NULL;
+ return 0;
+ }
+ return -1;
+#else
+ int ret = ::pclose(_fpt);
+ _fpt=NULL;
+ return ret;
+#endif
+}
+
+// non-null if file is open
+FILE *Fl_Process::desc() const {
+ return _fpt;
+}
+
+char *Fl_Process::get_line(char * line, size_t s) const {
+ return _fpt ? fgets(line, (int)s, _fpt) : NULL;
+}
+
+// returns fileno(FILE*):
+// (file must be open, i.e. _fpt must be non-null)
+// *FIXME* we should find a better solution for the 'fileno' issue
+// non null if file is open
+int Fl_Process::get_fileno() const {
+#ifdef _MSC_VER
+ return _fileno(_fpt); // suppress MSVC warning
+#else
+ return fileno(_fpt);
+#endif
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+
+bool Fl_Process::createPipe(HANDLE * h, BOOL bInheritHnd) {
+ SECURITY_ATTRIBUTES sa;
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = bInheritHnd;
+ return CreatePipe (&h[0],&h[1],&sa,0) ? true : false;
+}
+
+FILE *Fl_Process::freeHandles() {
+ clean_close(pin[0]); clean_close(pin[1]);
+ clean_close(pout[0]); clean_close(pout[1]);
+ clean_close(perr[0]); clean_close(perr[1]);
+ return NULL; // convenient for error management
+}
+
+void Fl_Process::clean_close(HANDLE& h) {
+ if (h!= INVALID_HANDLE_VALUE) CloseHandle(h);
+ h = INVALID_HANDLE_VALUE;
+}
+
+#endif
+
+
+// Shell command support...
+
+static bool prepare_shell_command(const char * &command) { // common pre-shell command code all platforms
+ shell_window->hide();
+ if (s_proc.desc()) {
+ fl_alert("Previous shell command still running!");
+ return false;
+ }
+ if ((command = shell_command_input->value()) == NULL || !*command) {
+ fl_alert("No shell command entered!");
+ return false;
+ }
+ if (shell_savefl_button->value()) {
+ save_cb(0, 0);
+ }
+ if (shell_writecode_button->value()) {
+ write_code_files();
+ }
+ if (shell_writemsgs_button->value()) {
+ write_strings_cb(0, 0);
+ }
+ return true;
+}
+
+// Support the full piped shell command...
+void shell_pipe_cb(FL_SOCKET, void*) {
+ char line[1024]=""; // Line from command output...
+
+ if (s_proc.get_line(line, sizeof(line)) != NULL) {
+ // Add the line to the output list...
+ shell_run_terminal->append(line);
+ } else {
+ // End of file; tell the parent...
+ Fl::remove_fd(s_proc.get_fileno());
+ s_proc.close();
+ shell_run_terminal->append("... END SHELL COMMAND ...\n");
+ }
+}
+
+void do_shell_command(Fl_Return_Button*, void*) {
+ const char *command=NULL; // Command to run
+
+ if (!prepare_shell_command(command)) return;
+
+ // Show the output window and clear things...
+ shell_run_terminal->text("");
+ shell_run_terminal->append(command);
+ shell_run_terminal->append("\n");
+ shell_run_window->label("Shell Command Running...");
+
+ if (s_proc.popen((char *)command) == NULL) {
+ fl_alert("Unable to run shell command: %s", strerror(errno));
+ return;
+ }
+
+ shell_run_button->deactivate();
+
+ Fl_Preferences pos(fluid_prefs, "shell_run_Window_pos");
+ int x, y, w, h;
+ pos.get("x", x, -1);
+ pos.get("y", y, 0);
+ pos.get("w", w, 640);
+ pos.get("h", h, 480);
+ if (x!=-1) {
+ shell_run_window->resize(x, y, w, h);
+ }
+ shell_run_window->show();
+
+ Fl::add_fd(s_proc.get_fileno(), shell_pipe_cb);
+
+ while (s_proc.desc()) Fl::wait();
+
+ shell_run_button->activate();
+ shell_run_window->label("Shell Command Complete");
+ fl_beep();
+
+ while (shell_run_window->shown()) Fl::wait();
+}
+
+/**
+ Show a dialog box to run an external shell command.
+ */
+void show_shell_window() {
+ shell_window->hotspot(shell_command_input);
+ shell_window->show();
+}
+