Mentions légales du service

Skip to content
Snippets Groups Projects
util.c 12.97 KiB
#include "main.h"

/* ================================================================================== */
/*! \brief Displays an error message with the location of this error in the source code

This routine is mainly called by the macros defined in mpf.h : SETERRA, SETERRQ, CHKERRA, CHKERRQ, CHKPTRA and CHKPTRQ.
It displays the processor rank followed by a complete error message defining and locating the error that occured.
\param line the line of the source file where the error occured
\param package the package where the source file is located (can be NULL if not known)
\param file the name of the source file
\param number the number of the error
\param message the error message (can be NULL if there is no message)
*/
int MpfError(int line,char *package,char *file,const char *function, int number, ...) {
  va_list args;
  char *message, *pos, *pos2 ;

  va_start (args,number) ;
  message = va_arg(args, char *) ;

  fprintf(stderr,"[-] ERROR ");

  if (strcmp("-",function))
    fprintf(stderr,"in %30s() ",function) ;

  /* Cherche tous les "/src/" dans __FILE__, et si j'en trouve, j'affiche seulement a partir du dernier "src/..." */
  pos=file ;
  while ((pos2=strstr(pos, "/src/"))) {
    pos=pos2+1 ;
  }

  if (line != -1) {
    if (!package)
      fprintf(stderr,"([%s,%d] : ", pos, line) ;
    else
      fprintf(stderr,"[%s : %s,%d] : ",package,pos,line) ;
  }
  if (message)
    vfprintf(stderr, message, args);
  fprintf(stderr,"\n");
  fflush(stderr);

  va_end(args);

  return number ;
}
/* ================================================================================== */
/*! \brief Displays a warning message with the location of this error in the source code

This routine is mainly called by the macros defined in mpf.h : SETWARN.
It displays the processor rank followed by a complete error message defining and locating the error that occured.
\param line the line of the source file where the error occured
\param package the package where the source file is located (can be NULL if not known)
\param file the name of the source file
\param number the number of the error
\param message the error message (can be NULL if there is no message)
*/
int MpfWarning(int line,char *package,char *file,const char *function,int number, ...) {
  va_list args;
  char *message, *pos, *pos2 ;

  va_start (args,number) ;
  message = va_arg(args, char *) ;

  fprintf(stderr,"[-] WARNING ");

  if (strcmp("-",function))
    fprintf(stderr,"in %30s() ",function) ;

  /* Cherche tous les "/src/" dans __FILE__, et si j'en trouve, j'affiche seulement a partir du dernier "src/..." */
  pos=file ;
  while ((pos2=strstr(pos, "/src/"))) {
    pos=pos2+1 ;
  }

  if (line != -1) {
    if (!package)
      fprintf(stderr,"([%s,%d] : ", pos, line) ;
    else
      fprintf(stderr,"[%s : %s,%d] : ",package,pos,line) ;
  }
  if (message)
    vfprintf(stderr, message, args);
  fprintf(stderr,"\n");
  fflush(stderr);

  va_end(args);

  return number ;
}
/* ================================================================================== */
/*! \brief Print on screen a progress bar

For an assembly operation for instance, this routine can be used to display a nice progress indicator on screen.
\a currentValue must vary between 0 and \a maximumValue (included). It can be for instance the number of blocks assembled and total.
\param comm the communicator (for printf)
\param currentValue the current value of the progress parameter
\param maximumValue the maximum and final value of the progress parameter
\return 0 for success
*/
int Mpf_progressBar(int currentValue, int maximumValue) {
  div_t res ;
  int j ;
  static int progress = -1; /* varie de 0 a 100 au cours du calcul concerne */

  if (maximumValue==0)
    res.quot=100 ;
  else {
    if (currentValue<INT_MAX/100)
      res=div(currentValue*100, maximumValue) ;
    /* Calcule le quotient de la division */
    else
      res.quot=(int)( (long long) currentValue*100/maximumValue) ;
  }

  for (j=progress+1 ; j<=res.quot ; j++)
    if (j % 10 == 0) {
      printf(" %2d%% ", j ) ;
      fflush(stdout);
    } else {
      printf(".") ;
      fflush(stdout);
    }
  progress=res.quot ;
  if (currentValue>=maximumValue) {
    /* termine la barre de progression */
    printf(" done\n") ;
    progress=-1 ;
  }

  return 0 ;
}
/* ================================================================================== */
/*! \brief Convert string to double

like atof libc version but
- allows fortran style exponent beginning with 'D' or 'd'
- does not set errno.
*/
static double MpfAtof(const char *str) {
  int exponent, negative, n, num_digits, num_decimals ;
  char *p ;
  double number, p10 ;

  p = (char *) str;
  /* Skip leading whitespace */
  while (isspace(*p)) p++;

  /* Handle optional sign */
  negative = 0;
  switch (*p) {
    case '-': negative = 1; /* Fall through to increment position */
    case '+': p++;
  }

  number = 0.;
  exponent = 0;
  num_digits = 0;
  num_decimals = 0;

  /* Process string of digits */
  while (isdigit(*p)) {
    number = number * 10. + (*p - '0');
    p++;
    num_digits++;
  }

  /* Process decimal part */
  if ( (*p == '.') || (*p == ',') ) {
    p++;

    while (isdigit(*p)) {
      number = number * 10. + (*p - '0');
      p++;
      num_digits++;
      num_decimals++;
    }

    exponent -= num_decimals;
  }

  if (num_digits == 0)
    return 0.0;

  /* Correct for sign */
  if (negative) number = -number;

  /* Process an exponent string */
  if (*p == 'e' || *p == 'E' || *p == 'd' || *p == 'D') {
    /* Handle optional sign */
    negative = 0;
    switch(*++p) {
      case '-': negative = 1;   /* Fall through to increment pos */
      case '+': p++;
    }

    /* Process string of digits */
    n = 0;
    while (isdigit(*p)) {
      n = n * 10 + (*p - '0');
      p++;
    }

    if (negative)
      exponent -= n;
    else
      exponent += n;
  }

  if (exponent < DBL_MIN_EXP  || exponent > DBL_MAX_EXP) {
    return HUGE_VAL;
  }

  /* Scale the result */
  p10 = 10.;
  n = exponent;
  if (n < 0) n = -n;
  while (n) {
    if (n & 1) {
      if (exponent < 0)
        number /= p10;
      else
        number *= p10;
    }
    n >>= 1;
    p10 *= p10;
  }

  return number;
}
/* ================================================================================== */
#define MPF_OPT_RFLAG 1
/* ================================================================================== */
static void MpfArgSqueeze( int  *Argc, char **argv ) {
  int argc, i, j;

  /* Compress out the eliminated args */
  argc = *Argc;
  j    = 0;
  i    = 0;
  while (j < argc) {
    while (j < argc && argv[j] == 0) j++;
    if (j < argc) argv[i++] = argv[j++];
  }
  /* Back off the last value if it is null */
  if (!argv[i-1]) i--;
  *Argc = i;
}
/* ================================================================================== */
/*! \brief Find a name in an argument list.

\param argc number of arguments
\param argv argument vector
\param name name to find
\return index in argv of name; -1 if name is not in argv
*/
static int MpfArgFindName(int argc, char **argv, const char *name ) {
  int  i;

  for (i=0; i<argc; i++) {
    // Skip the initial(s) '-'
    char *argv_i=argv[i];
    while (argv_i && argv_i[0]!=0 && argv_i[0]=='-') argv_i++;
    while (name && name[0]!=0 && name[0]=='-') name++;
    if (strcmp( argv_i, name ) == 0) return i;
  }
  return -1;
}
/* ================================================================================== */
/*! \brief Get the value (double) of a named parameter.

\param Argc pointer to argument count
\param argv argument vector
\param rflag if true, remove the argument and its value from argv
\param name name to find
\param val pointer to value (will be set only if found)
\return 1 on success
*/
int MpfArgGetDouble( int *Argc, char **argv, int rflag, const char *name, double *val ) {
  int idx;

  idx = MpfArgFindName( *Argc, argv, name );
  if (idx < 0) return 0;

  if (idx + 1 >= *Argc) {
    SETERRA(1,"Missing value for argument \"%s\".", name );
    return 0;
  }

  *val = MpfAtof( argv[idx+1] );
  if (MPF_OPT_RFLAG && rflag) {
    argv[idx]   = 0;
    argv[idx+1] = 0;
    MpfArgSqueeze( Argc, argv );
  }
  return 1;
}
/* ================================================================================== */
/*! \brief Return 1 if name is in argument list

\param Argc pointer to argument count
\param argv argument vector
\param rflag if true, remove the argument and its value from argv
\param name name to search for
\return 1 on success
*/
int MpfArgHasName( int *Argc, char **argv, int rflag, const char *name ) {
  int idx;

  idx = MpfArgFindName( *Argc, argv, name );
  if (idx < 0) return 0;

  if (MPF_OPT_RFLAG && rflag) {
    argv[idx]   = 0;
    MpfArgSqueeze( Argc, argv );
  }
  return 1;
}
/* ================================================================================== */
/*! \brief Get the value (integer) of a named parameter.

This routine handles both decimal and hexidecimal integers.
\param Argc pointer to argument count
\param argv argument vector
\param rflag if true, remove the argument and its value from argv
\param name name to find
\param val pointer to value (will be set only if found)
\return 1 on success
*/
int MpfArgGetInt( int  *Argc, char **argv, int rflag, const char *name, int  *val ) {
  int idx;
  char *p;

  idx = MpfArgFindName( *Argc, argv, name );
  if (idx < 0) return 0;

  if (idx + 1 >= *Argc) {
    SETERRA(1,"Missing value for argument \"%s\".", name );
    return 0;
  }

  p = argv[idx+1];
  /* Check for hexidecimal value */
  if ((strlen(p) > 1) && p[0] == '0' && p[1] == 'x') {
    sscanf( p, "%i", val );
  } else {
    if (strlen(p) > 1 && p[0] == '-' && p[1] >= 'A' && p[1] <= 'z') {
      SETERRA(1,"Missing value for argument \"%s\".", name );
      return 0;
    }
    *val = atoi( p );
  }

  if (MPF_OPT_RFLAG && rflag) {
    argv[idx]   = 0;
    argv[idx+1] = 0;
    MpfArgSqueeze( Argc, argv );
  }
  return 1;
}
/* ================================================================================== */
/*! \brief Get the value (string) of a named parameter.

\param Argc pointer to argument count
\param argv argument vector
\param rflag if true, remove the argument and its value from argv
\param name name to find
\param val pointer to buffer to hold value (will be set only if found).
\return 1 on success
*/
int MpfArgGetString( int *Argc, char **argv, int rflag, const char *name, char **val ) {
  int idx;

  idx = MpfArgFindName( *Argc, argv, name );
  if (idx < 0) return 0;

  if (idx + 1 >= *Argc) {
    SETERRA(1,"Missing value for argument \"%s\".", name );
    return 0;
  }

  *val = (char *)strdup(argv[idx+1]);
  if (MPF_OPT_RFLAG && rflag) {
    argv[idx]   = 0;
    argv[idx+1] = 0;
    MpfArgSqueeze( Argc, argv );
  }
  return 1;
}
/* ================================================================================== */
Time get_time() {
  Time result ;
#ifdef _WIN32
  int64_t frequency;
  int64_t value;
  double dTime;
  QueryPerformanceFrequency(&frequency);
  QueryPerformanceCounter(&value);
  dTime = ((double)value) / ((double)frequency);
  result.tv_sec = (int64_t) dTime;
  result.tv_nsec = (int64_t) (1.e9 * (dTime - result.tv_sec));
  if (result.tv_nsec >= 1000000000) {
    result.tv_sec += 1;
    result.tv_nsec = 0;
  }
#elif defined(HAVE_LIBRT)
  int ierr ;
  ierr=clock_gettime(CLOCK_MONOTONIC, &result); CHKERRA(ierr);
#elif defined(HAVE_MACH_MACH_TIME_H) /* Version OSX */
  static double timeConvert = 0.0;
  if ( timeConvert == 0.0 )
  {
    mach_timebase_info_data_t timeBase;
    (void)mach_timebase_info( &timeBase );
    timeConvert = (double)timeBase.numer /
        (double)timeBase.denom /
        1000000000.0;
  }
  double t = (double)mach_absolute_time( ) * timeConvert;
  result.tv_sec  = (long)floor(t) ; /* seconds */
  result.tv_nsec = (long)floor( (t-(double)result.tv_sec)*1.e9 ) ;  /* uSecs */
#else
  int ierr ;
  struct rusage temp;
  ierr=getrusage(RUSAGE_SELF,&temp); CHKERRA(ierr);
  result.tv_sec  = (time_t)(temp.ru_utime.tv_sec) ; /* seconds */
  result.tv_nsec = (long)(1000*temp.ru_utime.tv_usec) ;  /* uSecs */
#endif /* _WIN32 */
  return result;
}
/* ================================================================================== */
Time time_interval(Time t1, Time t2) {
  Time result;
  result.tv_sec = t2.tv_sec - t1.tv_sec;
  result.tv_nsec = t2.tv_nsec - t1.tv_nsec;
  if (result.tv_nsec < 0) {
    result.tv_sec -= 1;
    result.tv_nsec += 1000000000;
  }
  return result;
}
/* ================================================================================== */
Time add_times(Time t1, Time t2) {
  Time result;
  result.tv_sec = t1.tv_sec + t2.tv_sec;
  result.tv_nsec = t1.tv_nsec + t2.tv_nsec;
  if (result.tv_nsec >= 1000000000) {
    result.tv_sec += 1;
    result.tv_nsec -= 1000000000;
  }
  return result;
}
/* ================================================================================== */
double time_in_s(Time t) {
  return t.tv_sec + (((double)t.tv_nsec) / 1.e9);
}
/* ================================================================================== */
double time_interval_in_seconds(Time t1, Time t2) {
  Time interval = time_interval(t1, t2);
  return time_in_s(interval);
}