<commit_before>//
// clib-configure.c
//
// Copyright (c) 2012-2020 clib authors
// MIT licensed
//

#include <curl/curl.h>
#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>

#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <unistd.h>
#endif

#ifdef HAVE_PTHREADS
#include <pthread.h>
#endif

#ifdef _WIN32
#include <direct.h>
#define getcwd _getcwd
#else
#include <unistd.h>
#endif

#include "common/clib-cache.h"
#include "common/clib-package.h"

#include <asprintf/asprintf.h>
#include <commander/commander.h>
#include <debug/debug.h>
#include <fs/fs.h>
#include <hash/hash.h>
#include <list/list.h>
#include <logger/logger.h>
#include <path-join/path-join.h>
#include <str-flatten/str-flatten.h>
#include <trim/trim.h>

#include "version.h"

#define CLIB_PACKAGE_CACHE_TIME 30 * 24 * 60 * 60
#define PROGRAM_NAME "clib-configure"

#define SX(s) #s
#define S(s) SX(s)

#ifdef HAVE_PTHREADS
#define MAX_THREADS 4
#endif

#if defined(_WIN32) || defined(WIN32) || defined(__MINGW32__) ||               \
    defined(__MINGW64__) || defined(__CYGWIN__)
#define setenv(k, v, _) _putenv_s(k, v)
#define realpath(a, b) _fullpath(a, b, strlen(a))
#endif

typedef struct options options_t;
struct options {
  const char *dir;
  char *prefix;
  int force;
  int verbose;
  int dev;
  int skip_cache;
  int flags;
  int global;
#ifdef HAVE_PTHREADS
  unsigned int concurrency;
#endif
};

const char *manifest_names[] = {"clib.json", "package.json", 0};

clib_package_opts_t package_opts = {0};
clib_package_t *root_package = 0;

hash_t *configured = 0;
command_t program = {0};
debug_t debugger = {0};

char **rest_argv = 0;
int rest_offset = 0;
int rest_argc = 0;

options_t opts = {.skip_cache = 0,
                  .verbose = 1,
                  .force = 0,
                  .dev = 0,
#ifdef HAVE_PTHREADS
                  .concurrency = MAX_THREADS,
#endif

#ifdef _WIN32
                  .dir = ".\\deps"
#else
                  .dir = "./deps"
#endif

};

int configure_package(const char *dir);

#ifdef HAVE_PTHREADS
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
typedef struct clib_package_thread clib_package_thread_t;
struct clib_package_thread {
  const char *dir;
};

void *configure_package_with_manifest_name_thread(void *arg) {
  clib_package_thread_t *wrap = arg;
  const char *dir = wrap->dir;
  configure_package(dir);
  return 0;
}
#endif

