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/>. */
24 #include "data/file-handle-def.h"
25 #include "data/settings.h"
26 #include "libpspp/i18n.h"
27 #include "libpspp/message.h"
28 #include "libpspp/string-map.h"
29 #include "libpspp/string-set.h"
30 #include "output/driver.h"
31 #include "output/group-item.h"
32 #include "output/page-setup-item.h"
33 #include "output/pivot-table.h"
34 #include "output/spv/light-binary-parser.h"
35 #include "output/spv/spv-legacy-data.h"
36 #include "output/spv/spv-output.h"
37 #include "output/spv/spv-select.h"
38 #include "output/spv/spv-table-look.h"
39 #include "output/spv/spv.h"
40 #include "output/table-item.h"
41 #include "output/text-item.h"
43 #include "gl/c-ctype.h"
45 #include "gl/progname.h"
46 #include "gl/version-etc.h"
47 #include "gl/xalloc.h"
49 #include <libxml/tree.h>
50 #include <libxml/xpath.h>
51 #include <libxml/xpathInternals.h>
54 #define _(msgid) gettext (msgid)
56 /* -O key=value: Output driver options. */
57 static struct string_map output_options
58 = STRING_MAP_INITIALIZER (output_options);
60 /* --member-name: Include .zip member name in "dir" output. */
61 static bool show_member_names;
63 /* --show-hidden, --select, --commands, ...: Selection criteria. */
64 static struct spv_criteria *criteria;
65 static size_t n_criteria, allocated_criteria;
67 /* --or: Add new element to 'criteria' array. */
68 static bool new_criteria;
70 /* --sort: Sort members under dump-light-table, to make comparisons easier. */
73 /* --raw: Dump raw binary data in dump-light-table. */
76 /* -f, --force: Keep output file even on error. */
79 /* --table-look: TableLook to replace table style for conversion. */
80 static struct pivot_table_look *table_look;
82 /* Number of warnings issued. */
83 static size_t n_warnings;
85 static void usage (void);
86 static void parse_options (int argc, char **argv);
89 dump_item (const struct spv_item *item)
91 if (show_member_names && (item->xml_member || item->bin_member))
93 const char *x = item->xml_member;
94 const char *b = item->bin_member;
96 ? xasprintf (_("%s and %s:"), x, b)
97 : xasprintf ("%s:", x ? x : b));
98 text_item_submit (text_item_create_nocopy (TEXT_ITEM_TITLE, s));
101 switch (spv_item_get_type (item))
103 case SPV_ITEM_HEADING:
107 spv_text_submit (item);
111 pivot_table_submit (pivot_table_ref (spv_item_get_table (item)));
120 case SPV_ITEM_OBJECT:
132 print_item_directory (const struct spv_item *item)
134 for (int i = 1; i < spv_item_get_level (item); i++)
137 enum spv_item_type type = spv_item_get_type (item);
138 printf ("- %s", spv_item_type_to_string (type));
140 const char *label = spv_item_get_label (item);
142 printf (" \"%s\"", label);
144 if (type == SPV_ITEM_TABLE)
146 const struct pivot_table *table = spv_item_get_table (item);
147 char *title = pivot_value_to_string (table->title,
148 SETTINGS_VALUE_SHOW_DEFAULT,
149 SETTINGS_VALUE_SHOW_DEFAULT);
150 if (!label || strcmp (title, label))
151 printf (" title \"%s\"", title);
155 const char *command_id = spv_item_get_command_id (item);
157 printf (" command \"%s\"", command_id);
159 const char *subtype = spv_item_get_subtype (item);
160 if (subtype && (!label || strcmp (label, subtype)))
161 printf (" subtype \"%s\"", subtype);
163 if (!spv_item_is_visible (item))
164 printf (" (hidden)");
165 if (show_member_names && (item->xml_member || item->bin_member))
167 if (item->xml_member && item->bin_member)
168 printf (" in %s and %s", item->xml_member, item->bin_member);
169 else if (item->xml_member)
170 printf (" in %s", item->xml_member);
171 else if (item->bin_member)
172 printf (" in %s", item->bin_member);
178 run_detect (int argc UNUSED, char **argv)
180 char *err = spv_detect (argv[1]);
182 error (1, 0, "%s", err);
186 run_directory (int argc UNUSED, char **argv)
188 struct spv_reader *spv;
189 char *err = spv_open (argv[1], &spv);
191 error (1, 0, "%s", err);
193 struct spv_item **items;
195 spv_select (spv, criteria, n_criteria, &items, &n_items);
196 for (size_t i = 0; i < n_items; i++)
197 print_item_directory (items[i]);
205 const struct spv_item **nodes;
209 const struct spv_item *stub[N_STUB];
213 swap_nodes (const struct spv_item **a, const struct spv_item **b)
215 const struct spv_item *tmp = *a;
221 get_path (const struct spv_item *item, struct item_path *path)
223 size_t allocated = 10;
224 path->nodes = path->stub;
229 if (path->n >= allocated)
231 if (path->nodes == path->stub)
232 path->nodes = xmemdup (path->stub, sizeof path->stub);
233 path->nodes = x2nrealloc (path->nodes, &allocated,
234 sizeof *path->nodes);
236 path->nodes[path->n++] = item;
240 for (size_t i = 0; i < path->n / 2; i++)
241 swap_nodes (&path->nodes[i], &path->nodes[path->n - i - 1]);
245 free_path (struct item_path *path)
247 if (path && path->nodes != path->stub)
252 dump_heading_transition (const struct spv_item *old,
253 const struct spv_item *new)
258 struct item_path old_path, new_path;
259 get_path (old, &old_path);
260 get_path (new, &new_path);
263 for (; common < old_path.n && common < new_path.n; common++)
264 if (old_path.nodes[common] != new_path.nodes[common])
267 for (size_t i = common; i < old_path.n; i++)
268 group_close_item_submit (group_close_item_create ());
269 for (size_t i = common; i < new_path.n; i++)
270 group_open_item_submit (group_open_item_create (
271 new_path.nodes[i]->command_id));
273 free_path (&old_path);
274 free_path (&new_path);
278 run_convert (int argc UNUSED, char **argv)
280 struct spv_reader *spv;
281 char *err = spv_open (argv[1], &spv);
283 error (1, 0, "%s", err);
286 spv_item_set_table_look (spv_get_root (spv), table_look);
288 output_engine_push ();
289 output_set_filename (argv[1]);
290 string_map_replace (&output_options, "output-file", argv[2]);
291 struct output_driver *driver = output_driver_create (&output_options);
294 output_driver_register (driver);
296 const struct page_setup *ps = spv_get_page_setup (spv);
298 page_setup_item_submit (page_setup_item_create (ps));
300 struct spv_item **items;
302 spv_select (spv, criteria, n_criteria, &items, &n_items);
303 struct spv_item *prev_heading = spv_get_root (spv);
304 for (size_t i = 0; i < n_items; i++)
306 struct spv_item *heading
307 = items[i]->type == SPV_ITEM_HEADING ? items[i] : items[i]->parent;
308 dump_heading_transition (prev_heading, heading);
309 dump_item (items[i]);
310 prev_heading = heading;
312 dump_heading_transition (prev_heading, spv_get_root (spv));
317 output_engine_pop ();
320 if (n_warnings && !force)
322 /* XXX There could be other files to unlink, e.g. the ascii driver can
323 produce additional files with the charts. */
328 static const struct pivot_table *
329 get_first_table (const struct spv_reader *spv)
331 struct spv_item **items;
333 spv_select (spv, criteria, n_criteria, &items, &n_items);
335 for (size_t i = 0; i < n_items; i++)
336 if (spv_item_is_table (items[i]))
339 return spv_item_get_table (items[i]);
347 run_get_table_look (int argc UNUSED, char **argv)
349 struct spv_reader *spv;
350 char *err = spv_open (argv[1], &spv);
352 error (1, 0, "%s", err);
354 const struct pivot_table *table = get_first_table (spv);
356 error (1, 0, "%s: no tables found", argv[1]);
358 err = spv_table_look_write (argv[2], pivot_table_get_look (table));
360 error (1, 0, "%s", err);
366 run_convert_table_look (int argc UNUSED, char **argv)
368 struct pivot_table_look *look;
369 char *err = spv_table_look_read (argv[1], &look);
371 error (1, 0, "%s", err);
373 err = spv_table_look_write (argv[2], look);
375 error (1, 0, "%s", err);
377 pivot_table_look_uninit (look);
382 run_dump (int argc UNUSED, char **argv)
384 struct spv_reader *spv;
385 char *err = spv_open (argv[1], &spv);
387 error (1, 0, "%s", err);
389 struct spv_item **items;
391 spv_select (spv, criteria, n_criteria, &items, &n_items);
392 for (size_t i = 0; i < n_items; i++)
393 if (items[i]->type == SPV_ITEM_TABLE)
395 pivot_table_dump (spv_item_get_table (items[i]), 0);
404 compare_borders (const void *a_, const void *b_)
406 const struct spvlb_border *const *ap = a_;
407 const struct spvlb_border *const *bp = b_;
408 uint32_t a = (*ap)->border_type;
409 uint32_t b = (*bp)->border_type;
411 return a < b ? -1 : a > b;
415 compare_cells (const void *a_, const void *b_)
417 const struct spvlb_cell *const *ap = a_;
418 const struct spvlb_cell *const *bp = b_;
419 uint64_t a = (*ap)->index;
420 uint64_t b = (*bp)->index;
422 return a < b ? -1 : a > b;
426 run_dump_light_table (int argc UNUSED, char **argv)
428 if (raw && isatty (STDOUT_FILENO))
429 error (1, 0, "not writing binary data to tty");
431 struct spv_reader *spv;
432 char *err = spv_open (argv[1], &spv);
434 error (1, 0, "%s", err);
436 struct spv_item **items;
438 spv_select (spv, criteria, n_criteria, &items, &n_items);
439 for (size_t i = 0; i < n_items; i++)
441 if (!spv_item_is_light_table (items[i]))
449 error = spv_item_get_raw_light_table (items[i], &data, &size);
452 fwrite (data, size, 1, stdout);
458 struct spvlb_table *table;
459 error = spv_item_get_light_table (items[i], &table);
464 qsort (table->borders->borders, table->borders->n_borders,
465 sizeof *table->borders->borders, compare_borders);
466 qsort (table->cells->cells, table->cells->n_cells,
467 sizeof *table->cells->cells, compare_cells);
469 spvlb_print_table (items[i]->bin_member, 0, table);
470 spvlb_free_table (table);
475 msg (ME, "%s", error);
486 run_dump_legacy_data (int argc UNUSED, char **argv)
488 struct spv_reader *spv;
489 char *err = spv_open (argv[1], &spv);
491 error (1, 0, "%s", err);
493 struct spv_item **items;
495 spv_select (spv, criteria, n_criteria, &items, &n_items);
496 for (size_t i = 0; i < n_items; i++)
497 if (spv_item_is_legacy_table (items[i]))
499 struct spv_data data;
505 error = spv_item_get_raw_legacy_data (items[i], &data, &size);
508 fwrite (data, size, 1, stdout);
514 error = spv_item_get_legacy_data (items[i], &data);
517 printf ("%s:\n", items[i]->bin_member);
518 spv_data_dump (&data, stdout);
519 spv_data_uninit (&data);
526 msg (ME, "%s", error);
535 /* This is really bogus.
537 XPath doesn't have any notion of a default XML namespace, but all of the
538 elements in the documents we're interested in have a namespace. Thus, we'd
539 need to require the XPath expressions to have a namespace on every single
540 element: vis:sourceVariable, vis:graph, and so on. That's a pain. So,
541 instead, we remove the default namespace from everyplace it occurs. XPath
542 does support the null namespace, so this allows sourceVariable, graph,
545 See http://plasmasturm.org/log/259/ and
546 https://mail.gnome.org/archives/xml/2003-April/msg00144.html for more
549 remove_default_xml_namespace (xmlNode *node)
551 if (node->ns && !node->ns->prefix)
554 for (xmlNode *child = node->children; child; child = child->next)
555 remove_default_xml_namespace (child);
559 register_ns (xmlXPathContext *ctx, const char *prefix, const char *uri)
561 xmlXPathRegisterNs (ctx, CHAR_CAST (xmlChar *, prefix),
562 CHAR_CAST (xmlChar *, uri));
565 static xmlXPathContext *
566 create_xpath_context (xmlDoc *doc)
568 xmlXPathContext *ctx = xmlXPathNewContext (doc);
569 register_ns (ctx, "vgr", "http://xml.spss.com/spss/viewer/viewer-graph");
570 register_ns (ctx, "vizml", "http://xml.spss.com/visualization");
571 register_ns (ctx, "vmd", "http://xml.spss.com/spss/viewer/viewer-model");
572 register_ns (ctx, "vps", "http://xml.spss.com/spss/viewer/viewer-pagesetup");
573 register_ns (ctx, "vst", "http://xml.spss.com/spss/viewer/viewer-style");
574 register_ns (ctx, "vtb", "http://xml.spss.com/spss/viewer/viewer-table");
575 register_ns (ctx, "vtl", "http://xml.spss.com/spss/viewer/table-looks");
576 register_ns (ctx, "vtt", "http://xml.spss.com/spss/viewer/viewer-treemodel");
577 register_ns (ctx, "vtx", "http://xml.spss.com/spss/viewer/viewer-text");
578 register_ns (ctx, "xsi", "http://www.w3.org/2001/XMLSchema-instance");
583 dump_xml (int argc, char **argv, const char *member_name,
584 char *error_s, xmlDoc *doc)
590 printf ("<!-- %s -->\n", member_name);
591 xmlElemDump (stdout, NULL, xmlDocGetRootElement (doc));
596 bool any_results = false;
598 remove_default_xml_namespace (xmlDocGetRootElement (doc));
599 for (int i = 2; i < argc; i++)
601 xmlXPathContext *xpath_ctx = create_xpath_context (doc);
602 xmlXPathSetContextNode (xmlDocGetRootElement (doc),
604 xmlXPathObject *xpath_obj = xmlXPathEvalExpression(
605 CHAR_CAST (xmlChar *, argv[i]), xpath_ctx);
607 error (1, 0, _("%s: invalid XPath expression"), argv[i]);
609 const xmlNodeSet *nodes = xpath_obj->nodesetval;
610 if (nodes && nodes->nodeNr > 0)
614 printf ("<!-- %s -->\n", member_name);
617 for (size_t j = 0; j < nodes->nodeNr; j++)
619 xmlElemDump (stdout, doc, nodes->nodeTab[j]);
624 xmlXPathFreeObject (xpath_obj);
625 xmlXPathFreeContext (xpath_ctx);
634 printf ("<!-- %s -->\n", member_name);
635 msg (ME, "%s", error_s);
641 run_dump_legacy_table (int argc, char **argv)
643 struct spv_reader *spv;
644 char *err = spv_open (argv[1], &spv);
646 error (1, 0, "%s", err);
648 struct spv_item **items;
650 spv_select (spv, criteria, n_criteria, &items, &n_items);
651 for (size_t i = 0; i < n_items; i++)
652 if (spv_item_is_legacy_table (items[i]))
655 char *error_s = spv_item_get_legacy_table (items[i], &doc);
656 dump_xml (argc, argv, items[i]->xml_member, error_s, doc);
664 run_dump_structure (int argc, char **argv)
666 struct spv_reader *spv;
667 char *err = spv_open (argv[1], &spv);
669 error (1, 0, "%s", err);
671 struct spv_item **items;
673 spv_select (spv, criteria, n_criteria, &items, &n_items);
674 const char *last_structure_member = NULL;
675 for (size_t i = 0; i < n_items; i++)
676 if (!last_structure_member || strcmp (items[i]->structure_member,
677 last_structure_member))
679 last_structure_member = items[i]->structure_member;
682 char *error_s = spv_item_get_structure (items[i], &doc);
683 dump_xml (argc, argv, items[i]->structure_member, error_s, doc);
691 run_is_legacy (int argc UNUSED, char **argv)
693 struct spv_reader *spv;
694 char *err = spv_open (argv[1], &spv);
696 error (1, 0, "%s", err);
698 bool is_legacy = false;
700 struct spv_item **items;
702 spv_select (spv, criteria, n_criteria, &items, &n_items);
703 for (size_t i = 0; i < n_items; i++)
704 if (spv_item_is_legacy_table (items[i]))
713 exit (is_legacy ? EXIT_SUCCESS : EXIT_FAILURE);
719 int min_args, max_args;
720 void (*run) (int argc, char **argv);
723 static const struct command commands[] =
725 { "detect", 1, 1, run_detect },
726 { "dir", 1, 1, run_directory },
727 { "convert", 2, 2, run_convert },
728 { "get-table-look", 2, 2, run_get_table_look },
729 { "convert-table-look", 2, 2, run_convert_table_look },
731 /* Undocumented commands. */
732 { "dump", 1, 1, run_dump },
733 { "dump-light-table", 1, 1, run_dump_light_table },
734 { "dump-legacy-data", 1, 1, run_dump_legacy_data },
735 { "dump-legacy-table", 1, INT_MAX, run_dump_legacy_table },
736 { "dump-structure", 1, INT_MAX, run_dump_structure },
737 { "is-legacy", 1, 1, run_is_legacy },
739 static const int n_commands = sizeof commands / sizeof *commands;
741 static const struct command *
742 find_command (const char *name)
744 for (size_t i = 0; i < n_commands; i++)
746 const struct command *c = &commands[i];
747 if (!strcmp (name, c->name))
754 emit_msg (const struct msg *m, void *aux UNUSED)
756 if (m->severity == MSG_S_ERROR || m->severity == MSG_S_WARNING)
759 char *s = msg_to_string (m);
760 fprintf (stderr, "%s\n", s);
765 main (int argc, char **argv)
767 set_program_name (argv[0]);
768 msg_set_handler (emit_msg, NULL);
772 parse_options (argc, argv);
778 error (1, 0, _("missing command name (use --help for help)"));
780 const struct command *c = find_command (argv[0]);
782 error (1, 0, _("unknown command \"%s\" (use --help for help)"), argv[0]);
784 int n_args = argc - 1;
785 if (n_args < c->min_args || n_args > c->max_args)
787 if (c->min_args == c->max_args)
790 ngettext ("\"%s\" command takes exactly %d argument",
791 "\"%s\" command takes exactly %d arguments",
792 c->min_args), c->name, c->min_args);
794 else if (c->max_args == INT_MAX)
797 ngettext ("\"%s\" command requires at least %d argument",
798 "\"%s\" command requires at least %d arguments",
799 c->min_args), c->name, c->min_args);
804 _("\"%s\" command requires between %d and %d arguments"),
805 c->name, c->min_args, c->max_args);
813 pivot_table_look_uninit (table_look);
818 return n_warnings ? EXIT_FAILURE : EXIT_SUCCESS;
821 static struct spv_criteria *
824 if (!n_criteria || new_criteria)
826 new_criteria = false;
827 if (n_criteria >= allocated_criteria)
828 criteria = x2nrealloc (criteria, &allocated_criteria,
830 criteria[n_criteria++] = (struct spv_criteria) SPV_CRITERIA_INITIALIZER;
833 return &criteria[n_criteria - 1];
837 parse_select (char *arg)
839 bool invert = arg[0] == '^';
842 unsigned classes = 0;
843 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
845 if (!strcmp (arg, "all"))
846 classes = SPV_ALL_CLASSES;
847 else if (!strcmp (arg, "help"))
849 puts (_("The following object classes are supported:"));
850 for (int class = 0; class < SPV_N_CLASSES; class++)
851 printf ("- %s\n", spv_item_class_to_string (class));
856 int class = spv_item_class_from_string (token);
857 if (class == SPV_N_CLASSES)
858 error (1, 0, _("%s: unknown object class (use --select=help "
860 classes |= 1u << class;
864 struct spv_criteria *c = get_criteria ();
865 c->classes = invert ? classes ^ SPV_ALL_CLASSES : classes;
868 static struct spv_criteria_match *
869 get_criteria_match (const char **arg)
871 struct spv_criteria *c = get_criteria ();
872 if ((*arg)[0] == '^')
882 parse_commands (const char *arg)
884 struct spv_criteria_match *cm = get_criteria_match (&arg);
885 string_array_parse (&cm->commands, ss_cstr (arg), ss_cstr (","));
889 parse_subtypes (const char *arg)
891 struct spv_criteria_match *cm = get_criteria_match (&arg);
892 string_array_parse (&cm->subtypes, ss_cstr (arg), ss_cstr (","));
896 parse_labels (const char *arg)
898 struct spv_criteria_match *cm = get_criteria_match (&arg);
899 string_array_parse (&cm->labels, ss_cstr (arg), ss_cstr (","));
903 parse_instances (char *arg)
905 struct spv_criteria *c = get_criteria ();
906 size_t allocated_instances = c->n_instances;
908 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
910 if (c->n_instances >= allocated_instances)
911 c->instances = x2nrealloc (c->instances, &allocated_instances,
912 sizeof *c->instances);
914 c->instances[c->n_instances++] = (!strcmp (token, "last") ? -1
920 parse_nth_commands (char *arg)
922 struct spv_criteria *c = get_criteria ();
923 size_t allocated_commands = c->n_commands;
925 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
927 if (c->n_commands >= allocated_commands)
928 c->commands = x2nrealloc (c->commands, &allocated_commands,
929 sizeof *c->commands);
931 c->commands[c->n_commands++] = atoi (token);
936 parse_members (const char *arg)
938 struct spv_criteria *cm = get_criteria ();
939 string_array_parse (&cm->members, ss_cstr (arg), ss_cstr (","));
943 parse_table_look (const char *arg)
947 pivot_table_look_uninit (table_look);
951 char *error_s = spv_table_look_read (arg, &table_look);
953 error (1, 0, "%s", error_s);
957 parse_options (int argc, char *argv[])
963 OPT_MEMBER_NAMES = UCHAR_MAX + 1,
978 static const struct option long_options[] =
980 /* Input selection options. */
981 { "show-hidden", no_argument, NULL, OPT_SHOW_HIDDEN },
982 { "select", required_argument, NULL, OPT_SELECT },
983 { "commands", required_argument, NULL, OPT_COMMANDS },
984 { "nth-commands", required_argument, NULL, OPT_NTH_COMMANDS },
985 { "subtypes", required_argument, NULL, OPT_SUBTYPES },
986 { "labels", required_argument, NULL, OPT_LABELS },
987 { "instances", required_argument, NULL, OPT_INSTANCES },
988 { "members", required_argument, NULL, OPT_MEMBERS },
989 { "errors", no_argument, NULL, OPT_ERRORS },
990 { "or", no_argument, NULL, OPT_OR },
992 /* "dir" command options. */
993 { "member-names", no_argument, NULL, OPT_MEMBER_NAMES },
995 /* "convert" command options. */
996 { "force", no_argument, NULL, 'f' },
997 { "table-look", required_argument, NULL, OPT_TABLE_LOOK },
999 /* "dump-light-table" command options. */
1000 { "sort", no_argument, NULL, OPT_SORT },
1001 { "raw", no_argument, NULL, OPT_RAW },
1003 { "help", no_argument, NULL, 'h' },
1004 { "version", no_argument, NULL, 'v' },
1006 { NULL, 0, NULL, 0 },
1011 c = getopt_long (argc, argv, "O:hvf", long_options, NULL);
1018 output_driver_parse_option (optarg, &output_options);
1021 case OPT_MEMBER_NAMES:
1022 show_member_names = true;
1025 case OPT_SHOW_HIDDEN:
1026 get_criteria ()->include_hidden = true;
1030 parse_select (optarg);
1034 parse_commands (optarg);
1037 case OPT_NTH_COMMANDS:
1038 parse_nth_commands (optarg);
1042 parse_subtypes (optarg);
1046 parse_labels (optarg);
1050 parse_instances (optarg);
1054 parse_members (optarg);
1058 get_criteria ()->error = true;
1062 new_criteria = true;
1073 case OPT_TABLE_LOOK:
1074 parse_table_look (optarg);
1082 version_etc (stdout, "pspp-output", PACKAGE_NAME, PACKAGE_VERSION,
1083 "Ben Pfaff", "John Darrington", NULL_SENTINEL);
1084 exit (EXIT_SUCCESS);
1088 exit (EXIT_SUCCESS);
1091 exit (EXIT_FAILURE);
1099 struct string s = DS_EMPTY_INITIALIZER;
1100 struct string_set formats = STRING_SET_INITIALIZER(formats);
1101 output_get_supported_formats (&formats);
1103 const struct string_set_node *node;
1104 STRING_SET_FOR_EACH (format, node, &formats)
1106 if (!ds_is_empty (&s))
1107 ds_put_byte (&s, ' ');
1108 ds_put_cstr (&s, format);
1110 string_set_destroy (&formats);
1113 %s, a utility for working with SPSS viewer (.spv) files.\n\
1114 Usage: %s [OPTION]... COMMAND ARG...\n\
1116 The following commands are available:\n\
1117 detect FILE Detect whether FILE is an SPV file.\n\
1118 dir FILE List tables and other items in FILE.\n\
1119 convert SOURCE DEST Convert .spv SOURCE to DEST.\n\
1120 get-table-look SOURCE DEST Copies first selected TableLook into DEST\n\
1121 convert-table-look SOURCE DEST Copies .tlo or .stt SOURCE into DEST\n\
1123 Input selection options for \"dir\" and \"convert\":\n\
1124 --select=CLASS... include only some kinds of objects\n\
1125 --select=help print known object classes\n\
1126 --commands=COMMAND... include only specified COMMANDs\n\
1127 --nth-commands=N... include only the Nth instance of selected commands\n\
1128 --subtypes=SUBTYPE... include only specified SUBTYPEs of output\n\
1129 --labels=LABEL... include only output objects with the given LABELs\n\
1130 --instances=INSTANCE... include only the given object INSTANCEs\n\
1131 --show-hidden include hidden output objects\n\
1132 --or separate two sets of selection options\n\
1134 \"convert\" by default infers the destination's format from its extension.\n\
1135 The known extensions are: %s\n\
1136 The following options override \"convert\" behavior:\n\
1137 -O format=FORMAT set destination format to FORMAT\n\
1138 -O OPTION=VALUE set output option\n\
1139 -f, --force keep output file even given errors\n\
1140 --table-look=FILE override tables' style with TableLook from FILE\n\
1142 --help display this help and exit\n\
1143 --version output version information and exit\n",
1144 program_name, program_name, ds_cstr (&s));