/*
 * kmp_debug.cpp -- debug utilities for the Guide library
 */


//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//


#include "kmp.h"
#include "kmp_debug.h" /* really necessary? */
#include "kmp_i18n.h"
#include "kmp_io.h"

#ifdef KMP_DEBUG
void __kmp_debug_printf_stdout(char const *format, ...) {
  va_list ap;
  va_start(ap, format);

  __kmp_vprintf(kmp_out, format, ap);

  va_end(ap);
}
#endif

void __kmp_debug_printf(char const *format, ...) {
  va_list ap;
  va_start(ap, format);

  __kmp_vprintf(kmp_err, format, ap);

  va_end(ap);
}

#ifdef KMP_USE_ASSERT
int __kmp_debug_assert(char const *msg, char const *file, int line) {

  if (file == NULL) {
    file = KMP_I18N_STR(UnknownFile);
  } else {
    // Remove directories from path, leave only file name. File name is enough,
    // there is no need in bothering developers and customers with full paths.
    char const *slash = strrchr(file, '/');
    if (slash != NULL) {
      file = slash + 1;
    }; // if
  }; // if

#ifdef KMP_DEBUG
  __kmp_acquire_bootstrap_lock(&__kmp_stdio_lock);
  __kmp_debug_printf("Assertion failure at %s(%d): %s.\n", file, line, msg);
  __kmp_release_bootstrap_lock(&__kmp_stdio_lock);
#ifdef USE_ASSERT_BREAK
#if KMP_OS_WINDOWS
  DebugBreak();
#endif
#endif // USE_ASSERT_BREAK
#ifdef USE_ASSERT_STALL
  /*    __kmp_infinite_loop(); */
  for (;;)
    ;
#endif // USE_ASSERT_STALL
#ifdef USE_ASSERT_SEG
  {
    int volatile *ZERO = (int *)0;
    ++(*ZERO);
  }
#endif // USE_ASSERT_SEG
#endif

  __kmp_msg(kmp_ms_fatal, KMP_MSG(AssertionFailure, file, line),
            KMP_HNT(SubmitBugReport), __kmp_msg_null);

  return 0;

} // __kmp_debug_assert

#endif // KMP_USE_ASSERT

/* Dump debugging buffer to stderr */
void __kmp_dump_debug_buffer(void) {
  if (__kmp_debug_buffer != NULL) {
    int i;
    int dc = __kmp_debug_count;
    char *db = &__kmp_debug_buffer[(dc % __kmp_debug_buf_lines) *
                                   __kmp_debug_buf_chars];
    char *db_end =
        &__kmp_debug_buffer[__kmp_debug_buf_lines * __kmp_debug_buf_chars];
    char *db2;

    __kmp_acquire_bootstrap_lock(&__kmp_stdio_lock);
    __kmp_printf_no_lock("\nStart dump of debugging buffer (entry=%d):\n",
                         dc % __kmp_debug_buf_lines);

    for (i = 0; i < __kmp_debug_buf_lines; i++) {

      if (*db != '\0') {
        /* Fix up where no carriage return before string termination char */
        for (db2 = db + 1; db2 < db + __kmp_debug_buf_chars - 1; db2++) {
          if (*db2 == '\0') {
            if (*(db2 - 1) != '\n') {
              *db2 = '\n';
              *(db2 + 1) = '\0';
            }
            break;
          }
        }
        /* Handle case at end by shortening the printed message by one char if
         * necessary */
        if (db2 == db + __kmp_debug_buf_chars - 1 && *db2 == '\0' &&
            *(db2 - 1) != '\n') {
          *(db2 - 1) = '\n';
        }

        __kmp_printf_no_lock("%4d: %.*s", i, __kmp_debug_buf_chars, db);
        *db = '\0'; /* only let it print once! */
      }

      db += __kmp_debug_buf_chars;
      if (db >= db_end)
        db = __kmp_debug_buffer;
    }

    __kmp_printf_no_lock("End dump of debugging buffer (entry=%d).\n\n",
                         (dc + i - 1) % __kmp_debug_buf_lines);
    __kmp_release_bootstrap_lock(&__kmp_stdio_lock);
  }
}
