Make zck a proper utility with arguments and help. Still needs some work
authorJonathan Dieter <jdieter@gmail.com>
Thu, 3 May 2018 19:52:11 +0000 (22:52 +0300)
committerJonathan Dieter <jdieter@gmail.com>
Thu, 3 May 2018 19:52:11 +0000 (22:52 +0300)
on splitting strings.

Signed-off-by: Jonathan Dieter <jdieter@gmail.com>
src/zck.c

index 3d2a7f0652ac0be47a8059ac63c281f14c85e6de..19fed1721a1c6621a2f2654b543da71f9fd2ac3e 100644 (file)
--- a/src/zck.c
+++ b/src/zck.c
 #include <fcntl.h>
 #include <unistd.h>
 #include <zck.h>
+#include <argp.h>
 
 #include "buzhash/buzhash.h"
 #include "memmem.h"
 
+static char doc[] = "zck - Create a new zchunk file";
+
+static char args_doc[] = "<file>";
+
+void version() {
+    printf(ZCK_NAME " " ZCK_VERSION "\nCopyright (c) 2018 Jonathan Dieter\n");
+    exit(0);
+}
+
+static struct argp_option options[] = {
+    {"verbose", 'v', 0,        0,
+     "Increase verbosity (can be specified more than once for debugging)"},
+    {"quiet",   'q', 0,        0, "Only show errors"},
+    {"split",   's', "STRING", 0, "Split chunks at beginning of STRING"},
+    {"dict",    'D', "FILE",   0, "Set zstd compression dictionary to FILE"},
+    {"version", 'V', 0,        0, "Show program version"},
+    { 0 }
+};
+
+struct arguments {
+  char *args[1];
+  zck_log_type log_level;
+  char *split_string;
+  char *dict;
+};
+
+static error_t parse_opt (int key, char *arg, struct argp_state *state) {
+    struct arguments *arguments = state->input;
+
+    switch (key) {
+        case 'v':
+            arguments->log_level -= 1;
+            if(arguments->log_level < ZCK_LOG_DEBUG)
+                arguments->log_level = ZCK_LOG_DEBUG;
+            break;
+        case 'q':
+            arguments->log_level = ZCK_LOG_ERROR;
+            break;
+        case 's':
+            arguments->split_string = arg;
+            break;
+        case 'D':
+            arguments->dict = arg;
+            break;
+        case 'V':
+            version();
+            break;
+
+        case ARGP_KEY_ARG:
+            if (state->arg_num >= 1) {
+                argp_usage (state);
+                return EINVAL;
+            }
+            arguments->args[state->arg_num] = arg;
+
+            break;
+
+        case ARGP_KEY_END:
+            if (state->arg_num < 1) {
+                argp_usage (state);
+                return EINVAL;
+            }
+            break;
+
+        default:
+            return ARGP_ERR_UNKNOWN;
+    }
+    return 0;
+}
+
+static struct argp argp = {options, parse_opt, args_doc, doc};
+
 int main (int argc, char *argv[]) {
+    struct arguments arguments = {0};
+
+    /* Defaults */
+    arguments.log_level = ZCK_LOG_WARNING;
+
+    argp_parse (&argp, argc, argv, 0, 0, &arguments);
+
+    zck_set_log_level(arguments.log_level);
+
     char *out_name;
+    out_name = malloc(strlen(arguments.args[0]) + 5);
+    snprintf(out_name, strlen(arguments.args[0]) + 5, "%s.zck",
+             arguments.args[0]);
+
+    /* Set dictionary if available */
     char *dict = NULL;
     size_t dict_size = 0;
-
-    zck_set_log_level(ZCK_LOG_DEBUG);
-
-    if(argc < 3 || argc > 4) {
-        printf("Usage: %s <file> <split string> [optional dictionary]\n", argv[0]);
-        exit(1);
-    }
-    out_name = malloc(strlen(argv[1]) + 5);
-    snprintf(out_name, strlen(argv[1]) + 5, "%s.zck", argv[1]);
-    if(argc == 4) {
-        int dict_fd = open(argv[3], O_RDONLY);
+    if(arguments.dict != NULL) {
+        int dict_fd = open(arguments.dict, O_RDONLY);
         if(dict_fd < 0) {
-            printf("Unable to open dictionary %s for reading", argv[3]);
+            printf("Unable to open dictionary %s for reading", arguments.dict);
             perror("");
             exit(1);
         }
@@ -75,7 +153,7 @@ int main (int argc, char *argv[]) {
         close(dict_fd);
     }
 
-    int dst_fd = open(out_name, O_EXCL | O_WRONLY | O_CREAT, 0644);
+    int dst_fd = open(out_name, O_TRUNC | O_WRONLY | O_CREAT, 0644);
     if(dst_fd < 0) {
         printf("Unable to open %s", out_name);
         perror("");
@@ -107,8 +185,8 @@ int main (int argc, char *argv[]) {
     free(dict);
 
     char *data;
-    int in_fd = open(argv[1], O_RDONLY);
-    int in_size = 0;
+    int in_fd = open(arguments.args[0], O_RDONLY);
+    off_t in_size = 0;
     if(in_fd < 0) {
         printf("Unable to open %s for reading", argv[1]);
         perror("");
@@ -131,8 +209,7 @@ int main (int argc, char *argv[]) {
         }
         close(in_fd);
 
-        /* Chunk based on string in argv[2] (Currently with ugly hack to group srpms together) */
-        if(False) {
+        if(arguments.split_string) {
             char *found = data;
             char *search = found;
             char *prev_srpm = memmem(search, in_size - (search-data), "<rpm:sourcerpm", 14);
@@ -189,6 +266,10 @@ int main (int argc, char *argv[]) {
             char *start = data;
             char *window_loc;
 
+            if(arguments.log_level <= ZCK_LOG_INFO) {
+                printf("Using buzhash algorithm for automatic chunking\n");
+                printf("Window size: %lu\n", buzhash_width);
+            }
             while(cur_loc < data + in_size) {
                 uint32_t bh = 0;
                 window_loc = cur_loc;
@@ -197,14 +278,15 @@ int main (int argc, char *argv[]) {
                     cur_loc += buzhash_width;
                     while(cur_loc < data + in_size) {
                         bh = buzhash_update(cur_loc, bh);
-                        if(((bh) & (8192 - 1)) == 0)
+                        if(((bh) & (buzhash_width - 1)) == 0)
                             break;
                         cur_loc++;
                     }
                 } else {
                     cur_loc = data + in_size;
                 }
-                printf("Completing %li bytes\n", (long)(cur_loc-start));
+                if(arguments.log_level <= ZCK_LOG_DEBUG)
+                    printf("Completing %li bytes\n", (long)(cur_loc-start));
                 if(zck_write(zck, start, cur_loc-start) < 0)
                     exit(1);
                 if(zck_end_chunk(zck) < 0)
@@ -216,6 +298,13 @@ int main (int argc, char *argv[]) {
     }
     if(!zck_close(zck))
         exit(1);
+    if(arguments.log_level <= ZCK_LOG_INFO) {
+        zckIndex *idx = zck_get_index(zck);
+        printf("Wrote %lu bytes in %lu chunks\n",
+               zck_get_data_length(zck) + zck_get_header_length(zck),
+               idx->count);
+    }
+
     zck_free(&zck);
     close(dst_fd);
 }