1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2017, 2018 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
26 #include "data/file-handle-def.h"
27 #include "data/settings.h"
28 #include "libpspp/encoding-guesser.h"
29 #include "libpspp/i18n.h"
30 #include "libpspp/message.h"
31 #include "libpspp/string-map.h"
32 #include "libpspp/string-set.h"
33 #include "output/driver.h"
34 #include "output/group-item.h"
35 #include "output/image-item.h"
36 #include "output/page-setup-item.h"
37 #include "output/pivot-table.h"
38 #include "output/spv/light-binary-parser.h"
39 #include "output/spv/spv-legacy-data.h"
40 #include "output/spv/spv-light-decoder.h"
41 #include "output/spv/spv-output.h"
42 #include "output/spv/spv-select.h"
43 #include "output/spv/spv-table-look.h"
44 #include "output/spv/spv.h"
45 #include "output/table-item.h"
46 #include "output/text-item.h"
48 #include "gl/c-ctype.h"
50 #include "gl/progname.h"
51 #include "gl/version-etc.h"
52 #include "gl/xalloc.h"
54 #include <libxml/tree.h>
55 #include <libxml/xpath.h>
56 #include <libxml/xpathInternals.h>
59 #define _(msgid) gettext (msgid)
61 /* -O key=value: Output driver options. */
62 static struct string_map output_options
63 = STRING_MAP_INITIALIZER (output_options);
65 /* --member-names: Include .zip member name in "dir" output. */
66 static bool show_member_names;
68 /* --show-hidden, --select, --commands, ...: Selection criteria. */
69 static struct spv_criteria *criteria;
70 static size_t n_criteria, allocated_criteria;
72 /* --or: Add new element to 'criteria' array. */
73 static bool new_criteria;
75 /* --sort: Sort members under dump-light-table, to make comparisons easier. */
78 /* --raw: Dump raw binary data in "dump-light-table"; dump all strings in
82 /* --no-ascii-only: Drop all-ASCII strings in "strings". */
83 static bool exclude_ascii_only;
85 /* --utf8-only: Only print strings that have UTF-8 multibyte sequences in
87 static bool include_utf8_only;
89 /* -f, --force: Keep output file even on error. */
92 /* --table-look: TableLook to replace table style for conversion. */
93 static struct pivot_table_look *table_look;
95 /* Number of warnings issued. */
96 static size_t n_warnings;
98 static void usage (void);
99 static void developer_usage (void);
100 static void parse_options (int argc, char **argv);
103 dump_item (const struct spv_item *item)
105 if (show_member_names && (item->xml_member || item->bin_member))
107 const char *x = item->xml_member;
108 const char *b = item->bin_member;
110 /* The strings below are not marked for translation because they are only
111 useful to developers. */
113 ? xasprintf ("%s and %s:", x, b)
114 : xasprintf ("%s:", x ? x : b));
115 text_item_submit (text_item_create_nocopy (TEXT_ITEM_TITLE, s,
116 xstrdup ("Member Names")));
119 switch (spv_item_get_type (item))
121 case SPV_ITEM_HEADING:
125 spv_text_submit (item);
129 pivot_table_submit (pivot_table_ref (spv_item_get_table (item)));
139 image_item_submit (image_item_create (cairo_surface_reference (
140 spv_item_get_image (item))));
152 print_item_directory (const struct spv_item *item)
154 for (int i = 1; i < spv_item_get_level (item); i++)
157 enum spv_item_type type = spv_item_get_type (item);
158 printf ("- %s", spv_item_type_to_string (type));
160 const char *label = spv_item_get_label (item);
162 printf (" \"%s\"", label);
164 if (type == SPV_ITEM_TABLE)
166 const struct pivot_table *table = spv_item_get_table (item);
167 char *title = pivot_value_to_string (table->title, table);
168 if (!label || strcmp (title, label))
169 printf (" title \"%s\"", title);
173 const char *command_id = spv_item_get_command_id (item);
175 printf (" command \"%s\"", command_id);
177 const char *subtype = spv_item_get_subtype (item);
178 if (subtype && (!label || strcmp (label, subtype)))
179 printf (" subtype \"%s\"", subtype);
181 if (!spv_item_is_visible (item))
182 printf (" (hidden)");
184 if (show_member_names)
186 const char *members[] = {
193 for (size_t i = 0; i < sizeof members / sizeof *members; i++)
195 printf (" %s %s", n++ == 0 ? "in" : "and", members[i]);
201 run_detect (int argc UNUSED, char **argv)
203 char *err = spv_detect (argv[1]);
205 error (1, 0, "%s", err);
209 run_directory (int argc UNUSED, char **argv)
211 struct spv_reader *spv;
212 char *err = spv_open (argv[1], &spv);
214 error (1, 0, "%s", err);
216 struct spv_item **items;
218 spv_select (spv, criteria, n_criteria, &items, &n_items);
219 for (size_t i = 0; i < n_items; i++)
220 print_item_directory (items[i]);
228 const struct spv_item **nodes;
232 const struct spv_item *stub[N_STUB];
236 swap_nodes (const struct spv_item **a, const struct spv_item **b)
238 const struct spv_item *tmp = *a;
244 get_path (const struct spv_item *item, struct item_path *path)
246 size_t allocated = 10;
247 path->nodes = path->stub;
252 if (path->n >= allocated)
254 if (path->nodes == path->stub)
255 path->nodes = xmemdup (path->stub, sizeof path->stub);
256 path->nodes = x2nrealloc (path->nodes, &allocated,
257 sizeof *path->nodes);
259 path->nodes[path->n++] = item;
263 for (size_t i = 0; i < path->n / 2; i++)
264 swap_nodes (&path->nodes[i], &path->nodes[path->n - i - 1]);
268 free_path (struct item_path *path)
270 if (path && path->nodes != path->stub)
275 dump_heading_transition (const struct spv_item *old,
276 const struct spv_item *new)
281 struct item_path old_path, new_path;
282 get_path (old, &old_path);
283 get_path (new, &new_path);
286 for (; common < old_path.n && common < new_path.n; common++)
287 if (old_path.nodes[common] != new_path.nodes[common])
290 for (size_t i = common; i < old_path.n; i++)
291 group_close_item_submit (group_close_item_create ());
292 for (size_t i = common; i < new_path.n; i++)
293 group_open_item_submit (group_open_item_create (
294 new_path.nodes[i]->command_id,
295 new_path.nodes[i]->label));
297 free_path (&old_path);
298 free_path (&new_path);
302 run_convert (int argc UNUSED, char **argv)
304 struct spv_reader *spv;
305 char *err = spv_open (argv[1], &spv);
307 error (1, 0, "%s", err);
310 spv_item_set_table_look (spv_get_root (spv), table_look);
312 output_engine_push ();
313 output_set_filename (argv[1]);
314 string_map_replace (&output_options, "output-file", argv[2]);
315 struct output_driver *driver = output_driver_create (&output_options);
318 output_driver_register (driver);
320 const struct page_setup *ps = spv_get_page_setup (spv);
322 page_setup_item_submit (page_setup_item_create (ps));
324 struct spv_item **items;
326 spv_select (spv, criteria, n_criteria, &items, &n_items);
327 struct spv_item *prev_heading = spv_get_root (spv);
328 for (size_t i = 0; i < n_items; i++)
330 struct spv_item *heading
331 = items[i]->type == SPV_ITEM_HEADING ? items[i] : items[i]->parent;
332 dump_heading_transition (prev_heading, heading);
333 dump_item (items[i]);
334 prev_heading = heading;
336 dump_heading_transition (prev_heading, spv_get_root (spv));
341 output_engine_pop ();
344 if (n_warnings && !force)
346 /* XXX There could be other files to unlink, e.g. the ascii driver can
347 produce additional files with the charts. */
352 static const struct pivot_table *
353 get_first_table (const struct spv_reader *spv)
355 struct spv_item **items;
357 spv_select (spv, criteria, n_criteria, &items, &n_items);
359 for (size_t i = 0; i < n_items; i++)
360 if (spv_item_is_table (items[i]))
363 return spv_item_get_table (items[i]);
371 run_get_table_look (int argc UNUSED, char **argv)
373 struct pivot_table_look *look;
374 if (strcmp (argv[1], "-"))
376 struct spv_reader *spv;
377 char *err = spv_open (argv[1], &spv);
379 error (1, 0, "%s", err);
381 const struct pivot_table *table = get_first_table (spv);
383 error (1, 0, "%s: no tables found", argv[1]);
385 look = pivot_table_look_ref (pivot_table_get_look (table));
390 look = pivot_table_look_ref (pivot_table_look_builtin_default ());
392 char *err = spv_table_look_write (argv[2], look);
394 error (1, 0, "%s", err);
396 pivot_table_look_unref (look);
400 run_convert_table_look (int argc UNUSED, char **argv)
402 struct pivot_table_look *look;
403 char *err = spv_table_look_read (argv[1], &look);
405 error (1, 0, "%s", err);
407 err = spv_table_look_write (argv[2], look);
409 error (1, 0, "%s", err);
411 pivot_table_look_unref (look);
416 run_dump (int argc UNUSED, char **argv)
418 struct spv_reader *spv;
419 char *err = spv_open (argv[1], &spv);
421 error (1, 0, "%s", err);
423 struct spv_item **items;
425 spv_select (spv, criteria, n_criteria, &items, &n_items);
426 for (size_t i = 0; i < n_items; i++)
427 if (items[i]->type == SPV_ITEM_TABLE)
429 pivot_table_dump (spv_item_get_table (items[i]), 0);
438 compare_borders (const void *a_, const void *b_)
440 const struct spvlb_border *const *ap = a_;
441 const struct spvlb_border *const *bp = b_;
442 uint32_t a = (*ap)->border_type;
443 uint32_t b = (*bp)->border_type;
445 return a < b ? -1 : a > b;
449 compare_cells (const void *a_, const void *b_)
451 const struct spvlb_cell *const *ap = a_;
452 const struct spvlb_cell *const *bp = b_;
453 uint64_t a = (*ap)->index;
454 uint64_t b = (*bp)->index;
456 return a < b ? -1 : a > b;
460 run_dump_light_table (int argc UNUSED, char **argv)
462 if (raw && isatty (STDOUT_FILENO))
463 error (1, 0, "not writing binary data to tty");
465 struct spv_reader *spv;
466 char *err = spv_open (argv[1], &spv);
468 error (1, 0, "%s", err);
470 struct spv_item **items;
472 spv_select (spv, criteria, n_criteria, &items, &n_items);
473 for (size_t i = 0; i < n_items; i++)
475 if (!spv_item_is_light_table (items[i]))
483 error = spv_item_get_raw_light_table (items[i], &data, &size);
486 fwrite (data, size, 1, stdout);
492 struct spvlb_table *table;
493 error = spv_item_get_light_table (items[i], &table);
498 qsort (table->borders->borders, table->borders->n_borders,
499 sizeof *table->borders->borders, compare_borders);
500 qsort (table->cells->cells, table->cells->n_cells,
501 sizeof *table->cells->cells, compare_cells);
503 spvlb_print_table (items[i]->bin_member, 0, table);
504 spvlb_free_table (table);
509 msg (ME, "%s", error);
520 run_dump_legacy_data (int argc UNUSED, char **argv)
522 struct spv_reader *spv;
523 char *err = spv_open (argv[1], &spv);
525 error (1, 0, "%s", err);
527 if (raw && isatty (STDOUT_FILENO))
528 error (1, 0, "not writing binary data to tty");
530 struct spv_item **items;
532 spv_select (spv, criteria, n_criteria, &items, &n_items);
533 for (size_t i = 0; i < n_items; i++)
534 if (spv_item_is_legacy_table (items[i]))
536 struct spv_data data;
542 error = spv_item_get_raw_legacy_data (items[i], &data, &size);
545 fwrite (data, size, 1, stdout);
551 error = spv_item_get_legacy_data (items[i], &data);
554 printf ("%s:\n", items[i]->bin_member);
555 spv_data_dump (&data, stdout);
556 spv_data_uninit (&data);
563 msg (ME, "%s", error);
572 /* This is really bogus.
574 XPath doesn't have any notion of a default XML namespace, but all of the
575 elements in the documents we're interested in have a namespace. Thus, we'd
576 need to require the XPath expressions to have a namespace on every single
577 element: vis:sourceVariable, vis:graph, and so on. That's a pain. So,
578 instead, we remove the default namespace from everyplace it occurs. XPath
579 does support the null namespace, so this allows sourceVariable, graph,
582 See http://plasmasturm.org/log/259/ and
583 https://mail.gnome.org/archives/xml/2003-April/msg00144.html for more
586 remove_default_xml_namespace (xmlNode *node)
588 if (node->ns && !node->ns->prefix)
591 for (xmlNode *child = node->children; child; child = child->next)
592 remove_default_xml_namespace (child);
596 register_ns (xmlXPathContext *ctx, const char *prefix, const char *uri)
598 xmlXPathRegisterNs (ctx, CHAR_CAST (xmlChar *, prefix),
599 CHAR_CAST (xmlChar *, uri));
602 static xmlXPathContext *
603 create_xpath_context (xmlDoc *doc)
605 xmlXPathContext *ctx = xmlXPathNewContext (doc);
606 register_ns (ctx, "vgr", "http://xml.spss.com/spss/viewer/viewer-graph");
607 register_ns (ctx, "vizml", "http://xml.spss.com/visualization");
608 register_ns (ctx, "vmd", "http://xml.spss.com/spss/viewer/viewer-model");
609 register_ns (ctx, "vps", "http://xml.spss.com/spss/viewer/viewer-pagesetup");
610 register_ns (ctx, "vst", "http://xml.spss.com/spss/viewer/viewer-style");
611 register_ns (ctx, "vtb", "http://xml.spss.com/spss/viewer/viewer-table");
612 register_ns (ctx, "vtl", "http://xml.spss.com/spss/viewer/table-looks");
613 register_ns (ctx, "vtt", "http://xml.spss.com/spss/viewer/viewer-treemodel");
614 register_ns (ctx, "vtx", "http://xml.spss.com/spss/viewer/viewer-text");
615 register_ns (ctx, "xsi", "http://www.w3.org/2001/XMLSchema-instance");
620 dump_xml (int argc, char **argv, const char *member_name,
621 char *error_s, xmlDoc *doc)
627 printf ("<!-- %s -->\n", member_name);
628 xmlElemDump (stdout, NULL, xmlDocGetRootElement (doc));
633 bool any_results = false;
635 remove_default_xml_namespace (xmlDocGetRootElement (doc));
636 for (int i = 2; i < argc; i++)
638 xmlXPathContext *xpath_ctx = create_xpath_context (doc);
639 xmlXPathSetContextNode (xmlDocGetRootElement (doc),
641 xmlXPathObject *xpath_obj = xmlXPathEvalExpression(
642 CHAR_CAST (xmlChar *, argv[i]), xpath_ctx);
644 error (1, 0, _("%s: invalid XPath expression"), argv[i]);
646 const xmlNodeSet *nodes = xpath_obj->nodesetval;
647 if (nodes && nodes->nodeNr > 0)
651 printf ("<!-- %s -->\n", member_name);
654 for (size_t j = 0; j < nodes->nodeNr; j++)
656 xmlElemDump (stdout, doc, nodes->nodeTab[j]);
661 xmlXPathFreeObject (xpath_obj);
662 xmlXPathFreeContext (xpath_ctx);
671 printf ("<!-- %s -->\n", member_name);
672 msg (ME, "%s", error_s);
678 run_dump_legacy_table (int argc, char **argv)
680 struct spv_reader *spv;
681 char *err = spv_open (argv[1], &spv);
683 error (1, 0, "%s", err);
685 struct spv_item **items;
687 spv_select (spv, criteria, n_criteria, &items, &n_items);
688 for (size_t i = 0; i < n_items; i++)
689 if (spv_item_is_legacy_table (items[i]))
692 char *error_s = spv_item_get_legacy_table (items[i], &doc);
693 dump_xml (argc, argv, items[i]->xml_member, error_s, doc);
701 run_dump_structure (int argc, char **argv)
703 struct spv_reader *spv;
704 char *err = spv_open (argv[1], &spv);
706 error (1, 0, "%s", err);
708 struct spv_item **items;
710 spv_select (spv, criteria, n_criteria, &items, &n_items);
711 const char *last_structure_member = NULL;
712 for (size_t i = 0; i < n_items; i++)
713 if (!last_structure_member || strcmp (items[i]->structure_member,
714 last_structure_member))
716 last_structure_member = items[i]->structure_member;
719 char *error_s = spv_item_get_structure (items[i], &doc);
720 dump_xml (argc, argv, items[i]->structure_member, error_s, doc);
728 run_is_legacy (int argc UNUSED, char **argv)
730 struct spv_reader *spv;
731 char *err = spv_open (argv[1], &spv);
733 error (1, 0, "%s", err);
735 bool is_legacy = false;
737 struct spv_item **items;
739 spv_select (spv, criteria, n_criteria, &items, &n_items);
740 for (size_t i = 0; i < n_items; i++)
741 if (spv_item_is_legacy_table (items[i]))
750 exit (is_legacy ? EXIT_SUCCESS : EXIT_FAILURE);
754 is_all_ascii (const char *s)
757 if (!encoding_guess_is_ascii_text (*s))
764 dump_strings (const char *encoding, struct string_array *strings)
766 string_array_sort (strings);
767 string_array_uniq (strings);
771 if (exclude_ascii_only || include_utf8_only)
774 for (size_t j = 0; j < strings->n; j++)
776 char *s = strings->strings[j];
777 bool is_ascii = is_all_ascii (s);
778 bool is_utf8 = !u8_check (CHAR_CAST (uint8_t *, s), strlen (s));
779 if (!is_ascii && (!include_utf8_only || is_utf8))
780 strings->strings[i++] = s;
786 for (size_t i = 0; i < strings->n; i++)
787 puts (strings->strings[i]);
791 size_t n_nonascii = 0;
793 for (size_t i = 0; i < strings->n; i++)
795 const char *s = strings->strings[i];
796 if (!is_all_ascii (s))
799 if (!u8_check (CHAR_CAST (uint8_t *, s), strlen (s)))
803 printf ("%s: %zu unique strings, %zu non-ASCII, %zu UTF-8.\n",
804 encoding, strings->n, n_nonascii, n_utf8);
809 run_strings (int argc UNUSED, char **argv)
811 struct spv_reader *spv;
812 char *err = spv_open (argv[1], &spv);
814 error (1, 0, "%s", err);
816 struct encoded_strings
819 struct string_array strings;
823 size_t allocated_es = 0;
825 struct spv_item **items;
827 spv_select (spv, criteria, n_criteria, &items, &n_items);
828 for (size_t i = 0; i < n_items; i++)
830 if (!spv_item_is_light_table (items[i]))
834 struct spvlb_table *table;
835 error = spv_item_get_light_table (items[i], &table);
838 msg (ME, "%s", error);
843 const char *table_encoding = spvlb_table_get_encoding (table);
845 for (j = 0; j < n_es; j++)
846 if (!strcmp (es[j].encoding, table_encoding))
850 if (n_es >= allocated_es)
851 es = x2nrealloc (es, &allocated_es, sizeof *es);
852 es[n_es++] = (struct encoded_strings) {
853 .encoding = xstrdup (table_encoding),
854 .strings = STRING_ARRAY_INITIALIZER,
857 collect_spvlb_strings (table, &es[j].strings);
861 for (size_t i = 0; i < n_es; i++)
863 dump_strings (es[i].encoding, &es[i].strings);
864 free (es[i].encoding);
865 string_array_destroy (&es[i].strings);
875 int min_args, max_args;
876 void (*run) (int argc, char **argv);
879 static const struct command commands[] =
881 { "detect", 1, 1, run_detect },
882 { "dir", 1, 1, run_directory },
883 { "convert", 2, 2, run_convert },
884 { "get-table-look", 2, 2, run_get_table_look },
885 { "convert-table-look", 2, 2, run_convert_table_look },
887 /* Undocumented commands. */
888 { "dump", 1, 1, run_dump },
889 { "dump-light-table", 1, 1, run_dump_light_table },
890 { "dump-legacy-data", 1, 1, run_dump_legacy_data },
891 { "dump-legacy-table", 1, INT_MAX, run_dump_legacy_table },
892 { "dump-structure", 1, INT_MAX, run_dump_structure },
893 { "is-legacy", 1, 1, run_is_legacy },
894 { "strings", 1, 1, run_strings },
896 static const int n_commands = sizeof commands / sizeof *commands;
898 static const struct command *
899 find_command (const char *name)
901 for (size_t i = 0; i < n_commands; i++)
903 const struct command *c = &commands[i];
904 if (!strcmp (name, c->name))
911 emit_msg (const struct msg *m, void *aux UNUSED)
913 if (m->severity == MSG_S_ERROR || m->severity == MSG_S_WARNING)
916 char *s = msg_to_string (m);
917 fprintf (stderr, "%s\n", s);
922 main (int argc, char **argv)
924 set_program_name (argv[0]);
925 msg_set_handler (emit_msg, NULL);
929 parse_options (argc, argv);
935 error (1, 0, _("missing command name (use --help for help)"));
937 const struct command *c = find_command (argv[0]);
939 error (1, 0, _("unknown command \"%s\" (use --help for help)"), argv[0]);
941 int n_args = argc - 1;
942 if (n_args < c->min_args || n_args > c->max_args)
944 if (c->min_args == c->max_args)
947 ngettext ("\"%s\" command takes exactly %d argument",
948 "\"%s\" command takes exactly %d arguments",
949 c->min_args), c->name, c->min_args);
951 else if (c->max_args == INT_MAX)
954 ngettext ("\"%s\" command requires at least %d argument",
955 "\"%s\" command requires at least %d arguments",
956 c->min_args), c->name, c->min_args);
961 _("\"%s\" command requires between %d and %d arguments"),
962 c->name, c->min_args, c->max_args);
968 pivot_table_look_unref (table_look);
971 return n_warnings ? EXIT_FAILURE : EXIT_SUCCESS;
974 static struct spv_criteria *
977 if (!n_criteria || new_criteria)
979 new_criteria = false;
980 if (n_criteria >= allocated_criteria)
981 criteria = x2nrealloc (criteria, &allocated_criteria,
983 criteria[n_criteria++] = (struct spv_criteria) SPV_CRITERIA_INITIALIZER;
986 return &criteria[n_criteria - 1];
990 parse_select (char *arg)
992 bool invert = arg[0] == '^';
995 unsigned classes = 0;
996 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
998 if (!strcmp (arg, "all"))
999 classes = SPV_ALL_CLASSES;
1000 else if (!strcmp (arg, "help"))
1002 puts (_("The following object classes are supported:"));
1003 for (int class = 0; class < SPV_N_CLASSES; class++)
1004 printf ("- %s\n", spv_item_class_to_string (class));
1009 int class = spv_item_class_from_string (token);
1010 if (class == SPV_N_CLASSES)
1011 error (1, 0, _("%s: unknown object class (use --select=help "
1013 classes |= 1u << class;
1017 struct spv_criteria *c = get_criteria ();
1018 c->classes = invert ? classes ^ SPV_ALL_CLASSES : classes;
1021 static struct spv_criteria_match *
1022 get_criteria_match (const char **arg)
1024 struct spv_criteria *c = get_criteria ();
1025 if ((*arg)[0] == '^')
1035 parse_commands (const char *arg)
1037 struct spv_criteria_match *cm = get_criteria_match (&arg);
1038 string_array_parse (&cm->commands, ss_cstr (arg), ss_cstr (","));
1042 parse_subtypes (const char *arg)
1044 struct spv_criteria_match *cm = get_criteria_match (&arg);
1045 string_array_parse (&cm->subtypes, ss_cstr (arg), ss_cstr (","));
1049 parse_labels (const char *arg)
1051 struct spv_criteria_match *cm = get_criteria_match (&arg);
1052 string_array_parse (&cm->labels, ss_cstr (arg), ss_cstr (","));
1056 parse_instances (char *arg)
1058 struct spv_criteria *c = get_criteria ();
1059 size_t allocated_instances = c->n_instances;
1061 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
1063 if (c->n_instances >= allocated_instances)
1064 c->instances = x2nrealloc (c->instances, &allocated_instances,
1065 sizeof *c->instances);
1067 c->instances[c->n_instances++] = (!strcmp (token, "last") ? -1
1073 parse_nth_commands (char *arg)
1075 struct spv_criteria *c = get_criteria ();
1076 size_t allocated_commands = c->n_commands;
1078 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
1080 if (c->n_commands >= allocated_commands)
1081 c->commands = x2nrealloc (c->commands, &allocated_commands,
1082 sizeof *c->commands);
1084 c->commands[c->n_commands++] = atoi (token);
1089 parse_members (const char *arg)
1091 struct spv_criteria *cm = get_criteria ();
1092 string_array_parse (&cm->members, ss_cstr (arg), ss_cstr (","));
1096 parse_table_look (const char *arg)
1098 pivot_table_look_unref (table_look);
1100 char *error_s = spv_table_look_read (arg, &table_look);
1102 error (1, 0, "%s", error_s);
1106 parse_options (int argc, char *argv[])
1112 OPT_MEMBER_NAMES = UCHAR_MAX + 1,
1130 static const struct option long_options[] =
1132 /* Input selection options. */
1133 { "show-hidden", no_argument, NULL, OPT_SHOW_HIDDEN },
1134 { "select", required_argument, NULL, OPT_SELECT },
1135 { "commands", required_argument, NULL, OPT_COMMANDS },
1136 { "nth-commands", required_argument, NULL, OPT_NTH_COMMANDS },
1137 { "subtypes", required_argument, NULL, OPT_SUBTYPES },
1138 { "labels", required_argument, NULL, OPT_LABELS },
1139 { "instances", required_argument, NULL, OPT_INSTANCES },
1140 { "members", required_argument, NULL, OPT_MEMBERS },
1141 { "errors", no_argument, NULL, OPT_ERRORS },
1142 { "or", no_argument, NULL, OPT_OR },
1144 /* "dir" command options. */
1145 { "member-names", no_argument, NULL, OPT_MEMBER_NAMES },
1147 /* "convert" command options. */
1148 { "force", no_argument, NULL, 'f' },
1149 { "table-look", required_argument, NULL, OPT_TABLE_LOOK },
1151 /* "dump-light-table" command options. */
1152 { "sort", no_argument, NULL, OPT_SORT },
1153 { "raw", no_argument, NULL, OPT_RAW },
1155 /* "strings" command options. */
1156 { "no-ascii-only", no_argument, NULL, OPT_NO_ASCII_ONLY },
1157 { "utf8-only", no_argument, NULL, OPT_UTF8_ONLY },
1159 { "help", no_argument, NULL, 'h' },
1160 { "help-developer", no_argument, NULL, OPT_HELP_DEVELOPER },
1161 { "version", no_argument, NULL, 'v' },
1163 { NULL, 0, NULL, 0 },
1168 c = getopt_long (argc, argv, "O:hvf", long_options, NULL);
1175 output_driver_parse_option (optarg, &output_options);
1178 case OPT_MEMBER_NAMES:
1179 show_member_names = true;
1182 case OPT_SHOW_HIDDEN:
1183 get_criteria ()->include_hidden = true;
1187 parse_select (optarg);
1191 parse_commands (optarg);
1194 case OPT_NTH_COMMANDS:
1195 parse_nth_commands (optarg);
1199 parse_subtypes (optarg);
1203 parse_labels (optarg);
1207 parse_instances (optarg);
1211 parse_members (optarg);
1215 get_criteria ()->error = true;
1219 new_criteria = true;
1230 case OPT_TABLE_LOOK:
1231 parse_table_look (optarg);
1234 case OPT_NO_ASCII_ONLY:
1235 exclude_ascii_only = true;
1239 include_utf8_only = true;
1247 version_etc (stdout, "pspp-output", PACKAGE_NAME, PACKAGE_VERSION,
1248 "Ben Pfaff", "John Darrington", NULL_SENTINEL);
1249 exit (EXIT_SUCCESS);
1253 exit (EXIT_SUCCESS);
1255 case OPT_HELP_DEVELOPER:
1257 exit (EXIT_SUCCESS);
1260 exit (EXIT_FAILURE);
1268 struct string s = DS_EMPTY_INITIALIZER;
1269 struct string_set formats = STRING_SET_INITIALIZER(formats);
1270 output_get_supported_formats (&formats);
1272 const struct string_set_node *node;
1273 STRING_SET_FOR_EACH (format, node, &formats)
1275 if (!ds_is_empty (&s))
1276 ds_put_byte (&s, ' ');
1277 ds_put_cstr (&s, format);
1279 string_set_destroy (&formats);
1282 %s, a utility for working with SPSS viewer (.spv) files.\n\
1283 Usage: %s [OPTION]... COMMAND ARG...\n\
1285 The following commands are available:\n\
1286 detect FILE Detect whether FILE is an SPV file.\n\
1287 dir FILE List tables and other items in FILE.\n\
1288 convert SOURCE DEST Convert .spv SOURCE to DEST.\n\
1289 get-table-look SOURCE DEST Copies first selected TableLook into DEST\n\
1290 convert-table-look SOURCE DEST Copies .tlo or .stt SOURCE into DEST\n\
1292 Input selection options for \"dir\" and \"convert\":\n\
1293 --select=CLASS... include only some kinds of objects\n\
1294 --select=help print known object classes\n\
1295 --commands=COMMAND... include only specified COMMANDs\n\
1296 --nth-commands=N... include only the Nth instance of selected commands\n\
1297 --subtypes=SUBTYPE... include only specified SUBTYPEs of output\n\
1298 --labels=LABEL... include only output objects with the given LABELs\n\
1299 --instances=INSTANCE... include only the given object INSTANCEs\n\
1300 --show-hidden include hidden output objects\n\
1301 --or separate two sets of selection options\n\
1303 \"convert\" by default infers the destination's format from its extension.\n\
1304 The known extensions are: %s\n\
1305 The following options override \"convert\" behavior:\n\
1306 -O format=FORMAT set destination format to FORMAT\n\
1307 -O OPTION=VALUE set output option\n\
1308 -f, --force keep output file even given errors\n\
1309 --table-look=FILE override tables' style with TableLook from FILE\n\
1311 --help display this help and exit\n\
1312 --help-developer display help for developer commands and exit\n\
1313 --version output version information and exit\n",
1314 program_name, program_name, ds_cstr (&s));
1319 developer_usage (void)
1322 The following developer commands are available:\n\
1323 dump FILE Dump pivot table structure\n\
1324 [--raw | --sort] dump-light-table FILE Dump light tables\n\
1325 [--raw] dump-legacy-data FILE Dump legacy table data\n\
1326 dump-legacy-table FILE [XPATH]... Dump legacy table XML\n\
1327 dump-structure FILE [XPATH]... Dump structure XML\n\
1328 is-legacy FILE Exit with status 0 if any legacy table selected\n\
1329 strings FILE Dump analysis of strings\n\
1331 Additional input selection options:\n\
1332 --members=MEMBER... include only objects with these Zip member names\n\
1333 --errors include only objects that cannot be loaded\n\
1335 Additional options for \"dir\" command:\n\
1336 --member-names show Zip member names with objects\n\
1338 Options for the \"strings\" command:\n\
1339 --raw Dump all (unique) strings\n\
1340 --raw --no-ascii-only Dump all strings that contain non-ASCII characters\n\
1341 --raw --utf8-only Dump all non-ASCII strings that are valid UTF-8\n\
1344 --raw print raw binary data instead of a parsed version\n\
1345 --sort sort borders and areas for shorter \"diff\" output\n");