Program Listing for File error_handling.h

Return to documentation for file (include/rcutils/error_handling.h)

// Copyright 2014 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


#ifndef RCUTILS__ERROR_HANDLING_H_
#define RCUTILS__ERROR_HANDLING_H_

#ifdef __cplusplus
extern "C"
{
#endif

#ifndef __STDC_WANT_LIB_EXT1__
#define __STDC_WANT_LIB_EXT1__ 1  // indicate we would like strnlen_s if available
#endif
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "rcutils/allocator.h"
#include "rcutils/macros.h"
#include "rcutils/snprintf.h"
#include "rcutils/testing/fault_injection.h"
#include "rcutils/types/rcutils_ret.h"
#include "rcutils/visibility_control.h"

#ifdef __STDC_LIB_EXT1__

#define RCUTILS_SAFE_FWRITE_TO_STDERR(msg) \
  do {fwrite(msg, sizeof(char), strnlen_s(msg, 4096), stderr);} while (0)
#else
#define RCUTILS_SAFE_FWRITE_TO_STDERR(msg) \
  do {fwrite(msg, sizeof(char), strlen(msg), stderr);} while (0)
#endif


#define RCUTILS_SAFE_FWRITE_TO_STDERR_WITH_FORMAT_STRING(format_string, ...) \
  do { \
    char output_msg[RCUTILS_ERROR_MESSAGE_MAX_LENGTH]; \
    int ret = rcutils_snprintf(output_msg, sizeof(output_msg), format_string, __VA_ARGS__); \
    if (ret < 0) { \
      RCUTILS_SAFE_FWRITE_TO_STDERR("Failed to call snprintf for error message formatting\n"); \
    } else { \
      RCUTILS_SAFE_FWRITE_TO_STDERR(output_msg); \
    } \
  } while (0)

#define RCUTILS_ERROR_STATE_LINE_NUMBER_STR_MAX_LENGTH 20  // "18446744073709551615"

#define RCUTILS_ERROR_FORMATTING_CHARACTERS 6  // ', at ' + ':'

#define RCUTILS_ERROR_MESSAGE_MAX_LENGTH 1024


#define RCUTILS_ERROR_STATE_MESSAGE_MAX_LENGTH 768


#define RCUTILS_ERROR_STATE_FILE_MAX_LENGTH ( \
    RCUTILS_ERROR_MESSAGE_MAX_LENGTH - \
    RCUTILS_ERROR_STATE_MESSAGE_MAX_LENGTH - \
    RCUTILS_ERROR_STATE_LINE_NUMBER_STR_MAX_LENGTH - \
    RCUTILS_ERROR_FORMATTING_CHARACTERS - \
    1)

typedef struct rcutils_error_string_s
{
  char str[RCUTILS_ERROR_MESSAGE_MAX_LENGTH];
} rcutils_error_string_t;

typedef struct rcutils_error_state_s
{
  char message[RCUTILS_ERROR_STATE_MESSAGE_MAX_LENGTH];
  char file[RCUTILS_ERROR_STATE_FILE_MAX_LENGTH];
  uint64_t line_number;
} rcutils_error_state_t;

// make sure our math is right...
#if __STDC_VERSION__ >= 201112L
static_assert(
  sizeof(rcutils_error_string_t) == (
    RCUTILS_ERROR_STATE_MESSAGE_MAX_LENGTH +
    RCUTILS_ERROR_STATE_FILE_MAX_LENGTH +
    RCUTILS_ERROR_STATE_LINE_NUMBER_STR_MAX_LENGTH +
    RCUTILS_ERROR_FORMATTING_CHARACTERS +
    1 /* null terminating character */),
  "Maximum length calculations incorrect");
#endif


RCUTILS_PUBLIC
RCUTILS_WARN_UNUSED
rcutils_ret_t
rcutils_initialize_error_handling_thread_local_storage(rcutils_allocator_t allocator);


RCUTILS_PUBLIC
void
rcutils_set_error_state(const char * error_string, const char * file, size_t line_number);


#define RCUTILS_CHECK_ARGUMENT_FOR_NULL(argument, error_return_type) \
  RCUTILS_CHECK_FOR_NULL_WITH_MSG( \
    argument, #argument " argument is null", \
    return error_return_type)


#define RCUTILS_CHECK_FOR_NULL_WITH_MSG(value, msg, error_statement) \
  do { \
    if (NULL == value) { \
      RCUTILS_SET_ERROR_MSG(msg); \
      error_statement; \
    } \
  } while (0)


#define RCUTILS_SET_ERROR_MSG(msg) \
  do {rcutils_set_error_state(msg, __FILE__, __LINE__);} while (0)


#define RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING(format_string, ...) \
  do { \
    char output_msg[RCUTILS_ERROR_MESSAGE_MAX_LENGTH]; \
    int ret = rcutils_snprintf(output_msg, sizeof(output_msg), format_string, __VA_ARGS__); \
    if (ret < 0) { \
      RCUTILS_SAFE_FWRITE_TO_STDERR("Failed to call snprintf for error message formatting\n"); \
    } else { \
      RCUTILS_SET_ERROR_MSG(output_msg); \
    } \
  } while (0)


#define RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(error_return_value) \
  RCUTILS_CAN_FAIL_WITH( \
  { \
    RCUTILS_SET_ERROR_MSG("Injecting " RCUTILS_STRINGIFY(error_return_value)); \
    return error_return_value; \
  })

RCUTILS_PUBLIC
RCUTILS_WARN_UNUSED
bool
rcutils_error_is_set(void);


RCUTILS_PUBLIC
RCUTILS_WARN_UNUSED
const rcutils_error_state_t *
rcutils_get_error_state(void);


RCUTILS_PUBLIC
RCUTILS_WARN_UNUSED
rcutils_error_string_t
rcutils_get_error_string(void);

RCUTILS_PUBLIC
void
rcutils_reset_error(void);

#ifdef __cplusplus
}
#endif

#endif  // RCUTILS__ERROR_HANDLING_H_