X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=utilities%2Fpspp-output.c;h=8e80faad511af37fcac25ed366526fb36d48c8ef;hb=refs%2Fheads%2Fctables7;hp=b3b4b57fa0fe42d2f9c88cebd462d8773a8bc85b;hpb=24e84c14af8ac6dc897344104e756c8820f9a031;p=pspp diff --git a/utilities/pspp-output.c b/utilities/pspp-output.c index b3b4b57fa0..8e80faad51 100644 --- a/utilities/pspp-output.c +++ b/utilities/pspp-output.c @@ -16,29 +16,31 @@ #include +#include #include #include #include #include +#include #include "data/file-handle-def.h" #include "data/settings.h" +#include "libpspp/encoding-guesser.h" #include "libpspp/i18n.h" #include "libpspp/message.h" #include "libpspp/string-map.h" #include "libpspp/string-set.h" +#include "libpspp/zip-reader.h" #include "output/driver.h" -#include "output/group-item.h" -#include "output/page-setup-item.h" +#include "output/output-item.h" #include "output/pivot-table.h" +#include "output/page-setup.h" +#include "output/select.h" #include "output/spv/light-binary-parser.h" #include "output/spv/spv-legacy-data.h" -#include "output/spv/spv-output.h" -#include "output/spv/spv-select.h" +#include "output/spv/spv-light-decoder.h" #include "output/spv/spv-table-look.h" #include "output/spv/spv.h" -#include "output/table-item.h" -#include "output/text-item.h" #include "gl/c-ctype.h" #include "gl/error.h" @@ -57,11 +59,11 @@ static struct string_map output_options = STRING_MAP_INITIALIZER (output_options); -/* --member-name: Include .zip member name in "dir" output. */ +/* --member-names: Include .zip member name in "dir" output. */ static bool show_member_names; /* --show-hidden, --select, --commands, ...: Selection criteria. */ -static struct spv_criteria *criteria; +static struct output_criteria *criteria; static size_t n_criteria, allocated_criteria; /* --or: Add new element to 'criteria' array. */ @@ -70,9 +72,17 @@ static bool new_criteria; /* --sort: Sort members under dump-light-table, to make comparisons easier. */ static bool sort; -/* --raw: Dump raw binary data in dump-light-table. */ +/* --raw: Dump raw binary data in "dump-light-table"; dump all strings in + "strings". */ static bool raw; +/* --no-ascii-only: Drop all-ASCII strings in "strings". */ +static bool exclude_ascii_only; + +/* --utf8-only: Only print strings that have UTF-8 multibyte sequences in + * "strings". */ +static bool include_utf8_only; + /* -f, --force: Keep output file even on error. */ static bool force; @@ -83,95 +93,88 @@ static struct pivot_table_look *table_look; static size_t n_warnings; static void usage (void); +static void developer_usage (void); static void parse_options (int argc, char **argv); -static void -dump_item (const struct spv_item *item) +static struct output_item * +annotate_member_names (const struct output_item *in) { - if (show_member_names && (item->xml_member || item->bin_member)) + if (in->type == OUTPUT_ITEM_GROUP) { - const char *x = item->xml_member; - const char *b = item->bin_member; - char *s = (x && b - ? xasprintf (_("%s and %s:"), x, b) - : xasprintf ("%s:", x ? x : b)); - text_item_submit (text_item_create_nocopy (TEXT_ITEM_TITLE, s)); - } - - switch (spv_item_get_type (item)) - { - case SPV_ITEM_HEADING: - break; - - case SPV_ITEM_TEXT: - spv_text_submit (item); - break; - - case SPV_ITEM_TABLE: - pivot_table_submit (pivot_table_ref (spv_item_get_table (item))); - break; - - case SPV_ITEM_GRAPH: - break; - - case SPV_ITEM_MODEL: - break; - - case SPV_ITEM_OBJECT: - break; - - case SPV_ITEM_TREE: - break; + struct output_item *out = group_item_clone_empty (in); + for (size_t i = 0; i < in->group.n_children; i++) + { + const struct output_item *item = in->group.children[i]; + const char *members[4]; + size_t n = spv_info_get_members (item->spv_info, members, + sizeof members / sizeof *members); + if (n) + { + struct string s = DS_EMPTY_INITIALIZER; + ds_put_cstr (&s, members[0]); + for (size_t i = 1; i < n; i++) + ds_put_format (&s, " and %s", members[i]); + group_item_add_child (out, text_item_create_nocopy ( + TEXT_ITEM_TITLE, ds_steal_cstr (&s), + xstrdup ("Member Names"))); + } - default: - abort (); + group_item_add_child (out, output_item_ref (item)); + } + return out; } + else + return output_item_ref (in); } static void -print_item_directory (const struct spv_item *item) +print_item_directory (const struct output_item *item, int level) { - for (int i = 1; i < spv_item_get_level (item); i++) + for (int i = 0; i < level; i++) printf (" "); - enum spv_item_type type = spv_item_get_type (item); - printf ("- %s", spv_item_type_to_string (type)); + printf ("- %s", output_item_type_to_string (item->type)); - const char *label = spv_item_get_label (item); + const char *label = output_item_get_label (item); if (label) printf (" \"%s\"", label); - if (type == SPV_ITEM_TABLE) + if (item->type == OUTPUT_ITEM_TABLE) { - const struct pivot_table *table = spv_item_get_table (item); - char *title = pivot_value_to_string (table->title, - SETTINGS_VALUE_SHOW_DEFAULT, - SETTINGS_VALUE_SHOW_DEFAULT); + char *title = pivot_value_to_string (item->table->title, item->table); if (!label || strcmp (title, label)) printf (" title \"%s\"", title); free (title); } - const char *command_id = spv_item_get_command_id (item); - if (command_id) - printf (" command \"%s\"", command_id); + if (item->command_name) + printf (" command \"%s\"", item->command_name); - const char *subtype = spv_item_get_subtype (item); - if (subtype && (!label || strcmp (label, subtype))) - printf (" subtype \"%s\"", subtype); + char *subtype = output_item_get_subtype (item); + if (subtype) + { + if (!label || strcmp (label, subtype)) + printf (" subtype \"%s\"", subtype); + free (subtype); + } + + if (!item->show) + printf (" (%s)", item->type == OUTPUT_ITEM_GROUP ? "collapsed" : "hidden"); - if (!spv_item_is_visible (item)) - printf (" (hidden)"); - if (show_member_names && (item->xml_member || item->bin_member)) + if (show_member_names) { - if (item->xml_member && item->bin_member) - printf (" in %s and %s", item->xml_member, item->bin_member); - else if (item->xml_member) - printf (" in %s", item->xml_member); - else if (item->bin_member) - printf (" in %s", item->bin_member); + const char *members[4]; + size_t n = spv_info_get_members (item->spv_info, members, + sizeof members / sizeof *members); + + for (size_t i = 0; i < n; i++) + printf (" %s %s", i == 0 ? "in" : "and", members[i]); } putchar ('\n'); + + if (item->type == OUTPUT_ITEM_GROUP) + for (size_t i = 0; i < item->group.n_children; i++) + print_item_directory (item->group.children[i], level + 1); } static void @@ -182,108 +185,49 @@ run_detect (int argc UNUSED, char **argv) error (1, 0, "%s", err); } -static void -run_directory (int argc UNUSED, char **argv) +static struct output_item * +read_and_filter_spv (const char *name, struct page_setup **psp) { - struct spv_reader *spv; - char *err = spv_open (argv[1], &spv); + struct output_item *root; + char *err = spv_read (name, &root, psp); if (err) error (1, 0, "%s", err); - - struct spv_item **items; - size_t n_items; - spv_select (spv, criteria, n_criteria, &items, &n_items); - for (size_t i = 0; i < n_items; i++) - print_item_directory (items[i]); - free (items); - - spv_close (spv); -} - -struct item_path - { - const struct spv_item **nodes; - size_t n; - -#define N_STUB 10 - const struct spv_item *stub[N_STUB]; - }; - -static void -swap_nodes (const struct spv_item **a, const struct spv_item **b) -{ - const struct spv_item *tmp = *a; - *a = *b; - *b = tmp; -} - -static void -get_path (const struct spv_item *item, struct item_path *path) -{ - size_t allocated = 10; - path->nodes = path->stub; - path->n = 0; - - while (item) - { - if (path->n >= allocated) - { - if (path->nodes == path->stub) - path->nodes = xmemdup (path->stub, sizeof path->stub); - path->nodes = x2nrealloc (path->nodes, &allocated, - sizeof *path->nodes); - } - path->nodes[path->n++] = item; - item = item->parent; - } - - for (size_t i = 0; i < path->n / 2; i++) - swap_nodes (&path->nodes[i], &path->nodes[path->n - i - 1]); + return output_select (root, criteria, n_criteria); } static void -free_path (struct item_path *path) +run_directory (int argc UNUSED, char **argv) { - if (path && path->nodes != path->stub) - free (path->nodes); + struct output_item *root = read_and_filter_spv (argv[1], NULL); + for (size_t i = 0; i < root->group.n_children; i++) + print_item_directory (root->group.children[i], 0); + output_item_unref (root); } static void -dump_heading_transition (const struct spv_item *old, - const struct spv_item *new) +set_table_look_recursively (struct output_item *item, + const struct pivot_table_look *look) { - if (old == new) - return; - - struct item_path old_path, new_path; - get_path (old, &old_path); - get_path (new, &new_path); - - size_t common = 0; - for (; common < old_path.n && common < new_path.n; common++) - if (old_path.nodes[common] != new_path.nodes[common]) - break; - - for (size_t i = common; i < old_path.n; i++) - group_close_item_submit (group_close_item_create ()); - for (size_t i = common; i < new_path.n; i++) - group_open_item_submit (group_open_item_create ( - new_path.nodes[i]->command_id)); - - free_path (&old_path); - free_path (&new_path); + if (item->type == OUTPUT_ITEM_TABLE) + pivot_table_set_look (item->table, look); + else if (item->type == OUTPUT_ITEM_GROUP) + for (size_t i = 0; i < item->group.n_children; i++) + set_table_look_recursively (item->group.children[i], look); } static void run_convert (int argc UNUSED, char **argv) { - struct spv_reader *spv; - char *err = spv_open (argv[1], &spv); - if (err) - error (1, 0, "%s", err); - + struct page_setup *ps; + struct output_item *root = read_and_filter_spv (argv[1], &ps); if (table_look) - spv_item_set_table_look (spv_get_root (spv), table_look); + set_table_look_recursively (root, table_look); + if (show_member_names) + { + struct output_item *new_root = annotate_member_names (root); + output_item_unref (root); + root = new_root; + } output_engine_push (); output_set_filename (argv[1]); @@ -293,26 +237,12 @@ run_convert (int argc UNUSED, char **argv) exit (EXIT_FAILURE); output_driver_register (driver); - const struct page_setup *ps = spv_get_page_setup (spv); if (ps) - page_setup_item_submit (page_setup_item_create (ps)); - - struct spv_item **items; - size_t n_items; - spv_select (spv, criteria, n_criteria, &items, &n_items); - struct spv_item *prev_heading = spv_get_root (spv); - for (size_t i = 0; i < n_items; i++) { - struct spv_item *heading - = items[i]->type == SPV_ITEM_HEADING ? items[i] : items[i]->parent; - dump_heading_transition (prev_heading, heading); - dump_item (items[i]); - prev_heading = heading; + output_set_page_setup (ps); + page_setup_destroy (ps); } - dump_heading_transition (prev_heading, spv_get_root (spv)); - free (items); - - spv_close (spv); + output_item_submit_children (root); output_engine_pop (); fh_done (); @@ -326,40 +256,45 @@ run_convert (int argc UNUSED, char **argv) } static const struct pivot_table * -get_first_table (const struct spv_reader *spv) +get_first_table (const struct output_item *item) { - struct spv_item **items; - size_t n_items; - spv_select (spv, criteria, n_criteria, &items, &n_items); - - for (size_t i = 0; i < n_items; i++) - if (spv_item_is_table (items[i])) + if (item->type == OUTPUT_ITEM_TABLE) + return item->table; + else if (item->type == OUTPUT_ITEM_GROUP) + for (size_t i = 0; i < item->group.n_children; i++) { - free (items); - return spv_item_get_table (items[i]); + const struct pivot_table *table + = get_first_table (item->group.children[i]); + if (table) + return table; } - free (items); return NULL; } static void run_get_table_look (int argc UNUSED, char **argv) { - struct spv_reader *spv; - char *err = spv_open (argv[1], &spv); - if (err) - error (1, 0, "%s", err); + struct pivot_table_look *look; + if (strcmp (argv[1], "-")) + { + struct output_item *root = read_and_filter_spv (argv[1], NULL); + const struct pivot_table *table = get_first_table (root); + if (!table) + error (1, 0, "%s: no tables found", argv[1]); + + look = pivot_table_look_ref (pivot_table_get_look (table)); - const struct pivot_table *table = get_first_table (spv); - if (!table) - error (1, 0, "%s: no tables found", argv[1]); + output_item_unref (root); + } + else + look = pivot_table_look_ref (pivot_table_look_builtin_default ()); - err = spv_table_look_write (argv[2], pivot_table_get_look (table)); + char *err = spv_table_look_write (argv[2], look); if (err) error (1, 0, "%s", err); - spv_close (spv); + pivot_table_look_unref (look); } static void @@ -374,30 +309,16 @@ run_convert_table_look (int argc UNUSED, char **argv) if (err) error (1, 0, "%s", err); - pivot_table_look_uninit (look); + pivot_table_look_unref (look); free (look); } static void run_dump (int argc UNUSED, char **argv) { - struct spv_reader *spv; - char *err = spv_open (argv[1], &spv); - if (err) - error (1, 0, "%s", err); - - struct spv_item **items; - size_t n_items; - spv_select (spv, criteria, n_criteria, &items, &n_items); - for (size_t i = 0; i < n_items; i++) - if (items[i]->type == SPV_ITEM_TABLE) - { - pivot_table_dump (spv_item_get_table (items[i]), 0); - putchar ('\n'); - } - free (items); - - spv_close (spv); + struct output_item *root = read_and_filter_spv (argv[1], NULL); + output_item_dump (root, 0); + output_item_unref (root); } static int @@ -422,114 +343,108 @@ compare_cells (const void *a_, const void *b_) return a < b ? -1 : a > b; } +static char * WARN_UNUSED_RESULT +dump_raw (struct zip_reader *zr, const char *member_name) +{ + void *data; + size_t size; + char *error = zip_member_read_all (zr, member_name, &data, &size); + if (!error) + { + fwrite (data, size, 1, stdout); + free (data); + } + return error; +} + +static void +dump_light_table (const struct output_item *item) +{ + char *error; + if (raw) + error = dump_raw (item->spv_info->zip_reader, + item->spv_info->bin_member); + else + { + struct spvlb_table *table; + error = spv_read_light_table (item->spv_info->zip_reader, + item->spv_info->bin_member, &table); + if (!error) + { + if (sort) + { + qsort (table->borders->borders, table->borders->n_borders, + sizeof *table->borders->borders, compare_borders); + qsort (table->cells->cells, table->cells->n_cells, + sizeof *table->cells->cells, compare_cells); + } + spvlb_print_table (item->spv_info->bin_member, 0, table); + spvlb_free_table (table); + } + } + if (error) + { + msg (ME, "%s", error); + free (error); + } +} + static void run_dump_light_table (int argc UNUSED, char **argv) { if (raw && isatty (STDOUT_FILENO)) error (1, 0, "not writing binary data to tty"); - struct spv_reader *spv; - char *err = spv_open (argv[1], &spv); - if (err) - error (1, 0, "%s", err); + struct output_item *root = read_and_filter_spv (argv[1], NULL); + struct output_iterator iter; + OUTPUT_ITEM_FOR_EACH (&iter, root) + if (iter.cur->type == OUTPUT_ITEM_TABLE && !iter.cur->spv_info->xml_member) + dump_light_table (iter.cur); + output_item_unref (root); +} - struct spv_item **items; - size_t n_items; - spv_select (spv, criteria, n_criteria, &items, &n_items); - for (size_t i = 0; i < n_items; i++) +static void +dump_legacy_data (const struct output_item *item) +{ + char *error; + if (raw) + error = dump_raw (item->spv_info->zip_reader, + item->spv_info->bin_member); + else { - if (!spv_item_is_light_table (items[i])) - continue; - - char *error; - if (raw) - { - void *data; - size_t size; - error = spv_item_get_raw_light_table (items[i], &data, &size); - if (!error) - { - fwrite (data, size, 1, stdout); - free (data); - } - } - else + struct spv_data data; + error = spv_read_legacy_data (item->spv_info->zip_reader, + item->spv_info->bin_member, &data); + if (!error) { - struct spvlb_table *table; - error = spv_item_get_light_table (items[i], &table); - if (!error) - { - if (sort) - { - qsort (table->borders->borders, table->borders->n_borders, - sizeof *table->borders->borders, compare_borders); - qsort (table->cells->cells, table->cells->n_cells, - sizeof *table->cells->cells, compare_cells); - } - spvlb_print_table (items[i]->bin_member, 0, table); - spvlb_free_table (table); - } - } - if (error) - { - msg (ME, "%s", error); - free (error); + printf ("%s:\n", item->spv_info->bin_member); + spv_data_dump (&data, stdout); + spv_data_uninit (&data); + printf ("\n"); } } - free (items); - - spv_close (spv); + if (error) + { + msg (ME, "%s", error); + free (error); + } } static void run_dump_legacy_data (int argc UNUSED, char **argv) { - struct spv_reader *spv; - char *err = spv_open (argv[1], &spv); - if (err) - error (1, 0, "%s", err); - - struct spv_item **items; - size_t n_items; - spv_select (spv, criteria, n_criteria, &items, &n_items); - for (size_t i = 0; i < n_items; i++) - if (spv_item_is_legacy_table (items[i])) - { - struct spv_data data; - char *error; - if (raw) - { - void *data; - size_t size; - error = spv_item_get_raw_legacy_data (items[i], &data, &size); - if (!error) - { - fwrite (data, size, 1, stdout); - free (data); - } - } - else - { - error = spv_item_get_legacy_data (items[i], &data); - if (!error) - { - printf ("%s:\n", items[i]->bin_member); - spv_data_dump (&data, stdout); - spv_data_uninit (&data); - printf ("\n"); - } - } - - if (error) - { - msg (ME, "%s", error); - free (error); - } - } - free (items); + if (raw && isatty (STDOUT_FILENO)) + error (1, 0, "not writing binary data to tty"); - spv_close (spv); + struct output_item *root = read_and_filter_spv (argv[1], NULL); + struct output_iterator iter; + OUTPUT_ITEM_FOR_EACH (&iter, root) + if (iter.cur->type == OUTPUT_ITEM_TABLE + && iter.cur->spv_info->xml_member + && iter.cur->spv_info->bin_member) + dump_legacy_data (iter.cur); + output_item_unref (root); } /* This is really bogus. @@ -625,7 +540,7 @@ dump_xml (int argc, char **argv, const char *member_name, xmlXPathFreeContext (xpath_ctx); } if (any_results) - putchar ('\n');; + putchar ('\n'); } xmlFreeDoc (doc); } @@ -638,79 +553,206 @@ dump_xml (int argc, char **argv, const char *member_name, } static void -run_dump_legacy_table (int argc, char **argv) +dump_legacy_table (int argc, char **argv, const struct output_item *item) { - struct spv_reader *spv; - char *err = spv_open (argv[1], &spv); - if (err) - error (1, 0, "%s", err); + xmlDoc *doc; + char *error_s = spv_read_xml_member (item->spv_info->zip_reader, + item->spv_info->xml_member, + false, "visualization", &doc); + dump_xml (argc, argv, item->spv_info->xml_member, error_s, doc); +} - struct spv_item **items; - size_t n_items; - spv_select (spv, criteria, n_criteria, &items, &n_items); - for (size_t i = 0; i < n_items; i++) - if (spv_item_is_legacy_table (items[i])) - { - xmlDoc *doc; - char *error_s = spv_item_get_legacy_table (items[i], &doc); - dump_xml (argc, argv, items[i]->xml_member, error_s, doc); - } - free (items); +static void +run_dump_legacy_table (int argc, char **argv) +{ + struct output_item *root = read_and_filter_spv (argv[1], NULL); + struct output_iterator iter; + OUTPUT_ITEM_FOR_EACH (&iter, root) + if (iter.cur->type == OUTPUT_ITEM_TABLE + && iter.cur->spv_info->xml_member) + dump_legacy_table (argc, argv, iter.cur); + output_item_unref (root); +} - spv_close (spv); +static void +dump_structure (int argc, char **argv, const struct output_item *item) +{ + xmlDoc *doc; + char *error_s = spv_read_xml_member (item->spv_info->zip_reader, + item->spv_info->structure_member, + true, "heading", &doc); + dump_xml (argc, argv, item->spv_info->structure_member, error_s, doc); } static void run_dump_structure (int argc, char **argv) { - struct spv_reader *spv; - char *err = spv_open (argv[1], &spv); - if (err) - error (1, 0, "%s", err); + struct output_item *root = read_and_filter_spv (argv[1], NULL); - struct spv_item **items; - size_t n_items; - spv_select (spv, criteria, n_criteria, &items, &n_items); const char *last_structure_member = NULL; - for (size_t i = 0; i < n_items; i++) - if (!last_structure_member || strcmp (items[i]->structure_member, - last_structure_member)) - { - last_structure_member = items[i]->structure_member; - - xmlDoc *doc; - char *error_s = spv_item_get_structure (items[i], &doc); - dump_xml (argc, argv, items[i]->structure_member, error_s, doc); - } - free (items); + struct output_iterator iter; + OUTPUT_ITEM_FOR_EACH (&iter, root) + { + const struct output_item *item = iter.cur; + if (item->spv_info->structure_member + && (!last_structure_member + || strcmp (item->spv_info->structure_member, + last_structure_member))) + { + last_structure_member = item->spv_info->structure_member; + dump_structure (argc, argv, item); + } + } + output_item_unref (root); +} - spv_close (spv); +static bool +is_any_legacy (const struct output_item *item) +{ + if (item->type == OUTPUT_ITEM_TABLE) + return item->spv_info->xml_member != NULL; + else if (item->type == OUTPUT_ITEM_GROUP) + for (size_t i = 0; i < item->group.n_children; i++) + if (is_any_legacy (item->group.children[i])) + return true; + + return false; } static void run_is_legacy (int argc UNUSED, char **argv) { - struct spv_reader *spv; - char *err = spv_open (argv[1], &spv); - if (err) - error (1, 0, "%s", err); + struct output_item *root = read_and_filter_spv (argv[1], NULL); + bool is_legacy = is_any_legacy (root); + output_item_unref (root); - bool is_legacy = false; + exit (is_legacy ? EXIT_SUCCESS : EXIT_FAILURE); +} - struct spv_item **items; - size_t n_items; - spv_select (spv, criteria, n_criteria, &items, &n_items); - for (size_t i = 0; i < n_items; i++) - if (spv_item_is_legacy_table (items[i])) - { - is_legacy = true; - break; - } - free (items); +static bool +is_all_ascii (const char *s) +{ + for (; *s; s++) + if (!encoding_guess_is_ascii_text (*s)) + return false; - spv_close (spv); + return true; +} - exit (is_legacy ? EXIT_SUCCESS : EXIT_FAILURE); +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); } struct command @@ -735,6 +777,7 @@ static const struct command commands[] = { "dump-legacy-table", 1, INT_MAX, run_dump_legacy_table }, { "dump-structure", 1, INT_MAX, run_dump_structure }, { "is-legacy", 1, 1, run_is_legacy }, + { "strings", 1, 1, run_strings }, }; static const int n_commands = sizeof commands / sizeof *commands; @@ -765,7 +808,7 @@ int main (int argc, char **argv) { set_program_name (argv[0]); - msg_set_handler (emit_msg, NULL); + msg_set_handler (&(struct msg_handler) { .output_msg = emit_msg }); settings_init (); i18n_init (); @@ -808,17 +851,13 @@ main (int argc, char **argv) c->run (argc, argv); - if (table_look) - { - pivot_table_look_uninit (table_look); - free (table_look); - } + pivot_table_look_unref (table_look); i18n_done (); return n_warnings ? EXIT_FAILURE : EXIT_SUCCESS; } -static struct spv_criteria * +static struct output_criteria * get_criteria (void) { if (!n_criteria || new_criteria) @@ -827,7 +866,8 @@ get_criteria (void) if (n_criteria >= allocated_criteria) criteria = x2nrealloc (criteria, &allocated_criteria, sizeof *criteria); - criteria[n_criteria++] = (struct spv_criteria) SPV_CRITERIA_INITIALIZER; + criteria[n_criteria++] + = (struct output_criteria) OUTPUT_CRITERIA_INITIALIZER; } return &criteria[n_criteria - 1]; @@ -843,32 +883,32 @@ parse_select (char *arg) for (char *token = strtok (arg, ","); token; token = strtok (NULL, ",")) { if (!strcmp (arg, "all")) - classes = SPV_ALL_CLASSES; + classes = OUTPUT_ALL_CLASSES; else if (!strcmp (arg, "help")) { puts (_("The following object classes are supported:")); - for (int class = 0; class < SPV_N_CLASSES; class++) - printf ("- %s\n", spv_item_class_to_string (class)); + for (int class = 0; class < OUTPUT_N_CLASSES; class++) + printf ("- %s\n", output_item_class_to_string (class)); exit (0); } else { - int class = spv_item_class_from_string (token); - if (class == SPV_N_CLASSES) - error (1, 0, _("%s: unknown object class (use --select=help " - "for help"), arg); + int class = output_item_class_from_string (token); + if (class == OUTPUT_N_CLASSES) + error (1, 0, _("unknown object class \"%s\" (use --select=help " + "for help)"), arg); classes |= 1u << class; } } - struct spv_criteria *c = get_criteria (); - c->classes = invert ? classes ^ SPV_ALL_CLASSES : classes; + struct output_criteria *c = get_criteria (); + c->classes = invert ? classes ^ OUTPUT_ALL_CLASSES : classes; } -static struct spv_criteria_match * +static struct output_criteria_match * get_criteria_match (const char **arg) { - struct spv_criteria *c = get_criteria (); + struct output_criteria *c = get_criteria (); if ((*arg)[0] == '^') { (*arg)++; @@ -881,28 +921,28 @@ get_criteria_match (const char **arg) static void parse_commands (const char *arg) { - struct spv_criteria_match *cm = get_criteria_match (&arg); + struct output_criteria_match *cm = get_criteria_match (&arg); string_array_parse (&cm->commands, ss_cstr (arg), ss_cstr (",")); } static void parse_subtypes (const char *arg) { - struct spv_criteria_match *cm = get_criteria_match (&arg); + struct output_criteria_match *cm = get_criteria_match (&arg); string_array_parse (&cm->subtypes, ss_cstr (arg), ss_cstr (",")); } static void parse_labels (const char *arg) { - struct spv_criteria_match *cm = get_criteria_match (&arg); + struct output_criteria_match *cm = get_criteria_match (&arg); string_array_parse (&cm->labels, ss_cstr (arg), ss_cstr (",")); } static void parse_instances (char *arg) { - struct spv_criteria *c = get_criteria (); + struct output_criteria *c = get_criteria (); size_t allocated_instances = c->n_instances; for (char *token = strtok (arg, ","); token; token = strtok (NULL, ",")) @@ -919,7 +959,7 @@ parse_instances (char *arg) static void parse_nth_commands (char *arg) { - struct spv_criteria *c = get_criteria (); + struct output_criteria *c = get_criteria (); size_t allocated_commands = c->n_commands; for (char *token = strtok (arg, ","); token; token = strtok (NULL, ",")) @@ -935,20 +975,16 @@ parse_nth_commands (char *arg) static void parse_members (const char *arg) { - struct spv_criteria *cm = get_criteria (); + struct output_criteria *cm = get_criteria (); string_array_parse (&cm->members, ss_cstr (arg), ss_cstr (",")); } static void parse_table_look (const char *arg) { - if (table_look) - { - pivot_table_look_uninit (table_look); - free (table_look); - } + pivot_table_look_unref (table_look); - char *error_s = spv_table_look_read (arg, &table_look); + char *error_s = pivot_table_look_read (arg, &table_look); if (error_s) error (1, 0, "%s", error_s); } @@ -973,7 +1009,10 @@ parse_options (int argc, char *argv[]) OPT_OR, OPT_SORT, OPT_RAW, + OPT_NO_ASCII_ONLY, + OPT_UTF8_ONLY, OPT_TABLE_LOOK, + OPT_HELP_DEVELOPER, }; static const struct option long_options[] = { @@ -1000,7 +1039,12 @@ parse_options (int argc, char *argv[]) { "sort", no_argument, NULL, OPT_SORT }, { "raw", no_argument, NULL, OPT_RAW }, + /* "strings" command options. */ + { "no-ascii-only", no_argument, NULL, OPT_NO_ASCII_ONLY }, + { "utf8-only", no_argument, NULL, OPT_UTF8_ONLY }, + { "help", no_argument, NULL, 'h' }, + { "help-developer", no_argument, NULL, OPT_HELP_DEVELOPER }, { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 }, @@ -1074,6 +1118,14 @@ parse_options (int argc, char *argv[]) parse_table_look (optarg); break; + case OPT_NO_ASCII_ONLY: + exclude_ascii_only = true; + break; + + case OPT_UTF8_ONLY: + include_utf8_only = true; + break; + case 'f': force = true; break; @@ -1087,6 +1139,10 @@ parse_options (int argc, char *argv[]) usage (); exit (EXIT_SUCCESS); + case OPT_HELP_DEVELOPER: + developer_usage (); + exit (EXIT_SUCCESS); + default: exit (EXIT_FAILURE); } @@ -1140,7 +1196,38 @@ The following options override \"convert\" behavior:\n\ --table-look=FILE override tables' style with TableLook from FILE\n\ Other options:\n\ --help display this help and exit\n\ + --help-developer display help for developer commands and exit\n\ --version output version information and exit\n", program_name, program_name, ds_cstr (&s)); ds_destroy (&s); } + +static void +developer_usage (void) +{ + printf ("\ +The following developer commands are available:\n\ + dump FILE Dump pivot table structure\n\ + [--raw | --sort] dump-light-table FILE Dump light tables\n\ + [--raw] dump-legacy-data FILE Dump legacy table data\n\ + dump-legacy-table FILE [XPATH]... Dump legacy table XML\n\ + dump-structure FILE [XPATH]... Dump structure XML\n\ + is-legacy FILE Exit with status 0 if any legacy table selected\n\ + strings FILE Dump analysis of strings\n\ +\n\ +Additional input selection options:\n\ + --members=MEMBER... include only objects with these Zip member names\n\ + --errors include only objects that cannot be loaded\n\ +\n\ +Additional options for \"dir\" command:\n\ + --member-names show Zip member names with objects\n\ +\n\ +Options for the \"strings\" command:\n\ + --raw Dump all (unique) strings\n\ + --raw --no-ascii-only Dump all strings that contain non-ASCII characters\n\ + --raw --utf8-only Dump all non-ASCII strings that are valid UTF-8\n\ +\n\ +Other options:\n\ + --raw print raw binary data instead of a parsed version\n\ + --sort sort borders and areas for shorter \"diff\" output\n"); +}