Commit c3dff986 authored by Arnaud Blanchard's avatar Arnaud Blanchard
Browse files

Add function to manage semaphores(ideally for blc_channel

parent c64ea816
......@@ -73,6 +73,8 @@ void *blc_command_interpret_loop(char const *option);
///Start a thread listinning to the user entry without blocking.
void blc_command_interpret_thread(char const *option, void (*ask_quitting_funtion)());
void blc_command_interpret_block();
///Display the list of blc_command with help.
void blc_command_display_help();
......@@ -80,13 +82,31 @@ void blc_command_update_float_cb(char const *argument, void *float_pt);
void blc_command_update_double_cb(char const *argument, void *double_pt);
void blc_command_update_int_cb(char const *argument, void *int_pt);
int blc_loop_try_add_waiting_semaphore(void *semaphore);
int blc_loop_try_add_posting_semaphore(void *semaphore);
/**The loop will start only once the semaphore is available.
The waiting time does not count is the loop timing.
When quitind these semaphores will be posted to be unlock the waiting loop
We use void* instead of sem_t* to not force every body to include semaphore.h*/
void blc_loop_add_waiting_semaphore(void *semaphore);
/**In the end the loop, this sempahore will be posted
We use void* instead of sem_t* to not force every body to include semaphore.h*/
void blc_loop_add_posting_semaphore(void *semaphore);
/**The loop willt start only once the waiting_callback callback will be executed.
The waiting time does not count is the loop timing*/
void blc_loop_add_waiting_callback( void(*waiting_callback)(void*), void *user_data);
/// Loop period in ms. If loop period = BLC_LOOP_NON_STOP the system is as fast as possible, if it is BLC_LOOP_BLOCK , it is command with return on stdin. If itis BLC_LLOP_THREAD it starts a parrallel thread to interpret command. In this latter case do not use stdin yourself.
void blc_command_loop_init(long loop_period);
int blc_command_loop_start();
void blc_command_loop_end();
/**Wait until the blc_loop_stop.
Return the loop_thred pointer (always NULL for now)*/
void *blc_loop_wait_stop();
/** Stop a textual program
* - Send a quitting message with the name of the app on stderr.
* - Send 'q' and flush on stdout if it is a piped output
......
......@@ -85,6 +85,10 @@ void blc_program_option_display_help();
* - set internal variables setting if the input and output terminal are tty*/
void blc_program_init(int *argc, char ***argv, void(*exit_cb)(void));
/** Check wether threre is no more argument to parse. Otherwise publish information and quit.
This should be used after 'blc_program_init', 'blc_program_option_interpret', or 'blc_program_option_interpret_and_print_title' if you do not plan to parse them yourself.*/
void blc_program_check_full_parsing(int argc, char **argv);
/** Stop a textual program
* - Send a quitting message with the name of the app on stderr.
* - Send 'q' and flush on stdout if it is a piped output
......
......@@ -57,44 +57,13 @@ static int blc_commands_nb = 0;
static sem_t *sems_to_unlock=NULL;
static int sems_to_unlock_nb=0;
void pause_cb()
{
if (blc_status==BLC_RUN){
blc_status=BLC_PAUSE;
fprintf(stderr, "=== %s: pause ===\n", blc_program_name);
blc_command_interpret();
}else {
fprintf(stderr, "=== %s: running ===\n", blc_program_name);
blc_status=BLC_RUN;
}
}
void blc_loop_sem_to_unlock_on_stop(void *sem){
APPEND_ITEM(&sems_to_unlock, &sems_to_unlock_nb, &sem);
}
void blc_command_ask_quit(){
sem_t *sem;
blc_status=BLC_QUIT;
FOR_EACH(sem, sems_to_unlock, sems_to_unlock_nb ){
while (sem_trywait(sem)!=0){
if (errno==EAGAIN) sem_post(sem);
else EXIT_ON_SYSTEM_ERROR("unlocking semaphore");
}
sem_post(sem);
}
if (blc_command_loop_period==-2){ //thread
sleep(10);
fprintf(stderr, "=== %s: error program not quitting ! We force it. ===\n", blc_program_name);
exit(EXIT_FAILURE);
}
}
START_EXTERN_C
void blc_command_display_help()
......@@ -117,7 +86,6 @@ void blc_command_display_help()
}
}
void blc_command_add(const char *command_name, type_blc_command_cb callback, const char *prompt, const char *help, void *user_data){
blc_command tmp_command;
int i;
......@@ -175,7 +143,7 @@ void blc_command_interpret_string(char const *input_string, size_t size){
if (command < blc_commands) fprintf(stderr, "Unknown command in: %s\n", input_string);
}
static void blc_command_interpret_block(){
void blc_command_interpret_block(){
char *line=NULL;
size_t line_capability=0;
ssize_t line_size;
......@@ -234,23 +202,16 @@ int blc_command_try_to_interpret(){
return 1;
}
/// if the parameter is not null we should display the help at each command.
void *command_thread_interpret_loop(void *){
while(blc_status==BLC_RUN){
blc_command_interpret();
}
return NULL;
}
/*
void blc_command_interpret_thread(char const *option, void (*ask_quit_funcion)()){
pthread_t thread;
if (ask_quit_funcion==NULL) ask_quit_funcion=blc_command_ask_quit;
blc_command_loop_period=-2;
// if (strchr(option, 'h')) blc_command_add("h", (type_blc_command_cb)blc_command_display_help, NULL, "display this help", NULL);
// if (strchr(option, 'q')) blc_command_add("q", (type_blc_command_cb)ask_quit_funcion, NULL, "quit the application", NULL);
if (strchr(option, 'h')) blc_command_add("h", (type_blc_command_cb)blc_command_display_help, NULL, "display this help", NULL);
if (strchr(option, 'q')) blc_command_add("q", (type_blc_command_cb)ask_quit_funcion, NULL, "quit the application", NULL);
SYSTEM_ERROR_CHECK(pthread_create(&thread, NULL, command_thread_interpret_loop, NULL), -1, NULL);
}
}*/
void blc_command_update_int_cb(char const *argument, void *int_pt){
char *endptr;
......
......@@ -5,6 +5,7 @@
#include <errno.h> //errno
#include <time.h> //nanosleep
#include <sys/time.h> //gettimeofday
#include <pthread.h> //pthread_mutex
static struct timeval timer;
static uint blc_period=0;
......@@ -14,23 +15,41 @@ static uint blc_duration_min=UINT_MAX, blc_duration_max=0;
static long blc_current_duration;
static int intermediate_iteration;
long blc_command_loop_period;
long blc_command_loop_period=-2; //unitialised
int blc_loop_iteration;
static void(**waiting_callbacks)(void*)=NULL;
static void **waiting_callabacks_user_data=NULL;
static int waiting_callbacks_nb=0;
static sem_t **waiting_semaphores;
static int waiting_semaphores_nb;
static sem_t **posting_semaphores;
static int posting_semaphores_nb;
static pthread_t loop_thread, loop_check_stuck_thread;
static pthread_mutex_t mutex_lock_keyboard=PTHREAD_MUTEX_INITIALIZER;
#include "blc_program.h"
type_blc_status blc_status=BLC_RUN;
void blc_fprint_stats(FILE *file)
{
fprintf(file, "%d iterations, average duration: %.3fms [%.3f, %.3f], average frequency: %.3fHz period: %.3fms\n", intermediate_iteration, blc_duration/(1000.f*intermediate_iteration), blc_duration_min/1000., blc_duration_max/1000., 1e6*intermediate_iteration/(double)blc_period, blc_period/(1000.*intermediate_iteration));
intermediate_iteration=0;
blc_period=0;
blc_duration=0;
blc_duration_min=UINT_MAX;
blc_duration_max=0;
if (intermediate_iteration){
fprintf(file, "%s: %d iterations, average duration: %.3fms [%.3f, %.3f], average frequency: %.3fHz period: %.3fms\n", blc_program_name, intermediate_iteration, blc_duration/(1000.f*intermediate_iteration), blc_duration_min/1000., blc_duration_max/1000., 1e6*intermediate_iteration/(double)blc_period, blc_period/(1000.*intermediate_iteration));
intermediate_iteration=0;
blc_period=0;
blc_duration=0;
blc_duration_min=UINT_MAX;
blc_duration_max=0;
}
else fprintf(file, "%s: No new iteration yet\n", blc_program_name);
gettimeofday(&timer, NULL);
}
......@@ -38,57 +57,181 @@ static void display_stats(){
blc_fprint_stats(stderr);
}
void blc_loop_add_waiting_callback( void(*waiting_callback)(void*), void *user_data){
MANY_REALLOCATIONS(&waiting_callbacks, waiting_callbacks_nb+1);
MANY_REALLOCATIONS(&waiting_callabacks_user_data, waiting_callbacks_nb+1);
waiting_callbacks[waiting_callbacks_nb]=waiting_callback;
waiting_callabacks_user_data[waiting_callbacks_nb]=user_data;
waiting_callbacks_nb++;
}
int blc_loop_try_add_waiting_semaphore(void *semaphore){
if (semaphore==NULL) return 0;
APPEND_ITEM(&waiting_semaphores, &waiting_semaphores_nb, &semaphore);
return 1;
}
int blc_loop_try_add_posting_semaphore(void *semaphore){
if (semaphore==NULL) return 0;
APPEND_ITEM(&posting_semaphores, &posting_semaphores_nb, &semaphore);
return 1;
}
void blc_loop_add_waiting_semaphore(void *semaphore){
if (blc_loop_try_add_waiting_semaphore(semaphore)==0) EXIT_ON_ERROR("The semaphore you want to add is NULL");
}
void blc_loop_add_posting_semaphore(void *semaphore){
if (blc_loop_try_add_posting_semaphore(semaphore)==0) EXIT_ON_ERROR("The semaphore you want to add is NULL");
}
void blc_command_ask_quit(){
sem_t **sem;
if (blc_status==BLC_PAUSE) BLC_PTHREAD_CHECK(pthread_mutex_unlock(&mutex_lock_keyboard), NULL);
blc_status=BLC_QUIT;
FOR_EACH(sem, waiting_semaphores, waiting_semaphores_nb ){
while (sem_trywait(*sem)!=0){
if (errno==EAGAIN) sem_post(*sem);
else EXIT_ON_SYSTEM_ERROR("unlocking semaphore");
}
sem_post(*sem);
}
}
void pause_cb()
{
if (blc_status==BLC_RUN){
blc_status=BLC_PAUSE;
fprintf(stderr, "=== %s: pause ===\n", blc_program_name);
}else {
blc_status=BLC_RUN;
BLC_PTHREAD_CHECK(pthread_mutex_unlock(&mutex_lock_keyboard), NULL);
fprintf(stderr, "=== %s: running ===\n", blc_program_name);
}
}
static void *loop_check_stuck(void*){
int iteration;
int checking_time=5;
int was_stucked=0;
while(1){
iteration = blc_loop_iteration;
sleep(checking_time);
if (iteration==blc_loop_iteration) {
color_eprintf(BLC_YELLOW, "'%s' seems blocked on iteration '%d'. The loop has been stopped for more than %ds\n", blc_program_name, iteration, checking_time);
was_stucked=1;
}
else if (was_stucked) {
color_eprintf(BLC_GREEN, "'%s' program restart iteration '%d'.\n", blc_program_name, iteration);
was_stucked=0;
}
}
return NULL;
}
/// if the parameter is not null we should display the help at each command.
static void *command_thread_interpret_loop(void *){
while(blc_status!=BLC_QUIT){
blc_command_interpret_block();
if (blc_command_loop_period==-1) BLC_PTHREAD_CHECK(pthread_mutex_unlock(&mutex_lock_keyboard), NULL);
//blc_command_interpret();
}
return NULL;
}
void blc_command_loop_init(long loop_period)
{
if (blc_command_loop_period!=-2) EXIT_ON_ERROR("You already launch a loop");
blc_loop_iteration=0;
intermediate_iteration=0;
blc_command_loop_period=loop_period;
if (blc_input_terminal && (blc_command_loop_period!=-1) && (blc_command_loop_period!=-2)) blc_command_add("", (type_blc_command_cb)pause_cb, NULL, "set on/off pause", NULL);
if (blc_command_loop_period!=-2){
blc_command_add("h", (type_blc_command_cb)blc_command_display_help, NULL, "display this help", NULL);
blc_command_add("q", (type_blc_command_cb)blc_command_ask_quit, NULL, "quit the application", NULL);
BLC_PTHREAD_CHECK(pthread_mutex_lock(&mutex_lock_keyboard), NULL);
if (blc_input_terminal){
blc_command_display_help(); //We display help only for keyboard
if (blc_command_loop_period!=-1) blc_command_add("", (type_blc_command_cb)pause_cb, NULL, "set on/off pause", NULL);
}
if (blc_command_loop_period!=-1) blc_command_add("s", (type_blc_command_cb)display_stats, NULL, "display time stats", NULL);
if (blc_input_terminal) blc_command_display_help();
/* if (blc_command_loop_period!=-1)
if (blc_command_loop_period==-2);*/
fprintf(stderr, "=== %s: running ===\n", blc_program_name);
blc_command_interpret_thread("hq", NULL);
blc_command_add("h", (type_blc_command_cb)blc_command_display_help, NULL, "display this help", NULL);
blc_command_add("q", (type_blc_command_cb)blc_command_ask_quit, NULL, "quit the application", NULL);
if (loop_period!=-1) { //we lock on keyboard. But if the program lock we still read keyboard
SYSTEM_ERROR_CHECK(pthread_create(&loop_check_stuck_thread, NULL, loop_check_stuck, NULL), -1, NULL);
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_name);
}
SYSTEM_ERROR_CHECK(pthread_create(&loop_thread, NULL, command_thread_interpret_loop, NULL), -1, NULL);
}
int blc_command_loop_start(){
if (intermediate_iteration==0) blc_us_time_diff(&timer);
else blc_period+=blc_current_duration+blc_us_time_diff(&timer);
switch (blc_command_loop_period){
case -1: blc_command_interpret();break;
case -2: break;
default:;//blc_command_try_to_interpret();
int i;
//We wait before counting the duration time as the time for waiting does not matter
//We eventiualy wait for keyboard return key
if ((blc_status==BLC_PAUSE) || (blc_command_loop_period==-1)) BLC_PTHREAD_CHECK(pthread_mutex_lock(&mutex_lock_keyboard), NULL);
else if (blc_status==BLC_RUN){
//We wait for semaphore
FOR(i, waiting_semaphores_nb) SYSTEM_ERROR_CHECK(sem_wait(waiting_semaphores[i]), -1, NULL);
//Waiting general user defined callbacks
FOR(i, waiting_callbacks_nb) waiting_callbacks[i](waiting_callabacks_user_data[i]);
}
else blc_command_loop_period=-2; //In case we start another loop after
//We start counting the duration time
if (intermediate_iteration==0) blc_us_time_diff(&timer);
else blc_period+=blc_current_duration + blc_us_time_diff(&timer);
return blc_status;
}
void blc_command_loop_end(){
div_t ratio;
struct timespec time_left;
int diff;
struct timespec time_left, tmp_rem;
int diff, i;
if (blc_status==BLC_QUIT) EXIT_ON_ERROR("You have stopped the loop, you should not access here");
//We post the semaphore usualy to say the data is ready to read
FOR(i, posting_semaphores_nb) SYSTEM_ERROR_CHECK(sem_post(posting_semaphores[i]), -1, NULL);
blc_current_duration=blc_us_time_diff(&timer);
blc_duration+=blc_current_duration;
if (blc_duration<blc_duration_min) blc_duration_min=blc_duration;
else if (blc_duration > blc_duration_max) blc_duration_max=blc_duration;
if (blc_current_duration<blc_duration_min) blc_duration_min=blc_current_duration;
else if (blc_current_duration > blc_duration_max) blc_duration_max=blc_current_duration;
if (blc_command_loop_period > 0){
diff=blc_command_loop_period - blc_current_duration;
ratio=div(diff, 1e6);
time_left.tv_sec = ratio.quot;
time_left.tv_nsec = ratio.rem*1e9;
if (diff < 0) color_fprintf(BLC_YELLOW, stderr, "\rMissing %.3fms in the BLC_COMMAND_LOOP", diff/1000.f);
else SYSTEM_ERROR_RETRY_ON_SPECIFIC_ERRNO(nanosleep(&time_left, &time_left), 0, EINTR, "Time left %.3fms", time_left.tv_nsec/1e6f + time_left.tv_sec*1000);
time_left.tv_nsec = ratio.rem*1000;
if (diff < 0) color_fprintf(BLC_YELLOW, stderr, "\rMissing %.3fms in the BLC_COMMAND_LOOP", -diff/1000.f);
else SYSTEM_ERROR_RETRY_ON_SPECIFIC_ERRNO(nanosleep(&time_left, &tmp_rem), -1, EINTR, "Time left %.3fms", tmp_rem.tv_nsec/1e6f + tmp_rem.tv_sec*1000);
/* Warning the nanosleep can be overtimed of 10ms !!! it is the same for usleep !! */
}
intermediate_iteration++;
blc_loop_iteration++;
}
void *blc_loop_wait_stop(){
void *result;
SYSTEM_ERROR_CHECK(pthread_join(loop_thread, &result), -1, NULL);
return result;
}
......@@ -13,8 +13,6 @@
 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. */
#include "blc_program.h"
#include "program.hpp" // internal to blc
......@@ -201,22 +199,69 @@ void blc_program_add_output_pipe_option(FILE *file, char letter, char const *lon
APPEND_ITEM(&blc_program_options, &blc_program_options_nb, &tmp_program_option);
}
static void blc_program_interpret_parameters(int *argc, char **argv[]){
char *tmp_parameter=NULL, *tmp_arg;
int missing_parameters_nb;
int i, j;
size_t linecap;
ssize_t parameter_read;
FOR(i, blc_program_parameters_nb){
switch(blc_program_parameters[i].type){
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);
SYSTEM_ERROR_CHECK(parameter_read=getline(&tmp_parameter, &linecap, stdin), -1, "Reading input for parameter");
tmp_parameter[parameter_read-1]=0;//Remove the last return;
(*blc_program_parameters[i].string_pt)=tmp_parameter;
linecap=0;
tmp_parameter=NULL;
// }else EXIT_ON_ERROR("Missing '%s' argument : %s", blc_program_parameters[i].name, blc_program_parameters[i].help);
}
else *blc_program_parameters[i].string_pt=blc_program_parameters[i].default_value;
}
else {
*blc_program_parameters[i].string_pt=(*argv)[0];
(*argc)--;
(*argv)++;
}
break;
case STRING_LIST: EXIT_ON_ERROR("STRING LIST is not yet managed");
if (isatty(STDIN_FILENO)) {
missing_parameters_nb = blc_program_parameters[i].required_nb-(*argc-optind-i);
if (missing_parameters_nb>0){
FOR(j, missing_parameters_nb){
fprintf(stderr, "%s: %s? ", blc_program_parameters[i].help, blc_program_parameters[i].name);
linecap=0;
SYSTEM_ERROR_CHECK(parameter_read=getline(&tmp_arg, &linecap, stdin), -1, "Reading input for parameter"); //getline(blc_program_parameters[i].string_pt, sizeof(blc_program_parameters[i].string_pt), stdin), NULL, "Wrong channel input name");
tmp_arg[parameter_read-1]=0;//Remove the last return;
APPEND_ITEM(argv, argc, &tmp_arg);
}
parameter_read=0;
APPEND_ITEM(argv, argc, &parameter_read);
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];
break;
}
}
}
void blc_program_option_interpret(int *argc, char **argv[])
{
char *optstring, *tmp_arg;
char *optstring;
int ret, option_index;
int optstring_size=0;
int options_nb=0;
int missing_parameters_nb;
int i, j;
struct option *long_options = NULL, tmp_option;
struct stat stat_data;
type_program_option *program_option;
char pipe_name[PATH_MAX+1];
char *tmp_parameter=NULL;
size_t linecap;
ssize_t parameter_read;
blc_program_name = basename(*argv[0]);
......@@ -297,46 +342,11 @@ void blc_program_option_interpret(int *argc, char **argv[])
break;
}
}
(*argc)-=optind;
(*argv)+=optind;
//Now, parse parameters
FOR(i, blc_program_parameters_nb){
switch(blc_program_parameters[i].type){
case STRING :
if ((i+optind)>=(*argc)){//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);
SYSTEM_ERROR_CHECK(parameter_read=getline(&tmp_parameter, &linecap, stdin), -1, "Reading input for parameter");
tmp_parameter[parameter_read-1]=0;//Remove the last return;
(*blc_program_parameters[i].string_pt)=tmp_parameter;
linecap=0;
tmp_parameter=NULL;
// }else EXIT_ON_ERROR("Missing '%s' argument : %s", blc_program_parameters[i].name, blc_program_parameters[i].help);
}
else *blc_program_parameters[i].string_pt=blc_program_parameters[i].default_value;
}
else *blc_program_parameters[i].string_pt=(*argv)[i+optind];
break;
case STRING_LIST:
if (isatty(STDIN_FILENO)) {
missing_parameters_nb = blc_program_parameters[i].required_nb-(*argc-optind-i);
if (missing_parameters_nb>0){
FOR(j, missing_parameters_nb){
fprintf(stderr, "%s: %s? ", blc_program_parameters[i].help, blc_program_parameters[i].name);
linecap=0;
SYSTEM_ERROR_CHECK(parameter_read=getline(&tmp_arg, &linecap, stdin), -1, "Reading input for parameter"); //getline(blc_program_parameters[i].string_pt, sizeof(blc_program_parameters[i].string_pt), stdin), NULL, "Wrong channel input name");
tmp_arg[parameter_read-1]=0;//Remove the last return;
APPEND_ITEM(argv, argc, &tmp_arg);
}
parameter_read=0;
APPEND_ITEM(argv, argc, &parameter_read);
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];
break;
}
}
blc_program_interpret_parameters(argc, argv);
}
void blc_program_option_interpret_and_print_title(int *argc, char ***argv){
......@@ -414,29 +424,29 @@ void blc_program_option_display_help()
}
static void on_sigterm(int){
fprintf(stderr, "\nReceiving SIGTERM (kill)\n");
fprintf(stderr, "\n%s: receiving SIGTERM (kill)\n", blc_program_name);
exit(EXIT_SUCCESS);
}
static void on_sigint(int){
if (blc_status==BLC_QUIT){
fprintf(stderr, "\n\nReceiving SIGINT (Ctrl+C) in quiting mode. Force to quit.\n\n\n");
fprintf(stderr, "\n\n%s: receiving SIGINT (Ctrl+C) in quiting mode. Force to quit.\n\n\n", blc_program_name);
exit(EXIT_FAILURE);
}
else {
fprintf(stderr, "\nReceiving SIGINT (Ctrl+C). Try to quit. Resend SIGINT if it does not quit.\n\n");
fprintf(stderr, "\n%s :receiving SIGINT (Ctrl+C). Try to quit. Resend SIGINT if it does not quit.\n\n", blc_program_name);
blc_status=BLC_QUIT;
}
}
static void on_sigsegv(int){
fprintf(stderr, "\n\nSegmentation fault ( memory access error ! )\n\n\n");
fprintf(stderr, "\n\n%s: segmentation fault ( memory access error ! )\n\n\n", blc_program_name);
exit(EXIT_FAILURE);
}
//Normal exit is not called with value of 1 in exit
static void on_sigabrt(int ){
fprintf(stderr, "\nReceiving SIGABORT ( error ! )\n");
fprintf(stderr, "\n%s: receiving SIGABORT ( error ! )\n", blc_program_name);
exit(EXIT_FAILURE);
}
......@@ -469,6 +479,8 @@ void blc_program_init(int *argc, char ***argv, void (*exit_cb)(void))
blc_program_add_option(&help, 'h', "help", 0, "display this help", NULL);
blc_program_option_interpret_and_print_title(argc, argv);
blc_program_check_full_parsing(*argc, *argv);
if (help){
blc_program_option_display_help();
......@@ -479,6 +491,18 @@ void blc_program_init(int *argc, char ***argv, void (*exit_cb)(void))
if (exit_cb) atexit(exit_cb); //This will be called first
}
void blc_program_check_full_parsing(int argc, char **argv){
int i;
if (argc!=0) {
blc_program_option_display_help();
fprintf(stderr, "Unused arguments:");
FOR(i, argc) fprintf(stderr, "'%s' ", argv[i]);
fprintf(stderr, "\n");
EXIT_ON_ERROR("Somme arguments are wrong, they have not been parsed.");
}
}
void blc_quit()
{
fprintf(stderr, "Quitting %s\n", blc_program_name);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment