- pattern_entry_t *entry;
- pattern_entry_t **pattern_arr;
- pattern_dumper_t *dump;
- int i, count = pset_count(status->pattern_hash);
-
- printf("\n%d pattern detected\n", count);
-
- if (count <= 0)
- return;
-
- /* creates a dumper */
- dump = new_vcg_dumper("pattern.vcg", 100);
-
- pattern_arr = xmalloc(sizeof(*pattern_arr) * count);
- for (i = 0, entry = pset_first(status->pattern_hash);
- entry && i < count;
- entry = pset_next(status->pattern_hash), ++i) {
- pattern_arr[i] = entry;
- }
- assert(count == i);
- count = i;
-
- /* sort it */
- qsort(pattern_arr, count, sizeof(*pattern_arr), pattern_count_cmp);
-
- for (i = 0; i < count; ++i) {
- entry = pattern_arr[i];
- if (entry->count.cnt[0] < status->bound)
- continue;
-
- /* dump a pattern */
- pattern_dump_new_pattern(dump, &entry->count);
- decode_node(entry->buf, entry->len, dump);
- pattern_dump_finish_pattern(dump);
- }
-
- /* destroy it */
- pattern_end(dump);
-}
+ FILE *f;
+ size_t count = pset_count(status->pattern_hash);
+
+ if (count <= 0)
+ return;
+
+ f = fopen(fname, "wb");
+ if (! f) {
+ perror(fname);
+ return;
+ } /* if */
+
+ fwrite("FPS1", 4, 1, f);
+ fwrite(&count, sizeof(count), 1, f);
+
+ foreach_pset(status->pattern_hash, pattern_entry_t, entry) {
+ fwrite(entry, offsetof(pattern_entry_t, buf) + entry->len, 1, f);
+ } /* for */
+ fclose(f);
+} /* store_pattern */
+
+/**
+ * Read collected patterns from a file.
+ *
+ * @param fname filename
+ */
+static HASH_MAP(pattern_entry_t) *read_pattern(const char *fname)
+{
+ FILE *f;
+ pattern_entry_t *entry, tmp;
+ size_t i, count;
+ unsigned j;
+ char magic[4];
+ HASH_MAP(pattern_entry_t) *pattern_hash = new_pset(pattern_cmp, 8);
+ BYTE buffer[PATTERN_STORE_SIZE];
+ CODE_BUFFER buf;
+ int res;
+
+ f = fopen(fname, "rb");
+ if (! f) {
+ perror(fname);
+ return NULL;
+ } /* if */
+
+ res = fread(magic, 4, 1, f);
+ if (res != 1)
+ goto read_error;
+ count = 0;
+ res = fread(&count, sizeof(count), 1, f);
+ if (res != 1 || memcmp(magic, "FPS1", 4) != 0 || count <= 0)
+ goto read_error;
+
+ /* read all pattern entries and put them into the hash table. */
+ for (i = 0; i < count; ++i) {
+ init_buf(&buf, buffer, sizeof(buffer));
+ res = fread(&tmp, offsetof(pattern_entry_t, buf), 1, f);
+ if (res != 1)
+ goto read_error;
+ for (j = 0; j < tmp.len; ++j)
+ put_byte(&buf, fgetc(f));
+ entry = pattern_get_entry(&buf, pattern_hash);
+ entry->count = tmp.count;
+ } /* for */
+ fclose(f);
+
+ lc_printf("Read %zu pattern from %s\n", count, fname);
+ assert(pset_count(pattern_hash) == count);
+
+ return pattern_hash;
+
+read_error:
+ fprintf(stderr, "Error: %s is not a Firm pattern store. Ignored.\n", fname);
+ fclose(f);
+ return NULL;
+} /* read_pattern */
+
+/**
+ * Write the collected patterns to a VCG file for inspection.
+ *
+ * @param fname name of the VCG file to create
+ */
+static void pattern_output(const char *fname)
+{
+ pattern_entry_t **pattern_arr;
+ pattern_dumper_t *dump;
+ size_t i, count = pset_count(status->pattern_hash);
+
+ lc_printf("\n%zu pattern detected\n", count);
+
+ if (count == 0)
+ return;
+
+ /* creates a dumper */
+ dump = new_vcg_dumper(fname, 100);
+
+ pattern_arr = XMALLOCN(pattern_entry_t*, count);
+ i = 0;
+ foreach_pset(status->pattern_hash, pattern_entry_t, entry) {
+ pattern_arr[i++] = entry;
+ } /* for */
+ assert(count == i);
+ count = i;
+
+ /* sort it */
+ qsort(pattern_arr, count, sizeof(*pattern_arr), pattern_count_cmp);
+
+ for (i = 0; i < count; ++i) {
+ pattern_entry_t *const entry = pattern_arr[i];
+ if (cnt_to_uint(&entry->count) < status->bound)
+ continue;
+
+ /* dump a pattern */
+ pattern_dump_new_pattern(dump, &entry->count);
+ decode_node(entry->buf, entry->len, dump);
+ pattern_dump_finish_pattern(dump);
+ } /* for */
+
+ /* destroy it */
+ pattern_end(dump);
+} /* pattern_output */