From 74e91ff8c198d22f07d943d96528c9c2d3eb629c Mon Sep 17 00:00:00 2001
From: Michele Calgaro <michele.calgaro@yahoo.it>
Date: Sun, 9 Jul 2023 17:22:04 +0900
Subject: Added logic to detect how to call the indenter

Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
---
 src/IndentHandler.cpp | 390 ++++++++++++++++++++++++++++++--------------------
 src/IndentHandler.h   |   5 +-
 2 files changed, 234 insertions(+), 161 deletions(-)

diff --git a/src/IndentHandler.cpp b/src/IndentHandler.cpp
index a11ea24..5e74706 100644
--- a/src/IndentHandler.cpp
+++ b/src/IndentHandler.cpp
@@ -21,6 +21,7 @@
 #include "IndentHandler.h"
 
 #include <cstdlib>
+#include <unistd.h>
 
 #include "MainWindow.h"
 #include "SettingsPaths.h"
@@ -41,11 +42,11 @@
 #include <tqlineedit.h>
 #include <tqmessagebox.h>
 #include <tqpopupmenu.h>
+#include <tqprocess.h>
 #include <tqspinbox.h>
 #include <tqtoolbox.h>
 #include <tqtoolbutton.h>
 #include <tqtooltip.h>
-//--- #include <tqprocess.h>
 //--- #include <tqsettings.h>
 //--- #include <tqstringlist.h>
 //--- #include <tqbytearray.h>
@@ -468,11 +469,11 @@ TQString IndentHandler::generateShellScript(const TQString &configFilename)
 //--- 
 //--- 	// Set the directory where the indenter will be executed for the process' environment as PWD.
 //--- 	TQStringList env = indentProcess.environment();
-//--- 	env << "PWD=" + TQFileInfo(m_tempDirectoryStr).absoluteFilePath();
+//--- 	env << "PWD=" + TQFileInfo(m_tempDirectoryStr).absFilePath();
 //--- 	indentProcess.setEnvironment(env);
 //--- 
 //--- 	// Set the directory for the indenter execution
-//--- 	indentProcess.setWorkingDirectory(TQFileInfo(m_tempDirectoryStr).absoluteFilePath());
+//--- 	indentProcess.setWorkingDirectory(TQFileInfo(m_tempDirectoryStr).absFilePath());
 //--- 
 //--- 	tqDebug() << __LINE__ << " " << __FUNCTION__ << ": Will call the indenter in the directory " <<
 //--- 	        indentProcess.workingDirectory() << " using this commandline call: " <<
@@ -921,6 +922,14 @@ void IndentHandler::resetToDefaultValues()
 	}
 }
 
+/*
+    \brief Feedback when the inderter process has finished
+ */
+void IndentHandler::indenterProcessFinished()
+{
+	m_indenterProcessFinished = true;
+}
+
 /*
     \brief Opens and parses the indenter ini file that is declared by \a iniFilePath.
  */
@@ -1368,162 +1377,225 @@ TQString IndentHandler::getIndenterCfgFile()
  */
 bool IndentHandler::createIndenterCallString()
 {
-//--- 	TQProcess indentProcess;
-//--- 
-//--- 	if (m_indenterFileName.isEmpty())
-//--- 	{
-//--- 		return false;
-//--- 	}
-//--- 
-//--- 	// First try to call the indenter inside of the data dir, using some suffix
-//--- 	// ------------------------------------------------------------------------
-//--- 
-//--- 	// Set the directory for the indenter execution
-//--- 	indentProcess.setWorkingDirectory(TQFileInfo(m_indenterDirectoryStr).absoluteFilePath());
-//--- 
-//--- 	foreach(TQString suffix, TQStringList() << "" << ".exe" << ".bat" << ".com" << ".sh")
-//--- 	{
-//--- 		m_indenterExecutableSuffix     = suffix;
-//--- 		m_indenterExecutableCallString = TQFileInfo(m_indenterDirectoryStr).absoluteFilePath() + "/" +
-//--- 		        m_indenterFileName;
-//--- 		m_indenterExecutableCallString += suffix;
-//--- 
-//--- 		// Only try to call the indenter, if the file exists.
-//--- 		if (TQFile::exists(m_indenterExecutableCallString))
-//--- 		{
-//--- 			// Only try to call the indenter directly if it is no php file
-//--- 			if (TQFileInfo(m_indenterExecutableCallString).suffix().toLower() != "php")
-//--- 			{
-//--- 				indentProcess.start(
-//--- 					"\"" + m_indenterExecutableCallString +  +"\" " + m_indenterShowHelpParameter);
-//--- 				if (indentProcess.waitForFinished(2000))
-//--- 				{
-//--- 					m_indenterExecutableCallString = "\"" + m_indenterExecutableCallString + "\"";
-//--- 					return true;
-//--- 				}
-//--- 				else if (indentProcess.error() == TQProcess::Timedout)
-//--- 				{
-//--- 					m_indenterExecutableCallString = "\"" + m_indenterExecutableCallString + "\"";
-//--- 					return true;
-//--- 				}
-//--- 			}
-//--- 
-//--- 			// Test for needed interpreters
-//--- 			// ----------------------------
-//--- 			// If the file could not be executed, try to find a shebang at its start or test if its a php
-//--- 			// file.
-//--- 			TQString interpreterName = "";
-//--- 			TQFile   indenterExecutable(m_indenterExecutableCallString);
-//--- 
-//--- 			// If indenter executable file has .php as suffix, use php as default interpreter
-//--- 			if (TQFileInfo(m_indenterExecutableCallString).suffix().toLower() == "php")
-//--- 			{
-//--- 				interpreterName = "php -f";
-//--- 			}
-//--- 			// Else try to open the file and read the shebang.
-//--- 			else if (indenterExecutable.open(TQFile::ReadOnly))
-//--- 			{
-//--- 				// Read the first line of the file.
-//--- 				TQTextStream indenterExecutableContent(&indenterExecutable);
-//--- 				TQString     firstLineOfIndenterExe = indenterExecutableContent.readLine(75);
-//--- 				indenterExecutable.close();
-//--- 
-//--- 				// If the initial shebang is found, read the named intepreter. e.g. perl
-//--- 				if (firstLineOfIndenterExe.startsWith("#!"))
-//--- 				{
-//--- 					// Get the rightmost word. by splitting the string into only full words.
-//--- 					interpreterName = firstLineOfIndenterExe.split("/").last();
-//--- 				}
-//--- 			}
-//--- 
-//--- 			// Try to call the interpreter, if it exists.
-//--- 			if (!interpreterName.isEmpty())
-//--- 			{
-//--- 				m_indenterExecutableCallString = interpreterName + " \"" + m_indenterExecutableCallString +
-//--- 				        "\"";
-//--- 				indentProcess.start(interpreterName + " -h");
-//--- 				if (indentProcess.waitForFinished(2000))
-//--- 				{
-//--- 					return true;
-//--- 				}
-//--- 				else if (indentProcess.error() == TQProcess::Timedout)
-//--- 				{
-//--- 					return true;
-//--- 				}
-//--- 				// now we know an interpreter is needed but it could not be called, so inform the user.
-//--- 				else
-//--- 				{
-//--- 					m_errorMessageDialog->showMessage(tr("Interpreter needed"), tr(
-//--- 										"To use the selected indenter the program \"%1\" needs to be available in the global environment. You should add an entry to your path settings.").arg(
-//--- 										interpreterName));
-//--- 					return true;
-//--- 				}
-//--- 			}
-//--- 		}
-//--- 	}
-//--- 
-//--- 	// If unsuccessful try if the indenter executable is a JavaScript file
-//--- 	// -------------------------------------------------------------------
-//--- 	m_indenterExecutableSuffix     = ".js";
-//--- 	m_indenterExecutableCallString = TQFileInfo(m_indenterDirectoryStr).absoluteFilePath() + "/" +
-//--- 	        m_indenterFileName;
-//--- 	m_indenterExecutableCallString += m_indenterExecutableSuffix;
-//--- 	if (TQFile::exists(m_indenterExecutableCallString))
-//--- 	{
-//--- 		return true;
-//--- 	}
-//--- 
-//--- 	// If unsuccessful try to call the indenter global, using some suffix
-//--- 	// ------------------------------------------------------------------
-//--- 	foreach(TQString suffix, TQStringList() << "" << ".exe" << ".bat" << ".com" << ".sh")
-//--- 	{
-//--- 		m_indenterExecutableSuffix     = suffix;
-//--- 		m_indenterExecutableCallString = m_indenterFileName + suffix;
-//--- 		indentProcess.start(m_indenterExecutableCallString + " " + m_indenterShowHelpParameter);
-//--- 		if (indentProcess.waitForFinished(2000))
-//--- 		{
-//--- 			return true;
-//--- 		}
-//--- 		else if (indentProcess.error() == TQProcess::Timedout)
-//--- 		{
-//--- 			return true;
-//--- 		}
-//--- 	}
-//--- 
-//--- 	// If even globally calling the indenter fails, try calling .com and .exe via wine
-//--- 	// -------------------------------------------------------------------------------
-//--- 	m_indenterExecutableCallString = "\"" + TQFileInfo(m_indenterDirectoryStr).absoluteFilePath() + "/" +
-//--- 	        m_indenterFileName;
-//--- 
-//--- 	foreach(TQString suffix, TQStringList() << ".exe" << ".com")
-//--- 	{
-//--- 		m_indenterExecutableSuffix = suffix;
-//--- 		if (TQFile::exists(m_indenterDirectoryStr + "/" + m_indenterFileName + suffix))
-//--- 		{
-//--- 			TQProcess wineTestProcess;
-//--- 			wineTestProcess.start("wine --version");
-//--- 			// if the process of wine was not callable assume that wine is not installed
-//--- 			if (!wineTestProcess.waitForFinished(2000))
-//--- 			{
-//--- 				m_errorMessageDialog->showMessage(tr("wine not installed"), tr(
-//--- 									"There exists only a win32 executable of the indenter and wine does not seem to be installed. Please install wine to be able to run the indenter."));
-//--- 				m_indenterExecutableCallString = "";
-//--- 				return false;
-//--- 			}
-//--- 			else
-//--- 			{
-//--- 				m_indenterExecutableCallString = "\"" +
-//--- 				        TQFileInfo(m_indenterDirectoryStr).absoluteFilePath() + "/";
-//--- 				m_indenterExecutableCallString += m_indenterFileName + suffix + "\"";
-//--- 				m_indenterExecutableCallString  = "wine " + m_indenterExecutableCallString;
-//--- 
-//--- 				return true;
-//--- 			}
-//--- 		}
-//--- 	}
-//--- 
-//--- 	m_indenterExecutableCallString = "";
-//--- 	m_indenterExecutableSuffix     = "";
+	TQProcess indentProcess(this);
+	TQObject::connect(&indentProcess, SIGNAL(processExited()), this, SLOT(indenterProcessFinished()));
+
+	if (m_indenterFileName.isEmpty())
+	{
+		return false;
+	}
+
+	// First try to call the indenter inside of the data dir, using some suffix
+	// ------------------------------------------------------------------------
+
+	// Set the directory for the indenter execution
+	indentProcess.setWorkingDirectory(TQFileInfo(m_indenterDirectoryStr).absFilePath());
+
+	TQStringList extentionList;
+	extentionList << "" << ".exe" << ".bat" << ".com" << ".sh";
+	for (const TQString &suffix : extentionList)
+	{
+		m_indenterExecutableSuffix     = suffix;
+		m_indenterExecutableCallString = TQFileInfo(m_indenterDirectoryStr).absFilePath() + "/" +
+			m_indenterFileName;
+		m_indenterExecutableCallString += suffix;
+
+		// Only try to call the indenter, if the file exists.
+		if (TQFile::exists(m_indenterExecutableCallString))
+		{
+			// Only try to call the indenter directly if it is no php file
+			if (TQFileInfo(m_indenterExecutableCallString).extension(false).lower() != "php")
+			{
+				indentProcess.clearArguments();
+				indentProcess.addArgument(m_indenterExecutableCallString);
+				indentProcess.addArgument(m_indenterShowHelpParameter);
+				m_indenterProcessFinished = false;
+				indentProcess.start();
+				int counter = 20; // roughtly 2s at 100ms interval
+				while (!m_indenterProcessFinished && counter > 0)
+				{
+					usleep(100 * 1000);
+					tqApp->processEvents();
+					--counter;
+				}
+				if (indentProcess.normalExit())
+				{
+					m_indenterExecutableCallString = "\"" + m_indenterExecutableCallString + "\"";
+					return true;
+				}
+				else
+				{
+					if (indentProcess.isRunning())
+					{
+						indentProcess.kill();
+					}
+				}
+			}
+
+			// Test for needed interpreters
+			// ----------------------------
+			// If the file could not be executed, try to find a shebang at its start or test if its a php
+			// file.
+			TQString interpreterName = "";
+			TQFile   indenterExecutable(m_indenterExecutableCallString);
+
+			// If indenter executable file has .php as suffix, use php as default interpreter
+			if (TQFileInfo(m_indenterExecutableCallString).extension(false).lower() == "php")
+			{
+				interpreterName = "php -f";
+			}
+			// Else try to open the file and read the shebang.
+			else if (indenterExecutable.open(IO_ReadOnly))
+			{
+				// Read the first line of the file.
+				TQTextStream indenterExecutableContent(&indenterExecutable);
+				TQString     firstLineOfIndenterExe = indenterExecutableContent.readLine();
+				indenterExecutable.close();
+
+				// If the initial shebang is found, read the named intepreter. e.g. perl
+				if (firstLineOfIndenterExe.startsWith("#!"))
+				{
+					// Get the rightmost word. by splitting the string into only full words.
+					TQStringList indenterFirstLineStrings = TQStringList::split("/", firstLineOfIndenterExe);
+					interpreterName = indenterFirstLineStrings.last();
+				}
+			}
+
+			// Try to call the interpreter, if it exists.
+			if (!interpreterName.isEmpty())
+			{
+				m_indenterExecutableCallString = interpreterName + " \"" +
+					m_indenterExecutableCallString + "\"";
+				indentProcess.clearArguments();
+				indentProcess.addArgument(interpreterName);
+				indentProcess.addArgument("-h");
+				m_indenterProcessFinished = false;
+				indentProcess.start();
+				int counter = 20; // roughtly 2s at 100ms interval
+				while (!m_indenterProcessFinished && counter > 0)
+				{
+					usleep(100 * 1000);
+					tqApp->processEvents();
+					--counter;
+				}
+				if (indentProcess.normalExit())
+				{
+					return true;
+				}
+				// now we know an interpreter is needed but it could not be called, so inform the user.
+				else
+				{
+					if (indentProcess.isRunning())
+					{
+						indentProcess.kill();
+					}
+					m_errorMessageDialog->showMessage(tr("Interpreter needed"),
+							tr("To use the selected indenter the program \"%1\" needs to be available in the global environment. "
+								"You should add an entry to your path settings.").arg(interpreterName));
+					return true;
+				}
+			}
+		}
+	}
+
+	// If unsuccessful try if the indenter executable is a JavaScript file
+	// -------------------------------------------------------------------
+	m_indenterExecutableSuffix     = ".js";
+	m_indenterExecutableCallString = TQFileInfo(m_indenterDirectoryStr).absFilePath() + "/" +
+		m_indenterFileName;
+	m_indenterExecutableCallString += m_indenterExecutableSuffix;
+	if (TQFile::exists(m_indenterExecutableCallString))
+	{
+		return true;
+	}
+
+	// If unsuccessful try to call the indenter global, using some suffix
+	// ------------------------------------------------------------------
+	extentionList.clear();
+	extentionList << "" << ".exe" << ".bat" << ".com" << ".sh";
+	for (const TQString &suffix : extentionList)
+	{
+		m_indenterExecutableSuffix     = suffix;
+		m_indenterExecutableCallString = m_indenterFileName + suffix;
+		indentProcess.clearArguments();
+		indentProcess.addArgument(m_indenterExecutableCallString);
+		indentProcess.addArgument(m_indenterShowHelpParameter);
+		m_indenterProcessFinished = false;
+		indentProcess.start();
+		int counter = 20; // roughtly 2s at 100ms interval
+		while (!m_indenterProcessFinished && counter > 0)
+		{
+			usleep(100 * 1000);
+			tqApp->processEvents();
+			--counter;
+		}
+		if (indentProcess.normalExit())
+		{
+			return true;
+		}
+		else
+		{
+			if (indentProcess.isRunning())
+			{
+				indentProcess.kill();
+			}
+		}
+	}
+
+	// If even globally calling the indenter fails, try calling .com and .exe via wine
+	// -------------------------------------------------------------------------------
+	m_indenterExecutableCallString = "\"" + TQFileInfo(m_indenterDirectoryStr).absFilePath() + "/" +
+		m_indenterFileName;
+
+	extentionList.clear();
+	extentionList << ".exe" << ".com";
+	for (const TQString &suffix : extentionList)
+	{
+		m_indenterExecutableSuffix = suffix;
+		if (TQFile::exists(m_indenterDirectoryStr + "/" + m_indenterFileName + suffix))
+		{
+			indentProcess.clearArguments();
+			indentProcess.addArgument("wine");
+			indentProcess.addArgument("--version");
+			m_indenterProcessFinished = false;
+			indentProcess.start();
+			int counter = 20; // roughtly 2s at 100ms interval
+			while (!m_indenterProcessFinished && counter > 0)
+			{
+				usleep(100 * 1000);
+				tqApp->processEvents();
+				--counter;
+			}
+			// if the process of wine was not callable assume that wine is not installed
+			if (indentProcess.normalExit())
+			{
+				m_errorMessageDialog->showMessage(tr("wine not installed"), tr(
+							"There exists only a win32 executable of the indenter and wine does not seem to be installed. Please install wine to be able to run the indenter."));
+				m_indenterExecutableCallString = "";
+				return false;
+			}
+			else
+			{
+				if (indentProcess.isRunning())
+				{
+					indentProcess.kill();
+				}
+				m_indenterExecutableCallString = "\"" +
+					TQFileInfo(m_indenterDirectoryStr).absFilePath() + "/";
+				m_indenterExecutableCallString += m_indenterFileName + suffix + "\"";
+				m_indenterExecutableCallString  = "wine " + m_indenterExecutableCallString;
+
+				return true;
+			}
+		}
+	}
+
+	m_indenterExecutableCallString = "";
+	m_indenterExecutableSuffix     = "";
+	if (indentProcess.isRunning())
+	{
+		indentProcess.kill();
+	}
 	return false;
 }
 
