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/output-item.h"
35 #include "output/pivot-table.h"
36 #include "output/spv/light-binary-parser.h"
37 #include "output/spv/spv-legacy-data.h"
38 #include "output/spv/spv-light-decoder.h"
39 #include "output/spv/spv-output.h"
40 #include "output/spv/spv-select.h"
41 #include "output/spv/spv-table-look.h"
42 #include "output/spv/spv.h"
44 #include "gl/c-ctype.h"
46 #include "gl/progname.h"
47 #include "gl/version-etc.h"
48 #include "gl/xalloc.h"
50 #include <libxml/tree.h>
51 #include <libxml/xpath.h>
52 #include <libxml/xpathInternals.h>
55 #define _(msgid) gettext (msgid)
57 /* -O key=value: Output driver options. */
58 static struct string_map output_options
59 = STRING_MAP_INITIALIZER (output_options);
61 /* --member-names: Include .zip member name in "dir" output. */
62 static bool show_member_names;
64 /* --show-hidden, --select, --commands, ...: Selection criteria. */
65 static struct spv_criteria *criteria;
66 static size_t n_criteria, allocated_criteria;
68 /* --or: Add new element to 'criteria' array. */
69 static bool new_criteria;
71 /* --sort: Sort members under dump-light-table, to make comparisons easier. */
74 /* --raw: Dump raw binary data in "dump-light-table"; dump all strings in
78 /* --no-ascii-only: Drop all-ASCII strings in "strings". */
79 static bool exclude_ascii_only;
81 /* --utf8-only: Only print strings that have UTF-8 multibyte sequences in
83 static bool include_utf8_only;
85 /* -f, --force: Keep output file even on error. */
88 /* --table-look: TableLook to replace table style for conversion. */
89 static struct pivot_table_look *table_look;
91 /* Number of warnings issued. */
92 static size_t n_warnings;
94 static void usage (void);
95 static void developer_usage (void);
96 static void parse_options (int argc, char **argv);
99 dump_item (const struct spv_item *item)
101 if (show_member_names && (item->xml_member || item->bin_member))
103 const char *x = item->xml_member;
104 const char *b = item->bin_member;
106 /* The strings below are not marked for translation because they are only
107 useful to developers. */
109 ? xasprintf ("%s and %s:", x, b)
110 : xasprintf ("%s:", x ? x : b));
111 output_item_submit (text_item_create_nocopy (TEXT_ITEM_TITLE, s,
112 xstrdup ("Member Names")));
115 switch (spv_item_get_type (item))
117 case SPV_ITEM_HEADING:
121 spv_text_submit (item);
125 pivot_table_submit (pivot_table_ref (spv_item_get_table (item)));
135 output_item_submit (image_item_create (cairo_surface_reference (
136 spv_item_get_image (item))));
148 print_item_directory (const struct spv_item *item)
150 for (int i = 1; i < spv_item_get_level (item); i++)
153 enum spv_item_type type = spv_item_get_type (item);
154 printf ("- %s", spv_item_type_to_string (type));
156 const char *label = spv_item_get_label (item);
158 printf (" \"%s\"", label);
160 if (type == SPV_ITEM_TABLE)
162 const struct pivot_table *table = spv_item_get_table (item);
163 char *title = pivot_value_to_string (table->title, table);
164 if (!label || strcmp (title, label))
165 printf (" title \"%s\"", title);
169 const char *command_id = spv_item_get_command_id (item);
171 printf (" command \"%s\"", command_id);
173 const char *subtype = spv_item_get_subtype (item);
174 if (subtype && (!label || strcmp (label, subtype)))
175 printf (" subtype \"%s\"", subtype);
177 if (!spv_item_is_visible (item))
178 printf (" (hidden)");
180 if (show_member_names)
182 const char *members[] = {
189 for (size_t i = 0; i < sizeof members / sizeof *members; i++)
191 printf (" %s %s", n++ == 0 ? "in" : "and", members[i]);
197 run_detect (int argc UNUSED, char **argv)
199 char *err = spv_detect (argv[1]);
201 error (1, 0, "%s", err);
205 run_directory (int argc UNUSED, char **argv)
207 struct spv_reader *spv;
208 char *err = spv_open (argv[1], &spv);
210 error (1, 0, "%s", err);
212 struct spv_item **items;
214 spv_select (spv, criteria, n_criteria, &items, &n_items);
215 for (size_t i = 0; i < n_items; i++)
216 print_item_directory (items[i]);
224 const struct spv_item **nodes;
228 const struct spv_item *stub[N_STUB];
232 swap_nodes (const struct spv_item **a, const struct spv_item **b)
234 const struct spv_item *tmp = *a;
240 get_path (const struct spv_item *item, struct item_path *path)
242 size_t allocated = 10;
243 path->nodes = path->stub;
248 if (path->n >= allocated)
250 if (path->nodes == path->stub)
251 path->nodes = xmemdup (path->stub, sizeof path->stub);
252 path->nodes = x2nrealloc (path->nodes, &allocated,
253 sizeof *path->nodes);
255 path->nodes[path->n++] = item;
259 for (size_t i = 0; i < path->n / 2; i++)
260 swap_nodes (&path->nodes[i], &path->nodes[path->n - i - 1]);
264 free_path (struct item_path *path)
266 if (path && path->nodes != path->stub)
271 dump_heading_transition (const struct spv_item *old,
272 const struct spv_item *new)
277 struct item_path old_path, new_path;
278 get_path (old, &old_path);
279 get_path (new, &new_path);
282 for (; common < old_path.n && common < new_path.n; common++)
283 if (old_path.nodes[common] != new_path.nodes[common])
286 for (size_t i = common; i < old_path.n; i++)
287 output_item_submit (group_close_item_create ());
288 for (size_t i = common; i < new_path.n; i++)
289 output_item_submit (group_open_item_create (
290 new_path.nodes[i]->command_id,
291 new_path.nodes[i]->label));
293 free_path (&old_path);
294 free_path (&new_path);
298 run_convert (int argc UNUSED, char **argv)
300 struct spv_reader *spv;
301 char *err = spv_open (argv[1], &spv);
303 error (1, 0, "%s", err);
306 spv_item_set_table_look (spv_get_root (spv), table_look);
308 output_engine_push ();
309 output_set_filename (argv[1]);
310 string_map_replace (&output_options, "output-file", argv[2]);
311 struct output_driver *driver = output_driver_create (&output_options);
314 output_driver_register (driver);
316 const struct page_setup *ps = spv_get_page_setup (spv);
318 output_item_submit (page_setup_item_create (ps));
320 struct spv_item **items;
322 spv_select (spv, criteria, n_criteria, &items, &n_items);
323 struct spv_item *prev_heading = spv_get_root (spv);
324 for (size_t i = 0; i < n_items; i++)
326 struct spv_item *heading
327 = items[i]->type == SPV_ITEM_HEADING ? items[i] : items[i]->parent;
328 dump_heading_transition (prev_heading, heading);
329 dump_item (items[i]);
330 prev_heading = heading;
332 dump_heading_transition (prev_heading, spv_get_root (spv));
337 output_engine_pop ();
340 if (n_warnings && !force)
342 /* XXX There could be other files to unlink, e.g. the ascii driver can
343 produce additional files with the charts. */
348 static const struct pivot_table *
349 get_first_table (const struct spv_reader *spv)
351 struct spv_item **items;
353 spv_select (spv, criteria, n_criteria, &items, &n_items);
355 for (size_t i = 0; i < n_items; i++)
356 if (spv_item_is_table (items[i]))
359 return spv_item_get_table (items[i]);
367 run_get_table_look (int argc UNUSED, char **argv)
369 struct pivot_table_look *look;
370 if (strcmp (argv[1], "-"))
372 struct spv_reader *spv;
373 char *err = spv_open (argv[1], &spv);
375 error (1, 0, "%s", err);
377 const struct pivot_table *table = get_first_table (spv);
379 error (1, 0, "%s: no tables found", argv[1]);
381 look = pivot_table_look_ref (pivot_table_get_look (table));
386 look = pivot_table_look_ref (pivot_table_look_builtin_default ());
388 char *err = spv_table_look_write (argv[2], look);
390 error (1, 0, "%s", err);
392 pivot_table_look_unref (look);
396 run_convert_table_look (int argc UNUSED, char **argv)
398 struct pivot_table_look *look;
399 char *err = spv_table_look_read (argv[1], &look);
401 error (1, 0, "%s", err);
403 err = spv_table_look_write (argv[2], look);
405 error (1, 0, "%s", err);
407 pivot_table_look_unref (look);
412 run_dump (int argc UNUSED, char **argv)
414 struct spv_reader *spv;
415 char *err = spv_open (argv[1], &spv);
417 error (1, 0, "%s", err);
419 struct spv_item **items;
421 spv_select (spv, criteria, n_criteria, &items, &n_items);
422 for (size_t i = 0; i < n_items; i++)
423 if (items[i]->type == SPV_ITEM_TABLE)
425 pivot_table_dump (spv_item_get_table (items[i]), 0);
434 compare_borders (const void *a_, const void *b_)
436 const struct spvlb_border *const *ap = a_;
437 const struct spvlb_border *const *bp = b_;
438 uint32_t a = (*ap)->border_type;
439 uint32_t b = (*bp)->border_type;
441 return a < b ? -1 : a > b;
445 compare_cells (const void *a_, const void *b_)
447 const struct spvlb_cell *const *ap = a_;
448 const struct spvlb_cell *const *bp = b_;
449 uint64_t a = (*ap)->index;
450 uint64_t b = (*bp)->index;
452 return a < b ? -1 : a > b;
456 run_dump_light_table (int argc UNUSED, char **argv)
458 if (raw && isatty (STDOUT_FILENO))
459 error (1, 0, "not writing binary data to tty");
461 struct spv_reader *spv;
462 char *err = spv_open (argv[1], &spv);
464 error (1, 0, "%s", err);
466 struct spv_item **items;
468 spv_select (spv, criteria, n_criteria, &items, &n_items);
469 for (size_t i = 0; i < n_items; i++)
471 if (!spv_item_is_light_table (items[i]))
479 error = spv_item_get_raw_light_table (items[i], &data, &size);
482 fwrite (data, size, 1, stdout);
488 struct spvlb_table *table;
489 error = spv_item_get_light_table (items[i], &table);
494 qsort (table->borders->borders, table->borders->n_borders,
495 sizeof *table->borders->borders, compare_borders);
496 qsort (table->cells->cells, table->cells->n_cells,
497 sizeof *table->cells->cells, compare_cells);
499 spvlb_print_table (items[i]->bin_member, 0, table);
500 spvlb_free_table (table);
505 msg (ME, "%s", error);
516 run_dump_legacy_data (int argc UNUSED, char **argv)
518 struct spv_reader *spv;
519 char *err = spv_open (argv[1], &spv);
521 error (1, 0, "%s", err);
523 if (raw && isatty (STDOUT_FILENO))
524 error (1, 0, "not writing binary data to tty");
526 struct spv_item **items;
528 spv_select (spv, criteria, n_criteria, &items, &n_items);
529 for (size_t i = 0; i < n_items; i++)
530 if (spv_item_is_legacy_table (items[i]))
532 struct spv_data data;
538 error = spv_item_get_raw_legacy_data (items[i], &data, &size);
541 fwrite (data, size, 1, stdout);
547 error = spv_item_get_legacy_data (items[i], &data);
550 printf ("%s:\n", items[i]->bin_member);
551 spv_data_dump (&data, stdout);
552 spv_data_uninit (&data);
559 msg (ME, "%s", error);
568 /* This is really bogus.
570 XPath doesn't have any notion of a default XML namespace, but all of the
571 elements in the documents we're interested in have a namespace. Thus, we'd
572 need to require the XPath expressions to have a namespace on every single
573 element: vis:sourceVariable, vis:graph, and so on. That's a pain. So,
574 instead, we remove the default namespace from everyplace it occurs. XPath
575 does support the null namespace, so this allows sourceVariable, graph,
578 See http://plasmasturm.org/log/259/ and
579 https://mail.gnome.org/archives/xml/2003-April/msg00144.html for more
582 remove_default_xml_namespace (xmlNode *node)
584 if (node->ns && !node->ns->prefix)
587 for (xmlNode *child = node->children; child; child = child->next)
588 remove_default_xml_namespace (child);
592 register_ns (xmlXPathContext *ctx, const char *prefix, const char *uri)
594 xmlXPathRegisterNs (ctx, CHAR_CAST (xmlChar *, prefix),
595 CHAR_CAST (xmlChar *, uri));
598 static xmlXPathContext *
599 create_xpath_context (xmlDoc *doc)
601 xmlXPathContext *ctx = xmlXPathNewContext (doc);
602 register_ns (ctx, "vgr", "http://xml.spss.com/spss/viewer/viewer-graph");
603 register_ns (ctx, "vizml", "http://xml.spss.com/visualization");
604 register_ns (ctx, "vmd", "http://xml.spss.com/spss/viewer/viewer-model");
605 register_ns (ctx, "vps", "http://xml.spss.com/spss/viewer/viewer-pagesetup");
606 register_ns (ctx, "vst", "http://xml.spss.com/spss/viewer/viewer-style");
607 register_ns (ctx, "vtb", "http://xml.spss.com/spss/viewer/viewer-table");
608 register_ns (ctx, "vtl", "http://xml.spss.com/spss/viewer/table-looks");
609 register_ns (ctx, "vtt", "http://xml.spss.com/spss/viewer/viewer-treemodel");
610 register_ns (ctx, "vtx", "http://xml.spss.com/spss/viewer/viewer-text");
611 register_ns (ctx, "xsi", "http://www.w3.org/2001/XMLSchema-instance");
616 dump_xml (int argc, char **argv, const char *member_name,
617 char *error_s, xmlDoc *doc)
623 printf ("<!-- %s -->\n", member_name);
624 xmlElemDump (stdout, NULL, xmlDocGetRootElement (doc));
629 bool any_results = false;
631 remove_default_xml_namespace (xmlDocGetRootElement (doc));
632 for (int i = 2; i < argc; i++)
634 xmlXPathContext *xpath_ctx = create_xpath_context (doc);
635 xmlXPathSetContextNode (xmlDocGetRootElement (doc),
637 xmlXPathObject *xpath_obj = xmlXPathEvalExpression(
638 CHAR_CAST (xmlChar *, argv[i]), xpath_ctx);
640 error (1, 0, _("%s: invalid XPath expression"), argv[i]);
642 const xmlNodeSet *nodes = xpath_obj->nodesetval;
643 if (nodes && nodes->nodeNr > 0)
647 printf ("<!-- %s -->\n", member_name);
650 for (size_t j = 0; j < nodes->nodeNr; j++)
652 xmlElemDump (stdout, doc, nodes->nodeTab[j]);
657 xmlXPathFreeObject (xpath_obj);
658 xmlXPathFreeContext (xpath_ctx);
667 printf ("<!-- %s -->\n", member_name);
668 msg (ME, "%s", error_s);
674 run_dump_legacy_table (int argc, char **argv)
676 struct spv_reader *spv;
677 char *err = spv_open (argv[1], &spv);
679 error (1, 0, "%s", err);
681 struct spv_item **items;
683 spv_select (spv, criteria, n_criteria, &items, &n_items);
684 for (size_t i = 0; i < n_items; i++)
685 if (spv_item_is_legacy_table (items[i]))
688 char *error_s = spv_item_get_legacy_table (items[i], &doc);
689 dump_xml (argc, argv, items[i]->xml_member, error_s, doc);
697 run_dump_structure (int argc, char **argv)
699 struct spv_reader *spv;
700 char *err = spv_open (argv[1], &spv);
702 error (1, 0, "%s", err);
704 struct spv_item **items;
706 spv_select (spv, criteria, n_criteria, &items, &n_items);
707 const char *last_structure_member = NULL;
708 for (size_t i = 0; i < n_items; i++)
709 if (!last_structure_member || strcmp (items[i]->structure_member,
710 last_structure_member))
712 last_structure_member = items[i]->structure_member;
715 char *error_s = spv_item_get_structure (items[i], &doc);
716 dump_xml (argc, argv, items[i]->structure_member, error_s, doc);
724 run_is_legacy (int argc UNUSED, char **argv)
726 struct spv_reader *spv;
727 char *err = spv_open (argv[1], &spv);
729 error (1, 0, "%s", err);
731 bool is_legacy = false;
733 struct spv_item **items;
735 spv_select (spv, criteria, n_criteria, &items, &n_items);
736 for (size_t i = 0; i < n_items; i++)
737 if (spv_item_is_legacy_table (items[i]))
746 exit (is_legacy ? EXIT_SUCCESS : EXIT_FAILURE);
750 is_all_ascii (const char *s)
753 if (!encoding_guess_is_ascii_text (*s))
760 dump_strings (const char *encoding, struct string_array *strings)
762 string_array_sort (strings);
763 string_array_uniq (strings);
767 if (exclude_ascii_only || include_utf8_only)
770 for (size_t j = 0; j < strings->n; j++)
772 char *s = strings->strings[j];
773 bool is_ascii = is_all_ascii (s);
774 bool is_utf8 = !u8_check (CHAR_CAST (uint8_t *, s), strlen (s));
775 if (!is_ascii && (!include_utf8_only || is_utf8))
776 strings->strings[i++] = s;
782 for (size_t i = 0; i < strings->n; i++)
783 puts (strings->strings[i]);
787 size_t n_nonascii = 0;
789 for (size_t i = 0; i < strings->n; i++)
791 const char *s = strings->strings[i];
792 if (!is_all_ascii (s))
795 if (!u8_check (CHAR_CAST (uint8_t *, s), strlen (s)))
799 printf ("%s: %zu unique strings, %zu non-ASCII, %zu UTF-8.\n",
800 encoding, strings->n, n_nonascii, n_utf8);
805 run_strings (int argc UNUSED, char **argv)
807 struct spv_reader *spv;
808 char *err = spv_open (argv[1], &spv);
810 error (1, 0, "%s", err);
812 struct encoded_strings
815 struct string_array strings;
819 size_t allocated_es = 0;
821 struct spv_item **items;
823 spv_select (spv, criteria, n_criteria, &items, &n_items);
824 for (size_t i = 0; i < n_items; i++)
826 if (!spv_item_is_light_table (items[i]))
830 struct spvlb_table *table;
831 error = spv_item_get_light_table (items[i], &table);
834 msg (ME, "%s", error);
839 const char *table_encoding = spvlb_table_get_encoding (table);
841 for (j = 0; j < n_es; j++)
842 if (!strcmp (es[j].encoding, table_encoding))
846 if (n_es >= allocated_es)
847 es = x2nrealloc (es, &allocated_es, sizeof *es);
848 es[n_es++] = (struct encoded_strings) {
849 .encoding = xstrdup (table_encoding),
850 .strings = STRING_ARRAY_INITIALIZER,
853 collect_spvlb_strings (table, &es[j].strings);
857 for (size_t i = 0; i < n_es; i++)
859 dump_strings (es[i].encoding, &es[i].strings);
860 free (es[i].encoding);
861 string_array_destroy (&es[i].strings);
871 int min_args, max_args;
872 void (*run) (int argc, char **argv);
875 static const struct command commands[] =
877 { "detect", 1, 1, run_detect },
878 { "dir", 1, 1, run_directory },
879 { "convert", 2, 2, run_convert },
880 { "get-table-look", 2, 2, run_get_table_look },
881 { "convert-table-look", 2, 2, run_convert_table_look },
883 /* Undocumented commands. */
884 { "dump", 1, 1, run_dump },
885 { "dump-light-table", 1, 1, run_dump_light_table },
886 { "dump-legacy-data", 1, 1, run_dump_legacy_data },
887 { "dump-legacy-table", 1, INT_MAX, run_dump_legacy_table },
888 { "dump-structure", 1, INT_MAX, run_dump_structure },
889 { "is-legacy", 1, 1, run_is_legacy },
890 { "strings", 1, 1, run_strings },
892 static const int n_commands = sizeof commands / sizeof *commands;
894 static const struct command *
895 find_command (const char *name)
897 for (size_t i = 0; i < n_commands; i++)
899 const struct command *c = &commands[i];
900 if (!strcmp (name, c->name))
907 emit_msg (const struct msg *m, void *aux UNUSED)
909 if (m->severity == MSG_S_ERROR || m->severity == MSG_S_WARNING)
912 char *s = msg_to_string (m);
913 fprintf (stderr, "%s\n", s);
918 main (int argc, char **argv)
920 set_program_name (argv[0]);
921 msg_set_handler (emit_msg, NULL);
925 parse_options (argc, argv);
931 error (1, 0, _("missing command name (use --help for help)"));
933 const struct command *c = find_command (argv[0]);
935 error (1, 0, _("unknown command \"%s\" (use --help for help)"), argv[0]);
937 int n_args = argc - 1;
938 if (n_args < c->min_args || n_args > c->max_args)
940 if (c->min_args == c->max_args)
943 ngettext ("\"%s\" command takes exactly %d argument",
944 "\"%s\" command takes exactly %d arguments",
945 c->min_args), c->name, c->min_args);
947 else if (c->max_args == INT_MAX)
950 ngettext ("\"%s\" command requires at least %d argument",
951 "\"%s\" command requires at least %d arguments",
952 c->min_args), c->name, c->min_args);
957 _("\"%s\" command requires between %d and %d arguments"),
958 c->name, c->min_args, c->max_args);
964 pivot_table_look_unref (table_look);
967 return n_warnings ? EXIT_FAILURE : EXIT_SUCCESS;
970 static struct spv_criteria *
973 if (!n_criteria || new_criteria)
975 new_criteria = false;
976 if (n_criteria >= allocated_criteria)
977 criteria = x2nrealloc (criteria, &allocated_criteria,
979 criteria[n_criteria++] = (struct spv_criteria) SPV_CRITERIA_INITIALIZER;
982 return &criteria[n_criteria - 1];
986 parse_select (char *arg)
988 bool invert = arg[0] == '^';
991 unsigned classes = 0;
992 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
994 if (!strcmp (arg, "all"))
995 classes = SPV_ALL_CLASSES;
996 else if (!strcmp (arg, "help"))
998 puts (_("The following object classes are supported:"));
999 for (int class = 0; class < SPV_N_CLASSES; class++)
1000 printf ("- %s\n", spv_item_class_to_string (class));
1005 int class = spv_item_class_from_string (token);
1006 if (class == SPV_N_CLASSES)
1007 error (1, 0, _("%s: unknown object class (use --select=help "
1009 classes |= 1u << class;
1013 struct spv_criteria *c = get_criteria ();
1014 c->classes = invert ? classes ^ SPV_ALL_CLASSES : classes;
1017 static struct spv_criteria_match *
1018 get_criteria_match (const char **arg)
1020 struct spv_criteria *c = get_criteria ();
1021 if ((*arg)[0] == '^')
1031 parse_commands (const char *arg)
1033 struct spv_criteria_match *cm = get_criteria_match (&arg);
1034 string_array_parse (&cm->commands, ss_cstr (arg), ss_cstr (","));
1038 parse_subtypes (const char *arg)
1040 struct spv_criteria_match *cm = get_criteria_match (&arg);
1041 string_array_parse (&cm->subtypes, ss_cstr (arg), ss_cstr (","));
1045 parse_labels (const char *arg)
1047 struct spv_criteria_match *cm = get_criteria_match (&arg);
1048 string_array_parse (&cm->labels, ss_cstr (arg), ss_cstr (","));
1052 parse_instances (char *arg)
1054 struct spv_criteria *c = get_criteria ();
1055 size_t allocated_instances = c->n_instances;
1057 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
1059 if (c->n_instances >= allocated_instances)
1060 c->instances = x2nrealloc (c->instances, &allocated_instances,
1061 sizeof *c->instances);
1063 c->instances[c->n_instances++] = (!strcmp (token, "last") ? -1
1069 parse_nth_commands (char *arg)
1071 struct spv_criteria *c = get_criteria ();
1072 size_t allocated_commands = c->n_commands;
1074 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
1076 if (c->n_commands >= allocated_commands)
1077 c->commands = x2nrealloc (c->commands, &allocated_commands,
1078 sizeof *c->commands);
1080 c->commands[c->n_commands++] = atoi (token);
1085 parse_members (const char *arg)
1087 struct spv_criteria *cm = get_criteria ();
1088 string_array_parse (&cm->members, ss_cstr (arg), ss_cstr (","));
1092 parse_table_look (const char *arg)
1094 pivot_table_look_unref (table_look);
1096 char *error_s = spv_table_look_read (arg, &table_look);
1098 error (1, 0, "%s", error_s);
1102 parse_options (int argc, char *argv[])
1108 OPT_MEMBER_NAMES = UCHAR_MAX + 1,
1126 static const struct option long_options[] =
1128 /* Input selection options. */
1129 { "show-hidden", no_argument, NULL, OPT_SHOW_HIDDEN },
1130 { "select", required_argument, NULL, OPT_SELECT },
1131 { "commands", required_argument, NULL, OPT_COMMANDS },
1132 { "nth-commands", required_argument, NULL, OPT_NTH_COMMANDS },
1133 { "subtypes", required_argument, NULL, OPT_SUBTYPES },
1134 { "labels", required_argument, NULL, OPT_LABELS },
1135 { "instances", required_argument, NULL, OPT_INSTANCES },
1136 { "members", required_argument, NULL, OPT_MEMBERS },
1137 { "errors", no_argument, NULL, OPT_ERRORS },
1138 { "or", no_argument, NULL, OPT_OR },
1140 /* "dir" command options. */
1141 { "member-names", no_argument, NULL, OPT_MEMBER_NAMES },
1143 /* "convert" command options. */
1144 { "force", no_argument, NULL, 'f' },
1145 { "table-look", required_argument, NULL, OPT_TABLE_LOOK },
1147 /* "dump-light-table" command options. */
1148 { "sort", no_argument, NULL, OPT_SORT },
1149 { "raw", no_argument, NULL, OPT_RAW },
1151 /* "strings" command options. */
1152 { "no-ascii-only", no_argument, NULL, OPT_NO_ASCII_ONLY },
1153 { "utf8-only", no_argument, NULL, OPT_UTF8_ONLY },
1155 { "help", no_argument, NULL, 'h' },
1156 { "help-developer", no_argument, NULL, OPT_HELP_DEVELOPER },
1157 { "version", no_argument, NULL, 'v' },
1159 { NULL, 0, NULL, 0 },
1164 c = getopt_long (argc, argv, "O:hvf", long_options, NULL);
1171 output_driver_parse_option (optarg, &output_options);
1174 case OPT_MEMBER_NAMES:
1175 show_member_names = true;
1178 case OPT_SHOW_HIDDEN:
1179 get_criteria ()->include_hidden = true;
1183 parse_select (optarg);
1187 parse_commands (optarg);
1190 case OPT_NTH_COMMANDS:
1191 parse_nth_commands (optarg);
1195 parse_subtypes (optarg);
1199 parse_labels (optarg);
1203 parse_instances (optarg);
1207 parse_members (optarg);
1211 get_criteria ()->error = true;
1215 new_criteria = true;
1226 case OPT_TABLE_LOOK:
1227 parse_table_look (optarg);
1230 case OPT_NO_ASCII_ONLY:
1231 exclude_ascii_only = true;
1235 include_utf8_only = true;
1243 version_etc (stdout, "pspp-output", PACKAGE_NAME, PACKAGE_VERSION,
1244 "Ben Pfaff", "John Darrington", NULL_SENTINEL);
1245 exit (EXIT_SUCCESS);
1249 exit (EXIT_SUCCESS);
1251 case OPT_HELP_DEVELOPER:
1253 exit (EXIT_SUCCESS);
1256 exit (EXIT_FAILURE);
1264 struct string s = DS_EMPTY_INITIALIZER;
1265 struct string_set formats = STRING_SET_INITIALIZER(formats);
1266 output_get_supported_formats (&formats);
1268 const struct string_set_node *node;
1269 STRING_SET_FOR_EACH (format, node, &formats)
1271 if (!ds_is_empty (&s))
1272 ds_put_byte (&s, ' ');
1273 ds_put_cstr (&s, format);
1275 string_set_destroy (&formats);
1278 %s, a utility for working with SPSS viewer (.spv) files.\n\
1279 Usage: %s [OPTION]... COMMAND ARG...\n\
1281 The following commands are available:\n\
1282 detect FILE Detect whether FILE is an SPV file.\n\
1283 dir FILE List tables and other items in FILE.\n\
1284 convert SOURCE DEST Convert .spv SOURCE to DEST.\n\
1285 get-table-look SOURCE DEST Copies first selected TableLook into DEST\n\
1286 convert-table-look SOURCE DEST Copies .tlo or .stt SOURCE into DEST\n\
1288 Input selection options for \"dir\" and \"convert\":\n\
1289 --select=CLASS... include only some kinds of objects\n\
1290 --select=help print known object classes\n\
1291 --commands=COMMAND... include only specified COMMANDs\n\
1292 --nth-commands=N... include only the Nth instance of selected commands\n\
1293 --subtypes=SUBTYPE... include only specified SUBTYPEs of output\n\
1294 --labels=LABEL... include only output objects with the given LABELs\n\
1295 --instances=INSTANCE... include only the given object INSTANCEs\n\
1296 --show-hidden include hidden output objects\n\
1297 --or separate two sets of selection options\n\
1299 \"convert\" by default infers the destination's format from its extension.\n\
1300 The known extensions are: %s\n\
1301 The following options override \"convert\" behavior:\n\
1302 -O format=FORMAT set destination format to FORMAT\n\
1303 -O OPTION=VALUE set output option\n\
1304 -f, --force keep output file even given errors\n\
1305 --table-look=FILE override tables' style with TableLook from FILE\n\
1307 --help display this help and exit\n\
1308 --help-developer display help for developer commands and exit\n\
1309 --version output version information and exit\n",
1310 program_name, program_name, ds_cstr (&s));
1315 developer_usage (void)
1318 The following developer commands are available:\n\
1319 dump FILE Dump pivot table structure\n\
1320 [--raw | --sort] dump-light-table FILE Dump light tables\n\
1321 [--raw] dump-legacy-data FILE Dump legacy table data\n\
1322 dump-legacy-table FILE [XPATH]... Dump legacy table XML\n\
1323 dump-structure FILE [XPATH]... Dump structure XML\n\
1324 is-legacy FILE Exit with status 0 if any legacy table selected\n\
1325 strings FILE Dump analysis of strings\n\
1327 Additional input selection options:\n\
1328 --members=MEMBER... include only objects with these Zip member names\n\
1329 --errors include only objects that cannot be loaded\n\
1331 Additional options for \"dir\" command:\n\
1332 --member-names show Zip member names with objects\n\
1334 Options for the \"strings\" command:\n\
1335 --raw Dump all (unique) strings\n\
1336 --raw --no-ascii-only Dump all strings that contain non-ASCII characters\n\
1337 --raw --utf8-only Dump all non-ASCII strings that are valid UTF-8\n\
1340 --raw print raw binary data instead of a parsed version\n\
1341 --sort sort borders and areas for shorter \"diff\" output\n");