From 90e8c18b7aae597bc6fad4eebe480d345880d72d Mon Sep 17 00:00:00 2001
From: Arnaud Blanchard <arnaud.blanchard@ensea.fr>
Date: Tue, 16 Jul 2019 18:23:26 +0200
Subject: [PATCH] Add example

---
 CMakeLists.txt                  |  2 +-
 src/blc_loop.cpp                |  8 +--
 src/blc_program.cpp             | 87 ++++++++++++++++++++++-----------
 t_interactive/CMakeLists.txt    | 22 +++++++++
 t_interactive/t_interactive.cpp | 32 ++++++++++++
 t_interactive/test_result.log   | 19 +++++++
 6 files changed, 135 insertions(+), 35 deletions(-)
 create mode 100644 t_interactive/CMakeLists.txt
 create mode 100644 t_interactive/t_interactive.cpp
 create mode 100644 t_interactive/test_result.log

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6a6f831..c7d294b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,7 +18,7 @@ find_package(blc_core REQUIRED)
 #source files
 set(sources src/blc_loop.cpp src/blc_program.cpp src/blc_command.cpp)
 
-add_definitions(${BL_DEFINITIONS})
+add_definitions(${BL_DEFINITIONS} -std=c++14)
 include_directories(include ${BL_INCLUDE_DIRS})
 
 #shared lib
diff --git a/src/blc_loop.cpp b/src/blc_loop.cpp
index dd895d0..7cf82ce 100644
--- a/src/blc_loop.cpp
+++ b/src/blc_loop.cpp
@@ -1,6 +1,4 @@
 
-#include "blc_command.h"
-#include "blc_realtime.h"
 #include <unistd.h> //sleep
 #include <errno.h> //errno
 #include <math.h> //pthread_mutex
