aoc/src/advent_utility.c
2024-12-03 12:17:24 -08:00

169 lines
4.7 KiB
C

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define PCRE2_CODE_UNIT_WIDTH 8
#include "pcre2.h"
#if defined __linux__ || defined __APPLE__
#include <openssl/md5.h>
#else
#include <md5.h>
#endif
#include "advent_utility.h"
char *md5_str(const char *input) {
unsigned char digest[16];
#if defined __linux__ || defined __APPLE__
MD5_CTX context;
MD5_Init(&context);
MD5_Update(&context, input, strlen(input));
MD5_Final(digest, &context);
#else
struct MD5Context context;
MD5Init(&context);
MD5Update(&context, input, strlen(input));
MD5Final(digest, &context);
#endif
char *md5string = malloc(33);
for (int i = 0; i < 16; ++i) {
snprintf(&md5string[i * 2], 33, "%02x", (unsigned int) digest[i]);
}
return md5string;
}
Vector *string_to_int_vector(const char *input_string, const char *delim) {
char *copy = strdup(input_string);
char *token = strtok(copy, delim);
Vector *v = malloc(sizeof(Vector));
vec_init(v, free);
while (token != NULL) {
int *i = malloc(sizeof(int));
*i = atoi(token);
vec_push(v, i, NULL);
token = strtok(NULL, delim);
}
free(copy);
return v;
}
int int_comp(const void *a, const void *b) {
return *(int *) a - *(int *) b;
}
char **get_matches(char *in, char *pat, size_t *sz, size_t max_matches) {
pcre2_code *re;
PCRE2_SPTR pattern = (PCRE2_SPTR)pat;
int errnum;
size_t erroff;
PCRE2_SPTR8 substr;
size_t substr_sz;
PCRE2_SPTR subject = (PCRE2_SPTR)in;
size_t subject_sz = strlen(in);
re = pcre2_compile(pattern, PCRE2_ZERO_TERMINATED, 0, &errnum, &erroff, NULL);
if (re == NULL) {
char buffer[256];
pcre2_get_error_message(errnum, buffer, sizeof(buffer));
printf("PCRE2 compilation failed at offset %d: %s\n", (int) erroff, buffer);
return NULL;
}
char **matches = NULL;
matches = malloc(sizeof(char *) * max_matches);
if (matches == NULL) {
printf("failed to malloc matches\n");
pcre2_code_free(re);
return NULL;
}
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern_8(re, NULL);
int rc = pcre2_match(re, subject, subject_sz, 0, 0, match_data, NULL);
if (rc < 0) {
switch (rc) {
case PCRE2_ERROR_NOMATCH:
printf("PCRE2 no matches\n");
break;
default:
printf("PCRE2 matching error %d\n", rc);
break;
}
pcre2_match_data_free(match_data);
pcre2_code_free(re);
return NULL;
}
PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
*sz = 0;
for (int i = 0; i < rc; ++i) {
substr = subject + ovector[2*i];
substr_sz = ovector[2*i+1] - ovector[2*i];
matches[*sz] = (char *) malloc(substr_sz + 1);
strncpy(matches[*sz], substr, substr_sz);
*sz += 1;
}
// Now loop through rest of the matches, if there are any
for (;;) {
uint32_t options = 0;
PCRE2_SIZE start_offset = ovector[1];
// Check for empty match
if (ovector[0] == ovector[1]) {
if (ovector[0] == subject_sz) {
break;
}
options = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED;
}
rc = pcre2_match(re, subject, subject_sz, start_offset, options, match_data, NULL);
if (rc == PCRE2_ERROR_NOMATCH) {
// All matches have been found
if (options == 0) {
break;
}
// Handle newlines
ovector[1] = start_offset + 1;
if (start_offset < subject_sz - 1 &&
//subject[start_offset] == '\r' &&
subject[start_offset + 1] == '\n') {
ovector[1] += 1;
}
continue;
}
// Other failures, non-recoverable
if (rc < 0) {
printf("PCRE2 match-matching error %d\n", rc);
pcre2_match_data_free(match_data);
pcre2_code_free(re);
return NULL;
}
for (int i = 0; i < rc; ++i) {
substr = subject + ovector[2*i];
substr_sz = ovector[2*i+1] - ovector[2*i];
matches[*sz] = (char *) malloc(substr_sz + 1);
strncpy(matches[*sz], substr, substr_sz);
*sz += 1;
}
}
pcre2_match_data_free(match_data);
pcre2_code_free(re);
return matches;
}
void free_matches(char **matches, size_t sz) {
for (size_t i = 0; i < sz; ++i) {
free(matches[i]);
}
free(matches);
}