Math Processor Unit Library

libmpu – library of arithmetic functions for integer, real, and complex numbers of increased digit capacity

16 Commits   0 Branches   2 Tags

/***************************************************************
  __MPU_WARNING.C

       This file contains source code of functions for
       MPU extra warnings operations.

       PART OF : MPU - library .

       USAGE   : Internal only .

       NOTE    : NONE .

       Copyright (C) 2000 - 2024  by Andrew V.Kosteltsev.
       All Rights Reserved.
 ***************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <nls.h>

#include <errno.h>   /* errno(3)  */
#include <string.h>  /* strcpy(3) */
#include <strings.h> /* bzero(3)  */
#include <stdlib.h>
#include <stdio.h>
#include <locale.h>

#include <libmpu.h>
#include <mpu-context.h>

#include <mpu-emutype.h>
#include <mpu-integer.h>
#include <mpu-real.h>
#include <mpu-floatp.h>
#include <mpu-ioreal.h>

#include <mpu-char.h>
#include <mpu-symbols.h>

#include <mpu-math-errno.h>
#include <mpu-mtherr.h>

/*
  __mpu_warning() работает с внешним форматом чисел.

  Данная вункция вызывается только в том случае,
  когда переменная __extra_warnings имеет значение
  отличное от нуля.

  Пользователь может определить собственную функцию
  __mpu_warning() в качестве замены данного стандартного
  обработчика вывода дополнительных предупреждений.
 */

#define         MSG_FORMAT "message:  %0.4d: %s(): %s" /* type, name, msg */
#define   ERROR_MSG_FORMAT   "error: E%0.4d: %s(): %s" /* type, name, msg */
#define WARNING_MSG_FORMAT "warning: W%0.4d: %s(): %s" /* type, name, msg */


int __use_default_mpu_warning = 1;

