191 lines
5.2 KiB
C
191 lines
5.2 KiB
C
#include "hashmap.h"
|
|
#include <errno.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#define INPUT_BUF_SIZE 1024
|
|
|
|
const char HASHMAPP_MAGIC[] = "HSMP";
|
|
|
|
typedef struct AppState {
|
|
char running;
|
|
HashMap map;
|
|
} AppState;
|
|
|
|
void open_file(HashMap *map, const char *filename) {
|
|
FILE *file = fopen(filename, "r");
|
|
if (file == NULL) {
|
|
fprintf(stderr, "failed to open file: %s\n", strerror(errno));
|
|
return;
|
|
}
|
|
|
|
fseek(file, 0, SEEK_END);
|
|
long filesize = ftell(file);
|
|
fseek(file, 0, SEEK_SET);
|
|
if (filesize < 4) {
|
|
fprintf(stderr, "invalid file: %s\n", filename);
|
|
return;
|
|
}
|
|
|
|
int magic_len = strlen(HASHMAPP_MAGIC);
|
|
char magic[magic_len + 1];
|
|
unsigned long cur = ftell(file);
|
|
fread(magic, magic_len, 1, file);
|
|
magic[magic_len] = 0;
|
|
if (strcmp(HASHMAPP_MAGIC, magic) != 0) {
|
|
fprintf(stderr, "invalid file: %s\n", filename);
|
|
return;
|
|
}
|
|
|
|
while (cur < filesize) {
|
|
uint16_t key_len = 0;
|
|
fread(&key_len, sizeof(uint16_t), 1, file);
|
|
char key[key_len + 1];
|
|
fread(key, key_len, 1, file);
|
|
key[key_len] = 0;
|
|
|
|
uint16_t data_size = 0;
|
|
fread(&data_size, sizeof(uint16_t), 1, file);
|
|
char *data = malloc(data_size);
|
|
fread(data, data_size, 1, file);
|
|
data[data_size] = 0;
|
|
|
|
map_set(map, key, data, data_size);
|
|
|
|
cur = ftell(file);
|
|
}
|
|
|
|
if (fclose(file) != 0) {
|
|
fprintf(stderr, "failed to close file: %s\n", strerror(errno));
|
|
return;
|
|
}
|
|
|
|
printf("opened db: %s\n", filename);
|
|
}
|
|
|
|
void write_file(HashMap *map, const char *filename) {
|
|
FILE *file = fopen(filename, "w+");
|
|
if (file == NULL) {
|
|
fprintf(stderr, "failed to open file: %s\n", strerror(errno));
|
|
return;
|
|
}
|
|
|
|
int fd = fileno(file);
|
|
if (fd == -1) {
|
|
fprintf(stderr, "failed to get descriptor: %s\n", strerror(errno));
|
|
fclose(file);
|
|
return;
|
|
}
|
|
|
|
unsigned long offset = 0;
|
|
offset += fwrite(HASHMAPP_MAGIC, strlen(HASHMAPP_MAGIC), 1, file);
|
|
|
|
for (uint16_t bucket_i = 0; bucket_i < HASHMAP_BUCKETS; bucket_i++) {
|
|
Bucket *bucket = &map->buckets[bucket_i];
|
|
for (uint16_t i = 0; i < bucket->n_entries; i++) {
|
|
Entry *entry = &bucket->entries[i];
|
|
uint16_t key_len = strlen(entry->key);
|
|
uint16_t data_len = strlen(entry->data);
|
|
offset += fwrite(&key_len, sizeof(uint16_t), 1, file);
|
|
offset += fwrite(entry->key, strlen(entry->key), 1, file);
|
|
offset += fwrite(&data_len, sizeof(uint16_t), 1, file);
|
|
offset += fwrite(entry->data, strlen(entry->data), 1, file);
|
|
}
|
|
}
|
|
|
|
if (ftruncate(fd, offset) != 0) {
|
|
fprintf(stderr, "failed to truncate file: %s\n", strerror(errno));
|
|
fclose(file);
|
|
return;
|
|
}
|
|
if (fclose(file) != 0) {
|
|
fprintf(stderr, "failed to close file: %s\n", strerror(errno));
|
|
return;
|
|
}
|
|
|
|
printf("written db to \"%s\" successfully.\n", filename);
|
|
}
|
|
|
|
void handle_command(AppState *app, char *buf, size_t buf_len) {
|
|
if (!strcmp(buf, "q"))
|
|
app->running = 0;
|
|
else if (strcmp(buf, "w ") > 0)
|
|
write_file(&app->map, buf + 2);
|
|
else if (strcmp(buf, "o ") > 0)
|
|
open_file(&app->map, buf + 2);
|
|
else
|
|
printf("?\n");
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
printf("hashmapp. the map to app all hashes. wait-\n"
|
|
"\":q\" to exit\n"
|
|
"\":w <file>\" to save\n"
|
|
"\":o <file>\" to load\n\n");
|
|
|
|
AppState app = { 0 };
|
|
init_map(&app.map);
|
|
|
|
char buf[INPUT_BUF_SIZE];
|
|
app.running = 1;
|
|
while (app.running) {
|
|
memset(buf, 0, INPUT_BUF_SIZE);
|
|
|
|
printf("> ");
|
|
if (fgets(buf, INPUT_BUF_SIZE, stdin) == NULL) {
|
|
fprintf(stderr, "failed to read stdin: %u\n", errno);
|
|
return EXIT_FAILURE;
|
|
}
|
|
size_t buf_len = strnlen(buf, INPUT_BUF_SIZE);
|
|
buf[buf_len - 1] = 0;
|
|
|
|
if (buf_len == 0)
|
|
continue;
|
|
|
|
if (buf[0] == ':') {
|
|
if (buf_len < 2) {
|
|
printf("?\n");
|
|
continue;
|
|
}
|
|
|
|
handle_command(&app, buf + 1, buf_len - 1);
|
|
continue;
|
|
}
|
|
|
|
char *eq = strchr(buf, '=');
|
|
if (eq == NULL) {
|
|
void *data = map_get(&app.map, buf);
|
|
if (data == NULL)
|
|
printf("\n");
|
|
else
|
|
printf("%s\n", (char*)data);
|
|
|
|
continue;
|
|
}
|
|
|
|
uint16_t key_len = eq - buf + 1;
|
|
char key[key_len];
|
|
strncpy(key, buf, key_len);
|
|
key[key_len - 1] = 0;
|
|
|
|
uint16_t value_len = strlen(buf + key_len);
|
|
char *value = malloc(sizeof(char) * value_len);
|
|
strncpy(value, buf + key_len, value_len);
|
|
value[value_len] = 0;
|
|
|
|
map_set(&app.map, key, value, value_len);
|
|
}
|
|
|
|
for (size_t bucket_i = 0; bucket_i < HASHMAP_BUCKETS; bucket_i++) {
|
|
Bucket *bucket = &app.map.buckets[bucket_i];
|
|
for (size_t i = 0; i < bucket->n_entries; i++) {
|
|
free(bucket->entries[i].key);
|
|
free(bucket->entries[i].data);
|
|
}
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|