about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--filehash.c49
-rw-r--r--filehash.h9
-rw-r--r--forg-import.c57
3 files changed, 99 insertions, 16 deletions
diff --git a/filehash.c b/filehash.c
index ace1992..03f75a5 100644
--- a/filehash.c
+++ b/filehash.c
@@ -1,5 +1,6 @@
 #include "filehash.h"
 
+#include <err.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -8,6 +9,7 @@ struct filehash_t
   const char *hash_program;
   const char **argv;
   unsigned max_per_invocation;
+  unsigned next;
 };
 
 filehash_t *
@@ -25,12 +27,14 @@ filehash_new(const char *hash_program, unsigned max_per_invocation)
     .argv = reallocarray(NULL, 1 + max_per_invocation, sizeof(const char *)),
   };
 
-  if (!fh->hash_program)
-    goto fail;
   if (!fh->argv)
     goto fail;
 
-  fh->argv[max_per_invocation] = NULL;
+  for (int i = 0; i <= max_per_invocation; ++i)
+    fh->argv[i] = NULL;
+
+  if (!fh->hash_program)
+    goto fail;
 
   return fh;
 
@@ -39,13 +43,50 @@ fail:
   return NULL;
 }
 
+#include <stdio.h>
+static int run_hash(filehash_t *fh)
+{
+  fputs(fh->hash_program, stderr);
+  for (int i = 0; i < fh->next; ++i) {
+    fputc(' ', stderr);
+    fputs(fh->argv[i], stderr);
+  }
+  fputc('\n', stderr);
+  return 0;
+}
+
+filehash_state_t filehash_send(filehash_t *fh, const char *file_name)
+{
+  if (fh->next >= fh->max_per_invocation)
+    return fhs_rejected;
+
+  const char *copy = strdup(file_name);
+  if (!copy) {
+    warn("strdup");
+    return fhs_failure;
+  }
+
+  fh->argv[fh->next++] = copy;
+  if (fh->next < fh->max_per_invocation)
+    return fhs_accepts;
+
+  if (run_hash(fh) == -1)
+    return fhs_failure;
+
+  return fhs_full;
+}
+
 void
 filehash_free(filehash_t *fh)
 {
   if (!fh)
     return;
 
-  free(fh->argv);
+  if (fh->argv) {
+    for (int i = 0; i <= fh->max_per_invocation; ++i)
+      free((void *)fh->argv[i]);
+    free(fh->argv);
+  }
   free((void *)fh->hash_program);
   free(fh);
 }
diff --git a/filehash.h b/filehash.h
index c52f983..0639c25 100644
--- a/filehash.h
+++ b/filehash.h
@@ -2,8 +2,17 @@
 
 typedef struct filehash_t filehash_t;
 
+typedef enum {
+  fhs_accepts,
+  fhs_failure,
+  fhs_full,
+  fhs_rejected,
+} filehash_state_t;
+
 filehash_t *
 filehash_new(const char *hash_program, unsigned max_per_invocation);
 
+filehash_state_t filehash_send(filehash_t *, const char *file_name);
+
 void
 filehash_free(filehash_t *);
diff --git a/forg-import.c b/forg-import.c
index 30ee7fc..4cfbcb6 100644
--- a/forg-import.c
+++ b/forg-import.c
@@ -7,13 +7,16 @@
 #include <sysexits.h>
 #include <unistd.h>
 
+#include "filehash.h"
+#include "macros.h"
+
 #define optstr "0h:L:r:"
 
 typedef struct
 {
-  const char *hash;
+  const char *hash_program;
   const char *repository;
-  unsigned hash_max_lines;
+  unsigned max_per_invocation;
   char **files;
   unsigned n_files;
   char input_sep;
@@ -61,9 +64,9 @@ read_opts(int argc, char **argv)
   int o;
   const char *prgname;
   options_t options = {
-    .hash = "md5sum",
+    .hash_program = "md5sum",
     .repository = ".",
-    .hash_max_lines = 4096,
+    .max_per_invocation = 4096,
     .input_sep = '\n',
   };
 
@@ -75,10 +78,10 @@ read_opts(int argc, char **argv)
         options.input_sep = '\0';
         break;
       case 'h':
-        options.hash = optarg;
+        options.hash_program = optarg;
         break;
       case 'L':
-        if (str_to_uint(optarg, &options.hash_max_lines))
+        if (str_to_uint(optarg, &options.max_per_invocation))
           goto fail;
         break;
       case 'r':
@@ -167,22 +170,52 @@ done:
 }
 
 static int
-run(const options_t *opts)
+run(const options_t *opts, filehash_t *fh)
 {
+  int ret = 0;
   void *aux = NULL;
-  const char *file;
+  const char *file_name;
 
-  while (file = iter_files(opts, &aux), file)
-    warnx("[%s]", file);
+  while (file_name = iter_files(opts, &aux), file_name) {
 
-  return 0;
+    switch (filehash_send(fh, file_name)) {
+      case fhs_accepts:
+        continue;
+
+      case fhs_failure:
+        warnx("handle failure!");
+        ret = 1;
+        goto exit;
+
+      case fhs_full:
+        warnx("handle full!");
+        filehash_free(fh);
+        fh = filehash_new(opts->hash_program, opts->max_per_invocation);
+        break;
+
+      case fhs_rejected:
+        bug_abort;
+
+    }
+
+  }
+
+exit:
+  filehash_free(fh);
+  return ret;
 }
 
 int
 main(int argc, char **argv)
 {
   options_t opts;
+  filehash_t *fh;
 
   opts = read_opts(argc, argv);
-  return run(&opts);
+
+  fh = filehash_new(opts.hash_program, opts.max_per_invocation);
+  if (!fh)
+    err(1, "filehash_new");
+
+  return run(&opts, fh);
 }