<commit_before>
#include <stdlib.h>
#include <string.h>
#include <stdalign.h>
#include <GL/gl.h>

#include <rescache/rescache.h>

#include "types.h"
#include "shader.h"
#include "load-shader.h"
#include "load-program.h"

struct program_key
{
	size_t n;
	char keys[];
};

static int string_cmp(const void *a, const void *b) { return strcmp(a, b); }

static int make_key(char const *const *keys, size_t n, void **out, size_t *size)
{
	struct program_key *pk;
	size_t i, j, len, sz;
	char const **sorted_keys;

	sorted_keys = malloc(n * sizeof *sorted_keys);
	if (!sorted_keys) { return -1; }
	(void)memcpy(sorted_keys, keys, n * sizeof *keys);

	sz = sizeof *pk;
	for (i = 0; i < n; i++) {
		/* FIXME: Potential overflow */
		sz += strlen(keys[i]) + 1;
	}

	pk = malloc(sz);
	if (!pk) { free(sorted_keys); return -2; }

	qsort(sorted_keys, n, sizeof *sorted_keys, string_cmp);

	(void)memset(pk, 0, sz);
	for (i = 0, j = 0; i < n; i++) {
		len = strlen(sorted_keys[i]);
		(void)memcpy(pk->keys + j, sorted_keys[i], len);
		j += len + 1;
	}
	free(sorted_keys);

	*out = pk;
	*size = sz;

	return 0;
}

static int load_program(void const *key, size_t ksz, void *data, void *link)
{
	char const *p;
	struct glshader const **shaders;
	size_t i;
	int result;

	struct program_key const *pk = key;
	struct glprogram *program = data;
	struct glstate *state = link;
<commit_msg>Fix creation of program resource-key<commit_after>
#include <stdlib.h>
#include <string.h>
#include <stdalign.h>
#include <GL/gl.h>

#include <rescache/rescache.h>

#include "types.h"
#include "shader.h"
#include "load-shader.h"
#include "load-program.h"

struct program_key
{
	size_t n;
	char keys[];
};

static int string_cmp(const void *a, const void *b) {
	char const *a_str = *(char const *const *)a;
	char const *b_str = *(char const *const *)b;
	return strcmp(a_str, b_str);
}

static int make_key(char const *const *keys, size_t n, void **out, size_t *size)
{
	struct program_key *pk;
	size_t i, j, len, sz;
	char const **sorted_keys;

	sorted_keys = malloc(n * sizeof *sorted_keys);
	if (!sorted_keys) { return -1; }
	(void)memcpy(sorted_keys, keys, n * sizeof *keys);

	sz = sizeof *pk;
	for (i = 0; i < n; i++) {
		/* FIXME: Potential overflow */
		sz += strlen(keys[i]) + 1;
	}

	pk = malloc(sz);
	if (!pk) { free(sorted_keys); return -2; }

	qsort(sorted_keys, n, sizeof *sorted_keys, string_cmp);

	(void)memset(pk, 0, sz);
	for (i = 0, j = 0; i < n; i++) {
		len = strlen(sorted_keys[i]);
		(void)memcpy(pk->keys + j, sorted_keys[i], len);
		j += len + 1;
	}
	free(sorted_keys);

	pk->n = n;
	*out = pk;
	*size = sz;

	return 0;
}

static int load_program(void const *key, size_t ksz, void *data, void *link)
{
	char const *p;
	struct glshader const **shaders;
	size_t i;
	int result;

	struct program_key const *pk = key;
	struct glprogram *program = data;
	struct glstate *state = link;

{'fraction_non_alphanumeric': 0.1653899721448468, 'fraction_numerical': 0.006267409470752089, 'mean_word_length': 4.058098591549296, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 16, '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': '88441', 'n_tokens_mistral': 1216, 'n_tokens_neox': 1179, 'n_words': 342}