+static void
+dump_strings (const char *encoding, struct string_array *strings)
+{
+ string_array_sort (strings);
+ string_array_uniq (strings);
+
+ if (raw)
+ {
+ if (exclude_ascii_only || include_utf8_only)
+ {
+ size_t i = 0;
+ for (size_t j = 0; j < strings->n; j++)
+ {
+ char *s = strings->strings[j];
+ bool is_ascii = is_all_ascii (s);
+ bool is_utf8 = !u8_check (CHAR_CAST (uint8_t *, s), strlen (s));
+ if (!is_ascii && (!include_utf8_only || is_utf8))
+ strings->strings[i++] = s;
+ else
+ free (s);
+ }
+ strings->n = i;
+ }
+ for (size_t i = 0; i < strings->n; i++)
+ puts (strings->strings[i]);
+ }
+ else
+ {
+ size_t n_nonascii = 0;
+ size_t n_utf8 = 0;
+ for (size_t i = 0; i < strings->n; i++)
+ {
+ const char *s = strings->strings[i];
+ if (!is_all_ascii (s))
+ {
+ n_nonascii++;
+ if (!u8_check (CHAR_CAST (uint8_t *, s), strlen (s)))
+ n_utf8++;
+ }
+ }
+ printf ("%s: %zu unique strings, %zu non-ASCII, %zu UTF-8.\n",
+ encoding, strings->n, n_nonascii, n_utf8);
+ }
+}
+
+struct encoded_strings
+ {
+ char *encoding;
+ struct string_array strings;
+ };
+
+struct encoded_strings_table
+ {
+ struct encoded_strings *es;
+ size_t n, allocated;
+ };
+
+static void
+collect_strings (const struct output_item *item,
+ struct encoded_strings_table *t)
+{
+ char *error;
+ struct spvlb_table *table;
+ error = spv_read_light_table (item->spv_info->zip_reader,
+ item->spv_info->bin_member, &table);
+ if (error)
+ {
+ msg (ME, "%s", error);
+ free (error);
+ return;
+ }
+
+ const char *table_encoding = spvlb_table_get_encoding (table);
+ size_t j = 0;
+ for (j = 0; j < t->n; j++)
+ if (!strcmp (t->es[j].encoding, table_encoding))
+ break;
+ if (j >= t->n)
+ {
+ if (t->n >= t->allocated)
+ t->es = x2nrealloc (t->es, &t->allocated, sizeof *t->es);
+ t->es[t->n++] = (struct encoded_strings) {
+ .encoding = xstrdup (table_encoding),
+ .strings = STRING_ARRAY_INITIALIZER,
+ };
+ }
+ collect_spvlb_strings (table, &t->es[j].strings);
+}
+
+static void
+run_strings (int argc UNUSED, char **argv)
+{
+ struct output_item *root = read_and_filter_spv (argv[1], NULL);
+
+ struct encoded_strings_table t = { .es = NULL };
+ struct output_iterator iter;
+ OUTPUT_ITEM_FOR_EACH (&iter, root)
+ {
+ const struct output_item *item = iter.cur;
+ if (item->type == OUTPUT_ITEM_TABLE
+ && !item->spv_info->xml_member
+ && item->spv_info->bin_member)
+ collect_strings (item, &t);
+ }
+
+ for (size_t i = 0; i < t.n; i++)
+ {
+ dump_strings (t.es[i].encoding, &t.es[i].strings);
+ free (t.es[i].encoding);
+ string_array_destroy (&t.es[i].strings);
+ }
+ free (t.es);
+
+ output_item_unref (root);