Commit 742d4f18 authored by Arnaud Blanchard's avatar Arnaud Blanchard
Browse files

Merge branch 'master' of https://framagit.org/blibs/blc_program

parents 43238a8c b333e340
......@@ -28,22 +28,22 @@ Few functions helping for pseudo realtime applications.
#include "blc_tools.h"
#define BLC_COMMAND_LOOP_THREAD() for(blc_command_loop_init(-2); blc_command_loop_start();blc_command_loop_end())
/**
0 for system as fast as possible, -1 for blocking on keyborad.
period in microseconds
0 for system as fast as possible, -1 for blocking on keyborad, -2 blocking after first iteration.
Warning the period can be till 10ms longer than, asked. Problem of usleep/nano sleep */
#define BLC_COMMAND_LOOP(period) for(blc_command_loop_init(period); blc_command_loop_start();blc_command_loop_end())
typedef enum {BLC_QUIT=0, BLC_RUN, BLC_PAUSE} type_blc_status;
typedef enum {BLC_QUIT=0, BLC_RUN, BLC_PAUSE, BLC_STEPS} type_blc_status;
typedef void (*type_blc_command_cb)(char const *argument, void *user_data);
extern int blc_input_terminal, blc_output_terminal;
extern type_blc_status blc_status;
extern int blc_loop_iteration;
extern uint64_t blc_loop_iteration;
extern uint64_t blc_loop_iteration_limit;
extern long blc_command_loop_period;
extern FILE *blc_profile_file;
START_EXTERN_C
......@@ -58,6 +58,9 @@ void pause_cb();
///Add a command in the list of possible command lines from the user.
void blc_command_add(const char *command_name, type_blc_command_cb callback, const char *prompt, const char *help, void *user_data);
///Remove a previously added command
void blc_command_remove(const char *command_name);
///Interpret the command passed in string.
void blc_command_interpret_string(char const *input_string, size_t size);
......@@ -98,7 +101,10 @@ 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.
/** Loop period in ms.
- 0 the system is as fast as possible
- -1 it blocks on keyboard
- -2 it blocks on keyboard after a first iteration*/
void blc_command_loop_init(long loop_period);
int blc_command_loop_start();
void blc_command_loop_end();
......
......@@ -29,20 +29,8 @@
#include "blc_core.h"
#include "blc_command.h"
START_EXTERN_C
///Add an argument to the list argv of arguments. Add eventually a value as well.
void blc_add_arg( int *argc, char ***argv, char const *arg, char const *value);
///Allocate and fill a command line with the array of argument. The array must be terminated by a NULL argument and must the returned command line me be freed after use.
///It does not handle spaces in argument !!!
char *blc_create_command_line_from_argv(char const *const *argv);
///Allocate and fill an array of argument by spiting the command_line. The array is terminated by a NULL argument and it must be freed after used.
///It does not handle spaces in argument !!!
char * const*blc_create_argv_from_command_line(char const *command_line);
///Set the desciption of the program used for help. A copy of desciption is done (strdup).
void blc_program_set_description(char const *description);
......
......@@ -97,11 +97,23 @@ void blc_command_add(const char *command_name, type_blc_command_cb callback, con
tmp_command.user_data = user_data;
FOR_INV(i, blc_commands_nb)
if (strcmp(blc_commands[i].name, command_name) == 0) EXIT_ON_ERROR("%s: command '%s' is already defined.", blc_program_name, command_name);
if (strcmp(blc_commands[i].name, command_name) == 0) EXIT_ON_ERROR("%s: command '%s' is already defined.", blc_program_id, command_name);
APPEND_ITEM(&blc_commands, &blc_commands_nb, &tmp_command);
}
void blc_command_remove(const char *command_name){
int i;
FOR_INV(i, blc_commands_nb){
if (strcmp(blc_commands[i].name, command_name) == 0) break;
}
if (i==-1) EXIT_ON_ERROR("You try to remove a command '%s' that does not exist", command_name);
REMOVE_ITEM(&blc_commands, &blc_commands_nb, i);
}
void blc_command_interpret_string(char const *input_string, size_t size){
char const*parameter;
char *parameter2;
......@@ -110,7 +122,7 @@ void blc_command_interpret_string(char const *input_string, size_t size){
const blc_command *command;
size_t name_size, line_capability=0;
FOR_EACH_INV(command, blc_commands, blc_commands_nb){
FOR_EACH(command, blc_commands, blc_commands_nb){
name_size = strlen(command->name);
if (strncmp(command->name, input_string, name_size) == 0){
parameter = input_string + name_size;
......@@ -122,19 +134,26 @@ void blc_command_interpret_string(char const *input_string, size_t size){
parameter2_size = getline(&parameter2, &line_capability, stdin)-1;
parameter2[parameter2_size]=0;
}
if (command->callback) command->callback(parameter2, command->user_data); //In which callback is NULL ??
if (command->callback == NULL) EXIT_ON_ERROR("Command callback is NULL for command '%s'", command->name);
command->callback(parameter2, command->user_data);
FREE(parameter2);
line_capability=0;
break;
break; //Command has been found
}
else{
if ((command->prompt != NULL) && (command->prompt[0]!='|')) continue; // If we do not wait for parameter, the command must be exact.
else command->callback(parameter, command->user_data);
break;
//A parameter was expected
if (command->prompt) {
command->callback(parameter, command->user_data);
break;
}
else continue; //Maybe it is a command with a longer name, we continue to check
/* if ((command->prompt != NULL) && (command->prompt[0]!='|')) continue; // If we do not wait for parameter, the command must be exact.
else
return;*/
}
}
}
if (command < blc_commands) fprintf(stderr, "%s: unknown command in: '%s'\n", blc_program_name, input_string);
if (command == blc_commands+blc_commands_nb) fprintf(stderr, "%s: unknown command in: '%s'\n", blc_program_id, input_string);
}
void blc_command_interpret_block(){
......@@ -158,7 +177,6 @@ void blc_command_interpret_block(){
else{
line_size=line_size-1;
line[line_size]=0; // Removing the last return char (\n)
blc_command_interpret_string(line, line_size);
}
FREE(line);
......
......@@ -3,6 +3,8 @@
#include "blc_realtime.h"
#include <unistd.h> //sleep
#include <errno.h> //errno
#include <math.h> //pthread_mutex
#include <time.h> //nanosleep
#include <sys/time.h> //gettimeofday
#include <pthread.h> //pthread_mutex
......@@ -16,7 +18,8 @@ static long blc_current_duration;
static int intermediate_iteration;
long blc_command_loop_period=-2; //unitialised
int blc_loop_iteration;
uint64_t blc_loop_iteration_limit=UINT64_MAX;
uint64_t blc_loop_iteration=0;
static void(**waiting_callbacks)(void*)=NULL;
static void **waiting_callabacks_user_data=NULL;
......@@ -31,6 +34,11 @@ static int posting_semaphores_nb;
static pthread_t loop_thread, loop_check_stuck_thread;
static pthread_mutex_t mutex_lock_keyboard=PTHREAD_MUTEX_INITIALIZER;
static int step_iteration;
static struct timeval step_timer, profile_timer;
static sem_t *blocking_semaphore=NULL;
#include "blc_program.h"
type_blc_status blc_status=BLC_RUN;
......@@ -38,14 +46,14 @@ type_blc_status blc_status=BLC_RUN;
void blc_fprint_stats(FILE *file)
{
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));
fprintf(file, "%-16.16s %4d iterations duration:%8.3fms[%8.3f, %8.3f] frequency:%8.3fHz period:%8.3fms\n", blc_program_id, 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);
else fprintf(file, "%s: No new iteration yet\n", blc_program_id);
gettimeofday(&timer, NULL);
}
......@@ -84,37 +92,77 @@ 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_send_to_stdout(char const *argument){
//We send the argument to stdout if it is not a terminal
static void blc_command_send_to_stdout(char const *argument){
if (blc_output_terminal==0){
if (argument) SYSTEM_ERROR_CHECK(printf("%s", argument), -1, NULL);
SYSTEM_ERROR_CHECK(printf("\n"), -1, NULL);
SYSTEM_ERROR_CHECK(fflush(stdout), -1, NULL);
}
}
//We execute the argument and send it with prefix '&' to stdout if it is not a terminal
static void blc_command_send_to_all(char const *argument){
blc_command_interpret_string(argument, strlen(argument));
if (blc_output_terminal==0){
if (argument) SYSTEM_ERROR_CHECK(printf("&%s", argument), -1, NULL);
SYSTEM_ERROR_CHECK(printf("\n"), -1, NULL);
SYSTEM_ERROR_CHECK(fflush(stdout), -1, NULL);
}
}
void blc_command_ask_quit(){
sem_t **sem;
if (blc_status==BLC_PAUSE) BLC_PTHREAD_CHECK(pthread_mutex_unlock(&mutex_lock_keyboard), NULL);
if (blc_status==BLC_PAUSE) BLC_PTHREAD_CHECK(pthread_mutex_unlock(&mutex_lock_keyboard), NULL);
blc_status=BLC_QUIT;
if (blc_status!=BLC_STEPS) 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");
if (blocking_semaphore){
if (sem_trywait(blocking_semaphore)==0){
sem_post(blocking_semaphore); // we succeed, it was not a problem, I free it.
blocking_semaphore=NULL;
}
sem_post(*sem);
else if (errno==EAGAIN) sem_post(blocking_semaphore);
else EXIT_ON_SYSTEM_ERROR("unlocking semaphore for quitting");
}
}
static void step_forward_cb(const char* steps_nb_str, void*){
int steps_nb, pos;
if (steps_nb_str){
if (sscanf(steps_nb_str, "%d%n", &steps_nb, &pos)!=1 || pos !=strlen(steps_nb_str) || steps_nb<1){
color_eprintf(BLC_YELLOW, "'%s' is not a valid step number\n", steps_nb_str);
return;
}
else {
blc_status=BLC_STEPS;
blc_loop_iteration_limit=blc_loop_iteration+steps_nb;
blc_us_time_diff(&step_timer);
BLC_PTHREAD_CHECK(pthread_mutex_unlock(&mutex_lock_keyboard), NULL);
}
}
else {
blc_status=BLC_STEPS;
blc_loop_iteration_limit=blc_loop_iteration+1;
blc_us_time_diff(&step_timer);
BLC_PTHREAD_CHECK(pthread_mutex_unlock(&mutex_lock_keyboard), NULL);
}
step_iteration=blc_loop_iteration;
blc_command_remove(">");
}
void pause_cb()
{
if (blc_status==BLC_RUN){
if (blc_status==BLC_RUN || blc_status==BLC_STEPS){
blc_status=BLC_PAUSE;
fprintf(stderr, "=== %s: pause ===\n", blc_program_name);
}else {
blc_command_add(">", step_forward_cb, "|iterations", "continue for steps nb iterations", NULL);
fprintf(stderr, "=== %s: pause iteration %lld === '' to continue, '>[<nb>]' to step one or run nb iterations ===\n", blc_program_id, blc_loop_iteration);
}else if (blc_status==BLC_PAUSE){
blc_command_remove(">");
blc_status=BLC_RUN;
fprintf(stderr, "=== %s: continue === \n", blc_program_id);
BLC_PTHREAD_CHECK(pthread_mutex_unlock(&mutex_lock_keyboard), NULL);
fprintf(stderr, "=== %s: running ===\n", blc_program_name);
}
else EXIT_ON_ERROR("Unknown status '%d'", blc_status);
}
static void *loop_check_stuck(void*){
......@@ -128,11 +176,12 @@ static void *loop_check_stuck(void*){
sleep(checking_time);
if(blc_status==BLC_RUN){ //in BLC_PAUSE it is normal to block
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);
color_eprintf(BLC_YELLOW, "'%s' seems blocked on iteration '%d'. The loop has been stopped for more than %ds\n", blc_program_id, iteration, checking_time);
if (blc_profile_file) fflush(blc_profile_file); //It may help for debuggage
was_stucked=1;
}
else if (was_stucked) {
color_eprintf(BLC_GREEN, "'%s' program restart iteration '%d'.\n", blc_program_name, iteration);
color_eprintf(BLC_GREEN, "'%s' program restart iteration '%d'.\n", blc_program_id, iteration);
was_stucked=0;
}
}
......@@ -151,15 +200,16 @@ static void *command_thread_interpret_loop(void *){
return NULL;
}
void blc_command_loop_init(long loop_period)
{
if (blc_command_loop_period!=-2) EXIT_ON_ERROR("You already launch a loop");
void blc_command_loop_init(long loop_period){
if (blc_command_loop_period==-3) EXIT_ON_ERROR("You already are in a blc_command_loop");
blc_loop_iteration=0;
intermediate_iteration=0;
blc_command_loop_period=loop_period;
BLC_PTHREAD_CHECK(pthread_mutex_lock(&mutex_lock_keyboard), NULL);
if (blc_command_loop_period==-2){
blc_command_loop_period=-1;
}
else BLC_PTHREAD_CHECK(pthread_mutex_lock(&mutex_lock_keyboard), NULL);
if (blc_input_terminal){
blc_command_display_help(); //We display help only for keyboard
......@@ -169,32 +219,44 @@ void blc_command_loop_init(long loop_period)
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
if (blc_command_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);
fprintf(stderr, "=== %s: running ===\n", blc_program_id);
}
blc_command_add("|", (type_blc_command_cb)blc_command_send_to_stdout, "|text", "send the text to stdout", NULL);
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);
SYSTEM_ERROR_CHECK(pthread_create(&loop_thread, NULL, command_thread_interpret_loop, NULL), -1, NULL);
}
int blc_command_loop_start(){
int i;
if (blc_profile_file) gettimeofday(&profile_timer, NULL);
//We wait before counting the duration time as the time for waiting does not matter
if (blc_loop_iteration==blc_loop_iteration_limit){
fprintf(stderr, "%s: %d iterations executed in %.3fms\n", blc_program_id, (int)blc_loop_iteration-step_iteration, blc_us_time_diff(&step_timer)/1000.f);
pause_cb();
}
//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){
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);
FOR(i, waiting_semaphores_nb) {
blocking_semaphore=waiting_semaphores[i];
SYSTEM_ERROR_CHECK(sem_wait(blocking_semaphore), -1, NULL);
}
blocking_semaphore=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
else blc_command_loop_period=-3; //In case we start another loop after
//We start counting the duration time
if (intermediate_iteration==0) blc_us_time_diff(&timer);
......@@ -207,11 +269,16 @@ void blc_command_loop_end(){
div_t ratio;
struct timespec time_left, tmp_rem;
int diff, i;
uint64_t start_time;
if (blc_profile_file) start_time=timer.tv_sec*1000000+timer.tv_usec;
blc_current_duration=blc_us_time_diff(&timer);
if (blc_profile_file) fprintf(blc_profile_file, "%16ld\t%16lld\t%8lu\t\n",profile_timer.tv_sec*1000000+profile_timer.tv_usec, start_time, blc_current_duration);
// fflush(stderr);
//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_current_duration<blc_duration_min) blc_duration_min=blc_current_duration;
......@@ -222,7 +289,7 @@ void blc_command_loop_end(){
ratio=div(diff, 1e6);
time_left.tv_sec = ratio.quot;
time_left.tv_nsec = ratio.rem*1000;
if (diff < 0) color_fprintf(BLC_YELLOW, stderr, "\r%s: Missing %.3fms in the BLC_COMMAND_LOOP requesting refresh of %.3fms\n", blc_program_name, -diff/1000.f, blc_command_loop_period/1000.f);
if (diff < 0) color_fprintf(BLC_YELLOW, stderr, "\r%s: Missing %.3fms in the BLC_COMMAND_LOOP requesting refresh of %.3fms\n", blc_program_id, -diff/1000.f, blc_command_loop_period/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 !! */
}
......
......@@ -15,6 +15,7 @@
#include "blc_program.h"
#include "program.hpp" // internal to blc
#include <sys/time.h>
#include <stdio.h>
#include <sys/ioctl.h>
......@@ -76,6 +77,10 @@ struct program_parameter{
char const *default_value;
};
FILE *blc_profile_file=NULL;
int blc_input_terminal, blc_output_terminal;
// Static means it is only existing in this file
static char const *program_description=NULL;
static type_program_option *blc_program_options=NULL;
......@@ -83,52 +88,11 @@ static int blc_program_options_nb=0;
static struct program_parameter *blc_program_parameters=NULL;
static int blc_program_parameters_nb;
int blc_input_terminal, blc_output_terminal;
START_EXTERN_C
void blc_add_arg( int *argc, char ***argv, char const *arg, char const *value){
APPEND_ITEM(argv, argc, &arg);
if (value!=NULL) APPEND_ITEM(argv, argc, &value);
}
char *blc_create_command_line_from_argv(char const *const *argv){
int command_line_size, i;
char *command_line, *pos;
command_line_size=0;
for(i=0; argv[i] != NULL; i++) command_line_size+=strlen(argv[i])+1; // + 1 for the space
command_line=MANY_ALLOCATIONS(command_line_size+1, char);
pos=command_line;
for(i=0; argv[i] != NULL; i++)
pos+=sprintf(pos, "%s ", argv[i]);
return command_line;
}
char * const*blc_create_argv_from_command_line(char const *command_line)
{
char * const*argv=NULL;
char *arg_pt;
char const *pos;
char tmp_arg[NAME_MAX+1];
int length, argc=0;
pos=command_line;
while(sscanf(pos, SCAN_CONV(NAME_MAX, "s")"%n", tmp_arg, &length)==1)
{
arg_pt = strdup(tmp_arg);
APPEND_ITEM(&argv, &argc, &arg_pt);
pos+=length;
}
arg_pt=NULL;
APPEND_ITEM(&argv, &argc, &arg_pt);
return argv;
}
void blc_program_set_description(char const *description)
{
program_description=strdup(description);
program_description=description;
}
void blc_program_add_parameter(char const**result, char const *name, int required, char const *help, char const *default_value)
......@@ -160,6 +124,8 @@ void blc_program_add_multiple_parameters(char ***result_list, char const *name,
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);
tmp_program_option.type = STRING;
tmp_program_option.string_pt = result;
(*tmp_program_option.string_pt)=NULL;
......@@ -210,7 +176,6 @@ static void blc_program_option_interpret(int *argc, char **argv[])
type_program_option *program_option;
char pipe_name[PATH_MAX+1];
blc_program_name = basename(*argv[0]);
//We store enough room for all the optional letters + ':' + terminating null char
optstring = MANY_ALLOCATIONS(blc_program_options_nb*2+1, char);
......@@ -220,9 +185,11 @@ static void blc_program_option_interpret(int *argc, char **argv[])
{
optstring[optstring_size++]=program_option->letter;
tmp_option.name = (const char*)program_option->name;
if (program_option->parameter) tmp_option.has_arg=required_argument;
if (program_option->parameter){
tmp_option.has_arg=required_argument; //optional_argument does not work on OSX !!
}
else tmp_option.has_arg=no_argument;
if (tmp_option.has_arg !=0) optstring[optstring_size++]=':';
if (tmp_option.has_arg==required_argument) optstring[optstring_size++]=':'; //optional_argument does not work on OSX !!
tmp_option.flag = NULL;
tmp_option.val=program_option->letter;
APPEND_ITEM(&long_options, &options_nb, &tmp_option);
......@@ -242,12 +209,17 @@ static void blc_program_option_interpret(int *argc, char **argv[])
{
if (ret == program_option->letter) //TODO see what to do with special char '?' and ':'
{
if (optarg == NULL) *program_option->string_pt="1";
if (optarg == NULL) {
if (program_option->default_value) *program_option->string_pt=program_option->default_value;
else *program_option->string_pt="1";
}
else{
switch (program_option->type){
case STRING:
*program_option->string_pt = optarg;
break;
//Pipe not in use anymore
case INPUT_PIPE:
SPRINTF(pipe_name, "/tmp/blc_pipes/%s", optarg);
SYSTEM_ERROR_CHECK(freopen(optarg, "r", program_option->pipe), NULL, NULL);
......@@ -311,7 +283,7 @@ static void blc_program_interpret_parameters(int *argc, char **argv[]){
parameter_read=getline(&tmp_parameter, &linecap, stdin);
if (parameter_read==-1){
if (errno==ENOTTY) {
color_eprintf(BLC_RED, "\nQuitting '%s': The standard input is not available. You probably have a program on an input pipe which has crashed\n", blc_program_name);
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");
......@@ -355,12 +327,15 @@ static void blc_program_interpret_parameters(int *argc, char **argv[]){
}
void blc_program_parse_args(int *argc, char ***argv){
blc_program_name=basename(*argv[0]);
SYSTEM_ERROR_CHECK(asprintf((char**)&blc_program_id, "%s%d", blc_program_name, getpid()), -1, "Argv0: '%s'", *argv[0]);
blc_program_option_interpret(argc, argv);
blc_program_interpret_parameters(argc, argv);
}
void blc_program_parse_args_and_print_title(int *argc, char ***argv){
underline_fprintf('=', stderr, blc_program_name);
underline_fprintf('=', stderr, basename(*argv[0]));
blc_program_parse_args(argc, argv);
}
......@@ -406,7 +381,7 @@ void blc_program_args_display_help()
option_length_max+=10;
if (blc_program_parameters_nb) fprintf(stderr, POSITIONAL_ARGUMENTS_TITLE);
FOR_EACH(parameter, blc_program_parameters, blc_program_parameters_nb){
fprintf(stderr, " %-*s %s", option_length_max-2, parameter->name, parameter->help);
fprintf(stderr, " %-*s %s\n", option_length_max-2, parameter->name, parameter->help);
if (parameter->default_value) fprintf(stderr, " (default: %s)\n", parameter->default_value);
}
......@@ -433,37 +408,37 @@ void blc_program_args_display_help()
}
static void on_sigterm(int){
fprintf(stderr, "\n%s: receiving SIGTERM (kill)\n", blc_program_name);
fprintf(stderr, "%s: receiving SIGTERM (kill)\n", blc_program_id);
exit(EXIT_SUCCESS);
}
static void on_sigint(int){
if (blc_status==BLC_QUIT){
fprintf(stderr, "\n%s: receiving SIGINT (Ctrl+C) in quiting mode. Force to quit.\n", blc_program_name);
fprintf(stderr, "%s: receiving SIGINT (Ctrl+C) in quiting mode. Force to quit.\n", blc_program_id);
exit(EXIT_FAILURE);
}
else {
fprintf(stderr, "\n%s :receiving SIGINT (Ctrl+C). Try to quit. Resend SIGINT if it does not quit.\n", blc_program_name);
fprintf(stderr, "%s :receiving SIGINT (Ctrl+C). Try to quit. Resend SIGINT if it does not quit.\n", blc_program_id);
blc_status=BLC_QUIT;
}
}
static void on_sigsegv(int){
fprintf(stderr, "\n%s: segmentation fault ( memory access error ! )\n", blc_program_name);
fprintf(stderr, "%s: segmentation fault ( memory access error ! )\n", blc_program_id);
exit(EXIT_FAILURE);
}
//Normal exit is not called with value of 1 in exit
static void on_sigabrt(int ){
fprintf(stderr, "\n%s: receiving SIGABORT ( error ! )\n", blc_program_name);
exit(EXIT_FAILURE);
fprintf(stderr, "%s: receiving SIGABORT ( error ! )\n", blc_program_id);
}
//At this moment error_exit_cb is the same than normal exit
void blc_program_init(int *argc, char ***argv, void (*exit_cb)(void))
{
char const*help;
char const*help, *profile;
struct sigaction action;
struct timeval timer;
CLEAR(action);
action.sa_handler = on_sigterm;
......@@ -484,8 +459,17 @@ void blc_program_init(int *argc, char ***argv, void (*exit_cb)(void))
if (isatty(STDERR_FILENO) && blc_input_terminal) blc_stderr_ansi=1;
else blc_stderr_ansi; //This is not waranty. It is safer to use blc_stderr_ansi_detect but it causes trouble when many program are launched at once
blc_program_add_option(&profile, '~', "profile", "filename", "profile the execution of the loop", NULL);
blc_program_add_option(&help, 'h', "help", 0, "display this help", NULL);
blc_program_parse_args_and_print_title(argc, argv);
if (profile){
SYSTEM_ERROR_CHECK(blc_profile_file=fopen(profile, "w"), NULL, "filename: %s", profile);
fprintf(blc_profile_file, "#start_time(µs) \texec_time(µs) \tduration(µs) \t\n");
gettimeofday(&timer, NULL);