diff --git a/cmake/version.cmake b/cmake/version.cmake
index bd9cdeb..266d101 100644
--- a/cmake/version.cmake
+++ b/cmake/version.cmake
@@ -3,7 +3,7 @@
#
set (TK_UTIL_MAJOR_VERSION "6")
-set (TK_UTIL_MINOR_VERSION "9")
+set (TK_UTIL_MINOR_VERSION "10")
set (TK_UTIL_RELEASE_VERSION "0")
set (TK_UTIL_VERSION ${TK_UTIL_MAJOR_VERSION}.${TK_UTIL_MINOR_VERSION}.${TK_UTIL_RELEASE_VERSION})
diff --git a/src/TkUtil/CMakeLists.txt b/src/TkUtil/CMakeLists.txt
index 591c5de..fc4bb77 100644
--- a/src/TkUtil/CMakeLists.txt
+++ b/src/TkUtil/CMakeLists.txt
@@ -30,7 +30,7 @@ foreach (lib ${ALL_TARGETS})
endforeach (lib)
target_link_libraries (TkUtil PUBLIC ${Iconv_LIBRARIES})
target_include_directories (TkUtil PUBLIC $$)
-target_link_libraries (TkUtil PUBLIC pthread)
+target_link_libraries (TkUtil PUBLIC stdc++fs pthread)
# INSTALLATION :
include(CMakePackageConfigHelpers)
diff --git a/src/TkUtil/File.cpp b/src/TkUtil/File.cpp
index 2a4285c..7015286 100644
--- a/src/TkUtil/File.cpp
+++ b/src/TkUtil/File.cpp
@@ -14,7 +14,7 @@
#include
#include
#include
-#include
+#include
USING_STD
@@ -245,6 +245,28 @@ bool File::isExecutable ( ) const
} // File::isExecutable
+void File::getChildren (std::vector& directories, std::vector& files) const // v 6.10.0
+{ // API C++ 17
+ directories.clear ( );
+ files.clear ( );
+
+ if (false == isDirectory ( ))
+ {
+ UTF8String message (charset);
+ message << "Impossibilité de donner la liste des sous-répertoires et fichiers : " << getFullFileName ( ) << " n'est pas un répertoire.";
+ throw Exception (message);
+ } // if (false == isDirectory ( ))
+
+ for (const auto& entry : filesystem::directory_iterator (getFullFileName ( )))
+ {
+ if (true == filesystem::is_directory (entry))
+ directories.push_back (File (filesystem::path (entry)));
+ else if (true == filesystem::is_regular_file (entry))
+ files.push_back (File (filesystem::path (entry)));
+ } // for (const auto& entry : filesystem::directory_iterator (getFullFileName ( )))
+} // File::getChildren
+
+
mode_t File::getAccessRights ( ) const // v 5.11.0
{
errno = 0;
diff --git a/src/TkUtil/Process.cpp b/src/TkUtil/Process.cpp
index 7398e32..70588cd 100644
--- a/src/TkUtil/Process.cpp
+++ b/src/TkUtil/Process.cpp
@@ -326,11 +326,12 @@ void Process::execute (bool autoDelete)
int Process::wait ( )
{
if (true == isCompleted ( ))
- {
+ return getCompletionCode ( ); // v 6.10.0
+/* {
UTF8String errorMsg (charset);
errorMsg << "Impossibilité d'attendre la fin du processus " << getName ( ) << " : processus terminé.";
throw Exception (errorMsg);
- } // if (true == isCompleted ( ))
+ } // if (true == isCompleted ( )) */
setWaited (true);
pid_t childPid = getPid ( );
int status = -1;
@@ -446,9 +447,7 @@ void Process::initialize (char* envp [])
string Process::getChildLine ( )
{
if ((true == isCompleted ( )) && (0 == _childBuffer.length ( )))
- { // v 2.21.0 : le remplissage du buffer n'est plus effectué dans
- // childDeath (accès concurrents depuis la même pile aux fonctions de
- // la lib malloc).
+ { // v 2.21.0 : le remplissage du buffer n'est plus effectué dans childDeath (accès concurrents depuis la même pile aux fonctions de la lib malloc).
try
{
fillChildBuffer ( );
diff --git a/src/TkUtil/public/TkUtil/File.h b/src/TkUtil/public/TkUtil/File.h
index aacc1b0..6ca68fd 100644
--- a/src/TkUtil/public/TkUtil/File.h
+++ b/src/TkUtil/public/TkUtil/File.h
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
BEGIN_NAMESPACE_UTIL
@@ -120,22 +121,30 @@ class File
* @return true si le fichier est accessible en exécution, sinon false.
*/
virtual bool isExecutable ( ) const;
+
+ /**
+ * @return La liste des sous-répertoires (exception faite de "." et "..") et fichiers.
+ * @exception Une exception est levée en cas d'erreur, notamment si l'instance n'est pas un répertoire.
+ * @since 6.10.0
+ */
+ virtual void getChildren (std::vector& directories, std::vector& files) const;
/**
* @return Les droits d'accès sur le fichier (champ st_mode de la structure stat).
- * Combinaison par opérateur | des flags S_IR*, S_IW*, S_IX*, * pouvant prendre pour
- * valeurs USR, GRP, OTH (cf. man chmod).
+ * Combinaison par opérateur | des flags S_IR*, S_IW*, S_IX*, * pouvant prendre pour valeurs USR, GRP, OTH (cf. man chmod).
* @exception Une exception est levée en cas d'erreur.
* @see setAccessRights
+ * @since 5.11.0
*/
- virtual mode_t getAccessRights ( ) const; // v 5.11.0
+ virtual mode_t getAccessRights ( ) const;
/**
* @param Nouveaux droits d'accès sur le fichier (champ st_mode de la structure stat).
* @exception Une exception est levée en cas d'erreur.
* @see getAccessRights
+ * @since 5.11.0
*/
- virtual void setAccessRights (mode_t rigths); // v 5.11.0
+ virtual void setAccessRights (mode_t rigths);
/**
* Créé effectivement le fichier si celui-ci n'existe pas. Créé l'arborescence parente si nécessaire.
@@ -154,11 +163,11 @@ class File
* Déplace physiquement le fichier.
* @param Nouveau path du fichier.
* @param Si true détruit l'éventuel fichier ayant le path demandé.
- * Si false et qu'un fichier existe déjà alors lève une exception.
+ * Si false et qu'un fichier existe déjà alors lève une exception.
* @exception Une exception est levée en cas d'impossibilité de déplacer le fichier.
* @see setFullFileName
*/
- virtual void rename (const std::string& newpath, bool erase); // v 5.4.0
+ virtual void rename (const std::string& newpath, bool erase); // v 5.4.0
/**
* Détruit le fichier s'il existe.
@@ -173,16 +182,14 @@ class File
virtual void print (IN_STD ostream& stream) const;
/**
- * @return Le masque de permissions utilisé lors de la création de
- * fichiers.
+ * @return Le masque de permissions utilisé lors de la création de fichiers.
*/
static mode_t getUMask ( );
/**
* Créé un nom unique de fichier temporaire.
* @param Préfix du nom de fichier temporaire.
- * @param true si le fichier doit être créé dans le répertoire des fichiers temporaires,
- * false si il doit être créé en relatif par rapport à prefix.
+ * @param true si le fichier doit être créé dans le répertoire des fichiers temporaires, false si il doit être créé en relatif par rapport à prefix.
* @exception Une exception est levée en cas d'échec.
*/
static IN_STD string createTemporaryName (const IN_STD string& prefix, bool inTmpDir = true);
diff --git a/src/TkUtil/public/TkUtil/Process.h b/src/TkUtil/public/TkUtil/Process.h
index 62c6c41..22e0a74 100644
--- a/src/TkUtil/public/TkUtil/Process.h
+++ b/src/TkUtil/public/TkUtil/Process.h
@@ -79,6 +79,30 @@ BEGIN_NAMESPACE_UTIL
* // ...
* }
*
+ * 3- Lecture de la sortie standard du processus lancé (cf. src/tests/process.cpp) :
+ *
+ * unique_ptr process (new Process ("ls"));
+ * process->getOptions ( ).addOption ("-al");
+ * process->getOptions ( ).addOption (argv [1]);
+ * cout << "Cmd line is : " << process->getCommandLine ( ) << endl;
+ * process->enableChildToSonCommunications (true);
+ * process->execute (false);
+ * const int status = process->wait ( );
+ * cout << "Process standard output :" << endl;
+ * bool completed = false;
+ * while (false == completed)
+ * {
+ * try
+ * {
+ * const string output = process->getChildLine ( );
+ * cout << output << endl;
+ * }
+ * catch (...)
+ * {
+ * completed = true;
+ * }
+ * } // while (false == completed)
+ *
*
* Cette classe permet également de connaître le répertoire courrant de l'application à l'aide de la méthode statique getCurrentDirectory.
*
@@ -141,8 +165,7 @@ class Process
Process (const IN_STD string& processName);
/**
- * Destructeur : appelé automatiquement par l'instance en fin d'exécution
- * si true est passé en argument d'execute .
+ * Destructeur : appelé automatiquement par l'instance en fin d'exécution si true est passé en argument d'execute .
* @see execute
*/
virtual ~Process ( );
@@ -150,7 +173,7 @@ class Process
/**
* Créé une instance à partir de la ligne de commande transmise en argument (exécutable puis arguments).
* @return instance créée.
- * @todo possibilité de déclarer des variables d'environnement avant l'exécutable avec la synatxe variable=valeur
+ * @todo possibilité de déclarer des variables d'environnement avant l'exécutable avec la syntaxe variable=valeur
*/
static Process* create (const std::string& cmdLine); // v 6.2.0
@@ -160,8 +183,7 @@ class Process
virtual ProcessOptions& getOptions ( );
/**
- * @return La ligne de commande complète qui sera exécutée. A des
- * fins de débogage, méthode non utilisée par execute.
+ * @return La ligne de commande complète qui sera exécutée. A des fins de débogage, méthode non utilisée par execute.
*/
virtual IN_STD string getCommandLine ( );
@@ -173,8 +195,8 @@ class Process
virtual void execute (bool autoDelete = true);
/**
- * Attend la fin du processus fils.
- * @return status de retour du processus fils.
+ * Attend si nécessaire la fin du processus fils.
+ * @return status de retour du processus fils (getCompletionCode ( )).
* @see getCompletionCode
* @see getErrorMessage
*/
@@ -224,16 +246,12 @@ class Process
* @see getCompletionCode
* @see isCompleted
*/
-// virtual const IN_STD string& getErrorMessage ( ) const // v 4.4.0
-// { return _errorMessage; }
- virtual const IN_STD string getErrorMessage ( ) const // v 4.4.0
+ virtual const IN_STD string getErrorMessage ( ) const
{ return std::string (_errorMessage); }
/**
- * A invoquer si un pipe doit être ouvert de la sortie standard du
- * processus fils vers le processus père.
- * @param true si la communication doit être en mode bloquant, false
- * dans le cas contraire. Le mode non bloquant est irréversible.
+ * A invoquer si un pipe doit être ouvert de la sortie standard du processus fils vers le processus père.
+ * @param true si la communication doit être en mode bloquant, false dans le cas contraire. Le mode non bloquant est irréversible.
* @exception Lève une exception en cas d'erreur
* @see getpipeDescriptors
* @see getChildLine
@@ -241,8 +259,7 @@ class Process
void enableChildToSonCommunications (bool blocking = true);
/**
- * @return true si un pipe doit être ouvert de la sortie standard du
- * processus fils vers le processus père.
+ * @return true si un pipe doit être ouvert de la sortie standard du processus fils vers le processus père.
* @see enableChildToSonCommunications
*/
bool isChildToSonCommunicationsEnabled ( ) const
@@ -279,8 +296,7 @@ class Process
* int main (int argc, char* argv[], char* envp [])
* @warning il est essentiel d'appeler cette fonction avant le lancement de tout process fils. En son absence
* il est possible que l'exécution du process fils échoue.
- * @deprecated Utiliser la version utilisant également argc et
- * argv du main.
+ * @deprecated Utiliser la version utilisant également argc et argv du main.
*/
static void initialize (char* envp []);
@@ -303,8 +319,7 @@ class Process
* @see getCurrentSoftware
* @see getCurrentSoftwareVersion
*/
- static void setCurrentSoftware (
- const IN_STD string& name, const Version& version = Version ("0.0.0"));
+ static void setCurrentSoftware (const IN_STD string& name, const Version& version = Version ("0.0.0"));
/**
* @return Le nom du logiciel courrant, ou une chaine vide s'il n'a pas été renseigné par setCurrentSoftware.
@@ -342,20 +357,14 @@ class Process
/**
* @param Le message d'erreur associé à une terminaison anormale.
- * Sa recopie se limite aux PROCESS_ERROR_MESSAGE_SIZE-1
- * premiers caractères. Depuis la version 4.4.0 la gestion
- * du message d'erreur est géré dans un tampon pré-alloué car
- * ce message peut être issu d'un signal émis et recopié
- * dans un handler sur signal où il ne fait pas bon d'utiliser
- * malloc et free.
+ * Sa recopie se limite aux PROCESS_ERROR_MESSAGE_SIZE-1 premiers caractères. Depuis la version 4.4.0 la gestion
+ * du message d'erreur est géré dans un tampon pré-alloué car ce message peut être issu d'un signal émis et recopié
+ * dans un handler sur signal où il ne fait pas bon d'utiliser malloc et free.
*/
-// virtual void setErrorMessage (const IN_STD string& message) // v 4.4.0
-// { _errorMessage = message; }
- virtual void setErrorMessage (const char* message); // v 4.4.0
+ virtual void setErrorMessage (const char* message);
/**
- * @return True si la terminaison du processus fils est attendue,
- * sinon false.
+ * @return True si la terminaison du processus fils est attendue, sinon false.
* @see setWaited
* @see waited
*/
@@ -371,9 +380,7 @@ class Process
{ _waited = waited; }
/**
- * Lit les l'ensemble des données dans le pipe de communication avec
- * le processus fils et les stocke dans l'attente d'appels à
- * getChildLine.
+ * Lit les l'ensemble des données dans le pipe de communication avec le processus fils et les stocke dans l'attente d'appels à getChildLine.
*/
virtual void fillChildBuffer ( );
@@ -383,12 +390,11 @@ class Process
* @param Si true, ajoute un caractère de fin de ligne après
* la chaine.
*/
- virtual void appendChildBuffer (
- const IN_STD string& str, bool newLine = true);
+ virtual void appendChildBuffer (const IN_STD string& str, bool newLine = true);
/**
* Appelé lorsqu'un processus fils est fini. Marque l'instance comme terminée.
- *iDepuis la version 4.4.0 ne détruit plus l'instance associée si isWaited retourne false.
+ * Depuis la version 4.4.0 ne détruit plus l'instance associée si isWaited retourne false.
* @param nature du signal reçu.
* @param informations sur l'origine du signal
* @param contexte d'appel du signal
@@ -417,13 +423,10 @@ class Process
/** Le caractère "terminé" de l'instance. */
bool _completed;
- /** Vaut true si un pipe de communication doit être ouvert de la sortie
- * standard du processus fils vers le processus père. */
+ /** Vaut true si un pipe de communication doit être ouvert de la sortie standard du processus fils vers le processus père. */
bool _childToSonCommunications;
- /** Vaut true si les communications du processus fils vers le processus
- * père sont bloquantes, false dans le cas contraire. Vaut true par
- * défaut.
+ /** Vaut true si les communications du processus fils vers le processus père sont bloquantes, false dans le cas contraire. Vaut true par défaut.
*/
bool _blockingCommunications;
@@ -447,8 +450,7 @@ class Process
int _completionCode;
/** Le message d'erreur associé à une terminaison anormale. */
-// IN_STD string _errorMessage; // v 4.4.0
- char _errorMessage [PROCESS_ERROR_MESSAGE_SIZE];// v 4.4.0
+ char _errorMessage [PROCESS_ERROR_MESSAGE_SIZE];
/** La table comprenant les ids des tâches et les pointeurs sur les instances associées de cette classe.
*/
diff --git a/src/TkUtilScripting/CMakeLists.txt b/src/TkUtilScripting/CMakeLists.txt
index 565c596..f8da659 100644
--- a/src/TkUtilScripting/CMakeLists.txt
+++ b/src/TkUtilScripting/CMakeLists.txt
@@ -26,6 +26,7 @@ file (GLOB CPP_SOURCES *.i *.cpp)
# => dans cette version on ne génère que _TkUtilScripting qui sera utilisé directement depuis les scripts comme par les exécutables.
set (ALL_TARGETS TkUtilScripting)
set_property (SOURCE TkUtilScripting.i PROPERTY CPLUSPLUS ON)
+set_property (SOURCE TkUtilScripting.i PROPERTY USE_SWIG_DEPENDENCIES TRUE)
swig_add_library (TkUtilScripting TYPE SHARED LANGUAGE PYTHON SOURCES ${CPP_SOURCES})
cmake_policy (SET CMP0086 NEW)
set_source_files_properties (TkUtilScripting.i PROPERTIES SWIG_MODULE_NAME TkUtil)
@@ -39,7 +40,7 @@ if (SWIG_VERSION VERSION_GREATER 4)
list (APPEND MT_SWIG_COMPILE_OPTIONS "-doxygen")
endif (SWIG_VERSION VERSION_GREATER 4)
# Avec cmake_policy (SET CMP0086 NEW) -module ${SWIG_MODULE_NAME} devrait être automatiquement passé, SWIG_MODULE_NAME étant défini comme propriété du fichier swig. Mais ...
-swig_link_libraries (TkUtilScripting PUBLIC TkUtil ${Python_LIBRARIES})
+target_link_libraries (TkUtilScripting PUBLIC TkUtil ${Python_LIBRARIES})
target_include_directories (TkUtilScripting PUBLIC $$)
foreach (lib ${ALL_TARGETS})
target_include_directories (TkUtilScripting PRIVATE ${Python_INCLUDE_DIRS})
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 50081c5..fbbad54 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -3,9 +3,9 @@ include (${GUIToolkitsVariables_CMAKE_DIR}/common.cmake)
include (${GUIToolkitsVariables_CMAKE_DIR}/workarounds.cmake)
set (ALL_EXECUTABLES
- ansi_esc_codes canceled_threads conversions date exceptions
+ ansi_esc_codes canceled_threads conversions date dir_list exceptions
fileExtractor fileinfos fileopts hostinfos joinable locale
- logs memory modify_script remoteProcess removefile script_tags
+ logs memory modify_script process remoteProcess removefile script_tags
scripting_logs thread_manager thread_pool timer tmpfile
unicode urlfifo user_representation userinfos utf8 utf8chars
)
diff --git a/src/tests/dir_list.cpp b/src/tests/dir_list.cpp
new file mode 100644
index 0000000..96e2696
--- /dev/null
+++ b/src/tests/dir_list.cpp
@@ -0,0 +1,56 @@
+/**
+ * Test simple de la classe File pour avoir la composition d'un répertoire.
+ */
+#include "TkUtil/Exception.h"
+#include "TkUtil/File.h"
+
+#include
+#include
+
+
+USING_STD
+USING_UTIL
+
+
+
+int main (int argc, char* argv [], char* envp[])
+{
+ if (2 != argc)
+ {
+ cout << "Syntax : " << argv [0] << " directory" << endl;
+ return -1;
+ } // if (2 != argc))
+
+ try
+ {
+ File dir (argv [1]);
+ vector directories, files;
+ dir.getChildren (directories, files);
+
+ cout << dir.getFullFileName ( ) << "directories : " << endl;
+ for (vector::const_iterator itd = directories.begin ( ); directories.end ( ) != itd; itd++)
+ cout << (*itd).getFileName ( ) << ' ';
+ cout << endl;
+ cout << dir.getFullFileName ( ) << "files : " << endl;
+ for (vector::const_iterator itf = files.begin ( ); files.end ( ) != itf; itf++)
+ cout << (*itf).getFileName ( ) << ' ';
+ cout << endl;
+ }
+ catch (const Exception& exc)
+ {
+ cout << "Exception caught : " << exc.getFullMessage ( ) << endl;
+ return -1;
+ }
+ catch (const exception& e)
+ {
+ cout << "Standard exception caught : " << e.what ( ) << endl;
+ return -1;
+ }
+ catch (...)
+ {
+ cout << "Undocumented exception caught." << endl;
+ return -1;
+ }
+
+ return 0;
+} // main
diff --git a/src/tests/process.cpp b/src/tests/process.cpp
new file mode 100644
index 0000000..6da8517
--- /dev/null
+++ b/src/tests/process.cpp
@@ -0,0 +1,71 @@
+/**
+ * Test simple de la classe Process avec récupération de la sortie standard du processus détaché.
+ */
+#include "TkUtil/Exception.h"
+#include "TkUtil/Process.h"
+
+#include
+#include
+
+
+USING_STD
+USING_UTIL
+
+
+
+int main (int argc, char* argv [], char* envp[])
+{
+ if (2 != argc)
+ {
+ cout << "Syntax : " << argv [0] << " directory" << endl;
+ return -1;
+ } // if (2 != argc))
+
+ try
+ {
+ Process::initialize (envp);
+
+ unique_ptr process (new Process ("ls"));
+ process->getOptions ( ).addOption ("-al");
+ process->getOptions ( ).addOption (argv [1]);
+ cout << "Cmd line is : " << process->getCommandLine ( ) << endl;
+ process->enableChildToSonCommunications (true);
+ process->execute (false);
+ const int status = process->wait ( );
+ cout << "Process standard output :" << endl;
+ bool completed = false;
+ while (false == completed)
+ {
+ try
+ {
+ const string output = process->getChildLine ( );
+ cout << output << endl;
+ }
+ catch (...)
+ {
+ completed = true;
+ }
+ } // while (false == completed)
+ if (0 != status)
+ cout << "Process failed : " << process->getErrorMessage ( ) << endl;
+
+ return status;
+ }
+ catch (const Exception& exc)
+ {
+ cout << "Exception caught : " << exc.getFullMessage ( ) << endl;
+ return -1;
+ }
+ catch (const exception& e)
+ {
+ cout << "Standard exception caught : " << e.what ( ) << endl;
+ return -1;
+ }
+ catch (...)
+ {
+ cout << "Undocumented exception caught." << endl;
+ return -1;
+ }
+
+ return 0;
+} // main
diff --git a/versions.txt b/versions.txt
index 01e8940..d8f6a2b 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,3 +1,14 @@
+Version 6.10.0 : 04/10/24
+=================
+
+Process::wait : correctif. Retourne getCompletionCode ( ) si déjà achevé à la place de lever une exception.
+Affecte des processus très brefs type "ls" dont on veut avoir un retour. Le programme test src/tests/process.cpp illustre un usage de ce type.
+
+Méthode File::getChildren retournant la liste des sous-répertoires et fichiers. Le programme test src/tests/dir_list.cpp illustre son usage.
+
+TkUtilScripting : retouches utilisation de swig (target_link_libraries, USE_SWIG_DEPENDENCIES).
+
+
Version 6.9.0 : 06/09/24
================