]> thyrsus.com Git - comparator.git/commitdiff
Initial revision
authorEric S. Raymond <esr@thyrsus.com>
Tue, 2 Sep 2003 19:21:31 +0000 (19:21 +0000)
committerEric S. Raymond <esr@thyrsus.com>
Tue, 2 Sep 2003 19:21:31 +0000 (19:21 +0000)
main.c [new file with mode: 0644]

diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..187cd62
--- /dev/null
+++ b/main.c
@@ -0,0 +1,194 @@
+/* main.c -- main sequence of comparator */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include "shred.h"
+
+static int chunk_count, sort_count;
+static struct hash_t *chunk_buffer;
+static struct sorthash_t *sort_buffer;
+
+/* 
+ * We differentiate these two functions in order to avaid the memory
+ * overhead of the extra (char *) when assembling shred lists to be written
+ * to a file.  This is only worth bothering with because the data sets
+ * can get quite large.
+ */
+
+static void filehook(struct hash_t hash, const char *file)
+/* hook to store only hashes */
+{
+    chunk_buffer = (struct hash_t *)realloc(chunk_buffer, 
+                                     sizeof(struct hash_t) * (chunk_count+1));
+    
+    chunk_buffer[chunk_count++] = hash;
+}
+
+
+static void corehook(struct hash_t hash, const char *file)
+/* hook to store hash and file */
+{
+    sort_buffer = (struct sorthash_t *)realloc(sort_buffer, 
+                                     sizeof(struct sorthash_t) * (sort_count+1));
+    
+    sort_buffer[sort_count].hash = hash;
+    sort_buffer[sort_count].file = (char *)file;
+    sort_count++;
+}
+
+static void generate_shredfile(const char *tree, FILE *ofp)
+/* generate shred file for given tree */
+{
+    char       **place, **list;
+    int                file_count;
+    u_int32_t  netfile_count;
+
+    list = sorted_file_list(tree, &file_count);
+
+    fputs("#SHIF-A 1.0\n", ofp);
+    fputs("Generator-Program: shredtree 1.0\n", ofp);
+    fputs("Hash-Method: MD5\n", ofp);
+    fprintf(ofp, "Normalization: %s\n", rws ? "remove_whitespace" : "none");
+    fprintf(ofp, "Shred-Size: %d\n", shredsize);
+    fputs("%%\n", ofp);
+
+    netfile_count = htonl(file_count);
+    fwrite(&netfile_count, sizeof(u_int32_t), 1, ofp);
+    for (place = list; place < list + file_count; place++)
+    {
+       linenum_t       net_chunks;
+
+       /* shredfile adds data to chunk_buffer */
+       chunk_buffer = (struct hash_t *)calloc(sizeof(struct hash_t), 1);
+       chunk_count = 0;
+       shredfile(*place, filehook);
+
+       /* the actual output */
+       fputs(*place, ofp);
+       fputc('\n', ofp);
+       net_chunks = TONET(chunk_count);
+       fwrite((char *)&net_chunks, sizeof(linenum_t), 1, ofp);
+       fwrite(chunk_buffer, sizeof(struct hash_t), chunk_count, ofp);
+       free(chunk_buffer);
+    }
+}
+
+static struct sorthash_t *generate_shredlist(const int argc, 
+                                            const char *argv[])
+/* generate an in-core list of sorthash structures */
+{
+    int        i, file_count;
+
+    sort_buffer = (struct sorthash_t*)calloc(sizeof(struct sorthash_t),1);
+    sort_count = 0;
+
+    for (i = 0; i < argc; i++)
+    {
+       char    **place, **list;
+
+       list = sorted_file_list(argv[i], &file_count);
+       for (place = list; place < list + file_count; place++)
+           shredfile(*place, corehook);
+       free(list);
+    }
+
+    /* caller is responsible for freeing this */
+    return(sort_buffer);
+}
+
+void report_time(char *legend, ...)
+{
+    static time_t mark_time;
+    time_t endtime = time(NULL);
+    va_list    ap;
+
+    if (mark_time)
+    {
+       int elapsed = endtime - mark_time;
+       int hours = elapsed/3600; elapsed %= 3600;
+       int minutes = elapsed/60; elapsed %= 60;
+       int seconds = elapsed;
+       char    buf[BUFSIZ];
+
+       va_start(ap, legend);
+       vsprintf(buf, legend, ap);
+       fprintf(stderr, "%% %s: %dh %dm %ds\n", buf, hours, minutes, seconds);
+    }
+    mark_time = endtime;
+}
+
+static void shredreport(int argc, char *argv[])
+/* merge hashes from several files and generate a report to standard output */
+{
+    extern char        *optarg;        /* set by getopt */
+    extern int optind;         /* set by getopt */
+    int        hashcount;
+    struct sorthash_t *obarray;
+
+    report_time(NULL);
+    obarray = merge_hashes(argc, argv, &hashcount);
+    report_time("Hash merge done, %d entries", hashcount);
+    sort_hashes(obarray, hashcount);
+    report_time("Sort done");
+    emit_report(obarray, hashcount);
+}
+
+main(int argc, char *argv[])
+{
+    extern char        *optarg;        /* set by getopt */
+    extern int optind;         /* set by getopt */
+
+    int status, file_only;
+
+    file_only = 0;
+    while ((status = getopt(argc, argv, "cd:fhs:w")) != EOF)
+    {
+       switch (status)
+       {
+       case 'c':
+           c_only = 1;
+           break;
+
+       case 'f':
+           file_only = 1;
+           break;
+
+       case 'd':
+           chdir(optarg);
+           break;
+
+       case 's':
+           shredsize = atoi(optarg);
+           break;
+
+       case 'w':
+           rws = 1;
+           break;
+
+       case 'x':
+           debug = 1;
+           break;
+
+       case 'h':
+       default:
+           fprintf(stderr,"usage: shredtree [-c] [-d dir ] [-s shredsize] [-w] [-x] path\n");
+           fprintf(stderr,"  -c      = check .c, .h, and .txt files only.\n");
+           fprintf(stderr,"  -d dir  = change directory before digesting.\n");
+           fprintf(stderr,"  -h      = help (display this message).\n");
+           fprintf(stderr,"  -s size = set shred size (default %d)\n",
+                   shredsize);
+           fprintf(stderr,"  -w      = remove whitespace.\n");
+           fprintf(stderr,"  -x      = debug, display chunks in output.\n");
+           exit(0);
+       }
+    }
+
+    if (file_only)
+       generate_shredfile(argv[optind], stdout);
+    else
+       shredreport(argc - optind, argv + optind);
+    exit(0);
+}
+
+/* main.c ends here */