From c774e08eb19b61f7f636e6e87bd4cd8723173813 Mon Sep 17 00:00:00 2001 From: ari melody Date: Fri, 13 Mar 2026 04:22:02 +0000 Subject: [PATCH] db read and write --- .gitignore | 1 + hashmap.c | 4 +- hashmap.h | 4 +- main.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 146 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index c3cfdde..6881a92 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ hashmap +*.db diff --git a/hashmap.c b/hashmap.c index f34ffec..ff2245d 100644 --- a/hashmap.c +++ b/hashmap.c @@ -20,7 +20,7 @@ long long hash(const char *s) { return value; } -void *get(HashMap *map, char *key) { +void *map_get(HashMap *map, char *key) { Bucket *bucket = &map->buckets[hash(key) % HASHMAP_BUCKETS]; Entry *entry = NULL; @@ -32,7 +32,7 @@ void *get(HashMap *map, char *key) { return NULL; } -Entry *set(HashMap *map, char *key, void *data, size_t data_size) { +Entry *map_set(HashMap *map, char *key, void *data, size_t data_size) { Bucket *bucket = &map->buckets[hash(key) % HASHMAP_BUCKETS]; Entry *entry = NULL; diff --git a/hashmap.h b/hashmap.h index 873d66c..64c271c 100644 --- a/hashmap.h +++ b/hashmap.h @@ -22,7 +22,7 @@ typedef struct HashMap { } HashMap; void init_map(HashMap *map); -void *get(HashMap *map, char *key); -Entry *set(HashMap *map, char *key, void *data, size_t data_size); +void *map_get(HashMap *map, char *key); +Entry *map_set(HashMap *map, char *key, void *data, size_t data_size); #endif // _HASHMAP_H diff --git a/main.c b/main.c index d49d595..99aa766 100644 --- a/main.c +++ b/main.c @@ -1,23 +1,140 @@ #include "hashmap.h" #include +#include #include #include #include +#include #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\n"); + "\":q\" to exit\n" + "\":w \" to save\n" + "\":o \" to load\n\n"); - HashMap map; - init_map(&map); + AppState app = { 0 }; + init_map(&app.map); + + char buf[INPUT_BUF_SIZE]; + app.running = 1; + while (app.running) { + memset(buf, 0, INPUT_BUF_SIZE); - char running = 1; - while (running) { printf("> "); - - char buf[INPUT_BUF_SIZE]; if (fgets(buf, INPUT_BUF_SIZE, stdin) == NULL) { fprintf(stderr, "failed to read stdin: %u\n", errno); return EXIT_FAILURE; @@ -25,12 +142,22 @@ int main(int argc, char *argv[]) { size_t buf_len = strnlen(buf, INPUT_BUF_SIZE); buf[buf_len - 1] = 0; - if (!strcmp(buf, ":q")) - break; + 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 = get(&map, buf); + void *data = map_get(&app.map, buf); if (data == NULL) printf("\n"); else @@ -39,21 +166,21 @@ int main(int argc, char *argv[]) { continue; } - size_t key_len = eq - buf + 1; + uint16_t key_len = eq - buf + 1; char key[key_len]; strncpy(key, buf, key_len); key[key_len - 1] = 0; - size_t value_len = strlen(buf + key_len); + 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; - set(&map, key, value, value_len); + map_set(&app.map, key, value, value_len); } for (size_t bucket_i = 0; bucket_i < HASHMAP_BUCKETS; bucket_i++) { - Bucket *bucket = &map.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);