void __mpu_warning( struct __exception *pexcept )
{
  __mpu_char8_t                 str[MPU_MATH_ERROR_MSG_SIZE];
  __mpu_char8_t    error_msg_format[MPU_MATH_ERROR_MSG_SIZE];
  __mpu_char8_t  warning_msg_format[MPU_MATH_ERROR_MSG_SIZE];
  __mpu_char8_t                 fmt[MPU_MATH_ERROR_MSG_SIZE];

  /************************************************************
    Floating point exception.
    ==========================================================
    Исключение операции с плавающей точкой.
   ************************************************************/
  __mpu_char8_t *exception = (__mpu_char8_t *)N_("Floating point exception");
  /************************************************************
    Unknown message source.
    ==========================================================
    Неизвестный источник сообщения.
   ************************************************************/
  __mpu_char8_t *unknown   = (__mpu_char8_t *)N_("Unknown message source");

#if ENABLE_NLS == 1
    char   *back_locale = NULL;
    char   *lt          = NULL;
    char   *back_env    = NULL;

    /*******************************************************
      Так как gettext в первую очередь проверяет LC_ALL,
      затем LC_MESSAGE и в процессе работы пользуется
      LC_CTYPE, мы для простоты временно выставляем LC_ALL.
      Использование LC_MESSAGE при отличном от него LC_ALL
      нам ничего не даст.
     *******************************************************/
    back_locale = setlocale( LC_ALL, (const char *)NULL );
    lt = setlocale( LC_ALL, (const char *)"ru" );

    back_env = getenv( (const char *)"LANGUAGE" );
    (void)setenv( (const char *)"LANGUAGE", (const char *)"ru", 1 /* 1 - overwrite */ );

    exception = (__mpu_char8_t *)dgettext( PACKAGE, (const char *)exception );
    unknown   = (__mpu_char8_t *)dgettext( PACKAGE, (const char *)unknown );
#endif

  strcpy(   (char *)&error_msg_format[0],   ERROR_MSG_FORMAT );
  strcpy( (char *)&warning_msg_format[0], WARNING_MSG_FORMAT );

  /*******************************************************
    ERRNO FOR MESSAGES:
       _INTEGER_ + 1000, _REAL_ + 2000, _COMPLEX_ + 3000.
    MESSAGES TYPE:
       TRUE - error; FALSE - warning.
   *******************************************************/
  switch( pexcept->who )
  {
    case _INTEGER_:
      pexcept->type = __integer_error_no;
      sprintf( (char *)&str[0],
               (pexcept->msg_type) ? (error_msg_format) :
                                     (warning_msg_format),
               pexcept->type + 1000, (char *)pexcept->name, (char *)pexcept->msg );
      break;

    case    _REAL_:
      pexcept->type = __real_error_no;
      sprintf( (char *)&str[0],
               (pexcept->msg_type) ? (error_msg_format) :
                                     (warning_msg_format),
               pexcept->type + 2000, (char *)pexcept->name, (char *)pexcept->msg );
      break;

    case _COMPLEX_:
      pexcept->type = __complex_error_no;
      sprintf( (char *)&str[0],
               (pexcept->msg_type) ? (error_msg_format) :
                                     (warning_msg_format),
               pexcept->type + 3000, (char *)pexcept->name, (char *)pexcept->msg );
      break;

    case    _MATH_:
      {
        __mpu_char8_t    s[REAL_131072_MAX_STRING]; /* mpu-floatp.h */
        __mpu_char8_t  num[REAL_131072_MAX_STRING];
        __mpu_char8_t   st[MPU_MATH_ERROR_MSG_SIZE];

        EMUSHORT       eic[NPIR_131072];
        int            n_bits;

        /* Type the string STR[] */
        if( pexcept->arg_1 )
        {
          n_bits = pexcept->nb_a1 * BITS_PER_BYTE;

          unpack( (EMUSHORT *)&eic[0], (EMUSHORT *)pexcept->arg_1, n_bits );

          ei_real_to_ascii( (__mpu_char8_t *)&s[0],
                            (EMUSHORT *)&eic[0],
                            (_get_ndec( pexcept->nb_a1 ) < 12) ? _get_ndec( pexcept->nb_a1 ): 12,
                            'E', 0, 0, n_bits );

          strcpy( (char *)&num[0], (char *)&s[0] );
          strcpy( (char *)&fmt[0], exception );
          strcat( (char *)&fmt[0], ": %s( %s" );
          sprintf( (char *)&str[0], (const char *)&fmt[0], (char *)pexcept->name, (char *)&num[0] );
        }
        else
        {
          strcpy( (char *)&fmt[0], exception );
          strcat( (char *)&fmt[0], ": %s( " );
          sprintf( (char *)&str[0], (const char *)&fmt[0], (char *)pexcept->name );
        }

        if( pexcept->arg_2 )
        {
          n_bits = pexcept->nb_a2 * BITS_PER_BYTE;

          unpack( (EMUSHORT *)&eic[0], (EMUSHORT *)pexcept->arg_2, n_bits );

          ei_real_to_ascii( (__mpu_char8_t *)&s[0],
                            (EMUSHORT *)&eic[0],
                            (_get_ndec( pexcept->nb_a2 ) < 12) ? _get_ndec( pexcept->nb_a2 ): 12,
                            'E', 0, 0, n_bits );

          strcpy( (char *)&num[0], (char *)&s[0] );
          strcpy( (char *)&fmt[0], ", %s ): %s" );
          sprintf( (char *)&st[0], (const char *)&fmt[0], (char *)&num[0], (char *)pexcept->msg );
          strcat( (char *)&str[0], (char *)&st[0] );
        }
        else
        {
          strcpy( (char *)&fmt[0], " ): %s" );
          sprintf( (char *)&st[0], (const char *)&fmt[0], (char *)pexcept->msg );
          strcat( (char *)&str[0], (char *)&st[0] );
        }
      }
      break;

    default:
      {
        strcpy( (char *)&fmt[0], unknown );
        strcat( (char *)&fmt[0], ": %0.4d: %s(): %s" );
        sprintf( (char *)&str[0], (const char *)&fmt[0], pexcept->type, (char *)pexcept->name, (char *)pexcept->msg );
      }
      break;

  } /* End switch( pexcept->who ) */

  strcpy( (char *)&fmt[0], "%s.\n" );

  fprintf( stderr, (const char *)&fmt[0], (char *)&str[0] );

#if ENABLE_NLS == 1
  /* restore locale and environment */
  if( back_locale )
    (void)setlocale( LC_ALL, (const char *)back_locale );

  if( back_env )
    (void)setenv( (const char *)"LANGUAGE", (const char *)back_env, 1 /* 1 - overwrite */ );
#endif

  return;

} /* End of __mpu_warning() */