@@ -203,7 +201,6 @@ void blc_command_loop_init(long loop_period){
     intermediate_iteration=0;
     blc_command_loop_period=loop_period;
     
-    //If blc_command_loop_period==2 we execute an iteration before stopping
     if (blc_command_loop_period==-2){
         blc_command_loop_period=-1;
     }
@@ -223,14 +220,13 @@ void blc_command_loop_init(long loop_period){
         blc_command_add("s", (type_blc_command_cb)display_stats, NULL, "display time stats", NULL); //We did not do stat on keyboard
         fprintf(stderr, "=== %s: running ===\n", blc_program_id);
     }
-    blc_command_add("|", (type_blc_command_cb)blc_command_send_to_stdout, "command", "send the command to stdout", NULL);
-    blc_command_add("&", (type_blc_command_cb)blc_command_send_to_all, "command", "intepret caommdn and send it to stdout", NULL);
+    blc_command_add("|", (type_blc_command_cb)blc_command_send_to_stdout, "command", "sends the command to stdout", NULL);
+    blc_command_add("&", (type_blc_command_cb)blc_command_send_to_all, "command", "inteprets command and sends it to stdout", NULL);
 
     BLC_PTHREAD_CHECK(pthread_create(&loop_thread, NULL, command_thread_interpret_loop, NULL), NULL);
 }
 
 int blc_command_loop_start(){
-    int continue_value;
     int i;
     //We wait before counting the duration time as the time for waiting does not matter
     
diff --git a/src/blc_program.cpp b/src/blc_program.cpp
index 627c3d2..5c00bcf 100644
--- a/src/blc_program.cpp
+++ b/src/blc_program.cpp
@@ -105,7 +105,7 @@ void blc_program_add_parameter(char const**result, char const *name, int require
     parameter.required_nb=(required!=0); //At this moment only binary choices are possible
     parameter.help=help;
     parameter.default_value=default_value;
-
+    
     APPEND_ITEM(&blc_program_parameters, &blc_program_parameters_nb, &parameter);
 }
 
@@ -113,18 +113,21 @@ void blc_program_add_multiple_parameters(char ***result_list, char const *name,
 {
     struct program_parameter parameter;
     
+    *result_list=nullptr;
+    
     parameter.type=STRING_LIST;
     parameter.string_list_pt=result_list;
     parameter.name=name;
     parameter.required_nb=required_nb;
     parameter.help=help;
+    parameter.default_value=nullptr;
     APPEND_ITEM(&blc_program_parameters, &blc_program_parameters_nb, &parameter);
 }
 
 void blc_program_add_option(char const **result, char letter, char const *long_option, char const *parameter, char const *help,  char const* default_value){
     type_program_option  tmp_program_option;
     
-   // if ((parameter) && (default_value)) EXIT_ON_ERROR("option '%s': you cannot required an parameter '%s' and having a default value '%s'", long_option, parameter, default_value);
+    // if ((parameter) && (default_value)) EXIT_ON_ERROR("option '%s': you cannot required an parameter '%s' and having a default value '%s'", long_option, parameter, default_value);
     
     tmp_program_option.type = STRING;
     tmp_program_option.string_pt =  result;
@@ -216,30 +219,30 @@ static void blc_program_option_interpret(int *argc, char **argv[])
                 }
                 else{
                     switch (program_option->type){
-                        case STRING:
+                            case STRING:
                             *program_option->string_pt = optarg;
                             break;
                             
                             //Pipe not in use anymore
-                        case INPUT_PIPE:
+                            case INPUT_PIPE:
                             SPRINTF(pipe_name, "/tmp/blc_pipes/%s", optarg);
                             SYSTEM_ERROR_CHECK(freopen(optarg, "r", program_option->pipe), NULL, NULL);
                             break;
-                        case OUTPUT_PIPE:
+                            case OUTPUT_PIPE:
                             mkdir("/tmp/blc_pipes", S_IRWXU);
                             SPRINTF(pipe_name, "/tmp/blc_pipes/%s", optarg);
                             if (mkfifo(pipe_name, S_IRWXU) !=0)
+                        {
+                            if (errno==EEXIST)
                             {
-                                if (errno==EEXIST)
-                                {
-                                    SYSTEM_SUCCESS_CHECK(stat(pipe_name, &stat_data), 0, "Checking data of '%s'.", pipe_name);
-                                    if (stat_data.st_mode == S_IFIFO){
-                                        SYSTEM_ERROR_CHECK(freopen(pipe_name, "w", program_option->pipe), NULL, NULL);
-                                    }
-                                    else EXIT_ON_ERROR("Cannot use '%s' as a output pipe.", pipe_name);
+                                SYSTEM_SUCCESS_CHECK(stat(pipe_name, &stat_data), 0, "Checking data of '%s'.", pipe_name);
+                                if (stat_data.st_mode == S_IFIFO){
+                                    SYSTEM_ERROR_CHECK(freopen(pipe_name, "w", program_option->pipe), NULL, NULL);
                                 }
-                                else EXIT_ON_SYSTEM_ERROR("Creating output pipe '%s'.", pipe_name);
+                                else EXIT_ON_ERROR("Cannot use '%s' as a output pipe.", pipe_name);
                             }
+                            else EXIT_ON_SYSTEM_ERROR("Creating output pipe '%s'.", pipe_name);
+                        }
                             break;
                         default:EXIT_ON_ERROR("Type %d not managed.", program_option->type);
                     }
@@ -257,7 +260,7 @@ static void blc_program_option_interpret(int *argc, char **argv[])
     FOR_EACH_INV(program_option, blc_program_options, blc_program_options_nb)
     {
         switch (program_option->type){
-            case STRING:
+                case STRING:
                 if (*program_option->string_pt==NULL) *program_option->string_pt=(char*)program_option->default_value;
                 break;
         }
@@ -273,21 +276,22 @@ static void blc_program_interpret_parameters(int *argc, char **argv[]){
     int i, j;
     size_t linecap;
     ssize_t parameter_read;
+    int list_parameters_nb=0;
     
     FOR(i, blc_program_parameters_nb){
         switch(blc_program_parameters[i].type){
-            case STRING :
+                case STRING :
                 if ((*argc)==0){//There is no more argument to interpret
                     if (blc_program_parameters[i].required_nb){
                         if (isatty(STDIN_FILENO)) fprintf(stderr, "%s: %s? ", blc_program_parameters[i].help, blc_program_parameters[i].name);
-
+                        
                         parameter_read=getline(&tmp_parameter, &linecap, stdin);
                         if (parameter_read==-1){
-                        	if (errno==ENOTTY) {
-                        		color_eprintf(BLC_RED, "Quitting '%s': The standard input is not available. You probably have a program on an input pipe which has crashed\n", blc_program_id);
-                        		exit(1);
-                        	}
-                        	else EXIT_ON_SYSTEM_ERROR("Reading input for parameter");
+                            if (errno==ENOTTY) {
+                                color_eprintf(BLC_RED, "Quitting '%s': The standard input is not available. You probably have a program on an input pipe which has crashed\n", blc_program_id);
+                                exit(1);
+                            }
+                            else EXIT_ON_SYSTEM_ERROR("Reading input for parameter");
                         }
                         tmp_parameter[parameter_read-1]=0;//Remove the last return;
                         (*blc_program_parameters[i].string_pt)=tmp_parameter;
@@ -304,7 +308,7 @@ static void blc_program_interpret_parameters(int *argc, char **argv[]){
                 }
                 break;
                 
-            case STRING_LIST: EXIT_ON_ERROR("STRING LIST is not yet managed");
+                case STRING_LIST:
                 if (isatty(STDIN_FILENO)) {
                     missing_parameters_nb = blc_program_parameters[i].required_nb-(*argc-optind-i);
                     if (missing_parameters_nb>0){
@@ -320,8 +324,35 @@ static void blc_program_interpret_parameters(int *argc, char **argv[]){
                         argc--;//The last NULL parameter does not count
                     }
                 }
-                else EXIT_ON_ERROR("Missing '%s' arguments : %s you must have %d arguments", blc_program_parameters[i].name, blc_program_parameters[i].help, missing_parameters_nb);
-                *(blc_program_parameters[i].string_list_pt)=&(*argv)[i+optind];
+                else {
+                    do{
+                        parameter_read=getline(&tmp_parameter, &linecap, stdin);
+                        if (parameter_read==-1){
+                            if (errno==ENOTTY) {
+                                color_eprintf(BLC_RED, "Quitting '%s': The standard input is not available. You probably have a program on an input pipe which has crashed\n", blc_program_id);
+                                exit(1);
+                            }
+                            else EXIT_ON_SYSTEM_ERROR("Reading input for parameter");
+                        }
+                        tmp_parameter[parameter_read-1]=0;//Remove the last return;
+                        APPEND_ITEM(blc_program_parameters[i].string_list_pt, &list_parameters_nb, tmp_parameter);
+                        linecap=0;
+                        fprintf(stderr, "Parameters '%s' %ld\n", tmp_parameter, parameter_read );
+                        tmp_parameter=nullptr;
+                    }
+                    while(parameter_read>0);
+                }//EXIT_ON_ERROR("Missing '%s' arguments : %s you must have %d arguments", blc_program_parameters[i].name, blc_program_parameters[i].help, missing_parameters_nb);
+                
+                if (blc_program_parameters[i].required_nb==-1){
+                    while((*argc)){
+                        APPEND_ITEM((blc_program_parameters[i].string_list_pt), &list_parameters_nb, **argv);
+                        (*argc)--;
+                        (*argv)++;
+                    }
+                }
+                else EXIT_ON_ERROR("Precise number of parameter is not managed");
+                APPEND_ITEM(blc_program_parameters[i].string_pt, &list_parameters_nb, tmp_parameter);
+
                 break;
         }
     }
@@ -399,9 +430,9 @@ void blc_program_args_display_help()
         fprintf(stderr, "%*c", option_length_max - tmp_length, ' ');
         fprintf(stderr, "%s", program_option->help);
         if (program_option->default_value) {
-       //     if (program_option->type==BLC_CHANNEL) fprintf(stderr, " (default: %s<pid>)\n", program_option->default_value);
-       //     else
-        	fprintf(stderr, " (default: %s)\n", program_option->default_value);
+            //     if (program_option->type==BLC_CHANNEL) fprintf(stderr, " (default: %s<pid>)\n", program_option->default_value);
+            //     else
+            fprintf(stderr, " (default: %s)\n", program_option->default_value);
         }
         else fprintf(stderr, "\n");
     }
@@ -521,6 +552,6 @@ void blc_quit()
         fprintf(stderr, "Quitting %s\n", blc_program_id);
         FREE(blc_program_id);
     }
-
+    
 }
 END_EXTERN_C
diff --git a/t_interactive/CMakeLists.txt b/t_interactive/CMakeLists.txt
new file mode 100644
index 0000000..ace3f53
--- /dev/null
+++ b/t_interactive/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright  ETIS — ENSEA, Université de Cergy-Pontoise, CNRS (2011 - 2016)
+# Author: Arnaud Blanchard (November 2016)
+#
+# This software is governed by the CeCILL v2.1 license under French law and abiding by the rules of distribution of free software.
+# You can use, modify and/ or redistribute the software under the terms of the CeCILL v2.1 license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info".
+# As a counterpart to the access to the source code and  rights to copy, modify and redistribute granted by the license,
+# users are provided only with a limited warranty and the software's author, the holder of the economic rights,  and the successive licensors have only limited liability.
+# In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or developing or reproducing the software by the user in light of its specific status of free software,
+# that may mean  that it is complicated to manipulate, and that also therefore means that it is reserved for developers and experienced professionals having in-depth computer knowledge.
+# Users are therefore encouraged to load and test the software's suitability as regards their requirements in conditions enabling the security of their systems and/or data to be ensured  and, more generally, to use and operate it in the same conditions as regards security.
+# The fact that you are presently reading this means that you have had knowledge of the CeCILL v2.1 license and that you accept its terms. 
+
+cmake_minimum_required(VERSION 2.6)
+project(t_interactive)
+
+find_package(blc_program REQUIRED)
+
+#Add your definitions, include directories, sources and libraries now
+add_definitions(${BL_DEFINITIONS})
+include_directories(${BL_INCLUDE_DIRS})
+add_executable(t_interactive t_interactive.cpp)
+target_link_libraries(t_interactive ${BL_LIBRARIES})
diff --git a/t_interactive/t_interactive.cpp b/t_interactive/t_interactive.cpp
new file mode 100644
index 0000000..1ea4eec
--- /dev/null
+++ b/t_interactive/t_interactive.cpp
@@ -0,0 +1,32 @@
+/*Demonstration of blc_program API*/
+
+#include "blc_program.h"
+
+void display_test_text(char const*, void*user_data){
+    char const* text_to_display=(char const*)user_data;
+    
+    fprintf(stderr, "\nTEST:%s\n\n", text_to_display);
+}
+
+void display_argument(char const* argument, void*user_data){
+    fprintf(stderr, "\nARGUMENT:%s\n\n", argument);
+}
+
+int main( int argc, char **argv){
+    char const*data_to_pass="Here the text to display";
+
+    fprintf(stderr, "Test BLC_COMMAND_LOOP\n");
+    
+    blc_command_add("t", display_test_text, NULL, "Call a function which display the test text", (void*)data_to_pass);
+    blc_command_add("a", display_argument, "argument to display", "Call a function which display the text passed as argument", NULL);
+
+    //Wait for keyboard and loop till 'q' or Ctrl-C
+    //-2 execute the loop once and wait for keboard
+    //-1 wait for keyboard
+    //>=0 loop without blocking at the period given in µs (0 as fast as possible)
+    
+    BLC_COMMAND_LOOP(-2){
+        blc_command_display_help();
+    }
+    return EXIT_SUCCESS;
+}
diff --git a/t_interactive/test_result.log b/t_interactive/test_result.log
new file mode 100644
index 0000000..aa121f4
--- /dev/null
+++ b/t_interactive/test_result.log
@@ -0,0 +1,19 @@
+Display help:
+
+usage: t_parse_args [-f] [-s string] string [string]
+
+Program to show how to parse arguments.
+
+positional arguments:
+  string                  Required parameter 
+  string                  Show how to accept simple text as option
+
+optional arguments:
+ -f, --flag              Show how to read a flag
+ -s, --simple string     Simple text as option (default: Default text)
+
+Parsed arguments:
+- The simple option text is: 'Default text'
+- The flag is not activated.
+- The first argument is: 'arg1'
+- The optional argument is: 'arg2'
-- 
GitLab