diff --git a/src/IndentHandler.h b/src/IndentHandler.h
index 9677f6a..0d51a0a 100644
--- a/src/IndentHandler.h
+++ b/src/IndentHandler.h
@@ -65,7 +65,7 @@ class IndentHandler : public TQWidget
 ///-- 	protected:
 ///-- 		bool event(TQEvent *event);
 ///-- 		void wheelEvent(TQWheelEvent *event);
-///-- 
+
 	private slots:
 		void setIndenter(int indenterID);
 		void showIndenterManual() const;
@@ -74,6 +74,7 @@ class IndentHandler : public TQWidget
 		void createIndenterCallShellScript();
 		void resetIndenterParameter();
 		void handleChangedIndenterSettings();
+		void indenterProcessFinished();
 
 	private:
 ///-- 		TQString callExecutableIndenter(TQString sourceCode, TQString inputFileExtension);
@@ -166,7 +167,7 @@ class IndentHandler : public TQWidget
 		UiGuiErrorMessage  *m_errorMessageDialog;
 		TQString           m_indenterExecutableCallString;
 		TQString           m_indenterExecutableSuffix;
-///-- 
+		bool               m_indenterProcessFinished;
 
 ///-- 		//TODO: This function should go into a string helper/tool class/file.
 ///-- 		TQString encodeToHTML(const TQString &text);
-- 
cgit v1.2.3

