#ifndef MUTILS_UTIL_H
#define MUTILS_UTIL_H
/**
  \file

\verbatim
  $Id: util.h,v 1.13 2015/01/19 19:47:30 rauch Exp $
\endverbatim
  \author Kevin P. Rauch
  \brief  The MathUtils miscellaneous utilities library.

*/
#include "mutils/platform.h"

#ifdef __cplusplus
#  include <cstdio>
#  include <cstdlib>
#  include <cstring>
   using std::FILE;
   using std::size_t;
#else
#  include <stdio.h>
#  include <stdlib.h>
#  include <string.h>
#endif

#ifdef mu_os_mswin
#  if !defined(strcasecmp)
#    define strcasecmp  stricmp
#    define strncasecmp strnicmp
#  endif
#elif !defined(__DECC)
#  include <strings.h>
#endif

#ifndef mu_os_mswin
#  include <unistd.h>
#endif

#define MU_VERMAX  32 /* Max length of version string. */
#define MU_DATEMAX 24 /* Max length of cppdate string. */

#ifdef __cplusplus
extern "C" {
namespace MUTILS {
#endif

DLLSPEC extern void
  mu_cppdate(char str[ /*MU_DATEMAX*/ ], const char *date, const char *time),
  mu_error_action(int, const char *, const char *, int, int),
  mu_split_tag(char pre[], int *maj, int *min, int *clas, int *bug,
    int *y, int *m, int *d, const char *tag);

DLLSPEC extern char
 *mu_utoa9(char *str, unsigned i, int strip),
 *mu_fgetline(char *, long int, FILE *);

DLLSPEC extern const char
 *mu_platform(void),
 *mu_version(void),
 *mu_verstr(char verstr[ /*MU_VERMAX*/ ], const char *pre,
	    int maj, int min, int clas, int bug);

DLLSPEC extern int
  mu_ppmtext(char *, char *, int, int, int),
  mu_vernum(const char *name, const char *cvs);

#define MU_iferr_abort(err, func)  do { \
  if (err) mu_error_action(-1, func, __FILE__, __LINE__, -1); } while (0)

#define MU_iferr_warn(err, func)  do { \
  if (err) mu_error_action(-1, func, __FILE__, __LINE__,  0); } while (0)

#define MU_iferr(err, func)  do { \
  if (err) mu_error_action(-1, func, __FILE__, __LINE__,  1); } while (0)

#define MU_iferrn_abort(err, func)  do { \
  int errn=(err); \
  if (errn) mu_error_action(errn, func, __FILE__, __LINE__, -1); } while (0)

#define MU_iferrn_warn(err, func)  do { \
  int errn=(err); \
  if (errn) mu_error_action(errn, func, __FILE__, __LINE__,  0); } while (0)

#define MU_iferrn(err, func)  do { \
  int errn=(err); \
  if (errn) mu_error_action(errn, func, __FILE__, __LINE__,  1); } while (0)

#define mu_alloc(s)      mu_alloc_r(NULL, s)
#define mu_realloc(p, s) mu_realloc_r(NULL, p, s)
#define mu_free(p)       mu_free_r(NULL, p)
#define mu_freeall()     mu_freeall_r(NULL)

DLLSPEC extern int mu_free_r(void **, void *);
DLLSPEC extern void
   mu_freeall_r(void *), *mu_alloc_r(void **, size_t),
  *mu_realloc_r(void **, void *, size_t);


DLLSPEC extern int  mu_clock_Hz(void);
DLLSPEC extern void mu_wait_time(double);
DLLSPEC extern double
  mu_clock_time(void), mu_cpu_time(void),
  mu_system_time(void), mu_user_time(void);


DLLSPEC extern char *mu_optarg;
DLLSPEC extern int
  mu_opterr, mu_optind, mu_optopt,
  mu_getopt(int argc, char * const argv[], const char *opts);

DLLSPEC extern double
  mu_time_unary(double (*fn)(double), double x1, double x2, double tmin);

DLLSPEC extern double
  mu_time_binary(double (*fn)(double, double), double x1,
                 double x2, double y1, double y2, double tmin);

DLLSPEC extern double
  mu_time_trinary(double (*fn)(double, double, double), double x1,
                  double x2, double y1, double y2, double z1, double z2,
		  double tmin);

#ifdef __cplusplus
}  // namespace MUTILS
}  // extern "C"
#endif

#endif  /* MUTILS_UTIL_H */
