
#include "../../common/common.h"


const char *OpenSSL_version(int);
# define OPENSSL_VERSION          0

static const char *Build_OpenSSL_LP_Version_String(const char *str)
{
  char ver[32];
  int pos = 0;

  if (str == NULL)
    return NULL;

  int n = sscanf(str, "OpenSSL %31s%n", (char *)&ver, &pos);
  if (n == 1) {
    size_t size = strlen(str) + ARR_LEN(LP_SUFFIX) + 1;
    char *new_ver_str = (char *) calloc(size, sizeof(char));
    if (new_ver_str == NULL) {
      return str;
    }
    sprintf(new_ver_str, "OpenSSL %s", ver);
    strcat(new_ver_str, LP_SUFFIX);
    strcat(new_ver_str, &str[pos]);

    return new_ver_str;
  }

  return str;
}

__attribute__((visibility ("default")))
const char *OpenSSL_version_lp(int type)
{
  static volatile const char *new_ver_str;
  const int _0 = 0;

  /* Implement a lock without using the pthread functions.  We can't assume
     that the function will be called only in single-threaded applications.
     Hence if two threads called this function we have to be careful with the
     state that thread #1 is building the string and thread #2 called this
     function. In this case we have to block thread #2 until the string is
     completed.  */
  static atomic_int lock = 0;

  /* Initialize variables.  */
  if (atomic_compare_exchange_strong(&lock, &_0, 1)) {
    const char *str = CALL_OLD_FUNCTION_1(OpenSSL_version, OPENSSL_VERSION);
    new_ver_str = Build_OpenSSL_LP_Version_String(str);
    atomic_store(&lock, 2);
  }

  while (atomic_load(&lock) < 2)
    ; /* Wait for variable initialization to end.  */

  if (type == OPENSSL_VERSION) {
    return (const char *) new_ver_str;
  }

  return CALL_OLD_FUNCTION_1(OpenSSL_version, type);
}
