From f2912ab7a76a0362c41ca8b336cc6933f4f9fc30 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Mon, 16 Apr 2007 23:56:58 -0700 Subject: [PATCH] Add categories and bins to store data Test the whole works by reading all data and then writing it out, (with atomic replacement of original files). --- mnemon.c | 424 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 380 insertions(+), 44 deletions(-) diff --git a/mnemon.c b/mnemon.c index 8f735f4..a1872bc 100644 --- a/mnemon.c +++ b/mnemon.c @@ -26,16 +26,81 @@ #include #include #include +#include + +typedef struct _item { + int count; + char *challenge; + char *response; +} item_t; + +typedef struct _bin { + int count; + int items_size; + int num_items; + item_t **items; +} bin_t; + +typedef struct _category { + char *name; + int items_size; + int num_items; + item_t *items; +} category_t; typedef struct _mnemon { - int dummy; + char *dir_name; + + int categories_size; + int num_categories; + category_t *categories; + + int bins_size; + int num_bins; + bin_t *bins; } mnemon_t; -typedef struct _ic { - int bin; - char *challenge; - char *response; -} ic_t; +static void * +xmalloc (size_t size) +{ + void *ret; + + ret = malloc (size); + if (ret == NULL) { + fprintf (stderr, "Error: out of memory\n"); + exit (1); + } + + return ret; +} + +static void * +xrealloc (void *ptr, size_t size) +{ + void *ret; + + ret = realloc (ptr, size); + if (ret == NULL) { + fprintf (stderr, "Error: out of memory\n"); + exit (1); + } + + return ret; +} + +static char * +xstrdup (const char *s) +{ + char *ret; + + ret = strdup (s); + if (s == NULL) { + fprintf (stderr, "Error: out of memory\n"); + exit (1); + } + + return ret; +} static void xasprintf (char **strp, const char *fmt, ...) @@ -53,6 +118,260 @@ xasprintf (char **strp, const char *fmt, ...) } } +static void +item_init (item_t *item, + int count, + const char *challenge, + const char *response) +{ + item->count = count; + + item->challenge = xmalloc (strlen (challenge) + 1 + + strlen (response) + 1); + item->response = item->challenge + strlen (challenge) + 1; + + strcpy (item->challenge, challenge); + strcpy (item->response, response); +} + +static void +item_fini (item_t *item) +{ + /* item->response shares allocation with item->challenge, so + * doesn't require a separate call to free */ + free (item->challenge); +} + +static void +category_init (category_t *category, + const char *name) +{ + category->name = xstrdup (name); + + category->items_size = 0; + category->num_items = 0; + category->items = NULL; +} + +static void +category_fini (category_t *category) +{ + int i; + + for (i = 0; i < category->num_items; i++) + item_fini (&category->items[i]); + + free (category->items); + + free (category->name); +} + +static void +category_grow (category_t *category) +{ + if (category->items_size) + category->items_size *= 2; + else + category->items_size = 1; + + category->items = xrealloc (category->items, + category->items_size * sizeof (item_t)); +} + +static item_t * +category_add_item (category_t *category, + int count, + const char *challenge, + const char *response) +{ + item_t *item; + + if (category->num_items == category->items_size) + category_grow (category); + + item = &category->items[category->num_items++]; + + item_init (item, count, challenge, response); + + return item; +} + +static void +category_print (category_t *category, + FILE *file) +{ + int i; + item_t *item; + + for (i = 0; i < category->num_items; i++) { + item = &category->items[i]; + if (i != 0) + fprintf (file, "\n"); + fprintf (file, "%d\n%s\n%s\n", + item->count, + item->challenge, + item->response); + } +} + +static void +bin_init (bin_t *bin, + int count) +{ + bin->count = count; + + bin->items_size = 0; + bin->num_items = 0; + bin->items = NULL; +} + +static void +bin_fini (bin_t *bin) +{ + free (bin->items); +} + +static void +bin_grow (bin_t *bin) +{ + if (bin->items_size) + bin->items_size *= 2; + else + bin->items_size = 1; + + bin->items = xrealloc (bin->items, + bin->items_size * sizeof (item_t*)); +} + +static void +bin_add_item (bin_t *bin, + item_t *item) +{ + assert (item->count == bin->count); + + if (bin->num_items == bin->items_size) + bin_grow (bin); + + bin->items[bin->num_items++] = item; +} + +static void +mnemon_init (mnemon_t *mnemon) +{ + char *home; + + home = getenv ("HOME"); + if (home == NULL) + home = ""; + + xasprintf (&mnemon->dir_name, "%s/.mnemon", getenv ("HOME")); + + mnemon->categories_size = 0; + mnemon->num_categories = 0; + mnemon->categories = NULL; + + mnemon->bins_size = 0; + mnemon->num_bins = 0; + mnemon->bins = NULL; +} + +static void +mnemon_fini (mnemon_t *mnemon) +{ + int i; + + for (i = 0; i < mnemon->num_bins; i++) + bin_fini (&mnemon->bins[i]); + free (mnemon->bins); + + for (i = 0; i < mnemon->num_categories; i++) + category_fini (&mnemon->categories[i]); + free (mnemon->categories); + + free (mnemon->dir_name); +} + +static void +mnemon_categories_grow (mnemon_t *mnemon) +{ + if (mnemon->categories_size) + mnemon->categories_size *= 2; + else + mnemon->categories_size = 1; + + mnemon->categories = xrealloc (mnemon->categories, + mnemon->categories_size * sizeof (category_t)); +} + +static category_t * +mnemon_get_category (mnemon_t *mnemon, + const char *name) +{ + int i; + category_t *category; + + for (i = 0; i < mnemon->num_categories; i++) + if (strcmp (mnemon->categories[i].name, name) == 0) + return &mnemon->categories[i]; + + mnemon_categories_grow (mnemon); + + category = &mnemon->categories[mnemon->num_categories++]; + + category_init (category, name); + + return category; +} + +static void +mnemon_bins_grow (mnemon_t *mnemon) +{ + if (mnemon->bins_size) + mnemon->bins_size *= 2; + else + mnemon->bins_size = 1; + + mnemon->bins = xrealloc (mnemon->bins, + mnemon->bins_size * sizeof (bin_t)); +} + +static bin_t * +mnemon_get_bin (mnemon_t *mnemon, + int count) +{ + int i; + bin_t *bin; + + for (i = 0; i < mnemon->num_bins; i++) + if (mnemon->bins[i].count == count) + return &mnemon->bins[i]; + + mnemon_bins_grow (mnemon); + + bin = &mnemon->bins[mnemon->num_bins++]; + + bin_init (bin, count); + + return bin; +} + +static void +mnemon_add_item (mnemon_t *mnemon, + category_t *category, + int count, + const char *challenge, + const char *response) +{ + item_t *item; + bin_t *bin; + + item = category_add_item (category, count, challenge, response); + + bin = mnemon_get_bin (mnemon, count); + + bin_add_item (bin, item); +} + static void chomp (char *s) { @@ -64,14 +383,19 @@ chomp (char *s) } static void -mnemon_load_from_file (mnemon_t *mnemon, - char *path) +mnemon_load_category (mnemon_t *mnemon, + const char *name) { FILE *file; char *line = NULL, *end; size_t line_size = 0; ssize_t bytes_read; int line_count = 0; + char *path; + category_t *category; + + path = xmalloc (strlen (mnemon->dir_name) + 1 + strlen (name) + 1); + sprintf (path, "%s/%s", mnemon->dir_name, name); file = fopen (path, "r"); if (file == NULL) { @@ -80,8 +404,11 @@ mnemon_load_from_file (mnemon_t *mnemon, exit (1); } + category = mnemon_get_category (mnemon, name); + while (1) { - ic_t ic; + int count; + char *challenge, *response; /* Read bin number (ignoring blank separator lines) */ do { @@ -92,7 +419,7 @@ mnemon_load_from_file (mnemon_t *mnemon, chomp (line); } while (*line == '\0'); - ic.bin = strtol (line, &end, 10); + count = strtol (line, &end, 10); if (*end != '\0') { fprintf (stderr, "Failed to parse bin number from \"%s\" at %s:%d\n", line, path, line_count); @@ -105,7 +432,7 @@ mnemon_load_from_file (mnemon_t *mnemon, break; line_count++; chomp (line); - ic.challenge = strdup (line); + challenge = strdup (line); /* Read response */ bytes_read = getline (&line, &line_size, file); @@ -113,31 +440,29 @@ mnemon_load_from_file (mnemon_t *mnemon, break; line_count++; chomp (line); - ic.response = strdup (line); + response = line; - /* XXX: Add ic to mnemon here */ - printf ("%d: %s => %s\n", ic.bin, ic.challenge, ic.response); - free (ic.challenge); - free (ic.response); + mnemon_add_item (mnemon, category, count, challenge, response); + + free (challenge); } END_OF_FILE: free (line); fclose (file); + free (path); } static void -mnemon_load_from_directory_recursive (mnemon_t *mnemon, - char *path) +mnemon_load (mnemon_t *mnemon) { DIR *dir; struct dirent *dirent; - char *child_path; - dir = opendir (path); + dir = opendir (mnemon->dir_name); if (dir == NULL) { fprintf (stderr, "Error: Failed to open directory %s: %s\n", - path, strerror (errno)); + mnemon->dir_name, strerror (errno)); exit (1); } @@ -146,43 +471,48 @@ mnemon_load_from_directory_recursive (mnemon_t *mnemon, if (dirent == NULL) break; - xasprintf (&child_path, "%s/%s", path, dirent->d_name); - if (dirent->d_type == DT_DIR) { - if (strcmp (dirent->d_name, ".") && - strcmp (dirent->d_name, "..")) - { - mnemon_load_from_directory_recursive (mnemon, child_path); - } - } else if (dirent->d_type == DT_REG) { + if (dirent->d_type == DT_REG) { /* Ignore files matching *~, (yes, this shouldn't be * hard-coded in such an ad-hoc way, but there you go. */ - if (child_path[strlen(child_path)-1] != '~') - mnemon_load_from_file (mnemon, child_path); - } else { - fprintf (stderr, "Warning: Ignoring file %s\n", child_path); + if (dirent->d_name[strlen(dirent->d_name)-1] != '~') + mnemon_load_category (mnemon, dirent->d_name); } - - free (child_path); } closedir (dir); } static void -mnemon_init (mnemon_t *mnemon) +mnemon_save (mnemon_t *mnemon) { - char *dot_mnemon; - char *home; + int i, err; + char *filename, *lock_filename; + FILE *file; + category_t *category; - home = getenv ("HOME"); - if (home == NULL) - home = ""; + for (i = 0; i < mnemon->num_categories; i++) { + category = &mnemon->categories[i]; - xasprintf (&dot_mnemon, "%s/.mnemon", getenv ("HOME")); + xasprintf (&filename, "%s/%s", + mnemon->dir_name, category->name); + xasprintf (&lock_filename, "%s/.#%s", + mnemon->dir_name, category->name); + file = fopen (lock_filename, "w"); + if (file == NULL) { + fprintf (stderr, "Error: Failed to open %s for writing: %s\n", + lock_filename, strerror (errno)); + continue; + } - mnemon_load_from_directory_recursive (mnemon, dot_mnemon); + category_print (category, file); - free (dot_mnemon); + err = rename (lock_filename, filename); + if (err < 0) { + fprintf (stderr, "Error: Failes to rename %s to %s: %s\n", + lock_filename, filename, strerror (errno)); + continue; + } + } } int @@ -192,5 +522,11 @@ main (int argc, char *argv[]) mnemon_init (&mnemon); + mnemon_load (&mnemon); + + mnemon_save (&mnemon); + + mnemon_fini (&mnemon); + return 0; } -- 2.43.0