int configure_package_with_manifest_name(const char *dir, const char *file) {
  clib_package_t *package = 0;
  char *json = 0;
  int ok = 0;
  int rc = 0;

#ifdef PATH_MAX
  long path_max = PATH_MAX;
#elif defined(_PC_PATH_MAX)
  long path_max = pathconf(dir, _PC_PATH_MAX);
#else
  long path_max = 4096;
#endif

  char *path = path_join(dir, file);

  if (0 == path) {
    return -ENOMEM;
  }

#ifdef HAVE_PTHREADS
  pthread_mutex_lock(&mutex);
#endif

  if (!root_package) {
    const char *name = NULL;
    char *json = NULL;
    unsigned int i = 0;

    do {
      name = manifest_names[i];
      json = fs_read(name);
    } while (NULL != manifest_names[++i] && !json);

    if (json) {
      root_package = clib_package_new(json, opts.verbose);
    }

    if (root_package && root_package->prefix) {
      char prefix[path_max];
      memset(prefix, 0, path_max);
      realpath(root_package->prefix, prefix);
      unsigned long int size = strlen(prefix) + 1;
      free(root_package->prefix);
      root_package->prefix = malloc(size);
      memset((void *)root_package->prefix, 0, size);
      memcpy((void *)root_package->prefix, prefix, size);
    }
  }

  if (hash_has(configured, path)) {
#ifdef HAVE_PTHREADS
    pthread_mutex_unlock(&mutex);
#endif
    goto cleanup;
  }

#ifdef HAVE_PTHREADS
  pthread_mutex_unlock(&mutex);
#endif

  if (0 == fs_exists(path)) {
    debug(&debugger, "read %s", path);
    json = fs_read(path);
  }

  if (0 != json) {
#ifdef DEBUG
    package = clib_package_new(json, 1);
#else<commit_msg>Fix memory leak (#228)<commit_after>//
// clib-configure.c
//
// Copyright (c) 2012-2021 clib authors
// MIT licensed
//

#include <curl/curl.h>
#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>

#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <unistd.h>
#endif

#ifdef HAVE_PTHREADS
#include <pthread.h>
#endif

#ifdef _WIN32
#include <direct.h>
#define getcwd _getcwd
#else
#include <unistd.h>
#endif

#include "common/clib-cache.h"
#include "common/clib-package.h"

#include <asprintf/asprintf.h>
#include <commander/commander.h>
#include <debug/debug.h>
#include <fs/fs.h>
#include <hash/hash.h>
#include <list/list.h>
#include <logger/logger.h>
#include <path-join/path-join.h>
#include <str-flatten/str-flatten.h>
#include <trim/trim.h>

#include "version.h"

#define CLIB_PACKAGE_CACHE_TIME 30 * 24 * 60 * 60
#define PROGRAM_NAME "clib-configure"

#define SX(s) #s
#define S(s) SX(s)

#ifdef HAVE_PTHREADS
#define MAX_THREADS 4
#endif

#if defined(_WIN32) || defined(WIN32) || defined(__MINGW32__) ||               \
    defined(__MINGW64__) || defined(__CYGWIN__)
#define setenv(k, v, _) _putenv_s(k, v)
#define realpath(a, b) _fullpath(a, b, strlen(a))
#endif

typedef struct options options_t;
struct options {
  const char *dir;
  char *prefix;
  int force;
  int verbose;
  int dev;
  int skip_cache;
  int flags;
  int global;
#ifdef HAVE_PTHREADS
  unsigned int concurrency;
#endif
};

const char *manifest_names[] = {"clib.json", "package.json", 0};

clib_package_opts_t package_opts = {0};
clib_package_t *root_package = 0;

hash_t *configured = 0;
command_t program = {0};
debug_t debugger = {0};

char **rest_argv = 0;
int rest_offset = 0;
int rest_argc = 0;

options_t opts = {.skip_cache = 0,
                  .verbose = 1,
                  .force = 0,
                  .dev = 0,
#ifdef HAVE_PTHREADS
                  .concurrency = MAX_THREADS,
#endif

#ifdef _WIN32
                  .dir = ".\\deps"
#else
                  .dir = "./deps"
#endif

};

int configure_package(const char *dir);

#ifdef HAVE_PTHREADS
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
typedef struct clib_package_thread clib_package_thread_t;
struct clib_package_thread {
  const char *dir;
};

void *configure_package_with_manifest_name_thread(void *arg) {
  clib_package_thread_t *wrap = arg;
  const char *dir = wrap->dir;
  configure_package(dir);
  return 0;
}
#endif

int configure_package_with_manifest_name(const char *dir, const char *file) {
  clib_package_t *package = 0;
  char *json = NULL;
  int ok = 0;
  int rc = 0;

#ifdef PATH_MAX
  long path_max = PATH_MAX;
#elif defined(_PC_PATH_MAX)
  long path_max = pathconf(dir, _PC_PATH_MAX);
#else
  long path_max = 4096;
#endif

  char *path = path_join(dir, file);

  if (0 == path) {
    return -ENOMEM;
  }

#ifdef HAVE_PTHREADS
  pthread_mutex_lock(&mutex);
#endif

  if (!root_package) {
    const char *name = NULL;
    unsigned int i = 0;

    do {
      name = manifest_names[i];
      json = fs_read(name);
    } while (NULL != manifest_names[++i] && !json);

    if (json) {
      root_package = clib_package_new(json, opts.verbose);
    }

    if (root_package && root_package->prefix) {
      char prefix[path_max];
      memset(prefix, 0, path_max);
      realpath(root_package->prefix, prefix);
      unsigned long int size = strlen(prefix) + 1;
      free(root_package->prefix);
      root_package->prefix = malloc(size);
      memset((void *)root_package->prefix, 0, size);
      memcpy((void *)root_package->prefix, prefix, size);
    }
  }

  if (hash_has(configured, path)) {
#ifdef HAVE_PTHREADS
    pthread_mutex_unlock(&mutex);
#endif
    goto cleanup;
  }

#ifdef HAVE_PTHREADS
  pthread_mutex_unlock(&mutex);
#endif

  // Free the json if it was allocated before attempting to modify it
  free(json);

  if (0 == fs_exists(path)) {
    debug(&debugger, "read %s", path);
    json = fs_read(path);
  }

  if (0 != json) {
#ifdef DEBUG
    package = clib_package_new(json, 1);
#else
{'fraction_non_alphanumeric': 0.1362503116429818, 'fraction_numerical': 0.014958863126402393, 'mean_word_length': 3.545609065155807, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6774322', 'n_tokens_mistral': 3120, 'n_tokens_neox': 2970, 'n_words': 724}